| /********************************* | |
| * Symbols for Basic Mathematics | |
| ********************************/ | |
| var Digit = P(VanillaSymbol, function(_, super_) { | |
| _.createLeftOf = function(cursor) { | |
| if (cursor.options.autoSubscriptNumerals | |
| && cursor.parent !== cursor.parent.parent.sub | |
| && ((cursor[L] instanceof Variable && cursor[L].isItalic !== false) | |
| || (cursor[L] instanceof SupSub | |
| && cursor[L][L] instanceof Variable | |
| && cursor[L][L].isItalic !== false))) { | |
| LatexCmds._().createLeftOf(cursor); | |
| super_.createLeftOf.call(this, cursor); | |
| cursor.insRightOf(cursor.parent.parent); | |
| } | |
| else super_.createLeftOf.call(this, cursor); | |
| }; | |
| }); | |
| var Variable = P(Symbol, function(_, super_) { | |
| _.init = function(ch, html) { | |
| super_.init.call(this, ch, '<var>'+(html || ch)+'</var>'); | |
| }; | |
| _.text = function() { | |
| var text = this.ctrlSeq; | |
| if (this[L] && !(this[L] instanceof Variable) | |
| && !(this[L] instanceof BinaryOperator) | |
| && this[L].ctrlSeq !== "\\ ") | |
| text = '*' + text; | |
| if (this[R] && !(this[R] instanceof BinaryOperator) | |
| && !(this[R] instanceof SupSub)) | |
| text += '*'; | |
| return text; | |
| }; | |
| }); | |
| Options.p.autoCommands = { _maxLength: 0 }; | |
| optionProcessors.autoCommands = function(cmds) { | |
| if (!/^[a-z]+(?: [a-z]+)*$/i.test(cmds)) { | |
| throw '"'+cmds+'" not a space-delimited list of only letters'; | |
| } | |
| var list = cmds.split(' '), dict = {}, maxLength = 0; | |
| for (var i = 0; i < list.length; i += 1) { | |
| var cmd = list[i]; | |
| if (cmd.length < 2) { | |
| throw 'autocommand "'+cmd+'" not minimum length of 2'; | |
| } | |
| if (LatexCmds[cmd] === OperatorName) { | |
| throw '"' + cmd + '" is a built-in operator name'; | |
| } | |
| dict[cmd] = 1; | |
| maxLength = max(maxLength, cmd.length); | |
| } | |
| dict._maxLength = maxLength; | |
| return dict; | |
| }; | |
| var Letter = P(Variable, function(_, super_) { | |
| _.init = function(ch) { return super_.init.call(this, this.letter = ch); }; | |
| _.createLeftOf = function(cursor) { | |
| super_.createLeftOf.apply(this, arguments); | |
| var autoCmds = cursor.options.autoCommands, maxLength = autoCmds._maxLength; | |
| if (maxLength > 0) { | |
| // want longest possible autocommand, so join together longest | |
| // sequence of letters | |
| var str = '', l = this, i = 0; | |
| // FIXME: l.ctrlSeq === l.letter checks if first or last in an operator name | |
| while (l instanceof Letter && l.ctrlSeq === l.letter && i < maxLength) { | |
| str = l.letter + str, l = l[L], i += 1; | |
| } | |
| // check for an autocommand, going thru substrings longest to shortest | |
| while (str.length) { | |
| if (autoCmds.hasOwnProperty(str)) { | |
| for (var i = 1, l = this; i < str.length; i += 1, l = l[L]); | |
| Fragment(l, this).remove(); | |
| cursor[L] = l[L]; | |
| return LatexCmds[str](str).createLeftOf(cursor); | |
| } | |
| str = str.slice(1); | |
| } | |
| } | |
| }; | |
| _.italicize = function(bool) { | |
| this.isItalic = bool; | |
| this.jQ.toggleClass('mq-operator-name', !bool); | |
| return this; | |
| }; | |
| _.finalizeTree = _.siblingDeleted = _.siblingCreated = function(opts, dir) { | |
| // don't auto-un-italicize if the sibling to my right changed (dir === R or | |
| // undefined) and it's now a Letter, it will un-italicize everyone | |
| if (dir !== L && this[R] instanceof Letter) return; | |
| this.autoUnItalicize(opts); | |
| }; | |
| _.autoUnItalicize = function(opts) { | |
| var autoOps = opts.autoOperatorNames; | |
| if (autoOps._maxLength === 0) return; | |
| // want longest possible operator names, so join together entire contiguous | |
| // sequence of letters | |
| var str = this.letter; | |
| for (var l = this[L]; l instanceof Letter; l = l[L]) str = l.letter + str; | |
| for (var r = this[R]; r instanceof Letter; r = r[R]) str += r.letter; | |
| // removeClass and delete flags from all letters before figuring out | |
| // which, if any, are part of an operator name | |
| Fragment(l[R] || this.parent.ends[L], r[L] || this.parent.ends[R]).each(function(el) { | |
| el.italicize(true).jQ.removeClass('mq-first mq-last mq-followed-by-supsub'); | |
| el.ctrlSeq = el.letter; | |
| }); | |
| // check for operator names: at each position from left to right, check | |
| // substrings from longest to shortest | |
| outer: for (var i = 0, first = l[R] || this.parent.ends[L]; i < str.length; i += 1, first = first[R]) { | |
| for (var len = min(autoOps._maxLength, str.length - i); len > 0; len -= 1) { | |
| var word = str.slice(i, i + len); | |
| if (autoOps.hasOwnProperty(word)) { | |
| for (var j = 0, letter = first; j < len; j += 1, letter = letter[R]) { | |
| letter.italicize(false); | |
| var last = letter; | |
| } | |
| var isBuiltIn = BuiltInOpNames.hasOwnProperty(word); | |
| first.ctrlSeq = (isBuiltIn ? '\\' : '\\operatorname{') + first.ctrlSeq; | |
| last.ctrlSeq += (isBuiltIn ? ' ' : '}'); | |
| if (TwoWordOpNames.hasOwnProperty(word)) last[L][L][L].jQ.addClass('mq-last'); | |
| if (!shouldOmitPadding(first[L])) first.jQ.addClass('mq-first'); | |
| if (!shouldOmitPadding(last[R])) { | |
| if (last[R] instanceof SupSub) { | |
| var supsub = last[R]; // XXX monkey-patching, but what's the right thing here? | |
| // Have operatorname-specific code in SupSub? A CSS-like language to style the | |
| // math tree, but which ignores cursor and selection (which CSS can't)? | |
| var respace = supsub.siblingCreated = supsub.siblingDeleted = function() { | |
| supsub.jQ.toggleClass('mq-after-operator-name', !(supsub[R] instanceof Bracket)); | |
| }; | |
| respace(); | |
| } | |
| else { | |
| last.jQ.toggleClass('mq-last', !(last[R] instanceof Bracket)); | |
| } | |
| } | |
| i += len - 1; | |
| first = last; | |
| continue outer; | |
| } | |
| } | |
| } | |
| }; | |
| function shouldOmitPadding(node) { | |
| // omit padding if no node, or if node already has padding (to avoid double-padding) | |
| return !node || (node instanceof BinaryOperator) || (node instanceof SummationNotation); | |
| } | |
| }); | |
| var BuiltInOpNames = {}; // the set of operator names like \sin, \cos, etc that | |
| // are built-into LaTeX, see Section 3.17 of the Short Math Guide: http://tinyurl.com/jm9okjc | |
| // MathQuill auto-unitalicizes some operator names not in that set, like 'hcf' | |
| // and 'arsinh', which must be exported as \operatorname{hcf} and | |
| // \operatorname{arsinh}. Note: over/under line/arrow \lim variants like | |
| // \varlimsup are not supported | |
| var AutoOpNames = Options.p.autoOperatorNames = { _maxLength: 9 }; // the set | |
| // of operator names that MathQuill auto-unitalicizes by default; overridable | |
| var TwoWordOpNames = { limsup: 1, liminf: 1, projlim: 1, injlim: 1 }; | |
| (function() { | |
| var mostOps = ('arg deg det dim exp gcd hom inf ker lg lim ln log max min sup' | |
| + ' limsup liminf injlim projlim Pr').split(' '); | |
| for (var i = 0; i < mostOps.length; i += 1) { | |
| BuiltInOpNames[mostOps[i]] = AutoOpNames[mostOps[i]] = 1; | |
| } | |
| var builtInTrigs = // why coth but not sech and csch, LaTeX? | |
| 'sin cos tan arcsin arccos arctan sinh cosh tanh sec csc cot coth'.split(' '); | |
| for (var i = 0; i < builtInTrigs.length; i += 1) { | |
| BuiltInOpNames[builtInTrigs[i]] = 1; | |
| } | |
| var autoTrigs = 'sin cos tan sec cosec csc cotan cot ctg'.split(' '); | |
| for (var i = 0; i < autoTrigs.length; i += 1) { | |
| AutoOpNames[autoTrigs[i]] = | |
| AutoOpNames['arc'+autoTrigs[i]] = | |
| AutoOpNames[autoTrigs[i]+'h'] = | |
| AutoOpNames['ar'+autoTrigs[i]+'h'] = | |
| AutoOpNames['arc'+autoTrigs[i]+'h'] = 1; | |
| } | |
| // compat with some of the nonstandard LaTeX exported by MathQuill | |
| // before #247. None of these are real LaTeX commands so, seems safe | |
| var moreNonstandardOps = 'gcf hcf lcm proj span'.split(' '); | |
| for (var i = 0; i < moreNonstandardOps.length; i += 1) { | |
| AutoOpNames[moreNonstandardOps[i]] = 1; | |
| } | |
| }()); | |
| optionProcessors.autoOperatorNames = function(cmds) { | |
| if (!/^[a-z]+(?: [a-z]+)*$/i.test(cmds)) { | |
| throw '"'+cmds+'" not a space-delimited list of only letters'; | |
| } | |
| var list = cmds.split(' '), dict = {}, maxLength = 0; | |
| for (var i = 0; i < list.length; i += 1) { | |
| var cmd = list[i]; | |
| if (cmd.length < 2) { | |
| throw '"'+cmd+'" not minimum length of 2'; | |
| } | |
| dict[cmd] = 1; | |
| maxLength = max(maxLength, cmd.length); | |
| } | |
| dict._maxLength = maxLength; | |
| return dict; | |
| }; | |
| var OperatorName = P(Symbol, function(_, super_) { | |
| _.init = function(fn) { this.ctrlSeq = fn; }; | |
| _.createLeftOf = function(cursor) { | |
| var fn = this.ctrlSeq; | |
| for (var i = 0; i < fn.length; i += 1) { | |
| Letter(fn.charAt(i)).createLeftOf(cursor); | |
| } | |
| }; | |
| _.parser = function() { | |
| var fn = this.ctrlSeq; | |
| var block = MathBlock(); | |
| for (var i = 0; i < fn.length; i += 1) { | |
| Letter(fn.charAt(i)).adopt(block, block.ends[R], 0); | |
| } | |
| return Parser.succeed(block.children()); | |
| }; | |
| }); | |
| for (var fn in AutoOpNames) if (AutoOpNames.hasOwnProperty(fn)) { | |
| LatexCmds[fn] = OperatorName; | |
| } | |
| LatexCmds.operatorname = P(MathCommand, function(_) { | |
| _.createLeftOf = noop; | |
| _.numBlocks = function() { return 1; }; | |
| _.parser = function() { | |
| return latexMathParser.block.map(function(b) { return b.children(); }); | |
| }; | |
| }); | |
| LatexCmds.f = P(Letter, function(_, super_) { | |
| _.init = function() { | |
| Symbol.p.init.call(this, this.letter = 'f', '<var class="mq-f">f</var>'); | |
| }; | |
| _.italicize = function(bool) { | |
| this.jQ.html('f').toggleClass('mq-f', bool); | |
| return super_.italicize.apply(this, arguments); | |
| }; | |
| }); | |
| // VanillaSymbol's | |
| LatexCmds[' '] = LatexCmds.space = bind(VanillaSymbol, '\\ ', ' '); | |
| LatexCmds["'"] = LatexCmds.prime = bind(VanillaSymbol, "'", '′'); | |
| LatexCmds['″'] = LatexCmds.dprime = bind(VanillaSymbol, '″', '″'); | |
| LatexCmds.backslash = bind(VanillaSymbol,'\\backslash ','\\'); | |
| if (!CharCmds['\\']) CharCmds['\\'] = LatexCmds.backslash; | |
| LatexCmds.$ = bind(VanillaSymbol, '\\$', '$'); | |
| // does not use Symbola font | |
| var NonSymbolaSymbol = P(Symbol, function(_, super_) { | |
| _.init = function(ch, html) { | |
| super_.init.call(this, ch, '<span class="mq-nonSymbola">'+(html || ch)+'</span>'); | |
| }; | |
| }); | |
| LatexCmds['@'] = NonSymbolaSymbol; | |
| LatexCmds['&'] = bind(NonSymbolaSymbol, '\\&', '&'); | |
| LatexCmds['%'] = bind(NonSymbolaSymbol, '\\%', '%'); | |
| //the following are all Greek to me, but this helped a lot: http://www.ams.org/STIX/ion/stixsig03.html | |
| //lowercase Greek letter variables | |
| LatexCmds.alpha = | |
| LatexCmds.beta = | |
| LatexCmds.gamma = | |
| LatexCmds.delta = | |
| LatexCmds.zeta = | |
| LatexCmds.eta = | |
| LatexCmds.theta = | |
| LatexCmds.iota = | |
| LatexCmds.kappa = | |
| LatexCmds.mu = | |
| LatexCmds.nu = | |
| LatexCmds.xi = | |
| LatexCmds.rho = | |
| LatexCmds.sigma = | |
| LatexCmds.tau = | |
| LatexCmds.chi = | |
| LatexCmds.psi = | |
| LatexCmds.omega = P(Variable, function(_, super_) { | |
| _.init = function(latex) { | |
| super_.init.call(this,'\\'+latex+' ','&'+latex+';'); | |
| }; | |
| }); | |
| //why can't anybody FUCKING agree on these | |
| LatexCmds.phi = //W3C or Unicode? | |
| bind(Variable,'\\phi ','ϕ'); | |
| LatexCmds.phiv = //Elsevier and 9573-13 | |
| LatexCmds.varphi = //AMS and LaTeX | |
| bind(Variable,'\\varphi ','φ'); | |
| LatexCmds.epsilon = //W3C or Unicode? | |
| bind(Variable,'\\epsilon ','ϵ'); | |
| LatexCmds.epsiv = //Elsevier and 9573-13 | |
| LatexCmds.varepsilon = //AMS and LaTeX | |
| bind(Variable,'\\varepsilon ','ε'); | |
| LatexCmds.piv = //W3C/Unicode and Elsevier and 9573-13 | |
| LatexCmds.varpi = //AMS and LaTeX | |
| bind(Variable,'\\varpi ','ϖ'); | |
| LatexCmds.sigmaf = //W3C/Unicode | |
| LatexCmds.sigmav = //Elsevier | |
| LatexCmds.varsigma = //LaTeX | |
| bind(Variable,'\\varsigma ','ς'); | |
| LatexCmds.thetav = //Elsevier and 9573-13 | |
| LatexCmds.vartheta = //AMS and LaTeX | |
| LatexCmds.thetasym = //W3C/Unicode | |
| bind(Variable,'\\vartheta ','ϑ'); | |
| LatexCmds.upsilon = //AMS and LaTeX and W3C/Unicode | |
| LatexCmds.upsi = //Elsevier and 9573-13 | |
| bind(Variable,'\\upsilon ','υ'); | |
| //these aren't even mentioned in the HTML character entity references | |
| LatexCmds.gammad = //Elsevier | |
| LatexCmds.Gammad = //9573-13 -- WTF, right? I dunno if this was a typo in the reference (see above) | |
| LatexCmds.digamma = //LaTeX | |
| bind(Variable,'\\digamma ','ϝ'); | |
| LatexCmds.kappav = //Elsevier | |
| LatexCmds.varkappa = //AMS and LaTeX | |
| bind(Variable,'\\varkappa ','ϰ'); | |
| LatexCmds.rhov = //Elsevier and 9573-13 | |
| LatexCmds.varrho = //AMS and LaTeX | |
| bind(Variable,'\\varrho ','ϱ'); | |
| //Greek constants, look best in non-italicized Times New Roman | |
| LatexCmds.pi = LatexCmds['π'] = bind(NonSymbolaSymbol,'\\pi ','π'); | |
| LatexCmds.lambda = bind(NonSymbolaSymbol,'\\lambda ','λ'); | |
| //uppercase greek letters | |
| LatexCmds.Upsilon = //LaTeX | |
| LatexCmds.Upsi = //Elsevier and 9573-13 | |
| LatexCmds.upsih = //W3C/Unicode "upsilon with hook" | |
| LatexCmds.Upsih = //'cos it makes sense to me | |
| bind(Symbol,'\\Upsilon ','<var style="font-family: serif">ϒ</var>'); //Symbola's 'upsilon with a hook' is a capital Y without hooks :( | |
| //other symbols with the same LaTeX command and HTML character entity reference | |
| LatexCmds.Gamma = | |
| LatexCmds.Delta = | |
| LatexCmds.Theta = | |
| LatexCmds.Lambda = | |
| LatexCmds.Xi = | |
| LatexCmds.Pi = | |
| LatexCmds.Sigma = | |
| LatexCmds.Phi = | |
| LatexCmds.Psi = | |
| LatexCmds.Omega = | |
| LatexCmds.forall = P(VanillaSymbol, function(_, super_) { | |
| _.init = function(latex) { | |
| super_.init.call(this,'\\'+latex+' ','&'+latex+';'); | |
| }; | |
| }); | |
| // symbols that aren't a single MathCommand, but are instead a whole | |
| // Fragment. Creates the Fragment from a LaTeX string | |
| var LatexFragment = P(MathCommand, function(_) { | |
| _.init = function(latex) { this.latex = latex; }; | |
| _.createLeftOf = function(cursor) { | |
| var block = latexMathParser.parse(this.latex); | |
| block.children().adopt(cursor.parent, cursor[L], cursor[R]); | |
| cursor[L] = block.ends[R]; | |
| block.jQize().insertBefore(cursor.jQ); | |
| block.finalizeInsert(cursor.options, cursor); | |
| if (block.ends[R][R].siblingCreated) block.ends[R][R].siblingCreated(cursor.options, L); | |
| if (block.ends[L][L].siblingCreated) block.ends[L][L].siblingCreated(cursor.options, R); | |
| cursor.parent.bubble('reflow'); | |
| }; | |
| _.parser = function() { | |
| var frag = latexMathParser.parse(this.latex).children(); | |
| return Parser.succeed(frag); | |
| }; | |
| }); | |
| // for what seems to me like [stupid reasons][1], Unicode provides | |
| // subscripted and superscripted versions of all ten Arabic numerals, | |
| // as well as [so-called "vulgar fractions"][2]. | |
| // Nobody really cares about most of them, but some of them actually | |
| // predate Unicode, dating back to [ISO-8859-1][3], apparently also | |
| // known as "Latin-1", which among other things [Windows-1252][4] | |
| // largely coincides with, so Microsoft Word sometimes inserts them | |
| // and they get copy-pasted into MathQuill. | |
| // | |
| // (Irrelevant but funny story: though not a superset of Latin-1 aka | |
| // ISO-8859-1, Windows-1252 **is** a strict superset of the "closely | |
| // related but distinct"[3] "ISO 8859-1" -- see the lack of a dash | |
| // after "ISO"? Completely different character set, like elephants vs | |
| // elephant seals, or "Zombies" vs "Zombie Redneck Torture Family". | |
| // What kind of idiot would get them confused. | |
| // People in fact got them confused so much, it was so common to | |
| // mislabel Windows-1252 text as ISO-8859-1, that most modern web | |
| // browsers and email clients treat the MIME charset of ISO-8859-1 | |
| // as actually Windows-1252, behavior now standard in the HTML5 spec.) | |
| // | |
| // [1]: http://en.wikipedia.org/wiki/Unicode_subscripts_andsuper_scripts | |
| // [2]: http://en.wikipedia.org/wiki/Number_Forms | |
| // [3]: http://en.wikipedia.org/wiki/ISO/IEC_8859-1 | |
| // [4]: http://en.wikipedia.org/wiki/Windows-1252 | |
| LatexCmds['¹'] = bind(LatexFragment, '^1'); | |
| LatexCmds['²'] = bind(LatexFragment, '^2'); | |
| LatexCmds['³'] = bind(LatexFragment, '^3'); | |
| LatexCmds['¼'] = bind(LatexFragment, '\\frac14'); | |
| LatexCmds['½'] = bind(LatexFragment, '\\frac12'); | |
| LatexCmds['¾'] = bind(LatexFragment, '\\frac34'); | |
| var PlusMinus = P(BinaryOperator, function(_) { | |
| _.init = VanillaSymbol.prototype.init; | |
| _.contactWeld = _.siblingCreated = _.siblingDeleted = function(opts, dir) { | |
| function determineOpClassType(node) { | |
| if (node[L]) { | |
| // If the left sibling is a binary operator or a separator (comma, semicolon, colon) | |
| // or an open bracket (open parenthesis, open square bracket) | |
| // consider the operator to be unary | |
| if (node[L] instanceof BinaryOperator || /^[,;:\(\[]$/.test(node[L].ctrlSeq)) { | |
| return ''; | |
| } | |
| } else if (node.parent && node.parent.parent && node.parent.parent.isStyleBlock()) { | |
| //if we are in a style block at the leftmost edge, determine unary/binary based on | |
| //the style block | |
| //this allows style blocks to be transparent for unary/binary purposes | |
| return determineOpClassType(node.parent.parent); | |
| } else { | |
| return ''; | |
| } | |
| return 'mq-binary-operator'; | |
| }; | |
| if (dir === R) return; // ignore if sibling only changed on the right | |
| this.jQ[0].className = determineOpClassType(this); | |
| return this; | |
| }; | |
| }); | |
| LatexCmds['+'] = bind(PlusMinus, '+', '+'); | |
| //yes, these are different dashes, I think one is an en dash and the other is a hyphen | |
| LatexCmds['–'] = LatexCmds['-'] = bind(PlusMinus, '-', '−'); | |
| LatexCmds['±'] = LatexCmds.pm = LatexCmds.plusmn = LatexCmds.plusminus = | |
| bind(PlusMinus,'\\pm ','±'); | |
| LatexCmds.mp = LatexCmds.mnplus = LatexCmds.minusplus = | |
| bind(PlusMinus,'\\mp ','∓'); | |
| CharCmds['*'] = LatexCmds.sdot = LatexCmds.cdot = | |
| bind(BinaryOperator, '\\cdot ', '·', '*'); | |
| //semantically should be ⋅, but · looks better | |
| var Inequality = P(BinaryOperator, function(_, super_) { | |
| _.init = function(data, strict) { | |
| this.data = data; | |
| this.strict = strict; | |
| var strictness = (strict ? 'Strict' : ''); | |
| super_.init.call(this, data['ctrlSeq'+strictness], data['html'+strictness], | |
| data['text'+strictness]); | |
| }; | |
| _.swap = function(strict) { | |
| this.strict = strict; | |
| var strictness = (strict ? 'Strict' : ''); | |
| this.ctrlSeq = this.data['ctrlSeq'+strictness]; | |
| this.jQ.html(this.data['html'+strictness]); | |
| this.textTemplate = [ this.data['text'+strictness] ]; | |
| }; | |
| _.deleteTowards = function(dir, cursor) { | |
| if (dir === L && !this.strict) { | |
| this.swap(true); | |
| this.bubble('reflow'); | |
| return; | |
| } | |
| super_.deleteTowards.apply(this, arguments); | |
| }; | |
| }); | |
| var less = { ctrlSeq: '\\le ', html: '≤', text: '≤', | |
| ctrlSeqStrict: '<', htmlStrict: '<', textStrict: '<' }; | |
| var greater = { ctrlSeq: '\\ge ', html: '≥', text: '≥', | |
| ctrlSeqStrict: '>', htmlStrict: '>', textStrict: '>' }; | |
| LatexCmds['<'] = LatexCmds.lt = bind(Inequality, less, true); | |
| LatexCmds['>'] = LatexCmds.gt = bind(Inequality, greater, true); | |
| LatexCmds['≤'] = LatexCmds.le = LatexCmds.leq = bind(Inequality, less, false); | |
| LatexCmds['≥'] = LatexCmds.ge = LatexCmds.geq = bind(Inequality, greater, false); | |
| var Equality = P(BinaryOperator, function(_, super_) { | |
| _.init = function() { | |
| super_.init.call(this, '=', '='); | |
| }; | |
| _.createLeftOf = function(cursor) { | |
| if (cursor[L] instanceof Inequality && cursor[L].strict) { | |
| cursor[L].swap(false); | |
| cursor[L].bubble('reflow'); | |
| return; | |
| } | |
| super_.createLeftOf.apply(this, arguments); | |
| }; | |
| }); | |
| LatexCmds['='] = Equality; | |
| LatexCmds['×'] = LatexCmds.times = bind(BinaryOperator, '\\times ', '×', '[x]'); | |
| LatexCmds['÷'] = LatexCmds.div = LatexCmds.divide = LatexCmds.divides = | |
| bind(BinaryOperator,'\\div ','÷', '[/]'); | |
| CharCmds['~'] = LatexCmds.sim = bind(BinaryOperator, '\\sim ', '~', '~'); |