├── CNAME ├── README.md ├── .jshintrc ├── .gitignore ├── testcases ├── README.md ├── test-extensions │ ├── hacks.js │ ├── phys2.js │ └── phys1.js ├── testcases.css ├── LICENSE ├── render-equations.js ├── equations.html ├── index.html ├── responsive.html └── testcases.yml ├── index.html ├── src ├── z-load-complete.js ├── css │ ├── html-css.css │ └── common-html.css ├── license.js ├── html.js └── tex.js ├── docker-compose.yml ├── Makefile ├── .editorconfig ├── package.json ├── LICENSE ├── dist ├── License.txt ├── arabic.css ├── unpacked │ ├── arabic.css │ └── arabic.js ├── arabic.js └── README.md └── gulpfile.js /CNAME: -------------------------------------------------------------------------------- 1 | arabicmath.org -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | dist/README.md -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /extensions/ 2 | /node_modules/ 3 | /mathjax/ 4 | /.idea 5 | .DS_Store 6 | /static/ 7 | -------------------------------------------------------------------------------- /testcases/README.md: -------------------------------------------------------------------------------- 1 | # Arabic-MathJax-TestCases 2 | Test cases for the Arabic extension of MathJax. 3 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/z-load-complete.js: -------------------------------------------------------------------------------- 1 | // This file starting with the letter `z` to make sure it gets concatenated last! 2 | MathJax.Ajax.loadComplete("[arabic]/unpacked/arabic.js"); 3 | -------------------------------------------------------------------------------- /testcases/test-extensions/hacks.js: -------------------------------------------------------------------------------- 1 | MathJax.Hub.Config({ 2 | // Arabic decimal mark 3 | Arabic: { 4 | numbersMap: { 5 | '\\.': '٫' 6 | } 7 | } 8 | }); 9 | 10 | MathJax.Ajax.loadComplete("[Test]/hacks.js"); 11 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | main: 2 | image: node:9.4.0 3 | 4 | working_dir: /code/ 5 | environment: 6 | PORT: "1990" 7 | command: node node_modules/.bin/gulp 8 | 9 | ports: 10 | - "1990:1990" 11 | 12 | volumes: 13 | - ".:/code/" 14 | -------------------------------------------------------------------------------- /src/css/html-css.css: -------------------------------------------------------------------------------- 1 | /* HTML-CSS Output Jax CSS */ 2 | .MathJax .mfliph { 3 | display: inline-block !important; 4 | -moz-transform: scaleX(-1); 5 | -webkit-transform: scaleX(-1); 6 | -o-transform: scaleX(-1); 7 | transform: scaleX(-1); 8 | -ms-filter: fliph; 9 | filter: fliph; 10 | } 11 | 12 | .MathJax .mar { 13 | font-style: normal !important; 14 | } 15 | .MathJax .mar > span { 16 | font-style: normal !important; 17 | } 18 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | correct_perms: 2 | sudo chown -R $$USER . 3 | chmod -R a+r . 4 | find extensions/ testcases/ -type d -exec chmod a+x {} \; 5 | 6 | 7 | init: 8 | docker-compose run main npm install 9 | make correct_perms 10 | 11 | deploy: 12 | cat extensions/arabic/arabic.js > static/arabic/arabic.js 13 | cd static/ \ 14 | && git add arabic/arabic.js \ 15 | && git push \ 16 | && (git ci -m "Auto update on `date`" || true) \ 17 | && git push 18 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | root = true 4 | 5 | # Unix-style newlines with a newline ending every file 6 | [*] 7 | end_of_line = lf 8 | insert_final_newline = true 9 | charset = utf-8 10 | 11 | 12 | # Matches multiple files with brace expansion notation 13 | # Set default charset 14 | [*.js] 15 | indent_style = space 16 | indent_size = 2 17 | 18 | 19 | # Tab indentation (no size specified) 20 | [Makefile] 21 | indent_style = tab 22 | 23 | 24 | # Matches the exact files either package.json or .travis.yml 25 | [{package.json,.*.yml,*.html}] 26 | indent_style = space 27 | indent_size = 2 28 | -------------------------------------------------------------------------------- /testcases/testcases.css: -------------------------------------------------------------------------------- 1 | /* Test Cases Styles */ 2 | #wrapper { 3 | margin: 0 auto; 4 | padding-top: 40px; 5 | } 6 | 7 | table { 8 | margin: 0 auto; 9 | } 10 | 11 | hr { 12 | margin-top: 30px; 13 | margin-bottom: 30px; 14 | } 15 | 16 | .MathJax_Display { 17 | margin: 20px auto; 18 | } 19 | 20 | .inline-link { 21 | opacity: 0; 22 | display: block; 23 | position: absolute; 24 | background-color: white; 25 | border: solid white; 26 | border-width: 0 4px; 27 | box-shadow: 1px 1px 3px black; 28 | border-radius: 4px; 29 | } 30 | 31 | td:hover .inline-link { 32 | opacity: 0.5; 33 | } 34 | 35 | td:hover .inline-link:hover { 36 | opacity: 1; 37 | } 38 | 39 | .hidden { 40 | display: none; 41 | } 42 | -------------------------------------------------------------------------------- /testcases/test-extensions/phys2.js: -------------------------------------------------------------------------------- 1 | //MathJax.Hub.Register.StartupHook('Arabic TeX Startup', function () { 2 | // var ArabicText = MathJax.Arabic.ArabicText; 3 | // var ArabicTeX = MathJax.Arabic.ArabicTeX; 4 | // var ArabicSymbols = MathJax.Arabic.ArabicSymbols; 5 | // 6 | // MathJax.Arabic.AugmentDict({ 7 | // // Solar Energy Course Part #2 8 | // //'mass': 'MaterialMassAr', 'm', 'ك', 9 | // //'capacity': 'CapacityAr': 'C', 'ح', 10 | // //'materialheat': 'MaterialHeat': 'p', 'ن', 11 | // //'temperature': 'Temperature': 'T', 'د', 12 | // //'latentheat': 'LatentHeat': 'Q', 'ح_ك', 13 | // //'latentenergy': 'LatentEnergy': '\\lambda', 'ط_ك', 14 | // //'heatflux': 'HeatFlux': 'Q_\\text{cond}', 'ح_ت', 15 | // //'thermalconduct': 'ThermalConductivity': 'K', 'ت_ح', 16 | // //'area': 'Area': 'A', 'م', 17 | // //'heattransfcoeff': 'HeatTransferCoefficient': 'h', 'م.ح', 18 | // }); 19 | //}); 20 | 21 | MathJax.Ajax.loadComplete("[Test]/phys2.js"); 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "arabic-mathjax", 3 | "version": "2.1.1", 4 | "description": "A docker container for developing my MathJax plugins.", 5 | "main": "gulpfile.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/OmarIthawi/arabic-mathjax.git" 12 | }, 13 | "devDependencies": { 14 | "browser-sync": "^2.26.3", 15 | "gulp": "^4.0.2", 16 | "gulp-uglifycss": "^1.1.0", 17 | "gulp-concat": "^2.6.0", 18 | "gulp-order": "^1.2.0", 19 | "gulp-plumber": "1.0.0", 20 | "gulp-replace": "^0.5.4", 21 | "gulp-uglify": "^1.2.0", 22 | "run-sequence": "^1.2.1" 23 | }, 24 | "author": "Omar Al-Ithawi ", 25 | "generator": "Quench ", 26 | "license": "MIT", 27 | "bugs": { 28 | "url": "https://github.com/OmarIthawi/arabic-mathjax/issues" 29 | }, 30 | "homepage": "http://www.omardo.com/arabic-mathjax/index.html", 31 | "dependencies": {} 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Edraak.org, Omar Al-Ithawi and contributors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /dist/License.txt: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2015 Edraak.org, Omar Al-Ithawi and contributors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /testcases/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Edraak.org, Omar Al-Ithawi and contributors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/license.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * The MIT License 3 | * 4 | * Copyright (c) 2015-2016 Edraak.org, Omar Al-Ithawi and contributors. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | -------------------------------------------------------------------------------- /testcases/render-equations.js: -------------------------------------------------------------------------------- 1 | var renderEquations = function () { 2 | var $ = jQuery; 3 | 4 | var loadTestCases = function (cb) { 5 | $.get('testcases.yml', function (testcasesYAMLStr) { 6 | cb(jsyaml.load(testcasesYAMLStr)); 7 | }); 8 | }; 9 | 10 | 11 | $.get('equations.html', function (template) { 12 | loadTestCases(function (testCases) { 13 | var rendered = Mustache.render(template, { 14 | equations: testCases.equations.reverse() 15 | }); 16 | 17 | $('#equations').html(rendered); 18 | 19 | 20 | var render = function () { 21 | var $scriptTemplate = $(' 48 | 49 | 50 | # 51 | 52 | {{#hide_arabic}} 53 | English-only test case. 54 | {{/hide_arabic}} 55 | 56 | {{^hide_arabic}} 57 | 62 | {{/hide_arabic}} 63 | 64 | 65 | {{/experimental}} 66 | {{/equations}} 67 | 68 |
69 |
70 | -------------------------------------------------------------------------------- /dist/unpacked/arabic.css: -------------------------------------------------------------------------------- 1 | /* CommonHTML Output Jax CSS */ 2 | .MathJax_CHTML .mfliph { 3 | display: inline-block !important; 4 | -moz-transform: scaleX(-1); 5 | -webkit-transform: scaleX(-1); 6 | -o-transform: scaleX(-1); 7 | transform: scaleX(-1); 8 | -ms-filter: fliph; 9 | filter: fliph; 10 | } 11 | 12 | .MathJax_CHTML .mar { 13 | font-style: normal !important; 14 | } 15 | 16 | .MathJax_CHTML .mar > span { 17 | font-style: normal !important; 18 | } 19 | 20 | .mfliph > .mjx-char { 21 | direction: rtl; 22 | text-align: right; 23 | } 24 | 25 | .mfliph .MJXc-TeX-unknown-I, .mfliph.MJXc-TeX-unknown-I { 26 | font-style: normal !important; 27 | } 28 | 29 | .mfliph.mar > .mjx-char.MJXc-TeX-unknown-I { 30 | border: solid transparent; 31 | border-width: 0.45em 0; 32 | } 33 | 34 | .mfliph.mar > .mjx-char.MJXc-TeX-unknown-R { 35 | border: solid transparent; 36 | border-width: 0.45em 0; 37 | } 38 | 39 | .mjx-mn > .mfliph.mar > .mjx-char.MJXc-TeX-unknown-I { 40 | border-width: 0; 41 | } 42 | 43 | .mjx-stack > .mjx-sup > span > .mfliph.mar > .MJXc-TeX-unknown-I { 44 | border-bottom-width: 0.85em; 45 | } 46 | 47 | .MJXc-stacked > .mjx-numerator > span > .mfliph.mar > .MJXc-TeX-unknown-R { 48 | padding-top: 0.45em; 49 | border: none; 50 | } 51 | 52 | .MJXc-stacked > .mjx-denominator > span > .mfliph.mar > .MJXc-TeX-unknown-R { 53 | padding-bottom: 0.45em; 54 | border: none; 55 | } 56 | 57 | .MJXc-stacked > .mjx-denominator > span > .mfliph > .mjx-char.MJXc-TeX-unknown-R { 58 | padding-bottom: 0.45em; 59 | border: none; 60 | } 61 | 62 | /* Fixing \transn to give it a reserved space using boarder */ 63 | .MathJax_CHTML .mjx-mrow > .mjx-mtext .mjx-char.MJXc-TeX-unknown-R { 64 | border: solid transparent; 65 | border-width: 0.45em 0; 66 | } 67 | 68 | /* HTML-CSS Output Jax CSS */ 69 | .MathJax .mfliph { 70 | display: inline-block !important; 71 | -moz-transform: scaleX(-1); 72 | -webkit-transform: scaleX(-1); 73 | -o-transform: scaleX(-1); 74 | transform: scaleX(-1); 75 | -ms-filter: fliph; 76 | filter: fliph; 77 | } 78 | 79 | .MathJax .mar { 80 | font-style: normal !important; 81 | } 82 | .MathJax .mar > span { 83 | font-style: normal !important; 84 | } 85 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var path = require('path'); 3 | var plumber = require('gulp-plumber'); 4 | var uglify = require('gulp-uglify'); 5 | var uglifycss = require('gulp-uglifycss'); 6 | var browserSync = require('browser-sync'); 7 | var concat = require('gulp-concat'); 8 | var order = require('gulp-order'); 9 | var replace = require('gulp-replace'); 10 | var runSequence = require('run-sequence'); 11 | 12 | var unicodeEscapeArabicChars = function (match) { 13 | // Replaces arabic chars with their unicode equivalent. 14 | var hexCharCode = match.charCodeAt(0).toString(16); 15 | var zeroPrefixed = ('0000' + hexCharCode).slice(-4); 16 | return '\\u' + zeroPrefixed; 17 | }; 18 | 19 | var arabicCharsRegExp = /[^\x00-\x7F]/g; 20 | 21 | gulp.task('browser-sync', function () { 22 | browserSync({ 23 | port: process.env.PORT || 3000, 24 | server: { 25 | baseDir: __dirname 26 | } 27 | }); 28 | }); 29 | 30 | 31 | gulp.task('bs-reload', function () { 32 | browserSync.reload(); 33 | }); 34 | 35 | 36 | gulp.task('scripts-concat', function () { 37 | return gulp.src(path.join(__dirname, 'src/*.js')) 38 | .pipe(plumber({ 39 | errorHandler: function (error) { 40 | console.log(error.message); 41 | this.emit('end'); 42 | } 43 | })) 44 | .pipe(order([ 45 | 'license.js', 46 | '*.js' 47 | ])) 48 | .pipe(concat('arabic.js')) 49 | .pipe(replace(arabicCharsRegExp, unicodeEscapeArabicChars)) 50 | .pipe(gulp.dest(path.join(__dirname, 'dist/unpacked/'))); 51 | }); 52 | 53 | 54 | gulp.task('scripts-pack', function () { 55 | return gulp.src(path.join(__dirname, 'dist/unpacked/arabic.js')) 56 | .pipe(plumber({ 57 | errorHandler: function (error) { 58 | console.log(error.message); 59 | this.emit('end'); 60 | } 61 | })) 62 | .pipe(uglify({ 63 | preserveComments: 'some' 64 | })) 65 | .pipe(replace(arabicCharsRegExp, unicodeEscapeArabicChars)) 66 | .pipe(replace('[arabic]/unpacked/arabic.js', '[arabic]/arabic.js')) 67 | .pipe(gulp.dest(path.join(__dirname, 'dist/'))); 68 | }); 69 | 70 | gulp.task('styles-concat', function () { 71 | return gulp.src(path.join(__dirname, 'src/css/*.css')) 72 | .pipe(plumber({ 73 | errorHandler: function (error) { 74 | console.log(error.message); 75 | this.emit('end'); 76 | } 77 | })) 78 | .pipe(concat('arabic.css')) 79 | .pipe(gulp.dest(path.join(__dirname, 'dist/unpacked/'))); 80 | }); 81 | 82 | gulp.task('styles-pack', function () { 83 | return gulp.src(path.join(__dirname, 'dist/unpacked/arabic.css')) 84 | .pipe(plumber({ 85 | errorHandler: function (error) { 86 | console.log(error.message); 87 | this.emit('end'); 88 | } 89 | })) 90 | .pipe(uglifycss({ 91 | maxLineLen: 80 92 | })) 93 | .pipe(gulp.dest(path.join(__dirname, 'dist/'))); 94 | }); 95 | 96 | gulp.task('build-and-reload', function () { 97 | runSequence( 98 | 'scripts-concat', 99 | 'scripts-pack', 100 | 'styles-concat', 101 | 'styles-pack', 102 | 'bs-reload' 103 | ); 104 | }); 105 | 106 | gulp.task('default', ['build-and-reload', 'browser-sync'], function () { 107 | gulp.watch(path.join(__dirname, 'src/**/*.{js,css}'), ['build-and-reload']); 108 | gulp.watch(path.join(__dirname, 'testcases/**/*.{html,css,js,yml}'), ['build-and-reload']); 109 | gulp.watch(path.join(__dirname, 'mathjax/unpacked/jax/input/TeX/**/*.js'), ['bs-reload']); 110 | }); 111 | -------------------------------------------------------------------------------- /testcases/test-extensions/phys1.js: -------------------------------------------------------------------------------- 1 | // Stuff, that I've just copied! 2 | MathJax.Hub.Config({ 3 | Arabic: { 4 | dict: { 5 | // omarDoesNotKnowIt 6 | "EKAr": ["ek", 'Text', ['e', 'انتشار،ك']], 7 | "EspsilonRAr": ["er", 'TeX', ['\\epsilon{}r', '\\fliph{\\epsilon{}r}']], 8 | "CurrentDensityAr": ["J", 'Symbols', ['J', 'ك.ت']], 9 | "FillFactorAr": ["FF", 'Symbols', ['FF', 'ع.ت']], 10 | "OpenCircuitAr": ["oc", 'Symbols', ['oc', 'م']], 11 | "SpreadCoefficientAr": ["D", 'Symbols', ['D', 'م']], 12 | "RadiationAr": ["rad", 'Symbols', ['l', 'ع']], 13 | "TemratureAr": ["Tmpr", 'Symbols', ['T', 'د']], 14 | "ConcentrationReceiverAtomAr": ["NA", 'Symbols', ['NA', 'ن_ق']], 15 | "ConcentrationDonorAtomAr": ["ND", 'Symbols', ['ND', 'ن_م']], 16 | "ConcentrationCarierPureAr": ["nii", 'Symbols', ['ni', 'ن_ك']], 17 | "DeplationAreaWidthAr": ["Wd", 'Symbols', ['W', 'ل_ن']], 18 | "ElectronsMotionConstantAr": ["mue", 'TeX', ['\\mu{}e', '\\fliph{\\mu{}e}']], 19 | "DiffusionElectronsAr": ["diffe", 'Symbols', ['\\text{diff},e', 'ن\\ ك']] 20 | } 21 | } 22 | }); 23 | 24 | 25 | // Physics Names 26 | MathJax.Hub.Config({ 27 | Arabic: { 28 | dict: { 29 | "AirMassAr": ["AM", 'Text', ['AM', 'كتلة هواء']], 30 | "ShortCircuitAr": ["sc", 'Symbols', ['sc', 'ق']], 31 | "PhotovoltaicEnergyAr": ["P", 'Symbols', ['P', 'ط']], 32 | "INAr": ["inn", 'Symbols', ['in', 'د']], 33 | "DiffusionLengthAr": ["Ld", 'Symbols', ['L_d', 'ل_ر']], 34 | "CurrentAr": ["current", 'Symbols', ['I', 'ت']], 35 | "VoltageAr": ["V", 'Symbols', ['V', 'جـ']] 36 | } 37 | } 38 | }); 39 | 40 | 41 | // Physics Constants 42 | MathJax.Hub.Config({ 43 | Arabic: { 44 | dict: { 45 | "LightSpeedAr": ["lspeed", 'Text', ['c', 'سرعة الضوء']], 46 | "PlancksAr": ["Plancks", 'Text', ['\\hbar', 'ثابت بلانك']], 47 | "BoltzmannsAr": ["Boltzmanns", 'Text', ['k', 'ثابت بولتزمان']], 48 | "EpsilonZeroAr": ["epsilonzero", 'TeX', ['\\varepsilon_\\zero', '\\fliph{\\varepsilon_\\zero}']] 49 | } 50 | } 51 | }); 52 | 53 | 54 | // Chemistry Units 55 | MathJax.Hub.Config({ 56 | Arabic: { 57 | dict: { 58 | "PHAr": ["ph", 'Text', ['ph', 'ف']], 59 | "ElectronAr": ["elctrn", 'Text', ['n', 'الكترون']] 60 | } 61 | } 62 | }); 63 | 64 | 65 | // Other Physics Units 66 | MathJax.Hub.Config({ 67 | Arabic: { 68 | dict: { 69 | "SecondsAr": ["scnd", 'Text', ['s', 'ث']], 70 | "HourAr": ["hour", 'Text', ['h', 'ساعة']], 71 | "DayAr": ["day", 'Text', ['\\text{day}', 'يوم']], 72 | "YearAr": ["year", 'Text', ['\\text{year}', 'سنة']], 73 | "AmpAr": ["Amp", 'Text', ['A', 'امبير']], 74 | "VoltAr": ["volt", 'Text', ['v', 'فولت']], 75 | "KilvenAr": ["Klvn", 'Text', ['K', 'كلفن']], 76 | "HoleAr": ["hole", 'Text', ['p', 'ثقب']], 77 | "WattAr": ["Watt", 'Text', ['W', 'واط']], 78 | "FaradAr": ["F", 'Text', ['F', 'فاراد']], 79 | "CentimeterAr": ["cm", 'Text', ['\\text{cm}', 'سم']], 80 | "GramAr": ["grm", 'Text', ['g', 'غرام']] 81 | } 82 | } 83 | }); 84 | 85 | 86 | // Misc 87 | MathJax.Hub.Config({ 88 | Arabic: { 89 | dict: { 90 | "MaxAr": ["max", 'Text', ['p', 'اقصى']] 91 | } 92 | } 93 | }); 94 | 95 | 96 | // Amplifiers 97 | MathJax.Hub.Config({ 98 | Arabic: { 99 | dict: { 100 | "MegaAr": ["Mega", 'Text', ['M', 'ميجا']], 101 | "NanoAr": ["nano", 'Text', ['n', 'نانو']], 102 | "GigaAr": ["Giga", 'Text', ['G', 'جيجا']], 103 | "TeraAr": ["Tera", 'Text', ['T', 'تيرا']], 104 | "KiloAr": ["kilo", 'Text', ['k', 'كيلو']], 105 | "MicroAr": ["micro", 'Text', ['\\mu', 'مايكرو']] 106 | } 107 | } 108 | }); 109 | 110 | 111 | MathJax.Hub.Config({ 112 | Arabic: { 113 | identifiersMap: { 114 | // Math functions 115 | // Energy 116 | 'E': 'ط', 117 | 118 | // Meter 119 | 'm': 'م', 120 | 121 | // Initial charge 122 | 'q': 'ش' 123 | } 124 | } 125 | }); 126 | 127 | MathJax.Ajax.loadComplete("[Test]/phys1.js"); 128 | -------------------------------------------------------------------------------- /src/html.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var mathElements = [ 3 | 'mfrac', 4 | 'mi', 5 | 'mn', 6 | 'mo', 7 | 'mroot', 8 | 'mrow', 9 | 'ms', 10 | 'msqrt', 11 | 'mstyle', 12 | 'msubsup', 13 | 'mtext' 14 | ]; 15 | 16 | MathJax.Hub.Register.StartupHook('CommonHTML Jax Ready', function () { 17 | var CHTML = MathJax.OutputJax.CommonHTML; 18 | var originalUnkownChar = CHTML.unknownChar; 19 | 20 | CHTML.Augment({ 21 | unknownChar: function () { 22 | var arabicUnicodeStart = MathJax.Hub.config.Arabic.arabicUnicodeStart; 23 | var arabicUnicodeEnd = MathJax.Hub.config.Arabic.arabicUnicodeEnd; 24 | var returnObject = originalUnkownChar.apply(this, arguments); 25 | var n = returnObject.n; 26 | var isArabic = (arabicUnicodeStart <= n && n <= arabicUnicodeEnd); 27 | 28 | if (isArabic) { 29 | returnObject.type = 'char'; 30 | } 31 | 32 | return returnObject; 33 | }, 34 | }); 35 | 36 | MathJax.Hub.Register.StartupHook('Arabic TeX Ready', function () { 37 | var MML = MathJax.ElementJax.mml; 38 | 39 | var makeElementFlippable = function (name) { 40 | var originalToHTML = MML[name].prototype.toCommonHTML; 41 | 42 | MML[name].Augment({ 43 | toCommonHTML: function () { 44 | var element = originalToHTML.apply(this, arguments); 45 | 46 | if (this.arabicFlipH) { 47 | var flipElement = document.createElement('span'); 48 | 49 | flipElement.className = 'mfliph'; 50 | 51 | if ('ar' === this.arabicFontLang) { 52 | flipElement.className += ' mar'; // Keep the leading space 53 | } 54 | 55 | while (element.firstChild) { 56 | flipElement.appendChild(element.firstChild); 57 | } 58 | 59 | element.appendChild(flipElement); 60 | } 61 | 62 | return element; 63 | } 64 | }); 65 | }; 66 | 67 | ['mtr', 'mtd'].concat(mathElements).forEach(makeElementFlippable); 68 | 69 | MathJax.Hub.Register.StartupHook('CommonHTML multiline Ready', function () { 70 | var originalAddLine = MML.mbase.prototype.CHTMLaddLine; 71 | 72 | MML.mbase.Augment({ 73 | CHTMLaddLine: function () { 74 | var stack = arguments[0]; 75 | 76 | // TODO: Would it be possible to use the usual env settings 77 | // to fix this issue, instead of doing a querySelector? 78 | if (stack && stack.querySelector('.mfliph')) { 79 | stack.className = 'mfliph'; 80 | } 81 | 82 | originalAddLine.apply(this, arguments); 83 | } 84 | }); 85 | 86 | MathJax.Hub.Startup.signal.Post('Arabic CommonHTML multiline Ready'); 87 | }); 88 | 89 | MathJax.Hub.Register.StartupHook('CommonHTML mtable Ready', function () { 90 | makeElementFlippable('mtable'); 91 | MathJax.Hub.Startup.signal.Post('Arabic CommonHTML mtable Ready'); 92 | }); 93 | 94 | MathJax.Hub.Startup.signal.Post('Arabic CommonHTML Ready'); 95 | }); 96 | }); 97 | 98 | MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready', function () { 99 | MathJax.Hub.Register.StartupHook('Arabic TeX Ready', function () { 100 | var MML = MathJax.ElementJax.mml; 101 | 102 | var makeElementFlippable = function (name) { 103 | var originalToHTML = MML[name].prototype.toHTML; 104 | 105 | MML[name].Augment({ 106 | toHTML: function () { 107 | var element = originalToHTML.apply(this, arguments); 108 | if (this.arabicFlipH) { 109 | var flipElement = document.createElement('span'); 110 | 111 | flipElement.className = 'mfliph'; 112 | 113 | if ('ar' === this.arabicFontLang) { 114 | flipElement.className += ' mar'; // Keep the leading space 115 | } 116 | 117 | while (element.firstChild) { 118 | flipElement.appendChild(element.firstChild); 119 | } 120 | 121 | element.appendChild(flipElement); 122 | } 123 | 124 | return element; 125 | } 126 | }); 127 | }; 128 | 129 | mathElements.forEach(makeElementFlippable); 130 | 131 | MathJax.Hub.Register.StartupHook('HTML-CSS multiline Ready', function () { 132 | var originalAddLine = MML.mbase.prototype.HTMLaddLine; 133 | 134 | MML.mbase.Augment({ 135 | HTMLaddLine: function () { 136 | var stack = arguments[0]; 137 | 138 | // TODO: Would it be possible to use the usual env settings 139 | // to fix this issue, instead of doing a querySelector? 140 | if (stack && stack.querySelector('.mfliph')) { 141 | stack.className = 'mfliph'; 142 | } 143 | 144 | originalAddLine.apply(this, arguments); 145 | } 146 | }); 147 | 148 | MathJax.Hub.Startup.signal.Post('Arabic HTML-CSS multiline Ready'); 149 | }); 150 | 151 | MathJax.Hub.Register.StartupHook('HTML-CSS mtable Ready', function () { 152 | makeElementFlippable('mtable'); 153 | MathJax.Hub.Startup.signal.Post('Arabic HTML-CSS mtable Ready'); 154 | }); 155 | 156 | MathJax.Hub.Startup.signal.Post('Arabic HTML-CSS Ready'); 157 | }); 158 | }); 159 | }()); 160 | -------------------------------------------------------------------------------- /testcases/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Test Cases for the Arabic.js MathJax Package 6 | 7 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 40 | 41 | 42 | 69 | 70 | 117 | 118 | 119 | 182 | 183 | 192 | 193 | 194 | 195 |

196 | 197 | 198 |

199 |
200 |
201 |
202 | 203 | 204 | -------------------------------------------------------------------------------- /dist/arabic.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * The MIT License 3 | * 4 | * Copyright (c) 2015-2016 Edraak.org, Omar Al-Ithawi and contributors. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | !function(){var a=["mfrac","mi","mn","mo","mroot","mrow","ms","msqrt","mstyle","msubsup","mtext"];MathJax.Hub.Register.StartupHook("CommonHTML Jax Ready",function(){var t=MathJax.OutputJax.CommonHTML,r=t.unknownChar;t.Augment({unknownChar:function(){var a=MathJax.Hub.config.Arabic.arabicUnicodeStart,t=MathJax.Hub.config.Arabic.arabicUnicodeEnd,n=r.apply(this,arguments),e=n.n,i=a<=e&&e<=t;return i&&(n.type="char"),n}}),MathJax.Hub.Register.StartupHook("Arabic TeX Ready",function(){var t=MathJax.ElementJax.mml,r=function(a){var r=t[a].prototype.toCommonHTML;t[a].Augment({toCommonHTML:function(){var a=r.apply(this,arguments);if(this.arabicFlipH){var t=document.createElement("span");for(t.className="mfliph","ar"===this.arabicFontLang&&(t.className+=" mar");a.firstChild;)t.appendChild(a.firstChild);a.appendChild(t)}return a}})};["mtr","mtd"].concat(a).forEach(r),MathJax.Hub.Register.StartupHook("CommonHTML multiline Ready",function(){var a=t.mbase.prototype.CHTMLaddLine;t.mbase.Augment({CHTMLaddLine:function(){var t=arguments[0];t&&t.querySelector(".mfliph")&&(t.className="mfliph"),a.apply(this,arguments)}}),MathJax.Hub.Startup.signal.Post("Arabic CommonHTML multiline Ready")}),MathJax.Hub.Register.StartupHook("CommonHTML mtable Ready",function(){r("mtable"),MathJax.Hub.Startup.signal.Post("Arabic CommonHTML mtable Ready")}),MathJax.Hub.Startup.signal.Post("Arabic CommonHTML Ready")})}),MathJax.Hub.Register.StartupHook("HTML-CSS Jax Ready",function(){MathJax.Hub.Register.StartupHook("Arabic TeX Ready",function(){var t=MathJax.ElementJax.mml,r=function(a){var r=t[a].prototype.toHTML;t[a].Augment({toHTML:function(){var a=r.apply(this,arguments);if(this.arabicFlipH){var t=document.createElement("span");for(t.className="mfliph","ar"===this.arabicFontLang&&(t.className+=" mar");a.firstChild;)t.appendChild(a.firstChild);a.appendChild(t)}return a}})};a.forEach(r),MathJax.Hub.Register.StartupHook("HTML-CSS multiline Ready",function(){var a=t.mbase.prototype.HTMLaddLine;t.mbase.Augment({HTMLaddLine:function(){var t=arguments[0];t&&t.querySelector(".mfliph")&&(t.className="mfliph"),a.apply(this,arguments)}}),MathJax.Hub.Startup.signal.Post("Arabic HTML-CSS multiline Ready")}),MathJax.Hub.Register.StartupHook("HTML-CSS mtable Ready",function(){r("mtable"),MathJax.Hub.Startup.signal.Post("Arabic HTML-CSS mtable Ready")}),MathJax.Hub.Startup.signal.Post("Arabic HTML-CSS Ready")})})}(),MathJax.Extension.Arabic={version:"2.1.1",config:MathJax.Hub.CombineConfig("Arabic",{dict:{Zero:["zero","Text",["0","\u0635\u0641\u0631"]],Radius:["radius","Text",["r","\u0646\u0642"]],Area:["Area","Text",["A","\u0645"]],Charge:["charge","TeX",["C","\\fliph{\\text{\u069b}}"]]},identifiersMap:{a:"\u0623",b:"\u0628",c:"\u062c\u0640",x:"\u0633",y:"\u0635",z:"\u0639",n:"\u0646",f:"\u0642",g:"\u062c\u0640",h:"\u0647\u0640",k:"\u0643",r:"\u0631",t:"\u062a",d:"\u062f",e:"\u0647\u0640",m:"\u0645",l:"\u0644",sin:"\u062c\u0627",cos:"\u062c\u062a\u0627",tan:"\u0638\u0627",cot:"\u0638\u062a\u0627",sec:"\u0642\u0627",csc:"\u0642\u062a\u0627",log:"\u0644\u0648"},numbersMap:{0:"\u0660",1:"\u0661",2:"\u0662",3:"\u0663",4:"\u0664",5:"\u0665",6:"\u0666",7:"\u0667",8:"\u0668",9:"\u0669"},arabicUnicodeStart:1536,arabicUnicodeEnd:1791,arabicLanguageRegExp:/([\u0600-\u06FF]+)/g,arabicDecimalSplitter:"\u066b",operatorsMap:{",":"\u060c",";":"\u061b",lim:"\u0646\u0647\u0640\u0640\u0627"},isArabicPage:function(){return"ar"===document.documentElement.lang}}),TeX:function(a,t){return function(r){var n,e=MathJax.InputJax.TeX;n="ar"===this.stack.env.lang?t:a,this.Push(e.Parse(n).mml())}},Text:function(a,t){return MathJax.Extension.Arabic.TeX(a,"\\fliph{\\text{"+t+"}}")},Symbols:function(a,t){var r=t.replace(MathJax.Hub.config.Arabic.arabicLanguageRegExp,"\\fliph{\\text{$1}}");return MathJax.Extension.Arabic.TeX(a,r)},MapNumbers:function(a){var t=MathJax.Hub.config.Arabic.numbersMap,r=function(a){return t[a]};return a.replace(/[0-9]/g,r)}},MathJax.Hub.Startup.signal.Post("Arabic TeX Startup"),MathJax.Hub.Register.StartupHook("TeX Jax Ready",function(){var a=MathJax.InputJax.TeX,t=MathJax.Extension.Arabic,r=a.Parse.prototype.mmlToken,n=MathJax.Hub.config.Arabic.dict,e=function(){var a=/[\\^$.*+?()[\]{}|]/g;return function(t){return t.replace(a,"\\$&")}}(),i=function(a){var t=Object.keys(a).sort(function(a,t){return t.length-a.length});return new RegExp(t.map(e).join("|"),"gi")};a.Definitions.Add({macros:{ar:"HandleArabic",alwaysar:"MarkAsArabic",fliph:"HandleFlipHorizontal",transn:"TranslateNumbers",tmfrac:"TranslateMixedFraction",transx:"TranslateTeX",transt:"TranslateText",transs:"TranslateSymbols"}});var o=a.Stack.Item.array,c=o.prototype.clearEnv,u=o.prototype.Init;o.Augment({Init:function(){u.apply(this,arguments),this.copyEnv=!0},clearEnv:function(){var a=this.env.lang;c.apply(this,arguments),a&&(this.env.lang=a)}}),a.Definitions.Add({macros:function(){var a={};return Object.keys(n).forEach(function(t){var r=n[t][0];a[r]=t}),a}()}),a.Parse.Augment(function(){var a={};return Object.keys(n).forEach(function(r){var e=n[r][1],i=n[r][2];a[r]=t[e].apply(null,i)}),a}()),a.Parse.Augment({flipHorizontal:function(a){return a.arabicFlipH=!a.arabicFlipH,a},arabicNumber:function(a){var r=a.data[0].data[0],n=t.MapNumbers(r);return n!==r&&(a.data[0].data[0]=n,a.arabicFontLang="ar"),this.flipHorizontal(a)},arabicIdentifier:function(){var a=MathJax.Hub.config.Arabic.identifiersMap,t=i(a),r=function(t){return a[t.toLowerCase()]};return function(a){var n=a.data[0].data[0];if("chars"===a.data[0].type){var e=n.replace(t,r);e!==n&&(a.data[0].data[0]=e,a.arabicFontLang="ar")}return this.flipHorizontal(a)}}(),arabicOperator:function(){var a=MathJax.Hub.config.Arabic.operatorsMap,t=i(a),r=function(t){return a[t]};return function(a){var n=a.data[0].data[0],e=n.replace(t,r);return e!==n&&(a=this.flipHorizontal(a),a.arabicFontLang="ar",a.data[0].data[0]=e),a}}(),_getArgumentMML:function(a){var t=this.ParseArg(a);return t.inferred&&1===t.data.length?t=t.data[0]:delete t.inferred,t},mmlToken:function(a){var t=r.call(this,a);return"ar"===this.stack.env.lang&&this.markArabicToken(t),t},markArabicToken:function(a){return"mn"===a.type?this.arabicNumber(a):"mi"===a.type?this.arabicIdentifier(a):"mo"===a.type?this.arabicOperator(a):a},HandleArabic:function(a){MathJax.Hub.config.Arabic.isArabicPage&&this.MarkAsArabic(a)},TranslateTeX:function(a){var r=this.GetArgument(a),n=this.GetArgument(a),e=t.TeX(r,n);return e.call(this,a)},TranslateText:function(a){var r=this.GetArgument(a),n=this.GetArgument(a),e=t.Text(r,n);return e.call(this,a)},TranslateNumbers:function(a){var r=this.GetArgument(a),n=MathJax.Hub.config.Arabic.arabicDecimalSplitter,e=t.MapNumbers(r,!0).replace(/,/g,"").replace(/\./g,n),i=MathJax.Extension.Arabic.TeX(r,"\\fliph{\\text{"+e+"}}");return i.call(this,a)},TranslateSymbols:function(a){var r=this.GetArgument(a),n=this.GetArgument(a),e=t.Symbols(r,n);return e.call(this,a)},TranslateMixedFraction:function(){var a=this.GetArgument(name),t=this.GetArgument(name),r=this.GetArgument(name),n=MathJax.Extension.Arabic.TeX(a+"\\frac{"+t+"}{"+r+"}","\\alwaysar{\\fliph{\\frac{"+t+"}{"+r+"}"+a+"}}");return n.call(this,name)},MarkAsArabic:function(a){var t=this.stack.env.lang;this.stack.env.lang="ar";var r=this._getArgumentMML(a);this.stack.env.lang=t,this.Push(this.flipHorizontal(r))},HandleFlipHorizontal:function(a){var t=this._getArgumentMML(a);this.Push(this.flipHorizontal(t))}}),MathJax.Hub.Startup.signal.Post("Arabic TeX Ready")}),MathJax.Ajax.loadComplete("[arabic]/arabic.js"); -------------------------------------------------------------------------------- /dist/README.md: -------------------------------------------------------------------------------- 1 | # MathJax Arabic Extension 2 | This is an extension to MathJax (v2.5+), that provides basic Arabic support to MathJax. 3 | 4 | The extension so far only supports TeX input with HTML-CSS output. However, support to other input and output 5 | jaxes is possible. 6 | 7 | ## Key Features 8 | It provides the following: 9 | 10 | - Flip the Equation and render it the Right-to-left (RTL) way! 11 | - Translate commonly used identifiers and functions. 12 | 13 | ## How to Use the Extension 14 | ### Install the Extension 15 | First you'd like to [install](http://mathjax.readthedocs.org/en/latest/installation.html) 16 | and [configure](http://mathjax.readthedocs.org/en/latest/configuration.html) MathJax in your page. 17 | 18 | Then you'll need to include the `arabic.js` as an extension, here's an example configuration: 19 | 20 | MathJax.Ajax.config.path["arabic"] = "https://cdn.rawgit.com/OmarIthawi/arabic-mathjax/v1.2/dist"; 21 | 22 | MathJax.Hub.Config({ 23 | extensions: [ 24 | "[arabic]/arabic.js" 25 | ] 26 | }); 27 | 28 | 29 | ### The Amiri Font 30 | The extension relies (sort of) on the 31 | [Amiri font](https://www.google.com/fonts#UsePlace:use/Collection:Amiri) 32 | to render beautifully (kinda). 33 | 34 | One way to include the font is to add the following CSS from Google Fonts: 35 | 36 | 37 | 38 | 39 | Also you'd like to set the font as the undefined family. Because of a bug in MathJax, you should stick with a single 40 | font-family e.g. use `Amiri` or `serif` but not `Amiri, serif`. 41 | 42 | MathJax.Hub.Config({ 43 | 'HTML-CSS': { 44 | undefinedFamily: 'Amiri' 45 | } 46 | }); 47 | 48 | ### Typeset an Arabic Equation 49 | The extension provides the following additional TeX commands to be typeset an Arabic equation: 50 | 51 | 1. **`\alwaysar`** 52 | 53 | `\alwaysar{EQUATION}` A macro to translate and RTL'ize an `EQUATION`, where `EQUATION` can be anything from 54 | `x = 1` to `e^x=\lim_{n\to\infty}`. 55 | 56 | Wrap any TeX equation with it, and it *should* just work. 57 | 58 | 2. **`\ar`** 59 | 60 | `\ar{EQUATION}` (**Recommended**) A similar macro to `\alwaysar{EQUATION}`, but it only translate and RTL'ize the equation if the page is Arabic. 61 | 62 | Bellow is an example equation: 63 | 64 | \ar{x=1} 65 | 66 | The above would render **x=1** beautifully in an English page, while it should render **س=١** in an Arabic page 67 | even more beautifully ( in my opinion :) ). 68 | 69 | ## Supported Features 70 | - Flip everything (almost) including: 71 | * Parentheses `()`, braces `{}`, and brackets `[]` 72 | * Things that should be flipped like: Integration `∫`, Root `√` and Sigma `Σ` 73 | 74 | - Doesn't flip the things that should't be flipped, 75 | like the following letters: Theta `Θ`, Pi `π`, and Epsilon `ε` 76 | 77 | - Translate the basic math functions: 78 | * `\sin` --> `جا` 79 | * `\cos` --> `تا` 80 | * `\tan` --> `ظا` 81 | * `\cot` --> `ظتا` 82 | * `\sec` --> `قا` 83 | * `\csc` --> `قتا` 84 | * `\log` --> `لو` 85 | 86 | 87 | - Translate `\lim` into `نها`, Although some would prefer `غــا`, but that's just 88 | a preference, may someone can patch it to support `ar_IQ` for the Iraqi people! 89 | 90 | - Render the Arabic numbers (١, ٢, ٣) instead of (1, 2, 3), which is awesome! 91 | 92 | - The following new commands: 93 | * **Circle radius:** `\radius` Translates to `r` and `نق` 94 | * **Area of circle:** (and other stuff) `\Area` Translates to `A` and `م` 95 | * **Arabic Zero:** `\zero` Renders the `صفر`in Arabic while printing normal `0` in English. 96 | The former is usually preferred by the Arabic Math textbooks. 97 | * **Charge Sheen Character:** `\charge` Renders the 98 | [`ڛ` (Unicode U+069B)](https://www.compart.com/en/unicode/U+069B) 99 | character in Arabic while printing `C` in English. 100 | 101 | This sheen character is then replaced by a more appropriate Ruqa (رقعة) character, when using 102 | the [modified Amiri font](https://github.com/OmarIthawi/amiri/releases). 103 | 104 | - Bilingual commands, which prints the first argument on English pages and the second argument on Arabic pages. 105 | Useful to to build bilingual equations for strings that the extension provides no explicit support to. 106 | **Note** The first (English) argument is always a TeX input, while the second (Arabic) can be 107 | TeX, Text or TeX with Symbols, depending on the command you're using. 108 | * **Translate a TeX input** `\transx` 109 | * **Translate a text input** `\transt` e.g. `\transt{\text{if}}{إذا}` for the Math piecewise equations. 110 | * **Translate a TeX input with Arabic symbols** `\transs`: e.g. `\transs{A_b}{أ_ب}` 111 | * **Translate Arabic numbers** `\transn`: e.g. `\transn{2000,000.195}` 112 | * **Translate Mixed Fractions** `\tmfrac`: e.g. `\tmfrac{10}{1}{2}` to denote `10.5` as a mixed fraction 113 | 114 | - Basic variable and function names translation: 115 | * `A` --> `أ` 116 | * `B` --> `ب` 117 | * `C` --> `حـ` 118 | * `a` --> `ا` 119 | * `b` --> `ب` 120 | * `c` --> `حـ` 121 | * `d` --> `د` 122 | * `e` --> `هـ` 123 | * `m` --> `م` 124 | * `l` --> `ل` 125 | * `n` --> `ن` 126 | * `f` --> `ق` 127 | * `g` --> `حـ` 128 | * `h` --> `هـ` 129 | * `k` --> `ك` 130 | * `r` --> `ر` 131 | * `t` --> `ت` 132 | * `x` --> `س` 133 | * `y` --> `ص` 134 | * `z` --> `ع` 135 | 136 | 137 | - Translation to other identifiers and operators like limits (`\lim`), sine, cosine and tan. 138 | 139 | 140 | - A very configurable translation utility to provide English/Arabic TeX 141 | commands (same command, with language-dependent output). 142 | 143 | - A configurable page language detection (defaults to the `lang` attribute of `` tag). 144 | 145 | - It is generally configurable, but I haven't documented how to do it! 146 | 147 | ## Experimental Stuff 148 | Additional extensions for Physics and some Chemistry units and symbols exists, 149 | however, it is not tested/developed well. If you're curious, you can take a look 150 | at the following extensions: 151 | 152 | - [`phys1.js`](https://github.com/OmarIthawi/arabic-mathjax/blob/master/testcases/test-extensions/phys1.js): 153 | Contains general physics units like Farad and speed of light. Interesting stuff, but haven't had proper 154 | testing and usage (yet). 155 | 156 | - [`phys2.js`](https://github.com/OmarIthawi/arabic-mathjax/blob/master/testcases/test-extensions/phys2.js): 157 | Additional advanced physics units that I don't understand as much! 158 | 159 | - [`hacks.js`](https://github.com/OmarIthawi/arabic-mathjax/blob/master/testcases/test-extensions/hacks.js): 160 | A hack to convert the English decimal mark from `.` to `٫` 161 | ([Arabic decimal mark, Unicode 0x066b](http://www.unicodemap.org/details/0x066B/index.html)). 162 | Although the Arabic decimal mark exists, I'm not sure if it is 163 | [common enough](https://en.wikipedia.org/wiki/Decimal_mark#Countries_using_Arabic_numerals_with_decimal_comma) 164 | to include it in the main installation. 165 | 166 | # How to Contribute 167 | Well, just issue a pull request to this repo and ping me (my GitHub username is @OmarIthawi). 168 | Even better, grab my docker-based development environment from here so you can have a better development experience: 169 | 170 | $ git clone https://github.com/OmarIthawi/arabic-mathjax.git 171 | $ cd arabic-mathjax 172 | $ git clone git@github.com:mathjax/MathJax mathjax 173 | $ cd mathjax 174 | $ git checkout 2.7.1 175 | $ cd .. 176 | $ make init 177 | $ docker-compose up 178 | 179 | 180 | # License 181 | The MIT License 182 | 183 | Copyright (c) 2015-2016 Edraak.org, Omar Al-Ithawi and contributors. 184 | 185 | # Author 186 | 187 | - Omar Al-Ithawi 188 | 189 | # A bit of a Background 190 | Why this plugin exists? Well, I could tell you an interesting story like I wanted to change the world, 191 | but frankly we needed it to display Math equations for our Arabic learners at [Edraak.org](https://www.edraak.org), 192 | and therefore I made it. 193 | 194 | Well, it does change the world somehow, at the least in the eyes of our learners ^\_^ 195 | 196 | # Fork Info 197 | The original repository is: 198 | - https://github.com/Edraak/arabic-mathjax 199 | 200 | This fork aims to be more updated and supported. 201 | -------------------------------------------------------------------------------- /testcases/responsive.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Arabic.js Responsive Test Case 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 36 | 37 | 38 | 65 | 66 | 112 | 113 | 114 | 177 | 178 | 179 | 180 |
181 | 182 | 183 |
184 | 185 |
186 | 189 | 190 |
191 | 192 | 195 | 196 |
197 | 198 | 201 | 202 |
203 | 204 | 207 | 208 |
209 | 210 | 213 |
214 | 229 |
230 | 231 | 232 | -------------------------------------------------------------------------------- /src/tex.js: -------------------------------------------------------------------------------- 1 | MathJax.Extension.Arabic = { 2 | version: '2.1.1', 3 | config: MathJax.Hub.CombineConfig("Arabic", { 4 | dict: { 5 | // A macros to force English zero in both languages 6 | 'Zero': ['zero', 'Text', ['0', 'صفر']], // Better localized Zero 7 | 'Radius': ['radius', 'Text', ['r', 'نق']], // Circle radius 8 | 'Area': ['Area', 'Text', ['A', 'م']], // Area of circles and other stuff 9 | 10 | // Used for special charge character in the modified Amiri font: 11 | // - https://github.com/OmarIthawi/amiri/releases 12 | // This only will work when activating that font. 13 | 'Charge': ['charge', 'TeX', ['C', '\\fliph{\\text{ڛ}}']], 14 | }, 15 | identifiersMap: { 16 | // Variable names 17 | 'a': 'أ', 18 | 'b': 'ب', // TODO: Consider using Arabic letter dotless beh 0x66e instead 19 | 'c': 'جـ', // Suffixed with Unicode Arabic Tatweel 0x0640 20 | 'x': 'س', 21 | 'y': 'ص', 22 | 'z': 'ع', 23 | 'n': 'ن', 24 | 25 | // Function names 26 | 'f': 'ق', // TODO: Consider using dotless qaf (ٯ) instead 27 | 'g': 'جـ', // With Unicode Arabic Tatweel 0x0640 28 | 'h': 'هـ', // With Unicode Arabic Tatweel 0x0640 29 | 30 | // Mixed use 31 | 'k': 'ك', 32 | 'r': 'ر', 33 | 't': 'ت', 34 | 'd': 'د', // Function, variable and (dx) 35 | 'e': 'هـ', // With Unicode Arabic Tatweel 0x0640 36 | 'm': 'م', 37 | 'l': 'ل', 38 | 39 | // Math functions 40 | 'sin': 'جا', 41 | 'cos': 'جتا', 42 | 'tan': 'ظا', 43 | 'cot': 'ظتا', 44 | 'sec': 'قا', 45 | 'csc': 'قتا', 46 | 'log': 'لو' 47 | }, 48 | numbersMap: { 49 | '0': '٠', 50 | '1': '١', 51 | '2': '٢', 52 | '3': '٣', 53 | '4': '٤', 54 | '5': '٥', 55 | '6': '٦', 56 | '7': '٧', 57 | '8': '٨', 58 | '9': '٩' 59 | }, 60 | arabicUnicodeStart: 0x600, 61 | arabicUnicodeEnd: 0x6FF, 62 | arabicLanguageRegExp: /([\u0600-\u06FF]+)/g, 63 | arabicDecimalSplitter: '٫', // Used by `\transn` 64 | operatorsMap: { 65 | // English to Arabic punctuations 66 | ',': '،', 67 | ';': '؛', 68 | // Limits 69 | 'lim': 'نهــا' 70 | }, 71 | isArabicPage: function () { 72 | return document.documentElement.lang === 'ar'; 73 | } 74 | }), 75 | TeX: function (english, arabic) { 76 | // Creates a translated TeX macro. 77 | 78 | return function (name) { 79 | var TEX = MathJax.InputJax.TeX; 80 | 81 | var tex; 82 | if ('ar' === this.stack.env.lang) { 83 | tex = arabic; 84 | } else { 85 | tex = english; 86 | } 87 | 88 | this.Push(TEX.Parse(tex).mml()); 89 | }; 90 | }, 91 | Text: function (english, arabicText) { 92 | // Creates a translated TeX macro, with an Arabic plain text. 93 | 94 | return MathJax.Extension.Arabic.TeX(english, '\\fliph{\\text{' + arabicText + '}}'); 95 | }, 96 | Symbols: function (english, arabicSymbols) { 97 | // Creates a translated TeX macro that converts Arabic symbols into text nodes, 98 | // and treats everything else as normal TeX. 99 | var arabic = arabicSymbols.replace( 100 | MathJax.Hub.config.Arabic.arabicLanguageRegExp, 101 | '\\fliph{\\text{$1}}' 102 | ); 103 | 104 | return MathJax.Extension.Arabic.TeX(english, arabic); 105 | }, 106 | MapNumbers: function (text) { 107 | var numbersMap = MathJax.Hub.config.Arabic.numbersMap; 108 | 109 | var replaceNumber = function (m) { 110 | return numbersMap[m]; 111 | }; 112 | 113 | return text.replace(/[0-9]/g, replaceNumber); 114 | } 115 | }; 116 | 117 | 118 | MathJax.Hub.Startup.signal.Post('Arabic TeX Startup'); 119 | 120 | 121 | MathJax.Hub.Register.StartupHook('TeX Jax Ready', function () { 122 | var TEX = MathJax.InputJax.TeX; 123 | var Arabic = MathJax.Extension.Arabic; 124 | 125 | var texParseMMLToken = TEX.Parse.prototype.mmlToken; 126 | var dict = MathJax.Hub.config.Arabic.dict; 127 | 128 | var escapeRegExp = (function () { 129 | var regExpChar = /[\\^$.*+?()[\]{}|]/g; 130 | 131 | return function (string) { 132 | return string.replace(regExpChar,'\\$&'); 133 | }; 134 | }()); 135 | 136 | var getKeysRegExp = function (map) { 137 | var keys = Object.keys(map).sort(function (a, b) { 138 | return b.length - a.length; 139 | }); 140 | 141 | return new RegExp(keys.map(escapeRegExp).join('|'), 'gi'); 142 | }; 143 | 144 | 145 | TEX.Definitions.Add({ 146 | macros: { 147 | 'ar': 'HandleArabic', 148 | 'alwaysar': 'MarkAsArabic', 149 | 'fliph': 'HandleFlipHorizontal', 150 | 'transn': 'TranslateNumbers', 151 | 'tmfrac': 'TranslateMixedFraction', 152 | 'transx': 'TranslateTeX', 153 | 'transt': 'TranslateText', 154 | 'transs': 'TranslateSymbols' 155 | } 156 | }); 157 | 158 | var array = TEX.Stack.Item.array; 159 | var arrayClearEnv = array.prototype.clearEnv; 160 | var arrayInit = array.prototype.Init; 161 | 162 | array.Augment({ 163 | Init: function () { 164 | // Overcome the copyEnv issue that has been introduced in: 165 | // - Pull Request: https://github.com/mathjax/MathJax/pull/1523 166 | // 167 | // Otherwise arrays won't be Arabized. 168 | // - Bug Report: https://groups.google.com/forum/#!topic/mathjax-dev/cWoTKcwMqmY 169 | arrayInit.apply(this, arguments); 170 | this.copyEnv = true; 171 | }, 172 | clearEnv: function () { 173 | // Propagate `lang` from Arrays to their children fractions and others. 174 | // This is a bug in the MathJax itself, so this code should be removed once the bug is fixed. 175 | // Follow up on https://github.com/mathjax/MathJax/pull/1523 176 | // It's still not clear how/when a proper solution is possible. 177 | var lang = this.env.lang; 178 | 179 | arrayClearEnv.apply(this, arguments); 180 | 181 | if (lang) { 182 | this.env.lang = lang; 183 | } 184 | } 185 | }); 186 | 187 | TEX.Definitions.Add({ 188 | macros: function () { 189 | var definitions = {}; 190 | 191 | Object.keys(dict).forEach(function (key) { 192 | var texCommand = dict[key][0]; 193 | definitions[texCommand] = key; 194 | }); 195 | 196 | return definitions; 197 | }() 198 | }); 199 | 200 | 201 | TEX.Parse.Augment(function () { 202 | var parsers = {}; 203 | 204 | Object.keys(dict).forEach(function (key) { 205 | var helperName = dict[key][1]; // Text, TeX or Symbols 206 | var helperParams = dict[key][2]; 207 | 208 | parsers[key] = Arabic[helperName].apply(null, helperParams); 209 | }); 210 | 211 | return parsers; 212 | }()); 213 | 214 | 215 | TEX.Parse.Augment({ 216 | flipHorizontal: function (token) { 217 | token.arabicFlipH = !token.arabicFlipH; 218 | // Invert the value, because flipping twice means, it is not flipped 219 | return token; 220 | }, 221 | arabicNumber: function (token) { 222 | var text = token.data[0].data[0]; 223 | var mapped = Arabic.MapNumbers(text); 224 | 225 | if (mapped !== text) { 226 | token.data[0].data[0] = mapped; 227 | token.arabicFontLang = 'ar'; 228 | } 229 | 230 | return this.flipHorizontal(token); 231 | }, 232 | arabicIdentifier: (function () { 233 | var identifiersMap = MathJax.Hub.config.Arabic.identifiersMap; 234 | var identifiersKeysRegExp = getKeysRegExp(identifiersMap); 235 | 236 | var replaceIdentifier = function (m) { 237 | return identifiersMap[m.toLowerCase()]; 238 | }; 239 | 240 | return function (token) { 241 | var text = token.data[0].data[0]; 242 | 243 | if ('chars' === token.data[0].type) { 244 | // English Symbols like X and Y 245 | var mapped = text.replace(identifiersKeysRegExp, replaceIdentifier); 246 | 247 | if (mapped !== text) { 248 | token.data[0].data[0] = mapped; 249 | token.arabicFontLang = 'ar'; 250 | } 251 | } 252 | 253 | return this.flipHorizontal(token); 254 | } 255 | }()), 256 | arabicOperator: (function () { 257 | var operatorsMap = MathJax.Hub.config.Arabic.operatorsMap; 258 | var operatorsKeysRegExp = getKeysRegExp(operatorsMap); 259 | 260 | var replaceOperator = function (m) { 261 | return operatorsMap[m]; 262 | }; 263 | 264 | return function (token) { 265 | var text = token.data[0].data[0]; 266 | var mapped = text.replace(operatorsKeysRegExp, replaceOperator); 267 | 268 | if (mapped !== text) { 269 | token = this.flipHorizontal(token); 270 | token.arabicFontLang = 'ar'; 271 | token.data[0].data[0] = mapped; 272 | } 273 | 274 | return token; 275 | } 276 | }()), 277 | _getArgumentMML: function (name) { 278 | // returns an argument that is a single MathML element 279 | // (in an mrow if necessary) 280 | // 281 | // This functions has been copied here from extensions/TeX/HTML.js, to avoid 282 | // adding a dependency. 283 | // 284 | // TODO: Consider importing (as a dependency) this from HTML.js instead! 285 | var arg = this.ParseArg(name); 286 | if (arg.inferred && arg.data.length === 1) { 287 | arg = arg.data[0]; 288 | } else { 289 | delete arg.inferred; 290 | } 291 | 292 | return arg; 293 | }, 294 | mmlToken: function (token) { 295 | // TODO: Check for possible incompatibility with boldsymbol extension 296 | var parsedToken = texParseMMLToken.call(this, token); 297 | 298 | if ('ar' === this.stack.env.lang) { 299 | this.markArabicToken(parsedToken); 300 | } 301 | 302 | return parsedToken; 303 | }, 304 | markArabicToken: function (token) { 305 | if ('mn' === token.type) { 306 | return this.arabicNumber(token); 307 | } else if ('mi' === token.type) { 308 | return this.arabicIdentifier(token); 309 | } else if ('mo' === token.type) { 310 | return this.arabicOperator(token); 311 | } 312 | 313 | return token; 314 | }, 315 | HandleArabic: function (name) { 316 | if (MathJax.Hub.config.Arabic.isArabicPage) { 317 | this.MarkAsArabic(name); 318 | } 319 | }, 320 | TranslateTeX: function (name) { 321 | var english = this.GetArgument(name); 322 | var arabicText = this.GetArgument(name); 323 | var helper = Arabic.TeX(english, arabicText); 324 | return helper.call(this, name); 325 | }, 326 | TranslateText: function (name) { 327 | var english = this.GetArgument(name); 328 | var arabicText = this.GetArgument(name); 329 | var helper = Arabic.Text(english, arabicText); 330 | return helper.call(this, name); 331 | }, 332 | TranslateNumbers: function (name) { 333 | var english = this.GetArgument(name); 334 | var arabicDecimalSplitter = MathJax.Hub.config.Arabic.arabicDecimalSplitter; 335 | 336 | var arabicNumbers = Arabic.MapNumbers(english, true) 337 | .replace(/,/g, '') 338 | .replace(/\./g, arabicDecimalSplitter); 339 | 340 | var helper = MathJax.Extension.Arabic.TeX( 341 | english, '\\fliph{\\text{' + arabicNumbers + '}}' 342 | ); 343 | return helper.call(this, name); 344 | }, 345 | TranslateSymbols: function (name) { 346 | var english = this.GetArgument(name); 347 | var arabicText = this.GetArgument(name); 348 | var helper = Arabic.Symbols(english, arabicText); 349 | return helper.call(this, name); 350 | }, 351 | TranslateMixedFraction: function () { 352 | var integer = this.GetArgument(name); 353 | var numerator = this.GetArgument(name); 354 | var denominator = this.GetArgument(name); 355 | 356 | var tex = MathJax.Extension.Arabic.TeX( 357 | integer + '\\frac{' + numerator + '}{' + denominator + '}', 358 | '\\alwaysar{\\fliph{\\frac{' + numerator + '}{' + denominator + '}' + integer + '}}' 359 | ); 360 | 361 | return tex.call(this, name); 362 | }, 363 | MarkAsArabic: function (name) { 364 | var originalLang = this.stack.env.lang; 365 | 366 | this.stack.env.lang = 'ar'; 367 | var arg = this._getArgumentMML(name); 368 | 369 | this.stack.env.lang = originalLang; // Reset the language for other elements. 370 | 371 | this.Push(this.flipHorizontal(arg)); 372 | }, 373 | HandleFlipHorizontal: function (name) { 374 | var arg = this._getArgumentMML(name); 375 | this.Push(this.flipHorizontal(arg)); 376 | } 377 | }); 378 | 379 | MathJax.Hub.Startup.signal.Post('Arabic TeX Ready'); 380 | }); 381 | -------------------------------------------------------------------------------- /testcases/testcases.yml: -------------------------------------------------------------------------------- 1 | equations: 2 | - id: "1" 3 | name: "Fraction 1" 4 | equation: > 5 | x=\frac{11+y}{1+2z^2} 6 | 7 | - id: "2" 8 | name: "Fraction 2" 9 | equation: > 10 | x=\frac{1+y}{1+2z^2} 11 | 12 | - id: "3" 13 | name: "Fraction 3" 14 | equation: > 15 | x=\frac{1+y}{1+2x^2} 16 | 17 | - id: "4" 18 | name: "Big fraction" 19 | equation: > 20 | 2 = \left( \frac{\left(3-x\right) \times 2}{3-x} \right) 21 | 22 | - id: "5" 23 | name: "Square" 24 | equation: > 25 | x={-b\pm\sqrt{b^2-4ac} \over 2a} 26 | 27 | - id: "6" 28 | name: "Integration" 29 | equation: > 30 | \int_\zero^\infty e^{-x^2} dx=\frac{\sqrt{\pi}}{2} 31 | 32 | - id: "7" 33 | name: "Superscript and subscript" 34 | equation: > 35 | x = 10^{20}_5 36 | 37 | - id: "8" 38 | name: "Sum" 39 | equation: > 40 | \sum_{n=1}^\infty {1\over n^2} = {\pi^2\over 6} 41 | 42 | - id: "9" 43 | name: "Lightspeed" 44 | experimental: yes 45 | equation: > 46 | \lspeed = 299792458{m \over \scnd} 47 | 48 | - id: "10" 49 | name: "Initial charge" 50 | equation: > 51 | q = 10 52 | 53 | - id: "11" 54 | name: "Energy" 55 | equation: > 56 | E = x 57 | 58 | - id: "12" 59 | name: "Meter" 60 | experimental: yes 61 | equation: > 62 | x = 10m + 20\cm 63 | 64 | - id: "13" 65 | name: "Misc symbols A" 66 | experimental: yes 67 | equation: > 68 | a = \epsilonzero + \varepsilon 69 | 70 | - id: "14" 71 | name: "Misc symbols B" 72 | equation: > 73 | b = \phi + \lambda + \theta + \Phi 74 | 75 | - id: "15" 76 | name: "Misc symbols C" 77 | equation: > 78 | c = \eta + € 79 | 80 | - id: "16" 81 | name: "Plancks and Boltzmanns" 82 | experimental: yes 83 | equation: > 84 | \Plancks \neq \Boltzmanns 85 | 86 | - id: "17" 87 | name: "Air Mass" 88 | experimental: yes 89 | equation: > 90 | \AM = x 91 | 92 | - id: "18" 93 | name: "Radiation" 94 | experimental: yes 95 | equation: > 96 | \rad = x 97 | 98 | - id: "19" 99 | name: "Amplifiers" 100 | experimental: yes 101 | equation: > 102 | 1\Mega, 2\nano, 3\Giga, 4\Tera, 3\kilo, 20\micro 103 | 104 | - id: "20" 105 | name: "Electricity" 106 | experimental: yes 107 | equation: > 108 | \Watt = \Amp \times \volt 109 | 110 | - id: "21" 111 | name: "Sine and Cosine" 112 | equation: > 113 | \tan \theta = {\cos \theta \over \sin \theta} 114 | 115 | - id: "22" 116 | name: "Temrature" 117 | experimental: yes 118 | equation: > 119 | \Tmpr = 10\Klvn 120 | 121 | - id: "23" 122 | name: "Current" 123 | experimental: yes 124 | equation: > 125 | \current = 10\Amp 126 | 127 | - id: "24" 128 | name: "ER #1" 129 | experimental: yes 130 | equation: > 131 | \er 132 | 133 | - id: "24.b" 134 | name: "ER #2" 135 | experimental: yes 136 | equation: > 137 | \er = x 138 | 139 | - id: "25" 140 | name: "The J stuff" 141 | experimental: yes 142 | equation: > 143 | \J_\zero, \J_\ph, \J_\diffe, \J_\sc 144 | 145 | - id: "26" 146 | name: "Voltage of Open Circuit" 147 | experimental: yes 148 | equation: > 149 | \V_\oc 150 | 151 | - id: "27" 152 | name: "Concentation Stuff" 153 | experimental: yes 154 | equation: > 155 | \NA, \ND, \nii 156 | 157 | - id: "28" 158 | name: "Deplation Area" 159 | experimental: yes 160 | equation: > 161 | \Wd = x 162 | 163 | - id: "29" 164 | name: "Farad" 165 | experimental: yes 166 | equation: > 167 | \F = {{\scnd^4 \cdot \Amp^2} \over {\kilo\grm \cdot m^2}} 168 | 169 | - id: "30" 170 | name: "Diffusion Length" 171 | experimental: yes 172 | equation: > 173 | \Ld = 10m 174 | 175 | - id: "31" 176 | name: "Electrons Diffusion" 177 | experimental: yes 178 | equation: > 179 | \D_\ek 180 | 181 | - id: "32" 182 | name: "Electrons Motion Constant" 183 | experimental: yes 184 | equation: > 185 | \mue 186 | 187 | - id: "33" 188 | name: "Hole" 189 | experimental: yes 190 | equation: > 191 | 20\hole 192 | 193 | - id: "34" 194 | name: "Electrons" 195 | experimental: yes 196 | equation: > 197 | 2 \elctrn 198 | 199 | - id: "35" 200 | name: "Time" 201 | experimental: yes 202 | equation: > 203 | 1\year = 365.25\day, 1\day = 24\hour 204 | 205 | - id: "36" 206 | name: "Max Watt" 207 | experimental: yes 208 | equation: > 209 | \Watt_\max 210 | 211 | - id: "37" 212 | name: "Fill Factor" 213 | experimental: yes 214 | equation: > 215 | \FF 216 | 217 | - id: "38" 218 | name: "Photovoltaic Energy" 219 | experimental: yes 220 | equation: > 221 | \P_\inn 222 | 223 | - id: "39" 224 | name: "Limits" 225 | equation: > 226 | e^x=\lim_{n\to\infty} \left( 1+\frac{x}{n} \right)^n 227 | 228 | - id: "40" 229 | name: "Limits #2" 230 | equation: > 231 | e^x=\lim_{4578545n\to\infty} y 232 | 233 | - id: "41" 234 | name: "F prime of x" 235 | equation: > 236 | y = f^\prime(x) 237 | 238 | - id: "42" 239 | name: "F double prime of x" 240 | equation: > 241 | y = f^{\prime\prime}(x) 242 | 243 | - id: "43" 244 | name: "F triple prime of x" 245 | equation: > 246 | y = f^{\prime\prime\prime}(x) 247 | 248 | - id: "44" 249 | name: "Matrix" 250 | equation: > 251 | \left[ \begin{array}{rr} 5 & -2 \\ 3 & \zero \end{array} \right] 252 | 253 | - id: "45" 254 | name: "Matrix #2" 255 | equation: > 256 | \left[ \begin{array}{rr} 1 & 4 \\ 10 & 7 \end{array} \right] 257 | 258 | - id: "46" 259 | name: "Matrix #3" 260 | equation: > 261 | \left[ \begin{array}{rr} 5 & -2 & 5 \\ 5 && -2 \\ 3 & \zero & 10 \end{array} \right] 262 | 263 | - id: "47" 264 | name: "Piecewise (Branched) function #1" 265 | equation: > 266 | x = \left\{\begin{array}{l} a + b = 0\\ \varphi a + \psi b = 1\end{array}\right. 267 | 268 | - id: "48" 269 | name: "Log" 270 | equation: > 271 | \log_b(xy) = \log_b (x) + \log_b (y), \, 272 | 273 | - id: "49" 274 | name: "Union and Intersection" 275 | equation: > 276 | A \cup B \cap C 277 | 278 | - id: "50" 279 | name: "Some signs" 280 | equation: > 281 | A \ne B \leq C \not\subset \Delta 282 | 283 | - id: "51" 284 | name: "More vars" 285 | equation: > 286 | l \neq m 287 | 288 | - id: "52" 289 | name: "Area and Radius" 290 | equation: > 291 | \Area = \pi\radius^2 292 | 293 | - id: "54" 294 | name: "Stretchy Arrow" 295 | equation: > 296 | \xrightarrow{\Delta A + \radius^{20}}\ =\ \xrightarrow{B} 297 | 298 | - id: "55" 299 | name: "Function composition" 300 | equation: > 301 | (g \circ h)(x) = h(g(x)) 302 | 303 | - id: "66" 304 | name: "Piecewise Function #2" 305 | equation: > 306 | f(x) = \left\{\begin{array}{l} \left[ {1 \over 2}x + 2 \right] \ , 2 \le x \lt 4 \\ { \left| 4x \right| \over x^2-36 } \ , x \ge 4 \end{array}\right. 307 | 308 | - id: "67" 309 | name: "Piecewise Function #3" 310 | equation: > 311 | f(x) = \left\{ \begin{array}{l} ax^2 - bx \ , x \lt 3 \\ a x^3+6bx-9 \ , x\ge3 \end{array}\right. 312 | 313 | - id: "68" 314 | name: "Piecewise function #4 (Arabic)" 315 | equation: > 316 | x = \left\{\begin{array}{l} abc + 10 \\ xyz + 20 \end{array}\right. 317 | 318 | - id: "70" 319 | name: "Polynomial" 320 | equation: > 321 | f(x) = ax^3+6bx-9 322 | 323 | - id: "71" 324 | name: "Array (Table)" 325 | equation: > 326 | q(x) = \begin{array}{l} 1y & {z \over a - 2} \\ be^3 & {c \over g - 4} \end{array} 327 | 328 | - id: "72" 329 | name: "Bare bones array" 330 | equation: > 331 | \begin{array}{l} 5 \\ h^6 \end{array} 332 | 333 | - id: "73" 334 | name: "Cases (Piecewise) Environment" 335 | equation: > 336 | |x| = \begin{cases} x & \transt{\text{ if }}{ إذا } x \ge 0 \\ -x & \transt{\text{ if }}{ إذا } x \lt 0 \end{cases} 337 | 338 | - id: "74" 339 | name: "Parenthesis Matrix" 340 | equation: > 341 | \begin{pmatrix} aaa & b\cr c & ddd \end{pmatrix} 342 | 343 | - id: "78" 344 | name: "More Math Functions" 345 | equation: > 346 | \cot x , \sec y , \csc z 347 | 348 | - id: "79" 349 | name: "Single Square Root" 350 | equation: > 351 | \sqrt{2} 352 | 353 | - id: "80" 354 | name: "Semi colon" 355 | equation: > 356 | x=y; y=0 357 | 358 | - id: "81" 359 | name: "Single right arrow" 360 | equation: > 361 | a \rightarrow b 362 | 363 | - id: "82" 364 | name: "Factorial" 365 | equation: > 366 | n! 367 | 368 | - id: "83" 369 | name: "Cube Root" 370 | equation: > 371 | \sqrt[3]{2} 372 | 373 | - id: "84" 374 | name: "Upper case XYZ" 375 | equation: > 376 | f(x) = (X \times Y \times Z) \, \transt{\text{or}}{أو} \, (XYZ) 377 | 378 | - id: "85" 379 | name: "Partially Arabic (It should display: س=١ x=1)" 380 | note: " (It's OK to break, check the code Comments)" 381 | # Ref: https://github.com/mathjax/MathJax-third-party-extensions/pull/20#discussion_r63028905 382 | hide_arabic: True 383 | equation: > 384 | \alwaysar{x=1} \, x=1 385 | 386 | - id: "86" 387 | name: "Charge Character" 388 | note: "Renders the special-sheen character in Arabic" 389 | equation: > 390 | \charge = 1 391 | 392 | - id: "87" 393 | name: Colored equations 394 | note: 395 | equation: > 396 | \textcolor{blue}{3}a^\textcolor{coral}{2}-\textcolor{blue}{5}b^\textcolor{coral}{\frac{1}{2}\cdot3}. 397 | 398 | - id: "88" 399 | name: Derivative 400 | note: 401 | equation: > 402 | \displaystyle\int \dfrac{e^x}{1+e^{2x}}\,dx. 403 | 404 | - id: "89" 405 | name: Array 406 | note: 407 | equation: > 408 | \begin{array}{rrrrr}3x&{}+2y&{}+z&\\-4x&+y&&-7\\\hline -x&+3y&+z&-7\end{array} 409 | 410 | - id: "90" 411 | name: Aligned part no. 1 412 | note: 413 | equation: > 414 | A = \begin{bmatrix}a_{11} & a_{12} & \dots \\\vdots & \ddots & \\a_{K1} && a_{KK}\end{bmatrix} 415 | 416 | - id: "91" 417 | name: Alignment part no. 2 418 | note: 419 | equation: > 420 | \left(\smash{\underbrace{\left[\begin{array}{ccc}a&b&c\\d&e&f\\g&h&i\end{array}\right]}_{A}}\left[\begin{array}{c}x_1\\x_2\\x_3\end{array}\right]\right)\\\\\\\\ 421 | 422 | - id: "92" 423 | name: Strikethroughs using the \enclose extension (and limits) 424 | note: 425 | equation: > 426 | \require{enclose}\small\begin{align}\lim\limits_{x \to 5} \frac{x-5}{x^2-25}&=\lim\limits_{x \to 5} \frac{x-5}{(x-5)(x+5)}\\\\&=\lim\limits_{x \to 5} \frac{\enclose{horizontalstrike}{x-5}}{\enclose{horizontalstrike}{(x-5)}(x+5)}\\\\&=\lim\limits_{x \to 5} \frac{1}{x+5}\\\\&=\frac{1}{5+5}=\frac{1}{10}\end{align} 427 | 428 | - id: "93" 429 | name: Small 430 | note: 431 | equation: > 432 | \small\dfrac{df}{dt}=\lim\limits_{h\to0}\dfrac{f(t+h)-f(t)}{h} 433 | 434 | - id: "94" 435 | name: Scriptsize 436 | note: 437 | equation: > 438 | \scriptsize\dfrac{df}{dt}=\lim\limits_{h\to0}\dfrac{f(t+h)-f(t)}{h} 439 | 440 | - id: "95" 441 | name: Tiny 442 | note: 443 | equation: > 444 | \tiny\dfrac{df}{dt}=\lim\limits_{h\to0}\dfrac{f(t+h)-f(t)}{h} 445 | 446 | - id: "96" 447 | name: Lots of symbols 448 | note: 449 | equation: > 450 | \begin{align}\sum_{k=1}^xf(k)={}&C+\int_0^xf(t)\,dt+\frac{1}{2}f(x)\\&+\sum_{k=1}^\infty\frac{B_{2k}}{(2k)!}f^{(2k-1)}(x)\end{align} 451 | 452 | - id: "97" 453 | name: MathBB no. 1 454 | note: 455 | equation: > 456 | \mathbb{N}_0=\{x\mid x\in\mathbb{Z},x\ge0\} 457 | 458 | - id: "98" 459 | name: MathBB no. 2 460 | note: 461 | equation: > 462 | \mathbb{N}^*=\{x\mid x\in\mathbb{Z},x>0\} 463 | 464 | - id: "99" 465 | name: Yet another Piecwise 466 | note: 467 | equation: > 468 | f(x)=\begin{cases}0&x<0\\\frac{100-x}{100}&0\leq x\leq100\\0&100< x\end{cases} 469 | 470 | - id: "100" 471 | name: Custom Text and Coloring 472 | note: 473 | equation: > 474 | \textcolor{blue}{\transt{\text{rational number}}{رقم منطقي}=\frac{\transt{\text{integer}}{عدد صحيح}}{\transt{\text{integer}}{عدد صحيح}}} 475 | 476 | - id: "102" 477 | name: "Step by step solving with large numbers" 478 | note: 479 | equation: > 480 | \begin{align}\textcolor{coral}{2}\times\textcolor{coral}{3}&= 481 | \textcolor{blue}{\transn{1,000,000.532}x}\\\textcolor{coral}{1} 482 | \times\textcolor{coral}{7}&=\textcolor{blue}{\transn{7,658}y}\\ 483 | \textcolor{coral}{3}\times\textcolor{coral}{4}\times 484 | \textcolor{coral}{5}&=\textcolor{blue}{60}\end{align} 485 | 486 | - id: "103" 487 | name: "Mixed Fractions" 488 | note: 489 | equation: > 490 | \tmfrac{20}{1}{2} 491 | 492 | - id: "104" 493 | name: "Mixed Fractions with Symbols" 494 | note: 495 | equation: > 496 | \tmfrac{x}{y}{z} 497 | -------------------------------------------------------------------------------- /dist/unpacked/arabic.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * The MIT License 3 | * 4 | * Copyright (c) 2015-2016 Edraak.org, Omar Al-Ithawi and contributors. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | (function () { 26 | var mathElements = [ 27 | 'mfrac', 28 | 'mi', 29 | 'mn', 30 | 'mo', 31 | 'mroot', 32 | 'mrow', 33 | 'ms', 34 | 'msqrt', 35 | 'mstyle', 36 | 'msubsup', 37 | 'mtext' 38 | ]; 39 | 40 | MathJax.Hub.Register.StartupHook('CommonHTML Jax Ready', function () { 41 | var CHTML = MathJax.OutputJax.CommonHTML; 42 | var originalUnkownChar = CHTML.unknownChar; 43 | 44 | CHTML.Augment({ 45 | unknownChar: function () { 46 | var arabicUnicodeStart = MathJax.Hub.config.Arabic.arabicUnicodeStart; 47 | var arabicUnicodeEnd = MathJax.Hub.config.Arabic.arabicUnicodeEnd; 48 | var returnObject = originalUnkownChar.apply(this, arguments); 49 | var n = returnObject.n; 50 | var isArabic = (arabicUnicodeStart <= n && n <= arabicUnicodeEnd); 51 | 52 | if (isArabic) { 53 | returnObject.type = 'char'; 54 | } 55 | 56 | return returnObject; 57 | }, 58 | }); 59 | 60 | MathJax.Hub.Register.StartupHook('Arabic TeX Ready', function () { 61 | var MML = MathJax.ElementJax.mml; 62 | 63 | var makeElementFlippable = function (name) { 64 | var originalToHTML = MML[name].prototype.toCommonHTML; 65 | 66 | MML[name].Augment({ 67 | toCommonHTML: function () { 68 | var element = originalToHTML.apply(this, arguments); 69 | 70 | if (this.arabicFlipH) { 71 | var flipElement = document.createElement('span'); 72 | 73 | flipElement.className = 'mfliph'; 74 | 75 | if ('ar' === this.arabicFontLang) { 76 | flipElement.className += ' mar'; // Keep the leading space 77 | } 78 | 79 | while (element.firstChild) { 80 | flipElement.appendChild(element.firstChild); 81 | } 82 | 83 | element.appendChild(flipElement); 84 | } 85 | 86 | return element; 87 | } 88 | }); 89 | }; 90 | 91 | ['mtr', 'mtd'].concat(mathElements).forEach(makeElementFlippable); 92 | 93 | MathJax.Hub.Register.StartupHook('CommonHTML multiline Ready', function () { 94 | var originalAddLine = MML.mbase.prototype.CHTMLaddLine; 95 | 96 | MML.mbase.Augment({ 97 | CHTMLaddLine: function () { 98 | var stack = arguments[0]; 99 | 100 | // TODO: Would it be possible to use the usual env settings 101 | // to fix this issue, instead of doing a querySelector? 102 | if (stack && stack.querySelector('.mfliph')) { 103 | stack.className = 'mfliph'; 104 | } 105 | 106 | originalAddLine.apply(this, arguments); 107 | } 108 | }); 109 | 110 | MathJax.Hub.Startup.signal.Post('Arabic CommonHTML multiline Ready'); 111 | }); 112 | 113 | MathJax.Hub.Register.StartupHook('CommonHTML mtable Ready', function () { 114 | makeElementFlippable('mtable'); 115 | MathJax.Hub.Startup.signal.Post('Arabic CommonHTML mtable Ready'); 116 | }); 117 | 118 | MathJax.Hub.Startup.signal.Post('Arabic CommonHTML Ready'); 119 | }); 120 | }); 121 | 122 | MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready', function () { 123 | MathJax.Hub.Register.StartupHook('Arabic TeX Ready', function () { 124 | var MML = MathJax.ElementJax.mml; 125 | 126 | var makeElementFlippable = function (name) { 127 | var originalToHTML = MML[name].prototype.toHTML; 128 | 129 | MML[name].Augment({ 130 | toHTML: function () { 131 | var element = originalToHTML.apply(this, arguments); 132 | if (this.arabicFlipH) { 133 | var flipElement = document.createElement('span'); 134 | 135 | flipElement.className = 'mfliph'; 136 | 137 | if ('ar' === this.arabicFontLang) { 138 | flipElement.className += ' mar'; // Keep the leading space 139 | } 140 | 141 | while (element.firstChild) { 142 | flipElement.appendChild(element.firstChild); 143 | } 144 | 145 | element.appendChild(flipElement); 146 | } 147 | 148 | return element; 149 | } 150 | }); 151 | }; 152 | 153 | mathElements.forEach(makeElementFlippable); 154 | 155 | MathJax.Hub.Register.StartupHook('HTML-CSS multiline Ready', function () { 156 | var originalAddLine = MML.mbase.prototype.HTMLaddLine; 157 | 158 | MML.mbase.Augment({ 159 | HTMLaddLine: function () { 160 | var stack = arguments[0]; 161 | 162 | // TODO: Would it be possible to use the usual env settings 163 | // to fix this issue, instead of doing a querySelector? 164 | if (stack && stack.querySelector('.mfliph')) { 165 | stack.className = 'mfliph'; 166 | } 167 | 168 | originalAddLine.apply(this, arguments); 169 | } 170 | }); 171 | 172 | MathJax.Hub.Startup.signal.Post('Arabic HTML-CSS multiline Ready'); 173 | }); 174 | 175 | MathJax.Hub.Register.StartupHook('HTML-CSS mtable Ready', function () { 176 | makeElementFlippable('mtable'); 177 | MathJax.Hub.Startup.signal.Post('Arabic HTML-CSS mtable Ready'); 178 | }); 179 | 180 | MathJax.Hub.Startup.signal.Post('Arabic HTML-CSS Ready'); 181 | }); 182 | }); 183 | }()); 184 | 185 | MathJax.Extension.Arabic = { 186 | version: '2.1.1', 187 | config: MathJax.Hub.CombineConfig("Arabic", { 188 | dict: { 189 | // A macros to force English zero in both languages 190 | 'Zero': ['zero', 'Text', ['0', '\u0635\u0641\u0631']], // Better localized Zero 191 | 'Radius': ['radius', 'Text', ['r', '\u0646\u0642']], // Circle radius 192 | 'Area': ['Area', 'Text', ['A', '\u0645']], // Area of circles and other stuff 193 | 194 | // Used for special charge character in the modified Amiri font: 195 | // - https://github.com/OmarIthawi/amiri/releases 196 | // This only will work when activating that font. 197 | 'Charge': ['charge', 'TeX', ['C', '\\fliph{\\text{\u069b}}']], 198 | }, 199 | identifiersMap: { 200 | // Variable names 201 | 'a': '\u0623', 202 | 'b': '\u0628', // TODO: Consider using Arabic letter dotless beh 0x66e instead 203 | 'c': '\u062c\u0640', // Suffixed with Unicode Arabic Tatweel 0x0640 204 | 'x': '\u0633', 205 | 'y': '\u0635', 206 | 'z': '\u0639', 207 | 'n': '\u0646', 208 | 209 | // Function names 210 | 'f': '\u0642', // TODO: Consider using dotless qaf (\u066f) instead 211 | 'g': '\u062c\u0640', // With Unicode Arabic Tatweel 0x0640 212 | 'h': '\u0647\u0640', // With Unicode Arabic Tatweel 0x0640 213 | 214 | // Mixed use 215 | 'k': '\u0643', 216 | 'r': '\u0631', 217 | 't': '\u062a', 218 | 'd': '\u062f', // Function, variable and (dx) 219 | 'e': '\u0647\u0640', // With Unicode Arabic Tatweel 0x0640 220 | 'm': '\u0645', 221 | 'l': '\u0644', 222 | 223 | // Math functions 224 | 'sin': '\u062c\u0627', 225 | 'cos': '\u062c\u062a\u0627', 226 | 'tan': '\u0638\u0627', 227 | 'cot': '\u0638\u062a\u0627', 228 | 'sec': '\u0642\u0627', 229 | 'csc': '\u0642\u062a\u0627', 230 | 'log': '\u0644\u0648' 231 | }, 232 | numbersMap: { 233 | '0': '\u0660', 234 | '1': '\u0661', 235 | '2': '\u0662', 236 | '3': '\u0663', 237 | '4': '\u0664', 238 | '5': '\u0665', 239 | '6': '\u0666', 240 | '7': '\u0667', 241 | '8': '\u0668', 242 | '9': '\u0669' 243 | }, 244 | arabicUnicodeStart: 0x600, 245 | arabicUnicodeEnd: 0x6FF, 246 | arabicLanguageRegExp: /([\u0600-\u06FF]+)/g, 247 | arabicDecimalSplitter: '\u066b', // Used by `\transn` 248 | operatorsMap: { 249 | // English to Arabic punctuations 250 | ',': '\u060c', 251 | ';': '\u061b', 252 | // Limits 253 | 'lim': '\u0646\u0647\u0640\u0640\u0627' 254 | }, 255 | isArabicPage: function () { 256 | return document.documentElement.lang === 'ar'; 257 | } 258 | }), 259 | TeX: function (english, arabic) { 260 | // Creates a translated TeX macro. 261 | 262 | return function (name) { 263 | var TEX = MathJax.InputJax.TeX; 264 | 265 | var tex; 266 | if ('ar' === this.stack.env.lang) { 267 | tex = arabic; 268 | } else { 269 | tex = english; 270 | } 271 | 272 | this.Push(TEX.Parse(tex).mml()); 273 | }; 274 | }, 275 | Text: function (english, arabicText) { 276 | // Creates a translated TeX macro, with an Arabic plain text. 277 | 278 | return MathJax.Extension.Arabic.TeX(english, '\\fliph{\\text{' + arabicText + '}}'); 279 | }, 280 | Symbols: function (english, arabicSymbols) { 281 | // Creates a translated TeX macro that converts Arabic symbols into text nodes, 282 | // and treats everything else as normal TeX. 283 | var arabic = arabicSymbols.replace( 284 | MathJax.Hub.config.Arabic.arabicLanguageRegExp, 285 | '\\fliph{\\text{$1}}' 286 | ); 287 | 288 | return MathJax.Extension.Arabic.TeX(english, arabic); 289 | }, 290 | MapNumbers: function (text) { 291 | var numbersMap = MathJax.Hub.config.Arabic.numbersMap; 292 | 293 | var replaceNumber = function (m) { 294 | return numbersMap[m]; 295 | }; 296 | 297 | return text.replace(/[0-9]/g, replaceNumber); 298 | } 299 | }; 300 | 301 | 302 | MathJax.Hub.Startup.signal.Post('Arabic TeX Startup'); 303 | 304 | 305 | MathJax.Hub.Register.StartupHook('TeX Jax Ready', function () { 306 | var TEX = MathJax.InputJax.TeX; 307 | var Arabic = MathJax.Extension.Arabic; 308 | 309 | var texParseMMLToken = TEX.Parse.prototype.mmlToken; 310 | var dict = MathJax.Hub.config.Arabic.dict; 311 | 312 | var escapeRegExp = (function () { 313 | var regExpChar = /[\\^$.*+?()[\]{}|]/g; 314 | 315 | return function (string) { 316 | return string.replace(regExpChar,'\\$&'); 317 | }; 318 | }()); 319 | 320 | var getKeysRegExp = function (map) { 321 | var keys = Object.keys(map).sort(function (a, b) { 322 | return b.length - a.length; 323 | }); 324 | 325 | return new RegExp(keys.map(escapeRegExp).join('|'), 'gi'); 326 | }; 327 | 328 | 329 | TEX.Definitions.Add({ 330 | macros: { 331 | 'ar': 'HandleArabic', 332 | 'alwaysar': 'MarkAsArabic', 333 | 'fliph': 'HandleFlipHorizontal', 334 | 'transn': 'TranslateNumbers', 335 | 'tmfrac': 'TranslateMixedFraction', 336 | 'transx': 'TranslateTeX', 337 | 'transt': 'TranslateText', 338 | 'transs': 'TranslateSymbols' 339 | } 340 | }); 341 | 342 | var array = TEX.Stack.Item.array; 343 | var arrayClearEnv = array.prototype.clearEnv; 344 | var arrayInit = array.prototype.Init; 345 | 346 | array.Augment({ 347 | Init: function () { 348 | // Overcome the copyEnv issue that has been introduced in: 349 | // - Pull Request: https://github.com/mathjax/MathJax/pull/1523 350 | // 351 | // Otherwise arrays won't be Arabized. 352 | // - Bug Report: https://groups.google.com/forum/#!topic/mathjax-dev/cWoTKcwMqmY 353 | arrayInit.apply(this, arguments); 354 | this.copyEnv = true; 355 | }, 356 | clearEnv: function () { 357 | // Propagate `lang` from Arrays to their children fractions and others. 358 | // This is a bug in the MathJax itself, so this code should be removed once the bug is fixed. 359 | // Follow up on https://github.com/mathjax/MathJax/pull/1523 360 | // It's still not clear how/when a proper solution is possible. 361 | var lang = this.env.lang; 362 | 363 | arrayClearEnv.apply(this, arguments); 364 | 365 | if (lang) { 366 | this.env.lang = lang; 367 | } 368 | } 369 | }); 370 | 371 | TEX.Definitions.Add({ 372 | macros: function () { 373 | var definitions = {}; 374 | 375 | Object.keys(dict).forEach(function (key) { 376 | var texCommand = dict[key][0]; 377 | definitions[texCommand] = key; 378 | }); 379 | 380 | return definitions; 381 | }() 382 | }); 383 | 384 | 385 | TEX.Parse.Augment(function () { 386 | var parsers = {}; 387 | 388 | Object.keys(dict).forEach(function (key) { 389 | var helperName = dict[key][1]; // Text, TeX or Symbols 390 | var helperParams = dict[key][2]; 391 | 392 | parsers[key] = Arabic[helperName].apply(null, helperParams); 393 | }); 394 | 395 | return parsers; 396 | }()); 397 | 398 | 399 | TEX.Parse.Augment({ 400 | flipHorizontal: function (token) { 401 | token.arabicFlipH = !token.arabicFlipH; 402 | // Invert the value, because flipping twice means, it is not flipped 403 | return token; 404 | }, 405 | arabicNumber: function (token) { 406 | var text = token.data[0].data[0]; 407 | var mapped = Arabic.MapNumbers(text); 408 | 409 | if (mapped !== text) { 410 | token.data[0].data[0] = mapped; 411 | token.arabicFontLang = 'ar'; 412 | } 413 | 414 | return this.flipHorizontal(token); 415 | }, 416 | arabicIdentifier: (function () { 417 | var identifiersMap = MathJax.Hub.config.Arabic.identifiersMap; 418 | var identifiersKeysRegExp = getKeysRegExp(identifiersMap); 419 | 420 | var replaceIdentifier = function (m) { 421 | return identifiersMap[m.toLowerCase()]; 422 | }; 423 | 424 | return function (token) { 425 | var text = token.data[0].data[0]; 426 | 427 | if ('chars' === token.data[0].type) { 428 | // English Symbols like X and Y 429 | var mapped = text.replace(identifiersKeysRegExp, replaceIdentifier); 430 | 431 | if (mapped !== text) { 432 | token.data[0].data[0] = mapped; 433 | token.arabicFontLang = 'ar'; 434 | } 435 | } 436 | 437 | return this.flipHorizontal(token); 438 | } 439 | }()), 440 | arabicOperator: (function () { 441 | var operatorsMap = MathJax.Hub.config.Arabic.operatorsMap; 442 | var operatorsKeysRegExp = getKeysRegExp(operatorsMap); 443 | 444 | var replaceOperator = function (m) { 445 | return operatorsMap[m]; 446 | }; 447 | 448 | return function (token) { 449 | var text = token.data[0].data[0]; 450 | var mapped = text.replace(operatorsKeysRegExp, replaceOperator); 451 | 452 | if (mapped !== text) { 453 | token = this.flipHorizontal(token); 454 | token.arabicFontLang = 'ar'; 455 | token.data[0].data[0] = mapped; 456 | } 457 | 458 | return token; 459 | } 460 | }()), 461 | _getArgumentMML: function (name) { 462 | // returns an argument that is a single MathML element 463 | // (in an mrow if necessary) 464 | // 465 | // This functions has been copied here from extensions/TeX/HTML.js, to avoid 466 | // adding a dependency. 467 | // 468 | // TODO: Consider importing (as a dependency) this from HTML.js instead! 469 | var arg = this.ParseArg(name); 470 | if (arg.inferred && arg.data.length === 1) { 471 | arg = arg.data[0]; 472 | } else { 473 | delete arg.inferred; 474 | } 475 | 476 | return arg; 477 | }, 478 | mmlToken: function (token) { 479 | // TODO: Check for possible incompatibility with boldsymbol extension 480 | var parsedToken = texParseMMLToken.call(this, token); 481 | 482 | if ('ar' === this.stack.env.lang) { 483 | this.markArabicToken(parsedToken); 484 | } 485 | 486 | return parsedToken; 487 | }, 488 | markArabicToken: function (token) { 489 | if ('mn' === token.type) { 490 | return this.arabicNumber(token); 491 | } else if ('mi' === token.type) { 492 | return this.arabicIdentifier(token); 493 | } else if ('mo' === token.type) { 494 | return this.arabicOperator(token); 495 | } 496 | 497 | return token; 498 | }, 499 | HandleArabic: function (name) { 500 | if (MathJax.Hub.config.Arabic.isArabicPage) { 501 | this.MarkAsArabic(name); 502 | } 503 | }, 504 | TranslateTeX: function (name) { 505 | var english = this.GetArgument(name); 506 | var arabicText = this.GetArgument(name); 507 | var helper = Arabic.TeX(english, arabicText); 508 | return helper.call(this, name); 509 | }, 510 | TranslateText: function (name) { 511 | var english = this.GetArgument(name); 512 | var arabicText = this.GetArgument(name); 513 | var helper = Arabic.Text(english, arabicText); 514 | return helper.call(this, name); 515 | }, 516 | TranslateNumbers: function (name) { 517 | var english = this.GetArgument(name); 518 | var arabicDecimalSplitter = MathJax.Hub.config.Arabic.arabicDecimalSplitter; 519 | 520 | var arabicNumbers = Arabic.MapNumbers(english, true) 521 | .replace(/,/g, '') 522 | .replace(/\./g, arabicDecimalSplitter); 523 | 524 | var helper = MathJax.Extension.Arabic.TeX( 525 | english, '\\fliph{\\text{' + arabicNumbers + '}}' 526 | ); 527 | return helper.call(this, name); 528 | }, 529 | TranslateSymbols: function (name) { 530 | var english = this.GetArgument(name); 531 | var arabicText = this.GetArgument(name); 532 | var helper = Arabic.Symbols(english, arabicText); 533 | return helper.call(this, name); 534 | }, 535 | TranslateMixedFraction: function () { 536 | var integer = this.GetArgument(name); 537 | var numerator = this.GetArgument(name); 538 | var denominator = this.GetArgument(name); 539 | 540 | var tex = MathJax.Extension.Arabic.TeX( 541 | integer + '\\frac{' + numerator + '}{' + denominator + '}', 542 | '\\alwaysar{\\fliph{\\frac{' + numerator + '}{' + denominator + '}' + integer + '}}' 543 | ); 544 | 545 | return tex.call(this, name); 546 | }, 547 | MarkAsArabic: function (name) { 548 | var originalLang = this.stack.env.lang; 549 | 550 | this.stack.env.lang = 'ar'; 551 | var arg = this._getArgumentMML(name); 552 | 553 | this.stack.env.lang = originalLang; // Reset the language for other elements. 554 | 555 | this.Push(this.flipHorizontal(arg)); 556 | }, 557 | HandleFlipHorizontal: function (name) { 558 | var arg = this._getArgumentMML(name); 559 | this.Push(this.flipHorizontal(arg)); 560 | } 561 | }); 562 | 563 | MathJax.Hub.Startup.signal.Post('Arabic TeX Ready'); 564 | }); 565 | 566 | // This file starting with the letter `z` to make sure it gets concatenated last! 567 | MathJax.Ajax.loadComplete("[arabic]/unpacked/arabic.js"); 568 | --------------------------------------------------------------------------------