aboutsummaryrefslogtreecommitdiff
path: root/js/mathjax/extensions/TeX/text-macros.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/mathjax/extensions/TeX/text-macros.js')
-rw-r--r--js/mathjax/extensions/TeX/text-macros.js489
1 files changed, 489 insertions, 0 deletions
diff --git a/js/mathjax/extensions/TeX/text-macros.js b/js/mathjax/extensions/TeX/text-macros.js
new file mode 100644
index 0000000..447a853
--- /dev/null
+++ b/js/mathjax/extensions/TeX/text-macros.js
@@ -0,0 +1,489 @@
+// @license magnet:?xt=urn:btih:8e4f440f4c65981c5bf93c76d35135ba5064d8b7dn=apache-2.0.txt Apache-2.0
+/*************************************************************
+ *
+ * MathJax/extensions/TeX/text-macros.js
+ *
+ * Implements the processing of some text-mode macros inside
+ * \text{} and other text boxes.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (c) 2018-2020 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.
+ */
+
+MathJax.Extension["TeX/text-macros"] = {
+ version: "2.7.9"
+};
+
+MathJax.Hub.Register.StartupHook("TeX Jax Ready", function () {
+ var MML = MathJax.ElementJax.mml;
+ var TEX = MathJax.InputJax.TeX;
+ var TEXDEF = TEX.Definitions;
+
+ TEX.Parse.Augment({
+ //
+ // Replace InternalMath with parser that handles some text macros
+ //
+ InternalMath: function(text,level) {
+ var mml = TextParser(text, {}).Parse();
+ if (level != null) {
+ mml = [MML.mstyle.apply(MML,mml).With({displaystyle:false, scriptlevel:level})];
+ } else if (mml.length > 1) {
+ mml = [MML.mrow.apply(MML,mml)];
+ }
+ return mml;
+ },
+
+ //
+ // Correctly skip newline as well as comment
+ //
+ Comment: function (c) {
+ while (this.i < this.string.length && this.string.charAt(this.i) != "\n") {this.i++}
+ this.i++;
+ },
+
+ //
+ // Correctly skip trailing space as well
+ //
+ GetCS: function () {
+ var CS = this.string.slice(this.i).match(/^([a-z]+|.) ?/i);
+ if (CS) {this.i += CS[0].length; return CS[1]} else {this.i++; return " "}
+ }
+
+ });
+
+ //
+ // The text parser is a subclass of the math parser, so we can use
+ // some of the existing methods (like GetArgument()), and some of the
+ // control sequence implementations (like Macro, Spacer, etc.)
+ //
+ var TextParser = TEX.TextParser = TEX.Parse.Subclass({
+
+ Init: function (text, env) {
+ this.env = MathJax.Hub.Insert({},env);
+ this.stack = {env: this.env};
+ this.string = text;
+ this.i = 0;
+ this.mml = []; // the accumulated MathML elements
+ this.text = ''; // the accumulated text so far
+ },
+
+ //
+ // These are the special characters in text mode
+ //
+ textSpecial: {
+ '\\': 'ControlSequence',
+ '$': 'Math',
+ '%': 'Comment',
+ '^': 'MathModeOnly',
+ '_': 'MathModeOnly',
+ '&': 'Misplaced',
+ '#': 'Misplaced',
+ '~': 'Tilde',
+ ' ': 'Space',
+ '\t': 'Space',
+ '\r': 'Space',
+ '\n': 'Space',
+ '\u00A0': 'Tilde',
+ '{': 'OpenBrace',
+ '}': 'CloseBrace',
+ '`': 'OpenQuote',
+ "'": 'CloseQuote'
+ },
+
+ //
+ // These are text-mode macros we support
+ //
+ textMacros: {
+ '(': 'Math',
+
+ '$': 'SelfQuote',
+ '_': 'SelfQuote',
+ '%': 'SelfQuote',
+ '{': 'SelfQuote',
+ '}': 'SelfQuote',
+ ' ': 'SelfQuote',
+ '&': 'SelfQuote',
+ '#': 'SelfQuote',
+ '\\': 'SelfQuote',
+
+ "'": ['Accent', '\u00B4'],
+ '`': ['Accent', '\u0060'],
+ '^': ['Accent', '^'],
+ '"': ['Accent', '\u00A8'],
+ '~': ['Accent', '~'],
+ '=': ['Accent', '\u00AF'],
+ '.': ['Accent', '\u02D9'],
+ 'u': ['Accent', '\u02D8'],
+ 'v': ['Accent', '\u02C7'],
+
+ emph: 'Emph',
+ rm: ['SetFont',MML.VARIANT.NORMAL],
+ mit: ['SetFont',MML.VARIANT.ITALIC],
+ oldstyle: ['SetFont',MML.VARIANT.OLDSTYLE],
+ cal: ['SetFont',MML.VARIANT.CALIGRAPHIC],
+ it: ['SetFont','-tex-mathit'], // needs special handling
+ bf: ['SetFont',MML.VARIANT.BOLD],
+ bbFont: ['SetFont',MML.VARIANT.DOUBLESTRUCK],
+ scr: ['SetFont',MML.VARIANT.SCRIPT],
+ frak: ['SetFont',MML.VARIANT.FRAKTUR],
+ sf: ['SetFont',MML.VARIANT.SANSSERIF],
+ tt: ['SetFont',MML.VARIANT.MONOSPACE],
+
+ tiny: ['SetSize',0.5],
+ Tiny: ['SetSize',0.6], // non-standard
+ scriptsize: ['SetSize',0.7],
+ small: ['SetSize',0.85],
+ normalsize: ['SetSize',1.0],
+ large: ['SetSize',1.2],
+ Large: ['SetSize',1.44],
+ LARGE: ['SetSize',1.73],
+ huge: ['SetSize',2.07],
+ Huge: ['SetSize',2.49],
+
+ mathcal: 'MathModeOnly',
+ mathscr: 'MathModeOnly',
+ mathrm: 'MathModeOnly',
+ mathbf: 'MathModeOnly',
+ mathbb: 'MathModeOnly',
+ mathit: 'MathModeOnly',
+ mathfrak: 'MathModeOnly',
+ mathsf: 'MathModeOnly',
+ mathtt: 'MathModeOnly',
+ Bbb: ['Macro','{\\bbFont #1}',1],
+ textrm: ['Macro','{\\rm #1}',1],
+ textit: ['Macro','{\\it #1}',1],
+ textbf: ['Macro','{\\bf #1}',1],
+ textsf: ['Macro','{\\sf #1}',1],
+ texttt: ['Macro','{\\tt #1}',1],
+
+ dagger: ['Insert', '\u2020'],
+ ddagger: ['Insert', '\u2021'],
+ S: ['Insert', '\u00A7']
+ },
+
+ //
+ // These are the original macros that are allowed in text mode
+ //
+ useMathMacros: {
+ ',': true,
+ ':': true,
+ '>': true,
+ ';': true,
+ '!': true,
+ enspace: true,
+ quad: true,
+ qquad: true,
+ thinspace: true,
+ negthinspace: true,
+
+ hskip: true,
+ hspace: true,
+ kern: true,
+ mskip: true,
+ mspace: true,
+ mkern: true,
+ rule: true,
+ Rule: true,
+ Space: true,
+
+ color: true,
+ href: true,
+ unicode: true,
+
+ ref: true,
+ eqref: true
+ },
+
+ //
+ // Look through the text for special characters and process them.
+ // Save any accumulated text aat the end and return the MathML
+ // elements produced.
+ //
+ Parse: function () {
+ var c;
+ while ((c = this.string.charAt(this.i++))) {
+ if (this.textSpecial.hasOwnProperty(c)) {
+ this[this.textSpecial[c]](c);
+ } else {
+ this.text += c;
+ }
+ }
+ this.SaveText();
+ return this.mml;
+ },
+
+ //
+ // Handle a control sequence name
+ // If it is a text-mode macro, use it.
+ // Otherwise look for it in the math-mode lists
+ // Report an error if it is not there
+ // Otherwise check if it is a macro or one of the allowed control sequences
+ // Run the macro (with arguments if given)
+ //
+ ControlSequence: function (c) {
+ var cs = this.GetCS(), name = c + cs, cmd;
+ if (this.textMacros.hasOwnProperty(cs)) {
+ cmd = this.textMacros[cs];
+ } else {
+ cmd = this.LookupCS(cs);
+ if (!cmd) {
+ this.Error(["UndefinedControlSequence","Undefined control sequence %1",name]);
+ }
+ if ((!(cmd instanceof Array) || cmd[0] !== 'Macro') &&
+ !this.useMathMacros.hasOwnProperty(cs)) {
+ this.Error(["MathMacro","'%1' is only supported in math mode",name]);
+ }
+ }
+ if (cmd instanceof Array) {
+ if (!this.hasOwnProperty[cmd[0]]) this.SaveText();
+ this[cmd[0]].apply(this,[name].concat(cmd.slice(1)));
+ } else {
+ if (!this.hasOwnProperty[cmd]) this.SaveText();
+ this[cmd].call(this,name);
+ }
+ },
+
+ //
+ // Lookup the CS as a math-mode macro
+ //
+ LookupCS: function(cs) {
+ if (TEXDEF.macros.hasOwnProperty(cs)) return TEXDEF.macros[cs];
+ if (TEXDEF.mathchar0mi.hasOwnProperty(cs)) return TEXDEF.mathchar0mi[cs];
+ if (TEXDEF.mathchar0mo.hasOwnProperty(cs)) return TEXDEF.mathchar0mo[cs];
+ if (TEXDEF.mathchar7.hasOwnProperty(cs)) return TEXDEF.mathchar7[cs];
+ if (TEXDEF.delimiter.hasOwnProperty('\\'+cs)) return TEXDEF.delimiter['\\'+cs];
+ return null;
+ },
+
+ //
+ // Handle internal math mode
+ // Look for the close delimiter and process the contents
+ //
+ Math: function (open) {
+ this.SaveText();
+ var i = this.i, j;
+ var braces = 0, c;
+ while ((c = this.GetNext())) {
+ j = this.i++;
+ switch(c) {
+ case '\\':
+ var cs = this.GetCS();
+ if (cs === ')') c = '\\(';
+ case '$':
+ if (braces === 0 && open === c) {
+ this.Push(TEX.Parse(this.string.substr(i, j-i),this.env).mml());
+ return;
+ }
+ break;
+
+ case '{':
+ braces++;
+ break;
+
+ case '}':
+ if (braces == 0) {
+ this.Error(["ExtraCloseMissingOpen","Extra close brace or missing open brace"]);
+ }
+ braces--;
+ break;
+ }
+ }
+ this.Error(["MathNotTerminated","Math not terminated in text box"]);
+ },
+
+ //
+ // Character can only be used in math mode
+ //
+ MathModeOnly: function (c) {
+ this.Error(["MathModeOnly","'%1' allowed only in math mode",c]);
+ },
+
+ //
+ // Character is being used out of place
+ //
+ Misplaced: function (c) {
+ this.Error(["Misplaced","'%1' can not be used here",c]);
+ },
+
+ //
+ // Braces start new environments
+ //
+ OpenBrace: function (c) {
+ var env = this.env;
+ this.env = MathJax.Hub.Insert({}, env);
+ this.env.oldEnv = env;
+ },
+ CloseBrace: function (c) {
+ if (this.env.oldEnv) {
+ this.SaveText();
+ this.env = this.env.oldEnv;
+ } else {
+ this.Error(["ExtraCloseMissingOpen","Extra close brace or missing open brace"]);
+ }
+ },
+
+ //
+ // Handle open and close quotes
+ //
+ OpenQuote: function (c) {
+ if (this.string.charAt(this.i) === c) {
+ this.text += "\u201C";
+ this.i++;
+ } else {
+ this.text += "\u2018"
+ }
+ },
+ CloseQuote: function (c) {
+ if (this.string.charAt(this.i) === c) {
+ this.text += "\u201D";
+ this.i++;
+ } else {
+ this.text += "\u2019"
+ }
+ },
+
+ //
+ // Handle non-breaking and regular spaces
+ //
+ Tilde: function (c) {
+ this.text += '\u00A0';
+ },
+ Space: function (c) {
+ this.text += ' ';
+ while (this.GetNext().match(/\s/)) this.i++;
+ },
+
+ //
+ // Insert the escaped characer
+ //
+ SelfQuote: function (name) {
+ this.text += name.substr(1);
+ },
+
+ //
+ // Insert a given character
+ //
+ Insert: function (name, c) {
+ this.text += c;
+ },
+
+ //
+ // Create an accented character using mover
+ //
+ Accent: function (name, c) {
+ this.SaveText();
+ var base = this.ParseArg(name);
+ var accent = MML.mo(MML.chars(c));
+ if (this.env.mathvariant) accent.mathvariant = this.env.mathvariant;
+ this.Push(MML.mover(base,accent));
+ },
+
+ //
+ // Switch to/from italics
+ //
+ Emph: function (name) {
+ this.UseFont(name, this.env.mathvariant === '-tex-mathit' ? 'normal' : '-tex-mathit');
+ },
+
+ //
+ // Use a given font on its argument
+ //
+ UseFont: function (name, variant) {
+ this.SaveText();
+ this.Push(this.ParseTextArg(name,{mathvariant: variant}));
+ },
+
+ //
+ // Set a font for the rest of the text
+ //
+ SetFont: function (name, variant) {
+ this.SaveText();
+ this.env.mathvariant = variant;
+ },
+
+ //
+ // Set the size to use
+ //
+ SetSize: function (name, size) {
+ this.SaveText();
+ this.env.mathsize = size;
+ },
+
+ //
+ // Process the argument as text with the given environment settings
+ //
+ ParseTextArg: function (name, env) {
+ var text = this.GetArgument(name);
+ env = MathJax.Hub.Insert(MathJax.Hub.Insert({}, this.env), env);
+ delete env.oldEnv;
+ return TextParser(text, env).Parse();
+ },
+
+ //
+ // Process an argument as text (overrides the math-mode version)
+ //
+ ParseArg: function (name) {
+ var mml = TextParser(this.GetArgument(name), this.env).Parse();
+ if (mml.length === 0) return mml[0];
+ return MML.mrow.apply(MML.mrow, mml);
+ },
+
+ //
+ // Create an mtext element with the accumulated text, if any
+ // and set it variant
+ //
+ SaveText: function () {
+ if (this.text) {
+ var text = MML.mtext(MML.chars(this.text));
+ if (this.env.mathvariant) text.mathvariant = this.env.mathvariant;
+ this.Push(text);
+ }
+ this.text = "";
+ },
+
+ //
+ // Save a MathML element or array, setting its size and color, if any
+ //
+ Push: function (mml) {
+ if (mml instanceof Array) {
+ if (this.env.mathsize || this.env.mathcolor) {
+ mml = MML.mstyle.apply(MML,mml);
+ if (this.env.mathsize) mml.mathsize = this.env.mathsize;
+ if (this.env.mathcolor) mml.mathcolor = this.env.mathcolor;
+ }
+ this.mml.push.apply(this.mml,mml);
+ } else {
+ if (this.env.mathsize && !mml.mathsize) mml.mathsize = this.env.mathsize;
+ if (this.env.mathcolor && !mml.mathcolor) mml.mathcolor = this.env.mathcolor;
+ this.mml.push(mml);
+ }
+ },
+
+ //
+ // Throw an error
+ //
+ Error: function (message) {
+ TEX.Error(message);
+ }
+
+ });
+
+ MathJax.Hub.Startup.signal.Post('TeX text-macros Ready');
+
+});
+
+MathJax.Ajax.loadComplete('[MathJax]/extensions/TeX/text-macros.js');
+// @license-end