PageRenderTime 36ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/talk2/mathjax/unpacked/MathJax.js

https://github.com/williamstein/mazur-explicit-formula
JavaScript | 2476 lines | 1858 code | 157 blank | 461 comment | 647 complexity | 093677426d7b68ea8b36f82d8059b064 MD5 | raw file
Possible License(s): Apache-2.0, GPL-2.0, MIT
  1. /*************************************************************
  2. *
  3. * MathJax.js
  4. *
  5. * The main support code for the MathJax Hub, including the
  6. * Ajax, Callback, Messaging, and Object-Oriented Programming
  7. * libraries, as well as the base Jax classes, and startup
  8. * processing code.
  9. *
  10. * ---------------------------------------------------------------------
  11. *
  12. * Copyright (c) 2009-2012 Design Science, Inc.
  13. *
  14. * Licensed under the Apache License, Version 2.0 (the "License");
  15. * you may not use this file except in compliance with the License.
  16. * You may obtain a copy of the License at
  17. *
  18. * http://www.apache.org/licenses/LICENSE-2.0
  19. *
  20. * Unless required by applicable law or agreed to in writing, software
  21. * distributed under the License is distributed on an "AS IS" BASIS,
  22. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  23. * See the License for the specific language governing permissions and
  24. * limitations under the License.
  25. */
  26. if (document.getElementById && document.childNodes && document.createElement) {
  27. if (!window.MathJax) {window.MathJax= {}}
  28. if (!MathJax.Hub) { // skip if already loaded
  29. MathJax.version = "2.1";
  30. MathJax.fileversion = "2.1";
  31. /**********************************************************/
  32. (function (BASENAME) {
  33. var BASE = window[BASENAME];
  34. if (!BASE) {BASE = window[BASENAME] = {}}
  35. var PROTO = []; // a static object used to indicate when a prototype is being created
  36. var OBJECT = function (def) {
  37. var obj = def.constructor; if (!obj) {obj = new Function("")}
  38. for (var id in def) {if (id !== 'constructor' && def.hasOwnProperty(id)) {obj[id] = def[id]}}
  39. return obj;
  40. };
  41. var CONSTRUCTOR = function () {
  42. return new Function ("return arguments.callee.Init.call(this,arguments)");
  43. };
  44. //
  45. // Test for Safari 2.x bug (can't replace prototype for result of new Function()).
  46. // (We don't use this version for everyone since it is a closure and we don't need that).
  47. //
  48. var BUGTEST = CONSTRUCTOR(); BUGTEST.prototype = {bug_test: 1};
  49. if (!BUGTEST.prototype.bug_test) {
  50. CONSTRUCTOR = function () {
  51. return function () {return arguments.callee.Init.call(this,arguments)};
  52. };
  53. };
  54. BASE.Object = OBJECT({
  55. constructor: CONSTRUCTOR(),
  56. Subclass: function (def,classdef) {
  57. var obj = CONSTRUCTOR();
  58. obj.SUPER = this; obj.Init = this.Init;
  59. obj.Subclass = this.Subclass; obj.Augment = this.Augment;
  60. obj.protoFunction = this.protoFunction;
  61. obj.can = this.can; obj.has = this.has; obj.isa = this.isa;
  62. obj.prototype = new this(PROTO);
  63. obj.prototype.constructor = obj; // the real constructor
  64. obj.Augment(def,classdef);
  65. return obj;
  66. },
  67. Init: function (args) {
  68. var obj = this;
  69. if (args.length === 1 && args[0] === PROTO) {return obj}
  70. if (!(obj instanceof args.callee)) {obj = new args.callee(PROTO)}
  71. return obj.Init.apply(obj,args) || obj;
  72. },
  73. Augment: function (def,classdef) {
  74. var id;
  75. if (def != null) {
  76. for (id in def) {if (def.hasOwnProperty(id)) {this.protoFunction(id,def[id])}}
  77. // MSIE doesn't list toString even if it is not native so handle it separately
  78. if (def.toString !== this.prototype.toString && def.toString !== {}.toString)
  79. {this.protoFunction('toString',def.toString)}
  80. }
  81. if (classdef != null) {
  82. for (id in classdef) {if (classdef.hasOwnProperty(id)) {this[id] = classdef[id]}}
  83. }
  84. return this;
  85. },
  86. protoFunction: function (id,def) {
  87. this.prototype[id] = def;
  88. if (typeof def === "function") {def.SUPER = this.SUPER.prototype}
  89. },
  90. prototype: {
  91. Init: function () {},
  92. SUPER: function (fn) {return fn.callee.SUPER},
  93. can: function (method) {return typeof(this[method]) === "function"},
  94. has: function (property) {return typeof(this[property]) !== "undefined"},
  95. isa: function (obj) {return (obj instanceof Object) && (this instanceof obj)}
  96. },
  97. can: function (method) {return this.prototype.can.call(this,method)},
  98. has: function (property) {return this.prototype.has.call(this,property)},
  99. isa: function (obj) {
  100. var constructor = this;
  101. while (constructor) {
  102. if (constructor === obj) {return true} else {constructor = constructor.SUPER}
  103. }
  104. return false;
  105. },
  106. SimpleSUPER: OBJECT({
  107. constructor: function (def) {return this.SimpleSUPER.define(def)},
  108. define: function (src) {
  109. var dst = {};
  110. if (src != null) {
  111. for (var id in src) {if (src.hasOwnProperty(id)) {dst[id] = this.wrap(id,src[id])}}
  112. // MSIE doesn't list toString even if it is not native so handle it separately
  113. if (src.toString !== this.prototype.toString && src.toString !== {}.toString)
  114. {dst.toString = this.wrap('toString',src.toString)}
  115. }
  116. return dst;
  117. },
  118. wrap: function (id,f) {
  119. if (typeof(f) === 'function' && f.toString().match(/\.\s*SUPER\s*\(/)) {
  120. var fn = new Function(this.wrapper);
  121. fn.label = id; fn.original = f; f = fn;
  122. fn.toString = this.stringify;
  123. }
  124. return f;
  125. },
  126. wrapper: function () {
  127. var fn = arguments.callee;
  128. this.SUPER = fn.SUPER[fn.label];
  129. try {var result = fn.original.apply(this,arguments)}
  130. catch (err) {delete this.SUPER; throw err}
  131. delete this.SUPER;
  132. return result;
  133. }.toString().replace(/^\s*function\s*\(\)\s*\{\s*/i,"").replace(/\s*\}\s*$/i,""),
  134. toString: function () {
  135. return this.original.toString.apply(this.original,arguments);
  136. }
  137. })
  138. });
  139. })("MathJax");
  140. /**********************************************************/
  141. /*
  142. * Create a callback function from various forms of data:
  143. *
  144. * MathJax.Callback(fn) -- callback to a function
  145. *
  146. * MathJax.Callback([fn]) -- callback to function
  147. * MathJax.Callback([fn,data...])
  148. * -- callback to function with given data as arguments
  149. * MathJax.Callback([object,fn])
  150. * -- call fn with object as "this"
  151. * MathJax.Callback([object,fn,data...])
  152. * -- call fn with object as "this" and data as arguments
  153. * MathJax.Callback(["method",object])
  154. * -- call method of object wth object as "this"
  155. * MathJax.Callback(["method",object,data...])
  156. * -- as above, but with data as arguments to method
  157. *
  158. * MathJax.Callback({hook: fn, data: [...], object: this})
  159. * -- give function, data, and object to act as "this" explicitly
  160. *
  161. * MathJax.Callback("code") -- callback that compiles and executes a string
  162. *
  163. * MathJax.Callback([...],i)
  164. * -- use slice of array starting at i and interpret
  165. * result as above. (Used for passing "arguments" array
  166. * and trimming initial arguments, if any.)
  167. */
  168. /*
  169. * MathJax.Callback.After([...],cb1,cb2,...)
  170. * -- make a callback that isn't called until all the other
  171. * ones are called first. I.e., wait for a union of
  172. * callbacks to occur before making the given callback.
  173. */
  174. /*
  175. * MathJax.Callback.Queue([callback,...])
  176. * -- make a synchronized queue of commands that process
  177. * sequentially, waiting for those that return uncalled
  178. * callbacks.
  179. */
  180. /*
  181. * MathJax.Callback.Signal(name)
  182. * -- finds or creates a names signal, to which listeners
  183. * can be attached and are signaled by messages posted
  184. * to the signal. Responses can be asynchronous.
  185. */
  186. (function (BASENAME) {
  187. var BASE = window[BASENAME];
  188. if (!BASE) {BASE = window[BASENAME] = {}}
  189. //
  190. // Create a callback from an associative array
  191. //
  192. var CALLBACK = function (data) {
  193. var cb = new Function("return arguments.callee.execute.apply(arguments.callee,arguments)");
  194. for (var id in CALLBACK.prototype) {
  195. if (CALLBACK.prototype.hasOwnProperty(id)) {
  196. if (typeof(data[id]) !== 'undefined') {cb[id] = data[id]}
  197. else {cb[id] = CALLBACK.prototype[id]}
  198. }
  199. }
  200. cb.toString = CALLBACK.prototype.toString;
  201. return cb;
  202. };
  203. CALLBACK.prototype = {
  204. isCallback: true,
  205. hook: function () {},
  206. data: [],
  207. object: window,
  208. execute: function () {
  209. if (!this.called || this.autoReset) {
  210. this.called = !this.autoReset;
  211. return this.hook.apply(this.object,this.data.concat([].slice.call(arguments,0)));
  212. }
  213. },
  214. reset: function () {delete this.called},
  215. toString: function () {return this.hook.toString.apply(this.hook,arguments)}
  216. };
  217. var ISCALLBACK = function (f) {
  218. return (typeof(f) === "function" && f.isCallback);
  219. }
  220. //
  221. // Evaluate a string in global context
  222. //
  223. var EVAL = function (code) {return eval.call(window,code)}
  224. EVAL("var __TeSt_VaR__ = 1"); // check if it works in global context
  225. if (window.__TeSt_VaR__) {
  226. try { delete window.__TeSt_VaR__; } // NOTE IE9 throws when in IE7 mode
  227. catch (error) { window.__TeSt_VaR__ = null; }
  228. } else {
  229. if (window.execScript) {
  230. // IE
  231. EVAL = function (code) {
  232. BASE.__code = code;
  233. code = "try {"+BASENAME+".__result = eval("+BASENAME+".__code)} catch(err) {"+BASENAME+".__result = err}";
  234. window.execScript(code);
  235. var result = BASE.__result; delete BASE.__result; delete BASE.__code;
  236. if (result instanceof Error) {throw result}
  237. return result;
  238. }
  239. } else {
  240. // Safari2
  241. EVAL = function (code) {
  242. BASE.__code = code;
  243. code = "try {"+BASENAME+".__result = eval("+BASENAME+".__code)} catch(err) {"+BASENAME+".__result = err}";
  244. var head = (document.getElementsByTagName("head"))[0]; if (!head) {head = document.body}
  245. var script = document.createElement("script");
  246. script.appendChild(document.createTextNode(code));
  247. head.appendChild(script); head.removeChild(script);
  248. var result = BASE.__result; delete BASE.__result; delete BASE.__code;
  249. if (result instanceof Error) {throw result}
  250. return result;
  251. }
  252. }
  253. }
  254. //
  255. // Create a callback from various types of data
  256. //
  257. var USING = function (args,i) {
  258. if (arguments.length > 1) {
  259. if (arguments.length === 2 && !(typeof arguments[0] === 'function') &&
  260. arguments[0] instanceof Object && typeof arguments[1] === 'number')
  261. {args = [].slice.call(args,i)}
  262. else {args = [].slice.call(arguments,0)}
  263. }
  264. if (args instanceof Array && args.length === 1) {args = args[0]}
  265. if (typeof args === 'function') {
  266. if (args.execute === CALLBACK.prototype.execute) {return args}
  267. return CALLBACK({hook: args});
  268. } else if (args instanceof Array) {
  269. if (typeof(args[0]) === 'string' && args[1] instanceof Object &&
  270. typeof args[1][args[0]] === 'function') {
  271. return CALLBACK({hook: args[1][args[0]], object: args[1], data: args.slice(2)});
  272. } else if (typeof args[0] === 'function') {
  273. return CALLBACK({hook: args[0], data: args.slice(1)});
  274. } else if (typeof args[1] === 'function') {
  275. return CALLBACK({hook: args[1], object: args[0], data: args.slice(2)});
  276. }
  277. } else if (typeof(args) === 'string') {
  278. return CALLBACK({hook: EVAL, data: [args]});
  279. } else if (args instanceof Object) {
  280. return CALLBACK(args);
  281. } else if (typeof(args) === 'undefined') {
  282. return CALLBACK({});
  283. }
  284. throw Error("Can't make callback from given data");
  285. };
  286. //
  287. // Wait for a given time to elapse and then perform the callback
  288. //
  289. var DELAY = function (time,callback) {
  290. callback = USING(callback);
  291. callback.timeout = setTimeout(callback,time);
  292. return callback;
  293. };
  294. //
  295. // Callback used by AFTER, QUEUE, and SIGNAL to check if calls have completed
  296. //
  297. var WAITFOR = function (callback,signal) {
  298. callback = USING(callback);
  299. if (!callback.called) {WAITSIGNAL(callback,signal); signal.pending++}
  300. };
  301. var WAITEXECUTE = function () {
  302. var signals = this.signal; delete this.signal;
  303. this.execute = this.oldExecute; delete this.oldExecute;
  304. var result = this.execute.apply(this,arguments);
  305. if (ISCALLBACK(result) && !result.called) {WAITSIGNAL(result,signals)} else {
  306. for (var i = 0, m = signals.length; i < m; i++) {
  307. signals[i].pending--;
  308. if (signals[i].pending <= 0) {signals[i].call()}
  309. }
  310. }
  311. };
  312. var WAITSIGNAL = function (callback,signals) {
  313. if (!(signals instanceof Array)) {signals = [signals]}
  314. if (!callback.signal) {
  315. callback.oldExecute = callback.execute;
  316. callback.execute = WAITEXECUTE;
  317. callback.signal = signals;
  318. } else if (signals.length === 1) {callback.signal.push(signals[0])}
  319. else {callback.signal = callback.signal.concat(signals)}
  320. };
  321. //
  322. // Create a callback that is called when a collection of other callbacks have
  323. // all been executed. If the callback gets called immediately (i.e., the
  324. // others are all already called), check if it returns another callback
  325. // and return that instead.
  326. //
  327. var AFTER = function (callback) {
  328. callback = USING(callback);
  329. callback.pending = 0;
  330. for (var i = 1, m = arguments.length; i < m; i++)
  331. {if (arguments[i]) {WAITFOR(arguments[i],callback)}}
  332. if (callback.pending === 0) {
  333. var result = callback();
  334. if (ISCALLBACK(result)) {callback = result}
  335. }
  336. return callback;
  337. };
  338. //
  339. // An array of prioritized hooks that are executed sequentially
  340. // with a given set of data.
  341. //
  342. var HOOKS = MathJax.Object.Subclass({
  343. //
  344. // Initialize the array and the auto-reset status
  345. //
  346. Init: function (reset) {
  347. this.hooks = [];
  348. this.reset = reset;
  349. },
  350. //
  351. // Add a callback to the list, in priority order (default priority is 10)
  352. //
  353. Add: function (hook,priority) {
  354. if (priority == null) {priority = 10}
  355. if (!ISCALLBACK(hook)) {hook = USING(hook)}
  356. hook.priority = priority;
  357. var i = this.hooks.length;
  358. while (i > 0 && priority < this.hooks[i-1].priority) {i--}
  359. this.hooks.splice(i,0,hook);
  360. return hook;
  361. },
  362. Remove: function (hook) {
  363. for (var i = 0, m = this.hooks.length; i < m; i++) {
  364. if (this.hooks[i] === hook) {this.hooks.splice(i,1); return}
  365. }
  366. },
  367. //
  368. // Execute the list of callbacks, resetting them if requested.
  369. // If any return callbacks, return a callback that will be
  370. // executed when they all have completed.
  371. //
  372. Execute: function () {
  373. var callbacks = [{}];
  374. for (var i = 0, m = this.hooks.length; i < m; i++) {
  375. if (this.reset) {this.hooks[i].reset()}
  376. var result = this.hooks[i].apply(window,arguments);
  377. if (ISCALLBACK(result) && !result.called) {callbacks.push(result)}
  378. }
  379. if (callbacks.length === 1) {return null}
  380. if (callbacks.length === 2) {return callbacks[1]}
  381. return AFTER.apply({},callbacks);
  382. }
  383. });
  384. //
  385. // Run an array of callbacks passing them the given data.
  386. // (Legacy function, since this has been replaced by the HOOKS object).
  387. //
  388. var EXECUTEHOOKS = function (hooks,data,reset) {
  389. if (!hooks) {return null}
  390. if (!(hooks instanceof Array)) {hooks = [hooks]}
  391. if (!(data instanceof Array)) {data = (data == null ? [] : [data])}
  392. var handler = HOOKS(reset);
  393. for (var i = 0, m = hooks.length; i < m; i++) {handler.Add(hooks[i])}
  394. return handler.Execute.apply(handler,data);
  395. };
  396. //
  397. // Command queue that performs commands in order, waiting when
  398. // necessary for commands to complete asynchronousely
  399. //
  400. var QUEUE = BASE.Object.Subclass({
  401. //
  402. // Create the queue and push any commands that are specified
  403. //
  404. Init: function () {
  405. this.pending = 0; this.running = 0;
  406. this.queue = [];
  407. this.Push.apply(this,arguments);
  408. },
  409. //
  410. // Add commands to the queue and run them. Adding a callback object
  411. // (rather than a callback specification) queues a wait for that callback.
  412. // Return the final callback for synchronization purposes.
  413. //
  414. Push: function () {
  415. var callback;
  416. for (var i = 0, m = arguments.length; i < m; i++) {
  417. callback = USING(arguments[i]);
  418. if (callback === arguments[i] && !callback.called)
  419. {callback = USING(["wait",this,callback])}
  420. this.queue.push(callback);
  421. }
  422. if (!this.running && !this.pending) {this.Process()}
  423. return callback;
  424. },
  425. //
  426. // Process the command queue if we aren't waiting on another command
  427. //
  428. Process: function (queue) {
  429. while (!this.running && !this.pending && this.queue.length) {
  430. var callback = this.queue[0];
  431. queue = this.queue.slice(1); this.queue = [];
  432. this.Suspend(); var result = callback(); this.Resume();
  433. if (queue.length) {this.queue = queue.concat(this.queue)}
  434. if (ISCALLBACK(result) && !result.called) {WAITFOR(result,this)}
  435. }
  436. },
  437. //
  438. // Suspend/Resume command processing on this queue
  439. //
  440. Suspend: function () {this.running++},
  441. Resume: function () {if (this.running) {this.running--}},
  442. //
  443. // Used by WAITFOR to restart the queue when an action completes
  444. //
  445. call: function () {this.Process.apply(this,arguments)},
  446. wait: function (callback) {return callback}
  447. });
  448. //
  449. // Create a named signal that listeners can attach to, to be signaled by
  450. // postings made to the signal. Posts are queued if they occur while one
  451. // is already in process.
  452. //
  453. var SIGNAL = QUEUE.Subclass({
  454. Init: function (name) {
  455. QUEUE.prototype.Init.call(this);
  456. this.name = name;
  457. this.posted = []; // the messages posted so far
  458. this.listeners = HOOKS(true); // those with interest in this signal
  459. },
  460. //
  461. // Post a message to the signal listeners, with callback for when complete
  462. //
  463. Post: function (message,callback,forget) {
  464. callback = USING(callback);
  465. if (this.posting || this.pending) {
  466. this.Push(["Post",this,message,callback,forget]);
  467. } else {
  468. this.callback = callback; callback.reset();
  469. if (!forget) {this.posted.push(message)}
  470. this.Suspend(); this.posting = true;
  471. var result = this.listeners.Execute(message);
  472. if (ISCALLBACK(result) && !result.called) {WAITFOR(result,this)}
  473. this.Resume(); delete this.posting;
  474. if (!this.pending) {this.call()}
  475. }
  476. return callback;
  477. },
  478. //
  479. // Clear the post history (so new listeners won't get old messages)
  480. //
  481. Clear: function (callback) {
  482. callback = USING(callback);
  483. if (this.posting || this.pending) {
  484. callback = this.Push(["Clear",this,callback]);
  485. } else {
  486. this.posted = [];
  487. callback();
  488. }
  489. return callback;
  490. },
  491. //
  492. // Call the callback (all replies are in) and process the command queue
  493. //
  494. call: function () {this.callback(this); this.Process()},
  495. //
  496. // A listener calls this to register intrest in the signal (so it will be called
  497. // when posts occur). If ignorePast is true, it will not be sent the post history.
  498. //
  499. Interest: function (callback,ignorePast,priority) {
  500. callback = USING(callback);
  501. this.listeners.Add(callback,priority);
  502. if (!ignorePast) {
  503. for (var i = 0, m = this.posted.length; i < m; i++) {
  504. callback.reset();
  505. var result = callback(this.posted[i]);
  506. if (ISCALLBACK(result) && i === this.posted.length-1) {WAITFOR(result,this)}
  507. }
  508. }
  509. return callback;
  510. },
  511. //
  512. // A listener calls this to remove itself from a signal
  513. //
  514. NoInterest: function (callback) {
  515. this.listeners.Remove(callback);
  516. },
  517. //
  518. // Hook a callback to a particular message on this signal
  519. //
  520. MessageHook: function (msg,callback,priority) {
  521. callback = USING(callback);
  522. if (!this.hooks) {this.hooks = {}; this.Interest(["ExecuteHooks",this])}
  523. if (!this.hooks[msg]) {this.hooks[msg] = HOOKS(true)}
  524. this.hooks[msg].Add(callback,priority);
  525. for (var i = 0, m = this.posted.length; i < m; i++)
  526. {if (this.posted[i] == msg) {callback.reset(); callback(this.posted[i])}}
  527. return callback;
  528. },
  529. //
  530. // Execute the message hooks for the given message
  531. //
  532. ExecuteHooks: function (msg,more) {
  533. var type = ((msg instanceof Array) ? msg[0] : msg);
  534. if (!this.hooks[type]) {return null}
  535. return this.hooks[type].Execute(msg);
  536. }
  537. },{
  538. signals: {}, // the named signals
  539. find: function (name) {
  540. if (!SIGNAL.signals[name]) {SIGNAL.signals[name] = new SIGNAL(name)}
  541. return SIGNAL.signals[name];
  542. }
  543. });
  544. //
  545. // The main entry-points
  546. //
  547. BASE.Callback = BASE.CallBack = USING;
  548. BASE.Callback.Delay = DELAY;
  549. BASE.Callback.After = AFTER;
  550. BASE.Callback.Queue = QUEUE;
  551. BASE.Callback.Signal = SIGNAL.find;
  552. BASE.Callback.Hooks = HOOKS;
  553. BASE.Callback.ExecuteHooks = EXECUTEHOOKS;
  554. })("MathJax");
  555. /**********************************************************/
  556. (function (BASENAME) {
  557. var BASE = window[BASENAME];
  558. if (!BASE) {BASE = window[BASENAME] = {}}
  559. var isSafari2 = (navigator.vendor === "Apple Computer, Inc." &&
  560. typeof navigator.vendorSub === "undefined");
  561. var sheets = 0; // used by Safari2
  562. //
  563. // Update sheets count and look up the head object
  564. //
  565. var HEAD = function (head) {
  566. if (document.styleSheets && document.styleSheets.length > sheets)
  567. {sheets = document.styleSheets.length}
  568. if (!head) {
  569. head = (document.getElementsByTagName("head"))[0];
  570. if (!head) {head = document.body}
  571. }
  572. return head;
  573. };
  574. //
  575. // Remove scripts that are completed so they don't clutter up the HEAD.
  576. // This runs via setTimeout since IE7 can't remove the script while it is running.
  577. //
  578. var SCRIPTS = []; // stores scripts to be removed after a delay
  579. var REMOVESCRIPTS = function () {
  580. for (var i = 0, m = SCRIPTS.length; i < m; i++) {BASE.Ajax.head.removeChild(SCRIPTS[i])}
  581. SCRIPTS = [];
  582. };
  583. BASE.Ajax = {
  584. loaded: {}, // files already loaded
  585. loading: {}, // files currently in process of loading
  586. loadHooks: {}, // hooks to call when files are loaded
  587. timeout: 15*1000, // timeout for loading of files (15 seconds)
  588. styleDelay: 1, // delay to use before styles are available
  589. config: {root: ""}, // URL of root directory to load from
  590. STATUS: {
  591. OK: 1, // file is loading or did load OK
  592. ERROR: -1 // file timed out during load
  593. },
  594. rootPattern: new RegExp("^\\["+BASENAME+"\\]"),
  595. //
  596. // Return a complete URL to a file (replacing the root pattern)
  597. //
  598. fileURL: function (file) {return file.replace(this.rootPattern,this.config.root)},
  599. //
  600. // Load a file if it hasn't been already.
  601. // Make sure the file URL is "safe"?
  602. //
  603. Require: function (file,callback) {
  604. callback = BASE.Callback(callback); var type;
  605. if (file instanceof Object) {for (var i in file) {}; type = i.toUpperCase(); file = file[i]}
  606. else {type = file.split(/\./).pop().toUpperCase()}
  607. file = this.fileURL(file);
  608. // FIXME: check that URL is OK
  609. if (this.loaded[file]) {
  610. callback(this.loaded[file]);
  611. } else {
  612. var FILE = {}; FILE[type] = file;
  613. this.Load(FILE,callback);
  614. }
  615. return callback;
  616. },
  617. //
  618. // Load a file regardless of where it is and whether it has
  619. // already been loaded.
  620. //
  621. Load: function (file,callback) {
  622. callback = BASE.Callback(callback); var type;
  623. if (file instanceof Object) {for (var i in file) {}; type = i.toUpperCase(); file = file[i]}
  624. else {type = file.split(/\./).pop().toUpperCase()}
  625. file = this.fileURL(file);
  626. if (this.loading[file]) {
  627. this.addHook(file,callback);
  628. } else {
  629. this.head = HEAD(this.head);
  630. if (this.loader[type]) {this.loader[type].call(this,file,callback)}
  631. else {throw Error("Can't load files of type "+type)}
  632. }
  633. return callback;
  634. },
  635. //
  636. // Register a load hook for a particular file (it will be called when
  637. // loadComplete() is called for that file)
  638. //
  639. LoadHook: function (file,callback,priority) {
  640. callback = BASE.Callback(callback);
  641. if (file instanceof Object) {for (var i in file) {file = file[i]}}
  642. file = this.fileURL(file);
  643. if (this.loaded[file]) {callback(this.loaded[file])}
  644. else {this.addHook(file,callback,priority)}
  645. return callback;
  646. },
  647. addHook: function (file,callback,priority) {
  648. if (!this.loadHooks[file]) {this.loadHooks[file] = MathJax.Callback.Hooks()}
  649. this.loadHooks[file].Add(callback,priority);
  650. },
  651. //
  652. // Used when files are combined in a preloading configuration file
  653. //
  654. Preloading: function () {
  655. for (var i = 0, m = arguments.length; i < m; i++) {
  656. var file = this.fileURL(arguments[i]);
  657. if (!this.loading[file]) {this.loading[file] = {preloaded: true}}
  658. }
  659. },
  660. //
  661. // Code used to load the various types of files
  662. // (JS for JavaScript, CSS for style sheets)
  663. //
  664. loader: {
  665. //
  666. // Create a SCRIPT tag to load the file
  667. //
  668. JS: function (file,callback) {
  669. var script = document.createElement("script");
  670. var timeout = BASE.Callback(["loadTimeout",this,file]);
  671. this.loading[file] = {
  672. callback: callback,
  673. message: BASE.Message.File(file),
  674. timeout: setTimeout(timeout,this.timeout),
  675. status: this.STATUS.OK,
  676. script: script
  677. };
  678. script.onerror = timeout; // doesn't work in IE and no apparent substitute
  679. script.type = "text/javascript";
  680. script.src = file;
  681. this.head.appendChild(script);
  682. },
  683. //
  684. // Create a LINK tag to load the style sheet
  685. //
  686. CSS: function (file,callback) {
  687. var link = document.createElement("link");
  688. link.rel = "stylesheet"; link.type = "text/css"; link.href = file;
  689. this.loading[file] = {
  690. callback: callback,
  691. message: BASE.Message.File(file),
  692. status: this.STATUS.OK
  693. };
  694. this.head.appendChild(link);
  695. this.timer.create.call(this,[this.timer.file,file],link);
  696. }
  697. },
  698. //
  699. // Timing code for checking when style sheets are available.
  700. //
  701. timer: {
  702. //
  703. // Create the timing callback and start the timing loop.
  704. // We use a delay because some browsers need it to allow the styles
  705. // to be processed.
  706. //
  707. create: function (callback,node) {
  708. callback = BASE.Callback(callback);
  709. if (node.nodeName === "STYLE" && node.styleSheet &&
  710. typeof(node.styleSheet.cssText) !== 'undefined') {
  711. callback(this.STATUS.OK); // MSIE processes style immediately, but doesn't set its styleSheet!
  712. } else if (window.chrome && typeof(window.sessionStorage) !== "undefined" &&
  713. node.nodeName === "STYLE") {
  714. callback(this.STATUS.OK); // Same for Chrome 5 (beta), Grrr.
  715. } else if (isSafari2) {
  716. this.timer.start(this,[this.timer.checkSafari2,sheets++,callback],this.styleDelay);
  717. } else {
  718. this.timer.start(this,[this.timer.checkLength,node,callback],this.styleDelay);
  719. }
  720. return callback;
  721. },
  722. //
  723. // Start the timer for the given callback checker
  724. //
  725. start: function (AJAX,check,delay,timeout) {
  726. check = BASE.Callback(check);
  727. check.execute = this.execute; check.time = this.time;
  728. check.STATUS = AJAX.STATUS; check.timeout = timeout || AJAX.timeout;
  729. check.delay = check.total = 0;
  730. if (delay) {setTimeout(check,delay)} else {check()}
  731. },
  732. //
  733. // Increment the time total, increase the delay
  734. // and test if we are past the timeout time.
  735. //
  736. time: function (callback) {
  737. this.total += this.delay;
  738. this.delay = Math.floor(this.delay * 1.05 + 5);
  739. if (this.total >= this.timeout) {callback(this.STATUS.ERROR); return 1}
  740. return 0;
  741. },
  742. //
  743. // For JS file loads, call the proper routine according to status
  744. //
  745. file: function (file,status) {
  746. if (status < 0) {BASE.Ajax.loadTimeout(file)} else {BASE.Ajax.loadComplete(file)}
  747. },
  748. //
  749. // Call the hook with the required data
  750. //
  751. execute: function () {this.hook.call(this.object,this,this.data[0],this.data[1])},
  752. //
  753. // Safari2 doesn't set the link's stylesheet, so we need to look in the
  754. // document.styleSheets array for the new sheet when it is created
  755. //
  756. checkSafari2: function (check,length,callback) {
  757. if (check.time(callback)) return;
  758. if (document.styleSheets.length > length &&
  759. document.styleSheets[length].cssRules &&
  760. document.styleSheets[length].cssRules.length)
  761. {callback(check.STATUS.OK)} else {setTimeout(check,check.delay)}
  762. },
  763. //
  764. // Look for the stylesheets rules and check when they are defined
  765. // and no longer of length zero. (This assumes there actually ARE
  766. // some rules in the stylesheet.)
  767. //
  768. checkLength: function (check,node,callback) {
  769. if (check.time(callback)) return;
  770. var isStyle = 0; var sheet = (node.sheet || node.styleSheet);
  771. try {if ((sheet.cssRules||sheet.rules||[]).length > 0) {isStyle = 1}} catch(err) {
  772. if (err.message.match(/protected variable|restricted URI/)) {isStyle = 1}
  773. else if (err.message.match(/Security error/)) {
  774. // Firefox3 gives "Security error" for missing files, so
  775. // can't distinguish that from OK files on remote servers.
  776. // or OK files in different directory from local files.
  777. isStyle = 1; // just say it is OK (can't really tell)
  778. }
  779. }
  780. if (isStyle) {
  781. // Opera 9.6 requires this setTimeout
  782. setTimeout(BASE.Callback([callback,check.STATUS.OK]),0);
  783. } else {
  784. setTimeout(check,check.delay);
  785. }
  786. }
  787. },
  788. //
  789. // JavaScript code must call this when they are completely initialized
  790. // (this allows them to perform asynchronous actions before indicating
  791. // that they are complete).
  792. //
  793. loadComplete: function (file) {
  794. file = this.fileURL(file);
  795. var loading = this.loading[file];
  796. if (loading && !loading.preloaded) {
  797. BASE.Message.Clear(loading.message);
  798. clearTimeout(loading.timeout);
  799. if (loading.script) {
  800. if (SCRIPTS.length === 0) {setTimeout(REMOVESCRIPTS,0)}
  801. SCRIPTS.push(loading.script);
  802. }
  803. this.loaded[file] = loading.status; delete this.loading[file];
  804. this.addHook(file,loading.callback);
  805. } else {
  806. if (loading) {delete this.loading[file]}
  807. this.loaded[file] = this.STATUS.OK;
  808. loading = {status: this.STATUS.OK}
  809. }
  810. if (!this.loadHooks[file]) {return null}
  811. return this.loadHooks[file].Execute(loading.status);
  812. },
  813. //
  814. // If a file fails to load within the timeout period (or the onerror handler
  815. // is called), this routine runs to signal the error condition.
  816. //
  817. loadTimeout: function (file) {
  818. if (this.loading[file].timeout) {clearTimeout(this.loading[file].timeout)}
  819. this.loading[file].status = this.STATUS.ERROR;
  820. this.loadError(file);
  821. this.loadComplete(file);
  822. },
  823. //
  824. // The default error hook for file load failures
  825. //
  826. loadError: function (file) {
  827. BASE.Message.Set("File failed to load: "+file,null,2000);
  828. BASE.Hub.signal.Post(["file load error",file]);
  829. },
  830. //
  831. // Defines a style sheet from a hash of style declarations (key:value pairs
  832. // where the key is the style selector and the value is a hash of CSS attributes
  833. // and values).
  834. //
  835. Styles: function (styles,callback) {
  836. var styleString = this.StyleString(styles);
  837. if (styleString === "") {
  838. callback = BASE.Callback(callback);
  839. callback();
  840. } else {
  841. var style = document.createElement("style"); style.type = "text/css";
  842. this.head = HEAD(this.head);
  843. this.head.appendChild(style);
  844. if (style.styleSheet && typeof(style.styleSheet.cssText) !== 'undefined') {
  845. style.styleSheet.cssText = styleString;
  846. } else {
  847. style.appendChild(document.createTextNode(styleString));
  848. }
  849. callback = this.timer.create.call(this,callback,style);
  850. }
  851. return callback;
  852. },
  853. //
  854. // Create a stylesheet string from a style declaration object
  855. //
  856. StyleString: function (styles) {
  857. if (typeof(styles) === 'string') {return styles}
  858. var string = "", id, style;
  859. for (id in styles) {if (styles.hasOwnProperty(id)) {
  860. if (typeof styles[id] === 'string') {
  861. string += id + " {"+styles[id]+"}\n";
  862. } else if (styles[id] instanceof Array) {
  863. for (var i = 0; i < styles[id].length; i++) {
  864. style = {}; style[id] = styles[id][i];
  865. string += this.StyleString(style);
  866. }
  867. } else if (id.substr(0,6) === '@media') {
  868. string += id + " {"+this.StyleString(styles[id])+"}\n";
  869. } else if (styles[id] != null) {
  870. style = [];
  871. for (var name in styles[id]) {if (styles[id].hasOwnProperty(name)) {
  872. if (styles[id][name] != null)
  873. {style[style.length] = name + ': ' + styles[id][name]}
  874. }}
  875. string += id +" {"+style.join('; ')+"}\n";
  876. }
  877. }}
  878. return string;
  879. }
  880. };
  881. })("MathJax");
  882. /**********************************************************/
  883. MathJax.HTML = {
  884. //
  885. // Create an HTML element with given attributes and content.
  886. // The def parameter is an (optional) object containing key:value pairs
  887. // of the attributes and their values, and contents is an (optional)
  888. // array of strings to be inserted as text, or arrays of the form
  889. // [type,def,contents] that describes an HTML element to be inserted
  890. // into the current element. Thus the contents can describe a complete
  891. // HTML snippet of arbitrary complexity. E.g.:
  892. //
  893. // MathJax.HTML.Element("span",{id:"mySpan",style{"font-style":"italic"}},[
  894. // "(See the ",["a",{href:"http://www.mathjax.org"},["MathJax home page"]],
  895. // " for more details.)"]);
  896. //
  897. Element: function (type,def,contents) {
  898. var obj = document.createElement(type);
  899. if (def) {
  900. if (def.style) {
  901. var style = def.style; def.style = {};
  902. for (var id in style) {if (style.hasOwnProperty(id))
  903. {def.style[id.replace(/-([a-z])/g,this.ucMatch)] = style[id]}}
  904. }
  905. MathJax.Hub.Insert(obj,def);
  906. }
  907. if (contents) {
  908. if (!(contents instanceof Array)) {contents = [contents]}
  909. for (var i = 0; i < contents.length; i++) {
  910. if (contents[i] instanceof Array) {
  911. obj.appendChild(this.Element(contents[i][0],contents[i][1],contents[i][2]));
  912. } else {
  913. obj.appendChild(document.createTextNode(contents[i]));
  914. }
  915. }
  916. }
  917. return obj;
  918. },
  919. ucMatch: function (match,c) {return c.toUpperCase()},
  920. addElement: function (span,type,def,contents) {return span.appendChild(this.Element(type,def,contents))},
  921. TextNode: function (text) {return document.createTextNode(text)},
  922. addText: function (span,text) {return span.appendChild(this.TextNode(text))},
  923. //
  924. // Set and get the text of a script
  925. //
  926. setScript: function (script,text) {
  927. if (this.setScriptBug) {script.text = text} else {
  928. while (script.firstChild) {script.removeChild(script.firstChild)}
  929. this.addText(script,text);
  930. }
  931. },
  932. getScript: function (script) {
  933. var text = (script.text === "" ? script.innerHTML : script.text);
  934. return text.replace(/^\s+/,"").replace(/\s+$/,"");
  935. },
  936. //
  937. // Manage cookies
  938. //
  939. Cookie: {
  940. prefix: "mjx",
  941. expires: 365,
  942. //
  943. // Save an object as a named cookie
  944. //
  945. Set: function (name,def) {
  946. var keys = [];
  947. if (def) {
  948. for (var id in def) {if (def.hasOwnProperty(id)) {
  949. keys.push(id+":"+def[id].toString().replace(/&/g,"&&"));
  950. }}
  951. }
  952. var cookie = this.prefix+"."+name+"="+escape(keys.join('&;'));
  953. if (this.expires) {
  954. var time = new Date(); time.setDate(time.getDate() + this.expires);
  955. cookie += '; expires='+time.toGMTString();
  956. }
  957. document.cookie = cookie+"; path=/";
  958. },
  959. //
  960. // Get the contents of a named cookie and incorporate
  961. // it into the given object (or return a fresh one)
  962. //
  963. Get: function (name,obj) {
  964. if (!obj) {obj = {}}
  965. var pattern = new RegExp("(?:^|;\\s*)"+this.prefix+"\\."+name+"=([^;]*)(?:;|$)");
  966. var match = pattern.exec(document.cookie);
  967. if (match && match[1] !== "") {
  968. var keys = unescape(match[1]).split('&;');
  969. for (var i = 0, m = keys.length; i < m; i++) {
  970. match = keys[i].match(/([^:]+):(.*)/);
  971. var value = match[2].replace(/&&/g,'&');
  972. if (value === "true") {value = true} else if (value === "false") {value = false}
  973. else if (value.match(/^-?(\d+(\.\d+)?|\.\d+)$/)) {value = parseFloat(value)}
  974. obj[match[1]] = value;
  975. }
  976. }
  977. return obj;
  978. }
  979. }
  980. };
  981. /**********************************************************/
  982. MathJax.Message = {
  983. ready: false, // used to tell when the styles are available
  984. log: [{}], current: null,
  985. textNodeBug: (navigator.vendor === "Apple Computer, Inc." &&
  986. typeof navigator.vendorSub === "undefined") ||
  987. (window.hasOwnProperty && window.hasOwnProperty("konqueror")), // Konqueror displays some gibberish with text.nodeValue = "..."
  988. styles: {
  989. "#MathJax_Message": {
  990. position: "fixed", left: "1px", bottom: "2px",
  991. 'background-color': "#E6E6E6", border: "1px solid #959595",
  992. margin: "0px", padding: "2px 8px",
  993. 'z-index': "102", color: "black", 'font-size': "80%",
  994. width: "auto", 'white-space': "nowrap"
  995. },
  996. "#MathJax_MSIE_Frame": {
  997. position: "absolute",
  998. top:0, left: 0, width: "0px", 'z-index': 101,
  999. border: "0px", margin: "0px", padding: "0px"
  1000. }
  1001. },
  1002. browsers: {
  1003. MSIE: function (browser) {
  1004. MathJax.Hub.config.styles["#MathJax_Message"].position = "absolute";
  1005. MathJax.Message.quirks = (document.compatMode === "BackCompat");
  1006. },
  1007. Chrome: function (browser) {
  1008. MathJax.Hub.config.styles["#MathJax_Message"].bottom = "1.5em";
  1009. MathJax.Hub.config.styles["#MathJax_Message"].left = "1em";
  1010. }
  1011. },
  1012. Init: function (styles) {
  1013. if (styles) {this.ready = true}
  1014. if (!document.body || !this.ready) {return false}
  1015. //
  1016. // ASCIIMathML replaces the entire page with a copy of itself (@#!#%@!!)
  1017. // so check that this.div is still part of the page, otherwise look up
  1018. // the copy and use that.
  1019. //
  1020. if (this.div && this.div.parentNode == null) {
  1021. this.div = document.getElementById("MathJax_Message");
  1022. if (this.div) {this.text = this.div.firstChild}
  1023. }
  1024. if (!this.div) {
  1025. var frame = document.body;
  1026. if (MathJax.Hub.Browser.isMSIE) {
  1027. frame = this.frame = this.addDiv(document.body); frame.removeAttribute("id");
  1028. frame.style.position = "absolute";
  1029. frame.style.border = frame.style.margin = frame.style.padding = "0px";
  1030. frame.style.zIndex = "101"; frame.style.height = "0px";
  1031. frame = this.addDiv(frame);
  1032. frame.id = "MathJax_MSIE_Frame";
  1033. window.attachEvent("onscroll",this.MoveFrame);
  1034. window.attachEvent("onresize",this.MoveFrame);
  1035. this.MoveFrame();
  1036. }
  1037. this.div = this.addDiv(frame); this.div.style.display = "none";
  1038. this.text = this.div.appendChild(document.createTextNode(""));
  1039. }
  1040. return true;
  1041. },
  1042. addDiv: function (parent) {
  1043. var div = document.createElement("div");
  1044. div.id = "MathJax_Message";
  1045. if (parent.firstChild) {parent.insertBefore(div,parent.firstChild)}
  1046. else {parent.appendChild(div)}
  1047. return div;
  1048. },
  1049. MoveFrame: function () {
  1050. var body = (MathJax.Message.quirks ? document.body : document.documentElement);
  1051. var frame = MathJax.Message.frame;
  1052. frame.style.left = body.scrollLeft + 'px';
  1053. frame.style.top = body.scrollTop + 'px';
  1054. frame.style.width = body.clientWidth + 'px';
  1055. frame = frame.firstChild;
  1056. frame.style.height = body.clientHeight + 'px';
  1057. },
  1058. filterText: function (text,n) {
  1059. if (MathJax.Hub.config.messageStyle === "simple") {
  1060. if (text.match(/^Loading /)) {
  1061. if (!this.loading) {this.loading = "Loading "}
  1062. text = this.loading; this.loading += ".";
  1063. } else if (text.match(/^Processing /)) {
  1064. if (!this.processing) {this.processing = "Processing "}
  1065. text = this.processing; this.processing += ".";
  1066. } else if (text.match(/^Typesetting /)) {
  1067. if (!this.typesetting) {this.typesetting = "Typesetting "}
  1068. text = this.typesetting; this.typesetting += ".";
  1069. }
  1070. }
  1071. return text;
  1072. },
  1073. Set: function (text,n,clearDelay) {
  1074. if (this.timer) {clearTimeout(this.timer); delete this.timeout}
  1075. if (n == null) {n = this.log.length; this.log[n] = {}}
  1076. this.log[n].text = text; this.log[n].filteredText = text = this.filterText(text,n);
  1077. if (typeof(this.log[n].next) === "undefined") {
  1078. this.log[n].next = this.current;
  1079. if (this.current != null) {this.log[this.current].prev = n}
  1080. this.current = n;
  1081. }
  1082. if (this.current === n && MathJax.Hub.config.messageStyle !== "none") {
  1083. if (this.Init()) {
  1084. if (this.textNodeBug) {this.div.innerHTML = text} else {this.text.nodeValue = text}
  1085. this.div.style.display = "";
  1086. if (this.status) {window.status = ""; delete this.status}
  1087. } else {
  1088. window.status = text;
  1089. this.status = true;
  1090. }
  1091. }
  1092. if (clearDelay) {setTimeout(MathJax.Callback(["Clear",this,n]),clearDelay)}
  1093. else if (clearDelay == 0) {this.Clear(n,0)}
  1094. return n;
  1095. },
  1096. Clear: function (n,delay) {
  1097. if (this.log[n].prev != null) {this.log[this.log[n].prev].next = this.log[n].next}
  1098. if (this.log[n].next != null) {this.log[this.log[n].next].prev = this.log[n].prev}
  1099. if (this.current === n) {
  1100. this.current = this.log[n].next;
  1101. if (this.text) {
  1102. if (this.div.parentNode == null) {this.Init()} // see ASCIIMathML comments above
  1103. if (this.current == null) {
  1104. if (this.timer) {clearTimeout(this.timer); delete this.timer}
  1105. if (delay == null) {delay = 600}
  1106. if (delay === 0) {this.Remove()}
  1107. else {this.timer = setTimeout(MathJax.Callback(["Remove",this]),delay)}
  1108. } else if (MathJax.Hub.config.messageStyle !== "none") {
  1109. if (this.textNodeBug) {this.div.innerHTML = this.log[this.current].filteredText}
  1110. else {this.text.nodeValue = this.log[this.current].filteredText}
  1111. }
  1112. if (this.status) {window.status = ""; delete this.status}
  1113. } else if (this.status) {
  1114. window.status = (this.current == null ? "" : this.log[this.current].text);
  1115. }
  1116. }
  1117. delete this.log[n].next; delete this.log[n].prev;
  1118. delete this.log[n].filteredText;
  1119. },
  1120. Remove: function () {
  1121. // FIXME: do a fade out or something else interesting?
  1122. this.text.nodeValue = "";
  1123. this.div.style.display = "none";
  1124. },
  1125. File: function (file) {
  1126. var root = MathJax.Ajax.config.root;
  1127. if (file.substr(0,root.length) === root) {file = "[MathJax]"+file.substr(root.length)}
  1128. return this.Set("Loading "+file);
  1129. },
  1130. Log: function () {
  1131. var strings = [];
  1132. for (var i = 1, m = this.log.length; i < m; i++) {strings[i] = this.log[i].text}
  1133. return strings.join("\n");
  1134. }
  1135. };
  1136. /**********************************************************/
  1137. MathJax.Hub = {
  1138. config: {
  1139. root: "",
  1140. config: [], // list of configuration files to load
  1141. styleSheets: [], // list of CSS files to load
  1142. styles: { // styles to generate in-line
  1143. ".MathJax_Preview": {color: "#888"}
  1144. },
  1145. jax: [], // list of input and output jax to load
  1146. extensions: [], // list of extensions to load
  1147. preJax: null, // pattern to remove from before math script tag
  1148. postJax: null, // pattern to remove from after math script tag
  1149. displayAlign: 'center', // how to align displayed equations (left, center, right)
  1150. displayIndent: '0', // indentation for displayed equations (when not centered)
  1151. preRemoveClass: 'MathJax_Preview', // class of objects to remove preceeding math script
  1152. showProcessingMessages: true, // display "Processing math: nn%" messages or not
  1153. messageStyle: "normal", // set to "none" or "simple" (for "Loading..." and "Processing...")
  1154. delayStartupUntil: "none", // set to "onload" to delay setup until the onload handler runs
  1155. // set to "configured" to delay startup until MathJax.Hub.Configured() is called
  1156. // set to a Callback to wait for before continuing with the startup
  1157. skipStartupTypeset: false, // set to true to skip PreProcess and Process during startup
  1158. "v1.0-compatible": true, // set to false to prevent message about configuration change
  1159. elements: [], // array of elements to process when none is given explicitly
  1160. positionToHash: true, // after initial typeset pass, position to #hash location?
  1161. showMathMenu: true, // attach math context menu to typeset math?
  1162. showMathMenuMSIE: true, // separtely determine if MSIE should have math menu
  1163. // (since the code for that is a bit delicate)
  1164. menuSettings: {
  1165. zoom: "None", // when to do MathZoom
  1166. CTRL: false, // require CTRL for MathZoom?
  1167. ALT: false, // require Alt or Option?
  1168. CMD: false, // require CMD?
  1169. Shift: false, // require Shift?
  1170. discoverable: false, // make math menu discoverable on hover?
  1171. zscale: "200%", // the scaling factor for MathZoom
  1172. renderer: "", // set when Jax are loaded
  1173. font: "Auto", // what font HTML-CSS should use
  1174. context: "MathJax", // or "Browser" for pass-through to browser menu
  1175. mpContext: false, // true means pass menu events to MathPlayer in IE
  1176. mpMouse: false, // true means pass mouse events to MathPlayer in IE
  1177. texHints: true // include class names for TeXAtom elements
  1178. },
  1179. errorSettings: {
  1180. message: ["[Math Processing Error]"], // HTML snippet structure for message to use
  1181. style: {color: "#CC0000", "font-style":"italic"} // style for message
  1182. }
  1183. },
  1184. preProcessors: MathJax.Callback.Hooks(true), // list of callbacks for preprocessing (initialized by extensions)
  1185. inputJax: {}, // mime-type mapped to input jax (by registration)
  1186. outputJax: {order:{}}, // mime-type mapped to output jax list (by registration)
  1187. processUpdateTime: 250, // time between screen updates when processing math (milliseconds)
  1188. processUpdateDelay: 10, // pause between screen updates to allow other processing (milliseconds)
  1189. signal: MathJax.Callback.Signal("Hub"), // Signal used for Hub events
  1190. Config: function (def) {
  1191. this.Insert(this.config,def);
  1192. if (this.config.Augment) {this.Augment(this.config.Augment)}
  1193. },
  1194. CombineConfig: function (name,def) {
  1195. var config = this.config, id, parent; name = name.split(/\./);
  1196. for (var i = 0, m = name.length; i < m; i++) {
  1197. id = name[i]; if (!config[id]) {config[id] = {}}
  1198. parent = config; config = config[id];
  1199. }
  1200. parent[id] = config = this.Insert(def,config);
  1201. return config;
  1202. },
  1203. Register: {
  1204. PreProcessor: function () {MathJax.Hub.preProcessors.Add.apply(MathJax.Hub.preProcessors,arguments)},
  1205. MessageHook: function () {return MathJax.Hub.signal.MessageHook.apply(MathJax.Hub.signal,arguments)},
  1206. StartupHook: function () {return MathJax.Hub.Startup.signal.MessageHook.apply(MathJax.Hub.Startup.signal,arguments)},
  1207. LoadHook: function () {return MathJax.Ajax.LoadHook.apply(MathJax.Ajax,arguments)}
  1208. },
  1209. getAllJax: function (element) {
  1210. var jax = [], scripts = this.elementScripts(element);
  1211. for (var i = 0, m = scripts.length; i < m; i++) {
  1212. if (scripts[i].MathJax && scripts[i].MathJax.elementJax)
  1213. {jax.push(scripts[i].MathJax.elementJax)}
  1214. }
  1215. return jax;
  1216. },
  1217. getJaxByType: function (type,element) {
  1218. var jax = [], scripts = this.elementScripts(element);
  1219. for (var i = 0, m = scripts.length; i < m; i++) {
  1220. if (scripts[i].MathJax && scripts[i].MathJax.elementJax &&
  1221. scripts[i].MathJax.elementJax.mimeType === type)
  1222. {jax.push(scripts[i].MathJax.elementJax)}
  1223. }
  1224. return jax;
  1225. },
  1226. getJaxByInputType: function (type,element) {
  1227. var jax = [], scripts = this.elementScripts(element);
  1228. for (var i = 0, m = scripts.length; i < m; i++) {
  1229. if (scripts[i].MathJax && scripts[i].MathJax.elementJax &&
  1230. scripts[i].type && scripts[i].type.replace(/ *;(.|\s)*/,"") === type)
  1231. {jax.push(scripts[i].MathJax.elementJax)}
  1232. }
  1233. return jax;
  1234. },
  1235. getJaxFor: function (element) {
  1236. if (typeof(element) === 'string') {element = document.getElementById(element)}
  1237. if (element && element.MathJax) {return element.MathJax.elementJax}
  1238. if (element && element.isMathJax) {
  1239. while (element && !element.jaxID) {element = element.parentNode}
  1240. if (element) {return MathJax.OutputJax[element.jaxID].getJaxFromMath(element)}
  1241. }
  1242. return null;
  1243. },
  1244. isJax: function (element) {
  1245. if (typeof(element) === 'string') {element = document.getElementById(element)}
  1246. if (element && element.isMathJax) {return 1}
  1247. if (element && element.tagName != null && element.tagName.toLowerCase() === 'script') {
  1248. if (element.MathJax)
  1249. {return (element.MathJax.state === MathJax.ElementJax.STATE.PROCESSED ? 1 : -1)}
  1250. if (element.type && this.inputJax[element.type.replace(/ *;(.|\s)*/,"")]) {return -1}
  1251. }
  1252. return 0;
  1253. },
  1254. setRenderer: function (renderer,type) {
  1255. if (!renderer) return;
  1256. if (!MathJax.OutputJax[renderer]) {
  1257. this.config.menuSettings.renderer = "";
  1258. var file = "[MathJax]/jax/output/"+renderer+"/config.js";
  1259. return MathJax.Ajax.Require(file,["setRenderer",this,renderer,type]);
  1260. } else {
  1261. this.config.menuSettings.renderer = renderer;
  1262. if (type == null) {type = "jax/mml"}
  1263. var jax = this.outputJax;
  1264. if (jax[type] && jax[type].length) {
  1265. if (renderer !== jax[type][0].id) {
  1266. jax[type].unshift(MathJax.OutputJax[renderer]);
  1267. return this.signal.Post(["Renderer Selected",renderer]);
  1268. }
  1269. }
  1270. return null;
  1271. }
  1272. },
  1273. Queue: function () {
  1274. return this.queue.Push.apply(this.queue,arguments);
  1275. },
  1276. Typeset: function (element,callback) {
  1277. if (!MathJax.isReady) return null;
  1278. var ec = this.elementCallback(element,callback);
  1279. var queue = MathJax.Callback.Queue();
  1280. for (var i = 0, m = ec.elements.length; i < m; i++) {
  1281. if (ec.elements[i]) {
  1282. queue.Push(
  1283. ["PreProcess",this,ec.elements[i]],
  1284. ["Process",this,ec.elements[i]]
  1285. );
  1286. }
  1287. }
  1288. return queue.Push(ec.callback);
  1289. },
  1290. PreProcess: function (element,callback) {
  1291. var ec = this.elementCallback(element,callback);
  1292. var queue = MathJax.Callback.Queue();
  1293. for (var i = 0, m = ec.elements.length; i < m; i++) {
  1294. if (ec.elements[i]) {
  1295. queue.Push(
  1296. ["Post",this.signal,["Begin PreProcess",ec.elements[i]]],
  1297. (arguments.callee.disabled? {} : ["Execute",this.preProcessors,ec.elements[i]]),
  1298. ["Post",this.signal,["End PreProcess",ec.elements[i]]]
  1299. );
  1300. }
  1301. }
  1302. return queue.Push(ec.callback);
  1303. },
  1304. Process: function (element,callback) {return this.takeAction("Process",element,callback)},
  1305. Update: function (element,callback) {return this.takeAction("Update",element,callback)},
  1306. Reprocess: function (element,callback) {return this.takeAction("Reprocess",element,callback)},
  1307. Rerender: function (element,callback) {return this.takeAction("Rerender",element,callback)},
  1308. takeAction: function (action,element,callback) {
  1309. var ec = this.elementCallback(element,callback);
  1310. var queue = MathJax.Callback.Queue(["Clear",this.signal]);
  1311. for (var i = 0, m = ec.elements.length; i < m; i++) {
  1312. if (ec.elements[i]) {
  1313. var state = {
  1314. scripts: [], // filled in by prepareScripts
  1315. start: new Date().getTime(), // timer for processing messages
  1316. i: 0, j: 0, // current script, current jax
  1317. jax: {}, // scripts grouped by output jax
  1318. jaxIDs: [] // id's of jax used
  1319. };
  1320. queue.Push(
  1321. ["Post",this.signal,["Begin "+action,ec.elements[i]]],
  1322. ["Post",this.signal,["Begin Math",ec.elements[i],action]],
  1323. ["prepareScripts",this,action,ec.elements[i],state],
  1324. ["Post",this.signal,["Begin Math Input",ec.elements[i],action]],
  1325. ["processInput",this,state],
  1326. ["Post",this.signal,["End Math Input",ec.elements[i],action]],
  1327. ["prepareOutput",this,state,"preProcess"],
  1328. ["Post",this.signal,["Begin Math Output",ec.elements[i],action]],
  1329. ["processOutput",this,state],
  1330. ["Post",this.signal,["End Math Output",ec.elements[i],action]],
  1331. ["prepareOutput",this,state,"postProcess"],
  1332. ["Post",this.signal,["End Math",ec.elements[i],action]],
  1333. ["Post",this.signal,["End "+action,ec.elements[i]]]
  1334. );
  1335. }
  1336. }
  1337. return queue.Push(ec.callback);
  1338. },
  1339. scriptAction: {
  1340. Process: function (script) {},
  1341. Update: function (script) {
  1342. var jax = script.MathJax.elementJax;
  1343. if (jax && jax.needsUpdate()) {jax.Remove(true); script.MathJax.state = jax.STATE.UPDATE}
  1344. else {script.MathJax.state = jax.STATE.PROCESSED}
  1345. },
  1346. Reprocess: function (script) {
  1347. var jax = script.MathJax.elementJax;
  1348. if (jax) {jax.Remove(true); script.MathJax.state = jax.STATE.UPDATE}
  1349. },
  1350. Rerender: function (script) {
  1351. var jax = script.MathJax.elementJax;
  1352. if (jax) {jax.Remove(true); script.MathJax.state = jax.STATE.OUTPUT}
  1353. }
  1354. },
  1355. prepareScripts: function (action,element,state) {
  1356. if (arguments.callee.disabled) return;
  1357. var scripts = this.elementScripts(element);
  1358. var STATE = MathJax.ElementJax.STATE;
  1359. for (var i = 0, m = scripts.length; i < m; i++) {
  1360. var script = scripts[i];
  1361. if (script.type && this.inputJax[script.type.replace(/ *;(.|\n)*/,"")]) {
  1362. if (script.MathJax) {
  1363. if (script.MathJax.elementJax && script.MathJax.elementJax.hover) {
  1364. MathJax.Extension.MathEvents.Hover.ClearHover(script.MathJax.elementJax);
  1365. }
  1366. if (script.MathJax.state !== STATE.PENDING) {this.scriptAction[action](script)}
  1367. }
  1368. if (!script.MathJax) {script.MathJax = {state: STATE.PENDING}}
  1369. if (script.MathJax.state !== STATE.PROCESSED) {state.scripts.push(script)}
  1370. }
  1371. }
  1372. },
  1373. checkScriptSiblings: function (script) {
  1374. if (script.MathJax.checked) return;
  1375. var config = this.config, pre = script.previousSibling;
  1376. if (pre && pre.nodeName === "#text") {
  1377. var preJax,postJax, post = script.nextSibling;
  1378. if (post && post.nodeName !== "#text") {post = null}
  1379. if (config.preJax) {
  1380. if (typeof(config.preJax) === "string") {config.preJax = new RegExp(config.preJax+"$")}
  1381. preJax = pre.nodeValue.match(config.preJax);
  1382. }
  1383. if (config.postJax && post) {
  1384. if (typeof(config.postJax) === "string") {config.postJax = new RegExp("^"+config.postJax)}
  1385. postJax = post.nodeValue.match(config.postJax);
  1386. }
  1387. if (preJax && (!config.postJax || postJax)) {
  1388. pre.nodeValue = pre.nodeValue.replace
  1389. (config.preJax,(preJax.length > 1? preJax[1] : ""));
  1390. pre = null;
  1391. }
  1392. if (postJax && (!config.preJax || preJax)) {
  1393. post.nodeValue = post.nodeValue.replace
  1394. (config.postJax,(postJax.length > 1? postJax[1] : ""));
  1395. }
  1396. if (pre && !pre.nodeValue.match(/\S/)) {pre = pre.previousSibling}
  1397. }
  1398. if (config.preRemoveClass && pre && pre.className === config.preRemoveClass)
  1399. {script.MathJax.preview = pre}
  1400. script.MathJax.checked = 1;
  1401. },
  1402. processInput: function (state) {
  1403. var jax, STATE = MathJax.ElementJax.STATE;
  1404. var script, prev, m = state.scripts.length;
  1405. try {
  1406. //
  1407. // Loop through the scripts
  1408. //
  1409. while (state.i < m) {
  1410. script = state.scripts[state.i]; if (!script) {state.i++; continue}
  1411. //
  1412. // Remove previous error marker, if any
  1413. //
  1414. prev = script.previousSibling;
  1415. if (prev && prev.className === "MathJax_Error") {prev.parentNode.removeChild(prev)}
  1416. //
  1417. // Check if already processed or needs processing
  1418. //
  1419. if (!script.MathJax || script.MathJax.state === STATE.PROCESSED) {state.i++; continue};
  1420. if (!script.MathJax.elementJax || script.MathJax.state === STATE.UPDATE) {
  1421. this.checkScriptSiblings(script); // remove preJax/postJax etc.
  1422. var type = script.type.replace(/ *;(.|\s)*/,""); // the input jax type
  1423. jax = this.inputJax[type].Process(script,state); // run the input jax
  1424. if (typeof jax === 'function') { // if a callback was returned
  1425. if (jax.called) continue; // go back and call Process() again
  1426. this.RestartAfter(jax); // wait for the callback
  1427. }
  1428. jax.Attach(script,this.inputJax[type].id); // register the jax on the script
  1429. this.saveScript(jax,state,script,STATE); // add script to state
  1430. } else if (script.MathJax.state === STATE.OUTPUT) {
  1431. this.saveScript(script.MathJax.elementJax,state,script,STATE); // add script to state
  1432. }
  1433. //
  1434. // Go on to the next script, and check if we need to update the processing message
  1435. //
  1436. state.i++; var now = new Date().getTime();
  1437. if (now - state.start > this.processUpdateTime && state.i < state.scripts.length)
  1438. {state.start = now; this.RestartAfter(MathJax.Callback.Delay(1))}
  1439. }
  1440. } catch (err) {return this.processError(err,state,"Input")}
  1441. //
  1442. // Put up final message, reset the state and return
  1443. //
  1444. if (state.scripts.length && this.config.showProcessingMessages)
  1445. {MathJax.Message.Set("Processing math: 100%",0)}
  1446. state.start = new Date().getTime(); state.i = state.j = 0;
  1447. return null;
  1448. },
  1449. saveScript: function (jax,state,script,STATE) {
  1450. //
  1451. // Check that output jax exists
  1452. //
  1453. if (!this.outputJax[jax.mimeType]) {
  1454. script.MathJax.state = STATE.UPDATE;
  1455. throw Error("No output jax registered for "+jax.mimeType);
  1456. }
  1457. //
  1458. // Record the output jax
  1459. // and put this script in the queue for that jax
  1460. //
  1461. jax.outputJax = this.outputJax[jax.mimeType][0].id;
  1462. if (!state.jax[jax.outputJax]) {
  1463. if (state.jaxIDs.length === 0) {
  1464. // use original array until we know there are more (rather than two copies)
  1465. state.jax[jax.outputJax] = state.scripts;
  1466. } else {
  1467. if (state.jaxIDs.length === 1) // get the script so far for the existing jax
  1468. {state.jax[state.jaxIDs[0]] = state.scripts.slice(0,state.i)}
  1469. state.jax[jax.outputJax] = []; // start a new array for the new jax
  1470. }
  1471. state.jaxIDs.push(jax.outputJax); // save the ID of the jax
  1472. }
  1473. if (state.jaxIDs.length > 1) {state.jax[jax.outputJax].push(script)}
  1474. //
  1475. // Mark script as needing output
  1476. //
  1477. script.MathJax.state = STATE.OUTPUT;
  1478. },
  1479. //
  1480. // Pre- and post-process scripts by jax
  1481. // (to get scaling factors, hide/show output, and so on)
  1482. // Since this can cause the jax to load, we need to trap restarts
  1483. //
  1484. prepareOutput: function (state,method) {
  1485. while (state.j < state.jaxIDs.length) {
  1486. var id = state.jaxIDs[state.j], JAX = MathJax.OutputJax[id];
  1487. if (JAX[method]) {
  1488. try {
  1489. var result = JAX[method](state);
  1490. if (typeof result === 'function') {
  1491. if (result.called) continue; // go back and try again
  1492. this.RestartAfter(result);
  1493. }
  1494. } catch (err) {
  1495. if (!err.restart) {
  1496. MathJax.Message.Set("Error preparing "+id+" output ("+method+")",null,600);
  1497. MathJax.Hub.lastPrepError = err;
  1498. state.j++;
  1499. }
  1500. return MathJax.Callback.After(["prepareOutput",this,state,method],err.restart);
  1501. }
  1502. }
  1503. state.j++;
  1504. }
  1505. return null;
  1506. },
  1507. processOutput: function (state) {
  1508. var result, STATE = MathJax.ElementJax.STATE, script, m = state.scripts.length;
  1509. try {
  1510. //
  1511. // Loop through the scripts
  1512. //
  1513. while (state.i < m) {
  1514. //
  1515. // Check that there is an element jax
  1516. //
  1517. script = state.scripts[state.i]; if (!script || !script.MathJax) {state.i++; continue}
  1518. var jax = script.MathJax.elementJax; if (!jax) {state.i++; continue}
  1519. //
  1520. // Call the output Jax's Process method (which will be its Translate()
  1521. // method once loaded). Mark it as complete and remove the preview.
  1522. //
  1523. result = MathJax.OutputJax[jax.outputJax].Process(script,state);
  1524. script.MathJax.state = STATE.PROCESSED; state.i++;
  1525. if (script.MathJax.preview) {script.MathJax.preview.innerHTML = ""}
  1526. //
  1527. // Signal that new math is available
  1528. //
  1529. this.signal.Post(["New Math",jax.inputID]); // FIXME: wait for this? (i.e., restart if returns uncalled callback)
  1530. //
  1531. // Update the processing message, if needed
  1532. //
  1533. var now = new Date().getTime();
  1534. if (now - state.start > this.processUpdateTime && state.i < state.scripts.length)
  1535. {state.start = now; this.RestartAfter(MathJax.Callback.Delay(this.processUpdateDelay))}
  1536. }
  1537. } catch (err) {return this.processError(err,state,"Output")}
  1538. //
  1539. // Put up the typesetting-complete message
  1540. //
  1541. if (state.scripts.length && this.config.showProcessingMessages) {
  1542. MathJax.Message.Set("Typesetting math: 100%",0);
  1543. MathJax.Message.Clear(0);
  1544. }
  1545. state.i = state.j = 0;
  1546. return null;
  1547. },
  1548. processMessage: function (state,type) {
  1549. var m = Math.floor(state.i/(state.scripts.length)*100);
  1550. var message = (type === "Output" ? "Typesetting" : "Processing");
  1551. if (this.config.showProcessingMessages) {MathJax.Message.Set(message+" math: "+m+"%",0)}
  1552. },
  1553. processError: function (err,state,type) {
  1554. if (!err.restart) {
  1555. if (!this.config.errorSettings.message) {throw err}
  1556. this.formatError(state.scripts[state.i],err); state.i++;
  1557. }
  1558. this.processMessage(state,type);
  1559. return MathJax.Callback.After(["process"+type,this,state],err.restart);
  1560. },
  1561. formatError: function (script,err) {
  1562. var error = MathJax.HTML.Element("span",{className:"MathJax_Error"},this.config.errorSettings.message);
  1563. error.jaxID = "Error";
  1564. if (MathJax.Extension.MathEvents) {
  1565. error.oncontextmenu = MathJax.Extension.MathEvents.Event.Menu;
  1566. error.onmousedown = MathJax.Extension.MathEvents.Event.Mousedown;
  1567. } else {
  1568. MathJax.Ajax.Require("[MathJax]/extensions/MathEvents.js",function () {
  1569. error.oncontextmenu = MathJax.Extension.MathEvents.Event.Menu;
  1570. error.onmousedown = MathJax.Extension.MathEvents.Event.Mousedown;
  1571. });
  1572. }
  1573. script.parentNode.insertBefore(error,script);
  1574. if (script.MathJax.preview) {script.MathJax.preview.innerHTML = ""}
  1575. this.lastError = err;
  1576. this.signal.Post(["Math Processing Error",script,err]);
  1577. },
  1578. RestartAfter: function (callback) {
  1579. throw this.Insert(Error("restart"),{restart: MathJax.Callback(callback)});
  1580. },
  1581. elementCallback: function (element,callback) {
  1582. if (callback == null && (element instanceof Array || typeof element === 'function'))
  1583. {try {MathJax.Callback(element); callback = element; element = null} catch(e) {}}
  1584. if (element == null) {element = this.config.elements || []}
  1585. if (!(element instanceof Array)) {element = [element]}
  1586. element = [].concat(element); // make a copy so the original isn't changed
  1587. for (var i = 0, m = element.length; i < m; i++)
  1588. {if (typeof(element[i]) === 'string') {element[i] = document.getElementById(element[i])}}
  1589. if (element.length == 0) {element.push(document.body)}
  1590. if (!callback) {callback = {}}
  1591. return {elements: element, callback: callback};
  1592. },
  1593. elementScripts: function (element) {
  1594. if (typeof(element) === 'string') {element = document.getElementById(element)}
  1595. if (element == null) {element = document.body}
  1596. if (element.tagName != null && element.tagName.toLowerCase() === "script") {return [element]}
  1597. return element.getElementsByTagName("script");
  1598. },
  1599. Insert: function (dst,src) {
  1600. for (var id in src) {if (src.hasOwnProperty(id)) {
  1601. // allow for concatenation of arrays?
  1602. if (typeof src[id] === 'object' && !(src[id] instanceof Array) &&
  1603. (typeof dst[id] === 'object' || typeof dst[id] === 'function')) {
  1604. this.Insert(dst[id],src[id]);
  1605. } else {
  1606. dst[id] = src[id];
  1607. }
  1608. }}
  1609. return dst;
  1610. }
  1611. };
  1612. MathJax.Hub.Insert(MathJax.Hub.config.styles,MathJax.Message.styles);
  1613. MathJax.Hub.Insert(MathJax.Hub.config.styles,{".MathJax_Error":MathJax.Hub.config.errorSettings.style});
  1614. //
  1615. // Storage area for extensions and preprocessors
  1616. //
  1617. MathJax.Extension = {};
  1618. //
  1619. // Hub Startup code
  1620. //
  1621. MathJax.Hub.Configured = MathJax.Callback({}); // called when configuration is complete
  1622. MathJax.Hub.Startup = {
  1623. script: "", // the startup script from the SCRIPT call that loads MathJax.js
  1624. queue: MathJax.Callback.Queue(), // Queue used for startup actions
  1625. signal: MathJax.Callback.Signal("Startup"), // Signal used for startup events
  1626. params: {},
  1627. //
  1628. // Load the configuration files
  1629. //
  1630. Config: function () {
  1631. this.queue.Push(["Post",this.signal,"Begin Config"]);
  1632. //
  1633. // Check for user cookie configuration
  1634. //
  1635. var user = MathJax.HTML.Cookie.Get("user");
  1636. if (user.URL || user.Config) {
  1637. if (confirm(
  1638. "MathJax has found a user-configuration cookie that includes code to be run. " +
  1639. "Do you want to run it?\n\n"+
  1640. "(You should press Cancel unless you set up the cookie yourself.)"
  1641. )) {
  1642. if (user.URL) {this.queue.Push(["Require",MathJax.Ajax,user.URL])}
  1643. if (user.Config) {this.queue.Push(new Function(user.Config))}
  1644. } else {MathJax.HTML.Cookie.Set("user",{})}
  1645. }
  1646. //
  1647. // Run the config files, if any are given in the parameter list
  1648. //
  1649. if (this.params.config) {
  1650. var files = this.params.config.split(/,/);
  1651. for (var i = 0, m = files.length; i < m; i++) {
  1652. if (!files[i].match(/\.js$/)) {files[i] += ".js"}
  1653. this.queue.Push(["Require",MathJax.Ajax,this.URL("config",files[i])]);
  1654. }
  1655. }
  1656. //
  1657. // Run the deprecated configuration script, if any (ignoring return value)
  1658. // Wait for the startup delay signal
  1659. // Run the mathjax-config blocks
  1660. // Handle the default configuration (v1.0 compatible)
  1661. // Load the files in the configuration's config array
  1662. //
  1663. if (this.script.match(/\S/)) {this.queue.Push(this.script+";\n1;")}
  1664. this.queue.Push(
  1665. ["ConfigDelay",this],
  1666. ["ConfigBlocks",this],
  1667. ["ConfigDefault",this],
  1668. [function (THIS) {return THIS.loadArray(MathJax.Hub.config.config,"config",null,true)},this],
  1669. ["Post",this.signal,"End Config"]
  1670. );
  1671. },
  1672. //
  1673. // Return the delay callback
  1674. //
  1675. ConfigDelay: function () {
  1676. var delay = this.params.delayStartupUntil || MathJax.Hub.config.delayStartupUntil;
  1677. if (delay === "onload") {return this.onload}
  1678. if (delay === "configured") {return MathJax.Hub.Configured}
  1679. return delay;
  1680. },
  1681. //
  1682. // Run the scipts of type=text/x-mathajx-config
  1683. //
  1684. ConfigBlocks: function () {
  1685. var scripts = document.getElementsByTagName("script");
  1686. var last = null, queue = MathJax.Callback.Queue();
  1687. for (var i = 0, m = scripts.length; i < m; i++) {
  1688. var type = String(scripts[i].type).replace(/ /g,"");
  1689. if (type.match(/^text\/x-mathjax-config(;.*)?$/) && !type.match(/;executed=true/)) {
  1690. scripts[i].type += ";executed=true";
  1691. last = queue.Push(scripts[i].innerHTML+";\n1;");
  1692. }
  1693. }
  1694. return last;
  1695. },
  1696. //
  1697. // Check for v1.0 no-configuration and put up a warning message.
  1698. //
  1699. ConfigDefault: function () {
  1700. var CONFIG = MathJax.Hub.config;
  1701. if (CONFIG["v1.0-compatible"] && (CONFIG.jax||[]).length === 0 &&
  1702. !this.params.config && (CONFIG.config||[]).length === 0)
  1703. {return MathJax.Ajax.Require(this.URL("extensions","v1.0-warning.js"))}
  1704. },
  1705. //
  1706. // Read cookie and set up menu defaults
  1707. // (adjust the jax to accommodate renderer preferences)
  1708. //
  1709. Cookie: function () {
  1710. return this.queue.Push(
  1711. ["Post",this.signal,"Begin Cookie"],
  1712. ["Get",MathJax.HTML.Cookie,"menu",MathJax.Hub.config.menuSettings],
  1713. [function (config) {
  1714. var renderer = config.menuSettings.renderer, jax = config.jax;
  1715. if (renderer) {
  1716. var name = "output/"+renderer; jax.sort();
  1717. for (var i = 0, m = jax.length; i < m; i++) {
  1718. if (jax[i].substr(0,7) === "output/") break;
  1719. }
  1720. if (i == m-1) {jax.pop()} else {
  1721. while (i < m) {if (jax[i] === name) {jax.splice(i,1); break}; i++}
  1722. }
  1723. jax.unshift(name);
  1724. }
  1725. },MathJax.Hub.config],
  1726. ["Post",this.signal,"End Cookie"]
  1727. );
  1728. },
  1729. //
  1730. // Setup stylesheets and extra styles
  1731. //
  1732. Styles: function () {
  1733. return this.queue.Push(
  1734. ["Post",this.signal,"Begin Styles"],
  1735. ["loadArray",this,MathJax.Hub.config.styleSheets,"config"],
  1736. ["Styles",MathJax.Ajax,MathJax.Hub.config.styles],
  1737. ["Post",this.signal,"End Styles"]
  1738. );
  1739. },
  1740. //
  1741. // Load the input and output jax
  1742. //
  1743. Jax: function () {
  1744. var config = MathJax.Hub.config, jax = MathJax.Hub.outputJax;
  1745. // Save the order of the output jax since they are loading asynchronously
  1746. for (var i = 0, m = config.jax.length, k = 0; i < m; i++) {
  1747. var name = config.jax[i].substr(7);
  1748. if (config.jax[i].substr(0,7) === "output/" && jax.order[name] == null)
  1749. {jax.order[name] = k; k++}
  1750. }
  1751. var queue = MathJax.Callback.Queue();
  1752. return queue.Push(
  1753. ["Post",this.signal,"Begin Jax"],
  1754. ["loadArray",this,config.jax,"jax","config.js"],
  1755. ["Post",this.signal,"End Jax"]
  1756. );
  1757. },
  1758. //
  1759. // Load the extensions
  1760. //
  1761. Extensions: function () {
  1762. var queue = MathJax.Callback.Queue();
  1763. return queue.Push(
  1764. ["Post",this.signal,"Begin Extensions"],
  1765. ["loadArray",this,MathJax.Hub.config.extensions,"extensions"],
  1766. ["Post",this.signal,"End Extensions"]
  1767. );
  1768. },
  1769. //
  1770. // Initialize the Message system
  1771. //
  1772. Message: function () {
  1773. MathJax.Message.Init(true);
  1774. },
  1775. //
  1776. // Set the math menu renderer, if it isn't already
  1777. // (this must come after the jax are loaded)
  1778. //
  1779. Menu: function () {
  1780. var menu = MathJax.Hub.config.menuSettings, jax = MathJax.Hub.outputJax, registered;
  1781. for (var id in jax) {if (jax.hasOwnProperty(id)) {
  1782. if (jax[id].length) {registered = jax[id]; break}
  1783. }}
  1784. if (registered && registered.length) {
  1785. if (menu.renderer && menu.renderer !== registered[0].id)
  1786. {registered.unshift(MathJax.OutputJax[menu.renderer])}
  1787. menu.renderer = registered[0].id;
  1788. }
  1789. },
  1790. //
  1791. // Set the location to the designated hash position
  1792. //
  1793. Hash: function () {
  1794. if (MathJax.Hub.config.positionToHash && document.location.hash &&
  1795. document.body && document.body.scrollIntoView) {
  1796. var name = document.location.hash.substr(1);
  1797. var target = document.getElementById(name);
  1798. if (!target) {
  1799. var a = document.getElementsByTagName("a");
  1800. for (var i = 0, m = a.length; i < m; i++)
  1801. {if (a[i].name === name) {target = a[i]; break}}
  1802. }
  1803. if (target) {
  1804. while (!target.scrollIntoView) {target = target.parentNode}
  1805. target = this.HashCheck(target);
  1806. if (target && target.scrollIntoView)
  1807. {setTimeout(function () {target.scrollIntoView(true)},1)}
  1808. }
  1809. }
  1810. },
  1811. HashCheck: function (target) {
  1812. if (target.isMathJax) {
  1813. var jax = MathJax.Hub.getJaxFor(target);
  1814. if (jax && MathJax.OutputJax[jax.outputJax].hashCheck)
  1815. {target = MathJax.OutputJax[jax.outputJax].hashCheck(target)}
  1816. }
  1817. return target;
  1818. },
  1819. //
  1820. // Load the Menu and Zoom code, if it hasn't already been loaded.
  1821. // This is called after the initial typeset, so should no longer be
  1822. // competing with other page loads, but will make these available
  1823. // if needed later on.
  1824. //
  1825. MenuZoom: function () {
  1826. if (!MathJax.Extension.MathMenu) {
  1827. setTimeout(
  1828. MathJax.Callback(["Require",MathJax.Ajax,"[MathJax]/extensions/MathMenu.js",{}]),
  1829. 1000
  1830. );
  1831. }
  1832. if (!MathJax.Extension.MathZoom) {
  1833. setTimeout(
  1834. MathJax.Callback(["Require",MathJax.Ajax,"[MathJax]/extensions/MathZoom.js",{}]),
  1835. 2000
  1836. );
  1837. }
  1838. },
  1839. //
  1840. // Setup the onload callback
  1841. //
  1842. onLoad: function () {
  1843. var onload = this.onload =
  1844. MathJax.Callback(function () {MathJax.Hub.Startup.signal.Post("onLoad")});
  1845. if (document.body && document.readyState)
  1846. if (MathJax.Hub.Browser.isMSIE) {
  1847. // IE can change from loading to interactive before
  1848. // full page is ready, so go with complete (even though
  1849. // that means we may have to wait longer).
  1850. if (document.readyState === "complete") {return [onload]}
  1851. } else if (document.readyState !== "loading") {return [onload]}
  1852. if (window.addEventListener) {
  1853. window.addEventListener("load",onload,false);
  1854. if (!this.params.noDOMContentEvent)
  1855. {window.addEventListener("DOMContentLoaded",onload,false)}
  1856. }
  1857. else if (window.attachEvent) {window.attachEvent("onload",onload)}
  1858. else {window.onload = onload}
  1859. return onload;
  1860. },
  1861. //
  1862. // Perform the initial typesetting (or skip if configuration says to)
  1863. //
  1864. Typeset: function (element,callback) {
  1865. if (MathJax.Hub.config.skipStartupTypeset) {return function () {}}
  1866. return this.queue.Push(
  1867. ["Post",this.signal,"Begin Typeset"],
  1868. ["Typeset",MathJax.Hub,element,callback],
  1869. ["Post",this.signal,"End Typeset"]
  1870. );
  1871. },
  1872. //
  1873. // Create a URL in the MathJax hierarchy
  1874. //
  1875. URL: function (dir,name) {
  1876. if (!name.match(/^([a-z]+:\/\/|\[|\/)/)) {name = "[MathJax]/"+dir+"/"+name}
  1877. return name;
  1878. },
  1879. //
  1880. // Load an array of files, waiting for all of them
  1881. // to be loaded before going on
  1882. //
  1883. loadArray: function (files,dir,name,synchronous) {
  1884. if (files) {
  1885. if (!(files instanceof Array)) {files = [files]}
  1886. if (files.length) {
  1887. var queue = MathJax.Callback.Queue(), callback = {}, file;
  1888. for (var i = 0, m = files.length; i < m; i++) {
  1889. file = this.URL(dir,files[i]);
  1890. if (name) {file += "/" + name}
  1891. if (synchronous) {queue.Push(["Require",MathJax.Ajax,file,callback])}
  1892. else {queue.Push(MathJax.Ajax.Require(file,callback))}
  1893. }
  1894. return queue.Push({}); // wait for everything to finish
  1895. }
  1896. }
  1897. return null;
  1898. }
  1899. };
  1900. /**********************************************************/
  1901. (function (BASENAME) {
  1902. var BASE = window[BASENAME], ROOT = "["+BASENAME+"]";
  1903. var HUB = BASE.Hub, AJAX = BASE.Ajax, CALLBACK = BASE.Callback;
  1904. var JAX = MathJax.Object.Subclass({
  1905. JAXFILE: "jax.js",
  1906. require: null, // array of files to load before jax.js is complete
  1907. config: {},
  1908. //
  1909. // Make a subclass and return an instance of it.
  1910. // (FIXME: should we replace config with a copy of the constructor's
  1911. // config? Otherwise all subclasses share the same config structure.)
  1912. //
  1913. Init: function (def,cdef) {
  1914. if (arguments.length === 0) {return this}
  1915. return (this.constructor.Subclass(def,cdef))();
  1916. },
  1917. //
  1918. // Augment by merging with class definition (not replacing)
  1919. //
  1920. Augment: function (def,cdef) {
  1921. var cObject = this.constructor, ndef = {};
  1922. if (def != null) {
  1923. for (var id in def) {if (def.hasOwnProperty(id)) {
  1924. if (typeof def[id] === "function")
  1925. {cObject.protoFunction(id,def[id])} else {ndef[id] = def[id]}
  1926. }}
  1927. // MSIE doesn't list toString even if it is not native so handle it separately
  1928. if (def.toString !== cObject.prototype.toString && def.toString !== {}.toString)
  1929. {cObject.protoFunction('toString',def.toString)}
  1930. }
  1931. HUB.Insert(cObject.prototype,ndef);
  1932. cObject.Augment(null,cdef);
  1933. return this;
  1934. },
  1935. Translate: function (script,state) {
  1936. throw Error(this.directory+"/"+this.JAXFILE+" failed to define the Translate() method");
  1937. },
  1938. Register: function (mimetype) {},
  1939. Config: function () {
  1940. this.config = HUB.CombineConfig(this.id,this.config);
  1941. if (this.config.Augment) {this.Augment(this.config.Augment)}
  1942. },
  1943. Startup: function () {},
  1944. loadComplete: function (file) {
  1945. if (file === "config.js") {
  1946. return AJAX.loadComplete(this.directory+"/"+file);
  1947. } else {
  1948. var queue = CALLBACK.Queue();
  1949. queue.Push(
  1950. HUB.Register.StartupHook("End Config",{}), // wait until config complete
  1951. ["Post",HUB.Startup.signal,this.id+" Jax Config"],
  1952. ["Config",this],
  1953. ["Post",HUB.Startup.signal,this.id+" Jax Require"],
  1954. // Config may set the required and extensions array,
  1955. // so use functions to delay making the reference until needed
  1956. [function (THIS) {return MathJax.Hub.Startup.loadArray(THIS.require,this.directory)},this],
  1957. [function (config,id) {return MathJax.Hub.Startup.loadArray(config.extensions,"extensions/"+id)},this.config||{},this.id],
  1958. ["Post",HUB.Startup.signal,this.id+" Jax Startup"],
  1959. ["Startup",this],
  1960. ["Post",HUB.Startup.signal,this.id+" Jax Ready"]
  1961. );
  1962. if (this.copyTranslate) {
  1963. queue.Push(
  1964. [function (THIS) {
  1965. THIS.preProcess = THIS.preTranslate;
  1966. THIS.Process = THIS.Translate;
  1967. THIS.postProcess = THIS.postTranslate;
  1968. },this.constructor.prototype]
  1969. );
  1970. }
  1971. return queue.Push(["loadComplete",AJAX,this.directory+"/"+file]);
  1972. }
  1973. }
  1974. },{
  1975. id: "Jax",
  1976. version: "2.1",
  1977. directory: ROOT+"/jax",
  1978. extensionDir: ROOT+"/extensions"
  1979. });
  1980. /***********************************/
  1981. BASE.InputJax = JAX.Subclass({
  1982. elementJax: "mml", // the element jax to load for this input jax
  1983. copyTranslate: true,
  1984. Process: function (script,state) {
  1985. var queue = CALLBACK.Queue(), file;
  1986. // Load any needed element jax
  1987. var jax = this.elementJax; if (!(jax instanceof Array)) {jax = [jax]}
  1988. for (var i = 0, m = jax.length; i < m; i++) {
  1989. file = BASE.ElementJax.directory+"/"+jax[i]+"/"+this.JAXFILE;
  1990. if (!this.require) {this.require = []}
  1991. else if (!(this.require instanceof Array)) {this.require = [this.require]};
  1992. this.require.push(file); // so Startup will wait for it to be loaded
  1993. queue.Push(AJAX.Require(file));
  1994. }
  1995. // Load the input jax
  1996. file = this.directory+"/"+this.JAXFILE;
  1997. var load = queue.Push(AJAX.Require(file));
  1998. if (!load.called) {
  1999. this.constructor.prototype.Process = function () {
  2000. if (!load.called) {return load}
  2001. throw Error(file+" failed to load properly");
  2002. }
  2003. }
  2004. // Load the associated output jax
  2005. jax = HUB.outputJax["jax/"+jax[0]];
  2006. if (jax) {queue.Push(AJAX.Require(jax[0].directory+"/"+this.JAXFILE))}
  2007. return queue.Push({});
  2008. },
  2009. needsUpdate: function (jax) {
  2010. var script = jax.SourceElement();
  2011. return (jax.originalText !== BASE.HTML.getScript(script));
  2012. },
  2013. Register: function (mimetype) {
  2014. if (!HUB.inputJax) {HUB.inputJax = {}}
  2015. HUB.inputJax[mimetype] = this;
  2016. }
  2017. },{
  2018. id: "InputJax",
  2019. version: "2.1",
  2020. directory: JAX.directory+"/input",
  2021. extensionDir: JAX.extensionDir
  2022. });
  2023. /***********************************/
  2024. BASE.OutputJax = JAX.Subclass({
  2025. copyTranslate: true,
  2026. preProcess: function (state) {
  2027. var load, file = this.directory+"/"+this.JAXFILE;
  2028. this.constructor.prototype.preProcess = function (state) {
  2029. if (!load.called) {return load}
  2030. throw Error(file+" failed to load properly");
  2031. }
  2032. load = AJAX.Require(file);
  2033. return load;
  2034. },
  2035. Register: function (mimetype) {
  2036. var jax = HUB.outputJax;
  2037. if (!jax[mimetype]) {jax[mimetype] = []}
  2038. // If the output jax is earlier in the original configuration list, put it first here
  2039. if (jax[mimetype].length && (this.id === HUB.config.menuSettings.renderer ||
  2040. (jax.order[this.id]||0) < (jax.order[jax[mimetype][0].id]||0)))
  2041. {jax[mimetype].unshift(this)} else {jax[mimetype].push(this)}
  2042. // Make sure the element jax is loaded before Startup is called
  2043. if (!this.require) {this.require = []}
  2044. else if (!(this.require instanceof Array)) {this.require = [this.require]};
  2045. this.require.push(BASE.ElementJax.directory+"/"+(mimetype.split(/\//)[1])+"/"+this.JAXFILE);
  2046. },
  2047. Remove: function (jax) {}
  2048. },{
  2049. id: "OutputJax",
  2050. version: "2.1",
  2051. directory: JAX.directory+"/output",
  2052. extensionDir: JAX.extensionDir,
  2053. fontDir: ROOT+(BASE.isPacked?"":"/..")+"/fonts",
  2054. imageDir: ROOT+(BASE.isPacked?"":"/..")+"/images"
  2055. });
  2056. /***********************************/
  2057. BASE.ElementJax = JAX.Subclass({
  2058. // make a subclass, not an instance
  2059. Init: function (def,cdef) {return this.constructor.Subclass(def,cdef)},
  2060. inputJax: null,
  2061. outputJax: null,
  2062. inputID: null,
  2063. originalText: "",
  2064. mimeType: "",
  2065. Text: function (text,callback) {
  2066. var script = this.SourceElement();
  2067. BASE.HTML.setScript(script,text);
  2068. script.MathJax.state = this.STATE.UPDATE;
  2069. return HUB.Update(script,callback);
  2070. },
  2071. Reprocess: function (callback) {
  2072. var script = this.SourceElement();
  2073. script.MathJax.state = this.STATE.UPDATE;
  2074. return HUB.Reprocess(script,callback);
  2075. },
  2076. Update: function (callback) {return this.Rerender(callback)},
  2077. Rerender: function (callback) {
  2078. var script = this.SourceElement();
  2079. script.MathJax.state = this.STATE.OUTPUT;
  2080. return HUB.Process(script,callback);
  2081. },
  2082. Remove: function (keep) {
  2083. if (this.hover) {this.hover.clear(this)}
  2084. BASE.OutputJax[this.outputJax].Remove(this);
  2085. if (!keep) {
  2086. HUB.signal.Post(["Remove Math",this.inputID]); // wait for this to finish?
  2087. this.Detach();
  2088. }
  2089. },
  2090. needsUpdate: function () {
  2091. return BASE.InputJax[this.inputJax].needsUpdate(this);
  2092. },
  2093. SourceElement: function () {return document.getElementById(this.inputID)},
  2094. Attach: function (script,inputJax) {
  2095. var jax = script.MathJax.elementJax;
  2096. if (script.MathJax.state === this.STATE.UPDATE) {
  2097. jax.Clone(this);
  2098. } else {
  2099. jax = script.MathJax.elementJax = this;
  2100. if (script.id) {this.inputID = script.id}
  2101. else {script.id = this.inputID = BASE.ElementJax.GetID(); this.newID = 1}
  2102. }
  2103. jax.originalText = BASE.HTML.getScript(script);
  2104. jax.inputJax = inputJax;
  2105. if (jax.root) {jax.root.inputID = jax.inputID}
  2106. return jax;
  2107. },
  2108. Detach: function () {
  2109. var script = this.SourceElement(); if (!script) return;
  2110. try {delete script.MathJax} catch(err) {script.MathJax = null}
  2111. if (this.newID) {script.id = ""}
  2112. },
  2113. Clone: function (jax) {
  2114. var id;
  2115. for (id in this) {
  2116. if (!this.hasOwnProperty(id)) continue;
  2117. if (typeof(jax[id]) === 'undefined' && id !== 'newID') {delete this[id]}
  2118. }
  2119. for (id in jax) {
  2120. if (!jax.hasOwnProperty(id)) continue;
  2121. if (typeof(this[id]) === 'undefined' || (this[id] !== jax[id] && id !== 'inputID'))
  2122. {this[id] = jax[id]}
  2123. }
  2124. }
  2125. },{
  2126. id: "ElementJax",
  2127. version: "2.1",
  2128. directory: JAX.directory+"/element",
  2129. extensionDir: JAX.extensionDir,
  2130. ID: 0, // jax counter (for IDs)
  2131. STATE: {
  2132. PENDING: 1, // script is identified as math but not yet processed
  2133. PROCESSED: 2, // script has been processed
  2134. UPDATE: 3, // elementJax should be updated
  2135. OUTPUT: 4 // output should be updated (input is OK)
  2136. },
  2137. GetID: function () {this.ID++; return "MathJax-Element-"+this.ID},
  2138. Subclass: function () {
  2139. var obj = JAX.Subclass.apply(this,arguments);
  2140. obj.loadComplete = this.prototype.loadComplete;
  2141. return obj;
  2142. }
  2143. });
  2144. BASE.ElementJax.prototype.STATE = BASE.ElementJax.STATE;
  2145. //
  2146. // Some "Fake" jax used to allow menu access for "Math Processing Error" messages
  2147. //
  2148. BASE.OutputJax.Error = {
  2149. id: "Error", version: "2.1", config: {},
  2150. ContextMenu: function () {return BASE.Extension.MathEvents.Event.ContextMenu.apply(BASE.Extension.MathEvents.Event,arguments)},
  2151. Mousedown: function () {return BASE.Extension.MathEvents.Event.AltContextMenu.apply(BASE.Extension.MathEvents.Event,arguments)},
  2152. getJaxFromMath: function () {return {inputJax:"Error", outputJax:"Error", originalText:"Math Processing Error"}}
  2153. };
  2154. BASE.InputJax.Error = {
  2155. id: "Error", version: "2.1", config: {},
  2156. sourceMenuTitle: "Error Message"
  2157. };
  2158. })("MathJax");
  2159. /**********************************************************/
  2160. (function (BASENAME) {
  2161. var BASE = window[BASENAME];
  2162. if (!BASE) {BASE = window[BASENAME] = {}}
  2163. var HUB = BASE.Hub; var STARTUP = HUB.Startup; var CONFIG = HUB.config;
  2164. var HEAD = document.getElementsByTagName("head")[0];
  2165. if (!HEAD) {HEAD = document.childNodes[0]};
  2166. var scripts = (document.documentElement || document).getElementsByTagName("script");
  2167. var namePattern = new RegExp("(^|/)"+BASENAME+"\\.js(\\?.*)?$");
  2168. for (var i = scripts.length-1; i >= 0; i--) {
  2169. if ((scripts[i].src||"").match(namePattern)) {
  2170. STARTUP.script = scripts[i].innerHTML;
  2171. if (RegExp.$2) {
  2172. var params = RegExp.$2.substr(1).split(/\&/);
  2173. for (var j = 0, m = params.length; j < m; j++) {
  2174. var KV = params[j].match(/(.*)=(.*)/);
  2175. if (KV) {STARTUP.params[unescape(KV[1])] = unescape(KV[2])}
  2176. }
  2177. }
  2178. CONFIG.root = scripts[i].src.replace(/(^|\/)[^\/]*(\?.*)?$/,'');
  2179. break;
  2180. }
  2181. }
  2182. BASE.Ajax.config = CONFIG;
  2183. var BROWSERS = {
  2184. isMac: (navigator.platform.substr(0,3) === "Mac"),
  2185. isPC: (navigator.platform.substr(0,3) === "Win"),
  2186. isMSIE: (window.ActiveXObject != null && window.clipboardData != null),
  2187. isFirefox: ((window.netscape != null || window.mozPaintCount != null) &&
  2188. document.ATTRIBUTE_NODE != null && !window.opera),
  2189. isSafari: (navigator.userAgent.match(/ (Apple)?WebKit\//) != null &&
  2190. (!window.chrome || window.chrome.loadTimes == null)),
  2191. isChrome: (window.chrome != null && window.chrome.loadTimes != null),
  2192. isOpera: (window.opera != null && window.opera.version != null),
  2193. isKonqueror: (window.hasOwnProperty && window.hasOwnProperty("konqueror") && navigator.vendor == "KDE"),
  2194. versionAtLeast: function (v) {
  2195. var bv = (this.version).split('.'); v = (new String(v)).split('.');
  2196. for (var i = 0, m = v.length; i < m; i++)
  2197. {if (bv[i] != v[i]) {return parseInt(bv[i]||"0") >= parseInt(v[i])}}
  2198. return true;
  2199. },
  2200. Select: function (choices) {
  2201. var browser = choices[HUB.Browser];
  2202. if (browser) {return browser(HUB.Browser)}
  2203. return null;
  2204. }
  2205. };
  2206. var AGENT = navigator.userAgent
  2207. .replace(/^Mozilla\/(\d+\.)+\d+ /,"") // remove initial Mozilla, which is never right
  2208. .replace(/[a-z][-a-z0-9._: ]+\/\d+[^ ]*-[^ ]*\.([a-z][a-z])?\d+ /i,"") // remove linux version
  2209. .replace(/Gentoo |Ubuntu\/(\d+\.)*\d+ (\([^)]*\) )?/,""); // special case for these
  2210. HUB.Browser = HUB.Insert(HUB.Insert(new String("Unknown"),{version: "0.0"}),BROWSERS);
  2211. for (var browser in BROWSERS) {if (BROWSERS.hasOwnProperty(browser)) {
  2212. if (BROWSERS[browser] && browser.substr(0,2) === "is") {
  2213. browser = browser.slice(2);
  2214. if (browser === "Mac" || browser === "PC") continue;
  2215. HUB.Browser = HUB.Insert(new String(browser),BROWSERS);
  2216. var VERSION = new RegExp(
  2217. ".*(Version)/((?:\\d+\\.)+\\d+)|" + // for Safari and Opera10
  2218. ".*("+browser+")"+(browser == "MSIE" ? " " : "/")+"((?:\\d+\\.)*\\d+)|"+ // for one of the main browser
  2219. "(?:^|\\(| )([a-z][-a-z0-9._: ]+|(?:Apple)?WebKit)/((?:\\d+\\.)+\\d+)"); // for unrecognized browser
  2220. var MATCH = VERSION.exec(AGENT) || ["","","","unknown","0.0"];
  2221. HUB.Browser.name = (MATCH[1] == "Version" ? browser : (MATCH[3] || MATCH[5]));
  2222. HUB.Browser.version = MATCH[2] || MATCH[4] || MATCH[6];
  2223. break;
  2224. }
  2225. }};
  2226. //
  2227. // Initial browser-specific info (e.g., touch up version or name)
  2228. //
  2229. HUB.Browser.Select({
  2230. Safari: function (browser) {
  2231. var v = parseInt((String(browser.version).split("."))[0]);
  2232. if (v > 85) {browser.webkit = browser.version}
  2233. if (v >= 534) {browser.version = "5.1"}
  2234. else if (v >= 533) {browser.version = "5.0"}
  2235. else if (v >= 526) {browser.version = "4.0"}
  2236. else if (v >= 525) {browser.version = "3.1"}
  2237. else if (v > 500) {browser.version = "3.0"}
  2238. else if (v > 400) {browser.version = "2.0"}
  2239. else if (v > 85) {browser.version = "1.0"}
  2240. browser.isMobile = (navigator.appVersion.match(/Mobile/i) != null);
  2241. browser.noContextMenu = browser.isMobile;
  2242. },
  2243. Firefox: function (browser) {
  2244. if ((browser.version === "0.0" || navigator.userAgent.match(/Firefox/) == null) &&
  2245. navigator.product === "Gecko") {
  2246. var rv = navigator.userAgent.match(/[\/ ]rv:(\d+\.\d.*?)[\) ]/);
  2247. if (rv) {browser.version = rv[1]}
  2248. else {
  2249. var date = (navigator.buildID||navigator.productSub||"0").substr(0,8);
  2250. if (date >= "20111220") {browser.version = "9.0"}
  2251. else if (date >= "20111120") {browser.version = "8.0"}
  2252. else if (date >= "20110927") {browser.version = "7.0"}
  2253. else if (date >= "20110816") {browser.version = "6.0"}
  2254. else if (date >= "20110621") {browser.version = "5.0"}
  2255. else if (date >= "20110320") {browser.version = "4.0"}
  2256. else if (date >= "20100121") {browser.version = "3.6"}
  2257. else if (date >= "20090630") {browser.version = "3.5"}
  2258. else if (date >= "20080617") {browser.version = "3.0"}
  2259. else if (date >= "20061024") {browser.version = "2.0"}
  2260. }
  2261. }
  2262. browser.isMobile = (navigator.appVersion.match(/Android/i) != null ||
  2263. navigator.userAgent.match(/ Fennec\//) != null);
  2264. },
  2265. Opera: function (browser) {browser.version = opera.version()},
  2266. MSIE: function (browser) {
  2267. browser.isIE9 = !!(document.documentMode && (window.performance || window.msPerformance));
  2268. MathJax.HTML.setScriptBug = !browser.isIE9 || document.documentMode < 9;
  2269. var MathPlayer = false;
  2270. try {new ActiveXObject("MathPlayer.Factory.1"); browser.hasMathPlayer = MathPlayer = true}
  2271. catch (err) {}
  2272. try {
  2273. if (MathPlayer && !STARTUP.params.NoMathPlayer) {
  2274. var mathplayer = document.createElement("object");
  2275. mathplayer.id = "mathplayer"; mathplayer.classid = "clsid:32F66A20-7614-11D4-BD11-00104BD3F987";
  2276. document.getElementsByTagName("head")[0].appendChild(mathplayer);
  2277. document.namespaces.add("m","http://www.w3.org/1998/Math/MathML");
  2278. browser.mpNamespace = true;
  2279. if (document.readyState && (document.readyState === "loading" ||
  2280. document.readyState === "interactive")) {
  2281. document.write('<?import namespace="m" implementation="#MathPlayer">');
  2282. browser.mpImported = true;
  2283. }
  2284. } else {
  2285. // Adding any namespace avoids a crash in IE9 in IE9-standards mode
  2286. // (any reference to document.namespaces before document.readyState is
  2287. // "complete" causes an "unspecified error" to be thrown)
  2288. document.namespaces.add("mjx_IE_fix","http://www.w3.org/1999/xlink");
  2289. }
  2290. } catch (err) {}
  2291. }
  2292. });
  2293. HUB.Browser.Select(MathJax.Message.browsers);
  2294. HUB.queue = BASE.Callback.Queue();
  2295. HUB.queue.Push(
  2296. ["Post",STARTUP.signal,"Begin"],
  2297. ["Config",STARTUP],
  2298. ["Cookie",STARTUP],
  2299. ["Styles",STARTUP],
  2300. ["Message",STARTUP],
  2301. function () {
  2302. // Do Jax and Extensions in parallel, but wait for them all to complete
  2303. var queue = BASE.Callback.Queue(
  2304. STARTUP.Jax(),
  2305. STARTUP.Extensions()
  2306. );
  2307. return queue.Push({});
  2308. },
  2309. ["Menu",STARTUP],
  2310. STARTUP.onLoad(),
  2311. function () {MathJax.isReady = true}, // indicates that MathJax is ready to process math
  2312. ["Typeset",STARTUP],
  2313. ["Hash",STARTUP],
  2314. ["MenuZoom",STARTUP],
  2315. ["Post",STARTUP.signal,"End"]
  2316. );
  2317. })("MathJax");
  2318. }}
  2319. /**********************************************************/