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">‍</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 '&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 = '<';
- else if (ch === '>') html = '>';
- 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 ','≠');
-
- LatexCmds.ast = LatexCmds.star = LatexCmds.loast = LatexCmds.lowast =
- bind(BinaryOperator,'\\ast ','∗');
- //case 'there4 = // a special exception for this one, perhaps?
- LatexCmds.therefor = LatexCmds.therefore =
- bind(BinaryOperator,'\\therefore ','∴');
-
- LatexCmds.cuz = // l33t
- LatexCmds.because = bind(BinaryOperator,'\\because ','∵');
-
- LatexCmds.prop = LatexCmds.propto = bind(BinaryOperator,'\\propto ','∝');
-
- LatexCmds['\u2248'] = LatexCmds.asymp = LatexCmds.approx = bind(BinaryOperator,'\\approx ','≈');
-
- LatexCmds.isin = LatexCmds['in'] = bind(BinaryOperator,'\\in ','∈');
-
- LatexCmds.ni = LatexCmds.contains = bind(BinaryOperator,'\\ni ','∋');
-
- LatexCmds.notni = LatexCmds.niton = LatexCmds.notcontains = LatexCmds.doesnotcontain =
- bind(BinaryOperator,'\\not\\ni ','∌');
-
- LatexCmds.sub = LatexCmds.subset = bind(BinaryOperator,'\\subset ','⊂');
-
- LatexCmds.sup = LatexCmds.supset = LatexCmds.superset =
- bind(BinaryOperator,'\\supset ','⊃');
-
- LatexCmds.nsub = LatexCmds.notsub =
- LatexCmds.nsubset = LatexCmds.notsubset =
- bind(BinaryOperator,'\\not\\subset ','⊄');
-
- LatexCmds.nsup = LatexCmds.notsup =
- LatexCmds.nsupset = LatexCmds.notsupset =
- LatexCmds.nsuperset = LatexCmds.notsuperset =
- bind(BinaryOperator,'\\not\\supset ','⊅');
-
- LatexCmds.sube = LatexCmds.subeq = LatexCmds.subsete = LatexCmds.subseteq =
- bind(BinaryOperator,'\\subseteq ','⊆');
-
- LatexCmds.supe = LatexCmds.supeq =
- LatexCmds.supsete = LatexCmds.supseteq =
- LatexCmds.supersete = LatexCmds.superseteq =
- bind(BinaryOperator,'\\supseteq ','⊇');
-
- LatexCmds.nsube = LatexCmds.nsubeq =
- LatexCmds.notsube = LatexCmds.notsubeq =
- LatexCmds.nsubsete = LatexCmds.nsubseteq =
- LatexCmds.notsubsete = LatexCmds.notsubseteq =
- bind(BinaryOperator,'\\not\\subseteq ','⊈');
-
- 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 ','⊉');
-
-
-//the canonical sets of numbers
- LatexCmds.N = LatexCmds.naturals = LatexCmds.Naturals =
- bind(VanillaSymbol,'\\mathbb{N}','ℕ');
-
- LatexCmds.P =
- LatexCmds.primes = LatexCmds.Primes =
- LatexCmds.projective = LatexCmds.Projective =
- LatexCmds.probability = LatexCmds.Probability =
- bind(VanillaSymbol,'\\mathbb{P}','ℙ');
-
- LatexCmds.Z = LatexCmds.integers = LatexCmds.Integers =
- bind(VanillaSymbol,'\\mathbb{Z}','ℤ');
-
- LatexCmds.Q = LatexCmds.rationals = LatexCmds.Rationals =
- bind(VanillaSymbol,'\\mathbb{Q}','ℚ');
-
- LatexCmds.R = LatexCmds.reals = LatexCmds.Reals =
- bind(VanillaSymbol,'\\mathbb{R}','ℝ');
-
- LatexCmds.C =
- LatexCmds.complex = LatexCmds.Complex =
- LatexCmds.complexes = LatexCmds.Complexes =
- LatexCmds.complexplane = LatexCmds.Complexplane = LatexCmds.ComplexPlane =
- bind(VanillaSymbol,'\\mathbb{C}','ℂ');
-
- LatexCmds.H = LatexCmds.Hamiltonian = LatexCmds.quaternions = LatexCmds.Quaternions =
- bind(VanillaSymbol,'\\mathbb{H}','ℍ');
-
-//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 ', '◇');
- LatexCmds.bigtriangleup = bind(VanillaSymbol, '\\bigtriangleup ', '△');
- LatexCmds.ominus = bind(VanillaSymbol, '\\ominus ', '⊖');
- LatexCmds.uplus = bind(VanillaSymbol, '\\uplus ', '⊎');
- LatexCmds.bigtriangledown = bind(VanillaSymbol, '\\bigtriangledown ', '▽');
- LatexCmds.sqcap = bind(VanillaSymbol, '\\sqcap ', '⊓');
- LatexCmds.triangleleft = bind(VanillaSymbol, '\\triangleleft ', '⊲');
- LatexCmds.sqcup = bind(VanillaSymbol, '\\sqcup ', '⊔');
- LatexCmds.triangleright = bind(VanillaSymbol, '\\triangleright ', '⊳');
- LatexCmds.odot = bind(VanillaSymbol, '\\odot ', '⊙');
- LatexCmds.bigcirc = bind(VanillaSymbol, '\\bigcirc ', '◯');
- LatexCmds.dagger = bind(VanillaSymbol, '\\dagger ', '†');
- LatexCmds.ddagger = bind(VanillaSymbol, '\\ddagger ', '‡');
- LatexCmds.wr = bind(VanillaSymbol, '\\wr ', '≀');
- LatexCmds.amalg = bind(VanillaSymbol, '\\amalg ', '∐');
-
-//relationship symbols
- LatexCmds.models = bind(VanillaSymbol, '\\models ', '⊨');
- LatexCmds.prec = bind(VanillaSymbol, '\\prec ', '≺');
- LatexCmds.succ = bind(VanillaSymbol, '\\succ ', '≻');
- LatexCmds.preceq = bind(VanillaSymbol, '\\preceq ', '≼');
- LatexCmds.succeq = bind(VanillaSymbol, '\\succeq ', '≽');
- LatexCmds.simeq = bind(VanillaSymbol, '\\simeq ', '≃');
- LatexCmds.mid = bind(VanillaSymbol, '\\mid ', '∣');
- LatexCmds.ll = bind(VanillaSymbol, '\\ll ', '≪');
- LatexCmds.gg = bind(VanillaSymbol, '\\gg ', '≫');
- LatexCmds.parallel = bind(VanillaSymbol, '\\parallel ', '∥');
- LatexCmds.bowtie = bind(VanillaSymbol, '\\bowtie ', '⋈');
- LatexCmds.sqsubset = bind(VanillaSymbol, '\\sqsubset ', '⊏');
- LatexCmds.sqsupset = bind(VanillaSymbol, '\\sqsupset ', '⊐');
- LatexCmds.smile = bind(VanillaSymbol, '\\smile ', '⌣');
- LatexCmds.sqsubseteq = bind(VanillaSymbol, '\\sqsubseteq ', '⊑');
- LatexCmds.sqsupseteq = bind(VanillaSymbol, '\\sqsupseteq ', '⊒');
- LatexCmds.doteq = bind(VanillaSymbol, '\\doteq ', '≐');
- LatexCmds.frown = bind(VanillaSymbol, '\\frown ', '⌢');
- LatexCmds.vdash = bind(VanillaSymbol, '\\vdash ', '⊦');
- LatexCmds.dashv = bind(VanillaSymbol, '\\dashv ', '⊣');
-
-//arrows
- LatexCmds.longleftarrow = bind(VanillaSymbol, '\\longleftarrow ', '←');
- LatexCmds.longrightarrow = bind(VanillaSymbol, '\\longrightarrow ', '→');
- LatexCmds.Longleftarrow = bind(VanillaSymbol, '\\Longleftarrow ', '⇐');
- LatexCmds.Longrightarrow = bind(VanillaSymbol, '\\Longrightarrow ', '⇒');
- LatexCmds.longleftrightarrow = bind(VanillaSymbol, '\\longleftrightarrow ', '↔');
- LatexCmds.updownarrow = bind(VanillaSymbol, '\\updownarrow ', '↕');
- LatexCmds.Longleftrightarrow = bind(VanillaSymbol, '\\Longleftrightarrow ', '⇔');
- LatexCmds.Updownarrow = bind(VanillaSymbol, '\\Updownarrow ', '⇕');
- LatexCmds.mapsto = bind(VanillaSymbol, '\\mapsto ', '↦');
- LatexCmds.nearrow = bind(VanillaSymbol, '\\nearrow ', '↗');
- LatexCmds.hookleftarrow = bind(VanillaSymbol, '\\hookleftarrow ', '↩');
- LatexCmds.hookrightarrow = bind(VanillaSymbol, '\\hookrightarrow ', '↪');
- LatexCmds.searrow = bind(VanillaSymbol, '\\searrow ', '↘');
- LatexCmds.leftharpoonup = bind(VanillaSymbol, '\\leftharpoonup ', '↼');
- LatexCmds.rightharpoonup = bind(VanillaSymbol, '\\rightharpoonup ', '⇀');
- LatexCmds.swarrow = bind(VanillaSymbol, '\\swarrow ', '↙');
- LatexCmds.leftharpoondown = bind(VanillaSymbol, '\\leftharpoondown ', '↽');
- LatexCmds.rightharpoondown = bind(VanillaSymbol, '\\rightharpoondown ', '⇁');
- LatexCmds.nwarrow = bind(VanillaSymbol, '\\nwarrow ', '↖');
-
-//Misc
- LatexCmds.ldots = bind(VanillaSymbol, '\\ldots ', '…');
- LatexCmds.cdots = bind(VanillaSymbol, '\\cdots ', '⋯');
- LatexCmds.vdots = bind(VanillaSymbol, '\\vdots ', '⋮');
- LatexCmds.ddots = bind(VanillaSymbol, '\\ddots ', '⋰');
- LatexCmds.surd = bind(VanillaSymbol, '\\surd ', '√');
- LatexCmds.triangle = bind(VanillaSymbol, '\\triangle ', '▵');
- LatexCmds.ell = bind(VanillaSymbol, '\\ell ', 'ℓ');
- LatexCmds.top = bind(VanillaSymbol, '\\top ', '⊤');
- LatexCmds.flat = bind(VanillaSymbol, '\\flat ', '♭');
- LatexCmds.natural = bind(VanillaSymbol, '\\natural ', '♮');
- LatexCmds.sharp = bind(VanillaSymbol, '\\sharp ', '♯');
- LatexCmds.wp = bind(VanillaSymbol, '\\wp ', '℘');
- LatexCmds.bot = bind(VanillaSymbol, '\\bot ', '⊥');
- LatexCmds.clubsuit = bind(VanillaSymbol, '\\clubsuit ', '♣');
- LatexCmds.diamondsuit = bind(VanillaSymbol, '\\diamondsuit ', '♢');
- LatexCmds.heartsuit = bind(VanillaSymbol, '\\heartsuit ', '♡');
- LatexCmds.spadesuit = bind(VanillaSymbol, '\\spadesuit ', '♠');
-
-//variable-sized
- LatexCmds.oint = bind(VanillaSymbol, '\\oint ', '∮');
- LatexCmds.bigcap = bind(VanillaSymbol, '\\bigcap ', '∩');
- LatexCmds.bigcup = bind(VanillaSymbol, '\\bigcup ', '∪');
- LatexCmds.bigsqcup = bind(VanillaSymbol, '\\bigsqcup ', '⊔');
- LatexCmds.bigvee = bind(VanillaSymbol, '\\bigvee ', '∨');
- LatexCmds.bigwedge = bind(VanillaSymbol, '\\bigwedge ', '∧');
- LatexCmds.bigodot = bind(VanillaSymbol, '\\bigodot ', '⊙');
- LatexCmds.bigotimes = bind(VanillaSymbol, '\\bigotimes ', '⊗');
- LatexCmds.bigoplus = bind(VanillaSymbol, '\\bigoplus ', '⊕');
- LatexCmds.biguplus = bind(VanillaSymbol, '\\biguplus ', '⊎');
-
-//delimiters
- LatexCmds.lfloor = bind(VanillaSymbol, '\\lfloor ', '⌊');
- LatexCmds.rfloor = bind(VanillaSymbol, '\\rfloor ', '⌋');
- LatexCmds.lceil = bind(VanillaSymbol, '\\lceil ', '⌈');
- LatexCmds.rceil = bind(VanillaSymbol, '\\rceil ', '⌉');
- 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>∫</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 ','⊥');
- LatexCmds.nabla = LatexCmds.del = bind(VanillaSymbol,'\\nabla ','∇');
- LatexCmds.hbar = bind(VanillaSymbol,'\\hbar ','ℏ');
-
- LatexCmds.AA = LatexCmds.Angstrom = LatexCmds.angstrom =
- bind(VanillaSymbol,'\\text\\AA ','Å');
-
- LatexCmds.ring = LatexCmds.circ = LatexCmds.circle =
- bind(VanillaSymbol,'\\circ ','∘');
-
- LatexCmds.bull = LatexCmds.bullet = bind(VanillaSymbol,'\\bullet ','•');
-
- LatexCmds.setminus = LatexCmds.smallsetminus =
- bind(VanillaSymbol,'\\setminus ','∖');
-
- LatexCmds.not = //bind(Symbol,'\\not ','<span class="not">/</span>');
- LatexCmds['\u00ac'] = LatexCmds.neg = bind(VanillaSymbol,'\\neg ','¬');
-
- LatexCmds['\u2026'] = LatexCmds.dots = LatexCmds.ellip = LatexCmds.hellip =
- LatexCmds.ellipsis = LatexCmds.hellipsis =
- bind(VanillaSymbol,'\\dots ','…');
-
- LatexCmds.converges =
- LatexCmds.darr = LatexCmds.dnarr = LatexCmds.dnarrow = LatexCmds.downarrow =
- bind(VanillaSymbol,'\\downarrow ','↓');
-
- LatexCmds.dArr = LatexCmds.dnArr = LatexCmds.dnArrow = LatexCmds.Downarrow =
- bind(VanillaSymbol,'\\Downarrow ','⇓');
-
- LatexCmds.diverges = LatexCmds.uarr = LatexCmds.uparrow =
- bind(VanillaSymbol,'\\uparrow ','↑');
-
- LatexCmds.uArr = LatexCmds.Uparrow = bind(VanillaSymbol,'\\Uparrow ','⇑');
-
- LatexCmds.to = bind(BinaryOperator,'\\to ','→');
-
- LatexCmds.rarr = LatexCmds.rightarrow = bind(VanillaSymbol,'\\rightarrow ','→');
-
- LatexCmds.implies = bind(BinaryOperator,'\\Rightarrow ','⇒');
-
- LatexCmds.rArr = LatexCmds.Rightarrow = bind(VanillaSymbol,'\\Rightarrow ','⇒');
-
- LatexCmds.gets = bind(BinaryOperator,'\\gets ','←');
-
- LatexCmds.larr = LatexCmds.leftarrow = bind(VanillaSymbol,'\\leftarrow ','←');
-
- LatexCmds.impliedby = bind(BinaryOperator,'\\Leftarrow ','⇐');
-
- LatexCmds.lArr = LatexCmds.Leftarrow = bind(VanillaSymbol,'\\Leftarrow ','⇐');
-
- LatexCmds.harr = LatexCmds.lrarr = LatexCmds.leftrightarrow =
- bind(VanillaSymbol,'\\leftrightarrow ','↔');
-
- LatexCmds.iff = bind(BinaryOperator,'\\Leftrightarrow ','⇔');
-
- LatexCmds.hArr = LatexCmds.lrArr = LatexCmds.Leftrightarrow =
- bind(VanillaSymbol,'\\Leftrightarrow ','⇔');
-
- LatexCmds.Re = LatexCmds.Real = LatexCmds.real = bind(VanillaSymbol,'\\Re ','ℜ');
-
- LatexCmds.Im = LatexCmds.imag =
- LatexCmds.image = LatexCmds.imagin = LatexCmds.imaginary = LatexCmds.Imaginary =
- bind(VanillaSymbol,'\\Im ','ℑ');
-
- LatexCmds.part = LatexCmds.partial = bind(VanillaSymbol,'\\partial ','∂');
-
- LatexCmds.infty = LatexCmds.infin = LatexCmds.infinity =
- bind(VanillaSymbol,'\\infty ','∞');
-
- LatexCmds.alef = LatexCmds.alefsym = LatexCmds.aleph = LatexCmds.alephsym =
- bind(VanillaSymbol,'\\aleph ','ℵ');
-
- LatexCmds.xist = //LOL
- LatexCmds.xists = LatexCmds.exist = LatexCmds.exists =
- bind(VanillaSymbol,'\\exists ','∃');
-
- LatexCmds.and = LatexCmds.land = LatexCmds.wedge =
- bind(VanillaSymbol,'\\wedge ','∧');
-
- LatexCmds.or = LatexCmds.lor = LatexCmds.vee = bind(VanillaSymbol,'\\vee ','∨');
-
- LatexCmds.o = LatexCmds.O =
- LatexCmds.empty = LatexCmds.emptyset =
- LatexCmds.oslash = LatexCmds.Oslash =
- LatexCmds.nothing = LatexCmds.varnothing =
- bind(BinaryOperator,'\\varnothing ','∅');
-
- LatexCmds.cup = LatexCmds.union = bind(BinaryOperator,'\\cup ','∪');
-
- LatexCmds.cap = LatexCmds.intersect = LatexCmds.intersection =
- bind(BinaryOperator,'\\cap ','∩');
-
- LatexCmds.deg = LatexCmds.degree = bind(VanillaSymbol,'^\\circ ','°');
-
- LatexCmds.ang = LatexCmds.angle = bind(VanillaSymbol,'\\angle ','∠');
- /*********************************
- * 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">ƒ</var>');
- };
- _.italicize = function(bool) {
- this.jQ.html(bool ? 'ƒ' : 'f').toggleClass('mq-florin', bool);
- return super_.italicize.apply(this, arguments);
- };
- });
-
-// VanillaSymbol's
- LatexCmds[' '] = LatexCmds.space = bind(VanillaSymbol, '\\ ', ' ');
-
- LatexCmds["'"] = LatexCmds.prime = bind(VanillaSymbol, "'", '′');
-
- LatexCmds.backslash = bind(VanillaSymbol,'\\backslash ','\\');
- if (!CharCmds['\\']) CharCmds['\\'] = LatexCmds.backslash;
-
- LatexCmds.$ = bind(VanillaSymbol, '\\$', '$');
-
-// does not use Symbola font
- var NonSymbolaSymbol = P(Symbol, function(_, super_) {
- _.init = function(ch, html) {
- super_.init.call(this, ch, '<span class="mq-nonSymbola">'+(html || ch)+'</span>');
- };
- });
-
- LatexCmds['@'] = NonSymbolaSymbol;
- LatexCmds['&'] = bind(NonSymbolaSymbol, '\\&', '&');
- LatexCmds['%'] = bind(NonSymbolaSymbol, '\\%', '%');
-
-//the following are all Greek to me, but this helped a lot: http://www.ams.org/STIX/ion/stixsig03.html
-
-//lowercase Greek letter variables
- LatexCmds.alpha =
- LatexCmds.beta =
- LatexCmds.gamma =
- LatexCmds.delta =
- LatexCmds.zeta =
- LatexCmds.eta =
- LatexCmds.theta =
- LatexCmds.iota =
- LatexCmds.kappa =
- LatexCmds.mu =
- LatexCmds.nu =
- LatexCmds.xi =
- LatexCmds.rho =
- LatexCmds.sigma =
- LatexCmds.tau =
- LatexCmds.chi =
- LatexCmds.psi =
- LatexCmds.omega = P(Variable, function(_, super_) {
- _.init = function(latex) {
- super_.init.call(this,'\\'+latex+' ','&'+latex+';');
- };
- });
-
-//why can't anybody FUCKING agree on these
- LatexCmds.phi = //W3C or Unicode?
- bind(Variable,'\\phi ','ϕ');
-
- LatexCmds.phiv = //Elsevier and 9573-13
- LatexCmds.varphi = //AMS and LaTeX
- bind(Variable,'\\varphi ','φ');
-
- LatexCmds.epsilon = //W3C or Unicode?
- bind(Variable,'\\epsilon ','ϵ');
-
- LatexCmds.epsiv = //Elsevier and 9573-13
- LatexCmds.varepsilon = //AMS and LaTeX
- bind(Variable,'\\varepsilon ','ε');
-
- LatexCmds.piv = //W3C/Unicode and Elsevier and 9573-13
- LatexCmds.varpi = //AMS and LaTeX
- bind(Variable,'\\varpi ','ϖ');
-
- LatexCmds.sigmaf = //W3C/Unicode
- LatexCmds.sigmav = //Elsevier
- LatexCmds.varsigma = //LaTeX
- bind(Variable,'\\varsigma ','ς');
-
- LatexCmds.thetav = //Elsevier and 9573-13
- LatexCmds.vartheta = //AMS and LaTeX
- LatexCmds.thetasym = //W3C/Unicode
- bind(Variable,'\\vartheta ','ϑ');
-
- LatexCmds.upsilon = //AMS and LaTeX and W3C/Unicode
- LatexCmds.upsi = //Elsevier and 9573-13
- bind(Variable,'\\upsilon ','υ');
-
-//these aren't even mentioned in the HTML character entity references
- LatexCmds.gammad = //Elsevier
- LatexCmds.Gammad = //9573-13 -- WTF, right? I dunno if this was a typo in the reference (see above)
- LatexCmds.digamma = //LaTeX
- bind(Variable,'\\digamma ','ϝ');
-
- LatexCmds.kappav = //Elsevier
- LatexCmds.varkappa = //AMS and LaTeX
- bind(Variable,'\\varkappa ','ϰ');
-
- LatexCmds.rhov = //Elsevier and 9573-13
- LatexCmds.varrho = //AMS and LaTeX
- bind(Variable,'\\varrho ','ϱ');
-
-//Greek constants, look best in non-italicized Times New Roman
- LatexCmds.pi = LatexCmds['\u03c0'] = bind(NonSymbolaSymbol,'\\pi ','π');
- LatexCmds.lambda = bind(NonSymbolaSymbol,'\\lambda ','λ');
-
-//uppercase greek letters
-
- LatexCmds.Upsilon = //LaTeX
- LatexCmds.Upsi = //Elsevier and 9573-13
- LatexCmds.upsih = //W3C/Unicode "upsilon with hook"
- LatexCmds.Upsih = //'cos it makes sense to me
- bind(Symbol,'\\Upsilon ','<var style="font-family: serif">ϒ</var>'); //Symbola's 'upsilon with a hook' is a capital Y without hooks :(
-
-//other symbols with the same LaTeX command and HTML character entity reference
- LatexCmds.Gamma =
- LatexCmds.Delta =
- LatexCmds.Theta =
- LatexCmds.Lambda =
- LatexCmds.Xi =
- LatexCmds.Pi =
- LatexCmds.Sigma =
- LatexCmds.Phi =
- LatexCmds.Psi =
- LatexCmds.Omega =
- LatexCmds.forall = P(VanillaSymbol, function(_, super_) {
- _.init = function(latex) {
- super_.init.call(this,'\\'+latex+' ','&'+latex+';');
- };
- });
-
-// symbols that aren't a single MathCommand, but are instead a whole
-// Fragment. Creates the Fragment from a LaTeX string
- var LatexFragment = P(MathCommand, function(_) {
- _.init = function(latex) { this.latex = latex; };
- _.createLeftOf = function(cursor) {
- var block = latexMathParser.parse(this.latex);
- block.children().adopt(cursor.parent, cursor[L], cursor[R]);
- cursor[L] = block.ends[R];
- block.jQize().insertBefore(cursor.jQ);
- block.finalizeInsert(cursor.options, cursor);
- if (block.ends[R][R].siblingCreated) block.ends[R][R].siblingCreated(cursor.options, L);
- if (block.ends[L][L].siblingCreated) block.ends[L][L].siblingCreated(cursor.options, R);
- cursor.parent.bubble('reflow');
- };
- _.parser = function() {
- var frag = latexMathParser.parse(this.latex).children();
- return Parser.succeed(frag);
- };
- });
-
-// for what seems to me like [stupid reasons][1], Unicode provides
-// subscripted and superscripted versions of all ten Arabic numerals,
-// as well as [so-called "vulgar fractions"][2].
-// Nobody really cares about most of them, but some of them actually
-// predate Unicode, dating back to [ISO-8859-1][3], apparently also
-// known as "Latin-1", which among other things [Windows-1252][4]
-// largely coincides with, so Microsoft Word sometimes inserts them
-// and they get copy-pasted into MathQuill.
-//
-// (Irrelevant but funny story: 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, '-', '−');
- LatexCmds['\u00b1'] = LatexCmds.pm = LatexCmds.plusmn = LatexCmds.plusminus =
- bind(PlusMinus,'\\pm ','±');
- LatexCmds.mp = LatexCmds.mnplus = LatexCmds.minusplus =
- bind(PlusMinus,'\\mp ','∓');
-
- CharCmds['*'] = LatexCmds.sdot = LatexCmds.cdot =
- bind(BinaryOperator, '\\cdot ', '·', '*');
-//semantically should be ⋅, but · looks better
-
- var Inequality = P(BinaryOperator, function(_, super_) {
- _.init = function(data, strict) {
- this.data = data;
- this.strict = strict;
- var strictness = (strict ? 'Strict' : '');
- super_.init.call(this, data['ctrlSeq'+strictness], data['html'+strictness],
- data['text'+strictness]);
- };
- _.swap = function(strict) {
- this.strict = strict;
- var strictness = (strict ? 'Strict' : '');
- this.ctrlSeq = this.data['ctrlSeq'+strictness];
- this.jQ.html(this.data['html'+strictness]);
- this.textTemplate = [ this.data['text'+strictness] ];
- };
- _.deleteTowards = function(dir, cursor) {
- if (dir === L && !this.strict) {
- this.swap(true);
- return;
- }
- super_.deleteTowards.apply(this, arguments);
- };
- });
-
- var less = { ctrlSeq: '\\le ', html: '≤', text: '\u2264',
- ctrlSeqStrict: '<', htmlStrict: '<', textStrict: '<' };
- var greater = { ctrlSeq: '\\ge ', html: '≥', text: '\u2265',
- ctrlSeqStrict: '>', htmlStrict: '>', 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 ', '×', '[x]');
-
- LatexCmds['\u00f7'] = LatexCmds.div = LatexCmds.divide = LatexCmds.divides =
- bind(BinaryOperator,'\\div ','÷', '[/]');
- /***************************
- * 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"> </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 ','∑');
-
- LatexCmds['\u220f'] =
- LatexCmds.prod =
- LatexCmds.product = bind(SummationNotation,'\\prod ','∏');
-
- LatexCmds.coprod =
- LatexCmds.coproduct = bind(SummationNotation,'\\coprod ','∐');
-
-
-
- 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"> </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"> </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">√</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">→</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">√</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 = {
- '(': ')',
- ')': '(',
- '[': ']',
- ']': '[',
- '{': '}',
- '}': '{',
- '\\{': '\\}',
- '\\}': '\\{',
- '⟨': '⟩',
- '⟩': '⟨',
- '\\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, '⟨', '⟩', '\\langle ', '\\rangle ');
- LatexCmds.rangle = bind(Bracket, R, '⟨', '⟩', '\\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">‍</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="<":">"===e&&(i=">"),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 ","≠"),De.ast=De.star=De.loast=De.lowast=i(Q,"\\ast ","∗"),De.therefor=De.therefore=i(Q,"\\therefore ","∴"),De.cuz=De.because=i(Q,"\\because ","∵"),De.prop=De.propto=i(Q,"\\propto ","∝"),De["≈"]=De.asymp=De.approx=i(Q,"\\approx ","≈"),De.isin=De["in"]=i(Q,"\\in ","∈"),De.ni=De.contains=i(Q,"\\ni ","∋"),De.notni=De.niton=De.notcontains=De.doesnotcontain=i(Q,"\\not\\ni ","∌"),De.sub=De.subset=i(Q,"\\subset ","⊂"),De.sup=De.supset=De.superset=i(Q,"\\supset ","⊃"),De.nsub=De.notsub=De.nsubset=De.notsubset=i(Q,"\\not\\subset ","⊄"),De.nsup=De.notsup=De.nsupset=De.notsupset=De.nsuperset=De.notsuperset=i(Q,"\\not\\supset ","⊅"),De.sube=De.subeq=De.subsete=De.subseteq=i(Q,"\\subseteq ","⊆"),De.supe=De.supeq=De.supsete=De.supseteq=De.supersete=De.superseteq=i(Q,"\\supseteq ","⊇"),De.nsube=De.nsubeq=De.notsube=De.notsubeq=De.nsubsete=De.nsubseteq=De.notsubsete=De.notsubseteq=i(Q,"\\not\\subseteq ","⊈"),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 ","⊉"),De.N=De.naturals=De.Naturals=i(j,"\\mathbb{N}","ℕ"),De.P=De.primes=De.Primes=De.projective=De.Projective=De.probability=De.Probability=i(j,"\\mathbb{P}","ℙ"),De.Z=De.integers=De.Integers=i(j,"\\mathbb{Z}","ℤ"),De.Q=De.rationals=De.Rationals=i(j,"\\mathbb{Q}","ℚ"),De.R=De.reals=De.Reals=i(j,"\\mathbb{R}","ℝ"),De.C=De.complex=De.Complex=De.complexes=De.Complexes=De.complexplane=De.Complexplane=De.ComplexPlane=i(j,"\\mathbb{C}","ℂ"),De.H=De.Hamiltonian=De.quaternions=De.Quaternions=i(j,"\\mathbb{H}","ℍ"),De.quad=De.emsp=i(j,"\\quad "," "),De.qquad=i(j,"\\qquad "," "),De.diamond=i(j,"\\diamond ","◇"),De.bigtriangleup=i(j,"\\bigtriangleup ","△"),De.ominus=i(j,"\\ominus ","⊖"),De.uplus=i(j,"\\uplus ","⊎"),De.bigtriangledown=i(j,"\\bigtriangledown ","▽"),De.sqcap=i(j,"\\sqcap ","⊓"),De.triangleleft=i(j,"\\triangleleft ","⊲"),De.sqcup=i(j,"\\sqcup ","⊔"),De.triangleright=i(j,"\\triangleright ","⊳"),De.odot=i(j,"\\odot ","⊙"),De.bigcirc=i(j,"\\bigcirc ","◯"),De.dagger=i(j,"\\dagger ","†"),De.ddagger=i(j,"\\ddagger ","‡"),De.wr=i(j,"\\wr ","≀"),De.amalg=i(j,"\\amalg ","∐"),De.models=i(j,"\\models ","⊨"),De.prec=i(j,"\\prec ","≺"),De.succ=i(j,"\\succ ","≻"),De.preceq=i(j,"\\preceq ","≼"),De.succeq=i(j,"\\succeq ","≽"),De.simeq=i(j,"\\simeq ","≃"),De.mid=i(j,"\\mid ","∣"),De.ll=i(j,"\\ll ","≪"),De.gg=i(j,"\\gg ","≫"),De.parallel=i(j,"\\parallel ","∥"),De.bowtie=i(j,"\\bowtie ","⋈"),De.sqsubset=i(j,"\\sqsubset ","⊏"),De.sqsupset=i(j,"\\sqsupset ","⊐"),De.smile=i(j,"\\smile ","⌣"),De.sqsubseteq=i(j,"\\sqsubseteq ","⊑"),De.sqsupseteq=i(j,"\\sqsupseteq ","⊒"),De.doteq=i(j,"\\doteq ","≐"),De.frown=i(j,"\\frown ","⌢"),De.vdash=i(j,"\\vdash ","⊦"),De.dashv=i(j,"\\dashv ","⊣"),De.longleftarrow=i(j,"\\longleftarrow ","←"),De.longrightarrow=i(j,"\\longrightarrow ","→"),De.Longleftarrow=i(j,"\\Longleftarrow ","⇐"),De.Longrightarrow=i(j,"\\Longrightarrow ","⇒"),De.longleftrightarrow=i(j,"\\longleftrightarrow ","↔"),De.updownarrow=i(j,"\\updownarrow ","↕"),De.Longleftrightarrow=i(j,"\\Longleftrightarrow ","⇔"),De.Updownarrow=i(j,"\\Updownarrow ","⇕"),De.mapsto=i(j,"\\mapsto ","↦"),De.nearrow=i(j,"\\nearrow ","↗"),De.hookleftarrow=i(j,"\\hookleftarrow ","↩"),De.hookrightarrow=i(j,"\\hookrightarrow ","↪"),De.searrow=i(j,"\\searrow ","↘"),De.leftharpoonup=i(j,"\\leftharpoonup ","↼"),De.rightharpoonup=i(j,"\\rightharpoonup ","⇀"),De.swarrow=i(j,"\\swarrow ","↙"),De.leftharpoondown=i(j,"\\leftharpoondown ","↽"),De.rightharpoondown=i(j,"\\rightharpoondown ","⇁"),De.nwarrow=i(j,"\\nwarrow ","↖"),De.ldots=i(j,"\\ldots ","…"),De.cdots=i(j,"\\cdots ","⋯"),De.vdots=i(j,"\\vdots ","⋮"),De.ddots=i(j,"\\ddots ","⋰"),De.surd=i(j,"\\surd ","√"),De.triangle=i(j,"\\triangle ","▵"),De.ell=i(j,"\\ell ","ℓ"),De.top=i(j,"\\top ","⊤"),De.flat=i(j,"\\flat ","♭"),De.natural=i(j,"\\natural ","♮"),De.sharp=i(j,"\\sharp ","♯"),De.wp=i(j,"\\wp ","℘"),De.bot=i(j,"\\bot ","⊥"),De.clubsuit=i(j,"\\clubsuit ","♣"),De.diamondsuit=i(j,"\\diamondsuit ","♢"),De.heartsuit=i(j,"\\heartsuit ","♡"),De.spadesuit=i(j,"\\spadesuit ","♠"),De.oint=i(j,"\\oint ","∮"),De.bigcap=i(j,"\\bigcap ","∩"),De.bigcup=i(j,"\\bigcup ","∪"),De.bigsqcup=i(j,"\\bigsqcup ","⊔"),De.bigvee=i(j,"\\bigvee ","∨"),De.bigwedge=i(j,"\\bigwedge ","∧"),De.bigodot=i(j,"\\bigodot ","⊙"),De.bigotimes=i(j,"\\bigotimes ","⊗"),De.bigoplus=i(j,"\\bigoplus ","⊕"),De.biguplus=i(j,"\\biguplus ","⊎"),De.lfloor=i(j,"\\lfloor ","⌊"),De.rfloor=i(j,"\\rfloor ","⌋"),De.lceil=i(j,"\\lceil ","⌈"),De.rceil=i(j,"\\rceil ","⌉"),De.opencurlybrace=De.lbrace=i(j,"\\lbrace ","{"),De.closecurlybrace=De.rbrace=i(j,"\\rbrace ","}"),De["∫"]=De["int"]=De.integral=i(C,"\\int ","<big>∫</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 ","⊥"),De.nabla=De.del=i(j,"\\nabla ","∇"),De.hbar=i(j,"\\hbar ","ℏ"),De.AA=De.Angstrom=De.angstrom=i(j,"\\text\\AA ","Å"),De.ring=De.circ=De.circle=i(j,"\\circ ","∘"),De.bull=De.bullet=i(j,"\\bullet ","•"),De.setminus=De.smallsetminus=i(j,"\\setminus ","∖"),De.not=De["¬"]=De.neg=i(j,"\\neg ","¬"),De["…"]=De.dots=De.ellip=De.hellip=De.ellipsis=De.hellipsis=i(j,"\\dots ","…"),De.converges=De.darr=De.dnarr=De.dnarrow=De.downarrow=i(j,"\\downarrow ","↓"),De.dArr=De.dnArr=De.dnArrow=De.Downarrow=i(j,"\\Downarrow ","⇓"),De.diverges=De.uarr=De.uparrow=i(j,"\\uparrow ","↑"),De.uArr=De.Uparrow=i(j,"\\Uparrow ","⇑"),De.to=i(Q,"\\to ","→"),De.rarr=De.rightarrow=i(j,"\\rightarrow ","→"),De.implies=i(Q,"\\Rightarrow ","⇒"),De.rArr=De.Rightarrow=i(j,"\\Rightarrow ","⇒"),De.gets=i(Q,"\\gets ","←"),De.larr=De.leftarrow=i(j,"\\leftarrow ","←"),De.impliedby=i(Q,"\\Leftarrow ","⇐"),De.lArr=De.Leftarrow=i(j,"\\Leftarrow ","⇐"),De.harr=De.lrarr=De.leftrightarrow=i(j,"\\leftrightarrow ","↔"),De.iff=i(Q,"\\Leftrightarrow ","⇔"),De.hArr=De.lrArr=De.Leftrightarrow=i(j,"\\Leftrightarrow ","⇔"),De.Re=De.Real=De.real=i(j,"\\Re ","ℜ"),De.Im=De.imag=De.image=De.imagin=De.imaginary=De.Imaginary=i(j,"\\Im ","ℑ"),De.part=De.partial=i(j,"\\partial ","∂"),De.infty=De.infin=De.infinity=i(j,"\\infty ","∞"),De.alef=De.alefsym=De.aleph=De.alephsym=i(j,"\\aleph ","ℵ"),De.xist=De.xists=De.exist=De.exists=i(j,"\\exists ","∃"),De.and=De.land=De.wedge=i(j,"\\wedge ","∧"),De.or=De.lor=De.vee=i(j,"\\vee ","∨"),De.o=De.O=De.empty=De.emptyset=De.oslash=De.Oslash=De.nothing=De.varnothing=i(Q,"\\varnothing ","∅"),De.cup=De.union=i(Q,"\\cup ","∪"),De.cap=De.intersect=De.intersection=i(Q,"\\cap ","∩"),De.deg=De.degree=i(j,"^\\circ ","°"),De.ang=De.angle=i(j,"\\angle ","∠"),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">ƒ</var>')},t.italicize=function(t){return this.jQ.html(t?"ƒ":"f").toggleClass("mq-florin",t),e.italicize.apply(this,arguments)}}),De[" "]=De.space=i(j,"\\ "," "),De["'"]=De.prime=i(j,"'","′"),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,"\\&","&"),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 ","ϕ"),De.phiv=De.varphi=i(R,"\\varphi ","φ"),De.epsilon=i(R,"\\epsilon ","ϵ"),De.epsiv=De.varepsilon=i(R,"\\varepsilon ","ε"),De.piv=De.varpi=i(R,"\\varpi ","ϖ"),De.sigmaf=De.sigmav=De.varsigma=i(R,"\\varsigma ","ς"),De.thetav=De.vartheta=De.thetasym=i(R,"\\vartheta ","ϑ"),De.upsilon=De.upsi=i(R,"\\upsilon ","υ"),De.gammad=De.Gammad=De.digamma=i(R,"\\digamma ","ϝ"),De.kappav=De.varkappa=i(R,"\\varkappa ","ϰ"),De.rhov=De.varrho=i(R,"\\varrho ","ϱ"),De.pi=De["π"]=i(F,"\\pi ","π"),De.lambda=i(F,"\\lambda ","λ"),De.Upsilon=De.Upsi=De.upsih=De.Upsih=i(C,"\\Upsilon ",'<var style="font-family: serif">ϒ</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,"-","−"),De["±"]=De.pm=De.plusmn=De.plusminus=i(N,"\\pm ","±"),De.mp=De.mnplus=De.minusplus=i(N,"\\mp ","∓"),_e["*"]=De.sdot=De.cdot=i(Q,"\\cdot ","·","*"),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:"≤",text:"≤",ctrlSeqStrict:"<",htmlStrict:"<",textStrict:"<"},W={ctrlSeq:"\\ge ",html:"≥",text:"≥",ctrlSeqStrict:">",htmlStrict:">",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 ","×","[x]"),De["÷"]=De.div=De.divide=De.divides=i(Q,"\\div ","÷","[/]"),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"> </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 ","∑"),De["∏"]=De.prod=De.product=i(re,"\\prod ","∏"),De.coprod=De.coproduct=i(re,"\\coprod ","∐"),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"> </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"> </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">√</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">→</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">√</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={"(":")",")":"(","[":"]","]":"[","{":"}","}":"{","\\{":"\\}","\\}":"\\{","⟨":"⟩","⟩":"⟨","\\langle ":"\\rangle ","\\rangle ":"\\langle ","|":"|"},f("("),f("["),f("{","\\{"),De.langle=i(pe,Ce,"⟨","⟩","\\langle ","\\rangle "),De.rangle=i(pe,je,"⟨","⟩","\\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