This commit is contained in:
520
AutoLaTeX/MathJax/extensions/TeX/mhchem.js
vendored
Normal file
520
AutoLaTeX/MathJax/extensions/TeX/mhchem.js
vendored
Normal file
@@ -0,0 +1,520 @@
|
||||
/* -*- 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-2017 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.2",
|
||||
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 preceeding 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");
|
||||
|
||||
}}
|
||||
Reference in New Issue
Block a user