UNPKG

@gerhobbelt/mathjax-third-party-extensions

Version:

A list of MathJax extensions provided by third-party contributors

462 lines (387 loc) 13.4 kB
/* * ../../../../legacy/arabic/arabic.js * * Copyright (c) 2009-2018 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*! * The MIT License * * Copyright (c) 2015-2016 The Queen Rania Foundation for Education and Development * * http://www.qrf.org * http://www.edraak.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ MathJax.Hub.Register.StartupHook('HTML-CSS Jax Require', function () { MathJax.Hub.Config({ 'HTML-CSS': { styles: { '.MathJax .mfliph': { 'display': 'inline-block !important', '-moz-transform': 'scaleX(-1)', '-webkit-transform': 'scaleX(-1)', '-o-transform': 'scaleX(-1)', 'transform': 'scaleX(-1)', '-ms-filter': 'fliph', 'filter': 'fliph' }, '.MathJax .mar': { 'font-style': 'normal !important' }, '.MathJax .mar > span': { 'font-style': 'normal !important' } } } }); }); MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready', function () { MathJax.Hub.Register.StartupHook('Arabic TeX Ready', function () { var MML = MathJax.ElementJax.mml; var makeElementFlippable = function (name) { var originalToHTML = MML[name].prototype.toHTML; MML[name].Augment({ toHTML: function () { var element = originalToHTML.apply(this, arguments); if (this.arabicFlipH) { var flipElement = document.createElement('span'); flipElement.className = 'mfliph'; if ('ar' === this.arabicFontLang) { flipElement.className += ' mar'; // Keep the leading space } while (element.firstChild) { flipElement.appendChild(element.firstChild); } element.appendChild(flipElement); } return element; } }); }; [ 'mfrac', 'mi', 'mn', 'mo', 'mrow', 'ms', 'msqrt', 'msubsup', 'mroot', 'mtext' ].forEach(makeElementFlippable); MathJax.Hub.Register.StartupHook('HTML-CSS mtable Ready', function () { makeElementFlippable('mtable'); MathJax.Hub.Startup.signal.Post('Arabic mtable Ready'); }); MathJax.Hub.Startup.signal.Post('Arabic Ready'); }); }); MathJax.Extension.Arabic = { version: '1.0.0', config: MathJax.Hub.CombineConfig("Arabic", { dict: { // A macros to force English zero in both languages 'Zero': ['zero', 'Text', ['0', '\u0635\u0641\u0631']], // Better localized Zero 'Radius': ['radius', 'Text', ['r', '\u0646\u0642']], // Circle radius 'Area': ['Area', 'Text', ['A', '\u0645']] // Area of circles and other stuff }, identifiersMap: { // Variable names 'a': '\u0623', 'b': '\u0628', // TODO: Consider using Arabic letter dotless beh 0x66e instead 'c': '\u062c\u0640', // Suffixed with Unicode Arabic Tatweel 0x0640 'x': '\u0633', 'y': '\u0635', 'z': '\u0639', 'n': '\u0646', // Function names 'f': '\u0642', // TODO: Consider using dotless qaf (\u066f) instead 'g': '\u062c\u0640', // With Unicode Arabic Tatweel 0x0640 'h': '\u0647\u0640', // With Unicode Arabic Tatweel 0x0640 // Mixed use 'k': '\u0643', 'r': '\u0631', 't': '\u062a', 'd': '\u062f', // Function, variable and (dx) 'e': '\u0647\u0640', // With Unicode Arabic Tatweel 0x0640 'm': '\u0645', 'l': '\u0644', // Math functions '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' }, operatorsMap: { // English to Arabic punctuations ',': '\u060c', ';': '\u061b', // Limits 'lim': '\u0646\u0647\u0640\u0640\u0627' }, isArabicPage: (document.documentElement.lang === 'ar') }), arabicLanguageRegExp: /([\u0600-\u06FF]+)/g, TeX: function (english, arabic) { // Creates a translated TeX macro. return function (name) { var TEX = MathJax.InputJax.TeX; var tex; if ('ar' === this.stack.env.lang) { tex = arabic; } else { tex = english; } this.Push(TEX.Parse(tex).mml()); }; }, Text: function (english, arabicText) { // Creates a translated TeX macro, with an Arabic plain text. return MathJax.Extension.Arabic.TeX(english, '\\fliph{\\text{' + arabicText + '}}'); }, Symbols: function (english, arabicSymbols) { // Creates a translated TeX macro that converts Arabic symbols into text nodes, // and treats everything else as normal TeX. var arabic = arabicSymbols.replace( MathJax.Extension.Arabic.arabicLanguageRegExp, '\\fliph{\\text{$1}}' ); return MathJax.Extension.Arabic.TeX(english, arabic); } }; MathJax.Hub.Startup.signal.Post('Arabic TeX Startup'); MathJax.Hub.Register.StartupHook('TeX Jax Ready', function () { var TEX = MathJax.InputJax.TeX; var Arabic = MathJax.Extension.Arabic; var texParseMMLToken = TEX.Parse.prototype.mmlToken; var dict = MathJax.Hub.config.Arabic.dict; var escapeRegExp = (function () { var regExpChar = /[\\^$.*+?()[\]{}|]/g; return function (string) { return string.replace(regExpChar,'\\$&'); }; }()); var getKeysRegExp = function (map) { var keys = Object.keys(map).sort(function (a, b) { return b.length - a.length; }); return new RegExp(keys.map(escapeRegExp).join('|'), 'gi'); }; TEX.Definitions.Add({ macros: { 'ar': 'HandleArabic', 'alwaysar': 'MarkAsArabic', 'fliph': 'HandleFlipHorizontal', 'transx': 'TranslateTeX', 'transt': 'TranslateText', 'transs': 'TranslateSymbols' } }); var array = TEX.Stack.Item.array; var arrayClearEnv = array.prototype.clearEnv; array.Augment({ clearEnv: function () { // Propagate `lang` from Arrays to their children fractions and others. // This is a bug in the MathJax itself, so this code should be removed once the bug is fixed. var lang = this.env.lang; arrayClearEnv.apply(this, arguments); if (lang) { this.env.lang = lang; } } }); TEX.Definitions.Add({ macros: function () { var definitions = {}; Object.keys(dict).forEach(function (key) { var texCommand = dict[key][0]; definitions[texCommand] = key; }); return definitions; }() }); TEX.Parse.Augment(function () { var parsers = {}; Object.keys(dict).forEach(function (key) { var helperName = dict[key][1]; // Text, TeX or Symbols var helperParams = dict[key][2]; parsers[key] = Arabic[helperName].apply(null, helperParams); }); return parsers; }()); TEX.Parse.Augment({ flipHorizontal: function (token) { token.arabicFlipH = !token.arabicFlipH; // Invert the value, because flipping twice means, it is not flipped return token; }, arabicNumber: (function () { var englishNumbersRegExp = /[0-9]/g; var numbersMap = MathJax.Hub.config.Arabic.numbersMap; var replaceNumber = function (m) { return numbersMap[m]; }; return function (token) { var text = token.data[0].data[0]; var mapped = text.replace(englishNumbersRegExp, replaceNumber); if (mapped !== text) { token.data[0].data[0] = mapped; token.arabicFontLang = 'ar'; } return this.flipHorizontal(token); } }()), arabicIdentifier: (function () { var identifiersMap = MathJax.Hub.config.Arabic.identifiersMap; var identifiersKeysRegExp = getKeysRegExp(identifiersMap); var replaceIdentifier = function (m) { return identifiersMap[m.toLowerCase()]; }; return function (token) { var text = token.data[0].data[0]; if ('chars' === token.data[0].type) { // English Symbols like X and Y var mapped = text.replace(identifiersKeysRegExp, replaceIdentifier); if (mapped !== text) { token.data[0].data[0] = mapped; token.arabicFontLang = 'ar'; } } return this.flipHorizontal(token); } }()), arabicOperator: (function () { var operatorsMap = MathJax.Hub.config.Arabic.operatorsMap; var operatorsKeysRegExp = getKeysRegExp(operatorsMap); var replaceOperator = function (m) { return operatorsMap[m]; }; return function (token) { var text = token.data[0].data[0]; var mapped = text.replace(operatorsKeysRegExp, replaceOperator); if (mapped !== text) { token = this.flipHorizontal(token); token.arabicFontLang = 'ar'; token.data[0].data[0] = mapped; } return token; } }()), _getArgumentMML: function (name) { // returns an argument that is a single MathML element // (in an mrow if necessary) // // This functions has been copied here from extensions/TeX/HTML.js, to avoid // adding a dependency. // // TODO: Consider importing (as a dependency) this from HTML.js instead! var arg = this.ParseArg(name); if (arg.inferred && arg.data.length === 1) { arg = arg.data[0]; } else { delete arg.inferred; } return arg; }, mmlToken: function (token) { // TODO: Check for possible incompatibility with boldsymbol extension var parsedToken = texParseMMLToken.call(this, token); if ('ar' === this.stack.env.lang) { this.markArabicToken(parsedToken); } return parsedToken; }, markArabicToken: function (token) { if ('mn' === token.type) { return this.arabicNumber(token); } else if ('mi' === token.type) { return this.arabicIdentifier(token); } else if ('mo' === token.type) { return this.arabicOperator(token); } return token; }, HandleArabic: function (name) { if (MathJax.Hub.config.Arabic.isArabicPage) { this.MarkAsArabic(name); } }, TranslateTeX: function (name) { var english = this.GetArgument(name); var arabicText = this.GetArgument(name); var helper = Arabic.TeX(english, arabicText); return helper.call(this, name); }, TranslateText: function (name) { var english = this.GetArgument(name); var arabicText = this.GetArgument(name); var helper = Arabic.Text(english, arabicText); return helper.call(this, name); }, TranslateSymbols: function (name) { var english = this.GetArgument(name); var arabicText = this.GetArgument(name); var helper = Arabic.Symbols(english, arabicText); return helper.call(this, name); }, MarkAsArabic: function (name) { var originalLang = this.stack.env.lang; this.stack.env.lang = 'ar'; var arg = this._getArgumentMML(name); this.stack.env.lang = originalLang; // Reset the language for other elements. this.Push(this.flipHorizontal(arg)); }, HandleFlipHorizontal: function (name) { var arg = this._getArgumentMML(name); this.Push(this.flipHorizontal(arg)); } }); MathJax.Hub.Startup.signal.Post('Arabic TeX Ready'); }); // This file starting with the letter `z` to make sure it gets concatenated last! MathJax.Ajax.loadComplete("[Contrib]/arabic/arabic.js");