aboutsummaryrefslogtreecommitdiff
path: root/js/mathjax/extensions/TeX/mhchem.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/mathjax/extensions/TeX/mhchem.js')
-rw-r--r--js/mathjax/extensions/TeX/mhchem.js522
1 files changed, 522 insertions, 0 deletions
diff --git a/js/mathjax/extensions/TeX/mhchem.js b/js/mathjax/extensions/TeX/mhchem.js
new file mode 100644
index 0000000..9d15876
--- /dev/null
+++ b/js/mathjax/extensions/TeX/mhchem.js
@@ -0,0 +1,522 @@
+// @license magnet:?xt=urn:btih:8e4f440f4c65981c5bf93c76d35135ba5064d8b7dn=apache-2.0.txt Apache-2.0
+/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+
+/*************************************************************
+ *
+ * MathJax/extensions/TeX/mhchem.js
+ *
+ * Implements the \ce command for handling chemical formulas
+ * from the mhchem LaTeX package.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (c) 2011-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.
+ */
+
+
+//
+// Don't replace [Contrib]/mhchem if it is already loaded
+//
+if (MathJax.Extension["TeX/mhchem"]) {
+ MathJax.Ajax.loadComplete("[MathJax]/extensions/TeX/mhchem.js");
+} else {
+
+MathJax.Extension["TeX/mhchem"] = {
+ version: "2.7.9",
+ config: MathJax.Hub.CombineConfig("TeX.mhchem",{
+ legacy: true
+ })
+};
+
+//
+// Load [mhchem]/mhchem.js if not configured for legacy vesion
+//
+if (!MathJax.Extension["TeX/mhchem"].config.legacy) {
+ if (!MathJax.Ajax.config.path.mhchem) {
+ MathJax.Ajax.config.path.mhchem = MathJax.Hub.config.root + "/extensions/TeX/mhchem3";
+ }
+ MathJax.Callback.Queue(
+ ["Require",MathJax.Ajax,"[mhchem]/mhchem.js"],
+ ["loadComplete",MathJax.Ajax,"[MathJax]/extensions/TeX/mhchem.js"]
+ );
+} else {
+
+MathJax.Hub.Register.StartupHook("TeX Jax Ready",function () {
+
+ var TEX = MathJax.InputJax.TeX;
+
+ /*
+ * This is the main class for handing the \ce and related commands.
+ * Its main method is Parse() which takes the argument to \ce and
+ * returns the corresponding TeX string.
+ */
+
+ var CE = MathJax.Object.Subclass({
+ string: "", // the \ce string being parsed
+ i: 0, // the current position in the string
+ tex: "", // the partially processed TeX result
+ TEX: "", // the full TeX result
+ atom: false, // last processed token is an atom
+ sup: "", // pending superscript
+ sub: "", // pending subscript
+ presup: "", // pending pre-superscript
+ presub: "", // pending pre-subscript
+
+ //
+ // Store the string when a CE object is created
+ //
+ Init: function (string) {this.string = string},
+
+ //
+ // These are the special characters and the methods that
+ // handle them. All others are passed through verbatim.
+ //
+ ParseTable: {
+ '-': "Minus",
+ '+': "Plus",
+ '(': "Open",
+ ')': "Close",
+ '[': "Open",
+ ']': "Close",
+ '<': "Less",
+ '^': "Superscript",
+ '_': "Subscript",
+ '*': "Dot",
+ '.': "Dot",
+ '=': "Equal",
+ '#': "Pound",
+ '$': "Math",
+ '\\': "Macro",
+ ' ': "Space"
+ },
+ //
+ // Basic arrow names for reactions
+ //
+ Arrows: {
+ '->': "rightarrow",
+ '<-': "leftarrow",
+ '<->': "leftrightarrow",
+ '<=>': "rightleftharpoons",
+ '<=>>': "Rightleftharpoons",
+ '<<=>': "Leftrightharpoons",
+ '^': "uparrow",
+ 'v': "downarrow"
+ },
+
+ //
+ // Implementations for the various bonds
+ // (the ~ ones are hacks that don't work well in NativeMML)
+ //
+ Bonds: {
+ '-': "-",
+ '=': "=",
+ '#': "\\equiv",
+ '~': "\\tripledash",
+ '~-': "\\begin{CEstack}{}\\tripledash\\\\-\\end{CEstack}",
+ '~=': "\\raise2mu{\\begin{CEstack}{}\\tripledash\\\\-\\\\-\\end{CEstack}}",
+ '~--': "\\raise2mu{\\begin{CEstack}{}\\tripledash\\\\-\\\\-\\end{CEstack}}",
+ '-~-': "\\raise2mu{\\begin{CEstack}{}-\\\\\\tripledash\\\\-\\end{CEstack}}",
+ '...': "{\\cdot}{\\cdot}{\\cdot}",
+ '....': "{\\cdot}{\\cdot}{\\cdot}{\\cdot}",
+ '->': "\\rightarrow",
+ '<-': "\\leftarrow",
+ '??': "\\text{??}" // unknown bond
+ },
+
+ //
+ // This converts the CE string to a TeX string.
+ // It loops through the string and calls the proper
+ // method depending on the ccurrent character.
+ //
+ Parse: function () {
+ this.tex = ""; this.atom = false;
+ while (this.i < this.string.length) {
+ var c = this.string.charAt(this.i);
+ if (c.match(/[a-z]/i)) {this.ParseLetter()}
+ else if (c.match(/[0-9]/)) {this.ParseNumber()}
+ else {this["Parse"+(this.ParseTable[c]||"Other")](c)}
+ }
+ this.FinishAtom(true);
+ return this.TEX;
+ },
+
+ //
+ // Make an atom name or a down arrow
+ //
+ ParseLetter: function () {
+ this.FinishAtom();
+ if (this.Match(/^v( |$)/)) {
+ this.tex += "{\\"+this.Arrows["v"]+"}";
+ } else {
+ this.tex += "\\text{"+this.Match(/^[a-z]+/i)+"}";
+ this.atom = true;
+ }
+ },
+
+ //
+ // Make a number or fraction preceding an atom,
+ // or a subscript for an atom.
+ //
+ ParseNumber: function () {
+ var n = this.Match(/^\d+/);
+ if (this.atom && !this.sub) {
+ this.sub = n;
+ } else {
+ this.FinishAtom();
+ var match = this.Match(/^\/\d+/);
+ if (match) {
+ var frac = "\\frac{"+n+"}{"+match.substr(1)+"}";
+ this.tex += "\\mathchoice{\\textstyle"+frac+"}{"+frac+"}{"+frac+"}{"+frac+"}";
+ } else {
+ this.tex += n;
+ if (this.i < this.string.length) {this.tex += "\\,"}
+ }
+ }
+ },
+
+ //
+ // Make a superscript minus, or an arrow, or a single bond.
+ //
+ ParseMinus: function (c) {
+ if (this.atom && (this.i === this.string.length-1 || this.string.charAt(this.i+1) === " ")) {
+ this.sup += c;
+ } else {
+ this.FinishAtom();
+ if (this.string.substr(this.i,2) === "->") {this.i += 2; this.AddArrow("->"); return}
+ else {this.tex += "{-}"}
+ }
+ this.i++;
+ },
+
+ //
+ // Make a superscript plus, or pass it through
+ //
+ ParsePlus: function (c) {
+ if (this.atom) {this.sup += c} else {this.FinishAtom(); this.tex += c}
+ this.i++;
+ },
+
+ //
+ // Handle dots and double or triple bonds
+ //
+ ParseDot: function (c) {this.FinishAtom(); this.tex += "\\cdot "; this.i++},
+ ParseEqual: function (c) {this.FinishAtom(); this.tex += "{=}"; this.i++},
+ ParsePound: function (c) {this.FinishAtom(); this.tex += "{\\equiv}"; this.i++},
+
+ //
+ // Look for (v) or (^), or pass it through
+ //
+ ParseOpen: function (c) {
+ this.FinishAtom();
+ var match = this.Match(/^\([v^]\)/);
+ if (match) {this.tex += "{\\"+this.Arrows[match.charAt(1)]+"}"}
+ else {this.tex += "{"+c; this.i++}
+ },
+ //
+ // Allow ) and ] to get super- and subscripts
+ //
+ ParseClose: function (c) {this.FinishAtom(); this.atom = true; this.tex += c+"}"; this.i++},
+
+ //
+ // Make the proper arrow
+ //
+ ParseLess: function (c) {
+ this.FinishAtom();
+ var arrow = this.Match(/^(<->?|<=>>?|<<=>)/);
+ if (!arrow) {this.tex += c; this.i++} else {this.AddArrow(arrow)}
+ },
+
+ //
+ // Look for a superscript, or an up arrow
+ //
+ ParseSuperscript: function (c) {
+ c = this.string.charAt(++this.i);
+ if (c === "{") {
+ this.i++; var m = this.Find("}");
+ if (m === "-.") {this.sup += "{-}{\\cdot}"}
+ else if (m) {this.sup += CE(m).Parse().replace(/^\{-\}/,"-")}
+ } else if (c === " " || c === "") {
+ this.tex += "{\\"+this.Arrows["^"]+"}"; this.i++;
+ } else {
+ var n = this.Match(/^(\d+|-\.)/);
+ if (n) {this.sup += n}
+ }
+ },
+ //
+ // Look for subscripts
+ //
+ ParseSubscript: function (c) {
+ if (this.string.charAt(++this.i) == "{") {
+ this.i++; this.sub += CE(this.Find("}")).Parse().replace(/^\{-\}/,"-");
+ } else {
+ var n = this.Match(/^\d+/);
+ if (n) {this.sub += n}
+ }
+ },
+
+ //
+ // Look for raw TeX code to include
+ //
+ ParseMath: function (c) {
+ this.FinishAtom();
+ this.i++; this.tex += this.Find(c);
+ },
+
+ //
+ // Look for specific macros for bonds
+ // and allow \} to have subscripts
+ //
+ ParseMacro: function (c) {
+ this.FinishAtom();
+ this.i++; var match = this.Match(/^([a-z]+|.)/i)||" ";
+ if (match === "sbond") {this.tex += "{-}"}
+ else if (match === "dbond") {this.tex += "{=}"}
+ else if (match === "tbond") {this.tex += "{\\equiv}"}
+ else if (match === "bond") {
+ var bond = (this.Match(/^\{.*?\}/)||"");
+ bond = bond.substr(1,bond.length-2);
+ this.tex += "{"+(this.Bonds[bond]||"\\text{??}")+"}";
+ }
+ else if (match === "{") {this.tex += "{\\{"}
+ else if (match === "}") {this.tex += "\\}}"; this.atom = true}
+ else {this.tex += c+match}
+ },
+
+ //
+ // Ignore spaces
+ //
+ ParseSpace: function (c) {this.FinishAtom(); this.i++},
+
+ //
+ // Pass anything else on verbatim
+ //
+ ParseOther: function (c) {this.FinishAtom(); this.tex += c; this.i++},
+
+ //
+ // Process an arrow (looking for brackets for above and below)
+ //
+ AddArrow: function (arrow) {
+ var c = this.Match(/^[CT]\[/);
+ if (c) {this.i--; c = c.charAt(0)}
+ var above = this.GetBracket(c), below = this.GetBracket(c);
+ arrow = this.Arrows[arrow];
+ if (above || below) {
+ if (below) {arrow += "["+below+"]"}
+ arrow += "{"+above+"}";
+ arrow = "\\mathrel{\\x"+arrow+"}";
+ } else {
+ arrow = "\\long"+arrow+" ";
+ }
+ this.tex += arrow;
+ },
+
+ //
+ // Handle the super and subscripts for an atom
+ //
+ FinishAtom: function (force) {
+ if (this.sup || this.sub || this.presup || this.presub) {
+ if (!force && !this.atom) {
+ if (this.tex === "" && !this.sup && !this.sub) return;
+ if (!this.presup && !this.presub &&
+ (this.tex === "" || this.tex === "{" ||
+ (this.tex === "}" && this.TEX.substr(-1) === "{"))) {
+ this.presup = this.sup, this.presub = this.sub; // save for later
+ this.sub = this.sup = "";
+ this.TEX += this.tex; this.tex = "";
+ return;
+ }
+ }
+ if (this.sub && !this.sup) {this.sup = "\\Space{0pt}{0pt}{.2em}"} // forces subscripts to align properly
+ if ((this.presup || this.presub) && this.tex !== "{") {
+ if (!this.presup && !this.sup) {this.presup = "\\Space{0pt}{0pt}{.2em}"}
+ this.tex = "\\CEprescripts{"+(this.presub||"\\CEnone")+"}{"+(this.presup||"\\CEnone")+"}"
+ + "{"+(this.tex !== "}" ? this.tex : "")+"}"
+ + "{"+(this.sub||"\\CEnone")+"}{"+(this.sup||"\\CEnone")+"}"
+ + (this.tex === "}" ? "}" : "");
+ this.presub = this.presup = "";
+ } else {
+ if (this.sup) this.tex += "^{"+this.sup+"}";
+ if (this.sub) this.tex += "_{"+this.sub+"}";
+ }
+ this.sup = this.sub = "";
+ }
+ this.TEX += this.tex; this.tex = "";
+ this.atom = false;
+ },
+
+ //
+ // Find a bracket group and handle C and T prefixes
+ //
+ GetBracket: function (c) {
+ if (this.string.charAt(this.i) !== "[") {return ""}
+ this.i++; var bracket = this.Find("]");
+ if (c === "C") {bracket = "\\ce{"+bracket+"}"} else
+ if (c === "T") {
+ if (!bracket.match(/^\{.*\}$/)) {bracket = "{"+bracket+"}"}
+ bracket = "\\text"+bracket;
+ };
+ return bracket;
+ },
+
+ //
+ // Check if the string matches a regular expression
+ // and move past it if so, returning the match
+ //
+ Match: function (regex) {
+ var match = regex.exec(this.string.substr(this.i));
+ if (match) {match = match[0]; this.i += match.length}
+ return match;
+ },
+
+ //
+ // Find a particular character, skipping over braced groups
+ //
+ Find: function (c) {
+ var m = this.string.length, i = this.i, braces = 0;
+ while (this.i < m) {
+ var C = this.string.charAt(this.i++);
+ if (C === c && braces === 0) {return this.string.substr(i,this.i-i-1)}
+ if (C === "{") {braces++} else
+ if (C === "}") {
+ if (braces) {braces--}
+ else {
+ TEX.Error(["ExtraCloseMissingOpen","Extra close brace or missing open brace"])
+ }
+ }
+ }
+ if (braces) {TEX.Error(["MissingCloseBrace","Missing close brace"])}
+ TEX.Error(["NoClosingChar","Can't find closing %1",c]);
+ }
+
+ });
+
+ MathJax.Extension["TeX/mhchem"].CE = CE;
+
+ /***************************************************************************/
+
+ TEX.Definitions.Add({
+ macros: {
+ //
+ // Set up the macros for chemistry
+ //
+ ce: 'CE',
+ cf: 'CE',
+ cee: 'CE',
+
+ //
+ // Make these load AMSmath package (redefined below when loaded)
+ //
+ xleftrightarrow: ['Extension','AMSmath'],
+ xrightleftharpoons: ['Extension','AMSmath'],
+ xRightleftharpoons: ['Extension','AMSmath'],
+ xLeftrightharpoons: ['Extension','AMSmath'],
+
+ // FIXME: These don't work well in FF NativeMML mode
+ longrightleftharpoons: ["Macro","\\stackrel{\\textstyle{{-}\\!\\!{\\rightharpoonup}}}{\\smash{{\\leftharpoondown}\\!\\!{-}}}"],
+ longRightleftharpoons: ["Macro","\\stackrel{\\textstyle{-}\\!\\!{\\rightharpoonup}}{\\small\\smash\\leftharpoondown}"],
+ longLeftrightharpoons: ["Macro","\\stackrel{\\rightharpoonup}{{{\\leftharpoondown}\\!\\!\\textstyle{-}}}"],
+
+ //
+ // Add \hyphen used in some mhchem examples
+ //
+ hyphen: ["Macro","\\text{-}"],
+
+ //
+ // Handle prescripts and none
+ //
+ CEprescripts: "CEprescripts",
+ CEnone: "CEnone",
+
+ //
+ // Needed for \bond for the ~ forms
+ //
+ tripledash: ["Macro","\\raise3mu{\\tiny\\text{-}\\kern2mu\\text{-}\\kern2mu\\text{-}}"]
+ },
+
+ //
+ // Needed for \bond for the ~ forms
+ //
+ environment: {
+ CEstack: ['Array',null,null,null,'r',null,"0.001em",'T',1]
+ }
+ },null,true);
+
+ if (!MathJax.Extension["TeX/AMSmath"]) {
+ TEX.Definitions.Add({
+ macros: {
+ xrightarrow: ['Extension','AMSmath'],
+ xleftarrow: ['Extension','AMSmath']
+ }
+ },null,true);
+ }
+
+ //
+ // These arrows need to wait until AMSmath is loaded
+ //
+ MathJax.Hub.Register.StartupHook("TeX AMSmath Ready",function () {
+ TEX.Definitions.Add({
+ macros: {
+ //
+ // Some of these are hacks for now
+ //
+ xleftrightarrow: ['xArrow',0x2194,6,6],
+ xrightleftharpoons: ['xArrow',0x21CC,5,7], // FIXME: doesn't stretch in HTML-CSS output
+ xRightleftharpoons: ['xArrow',0x21CC,5,7], // FIXME: how should this be handled?
+ xLeftrightharpoons: ['xArrow',0x21CC,5,7]
+ }
+ },null,true);
+ });
+
+ TEX.Parse.Augment({
+
+ //
+ // Implements \ce and friends
+ //
+ CE: function (name) {
+ var arg = this.GetArgument(name);
+ var tex = CE(arg).Parse();
+ this.string = tex + this.string.substr(this.i); this.i = 0;
+ },
+
+ //
+ // Implements \CEprescripts{presub}{presup}{base}{sub}{sup}
+ //
+ CEprescripts: function (name) {
+ var presub = this.ParseArg(name),
+ presup = this.ParseArg(name),
+ base = this.ParseArg(name),
+ sub = this.ParseArg(name),
+ sup = this.ParseArg(name);
+ var MML = MathJax.ElementJax.mml;
+ this.Push(MML.mmultiscripts(base,sub,sup,MML.mprescripts(),presub,presup));
+ },
+ CEnone: function (name) {
+ this.Push(MathJax.ElementJax.mml.none());
+ }
+
+ });
+
+ //
+ // Indicate that the extension is ready
+ //
+ MathJax.Hub.Startup.signal.Post("TeX mhchem Ready");
+
+});
+
+MathJax.Ajax.loadComplete("[MathJax]/extensions/TeX/mhchem.js");
+
+}}
+// @license-end