Skip to content

Instantly share code, notes, and snippets.

@codehz
Last active November 13, 2022 10:51
Show Gist options
  • Save codehz/e502f244d05d34f16f521429315148ac to your computer and use it in GitHub Desktop.
Save codehz/e502f244d05d34f16f521429315148ac to your computer and use it in GitHub Desktop.
知乎公式渲染强制使用MathJax
This file has been truncated, but you can view the full file.
// ==UserScript==
// @name Zhihu MathJax
// @namespace http://tampermonkey.net/
// @version 0.3
// @description 知乎公式渲染强制使用MathJax,配合AdBlock拦截www.zhihu.com/equation较为合适(因为用脚本隐藏还是会进行网络请求。。。)(修改自 https://zhuanlan.zhihu.com/p/27551432 ,感谢 @梨梨喵 和 @帅气可爱魔理沙 ,假装可以艾特到)
// @author CodeHz
// @match http*://*.zhihu.com/*
// @grant GM_addStyle
// ==/UserScript==
// MathJax single file build. Licenses of its components apply
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax.js
*
* The main support code for the MathJax Hub, including the
* Ajax, Callback, Messaging, and Object-Oriented Programming
* libraries, as well as the base Jax classes, and startup
* processing code.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2009-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Check if browser can support MathJax (no one fails this nowadays)
//
if (document.getElementById && document.childNodes && document.createElement) {
//
// Skip if MathJax is already loaded
//
if (!(window.MathJax && MathJax.Hub)) {
//
// Get author configuration from MathJax variable, if any
//
if (window.MathJax) {window.MathJax = {AuthorConfig: window.MathJax}}
else {window.MathJax = {}}
// MathJax.isPacked = true; // This line is uncommented by the packer.
MathJax.version = "2.7.1";
MathJax.fileversion = "2.7.1";
MathJax.cdnVersion = "2.7.1"; // specifies a revision to break caching
MathJax.cdnFileVersions = {}; // can be used to specify revisions for individual files
/**********************************************************/
(function (BASENAME) {
var BASE = window[BASENAME];
if (!BASE) {BASE = window[BASENAME] = {}}
var PROTO = []; // a static object used to indicate when a prototype is being created
var OBJECT = function (def) {
var obj = def.constructor; if (!obj) {obj = function () {}}
for (var id in def) {if (id !== 'constructor' && def.hasOwnProperty(id)) {obj[id] = def[id]}}
return obj;
};
var CONSTRUCTOR = function () {
return function () {return arguments.callee.Init.call(this,arguments)};
};
BASE.Object = OBJECT({
constructor: CONSTRUCTOR(),
Subclass: function (def,classdef) {
var obj = CONSTRUCTOR();
obj.SUPER = this; obj.Init = this.Init;
obj.Subclass = this.Subclass; obj.Augment = this.Augment;
obj.protoFunction = this.protoFunction;
obj.can = this.can; obj.has = this.has; obj.isa = this.isa;
obj.prototype = new this(PROTO);
obj.prototype.constructor = obj; // the real constructor
obj.Augment(def,classdef);
return obj;
},
Init: function (args) {
var obj = this;
if (args.length === 1 && args[0] === PROTO) {return obj}
if (!(obj instanceof args.callee)) {obj = new args.callee(PROTO)}
return obj.Init.apply(obj,args) || obj;
},
Augment: function (def,classdef) {
var id;
if (def != null) {
for (id in def) {if (def.hasOwnProperty(id)) {this.protoFunction(id,def[id])}}
// MSIE doesn't list toString even if it is not native so handle it separately
if (def.toString !== this.prototype.toString && def.toString !== {}.toString)
{this.protoFunction('toString',def.toString)}
}
if (classdef != null) {
for (id in classdef) {if (classdef.hasOwnProperty(id)) {this[id] = classdef[id]}}
}
return this;
},
protoFunction: function (id,def) {
this.prototype[id] = def;
if (typeof def === "function") {def.SUPER = this.SUPER.prototype}
},
prototype: {
Init: function () {},
SUPER: function (fn) {return fn.callee.SUPER},
can: function (method) {return typeof(this[method]) === "function"},
has: function (property) {return typeof(this[property]) !== "undefined"},
isa: function (obj) {return (obj instanceof Object) && (this instanceof obj)}
},
can: function (method) {return this.prototype.can.call(this,method)},
has: function (property) {return this.prototype.has.call(this,property)},
isa: function (obj) {
var constructor = this;
while (constructor) {
if (constructor === obj) {return true} else {constructor = constructor.SUPER}
}
return false;
},
SimpleSUPER: OBJECT({
constructor: function (def) {return this.SimpleSUPER.define(def)},
define: function (src) {
var dst = {};
if (src != null) {
for (var id in src) {if (src.hasOwnProperty(id)) {dst[id] = this.wrap(id,src[id])}}
// MSIE doesn't list toString even if it is not native so handle it separately
if (src.toString !== this.prototype.toString && src.toString !== {}.toString)
{dst.toString = this.wrap('toString',src.toString)}
}
return dst;
},
wrap: function (id,f) {
if (typeof(f) !== 'function' || !f.toString().match(/\.\s*SUPER\s*\(/)) {return f}
var fn = function () {
this.SUPER = fn.SUPER[id];
try {var result = f.apply(this,arguments)} catch (err) {delete this.SUPER; throw err}
delete this.SUPER;
return result;
}
fn.toString = function () {return f.toString.apply(f,arguments)}
return fn;
}
})
});
BASE.Object.isArray = Array.isArray || function (obj) {
return Object.prototype.toString.call(obj) === "[object Array]";
};
BASE.Object.Array = Array;
})("MathJax");
/**********************************************************/
/*
* Create a callback function from various forms of data:
*
* MathJax.Callback(fn) -- callback to a function
*
* MathJax.Callback([fn]) -- callback to function
* MathJax.Callback([fn,data...])
* -- callback to function with given data as arguments
* MathJax.Callback([object,fn])
* -- call fn with object as "this"
* MathJax.Callback([object,fn,data...])
* -- call fn with object as "this" and data as arguments
* MathJax.Callback(["method",object])
* -- call method of object wth object as "this"
* MathJax.Callback(["method",object,data...])
* -- as above, but with data as arguments to method
*
* MathJax.Callback({hook: fn, data: [...], object: this})
* -- give function, data, and object to act as "this" explicitly
*
* MathJax.Callback("code") -- callback that compiles and executes a string
*
* MathJax.Callback([...],i)
* -- use slice of array starting at i and interpret
* result as above. (Used for passing "arguments" array
* and trimming initial arguments, if any.)
*/
/*
* MathJax.Callback.After([...],cb1,cb2,...)
* -- make a callback that isn't called until all the other
* ones are called first. I.e., wait for a union of
* callbacks to occur before making the given callback.
*/
/*
* MathJax.Callback.Queue([callback,...])
* -- make a synchronized queue of commands that process
* sequentially, waiting for those that return uncalled
* callbacks.
*/
/*
* MathJax.Callback.Signal(name)
* -- finds or creates a names signal, to which listeners
* can be attached and are signaled by messages posted
* to the signal. Responses can be asynchronous.
*/
(function (BASENAME) {
var BASE = window[BASENAME];
if (!BASE) {BASE = window[BASENAME] = {}}
var isArray = BASE.Object.isArray;
//
// Create a callback from an associative array
//
var CALLBACK = function (data) {
var cb = function () {return arguments.callee.execute.apply(arguments.callee,arguments)};
for (var id in CALLBACK.prototype) {
if (CALLBACK.prototype.hasOwnProperty(id)) {
if (typeof(data[id]) !== 'undefined') {cb[id] = data[id]}
else {cb[id] = CALLBACK.prototype[id]}
}
}
cb.toString = CALLBACK.prototype.toString;
return cb;
};
CALLBACK.prototype = {
isCallback: true,
hook: function () {},
data: [],
object: window,
execute: function () {
if (!this.called || this.autoReset) {
this.called = !this.autoReset;
return this.hook.apply(this.object,this.data.concat([].slice.call(arguments,0)));
}
},
reset: function () {delete this.called},
toString: function () {return this.hook.toString.apply(this.hook,arguments)}
};
var ISCALLBACK = function (f) {
return (typeof(f) === "function" && f.isCallback);
}
//
// Evaluate a string in global context
//
var EVAL = function (code) {return eval.call(window,code)}
var TESTEVAL = function () {
EVAL("var __TeSt_VaR__ = 1"); // check if it works in global context
if (window.__TeSt_VaR__) {
try { delete window.__TeSt_VaR__; } // NOTE IE9 throws when in IE7 mode
catch (error) { window.__TeSt_VaR__ = null; }
} else {
if (window.execScript) {
// IE
EVAL = function (code) {
BASE.__code = code;
code = "try {"+BASENAME+".__result = eval("+BASENAME+".__code)} catch(err) {"+BASENAME+".__result = err}";
window.execScript(code);
var result = BASE.__result; delete BASE.__result; delete BASE.__code;
if (result instanceof Error) {throw result}
return result;
}
} else {
// Safari2
EVAL = function (code) {
BASE.__code = code;
code = "try {"+BASENAME+".__result = eval("+BASENAME+".__code)} catch(err) {"+BASENAME+".__result = err}";
var head = (document.getElementsByTagName("head"))[0]; if (!head) {head = document.body}
var script = document.createElement("script");
script.appendChild(document.createTextNode(code));
head.appendChild(script); head.removeChild(script);
var result = BASE.__result; delete BASE.__result; delete BASE.__code;
if (result instanceof Error) {throw result}
return result;
}
}
}
TESTEVAL = null;
};
//
// Create a callback from various types of data
//
var USING = function (args,i) {
if (arguments.length > 1) {
if (arguments.length === 2 && !(typeof arguments[0] === 'function') &&
arguments[0] instanceof Object && typeof arguments[1] === 'number')
{args = [].slice.call(args,i)}
else {args = [].slice.call(arguments,0)}
}
if (isArray(args) && args.length === 1) {args = args[0]}
if (typeof args === 'function') {
if (args.execute === CALLBACK.prototype.execute) {return args}
return CALLBACK({hook: args});
} else if (isArray(args)) {
if (typeof(args[0]) === 'string' && args[1] instanceof Object &&
typeof args[1][args[0]] === 'function') {
return CALLBACK({hook: args[1][args[0]], object: args[1], data: args.slice(2)});
} else if (typeof args[0] === 'function') {
return CALLBACK({hook: args[0], data: args.slice(1)});
} else if (typeof args[1] === 'function') {
return CALLBACK({hook: args[1], object: args[0], data: args.slice(2)});
}
} else if (typeof(args) === 'string') {
if (TESTEVAL) TESTEVAL();
return CALLBACK({hook: EVAL, data: [args]});
} else if (args instanceof Object) {
return CALLBACK(args);
} else if (typeof(args) === 'undefined') {
return CALLBACK({});
}
throw Error("Can't make callback from given data");
};
//
// Wait for a given time to elapse and then perform the callback
//
var DELAY = function (time,callback) {
callback = USING(callback);
callback.timeout = setTimeout(callback,time);
return callback;
};
//
// Callback used by AFTER, QUEUE, and SIGNAL to check if calls have completed
//
var WAITFOR = function (callback,signal) {
callback = USING(callback);
if (!callback.called) {WAITSIGNAL(callback,signal); signal.pending++}
};
var WAITEXECUTE = function () {
var signals = this.signal; delete this.signal;
this.execute = this.oldExecute; delete this.oldExecute;
var result = this.execute.apply(this,arguments);
if (ISCALLBACK(result) && !result.called) {WAITSIGNAL(result,signals)} else {
for (var i = 0, m = signals.length; i < m; i++) {
signals[i].pending--;
if (signals[i].pending <= 0) {signals[i].call()}
}
}
};
var WAITSIGNAL = function (callback,signals) {
if (!isArray(signals)) {signals = [signals]}
if (!callback.signal) {
callback.oldExecute = callback.execute;
callback.execute = WAITEXECUTE;
callback.signal = signals;
} else if (signals.length === 1) {callback.signal.push(signals[0])}
else {callback.signal = callback.signal.concat(signals)}
};
//
// Create a callback that is called when a collection of other callbacks have
// all been executed. If the callback gets called immediately (i.e., the
// others are all already called), check if it returns another callback
// and return that instead.
//
var AFTER = function (callback) {
callback = USING(callback);
callback.pending = 0;
for (var i = 1, m = arguments.length; i < m; i++)
{if (arguments[i]) {WAITFOR(arguments[i],callback)}}
if (callback.pending === 0) {
var result = callback();
if (ISCALLBACK(result)) {callback = result}
}
return callback;
};
//
// An array of prioritized hooks that are executed sequentially
// with a given set of data.
//
var HOOKS = MathJax.Object.Subclass({
//
// Initialize the array and the auto-reset status
//
Init: function (reset) {
this.hooks = [];
this.remove = []; // used when hooks are removed during execution of list
this.reset = reset;
this.running = false;
},
//
// Add a callback to the list, in priority order (default priority is 10)
//
Add: function (hook,priority) {
if (priority == null) {priority = 10}
if (!ISCALLBACK(hook)) {hook = USING(hook)}
hook.priority = priority;
var i = this.hooks.length;
while (i > 0 && priority < this.hooks[i-1].priority) {i--}
this.hooks.splice(i,0,hook);
return hook;
},
Remove: function (hook) {
for (var i = 0, m = this.hooks.length; i < m; i++) {
if (this.hooks[i] === hook) {
if (this.running) {this.remove.push(i)}
else {this.hooks.splice(i,1)}
return;
}
}
},
//
// Execute the list of callbacks, resetting them if requested.
// If any return callbacks, return a callback that will be
// executed when they all have completed.
// Remove any hooks that requested being removed during processing.
//
Execute: function () {
var callbacks = [{}];
this.running = true;
for (var i = 0, m = this.hooks.length; i < m; i++) {
if (this.reset) {this.hooks[i].reset()}
var result = this.hooks[i].apply(window,arguments);
if (ISCALLBACK(result) && !result.called) {callbacks.push(result)}
}
this.running = false;
if (this.remove.length) {this.RemovePending()}
if (callbacks.length === 1) {return null}
if (callbacks.length === 2) {return callbacks[1]}
return AFTER.apply({},callbacks);
},
//
// Remove hooks that asked to be removed during execution of list
//
RemovePending: function () {
this.remove = this.remove.sort();
for (var i = this.remove.length-1; i >= 0; i--) {this.hooks.splice(i,1)}
this.remove = [];
}
});
//
// Run an array of callbacks passing them the given data.
// (Legacy function, since this has been replaced by the HOOKS object).
//
var EXECUTEHOOKS = function (hooks,data,reset) {
if (!hooks) {return null}
if (!isArray(hooks)) {hooks = [hooks]}
if (!isArray(data)) {data = (data == null ? [] : [data])}
var handler = HOOKS(reset);
for (var i = 0, m = hooks.length; i < m; i++) {handler.Add(hooks[i])}
return handler.Execute.apply(handler,data);
};
//
// Command queue that performs commands in order, waiting when
// necessary for commands to complete asynchronousely
//
var QUEUE = BASE.Object.Subclass({
//
// Create the queue and push any commands that are specified
//
Init: function () {
this.pending = this.running = 0;
this.queue = [];
this.Push.apply(this,arguments);
},
//
// Add commands to the queue and run them. Adding a callback object
// (rather than a callback specification) queues a wait for that callback.
// Return the final callback for synchronization purposes.
//
Push: function () {
var callback;
for (var i = 0, m = arguments.length; i < m; i++) {
callback = USING(arguments[i]);
if (callback === arguments[i] && !callback.called)
{callback = USING(["wait",this,callback])}
this.queue.push(callback);
}
if (!this.running && !this.pending) {this.Process()}
return callback;
},
//
// Process the command queue if we aren't waiting on another command
//
Process: function (queue) {
while (!this.running && !this.pending && this.queue.length) {
var callback = this.queue[0];
queue = this.queue.slice(1); this.queue = [];
this.Suspend(); var result = callback(); this.Resume();
if (queue.length) {this.queue = queue.concat(this.queue)}
if (ISCALLBACK(result) && !result.called) {WAITFOR(result,this)}
}
},
//
// Suspend/Resume command processing on this queue
//
Suspend: function () {this.running++},
Resume: function () {if (this.running) {this.running--}},
//
// Used by WAITFOR to restart the queue when an action completes
//
call: function () {this.Process.apply(this,arguments)},
wait: function (callback) {return callback}
});
//
// Create a named signal that listeners can attach to, to be signaled by
// postings made to the signal. Posts are queued if they occur while one
// is already in process.
//
var SIGNAL = QUEUE.Subclass({
Init: function (name) {
QUEUE.prototype.Init.call(this);
this.name = name;
this.posted = []; // the messages posted so far
this.listeners = HOOKS(true); // those with interest in this signal
this.posting = false;
this.callback = null;
},
//
// Post a message to the signal listeners, with callback for when complete
//
Post: function (message,callback,forget) {
callback = USING(callback);
if (this.posting || this.pending) {
this.Push(["Post",this,message,callback,forget]);
} else {
this.callback = callback; callback.reset();
if (!forget) {this.posted.push(message)}
this.Suspend(); this.posting = true;
var result = this.listeners.Execute(message);
if (ISCALLBACK(result) && !result.called) {WAITFOR(result,this)}
this.Resume(); this.posting = false;
if (!this.pending) {this.call()}
}
return callback;
},
//
// Clear the post history (so new listeners won't get old messages)
//
Clear: function (callback) {
callback = USING(callback);
if (this.posting || this.pending) {
callback = this.Push(["Clear",this,callback]);
} else {
this.posted = [];
callback();
}
return callback;
},
//
// Call the callback (all replies are in) and process the command queue
//
call: function () {this.callback(this); this.Process()},
//
// A listener calls this to register interest in the signal (so it will be called
// when posts occur). If ignorePast is true, it will not be sent the post history.
//
Interest: function (callback,ignorePast,priority) {
callback = USING(callback);
this.listeners.Add(callback,priority);
if (!ignorePast) {
for (var i = 0, m = this.posted.length; i < m; i++) {
callback.reset();
var result = callback(this.posted[i]);
if (ISCALLBACK(result) && i === this.posted.length-1) {WAITFOR(result,this)}
}
}
return callback;
},
//
// A listener calls this to remove itself from a signal
//
NoInterest: function (callback) {
this.listeners.Remove(callback);
},
//
// Hook a callback to a particular message on this signal
//
MessageHook: function (msg,callback,priority) {
callback = USING(callback);
if (!this.hooks) {this.hooks = {}; this.Interest(["ExecuteHooks",this])}
if (!this.hooks[msg]) {this.hooks[msg] = HOOKS(true)}
this.hooks[msg].Add(callback,priority);
for (var i = 0, m = this.posted.length; i < m; i++)
{if (this.posted[i] == msg) {callback.reset(); callback(this.posted[i])}}
callback.msg = msg; // keep track so we can remove it
return callback;
},
//
// Execute the message hooks for the given message
//
ExecuteHooks: function (msg) {
var type = (isArray(msg) ? msg[0] : msg);
if (!this.hooks[type]) {return null}
return this.hooks[type].Execute(msg);
},
//
// Remove a hook safely
//
RemoveHook: function (hook) {
this.hooks[hook.msg].Remove(hook);
}
},{
signals: {}, // the named signals
find: function (name) {
if (!SIGNAL.signals[name]) {SIGNAL.signals[name] = new SIGNAL(name)}
return SIGNAL.signals[name];
}
});
//
// The main entry-points
//
BASE.Callback = BASE.CallBack = USING;
BASE.Callback.Delay = DELAY;
BASE.Callback.After = AFTER;
BASE.Callback.Queue = QUEUE;
BASE.Callback.Signal = SIGNAL.find;
BASE.Callback.Hooks = HOOKS;
BASE.Callback.ExecuteHooks = EXECUTEHOOKS;
})("MathJax");
/**********************************************************/
(function (BASENAME) {
var BASE = window[BASENAME];
if (!BASE) {BASE = window[BASENAME] = {}}
var isSafari2 = (navigator.vendor === "Apple Computer, Inc." &&
typeof navigator.vendorSub === "undefined");
var sheets = 0; // used by Safari2
//
// Update sheets count and look up the head object
//
var HEAD = function (head) {
if (document.styleSheets && document.styleSheets.length > sheets)
{sheets = document.styleSheets.length}
if (!head) {
head = document.head || ((document.getElementsByTagName("head"))[0]);
if (!head) {head = document.body}
}
return head;
};
//
// Remove scripts that are completed so they don't clutter up the HEAD.
// This runs via setTimeout since IE7 can't remove the script while it is running.
//
var SCRIPTS = []; // stores scripts to be removed after a delay
var REMOVESCRIPTS = function () {
for (var i = 0, m = SCRIPTS.length; i < m; i++) {BASE.Ajax.head.removeChild(SCRIPTS[i])}
SCRIPTS = [];
};
var PATH = {};
PATH[BASENAME] = ""; // empty path gets the root URL
PATH.a11y = '[MathJax]/extensions/a11y'; // a11y extensions
PATH.Contrib = "https://cdn.mathjax.org/mathjax/contrib"; // the third-party extensions
BASE.Ajax = {
loaded: {}, // files already loaded
loading: {}, // files currently in process of loading
loadHooks: {}, // hooks to call when files are loaded
timeout: 15*1000, // timeout for loading of files (15 seconds)
styleDelay: 1, // delay to use before styles are available
config: {
root: "", // URL of root directory to load from
path: PATH // paths to named URL's (e.g., [MathJax]/...)
},
params: {}, // filled in from MathJax.js?...
STATUS: {
OK: 1, // file is loading or did load OK
ERROR: -1 // file timed out during load
},
//
// Return a complete URL to a file (replacing any root names)
//
fileURL: function (file) {
var match;
while ((match = file.match(/^\[([-._a-z0-9]+)\]/i)) && PATH.hasOwnProperty(match[1])) {
file = (PATH[match[1]]||this.config.root) + file.substr(match[1].length+2);
}
return file;
},
//
// Replace root names if URL includes one
//
fileName: function (url) {
var root = this.config.root;
if (url.substr(0,root.length) === root) {url = "["+BASENAME+"]"+url.substr(root.length)}
do {
var recheck = false;
for (var id in PATH) {if (PATH.hasOwnProperty(id) && PATH[id]) {
if (url.substr(0,PATH[id].length) === PATH[id]) {
url = "["+id+"]"+url.substr(PATH[id].length);
recheck = true;
break;
}
}}
} while (recheck);
return url;
},
//
// Cache-breaking revision number for file
//
fileRev: function (file) {
var V = BASE.cdnFileVersions[file] || BASE.cdnVersion || '';
if (V) {V = "?V="+V}
return V;
},
urlRev: function (file) {return this.fileURL(file)+this.fileRev(file)},
//
// Load a file if it hasn't been already.
// Make sure the file URL is "safe"?
//
Require: function (file,callback) {
callback = BASE.Callback(callback); var type;
if (file instanceof Object) {
for (var i in file)
{if (file.hasOwnProperty(i)) {type = i.toUpperCase(); file = file[i]}}
} else {type = file.split(/\./).pop().toUpperCase()}
if (this.params.noContrib && file.substr(0,9) === "[Contrib]") {
callback(this.STATUS.ERROR);
} else {
file = this.fileURL(file);
// FIXME: check that URL is OK
if (this.loaded[file]) {
callback(this.loaded[file]);
} else {
var FILE = {}; FILE[type] = file;
this.Load(FILE,callback);
}
}
return callback;
},
//
// Load a file regardless of where it is and whether it has
// already been loaded.
//
Load: function (file,callback) {
callback = BASE.Callback(callback); var type;
if (file instanceof Object) {
for (var i in file)
{if (file.hasOwnProperty(i)) {type = i.toUpperCase(); file = file[i]}}
} else {type = file.split(/\./).pop().toUpperCase()}
file = this.fileURL(file);
if (this.loading[file]) {
this.addHook(file,callback);
} else {
this.head = HEAD(this.head);
if (this.loader[type]) {this.loader[type].call(this,file,callback)}
else {throw Error("Can't load files of type "+type)}
}
return callback;
},
//
// Register a load hook for a particular file (it will be called when
// loadComplete() is called for that file)
//
LoadHook: function (file,callback,priority) {
callback = BASE.Callback(callback);
if (file instanceof Object)
{for (var i in file) {if (file.hasOwnProperty(i)) {file = file[i]}}}
file = this.fileURL(file);
if (this.loaded[file]) {callback(this.loaded[file])}
else {this.addHook(file,callback,priority)}
return callback;
},
addHook: function (file,callback,priority) {
if (!this.loadHooks[file]) {this.loadHooks[file] = MathJax.Callback.Hooks()}
this.loadHooks[file].Add(callback,priority);
callback.file = file;
},
removeHook: function (hook) {
if (this.loadHooks[hook.file]) {
this.loadHooks[hook.file].Remove(hook);
if (!this.loadHooks[hook.file].hooks.length) {delete this.loadHooks[hook.file]}
}
},
//
// Used when files are combined in a preloading configuration file
//
Preloading: function () {
for (var i = 0, m = arguments.length; i < m; i++) {
var file = this.fileURL(arguments[i]);
if (!this.loading[file]) {this.loading[file] = {preloaded: true}}
}
},
//
// Code used to load the various types of files
// (JS for JavaScript, CSS for style sheets)
//
loader: {
//
// Create a SCRIPT tag to load the file
//
JS: function (file,callback) {
var name = this.fileName(file);
var script = document.createElement("script");
var timeout = BASE.Callback(["loadTimeout",this,file]);
this.loading[file] = {
callback: callback,
timeout: setTimeout(timeout,this.timeout),
status: this.STATUS.OK,
script: script
};
//
// Add this to the structure above after it is created to prevent recursion
// when loading the initial localization file (before loading messsage is available)
//
this.loading[file].message = BASE.Message.File(name);
script.onerror = timeout; // doesn't work in IE and no apparent substitute
script.type = "text/javascript";
script.src = file+this.fileRev(name);
this.head.appendChild(script);
},
//
// Create a LINK tag to load the style sheet
//
CSS: function (file,callback) {
var name = this.fileName(file);
var link = document.createElement("link");
link.rel = "stylesheet"; link.type = "text/css";
link.href = file+this.fileRev(name);
this.loading[file] = {
callback: callback,
message: BASE.Message.File(name),
status: this.STATUS.OK
};
this.head.appendChild(link);
this.timer.create.call(this,[this.timer.file,file],link);
}
},
//
// Timing code for checking when style sheets are available.
//
timer: {
//
// Create the timing callback and start the timing loop.
// We use a delay because some browsers need it to allow the styles
// to be processed.
//
create: function (callback,node) {
callback = BASE.Callback(callback);
if (node.nodeName === "STYLE" && node.styleSheet &&
typeof(node.styleSheet.cssText) !== 'undefined') {
callback(this.STATUS.OK); // MSIE processes style immediately, but doesn't set its styleSheet!
} else if (window.chrome && node.nodeName === "LINK") {
callback(this.STATUS.OK); // Chrome doesn't give access to cssRules for stylesheet in
// a link node, so we can't detect when it is loaded.
} else if (isSafari2) {
this.timer.start(this,[this.timer.checkSafari2,sheets++,callback],this.styleDelay);
} else {
this.timer.start(this,[this.timer.checkLength,node,callback],this.styleDelay);
}
return callback;
},
//
// Start the timer for the given callback checker
//
start: function (AJAX,check,delay,timeout) {
check = BASE.Callback(check);
check.execute = this.execute; check.time = this.time;
check.STATUS = AJAX.STATUS; check.timeout = timeout || AJAX.timeout;
check.delay = check.total = delay || 0;
if (delay) {setTimeout(check,delay)} else {check()}
},
//
// Increment the time total, increase the delay
// and test if we are past the timeout time.
//
time: function (callback) {
this.total += this.delay;
this.delay = Math.floor(this.delay * 1.05 + 5);
if (this.total >= this.timeout) {callback(this.STATUS.ERROR); return 1}
return 0;
},
//
// For JS file loads, call the proper routine according to status
//
file: function (file,status) {
if (status < 0) {BASE.Ajax.loadTimeout(file)} else {BASE.Ajax.loadComplete(file)}
},
//
// Call the hook with the required data
//
execute: function () {this.hook.call(this.object,this,this.data[0],this.data[1])},
//
// Safari2 doesn't set the link's stylesheet, so we need to look in the
// document.styleSheets array for the new sheet when it is created
//
checkSafari2: function (check,length,callback) {
if (check.time(callback)) return;
if (document.styleSheets.length > length &&
document.styleSheets[length].cssRules &&
document.styleSheets[length].cssRules.length)
{callback(check.STATUS.OK)} else {setTimeout(check,check.delay)}
},
//
// Look for the stylesheets rules and check when they are defined
// and no longer of length zero. (This assumes there actually ARE
// some rules in the stylesheet.)
//
checkLength: function (check,node,callback) {
if (check.time(callback)) return;
var isStyle = 0; var sheet = (node.sheet || node.styleSheet);
try {if ((sheet.cssRules||sheet.rules||[]).length > 0) {isStyle = 1}} catch(err) {
if (err.message.match(/protected variable|restricted URI/)) {isStyle = 1}
else if (err.message.match(/Security error/)) {
// Firefox3 gives "Security error" for missing files, so
// can't distinguish that from OK files on remote servers.
// or OK files in different directory from local files.
isStyle = 1; // just say it is OK (can't really tell)
}
}
if (isStyle) {
// Opera 9.6 requires this setTimeout
setTimeout(BASE.Callback([callback,check.STATUS.OK]),0);
} else {
setTimeout(check,check.delay);
}
}
},
//
// JavaScript code must call this when they are completely initialized
// (this allows them to perform asynchronous actions before indicating
// that they are complete).
//
loadComplete: function (file) {
file = this.fileURL(file);
var loading = this.loading[file];
if (loading && !loading.preloaded) {
BASE.Message.Clear(loading.message);
clearTimeout(loading.timeout);
if (loading.script) {
if (SCRIPTS.length === 0) {setTimeout(REMOVESCRIPTS,0)}
SCRIPTS.push(loading.script);
}
this.loaded[file] = loading.status; delete this.loading[file];
this.addHook(file,loading.callback);
} else {
if (loading) {delete this.loading[file]}
this.loaded[file] = this.STATUS.OK;
loading = {status: this.STATUS.OK}
}
if (!this.loadHooks[file]) {return null}
return this.loadHooks[file].Execute(loading.status);
},
//
// If a file fails to load within the timeout period (or the onerror handler
// is called), this routine runs to signal the error condition.
//
loadTimeout: function (file) {
if (this.loading[file].timeout) {clearTimeout(this.loading[file].timeout)}
this.loading[file].status = this.STATUS.ERROR;
this.loadError(file);
this.loadComplete(file);
},
//
// The default error hook for file load failures
//
loadError: function (file) {
BASE.Message.Set(["LoadFailed","File failed to load: %1",file],null,2000);
BASE.Hub.signal.Post(["file load error",file]);
},
//
// Defines a style sheet from a hash of style declarations (key:value pairs
// where the key is the style selector and the value is a hash of CSS attributes
// and values).
//
Styles: function (styles,callback) {
var styleString = this.StyleString(styles);
if (styleString === "") {
callback = BASE.Callback(callback);
callback();
} else {
var style = document.createElement("style"); style.type = "text/css";
this.head = HEAD(this.head);
this.head.appendChild(style);
if (style.styleSheet && typeof(style.styleSheet.cssText) !== 'undefined') {
style.styleSheet.cssText = styleString;
} else {
style.appendChild(document.createTextNode(styleString));
}
callback = this.timer.create.call(this,callback,style);
}
return callback;
},
//
// Create a stylesheet string from a style declaration object
//
StyleString: function (styles) {
if (typeof(styles) === 'string') {return styles}
var string = "", id, style;
for (id in styles) {if (styles.hasOwnProperty(id)) {
if (typeof styles[id] === 'string') {
string += id + " {"+styles[id]+"}\n";
} else if (BASE.Object.isArray(styles[id])) {
for (var i = 0; i < styles[id].length; i++) {
style = {}; style[id] = styles[id][i];
string += this.StyleString(style);
}
} else if (id.substr(0,6) === '@media') {
string += id + " {"+this.StyleString(styles[id])+"}\n";
} else if (styles[id] != null) {
style = [];
for (var name in styles[id]) {if (styles[id].hasOwnProperty(name)) {
if (styles[id][name] != null)
{style[style.length] = name + ': ' + styles[id][name]}
}}
string += id +" {"+style.join('; ')+"}\n";
}
}}
return string;
}
};
})("MathJax");
/**********************************************************/
MathJax.HTML = {
//
// Create an HTML element with given attributes and content.
// The def parameter is an (optional) object containing key:value pairs
// of the attributes and their values, and contents is an (optional)
// array of strings to be inserted as text, or arrays of the form
// [type,def,contents] that describes an HTML element to be inserted
// into the current element. Thus the contents can describe a complete
// HTML snippet of arbitrary complexity. E.g.:
//
// MathJax.HTML.Element("span",{id:"mySpan",style{"font-style":"italic"}},[
// "(See the ",["a",{href:"http://www.mathjax.org"},["MathJax home page"]],
// " for more details.)"]);
//
Element: function (type,def,contents) {
var obj = document.createElement(type), id;
if (def) {
if (def.hasOwnProperty("style")) {
var style = def.style; def.style = {};
for (id in style) {if (style.hasOwnProperty(id))
{def.style[id.replace(/-([a-z])/g,this.ucMatch)] = style[id]}}
}
MathJax.Hub.Insert(obj,def);
for (id in def) {
if (id === "role" || id.substr(0,5) === "aria-") obj.setAttribute(id,def[id]);
}
}
if (contents) {
if (!MathJax.Object.isArray(contents)) {contents = [contents]}
for (var i = 0, m = contents.length; i < m; i++) {
if (MathJax.Object.isArray(contents[i])) {
obj.appendChild(this.Element(contents[i][0],contents[i][1],contents[i][2]));
} else if (type === "script") { // IE throws an error if script is added as a text node
this.setScript(obj, contents[i]);
} else {
obj.appendChild(document.createTextNode(contents[i]));
}
}
}
return obj;
},
ucMatch: function (match,c) {return c.toUpperCase()},
addElement: function (span,type,def,contents) {return span.appendChild(this.Element(type,def,contents))},
TextNode: function (text) {return document.createTextNode(text)},
addText: function (span,text) {return span.appendChild(this.TextNode(text))},
//
// Set and get the text of a script
//
setScript: function (script,text) {
if (this.setScriptBug) {script.text = text} else {
while (script.firstChild) {script.removeChild(script.firstChild)}
this.addText(script,text);
}
},
getScript: function (script) {
var text = (script.text === "" ? script.innerHTML : script.text);
return text.replace(/^\s+/,"").replace(/\s+$/,"");
},
//
// Manage cookies
//
Cookie: {
prefix: "mjx",
expires: 365,
//
// Save an object as a named cookie
//
Set: function (name,def) {
var keys = [];
if (def) {
for (var id in def) {if (def.hasOwnProperty(id)) {
keys.push(id+":"+def[id].toString().replace(/&/g,"&&"));
}}
}
var cookie = this.prefix+"."+name+"="+escape(keys.join('&;'));
if (this.expires) {
var time = new Date(); time.setDate(time.getDate() + this.expires);
cookie += '; expires='+time.toGMTString();
}
try {document.cookie = cookie+"; path=/"} catch (err) {} // ignore errors saving cookies
},
//
// Get the contents of a named cookie and incorporate
// it into the given object (or return a fresh one)
//
Get: function (name,obj) {
if (!obj) {obj = {}}
var pattern = new RegExp("(?:^|;\\s*)"+this.prefix+"\\."+name+"=([^;]*)(?:;|$)");
var match;
try {match = pattern.exec(document.cookie)} catch (err) {}; // ignore errors reading cookies
if (match && match[1] !== "") {
var keys = unescape(match[1]).split('&;');
for (var i = 0, m = keys.length; i < m; i++) {
match = keys[i].match(/([^:]+):(.*)/);
var value = match[2].replace(/&&/g,'&');
if (value === "true") {value = true} else if (value === "false") {value = false}
else if (value.match(/^-?(\d+(\.\d+)?|\.\d+)$/)) {value = parseFloat(value)}
obj[match[1]] = value;
}
}
return obj;
}
}
};
/**********************************************************/
MathJax.Localization = {
locale: "en",
directory: "[MathJax]/localization",
strings: {
// Currently, this list is not modified by the MathJax-i18n script. You can
// run the following command in MathJax/unpacked/localization to update it:
//
// find . -name "*.js" | xargs grep menuTitle\: | grep -v qqq | sed 's/^\.\/\(.*\)\/.*\.js\: / "\1"\: \{/' | sed 's/,$/\},/' | sed 's/"English"/"English", isLoaded: true/' > tmp ; sort tmp > tmp2 ; sed '$ s/,$//' tmp2 ; rm tmp*
//
// This only takes languages with localization data so you must also add
// the languages that use a remap but are not translated at all.
//
"ast": {menuTitle: "asturianu"},
"bg": {menuTitle: "\u0431\u044A\u043B\u0433\u0430\u0440\u0441\u043A\u0438"},
"bcc": {menuTitle: "\u0628\u0644\u0648\u0686\u06CC"},
"br": {menuTitle: "brezhoneg"},
"ca": {menuTitle: "catal\u00E0"},
"cdo": {menuTitle: "M\u00ECng-d\u0115\u0324ng-ng\u1E73\u0304"},
"cs": {menuTitle: "\u010De\u0161tina"},
"da": {menuTitle: "dansk"},
"de": {menuTitle: "Deutsch"},
"diq": {menuTitle: "Zazaki"},
"en": {menuTitle: "English", isLoaded: true},
"eo": {menuTitle: "Esperanto"},
"es": {menuTitle: "espa\u00F1ol"},
"fa": {menuTitle: "\u0641\u0627\u0631\u0633\u06CC"},
"fi": {menuTitle: "suomi"},
"fr": {menuTitle: "fran\u00E7ais"},
"gl": {menuTitle: "galego"},
"he": {menuTitle: "\u05E2\u05D1\u05E8\u05D9\u05EA"},
"ia": {menuTitle: "interlingua"},
"it": {menuTitle: "italiano"},
"ja": {menuTitle: "\u65E5\u672C\u8A9E"},
"kn": {menuTitle: "\u0C95\u0CA8\u0CCD\u0CA8\u0CA1"},
"ko": {menuTitle: "\uD55C\uAD6D\uC5B4"},
"lb": {menuTitle: "L\u00EBtzebuergesch"},
"lki": {menuTitle: "\u0644\u06D5\u06A9\u06CC"},
"lt": {menuTitle: "lietuvi\u0173"},
"mk": {menuTitle: "\u043C\u0430\u043A\u0435\u0434\u043E\u043D\u0441\u043A\u0438"},
"nl": {menuTitle: "Nederlands"},
"oc": {menuTitle: "occitan"},
"pl": {menuTitle: "polski"},
"pt": {menuTitle: "portugus\u00EA"},
"pt-br": {menuTitle: "portugu\u00EAs do Brasil"},
"ru": {menuTitle: "\u0440\u0443\u0441\u0441\u043A\u0438\u0439"},
"sco": {menuTitle: "Scots"},
"scn": {menuTitle: "sicilianu"},
"sl": {menuTitle: "sloven\u0161\u010Dina"},
"sv": {menuTitle: "svenska"},
"tr": {menuTitle: "T\u00FCrk\u00E7e"},
"uk": {menuTitle: "\u0443\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u0430"},
"vi": {menuTitle: "Ti\u1EBFng Vi\u1EC7t"},
"zh-hans": {menuTitle: "\u4E2D\u6587\uFF08\u7B80\u4F53\uFF09"}
},
//
// The pattern for substitution escapes:
// %n or %{n} or %{plural:%n|option1|option1|...} or %c
//
pattern: /%(\d+|\{\d+\}|\{[a-z]+:\%\d+(?:\|(?:%\{\d+\}|%.|[^\}])*)+\}|.)/g,
SPLIT: ("axb".split(/(x)/).length === 3 ?
function (string,regex) {return string.split(regex)} :
//
// IE8 and below don't do split() correctly when the pattern includes
// parentheses (the split should include the matched exrepssions).
// So implement it by hand here.
//
function (string,regex) {
var result = [], match, last = 0;
regex.lastIndex = 0;
while ((match = regex.exec(string))) {
result.push(string.substr(last,match.index-last));
result.push.apply(result,match.slice(1));
last = match.index + match[0].length;
}
result.push(string.substr(last));
return result;
}),
_: function (id,phrase) {
if (MathJax.Object.isArray(phrase)) {return this.processSnippet(id,phrase)}
return this.processString(this.lookupPhrase(id,phrase),[].slice.call(arguments,2));
},
processString: function (string,args,domain) {
//
// Process arguments for substitution
// If the argument is a snippet (and we are processing snippets) do so,
// Otherwise, if it is a number, convert it for the lacale
//
var i, m, isArray = MathJax.Object.isArray;
for (i = 0, m = args.length; i < m; i++) {
if (domain && isArray(args[i])) {args[i] = this.processSnippet(domain,args[i])}
}
//
// Split string at escapes and process them individually
//
var parts = this.SPLIT(string,this.pattern);
for (i = 1, m = parts.length; i < m; i += 2) {
var c = parts[i].charAt(0); // first char will be { or \d or a char to be kept literally
if (c >= "0" && c <= "9") { // %n
parts[i] = args[parts[i]-1];
if (typeof parts[i] === "number") parts[i] = this.number(parts[i]);
} else if (c === "{") { // %{n} or %{plural:%n|...}
c = parts[i].substr(1);
if (c >= "0" && c <= "9") { // %{n}
parts[i] = args[parts[i].substr(1,parts[i].length-2)-1];
if (typeof parts[i] === "number") parts[i] = this.number(parts[i]);
} else { // %{plural:%n|...}
var match = parts[i].match(/^\{([a-z]+):%(\d+)\|(.*)\}$/);
if (match) {
if (match[1] === "plural") {
var n = args[match[2]-1];
if (typeof n === "undefined") {
parts[i] = "???"; // argument doesn't exist
} else {
n = this.plural(n) - 1; // index of the form to use
var plurals = match[3].replace(/(^|[^%])(%%)*%\|/g,"$1$2%\uEFEF").split(/\|/); // the parts (replacing %| with a special character)
if (n >= 0 && n < plurals.length) {
parts[i] = this.processString(plurals[n].replace(/\uEFEF/g,"|"),args,domain);
} else {
parts[i] = "???"; // no string for this index
}
}
} else {parts[i] = "%"+parts[i]} // not "plural", put back the % and leave unchanged
}
}
}
if (parts[i] == null) {parts[i] = "???"}
}
//
// If we are not forming a snippet, return the completed string
//
if (!domain) {return parts.join("")}
//
// We need to return an HTML snippet, so buld it from the
// broken up string with inserted parts (that could be snippets)
//
var snippet = [], part = "";
for (i = 0; i < m; i++) {
part += parts[i]; i++; // add the string and move on to substitution result
if (i < m) {
if (isArray(parts[i])) { // substitution was a snippet
snippet.push(part); // add the accumulated string
snippet = snippet.concat(parts[i]); // concatenate the substution snippet
part = ""; // start accumulating a new string
} else { // substitution was a string
part += parts[i]; // add to accumulating string
}
}
}
if (part !== "") {snippet.push(part)} // add final string
return snippet;
},
processSnippet: function (domain,snippet) {
var result = []; // the new snippet
//
// Look through the original snippet for
// strings or snippets to translate
//
for (var i = 0, m = snippet.length; i < m; i++) {
if (MathJax.Object.isArray(snippet[i])) {
//
// This could be a sub-snippet:
// ["tag"] or ["tag",{properties}] or ["tag",{properties},snippet]
// Or it could be something to translate:
// [id,string,args] or [domain,snippet]
var data = snippet[i];
if (typeof data[1] === "string") { // [id,string,args]
var id = data[0]; if (!MathJax.Object.isArray(id)) {id = [domain,id]}
var phrase = this.lookupPhrase(id,data[1]);
result = result.concat(this.processMarkdown(phrase,data.slice(2),domain));
} else if (MathJax.Object.isArray(data[1])) { // [domain,snippet]
result = result.concat(this.processSnippet.apply(this,data));
} else if (data.length >= 3) { // ["tag",{properties},snippet]
result.push([data[0],data[1],this.processSnippet(domain,data[2])]);
} else { // ["tag"] or ["tag",{properties}]
result.push(snippet[i]);
}
} else { // a string
result.push(snippet[i]);
}
}
return result;
},
markdownPattern: /(%.)|(\*{1,3})((?:%.|.)+?)\2|(`+)((?:%.|.)+?)\4|\[((?:%.|.)+?)\]\(([^\s\)]+)\)/,
// %c or *bold*, **italics**, ***bold-italics***, or `code`, or [link](url)
processMarkdown: function (phrase,args,domain) {
var result = [], data;
//
// Split the string by the Markdown pattern
// (the text blocks are separated by
// c,stars,star-text,backtics,code-text,link-text,URL).
// Start with teh first text string from the split.
//
var parts = phrase.split(this.markdownPattern);
var string = parts[0];
//
// Loop through the matches and process them
//
for (var i = 1, m = parts.length; i < m; i += 8) {
if (parts[i+1]) { // stars (for bold/italic)
//
// Select the tag to use by number of stars (three stars requires two tags)
//
data = this.processString(parts[i+2],args,domain);
if (!MathJax.Object.isArray(data)) {data = [data]}
data = [["b","i","i"][parts[i+1].length-1],{},data]; // number of stars determines type
if (parts[i+1].length === 3) {data = ["b",{},data]} // bold-italic
} else if (parts[i+3]) { // backtics (for code)
//
// Remove one leading or trailing space, and process substitutions
// Make a <code> tag
//
data = this.processString(parts[i+4].replace(/^\s/,"").replace(/\s$/,""),args,domain);
if (!MathJax.Object.isArray(data)) {data = [data]}
data = ["code",{},data];
} else if (parts[i+5]) { // hyperlink
//
// Process the link text, and make an <a> tag with the URL
//
data = this.processString(parts[i+5],args,domain);
if (!MathJax.Object.isArray(data)) {data = [data]}
data = ["a",{href:this.processString(parts[i+6],args),target:"_blank"},data];
} else {
//
// Escaped character (%c) gets added into the string.
//
string += parts[i]; data = null;
}
//
// If there is a tag to insert,
// Add any pending string, then push the tag
//
if (data) {
result = this.concatString(result,string,args,domain);
result.push(data); string = "";
}
//
// Process the string that follows matches pattern
//
if (parts[i+7] !== "") {string += parts[i+7]}
};
//
// Add any pending string and return the resulting snippet
//
result = this.concatString(result,string,args,domain);
return result;
},
concatString: function (result,string,args,domain) {
if (string != "") {
//
// Process the substutions.
// If the result is not a snippet, turn it into one.
// Then concatenate the snippet to the current one
//
string = this.processString(string,args,domain);
if (!MathJax.Object.isArray(string)) {string = [string]}
result = result.concat(string);
}
return result;
},
lookupPhrase: function (id,phrase,domain) {
//
// Get the domain and messageID
//
if (!domain) {domain = "_"}
if (MathJax.Object.isArray(id)) {domain = (id[0] || "_"); id = (id[1] || "")}
//
// Check if the data is available and if not,
// load it and throw a restart error so the calling
// code can wait for the load and try again.
//
var load = this.loadDomain(domain);
if (load) {MathJax.Hub.RestartAfter(load)}
//
// Look up the message in the localization data
// (if not found, the original English is used)
//
var localeData = this.strings[this.locale];
if (localeData) {
if (localeData.domains && domain in localeData.domains) {
var domainData = localeData.domains[domain];
if (domainData.strings && id in domainData.strings)
{phrase = domainData.strings[id]}
}
}
//
// return the translated phrase
//
return phrase;
},
//
// Load a langauge data file from the proper
// directory and file.
//
loadFile: function (file,data,callback) {
callback = MathJax.Callback(callback);
file = (data.file || file); // the data's file name or the default name
if (!file.match(/\.js$/)) {file += ".js"} // add .js if needed
//
// Add the directory if the file doesn't
// contain a full URL already.
//
if (!file.match(/^([a-z]+:|\[MathJax\])/)) {
var dir = (this.strings[this.locale].directory ||
this.directory + "/" + this.locale ||
"[MathJax]/localization/" + this.locale);
file = dir + "/" + file;
}
//
// Load the file and mark the data as loaded (even if it
// failed to load, so we don't continue to try to load it
// over and over).
//
var load = MathJax.Ajax.Require(file,function () {data.isLoaded = true; return callback()});
//
// Return the callback if needed, otherwise null.
//
return (load.called ? null : load);
},
//
// Check to see if the localization data are loaded
// for the given domain; if not, load the data file,
// and return a callback for the loading operation.
// Otherwise return null (data are loaded).
//
loadDomain: function (domain,callback) {
var load, localeData = this.strings[this.locale];
if (localeData) {
if (!localeData.isLoaded) {
load = this.loadFile(this.locale,localeData);
if (load) {
return MathJax.Callback.Queue(
load,["loadDomain",this,domain] // call again to load domain
).Push(callback||{});
}
}
if (localeData.domains && domain in localeData.domains) {
var domainData = localeData.domains[domain];
if (!domainData.isLoaded) {
load = this.loadFile(domain,domainData);
if (load) {return MathJax.Callback.Queue(load).Push(callback)}
}
}
}
// localization data are loaded, so just do the callback
return MathJax.Callback(callback)();
},
//
// Perform a function, properly handling
// restarts due to localization file loads.
//
// Note that this may return before the function
// has been called successfully, so you should
// consider fn as running asynchronously. (Callbacks
// can be used to synchronize it with other actions.)
//
Try: function (fn) {
fn = MathJax.Callback(fn); fn.autoReset = true;
try {fn()} catch (err) {
if (!err.restart) {throw err}
MathJax.Callback.After(["Try",this,fn],err.restart);
}
},
//
// Reset the current language
//
resetLocale: function(locale) {
// Selection algorithm:
// 1) Downcase locale name (e.g. "en-US" => "en-us")
// 2) Try a parent language (e.g. "en-us" => "en")
// 3) Try the fallback specified in the data (e.g. "pt" => "pt-br")
// 4) Otherwise don't change the locale.
if (!locale) return;
locale = locale.toLowerCase();
while (!this.strings[locale]) {
var dashPos = locale.lastIndexOf("-");
if (dashPos === -1) return;
locale = locale.substring(0, dashPos);
}
var remap = this.strings[locale].remap;
this.locale = remap ? remap : locale;
},
//
// Set the current language
//
setLocale: function(locale) {
this.resetLocale(locale);
if (MathJax.Menu) {this.loadDomain("MathMenu")}
},
//
// Add or update a language or domain
//
addTranslation: function (locale,domain,definition) {
var data = this.strings[locale], isNew = false;
if (!data) {data = this.strings[locale] = {}; isNew = true}
if (!data.domains) {data.domains = {}}
if (domain) {
if (!data.domains[domain]) {data.domains[domain] = {}}
data = data.domains[domain];
}
MathJax.Hub.Insert(data,definition);
if (isNew && MathJax.Menu.menu) {MathJax.Menu.CreateLocaleMenu()}
},
//
// Set CSS for an element based on font requirements
//
setCSS: function (div) {
var locale = this.strings[this.locale];
if (locale) {
if (locale.fontFamily) {div.style.fontFamily = locale.fontFamily}
if (locale.fontDirection) {
div.style.direction = locale.fontDirection;
if (locale.fontDirection === "rtl") {div.style.textAlign = "right"}
}
}
return div;
},
//
// Get the language's font family or direction
//
fontFamily: function () {
var locale = this.strings[this.locale];
return (locale ? locale.fontFamily : null);
},
fontDirection: function () {
var locale = this.strings[this.locale];
return (locale ? locale.fontDirection : null);
},
//
// Get the language's plural index for a number
//
plural: function (n) {
var locale = this.strings[this.locale];
if (locale && locale.plural) {return locale.plural(n)}
// default
if (n == 1) {return 1} // one
return 2; // other
},
//
// Convert a number to language-specific form
//
number: function(n) {
var locale = this.strings[this.locale];
if (locale && locale.number) {return locale.number(n)}
// default
return n;
}
};
/**********************************************************/
MathJax.Message = {
ready: false, // used to tell when the styles are available
log: [{}], current: null,
textNodeBug: (navigator.vendor === "Apple Computer, Inc." &&
typeof navigator.vendorSub === "undefined") ||
(window.hasOwnProperty && window.hasOwnProperty("konqueror")), // Konqueror displays some gibberish with text.nodeValue = "..."
styles: {
"#MathJax_Message": {
position: "fixed", left: "1px", bottom: "2px",
'background-color': "#E6E6E6", border: "1px solid #959595",
margin: "0px", padding: "2px 8px",
'z-index': "102", color: "black", 'font-size': "80%",
width: "auto", 'white-space': "nowrap"
},
"#MathJax_MSIE_Frame": {
position: "absolute",
top:0, left: 0, width: "0px", 'z-index': 101,
border: "0px", margin: "0px", padding: "0px"
}
},
browsers: {
MSIE: function (browser) {
MathJax.Message.msieFixedPositionBug = ((document.documentMode||0) < 7);
if (MathJax.Message.msieFixedPositionBug)
{MathJax.Hub.config.styles["#MathJax_Message"].position = "absolute"}
MathJax.Message.quirks = (document.compatMode === "BackCompat");
},
Chrome: function (browser) {
MathJax.Hub.config.styles["#MathJax_Message"].bottom = "1.5em";
MathJax.Hub.config.styles["#MathJax_Message"].left = "1em";
}
},
Init: function (styles) {
if (styles) {this.ready = true}
if (!document.body || !this.ready) {return false}
//
// ASCIIMathML replaces the entire page with a copy of itself (@#!#%@!!)
// so check that this.div is still part of the page, otherwise look up
// the copy and use that.
//
if (this.div && this.div.parentNode == null) {
this.div = document.getElementById("MathJax_Message");
if (this.div) {this.text = this.div.firstChild}
}
if (!this.div) {
var frame = document.body;
if (this.msieFixedPositionBug && window.attachEvent) {
frame = this.frame = this.addDiv(document.body); frame.removeAttribute("id");
frame.style.position = "absolute";
frame.style.border = frame.style.margin = frame.style.padding = "0px";
frame.style.zIndex = "101"; frame.style.height = "0px";
frame = this.addDiv(frame);
frame.id = "MathJax_MSIE_Frame";
window.attachEvent("onscroll",this.MoveFrame);
window.attachEvent("onresize",this.MoveFrame);
this.MoveFrame();
}
this.div = this.addDiv(frame); this.div.style.display = "none";
this.text = this.div.appendChild(document.createTextNode(""));
}
return true;
},
addDiv: function (parent) {
var div = document.createElement("div");
div.id = "MathJax_Message";
if (parent.firstChild) {parent.insertBefore(div,parent.firstChild)}
else {parent.appendChild(div)}
return div;
},
MoveFrame: function () {
var body = (MathJax.Message.quirks ? document.body : document.documentElement);
var frame = MathJax.Message.frame;
frame.style.left = body.scrollLeft + 'px';
frame.style.top = body.scrollTop + 'px';
frame.style.width = body.clientWidth + 'px';
frame = frame.firstChild;
frame.style.height = body.clientHeight + 'px';
},
localize: function (message) {
return MathJax.Localization._(message,message);
},
filterText: function (text,n,id) {
if (MathJax.Hub.config.messageStyle === "simple") {
if (id === "LoadFile") {
if (!this.loading) {this.loading = this.localize("Loading") + " "}
text = this.loading; this.loading += ".";
} else if (id === "ProcessMath") {
if (!this.processing) {this.processing = this.localize("Processing") + " "}
text = this.processing; this.processing += ".";
} else if (id === "TypesetMath") {
if (!this.typesetting) {this.typesetting = this.localize("Typesetting") + " "}
text = this.typesetting; this.typesetting += ".";
}
}
return text;
},
clearCounts: function () {
delete this.loading;
delete this.processing;
delete this.typesetting;
},
Set: function (text,n,clearDelay) {
if (n == null) {n = this.log.length; this.log[n] = {}}
//
// Translate message if it is [id,message,arguments]
//
var id = "";
if (MathJax.Object.isArray(text)) {
id = text[0]; if (MathJax.Object.isArray(id)) {id = id[1]}
//
// Localization._() will throw a restart error if a localization file
// needs to be loaded, so trap that and redo the Set() call
// after it is loaded.
//
try {
text = MathJax.Localization._.apply(MathJax.Localization,text);
} catch (err) {
if (!err.restart) {throw err}
if (!err.restart.called) {
//
// Mark it so we can tell if the Clear() comes before the message is displayed
//
if (this.log[n].restarted == null) {this.log[n].restarted = 0}
this.log[n].restarted++; delete this.log[n].cleared;
MathJax.Callback.After(["Set",this,text,n,clearDelay],err.restart);
return n;
}
}
}
//
// Clear the timout timer.
//
if (this.timer) {clearTimeout(this.timer); delete this.timer}
//
// Save the message and filtered message.
//
this.log[n].text = text; this.log[n].filteredText = text = this.filterText(text,n,id);
//
// Hook the message into the message list so we can tell
// what message to put up when this one is removed.
//
if (typeof(this.log[n].next) === "undefined") {
this.log[n].next = this.current;
if (this.current != null) {this.log[this.current].prev = n}
this.current = n;
}
//
// Show the message if it is the currently active one.
//
if (this.current === n && MathJax.Hub.config.messageStyle !== "none") {
if (this.Init()) {
if (this.textNodeBug) {this.div.innerHTML = text} else {this.text.nodeValue = text}
this.div.style.display = "";
if (this.status) {window.status = ""; delete this.status}
} else {
window.status = text;
this.status = true;
}
}
//
// Check if the message was resetarted to load a localization file
// and if it has been cleared in the meanwhile.
//
if (this.log[n].restarted) {
if (this.log[n].cleared) {clearDelay = 0}
if (--this.log[n].restarted === 0) {delete this.log[n].cleared}
}
//
// Check if we need to clear the message automatically.
//
if (clearDelay) {setTimeout(MathJax.Callback(["Clear",this,n]),clearDelay)}
else if (clearDelay == 0) {this.Clear(n,0)}
//
// Return the message number.
//
return n;
},
Clear: function (n,delay) {
//
// Detatch the message from the active list.
//
if (this.log[n].prev != null) {this.log[this.log[n].prev].next = this.log[n].next}
if (this.log[n].next != null) {this.log[this.log[n].next].prev = this.log[n].prev}
//
// If it is the current message, get the next one to show.
//
if (this.current === n) {
this.current = this.log[n].next;
if (this.text) {
if (this.div.parentNode == null) {this.Init()} // see ASCIIMathML comments above
if (this.current == null) {
//
// If there are no more messages, remove the message box.
//
if (this.timer) {clearTimeout(this.timer); delete this.timer}
if (delay == null) {delay = 600}
if (delay === 0) {this.Remove()}
else {this.timer = setTimeout(MathJax.Callback(["Remove",this]),delay)}
} else if (MathJax.Hub.config.messageStyle !== "none") {
//
// If there is an old message, put it in place
//
if (this.textNodeBug) {this.div.innerHTML = this.log[this.current].filteredText}
else {this.text.nodeValue = this.log[this.current].filteredText}
}
if (this.status) {window.status = ""; delete this.status}
} else if (this.status) {
window.status = (this.current == null ? "" : this.log[this.current].text);
}
}
//
// Clean up the log data no longer needed
//
delete this.log[n].next; delete this.log[n].prev;
delete this.log[n].filteredText;
//
// If this is a restarted localization message, mark that it has been cleared
// while waiting for the file to load.
//
if (this.log[n].restarted) {this.log[n].cleared = true}
},
Remove: function () {
// FIXME: do a fade out or something else interesting?
this.text.nodeValue = "";
this.div.style.display = "none";
},
File: function (file) {
return this.Set(["LoadFile","Loading %1",file],null,null);
},
Log: function () {
var strings = [];
for (var i = 1, m = this.log.length; i < m; i++) {strings[i] = this.log[i].text}
return strings.join("\n");
}
};
/**********************************************************/
MathJax.Hub = {
config: {
root: "",
config: [], // list of configuration files to load
styleSheets: [], // list of CSS files to load
styles: { // styles to generate in-line
".MathJax_Preview": {color: "#888"}
},
jax: [], // list of input and output jax to load
extensions: [], // list of extensions to load
preJax: null, // pattern to remove from before math script tag
postJax: null, // pattern to remove from after math script tag
displayAlign: 'center', // how to align displayed equations (left, center, right)
displayIndent: '0', // indentation for displayed equations (when not centered)
preRemoveClass: 'MathJax_Preview', // class of objects to remove preceeding math script
showProcessingMessages: true, // display "Processing math: nn%" messages or not
messageStyle: "normal", // set to "none" or "simple" (for "Loading..." and "Processing...")
delayStartupUntil: "none", // set to "onload" to delay setup until the onload handler runs
// set to "configured" to delay startup until MathJax.Hub.Configured() is called
// set to a Callback to wait for before continuing with the startup
skipStartupTypeset: false, // set to true to skip PreProcess and Process during startup
elements: [], // array of elements to process when none is given explicitly
positionToHash: true, // after initial typeset pass, position to #hash location?
showMathMenu: true, // attach math context menu to typeset math?
showMathMenuMSIE: true, // separtely determine if MSIE should have math menu
// (since the code for that is a bit delicate)
menuSettings: {
zoom: "None", // when to do MathZoom
CTRL: false, // require CTRL for MathZoom?
ALT: false, // require Alt or Option?
CMD: false, // require CMD?
Shift: false, // require Shift?
discoverable: false, // make math menu discoverable on hover?
zscale: "200%", // the scaling factor for MathZoom
renderer: null, // set when Jax are loaded
font: "Auto", // what font HTML-CSS should use
context: "MathJax", // or "Browser" for pass-through to browser menu
locale: null, // the language to use for messages
mpContext: false, // true means pass menu events to MathPlayer in IE
mpMouse: false, // true means pass mouse events to MathPlayer in IE
texHints: true, // include class names for TeXAtom elements
FastPreview: null, // use PreviewHTML output as preview?
assistiveMML: null, // include hidden MathML for screen readers?
inTabOrder: true, // set to false if math elements should be included in the tabindex
semantics: false // add semantics tag with original form in MathML output
},
errorSettings: {
// localized HTML snippet structure for message to use
message: ["[",["MathProcessingError","Math Processing Error"],"]"],
style: {color: "#CC0000", "font-style":"italic"} // style for message
},
ignoreMMLattributes: {} // attributes not to copy to HTML-CSS or SVG output
// from MathML input (in addition to the ones in MML.nocopyAttributes).
// An id set to true will be ignored, one set to false will
// be allowed (even if other criteria normally would prevent
// it from being copied); use false carefully!
},
preProcessors: MathJax.Callback.Hooks(true), // list of callbacks for preprocessing (initialized by extensions)
inputJax: {}, // mime-type mapped to input jax (by registration)
outputJax: {order:{}}, // mime-type mapped to output jax list (by registration)
processSectionDelay: 50, // pause between input and output phases of processing
processUpdateTime: 250, // time between screen updates when processing math (milliseconds)
processUpdateDelay: 10, // pause between screen updates to allow other processing (milliseconds)
signal: MathJax.Callback.Signal("Hub"), // Signal used for Hub events
Config: function (def) {
this.Insert(this.config,def);
if (this.config.Augment) {this.Augment(this.config.Augment)}
},
CombineConfig: function (name,def) {
var config = this.config, id, parent; name = name.split(/\./);
for (var i = 0, m = name.length; i < m; i++) {
id = name[i]; if (!config[id]) {config[id] = {}}
parent = config; config = config[id];
}
parent[id] = config = this.Insert(def,config);
return config;
},
Register: {
PreProcessor: function () {return MathJax.Hub.preProcessors.Add.apply(MathJax.Hub.preProcessors,arguments)},
MessageHook: function () {return MathJax.Hub.signal.MessageHook.apply(MathJax.Hub.signal,arguments)},
StartupHook: function () {return MathJax.Hub.Startup.signal.MessageHook.apply(MathJax.Hub.Startup.signal,arguments)},
LoadHook: function () {return MathJax.Ajax.LoadHook.apply(MathJax.Ajax,arguments)}
},
UnRegister: {
PreProcessor: function (hook) {MathJax.Hub.preProcessors.Remove(hook)},
MessageHook: function (hook) {MathJax.Hub.signal.RemoveHook(hook)},
StartupHook: function (hook) {MathJax.Hub.Startup.signal.RemoveHook(hook)},
LoadHook: function (hook) {MathJax.Ajax.removeHook(hook)}
},
getAllJax: function (element) {
var jax = [], scripts = this.elementScripts(element);
for (var i = 0, m = scripts.length; i < m; i++) {
if (scripts[i].MathJax && scripts[i].MathJax.elementJax)
{jax.push(scripts[i].MathJax.elementJax)}
}
return jax;
},
getJaxByType: function (type,element) {
var jax = [], scripts = this.elementScripts(element);
for (var i = 0, m = scripts.length; i < m; i++) {
if (scripts[i].MathJax && scripts[i].MathJax.elementJax &&
scripts[i].MathJax.elementJax.mimeType === type)
{jax.push(scripts[i].MathJax.elementJax)}
}
return jax;
},
getJaxByInputType: function (type,element) {
var jax = [], scripts = this.elementScripts(element);
for (var i = 0, m = scripts.length; i < m; i++) {
if (scripts[i].MathJax && scripts[i].MathJax.elementJax &&
scripts[i].type && scripts[i].type.replace(/ *;(.|\s)*/,"") === type)
{jax.push(scripts[i].MathJax.elementJax)}
}
return jax;
},
getJaxFor: function (element) {
if (typeof(element) === 'string') {element = document.getElementById(element)}
if (element && element.MathJax) {return element.MathJax.elementJax}
if (this.isMathJaxNode(element)) {
if (!element.isMathJax) {element = element.firstChild} // for NativeMML output
while (element && !element.jaxID) {element = element.parentNode}
if (element) {return MathJax.OutputJax[element.jaxID].getJaxFromMath(element)}
}
return null;
},
isJax: function (element) {
if (typeof(element) === 'string') {element = document.getElementById(element)}
if (this.isMathJaxNode(element)) {return 1}
if (element && (element.tagName||"").toLowerCase() === 'script') {
if (element.MathJax)
{return (element.MathJax.state === MathJax.ElementJax.STATE.PROCESSED ? 1 : -1)}
if (element.type && this.inputJax[element.type.replace(/ *;(.|\s)*/,"")]) {return -1}
}
return 0;
},
isMathJaxNode: function (element) {
return !!element && (element.isMathJax || (element.className||"") === "MathJax_MathML");
},
setRenderer: function (renderer,type) {
if (!renderer) return;
if (!MathJax.OutputJax[renderer]) {
this.config.menuSettings.renderer = "";
var file = "[MathJax]/jax/output/"+renderer+"/config.js";
return MathJax.Ajax.Require(file,["setRenderer",this,renderer,type]);
} else {
this.config.menuSettings.renderer = renderer;
if (type == null) {type = "jax/mml"}
var jax = this.outputJax;
if (jax[type] && jax[type].length) {
if (renderer !== jax[type][0].id) {
jax[type].unshift(MathJax.OutputJax[renderer]);
return this.signal.Post(["Renderer Selected",renderer]);
}
}
return null;
}
},
Queue: function () {
return this.queue.Push.apply(this.queue,arguments);
},
Typeset: function (element,callback) {
if (!MathJax.isReady) return null;
var ec = this.elementCallback(element,callback);
if (ec.count) {
var queue = MathJax.Callback.Queue(
["PreProcess",this,ec.elements],
["Process",this,ec.elements]
);
}
return queue.Push(ec.callback);
},
PreProcess: function (element,callback) {
var ec = this.elementCallback(element,callback);
var queue = MathJax.Callback.Queue();
if (ec.count) {
var elements = (ec.count === 1 ? [ec.elements] : ec.elements);
queue.Push(["Post",this.signal,["Begin PreProcess",ec.elements]]);
for (var i = 0, m = elements.length; i < m; i++) {
if (elements[i]) {queue.Push(["Execute",this.preProcessors,elements[i]])}
}
queue.Push(["Post",this.signal,["End PreProcess",ec.elements]]);
}
return queue.Push(ec.callback);
},
Process: function (element,callback) {return this.takeAction("Process",element,callback)},
Update: function (element,callback) {return this.takeAction("Update",element,callback)},
Reprocess: function (element,callback) {return this.takeAction("Reprocess",element,callback)},
Rerender: function (element,callback) {return this.takeAction("Rerender",element,callback)},
takeAction: function (action,element,callback) {
var ec = this.elementCallback(element,callback);
var elements = ec.elements;
var queue = MathJax.Callback.Queue(["Clear",this.signal]);
var state = {
scripts: [], // filled in by prepareScripts
start: new Date().getTime(), // timer for processing messages
i: 0, j: 0, // current script, current jax
jax: {}, // scripts grouped by output jax
jaxIDs: [] // id's of jax used
};
if (ec.count) {
var delay = ["Delay",MathJax.Callback,this.processSectionDelay];
if (!delay[2]) {delay = {}}
queue.Push(
["clearCounts",MathJax.Message],
["Post",this.signal,["Begin "+action,elements]],
["Post",this.signal,["Begin Math",elements,action]],
["prepareScripts",this,action,elements,state],
["Post",this.signal,["Begin Math Input",elements,action]],
["processInput",this,state],
["Post",this.signal,["End Math Input",elements,action]],
delay,
["prepareOutput",this,state,"preProcess"],
delay,
["Post",this.signal,["Begin Math Output",elements,action]],
["processOutput",this,state],
["Post",this.signal,["End Math Output",elements,action]],
delay,
["prepareOutput",this,state,"postProcess"],
delay,
["Post",this.signal,["End Math",elements,action]],
["Post",this.signal,["End "+action,elements]],
["clearCounts",MathJax.Message]
);
}
return queue.Push(ec.callback);
},
scriptAction: {
Process: function (script) {},
Update: function (script) {
var jax = script.MathJax.elementJax;
if (jax && jax.needsUpdate()) {jax.Remove(true); script.MathJax.state = jax.STATE.UPDATE}
else {script.MathJax.state = jax.STATE.PROCESSED}
},
Reprocess: function (script) {
var jax = script.MathJax.elementJax;
if (jax) {jax.Remove(true); script.MathJax.state = jax.STATE.UPDATE}
},
Rerender: function (script) {
var jax = script.MathJax.elementJax;
if (jax) {jax.Remove(true); script.MathJax.state = jax.STATE.OUTPUT}
}
},
prepareScripts: function (action,element,state) {
if (arguments.callee.disabled) return;
var scripts = this.elementScripts(element);
var STATE = MathJax.ElementJax.STATE;
for (var i = 0, m = scripts.length; i < m; i++) {
var script = scripts[i];
if (script.type && this.inputJax[script.type.replace(/ *;(.|\n)*/,"")]) {
if (script.MathJax) {
if (script.MathJax.elementJax && script.MathJax.elementJax.hover) {
MathJax.Extension.MathEvents.Hover.ClearHover(script.MathJax.elementJax);
}
if (script.MathJax.state !== STATE.PENDING) {this.scriptAction[action](script)}
}
if (!script.MathJax) {script.MathJax = {state: STATE.PENDING}}
if (script.MathJax.error) delete script.MathJax.error;
if (script.MathJax.state !== STATE.PROCESSED) {state.scripts.push(script)}
}
}
},
checkScriptSiblings: function (script) {
if (script.MathJax.checked) return;
var config = this.config, pre = script.previousSibling;
if (pre && pre.nodeName === "#text") {
var preJax,postJax, post = script.nextSibling;
if (post && post.nodeName !== "#text") {post = null}
if (config.preJax) {
if (typeof(config.preJax) === "string") {config.preJax = new RegExp(config.preJax+"$")}
preJax = pre.nodeValue.match(config.preJax);
}
if (config.postJax && post) {
if (typeof(config.postJax) === "string") {config.postJax = new RegExp("^"+config.postJax)}
postJax = post.nodeValue.match(config.postJax);
}
if (preJax && (!config.postJax || postJax)) {
pre.nodeValue = pre.nodeValue.replace
(config.preJax,(preJax.length > 1? preJax[1] : ""));
pre = null;
}
if (postJax && (!config.preJax || preJax)) {
post.nodeValue = post.nodeValue.replace
(config.postJax,(postJax.length > 1? postJax[1] : ""));
}
if (pre && !pre.nodeValue.match(/\S/)) {pre = pre.previousSibling}
}
if (config.preRemoveClass && pre && pre.className === config.preRemoveClass)
{script.MathJax.preview = pre}
script.MathJax.checked = 1;
},
processInput: function (state) {
var jax, STATE = MathJax.ElementJax.STATE;
var script, prev, m = state.scripts.length;
try {
//
// Loop through the scripts
//
while (state.i < m) {
script = state.scripts[state.i]; if (!script) {state.i++; continue}
//
// Remove previous error marker, if any
//
prev = script.previousSibling;
if (prev && prev.className === "MathJax_Error") {prev.parentNode.removeChild(prev)}
//
// Check if already processed or needs processing
//
if (!script.parentNode || !script.MathJax || script.MathJax.state === STATE.PROCESSED) {state.i++; continue};
if (!script.MathJax.elementJax || script.MathJax.state === STATE.UPDATE) {
this.checkScriptSiblings(script); // remove preJax/postJax etc.
var type = script.type.replace(/ *;(.|\s)*/,""); // the input jax type
var input = this.inputJax[type]; // the input jax itself
jax = input.Process(script,state); // run the input jax
if (typeof jax === 'function') { // if a callback was returned
if (jax.called) continue; // go back and call Process() again
this.RestartAfter(jax); // wait for the callback
}
jax = jax.Attach(script,input.id); // register the jax on the script
this.saveScript(jax,state,script,STATE); // add script to state
this.postInputHooks.Execute(jax,input.id,script); // run global jax filters
} else if (script.MathJax.state === STATE.OUTPUT) {
this.saveScript(script.MathJax.elementJax,state,script,STATE); // add script to state
}
//
// Go on to the next script, and check if we need to update the processing message
//
state.i++; var now = new Date().getTime();
if (now - state.start > this.processUpdateTime && state.i < state.scripts.length)
{state.start = now; this.RestartAfter(MathJax.Callback.Delay(1))}
}
} catch (err) {return this.processError(err,state,"Input")}
//
// Put up final message, reset the state and return
//
if (state.scripts.length && this.config.showProcessingMessages)
{MathJax.Message.Set(["ProcessMath","Processing math: %1%%",100],0)}
state.start = new Date().getTime(); state.i = state.j = 0;
return null;
},
postInputHooks: MathJax.Callback.Hooks(true), // hooks to run after element jax is created
saveScript: function (jax,state,script,STATE) {
//
// Check that output jax exists
//
if (!this.outputJax[jax.mimeType]) {
script.MathJax.state = STATE.UPDATE;
throw Error("No output jax registered for "+jax.mimeType);
}
//
// Record the output jax
// and put this script in the queue for that jax
//
jax.outputJax = this.outputJax[jax.mimeType][0].id;
if (!state.jax[jax.outputJax]) {
if (state.jaxIDs.length === 0) {
// use original array until we know there are more (rather than two copies)
state.jax[jax.outputJax] = state.scripts;
} else {
if (state.jaxIDs.length === 1) // get the script so far for the existing jax
{state.jax[state.jaxIDs[0]] = state.scripts.slice(0,state.i)}
state.jax[jax.outputJax] = []; // start a new array for the new jax
}
state.jaxIDs.push(jax.outputJax); // save the ID of the jax
}
if (state.jaxIDs.length > 1) {state.jax[jax.outputJax].push(script)}
//
// Mark script as needing output
//
script.MathJax.state = STATE.OUTPUT;
},
//
// Pre- and post-process scripts by jax
// (to get scaling factors, hide/show output, and so on)
// Since this can cause the jax to load, we need to trap restarts
//
prepareOutput: function (state,method) {
while (state.j < state.jaxIDs.length) {
var id = state.jaxIDs[state.j], JAX = MathJax.OutputJax[id];
if (JAX[method]) {
try {
var result = JAX[method](state);
if (typeof result === 'function') {
if (result.called) continue; // go back and try again
this.RestartAfter(result);
}
} catch (err) {
if (!err.restart) {
MathJax.Message.Set(["PrepError","Error preparing %1 output (%2)",id,method],null,600);
MathJax.Hub.lastPrepError = err;
state.j++;
}
return MathJax.Callback.After(["prepareOutput",this,state,method],err.restart);
}
}
state.j++;
}
return null;
},
processOutput: function (state) {
var result, STATE = MathJax.ElementJax.STATE, script, m = state.scripts.length;
try {
//
// Loop through the scripts
//
while (state.i < m) {
//
// Check that there is an element jax
//
script = state.scripts[state.i];
if (!script || !script.parentNode || !script.MathJax || script.MathJax.error) {state.i++; continue}
var jax = script.MathJax.elementJax; if (!jax) {state.i++; continue}
//
// Call the output Jax's Process method (which will be its Translate()
// method once loaded). Mark it as complete and remove the preview unless
// the Process() call returns an explicit false value (in which case, it will
// handle this later during the postProcess phase, as HTML-CSS does).
//
result = MathJax.OutputJax[jax.outputJax].Process(script,state);
if (result !== false) {
script.MathJax.state = STATE.PROCESSED;
if (script.MathJax.preview) {
script.MathJax.preview.innerHTML = "";
script.MathJax.preview.style.display = "none";
}
//
// Signal that new math is available
//
this.signal.Post(["New Math",jax.inputID]); // FIXME: wait for this? (i.e., restart if returns uncalled callback)
}
//
// Go on to next math expression
//
state.i++;
//
// Update the processing message, if needed
//
var now = new Date().getTime();
if (now - state.start > this.processUpdateTime && state.i < state.scripts.length)
{state.start = now; this.RestartAfter(MathJax.Callback.Delay(this.processUpdateDelay))}
}
} catch (err) {return this.processError(err,state,"Output")}
//
// Put up the typesetting-complete message
//
if (state.scripts.length && this.config.showProcessingMessages) {
MathJax.Message.Set(["TypesetMath","Typesetting math: %1%%",100],0);
MathJax.Message.Clear(0);
}
state.i = state.j = 0;
return null;
},
processMessage: function (state,type) {
var m = Math.floor(state.i/(state.scripts.length)*100);
var message = (type === "Output" ? ["TypesetMath","Typesetting math: %1%%"] :
["ProcessMath","Processing math: %1%%"]);
if (this.config.showProcessingMessages) {MathJax.Message.Set(message.concat(m),0)}
},
processError: function (err,state,type) {
if (!err.restart) {
if (!this.config.errorSettings.message) {throw err}
this.formatError(state.scripts[state.i],err); state.i++;
}
this.processMessage(state,type);
return MathJax.Callback.After(["process"+type,this,state],err.restart);
},
formatError: function (script,err) {
var LOCALIZE = function (id,text,arg1,arg2) {return MathJax.Localization._(id,text,arg1,arg2)};
//
// Get the error message, URL, and line, and save it for
// reporting in the Show Math As Error menu
//
var message = LOCALIZE("ErrorMessage","Error: %1",err.message)+"\n";
if (err.sourceURL||err.fileName) message += "\n"+LOCALIZE("ErrorFile","file: %1",err.sourceURL||err.fileName);
if (err.line||err.lineNumber) message += "\n"+LOCALIZE("ErrorLine","line: %1",err.line||err.lineNumber);
message += "\n\n"+LOCALIZE("ErrorTips","Debugging tips: use %1, inspect %2 in the browser console","'unpacked/MathJax.js'","'MathJax.Hub.lastError'");
script.MathJax.error = MathJax.OutputJax.Error.Jax(message,script);
if (script.MathJax.elementJax)
script.MathJax.error.inputID = script.MathJax.elementJax.inputID;
//
// Create the [Math Processing Error] span
//
var errorSettings = this.config.errorSettings;
var errorText = LOCALIZE(errorSettings.messageId,errorSettings.message);
var error = MathJax.HTML.Element("span", {
className:"MathJax_Error", jaxID:"Error", isMathJax:true,
id: script.MathJax.error.inputID+"-Frame"
},[["span",null,errorText]]);
//
// Attach the menu events
//
MathJax.Ajax.Require("[MathJax]/extensions/MathEvents.js",function () {
var EVENT = MathJax.Extension.MathEvents.Event,
HUB = MathJax.Hub;
error.oncontextmenu = EVENT.Menu;
error.onmousedown = EVENT.Mousedown;
error.onkeydown = EVENT.Keydown;
error.tabIndex = HUB.getTabOrder(HUB.getJaxFor(script));
});
//
// Insert the error into the page and remove any preview
//
var node = document.getElementById(error.id);
if (node) node.parentNode.removeChild(node);
if (script.parentNode) script.parentNode.insertBefore(error,script);
if (script.MathJax.preview) {
script.MathJax.preview.innerHTML = "";
script.MathJax.preview.style.display = "none";
}
//
// Save the error for debugging purposes
// Report the error as a signal
//
this.lastError = err;
this.signal.Post(["Math Processing Error",script,err]);
},
RestartAfter: function (callback) {
throw this.Insert(Error("restart"),{restart: MathJax.Callback(callback)});
},
elementCallback: function (element,callback) {
if (callback == null && (MathJax.Object.isArray(element) || typeof element === 'function'))
{try {MathJax.Callback(element); callback = element; element = null} catch(e) {}}
if (element == null) {element = this.config.elements || []}
if (this.isHTMLCollection(element)) {element = this.HTMLCollection2Array(element)}
if (!MathJax.Object.isArray(element)) {element = [element]}
element = [].concat(element); // make a copy so the original isn't changed
for (var i = 0, m = element.length; i < m; i++)
{if (typeof(element[i]) === 'string') {element[i] = document.getElementById(element[i])}}
if (!document.body) {document.body = document.getElementsByTagName("body")[0]}
if (element.length == 0) {element.push(document.body)}
if (!callback) {callback = {}}
return {
count: element.length,
elements: (element.length === 1 ? element[0] : element),
callback: callback
};
},
elementScripts: function (element) {
var scripts = [];
if (MathJax.Object.isArray(element) || this.isHTMLCollection(element)) {
for (var i = 0, m = element.length; i < m; i++) {
var alreadyDone = 0;
for (var j = 0; j < i && !alreadyDone; j++)
{alreadyDone = element[j].contains(element[i])}
if (!alreadyDone) scripts.push.apply(scripts,this.elementScripts(element[i]));
}
return scripts;
}
if (typeof(element) === 'string') {element = document.getElementById(element)}
if (!document.body) {document.body = document.getElementsByTagName("body")[0]}
if (element == null) {element = document.body}
if (element.tagName != null && element.tagName.toLowerCase() === "script") {return [element]}
scripts = element.getElementsByTagName("script");
if (this.msieHTMLCollectionBug) {scripts = this.HTMLCollection2Array(scripts)}
return scripts;
},
//
// IE8 fails to check "obj instanceof HTMLCollection" for some values of obj.
//
isHTMLCollection: function (obj) {
return ("HTMLCollection" in window && typeof(obj) === "object" && obj instanceof HTMLCollection);
},
//
// IE8 doesn't deal with HTMLCollection as an array, so convert to array
//
HTMLCollection2Array: function (nodes) {
if (!this.msieHTMLCollectionBug) {return [].slice.call(nodes)}
var NODES = [];
for (var i = 0, m = nodes.length; i < m; i++) {NODES[i] = nodes[i]}
return NODES;
},
Insert: function (dst,src) {
for (var id in src) {if (src.hasOwnProperty(id)) {
// allow for concatenation of arrays?
if (typeof src[id] === 'object' && !(MathJax.Object.isArray(src[id])) &&
(typeof dst[id] === 'object' || typeof dst[id] === 'function')) {
this.Insert(dst[id],src[id]);
} else {
dst[id] = src[id];
}
}}
return dst;
},
getTabOrder: function(script) {
return this.config.menuSettings.inTabOrder ? 0 : -1;
},
// Old browsers (e.g. Internet Explorer <= 8) do not support trim().
SplitList: ("trim" in String.prototype ?
function (list) {return list.trim().split(/\s+/)} :
function (list) {return list.replace(/^\s+/,'').
replace(/\s+$/,'').split(/\s+/)})
};
MathJax.Hub.Insert(MathJax.Hub.config.styles,MathJax.Message.styles);
MathJax.Hub.Insert(MathJax.Hub.config.styles,{".MathJax_Error":MathJax.Hub.config.errorSettings.style});
//
// Storage area for extensions and preprocessors
//
MathJax.Extension = {};
//
// Hub Startup code
//
MathJax.Hub.Configured = MathJax.Callback({}); // called when configuration is complete
MathJax.Hub.Startup = {
script: "", // the startup script from the SCRIPT call that loads MathJax.js
queue: MathJax.Callback.Queue(), // Queue used for startup actions
signal: MathJax.Callback.Signal("Startup"), // Signal used for startup events
params: {},
//
// Load the configuration files
//
Config: function () {
this.queue.Push(["Post",this.signal,"Begin Config"]);
//
// Make sure root is set before loading any files
//
if (MathJax.AuthorConfig && MathJax.AuthorConfig.root)
MathJax.Ajax.config.root = MathJax.AuthorConfig.root;
//
// If a locale is given as a parameter,
// set the locale and the default menu value for the locale
//
if (this.params.locale) {
MathJax.Localization.resetLocale(this.params.locale);
MathJax.Hub.config.menuSettings.locale = this.params.locale;
}
//
// Run the config files, if any are given in the parameter list
//
if (this.params.config) {
var files = this.params.config.split(/,/);
for (var i = 0, m = files.length; i < m; i++) {
if (!files[i].match(/\.js$/)) {files[i] += ".js"}
this.queue.Push(["Require",MathJax.Ajax,this.URL("config",files[i])]);
}
}
//
// Perform author configuration from in-line MathJax = {...}
//
this.queue.Push(["Config",MathJax.Hub,MathJax.AuthorConfig]);
//
// Run the deprecated configuration script, if any (ignoring return value)
// Wait for the startup delay signal
// Run the mathjax-config blocks
// Load the files in the configuration's config array
//
if (this.script.match(/\S/)) {this.queue.Push(this.script+";\n1;")}
this.queue.Push(
["ConfigDelay",this],
["ConfigBlocks",this],
[function (THIS) {return THIS.loadArray(MathJax.Hub.config.config,"config",null,true)},this],
["Post",this.signal,"End Config"]
);
},
//
// Return the delay callback
//
ConfigDelay: function () {
var delay = this.params.delayStartupUntil || MathJax.Hub.config.delayStartupUntil;
if (delay === "onload") {return this.onload}
if (delay === "configured") {return MathJax.Hub.Configured}
return delay;
},
//
// Run the scripts of type=text/x-mathjax-config
//
ConfigBlocks: function () {
var scripts = document.getElementsByTagName("script");
var queue = MathJax.Callback.Queue();
for (var i = 0, m = scripts.length; i < m; i++) {
var type = String(scripts[i].type).replace(/ /g,"");
if (type.match(/^text\/x-mathjax-config(;.*)?$/) && !type.match(/;executed=true/)) {
scripts[i].type += ";executed=true";
queue.Push(scripts[i].innerHTML+";\n1;");
}
}
return queue.Push(function () {MathJax.Ajax.config.root = MathJax.Hub.config.root});
},
//
// Read cookie and set up menu defaults
// (set the locale according to the cookie)
// (adjust the jax to accommodate renderer preferences)
//
Cookie: function () {
return this.queue.Push(
["Post",this.signal,"Begin Cookie"],
["Get",MathJax.HTML.Cookie,"menu",MathJax.Hub.config.menuSettings],
[function (config) {
var SETTINGS = config.menuSettings;
if (SETTINGS.locale) MathJax.Localization.resetLocale(SETTINGS.locale);
var renderer = config.menuSettings.renderer, jax = config.jax;
if (renderer) {
var name = "output/"+renderer; jax.sort();
for (var i = 0, m = jax.length; i < m; i++) {
if (jax[i].substr(0,7) === "output/") break;
}
if (i == m-1) {jax.pop()} else {
while (i < m) {if (jax[i] === name) {jax.splice(i,1); break}; i++}
}
jax.unshift(name);
}
if (SETTINGS.CHTMLpreview != null) {
if (SETTINGS.FastPreview == null) SETTINGS.FastPreview = SETTINGS.CHTMLpreview;
delete SETTINGS.CHTMLpreview;
}
if (SETTINGS.FastPreview && !MathJax.Extension["fast-preview"])
MathJax.Hub.config.extensions.push("fast-preview.js");
if (config.menuSettings.assistiveMML && !MathJax.Extension.AssistiveMML)
MathJax.Hub.config.extensions.push("AssistiveMML.js");
},MathJax.Hub.config],
["Post",this.signal,"End Cookie"]
);
},
//
// Setup stylesheets and extra styles
//
Styles: function () {
return this.queue.Push(
["Post",this.signal,"Begin Styles"],
["loadArray",this,MathJax.Hub.config.styleSheets,"config"],
["Styles",MathJax.Ajax,MathJax.Hub.config.styles],
["Post",this.signal,"End Styles"]
);
},
//
// Load the input and output jax
//
Jax: function () {
var config = MathJax.Hub.config, jax = MathJax.Hub.outputJax;
// Save the order of the output jax since they are loading asynchronously
for (var i = 0, m = config.jax.length, k = 0; i < m; i++) {
var name = config.jax[i].substr(7);
if (config.jax[i].substr(0,7) === "output/" && jax.order[name] == null)
{jax.order[name] = k; k++}
}
var queue = MathJax.Callback.Queue();
return queue.Push(
["Post",this.signal,"Begin Jax"],
["loadArray",this,config.jax,"jax","config.js"],
["Post",this.signal,"End Jax"]
);
},
//
// Load the extensions
//
Extensions: function () {
var queue = MathJax.Callback.Queue();
return queue.Push(
["Post",this.signal,"Begin Extensions"],
["loadArray",this,MathJax.Hub.config.extensions,"extensions"],
["Post",this.signal,"End Extensions"]
);
},
//
// Initialize the Message system
//
Message: function () {
MathJax.Message.Init(true);
},
//
// Set the math menu renderer, if it isn't already
// (this must come after the jax are loaded)
//
Menu: function () {
var menu = MathJax.Hub.config.menuSettings, jax = MathJax.Hub.outputJax, registered;
for (var id in jax) {if (jax.hasOwnProperty(id)) {
if (jax[id].length) {registered = jax[id]; break}
}}
if (registered && registered.length) {
if (menu.renderer && menu.renderer !== registered[0].id)
{registered.unshift(MathJax.OutputJax[menu.renderer])}
menu.renderer = registered[0].id;
}
},
//
// Set the location to the designated hash position
//
Hash: function () {
if (MathJax.Hub.config.positionToHash && document.location.hash &&
document.body && document.body.scrollIntoView) {
var name = document.location.hash.substr(1);
var target = document.getElementById(name);
if (!target) {
var a = document.getElementsByTagName("a");
for (var i = 0, m = a.length; i < m; i++)
{if (a[i].name === name) {target = a[i]; break}}
}
if (target) {
while (!target.scrollIntoView) {target = target.parentNode}
target = this.HashCheck(target);
if (target && target.scrollIntoView)
{setTimeout(function () {target.scrollIntoView(true)},1)}
}
}
},
HashCheck: function (target) {
var jax = MathJax.Hub.getJaxFor(target);
if (jax && MathJax.OutputJax[jax.outputJax].hashCheck)
{target = MathJax.OutputJax[jax.outputJax].hashCheck(target)}
return target;
},
//
// Load the Menu and Zoom code, if it hasn't already been loaded.
// This is called after the initial typeset, so should no longer be
// competing with other page loads, but will make these available
// if needed later on.
//
MenuZoom: function () {
if (MathJax.Hub.config.showMathMenu) {
if (!MathJax.Extension.MathMenu) {
setTimeout(
function () {
MathJax.Callback.Queue(
["Require",MathJax.Ajax,"[MathJax]/extensions/MathMenu.js",{}],
["loadDomain",MathJax.Localization,"MathMenu"]
)
},1000
);
} else {
setTimeout(
MathJax.Callback(["loadDomain",MathJax.Localization,"MathMenu"]),
1000
);
}
if (!MathJax.Extension.MathZoom) {
setTimeout(
MathJax.Callback(["Require",MathJax.Ajax,"[MathJax]/extensions/MathZoom.js",{}]),
2000
);
}
}
},
//
// Setup the onload callback
//
onLoad: function () {
var onload = this.onload =
MathJax.Callback(function () {MathJax.Hub.Startup.signal.Post("onLoad")});
if (document.body && document.readyState)
if (MathJax.Hub.Browser.isMSIE) {
// IE can change from loading to interactive before
// full page is ready, so go with complete (even though
// that means we may have to wait longer).
if (document.readyState === "complete") {return [onload]}
} else if (document.readyState !== "loading") {return [onload]}
if (window.addEventListener) {
window.addEventListener("load",onload,false);
if (!this.params.noDOMContentEvent)
{window.addEventListener("DOMContentLoaded",onload,false)}
}
else if (window.attachEvent) {window.attachEvent("onload",onload)}
else {window.onload = onload}
return onload;
},
//
// Perform the initial typesetting (or skip if configuration says to)
//
Typeset: function (element,callback) {
if (MathJax.Hub.config.skipStartupTypeset) {return function () {}}
return this.queue.Push(
["Post",this.signal,"Begin Typeset"],
["Typeset",MathJax.Hub,element,callback],
["Post",this.signal,"End Typeset"]
);
},
//
// Create a URL in the MathJax hierarchy
//
URL: function (dir,name) {
if (!name.match(/^([a-z]+:\/\/|\[|\/)/)) {name = "[MathJax]/"+dir+"/"+name}
return name;
},
//
// Load an array of files, waiting for all of them
// to be loaded before going on
//
loadArray: function (files,dir,name,synchronous) {
if (files) {
if (!MathJax.Object.isArray(files)) {files = [files]}
if (files.length) {
var queue = MathJax.Callback.Queue(), callback = {}, file;
for (var i = 0, m = files.length; i < m; i++) {
file = this.URL(dir,files[i]);
if (name) {file += "/" + name}
if (synchronous) {queue.Push(["Require",MathJax.Ajax,file,callback])}
else {queue.Push(MathJax.Ajax.Require(file,callback))}
}
return queue.Push({}); // wait for everything to finish
}
}
return null;
}
};
/**********************************************************/
(function (BASENAME) {
var BASE = window[BASENAME], ROOT = "["+BASENAME+"]";
var HUB = BASE.Hub, AJAX = BASE.Ajax, CALLBACK = BASE.Callback;
var JAX = MathJax.Object.Subclass({
JAXFILE: "jax.js",
require: null, // array of files to load before jax.js is complete
config: {},
//
// Make a subclass and return an instance of it.
// (FIXME: should we replace config with a copy of the constructor's
// config? Otherwise all subclasses share the same config structure.)
//
Init: function (def,cdef) {
if (arguments.length === 0) {return this}
return (this.constructor.Subclass(def,cdef))();
},
//
// Augment by merging with class definition (not replacing)
//
Augment: function (def,cdef) {
var cObject = this.constructor, ndef = {};
if (def != null) {
for (var id in def) {if (def.hasOwnProperty(id)) {
if (typeof def[id] === "function")
{cObject.protoFunction(id,def[id])} else {ndef[id] = def[id]}
}}
// MSIE doesn't list toString even if it is not native so handle it separately
if (def.toString !== cObject.prototype.toString && def.toString !== {}.toString)
{cObject.protoFunction('toString',def.toString)}
}
HUB.Insert(cObject.prototype,ndef);
cObject.Augment(null,cdef);
return this;
},
Translate: function (script,state) {
throw Error(this.directory+"/"+this.JAXFILE+" failed to define the Translate() method");
},
Register: function (mimetype) {},
Config: function () {
this.config = HUB.CombineConfig(this.id,this.config);
if (this.config.Augment) {this.Augment(this.config.Augment)}
},
Startup: function () {},
loadComplete: function (file) {
if (file === "config.js") {
return AJAX.loadComplete(this.directory+"/"+file);
} else {
var queue = CALLBACK.Queue();
queue.Push(
HUB.Register.StartupHook("End Config",{}), // wait until config complete
["Post",HUB.Startup.signal,this.id+" Jax Config"],
["Config",this],
["Post",HUB.Startup.signal,this.id+" Jax Require"],
// Config may set the required and extensions array,
// so use functions to delay making the reference until needed
[function (THIS) {return MathJax.Hub.Startup.loadArray(THIS.require,this.directory)},this],
[function (config,id) {return MathJax.Hub.Startup.loadArray(config.extensions,"extensions/"+id)},this.config||{},this.id],
["Post",HUB.Startup.signal,this.id+" Jax Startup"],
["Startup",this],
["Post",HUB.Startup.signal,this.id+" Jax Ready"]
);
if (this.copyTranslate) {
queue.Push(
[function (THIS) {
THIS.preProcess = THIS.preTranslate;
THIS.Process = THIS.Translate;
THIS.postProcess = THIS.postTranslate;
},this.constructor.prototype]
);
}
return queue.Push(["loadComplete",AJAX,this.directory+"/"+file]);
}
}
},{
id: "Jax",
version: "2.7.1",
directory: ROOT+"/jax",
extensionDir: ROOT+"/extensions"
});
/***********************************/
BASE.InputJax = JAX.Subclass({
elementJax: "mml", // the element jax to load for this input jax
sourceMenuTitle: /*_(MathMenu)*/ ["Original","Original Form"],
copyTranslate: true,
Process: function (script,state) {
var queue = CALLBACK.Queue(), file;
// Load any needed element jax
var jax = this.elementJax; if (!BASE.Object.isArray(jax)) {jax = [jax]}
for (var i = 0, m = jax.length; i < m; i++) {
file = BASE.ElementJax.directory+"/"+jax[i]+"/"+this.JAXFILE;
if (!this.require) {this.require = []}
else if (!BASE.Object.isArray(this.require)) {this.require = [this.require]};
this.require.push(file); // so Startup will wait for it to be loaded
queue.Push(AJAX.Require(file));
}
// Load the input jax
file = this.directory+"/"+this.JAXFILE;
var load = queue.Push(AJAX.Require(file));
if (!load.called) {
this.constructor.prototype.Process = function () {
if (!load.called) {return load}
throw Error(file+" failed to load properly");
}
}
// Load the associated output jax
jax = HUB.outputJax["jax/"+jax[0]];
if (jax) {queue.Push(AJAX.Require(jax[0].directory+"/"+this.JAXFILE))}
return queue.Push({});
},
needsUpdate: function (jax) {
var script = jax.SourceElement();
return (jax.originalText !== BASE.HTML.getScript(script));
},
Register: function (mimetype) {
if (!HUB.inputJax) {HUB.inputJax = {}}
HUB.inputJax[mimetype] = this;
}
},{
id: "InputJax",
version: "2.7.1",
directory: JAX.directory+"/input",
extensionDir: JAX.extensionDir
});
/***********************************/
BASE.OutputJax = JAX.Subclass({
copyTranslate: true,
preProcess: function (state) {
var load, file = this.directory+"/"+this.JAXFILE;
this.constructor.prototype.preProcess = function (state) {
if (!load.called) {return load}
throw Error(file+" failed to load properly");
}
load = AJAX.Require(file);
return load;
},
Register: function (mimetype) {
var jax = HUB.outputJax;
if (!jax[mimetype]) {jax[mimetype] = []}
// If the output jax is earlier in the original configuration list, put it first here
if (jax[mimetype].length && (this.id === HUB.config.menuSettings.renderer ||
(jax.order[this.id]||0) < (jax.order[jax[mimetype][0].id]||0)))
{jax[mimetype].unshift(this)} else {jax[mimetype].push(this)}
// Make sure the element jax is loaded before Startup is called
if (!this.require) {this.require = []}
else if (!BASE.Object.isArray(this.require)) {this.require = [this.require]};
this.require.push(BASE.ElementJax.directory+"/"+(mimetype.split(/\//)[1])+"/"+this.JAXFILE);
},
Remove: function (jax) {}
},{
id: "OutputJax",
version: "2.7.1",
directory: JAX.directory+"/output",
extensionDir: JAX.extensionDir,
fontDir: ROOT+(BASE.isPacked?"":"/..")+"/fonts",
imageDir: ROOT+(BASE.isPacked?"":"/..")+"/images"
});
/***********************************/
BASE.ElementJax = JAX.Subclass({
// make a subclass, not an instance
Init: function (def,cdef) {return this.constructor.Subclass(def,cdef)},
inputJax: null,
outputJax: null,
inputID: null,
originalText: "",
mimeType: "",
sourceMenuTitle: /*_(MathMenu)*/ ["MathMLcode","MathML Code"],
Text: function (text,callback) {
var script = this.SourceElement();
BASE.HTML.setScript(script,text);
script.MathJax.state = this.STATE.UPDATE;
return HUB.Update(script,callback);
},
Reprocess: function (callback) {
var script = this.SourceElement();
script.MathJax.state = this.STATE.UPDATE;
return HUB.Reprocess(script,callback);
},
Update: function (callback) {return this.Rerender(callback)},
Rerender: function (callback) {
var script = this.SourceElement();
script.MathJax.state = this.STATE.OUTPUT;
return HUB.Process(script,callback);
},
Remove: function (keep) {
if (this.hover) {this.hover.clear(this)}
BASE.OutputJax[this.outputJax].Remove(this);
if (!keep) {
HUB.signal.Post(["Remove Math",this.inputID]); // wait for this to finish?
this.Detach();
}
},
needsUpdate: function () {
return BASE.InputJax[this.inputJax].needsUpdate(this);
},
SourceElement: function () {return document.getElementById(this.inputID)},
Attach: function (script,inputJax) {
var jax = script.MathJax.elementJax;
if (script.MathJax.state === this.STATE.UPDATE) {
jax.Clone(this);
} else {
jax = script.MathJax.elementJax = this;
if (script.id) {this.inputID = script.id}
else {script.id = this.inputID = BASE.ElementJax.GetID(); this.newID = 1}
}
jax.originalText = BASE.HTML.getScript(script);
jax.inputJax = inputJax;
if (jax.root) {jax.root.inputID = jax.inputID}
return jax;
},
Detach: function () {
var script = this.SourceElement(); if (!script) return;
try {delete script.MathJax} catch(err) {script.MathJax = null}
if (this.newID) {script.id = ""}
},
Clone: function (jax) {
var id;
for (id in this) {
if (!this.hasOwnProperty(id)) continue;
if (typeof(jax[id]) === 'undefined' && id !== 'newID') {delete this[id]}
}
for (id in jax) {
if (!jax.hasOwnProperty(id)) continue;
if (typeof(this[id]) === 'undefined' || (this[id] !== jax[id] && id !== 'inputID'))
{this[id] = jax[id]}
}
}
},{
id: "ElementJax",
version: "2.7.1",
directory: JAX.directory+"/element",
extensionDir: JAX.extensionDir,
ID: 0, // jax counter (for IDs)
STATE: {
PENDING: 1, // script is identified as math but not yet processed
PROCESSED: 2, // script has been processed
UPDATE: 3, // elementJax should be updated
OUTPUT: 4 // output should be updated (input is OK)
},
GetID: function () {this.ID++; return "MathJax-Element-"+this.ID},
Subclass: function () {
var obj = JAX.Subclass.apply(this,arguments);
obj.loadComplete = this.prototype.loadComplete;
return obj;
}
});
BASE.ElementJax.prototype.STATE = BASE.ElementJax.STATE;
//
// Some "Fake" jax used to allow menu access for "Math Processing Error" messages
//
BASE.OutputJax.Error = {
id: "Error", version: "2.7.1", config: {}, errors: 0,
ContextMenu: function () {return BASE.Extension.MathEvents.Event.ContextMenu.apply(BASE.Extension.MathEvents.Event,arguments)},
Mousedown: function () {return BASE.Extension.MathEvents.Event.AltContextMenu.apply(BASE.Extension.MathEvents.Event,arguments)},
getJaxFromMath: function (math) {return (math.nextSibling.MathJax||{}).error},
Jax: function (text,script) {
var jax = MathJax.Hub.inputJax[script.type.replace(/ *;(.|\s)*/,"")];
this.errors++;
return {
inputJax: (jax||{id:"Error"}).id, // Use Error InputJax as fallback
outputJax: "Error",
inputID: "MathJax-Error-"+this.errors,
sourceMenuTitle: /*_(MathMenu)*/ ["ErrorMessage","Error Message"],
sourceMenuFormat: "Error",
originalText: MathJax.HTML.getScript(script),
errorText: text
}
}
};
BASE.InputJax.Error = {
id: "Error", version: "2.7.1", config: {},
sourceMenuTitle: /*_(MathMenu)*/ ["Original","Original Form"]
};
})("MathJax");
/**********************************************************/
(function (BASENAME) {
var BASE = window[BASENAME];
if (!BASE) {BASE = window[BASENAME] = {}}
var HUB = BASE.Hub; var STARTUP = HUB.Startup; var CONFIG = HUB.config;
var HEAD = document.head || (document.getElementsByTagName("head")[0]);
if (!HEAD) {HEAD = document.childNodes[0]};
var scripts = (document.documentElement || document).getElementsByTagName("script");
if (scripts.length === 0 && HEAD.namespaceURI)
scripts = document.getElementsByTagNameNS(HEAD.namespaceURI,"script");
var namePattern = new RegExp("(^|/)"+BASENAME+"\\.js(\\?.*)?$");
for (var i = scripts.length-1; i >= 0; i--) {
if ((scripts[i].src||"").match(namePattern)) {
STARTUP.script = scripts[i].innerHTML;
if (RegExp.$2) {
var params = RegExp.$2.substr(1).split(/\&/);
for (var j = 0, m = params.length; j < m; j++) {
var KV = params[j].match(/(.*)=(.*)/);
if (KV) {STARTUP.params[unescape(KV[1])] = unescape(KV[2])}
else {STARTUP.params[params[j]] = true}
}
}
CONFIG.root = scripts[i].src.replace(/(^|\/)[^\/]*(\?.*)?$/,'');
BASE.Ajax.config.root = CONFIG.root;
BASE.Ajax.params = STARTUP.params;
break;
}
}
var AGENT = navigator.userAgent;
var BROWSERS = {
isMac: (navigator.platform.substr(0,3) === "Mac"),
isPC: (navigator.platform.substr(0,3) === "Win"),
isMSIE: ("ActiveXObject" in window && "clipboardData" in window),
isEdge: ("MSGestureEvent" in window && "chrome" in window &&
window.chrome.loadTimes == null),
isFirefox: (!!AGENT.match(/Gecko\//) && !AGENT.match(/like Gecko/)),
isSafari: (!!AGENT.match(/ (Apple)?WebKit\//) && !AGENT.match(/ like iPhone /) &&
(!window.chrome || window.chrome.app == null)),
isChrome: ("chrome" in window && window.chrome.loadTimes != null),
isOpera: ("opera" in window && window.opera.version != null),
isKonqueror: ("konqueror" in window && navigator.vendor == "KDE"),
versionAtLeast: function (v) {
var bv = (this.version).split('.'); v = (new String(v)).split('.');
for (var i = 0, m = v.length; i < m; i++)
{if (bv[i] != v[i]) {return parseInt(bv[i]||"0") >= parseInt(v[i])}}
return true;
},
Select: function (choices) {
var browser = choices[HUB.Browser];
if (browser) {return browser(HUB.Browser)}
return null;
}
};
var xAGENT = AGENT
.replace(/^Mozilla\/(\d+\.)+\d+ /,"") // remove initial Mozilla, which is never right
.replace(/[a-z][-a-z0-9._: ]+\/\d+[^ ]*-[^ ]*\.([a-z][a-z])?\d+ /i,"") // remove linux version
.replace(/Gentoo |Ubuntu\/(\d+\.)*\d+ (\([^)]*\) )?/,""); // special case for these
HUB.Browser = HUB.Insert(HUB.Insert(new String("Unknown"),{version: "0.0"}),BROWSERS);
for (var browser in BROWSERS) {if (BROWSERS.hasOwnProperty(browser)) {
if (BROWSERS[browser] && browser.substr(0,2) === "is") {
browser = browser.slice(2);
if (browser === "Mac" || browser === "PC") continue;
HUB.Browser = HUB.Insert(new String(browser),BROWSERS);
var VERSION = new RegExp(
".*(Version/| Trident/.*; rv:)((?:\\d+\\.)+\\d+)|" + // for Safari, Opera10, and IE11+
".*("+browser+")"+(browser == "MSIE" ? " " : "/")+"((?:\\d+\\.)*\\d+)|"+ // for one of the main browsers
"(?:^|\\(| )([a-z][-a-z0-9._: ]+|(?:Apple)?WebKit)/((?:\\d+\\.)+\\d+)"); // for unrecognized browser
var MATCH = VERSION.exec(xAGENT) || ["","","","unknown","0.0"];
HUB.Browser.name = (MATCH[1] != "" ? browser : (MATCH[3] || MATCH[5]));
HUB.Browser.version = MATCH[2] || MATCH[4] || MATCH[6];
break;
}
}};
//
// Initial browser-specific info (e.g., touch up version or name, check for MathPlayer, etc.)
// Wrap in try/catch just in case of error (see issue #1155).
//
try {HUB.Browser.Select({
Safari: function (browser) {
var v = parseInt((String(browser.version).split("."))[0]);
if (v > 85) {browser.webkit = browser.version}
if (v >= 538) {browser.version = "8.0"}
else if (v >= 537) {browser.version = "7.0"}
else if (v >= 536) {browser.version = "6.0"}
else if (v >= 534) {browser.version = "5.1"}
else if (v >= 533) {browser.version = "5.0"}
else if (v >= 526) {browser.version = "4.0"}
else if (v >= 525) {browser.version = "3.1"}
else if (v > 500) {browser.version = "3.0"}
else if (v > 400) {browser.version = "2.0"}
else if (v > 85) {browser.version = "1.0"}
browser.webkit = (navigator.appVersion.match(/WebKit\/(\d+)\./))[1];
browser.isMobile = (navigator.appVersion.match(/Mobile/i) != null);
browser.noContextMenu = browser.isMobile;
},
Firefox: function (browser) {
if ((browser.version === "0.0" || AGENT.match(/Firefox/) == null) &&
navigator.product === "Gecko") {
var rv = AGENT.match(/[\/ ]rv:(\d+\.\d.*?)[\) ]/);
if (rv) {browser.version = rv[1]}
else {
var date = (navigator.buildID||navigator.productSub||"0").substr(0,8);
if (date >= "20111220") {browser.version = "9.0"}
else if (date >= "20111120") {browser.version = "8.0"}
else if (date >= "20110927") {browser.version = "7.0"}
else if (date >= "20110816") {browser.version = "6.0"}
else if (date >= "20110621") {browser.version = "5.0"}
else if (date >= "20110320") {browser.version = "4.0"}
else if (date >= "20100121") {browser.version = "3.6"}
else if (date >= "20090630") {browser.version = "3.5"}
else if (date >= "20080617") {browser.version = "3.0"}
else if (date >= "20061024") {browser.version = "2.0"}
}
}
browser.isMobile = (navigator.appVersion.match(/Android/i) != null ||
AGENT.match(/ Fennec\//) != null ||
AGENT.match(/Mobile/) != null);
},
Chrome: function (browser) {
browser.noContextMenu = browser.isMobile = !!navigator.userAgent.match(/ Mobile[ \/]/);
},
Opera: function (browser) {browser.version = opera.version()},
Edge: function (browser) {
browser.isMobile = !!navigator.userAgent.match(/ Phone/);
},
MSIE: function (browser) {
browser.isMobile = !!navigator.userAgent.match(/ Phone/);
browser.isIE9 = !!(document.documentMode && (window.performance || window.msPerformance));
MathJax.HTML.setScriptBug = !browser.isIE9 || document.documentMode < 9;
MathJax.Hub.msieHTMLCollectionBug = (document.documentMode < 9);
//
// MathPlayer doesn't function properly in IE10, and not at all in IE11,
// so don't even try to load it.
//
if (document.documentMode < 10 && !STARTUP.params.NoMathPlayer) {
try {
new ActiveXObject("MathPlayer.Factory.1");
browser.hasMathPlayer = true;
} catch (err) {}
try {
if (browser.hasMathPlayer) {
var mathplayer = document.createElement("object");
mathplayer.id = "mathplayer"; mathplayer.classid = "clsid:32F66A20-7614-11D4-BD11-00104BD3F987";
HEAD.appendChild(mathplayer);
document.namespaces.add("m","http://www.w3.org/1998/Math/MathML");
browser.mpNamespace = true;
if (document.readyState && (document.readyState === "loading" ||
document.readyState === "interactive")) {
document.write('<?import namespace="m" implementation="#MathPlayer">');
browser.mpImported = true;
}
} else {
// Adding any namespace avoids a crash in IE9 in IE9-standards mode
// (any reference to document.namespaces before document.readyState is
// "complete" causes an "unspecified error" to be thrown)
document.namespaces.add("mjx_IE_fix","http://www.w3.org/1999/xlink");
}
} catch (err) {}
}
}
});} catch (err) {
console.error(err.message);
}
MathJax.Ajax.Preloading(
"[MathJax]/jax/element/mml/jax.js",
"[MathJax]/jax/element/mml/optable/Arrows.js",
"[MathJax]/jax/element/mml/optable/MiscMathSymbolsA.js",
"[MathJax]/jax/element/mml/optable/Dingbats.js",
"[MathJax]/jax/element/mml/optable/GeneralPunctuation.js",
"[MathJax]/jax/element/mml/optable/SpacingModLetters.js",
"[MathJax]/jax/element/mml/optable/MiscTechnical.js",
"[MathJax]/jax/element/mml/optable/SupplementalArrowsA.js",
"[MathJax]/jax/element/mml/optable/GreekAndCoptic.js",
"[MathJax]/jax/element/mml/optable/LetterlikeSymbols.js",
"[MathJax]/jax/element/mml/optable/SupplementalArrowsB.js",
"[MathJax]/jax/element/mml/optable/BasicLatin.js",
"[MathJax]/jax/element/mml/optable/MiscSymbolsAndArrows.js",
"[MathJax]/jax/element/mml/optable/CombDiacritMarks.js",
"[MathJax]/jax/element/mml/optable/GeometricShapes.js",
"[MathJax]/jax/element/mml/optable/MathOperators.js",
"[MathJax]/jax/element/mml/optable/MiscMathSymbolsB.js",
"[MathJax]/jax/element/mml/optable/SuppMathOperators.js",
"[MathJax]/jax/element/mml/optable/CombDiactForSymbols.js",
"[MathJax]/jax/element/mml/optable/Latin1Supplement.js",
"[MathJax]/extensions/MathEvents.js",
"[MathJax]/extensions/MathZoom.js",
"[MathJax]/extensions/MathMenu.js",
"[MathJax]/extensions/toMathML.js",
"[MathJax]/extensions/HelpDialog.js",
"[MathJax]/jax/input/TeX/config.js",
"[MathJax]/jax/input/TeX/jax.js",
"[MathJax]/jax/output/SVG/config.js",
"[MathJax]/jax/output/SVG/jax.js",
"[MathJax]/jax/output/SVG/autoload/mtable.js",
"[MathJax]/jax/output/SVG/autoload/mglyph.js",
"[MathJax]/jax/output/SVG/autoload/mmultiscripts.js",
"[MathJax]/jax/output/SVG/autoload/annotation-xml.js",
"[MathJax]/jax/output/SVG/autoload/maction.js",
"[MathJax]/jax/output/SVG/autoload/multiline.js",
"[MathJax]/jax/output/SVG/autoload/menclose.js",
"[MathJax]/jax/output/SVG/autoload/ms.js",
"[MathJax]/extensions/tex2jax.js",
"[MathJax]/extensions/TeX/AMScd.js",
"[MathJax]/extensions/TeX/AMSmath.js",
"[MathJax]/extensions/TeX/AMSsymbols.js",
"[MathJax]/extensions/TeX/HTML.js",
"[MathJax]/extensions/TeX/action.js",
"[MathJax]/extensions/TeX/autobold.js",
"[MathJax]/extensions/TeX/bbox.js",
"[MathJax]/extensions/TeX/boldsymbol.js",
"[MathJax]/extensions/TeX/cancel.js",
"[MathJax]/extensions/TeX/color.js",
"[MathJax]/extensions/TeX/enclose.js",
"[MathJax]/extensions/TeX/extpfeil.js",
"[MathJax]/extensions/TeX/mathchoice.js",
"[MathJax]/extensions/TeX/mediawiki-texvc.js",
"[MathJax]/extensions/TeX/mhchem.js",
"[MathJax]/extensions/TeX/newcommand.js",
"[MathJax]/extensions/TeX/unicode.js",
"[MathJax]/extensions/TeX/verb.js",
"[MathJax]/jax/output/SVG/fonts/TeX/fontdata.js",
"[MathJax]/jax/output/SVG/fonts/TeX/fontdata-extra.js",
"[MathJax]/jax/output/SVG/fonts/TeX/AMS/Regular/Main.js",
"[MathJax]/jax/output/SVG/fonts/TeX/AMS/Regular/Arrows.js",
"[MathJax]/jax/output/SVG/fonts/TeX/AMS/Regular/BoxDrawing.js",
"[MathJax]/jax/output/SVG/fonts/TeX/AMS/Regular/CombDiacritMarks.js",
"[MathJax]/jax/output/SVG/fonts/TeX/AMS/Regular/Dingbats.js",
"[MathJax]/jax/output/SVG/fonts/TeX/AMS/Regular/EnclosedAlphanum.js",
"[MathJax]/jax/output/SVG/fonts/TeX/AMS/Regular/GeneralPunctuation.js",
"[MathJax]/jax/output/SVG/fonts/TeX/AMS/Regular/GeometricShapes.js",
"[MathJax]/jax/output/SVG/fonts/TeX/AMS/Regular/GreekAndCoptic.js",
"[MathJax]/jax/output/SVG/fonts/TeX/AMS/Regular/Latin1Supplement.js",
"[MathJax]/jax/output/SVG/fonts/TeX/AMS/Regular/LatinExtendedA.js",
"[MathJax]/jax/output/SVG/fonts/TeX/AMS/Regular/LetterlikeSymbols.js",
"[MathJax]/jax/output/SVG/fonts/TeX/AMS/Regular/MathOperators.js",
"[MathJax]/jax/output/SVG/fonts/TeX/AMS/Regular/MiscMathSymbolsB.js",
"[MathJax]/jax/output/SVG/fonts/TeX/AMS/Regular/MiscSymbols.js",
"[MathJax]/jax/output/SVG/fonts/TeX/AMS/Regular/MiscTechnical.js",
"[MathJax]/jax/output/SVG/fonts/TeX/AMS/Regular/PUA.js",
"[MathJax]/jax/output/SVG/fonts/TeX/AMS/Regular/SpacingModLetters.js",
"[MathJax]/jax/output/SVG/fonts/TeX/AMS/Regular/SuppMathOperators.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Caligraphic/Bold/Main.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Caligraphic/Regular/Main.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Fraktur/Bold/Main.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Fraktur/Bold/BasicLatin.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Fraktur/Bold/Other.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Fraktur/Bold/PUA.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Fraktur/Regular/Main.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Fraktur/Regular/BasicLatin.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Fraktur/Regular/Other.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Fraktur/Regular/PUA.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Bold/Main.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Bold/Arrows.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Bold/BasicLatin.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Bold/CombDiacritMarks.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Bold/CombDiactForSymbols.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Bold/GeneralPunctuation.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Bold/GeometricShapes.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Bold/GreekAndCoptic.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Bold/Latin1Supplement.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Bold/LatinExtendedA.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Bold/LatinExtendedB.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Bold/LetterlikeSymbols.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Bold/MathOperators.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Bold/MiscMathSymbolsA.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Bold/MiscSymbols.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Bold/MiscTechnical.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Bold/SpacingModLetters.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Bold/SupplementalArrowsA.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Bold/SuppMathOperators.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Italic/Main.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Italic/BasicLatin.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Italic/CombDiacritMarks.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Italic/GeneralPunctuation.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Italic/GreekAndCoptic.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Italic/LatinExtendedA.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Italic/LatinExtendedB.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Italic/LetterlikeSymbols.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Regular/BasicLatin.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Regular/CombDiacritMarks.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Regular/GeometricShapes.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Regular/GreekAndCoptic.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Regular/LatinExtendedA.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Regular/LatinExtendedB.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Regular/LetterlikeSymbols.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Regular/MiscSymbols.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Regular/SpacingModLetters.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Main/Regular/SuppMathOperators.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Math/BoldItalic/Main.js",
"[MathJax]/jax/output/SVG/fonts/TeX/SansSerif/Bold/Main.js",
"[MathJax]/jax/output/SVG/fonts/TeX/SansSerif/Bold/BasicLatin.js",
"[MathJax]/jax/output/SVG/fonts/TeX/SansSerif/Bold/CombDiacritMarks.js",
"[MathJax]/jax/output/SVG/fonts/TeX/SansSerif/Bold/Other.js",
"[MathJax]/jax/output/SVG/fonts/TeX/SansSerif/Italic/Main.js",
"[MathJax]/jax/output/SVG/fonts/TeX/SansSerif/Italic/BasicLatin.js",
"[MathJax]/jax/output/SVG/fonts/TeX/SansSerif/Italic/CombDiacritMarks.js",
"[MathJax]/jax/output/SVG/fonts/TeX/SansSerif/Italic/Other.js",
"[MathJax]/jax/output/SVG/fonts/TeX/SansSerif/Regular/Main.js",
"[MathJax]/jax/output/SVG/fonts/TeX/SansSerif/Regular/BasicLatin.js",
"[MathJax]/jax/output/SVG/fonts/TeX/SansSerif/Regular/CombDiacritMarks.js",
"[MathJax]/jax/output/SVG/fonts/TeX/SansSerif/Regular/Other.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Script/Regular/Main.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Script/Regular/BasicLatin.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Size1/Regular/Main.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Size2/Regular/Main.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Size3/Regular/Main.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Size4/Regular/Main.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Typewriter/Regular/Main.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Typewriter/Regular/BasicLatin.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Typewriter/Regular/CombDiacritMarks.js",
"[MathJax]/jax/output/SVG/fonts/TeX/Typewriter/Regular/Other.js");
MathJax.Hub.Config({"v1.0-compatible":false});
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/jax/element/mml/jax.js
*
* Implements the MML ElementJax that holds the internal represetation
* of the mathematics on the page. Various InputJax will produce this
* format, and the OutputJax will display it in various formats.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2009-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
MathJax.ElementJax.mml = MathJax.ElementJax({
mimeType: "jax/mml"
},{
id: "mml",
version: "2.7.1",
directory: MathJax.ElementJax.directory + "/mml",
extensionDir: MathJax.ElementJax.extensionDir + "/mml",
optableDir: MathJax.ElementJax.directory + "/mml/optable"
});
MathJax.ElementJax.mml.Augment({
Init: function () {
if (arguments.length === 1 && arguments[0].type === "math") {this.root = arguments[0]}
else {this.root = MathJax.ElementJax.mml.math.apply(this,arguments)}
if (this.root.attr && this.root.attr.mode) {
if (!this.root.display && this.root.attr.mode === "display") {
this.root.display = "block";
this.root.attrNames.push("display");
}
delete this.root.attr.mode;
for (var i = 0, m = this.root.attrNames.length; i < m; i++) {
if (this.root.attrNames[i] === "mode") {this.root.attrNames.splice(i,1); break}
}
}
}
},{
INHERIT: "_inherit_",
AUTO: "_auto_",
SIZE: {
INFINITY: "infinity",
SMALL: "small",
NORMAL: "normal",
BIG: "big"
},
COLOR: {
TRANSPARENT: "transparent"
},
VARIANT: {
NORMAL: "normal",
BOLD: "bold",
ITALIC: "italic",
BOLDITALIC: "bold-italic",
DOUBLESTRUCK: "double-struck",
FRAKTUR: "fraktur",
BOLDFRAKTUR: "bold-fraktur",
SCRIPT: "script",
BOLDSCRIPT: "bold-script",
SANSSERIF: "sans-serif",
BOLDSANSSERIF: "bold-sans-serif",
SANSSERIFITALIC: "sans-serif-italic",
SANSSERIFBOLDITALIC: "sans-serif-bold-italic",
MONOSPACE: "monospace",
INITIAL: "inital",
TAILED: "tailed",
LOOPED: "looped",
STRETCHED: "stretched",
CALIGRAPHIC: "-tex-caligraphic",
OLDSTYLE: "-tex-oldstyle"
},
FORM: {
PREFIX: "prefix",
INFIX: "infix",
POSTFIX: "postfix"
},
LINEBREAK: {
AUTO: "auto",
NEWLINE: "newline",
NOBREAK: "nobreak",
GOODBREAK: "goodbreak",
BADBREAK: "badbreak"
},
LINEBREAKSTYLE: {
BEFORE: "before",
AFTER: "after",
DUPLICATE: "duplicate",
INFIXLINBREAKSTYLE: "infixlinebreakstyle"
},
INDENTALIGN: {
LEFT: "left",
CENTER: "center",
RIGHT: "right",
AUTO: "auto",
ID: "id",
INDENTALIGN: "indentalign"
},
INDENTSHIFT: {
INDENTSHIFT: "indentshift"
},
LINETHICKNESS: {
THIN: "thin",
MEDIUM: "medium",
THICK: "thick"
},
NOTATION: {
LONGDIV: "longdiv",
ACTUARIAL: "actuarial",
RADICAL: "radical",
BOX: "box",
ROUNDEDBOX: "roundedbox",
CIRCLE: "circle",
LEFT: "left",
RIGHT: "right",
TOP: "top",
BOTTOM: "bottom",
UPDIAGONALSTRIKE: "updiagonalstrike",
DOWNDIAGONALSTRIKE: "downdiagonalstrike",
UPDIAGONALARROW: "updiagonalarrow",
VERTICALSTRIKE: "verticalstrike",
HORIZONTALSTRIKE: "horizontalstrike",
PHASORANGLE: "phasorangle",
MADRUWB: "madruwb"
},
ALIGN: {
TOP: "top",
BOTTOM: "bottom",
CENTER: "center",
BASELINE: "baseline",
AXIS: "axis",
LEFT: "left",
RIGHT: "right"
},
LINES: {
NONE: "none",
SOLID: "solid",
DASHED: "dashed"
},
SIDE: {
LEFT: "left",
RIGHT: "right",
LEFTOVERLAP: "leftoverlap",
RIGHTOVERLAP: "rightoverlap"
},
WIDTH: {
AUTO: "auto",
FIT: "fit"
},
ACTIONTYPE: {
TOGGLE: "toggle",
STATUSLINE: "statusline",
TOOLTIP: "tooltip",
INPUT: "input"
},
LENGTH: {
VERYVERYTHINMATHSPACE: "veryverythinmathspace",
VERYTHINMATHSPACE: "verythinmathspace",
THINMATHSPACE: "thinmathspace",
MEDIUMMATHSPACE: "mediummathspace",
THICKMATHSPACE: "thickmathspace",
VERYTHICKMATHSPACE: "verythickmathspace",
VERYVERYTHICKMATHSPACE: "veryverythickmathspace",
NEGATIVEVERYVERYTHINMATHSPACE: "negativeveryverythinmathspace",
NEGATIVEVERYTHINMATHSPACE: "negativeverythinmathspace",
NEGATIVETHINMATHSPACE: "negativethinmathspace",
NEGATIVEMEDIUMMATHSPACE: "negativemediummathspace",
NEGATIVETHICKMATHSPACE: "negativethickmathspace",
NEGATIVEVERYTHICKMATHSPACE: "negativeverythickmathspace",
NEGATIVEVERYVERYTHICKMATHSPACE: "negativeveryverythickmathspace"
},
OVERFLOW: {
LINBREAK: "linebreak",
SCROLL: "scroll",
ELIDE: "elide",
TRUNCATE: "truncate",
SCALE: "scale"
},
UNIT: {
EM: "em",
EX: "ex",
PX: "px",
IN: "in",
CM: "cm",
MM: "mm",
PT: "pt",
PC: "pc"
},
TEXCLASS: {
ORD: 0,
OP: 1,
BIN: 2,
REL: 3,
OPEN: 4,
CLOSE: 5,
PUNCT: 6,
INNER: 7,
VCENTER: 8,
NONE: -1
},
TEXCLASSNAMES: ["ORD", "OP", "BIN", "REL", "OPEN", "CLOSE", "PUNCT", "INNER", "VCENTER"],
skipAttributes: {
texClass:true, useHeight:true, texprimestyle:true
},
copyAttributes: {
displaystyle:1, scriptlevel:1, open:1, close:1, form:1,
actiontype: 1,
fontfamily:true, fontsize:true, fontweight:true, fontstyle:true,
color:true, background:true,
id:true, "class":1, href:true, style:true
},
copyAttributeNames: [
"displaystyle", "scriptlevel", "open", "close", "form", // force these to be copied
"actiontype",
"fontfamily", "fontsize", "fontweight", "fontstyle",
"color", "background",
"id", "class", "href", "style"
],
nocopyAttributes: {
fontfamily: true, fontsize: true, fontweight: true, fontstyle: true,
color: true, background: true,
id: true, 'class': true, href: true, style: true,
xmlns: true
},
Error: function (message,def) {
var mml = this.merror(message),
dir = MathJax.Localization.fontDirection(),
font = MathJax.Localization.fontFamily();
if (def) {mml = mml.With(def)}
if (dir || font) {
mml = this.mstyle(mml);
if (dir) {mml.dir = dir}
if (font) {mml.style.fontFamily = "font-family: "+font}
}
return mml;
}
});
(function (MML) {
MML.mbase = MathJax.Object.Subclass({
type: "base", isToken: false,
defaults: {
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
dir: MML.INHERIT
},
noInherit: {},
noInheritAttribute: {
texClass: true
},
getRemoved: {},
linebreakContainer: false,
Init: function () {
this.data = [];
if (this.inferRow && !(arguments.length === 1 && arguments[0].inferred))
{this.Append(MML.mrow().With({inferred: true, notParent: true}))}
this.Append.apply(this,arguments);
},
With: function (def) {
for (var id in def) {if (def.hasOwnProperty(id)) {this[id] = def[id]}}
return this;
},
Append: function () {
if (this.inferRow && this.data.length) {
this.data[0].Append.apply(this.data[0],arguments);
} else {
for (var i = 0, m = arguments.length; i < m; i++)
{this.SetData(this.data.length,arguments[i])}
}
},
SetData: function (i,item) {
if (item != null) {
if (!(item instanceof MML.mbase))
{item = (this.isToken || this.isChars ? MML.chars(item) : MML.mtext(item))}
item.parent = this;
item.setInherit(this.inheritFromMe ? this : this.inherit);
}
this.data[i] = item;
},
Parent: function () {
var parent = this.parent;
while (parent && parent.notParent) {parent = parent.parent}
return parent;
},
Get: function (name,nodefault,noself) {
if (!noself) {
if (this[name] != null) {return this[name]}
if (this.attr && this.attr[name] != null) {return this.attr[name]}
}
// FIXME: should cache these values and get from cache
// (clear cache when appended to a new object?)
var parent = this.Parent();
if (parent && parent["adjustChild_"+name] != null) {
return (parent["adjustChild_"+name])(this.childPosition(),nodefault);
}
var obj = this.inherit; var root = obj;
while (obj) {
var value = obj[name]; if (value == null && obj.attr) {value = obj.attr[name]}
if (obj.removedStyles && obj.getRemoved[name] && value == null) value = obj.removedStyles[obj.getRemoved[name]];
if (value != null && obj.noInheritAttribute && !obj.noInheritAttribute[name]) {
var noInherit = obj.noInherit[this.type];
if (!(noInherit && noInherit[name])) {return value}
}
root = obj; obj = obj.inherit;
}
if (!nodefault) {
if (this.defaults[name] === MML.AUTO) {return this.autoDefault(name)}
if (this.defaults[name] !== MML.INHERIT && this.defaults[name] != null)
{return this.defaults[name]}
if (root) {return root.defaults[name]}
}
return null;
},
hasValue: function (name) {return (this.Get(name,true) != null)},
getValues: function () {
var values = {};
for (var i = 0, m = arguments.length; i < m; i++)
{values[arguments[i]] = this.Get(arguments[i])}
return values;
},
adjustChild_scriptlevel: function (i,nodef) {return this.Get("scriptlevel",nodef)}, // always inherit from parent
adjustChild_displaystyle: function (i,nodef) {return this.Get("displaystyle",nodef)}, // always inherit from parent
adjustChild_texprimestyle: function (i,nodef) {return this.Get("texprimestyle",nodef)}, // always inherit from parent
childPosition: function () {
var child = this, parent = child.parent;
while (parent.notParent) {child = parent; parent = child.parent}
for (var i = 0, m = parent.data.length; i < m; i++) {if (parent.data[i] === child) {return i}}
return null;
},
setInherit: function (obj) {
if (obj !== this.inherit && this.inherit == null) {
this.inherit = obj;
for (var i = 0, m = this.data.length; i < m; i++) {
if (this.data[i] && this.data[i].setInherit) {this.data[i].setInherit(obj)}
}
}
},
setTeXclass: function (prev) {
this.getPrevClass(prev);
return (typeof(this.texClass) !== "undefined" ? this : prev);
},
getPrevClass: function (prev) {
if (prev) {
this.prevClass = prev.Get("texClass");
this.prevLevel = prev.Get("scriptlevel");
}
},
updateTeXclass: function (core) {
if (core) {
this.prevClass = core.prevClass; delete core.prevClass;
this.prevLevel = core.prevLevel; delete core.prevLevel;
this.texClass = core.Get("texClass");
}
},
texSpacing: function () {
var prev = (this.prevClass != null ? this.prevClass : MML.TEXCLASS.NONE);
var tex = (this.Get("texClass") || MML.TEXCLASS.ORD);
if (prev === MML.TEXCLASS.NONE || tex === MML.TEXCLASS.NONE) {return ""}
if (prev === MML.TEXCLASS.VCENTER) {prev = MML.TEXCLASS.ORD}
if (tex === MML.TEXCLASS.VCENTER) {tex = MML.TEXCLASS.ORD}
var space = this.TEXSPACE[prev][tex];
if ((this.prevLevel > 0 || this.Get("scriptlevel") > 0) && space >= 0) {return ""}
return this.TEXSPACELENGTH[Math.abs(space)];
},
TEXSPACELENGTH:[
"",
MML.LENGTH.THINMATHSPACE,
MML.LENGTH.MEDIUMMATHSPACE,
MML.LENGTH.THICKMATHSPACE
],
// See TeXBook Chapter 18 (p. 170)
TEXSPACE: [
[ 0,-1, 2, 3, 0, 0, 0, 1], // ORD
[-1,-1, 0, 3, 0, 0, 0, 1], // OP
[ 2, 2, 0, 0, 2, 0, 0, 2], // BIN
[ 3, 3, 0, 0, 3, 0, 0, 3], // REL
[ 0, 0, 0, 0, 0, 0, 0, 0], // OPEN
[ 0,-1, 2, 3, 0, 0, 0, 1], // CLOSE
[ 1, 1, 0, 1, 1, 1, 1, 1], // PUNCT
[ 1,-1, 2, 3, 1, 0, 1, 1] // INNER
],
autoDefault: function (name) {return ""},
isSpacelike: function () {return false},
isEmbellished: function () {return false},
Core: function () {return this},
CoreMO: function () {return this},
childIndex: function(child) {
if (child == null) return;
for (var i = 0, m = this.data.length; i < m; i++) if (child === this.data[i]) return i;
},
CoreIndex: function () {
return (this.inferRow ? this.data[0]||this : this).childIndex(this.Core());
},
hasNewline: function () {
if (this.isEmbellished()) {return this.CoreMO().hasNewline()}
if (this.isToken || this.linebreakContainer) {return false}
for (var i = 0, m = this.data.length; i < m; i++) {
if (this.data[i] && this.data[i].hasNewline()) {return true}
}
return false;
},
array: function () {if (this.inferred) {return this.data} else {return [this]}},
toString: function () {return this.type+"("+this.data.join(",")+")"},
getAnnotation: function () {return null}
},{
childrenSpacelike: function () {
for (var i = 0, m = this.data.length; i < m; i++)
{if (!this.data[i].isSpacelike()) {return false}}
return true;
},
childEmbellished: function () {
return (this.data[0] && this.data[0].isEmbellished());
},
childCore: function () {return (this.inferRow && this.data[0] ? this.data[0].Core() : this.data[0])},
childCoreMO: function () {return (this.data[0] ? this.data[0].CoreMO() : null)},
setChildTeXclass: function (prev) {
if (this.data[0]) {
prev = this.data[0].setTeXclass(prev);
this.updateTeXclass(this.data[0]);
}
return prev;
},
setBaseTeXclasses: function (prev) {
this.getPrevClass(prev); this.texClass = null;
if (this.data[0]) {
if (this.isEmbellished() || this.data[0].isa(MML.mi)) {
prev = this.data[0].setTeXclass(prev);
this.updateTeXclass(this.Core());
} else {this.data[0].setTeXclass(); prev = this}
} else {prev = this}
for (var i = 1, m = this.data.length; i < m; i++)
{if (this.data[i]) {this.data[i].setTeXclass()}}
return prev;
},
setSeparateTeXclasses: function (prev) {
this.getPrevClass(prev);
for (var i = 0, m = this.data.length; i < m; i++)
{if (this.data[i]) {this.data[i].setTeXclass()}}
if (this.isEmbellished()) {this.updateTeXclass(this.Core())}
return this;
}
});
MML.mi = MML.mbase.Subclass({
type: "mi", isToken: true,
texClass: MML.TEXCLASS.ORD,
defaults: {
mathvariant: MML.AUTO,
mathsize: MML.INHERIT,
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
dir: MML.INHERIT
},
autoDefault: function (name) {
if (name === "mathvariant") {
var mi = (this.data[0]||"").toString();
return (mi.length === 1 ||
(mi.length === 2 && mi.charCodeAt(0) >= 0xD800 && mi.charCodeAt(0) < 0xDC00) ?
MML.VARIANT.ITALIC : MML.VARIANT.NORMAL);
}
return "";
},
setTeXclass: function (prev) {
this.getPrevClass(prev);
var name = this.data.join("");
if (name.length > 1 && name.match(/^[a-z][a-z0-9]*$/i) &&
this.texClass === MML.TEXCLASS.ORD) {
this.texClass = MML.TEXCLASS.OP;
this.autoOP = true;
}
return this;
}
});
MML.mn = MML.mbase.Subclass({
type: "mn", isToken: true,
texClass: MML.TEXCLASS.ORD,
defaults: {
mathvariant: MML.INHERIT,
mathsize: MML.INHERIT,
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
dir: MML.INHERIT
}
});
MML.mo = MML.mbase.Subclass({
type: "mo", isToken: true,
defaults: {
mathvariant: MML.INHERIT,
mathsize: MML.INHERIT,
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
dir: MML.INHERIT,
form: MML.AUTO,
fence: MML.AUTO,
separator: MML.AUTO,
lspace: MML.AUTO,
rspace: MML.AUTO,
stretchy: MML.AUTO,
symmetric: MML.AUTO,
maxsize: MML.AUTO,
minsize: MML.AUTO,
largeop: MML.AUTO,
movablelimits: MML.AUTO,
accent: MML.AUTO,
linebreak: MML.LINEBREAK.AUTO,
lineleading: MML.INHERIT,
linebreakstyle: MML.AUTO,
linebreakmultchar: MML.INHERIT,
indentalign: MML.INHERIT,
indentshift: MML.INHERIT,
indenttarget: MML.INHERIT,
indentalignfirst: MML.INHERIT,
indentshiftfirst: MML.INHERIT,
indentalignlast: MML.INHERIT,
indentshiftlast: MML.INHERIT,
texClass: MML.AUTO
},
defaultDef: {
form: MML.FORM.INFIX,
fence: false,
separator: false,
lspace: MML.LENGTH.THICKMATHSPACE,
rspace: MML.LENGTH.THICKMATHSPACE,
stretchy: false,
symmetric: false,
maxsize: MML.SIZE.INFINITY,
minsize: '0em', //'1em',
largeop: false,
movablelimits: false,
accent: false,
linebreak: MML.LINEBREAK.AUTO,
lineleading: "1ex",
linebreakstyle: "before",
indentalign: MML.INDENTALIGN.AUTO,
indentshift: "0",
indenttarget: "",
indentalignfirst: MML.INDENTALIGN.INDENTALIGN,
indentshiftfirst: MML.INDENTSHIFT.INDENTSHIFT,
indentalignlast: MML.INDENTALIGN.INDENTALIGN,
indentshiftlast: MML.INDENTSHIFT.INDENTSHIFT,
texClass: MML.TEXCLASS.REL // for MML, but TeX sets ORD explicitly
},
SPACE_ATTR: {lspace: 0x01, rspace: 0x02, form: 0x04},
useMMLspacing: 0x07,
autoDefault: function (name,nodefault) {
var def = this.def;
if (!def) {
if (name === "form") {this.useMMLspacing &= ~this.SPACE_ATTR.form; return this.getForm()}
var mo = this.data.join("");
var forms = [this.Get("form"),MML.FORM.INFIX,MML.FORM.POSTFIX,MML.FORM.PREFIX];
for (var i = 0, m = forms.length; i < m; i++) {
var data = this.OPTABLE[forms[i]][mo];
if (data) {def = this.makeDef(data); break}
}
if (!def) {def = this.CheckRange(mo)}
if (!def && nodefault) {def = {}} else {
if (!def) {def = MathJax.Hub.Insert({},this.defaultDef)}
if (this.parent) {this.def = def} else {def = MathJax.Hub.Insert({},def)}
def.form = forms[0];
}
}
this.useMMLspacing &= ~(this.SPACE_ATTR[name] || 0);
if (def[name] != null) {return def[name]}
else if (!nodefault) {return this.defaultDef[name]}
return "";
},
CheckRange: function (mo) {
var n = mo.charCodeAt(0);
if (n >= 0xD800 && n < 0xDC00) {n = (((n-0xD800)<<10)+(mo.charCodeAt(1)-0xDC00))+0x10000}
for (var i = 0, m = this.RANGES.length; i < m && this.RANGES[i][0] <= n; i++) {
if (n <= this.RANGES[i][1]) {
if (this.RANGES[i][3]) {
var file = MML.optableDir+"/"+this.RANGES[i][3]+".js";
this.RANGES[i][3] = null;
MathJax.Hub.RestartAfter(MathJax.Ajax.Require(file));
}
var data = MML.TEXCLASSNAMES[this.RANGES[i][2]];
data = this.OPTABLE.infix[mo] = MML.mo.OPTYPES[data === "BIN" ? "BIN3" : data];
return this.makeDef(data);
}
}
return null;
},
makeDef: function (data) {
if (data[2] == null) {data[2] = this.defaultDef.texClass}
if (!data[3]) {data[3] = {}}
var def = MathJax.Hub.Insert({},data[3]);
def.lspace = this.SPACE[data[0]]; def.rspace = this.SPACE[data[1]];
def.texClass = data[2];
if (def.texClass === MML.TEXCLASS.REL &&
(this.movablelimits || this.data.join("").match(/^[a-z]+$/i)))
{def.texClass = MML.TEXCLASS.OP} // mark named operators as OP
return def;
},
getForm: function () {
var core = this, parent = this.parent, Parent = this.Parent();
while (Parent && Parent.isEmbellished())
{core = parent; parent = Parent.parent; Parent = Parent.Parent()}
if (parent && parent.type === "mrow" && parent.NonSpaceLength() !== 1) {
if (parent.FirstNonSpace() === core) {return MML.FORM.PREFIX}
if (parent.LastNonSpace() === core) {return MML.FORM.POSTFIX}
}
return MML.FORM.INFIX;
},
isEmbellished: function () {return true},
hasNewline: function () {return (this.Get("linebreak") === MML.LINEBREAK.NEWLINE)},
CoreParent: function () {
var parent = this;
while (parent && parent.isEmbellished() &&
parent.CoreMO() === this && !parent.isa(MML.math)) {parent = parent.Parent()}
return parent;
},
CoreText: function (parent) {
if (!parent) {return ""}
if (parent.isEmbellished()) {return parent.CoreMO().data.join("")}
while ((((parent.isa(MML.mrow) || parent.isa(MML.TeXAtom) ||
parent.isa(MML.mstyle) || parent.isa(MML.mphantom)) &&
parent.data.length === 1) || parent.isa(MML.munderover)) &&
parent.data[0]) {parent = parent.data[0]}
if (!parent.isToken) {return ""} else {return parent.data.join("")}
},
remapChars: {
'*':"\u2217",
'"':"\u2033",
"\u00B0":"\u2218",
"\u00B2":"2",
"\u00B3":"3",
"\u00B4":"\u2032",
"\u00B9":"1"
},
remap: function (text,map) {
text = text.replace(/-/g,"\u2212");
if (map) {
text = text.replace(/'/g,"\u2032").replace(/`/g,"\u2035");
if (text.length === 1) {text = map[text]||text}
}
return text;
},
setTeXclass: function (prev) {
var values = this.getValues("form","lspace","rspace","fence"); // sets useMMLspacing
if (this.useMMLspacing) {this.texClass = MML.TEXCLASS.NONE; return this}
if (values.fence && !this.texClass) {
if (values.form === MML.FORM.PREFIX) {this.texClass = MML.TEXCLASS.OPEN}
if (values.form === MML.FORM.POSTFIX) {this.texClass = MML.TEXCLASS.CLOSE}
}
this.texClass = this.Get("texClass");
if (this.data.join("") === "\u2061") {
// force previous node to be texClass OP, and skip this node
if (prev) {prev.texClass = MML.TEXCLASS.OP; prev.fnOP = true}
this.texClass = this.prevClass = MML.TEXCLASS.NONE;
return prev;
}
return this.adjustTeXclass(prev);
},
adjustTeXclass: function (prev) {
if (this.texClass === MML.TEXCLASS.NONE) {return prev}
if (prev) {
if (prev.autoOP && (this.texClass === MML.TEXCLASS.BIN ||
this.texClass === MML.TEXCLASS.REL))
{prev.texClass = MML.TEXCLASS.ORD}
this.prevClass = prev.texClass || MML.TEXCLASS.ORD;
this.prevLevel = prev.Get("scriptlevel")
} else {this.prevClass = MML.TEXCLASS.NONE}
if (this.texClass === MML.TEXCLASS.BIN &&
(this.prevClass === MML.TEXCLASS.NONE ||
this.prevClass === MML.TEXCLASS.BIN ||
this.prevClass === MML.TEXCLASS.OP ||
this.prevClass === MML.TEXCLASS.REL ||
this.prevClass === MML.TEXCLASS.OPEN ||
this.prevClass === MML.TEXCLASS.PUNCT)) {
this.texClass = MML.TEXCLASS.ORD;
} else if (this.prevClass === MML.TEXCLASS.BIN &&
(this.texClass === MML.TEXCLASS.REL ||
this.texClass === MML.TEXCLASS.CLOSE ||
this.texClass === MML.TEXCLASS.PUNCT)) {
prev.texClass = this.prevClass = MML.TEXCLASS.ORD;
} else if (this.texClass === MML.TEXCLASS.BIN) {
//
// Check if node is the last one in its container since the rule
// above only takes effect if there is a node that follows.
//
var child = this, parent = this.parent;
while (parent && parent.parent && parent.isEmbellished() &&
(parent.data.length === 1 ||
(parent.type !== "mrow" && parent.Core() === child))) // handles msubsup and munderover
{child = parent; parent = parent.parent}
if (parent.data[parent.data.length-1] === child) this.texClass = MML.TEXCLASS.ORD;
}
return this;
}
});
MML.mtext = MML.mbase.Subclass({
type: "mtext", isToken: true,
isSpacelike: function () {return true},
texClass: MML.TEXCLASS.ORD,
defaults: {
mathvariant: MML.INHERIT,
mathsize: MML.INHERIT,
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
dir: MML.INHERIT
}
});
MML.mspace = MML.mbase.Subclass({
type: "mspace", isToken: true,
isSpacelike: function () {return true},
defaults: {
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
width: "0em",
height: "0ex",
depth: "0ex",
linebreak: MML.LINEBREAK.AUTO
},
hasDimAttr: function () {
return (this.hasValue("width") || this.hasValue("height") ||
this.hasValue("depth"));
},
hasNewline: function () {
// The MathML spec says that the linebreak attribute should be ignored
// if any dimensional attribute is set.
return (!this.hasDimAttr() &&
this.Get("linebreak") === MML.LINEBREAK.NEWLINE);
}
});
MML.ms = MML.mbase.Subclass({
type: "ms", isToken: true,
texClass: MML.TEXCLASS.ORD,
defaults: {
mathvariant: MML.INHERIT,
mathsize: MML.INHERIT,
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
dir: MML.INHERIT,
lquote: '"',
rquote: '"'
}
});
MML.mglyph = MML.mbase.Subclass({
type: "mglyph", isToken: true,
texClass: MML.TEXCLASS.ORD,
defaults: {
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
alt: "",
src: "",
width: MML.AUTO,
height: MML.AUTO,
valign: "0em"
}
});
MML.mrow = MML.mbase.Subclass({
type: "mrow",
isSpacelike: MML.mbase.childrenSpacelike,
inferred: false, notParent: false,
isEmbellished: function () {
var isEmbellished = false;
for (var i = 0, m = this.data.length; i < m; i++) {
if (this.data[i] == null) continue;
if (this.data[i].isEmbellished()) {
if (isEmbellished) {return false}
isEmbellished = true; this.core = i;
} else if (!this.data[i].isSpacelike()) {return false}
}
return isEmbellished;
},
NonSpaceLength: function () {
var n = 0;
for (var i = 0, m = this.data.length; i < m; i++)
{if (this.data[i] && !this.data[i].isSpacelike()) {n++}}
return n;
},
FirstNonSpace: function () {
for (var i = 0, m = this.data.length; i < m; i++)
{if (this.data[i] && !this.data[i].isSpacelike()) {return this.data[i]}}
return null;
},
LastNonSpace: function () {
for (var i = this.data.length-1; i >= 0; i--)
{if (this.data[0] && !this.data[i].isSpacelike()) {return this.data[i]}}
return null;
},
Core: function () {
if (!(this.isEmbellished()) || typeof(this.core) === "undefined") {return this}
return this.data[this.core];
},
CoreMO: function () {
if (!(this.isEmbellished()) || typeof(this.core) === "undefined") {return this}
return this.data[this.core].CoreMO();
},
toString: function () {
if (this.inferred) {return '[' + this.data.join(',') + ']'}
return this.SUPER(arguments).toString.call(this);
},
setTeXclass: function (prev) {
var i, m = this.data.length;
if ((this.open || this.close) && (!prev || !prev.fnOP)) {
//
// <mrow> came from \left...\right
// so treat as subexpression (tex class INNER)
//
this.getPrevClass(prev); prev = null;
for (i = 0; i < m; i++)
{if (this.data[i]) {prev = this.data[i].setTeXclass(prev)}}
if (!this.hasOwnProperty("texClass")) this.texClass = MML.TEXCLASS.INNER;
return this;
} else {
//
// Normal <mrow>, so treat as
// thorugh mrow is not there
//
for (i = 0; i < m; i++)
{if (this.data[i]) {prev = this.data[i].setTeXclass(prev)}}
if (this.data[0]) {this.updateTeXclass(this.data[0])}
return prev;
}
},
getAnnotation: function (name) {
if (this.data.length != 1) return null;
return this.data[0].getAnnotation(name);
}
});
MML.mfrac = MML.mbase.Subclass({
type: "mfrac", num: 0, den: 1,
linebreakContainer: true,
isEmbellished: MML.mbase.childEmbellished,
Core: MML.mbase.childCore,
CoreMO: MML.mbase.childCoreMO,
defaults: {
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
linethickness: MML.LINETHICKNESS.MEDIUM,
numalign: MML.ALIGN.CENTER,
denomalign: MML.ALIGN.CENTER,
bevelled: false
},
adjustChild_displaystyle: function (n) {return false},
adjustChild_scriptlevel: function (n) {
var level = this.Get("scriptlevel");
if (!this.Get("displaystyle") || level > 0) {level++}
return level;
},
adjustChild_texprimestyle: function (n) {
if (n == this.den) {return true}
return this.Get("texprimestyle");
},
setTeXclass: MML.mbase.setSeparateTeXclasses
});
MML.msqrt = MML.mbase.Subclass({
type: "msqrt",
inferRow: true,
linebreakContainer: true,
texClass: MML.TEXCLASS.ORD,
setTeXclass: MML.mbase.setSeparateTeXclasses,
adjustChild_texprimestyle: function (n) {return true}
});
MML.mroot = MML.mbase.Subclass({
type: "mroot",
linebreakContainer: true,
texClass: MML.TEXCLASS.ORD,
adjustChild_displaystyle: function (n) {
if (n === 1) {return false}
return this.Get("displaystyle");
},
adjustChild_scriptlevel: function (n) {
var level = this.Get("scriptlevel");
if (n === 1) {level += 2}
return level;
},
adjustChild_texprimestyle: function (n) {
if (n === 0) {return true};
return this.Get("texprimestyle");
},
setTeXclass: MML.mbase.setSeparateTeXclasses
});
MML.mstyle = MML.mbase.Subclass({
type: "mstyle",
isSpacelike: MML.mbase.childrenSpacelike,
isEmbellished: MML.mbase.childEmbellished,
Core: MML.mbase.childCore,
CoreMO: MML.mbase.childCoreMO,
inferRow: true,
defaults: {
scriptlevel: MML.INHERIT,
displaystyle: MML.INHERIT,
scriptsizemultiplier: Math.sqrt(1/2),
scriptminsize: "8pt",
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
dir: MML.INHERIT,
infixlinebreakstyle: MML.LINEBREAKSTYLE.BEFORE,
decimalseparator: "."
},
adjustChild_scriptlevel: function (n) {
var level = this.scriptlevel;
if (level == null) {
level = this.Get("scriptlevel");
} else if (String(level).match(/^ *[-+]/)) {
var LEVEL = this.Get("scriptlevel",null,true);
level = LEVEL + parseInt(level);
}
return level;
},
inheritFromMe: true,
noInherit: {
mpadded: {width: true, height: true, depth: true, lspace: true, voffset: true},
mtable: {width: true, height: true, depth: true, align: true}
},
getRemoved: {fontfamily:"fontFamily", fontweight:"fontWeight", fontstyle:"fontStyle", fontsize:"fontSize"},
setTeXclass: MML.mbase.setChildTeXclass
});
MML.merror = MML.mbase.Subclass({
type: "merror",
inferRow: true,
linebreakContainer: true,
texClass: MML.TEXCLASS.ORD
});
MML.mpadded = MML.mbase.Subclass({
type: "mpadded",
inferRow: true,
isSpacelike: MML.mbase.childrenSpacelike,
isEmbellished: MML.mbase.childEmbellished,
Core: MML.mbase.childCore,
CoreMO: MML.mbase.childCoreMO,
defaults: {
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
width: "",
height: "",
depth: "",
lspace: 0,
voffset: 0
},
setTeXclass: MML.mbase.setChildTeXclass
});
MML.mphantom = MML.mbase.Subclass({
type: "mphantom",
texClass: MML.TEXCLASS.ORD,
inferRow: true,
isSpacelike: MML.mbase.childrenSpacelike,
isEmbellished: MML.mbase.childEmbellished,
Core: MML.mbase.childCore,
CoreMO: MML.mbase.childCoreMO,
setTeXclass: MML.mbase.setChildTeXclass
});
MML.mfenced = MML.mbase.Subclass({
type: "mfenced",
defaults: {
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
open: '(',
close: ')',
separators: ','
},
addFakeNodes: function () {
var values = this.getValues("open","close","separators");
values.open = values.open.replace(/[ \t\n\r]/g,"");
values.close = values.close.replace(/[ \t\n\r]/g,"");
values.separators = values.separators.replace(/[ \t\n\r]/g,"");
//
// Create a fake node for the open item
//
if (values.open !== "") {
this.SetData("open",MML.mo(values.open).With({
fence:true, form:MML.FORM.PREFIX, texClass:MML.TEXCLASS.OPEN
}));
//
// Clear flag for using MML spacing even though form is specified
//
this.data.open.useMMLspacing = 0;
}
//
// Create fake nodes for the separators
//
if (values.separators !== "") {
while (values.separators.length < this.data.length)
{values.separators += values.separators.charAt(values.separators.length-1)}
for (var i = 1, m = this.data.length; i < m; i++) {
if (this.data[i]) {
this.SetData("sep"+i,MML.mo(values.separators.charAt(i-1)).With({separator:true}))
this.data["sep"+i].useMMLspacing = 0;
}
}
}
//
// Create fake node for the close item
//
if (values.close !== "") {
this.SetData("close",MML.mo(values.close).With({
fence:true, form:MML.FORM.POSTFIX, texClass:MML.TEXCLASS.CLOSE
}));
//
// Clear flag for using MML spacing even though form is specified
//
this.data.close.useMMLspacing = 0;
}
},
texClass: MML.TEXCLASS.OPEN,
setTeXclass: function (prev) {
this.addFakeNodes();
this.getPrevClass(prev);
if (this.data.open) {prev = this.data.open.setTeXclass(prev)}
if (this.data[0]) {prev = this.data[0].setTeXclass(prev)}
for (var i = 1, m = this.data.length; i < m; i++) {
if (this.data["sep"+i]) {prev = this.data["sep"+i].setTeXclass(prev)}
if (this.data[i]) {prev = this.data[i].setTeXclass(prev)}
}
if (this.data.close) {prev = this.data.close.setTeXclass(prev)}
this.updateTeXclass(this.data.open);
this.texClass = MML.TEXCLASS.INNER;
return prev;
}
});
MML.menclose = MML.mbase.Subclass({
type: "menclose",
inferRow: true,
linebreakContainer: true,
defaults: {
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
notation: MML.NOTATION.LONGDIV,
texClass: MML.TEXCLASS.ORD
},
setTeXclass: MML.mbase.setSeparateTeXclasses
});
MML.msubsup = MML.mbase.Subclass({
type: "msubsup", base: 0, sub: 1, sup: 2,
isEmbellished: MML.mbase.childEmbellished,
Core: MML.mbase.childCore,
CoreMO: MML.mbase.childCoreMO,
defaults: {
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
subscriptshift: "",
superscriptshift: "",
texClass: MML.AUTO
},
autoDefault: function (name) {
if (name === "texClass")
{return (this.isEmbellished() ? this.CoreMO().Get(name) : MML.TEXCLASS.ORD)}
return 0;
},
adjustChild_displaystyle: function (n) {
if (n > 0) {return false}
return this.Get("displaystyle");
},
adjustChild_scriptlevel: function (n) {
var level = this.Get("scriptlevel");
if (n > 0) {level++}
return level;
},
adjustChild_texprimestyle: function (n) {
if (n === this.sub) {return true}
return this.Get("texprimestyle");
},
setTeXclass: MML.mbase.setBaseTeXclasses
});
MML.msub = MML.msubsup.Subclass({type: "msub"});
MML.msup = MML.msubsup.Subclass({type: "msup", sub:2, sup:1});
MML.mmultiscripts = MML.msubsup.Subclass({
type: "mmultiscripts",
adjustChild_texprimestyle: function (n) {
if (n % 2 === 1) {return true}
return this.Get("texprimestyle");
}
});
MML.mprescripts = MML.mbase.Subclass({type: "mprescripts"});
MML.none = MML.mbase.Subclass({type: "none"});
MML.munderover = MML.mbase.Subclass({
type: "munderover",
base: 0, under: 1, over: 2, sub: 1, sup: 2,
ACCENTS: ["", "accentunder", "accent"],
linebreakContainer: true,
isEmbellished: MML.mbase.childEmbellished,
Core: MML.mbase.childCore,
CoreMO: MML.mbase.childCoreMO,
defaults: {
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
accent: MML.AUTO,
accentunder: MML.AUTO,
align: MML.ALIGN.CENTER,
texClass: MML.AUTO,
subscriptshift: "", // when converted to msubsup by moveablelimits
superscriptshift: "" // when converted to msubsup by moveablelimits
},
autoDefault: function (name) {
if (name === "texClass")
{return (this.isEmbellished() ? this.CoreMO().Get(name) : MML.TEXCLASS.ORD)}
if (name === "accent" && this.data[this.over]) {return this.data[this.over].CoreMO().Get("accent")}
if (name === "accentunder" && this.data[this.under]) {return this.data[this.under].CoreMO().Get("accent")}
return false;
},
adjustChild_displaystyle: function (n) {
if (n > 0) {return false}
return this.Get("displaystyle");
},
adjustChild_scriptlevel: function (n) {
var level = this.Get("scriptlevel");
var force = (this.data[this.base] && !this.Get("displaystyle") &&
this.data[this.base].CoreMO().Get("movablelimits"));
if (n == this.under && (force || !this.Get("accentunder"))) {level++}
if (n == this.over && (force || !this.Get("accent"))) {level++}
return level;
},
adjustChild_texprimestyle: function (n) {
if (n === this.base && this.data[this.over]) {return true}
return this.Get("texprimestyle");
},
setTeXclass: MML.mbase.setBaseTeXclasses
});
MML.munder = MML.munderover.Subclass({type: "munder"});
MML.mover = MML.munderover.Subclass({
type: "mover", over: 1, under: 2, sup: 1, sub: 2,
ACCENTS: ["", "accent", "accentunder"]
});
MML.mtable = MML.mbase.Subclass({
type: "mtable",
defaults: {
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
align: MML.ALIGN.AXIS,
rowalign: MML.ALIGN.BASELINE,
columnalign: MML.ALIGN.CENTER,
groupalign: "{left}",
alignmentscope: true,
columnwidth: MML.WIDTH.AUTO,
width: MML.WIDTH.AUTO,
rowspacing: "1ex",
columnspacing: ".8em",
rowlines: MML.LINES.NONE,
columnlines: MML.LINES.NONE,
frame: MML.LINES.NONE,
framespacing: "0.4em 0.5ex",
equalrows: false,
equalcolumns: false,
displaystyle: false,
side: MML.SIDE.RIGHT,
minlabelspacing: "0.8em",
texClass: MML.TEXCLASS.ORD,
useHeight: 1
},
adjustChild_displaystyle: function () {
return (this.displaystyle != null ? this.displaystyle : this.defaults.displaystyle);
},
inheritFromMe: true,
noInherit: {
mover: {align: true},
munder: {align: true},
munderover: {align: true},
mtable: {
align: true, rowalign: true, columnalign: true, groupalign: true,
alignmentscope: true, columnwidth: true, width: true, rowspacing: true,
columnspacing: true, rowlines: true, columnlines: true, frame: true,
framespacing: true, equalrows: true, equalcolumns: true, displaystyle: true,
side: true, minlabelspacing: true, texClass: true, useHeight: 1
}
},
linebreakContainer: true,
Append: function () {
for (var i = 0, m = arguments.length; i < m; i++) {
if (!((arguments[i] instanceof MML.mtr) ||
(arguments[i] instanceof MML.mlabeledtr))) {arguments[i] = MML.mtr(arguments[i])}
}
this.SUPER(arguments).Append.apply(this,arguments);
},
setTeXclass: MML.mbase.setSeparateTeXclasses
});
MML.mtr = MML.mbase.Subclass({
type: "mtr",
defaults: {
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
rowalign: MML.INHERIT,
columnalign: MML.INHERIT,
groupalign: MML.INHERIT
},
inheritFromMe: true,
noInherit: {
mrow: {rowalign: true, columnalign: true, groupalign: true},
mtable: {rowalign: true, columnalign: true, groupalign: true}
},
linebreakContainer: true,
Append: function () {
for (var i = 0, m = arguments.length; i < m; i++) {
if (!(arguments[i] instanceof MML.mtd)) {arguments[i] = MML.mtd(arguments[i])}
}
this.SUPER(arguments).Append.apply(this,arguments);
},
setTeXclass: MML.mbase.setSeparateTeXclasses
});
MML.mtd = MML.mbase.Subclass({
type: "mtd",
inferRow: true,
linebreakContainer: true,
isEmbellished: MML.mbase.childEmbellished,
Core: MML.mbase.childCore,
CoreMO: MML.mbase.childCoreMO,
defaults: {
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
rowspan: 1,
columnspan: 1,
rowalign: MML.INHERIT,
columnalign: MML.INHERIT,
groupalign: MML.INHERIT
},
setTeXclass: MML.mbase.setSeparateTeXclasses
});
MML.maligngroup = MML.mbase.Subclass({
type: "maligngroup",
isSpacelike: function () {return true},
defaults: {
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
groupalign: MML.INHERIT
},
inheritFromMe: true,
noInherit: {
mrow: {groupalign: true},
mtable: {groupalign: true}
}
});
MML.malignmark = MML.mbase.Subclass({
type: "malignmark",
defaults: {
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
edge: MML.SIDE.LEFT
},
isSpacelike: function () {return true}
});
MML.mlabeledtr = MML.mtr.Subclass({
type: "mlabeledtr"
});
MML.maction = MML.mbase.Subclass({
type: "maction",
defaults: {
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
actiontype: MML.ACTIONTYPE.TOGGLE,
selection: 1
},
selected: function () {return this.data[this.Get("selection")-1] || MML.NULL},
isEmbellished: function () {return this.selected().isEmbellished()},
isSpacelike: function () {return this.selected().isSpacelike()},
Core: function () {return this.selected().Core()},
CoreMO: function () {return this.selected().CoreMO()},
setTeXclass: function (prev) {
if (this.Get("actiontype") === MML.ACTIONTYPE.TOOLTIP && this.data[1]) {
// Make sure tooltip has proper spacing when typeset (see issue #412)
this.data[1].setTeXclass();
}
var selected = this.selected();
prev = selected.setTeXclass(prev);
this.updateTeXclass(selected);
return prev;
}
});
MML.semantics = MML.mbase.Subclass({
type: "semantics", notParent: true,
isEmbellished: MML.mbase.childEmbellished,
Core: MML.mbase.childCore,
CoreMO: MML.mbase.childCoreMO,
defaults: {
definitionURL: null,
encoding: null
},
setTeXclass: MML.mbase.setChildTeXclass,
getAnnotation: function (name) {
var encodingList = MathJax.Hub.config.MathMenu.semanticsAnnotations[name];
if (encodingList) {
for (var i = 0, m = this.data.length; i < m; i++) {
var encoding = this.data[i].Get("encoding");
if (encoding) {
for (var j = 0, n = encodingList.length; j < n; j++) {
if (encodingList[j] === encoding) return this.data[i];
}
}
}
}
return null;
}
});
MML.annotation = MML.mbase.Subclass({
type: "annotation", isChars: true,
linebreakContainer: true,
defaults: {
definitionURL: null,
encoding: null,
cd: "mathmlkeys",
name: "",
src: null
}
});
MML["annotation-xml"] = MML.mbase.Subclass({
type: "annotation-xml",
linebreakContainer: true,
defaults: {
definitionURL: null,
encoding: null,
cd: "mathmlkeys",
name: "",
src: null
}
});
MML.math = MML.mstyle.Subclass({
type: "math",
defaults: {
mathvariant: MML.VARIANT.NORMAL,
mathsize: MML.SIZE.NORMAL,
mathcolor: "", // should be "black", but allow it to inherit from surrounding text
mathbackground: MML.COLOR.TRANSPARENT,
dir: "ltr",
scriptlevel: 0,
displaystyle: MML.AUTO,
display: "inline",
maxwidth: "",
overflow: MML.OVERFLOW.LINEBREAK,
altimg: "",
'altimg-width': "",
'altimg-height': "",
'altimg-valign': "",
alttext: "",
cdgroup: "",
scriptsizemultiplier: Math.sqrt(1/2),
scriptminsize: "8px", // should be 8pt, but that's too big
infixlinebreakstyle: MML.LINEBREAKSTYLE.BEFORE,
lineleading: "1ex",
indentshift: "auto", // use user configuration
indentalign: MML.INDENTALIGN.AUTO,
indentalignfirst: MML.INDENTALIGN.INDENTALIGN,
indentshiftfirst: MML.INDENTSHIFT.INDENTSHIFT,
indentalignlast: MML.INDENTALIGN.INDENTALIGN,
indentshiftlast: MML.INDENTSHIFT.INDENTSHIFT,
decimalseparator: ".",
texprimestyle: false // is it in TeX's C' style?
},
autoDefault: function (name) {
if (name === "displaystyle") {return this.Get("display") === "block"}
return "";
},
linebreakContainer: true,
setTeXclass: MML.mbase.setChildTeXclass,
getAnnotation: function (name) {
if (this.data.length != 1) return null;
return this.data[0].getAnnotation(name);
}
});
MML.chars = MML.mbase.Subclass({
type: "chars",
Append: function () {this.data.push.apply(this.data,arguments)},
value: function () {return this.data.join("")},
toString: function () {return this.data.join("")}
});
MML.entity = MML.mbase.Subclass({
type: "entity",
Append: function () {this.data.push.apply(this.data,arguments)},
value: function () {
if (this.data[0].substr(0,2) === "#x") {return parseInt(this.data[0].substr(2),16)}
else if (this.data[0].substr(0,1) === "#") {return parseInt(this.data[0].substr(1))}
else {return 0} // FIXME: look up named entities from table
},
toString: function () {
var n = this.value();
if (n <= 0xFFFF) {return String.fromCharCode(n)}
n -= 0x10000;
return String.fromCharCode((n>>10)+0xD800)
+ String.fromCharCode((n&0x3FF)+0xDC00);
}
});
MML.xml = MML.mbase.Subclass({
type: "xml",
Init: function () {
this.div = document.createElement("div");
return this.SUPER(arguments).Init.apply(this,arguments);
},
Append: function () {
for (var i = 0, m = arguments.length; i < m; i++) {
var node = this.Import(arguments[i]);
this.data.push(node);
this.div.appendChild(node);
}
},
Import: function (node) {
if (document.importNode) {return document.importNode(node,true)}
//
// IE < 9 doesn't have importNode, so fake it.
//
var nNode, i, m;
if (node.nodeType === 1) { // ELEMENT_NODE
nNode = document.createElement(node.nodeName);
for (i = 0, m = node.attributes.length; i < m; i++) {
var attribute = node.attributes[i];
if (attribute.specified && attribute.nodeValue != null && attribute.nodeValue != '')
{nNode.setAttribute(attribute.nodeName,attribute.nodeValue)}
if (attribute.nodeName === "style") {nNode.style.cssText = attribute.nodeValue}
}
if (node.className) {nNode.className = node.className}
} else if (node.nodeType === 3 || node.nodeType === 4) { // TEXT_NODE or CDATA_SECTION_NODE
nNode = document.createTextNode(node.nodeValue);
} else if (node.nodeType === 8) { // COMMENT_NODE
nNode = document.createComment(node.nodeValue);
} else {
return document.createTextNode('');
}
for (i = 0, m = node.childNodes.length; i < m; i++)
{nNode.appendChild(this.Import(node.childNodes[i]))}
return nNode;
},
value: function () {return this.div},
toString: function () {return this.div.innerHTML}
});
MML.TeXAtom = MML.mbase.Subclass({
type: "texatom",
linebreakContainer: true,
inferRow: true, notParent: true,
texClass: MML.TEXCLASS.ORD,
Core: MML.mbase.childCore,
CoreMO: MML.mbase.childCoreMO,
isEmbellished: MML.mbase.childEmbellished,
setTeXclass: function (prev) {
this.data[0].setTeXclass();
return this.adjustTeXclass(prev);
},
adjustTeXclass: MML.mo.prototype.adjustTeXclass
});
MML.NULL = MML.mbase().With({type:"null"});
var TEXCLASS = MML.TEXCLASS;
var MO = {
ORD: [0,0,TEXCLASS.ORD],
ORD11: [1,1,TEXCLASS.ORD],
ORD21: [2,1,TEXCLASS.ORD],
ORD02: [0,2,TEXCLASS.ORD],
ORD55: [5,5,TEXCLASS.ORD],
OP: [1,2,TEXCLASS.OP,{largeop: true, movablelimits: true, symmetric: true}],
OPFIXED: [1,2,TEXCLASS.OP,{largeop: true, movablelimits: true}],
INTEGRAL: [0,1,TEXCLASS.OP,{largeop: true, symmetric: true}],
INTEGRAL2: [1,2,TEXCLASS.OP,{largeop: true, symmetric: true}],
BIN3: [3,3,TEXCLASS.BIN],
BIN4: [4,4,TEXCLASS.BIN],
BIN01: [0,1,TEXCLASS.BIN],
BIN5: [5,5,TEXCLASS.BIN],
TALLBIN: [4,4,TEXCLASS.BIN,{stretchy: true}],
BINOP: [4,4,TEXCLASS.BIN,{largeop: true, movablelimits: true}],
REL: [5,5,TEXCLASS.REL],
REL1: [1,1,TEXCLASS.REL,{stretchy: true}],
REL4: [4,4,TEXCLASS.REL],
RELSTRETCH: [5,5,TEXCLASS.REL,{stretchy: true}],
RELACCENT: [5,5,TEXCLASS.REL,{accent: true}],
WIDEREL: [5,5,TEXCLASS.REL,{accent: true, stretchy: true}],
OPEN: [0,0,TEXCLASS.OPEN,{fence: true, stretchy: true, symmetric: true}],
CLOSE: [0,0,TEXCLASS.CLOSE,{fence: true, stretchy: true, symmetric: true}],
INNER: [0,0,TEXCLASS.INNER],
PUNCT: [0,3,TEXCLASS.PUNCT],
ACCENT: [0,0,TEXCLASS.ORD,{accent: true}],
WIDEACCENT: [0,0,TEXCLASS.ORD,{accent: true, stretchy: true}]
};
MML.mo.Augment({
SPACE: [
'0em',
'0.1111em',
'0.1667em',
'0.2222em',
'0.2667em',
'0.3333em'
],
RANGES: [
[0x20,0x7F,TEXCLASS.REL,"BasicLatin"],
[0xA0,0xFF,TEXCLASS.ORD,"Latin1Supplement"],
[0x100,0x17F,TEXCLASS.ORD],
[0x180,0x24F,TEXCLASS.ORD],
[0x2B0,0x2FF,TEXCLASS.ORD,"SpacingModLetters"],
[0x300,0x36F,TEXCLASS.ORD,"CombDiacritMarks"],
[0x370,0x3FF,TEXCLASS.ORD,"GreekAndCoptic"],
[0x1E00,0x1EFF,TEXCLASS.ORD],
[0x2000,0x206F,TEXCLASS.PUNCT,"GeneralPunctuation"],
[0x2070,0x209F,TEXCLASS.ORD],
[0x20A0,0x20CF,TEXCLASS.ORD],
[0x20D0,0x20FF,TEXCLASS.ORD,"CombDiactForSymbols"],
[0x2100,0x214F,TEXCLASS.ORD,"LetterlikeSymbols"],
[0x2150,0x218F,TEXCLASS.ORD],
[0x2190,0x21FF,TEXCLASS.REL,"Arrows"],
[0x2200,0x22FF,TEXCLASS.BIN,"MathOperators"],
[0x2300,0x23FF,TEXCLASS.ORD,"MiscTechnical"],
[0x2460,0x24FF,TEXCLASS.ORD],
[0x2500,0x259F,TEXCLASS.ORD],
[0x25A0,0x25FF,TEXCLASS.ORD,"GeometricShapes"],
[0x2700,0x27BF,TEXCLASS.ORD,"Dingbats"],
[0x27C0,0x27EF,TEXCLASS.ORD,"MiscMathSymbolsA"],
[0x27F0,0x27FF,TEXCLASS.REL,"SupplementalArrowsA"],
[0x2900,0x297F,TEXCLASS.REL,"SupplementalArrowsB"],
[0x2980,0x29FF,TEXCLASS.ORD,"MiscMathSymbolsB"],
[0x2A00,0x2AFF,TEXCLASS.BIN,"SuppMathOperators"],
[0x2B00,0x2BFF,TEXCLASS.ORD,"MiscSymbolsAndArrows"],
[0x1D400,0x1D7FF,TEXCLASS.ORD]
],
OPTABLE: {
prefix: {
'\u2200': MO.ORD21, // for all
'\u2202': MO.ORD21, // partial differential
'\u2203': MO.ORD21, // there exists
'\u2207': MO.ORD21, // nabla
'\u220F': MO.OP, // n-ary product
'\u2210': MO.OP, // n-ary coproduct
'\u2211': MO.OP, // n-ary summation
'\u2212': MO.BIN01, // minus sign
'\u2213': MO.BIN01, // minus-or-plus sign
'\u221A': [1,1,TEXCLASS.ORD,{stretchy: true}], // square root
'\u2220': MO.ORD, // angle
'\u222B': MO.INTEGRAL, // integral
'\u222E': MO.INTEGRAL, // contour integral
'\u22C0': MO.OP, // n-ary logical and
'\u22C1': MO.OP, // n-ary logical or
'\u22C2': MO.OP, // n-ary intersection
'\u22C3': MO.OP, // n-ary union
'\u2308': MO.OPEN, // left ceiling
'\u230A': MO.OPEN, // left floor
'\u27E8': MO.OPEN, // mathematical left angle bracket
'\u27EE': MO.OPEN, // mathematical left flattened parenthesis
'\u2A00': MO.OP, // n-ary circled dot operator
'\u2A01': MO.OP, // n-ary circled plus operator
'\u2A02': MO.OP, // n-ary circled times operator
'\u2A04': MO.OP, // n-ary union operator with plus
'\u2A06': MO.OP, // n-ary square union operator
'\u00AC': MO.ORD21, // not sign
'\u00B1': MO.BIN01, // plus-minus sign
'(': MO.OPEN, // left parenthesis
'+': MO.BIN01, // plus sign
'-': MO.BIN01, // hyphen-minus
'[': MO.OPEN, // left square bracket
'{': MO.OPEN, // left curly bracket
'|': MO.OPEN // vertical line
},
postfix: {
'!': [1,0,TEXCLASS.CLOSE], // exclamation mark
'&': MO.ORD, // ampersand
'\u2032': MO.ORD02, // prime
'\u203E': MO.WIDEACCENT, // overline
'\u2309': MO.CLOSE, // right ceiling
'\u230B': MO.CLOSE, // right floor
'\u23DE': MO.WIDEACCENT, // top curly bracket
'\u23DF': MO.WIDEACCENT, // bottom curly bracket
'\u266D': MO.ORD02, // music flat sign
'\u266E': MO.ORD02, // music natural sign
'\u266F': MO.ORD02, // music sharp sign
'\u27E9': MO.CLOSE, // mathematical right angle bracket
'\u27EF': MO.CLOSE, // mathematical right flattened parenthesis
'\u02C6': MO.WIDEACCENT, // modifier letter circumflex accent
'\u02C7': MO.WIDEACCENT, // caron
'\u02C9': MO.WIDEACCENT, // modifier letter macron
'\u02CA': MO.ACCENT, // modifier letter acute accent
'\u02CB': MO.ACCENT, // modifier letter grave accent
'\u02D8': MO.ACCENT, // breve
'\u02D9': MO.ACCENT, // dot above
'\u02DC': MO.WIDEACCENT, // small tilde
'\u0302': MO.WIDEACCENT, // combining circumflex accent
'\u00A8': MO.ACCENT, // diaeresis
'\u00AF': MO.WIDEACCENT, // macron
')': MO.CLOSE, // right parenthesis
']': MO.CLOSE, // right square bracket
'^': MO.WIDEACCENT, // circumflex accent
'_': MO.WIDEACCENT, // low line
'`': MO.ACCENT, // grave accent
'|': MO.CLOSE, // vertical line
'}': MO.CLOSE, // right curly bracket
'~': MO.WIDEACCENT // tilde
},
infix: {
'': MO.ORD, // empty <mo>
'%': [3,3,TEXCLASS.ORD], // percent sign
'\u2022': MO.BIN4, // bullet
'\u2026': MO.INNER, // horizontal ellipsis
'\u2044': MO.TALLBIN, // fraction slash
'\u2061': MO.ORD, // function application
'\u2062': MO.ORD, // invisible times
'\u2063': [0,0,TEXCLASS.ORD,{linebreakstyle:"after", separator: true}], // invisible separator
'\u2064': MO.ORD, // invisible plus
'\u2190': MO.WIDEREL, // leftwards arrow
'\u2191': MO.RELSTRETCH, // upwards arrow
'\u2192': MO.WIDEREL, // rightwards arrow
'\u2193': MO.RELSTRETCH, // downwards arrow
'\u2194': MO.WIDEREL, // left right arrow
'\u2195': MO.RELSTRETCH, // up down arrow
'\u2196': MO.RELSTRETCH, // north west arrow
'\u2197': MO.RELSTRETCH, // north east arrow
'\u2198': MO.RELSTRETCH, // south east arrow
'\u2199': MO.RELSTRETCH, // south west arrow
'\u21A6': MO.WIDEREL, // rightwards arrow from bar
'\u21A9': MO.WIDEREL, // leftwards arrow with hook
'\u21AA': MO.WIDEREL, // rightwards arrow with hook
'\u21BC': MO.WIDEREL, // leftwards harpoon with barb upwards
'\u21BD': MO.WIDEREL, // leftwards harpoon with barb downwards
'\u21C0': MO.WIDEREL, // rightwards harpoon with barb upwards
'\u21C1': MO.WIDEREL, // rightwards harpoon with barb downwards
'\u21CC': MO.WIDEREL, // rightwards harpoon over leftwards harpoon
'\u21D0': MO.WIDEREL, // leftwards double arrow
'\u21D1': MO.RELSTRETCH, // upwards double arrow
'\u21D2': MO.WIDEREL, // rightwards double arrow
'\u21D3': MO.RELSTRETCH, // downwards double arrow
'\u21D4': MO.WIDEREL, // left right double arrow
'\u21D5': MO.RELSTRETCH, // up down double arrow
'\u2208': MO.REL, // element of
'\u2209': MO.REL, // not an element of
'\u220B': MO.REL, // contains as member
'\u2212': MO.BIN4, // minus sign
'\u2213': MO.BIN4, // minus-or-plus sign
'\u2215': MO.TALLBIN, // division slash
'\u2216': MO.BIN4, // set minus
'\u2217': MO.BIN4, // asterisk operator
'\u2218': MO.BIN4, // ring operator
'\u2219': MO.BIN4, // bullet operator
'\u221D': MO.REL, // proportional to
'\u2223': MO.REL, // divides
'\u2225': MO.REL, // parallel to
'\u2227': MO.BIN4, // logical and
'\u2228': MO.BIN4, // logical or
'\u2229': MO.BIN4, // intersection
'\u222A': MO.BIN4, // union
'\u223C': MO.REL, // tilde operator
'\u2240': MO.BIN4, // wreath product
'\u2243': MO.REL, // asymptotically equal to
'\u2245': MO.REL, // approximately equal to
'\u2248': MO.REL, // almost equal to
'\u224D': MO.REL, // equivalent to
'\u2250': MO.REL, // approaches the limit
'\u2260': MO.REL, // not equal to
'\u2261': MO.REL, // identical to
'\u2264': MO.REL, // less-than or equal to
'\u2265': MO.REL, // greater-than or equal to
'\u226A': MO.REL, // much less-than
'\u226B': MO.REL, // much greater-than
'\u227A': MO.REL, // precedes
'\u227B': MO.REL, // succeeds
'\u2282': MO.REL, // subset of
'\u2283': MO.REL, // superset of
'\u2286': MO.REL, // subset of or equal to
'\u2287': MO.REL, // superset of or equal to
'\u228E': MO.BIN4, // multiset union
'\u2291': MO.REL, // square image of or equal to
'\u2292': MO.REL, // square original of or equal to
'\u2293': MO.BIN4, // square cap
'\u2294': MO.BIN4, // square cup
'\u2295': MO.BIN4, // circled plus
'\u2296': MO.BIN4, // circled minus
'\u2297': MO.BIN4, // circled times
'\u2298': MO.BIN4, // circled division slash
'\u2299': MO.BIN4, // circled dot operator
'\u22A2': MO.REL, // right tack
'\u22A3': MO.REL, // left tack
'\u22A4': MO.ORD55, // down tack
'\u22A5': MO.REL, // up tack
'\u22A8': MO.REL, // true
'\u22C4': MO.BIN4, // diamond operator
'\u22C5': MO.BIN4, // dot operator
'\u22C6': MO.BIN4, // star operator
'\u22C8': MO.REL, // bowtie
'\u22EE': MO.ORD55, // vertical ellipsis
'\u22EF': MO.INNER, // midline horizontal ellipsis
'\u22F1': [5,5,TEXCLASS.INNER], // down right diagonal ellipsis
'\u25B3': MO.BIN4, // white up-pointing triangle
'\u25B5': MO.BIN4, // white up-pointing small triangle
'\u25B9': MO.BIN4, // white right-pointing small triangle
'\u25BD': MO.BIN4, // white down-pointing triangle
'\u25BF': MO.BIN4, // white down-pointing small triangle
'\u25C3': MO.BIN4, // white left-pointing small triangle
'\u2758': MO.REL, // light vertical bar
'\u27F5': MO.WIDEREL, // long leftwards arrow
'\u27F6': MO.WIDEREL, // long rightwards arrow
'\u27F7': MO.WIDEREL, // long left right arrow
'\u27F8': MO.WIDEREL, // long leftwards double arrow
'\u27F9': MO.WIDEREL, // long rightwards double arrow
'\u27FA': MO.WIDEREL, // long left right double arrow
'\u27FC': MO.WIDEREL, // long rightwards arrow from bar
'\u2A2F': MO.BIN4, // vector or cross product
'\u2A3F': MO.BIN4, // amalgamation or coproduct
'\u2AAF': MO.REL, // precedes above single-line equals sign
'\u2AB0': MO.REL, // succeeds above single-line equals sign
'\u00B1': MO.BIN4, // plus-minus sign
'\u00B7': MO.BIN4, // middle dot
'\u00D7': MO.BIN4, // multiplication sign
'\u00F7': MO.BIN4, // division sign
'*': MO.BIN3, // asterisk
'+': MO.BIN4, // plus sign
',': [0,3,TEXCLASS.PUNCT,{linebreakstyle:"after", separator: true}], // comma
'-': MO.BIN4, // hyphen-minus
'.': [3,3,TEXCLASS.ORD], // full stop
'/': MO.ORD11, // solidus
':': [1,2,TEXCLASS.REL], // colon
';': [0,3,TEXCLASS.PUNCT,{linebreakstyle:"after", separator: true}], // semicolon
'<': MO.REL, // less-than sign
'=': MO.REL, // equals sign
'>': MO.REL, // greater-than sign
'?': [1,1,TEXCLASS.CLOSE], // question mark
'\\': MO.ORD, // reverse solidus
'^': MO.ORD11, // circumflex accent
'_': MO.ORD11, // low line
'|': [2,2,TEXCLASS.ORD,{fence: true, stretchy: true, symmetric: true}], // vertical line
'#': MO.ORD, // #
'$': MO.ORD, // $
'\u002E': [0,3,TEXCLASS.PUNCT,{separator: true}], // \ldotp
'\u02B9': MO.ORD, // prime
'\u0300': MO.ACCENT, // \grave
'\u0301': MO.ACCENT, // \acute
'\u0303': MO.WIDEACCENT, // \tilde
'\u0304': MO.ACCENT, // \bar
'\u0306': MO.ACCENT, // \breve
'\u0307': MO.ACCENT, // \dot
'\u0308': MO.ACCENT, // \ddot
'\u030C': MO.ACCENT, // \check
'\u0332': MO.WIDEACCENT, // horizontal line
'\u0338': MO.REL4, // \not
'\u2015': [0,0,TEXCLASS.ORD,{stretchy: true}], // horizontal line
'\u2017': [0,0,TEXCLASS.ORD,{stretchy: true}], // horizontal line
'\u2020': MO.BIN3, // \dagger
'\u2021': MO.BIN3, // \ddagger
'\u20D7': MO.ACCENT, // \vec
'\u2111': MO.ORD, // \Im
'\u2113': MO.ORD, // \ell
'\u2118': MO.ORD, // \wp
'\u211C': MO.ORD, // \Re
'\u2205': MO.ORD, // \emptyset
'\u221E': MO.ORD, // \infty
'\u2305': MO.BIN3, // barwedge
'\u2306': MO.BIN3, // doublebarwedge
'\u2322': MO.REL4, // \frown
'\u2323': MO.REL4, // \smile
'\u2329': MO.OPEN, // langle
'\u232A': MO.CLOSE, // rangle
'\u23AA': MO.ORD, // \bracevert
'\u23AF': [0,0,TEXCLASS.ORD,{stretchy: true}], // \underline
'\u23B0': MO.OPEN, // \lmoustache
'\u23B1': MO.CLOSE, // \rmoustache
'\u2500': MO.ORD, // horizontal line
'\u25EF': MO.BIN3, // \bigcirc
'\u2660': MO.ORD, // \spadesuit
'\u2661': MO.ORD, // \heartsuit
'\u2662': MO.ORD, // \diamondsuit
'\u2663': MO.ORD, // \clubsuit
'\u3008': MO.OPEN, // langle
'\u3009': MO.CLOSE, // rangle
'\uFE37': MO.WIDEACCENT, // horizontal brace down
'\uFE38': MO.WIDEACCENT // horizontal brace up
}
}
},{
OPTYPES: MO
});
//
// These are not in the W3C table, but FF works this way,
// and it makes sense, so add it here
//
var OPTABLE = MML.mo.prototype.OPTABLE;
OPTABLE.infix["^"] = MO.WIDEREL;
OPTABLE.infix["_"] = MO.WIDEREL;
OPTABLE.prefix["\u2223"] = MO.OPEN;
OPTABLE.prefix["\u2225"] = MO.OPEN;
OPTABLE.postfix["\u2223"] = MO.CLOSE;
OPTABLE.postfix["\u2225"] = MO.CLOSE;
})(MathJax.ElementJax.mml);
MathJax.ElementJax.mml.loadComplete("jax.js");
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/Arrows.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
infix: {
'\u219A': MO.RELACCENT, // leftwards arrow with stroke
'\u219B': MO.RELACCENT, // rightwards arrow with stroke
'\u219C': MO.WIDEREL, // leftwards wave arrow
'\u219D': MO.WIDEREL, // rightwards wave arrow
'\u219E': MO.WIDEREL, // leftwards two headed arrow
'\u219F': MO.WIDEREL, // upwards two headed arrow
'\u21A0': MO.WIDEREL, // rightwards two headed arrow
'\u21A1': MO.RELSTRETCH, // downwards two headed arrow
'\u21A2': MO.WIDEREL, // leftwards arrow with tail
'\u21A3': MO.WIDEREL, // rightwards arrow with tail
'\u21A4': MO.WIDEREL, // leftwards arrow from bar
'\u21A5': MO.RELSTRETCH, // upwards arrow from bar
'\u21A7': MO.RELSTRETCH, // downwards arrow from bar
'\u21A8': MO.RELSTRETCH, // up down arrow with base
'\u21AB': MO.WIDEREL, // leftwards arrow with loop
'\u21AC': MO.WIDEREL, // rightwards arrow with loop
'\u21AD': MO.WIDEREL, // left right wave arrow
'\u21AE': MO.RELACCENT, // left right arrow with stroke
'\u21AF': MO.RELSTRETCH, // downwards zigzag arrow
'\u21B0': MO.RELSTRETCH, // upwards arrow with tip leftwards
'\u21B1': MO.RELSTRETCH, // upwards arrow with tip rightwards
'\u21B2': MO.RELSTRETCH, // downwards arrow with tip leftwards
'\u21B3': MO.RELSTRETCH, // downwards arrow with tip rightwards
'\u21B4': MO.RELSTRETCH, // rightwards arrow with corner downwards
'\u21B5': MO.RELSTRETCH, // downwards arrow with corner leftwards
'\u21B6': MO.RELACCENT, // anticlockwise top semicircle arrow
'\u21B7': MO.RELACCENT, // clockwise top semicircle arrow
'\u21B8': MO.REL, // north west arrow to long bar
'\u21B9': MO.WIDEREL, // leftwards arrow to bar over rightwards arrow to bar
'\u21BA': MO.REL, // anticlockwise open circle arrow
'\u21BB': MO.REL, // clockwise open circle arrow
'\u21BE': MO.RELSTRETCH, // upwards harpoon with barb rightwards
'\u21BF': MO.RELSTRETCH, // upwards harpoon with barb leftwards
'\u21C2': MO.RELSTRETCH, // downwards harpoon with barb rightwards
'\u21C3': MO.RELSTRETCH, // downwards harpoon with barb leftwards
'\u21C4': MO.WIDEREL, // rightwards arrow over leftwards arrow
'\u21C5': MO.RELSTRETCH, // upwards arrow leftwards of downwards arrow
'\u21C6': MO.WIDEREL, // leftwards arrow over rightwards arrow
'\u21C7': MO.WIDEREL, // leftwards paired arrows
'\u21C8': MO.RELSTRETCH, // upwards paired arrows
'\u21C9': MO.WIDEREL, // rightwards paired arrows
'\u21CA': MO.RELSTRETCH, // downwards paired arrows
'\u21CB': MO.WIDEREL, // leftwards harpoon over rightwards harpoon
'\u21CD': MO.RELACCENT, // leftwards double arrow with stroke
'\u21CE': MO.RELACCENT, // left right double arrow with stroke
'\u21CF': MO.RELACCENT, // rightwards double arrow with stroke
'\u21D6': MO.RELSTRETCH, // north west double arrow
'\u21D7': MO.RELSTRETCH, // north east double arrow
'\u21D8': MO.RELSTRETCH, // south east double arrow
'\u21D9': MO.RELSTRETCH, // south west double arrow
'\u21DA': MO.WIDEREL, // leftwards triple arrow
'\u21DB': MO.WIDEREL, // rightwards triple arrow
'\u21DC': MO.WIDEREL, // leftwards squiggle arrow
'\u21DD': MO.WIDEREL, // rightwards squiggle arrow
'\u21DE': MO.REL, // upwards arrow with double stroke
'\u21DF': MO.REL, // downwards arrow with double stroke
'\u21E0': MO.WIDEREL, // leftwards dashed arrow
'\u21E1': MO.RELSTRETCH, // upwards dashed arrow
'\u21E2': MO.WIDEREL, // rightwards dashed arrow
'\u21E3': MO.RELSTRETCH, // downwards dashed arrow
'\u21E4': MO.WIDEREL, // leftwards arrow to bar
'\u21E5': MO.WIDEREL, // rightwards arrow to bar
'\u21E6': MO.WIDEREL, // leftwards white arrow
'\u21E7': MO.RELSTRETCH, // upwards white arrow
'\u21E8': MO.WIDEREL, // rightwards white arrow
'\u21E9': MO.RELSTRETCH, // downwards white arrow
'\u21EA': MO.RELSTRETCH, // upwards white arrow from bar
'\u21EB': MO.RELSTRETCH, // upwards white arrow on pedestal
'\u21EC': MO.RELSTRETCH, // upwards white arrow on pedestal with horizontal bar
'\u21ED': MO.RELSTRETCH, // upwards white arrow on pedestal with vertical bar
'\u21EE': MO.RELSTRETCH, // upwards white double arrow
'\u21EF': MO.RELSTRETCH, // upwards white double arrow on pedestal
'\u21F0': MO.WIDEREL, // rightwards white arrow from wall
'\u21F1': MO.REL, // north west arrow to corner
'\u21F2': MO.REL, // south east arrow to corner
'\u21F3': MO.RELSTRETCH, // up down white arrow
'\u21F4': MO.RELACCENT, // right arrow with small circle
'\u21F5': MO.RELSTRETCH, // downwards arrow leftwards of upwards arrow
'\u21F6': MO.WIDEREL, // three rightwards arrows
'\u21F7': MO.RELACCENT, // leftwards arrow with vertical stroke
'\u21F8': MO.RELACCENT, // rightwards arrow with vertical stroke
'\u21F9': MO.RELACCENT, // left right arrow with vertical stroke
'\u21FA': MO.RELACCENT, // leftwards arrow with double vertical stroke
'\u21FB': MO.RELACCENT, // rightwards arrow with double vertical stroke
'\u21FC': MO.RELACCENT, // left right arrow with double vertical stroke
'\u21FD': MO.WIDEREL, // leftwards open-headed arrow
'\u21FE': MO.WIDEREL, // rightwards open-headed arrow
'\u21FF': MO.WIDEREL // left right open-headed arrow
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/Arrows.js");
})(MathJax.ElementJax.mml);
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/MiscMathSymbolsA.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
prefix: {
'\u27E6': MO.OPEN, // mathematical left white square bracket
'\u27EA': MO.OPEN, // mathematical left double angle bracket
'\u27EC': MO.OPEN // mathematical left white tortoise shell bracket
},
postfix: {
'\u27E7': MO.CLOSE, // mathematical right white square bracket
'\u27EB': MO.CLOSE, // mathematical right double angle bracket
'\u27ED': MO.CLOSE // mathematical right white tortoise shell bracket
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/MiscMathSymbolsA.js");
})(MathJax.ElementJax.mml);
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/Dingbats.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
prefix: {
'\u2772': MO.OPEN // light left tortoise shell bracket ornament
},
postfix: {
'\u2773': MO.CLOSE // light right tortoise shell bracket ornament
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/Dingbats.js");
})(MathJax.ElementJax.mml);
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/GeneralPunctuation.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
prefix: {
'\u2016': [0,0,TEXCLASS.ORD,{fence: true, stretchy: true}], // double vertical line
'\u2018': [0,0,TEXCLASS.OPEN,{fence: true}], // left single quotation mark
'\u201C': [0,0,TEXCLASS.OPEN,{fence: true}] // left double quotation mark
},
postfix: {
'\u2016': [0,0,TEXCLASS.ORD,{fence: true, stretchy: true}], // double vertical line
'\u2019': [0,0,TEXCLASS.CLOSE,{fence: true}], // right single quotation mark
'\u201D': [0,0,TEXCLASS.CLOSE,{fence: true}] // right double quotation mark
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/GeneralPunctuation.js");
})(MathJax.ElementJax.mml);
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/SpacingModLetters.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
postfix: {
'\u02CD': MO.WIDEACCENT, // modifier letter low macron
'\u02DA': MO.ACCENT, // ring above
'\u02DD': MO.ACCENT, // double acute accent
'\u02F7': MO.WIDEACCENT // modifier letter low tilde
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/SpacingModLetters.js");
})(MathJax.ElementJax.mml);
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/MiscTechnical.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
postfix: {
'\u23B4': MO.WIDEACCENT, // top square bracket
'\u23B5': MO.WIDEACCENT, // bottom square bracket
'\u23DC': MO.WIDEACCENT, // top parenthesis
'\u23DD': MO.WIDEACCENT, // bottom parenthesis
'\u23E0': MO.WIDEACCENT, // top tortoise shell bracket
'\u23E1': MO.WIDEACCENT // bottom tortoise shell bracket
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/MiscTechnical.js");
})(MathJax.ElementJax.mml);
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/SupplementalArrowsA.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
infix: {
'\u27F0': MO.RELSTRETCH, // upwards quadruple arrow
'\u27F1': MO.RELSTRETCH, // downwards quadruple arrow
'\u27FB': MO.WIDEREL, // long leftwards arrow from bar
'\u27FD': MO.WIDEREL, // long leftwards double arrow from bar
'\u27FE': MO.WIDEREL, // long rightwards double arrow from bar
'\u27FF': MO.WIDEREL // long rightwards squiggle arrow
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/SupplementalArrowsA.js");
})(MathJax.ElementJax.mml);
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/GreekAndCoptic.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
infix: {
'\u03F6': MO.REL // greek reversed lunate epsilon symbol
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/GreekAndCoptic.js");
})(MathJax.ElementJax.mml);
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/LetterlikeSymbols.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
prefix: {
'\u2145': MO.ORD21, // double-struck italic capital d
'\u2146': [2,0,TEXCLASS.ORD] // double-struck italic small d
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/LetterlikeSymbols.js");
})(MathJax.ElementJax.mml);
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/SupplementalArrowsB.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
infix: {
'\u2900': MO.RELACCENT, // rightwards two-headed arrow with vertical stroke
'\u2901': MO.RELACCENT, // rightwards two-headed arrow with double vertical stroke
'\u2902': MO.RELACCENT, // leftwards double arrow with vertical stroke
'\u2903': MO.RELACCENT, // rightwards double arrow with vertical stroke
'\u2904': MO.RELACCENT, // left right double arrow with vertical stroke
'\u2905': MO.RELACCENT, // rightwards two-headed arrow from bar
'\u2906': MO.RELACCENT, // leftwards double arrow from bar
'\u2907': MO.RELACCENT, // rightwards double arrow from bar
'\u2908': MO.REL, // downwards arrow with horizontal stroke
'\u2909': MO.REL, // upwards arrow with horizontal stroke
'\u290A': MO.RELSTRETCH, // upwards triple arrow
'\u290B': MO.RELSTRETCH, // downwards triple arrow
'\u290C': MO.WIDEREL, // leftwards double dash arrow
'\u290D': MO.WIDEREL, // rightwards double dash arrow
'\u290E': MO.WIDEREL, // leftwards triple dash arrow
'\u290F': MO.WIDEREL, // rightwards triple dash arrow
'\u2910': MO.WIDEREL, // rightwards two-headed triple dash arrow
'\u2911': MO.RELACCENT, // rightwards arrow with dotted stem
'\u2912': MO.RELSTRETCH, // upwards arrow to bar
'\u2913': MO.RELSTRETCH, // downwards arrow to bar
'\u2914': MO.RELACCENT, // rightwards arrow with tail with vertical stroke
'\u2915': MO.RELACCENT, // rightwards arrow with tail with double vertical stroke
'\u2916': MO.RELACCENT, // rightwards two-headed arrow with tail
'\u2917': MO.RELACCENT, // rightwards two-headed arrow with tail with vertical stroke
'\u2918': MO.RELACCENT, // rightwards two-headed arrow with tail with double vertical stroke
'\u2919': MO.RELACCENT, // leftwards arrow-tail
'\u291A': MO.RELACCENT, // rightwards arrow-tail
'\u291B': MO.RELACCENT, // leftwards double arrow-tail
'\u291C': MO.RELACCENT, // rightwards double arrow-tail
'\u291D': MO.RELACCENT, // leftwards arrow to black diamond
'\u291E': MO.RELACCENT, // rightwards arrow to black diamond
'\u291F': MO.RELACCENT, // leftwards arrow from bar to black diamond
'\u2920': MO.RELACCENT, // rightwards arrow from bar to black diamond
'\u2921': MO.RELSTRETCH, // north west and south east arrow
'\u2922': MO.RELSTRETCH, // north east and south west arrow
'\u2923': MO.REL, // north west arrow with hook
'\u2924': MO.REL, // north east arrow with hook
'\u2925': MO.REL, // south east arrow with hook
'\u2926': MO.REL, // south west arrow with hook
'\u2927': MO.REL, // north west arrow and north east arrow
'\u2928': MO.REL, // north east arrow and south east arrow
'\u2929': MO.REL, // south east arrow and south west arrow
'\u292A': MO.REL, // south west arrow and north west arrow
'\u292B': MO.REL, // rising diagonal crossing falling diagonal
'\u292C': MO.REL, // falling diagonal crossing rising diagonal
'\u292D': MO.REL, // south east arrow crossing north east arrow
'\u292E': MO.REL, // north east arrow crossing south east arrow
'\u292F': MO.REL, // falling diagonal crossing north east arrow
'\u2930': MO.REL, // rising diagonal crossing south east arrow
'\u2931': MO.REL, // north east arrow crossing north west arrow
'\u2932': MO.REL, // north west arrow crossing north east arrow
'\u2933': MO.RELACCENT, // wave arrow pointing directly right
'\u2934': MO.REL, // arrow pointing rightwards then curving upwards
'\u2935': MO.REL, // arrow pointing rightwards then curving downwards
'\u2936': MO.REL, // arrow pointing downwards then curving leftwards
'\u2937': MO.REL, // arrow pointing downwards then curving rightwards
'\u2938': MO.REL, // right-side arc clockwise arrow
'\u2939': MO.REL, // left-side arc anticlockwise arrow
'\u293A': MO.RELACCENT, // top arc anticlockwise arrow
'\u293B': MO.RELACCENT, // bottom arc anticlockwise arrow
'\u293C': MO.RELACCENT, // top arc clockwise arrow with minus
'\u293D': MO.RELACCENT, // top arc anticlockwise arrow with plus
'\u293E': MO.REL, // lower right semicircular clockwise arrow
'\u293F': MO.REL, // lower left semicircular anticlockwise arrow
'\u2940': MO.REL, // anticlockwise closed circle arrow
'\u2941': MO.REL, // clockwise closed circle arrow
'\u2942': MO.RELACCENT, // rightwards arrow above short leftwards arrow
'\u2943': MO.RELACCENT, // leftwards arrow above short rightwards arrow
'\u2944': MO.RELACCENT, // short rightwards arrow above leftwards arrow
'\u2945': MO.RELACCENT, // rightwards arrow with plus below
'\u2946': MO.RELACCENT, // leftwards arrow with plus below
'\u2947': MO.RELACCENT, // rightwards arrow through x
'\u2948': MO.RELACCENT, // left right arrow through small circle
'\u2949': MO.REL, // upwards two-headed arrow from small circle
'\u294A': MO.RELACCENT, // left barb up right barb down harpoon
'\u294B': MO.RELACCENT, // left barb down right barb up harpoon
'\u294C': MO.REL, // up barb right down barb left harpoon
'\u294D': MO.REL, // up barb left down barb right harpoon
'\u294E': MO.WIDEREL, // left barb up right barb up harpoon
'\u294F': MO.RELSTRETCH, // up barb right down barb right harpoon
'\u2950': MO.WIDEREL, // left barb down right barb down harpoon
'\u2951': MO.RELSTRETCH, // up barb left down barb left harpoon
'\u2952': MO.WIDEREL, // leftwards harpoon with barb up to bar
'\u2953': MO.WIDEREL, // rightwards harpoon with barb up to bar
'\u2954': MO.RELSTRETCH, // upwards harpoon with barb right to bar
'\u2955': MO.RELSTRETCH, // downwards harpoon with barb right to bar
'\u2956': MO.RELSTRETCH, // leftwards harpoon with barb down to bar
'\u2957': MO.RELSTRETCH, // rightwards harpoon with barb down to bar
'\u2958': MO.RELSTRETCH, // upwards harpoon with barb left to bar
'\u2959': MO.RELSTRETCH, // downwards harpoon with barb left to bar
'\u295A': MO.WIDEREL, // leftwards harpoon with barb up from bar
'\u295B': MO.WIDEREL, // rightwards harpoon with barb up from bar
'\u295C': MO.RELSTRETCH, // upwards harpoon with barb right from bar
'\u295D': MO.RELSTRETCH, // downwards harpoon with barb right from bar
'\u295E': MO.WIDEREL, // leftwards harpoon with barb down from bar
'\u295F': MO.WIDEREL, // rightwards harpoon with barb down from bar
'\u2960': MO.RELSTRETCH, // upwards harpoon with barb left from bar
'\u2961': MO.RELSTRETCH, // downwards harpoon with barb left from bar
'\u2962': MO.RELACCENT, // leftwards harpoon with barb up above leftwards harpoon with barb down
'\u2963': MO.REL, // upwards harpoon with barb left beside upwards harpoon with barb right
'\u2964': MO.RELACCENT, // rightwards harpoon with barb up above rightwards harpoon with barb down
'\u2965': MO.REL, // downwards harpoon with barb left beside downwards harpoon with barb right
'\u2966': MO.RELACCENT, // leftwards harpoon with barb up above rightwards harpoon with barb up
'\u2967': MO.RELACCENT, // leftwards harpoon with barb down above rightwards harpoon with barb down
'\u2968': MO.RELACCENT, // rightwards harpoon with barb up above leftwards harpoon with barb up
'\u2969': MO.RELACCENT, // rightwards harpoon with barb down above leftwards harpoon with barb down
'\u296A': MO.RELACCENT, // leftwards harpoon with barb up above long dash
'\u296B': MO.RELACCENT, // leftwards harpoon with barb down below long dash
'\u296C': MO.RELACCENT, // rightwards harpoon with barb up above long dash
'\u296D': MO.RELACCENT, // rightwards harpoon with barb down below long dash
'\u296E': MO.RELSTRETCH, // upwards harpoon with barb left beside downwards harpoon with barb right
'\u296F': MO.RELSTRETCH, // downwards harpoon with barb left beside upwards harpoon with barb right
'\u2970': MO.RELACCENT, // right double arrow with rounded head
'\u2971': MO.RELACCENT, // equals sign above rightwards arrow
'\u2972': MO.RELACCENT, // tilde operator above rightwards arrow
'\u2973': MO.RELACCENT, // leftwards arrow above tilde operator
'\u2974': MO.RELACCENT, // rightwards arrow above tilde operator
'\u2975': MO.RELACCENT, // rightwards arrow above almost equal to
'\u2976': MO.RELACCENT, // less-than above leftwards arrow
'\u2977': MO.RELACCENT, // leftwards arrow through less-than
'\u2978': MO.RELACCENT, // greater-than above rightwards arrow
'\u2979': MO.RELACCENT, // subset above rightwards arrow
'\u297A': MO.RELACCENT, // leftwards arrow through subset
'\u297B': MO.RELACCENT, // superset above leftwards arrow
'\u297C': MO.RELACCENT, // left fish tail
'\u297D': MO.RELACCENT, // right fish tail
'\u297E': MO.REL, // up fish tail
'\u297F': MO.REL // down fish tail
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/SupplementalArrowsB.js");
})(MathJax.ElementJax.mml);
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/BasicLatin.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
prefix: {
'||': [0,0,TEXCLASS.BIN,{fence: true, stretchy: true, symmetric: true}], // multiple character operator: ||
'|||': [0,0,TEXCLASS.ORD,{fence: true, stretchy: true, symmetric: true}] // multiple character operator: |||
},
postfix: {
'!!': [1,0,TEXCLASS.BIN], // multiple character operator: !!
'\'': MO.ACCENT, // apostrophe
'++': [0,0,TEXCLASS.BIN], // multiple character operator: ++
'--': [0,0,TEXCLASS.BIN], // multiple character operator: --
'..': [0,0,TEXCLASS.BIN], // multiple character operator: ..
'...': MO.ORD, // multiple character operator: ...
'||': [0,0,TEXCLASS.BIN,{fence: true, stretchy: true, symmetric: true}], // multiple character operator: ||
'|||': [0,0,TEXCLASS.ORD,{fence: true, stretchy: true, symmetric: true}] // multiple character operator: |||
},
infix: {
'!=': MO.BIN4, // multiple character operator: !=
'&&': MO.BIN4, // multiple character operator: &&
'**': [1,1,TEXCLASS.BIN], // multiple character operator: **
'*=': MO.BIN4, // multiple character operator: *=
'+=': MO.BIN4, // multiple character operator: +=
'-=': MO.BIN4, // multiple character operator: -=
'->': MO.BIN5, // multiple character operator: ->
'//': [1,1,TEXCLASS.BIN], // multiple character operator: //
'/=': MO.BIN4, // multiple character operator: /=
':=': MO.BIN4, // multiple character operator: :=
'<=': MO.BIN5, // multiple character operator: <=
'<>': [1,1,TEXCLASS.BIN], // multiple character operator: <>
'==': MO.BIN4, // multiple character operator: ==
'>=': MO.BIN5, // multiple character operator: >=
'@': MO.ORD11, // commercial at
'||': [2,2,TEXCLASS.BIN,{fence: true, stretchy: true, symmetric: true}], // multiple character operator: ||
'|||': [2,2,TEXCLASS.ORD,{fence: true, stretchy: true, symmetric: true}] // multiple character operator: |||
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/BasicLatin.js");
})(MathJax.ElementJax.mml);
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/MiscSymbolsAndArrows.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
infix: {
'\u2B45': MO.RELSTRETCH, // leftwards quadruple arrow
'\u2B46': MO.RELSTRETCH // rightwards quadruple arrow
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/MiscSymbolsAndArrows.js");
})(MathJax.ElementJax.mml);
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/CombDiacritMarks.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
postfix: {
'\u0311': MO.ACCENT // combining inverted breve
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/CombDiacritMarks.js");
})(MathJax.ElementJax.mml);
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/GeometricShapes.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
infix: {
'\u25A0': MO.BIN3, // black square
'\u25A1': MO.BIN3, // white square
'\u25AA': MO.BIN3, // black small square
'\u25AB': MO.BIN3, // white small square
'\u25AD': MO.BIN3, // white rectangle
'\u25AE': MO.BIN3, // black vertical rectangle
'\u25AF': MO.BIN3, // white vertical rectangle
'\u25B0': MO.BIN3, // black parallelogram
'\u25B1': MO.BIN3, // white parallelogram
'\u25B2': MO.BIN4, // black up-pointing triangle
'\u25B4': MO.BIN4, // black up-pointing small triangle
'\u25B6': MO.BIN4, // black right-pointing triangle
'\u25B7': MO.BIN4, // white right-pointing triangle
'\u25B8': MO.BIN4, // black right-pointing small triangle
'\u25BC': MO.BIN4, // black down-pointing triangle
'\u25BE': MO.BIN4, // black down-pointing small triangle
'\u25C0': MO.BIN4, // black left-pointing triangle
'\u25C1': MO.BIN4, // white left-pointing triangle
'\u25C2': MO.BIN4, // black left-pointing small triangle
'\u25C4': MO.BIN4, // black left-pointing pointer
'\u25C5': MO.BIN4, // white left-pointing pointer
'\u25C6': MO.BIN4, // black diamond
'\u25C7': MO.BIN4, // white diamond
'\u25C8': MO.BIN4, // white diamond containing black small diamond
'\u25C9': MO.BIN4, // fisheye
'\u25CC': MO.BIN4, // dotted circle
'\u25CD': MO.BIN4, // circle with vertical fill
'\u25CE': MO.BIN4, // bullseye
'\u25CF': MO.BIN4, // black circle
'\u25D6': MO.BIN4, // left half black circle
'\u25D7': MO.BIN4, // right half black circle
'\u25E6': MO.BIN4 // white bullet
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/GeometricShapes.js");
})(MathJax.ElementJax.mml);
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/MathOperators.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
prefix: {
'\u2204': MO.ORD21, // there does not exist
'\u221B': MO.ORD11, // cube root
'\u221C': MO.ORD11, // fourth root
'\u2221': MO.ORD, // measured angle
'\u2222': MO.ORD, // spherical angle
'\u222C': MO.INTEGRAL, // double integral
'\u222D': MO.INTEGRAL, // triple integral
'\u222F': MO.INTEGRAL, // surface integral
'\u2230': MO.INTEGRAL, // volume integral
'\u2231': MO.INTEGRAL, // clockwise integral
'\u2232': MO.INTEGRAL, // clockwise contour integral
'\u2233': MO.INTEGRAL // anticlockwise contour integral
},
infix: {
'\u2201': [1,2,TEXCLASS.ORD], // complement
'\u2206': MO.BIN3, // increment
'\u220A': MO.REL, // small element of
'\u220C': MO.REL, // does not contain as member
'\u220D': MO.REL, // small contains as member
'\u220E': MO.BIN3, // end of proof
'\u2214': MO.BIN4, // dot plus
'\u221F': MO.REL, // right angle
'\u2224': MO.REL, // does not divide
'\u2226': MO.REL, // not parallel to
'\u2234': MO.REL, // therefore
'\u2235': MO.REL, // because
'\u2236': MO.REL, // ratio
'\u2237': MO.REL, // proportion
'\u2238': MO.BIN4, // dot minus
'\u2239': MO.REL, // excess
'\u223A': MO.BIN4, // geometric proportion
'\u223B': MO.REL, // homothetic
'\u223D': MO.REL, // reversed tilde
'\u223D\u0331': MO.BIN3, // reversed tilde with underline
'\u223E': MO.REL, // inverted lazy s
'\u223F': MO.BIN3, // sine wave
'\u2241': MO.REL, // not tilde
'\u2242': MO.REL, // minus tilde
'\u2242\u0338': MO.REL, // minus tilde with slash
'\u2244': MO.REL, // not asymptotically equal to
'\u2246': MO.REL, // approximately but not actually equal to
'\u2247': MO.REL, // neither approximately nor actually equal to
'\u2249': MO.REL, // not almost equal to
'\u224A': MO.REL, // almost equal or equal to
'\u224B': MO.REL, // triple tilde
'\u224C': MO.REL, // all equal to
'\u224E': MO.REL, // geometrically equivalent to
'\u224E\u0338': MO.REL, // geometrically equivalent to with slash
'\u224F': MO.REL, // difference between
'\u224F\u0338': MO.REL, // difference between with slash
'\u2251': MO.REL, // geometrically equal to
'\u2252': MO.REL, // approximately equal to or the image of
'\u2253': MO.REL, // image of or approximately equal to
'\u2254': MO.REL, // colon equals
'\u2255': MO.REL, // equals colon
'\u2256': MO.REL, // ring in equal to
'\u2257': MO.REL, // ring equal to
'\u2258': MO.REL, // corresponds to
'\u2259': MO.REL, // estimates
'\u225A': MO.REL, // equiangular to
'\u225C': MO.REL, // delta equal to
'\u225D': MO.REL, // equal to by definition
'\u225E': MO.REL, // measured by
'\u225F': MO.REL, // questioned equal to
'\u2262': MO.REL, // not identical to
'\u2263': MO.REL, // strictly equivalent to
'\u2266': MO.REL, // less-than over equal to
'\u2266\u0338': MO.REL, // less-than over equal to with slash
'\u2267': MO.REL, // greater-than over equal to
'\u2268': MO.REL, // less-than but not equal to
'\u2269': MO.REL, // greater-than but not equal to
'\u226A\u0338': MO.REL, // much less than with slash
'\u226B\u0338': MO.REL, // much greater than with slash
'\u226C': MO.REL, // between
'\u226D': MO.REL, // not equivalent to
'\u226E': MO.REL, // not less-than
'\u226F': MO.REL, // not greater-than
'\u2270': MO.REL, // neither less-than nor equal to
'\u2271': MO.REL, // neither greater-than nor equal to
'\u2272': MO.REL, // less-than or equivalent to
'\u2273': MO.REL, // greater-than or equivalent to
'\u2274': MO.REL, // neither less-than nor equivalent to
'\u2275': MO.REL, // neither greater-than nor equivalent to
'\u2276': MO.REL, // less-than or greater-than
'\u2277': MO.REL, // greater-than or less-than
'\u2278': MO.REL, // neither less-than nor greater-than
'\u2279': MO.REL, // neither greater-than nor less-than
'\u227C': MO.REL, // precedes or equal to
'\u227D': MO.REL, // succeeds or equal to
'\u227E': MO.REL, // precedes or equivalent to
'\u227F': MO.REL, // succeeds or equivalent to
'\u227F\u0338': MO.REL, // succeeds or equivalent to with slash
'\u2280': MO.REL, // does not precede
'\u2281': MO.REL, // does not succeed
'\u2282\u20D2': MO.REL, // subset of with vertical line
'\u2283\u20D2': MO.REL, // superset of with vertical line
'\u2284': MO.REL, // not a subset of
'\u2285': MO.REL, // not a superset of
'\u2288': MO.REL, // neither a subset of nor equal to
'\u2289': MO.REL, // neither a superset of nor equal to
'\u228A': MO.REL, // subset of with not equal to
'\u228B': MO.REL, // superset of with not equal to
'\u228C': MO.BIN4, // multiset
'\u228D': MO.BIN4, // multiset multiplication
'\u228F': MO.REL, // square image of
'\u228F\u0338': MO.REL, // square image of with slash
'\u2290': MO.REL, // square original of
'\u2290\u0338': MO.REL, // square original of with slash
'\u229A': MO.BIN4, // circled ring operator
'\u229B': MO.BIN4, // circled asterisk operator
'\u229C': MO.BIN4, // circled equals
'\u229D': MO.BIN4, // circled dash
'\u229E': MO.BIN4, // squared plus
'\u229F': MO.BIN4, // squared minus
'\u22A0': MO.BIN4, // squared times
'\u22A1': MO.BIN4, // squared dot operator
'\u22A6': MO.REL, // assertion
'\u22A7': MO.REL, // models
'\u22A9': MO.REL, // forces
'\u22AA': MO.REL, // triple vertical bar right turnstile
'\u22AB': MO.REL, // double vertical bar double right turnstile
'\u22AC': MO.REL, // does not prove
'\u22AD': MO.REL, // not true
'\u22AE': MO.REL, // does not force
'\u22AF': MO.REL, // negated double vertical bar double right turnstile
'\u22B0': MO.REL, // precedes under relation
'\u22B1': MO.REL, // succeeds under relation
'\u22B2': MO.REL, // normal subgroup of
'\u22B3': MO.REL, // contains as normal subgroup
'\u22B4': MO.REL, // normal subgroup of or equal to
'\u22B5': MO.REL, // contains as normal subgroup or equal to
'\u22B6': MO.REL, // original of
'\u22B7': MO.REL, // image of
'\u22B8': MO.REL, // multimap
'\u22B9': MO.REL, // hermitian conjugate matrix
'\u22BA': MO.BIN4, // intercalate
'\u22BB': MO.BIN4, // xor
'\u22BC': MO.BIN4, // nand
'\u22BD': MO.BIN4, // nor
'\u22BE': MO.BIN3, // right angle with arc
'\u22BF': MO.BIN3, // right triangle
'\u22C7': MO.BIN4, // division times
'\u22C9': MO.BIN4, // left normal factor semidirect product
'\u22CA': MO.BIN4, // right normal factor semidirect product
'\u22CB': MO.BIN4, // left semidirect product
'\u22CC': MO.BIN4, // right semidirect product
'\u22CD': MO.REL, // reversed tilde equals
'\u22CE': MO.BIN4, // curly logical or
'\u22CF': MO.BIN4, // curly logical and
'\u22D0': MO.REL, // double subset
'\u22D1': MO.REL, // double superset
'\u22D2': MO.BIN4, // double intersection
'\u22D3': MO.BIN4, // double union
'\u22D4': MO.REL, // pitchfork
'\u22D5': MO.REL, // equal and parallel to
'\u22D6': MO.REL, // less-than with dot
'\u22D7': MO.REL, // greater-than with dot
'\u22D8': MO.REL, // very much less-than
'\u22D9': MO.REL, // very much greater-than
'\u22DA': MO.REL, // less-than equal to or greater-than
'\u22DB': MO.REL, // greater-than equal to or less-than
'\u22DC': MO.REL, // equal to or less-than
'\u22DD': MO.REL, // equal to or greater-than
'\u22DE': MO.REL, // equal to or precedes
'\u22DF': MO.REL, // equal to or succeeds
'\u22E0': MO.REL, // does not precede or equal
'\u22E1': MO.REL, // does not succeed or equal
'\u22E2': MO.REL, // not square image of or equal to
'\u22E3': MO.REL, // not square original of or equal to
'\u22E4': MO.REL, // square image of or not equal to
'\u22E5': MO.REL, // square original of or not equal to
'\u22E6': MO.REL, // less-than but not equivalent to
'\u22E7': MO.REL, // greater-than but not equivalent to
'\u22E8': MO.REL, // precedes but not equivalent to
'\u22E9': MO.REL, // succeeds but not equivalent to
'\u22EA': MO.REL, // not normal subgroup of
'\u22EB': MO.REL, // does not contain as normal subgroup
'\u22EC': MO.REL, // not normal subgroup of or equal to
'\u22ED': MO.REL, // does not contain as normal subgroup or equal
'\u22F0': MO.REL, // up right diagonal ellipsis
'\u22F2': MO.REL, // element of with long horizontal stroke
'\u22F3': MO.REL, // element of with vertical bar at end of horizontal stroke
'\u22F4': MO.REL, // small element of with vertical bar at end of horizontal stroke
'\u22F5': MO.REL, // element of with dot above
'\u22F6': MO.REL, // element of with overbar
'\u22F7': MO.REL, // small element of with overbar
'\u22F8': MO.REL, // element of with underbar
'\u22F9': MO.REL, // element of with two horizontal strokes
'\u22FA': MO.REL, // contains with long horizontal stroke
'\u22FB': MO.REL, // contains with vertical bar at end of horizontal stroke
'\u22FC': MO.REL, // small contains with vertical bar at end of horizontal stroke
'\u22FD': MO.REL, // contains with overbar
'\u22FE': MO.REL, // small contains with overbar
'\u22FF': MO.REL // z notation bag membership
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/MathOperators.js");
})(MathJax.ElementJax.mml);
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/MiscMathSymbolsB.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
prefix: {
'\u2980': [0,0,TEXCLASS.ORD,{fence: true, stretchy: true}], // triple vertical bar delimiter
'\u2983': MO.OPEN, // left white curly bracket
'\u2985': MO.OPEN, // left white parenthesis
'\u2987': MO.OPEN, // z notation left image bracket
'\u2989': MO.OPEN, // z notation left binding bracket
'\u298B': MO.OPEN, // left square bracket with underbar
'\u298D': MO.OPEN, // left square bracket with tick in top corner
'\u298F': MO.OPEN, // left square bracket with tick in bottom corner
'\u2991': MO.OPEN, // left angle bracket with dot
'\u2993': MO.OPEN, // left arc less-than bracket
'\u2995': MO.OPEN, // double left arc greater-than bracket
'\u2997': MO.OPEN, // left black tortoise shell bracket
'\u29FC': MO.OPEN // left-pointing curved angle bracket
},
postfix: {
'\u2980': [0,0,TEXCLASS.ORD,{fence: true, stretchy: true}], // triple vertical bar delimiter
'\u2984': MO.CLOSE, // right white curly bracket
'\u2986': MO.CLOSE, // right white parenthesis
'\u2988': MO.CLOSE, // z notation right image bracket
'\u298A': MO.CLOSE, // z notation right binding bracket
'\u298C': MO.CLOSE, // right square bracket with underbar
'\u298E': MO.CLOSE, // right square bracket with tick in bottom corner
'\u2990': MO.CLOSE, // right square bracket with tick in top corner
'\u2992': MO.CLOSE, // right angle bracket with dot
'\u2994': MO.CLOSE, // right arc greater-than bracket
'\u2996': MO.CLOSE, // double right arc less-than bracket
'\u2998': MO.CLOSE, // right black tortoise shell bracket
'\u29FD': MO.CLOSE // right-pointing curved angle bracket
},
infix: {
'\u2981': MO.BIN3, // z notation spot
'\u2982': MO.BIN3, // z notation type colon
'\u2999': MO.BIN3, // dotted fence
'\u299A': MO.BIN3, // vertical zigzag line
'\u299B': MO.BIN3, // measured angle opening left
'\u299C': MO.BIN3, // right angle variant with square
'\u299D': MO.BIN3, // measured right angle with dot
'\u299E': MO.BIN3, // angle with s inside
'\u299F': MO.BIN3, // acute angle
'\u29A0': MO.BIN3, // spherical angle opening left
'\u29A1': MO.BIN3, // spherical angle opening up
'\u29A2': MO.BIN3, // turned angle
'\u29A3': MO.BIN3, // reversed angle
'\u29A4': MO.BIN3, // angle with underbar
'\u29A5': MO.BIN3, // reversed angle with underbar
'\u29A6': MO.BIN3, // oblique angle opening up
'\u29A7': MO.BIN3, // oblique angle opening down
'\u29A8': MO.BIN3, // measured angle with open arm ending in arrow pointing up and right
'\u29A9': MO.BIN3, // measured angle with open arm ending in arrow pointing up and left
'\u29AA': MO.BIN3, // measured angle with open arm ending in arrow pointing down and right
'\u29AB': MO.BIN3, // measured angle with open arm ending in arrow pointing down and left
'\u29AC': MO.BIN3, // measured angle with open arm ending in arrow pointing right and up
'\u29AD': MO.BIN3, // measured angle with open arm ending in arrow pointing left and up
'\u29AE': MO.BIN3, // measured angle with open arm ending in arrow pointing right and down
'\u29AF': MO.BIN3, // measured angle with open arm ending in arrow pointing left and down
'\u29B0': MO.BIN3, // reversed empty set
'\u29B1': MO.BIN3, // empty set with overbar
'\u29B2': MO.BIN3, // empty set with small circle above
'\u29B3': MO.BIN3, // empty set with right arrow above
'\u29B4': MO.BIN3, // empty set with left arrow above
'\u29B5': MO.BIN3, // circle with horizontal bar
'\u29B6': MO.BIN4, // circled vertical bar
'\u29B7': MO.BIN4, // circled parallel
'\u29B8': MO.BIN4, // circled reverse solidus
'\u29B9': MO.BIN4, // circled perpendicular
'\u29BA': MO.BIN4, // circle divided by horizontal bar and top half divided by vertical bar
'\u29BB': MO.BIN4, // circle with superimposed x
'\u29BC': MO.BIN4, // circled anticlockwise-rotated division sign
'\u29BD': MO.BIN4, // up arrow through circle
'\u29BE': MO.BIN4, // circled white bullet
'\u29BF': MO.BIN4, // circled bullet
'\u29C0': MO.REL, // circled less-than
'\u29C1': MO.REL, // circled greater-than
'\u29C2': MO.BIN3, // circle with small circle to the right
'\u29C3': MO.BIN3, // circle with two horizontal strokes to the right
'\u29C4': MO.BIN4, // squared rising diagonal slash
'\u29C5': MO.BIN4, // squared falling diagonal slash
'\u29C6': MO.BIN4, // squared asterisk
'\u29C7': MO.BIN4, // squared small circle
'\u29C8': MO.BIN4, // squared square
'\u29C9': MO.BIN3, // two joined squares
'\u29CA': MO.BIN3, // triangle with dot above
'\u29CB': MO.BIN3, // triangle with underbar
'\u29CC': MO.BIN3, // s in triangle
'\u29CD': MO.BIN3, // triangle with serifs at bottom
'\u29CE': MO.REL, // right triangle above left triangle
'\u29CF': MO.REL, // left triangle beside vertical bar
'\u29CF\u0338': MO.REL, // left triangle beside vertical bar with slash
'\u29D0': MO.REL, // vertical bar beside right triangle
'\u29D0\u0338': MO.REL, // vertical bar beside right triangle with slash
'\u29D1': MO.REL, // bowtie with left half black
'\u29D2': MO.REL, // bowtie with right half black
'\u29D3': MO.REL, // black bowtie
'\u29D4': MO.REL, // times with left half black
'\u29D5': MO.REL, // times with right half black
'\u29D6': MO.BIN4, // white hourglass
'\u29D7': MO.BIN4, // black hourglass
'\u29D8': MO.BIN3, // left wiggly fence
'\u29D9': MO.BIN3, // right wiggly fence
'\u29DB': MO.BIN3, // right double wiggly fence
'\u29DC': MO.BIN3, // incomplete infinity
'\u29DD': MO.BIN3, // tie over infinity
'\u29DE': MO.REL, // infinity negated with vertical bar
'\u29DF': MO.BIN3, // double-ended multimap
'\u29E0': MO.BIN3, // square with contoured outline
'\u29E1': MO.REL, // increases as
'\u29E2': MO.BIN4, // shuffle product
'\u29E3': MO.REL, // equals sign and slanted parallel
'\u29E4': MO.REL, // equals sign and slanted parallel with tilde above
'\u29E5': MO.REL, // identical to and slanted parallel
'\u29E6': MO.REL, // gleich stark
'\u29E7': MO.BIN3, // thermodynamic
'\u29E8': MO.BIN3, // down-pointing triangle with left half black
'\u29E9': MO.BIN3, // down-pointing triangle with right half black
'\u29EA': MO.BIN3, // black diamond with down arrow
'\u29EB': MO.BIN3, // black lozenge
'\u29EC': MO.BIN3, // white circle with down arrow
'\u29ED': MO.BIN3, // black circle with down arrow
'\u29EE': MO.BIN3, // error-barred white square
'\u29EF': MO.BIN3, // error-barred black square
'\u29F0': MO.BIN3, // error-barred white diamond
'\u29F1': MO.BIN3, // error-barred black diamond
'\u29F2': MO.BIN3, // error-barred white circle
'\u29F3': MO.BIN3, // error-barred black circle
'\u29F4': MO.REL, // rule-delayed
'\u29F5': MO.BIN4, // reverse solidus operator
'\u29F6': MO.BIN4, // solidus with overbar
'\u29F7': MO.BIN4, // reverse solidus with horizontal stroke
'\u29F8': MO.BIN3, // big solidus
'\u29F9': MO.BIN3, // big reverse solidus
'\u29FA': MO.BIN3, // double plus
'\u29FB': MO.BIN3, // triple plus
'\u29FE': MO.BIN4, // tiny
'\u29FF': MO.BIN4 // miny
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/MiscMathSymbolsB.js");
})(MathJax.ElementJax.mml);
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/SuppMathOperators.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
prefix: {
'\u2A03': MO.OP, // n-ary union operator with dot
'\u2A05': MO.OP, // n-ary square intersection operator
'\u2A07': MO.OP, // two logical and operator
'\u2A08': MO.OP, // two logical or operator
'\u2A09': MO.OP, // n-ary times operator
'\u2A0A': MO.OP, // modulo two sum
'\u2A0B': MO.INTEGRAL2, // summation with integral
'\u2A0C': MO.INTEGRAL, // quadruple integral operator
'\u2A0D': MO.INTEGRAL2, // finite part integral
'\u2A0E': MO.INTEGRAL2, // integral with double stroke
'\u2A0F': MO.INTEGRAL2, // integral average with slash
'\u2A10': MO.OP, // circulation function
'\u2A11': MO.OP, // anticlockwise integration
'\u2A12': MO.OP, // line integration with rectangular path around pole
'\u2A13': MO.OP, // line integration with semicircular path around pole
'\u2A14': MO.OP, // line integration not including the pole
'\u2A15': MO.INTEGRAL2, // integral around a point operator
'\u2A16': MO.INTEGRAL2, // quaternion integral operator
'\u2A17': MO.INTEGRAL2, // integral with leftwards arrow with hook
'\u2A18': MO.INTEGRAL2, // integral with times sign
'\u2A19': MO.INTEGRAL2, // integral with intersection
'\u2A1A': MO.INTEGRAL2, // integral with union
'\u2A1B': MO.INTEGRAL2, // integral with overbar
'\u2A1C': MO.INTEGRAL2, // integral with underbar
'\u2AFC': MO.OP, // large triple vertical bar operator
'\u2AFF': MO.OP // n-ary white vertical bar
},
infix: {
'\u2A1D': MO.BIN3, // join
'\u2A1E': MO.BIN3, // large left triangle operator
'\u2A1F': MO.BIN3, // z notation schema composition
'\u2A20': MO.BIN3, // z notation schema piping
'\u2A21': MO.BIN3, // z notation schema projection
'\u2A22': MO.BIN4, // plus sign with small circle above
'\u2A23': MO.BIN4, // plus sign with circumflex accent above
'\u2A24': MO.BIN4, // plus sign with tilde above
'\u2A25': MO.BIN4, // plus sign with dot below
'\u2A26': MO.BIN4, // plus sign with tilde below
'\u2A27': MO.BIN4, // plus sign with subscript two
'\u2A28': MO.BIN4, // plus sign with black triangle
'\u2A29': MO.BIN4, // minus sign with comma above
'\u2A2A': MO.BIN4, // minus sign with dot below
'\u2A2B': MO.BIN4, // minus sign with falling dots
'\u2A2C': MO.BIN4, // minus sign with rising dots
'\u2A2D': MO.BIN4, // plus sign in left half circle
'\u2A2E': MO.BIN4, // plus sign in right half circle
'\u2A30': MO.BIN4, // multiplication sign with dot above
'\u2A31': MO.BIN4, // multiplication sign with underbar
'\u2A32': MO.BIN4, // semidirect product with bottom closed
'\u2A33': MO.BIN4, // smash product
'\u2A34': MO.BIN4, // multiplication sign in left half circle
'\u2A35': MO.BIN4, // multiplication sign in right half circle
'\u2A36': MO.BIN4, // circled multiplication sign with circumflex accent
'\u2A37': MO.BIN4, // multiplication sign in double circle
'\u2A38': MO.BIN4, // circled division sign
'\u2A39': MO.BIN4, // plus sign in triangle
'\u2A3A': MO.BIN4, // minus sign in triangle
'\u2A3B': MO.BIN4, // multiplication sign in triangle
'\u2A3C': MO.BIN4, // interior product
'\u2A3D': MO.BIN4, // righthand interior product
'\u2A3E': MO.BIN4, // z notation relational composition
'\u2A40': MO.BIN4, // intersection with dot
'\u2A41': MO.BIN4, // union with minus sign
'\u2A42': MO.BIN4, // union with overbar
'\u2A43': MO.BIN4, // intersection with overbar
'\u2A44': MO.BIN4, // intersection with logical and
'\u2A45': MO.BIN4, // union with logical or
'\u2A46': MO.BIN4, // union above intersection
'\u2A47': MO.BIN4, // intersection above union
'\u2A48': MO.BIN4, // union above bar above intersection
'\u2A49': MO.BIN4, // intersection above bar above union
'\u2A4A': MO.BIN4, // union beside and joined with union
'\u2A4B': MO.BIN4, // intersection beside and joined with intersection
'\u2A4C': MO.BIN4, // closed union with serifs
'\u2A4D': MO.BIN4, // closed intersection with serifs
'\u2A4E': MO.BIN4, // double square intersection
'\u2A4F': MO.BIN4, // double square union
'\u2A50': MO.BIN4, // closed union with serifs and smash product
'\u2A51': MO.BIN4, // logical and with dot above
'\u2A52': MO.BIN4, // logical or with dot above
'\u2A53': MO.BIN4, // double logical and
'\u2A54': MO.BIN4, // double logical or
'\u2A55': MO.BIN4, // two intersecting logical and
'\u2A56': MO.BIN4, // two intersecting logical or
'\u2A57': MO.BIN4, // sloping large or
'\u2A58': MO.BIN4, // sloping large and
'\u2A59': MO.REL, // logical or overlapping logical and
'\u2A5A': MO.BIN4, // logical and with middle stem
'\u2A5B': MO.BIN4, // logical or with middle stem
'\u2A5C': MO.BIN4, // logical and with horizontal dash
'\u2A5D': MO.BIN4, // logical or with horizontal dash
'\u2A5E': MO.BIN4, // logical and with double overbar
'\u2A5F': MO.BIN4, // logical and with underbar
'\u2A60': MO.BIN4, // logical and with double underbar
'\u2A61': MO.BIN4, // small vee with underbar
'\u2A62': MO.BIN4, // logical or with double overbar
'\u2A63': MO.BIN4, // logical or with double underbar
'\u2A64': MO.BIN4, // z notation domain antirestriction
'\u2A65': MO.BIN4, // z notation range antirestriction
'\u2A66': MO.REL, // equals sign with dot below
'\u2A67': MO.REL, // identical with dot above
'\u2A68': MO.REL, // triple horizontal bar with double vertical stroke
'\u2A69': MO.REL, // triple horizontal bar with triple vertical stroke
'\u2A6A': MO.REL, // tilde operator with dot above
'\u2A6B': MO.REL, // tilde operator with rising dots
'\u2A6C': MO.REL, // similar minus similar
'\u2A6D': MO.REL, // congruent with dot above
'\u2A6E': MO.REL, // equals with asterisk
'\u2A6F': MO.REL, // almost equal to with circumflex accent
'\u2A70': MO.REL, // approximately equal or equal to
'\u2A71': MO.BIN4, // equals sign above plus sign
'\u2A72': MO.BIN4, // plus sign above equals sign
'\u2A73': MO.REL, // equals sign above tilde operator
'\u2A74': MO.REL, // double colon equal
'\u2A75': MO.REL, // two consecutive equals signs
'\u2A76': MO.REL, // three consecutive equals signs
'\u2A77': MO.REL, // equals sign with two dots above and two dots below
'\u2A78': MO.REL, // equivalent with four dots above
'\u2A79': MO.REL, // less-than with circle inside
'\u2A7A': MO.REL, // greater-than with circle inside
'\u2A7B': MO.REL, // less-than with question mark above
'\u2A7C': MO.REL, // greater-than with question mark above
'\u2A7D': MO.REL, // less-than or slanted equal to
'\u2A7D\u0338': MO.REL, // less-than or slanted equal to with slash
'\u2A7E': MO.REL, // greater-than or slanted equal to
'\u2A7E\u0338': MO.REL, // greater-than or slanted equal to with slash
'\u2A7F': MO.REL, // less-than or slanted equal to with dot inside
'\u2A80': MO.REL, // greater-than or slanted equal to with dot inside
'\u2A81': MO.REL, // less-than or slanted equal to with dot above
'\u2A82': MO.REL, // greater-than or slanted equal to with dot above
'\u2A83': MO.REL, // less-than or slanted equal to with dot above right
'\u2A84': MO.REL, // greater-than or slanted equal to with dot above left
'\u2A85': MO.REL, // less-than or approximate
'\u2A86': MO.REL, // greater-than or approximate
'\u2A87': MO.REL, // less-than and single-line not equal to
'\u2A88': MO.REL, // greater-than and single-line not equal to
'\u2A89': MO.REL, // less-than and not approximate
'\u2A8A': MO.REL, // greater-than and not approximate
'\u2A8B': MO.REL, // less-than above double-line equal above greater-than
'\u2A8C': MO.REL, // greater-than above double-line equal above less-than
'\u2A8D': MO.REL, // less-than above similar or equal
'\u2A8E': MO.REL, // greater-than above similar or equal
'\u2A8F': MO.REL, // less-than above similar above greater-than
'\u2A90': MO.REL, // greater-than above similar above less-than
'\u2A91': MO.REL, // less-than above greater-than above double-line equal
'\u2A92': MO.REL, // greater-than above less-than above double-line equal
'\u2A93': MO.REL, // less-than above slanted equal above greater-than above slanted equal
'\u2A94': MO.REL, // greater-than above slanted equal above less-than above slanted equal
'\u2A95': MO.REL, // slanted equal to or less-than
'\u2A96': MO.REL, // slanted equal to or greater-than
'\u2A97': MO.REL, // slanted equal to or less-than with dot inside
'\u2A98': MO.REL, // slanted equal to or greater-than with dot inside
'\u2A99': MO.REL, // double-line equal to or less-than
'\u2A9A': MO.REL, // double-line equal to or greater-than
'\u2A9B': MO.REL, // double-line slanted equal to or less-than
'\u2A9C': MO.REL, // double-line slanted equal to or greater-than
'\u2A9D': MO.REL, // similar or less-than
'\u2A9E': MO.REL, // similar or greater-than
'\u2A9F': MO.REL, // similar above less-than above equals sign
'\u2AA0': MO.REL, // similar above greater-than above equals sign
'\u2AA1': MO.REL, // double nested less-than
'\u2AA1\u0338': MO.REL, // double nested less-than with slash
'\u2AA2': MO.REL, // double nested greater-than
'\u2AA2\u0338': MO.REL, // double nested greater-than with slash
'\u2AA3': MO.REL, // double nested less-than with underbar
'\u2AA4': MO.REL, // greater-than overlapping less-than
'\u2AA5': MO.REL, // greater-than beside less-than
'\u2AA6': MO.REL, // less-than closed by curve
'\u2AA7': MO.REL, // greater-than closed by curve
'\u2AA8': MO.REL, // less-than closed by curve above slanted equal
'\u2AA9': MO.REL, // greater-than closed by curve above slanted equal
'\u2AAA': MO.REL, // smaller than
'\u2AAB': MO.REL, // larger than
'\u2AAC': MO.REL, // smaller than or equal to
'\u2AAD': MO.REL, // larger than or equal to
'\u2AAE': MO.REL, // equals sign with bumpy above
'\u2AAF\u0338': MO.REL, // precedes above single-line equals sign with slash
'\u2AB0\u0338': MO.REL, // succeeds above single-line equals sign with slash
'\u2AB1': MO.REL, // precedes above single-line not equal to
'\u2AB2': MO.REL, // succeeds above single-line not equal to
'\u2AB3': MO.REL, // precedes above equals sign
'\u2AB4': MO.REL, // succeeds above equals sign
'\u2AB5': MO.REL, // precedes above not equal to
'\u2AB6': MO.REL, // succeeds above not equal to
'\u2AB7': MO.REL, // precedes above almost equal to
'\u2AB8': MO.REL, // succeeds above almost equal to
'\u2AB9': MO.REL, // precedes above not almost equal to
'\u2ABA': MO.REL, // succeeds above not almost equal to
'\u2ABB': MO.REL, // double precedes
'\u2ABC': MO.REL, // double succeeds
'\u2ABD': MO.REL, // subset with dot
'\u2ABE': MO.REL, // superset with dot
'\u2ABF': MO.REL, // subset with plus sign below
'\u2AC0': MO.REL, // superset with plus sign below
'\u2AC1': MO.REL, // subset with multiplication sign below
'\u2AC2': MO.REL, // superset with multiplication sign below
'\u2AC3': MO.REL, // subset of or equal to with dot above
'\u2AC4': MO.REL, // superset of or equal to with dot above
'\u2AC5': MO.REL, // subset of above equals sign
'\u2AC6': MO.REL, // superset of above equals sign
'\u2AC7': MO.REL, // subset of above tilde operator
'\u2AC8': MO.REL, // superset of above tilde operator
'\u2AC9': MO.REL, // subset of above almost equal to
'\u2ACA': MO.REL, // superset of above almost equal to
'\u2ACB': MO.REL, // subset of above not equal to
'\u2ACC': MO.REL, // superset of above not equal to
'\u2ACD': MO.REL, // square left open box operator
'\u2ACE': MO.REL, // square right open box operator
'\u2ACF': MO.REL, // closed subset
'\u2AD0': MO.REL, // closed superset
'\u2AD1': MO.REL, // closed subset or equal to
'\u2AD2': MO.REL, // closed superset or equal to
'\u2AD3': MO.REL, // subset above superset
'\u2AD4': MO.REL, // superset above subset
'\u2AD5': MO.REL, // subset above subset
'\u2AD6': MO.REL, // superset above superset
'\u2AD7': MO.REL, // superset beside subset
'\u2AD8': MO.REL, // superset beside and joined by dash with subset
'\u2AD9': MO.REL, // element of opening downwards
'\u2ADA': MO.REL, // pitchfork with tee top
'\u2ADB': MO.REL, // transversal intersection
'\u2ADC': MO.REL, // forking
'\u2ADD': MO.REL, // nonforking
'\u2ADE': MO.REL, // short left tack
'\u2ADF': MO.REL, // short down tack
'\u2AE0': MO.REL, // short up tack
'\u2AE1': MO.REL, // perpendicular with s
'\u2AE2': MO.REL, // vertical bar triple right turnstile
'\u2AE3': MO.REL, // double vertical bar left turnstile
'\u2AE4': MO.REL, // vertical bar double left turnstile
'\u2AE5': MO.REL, // double vertical bar double left turnstile
'\u2AE6': MO.REL, // long dash from left member of double vertical
'\u2AE7': MO.REL, // short down tack with overbar
'\u2AE8': MO.REL, // short up tack with underbar
'\u2AE9': MO.REL, // short up tack above short down tack
'\u2AEA': MO.REL, // double down tack
'\u2AEB': MO.REL, // double up tack
'\u2AEC': MO.REL, // double stroke not sign
'\u2AED': MO.REL, // reversed double stroke not sign
'\u2AEE': MO.REL, // does not divide with reversed negation slash
'\u2AEF': MO.REL, // vertical line with circle above
'\u2AF0': MO.REL, // vertical line with circle below
'\u2AF1': MO.REL, // down tack with circle below
'\u2AF2': MO.REL, // parallel with horizontal stroke
'\u2AF3': MO.REL, // parallel with tilde operator
'\u2AF4': MO.BIN4, // triple vertical bar binary relation
'\u2AF5': MO.BIN4, // triple vertical bar with horizontal stroke
'\u2AF6': MO.BIN4, // triple colon operator
'\u2AF7': MO.REL, // triple nested less-than
'\u2AF8': MO.REL, // triple nested greater-than
'\u2AF9': MO.REL, // double-line slanted less-than or equal to
'\u2AFA': MO.REL, // double-line slanted greater-than or equal to
'\u2AFB': MO.BIN4, // triple solidus binary relation
'\u2AFD': MO.BIN4, // double solidus operator
'\u2AFE': MO.BIN3 // white vertical bar
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/SuppMathOperators.js");
})(MathJax.ElementJax.mml);
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/CombDiactForSymbols.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
postfix: {
'\u20DB': MO.ACCENT, // combining three dots above
'\u20DC': MO.ACCENT // combining four dots above
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/CombDiactForSymbols.js");
})(MathJax.ElementJax.mml);
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/Latin1Supplement.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
postfix: {
'\u00B0': MO.ORD, // degree sign
'\u00B4': MO.ACCENT, // acute accent
'\u00B8': MO.ACCENT // cedilla
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/Latin1Supplement.js");
})(MathJax.ElementJax.mml);
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/extensions/MathEvents.js
*
* Implements the event handlers needed by the output jax to perform
* menu, hover, and other events.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2011-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
(function (HUB,HTML,AJAX,CALLBACK,LOCALE,OUTPUT,INPUT) {
var VERSION = "2.7.1";
var EXTENSION = MathJax.Extension;
var ME = EXTENSION.MathEvents = {version: VERSION};
var SETTINGS = HUB.config.menuSettings;
var CONFIG = {
hover: 500, // time required to be considered a hover
frame: {
x: 3.5, y: 5, // frame padding and
bwidth: 1, // frame border width (in pixels)
bcolor: "#A6D", // frame border color
hwidth: "15px", // haze width
hcolor: "#83A" // haze color
},
button: {
x: -6, y: -3, // menu button offsets
wx: -2 // button offset for full-width equations
},
fadeinInc: .2, // increment for fade-in
fadeoutInc: .05, // increment for fade-out
fadeDelay: 50, // delay between fade-in or fade-out steps
fadeoutStart: 400, // delay before fade-out after mouseout
fadeoutDelay: 15*1000, // delay before automatic fade-out
styles: {
".MathJax_Hover_Frame": {
"border-radius": ".25em", // Opera 10.5 and IE9
"-webkit-border-radius": ".25em", // Safari and Chrome
"-moz-border-radius": ".25em", // Firefox
"-khtml-border-radius": ".25em", // Konqueror
"box-shadow": "0px 0px 15px #83A", // Opera 10.5 and IE9
"-webkit-box-shadow": "0px 0px 15px #83A", // Safari and Chrome
"-moz-box-shadow": "0px 0px 15px #83A", // Forefox
"-khtml-box-shadow": "0px 0px 15px #83A", // Konqueror
border: "1px solid #A6D ! important",
display: "inline-block", position:"absolute"
},
".MathJax_Menu_Button .MathJax_Hover_Arrow": {
position:"absolute",
cursor:"pointer",
display:"inline-block",
border:"2px solid #AAA",
"border-radius":"4px",
"-webkit-border-radius": "4px", // Safari and Chrome
"-moz-border-radius": "4px", // Firefox
"-khtml-border-radius": "4px", // Konqueror
"font-family":"'Courier New',Courier",
"font-size":"9px",
color:"#F0F0F0"
},
".MathJax_Menu_Button .MathJax_Hover_Arrow span": {
display:"block",
"background-color":"#AAA",
border:"1px solid",
"border-radius":"3px",
"line-height":0,
padding:"4px"
},
".MathJax_Hover_Arrow:hover": {
color:"white!important",
border:"2px solid #CCC!important"
},
".MathJax_Hover_Arrow:hover span": {
"background-color":"#CCC!important"
}
}
};
//
// Common event-handling code
//
var EVENT = ME.Event = {
LEFTBUTTON: 0, // the event.button value for left button
RIGHTBUTTON: 2, // the event.button value for right button
MENUKEY: "altKey", // the event value for alternate context menu
/*************************************************************/
/*
* Enum element for key codes.
*/
KEY: {
RETURN: 13,
ESCAPE: 27,
SPACE: 32,
LEFT: 37,
UP: 38,
RIGHT: 39,
DOWN: 40
},
Mousedown: function (event) {return EVENT.Handler(event,"Mousedown",this)},
Mouseup: function (event) {return EVENT.Handler(event,"Mouseup",this)},
Mousemove: function (event) {return EVENT.Handler(event,"Mousemove",this)},
Mouseover: function (event) {return EVENT.Handler(event,"Mouseover",this)},
Mouseout: function (event) {return EVENT.Handler(event,"Mouseout",this)},
Click: function (event) {return EVENT.Handler(event,"Click",this)},
DblClick: function (event) {return EVENT.Handler(event,"DblClick",this)},
Menu: function (event) {return EVENT.Handler(event,"ContextMenu",this)},
//
// Call the output jax's event handler or the zoom handler
//
Handler: function (event,type,math) {
if (AJAX.loadingMathMenu) {return EVENT.False(event)}
var jax = OUTPUT[math.jaxID];
if (!event) {event = window.event}
event.isContextMenu = (type === "ContextMenu");
if (jax[type]) {return jax[type](event,math)}
if (EXTENSION.MathZoom) {return EXTENSION.MathZoom.HandleEvent(event,type,math)}
},
//
// Try to cancel the event in every way we can
//
False: function (event) {
if (!event) {event = window.event}
if (event) {
if (event.preventDefault) {event.preventDefault()} else {event.returnValue = false}
if (event.stopPropagation) {event.stopPropagation()}
event.cancelBubble = true;
}
return false;
},
//
// Keydown event handler. Should only fire on Space key.
//
Keydown: function (event, math) {
if (!event) event = window.event;
if (event.keyCode === EVENT.KEY.SPACE) {
EVENT.ContextMenu(event, this);
};
},
//
// Load the contextual menu code, if needed, and post the menu
//
ContextMenu: function (event,math,force) {
//
// Check if we are showing menus
//
var JAX = OUTPUT[math.jaxID], jax = JAX.getJaxFromMath(math);
var show = (JAX.config.showMathMenu != null ? JAX : HUB).config.showMathMenu;
if (!show || (SETTINGS.context !== "MathJax" && !force)) return;
//
// Remove selections, remove hover fades
//
if (ME.msieEventBug) {event = window.event || event}
EVENT.ClearSelection(); HOVER.ClearHoverTimer();
if (jax.hover) {
if (jax.hover.remove) {clearTimeout(jax.hover.remove); delete jax.hover.remove}
jax.hover.nofade = true;
}
//
// If the menu code is loaded,
// Check if localization needs loading;
// If not, post the menu, and return.
// Otherwise wait for the localization to load
// Otherwse load the menu code.
// Try again after the file is loaded.
//
var MENU = MathJax.Menu; var load, fn;
if (MENU) {
if (MENU.loadingDomain) {return EVENT.False(event)}
load = LOCALE.loadDomain("MathMenu");
if (!load) {
MENU.jax = jax;
var source = MENU.menu.Find("Show Math As").submenu;
source.items[0].name = jax.sourceMenuTitle;
source.items[0].format = (jax.sourceMenuFormat||"MathML");
source.items[1].name = INPUT[jax.inputJax].sourceMenuTitle;
source.items[5].disabled = !INPUT[jax.inputJax].annotationEncoding;
//
// Try and find each known annotation format and enable the menu
// items accordingly.
//
var annotations = source.items[2]; annotations.disabled = true;
var annotationItems = annotations.submenu.items;
annotationList = MathJax.Hub.Config.semanticsAnnotations;
for (var i = 0, m = annotationItems.length; i < m; i++) {
var name = annotationItems[i].name[1]
if (jax.root && jax.root.getAnnotation(name) !== null) {
annotations.disabled = false;
annotationItems[i].hidden = false;
} else {
annotationItems[i].hidden = true;
}
}
var MathPlayer = MENU.menu.Find("Math Settings","MathPlayer");
MathPlayer.hidden = !(jax.outputJax === "NativeMML" && HUB.Browser.hasMathPlayer);
return MENU.menu.Post(event);
}
MENU.loadingDomain = true;
fn = function () {delete MENU.loadingDomain};
} else {
if (AJAX.loadingMathMenu) {return EVENT.False(event)}
AJAX.loadingMathMenu = true;
load = AJAX.Require("[MathJax]/extensions/MathMenu.js");
fn = function () {
delete AJAX.loadingMathMenu;
if (!MathJax.Menu) {MathJax.Menu = {}}
}
}
var ev = {
pageX:event.pageX, pageY:event.pageY,
clientX:event.clientX, clientY:event.clientY
};
CALLBACK.Queue(
load, fn, // load the file and delete the marker when done
["ContextMenu",EVENT,ev,math,force] // call this function again
);
return EVENT.False(event);
},
//
// Mousedown handler for alternate means of accessing menu
//
AltContextMenu: function (event,math) {
var JAX = OUTPUT[math.jaxID];
var show = (JAX.config.showMathMenu != null ? JAX : HUB).config.showMathMenu;
if (show) {
show = (JAX.config.showMathMenuMSIE != null ? JAX : HUB).config.showMathMenuMSIE;
if (SETTINGS.context === "MathJax" && !SETTINGS.mpContext && show) {
if (!ME.noContextMenuBug || event.button !== EVENT.RIGHTBUTTON) return;
} else {
if (!event[EVENT.MENUKEY] || event.button !== EVENT.LEFTBUTTON) return;
}
return JAX.ContextMenu(event,math,true);
}
},
ClearSelection: function () {
if (ME.safariContextMenuBug) {setTimeout("window.getSelection().empty()",0)}
if (document.selection) {setTimeout("document.selection.empty()",0)}
},
getBBox: function (span) {
span.appendChild(ME.topImg);
var h = ME.topImg.offsetTop, d = span.offsetHeight-h, w = span.offsetWidth;
span.removeChild(ME.topImg);
return {w:w, h:h, d:d};
}
};
//
// Handle hover "discoverability"
//
var HOVER = ME.Hover = {
//
// Check if we are moving from a non-MathJax element to a MathJax one
// and either start fading in again (if it is fading out) or start the
// timer for the hover
//
Mouseover: function (event,math) {
if (SETTINGS.discoverable || SETTINGS.zoom === "Hover") {
var from = event.fromElement || event.relatedTarget,
to = event.toElement || event.target;
if (from && to && (HUB.isMathJaxNode(from) !== HUB.isMathJaxNode(to) ||
HUB.getJaxFor(from) !== HUB.getJaxFor(to))) {
var jax = this.getJaxFromMath(math);
if (jax.hover) {HOVER.ReHover(jax)} else {HOVER.HoverTimer(jax,math)}
return EVENT.False(event);
}
}
},
//
// Check if we are moving from a MathJax element to a non-MathJax one
// and either start fading out, or clear the timer if we haven't
// hovered yet
//
Mouseout: function (event,math) {
if (SETTINGS.discoverable || SETTINGS.zoom === "Hover") {
var from = event.fromElement || event.relatedTarget,
to = event.toElement || event.target;
if (from && to && (HUB.isMathJaxNode(from) !== HUB.isMathJaxNode(to) ||
HUB.getJaxFor(from) !== HUB.getJaxFor(to))) {
var jax = this.getJaxFromMath(math);
if (jax.hover) {HOVER.UnHover(jax)} else {HOVER.ClearHoverTimer()}
return EVENT.False(event);
}
}
},
//
// Restart hover timer if the mouse moves
//
Mousemove: function (event,math) {
if (SETTINGS.discoverable || SETTINGS.zoom === "Hover") {
var jax = this.getJaxFromMath(math); if (jax.hover) return;
if (HOVER.lastX == event.clientX && HOVER.lastY == event.clientY) return;
HOVER.lastX = event.clientX; HOVER.lastY = event.clientY;
HOVER.HoverTimer(jax,math);
return EVENT.False(event);
}
},
//
// Clear the old timer and start a new one
//
HoverTimer: function (jax,math) {
this.ClearHoverTimer();
this.hoverTimer = setTimeout(CALLBACK(["Hover",this,jax,math]),CONFIG.hover);
},
ClearHoverTimer: function () {
if (this.hoverTimer) {clearTimeout(this.hoverTimer); delete this.hoverTimer}
},
//
// Handle putting up the hover frame
//
Hover: function (jax,math) {
//
// Check if Zoom handles the hover event
//
if (EXTENSION.MathZoom && EXTENSION.MathZoom.Hover({},math)) return;
//
// Get the hover data
//
var JAX = OUTPUT[jax.outputJax],
span = JAX.getHoverSpan(jax,math),
bbox = JAX.getHoverBBox(jax,span,math),
show = (JAX.config.showMathMenu != null ? JAX : HUB).config.showMathMenu;
var dx = CONFIG.frame.x, dy = CONFIG.frame.y, dd = CONFIG.frame.bwidth; // frame size
if (ME.msieBorderWidthBug) {dd = 0}
jax.hover = {opacity:0, id:jax.inputID+"-Hover"};
//
// The frame and menu button
//
var frame = HTML.Element("span",{
id:jax.hover.id, isMathJax: true,
style:{display:"inline-block", width:0, height:0, position:"relative"}
},[["span",{
className:"MathJax_Hover_Frame", isMathJax: true,
style:{
display:"inline-block", position:"absolute",
top:this.Px(-bbox.h-dy-dd-(bbox.y||0)), left:this.Px(-dx-dd+(bbox.x||0)),
width:this.Px(bbox.w+2*dx), height:this.Px(bbox.h+bbox.d+2*dy),
opacity:0, filter:"alpha(opacity=0)"
}}
]]
);
var button = HTML.Element("span",{
isMathJax: true, id:jax.hover.id+"Menu", className:"MathJax_Menu_Button",
style:{display:"inline-block", "z-index": 1, width:0, height:0, position:"relative"}
},[["span",{
className: "MathJax_Hover_Arrow", isMathJax: true, math: math,
onclick: this.HoverMenu, jax:JAX.id,
style: {
left:this.Px(bbox.w+dx+dd+(bbox.x||0)+CONFIG.button.x),
top:this.Px(-bbox.h-dy-dd-(bbox.y||0)-CONFIG.button.y),
opacity:0, filter:"alpha(opacity=0)"
}
},[["span",{isMathJax:true},"\u25BC"]]]]
);
if (bbox.width) {
frame.style.width = button.style.width = bbox.width;
frame.style.marginRight = button.style.marginRight = "-"+bbox.width;
frame.firstChild.style.width = bbox.width;
button.firstChild.style.left = "";
button.firstChild.style.right = this.Px(CONFIG.button.wx);
}
//
// Add the frame and button
//
span.parentNode.insertBefore(frame,span);
if (show) {span.parentNode.insertBefore(button,span)}
if (span.style) {span.style.position = "relative"} // so math is on top of hover frame
//
// Start the hover fade-in
//
this.ReHover(jax);
},
//
// Restart the hover fade in and fade-out timers
//
ReHover: function (jax) {
if (jax.hover.remove) {clearTimeout(jax.hover.remove)}
jax.hover.remove = setTimeout(CALLBACK(["UnHover",this,jax]),CONFIG.fadeoutDelay);
this.HoverFadeTimer(jax,CONFIG.fadeinInc);
},
//
// Start the fade-out
//
UnHover: function (jax) {
if (!jax.hover.nofade) {this.HoverFadeTimer(jax,-CONFIG.fadeoutInc,CONFIG.fadeoutStart)}
},
//
// Handle the fade-in and fade-out
//
HoverFade: function (jax) {
delete jax.hover.timer;
jax.hover.opacity = Math.max(0,Math.min(1,jax.hover.opacity + jax.hover.inc));
jax.hover.opacity = Math.floor(1000*jax.hover.opacity)/1000;
var frame = document.getElementById(jax.hover.id),
button = document.getElementById(jax.hover.id+"Menu");
frame.firstChild.style.opacity = jax.hover.opacity;
frame.firstChild.style.filter = "alpha(opacity="+Math.floor(100*jax.hover.opacity)+")";
if (button) {
button.firstChild.style.opacity = jax.hover.opacity;
button.firstChild.style.filter = frame.style.filter;
}
if (jax.hover.opacity === 1) {return}
if (jax.hover.opacity > 0) {this.HoverFadeTimer(jax,jax.hover.inc); return}
frame.parentNode.removeChild(frame);
if (button) {button.parentNode.removeChild(button)}
if (jax.hover.remove) {clearTimeout(jax.hover.remove)}
delete jax.hover;
},
//
// Set the fade to in or out (via inc) and start the timer, if needed
//
HoverFadeTimer: function (jax,inc,delay) {
jax.hover.inc = inc;
if (!jax.hover.timer) {
jax.hover.timer = setTimeout(CALLBACK(["HoverFade",this,jax]),(delay||CONFIG.fadeDelay));
}
},
//
// Handle a click on the menu button
//
HoverMenu: function (event) {
if (!event) {event = window.event}
return OUTPUT[this.jax].ContextMenu(event,this.math,true);
},
//
// Clear all hover timers
//
ClearHover: function (jax) {
if (jax.hover.remove) {clearTimeout(jax.hover.remove)}
if (jax.hover.timer) {clearTimeout(jax.hover.timer)}
HOVER.ClearHoverTimer();
delete jax.hover;
},
//
// Make a measurement in pixels
//
Px: function (m) {
if (Math.abs(m) < .006) {return "0px"}
return m.toFixed(2).replace(/\.?0+$/,"") + "px";
},
//
// Preload images so they show up with the menu
//
getImages: function () {
if (SETTINGS.discoverable) {
var menu = new Image();
menu.src = CONFIG.button.src;
}
}
};
//
// Handle touch events.
//
// Use double-tap-and-hold as a replacement for context menu event.
// Use double-tap as a replacement for double click.
//
var TOUCH = ME.Touch = {
last: 0, // time of last tap event
delay: 500, // delay time for double-click
//
// Check if this is a double-tap, and if so, start the timer
// for the double-tap and hold (to trigger the contextual menu)
//
start: function (event) {
var now = new Date().getTime();
var dblTap = (now - TOUCH.last < TOUCH.delay && TOUCH.up);
TOUCH.last = now; TOUCH.up = false;
if (dblTap) {
TOUCH.timeout = setTimeout(TOUCH.menu,TOUCH.delay,event,this);
event.preventDefault();
}
},
//
// Check if there is a timeout pending, i.e., we have a
// double-tap and were waiting to see if it is held long
// enough for the menu. Since we got the end before the
// timeout, it is a double-click, not a double-tap-and-hold.
// Prevent the default action and issue a double click.
//
end: function (event) {
var now = new Date().getTime();
TOUCH.up = (now - TOUCH.last < TOUCH.delay);
if (TOUCH.timeout) {
clearTimeout(TOUCH.timeout);
delete TOUCH.timeout; TOUCH.last = 0; TOUCH.up = false;
event.preventDefault();
return EVENT.Handler((event.touches[0]||event.touch),"DblClick",this);
}
},
//
// If the timeout passes without an end event, we issue
// the contextual menu event.
//
menu: function (event,math) {
delete TOUCH.timeout; TOUCH.last = 0; TOUCH.up = false;
return EVENT.Handler((event.touches[0]||event.touch),"ContextMenu",math);
}
};
/*
* //
* // Mobile screens are small, so use larger version of arrow
* //
* if (HUB.Browser.isMobile) {
* var arrow = CONFIG.styles[".MathJax_Hover_Arrow"];
* arrow.width = "25px"; arrow.height = "18px";
* CONFIG.button.x = -6;
* }
*/
//
// Set up browser-specific values
//
HUB.Browser.Select({
MSIE: function (browser) {
var mode = (document.documentMode || 0);
var isIE8 = browser.versionAtLeast("8.0");
ME.msieBorderWidthBug = (document.compatMode === "BackCompat"); // borders are inside offsetWidth/Height
ME.msieEventBug = browser.isIE9; // must get event from window even though event is passed
ME.msieAlignBug = (!isIE8 || mode < 8); // inline-block spans don't rest on baseline
if (mode < 9) {EVENT.LEFTBUTTON = 1} // IE < 9 has wrong event.button values
},
Safari: function (browser) {
ME.safariContextMenuBug = true; // selection can be started by contextmenu event
},
Opera: function (browser) {
ME.operaPositionBug = true; // position is wrong unless border is used
},
Konqueror: function (browser) {
ME.noContextMenuBug = true; // doesn't produce contextmenu event
}
});
//
// Used in measuring zoom and hover positions
//
ME.topImg = (ME.msieAlignBug ?
HTML.Element("img",{style:{width:0,height:0,position:"relative"},src:"about:blank"}) :
HTML.Element("span",{style:{width:0,height:0,display:"inline-block"}})
);
if (ME.operaPositionBug) {ME.topImg.style.border="1px solid"}
//
// Get configuration from user
//
ME.config = CONFIG = HUB.CombineConfig("MathEvents",CONFIG);
var SETFRAME = function () {
var haze = CONFIG.styles[".MathJax_Hover_Frame"];
haze.border = CONFIG.frame.bwidth+"px solid "+CONFIG.frame.bcolor+" ! important";
haze["box-shadow"] = haze["-webkit-box-shadow"] =
haze["-moz-box-shadow"] = haze["-khtml-box-shadow"] =
"0px 0px "+CONFIG.frame.hwidth+" "+CONFIG.frame.hcolor;
};
//
// Queue the events needed for startup
//
CALLBACK.Queue(
HUB.Register.StartupHook("End Config",{}), // wait until config is complete
[SETFRAME],
["getImages",HOVER],
["Styles",AJAX,CONFIG.styles],
["Post",HUB.Startup.signal,"MathEvents Ready"],
["loadComplete",AJAX,"[MathJax]/extensions/MathEvents.js"]
);
})(MathJax.Hub,MathJax.HTML,MathJax.Ajax,MathJax.Callback,
MathJax.Localization,MathJax.OutputJax,MathJax.InputJax);
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/extensions/MathZoom.js
*
* Implements the zoom feature for enlarging math expressions. It is
* loaded automatically when the Zoom menu selection changes from "None".
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
(function (HUB,HTML,AJAX,HTMLCSS,nMML) {
var VERSION = "2.7.1";
var CONFIG = HUB.CombineConfig("MathZoom",{
styles: {
//
// The styles for the MathZoom display box
//
"#MathJax_Zoom": {
position:"absolute", "background-color":"#F0F0F0", overflow:"auto",
display:"block", "z-index":301, padding:".5em", border:"1px solid black", margin:0,
"font-weight":"normal", "font-style":"normal",
"text-align":"left", "text-indent":0, "text-transform":"none",
"line-height":"normal", "letter-spacing":"normal", "word-spacing":"normal",
"word-wrap":"normal", "white-space":"nowrap", "float":"none",
"-webkit-box-sizing":"content-box", // Android ≤ 2.3, iOS ≤ 4
"-moz-box-sizing":"content-box", // Firefox ≤ 28
"box-sizing":"content-box", // Chrome, Firefox 29+, IE 8+, Opera, Safari 5.1
"box-shadow":"5px 5px 15px #AAAAAA", // Opera 10.5 and IE9
"-webkit-box-shadow":"5px 5px 15px #AAAAAA", // Safari 3 and Chrome
"-moz-box-shadow":"5px 5px 15px #AAAAAA", // Forefox 3.5
"-khtml-box-shadow":"5px 5px 15px #AAAAAA", // Konqueror
filter: "progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true')" // IE
},
//
// The styles for the hidden overlay (should not need to be adjusted by the page author)
//
"#MathJax_ZoomOverlay": {
position:"absolute", left:0, top:0, "z-index":300, display:"inline-block",
width:"100%", height:"100%", border:0, padding:0, margin:0,
"background-color":"white", opacity:0, filter:"alpha(opacity=0)"
},
"#MathJax_ZoomFrame": {
position:"relative", display:"inline-block",
height:0, width:0
},
"#MathJax_ZoomEventTrap": {
position:"absolute", left:0, top:0, "z-index":302,
display:"inline-block", border:0, padding:0, margin:0,
"background-color":"white", opacity:0, filter:"alpha(opacity=0)"
}
}
});
var FALSE, HOVER, EVENT;
MathJax.Hub.Register.StartupHook("MathEvents Ready",function () {
EVENT = MathJax.Extension.MathEvents.Event;
FALSE = MathJax.Extension.MathEvents.Event.False;
HOVER = MathJax.Extension.MathEvents.Hover;
});
/*************************************************************/
var ZOOM = MathJax.Extension.MathZoom = {
version: VERSION,
settings: HUB.config.menuSettings,
scrollSize: 18, // width of scrool bars
//
// Process events passed from output jax
//
HandleEvent: function (event,type,math) {
if (ZOOM.settings.CTRL && !event.ctrlKey) return true;
if (ZOOM.settings.ALT && !event.altKey) return true;
if (ZOOM.settings.CMD && !event.metaKey) return true;
if (ZOOM.settings.Shift && !event.shiftKey) return true;
if (!ZOOM[type]) return true;
return ZOOM[type](event,math);
},
//
// Zoom on click
//
Click: function (event,math) {
if (this.settings.zoom === "Click") {return this.Zoom(event,math)}
},
//
// Zoom on double click
//
DblClick: function (event,math) {
if (this.settings.zoom === "Double-Click" || this.settings.zoom === "DoubleClick") {return this.Zoom(event,math)}
},
//
// Zoom on hover (called by MathEvents.Hover)
//
Hover: function (event,math) {
if (this.settings.zoom === "Hover") {this.Zoom(event,math); return true}
return false;
},
//
// Handle the actual zooming
//
Zoom: function (event,math) {
//
// Remove any other zoom and clear timers
//
this.Remove(); HOVER.ClearHoverTimer(); EVENT.ClearSelection();
//
// Find the jax
//
var JAX = MathJax.OutputJax[math.jaxID];
var jax = JAX.getJaxFromMath(math);
if (jax.hover) {HOVER.UnHover(jax)}
//
// Create the DOM elements for the zoom box
//
var container = this.findContainer(math);
var Mw = Math.floor(.85*container.clientWidth),
Mh = Math.max(document.body.clientHeight,document.documentElement.clientHeight);
if (this.getOverflow(container) !== "visible") {Mh = Math.min(container.clientHeight,Mh)}
Mh = Math.floor(.85*Mh);
var div = HTML.Element(
"span",{id:"MathJax_ZoomFrame"},[
["span",{id:"MathJax_ZoomOverlay", onmousedown:this.Remove}],
["span",{
id:"MathJax_Zoom", onclick:this.Remove,
style:{visibility:"hidden", fontSize:this.settings.zscale}
},[["span",{style:{display:"inline-block", "white-space":"nowrap"}}]]
]]
);
var zoom = div.lastChild, span = zoom.firstChild, overlay = div.firstChild;
math.parentNode.insertBefore(div,math); math.parentNode.insertBefore(math,div); // put div after math
if (span.addEventListener) {span.addEventListener("mousedown",this.Remove,true)}
var eW = zoom.offsetWidth || zoom.clientWidth; Mw -= eW; Mh -= eW;
zoom.style.maxWidth = Mw+"px"; zoom.style.maxHeight = Mh+"px";
if (this.msieTrapEventBug) {
var trap = HTML.Element("span",{id:"MathJax_ZoomEventTrap", onmousedown:this.Remove});
div.insertBefore(trap,zoom);
}
//
// Display the zoomed math
//
if (this.msieZIndexBug) {
// MSIE doesn't do z-index properly, so move the div to the document.body,
// and use an image as a tracker for the usual position
var tracker = HTML.addElement(document.body,"img",{
src:"about:blank", id:"MathJax_ZoomTracker", width:0, height:0,
style:{width:0, height:0, position:"relative"}
});
div.style.position = "relative";
div.style.zIndex = CONFIG.styles["#MathJax_ZoomOverlay"]["z-index"];
div = tracker;
}
var bbox = JAX.Zoom(jax,span,math,Mw,Mh);
//
// Fix up size and position for browsers with bugs (IE)
//
if (this.msiePositionBug) {
if (this.msieSizeBug)
{zoom.style.height = bbox.zH+"px"; zoom.style.width = bbox.zW+"px"} // IE8 gets the dimensions completely wrong
if (zoom.offsetHeight > Mh) {zoom.style.height = Mh+"px"; zoom.style.width = (bbox.zW+this.scrollSize)+"px"} // IE doesn't do max-height?
if (zoom.offsetWidth > Mw) {zoom.style.width = Mw+"px"; zoom.style.height = (bbox.zH+this.scrollSize)+"px"}
}
if (this.operaPositionBug) {zoom.style.width = Math.min(Mw,bbox.zW)+"px"} // Opera gets width as 0?
if (zoom.offsetWidth > eW && zoom.offsetWidth-eW < Mw && zoom.offsetHeight-eW < Mh)
{zoom.style.overflow = "visible"} // don't show scroll bars if we don't need to
this.Position(zoom,bbox);
if (this.msieTrapEventBug) {
trap.style.height = zoom.clientHeight+"px"; trap.style.width = zoom.clientWidth+"px";
trap.style.left = (parseFloat(zoom.style.left)+zoom.clientLeft)+"px";
trap.style.top = (parseFloat(zoom.style.top)+zoom.clientTop)+"px";
}
zoom.style.visibility = "";
//
// Add event handlers
//
if (this.settings.zoom === "Hover") {overlay.onmouseover = this.Remove}
if (window.addEventListener) {addEventListener("resize",this.Resize,false)}
else if (window.attachEvent) {attachEvent("onresize",this.Resize)}
else {this.onresize = window.onresize; window.onresize = this.Resize}
//
// Let others know about the zoomed math
//
HUB.signal.Post(["math zoomed",jax]);
//
// Canel further actions
//
return FALSE(event);
},
//
// Set the position of the zoom box and overlay
//
Position: function (zoom,bbox) {
zoom.style.display = "none"; // avoids getting excessive width in Resize()
var XY = this.Resize(), x = XY.x, y = XY.y, W = bbox.mW;
zoom.style.display = "";
var dx = -W-Math.floor((zoom.offsetWidth-W)/2), dy = bbox.Y;
zoom.style.left = Math.max(dx,10-x)+"px"; zoom.style.top = Math.max(dy,10-y)+"px";
if (!ZOOM.msiePositionBug) {ZOOM.SetWH()} // refigure overlay width/height
},
//
// Handle resizing of overlay while zoom is displayed
//
Resize: function (event) {
if (ZOOM.onresize) {ZOOM.onresize(event)}
var div = document.getElementById("MathJax_ZoomFrame"),
overlay = document.getElementById("MathJax_ZoomOverlay");
var xy = ZOOM.getXY(div), obj = ZOOM.findContainer(div);
if (ZOOM.getOverflow(obj) !== "visible") {
overlay.scroll_parent = obj; // Save this for future reference.
var XY = ZOOM.getXY(obj); // Remove container position
xy.x -= XY.x; xy.y -= XY.y;
XY = ZOOM.getBorder(obj); // Remove container border
xy.x -= XY.x; xy.y -= XY.y;
}
overlay.style.left = (-xy.x)+"px"; overlay.style.top = (-xy.y)+"px";
if (ZOOM.msiePositionBug) {setTimeout(ZOOM.SetWH,0)} else {ZOOM.SetWH()}
return xy;
},
SetWH: function () {
var overlay = document.getElementById("MathJax_ZoomOverlay");
if (!overlay) return;
overlay.style.display = "none"; // so scrollWidth/Height will be right below
var doc = overlay.scroll_parent || document.documentElement || document.body;
overlay.style.width = doc.scrollWidth + "px";
overlay.style.height = Math.max(doc.clientHeight,doc.scrollHeight) + "px";
overlay.style.display = "";
},
findContainer: function (obj) {
obj = obj.parentNode;
while (obj.parentNode && obj !== document.body && ZOOM.getOverflow(obj) === "visible")
{obj = obj.parentNode}
return obj;
},
//
// Look up CSS properties (use getComputeStyle if available, or currentStyle if not)
//
getOverflow: (window.getComputedStyle ?
function (obj) {return getComputedStyle(obj).overflow} :
function (obj) {return (obj.currentStyle||{overflow:"visible"}).overflow}),
getBorder: function (obj) {
var size = {thin: 1, medium: 2, thick: 3};
var style = (window.getComputedStyle ? getComputedStyle(obj) :
(obj.currentStyle || {borderLeftWidth:0,borderTopWidth:0}));
var x = style.borderLeftWidth, y = style.borderTopWidth;
if (size[x]) {x = size[x]} else {x = parseInt(x)}
if (size[y]) {y = size[y]} else {y = parseInt(y)}
return {x:x, y:y};
},
//
// Get the position of an element on the page
//
getXY: function (div) {
var x = 0, y = 0, obj;
obj = div; while (obj.offsetParent) {x += obj.offsetLeft; obj = obj.offsetParent}
if (ZOOM.operaPositionBug) {div.style.border = "1px solid"} // to get vertical position right
obj = div; while (obj.offsetParent) {y += obj.offsetTop; obj = obj.offsetParent}
if (ZOOM.operaPositionBug) {div.style.border = ""}
return {x:x, y:y};
},
//
// Remove zoom display and event handlers
//
Remove: function (event) {
var div = document.getElementById("MathJax_ZoomFrame");
if (div) {
var JAX = MathJax.OutputJax[div.previousSibling.jaxID];
var jax = JAX.getJaxFromMath(div.previousSibling);
HUB.signal.Post(["math unzoomed",jax]);
div.parentNode.removeChild(div);
div = document.getElementById("MathJax_ZoomTracker");
if (div) {div.parentNode.removeChild(div)}
if (ZOOM.operaRefreshBug) {
// force a redisplay of the page
// (Opera doesn't refresh properly after the zoom is removed)
var overlay = HTML.addElement(document.body,"div",{
style:{position:"fixed", left:0, top:0, width:"100%", height:"100%",
backgroundColor:"white", opacity:0},
id: "MathJax_OperaDiv"
});
document.body.removeChild(overlay);
}
if (window.removeEventListener) {removeEventListener("resize",ZOOM.Resize,false)}
else if (window.detachEvent) {detachEvent("onresize",ZOOM.Resize)}
else {window.onresize = ZOOM.onresize; delete ZOOM.onresize}
}
return FALSE(event);
}
};
/*************************************************************/
HUB.Browser.Select({
MSIE: function (browser) {
var mode = (document.documentMode || 0);
var isIE9 = (mode >= 9);
ZOOM.msiePositionBug = !isIE9;
ZOOM.msieSizeBug = browser.versionAtLeast("7.0") &&
(!document.documentMode || mode === 7 || mode === 8);
ZOOM.msieZIndexBug = (mode <= 7);
ZOOM.msieInlineBlockAlignBug = (mode <= 7);
ZOOM.msieTrapEventBug = !window.addEventListener;
if (document.compatMode === "BackCompat") {ZOOM.scrollSize = 52} // don't know why this is so far off
if (isIE9) {delete CONFIG.styles["#MathJax_Zoom"].filter}
},
Opera: function (browser) {
ZOOM.operaPositionBug = true;
ZOOM.operaRefreshBug = true;
}
});
ZOOM.topImg = (ZOOM.msieInlineBlockAlignBug ?
HTML.Element("img",{style:{width:0,height:0,position:"relative"},src:"about:blank"}) :
HTML.Element("span",{style:{width:0,height:0,display:"inline-block"}})
);
if (ZOOM.operaPositionBug || ZOOM.msieTopBug) {ZOOM.topImg.style.border="1px solid"}
/*************************************************************/
MathJax.Callback.Queue(
["StartupHook",MathJax.Hub.Register,"Begin Styles",{}],
["Styles",AJAX,CONFIG.styles],
["Post",HUB.Startup.signal,"MathZoom Ready"],
["loadComplete",AJAX,"[MathJax]/extensions/MathZoom.js"]
);
})(MathJax.Hub,MathJax.HTML,MathJax.Ajax,MathJax.OutputJax["HTML-CSS"],MathJax.OutputJax.NativeMML);
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/extensions/MathMenu.js
*
* Implements a right-mouse (or CTRL-click) menu over mathematics
* elements that gives the user the ability to copy the source,
* change the math size, and zoom settings.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
(function (HUB,HTML,AJAX,CALLBACK,OUTPUT) {
var VERSION = "2.7.1";
var SIGNAL = MathJax.Callback.Signal("menu"); // signal for menu events
MathJax.Extension.MathMenu = {
version: VERSION,
signal: SIGNAL
};
var _ = function (id) {
return MathJax.Localization._.apply(
MathJax.Localization,
[["MathMenu",id]].concat([].slice.call(arguments,1))
);
};
var isArray = MathJax.Object.isArray;
var isPC = HUB.Browser.isPC, isMSIE = HUB.Browser.isMSIE, isIE9 = ((document.documentMode||0) > 8);
var ROUND = (isPC ? null : "5px");
var CONFIG = HUB.CombineConfig("MathMenu",{
delay: 150, // the delay for submenus
showRenderer: true, // show the "Math Renderer" menu?
showMathPlayer: true, // show the "MathPlayer" menu?
showFontMenu: false, // show the "Font Preference" menu?
showContext: false, // show the "Context Menu" menu?
showDiscoverable: false, // show the "Discoverable" menu?
showLocale: true, // show the "Locale" menu?
showLocaleURL: false, // show the "Load from URL" menu?
semanticsAnnotations: {
"TeX": ["TeX", "LaTeX", "application/x-tex"],
"StarMath": ["StarMath 5.0"],
"Maple": ["Maple"],
"ContentMathML": ["MathML-Content", "application/mathml-content+xml"],
"OpenMath": ["OpenMath"]
},
windowSettings: { // for source window
status: "no", toolbar: "no", locationbar: "no", menubar: "no",
directories: "no", personalbar: "no", resizable: "yes", scrollbars: "yes",
width: 400, height: 300,
left: Math.round((screen.width - 400)/2),
top: Math.round((screen.height - 300)/3)
},
styles: {
"#MathJax_About": {
position:"fixed", left:"50%", width:"auto", "text-align":"center",
border:"3px outset", padding:"1em 2em", "background-color":"#DDDDDD", color:"black",
cursor: "default", "font-family":"message-box", "font-size":"120%",
"font-style":"normal", "text-indent":0, "text-transform":"none",
"line-height":"normal", "letter-spacing":"normal", "word-spacing":"normal",
"word-wrap":"normal", "white-space":"nowrap", "float":"none", "z-index":201,
"border-radius": "15px", // Opera 10.5 and IE9
"-webkit-border-radius": "15px", // Safari and Chrome
"-moz-border-radius": "15px", // Firefox
"-khtml-border-radius": "15px", // Konqueror
"box-shadow":"0px 10px 20px #808080", // Opera 10.5 and IE9
"-webkit-box-shadow":"0px 10px 20px #808080", // Safari 3 and Chrome
"-moz-box-shadow":"0px 10px 20px #808080", // Forefox 3.5
"-khtml-box-shadow":"0px 10px 20px #808080", // Konqueror
filter: "progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true')" // IE
},
"#MathJax_About.MathJax_MousePost": {
outline:"none"
},
".MathJax_Menu": {
position:"absolute", "background-color":"white", color:"black",
width:"auto", padding:(isPC ? "2px" : "5px 0px"),
border:"1px solid #CCCCCC", margin:0, cursor:"default",
font: "menu", "text-align":"left", "text-indent":0, "text-transform":"none",
"line-height":"normal", "letter-spacing":"normal", "word-spacing":"normal",
"word-wrap":"normal", "white-space":"nowrap", "float":"none", "z-index":201,
"border-radius": ROUND, // Opera 10.5 and IE9
"-webkit-border-radius": ROUND, // Safari and Chrome
"-moz-border-radius": ROUND, // Firefox
"-khtml-border-radius": ROUND, // Konqueror
"box-shadow":"0px 10px 20px #808080", // Opera 10.5 and IE9
"-webkit-box-shadow":"0px 10px 20px #808080", // Safari 3 and Chrome
"-moz-box-shadow":"0px 10px 20px #808080", // Forefox 3.5
"-khtml-box-shadow":"0px 10px 20px #808080", // Konqueror
filter: "progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true')" // IE
},
".MathJax_MenuItem": {
padding: (isPC ? "2px 2em" : "1px 2em"),
background:"transparent"
},
".MathJax_MenuArrow": {
position:"absolute", right:".5em", "padding-top":".25em", color:"#666666",
"font-family": (isMSIE ? "'Arial unicode MS'" : null), "font-size": ".75em"
},
".MathJax_MenuActive .MathJax_MenuArrow": {color:"white"},
".MathJax_MenuArrow.RTL": {left:".5em", right:"auto"},
".MathJax_MenuCheck": {
position:"absolute", left:".7em",
"font-family": (isMSIE ? "'Arial unicode MS'" : null)
},
".MathJax_MenuCheck.RTL": {right:".7em", left:"auto"},
".MathJax_MenuRadioCheck": {
position:"absolute", left: (isPC ? "1em" : ".7em")
},
".MathJax_MenuRadioCheck.RTL": {
right: (isPC ? "1em" : ".7em"), left:"auto"
},
".MathJax_MenuLabel": {
padding: (isPC ? "2px 2em 4px 1.33em" : "1px 2em 3px 1.33em"),
"font-style":"italic"
},
".MathJax_MenuRule": {
"border-top": (isPC ? "1px solid #CCCCCC" : "1px solid #DDDDDD"),
margin: (isPC ? "4px 1px 0px" : "4px 3px")
},
".MathJax_MenuDisabled": {
color:"GrayText"
},
".MathJax_MenuActive": {
"background-color": (isPC ? "Highlight" : "#606872"),
color: (isPC ? "HighlightText" : "white")
},
".MathJax_MenuDisabled:focus, .MathJax_MenuLabel:focus": {
"background-color": "#E8E8E8"
},
".MathJax_ContextMenu:focus": {
outline:"none"
},
".MathJax_ContextMenu .MathJax_MenuItem:focus": {
outline:"none"
},
"#MathJax_AboutClose": {
top:".2em", right:".2em"
},
".MathJax_Menu .MathJax_MenuClose": {
top:"-10px", left:"-10px"
},
".MathJax_MenuClose": {
position:"absolute",
cursor:"pointer",
display:"inline-block",
border:"2px solid #AAA",
"border-radius":"18px",
"-webkit-border-radius": "18px", // Safari and Chrome
"-moz-border-radius": "18px", // Firefox
"-khtml-border-radius": "18px", // Konqueror
"font-family":"'Courier New',Courier",
"font-size":"24px",
color:"#F0F0F0"
},
".MathJax_MenuClose span": {
display:"block", "background-color":"#AAA", border:"1.5px solid",
"border-radius":"18px",
"-webkit-border-radius": "18px", // Safari and Chrome
"-moz-border-radius": "18px", // Firefox
"-khtml-border-radius": "18px", // Konqueror
"line-height":0,
padding:"8px 0 6px" // may need to be browser-specific
},
".MathJax_MenuClose:hover": {
color:"white!important",
border:"2px solid #CCC!important"
},
".MathJax_MenuClose:hover span": {
"background-color":"#CCC!important"
},
".MathJax_MenuClose:hover:focus": {
outline:"none"
}
}
});
var FALSE, HOVER, KEY;
HUB.Register.StartupHook("MathEvents Ready",function () {
FALSE = MathJax.Extension.MathEvents.Event.False;
HOVER = MathJax.Extension.MathEvents.Hover;
KEY = MathJax.Extension.MathEvents.Event.KEY;
});
/*************************************************************/
/*
* Abstract class of all keyboard navigatable objects.
*/
var NAV = MathJax.Object.Subclass({
/*
* Moving in the list of items.
*/
Keydown: function(event, menu) {
switch (event.keyCode) {
case KEY.ESCAPE:
this.Remove(event, menu);
break;
case KEY.RIGHT:
this.Right(event, menu);
break;
case KEY.LEFT:
this.Left(event, menu);
break;
case KEY.UP:
this.Up(event, menu);
break;
case KEY.DOWN:
this.Down(event, menu);
break;
case KEY.RETURN:
case KEY.SPACE:
this.Space(event, menu);
break;
default:
return;
break;
}
return FALSE(event);
},
Escape: function(event, menu) { },
Right: function(event, menu) { },
Left: function(event, menu) { },
Up: function(event, menu) { },
Down: function(event, menu) { },
Space: function(event, menu) { }
}, {});
/*************************************************************/
/*
* The main menu class
*/
var MENU = MathJax.Menu = NAV.Subclass({
version: VERSION,
items: [],
posted: false,
title: null,
margin: 5,
Init: function (def) {this.items = [].slice.call(arguments,0)},
With: function (def) {if (def) {HUB.Insert(this,def)}; return this},
/*
* Display the menu
*/
Post: function (event,parent,forceLTR) {
if (!event) {event = window.event||{}}
var div = document.getElementById("MathJax_MenuFrame");
if (!div) {
div = MENU.Background(this);
delete ITEM.lastItem; delete ITEM.lastMenu;
delete MENU.skipUp;
SIGNAL.Post(["post",MENU.jax]);
MENU.isRTL = (MathJax.Localization.fontDirection() === "rtl");
}
var menu = HTML.Element("div",{
onmouseup: MENU.Mouseup, ondblclick: FALSE,
ondragstart: FALSE, onselectstart: FALSE, oncontextmenu: FALSE,
menuItem: this, className: "MathJax_Menu", onkeydown: MENU.Keydown,
role: "menu"
});
if (event.type === "contextmenu" || event.type === "mouseover")
menu.className += " MathJax_ContextMenu";
if (!forceLTR) {MathJax.Localization.setCSS(menu)}
for (var i = 0, m = this.items.length; i < m; i++) {this.items[i].Create(menu)}
if (MENU.isMobile) {
HTML.addElement(menu,"span",{
className: "MathJax_MenuClose", menu: parent,
ontouchstart: MENU.Close, ontouchend: FALSE, onmousedown: MENU.Close, onmouseup: FALSE
},[["span",{},"\u00D7"]]);
}
div.appendChild(menu);
this.posted = true;
if (menu.offsetWidth) menu.style.width = (menu.offsetWidth+2) + "px";
var x = event.pageX, y = event.pageY;
var bbox = document.body.getBoundingClientRect();
var styles = (window.getComputedStyle ? window.getComputedStyle(document.body) : {marginLeft: "0px"});
var bodyRight = bbox.right - Math.min(0,bbox.left) + parseFloat(styles.marginLeft);
if (!x && !y && "clientX" in event) {
x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
if (!parent) {
var node = MENU.CurrentNode() || event.target;
if ((event.type === "keydown" || (!x && !y)) && node) {
var offsetX = window.pageXOffset || document.documentElement.scrollLeft;
var offsetY = window.pageYOffset || document.documentElement.scrollTop;
var rect = node.getBoundingClientRect();
x = (rect.right + rect.left) / 2 + offsetX;
y = (rect.bottom + rect.top) / 2 + offsetY;
}
if (x + menu.offsetWidth > bodyRight - this.margin)
{x = bodyRight - menu.offsetWidth - this.margin}
if (MENU.isMobile) {x = Math.max(5,x-Math.floor(menu.offsetWidth/2)); y -= 20}
MENU.skipUp = event.isContextMenu;
} else {
var side = "left", mw = parent.offsetWidth;
x = (MENU.isMobile ? 30 : mw - 2); y = 0;
while (parent && parent !== div) {
x += parent.offsetLeft; y += parent.offsetTop;
parent = parent.parentNode;
}
if (!MENU.isMobile) {
if ((MENU.isRTL && x - mw - menu.offsetWidth > this.margin) ||
(!MENU.isRTL && x + menu.offsetWidth > bodyRight - this.margin))
{side = "right"; x = Math.max(this.margin,x - mw - menu.offsetWidth + 6)}
}
if (!isPC) {
// in case these ever get implemented
menu.style["borderRadiusTop"+side] = 0; // Opera 10.5
menu.style["WebkitBorderRadiusTop"+side] = 0; // Safari and Chrome
menu.style["MozBorderRadiusTop"+side] = 0; // Firefox
menu.style["KhtmlBorderRadiusTop"+side] = 0; // Konqueror
}
}
menu.style.left = x+"px"; menu.style.top = y+"px";
if (document.selection && document.selection.empty) {document.selection.empty()}
// Focusing while keeping the scroll position.
var oldX = window.pageXOffset || document.documentElement.scrollLeft;
var oldY = window.pageYOffset || document.documentElement.scrollTop;
MENU.Focus(menu);
if (event.type === "keydown") {
MENU.skipMouseoverFromKey = true;
setTimeout(function() {delete MENU.skipMouseoverFromKey;}, CONFIG.delay);
}
window.scrollTo(oldX, oldY);
return FALSE(event);
},
/*
* Remove the menu from the screen
*/
Remove: function (event,menu) {
SIGNAL.Post(["unpost",MENU.jax]);
var div = document.getElementById("MathJax_MenuFrame");
if (div) {
div.parentNode.removeChild(div);
if (this.msieFixedPositionBug) {detachEvent("onresize",MENU.Resize)}
}
if (MENU.jax.hover) {
delete MENU.jax.hover.nofade;
HOVER.UnHover(MENU.jax);
}
MENU.Unfocus(menu);
if (event.type === "mousedown") MENU.CurrentNode().blur();
return FALSE(event);
},
/*
* Find an item in a menu (or submenu) by name (Find) or ID (FindID).
* A list of names or IDs means descend into submenus.
*/
Find: function (name) {return this.FindN(1,name,[].slice.call(arguments,1))},
FindId: function (name) {return this.FindN(0,name,[].slice.call(arguments,1))},
FindN: function (n,name,names) {
for (var i = 0, m = this.items.length; i < m; i++) {
if (this.items[i].name[n] === name) {
if (names.length) {
if (!this.items[i].submenu) {return null}
return this.items[i].submenu.FindN(n,names[0],names.slice(1));
}
return this.items[i];
}
}
return null;
},
/*
* Find the index of a menu item (so we can insert before or after it)
*/
IndexOf: function (name) {return this.IndexOfN(1,name)},
IndexOfId: function (name) {return this.IndexOfN(0,name)},
IndexOfN: function (n,name) {
for (var i = 0, m = this.items.length; i < m; i++)
{if (this.items[i].name[n] === name) {return i}}
return null;
},
Right: function(event, menu) {
MENU.Right(event, menu);
},
Left: function(event, menu) {
MENU.Left(event, menu);
},
Up: function(event, menu) {
var node = menu.lastChild;
node.menuItem.Activate(event, node);
},
Down: function(event, menu) {
var node = menu.firstChild;
node.menuItem.Activate(event, node);
},
Space: function(event, menu) {
this.Remove(event, menu);
}
},{
config: CONFIG,
Remove: function (event) {return MENU.Event(event,this,"Remove")},
Mouseover: function (event) {return MENU.Event(event,this,"Mouseover")},
Mouseout: function (event) {return MENU.Event(event,this,"Mouseout")},
Mousedown: function (event) {return MENU.Event(event,this,"Mousedown")},
Mouseup: function (event) {return MENU.Event(event,this,"Mouseup")},
Keydown: function (event) {return MENU.Event(event,this,"Keydown")},
/*
* Events for mobile devices.
*/
Touchstart: function (event) {return MENU.Event(event,this,"Touchstart")},
Touchend: function (event) {return MENU.Event(event,this,"Touchend")},
Close: function (event) {
return MENU.Event(event,this.menu||this.parentNode,(this.menu?"Touchend":"Remove"));
},
Event: function (event,menu,type,force) {
if (MENU.skipMouseover && type === "Mouseover" && !force) {return FALSE(event)}
if (MENU.skipMouseoverFromKey && type === "Mouseover") {
delete MENU.skipMouseoverFromKey;
return FALSE(event);
}
if (MENU.skipUp) {
if (type.match(/Mouseup|Touchend/)) {delete MENU.skipUp; return FALSE(event)}
if (type === "Touchstart" ||
(type === "Mousedown" && !MENU.skipMousedown)) {delete MENU.skipUp}
}
if (!event) {event = window.event}
var item = menu.menuItem;
if (item && item[type]) {return item[type](event,menu)}
return null;
},
/*
* Style for the background DIV
*/
BGSTYLE: {
position:"absolute", left:0, top:0, "z-index":200,
width:"100%", height:"100%", border:0, padding:0, margin:0
},
Background: function (menu) {
var div = HTML.addElement(document.body,"div",
{style:this.BGSTYLE, id:"MathJax_MenuFrame"},
[["div",{style: this.BGSTYLE, menuItem: menu, onmousedown: this.Remove}]]);
var bg = div.firstChild;
if (MENU.msieBackgroundBug) {
// MSIE doesn't allow transparent background to be hit boxes, so
// fake it using opacity with solid background color
bg.style.backgroundColor = "white"; bg.style.filter = "alpha(opacity=0)";
}
if (MENU.msieFixedPositionBug) {
// MSIE can't do fixed position, so use a full-sized background
// and an onresize handler to update it (stupid, but necessary)
div.width = div.height = 0; this.Resize();
attachEvent("onresize",this.Resize);
} else {
// otherwise, use a fixed position DIV to cover the viewport
bg.style.position = "fixed";
}
return div;
},
Resize: function () {setTimeout(MENU.SetWH,0)},
SetWH: function () {
var bg = document.getElementById("MathJax_MenuFrame");
if (bg) {
bg = bg.firstChild;
bg.style.width = bg.style.height = "1px"; // so scrollWidth/Height will be right below
bg.style.width = document.body.scrollWidth + "px";
bg.style.height = document.body.scrollHeight + "px";
}
},
/*************************************************************/
/*
* Keyboard navigation of menu.
*/
posted: false, // Is a menu open?
active: null, // The focused in HTML node in the menu.
GetNode: function(jax) {
var node = document.getElementById(jax.inputID + "-Frame");
return node.isMathJax ? node : node.firstChild;
},
CurrentNode: function() {
return MENU.GetNode(MENU.jax);
},
AllNodes: function() {
var jaxs = MathJax.Hub.getAllJax();
var nodes = [];
for (var i = 0, jax; jax = jaxs[i]; i++) {
nodes.push(MENU.GetNode(jax));
}
return nodes;
},
ActiveNode: function() {
return MENU.active;
},
FocusNode: function(node) {
MENU.active = node;
node.focus();
},
//
// Focus is a global affair, since we only ever want a single focused item.
//
Focus: function(menu) {
!MENU.posted ? MENU.Activate(menu) : MENU.ActiveNode().tabIndex = -1;
menu.tabIndex = 0;
MENU.FocusNode(menu);
},
Activate: function(event, menu) {
MENU.UnsetTabIndex();
MENU.posted = true;
},
Unfocus: function() {
MENU.ActiveNode().tabIndex = -1;
MENU.SetTabIndex();
MENU.FocusNode(MENU.CurrentNode());
MENU.posted = false;
},
MoveHorizontal: function(event, menu, move) {
if (!event.shiftKey) return;
var jaxs = MENU.AllNodes();
var len = jaxs.length;
if (len === 0) return;
var next = jaxs[MENU.Mod(move(MENU.IndexOf(jaxs, MENU.CurrentNode())), len)];
if (next === MENU.CurrentNode()) return;
MENU.menu.Remove(event, menu);
MENU.jax = MathJax.Hub.getJaxFor(next);
MENU.FocusNode(next);
MENU.menu.Post(null);
},
Right: function(event, menu) {
MENU.MoveHorizontal(event, menu, function(x) {return x + 1;});
},
Left: function(event, menu) {
MENU.MoveHorizontal(event, menu, function(x) {return x - 1;});
},
UnsetTabIndex: function () {
var jaxs = MENU.AllNodes();
for (var j = 0, jax; jax = jaxs[j]; j++) {
if (jax.tabIndex > 0) {
jax.oldTabIndex = jax.tabIndex;
}
jax.tabIndex = -1;
}
},
SetTabIndex: function () {
var jaxs = MENU.AllNodes();
for (var j = 0, jax; jax = jaxs[j]; j++) {
if (jax.oldTabIndex !== undefined) {
jax.tabIndex = jax.oldTabIndex
delete jax.oldTabIndex;
} else {
jax.tabIndex = HUB.getTabOrder(jax);
}
}
},
//TODO: Move to utility class.
// Computes a mod n.
Mod: function(a, n) {
return ((a % n) + n) % n;
},
IndexOf: (Array.prototype.indexOf ?
function (A, item, start) {return A.indexOf(item, start);} :
function (A, item, start) {
for (var i = (start || 0), j = A.length; i < j; i++) {
if (item === A[i]) return i;
}
return -1;
}),
saveCookie: function () {HTML.Cookie.Set("menu",this.cookie)},
getCookie: function () {this.cookie = HTML.Cookie.Get("menu")}
});
MathJax.Menu.NAV = NAV;
/*************************************************************/
/*
* Abstract class of menu items.
*/
var ITEM = MENU.ITEM = NAV.Subclass({
name: "", // The menu item's label as [id,label] pair.
node: null, // The HTML node of the item.
menu: null, // The parent menu containing that item. HTML node.
Attributes: function(def) {
return HUB.Insert(
{onmouseup: MENU.Mouseup,
ondragstart: FALSE, onselectstart: FALSE, onselectend: FALSE,
ontouchstart: MENU.Touchstart, ontouchend: MENU.Touchend,
className: "MathJax_MenuItem", role: this.role,
menuItem: this},
def);
},
Create: function (menu) {
if (!this.hidden) {
var def = this.Attributes();
var label = this.Label(def,menu);
HTML.addElement(menu, "div", def, label);
}
},
Name: function () {return _(this.name[0],this.name[1])},
Mouseover: function (event,menu) {
if (menu.parentNode === MENU.ActiveNode().parentNode) {
this.Deactivate(MENU.ActiveNode());
}
this.Activate(event, menu);
},
Mouseout: function (event,menu) {
this.Deactivate(menu);
},
Mouseup: function (event,menu) {return this.Remove(event,menu)},
DeactivateSubmenus: function(menu) {
var menus = document.getElementById("MathJax_MenuFrame").childNodes,
items = ITEM.GetMenuNode(menu).childNodes;
for (var i = 0, m = items.length; i < m; i++) {
var item = items[i].menuItem;
// Deactivates submenu items.
if (item && item.submenu && item.submenu.posted &&
item !== menu.menuItem) {
item.Deactivate(items[i]);
}
}
this.RemoveSubmenus(menu, menus);
},
RemoveSubmenus: function(menu, menus) {
menus = menus || document.getElementById("MathJax_MenuFrame").childNodes;
var m = menus.length-1;
while (m >= 0 && ITEM.GetMenuNode(menu).menuItem !== menus[m].menuItem) {
menus[m].menuItem.posted = false;
menus[m].parentNode.removeChild(menus[m]);
m--;
}
},
Touchstart: function (event,menu) {return this.TouchEvent(event,menu,"Mousedown")},
Touchend: function (event,menu) {return this.TouchEvent(event,menu,"Mouseup")},
TouchEvent: function (event,menu,type) {
if (this !== ITEM.lastItem) {
if (ITEM.lastMenu) {MENU.Event(event,ITEM.lastMenu,"Mouseout")}
MENU.Event(event,menu,"Mouseover",true);
ITEM.lastItem = this; ITEM.lastMenu = menu;
}
if (this.nativeTouch) {return null}
MENU.Event(event,menu,type);
return false;
},
Remove: function (event,menu) {
menu = menu.parentNode.menuItem;
return menu.Remove(event,menu);
},
With: function (def) {if (def) {HUB.Insert(this,def)}; return this},
isRTL: function () {return MENU.isRTL},
rtlClass: function () {return (this.isRTL() ? " RTL" : "")}
}, {
GetMenuNode: function(item) {
return item.parentNode;
}
});
/*************************************************************/
/*
* Abstract class of menu items that are focusable and perform some action
*/
MENU.ENTRY = MENU.ITEM.Subclass({
role: "menuitem", // Aria role.
Attributes: function(def) {
def = HUB.Insert(
{onmouseover: MENU.Mouseover, onmouseout: MENU.Mouseout,
onmousedown: MENU.Mousedown, onkeydown: MENU.Keydown,
"aria-disabled": !!this.disabled},
def);
def = this.SUPER(arguments).Attributes.call(this, def);
if (this.disabled) {
def.className += " MathJax_MenuDisabled";
}
return def;
},
MoveVertical: function(event, item, move) {
var menuNode = ITEM.GetMenuNode(item);
var items = [];
for (var i = 0, allItems = menuNode.menuItem.items, it;
it = allItems[i]; i++) {
if (!it.hidden) {
items.push(it);
}
}
var index = MENU.IndexOf(items, this);
if (index === -1) return;
var len = items.length;
var children = menuNode.childNodes;
do {
index = MENU.Mod(move(index), len);
} while (items[index].hidden || !children[index].role ||
children[index].role === "separator");
this.Deactivate(item);
items[index].Activate(event, children[index]);
},
Up: function(event, item) {
this.MoveVertical(event, item, function(x) { return x - 1; });
},
Down: function(event, item) {
this.MoveVertical(event, item, function(x) { return x + 1; });
},
Right: function(event, item) {
this.MoveHorizontal(event, item, MENU.Right, !this.isRTL());
},
Left: function(event, item) {
this.MoveHorizontal(event, item, MENU.Left, this.isRTL());
},
MoveHorizontal: function(event, item, move, rtl) {
var menuNode = ITEM.GetMenuNode(item);
if (menuNode.menuItem === MENU.menu && event.shiftKey) {
move(event, item);
}
if (rtl) return;
if (menuNode.menuItem !== MENU.menu) {
this.Deactivate(item);
}
var parentNodes = menuNode.previousSibling.childNodes;
var length = parentNodes.length;
while (length--) {
var parent = parentNodes[length];
if (parent.menuItem.submenu &&
parent.menuItem.submenu === menuNode.menuItem) {
MENU.Focus(parent);
break;
}
}
this.RemoveSubmenus(item);
},
Space: function (event, menu) {
this.Mouseup(event, menu);
},
Activate: function (event, menu) {
this.Deactivate(menu);
if (!this.disabled) {
menu.className += " MathJax_MenuActive";
}
this.DeactivateSubmenus(menu);
MENU.Focus(menu);
},
Deactivate: function (menu) {
menu.className = menu.className.replace(/ MathJax_MenuActive/,"");
}
});
/*************************************************************/
/*
* A menu item that performs a command when selected
*/
MENU.ITEM.COMMAND = MENU.ENTRY.Subclass({
action: function () {},
Init: function (name,action,def) {
if (!isArray(name)) {name = [name,name]} // make [id,label] pair
this.name = name; this.action = action;
this.With(def);
},
Label: function (def,menu) {return [this.Name()]},
Mouseup: function (event,menu) {
if (!this.disabled) {
this.Remove(event,menu);
SIGNAL.Post(["command",this]);
this.action.call(this,event);
}
return FALSE(event);
}
});
/*************************************************************/
/*
* A menu item that posts a submenu
*/
MENU.ITEM.SUBMENU = MENU.ENTRY.Subclass({
submenu: null, // the submenu
marker: "\u25BA", // the submenu arrow
markerRTL: "\u25C4", // the submenu arrow for RTL
Attributes: function(def) {
def = HUB.Insert({"aria-haspopup": "true"}, def);
def = this.SUPER(arguments).Attributes.call(this, def);
return def;
},
Init: function (name,def) {
if (!isArray(name)) {name = [name,name]} // make [id,label] pair
this.name = name; var i = 1;
if (!(def instanceof MENU.ITEM)) {this.With(def), i++}
this.submenu = MENU.apply(MENU,[].slice.call(arguments,i));
},
Label: function (def,menu) {
this.submenu.posted = false;
return [this.Name()+" ",["span",{
className:"MathJax_MenuArrow" + this.rtlClass()
},[this.isRTL() ? this.markerRTL : this.marker]]];
},
Timer: function (event,menu) {
this.ClearTimer();
event = {type: event.type,
clientX: event.clientX, clientY: event.clientY}; // MSIE can't pass the event below
this.timer = setTimeout(CALLBACK(["Mouseup",this,event,menu]),CONFIG.delay);
},
ClearTimer: function() {
if (this.timer) {
clearTimeout(this.timer);
}
},
Touchend: function (event,menu) {
var forceout = this.submenu.posted;
var result = this.SUPER(arguments).Touchend.apply(this,arguments);
if (forceout) {this.Deactivate(menu); delete ITEM.lastItem; delete ITEM.lastMenu}
return result;
},
Mouseout: function(event, menu) {
if (!this.submenu.posted) {
this.Deactivate(menu);
}
this.ClearTimer();
},
Mouseover: function(event, menu) {
this.Activate(event, menu);
},
Mouseup: function (event,menu) {
if (!this.disabled) {
if (!this.submenu.posted) {
this.ClearTimer();
this.submenu.Post(event, menu, this.ltr);
MENU.Focus(menu);
} else {
this.DeactivateSubmenus(menu);
}
}
return FALSE(event);
},
Activate: function (event, menu) {
if (!this.disabled) {
this.Deactivate(menu);
menu.className += " MathJax_MenuActive";
}
if (!this.submenu.posted) {
this.DeactivateSubmenus(menu);
if (!MENU.isMobile) {
this.Timer(event,menu);
}
}
MENU.Focus(menu);
},
MoveVertical: function(event, item, move) {
this.ClearTimer();
this.SUPER(arguments).MoveVertical.apply(this, arguments);
},
MoveHorizontal: function(event, menu, move, rtl) {
if (!rtl) {
this.SUPER(arguments).MoveHorizontal.apply(this, arguments);
return;
}
if (this.disabled) return;
if (!this.submenu.posted) {
this.Activate(event, menu);
return;
}
var submenuNodes = ITEM.GetMenuNode(menu).nextSibling.childNodes;
if (submenuNodes.length > 0) {
this.submenu.items[0].Activate(event, submenuNodes[0]);
}
}
});
/*************************************************************/
/*
* A menu item that is one of several radio buttons
*/
MENU.ITEM.RADIO = MENU.ENTRY.Subclass({
variable: null, // the variable name
marker: (isPC ? "\u25CF" : "\u2713"), // the checkmark
role: "menuitemradio",
Attributes: function(def) {
var checked = CONFIG.settings[this.variable] === this.value ? "true" : "false";
def = HUB.Insert({"aria-checked": checked}, def);
def = this.SUPER(arguments).Attributes.call(this, def);
return def;
},
Init: function (name,variable,def) {
if (!isArray(name)) {name = [name,name]} // make [id,label] pair
this.name = name; this.variable = variable; this.With(def);
if (this.value == null) {this.value = this.name[0]}
},
Label: function (def,menu) {
var span = {className:"MathJax_MenuRadioCheck" + this.rtlClass()};
if (CONFIG.settings[this.variable] !== this.value) {
span = {style:{display:"none"}};
}
return [["span",span,[this.marker]]," "+this.Name()];
},
Mouseup: function (event,menu) {
if (!this.disabled) {
var child = menu.parentNode.childNodes;
for (var i = 0, m = child.length; i < m; i++) {
var item = child[i].menuItem;
if (item && item.variable === this.variable) {
child[i].firstChild.style.display = "none";
}
}
menu.firstChild.display = "";
CONFIG.settings[this.variable] = this.value;
MENU.cookie[this.variable] = CONFIG.settings[this.variable]; MENU.saveCookie();
SIGNAL.Post(["radio button",this]);
}
this.Remove(event,menu);
if (this.action && !this.disabled) {this.action.call(MENU,this)}
return FALSE(event);
}
});
/*************************************************************/
/*
* A menu item that is checkable
*/
MENU.ITEM.CHECKBOX = MENU.ENTRY.Subclass({
variable: null, // the variable name
marker: "\u2713", // the checkmark
role: "menuitemcheckbox",
Attributes: function(def) {
var checked = CONFIG.settings[this.variable] ? "true" : "false";
def = HUB.Insert({"aria-checked": checked}, def);
def = this.SUPER(arguments).Attributes.call(this, def);
return def;
},
Init: function (name,variable,def) {
if (!isArray(name)) {name = [name,name]} // make [id,label] pair
this.name = name; this.variable = variable; this.With(def);
},
Label: function (def,menu) {
var span = {className:"MathJax_MenuCheck" + this.rtlClass()};
if (!CONFIG.settings[this.variable]) {span = {style:{display:"none"}}}
return [["span",span,[this.marker]]," "+this.Name()];
},
Mouseup: function (event,menu) {
if (!this.disabled) {
menu.firstChild.display = (CONFIG.settings[this.variable] ? "none" : "");
CONFIG.settings[this.variable] = !CONFIG.settings[this.variable];
MENU.cookie[this.variable] = CONFIG.settings[this.variable]; MENU.saveCookie();
SIGNAL.Post(["checkbox",this]);
}
this.Remove(event,menu);
if (this.action && !this.disabled) {this.action.call(MENU,this)}
return FALSE(event);
}
});
/*************************************************************/
/*
* A menu item that is a label
*/
MENU.ITEM.LABEL = MENU.ENTRY.Subclass({
role: "menuitem", // Aria role.
Init: function (name,def) {
if (!isArray(name)) {name = [name,name]} // make [id,label] pair
this.name = name; this.With(def);
},
Label: function (def,menu) {
def.className += " MathJax_MenuLabel";
return [this.Name()];
},
Activate: function(event, menu) {
this.Deactivate(menu);
MENU.Focus(menu);
},
Mouseup: function (event,menu) { }
});
/*************************************************************/
/*
* A rule in a menu
*/
MENU.ITEM.RULE = MENU.ITEM.Subclass({
role: "separator",
Attributes: function(def) {
def = HUB.Insert({"aria-orientation": "vertical"}, def);
def = this.SUPER(arguments).Attributes.call(this, def);
return def;
},
Label: function (def,menu) {
def.className += " MathJax_MenuRule";
return null;
}
});
/*************************************************************/
/*************************************************************/
/*
* Handle the ABOUT box
*/
MENU.About = function (event) {
var font = MENU.About.GetFont();
var format = MENU.About.GetFormat();
var jax = ["MathJax.js v"+MathJax.fileversion,["br"]];
jax.push(["div",{style:{"border-top":"groove 2px",margin:".25em 0"}}]);
MENU.About.GetJax(jax,MathJax.InputJax,["InputJax","%1 Input Jax v%2"]);
MENU.About.GetJax(jax,MathJax.OutputJax,["OutputJax","%1 Output Jax v%2"]);
MENU.About.GetJax(jax,MathJax.ElementJax,["ElementJax","%1 Element Jax v%2"]);
jax.push(["div",{style:{"border-top":"groove 2px",margin:".25em 0"}}]);
MENU.About.GetJax(jax,MathJax.Extension,["Extension","%1 Extension v%2"],true);
jax.push(["div",{style:{"border-top":"groove 2px",margin:".25em 0"}}],["center",{},[
HUB.Browser + " v"+HUB.Browser.version + (format ?
" \u2014 " + _(format.replace(/ /g,""),format) : "")
]]);
MENU.About.div = MENU.Background(MENU.About);
var about = HTML.addElement(MENU.About.div,"div",{
id: "MathJax_About", tabIndex: 0, onkeydown: MENU.About.Keydown
},[
["b",{style:{fontSize:"120%"}},["MathJax"]]," v"+MathJax.version,["br"],
_(font.replace(/ /g,""),"using "+font),["br"],["br"],
["span",{style:{
display:"inline-block", "text-align":"left", "font-size":"80%",
"max-height":"20em", overflow:"auto",
"background-color":"#E4E4E4", padding:".4em .6em", border:"1px inset"
}, tabIndex: 0},jax],["br"],["br"],
["a",{href:"http://www.mathjax.org/"},["www.mathjax.org"]],
["span",{className:"MathJax_MenuClose",id:"MathJax_AboutClose",
onclick:MENU.About.Remove,
onkeydown: MENU.About.Keydown, tabIndex: 0, role: "button",
"aria-label": _("CloseAboutDialog","Close about MathJax dialog")},
[["span",{},"\u00D7"]]]
]);
if (event.type === "mouseup") about.className += " MathJax_MousePost";
about.focus();
MathJax.Localization.setCSS(about);
var doc = (document.documentElement||{});
var H = window.innerHeight || doc.clientHeight || doc.scrollHeight || 0;
if (MENU.prototype.msieAboutBug) {
about.style.width = "20em"; about.style.position = "absolute";
about.style.left = Math.floor((document.documentElement.scrollWidth - about.offsetWidth)/2)+"px";
about.style.top = (Math.floor((H-about.offsetHeight)/3)+document.body.scrollTop)+"px";
} else {
about.style.marginLeft = Math.floor(-about.offsetWidth/2)+"px";
about.style.top = Math.floor((H-about.offsetHeight)/3)+"px";
}
};
MENU.About.Remove = function (event) {
if (MENU.About.div) {document.body.removeChild(MENU.About.div); delete MENU.About.div}
};
MENU.About.Keydown = function(event) {
if (event.keyCode === KEY.ESCAPE ||
(this.id === "MathJax_AboutClose" &&
(event.keyCode === KEY.SPACE || event.keyCode === KEY.RETURN))) {
MENU.About.Remove(event);
MENU.CurrentNode().focus();
FALSE(event);
}
},
MENU.About.GetJax = function (jax,JAX,type,noTypeCheck) {
var info = [];
for (var id in JAX) {if (JAX.hasOwnProperty(id) && JAX[id]) {
if ((noTypeCheck && JAX[id].version) || (JAX[id].isa && JAX[id].isa(JAX)))
{info.push(_(type[0],type[1],(JAX[id].id||id),JAX[id].version))}
}}
info.sort();
for (var i = 0, m = info.length; i < m; i++) {jax.push(info[i],["br"])}
return jax;
};
MENU.About.GetFont = function () {
var jax = MathJax.Hub.outputJax["jax/mml"][0] || {};
var font = {
SVG: "web SVG",
CommonHTML: "web TeX",
"HTML-CSS": (jax.imgFonts ? "image" : (jax.webFonts ? "web" : "local")+" "+jax.fontInUse)
}[jax.id] || "generic";
return font + " fonts";
};
MENU.About.GetFormat = function () {
var jax = MathJax.Hub.outputJax["jax/mml"][0] || {};
if (jax.id !== "HTML-CSS"|| !jax.webFonts || jax.imgFonts) return;
return jax.allowWebFonts.replace(/otf/,"woff or otf") + " fonts";
};
/*
* Handle the MathJax HELP menu
*/
MENU.Help = function (event) {
AJAX.Require("[MathJax]/extensions/HelpDialog.js",
function () {MathJax.Extension.Help.Dialog({type:event.type})});
};
/*
* Handle showing of element's source
*/
MENU.ShowSource = function (event) {
if (!event) {event = window.event}
var EVENT = {screenX:event.screenX, screenY:event.screenY};
if (!MENU.jax) return;
if (this.format === "MathML") {
var MML = MathJax.ElementJax.mml;
if (MML && typeof(MML.mbase.prototype.toMathML) !== "undefined") {
// toMathML() can call MathJax.Hub.RestartAfter, so trap errors and check
try {MENU.ShowSource.Text(MENU.jax.root.toMathML("",MENU.jax),event)} catch (err) {
if (!err.restart) {throw err}
CALLBACK.After([this,MENU.ShowSource,EVENT],err.restart);
}
} else if (!AJAX.loadingToMathML) {
AJAX.loadingToMathML = true;
MENU.ShowSource.Window(event); // WeBKit needs to open window on click event
CALLBACK.Queue(
AJAX.Require("[MathJax]/extensions/toMathML.js"),
function () {
delete AJAX.loadingToMathML;
if (!MML.mbase.prototype.toMathML) {MML.mbase.prototype.toMathML = function () {}}
},
[this,MENU.ShowSource,EVENT] // call this function again
);
return;
}
} else if (this.format === "Error") {
MENU.ShowSource.Text(MENU.jax.errorText,event);
} else if (CONFIG.semanticsAnnotations[this.format]) {
var annotation = MENU.jax.root.getAnnotation(this.format);
if (annotation.data[0]) MENU.ShowSource.Text(annotation.data[0].toString());
} else {
if (MENU.jax.originalText == null) {
alert(_("NoOriginalForm","No original form available"));
return;
}
MENU.ShowSource.Text(MENU.jax.originalText,event);
}
};
MENU.ShowSource.Window = function (event) {
if (!MENU.ShowSource.w) {
var def = [], DEF = CONFIG.windowSettings;
for (var id in DEF) {if (DEF.hasOwnProperty(id)) {def.push(id+"="+DEF[id])}}
MENU.ShowSource.w = window.open("","_blank",def.join(","));
}
return MENU.ShowSource.w;
};
MENU.ShowSource.Text = function (text,event) {
var w = MENU.ShowSource.Window(event); delete MENU.ShowSource.w;
text = text.replace(/^\s*/,"").replace(/\s*$/,"");
text = text.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
var title = _("EqSource","MathJax Equation Source");
if (MENU.isMobile) {
w.document.open();
w.document.write("<html><head><meta name='viewport' content='width=device-width, initial-scale=1.0' /><title>"+title+"</title></head><body style='font-size:85%'>");
w.document.write("<pre>"+text+"</pre>");
w.document.write("<hr><input type='button' value='"+_("Close","Close")+"' onclick='window.close()' />");
w.document.write("</body></html>");
w.document.close();
} else {
w.document.open();
w.document.write("<html><head><title>"+title+"</title></head><body style='font-size:85%'>");
w.document.write("<table><tr><td><pre>"+text+"</pre></td></tr></table>");
w.document.write("</body></html>");
w.document.close();
var table = w.document.body.firstChild;
setTimeout(function () {
var H = (w.outerHeight-w.innerHeight)||30, W = (w.outerWidth-w.innerWidth)||30, x, y;
W = Math.max(140,Math.min(Math.floor(.5*screen.width),table.offsetWidth+W+25));
H = Math.max(40,Math.min(Math.floor(.5*screen.height),table.offsetHeight+H+25));
if (MENU.prototype.msieHeightBug) {H += 35}; // for title bar in XP
w.resizeTo(W,H);
var X; try {X = event.screenX} catch (e) {}; // IE8 throws an error accessing screenX
if (event && X != null) {
x = Math.max(0,Math.min(event.screenX-Math.floor(W/2), screen.width-W-20));
y = Math.max(0,Math.min(event.screenY-Math.floor(H/2), screen.height-H-20));
w.moveTo(x,y);
}
},50);
}
};
/*
* Handle rescaling all the math
*/
MENU.Scale = function () {
var JAX = ["CommonHTML","HTML-CSS","SVG","NativeMML","PreviewHTML"], m = JAX.length,
SCALE = 100, i, jax;
for (i = 0; i < m; i++) {
jax = OUTPUT[JAX[i]];
if (jax) {SCALE = jax.config.scale; break}
}
var scale = prompt(_("ScaleMath","Scale all mathematics (compared to surrounding text) by"),SCALE+"%");
if (scale) {
if (scale.match(/^\s*\d+(\.\d*)?\s*%?\s*$/)) {
scale = parseFloat(scale);
if (scale) {
if (scale !== SCALE) {
for (i = 0; i < m; i++) {
jax = OUTPUT[JAX[i]];
if (jax) jax.config.scale = scale;
}
MENU.cookie.scale = HUB.config.scale = scale;
MENU.saveCookie();
HUB.Queue(["Rerender",HUB]);
}
} else {alert(_("NonZeroScale","The scale should not be zero"))}
} else {alert(_("PercentScale",
"The scale should be a percentage (e.g., 120%%)"))}
}
};
/*
* Handle loading the zoom code
*/
MENU.Zoom = function () {
if (!MathJax.Extension.MathZoom) {AJAX.Require("[MathJax]/extensions/MathZoom.js")}
};
/*
* Handle changing the renderer
*/
MENU.Renderer = function () {
var jax = HUB.outputJax["jax/mml"];
if (jax[0] !== CONFIG.settings.renderer) {
var BROWSER = HUB.Browser, message, MESSAGE = MENU.Renderer.Messages, warned;
//
// Check that the new renderer is appropriate for the browser
//
switch (CONFIG.settings.renderer) {
case "NativeMML":
if (!CONFIG.settings.warnedMML) {
if (BROWSER.isChrome && BROWSER.version.substr(0,3) !== "24.") {message = MESSAGE.MML.WebKit}
else if (BROWSER.isSafari && !BROWSER.versionAtLeast("5.0")) {message = MESSAGE.MML.WebKit}
else if (BROWSER.isMSIE) {if (!BROWSER.hasMathPlayer) {message = MESSAGE.MML.MSIE}}
else if (BROWSER.isEdge) {message = MESSAGE.MML.WebKit}
else {message = MESSAGE.MML[BROWSER]}
warned = "warnedMML";
}
break;
case "SVG":
if (!CONFIG.settings.warnedSVG) {
if (BROWSER.isMSIE && !isIE9) {message = MESSAGE.SVG.MSIE}
}
break;
}
if (message) {
message = _(message[0],message[1]);
message += "\n\n";
message += _("SwitchAnyway",
"Switch the renderer anyway?\n\n" +
"(Press OK to switch, CANCEL to continue with the current renderer)");
MENU.cookie.renderer = jax[0].id; MENU.saveCookie();
if (!confirm(message)) {
MENU.cookie.renderer = CONFIG.settings.renderer = HTML.Cookie.Get("menu").renderer;
MENU.saveCookie();
return;
}
if (warned) {MENU.cookie.warned = CONFIG.settings.warned = true}
MENU.cookie.renderer = CONFIG.settings.renderer; MENU.saveCookie();
}
HUB.Queue(
["setRenderer",HUB,CONFIG.settings.renderer,"jax/mml"],
["Rerender",HUB]
);
}
};
MENU.Renderer.Messages = {
MML: {
WebKit: ["WebkitNativeMMLWarning",
"Your browser doesn't seem to support MathML natively, " +
"so switching to MathML output may cause the mathematics " +
"on the page to become unreadable."],
MSIE: ["MSIENativeMMLWarning",
"Internet Explorer requires the MathPlayer plugin " +
"in order to process MathML output."],
Opera: ["OperaNativeMMLWarning",
"Opera's support for MathML is limited, so switching to " +
"MathML output may cause some expressions to render poorly."],
Safari: ["SafariNativeMMLWarning",
"Your browser's native MathML does not implement all the features " +
"used by MathJax, so some expressions may not render properly."],
Firefox: ["FirefoxNativeMMLWarning",
"Your browser's native MathML does not implement all the features " +
"used by MathJax, so some expressions may not render properly."]
},
SVG: {
MSIE: ["MSIESVGWarning",
"SVG is not implemented in Internet Explorer prior to " +
"IE9 or when it is emulating IE8 or below. " +
"Switching to SVG output will cause the mathematics to " +
"not display properly."]
}
};
/*
* Toggle assistive MML settings
*/
MENU.AssistiveMML = function (item,restart) {
var AMML = MathJax.Extension.AssistiveMML;
if (!AMML) {
// Try to load the extension, but only try once.
if (!restart)
AJAX.Require("[MathJax]/extensions/AssistiveMML.js",["AssistiveMML",MENU,item,true]);
return;
}
MathJax.Hub.Queue([(CONFIG.settings.assistiveMML ? "Add" : "Remove")+"AssistiveMathML",AMML]);
};
/*
* Handle setting the HTMLCSS fonts
*/
MENU.Font = function () {
var HTMLCSS = OUTPUT["HTML-CSS"]; if (!HTMLCSS) return;
document.location.reload();
};
/*
* Handle selection of locale and rerender the page
*/
MENU.Locale = function () {
MathJax.Localization.setLocale(CONFIG.settings.locale);
MathJax.Hub.Queue(["Reprocess",MathJax.Hub]); // FIXME: Just reprocess error messages?
};
MENU.LoadLocale = function () {
var url = prompt(_("LoadURL","Load translation data from this URL:"));
if (url) {
if (!url.match(/\.js$/)) {
alert(_("BadURL",
"The URL should be for a javascript file that defines MathJax translation data. " +
"Javascript file names should end with '.js'"
));
}
AJAX.Require(url,function (status) {
if (status != AJAX.STATUS.OK) {alert(_("BadData","Failed to load translation data from %1",url))}
});
}
};
/*
* Handle setting MathPlayer events
*/
MENU.MPEvents = function (item) {
var discoverable = CONFIG.settings.discoverable,
MESSAGE = MENU.MPEvents.Messages;
if (!isIE9) {
if (CONFIG.settings.mpMouse && !confirm(_.apply(_,MESSAGE.IE8warning))) {
delete MENU.cookie.mpContext; delete CONFIG.settings.mpContext;
delete MENU.cookie.mpMouse; delete CONFIG.settings.mpMouse;
MENU.saveCookie();
return;
}
CONFIG.settings.mpContext = CONFIG.settings.mpMouse;
MENU.cookie.mpContext = MENU.cookie.mpMouse = CONFIG.settings.mpMouse;
MENU.saveCookie();
MathJax.Hub.Queue(["Rerender",MathJax.Hub])
} else if (!discoverable && item.name[1] === "Menu Events" && CONFIG.settings.mpContext) {
alert(_.apply(_,MESSAGE.IE9warning));
}
};
MENU.MPEvents.Messages = {
IE8warning: ["IE8warning",
"This will disable the MathJax menu and zoom features, " +
"but you can Alt-Click on an expression to obtain the MathJax " +
"menu instead.\n\nReally change the MathPlayer settings?"],
IE9warning: ["IE9warning",
"The MathJax contextual menu will be disabled, but you can " +
"Alt-Click on an expression to obtain the MathJax menu instead."]
};
/*************************************************************/
/*************************************************************/
HUB.Browser.Select({
MSIE: function (browser) {
var quirks = (document.compatMode === "BackCompat");
var isIE8 = browser.versionAtLeast("8.0") && document.documentMode > 7;
MENU.Augment({
margin: 20,
msieBackgroundBug: ((document.documentMode||0) < 9),
msieFixedPositionBug: (quirks || !isIE8),
msieAboutBug: quirks,
msieHeightBug: ((document.documentMode||0) < 9)
// height of window doesn't include title bar in XP
});
if (isIE9) {
delete CONFIG.styles["#MathJax_About"].filter;
delete CONFIG.styles[".MathJax_Menu"].filter;
}
},
Firefox: function (browser) {
MENU.skipMouseover = browser.isMobile && browser.versionAtLeast("6.0");
MENU.skipMousedown = browser.isMobile;
}
});
MENU.isMobile = HUB.Browser.isMobile;
MENU.noContextMenu = HUB.Browser.noContextMenu;
/*************************************************************/
//
// Creates the locale menu from the list of locales in MathJax.Localization.strings
//
MENU.CreateLocaleMenu = function () {
if (!MENU.menu) return;
var menu = MENU.menu.Find("Language").submenu, items = menu.items;
//
// Get the names of the languages and sort them
//
var locales = [], LOCALE = MathJax.Localization.strings;
for (var id in LOCALE) {if (LOCALE.hasOwnProperty(id)) {locales.push(id)}}
locales = locales.sort(); menu.items = [];
//
// Add a menu item for each
//
for (var i = 0, m = locales.length; i < m; i++) {
var title = LOCALE[locales[i]].menuTitle;
if (title) {title += " ("+locales[i]+")"} else {title = locales[i]}
menu.items.push(ITEM.RADIO([locales[i],title],"locale",{action:MENU.Locale}));
}
//
// Add the rule and "Load from URL" items
//
menu.items.push(items[items.length-2],items[items.length-1]);
};
//
// Create the annotation menu from MathJax.Hub.config.semanticsAnnotations
//
MENU.CreateAnnotationMenu = function () {
if (!MENU.menu) return;
var menu = MENU.menu.Find("Show Math As","Annotation").submenu;
var annotations = CONFIG.semanticsAnnotations;
for (var a in annotations) {
if (annotations.hasOwnProperty(a)) {
menu.items.push(ITEM.COMMAND([a,a], MENU.ShowSource, {hidden: true, nativeTouch: true, format: a}));
}
}
};
/*************************************************************/
HUB.Register.StartupHook("End Config",function () {
/*
* Get the menu settings from the HUB (which includes the
* data from the cookie already), and add the format, if
* it wasn't set in the cookie.
*/
CONFIG.settings = HUB.config.menuSettings;
if (typeof(CONFIG.settings.showRenderer) !== "undefined") {CONFIG.showRenderer = CONFIG.settings.showRenderer}
if (typeof(CONFIG.settings.showFontMenu) !== "undefined") {CONFIG.showFontMenu = CONFIG.settings.showFontMenu}
if (typeof(CONFIG.settings.showContext) !== "undefined") {CONFIG.showContext = CONFIG.settings.showContext}
MENU.getCookie();
/*
* The main menu
*/
// Localization: items used as key, should be refactored.
MENU.menu = MENU(
ITEM.SUBMENU(["Show","Show Math As"],
ITEM.COMMAND(["MathMLcode","MathML Code"], MENU.ShowSource, {nativeTouch: true, format: "MathML"}),
ITEM.COMMAND(["Original","Original Form"], MENU.ShowSource, {nativeTouch: true}),
ITEM.SUBMENU(["Annotation","Annotation"], {disabled:true}),
ITEM.RULE(),
ITEM.CHECKBOX(["texHints","Show TeX hints in MathML"], "texHints"),
ITEM.CHECKBOX(["semantics","Add original form as annotation"], "semantics")
),
ITEM.RULE(),
ITEM.SUBMENU(["Settings","Math Settings"],
ITEM.SUBMENU(["ZoomTrigger","Zoom Trigger"],
ITEM.RADIO(["Hover","Hover"], "zoom", {action: MENU.Zoom}),
ITEM.RADIO(["Click","Click"], "zoom", {action: MENU.Zoom}),
ITEM.RADIO(["DoubleClick","Double-Click"], "zoom", {action: MENU.Zoom}),
ITEM.RADIO(["NoZoom","No Zoom"], "zoom", {value: "None"}),
ITEM.RULE(),
ITEM.LABEL(["TriggerRequires","Trigger Requires:"]),
ITEM.CHECKBOX((HUB.Browser.isMac ? ["Option","Option"] : ["Alt","Alt"]), "ALT"),
ITEM.CHECKBOX(["Command","Command"], "CMD", {hidden: !HUB.Browser.isMac}),
ITEM.CHECKBOX(["Control","Control"], "CTRL", {hidden: HUB.Browser.isMac}),
ITEM.CHECKBOX(["Shift","Shift"], "Shift")
),
ITEM.SUBMENU(["ZoomFactor","Zoom Factor"],
ITEM.RADIO("125%", "zscale"),
ITEM.RADIO("133%", "zscale"),
ITEM.RADIO("150%", "zscale"),
ITEM.RADIO("175%", "zscale"),
ITEM.RADIO("200%", "zscale"),
ITEM.RADIO("250%", "zscale"),
ITEM.RADIO("300%", "zscale"),
ITEM.RADIO("400%", "zscale")
),
ITEM.RULE(),
ITEM.SUBMENU(["Renderer","Math Renderer"], {hidden:!CONFIG.showRenderer},
ITEM.RADIO(["HTML-CSS","HTML-CSS"], "renderer", {action: MENU.Renderer}),
ITEM.RADIO(["CommonHTML","Common HTML"], "renderer", {action: MENU.Renderer, value:"CommonHTML"}),
ITEM.RADIO(["PreviewHTML","Preview HTML"],"renderer", {action: MENU.Renderer, value:"PreviewHTML"}),
ITEM.RADIO(["MathML","MathML"], "renderer", {action: MENU.Renderer, value:"NativeMML"}),
ITEM.RADIO(["SVG","SVG"], "renderer", {action: MENU.Renderer}),
ITEM.RADIO(["PlainSource","Plain Source"],"renderer", {action: MENU.Renderer, value:"PlainSource"}),
ITEM.RULE(),
ITEM.CHECKBOX(["FastPreview","Fast Preview"], "FastPreview")
),
ITEM.SUBMENU("MathPlayer", {hidden:!HUB.Browser.isMSIE || !CONFIG.showMathPlayer,
disabled:!HUB.Browser.hasMathPlayer},
ITEM.LABEL(["MPHandles","Let MathPlayer Handle:"]),
ITEM.CHECKBOX(["MenuEvents","Menu Events"], "mpContext", {action: MENU.MPEvents, hidden:!isIE9}),
ITEM.CHECKBOX(["MouseEvents","Mouse Events"], "mpMouse", {action: MENU.MPEvents, hidden:!isIE9}),
ITEM.CHECKBOX(["MenuAndMouse","Mouse and Menu Events"], "mpMouse", {action: MENU.MPEvents, hidden:isIE9})
),
ITEM.SUBMENU(["FontPrefs","Font Preference"], {hidden:!CONFIG.showFontMenu},
ITEM.LABEL(["ForHTMLCSS","For HTML-CSS:"]),
ITEM.RADIO(["Auto","Auto"], "font", {action: MENU.Font}),
ITEM.RULE(),
ITEM.RADIO(["TeXLocal","TeX (local)"], "font", {action: MENU.Font}),
ITEM.RADIO(["TeXWeb","TeX (web)"], "font", {action: MENU.Font}),
ITEM.RADIO(["TeXImage","TeX (image)"], "font", {action: MENU.Font}),
ITEM.RULE(),
ITEM.RADIO(["STIXLocal","STIX (local)"], "font", {action: MENU.Font}),
ITEM.RADIO(["STIXWeb","STIX (web)"], "font", {action: MENU.Font}),
ITEM.RULE(),
ITEM.RADIO(["AsanaMathWeb","Asana Math (web)"], "font", {action: MENU.Font}),
ITEM.RADIO(["GyrePagellaWeb","Gyre Pagella (web)"], "font", {action: MENU.Font}),
ITEM.RADIO(["GyreTermesWeb","Gyre Termes (web)"], "font", {action: MENU.Font}),
ITEM.RADIO(["LatinModernWeb","Latin Modern (web)"], "font", {action: MENU.Font}),
ITEM.RADIO(["NeoEulerWeb","Neo Euler (web)"], "font", {action: MENU.Font})
),
ITEM.SUBMENU(["ContextMenu","Contextual Menu"], {hidden:!CONFIG.showContext},
ITEM.RADIO(["MathJax","MathJax"], "context"),
ITEM.RADIO(["Browser","Browser"], "context")
),
ITEM.COMMAND(["Scale","Scale All Math ..."],MENU.Scale),
ITEM.RULE().With({hidden:!CONFIG.showDiscoverable, name:["","discover_rule"]}),
ITEM.CHECKBOX(["Discoverable","Highlight on Hover"], "discoverable", {hidden:!CONFIG.showDiscoverable})
),
ITEM.SUBMENU(["Accessibility","Accessibility"],
ITEM.CHECKBOX(["AssistiveMML","Assistive MathML"], "assistiveMML", {action:MENU.AssistiveMML}),
ITEM.CHECKBOX(["InTabOrder","Include in Tab Order"], "inTabOrder")
),
ITEM.SUBMENU(["Locale","Language"], {hidden:!CONFIG.showLocale, ltr:true},
ITEM.RADIO("en", "locale", {action: MENU.Locale}),
ITEM.RULE().With({hidden:!CONFIG.showLocaleURL, name:["","localURL_rule"]}),
ITEM.COMMAND(["LoadLocale","Load from URL ..."], MENU.LoadLocale, {hidden:!CONFIG.showLocaleURL})
),
ITEM.RULE(),
ITEM.COMMAND(["About","About MathJax"],MENU.About),
ITEM.COMMAND(["Help","MathJax Help"],MENU.Help)
);
if (MENU.isMobile) {
(function () {
var settings = CONFIG.settings;
var trigger = MENU.menu.Find("Math Settings","Zoom Trigger").submenu;
trigger.items[0].disabled = trigger.items[1].disabled = true;
if (settings.zoom === "Hover" || settings.zoom == "Click") {settings.zoom = "None"}
trigger.items = trigger.items.slice(0,4);
if (navigator.appVersion.match(/[ (]Android[) ]/)) {
MENU.ITEM.SUBMENU.Augment({marker: "\u00BB"});
}
})();
}
MENU.CreateLocaleMenu();
MENU.CreateAnnotationMenu();
});
MENU.showRenderer = function (show) {
MENU.cookie.showRenderer = CONFIG.showRenderer = show; MENU.saveCookie();
MENU.menu.Find("Math Settings","Math Renderer").hidden = !show;
};
MENU.showMathPlayer = function (show) {
MENU.cookie.showMathPlayer = CONFIG.showMathPlayer = show; MENU.saveCookie();
MENU.menu.Find("Math Settings","MathPlayer").hidden = !show;
};
MENU.showFontMenu = function (show) {
MENU.cookie.showFontMenu = CONFIG.showFontMenu = show; MENU.saveCookie();
MENU.menu.Find("Math Settings","Font Preference").hidden = !show;
};
MENU.showContext = function (show) {
MENU.cookie.showContext = CONFIG.showContext = show; MENU.saveCookie();
MENU.menu.Find("Math Settings","Contextual Menu").hidden = !show;
};
MENU.showDiscoverable = function (show) {
MENU.cookie.showDiscoverable = CONFIG.showDiscoverable = show; MENU.saveCookie();
MENU.menu.Find("Math Settings","Highlight on Hover").hidden = !show;
MENU.menu.Find("Math Settings","discover_rule").hidden = !show;
};
MENU.showLocale = function (show) {
MENU.cookie.showLocale = CONFIG.showLocale = show; MENU.saveCookie();
MENU.menu.Find("Language").hidden = !show;
};
MathJax.Hub.Register.StartupHook("HTML-CSS Jax Ready",function () {
if (!MathJax.OutputJax["HTML-CSS"].config.imageFont)
{MENU.menu.Find("Math Settings","Font Preference","TeX (image)").disabled = true}
});
/*************************************************************/
CALLBACK.Queue(
HUB.Register.StartupHook("End Config",{}), // wait until config is complete
["Styles",AJAX,CONFIG.styles],
["Post",HUB.Startup.signal,"MathMenu Ready"],
["loadComplete",AJAX,"[MathJax]/extensions/MathMenu.js"]
);
})(MathJax.Hub,MathJax.HTML,MathJax.Ajax,MathJax.CallBack,MathJax.OutputJax);
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/extensions/toMathML.js
*
* Implements a toMathML() method for the mml Element Jax that returns
* a MathML string from a given math expression.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
MathJax.Hub.Register.LoadHook("[MathJax]/jax/element/mml/jax.js",function () {
var VERSION = "2.7.1";
var MML = MathJax.ElementJax.mml,
SETTINGS = MathJax.Hub.config.menuSettings;
MML.mbase.Augment({
toMathML: function (space) {
var inferred = (this.inferred && this.parent.inferRow);
if (space == null) {space = ""}
var tag = this.type, attr = this.toMathMLattributes();
if (tag === "mspace") {return space + "<"+tag+attr+" />"}
var data = [], SPACE = (this.isToken ? "" : space+(inferred ? "" : " "));
for (var i = 0, m = this.data.length; i < m; i++) {
if (this.data[i]) {data.push(this.data[i].toMathML(SPACE))}
else if (!this.isToken && !this.isChars) {data.push(SPACE+"<mrow />")}
}
if (this.isToken || this.isChars) {return space + "<"+tag+attr+">"+data.join("")+"</"+tag+">"}
if (inferred) {return data.join("\n")}
if (data.length === 0 || (data.length === 1 && data[0] === ""))
{return space + "<"+tag+attr+" />"}
return space + "<"+tag+attr+">\n"+data.join("\n")+"\n"+ space +"</"+tag+">";
},
toMathMLattributes: function () {
var defaults = (this.type === "mstyle" ? MML.math.prototype.defaults : this.defaults);
var names = (this.attrNames||MML.copyAttributeNames),
skip = MML.skipAttributes, copy = MML.copyAttributes;
var attr = [];
if (this.type === "math" && (!this.attr || !this.attr.xmlns))
{attr.push('xmlns="http://www.w3.org/1998/Math/MathML"')}
if (!this.attrNames) {
for (var id in defaults) {if (!skip[id] && !copy[id] && defaults.hasOwnProperty(id)) {
if (this[id] != null && this[id] !== defaults[id]) {
if (this.Get(id,null,1) !== this[id])
attr.push(id+'="'+this.toMathMLattribute(this[id])+'"');
}
}}
}
for (var i = 0, m = names.length; i < m; i++) {
if (copy[names[i]] === 1 && !defaults.hasOwnProperty(names[i])) continue;
value = (this.attr||{})[names[i]]; if (value == null) {value = this[names[i]]}
if (value != null) {attr.push(names[i]+'="'+this.toMathMLquote(value)+'"')}
}
this.toMathMLclass(attr);
if (attr.length) {return " "+attr.join(" ")} else {return ""}
},
toMathMLclass: function (attr) {
var CLASS = []; if (this["class"]) {CLASS.push(this["class"])}
if (this.isa(MML.TeXAtom) && SETTINGS.texHints) {
var TEXCLASS = ["ORD","OP","BIN","REL","OPEN","CLOSE","PUNCT","INNER","VCENTER"][this.texClass];
if (TEXCLASS) {
CLASS.push("MJX-TeXAtom-"+TEXCLASS)
if (TEXCLASS === "OP" && !this.movablelimits) CLASS.push("MJX-fixedlimits");
}
}
if (this.mathvariant && this.toMathMLvariants[this.mathvariant])
{CLASS.push("MJX"+this.mathvariant)}
if (this.variantForm) {CLASS.push("MJX-variant")}
if (CLASS.length) {attr.unshift('class="'+CLASS.join(" ")+'"')}
},
toMathMLattribute: function (value) {
if (typeof(value) === "string" &&
value.replace(/ /g,"").match(/^(([-+])?(\d+(\.\d*)?|\.\d+))mu$/)) {
// FIXME: should take scriptlevel into account
return (RegExp.$2||"")+((1/18)*RegExp.$3).toFixed(3).replace(/\.?0+$/,"")+"em";
}
else if (this.toMathMLvariants[value]) {return this.toMathMLvariants[value]}
return this.toMathMLquote(value);
},
toMathMLvariants: {
"-tex-caligraphic": MML.VARIANT.SCRIPT,
"-tex-caligraphic-bold": MML.VARIANT.BOLDSCRIPT,
"-tex-oldstyle": MML.VARIANT.NORMAL,
"-tex-oldstyle-bold": MML.VARIANT.BOLD,
"-tex-mathit": MML.VARIANT.ITALIC
},
toMathMLquote: function (string) {
string = String(string).split("");
for (var i = 0, m = string.length; i < m; i++) {
var n = string[i].charCodeAt(0);
if (n <= 0xD7FF || 0xE000 <= n) {
// Code points U+0000 to U+D7FF and U+E000 to U+FFFF.
// They are directly represented by n.
if (n > 0x7E || (n < 0x20 && n !== 0x0A && n !== 0x0D && n !== 0x09)) {
string[i] = "&#x"+n.toString(16).toUpperCase()+";";
} else {
var c =
{'&':'&amp;', '<':'&lt;', '>':'&gt;', '"':'&quot;'}[string[i]];
if (c) {string[i] = c}
}
} else if (i+1 < m) {
// Code points U+10000 to U+10FFFF.
// n is the lead surrogate, let's read the trail surrogate.
var trailSurrogate = string[i+1].charCodeAt(0);
var codePoint = (((n-0xD800)<<10)+(trailSurrogate-0xDC00)+0x10000);
string[i] = "&#x"+codePoint.toString(16).toUpperCase()+";";
string[i+1] = "";
i++;
} else {
// n is a lead surrogate without corresponding trail surrogate:
// remove that character.
string[i] = "";
}
}
return string.join("");
}
});
//
// Override math.toMathML in order to add semantics tag
// for the input format, if the user requests that in the
// Show As menu.
//
MML.math.Augment({
toMathML: function (space,jax) {
var annotation;
if (space == null) {space = ""}
if (jax && jax.originalText && SETTINGS.semantics)
{annotation = MathJax.InputJax[jax.inputJax].annotationEncoding}
var nested = (this.data[0] && this.data[0].data.length > 1);
var tag = this.type, attr = this.toMathMLattributes();
var data = [], SPACE = space + (annotation ? " " + (nested ? " " : "") : "") + " ";
for (var i = 0, m = this.data.length; i < m; i++) {
if (this.data[i]) {data.push(this.data[i].toMathML(SPACE))}
else {data.push(SPACE+"<mrow />")}
}
if (data.length === 0 || (data.length === 1 && data[0] === "")) {
if (!annotation) {return "<"+tag+attr+" />"}
data.push(SPACE+"<mrow />");
}
if (annotation) {
if (nested) {data.unshift(space+" <mrow>"); data.push(space+" </mrow>")}
data.unshift(space+" <semantics>");
var xmlEscapedTex = jax.originalText.replace(/[&<>]/g, function(item) {
return { '>': '&gt;', '<': '&lt;','&': '&amp;' }[item]
});
data.push(space+' <annotation encoding="'+annotation+'">'+xmlEscapedTex+"</annotation>");
data.push(space+" </semantics>");
}
return space+"<"+tag+attr+">\n"+data.join("\n")+"\n"+space+"</"+tag+">";
}
});
MML.msubsup.Augment({
toMathML: function (space) {
var tag = this.type;
if (this.data[this.sup] == null) {tag = "msub"}
if (this.data[this.sub] == null) {tag = "msup"}
var attr = this.toMathMLattributes();
delete this.data[0].inferred;
var data = [];
for (var i = 0, m = this.data.length; i < m; i++)
{if (this.data[i]) {data.push(this.data[i].toMathML(space+" "))}}
return space + "<"+tag+attr+">\n" + data.join("\n") + "\n" + space + "</"+tag+">";
}
});
MML.munderover.Augment({
toMathML: function (space) {
var tag = this.type;
var base = this.data[this.base];
if (base && base.isa(MML.TeXAtom) && base.movablelimits && !base.Get("displaystyle")) {
type = "msubsup";
if (this.data[this.under] == null) {tag = "msup"}
if (this.data[this.over] == null) {tag = "msub"}
} else {
if (this.data[this.under] == null) {tag = "mover"}
if (this.data[this.over] == null) {tag = "munder"}
}
var attr = this.toMathMLattributes();
delete this.data[0].inferred;
var data = [];
for (var i = 0, m = this.data.length; i < m; i++)
{if (this.data[i]) {data.push(this.data[i].toMathML(space+" "))}}
return space + "<"+tag+attr+">\n" + data.join("\n") + "\n" + space + "</"+tag+">";
}
});
MML.TeXAtom.Augment({
toMathML: function (space) {
// FIXME: Handle spacing using mpadded?
var attr = this.toMathMLattributes();
if (!attr && this.data[0].data.length === 1) {return space.substr(2) + this.data[0].toMathML(space)}
return space+"<mrow"+attr+">\n" + this.data[0].toMathML(space+" ")+"\n"+space+"</mrow>";
}
});
MML.chars.Augment({
toMathML: function (space) {return (space||"") + this.toMathMLquote(this.toString())}
});
MML.entity.Augment({
toMathML: function (space) {return (space||"") + "&"+this.data[0]+";<!-- "+this.toString()+" -->"}
});
MML.xml.Augment({
toMathML: function (space) {return (space||"") + this.toString()}
});
MathJax.Hub.Register.StartupHook("TeX mathchoice Ready",function () {
MML.TeXmathchoice.Augment({
toMathML: function (space) {return this.Core().toMathML(space)}
});
});
MathJax.Hub.Startup.signal.Post("toMathML Ready");
});
MathJax.Ajax.loadComplete("[MathJax]/extensions/toMathML.js");
/*************************************************************
*
* MathJax/extensions/HelpDialog.js
*
* Implements the MathJax Help dialog box.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2013-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
(function (HUB,HTML,AJAX,OUTPUT,LOCALE) {
var HELP = MathJax.Extension.Help = {
version: "2.7.1"
};
var STIXURL = "http://www.stixfonts.org/";
var MENU = MathJax.Menu;
var FALSE, KEY;
HUB.Register.StartupHook("MathEvents Ready",function () {
FALSE = MathJax.Extension.MathEvents.Event.False;
KEY = MathJax.Extension.MathEvents.Event.KEY;
});
var CONFIG = HUB.CombineConfig("HelpDialog",{
styles: {
"#MathJax_Help": {
position:"fixed", left:"50%", width:"auto", "max-width": "90%", "text-align":"center",
border:"3px outset", padding:"1em 2em", "background-color":"#DDDDDD", color:"black",
cursor: "default", "font-family":"message-box", "font-size":"120%",
"font-style":"normal", "text-indent":0, "text-transform":"none",
"line-height":"normal", "letter-spacing":"normal", "word-spacing":"normal",
"word-wrap":"normal", "white-space":"wrap", "float":"none", "z-index":201,
"border-radius": "15px", // Opera 10.5 and IE9
"-webkit-border-radius": "15px", // Safari and Chrome
"-moz-border-radius": "15px", // Firefox
"-khtml-border-radius": "15px", // Konqueror
"box-shadow":"0px 10px 20px #808080", // Opera 10.5 and IE9
"-webkit-box-shadow":"0px 10px 20px #808080", // Safari 3 and Chrome
"-moz-box-shadow":"0px 10px 20px #808080", // Forefox 3.5
"-khtml-box-shadow":"0px 10px 20px #808080", // Konqueror
filter: "progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true')" // IE
},
"#MathJax_Help.MathJax_MousePost": {
outline:"none"
},
"#MathJax_HelpContent": {
overflow:"auto", "text-align":"left", "font-size":"80%",
padding:".4em .6em", border:"1px inset", margin:"1em 0px",
"max-height":"20em", "max-width":"30em", "background-color":"#EEEEEE"
},
"#MathJax_HelpClose": {
position:"absolute", top:".2em", right:".2em",
cursor:"pointer",
display:"inline-block",
border:"2px solid #AAA",
"border-radius":"18px",
"-webkit-border-radius": "18px", // Safari and Chrome
"-moz-border-radius": "18px", // Firefox
"-khtml-border-radius": "18px", // Konqueror
"font-family":"'Courier New',Courier",
"font-size":"24px",
color:"#F0F0F0"
},
"#MathJax_HelpClose span": {
display:"block", "background-color":"#AAA", border:"1.5px solid",
"border-radius":"18px",
"-webkit-border-radius": "18px", // Safari and Chrome
"-moz-border-radius": "18px", // Firefox
"-khtml-border-radius": "18px", // Konqueror
"line-height":0,
padding:"8px 0 6px" // may need to be browser-specific
},
"#MathJax_HelpClose:hover": {
color:"white!important",
border:"2px solid #CCC!important"
},
"#MathJax_HelpClose:hover span": {
"background-color":"#CCC!important"
},
"#MathJax_HelpClose:hover:focus": {
outline:"none"
}
}
});
/*
* Handle the Help Dialog box
*/
HELP.Dialog = function (event) {
LOCALE.loadDomain("HelpDialog",["Post",HELP,event]);
};
HELP.Post = function (event) {
this.div = MENU.Background(this);
var help = HTML.addElement(this.div,"div",{
id: "MathJax_Help", tabIndex: 0, onkeydown: HELP.Keydown
},LOCALE._("HelpDialog",[
["b",{style:{fontSize:"120%"}},[["Help","MathJax Help"]]],
["div",{id: "MathJax_HelpContent", tabIndex: 0},[
["p",{},[["MathJax",
"*MathJax* is a JavaScript library that allows page authors to include " +
"mathematics within their web pages. As a reader, you don't need to do " +
"anything to make that happen."]]
],
["p",{},[["Browsers",
"*Browsers*: MathJax works with all modern browsers including IE6+, Firefox 3+, " +
"Chrome 0.2+, Safari 2+, Opera 9.6+ and most mobile browsers."]]
],
["p",{},[["Menu",
"*Math Menu*: MathJax adds a contextual menu to equations. Right-click or " +
"CTRL-click on any mathematics to access the menu."]]
],
["div",{style:{"margin-left":"1em"}},[
["p",{},[["ShowMath",
"*Show Math As* allows you to view the formula's source markup " +
"for copy & paste (as MathML or in its original format)."]]
],
["p",{},[["Settings",
"*Settings* gives you control over features of MathJax, such as the " +
"size of the mathematics, and the mechanism used to display equations."]]
],
["p",{},[["Language",
"*Language* lets you select the language used by MathJax for its menus " +
"and warning messages."]]
],
]],
["p",{},[["Zoom",
"*Math Zoom*: If you are having difficulty reading an equation, MathJax can " +
"enlarge it to help you see it better."]]
],
["p",{},[["Accessibilty",
"*Accessibility*: MathJax will automatically work with screen readers to make " +
"mathematics accessible to the visually impaired."]]
],
["p",{},[["Fonts",
"*Fonts*: MathJax will use certain math fonts if they are installed on your " +
"computer; otherwise, it will use web-based fonts. Although not required, " +
"locally installed fonts will speed up typesetting. We suggest installing " +
"the [STIX fonts](%1).",STIXURL]]
]
]],
["a",{href:"http://www.mathjax.org/"},["www.mathjax.org"]],
["span",{id: "MathJax_HelpClose", onclick: HELP.Remove,
onkeydown: HELP.Keydown, tabIndex: 0, role: "button",
"aria-label": LOCALE._(["HelpDialog","CloseDialog"],"Close help dialog")},
[["span",{},["\u00D7"]]]
]
]));
if (event.type === "mouseup") help.className += " MathJax_MousePost";
help.focus();
LOCALE.setCSS(help);
var doc = (document.documentElement||{});
var H = window.innerHeight || doc.clientHeight || doc.scrollHeight || 0;
if (MENU.prototype.msieAboutBug) {
help.style.width = "20em"; help.style.position = "absolute";
help.style.left = Math.floor((document.documentElement.scrollWidth - help.offsetWidth)/2)+"px";
help.style.top = (Math.floor((H-help.offsetHeight)/3)+document.body.scrollTop)+"px";
} else {
help.style.marginLeft = Math.floor(-help.offsetWidth/2)+"px";
help.style.top = Math.floor((H-help.offsetHeight)/3)+"px";
}
};
HELP.Remove = function (event) {
if (HELP.div) {document.body.removeChild(HELP.div); delete HELP.div}
};
HELP.Keydown = function(event) {
if (event.keyCode === KEY.ESCAPE ||
(this.id === "MathJax_HelpClose" &&
(event.keyCode === KEY.SPACE || event.keyCode === KEY.RETURN))) {
HELP.Remove(event);
MENU.CurrentNode().focus();
FALSE(event);
}
},
MathJax.Callback.Queue(
HUB.Register.StartupHook("End Config",{}), // wait until config is complete
["Styles",AJAX,CONFIG.styles],
["Post",HUB.Startup.signal,"HelpDialig Ready"],
["loadComplete",AJAX,"[MathJax]/extensions/HelpDialog.js"]
);
})(MathJax.Hub,MathJax.HTML,MathJax.Ajax,MathJax.OutputJax,MathJax.Localization);
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/jax/input/TeX/config.js
*
* Initializes the TeX InputJax (the main definition is in
* MathJax/jax/input/TeX/jax.js, which is loaded when needed).
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2009-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
MathJax.InputJax.TeX = MathJax.InputJax({
id: "TeX",
version: "2.7.1",
directory: MathJax.InputJax.directory + "/TeX",
extensionDir: MathJax.InputJax.extensionDir + "/TeX",
config: {
TagSide: "right",
TagIndent: "0.8em",
MultLineWidth: "85%",
equationNumbers: {
autoNumber: "none", // "AMS" for standard AMS numbering,
// or "all" for all displayed equations
formatNumber: function (n) {return n},
formatTag: function (n) {return '('+n+')'},
formatID: function (n) {return 'mjx-eqn-'+String(n).replace(/[:"'<>&]/g,"")},
formatURL: function (id,base) {return base+'#'+escape(id)},
useLabelIds: true
}
},
resetEquationNumbers: function () {} // filled in by AMSmath extension
});
MathJax.InputJax.TeX.Register("math/tex");
MathJax.InputJax.TeX.loadComplete("config.js");
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/jax/input/TeX/jax.js
*
* Implements the TeX InputJax that reads mathematics in
* TeX and LaTeX format and converts it to the MML ElementJax
* internal format.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2009-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
(function (TEX,HUB,AJAX) {
var MML, NBSP = "\u00A0";
var _ = function (id) {
return MathJax.Localization._.apply(MathJax.Localization,
[["TeX", id]].concat([].slice.call(arguments,1)));
};
var isArray = MathJax.Object.isArray;
var STACK = MathJax.Object.Subclass({
Init: function (env,inner) {
this.global = {isInner: inner};
this.data = [STACKITEM.start(this.global)];
if (env) {this.data[0].env = env}
this.env = this.data[0].env;
},
Push: function () {
var i, m, item, top;
for (i = 0, m = arguments.length; i < m; i++) {
item = arguments[i]; if (!item) continue;
if (item instanceof MML.mbase) {item = STACKITEM.mml(item)}
item.global = this.global;
top = (this.data.length ? this.Top().checkItem(item) : true);
if (top instanceof Array) {this.Pop(); this.Push.apply(this,top)}
else if (top instanceof STACKITEM) {this.Pop(); this.Push(top)}
else if (top) {
this.data.push(item);
if (item.env) {
if (item.copyEnv !== false) {
for (var id in this.env)
{if (this.env.hasOwnProperty(id)) {item.env[id] = this.env[id]}}
}
this.env = item.env;
} else {item.env = this.env}
}
}
},
Pop: function () {
var item = this.data.pop(); if (!item.isOpen) {delete item.env}
this.env = (this.data.length ? this.Top().env : {});
return item;
},
Top: function (n) {
if (n == null) {n = 1}
if (this.data.length < n) {return null}
return this.data[this.data.length-n];
},
Prev: function (noPop) {
var top = this.Top();
if (noPop) {return top.data[top.data.length-1]}
else {return top.Pop()}
},
toString: function () {return "stack[\n "+this.data.join("\n ")+"\n]"}
});
var STACKITEM = STACK.Item = MathJax.Object.Subclass({
type: "base",
endError: /*_()*/ ["ExtraOpenMissingClose","Extra open brace or missing close brace"],
closeError: /*_()*/ ["ExtraCloseMissingOpen","Extra close brace or missing open brace"],
rightError: /*_()*/ ["MissingLeftExtraRight","Missing \\left or extra \\right"],
Init: function () {
if (this.isOpen) {this.env = {}}
this.data = [];
this.Push.apply(this,arguments);
},
Push: function () {this.data.push.apply(this.data,arguments)},
Pop: function () {return this.data.pop()},
mmlData: function (inferred,forceRow) {
if (inferred == null) {inferred = true}
if (this.data.length === 1 && !forceRow) {return this.data[0]}
return MML.mrow.apply(MML,this.data).With((inferred ? {inferred: true}: {}));
},
checkItem: function (item) {
if (item.type === "over" && this.isOpen) {item.num = this.mmlData(false); this.data = []}
if (item.type === "cell" && this.isOpen) {
if (item.linebreak) {return false}
TEX.Error(["Misplaced","Misplaced %1",item.name]);
}
if (item.isClose && this[item.type+"Error"]) {TEX.Error(this[item.type+"Error"])}
if (!item.isNotStack) {return true}
this.Push(item.data[0]); return false;
},
With: function (def) {
for (var id in def) {if (def.hasOwnProperty(id)) {this[id] = def[id]}}
return this;
},
toString: function () {return this.type+"["+this.data.join("; ")+"]"}
});
STACKITEM.start = STACKITEM.Subclass({
type: "start", isOpen: true,
Init: function (global) {
this.SUPER(arguments).Init.call(this);
this.global = global;
},
checkItem: function (item) {
if (item.type === "stop") {return STACKITEM.mml(this.mmlData())}
return this.SUPER(arguments).checkItem.call(this,item);
}
});
STACKITEM.stop = STACKITEM.Subclass({
type: "stop", isClose: true
});
STACKITEM.open = STACKITEM.Subclass({
type: "open", isOpen: true,
stopError: /*_()*/ ["ExtraOpenMissingClose","Extra open brace or missing close brace"],
checkItem: function (item) {
if (item.type === "close") {
var mml = this.mmlData();
return STACKITEM.mml(MML.TeXAtom(mml)); // TeXAtom make it an ORD to prevent spacing (FIXME: should be another way)
}
return this.SUPER(arguments).checkItem.call(this,item);
}
});
STACKITEM.close = STACKITEM.Subclass({
type: "close", isClose: true
});
STACKITEM.prime = STACKITEM.Subclass({
type: "prime",
checkItem: function (item) {
if (this.data[0].type !== "msubsup")
{return [MML.msup(this.data[0],this.data[1]),item]}
this.data[0].SetData(this.data[0].sup,this.data[1]);
return [this.data[0],item];
}
});
STACKITEM.subsup = STACKITEM.Subclass({
type: "subsup",
stopError: /*_()*/ ["MissingScript","Missing superscript or subscript argument"],
supError: /*_()*/ ["MissingOpenForSup","Missing open brace for superscript"],
subError: /*_()*/ ["MissingOpenForSub","Missing open brace for subscript"],
checkItem: function (item) {
if (item.type === "open" || item.type === "left") {return true}
if (item.type === "mml") {
if (this.primes) {
if (this.position !== 2) {this.data[0].SetData(2,this.primes)}
else {item.data[0] = MML.mrow(this.primes.With({variantForm:true}),item.data[0])}
}
this.data[0].SetData(this.position,item.data[0]);
if (this.movesupsub != null) {this.data[0].movesupsub = this.movesupsub}
return STACKITEM.mml(this.data[0]);
}
if (this.SUPER(arguments).checkItem.call(this,item))
{TEX.Error(this[["","subError","supError"][this.position]])}
},
Pop: function () {}
});
STACKITEM.over = STACKITEM.Subclass({
type: "over", isClose: true, name: "\\over",
checkItem: function (item,stack) {
if (item.type === "over")
{TEX.Error(["AmbiguousUseOf","Ambiguous use of %1",item.name])}
if (item.isClose) {
var mml = MML.mfrac(this.num,this.mmlData(false));
if (this.thickness != null) {mml.linethickness = this.thickness}
if (this.open || this.close) {
mml.texWithDelims = true;
mml = TEX.fixedFence(this.open,mml,this.close);
}
return [STACKITEM.mml(mml), item];
}
return this.SUPER(arguments).checkItem.call(this,item);
},
toString: function () {return "over["+this.num+" / "+this.data.join("; ")+"]"}
});
STACKITEM.left = STACKITEM.Subclass({
type: "left", isOpen: true, delim: '(',
stopError: /*_()*/ ["ExtraLeftMissingRight", "Extra \\left or missing \\right"],
checkItem: function (item) {
if (item.type === "right")
{return STACKITEM.mml(TEX.fenced(this.delim,this.mmlData(),item.delim))}
return this.SUPER(arguments).checkItem.call(this,item);
}
});
STACKITEM.right = STACKITEM.Subclass({
type: "right", isClose: true, delim: ')'
});
STACKITEM.begin = STACKITEM.Subclass({
type: "begin", isOpen: true,
checkItem: function (item) {
if (item.type === "end") {
if (item.name !== this.name)
{TEX.Error(["EnvBadEnd","\\begin{%1} ended with \\end{%2}",this.name,item.name])}
if (!this.end) {return STACKITEM.mml(this.mmlData())}
return this.parse[this.end].call(this.parse,this,this.data);
}
if (item.type === "stop")
{TEX.Error(["EnvMissingEnd","Missing \\end{%1}",this.name])}
return this.SUPER(arguments).checkItem.call(this,item);
}
});
STACKITEM.end = STACKITEM.Subclass({
type: "end", isClose: true
});
STACKITEM.style = STACKITEM.Subclass({
type: "style",
checkItem: function (item) {
if (!item.isClose) {return this.SUPER(arguments).checkItem.call(this,item)}
var mml = MML.mstyle.apply(MML,this.data).With(this.styles);
return [STACKITEM.mml(mml),item];
}
});
STACKITEM.position = STACKITEM.Subclass({
type: "position",
checkItem: function (item) {
if (item.isClose) {TEX.Error(["MissingBoxFor","Missing box for %1",this.name])}
if (item.isNotStack) {
var mml = item.mmlData();
switch (this.move) {
case 'vertical':
mml = MML.mpadded(mml).With({height: this.dh, depth: this.dd, voffset: this.dh});
return [STACKITEM.mml(mml)];
case 'horizontal':
return [STACKITEM.mml(this.left),item,STACKITEM.mml(this.right)];
}
}
return this.SUPER(arguments).checkItem.call(this,item);
}
});
STACKITEM.array = STACKITEM.Subclass({
type: "array", isOpen: true, copyEnv: false, arraydef: {},
Init: function () {
this.table = []; this.row = []; this.frame = []; this.hfill = [];
this.SUPER(arguments).Init.apply(this,arguments);
},
checkItem: function (item) {
if (item.isClose && item.type !== "over") {
if (item.isEntry) {this.EndEntry(); this.clearEnv(); return false}
if (item.isCR) {this.EndEntry(); this.EndRow(); this.clearEnv(); return false}
this.EndTable(); this.clearEnv();
var scriptlevel = this.arraydef.scriptlevel; delete this.arraydef.scriptlevel;
var mml = MML.mtable.apply(MML,this.table).With(this.arraydef);
if (this.frame.length === 4) {
mml.frame = (this.frame.dashed ? "dashed" : "solid");
} else if (this.frame.length) {
mml.hasFrame = true;
if (this.arraydef.rowlines) {this.arraydef.rowlines = this.arraydef.rowlines.replace(/none( none)+$/,"none")}
mml = MML.menclose(mml).With({notation: this.frame.join(" "), isFrame: true});
if ((this.arraydef.columnlines||"none") != "none" ||
(this.arraydef.rowlines||"none") != "none") {mml.padding = 0} // HTML-CSS jax implements this
}
if (scriptlevel) {mml = MML.mstyle(mml).With({scriptlevel: scriptlevel})}
if (this.open || this.close) {mml = TEX.fenced(this.open,mml,this.close)}
mml = STACKITEM.mml(mml);
if (this.requireClose) {
if (item.type === 'close') {return mml}
TEX.Error(["MissingCloseBrace","Missing close brace"]);
}
return [mml,item];
}
return this.SUPER(arguments).checkItem.call(this,item);
},
EndEntry: function () {
var mtd = MML.mtd.apply(MML,this.data);
if (this.hfill.length) {
if (this.hfill[0] === 0) mtd.columnalign = "right";
if (this.hfill[this.hfill.length-1] === this.data.length)
mtd.columnalign = (mtd.columnalign ? "center" : "left");
}
this.row.push(mtd); this.data = []; this.hfill = [];
},
EndRow: function () {
var mtr = MML.mtr;
if (this.isNumbered && this.row.length === 3) {
this.row.unshift(this.row.pop()); // move equation number to first position
mtr = MML.mlabeledtr;
}
this.table.push(mtr.apply(MML,this.row)); this.row = [];
},
EndTable: function () {
if (this.data.length || this.row.length) {this.EndEntry(); this.EndRow()}
this.checkLines();
},
checkLines: function () {
if (this.arraydef.rowlines) {
var lines = this.arraydef.rowlines.split(/ /);
if (lines.length === this.table.length) {
this.frame.push("bottom"); lines.pop();
this.arraydef.rowlines = lines.join(' ');
} else if (lines.length < this.table.length-1) {
this.arraydef.rowlines += " none";
}
}
if (this.rowspacing) {
var rows = this.arraydef.rowspacing.split(/ /);
while (rows.length < this.table.length) {rows.push(this.rowspacing+"em")}
this.arraydef.rowspacing = rows.join(' ');
}
},
clearEnv: function () {
for (var id in this.env) {if (this.env.hasOwnProperty(id)) {delete this.env[id]}}
}
});
STACKITEM.cell = STACKITEM.Subclass({
type: "cell", isClose: true
});
STACKITEM.mml = STACKITEM.Subclass({
type: "mml", isNotStack: true,
Add: function () {this.data.push.apply(this.data,arguments); return this}
});
STACKITEM.fn = STACKITEM.Subclass({
type: "fn",
checkItem: function (item) {
if (this.data[0]) {
if (item.isOpen) {return true}
if (item.type !== "fn") {
if (item.type !== "mml" || !item.data[0]) {return [this.data[0],item]}
if (item.data[0].isa(MML.mspace)) {return [this.data[0],item]}
var mml = item.data[0]; if (mml.isEmbellished()) {mml = mml.CoreMO()}
if ([0,0,1,1,0,1,1,0,0,0][mml.Get("texClass")]) {return [this.data[0],item]}
}
return [this.data[0],MML.mo(MML.entity("#x2061")).With({texClass:MML.TEXCLASS.NONE}),item];
}
return this.SUPER(arguments).checkItem.apply(this,arguments);
}
});
STACKITEM.not = STACKITEM.Subclass({
type: "not",
checkItem: function (item) {
var mml, c;
if (item.type === "open" || item.type === "left") {return true}
if (item.type === "mml" && item.data[0].type.match(/^(mo|mi|mtext)$/)) {
mml = item.data[0], c = mml.data.join("");
if (c.length === 1 && !mml.movesupsub) {
c = STACKITEM.not.remap[c.charCodeAt(0)];
if (c) {mml.SetData(0,MML.chars(String.fromCharCode(c)))}
else {mml.Append(MML.chars("\u0338"))}
return item;
}
}
// \mathrel{\rlap{\notChar}}
mml = MML.mpadded(MML.mtext("\u29F8")).With({width:0});
mml = MML.TeXAtom(mml).With({texClass:MML.TEXCLASS.REL});
return [mml,item];
}
});
STACKITEM.not.remap = {
0x2190:0x219A, 0x2192:0x219B, 0x2194:0x21AE,
0x21D0:0x21CD, 0x21D2:0x21CF, 0x21D4:0x21CE,
0x2208:0x2209, 0x220B:0x220C, 0x2223:0x2224, 0x2225:0x2226,
0x223C:0x2241, 0x007E:0x2241, 0x2243:0x2244, 0x2245:0x2247,
0x2248:0x2249, 0x224D:0x226D, 0x003D:0x2260, 0x2261:0x2262,
0x003C:0x226E, 0x003E:0x226F, 0x2264:0x2270, 0x2265:0x2271,
0x2272:0x2274, 0x2273:0x2275, 0x2276:0x2278, 0x2277:0x2279,
0x227A:0x2280, 0x227B:0x2281, 0x2282:0x2284, 0x2283:0x2285,
0x2286:0x2288, 0x2287:0x2289, 0x22A2:0x22AC, 0x22A8:0x22AD,
0x22A9:0x22AE, 0x22AB:0x22AF, 0x227C:0x22E0, 0x227D:0x22E1,
0x2291:0x22E2, 0x2292:0x22E3, 0x22B2:0x22EA, 0x22B3:0x22EB,
0x22B4:0x22EC, 0x22B5:0x22ED, 0x2203:0x2204
};
STACKITEM.dots = STACKITEM.Subclass({
type: "dots",
checkItem: function (item) {
if (item.type === "open" || item.type === "left") {return true}
var dots = this.ldots;
if (item.type === "mml" && item.data[0].isEmbellished()) {
var tclass = item.data[0].CoreMO().Get("texClass");
if (tclass === MML.TEXCLASS.BIN || tclass === MML.TEXCLASS.REL) {dots = this.cdots}
}
return [dots,item];
}
});
var TEXDEF = {
//
// Add new definitions without overriding user-defined ones
//
Add: function (src,dst,nouser) {
if (!dst) {dst = this}
for (var id in src) {if (src.hasOwnProperty(id)) {
if (typeof src[id] === 'object' && !isArray(src[id]) &&
(typeof dst[id] === 'object' || typeof dst[id] === 'function'))
{this.Add(src[id],dst[id],src[id],nouser)}
else if (!dst[id] || !dst[id].isUser || !nouser) {dst[id] = src[id]}
}}
return dst;
}
};
var STARTUP = function () {
MML = MathJax.ElementJax.mml;
HUB.Insert(TEXDEF,{
// patterns for letters and numbers
letter: /[a-z]/i,
digit: /[0-9.]/,
number: /^(?:[0-9]+(?:\{,\}[0-9]{3})*(?:\.[0-9]*)*|\.[0-9]+)/,
special: {
'\\': 'ControlSequence',
'{': 'Open',
'}': 'Close',
'~': 'Tilde',
'^': 'Superscript',
'_': 'Subscript',
' ': 'Space',
"\t": 'Space',
"\r": 'Space',
"\n": 'Space',
"'": 'Prime',
'%': 'Comment',
'&': 'Entry',
'#': 'Hash',
'\u00A0': 'Space',
'\u2019': 'Prime'
},
remap: {
'-': '2212',
'*': '2217',
'`': '2018' // map ` to back quote
},
mathchar0mi: {
// Lower-case greek
alpha: '03B1',
beta: '03B2',
gamma: '03B3',
delta: '03B4',
epsilon: '03F5',
zeta: '03B6',
eta: '03B7',
theta: '03B8',
iota: '03B9',
kappa: '03BA',
lambda: '03BB',
mu: '03BC',
nu: '03BD',
xi: '03BE',
omicron: '03BF', // added for completeness
pi: '03C0',
rho: '03C1',
sigma: '03C3',
tau: '03C4',
upsilon: '03C5',
phi: '03D5',
chi: '03C7',
psi: '03C8',
omega: '03C9',
varepsilon: '03B5',
vartheta: '03D1',
varpi: '03D6',
varrho: '03F1',
varsigma: '03C2',
varphi: '03C6',
// Ord symbols
S: ['00A7',{mathvariant: MML.VARIANT.NORMAL}],
aleph: ['2135',{mathvariant: MML.VARIANT.NORMAL}],
hbar: ['210F',{variantForm:true}],
imath: '0131',
jmath: '0237',
ell: '2113',
wp: ['2118',{mathvariant: MML.VARIANT.NORMAL}],
Re: ['211C',{mathvariant: MML.VARIANT.NORMAL}],
Im: ['2111',{mathvariant: MML.VARIANT.NORMAL}],
partial: ['2202',{mathvariant: MML.VARIANT.NORMAL}],
infty: ['221E',{mathvariant: MML.VARIANT.NORMAL}],
prime: ['2032',{mathvariant: MML.VARIANT.NORMAL, variantForm:true}],
emptyset: ['2205',{mathvariant: MML.VARIANT.NORMAL}],
nabla: ['2207',{mathvariant: MML.VARIANT.NORMAL}],
top: ['22A4',{mathvariant: MML.VARIANT.NORMAL}],
bot: ['22A5',{mathvariant: MML.VARIANT.NORMAL}],
angle: ['2220',{mathvariant: MML.VARIANT.NORMAL}],
triangle: ['25B3',{mathvariant: MML.VARIANT.NORMAL}],
backslash: ['2216',{mathvariant: MML.VARIANT.NORMAL, variantForm:true}],
forall: ['2200',{mathvariant: MML.VARIANT.NORMAL}],
exists: ['2203',{mathvariant: MML.VARIANT.NORMAL}],
neg: ['00AC',{mathvariant: MML.VARIANT.NORMAL}],
lnot: ['00AC',{mathvariant: MML.VARIANT.NORMAL}],
flat: ['266D',{mathvariant: MML.VARIANT.NORMAL}],
natural: ['266E',{mathvariant: MML.VARIANT.NORMAL}],
sharp: ['266F',{mathvariant: MML.VARIANT.NORMAL}],
clubsuit: ['2663',{mathvariant: MML.VARIANT.NORMAL}],
diamondsuit: ['2662',{mathvariant: MML.VARIANT.NORMAL}],
heartsuit: ['2661',{mathvariant: MML.VARIANT.NORMAL}],
spadesuit: ['2660',{mathvariant: MML.VARIANT.NORMAL}]
},
mathchar0mo: {
surd: '221A',
// big ops
coprod: ['2210',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
bigvee: ['22C1',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
bigwedge: ['22C0',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
biguplus: ['2A04',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
bigcap: ['22C2',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
bigcup: ['22C3',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
'int': ['222B',{texClass: MML.TEXCLASS.OP}],
intop: ['222B',{texClass: MML.TEXCLASS.OP, movesupsub:true, movablelimits:true}],
iint: ['222C',{texClass: MML.TEXCLASS.OP}],
iiint: ['222D',{texClass: MML.TEXCLASS.OP}],
prod: ['220F',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
sum: ['2211',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
bigotimes: ['2A02',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
bigoplus: ['2A01',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
bigodot: ['2A00',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
oint: ['222E',{texClass: MML.TEXCLASS.OP}],
bigsqcup: ['2A06',{texClass: MML.TEXCLASS.OP, movesupsub:true}],
smallint: ['222B',{largeop:false}],
// binary operations
triangleleft: '25C3',
triangleright: '25B9',
bigtriangleup: '25B3',
bigtriangledown: '25BD',
wedge: '2227',
land: '2227',
vee: '2228',
lor: '2228',
cap: '2229',
cup: '222A',
ddagger: '2021',
dagger: '2020',
sqcap: '2293',
sqcup: '2294',
uplus: '228E',
amalg: '2A3F',
diamond: '22C4',
bullet: '2219',
wr: '2240',
div: '00F7',
odot: ['2299',{largeop: false}],
oslash: ['2298',{largeop: false}],
otimes: ['2297',{largeop: false}],
ominus: ['2296',{largeop: false}],
oplus: ['2295',{largeop: false}],
mp: '2213',
pm: '00B1',
circ: '2218',
bigcirc: '25EF',
setminus: ['2216',{variantForm:true}],
cdot: '22C5',
ast: '2217',
times: '00D7',
star: '22C6',
// Relations
propto: '221D',
sqsubseteq: '2291',
sqsupseteq: '2292',
parallel: '2225',
mid: '2223',
dashv: '22A3',
vdash: '22A2',
leq: '2264',
le: '2264',
geq: '2265',
ge: '2265',
lt: '003C',
gt: '003E',
succ: '227B',
prec: '227A',
approx: '2248',
succeq: '2AB0', // or '227C',
preceq: '2AAF', // or '227D',
supset: '2283',
subset: '2282',
supseteq: '2287',
subseteq: '2286',
'in': '2208',
ni: '220B',
notin: '2209',
owns: '220B',
gg: '226B',
ll: '226A',
sim: '223C',
simeq: '2243',
perp: '22A5',
equiv: '2261',
asymp: '224D',
smile: '2323',
frown: '2322',
ne: '2260',
neq: '2260',
cong: '2245',
doteq: '2250',
bowtie: '22C8',
models: '22A8',
notChar: '29F8',
// Arrows
Leftrightarrow: '21D4',
Leftarrow: '21D0',
Rightarrow: '21D2',
leftrightarrow: '2194',
leftarrow: '2190',
gets: '2190',
rightarrow: '2192',
to: '2192',
mapsto: '21A6',
leftharpoonup: '21BC',
leftharpoondown: '21BD',
rightharpoonup: '21C0',
rightharpoondown: '21C1',
nearrow: '2197',
searrow: '2198',
nwarrow: '2196',
swarrow: '2199',
rightleftharpoons: '21CC',
hookrightarrow: '21AA',
hookleftarrow: '21A9',
longleftarrow: '27F5',
Longleftarrow: '27F8',
longrightarrow: '27F6',
Longrightarrow: '27F9',
Longleftrightarrow: '27FA',
longleftrightarrow: '27F7',
longmapsto: '27FC',
// Misc.
ldots: '2026',
cdots: '22EF',
vdots: '22EE',
ddots: '22F1',
dotsc: '2026', // dots with commas
dotsb: '22EF', // dots with binary ops and relations
dotsm: '22EF', // dots with multiplication
dotsi: '22EF', // dots with integrals
dotso: '2026', // other dots
ldotp: ['002E', {texClass: MML.TEXCLASS.PUNCT}],
cdotp: ['22C5', {texClass: MML.TEXCLASS.PUNCT}],
colon: ['003A', {texClass: MML.TEXCLASS.PUNCT}]
},
mathchar7: {
Gamma: '0393',
Delta: '0394',
Theta: '0398',
Lambda: '039B',
Xi: '039E',
Pi: '03A0',
Sigma: '03A3',
Upsilon: '03A5',
Phi: '03A6',
Psi: '03A8',
Omega: '03A9',
'_': '005F',
'#': '0023',
'$': '0024',
'%': '0025',
'&': '0026',
And: '0026'
},
delimiter: {
'(': '(',
')': ')',
'[': '[',
']': ']',
'<': '27E8',
'>': '27E9',
'\\lt': '27E8',
'\\gt': '27E9',
'/': '/',
'|': ['|',{texClass:MML.TEXCLASS.ORD}],
'.': '',
'\\\\': '\\',
'\\lmoustache': '23B0', // non-standard
'\\rmoustache': '23B1', // non-standard
'\\lgroup': '27EE', // non-standard
'\\rgroup': '27EF', // non-standard
'\\arrowvert': '23D0',
'\\Arrowvert': '2016',
'\\bracevert': '23AA', // non-standard
'\\Vert': ['2016',{texClass:MML.TEXCLASS.ORD}],
'\\|': ['2016',{texClass:MML.TEXCLASS.ORD}],
'\\vert': ['|',{texClass:MML.TEXCLASS.ORD}],
'\\uparrow': '2191',
'\\downarrow': '2193',
'\\updownarrow': '2195',
'\\Uparrow': '21D1',
'\\Downarrow': '21D3',
'\\Updownarrow': '21D5',
'\\backslash': '\\',
'\\rangle': '27E9',
'\\langle': '27E8',
'\\rbrace': '}',
'\\lbrace': '{',
'\\}': '}',
'\\{': '{',
'\\rceil': '2309',
'\\lceil': '2308',
'\\rfloor': '230B',
'\\lfloor': '230A',
'\\lbrack': '[',
'\\rbrack': ']'
},
macros: {
displaystyle: ['SetStyle','D',true,0],
textstyle: ['SetStyle','T',false,0],
scriptstyle: ['SetStyle','S',false,1],
scriptscriptstyle: ['SetStyle','SS',false,2],
rm: ['SetFont',MML.VARIANT.NORMAL],
mit: ['SetFont',MML.VARIANT.ITALIC],
oldstyle: ['SetFont',MML.VARIANT.OLDSTYLE],
cal: ['SetFont',MML.VARIANT.CALIGRAPHIC],
it: ['SetFont',"-tex-mathit"], // needs special handling
bf: ['SetFont',MML.VARIANT.BOLD],
bbFont: ['SetFont',MML.VARIANT.DOUBLESTRUCK],
scr: ['SetFont',MML.VARIANT.SCRIPT],
frak: ['SetFont',MML.VARIANT.FRAKTUR],
sf: ['SetFont',MML.VARIANT.SANSSERIF],
tt: ['SetFont',MML.VARIANT.MONOSPACE],
// font:
tiny: ['SetSize',0.5],
Tiny: ['SetSize',0.6], // non-standard
scriptsize: ['SetSize',0.7],
small: ['SetSize',0.85],
normalsize: ['SetSize',1.0],
large: ['SetSize',1.2],
Large: ['SetSize',1.44],
LARGE: ['SetSize',1.73],
huge: ['SetSize',2.07],
Huge: ['SetSize',2.49],
arcsin: ['NamedFn'],
arccos: ['NamedFn'],
arctan: ['NamedFn'],
arg: ['NamedFn'],
cos: ['NamedFn'],
cosh: ['NamedFn'],
cot: ['NamedFn'],
coth: ['NamedFn'],
csc: ['NamedFn'],
deg: ['NamedFn'],
det: 'NamedOp',
dim: ['NamedFn'],
exp: ['NamedFn'],
gcd: 'NamedOp',
hom: ['NamedFn'],
inf: 'NamedOp',
ker: ['NamedFn'],
lg: ['NamedFn'],
lim: 'NamedOp',
liminf: ['NamedOp','lim&thinsp;inf'],
limsup: ['NamedOp','lim&thinsp;sup'],
ln: ['NamedFn'],
log: ['NamedFn'],
max: 'NamedOp',
min: 'NamedOp',
Pr: 'NamedOp',
sec: ['NamedFn'],
sin: ['NamedFn'],
sinh: ['NamedFn'],
sup: 'NamedOp',
tan: ['NamedFn'],
tanh: ['NamedFn'],
limits: ['Limits',1],
nolimits: ['Limits',0],
overline: ['UnderOver','00AF',null,1],
underline: ['UnderOver','005F'],
overbrace: ['UnderOver','23DE',1],
underbrace: ['UnderOver','23DF',1],
overparen: ['UnderOver','23DC'],
underparen: ['UnderOver','23DD'],
overrightarrow: ['UnderOver','2192'],
underrightarrow: ['UnderOver','2192'],
overleftarrow: ['UnderOver','2190'],
underleftarrow: ['UnderOver','2190'],
overleftrightarrow: ['UnderOver','2194'],
underleftrightarrow: ['UnderOver','2194'],
overset: 'Overset',
underset: 'Underset',
stackrel: ['Macro','\\mathrel{\\mathop{#2}\\limits^{#1}}',2],
over: 'Over',
overwithdelims: 'Over',
atop: 'Over',
atopwithdelims: 'Over',
above: 'Over',
abovewithdelims: 'Over',
brace: ['Over','{','}'],
brack: ['Over','[',']'],
choose: ['Over','(',')'],
frac: 'Frac',
sqrt: 'Sqrt',
root: 'Root',
uproot: ['MoveRoot','upRoot'],
leftroot: ['MoveRoot','leftRoot'],
left: 'LeftRight',
right: 'LeftRight',
middle: 'Middle',
llap: 'Lap',
rlap: 'Lap',
raise: 'RaiseLower',
lower: 'RaiseLower',
moveleft: 'MoveLeftRight',
moveright: 'MoveLeftRight',
',': ['Spacer',MML.LENGTH.THINMATHSPACE],
':': ['Spacer',MML.LENGTH.MEDIUMMATHSPACE], // for LaTeX
'>': ['Spacer',MML.LENGTH.MEDIUMMATHSPACE],
';': ['Spacer',MML.LENGTH.THICKMATHSPACE],
'!': ['Spacer',MML.LENGTH.NEGATIVETHINMATHSPACE],
enspace: ['Spacer',".5em"],
quad: ['Spacer',"1em"],
qquad: ['Spacer',"2em"],
thinspace: ['Spacer',MML.LENGTH.THINMATHSPACE],
negthinspace: ['Spacer',MML.LENGTH.NEGATIVETHINMATHSPACE],
hskip: 'Hskip',
hspace: 'Hskip',
kern: 'Hskip',
mskip: 'Hskip',
mspace: 'Hskip',
mkern: 'Hskip',
Rule: ['Rule'],
Space: ['Rule','blank'],
big: ['MakeBig',MML.TEXCLASS.ORD,0.85],
Big: ['MakeBig',MML.TEXCLASS.ORD,1.15],
bigg: ['MakeBig',MML.TEXCLASS.ORD,1.45],
Bigg: ['MakeBig',MML.TEXCLASS.ORD,1.75],
bigl: ['MakeBig',MML.TEXCLASS.OPEN,0.85],
Bigl: ['MakeBig',MML.TEXCLASS.OPEN,1.15],
biggl: ['MakeBig',MML.TEXCLASS.OPEN,1.45],
Biggl: ['MakeBig',MML.TEXCLASS.OPEN,1.75],
bigr: ['MakeBig',MML.TEXCLASS.CLOSE,0.85],
Bigr: ['MakeBig',MML.TEXCLASS.CLOSE,1.15],
biggr: ['MakeBig',MML.TEXCLASS.CLOSE,1.45],
Biggr: ['MakeBig',MML.TEXCLASS.CLOSE,1.75],
bigm: ['MakeBig',MML.TEXCLASS.REL,0.85],
Bigm: ['MakeBig',MML.TEXCLASS.REL,1.15],
biggm: ['MakeBig',MML.TEXCLASS.REL,1.45],
Biggm: ['MakeBig',MML.TEXCLASS.REL,1.75],
mathord: ['TeXAtom',MML.TEXCLASS.ORD],
mathop: ['TeXAtom',MML.TEXCLASS.OP],
mathopen: ['TeXAtom',MML.TEXCLASS.OPEN],
mathclose: ['TeXAtom',MML.TEXCLASS.CLOSE],
mathbin: ['TeXAtom',MML.TEXCLASS.BIN],
mathrel: ['TeXAtom',MML.TEXCLASS.REL],
mathpunct: ['TeXAtom',MML.TEXCLASS.PUNCT],
mathinner: ['TeXAtom',MML.TEXCLASS.INNER],
vcenter: ['TeXAtom',MML.TEXCLASS.VCENTER],
mathchoice: ['Extension','mathchoice'],
buildrel: 'BuildRel',
hbox: ['HBox',0],
text: 'HBox',
mbox: ['HBox',0],
fbox: 'FBox',
strut: 'Strut',
mathstrut: ['Macro','\\vphantom{(}'],
phantom: 'Phantom',
vphantom: ['Phantom',1,0],
hphantom: ['Phantom',0,1],
smash: 'Smash',
acute: ['Accent', "00B4"], // or 0301 or 02CA
grave: ['Accent', "0060"], // or 0300 or 02CB
ddot: ['Accent', "00A8"], // or 0308
tilde: ['Accent', "007E"], // or 0303 or 02DC
bar: ['Accent', "00AF"], // or 0304 or 02C9
breve: ['Accent', "02D8"], // or 0306
check: ['Accent', "02C7"], // or 030C
hat: ['Accent', "005E"], // or 0302 or 02C6
vec: ['Accent', "2192"], // or 20D7
dot: ['Accent', "02D9"], // or 0307
widetilde: ['Accent', "007E",1], // or 0303 or 02DC
widehat: ['Accent', "005E",1], // or 0302 or 02C6
matrix: 'Matrix',
array: 'Matrix',
pmatrix: ['Matrix','(',')'],
cases: ['Matrix','{','',"left left",null,".1em",null,true],
eqalign: ['Matrix',null,null,"right left",MML.LENGTH.THICKMATHSPACE,".5em",'D'],
displaylines: ['Matrix',null,null,"center",null,".5em",'D'],
cr: 'Cr',
'\\': 'CrLaTeX',
newline: 'Cr',
hline: ['HLine','solid'],
hdashline: ['HLine','dashed'],
// noalign: 'HandleNoAlign',
eqalignno: ['Matrix',null,null,"right left",MML.LENGTH.THICKMATHSPACE,".5em",'D',null,"right"],
leqalignno: ['Matrix',null,null,"right left",MML.LENGTH.THICKMATHSPACE,".5em",'D',null,"left"],
hfill: 'HFill',
hfil: 'HFill', // \hfil treated as \hfill for now
hfilll: 'HFill', // \hfilll treated as \hfill for now
// TeX substitution macros
bmod: ['Macro','\\mmlToken{mo}[lspace="thickmathspace" rspace="thickmathspace"]{mod}'],
pmod: ['Macro','\\pod{\\mmlToken{mi}{mod}\\kern 6mu #1}',1],
mod: ['Macro','\\mathchoice{\\kern18mu}{\\kern12mu}{\\kern12mu}{\\kern12mu}\\mmlToken{mi}{mod}\\,\\,#1',1],
pod: ['Macro','\\mathchoice{\\kern18mu}{\\kern8mu}{\\kern8mu}{\\kern8mu}(#1)',1],
iff: ['Macro','\\;\\Longleftrightarrow\\;'],
skew: ['Macro','{{#2{#3\\mkern#1mu}\\mkern-#1mu}{}}',3],
mathcal: ['Macro','{\\cal #1}',1],
mathscr: ['Macro','{\\scr #1}',1],
mathrm: ['Macro','{\\rm #1}',1],
mathbf: ['Macro','{\\bf #1}',1],
mathbb: ['Macro','{\\bbFont #1}',1],
Bbb: ['Macro','{\\bbFont #1}',1],
mathit: ['Macro','{\\it #1}',1],
mathfrak: ['Macro','{\\frak #1}',1],
mathsf: ['Macro','{\\sf #1}',1],
mathtt: ['Macro','{\\tt #1}',1],
textrm: ['Macro','\\mathord{\\rm\\text{#1}}',1],
textit: ['Macro','\\mathord{\\it\\text{#1}}',1],
textbf: ['Macro','\\mathord{\\bf\\text{#1}}',1],
textsf: ['Macro','\\mathord{\\sf\\text{#1}}',1],
texttt: ['Macro','\\mathord{\\tt\\text{#1}}',1],
pmb: ['Macro','\\rlap{#1}\\kern1px{#1}',1],
TeX: ['Macro','T\\kern-.14em\\lower.5ex{E}\\kern-.115em X'],
LaTeX: ['Macro','L\\kern-.325em\\raise.21em{\\scriptstyle{A}}\\kern-.17em\\TeX'],
' ': ['Macro','\\text{ }'],
// Specially handled
not: 'Not',
dots: 'Dots',
space: 'Tilde',
'\u00A0': 'Tilde',
// LaTeX
begin: 'BeginEnd',
end: 'BeginEnd',
newcommand: ['Extension','newcommand'],
renewcommand: ['Extension','newcommand'],
newenvironment: ['Extension','newcommand'],
renewenvironment: ['Extension','newcommand'],
def: ['Extension','newcommand'],
let: ['Extension','newcommand'],
verb: ['Extension','verb'],
boldsymbol: ['Extension','boldsymbol'],
tag: ['Extension','AMSmath'],
notag: ['Extension','AMSmath'],
label: ['Extension','AMSmath'],
ref: ['Extension','AMSmath'],
eqref: ['Extension','AMSmath'],
nonumber: ['Macro','\\notag'],
// Extensions to TeX
unicode: ['Extension','unicode'],
color: 'Color',
href: ['Extension','HTML'],
'class': ['Extension','HTML'],
style: ['Extension','HTML'],
cssId: ['Extension','HTML'],
bbox: ['Extension','bbox'],
mmlToken: 'MmlToken',
require: 'Require'
},
environment: {
array: ['AlignedArray'],
matrix: ['Array',null,null,null,'c'],
pmatrix: ['Array',null,'(',')','c'],
bmatrix: ['Array',null,'[',']','c'],
Bmatrix: ['Array',null,'\\{','\\}','c'],
vmatrix: ['Array',null,'\\vert','\\vert','c'],
Vmatrix: ['Array',null,'\\Vert','\\Vert','c'],
cases: ['Array',null,'\\{','.','ll',null,".2em",'T'],
equation: [null,'Equation'],
'equation*': [null,'Equation'],
eqnarray: ['ExtensionEnv',null,'AMSmath'],
'eqnarray*': ['ExtensionEnv',null,'AMSmath'],
align: ['ExtensionEnv',null,'AMSmath'],
'align*': ['ExtensionEnv',null,'AMSmath'],
aligned: ['ExtensionEnv',null,'AMSmath'],
multline: ['ExtensionEnv',null,'AMSmath'],
'multline*': ['ExtensionEnv',null,'AMSmath'],
split: ['ExtensionEnv',null,'AMSmath'],
gather: ['ExtensionEnv',null,'AMSmath'],
'gather*': ['ExtensionEnv',null,'AMSmath'],
gathered: ['ExtensionEnv',null,'AMSmath'],
alignat: ['ExtensionEnv',null,'AMSmath'],
'alignat*': ['ExtensionEnv',null,'AMSmath'],
alignedat: ['ExtensionEnv',null,'AMSmath']
},
p_height: 1.2 / .85 // cmex10 height plus depth over .85
});
//
// Add macros defined in the configuration
//
if (this.config.Macros) {
var MACROS = this.config.Macros;
for (var id in MACROS) {if (MACROS.hasOwnProperty(id)) {
if (typeof(MACROS[id]) === "string") {TEXDEF.macros[id] = ['Macro',MACROS[id]]}
else {TEXDEF.macros[id] = ["Macro"].concat(MACROS[id])}
TEXDEF.macros[id].isUser = true;
}}
}
};
/************************************************************************/
/*
* The TeX Parser
*/
var PARSE = MathJax.Object.Subclass({
Init: function (string,env) {
this.string = string; this.i = 0; this.macroCount = 0;
var ENV; if (env) {ENV = {}; for (var id in env) {if (env.hasOwnProperty(id)) {ENV[id] = env[id]}}}
this.stack = TEX.Stack(ENV,!!env);
this.Parse(); this.Push(STACKITEM.stop());
},
Parse: function () {
var c, n;
while (this.i < this.string.length) {
c = this.string.charAt(this.i++); n = c.charCodeAt(0);
if (n >= 0xD800 && n < 0xDC00) {c += this.string.charAt(this.i++)}
if (TEXDEF.special[c]) {this[TEXDEF.special[c]](c)}
else if (TEXDEF.letter.test(c)) {this.Variable(c)}
else if (TEXDEF.digit.test(c)) {this.Number(c)}
else {this.Other(c)}
}
},
Push: function () {this.stack.Push.apply(this.stack,arguments)},
mml: function () {
if (this.stack.Top().type !== "mml") {return null}
return this.stack.Top().data[0];
},
mmlToken: function (token) {return token}, // used by boldsymbol extension
/************************************************************************/
/*
* Handle various token classes
*/
/*
* Lookup a control-sequence and process it
*/
ControlSequence: function (c) {
var name = this.GetCS(), macro = this.csFindMacro(name);
if (macro) {
if (!isArray(macro)) {macro = [macro]}
var fn = macro[0]; if (!(fn instanceof Function)) {fn = this[fn]}
fn.apply(this,[c+name].concat(macro.slice(1)));
} else if (TEXDEF.mathchar0mi[name]) {this.csMathchar0mi(name,TEXDEF.mathchar0mi[name])}
else if (TEXDEF.mathchar0mo[name]) {this.csMathchar0mo(name,TEXDEF.mathchar0mo[name])}
else if (TEXDEF.mathchar7[name]) {this.csMathchar7(name,TEXDEF.mathchar7[name])}
else if (TEXDEF.delimiter["\\"+name] != null) {this.csDelimiter(name,TEXDEF.delimiter["\\"+name])}
else {this.csUndefined(c+name)}
},
//
// Look up a macro in the macros list
// (overridden in begingroup extension)
//
csFindMacro: function (name) {return TEXDEF.macros[name]},
//
// Handle normal mathchar (as an mi)
//
csMathchar0mi: function (name,mchar) {
var def = {mathvariant: MML.VARIANT.ITALIC};
if (isArray(mchar)) {def = mchar[1]; mchar = mchar[0]}
this.Push(this.mmlToken(MML.mi(MML.entity("#x"+mchar)).With(def)));
},
//
// Handle normal mathchar (as an mo)
//
csMathchar0mo: function (name,mchar) {
var def = {stretchy: false};
if (isArray(mchar)) {def = mchar[1]; def.stretchy = false; mchar = mchar[0]}
this.Push(this.mmlToken(MML.mo(MML.entity("#x"+mchar)).With(def)));
},
//
// Handle mathchar in current family
//
csMathchar7: function (name,mchar) {
var def = {mathvariant: MML.VARIANT.NORMAL};
if (isArray(mchar)) {def = mchar[1]; mchar = mchar[0]}
if (this.stack.env.font) {def.mathvariant = this.stack.env.font}
this.Push(this.mmlToken(MML.mi(MML.entity("#x"+mchar)).With(def)));
},
//
// Handle delimiter
//
csDelimiter: function (name,delim) {
var def = {};
if (isArray(delim)) {def = delim[1]; delim = delim[0]}
if (delim.length === 4) {delim = MML.entity('#x'+delim)} else {delim = MML.chars(delim)}
this.Push(this.mmlToken(MML.mo(delim).With({fence: false, stretchy: false}).With(def)));
},
//
// Handle undefined control sequence
// (overridden in noUndefined extension)
//
csUndefined: function (name) {
TEX.Error(["UndefinedControlSequence","Undefined control sequence %1",name]);
},
/*
* Handle a variable (a single letter)
*/
Variable: function (c) {
var def = {}; if (this.stack.env.font) {def.mathvariant = this.stack.env.font}
this.Push(this.mmlToken(MML.mi(MML.chars(c)).With(def)));
},
/*
* Determine the extent of a number (pattern may need work)
*/
Number: function (c) {
var mml, n = this.string.slice(this.i-1).match(TEXDEF.number);
if (n) {mml = MML.mn(n[0].replace(/[{}]/g,"")); this.i += n[0].length - 1}
else {mml = MML.mo(MML.chars(c))}
if (this.stack.env.font) {mml.mathvariant = this.stack.env.font}
this.Push(this.mmlToken(mml));
},
/*
* Handle { and }
*/
Open: function (c) {this.Push(STACKITEM.open())},
Close: function (c) {this.Push(STACKITEM.close())},
/*
* Handle tilde and spaces
*/
Tilde: function (c) {this.Push(MML.mtext(MML.chars(NBSP)))},
Space: function (c) {},
/*
* Handle ^, _, and '
*/
Superscript: function (c) {
if (this.GetNext().match(/\d/)) // don't treat numbers as a unit
{this.string = this.string.substr(0,this.i+1)+" "+this.string.substr(this.i+1)}
var primes, base, top = this.stack.Top();
if (top.type === "prime") {base = top.data[0]; primes = top.data[1]; this.stack.Pop()}
else {base = this.stack.Prev(); if (!base) {base = MML.mi("")}}
if (base.isEmbellishedWrapper) {base = base.data[0].data[0]}
var movesupsub = base.movesupsub, position = base.sup;
if ((base.type === "msubsup" && base.data[base.sup]) ||
(base.type === "munderover" && base.data[base.over] && !base.subsupOK))
{TEX.Error(["DoubleExponent","Double exponent: use braces to clarify"])}
if (base.type !== "msubsup") {
if (movesupsub) {
if (base.type !== "munderover" || base.data[base.over]) {
if (base.movablelimits && base.isa(MML.mi)) {base = this.mi2mo(base)}
base = MML.munderover(base,null,null).With({movesupsub:true})
}
position = base.over;
} else {
base = MML.msubsup(base,null,null);
position = base.sup;
}
}
this.Push(STACKITEM.subsup(base).With({
position: position, primes: primes, movesupsub: movesupsub
}));
},
Subscript: function (c) {
if (this.GetNext().match(/\d/)) // don't treat numbers as a unit
{this.string = this.string.substr(0,this.i+1)+" "+this.string.substr(this.i+1)}
var primes, base, top = this.stack.Top();
if (top.type === "prime") {base = top.data[0]; primes = top.data[1]; this.stack.Pop()}
else {base = this.stack.Prev(); if (!base) {base = MML.mi("")}}
if (base.isEmbellishedWrapper) {base = base.data[0].data[0]}
var movesupsub = base.movesupsub, position = base.sub;
if ((base.type === "msubsup" && base.data[base.sub]) ||
(base.type === "munderover" && base.data[base.under] && !base.subsupOK))
{TEX.Error(["DoubleSubscripts","Double subscripts: use braces to clarify"])}
if (base.type !== "msubsup") {
if (movesupsub) {
if (base.type !== "munderover" || base.data[base.under]) {
if (base.movablelimits && base.isa(MML.mi)) {base = this.mi2mo(base)}
base = MML.munderover(base,null,null).With({movesupsub:true})
}
position = base.under;
} else {
base = MML.msubsup(base,null,null);
position = base.sub;
}
}
this.Push(STACKITEM.subsup(base).With({
position: position, primes: primes, movesupsub: movesupsub
}));
},
PRIME: "\u2032", SMARTQUOTE: "\u2019",
Prime: function (c) {
var base = this.stack.Prev(); if (!base) {base = MML.mi()}
if (base.type === "msubsup" && base.data[base.sup]) {
TEX.Error(["DoubleExponentPrime",
"Prime causes double exponent: use braces to clarify"]);
}
var sup = ""; this.i--;
do {sup += this.PRIME; this.i++, c = this.GetNext()}
while (c === "'" || c === this.SMARTQUOTE);
sup = ["","\u2032","\u2033","\u2034","\u2057"][sup.length] || sup;
this.Push(STACKITEM.prime(base,this.mmlToken(MML.mo(sup))));
},
mi2mo: function (mi) {
var mo = MML.mo(); mo.Append.apply(mo,mi.data); var id;
for (id in mo.defaults)
{if (mo.defaults.hasOwnProperty(id) && mi[id] != null) {mo[id] = mi[id]}}
for (id in MML.copyAttributes)
{if (MML.copyAttributes.hasOwnProperty(id) && mi[id] != null) {mo[id] = mi[id]}}
mo.lspace = mo.rspace = "0"; // prevent mo from having space in NativeMML
mo.useMMLspacing &= ~(mo.SPACE_ATTR.lspace | mo.SPACE_ATTR.rspace); // don't count these explicit settings
return mo;
},
/*
* Handle comments
*/
Comment: function (c) {
while (this.i < this.string.length && this.string.charAt(this.i) != "\n") {this.i++}
},
/*
* Handle hash marks outside of definitions
*/
Hash: function (c) {
TEX.Error(["CantUseHash1",
"You can't use 'macro parameter character #' in math mode"]);
},
/*
* Handle other characters (as <mo> elements)
*/
Other: function (c) {
var def, mo;
if (this.stack.env.font) {def = {mathvariant: this.stack.env.font}}
if (TEXDEF.remap[c]) {
c = TEXDEF.remap[c];
if (isArray(c)) {def = c[1]; c = c[0]}
mo = MML.mo(MML.entity('#x'+c)).With(def);
} else {
mo = MML.mo(c).With(def);
}
if (mo.autoDefault("stretchy",true)) {mo.stretchy = false}
if (mo.autoDefault("texClass",true) == "") {mo = MML.TeXAtom(mo)}
this.Push(this.mmlToken(mo));
},
/************************************************************************/
/*
* Macros
*/
SetFont: function (name,font) {this.stack.env.font = font},
SetStyle: function (name,texStyle,style,level) {
this.stack.env.style = texStyle; this.stack.env.level = level;
this.Push(STACKITEM.style().With({styles: {displaystyle: style, scriptlevel: level}}));
},
SetSize: function (name,size) {
this.stack.env.size = size;
this.Push(STACKITEM.style().With({styles: {mathsize: size+"em"}})); // convert to absolute?
},
Color: function (name) {
var color = this.GetArgument(name);
var old = this.stack.env.color; this.stack.env.color = color;
var math = this.ParseArg(name);
if (old) {this.stack.env.color} else {delete this.stack.env.color}
this.Push(MML.mstyle(math).With({mathcolor: color}));
},
Spacer: function (name,space) {
this.Push(MML.mspace().With({width: space, mathsize: MML.SIZE.NORMAL, scriptlevel:0}));
},
LeftRight: function (name) {
this.Push(STACKITEM[name.substr(1)]().With({delim: this.GetDelimiter(name)}));
},
Middle: function (name) {
var delim = this.GetDelimiter(name);
this.Push(MML.TeXAtom().With({texClass:MML.TEXCLASS.CLOSE}));
if (this.stack.Top().type !== "left")
{TEX.Error(["MisplacedMiddle","%1 must be within \\left and \\right",name])}
this.Push(MML.mo(delim).With({stretchy:true}));
this.Push(MML.TeXAtom().With({texClass:MML.TEXCLASS.OPEN}));
},
NamedFn: function (name,id) {
if (!id) {id = name.substr(1)};
var mml = MML.mi(id).With({texClass: MML.TEXCLASS.OP});
this.Push(STACKITEM.fn(this.mmlToken(mml)));
},
NamedOp: function (name,id) {
if (!id) {id = name.substr(1)};
id = id.replace(/&thinsp;/,"\u2006");
var mml = MML.mo(id).With({
movablelimits: true,
movesupsub: true,
form: MML.FORM.PREFIX,
texClass: MML.TEXCLASS.OP
});
mml.useMMLspacing &= ~mml.SPACE_ATTR.form; // don't count this explicit form setting
this.Push(this.mmlToken(mml));
},
Limits: function (name,limits) {
var op = this.stack.Prev("nopop");
if (!op || (op.Get("texClass") !== MML.TEXCLASS.OP && op.movesupsub == null))
{TEX.Error(["MisplacedLimits","%1 is allowed only on operators",name])}
var top = this.stack.Top();
if (op.type === "munderover" && !limits) {
op = top.data[top.data.length-1] = MML.msubsup.apply(MML.subsup,op.data);
} else if (op.type === "msubsup" && limits) {
op = top.data[top.data.length-1] = MML.munderover.apply(MML.underover,op.data);
}
op.movesupsub = (limits ? true : false);
op.Core().movablelimits = false;
if (op.movablelimits) op.movablelimits = false;
},
Over: function (name,open,close) {
var mml = STACKITEM.over().With({name: name});
if (open || close) {
mml.open = open; mml.close = close;
} else if (name.match(/withdelims$/)) {
mml.open = this.GetDelimiter(name);
mml.close = this.GetDelimiter(name);
}
if (name.match(/^\\above/)) {mml.thickness = this.GetDimen(name)}
else if (name.match(/^\\atop/) || open || close) {mml.thickness = 0}
this.Push(mml);
},
Frac: function (name) {
var num = this.ParseArg(name);
var den = this.ParseArg(name);
this.Push(MML.mfrac(num,den));
},
Sqrt: function (name) {
var n = this.GetBrackets(name), arg = this.GetArgument(name);
if (arg === "\\frac") {arg += "{"+this.GetArgument(arg)+"}{"+this.GetArgument(arg)+"}"}
var mml = TEX.Parse(arg,this.stack.env).mml();
if (!n) {mml = MML.msqrt.apply(MML,mml.array())}
else {mml = MML.mroot(mml,this.parseRoot(n))}
this.Push(mml);
},
Root: function (name) {
var n = this.GetUpTo(name,"\\of");
var arg = this.ParseArg(name);
this.Push(MML.mroot(arg,this.parseRoot(n)));
},
parseRoot: function (n) {
var env = this.stack.env, inRoot = env.inRoot; env.inRoot = true;
var parser = TEX.Parse(n,env); n = parser.mml(); var global = parser.stack.global;
if (global.leftRoot || global.upRoot) {
n = MML.mpadded(n);
if (global.leftRoot) {n.width = global.leftRoot}
if (global.upRoot) {n.voffset = global.upRoot; n.height = global.upRoot}
}
env.inRoot = inRoot;
return n;
},
MoveRoot: function (name,id) {
if (!this.stack.env.inRoot)
{TEX.Error(["MisplacedMoveRoot","%1 can appear only within a root",name])}
if (this.stack.global[id])
{TEX.Error(["MultipleMoveRoot","Multiple use of %1",name])}
var n = this.GetArgument(name);
if (!n.match(/-?[0-9]+/))
{TEX.Error(["IntegerArg","The argument to %1 must be an integer",name])}
n = (n/15)+"em";
if (n.substr(0,1) !== "-") {n = "+"+n}
this.stack.global[id] = n;
},
Accent: function (name,accent,stretchy) {
var c = this.ParseArg(name);
var def = {accent: true}; if (this.stack.env.font) {def.mathvariant = this.stack.env.font}
var mml = this.mmlToken(MML.mo(MML.entity("#x"+accent)).With(def));
mml.stretchy = (stretchy ? true : false);
var mo = (c.isEmbellished() ? c.CoreMO() : c);
if (mo.isa(MML.mo)) mo.movablelimits = false;
this.Push(MML.TeXAtom(MML.munderover(c,null,mml).With({accent: true})));
},
UnderOver: function (name,c,stack,noaccent) {
var pos = {o: "over", u: "under"}[name.charAt(1)];
var base = this.ParseArg(name);
if (base.Get("movablelimits")) {base.movablelimits = false}
if (base.isa(MML.munderover) && base.isEmbellished()) {
base.Core().With({lspace:0,rspace:0}); // get spacing right for NativeMML
base = MML.mrow(MML.mo().With({rspace:0}),base); // add an empty <mi> so it's not embellished any more
}
var mml = MML.munderover(base,null,null);
mml.SetData(
mml[pos],
this.mmlToken(MML.mo(MML.entity("#x"+c)).With({stretchy:true, accent:!noaccent}))
);
if (stack) {mml = MML.TeXAtom(mml).With({texClass:MML.TEXCLASS.OP, movesupsub:true})}
this.Push(mml.With({subsupOK:true}));
},
Overset: function (name) {
var top = this.ParseArg(name), base = this.ParseArg(name);
if (base.movablelimits) base.movablelimits = false;
this.Push(MML.mover(base,top));
},
Underset: function (name) {
var bot = this.ParseArg(name), base = this.ParseArg(name);
if (base.movablelimits) base.movablelimits = false;
this.Push(MML.munder(base,bot));
},
TeXAtom: function (name,mclass) {
var def = {texClass: mclass}, mml;
if (mclass == MML.TEXCLASS.OP) {
def.movesupsub = def.movablelimits = true;
var arg = this.GetArgument(name);
var match = arg.match(/^\s*\\rm\s+([a-zA-Z0-9 ]+)$/);
if (match) {
def.mathvariant = MML.VARIANT.NORMAL;
mml = STACKITEM.fn(this.mmlToken(MML.mi(match[1]).With(def)));
} else {
mml = STACKITEM.fn(MML.TeXAtom(TEX.Parse(arg,this.stack.env).mml()).With(def));
}
} else {mml = MML.TeXAtom(this.ParseArg(name)).With(def)}
this.Push(mml);
},
MmlToken: function (name) {
var type = this.GetArgument(name),
attr = this.GetBrackets(name,"").replace(/^\s+/,""),
data = this.GetArgument(name),
def = {attrNames:[]}, match;
if (!MML[type] || !MML[type].prototype.isToken)
{TEX.Error(["NotMathMLToken","%1 is not a token element",type])}
while (attr !== "") {
match = attr.match(/^([a-z]+)\s*=\s*('[^']*'|"[^"]*"|[^ ,]*)\s*,?\s*/i);
if (!match)
{TEX.Error(["InvalidMathMLAttr","Invalid MathML attribute: %1",attr])}
if (MML[type].prototype.defaults[match[1]] == null && !this.MmlTokenAllow[match[1]]) {
TEX.Error(["UnknownAttrForElement",
"%1 is not a recognized attribute for %2",
match[1],type]);
}
var value = this.MmlFilterAttribute(match[1],match[2].replace(/^(['"])(.*)\1$/,"$2"));
if (value) {
if (value.toLowerCase() === "true") {value = true}
else if (value.toLowerCase() === "false") {value = false}
def[match[1]] = value;
def.attrNames.push(match[1]);
}
attr = attr.substr(match[0].length);
}
this.Push(this.mmlToken(MML[type](data).With(def)));
},
MmlFilterAttribute: function (name,value) {return value},
MmlTokenAllow: {
fontfamily:1, fontsize:1, fontweight:1, fontstyle:1,
color:1, background:1,
id:1, "class":1, href:1, style:1
},
Strut: function (name) {
this.Push(MML.mpadded(MML.mrow()).With({height: "8.6pt", depth: "3pt", width: 0}));
},
Phantom: function (name,v,h) {
var box = MML.mphantom(this.ParseArg(name));
if (v || h) {
box = MML.mpadded(box);
if (h) {box.height = box.depth = 0}
if (v) {box.width = 0}
}
this.Push(MML.TeXAtom(box));
},
Smash: function (name) {
var bt = this.trimSpaces(this.GetBrackets(name,""));
var smash = MML.mpadded(this.ParseArg(name));
switch (bt) {
case "b": smash.depth = 0; break;
case "t": smash.height = 0; break;
default: smash.height = smash.depth = 0;
}
this.Push(MML.TeXAtom(smash));
},
Lap: function (name) {
var mml = MML.mpadded(this.ParseArg(name)).With({width: 0});
if (name === "\\llap") {mml.lspace = "-1width"}
this.Push(MML.TeXAtom(mml));
},
RaiseLower: function (name) {
var h = this.GetDimen(name);
var item = STACKITEM.position().With({name: name, move: 'vertical'});
if (h.charAt(0) === '-') {h = h.slice(1); name = {raise: "\\lower", lower: "\\raise"}[name.substr(1)]}
if (name === "\\lower") {item.dh = '-'+h; item.dd = '+'+h} else {item.dh = '+'+h; item.dd = '-'+h}
this.Push(item);
},
MoveLeftRight: function (name) {
var h = this.GetDimen(name);
var nh = (h.charAt(0) === '-' ? h.slice(1) : '-'+h);
if (name === "\\moveleft") {var tmp = h; h = nh; nh = tmp}
this.Push(STACKITEM.position().With({
name: name, move: 'horizontal',
left: MML.mspace().With({width: h, mathsize: MML.SIZE.NORMAL}),
right: MML.mspace().With({width: nh, mathsize: MML.SIZE.NORMAL})
}));
},
Hskip: function (name) {
this.Push(MML.mspace().With({width: this.GetDimen(name), mathsize: MML.SIZE.NORMAL}));
},
Rule: function (name,style) {
var w = this.GetDimen(name),
h = this.GetDimen(name),
d = this.GetDimen(name);
var mml, def = {width:w, height:h, depth:d};
if (style !== 'blank') {
if (parseFloat(w) && parseFloat(h)+parseFloat(d))
{def.mathbackground = (this.stack.env.color || "black")}
mml = MML.mpadded(MML.mrow()).With(def);
} else {
mml = MML.mspace().With(def);
}
this.Push(mml);
},
MakeBig: function (name,mclass,size) {
size *= TEXDEF.p_height;
size = String(size).replace(/(\.\d\d\d).+/,'$1')+"em";
var delim = this.GetDelimiter(name,true);
this.Push(MML.TeXAtom(MML.mo(delim).With({
minsize: size, maxsize: size,
fence: true, stretchy: true, symmetric: true
})).With({texClass: mclass}));
},
BuildRel: function (name) {
var top = this.ParseUpTo(name,"\\over");
var bot = this.ParseArg(name);
this.Push(MML.TeXAtom(MML.munderover(bot,null,top)).With({texClass: MML.TEXCLASS.REL}));
},
HBox: function (name,style) {
this.Push.apply(this,this.InternalMath(this.GetArgument(name),style));
},
FBox: function (name) {
this.Push(MML.menclose.apply(MML,this.InternalMath(this.GetArgument(name))).With({notation:"box"}));
},
Not: function (name) {
this.Push(STACKITEM.not());
},
Dots: function (name) {
this.Push(STACKITEM.dots().With({
ldots: this.mmlToken(MML.mo(MML.entity("#x2026")).With({stretchy:false})),
cdots: this.mmlToken(MML.mo(MML.entity("#x22EF")).With({stretchy:false}))
}));
},
Require: function (name) {
var file = this.GetArgument(name)
.replace(/.*\//,"") // remove any leading path
.replace(/[^a-z0-9_.-]/ig,""); // remove illegal characters
this.Extension(null,file);
},
Extension: function (name,file,array) {
if (name && !typeof(name) === "string") {name = name.name}
file = TEX.extensionDir+"/"+file;
if (!file.match(/\.js$/)) {file += ".js"}
if (!AJAX.loaded[AJAX.fileURL(file)]) {
if (name != null) {delete TEXDEF[array || 'macros'][name.replace(/^\\/,"")]}
HUB.RestartAfter(AJAX.Require(file));
}
},
Macro: function (name,macro,argcount,def) {
if (argcount) {
var args = [];
if (def != null) {
var optional = this.GetBrackets(name);
args.push(optional == null ? def : optional);
}
for (var i = args.length; i < argcount; i++) {args.push(this.GetArgument(name))}
macro = this.SubstituteArgs(args,macro);
}
this.string = this.AddArgs(macro,this.string.slice(this.i));
this.i = 0;
if (++this.macroCount > TEX.config.MAXMACROS) {
TEX.Error(["MaxMacroSub1",
"MathJax maximum macro substitution count exceeded; " +
"is there a recursive macro call?"]);
}
},
Matrix: function (name,open,close,align,spacing,vspacing,style,cases,numbered) {
var c = this.GetNext();
if (c === "")
{TEX.Error(["MissingArgFor","Missing argument for %1",name])}
if (c === "{") {this.i++} else {this.string = c+"}"+this.string.slice(this.i+1); this.i = 0}
var array = STACKITEM.array().With({
requireClose: true,
arraydef: {
rowspacing: (vspacing||"4pt"),
columnspacing: (spacing||"1em")
}
});
if (cases) {array.isCases = true}
if (numbered) {array.isNumbered = true; array.arraydef.side = numbered}
if (open || close) {array.open = open; array.close = close}
if (style === "D") {array.arraydef.displaystyle = true}
if (align != null) {array.arraydef.columnalign = align}
this.Push(array);
},
Entry: function (name) {
this.Push(STACKITEM.cell().With({isEntry: true, name: name}));
if (this.stack.Top().isCases) {
var string = this.string;
var braces = 0, i = this.i, m = string.length;
while (i < m) {
var c = string.charAt(i);
if (c === "{") {braces++; i++}
else if (c === "}") {if (braces === 0) {m = 0} else {braces--; i++}}
else if (c === "&" && braces === 0) {
TEX.Error(["ExtraAlignTab","Extra alignment tab in \\cases text"]);
} else if (c === "\\") {
if (string.substr(i).match(/^((\\cr)[^a-zA-Z]|\\\\)/)) {m = 0} else {i += 2}
} else {i++}
}
var text = string.substr(this.i,i-this.i);
if (!text.match(/^\s*\\text[^a-zA-Z]/)) {
this.Push.apply(this,this.InternalMath(text,0));
this.i = i;
}
}
},
Cr: function (name) {
this.Push(STACKITEM.cell().With({isCR: true, name: name}));
},
CrLaTeX: function (name) {
var n;
if (this.string.charAt(this.i) === "[") {
n = this.GetBrackets(name,"").replace(/ /g,"").replace(/,/,".");
if (n && !this.matchDimen(n)) {
TEX.Error(["BracketMustBeDimension",
"Bracket argument to %1 must be a dimension",name]);
}
}
this.Push(STACKITEM.cell().With({isCR: true, name: name, linebreak: true}));
var top = this.stack.Top();
if (top.isa(STACKITEM.array)) {
if (n && top.arraydef.rowspacing) {
var rows = top.arraydef.rowspacing.split(/ /);
if (!top.rowspacing) {top.rowspacing = this.dimen2em(rows[0])}
while (rows.length < top.table.length) {rows.push(this.Em(top.rowspacing))}
rows[top.table.length-1] = this.Em(Math.max(0,top.rowspacing+this.dimen2em(n)));
top.arraydef.rowspacing = rows.join(' ');
}
} else {
if (n) {this.Push(MML.mspace().With({depth:n}))}
this.Push(MML.mspace().With({linebreak:MML.LINEBREAK.NEWLINE}));
}
},
emPerInch: 7.2,
pxPerInch: 72,
matchDimen: function (dim) {
return dim.match(/^(-?(?:\.\d+|\d+(?:\.\d*)?))(px|pt|em|ex|mu|pc|in|mm|cm)$/);
},
dimen2em: function (dim) {
var match = this.matchDimen(dim);
var m = parseFloat(match[1]||"1"), unit = match[2];
if (unit === "em") {return m}
if (unit === "ex") {return m * .43}
if (unit === "pt") {return m / 10} // 10 pt to an em
if (unit === "pc") {return m * 1.2} // 12 pt to a pc
if (unit === "px") {return m * this.emPerInch / this.pxPerInch}
if (unit === "in") {return m * this.emPerInch}
if (unit === "cm") {return m * this.emPerInch / 2.54} // 2.54 cm to an inch
if (unit === "mm") {return m * this.emPerInch / 25.4} // 10 mm to a cm
if (unit === "mu") {return m / 18}
return 0;
},
Em: function (m) {
if (Math.abs(m) < .0006) {return "0em"}
return m.toFixed(3).replace(/\.?0+$/,"") + "em";
},
HLine: function (name,style) {
if (style == null) {style = "solid"}
var top = this.stack.Top();
if (!top.isa(STACKITEM.array) || top.data.length)
{TEX.Error(["Misplaced","Misplaced %1",name])}
if (top.table.length == 0) {
top.frame.push("top");
} else {
var lines = (top.arraydef.rowlines ? top.arraydef.rowlines.split(/ /) : []);
while (lines.length < top.table.length) {lines.push("none")}
lines[top.table.length-1] = style;
top.arraydef.rowlines = lines.join(' ');
}
},
HFill: function (name) {
var top = this.stack.Top();
if (top.isa(STACKITEM.array)) top.hfill.push(top.data.length);
else TEX.Error(["UnsupportedHFill","Unsupported use of %1",name]);
},
/************************************************************************/
/*
* LaTeX environments
*/
BeginEnd: function (name) {
var env = this.GetArgument(name), isEnd = false;
if (env.match(/^\\end\\/)) {isEnd = true; env = env.substr(5)} // special \end{} for \newenvironment environments
if (env.match(/\\/i)) {TEX.Error(["InvalidEnv","Invalid environment name '%1'",env])}
var cmd = this.envFindName(env);
if (!cmd) {TEX.Error(["UnknownEnv","Unknown environment '%1'",env])}
if (!isArray(cmd)) {cmd = [cmd]}
var end = (isArray(cmd[1]) ? cmd[1][0] : cmd[1]);
var mml = STACKITEM.begin().With({name: env, end: end, parse:this});
if (name === "\\end") {
if (!isEnd && isArray(cmd[1]) && this[cmd[1][1]]) {
mml = this[cmd[1][1]].apply(this,[mml].concat(cmd.slice(2)));
} else {
mml = STACKITEM.end().With({name: env});
}
} else {
if (++this.macroCount > TEX.config.MAXMACROS) {
TEX.Error(["MaxMacroSub2",
"MathJax maximum substitution count exceeded; " +
"is there a recursive latex environment?"]);
}
if (cmd[0] && this[cmd[0]]) {mml = this[cmd[0]].apply(this,[mml].concat(cmd.slice(2)))}
}
this.Push(mml);
},
envFindName: function (name) {return TEXDEF.environment[name]},
Equation: function (begin,row) {return row},
ExtensionEnv: function (begin,file) {this.Extension(begin.name,file,"environment")},
Array: function (begin,open,close,align,spacing,vspacing,style,raggedHeight) {
if (!align) {align = this.GetArgument("\\begin{"+begin.name+"}")}
var lines = ("c"+align).replace(/[^clr|:]/g,'').replace(/[^|:]([|:])+/g,'$1');
align = align.replace(/[^clr]/g,'').split('').join(' ');
align = align.replace(/l/g,'left').replace(/r/g,'right').replace(/c/g,'center');
var array = STACKITEM.array().With({
arraydef: {
columnalign: align,
columnspacing: (spacing||"1em"),
rowspacing: (vspacing||"4pt")
}
});
if (lines.match(/[|:]/)) {
if (lines.charAt(0).match(/[|:]/)) {array.frame.push("left"); array.frame.dashed = lines.charAt(0) === ":"}
if (lines.charAt(lines.length-1).match(/[|:]/)) {array.frame.push("right")}
lines = lines.substr(1,lines.length-2);
array.arraydef.columnlines =
lines.split('').join(' ').replace(/[^|: ]/g,'none').replace(/\|/g,'solid').replace(/:/g,'dashed');
}
if (open) {array.open = this.convertDelimiter(open)}
if (close) {array.close = this.convertDelimiter(close)}
if (style === "D") {array.arraydef.displaystyle = true}
else if (style) {array.arraydef.displaystyle = false}
if (style === "S") {array.arraydef.scriptlevel = 1} // FIXME: should use mstyle?
if (raggedHeight) {array.arraydef.useHeight = false}
this.Push(begin);
return array;
},
AlignedArray: function (begin) {
var align = this.GetBrackets("\\begin{"+begin.name+"}");
return this.setArrayAlign(this.Array.apply(this,arguments),align);
},
setArrayAlign: function (array,align) {
align = this.trimSpaces(align||"");
if (align === "t") {array.arraydef.align = "baseline 1"}
else if (align === "b") {array.arraydef.align = "baseline -1"}
else if (align === "c") {array.arraydef.align = "center"}
else if (align) {array.arraydef.align = align} // FIXME: should be an error?
return array;
},
/************************************************************************/
/*
* String handling routines
*/
/*
* Convert delimiter to character
*/
convertDelimiter: function (c) {
if (c) {c = TEXDEF.delimiter[c]}
if (c == null) {return null}
if (isArray(c)) {c = c[0]}
if (c.length === 4) {c = String.fromCharCode(parseInt(c,16))}
return c;
},
/*
* Trim spaces from a string
*/
trimSpaces: function (text) {
if (typeof(text) != 'string') {return text}
var TEXT = text.replace(/^\s+|\s+$/g,'');
if (TEXT.match(/\\$/) && text.match(/ $/)) TEXT += " ";
return TEXT;
},
/*
* Check if the next character is a space
*/
nextIsSpace: function () {
return this.string.charAt(this.i).match(/\s/);
},
/*
* Get the next non-space character
*/
GetNext: function () {
while (this.nextIsSpace()) {this.i++}
return this.string.charAt(this.i);
},
/*
* Get and return a control-sequence name
*/
GetCS: function () {
var CS = this.string.slice(this.i).match(/^([a-z]+|.) ?/i);
if (CS) {this.i += CS[1].length; return CS[1]} else {this.i++; return " "}
},
/*
* Get and return a TeX argument (either a single character or control sequence,
* or the contents of the next set of braces).
*/
GetArgument: function (name,noneOK) {
switch (this.GetNext()) {
case "":
if (!noneOK) {TEX.Error(["MissingArgFor","Missing argument for %1",name])}
return null;
case '}':
if (!noneOK) {
TEX.Error(["ExtraCloseMissingOpen",
"Extra close brace or missing open brace"]);
}
return null;
case '\\':
this.i++; return "\\"+this.GetCS();
case '{':
var j = ++this.i, parens = 1;
while (this.i < this.string.length) {
switch (this.string.charAt(this.i++)) {
case '\\': this.i++; break;
case '{': parens++; break;
case '}':
if (--parens == 0) {return this.string.slice(j,this.i-1)}
break;
}
}
TEX.Error(["MissingCloseBrace","Missing close brace"]);
break;
}
return this.string.charAt(this.i++);
},
/*
* Get an optional LaTeX argument in brackets
*/
GetBrackets: function (name,def) {
if (this.GetNext() != '[') {return def};
var j = ++this.i, parens = 0;
while (this.i < this.string.length) {
switch (this.string.charAt(this.i++)) {
case '{': parens++; break;
case '\\': this.i++; break;
case '}':
if (parens-- <= 0) {
TEX.Error(["ExtraCloseLooking",
"Extra close brace while looking for %1","']'"]);
}
break;
case ']':
if (parens == 0) {return this.string.slice(j,this.i-1)}
break;
}
}
TEX.Error(["MissingCloseBracket",
"Couldn't find closing ']' for argument to %1",name]);
},
/*
* Get the name of a delimiter (check it in the delimiter list).
*/
GetDelimiter: function (name,braceOK) {
while (this.nextIsSpace()) {this.i++}
var c = this.string.charAt(this.i); this.i++;
if (this.i <= this.string.length) {
if (c == "\\") {c += this.GetCS(name)}
else if (c === "{" && braceOK) {this.i--; c = this.GetArgument(name)}
if (TEXDEF.delimiter[c] != null) {return this.convertDelimiter(c)}
}
TEX.Error(["MissingOrUnrecognizedDelim",
"Missing or unrecognized delimiter for %1",name]);
},
/*
* Get a dimension (including its units).
*/
GetDimen: function (name) {
var dimen;
if (this.nextIsSpace()) {this.i++}
if (this.string.charAt(this.i) == '{') {
dimen = this.GetArgument(name);
if (dimen.match(/^\s*([-+]?([.,]\d+|\d+([.,]\d*)?))\s*(pt|em|ex|mu|px|mm|cm|in|pc)\s*$/))
{return dimen.replace(/ /g,"").replace(/,/,".")}
} else {
dimen = this.string.slice(this.i);
var match = dimen.match(/^\s*(([-+]?([.,]\d+|\d+([.,]\d*)?))\s*(pt|em|ex|mu|px|mm|cm|in|pc)) ?/);
if (match) {
this.i += match[0].length;
return match[1].replace(/ /g,"").replace(/,/,".");
}
}
TEX.Error(["MissingDimOrUnits",
"Missing dimension or its units for %1",name]);
},
/*
* Get everything up to the given control sequence (token)
*/
GetUpTo: function (name,token) {
while (this.nextIsSpace()) {this.i++}
var j = this.i, k, c, parens = 0;
while (this.i < this.string.length) {
k = this.i; c = this.string.charAt(this.i++);
switch (c) {
case '\\': c += this.GetCS(); break;
case '{': parens++; break;
case '}':
if (parens == 0) {
TEX.Error(["ExtraCloseLooking",
"Extra close brace while looking for %1",token])
}
parens--;
break;
}
if (parens == 0 && c == token) {return this.string.slice(j,k)}
}
TEX.Error(["TokenNotFoundForCommand",
"Couldn't find %1 for %2",token,name]);
},
/*
* Parse various substrings
*/
ParseArg: function (name) {return TEX.Parse(this.GetArgument(name),this.stack.env).mml()},
ParseUpTo: function (name,token) {return TEX.Parse(this.GetUpTo(name,token),this.stack.env).mml()},
/*
* Break up a string into text and math blocks
*/
InternalMath: function (text,level) {
var def = (this.stack.env.font ? {mathvariant: this.stack.env.font} : {});
var mml = [], i = 0, k = 0, c, match = '', braces = 0;
if (text.match(/\\?[${}\\]|\\\(|\\(eq)?ref\s*\{/)) {
while (i < text.length) {
c = text.charAt(i++);
if (c === '$') {
if (match === '$' && braces === 0) {
mml.push(MML.TeXAtom(TEX.Parse(text.slice(k,i-1),{}).mml()));
match = ''; k = i;
} else if (match === '') {
if (k < i-1) mml.push(this.InternalText(text.slice(k,i-1),def));
match = '$'; k = i;
}
} else if (c === '{' && match !== '') {
braces++;
} else if (c === '}') {
if (match === '}' && braces === 0) {
mml.push(MML.TeXAtom(TEX.Parse(text.slice(k,i),{}).mml().With(def)));
match = ''; k = i;
} else if (match !== '') {
if (braces) braces--;
}
} else if (c === '\\') {
if (match === '' && text.substr(i).match(/^(eq)?ref\s*\{/)) {
var len = RegExp["$&"].length;
if (k < i-1) mml.push(this.InternalText(text.slice(k,i-1),def));
match = '}'; k = i-1; i += len;
} else {
c = text.charAt(i++);
if (c === '(' && match === '') {
if (k < i-2) mml.push(this.InternalText(text.slice(k,i-2),def));
match = ')'; k = i;
} else if (c === ')' && match === ')' && braces === 0) {
mml.push(MML.TeXAtom(TEX.Parse(text.slice(k,i-2),{}).mml()));
match = ''; k = i;
} else if (c.match(/[${}\\]/) && match === '') {
i--; text = text.substr(0,i-1) + text.substr(i); // remove \ from \$, \{, \}, or \\
}
}
}
}
if (match !== '') TEX.Error(["MathNotTerminated","Math not terminated in text box"]);
}
if (k < text.length) mml.push(this.InternalText(text.slice(k),def));
if (level != null) {
mml = [MML.mstyle.apply(MML,mml).With({displaystyle:false,scriptlevel:level})];
} else if (mml.length > 1) {
mml = [MML.mrow.apply(MML,mml)];
}
return mml;
},
InternalText: function (text,def) {
text = text.replace(/^\s+/,NBSP).replace(/\s+$/,NBSP);
return MML.mtext(MML.chars(text)).With(def);
},
/*
* Replace macro paramters with their values
*/
SubstituteArgs: function (args,string) {
var text = ''; var newstring = ''; var c; var i = 0;
while (i < string.length) {
c = string.charAt(i++);
if (c === "\\") {text += c + string.charAt(i++)}
else if (c === '#') {
c = string.charAt(i++);
if (c === '#') {text += c} else {
if (!c.match(/[1-9]/) || c > args.length) {
TEX.Error(["IllegalMacroParam",
"Illegal macro parameter reference"]);
}
newstring = this.AddArgs(this.AddArgs(newstring,text),args[c-1]);
text = '';
}
} else {text += c}
}
return this.AddArgs(newstring,text);
},
/*
* Make sure that macros are followed by a space if their names
* could accidentally be continued into the following text.
*/
AddArgs: function (s1,s2) {
if (s2.match(/^[a-z]/i) && s1.match(/(^|[^\\])(\\\\)*\\[a-z]+$/i)) {s1 += ' '}
if (s1.length + s2.length > TEX.config.MAXBUFFER) {
TEX.Error(["MaxBufferSize",
"MathJax internal buffer size exceeded; is there a recursive macro call?"]);
}
return s1+s2;
}
});
/************************************************************************/
TEX.Augment({
Stack: STACK, Parse: PARSE, Definitions: TEXDEF, Startup: STARTUP,
config: {
MAXMACROS: 10000, // maximum number of macro substitutions per equation
MAXBUFFER: 5*1024 // maximum size of TeX string to process
},
sourceMenuTitle: /*_(MathMenu)*/ ["TeXCommands","TeX Commands"],
annotationEncoding: "application/x-tex",
prefilterHooks: MathJax.Callback.Hooks(true), // hooks to run before processing TeX
postfilterHooks: MathJax.Callback.Hooks(true), // hooks to run after processing TeX
//
// Check if AMSmath extension must be loaded and push
// it on the extensions array, if needed
//
Config: function () {
this.SUPER(arguments).Config.apply(this,arguments);
if (this.config.equationNumbers.autoNumber !== "none") {
if (!this.config.extensions) {this.config.extensions = []}
this.config.extensions.push("AMSmath.js");
}
},
//
// Convert TeX to ElementJax
//
Translate: function (script) {
var mml, isError = false, math = MathJax.HTML.getScript(script);
var display = (script.type.replace(/\n/g," ").match(/(;|\s|\n)mode\s*=\s*display(;|\s|\n|$)/) != null);
var data = {math:math, display:display, script:script};
var callback = this.prefilterHooks.Execute(data); if (callback) return callback;
math = data.math;
try {
mml = TEX.Parse(math).mml();
} catch(err) {
if (!err.texError) {throw err}
mml = this.formatError(err,math,display,script);
isError = true;
}
if (mml.isa(MML.mtable) && mml.displaystyle === "inherit") mml.displaystyle = display; // for tagged equations
if (mml.inferred) {mml = MML.apply(MathJax.ElementJax,mml.data)} else {mml = MML(mml)}
if (display) {mml.root.display = "block"}
if (isError) {mml.texError = true}
data.math = mml;
return this.postfilterHooks.Execute(data) || data.math;
},
prefilterMath: function (math,displaystyle,script) {
return math;
},
postfilterMath: function (math,displaystyle,script) {
this.combineRelations(math.root);
return math;
},
formatError: function (err,math,display,script) {
var message = err.message.replace(/\n.*/,"");
HUB.signal.Post(["TeX Jax - parse error",message,math,display,script]);
return MML.Error(message);
},
//
// Produce an error and stop processing this equation
//
Error: function (message) {
//
// Translate message if it is ["id","message",args]
//
if (isArray(message)) {message = _.apply(_,message)}
throw HUB.Insert(Error(message),{texError: true});
},
//
// Add a user-defined macro to the macro list
//
Macro: function (name,def,argn) {
TEXDEF.macros[name] = ['Macro'].concat([].slice.call(arguments,1));
TEXDEF.macros[name].isUser = true;
},
/*
* Create an mrow that has stretchy delimiters at either end, as needed
*/
fenced: function (open,mml,close) {
var mrow = MML.mrow().With({open:open, close:close, texClass:MML.TEXCLASS.INNER});
mrow.Append(
MML.mo(open).With({fence:true, stretchy:true, symmetric:true, texClass:MML.TEXCLASS.OPEN}),
mml,
MML.mo(close).With({fence:true, stretchy:true, symmetric:true, texClass:MML.TEXCLASS.CLOSE})
);
return mrow;
},
/*
* Create an mrow that has \mathchoice using \bigg and \big for the delimiters
*/
fixedFence: function (open,mml,close) {
var mrow = MML.mrow().With({open:open, close:close, texClass:MML.TEXCLASS.ORD});
if (open) {mrow.Append(this.mathPalette(open,"l"))}
if (mml.type === "mrow") {mrow.Append.apply(mrow,mml.data)} else {mrow.Append(mml)}
if (close) {mrow.Append(this.mathPalette(close,"r"))}
return mrow;
},
mathPalette: function (fence,side) {
if (fence === '{' || fence === '}') {fence = "\\"+fence}
var D = '{\\bigg'+side+' '+fence+'}', T = '{\\big'+side+' '+fence+'}';
return TEX.Parse('\\mathchoice'+D+T+T+T,{}).mml();
},
//
// Combine adjacent <mo> elements that are relations
// (since MathML treats the spacing very differently)
//
combineRelations: function (mml) {
var i, m, m1, m2;
for (i = 0, m = mml.data.length; i < m; i++) {
if (mml.data[i]) {
if (mml.isa(MML.mrow)) {
while (i+1 < m && (m1 = mml.data[i]) && (m2 = mml.data[i+1]) &&
m1.isa(MML.mo) && m2.isa(MML.mo) &&
m1.Get("texClass") === MML.TEXCLASS.REL &&
m2.Get("texClass") === MML.TEXCLASS.REL) {
if (m1.variantForm == m2.variantForm &&
m1.Get("mathvariant") == m2.Get("mathvariant") && m1.style == m2.style &&
m1["class"] == m2["class"] && !m1.id && !m2.id) {
m1.Append.apply(m1,m2.data);
mml.data.splice(i+1,1); m--;
} else {
m1.rspace = m2.lspace = "0pt"; i++;
}
}
}
if (!mml.data[i].isToken) {this.combineRelations(mml.data[i])}
}
}
}
});
//
// Add the default filters
//
TEX.prefilterHooks.Add(function (data) {
data.math = TEX.prefilterMath(data.math,data.display,data.script);
});
TEX.postfilterHooks.Add(function (data) {
data.math = TEX.postfilterMath(data.math,data.display,data.script);
});
TEX.loadComplete("jax.js");
})(MathJax.InputJax.TeX,MathJax.Hub,MathJax.Ajax);
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/jax/output/SVG/config.js
*
* Initializes the SVG OutputJax (the main definition is in
* MathJax/jax/input/SVG/jax.js, which is loaded when needed).
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2011-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
MathJax.OutputJax.SVG = MathJax.OutputJax({
id: "SVG",
version: "2.7.1",
directory: MathJax.OutputJax.directory + "/SVG",
extensionDir: MathJax.OutputJax.extensionDir + "/SVG",
autoloadDir: MathJax.OutputJax.directory + "/SVG/autoload",
fontDir: MathJax.OutputJax.directory + "/SVG/fonts", // font name added later
config: {
scale: 100, minScaleAdjust: 50, // global math scaling factor, and minimum adjusted scale factor
font: "TeX", // currently the only font available
blacker: 1, // stroke-width to make fonts blacker
mtextFontInherit: false, // to make <mtext> be in page font rather than MathJax font
undefinedFamily: "STIXGeneral,'Arial Unicode MS',serif", // fonts to use for missing characters
addMMLclasses: false, // keep MathML structure and use CSS classes to mark elements
useFontCache: true, // use <use> elements to re-use font paths rather than repeat paths every time
useGlobalCache: true, // store fonts in a global <defs> for use in all equations, or one in each equation
EqnChunk: (MathJax.Hub.Browser.isMobile ? 10: 50),
// number of equations to process before showing them
EqnChunkFactor: 1.5, // chunk size is multiplied by this after each chunk
EqnChunkDelay: 100, // milliseconds to delay between chunks (to let browser
// respond to other events)
linebreaks: {
automatic: false, // when false, only process linebreak="newline",
// when true, insert line breaks automatically in long expressions.
width: "container" // maximum width of a line for automatic line breaks (e.g. "30em").
// use "container" to compute size from containing element,
// use "nn% container" for a portion of the container,
// use "nn%" for a portion of the window size
},
merrorStyle: {
fontSize:"90%", color:"#C00", background:"#FF8",
border: "1px solid #C00", padding:"3px"
},
styles: {
".MathJax_SVG_Display": {
"text-align": "center",
margin: "1em 0em"
},
//
// For mtextFontInherit version of \texttt{}
//
".MathJax_SVG .MJX-monospace": {
"font-family": "monospace"
},
//
// For mtextFontInherit version of \textsf{}
//
".MathJax_SVG .MJX-sans-serif": {
"font-family": "sans-serif"
},
//
// For tooltips
//
"#MathJax_SVG_Tooltip": {
"background-color": "InfoBackground", color: "InfoText",
border: "1px solid black",
"box-shadow": "2px 2px 5px #AAAAAA", // Opera 10.5
"-webkit-box-shadow": "2px 2px 5px #AAAAAA", // Safari 3 and Chrome
"-moz-box-shadow": "2px 2px 5px #AAAAAA", // Forefox 3.5
"-khtml-box-shadow": "2px 2px 5px #AAAAAA", // Konqueror
padding: "3px 4px",
"z-index": 401
}
}
}
});
if (!MathJax.Hub.config.delayJaxRegistration) {MathJax.OutputJax.SVG.Register("jax/mml")}
MathJax.OutputJax.SVG.loadComplete("config.js");
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/jax/output/SVG/jax.js
*
* Implements the SVG OutputJax that displays mathematics using
* SVG (or VML in IE) to position the characters from math fonts
* in their proper locations.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2011-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
(function (AJAX,HUB,HTML,SVG) {
var MML;
var isArray = MathJax.Object.isArray;
var SVGNS = "http://www.w3.org/2000/svg";
var XLINKNS = "http://www.w3.org/1999/xlink";
//
// Get the URL of the page (for use with xlink:href) when there
// is a <base> element on the page.
//
var SVGURL = (document.getElementsByTagName("base").length === 0) ? "" :
String(document.location).replace(/#.*$/,"");
SVG.Augment({
HFUZZ: 2, // adjustments for height and depth of final svg element
DFUZZ: 2, // to get baselines right (fragile).
config: {
styles: {
".MathJax_SVG": {
"display": "inline",
"font-style": "normal",
"font-weight": "normal",
"line-height": "normal",
"font-size": "100%",
"font-size-adjust":"none",
"text-indent": 0,
"text-align": "left",
"text-transform": "none",
"letter-spacing": "normal",
"word-spacing": "normal",
"word-wrap": "normal",
"white-space": "nowrap",
"float": "none",
"direction": "ltr",
"max-width": "none", "max-height": "none",
"min-width": 0, "min-height": 0,
border: 0, padding: 0, margin: 0
},
".MathJax_SVG_Display": {
position: "relative",
display: "block!important",
"text-indent": 0,
"max-width": "none", "max-height": "none",
"min-width": 0, "min-height": 0,
width: "100%"
},
".MathJax_SVG *": {
transition: "none",
"-webkit-transition": "none",
"-moz-transition": "none",
"-ms-transition": "none",
"-o-transition": "none"
},
".mjx-svg-href": {
fill: "blue", stroke: "blue"
},
".MathJax_SVG_Processing": {
visibility: "hidden", position:"absolute", top:0, left:0,
width:0, height: 0, overflow:"hidden", display:"block!important"
},
".MathJax_SVG_Processed": {display:"none!important"},
".MathJax_SVG_ExBox": {
display:"block!important", overflow:"hidden",
width:"1px", height:"60ex",
"min-height": 0, "max-height":"none",
padding:0, border: 0, margin: 0
},
".MathJax_SVG_LineBox": {display: "table!important"},
".MathJax_SVG_LineBox span": {
display: "table-cell!important",
width: "10000em!important",
"min-width":0, "max-width":"none",
padding:0, border:0, margin:0
},
"#MathJax_SVG_Tooltip": {
position: "absolute", left: 0, top: 0,
width: "auto", height: "auto",
display: "none"
}
}
},
hideProcessedMath: true, // use display:none until all math is processed
fontNames: ["TeX","STIX","STIX-Web","Asana-Math",
"Gyre-Termes","Gyre-Pagella","Latin-Modern","Neo-Euler"],
Config: function () {
this.SUPER(arguments).Config.apply(this,arguments);
var settings = HUB.config.menuSettings, config = this.config, font = settings.font;
if (settings.scale) {config.scale = settings.scale}
if (font && font !== "Auto") {
font = font.replace(/(Local|Web|Image)$/i,"");
font = font.replace(/([a-z])([A-Z])/,"$1-$2");
this.fontInUse = font;
} else {
this.fontInUse = config.font || "TeX";
}
if (this.fontNames.indexOf(this.fontInUse) < 0) {this.fontInUse = "TeX"}
this.fontDir += "/" + this.fontInUse;
if (!this.require) {this.require = []}
this.require.push(this.fontDir+"/fontdata.js");
this.require.push(MathJax.OutputJax.extensionDir+"/MathEvents.js");
},
Startup: function () {
// Set up event handling
EVENT = MathJax.Extension.MathEvents.Event;
TOUCH = MathJax.Extension.MathEvents.Touch;
HOVER = MathJax.Extension.MathEvents.Hover;
this.ContextMenu = EVENT.ContextMenu;
this.Mousedown = EVENT.AltContextMenu;
this.Mouseover = HOVER.Mouseover;
this.Mouseout = HOVER.Mouseout;
this.Mousemove = HOVER.Mousemove;
// Make hidden div for doing tests and storing global SVG <defs>
this.hiddenDiv = HTML.Element("div",{
style:{visibility:"hidden", overflow:"hidden", position:"absolute", top:0,
height:"1px", width: "auto", padding:0, border:0, margin:0,
textAlign:"left", textIndent:0, textTransform:"none",
lineHeight:"normal", letterSpacing:"normal", wordSpacing:"normal"}
});
if (!document.body.firstChild) {document.body.appendChild(this.hiddenDiv)}
else {document.body.insertBefore(this.hiddenDiv,document.body.firstChild)}
this.hiddenDiv = HTML.addElement(this.hiddenDiv,"div",{id:"MathJax_SVG_Hidden"});
// Determine pixels-per-inch and em-size
var div = HTML.addElement(this.hiddenDiv,"div",{style:{width:"5in"}});
this.pxPerInch = div.offsetWidth/5; this.hiddenDiv.removeChild(div);
// Used for measuring text sizes
this.textSVG = this.Element("svg");
// Global defs for font glyphs
BBOX.GLYPH.defs = this.addElement(this.addElement(this.hiddenDiv.parentNode,"svg"),
"defs",{id:"MathJax_SVG_glyphs"});
// Used in preTranslate to get scaling factors
this.ExSpan = HTML.Element("span",
{style:{position:"absolute","font-size-adjust":"none"}},
[["span",{className:"MathJax_SVG_ExBox"}]]
);
// Used in preTranslate to get linebreak width
this.linebreakSpan = HTML.Element("span",{className:"MathJax_SVG_LineBox"},[["span"]]);
// Set up styles
return AJAX.Styles(this.config.styles,["InitializeSVG",this]);
},
//
// Handle initialization that requires styles to be set up
//
InitializeSVG: function () {
//
// Get the default sizes (need styles in place to do this)
//
document.body.appendChild(this.ExSpan);
document.body.appendChild(this.linebreakSpan);
this.defaultEx = this.ExSpan.firstChild.offsetHeight/60;
this.defaultWidth = this.linebreakSpan.firstChild.offsetWidth;
document.body.removeChild(this.linebreakSpan);
document.body.removeChild(this.ExSpan);
},
preTranslate: function (state) {
var scripts = state.jax[this.id], i, m = scripts.length, n,
script, prev, span, div, test, jax, ex, em, maxwidth, relwidth = false, cwidth,
linebreak = this.config.linebreaks.automatic, width = this.config.linebreaks.width;
if (linebreak) {
relwidth = (width.match(/^\s*(\d+(\.\d*)?%\s*)?container\s*$/) != null);
if (relwidth) {width = width.replace(/\s*container\s*/,"")}
else {maxwidth = this.defaultWidth}
if (width === "") {width = "100%"}
} else {maxwidth = 100000} // a big width, so no implicit line breaks
//
// Loop through the scripts
//
for (i = 0; i < m; i++) {
script = scripts[i]; if (!script.parentNode) continue;
//
// Remove any existing output
//
prev = script.previousSibling;
if (prev && String(prev.className).match(/^MathJax(_SVG)?(_Display)?( MathJax(_SVG)?_Process(ing|ed))?$/))
{prev.parentNode.removeChild(prev)}
if (script.MathJax.preview) script.MathJax.preview.style.display = "none";
//
// Add the span, and a div if in display mode,
// then set the role and mark it as being processed
//
jax = script.MathJax.elementJax; if (!jax) continue;
jax.SVG = {
display: (jax.root.Get("display") === "block"),
preview: (jax.SVG||{}).preview // in case typeset calls are interleaved
};
span = div = HTML.Element("span",{
style: {"font-size": this.config.scale+"%", display:"inline-block"},
className:"MathJax_SVG", id:jax.inputID+"-Frame", isMathJax:true, jaxID:this.id,
oncontextmenu:EVENT.Menu, onmousedown: EVENT.Mousedown,
onmouseover:EVENT.Mouseover, onmouseout:EVENT.Mouseout, onmousemove:EVENT.Mousemove,
onclick:EVENT.Click, ondblclick:EVENT.DblClick,
// Added for keyboard accessible menu.
onkeydown: EVENT.Keydown, tabIndex: HUB.getTabOrder(jax)
});
if (HUB.Browser.noContextMenu) {
span.ontouchstart = TOUCH.start;
span.ontouchend = TOUCH.end;
}
if (jax.SVG.display) {
div = HTML.Element("div",{className:"MathJax_SVG_Display"});
div.appendChild(span);
}
div.className += " MathJax_SVG_Processing";
script.parentNode.insertBefore(div,script);
//
// Add the test span for determining scales and linebreak widths
//
script.parentNode.insertBefore(this.ExSpan.cloneNode(true),script);
div.parentNode.insertBefore(this.linebreakSpan.cloneNode(true),div);
}
//
// Determine the scaling factors for each script
// (this only requires one reflow rather than a reflow for each equation)
//
var hidden = [];
for (i = 0; i < m; i++) {
script = scripts[i]; if (!script.parentNode) continue;
test = script.previousSibling; div = test.previousSibling;
jax = script.MathJax.elementJax; if (!jax) continue;
ex = test.firstChild.offsetHeight/60;
cwidth = Math.max(0,(div.previousSibling.firstChild.offsetWidth-2) / this.config.scale * 100);
if (ex === 0 || ex === "NaN") {
// can't read width, so move to hidden div for processing
hidden.push(div);
jax.SVG.isHidden = true;
ex = this.defaultEx; cwidth = this.defaultWidth;
}
if (relwidth) {maxwidth = cwidth}
jax.SVG.ex = ex;
jax.SVG.em = em = ex / SVG.TeX.x_height * 1000; // scale ex to x_height
jax.SVG.cwidth = cwidth/em * 1000;
jax.SVG.lineWidth = (linebreak ? this.length2em(width,1,maxwidth/em*1000) : SVG.BIGDIMEN);
}
for (i = 0, n = hidden.length; i < n; i++) {
this.hiddenDiv.appendChild(hidden[i]);
this.addElement(this.hiddenDiv,"br");
}
//
// Remove the test spans used for determining scales and linebreak widths
//
for (i = 0; i < m; i++) {
script = scripts[i]; if (!script.parentNode) continue;
test = scripts[i].previousSibling; span = test.previousSibling;
jax = scripts[i].MathJax.elementJax; if (!jax) continue;
if (!jax.SVG.isHidden) {span = span.previousSibling}
span.parentNode.removeChild(span);
test.parentNode.removeChild(test);
if (script.MathJax.preview) script.MathJax.preview.style.display = "";
}
//
// Set state variables used for displaying equations in chunks
//
state.SVGeqn = state.SVGlast = 0; state.SVGi = -1;
state.SVGchunk = this.config.EqnChunk;
state.SVGdelay = false;
},
Translate: function (script,state) {
if (!script.parentNode) return;
//
// If we are supposed to do a chunk delay, do it
//
if (state.SVGdelay) {
state.SVGdelay = false;
HUB.RestartAfter(MathJax.Callback.Delay(this.config.EqnChunkDelay));
}
//
// Get the data about the math
//
var jax = script.MathJax.elementJax, math = jax.root, div, span,
localCache = (SVG.config.useFontCache && !SVG.config.useGlobalCache);
if (jax.SVG.isHidden) {
span = document.getElementById(jax.inputID+"-Frame");
div = (jax.SVG.display ? span.parentElement : span);
} else {
div = script.previousSibling;
span = (jax.SVG.display ? (div||{}).firstChild||div : div);
}
if (!div) return;
//
// Set the font metrics
//
this.em = MML.mbase.prototype.em = jax.SVG.em; this.ex = jax.SVG.ex;
this.linebreakWidth = jax.SVG.lineWidth; this.cwidth = jax.SVG.cwidth;
//
// Typeset the math
//
this.mathDiv = div;
span.appendChild(this.textSVG);
if (localCache) {SVG.resetGlyphs()}
this.initSVG(math,span);
math.setTeXclass();
try {math.toSVG(span,div)} catch (err) {
if (err.restart) {while (span.firstChild) {span.removeChild(span.firstChild)}}
if (localCache) {BBOX.GLYPH.n--}
throw err;
}
span.removeChild(this.textSVG);
//
// Put it in place, and remove the processing marker
//
if (jax.SVG.isHidden) {script.parentNode.insertBefore(div,script)}
div.className = div.className.split(/ /)[0];
//
// Check if we are hiding the math until more is processed
//
if (this.hideProcessedMath) {
//
// Hide the math and don't let its preview be removed
//
div.className += " MathJax_SVG_Processed";
if (script.MathJax.preview) {
jax.SVG.preview = script.MathJax.preview;
delete script.MathJax.preview;
}
//
// Check if we should show this chunk of equations
//
state.SVGeqn += (state.i - state.SVGi); state.SVGi = state.i;
if (state.SVGeqn >= state.SVGlast + state.SVGchunk) {
this.postTranslate(state,true);
state.SVGchunk = Math.floor(state.SVGchunk*this.config.EqnChunkFactor);
state.SVGdelay = true; // delay if there are more scripts
}
}
},
postTranslate: function (state,partial) {
var scripts = state.jax[this.id];
if (!this.hideProcessedMath) return;
//
// Reveal this chunk of math
//
for (var i = state.SVGlast, m = state.SVGeqn; i < m; i++) {
var script = scripts[i];
if (script && script.MathJax.elementJax) {
//
// Remove the processed marker
//
script.previousSibling.className = script.previousSibling.className.split(/ /)[0];
var data = script.MathJax.elementJax.SVG;
//
// Remove the preview, if any
//
if (data.preview) {
data.preview.innerHTML = "";
data.preview.style.display = "none";
script.MathJax.preview = data.preview;
delete data.preview;
}
}
}
//
// Save our place so we know what is revealed
//
state.SVGlast = state.SVGeqn;
},
resetGlyphs: function (reset) {
if (this.config.useFontCache) {
var GLYPH = BBOX.GLYPH;
if (this.config.useGlobalCache) {
GLYPH.defs = document.getElementById("MathJax_SVG_glyphs");
GLYPH.defs.innerHTML = "";
} else {
GLYPH.defs = this.Element("defs");
GLYPH.n++;
}
GLYPH.glyphs = {};
if (reset) {GLYPH.n = 0}
}
},
//
// Return the containing HTML element rather than the SVG element, since
// most browsers can't position to an SVG element properly.
//
hashCheck: function (target) {
if (target && target.nodeName.toLowerCase() === "g")
{do {target = target.parentNode} while (target && target.firstChild.nodeName !== "svg")}
return target;
},
getJaxFromMath: function (math) {
if (math.parentNode.className.match(/MathJax_SVG_Display/)) {math = math.parentNode}
do {math = math.nextSibling} while (math && math.nodeName.toLowerCase() !== "script");
return HUB.getJaxFor(math);
},
getHoverSpan: function (jax,math) {
math.style.position = "relative"; // make sure inline containers have position set
return math.firstChild;
},
getHoverBBox: function (jax,span,math) {
var bbox = EVENT.getBBox(span.parentNode);
bbox.h += 2; bbox.d -= 2; // bbox seems to be a bit off, so compensate (FIXME)
return bbox;
},
Zoom: function (jax,span,math,Mw,Mh) {
//
// Re-render at larger size
//
span.className = "MathJax_SVG";
//
// get em size (taken from this.preTranslate)
//
var emex = span.appendChild(this.ExSpan.cloneNode(true));
var ex = emex.firstChild.offsetHeight/60;
this.em = MML.mbase.prototype.em = ex / SVG.TeX.x_height * 1000; this.ex = ex;
this.linebreakWidth = jax.SVG.lineWidth; this.cwidth = jax.SVG.cwidth;
emex.parentNode.removeChild(emex);
span.appendChild(this.textSVG);
this.mathDIV = span; this.zoomScale = parseInt(HUB.config.menuSettings.zscale) / 100;
var tw = jax.root.data[0].SVGdata.tw; if (tw && tw < this.cwidth) this.cwidth = tw;
this.idPostfix = "-zoom"; jax.root.toSVG(span,span); this.idPostfix = "";
this.zoomScale = 1;
span.removeChild(this.textSVG);
//
// Don't allow overlaps on any edge
//
var svg = span.getElementsByTagName("svg")[0].style;
svg.marginTop = svg.marginRight = svg.marginLeft = 0;
if (svg.marginBottom.charAt(0) === "-")
span.style.marginBottom = svg.marginBottom.substr(1);
if (this.operaZoomRefresh)
{setTimeout(function () {span.firstChild.style.border="1px solid transparent"},1)}
//
// WebKit bug (issue #749)
//
if (span.offsetWidth < span.firstChild.offsetWidth) {
span.style.minWidth = span.firstChild.offsetWidth + "px";
math.style.minWidth = math.firstChild.offsetWidth + "px";
}
//
// Get height and width of zoomed math and original math
//
span.style.position = math.style.position = "absolute";
var zW = span.offsetWidth, zH = span.offsetHeight,
mH = math.offsetHeight, mW = math.offsetWidth;
span.style.position = math.style.position = "";
//
return {Y:-EVENT.getBBox(span).h, mW:mW, mH:mH, zW:zW, zH:zH};
},
initSVG: function (math,span) {},
Remove: function (jax) {
var span = document.getElementById(jax.inputID+"-Frame");
if (span) {
if (jax.SVG.display) {span = span.parentNode}
span.parentNode.removeChild(span);
}
delete jax.SVG;
},
Em: function (m) {
if (Math.abs(m) < .0006) return "0";
return m.toFixed(3).replace(/\.?0+$/,"") + "em";
},
Ex: function (m) {
m = m / this.TeX.x_height;
if (Math.abs(m) < .0006) return "0";
return m.toFixed(3).replace(/\.?0+$/,"") + "ex";
},
Percent: function (m) {
return (100*m).toFixed(1).replace(/\.?0+$/,"") + "%";
},
Fixed: function (m,n) {
if (Math.abs(m) < .0006) return "0";
return m.toFixed(n||3).replace(/\.?0+$/,"");
},
length2em: function (length,mu,size) {
if (typeof(length) !== "string") {length = length.toString()}
if (length === "") {return ""}
if (length === MML.SIZE.NORMAL) {return 1000}
if (length === MML.SIZE.BIG) {return 2000}
if (length === MML.SIZE.SMALL) {return 710}
if (length === "infinity") {return SVG.BIGDIMEN}
if (length.match(/mathspace$/)) {return 1000*SVG.MATHSPACE[length]}
var emFactor = (this.zoomScale || 1) / SVG.em;
var match = length.match(/^\s*([-+]?(?:\.\d+|\d+(?:\.\d*)?))?(pt|em|ex|mu|px|pc|in|mm|cm|%)?/);
var m = parseFloat(match[1]||"1") * 1000, unit = match[2];
if (size == null) {size = 1000}; if (mu == null) {mu = 1}
if (unit === "em") {return m}
if (unit === "ex") {return m * SVG.TeX.x_height/1000}
if (unit === "%") {return m / 100 * size / 1000}
if (unit === "px") {return m * emFactor}
if (unit === "pt") {return m / 10} // 10 pt to an em
if (unit === "pc") {return m * 1.2} // 12 pt to a pc
if (unit === "in") {return m * this.pxPerInch * emFactor}
if (unit === "cm") {return m * this.pxPerInch * emFactor / 2.54} // 2.54 cm to an inch
if (unit === "mm") {return m * this.pxPerInch * emFactor / 25.4} // 10 mm to a cm
if (unit === "mu") {return m / 18 * mu}
return m*size / 1000; // relative to given size (or 1em as default)
},
thickness2em: function (length,mu) {
var thick = SVG.TeX.rule_thickness;
if (length === MML.LINETHICKNESS.MEDIUM) {return thick}
if (length === MML.LINETHICKNESS.THIN) {return .67*thick}
if (length === MML.LINETHICKNESS.THICK) {return 1.67*thick}
return this.length2em(length,mu,thick);
},
getPadding: function (styles) {
var padding = {top:0, right:0, bottom:0, left:0}, has = false;
for (var id in padding) {if (padding.hasOwnProperty(id)) {
var pad = styles["padding"+id.charAt(0).toUpperCase()+id.substr(1)];
if (pad) {padding[id] = this.length2em(pad); has = true;}
}}
return (has ? padding : false);
},
getBorders: function (styles) {
var border = {top:0, right:0, bottom:0, left:0}, has = false;
for (var id in border) {if (border.hasOwnProperty(id)) {
var ID = "border"+id.charAt(0).toUpperCase()+id.substr(1);
var style = styles[ID+"Style"];
if (style && style !== "none") {
has = true;
border[id] = this.length2em(styles[ID+"Width"]);
border[id+"Style"] = styles[ID+"Style"];
border[id+"Color"] = styles[ID+"Color"];
if (border[id+"Color"] === "initial") {border[id+"Color"] = ""}
} else {delete border[id]}
}}
return (has ? border : false);
},
Element: function (type,def) {
var obj = (typeof(type) === "string" ? document.createElementNS(SVGNS,type) : type);
obj.isMathJax = true;
if (def) {for (var id in def) {if (def.hasOwnProperty(id)) {obj.setAttribute(id,def[id].toString())}}}
return obj;
},
addElement: function (parent,type,def) {return parent.appendChild(this.Element(type,def))},
TextNode: HTML.TextNode,
addText: HTML.addText,
ucMatch: HTML.ucMatch,
HandleVariant: function (variant,scale,text) {
var svg = BBOX.G();
var n, N, c, font, VARIANT, i, m, id, M, RANGES;
if (!variant) {variant = this.FONTDATA.VARIANT[MML.VARIANT.NORMAL]}
if (variant.forceFamily) {
text = BBOX.TEXT(scale,text,variant.font);
if (variant.h != null) {text.h = variant.h}; if (variant.d != null) {text.d = variant.d}
svg.Add(text); text = "";
}
VARIANT = variant;
for (i = 0, m = text.length; i < m; i++) {
variant = VARIANT;
n = text.charCodeAt(i); c = text.charAt(i);
if (n >= 0xD800 && n < 0xDBFF) {
i++; n = (((n-0xD800)<<10)+(text.charCodeAt(i)-0xDC00))+0x10000;
if (this.FONTDATA.RemapPlane1) {
var nv = this.FONTDATA.RemapPlane1(n,variant);
n = nv.n; variant = nv.variant;
}
} else {
RANGES = this.FONTDATA.RANGES;
for (id = 0, M = RANGES.length; id < M; id++) {
if (RANGES[id].name === "alpha" && variant.noLowerCase) continue;
N = variant["offset"+RANGES[id].offset];
if (N && n >= RANGES[id].low && n <= RANGES[id].high) {
if (RANGES[id].remap && RANGES[id].remap[n]) {
n = N + RANGES[id].remap[n];
} else {
n = n - RANGES[id].low + N;
if (RANGES[id].add) {n += RANGES[id].add}
}
if (variant["variant"+RANGES[id].offset])
{variant = this.FONTDATA.VARIANT[variant["variant"+RANGES[id].offset]]}
break;
}
}
}
if (variant.remap && variant.remap[n]) {
n = variant.remap[n];
if (variant.remap.variant) {variant = this.FONTDATA.VARIANT[variant.remap.variant]}
} else if (this.FONTDATA.REMAP[n] && !variant.noRemap) {
n = this.FONTDATA.REMAP[n];
}
if (isArray(n)) {variant = this.FONTDATA.VARIANT[n[1]]; n = n[0]}
if (typeof(n) === "string") {
text = n+text.substr(i+1);
m = text.length; i = -1;
continue;
}
font = this.lookupChar(variant,n); c = font[n];
if (c) {
if ((c[5] && c[5].space) || (c[5] === "" && c[0]+c[1] === 0)) {svg.w += c[2]} else {
c = [scale,font.id+"-"+n.toString(16).toUpperCase()].concat(c);
svg.Add(BBOX.GLYPH.apply(BBOX,c),svg.w,0);
}
} else if (this.FONTDATA.DELIMITERS[n]) {
c = this.createDelimiter(n,0,1,font);
svg.Add(c,svg.w,(this.FONTDATA.DELIMITERS[n].dir === "V" ? c.d: 0));
} else {
if (n <= 0xFFFF) {c = String.fromCharCode(n)} else {
N = n - 0x10000;
c = String.fromCharCode((N>>10)+0xD800)
+ String.fromCharCode((N&0x3FF)+0xDC00);
}
var box = BBOX.TEXT(scale*100/SVG.config.scale,c,{
"font-family":variant.defaultFamily||SVG.config.undefinedFamily,
"font-style":(variant.italic?"italic":""),
"font-weight":(variant.bold?"bold":"")
})
if (variant.h != null) {box.h = variant.h}; if (variant.d != null) {box.d = variant.d}
c = BBOX.G(); c.Add(box); svg.Add(c,svg.w,0);
HUB.signal.Post(["SVG Jax - unknown char",n,variant]);
}
}
if (text.length == 1 && font.skew && font.skew[n]) {svg.skew = font.skew[n]*1000}
if (svg.element.childNodes.length === 1 && !svg.element.firstChild.getAttribute("x")) {
svg.element = svg.element.firstChild;
svg.removeable = false; svg.scale = scale;
}
return svg;
},
lookupChar: function (variant,n) {
var i, m;
if (!variant.FONTS) {
var FONTS = this.FONTDATA.FONTS;
var fonts = (variant.fonts || this.FONTDATA.VARIANT.normal.fonts);
if (!(fonts instanceof Array)) {fonts = [fonts]}
if (variant.fonts != fonts) {variant.fonts = fonts}
variant.FONTS = [];
for (i = 0, m = fonts.length; i < m; i++) {
if (FONTS[fonts[i]]) {variant.FONTS.push(FONTS[fonts[i]])}
}
}
for (i = 0, m = variant.FONTS.length; i < m; i++) {
var font = variant.FONTS[i];
if (typeof(font) === "string") {delete variant.FONTS; this.loadFont(font)}
if (font[n]) {return font} else {this.findBlock(font,n)}
}
return {id:"unknown"};
},
findBlock: function (font,c) {
if (font.Ranges) {
// FIXME: do binary search?
for (var i = 0, m = font.Ranges.length; i < m; i++) {
if (c < font.Ranges[i][0]) return;
if (c <= font.Ranges[i][1]) {
var file = font.Ranges[i][2];
for (var j = font.Ranges.length-1; j >= 0; j--)
{if (font.Ranges[j][2] == file) {font.Ranges.splice(j,1)}}
this.loadFont(font.directory+"/"+file+".js");
}
}
}
},
loadFont: function (file) {
HUB.RestartAfter(AJAX.Require(this.fontDir+"/"+file));
},
createDelimiter: function (code,HW,scale,font) {
if (!scale) {scale = 1};
var svg = BBOX.G();
if (!code) {
svg.Clean(); delete svg.element;
svg.w = svg.r = this.TeX.nulldelimiterspace * scale;
return svg;
}
if (!(HW instanceof Array)) {HW = [HW,HW]}
var hw = HW[1]; HW = HW[0];
var delim = {alias: code};
while (delim.alias) {
code = delim.alias; delim = this.FONTDATA.DELIMITERS[code];
if (!delim) {delim = {HW: [0,this.FONTDATA.VARIANT[MML.VARIANT.NORMAL]]}}
}
if (delim.load) {HUB.RestartAfter(AJAX.Require(this.fontDir+"/fontdata-"+delim.load+".js"))}
for (var i = 0, m = delim.HW.length; i < m; i++) {
if (delim.HW[i][0]*scale >= HW-10-SVG.config.blacker || (i == m-1 && !delim.stretch)) {
if (delim.HW[i][2]) {scale *= delim.HW[i][2]}
if (delim.HW[i][3]) {code = delim.HW[i][3]}
return this.createChar(scale,[code,delim.HW[i][1]],font).With({stretched: true});
}
}
if (delim.stretch) {this["extendDelimiter"+delim.dir](svg,hw,delim.stretch,scale,font)}
return svg;
},
createChar: function (scale,data,font) {
var text = "", variant = {fonts: [data[1]], noRemap:true};
if (font && font === MML.VARIANT.BOLD) {variant.fonts = [data[1]+"-bold",data[1]]}
if (typeof(data[1]) !== "string") {variant = data[1]}
if (data[0] instanceof Array) {
for (var i = 0, m = data[0].length; i < m; i++) {text += String.fromCharCode(data[0][i])}
} else {text = String.fromCharCode(data[0])}
if (data[4]) {scale = scale*data[4]}
var svg = this.HandleVariant(variant,scale,text);
if (data[2]) {svg.x = data[2]*1000}
if (data[3]) {svg.y = data[3]*1000}
if (data[5]) {svg.h += data[5]*1000}
if (data[6]) {svg.d += data[6]*1000}
return svg;
},
extendDelimiterV: function (svg,H,delim,scale,font) {
var top = this.createChar(scale,(delim.top||delim.ext),font);
var bot = this.createChar(scale,(delim.bot||delim.ext),font);
var h = top.h + top.d + bot.h + bot.d;
var y = -top.h; svg.Add(top,0,y); y -= top.d;
if (delim.mid) {var mid = this.createChar(scale,delim.mid,font); h += mid.h + mid.d}
if (delim.min && H < h*delim.min) {H = h*delim.min}
if (H > h) {
var ext = this.createChar(scale,delim.ext,font);
var k = (delim.mid ? 2 : 1), eH = (H-h) / k, s = (eH+100) / (ext.h+ext.d);
while (k-- > 0) {
var g = SVG.Element("g",{transform:"translate("+ext.y+","+(y-s*ext.h+50+ext.y)+") scale(1,"+s+")"});
g.appendChild(ext.element.cloneNode(false)); svg.element.appendChild(g); y -= eH;
if (delim.mid && k) {svg.Add(mid,0,y-mid.h); y -= (mid.h+mid.d)}
}
} else if (delim.mid) {
y += (h - H)/2; svg.Add(mid,0,y-mid.h); y += -(mid.h + mid.d) + (h - H)/2;
} else {
y += (h - H);
}
svg.Add(bot,0,y-bot.h); svg.Clean();
svg.scale = scale;
svg.isMultiChar = true;
},
extendDelimiterH: function (svg,W,delim,scale,font) {
var left = this.createChar(scale,(delim.left||delim.rep),font);
var right = this.createChar(scale,(delim.right||delim.rep),font);
svg.Add(left,-left.l,0);
var w = (left.r - left.l) + (right.r - right.l), x = left.r - left.l;
if (delim.mid) {var mid = this.createChar(scale,delim.mid,font); w += mid.w}
if (delim.min && W < w*delim.min) {W = w*delim.min}
if (W > w) {
var rep = this.createChar(scale,delim.rep,font), fuzz = delim.fuzz || 0;
var k = (delim.mid ? 2 : 1), rW = (W-w) / k, s = (rW+fuzz) / (rep.r-rep.l);
while (k-- > 0) {
var g = SVG.Element("g",{transform:"translate("+(x-fuzz/2-s*rep.l+rep.x)+","+rep.y+") scale("+s+",1)"});
g.appendChild(rep.element.cloneNode(false)); svg.element.appendChild(g); x += rW;
if (delim.mid && k) {svg.Add(mid,x,0); x += mid.w}
}
} else if (delim.mid) {
x -= (w - W)/2; svg.Add(mid,x,0); x += mid.w - (w - W)/2;
} else {
x -= (w - W);
}
svg.Add(right,x-right.l,0); svg.Clean();
svg.scale = scale;
svg.isMultiChar = true;
},
MATHSPACE: {
veryverythinmathspace: 1/18,
verythinmathspace: 2/18,
thinmathspace: 3/18,
mediummathspace: 4/18,
thickmathspace: 5/18,
verythickmathspace: 6/18,
veryverythickmathspace: 7/18,
negativeveryverythinmathspace: -1/18,
negativeverythinmathspace: -2/18,
negativethinmathspace: -3/18,
negativemediummathspace: -4/18,
negativethickmathspace: -5/18,
negativeverythickmathspace: -6/18,
negativeveryverythickmathspace: -7/18
},
//
// Units are em/1000 so quad is 1em
//
TeX: {
x_height: 430.554,
quad: 1000,
num1: 676.508,
num2: 393.732,
num3: 443.73,
denom1: 685.951,
denom2: 344.841,
sup1: 412.892,
sup2: 362.892,
sup3: 288.888,
sub1: 150,
sub2: 247.217,
sup_drop: 386.108,
sub_drop: 50,
delim1: 2390,
delim2: 1000,
axis_height: 250,
rule_thickness: 60,
big_op_spacing1: 111.111,
big_op_spacing2: 166.666,
big_op_spacing3: 200,
big_op_spacing4: 600,
big_op_spacing5: 100,
scriptspace: 100,
nulldelimiterspace: 120,
delimiterfactor: 901,
delimitershortfall: 300,
min_rule_thickness: 1.25, // in pixels
min_root_space: 1.5 // in pixels
},
BIGDIMEN: 10000000,
NBSP: "\u00A0"
});
var BBOX = SVG.BBOX = MathJax.Object.Subclass({
type: "g", removeable: true,
Init: function (def) {
this.h = this.d = -SVG.BIGDIMEN; this.H = this.D = 0;
this.w = this.r = 0; this.l = SVG.BIGDIMEN;
this.x = this.y = 0; this.scale = 1; this.n = 0;
if (this.type) {this.element = SVG.Element(this.type,def)}
},
With: function (def) {return HUB.Insert(this,def)},
Add: function (svg,dx,dy,forcew,infront) {
if (dx) {svg.x += dx}; if (dy) {svg.y += dy};
if (svg.element) {
if (svg.removeable && svg.element.childNodes.length === 1 && svg.n === 1) {
var child = svg.element.firstChild, nodeName = child.nodeName.toLowerCase();
if (nodeName === "use" || nodeName === "rect") {
svg.element = child; svg.scale = svg.childScale;
var x = svg.childX, y = svg.childY;
svg.x += x; svg.y += y;
svg.h -= y; svg.d += y; svg.H -= y; svg.D +=y;
svg.w -= x; svg.r -= x; svg.l += x;
svg.removeable = false;
child.setAttribute("x",Math.floor(svg.x/svg.scale));
child.setAttribute("y",Math.floor(svg.y/svg.scale));
}
}
if (Math.abs(svg.x) < 1 && Math.abs(svg.y) < 1) {
svg.remove = svg.removeable;
} else {
nodeName = svg.element.nodeName.toLowerCase();
if (nodeName === "g") {
if (!svg.element.firstChild) {svg.remove = svg.removeable}
else {svg.element.setAttribute("transform","translate("+Math.floor(svg.x)+","+Math.floor(svg.y)+")")}
} else if (nodeName === "line" || nodeName === "polygon" ||
nodeName === "path" || nodeName === "a") {
var transform = svg.element.getAttribute("transform") || "";
if (transform) transform = " "+transform;
transform = "translate("+Math.floor(svg.x)+","+Math.floor(svg.y)+")"+transform;
svg.element.setAttribute("transform",transform);
} else {
svg.element.setAttribute("x",Math.floor(svg.x/svg.scale));
svg.element.setAttribute("y",Math.floor(svg.y/svg.scale));
}
}
if (svg.remove) {
this.n += svg.n;
while (svg.element.firstChild) {
if (infront && this.element.firstChild) {
this.element.insertBefore(svg.element.firstChild,this.element.firstChild);
} else {
this.element.appendChild(svg.element.firstChild);
}
}
} else {
if (infront) {this.element.insertBefore(svg.element,this.element.firstChild)}
else {this.element.appendChild(svg.element)}
}
delete svg.element;
}
if (svg.hasIndent) {this.hasIndent = svg.hasIndent}
if (svg.tw != null) {this.tw = svg.tw}
if (svg.d - svg.y > this.d) {this.d = svg.d - svg.y; if (this.d > this.D) {this.D = this.d}}
if (svg.y + svg.h > this.h) {this.h = svg.y + svg.h; if (this.h > this.H) {this.H = this.h}}
if (svg.D - svg.y > this.D) {this.D = svg.D - svg.y}
if (svg.y + svg.H > this.H) {this.H = svg.y + svg.H}
if (svg.x + svg.l < this.l) {this.l = svg.x + svg.l}
if (svg.x + svg.r > this.r) {this.r = svg.x + svg.r}
if (forcew || svg.x + svg.w + (svg.X||0) > this.w) {this.w = svg.x + svg.w + (svg.X||0)}
this.childScale = svg.scale; this.childX = svg.x; this.childY = svg.y; this.n++;
return svg;
},
Align: function (svg,align,dx,dy,shift) {
dx = ({left: dx, center: (this.w - svg.w)/2, right: this.w - svg.w - dx})[align] || 0;
var w = this.w; this.Add(svg,dx+(shift||0),dy); this.w = w;
},
Clean: function () {
if (this.h === -SVG.BIGDIMEN) {this.h = this.d = this.l = 0}
return this;
}
});
BBOX.ROW = BBOX.Subclass({
Init: function () {
this.SUPER(arguments).Init.call(this);
this.svg = []; this.sh = this.sd = 0;
},
Check: function (data) {
var svg = data.toSVG(); this.svg.push(svg);
if (data.SVGcanStretch("Vertical")) {svg.mml = data}
if (svg.h > this.sh) {this.sh = svg.h}
if (svg.d > this.sd) {this.sd = svg.d}
},
Stretch: function () {
for (var i = 0, m = this.svg.length; i < m; i++)
{
var svg = this.svg[i], mml = svg.mml;
if (mml) {
if (mml.forceStretch || mml.SVGdata.h !== this.sh || mml.SVGdata.d !== this.sd) {
svg = mml.SVGstretchV(this.sh,this.sd);
}
mml.SVGdata.HW = this.sh; mml.SVGdata.D = this.sd;
}
if (svg.ic) {this.ic = svg.ic} else {delete this.ic}
this.Add(svg,this.w,0,true);
}
delete this.svg;
}
});
BBOX.RECT = BBOX.Subclass({
type: "rect", removeable: false,
Init: function (h,d,w,def) {
if (def == null) {def = {stroke:"none"}}
def.width = Math.floor(w); def.height = Math.floor(h+d);
this.SUPER(arguments).Init.call(this,def);
this.w = this.r = w; this.h = this.H = h+d; this.d = this.D = this.l = 0; this.y = -d;
}
});
BBOX.FRAME = BBOX.Subclass({
type: "rect", removeable: false,
Init: function (h,d,w,t,dash,color,def) {
if (def == null) {def = {}}; def.fill = "none";
def["stroke-width"] = SVG.Fixed(t,2);
def.width = Math.floor(w-t); def.height = Math.floor(h+d-t);
def.transform = "translate("+Math.floor(t/2)+","+Math.floor(-d+t/2)+")";
if (dash === "dashed")
{def["stroke-dasharray"] = [Math.floor(6*SVG.em),Math.floor(6*SVG.em)].join(" ")}
this.SUPER(arguments).Init.call(this,def);
this.w = this.r = w; this.h = this.H = h;
this.d = this.D = d; this.l = 0;
}
});
BBOX.HLINE = BBOX.Subclass({
type: "line", removeable: false,
Init: function (w,t,dash,color,def) {
if (def == null) {def = {"stroke-linecap":"square"}}
if (color && color !== "") {def.stroke = color}
def["stroke-width"] = SVG.Fixed(t,2);
def.x1 = def.y1 = def.y2 = Math.floor(t/2); def.x2 = Math.floor(w-t/2);
if (dash === "dashed") {
var n = Math.floor(Math.max(0,w-t)/(6*t)), m = Math.floor(Math.max(0,w-t)/(2*n+1));
def["stroke-dasharray"] = m+" "+m;
}
if (dash === "dotted") {
def["stroke-dasharray"] = [1,Math.max(150,Math.floor(2*t))].join(" ");
def["stroke-linecap"] = "round";
}
this.SUPER(arguments).Init.call(this,def);
this.w = this.r = w; this.l = 0; this.h = this.H = t; this.d = this.D = 0;
}
});
BBOX.VLINE = BBOX.Subclass({
type: "line", removeable: false,
Init: function (h,t,dash,color,def) {
if (def == null) {def = {"stroke-linecap":"square"}}
if (color && color !== "") {def.stroke = color}
def["stroke-width"] = SVG.Fixed(t,2);
def.x1 = def.x2 = def.y1 = Math.floor(t/2); def.y2 = Math.floor(h-t/2);
if (dash === "dashed") {
var n = Math.floor(Math.max(0,h-t)/(6*t)), m = Math.floor(Math.max(0,h-t)/(2*n+1));
def["stroke-dasharray"] = m+" "+m;
}
if (dash === "dotted") {
def["stroke-dasharray"] = [1,Math.max(150,Math.floor(2*t))].join(" ");
def["stroke-linecap"] = "round";
}
this.SUPER(arguments).Init.call(this,def);
this.w = this.r = t; this.l = 0; this.h = this.H = h; this.d = this.D = 0;
}
});
BBOX.TEXT = BBOX.Subclass({
type: "text", removeable: false,
Init: function (scale,text,def) {
if (!def) {def = {}}; def.stroke = "none";
if (def["font-style"] === "") delete def["font-style"];
if (def["font-weight"] === "") delete def["font-weight"];
this.SUPER(arguments).Init.call(this,def);
SVG.addText(this.element,text);
SVG.textSVG.appendChild(this.element);
var bbox = this.element.getBBox();
SVG.textSVG.removeChild(this.element);
scale *= 1000/SVG.em;
this.element.setAttribute("transform","scale("+SVG.Fixed(scale)+") matrix(1 0 0 -1 0 0)");
this.w = this.r = bbox.width*scale; this.l = 0;
this.h = this.H = -bbox.y*scale;
this.d = this.D = (bbox.height + bbox.y)*scale;
}
});
BBOX.G = BBOX;
BBOX.NULL = BBOX.Subclass({
Init: function () {
this.SUPER(arguments).Init.apply(this,arguments);
this.Clean();
}
});
BBOX.GLYPH = BBOX.Subclass({
type: "path", removeable: false,
Init: function (scale,id,h,d,w,l,r,p) {
var def, t = SVG.config.blacker, GLYPH = BBOX.GLYPH;
var cache = SVG.config.useFontCache;
var transform = (scale === 1 ? null : "scale("+SVG.Fixed(scale)+")");
if (cache && !SVG.config.useGlobalCache) {id = "E"+GLYPH.n+"-"+id}
if (!cache || !GLYPH.glyphs[id]) {
def = {"stroke-width":t};
if (cache) {def.id = id} else if (transform) {def.transform = transform}
def.d = (p ? "M"+p+"Z" : "");
this.SUPER(arguments).Init.call(this,def);
if (cache) {GLYPH.defs.appendChild(this.element); GLYPH.glyphs[id] = true;}
}
if (cache) {
def = {}; if (transform) {def.transform = transform}
this.element = SVG.Element("use",def);
this.element.setAttributeNS(XLINKNS,"href",SVGURL+"#"+id);
}
this.h = (h+t) * scale; this.d = (d+t) * scale; this.w = (w+t/2) *scale;
this.l = (l+t/2) * scale; this.r = (r+t/2) * scale;
this.H = Math.max(0,this.h); this.D = Math.max(0,this.d);
this.x = this.y = 0; this.scale = scale;
}
},{
glyphs: {}, // which glpyhs have been used
defs: null, // the SVG <defs> element where glyphs are stored
n: 0 // the ID for local <defs> for self-contained SVG elements
});
HUB.Register.StartupHook("mml Jax Ready",function () {
MML = MathJax.ElementJax.mml;
MML.mbase.Augment({
SVG: BBOX,
toSVG: function () {
this.SVGgetStyles();
var variant = this.SVGgetVariant();
var svg = this.SVG(); this.SVGgetScale(svg);
this.SVGhandleSpace(svg);
for (var i = 0, m = this.data.length; i < m; i++) {
if (this.data[i]) {
var child = svg.Add(this.data[i].toSVG(variant,svg.scale),svg.w,0,true);
if (child.skew) {svg.skew = child.skew}
}
}
svg.Clean(); var text = this.data.join("");
if (svg.skew && text.length !== 1) {delete svg.skew}
if (svg.r > svg.w && text.length === 1 && !variant.noIC)
{svg.ic = svg.r - svg.w; svg.w = svg.r}
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
},
SVGchildSVG: function (i) {
return (this.data[i] ? this.data[i].toSVG() : BBOX());
},
SVGdataStretched: function (i,HW,D) {
this.SVGdata = {HW:HW, D:D};
if (!this.data[i]) {return BBOX()}
if (D != null) {return this.data[i].SVGstretchV(HW,D)}
if (HW != null) {return this.data[i].SVGstretchH(HW)}
return this.data[i].toSVG();
},
SVGsaveData: function (svg) {
if (!this.SVGdata) {this.SVGdata = {}}
this.SVGdata.w = svg.w, this.SVGdata.x = svg.x;
this.SVGdata.h = svg.h, this.SVGdata.d = svg.d;
if (svg.y) {this.SVGdata.h += svg.y; this.SVGdata.d -= svg.y}
if (svg.X != null) {this.SVGdata.X = svg.X}
if (svg.tw != null) {this.SVGdata.tw = svg.tw}
if (svg.skew) {this.SVGdata.skew = svg.skew}
if (svg.ic) {this.SVGdata.ic = svg.ic}
if (this["class"]) {svg.removeable = false; SVG.Element(svg.element,{"class":this["class"]})}
// FIXME: if an element is split by linebreaking, the ID will be the same on both parts
// FIXME: if an element has an id, its zoomed copy will have the same ID
if (this.id) {svg.removeable = false; SVG.Element(svg.element,{"id":this.id})}
if (this.href) {this.SVGaddHref(svg)}
if (SVG.config.addMMLclasses) {
this.SVGaddClass(svg.element,"mjx-svg-"+this.type);
svg.removeable = false;
}
var style = this.style;
if (style && svg.element) {
svg.element.style.cssText = style;
if (svg.element.style.fontSize) {svg.element.style.fontSize = ""} // handled by scale
svg.element.style.border = svg.element.style.padding = "";
if (svg.removeable) {svg.removeable = (svg.element.style.cssText === "")}
}
this.SVGaddAttributes(svg);
},
SVGaddClass: function (node,name) {
var classes = node.getAttribute("class");
node.setAttribute("class",(classes ? classes+" " : "")+name);
},
SVGaddAttributes: function (svg) {
//
// Copy RDFa, aria, and other tags from the MathML to the HTML-CSS
// output spans Don't copy those in the MML.nocopyAttributes list,
// the ignoreMMLattributes configuration list, or anything tha
// already exists as a property of the span (e.g., no "onlick", etc.)
// If a name in the ignoreMMLattributes object is set to false, then
// the attribute WILL be copied.
//
if (this.attrNames) {
var copy = this.attrNames, skip = MML.nocopyAttributes, ignore = HUB.config.ignoreMMLattributes;
var defaults = (this.type === "mstyle" ? MML.math.prototype.defaults : this.defaults);
for (var i = 0, m = copy.length; i < m; i++) {
var id = copy[i];
if (ignore[id] == false || (!skip[id] && !ignore[id] &&
defaults[id] == null && typeof(svg.element[id]) === "undefined")) {
svg.element.setAttribute(id,this.attr[id]);
svg.removeable = false;
}
}
}
},
SVGaddHref: function (svg) {
var a = SVG.Element("a",{"class":"mjx-svg-href"});
a.setAttributeNS(XLINKNS,"href",this.href);
a.onclick = this.SVGlink;
SVG.addElement(a,"rect",{width:svg.w, height:svg.h+svg.d, y:-svg.d,
fill:"none", stroke:"none", "pointer-events":"all"});
if (svg.type === "svg") {
// for svg element, put <a> inside the main <g> element
var g = svg.element.firstChild;
while (g.firstChild) {a.appendChild(g.firstChild)}
g.appendChild(a);
} else {
a.appendChild(svg.element); svg.element = a;
}
svg.removeable = false;
},
//
// WebKit currently scrolls to the BOTTOM of an svg element if it contains the
// target of the link, so implement link by hand, to the containing span element.
//
SVGlink: function () {
var href = this.href.animVal;
if (href.charAt(0) === "#") {
var target = SVG.hashCheck(document.getElementById(href.substr(1)));
if (target && target.scrollIntoView)
{setTimeout(function () {target.parentNode.scrollIntoView(true)},1)}
}
document.location = href;
},
SVGgetStyles: function () {
if (this.style) {
var span = HTML.Element("span");
span.style.cssText = this.style;
this.styles = this.SVGprocessStyles(span.style);
}
},
SVGprocessStyles: function (style) {
var styles = {border:SVG.getBorders(style), padding:SVG.getPadding(style)};
if (!styles.border) {delete styles.border}
if (!styles.padding) {delete styles.padding}
if (style.fontSize) {styles.fontSize = style.fontSize}
if (style.color) {styles.color = style.color}
if (style.backgroundColor) {styles.background = style.backgroundColor}
if (style.fontStyle) {styles.fontStyle = style.fontStyle}
if (style.fontWeight) {styles.fontWeight = style.fontWeight}
if (style.fontFamily) {styles.fontFamily = style.fontFamily}
if (styles.fontWeight && styles.fontWeight.match(/^\d+$/))
{styles.fontWeight = (parseInt(styles.fontWeight) > 600 ? "bold" : "normal")}
return styles;
},
SVGhandleSpace: function (svg) {
if (this.useMMLspacing) {
if (this.type !== "mo") return;
var values = this.getValues("scriptlevel","lspace","rspace");
if (values.scriptlevel <= 0 || this.hasValue("lspace") || this.hasValue("rspace")) {
var mu = this.SVGgetMu(svg);
values.lspace = Math.max(0,SVG.length2em(values.lspace,mu));
values.rspace = Math.max(0,SVG.length2em(values.rspace,mu));
var core = this, parent = this.Parent();
while (parent && parent.isEmbellished() && parent.Core() === core)
{core = parent; parent = parent.Parent()}
if (values.lspace) {svg.x += values.lspace}
if (values.rspace) {svg.X = values.rspace}
}
} else {
var space = this.texSpacing();
this.SVGgetScale();
if (space !== "") {svg.x += SVG.length2em(space,this.scale)*this.mscale}
}
},
SVGhandleColor: function (svg) {
var values = this.getValues("mathcolor","color");
if (this.styles && this.styles.color && !values.color) {values.color = this.styles.color}
if (values.color && !this.mathcolor) {values.mathcolor = values.color}
if (values.mathcolor) {
SVG.Element(svg.element,{fill:values.mathcolor,stroke:values.mathcolor})
svg.removeable = false;
}
var borders = (this.styles||{}).border, padding = (this.styles||{}).padding,
bleft = ((borders||{}).left||0), pleft = ((padding||{}).left||0), id;
values.background = (this.mathbackground || this.background ||
(this.styles||{}).background || MML.COLOR.TRANSPARENT);
if (bleft + pleft) {
//
// Make a box and move the contents of svg to it,
// then add it back into svg, but offset by the left amount
//
var dup = BBOX(); for (id in svg) {if (svg.hasOwnProperty(id)) {dup[id] = svg[id]}}
dup.x = 0; dup.y = 0;
svg.element = SVG.Element("g"); svg.removeable = true;
svg.Add(dup,bleft+pleft,0);
}
//
// Adjust size by padding and dashed borders (left is taken care of above)
//
if (padding) {svg.w += padding.right||0; svg.h += padding.top||0; svg.d += padding.bottom||0}
if (borders) {svg.w += borders.right||0; svg.h += borders.top||0; svg.d += borders.bottom||0}
//
// Add background color
//
if (values.background !== MML.COLOR.TRANSPARENT) {
var nodeName = svg.element.nodeName.toLowerCase();
if (nodeName !== "g" && nodeName !== "svg") {
var g = SVG.Element("g"); g.appendChild(svg.element);
svg.element = g; svg.removeable = true;
}
svg.Add(BBOX.RECT(svg.h,svg.d,svg.w,{fill:values.background,stroke:"none"}),0,0,false,true)
}
//
// Add borders
//
if (borders) {
var dd = 5; // fuzz factor to avoid anti-alias problems at edges
var sides = {
left: ["V",svg.h+svg.d,-dd,-svg.d],
right: ["V",svg.h+svg.d,svg.w-borders.right+dd,-svg.d],
top: ["H",svg.w,0,svg.h-borders.top+dd],
bottom:["H",svg.w,0,-svg.d-dd]
}
for (id in sides) {if (sides.hasOwnProperty(id)) {
if (borders[id]) {
var side = sides[id], box = BBOX[side[0]+"LINE"];
svg.Add(box(side[1],borders[id],borders[id+"Style"],borders[id+"Color"]),side[2],side[3]);
}
}}
}
},
SVGhandleVariant: function (variant,scale,text) {
return SVG.HandleVariant(variant,scale,text);
},
SVGgetVariant: function () {
var values = this.getValues("mathvariant","fontfamily","fontweight","fontstyle");
var variant = values.mathvariant;
if (this.variantForm) variant = "-"+SVG.fontInUse+"-variant";
values.hasVariant = this.Get("mathvariant",true); // null if not explicitly specified
if (!values.hasVariant) {
values.family = values.fontfamily;
values.weight = values.fontweight;
values.style = values.fontstyle;
}
if (this.styles) {
if (!values.style && this.styles.fontStyle) {values.style = this.styles.fontStyle}
if (!values.weight && this.styles.fontWeight) {values.weight = this.styles.fontWeight}
if (!values.family && this.styles.fontFamily) {values.family = this.styles.fontFamily}
}
if (values.family && !values.hasVariant) {
if (!values.weight && values.mathvariant.match(/bold/)) {values.weight = "bold"}
if (!values.style && values.mathvariant.match(/italic/)) {values.style = "italic"}
variant = {forceFamily: true, font: {"font-family":values.family}};
if (values.style) {variant.font["font-style"] = values.style}
if (values.weight) {variant.font["font-weight"] = values.weight}
return variant;
}
if (values.weight === "bold") {
variant = {
normal:MML.VARIANT.BOLD, italic:MML.VARIANT.BOLDITALIC,
fraktur:MML.VARIANT.BOLDFRAKTUR, script:MML.VARIANT.BOLDSCRIPT,
"sans-serif":MML.VARIANT.BOLDSANSSERIF,
"sans-serif-italic":MML.VARIANT.SANSSERIFBOLDITALIC
}[variant]||variant;
} else if (values.weight === "normal") {
variant = {
bold:MML.VARIANT.normal, "bold-italic":MML.VARIANT.ITALIC,
"bold-fraktur":MML.VARIANT.FRAKTUR, "bold-script":MML.VARIANT.SCRIPT,
"bold-sans-serif":MML.VARIANT.SANSSERIF,
"sans-serif-bold-italic":MML.VARIANT.SANSSERIFITALIC
}[variant]||variant;
}
if (values.style === "italic") {
variant = {
normal:MML.VARIANT.ITALIC, bold:MML.VARIANT.BOLDITALIC,
"sans-serif":MML.VARIANT.SANSSERIFITALIC,
"bold-sans-serif":MML.VARIANT.SANSSERIFBOLDITALIC
}[variant]||variant;
} else if (values.style === "normal") {
variant = {
italic:MML.VARIANT.NORMAL, "bold-italic":MML.VARIANT.BOLD,
"sans-serif-italic":MML.VARIANT.SANSSERIF,
"sans-serif-bold-italic":MML.VARIANT.BOLDSANSSERIF
}[variant]||variant;
}
if (!(variant in SVG.FONTDATA.VARIANT)) {
// If the mathvariant value is invalid or not supported by this
// font, fallback to normal. See issue 363.
variant = "normal";
}
return SVG.FONTDATA.VARIANT[variant];
},
SVGgetScale: function (svg) {
var scale = 1;
if (this.mscale) {
scale = this.scale;
} else {
var values = this.getValues("scriptlevel","fontsize");
values.mathsize = (this.isToken ? this : this.Parent()).Get("mathsize");
if ((this.styles||{}).fontSize && !values.fontsize) {values.fontsize = this.styles.fontSize}
if (values.fontsize && !this.mathsize) {values.mathsize = values.fontsize}
if (values.scriptlevel !== 0) {
if (values.scriptlevel > 2) {values.scriptlevel = 2}
scale = Math.pow(this.Get("scriptsizemultiplier"),values.scriptlevel);
values.scriptminsize = SVG.length2em(this.Get("scriptminsize"))/1000;
if (scale < values.scriptminsize) {scale = values.scriptminsize}
}
this.scale = scale; this.mscale = SVG.length2em(values.mathsize)/1000;
}
if (svg) {svg.scale = scale; if (this.isToken) {svg.scale *= this.mscale}}
return scale * this.mscale;
},
SVGgetMu: function (svg) {
var mu = 1, values = this.getValues("scriptlevel","scriptsizemultiplier");
if (svg.scale && svg.scale !== 1) {mu = 1/svg.scale}
if (values.scriptlevel !== 0) {
if (values.scriptlevel > 2) {values.scriptlevel = 2}
mu = Math.sqrt(Math.pow(values.scriptsizemultiplier,values.scriptlevel));
}
return mu;
},
SVGnotEmpty: function (data) {
while (data) {
if ((data.type !== "mrow" && data.type !== "texatom") ||
data.data.length > 1) {return true}
data = data.data[0];
}
return false;
},
SVGcanStretch: function (direction) {
var can = false;
if (this.isEmbellished()) {
var core = this.Core();
if (core && core !== this) {
can = core.SVGcanStretch(direction);
if (can && core.forceStretch) {this.forceStretch = true}
}
}
return can;
},
SVGstretchV: function (h,d) {return this.toSVG(h,d)},
SVGstretchH: function (w) {return this.toSVG(w)},
SVGlineBreaks: function () {return false}
},{
SVGemptySVG: function () {
var svg = this.SVG();
svg.Clean();
this.SVGsaveData(svg);
return svg;
},
SVGautoload: function () {
var file = SVG.autoloadDir+"/"+this.type+".js";
HUB.RestartAfter(AJAX.Require(file));
},
SVGautoloadFile: function (name) {
var file = SVG.autoloadDir+"/"+name+".js";
HUB.RestartAfter(AJAX.Require(file));
}
});
MML.chars.Augment({
toSVG: function (variant,scale,remap,chars) {
var text = this.data.join("").replace(/[\u2061-\u2064]/g,""); // remove invisibles
if (remap) {text = remap(text,chars)}
return this.SVGhandleVariant(variant,scale,text);
}
});
MML.entity.Augment({
toSVG: function (variant,scale,remap,chars) {
var text = this.toString().replace(/[\u2061-\u2064]/g,""); // remove invisibles
if (remap) {text = remap(text,chars)}
return this.SVGhandleVariant(variant,scale,text);
}
});
MML.mo.Augment({
toSVG: function (HW,D) {
this.SVGgetStyles();
var svg = this.svg = this.SVG();
var scale = this.SVGgetScale(svg);
this.SVGhandleSpace(svg);
if (this.data.length == 0) {svg.Clean(); this.SVGsaveData(svg); return svg}
//
// Stretch the operator, if that is requested
//
if (D != null) {return this.SVGstretchV(HW,D)}
else if (HW != null) {return this.SVG.strechH(HW)}
//
// Get the variant, and check for operator size
//
var variant = this.SVGgetVariant();
var values = this.getValues("largeop","displaystyle");
if (values.largeop)
{variant = SVG.FONTDATA.VARIANT[values.displaystyle ? "-largeOp" : "-smallOp"]}
//
// Get character translation for superscript and accents
//
var parent = this.CoreParent(),
isScript = (parent && parent.isa(MML.msubsup) && this !== parent.data[0]),
mapchars = (isScript?this.remapChars:null);
if (this.data.join("").length === 1 && parent && parent.isa(MML.munderover) &&
this.CoreText(parent.data[parent.base]).length === 1) {
var over = parent.data[parent.over], under = parent.data[parent.under];
if (over && this === over.CoreMO() && parent.Get("accent")) {mapchars = SVG.FONTDATA.REMAPACCENT}
else if (under && this === under.CoreMO() && parent.Get("accentunder")) {mapchars = SVG.FONTDATA.REMAPACCENTUNDER}
}
//
// Primes must come from another font
//
if (isScript && this.data.join("").match(/['`"\u00B4\u2032-\u2037\u2057]/))
{variant = SVG.FONTDATA.VARIANT["-"+SVG.fontInUse+"-variant"]}
//
// Typeset contents
//
for (var i = 0, m = this.data.length; i < m; i++) {
if (this.data[i]) {
var text = this.data[i].toSVG(variant,scale,this.remap,mapchars), x = svg.w;
if (x === 0 && -text.l > 10*text.w) {x += -text.l} // initial combining character doesn't combine
svg.Add(text,x,0,true);
if (text.skew) {svg.skew = text.skew}
}
}
svg.Clean();
if (this.data.join("").length !== 1) {delete svg.skew}
//
// Handle large operator centering
//
if (values.largeop) {
svg.y = SVG.TeX.axis_height - (svg.h - svg.d)/2/scale;
if (svg.r > svg.w) {svg.ic = svg.r - svg.w; svg.w = svg.r}
}
//
// Finish up
//
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
},
SVGcanStretch: function (direction) {
if (!this.Get("stretchy")) {return false}
var c = this.data.join("");
if (c.length > 1) {return false}
var parent = this.CoreParent();
if (parent && parent.isa(MML.munderover) &&
this.CoreText(parent.data[parent.base]).length === 1) {
var over = parent.data[parent.over], under = parent.data[parent.under];
if (over && this === over.CoreMO() && parent.Get("accent")) {c = SVG.FONTDATA.REMAPACCENT[c]||c}
else if (under && this === under.CoreMO() && parent.Get("accentunder")) {c = SVG.FONTDATA.REMAPACCENTUNDER[c]||c}
}
c = SVG.FONTDATA.DELIMITERS[c.charCodeAt(0)];
var can = (c && c.dir == direction.substr(0,1));
if (!can) {delete this.svg}
this.forceStretch = can && (this.Get("minsize",true) || this.Get("maxsize",true));
return can;
},
SVGstretchV: function (h,d) {
var svg = this.svg || this.toSVG();
var values = this.getValues("symmetric","maxsize","minsize");
var axis = SVG.TeX.axis_height*svg.scale, mu = this.SVGgetMu(svg), H;
if (values.symmetric) {H = 2*Math.max(h-axis,d+axis)} else {H = h + d}
values.maxsize = SVG.length2em(values.maxsize,mu,svg.h+svg.d);
values.minsize = SVG.length2em(values.minsize,mu,svg.h+svg.d);
H = Math.max(values.minsize,Math.min(values.maxsize,H));
if (H != values.minsize)
{H = [Math.max(H*SVG.TeX.delimiterfactor/1000,H-SVG.TeX.delimitershortfall),H]}
svg = SVG.createDelimiter(this.data.join("").charCodeAt(0),H,svg.scale);
if (values.symmetric) {H = (svg.h + svg.d)/2 + axis}
else {H = (svg.h + svg.d) * h/(h + d)}
svg.y = H - svg.h;
this.SVGhandleSpace(svg);
this.SVGhandleColor(svg);
delete this.svg.element;
this.SVGsaveData(svg);
svg.stretched = true;
return svg;
},
SVGstretchH: function (w) {
var svg = this.svg || this.toSVG(), mu = this.SVGgetMu(svg);
var values = this.getValues("maxsize","minsize","mathvariant","fontweight");
// FIXME: should take style="font-weight:bold" into account as well
if ((values.fontweight === "bold" || parseInt(values.fontweight) >= 600) &&
!this.Get("mathvariant",true)) {values.mathvariant = MML.VARIANT.BOLD}
values.maxsize = SVG.length2em(values.maxsize,mu,svg.w);
values.minsize = SVG.length2em(values.minsize,mu,svg.w);
w = Math.max(values.minsize,Math.min(values.maxsize,w));
svg = SVG.createDelimiter(this.data.join("").charCodeAt(0),w,svg.scale,values.mathvariant);
this.SVGhandleSpace(svg);
this.SVGhandleColor(svg);
delete this.svg.element;
this.SVGsaveData(svg);
svg.stretched = true;
return svg;
}
});
MML.mn.Augment({
SVGremapMinus: function (text) {return text.replace(/^-/,"\u2212")},
toSVG: function () {
this.SVGgetStyles();
var variant = this.SVGgetVariant();
var svg = this.SVG(); this.SVGgetScale(svg);
this.SVGhandleSpace(svg);
var remap = this.SVGremapMinus;
for (var i = 0, m = this.data.length; i < m; i++) {
if (this.data[i]) {
var child = svg.Add(this.data[i].toSVG(variant,svg.scale,remap),svg.w,0,true);
if (child.skew) {svg.skew = child.skew}
remap = null;
}
}
svg.Clean(); var text = this.data.join("");
if (svg.skew && text.length !== 1) {delete svg.skew}
if (svg.r > svg.w && text.length === 1 && !variant.noIC)
{svg.ic = svg.r - svg.w; svg.w = svg.r}
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
},
}),
MML.mtext.Augment({
toSVG: function () {
if (SVG.config.mtextFontInherit || this.Parent().type === "merror") {
this.SVGgetStyles();
var svg = this.SVG(), scale = this.SVGgetScale(svg);
this.SVGhandleSpace(svg);
var variant = this.SVGgetVariant(), def = {direction:this.Get("dir")};
if (variant.bold) {def["font-weight"] = "bold"}
if (variant.italic) {def["font-style"] = "italic"}
variant = this.Get("mathvariant");
if (variant === "monospace") {def["class"] = "MJX-monospace"}
else if (variant.match(/sans-serif/)) {def["class"] = "MJX-sans-serif"}
svg.Add(BBOX.TEXT(scale*100/SVG.config.scale,this.data.join(""),def)); svg.Clean();
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
} else {
return this.SUPER(arguments).toSVG.call(this);
}
}
});
MML.merror.Augment({
toSVG: function (HW,D) {
this.SVGgetStyles();
var svg = this.SVG(), scale = SVG.length2em(this.styles.fontSize||1)/1000;
this.SVGhandleSpace(svg);
var def = (scale !== 1 ? {transform:"scale("+SVG.Fixed(scale)+")"} : {});
var bbox = BBOX(def);
bbox.Add(this.SVGchildSVG(0)); bbox.Clean();
if (scale !== 1) {
bbox.removeable = false;
var adjust = ["w","h","d","l","r","D","H"];
for (var i = 0, m = adjust.length; i < m; i++) {bbox[adjust[i]] *= scale}
}
svg.Add(bbox); svg.Clean();
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
},
SVGgetStyles: function () {
var span = HTML.Element("span",{style: SVG.config.merrorStyle});
this.styles = this.SVGprocessStyles(span.style);
if (this.style) {
span.style.cssText = this.style;
HUB.Insert(this.styles,this.SVGprocessStyles(span.style));
}
}
});
MML.ms.Augment({toSVG: MML.mbase.SVGautoload});
MML.mglyph.Augment({toSVG: MML.mbase.SVGautoload});
MML.mspace.Augment({
toSVG: function () {
this.SVGgetStyles();
var values = this.getValues("height","depth","width");
values.mathbackground = this.mathbackground;
if (this.background && !this.mathbackground) {values.mathbackground = this.background}
var svg = this.SVG(); this.SVGgetScale(svg);
var scale = this.mscale, mu = this.SVGgetMu(svg);
svg.h = SVG.length2em(values.height,mu) * scale;
svg.d = SVG.length2em(values.depth,mu) * scale;
svg.w = svg.r = SVG.length2em(values.width,mu) * scale;
if (svg.w < 0) {svg.x = svg.w; svg.w = svg.r = 0}
if (svg.h < -svg.d) {svg.d = -svg.h}
svg.l = 0; svg.Clean();
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
}
});
MML.mphantom.Augment({
toSVG: function (HW,D) {
this.SVGgetStyles();
var svg = this.SVG(); this.SVGgetScale(svg);
if (this.data[0] != null) {
this.SVGhandleSpace(svg); svg.Add(this.SVGdataStretched(0,HW,D)); svg.Clean();
while (svg.element.firstChild) {svg.element.removeChild(svg.element.firstChild)}
}
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
if (svg.removeable && !svg.element.firstChild) {delete svg.element}
return svg;
}
});
MML.mpadded.Augment({
toSVG: function (HW,D) {
this.SVGgetStyles();
var svg = this.SVG();
if (this.data[0] != null) {
this.SVGgetScale(svg); this.SVGhandleSpace(svg);
var pad = this.SVGdataStretched(0,HW,D), mu = this.SVGgetMu(svg);
var values = this.getValues("height","depth","width","lspace","voffset"), X = 0, Y = 0;
if (values.lspace) {X = this.SVGlength2em(pad,values.lspace,mu)}
if (values.voffset) {Y = this.SVGlength2em(pad,values.voffset,mu)}
var h = pad.h, d = pad.d, w = pad.w, y = pad.y; // these can change durring the Add()
svg.Add(pad,X,Y); svg.Clean();
svg.h = h+y; svg.d = d-y; svg.w = w; svg.removeable = false;
if (values.height !== "") {svg.h = this.SVGlength2em(svg,values.height,mu,"h",0)}
if (values.depth !== "") {svg.d = this.SVGlength2em(svg,values.depth,mu,"d",0)}
if (values.width !== "") {svg.w = this.SVGlength2em(svg,values.width,mu,"w",0)}
if (svg.h > svg.H) {svg.H = svg.h}; if (svg.d > svg.D) {svg.D = svg.d}
}
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
},
SVGlength2em: function (svg,length,mu,d,m) {
if (m == null) {m = -SVG.BIGDIMEN}
var match = String(length).match(/width|height|depth/);
var size = (match ? svg[match[0].charAt(0)] : (d ? svg[d] : 0));
var v = SVG.length2em(length,mu,size/this.mscale)*this.mscale;
if (d && String(length).match(/^\s*[-+]/))
{return Math.max(m,svg[d]+v)} else {return v}
}
});
MML.mrow.Augment({
SVG: BBOX.ROW,
toSVG: function (h,d) {
this.SVGgetStyles();
var svg = this.SVG();
this.SVGhandleSpace(svg);
if (d != null) {svg.sh = h; svg.sd = d}
for (var i = 0, m = this.data.length; i < m; i++)
{if (this.data[i]) {svg.Check(this.data[i])}}
svg.Stretch(); svg.Clean();
if (this.data.length === 1 && this.data[0]) {
var data = this.data[0].SVGdata;
if (data.skew) {svg.skew = data.skew}
}
if (this.SVGlineBreaks(svg)) {svg = this.SVGmultiline(svg)}
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
},
SVGlineBreaks: function (svg) {
if (!this.parent.linebreakContainer) {return false}
return (SVG.config.linebreaks.automatic &&
svg.w > SVG.linebreakWidth) || this.hasNewline();
},
SVGmultiline: function (span) {MML.mbase.SVGautoloadFile("multiline")},
SVGstretchH: function (w) {
var svg = this.SVG();
this.SVGhandleSpace(svg);
for (var i = 0, m = this.data.length; i < m; i++)
{svg.Add(this.SVGdataStretched(i,w),svg.w,0)}
svg.Clean();
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
}
});
MML.mstyle.Augment({
toSVG: function () {
this.SVGgetStyles();
var svg = this.SVG();
if (this.data[0] != null) {
this.SVGhandleSpace(svg);
var math = svg.Add(this.data[0].toSVG()); svg.Clean();
if (math.ic) {svg.ic = math.ic}
this.SVGhandleColor(svg);
}
this.SVGsaveData(svg);
return svg;
},
SVGstretchH: function (w) {
return (this.data[0] != null ? this.data[0].SVGstretchH(w) : BBOX.NULL());
},
SVGstretchV: function (h,d) {
return (this.data[0] != null ? this.data[0].SVGstretchV(h,d) : BBOX.NULL());
}
});
MML.mfrac.Augment({
toSVG: function () {
this.SVGgetStyles();
var svg = this.SVG(), scale = this.SVGgetScale(svg);
var frac = BBOX(); frac.scale = svg.scale; this.SVGhandleSpace(frac);
var num = this.SVGchildSVG(0), den = this.SVGchildSVG(1);
var values = this.getValues("displaystyle","linethickness","numalign","denomalign","bevelled");
var isDisplay = values.displaystyle;
var a = SVG.TeX.axis_height * scale;
if (values.bevelled) {
var delta = (isDisplay ? 400 : 150);
var H = Math.max(num.h+num.d,den.h+den.d)+2*delta;
var bevel = SVG.createDelimiter(0x2F,H);
frac.Add(num,0,(num.d-num.h)/2+a+delta);
frac.Add(bevel,num.w-delta/2,(bevel.d-bevel.h)/2+a);
frac.Add(den,num.w+bevel.w-delta,(den.d-den.h)/2+a-delta);
} else {
var W = Math.max(num.w,den.w);
var t = SVG.thickness2em(values.linethickness,this.scale)*this.mscale, p,q, u,v;
var mt = SVG.TeX.min_rule_thickness/SVG.em * 1000;
if (isDisplay) {u = SVG.TeX.num1; v = SVG.TeX.denom1}
else {u = (t === 0 ? SVG.TeX.num3 : SVG.TeX.num2); v = SVG.TeX.denom2}
u *= scale; v *= scale;
if (t === 0) {// \atop
p = Math.max((isDisplay ? 7 : 3) * SVG.TeX.rule_thickness, 2*mt); // force to at least 2 px
q = (u - num.d) - (den.h - v);
if (q < p) {u += (p - q)/2; v += (p - q)/2}
frac.w = W; t = 0;
} else {// \over
p = Math.max((isDisplay ? 2 : 0) * mt + t, t/2 + 1.5*mt); // force to be at least 1.5px
q = (u - num.d) - (a + t/2); if (q < p) {u += p - q}
q = (a - t/2) - (den.h - v); if (q < p) {v += p - q}
frac.Add(BBOX.RECT(t/2,t/2,W+2*t),0,a);
}
frac.Align(num,values.numalign,t,u);
frac.Align(den,values.denomalign,t,-v);
}
frac.Clean(); svg.Add(frac,0,0); svg.Clean();
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
},
SVGcanStretch: function (direction) {return false},
SVGhandleSpace: function (svg) {
if (!this.texWithDelims && !this.useMMLspacing) {
//
// Add nulldelimiterspace around the fraction
// (TeXBook pg 150 and Appendix G rule 15e)
//
svg.x = svg.X = SVG.TeX.nulldelimiterspace * this.mscale;
}
this.SUPER(arguments).SVGhandleSpace.call(this,svg);
}
});
MML.msqrt.Augment({
toSVG: function () {
this.SVGgetStyles();
var svg = this.SVG(), scale = this.SVGgetScale(svg); this.SVGhandleSpace(svg);
var base = this.SVGchildSVG(0), rule, surd;
var t = SVG.TeX.rule_thickness * scale, p,q, H, x = 0;
if (this.Get("displaystyle")) {p = SVG.TeX.x_height * scale} else {p = t}
q = Math.max(t + p/4,1000*SVG.TeX.min_root_space/SVG.em);
H = base.h + base.d + q + t;
surd = SVG.createDelimiter(0x221A,H,scale);
if (surd.h + surd.d > H) {q = ((surd.h+surd.d) - (H-t)) / 2}
rule = BBOX.RECT(t,0,base.w);
H = base.h + q + t;
x = this.SVGaddRoot(svg,surd,x,surd.h+surd.d-H,scale);
svg.Add(surd,x,H-surd.h);
svg.Add(rule,x+surd.w,H-rule.h);
svg.Add(base,x+surd.w,0);
svg.Clean();
svg.h += t; svg.H += t;
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
},
SVGaddRoot: function (svg,surd,x,d,scale) {return x}
});
MML.mroot.Augment({
toSVG: MML.msqrt.prototype.toSVG,
SVGaddRoot: function (svg,surd,x,d,scale) {
var dx = (surd.isMultiChar ? .55 : .65) * surd.w;
if (this.data[1]) {
var root = this.data[1].toSVG(); root.x = 0;
var h = this.SVGrootHeight(surd.h+surd.d,scale,root)-d;
var w = Math.min(root.w,root.r); // remove extra right-hand padding, if any
x = Math.max(w,dx);
svg.Add(root,x-w,h);
} else {dx = x}
return x - dx;
},
SVGrootHeight: function (d,scale,root) {
return .45*(d-900*scale) + 600*scale + Math.max(0,root.d-75);
}
});
MML.mfenced.Augment({
SVG: BBOX.ROW,
toSVG: function () {
this.SVGgetStyles();
var svg = this.SVG();
this.SVGhandleSpace(svg);
if (this.data.open) {svg.Check(this.data.open)}
if (this.data[0] != null) {svg.Check(this.data[0])}
for (var i = 1, m = this.data.length; i < m; i++) {
if (this.data[i]) {
if (this.data["sep"+i]) {svg.Check(this.data["sep"+i])}
svg.Check(this.data[i]);
}
}
if (this.data.close) {svg.Check(this.data.close)}
svg.Stretch(); svg.Clean();
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
}
});
MML.menclose.Augment({toSVG: MML.mbase.SVGautoload});
MML.maction.Augment({toSVG: MML.mbase.SVGautoload});
MML.semantics.Augment({
toSVG: function () {
this.SVGgetStyles();
var svg = this.SVG();
if (this.data[0] != null) {
this.SVGhandleSpace(svg);
svg.Add(this.data[0].toSVG()); svg.Clean();
} else {svg.Clean()}
this.SVGsaveData(svg);
return svg;
},
SVGstretchH: function (w) {
return (this.data[0] != null ? this.data[0].SVGstretchH(w) : BBOX.NULL());
},
SVGstretchV: function (h,d) {
return (this.data[0] != null ? this.data[0].SVGstretchV(h,d) : BBOX.NULL());
}
});
MML.munderover.Augment({
toSVG: function (HW,D) {
this.SVGgetStyles();
var values = this.getValues("displaystyle","accent","accentunder","align");
var base = this.data[this.base];
if (!values.displaystyle && base != null &&
(base.movablelimits || base.CoreMO().Get("movablelimits")))
{return MML.msubsup.prototype.toSVG.call(this)}
var svg = this.SVG(), scale = this.SVGgetScale(svg); this.SVGhandleSpace(svg);
var boxes = [], stretch = [], box, i, m, W = -SVG.BIGDIMEN, WW = W;
for (i = 0, m = this.data.length; i < m; i++) {
if (this.data[i] != null) {
if (i == this.base) {
boxes[i] = this.SVGdataStretched(i,HW,D);
stretch[i] = (D != null || HW == null) && this.data[i].SVGcanStretch("Horizontal");
} else {
boxes[i] = this.data[i].toSVG(); boxes[i].x = 0; delete boxes[i].X;
stretch[i] = this.data[i].SVGcanStretch("Horizontal");
}
if (boxes[i].w > WW) {WW = boxes[i].w}
if (!stretch[i] && WW > W) {W = WW}
}
}
if (D == null && HW != null) {W = HW} else if (W == -SVG.BIGDIMEN) {W = WW}
for (i = WW = 0, m = this.data.length; i < m; i++) {if (this.data[i]) {
if (stretch[i]) {
boxes[i] = this.data[i].SVGstretchH(W);
if (i !== this.base) {boxes[i].x = 0; delete boxes[i].X}
}
if (boxes[i].w > WW) {WW = boxes[i].w}
}}
var t = SVG.TeX.rule_thickness * this.mscale;
var x, y, z1, z2, z3, dw, k, delta = 0;
base = boxes[this.base] || {w:0, h:0, d:0, H:0, D:0, l:0, r:0, y:0, scale:scale};
if (base.ic) {delta = 1.3*base.ic + .05} // adjust faked IC to be more in line with expeted results
for (i = 0, m = this.data.length; i < m; i++) {
if (this.data[i] != null) {
box = boxes[i];
z3 = SVG.TeX.big_op_spacing5 * scale;
var accent = (i != this.base && values[this.ACCENTS[i]]);
if (accent && box.w <= 1) {
box.x = -box.l;
boxes[i] = BBOX.G().With({removeable: false});
boxes[i].Add(box); boxes[i].Clean();
boxes[i].w = -box.l; box = boxes[i];
}
dw = {left:0, center:(WW-box.w)/2, right:WW-box.w}[values.align];
x = dw; y = 0;
if (i == this.over) {
if (accent) {
k = t * scale; z3 = 0;
if (base.skew) {
x += base.skew; svg.skew = base.skew;
if (x+box.w > WW) {svg.skew += (WW-box.w-x)/2}
}
} else {
z1 = SVG.TeX.big_op_spacing1 * scale;
z2 = SVG.TeX.big_op_spacing3 * scale;
k = Math.max(z1,z2-Math.max(0,box.d));
}
k = Math.max(k,1500/SVG.em);
x += delta/2; y = base.y + base.h + box.d + k;
box.h += z3; if (box.h > box.H) {box.H = box.h}
} else if (i == this.under) {
if (accent) {
k = 3*t * scale; z3 = 0;
} else {
z1 = SVG.TeX.big_op_spacing2 * scale;
z2 = SVG.TeX.big_op_spacing4 * scale;
k = Math.max(z1,z2-box.h);
}
k = Math.max(k,1500/SVG.em);
x -= delta/2; y = base.y -(base.d + box.h + k);
box.d += z3; if (box.d > box.D) {box.D = box.d}
}
svg.Add(box,x,y);
}
}
svg.Clean();
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
}
});
MML.msubsup.Augment({
toSVG: function (HW,D) {
this.SVGgetStyles();
var svg = this.SVG(), scale = this.SVGgetScale(svg); this.SVGhandleSpace(svg);
var mu = this.SVGgetMu(svg);
var base = svg.Add(this.SVGdataStretched(this.base,HW,D));
var sscale = (this.data[this.sup] || this.data[this.sub] || this).SVGgetScale();
var x_height = SVG.TeX.x_height * scale, s = SVG.TeX.scriptspace * scale;
var sup, sub;
if (this.SVGnotEmpty(this.data[this.sup])) {
sup = this.data[this.sup].toSVG();
sup.w += s; sup.r = Math.max(sup.w,sup.r);
}
if (this.SVGnotEmpty(this.data[this.sub])) {
sub = this.data[this.sub].toSVG();
sub.w += s; sub.r = Math.max(sub.w,sub.r);
}
var q = SVG.TeX.sup_drop * sscale, r = SVG.TeX.sub_drop * sscale;
var u = base.h+(base.y||0) - q, v = base.d-(base.y||0) + r, delta = 0, p;
if (base.ic) {
base.w -= base.ic; // remove IC (added by mo and mi)
delta = 1.3*base.ic+.05; // adjust faked IC to be more in line with expeted results
}
if (this.data[this.base] &&
(this.data[this.base].type === "mi" || this.data[this.base].type === "mo")) {
if (this.data[this.base].data.join("").length === 1 && base.scale === 1 &&
!base.stretched && !this.data[this.base].Get("largeop")) {u = v = 0}
}
var min = this.getValues("subscriptshift","superscriptshift");
min.subscriptshift = (min.subscriptshift === "" ? 0 : SVG.length2em(min.subscriptshift,mu));
min.superscriptshift = (min.superscriptshift === "" ? 0 : SVG.length2em(min.superscriptshift,mu));
var x = base.w + base.x;
if (!sup) {
if (sub) {
v = Math.max(v,SVG.TeX.sub1*scale,sub.h-(4/5)*x_height,min.subscriptshift);
svg.Add(sub,x,-v); this.data[this.sub].SVGdata.dy = -v;
}
} else {
if (!sub) {
values = this.getValues("displaystyle","texprimestyle");
p = SVG.TeX[(values.displaystyle ? "sup1" : (values.texprimestyle ? "sup3" : "sup2"))];
u = Math.max(u,p*scale,sup.d+(1/4)*x_height,min.superscriptshift);
svg.Add(sup,x+delta,u);
this.data[this.sup].SVGdata.dx = delta;
this.data[this.sup].SVGdata.dy = u;
} else {
v = Math.max(v,SVG.TeX.sub2*scale);
var t = SVG.TeX.rule_thickness * scale;
if ((u - sup.d) - (sub.h - v) < 3*t) {
v = 3*t - u + sup.d + sub.h;
q = (4/5)*x_height - (u - sup.d);
if (q > 0) {u += q; v -= q}
}
svg.Add(sup,x+delta,Math.max(u,min.superscriptshift));
svg.Add(sub,x,-Math.max(v,min.subscriptshift));
this.data[this.sup].SVGdata.dx = delta;
this.data[this.sup].SVGdata.dy = Math.max(u,min.superscriptshift);
this.data[this.sub].SVGdata.dy = -Math.max(v,min.subscriptshift);
}
}
svg.Clean();
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
}
});
MML.mmultiscripts.Augment({toSVG: MML.mbase.SVGautoload});
MML.mtable.Augment({toSVG: MML.mbase.SVGautoload});
MML["annotation-xml"].Augment({toSVG: MML.mbase.SVGautoload});
MML.math.Augment({
SVG: BBOX.Subclass({type:"svg", removeable: false}),
toSVG: function (span,div) {
var CONFIG = SVG.config;
//
// All the data should be in an inferrerd row
//
if (this.data[0]) {
this.SVGgetStyles();
MML.mbase.prototype.displayAlign = HUB.config.displayAlign;
MML.mbase.prototype.displayIndent = HUB.config.displayIndent;
if (String(HUB.config.displayIndent).match(/^0($|[a-z%])/i))
MML.mbase.prototype.displayIndent = "0";
//
// Put content in a <g> with defaults and matrix that flips y axis.
// Put that in an <svg> with xlink defined.
//
var box = BBOX.G(); box.Add(this.data[0].toSVG(),0,0,true); box.Clean();
this.SVGhandleColor(box);
SVG.Element(box.element,{
stroke:"currentColor", fill:"currentColor", "stroke-width":0,
transform: "matrix(1 0 0 -1 0 0)"
});
box.removeable = false;
var svg = this.SVG();
svg.element.setAttribute("xmlns:xlink",XLINKNS);
if (CONFIG.useFontCache && !CONFIG.useGlobalCache)
{svg.element.appendChild(BBOX.GLYPH.defs)}
svg.Add(box); svg.Clean();
this.SVGsaveData(svg);
//
// If this element is not the top-level math element
// remove the transform and return the svg object
// (issue #614).
//
if (!span) {
svg.element = svg.element.firstChild; // remove <svg> element
svg.element.removeAttribute("transform");
svg.removable = true;
return svg;
}
//
// Style the <svg> to get the right size and placement
//
var l = Math.max(-svg.l,0), r = Math.max(svg.r-svg.w,0);
var style = svg.element.style, px = SVG.TeX.x_height/SVG.ex;
var H = (Math.ceil(svg.H/px)+1)*px+SVG.HFUZZ, // round to pixels and add padding
D = (Math.ceil(svg.D/px)+1)*px+SVG.DFUZZ;
var w = l + svg.w + r;
svg.element.setAttribute("width",SVG.Ex(w));
svg.element.setAttribute("height",SVG.Ex(H+D));
style.verticalAlign = SVG.Ex(-D);
if (l) style.marginLeft = SVG.Ex(-l);
if (r) style.marginRight = SVG.Ex(-r);
svg.element.setAttribute("viewBox",SVG.Fixed(-l,1)+" "+SVG.Fixed(-H,1)+" "+
SVG.Fixed(w,1)+" "+SVG.Fixed(H+D,1));
//
// If there is extra height or depth, hide that
//
if (svg.H > svg.h) style.marginTop = SVG.Ex(svg.h-H);
if (svg.D > svg.d) {
style.marginBottom = SVG.Ex(svg.d-D);
style.verticalAlign = SVG.Ex(-svg.d);
}
//
// The approximate ex can cause full-width equations to be too wide,
// so if they are close to full width, make sure they aren't too big.
//
if (Math.abs(w-SVG.cwidth) < 10)
style.maxWidth = SVG.Fixed(SVG.cwidth*SVG.em/1000);
//
// Add it to the MathJax span
//
var alttext = this.Get("alttext");
if (alttext && !svg.element.getAttribute("aria-label")) svg.element.setAttribute("aria-label",alttext);
if (!svg.element.getAttribute("role")) svg.element.setAttribute("role","img");
svg.element.setAttribute("focusable","false");
span.appendChild(svg.element);
svg.element = null;
//
// Handle indentalign and indentshift for single-line displays
//
if (!this.isMultiline && this.Get("display") === "block" && !svg.hasIndent) {
var values = this.getValues("indentalignfirst","indentshiftfirst","indentalign","indentshift");
if (values.indentalignfirst !== MML.INDENTALIGN.INDENTALIGN) {values.indentalign = values.indentalignfirst}
if (values.indentalign === MML.INDENTALIGN.AUTO) {values.indentalign = this.displayAlign}
if (values.indentshiftfirst !== MML.INDENTSHIFT.INDENTSHIFT) {values.indentshift = values.indentshiftfirst}
if (values.indentshift === "auto") {values.indentshift = "0"}
var shift = SVG.length2em(values.indentshift,1,SVG.cwidth);
if (this.displayIndent !== "0") {
var indent = SVG.length2em(this.displayIndent,1,SVG.cwidth);
shift += (values.indentalign === MML.INDENTALIGN.RIGHT ? -indent : indent);
}
div.style.textAlign = values.indentalign;
if (shift) {
HUB.Insert(style,({
left: {marginLeft: SVG.Ex(shift)},
right: {marginRight: SVG.Ex(-shift), marginLeft: SVG.Ex(Math.max(0,shift-w))},
center: {marginLeft: SVG.Ex(shift), marginRight: SVG.Ex(-shift)}
})[values.indentalign]);
}
}
}
return span;
}
});
MML.TeXAtom.Augment({
toSVG: function (HW,D) {
this.SVGgetStyles();
var svg = this.SVG();
this.SVGhandleSpace(svg);
if (this.data[0] != null) {
var box = this.SVGdataStretched(0,HW,D), y = 0;
if (this.texClass === MML.TEXCLASS.VCENTER)
{y = SVG.TeX.axis_height - (box.h+box.d)/2 + box.d}
svg.Add(box,0,y);
svg.ic = box.ic; svg.skew = box.skew;
}
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
}
});
//
// Make sure these don't generate output
//
MML.maligngroup.Augment({toSVG: MML.mbase.SVGemptySVG});
MML.malignmark.Augment({toSVG: MML.mbase.SVGemptySVG});
MML.mprescripts.Augment({toSVG: MML.mbase.SVGemptySVG});
MML.none.Augment({toSVG: MML.mbase.SVGemptySVG});
//
// Loading isn't complete until the element jax is modified,
// but can't call loadComplete within the callback for "mml Jax Ready"
// (it would call SVG's Require routine, asking for the mml jax again)
// so wait until after the mml jax has finished processing.
//
// We also need to wait for the onload handler to run, since the loadComplete
// will call Config and Startup, which need to modify the body.
//
HUB.Register.StartupHook("onLoad",function () {
setTimeout(MathJax.Callback(["loadComplete",SVG,"jax.js"]),0);
});
});
HUB.Browser.Select({
Opera: function (browser) {
SVG.Augment({
operaZoomRefresh: true // Opera needs a kick to redraw zoomed equations
});
}
});
HUB.Register.StartupHook("End Cookie", function () {
if (HUB.config.menuSettings.zoom !== "None")
{AJAX.Require("[MathJax]/extensions/MathZoom.js")}
});
if (!document.createElementNS) {
//
// Try to handle SVG in IE8 and below, but fail
// (but don't crash on loading the file, so no delay for loadComplete)
//
if (!document.namespaces.svg) {document.namespaces.add("svg",SVGNS)}
SVG.Augment({
Element: function (type,def) {
var obj = (typeof(type) === "string" ? document.createElement("svg:"+type) : type);
obj.isMathJax = true;
if (def) {for (var id in def) {if (def.hasOwnProperty(id)) {obj.setAttribute(id,def[id].toString())}}}
return obj;
}
});
}
})(MathJax.Ajax, MathJax.Hub, MathJax.HTML, MathJax.OutputJax.SVG);
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/jax/output/SVG/autoload/mtable.js
*
* Implements the SVG output for <mtable> elements.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2011-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
MathJax.Hub.Register.StartupHook("SVG Jax Ready",function () {
var VERSION = "2.7.1";
var MML = MathJax.ElementJax.mml,
SVG = MathJax.OutputJax.SVG,
BBOX = SVG.BBOX;
MML.mtable.Augment({
toSVG: function (span) {
this.SVGgetStyles();
var svg = this.SVG(), scale = this.SVGgetScale(svg);
if (this.data.length === 0) {this.SVGsaveData(svg);return svg}
var values = this.getValues("columnalign","rowalign","columnspacing","rowspacing",
"columnwidth","equalcolumns","equalrows",
"columnlines","rowlines","frame","framespacing",
"align","useHeight","width","side","minlabelspacing");
// Handle relative width as fixed width in relation to container
if (values.width.match(/%$/))
{svg.width = values.width = SVG.Em((SVG.cwidth/1000)*(parseFloat(values.width)/100))}
var mu = this.SVGgetMu(svg);
var LABEL = -1;
var H = [], D = [], W = [], A = [], C = [], i, j, J = -1,
m, M, s, row, cell, mo, HD;
var LH = SVG.FONTDATA.lineH * scale * values.useHeight,
LD = SVG.FONTDATA.lineD * scale * values.useHeight;
//
// Create cells and measure columns and rows
//
for (i = 0, m = this.data.length; i < m; i++) {
row = this.data[i]; s = (row.type === "mlabeledtr" ? LABEL : 0);
A[i] = []; H[i] = LH; D[i] = LD;
for (j = s, M = row.data.length + s; j < M; j++) {
if (W[j] == null) {
if (j > J) {J = j}
C[j] = BBOX.G();
W[j] = -SVG.BIGDIMEN;
}
cell = row.data[j-s];
A[i][j] = cell.toSVG();
// if (row.data[j-s].isMultiline) {A[i][j].style.width = "100%"}
if (cell.isEmbellished()) {
mo = cell.CoreMO();
var min = mo.Get("minsize",true);
if (min) {
if (mo.SVGcanStretch("Vertical")) {
HD = mo.SVGdata.h + mo.SVGdata.d;
if (HD) {
min = SVG.length2em(min,mu,HD);
if (min*mo.SVGdata.h/HD > H[i]) {H[i] = min*mo.SVGdata.h/HD}
if (min*mo.SVGdata.d/HD > D[i]) {D[i] = min*mo.SVGdata.d/HD}
}
} else if (mo.SVGcanStretch("Horizontal")) {
min = SVG.length2em(min,mu,mo.SVGdata.w);
if (min > W[j]) {W[j] = min}
}
}
}
if (A[i][j].h > H[i]) {H[i] = A[i][j].h}
if (A[i][j].d > D[i]) {D[i] = A[i][j].d}
if (A[i][j].w > W[j]) {W[j] = A[i][j].w}
}
}
//
// Determine spacing and alignment
//
var SPLIT = MathJax.Hub.SplitList;
var CSPACE = SPLIT(values.columnspacing),
RSPACE = SPLIT(values.rowspacing),
CALIGN = SPLIT(values.columnalign),
RALIGN = SPLIT(values.rowalign),
CLINES = SPLIT(values.columnlines),
RLINES = SPLIT(values.rowlines),
CWIDTH = SPLIT(values.columnwidth),
RCALIGN = [];
for (i = 0, m = CSPACE.length; i < m; i++) {CSPACE[i] = SVG.length2em(CSPACE[i],mu)}
for (i = 0, m = RSPACE.length; i < m; i++) {RSPACE[i] = SVG.length2em(RSPACE[i],mu)}
while (CSPACE.length < J) {CSPACE.push(CSPACE[CSPACE.length-1])}
while (CALIGN.length <= J) {CALIGN.push(CALIGN[CALIGN.length-1])}
while (CLINES.length < J) {CLINES.push(CLINES[CLINES.length-1])}
while (CWIDTH.length <= J) {CWIDTH.push(CWIDTH[CWIDTH.length-1])}
while (RSPACE.length < A.length) {RSPACE.push(RSPACE[RSPACE.length-1])}
while (RALIGN.length <= A.length) {RALIGN.push(RALIGN[RALIGN.length-1])}
while (RLINES.length < A.length) {RLINES.push(RLINES[RLINES.length-1])}
if (C[LABEL]) {
CALIGN[LABEL] = (values.side.substr(0,1) === "l" ? "left" : "right");
CSPACE[LABEL] = -W[LABEL];
}
//
// Override row data
//
for (i = 0, m = A.length; i < m; i++) {
row = this.data[i]; RCALIGN[i] = [];
if (row.rowalign) {RALIGN[i] = row.rowalign}
if (row.columnalign) {
RCALIGN[i] = SPLIT(row.columnalign);
while (RCALIGN[i].length <= J) {RCALIGN[i].push(RCALIGN[i][RCALIGN[i].length-1])}
}
}
//
// Handle equal heights
//
if (values.equalrows) {
// FIXME: should really be based on row align (below is for baseline)
var Hm = Math.max.apply(Math,H), Dm = Math.max.apply(Math,D);
for (i = 0, m = A.length; i < m; i++)
{s = ((Hm + Dm) - (H[i] + D[i])) / 2; H[i] += s; D[i] += s}
}
// FIXME: do background colors for entire cell (include half the intercolumn space?)
//
// Determine array total height
//
HD = H[0] + D[A.length-1];
for (i = 0, m = A.length-1; i < m; i++)
{HD += Math.max(0,D[i]+H[i+1]+RSPACE[i])}
//
// Determine frame and line sizes
//
var fx = 0, fy = 0, fW, fH = HD;
if (values.frame !== "none" ||
(values.columnlines+values.rowlines).match(/solid|dashed/)) {
var frameSpacing = SPLIT(values.framespacing);
if (frameSpacing.length != 2) {
// invalid attribute value: use the default.
frameSpacing = SPLIT(this.defaults.framespacing);
}
fx = SVG.length2em(frameSpacing[0],mu);
fy = SVG.length2em(frameSpacing[1],mu);
fH = HD + 2*fy; // fW waits until svg.w is determined
}
//
// Compute alignment
//
var Y, fY, n = "";
if (typeof(values.align) !== "string") {values.align = String(values.align)}
if (values.align.match(/(top|bottom|center|baseline|axis)( +(-?\d+))?/))
{n = RegExp.$3||""; values.align = RegExp.$1} else {values.align = this.defaults.align}
if (n !== "") {
//
// Find the height of the given row
//
n = parseInt(n);
if (n < 0) {n = A.length + 1 + n}
if (n < 1) {n = 1} else if (n > A.length) {n = A.length}
Y = 0; fY = -(HD + fy) + H[0];
for (i = 0, m = n-1; i < m; i++) {
// FIXME: Should handle values.align for final row
var dY = Math.max(0,D[i]+H[i+1]+RSPACE[i]);
Y += dY; fY += dY;
}
} else {
Y = ({
top: -(H[0] + fy),
bottom: HD + fy - H[0],
center: HD/2 - H[0],
baseline: HD/2 - H[0],
axis: HD/2 + SVG.TeX.axis_height*scale - H[0]
})[values.align];
fY = ({
top: -(HD + 2*fy),
bottom: 0,
center: -(HD/2 + fy),
baseline: -(HD/2 + fy),
axis: SVG.TeX.axis_height*scale - HD/2 - fy
})[values.align];
}
var WW, WP = 0, Wt = 0, Wp = 0, p = 0, f = 0, P = [], F = [], Wf = 1;
//
if (values.equalcolumns && values.width !== "auto") {
//
// Handle equalcolumns for percent-width and fixed-width tables
//
// Get total width minus column spacing
WW = SVG.length2em(values.width,mu);
for (i = 0, m = Math.min(J,CSPACE.length); i < m; i++) {WW -= CSPACE[i]}
// Determine individual column widths
WW /= J;
for (i = 0, m = Math.min(J+1,CWIDTH.length); i < m; i++) {W[i] = WW}
} else {
//
// Get column widths for fit and percentage columns
//
// Calculate the natural widths and percentage widths,
// while keeping track of the fit and percentage columns
for(i = 0, m = Math.min(J+1,CWIDTH.length); i < m; i++) {
if (CWIDTH[i] === "auto") {Wt += W[i]}
else if (CWIDTH[i] === "fit") {F[f] = i; f++; Wt += W[i]}
else if (CWIDTH[i].match(/%$/))
{P[p] = i; p++; Wp += W[i]; WP += SVG.length2em(CWIDTH[i],mu,1)}
else {W[i] = SVG.length2em(CWIDTH[i],mu); Wt += W[i]}
}
// Get the full width (excluding inter-column spacing)
if (values.width === "auto") {
if (WP > .98) {Wf = Wp/(Wt+Wp); WW = Wt + Wp} else {WW = Wt / (1-WP)}
} else {
WW = SVG.length2em(values.width,mu);
for (i = 0, m = Math.min(J,CSPACE.length); i < m; i++) {WW -= CSPACE[i]}
}
// Determine the relative column widths
for (i = 0, m = P.length; i < m; i++) {
W[P[i]] = SVG.length2em(CWIDTH[P[i]],mu,WW*Wf); Wt += W[P[i]];
}
// Stretch fit columns, if any, otherwise stretch (or shrink) everything
if (Math.abs(WW - Wt) > .01) {
if (f && WW > Wt) {
WW = (WW - Wt) / f; for (i = 0, m = F.length; i < m; i++) {W[F[i]] += WW}
} else {WW = WW/Wt; for (j = 0; j <= J; j++) {W[j] *= WW}}
}
//
// Handle equal columns
//
if (values.equalcolumns) {
var Wm = Math.max.apply(Math,W);
for (j = 0; j <= J; j++) {W[j] = Wm}
}
}
//
// Lay out array columns
//
var y = Y, dy, align; s = (C[LABEL] ? LABEL : 0);
for (j = s; j <= J; j++) {
C[j].w = W[j];
for (i = 0, m = A.length; i < m; i++) {
if (A[i][j]) {
s = (this.data[i].type === "mlabeledtr" ? LABEL : 0);
cell = this.data[i].data[j-s];
if (cell.SVGcanStretch("Horizontal")) {
A[i][j] = cell.SVGstretchH(W[j]);
} else if (cell.SVGcanStretch("Vertical")) {
mo = cell.CoreMO();
var symmetric = mo.symmetric; mo.symmetric = false;
A[i][j] = cell.SVGstretchV(H[i],D[i]);
mo.symmetric = symmetric;
}
align = cell.rowalign||this.data[i].rowalign||RALIGN[i];
dy = ({top: H[i] - A[i][j].h,
bottom: A[i][j].d - D[i],
center: ((H[i]-D[i]) - (A[i][j].h-A[i][j].d))/2,
baseline: 0, axis: 0})[align] || 0; // FIXME: handle axis better?
align = (cell.columnalign||RCALIGN[i][j]||CALIGN[j])
C[j].Align(A[i][j],align,0,y+dy);
}
if (i < A.length-1) {y -= Math.max(0,D[i]+H[i+1]+RSPACE[i])}
}
y = Y;
}
//
// Place the columns and add column lines
//
var lw = 1.5*SVG.em;
var x = fx - lw/2;
for (j = 0; j <= J; j++) {
svg.Add(C[j],x,0); x += W[j] + CSPACE[j];
if (CLINES[j] !== "none" && j < J && j !== LABEL)
{svg.Add(BBOX.VLINE(fH,lw,CLINES[j]),x-CSPACE[j]/2,fY)}
}
svg.w += fx; svg.d = -fY; svg.h = fH+fY;
fW = svg.w;
//
// Add frame
//
if (values.frame !== "none") {
svg.Add(BBOX.HLINE(fW,lw,values.frame),0,fY+fH-lw);
svg.Add(BBOX.HLINE(fW,lw,values.frame),0,fY);
svg.Add(BBOX.VLINE(fH,lw,values.frame),0,fY);
svg.Add(BBOX.VLINE(fH,lw,values.frame),fW-lw,fY);
}
//
// Add row lines
//
y = Y - lw/2;
for (i = 0, m = A.length-1; i < m; i++) {
dy = Math.max(0,D[i]+H[i+1]+RSPACE[i]);
if (RLINES[i] !== MML.LINES.NONE && RLINES[i] !== "")
{svg.Add(BBOX.HLINE(fW,lw,RLINES[i]),0,y-D[i]-(dy-D[i]-H[i+1])/2)}
y -= dy;
}
//
// Finish the table
//
svg.Clean();
this.SVGhandleSpace(svg);
this.SVGhandleColor(svg);
//
// Place the labels, if any
//
if (C[LABEL]) {
svg.tw = Math.max(svg.w,svg.r) - Math.min(0,svg.l);
var indent = this.getValues("indentalignfirst","indentshiftfirst","indentalign","indentshift");
if (indent.indentalignfirst !== MML.INDENTALIGN.INDENTALIGN) {indent.indentalign = indent.indentalignfirst}
if (indent.indentalign === MML.INDENTALIGN.AUTO) {indent.indentalign = this.displayAlign}
if (indent.indentshiftfirst !== MML.INDENTSHIFT.INDENTSHIFT) {indent.indentshift = indent.indentshiftfirst}
if (indent.indentshift === "auto" || indent.indentshift === "") {indent.indentshift = "0"}
var shift = SVG.length2em(indent.indentshift,mu,SVG.cwidth);
var labelspace = SVG.length2em(values.minlabelspacing,mu,SVG.cwidth);
var labelW = labelspace + C[LABEL].w, labelshift = 0, tw = svg.w;
var dIndent = SVG.length2em(this.displayIndent,mu,SVG.cwidth);
s = (CALIGN[LABEL] === MML.INDENTALIGN.RIGHT ? -1 : 1);
if (indent.indentalign === MML.INDENTALIGN.CENTER) {
var dx = (SVG.cwidth-tw)/2; shift += dIndent;
if (labelW + s*labelshift > dx + s*shift) {
indent.indentalign = CALIGN[LABEL];
shift = s*(labelW + s*labelshift); tw += labelW + Math.max(0,shift);
}
} else if (CALIGN[LABEL] === indent.indentalign) {
if (dIndent < 0) {labelshift = s*dIndent; dIndent = 0}
shift += s*dIndent; if (labelW > s*shift) shift = s*labelW; shift += labelshift;
tw += s*shift;
} else {
shift -= s*dIndent;
if (tw - s*shift + labelW > SVG.cwidth) {
shift = s*(tw + labelW - SVG.cwidth);
if (s*shift > 0) {tw = SVG.cwidth + s*shift; shift = 0}
}
}
var eqn = svg; svg = this.SVG();
svg.hasIndent = true;
svg.w = svg.r = Math.max(tw,SVG.cwidth);
svg.Align(C[LABEL],CALIGN[LABEL],0,0,labelshift);
svg.Align(eqn,indent.indentalign,0,0,shift);
svg.tw = tw;
}
this.SVGsaveData(svg);
return svg;
},
SVGhandleSpace: function (svg) {
if (!this.hasFrame && !svg.width) {svg.x = svg.X = 167}
this.SUPER(arguments).SVGhandleSpace.call(this,svg);
}
});
MML.mtd.Augment({
toSVG: function (HW,D) {
var svg = this.svg = this.SVG();
if (this.data[0]) {
svg.Add(this.SVGdataStretched(0,HW,D));
svg.Clean();
}
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
}
});
MathJax.Hub.Startup.signal.Post("SVG mtable Ready");
MathJax.Ajax.loadComplete(SVG.autoloadDir+"/mtable.js");
});
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/jax/output/SVG/autoload/mglyph.js
*
* Implements the SVG output for <mglyph> elements.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2011-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
MathJax.Hub.Register.StartupHook("SVG Jax Ready",function () {
var VERSION = "2.7.1";
var MML = MathJax.ElementJax.mml,
SVG = MathJax.OutputJax.SVG,
BBOX = SVG.BBOX,
LOCALE = MathJax.Localization;
var XLINKNS = "http://www.w3.org/1999/xlink";
BBOX.MGLYPH = BBOX.Subclass({
type: "image", removeable: false,
Init: function (img,w,h,align,mu,def) {
if (def == null) {def = {}}
var W = img.width*1000/SVG.em, H = img.height*1000/SVG.em;
var WW = W, HH = H, y = 0;
if (w !== "") {W = SVG.length2em(w,mu,WW); H = (WW ? W/WW * HH : 0)}
if (h !== "") {H = SVG.length2em(h,mu,HH); if (w === "") {W = (HH ? H/HH * WW : 0)}}
if (align !== "" && align.match(/\d/)) {y = SVG.length2em(align,mu); def.y = -y}
def.height = Math.floor(H); def.width = Math.floor(W);
def.transform = "translate(0,"+H+") matrix(1 0 0 -1 0 0)";
def.preserveAspectRatio = "none";
this.SUPER(arguments).Init.call(this,def);
this.element.setAttributeNS(XLINKNS,"href",img.SRC);
this.w = this.r = W; this.h = this.H = H + y;
this.d = this.D = -y; this.l = 0;
}
});
MML.mglyph.Augment({
toSVG: function (variant,scale) {
this.SVGgetStyles(); var svg = this.SVG(), img, err;
this.SVGhandleSpace(svg);
var values = this.getValues("src","width","height","valign","alt");
if (values.src === "") {
values = this.getValues("index","fontfamily");
if (values.index) {
if (!scale) {scale = this.SVGgetScale()}
var def = {}; if (values.fontfamily) {def["font-family"] = values.fontfamily}
svg.Add(BBOX.TEXT(scale,String.fromCharCode(values.index),def));
}
} else {
if (!this.img) {this.img = MML.mglyph.GLYPH[values.src]}
if (!this.img) {
this.img = MML.mglyph.GLYPH[values.src] = {img: new Image(), status: "pending"};
img = this.img.img;
img.onload = MathJax.Callback(["SVGimgLoaded",this]);
img.onerror = MathJax.Callback(["SVGimgError",this]);
img.src = img.SRC = values.src;
MathJax.Hub.RestartAfter(img.onload);
}
if (this.img.status !== "OK") {
err = MML.Error(
LOCALE._(["MathML","BadMglyph"],"Bad mglyph: %1",values.src),
{mathsize:"75%"});
this.Append(err); svg = err.toSVG(); this.data.pop();
} else {
var mu = this.SVGgetMu(svg);
svg.Add(BBOX.MGLYPH(this.img.img,values.width,values.height,values.valign,mu,
{alt:values.alt, title:values.alt}));
}
}
svg.Clean();
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
},
SVGimgLoaded: function (event,status) {
if (typeof(event) === "string") {status = event}
this.img.status = (status || "OK")
},
SVGimgError: function () {this.img.img.onload("error")}
},{
GLYPH: {} // global list of all loaded glyphs
});
MathJax.Hub.Startup.signal.Post("SVG mglyph Ready");
MathJax.Ajax.loadComplete(SVG.autoloadDir+"/mglyph.js");
});
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/jax/output/SVG/autoload/mmultiscripts.js
*
* Implements the SVG output for <mmultiscripts> elements.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2011-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
MathJax.Hub.Register.StartupHook("SVG Jax Ready",function () {
var VERSION = "2.7.1";
var MML = MathJax.ElementJax.mml,
SVG = MathJax.OutputJax.SVG;
MML.mmultiscripts.Augment({
toSVG: function (HW,D) {
this.SVGgetStyles();
var svg = this.SVG(), scale = this.SVGgetScale(svg); this.SVGhandleSpace(svg);
var base = (this.data[this.base] ? this.SVGdataStretched(this.base,HW,D) : SVG.BBOX.G().Clean());
var x_height = SVG.TeX.x_height * scale,
s = SVG.TeX.scriptspace * scale * .75; // FIXME: .75 can be removed when IC is right?
var BOX = this.SVGgetScripts(s);
var sub = BOX[0], sup = BOX[1], presub = BOX[2], presup = BOX[3];
var sscale = (this.data[1]||this).SVGgetScale();
var q = SVG.TeX.sup_drop * sscale, r = SVG.TeX.sub_drop * sscale;
var u = base.h - q, v = base.d + r, delta = 0, p;
if (base.ic) {delta = base.ic}
if (this.data[this.base] &&
(this.data[this.base].type === "mi" || this.data[this.base].type === "mo")) {
if (this.data[this.base].data.join("").length === 1 && base.scale === 1 &&
!base.stretched && !this.data[this.base].Get("largeop")) {u = v = 0}
}
var min = this.getValues("subscriptshift","superscriptshift"), mu = this.SVGgetMu(svg);
min.subscriptshift = (min.subscriptshift === "" ? 0 : SVG.length2em(min.subscriptshift,mu));
min.superscriptshift = (min.superscriptshift === "" ? 0 : SVG.length2em(min.superscriptshift,mu));
var dx = 0;
if (presub) {dx = presub.w+delta} else if (presup) {dx = presup.w-delta}
svg.Add(base,Math.max(0,dx),0);
if (!sup && !presup) {
v = Math.max(v,SVG.TeX.sub1*scale,min.subscriptshift);
if (sub) {v = Math.max(v,sub.h-(4/5)*x_height)}
if (presub) {v = Math.max(v,presub.h-(4/5)*x_height)}
if (sub) {svg.Add(sub,dx+base.w+s-delta,-v)}
if (presub) {svg.Add(presub,0,-v)}
} else {
if (!sub && !presub) {
var values = this.getValues("displaystyle","texprimestyle");
p = SVG.TeX[(values.displaystyle ? "sup1" : (values.texprimestyle ? "sup3" : "sup2"))];
u = Math.max(u,p*scale,min.superscriptshift);
if (sup) {u = Math.max(u,sup.d+(1/4)*x_height)}
if (presup) {u = Math.max(u,presup.d+(1/4)*x_height)}
if (sup) {svg.Add(sup,dx+base.w+s,u)}
if (presup) {svg.Add(presup,0,u)}
} else {
v = Math.max(v,SVG.TeX.sub2*scale);
var t = SVG.TeX.rule_thickness * scale;
var h = (sub||presub).h, d = (sup||presup).d;
if (presub) {h = Math.max(h,presub.h)}
if (presup) {d = Math.max(d,presup.d)}
if ((u - d) - (h - v) < 3*t) {
v = 3*t - u + d + h; q = (4/5)*x_height - (u - d);
if (q > 0) {u += q; v -= q}
}
u = Math.max(u,min.superscriptshift); v = Math.max(v,min.subscriptshift);
if (sup) {svg.Add(sup,dx+base.w+s,u)}
if (presup) {svg.Add(presup,dx+delta-presup.w,u)}
if (sub) {svg.Add(sub,dx+base.w+s-delta,-v)}
if (presub) {svg.Add(presub,dx-presub.w,-v)}
}
}
svg.Clean();
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
var data = this.SVGdata;
data.dx = dx; data.s = s; data.u = u, data.v = v; data.delta = delta;
return svg;
},
SVGgetScripts: function (s) {
var sup, sub, BOX = [];
var i = 1, m = this.data.length, W = 0;
for (var k = 0; k < 4; k += 2) {
while (i < m && (this.data[i]||{}).type !== "mprescripts") {
var box = [null,null,null,null];
for (var j = k; j < k+2; j++) {
if (this.data[i] && this.data[i].type !== "none" && this.data[i].type !== "mprescripts") {
if (!BOX[j]) {BOX[j] = SVG.BBOX.G()}
box[j] = this.data[i].toSVG();
}
if ((this.data[i]||{}).type !== "mprescripts") i++;
}
var isPre = (k === 2);
if (isPre) W += Math.max((box[k]||{w:0}).w,(box[k+1]||{w:0}).w);
if (box[k]) BOX[k].Add(box[k].With({x:W-(isPre?box[k].w:0)}));
if (box[k+1]) BOX[k+1].Add(box[k+1].With({x:W-(isPre?box[k+1].w:0)}));
sub = BOX[k]||{w:0}; sup = BOX[k+1]||{w:0};
sub.w = sup.w = W = Math.max(sub.w,sup.w);
}
i++; W = 0;
}
for (j = 0; j < 4; j++) {if (BOX[j]) {BOX[j].w += s; BOX[j].Clean()}}
return BOX;
}
});
MathJax.Hub.Startup.signal.Post("SVG mmultiscripts Ready");
MathJax.Ajax.loadComplete(SVG.autoloadDir+"/mmultiscripts.js");
});
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/jax/output/SVG/autoload/annotation-xml.js
*
* Implements the SVG output for <annotation-xml> elements.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2013-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
MathJax.Hub.Register.StartupHook("SVG Jax Ready",function () {
var VERSION = "2.7.1";
var MML = MathJax.ElementJax.mml,
SVG = MathJax.OutputJax.SVG;
var BBOX = SVG.BBOX;
BBOX.FOREIGN = BBOX.Subclass({type: "foreignObject", removeable: false});
MML["annotation-xml"].Augment({
toSVG: function () {
var svg = this.SVG(); this.SVGhandleSpace(svg);
var encoding = this.Get("encoding");
for (var i = 0, m = this.data.length; i < m; i++)
{svg.Add(this.data[i].toSVG(encoding),svg.w,0)}
svg.Clean();
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
}
});
MML.xml.Augment({
toSVG: function (encoding) {
//
// Get size of xml content
//
var span = SVG.textSVG.parentNode;
SVG.mathDiv.style.width = "auto"; // Firefox returns offsetWidth = 0 without this
span.insertBefore(this.div,SVG.textSVG);
var w = this.div.offsetWidth, h = this.div.offsetHeight;
var strut = MathJax.HTML.addElement(this.div,"span",{
style:{display:"inline-block", overflow:"hidden", height:h+"px",
width:"1px", marginRight:"-1px"}
});
var d = this.div.offsetHeight - h; h -= d;
this.div.removeChild(strut);
span.removeChild(this.div); SVG.mathDiv.style.width = "";
//
// Create foreignObject element for the content
//
var scale = 1000/SVG.em;
var svg = BBOX.FOREIGN({
y:(-h)+"px", width:w+"px", height:(h+d)+"px",
transform:"scale("+scale+") matrix(1 0 0 -1 0 0)"
});
//
// Add the children to the foreignObject
//
for (var i = 0, m = this.data.length; i < m; i++)
{svg.element.appendChild(this.data[i].cloneNode(true))}
//
// Set the scale and finish up
//
svg.w = w*scale; svg.h = h*scale; svg.d = d*scale;
svg.r = svg.w; svg.l = 0;
svg.Clean();
this.SVGsaveData(svg);
return svg;
}
});
MathJax.Hub.Startup.signal.Post("SVG annotation-xml Ready");
MathJax.Ajax.loadComplete(SVG.autoloadDir+"/annotation-xml.js");
});
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/jax/output/SVG/autoload/maction.js
*
* Implements the SVG output for <maction> elements.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2011-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
MathJax.Hub.Register.StartupHook("SVG Jax Ready",function () {
var VERSION = "2.7.1";
var MML = MathJax.ElementJax.mml,
SVG = MathJax.OutputJax["SVG"];
var currentTip, hover, clear;
//
// Add configuration for tooltips
//
var CONFIG = SVG.config.tooltip = MathJax.Hub.Insert({
delayPost: 600, delayClear: 600,
offsetX: 10, offsetY: 5
},SVG.config.tooltip||{});
MML.maction.Augment({
SVGtooltip: MathJax.HTML.addElement(document.body,"div",{id:"MathJax_SVG_Tooltip"}),
toSVG: function (HW,D) {
this.SVGgetStyles();
var svg = this.SVG();
var selected = this.selected();
if (selected.type == "null") {this.SVGsaveData(svg);return svg;}
svg.Add(this.SVGdataStretched(this.Get("selection")-1,HW,D));
svg.removeable = false;
this.SVGhandleHitBox(svg);
this.SVGhandleSpace(svg);
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
},
SVGhandleHitBox: function (svg) {
var frame = SVG.Element("rect",
{width:svg.w, height:svg.h+svg.d, y:-svg.d, fill:"none", "pointer-events":"all"});
svg.element.insertBefore(frame,svg.element.firstChild);
var type = this.Get("actiontype");
if (this.SVGaction[type])
{this.SVGaction[type].call(this,svg,svg.element,this.Get("selection"))}
},
SVGstretchH: MML.mbase.prototype.SVGstretchH,
SVGstretchV: MML.mbase.prototype.SVGstretchV,
//
// Implementations for the various actions
//
SVGaction: {
toggle: function (svg,frame,selection) {
this.selection = selection;
SVG.Element(frame,{cursor:"pointer"});
frame.onclick = MathJax.Callback(["SVGclick",this]);
},
statusline: function (svg,frame,selection) {
frame.onmouseover = MathJax.Callback(["SVGsetStatus",this]),
frame.onmouseout = MathJax.Callback(["SVGclearStatus",this]);
frame.onmouseover.autoReset = frame.onmouseout.autoReset = true;
},
tooltip: function(svg,frame,selection) {
frame.onmouseover = MathJax.Callback(["SVGtooltipOver",this]),
frame.onmouseout = MathJax.Callback(["SVGtooltipOut",this]);
frame.onmouseover.autoReset = frame.onmouseout.autoReset = true;
}
},
//
// Handle a click on the maction element
// (remove the original rendering and rerender)
//
SVGclick: function (event) {
this.selection++;
if (this.selection > this.data.length) {this.selection = 1}
var math = this; while (math.type !== "math") {math = math.inherit}
var jax = MathJax.Hub.getJaxFor(math.inputID); //, hover = !!jax.hover;
jax.Update();
/*
* if (hover) {
* var span = document.getElementById(jax.inputID+"-Span");
* MathJax.Extension.MathEvents.Hover.Hover(jax,span);
* }
*/
return MathJax.Extension.MathEvents.Event.False(event);
},
//
// Set/Clear the window status message
//
SVGsetStatus: function (event) {
// FIXME: Do something better with non-token elements
this.messageID = MathJax.Message.Set
((this.data[1] && this.data[1].isToken) ?
this.data[1].data.join("") : this.data[1].toString());
},
SVGclearStatus: function (event) {
if (this.messageID) {MathJax.Message.Clear(this.messageID,0)}
delete this.messageID;
},
//
// Handle tooltips
//
SVGtooltipOver: function (event) {
if (!event) {event = window.event}
if (clear) {clearTimeout(clear); clear = null}
if (hover) {clearTimeout(hover)}
var x = event.pageX; var y = event.pageY;
if (x == null) {
x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
var callback = MathJax.Callback(["SVGtooltipPost",this,x+CONFIG.offsetX,y+CONFIG.offsetY])
hover = setTimeout(callback,CONFIG.delayPost);
},
SVGtooltipOut: function (event) {
if (hover) {clearTimeout(hover); hover = null}
if (clear) {clearTimeout(clear)}
var callback = MathJax.Callback(["SVGtooltipClear",this,80]);
clear = setTimeout(callback,CONFIG.delayClear);
},
SVGtooltipPost: function (x,y) {
hover = null; if (clear) {clearTimeout(clear); clear = null}
//
// Get the tip div and show it at the right location, then clear its contents
//
var tip = this.SVGtooltip;
tip.style.display = "block"; tip.style.opacity = "";
if (this === currentTip) return;
tip.style.left = x+"px"; tip.style.top = y+"px";
tip.innerHTML = ''; var span = MathJax.HTML.addElement(tip,"span");
//
// Get the sizes from the jax (FIXME: should calculate again?)
//
var math = this; while (math.type !== "math") {math = math.inherit}
var jax = MathJax.Hub.getJaxFor(math.inputID);
this.em = MML.mbase.prototype.em = jax.SVG.em; this.ex = jax.SVG.ex;
this.linebreakWidth = jax.SVG.lineWidth; this.cwidth = jax.SVG.cwidth;
//
// Make a new math element and temporarily move the tooltip to it
// Display the math containing the tip, but check for errors
// Then put the tip back into the maction element
//
var mml = this.data[1];
math = MML.math(mml);
try {math.toSVG(span,tip)} catch(err) {
this.SetData(1,mml); tip.style.display = "none";
if (!err.restart) {throw err}
MathJax.Callback.After(["SVGtooltipPost",this,x,y],err.restart);
return;
}
this.SetData(1,mml);
currentTip = this;
},
SVGtooltipClear: function (n) {
var tip = this.SVGtooltip;
if (n <= 0) {
tip.style.display = "none";
tip.style.opacity = "";
clear = null;
} else {
tip.style.opacity = n/100;
clear = setTimeout(MathJax.Callback(["SVGtooltipClear",this,n-20]),50);
}
}
});
MathJax.Hub.Startup.signal.Post("SVG maction Ready");
MathJax.Ajax.loadComplete(SVG.autoloadDir+"/maction.js");
});
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/jax/output/SVG/autoload/multiline.js
*
* Implements the SVG output for <mrow>'s that contain line breaks.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2011-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
MathJax.Hub.Register.StartupHook("SVG Jax Ready",function () {
var VERSION = "2.7.1";
var MML = MathJax.ElementJax.mml,
SVG = MathJax.OutputJax.SVG,
BBOX = SVG.BBOX;
//
// Penalties for the various line breaks
//
var PENALTY = {
newline: 0,
nobreak: 1000000,
goodbreak: [-200],
badbreak: [+200],
auto: [0],
toobig: 800,
nestfactor: 400,
spacefactor: -100,
spaceoffset: 2,
spacelimit: 1, // spaces larger than this get a penalty boost
fence: 500,
close: 500
};
var ENDVALUES = {linebreakstyle: "after"};
/**************************************************************************/
MML.mrow.Augment({
//
// Handle breaking an mrow into separate lines
//
SVGmultiline: function (svg) {
//
// Find the parent element and mark it as multiline
//
var parent = this;
while (parent.inferred || (parent.parent && parent.parent.type === "mrow" &&
parent.isEmbellished())) {parent = parent.parent}
var isTop = ((parent.type === "math" && parent.Get("display") === "block") ||
parent.type === "mtd");
parent.isMultiline = true;
//
// Default values for the line-breaking parameters
//
var VALUES = this.getValues(
"linebreak","linebreakstyle","lineleading","linebreakmultchar",
"indentalign","indentshift",
"indentalignfirst","indentshiftfirst",
"indentalignlast","indentshiftlast"
);
if (VALUES.linebreakstyle === MML.LINEBREAKSTYLE.INFIXLINEBREAKSTYLE)
{VALUES.linebreakstyle = this.Get("infixlinebreakstyle")}
VALUES.lineleading = SVG.length2em(VALUES.lineleading,1,0.5);
//
// Start with a fresh SVG element
// and make it full width if we are breaking to a specific width
// in the top-level math element
//
svg = this.SVG();
if (isTop && parent.type !== "mtd") {
if (SVG.linebreakWidth < SVG.BIGDIMEN) {svg.w = SVG.linebreakWidth}
else {svg.w = SVG.cwidth}
}
var state = {
n: 0, Y: 0,
scale: this.scale || 1,
isTop: isTop,
values: {},
VALUES: VALUES
},
align = this.SVGgetAlign(state,{}),
shift = this.SVGgetShift(state,{},align),
start = [],
end = {
index:[], penalty:PENALTY.nobreak,
w:0, W:shift, shift:shift, scanW:shift,
nest: 0
},
broken = false;
//
// Break the expression at its best line breaks
//
while (this.SVGbetterBreak(end,state) &&
(end.scanW >= SVG.linebreakWidth || end.penalty === PENALTY.newline)) {
this.SVGaddLine(svg,start,end.index,state,end.values,broken);
start = end.index.slice(0); broken = true;
align = this.SVGgetAlign(state,end.values);
shift = this.SVGgetShift(state,end.values,align);
if (align === MML.INDENTALIGN.CENTER) {shift = 0}
end.W = end.shift = end.scanW = shift; end.penalty = PENALTY.nobreak;
}
state.isLast = true;
this.SVGaddLine(svg,start,[],state,ENDVALUES,broken);
this.SVGhandleSpace(svg);
this.SVGhandleColor(svg);
svg.isMultiline = true;
this.SVGsaveData(svg);
return svg;
}
});
/**************************************************************************/
MML.mbase.Augment({
SVGlinebreakPenalty: PENALTY,
/****************************************************************/
//
// Locate the next linebreak that is better than the current one
//
SVGbetterBreak: function (info,state) {
if (this.isToken) {return false} // FIXME: handle breaking of token elements
if (this.isEmbellished()) {
info.embellished = this;
return this.CoreMO().SVGbetterBreak(info,state);
}
if (this.linebreakContainer) {return false}
//
// Get the current breakpoint position and other data
//
var index = info.index.slice(0), i = info.index.shift(),
m = this.data.length, W, w, scanW, broken = (info.index.length > 0), better = false;
if (i == null) {i = -1}; if (!broken) {i++; info.W += info.w; info.w = 0}
scanW = info.scanW = info.W; info.nest++;
//
// Look through the line for breakpoints,
// (as long as we are not too far past the breaking width)
//
while (i < m && info.scanW < 1.33*SVG.linebreakWidth) {
if (this.data[i]) {
if (this.data[i].SVGbetterBreak(info,state)) {
better = true; index = [i].concat(info.index); W = info.W; w = info.w;
if (info.penalty === PENALTY.newline) {
info.index = index;
if (info.nest) {info.nest--}
return true;
}
}
scanW = (broken ? info.scanW : this.SVGaddWidth(i,info,scanW));
}
info.index = []; i++; broken = false;
}
if (info.nest) {info.nest--}
info.index = index;
if (better) {info.W = W}
return better;
},
SVGaddWidth: function (i,info,scanW) {
if (this.data[i]) {
var svg = this.data[i].SVGdata;
scanW += svg.w + svg.x; if (svg.X) {scanW += svg.X}
info.W = info.scanW = scanW; info.w = 0;
}
return scanW;
},
/****************************************************************/
//
// Create a new line and move the required elements into it
// Position it using proper alignment and indenting
//
SVGaddLine: function (svg,start,end,state,values,broken) {
//
// Create a box for the line, with empty BBox
// fill it with the proper elements,
// and clean up the bbox
//
var line = BBOX();
state.first = broken; state.last = true;
this.SVGmoveLine(start,end,line,state,values);
line.Clean();
//
// Get the alignment and shift values
//
var align = this.SVGgetAlign(state,values),
shift = this.SVGgetShift(state,values,align);
//
// Set the Y offset based on previous depth, leading, and current height
//
if (state.n > 0) {
var LHD = SVG.FONTDATA.baselineskip * state.scale;
var leading = (state.values.lineleading == null ? state.VALUES : state.values).lineleading * state.scale;
state.Y -= Math.max(LHD,state.d + line.h + leading);
}
//
// Place the new line
//
if (line.w + shift > svg.w) svg.w = line.w + shift;
svg.Align(line,align,0,state.Y,shift);
//
// Save the values needed for the future
//
state.d = line.d; state.values = values; state.n++;
},
/****************************************************************/
//
// Get alignment and shift values from the given data
//
SVGgetAlign: function (state,values) {
var cur = values, prev = state.values, def = state.VALUES, align;
if (state.n === 0) {align = cur.indentalignfirst || prev.indentalignfirst || def.indentalignfirst}
else if (state.isLast) {align = prev.indentalignlast || def.indentalignlast}
else {align = prev.indentalign || def.indentalign}
if (align === MML.INDENTALIGN.INDENTALIGN) {align = prev.indentalign || def.indentalign}
if (align === MML.INDENTALIGN.AUTO) {align = (state.isTop ? this.displayAlign : MML.INDENTALIGN.LEFT)}
return align;
},
SVGgetShift: function (state,values,align) {
var cur = values, prev = state.values, def = state.VALUES, shift;
if (state.n === 0) {shift = cur.indentshiftfirst || prev.indentshiftfirst || def.indentshiftfirst}
else if (state.isLast) {shift = prev.indentshiftlast || def.indentshiftlast}
else {shift = prev.indentshift || def.indentshift}
if (shift === MML.INDENTSHIFT.INDENTSHIFT) {shift = prev.indentshift || def.indentshift}
if (shift === "auto" || shift === "") {shift = "0"}
shift = SVG.length2em(shift,1,SVG.cwidth);
if (state.isTop && this.displayIndent !== "0") {
var indent = SVG.length2em(this.displayIndent,1,SVG.cwidth);
shift += (align === MML.INDENTALIGN.RIGHT ? -indent: indent);
}
return shift;
},
/****************************************************************/
//
// Move the selected elements into the new line,
// moving whole items when possible, and parts of ones
// that are split by a line break.
//
SVGmoveLine: function (start,end,svg,state,values) {
var i = start[0], j = end[0];
if (i == null) {i = -1}; if (j == null) {j = this.data.length-1}
if (i === j && start.length > 1) {
//
// If starting and ending in the same element move the subpiece to the new line
//
this.data[i].SVGmoveSlice(start.slice(1),end.slice(1),svg,state,values,"paddingLeft");
} else {
//
// Otherwise, move the remainder of the initial item
// and any others up to the last one
//
var last = state.last; state.last = false;
while (i < j) {
if (this.data[i]) {
if (start.length <= 1) {this.data[i].SVGmove(svg,state,values)}
else {this.data[i].SVGmoveSlice(start.slice(1),[],svg,state,values,"paddingLeft")}
}
i++; state.first = false; start = [];
}
//
// If the last item is complete, move it,
// otherwise move the first part of it up to the split
//
state.last = last;
if (this.data[i]) {
if (end.length <= 1) {this.data[i].SVGmove(svg,state,values)}
else {this.data[i].SVGmoveSlice([],end.slice(1),svg,state,values,"paddingRight")}
}
}
},
/****************************************************************/
//
// Split an element and copy the selected items into the new part
//
SVGmoveSlice: function (start,end,svg,state,values,padding) {
//
// Create a new container for the slice of the element
// Move the selected portion into the slice
//
var slice = BBOX();
this.SVGmoveLine(start,end,slice,state,values);
slice.Clean();
if (this.href) {this.SVGaddHref(slice)}
this.SVGhandleColor(slice);
svg.Add(slice,svg.w,0,true);
return slice;
},
/****************************************************************/
//
// Move an element from its original position to its new location in
// a split element or the new line's position
//
SVGmove: function (line,state,values) {
// FIXME: handle linebreakstyle === "duplicate"
// FIXME: handle linebreakmultchar
if (!(state.first || state.last) ||
(state.first && state.values.linebreakstyle === MML.LINEBREAKSTYLE.BEFORE) ||
(state.last && values.linebreakstyle === MML.LINEBREAKSTYLE.AFTER)) {
//
// Recreate output
// Remove padding (if first, remove at leftt, if last remove at right)
// Add to line
//
var svg = this.toSVG(this.SVGdata.HW,this.SVGdata.D);
if (state.first || state.nextIsFirst) {svg.x = 0}
if (state.last && svg.X) {svg.X = 0}
line.Add(svg,line.w,0,true);
}
if (state.first && svg && svg.w === 0) {state.nextIsFirst = true}
else {delete state.nextIsFirst}
}
});
/**************************************************************************/
MML.mfenced.Augment({
SVGbetterBreak: function (info,state) {
//
// Get the current breakpoint position and other data
//
var index = info.index.slice(0), i = info.index.shift(),
m = this.data.length, W, w, scanW, broken = (info.index.length > 0), better = false;
if (i == null) {i = -1}; if (!broken) {i++; info.W += info.w; info.w = 0}
scanW = info.scanW = info.W; info.nest++;
//
// Create indices that include the delimiters and separators
//
if (!this.dataI) {
this.dataI = [];
if (this.data.open) {this.dataI.push("open")}
if (m) {this.dataI.push(0)}
for (var j = 1; j < m; j++) {
if (this.data["sep"+j]) {this.dataI.push("sep"+j)}
this.dataI.push(j);
}
if (this.data.close) {this.dataI.push("close")}
}
m = this.dataI.length;
//
// Look through the line for breakpoints, including the open, close, and separators
// (as long as we are not too far past the breaking width)
//
while (i < m && info.scanW < 1.33*SVG.linebreakWidth) {
var k = this.dataI[i];
if (this.data[k]) {
if (this.data[k].SVGbetterBreak(info,state)) {
better = true; index = [i].concat(info.index); W = info.W; w = info.w;
if (info.penalty === PENALTY.newline) {
info.index = index;
if (info.nest) {info.nest--}
return true;
}
}
scanW = (broken ? info.scanW : this.SVGaddWidth(i,info,scanW));
}
info.index = []; i++; broken = false;
}
if (info.nest) {info.nest--}
info.index = index;
if (better) {info.W = W; info.w = w}
return better;
},
SVGmoveLine: function (start,end,svg,state,values) {
var i = start[0], j = end[0];
if (i == null) {i = -1}; if (j == null) {j = this.dataI.length-1}
if (i === j && start.length > 1) {
//
// If starting and ending in the same element move the subpiece to the new line
//
this.data[this.dataI[i]].SVGmoveSlice(start.slice(1),end.slice(1),svg,state,values,"paddingLeft");
} else {
//
// Otherwise, move the remainder of the initial item
// and any others (including open and separators) up to the last one
//
var last = state.last; state.last = false; var k = this.dataI[i];
while (i < j) {
if (this.data[k]) {
if (start.length <= 1) {this.data[k].SVGmove(svg,state,values)}
else {this.data[k].SVGmoveSlice(start.slice(1),[],svg,state,values,"paddingLeft")}
}
i++; k = this.dataI[i]; state.first = false; start = [];
}
//
// If the last item is complete, move it
//
state.last = last;
if (this.data[k]) {
if (end.length <= 1) {this.data[k].SVGmove(svg,state,values)}
else {this.data[k].SVGmoveSlice([],end.slice(1),svg,state,values,"paddingRight")}
}
}
}
});
/**************************************************************************/
MML.msubsup.Augment({
SVGbetterBreak: function (info,state) {
if (!this.data[this.base]) {return false}
//
// Get the current breakpoint position and other data
//
var index = info.index.slice(0), i = info.index.shift(),
W, w, scanW, broken = (info.index.length > 0), better = false;
if (!broken) {info.W += info.w; info.w = 0}
scanW = info.scanW = info.W;
//
// Record the width of the base and the super- and subscripts
//
if (i == null) {this.SVGdata.dw = this.SVGdata.w - this.data[this.base].SVGdata.w}
//
// Check if the base can be broken
//
if (this.data[this.base].SVGbetterBreak(info,state)) {
better = true; index = [this.base].concat(info.index); W = info.W; w = info.w;
if (info.penalty === PENALTY.newline) {better = broken = true}
}
//
// Add in the base if it is unbroken, and add the scripts
//
if (!broken) {this.SVGaddWidth(this.base,info,scanW)}
info.scanW += this.SVGdata.dw; info.W = info.scanW;
info.index = []; if (better) {info.W = W; info.w = w; info.index = index}
return better;
},
SVGmoveLine: function (start,end,svg,state,values) {
//
// Move the proper part of the base
//
if (this.data[this.base]) {
if (start.length > 1) {
this.data[this.base].SVGmoveSlice(start.slice(1),end.slice(1),svg,state,values,"paddingLeft");
} else {
if (end.length <= 1) {this.data[this.base].SVGmove(svg,state,values)}
else {this.data[this.base].SVGmoveSlice([],end.slice(1),svg,state,values,"paddingRight")}
}
}
//
// If this is the end, check for super and subscripts, and move those
// by moving the stack that contains them, and shifting by the amount of the
// base that has been removed. Remove the empty base box from the stack.
//
if (end.length === 0) {
var sup = this.data[this.sup], sub = this.data[this.sub], w = svg.w, data;
if (sup) {data = sup.SVGdata||{}; svg.Add(sup.toSVG(),w+(data.dx||0),data.dy)}
if (sub) {data = sub.SVGdata||{}; svg.Add(sub.toSVG(),w+(data.dx||0),data.dy)}
}
}
});
/**************************************************************************/
MML.mmultiscripts.Augment({
SVGbetterBreak: function (info,state) {
if (!this.data[this.base]) {return false}
//
// Get the current breakpoint position and other data
//
var index = info.index.slice(0); info.index.shift();
var W, w, scanW, broken = (info.index.length > 0), better = false;
if (!broken) {info.W += info.w; info.w = 0}
info.scanW = info.W;
//
// The width of the postscripts
//
var dw = this.SVGdata.w - this.data[this.base].SVGdata.w - this.SVGdata.dx;
//
// Add in the prescripts
//
info.scanW += this.SVGdata.dx; scanW = info.scanW;
//
// Check if the base can be broken (but don't break between prescripts and base)
//
if (this.data[this.base].SVGbetterBreak(info,state)) {
better = true; index = [this.base].concat(info.index); W = info.W; w = info.w;
if (info.penalty === PENALTY.newline) {better = broken = true}
}
//
// Add in the base if it is unbroken, and add the postscripts
//
if (!broken) {this.SVGaddWidth(this.base,info,scanW)}
info.scanW += dw; info.W = info.scanW;
info.index = []; if (better) {info.W = W; info.w = w; info.index = index}
return better;
},
SVGmoveLine: function (start,end,svg,state,values) {
var dx, data = this.SVGdata;
//
// If this is the start, move the prescripts, if any.
//
if (start.length < 1) {
this.scriptBox = this.SVGgetScripts(this.SVGdata.s);
var presub = this.scriptBox[2], presup = this.scriptBox[3]; dx = svg.w + data.dx;
if (presup) {svg.Add(presup,dx+data.delta-presup.w,data.u)}
if (presub) {svg.Add(presub,dx-presub.w,-data.v)}
}
//
// Move the proper part of the base
//
if (this.data[this.base]) {
if (start.length > 1) {
this.data[this.base].SVGmoveSlice(start.slice(1),end.slice(1),svg,state,values,"paddingLeft");
} else {
if (end.length <= 1) {this.data[this.base].SVGmove(svg,state,values)}
else {this.data[this.base].SVGmoveSlice([],end.slice(1),svg,state,values,"paddingRight")}
}
}
//
// If this is the end, move the postscripts, if any.
//
if (end.length === 0) {
var sub = this.scriptBox[0], sup = this.scriptBox[1]; dx = svg.w + data.s;
if (sup) {svg.Add(sup,dx,data.u)}
if (sub) {svg.Add(sub,dx-data.delta,-data.v)}
delete this.scriptBox;
}
}
});
/**************************************************************************/
MML.mo.Augment({
//
// Override the method for checking line breaks to properly handle <mo>
//
SVGbetterBreak: function (info,state) {
if (info.values && info.values.last === this) {return false}
var values = this.getValues(
"linebreak","linebreakstyle","lineleading","linebreakmultchar",
"indentalign","indentshift",
"indentalignfirst","indentshiftfirst",
"indentalignlast","indentshiftlast",
"texClass", "fence"
);
if (values.linebreakstyle === MML.LINEBREAKSTYLE.INFIXLINEBREAKSTYLE)
{values.linebreakstyle = this.Get("infixlinebreakstyle")}
//
// Adjust nesting by TeX class (helps output that does not include
// mrows for nesting, but can leave these unbalanced.
//
if (values.texClass === MML.TEXCLASS.OPEN) {info.nest++}
if (values.texClass === MML.TEXCLASS.CLOSE && info.nest) {info.nest--}
//
// Get the default penalty for this location
//
var W = info.scanW, mo = info.embellished; delete info.embellished;
if (!mo || !mo.SVGdata) {mo = this}
var svg = mo.SVGdata, w = svg.w + svg.x;
if (values.linebreakstyle === MML.LINEBREAKSTYLE.AFTER) {W += w; w = 0}
if (W - info.shift === 0 && values.linebreak !== MML.LINEBREAK.NEWLINE)
{return false} // don't break at zero width (FIXME?)
var offset = SVG.linebreakWidth - W;
// adjust offest for explicit first-line indent and align
if (state.n === 0 && (values.indentshiftfirst !== state.VALUES.indentshiftfirst ||
values.indentalignfirst !== state.VALUES.indentalignfirst)) {
var align = this.SVGgetAlign(state,values),
shift = this.SVGgetShift(state,values,align);
offset += (info.shift - shift);
}
//
var penalty = Math.floor(offset / SVG.linebreakWidth * 1000);
if (penalty < 0) {penalty = PENALTY.toobig - 3*penalty}
if (values.fence) {penalty += PENALTY.fence}
if ((values.linebreakstyle === MML.LINEBREAKSTYLE.AFTER &&
values.texClass === MML.TEXCLASS.OPEN) ||
values.texClass === MML.TEXCLASS.CLOSE) {penalty += PENALTY.close}
penalty += info.nest * PENALTY.nestfactor;
//
// Get the penalty for this type of break and
// use it to modify the default penalty
//
var linebreak = PENALTY[values.linebreak||MML.LINEBREAK.AUTO];
if (!MathJax.Object.isArray(linebreak)) {
// for breaks past the width, don't modify penalty
if (offset >= 0) {penalty = linebreak * info.nest}
} else {penalty = Math.max(1,penalty + linebreak[0] * info.nest)}
//
// If the penalty is no better than the current one, return false
// Otherwise save the data for this breakpoint and return true
//
if (penalty >= info.penalty) {return false}
info.penalty = penalty; info.values = values; info.W = W; info.w = w;
values.lineleading = SVG.length2em(values.lineleading,1,state.VALUES.lineleading);
values.last = this;
return true;
}
});
/**************************************************************************/
MML.mspace.Augment({
//
// Override the method for checking line breaks to properly handle <mspace>
//
SVGbetterBreak: function (info,state) {
if (info.values && info.values.last === this) {return false}
var values = this.getValues("linebreak");
var linebreakValue = values.linebreak;
if (!linebreakValue || this.hasDimAttr()) {
// The MathML spec says that the linebreak attribute should be ignored
// if any dimensional attribute is set.
linebreakValue = MML.LINEBREAK.AUTO;
}
//
// Get the default penalty for this location
//
var W = info.scanW, svg = this.SVGdata, w = svg.w + svg.x;
if (W - info.shift === 0) {return false} // don't break at zero width (FIXME?)
var offset = SVG.linebreakWidth - W;
//
var penalty = Math.floor(offset / SVG.linebreakWidth * 1000);
if (penalty < 0) {penalty = PENALTY.toobig - 3*penalty}
penalty += info.nest * PENALTY.nestfactor;
//
// Get the penalty for this type of break and
// use it to modify the default penalty
//
var linebreak = PENALTY[linebreakValue];
if (linebreakValue === MML.LINEBREAK.AUTO && w >= PENALTY.spacelimit*1000 &&
!this.mathbackground && !this.backrgound)
{linebreak = [(w/1000+PENALTY.spaceoffset)*PENALTY.spacefactor]}
if (!MathJax.Object.isArray(linebreak)) {
// for breaks past the width, don't modify penalty
if (offset >= 0) {penalty = linebreak * info.nest}
} else {penalty = Math.max(1,penalty + linebreak[0] * info.nest)}
//
// If the penalty is no better than the current one, return false
// Otherwise save the data for this breakpoint and return true
//
if (penalty >= info.penalty) {return false}
info.penalty = penalty; info.values = values; info.W = W; info.w = w;
values.lineleading = state.VALUES.lineleading;
values.linebreakstyle = "before"; values.last = this;
return true;
}
});
//
// Hook into the mathchoice extension
//
MathJax.Hub.Register.StartupHook("TeX mathchoice Ready",function () {
MML.TeXmathchoice.Augment({
SVGbetterBreak: function (info,state) {
return this.Core().SVGbetterBreak(info,state);
},
SVGmoveLine: function (start,end,svg,state,values) {
return this.Core().SVGmoveSlice(start,end,svg,state,values);
}
});
});
//
// Have maction process only the selected item
//
MML.maction.Augment({
SVGbetterBreak: function (info,state) {
return this.Core().SVGbetterBreak(info,state);
},
SVGmoveLine: function (start,end,svg,state,values) {
return this.Core().SVGmoveSlice(start,end,svg,state,values);
},
});
//
// Have semantics only do the first element
// (FIXME: do we need to do anything special about annotation-xml?)
//
MML.semantics.Augment({
SVGbetterBreak: function (info,state) {
return (this.data[0] ? this.data[0].SVGbetterBreak(info,state) : false);
},
SVGmoveLine: function (start,end,svg,state,values) {
return (this.data[0] ? this.data[0].SVGmoveSlice(start,end,svg,state,values) : null);
}
});
/**************************************************************************/
MathJax.Hub.Startup.signal.Post("SVG multiline Ready");
MathJax.Ajax.loadComplete(SVG.autoloadDir+"/multiline.js");
});
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/jax/output/SVG/autoload/menclose.js
*
* Implements the SVG output for <menclose> elements.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2011-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
MathJax.Hub.Register.StartupHook("SVG Jax Ready",function () {
var VERSION = "2.7.1";
var MML = MathJax.ElementJax.mml,
SVG = MathJax.OutputJax.SVG,
BBOX = SVG.BBOX;
BBOX.ELLIPSE = BBOX.Subclass({
type: "ellipse", removeable: false,
Init: function (h,d,w,t,color,def) {
if (def == null) {def = {}}; def.fill = "none";
if (color) {def.stroke = color}
def["stroke-width"] = t.toFixed(2).replace(/\.?0+$/,"");
def.cx = Math.floor(w/2); def.cy = Math.floor((h+d)/2-d);
def.rx = Math.floor((w-t)/2); def.ry = Math.floor((h+d-t)/2);
this.SUPER(arguments).Init.call(this,def);
this.w = this.r = w; this.h = this.H = h;
this.d = this.D = d; this.l = 0;
}
});
BBOX.DLINE = BBOX.Subclass({
type: "line", removeable: false,
Init: function (h,d,w,t,color,updown,def) {
if (def == null) {def = {}}; def.fill = "none";
if (color) {def.stroke = color}
def["stroke-width"] = t.toFixed(2).replace(/\.?0+$/,"");
if (updown == "up") {
def.x1 = Math.floor(t/2); def.y1 = Math.floor(t/2-d);
def.x2 = Math.floor(w-t/2); def.y2 = Math.floor(h-t/2);
} else {
def.x1 = Math.floor(t/2); def.y1 = Math.floor(h-t/2);
def.x2 = Math.floor(w-t/2); def.y2 = Math.floor(t/2-d);
}
this.SUPER(arguments).Init.call(this,def);
this.w = this.r = w; this.h = this.H = h;
this.d = this.D = d; this.l = 0;
}
});
BBOX.FPOLY = BBOX.Subclass({
type: "polygon", removeable: false,
Init: function (points,color,def) {
if (def == null) {def = {}}
if (color) {def.fill = color}
var P = [], mx = 100000000, my = mx, Mx = -mx, My = Mx;
for (var i = 0, m = points.length; i < m; i++) {
var x = points[i][0], y = points[i][1];
if (x > Mx) {Mx = x}; if (x < mx) {mx = x}
if (y > My) {My = y}; if (y < my) {my = y}
P.push(Math.floor(x)+","+Math.floor(y));
}
def.points = P.join(" ");
this.SUPER(arguments).Init.call(this,def);
this.w = this.r = Mx; this.h = this.H = My;
this.d = this.D = -my; this.l = -mx;
}
});
BBOX.PPATH = BBOX.Subclass({
type: "path", removeable: false,
Init: function (h,d,w,p,t,color,def) {
if (def == null) {def = {}}; def.fill = "none";
if (color) {def.stroke = color}
def["stroke-width"] = t.toFixed(2).replace(/\.?0+$/,"");
def.d = p;
this.SUPER(arguments).Init.call(this,def);
this.w = this.r = w; this.h = this.H = h+d;
this.d = this.D = this.l = 0; this.y = -d;
}
});
MML.menclose.Augment({
toSVG: function (HW,DD) {
this.SVGgetStyles();
var svg = this.SVG(), scale = this.SVGgetScale(svg);
this.SVGhandleSpace(svg);
var base = this.SVGdataStretched(0,HW,DD);
var values = this.getValues("notation","thickness","padding","mathcolor","color");
if (values.color && !this.mathcolor) {values.mathcolor = values.color}
if (values.thickness == null) {values.thickness = ".075em"}
if (values.padding == null) {values.padding = ".2em"}
var mu = this.SVGgetMu(svg);
var p = SVG.length2em(values.padding,mu,1/SVG.em) * scale; // padding for enclosure
var t = SVG.length2em(values.thickness,mu,1/SVG.em); // thickness of lines
t = Math.max(1/SVG.em,t); // see issue #414
var H = base.h+p+t, D = base.d+p+t, W = base.w+2*(p+t);
var dx = 0, w, h, i, m, borders = [false,false,false,false];
// perform some reductio
@codehz
Copy link
Author

codehz commented Jun 25, 2017

配合AdBlock(或者类似拦截插件)拦截www.zhihu.com/equation请求较为合适(因为用脚本隐藏还是会进行网络请求。。。所以干脆不隐藏了)(修改自https://zhuanlan.zhihu.com/p/27551432,感谢@梨梨喵和@帅气可爱魔理沙,假装可以艾特到)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment