MathJax.js 70 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943
  1. var MathJax = {debug:true};
  2. var window = {
  3. MathJax: MathJax
  4. };
  5. var navigator = {};
  6. var document = null;
  7. exports.MathJax = MathJax;
  8. (function (BASENAME) {
  9. var BASE = window[BASENAME];
  10. if (!BASE) {BASE = window[BASENAME] = {}}
  11. var PROTO = []; // a static object used to indicate when a prototype is being created
  12. var OBJECT = function (def) {
  13. var obj = def.constructor; if (!obj) {obj = function () {}}
  14. for (var id in def) {if (id !== 'constructor' && def.hasOwnProperty(id)) {obj[id] = def[id]}}
  15. return obj;
  16. };
  17. var CONSTRUCTOR = function () {
  18. return function () {return arguments.callee.Init.call(this,arguments)};
  19. };
  20. BASE.Object = OBJECT({
  21. constructor: CONSTRUCTOR(),
  22. Subclass: function (def,classdef) {
  23. var obj = CONSTRUCTOR();
  24. obj.SUPER = this; obj.Init = this.Init;
  25. obj.Subclass = this.Subclass; obj.Augment = this.Augment;
  26. obj.protoFunction = this.protoFunction;
  27. obj.can = this.can; obj.has = this.has; obj.isa = this.isa;
  28. obj.prototype = new this(PROTO);
  29. obj.prototype.constructor = obj; // the real constructor
  30. obj.Augment(def,classdef);
  31. return obj;
  32. },
  33. Init: function (args) {
  34. var obj = this;
  35. if (args.length === 1 && args[0] === PROTO) {return obj}
  36. if (!(obj instanceof args.callee)) {obj = new args.callee(PROTO)}
  37. return obj.Init.apply(obj,args) || obj;
  38. },
  39. Augment: function (def,classdef) {
  40. var id;
  41. if (def != null) {
  42. for (id in def) {if (def.hasOwnProperty(id)) {this.protoFunction(id,def[id])}}
  43. // MSIE doesn't list toString even if it is not native so handle it separately
  44. if (def.toString !== this.prototype.toString && def.toString !== {}.toString)
  45. {this.protoFunction('toString',def.toString)}
  46. }
  47. if (classdef != null) {
  48. for (id in classdef) {if (classdef.hasOwnProperty(id)) {this[id] = classdef[id]}}
  49. }
  50. return this;
  51. },
  52. protoFunction: function (id,def) {
  53. this.prototype[id] = def;
  54. if (typeof def === "function") {def.SUPER = this.SUPER.prototype}
  55. },
  56. prototype: {
  57. Init: function () {},
  58. SUPER: function (fn) {return fn.callee.SUPER},
  59. can: function (method) {return typeof(this[method]) === "function"},
  60. has: function (property) {return typeof(this[property]) !== "undefined"},
  61. isa: function (obj) {return (obj instanceof Object) && (this instanceof obj)}
  62. },
  63. can: function (method) {return this.prototype.can.call(this,method)},
  64. has: function (property) {return this.prototype.has.call(this,property)},
  65. isa: function (obj) {
  66. var constructor = this;
  67. while (constructor) {
  68. if (constructor === obj) {return true} else {constructor = constructor.SUPER}
  69. }
  70. return false;
  71. },
  72. SimpleSUPER: OBJECT({
  73. constructor: function (def) {return this.SimpleSUPER.define(def)},
  74. define: function (src) {
  75. var dst = {};
  76. if (src != null) {
  77. for (var id in src) {if (src.hasOwnProperty(id)) {dst[id] = this.wrap(id,src[id])}}
  78. // MSIE doesn't list toString even if it is not native so handle it separately
  79. if (src.toString !== this.prototype.toString && src.toString !== {}.toString)
  80. {dst.toString = this.wrap('toString',src.toString)}
  81. }
  82. return dst;
  83. },
  84. wrap: function (id,f) {
  85. if (typeof(f) !== 'function' || !f.toString().match(/\.\s*SUPER\s*\(/)) {return f}
  86. var fn = function () {
  87. this.SUPER = fn.SUPER[id];
  88. try {var result = f.apply(this,arguments)} catch (err) {delete this.SUPER; throw err}
  89. delete this.SUPER;
  90. return result;
  91. }
  92. fn.toString = function () {return f.toString.apply(f,arguments)}
  93. return fn;
  94. }
  95. })
  96. });
  97. BASE.Object.isArray = Array.isArray || function (obj) {
  98. return Object.prototype.toString.call(obj) === "[object Array]";
  99. };
  100. BASE.Object.Array = Array;
  101. })("MathJax");
  102. /**********************************************************/
  103. /*
  104. * Create a callback function from various forms of data:
  105. *
  106. * MathJax.Callback(fn) -- callback to a function
  107. *
  108. * MathJax.Callback([fn]) -- callback to function
  109. * MathJax.Callback([fn,data...])
  110. * -- callback to function with given data as arguments
  111. * MathJax.Callback([object,fn])
  112. * -- call fn with object as "this"
  113. * MathJax.Callback([object,fn,data...])
  114. * -- call fn with object as "this" and data as arguments
  115. * MathJax.Callback(["method",object])
  116. * -- call method of object wth object as "this"
  117. * MathJax.Callback(["method",object,data...])
  118. * -- as above, but with data as arguments to method
  119. *
  120. * MathJax.Callback({hook: fn, data: [...], object: this})
  121. * -- give function, data, and object to act as "this" explicitly
  122. *
  123. * MathJax.Callback("code") -- callback that compiles and executes a string
  124. *
  125. * MathJax.Callback([...],i)
  126. * -- use slice of array starting at i and interpret
  127. * result as above. (Used for passing "arguments" array
  128. * and trimming initial arguments, if any.)
  129. */
  130. /*
  131. * MathJax.Callback.After([...],cb1,cb2,...)
  132. * -- make a callback that isn't called until all the other
  133. * ones are called first. I.e., wait for a union of
  134. * callbacks to occur before making the given callback.
  135. */
  136. /*
  137. * MathJax.Callback.Queue([callback,...])
  138. * -- make a synchronized queue of commands that process
  139. * sequentially, waiting for those that return uncalled
  140. * callbacks.
  141. */
  142. /*
  143. * MathJax.Callback.Signal(name)
  144. * -- finds or creates a names signal, to which listeners
  145. * can be attached and are signaled by messages posted
  146. * to the signal. Responses can be asynchronous.
  147. */
  148. (function (BASENAME) {
  149. var BASE = window[BASENAME];
  150. if (!BASE) {BASE = window[BASENAME] = {}}
  151. //
  152. // Create a callback from an associative array
  153. //
  154. var CALLBACK = function (data) {
  155. var cb = function () {return arguments.callee.execute.apply(arguments.callee,arguments)};
  156. for (var id in CALLBACK.prototype) {
  157. if (CALLBACK.prototype.hasOwnProperty(id)) {
  158. if (typeof(data[id]) !== 'undefined') {cb[id] = data[id]}
  159. else {cb[id] = CALLBACK.prototype[id]}
  160. }
  161. }
  162. cb.toString = CALLBACK.prototype.toString;
  163. return cb;
  164. };
  165. CALLBACK.prototype = {
  166. isCallback: true,
  167. hook: function () {},
  168. data: [],
  169. object: window,
  170. execute: function () {
  171. if (!this.called || this.autoReset) {
  172. this.called = !this.autoReset;
  173. return this.hook.apply(this.object,this.data.concat([].slice.call(arguments,0)));
  174. }
  175. },
  176. reset: function () {delete this.called},
  177. toString: function () {return this.hook.toString.apply(this.hook,arguments)}
  178. };
  179. var ISCALLBACK = function (f) {
  180. return (typeof(f) === "function" && f.isCallback);
  181. }
  182. //
  183. // Evaluate a string in global context
  184. //
  185. var EVAL = function (code) {return eval.call(window,code)}
  186. var TESTEVAL = function () {
  187. EVAL("var __TeSt_VaR__ = 1"); // check if it works in global context
  188. if (window.__TeSt_VaR__) {
  189. try { delete window.__TeSt_VaR__; } // NOTE IE9 throws when in IE7 mode
  190. catch (error) { window.__TeSt_VaR__ = null; }
  191. } else {
  192. if (window.execScript) {
  193. // IE
  194. EVAL = function (code) {
  195. BASE.__code = code;
  196. code = "try {"+BASENAME+".__result = eval("+BASENAME+".__code)} catch(err) {"+BASENAME+".__result = err}";
  197. window.execScript(code);
  198. var result = BASE.__result; delete BASE.__result; delete BASE.__code;
  199. if (result instanceof Error) {throw result}
  200. return result;
  201. }
  202. } else {
  203. // Safari2
  204. EVAL = function (code) {
  205. BASE.__code = code;
  206. code = "try {"+BASENAME+".__result = eval("+BASENAME+".__code)} catch(err) {"+BASENAME+".__result = err}";
  207. var head = (document.getElementsByTagName("head"))[0]; if (!head) {head = document.body}
  208. var script = document.createElement("script");
  209. script.appendChild(document.createTextNode(code));
  210. head.appendChild(script); head.removeChild(script);
  211. var result = BASE.__result; delete BASE.__result; delete BASE.__code;
  212. if (result instanceof Error) {throw result}
  213. return result;
  214. }
  215. }
  216. }
  217. TESTEVAL = null;
  218. }
  219. //
  220. // Create a callback from various types of data
  221. //
  222. var USING = function (args,i) {
  223. if (arguments.length > 1) {
  224. if (arguments.length === 2 && !(typeof arguments[0] === 'function') &&
  225. arguments[0] instanceof Object && typeof arguments[1] === 'number')
  226. {args = [].slice.call(args,i)}
  227. else {args = [].slice.call(arguments,0)}
  228. }
  229. if (args instanceof Array && args.length === 1) {args = args[0]}
  230. if (typeof args === 'function') {
  231. if (args.execute === CALLBACK.prototype.execute) {return args}
  232. return CALLBACK({hook: args});
  233. } else if (args instanceof Array) {
  234. if (typeof(args[0]) === 'string' && args[1] instanceof Object &&
  235. typeof args[1][args[0]] === 'function') {
  236. return CALLBACK({hook: args[1][args[0]], object: args[1], data: args.slice(2)});
  237. } else if (typeof args[0] === 'function') {
  238. return CALLBACK({hook: args[0], data: args.slice(1)});
  239. } else if (typeof args[1] === 'function') {
  240. return CALLBACK({hook: args[1], object: args[0], data: args.slice(2)});
  241. }
  242. } else if (typeof(args) === 'string') {
  243. if (TESTEVAL) TESTEVAL();
  244. return CALLBACK({hook: EVAL, data: [args]});
  245. } else if (args instanceof Object) {
  246. return CALLBACK(args);
  247. } else if (typeof(args) === 'undefined') {
  248. return CALLBACK({});
  249. }
  250. throw Error("Can't make callback from given data");
  251. };
  252. //
  253. // Wait for a given time to elapse and then perform the callback
  254. //
  255. var DELAY = function (time,callback) {
  256. callback = USING(callback);
  257. callback.timeout = setTimeout(callback,time);
  258. return callback;
  259. };
  260. //
  261. // Callback used by AFTER, QUEUE, and SIGNAL to check if calls have completed
  262. //
  263. var WAITFOR = function (callback,signal) {
  264. callback = USING(callback);
  265. if (!callback.called) {WAITSIGNAL(callback,signal); signal.pending++}
  266. };
  267. var WAITEXECUTE = function () {
  268. var signals = this.signal; delete this.signal;
  269. this.execute = this.oldExecute; delete this.oldExecute;
  270. var result = this.execute.apply(this,arguments);
  271. if (ISCALLBACK(result) && !result.called) {WAITSIGNAL(result,signals)} else {
  272. for (var i = 0, m = signals.length; i < m; i++) {
  273. signals[i].pending--;
  274. if (signals[i].pending <= 0) {signals[i].call()}
  275. }
  276. }
  277. };
  278. var WAITSIGNAL = function (callback,signals) {
  279. if (!(signals instanceof Array)) {signals = [signals]}
  280. if (!callback.signal) {
  281. callback.oldExecute = callback.execute;
  282. callback.execute = WAITEXECUTE;
  283. callback.signal = signals;
  284. } else if (signals.length === 1) {callback.signal.push(signals[0])}
  285. else {callback.signal = callback.signal.concat(signals)}
  286. };
  287. //
  288. // Create a callback that is called when a collection of other callbacks have
  289. // all been executed. If the callback gets called immediately (i.e., the
  290. // others are all already called), check if it returns another callback
  291. // and return that instead.
  292. //
  293. var AFTER = function (callback) {
  294. callback = USING(callback);
  295. callback.pending = 0;
  296. for (var i = 1, m = arguments.length; i < m; i++)
  297. {if (arguments[i]) {WAITFOR(arguments[i],callback)}}
  298. if (callback.pending === 0) {
  299. var result = callback();
  300. if (ISCALLBACK(result)) {callback = result}
  301. }
  302. return callback;
  303. };
  304. //
  305. // An array of prioritized hooks that are executed sequentially
  306. // with a given set of data.
  307. //
  308. var HOOKS = MathJax.Object.Subclass({
  309. //
  310. // Initialize the array and the auto-reset status
  311. //
  312. Init: function (reset) {
  313. this.hooks = [];
  314. this.remove = []; // used when hooks are removed during execution of list
  315. this.reset = reset;
  316. this.running = false;
  317. },
  318. //
  319. // Add a callback to the list, in priority order (default priority is 10)
  320. //
  321. Add: function (hook,priority) {
  322. if (priority == null) {priority = 10}
  323. if (!ISCALLBACK(hook)) {hook = USING(hook)}
  324. hook.priority = priority;
  325. var i = this.hooks.length;
  326. while (i > 0 && priority < this.hooks[i-1].priority) {i--}
  327. this.hooks.splice(i,0,hook);
  328. return hook;
  329. },
  330. Remove: function (hook) {
  331. for (var i = 0, m = this.hooks.length; i < m; i++) {
  332. if (this.hooks[i] === hook) {
  333. if (this.running) {this.remove.push(i)}
  334. else {this.hooks.splice(i,1)}
  335. return;
  336. }
  337. }
  338. },
  339. //
  340. // Execute the list of callbacks, resetting them if requested.
  341. // If any return callbacks, return a callback that will be
  342. // executed when they all have completed.
  343. // Remove any hooks that requested being removed during processing.
  344. //
  345. Execute: function () {
  346. var callbacks = [{}];
  347. this.running = true;
  348. for (var i = 0, m = this.hooks.length; i < m; i++) {
  349. if (this.reset) {this.hooks[i].reset()}
  350. var result = this.hooks[i].apply(window,arguments);
  351. if (ISCALLBACK(result) && !result.called) {callbacks.push(result)}
  352. }
  353. this.running = false;
  354. if (this.remove.length) {this.RemovePending()}
  355. if (callbacks.length === 1) {return null}
  356. if (callbacks.length === 2) {return callbacks[1]}
  357. return AFTER.apply({},callbacks);
  358. },
  359. //
  360. // Remove hooks that asked to be removed during execution of list
  361. //
  362. RemovePending: function () {
  363. this.remove = this.remove.sort();
  364. for (var i = this.remove.length-1; i >= 0; i--) {this.hooks.splice(i,1)}
  365. this.remove = [];
  366. }
  367. });
  368. //
  369. // Run an array of callbacks passing them the given data.
  370. // (Legacy function, since this has been replaced by the HOOKS object).
  371. //
  372. var EXECUTEHOOKS = function (hooks,data,reset) {
  373. if (!hooks) {return null}
  374. if (!(hooks instanceof Array)) {hooks = [hooks]}
  375. if (!(data instanceof Array)) {data = (data == null ? [] : [data])}
  376. var handler = HOOKS(reset);
  377. for (var i = 0, m = hooks.length; i < m; i++) {handler.Add(hooks[i])}
  378. return handler.Execute.apply(handler,data);
  379. };
  380. //
  381. // Command queue that performs commands in order, waiting when
  382. // necessary for commands to complete asynchronousely
  383. //
  384. var QUEUE = BASE.Object.Subclass({
  385. //
  386. // Create the queue and push any commands that are specified
  387. //
  388. Init: function () {
  389. this.pending = this.running = 0;
  390. this.queue = [];
  391. this.Push.apply(this,arguments);
  392. },
  393. //
  394. // Add commands to the queue and run them. Adding a callback object
  395. // (rather than a callback specification) queues a wait for that callback.
  396. // Return the final callback for synchronization purposes.
  397. //
  398. Push: function () {
  399. var callback;
  400. for (var i = 0, m = arguments.length; i < m; i++) {
  401. callback = USING(arguments[i]);
  402. if (callback === arguments[i] && !callback.called)
  403. {callback = USING(["wait",this,callback])}
  404. this.queue.push(callback);
  405. }
  406. if (!this.running && !this.pending) {this.Process()}
  407. return callback;
  408. },
  409. //
  410. // Process the command queue if we aren't waiting on another command
  411. //
  412. Process: function (queue) {
  413. while (!this.running && !this.pending && this.queue.length) {
  414. var callback = this.queue[0];
  415. queue = this.queue.slice(1); this.queue = [];
  416. this.Suspend(); var result = callback(); this.Resume();
  417. if (queue.length) {this.queue = queue.concat(this.queue)}
  418. if (ISCALLBACK(result) && !result.called) {WAITFOR(result,this)}
  419. }
  420. },
  421. //
  422. // Suspend/Resume command processing on this queue
  423. //
  424. Suspend: function () {this.running++},
  425. Resume: function () {if (this.running) {this.running--}},
  426. //
  427. // Used by WAITFOR to restart the queue when an action completes
  428. //
  429. call: function () {this.Process.apply(this,arguments)},
  430. wait: function (callback) {return callback}
  431. });
  432. //
  433. // Create a named signal that listeners can attach to, to be signaled by
  434. // postings made to the signal. Posts are queued if they occur while one
  435. // is already in process.
  436. //
  437. var SIGNAL = QUEUE.Subclass({
  438. Init: function (name) {
  439. QUEUE.prototype.Init.call(this);
  440. this.name = name;
  441. this.posted = []; // the messages posted so far
  442. this.listeners = HOOKS(true); // those with interest in this signal
  443. this.posting = false;
  444. this.callback = null;
  445. },
  446. //
  447. // Post a message to the signal listeners, with callback for when complete
  448. //
  449. Post: function (message,callback,forget) {
  450. callback = USING(callback);
  451. if (this.posting || this.pending) {
  452. this.Push(["Post",this,message,callback,forget]);
  453. } else {
  454. this.callback = callback; callback.reset();
  455. if (!forget) {this.posted.push(message)}
  456. this.Suspend(); this.posting = true;
  457. var result = this.listeners.Execute(message);
  458. if (ISCALLBACK(result) && !result.called) {WAITFOR(result,this)}
  459. this.Resume(); this.posting = false;
  460. if (!this.pending) {this.call()}
  461. }
  462. return callback;
  463. },
  464. //
  465. // Clear the post history (so new listeners won't get old messages)
  466. //
  467. Clear: function (callback) {
  468. callback = USING(callback);
  469. if (this.posting || this.pending) {
  470. callback = this.Push(["Clear",this,callback]);
  471. } else {
  472. this.posted = [];
  473. callback();
  474. }
  475. return callback;
  476. },
  477. //
  478. // Call the callback (all replies are in) and process the command queue
  479. //
  480. call: function () {this.callback(this); this.Process()},
  481. //
  482. // A listener calls this to register interest in the signal (so it will be called
  483. // when posts occur). If ignorePast is true, it will not be sent the post history.
  484. //
  485. Interest: function (callback,ignorePast,priority) {
  486. callback = USING(callback);
  487. this.listeners.Add(callback,priority);
  488. if (!ignorePast) {
  489. for (var i = 0, m = this.posted.length; i < m; i++) {
  490. callback.reset();
  491. var result = callback(this.posted[i]);
  492. if (ISCALLBACK(result) && i === this.posted.length-1) {WAITFOR(result,this)}
  493. }
  494. }
  495. return callback;
  496. },
  497. //
  498. // A listener calls this to remove itself from a signal
  499. //
  500. NoInterest: function (callback) {
  501. this.listeners.Remove(callback);
  502. },
  503. //
  504. // Hook a callback to a particular message on this signal
  505. //
  506. MessageHook: function (msg,callback,priority) {
  507. callback = USING(callback);
  508. if (!this.hooks) {this.hooks = {}; this.Interest(["ExecuteHooks",this])}
  509. if (!this.hooks[msg]) {this.hooks[msg] = HOOKS(true)}
  510. this.hooks[msg].Add(callback,priority);
  511. for (var i = 0, m = this.posted.length; i < m; i++)
  512. {if (this.posted[i] == msg) {callback.reset(); callback(this.posted[i])}}
  513. callback.msg = msg; // keep track so we can remove it
  514. return callback;
  515. },
  516. //
  517. // Execute the message hooks for the given message
  518. //
  519. ExecuteHooks: function (msg) {
  520. var type = ((msg instanceof Array) ? msg[0] : msg);
  521. if (!this.hooks[type]) {return null}
  522. return this.hooks[type].Execute(msg);
  523. },
  524. //
  525. // Remove a hook safely
  526. //
  527. RemoveHook: function (hook) {
  528. this.hooks[hook.msg].Remove(hook);
  529. }
  530. },{
  531. signals: {}, // the named signals
  532. find: function (name) {
  533. if (!SIGNAL.signals[name]) {SIGNAL.signals[name] = new SIGNAL(name)}
  534. return SIGNAL.signals[name];
  535. }
  536. });
  537. //
  538. // The main entry-points
  539. //
  540. BASE.Callback = BASE.CallBack = USING;
  541. BASE.Callback.Delay = DELAY;
  542. BASE.Callback.After = AFTER;
  543. BASE.Callback.Queue = QUEUE;
  544. BASE.Callback.Signal = SIGNAL.find;
  545. BASE.Callback.Hooks = HOOKS;
  546. BASE.Callback.ExecuteHooks = EXECUTEHOOKS;
  547. })("MathJax");
  548. /**********************************************************/
  549. (function (BASENAME) {
  550. var BASE = window[BASENAME];
  551. if (!BASE) {BASE = window[BASENAME] = {}}
  552. var isSafari2 = (navigator.vendor === "Apple Computer, Inc." &&
  553. typeof navigator.vendorSub === "undefined");
  554. var sheets = 0; // used by Safari2
  555. //
  556. // Update sheets count and look up the head object
  557. //
  558. var HEAD = function (head) {
  559. return null;
  560. /*
  561. if (document.styleSheets && document.styleSheets.length > sheets)
  562. {sheets = document.styleSheets.length}
  563. if (!head) {
  564. head = document.head || ((document.getElementsByTagName("head"))[0]);
  565. if (!head) {head = document.body}
  566. }
  567. return head;
  568. */
  569. };
  570. //
  571. // Remove scripts that are completed so they don't clutter up the HEAD.
  572. // This runs via setTimeout since IE7 can't remove the script while it is running.
  573. //
  574. var SCRIPTS = []; // stores scripts to be removed after a delay
  575. var REMOVESCRIPTS = function () {
  576. for (var i = 0, m = SCRIPTS.length; i < m; i++) {BASE.Ajax.head.removeChild(SCRIPTS[i])}
  577. SCRIPTS = [];
  578. };
  579. var PATH = {};
  580. PATH[BASENAME] = ""; // empty path gets the root URL
  581. BASE.Ajax = {
  582. loaded: {}, // files already loaded
  583. loading: {}, // files currently in process of loading
  584. loadHooks: {}, // hooks to call when files are loaded
  585. timeout: 15*1000, // timeout for loading of files (15 seconds)
  586. styleDelay: 1, // delay to use before styles are available
  587. config: {
  588. root: "", // URL of root directory to load from
  589. path: PATH // paths to named URL's (e.g., [MathJax]/...)
  590. },
  591. STATUS: {
  592. OK: 1, // file is loading or did load OK
  593. ERROR: -1 // file timed out during load
  594. },
  595. //
  596. // Return a complete URL to a file (replacing any root names)
  597. //
  598. fileURL: function (file) {
  599. var match = file.match(/^\[([-._a-z0-9]+)\]/i);
  600. if (match && match[1] in PATH)
  601. {file = (PATH[match[1]]||this.config.root) + file.substr(match[1].length+2)}
  602. return file;
  603. },
  604. //
  605. // Replace root names if URL includes one
  606. //
  607. fileName: function (url) {
  608. var root = this.config.root;
  609. if (url.substr(0,root.length) === root) {url = "["+BASENAME+"]"+url.substr(root.length)}
  610. else {
  611. for (var id in PATH) {if (PATH.hasOwnProperty(id) && PATH[id]) {
  612. if (url.substr(0,PATH[id].length) === PATH[id])
  613. {url = "["+id+"]"+url.substr(PATH[id].length); break}
  614. }}
  615. }
  616. return url;
  617. },
  618. //
  619. // Cache-breaking revision number for file
  620. //
  621. fileRev: function (file) {
  622. var rev = BASE.cdnFileVersions[name] || BASE.cdnVersion;
  623. if (rev) {rev = "?rev="+rev}
  624. return rev;
  625. },
  626. urlRev: function (file) {return this.fileURL(file)+this.fileRev(file)},
  627. //
  628. // Load a file if it hasn't been already.
  629. // Make sure the file URL is "safe"?
  630. //
  631. Require: function (file,callback) {
  632. callback = BASE.Callback(callback); var type;
  633. if (file instanceof Object) {
  634. for (var i in file)
  635. {if (file.hasOwnProperty(i)) {type = i.toUpperCase(); file = file[i]}}
  636. } else {type = file.split(/\./).pop().toUpperCase()}
  637. file = this.fileURL(file);
  638. // FIXME: check that URL is OK
  639. if (this.loaded[file]) {
  640. callback(this.loaded[file]);
  641. } else {
  642. var FILE = {}; FILE[type] = file;
  643. this.Load(FILE,callback);
  644. }
  645. return callback;
  646. },
  647. //
  648. // Load a file regardless of where it is and whether it has
  649. // already been loaded.
  650. //
  651. Load: function (file,callback) {
  652. callback = BASE.Callback(callback); var type;
  653. if (file instanceof Object) {
  654. for (var i in file)
  655. {if (file.hasOwnProperty(i)) {type = i.toUpperCase(); file = file[i]}}
  656. } else {type = file.split(/\./).pop().toUpperCase()}
  657. file = this.fileURL(file);
  658. if (this.loading[file]) {
  659. this.addHook(file,callback);
  660. } else {
  661. this.head = HEAD(this.head);
  662. if (this.loader[type]) {this.loader[type].call(this,file,callback)}
  663. else {throw Error("Can't load files of type "+type)}
  664. }
  665. return callback;
  666. },
  667. //
  668. // Register a load hook for a particular file (it will be called when
  669. // loadComplete() is called for that file)
  670. //
  671. LoadHook: function (file,callback,priority) {
  672. callback = BASE.Callback(callback);
  673. if (file instanceof Object)
  674. {for (var i in file) {if (file.hasOwnProperty(i)) {file = file[i]}}}
  675. file = this.fileURL(file);
  676. if (this.loaded[file]) {callback(this.loaded[file])}
  677. else {this.addHook(file,callback,priority)}
  678. return callback;
  679. },
  680. addHook: function (file,callback,priority) {
  681. if (!this.loadHooks[file]) {this.loadHooks[file] = MathJax.Callback.Hooks()}
  682. this.loadHooks[file].Add(callback,priority);
  683. callback.file = file;
  684. },
  685. removeHook: function (hook) {
  686. if (this.loadHooks[hook.file]) {
  687. this.loadHooks[hook.file].Remove(hook);
  688. if (!this.loadHooks[hook.file].hooks.length) {delete this.loadHooks[hook.file]}
  689. }
  690. },
  691. //
  692. // Used when files are combined in a preloading configuration file
  693. //
  694. Preloading: function () {
  695. for (var i = 0, m = arguments.length; i < m; i++) {
  696. var file = this.fileURL(arguments[i]);
  697. if (!this.loading[file] && !this.loaded[file]) {this.loading[file] = {preloaded: true}}
  698. }
  699. },
  700. //
  701. // Code used to load the various types of files
  702. // (JS for JavaScript, CSS for style sheets)
  703. //
  704. loader: {
  705. //
  706. // Create a SCRIPT tag to load the file
  707. //
  708. JS: function (file,callback) {
  709. var name = this.fileName(file);
  710. var timeout = BASE.Callback(["loadTimeout",this,file]);
  711. this.loading[file] = {
  712. callback: callback,
  713. timeout: setTimeout(timeout,this.timeout),
  714. status: this.STATUS.OK,
  715. script: null
  716. };
  717. //
  718. // Add this to the structure above after it is created to prevent recursion
  719. // when loading the initial localization file (before loading messsage is available)
  720. //
  721. this.loading[file].message = BASE.Message.File(name);
  722. if (window.System) {
  723. window.System.import(file).catch(timeout);
  724. } else {
  725. timeout(); // indicate a load failure
  726. }
  727. },
  728. //
  729. // Create a LINK tag to load the style sheet
  730. //
  731. CSS: function (file,callback) {
  732. var name = this.fileName(file);
  733. var link = document.createElement("link");
  734. link.rel = "stylesheet"; link.type = "text/css";
  735. link.href = file+this.fileRev(name);
  736. this.loading[file] = {
  737. callback: callback,
  738. message: BASE.Message.File(name),
  739. status: this.STATUS.OK
  740. };
  741. this.head.appendChild(link);
  742. this.timer.create.call(this,[this.timer.file,file],link);
  743. }
  744. },
  745. //
  746. // Timing code for checking when style sheets are available.
  747. //
  748. timer: {
  749. //
  750. // Create the timing callback and start the timing loop.
  751. // We use a delay because some browsers need it to allow the styles
  752. // to be processed.
  753. //
  754. create: function (callback,node) {
  755. callback = BASE.Callback(callback);
  756. if (node.nodeName === "STYLE" && node.styleSheet &&
  757. typeof(node.styleSheet.cssText) !== 'undefined') {
  758. callback(this.STATUS.OK); // MSIE processes style immediately, but doesn't set its styleSheet!
  759. } else if (window.chrome && node.nodeName === "LINK") {
  760. callback(this.STATUS.OK); // Chrome doesn't give access to cssRules for stylesheet in
  761. // a link node, so we can't detect when it is loaded.
  762. } else if (isSafari2) {
  763. this.timer.start(this,[this.timer.checkSafari2,sheets++,callback],this.styleDelay);
  764. } else {
  765. this.timer.start(this,[this.timer.checkLength,node,callback],this.styleDelay);
  766. }
  767. return callback;
  768. },
  769. //
  770. // Start the timer for the given callback checker
  771. //
  772. start: function (AJAX,check,delay,timeout) {
  773. check = BASE.Callback(check);
  774. check.execute = this.execute; check.time = this.time;
  775. check.STATUS = AJAX.STATUS; check.timeout = timeout || AJAX.timeout;
  776. check.delay = check.total = delay || 0;
  777. if (delay) {setTimeout(check,delay)} else {check()}
  778. },
  779. //
  780. // Increment the time total, increase the delay
  781. // and test if we are past the timeout time.
  782. //
  783. time: function (callback) {
  784. this.total += this.delay;
  785. this.delay = Math.floor(this.delay * 1.05 + 5);
  786. if (this.total >= this.timeout) {callback(this.STATUS.ERROR); return 1}
  787. return 0;
  788. },
  789. //
  790. // For JS file loads, call the proper routine according to status
  791. //
  792. file: function (file,status) {
  793. if (status < 0) {BASE.Ajax.loadTimeout(file)} else {BASE.Ajax.loadComplete(file)}
  794. },
  795. //
  796. // Call the hook with the required data
  797. //
  798. execute: function () {this.hook.call(this.object,this,this.data[0],this.data[1])},
  799. //
  800. // Safari2 doesn't set the link's stylesheet, so we need to look in the
  801. // document.styleSheets array for the new sheet when it is created
  802. //
  803. checkSafari2: function (check,length,callback) {
  804. if (check.time(callback)) return;
  805. if (document.styleSheets.length > length &&
  806. document.styleSheets[length].cssRules &&
  807. document.styleSheets[length].cssRules.length)
  808. {callback(check.STATUS.OK)} else {setTimeout(check,check.delay)}
  809. },
  810. //
  811. // Look for the stylesheets rules and check when they are defined
  812. // and no longer of length zero. (This assumes there actually ARE
  813. // some rules in the stylesheet.)
  814. //
  815. checkLength: function (check,node,callback) {
  816. if (check.time(callback)) return;
  817. var isStyle = 0; var sheet = (node.sheet || node.styleSheet);
  818. try {if ((sheet.cssRules||sheet.rules||[]).length > 0) {isStyle = 1}} catch(err) {
  819. if (err.message.match(/protected variable|restricted URI/)) {isStyle = 1}
  820. else if (err.message.match(/Security error/)) {
  821. // Firefox3 gives "Security error" for missing files, so
  822. // can't distinguish that from OK files on remote servers.
  823. // or OK files in different directory from local files.
  824. isStyle = 1; // just say it is OK (can't really tell)
  825. }
  826. }
  827. if (isStyle) {
  828. // Opera 9.6 requires this setTimeout
  829. setTimeout(BASE.Callback([callback,check.STATUS.OK]),0);
  830. } else {
  831. setTimeout(check,check.delay);
  832. }
  833. }
  834. },
  835. //
  836. // JavaScript code must call this when they are completely initialized
  837. // (this allows them to perform asynchronous actions before indicating
  838. // that they are complete).
  839. //
  840. loadComplete: function (file) {
  841. file = this.fileURL(file);
  842. var loading = this.loading[file];
  843. if (loading && !loading.preloaded) {
  844. BASE.Message.Clear(loading.message);
  845. if (loading.timeout) clearTimeout(loading.timeout);
  846. if (loading.script) {
  847. if (SCRIPTS.length === 0) {setTimeout(REMOVESCRIPTS,0)}
  848. SCRIPTS.push(loading.script);
  849. }
  850. this.loaded[file] = loading.status; delete this.loading[file];
  851. this.addHook(file,loading.callback);
  852. } else {
  853. if (loading) {delete this.loading[file]}
  854. this.loaded[file] = this.STATUS.OK;
  855. loading = {status: this.STATUS.OK}
  856. }
  857. if (!this.loadHooks[file]) {return null}
  858. return this.loadHooks[file].Execute(loading.status);
  859. },
  860. //
  861. // If a file fails to load within the timeout period (or the onerror handler
  862. // is called), this routine runs to signal the error condition.
  863. //
  864. loadTimeout: function (file) {
  865. if (this.loading[file].timeout) {clearTimeout(this.loading[file].timeout)}
  866. this.loading[file].status = this.STATUS.ERROR;
  867. this.loadError(file);
  868. this.loadComplete(file);
  869. },
  870. //
  871. // The default error hook for file load failures
  872. //
  873. loadError: function (file) {
  874. BASE.Message.Set(["LoadFailed","File failed to load: %1",file],null,2000);
  875. BASE.Hub.signal.Post(["file load error",file]);
  876. },
  877. //
  878. // Defines a style sheet from a hash of style declarations (key:value pairs
  879. // where the key is the style selector and the value is a hash of CSS attributes
  880. // and values).
  881. //
  882. Styles: function (styles,callback) {
  883. var styleString = this.StyleString(styles);
  884. if (styleString === "") {
  885. callback = BASE.Callback(callback);
  886. callback();
  887. } else {
  888. var style = document.createElement("style"); style.type = "text/css";
  889. this.head = HEAD(this.head);
  890. this.head.appendChild(style);
  891. if (style.styleSheet && typeof(style.styleSheet.cssText) !== 'undefined') {
  892. style.styleSheet.cssText = styleString;
  893. } else {
  894. style.appendChild(document.createTextNode(styleString));
  895. }
  896. callback = this.timer.create.call(this,callback,style);
  897. }
  898. return callback;
  899. },
  900. //
  901. // Create a stylesheet string from a style declaration object
  902. //
  903. StyleString: function (styles) {
  904. if (typeof(styles) === 'string') {return styles}
  905. var string = "", id, style;
  906. for (id in styles) {if (styles.hasOwnProperty(id)) {
  907. if (typeof styles[id] === 'string') {
  908. string += id + " {"+styles[id]+"}\n";
  909. } else if (styles[id] instanceof Array) {
  910. for (var i = 0; i < styles[id].length; i++) {
  911. style = {}; style[id] = styles[id][i];
  912. string += this.StyleString(style);
  913. }
  914. } else if (id.substr(0,6) === '@media') {
  915. string += id + " {"+this.StyleString(styles[id])+"}\n";
  916. } else if (styles[id] != null) {
  917. style = [];
  918. for (var name in styles[id]) {if (styles[id].hasOwnProperty(name)) {
  919. if (styles[id][name] != null)
  920. {style[style.length] = name + ': ' + styles[id][name]}
  921. }}
  922. string += id +" {"+style.join('; ')+"}\n";
  923. }
  924. }}
  925. return string;
  926. }
  927. };
  928. })("MathJax");
  929. /**********************************************************/
  930. MathJax.HTML = {
  931. setDocument: function (doc) {document = this.document = doc},
  932. //
  933. // Create an HTML element with given attributes and content.
  934. // The def parameter is an (optional) object containing key:value pairs
  935. // of the attributes and their values, and contents is an (optional)
  936. // array of strings to be inserted as text, or arrays of the form
  937. // [type,def,contents] that describes an HTML element to be inserted
  938. // into the current element. Thus the contents can describe a complete
  939. // HTML snippet of arbitrary complexity. E.g.:
  940. //
  941. // MathJax.HTML.Element("span",{id:"mySpan",style{"font-style":"italic"}},[
  942. // "(See the ",["a",{href:"http://www.mathjax.org"},["MathJax home page"]],
  943. // " for more details.)"]);
  944. //
  945. Element: function (type,def,contents) {
  946. var obj = document.createElement(type), id;
  947. if (def) {
  948. if (def.hasOwnProperty("style")) {
  949. var style = def.style; def.style = {};
  950. for (id in style) {if (style.hasOwnProperty(id))
  951. {def.style[id.replace(/-([a-z])/g,this.ucMatch)] = style[id]}}
  952. }
  953. MathJax.Hub.Insert(obj,def);
  954. for (id in def) {
  955. if (id === "role" || id.substr(0,5) === "aria-") obj.setAttribute(id,def[id]);
  956. }
  957. }
  958. if (contents) {
  959. if (!MathJax.Object.isArray(contents)) {contents = [contents]}
  960. for (var i = 0, m = contents.length; i < m; i++) {
  961. if (MathJax.Object.isArray(contents[i])) {
  962. obj.appendChild(this.Element(contents[i][0],contents[i][1],contents[i][2]));
  963. } else if (type === "script") { // IE throws an error if script is added as a text node
  964. this.setScript(obj, contents[i]);
  965. } else {
  966. obj.appendChild(document.createTextNode(contents[i]));
  967. }
  968. }
  969. }
  970. return obj;
  971. },
  972. ucMatch: function (match,c) {return c.toUpperCase()},
  973. addElement: function (span,type,def,contents) {return span.appendChild(this.Element(type,def,contents))},
  974. TextNode: function (text) {return document.createTextNode(text)},
  975. addText: function (span,text) {return span.appendChild(this.TextNode(text))},
  976. //
  977. // Set and get the text of a script
  978. //
  979. setScript: function (script,text) {
  980. if (this.setScriptBug) {script.text = text} else {
  981. while (script.firstChild) {script.removeChild(script.firstChild)}
  982. this.addText(script,text);
  983. }
  984. },
  985. getScript: function (script) {return script.innerText}
  986. }
  987. /**********************************************************/
  988. MathJax.Localization = {
  989. locale: "en",
  990. directory: "[MathJax]/localization",
  991. strings: {
  992. // Currently, this list is not modified by the MathJax-i18n script. You can
  993. // run the following command in MathJax/unpacked/localization to update it:
  994. //
  995. // find . -name "*.js" | xargs grep menuTitle\: | grep -v qqq | sed 's/^\.\/\(.*\)\/.*\.js\: / "\1"\: \{/' | sed 's/,$/\},/' | sed 's/"English"/"English", isLoaded: true/' > tmp ; sort tmp > tmp2 ; sed '$ s/,$//' tmp2 ; rm tmp*
  996. //
  997. // This only takes languages with localization data so you must also add
  998. // the languages that use a remap but are not translated at all.
  999. //
  1000. "ast": {menuTitle: "asturianu"},
  1001. "bg": {menuTitle: "\u0431\u044A\u043B\u0433\u0430\u0440\u0441\u043A\u0438"},
  1002. "bcc": {menuTitle: "\u0628\u0644\u0648\u0686\u06CC"},
  1003. "br": {menuTitle: "brezhoneg"},
  1004. "ca": {menuTitle: "catal\u00E0"},
  1005. "cdo": {menuTitle: "M\u00ECng-d\u0115\u0324ng-ng\u1E73\u0304"},
  1006. "cs": {menuTitle: "\u010De\u0161tina"},
  1007. "da": {menuTitle: "dansk"},
  1008. "de": {menuTitle: "Deutsch"},
  1009. "en": {menuTitle: "English", isLoaded: true},
  1010. "eo": {menuTitle: "Esperanto"},
  1011. "es": {menuTitle: "espa\u00F1ol"},
  1012. "fa": {menuTitle: "\u0641\u0627\u0631\u0633\u06CC"},
  1013. "fi": {menuTitle: "suomi"},
  1014. "fr": {menuTitle: "fran\u00E7ais"},
  1015. "gl": {menuTitle: "galego"},
  1016. "he": {menuTitle: "\u05E2\u05D1\u05E8\u05D9\u05EA"},
  1017. "ia": {menuTitle: "interlingua"},
  1018. "it": {menuTitle: "italiano"},
  1019. "ja": {menuTitle: "\u65E5\u672C\u8A9E"},
  1020. "kn": {menuTitle: "\u0C95\u0CA8\u0CCD\u0CA8\u0CA1"},
  1021. "ko": {menuTitle: "\uD55C\uAD6D\uC5B4"},
  1022. "lb": {menuTitle: "L\u00EBtzebuergesch"},
  1023. "lt": {menuTitle: "lietuvi\u0173"},
  1024. "mk": {menuTitle: "\u043C\u0430\u043A\u0435\u0434\u043E\u043D\u0441\u043A\u0438"},
  1025. "nl": {menuTitle: "Nederlands"},
  1026. "oc": {menuTitle: "occitan"},
  1027. "pl": {menuTitle: "polski"},
  1028. "pt": {menuTitle: "portugus\u00EA"},
  1029. "pt-br": {menuTitle: "portugu\u00EAs do Brasil"},
  1030. "ru": {menuTitle: "\u0440\u0443\u0441\u0441\u043A\u0438\u0439"},
  1031. "sco": {menuTitle: "Scots"},
  1032. "scn": {menuTitle: "sicilianu"},
  1033. "sl": {menuTitle: "sloven\u0161\u010Dina"},
  1034. "sv": {menuTitle: "svenska"},
  1035. "tr": {menuTitle: "T\u00FCrk\u00E7e"},
  1036. "uk": {menuTitle: "\u0443\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u0430"},
  1037. "vi": {menuTitle: "Ti\u1EBFng Vi\u1EC7t"},
  1038. "zh-hans": {menuTitle: "\u4E2D\u6587\uFF08\u7B80\u4F53\uFF09"}
  1039. },
  1040. //
  1041. // The pattern for substitution escapes:
  1042. // %n or %{n} or %{plural:%n|option1|option1|...} or %c
  1043. //
  1044. pattern: /%(\d+|\{\d+\}|\{[a-z]+:\%\d+(?:\|(?:%\{\d+\}|%.|[^\}])*)+\}|.)/g,
  1045. SPLIT: ("axb".split(/(x)/).length === 3 ?
  1046. function (string,regex) {return string.split(regex)} :
  1047. //
  1048. // IE8 and below don't do split() correctly when the pattern includes
  1049. // parentheses (the split should include the matched exrepssions).
  1050. // So implement it by hand here.
  1051. //
  1052. function (string,regex) {
  1053. var result = [], match, last = 0;
  1054. regex.lastIndex = 0;
  1055. while ((match = regex.exec(string))) {
  1056. result.push(string.substr(last,match.index-last));
  1057. result.push.apply(result,match.slice(1));
  1058. last = match.index + match[0].length;
  1059. }
  1060. result.push(string.substr(last));
  1061. return result;
  1062. }),
  1063. _: function (id,phrase) {
  1064. if (phrase instanceof Array) {return this.processSnippet(id,phrase)}
  1065. return this.processString(this.lookupPhrase(id,phrase),[].slice.call(arguments,2));
  1066. },
  1067. processString: function (string,args,domain) {
  1068. //
  1069. // Process arguments for substitution
  1070. // If the argument is a snippet (and we are processing snippets) do so,
  1071. // Otherwise, if it is a number, convert it for the lacale
  1072. //
  1073. var i, m;
  1074. for (i = 0, m = args.length; i < m; i++) {
  1075. if (domain && args[i] instanceof Array) {args[i] = this.processSnippet(domain,args[i])}
  1076. }
  1077. //
  1078. // Split string at escapes and process them individually
  1079. //
  1080. var parts = this.SPLIT(string,this.pattern);
  1081. for (i = 1, m = parts.length; i < m; i += 2) {
  1082. var c = parts[i].charAt(0); // first char will be { or \d or a char to be kept literally
  1083. if (c >= "0" && c <= "9") { // %n
  1084. parts[i] = args[parts[i]-1];
  1085. if (typeof parts[i] === "number") parts[i] = this.number(parts[i]);
  1086. } else if (c === "{") { // %{n} or %{plural:%n|...}
  1087. c = parts[i].substr(1);
  1088. if (c >= "0" && c <= "9") { // %{n}
  1089. parts[i] = args[parts[i].substr(1,parts[i].length-2)-1];
  1090. if (typeof parts[i] === "number") parts[i] = this.number(parts[i]);
  1091. } else { // %{plural:%n|...}
  1092. var match = parts[i].match(/^\{([a-z]+):%(\d+)\|(.*)\}$/);
  1093. if (match) {
  1094. if (match[1] === "plural") {
  1095. var n = args[match[2]-1];
  1096. if (typeof n === "undefined") {
  1097. parts[i] = "???"; // argument doesn't exist
  1098. } else {
  1099. n = this.plural(n) - 1; // index of the form to use
  1100. var plurals = match[3].replace(/(^|[^%])(%%)*%\|/g,"$1$2%\uEFEF").split(/\|/); // the parts (replacing %| with a special character)
  1101. if (n >= 0 && n < plurals.length) {
  1102. parts[i] = this.processString(plurals[n].replace(/\uEFEF/g,"|"),args,domain);
  1103. } else {
  1104. parts[i] = "???"; // no string for this index
  1105. }
  1106. }
  1107. } else {parts[i] = "%"+parts[i]} // not "plural", put back the % and leave unchanged
  1108. }
  1109. }
  1110. }
  1111. if (parts[i] == null) {parts[i] = "???"}
  1112. }
  1113. //
  1114. // If we are not forming a snippet, return the completed string
  1115. //
  1116. if (!domain) {return parts.join("")}
  1117. //
  1118. // We need to return an HTML snippet, so buld it from the
  1119. // broken up string with inserted parts (that could be snippets)
  1120. //
  1121. var snippet = [], part = "";
  1122. for (i = 0; i < m; i++) {
  1123. part += parts[i]; i++; // add the string and move on to substitution result
  1124. if (i < m) {
  1125. if (parts[i] instanceof Array) { // substitution was a snippet
  1126. snippet.push(part); // add the accumulated string
  1127. snippet = snippet.concat(parts[i]); // concatenate the substution snippet
  1128. part = ""; // start accumulating a new string
  1129. } else { // substitution was a string
  1130. part += parts[i]; // add to accumulating string
  1131. }
  1132. }
  1133. }
  1134. if (part !== "") {snippet.push(part)} // add final string
  1135. return snippet;
  1136. },
  1137. processSnippet: function (domain,snippet) {
  1138. var result = []; // the new snippet
  1139. //
  1140. // Look through the original snippet for
  1141. // strings or snippets to translate
  1142. //
  1143. for (var i = 0, m = snippet.length; i < m; i++) {
  1144. if (snippet[i] instanceof Array) {
  1145. //
  1146. // This could be a sub-snippet:
  1147. // ["tag"] or ["tag",{properties}] or ["tag",{properties},snippet]
  1148. // Or it could be something to translate:
  1149. // [id,string,args] or [domain,snippet]
  1150. var data = snippet[i];
  1151. if (typeof data[1] === "string") { // [id,string,args]
  1152. var id = data[0]; if (!(id instanceof Array)) {id = [domain,id]}
  1153. var phrase = this.lookupPhrase(id,data[1]);
  1154. result = result.concat(this.processMarkdown(phrase,data.slice(2),domain));
  1155. } else if (data[1] instanceof Array) { // [domain,snippet]
  1156. result = result.concat(this.processSnippet.apply(this,data));
  1157. } else if (data.length >= 3) { // ["tag",{properties},snippet]
  1158. result.push([data[0],data[1],this.processSnippet(domain,data[2])]);
  1159. } else { // ["tag"] or ["tag",{properties}]
  1160. result.push(snippet[i]);
  1161. }
  1162. } else { // a string
  1163. result.push(snippet[i]);
  1164. }
  1165. }
  1166. return result;
  1167. },
  1168. markdownPattern: /(%.)|(\*{1,3})((?:%.|.)+?)\2|(`+)((?:%.|.)+?)\4|\[((?:%.|.)+?)\]\(([^\s\)]+)\)/,
  1169. // %c or *bold*, **italics**, ***bold-italics***, or `code`, or [link](url)
  1170. processMarkdown: function (phrase,args,domain) {
  1171. var result = [], data;
  1172. //
  1173. // Split the string by the Markdown pattern
  1174. // (the text blocks are separated by
  1175. // c,stars,star-text,backtics,code-text,link-text,URL).
  1176. // Start with teh first text string from the split.
  1177. //
  1178. var parts = phrase.split(this.markdownPattern);
  1179. var string = parts[0];
  1180. //
  1181. // Loop through the matches and process them
  1182. //
  1183. for (var i = 1, m = parts.length; i < m; i += 8) {
  1184. if (parts[i+1]) { // stars (for bold/italic)
  1185. //
  1186. // Select the tag to use by number of stars (three stars requires two tags)
  1187. //
  1188. data = this.processString(parts[i+2],args,domain);
  1189. if (!(data instanceof Array)) {data = [data]}
  1190. data = [["b","i","i"][parts[i+1].length-1],{},data]; // number of stars determines type
  1191. if (parts[i+1].length === 3) {data = ["b",{},data]} // bold-italic
  1192. } else if (parts[i+3]) { // backtics (for code)
  1193. //
  1194. // Remove one leading or trailing space, and process substitutions
  1195. // Make a <code> tag
  1196. //
  1197. data = this.processString(parts[i+4].replace(/^\s/,"").replace(/\s$/,""),args,domain);
  1198. if (!(data instanceof Array)) {data = [data]}
  1199. data = ["code",{},data];
  1200. } else if (parts[i+5]) { // hyperlink
  1201. //
  1202. // Process the link text, and make an <a> tag with the URL
  1203. //
  1204. data = this.processString(parts[i+5],args,domain);
  1205. if (!(data instanceof Array)) {data = [data]}
  1206. data = ["a",{href:this.processString(parts[i+6],args),target:"_blank"},data];
  1207. } else {
  1208. //
  1209. // Escaped character (%c) gets added into the string.
  1210. //
  1211. string += parts[i]; data = null;
  1212. }
  1213. //
  1214. // If there is a tag to insert,
  1215. // Add any pending string, then push the tag
  1216. //
  1217. if (data) {
  1218. result = this.concatString(result,string,args,domain);
  1219. result.push(data); string = "";
  1220. }
  1221. //
  1222. // Process the string that follows matches pattern
  1223. //
  1224. if (parts[i+7] !== "") {string += parts[i+7]}
  1225. };
  1226. //
  1227. // Add any pending string and return the resulting snippet
  1228. //
  1229. result = this.concatString(result,string,args,domain);
  1230. return result;
  1231. },
  1232. concatString: function (result,string,args,domain) {
  1233. if (string != "") {
  1234. //
  1235. // Process the substutions.
  1236. // If the result is not a snippet, turn it into one.
  1237. // Then concatenate the snippet to the current one
  1238. //
  1239. string = this.processString(string,args,domain);
  1240. if (!(string instanceof Array)) {string = [string]}
  1241. result = result.concat(string);
  1242. }
  1243. return result;
  1244. },
  1245. lookupPhrase: function (id,phrase,domain) {
  1246. //
  1247. // Get the domain and messageID
  1248. //
  1249. if (!domain) {domain = "_"}
  1250. if (id instanceof Array) {domain = (id[0] || "_"); id = (id[1] || "")}
  1251. //
  1252. // Check if the data is available and if not,
  1253. // load it and throw a restart error so the calling
  1254. // code can wait for the load and try again.
  1255. //
  1256. var load = this.loadDomain(domain);
  1257. if (load) {MathJax.Hub.RestartAfter(load)}
  1258. //
  1259. // Look up the message in the localization data
  1260. // (if not found, the original English is used)
  1261. //
  1262. var localeData = this.strings[this.locale];
  1263. if (localeData) {
  1264. if (localeData.domains && domain in localeData.domains) {
  1265. var domainData = localeData.domains[domain];
  1266. if (domainData.strings && id in domainData.strings)
  1267. {phrase = domainData.strings[id]}
  1268. }
  1269. }
  1270. //
  1271. // return the translated phrase
  1272. //
  1273. return phrase;
  1274. },
  1275. //
  1276. // Load a langauge data file from the proper
  1277. // directory and file.
  1278. //
  1279. loadFile: function (file,data,callback) {
  1280. callback = MathJax.Callback(callback);
  1281. file = (data.file || file); // the data's file name or the default name
  1282. if (!file.match(/\.js$/)) {file += ".js"} // add .js if needed
  1283. //
  1284. // Add the directory if the file doesn't
  1285. // contain a full URL already.
  1286. //
  1287. if (!file.match(/^([a-z]+:|\[MathJax\])/)) {
  1288. var dir = (this.strings[this.locale].directory ||
  1289. this.directory + "/" + this.locale ||
  1290. "[MathJax]/localization/" + this.locale);
  1291. file = dir + "/" + file;
  1292. }
  1293. //
  1294. // Load the file and mark the data as loaded (even if it
  1295. // failed to load, so we don't continue to try to load it
  1296. // over and over).
  1297. //
  1298. var load = MathJax.Ajax.Require(file,function () {data.isLoaded = true; return callback()});
  1299. //
  1300. // Return the callback if needed, otherwise null.
  1301. //
  1302. return (load.called ? null : load);
  1303. },
  1304. //
  1305. // Check to see if the localization data are loaded
  1306. // for the given domain; if not, load the data file,
  1307. // and return a callback for the loading operation.
  1308. // Otherwise return null (data are loaded).
  1309. //
  1310. loadDomain: function (domain,callback) {
  1311. var load, localeData = this.strings[this.locale];
  1312. if (localeData) {
  1313. if (!localeData.isLoaded) {
  1314. load = this.loadFile(this.locale,localeData);
  1315. if (load) {
  1316. return MathJax.Callback.Queue(
  1317. load,["loadDomain",this,domain] // call again to load domain
  1318. ).Push(callback||{});
  1319. }
  1320. }
  1321. if (localeData.domains && domain in localeData.domains) {
  1322. var domainData = localeData.domains[domain];
  1323. if (!domainData.isLoaded) {
  1324. load = this.loadFile(domain,domainData);
  1325. if (load) {return MathJax.Callback.Queue(load).Push(callback)}
  1326. }
  1327. }
  1328. }
  1329. // localization data are loaded, so just do the callback
  1330. return MathJax.Callback(callback)();
  1331. },
  1332. //
  1333. // Perform a function, properly handling
  1334. // restarts due to localization file loads.
  1335. //
  1336. // Note that this may return before the function
  1337. // has been called successfully, so you should
  1338. // consider fn as running asynchronously. (Callbacks
  1339. // can be used to synchronize it with other actions.)
  1340. //
  1341. Try: function (fn) {
  1342. fn = MathJax.Callback(fn); fn.autoReset = true;
  1343. try {fn()} catch (err) {
  1344. if (!err.restart) {throw err}
  1345. MathJax.Callback.After(["Try",this,fn],err.restart);
  1346. }
  1347. },
  1348. //
  1349. // Reset the current language
  1350. //
  1351. resetLocale: function(locale) {
  1352. // Selection algorithm:
  1353. // 1) Downcase locale name (e.g. "en-US" => "en-us")
  1354. // 2) Try a parent language (e.g. "en-us" => "en")
  1355. // 3) Try the fallback specified in the data (e.g. "pt" => "pt-br")
  1356. // 4) Otherwise don't change the locale.
  1357. if (!locale) return;
  1358. locale = locale.toLowerCase();
  1359. while (!this.strings[locale]) {
  1360. var dashPos = locale.lastIndexOf("-");
  1361. if (dashPos === -1) return;
  1362. locale = locale.substring(0, dashPos);
  1363. }
  1364. var remap = this.strings[locale].remap;
  1365. this.locale = remap ? remap : locale;
  1366. },
  1367. //
  1368. // Set the current language
  1369. //
  1370. setLocale: function(locale) {
  1371. this.resetLocale(locale);
  1372. if (MathJax.Menu) {this.loadDomain("MathMenu")}
  1373. },
  1374. //
  1375. // Add or update a language or domain
  1376. //
  1377. addTranslation: function (locale,domain,definition) {
  1378. var data = this.strings[locale], isNew = false;
  1379. if (!data) {data = this.strings[locale] = {}; isNew = true}
  1380. if (!data.domains) {data.domains = {}}
  1381. if (domain) {
  1382. if (!data.domains[domain]) {data.domains[domain] = {}}
  1383. data = data.domains[domain];
  1384. }
  1385. MathJax.Hub.Insert(data,definition);
  1386. if (isNew && MathJax.Menu.menu) {MathJax.Menu.CreateLocaleMenu()}
  1387. },
  1388. //
  1389. // Set CSS for an element based on font requirements
  1390. //
  1391. setCSS: function (div) {
  1392. var locale = this.strings[this.locale];
  1393. if (locale) {
  1394. if (locale.fontFamily) {div.style.fontFamily = locale.fontFamily}
  1395. if (locale.fontDirection) {
  1396. div.style.direction = locale.fontDirection;
  1397. if (locale.fontDirection === "rtl") {div.style.textAlign = "right"}
  1398. }
  1399. }
  1400. return div;
  1401. },
  1402. //
  1403. // Get the language's font family or direction
  1404. //
  1405. fontFamily: function () {
  1406. var locale = this.strings[this.locale];
  1407. return (locale ? locale.fontFamily : null);
  1408. },
  1409. fontDirection: function () {
  1410. var locale = this.strings[this.locale];
  1411. return (locale ? locale.fontDirection : null);
  1412. },
  1413. //
  1414. // Get the language's plural index for a number
  1415. //
  1416. plural: function (n) {
  1417. var locale = this.strings[this.locale];
  1418. if (locale && locale.plural) {return locale.plural(n)}
  1419. // default
  1420. if (n == 1) {return 1} // one
  1421. return 2; // other
  1422. },
  1423. //
  1424. // Convert a number to language-specific form
  1425. //
  1426. number: function(n) {
  1427. var locale = this.strings[this.locale];
  1428. if (locale && locale.number) {return locale.number(n)}
  1429. // default
  1430. return n;
  1431. }
  1432. };
  1433. /**********************************************************/
  1434. MathJax.Message = {
  1435. localize: function (message) {
  1436. return MathJax.Localization._(message,message);
  1437. },
  1438. filterText: function (text,n,id) {
  1439. if (MathJax.Hub.config.messageStyle === "simple") {
  1440. if (id === "LoadFile") {
  1441. if (!this.loading) {this.loading = this.localize("Loading") + " "}
  1442. text = this.loading; this.loading += ".";
  1443. } else if (id === "ProcessMath") {
  1444. if (!this.processing) {this.processing = this.localize("Processing") + " "}
  1445. text = this.processing; this.processing += ".";
  1446. } else if (id === "TypesetMath") {
  1447. if (!this.typesetting) {this.typesetting = this.localize("Typesetting") + " "}
  1448. text = this.typesetting; this.typesetting += ".";
  1449. }
  1450. }
  1451. return text;
  1452. },
  1453. Set: function (text,n,clearDelay) {
  1454. if (MathJax.debug) {
  1455. if (Array.isArray(text)) {
  1456. text = MathJax.Localization._.apply(MathJax.Localization,text);
  1457. }
  1458. console.log("Message: "+text);
  1459. }
  1460. },
  1461. Clear: function (n,delay) {},
  1462. Remove: function () {},
  1463. File: function (file) {
  1464. return this.Set(["LoadFile","Loading %1",file],null,null);
  1465. },
  1466. Log: function () {}
  1467. };
  1468. /**********************************************************/
  1469. MathJax.Hub = {
  1470. config: {
  1471. root: "./mathjax2/legacy",
  1472. config: [], // list of configuration files to load
  1473. jax: [], // list of input and output jax to load
  1474. extensions: [], // list of extensions to load
  1475. preJax: null, // pattern to remove from before math script tag
  1476. postJax: null, // pattern to remove from after math script tag
  1477. displayAlign: 'center', // how to align displayed equations (left, center, right)
  1478. displayIndent: '0', // indentation for displayed equations (when not centered)
  1479. preRemoveClass: 'MathJax_Preview', // class of objects to remove preceeding math script
  1480. showProcessingMessages: true, // display "Processing math: nn%" messages or not
  1481. messageStyle: "normal", // set to "none" or "simple" (for "Loading..." and "Processing...")
  1482. delayStartupUntil: "none", // set to "onload" to delay setup until the onload handler runs
  1483. // set to "configured" to delay startup until MathJax.Hub.Configured() is called
  1484. // set to a Callback to wait for before continuing with the startup
  1485. skipStartupTypeset: false, // set to true to skip PreProcess and Process during startup
  1486. elements: [], // array of elements to process when none is given explicitly
  1487. positionToHash: true, // after initial typeset pass, position to #hash location?
  1488. showMathMenu: true, // attach math context menu to typeset math?
  1489. showMathMenuMSIE: true, // separtely determine if MSIE should have math menu
  1490. // (since the code for that is a bit delicate)
  1491. menuSettings: {
  1492. zoom: "None", // when to do MathZoom
  1493. CTRL: false, // require CTRL for MathZoom?
  1494. ALT: false, // require Alt or Option?
  1495. CMD: false, // require CMD?
  1496. Shift: false, // require Shift?
  1497. discoverable: false, // make math menu discoverable on hover?
  1498. zscale: "200%", // the scaling factor for MathZoom
  1499. renderer: null, // set when Jax are loaded
  1500. font: "Auto", // what font HTML-CSS should use
  1501. context: "MathJax", // or "Browser" for pass-through to browser menu
  1502. locale: null, // the language to use for messages
  1503. mpContext: false, // true means pass menu events to MathPlayer in IE
  1504. mpMouse: false, // true means pass mouse events to MathPlayer in IE
  1505. texHints: true, // include class names for TeXAtom elements
  1506. FastPreview: null, // use PreviewHTML output as preview?
  1507. assistiveMML: null, // include hidden MathML for screen readers?
  1508. inTabOrder: true, // set to false if math elements should be included in the tabindex
  1509. semantics: false // add semantics tag with original form in MathML output
  1510. },
  1511. errorSettings: {
  1512. // localized HTML snippet structure for message to use
  1513. message: ["[",["MathProcessingError","Math Processing Error"],"]"],
  1514. style: {color: "#CC0000", "font-style":"italic"} // style for message
  1515. },
  1516. ignoreMMLattributes: {} // attributes not to copy to HTML-CSS or SVG output
  1517. // from MathML input (in addition to the ones in MML.nocopyAttributes).
  1518. // An id set to true will be ignored, one set to false will
  1519. // be allowed (even if other criteria normally would prevent
  1520. // it from being copied); use false carefully!
  1521. },
  1522. preProcessors: MathJax.Callback.Hooks(true), // list of callbacks for preprocessing (initialized by extensions)
  1523. inputJax: {}, // mime-type mapped to input jax (by registration)
  1524. outputJax: {order:{}}, // mime-type mapped to output jax list (by registration)
  1525. processSectionDelay: 50, // pause between input and output phases of processing
  1526. processUpdateTime: 250, // time between screen updates when processing math (milliseconds)
  1527. processUpdateDelay: 10, // pause between screen updates to allow other processing (milliseconds)
  1528. signal: MathJax.Callback.Signal("Hub"), // Signal used for Hub events
  1529. Config: function (def) {
  1530. this.Insert(this.config,def);
  1531. if (this.config.Augment) {this.Augment(this.config.Augment)}
  1532. },
  1533. CombineConfig: function (name,def) {
  1534. var config = this.config, id, parent; name = name.split(/\./);
  1535. for (var i = 0, m = name.length; i < m; i++) {
  1536. id = name[i]; if (!config[id]) {config[id] = {}}
  1537. parent = config; config = config[id];
  1538. }
  1539. parent[id] = config = this.Insert(def,config);
  1540. return config;
  1541. },
  1542. Register: {
  1543. PreProcessor: function () {return MathJax.Hub.preProcessors.Add.apply(MathJax.Hub.preProcessors,arguments)},
  1544. MessageHook: function () {return MathJax.Hub.signal.MessageHook.apply(MathJax.Hub.signal,arguments)},
  1545. StartupHook: function () {return MathJax.Hub.Startup.signal.MessageHook.apply(MathJax.Hub.Startup.signal,arguments)},
  1546. LoadHook: function () {return MathJax.Ajax.LoadHook.apply(MathJax.Ajax,arguments)}
  1547. },
  1548. UnRegister: {
  1549. PreProcessor: function (hook) {MathJax.Hub.preProcessors.Remove(hook)},
  1550. MessageHook: function (hook) {MathJax.Hub.signal.RemoveHook(hook)},
  1551. StartupHook: function (hook) {MathJax.Hub.Startup.signal.RemoveHook(hook)},
  1552. LoadHook: function (hook) {MathJax.Ajax.removeHook(hook)}
  1553. },
  1554. setRenderer: function (renderer,type) {
  1555. if (!renderer) return;
  1556. if (!MathJax.OutputJax[renderer]) {
  1557. this.config.menuSettings.renderer = "";
  1558. var file = "[MathJax]/jax/output/"+renderer+"/config.js";
  1559. return MathJax.Ajax.Require(file,["setRenderer",this,renderer,type]);
  1560. } else {
  1561. this.config.menuSettings.renderer = renderer;
  1562. if (type == null) {type = "jax/mml"}
  1563. var jax = this.outputJax;
  1564. if (jax[type] && jax[type].length) {
  1565. if (renderer !== jax[type][0].id) {
  1566. jax[type].unshift(MathJax.OutputJax[renderer]);
  1567. return this.signal.Post(["Renderer Selected",renderer]);
  1568. }
  1569. }
  1570. return null;
  1571. }
  1572. },
  1573. Queue: function () {
  1574. return this.queue.Push.apply(this.queue,arguments);
  1575. },
  1576. RestartAfter: function (callback) {
  1577. throw this.Insert(Error("restart"),{restart: MathJax.Callback(callback)});
  1578. },
  1579. Insert: function (dst,src) {
  1580. for (var id in src) {if (src.hasOwnProperty(id)) {
  1581. // allow for concatenation of arrays?
  1582. if (typeof src[id] === 'object' && !(src[id] instanceof Array) &&
  1583. (typeof dst[id] === 'object' || typeof dst[id] === 'function')) {
  1584. this.Insert(dst[id],src[id]);
  1585. } else {
  1586. dst[id] = src[id];
  1587. }
  1588. }}
  1589. return dst;
  1590. },
  1591. // Old browsers (e.g. Internet Explorer <= 8) do not support trim().
  1592. SplitList: ("trim" in String.prototype ?
  1593. function (list) {return list.trim().split(/\s+/)} :
  1594. function (list) {return list.replace(/^\s+/,'').
  1595. replace(/\s+$/,'').split(/\s+/)})
  1596. };
  1597. //
  1598. // Storage area for extensions and preprocessors
  1599. //
  1600. MathJax.Extension = {};
  1601. MathJax.Hub.Startup = {
  1602. queue: MathJax.Callback.Queue(), // Queue used for startup actions
  1603. signal: MathJax.Callback.Signal("Startup") // Signal used for startup events
  1604. };
  1605. MathJax.Ajax.config.root = MathJax.Hub.config.root;
  1606. /**********************************************************/
  1607. (function (BASENAME) {
  1608. var BASE = window[BASENAME], ROOT = "["+BASENAME+"]";
  1609. var HUB = BASE.Hub, AJAX = BASE.Ajax, CALLBACK = BASE.Callback;
  1610. var JAX = MathJax.Object.Subclass({
  1611. JAXFILE: "jax.js",
  1612. require: null, // array of files to load before jax.js is complete
  1613. config: {},
  1614. //
  1615. // Make a subclass and return an instance of it.
  1616. // (FIXME: should we replace config with a copy of the constructor's
  1617. // config? Otherwise all subclasses share the same config structure.)
  1618. //
  1619. Init: function (def,cdef) {
  1620. if (arguments.length === 0) {return this}
  1621. return (this.constructor.Subclass(def,cdef))();
  1622. },
  1623. //
  1624. // Augment by merging with class definition (not replacing)
  1625. //
  1626. Augment: function (def,cdef) {
  1627. var cObject = this.constructor, ndef = {};
  1628. if (def != null) {
  1629. for (var id in def) {if (def.hasOwnProperty(id)) {
  1630. if (typeof def[id] === "function")
  1631. {cObject.protoFunction(id,def[id])} else {ndef[id] = def[id]}
  1632. }}
  1633. // MSIE doesn't list toString even if it is not native so handle it separately
  1634. if (def.toString !== cObject.prototype.toString && def.toString !== {}.toString)
  1635. {cObject.protoFunction('toString',def.toString)}
  1636. }
  1637. HUB.Insert(cObject.prototype,ndef);
  1638. cObject.Augment(null,cdef);
  1639. return this;
  1640. },
  1641. Translate: function (script,state) {
  1642. throw Error(this.directory+"/"+this.JAXFILE+" failed to define the Translate() method");
  1643. },
  1644. Register: function (mimetype) {},
  1645. Config: function () {
  1646. this.config = HUB.CombineConfig(this.id,this.config);
  1647. if (this.config.Augment) {this.Augment(this.config.Augment)}
  1648. },
  1649. Startup: function () {},
  1650. loadComplete: function (file) {
  1651. if (file === "config.js") {
  1652. return AJAX.loadComplete(this.directory+"/"+file);
  1653. } else {
  1654. var queue = CALLBACK.Queue();
  1655. queue.Push(
  1656. ["Post",HUB.Startup.signal,this.id+" Jax Config"],
  1657. ["Config",this],
  1658. ["Post",HUB.Startup.signal,this.id+" Jax Startup"],
  1659. ["Startup",this],
  1660. ["Post",HUB.Startup.signal,this.id+" Jax Ready"]
  1661. );
  1662. if (this.copyTranslate) {
  1663. queue.Push(
  1664. [function (THIS) {
  1665. THIS.preProcess = THIS.preTranslate;
  1666. THIS.Process = THIS.Translate;
  1667. THIS.postProcess = THIS.postTranslate;
  1668. },this.constructor.prototype]
  1669. );
  1670. }
  1671. return queue.Push(["loadComplete",AJAX,this.directory+"/"+file]);
  1672. }
  1673. }
  1674. },{
  1675. id: "Jax",
  1676. version: "2.6.0",
  1677. directory: ROOT+"/jax",
  1678. extensionDir: ROOT+"/extensions"
  1679. });
  1680. /***********************************/
  1681. BASE.InputJax = JAX.Subclass({
  1682. elementJax: "mml", // the element jax to load for this input jax
  1683. sourceMenuTitle: /*_(MathMenu)*/ ["Original","Original Form"],
  1684. copyTranslate: true,
  1685. Process: function (script,state) {
  1686. throw Error("Input jax failed to load properly")
  1687. },
  1688. needsUpdate: function (jax) {
  1689. var script = jax.SourceElement();
  1690. return (jax.originalText !== BASE.HTML.getScript(script));
  1691. },
  1692. Register: function (mimetype) {
  1693. if (!HUB.inputJax) {HUB.inputJax = {}}
  1694. HUB.inputJax[mimetype] = this;
  1695. }
  1696. },{
  1697. id: "InputJax",
  1698. version: "2.6.0",
  1699. directory: JAX.directory+"/input",
  1700. extensionDir: JAX.extensionDir
  1701. });
  1702. /***********************************/
  1703. BASE.OutputJax = JAX.Subclass({
  1704. copyTranslate: true,
  1705. preProcess: function (state) {
  1706. throw Error("Output jax failed to load properly");
  1707. },
  1708. Register: function (mimetype) {
  1709. var jax = HUB.outputJax;
  1710. if (!jax[mimetype]) {jax[mimetype] = []}
  1711. // If the output jax is earlier in the original configuration list, put it first here
  1712. if (jax[mimetype].length && (this.id === HUB.config.menuSettings.renderer ||
  1713. (jax.order[this.id]||0) < (jax.order[jax[mimetype][0].id]||0)))
  1714. {jax[mimetype].unshift(this)} else {jax[mimetype].push(this)}
  1715. },
  1716. Remove: function (jax) {}
  1717. },{
  1718. id: "OutputJax",
  1719. version: "2.6.0",
  1720. directory: JAX.directory+"/output",
  1721. extensionDir: JAX.extensionDir,
  1722. fontDir: ROOT+(BASE.isPacked?"":"/..")+"/fonts",
  1723. imageDir: ROOT+(BASE.isPacked?"":"/..")+"/images"
  1724. });
  1725. /***********************************/
  1726. BASE.ElementJax = JAX.Subclass({
  1727. // make a subclass, not an instance
  1728. Init: function (def,cdef) {return this.constructor.Subclass(def,cdef)},
  1729. inputJax: null,
  1730. outputJax: null,
  1731. inputID: null,
  1732. originalText: "",
  1733. mimeType: "",
  1734. sourceMenuTitle: /*_(MathMenu)*/ ["MathMLcode","MathML Code"],
  1735. Text: function (text,callback) {
  1736. var script = this.SourceElement();
  1737. BASE.HTML.setScript(script,text);
  1738. script.MathJax.state = this.STATE.UPDATE;
  1739. return HUB.Update(script,callback);
  1740. },
  1741. Reprocess: function (callback) {
  1742. var script = this.SourceElement();
  1743. script.MathJax.state = this.STATE.UPDATE;
  1744. return HUB.Reprocess(script,callback);
  1745. },
  1746. Update: function (callback) {return this.Rerender(callback)},
  1747. Rerender: function (callback) {
  1748. var script = this.SourceElement();
  1749. script.MathJax.state = this.STATE.OUTPUT;
  1750. return HUB.Process(script,callback);
  1751. },
  1752. Remove: function (keep) {
  1753. if (this.hover) {this.hover.clear(this)}
  1754. BASE.OutputJax[this.outputJax].Remove(this);
  1755. if (!keep) {
  1756. HUB.signal.Post(["Remove Math",this.inputID]); // wait for this to finish?
  1757. this.Detach();
  1758. }
  1759. },
  1760. needsUpdate: function () {
  1761. return BASE.InputJax[this.inputJax].needsUpdate(this);
  1762. },
  1763. SourceElement: function () {return document.getElementById(this.inputID)},
  1764. Attach: function (script,inputJax) {
  1765. var jax = script.MathJax.elementJax;
  1766. if (script.MathJax.state === this.STATE.UPDATE) {
  1767. jax.Clone(this);
  1768. } else {
  1769. jax = script.MathJax.elementJax = this;
  1770. if (script.id) {this.inputID = script.id}
  1771. else {script.id = this.inputID = BASE.ElementJax.GetID(); this.newID = 1}
  1772. }
  1773. jax.originalText = BASE.HTML.getScript(script);
  1774. jax.inputJax = inputJax;
  1775. if (jax.root) {jax.root.inputID = jax.inputID}
  1776. return jax;
  1777. },
  1778. Detach: function () {
  1779. var script = this.SourceElement(); if (!script) return;
  1780. try {delete script.MathJax} catch(err) {script.MathJax = null}
  1781. if (this.newID) {script.id = ""}
  1782. },
  1783. Clone: function (jax) {
  1784. var id;
  1785. for (id in this) {
  1786. if (!this.hasOwnProperty(id)) continue;
  1787. if (typeof(jax[id]) === 'undefined' && id !== 'newID') {delete this[id]}
  1788. }
  1789. for (id in jax) {
  1790. if (!jax.hasOwnProperty(id)) continue;
  1791. if (typeof(this[id]) === 'undefined' || (this[id] !== jax[id] && id !== 'inputID'))
  1792. {this[id] = jax[id]}
  1793. }
  1794. }
  1795. },{
  1796. id: "ElementJax",
  1797. version: "2.6.0",
  1798. directory: JAX.directory+"/element",
  1799. extensionDir: JAX.extensionDir,
  1800. ID: 0, // jax counter (for IDs)
  1801. STATE: {
  1802. PENDING: 1, // script is identified as math but not yet processed
  1803. PROCESSED: 2, // script has been processed
  1804. UPDATE: 3, // elementJax should be updated
  1805. OUTPUT: 4 // output should be updated (input is OK)
  1806. },
  1807. GetID: function () {this.ID++; return "MathJax-Element-"+this.ID},
  1808. Subclass: function () {
  1809. var obj = JAX.Subclass.apply(this,arguments);
  1810. obj.loadComplete = this.prototype.loadComplete;
  1811. return obj;
  1812. }
  1813. });
  1814. BASE.ElementJax.prototype.STATE = BASE.ElementJax.STATE;
  1815. })("MathJax");
  1816. MathJax.Hub.Browser = {Select: function () {}};