vendor/assets/javascripts/mathquill.js in mathquill_rails_dev-0.9.3.3 vs vendor/assets/javascripts/mathquill.js in mathquill_rails_dev-0.9.3.4

- old
+ new

@@ -1,4874 +1,3 @@ -/** - * MathQuill: http://mathquill.com - * by Jay and Han (laughinghan@gmail.com) - * - * This Source Code Form is subject to the terms of the - * Mozilla Public License, v. 2.0. If a copy of the MPL - * was not distributed with this file, You can obtain - * one at http://mozilla.org/MPL/2.0/. - */ - -(function() { - - var jQuery = window.jQuery, - undefined, - mqCmdId = 'mathquill-command-id', - mqBlockId = 'mathquill-block-id', - min = Math.min, - max = Math.max; - - function noop() {} - - /** - * A utility higher-order function that makes defining variadic - * functions more convenient by letting you essentially define functions - * with the last argument as a splat, i.e. the last argument "gathers up" - * remaining arguments to the function: - * var doStuff = variadic(function(first, rest) { return rest; }); - * doStuff(1, 2, 3); // => [2, 3] - */ - var __slice = [].slice; - function variadic(fn) { - var numFixedArgs = fn.length - 1; - return function() { - var args = __slice.call(arguments, 0, numFixedArgs); - var varArg = __slice.call(arguments, numFixedArgs); - return fn.apply(this, args.concat([ varArg ])); - }; - } - - /** - * A utility higher-order function that makes combining object-oriented - * programming and functional programming techniques more convenient: - * given a method name and any number of arguments to be bound, returns - * a function that calls it's first argument's method of that name (if - * it exists) with the bound arguments and any additional arguments that - * are passed: - * var sendMethod = send('method', 1, 2); - * var obj = { method: function() { return Array.apply(this, arguments); } }; - * sendMethod(obj, 3, 4); // => [1, 2, 3, 4] - * // or more specifically, - * var obj2 = { method: function(one, two, three) { return one*two + three; } }; - * sendMethod(obj2, 3); // => 5 - * sendMethod(obj2, 4); // => 6 - */ - var send = variadic(function(method, args) { - return variadic(function(obj, moreArgs) { - if (method in obj) return obj[method].apply(obj, args.concat(moreArgs)); - }); - }); - - /** - * A utility higher-order function that creates "implicit iterators" - * from "generators": given a function that takes in a sole argument, - * a "yield_" function, that calls "yield_" repeatedly with an object as - * a sole argument (presumably objects being iterated over), returns - * a function that calls it's first argument on each of those objects - * (if the first argument is a function, it is called repeatedly with - * each object as the first argument, otherwise it is stringified and - * the method of that name is called on each object (if such a method - * exists)), passing along all additional arguments: - * var a = [ - * { method: function(list) { list.push(1); } }, - * { method: function(list) { list.push(2); } }, - * { method: function(list) { list.push(3); } } - * ]; - * a.each = iterator(function(yield_) { - * for (var i in this) yield_(this[i]); - * }); - * var list = []; - * a.each('method', list); - * list; // => [1, 2, 3] - * // Note that the for-in loop will yield 'each', but 'each' maps to - * // the function object created by iterator() which does not have a - * // .method() method, so that just fails silently. - */ - function iterator(generator) { - return variadic(function(fn, args) { - if (typeof fn !== 'function') fn = send(fn); - var yield_ = function(obj) { return fn.apply(obj, [ obj ].concat(args)); }; - return generator.call(this, yield_); - }); - } - - /** - * sugar to make defining lots of commands easier. - * TODO: rethink this. - */ - function bind(cons /*, args... */) { - var args = __slice.call(arguments, 1); - return function() { - return cons.apply(this, args); - }; - } - - /** - * a development-only debug method. This definition and all - * calls to `pray` will be stripped from the minified - * build of mathquill. - * - * This function must be called by name to be removed - * at compile time. Do not define another function - * with the same name, and only call this function by - * name. - */ - function pray(message, cond) { - if (!cond) throw new Error('prayer failed: '+message); - } - var P = (function(prototype, ownProperty, undefined) { - // helper functions that also help minification - function isObject(o) { return typeof o === 'object'; } - function isFunction(f) { return typeof f === 'function'; } - - // used to extend the prototypes of superclasses (which might not - // have `.Bare`s) - function SuperclassBare() {} - - return function P(_superclass /* = Object */, definition) { - // handle the case where no superclass is given - if (definition === undefined) { - definition = _superclass; - _superclass = Object; - } - - // C is the class to be returned. - // - // It delegates to instantiating an instance of `Bare`, so that it - // will always return a new instance regardless of the calling - // context. - // - // TODO: the Chrome inspector shows all created objects as `C` - // rather than `Object`. Setting the .name property seems to - // have no effect. Is there a way to override this behavior? - function C() { - var self = new Bare; - if (isFunction(self.init)) self.init.apply(self, arguments); - return self; - } - - // C.Bare is a class with a noop constructor. Its prototype is the - // same as C, so that instances of C.Bare are also instances of C. - // New objects can be allocated without initialization by calling - // `new MyClass.Bare`. - function Bare() {} - C.Bare = Bare; - - // Set up the prototype of the new class. - var _super = SuperclassBare[prototype] = _superclass[prototype]; - var proto = Bare[prototype] = C[prototype] = C.p = new SuperclassBare; - - // other variables, as a minifier optimization - var extensions; - - - // set the constructor property on the prototype, for convenience - proto.constructor = C; - - C.mixin = function(def) { - Bare[prototype] = C[prototype] = P(C, def)[prototype]; - return C; - } - - return (C.open = function(def) { - extensions = {}; - - if (isFunction(def)) { - // call the defining function with all the arguments you need - // extensions captures the return value. - extensions = def.call(C, proto, _super, C, _superclass); - } - else if (isObject(def)) { - // if you passed an object instead, we'll take it - extensions = def; - } - - // ...and extend it - if (isObject(extensions)) { - for (var ext in extensions) { - if (ownProperty.call(extensions, ext)) { - proto[ext] = extensions[ext]; - } - } - } - - // if there's no init, we assume we're inheriting a non-pjs class, so - // we default to applying the superclass's constructor. - if (!isFunction(proto.init)) { - proto.init = _superclass; - } - - return C; - })(definition); - } - - // as a minifier optimization, we've closured in a few helper functions - // and the string 'prototype' (C[p] is much shorter than C.prototype) - })('prototype', ({}).hasOwnProperty); - /************************************************* - * Base classes of edit tree-related objects - * - * Only doing tree node manipulation via these - * adopt/ disown methods guarantees well-formedness - * of the tree. - ************************************************/ - -// L = 'left' -// R = 'right' -// -// the contract is that they can be used as object properties -// and (-L) === R, and (-R) === L. - var L = MathQuill.L = -1; - var R = MathQuill.R = 1; - - function prayDirection(dir) { - pray('a direction was passed', dir === L || dir === R); - } - - /** - * Tiny extension of jQuery adding directionalized DOM manipulation methods. - * - * Funny how Pjs v3 almost just works with `jQuery.fn.init`. - * - * jQuery features that don't work on $: - * - jQuery.*, like jQuery.ajax, obviously (Pjs doesn't and shouldn't - * copy constructor properties) - * - * - jQuery(function), the shortcut for `jQuery(document).ready(function)`, - * because `jQuery.fn.init` is idiosyncratic and Pjs doing, essentially, - * `jQuery.fn.init.apply(this, arguments)` isn't quite right, you need: - * - * _.init = function(s, c) { jQuery.fn.init.call(this, s, c, $(document)); }; - * - * if you actually give a shit (really, don't bother), - * see https://github.com/jquery/jquery/blob/1.7.2/src/core.js#L889 - * - * - jQuery(selector), because jQuery translates that to - * `jQuery(document).find(selector)`, but Pjs doesn't (should it?) let - * you override the result of a constructor call - * + note that because of the jQuery(document) shortcut-ness, there's also - * the 3rd-argument-needs-to-be-`$(document)` thing above, but the fix - * for that (as can be seen above) is really easy. This problem requires - * a way more intrusive fix - * - * And that's it! Everything else just magically works because jQuery internally - * uses `this.constructor()` everywhere (hence calling `$`), but never ever does - * `this.constructor.find` or anything like that, always doing `jQuery.find`. - */ - var $ = P(jQuery, function(_) { - _.insDirOf = function(dir, el) { - return dir === L ? - this.insertBefore(el.first()) : this.insertAfter(el.last()); - }; - _.insAtDirEnd = function(dir, el) { - return dir === L ? this.prependTo(el) : this.appendTo(el); - }; - }); - - var Point = P(function(_) { - _.parent = 0; - _[L] = 0; - _[R] = 0; - - _.init = function(parent, leftward, rightward) { - this.parent = parent; - this[L] = leftward; - this[R] = rightward; - }; - - this.copy = function(pt) { - return Point(pt.parent, pt[L], pt[R]); - }; - }); - - /** - * MathQuill virtual-DOM tree-node abstract base class - */ - var Node = P(function(_) { - _[L] = 0; - _[R] = 0 - _.parent = 0; - - var id = 0; - function uniqueNodeId() { return id += 1; } - this.byId = {}; - - _.init = function() { - this.id = uniqueNodeId(); - Node.byId[this.id] = this; - - this.ends = {}; - this.ends[L] = 0; - this.ends[R] = 0; - }; - - _.dispose = function() { delete Node.byId[this.id]; }; - - _.toString = function() { return '{{ MathQuill Node #'+this.id+' }}'; }; - - _.jQ = $(); - _.jQadd = function(jQ) { return this.jQ = this.jQ.add(jQ); }; - _.jQize = function(jQ) { - // jQuery-ifies this.html() and links up the .jQ of all corresponding Nodes - var jQ = $(jQ || this.html()); - - function jQadd(el) { - if (el.getAttribute) { - var cmdId = el.getAttribute('mathquill-command-id'); - var blockId = el.getAttribute('mathquill-block-id'); - if (cmdId) Node.byId[cmdId].jQadd(el); - if (blockId) Node.byId[blockId].jQadd(el); - } - for (el = el.firstChild; el; el = el.nextSibling) { - jQadd(el); - } - } - - for (var i = 0; i < jQ.length; i += 1) jQadd(jQ[i]); - return jQ; - }; - - _.createDir = function(dir, cursor) { - prayDirection(dir); - var node = this; - node.jQize(); - node.jQ.insDirOf(dir, cursor.jQ); - cursor[dir] = node.adopt(cursor.parent, cursor[L], cursor[R]); - return node; - }; - _.createLeftOf = function(el) { return this.createDir(L, el); }; - - _.selectChildren = function(leftEnd, rightEnd) { - return Selection(leftEnd, rightEnd); - }; - - _.bubble = iterator(function(yield_) { - for (var ancestor = this; ancestor; ancestor = ancestor.parent) { - var result = yield_(ancestor); - if (result === false) break; - } - - return this; - }); - - _.postOrder = iterator(function(yield_) { - (function recurse(descendant) { - descendant.eachChild(recurse); - yield_(descendant); - })(this); - - return this; - }); - - _.isEmpty = function() { - return this.ends[L] === 0 && this.ends[R] === 0; - }; - - _.children = function() { - return Fragment(this.ends[L], this.ends[R]); - }; - - _.eachChild = function() { - var children = this.children(); - children.each.apply(children, arguments); - return this; - }; - - _.foldChildren = function(fold, fn) { - return this.children().fold(fold, fn); - }; - - _.withDirAdopt = function(dir, parent, withDir, oppDir) { - Fragment(this, this).withDirAdopt(dir, parent, withDir, oppDir); - return this; - }; - - _.adopt = function(parent, leftward, rightward) { - Fragment(this, this).adopt(parent, leftward, rightward); - return this; - }; - - _.disown = function() { - Fragment(this, this).disown(); - return this; - }; - - _.remove = function() { - this.jQ.remove(); - this.postOrder('dispose'); - return this.disown(); - }; - }); - - function prayWellFormed(parent, leftward, rightward) { - pray('a parent is always present', parent); - pray('leftward is properly set up', (function() { - // either it's empty and `rightward` is the left end child (possibly empty) - if (!leftward) return parent.ends[L] === rightward; - - // or it's there and its [R] and .parent are properly set up - return leftward[R] === rightward && leftward.parent === parent; - })()); - - pray('rightward is properly set up', (function() { - // either it's empty and `leftward` is the right end child (possibly empty) - if (!rightward) return parent.ends[R] === leftward; - - // or it's there and its [L] and .parent are properly set up - return rightward[L] === leftward && rightward.parent === parent; - })()); - } - - - /** - * An entity outside the virtual tree with one-way pointers (so it's only a - * "view" of part of the tree, not an actual node/entity in the tree) that - * delimits a doubly-linked list of sibling nodes. - * It's like a fanfic love-child between HTML DOM DocumentFragment and the Range - * classes: like DocumentFragment, its contents must be sibling nodes - * (unlike Range, whose contents are arbitrary contiguous pieces of subtrees), - * but like Range, it has only one-way pointers to its contents, its contents - * have no reference to it and in fact may still be in the visible tree (unlike - * DocumentFragment, whose contents must be detached from the visible tree - * and have their 'parent' pointers set to the DocumentFragment). - */ - var Fragment = P(function(_) { - _.init = function(withDir, oppDir, dir) { - if (dir === undefined) dir = L; - prayDirection(dir); - - pray('no half-empty fragments', !withDir === !oppDir); - - this.ends = {}; - - if (!withDir) return; - - pray('withDir is passed to Fragment', withDir instanceof Node); - pray('oppDir is passed to Fragment', oppDir instanceof Node); - pray('withDir and oppDir have the same parent', - withDir.parent === oppDir.parent); - - this.ends[dir] = withDir; - this.ends[-dir] = oppDir; - - this.jQ = this.fold(this.jQ, function(jQ, el) { return jQ.add(el.jQ); }); - }; - _.jQ = $(); - - // like Cursor::withDirInsertAt(dir, parent, withDir, oppDir) - _.withDirAdopt = function(dir, parent, withDir, oppDir) { - return (dir === L ? this.adopt(parent, withDir, oppDir) - : this.adopt(parent, oppDir, withDir)); - }; - _.adopt = function(parent, leftward, rightward) { - prayWellFormed(parent, leftward, rightward); - - var self = this; - self.disowned = false; - - var leftEnd = self.ends[L]; - if (!leftEnd) return this; - - var rightEnd = self.ends[R]; - - if (leftward) { - // NB: this is handled in the ::each() block - // leftward[R] = leftEnd - } else { - parent.ends[L] = leftEnd; - } - - if (rightward) { - rightward[L] = rightEnd; - } else { - parent.ends[R] = rightEnd; - } - - self.ends[R][R] = rightward; - - self.each(function(el) { - el[L] = leftward; - el.parent = parent; - if (leftward) leftward[R] = el; - - leftward = el; - }); - - return self; - }; - - _.disown = function() { - var self = this; - var leftEnd = self.ends[L]; - - // guard for empty and already-disowned fragments - if (!leftEnd || self.disowned) return self; - - self.disowned = true; - - var rightEnd = self.ends[R] - var parent = leftEnd.parent; - - prayWellFormed(parent, leftEnd[L], leftEnd); - prayWellFormed(parent, rightEnd, rightEnd[R]); - - if (leftEnd[L]) { - leftEnd[L][R] = rightEnd[R]; - } else { - parent.ends[L] = rightEnd[R]; - } - - if (rightEnd[R]) { - rightEnd[R][L] = leftEnd[L]; - } else { - parent.ends[R] = leftEnd[L]; - } - - return self; - }; - - _.remove = function() { - this.jQ.remove(); - this.each('postOrder', 'dispose'); - return this.disown(); - }; - - _.each = iterator(function(yield_) { - var self = this; - var el = self.ends[L]; - if (!el) return self; - - for (; el !== self.ends[R][R]; el = el[R]) { - var result = yield_(el); - if (result === false) break; - } - - return self; - }); - - _.fold = function(fold, fn) { - this.each(function(el) { - fold = fn.call(this, fold, el); - }); - - return fold; - }; - }); - - - /** - * Registry of LaTeX commands and commands created when typing - * a single character. - * - * (Commands are all subclasses of Node.) - */ - var LatexCmds = {}, CharCmds = {}; - /******************************************** - * Cursor and Selection "singleton" classes - *******************************************/ - - /* The main thing that manipulates the Math DOM. Makes sure to manipulate the - HTML DOM to match. */ - - /* Sort of singletons, since there should only be one per editable math - textbox, but any one HTML document can contain many such textboxes, so any one - JS environment could actually contain many instances. */ - -//A fake cursor in the fake textbox that the math is rendered in. - var Cursor = P(Point, function(_) { - _.init = function(initParent, options) { - this.parent = initParent; - this.options = options; - - var jQ = this.jQ = this._jQ = $('<span class="mq-cursor">&zwj;</span>'); - //closured for setInterval - this.blink = function(){ jQ.toggleClass('mq-blink'); }; - - this.upDownCache = {}; - }; - - _.show = function() { - this.jQ = this._jQ.removeClass('mq-blink'); - if ('intervalId' in this) //already was shown, just restart interval - clearInterval(this.intervalId); - else { //was hidden and detached, insert this.jQ back into HTML DOM - if (this[R]) { - if (this.selection && this.selection.ends[L][L] === this[L]) - this.jQ.insertBefore(this.selection.jQ); - else - this.jQ.insertBefore(this[R].jQ.first()); - } - else - this.jQ.appendTo(this.parent.jQ); - this.parent.focus(); - } - this.intervalId = setInterval(this.blink, 500); - return this; - }; - _.hide = function() { - if ('intervalId' in this) - clearInterval(this.intervalId); - delete this.intervalId; - this.jQ.detach(); - this.jQ = $(); - return this; - }; - - _.withDirInsertAt = function(dir, parent, withDir, oppDir) { - if (parent !== this.parent && this.parent.blur) this.parent.blur(); - this.parent = parent; - this[dir] = withDir; - this[-dir] = oppDir; - }; - _.insDirOf = function(dir, el) { - prayDirection(dir); - this.withDirInsertAt(dir, el.parent, el[dir], el); - this.parent.jQ.addClass('mq-hasCursor'); - this.jQ.insDirOf(dir, el.jQ); - return this; - }; - _.insLeftOf = function(el) { return this.insDirOf(L, el); }; - _.insRightOf = function(el) { return this.insDirOf(R, el); }; - - _.insAtDirEnd = function(dir, el) { - prayDirection(dir); - this.withDirInsertAt(dir, el, 0, el.ends[dir]); - this.jQ.insAtDirEnd(dir, el.jQ); - el.focus(); - return this; - }; - _.insAtLeftEnd = function(el) { return this.insAtDirEnd(L, el); }; - _.insAtRightEnd = function(el) { return this.insAtDirEnd(R, el); }; - - /** - * jump up or down from one block Node to another: - * - cache the current Point in the node we're jumping from - * - check if there's a Point in it cached for the node we're jumping to - * + if so put the cursor there, - * + if not seek a position in the node that is horizontally closest to - * the cursor's current position - */ - _.jumpUpDown = function(from, to) { - var self = this; - self.upDownCache[from.id] = Point.copy(self); - var cached = self.upDownCache[to.id]; - if (cached) { - cached[R] ? self.insLeftOf(cached[R]) : self.insAtRightEnd(cached.parent); - } - else { - var pageX = self.offset().left; - to.seek(pageX, self); - } - }; - _.offset = function() { - //in Opera 11.62, .getBoundingClientRect() and hence jQuery::offset() - //returns all 0's on inline elements with negative margin-right (like - //the cursor) at the end of their parent, so temporarily remove the - //negative margin-right when calling jQuery::offset() - //Opera bug DSK-360043 - //http://bugs.jquery.com/ticket/11523 - //https://github.com/jquery/jquery/pull/717 - var self = this, offset = self.jQ.removeClass('mq-cursor').offset(); - self.jQ.addClass('mq-cursor'); - return offset; - } - _.unwrapGramp = function() { - var gramp = this.parent.parent; - var greatgramp = gramp.parent; - var rightward = gramp[R]; - var cursor = this; - - var leftward = gramp[L]; - gramp.disown().eachChild(function(uncle) { - if (uncle.isEmpty()) return; - - uncle.children() - .adopt(greatgramp, leftward, rightward) - .each(function(cousin) { - cousin.jQ.insertBefore(gramp.jQ.first()); - }) - ; - - leftward = uncle.ends[R]; - }); - - if (!this[R]) { //then find something to be rightward to insLeftOf - if (this[L]) - this[R] = this[L][R]; - else { - while (!this[R]) { - this.parent = this.parent[R]; - if (this.parent) - this[R] = this.parent.ends[L]; - else { - this[R] = gramp[R]; - this.parent = greatgramp; - break; - } - } - } - } - if (this[R]) - this.insLeftOf(this[R]); - else - this.insAtRightEnd(greatgramp); - - gramp.jQ.remove(); - - if (gramp[L].siblingDeleted) gramp[L].siblingDeleted(cursor.options, R); - if (gramp[R].siblingDeleted) gramp[R].siblingDeleted(cursor.options, L); - }; - _.startSelection = function() { - var anticursor = this.anticursor = Point.copy(this); - var ancestors = anticursor.ancestors = {}; // a map from each ancestor of - // the anticursor, to its child that is also an ancestor; in other words, - // the anticursor's ancestor chain in reverse order - for (var ancestor = anticursor; ancestor.parent; ancestor = ancestor.parent) { - ancestors[ancestor.parent.id] = ancestor; - } - }; - _.endSelection = function() { - delete this.anticursor; - }; - _.select = function() { - var anticursor = this.anticursor; - if (this[L] === anticursor[L] && this.parent === anticursor.parent) return false; - - // Find the lowest common ancestor (`lca`), and the ancestor of the cursor - // whose parent is the LCA (which'll be an end of the selection fragment). - for (var ancestor = this; ancestor.parent; ancestor = ancestor.parent) { - if (ancestor.parent.id in anticursor.ancestors) { - var lca = ancestor.parent; - break; - } - } - pray('cursor and anticursor in the same tree', lca); - // The cursor and the anticursor should be in the same tree, because the - // mousemove handler attached to the document, unlike the one attached to - // the root HTML DOM element, doesn't try to get the math tree node of the - // mousemove target, and Cursor::seek() based solely on coordinates stays - // within the tree of `this` cursor's root. - - // The other end of the selection fragment, the ancestor of the anticursor - // whose parent is the LCA. - var antiAncestor = anticursor.ancestors[lca.id]; - - // Now we have two either Nodes or Points, guaranteed to have a common - // parent and guaranteed that if both are Points, they are not the same, - // and we have to figure out which is the left end and which the right end - // of the selection. - var leftEnd, rightEnd, dir = R; - - // This is an extremely subtle algorithm. - // As a special case, `ancestor` could be a Point and `antiAncestor` a Node - // immediately to `ancestor`'s left. - // In all other cases, - // - both Nodes - // - `ancestor` a Point and `antiAncestor` a Node - // - `ancestor` a Node and `antiAncestor` a Point - // `antiAncestor[R] === rightward[R]` for some `rightward` that is - // `ancestor` or to its right, if and only if `antiAncestor` is to - // the right of `ancestor`. - if (ancestor[L] !== antiAncestor) { - for (var rightward = ancestor; rightward; rightward = rightward[R]) { - if (rightward[R] === antiAncestor[R]) { - dir = L; - leftEnd = ancestor; - rightEnd = antiAncestor; - break; - } - } - } - if (dir === R) { - leftEnd = antiAncestor; - rightEnd = ancestor; - } - - // only want to select Nodes up to Points, can't select Points themselves - if (leftEnd instanceof Point) leftEnd = leftEnd[R]; - if (rightEnd instanceof Point) rightEnd = rightEnd[L]; - - this.hide().selection = lca.selectChildren(leftEnd, rightEnd); - this.insDirOf(dir, this.selection.ends[dir]); - this.selectionChanged(); - return true; - }; - - _.clearSelection = function() { - if (this.selection) { - this.selection.clear(); - delete this.selection; - this.selectionChanged(); - } - return this; - }; - _.deleteSelection = function() { - if (!this.selection) return; - - this[L] = this.selection.ends[L][L]; - this[R] = this.selection.ends[R][R]; - this.selection.remove(); - this.selectionChanged(); - delete this.selection; - }; - _.replaceSelection = function() { - var seln = this.selection; - if (seln) { - this[L] = seln.ends[L][L]; - this[R] = seln.ends[R][R]; - delete this.selection; - } - return seln; - }; - }); - - var Selection = P(Fragment, function(_, super_) { - _.init = function() { - super_.init.apply(this, arguments); - this.jQ = this.jQ.wrapAll('<span class="mq-selection"></span>').parent(); - //can't do wrapAll(this.jQ = $(...)) because wrapAll will clone it - }; - _.adopt = function() { - this.jQ.replaceWith(this.jQ = this.jQ.children()); - return super_.adopt.apply(this, arguments); - }; - _.clear = function() { - // using the browser's native .childNodes property so that we - // don't discard text nodes. - this.jQ.replaceWith(this.jQ[0].childNodes); - return this; - }; - _.join = function(methodName) { - return this.fold('', function(fold, child) { - return fold + child[methodName](); - }); - }; - }); - /********************************************* - * Controller for a MathQuill instance, - * on which services are registered with - * - * Controller.open(function(_) { ... }); - * - ********************************************/ - - var Controller = P(function(_) { - _.init = function(API, root, container) { - this.API = API; - this.root = root; - this.container = container; - - API.__controller = root.controller = this; - - this.cursor = root.cursor = Cursor(root, API.__options); - // TODO: stop depending on root.cursor, and rm it - }; - - _.handle = function(name, dir) { - var handlers = this.API.__options.handlers; - if (handlers && handlers[name]) { - if (dir === L || dir === R) handlers[name](dir, this.API); - else handlers[name](this.API); - } - }; - - var notifyees = []; - this.onNotify = function(f) { notifyees.push(f); }; - _.notify = function() { - for (var i = 0; i < notifyees.length; i += 1) { - notifyees[i].apply(this.cursor, arguments); - } - return this; - }; - }); - /********************************************************* - * The publicly exposed MathQuill API. - ********************************************************/ - - /** - * Global function that takes an HTML element and, if it's the root HTML element - * of a static math or math or text field, returns its API object (if not, null). - * Identity of API object guaranteed if called multiple times, i.e.: - * - * var mathfield = MathQuill.MathField(mathFieldSpan); - * assert(MathQuill(mathFieldSpan) === mathfield); - * assert(MathQuill(mathFieldSpan) === MathQuill(mathFieldSpan)); - * - */ - function MathQuill(el) { - if (!el || !el.nodeType) return null; // check that `el` is a HTML element, using the - // same technique as jQuery: https://github.com/jquery/jquery/blob/679536ee4b7a92ae64a5f58d90e9cc38c001e807/src/core/init.js#L92 - var blockId = $(el).children('.mq-root-block').attr(mqBlockId); - return blockId ? Node.byId[blockId].controller.API : null; - }; - - MathQuill.noConflict = function() { - window.MathQuill = origMathQuill; - return MathQuill; - }; - var origMathQuill = window.MathQuill; - window.MathQuill = MathQuill; - - /** - * Returns function (to be publicly exported) that MathQuill-ifies an HTML - * element and returns an API object. If the element had already been MathQuill- - * ified into the same kind, return the original API object (if different kind - * or not an HTML element, null). - */ - function APIFnFor(APIClass) { - function APIFn(el, opts) { - var mq = MathQuill(el); - if (mq instanceof APIClass || !el || !el.nodeType) return mq; - return APIClass($(el), opts); - } - APIFn.prototype = APIClass.prototype; - return APIFn; - } - - var Options = P(), optionProcessors = {}; - MathQuill.__options = Options.p; - - var AbstractMathQuill = P(function(_) { - _.init = function() { throw "wtf don't call me, I'm 'abstract'"; }; - _.initRoot = function(root, el, opts) { - this.__options = Options(); - this.config(opts); - - var ctrlr = Controller(this, root, el); - ctrlr.createTextarea(); - - var contents = el.contents().detach(); - root.jQ = - $('<span class="mq-root-block"/>').attr(mqBlockId, root.id).appendTo(el); - this.latex(contents.text()); - - this.revert = function() { - return el.empty().unbind('.mathquill') - .removeClass('mq-editable-field mq-math-mode mq-text-mode') - .append(contents); - }; - }; - _.config = - MathQuill.config = function(opts) { - for (var opt in opts) if (opts.hasOwnProperty(opt)) { - var optVal = opts[opt], processor = optionProcessors[opt]; - this.__options[opt] = (processor ? processor(optVal) : optVal); - } - return this; - }; - _.el = function() { return this.__controller.container[0]; }; - _.text = function() { return this.__controller.exportText(this.__options); }; - _.latex = function(latex) { - if (arguments.length > 0) { - this.__controller.renderLatexMath(latex); - if (this.__controller.blurred) this.__controller.cursor.hide().parent.blur(); - return this; - } - return this.__controller.exportLatex(); - }; - _.html = function() { - return this.__controller.root.jQ.html() - .replace(/ mathquill-(?:command|block)-id="?\d+"?/g, '') - .replace(/<span class="?mq-cursor( mq-blink)?"?>.?<\/span>/i, '') - .replace(/ mq-hasCursor|mq-hasCursor ?/, '') - .replace(/ class=(""|(?= |>))/g, ''); - }; - _.reflow = function() { - this.__controller.root.postOrder('reflow'); - return this; - }; - }); - MathQuill.prototype = AbstractMathQuill.prototype; - - MathQuill.StaticMath = APIFnFor(P(AbstractMathQuill, function(_, super_) { - _.init = function(el) { - this.initRoot(MathBlock(), el.addClass('mq-math-mode')); - this.__controller.delegateMouseEvents(); - this.__controller.staticMathTextareaEvents(); - }; - _.latex = function() { - var returned = super_.latex.apply(this, arguments); - if (arguments.length > 0) { - this.__controller.root.postOrder('registerInnerField', this.innerFields = []); - } - return returned; - }; - })); - - var EditableField = MathQuill.EditableField = P(AbstractMathQuill, function(_) { - _.initRootAndEvents = function(root, el, opts) { - this.initRoot(root, el, opts); - this.__controller.editable = true; - this.__controller.delegateMouseEvents(); - this.__controller.editablesTextareaEvents(); - }; - _.focus = function() { this.__controller.textarea.focus(); return this; }; - _.blur = function() { this.__controller.textarea.blur(); return this; }; - _.write = function(latex) { - this.__controller.writeLatex(latex); - if (this.__controller.blurred) this.__controller.cursor.hide().parent.blur(); - return this; - }; - _.cmd = function(cmd) { - var ctrlr = this.__controller.notify(), cursor = ctrlr.cursor.show(); - if (/^\\[a-z]+$/i.test(cmd)) { - cmd = cmd.slice(1); - var klass = LatexCmds[cmd]; - if (klass) { - cmd = klass(cmd); - if (cursor.selection) cmd.replaces(cursor.replaceSelection()); - cmd.createLeftOf(cursor); - } - else /* TODO: API needs better error reporting */; - } - else cursor.parent.write(cursor, cmd, cursor.replaceSelection()); - if (ctrlr.blurred) cursor.hide().parent.blur(); - return this; - }; - _.select = function() { - var ctrlr = this.__controller; - ctrlr.notify('move').cursor.insAtRightEnd(ctrlr.root); - while (ctrlr.cursor[L]) ctrlr.selectLeft(); - return this; - }; - _.clearSelection = function() { - this.__controller.cursor.clearSelection(); - return this; - }; - - _.moveToDirEnd = function(dir) { - this.__controller.notify('move').cursor.insAtDirEnd(dir, this.__controller.root); - return this; - }; - _.moveToLeftEnd = function() { return this.moveToDirEnd(L); }; - _.moveToRightEnd = function() { return this.moveToDirEnd(R); }; - - _.keystroke = function(keys) { - var keys = keys.replace(/^\s+|\s+$/g, '').split(/\s+/); - for (var i = 0; i < keys.length; i += 1) { - this.__controller.keystroke(keys[i], { preventDefault: noop }); - } - return this; - }; - _.typedText = function(text) { - for (var i = 0; i < text.length; i += 1) this.__controller.typedText(text.charAt(i)); - return this; - }; - }); - - function RootBlockMixin(_) { - var names = 'workingGroupChange moveOutOf deleteOutOf selectOutOf upOutOf downOutOf reflow'.split(' '); - for (var i = 0; i < names.length; i += 1) (function(name) { - _[name] = function(dir) { this.controller.handle(name, dir); }; - }(names[i])); - } - var Parser = P(function(_, super_, Parser) { - // The Parser object is a wrapper for a parser function. - // Externally, you use one to parse a string by calling - // var result = SomeParser.parse('Me Me Me! Parse Me!'); - // You should never call the constructor, rather you should - // construct your Parser from the base parsers and the - // parser combinator methods. - - function parseError(stream, message) { - if (stream) { - stream = "'"+stream+"'"; - } - else { - stream = 'EOF'; - } - - throw 'Parse Error: '+message+' at '+stream; - } - - _.init = function(body) { this._ = body; }; - - _.parse = function(stream) { - return this.skip(eof)._(stream, success, parseError); - - function success(stream, result) { return result; } - }; - - // -*- primitive combinators -*- // - _.or = function(alternative) { - pray('or is passed a parser', alternative instanceof Parser); - - var self = this; - - return Parser(function(stream, onSuccess, onFailure) { - return self._(stream, onSuccess, failure); - - function failure(newStream) { - return alternative._(stream, onSuccess, onFailure); - } - }); - }; - - _.then = function(next) { - var self = this; - - return Parser(function(stream, onSuccess, onFailure) { - return self._(stream, success, onFailure); - - function success(newStream, result) { - var nextParser = (next instanceof Parser ? next : next(result)); - pray('a parser is returned', nextParser instanceof Parser); - return nextParser._(newStream, onSuccess, onFailure); - } - }); - }; - - // -*- optimized iterative combinators -*- // - _.many = function() { - var self = this; - - return Parser(function(stream, onSuccess, onFailure) { - var xs = []; - while (self._(stream, success, failure)); - return onSuccess(stream, xs); - - function success(newStream, x) { - stream = newStream; - xs.push(x); - return true; - } - - function failure() { - return false; - } - }); - }; - - _.times = function(min, max) { - if (arguments.length < 2) max = min; - var self = this; - - return Parser(function(stream, onSuccess, onFailure) { - var xs = []; - var result = true; - var failure; - - for (var i = 0; i < min; i += 1) { - result = self._(stream, success, firstFailure); - if (!result) return onFailure(stream, failure); - } - - for (; i < max && result; i += 1) { - result = self._(stream, success, secondFailure); - } - - return onSuccess(stream, xs); - - function success(newStream, x) { - xs.push(x); - stream = newStream; - return true; - } - - function firstFailure(newStream, msg) { - failure = msg; - stream = newStream; - return false; - } - - function secondFailure(newStream, msg) { - return false; - } - }); - }; - - // -*- higher-level combinators -*- // - _.result = function(res) { return this.then(succeed(res)); }; - _.atMost = function(n) { return this.times(0, n); }; - _.atLeast = function(n) { - var self = this; - return self.times(n).then(function(start) { - return self.many().map(function(end) { - return start.concat(end); - }); - }); - }; - - _.map = function(fn) { - return this.then(function(result) { return succeed(fn(result)); }); - }; - - _.skip = function(two) { - return this.then(function(result) { return two.result(result); }); - }; - - // -*- primitive parsers -*- // - var string = this.string = function(str) { - var len = str.length; - var expected = "expected '"+str+"'"; - - return Parser(function(stream, onSuccess, onFailure) { - var head = stream.slice(0, len); - - if (head === str) { - return onSuccess(stream.slice(len), head); - } - else { - return onFailure(stream, expected); - } - }); - }; - - var regex = this.regex = function(re) { - pray('regexp parser is anchored', re.toString().charAt(1) === '^'); - - var expected = 'expected '+re; - - return Parser(function(stream, onSuccess, onFailure) { - var match = re.exec(stream); - - if (match) { - var result = match[0]; - return onSuccess(stream.slice(result.length), result); - } - else { - return onFailure(stream, expected); - } - }); - }; - - var succeed = Parser.succeed = function(result) { - return Parser(function(stream, onSuccess) { - return onSuccess(stream, result); - }); - }; - - var fail = Parser.fail = function(msg) { - return Parser(function(stream, _, onFailure) { - return onFailure(stream, msg); - }); - }; - - var letter = Parser.letter = regex(/^[a-z]/i); - var letters = Parser.letters = regex(/^[a-z]*/i); - var digit = Parser.digit = regex(/^[0-9]/); - var digits = Parser.digits = regex(/^[0-9]*/); - var whitespace = Parser.whitespace = regex(/^\s+/); - var optWhitespace = Parser.optWhitespace = regex(/^\s*/); - - var any = Parser.any = Parser(function(stream, onSuccess, onFailure) { - if (!stream) return onFailure(stream, 'expected any character'); - - return onSuccess(stream.slice(1), stream.charAt(0)); - }); - - var all = Parser.all = Parser(function(stream, onSuccess, onFailure) { - return onSuccess('', stream); - }); - - var eof = Parser.eof = Parser(function(stream, onSuccess, onFailure) { - if (stream) return onFailure(stream, 'expected EOF'); - - return onSuccess(stream, stream); - }); - }); - /************************************************* - * Sane Keyboard Events Shim - * - * An abstraction layer wrapping the textarea in - * an object with methods to manipulate and listen - * to events on, that hides all the nasty cross- - * browser incompatibilities behind a uniform API. - * - * Design goal: This is a *HARD* internal - * abstraction barrier. Cross-browser - * inconsistencies are not allowed to leak through - * and be dealt with by event handlers. All future - * cross-browser issues that arise must be dealt - * with here, and if necessary, the API updated. - * - * Organization: - * - key values map and stringify() - * - saneKeyboardEvents() - * + defer() and flush() - * + event handler logic - * + attach event handlers and export methods - ************************************************/ - - var saneKeyboardEvents = (function() { - // The following [key values][1] map was compiled from the - // [DOM3 Events appendix section on key codes][2] and - // [a widely cited report on cross-browser tests of key codes][3], - // except for 10: 'Enter', which I've empirically observed in Safari on iOS - // and doesn't appear to conflict with any other known key codes. - // - // [1]: http://www.w3.org/TR/2012/WD-DOM-Level-3-Events-20120614/#keys-keyvalues - // [2]: http://www.w3.org/TR/2012/WD-DOM-Level-3-Events-20120614/#fixed-virtual-key-codes - // [3]: http://unixpapa.com/js/key.html - var KEY_VALUES = { - 8: 'Backspace', - 9: 'Tab', - - 10: 'Enter', // for Safari on iOS - - 13: 'Enter', - - 16: 'Shift', - 17: 'Control', - 18: 'Alt', - 20: 'CapsLock', - - 27: 'Esc', - - 32: 'Spacebar', - - 33: 'PageUp', - 34: 'PageDown', - 35: 'End', - 36: 'Home', - - 37: 'Left', - 38: 'Up', - 39: 'Right', - 40: 'Down', - - 45: 'Insert', - - 46: 'Del', - - 144: 'NumLock' - }; - - // To the extent possible, create a normalized string representation - // of the key combo (i.e., key code and modifier keys). - function stringify(evt) { - var which = evt.which || evt.keyCode; - var keyVal = KEY_VALUES[which]; - var key; - var modifiers = []; - - if (evt.ctrlKey) modifiers.push('Ctrl'); - if (evt.originalEvent && evt.originalEvent.metaKey) modifiers.push('Meta'); - if (evt.altKey) modifiers.push('Alt'); - if (evt.shiftKey) modifiers.push('Shift'); - - key = keyVal || String.fromCharCode(which); - - if (!modifiers.length && !keyVal) return key; - - modifiers.push(key); - return modifiers.join('-'); - } - - // create a keyboard events shim that calls callbacks at useful times - // and exports useful public methods - return function saneKeyboardEvents(el, handlers) { - var keydown = null; - var keypress = null; - - var textarea = jQuery(el); - var target = jQuery(handlers.container || textarea); - - // checkTextareaFor() is called after keypress or paste events to - // say "Hey, I think something was just typed" or "pasted" (resp.), - // so that at all subsequent opportune times (next event or timeout), - // will check for expected typed or pasted text. - // Need to check repeatedly because #135: in Safari 5.1 (at least), - // after selecting something and then typing, the textarea is - // incorrectly reported as selected during the input event (but not - // subsequently). - var checkTextarea = noop, timeoutId; - function checkTextareaFor(checker) { - checkTextarea = checker; - clearTimeout(timeoutId); - timeoutId = setTimeout(checker); - } - target.bind('keydown keypress input keyup focusout paste', function() { checkTextarea(); }); - - - // -*- public methods -*- // - function select(text) { - // check textarea at least once/one last time before munging (so - // no race condition if selection happens after keypress/paste but - // before checkTextarea), then never again ('cos it's been munged) - checkTextarea(); - checkTextarea = noop; - clearTimeout(timeoutId); - - textarea.val(text); - if (text) textarea[0].select(); - shouldBeSelected = !!text; - } - var shouldBeSelected = false; - - // -*- helper subroutines -*- // - - // Determine whether there's a selection in the textarea. - // This will always return false in IE < 9, which don't support - // HTMLTextareaElement::selection{Start,End}. - function hasSelection() { - var dom = textarea[0]; - - if (!('selectionStart' in dom)) return false; - return dom.selectionStart !== dom.selectionEnd; - } - - function handleKey() { - handlers.keystroke(stringify(keydown), keydown); - } - - // -*- event handlers -*- // - function onKeydown(e) { - keydown = e; - keypress = null; - - handleKey(); - if (shouldBeSelected) checkTextareaFor(function() { - textarea[0].select(); // re-select textarea in case it's an unrecognized - checkTextarea = noop; // key that clears the selection, then never - clearTimeout(timeoutId); // again, 'cos next thing might be blur - }); - } - - function onKeypress(e) { - // call the key handler for repeated keypresses. - // This excludes keypresses that happen directly - // after keydown. In that case, there will be - // no previous keypress, so we skip it here - if (keydown && keypress) handleKey(); - - keypress = e; - - checkTextareaFor(typedText); - } - function typedText() { - // If there is a selection, the contents of the textarea couldn't - // possibly have just been typed in. - // This happens in browsers like Firefox and Opera that fire - // keypress for keystrokes that are not text entry and leave the - // selection in the textarea alone, such as Ctrl-C. - // Note: we assume that browsers that don't support hasSelection() - // also never fire keypress on keystrokes that are not text entry. - // This seems reasonably safe because: - // - all modern browsers including IE 9+ support hasSelection(), - // making it extremely unlikely any browser besides IE < 9 won't - // - as far as we know IE < 9 never fires keypress on keystrokes - // that aren't text entry, which is only as reliable as our - // tests are comprehensive, but the IE < 9 way to do - // hasSelection() is poorly documented and is also only as - // reliable as our tests are comprehensive - // If anything like #40 or #71 is reported in IE < 9, see - // b1318e5349160b665003e36d4eedd64101ceacd8 - if (hasSelection()) return; - - var text = textarea.val(); - if (text.length === 1) { - textarea.val(''); - handlers.typedText(text); - } // in Firefox, keys that don't type text, just clear seln, fire keypress - // https://github.com/mathquill/mathquill/issues/293#issuecomment-40997668 - else if (text) textarea[0].select(); // re-select if that's why we're here - } - - function onBlur() { keydown = keypress = null; } - - function onPaste(e) { - // browsers are dumb. - // - // In Linux, middle-click pasting causes onPaste to be called, - // when the textarea is not necessarily focused. We focus it - // here to ensure that the pasted text actually ends up in the - // textarea. - // - // It's pretty nifty that by changing focus in this handler, - // we can change the target of the default action. (This works - // on keydown too, FWIW). - // - // And by nifty, we mean dumb (but useful sometimes). - textarea.focus(); - - checkTextareaFor(pastedText); - } - function pastedText() { - var text = textarea.val(); - textarea.val(''); - if (text) handlers.paste(text); - } - - // -*- attach event handlers -*- // - target.bind({ - keydown: onKeydown, - keypress: onKeypress, - focusout: onBlur, - paste: onPaste - }); - - // -*- export public methods -*- // - return { - select: select - }; - }; - }()); - /*********************************************** - * Export math in a human-readable text format - * As you can see, only half-baked so far. - **********************************************/ - - Controller.open(function(_, super_) { - _.exportText = function(opts) { - return this.root.foldChildren('', function(text, child) { - return text + child.text(opts); - }) - .replace(/\\operatorname\{(.*?)\}/g,"$1") - .replace(/\\/g, "") - .replace(/\* *\*/g,'*') - .replace(/ *_/g,'_') - .replace(/\* *$/,''); //Random cases of hanging multiplications...just remove these. - //TODO: '**' shouldnt happen, so it should really be dealt with by fixing whatever is causing them - }; - }); - Controller.open(function(_) { - _.focusBlurEvents = function() { - var ctrlr = this, root = ctrlr.root, cursor = ctrlr.cursor; - var blurTimeout; - ctrlr.textarea.focus(function() { - ctrlr.blurred = false; - clearTimeout(blurTimeout); - ctrlr.container.addClass('mq-focused'); - if (!cursor.parent) - cursor.insAtRightEnd(root); - if (cursor.selection) { - cursor.selection.jQ.removeClass('mq-blur'); - ctrlr.selectionChanged(); //re-select textarea contents after tabbing away and back - } - else - cursor.show(); - }).blur(function() { - ctrlr.blurred = true; - blurTimeout = setTimeout(function() { // wait for blur on window; if - root.postOrder('intentionalBlur'); // none, intentional blur: #264 - cursor.clearSelection(); - blur(); - }); - $(window).on('blur', windowBlur); - }); - function windowBlur() { // blur event also fired on window, just switching - clearTimeout(blurTimeout); // tabs/windows, not intentional blur - if (cursor.selection) cursor.selection.jQ.addClass('mq-blur'); - blur(); - } - function blur() { // not directly in the textarea blur handler so as to be - cursor.hide().parent.blur(); // synchronous with/in the same frame as - ctrlr.container.removeClass('mq-focused'); // clearing/blurring selection - $(window).off('blur', windowBlur); - } - ctrlr.blurred = true; - cursor.hide().parent.blur(); - }; - }); - - /** - * TODO: I wanted to move MathBlock::focus and blur here, it would clean - * up lots of stuff like, TextBlock::focus is set to MathBlock::focus - * and TextBlock::blur calls MathBlock::blur, when instead they could - * use inheritance and super_. - * - * Problem is, there's lots of calls to .focus()/.blur() on nodes - * outside Controller::focusBlurEvents(), such as .postOrder('blur') on - * insertion, which if MathBlock::blur becomes Node::blur, would add the - * 'blur' CSS class to all Symbol's (because .isEmpty() is true for all - * of them). - * - * I'm not even sure there aren't other troublesome calls to .focus() or - * .blur(), so this is TODO for now. - */ - /***************************************** - * Deals with the browser DOM events from - * interaction with the typist. - ****************************************/ - - Controller.open(function(_) { - _.keystroke = function(key, evt) { - this.cursor.parent.keystroke(key, evt, this); - }; - }); - - Node.open(function(_) { - _.keystroke = function(key, e, ctrlr) { - var cursor = ctrlr.cursor; - - switch (key) { - case 'Ctrl-Shift-Backspace': - case 'Ctrl-Backspace': - while (cursor[L] || cursor.selection) { - ctrlr.backspace(); - } - break; - - case 'Shift-Backspace': - case 'Backspace': - ctrlr.backspace(); - break; - - // Tab or Esc -> go one block right if it exists, else escape right. - case 'Esc': - case 'Tab': - ctrlr.escapeDir(R, key, e); - return; - - // Shift-Tab -> go one block left if it exists, else escape left. - case 'Shift-Tab': - case 'Shift-Esc': - ctrlr.escapeDir(L, key, e); - return; - - // End -> move to the end of the current block. - case 'End': - ctrlr.notify('move').cursor.insAtRightEnd(cursor.parent); - break; - - // Ctrl-End -> move all the way to the end of the root block. - case 'Ctrl-End': - ctrlr.notify('move').cursor.insAtRightEnd(ctrlr.root); - break; - - // Shift-End -> select to the end of the current block. - case 'Shift-End': - while (cursor[R]) { - ctrlr.selectRight(); - } - break; - - // Ctrl-Shift-End -> select to the end of the root block. - case 'Ctrl-Shift-End': - while (cursor[R] || cursor.parent !== ctrlr.root) { - ctrlr.selectRight(); - } - break; - - // Home -> move to the start of the root block or the current block. - case 'Home': - ctrlr.notify('move').cursor.insAtLeftEnd(cursor.parent); - break; - - // Ctrl-Home -> move to the start of the current block. - case 'Ctrl-Home': - ctrlr.notify('move').cursor.insAtLeftEnd(ctrlr.root); - break; - - // Shift-Home -> select to the start of the current block. - case 'Shift-Home': - while (cursor[L]) { - ctrlr.selectLeft(); - } - break; - - // Ctrl-Shift-Home -> move to the start of the root block. - case 'Ctrl-Shift-Home': - while (cursor[L] || cursor.parent !== ctrlr.root) { - ctrlr.selectLeft(); - } - break; - - case 'Left': ctrlr.moveLeft(); break; - case 'Shift-Left': ctrlr.selectLeft(); break; - case 'Ctrl-Left': break; - - case 'Right': ctrlr.moveRight(); break; - case 'Shift-Right': ctrlr.selectRight(); break; - case 'Ctrl-Right': break; - - case 'Up': ctrlr.moveUp(); break; - case 'Down': ctrlr.moveDown(); break; - - case 'Shift-Up': - if (cursor[L]) { - while (cursor[L]) ctrlr.selectLeft(); - } else { - ctrlr.selectLeft(); - } - - case 'Shift-Down': - if (cursor[R]) { - while (cursor[R]) ctrlr.selectRight(); - } - else { - ctrlr.selectRight(); - } - - case 'Ctrl-Up': break; - case 'Ctrl-Down': break; - - case 'Ctrl-Shift-Del': - case 'Ctrl-Del': - while (cursor[R] || cursor.selection) { - ctrlr.deleteForward(); - } - break; - - case 'Shift-Del': - case 'Del': - ctrlr.deleteForward(); - break; - - case 'Meta-A': - case 'Ctrl-A': - ctrlr.notify('move').cursor.insAtRightEnd(ctrlr.root); - while (cursor[L]) ctrlr.selectLeft(); - break; - - default: - return; - } - e.preventDefault(); - ctrlr.scrollHoriz(); - }; - - _.moveOutOf = // called by Controller::escapeDir, moveDir - _.moveTowards = // called by Controller::moveDir - _.deleteOutOf = // called by Controller::deleteDir - _.deleteTowards = // called by Controller::deleteDir - _.unselectInto = // called by Controller::selectDir - _.selectOutOf = // called by Controller::selectDir - _.selectTowards = // called by Controller::selectDir - function() { pray('overridden or never called on this node'); }; - }); - - Controller.open(function(_) { - this.onNotify(function(e) { - if (e === 'move' || e === 'upDown') this.show().clearSelection(); - }); - _.escapeDir = function(dir, key, e) { - prayDirection(dir); - var cursor = this.cursor; - - // only prevent default of Tab if not in the root editable - if (cursor.parent !== this.root) e.preventDefault(); - - // want to be a noop if in the root editable (in fact, Tab has an unrelated - // default browser action if so) - if (cursor.parent === this.root) return; - - cursor.parent.moveOutOf(dir, cursor); - cursor.parent.bubble('workingGroupChange'); - return this.notify('move'); - }; - - optionProcessors.leftRightIntoCmdGoes = function(updown) { - if (updown && updown !== 'up' && updown !== 'down') { - throw '"up" or "down" required for leftRightIntoCmdGoes option, ' - + 'got "'+updown+'"'; - } - return updown; - }; - _.moveDir = function(dir) { - prayDirection(dir); - var cursor = this.cursor, updown = cursor.options.leftRightIntoCmdGoes; - - if (cursor.selection) { - cursor.insDirOf(dir, cursor.selection.ends[dir]); - } - else if (cursor[dir]) cursor[dir].moveTowards(dir, cursor, updown); - else cursor.parent.moveOutOf(dir, cursor, updown); - - cursor.parent.bubble('workingGroupChange'); - return this.notify('move'); - }; - _.moveLeft = function() { return this.moveDir(L); }; - _.moveRight = function() { return this.moveDir(R); }; - - /** - * moveUp and moveDown have almost identical algorithms: - * - first check left and right, if so insAtLeft/RightEnd of them - * - else check the parent's 'upOutOf'/'downOutOf' property: - * + if it's a function, call it with the cursor as the sole argument and - * use the return value as if it were the value of the property - * + if it's a Node, jump up or down into it: - * - if there is a cached Point in the block, insert there - * - else, seekHoriz within the block to the current x-coordinate (to be - * as close to directly above/below the current position as possible) - * + unless it's exactly `true`, stop bubbling - */ - _.moveUp = function() { return moveUpDown(this, 'up'); }; - _.moveDown = function() { return moveUpDown(this, 'down'); }; - function moveUpDown(self, dir) { - var cursor = self.notify('upDown').cursor; - var dirInto = dir+'Into', dirOutOf = dir+'OutOf'; - if (cursor[R][dirInto]) cursor.insAtLeftEnd(cursor[R][dirInto]); - else if (cursor[L][dirInto]) cursor.insAtRightEnd(cursor[L][dirInto]); - else { - cursor.parent.bubble(function(ancestor) { - var prop = ancestor[dirOutOf]; - if (prop) { - if (typeof prop === 'function') prop = ancestor[dirOutOf](cursor); - if (prop instanceof Node) cursor.jumpUpDown(ancestor, prop); - if (prop !== true) return false; - } - }); - } - cursor.parent.bubble('workingGroupChange'); - return self; - } - this.onNotify(function(e) { if (e !== 'upDown') this.upDownCache = {}; }); - - this.onNotify(function(e) { if (e === 'edit') this.show().deleteSelection(); }); - _.deleteDir = function(dir) { - prayDirection(dir); - var cursor = this.cursor; - - var hadSelection = cursor.selection; - this.notify('edit'); // deletes selection if present - if (!hadSelection) { - if (cursor[dir]) cursor[dir].deleteTowards(dir, cursor); - else cursor.parent.deleteOutOf(dir, cursor); - } - - if (cursor[L].siblingDeleted) cursor[L].siblingDeleted(cursor.options, R); - if (cursor[R].siblingDeleted) cursor[R].siblingDeleted(cursor.options, L); - cursor.parent.bubble('reflow'); - cursor.parent.bubble('workingGroupChange'); - - return this; - }; - _.backspace = function() { return this.deleteDir(L); }; - _.deleteForward = function() { return this.deleteDir(R); }; - - this.onNotify(function(e) { if (e !== 'select') this.endSelection(); }); - _.selectDir = function(dir) { - var cursor = this.notify('select').cursor, seln = cursor.selection; - prayDirection(dir); - - if (!cursor.anticursor) cursor.startSelection(); - - var node = cursor[dir]; - if (node) { - // "if node we're selecting towards is inside selection (hence retracting) - // and is on the *far side* of the selection (hence is only node selected) - // and the anticursor is *inside* that node, not just on the other side" - if (seln && seln.ends[dir] === node && cursor.anticursor[-dir] !== node) { - node.unselectInto(dir, cursor); - } - else node.selectTowards(dir, cursor); - } - else cursor.parent.selectOutOf(dir, cursor); - - cursor.clearSelection(); - cursor.select() || cursor.show(); - }; - _.selectLeft = function() { return this.selectDir(L); }; - _.selectRight = function() { return this.selectDir(R); }; - }); -// Parser MathCommand - var latexMathParser = (function() { - function commandToBlock(cmd) { - var block = MathBlock(); - cmd.adopt(block, 0, 0); - return block; - } - function joinBlocks(blocks) { - var firstBlock = blocks[0] || MathBlock(); - - for (var i = 1; i < blocks.length; i += 1) { - blocks[i].children().adopt(firstBlock, firstBlock.ends[R], 0); - } - - return firstBlock; - } - - var string = Parser.string; - var regex = Parser.regex; - var letter = Parser.letter; - var any = Parser.any; - var optWhitespace = Parser.optWhitespace; - var succeed = Parser.succeed; - var fail = Parser.fail; - - // Parsers yielding MathCommands - var variable = letter.map(function(c) { return Letter(c); }); - var symbol = regex(/^[^${}\\_^]/).map(function(c) { return VanillaSymbol(c); }); - - var controlSequence = - regex(/^[^\\a-eg-zA-Z]/) // hotfix #164; match MathBlock::write - .or(string('\\').then( - regex(/^[a-z]+/i) - .or(regex(/^\s+/).result(' ')) - .or(any) - )).then(function(ctrlSeq) { - var cmdKlass = LatexCmds[ctrlSeq]; - - if (cmdKlass) { - return cmdKlass(ctrlSeq).parser(); - } - else { - return fail('unknown command: \\'+ctrlSeq); - } - }) - ; - - var command = - controlSequence - .or(variable) - .or(symbol) - ; - - // Parsers yielding MathBlocks - var mathGroup = string('{').then(function() { return mathSequence; }).skip(string('}')); - var mathBlock = optWhitespace.then(mathGroup.or(command.map(commandToBlock))); - var mathSequence = mathBlock.many().map(joinBlocks).skip(optWhitespace); - - var optMathBlock = - string('[').then( - mathBlock.then(function(block) { - return block.join('latex') !== ']' ? succeed(block) : fail(); - }) - .many().map(joinBlocks).skip(optWhitespace) - ).skip(string(']')) - ; - - var latexMath = mathSequence; - - latexMath.block = mathBlock; - latexMath.optBlock = optMathBlock; - return latexMath; - })(); - - Controller.open(function(_, super_) { - _.exportLatex = function() { - return this.root.latex().replace(/(\\[a-z]+) (?![a-z])/ig,'$1'); - }; - _.writeLatex = function(latex) { - var cursor = this.notify('edit').cursor; - - var all = Parser.all; - var eof = Parser.eof; - - var block = latexMathParser.skip(eof).or(all.result(false)).parse(latex); - - if (block && !block.isEmpty()) { - block.children().adopt(cursor.parent, cursor[L], cursor[R]); - var jQ = block.jQize(); - jQ.insertBefore(cursor.jQ); - cursor[L] = block.ends[R]; - 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'); - } - - return this; - }; - _.renderLatexMath = function(latex) { - var root = this.root, cursor = this.cursor; - - var all = Parser.all; - var eof = Parser.eof; - - var block = latexMathParser.skip(eof).or(all.result(false)).parse(latex); - - root.eachChild('postOrder', 'dispose'); - root.ends[L] = root.ends[R] = 0; - - if (block) { - block.children().adopt(root, 0, 0); - } - - var jQ = root.jQ; - - if (block) { - var html = block.join('html'); - jQ.html(html); - root.jQize(jQ.children()); - root.finalizeInsert(cursor.options); - } - else { - jQ.empty(); - } - - delete cursor.selection; - cursor.insAtRightEnd(root); - }; - _.renderLatexText = function(latex) { - var root = this.root, cursor = this.cursor; - - root.jQ.children().slice(1).remove(); - root.eachChild('postOrder', 'dispose'); - root.ends[L] = root.ends[R] = 0; - delete cursor.selection; - cursor.show().insAtRightEnd(root); - - var regex = Parser.regex; - var string = Parser.string; - var eof = Parser.eof; - var all = Parser.all; - - // Parser RootMathCommand - var mathMode = string('$').then(latexMathParser) - // because TeX is insane, math mode doesn't necessarily - // have to end. So we allow for the case that math mode - // continues to the end of the stream. - .skip(string('$').or(eof)) - .map(function(block) { - // HACK FIXME: this shouldn't have to have access to cursor - var rootMathCommand = RootMathCommand(cursor); - - rootMathCommand.createBlocks(); - var rootMathBlock = rootMathCommand.ends[L]; - block.children().adopt(rootMathBlock, 0, 0); - - return rootMathCommand; - }) - ; - - var escapedDollar = string('\\$').result('$'); - var textChar = escapedDollar.or(regex(/^[^$]/)).map(VanillaSymbol); - var latexText = mathMode.or(textChar).many(); - var commands = latexText.skip(eof).or(all.result(false)).parse(latex); - - if (commands) { - for (var i = 0; i < commands.length; i += 1) { - commands[i].adopt(root, root.ends[R], 0); - } - - root.jQize().appendTo(root.jQ); - - root.finalizeInsert(cursor.options); - } - }; - }); - /******************************************************** - * Deals with mouse events for clicking, drag-to-select - *******************************************************/ - - Controller.open(function(_) { - _.delegateMouseEvents = function() { - var ultimateRootjQ = this.root.jQ; - //drag-to-select event handling - this.container.bind('mousedown.mathquill', function(e) { - var rootjQ = $(e.target).closest('.mq-root-block'); - var root = Node.byId[rootjQ.attr(mqBlockId) || ultimateRootjQ.attr(mqBlockId)]; - var ctrlr = root.controller, cursor = ctrlr.cursor, blink = cursor.blink; - var textareaSpan = ctrlr.textareaSpan, textarea = ctrlr.textarea; - - var target; - function mousemove(e) { target = $(e.target); } - function docmousemove(e) { - if (!cursor.anticursor) cursor.startSelection(); - ctrlr.seek(target, e.pageX, e.pageY).cursor.select(); - target = undefined; - } - // outside rootjQ, the MathQuill node corresponding to the target (if any) - // won't be inside this root, so don't mislead Controller::seek with it - - function mouseup(e) { - cursor.blink = blink; - if (!cursor.selection) { - if (ctrlr.editable) { - cursor.show(); - } - else { - textareaSpan.detach(); - } - } - - // delete the mouse handlers now that we're not dragging anymore - rootjQ.unbind('mousemove', mousemove); - $(e.target.ownerDocument).unbind('mousemove', docmousemove).unbind('mouseup', mouseup); - } - - if (ctrlr.blurred) { - if (!ctrlr.editable) rootjQ.prepend(textareaSpan); - textarea.focus(); - } - e.preventDefault(); // doesn't work in IE\u22648, but it's a one-line fix: - e.target.unselectable = true; // http://jsbin.com/yagekiji/1 - - cursor.blink = noop; - ctrlr.seek($(e.target), e.pageX, e.pageY).cursor.startSelection(); - - rootjQ.mousemove(mousemove); - $(e.target.ownerDocument).mousemove(docmousemove).mouseup(mouseup); - // listen on document not just body to not only hear about mousemove and - // mouseup on page outside field, but even outside page, except iframes: https://github.com/mathquill/mathquill/commit/8c50028afcffcace655d8ae2049f6e02482346c5#commitcomment-6175800 - }); - } - }); - - Controller.open(function(_) { - _.seek = function(target, pageX, pageY) { - var cursor = this.notify('select').cursor; - - if (target) { - var nodeId = target.attr(mqBlockId) || target.attr(mqCmdId); - if (!nodeId) { - var targetParent = target.parent(); - nodeId = targetParent.attr(mqBlockId) || targetParent.attr(mqCmdId); - } - } - var node = nodeId ? Node.byId[nodeId] : this.root; - pray('nodeId is the id of some Node that exists', node); - - // don't clear selection until after getting node from target, in case - // target was selection span, otherwise target will have no parent and will - // seek from root, which is less accurate (e.g. fraction) - cursor.clearSelection().show(); - - node.seek(pageX, cursor); - this.scrollHoriz(); // before .selectFrom when mouse-selecting, so - // always hits no-selection case in scrollHoriz and scrolls slower - cursor.parent.bubble('workingGroupChange'); - return this; - }; - }); - /*********************************************** - * Horizontal panning for editable fields that - * overflow their width - **********************************************/ - - Controller.open(function(_) { - _.scrollHoriz = function() { - var cursor = this.cursor, seln = cursor.selection; - var rootRect = this.root.jQ[0].getBoundingClientRect(); - if (!seln) { - var x = cursor.jQ[0].getBoundingClientRect().left; - if (x > rootRect.right - 20) var scrollBy = x - (rootRect.right - 20); - else if (x < rootRect.left + 20) var scrollBy = x - (rootRect.left + 20); - else return; - } - else { - var rect = seln.jQ[0].getBoundingClientRect(); - var overLeft = rect.left - (rootRect.left + 20); - var overRight = rect.right - (rootRect.right - 20); - if (seln.ends[L] === cursor[R]) { - if (overLeft < 0) var scrollBy = overLeft; - else if (overRight > 0) { - if (rect.left - overRight < rootRect.left + 20) var scrollBy = overLeft; - else var scrollBy = overRight; - } - else return; - } - else { - if (overRight > 0) var scrollBy = overRight; - else if (overLeft < 0) { - if (rect.right - overLeft > rootRect.right - 20) var scrollBy = overRight; - else var scrollBy = overLeft; - } - else return; - } - } - this.root.jQ.stop().animate({ scrollLeft: '+=' + scrollBy}, 100); - }; - }); - /********************************************* - * Manage the MathQuill instance's textarea - * (as owned by the Controller) - ********************************************/ - - Controller.open(function(_) { - Options.p.substituteTextarea = function() { return $('<textarea>')[0]; }; - _.createTextarea = function() { - var textareaSpan = this.textareaSpan = $('<span class="mq-textarea"></span>'), - textarea = this.API.__options.substituteTextarea(); - if (!textarea.nodeType) { - throw 'substituteTextarea() must return a DOM element, got ' + textarea; - } - textarea = this.textarea = $(textarea).appendTo(textareaSpan); - - var ctrlr = this; - ctrlr.cursor.selectionChanged = function() { ctrlr.selectionChanged(); }; - ctrlr.container.bind('copy', function() { ctrlr.setTextareaSelection(); }); - }; - _.selectionChanged = function() { - var ctrlr = this; - forceIERedraw(ctrlr.container[0]); - - // throttle calls to setTextareaSelection(), because setting textarea.value - // and/or calling textarea.select() can have anomalously bad performance: - // https://github.com/mathquill/mathquill/issues/43#issuecomment-1399080 - if (ctrlr.textareaSelectionTimeout === undefined) { - ctrlr.textareaSelectionTimeout = setTimeout(function() { - ctrlr.setTextareaSelection(); - }); - } - }; - _.setTextareaSelection = function() { - this.textareaSelectionTimeout = undefined; - var latex = ''; - if (this.cursor.selection) { - latex = this.cursor.selection.join('latex'); - if (this.API.__options.statelessClipboard) { - // FIXME: like paste, only this works for math fields; should ask parent - latex = '$' + latex + '$'; - } - } - this.selectFn(latex); - }; - _.staticMathTextareaEvents = function() { - var ctrlr = this, root = ctrlr.root, cursor = ctrlr.cursor, - textarea = ctrlr.textarea, textareaSpan = ctrlr.textareaSpan; - - this.container.prepend('<span class="mq-selectable">$'+ctrlr.exportLatex()+'$</span>'); - ctrlr.blurred = true; - textarea.bind('cut paste', false) - .focus(function() { ctrlr.blurred = false; }).blur(function() { - if (cursor.selection) cursor.selection.clear(); - setTimeout(detach); //detaching during blur explodes in WebKit - }); - function detach() { - textareaSpan.detach(); - ctrlr.blurred = true; - } - - ctrlr.selectFn = function(text) { - textarea.val(text); - if (text) textarea.select(); - }; - }; - _.editablesTextareaEvents = function() { - var ctrlr = this, root = ctrlr.root, cursor = ctrlr.cursor, - textarea = ctrlr.textarea, textareaSpan = ctrlr.textareaSpan; - - var keyboardEventsShim = saneKeyboardEvents(textarea, this); - this.selectFn = function(text) { keyboardEventsShim.select(text); }; - - this.container.prepend(textareaSpan) - .on('cut', function(e) { - if (cursor.selection) { - setTimeout(function() { - ctrlr.notify('edit'); // deletes selection if present - cursor.parent.bubble('reflow'); - }); - } - }); - - this.focusBlurEvents(); - }; - _.typedText = function(ch) { - if (ch === '\n') return this.handle('enter'); - var cursor = this.notify().cursor; - cursor.parent.write(cursor, ch, cursor.show().replaceSelection()); - this.scrollHoriz(); - }; - _.paste = function(text) { - // TODO: document `statelessClipboard` config option in README, after - // making it work like it should, that is, in both text and math mode - // (currently only works in math fields, so worse than pointless, it - // only gets in the way by \text{}-ifying pasted stuff and $-ifying - // cut/copied LaTeX) - if (this.API.__options.statelessClipboard) { - if (text.slice(0,1) === '$' && text.slice(-1) === '$') { - text = text.slice(1, -1); - } - else { - text = '\\text{'+text+'}'; - } - } - // FIXME: this always inserts math or a TextBlock, even in a RootTextBlock - this.writeLatex(text).cursor.show(); - }; - }); - /************************************************* - * Abstract classes of math blocks and commands. - ************************************************/ - - /** - * Math tree node base class. - * Some math-tree-specific extensions to Node. - * Both MathBlock's and MathCommand's descend from it. - */ - var MathElement = P(Node, function(_, super_) { - _.finalizeInsert = function(options, cursor) { // `cursor` param is only for - // SupSub::contactWeld, and is deliberately only passed in by writeLatex, - // see ea7307eb4fac77c149a11ffdf9a831df85247693 - var self = this; - self.postOrder('finalizeTree', options); - self.postOrder('contactWeld', cursor); - - // note: this order is important. - // empty elements need the empty box provided by blur to - // be present in order for their dimensions to be measured - // correctly by 'reflow' handlers. - self.postOrder('blur'); - - self.postOrder('reflow'); - if (self[R].siblingCreated) self[R].siblingCreated(options, L); - if (self[L].siblingCreated) self[L].siblingCreated(options, R); - self.bubble('reflow'); - }; - }); - - /** - * Commands and operators, like subscripts, exponents, or fractions. - * Descendant commands are organized into blocks. - */ - var MathCommand = P(MathElement, function(_, super_) { - _.init = function(ctrlSeq, htmlTemplate, textTemplate) { - var cmd = this; - super_.init.call(cmd); - - if (!cmd.ctrlSeq) cmd.ctrlSeq = ctrlSeq; - if (htmlTemplate) cmd.htmlTemplate = htmlTemplate; - if (textTemplate) cmd.textTemplate = textTemplate; - }; - - // obvious methods - _.replaces = function(replacedFragment) { - replacedFragment.disown(); - this.replacedFragment = replacedFragment; - }; - _.isEmpty = function() { - return this.foldChildren(true, function(isEmpty, child) { - return isEmpty && child.isEmpty(); - }); - }; - - _.parser = function() { - var block = latexMathParser.block; - var self = this; - - return block.times(self.numBlocks()).map(function(blocks) { - self.blocks = blocks; - - for (var i = 0; i < blocks.length; i += 1) { - blocks[i].adopt(self, self.ends[R], 0); - } - - return self; - }); - }; - - // createLeftOf(cursor) and the methods it calls - _.createLeftOf = function(cursor) { - var cmd = this; - var replacedFragment = cmd.replacedFragment; - - cmd.createBlocks(); - super_.createLeftOf.call(cmd, cursor); - if (replacedFragment) { - replacedFragment.adopt(cmd.ends[L], 0, 0); - replacedFragment.jQ.appendTo(cmd.ends[L].jQ); - } - cmd.finalizeInsert(cursor.options); - cmd.placeCursor(cursor); - if((this instanceof BinaryOperator) || - (this instanceof Fraction) || - (this instanceof SupSub) || - (this instanceof SquareRoot)) - this.bubble('workingGroupChange'); - }; - _.createBlocks = function() { - var cmd = this, - numBlocks = cmd.numBlocks(), - blocks = cmd.blocks = Array(numBlocks); - - for (var i = 0; i < numBlocks; i += 1) { - var newBlock = blocks[i] = MathBlock(); - newBlock.adopt(cmd, cmd.ends[R], 0); - } - }; - _.placeCursor = function(cursor) { - //insert the cursor at the right end of the first empty child, searching - //left-to-right, or if none empty, the right end child - cursor.insAtRightEnd(this.foldChildren(this.ends[L], function(leftward, child) { - return leftward.isEmpty() ? leftward : child; - })); - }; - - // editability methods: called by the cursor for editing, cursor movements, - // and selection of the MathQuill tree, these all take in a direction and - // the cursor - _.moveTowards = function(dir, cursor, updown) { - var updownInto = updown && this[updown+'Into']; - cursor.insAtDirEnd(-dir, updownInto || this.ends[-dir]); - }; - _.deleteTowards = function(dir, cursor) { - cursor.startSelection(); - this.selectTowards(dir, cursor); - cursor.select(); - }; - _.selectTowards = function(dir, cursor) { - cursor[-dir] = this; - cursor[dir] = this[dir]; - }; - _.selectChildren = function() { - return Selection(this, this); - }; - _.unselectInto = function(dir, cursor) { - cursor.insAtDirEnd(-dir, cursor.anticursor.ancestors[this.id]); - }; - _.seek = function(pageX, cursor) { - function getBounds(node) { - var bounds = {} - bounds[L] = node.jQ.offset().left; - bounds[R] = bounds[L] + node.jQ.outerWidth(); - return bounds; - } - - var cmd = this; - var cmdBounds = getBounds(cmd); - - if (pageX < cmdBounds[L]) return cursor.insLeftOf(cmd); - if (pageX > cmdBounds[R]) return cursor.insRightOf(cmd); - - var leftLeftBound = cmdBounds[L]; - cmd.eachChild(function(block) { - var blockBounds = getBounds(block); - if (pageX < blockBounds[L]) { - // closer to this block's left bound, or the bound left of that? - if (pageX - leftLeftBound < blockBounds[L] - pageX) { - if (block[L]) cursor.insAtRightEnd(block[L]); - else cursor.insLeftOf(cmd); - } - else cursor.insAtLeftEnd(block); - return false; - } - else if (pageX > blockBounds[R]) { - if (block[R]) leftLeftBound = blockBounds[R]; // continue to next block - else { // last (rightmost) block - // closer to this block's right bound, or the cmd's right bound? - if (cmdBounds[R] - pageX < pageX - blockBounds[R]) { - cursor.insRightOf(cmd); - } - else cursor.insAtRightEnd(block); - } - } - else { - block.seek(pageX, cursor); - return false; - } - }); - } - - // methods involved in creating and cross-linking with HTML DOM nodes - /* - They all expect an .htmlTemplate like - '<span>&0</span>' - or - '<span><span>&0</span><span>&1</span></span>' - - See html.test.js for more examples. - - Requirements: - - For each block of the command, there must be exactly one "block content - marker" of the form '&<number>' where <number> is the 0-based index of the - block. (Like the LaTeX \newcommand syntax, but with a 0-based rather than - 1-based index, because JavaScript because C because Dijkstra.) - - The block content marker must be the sole contents of the containing - element, there can't even be surrounding whitespace, or else we can't - guarantee sticking to within the bounds of the block content marker when - mucking with the HTML DOM. - - The HTML not only must be well-formed HTML (of course), but also must - conform to the XHTML requirements on tags, specifically all tags must - either be self-closing (like '<br/>') or come in matching pairs. - Close tags are never optional. - - Note that &<number> isn't well-formed HTML; if you wanted a literal '&123', - your HTML template would have to have '&amp;123'. - */ - _.numBlocks = function() { - var matches = this.htmlTemplate.match(/&\d+/g); - return matches ? matches.length : 0; - }; - _.html = function() { - // Render the entire math subtree rooted at this command, as HTML. - // Expects .createBlocks() to have been called already, since it uses the - // .blocks array of child blocks. - // - // See html.test.js for example templates and intended outputs. - // - // Given an .htmlTemplate as described above, - // - insert the mathquill-command-id attribute into all top-level tags, - // which will be used to set this.jQ in .jQize(). - // This is straightforward: - // * tokenize into tags and non-tags - // * loop through top-level tokens: - // * add #cmdId attribute macro to top-level self-closing tags - // * else add #cmdId attribute macro to top-level open tags - // * skip the matching top-level close tag and all tag pairs - // in between - // - for each block content marker, - // + replace it with the contents of the corresponding block, - // rendered as HTML - // + insert the mathquill-block-id attribute into the containing tag - // This is even easier, a quick regex replace, since block tags cannot - // contain anything besides the block content marker. - // - // Two notes: - // - The outermost loop through top-level tokens should never encounter any - // top-level close tags, because we should have first encountered a - // matching top-level open tag, all inner tags should have appeared in - // matching pairs and been skipped, and then we should have skipped the - // close tag in question. - // - All open tags should have matching close tags, which means our inner - // loop should always encounter a close tag and drop nesting to 0. If - // a close tag is missing, the loop will continue until i >= tokens.length - // and token becomes undefined. This will not infinite loop, even in - // production without pray(), because it will then TypeError on .slice(). - - var cmd = this; - var blocks = cmd.blocks; - var cmdId = ' mathquill-command-id=' + cmd.id; - var tokens = cmd.htmlTemplate.match(/<[^<>]+>|[^<>]+/g); - - pray('no unmatched angle brackets', tokens.join('') === this.htmlTemplate); - - // add cmdId to all top-level tags - for (var i = 0, token = tokens[0]; token; i += 1, token = tokens[i]) { - // top-level self-closing tags - if (token.slice(-2) === '/>') { - tokens[i] = token.slice(0,-2) + cmdId + '/>'; - } - // top-level open tags - else if (token.charAt(0) === '<') { - pray('not an unmatched top-level close tag', token.charAt(1) !== '/'); - - tokens[i] = token.slice(0,-1) + cmdId + '>'; - - // skip matching top-level close tag and all tag pairs in between - var nesting = 1; - do { - i += 1, token = tokens[i]; - pray('no missing close tags', token); - // close tags - if (token.slice(0,2) === '</') { - nesting -= 1; - } - // non-self-closing open tags - else if (token.charAt(0) === '<' && token.slice(-2) !== '/>') { - nesting += 1; - } - } while (nesting > 0); - } - } - return tokens.join('').replace(/>&(\d+)/g, function($0, $1) { - return ' mathquill-block-id=' + blocks[$1].id + '>' + blocks[$1].join('html'); - }); - }; - - // methods to export a string representation of the math tree - _.latex = function() { - return this.foldChildren(this.ctrlSeq, function(latex, child) { - return latex + '{' + (child.latex() || ' ') + '}'; - }); - }; - _.textTemplate = ['']; - _.text = function(opts) { - var cmd = this, i = 0; - return cmd.foldChildren(cmd.textTemplate[i], function(text, child) { - i += 1; - var child_text = child.text(opts); - if (text && cmd.textTemplate[i] === '(' - && child_text[0] === '(' && child_text.slice(-1) === ')') - return text + child_text.slice(1, -1) + cmd.textTemplate[i]; - return text + child.text(opts) + (cmd.textTemplate[i] || ''); - }); - }; - }); - - /** - * Lightweight command without blocks or children. - */ - var Symbol = P(MathCommand, function(_, super_) { - _.init = function(ctrlSeq, html, text) { - if (!text) text = ctrlSeq && ctrlSeq.length > 1 ? ctrlSeq.slice(1) : ctrlSeq; - - super_.init.call(this, ctrlSeq, html, [ text ]); - }; - - _.parser = function() { return Parser.succeed(this); }; - _.numBlocks = function() { return 0; }; - - _.replaces = function(replacedFragment) { - replacedFragment.remove(); - }; - _.createBlocks = noop; - - _.moveTowards = function(dir, cursor) { - cursor.jQ.insDirOf(dir, this.jQ); - cursor[-dir] = this; - cursor[dir] = this[dir]; - }; - _.deleteTowards = function(dir, cursor) { - cursor[dir] = this.remove()[dir]; - }; - _.seek = function(pageX, cursor) { - // insert at whichever side the click was closer to - if (pageX - this.jQ.offset().left < this.jQ.outerWidth()/2) - cursor.insLeftOf(this); - else - cursor.insRightOf(this); - }; - - _.latex = function(){ return this.ctrlSeq; }; - _.text = function(){ return this.textTemplate; }; - _.placeCursor = noop; - _.isEmpty = function(){ return true; }; - }); - var VanillaSymbol = P(Symbol, function(_, super_) { - _.init = function(ch, html) { - super_.init.call(this, ch, '<span>'+(html || ch)+'</span>'); - }; - }); - var BinaryOperator = P(Symbol, function(_, super_) { - _.init = function(ctrlSeq, html, text) { - super_.init.call(this, - ctrlSeq, '<span class="mq-binary-operator">'+html+'</span>', text - ); - }; - }); - - /** - * Children and parent of MathCommand's. Basically partitions all the - * symbols and operators that descend (in the Math DOM tree) from - * ancestor operators. - */ - var MathBlock = P(MathElement, function(_, super_) { - _.join = function(methodName) { - return this.foldChildren('', function(fold, child) { - return fold + child[methodName](); - }); - }; - _.html = function() { return this.join('html'); }; - _.latex = function() { return this.join('latex'); }; - _.text = function(opts) { - return this.ends[L] === this.ends[R] ? - this.ends[L].text(opts) : - this.foldChildren('', function(text, child) { - return text + child.text(opts); - }) - ; - }; - - _.keystroke = function(key, e, ctrlr) { - if (ctrlr.API.__options.spaceBehavesLikeTab - && (key === 'Spacebar' || key === 'Shift-Spacebar')) { - e.preventDefault(); - ctrlr.escapeDir(key === 'Shift-Spacebar' ? L : R, key, e); - return; - } - return super_.keystroke.apply(this, arguments); - }; - - // editability methods: called by the cursor for editing, cursor movements, - // and selection of the MathQuill tree, these all take in a direction and - // the cursor - _.moveOutOf = function(dir, cursor, updown) { - var updownInto = updown && this.parent[updown+'Into']; - if (!updownInto && this[dir]) cursor.insAtDirEnd(-dir, this[dir]); - else cursor.insDirOf(dir, this.parent); - }; - _.selectOutOf = function(dir, cursor) { - cursor.insDirOf(dir, this.parent); - }; - _.deleteOutOf = function(dir, cursor) { - cursor.unwrapGramp(); - }; - _.seek = function(pageX, cursor) { - var node = this.ends[R]; - if (!node || node.jQ.offset().left + node.jQ.outerWidth() < pageX) { - return cursor.insAtRightEnd(this); - } - if (pageX < this.ends[L].jQ.offset().left) return cursor.insAtLeftEnd(this); - while (pageX < node.jQ.offset().left) node = node[L]; - return node.seek(pageX, cursor); - }; - _.write = function(cursor, ch, replacedFragment) { - var cmd; - if (ch.match(/^[a-eg-zA-Z]$/)) //exclude f because want florin - cmd = Letter(ch); - else if (cmd = CharCmds[ch] || LatexCmds[ch]) - cmd = cmd(ch); - else - cmd = VanillaSymbol(ch); - - if (replacedFragment) cmd.replaces(replacedFragment); - - cmd.createLeftOf(cursor); - }; - - _.focus = function() { - this.jQ.addClass('mq-hasCursor'); - this.jQ.removeClass('mq-empty'); - - return this; - }; - _.blur = function() { - this.jQ.removeClass('mq-hasCursor'); - if (this.isEmpty()) - this.jQ.addClass('mq-empty'); - - return this; - }; - }); - - var RootMathBlock = P(MathBlock, RootBlockMixin); - MathQuill.MathField = APIFnFor(P(EditableField, function(_, super_) { - _.init = function(el, opts) { - el.addClass('mq-editable-field mq-math-mode'); - this.initRootAndEvents(RootMathBlock(), el, opts); - }; - })); - /************************************************* - * Abstract classes of text blocks - ************************************************/ - - /** - * Blocks of plain text, with one or two TextPiece's as children. - * Represents flat strings of typically serif-font Roman characters, as - * opposed to hierchical, nested, tree-structured math. - * Wraps a single HTMLSpanElement. - */ - var TextBlock = P(Node, function(_, super_) { - _.ctrlSeq = '\\text'; - - _.replaces = function(replacedText) { - if (replacedText instanceof Fragment) - this.replacedText = replacedText.remove().jQ.text(); - else if (typeof replacedText === 'string') - this.replacedText = replacedText; - }; - - _.jQadd = function(jQ) { - super_.jQadd.call(this, jQ); - if (this.ends[L]) this.ends[L].jQadd(this.jQ[0].firstChild); - }; - - _.createLeftOf = function(cursor) { - var textBlock = this; - super_.createLeftOf.call(this, cursor); - - if (textBlock[R].siblingCreated) textBlock[R].siblingCreated(cursor.options, L); - if (textBlock[L].siblingCreated) textBlock[L].siblingCreated(cursor.options, R); - textBlock.bubble('reflow'); - - cursor.insAtRightEnd(textBlock); - - if (textBlock.replacedText) - for (var i = 0; i < textBlock.replacedText.length; i += 1) - textBlock.write(cursor, textBlock.replacedText.charAt(i)); - }; - - _.parser = function() { - var textBlock = this; - - // TODO: correctly parse text mode - var string = Parser.string; - var regex = Parser.regex; - var optWhitespace = Parser.optWhitespace; - return optWhitespace - .then(string('{')).then(regex(/^[^}]*/)).skip(string('}')) - .map(function(text) { - // TODO: is this the correct behavior when parsing - // the latex \text{} ? This violates the requirement that - // the text contents are always nonempty. Should we just - // disown the parent node instead? - TextPiece(text).adopt(textBlock, 0, 0); - return textBlock; - }) - ; - }; - - _.textContents = function() { - return this.foldChildren('', function(text, child) { - return text + child.text; - }); - }; - _.text = function(opts) { - if (opts.dropTextFieldsOnTextOutput) return ''; - return '"' + this.textContents() + '"'; - }; - _.latex = function() { return '\\text{' + this.textContents() + '}'; }; - _.html = function() { - return ( - '<span class="mq-text-mode" mathquill-command-id='+this.id+'>' - + this.textContents() - + '</span>' - ); - }; - - // editability methods: called by the cursor for editing, cursor movements, - // and selection of the MathQuill tree, these all take in a direction and - // the cursor - _.moveTowards = function(dir, cursor) { cursor.insAtDirEnd(-dir, this); }; - _.moveOutOf = function(dir, cursor) { cursor.insDirOf(dir, this); }; - _.unselectInto = _.moveTowards; - - // TODO: make these methods part of a shared mixin or something. - _.selectTowards = MathCommand.prototype.selectTowards; - _.deleteTowards = MathCommand.prototype.deleteTowards; - - _.selectOutOf = function(dir, cursor) { - cursor.insDirOf(dir, this); - }; - _.deleteOutOf = function(dir, cursor) { - // backspace and delete at ends of block don't unwrap - if (this.isEmpty()) cursor.insRightOf(this); - }; - _.write = function(cursor, ch, replacedFragment) { - if (replacedFragment) replacedFragment.remove(); - - if (ch !== '$') { - if (!cursor[L]) TextPiece(ch).createLeftOf(cursor); - else cursor[L].appendText(ch); - } - else if (this.isEmpty()) { - cursor.insRightOf(this); - VanillaSymbol('\\$','$').createLeftOf(cursor); - } - else if (!cursor[R]) cursor.insRightOf(this); - else if (!cursor[L]) cursor.insLeftOf(this); - else { // split apart - var leftBlock = TextBlock(); - var leftPc = this.ends[L]; - leftPc.disown(); - leftPc.adopt(leftBlock, 0, 0); - - cursor.insLeftOf(this); - super_.createLeftOf.call(leftBlock, cursor); - } - }; - - _.seek = function(pageX, cursor) { - cursor.hide(); - var textPc = fuseChildren(this); - - // insert cursor at approx position in DOMTextNode - var avgChWidth = this.jQ.width()/this.text.length; - var approxPosition = Math.round((pageX - this.jQ.offset().left)/avgChWidth); - if (approxPosition <= 0) cursor.insAtLeftEnd(this); - else if (approxPosition >= textPc.text.length) cursor.insAtRightEnd(this); - else cursor.insLeftOf(textPc.splitRight(approxPosition)); - - // move towards mousedown (pageX) - var displ = pageX - cursor.show().offset().left; // displacement - var dir = displ && displ < 0 ? L : R; - var prevDispl = dir; - // displ * prevDispl > 0 iff displacement direction === previous direction - while (cursor[dir] && displ * prevDispl > 0) { - cursor[dir].moveTowards(dir, cursor); - prevDispl = displ; - displ = pageX - cursor.offset().left; - } - if (dir*displ < -dir*prevDispl) cursor[-dir].moveTowards(-dir, cursor); - - if (!cursor.anticursor) { - // about to start mouse-selecting, the anticursor is gonna get put here - this.anticursorPosition = cursor[L] && cursor[L].text.length; - // ^ get it? 'cos if there's no cursor[L], it's 0... I'm a terrible person. - } - else if (cursor.anticursor.parent === this) { - // mouse-selecting within this TextBlock, re-insert the anticursor - var cursorPosition = cursor[L] && cursor[L].text.length;; - if (this.anticursorPosition === cursorPosition) { - cursor.anticursor = Point.copy(cursor); - } - else { - if (this.anticursorPosition < cursorPosition) { - var newTextPc = cursor[L].splitRight(this.anticursorPosition); - cursor[L] = newTextPc; - } - else { - var newTextPc = cursor[R].splitRight(this.anticursorPosition - cursorPosition); - } - cursor.anticursor = Point(this, newTextPc[L], newTextPc); - } - } - }; - - _.blur = function() { - MathBlock.prototype.blur.call(this); - fuseChildren(this); - }; - - function fuseChildren(self) { - self.jQ[0].normalize(); - - var textPcDom = self.jQ[0].firstChild; - var textPc = TextPiece(textPcDom.data); - textPc.jQadd(textPcDom); - - self.children().disown(); - return textPc.adopt(self, 0, 0); - } - - _.focus = MathBlock.prototype.focus; - }); - - /** - * Piece of plain text, with a TextBlock as a parent and no children. - * Wraps a single DOMTextNode. - * For convenience, has a .text property that's just a JavaScript string - * mirroring the text contents of the DOMTextNode. - * Text contents must always be nonempty. - */ - var TextPiece = P(Node, function(_, super_) { - _.init = function(text) { - super_.init.call(this); - this.text = text; - }; - _.jQadd = function(dom) { this.dom = dom; this.jQ = $(dom); }; - _.jQize = function() { - return this.jQadd(document.createTextNode(this.text)); - }; - _.appendText = function(text) { - this.text += text; - this.dom.appendData(text); - }; - _.prependText = function(text) { - this.text = text + this.text; - this.dom.insertData(0, text); - }; - _.insTextAtDirEnd = function(text, dir) { - prayDirection(dir); - if (dir === R) this.appendText(text); - else this.prependText(text); - }; - _.splitRight = function(i) { - var newPc = TextPiece(this.text.slice(i)).adopt(this.parent, this, this[R]); - newPc.jQadd(this.dom.splitText(i)); - this.text = this.text.slice(0, i); - return newPc; - }; - - function endChar(dir, text) { - return text.charAt(dir === L ? 0 : -1 + text.length); - } - - _.moveTowards = function(dir, cursor) { - prayDirection(dir); - - var ch = endChar(-dir, this.text) - - var from = this[-dir]; - if (from) from.insTextAtDirEnd(ch, dir); - else TextPiece(ch).createDir(-dir, cursor); - - return this.deleteTowards(dir, cursor); - }; - - _.latex = function() { return this.text; }; - - _.deleteTowards = function(dir, cursor) { - if (this.text.length > 1) { - if (dir === R) { - this.dom.deleteData(0, 1); - this.text = this.text.slice(1); - } - else { - // note that the order of these 2 lines is annoyingly important - // (the second line mutates this.text.length) - this.dom.deleteData(-1 + this.text.length, 1); - this.text = this.text.slice(0, -1); - } - } - else { - this.remove(); - this.jQ.remove(); - cursor[dir] = this[dir]; - } - }; - - _.selectTowards = function(dir, cursor) { - prayDirection(dir); - var anticursor = cursor.anticursor; - - var ch = endChar(-dir, this.text) - - if (anticursor[dir] === this) { - var newPc = TextPiece(ch).createDir(dir, cursor); - anticursor[dir] = newPc; - cursor.insDirOf(dir, newPc); - } - else { - var from = this[-dir]; - if (from) from.insTextAtDirEnd(ch, dir); - else { - var newPc = TextPiece(ch).createDir(-dir, cursor); - newPc.jQ.insDirOf(-dir, cursor.selection.jQ); - } - - if (this.text.length === 1 && anticursor[-dir] === this) { - anticursor[-dir] = this[-dir]; // `this` will be removed in deleteTowards - } - } - - return this.deleteTowards(dir, cursor); - }; - }); - - CharCmds.$ = - LatexCmds.text = - LatexCmds.textnormal = - LatexCmds.textrm = - LatexCmds.textup = - LatexCmds.textmd = TextBlock; - - function makeTextBlock(latex, tagName, attrs) { - return P(TextBlock, { - ctrlSeq: latex, - htmlTemplate: '<'+tagName+' '+attrs+'>&0</'+tagName+'>' - }); - } - - LatexCmds.em = LatexCmds.italic = LatexCmds.italics = - LatexCmds.emph = LatexCmds.textit = LatexCmds.textsl = - makeTextBlock('\\textit', 'i', 'class="mq-text-mode"'); - LatexCmds.strong = LatexCmds.bold = LatexCmds.textbf = - makeTextBlock('\\textbf', 'b', 'class="mq-text-mode"'); - LatexCmds.sf = LatexCmds.textsf = - makeTextBlock('\\textsf', 'span', 'class="mq-sans-serif mq-text-mode"'); - LatexCmds.tt = LatexCmds.texttt = - makeTextBlock('\\texttt', 'span', 'class="mq-monospace mq-text-mode"'); - LatexCmds.textsc = - makeTextBlock('\\textsc', 'span', 'style="font-variant:small-caps" class="mq-text-mode"'); - LatexCmds.uppercase = - makeTextBlock('\\uppercase', 'span', 'style="text-transform:uppercase" class="mq-text-mode"'); - LatexCmds.lowercase = - makeTextBlock('\\lowercase', 'span', 'style="text-transform:lowercase" class="mq-text-mode"'); - - - var RootMathCommand = P(MathCommand, function(_, super_) { - _.init = function(cursor) { - super_.init.call(this, '$'); - this.cursor = cursor; - }; - _.htmlTemplate = '<span class="mq-math-mode">&0</span>'; - _.createBlocks = function() { - super_.createBlocks.call(this); - - this.ends[L].cursor = this.cursor; - this.ends[L].write = function(cursor, ch, replacedFragment) { - if (ch !== '$') - MathBlock.prototype.write.call(this, cursor, ch, replacedFragment); - else if (this.isEmpty()) { - cursor.insRightOf(this.parent); - this.parent.deleteTowards(dir, cursor); - VanillaSymbol('\\$','$').createLeftOf(cursor.show()); - } - else if (!cursor[R]) - cursor.insRightOf(this.parent); - else if (!cursor[L]) - cursor.insLeftOf(this.parent); - else - MathBlock.prototype.write.call(this, cursor, ch, replacedFragment); - }; - }; - _.latex = function() { - return '$' + this.ends[L].latex() + '$'; - }; - }); - - var RootTextBlock = P(RootMathBlock, function(_, super_) { - _.keystroke = function(key) { - if (key === 'Spacebar' || key === 'Shift-Spacebar') return; - return super_.keystroke.apply(this, arguments); - }; - _.write = function(cursor, ch, replacedFragment) { - if (replacedFragment) replacedFragment.remove(); - if (ch === '$') - RootMathCommand(cursor).createLeftOf(cursor); - else { - var html; - if (ch === '<') html = '&lt;'; - else if (ch === '>') html = '&gt;'; - VanillaSymbol(ch, html).createLeftOf(cursor); - } - }; - }); - MathQuill.TextField = APIFnFor(P(EditableField, function(_) { - _.init = function(el) { - el.addClass('mq-editable-field mq-text-mode'); - this.initRootAndEvents(RootTextBlock(), el); - }; - _.latex = function(latex) { - if (arguments.length > 0) { - this.__controller.renderLatexText(latex); - if (this.__controller.blurred) this.__controller.cursor.hide().parent.blur(); - return this; - } - return this.__controller.exportLatex(); - }; - })); - /**************************************** - * Input box to type backslash commands - ***************************************/ - - var LatexCommandInput = - CharCmds['\\'] = P(MathCommand, function(_, super_) { - _.ctrlSeq = '\\'; - _.replaces = function(replacedFragment) { - this._replacedFragment = replacedFragment.disown(); - this.isEmpty = function() { return false; }; - }; - _.htmlTemplate = '<span class="mq-latex-command-input mq-non-leaf">\\<span>&0</span></span>'; - _.textTemplate = ['\\']; - _.createBlocks = function() { - super_.createBlocks.call(this); - this.ends[L].focus = function() { - this.parent.jQ.addClass('mq-hasCursor'); - if (this.isEmpty()) - this.parent.jQ.removeClass('mq-empty'); - - return this; - }; - this.ends[L].blur = function() { - this.parent.jQ.removeClass('mq-hasCursor'); - if (this.isEmpty()) - this.parent.jQ.addClass('mq-empty'); - - return this; - }; - this.ends[L].write = function(cursor, ch, replacedFragment) { - if (replacedFragment) replacedFragment.remove(); - if (this.parent.ends[L].latex().indexOf('matrix') == 0){ - if(/^matrix\dx\d$/.test(this.parent.ends[L].latex())){ - this.parent.renderCommand(cursor); - if (ch !== '\\' || !this.isEmpty()) this.parent.parent.write(cursor, ch); - } else { - VanillaSymbol(ch).createLeftOf(cursor); - } - return; - } - if (ch.match(/[a-z]/i)) VanillaSymbol(ch).createLeftOf(cursor); - else { - this.parent.renderCommand(cursor); - if (ch !== '\\' || !this.isEmpty()) this.parent.parent.write(cursor, ch); - } - }; - this.ends[L].keystroke = function(key, e, ctrlr) { - if (key === 'Tab' || key === 'Enter' || key === 'Spacebar') { - this.parent.renderCommand(ctrlr.cursor); - e.preventDefault(); - return; - } - return super_.keystroke.apply(this, arguments); - }; - }; - _.createLeftOf = function(cursor) { - super_.createLeftOf.call(this, cursor); - - if (this._replacedFragment) { - var el = this.jQ[0]; - this.jQ = - this._replacedFragment.jQ.addClass('mq-blur').bind( - 'mousedown mousemove', //FIXME: is monkey-patching the mousedown and mousemove handlers the right way to do this? - function(e) { - $(e.target = el).trigger(e); - return false; - } - ).insertBefore(this.jQ).add(this.jQ); - } - }; - _.latex = function() { - return '\\' + this.ends[L].latex() + ' '; - }; - _.renderCommand = function(cursor) { - this.jQ = this.jQ.last(); - this.remove(); - if (this[R]) { - cursor.insLeftOf(this[R]); - } else { - cursor.insAtRightEnd(this.parent); - } - - var latex = this.ends[L].latex(); - if (!latex) latex = ' '; - var cmd = LatexCmds[latex]; - if (cmd) { - cmd = cmd(latex); - if (this._replacedFragment) cmd.replaces(this._replacedFragment); - cmd.createLeftOf(cursor); - } else if (/matrix\dx\d/.test(latexCmd)) { - var p = latexCmd.substr(6).split('x'); - cmd = Matrix(p[0]|0||3, p[1]|0||3); - if (replacedFragment) cmd.replaces(replacedFragment); - cmd.createLeftOf(this); - } else { - cmd = TextBlock(); - cmd.replaces(latex); - cmd.createLeftOf(cursor); - cursor.insRightOf(cmd); - if (this._replacedFragment) - this._replacedFragment.remove(); - } - }; - }); - - /************************************ - * Symbols for Advanced Mathematics - ***********************************/ - - LatexCmds.notin = - LatexCmds.sim = - LatexCmds.cong = - LatexCmds.equiv = - LatexCmds.oplus = - LatexCmds.otimes = P(BinaryOperator, function(_, super_) { - _.init = function(latex) { - super_.init.call(this, '\\'+latex+' ', '&'+latex+';'); - }; - }); - - LatexCmds['\u2260'] = LatexCmds.ne = LatexCmds.neq = bind(BinaryOperator,'\\ne ','&ne;'); - - LatexCmds.ast = LatexCmds.star = LatexCmds.loast = LatexCmds.lowast = - bind(BinaryOperator,'\\ast ','&lowast;'); - //case 'there4 = // a special exception for this one, perhaps? - LatexCmds.therefor = LatexCmds.therefore = - bind(BinaryOperator,'\\therefore ','&there4;'); - - LatexCmds.cuz = // l33t - LatexCmds.because = bind(BinaryOperator,'\\because ','&#8757;'); - - LatexCmds.prop = LatexCmds.propto = bind(BinaryOperator,'\\propto ','&prop;'); - - LatexCmds['\u2248'] = LatexCmds.asymp = LatexCmds.approx = bind(BinaryOperator,'\\approx ','&asymp;'); - - LatexCmds.isin = LatexCmds['in'] = bind(BinaryOperator,'\\in ','&isin;'); - - LatexCmds.ni = LatexCmds.contains = bind(BinaryOperator,'\\ni ','&ni;'); - - LatexCmds.notni = LatexCmds.niton = LatexCmds.notcontains = LatexCmds.doesnotcontain = - bind(BinaryOperator,'\\not\\ni ','&#8716;'); - - LatexCmds.sub = LatexCmds.subset = bind(BinaryOperator,'\\subset ','&sub;'); - - LatexCmds.sup = LatexCmds.supset = LatexCmds.superset = - bind(BinaryOperator,'\\supset ','&sup;'); - - LatexCmds.nsub = LatexCmds.notsub = - LatexCmds.nsubset = LatexCmds.notsubset = - bind(BinaryOperator,'\\not\\subset ','&#8836;'); - - LatexCmds.nsup = LatexCmds.notsup = - LatexCmds.nsupset = LatexCmds.notsupset = - LatexCmds.nsuperset = LatexCmds.notsuperset = - bind(BinaryOperator,'\\not\\supset ','&#8837;'); - - LatexCmds.sube = LatexCmds.subeq = LatexCmds.subsete = LatexCmds.subseteq = - bind(BinaryOperator,'\\subseteq ','&sube;'); - - LatexCmds.supe = LatexCmds.supeq = - LatexCmds.supsete = LatexCmds.supseteq = - LatexCmds.supersete = LatexCmds.superseteq = - bind(BinaryOperator,'\\supseteq ','&supe;'); - - LatexCmds.nsube = LatexCmds.nsubeq = - LatexCmds.notsube = LatexCmds.notsubeq = - LatexCmds.nsubsete = LatexCmds.nsubseteq = - LatexCmds.notsubsete = LatexCmds.notsubseteq = - bind(BinaryOperator,'\\not\\subseteq ','&#8840;'); - - LatexCmds.nsupe = LatexCmds.nsupeq = - LatexCmds.notsupe = LatexCmds.notsupeq = - LatexCmds.nsupsete = LatexCmds.nsupseteq = - LatexCmds.notsupsete = LatexCmds.notsupseteq = - LatexCmds.nsupersete = LatexCmds.nsuperseteq = - LatexCmds.notsupersete = LatexCmds.notsuperseteq = - bind(BinaryOperator,'\\not\\supseteq ','&#8841;'); - - -//the canonical sets of numbers - LatexCmds.N = LatexCmds.naturals = LatexCmds.Naturals = - bind(VanillaSymbol,'\\mathbb{N}','&#8469;'); - - LatexCmds.P = - LatexCmds.primes = LatexCmds.Primes = - LatexCmds.projective = LatexCmds.Projective = - LatexCmds.probability = LatexCmds.Probability = - bind(VanillaSymbol,'\\mathbb{P}','&#8473;'); - - LatexCmds.Z = LatexCmds.integers = LatexCmds.Integers = - bind(VanillaSymbol,'\\mathbb{Z}','&#8484;'); - - LatexCmds.Q = LatexCmds.rationals = LatexCmds.Rationals = - bind(VanillaSymbol,'\\mathbb{Q}','&#8474;'); - - LatexCmds.R = LatexCmds.reals = LatexCmds.Reals = - bind(VanillaSymbol,'\\mathbb{R}','&#8477;'); - - LatexCmds.C = - LatexCmds.complex = LatexCmds.Complex = - LatexCmds.complexes = LatexCmds.Complexes = - LatexCmds.complexplane = LatexCmds.Complexplane = LatexCmds.ComplexPlane = - bind(VanillaSymbol,'\\mathbb{C}','&#8450;'); - - LatexCmds.H = LatexCmds.Hamiltonian = LatexCmds.quaternions = LatexCmds.Quaternions = - bind(VanillaSymbol,'\\mathbb{H}','&#8461;'); - -//spacing - LatexCmds.quad = LatexCmds.emsp = bind(VanillaSymbol,'\\quad ',' '); - LatexCmds.qquad = bind(VanillaSymbol,'\\qquad ',' '); - /* spacing special characters, gonna have to implement this in LatexCommandInput::onText somehow - case ',': - return VanillaSymbol('\\, ',' '); - case ':': - return VanillaSymbol('\\: ',' '); - case ';': - return VanillaSymbol('\\; ',' '); - case '!': - return Symbol('\\! ','<span style="margin-right:-.2em"></span>'); - */ - -//binary operators - LatexCmds.diamond = bind(VanillaSymbol, '\\diamond ', '&#9671;'); - LatexCmds.bigtriangleup = bind(VanillaSymbol, '\\bigtriangleup ', '&#9651;'); - LatexCmds.ominus = bind(VanillaSymbol, '\\ominus ', '&#8854;'); - LatexCmds.uplus = bind(VanillaSymbol, '\\uplus ', '&#8846;'); - LatexCmds.bigtriangledown = bind(VanillaSymbol, '\\bigtriangledown ', '&#9661;'); - LatexCmds.sqcap = bind(VanillaSymbol, '\\sqcap ', '&#8851;'); - LatexCmds.triangleleft = bind(VanillaSymbol, '\\triangleleft ', '&#8882;'); - LatexCmds.sqcup = bind(VanillaSymbol, '\\sqcup ', '&#8852;'); - LatexCmds.triangleright = bind(VanillaSymbol, '\\triangleright ', '&#8883;'); - LatexCmds.odot = bind(VanillaSymbol, '\\odot ', '&#8857;'); - LatexCmds.bigcirc = bind(VanillaSymbol, '\\bigcirc ', '&#9711;'); - LatexCmds.dagger = bind(VanillaSymbol, '\\dagger ', '&#0134;'); - LatexCmds.ddagger = bind(VanillaSymbol, '\\ddagger ', '&#135;'); - LatexCmds.wr = bind(VanillaSymbol, '\\wr ', '&#8768;'); - LatexCmds.amalg = bind(VanillaSymbol, '\\amalg ', '&#8720;'); - -//relationship symbols - LatexCmds.models = bind(VanillaSymbol, '\\models ', '&#8872;'); - LatexCmds.prec = bind(VanillaSymbol, '\\prec ', '&#8826;'); - LatexCmds.succ = bind(VanillaSymbol, '\\succ ', '&#8827;'); - LatexCmds.preceq = bind(VanillaSymbol, '\\preceq ', '&#8828;'); - LatexCmds.succeq = bind(VanillaSymbol, '\\succeq ', '&#8829;'); - LatexCmds.simeq = bind(VanillaSymbol, '\\simeq ', '&#8771;'); - LatexCmds.mid = bind(VanillaSymbol, '\\mid ', '&#8739;'); - LatexCmds.ll = bind(VanillaSymbol, '\\ll ', '&#8810;'); - LatexCmds.gg = bind(VanillaSymbol, '\\gg ', '&#8811;'); - LatexCmds.parallel = bind(VanillaSymbol, '\\parallel ', '&#8741;'); - LatexCmds.bowtie = bind(VanillaSymbol, '\\bowtie ', '&#8904;'); - LatexCmds.sqsubset = bind(VanillaSymbol, '\\sqsubset ', '&#8847;'); - LatexCmds.sqsupset = bind(VanillaSymbol, '\\sqsupset ', '&#8848;'); - LatexCmds.smile = bind(VanillaSymbol, '\\smile ', '&#8995;'); - LatexCmds.sqsubseteq = bind(VanillaSymbol, '\\sqsubseteq ', '&#8849;'); - LatexCmds.sqsupseteq = bind(VanillaSymbol, '\\sqsupseteq ', '&#8850;'); - LatexCmds.doteq = bind(VanillaSymbol, '\\doteq ', '&#8784;'); - LatexCmds.frown = bind(VanillaSymbol, '\\frown ', '&#8994;'); - LatexCmds.vdash = bind(VanillaSymbol, '\\vdash ', '&#8870;'); - LatexCmds.dashv = bind(VanillaSymbol, '\\dashv ', '&#8867;'); - -//arrows - LatexCmds.longleftarrow = bind(VanillaSymbol, '\\longleftarrow ', '&#8592;'); - LatexCmds.longrightarrow = bind(VanillaSymbol, '\\longrightarrow ', '&#8594;'); - LatexCmds.Longleftarrow = bind(VanillaSymbol, '\\Longleftarrow ', '&#8656;'); - LatexCmds.Longrightarrow = bind(VanillaSymbol, '\\Longrightarrow ', '&#8658;'); - LatexCmds.longleftrightarrow = bind(VanillaSymbol, '\\longleftrightarrow ', '&#8596;'); - LatexCmds.updownarrow = bind(VanillaSymbol, '\\updownarrow ', '&#8597;'); - LatexCmds.Longleftrightarrow = bind(VanillaSymbol, '\\Longleftrightarrow ', '&#8660;'); - LatexCmds.Updownarrow = bind(VanillaSymbol, '\\Updownarrow ', '&#8661;'); - LatexCmds.mapsto = bind(VanillaSymbol, '\\mapsto ', '&#8614;'); - LatexCmds.nearrow = bind(VanillaSymbol, '\\nearrow ', '&#8599;'); - LatexCmds.hookleftarrow = bind(VanillaSymbol, '\\hookleftarrow ', '&#8617;'); - LatexCmds.hookrightarrow = bind(VanillaSymbol, '\\hookrightarrow ', '&#8618;'); - LatexCmds.searrow = bind(VanillaSymbol, '\\searrow ', '&#8600;'); - LatexCmds.leftharpoonup = bind(VanillaSymbol, '\\leftharpoonup ', '&#8636;'); - LatexCmds.rightharpoonup = bind(VanillaSymbol, '\\rightharpoonup ', '&#8640;'); - LatexCmds.swarrow = bind(VanillaSymbol, '\\swarrow ', '&#8601;'); - LatexCmds.leftharpoondown = bind(VanillaSymbol, '\\leftharpoondown ', '&#8637;'); - LatexCmds.rightharpoondown = bind(VanillaSymbol, '\\rightharpoondown ', '&#8641;'); - LatexCmds.nwarrow = bind(VanillaSymbol, '\\nwarrow ', '&#8598;'); - -//Misc - LatexCmds.ldots = bind(VanillaSymbol, '\\ldots ', '&#8230;'); - LatexCmds.cdots = bind(VanillaSymbol, '\\cdots ', '&#8943;'); - LatexCmds.vdots = bind(VanillaSymbol, '\\vdots ', '&#8942;'); - LatexCmds.ddots = bind(VanillaSymbol, '\\ddots ', '&#8944;'); - LatexCmds.surd = bind(VanillaSymbol, '\\surd ', '&#8730;'); - LatexCmds.triangle = bind(VanillaSymbol, '\\triangle ', '&#9653;'); - LatexCmds.ell = bind(VanillaSymbol, '\\ell ', '&#8467;'); - LatexCmds.top = bind(VanillaSymbol, '\\top ', '&#8868;'); - LatexCmds.flat = bind(VanillaSymbol, '\\flat ', '&#9837;'); - LatexCmds.natural = bind(VanillaSymbol, '\\natural ', '&#9838;'); - LatexCmds.sharp = bind(VanillaSymbol, '\\sharp ', '&#9839;'); - LatexCmds.wp = bind(VanillaSymbol, '\\wp ', '&#8472;'); - LatexCmds.bot = bind(VanillaSymbol, '\\bot ', '&#8869;'); - LatexCmds.clubsuit = bind(VanillaSymbol, '\\clubsuit ', '&#9827;'); - LatexCmds.diamondsuit = bind(VanillaSymbol, '\\diamondsuit ', '&#9826;'); - LatexCmds.heartsuit = bind(VanillaSymbol, '\\heartsuit ', '&#9825;'); - LatexCmds.spadesuit = bind(VanillaSymbol, '\\spadesuit ', '&#9824;'); - -//variable-sized - LatexCmds.oint = bind(VanillaSymbol, '\\oint ', '&#8750;'); - LatexCmds.bigcap = bind(VanillaSymbol, '\\bigcap ', '&#8745;'); - LatexCmds.bigcup = bind(VanillaSymbol, '\\bigcup ', '&#8746;'); - LatexCmds.bigsqcup = bind(VanillaSymbol, '\\bigsqcup ', '&#8852;'); - LatexCmds.bigvee = bind(VanillaSymbol, '\\bigvee ', '&#8744;'); - LatexCmds.bigwedge = bind(VanillaSymbol, '\\bigwedge ', '&#8743;'); - LatexCmds.bigodot = bind(VanillaSymbol, '\\bigodot ', '&#8857;'); - LatexCmds.bigotimes = bind(VanillaSymbol, '\\bigotimes ', '&#8855;'); - LatexCmds.bigoplus = bind(VanillaSymbol, '\\bigoplus ', '&#8853;'); - LatexCmds.biguplus = bind(VanillaSymbol, '\\biguplus ', '&#8846;'); - -//delimiters - LatexCmds.lfloor = bind(VanillaSymbol, '\\lfloor ', '&#8970;'); - LatexCmds.rfloor = bind(VanillaSymbol, '\\rfloor ', '&#8971;'); - LatexCmds.lceil = bind(VanillaSymbol, '\\lceil ', '&#8968;'); - LatexCmds.rceil = bind(VanillaSymbol, '\\rceil ', '&#8969;'); - LatexCmds.opencurlybrace = LatexCmds.lbrace = bind(VanillaSymbol, '\\lbrace ', '{'); - LatexCmds.closecurlybrace = LatexCmds.rbrace = bind(VanillaSymbol, '\\rbrace ', '}'); - -//various symbols - - LatexCmds['\u222b'] = - LatexCmds['int'] = - LatexCmds.integral = bind(Symbol,'\\int ','<big>&int;</big>'); - - LatexCmds.caret = bind(VanillaSymbol,'\\text{^}','^'); - LatexCmds.underscore = bind(VanillaSymbol,'\\_','_'); - - LatexCmds.slash = bind(VanillaSymbol, '/'); - LatexCmds.vert = bind(VanillaSymbol,'|'); - LatexCmds.perp = LatexCmds.perpendicular = bind(VanillaSymbol,'\\perp ','&perp;'); - LatexCmds.nabla = LatexCmds.del = bind(VanillaSymbol,'\\nabla ','&nabla;'); - LatexCmds.hbar = bind(VanillaSymbol,'\\hbar ','&#8463;'); - - LatexCmds.AA = LatexCmds.Angstrom = LatexCmds.angstrom = - bind(VanillaSymbol,'\\text\\AA ','&#8491;'); - - LatexCmds.ring = LatexCmds.circ = LatexCmds.circle = - bind(VanillaSymbol,'\\circ ','&#8728;'); - - LatexCmds.bull = LatexCmds.bullet = bind(VanillaSymbol,'\\bullet ','&bull;'); - - LatexCmds.setminus = LatexCmds.smallsetminus = - bind(VanillaSymbol,'\\setminus ','&#8726;'); - - LatexCmds.not = //bind(Symbol,'\\not ','<span class="not">/</span>'); - LatexCmds['\u00ac'] = LatexCmds.neg = bind(VanillaSymbol,'\\neg ','&not;'); - - LatexCmds['\u2026'] = LatexCmds.dots = LatexCmds.ellip = LatexCmds.hellip = - LatexCmds.ellipsis = LatexCmds.hellipsis = - bind(VanillaSymbol,'\\dots ','&hellip;'); - - LatexCmds.converges = - LatexCmds.darr = LatexCmds.dnarr = LatexCmds.dnarrow = LatexCmds.downarrow = - bind(VanillaSymbol,'\\downarrow ','&darr;'); - - LatexCmds.dArr = LatexCmds.dnArr = LatexCmds.dnArrow = LatexCmds.Downarrow = - bind(VanillaSymbol,'\\Downarrow ','&dArr;'); - - LatexCmds.diverges = LatexCmds.uarr = LatexCmds.uparrow = - bind(VanillaSymbol,'\\uparrow ','&uarr;'); - - LatexCmds.uArr = LatexCmds.Uparrow = bind(VanillaSymbol,'\\Uparrow ','&uArr;'); - - LatexCmds.to = bind(BinaryOperator,'\\to ','&rarr;'); - - LatexCmds.rarr = LatexCmds.rightarrow = bind(VanillaSymbol,'\\rightarrow ','&rarr;'); - - LatexCmds.implies = bind(BinaryOperator,'\\Rightarrow ','&rArr;'); - - LatexCmds.rArr = LatexCmds.Rightarrow = bind(VanillaSymbol,'\\Rightarrow ','&rArr;'); - - LatexCmds.gets = bind(BinaryOperator,'\\gets ','&larr;'); - - LatexCmds.larr = LatexCmds.leftarrow = bind(VanillaSymbol,'\\leftarrow ','&larr;'); - - LatexCmds.impliedby = bind(BinaryOperator,'\\Leftarrow ','&lArr;'); - - LatexCmds.lArr = LatexCmds.Leftarrow = bind(VanillaSymbol,'\\Leftarrow ','&lArr;'); - - LatexCmds.harr = LatexCmds.lrarr = LatexCmds.leftrightarrow = - bind(VanillaSymbol,'\\leftrightarrow ','&harr;'); - - LatexCmds.iff = bind(BinaryOperator,'\\Leftrightarrow ','&hArr;'); - - LatexCmds.hArr = LatexCmds.lrArr = LatexCmds.Leftrightarrow = - bind(VanillaSymbol,'\\Leftrightarrow ','&hArr;'); - - LatexCmds.Re = LatexCmds.Real = LatexCmds.real = bind(VanillaSymbol,'\\Re ','&real;'); - - LatexCmds.Im = LatexCmds.imag = - LatexCmds.image = LatexCmds.imagin = LatexCmds.imaginary = LatexCmds.Imaginary = - bind(VanillaSymbol,'\\Im ','&image;'); - - LatexCmds.part = LatexCmds.partial = bind(VanillaSymbol,'\\partial ','&part;'); - - LatexCmds.infty = LatexCmds.infin = LatexCmds.infinity = - bind(VanillaSymbol,'\\infty ','&infin;'); - - LatexCmds.alef = LatexCmds.alefsym = LatexCmds.aleph = LatexCmds.alephsym = - bind(VanillaSymbol,'\\aleph ','&alefsym;'); - - LatexCmds.xist = //LOL - LatexCmds.xists = LatexCmds.exist = LatexCmds.exists = - bind(VanillaSymbol,'\\exists ','&exist;'); - - LatexCmds.and = LatexCmds.land = LatexCmds.wedge = - bind(VanillaSymbol,'\\wedge ','&and;'); - - LatexCmds.or = LatexCmds.lor = LatexCmds.vee = bind(VanillaSymbol,'\\vee ','&or;'); - - LatexCmds.o = LatexCmds.O = - LatexCmds.empty = LatexCmds.emptyset = - LatexCmds.oslash = LatexCmds.Oslash = - LatexCmds.nothing = LatexCmds.varnothing = - bind(BinaryOperator,'\\varnothing ','&empty;'); - - LatexCmds.cup = LatexCmds.union = bind(BinaryOperator,'\\cup ','&cup;'); - - LatexCmds.cap = LatexCmds.intersect = LatexCmds.intersection = - bind(BinaryOperator,'\\cap ','&cap;'); - - LatexCmds.deg = LatexCmds.degree = bind(VanillaSymbol,'^\\circ ','&deg;'); - - LatexCmds.ang = LatexCmds.angle = bind(VanillaSymbol,'\\angle ','&ang;'); - /********************************* - * Symbols for Basic Mathematics - ********************************/ - - var Variable = P(Symbol, function(_, super_) { - _.init = function(ch, html) { - super_.init.call(this, ch, '<var>'+(html || ch)+'</var>'); - }; - _.text = function(opts) { - var text = this.ctrlSeq; - if (this[L] && !(this[L] instanceof Variable) - && !(this[L] instanceof BinaryOperator) - && !(this[L].ctrlSeq === ',')) - text = '*' + text; - if (this[L] && !(this[L] instanceof BinaryOperator) - && (this.ctrlSeq[0] == '\\')) - text = '*' + text; - var auto_complete_command = false; - for (var l = this[L]; l instanceof Letter; l = l[L]) if(l.ctrlSeq[0] == '\\') { auto_complete_command = true; break;} - if (this[R] && !(this[R] instanceof BinaryOperator) - && !(this[R] instanceof Variable) - && !(this[R].ctrlSeq === '^') - && !(this[R].ctrlSeq === ',') - && !(this[R].ctrlSeq === '_') - && !auto_complete_command) - 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) { - var autoCmds = cursor.options.autoCommands, maxLength = autoCmds._maxLength; - if (maxLength > 0) { - // want longest possible autocommand, so join together longest - // sequence of letters - var str = this.letter, l = cursor[L], i = 1; - while (l instanceof 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 = 2, l = cursor[L]; i < str.length; i += 1, l = l[L]); - Fragment(l, cursor[L]).remove(); - cursor[L] = l[L]; - return LatexCmds[str](str).createLeftOf(cursor); - } - if(cursor.options.autoCommandFullWordOnly) break; - str = str.slice(1); - } - } - super_.createLeftOf.apply(this, arguments); - }; - _.italicize = function(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(opts.autoOnBrackets) return; - 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'); - 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 (opts.autoAllFunctions || 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 (nonOperatorSymbol(first[L])) first.jQ.addClass('mq-first'); - if (nonOperatorSymbol(last[R])) last.jQ.addClass('mq-last'); - - i += len - 1; - first = last; - continue outer; - } - } - } - }; - function nonOperatorSymbol(node) { - return node instanceof Symbol && !(node instanceof BinaryOperator); - } - }); - var BuiltInOpNames = {}; // http://latex.wikia.com/wiki/List_of_LaTeX_symbols#Named_operators:_sin.2C_cos.2C_etc. - // except for over/under line/arrow \lim variants like \varlimsup - var TwoWordOpNames = { limsup: 1, liminf: 1, projlim: 1, injlim: 1 }; - (function() { - var autoOps = Options.p.autoOperatorNames = { _maxLength: 9 }; - 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]] = autoOps[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) { - autoOps[autoTrigs[i]] = - autoOps['arc'+autoTrigs[i]] = - autoOps[autoTrigs[i]+'h'] = - autoOps['ar'+autoTrigs[i]+'h'] = - autoOps['arc'+autoTrigs[i]+'h'] = 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 BuiltInOpNames) if (BuiltInOpNames.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-florin">&fnof;</var>'); - }; - _.italicize = function(bool) { - this.jQ.html(bool ? '&fnof;' : 'f').toggleClass('mq-florin', bool); - return super_.italicize.apply(this, arguments); - }; - }); - -// VanillaSymbol's - LatexCmds[' '] = LatexCmds.space = bind(VanillaSymbol, '\\ ', ' '); - - LatexCmds["'"] = LatexCmds.prime = bind(VanillaSymbol, "'", '&prime;'); - - 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, '\\&', '&amp;'); - 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 ','&#981;'); - - LatexCmds.phiv = //Elsevier and 9573-13 - LatexCmds.varphi = //AMS and LaTeX - bind(Variable,'\\varphi ','&phi;'); - - LatexCmds.epsilon = //W3C or Unicode? - bind(Variable,'\\epsilon ','&#1013;'); - - LatexCmds.epsiv = //Elsevier and 9573-13 - LatexCmds.varepsilon = //AMS and LaTeX - bind(Variable,'\\varepsilon ','&epsilon;'); - - LatexCmds.piv = //W3C/Unicode and Elsevier and 9573-13 - LatexCmds.varpi = //AMS and LaTeX - bind(Variable,'\\varpi ','&piv;'); - - LatexCmds.sigmaf = //W3C/Unicode - LatexCmds.sigmav = //Elsevier - LatexCmds.varsigma = //LaTeX - bind(Variable,'\\varsigma ','&sigmaf;'); - - LatexCmds.thetav = //Elsevier and 9573-13 - LatexCmds.vartheta = //AMS and LaTeX - LatexCmds.thetasym = //W3C/Unicode - bind(Variable,'\\vartheta ','&thetasym;'); - - LatexCmds.upsilon = //AMS and LaTeX and W3C/Unicode - LatexCmds.upsi = //Elsevier and 9573-13 - bind(Variable,'\\upsilon ','&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 ','&#989;'); - - LatexCmds.kappav = //Elsevier - LatexCmds.varkappa = //AMS and LaTeX - bind(Variable,'\\varkappa ','&#1008;'); - - LatexCmds.rhov = //Elsevier and 9573-13 - LatexCmds.varrho = //AMS and LaTeX - bind(Variable,'\\varrho ','&#1009;'); - -//Greek constants, look best in non-italicized Times New Roman - LatexCmds.pi = LatexCmds['\u03c0'] = bind(NonSymbolaSymbol,'\\pi ','&pi;'); - LatexCmds.lambda = bind(NonSymbolaSymbol,'\\lambda ','&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">&upsih;</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: Windows-1252 is actually 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['\u00b9'] = bind(LatexFragment, '^1'); - LatexCmds['\u00b2'] = bind(LatexFragment, '^2'); - LatexCmds['\u00b3'] = bind(LatexFragment, '^3'); - LatexCmds['\u00bc'] = bind(LatexFragment, '\\frac14'); - LatexCmds['\u00bd'] = bind(LatexFragment, '\\frac12'); - LatexCmds['\u00be'] = bind(LatexFragment, '\\frac34'); - - var PlusMinus = P(BinaryOperator, function(_) { - _.init = VanillaSymbol.prototype.init; - - _.contactWeld = _.siblingCreated = _.siblingDeleted = function(opts, dir) { - if (dir === R) return; // ignore if sibling only changed on the right - this.jQ[0].className = - (!this[L] || this[L] instanceof BinaryOperator ? '' : 'mq-binary-operator'); - return this; - }; - }); - - LatexCmds['+'] = bind(PlusMinus, '+', '+'); -//yes, these are different dashes, I think one is an en dash and the other is a hyphen - LatexCmds['\u2013'] = LatexCmds['-'] = bind(PlusMinus, '-', '&minus;'); - LatexCmds['\u00b1'] = LatexCmds.pm = LatexCmds.plusmn = LatexCmds.plusminus = - bind(PlusMinus,'\\pm ','&plusmn;'); - LatexCmds.mp = LatexCmds.mnplus = LatexCmds.minusplus = - bind(PlusMinus,'\\mp ','&#8723;'); - - CharCmds['*'] = LatexCmds.sdot = LatexCmds.cdot = - bind(BinaryOperator, '\\cdot ', '&middot;', '*'); -//semantically should be &sdot;, but &middot; 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); - return; - } - super_.deleteTowards.apply(this, arguments); - }; - }); - - var less = { ctrlSeq: '\\le ', html: '&le;', text: '\u2264', - ctrlSeqStrict: '<', htmlStrict: '&lt;', textStrict: '<' }; - var greater = { ctrlSeq: '\\ge ', html: '&ge;', text: '\u2265', - ctrlSeqStrict: '>', htmlStrict: '&gt;', textStrict: '>' }; - - LatexCmds['<'] = LatexCmds.lt = bind(Inequality, less, true); - LatexCmds['>'] = LatexCmds.gt = bind(Inequality, greater, true); - LatexCmds['\u2264'] = LatexCmds.le = LatexCmds.leq = bind(Inequality, less, false); - LatexCmds['\u2265'] = 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); - return; - } - super_.createLeftOf.apply(this, arguments); - }; - }); - LatexCmds['='] = Equality; - - LatexCmds.times = bind(BinaryOperator, '\\times ', '&times;', '[x]'); - - LatexCmds['\u00f7'] = LatexCmds.div = LatexCmds.divide = LatexCmds.divides = - bind(BinaryOperator,'\\div ','&divide;', '[/]'); - /*************************** - * Commands and Operators. - **************************/ - - var scale, // = function(jQ, x, y) { ... } -//will use a CSS 2D transform to scale the jQuery-wrapped HTML elements, -//or the filter matrix transform fallback for IE 5.5-8, or gracefully degrade to -//increasing the fontSize to match the vertical Y scaling factor. - -//ideas from http://github.com/louisremi/jquery.transform.js -//see also http://msdn.microsoft.com/en-us/library/ms533014(v=vs.85).aspx - - forceIERedraw = noop, - div = document.createElement('div'), - div_style = div.style, - transformPropNames = { - transform:1, - WebkitTransform:1, - MozTransform:1, - OTransform:1, - msTransform:1 - }, - transformPropName; - - for (var prop in transformPropNames) { - if (prop in div_style) { - transformPropName = prop; - break; - } - } - - if (transformPropName) { - scale = function(jQ, x, y) { - jQ.css(transformPropName, 'scale('+x+','+y+')'); - }; - } - else if ('filter' in div_style) { //IE 6, 7, & 8 fallback, see https://github.com/laughinghan/mathquill/wiki/Transforms - forceIERedraw = function(el){ el.className = el.className; }; - scale = function(jQ, x, y) { //NOTE: assumes y > x - x /= (1+(y-1)/2); - jQ.css('fontSize', y + 'em'); - if (!jQ.hasClass('mq-matrixed-container')) { - jQ.addClass('mq-matrixed-container') - .wrapInner('<span class="mq-matrixed"></span>'); - } - var innerjQ = jQ.children() - .css('filter', 'progid:DXImageTransform.Microsoft' - + '.Matrix(M11=' + x + ",SizingMethod='auto expand')" - ); - function calculateMarginRight() { - jQ.css('marginRight', (innerjQ.width()-1)*(x-1)/x + 'px'); - } - calculateMarginRight(); - var intervalId = setInterval(calculateMarginRight); - $(window).load(function() { - clearTimeout(intervalId); - calculateMarginRight(); - }); - }; - } - else { - scale = function(jQ, x, y) { - jQ.css('fontSize', y + 'em'); - }; - } - - var Style = P(MathCommand, function(_, super_) { - _.init = function(ctrlSeq, tagName, attrs) { - super_.init.call(this, ctrlSeq, '<'+tagName+' '+attrs+'>&0</'+tagName+'>'); - }; - }); - -//fonts - LatexCmds.mathrm = bind(Style, '\\mathrm', 'span', 'class="mq-roman mq-font"'); - LatexCmds.mathit = bind(Style, '\\mathit', 'i', 'class="mq-font"'); - LatexCmds.mathbf = bind(Style, '\\mathbf', 'b', 'class="mq-font"'); - LatexCmds.mathsf = bind(Style, '\\mathsf', 'span', 'class="mq-sans-serif mq-font"'); - LatexCmds.mathtt = bind(Style, '\\mathtt', 'span', 'class="mq-monospace mq-font"'); -//text-decoration - LatexCmds.underline = bind(Style, '\\underline', 'span', 'class="mq-non-leaf mq-underline"'); - LatexCmds.overline = LatexCmds.bar = bind(Style, '\\overline', 'span', 'class="mq-non-leaf mq-overline"'); - -// `\textcolor{color}{math}` will apply a color to the given math content, where -// `color` is any valid CSS Color Value (see [SitePoint docs][] (recommended), -// [Mozilla docs][], or [W3C spec][]). -// -// [SitePoint docs]: http://reference.sitepoint.com/css/colorvalues -// [Mozilla docs]: https://developer.mozilla.org/en-US/docs/CSS/color_value#Values -// [W3C spec]: http://dev.w3.org/csswg/css3-color/#colorunits - var TextColor = LatexCmds.textcolor = P(MathCommand, function(_, super_) { - _.setColor = function(color) { - this.color = color; - this.htmlTemplate = - '<span class="mq-textcolor" style="color:' + color + '">&0</span>'; - }; - _.latex = function() { - return '\\textcolor{' + this.color + '}{' + this.blocks[0].latex() + '}'; - }; - _.parser = function() { - var self = this; - var optWhitespace = Parser.optWhitespace; - var string = Parser.string; - var regex = Parser.regex; - - return optWhitespace - .then(string('{')) - .then(regex(/^[#\w\s.,()%-]*/)) - .skip(string('}')) - .then(function(color) { - self.setColor(color); - return super_.parser.call(self); - }) - ; - }; - }); - -// Very similar to the \textcolor command, but will add the given CSS class. -// Usage: \class{classname}{math} -// Note regex that whitelists valid CSS classname characters: -// https://github.com/mathquill/mathquill/pull/191#discussion_r4327442 - var Class = LatexCmds['class'] = P(MathCommand, function(_, super_) { - _.parser = function() { - var self = this, string = Parser.string, regex = Parser.regex; - return Parser.optWhitespace - .then(string('{')) - .then(regex(/^[-\w\s\\\xA0-\xFF]*/)) - .skip(string('}')) - .then(function(cls) { - self.htmlTemplate = '<span class="mq-class '+cls+'">&0</span>'; - return super_.parser.call(self); - }) - ; - }; - }); - - var SupSub = P(MathCommand, function(_, super_) { - _.ctrlSeq = '_{...}^{...}'; - _.createLeftOf = function(cursor) { - if (!cursor[L] && cursor.options.supSubsRequireOperand) return; - return super_.createLeftOf.apply(this, arguments); - }; - _.contactWeld = function(cursor) { - // Look on either side for a SupSub, if one is found compare my - // .sub, .sup with its .sub, .sup. If I have one that it doesn't, - // then call .addBlock() on it with my block; if I have one that - // it also has, then insert my block's children into its block, - // unless my block has none, in which case insert the cursor into - // its block (and not mine, I'm about to remove myself) in the case - // I was just typed. - // TODO: simplify - - // equiv. to [L, R].forEach(function(dir) { ... }); - for (var dir = L; dir; dir = (dir === L ? R : false)) { - if (this[dir] instanceof SupSub) { - // equiv. to 'sub sup'.split(' ').forEach(function(supsub) { ... }); - for (var supsub = 'sub'; supsub; supsub = (supsub === 'sub' ? 'sup' : false)) { - var src = this[supsub], dest = this[dir][supsub]; - if (!src) continue; - if (!dest) this[dir].addBlock(src.disown()); - else if (!src.isEmpty()) { // ins src children at -dir end of dest - src.jQ.children().insAtDirEnd(-dir, dest.jQ); - var children = src.children().disown(); - var pt = Point(dest, children.ends[R], dest.ends[L]); - if (dir === L) children.adopt(dest, dest.ends[R], 0); - else children.adopt(dest, 0, dest.ends[L]); - } - else var pt = Point(dest, 0, dest.ends[L]); - this.placeCursor = (function(dest, src) { // TODO: don't monkey-patch - return function(cursor) { cursor.insAtDirEnd(-dir, dest || src); }; - }(dest, src)); - } - this.remove(); - if (cursor && cursor[L] === this) { - if (dir === R && pt) { - pt[L] ? cursor.insRightOf(pt[L]) : cursor.insAtLeftEnd(pt.parent); - } - else cursor.insRightOf(this[dir]); - } - break; - } - } - this.respace(); - }; - Options.p.charsThatBreakOutOfSupSub = ''; - _.finalizeTree = function() { - var supsub = this.supsub; - this.ends[L].write = function(cursor, ch) { - if (cursor.options.charsThatBreakOutOfSupSub.indexOf(ch) > -1) { - cursor.insRightOf(this.parent); - } - if ((supsub == 'sub') && cursor.options.noOperatorsInSubscript && !RegExp(/[A-Za-z0-9]/).test(ch)) { - cursor.insRightOf(this.parent); - } - MathBlock.p.write.apply(this, arguments); - }; - }; - _.latex = function() { - function latex(prefix, block) { - var l = block && block.latex(); - return block ? prefix + (l.length === 1 ? l : '{' + (l || ' ') + '}') : ''; - } - return latex('_', this.sub) + latex('^', this.sup); - }; - _.text = function(opts) { - //subscript first - var tex = ''; - if(this.sub) { - if(opts.noOperatorsInSubscript) { - // If this flag is enabled, subscripts should create variable names like 'r_outer', not 'r_(outer)' - tex += '_' + (this.sub && this.sub.ends[L] === this.sub.ends[R] ? - this.sub.ends[L].text(opts) : - this.sub.foldChildren('', function (text, child) { - return text + child.text(opts); - })); - } else { - tex += '_' + (this.sub && this.sub.ends[L] === this.sub.ends[R] ? - this.sub.ends[L].text(opts) : - '(' + this.sub.foldChildren('', function (text, child) { - return text + child.text(opts); - }) - + ')'); - } - } - if(this.sup) { - tex += '^' + (this.sup && this.sup.ends[L] === this.sup.ends[R] ? - this.sup.ends[L].text(opts) : - '(' + this.sup.foldChildren('', function (text, child) { - return text + child.text(opts); - }) - + ')'); - } - return tex; - }; - _.respace = _.siblingCreated = _.siblingDeleted = function(opts, dir) { - if (dir === R) return; // ignore if sibling only changed on the right - this.jQ.toggleClass('mq-limit', this[L].ctrlSeq === '\\int '); - }; - _.addBlock = function(block) { - if (this.supsub === 'sub') { - this.sup = this.upInto = this.sub.upOutOf = block; - block.adopt(this, this.sub, 0).downOutOf = this.sub; - block.jQ = $('<span class="mq-sup"/>').append(block.jQ.children()) - .attr(mqBlockId, block.id).prependTo(this.jQ); - } - else { - this.sub = this.downInto = this.sup.downOutOf = block; - block.adopt(this, 0, this.sup).upOutOf = this.sup; - block.jQ = $('<span class="mq-sub"></span>').append(block.jQ.children()) - .attr(mqBlockId, block.id).appendTo(this.jQ.removeClass('mq-sup-only')); - this.jQ.append('<span style="display:inline-block;width:0">&nbsp;</span>'); - } - // like 'sub sup'.split(' ').forEach(function(supsub) { ... }); - for (var i = 0; i < 2; i += 1) (function(cmd, supsub, oppositeSupsub, updown) { - cmd[supsub].deleteOutOf = function(dir, cursor) { - cursor.insDirOf(dir, this.parent); - if (!this.isEmpty()) { - cursor[-dir] = this.ends[dir]; - this.children().disown() - .withDirAdopt(dir, cursor.parent, cursor[dir], this.parent) - .jQ.insDirOf(dir, this.parent.jQ); - } - cmd.supsub = oppositeSupsub; - delete cmd[supsub]; - delete cmd[updown+'Into']; - cmd[oppositeSupsub][updown+'OutOf'] = insLeftOfMeUnlessAtEnd; - delete cmd[oppositeSupsub].deleteOutOf; - if (supsub === 'sub') $(cmd.jQ.addClass('mq-sup-only')[0].lastChild).remove(); - this.remove(); - }; - }(this, 'sub sup'.split(' ')[i], 'sup sub'.split(' ')[i], 'down up'.split(' ')[i])); - }; - }); - - var SummationNotation = P(MathCommand, function(_, super_) { - _.init = function(ch, html) { - if(Options.p.autoParensSummationNotation) - var htmlTemplate = - '<span><span class="mq-large-operator mq-non-leaf">' - + '<span class="mq-to"><span>&1</span></span>' - + '<big>'+html+'</big>' - + '<span class="mq-from"><span>&0</span></span>' - + '</span>' - + '<span class="mq-non-leaf">' - + '<span class="mq-scaled mq-paren">(</span>' - + '<span class="mq-non-leaf">&2</span>' - + '<span class="mq-scaled mq-paren">)</span>' - + '</span></span>'; - else - var htmlTemplate = - '<span class="mq-large-operator mq-non-leaf">' - + '<span class="mq-to"><span>&1</span></span>' - + '<big>'+html+'</big>' - + '<span class="mq-from"><span>&0</span></span>' - + '</span>'; - Symbol.prototype.init.call(this, ch, htmlTemplate); - }; - _.createLeftOf = function(cursor) { - super_.createLeftOf.apply(this, arguments); - if (cursor.options.sumStartsWithNEquals) { - Letter('n').createLeftOf(cursor); - Equality().createLeftOf(cursor); - } - }; - _.reflow = function() { - if(Options.p.autoParensSummationNotation) { - var delimjQs = this.jQ.children(':last').children(':first').add(this.jQ.children(':last').children(':last')); - var contentjQ = this.jQ.children(':last').children(':eq(1)'); - var height = contentjQ.outerHeight() / parseInt(contentjQ.css('fontSize'), 10); - scale(delimjQs, min(1 + .2*(height - 1), 1.2), 1.05*height); - } - }; - _.latex = function() { - function simplify(latex) { - return latex.length === 1 ? latex : '{' + (latex || ' ') + '}'; - } - if(Options.p.autoParensSummationNotation) - return this.ctrlSeq + '_{' + this.blocks[0].latex() + - '}^{' + this.blocks[1].latex() + '}\\left({' + this.blocks[2].latex() + '}\\right)'; - else - return this.ctrlSeq + '_' + simplify(this.ends[L].latex()) + - '^' + simplify(this.ends[R].latex()); - }; - _.text = function(opts) { - if(Options.p.autoParensSummationNotation) - return ' ' + this.ctrlSeq + '("' + this.blocks[0].text(opts).replace('=','" , ') + ' , ' + this.blocks[1].text(opts) + ',' + this.blocks[2].text(opts) + ')'; - else - return ' ' + this.ctrlSeq + '("' + this.ends[L].text(opts).replace('=','" , ') + ' , ' + this.ends[R].text(opts) + ')'; - } - _.parser = function() { - var string = Parser.string; - var optWhitespace = Parser.optWhitespace; - var whitespace = Parser.whitespace; - var succeed = Parser.succeed; - var block = latexMathParser.block; - - var self = this; - if(Options.p.autoParensSummationNotation) - var blocks = self.blocks = [ MathBlock(), MathBlock(), MathBlock() ]; - else - var blocks = self.blocks = [ MathBlock(), MathBlock() ]; - for (var i = 0; i < blocks.length; i += 1) { - blocks[i].adopt(self, self.ends[R], 0); - } - - if(Options.p.autoParensSummationNotation) - return optWhitespace.then(string('_')).then(function() { - var child = blocks[0]; - return block.then(function(block) { - block.children().adopt(child, child.ends[R], 0); - return succeed(self); - }); - }).then(optWhitespace).then(string('^')).then(function() { - var child = blocks[1]; - return block.then(function(block) { - block.children().adopt(child, child.ends[R], 0); - return succeed(self); - }); - }).then(string('\\left(')).then(function() { - var child = blocks[2]; - return block.then(function (block) { - block.children().adopt(child, child.ends[R], 0); - return succeed(self); - }); - }).then(string('\\right)')).result(self); - else - return optWhitespace.then(string('_').or(string('^'))).then(function(supOrSub) { - var child = blocks[supOrSub === '_' ? 0 : 1]; - return block.then(function(block) { - block.children().adopt(child, child.ends[R], 0); - return succeed(self); - }); - }).many().result(self); - }; - _.finalizeTree = function() { - this.downInto = this.ends[L]; - this.upInto = this.ends[R]; - this.ends[L].upOutOf = this.ends[R]; - this.ends[R].downOutOf = this.ends[L]; - }; - }); - - LatexCmds['\u2211'] = - LatexCmds.sum = - LatexCmds.summation = bind(SummationNotation,'\\sum ','&sum;'); - - LatexCmds['\u220f'] = - LatexCmds.prod = - LatexCmds.product = bind(SummationNotation,'\\prod ','&prod;'); - - LatexCmds.coprod = - LatexCmds.coproduct = bind(SummationNotation,'\\coprod ','&#8720;'); - - - - function insLeftOfMeUnlessAtEnd(cursor) { - // cursor.insLeftOf(cmd), unless cursor at the end of block, and every - // ancestor cmd is at the end of every ancestor block - var cmd = this.parent, ancestorCmd = cursor; - do { - if (ancestorCmd[R]) return cursor.insLeftOf(cmd); - ancestorCmd = ancestorCmd.parent.parent; - } while (ancestorCmd !== cmd); - cursor.insRightOf(cmd); - } - - LatexCmds.subscript = - LatexCmds._ = P(SupSub, function(_, super_) { - _.supsub = 'sub'; - _.ctrlSeq = '_'; - _.htmlTemplate = - '<span class="mq-supsub mq-non-leaf">' - + '<span class="mq-sub">&0</span>' - + '<span style="display:inline-block;width:0">&nbsp;</span>' - + '</span>' - ; - _.textTemplate = [ '_' ]; - _.finalizeTree = function() { - this.downInto = this.sub = this.ends[L]; - this.sub.upOutOf = insLeftOfMeUnlessAtEnd; - super_.finalizeTree.call(this); - }; - }); - - LatexCmds.superscript = - LatexCmds.supscript = - LatexCmds['^'] = P(SupSub, function(_, super_) { - _.supsub = 'sup'; - _.ctrlSeq = '^'; - _.htmlTemplate = - '<span class="mq-supsub mq-non-leaf mq-sup-only">' - + '<span class="mq-sup">&0</span>' - + '</span>' - ; - _.textTemplate = [ '^' ]; - _.finalizeTree = function() { - this.upInto = this.sup = this.ends[R]; - this.sup.downOutOf = insLeftOfMeUnlessAtEnd; - super_.finalizeTree.call(this); - }; - }); - - var Fraction = - LatexCmds.frac = - LatexCmds.dfrac = - LatexCmds.cfrac = - LatexCmds.fraction = P(MathCommand, function(_, super_) { - _.ctrlSeq = '\\frac'; - _.htmlTemplate = - '<span class="mq-fraction mq-non-leaf">' - + '<span class="mq-numerator">&0</span>' - + '<span class="mq-denominator">&1</span>' - + '<span style="display:inline-block;width:0">&nbsp;</span>' - + '</span>' - ; - _.textTemplate = ['((', ')/(', '))']; - _.finalizeTree = function() { - this.upInto = this.ends[R].upOutOf = this.ends[L]; - this.downInto = this.ends[L].downOutOf = this.ends[R]; - }; - }); - - var LiveFraction = - LatexCmds.over = - CharCmds['/'] = P(Fraction, function(_, super_) { - _.createLeftOf = function(cursor) { - if (!this.replacedFragment) { - var leftward = cursor[L]; - while (leftward && - !( - leftward instanceof BinaryOperator || - leftward instanceof (LatexCmds.text || noop) || - leftward instanceof SummationNotation || - leftward.ctrlSeq === '\\ ' || - /^[,;:]$/.test(leftward.ctrlSeq) - ) //lookbehind for operator - ) leftward = leftward[L]; - - if (leftward instanceof SummationNotation && leftward[R] instanceof SupSub) { - leftward = leftward[R]; - if (leftward[R] instanceof SupSub && leftward[R].ctrlSeq != leftward.ctrlSeq) - leftward = leftward[R]; - } - - if (leftward !== cursor[L]) { - this.replaces(Fragment(leftward[R] || cursor.parent.ends[L], cursor[L])); - cursor[L] = leftward; - } - } - super_.createLeftOf.call(this, cursor); - }; - }); - - var SquareRoot = - LatexCmds.sqrt = - LatexCmds['\u221a'] = P(MathCommand, function(_, super_) { - _.ctrlSeq = '\\sqrt'; - _.htmlTemplate = - '<span class="mq-non-leaf">' - + '<span class="mq-scaled mq-sqrt-prefix">&radic;</span>' - + '<span class="mq-non-leaf mq-sqrt-stem">&0</span>' - + '</span>' - ; - _.textTemplate = [' sqrt(', ')']; - _.parser = function() { - return latexMathParser.optBlock.then(function(optBlock) { - return latexMathParser.block.map(function(block) { - var nthroot = NthRoot(); - nthroot.blocks = [ optBlock, block ]; - optBlock.adopt(nthroot, 0, 0); - block.adopt(nthroot, optBlock, 0); - return nthroot; - }); - }).or(super_.parser.call(this)); - }; - _.reflow = function() { - var block = this.ends[R].jQ; - scale(block.prev(), 1, block.innerHeight()/+block.css('fontSize').slice(0,-2) - .1); - }; - }); - - var Vec = LatexCmds.vec = P(MathCommand, function(_, super_) { - _.ctrlSeq = '\\vec'; - _.htmlTemplate = - '<span class="mq-non-leaf">' - + '<span class="mq-vector-prefix">&rarr;</span>' - + '<span class="mq-vector-stem">&0</span>' - + '</span>' - ; - _.textTemplate = ['vec(', ')']; - }); - - var NthRoot = - LatexCmds.nthroot = P(SquareRoot, function(_, super_) { - _.htmlTemplate = - '<sup class="mq-nthroot mq-non-leaf">&0</sup>' - + '<span class="mq-scaled">' - + '<span class="mq-sqrt-prefix mq-scaled">&radic;</span>' - + '<span class="mq-sqrt-stem mq-non-leaf">&1</span>' - + '</span>' - ; - _.textTemplate = ['sqrt[', '](', ')']; - _.latex = function() { - return '\\sqrt['+this.ends[L].latex()+']{'+this.ends[R].latex()+'}'; - }; - _.text = function(opts) { - return ' ' + this.ends[R].text(opts) + '^(1/' + this.ends[L].text(opts) + ')'; - } - }); - - var Matrix = - LatexCmds.begin = P(MathCommand, function (_, _super) { - _.ctrlSeq = '\\matrix'; - _.numBlocks = function () { - return this.col * this.row; - }; - _.init = function (col, row) { - this.col = col; - this.row = row; - var html = ''; - for (var i = 0; i < row; i++) { - var r = ''; - for (var j = 0; j < col; j++) - r += '<span class="mq-cell">&' + (i * col + j) + '</span>' - html += '<span class="mq-row">' + r + '</span>'; - } - _super.init.call(this, this.ctrlSeq, '<span class="mq-matrix">' + html + '</span>', [ 'text' ]); - }; - _.latex = function () { - var latex = ''; - var index = 1; - var c = this.col; - var numBlocks = this.numBlocks(); - - this.eachChild(function (child) { - if (child.ends[L]) - latex += child.latex(); - if ((index) != numBlocks) { - if (index % c == 0) - latex += " \\\\ "; - else - latex += " & "; - } - index++; - }); - return '\\begin{matrix}' + latex + '\\end{matrix}'; - }; - _.text = function () { - var cells = []; - this.eachChild(function (child) { - if (child.ends[L]) - cells.push(child.text()) - }); - return 'matrix[' + this.col + '][' + this.row + ']{' + cells.join(',') + '}'; - }; - _.parser = function () { - var block = latexMathParser.block; - var string = Parser.string; - var regex = Parser.regex; - var optWhitespace = Parser.optWhitespace; - return regex(/^\{matrix\}[\s\S]*?\\end\{matrix\}/).map(function (body) { - body = body.substring(8, body.length - 12).trim(); - var rows = body.split(/\\\\/).map(function (r) { - return r.trim(); - }); - var rowsCount = rows.length; - var colsCount = 0; - var cells = []; - rows.forEach(function (r) { - var cols = r.split(/&/); - colsCount = Math.max(colsCount, cols.length); - cells = cells.concat(cols); - }); - - var matrix = Matrix(colsCount, rowsCount); - - var blocks = matrix.blocks = Array(matrix.numBlocks()); - for (var i = 0; i < blocks.length; i++) { - var newBlock = blocks[i] = latexMathParser.parse(cells[i]); - newBlock.adopt(matrix, matrix.ends[R], 0); - } - return matrix; - }) - }; - _.finalizeTree = function () { - for (var i = 0; i < this.row; i++) { - for (var j = 0; j < this.col; j++) { - var b = this.blocks[i * this.col + j]; - b.upOutOf = (i == 0 && j != 0) ? this.blocks[this.row * this.col - this.row + j - 1 ] : this.blocks[(i - 1) * this.col + j]; - b.downOutOf = ((i + 1) == this.row && (j + 1) != this.col) ? this.blocks[j + 1] : this.blocks[(i + 1) * this.col + j]; - } - } - } - }); - - - function DelimsMixin(_, super_) { - _.jQadd = function() { - super_.jQadd.apply(this, arguments); - this.delimjQs = this.jQ.children(':first').add(this.jQ.children(':last')); - this.contentjQ = this.jQ.children(':eq(1)'); - }; - _.reflow = function() { - var height = this.contentjQ.outerHeight() - / parseInt(this.contentjQ.css('fontSize'), 10); - scale(this.delimjQs, min(1 + .2*(height - 1), 1.2), 1.05*height); - }; - } - -// Round/Square/Curly/Angle Brackets (aka Parens/Brackets/Braces) -// first typed as one-sided bracket with matching "ghost" bracket at -// far end of current block, until you type an opposing one - var Bracket = P(P(MathCommand, DelimsMixin), function(_, super_) { - _.init = function(side, open, close, ctrlSeq, end) { - super_.init.call(this, '\\left'+ctrlSeq, undefined, [open, close]); - this.side = side; - this.sides = {}; - this.sides[L] = { ch: open, ctrlSeq: ctrlSeq }; - this.sides[R] = { ch: close, ctrlSeq: end }; - }; - _.numBlocks = function() { return 1; }; - _.html = function() { // wait until now so that .side may - this.htmlTemplate = // be set by createLeftOf or parser - '<span class="mq-non-leaf">' - + '<span class="mq-scaled mq-paren'+(this.side === R ? ' mq-ghost' : '')+'">' - + this.sides[L].ch - + '</span>' - + '<span class="mq-non-leaf">&0</span>' - + '<span class="mq-scaled mq-paren'+(this.side === L ? ' mq-ghost' : '')+'">' - + this.sides[R].ch - + '</span>' - + '</span>' - ; - return super_.html.call(this); - }; - _.latex = function() { - return '\\left'+this.sides[L].ctrlSeq+this.ends[L].latex()+'\\right'+this.sides[R].ctrlSeq; - }; - _.oppBrack = function(node, expectedSide) { - // node must be 1-sided bracket of expected side (if any, may be undefined), - // and unless I'm a pipe, node and I must be opposite-facing sides - return node instanceof Bracket && node.side && node.side !== -expectedSide - && (this.sides[this.side].ch === '|' || node.side === -this.side) && node; - }; - _.closeOpposing = function(brack) { - brack.side = 0; - brack.sides[this.side] = this.sides[this.side]; // copy over my info (may be - brack.delimjQs.eq(this.side === L ? 0 : 1) // mis-matched, like [a, b)) - .removeClass('mq-ghost').html(this.sides[this.side].ch); - }; - _.createLeftOf = function(cursor) { - if (!this.replacedFragment) { // unless wrapping seln in brackets, - // check if next to or inside an opposing one-sided bracket - var brack = this.oppBrack(cursor[L], L) || this.oppBrack(cursor[R], R) - || this.oppBrack(cursor.parent.parent); - } - if (brack) { - var side = this.side = -brack.side; // may be pipe with .side not yet set - this.closeOpposing(brack); - if (brack === cursor.parent.parent && cursor[side]) { // move the stuff between - Fragment(cursor[side], cursor.parent.ends[side], -side) // me and ghost outside - .disown().withDirAdopt(-side, brack.parent, brack, brack[side]) - .jQ.insDirOf(side, brack.jQ); - brack.bubble('reflow'); - } - } - else { - brack = this, side = brack.side; - if (brack.replacedFragment) brack.side = 0; // wrapping seln, don't be one-sided - else if (cursor[-side]) { // elsewise, auto-expand so ghost is at far end - brack.replaces(Fragment(cursor[-side], cursor.parent.ends[-side], side)); - cursor[-side] = 0; - } - super_.createLeftOf.call(brack, cursor); - } - if (side === L) cursor.insAtLeftEnd(brack.ends[L]); - else cursor.insRightOf(brack); - cursor.parent.bubble('workingGroupChange'); - }; - _.placeCursor = noop; - _.unwrap = function() { - this.ends[L].children().disown().adopt(this.parent, this, this[R]) - .jQ.insertAfter(this.jQ); - this.remove(); - }; - _.deleteSide = function(side, outward, cursor) { - var parent = this.parent, sib = this[side], farEnd = parent.ends[side]; - - if (side === this.side) { // deleting non-ghost of one-sided bracket, unwrap - this.unwrap(); - sib ? cursor.insDirOf(-side, sib) : cursor.insAtDirEnd(side, parent); - return; - } - - this.side = -side; - // check if like deleting outer close-brace of [(1+2)+3} where inner open- - if (this.oppBrack(this.ends[L].ends[this.side], side)) { // paren is ghost, - this.closeOpposing(this.ends[L].ends[this.side]); // if so become [1+2)+3 - var origEnd = this.ends[L].ends[side]; - this.unwrap(); - if (origEnd.siblingCreated) origEnd.siblingCreated(cursor.options, side); - sib ? cursor.insDirOf(-side, sib) : cursor.insAtDirEnd(side, parent); - } - else { // check if like deleting inner close-brace of ([1+2}+3) where - if (this.oppBrack(this.parent.parent, side)) { // outer open-paren is - this.parent.parent.closeOpposing(this); // ghost, if so become [1+2+3) - this.parent.parent.unwrap(); - } - else { // deleting one of a pair of brackets, become one-sided - this.sides[side] = { ch: OPP_BRACKS[this.sides[this.side].ch], - ctrlSeq: OPP_BRACKS[this.sides[this.side].ctrlSeq] }; - this.delimjQs.removeClass('mq-ghost') - .eq(side === L ? 0 : 1).addClass('mq-ghost').html(this.sides[side].ch); - } - if (sib) { // auto-expand so ghost is at far end - var origEnd = this.ends[L].ends[side]; - Fragment(sib, farEnd, -side).disown() - .withDirAdopt(-side, this.ends[L], origEnd, 0) - .jQ.insAtDirEnd(side, this.ends[L].jQ.removeClass('mq-empty')); - if (origEnd.siblingCreated) origEnd.siblingCreated(cursor.options, side); - cursor.insDirOf(-side, sib); - } // didn't auto-expand, cursor goes just outside or just inside parens - else (outward ? cursor.insDirOf(side, this) - : cursor.insAtDirEnd(side, this.ends[L])); - } - }; - _.deleteTowards = function(dir, cursor) { - this.deleteSide(-dir, false, cursor); - }; - _.finalizeTree = function(opts) { - this.ends[L].deleteOutOf = function(dir, cursor) { - this.parent.deleteSide(dir, true, cursor); - }; - if(opts.autoOnBrackets && this[L] instanceof Letter) - this[L].autoUnItalicize(opts); - // FIXME HACK: after initial creation/insertion, finalizeTree would only be - // called if the paren is selected and replaced, e.g. by LiveFraction - this.finalizeTree = this.intentionalBlur = function() { - this.delimjQs.eq(this.side === L ? 1 : 0).removeClass('mq-ghost'); - this.side = 0; - }; - }; - _.siblingCreated = function(opts, dir) { // if something typed between ghost and far - if (dir === -this.side) this.finalizeTree(); // end of its block, solidify - }; - }); - - var OPP_BRACKS = { - '(': ')', - ')': '(', - '[': ']', - ']': '[', - '{': '}', - '}': '{', - '\\{': '\\}', - '\\}': '\\{', - '&lang;': '&rang;', - '&rang;': '&lang;', - '\\langle ': '\\rangle ', - '\\rangle ': '\\langle ', - '|': '|' - }; - - function bindCharBracketPair(open, ctrlSeq) { - var ctrlSeq = ctrlSeq || open, close = OPP_BRACKS[open], end = OPP_BRACKS[ctrlSeq]; - CharCmds[open] = bind(Bracket, L, open, close, ctrlSeq, end); - CharCmds[close] = bind(Bracket, R, open, close, ctrlSeq, end); - } - bindCharBracketPair('('); - bindCharBracketPair('['); - bindCharBracketPair('{', '\\{'); - LatexCmds.langle = bind(Bracket, L, '&lang;', '&rang;', '\\langle ', '\\rangle '); - LatexCmds.rangle = bind(Bracket, R, '&lang;', '&rang;', '\\langle ', '\\rangle '); - CharCmds['|'] = bind(Bracket, L, '|', '|', '|', '|'); - - LatexCmds.left = P(MathCommand, function(_) { - _.parser = function() { - var regex = Parser.regex; - var string = Parser.string; - var succeed = Parser.succeed; - var optWhitespace = Parser.optWhitespace; - - return optWhitespace.then(regex(/^(?:[([|]|\\\{)/)) - .then(function(ctrlSeq) { // TODO: \langle, \rangle - var open = (ctrlSeq.charAt(0) === '\\' ? ctrlSeq.slice(1) : ctrlSeq); - return latexMathParser.then(function (block) { - return string('\\right').skip(optWhitespace) - .then(regex(/^(?:[\])|]|\\\})/)).map(function(end) { - var close = (end.charAt(0) === '\\' ? end.slice(1) : end); - var cmd = Bracket(0, open, close, ctrlSeq, end); - cmd.blocks = [ block ]; - block.adopt(cmd, 0, 0); - return cmd; - }) - ; - }); - }) - ; - }; - }); - - LatexCmds.right = P(MathCommand, function(_) { - _.parser = function() { - return Parser.fail('unmatched \\right'); - }; - }); - - var Binomial = - LatexCmds.binom = - LatexCmds.binomial = P(P(MathCommand, DelimsMixin), function(_, super_) { - _.ctrlSeq = '\\binom'; - _.htmlTemplate = - '<span class="mq-non-leaf">' - + '<span class="mq-paren mq-scaled">(</span>' - + '<span class="mq-non-leaf">' - + '<span class="mq-array mq-non-leaf">' - + '<span>&0</span>' - + '<span>&1</span>' - + '</span>' - + '</span>' - + '<span class="mq-paren mq-scaled">)</span>' - + '</span>' - ; - _.textTemplate = ['choose(',',',')']; - }); - - var Choose = - LatexCmds.choose = P(Binomial, function(_) { - _.createLeftOf = LiveFraction.prototype.createLeftOf; - }); - - var InnerMathField = P(MathQuill.MathField, function(_) { - _.init = function(root, container) { - RootBlockMixin(root); - this.__options = Options(); - var ctrlr = Controller(this, root, container); - ctrlr.editable = true; - ctrlr.createTextarea(); - ctrlr.editablesTextareaEvents(); - ctrlr.cursor.insAtRightEnd(root); - }; - }); - LatexCmds.MathQuillMathField = P(MathCommand, function(_, super_) { - _.ctrlSeq = '\\MathQuillMathField'; - _.htmlTemplate = - '<span class="mq-editable-field">' - + '<span class="mq-root-block">&0</span>' - + '</span>' - ; - _.parser = function() { - var self = this, - string = Parser.string, regex = Parser.regex, succeed = Parser.succeed; - return string('[').then(regex(/^[a-z][a-z0-9]*/i)).skip(string(']')) - .map(function(name) { self.name = name; }).or(succeed()) - .then(super_.parser.call(self)); - }; - _.finalizeTree = function() { InnerMathField(this.ends[L], this.jQ); }; - _.registerInnerField = function(innerFields) { - innerFields.push(innerFields[this.name] = this.ends[L].controller.API); - }; - _.latex = function(){ return this.ends[L].latex(); }; - _.text = function(opts){ return this.ends[L].text(opts); }; - }); - -}()); +!function(){function t(){}function e(t){var e=t.length-1;return function(){var n=ke.call(arguments,0,e),i=ke.call(arguments,e);return t.apply(this,n.concat([i]))}}function n(t){return e(function(e,n){"function"!=typeof e&&(e=Oe(e));var i=function(t){return e.apply(t,[t].concat(n))};return t.call(this,i)})}function i(t){var e=ke.call(arguments,1);return function(){return t.apply(this,e)}}function s(t,e){if(!e)throw new Error("prayer failed: "+t)}function r(t){s("a direction was passed",t===Ce||t===je)}function o(t,e,n){s("a parent is always present",t),s("leftward is properly set up",function(){return e?e[je]===n&&e.parent===t:t.ends[Ce]===n}()),s("rightward is properly set up",function(){return n?n[Ce]===e&&n.parent===t:t.ends[je]===e}())}function a(t){if(!t||!t.nodeType)return null;var e=Qe(t).children(".mq-root-block").attr(we);return e?Te.byId[e].controller.API:null}function l(t){function e(e,n){var i=a(e);return i instanceof t||!e||!e.nodeType?i:t(Qe(e),n)}return e.prototype=t.prototype,e}function c(t){var e,n="workingGroupChange moveOutOf deleteOutOf selectOutOf upOutOf downOutOf reflow".split(" ");for(e=0;e<n.length;e+=1)(function(e){t[e]=function(t){this.controller.handle(e,t)}})(n[e])}function h(t,e,n){return ye(A,{ctrlSeq:t,htmlTemplate:"<"+e+" "+n+">&0</"+e+">"})}function u(t){var e=this.parent,n=t;do{if(n[je])return t.insLeftOf(e);n=n.parent.parent}while(n!==e);t.insRightOf(e)}function p(t,e){t.jQadd=function(){e.jQadd.apply(this,arguments),this.delimjQs=this.jQ.children(":first").add(this.jQ.children(":last")),this.contentjQ=this.jQ.children(":eq(1)")},t.reflow=function(){var t=this.contentjQ.outerHeight()/parseInt(this.contentjQ.css("fontSize"),10);V(this.delimjQs,qe(1+.2*(t-1),1.2),1.05*t)}}function f(t,e){var e=e||t,n=fe[t],s=fe[e];_e[t]=i(pe,Ce,t,n,e,s),_e[n]=i(pe,je,t,n,e,s)}var d,m,g,b,v,w,q,x,k,O,y,C,j,Q,S,T,A,D,_,L,E,R,I,z,B,P,M,F,$,N,G,U,W,H,V,X,Z,K,Y,J,te,ee,ne,ie,se,re,oe,ae,le,ce,he,ue,pe,fe,de,me,ge,be=window.jQuery,ve="mathquill-command-id",we="mathquill-block-id",qe=Math.min,xe=Math.max,ke=[].slice,Oe=e(function(t,n){return e(function(e,i){return t in e?e[t].apply(e,n.concat(i)):void 0})}),ye=function(t,e,n){function i(t){return"object"==typeof t}function s(t){return"function"==typeof t}function r(){}return function o(a,l){function c(){var t=new h;return s(t.init)&&t.init.apply(t,arguments),t}function h(){}var u,p,f;return l===n&&(l=a,a=Object),c.Bare=h,u=r[t]=a[t],p=h[t]=c[t]=c.p=new r,p.constructor=c,c.mixin=function(e){return h[t]=c[t]=o(c,e)[t],c},(c.open=function(t){if(f={},s(t)?f=t.call(c,p,u,c,a):i(t)&&(f=t),i(f))for(var n in f)e.call(f,n)&&(p[n]=f[n]);return s(p.init)||(p.init=a),c})(l)}}("prototype",{}.hasOwnProperty),Ce=a.L=-1,je=a.R=1,Qe=ye(be,function(t){t.insDirOf=function(t,e){return t===Ce?this.insertBefore(e.first()):this.insertAfter(e.last())},t.insAtDirEnd=function(t,e){return t===Ce?this.prependTo(e):this.appendTo(e)}}),Se=ye(function(t){t.parent=0,t[Ce]=0,t[je]=0,t.init=function(t,e,n){this.parent=t,this[Ce]=e,this[je]=n},this.copy=function(t){return Se(t.parent,t[Ce],t[je])}}),Te=ye(function(t){function e(){return i+=1}t[Ce]=0,t[je]=0,t.parent=0;var i=0;this.byId={},t.init=function(){this.id=e(),Te.byId[this.id]=this,this.ends={},this.ends[Ce]=0,this.ends[je]=0},t.dispose=function(){delete Te.byId[this.id]},t.toString=function(){return"{{ MathQuill Node #"+this.id+" }}"},t.jQ=Qe(),t.jQadd=function(t){return this.jQ=this.jQ.add(t)},t.jQize=function(t){function e(t){var n,i;for(t.getAttribute&&(n=t.getAttribute("mathquill-command-id"),i=t.getAttribute("mathquill-block-id"),n&&Te.byId[n].jQadd(t),i&&Te.byId[i].jQadd(t)),t=t.firstChild;t;t=t.nextSibling)e(t)}var n;for(t=Qe(t||this.html()),n=0;n<t.length;n+=1)e(t[n]);return t},t.createDir=function(t,e){r(t);var n=this;return n.jQize(),n.jQ.insDirOf(t,e.jQ),e[t]=n.adopt(e.parent,e[Ce],e[je]),n},t.createLeftOf=function(t){return this.createDir(Ce,t)},t.selectChildren=function(t,e){return Ee(t,e)},t.bubble=n(function(t){var e,n;for(e=this;e&&(n=t(e),n!==!1);e=e.parent);return this}),t.postOrder=n(function(t){return function e(n){n.eachChild(e),t(n)}(this),this}),t.isEmpty=function(){return 0===this.ends[Ce]&&0===this.ends[je]},t.children=function(){return Ae(this.ends[Ce],this.ends[je])},t.eachChild=function(){var t=this.children();return t.each.apply(t,arguments),this},t.foldChildren=function(t,e){return this.children().fold(t,e)},t.withDirAdopt=function(t,e,n,i){return Ae(this,this).withDirAdopt(t,e,n,i),this},t.adopt=function(t,e,n){return Ae(this,this).adopt(t,e,n),this},t.disown=function(){return Ae(this,this).disown(),this},t.remove=function(){return this.jQ.remove(),this.postOrder("dispose"),this.disown()}}),Ae=ye(function(t){t.init=function(t,e,n){n===d&&(n=Ce),r(n),s("no half-empty fragments",!t==!e),this.ends={},t&&(s("withDir is passed to Fragment",t instanceof Te),s("oppDir is passed to Fragment",e instanceof Te),s("withDir and oppDir have the same parent",t.parent===e.parent),this.ends[n]=t,this.ends[-n]=e,this.jQ=this.fold(this.jQ,function(t,e){return t.add(e.jQ)}))},t.jQ=Qe(),t.withDirAdopt=function(t,e,n,i){return t===Ce?this.adopt(e,n,i):this.adopt(e,i,n)},t.adopt=function(t,e,n){var i,s,r;return o(t,e,n),i=this,i.disowned=!1,(s=i.ends[Ce])?(r=i.ends[je],e||(t.ends[Ce]=s),n?n[Ce]=r:t.ends[je]=r,i.ends[je][je]=n,i.each(function(n){n[Ce]=e,n.parent=t,e&&(e[je]=n),e=n}),i):this},t.disown=function(){var t,e,n=this,i=n.ends[Ce];return!i||n.disowned?n:(n.disowned=!0,t=n.ends[je],e=i.parent,o(e,i[Ce],i),o(e,t,t[je]),i[Ce]?i[Ce][je]=t[je]:e.ends[Ce]=t[je],t[je]?t[je][Ce]=i[Ce]:e.ends[je]=i[Ce],n)},t.remove=function(){return this.jQ.remove(),this.each("postOrder","dispose"),this.disown()},t.each=n(function(t){var e,n=this,i=n.ends[Ce];if(!i)return n;for(;i!==n.ends[je][je]&&(e=t(i),e!==!1);i=i[je]);return n}),t.fold=function(t,e){return this.each(function(n){t=e.call(this,t,n)}),t}}),De={},_e={},Le=ye(Se,function(t){t.init=function(t,e){this.parent=t,this.options=e;var n=this.jQ=this._jQ=Qe('<span class="mq-cursor">&zwj;</span>');this.blink=function(){n.toggleClass("mq-blink")},this.upDownCache={}},t.show=function(){return this.jQ=this._jQ.removeClass("mq-blink"),"intervalId"in this?clearInterval(this.intervalId):(this[je]?this.jQ.insertBefore(this.selection&&this.selection.ends[Ce][Ce]===this[Ce]?this.selection.jQ:this[je].jQ.first()):this.jQ.appendTo(this.parent.jQ),this.parent.focus()),this.intervalId=setInterval(this.blink,500),this},t.hide=function(){return"intervalId"in this&&clearInterval(this.intervalId),delete this.intervalId,this.jQ.detach(),this.jQ=Qe(),this},t.withDirInsertAt=function(t,e,n,i){e!==this.parent&&this.parent.blur&&this.parent.blur(),this.parent=e,this[t]=n,this[-t]=i},t.insDirOf=function(t,e){return r(t),this.withDirInsertAt(t,e.parent,e[t],e),this.parent.jQ.addClass("mq-hasCursor"),this.jQ.insDirOf(t,e.jQ),this},t.insLeftOf=function(t){return this.insDirOf(Ce,t)},t.insRightOf=function(t){return this.insDirOf(je,t)},t.insAtDirEnd=function(t,e){return r(t),this.withDirInsertAt(t,e,0,e.ends[t]),this.jQ.insAtDirEnd(t,e.jQ),e.focus(),this},t.insAtLeftEnd=function(t){return this.insAtDirEnd(Ce,t)},t.insAtRightEnd=function(t){return this.insAtDirEnd(je,t)},t.jumpUpDown=function(t,e){var n,i,s=this;s.upDownCache[t.id]=Se.copy(s),n=s.upDownCache[e.id],n?n[je]?s.insLeftOf(n[je]):s.insAtRightEnd(n.parent):(i=s.offset().left,e.seek(i,s))},t.offset=function(){var t=this,e=t.jQ.removeClass("mq-cursor").offset();return t.jQ.addClass("mq-cursor"),e},t.unwrapGramp=function(){var t=this.parent.parent,e=t.parent,n=t[je],i=this,s=t[Ce];if(t.disown().eachChild(function(i){i.isEmpty()||(i.children().adopt(e,s,n).each(function(e){e.jQ.insertBefore(t.jQ.first())}),s=i.ends[je])}),!this[je])if(this[Ce])this[je]=this[Ce][je];else for(;!this[je];){if(this.parent=this.parent[je],!this.parent){this[je]=t[je],this.parent=e;break}this[je]=this.parent.ends[Ce]}this[je]?this.insLeftOf(this[je]):this.insAtRightEnd(e),t.jQ.remove(),t[Ce].siblingDeleted&&t[Ce].siblingDeleted(i.options,je),t[je].siblingDeleted&&t[je].siblingDeleted(i.options,Ce)},t.startSelection=function(){var t,e=this.anticursor=Se.copy(this),n=e.ancestors={};for(t=e;t.parent;t=t.parent)n[t.parent.id]=t},t.endSelection=function(){delete this.anticursor},t.select=function(){var t,e,n,i,r,o,a,l=this.anticursor;if(this[Ce]===l[Ce]&&this.parent===l.parent)return!1;for(t=this;t.parent;t=t.parent)if(t.parent.id in l.ancestors){e=t.parent;break}if(s("cursor and anticursor in the same tree",e),n=l.ancestors[e.id],o=je,t[Ce]!==n)for(a=t;a;a=a[je])if(a[je]===n[je]){o=Ce,i=t,r=n;break}return o===je&&(i=n,r=t),i instanceof Se&&(i=i[je]),r instanceof Se&&(r=r[Ce]),this.hide().selection=e.selectChildren(i,r),this.insDirOf(o,this.selection.ends[o]),this.selectionChanged(),!0},t.clearSelection=function(){return this.selection&&(this.selection.clear(),delete this.selection,this.selectionChanged()),this},t.deleteSelection=function(){this.selection&&(this[Ce]=this.selection.ends[Ce][Ce],this[je]=this.selection.ends[je][je],this.selection.remove(),this.selectionChanged(),delete this.selection)},t.replaceSelection=function(){var t=this.selection;return t&&(this[Ce]=t.ends[Ce][Ce],this[je]=t.ends[je][je],delete this.selection),t}}),Ee=ye(Ae,function(t,e){t.init=function(){e.init.apply(this,arguments),this.jQ=this.jQ.wrapAll('<span class="mq-selection"></span>').parent()},t.adopt=function(){return this.jQ.replaceWith(this.jQ=this.jQ.children()),e.adopt.apply(this,arguments)},t.clear=function(){return this.jQ.replaceWith(this.jQ[0].childNodes),this},t.join=function(t){return this.fold("",function(e,n){return e+n[t]()})}}),Re=ye(function(t){t.init=function(t,e,n){this.API=t,this.root=e,this.container=n,t.__controller=e.controller=this,this.cursor=e.cursor=Le(e,t.__options)},t.handle=function(t,e){var n=this.API.__options.handlers;n&&n[t]&&(e===Ce||e===je?n[t](e,this.API):n[t](this.API))};var e=[];this.onNotify=function(t){e.push(t)},t.notify=function(){for(var t=0;t<e.length;t+=1)e[t].apply(this.cursor,arguments);return this}});a.noConflict=function(){return window.MathQuill=m,a},m=window.MathQuill,window.MathQuill=a,g=ye(),b={},a.__options=g.p,v=ye(function(t){t.init=function(){throw"wtf don't call me, I'm 'abstract'"},t.initRoot=function(t,e,n){var i,s;this.__options=g(),this.config(n),i=Re(this,t,e),i.createTextarea(),s=e.contents().detach(),t.jQ=Qe('<span class="mq-root-block"/>').attr(we,t.id).appendTo(e),this.latex(s.text()),this.revert=function(){return e.empty().unbind(".mathquill").removeClass("mq-editable-field mq-math-mode mq-text-mode").append(s)}},t.config=a.config=function(t){var e,n,i;for(e in t)t.hasOwnProperty(e)&&(n=t[e],i=b[e],this.__options[e]=i?i(n):n);return this},t.el=function(){return this.__controller.container[0]},t.text=function(){return this.__controller.exportText(this.__options)},t.latex=function(t){return arguments.length>0?(this.__controller.renderLatexMath(t),this.__controller.blurred&&this.__controller.cursor.hide().parent.blur(),this):this.__controller.exportLatex()},t.html=function(){return this.__controller.root.jQ.html().replace(/ mathquill-(?:command|block)-id="?\d+"?/g,"").replace(/<span class="?mq-cursor( mq-blink)?"?>.?<\/span>/i,"").replace(/ mq-hasCursor|mq-hasCursor ?/,"").replace(/ class=(""|(?= |>))/g,"")},t.reflow=function(){return this.__controller.root.postOrder("reflow"),this}}),a.prototype=v.prototype,a.StaticMath=l(ye(v,function(t,e){t.init=function(t){this.initRoot(S(),t.addClass("mq-math-mode")),this.__controller.delegateMouseEvents(),this.__controller.staticMathTextareaEvents()},t.latex=function(){var t=e.latex.apply(this,arguments);return arguments.length>0&&this.__controller.root.postOrder("registerInnerField",this.innerFields=[]),t}})),w=a.EditableField=ye(v,function(e){e.initRootAndEvents=function(t,e,n){this.initRoot(t,e,n),this.__controller.editable=!0,this.__controller.delegateMouseEvents(),this.__controller.editablesTextareaEvents()},e.focus=function(){return this.__controller.textarea.focus(),this},e.blur=function(){return this.__controller.textarea.blur(),this},e.write=function(t){return this.__controller.writeLatex(t),this.__controller.blurred&&this.__controller.cursor.hide().parent.blur(),this},e.cmd=function(t){var e,n=this.__controller.notify(),i=n.cursor.show();return/^\\[a-z]+$/i.test(t)?(t=t.slice(1),e=De[t],e&&(t=e(t),i.selection&&t.replaces(i.replaceSelection()),t.createLeftOf(i))):i.parent.write(i,t,i.replaceSelection()),n.blurred&&i.hide().parent.blur(),this},e.select=function(){var t=this.__controller;for(t.notify("move").cursor.insAtRightEnd(t.root);t.cursor[Ce];)t.selectLeft();return this},e.clearSelection=function(){return this.__controller.cursor.clearSelection(),this},e.moveToDirEnd=function(t){return this.__controller.notify("move").cursor.insAtDirEnd(t,this.__controller.root),this},e.moveToLeftEnd=function(){return this.moveToDirEnd(Ce)},e.moveToRightEnd=function(){return this.moveToDirEnd(je)},e.keystroke=function(e){var n;for(e=e.replace(/^\s+|\s+$/g,"").split(/\s+/),n=0;n<e.length;n+=1)this.__controller.keystroke(e[n],{preventDefault:t});return this},e.typedText=function(t){for(var e=0;e<t.length;e+=1)this.__controller.typedText(t.charAt(e));return this}}),q=ye(function(t,e,n){function i(t,e){throw t=t?"'"+t+"'":"EOF","Parse Error: "+e+" at "+t}var r,o,a,l,c,h,u,p,f,d,m,g,b;t.init=function(t){this._=t},t.parse=function(t){function e(t,e){return e}return this.skip(b)._(t,e,i)},t.or=function(t){s("or is passed a parser",t instanceof n);var e=this;return n(function(n,i,s){function r(){return t._(n,i,s)}return e._(n,i,r)})},t.then=function(t){var e=this;return n(function(i,r,o){function a(e,i){var a=t instanceof n?t:t(i);return s("a parser is returned",a instanceof n),a._(e,r,o)}return e._(i,a,o)})},t.many=function(){var t=this;return n(function(e,n){function i(t,n){return e=t,r.push(n),!0}function s(){return!1}for(var r=[];t._(e,i,s););return n(e,r)})},t.times=function(t,e){arguments.length<2&&(e=t);var i=this;return n(function(n,s,r){function o(t,e){return u.push(e),n=t,!0}function a(t,e){return c=e,n=t,!1}function l(){return!1}var c,h,u=[],p=!0;for(h=0;t>h;h+=1)if(p=i._(n,o,a),!p)return r(n,c);for(;e>h&&p;h+=1)p=i._(n,o,l);return s(n,u)})},t.result=function(t){return this.then(a(t))},t.atMost=function(t){return this.times(0,t)},t.atLeast=function(t){var e=this;return e.times(t).then(function(t){return e.many().map(function(e){return t.concat(e)})})},t.map=function(t){return this.then(function(e){return a(t(e))})},t.skip=function(t){return this.then(function(e){return t.result(e)})},r=this.string=function(t){var e=t.length,i="expected '"+t+"'";return n(function(n,s,r){var o=n.slice(0,e);return o===t?s(n.slice(e),o):r(n,i)})},o=this.regex=function(t){s("regexp parser is anchored","^"===t.toString().charAt(1));var e="expected "+t;return n(function(n,i,s){var r,o=t.exec(n);return o?(r=o[0],i(n.slice(r.length),r)):s(n,e)})},a=n.succeed=function(t){return n(function(e,n){return n(e,t)})},l=n.fail=function(t){return n(function(e,n,i){return i(e,t)})},c=n.letter=o(/^[a-z]/i),h=n.letters=o(/^[a-z]*/i),u=n.digit=o(/^[0-9]/),p=n.digits=o(/^[0-9]*/),f=n.whitespace=o(/^\s+/),d=n.optWhitespace=o(/^\s*/),m=n.any=n(function(t,e,n){return t?e(t.slice(1),t.charAt(0)):n(t,"expected any character")}),g=n.all=n(function(t,e){return e("",t)}),b=n.eof=n(function(t,e,n){return t?n(t,"expected EOF"):e(t,t)})}),x=function(){function e(t){var e,i=t.which||t.keyCode,s=n[i],r=[];return t.ctrlKey&&r.push("Ctrl"),t.originalEvent&&t.originalEvent.metaKey&&r.push("Meta"),t.altKey&&r.push("Alt"),t.shiftKey&&r.push("Shift"),e=s||String.fromCharCode(i),r.length||s?(r.push(e),r.join("-")):e}var n={8:"Backspace",9:"Tab",10:"Enter",13:"Enter",16:"Shift",17:"Control",18:"Alt",20:"CapsLock",27:"Esc",32:"Spacebar",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"Left",38:"Up",39:"Right",40:"Down",45:"Insert",46:"Del",144:"NumLock"};return function(n,i){function s(t){q=t,clearTimeout(d),d=setTimeout(t)}function r(e){q(),q=t,clearTimeout(d),v.val(e),e&&v[0].select(),m=!!e}function o(){var t=v[0];return"selectionStart"in t?t.selectionStart!==t.selectionEnd:!1}function a(){i.keystroke(e(g),g)}function l(e){g=e,b=null,a(),m&&s(function(){v[0].select(),q=t,clearTimeout(d)})}function c(t){g&&b&&a(),b=t,s(h)}function h(){if(!o()){var t=v.val();1===t.length?(v.val(""),i.typedText(t)):t&&v[0].select()}}function u(){g=b=null}function p(){v.focus(),s(f)}function f(){var t=v.val();v.val(""),t&&i.paste(t)}var d,m,g=null,b=null,v=be(n),w=be(i.container||v),q=t;return w.bind("keydown keypress input keyup focusout paste",function(){q()}),m=!1,w.bind({keydown:l,keypress:c,focusout:u,paste:p}),{select:r}}}(),Re.open(function(t){t.exportText=function(t){return this.root.foldChildren("",function(e,n){return e+n.text(t)}).replace(/\\operatorname\{(.*?)\}/g,"$1").replace(/\\/g,"").replace(/\* *\*/g,"*").replace(/ *_/g,"_").replace(/\* *$/,"")}}),Re.open(function(t){t.focusBlurEvents=function(){function t(){clearTimeout(n),r.selection&&r.selection.jQ.addClass("mq-blur"),e()}function e(){r.hide().parent.blur(),i.container.removeClass("mq-focused"),Qe(window).off("blur",t)}var n,i=this,s=i.root,r=i.cursor;i.textarea.focus(function(){i.blurred=!1,clearTimeout(n),i.container.addClass("mq-focused"),r.parent||r.insAtRightEnd(s),r.selection?(r.selection.jQ.removeClass("mq-blur"),i.selectionChanged()):r.show()}).blur(function(){i.blurred=!0,n=setTimeout(function(){s.postOrder("intentionalBlur"),r.clearSelection(),e()}),Qe(window).on("blur",t)}),i.blurred=!0,r.hide().parent.blur()}}),Re.open(function(t){t.keystroke=function(t,e){this.cursor.parent.keystroke(t,e,this)}}),Te.open(function(t){t.keystroke=function(t,e,n){var i=n.cursor;switch(t){case"Ctrl-Shift-Backspace":case"Ctrl-Backspace":for(;i[Ce]||i.selection;)n.backspace();break;case"Shift-Backspace":case"Backspace":n.backspace();break;case"Esc":case"Tab":return void n.escapeDir(je,t,e);case"Shift-Tab":case"Shift-Esc":return void n.escapeDir(Ce,t,e);case"End":n.notify("move").cursor.insAtRightEnd(i.parent);break;case"Ctrl-End":n.notify("move").cursor.insAtRightEnd(n.root);break;case"Shift-End":for(;i[je];)n.selectRight();break;case"Ctrl-Shift-End":for(;i[je]||i.parent!==n.root;)n.selectRight();break;case"Home":n.notify("move").cursor.insAtLeftEnd(i.parent);break;case"Ctrl-Home":n.notify("move").cursor.insAtLeftEnd(n.root);break;case"Shift-Home":for(;i[Ce];)n.selectLeft();break;case"Ctrl-Shift-Home":for(;i[Ce]||i.parent!==n.root;)n.selectLeft();break;case"Left":n.moveLeft();break;case"Shift-Left":n.selectLeft();break;case"Ctrl-Left":break;case"Right":n.moveRight();break;case"Shift-Right":n.selectRight();break;case"Ctrl-Right":break;case"Up":n.moveUp();break;case"Down":n.moveDown();break;case"Shift-Up":if(i[Ce])for(;i[Ce];)n.selectLeft();else n.selectLeft();case"Shift-Down":if(i[je])for(;i[je];)n.selectRight();else n.selectRight();case"Ctrl-Up":break;case"Ctrl-Down":break;case"Ctrl-Shift-Del":case"Ctrl-Del":for(;i[je]||i.selection;)n.deleteForward();break;case"Shift-Del":case"Del":n.deleteForward();break;case"Meta-A":case"Ctrl-A":for(n.notify("move").cursor.insAtRightEnd(n.root);i[Ce];)n.selectLeft();break;default:return}e.preventDefault(),n.scrollHoriz()},t.moveOutOf=t.moveTowards=t.deleteOutOf=t.deleteTowards=t.unselectInto=t.selectOutOf=t.selectTowards=function(){s("overridden or never called on this node")}}),Re.open(function(t){function e(t,e){var n=t.notify("upDown").cursor,i=e+"Into",s=e+"OutOf";return n[je][i]?n.insAtLeftEnd(n[je][i]):n[Ce][i]?n.insAtRightEnd(n[Ce][i]):n.parent.bubble(function(t){var e=t[s];return e&&("function"==typeof e&&(e=t[s](n)),e instanceof Te&&n.jumpUpDown(t,e),e!==!0)?!1:void 0}),n.parent.bubble("workingGroupChange"),t}this.onNotify(function(t){("move"===t||"upDown"===t)&&this.show().clearSelection()}),t.escapeDir=function(t,e,n){r(t);var i=this.cursor;return i.parent!==this.root&&n.preventDefault(),i.parent!==this.root?(i.parent.moveOutOf(t,i),i.parent.bubble("workingGroupChange"),this.notify("move")):void 0},b.leftRightIntoCmdGoes=function(t){if(t&&"up"!==t&&"down"!==t)throw'"up" or "down" required for leftRightIntoCmdGoes option, got "'+t+'"';return t},t.moveDir=function(t){r(t);var e=this.cursor,n=e.options.leftRightIntoCmdGoes;return e.selection?e.insDirOf(t,e.selection.ends[t]):e[t]?e[t].moveTowards(t,e,n):e.parent.moveOutOf(t,e,n),e.parent.bubble("workingGroupChange"),this.notify("move")},t.moveLeft=function(){return this.moveDir(Ce)},t.moveRight=function(){return this.moveDir(je)},t.moveUp=function(){return e(this,"up")},t.moveDown=function(){return e(this,"down")},this.onNotify(function(t){"upDown"!==t&&(this.upDownCache={})}),this.onNotify(function(t){"edit"===t&&this.show().deleteSelection()}),t.deleteDir=function(t){var e,n;return r(t),e=this.cursor,n=e.selection,this.notify("edit"),n||(e[t]?e[t].deleteTowards(t,e):e.parent.deleteOutOf(t,e)),e[Ce].siblingDeleted&&e[Ce].siblingDeleted(e.options,je),e[je].siblingDeleted&&e[je].siblingDeleted(e.options,Ce),e.parent.bubble("reflow"),e.parent.bubble("workingGroupChange"),this},t.backspace=function(){return this.deleteDir(Ce)},t.deleteForward=function(){return this.deleteDir(je)},this.onNotify(function(t){"select"!==t&&this.endSelection()}),t.selectDir=function(t){var e,n=this.notify("select").cursor,i=n.selection;r(t),n.anticursor||n.startSelection(),e=n[t],e?i&&i.ends[t]===e&&n.anticursor[-t]!==e?e.unselectInto(t,n):e.selectTowards(t,n):n.parent.selectOutOf(t,n),n.clearSelection(),n.select()||n.show()},t.selectLeft=function(){return this.selectDir(Ce)},t.selectRight=function(){return this.selectDir(je)}}),k=function(){function t(t){var e=S();return t.adopt(e,0,0),e}function e(t){var e,n=t[0]||S();for(e=1;e<t.length;e+=1)t[e].children().adopt(n,n.ends[je],0);return n}var n=q.string,i=q.regex,s=q.letter,r=q.any,o=q.optWhitespace,a=q.succeed,l=q.fail,c=s.map(function(t){return I(t)}),h=i(/^[^${}\\_^]/).map(function(t){return j(t)}),u=i(/^[^\\a-eg-zA-Z]/).or(n("\\").then(i(/^[a-z]+/i).or(i(/^\s+/).result(" ")).or(r))).then(function(t){var e=De[t];return e?e(t).parser():l("unknown command: \\"+t)}),p=u.or(c).or(h),f=n("{").then(function(){return m}).skip(n("}")),d=o.then(f.or(p.map(t))),m=d.many().map(e).skip(o),g=n("[").then(d.then(function(t){return"]"!==t.join("latex")?a(t):l()}).many().map(e).skip(o)).skip(n("]")),b=m;return b.block=d,b.optBlock=g,b}(),Re.open(function(t){t.exportLatex=function(){return this.root.latex().replace(/(\\[a-z]+) (?![a-z])/gi,"$1")},t.writeLatex=function(t){var e,n=this.notify("edit").cursor,i=q.all,s=q.eof,r=k.skip(s).or(i.result(!1)).parse(t);return r&&!r.isEmpty()&&(r.children().adopt(n.parent,n[Ce],n[je]),e=r.jQize(),e.insertBefore(n.jQ),n[Ce]=r.ends[je],r.finalizeInsert(n.options,n),r.ends[je][je].siblingCreated&&r.ends[je][je].siblingCreated(n.options,Ce),r.ends[Ce][Ce].siblingCreated&&r.ends[Ce][Ce].siblingCreated(n.options,je),n.parent.bubble("reflow")),this},t.renderLatexMath=function(t){var e,n,i=this.root,s=this.cursor,r=q.all,o=q.eof,a=k.skip(o).or(r.result(!1)).parse(t);i.eachChild("postOrder","dispose"),i.ends[Ce]=i.ends[je]=0,a&&a.children().adopt(i,0,0),e=i.jQ,a?(n=a.join("html"),e.html(n),i.jQize(e.children()),i.finalizeInsert(s.options)):e.empty(),delete s.selection,s.insAtRightEnd(i)},t.renderLatexText=function(t){var e,n,i,s,r,o,a,l,c,h,u=this.root,p=this.cursor;if(u.jQ.children().slice(1).remove(),u.eachChild("postOrder","dispose"),u.ends[Ce]=u.ends[je]=0,delete p.selection,p.show().insAtRightEnd(u),e=q.regex,n=q.string,i=q.eof,s=q.all,r=n("$").then(k).skip(n("$").or(i)).map(function(t){var e,n=_(p);return n.createBlocks(),e=n.ends[Ce],t.children().adopt(e,0,0),n}),o=n("\\$").result("$"),a=o.or(e(/^[^$]/)).map(j),l=r.or(a).many(),c=l.skip(i).or(s.result(!1)).parse(t)){for(h=0;h<c.length;h+=1)c[h].adopt(u,u.ends[je],0);u.jQize().appendTo(u.jQ),u.finalizeInsert(p.options)}}}),Re.open(function(e){e.delegateMouseEvents=function(){var e=this.root.jQ;this.container.bind("contextmenu.mathquill",function(t){for(var n=Qe(t.target).closest(".mq-root-block"),i=Te.byId[n.attr(we)||e.attr(we)],s=i.controller,r=s.cursor,o=s.seek(Qe(t.target),t.pageX,t.pageY).cursor.parent;!(o instanceof y);)if(o=o.parent,"undefined"==typeof o){o=i;break}return o.contextMenu(r,t),t.preventDefault(),!1}),this.container.bind("mousedown.mathquill",function(n){function i(t){o=Qe(t.target)}function s(t){h.anticursor||h.startSelection(),c.seek(o,t.pageX,t.pageY).cursor.select(),o=d}function r(t){h.blink=u,h.selection||(c.editable?h.show():p.detach()),a.unbind("mousemove",i),Qe(t.target.ownerDocument).unbind("mousemove",s).unbind("mouseup",r)}var o,a=Qe(n.target).closest(".mq-root-block"),l=Te.byId[a.attr(we)||e.attr(we)],c=l.controller,h=c.cursor,u=h.blink,p=c.textareaSpan,f=c.textarea;c.blurred&&(c.editable||a.prepend(p),f.focus()),n.preventDefault(),n.target.unselectable=!0,h.blink=t,c.seek(Qe(n.target),n.pageX,n.pageY).cursor.startSelection(),a.mousemove(i),Qe(n.target.ownerDocument).mousemove(s).mouseup(r)})}}),Re.open(function(t){t.seek=function(t,e){var n,i,r,o=this.notify("select").cursor;return t&&(n=t.attr(we)||t.attr(ve),n||(i=t.parent(),n=i.attr(we)||i.attr(ve))),r=n?Te.byId[n]:this.root,s("nodeId is the id of some Node that exists",r),o.clearSelection().show(),r.seek(e,o),this.scrollHoriz(),o.parent.bubble("workingGroupChange"),this}}),Re.open(function(t){t.scrollHoriz=function(){var t,e,n,i,s,r=this.cursor,o=r.selection,a=this.root.jQ[0].getBoundingClientRect();if(o)if(n=o.jQ[0].getBoundingClientRect(),i=n.left-(a.left+20),s=n.right-(a.right-20),o.ends[Ce]===r[je])if(0>i)e=i;else{if(!(s>0))return;e=n.left-s<a.left+20?i:s}else if(s>0)e=s;else{if(!(0>i))return;e=n.right-i>a.right-20?s:i}else if(t=r.jQ[0].getBoundingClientRect().left,t>a.right-20)e=t-(a.right-20);else{if(!(t<a.left+20))return;e=t-(a.left+20)}this.root.jQ.stop().animate({scrollLeft:"+="+e},100)}}),Re.open(function(t){g.p.substituteTextarea=function(){return Qe("<textarea>")[0]},t.createTextarea=function(){var t,e=this.textareaSpan=Qe('<span class="mq-textarea"></span>'),n=this.API.__options.substituteTextarea();if(!n.nodeType)throw"substituteTextarea() must return a DOM element, got "+n;n=this.textarea=Qe(n).appendTo(e),t=this,t.cursor.selectionChanged=function(){t.selectionChanged()},t.container.bind("copy",function(){t.setTextareaSelection()})},t.selectionChanged=function(){var t=this;X(t.container[0]),t.textareaSelectionTimeout===d&&(t.textareaSelectionTimeout=setTimeout(function(){t.setTextareaSelection()}))},t.setTextareaSelection=function(){this.textareaSelectionTimeout=d;var t="";this.cursor.selection&&(t=this.cursor.selection.join("latex"),this.API.__options.statelessClipboard&&(t="$"+t+"$")),this.selectFn(t)},t.staticMathTextareaEvents=function(){function t(){s.detach(),e.blurred=!0}var e=this,n=(e.root,e.cursor),i=e.textarea,s=e.textareaSpan;this.container.prepend('<span class="mq-selectable">$'+e.exportLatex()+"$</span>"),e.blurred=!0,i.bind("cut paste",!1).focus(function(){e.blurred=!1}).blur(function(){n.selection&&n.selection.clear(),setTimeout(t)}),e.selectFn=function(t){i.val(t),t&&i.select()}},t.editablesTextareaEvents=function(){var t=this,e=(t.root,t.cursor),n=t.textarea,i=t.textareaSpan,s=x(n,this);this.selectFn=function(t){s.select(t)},this.container.prepend(i).on("cut",function(){e.selection&&setTimeout(function(){t.notify("edit"),e.parent.bubble("reflow")})}),this.focusBlurEvents()},t.typedText=function(t){if("\n"===t)return this.handle("enter");var e=this.notify().cursor;e.parent.write(e,t,e.show().replaceSelection()),this.scrollHoriz()},t.paste=function(t){this.API.__options.statelessClipboard&&(t="$"===t.slice(0,1)&&"$"===t.slice(-1)?t.slice(1,-1):"\\text{"+t+"}"),this.writeLatex(t).cursor.show()}}),O=ye(Te,function(t){t.finalizeInsert=function(t,e){var n=this;n.postOrder("finalizeTree",t),n.postOrder("contactWeld",e),n.postOrder("blur"),n.postOrder("reflow"),n[je].siblingCreated&&n[je].siblingCreated(t,Ce),n[Ce].siblingCreated&&n[Ce].siblingCreated(t,je),n.bubble("reflow")},t.contextMenu=function(){},t.showPopupMenu=function(t,e){var n,i;for(1==Qe("#mq-popup-menu").length&&Qe("#mq-popup-menu").remove(),n=Qe("<ul></ul>").attr("id","mq-popup-menu").appendTo("body"),i=0;i<t.length;i++)Qe("<li></li>").attr("mq-menu-id",i).html(t[i].text).appendTo(n);n.menu({select:function(e,i){var s=1*i.item.attr("mq-menu-id");t[s].handler(e),n.hide()}}),n.position({my:"left top",of:e}),n.show(),Qe(document).bind("click",function(t){n.hide(),Qe(this).unbind(t)})}}),y=ye(O,function(t,e){t.init=function(t,n,i){var s=this;e.init.call(s),s.ctrlSeq||(s.ctrlSeq=t),n&&(s.htmlTemplate=n),i&&(s.textTemplate=i)},t.replaces=function(t){t.disown(),this.replacedFragment=t},t.isEmpty=function(){return this.foldChildren(!0,function(t,e){return t&&e.isEmpty()})},t.parser=function(){var t=k.block,e=this;return t.times(e.numBlocks()).map(function(t){e.blocks=t;for(var n=0;n<t.length;n+=1)t[n].adopt(e,e.ends[je],0);return e})},t.createLeftOf=function(t){var n,i=this;if(t.options.enableMatrixShortcuts&&"undefined"!=typeof t.parent&&"undefined"!=typeof t.parent&&t.parent.parent instanceof ue){if(","==i.ctrlSeq)return t.parent.parent.moveOrInsertColumn(t);if(";"==i.ctrlSeq)return t.parent.parent.insertRow(t);if(":"==i.ctrlSeq)return t.parent.parent.deleteRow(t);if("<"==i.ctrlSeq)return t.parent.parent.deleteColumn(t);if(">"==i.ctrlSeq)return t.parent.parent.insertColumn(t)}n=i.replacedFragment,i.createBlocks(),e.createLeftOf.call(i,t),n&&(n.adopt(i.ends[Ce],0,0),n.jQ.appendTo(i.ends[Ce].jQ)),i.finalizeInsert(t.options),i.placeCursor(t),(this instanceof Q||this instanceof oe||this instanceof se||this instanceof le)&&this.bubble("workingGroupChange")},t.createBlocks=function(){var t,e,n=this,i=n.numBlocks(),s=n.blocks=Array(i);for(t=0;i>t;t+=1)e=s[t]=S(),e.adopt(n,n.ends[je],0)},t.placeCursor=function(t){t.insAtRightEnd(this.foldChildren(this.ends[Ce],function(t,e){return t.isEmpty()?t:e}))},t.moveTowards=function(t,e,n){var i=n&&this[n+"Into"];e.insAtDirEnd(-t,i||this.ends[-t])},t.deleteTowards=function(t,e){e.startSelection(),this.selectTowards(t,e),e.select()},t.selectTowards=function(t,e){e[-t]=this,e[t]=this[t]},t.selectChildren=function(){return Ee(this,this)},t.unselectInto=function(t,e){e.insAtDirEnd(-t,e.anticursor.ancestors[this.id])},t.seek=function(t,e){function n(t){var e={};return e[Ce]=t.jQ.offset().left,e[je]=e[Ce]+t.jQ.outerWidth(),e}var i,s=this,r=n(s);return t<r[Ce]?e.insLeftOf(s):t>r[je]?e.insRightOf(s):(i=r[Ce],void s.eachChild(function(o){var a=n(o);return t<a[Ce]?(t-i<a[Ce]-t?o[Ce]?e.insAtRightEnd(o[Ce]):e.insLeftOf(s):e.insAtLeftEnd(o),!1):t>a[je]?void(o[je]?i=a[je]:r[je]-t<t-a[je]?e.insRightOf(s):e.insAtRightEnd(o)):(o.seek(t,e),!1)}))},t.numBlocks=function(){var t=this.htmlTemplate.match(/&\d+/g);return t?t.length:0},t.html=function(){var t,e,n,i=this,r=i.blocks,o=" mathquill-command-id="+i.id,a=i.htmlTemplate.match(/<[^<>]+>|[^<>]+/g);for(s("no unmatched angle brackets",a.join("")===this.htmlTemplate),t=0,e=a[0];e;t+=1,e=a[t])if("/>"===e.slice(-2))a[t]=e.slice(0,-2)+o+"/>";else if("<"===e.charAt(0)){s("not an unmatched top-level close tag","/"!==e.charAt(1)),a[t]=e.slice(0,-1)+o+">",n=1;do t+=1,e=a[t],s("no missing close tags",e),"</"===e.slice(0,2)?n-=1:"<"===e.charAt(0)&&"/>"!==e.slice(-2)&&(n+=1);while(n>0)}return a.join("").replace(/>&(\d+)/g,function(t,e){return" mathquill-block-id="+r[e].id+">"+r[e].join("html")})},t.latex=function(){return this.foldChildren(this.ctrlSeq,function(t,e){return t+"{"+(e.latex()||" ")+"}"})},t.textTemplate=[""],t.text=function(t){var e=this,n=0;return e.foldChildren(e.textTemplate[n],function(i,s){n+=1;var r=s.text(t);return i&&"("===e.textTemplate[n]&&"("===r[0]&&")"===r.slice(-1)?i+r.slice(1,-1)+e.textTemplate[n]:i+s.text(t)+(e.textTemplate[n]||"")})}}),C=ye(y,function(e,n){e.init=function(t,e,i){i||(i=t&&t.length>1?t.slice(1):t),n.init.call(this,t,e,[i])},e.parser=function(){return q.succeed(this)},e.numBlocks=function(){return 0},e.replaces=function(t){t.remove() +},e.createBlocks=t,e.moveTowards=function(t,e){e.jQ.insDirOf(t,this.jQ),e[-t]=this,e[t]=this[t]},e.deleteTowards=function(t,e){e[t]=this.remove()[t]},e.seek=function(t,e){t-this.jQ.offset().left<this.jQ.outerWidth()/2?e.insLeftOf(this):e.insRightOf(this)},e.latex=function(){return this.ctrlSeq},e.text=function(){return this.textTemplate},e.placeCursor=t,e.isEmpty=function(){return!0}}),j=ye(C,function(t,e){t.init=function(t,n){e.init.call(this,t,"<span>"+(n||t)+"</span>")}}),Q=ye(C,function(t,e){t.init=function(t,n,i){e.init.call(this,t,'<span class="mq-binary-operator">'+n+"</span>",i)}}),S=ye(O,function(t,e){t.join=function(t){return this.foldChildren("",function(e,n){return e+n[t]()})},t.html=function(){return this.join("html")},t.latex=function(){return this.join("latex")},t.text=function(t){return 0===this.ends[Ce]&&0===this.ends[je]?"":this.ends[Ce]===this.ends[je]?this.ends[Ce].text(t):this.foldChildren("",function(e,n){return e+n.text(t)})},t.keystroke=function(t,n,i){return!i.API.__options.spaceBehavesLikeTab||"Spacebar"!==t&&"Shift-Spacebar"!==t?e.keystroke.apply(this,arguments):(n.preventDefault(),void i.escapeDir("Shift-Spacebar"===t?Ce:je,t,n))},t.moveOutOf=function(t,e,n){var i=n&&this.parent[n+"Into"];!i&&this[t]?e.insAtDirEnd(-t,this[t]):e.insDirOf(t,this.parent)},t.selectOutOf=function(t,e){e.insDirOf(t,this.parent)},t.deleteOutOf=function(t,e){e.unwrapGramp()},t.seek=function(t,e){var n=this.ends[je];if(!n||n.jQ.offset().left+n.jQ.outerWidth()<t)return e.insAtRightEnd(this);if(t<this.ends[Ce].jQ.offset().left)return e.insAtLeftEnd(this);for(;t<n.jQ.offset().left;)n=n[Ce];return n.seek(t,e)},t.write=function(t,e,n){var i;i=e.match(/^[a-eg-zA-Z]$/)?I(e):(i=_e[e]||De[e])?i(e):j(e),n&&i.replaces(n),i.createLeftOf(t)},t.focus=function(){return this.jQ.addClass("mq-hasCursor"),this.jQ.removeClass("mq-empty"),this},t.blur=function(){return this.jQ.removeClass("mq-hasCursor"),this.isEmpty()&&this.jQ.addClass("mq-empty"),this}}),T=ye(S,c),a.MathField=l(ye(w,function(t){t.init=function(t,e){t.addClass("mq-editable-field mq-math-mode"),this.initRootAndEvents(T(),t,e)}})),A=ye(Te,function(t,e){function n(t){var e,n;return t.jQ[0].normalize(),e=t.jQ[0].firstChild,n=D(e.data),n.jQadd(e),t.children().disown(),n.adopt(t,0,0)}t.ctrlSeq="\\text",t.replaces=function(t){t instanceof Ae?this.replacedText=t.remove().jQ.text():"string"==typeof t&&(this.replacedText=t)},t.jQadd=function(t){e.jQadd.call(this,t),this.ends[Ce]&&this.ends[Ce].jQadd(this.jQ[0].firstChild)},t.createLeftOf=function(t){var n,i=this;if(e.createLeftOf.call(this,t),i[je].siblingCreated&&i[je].siblingCreated(t.options,Ce),i[Ce].siblingCreated&&i[Ce].siblingCreated(t.options,je),i.bubble("reflow"),t.insAtRightEnd(i),i.replacedText)for(n=0;n<i.replacedText.length;n+=1)i.write(t,i.replacedText.charAt(n))},t.parser=function(){var t=this,e=q.string,n=q.regex,i=q.optWhitespace;return i.then(e("{")).then(n(/^[^}]*/)).skip(e("}")).map(function(e){return D(e).adopt(t,0,0),t})},t.textContents=function(){return this.foldChildren("",function(t,e){return t+e.text})},t.text=function(t){return t.dropTextFieldsOnTextOutput?"":'"'+this.textContents()+'"'},t.latex=function(){return"\\text{"+this.textContents()+"}"},t.html=function(){return'<span class="mq-text-mode" mathquill-command-id='+this.id+">"+this.textContents()+"</span>"},t.moveTowards=function(t,e){e.insAtDirEnd(-t,this)},t.moveOutOf=function(t,e){e.insDirOf(t,this)},t.unselectInto=t.moveTowards,t.selectTowards=y.prototype.selectTowards,t.deleteTowards=y.prototype.deleteTowards,t.selectOutOf=function(t,e){e.insDirOf(t,this)},t.deleteOutOf=function(t,e){this.isEmpty()&&e.insRightOf(this)},t.write=function(t,n,i){var s,r;i&&i.remove(),"$"!==n?t[Ce]?t[Ce].appendText(n):D(n).createLeftOf(t):this.isEmpty()?(t.insRightOf(this),j("\\$","$").createLeftOf(t)):t[je]?t[Ce]?(s=A(),r=this.ends[Ce],r.disown(),r.adopt(s,0,0),t.insLeftOf(this),e.createLeftOf.call(s,t)):t.insLeftOf(this):t.insRightOf(this)},t.seek=function(t,e){var i,s,r,o,a,l,c,h;for(e.hide(),i=n(this),s=this.jQ.width()/this.text.length,r=Math.round((t-this.jQ.offset().left)/s),0>=r?e.insAtLeftEnd(this):r>=i.text.length?e.insAtRightEnd(this):e.insLeftOf(i.splitRight(r)),o=t-e.show().offset().left,a=o&&0>o?Ce:je,l=a;e[a]&&o*l>0;)e[a].moveTowards(a,e),l=o,o=t-e.offset().left;-a*l>a*o&&e[-a].moveTowards(-a,e),e.anticursor?e.anticursor.parent===this&&(c=e[Ce]&&e[Ce].text.length,this.anticursorPosition===c?e.anticursor=Se.copy(e):(this.anticursorPosition<c?(h=e[Ce].splitRight(this.anticursorPosition),e[Ce]=h):h=e[je].splitRight(this.anticursorPosition-c),e.anticursor=Se(this,h[Ce],h))):this.anticursorPosition=e[Ce]&&e[Ce].text.length},t.blur=function(){S.prototype.blur.call(this),n(this)},t.focus=S.prototype.focus}),D=ye(Te,function(t,e){function n(t,e){return e.charAt(t===Ce?0:-1+e.length)}t.init=function(t){e.init.call(this),this.text=t},t.jQadd=function(t){this.dom=t,this.jQ=Qe(t)},t.jQize=function(){return this.jQadd(document.createTextNode(this.text))},t.appendText=function(t){this.text+=t,this.dom.appendData(t)},t.prependText=function(t){this.text=t+this.text,this.dom.insertData(0,t)},t.insTextAtDirEnd=function(t,e){r(e),e===je?this.appendText(t):this.prependText(t)},t.splitRight=function(t){var e=D(this.text.slice(t)).adopt(this.parent,this,this[je]);return e.jQadd(this.dom.splitText(t)),this.text=this.text.slice(0,t),e},t.moveTowards=function(t,e){var i,s;return r(t),i=n(-t,this.text),s=this[-t],s?s.insTextAtDirEnd(i,t):D(i).createDir(-t,e),this.deleteTowards(t,e)},t.latex=function(){return this.text},t.deleteTowards=function(t,e){this.text.length>1?t===je?(this.dom.deleteData(0,1),this.text=this.text.slice(1)):(this.dom.deleteData(-1+this.text.length,1),this.text=this.text.slice(0,-1)):(this.remove(),this.jQ.remove(),e[t]=this[t])},t.selectTowards=function(t,e){var i,s,o,a;return r(t),i=e.anticursor,s=n(-t,this.text),i[t]===this?(o=D(s).createDir(t,e),i[t]=o,e.insDirOf(t,o)):(a=this[-t],a?a.insTextAtDirEnd(s,t):(o=D(s).createDir(-t,e),o.jQ.insDirOf(-t,e.selection.jQ)),1===this.text.length&&i[-t]===this&&(i[-t]=this[-t])),this.deleteTowards(t,e)}}),_e.$=De.text=De.textnormal=De.textrm=De.textup=De.textmd=A,De.em=De.italic=De.italics=De.emph=De.textit=De.textsl=h("\\textit","i",'class="mq-text-mode"'),De.strong=De.bold=De.textbf=h("\\textbf","b",'class="mq-text-mode"'),De.sf=De.textsf=h("\\textsf","span",'class="mq-sans-serif mq-text-mode"'),De.tt=De.texttt=h("\\texttt","span",'class="mq-monospace mq-text-mode"'),De.textsc=h("\\textsc","span",'style="font-variant:small-caps" class="mq-text-mode"'),De.uppercase=h("\\uppercase","span",'style="text-transform:uppercase" class="mq-text-mode"'),De.lowercase=h("\\lowercase","span",'style="text-transform:lowercase" class="mq-text-mode"'),_=ye(y,function(t,e){t.init=function(t){e.init.call(this,"$"),this.cursor=t},t.htmlTemplate='<span class="mq-math-mode">&0</span>',t.createBlocks=function(){e.createBlocks.call(this),this.ends[Ce].cursor=this.cursor,this.ends[Ce].write=function(t,e,n){"$"!==e?S.prototype.write.call(this,t,e,n):this.isEmpty()?(t.insRightOf(this.parent),this.parent.deleteTowards(dir,t),j("\\$","$").createLeftOf(t.show())):t[je]?t[Ce]?S.prototype.write.call(this,t,e,n):t.insLeftOf(this.parent):t.insRightOf(this.parent)}},t.latex=function(){return"$"+this.ends[Ce].latex()+"$"}}),L=ye(T,function(t,e){t.keystroke=function(t){return"Spacebar"!==t&&"Shift-Spacebar"!==t?e.keystroke.apply(this,arguments):void 0},t.write=function(t,e,n){if(n&&n.remove(),"$"===e)_(t).createLeftOf(t);else{var i;"<"===e?i="&lt;":">"===e&&(i="&gt;"),j(e,i).createLeftOf(t)}}}),a.TextField=l(ye(w,function(t){t.init=function(t){t.addClass("mq-editable-field mq-text-mode"),this.initRootAndEvents(L(),t)},t.latex=function(t){return arguments.length>0?(this.__controller.renderLatexText(t),this.__controller.blurred&&this.__controller.cursor.hide().parent.blur(),this):this.__controller.exportLatex()}})),E=_e["\\"]=ye(y,function(t,e){t.ctrlSeq="\\",t.replaces=function(t){this._replacedFragment=t.disown(),this.isEmpty=function(){return!1}},t.htmlTemplate='<span class="mq-latex-command-input mq-non-leaf">\\<span>&0</span></span>',t.textTemplate=["\\"],t.createBlocks=function(){e.createBlocks.call(this),this.ends[Ce].focus=function(){return this.parent.jQ.addClass("mq-hasCursor"),this.isEmpty()&&this.parent.jQ.removeClass("mq-empty"),this},this.ends[Ce].blur=function(){return this.parent.jQ.removeClass("mq-hasCursor"),this.isEmpty()&&this.parent.jQ.addClass("mq-empty"),this},this.ends[Ce].write=function(t,e,n){return n&&n.remove(),0==this.parent.ends[Ce].latex().indexOf("matrix")?void(/^matrix\dx\d$/.test(this.parent.ends[Ce].latex())?(this.parent.renderCommand(t),"\\"===e&&this.isEmpty()||this.parent.parent.write(t,e)):j(e).createLeftOf(t)):void(e.match(/[a-z]/i)?j(e).createLeftOf(t):(this.parent.renderCommand(t),"\\"===e&&this.isEmpty()||this.parent.parent.write(t,e)))},this.ends[Ce].keystroke=function(t,n,i){return"Tab"===t||"Enter"===t||"Spacebar"===t?(this.parent.renderCommand(i.cursor),void n.preventDefault()):e.keystroke.apply(this,arguments)}},t.createLeftOf=function(t){if(e.createLeftOf.call(this,t),this._replacedFragment){var n=this.jQ[0];this.jQ=this._replacedFragment.jQ.addClass("mq-blur").bind("mousedown mousemove",function(t){return Qe(t.target=n).trigger(t),!1}).insertBefore(this.jQ).add(this.jQ)}},t.latex=function(){return"\\"+this.ends[Ce].latex()+" "},t.renderCommand=function(t){var e,n;this.jQ=this.jQ.last(),this.remove(),this[je]?t.insLeftOf(this[je]):t.insAtRightEnd(this.parent),e=this.ends[Ce].latex(),e||(e=" "),n=De[e],n?(n=n(e),this._replacedFragment&&n.replaces(this._replacedFragment),n.createLeftOf(t)):(n=A(),n.replaces(e),n.createLeftOf(t),t.insRightOf(n),this._replacedFragment&&this._replacedFragment.remove())}}),De.notin=De.sim=De.cong=De.equiv=De.oplus=De.otimes=ye(Q,function(t,e){t.init=function(t){e.init.call(this,"\\"+t+" ","&"+t+";")}}),De["≠"]=De.ne=De.neq=i(Q,"\\ne ","&ne;"),De.ast=De.star=De.loast=De.lowast=i(Q,"\\ast ","&lowast;"),De.therefor=De.therefore=i(Q,"\\therefore ","&there4;"),De.cuz=De.because=i(Q,"\\because ","&#8757;"),De.prop=De.propto=i(Q,"\\propto ","&prop;"),De["≈"]=De.asymp=De.approx=i(Q,"\\approx ","&asymp;"),De.isin=De["in"]=i(Q,"\\in ","&isin;"),De.ni=De.contains=i(Q,"\\ni ","&ni;"),De.notni=De.niton=De.notcontains=De.doesnotcontain=i(Q,"\\not\\ni ","&#8716;"),De.sub=De.subset=i(Q,"\\subset ","&sub;"),De.sup=De.supset=De.superset=i(Q,"\\supset ","&sup;"),De.nsub=De.notsub=De.nsubset=De.notsubset=i(Q,"\\not\\subset ","&#8836;"),De.nsup=De.notsup=De.nsupset=De.notsupset=De.nsuperset=De.notsuperset=i(Q,"\\not\\supset ","&#8837;"),De.sube=De.subeq=De.subsete=De.subseteq=i(Q,"\\subseteq ","&sube;"),De.supe=De.supeq=De.supsete=De.supseteq=De.supersete=De.superseteq=i(Q,"\\supseteq ","&supe;"),De.nsube=De.nsubeq=De.notsube=De.notsubeq=De.nsubsete=De.nsubseteq=De.notsubsete=De.notsubseteq=i(Q,"\\not\\subseteq ","&#8840;"),De.nsupe=De.nsupeq=De.notsupe=De.notsupeq=De.nsupsete=De.nsupseteq=De.notsupsete=De.notsupseteq=De.nsupersete=De.nsuperseteq=De.notsupersete=De.notsuperseteq=i(Q,"\\not\\supseteq ","&#8841;"),De.N=De.naturals=De.Naturals=i(j,"\\mathbb{N}","&#8469;"),De.P=De.primes=De.Primes=De.projective=De.Projective=De.probability=De.Probability=i(j,"\\mathbb{P}","&#8473;"),De.Z=De.integers=De.Integers=i(j,"\\mathbb{Z}","&#8484;"),De.Q=De.rationals=De.Rationals=i(j,"\\mathbb{Q}","&#8474;"),De.R=De.reals=De.Reals=i(j,"\\mathbb{R}","&#8477;"),De.C=De.complex=De.Complex=De.complexes=De.Complexes=De.complexplane=De.Complexplane=De.ComplexPlane=i(j,"\\mathbb{C}","&#8450;"),De.H=De.Hamiltonian=De.quaternions=De.Quaternions=i(j,"\\mathbb{H}","&#8461;"),De.quad=De.emsp=i(j,"\\quad "," "),De.qquad=i(j,"\\qquad "," "),De.diamond=i(j,"\\diamond ","&#9671;"),De.bigtriangleup=i(j,"\\bigtriangleup ","&#9651;"),De.ominus=i(j,"\\ominus ","&#8854;"),De.uplus=i(j,"\\uplus ","&#8846;"),De.bigtriangledown=i(j,"\\bigtriangledown ","&#9661;"),De.sqcap=i(j,"\\sqcap ","&#8851;"),De.triangleleft=i(j,"\\triangleleft ","&#8882;"),De.sqcup=i(j,"\\sqcup ","&#8852;"),De.triangleright=i(j,"\\triangleright ","&#8883;"),De.odot=i(j,"\\odot ","&#8857;"),De.bigcirc=i(j,"\\bigcirc ","&#9711;"),De.dagger=i(j,"\\dagger ","&#0134;"),De.ddagger=i(j,"\\ddagger ","&#135;"),De.wr=i(j,"\\wr ","&#8768;"),De.amalg=i(j,"\\amalg ","&#8720;"),De.models=i(j,"\\models ","&#8872;"),De.prec=i(j,"\\prec ","&#8826;"),De.succ=i(j,"\\succ ","&#8827;"),De.preceq=i(j,"\\preceq ","&#8828;"),De.succeq=i(j,"\\succeq ","&#8829;"),De.simeq=i(j,"\\simeq ","&#8771;"),De.mid=i(j,"\\mid ","&#8739;"),De.ll=i(j,"\\ll ","&#8810;"),De.gg=i(j,"\\gg ","&#8811;"),De.parallel=i(j,"\\parallel ","&#8741;"),De.bowtie=i(j,"\\bowtie ","&#8904;"),De.sqsubset=i(j,"\\sqsubset ","&#8847;"),De.sqsupset=i(j,"\\sqsupset ","&#8848;"),De.smile=i(j,"\\smile ","&#8995;"),De.sqsubseteq=i(j,"\\sqsubseteq ","&#8849;"),De.sqsupseteq=i(j,"\\sqsupseteq ","&#8850;"),De.doteq=i(j,"\\doteq ","&#8784;"),De.frown=i(j,"\\frown ","&#8994;"),De.vdash=i(j,"\\vdash ","&#8870;"),De.dashv=i(j,"\\dashv ","&#8867;"),De.longleftarrow=i(j,"\\longleftarrow ","&#8592;"),De.longrightarrow=i(j,"\\longrightarrow ","&#8594;"),De.Longleftarrow=i(j,"\\Longleftarrow ","&#8656;"),De.Longrightarrow=i(j,"\\Longrightarrow ","&#8658;"),De.longleftrightarrow=i(j,"\\longleftrightarrow ","&#8596;"),De.updownarrow=i(j,"\\updownarrow ","&#8597;"),De.Longleftrightarrow=i(j,"\\Longleftrightarrow ","&#8660;"),De.Updownarrow=i(j,"\\Updownarrow ","&#8661;"),De.mapsto=i(j,"\\mapsto ","&#8614;"),De.nearrow=i(j,"\\nearrow ","&#8599;"),De.hookleftarrow=i(j,"\\hookleftarrow ","&#8617;"),De.hookrightarrow=i(j,"\\hookrightarrow ","&#8618;"),De.searrow=i(j,"\\searrow ","&#8600;"),De.leftharpoonup=i(j,"\\leftharpoonup ","&#8636;"),De.rightharpoonup=i(j,"\\rightharpoonup ","&#8640;"),De.swarrow=i(j,"\\swarrow ","&#8601;"),De.leftharpoondown=i(j,"\\leftharpoondown ","&#8637;"),De.rightharpoondown=i(j,"\\rightharpoondown ","&#8641;"),De.nwarrow=i(j,"\\nwarrow ","&#8598;"),De.ldots=i(j,"\\ldots ","&#8230;"),De.cdots=i(j,"\\cdots ","&#8943;"),De.vdots=i(j,"\\vdots ","&#8942;"),De.ddots=i(j,"\\ddots ","&#8944;"),De.surd=i(j,"\\surd ","&#8730;"),De.triangle=i(j,"\\triangle ","&#9653;"),De.ell=i(j,"\\ell ","&#8467;"),De.top=i(j,"\\top ","&#8868;"),De.flat=i(j,"\\flat ","&#9837;"),De.natural=i(j,"\\natural ","&#9838;"),De.sharp=i(j,"\\sharp ","&#9839;"),De.wp=i(j,"\\wp ","&#8472;"),De.bot=i(j,"\\bot ","&#8869;"),De.clubsuit=i(j,"\\clubsuit ","&#9827;"),De.diamondsuit=i(j,"\\diamondsuit ","&#9826;"),De.heartsuit=i(j,"\\heartsuit ","&#9825;"),De.spadesuit=i(j,"\\spadesuit ","&#9824;"),De.oint=i(j,"\\oint ","&#8750;"),De.bigcap=i(j,"\\bigcap ","&#8745;"),De.bigcup=i(j,"\\bigcup ","&#8746;"),De.bigsqcup=i(j,"\\bigsqcup ","&#8852;"),De.bigvee=i(j,"\\bigvee ","&#8744;"),De.bigwedge=i(j,"\\bigwedge ","&#8743;"),De.bigodot=i(j,"\\bigodot ","&#8857;"),De.bigotimes=i(j,"\\bigotimes ","&#8855;"),De.bigoplus=i(j,"\\bigoplus ","&#8853;"),De.biguplus=i(j,"\\biguplus ","&#8846;"),De.lfloor=i(j,"\\lfloor ","&#8970;"),De.rfloor=i(j,"\\rfloor ","&#8971;"),De.lceil=i(j,"\\lceil ","&#8968;"),De.rceil=i(j,"\\rceil ","&#8969;"),De.opencurlybrace=De.lbrace=i(j,"\\lbrace ","{"),De.closecurlybrace=De.rbrace=i(j,"\\rbrace ","}"),De["∫"]=De["int"]=De.integral=i(C,"\\int ","<big>&int;</big>"),De.caret=i(j,"\\text{^}","^"),De.underscore=i(j,"\\_","_"),De.slash=i(j,"/"),De.vert=i(j,"|"),De.perp=De.perpendicular=i(j,"\\perp ","&perp;"),De.nabla=De.del=i(j,"\\nabla ","&nabla;"),De.hbar=i(j,"\\hbar ","&#8463;"),De.AA=De.Angstrom=De.angstrom=i(j,"\\text\\AA ","&#8491;"),De.ring=De.circ=De.circle=i(j,"\\circ ","&#8728;"),De.bull=De.bullet=i(j,"\\bullet ","&bull;"),De.setminus=De.smallsetminus=i(j,"\\setminus ","&#8726;"),De.not=De["¬"]=De.neg=i(j,"\\neg ","&not;"),De["…"]=De.dots=De.ellip=De.hellip=De.ellipsis=De.hellipsis=i(j,"\\dots ","&hellip;"),De.converges=De.darr=De.dnarr=De.dnarrow=De.downarrow=i(j,"\\downarrow ","&darr;"),De.dArr=De.dnArr=De.dnArrow=De.Downarrow=i(j,"\\Downarrow ","&dArr;"),De.diverges=De.uarr=De.uparrow=i(j,"\\uparrow ","&uarr;"),De.uArr=De.Uparrow=i(j,"\\Uparrow ","&uArr;"),De.to=i(Q,"\\to ","&rarr;"),De.rarr=De.rightarrow=i(j,"\\rightarrow ","&rarr;"),De.implies=i(Q,"\\Rightarrow ","&rArr;"),De.rArr=De.Rightarrow=i(j,"\\Rightarrow ","&rArr;"),De.gets=i(Q,"\\gets ","&larr;"),De.larr=De.leftarrow=i(j,"\\leftarrow ","&larr;"),De.impliedby=i(Q,"\\Leftarrow ","&lArr;"),De.lArr=De.Leftarrow=i(j,"\\Leftarrow ","&lArr;"),De.harr=De.lrarr=De.leftrightarrow=i(j,"\\leftrightarrow ","&harr;"),De.iff=i(Q,"\\Leftrightarrow ","&hArr;"),De.hArr=De.lrArr=De.Leftrightarrow=i(j,"\\Leftrightarrow ","&hArr;"),De.Re=De.Real=De.real=i(j,"\\Re ","&real;"),De.Im=De.imag=De.image=De.imagin=De.imaginary=De.Imaginary=i(j,"\\Im ","&image;"),De.part=De.partial=i(j,"\\partial ","&part;"),De.infty=De.infin=De.infinity=i(j,"\\infty ","&infin;"),De.alef=De.alefsym=De.aleph=De.alephsym=i(j,"\\aleph ","&alefsym;"),De.xist=De.xists=De.exist=De.exists=i(j,"\\exists ","&exist;"),De.and=De.land=De.wedge=i(j,"\\wedge ","&and;"),De.or=De.lor=De.vee=i(j,"\\vee ","&or;"),De.o=De.O=De.empty=De.emptyset=De.oslash=De.Oslash=De.nothing=De.varnothing=i(Q,"\\varnothing ","&empty;"),De.cup=De.union=i(Q,"\\cup ","&cup;"),De.cap=De.intersect=De.intersection=i(Q,"\\cap ","&cap;"),De.deg=De.degree=i(j,"^\\circ ","&deg;"),De.ang=De.angle=i(j,"\\angle ","&ang;"),R=ye(C,function(t,e){t.init=function(t,n){e.init.call(this,t,"<var>"+(n||t)+"</var>")},t.text=function(){var t,e,n=this.ctrlSeq;for(!this[Ce]||this[Ce]instanceof R||this[Ce]instanceof Q||","===this[Ce].ctrlSeq||(n="*"+n),!this[Ce]||this[Ce]instanceof Q||"\\"!=this.ctrlSeq[0]||(n="*"+n),t=!1,e=this;e instanceof I;e=e[Ce])if("\\"==e.ctrlSeq[0]){t=!0;break}return!this[je]||this[je]instanceof Q||this[je]instanceof R||"^"===this[je].ctrlSeq||","===this[je].ctrlSeq||"_"===this[je].ctrlSeq||t||(n+="*"),n}}),g.p.autoCommands={_maxLength:0},b.autoCommands=function(t){var e,n,i,s,r;if(!/^[a-z]+(?: [a-z]+)*$/i.test(t))throw'"'+t+'" not a space-delimited list of only letters';for(e=t.split(" "),n={},i=0,s=0;s<e.length;s+=1){if(r=e[s],r.length<2)throw'autocommand "'+r+'" not minimum length of 2';if(De[r]===P)throw'"'+r+'" is a built-in operator name';n[r]=1,i=xe(i,r.length)}return n._maxLength=i,n},I=ye(R,function(t,e){function n(t){return t instanceof C&&!(t instanceof Q)}t.init=function(t){return e.init.call(this,this.letter=t)},t.createLeftOf=function(t){var n,i,s,r=t.options.autoCommands,o=r._maxLength;if(o>0){for(n=this.letter,i=t[Ce],s=1;i instanceof I&&o>s;)n=i.letter+n,i=i[Ce],s+=1;for(;n.length;){if(r.hasOwnProperty(n)){for(s=2,i=t[Ce];s<n.length;s+=1,i=i[Ce]);return Ae(i,t[Ce]).remove(),t[Ce]=i[Ce],De[n](n).createLeftOf(t)}if(t.options.autoCommandFullWordOnly)break;n=n.slice(1)}}e.createLeftOf.apply(this,arguments)},t.italicize=function(t){return this.jQ.toggleClass("mq-operator-name",!t),this},t.finalizeTree=t.siblingDeleted=t.siblingCreated=function(t,e){t.autoOnBrackets||e!==Ce&&this[je]instanceof I||this.autoUnItalicize(t,!0)},t.autoUnItalicize=function(t,e){var i,s,r,o,a,l,c,h,u,p,f,d=t.autoOperatorNames;if(0!==d._maxLength){for(i=this.letter,s=this[Ce];s instanceof I;s=s[Ce])i=s.letter+i;for(r=this[je];r instanceof I;r=r[je])i+=r.letter;Ae(s[je]||this.parent.ends[Ce],r[Ce]||this.parent.ends[je]).each(function(t){t.italicize(!0).jQ.removeClass("mq-first mq-last"),t.ctrlSeq=t.letter});t:for(o=0,a=s[je]||this.parent.ends[Ce];o<i.length;o+=1,a=a[je])for(l=qe(d._maxLength,i.length-o);l>0;l-=1)if(c=i.slice(o,o+l),t.autoAllFunctions||d.hasOwnProperty(c)){for(h=0,u=a;l>h;h+=1,u=u[je])e&&u.italicize(!1),p=u;f=z.hasOwnProperty(c),a.ctrlSeq=(f?"\\":"\\operatorname{")+a.ctrlSeq,p.ctrlSeq+=f?" ":"}",B.hasOwnProperty(c)&&p[Ce][Ce][Ce].jQ.addClass("mq-last"),n(a[Ce])&&a.jQ.addClass("mq-first"),n(p[je])&&p.jQ.addClass("mq-last"),o+=l-1,a=p;continue t}}}}),z={},B={limsup:1,liminf:1,projlim:1,injlim:1},function(){var t,e,n,i=g.p.autoOperatorNames={_maxLength:9},s="arg deg det dim exp gcd hom inf ker lg lim ln log max min sup limsup liminf injlim projlim Pr".split(" ");for(t=0;t<s.length;t+=1)z[s[t]]=i[s[t]]=1;for(e="sin cos tan arcsin arccos arctan sinh cosh tanh sec csc cot coth".split(" "),t=0;t<e.length;t+=1)z[e[t]]=1;for(n="sin cos tan sec cosec csc cotan cot ctg".split(" "),t=0;t<n.length;t+=1)i[n[t]]=i["arc"+n[t]]=i[n[t]+"h"]=i["ar"+n[t]+"h"]=i["arc"+n[t]+"h"]=1}(),b.autoOperatorNames=function(t){var e,n,i,s,r;if(!/^[a-z]+(?: [a-z]+)*$/i.test(t))throw'"'+t+'" not a space-delimited list of only letters';for(e=t.split(" "),n={},i=0,s=0;s<e.length;s+=1){if(r=e[s],r.length<2)throw'"'+r+'" not minimum length of 2';n[r]=1,i=xe(i,r.length)}return n._maxLength=i,n},P=ye(C,function(t){t.init=function(t){this.ctrlSeq=t},t.createLeftOf=function(t){var e,n=this.ctrlSeq;for(e=0;e<n.length;e+=1)I(n.charAt(e)).createLeftOf(t)},t.parser=function(){var t,e=this.ctrlSeq,n=S();for(t=0;t<e.length;t+=1)I(e.charAt(t)).adopt(n,n.ends[je],0);return q.succeed(n.children())}});for(M in z)z.hasOwnProperty(M)&&(De[M]=P);De.operatorname=ye(y,function(e){e.createLeftOf=t,e.numBlocks=function(){return 1},e.parser=function(){return k.block.map(function(t){return t.children()})}}),De.f=ye(I,function(t,e){t.init=function(){C.p.init.call(this,this.letter="f",'<var class="mq-florin">&fnof;</var>')},t.italicize=function(t){return this.jQ.html(t?"&fnof;":"f").toggleClass("mq-florin",t),e.italicize.apply(this,arguments)}}),De[" "]=De.space=i(j,"\\ "," "),De["'"]=De.prime=i(j,"'","&prime;"),De.backslash=i(j,"\\backslash ","\\"),_e["\\"]||(_e["\\"]=De.backslash),De.$=i(j,"\\$","$"),F=ye(C,function(t,e){t.init=function(t,n){e.init.call(this,t,'<span class="mq-nonSymbola">'+(n||t)+"</span>")}}),De["@"]=F,De["&"]=i(F,"\\&","&amp;"),De["%"]=i(F,"\\%","%"),De.alpha=De.beta=De.gamma=De.delta=De.zeta=De.eta=De.theta=De.iota=De.kappa=De.mu=De.nu=De.xi=De.rho=De.sigma=De.tau=De.chi=De.psi=De.omega=ye(R,function(t,e){t.init=function(t){e.init.call(this,"\\"+t+" ","&"+t+";")}}),De.phi=i(R,"\\phi ","&#981;"),De.phiv=De.varphi=i(R,"\\varphi ","&phi;"),De.epsilon=i(R,"\\epsilon ","&#1013;"),De.epsiv=De.varepsilon=i(R,"\\varepsilon ","&epsilon;"),De.piv=De.varpi=i(R,"\\varpi ","&piv;"),De.sigmaf=De.sigmav=De.varsigma=i(R,"\\varsigma ","&sigmaf;"),De.thetav=De.vartheta=De.thetasym=i(R,"\\vartheta ","&thetasym;"),De.upsilon=De.upsi=i(R,"\\upsilon ","&upsilon;"),De.gammad=De.Gammad=De.digamma=i(R,"\\digamma ","&#989;"),De.kappav=De.varkappa=i(R,"\\varkappa ","&#1008;"),De.rhov=De.varrho=i(R,"\\varrho ","&#1009;"),De.pi=De["π"]=i(F,"\\pi ","&pi;"),De.lambda=i(F,"\\lambda ","&lambda;"),De.Upsilon=De.Upsi=De.upsih=De.Upsih=i(C,"\\Upsilon ",'<var style="font-family: serif">&upsih;</var>'),De.Gamma=De.Delta=De.Theta=De.Lambda=De.Xi=De.Pi=De.Sigma=De.Phi=De.Psi=De.Omega=De.forall=ye(j,function(t,e){t.init=function(t){e.init.call(this,"\\"+t+" ","&"+t+";")}}),$=ye(y,function(t){t.init=function(t){this.latex=t},t.createLeftOf=function(t){var e=k.parse(this.latex);e.children().adopt(t.parent,t[Ce],t[je]),t[Ce]=e.ends[je],e.jQize().insertBefore(t.jQ),e.finalizeInsert(t.options,t),e.ends[je][je].siblingCreated&&e.ends[je][je].siblingCreated(t.options,Ce),e.ends[Ce][Ce].siblingCreated&&e.ends[Ce][Ce].siblingCreated(t.options,je),t.parent.bubble("reflow")},t.parser=function(){var t=k.parse(this.latex).children();return q.succeed(t)}}),De["¹"]=i($,"^1"),De["²"]=i($,"^2"),De["³"]=i($,"^3"),De["¼"]=i($,"\\frac14"),De["½"]=i($,"\\frac12"),De["¾"]=i($,"\\frac34"),N=ye(Q,function(t){t.init=j.prototype.init,t.contactWeld=t.siblingCreated=t.siblingDeleted=function(t,e){return e!==je?(this.jQ[0].className=!this[Ce]||this[Ce]instanceof Q?"":"mq-binary-operator",this):void 0}}),De["+"]=i(N,"+","+"),De["–"]=De["-"]=i(N,"-","&minus;"),De["±"]=De.pm=De.plusmn=De.plusminus=i(N,"\\pm ","&plusmn;"),De.mp=De.mnplus=De.minusplus=i(N,"\\mp ","&#8723;"),_e["*"]=De.sdot=De.cdot=i(Q,"\\cdot ","&middot;","*"),G=ye(Q,function(t,e){t.init=function(t,n){this.data=t,this.strict=n;var i=n?"Strict":"";e.init.call(this,t["ctrlSeq"+i],t["html"+i],t["text"+i])},t.swap=function(t){this.strict=t;var e=t?"Strict":"";this.ctrlSeq=this.data["ctrlSeq"+e],this.jQ.html(this.data["html"+e]),this.textTemplate=[this.data["text"+e]]},t.deleteTowards=function(t){return t!==Ce||this.strict?void e.deleteTowards.apply(this,arguments):void this.swap(!0)}}),U={ctrlSeq:"\\le ",html:"&le;",text:"≤",ctrlSeqStrict:"<",htmlStrict:"&lt;",textStrict:"<"},W={ctrlSeq:"\\ge ",html:"&ge;",text:"≥",ctrlSeqStrict:">",htmlStrict:"&gt;",textStrict:">"},De["<"]=De.lt=i(G,U,!0),De[">"]=De.gt=i(G,W,!0),De["≤"]=De.le=De.leq=i(G,U,!1),De["≥"]=De.ge=De.geq=i(G,W,!1),H=ye(Q,function(t,e){t.init=function(){e.init.call(this,"=","=")},t.createLeftOf=function(t){return t[Ce]instanceof G&&t[Ce].strict?void t[Ce].swap(!1):void e.createLeftOf.apply(this,arguments)}}),De["="]=H,De.times=i(Q,"\\times ","&times;","[x]"),De["÷"]=De.div=De.divide=De.divides=i(Q,"\\div ","&divide;","[/]"),X=t,Z=document.createElement("div"),K=Z.style,Y={transform:1,WebkitTransform:1,MozTransform:1,OTransform:1,msTransform:1};for(te in Y)if(te in K){J=te;break}J?V=function(t,e,n){t.css(J,"scale("+e+","+n+")")}:"filter"in K?(X=function(t){t.className=t.className},V=function(t,e,n){function i(){t.css("marginRight",(s.width()-1)*(e-1)/e+"px")}var s,r;e/=1+(n-1)/2,t.css("fontSize",n+"em"),t.hasClass("mq-matrixed-container")||t.addClass("mq-matrixed-container").wrapInner('<span class="mq-matrixed"></span>'),s=t.children().css("filter","progid:DXImageTransform.Microsoft.Matrix(M11="+e+",SizingMethod='auto expand')"),i(),r=setInterval(i),Qe(window).load(function(){clearTimeout(r),i()})}):V=function(t,e,n){t.css("fontSize",n+"em")},ee=ye(y,function(t,e){t.init=function(t,n,i){e.init.call(this,t,"<"+n+" "+i+">&0</"+n+">")}}),De.mathrm=i(ee,"\\mathrm","span",'class="mq-roman mq-font"'),De.mathit=i(ee,"\\mathit","i",'class="mq-font"'),De.mathbf=i(ee,"\\mathbf","b",'class="mq-font"'),De.mathsf=i(ee,"\\mathsf","span",'class="mq-sans-serif mq-font"'),De.mathtt=i(ee,"\\mathtt","span",'class="mq-monospace mq-font"'),De.underline=i(ee,"\\underline","span",'class="mq-non-leaf mq-underline"'),De.overline=De.bar=i(ee,"\\overline","span",'class="mq-non-leaf mq-overline"'),ne=De.textcolor=ye(y,function(t,e){t.setColor=function(t){this.color=t,this.htmlTemplate='<span class="mq-textcolor" style="color:'+t+'">&0</span>'},t.latex=function(){return"\\textcolor{"+this.color+"}{"+this.blocks[0].latex()+"}"},t.parser=function(){var t=this,n=q.optWhitespace,i=q.string,s=q.regex;return n.then(i("{")).then(s(/^[#\w\s.,()%-]*/)).skip(i("}")).then(function(n){return t.setColor(n),e.parser.call(t)})}}),ie=De["class"]=ye(y,function(t,e){t.parser=function(){var t=this,n=q.string,i=q.regex;return q.optWhitespace.then(n("{")).then(i(/^[-\w\s\\\xA0-\xFF]*/)).skip(n("}")).then(function(n){return t.htmlTemplate='<span class="mq-class '+n+'">&0</span>',e.parser.call(t)})}}),se=ye(y,function(t,e){t.ctrlSeq="_{...}^{...}",t.createLeftOf=function(t){return t[Ce]||!t.options.supSubsRequireOperand?e.createLeftOf.apply(this,arguments):void 0},t.contactWeld=function(t){var e,n,i,s,r,o;for(e=Ce;e;e=e===Ce?je:!1)if(this[e]instanceof se){for(n="sub";n;n="sub"===n?"sup":!1)i=this[n],s=this[e][n],i&&(s?i.isEmpty()?o=Se(s,0,s.ends[Ce]):(i.jQ.children().insAtDirEnd(-e,s.jQ),r=i.children().disown(),o=Se(s,r.ends[je],s.ends[Ce]),e===Ce?r.adopt(s,s.ends[je],0):r.adopt(s,0,s.ends[Ce])):this[e].addBlock(i.disown()),this.placeCursor=function(t,n){return function(i){i.insAtDirEnd(-e,t||n)}}(s,i));this.remove(),t&&t[Ce]===this&&(e===je&&o?o[Ce]?t.insRightOf(o[Ce]):t.insAtLeftEnd(o.parent):t.insRightOf(this[e]));break}this.respace()},g.p.charsThatBreakOutOfSupSub="",t.finalizeTree=function(){var t=this.supsub;this.ends[Ce].write=function(e,n){e.options.charsThatBreakOutOfSupSub.indexOf(n)>-1&&e.insRightOf(this.parent),"sub"==t&&e.options.noOperatorsInSubscript&&!RegExp(/[A-Za-z0-9]/).test(n)&&e.insRightOf(this.parent),S.p.write.apply(this,arguments)}},t.latex=function(){function t(t,e){var n=e&&e.latex();return e?t+(1===n.length?n:"{"+(n||" ")+"}"):""}return t("_",this.sub)+t("^",this.sup)},t.text=function(t){var e="";return this.sub&&(e+=t.noOperatorsInSubscript?"_"+(this.sub&&this.sub.ends[Ce]===this.sub.ends[je]?this.sub.ends[Ce].text(t):this.sub.foldChildren("",function(e,n){return e+n.text(t)})):"_"+(this.sub&&this.sub.ends[Ce]===this.sub.ends[je]?this.sub.ends[Ce].text(t):"("+this.sub.foldChildren("",function(e,n){return e+n.text(t)})+")")),this.sup&&(e+="^"+(this.sup&&this.sup.ends[Ce]===this.sup.ends[je]?this.sup.ends[Ce].text(t):"("+this.sup.foldChildren("",function(e,n){return e+n.text(t)})+")")),e},t.respace=t.siblingCreated=t.siblingDeleted=function(t,e){e!==je&&this.jQ.toggleClass("mq-limit","\\int "===this[Ce].ctrlSeq)},t.addBlock=function(t){"sub"===this.supsub?(this.sup=this.upInto=this.sub.upOutOf=t,t.adopt(this,this.sub,0).downOutOf=this.sub,t.jQ=Qe('<span class="mq-sup"/>').append(t.jQ.children()).attr(we,t.id).prependTo(this.jQ)):(this.sub=this.downInto=this.sup.downOutOf=t,t.adopt(this,0,this.sup).upOutOf=this.sup,t.jQ=Qe('<span class="mq-sub"></span>').append(t.jQ.children()).attr(we,t.id).appendTo(this.jQ.removeClass("mq-sup-only")),this.jQ.append('<span style="display:inline-block;width:0">&nbsp;</span>'));for(var e=0;2>e;e+=1)(function(t,e,n,i){t[e].deleteOutOf=function(s,r){r.insDirOf(s,this.parent),this.isEmpty()||(r[-s]=this.ends[s],this.children().disown().withDirAdopt(s,r.parent,r[s],this.parent).jQ.insDirOf(s,this.parent.jQ)),t.supsub=n,delete t[e],delete t[i+"Into"],t[n][i+"OutOf"]=u,delete t[n].deleteOutOf,"sub"===e&&Qe(t.jQ.addClass("mq-sup-only")[0].lastChild).remove(),this.remove()}})(this,"sub sup".split(" ")[e],"sup sub".split(" ")[e],"down up".split(" ")[e])}}),re=ye(y,function(t,e){t.init=function(t,e){var n;n=g.p.autoParensSummationNotation?'<span><span class="mq-large-operator mq-non-leaf"><span class="mq-to"><span>&1</span></span><big>'+e+'</big><span class="mq-from"><span>&0</span></span></span><span class="mq-non-leaf"><span class="mq-scaled mq-paren">(</span><span class="mq-non-leaf">&2</span><span class="mq-scaled mq-paren">)</span></span></span>':'<span class="mq-large-operator mq-non-leaf"><span class="mq-to"><span>&1</span></span><big>'+e+'</big><span class="mq-from"><span>&0</span></span></span>',C.prototype.init.call(this,t,n)},t.createLeftOf=function(t){e.createLeftOf.apply(this,arguments),t.options.sumStartsWithNEquals&&(I("n").createLeftOf(t),H().createLeftOf(t))},t.reflow=function(){var t,e,n;g.p.autoParensSummationNotation&&(t=this.jQ.children(":last").children(":first").add(this.jQ.children(":last").children(":last")),e=this.jQ.children(":last").children(":eq(1)"),n=e.outerHeight()/parseInt(e.css("fontSize"),10),V(t,qe(1+.2*(n-1),1.2),1.05*n))},t.latex=function(){function t(t){return 1===t.length?t:"{"+(t||" ")+"}"}return g.p.autoParensSummationNotation?this.ctrlSeq+"_{"+this.blocks[0].latex()+"}^{"+this.blocks[1].latex()+"}\\left({"+this.blocks[2].latex()+"}\\right)":this.ctrlSeq+"_"+t(this.ends[Ce].latex())+"^"+t(this.ends[je].latex())},t.text=function(t){return g.p.autoParensSummationNotation?" "+this.ctrlSeq+'("'+this.blocks[0].text(t).replace("=",'" , ')+" , "+this.blocks[1].text(t)+","+this.blocks[2].text(t)+")":" "+this.ctrlSeq+'("'+this.ends[Ce].text(t).replace("=",'" , ')+" , "+this.ends[je].text(t)+")"},t.parser=function(){var t,e,n=q.string,i=q.optWhitespace,s=(q.whitespace,q.succeed),r=k.block,o=this;for(t=o.blocks=g.p.autoParensSummationNotation?[S(),S(),S()]:[S(),S()],e=0;e<t.length;e+=1)t[e].adopt(o,o.ends[je],0);return g.p.autoParensSummationNotation?i.then(n("_")).then(function(){var e=t[0];return r.then(function(t){return t.children().adopt(e,e.ends[je],0),s(o)})}).then(i).then(n("^")).then(function(){var e=t[1];return r.then(function(t){return t.children().adopt(e,e.ends[je],0),s(o)})}).then(n("\\left(")).then(function(){var e=t[2];return r.then(function(t){return t.children().adopt(e,e.ends[je],0),s(o) +})}).then(n("\\right)")).result(o):i.then(n("_").or(n("^"))).then(function(e){var n=t["_"===e?0:1];return r.then(function(t){return t.children().adopt(n,n.ends[je],0),s(o)})}).many().result(o)},t.finalizeTree=function(){this.downInto=this.ends[Ce],this.upInto=this.ends[je],this.ends[Ce].upOutOf=this.ends[je],this.ends[je].downOutOf=this.ends[Ce]}}),De["∑"]=De.sum=De.summation=i(re,"\\sum ","&sum;"),De["∏"]=De.prod=De.product=i(re,"\\prod ","&prod;"),De.coprod=De.coproduct=i(re,"\\coprod ","&#8720;"),De.subscript=De._=ye(se,function(t,e){t.supsub="sub",t.ctrlSeq="_",t.htmlTemplate='<span class="mq-supsub mq-non-leaf"><span class="mq-sub">&0</span><span style="display:inline-block;width:0">&nbsp;</span></span>',t.textTemplate=["_"],t.finalizeTree=function(){this.downInto=this.sub=this.ends[Ce],this.sub.upOutOf=u,e.finalizeTree.call(this)}}),De.superscript=De.supscript=De["^"]=ye(se,function(t,e){t.supsub="sup",t.ctrlSeq="^",t.htmlTemplate='<span class="mq-supsub mq-non-leaf mq-sup-only"><span class="mq-sup">&0</span></span>',t.textTemplate=["^"],t.finalizeTree=function(){this.upInto=this.sup=this.ends[je],this.sup.downOutOf=u,e.finalizeTree.call(this)}}),oe=De.frac=De.dfrac=De.cfrac=De.fraction=ye(y,function(t){t.ctrlSeq="\\frac",t.htmlTemplate='<span class="mq-fraction mq-non-leaf"><span class="mq-numerator">&0</span><span class="mq-denominator">&1</span><span style="display:inline-block;width:0">&nbsp;</span></span>',t.textTemplate=["((",")/(","))"],t.finalizeTree=function(){this.upInto=this.ends[je].upOutOf=this.ends[Ce],this.downInto=this.ends[Ce].downOutOf=this.ends[je]}}),ae=De.over=_e["/"]=ye(oe,function(e,n){e.createLeftOf=function(e){if(!this.replacedFragment){for(var i=e[Ce];i&&!(i instanceof Q||i instanceof(De.text||t)||i instanceof re||"\\ "===i.ctrlSeq||/^[,;:]$/.test(i.ctrlSeq));)i=i[Ce];i instanceof re&&i[je]instanceof se&&(i=i[je],i[je]instanceof se&&i[je].ctrlSeq!=i.ctrlSeq&&(i=i[je])),i!==e[Ce]&&(this.replaces(Ae(i[je]||e.parent.ends[Ce],e[Ce])),e[Ce]=i)}n.createLeftOf.call(this,e)}}),le=De.sqrt=De["√"]=ye(y,function(t,e){t.ctrlSeq="\\sqrt",t.htmlTemplate='<span class="mq-non-leaf"><span class="mq-scaled mq-sqrt-prefix">&radic;</span><span class="mq-non-leaf mq-sqrt-stem">&0</span></span>',t.textTemplate=[" sqrt(",")"],t.parser=function(){return k.optBlock.then(function(t){return k.block.map(function(e){var n=he();return n.blocks=[t,e],t.adopt(n,0,0),e.adopt(n,t,0),n})}).or(e.parser.call(this))},t.reflow=function(){var t=this.ends[je].jQ;V(t.prev(),1,t.innerHeight()/+t.css("fontSize").slice(0,-2)-.1)}}),ce=De.vec=ye(y,function(t){t.ctrlSeq="\\vec",t.htmlTemplate='<span class="mq-non-leaf"><span class="mq-vector-prefix">&rarr;</span><span class="mq-vector-stem">&0</span></span>',t.textTemplate=["vec(",")"]}),he=De.nthroot=ye(le,function(t){t.htmlTemplate='<sup class="mq-nthroot mq-non-leaf">&0</sup><span class="mq-scaled"><span class="mq-sqrt-prefix mq-scaled">&radic;</span><span class="mq-sqrt-stem mq-non-leaf">&1</span></span>',t.textTemplate=["sqrt[","](",")"],t.latex=function(){return"\\sqrt["+this.ends[Ce].latex()+"]{"+this.ends[je].latex()+"}"},t.text=function(t){return" "+this.ends[je].text(t)+"^(1/"+this.ends[Ce].text(t)+")"}}),ue=De.begin=ye(y,function(t,e){t.numBlocks=function(){return this.col*this.row},t.init=function(t,n,i){var s,r,o,a;for(this.col=n,this.row=i,this.ctrlSeq=t,s="",r=0;i>r;r++){for(o="",a=0;n>a;a++)o+='<span class="mq-cell">&'+(r*n+a)+"</span>";s+='<span class="mq-row">'+o+"</span>"}switch(this.ctrlSeq){case"\\pmatrix":s='<span class="mq-scaled mq-paren">(</span><span class="mq-matrix">'+s+'</span><span class="mq-scaled mq-paren">)</span>';break;case"\\bmatrix":s='<span class="mq-scaled mq-paren">[</span><span class="mq-matrix">'+s+'</span><span class="mq-scaled mq-paren">]</span>';break;case"\\Bmatrix":s='<span class="mq-scaled mq-paren">{</span><span class="mq-matrix">'+s+'</span><span class="mq-scaled mq-paren">}</span>';break;case"\\vmatrix":s='<span class="mq-scaled mq-paren">|</span><span class="mq-matrix">'+s+'</span><span class="mq-scaled mq-paren">|</span>';break;case"\\Vmatrix":s='<span class="mq-scaled mq-paren">||</span><span class="mq-matrix">'+s+'</span><span class="mq-scaled mq-paren">||</span>';break;default:s='<span class="mq-matrix">'+s+"</span>"}e.init.call(this,this.ctrlSeq,'<span class="mq-matrix-outer mq-non-leaf">'+s+"</span>",["text"])},t.reflow=function(){var t=this.jQ.children(".mq-paren"),e=this.jQ.children(".mq-matrix").first(),n=e.outerHeight()/(1.133333*parseInt(e.css("fontSize"),10));V(t,qe(1+.2*(n-1),1.2),1.05*n),t.css("position","relative"),t.css("top",Math.round(.6*n)+"px")},t.contextMenu=function(t,e){var n=this,i=[{text:"Insert Column Before",handler:function(){n.insertColumn(t,Ce)}},{text:"Insert Column After",handler:function(){n.insertColumn(t,je)}},{text:"Insert Row Before",handler:function(){n.insertRow(t,Ce)}},{text:"Insert Row After",handler:function(){n.insertRow(t,je)}}];this.col>1&&i.push({text:"Delete Column",handler:function(){n.deleteColumn(t)}}),this.row>1&&i.push({text:"Delete Row",handler:function(){n.deleteRow(t)}}),this.showPopupMenu(i,e)},t.latex=function(){var t="",e=1,n=this.col,i=this.numBlocks(),s=this.ctrlSeq.substring(1,this.ctrlSeq.length);return this.eachChild(function(s){s.ends[Ce]&&(t+=s.latex()),e!=i&&(t+=e%n==0?" \\\\ ":" & "),e++}),"\\begin{"+s+"}"+t+"\\end{"+s+"}"},t.text=function(t){var e,n,i=[];for(this.eachChild(function(e){i.push(e.ends[Ce]?e.text(t):0)}),e="",n=0;n<i.length;n++)n>0&&n%this.col==0?e+="],[":n>0&&(e+=","),e+=i[n];return this.row>1?"[["+e+"]]":"["+e+"]"},t.parser=function(){{var t=(k.block,q.string,q.regex);q.optWhitespace}return t(/^\{[pbvBV]?matrix\}[\s\S]*?\\end\{[pbvBV]?matrix\}/).map(function(t){var e,n,i,s,r,o,a,l,c;for("}"==t.substring(7,1)?(e=t.substring(1,7),t=t.substring(8,t.length-12).trim()):(e=t.substring(1,8),t=t.substring(9,t.length-13).trim()),n=t.split(/\\\\/).map(function(t){return t.trim()}),i=n.length,s=0,r=[],n.forEach(function(t){var e=t.split(/&/);s=Math.max(s,e.length),r=r.concat(e)}),o=ue("\\"+e,s,i),a=o.blocks=Array(o.numBlocks()),l=0;l<a.length;l++)c=a[l]=k.parse(r[l]),c.adopt(o,o.ends[je],0);return o})},t.finalizeTree=function(){var t,e,n;for(t=0;t<this.row;t++)for(e=0;e<this.col;e++)n=this.blocks[t*this.col+e],n.upOutOf=0==t&&0!=e?this.blocks[this.row*this.col-this.row+e-1]:this.blocks[(t-1)*this.col+e],n.downOutOf=t+1==this.row&&e+1!=this.col?this.blocks[e+1]:this.blocks[(t+1)*this.col+e]},t.cursorRowCol=function(t){for(var e=0,n=0,i=t.parent;0!==i[Ce];)e++,e==this.col&&(e=0,n++),i=i[Ce];return{row:n,col:e}},t.deleteRow=function(t){var e,n,i;if(1!=this.row){for(e=this.cursorRowCol(t),n=e.row*this.col,i=0;i<this.col;i++)this.blocks[n].remove(),this.blocks.splice(n,1);n>0&&n<this.blocks.length?(this.blocks[n][Ce]=this.blocks[n-1],this.blocks[n-1][je]=this.blocks[n]):0==n?this.blocks[n][Ce]=0:this.blocks[n-1][je]=0,this.jQ.children(".mq-matrix").first().children(".mq-row").eq(e.row).remove(),this.row--,this.finalizeTree(),t.insAtLeftEnd(this.blocks[e.row>0?(e.row-1)*this.col+e.col:e.col]),this.reflow(),this.bubble("workingGroupChange")}},t.deleteColumn=function(t){var e,n,i;if(1!=this.col){for(e=this.cursorRowCol(t),n=e.col,i=0;i<this.row;i++)this.blocks[n].remove(),this.blocks.splice(n,1),n>0&&n<this.blocks.length?(this.blocks[n][Ce]=this.blocks[n-1],this.blocks[n-1][je]=this.blocks[n]):0==n?this.blocks[n][Ce]=0:this.blocks[n-1][je]=0,n+=this.col-1;this.col--,this.finalizeTree(),t.insAtLeftEnd(this.blocks[e.col<this.col?e.row*this.col+e.col:e.row*this.col+e.col-1]),this.reflow(),this.bubble("workingGroupChange")}},t.insertRow=function(t,e){var n,i,s,r,o=this.cursorRowCol(t);for(n="undefined"==typeof e?0===t[Ce]&&0!==t[je]:e==Ce?!0:!1,i=o.row*this.col+(n?0:this.col),n?this.jQ.children(".mq-matrix").first().children(".mq-row").eq(o.row).before('<span class="mq-row"></span>'):this.jQ.children(".mq-matrix").first().children(".mq-row").eq(o.row).after('<span class="mq-row"></span>'),s=0;s<this.col;s++)r=S(),r.adopt(this,i+s>0?this.blocks[i+s-1]:0,i+s>0?this.blocks[i+s-1][je]:this.ends[Ce]),r.jQ=Qe('<span class="mq-cell mq-empty" '+we+'="'+r.id+'"></span>'),i+s>0&&(this.blocks[i+s-1][je]=r),this.blocks.splice(i+s,0,r),this.jQ.children(".mq-matrix").first().children(".mq-row").eq(o.row+(n?0:1)).append(r.jQ);i+s<this.blocks.length&&(this.blocks[i+s][Ce]=r,r[je]=this.blocks[i+s]),this.row++,this.finalizeTree(),t.insAtLeftEnd(this.blocks[i]),this.reflow(),this.bubble("workingGroupChange")},t.insertColumn=function(t,e){var n,i,s,r=this.cursorRowCol(t);for(n="undefined"==typeof e?0===t[Ce]&&0!==t[je]:e==Ce?!0:!1,i=this.row-1;i>=0;i--)s=S(),n?(s.adopt(this,i*this.col+r.col-1>=0?this.blocks[i*this.col+r.col-1]:0,this.blocks[i*this.col+r.col]),s.jQ=Qe('<span class="mq-cell mq-empty" '+we+'="'+s.id+'"></span>'),i*this.col+r.col-1>=0&&(this.blocks[i*this.col+r.col-1][je]=s),this.blocks[i*this.col+r.col][Ce]=s,this.blocks.splice(i*this.col+r.col,0,s),this.jQ.children(".mq-matrix").first().children(".mq-row").eq(i).children(".mq-cell").eq(r.col).before(s.jQ)):(s.adopt(this,this.blocks[i*this.col+r.col],i*this.col+r.col+1<this.row*this.col?this.blocks[i*this.col+r.col+1]:0),s.jQ=Qe('<span class="mq-cell mq-empty" '+we+'="'+s.id+'"></span>'),this.blocks[i*this.col+r.col][je]=s,i*this.col+r.col+1<this.row*this.col&&(this.blocks[i*this.col+r.col+1][Ce]=s),this.blocks.splice(i*this.col+r.col+1,0,s),this.jQ.children(".mq-matrix").first().children(".mq-row").eq(i).children(".mq-cell").eq(r.col).after(s.jQ));this.col++,this.finalizeTree(),t.insAtLeftEnd(t.parent[n?Ce:je]),this.reflow(),this.bubble("workingGroupChange")},t.moveOrInsertColumn=function(t){var e=this.cursorRowCol(t);return e.col+1==this.col?this.insertColumn(t):(t.insAtLeftEnd(t.parent[je]),void this.bubble("workingGroupChange"))}}),De.matrix=i(ue,"\\matrix",1,1),De.bmatrix=i(ue,"\\bmatrix",1,1),De.Bmatrix=i(ue,"\\Bmatrix",1,1),De.vmatrix=i(ue,"\\vmatrix",1,1),De.Vmatrix=i(ue,"\\Vmatrix",1,1),De.pmatrix=i(ue,"\\pmatrix",1,1),pe=ye(ye(y,p),function(e,n){e.init=function(t,e,i,s,r){n.init.call(this,"\\left"+s,d,[e,i]),this.side=t,this.sides={},this.sides[Ce]={ch:e,ctrlSeq:s},this.sides[je]={ch:i,ctrlSeq:r}},e.numBlocks=function(){return 1},e.html=function(){return this.htmlTemplate='<span class="mq-non-leaf"><span class="mq-scaled mq-paren'+(this.side===je?" mq-ghost":"")+'">'+this.sides[Ce].ch+'</span><span class="mq-non-leaf">&0</span><span class="mq-scaled mq-paren'+(this.side===Ce?" mq-ghost":"")+'">'+this.sides[je].ch+"</span></span>",n.html.call(this)},e.latex=function(){return"\\left"+this.sides[Ce].ctrlSeq+this.ends[Ce].latex()+"\\right"+this.sides[je].ctrlSeq},e.oppBrack=function(t,e){return t instanceof pe&&t.side&&t.side!==-e&&("|"===this.sides[this.side].ch||t.side===-this.side)&&t},e.closeOpposing=function(t){t.side=0,t.sides[this.side]=this.sides[this.side],t.delimjQs.eq(this.side===Ce?0:1).removeClass("mq-ghost").html(this.sides[this.side].ch)},e.createLeftOf=function(t){var e,i,s,r,o,a;if(!this.replacedFragment&&(e=this.oppBrack(t[Ce],Ce)||this.oppBrack(t[je],je)||this.oppBrack(t.parent.parent),!e&&t.options.enableMatrixShortcuts&&"\\left["===this.ctrlSeq&&0===t[Ce]&&0===t[je]&&"undefined"!=typeof t.parent.parent&&t.parent.parent.ctrlSeq===this.ctrlSeq)){if(i=t.parent.parent[Ce],s=t.parent.parent.parent,t.parent.parent.unwrap(),0!==i?t.insRightOf(i):t.insAtLeftEnd(s),t.options.autoOnBrackets)for(r=t[Ce];r instanceof I;)r.jQ.hasClass("mq-operator-name")&&r.italicize(!0),r.ctrlSeq=r.ctrlSeq.replace("\\","").replace("operatorname{","").replace("}","").trim(),r=r[Ce];return o=ue("\\bmatrix",1,1),void o.createLeftOf(t)}e?(a=this.side=-e.side,this.closeOpposing(e),e===t.parent.parent&&t[a]&&(Ae(t[a],t.parent.ends[a],-a).disown().withDirAdopt(-a,e.parent,e,e[a]).jQ.insDirOf(a,e.jQ),e.bubble("reflow"))):(e=this,a=e.side,e.replacedFragment?e.side=0:t[-a]&&(e.replaces(Ae(t[-a],t.parent.ends[-a],a)),t[-a]=0),n.createLeftOf.call(e,t)),a===Ce?t.insAtLeftEnd(e.ends[Ce]):t.insRightOf(e),t.parent.bubble("workingGroupChange")},e.placeCursor=t,e.unwrap=function(){this.ends[Ce].children().disown().adopt(this.parent,this,this[je]).jQ.insertAfter(this.jQ),this.remove()},e.deleteSide=function(t,e,n){var i,s=this.parent,r=this[t],o=s.ends[t];return t===this.side?(this.unwrap(),void(r?n.insDirOf(-t,r):n.insAtDirEnd(t,s))):(this.side=-t,void(this.oppBrack(this.ends[Ce].ends[this.side],t)?(this.closeOpposing(this.ends[Ce].ends[this.side]),i=this.ends[Ce].ends[t],this.unwrap(),i.siblingCreated&&i.siblingCreated(n.options,t),r?n.insDirOf(-t,r):n.insAtDirEnd(t,s)):(this.oppBrack(this.parent.parent,t)?(this.parent.parent.closeOpposing(this),this.parent.parent.unwrap()):(this.sides[t]={ch:fe[this.sides[this.side].ch],ctrlSeq:fe[this.sides[this.side].ctrlSeq]},this.delimjQs.removeClass("mq-ghost").eq(t===Ce?0:1).addClass("mq-ghost").html(this.sides[t].ch)),r?(i=this.ends[Ce].ends[t],Ae(r,o,-t).disown().withDirAdopt(-t,this.ends[Ce],i,0).jQ.insAtDirEnd(t,this.ends[Ce].jQ.removeClass("mq-empty")),i.siblingCreated&&i.siblingCreated(n.options,t),n.insDirOf(-t,r)):e?n.insDirOf(t,this):n.insAtDirEnd(t,this.ends[Ce]))))},e.deleteTowards=function(t,e){this.deleteSide(-t,!1,e)},e.finalizeTree=function(t){this.ends[Ce].deleteOutOf=function(t,e){this.parent.deleteSide(t,!0,e)},t.autoOnBrackets&&this[Ce]instanceof I&&this[Ce].autoUnItalicize(t,"\\left["!==this.ctrlSeq),this.finalizeTree=this.intentionalBlur=function(){this.delimjQs.eq(this.side===Ce?1:0).removeClass("mq-ghost"),this.side=0}},e.siblingCreated=function(t,e){e===-this.side&&this.finalizeTree()}}),fe={"(":")",")":"(","[":"]","]":"[","{":"}","}":"{","\\{":"\\}","\\}":"\\{","&lang;":"&rang;","&rang;":"&lang;","\\langle ":"\\rangle ","\\rangle ":"\\langle ","|":"|"},f("("),f("["),f("{","\\{"),De.langle=i(pe,Ce,"&lang;","&rang;","\\langle ","\\rangle "),De.rangle=i(pe,je,"&lang;","&rang;","\\langle ","\\rangle "),_e["|"]=i(pe,Ce,"|","|","|","|"),De.left=ye(y,function(t){t.parser=function(){var t=q.regex,e=q.string,n=(q.succeed,q.optWhitespace);return n.then(t(/^(?:[([|]|\\\{)/)).then(function(i){var s="\\"===i.charAt(0)?i.slice(1):i;return k.then(function(r){return e("\\right").skip(n).then(t(/^(?:[\])|]|\\\})/)).map(function(t){var e="\\"===t.charAt(0)?t.slice(1):t,n=pe(0,s,e,i,t);return n.blocks=[r],r.adopt(n,0,0),n})})})}}),De.right=ye(y,function(t){t.parser=function(){return q.fail("unmatched \\right")}}),de=De.binom=De.binomial=ye(ye(y,p),function(t){t.ctrlSeq="\\binom",t.htmlTemplate='<span class="mq-non-leaf"><span class="mq-paren mq-scaled">(</span><span class="mq-non-leaf"><span class="mq-array mq-non-leaf"><span>&0</span><span>&1</span></span></span><span class="mq-paren mq-scaled">)</span></span>',t.textTemplate=["choose(",",",")"]}),me=De.choose=ye(de,function(t){t.createLeftOf=ae.prototype.createLeftOf}),ge=ye(a.MathField,function(t){t.init=function(t,e){c(t),this.__options=g();var n=Re(this,t,e);n.editable=!0,n.createTextarea(),n.editablesTextareaEvents(),n.cursor.insAtRightEnd(t)}}),De.MathQuillMathField=ye(y,function(t,e){t.ctrlSeq="\\MathQuillMathField",t.htmlTemplate='<span class="mq-editable-field"><span class="mq-root-block">&0</span></span>',t.parser=function(){var t=this,n=q.string,i=q.regex,s=q.succeed;return n("[").then(i(/^[a-z][a-z0-9]*/i)).skip(n("]")).map(function(e){t.name=e}).or(s()).then(e.parser.call(t))},t.finalizeTree=function(){ge(this.ends[Ce],this.jQ)},t.registerInnerField=function(t){t.push(t[this.name]=this.ends[Ce].controller.API)},t.latex=function(){return this.ends[Ce].latex()},t.text=function(t){return this.ends[Ce].text(t)}})}(); \ No newline at end of file