MathJax.js 124 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324
  1. /* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
  2. /* vim: set ts=2 et sw=2 tw=80: */
  3. /*************************************************************
  4. *
  5. * MathJax.js
  6. *
  7. * The main support code for the MathJax Hub, including the
  8. * Ajax, Callback, Messaging, and Object-Oriented Programming
  9. * libraries, as well as the base Jax classes, and startup
  10. * processing code.
  11. *
  12. * ---------------------------------------------------------------------
  13. *
  14. * Copyright (c) 2009-2018 The MathJax Consortium
  15. *
  16. * Licensed under the Apache License, Version 2.0 (the "License");
  17. * you may not use this file except in compliance with the License.
  18. * You may obtain a copy of the License at
  19. *
  20. * http://www.apache.org/licenses/LICENSE-2.0
  21. *
  22. * Unless required by applicable law or agreed to in writing, software
  23. * distributed under the License is distributed on an "AS IS" BASIS,
  24. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  25. * See the License for the specific language governing permissions and
  26. * limitations under the License.
  27. */
  28. //
  29. // Check if browser can support MathJax (no one fails this nowadays)
  30. //
  31. if (document.getElementById && document.childNodes && document.createElement) {
  32. //
  33. // Skip if MathJax is already loaded
  34. //
  35. if (!(window.MathJax && MathJax.Hub)) {
  36. //
  37. // Get author configuration from MathJax variable, if any
  38. //
  39. if (window.MathJax) {window.MathJax = {AuthorConfig: window.MathJax}}
  40. else {window.MathJax = {}}
  41. // MathJax.isPacked = true; // This line is uncommented by the packer.
  42. MathJax.version = "2.7.5";
  43. MathJax.fileversion = "2.7.5";
  44. MathJax.cdnVersion = "2.7.5"; // specifies a revision to break caching
  45. MathJax.cdnFileVersions = {}; // can be used to specify revisions for individual files
  46. /**********************************************************/
  47. (function (BASENAME) {
  48. var BASE = window[BASENAME];
  49. if (!BASE) {BASE = window[BASENAME] = {}}
  50. var PROTO = []; // a static object used to indicate when a prototype is being created
  51. var OBJECT = function (def) {
  52. var obj = def.constructor; if (!obj) {obj = function () {}}
  53. for (var id in def) {if (id !== 'constructor' && def.hasOwnProperty(id)) {obj[id] = def[id]}}
  54. return obj;
  55. };
  56. var CONSTRUCTOR = function () {
  57. return function () {return arguments.callee.Init.call(this,arguments)};
  58. };
  59. BASE.Object = OBJECT({
  60. constructor: CONSTRUCTOR(),
  61. Subclass: function (def,classdef) {
  62. var obj = CONSTRUCTOR();
  63. obj.SUPER = this; obj.Init = this.Init;
  64. obj.Subclass = this.Subclass; obj.Augment = this.Augment;
  65. obj.protoFunction = this.protoFunction;
  66. obj.can = this.can; obj.has = this.has; obj.isa = this.isa;
  67. obj.prototype = new this(PROTO);
  68. obj.prototype.constructor = obj; // the real constructor
  69. obj.Augment(def,classdef);
  70. return obj;
  71. },
  72. Init: function (args) {
  73. var obj = this;
  74. if (args.length === 1 && args[0] === PROTO) {return obj}
  75. if (!(obj instanceof args.callee)) {obj = new args.callee(PROTO)}
  76. return obj.Init.apply(obj,args) || obj;
  77. },
  78. Augment: function (def,classdef) {
  79. var id;
  80. if (def != null) {
  81. for (id in def) {if (def.hasOwnProperty(id)) {this.protoFunction(id,def[id])}}
  82. // MSIE doesn't list toString even if it is not native so handle it separately
  83. if (def.toString !== this.prototype.toString && def.toString !== {}.toString)
  84. {this.protoFunction('toString',def.toString)}
  85. }
  86. if (classdef != null) {
  87. for (id in classdef) {if (classdef.hasOwnProperty(id)) {this[id] = classdef[id]}}
  88. }
  89. return this;
  90. },
  91. protoFunction: function (id,def) {
  92. this.prototype[id] = def;
  93. if (typeof def === "function") {def.SUPER = this.SUPER.prototype}
  94. },
  95. prototype: {
  96. Init: function () {},
  97. SUPER: function (fn) {return fn.callee.SUPER},
  98. can: function (method) {return typeof(this[method]) === "function"},
  99. has: function (property) {return typeof(this[property]) !== "undefined"},
  100. isa: function (obj) {return (obj instanceof Object) && (this instanceof obj)}
  101. },
  102. can: function (method) {return this.prototype.can.call(this,method)},
  103. has: function (property) {return this.prototype.has.call(this,property)},
  104. isa: function (obj) {
  105. var constructor = this;
  106. while (constructor) {
  107. if (constructor === obj) {return true} else {constructor = constructor.SUPER}
  108. }
  109. return false;
  110. },
  111. SimpleSUPER: OBJECT({
  112. constructor: function (def) {return this.SimpleSUPER.define(def)},
  113. define: function (src) {
  114. var dst = {};
  115. if (src != null) {
  116. for (var id in src) {if (src.hasOwnProperty(id)) {dst[id] = this.wrap(id,src[id])}}
  117. // MSIE doesn't list toString even if it is not native so handle it separately
  118. if (src.toString !== this.prototype.toString && src.toString !== {}.toString)
  119. {dst.toString = this.wrap('toString',src.toString)}
  120. }
  121. return dst;
  122. },
  123. wrap: function (id,f) {
  124. if (typeof(f) !== 'function' || !f.toString().match(/\.\s*SUPER\s*\(/)) {return f}
  125. var fn = function () {
  126. this.SUPER = fn.SUPER[id];
  127. try {var result = f.apply(this,arguments)} catch (err) {delete this.SUPER; throw err}
  128. delete this.SUPER;
  129. return result;
  130. }
  131. fn.toString = function () {return f.toString.apply(f,arguments)}
  132. return fn;
  133. }
  134. })
  135. });
  136. BASE.Object.isArray = Array.isArray || function (obj) {
  137. return Object.prototype.toString.call(obj) === "[object Array]";
  138. };
  139. BASE.Object.Array = Array;
  140. })("MathJax");
  141. /**********************************************************/
  142. /*
  143. * Create a callback function from various forms of data:
  144. *
  145. * MathJax.Callback(fn) -- callback to a function
  146. *
  147. * MathJax.Callback([fn]) -- callback to function
  148. * MathJax.Callback([fn,data...])
  149. * -- callback to function with given data as arguments
  150. * MathJax.Callback([object,fn])
  151. * -- call fn with object as "this"
  152. * MathJax.Callback([object,fn,data...])
  153. * -- call fn with object as "this" and data as arguments
  154. * MathJax.Callback(["method",object])
  155. * -- call method of object wth object as "this"
  156. * MathJax.Callback(["method",object,data...])
  157. * -- as above, but with data as arguments to method
  158. *
  159. * MathJax.Callback({hook: fn, data: [...], object: this})
  160. * -- give function, data, and object to act as "this" explicitly
  161. *
  162. * MathJax.Callback("code") -- callback that compiles and executes a string
  163. *
  164. * MathJax.Callback([...],i)
  165. * -- use slice of array starting at i and interpret
  166. * result as above. (Used for passing "arguments" array
  167. * and trimming initial arguments, if any.)
  168. */
  169. /*
  170. * MathJax.Callback.After([...],cb1,cb2,...)
  171. * -- make a callback that isn't called until all the other
  172. * ones are called first. I.e., wait for a union of
  173. * callbacks to occur before making the given callback.
  174. */
  175. /*
  176. * MathJax.Callback.Queue([callback,...])
  177. * -- make a synchronized queue of commands that process
  178. * sequentially, waiting for those that return uncalled
  179. * callbacks.
  180. */
  181. /*
  182. * MathJax.Callback.Signal(name)
  183. * -- finds or creates a names signal, to which listeners
  184. * can be attached and are signaled by messages posted
  185. * to the signal. Responses can be asynchronous.
  186. */
  187. (function (BASENAME) {
  188. var BASE = window[BASENAME];
  189. if (!BASE) {BASE = window[BASENAME] = {}}
  190. var isArray = BASE.Object.isArray;
  191. //
  192. // Create a callback from an associative array
  193. //
  194. var CALLBACK = function (data) {
  195. var cb = function () {return arguments.callee.execute.apply(arguments.callee,arguments)};
  196. for (var id in CALLBACK.prototype) {
  197. if (CALLBACK.prototype.hasOwnProperty(id)) {
  198. if (typeof(data[id]) !== 'undefined') {cb[id] = data[id]}
  199. else {cb[id] = CALLBACK.prototype[id]}
  200. }
  201. }
  202. cb.toString = CALLBACK.prototype.toString;
  203. return cb;
  204. };
  205. CALLBACK.prototype = {
  206. isCallback: true,
  207. hook: function () {},
  208. data: [],
  209. object: window,
  210. execute: function () {
  211. if (!this.called || this.autoReset) {
  212. this.called = !this.autoReset;
  213. return this.hook.apply(this.object,this.data.concat([].slice.call(arguments,0)));
  214. }
  215. },
  216. reset: function () {delete this.called},
  217. toString: function () {return this.hook.toString.apply(this.hook,arguments)}
  218. };
  219. var ISCALLBACK = function (f) {
  220. return (typeof(f) === "function" && f.isCallback);
  221. }
  222. //
  223. // Evaluate a string in global context
  224. //
  225. var EVAL = function (code) {return eval.call(window,code)}
  226. var TESTEVAL = function () {
  227. EVAL("var __TeSt_VaR__ = 1"); // check if it works in global context
  228. if (window.__TeSt_VaR__) {
  229. try { delete window.__TeSt_VaR__; } // NOTE IE9 throws when in IE7 mode
  230. catch (error) { window.__TeSt_VaR__ = null; }
  231. } else {
  232. if (window.execScript) {
  233. // IE
  234. EVAL = function (code) {
  235. BASE.__code = code;
  236. code = "try {"+BASENAME+".__result = eval("+BASENAME+".__code)} catch(err) {"+BASENAME+".__result = err}";
  237. window.execScript(code);
  238. var result = BASE.__result; delete BASE.__result; delete BASE.__code;
  239. if (result instanceof Error) {throw result}
  240. return result;
  241. }
  242. } else {
  243. // Safari2
  244. EVAL = function (code) {
  245. BASE.__code = code;
  246. code = "try {"+BASENAME+".__result = eval("+BASENAME+".__code)} catch(err) {"+BASENAME+".__result = err}";
  247. var head = (document.getElementsByTagName("head"))[0]; if (!head) {head = document.body}
  248. var script = document.createElement("script");
  249. script.appendChild(document.createTextNode(code));
  250. head.appendChild(script); head.removeChild(script);
  251. var result = BASE.__result; delete BASE.__result; delete BASE.__code;
  252. if (result instanceof Error) {throw result}
  253. return result;
  254. }
  255. }
  256. }
  257. TESTEVAL = null;
  258. };
  259. //
  260. // Create a callback from various types of data
  261. //
  262. var USING = function (args,i) {
  263. if (arguments.length > 1) {
  264. if (arguments.length === 2 && !(typeof arguments[0] === 'function') &&
  265. arguments[0] instanceof Object && typeof arguments[1] === 'number')
  266. {args = [].slice.call(args,i)}
  267. else {args = [].slice.call(arguments,0)}
  268. }
  269. if (isArray(args) && args.length === 1 && typeof(args[0]) === 'function') {args = args[0]}
  270. if (typeof args === 'function') {
  271. if (args.execute === CALLBACK.prototype.execute) {return args}
  272. return CALLBACK({hook: args});
  273. } else if (isArray(args)) {
  274. if (typeof(args[0]) === 'string' && args[1] instanceof Object &&
  275. typeof args[1][args[0]] === 'function') {
  276. return CALLBACK({hook: args[1][args[0]], object: args[1], data: args.slice(2)});
  277. } else if (typeof args[0] === 'function') {
  278. return CALLBACK({hook: args[0], data: args.slice(1)});
  279. } else if (typeof args[1] === 'function') {
  280. return CALLBACK({hook: args[1], object: args[0], data: args.slice(2)});
  281. }
  282. } else if (typeof(args) === 'string') {
  283. if (TESTEVAL) TESTEVAL();
  284. return CALLBACK({hook: EVAL, data: [args]});
  285. } else if (args instanceof Object) {
  286. return CALLBACK(args);
  287. } else if (typeof(args) === 'undefined') {
  288. return CALLBACK({});
  289. }
  290. throw Error("Can't make callback from given data");
  291. };
  292. //
  293. // Wait for a given time to elapse and then perform the callback
  294. //
  295. var DELAY = function (time,callback) {
  296. callback = USING(callback);
  297. callback.timeout = setTimeout(callback,time);
  298. return callback;
  299. };
  300. //
  301. // Callback used by AFTER, QUEUE, and SIGNAL to check if calls have completed
  302. //
  303. var WAITFOR = function (callback,signal) {
  304. callback = USING(callback);
  305. if (!callback.called) {WAITSIGNAL(callback,signal); signal.pending++}
  306. };
  307. var WAITEXECUTE = function () {
  308. var signals = this.signal; delete this.signal;
  309. this.execute = this.oldExecute; delete this.oldExecute;
  310. var result = this.execute.apply(this,arguments);
  311. if (ISCALLBACK(result) && !result.called) {WAITSIGNAL(result,signals)} else {
  312. for (var i = 0, m = signals.length; i < m; i++) {
  313. signals[i].pending--;
  314. if (signals[i].pending <= 0) {signals[i].call()}
  315. }
  316. }
  317. };
  318. var WAITSIGNAL = function (callback,signals) {
  319. if (!isArray(signals)) {signals = [signals]}
  320. if (!callback.signal) {
  321. callback.oldExecute = callback.execute;
  322. callback.execute = WAITEXECUTE;
  323. callback.signal = signals;
  324. } else if (signals.length === 1) {callback.signal.push(signals[0])}
  325. else {callback.signal = callback.signal.concat(signals)}
  326. };
  327. //
  328. // Create a callback that is called when a collection of other callbacks have
  329. // all been executed. If the callback gets called immediately (i.e., the
  330. // others are all already called), check if it returns another callback
  331. // and return that instead.
  332. //
  333. var AFTER = function (callback) {
  334. callback = USING(callback);
  335. callback.pending = 0;
  336. for (var i = 1, m = arguments.length; i < m; i++)
  337. {if (arguments[i]) {WAITFOR(arguments[i],callback)}}
  338. if (callback.pending === 0) {
  339. var result = callback();
  340. if (ISCALLBACK(result)) {callback = result}
  341. }
  342. return callback;
  343. };
  344. //
  345. // An array of prioritized hooks that are executed sequentially
  346. // with a given set of data.
  347. //
  348. var HOOKS = MathJax.Object.Subclass({
  349. //
  350. // Initialize the array and the auto-reset status
  351. //
  352. Init: function (reset) {
  353. this.hooks = [];
  354. this.remove = []; // used when hooks are removed during execution of list
  355. this.reset = reset;
  356. this.running = false;
  357. },
  358. //
  359. // Add a callback to the list, in priority order (default priority is 10)
  360. //
  361. Add: function (hook,priority) {
  362. if (priority == null) {priority = 10}
  363. if (!ISCALLBACK(hook)) {hook = USING(hook)}
  364. hook.priority = priority;
  365. var i = this.hooks.length;
  366. while (i > 0 && priority < this.hooks[i-1].priority) {i--}
  367. this.hooks.splice(i,0,hook);
  368. return hook;
  369. },
  370. Remove: function (hook) {
  371. for (var i = 0, m = this.hooks.length; i < m; i++) {
  372. if (this.hooks[i] === hook) {
  373. if (this.running) {this.remove.push(i)}
  374. else {this.hooks.splice(i,1)}
  375. return;
  376. }
  377. }
  378. },
  379. //
  380. // Execute the list of callbacks, resetting them if requested.
  381. // If any return callbacks, return a callback that will be
  382. // executed when they all have completed.
  383. // Remove any hooks that requested being removed during processing.
  384. //
  385. Execute: function () {
  386. var callbacks = [{}];
  387. this.running = true;
  388. for (var i = 0, m = this.hooks.length; i < m; i++) {
  389. if (this.reset) {this.hooks[i].reset()}
  390. var result = this.hooks[i].apply(window,arguments);
  391. if (ISCALLBACK(result) && !result.called) {callbacks.push(result)}
  392. }
  393. this.running = false;
  394. if (this.remove.length) {this.RemovePending()}
  395. if (callbacks.length === 1) {return null}
  396. if (callbacks.length === 2) {return callbacks[1]}
  397. return AFTER.apply({},callbacks);
  398. },
  399. //
  400. // Remove hooks that asked to be removed during execution of list
  401. //
  402. RemovePending: function () {
  403. this.remove = this.remove.sort();
  404. for (var i = this.remove.length-1; i >= 0; i--) {this.hooks.splice(i,1)}
  405. this.remove = [];
  406. }
  407. });
  408. //
  409. // Run an array of callbacks passing them the given data.
  410. // (Legacy function, since this has been replaced by the HOOKS object).
  411. //
  412. var EXECUTEHOOKS = function (hooks,data,reset) {
  413. if (!hooks) {return null}
  414. if (!isArray(hooks)) {hooks = [hooks]}
  415. if (!isArray(data)) {data = (data == null ? [] : [data])}
  416. var handler = HOOKS(reset);
  417. for (var i = 0, m = hooks.length; i < m; i++) {handler.Add(hooks[i])}
  418. return handler.Execute.apply(handler,data);
  419. };
  420. //
  421. // Command queue that performs commands in order, waiting when
  422. // necessary for commands to complete asynchronousely
  423. //
  424. var QUEUE = BASE.Object.Subclass({
  425. //
  426. // Create the queue and push any commands that are specified
  427. //
  428. Init: function () {
  429. this.pending = this.running = 0;
  430. this.queue = [];
  431. this.Push.apply(this,arguments);
  432. },
  433. //
  434. // Add commands to the queue and run them. Adding a callback object
  435. // (rather than a callback specification) queues a wait for that callback.
  436. // Return the final callback for synchronization purposes.
  437. //
  438. Push: function () {
  439. var callback;
  440. for (var i = 0, m = arguments.length; i < m; i++) {
  441. callback = USING(arguments[i]);
  442. if (callback === arguments[i] && !callback.called)
  443. {callback = USING(["wait",this,callback])}
  444. this.queue.push(callback);
  445. }
  446. if (!this.running && !this.pending) {this.Process()}
  447. return callback;
  448. },
  449. //
  450. // Process the command queue if we aren't waiting on another command
  451. //
  452. Process: function (queue) {
  453. while (!this.running && !this.pending && this.queue.length) {
  454. var callback = this.queue[0];
  455. queue = this.queue.slice(1); this.queue = [];
  456. this.Suspend(); var result = callback(); this.Resume();
  457. if (queue.length) {this.queue = queue.concat(this.queue)}
  458. if (ISCALLBACK(result) && !result.called) {WAITFOR(result,this)}
  459. }
  460. },
  461. //
  462. // Suspend/Resume command processing on this queue
  463. //
  464. Suspend: function () {this.running++},
  465. Resume: function () {if (this.running) {this.running--}},
  466. //
  467. // Used by WAITFOR to restart the queue when an action completes
  468. //
  469. call: function () {this.Process.apply(this,arguments)},
  470. wait: function (callback) {return callback}
  471. });
  472. //
  473. // Create a named signal that listeners can attach to, to be signaled by
  474. // postings made to the signal. Posts are queued if they occur while one
  475. // is already in process.
  476. //
  477. var SIGNAL = QUEUE.Subclass({
  478. Init: function (name) {
  479. QUEUE.prototype.Init.call(this);
  480. this.name = name;
  481. this.posted = []; // the messages posted so far
  482. this.listeners = HOOKS(true); // those with interest in this signal
  483. this.posting = false;
  484. this.callback = null;
  485. },
  486. //
  487. // Post a message to the signal listeners, with callback for when complete
  488. //
  489. Post: function (message,callback,forget) {
  490. callback = USING(callback);
  491. if (this.posting || this.pending) {
  492. this.Push(["Post",this,message,callback,forget]);
  493. } else {
  494. this.callback = callback; callback.reset();
  495. if (!forget) {this.posted.push(message)}
  496. this.Suspend(); this.posting = true;
  497. var result = this.listeners.Execute(message);
  498. if (ISCALLBACK(result) && !result.called) {WAITFOR(result,this)}
  499. this.Resume(); this.posting = false;
  500. if (!this.pending) {this.call()}
  501. }
  502. return callback;
  503. },
  504. //
  505. // Clear the post history (so new listeners won't get old messages)
  506. //
  507. Clear: function (callback) {
  508. callback = USING(callback);
  509. if (this.posting || this.pending) {
  510. callback = this.Push(["Clear",this,callback]);
  511. } else {
  512. this.posted = [];
  513. callback();
  514. }
  515. return callback;
  516. },
  517. //
  518. // Call the callback (all replies are in) and process the command queue
  519. //
  520. call: function () {this.callback(this); this.Process()},
  521. //
  522. // A listener calls this to register interest in the signal (so it will be called
  523. // when posts occur). If ignorePast is true, it will not be sent the post history.
  524. //
  525. Interest: function (callback,ignorePast,priority) {
  526. callback = USING(callback);
  527. this.listeners.Add(callback,priority);
  528. if (!ignorePast) {
  529. for (var i = 0, m = this.posted.length; i < m; i++) {
  530. callback.reset();
  531. var result = callback(this.posted[i]);
  532. if (ISCALLBACK(result) && i === this.posted.length-1) {WAITFOR(result,this)}
  533. }
  534. }
  535. return callback;
  536. },
  537. //
  538. // A listener calls this to remove itself from a signal
  539. //
  540. NoInterest: function (callback) {
  541. this.listeners.Remove(callback);
  542. },
  543. //
  544. // Hook a callback to a particular message on this signal
  545. //
  546. MessageHook: function (msg,callback,priority) {
  547. callback = USING(callback);
  548. if (!this.hooks) {this.hooks = {}; this.Interest(["ExecuteHooks",this])}
  549. if (!this.hooks[msg]) {this.hooks[msg] = HOOKS(true)}
  550. this.hooks[msg].Add(callback,priority);
  551. for (var i = 0, m = this.posted.length; i < m; i++)
  552. {if (this.posted[i] == msg) {callback.reset(); callback(this.posted[i])}}
  553. callback.msg = msg; // keep track so we can remove it
  554. return callback;
  555. },
  556. //
  557. // Execute the message hooks for the given message
  558. //
  559. ExecuteHooks: function (msg) {
  560. var type = (isArray(msg) ? msg[0] : msg);
  561. if (!this.hooks[type]) {return null}
  562. return this.hooks[type].Execute(msg);
  563. },
  564. //
  565. // Remove a hook safely
  566. //
  567. RemoveHook: function (hook) {
  568. this.hooks[hook.msg].Remove(hook);
  569. }
  570. },{
  571. signals: {}, // the named signals
  572. find: function (name) {
  573. if (!SIGNAL.signals[name]) {SIGNAL.signals[name] = new SIGNAL(name)}
  574. return SIGNAL.signals[name];
  575. }
  576. });
  577. //
  578. // The main entry-points
  579. //
  580. BASE.Callback = BASE.CallBack = USING;
  581. BASE.Callback.Delay = DELAY;
  582. BASE.Callback.After = AFTER;
  583. BASE.Callback.Queue = QUEUE;
  584. BASE.Callback.Signal = SIGNAL.find;
  585. BASE.Callback.Hooks = HOOKS;
  586. BASE.Callback.ExecuteHooks = EXECUTEHOOKS;
  587. })("MathJax");
  588. /**********************************************************/
  589. (function (BASENAME) {
  590. var BASE = window[BASENAME];
  591. if (!BASE) {BASE = window[BASENAME] = {}}
  592. var isSafari2 = (navigator.vendor === "Apple Computer, Inc." &&
  593. typeof navigator.vendorSub === "undefined");
  594. var sheets = 0; // used by Safari2
  595. //
  596. // Update sheets count and look up the head object
  597. //
  598. var HEAD = function (head) {
  599. if (document.styleSheets && document.styleSheets.length > sheets)
  600. {sheets = document.styleSheets.length}
  601. if (!head) {
  602. head = document.head || ((document.getElementsByTagName("head"))[0]);
  603. if (!head) {head = document.body}
  604. }
  605. return head;
  606. };
  607. //
  608. // Remove scripts that are completed so they don't clutter up the HEAD.
  609. // This runs via setTimeout since IE7 can't remove the script while it is running.
  610. //
  611. var SCRIPTS = []; // stores scripts to be removed after a delay
  612. var REMOVESCRIPTS = function () {
  613. for (var i = 0, m = SCRIPTS.length; i < m; i++) {BASE.Ajax.head.removeChild(SCRIPTS[i])}
  614. SCRIPTS = [];
  615. };
  616. var PATH = {};
  617. PATH[BASENAME] = ""; // empty path gets the root URL
  618. PATH.a11y = '[MathJax]/extensions/a11y'; // a11y extensions
  619. PATH.Contrib = "https://cdn.mathjax.org/mathjax/contrib"; // the third-party extensions
  620. BASE.Ajax = {
  621. loaded: {}, // files already loaded
  622. loading: {}, // files currently in process of loading
  623. loadHooks: {}, // hooks to call when files are loaded
  624. timeout: 15*1000, // timeout for loading of files (15 seconds)
  625. styleDelay: 1, // delay to use before styles are available
  626. config: {
  627. root: "", // URL of root directory to load from
  628. path: PATH // paths to named URL's (e.g., [MathJax]/...)
  629. },
  630. params: {}, // filled in from MathJax.js?...
  631. STATUS: {
  632. OK: 1, // file is loading or did load OK
  633. ERROR: -1 // file timed out during load
  634. },
  635. //
  636. // Return a complete URL to a file (replacing any root names)
  637. //
  638. fileURL: function (file) {
  639. var match;
  640. while ((match = file.match(/^\[([-._a-z0-9]+)\]/i)) && PATH.hasOwnProperty(match[1])) {
  641. file = (PATH[match[1]]||this.config.root) + file.substr(match[1].length+2);
  642. }
  643. return file;
  644. },
  645. //
  646. // Replace root names if URL includes one
  647. //
  648. fileName: function (url) {
  649. var root = this.config.root;
  650. if (url.substr(0,root.length) === root) {url = "["+BASENAME+"]"+url.substr(root.length)}
  651. do {
  652. var recheck = false;
  653. for (var id in PATH) {if (PATH.hasOwnProperty(id) && PATH[id]) {
  654. if (url.substr(0,PATH[id].length) === PATH[id]) {
  655. url = "["+id+"]"+url.substr(PATH[id].length);
  656. recheck = true;
  657. break;
  658. }
  659. }}
  660. } while (recheck);
  661. return url;
  662. },
  663. //
  664. // Cache-breaking revision number for file
  665. //
  666. fileRev: function (file) {
  667. var V = BASE.cdnFileVersions[file] || BASE.cdnVersion || '';
  668. if (V) {V = "?V="+V}
  669. return V;
  670. },
  671. urlRev: function (file) {return this.fileURL(file)+this.fileRev(file)},
  672. //
  673. // Load a file if it hasn't been already.
  674. // Make sure the file URL is "safe"?
  675. //
  676. Require: function (file,callback) {
  677. callback = BASE.Callback(callback); var type;
  678. if (file instanceof Object) {
  679. for (var i in file)
  680. {if (file.hasOwnProperty(i)) {type = i.toUpperCase(); file = file[i]}}
  681. } else {type = file.split(/\./).pop().toUpperCase()}
  682. if (this.params.noContrib && file.substr(0,9) === "[Contrib]") {
  683. callback(this.STATUS.ERROR);
  684. } else {
  685. file = this.fileURL(file);
  686. // FIXME: check that URL is OK
  687. if (this.loaded[file]) {
  688. callback(this.loaded[file]);
  689. } else {
  690. var FILE = {}; FILE[type] = file;
  691. this.Load(FILE,callback);
  692. }
  693. }
  694. return callback;
  695. },
  696. //
  697. // Load a file regardless of where it is and whether it has
  698. // already been loaded.
  699. //
  700. Load: function (file,callback) {
  701. callback = BASE.Callback(callback); var type;
  702. if (file instanceof Object) {
  703. for (var i in file)
  704. {if (file.hasOwnProperty(i)) {type = i.toUpperCase(); file = file[i]}}
  705. } else {type = file.split(/\./).pop().toUpperCase()}
  706. file = this.fileURL(file);
  707. if (this.loading[file]) {
  708. this.addHook(file,callback);
  709. } else {
  710. this.head = HEAD(this.head);
  711. if (this.loader[type]) {this.loader[type].call(this,file,callback)}
  712. else {throw Error("Can't load files of type "+type)}
  713. }
  714. return callback;
  715. },
  716. //
  717. // Register a load hook for a particular file (it will be called when
  718. // loadComplete() is called for that file)
  719. //
  720. LoadHook: function (file,callback,priority) {
  721. callback = BASE.Callback(callback);
  722. if (file instanceof Object)
  723. {for (var i in file) {if (file.hasOwnProperty(i)) {file = file[i]}}}
  724. file = this.fileURL(file);
  725. if (this.loaded[file]) {callback(this.loaded[file])}
  726. else {this.addHook(file,callback,priority)}
  727. return callback;
  728. },
  729. addHook: function (file,callback,priority) {
  730. if (!this.loadHooks[file]) {this.loadHooks[file] = MathJax.Callback.Hooks()}
  731. this.loadHooks[file].Add(callback,priority);
  732. callback.file = file;
  733. },
  734. removeHook: function (hook) {
  735. if (this.loadHooks[hook.file]) {
  736. this.loadHooks[hook.file].Remove(hook);
  737. if (!this.loadHooks[hook.file].hooks.length) {delete this.loadHooks[hook.file]}
  738. }
  739. },
  740. //
  741. // Used when files are combined in a preloading configuration file
  742. //
  743. Preloading: function () {
  744. for (var i = 0, m = arguments.length; i < m; i++) {
  745. var file = this.fileURL(arguments[i]);
  746. if (!this.loading[file]) {this.loading[file] = {preloaded: true}}
  747. }
  748. },
  749. //
  750. // Code used to load the various types of files
  751. // (JS for JavaScript, CSS for style sheets)
  752. //
  753. loader: {
  754. //
  755. // Create a SCRIPT tag to load the file
  756. //
  757. JS: function (file,callback) {
  758. var name = this.fileName(file);
  759. var script = document.createElement("script");
  760. var timeout = BASE.Callback(["loadTimeout",this,file]);
  761. this.loading[file] = {
  762. callback: callback,
  763. timeout: setTimeout(timeout,this.timeout),
  764. status: this.STATUS.OK,
  765. script: script
  766. };
  767. //
  768. // Add this to the structure above after it is created to prevent recursion
  769. // when loading the initial localization file (before loading message is available)
  770. //
  771. this.loading[file].message = BASE.Message.File(name);
  772. script.onerror = timeout; // doesn't work in IE and no apparent substitute
  773. script.type = "text/javascript";
  774. script.src = file+this.fileRev(name);
  775. this.head.appendChild(script);
  776. },
  777. //
  778. // Create a LINK tag to load the style sheet
  779. //
  780. CSS: function (file,callback) {
  781. var name = this.fileName(file);
  782. var link = document.createElement("link");
  783. link.rel = "stylesheet"; link.type = "text/css";
  784. link.href = file+this.fileRev(name);
  785. this.loading[file] = {
  786. callback: callback,
  787. message: BASE.Message.File(name),
  788. status: this.STATUS.OK
  789. };
  790. this.head.appendChild(link);
  791. this.timer.create.call(this,[this.timer.file,file],link);
  792. }
  793. },
  794. //
  795. // Timing code for checking when style sheets are available.
  796. //
  797. timer: {
  798. //
  799. // Create the timing callback and start the timing loop.
  800. // We use a delay because some browsers need it to allow the styles
  801. // to be processed.
  802. //
  803. create: function (callback,node) {
  804. callback = BASE.Callback(callback);
  805. if (node.nodeName === "STYLE" && node.styleSheet &&
  806. typeof(node.styleSheet.cssText) !== 'undefined') {
  807. callback(this.STATUS.OK); // MSIE processes style immediately, but doesn't set its styleSheet!
  808. } else if (window.chrome && node.nodeName === "LINK") {
  809. callback(this.STATUS.OK); // Chrome doesn't give access to cssRules for stylesheet in
  810. // a link node, so we can't detect when it is loaded.
  811. } else if (isSafari2) {
  812. this.timer.start(this,[this.timer.checkSafari2,sheets++,callback],this.styleDelay);
  813. } else {
  814. this.timer.start(this,[this.timer.checkLength,node,callback],this.styleDelay);
  815. }
  816. return callback;
  817. },
  818. //
  819. // Start the timer for the given callback checker
  820. //
  821. start: function (AJAX,check,delay,timeout) {
  822. check = BASE.Callback(check);
  823. check.execute = this.execute; check.time = this.time;
  824. check.STATUS = AJAX.STATUS; check.timeout = timeout || AJAX.timeout;
  825. check.delay = check.total = delay || 0;
  826. if (delay) {setTimeout(check,delay)} else {check()}
  827. },
  828. //
  829. // Increment the time total, increase the delay
  830. // and test if we are past the timeout time.
  831. //
  832. time: function (callback) {
  833. this.total += this.delay;
  834. this.delay = Math.floor(this.delay * 1.05 + 5);
  835. if (this.total >= this.timeout) {callback(this.STATUS.ERROR); return 1}
  836. return 0;
  837. },
  838. //
  839. // For JS file loads, call the proper routine according to status
  840. //
  841. file: function (file,status) {
  842. if (status < 0) {BASE.Ajax.loadTimeout(file)} else {BASE.Ajax.loadComplete(file)}
  843. },
  844. //
  845. // Call the hook with the required data
  846. //
  847. execute: function () {this.hook.call(this.object,this,this.data[0],this.data[1])},
  848. //
  849. // Safari2 doesn't set the link's stylesheet, so we need to look in the
  850. // document.styleSheets array for the new sheet when it is created
  851. //
  852. checkSafari2: function (check,length,callback) {
  853. if (check.time(callback)) return;
  854. if (document.styleSheets.length > length &&
  855. document.styleSheets[length].cssRules &&
  856. document.styleSheets[length].cssRules.length)
  857. {callback(check.STATUS.OK)} else {setTimeout(check,check.delay)}
  858. },
  859. //
  860. // Look for the stylesheets rules and check when they are defined
  861. // and no longer of length zero. (This assumes there actually ARE
  862. // some rules in the stylesheet.)
  863. //
  864. checkLength: function (check,node,callback) {
  865. if (check.time(callback)) return;
  866. var isStyle = 0; var sheet = (node.sheet || node.styleSheet);
  867. try {if ((sheet.cssRules||sheet.rules||[]).length > 0) {isStyle = 1}} catch(err) {
  868. if (err.message.match(/protected variable|restricted URI/)) {isStyle = 1}
  869. else if (err.message.match(/Security error/)) {
  870. // Firefox3 gives "Security error" for missing files, so
  871. // can't distinguish that from OK files on remote servers.
  872. // or OK files in different directory from local files.
  873. isStyle = 1; // just say it is OK (can't really tell)
  874. }
  875. }
  876. if (isStyle) {
  877. // Opera 9.6 requires this setTimeout
  878. setTimeout(BASE.Callback([callback,check.STATUS.OK]),0);
  879. } else {
  880. setTimeout(check,check.delay);
  881. }
  882. }
  883. },
  884. //
  885. // JavaScript code must call this when they are completely initialized
  886. // (this allows them to perform asynchronous actions before indicating
  887. // that they are complete).
  888. //
  889. loadComplete: function (file) {
  890. file = this.fileURL(file);
  891. var loading = this.loading[file];
  892. if (loading && !loading.preloaded) {
  893. BASE.Message.Clear(loading.message);
  894. clearTimeout(loading.timeout);
  895. if (loading.script) {
  896. if (SCRIPTS.length === 0) {setTimeout(REMOVESCRIPTS,0)}
  897. SCRIPTS.push(loading.script);
  898. }
  899. this.loaded[file] = loading.status; delete this.loading[file];
  900. this.addHook(file,loading.callback);
  901. } else {
  902. if (loading) {delete this.loading[file]}
  903. this.loaded[file] = this.STATUS.OK;
  904. loading = {status: this.STATUS.OK}
  905. }
  906. if (!this.loadHooks[file]) {return null}
  907. return this.loadHooks[file].Execute(loading.status);
  908. },
  909. //
  910. // If a file fails to load within the timeout period (or the onerror handler
  911. // is called), this routine runs to signal the error condition.
  912. //
  913. loadTimeout: function (file) {
  914. if (this.loading[file].timeout) {clearTimeout(this.loading[file].timeout)}
  915. this.loading[file].status = this.STATUS.ERROR;
  916. this.loadError(file);
  917. this.loadComplete(file);
  918. },
  919. //
  920. // The default error hook for file load failures
  921. //
  922. loadError: function (file) {
  923. BASE.Message.Set(["LoadFailed","File failed to load: %1",file],null,2000);
  924. BASE.Hub.signal.Post(["file load error",file]);
  925. },
  926. //
  927. // Defines a style sheet from a hash of style declarations (key:value pairs
  928. // where the key is the style selector and the value is a hash of CSS attributes
  929. // and values).
  930. //
  931. Styles: function (styles,callback) {
  932. var styleString = this.StyleString(styles);
  933. if (styleString === "") {
  934. callback = BASE.Callback(callback);
  935. callback();
  936. } else {
  937. var style = document.createElement("style"); style.type = "text/css";
  938. this.head = HEAD(this.head);
  939. this.head.appendChild(style);
  940. if (style.styleSheet && typeof(style.styleSheet.cssText) !== 'undefined') {
  941. style.styleSheet.cssText = styleString;
  942. } else {
  943. style.appendChild(document.createTextNode(styleString));
  944. }
  945. callback = this.timer.create.call(this,callback,style);
  946. }
  947. return callback;
  948. },
  949. //
  950. // Create a stylesheet string from a style declaration object
  951. //
  952. StyleString: function (styles) {
  953. if (typeof(styles) === 'string') {return styles}
  954. var string = "", id, style;
  955. for (id in styles) {if (styles.hasOwnProperty(id)) {
  956. if (typeof styles[id] === 'string') {
  957. string += id + " {"+styles[id]+"}\n";
  958. } else if (BASE.Object.isArray(styles[id])) {
  959. for (var i = 0; i < styles[id].length; i++) {
  960. style = {}; style[id] = styles[id][i];
  961. string += this.StyleString(style);
  962. }
  963. } else if (id.substr(0,6) === '@media') {
  964. string += id + " {"+this.StyleString(styles[id])+"}\n";
  965. } else if (styles[id] != null) {
  966. style = [];
  967. for (var name in styles[id]) {if (styles[id].hasOwnProperty(name)) {
  968. if (styles[id][name] != null)
  969. {style[style.length] = name + ': ' + styles[id][name]}
  970. }}
  971. string += id +" {"+style.join('; ')+"}\n";
  972. }
  973. }}
  974. return string;
  975. }
  976. };
  977. })("MathJax");
  978. /**********************************************************/
  979. MathJax.HTML = {
  980. //
  981. // Create an HTML element with given attributes and content.
  982. // The def parameter is an (optional) object containing key:value pairs
  983. // of the attributes and their values, and contents is an (optional)
  984. // array of strings to be inserted as text, or arrays of the form
  985. // [type,def,contents] that describes an HTML element to be inserted
  986. // into the current element. Thus the contents can describe a complete
  987. // HTML snippet of arbitrary complexity. E.g.:
  988. //
  989. // MathJax.HTML.Element("span",{id:"mySpan",style{"font-style":"italic"}},[
  990. // "(See the ",["a",{href:"http://www.mathjax.org"},["MathJax home page"]],
  991. // " for more details.)"]);
  992. //
  993. Element: function (type,def,contents) {
  994. var obj = document.createElement(type), id;
  995. if (def) {
  996. if (def.hasOwnProperty("style")) {
  997. var style = def.style; def.style = {};
  998. for (id in style) {if (style.hasOwnProperty(id))
  999. {def.style[id.replace(/-([a-z])/g,this.ucMatch)] = style[id]}}
  1000. }
  1001. MathJax.Hub.Insert(obj,def);
  1002. for (id in def) {
  1003. if (id === "role" || id.substr(0,5) === "aria-") obj.setAttribute(id,def[id]);
  1004. }
  1005. }
  1006. if (contents) {
  1007. if (!MathJax.Object.isArray(contents)) {contents = [contents]}
  1008. for (var i = 0, m = contents.length; i < m; i++) {
  1009. if (MathJax.Object.isArray(contents[i])) {
  1010. obj.appendChild(this.Element(contents[i][0],contents[i][1],contents[i][2]));
  1011. } else if (type === "script") { // IE throws an error if script is added as a text node
  1012. this.setScript(obj, contents[i]);
  1013. } else {
  1014. obj.appendChild(document.createTextNode(contents[i]));
  1015. }
  1016. }
  1017. }
  1018. return obj;
  1019. },
  1020. ucMatch: function (match,c) {return c.toUpperCase()},
  1021. addElement: function (span,type,def,contents) {return span.appendChild(this.Element(type,def,contents))},
  1022. TextNode: function (text) {return document.createTextNode(text)},
  1023. addText: function (span,text) {return span.appendChild(this.TextNode(text))},
  1024. //
  1025. // Set and get the text of a script
  1026. //
  1027. setScript: function (script,text) {
  1028. if (this.setScriptBug) {script.text = text} else {
  1029. while (script.firstChild) {script.removeChild(script.firstChild)}
  1030. this.addText(script,text);
  1031. }
  1032. },
  1033. getScript: function (script) {
  1034. var text = (script.text === "" ? script.innerHTML : script.text);
  1035. return text.replace(/^\s+/,"").replace(/\s+$/,"");
  1036. },
  1037. //
  1038. // Manage cookies
  1039. //
  1040. Cookie: {
  1041. prefix: "mjx",
  1042. expires: 365,
  1043. //
  1044. // Save an object as a named cookie
  1045. //
  1046. Set: function (name,def) {
  1047. var keys = [];
  1048. if (def) {
  1049. for (var id in def) {if (def.hasOwnProperty(id)) {
  1050. keys.push(id+":"+def[id].toString().replace(/&/g,"&&"));
  1051. }}
  1052. }
  1053. var cookie = this.prefix+"."+name+"="+escape(keys.join('&;'));
  1054. if (this.expires) {
  1055. var time = new Date(); time.setDate(time.getDate() + this.expires);
  1056. cookie += '; expires='+time.toGMTString();
  1057. }
  1058. try {document.cookie = cookie+"; path=/"} catch (err) {} // ignore errors saving cookies
  1059. },
  1060. //
  1061. // Get the contents of a named cookie and incorporate
  1062. // it into the given object (or return a fresh one)
  1063. //
  1064. Get: function (name,obj) {
  1065. if (!obj) {obj = {}}
  1066. var pattern = new RegExp("(?:^|;\\s*)"+this.prefix+"\\."+name+"=([^;]*)(?:;|$)");
  1067. var match;
  1068. try {match = pattern.exec(document.cookie)} catch (err) {}; // ignore errors reading cookies
  1069. if (match && match[1] !== "") {
  1070. var keys = unescape(match[1]).split('&;');
  1071. for (var i = 0, m = keys.length; i < m; i++) {
  1072. match = keys[i].match(/([^:]+):(.*)/);
  1073. var value = match[2].replace(/&&/g,'&');
  1074. if (value === "true") {value = true} else if (value === "false") {value = false}
  1075. else if (value.match(/^-?(\d+(\.\d+)?|\.\d+)$/)) {value = parseFloat(value)}
  1076. obj[match[1]] = value;
  1077. }
  1078. }
  1079. return obj;
  1080. }
  1081. }
  1082. };
  1083. /**********************************************************/
  1084. MathJax.Localization = {
  1085. locale: "en",
  1086. directory: "[MathJax]/localization",
  1087. strings: {
  1088. // Currently, this list is not modified by the MathJax-i18n script. You can
  1089. // run the following command in MathJax/unpacked/localization to update it:
  1090. //
  1091. // 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*
  1092. //
  1093. // This only takes languages with localization data so you must also add
  1094. // the languages that use a remap but are not translated at all.
  1095. //
  1096. "ar": {menuTitle: "\u0627\u0644\u0639\u0631\u0628\u064A\u0629"},
  1097. "ast": {menuTitle: "asturianu"},
  1098. "bg": {menuTitle: "\u0431\u044A\u043B\u0433\u0430\u0440\u0441\u043A\u0438"},
  1099. "bcc": {menuTitle: "\u0628\u0644\u0648\u0686\u06CC"},
  1100. "br": {menuTitle: "brezhoneg"},
  1101. "ca": {menuTitle: "catal\u00E0"},
  1102. "cdo": {menuTitle: "M\u00ECng-d\u0115\u0324ng-ng\u1E73\u0304"},
  1103. "cs": {menuTitle: "\u010De\u0161tina"},
  1104. "da": {menuTitle: "dansk"},
  1105. "de": {menuTitle: "Deutsch"},
  1106. "diq": {menuTitle: "Zazaki"},
  1107. "en": {menuTitle: "English", isLoaded: true},
  1108. "eo": {menuTitle: "Esperanto"},
  1109. "es": {menuTitle: "espa\u00F1ol"},
  1110. "fa": {menuTitle: "\u0641\u0627\u0631\u0633\u06CC"},
  1111. "fi": {menuTitle: "suomi"},
  1112. "fr": {menuTitle: "fran\u00E7ais"},
  1113. "gl": {menuTitle: "galego"},
  1114. "he": {menuTitle: "\u05E2\u05D1\u05E8\u05D9\u05EA"},
  1115. "ia": {menuTitle: "interlingua"},
  1116. "it": {menuTitle: "italiano"},
  1117. "ja": {menuTitle: "\u65E5\u672C\u8A9E"},
  1118. "kn": {menuTitle: "\u0C95\u0CA8\u0CCD\u0CA8\u0CA1"},
  1119. "ko": {menuTitle: "\uD55C\uAD6D\uC5B4"},
  1120. "lb": {menuTitle: "L\u00EBtzebuergesch"},
  1121. "lki": {menuTitle: "\u0644\u06D5\u06A9\u06CC"},
  1122. "lt": {menuTitle: "lietuvi\u0173"},
  1123. "mk": {menuTitle: "\u043C\u0430\u043A\u0435\u0434\u043E\u043D\u0441\u043A\u0438"},
  1124. "nl": {menuTitle: "Nederlands"},
  1125. "oc": {menuTitle: "occitan"},
  1126. "pl": {menuTitle: "polski"},
  1127. "pt": {menuTitle: "portugu\u00EAs"},
  1128. "pt-br": {menuTitle: "portugu\u00EAs do Brasil"},
  1129. "ru": {menuTitle: "\u0440\u0443\u0441\u0441\u043A\u0438\u0439"},
  1130. "sco": {menuTitle: "Scots"},
  1131. "scn": {menuTitle: "sicilianu"},
  1132. "sk": {menuTitle: "sloven\u010Dina"},
  1133. "sl": {menuTitle: "sloven\u0161\u010Dina"},
  1134. "sv": {menuTitle: "svenska"},
  1135. "th": {menuTitle: "\u0E44\u0E17\u0E22"},
  1136. "tr": {menuTitle: "T\u00FCrk\u00E7e"},
  1137. "uk": {menuTitle: "\u0443\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u0430"},
  1138. "vi": {menuTitle: "Ti\u1EBFng Vi\u1EC7t"},
  1139. "zh-hans": {menuTitle: "\u4E2D\u6587\uFF08\u7B80\u4F53\uFF09"},
  1140. "zh-hant": {menuTitle: "\u6C49\u8BED"}
  1141. },
  1142. //
  1143. // The pattern for substitution escapes:
  1144. // %n or %{n} or %{plural:%n|option1|option1|...} or %c
  1145. //
  1146. pattern: /%(\d+|\{\d+\}|\{[a-z]+:\%\d+(?:\|(?:%\{\d+\}|%.|[^\}])*)+\}|.)/g,
  1147. SPLIT: ("axb".split(/(x)/).length === 3 ?
  1148. function (string,regex) {return string.split(regex)} :
  1149. //
  1150. // IE8 and below don't do split() correctly when the pattern includes
  1151. // parentheses (the split should include the matched exrepssions).
  1152. // So implement it by hand here.
  1153. //
  1154. function (string,regex) {
  1155. var result = [], match, last = 0;
  1156. regex.lastIndex = 0;
  1157. while ((match = regex.exec(string))) {
  1158. result.push(string.substr(last,match.index-last));
  1159. result.push.apply(result,match.slice(1));
  1160. last = match.index + match[0].length;
  1161. }
  1162. result.push(string.substr(last));
  1163. return result;
  1164. }),
  1165. _: function (id,phrase) {
  1166. if (MathJax.Object.isArray(phrase)) {return this.processSnippet(id,phrase)}
  1167. return this.processString(this.lookupPhrase(id,phrase),[].slice.call(arguments,2));
  1168. },
  1169. processString: function (string,args,domain) {
  1170. //
  1171. // Process arguments for substitution
  1172. // If the argument is a snippet (and we are processing snippets) do so,
  1173. // Otherwise, if it is a number, convert it for the lacale
  1174. //
  1175. var i, m, isArray = MathJax.Object.isArray;
  1176. for (i = 0, m = args.length; i < m; i++) {
  1177. if (domain && isArray(args[i])) {args[i] = this.processSnippet(domain,args[i])}
  1178. }
  1179. //
  1180. // Split string at escapes and process them individually
  1181. //
  1182. var parts = this.SPLIT(string,this.pattern);
  1183. for (i = 1, m = parts.length; i < m; i += 2) {
  1184. var c = parts[i].charAt(0); // first char will be { or \d or a char to be kept literally
  1185. if (c >= "0" && c <= "9") { // %n
  1186. parts[i] = args[parts[i]-1];
  1187. if (typeof parts[i] === "number") parts[i] = this.number(parts[i]);
  1188. } else if (c === "{") { // %{n} or %{plural:%n|...}
  1189. c = parts[i].substr(1);
  1190. if (c >= "0" && c <= "9") { // %{n}
  1191. parts[i] = args[parts[i].substr(1,parts[i].length-2)-1];
  1192. if (typeof parts[i] === "number") parts[i] = this.number(parts[i]);
  1193. } else { // %{plural:%n|...}
  1194. var match = parts[i].match(/^\{([a-z]+):%(\d+)\|(.*)\}$/);
  1195. if (match) {
  1196. if (match[1] === "plural") {
  1197. var n = args[match[2]-1];
  1198. if (typeof n === "undefined") {
  1199. parts[i] = "???"; // argument doesn't exist
  1200. } else {
  1201. n = this.plural(n) - 1; // index of the form to use
  1202. var plurals = match[3].replace(/(^|[^%])(%%)*%\|/g,"$1$2%\uEFEF").split(/\|/); // the parts (replacing %| with a special character)
  1203. if (n >= 0 && n < plurals.length) {
  1204. parts[i] = this.processString(plurals[n].replace(/\uEFEF/g,"|"),args,domain);
  1205. } else {
  1206. parts[i] = "???"; // no string for this index
  1207. }
  1208. }
  1209. } else {parts[i] = "%"+parts[i]} // not "plural", put back the % and leave unchanged
  1210. }
  1211. }
  1212. }
  1213. if (parts[i] == null) {parts[i] = "???"}
  1214. }
  1215. //
  1216. // If we are not forming a snippet, return the completed string
  1217. //
  1218. if (!domain) {return parts.join("")}
  1219. //
  1220. // We need to return an HTML snippet, so buld it from the
  1221. // broken up string with inserted parts (that could be snippets)
  1222. //
  1223. var snippet = [], part = "";
  1224. for (i = 0; i < m; i++) {
  1225. part += parts[i]; i++; // add the string and move on to substitution result
  1226. if (i < m) {
  1227. if (isArray(parts[i])) { // substitution was a snippet
  1228. snippet.push(part); // add the accumulated string
  1229. snippet = snippet.concat(parts[i]); // concatenate the substution snippet
  1230. part = ""; // start accumulating a new string
  1231. } else { // substitution was a string
  1232. part += parts[i]; // add to accumulating string
  1233. }
  1234. }
  1235. }
  1236. if (part !== "") {snippet.push(part)} // add final string
  1237. return snippet;
  1238. },
  1239. processSnippet: function (domain,snippet) {
  1240. var result = []; // the new snippet
  1241. //
  1242. // Look through the original snippet for
  1243. // strings or snippets to translate
  1244. //
  1245. for (var i = 0, m = snippet.length; i < m; i++) {
  1246. if (MathJax.Object.isArray(snippet[i])) {
  1247. //
  1248. // This could be a sub-snippet:
  1249. // ["tag"] or ["tag",{properties}] or ["tag",{properties},snippet]
  1250. // Or it could be something to translate:
  1251. // [id,string,args] or [domain,snippet]
  1252. var data = snippet[i];
  1253. if (typeof data[1] === "string") { // [id,string,args]
  1254. var id = data[0]; if (!MathJax.Object.isArray(id)) {id = [domain,id]}
  1255. var phrase = this.lookupPhrase(id,data[1]);
  1256. result = result.concat(this.processMarkdown(phrase,data.slice(2),domain));
  1257. } else if (MathJax.Object.isArray(data[1])) { // [domain,snippet]
  1258. result = result.concat(this.processSnippet.apply(this,data));
  1259. } else if (data.length >= 3) { // ["tag",{properties},snippet]
  1260. result.push([data[0],data[1],this.processSnippet(domain,data[2])]);
  1261. } else { // ["tag"] or ["tag",{properties}]
  1262. result.push(snippet[i]);
  1263. }
  1264. } else { // a string
  1265. result.push(snippet[i]);
  1266. }
  1267. }
  1268. return result;
  1269. },
  1270. markdownPattern: /(%.)|(\*{1,3})((?:%.|.)+?)\2|(`+)((?:%.|.)+?)\4|\[((?:%.|.)+?)\]\(([^\s\)]+)\)/,
  1271. // %c or *bold*, **italics**, ***bold-italics***, or `code`, or [link](url)
  1272. processMarkdown: function (phrase,args,domain) {
  1273. var result = [], data;
  1274. //
  1275. // Split the string by the Markdown pattern
  1276. // (the text blocks are separated by
  1277. // c,stars,star-text,backtics,code-text,link-text,URL).
  1278. // Start with the first text string from the split.
  1279. //
  1280. var parts = phrase.split(this.markdownPattern);
  1281. var string = parts[0];
  1282. //
  1283. // Loop through the matches and process them
  1284. //
  1285. for (var i = 1, m = parts.length; i < m; i += 8) {
  1286. if (parts[i+1]) { // stars (for bold/italic)
  1287. //
  1288. // Select the tag to use by number of stars (three stars requires two tags)
  1289. //
  1290. data = this.processString(parts[i+2],args,domain);
  1291. if (!MathJax.Object.isArray(data)) {data = [data]}
  1292. data = [["b","i","i"][parts[i+1].length-1],{},data]; // number of stars determines type
  1293. if (parts[i+1].length === 3) {data = ["b",{},data]} // bold-italic
  1294. } else if (parts[i+3]) { // backtics (for code)
  1295. //
  1296. // Remove one leading or trailing space, and process substitutions
  1297. // Make a <code> tag
  1298. //
  1299. data = this.processString(parts[i+4].replace(/^\s/,"").replace(/\s$/,""),args,domain);
  1300. if (!MathJax.Object.isArray(data)) {data = [data]}
  1301. data = ["code",{},data];
  1302. } else if (parts[i+5]) { // hyperlink
  1303. //
  1304. // Process the link text, and make an <a> tag with the URL
  1305. //
  1306. data = this.processString(parts[i+5],args,domain);
  1307. if (!MathJax.Object.isArray(data)) {data = [data]}
  1308. data = ["a",{href:this.processString(parts[i+6],args),target:"_blank"},data];
  1309. } else {
  1310. //
  1311. // Escaped character (%c) gets added into the string.
  1312. //
  1313. string += parts[i]; data = null;
  1314. }
  1315. //
  1316. // If there is a tag to insert,
  1317. // Add any pending string, then push the tag
  1318. //
  1319. if (data) {
  1320. result = this.concatString(result,string,args,domain);
  1321. result.push(data); string = "";
  1322. }
  1323. //
  1324. // Process the string that follows matches pattern
  1325. //
  1326. if (parts[i+7] !== "") {string += parts[i+7]}
  1327. };
  1328. //
  1329. // Add any pending string and return the resulting snippet
  1330. //
  1331. result = this.concatString(result,string,args,domain);
  1332. return result;
  1333. },
  1334. concatString: function (result,string,args,domain) {
  1335. if (string != "") {
  1336. //
  1337. // Process the substutions.
  1338. // If the result is not a snippet, turn it into one.
  1339. // Then concatenate the snippet to the current one
  1340. //
  1341. string = this.processString(string,args,domain);
  1342. if (!MathJax.Object.isArray(string)) {string = [string]}
  1343. result = result.concat(string);
  1344. }
  1345. return result;
  1346. },
  1347. lookupPhrase: function (id,phrase,domain) {
  1348. //
  1349. // Get the domain and messageID
  1350. //
  1351. if (!domain) {domain = "_"}
  1352. if (MathJax.Object.isArray(id)) {domain = (id[0] || "_"); id = (id[1] || "")}
  1353. //
  1354. // Check if the data is available and if not,
  1355. // load it and throw a restart error so the calling
  1356. // code can wait for the load and try again.
  1357. //
  1358. var load = this.loadDomain(domain);
  1359. if (load) {MathJax.Hub.RestartAfter(load)}
  1360. //
  1361. // Look up the message in the localization data
  1362. // (if not found, the original English is used)
  1363. //
  1364. var localeData = this.strings[this.locale];
  1365. if (localeData) {
  1366. if (localeData.domains && domain in localeData.domains) {
  1367. var domainData = localeData.domains[domain];
  1368. if (domainData.strings && id in domainData.strings)
  1369. {phrase = domainData.strings[id]}
  1370. }
  1371. }
  1372. //
  1373. // return the translated phrase
  1374. //
  1375. return phrase;
  1376. },
  1377. //
  1378. // Load a langauge data file from the proper
  1379. // directory and file.
  1380. //
  1381. loadFile: function (file,data,callback) {
  1382. callback = MathJax.Callback(callback);
  1383. file = (data.file || file); // the data's file name or the default name
  1384. if (!file.match(/\.js$/)) {file += ".js"} // add .js if needed
  1385. //
  1386. // Add the directory if the file doesn't
  1387. // contain a full URL already.
  1388. //
  1389. if (!file.match(/^([a-z]+:|\[MathJax\])/)) {
  1390. var dir = (this.strings[this.locale].directory ||
  1391. this.directory + "/" + this.locale ||
  1392. "[MathJax]/localization/" + this.locale);
  1393. file = dir + "/" + file;
  1394. }
  1395. //
  1396. // Load the file and mark the data as loaded (even if it
  1397. // failed to load, so we don't continue to try to load it
  1398. // over and over).
  1399. //
  1400. var load = MathJax.Ajax.Require(file,function () {data.isLoaded = true; return callback()});
  1401. //
  1402. // Return the callback if needed, otherwise null.
  1403. //
  1404. return (load.called ? null : load);
  1405. },
  1406. //
  1407. // Check to see if the localization data are loaded
  1408. // for the given domain; if not, load the data file,
  1409. // and return a callback for the loading operation.
  1410. // Otherwise return null (data are loaded).
  1411. //
  1412. loadDomain: function (domain,callback) {
  1413. var load, localeData = this.strings[this.locale];
  1414. if (localeData) {
  1415. if (!localeData.isLoaded) {
  1416. load = this.loadFile(this.locale,localeData);
  1417. if (load) {
  1418. return MathJax.Callback.Queue(
  1419. load,["loadDomain",this,domain] // call again to load domain
  1420. ).Push(callback||{});
  1421. }
  1422. }
  1423. if (localeData.domains && domain in localeData.domains) {
  1424. var domainData = localeData.domains[domain];
  1425. if (!domainData.isLoaded) {
  1426. load = this.loadFile(domain,domainData);
  1427. if (load) {return MathJax.Callback.Queue(load).Push(callback)}
  1428. }
  1429. }
  1430. }
  1431. // localization data are loaded, so just do the callback
  1432. return MathJax.Callback(callback)();
  1433. },
  1434. //
  1435. // Perform a function, properly handling
  1436. // restarts due to localization file loads.
  1437. //
  1438. // Note that this may return before the function
  1439. // has been called successfully, so you should
  1440. // consider fn as running asynchronously. (Callbacks
  1441. // can be used to synchronize it with other actions.)
  1442. //
  1443. Try: function (fn) {
  1444. fn = MathJax.Callback(fn); fn.autoReset = true;
  1445. try {fn()} catch (err) {
  1446. if (!err.restart) {throw err}
  1447. MathJax.Callback.After(["Try",this,fn],err.restart);
  1448. }
  1449. },
  1450. //
  1451. // Reset the current language
  1452. //
  1453. resetLocale: function(locale) {
  1454. // Selection algorithm:
  1455. // 1) Downcase locale name (e.g. "en-US" => "en-us")
  1456. // 2) Try a parent language (e.g. "en-us" => "en")
  1457. // 3) Try the fallback specified in the data (e.g. "pt" => "pt-br")
  1458. // 4) Otherwise don't change the locale.
  1459. if (!locale) return;
  1460. locale = locale.toLowerCase();
  1461. while (!this.strings[locale]) {
  1462. var dashPos = locale.lastIndexOf("-");
  1463. if (dashPos === -1) return;
  1464. locale = locale.substring(0, dashPos);
  1465. }
  1466. var remap = this.strings[locale].remap;
  1467. this.locale = remap ? remap : locale;
  1468. MathJax.Callback.Signal("Hub").Post(["Locale Reset", this.locale]);
  1469. },
  1470. //
  1471. // Set the current language
  1472. //
  1473. setLocale: function(locale) {
  1474. this.resetLocale(locale);
  1475. if (MathJax.Menu) {this.loadDomain("MathMenu")}
  1476. },
  1477. //
  1478. // Add or update a language or domain
  1479. //
  1480. addTranslation: function (locale,domain,definition) {
  1481. var data = this.strings[locale], isNew = false;
  1482. if (!data) {data = this.strings[locale] = {}; isNew = true}
  1483. if (!data.domains) {data.domains = {}}
  1484. if (domain) {
  1485. if (!data.domains[domain]) {data.domains[domain] = {}}
  1486. data = data.domains[domain];
  1487. }
  1488. MathJax.Hub.Insert(data,definition);
  1489. if (isNew && MathJax.Menu.menu) {MathJax.Menu.CreateLocaleMenu()}
  1490. },
  1491. //
  1492. // Set CSS for an element based on font requirements
  1493. //
  1494. setCSS: function (div) {
  1495. var locale = this.strings[this.locale];
  1496. if (locale) {
  1497. if (locale.fontFamily) {div.style.fontFamily = locale.fontFamily}
  1498. if (locale.fontDirection) {
  1499. div.style.direction = locale.fontDirection;
  1500. if (locale.fontDirection === "rtl") {div.style.textAlign = "right"}
  1501. }
  1502. }
  1503. return div;
  1504. },
  1505. //
  1506. // Get the language's font family or direction
  1507. //
  1508. fontFamily: function () {
  1509. var locale = this.strings[this.locale];
  1510. return (locale ? locale.fontFamily : null);
  1511. },
  1512. fontDirection: function () {
  1513. var locale = this.strings[this.locale];
  1514. return (locale ? locale.fontDirection : null);
  1515. },
  1516. //
  1517. // Get the language's plural index for a number
  1518. //
  1519. plural: function (n) {
  1520. var locale = this.strings[this.locale];
  1521. if (locale && locale.plural) {return locale.plural(n)}
  1522. // default
  1523. if (n == 1) {return 1} // one
  1524. return 2; // other
  1525. },
  1526. //
  1527. // Convert a number to language-specific form
  1528. //
  1529. number: function(n) {
  1530. var locale = this.strings[this.locale];
  1531. if (locale && locale.number) {return locale.number(n)}
  1532. // default
  1533. return n;
  1534. }
  1535. };
  1536. /**********************************************************/
  1537. MathJax.Message = {
  1538. ready: false, // used to tell when the styles are available
  1539. log: [{}], current: null,
  1540. textNodeBug: (navigator.vendor === "Apple Computer, Inc." &&
  1541. typeof navigator.vendorSub === "undefined") ||
  1542. (window.hasOwnProperty && window.hasOwnProperty("konqueror")), // Konqueror displays some gibberish with text.nodeValue = "..."
  1543. styles: {
  1544. "#MathJax_Message": {
  1545. position: "fixed", left: "1px", bottom: "2px",
  1546. 'background-color': "#E6E6E6", border: "1px solid #959595",
  1547. margin: "0px", padding: "2px 8px",
  1548. 'z-index': "102", color: "black", 'font-size': "80%",
  1549. width: "auto", 'white-space': "nowrap"
  1550. },
  1551. "#MathJax_MSIE_Frame": {
  1552. position: "absolute",
  1553. top:0, left: 0, width: "0px", 'z-index': 101,
  1554. border: "0px", margin: "0px", padding: "0px"
  1555. }
  1556. },
  1557. browsers: {
  1558. MSIE: function (browser) {
  1559. MathJax.Message.msieFixedPositionBug = ((document.documentMode||0) < 7);
  1560. if (MathJax.Message.msieFixedPositionBug)
  1561. {MathJax.Hub.config.styles["#MathJax_Message"].position = "absolute"}
  1562. MathJax.Message.quirks = (document.compatMode === "BackCompat");
  1563. },
  1564. Chrome: function (browser) {
  1565. MathJax.Hub.config.styles["#MathJax_Message"].bottom = "1.5em";
  1566. MathJax.Hub.config.styles["#MathJax_Message"].left = "1em";
  1567. }
  1568. },
  1569. Init: function (styles) {
  1570. if (styles) {this.ready = true}
  1571. if (!document.body || !this.ready) {return false}
  1572. //
  1573. // ASCIIMathML replaces the entire page with a copy of itself (@#!#%@!!)
  1574. // so check that this.div is still part of the page, otherwise look up
  1575. // the copy and use that.
  1576. //
  1577. if (this.div && this.div.parentNode == null) {
  1578. this.div = document.getElementById("MathJax_Message");
  1579. this.text = (this.div ? this.div.firstChild : null);
  1580. }
  1581. if (!this.div) {
  1582. var frame = document.body;
  1583. if (this.msieFixedPositionBug && window.attachEvent) {
  1584. frame = this.frame = this.addDiv(document.body); frame.removeAttribute("id");
  1585. frame.style.position = "absolute";
  1586. frame.style.border = frame.style.margin = frame.style.padding = "0px";
  1587. frame.style.zIndex = "101"; frame.style.height = "0px";
  1588. frame = this.addDiv(frame);
  1589. frame.id = "MathJax_MSIE_Frame";
  1590. window.attachEvent("onscroll",this.MoveFrame);
  1591. window.attachEvent("onresize",this.MoveFrame);
  1592. this.MoveFrame();
  1593. }
  1594. this.div = this.addDiv(frame); this.div.style.display = "none";
  1595. }
  1596. if (!this.text) {
  1597. this.text = this.div.appendChild(document.createTextNode(""));
  1598. }
  1599. return true;
  1600. },
  1601. addDiv: function (parent) {
  1602. var div = document.createElement("div");
  1603. div.id = "MathJax_Message";
  1604. if (parent.firstChild) {parent.insertBefore(div,parent.firstChild)}
  1605. else {parent.appendChild(div)}
  1606. return div;
  1607. },
  1608. MoveFrame: function () {
  1609. var body = (MathJax.Message.quirks ? document.body : document.documentElement);
  1610. var frame = MathJax.Message.frame;
  1611. frame.style.left = body.scrollLeft + 'px';
  1612. frame.style.top = body.scrollTop + 'px';
  1613. frame.style.width = body.clientWidth + 'px';
  1614. frame = frame.firstChild;
  1615. frame.style.height = body.clientHeight + 'px';
  1616. },
  1617. localize: function (message) {
  1618. return MathJax.Localization._(message,message);
  1619. },
  1620. filterText: function (text,n,id) {
  1621. if (MathJax.Hub.config.messageStyle === "simple") {
  1622. if (id === "LoadFile") {
  1623. if (!this.loading) {this.loading = this.localize("Loading") + " "}
  1624. text = this.loading; this.loading += ".";
  1625. } else if (id === "ProcessMath") {
  1626. if (!this.processing) {this.processing = this.localize("Processing") + " "}
  1627. text = this.processing; this.processing += ".";
  1628. } else if (id === "TypesetMath") {
  1629. if (!this.typesetting) {this.typesetting = this.localize("Typesetting") + " "}
  1630. text = this.typesetting; this.typesetting += ".";
  1631. }
  1632. }
  1633. return text;
  1634. },
  1635. clearCounts: function () {
  1636. delete this.loading;
  1637. delete this.processing;
  1638. delete this.typesetting;
  1639. },
  1640. Set: function (text,n,clearDelay) {
  1641. if (n == null) {n = this.log.length; this.log[n] = {}}
  1642. //
  1643. // Translate message if it is [id,message,arguments]
  1644. //
  1645. var id = "";
  1646. if (MathJax.Object.isArray(text)) {
  1647. id = text[0]; if (MathJax.Object.isArray(id)) {id = id[1]}
  1648. //
  1649. // Localization._() will throw a restart error if a localization file
  1650. // needs to be loaded, so trap that and redo the Set() call
  1651. // after it is loaded.
  1652. //
  1653. try {
  1654. text = MathJax.Localization._.apply(MathJax.Localization,text);
  1655. } catch (err) {
  1656. if (!err.restart) {throw err}
  1657. if (!err.restart.called) {
  1658. //
  1659. // Mark it so we can tell if the Clear() comes before the message is displayed
  1660. //
  1661. if (this.log[n].restarted == null) {this.log[n].restarted = 0}
  1662. this.log[n].restarted++; delete this.log[n].cleared;
  1663. MathJax.Callback.After(["Set",this,text,n,clearDelay],err.restart);
  1664. return n;
  1665. }
  1666. }
  1667. }
  1668. //
  1669. // Clear the timout timer.
  1670. //
  1671. if (this.timer) {clearTimeout(this.timer); delete this.timer}
  1672. //
  1673. // Save the message and filtered message.
  1674. //
  1675. this.log[n].text = text; this.log[n].filteredText = text = this.filterText(text,n,id);
  1676. //
  1677. // Hook the message into the message list so we can tell
  1678. // what message to put up when this one is removed.
  1679. //
  1680. if (typeof(this.log[n].next) === "undefined") {
  1681. this.log[n].next = this.current;
  1682. if (this.current != null) {this.log[this.current].prev = n}
  1683. this.current = n;
  1684. }
  1685. //
  1686. // Show the message if it is the currently active one.
  1687. //
  1688. if (this.current === n && MathJax.Hub.config.messageStyle !== "none") {
  1689. if (this.Init()) {
  1690. if (this.textNodeBug) {this.div.innerHTML = text} else {this.text.nodeValue = text}
  1691. this.div.style.display = "";
  1692. if (this.status) {window.status = ""; delete this.status}
  1693. } else {
  1694. window.status = text;
  1695. this.status = true;
  1696. }
  1697. }
  1698. //
  1699. // Check if the message was resetarted to load a localization file
  1700. // and if it has been cleared in the meanwhile.
  1701. //
  1702. if (this.log[n].restarted) {
  1703. if (this.log[n].cleared) {clearDelay = 0}
  1704. if (--this.log[n].restarted === 0) {delete this.log[n].cleared}
  1705. }
  1706. //
  1707. // Check if we need to clear the message automatically.
  1708. //
  1709. if (clearDelay) {setTimeout(MathJax.Callback(["Clear",this,n]),clearDelay)}
  1710. else if (clearDelay == 0) {this.Clear(n,0)}
  1711. //
  1712. // Return the message number.
  1713. //
  1714. return n;
  1715. },
  1716. Clear: function (n,delay) {
  1717. //
  1718. // Detatch the message from the active list.
  1719. //
  1720. if (this.log[n].prev != null) {this.log[this.log[n].prev].next = this.log[n].next}
  1721. if (this.log[n].next != null) {this.log[this.log[n].next].prev = this.log[n].prev}
  1722. //
  1723. // If it is the current message, get the next one to show.
  1724. //
  1725. if (this.current === n) {
  1726. this.current = this.log[n].next;
  1727. if (this.text) {
  1728. if (this.div.parentNode == null) {this.Init()} // see ASCIIMathML comments above
  1729. if (this.current == null) {
  1730. //
  1731. // If there are no more messages, remove the message box.
  1732. //
  1733. if (this.timer) {clearTimeout(this.timer); delete this.timer}
  1734. if (delay == null) {delay = 600}
  1735. if (delay === 0) {this.Remove()}
  1736. else {this.timer = setTimeout(MathJax.Callback(["Remove",this]),delay)}
  1737. } else if (MathJax.Hub.config.messageStyle !== "none") {
  1738. //
  1739. // If there is an old message, put it in place
  1740. //
  1741. if (this.textNodeBug) {this.div.innerHTML = this.log[this.current].filteredText}
  1742. else {this.text.nodeValue = this.log[this.current].filteredText}
  1743. }
  1744. if (this.status) {window.status = ""; delete this.status}
  1745. } else if (this.status) {
  1746. window.status = (this.current == null ? "" : this.log[this.current].text);
  1747. }
  1748. }
  1749. //
  1750. // Clean up the log data no longer needed
  1751. //
  1752. delete this.log[n].next; delete this.log[n].prev;
  1753. delete this.log[n].filteredText;
  1754. //
  1755. // If this is a restarted localization message, mark that it has been cleared
  1756. // while waiting for the file to load.
  1757. //
  1758. if (this.log[n].restarted) {this.log[n].cleared = true}
  1759. },
  1760. Remove: function () {
  1761. // FIXME: do a fade out or something else interesting?
  1762. this.text.nodeValue = "";
  1763. this.div.style.display = "none";
  1764. },
  1765. File: function (file) {
  1766. return this.Set(["LoadFile","Loading %1",file],null,null);
  1767. },
  1768. Log: function () {
  1769. var strings = [];
  1770. for (var i = 1, m = this.log.length; i < m; i++) {strings[i] = this.log[i].text}
  1771. return strings.join("\n");
  1772. }
  1773. };
  1774. /**********************************************************/
  1775. MathJax.Hub = {
  1776. config: {
  1777. root: "",
  1778. config: [], // list of configuration files to load
  1779. styleSheets: [], // list of CSS files to load
  1780. styles: { // styles to generate in-line
  1781. ".MathJax_Preview": {color: "#888"}
  1782. },
  1783. jax: [], // list of input and output jax to load
  1784. extensions: [], // list of extensions to load
  1785. preJax: null, // pattern to remove from before math script tag
  1786. postJax: null, // pattern to remove from after math script tag
  1787. displayAlign: 'center', // how to align displayed equations (left, center, right)
  1788. displayIndent: '0', // indentation for displayed equations (when not centered)
  1789. preRemoveClass: 'MathJax_Preview', // class of objects to remove preceding math script
  1790. showProcessingMessages: true, // display "Processing math: nn%" messages or not
  1791. messageStyle: "normal", // set to "none" or "simple" (for "Loading..." and "Processing...")
  1792. delayStartupUntil: "none", // set to "onload" to delay setup until the onload handler runs
  1793. // set to "configured" to delay startup until MathJax.Hub.Configured() is called
  1794. // set to a Callback to wait for before continuing with the startup
  1795. skipStartupTypeset: false, // set to true to skip PreProcess and Process during startup
  1796. elements: [], // array of elements to process when none is given explicitly
  1797. positionToHash: true, // after initial typeset pass, position to #hash location?
  1798. showMathMenu: true, // attach math context menu to typeset math?
  1799. showMathMenuMSIE: true, // separtely determine if MSIE should have math menu
  1800. // (since the code for that is a bit delicate)
  1801. menuSettings: {
  1802. zoom: "None", // when to do MathZoom
  1803. CTRL: false, // require CTRL for MathZoom?
  1804. ALT: false, // require Alt or Option?
  1805. CMD: false, // require CMD?
  1806. Shift: false, // require Shift?
  1807. discoverable: false, // make math menu discoverable on hover?
  1808. zscale: "200%", // the scaling factor for MathZoom
  1809. renderer: null, // set when Jax are loaded
  1810. font: "Auto", // what font HTML-CSS should use
  1811. context: "MathJax", // or "Browser" for pass-through to browser menu
  1812. locale: null, // the language to use for messages
  1813. mpContext: false, // true means pass menu events to MathPlayer in IE
  1814. mpMouse: false, // true means pass mouse events to MathPlayer in IE
  1815. texHints: true, // include class names for TeXAtom elements
  1816. FastPreview: null, // use PreviewHTML output as preview?
  1817. assistiveMML: null, // include hidden MathML for screen readers?
  1818. inTabOrder: true, // set to false if math elements should be included in the tabindex
  1819. semantics: false // add semantics tag with original form in MathML output
  1820. },
  1821. errorSettings: {
  1822. // localized HTML snippet structure for message to use
  1823. message: ["[",["MathProcessingError","Math Processing Error"],"]"],
  1824. style: {color: "#CC0000", "font-style":"italic"} // style for message
  1825. },
  1826. ignoreMMLattributes: {} // attributes not to copy to HTML-CSS or SVG output
  1827. // from MathML input (in addition to the ones in MML.nocopyAttributes).
  1828. // An id set to true will be ignored, one set to false will
  1829. // be allowed (even if other criteria normally would prevent
  1830. // it from being copied); use false carefully!
  1831. },
  1832. preProcessors: MathJax.Callback.Hooks(true), // list of callbacks for preprocessing (initialized by extensions)
  1833. inputJax: {}, // mime-type mapped to input jax (by registration)
  1834. outputJax: {order:{}}, // mime-type mapped to output jax list (by registration)
  1835. processSectionDelay: 50, // pause between input and output phases of processing
  1836. processUpdateTime: 250, // time between screen updates when processing math (milliseconds)
  1837. processUpdateDelay: 10, // pause between screen updates to allow other processing (milliseconds)
  1838. signal: MathJax.Callback.Signal("Hub"), // Signal used for Hub events
  1839. Config: function (def) {
  1840. this.Insert(this.config,def);
  1841. if (this.config.Augment) {this.Augment(this.config.Augment)}
  1842. },
  1843. CombineConfig: function (name,def) {
  1844. var config = this.config, id, parent; name = name.split(/\./);
  1845. for (var i = 0, m = name.length; i < m; i++) {
  1846. id = name[i]; if (!config[id]) {config[id] = {}}
  1847. parent = config; config = config[id];
  1848. }
  1849. parent[id] = config = this.Insert(def,config);
  1850. return config;
  1851. },
  1852. Register: {
  1853. PreProcessor: function () {return MathJax.Hub.preProcessors.Add.apply(MathJax.Hub.preProcessors,arguments)},
  1854. MessageHook: function () {return MathJax.Hub.signal.MessageHook.apply(MathJax.Hub.signal,arguments)},
  1855. StartupHook: function () {return MathJax.Hub.Startup.signal.MessageHook.apply(MathJax.Hub.Startup.signal,arguments)},
  1856. LoadHook: function () {return MathJax.Ajax.LoadHook.apply(MathJax.Ajax,arguments)}
  1857. },
  1858. UnRegister: {
  1859. PreProcessor: function (hook) {MathJax.Hub.preProcessors.Remove(hook)},
  1860. MessageHook: function (hook) {MathJax.Hub.signal.RemoveHook(hook)},
  1861. StartupHook: function (hook) {MathJax.Hub.Startup.signal.RemoveHook(hook)},
  1862. LoadHook: function (hook) {MathJax.Ajax.removeHook(hook)}
  1863. },
  1864. getAllJax: function (element) {
  1865. var jax = [], scripts = this.elementScripts(element);
  1866. for (var i = 0, m = scripts.length; i < m; i++) {
  1867. if (scripts[i].MathJax && scripts[i].MathJax.elementJax)
  1868. {jax.push(scripts[i].MathJax.elementJax)}
  1869. }
  1870. return jax;
  1871. },
  1872. getJaxByType: function (type,element) {
  1873. var jax = [], scripts = this.elementScripts(element);
  1874. for (var i = 0, m = scripts.length; i < m; i++) {
  1875. if (scripts[i].MathJax && scripts[i].MathJax.elementJax &&
  1876. scripts[i].MathJax.elementJax.mimeType === type)
  1877. {jax.push(scripts[i].MathJax.elementJax)}
  1878. }
  1879. return jax;
  1880. },
  1881. getJaxByInputType: function (type,element) {
  1882. var jax = [], scripts = this.elementScripts(element);
  1883. for (var i = 0, m = scripts.length; i < m; i++) {
  1884. if (scripts[i].MathJax && scripts[i].MathJax.elementJax &&
  1885. scripts[i].type && scripts[i].type.replace(/ *;(.|\s)*/,"") === type)
  1886. {jax.push(scripts[i].MathJax.elementJax)}
  1887. }
  1888. return jax;
  1889. },
  1890. getJaxFor: function (element) {
  1891. if (typeof(element) === 'string') {element = document.getElementById(element)}
  1892. if (element && element.MathJax) {return element.MathJax.elementJax}
  1893. if (this.isMathJaxNode(element)) {
  1894. if (!element.isMathJax) {element = element.firstChild} // for NativeMML output
  1895. while (element && !element.jaxID) {element = element.parentNode}
  1896. if (element) {return MathJax.OutputJax[element.jaxID].getJaxFromMath(element)}
  1897. }
  1898. return null;
  1899. },
  1900. isJax: function (element) {
  1901. if (typeof(element) === 'string') {element = document.getElementById(element)}
  1902. if (this.isMathJaxNode(element)) {return 1}
  1903. if (element && (element.tagName||"").toLowerCase() === 'script') {
  1904. if (element.MathJax)
  1905. {return (element.MathJax.state === MathJax.ElementJax.STATE.PROCESSED ? 1 : -1)}
  1906. if (element.type && this.inputJax[element.type.replace(/ *;(.|\s)*/,"")]) {return -1}
  1907. }
  1908. return 0;
  1909. },
  1910. isMathJaxNode: function (element) {
  1911. return !!element && (element.isMathJax || (element.className||"") === "MathJax_MathML");
  1912. },
  1913. setRenderer: function (renderer,type) {
  1914. if (!renderer) return;
  1915. var JAX = MathJax.OutputJax[renderer];
  1916. if (!JAX) {
  1917. MathJax.OutputJax[renderer] = MathJax.OutputJax({id: "unknown", version:"1.0.0", isUnknown: true});
  1918. this.config.menuSettings.renderer = "";
  1919. var file = "[MathJax]/jax/output/"+renderer+"/config.js";
  1920. return MathJax.Ajax.Require(file,["setRenderer",this,renderer,type]);
  1921. } else {
  1922. this.config.menuSettings.renderer = renderer;
  1923. if (type == null) {type = "jax/mml"}
  1924. if (JAX.isUnknown) JAX.Register(type);
  1925. var jax = this.outputJax;
  1926. if (jax[type] && jax[type].length) {
  1927. if (renderer !== jax[type][0].id) {
  1928. jax[type].unshift(JAX);
  1929. return this.signal.Post(["Renderer Selected",renderer]);
  1930. }
  1931. }
  1932. return null;
  1933. }
  1934. },
  1935. Queue: function () {
  1936. return this.queue.Push.apply(this.queue,arguments);
  1937. },
  1938. Typeset: function (element,callback) {
  1939. if (!MathJax.isReady) return null;
  1940. var ec = this.elementCallback(element,callback);
  1941. if (ec.count) {
  1942. var queue = MathJax.Callback.Queue(
  1943. ["PreProcess",this,ec.elements],
  1944. ["Process",this,ec.elements]
  1945. );
  1946. }
  1947. return queue.Push(ec.callback);
  1948. },
  1949. PreProcess: function (element,callback) {
  1950. var ec = this.elementCallback(element,callback);
  1951. var queue = MathJax.Callback.Queue();
  1952. if (ec.count) {
  1953. var elements = (ec.count === 1 ? [ec.elements] : ec.elements);
  1954. queue.Push(["Post",this.signal,["Begin PreProcess",ec.elements]]);
  1955. for (var i = 0, m = elements.length; i < m; i++) {
  1956. if (elements[i]) {queue.Push(["Execute",this.preProcessors,elements[i]])}
  1957. }
  1958. queue.Push(["Post",this.signal,["End PreProcess",ec.elements]]);
  1959. }
  1960. return queue.Push(ec.callback);
  1961. },
  1962. Process: function (element,callback) {return this.takeAction("Process",element,callback)},
  1963. Update: function (element,callback) {return this.takeAction("Update",element,callback)},
  1964. Reprocess: function (element,callback) {return this.takeAction("Reprocess",element,callback)},
  1965. Rerender: function (element,callback) {return this.takeAction("Rerender",element,callback)},
  1966. takeAction: function (action,element,callback) {
  1967. var ec = this.elementCallback(element,callback);
  1968. var elements = ec.elements;
  1969. var queue = MathJax.Callback.Queue(["Clear",this.signal]);
  1970. var state = {
  1971. scripts: [], // filled in by prepareScripts
  1972. start: new Date().getTime(), // timer for processing messages
  1973. i: 0, j: 0, // current script, current jax
  1974. jax: {}, // scripts grouped by output jax
  1975. jaxIDs: [] // id's of jax used
  1976. };
  1977. if (ec.count) {
  1978. var delay = ["Delay",MathJax.Callback,this.processSectionDelay];
  1979. if (!delay[2]) {delay = {}}
  1980. queue.Push(
  1981. ["clearCounts",MathJax.Message],
  1982. ["Post",this.signal,["Begin "+action,elements]],
  1983. ["Post",this.signal,["Begin Math",elements,action]],
  1984. ["prepareScripts",this,action,elements,state],
  1985. ["Post",this.signal,["Begin Math Input",elements,action]],
  1986. ["processInput",this,state],
  1987. ["Post",this.signal,["End Math Input",elements,action]],
  1988. delay,
  1989. ["prepareOutput",this,state,"preProcess"],
  1990. delay,
  1991. ["Post",this.signal,["Begin Math Output",elements,action]],
  1992. ["processOutput",this,state],
  1993. ["Post",this.signal,["End Math Output",elements,action]],
  1994. delay,
  1995. ["prepareOutput",this,state,"postProcess"],
  1996. delay,
  1997. ["Post",this.signal,["End Math",elements,action]],
  1998. ["Post",this.signal,["End "+action,elements]],
  1999. ["clearCounts",MathJax.Message]
  2000. );
  2001. }
  2002. return queue.Push(ec.callback);
  2003. },
  2004. scriptAction: {
  2005. Process: function (script) {},
  2006. Update: function (script) {
  2007. var jax = script.MathJax.elementJax;
  2008. if (jax && jax.needsUpdate()) {jax.Remove(true); script.MathJax.state = jax.STATE.UPDATE}
  2009. else {script.MathJax.state = jax.STATE.PROCESSED}
  2010. },
  2011. Reprocess: function (script) {
  2012. var jax = script.MathJax.elementJax;
  2013. if (jax) {jax.Remove(true); script.MathJax.state = jax.STATE.UPDATE}
  2014. },
  2015. Rerender: function (script) {
  2016. var jax = script.MathJax.elementJax;
  2017. if (jax) {jax.Remove(true); script.MathJax.state = jax.STATE.OUTPUT}
  2018. }
  2019. },
  2020. prepareScripts: function (action,element,state) {
  2021. if (arguments.callee.disabled) return;
  2022. var scripts = this.elementScripts(element);
  2023. var STATE = MathJax.ElementJax.STATE;
  2024. for (var i = 0, m = scripts.length; i < m; i++) {
  2025. var script = scripts[i];
  2026. if (script.type && this.inputJax[script.type.replace(/ *;(.|\n)*/,"")]) {
  2027. if (script.MathJax) {
  2028. if (script.MathJax.elementJax && script.MathJax.elementJax.hover) {
  2029. MathJax.Extension.MathEvents.Hover.ClearHover(script.MathJax.elementJax);
  2030. }
  2031. if (script.MathJax.state !== STATE.PENDING) {this.scriptAction[action](script)}
  2032. }
  2033. if (!script.MathJax) {script.MathJax = {state: STATE.PENDING}}
  2034. if (script.MathJax.error) delete script.MathJax.error;
  2035. if (script.MathJax.state !== STATE.PROCESSED) {state.scripts.push(script)}
  2036. }
  2037. }
  2038. },
  2039. checkScriptSiblings: function (script) {
  2040. if (script.MathJax.checked) return;
  2041. var config = this.config, pre = script.previousSibling;
  2042. if (pre && pre.nodeName === "#text") {
  2043. var preJax,postJax, post = script.nextSibling;
  2044. if (post && post.nodeName !== "#text") {post = null}
  2045. if (config.preJax) {
  2046. if (typeof(config.preJax) === "string") {config.preJax = new RegExp(config.preJax+"$")}
  2047. preJax = pre.nodeValue.match(config.preJax);
  2048. }
  2049. if (config.postJax && post) {
  2050. if (typeof(config.postJax) === "string") {config.postJax = new RegExp("^"+config.postJax)}
  2051. postJax = post.nodeValue.match(config.postJax);
  2052. }
  2053. if (preJax && (!config.postJax || postJax)) {
  2054. pre.nodeValue = pre.nodeValue.replace
  2055. (config.preJax,(preJax.length > 1? preJax[1] : ""));
  2056. pre = null;
  2057. }
  2058. if (postJax && (!config.preJax || preJax)) {
  2059. post.nodeValue = post.nodeValue.replace
  2060. (config.postJax,(postJax.length > 1? postJax[1] : ""));
  2061. }
  2062. if (pre && !pre.nodeValue.match(/\S/)) {pre = pre.previousSibling}
  2063. }
  2064. if (config.preRemoveClass && pre && pre.className === config.preRemoveClass)
  2065. {script.MathJax.preview = pre}
  2066. script.MathJax.checked = 1;
  2067. },
  2068. processInput: function (state) {
  2069. var jax, STATE = MathJax.ElementJax.STATE;
  2070. var script, prev, m = state.scripts.length;
  2071. try {
  2072. //
  2073. // Loop through the scripts
  2074. //
  2075. while (state.i < m) {
  2076. script = state.scripts[state.i]; if (!script) {state.i++; continue}
  2077. //
  2078. // Remove previous error marker, if any
  2079. //
  2080. prev = script.previousSibling;
  2081. if (prev && prev.className === "MathJax_Error") {prev.parentNode.removeChild(prev)}
  2082. //
  2083. // Check if already processed or needs processing
  2084. //
  2085. if (!script.parentNode || !script.MathJax || script.MathJax.state === STATE.PROCESSED) {state.i++; continue};
  2086. if (!script.MathJax.elementJax || script.MathJax.state === STATE.UPDATE) {
  2087. this.checkScriptSiblings(script); // remove preJax/postJax etc.
  2088. var type = script.type.replace(/ *;(.|\s)*/,""); // the input jax type
  2089. var input = this.inputJax[type]; // the input jax itself
  2090. jax = input.Process(script,state); // run the input jax
  2091. if (typeof jax === 'function') { // if a callback was returned
  2092. if (jax.called) continue; // go back and call Process() again
  2093. this.RestartAfter(jax); // wait for the callback
  2094. }
  2095. jax = jax.Attach(script,input.id); // register the jax on the script
  2096. this.saveScript(jax,state,script,STATE); // add script to state
  2097. this.postInputHooks.Execute(jax,input.id,script); // run global jax filters
  2098. } else if (script.MathJax.state === STATE.OUTPUT) {
  2099. this.saveScript(script.MathJax.elementJax,state,script,STATE); // add script to state
  2100. }
  2101. //
  2102. // Go on to the next script, and check if we need to update the processing message
  2103. //
  2104. state.i++; var now = new Date().getTime();
  2105. if (now - state.start > this.processUpdateTime && state.i < state.scripts.length)
  2106. {state.start = now; this.RestartAfter(MathJax.Callback.Delay(1))}
  2107. }
  2108. } catch (err) {return this.processError(err,state,"Input")}
  2109. //
  2110. // Put up final message, reset the state and return
  2111. //
  2112. if (state.scripts.length && this.config.showProcessingMessages)
  2113. {MathJax.Message.Set(["ProcessMath","Processing math: %1%%",100],0)}
  2114. state.start = new Date().getTime(); state.i = state.j = 0;
  2115. return null;
  2116. },
  2117. postInputHooks: MathJax.Callback.Hooks(true), // hooks to run after element jax is created
  2118. saveScript: function (jax,state,script,STATE) {
  2119. //
  2120. // Check that output jax exists
  2121. //
  2122. if (!this.outputJax[jax.mimeType]) {
  2123. script.MathJax.state = STATE.UPDATE;
  2124. throw Error("No output jax registered for "+jax.mimeType);
  2125. }
  2126. //
  2127. // Record the output jax
  2128. // and put this script in the queue for that jax
  2129. //
  2130. jax.outputJax = this.outputJax[jax.mimeType][0].id;
  2131. if (!state.jax[jax.outputJax]) {
  2132. if (state.jaxIDs.length === 0) {
  2133. // use original array until we know there are more (rather than two copies)
  2134. state.jax[jax.outputJax] = state.scripts;
  2135. } else {
  2136. if (state.jaxIDs.length === 1) // get the script so far for the existing jax
  2137. {state.jax[state.jaxIDs[0]] = state.scripts.slice(0,state.i)}
  2138. state.jax[jax.outputJax] = []; // start a new array for the new jax
  2139. }
  2140. state.jaxIDs.push(jax.outputJax); // save the ID of the jax
  2141. }
  2142. if (state.jaxIDs.length > 1) {state.jax[jax.outputJax].push(script)}
  2143. //
  2144. // Mark script as needing output
  2145. //
  2146. script.MathJax.state = STATE.OUTPUT;
  2147. },
  2148. //
  2149. // Pre- and post-process scripts by jax
  2150. // (to get scaling factors, hide/show output, and so on)
  2151. // Since this can cause the jax to load, we need to trap restarts
  2152. //
  2153. prepareOutput: function (state,method) {
  2154. while (state.j < state.jaxIDs.length) {
  2155. var id = state.jaxIDs[state.j], JAX = MathJax.OutputJax[id];
  2156. if (JAX[method]) {
  2157. try {
  2158. var result = JAX[method](state);
  2159. if (typeof result === 'function') {
  2160. if (result.called) continue; // go back and try again
  2161. this.RestartAfter(result);
  2162. }
  2163. } catch (err) {
  2164. if (!err.restart) {
  2165. MathJax.Message.Set(["PrepError","Error preparing %1 output (%2)",id,method],null,600);
  2166. MathJax.Hub.lastPrepError = err;
  2167. state.j++;
  2168. }
  2169. return MathJax.Callback.After(["prepareOutput",this,state,method],err.restart);
  2170. }
  2171. }
  2172. state.j++;
  2173. }
  2174. return null;
  2175. },
  2176. processOutput: function (state) {
  2177. var result, STATE = MathJax.ElementJax.STATE, script, m = state.scripts.length;
  2178. try {
  2179. //
  2180. // Loop through the scripts
  2181. //
  2182. while (state.i < m) {
  2183. //
  2184. // Check that there is an element jax
  2185. //
  2186. script = state.scripts[state.i];
  2187. if (!script || !script.parentNode || !script.MathJax || script.MathJax.error) {state.i++; continue}
  2188. var jax = script.MathJax.elementJax; if (!jax) {state.i++; continue}
  2189. //
  2190. // Call the output Jax's Process method (which will be its Translate()
  2191. // method once loaded). Mark it as complete and remove the preview unless
  2192. // the Process() call returns an explicit false value (in which case, it will
  2193. // handle this later during the postProcess phase, as HTML-CSS does).
  2194. //
  2195. result = MathJax.OutputJax[jax.outputJax].Process(script,state);
  2196. if (result !== false) {
  2197. script.MathJax.state = STATE.PROCESSED;
  2198. if (script.MathJax.preview) {
  2199. script.MathJax.preview.innerHTML = "";
  2200. script.MathJax.preview.style.display = "none";
  2201. }
  2202. //
  2203. // Signal that new math is available
  2204. //
  2205. this.signal.Post(["New Math",jax.inputID]); // FIXME: wait for this? (i.e., restart if returns uncalled callback)
  2206. }
  2207. //
  2208. // Go on to next math expression
  2209. //
  2210. state.i++;
  2211. //
  2212. // Update the processing message, if needed
  2213. //
  2214. var now = new Date().getTime();
  2215. if (now - state.start > this.processUpdateTime && state.i < state.scripts.length)
  2216. {state.start = now; this.RestartAfter(MathJax.Callback.Delay(this.processUpdateDelay))}
  2217. }
  2218. } catch (err) {return this.processError(err,state,"Output")}
  2219. //
  2220. // Put up the typesetting-complete message
  2221. //
  2222. if (state.scripts.length && this.config.showProcessingMessages) {
  2223. MathJax.Message.Set(["TypesetMath","Typesetting math: %1%%",100],0);
  2224. MathJax.Message.Clear(0);
  2225. }
  2226. state.i = state.j = 0;
  2227. return null;
  2228. },
  2229. processMessage: function (state,type) {
  2230. var m = Math.floor(state.i/(state.scripts.length)*100);
  2231. var message = (type === "Output" ? ["TypesetMath","Typesetting math: %1%%"] :
  2232. ["ProcessMath","Processing math: %1%%"]);
  2233. if (this.config.showProcessingMessages) {MathJax.Message.Set(message.concat(m),0)}
  2234. },
  2235. processError: function (err,state,type) {
  2236. if (!err.restart) {
  2237. if (!this.config.errorSettings.message) {throw err}
  2238. this.formatError(state.scripts[state.i],err); state.i++;
  2239. }
  2240. this.processMessage(state,type);
  2241. return MathJax.Callback.After(["process"+type,this,state],err.restart);
  2242. },
  2243. formatError: function (script,err) {
  2244. var LOCALIZE = function (id,text,arg1,arg2) {return MathJax.Localization._(id,text,arg1,arg2)};
  2245. //
  2246. // Get the error message, URL, and line, and save it for
  2247. // reporting in the Show Math As Error menu
  2248. //
  2249. var message = LOCALIZE("ErrorMessage","Error: %1",err.message)+"\n";
  2250. if (err.sourceURL||err.fileName) message += "\n"+LOCALIZE("ErrorFile","file: %1",err.sourceURL||err.fileName);
  2251. if (err.line||err.lineNumber) message += "\n"+LOCALIZE("ErrorLine","line: %1",err.line||err.lineNumber);
  2252. message += "\n\n"+LOCALIZE("ErrorTips","Debugging tips: use %1, inspect %2 in the browser console","'unpacked/MathJax.js'","'MathJax.Hub.lastError'");
  2253. script.MathJax.error = MathJax.OutputJax.Error.Jax(message,script);
  2254. if (script.MathJax.elementJax)
  2255. script.MathJax.error.inputID = script.MathJax.elementJax.inputID;
  2256. //
  2257. // Create the [Math Processing Error] span
  2258. //
  2259. var errorSettings = this.config.errorSettings;
  2260. var errorText = LOCALIZE(errorSettings.messageId,errorSettings.message);
  2261. var error = MathJax.HTML.Element("span", {
  2262. className:"MathJax_Error", jaxID:"Error", isMathJax:true,
  2263. id: script.MathJax.error.inputID+"-Frame"
  2264. },[["span",null,errorText]]);
  2265. //
  2266. // Attach the menu events
  2267. //
  2268. MathJax.Ajax.Require("[MathJax]/extensions/MathEvents.js",function () {
  2269. var EVENT = MathJax.Extension.MathEvents.Event,
  2270. HUB = MathJax.Hub;
  2271. error.oncontextmenu = EVENT.Menu;
  2272. error.onmousedown = EVENT.Mousedown;
  2273. error.onkeydown = EVENT.Keydown;
  2274. error.tabIndex = HUB.getTabOrder(HUB.getJaxFor(script));
  2275. });
  2276. //
  2277. // Insert the error into the page and remove any preview
  2278. //
  2279. var node = document.getElementById(error.id);
  2280. if (node) node.parentNode.removeChild(node);
  2281. if (script.parentNode) script.parentNode.insertBefore(error,script);
  2282. if (script.MathJax.preview) {
  2283. script.MathJax.preview.innerHTML = "";
  2284. script.MathJax.preview.style.display = "none";
  2285. }
  2286. //
  2287. // Save the error for debugging purposes
  2288. // Report the error as a signal
  2289. //
  2290. this.lastError = err;
  2291. this.signal.Post(["Math Processing Error",script,err]);
  2292. },
  2293. RestartAfter: function (callback) {
  2294. throw this.Insert(Error("restart"),{restart: MathJax.Callback(callback)});
  2295. },
  2296. elementCallback: function (element,callback) {
  2297. if (callback == null && (MathJax.Object.isArray(element) || typeof element === 'function'))
  2298. {try {MathJax.Callback(element); callback = element; element = null} catch(e) {}}
  2299. if (element == null) {element = this.config.elements || []}
  2300. if (this.isHTMLCollection(element)) {element = this.HTMLCollection2Array(element)}
  2301. if (!MathJax.Object.isArray(element)) {element = [element]}
  2302. element = [].concat(element); // make a copy so the original isn't changed
  2303. for (var i = 0, m = element.length; i < m; i++)
  2304. {if (typeof(element[i]) === 'string') {element[i] = document.getElementById(element[i])}}
  2305. if (!document.body) {document.body = document.getElementsByTagName("body")[0]}
  2306. if (element.length == 0) {element.push(document.body)}
  2307. if (!callback) {callback = {}}
  2308. return {
  2309. count: element.length,
  2310. elements: (element.length === 1 ? element[0] : element),
  2311. callback: callback
  2312. };
  2313. },
  2314. elementScripts: function (element) {
  2315. var scripts = [];
  2316. if (MathJax.Object.isArray(element) || this.isHTMLCollection(element)) {
  2317. for (var i = 0, m = element.length; i < m; i++) {
  2318. var alreadyDone = 0;
  2319. for (var j = 0; j < i && !alreadyDone; j++)
  2320. {alreadyDone = element[j].contains(element[i])}
  2321. if (!alreadyDone) scripts.push.apply(scripts,this.elementScripts(element[i]));
  2322. }
  2323. return scripts;
  2324. }
  2325. if (typeof(element) === 'string') {element = document.getElementById(element)}
  2326. if (!document.body) {document.body = document.getElementsByTagName("body")[0]}
  2327. if (element == null) {element = document.body}
  2328. if (element.tagName != null && element.tagName.toLowerCase() === "script") {return [element]}
  2329. scripts = element.getElementsByTagName("script");
  2330. if (this.msieHTMLCollectionBug) {scripts = this.HTMLCollection2Array(scripts)}
  2331. return scripts;
  2332. },
  2333. //
  2334. // IE8 fails to check "obj instanceof HTMLCollection" for some values of obj.
  2335. //
  2336. isHTMLCollection: function (obj) {
  2337. return ("HTMLCollection" in window && typeof(obj) === "object" && obj instanceof HTMLCollection);
  2338. },
  2339. //
  2340. // IE8 doesn't deal with HTMLCollection as an array, so convert to array
  2341. //
  2342. HTMLCollection2Array: function (nodes) {
  2343. if (!this.msieHTMLCollectionBug) {return [].slice.call(nodes)}
  2344. var NODES = [];
  2345. for (var i = 0, m = nodes.length; i < m; i++) {NODES[i] = nodes[i]}
  2346. return NODES;
  2347. },
  2348. Insert: function (dst,src) {
  2349. for (var id in src) {if (src.hasOwnProperty(id)) {
  2350. // allow for concatenation of arrays?
  2351. if (typeof src[id] === 'object' && !(MathJax.Object.isArray(src[id])) &&
  2352. (typeof dst[id] === 'object' || typeof dst[id] === 'function')) {
  2353. this.Insert(dst[id],src[id]);
  2354. } else {
  2355. dst[id] = src[id];
  2356. }
  2357. }}
  2358. return dst;
  2359. },
  2360. getTabOrder: function(script) {
  2361. return this.config.menuSettings.inTabOrder ? 0 : -1;
  2362. },
  2363. // Old browsers (e.g. Internet Explorer <= 8) do not support trim().
  2364. SplitList: ("trim" in String.prototype ?
  2365. function (list) {return list.trim().split(/\s+/)} :
  2366. function (list) {return list.replace(/^\s+/,'').
  2367. replace(/\s+$/,'').split(/\s+/)})
  2368. };
  2369. MathJax.Hub.Insert(MathJax.Hub.config.styles,MathJax.Message.styles);
  2370. MathJax.Hub.Insert(MathJax.Hub.config.styles,{".MathJax_Error":MathJax.Hub.config.errorSettings.style});
  2371. //
  2372. // Storage area for extensions and preprocessors
  2373. //
  2374. MathJax.Extension = {};
  2375. //
  2376. // Hub Startup code
  2377. //
  2378. MathJax.Hub.Configured = MathJax.Callback({}); // called when configuration is complete
  2379. MathJax.Hub.Startup = {
  2380. script: "", // the startup script from the SCRIPT call that loads MathJax.js
  2381. queue: MathJax.Callback.Queue(), // Queue used for startup actions
  2382. signal: MathJax.Callback.Signal("Startup"), // Signal used for startup events
  2383. params: {},
  2384. //
  2385. // Load the configuration files
  2386. //
  2387. Config: function () {
  2388. this.queue.Push(["Post",this.signal,"Begin Config"]);
  2389. //
  2390. // Make sure root is set before loading any files
  2391. //
  2392. if (MathJax.AuthorConfig && MathJax.AuthorConfig.root)
  2393. MathJax.Ajax.config.root = MathJax.AuthorConfig.root;
  2394. //
  2395. // If a locale is given as a parameter,
  2396. // set the locale and the default menu value for the locale
  2397. //
  2398. if (this.params.locale) {
  2399. MathJax.Localization.resetLocale(this.params.locale);
  2400. MathJax.Hub.config.menuSettings.locale = this.params.locale;
  2401. }
  2402. //
  2403. // Run the config files, if any are given in the parameter list
  2404. //
  2405. if (this.params.config) {
  2406. var files = this.params.config.split(/,/);
  2407. for (var i = 0, m = files.length; i < m; i++) {
  2408. if (!files[i].match(/\.js$/)) {files[i] += ".js"}
  2409. this.queue.Push(["Require",MathJax.Ajax,this.URL("config",files[i])]);
  2410. }
  2411. }
  2412. //
  2413. // Perform author configuration from in-line MathJax = {...}
  2414. //
  2415. this.queue.Push(["Config",MathJax.Hub,MathJax.AuthorConfig]);
  2416. //
  2417. // Run the deprecated configuration script, if any (ignoring return value)
  2418. // Wait for the startup delay signal
  2419. // Run the mathjax-config blocks
  2420. // Load the files in the configuration's config array
  2421. //
  2422. if (this.script.match(/\S/)) {this.queue.Push(this.script+";\n1;")}
  2423. this.queue.Push(
  2424. ["ConfigDelay",this],
  2425. ["ConfigBlocks",this],
  2426. [function (THIS) {return THIS.loadArray(MathJax.Hub.config.config,"config",null,true)},this],
  2427. ["Post",this.signal,"End Config"]
  2428. );
  2429. },
  2430. //
  2431. // Return the delay callback
  2432. //
  2433. ConfigDelay: function () {
  2434. var delay = this.params.delayStartupUntil || MathJax.Hub.config.delayStartupUntil;
  2435. if (delay === "onload") {return this.onload}
  2436. if (delay === "configured") {return MathJax.Hub.Configured}
  2437. return delay;
  2438. },
  2439. //
  2440. // Run the scripts of type=text/x-mathjax-config
  2441. //
  2442. ConfigBlocks: function () {
  2443. var scripts = document.getElementsByTagName("script");
  2444. var queue = MathJax.Callback.Queue();
  2445. for (var i = 0, m = scripts.length; i < m; i++) {
  2446. var type = String(scripts[i].type).replace(/ /g,"");
  2447. if (type.match(/^text\/x-mathjax-config(;.*)?$/) && !type.match(/;executed=true/)) {
  2448. scripts[i].type += ";executed=true";
  2449. queue.Push(scripts[i].innerHTML+";\n1;");
  2450. }
  2451. }
  2452. return queue.Push(function () {MathJax.Ajax.config.root = MathJax.Hub.config.root});
  2453. },
  2454. //
  2455. // Read cookie and set up menu defaults
  2456. // (set the locale according to the cookie)
  2457. // (adjust the jax to accommodate renderer preferences)
  2458. //
  2459. Cookie: function () {
  2460. return this.queue.Push(
  2461. ["Post",this.signal,"Begin Cookie"],
  2462. ["Get",MathJax.HTML.Cookie,"menu",MathJax.Hub.config.menuSettings],
  2463. [function (config) {
  2464. var SETTINGS = config.menuSettings;
  2465. if (SETTINGS.locale) MathJax.Localization.resetLocale(SETTINGS.locale);
  2466. var renderer = config.menuSettings.renderer, jax = config.jax;
  2467. if (renderer) {
  2468. var name = "output/"+renderer; jax.sort();
  2469. for (var i = 0, m = jax.length; i < m; i++) {
  2470. if (jax[i].substr(0,7) === "output/") break;
  2471. }
  2472. if (i == m-1) {jax.pop()} else {
  2473. while (i < m) {if (jax[i] === name) {jax.splice(i,1); break}; i++}
  2474. }
  2475. jax.unshift(name);
  2476. }
  2477. if (SETTINGS.CHTMLpreview != null) {
  2478. if (SETTINGS.FastPreview == null) SETTINGS.FastPreview = SETTINGS.CHTMLpreview;
  2479. delete SETTINGS.CHTMLpreview;
  2480. }
  2481. if (SETTINGS.FastPreview && !MathJax.Extension["fast-preview"])
  2482. MathJax.Hub.config.extensions.push("fast-preview.js");
  2483. if (config.menuSettings.assistiveMML && !MathJax.Extension.AssistiveMML)
  2484. MathJax.Hub.config.extensions.push("AssistiveMML.js");
  2485. },MathJax.Hub.config],
  2486. ["Post",this.signal,"End Cookie"]
  2487. );
  2488. },
  2489. //
  2490. // Setup stylesheets and extra styles
  2491. //
  2492. Styles: function () {
  2493. return this.queue.Push(
  2494. ["Post",this.signal,"Begin Styles"],
  2495. ["loadArray",this,MathJax.Hub.config.styleSheets,"config"],
  2496. ["Styles",MathJax.Ajax,MathJax.Hub.config.styles],
  2497. ["Post",this.signal,"End Styles"]
  2498. );
  2499. },
  2500. //
  2501. // Load the input and output jax
  2502. //
  2503. Jax: function () {
  2504. var config = MathJax.Hub.config, jax = MathJax.Hub.outputJax;
  2505. // Save the order of the output jax since they are loading asynchronously
  2506. for (var i = 0, m = config.jax.length, k = 0; i < m; i++) {
  2507. var name = config.jax[i].substr(7);
  2508. if (config.jax[i].substr(0,7) === "output/" && jax.order[name] == null)
  2509. {jax.order[name] = k; k++}
  2510. }
  2511. var queue = MathJax.Callback.Queue();
  2512. return queue.Push(
  2513. ["Post",this.signal,"Begin Jax"],
  2514. ["loadArray",this,config.jax,"jax","config.js"],
  2515. ["Post",this.signal,"End Jax"]
  2516. );
  2517. },
  2518. //
  2519. // Load the extensions
  2520. //
  2521. Extensions: function () {
  2522. var queue = MathJax.Callback.Queue();
  2523. return queue.Push(
  2524. ["Post",this.signal,"Begin Extensions"],
  2525. ["loadArray",this,MathJax.Hub.config.extensions,"extensions"],
  2526. ["Post",this.signal,"End Extensions"]
  2527. );
  2528. },
  2529. //
  2530. // Initialize the Message system
  2531. //
  2532. Message: function () {
  2533. MathJax.Message.Init(true);
  2534. },
  2535. //
  2536. // Set the math menu renderer, if it isn't already
  2537. // (this must come after the jax are loaded)
  2538. //
  2539. Menu: function () {
  2540. var menu = MathJax.Hub.config.menuSettings, jax = MathJax.Hub.outputJax, registered;
  2541. for (var id in jax) {if (jax.hasOwnProperty(id)) {
  2542. if (jax[id].length) {registered = jax[id]; break}
  2543. }}
  2544. if (registered && registered.length) {
  2545. if (menu.renderer && menu.renderer !== registered[0].id)
  2546. {registered.unshift(MathJax.OutputJax[menu.renderer])}
  2547. menu.renderer = registered[0].id;
  2548. }
  2549. },
  2550. //
  2551. // Set the location to the designated hash position
  2552. //
  2553. Hash: function () {
  2554. if (MathJax.Hub.config.positionToHash && document.location.hash &&
  2555. document.body && document.body.scrollIntoView) {
  2556. var name = decodeURIComponent(document.location.hash.substr(1));
  2557. var target = document.getElementById(name);
  2558. if (!target) {
  2559. var a = document.getElementsByTagName("a");
  2560. for (var i = 0, m = a.length; i < m; i++)
  2561. {if (a[i].name === name) {target = a[i]; break}}
  2562. }
  2563. if (target) {
  2564. while (!target.scrollIntoView) {target = target.parentNode}
  2565. target = this.HashCheck(target);
  2566. if (target && target.scrollIntoView)
  2567. {setTimeout(function () {target.scrollIntoView(true)},1)}
  2568. }
  2569. }
  2570. },
  2571. HashCheck: function (target) {
  2572. var jax = MathJax.Hub.getJaxFor(target);
  2573. if (jax && MathJax.OutputJax[jax.outputJax].hashCheck)
  2574. {target = MathJax.OutputJax[jax.outputJax].hashCheck(target)}
  2575. return target;
  2576. },
  2577. //
  2578. // Load the Menu and Zoom code, if it hasn't already been loaded.
  2579. // This is called after the initial typeset, so should no longer be
  2580. // competing with other page loads, but will make these available
  2581. // if needed later on.
  2582. //
  2583. MenuZoom: function () {
  2584. if (MathJax.Hub.config.showMathMenu) {
  2585. if (!MathJax.Extension.MathMenu) {
  2586. setTimeout(
  2587. function () {
  2588. MathJax.Callback.Queue(
  2589. ["Require",MathJax.Ajax,"[MathJax]/extensions/MathMenu.js",{}],
  2590. ["loadDomain",MathJax.Localization,"MathMenu"]
  2591. )
  2592. },1000
  2593. );
  2594. } else {
  2595. setTimeout(
  2596. MathJax.Callback(["loadDomain",MathJax.Localization,"MathMenu"]),
  2597. 1000
  2598. );
  2599. }
  2600. if (!MathJax.Extension.MathZoom) {
  2601. setTimeout(
  2602. MathJax.Callback(["Require",MathJax.Ajax,"[MathJax]/extensions/MathZoom.js",{}]),
  2603. 2000
  2604. );
  2605. }
  2606. }
  2607. },
  2608. //
  2609. // Setup the onload callback
  2610. //
  2611. onLoad: function () {
  2612. var onload = this.onload =
  2613. MathJax.Callback(function () {MathJax.Hub.Startup.signal.Post("onLoad")});
  2614. if (document.body && document.readyState)
  2615. if (MathJax.Hub.Browser.isMSIE) {
  2616. // IE can change from loading to interactive before
  2617. // full page is ready, so go with complete (even though
  2618. // that means we may have to wait longer).
  2619. if (document.readyState === "complete") {return [onload]}
  2620. } else if (document.readyState !== "loading") {return [onload]}
  2621. if (window.addEventListener) {
  2622. window.addEventListener("load",onload,false);
  2623. if (!this.params.noDOMContentEvent)
  2624. {window.addEventListener("DOMContentLoaded",onload,false)}
  2625. }
  2626. else if (window.attachEvent) {window.attachEvent("onload",onload)}
  2627. else {window.onload = onload}
  2628. return onload;
  2629. },
  2630. //
  2631. // Perform the initial typesetting (or skip if configuration says to)
  2632. //
  2633. Typeset: function (element,callback) {
  2634. if (MathJax.Hub.config.skipStartupTypeset) {return function () {}}
  2635. return this.queue.Push(
  2636. ["Post",this.signal,"Begin Typeset"],
  2637. ["Typeset",MathJax.Hub,element,callback],
  2638. ["Post",this.signal,"End Typeset"]
  2639. );
  2640. },
  2641. //
  2642. // Create a URL in the MathJax hierarchy
  2643. //
  2644. URL: function (dir,name) {
  2645. if (!name.match(/^([a-z]+:\/\/|\[|\/)/)) {name = "[MathJax]/"+dir+"/"+name}
  2646. return name;
  2647. },
  2648. //
  2649. // Load an array of files, waiting for all of them
  2650. // to be loaded before going on
  2651. //
  2652. loadArray: function (files,dir,name,synchronous) {
  2653. if (files) {
  2654. if (!MathJax.Object.isArray(files)) {files = [files]}
  2655. if (files.length) {
  2656. var queue = MathJax.Callback.Queue(), callback = {}, file;
  2657. for (var i = 0, m = files.length; i < m; i++) {
  2658. file = this.URL(dir,files[i]);
  2659. if (name) {file += "/" + name}
  2660. if (synchronous) {queue.Push(["Require",MathJax.Ajax,file,callback])}
  2661. else {queue.Push(MathJax.Ajax.Require(file,callback))}
  2662. }
  2663. return queue.Push({}); // wait for everything to finish
  2664. }
  2665. }
  2666. return null;
  2667. }
  2668. };
  2669. /**********************************************************/
  2670. (function (BASENAME) {
  2671. var BASE = window[BASENAME], ROOT = "["+BASENAME+"]";
  2672. var HUB = BASE.Hub, AJAX = BASE.Ajax, CALLBACK = BASE.Callback;
  2673. var JAX = MathJax.Object.Subclass({
  2674. JAXFILE: "jax.js",
  2675. require: null, // array of files to load before jax.js is complete
  2676. config: {},
  2677. //
  2678. // Make a subclass and return an instance of it.
  2679. // (FIXME: should we replace config with a copy of the constructor's
  2680. // config? Otherwise all subclasses share the same config structure.)
  2681. //
  2682. Init: function (def,cdef) {
  2683. if (arguments.length === 0) {return this}
  2684. return (this.constructor.Subclass(def,cdef))();
  2685. },
  2686. //
  2687. // Augment by merging with class definition (not replacing)
  2688. //
  2689. Augment: function (def,cdef) {
  2690. var cObject = this.constructor, ndef = {};
  2691. if (def != null) {
  2692. for (var id in def) {if (def.hasOwnProperty(id)) {
  2693. if (typeof def[id] === "function")
  2694. {cObject.protoFunction(id,def[id])} else {ndef[id] = def[id]}
  2695. }}
  2696. // MSIE doesn't list toString even if it is not native so handle it separately
  2697. if (def.toString !== cObject.prototype.toString && def.toString !== {}.toString)
  2698. {cObject.protoFunction('toString',def.toString)}
  2699. }
  2700. HUB.Insert(cObject.prototype,ndef);
  2701. cObject.Augment(null,cdef);
  2702. return this;
  2703. },
  2704. Translate: function (script,state) {
  2705. throw Error(this.directory+"/"+this.JAXFILE+" failed to define the Translate() method");
  2706. },
  2707. Register: function (mimetype) {},
  2708. Config: function () {
  2709. this.config = HUB.CombineConfig(this.id,this.config);
  2710. if (this.config.Augment) {this.Augment(this.config.Augment)}
  2711. },
  2712. Startup: function () {},
  2713. loadComplete: function (file) {
  2714. if (file === "config.js") {
  2715. return AJAX.loadComplete(this.directory+"/"+file);
  2716. } else {
  2717. var queue = CALLBACK.Queue();
  2718. queue.Push(
  2719. HUB.Register.StartupHook("End Config",{}), // wait until config complete
  2720. ["Post",HUB.Startup.signal,this.id+" Jax Config"],
  2721. ["Config",this],
  2722. ["Post",HUB.Startup.signal,this.id+" Jax Require"],
  2723. // Config may set the required and extensions array,
  2724. // so use functions to delay making the reference until needed
  2725. [function (THIS) {return MathJax.Hub.Startup.loadArray(THIS.require,this.directory)},this],
  2726. [function (config,id) {return MathJax.Hub.Startup.loadArray(config.extensions,"extensions/"+id)},this.config||{},this.id],
  2727. ["Post",HUB.Startup.signal,this.id+" Jax Startup"],
  2728. ["Startup",this],
  2729. ["Post",HUB.Startup.signal,this.id+" Jax Ready"]
  2730. );
  2731. if (this.copyTranslate) {
  2732. queue.Push(
  2733. [function (THIS) {
  2734. THIS.preProcess = THIS.preTranslate;
  2735. THIS.Process = THIS.Translate;
  2736. THIS.postProcess = THIS.postTranslate;
  2737. },this.constructor.prototype]
  2738. );
  2739. }
  2740. return queue.Push(["loadComplete",AJAX,this.directory+"/"+file]);
  2741. }
  2742. }
  2743. },{
  2744. id: "Jax",
  2745. version: "2.7.5",
  2746. directory: ROOT+"/jax",
  2747. extensionDir: ROOT+"/extensions"
  2748. });
  2749. /***********************************/
  2750. BASE.InputJax = JAX.Subclass({
  2751. elementJax: "mml", // the element jax to load for this input jax
  2752. sourceMenuTitle: /*_(MathMenu)*/ ["Original","Original Form"],
  2753. copyTranslate: true,
  2754. Process: function (script,state) {
  2755. var queue = CALLBACK.Queue(), file;
  2756. // Load any needed element jax
  2757. var jax = this.elementJax; if (!BASE.Object.isArray(jax)) {jax = [jax]}
  2758. for (var i = 0, m = jax.length; i < m; i++) {
  2759. file = BASE.ElementJax.directory+"/"+jax[i]+"/"+this.JAXFILE;
  2760. if (!this.require) {this.require = []}
  2761. else if (!BASE.Object.isArray(this.require)) {this.require = [this.require]};
  2762. this.require.push(file); // so Startup will wait for it to be loaded
  2763. queue.Push(AJAX.Require(file));
  2764. }
  2765. // Load the input jax
  2766. file = this.directory+"/"+this.JAXFILE;
  2767. var load = queue.Push(AJAX.Require(file));
  2768. if (!load.called) {
  2769. this.constructor.prototype.Process = function () {
  2770. if (!load.called) {return load}
  2771. throw Error(file+" failed to load properly");
  2772. }
  2773. }
  2774. // Load the associated output jax
  2775. jax = HUB.outputJax["jax/"+jax[0]];
  2776. if (jax) {queue.Push(AJAX.Require(jax[0].directory+"/"+this.JAXFILE))}
  2777. return queue.Push({});
  2778. },
  2779. needsUpdate: function (jax) {
  2780. var script = jax.SourceElement();
  2781. return (jax.originalText !== BASE.HTML.getScript(script));
  2782. },
  2783. Register: function (mimetype) {
  2784. if (!HUB.inputJax) {HUB.inputJax = {}}
  2785. HUB.inputJax[mimetype] = this;
  2786. }
  2787. },{
  2788. id: "InputJax",
  2789. version: "2.7.5",
  2790. directory: JAX.directory+"/input",
  2791. extensionDir: JAX.extensionDir
  2792. });
  2793. /***********************************/
  2794. BASE.OutputJax = JAX.Subclass({
  2795. copyTranslate: true,
  2796. preProcess: function (state) {
  2797. var load, file = this.directory+"/"+this.JAXFILE;
  2798. this.constructor.prototype.preProcess = function (state) {
  2799. if (!load.called) {return load}
  2800. throw Error(file+" failed to load properly");
  2801. }
  2802. load = AJAX.Require(file);
  2803. return load;
  2804. },
  2805. Process: function (state) {throw Error(this.id + " output jax failed to load properly")},
  2806. Register: function (mimetype) {
  2807. var jax = HUB.outputJax;
  2808. if (!jax[mimetype]) {jax[mimetype] = []}
  2809. // If the output jax is earlier in the original configuration list, put it first here
  2810. if (jax[mimetype].length && (this.id === HUB.config.menuSettings.renderer ||
  2811. (jax.order[this.id]||0) < (jax.order[jax[mimetype][0].id]||0)))
  2812. {jax[mimetype].unshift(this)} else {jax[mimetype].push(this)}
  2813. // Make sure the element jax is loaded before Startup is called
  2814. if (!this.require) {this.require = []}
  2815. else if (!BASE.Object.isArray(this.require)) {this.require = [this.require]};
  2816. this.require.push(BASE.ElementJax.directory+"/"+(mimetype.split(/\//)[1])+"/"+this.JAXFILE);
  2817. },
  2818. Remove: function (jax) {}
  2819. },{
  2820. id: "OutputJax",
  2821. version: "2.7.5",
  2822. directory: JAX.directory+"/output",
  2823. extensionDir: JAX.extensionDir,
  2824. fontDir: ROOT+(BASE.isPacked?"":"/..")+"/fonts",
  2825. imageDir: ROOT+(BASE.isPacked?"":"/..")+"/images"
  2826. });
  2827. /***********************************/
  2828. BASE.ElementJax = JAX.Subclass({
  2829. // make a subclass, not an instance
  2830. Init: function (def,cdef) {return this.constructor.Subclass(def,cdef)},
  2831. inputJax: null,
  2832. outputJax: null,
  2833. inputID: null,
  2834. originalText: "",
  2835. mimeType: "",
  2836. sourceMenuTitle: /*_(MathMenu)*/ ["MathMLcode","MathML Code"],
  2837. Text: function (text,callback) {
  2838. var script = this.SourceElement();
  2839. BASE.HTML.setScript(script,text);
  2840. script.MathJax.state = this.STATE.UPDATE;
  2841. return HUB.Update(script,callback);
  2842. },
  2843. Reprocess: function (callback) {
  2844. var script = this.SourceElement();
  2845. script.MathJax.state = this.STATE.UPDATE;
  2846. return HUB.Reprocess(script,callback);
  2847. },
  2848. Update: function (callback) {return this.Rerender(callback)},
  2849. Rerender: function (callback) {
  2850. var script = this.SourceElement();
  2851. script.MathJax.state = this.STATE.OUTPUT;
  2852. return HUB.Process(script,callback);
  2853. },
  2854. Remove: function (keep) {
  2855. if (this.hover) {this.hover.clear(this)}
  2856. BASE.OutputJax[this.outputJax].Remove(this);
  2857. if (!keep) {
  2858. HUB.signal.Post(["Remove Math",this.inputID]); // wait for this to finish?
  2859. this.Detach();
  2860. }
  2861. },
  2862. needsUpdate: function () {
  2863. return BASE.InputJax[this.inputJax].needsUpdate(this);
  2864. },
  2865. SourceElement: function () {return document.getElementById(this.inputID)},
  2866. Attach: function (script,inputJax) {
  2867. var jax = script.MathJax.elementJax;
  2868. if (script.MathJax.state === this.STATE.UPDATE) {
  2869. jax.Clone(this);
  2870. } else {
  2871. jax = script.MathJax.elementJax = this;
  2872. if (script.id) {this.inputID = script.id}
  2873. else {script.id = this.inputID = BASE.ElementJax.GetID(); this.newID = 1}
  2874. }
  2875. jax.originalText = BASE.HTML.getScript(script);
  2876. jax.inputJax = inputJax;
  2877. if (jax.root) {jax.root.inputID = jax.inputID}
  2878. return jax;
  2879. },
  2880. Detach: function () {
  2881. var script = this.SourceElement(); if (!script) return;
  2882. try {delete script.MathJax} catch(err) {script.MathJax = null}
  2883. if (this.newID) {script.id = ""}
  2884. },
  2885. Clone: function (jax) {
  2886. var id;
  2887. for (id in this) {
  2888. if (!this.hasOwnProperty(id)) continue;
  2889. if (typeof(jax[id]) === 'undefined' && id !== 'newID') {delete this[id]}
  2890. }
  2891. for (id in jax) {
  2892. if (!jax.hasOwnProperty(id)) continue;
  2893. if (typeof(this[id]) === 'undefined' || (this[id] !== jax[id] && id !== 'inputID'))
  2894. {this[id] = jax[id]}
  2895. }
  2896. }
  2897. },{
  2898. id: "ElementJax",
  2899. version: "2.7.5",
  2900. directory: JAX.directory+"/element",
  2901. extensionDir: JAX.extensionDir,
  2902. ID: 0, // jax counter (for IDs)
  2903. STATE: {
  2904. PENDING: 1, // script is identified as math but not yet processed
  2905. PROCESSED: 2, // script has been processed
  2906. UPDATE: 3, // elementJax should be updated
  2907. OUTPUT: 4 // output should be updated (input is OK)
  2908. },
  2909. GetID: function () {this.ID++; return "MathJax-Element-"+this.ID},
  2910. Subclass: function () {
  2911. var obj = JAX.Subclass.apply(this,arguments);
  2912. obj.loadComplete = this.prototype.loadComplete;
  2913. return obj;
  2914. }
  2915. });
  2916. BASE.ElementJax.prototype.STATE = BASE.ElementJax.STATE;
  2917. //
  2918. // Some "Fake" jax used to allow menu access for "Math Processing Error" messages
  2919. //
  2920. BASE.OutputJax.Error = {
  2921. id: "Error", version: "2.7.5", config: {}, errors: 0,
  2922. ContextMenu: function () {return BASE.Extension.MathEvents.Event.ContextMenu.apply(BASE.Extension.MathEvents.Event,arguments)},
  2923. Mousedown: function () {return BASE.Extension.MathEvents.Event.AltContextMenu.apply(BASE.Extension.MathEvents.Event,arguments)},
  2924. getJaxFromMath: function (math) {return (math.nextSibling.MathJax||{}).error},
  2925. Jax: function (text,script) {
  2926. var jax = MathJax.Hub.inputJax[script.type.replace(/ *;(.|\s)*/,"")];
  2927. this.errors++;
  2928. return {
  2929. inputJax: (jax||{id:"Error"}).id, // Use Error InputJax as fallback
  2930. outputJax: "Error",
  2931. inputID: "MathJax-Error-"+this.errors,
  2932. sourceMenuTitle: /*_(MathMenu)*/ ["ErrorMessage","Error Message"],
  2933. sourceMenuFormat: "Error",
  2934. originalText: MathJax.HTML.getScript(script),
  2935. errorText: text
  2936. }
  2937. }
  2938. };
  2939. BASE.InputJax.Error = {
  2940. id: "Error", version: "2.7.5", config: {},
  2941. sourceMenuTitle: /*_(MathMenu)*/ ["Original","Original Form"]
  2942. };
  2943. })("MathJax");
  2944. /**********************************************************/
  2945. (function (BASENAME) {
  2946. var BASE = window[BASENAME];
  2947. if (!BASE) {BASE = window[BASENAME] = {}}
  2948. var HUB = BASE.Hub; var STARTUP = HUB.Startup; var CONFIG = HUB.config;
  2949. var HEAD = document.head || (document.getElementsByTagName("head")[0]);
  2950. if (!HEAD) {HEAD = document.childNodes[0]};
  2951. var scripts = (document.documentElement || document).getElementsByTagName("script");
  2952. if (scripts.length === 0 && HEAD.namespaceURI)
  2953. scripts = document.getElementsByTagNameNS(HEAD.namespaceURI,"script");
  2954. var namePattern = new RegExp("(^|/)"+BASENAME+"\\.js(\\?.*)?$");
  2955. for (var i = scripts.length-1; i >= 0; i--) {
  2956. if ((scripts[i].src||"").match(namePattern)) {
  2957. STARTUP.script = scripts[i].innerHTML;
  2958. if (RegExp.$2) {
  2959. var params = RegExp.$2.substr(1).split(/\&/);
  2960. for (var j = 0, m = params.length; j < m; j++) {
  2961. var KV = params[j].match(/(.*)=(.*)/);
  2962. if (KV) {STARTUP.params[unescape(KV[1])] = unescape(KV[2])}
  2963. else {STARTUP.params[params[j]] = true}
  2964. }
  2965. }
  2966. CONFIG.root = scripts[i].src.replace(/(^|\/)[^\/]*(\?.*)?$/,'');
  2967. BASE.Ajax.config.root = CONFIG.root;
  2968. BASE.Ajax.params = STARTUP.params;
  2969. break;
  2970. }
  2971. }
  2972. var AGENT = navigator.userAgent;
  2973. var BROWSERS = {
  2974. isMac: (navigator.platform.substr(0,3) === "Mac"),
  2975. isPC: (navigator.platform.substr(0,3) === "Win"),
  2976. isMSIE: ("ActiveXObject" in window && "clipboardData" in window),
  2977. isEdge: ("MSGestureEvent" in window && "chrome" in window &&
  2978. window.chrome.loadTimes == null),
  2979. isFirefox: (!!AGENT.match(/Gecko\//) && !AGENT.match(/like Gecko/)),
  2980. isSafari: (!!AGENT.match(/ (Apple)?WebKit\//) && !AGENT.match(/ like iPhone /) &&
  2981. (!window.chrome || window.chrome.app == null)),
  2982. isChrome: ("chrome" in window && window.chrome.loadTimes != null),
  2983. isOpera: ("opera" in window && window.opera.version != null),
  2984. isKonqueror: ("konqueror" in window && navigator.vendor == "KDE"),
  2985. versionAtLeast: function (v) {
  2986. var bv = (this.version).split('.'); v = (new String(v)).split('.');
  2987. for (var i = 0, m = v.length; i < m; i++)
  2988. {if (bv[i] != v[i]) {return parseInt(bv[i]||"0") >= parseInt(v[i])}}
  2989. return true;
  2990. },
  2991. Select: function (choices) {
  2992. var browser = choices[HUB.Browser];
  2993. if (browser) {return browser(HUB.Browser)}
  2994. return null;
  2995. }
  2996. };
  2997. var xAGENT = AGENT
  2998. .replace(/^Mozilla\/(\d+\.)+\d+ /,"") // remove initial Mozilla, which is never right
  2999. .replace(/[a-z][-a-z0-9._: ]+\/\d+[^ ]*-[^ ]*\.([a-z][a-z])?\d+ /i,"") // remove linux version
  3000. .replace(/Gentoo |Ubuntu\/(\d+\.)*\d+ (\([^)]*\) )?/,""); // special case for these
  3001. HUB.Browser = HUB.Insert(HUB.Insert(new String("Unknown"),{version: "0.0"}),BROWSERS);
  3002. for (var browser in BROWSERS) {if (BROWSERS.hasOwnProperty(browser)) {
  3003. if (BROWSERS[browser] && browser.substr(0,2) === "is") {
  3004. browser = browser.slice(2);
  3005. if (browser === "Mac" || browser === "PC") continue;
  3006. HUB.Browser = HUB.Insert(new String(browser),BROWSERS);
  3007. var VERSION = new RegExp(
  3008. ".*(Version/| Trident/.*; rv:)((?:\\d+\\.)+\\d+)|" + // for Safari, Opera10, and IE11+
  3009. ".*("+browser+")"+(browser == "MSIE" ? " " : "/")+"((?:\\d+\\.)*\\d+)|"+ // for one of the main browsers
  3010. "(?:^|\\(| )([a-z][-a-z0-9._: ]+|(?:Apple)?WebKit)/((?:\\d+\\.)+\\d+)"); // for unrecognized browser
  3011. var MATCH = VERSION.exec(xAGENT) || ["","","","unknown","0.0"];
  3012. HUB.Browser.name = (MATCH[1] != "" ? browser : (MATCH[3] || MATCH[5]));
  3013. HUB.Browser.version = MATCH[2] || MATCH[4] || MATCH[6];
  3014. break;
  3015. }
  3016. }};
  3017. //
  3018. // Initial browser-specific info (e.g., touch up version or name, check for MathPlayer, etc.)
  3019. // Wrap in try/catch just in case of error (see issue #1155).
  3020. //
  3021. try {HUB.Browser.Select({
  3022. Safari: function (browser) {
  3023. var v = parseInt((String(browser.version).split("."))[0]);
  3024. if (v > 85) {browser.webkit = browser.version}
  3025. if (v >= 538) {browser.version = "8.0"}
  3026. else if (v >= 537) {browser.version = "7.0"}
  3027. else if (v >= 536) {browser.version = "6.0"}
  3028. else if (v >= 534) {browser.version = "5.1"}
  3029. else if (v >= 533) {browser.version = "5.0"}
  3030. else if (v >= 526) {browser.version = "4.0"}
  3031. else if (v >= 525) {browser.version = "3.1"}
  3032. else if (v > 500) {browser.version = "3.0"}
  3033. else if (v > 400) {browser.version = "2.0"}
  3034. else if (v > 85) {browser.version = "1.0"}
  3035. browser.webkit = (navigator.appVersion.match(/WebKit\/(\d+)\./))[1];
  3036. browser.isMobile = (navigator.appVersion.match(/Mobile/i) != null);
  3037. browser.noContextMenu = browser.isMobile;
  3038. },
  3039. Firefox: function (browser) {
  3040. if ((browser.version === "0.0" || AGENT.match(/Firefox/) == null) &&
  3041. navigator.product === "Gecko") {
  3042. var rv = AGENT.match(/[\/ ]rv:(\d+\.\d.*?)[\) ]/);
  3043. if (rv) {browser.version = rv[1]}
  3044. else {
  3045. var date = (navigator.buildID||navigator.productSub||"0").substr(0,8);
  3046. if (date >= "20111220") {browser.version = "9.0"}
  3047. else if (date >= "20111120") {browser.version = "8.0"}
  3048. else if (date >= "20110927") {browser.version = "7.0"}
  3049. else if (date >= "20110816") {browser.version = "6.0"}
  3050. else if (date >= "20110621") {browser.version = "5.0"}
  3051. else if (date >= "20110320") {browser.version = "4.0"}
  3052. else if (date >= "20100121") {browser.version = "3.6"}
  3053. else if (date >= "20090630") {browser.version = "3.5"}
  3054. else if (date >= "20080617") {browser.version = "3.0"}
  3055. else if (date >= "20061024") {browser.version = "2.0"}
  3056. }
  3057. }
  3058. browser.isMobile = (navigator.appVersion.match(/Android/i) != null ||
  3059. AGENT.match(/ Fennec\//) != null ||
  3060. AGENT.match(/Mobile/) != null);
  3061. },
  3062. Chrome: function (browser) {
  3063. browser.noContextMenu = browser.isMobile = !!navigator.userAgent.match(/ Mobile[ \/]/);
  3064. },
  3065. Opera: function (browser) {browser.version = opera.version()},
  3066. Edge: function (browser) {
  3067. browser.isMobile = !!navigator.userAgent.match(/ Phone/);
  3068. },
  3069. MSIE: function (browser) {
  3070. browser.isMobile = !!navigator.userAgent.match(/ Phone/);
  3071. browser.isIE9 = !!(document.documentMode && (window.performance || window.msPerformance));
  3072. MathJax.HTML.setScriptBug = !browser.isIE9 || document.documentMode < 9;
  3073. MathJax.Hub.msieHTMLCollectionBug = (document.documentMode < 9);
  3074. //
  3075. // MathPlayer doesn't function properly in IE10, and not at all in IE11,
  3076. // so don't even try to load it.
  3077. //
  3078. if (document.documentMode < 10 && !STARTUP.params.NoMathPlayer) {
  3079. try {
  3080. new ActiveXObject("MathPlayer.Factory.1");
  3081. browser.hasMathPlayer = true;
  3082. } catch (err) {}
  3083. try {
  3084. if (browser.hasMathPlayer) {
  3085. var mathplayer = document.createElement("object");
  3086. mathplayer.id = "mathplayer"; mathplayer.classid = "clsid:32F66A20-7614-11D4-BD11-00104BD3F987";
  3087. HEAD.appendChild(mathplayer);
  3088. document.namespaces.add("m","http://www.w3.org/1998/Math/MathML");
  3089. browser.mpNamespace = true;
  3090. if (document.readyState && (document.readyState === "loading" ||
  3091. document.readyState === "interactive")) {
  3092. document.write('<?import namespace="m" implementation="#MathPlayer">');
  3093. browser.mpImported = true;
  3094. }
  3095. } else {
  3096. // Adding any namespace avoids a crash in IE9 in IE9-standards mode
  3097. // (any reference to document.namespaces before document.readyState is
  3098. // "complete" causes an "unspecified error" to be thrown)
  3099. document.namespaces.add("mjx_IE_fix","http://www.w3.org/1999/xlink");
  3100. }
  3101. } catch (err) {}
  3102. }
  3103. }
  3104. });} catch (err) {
  3105. console.error(err.message);
  3106. }
  3107. HUB.Browser.Select(MathJax.Message.browsers);
  3108. if (BASE.AuthorConfig && typeof BASE.AuthorConfig.AuthorInit === "function") {BASE.AuthorConfig.AuthorInit()}
  3109. HUB.queue = BASE.Callback.Queue();
  3110. HUB.queue.Push(
  3111. ["Post",STARTUP.signal,"Begin"],
  3112. ["Config",STARTUP],
  3113. ["Cookie",STARTUP],
  3114. ["Styles",STARTUP],
  3115. ["Message",STARTUP],
  3116. function () {
  3117. // Do Jax and Extensions in parallel, but wait for them all to complete
  3118. var queue = BASE.Callback.Queue(
  3119. STARTUP.Jax(),
  3120. STARTUP.Extensions()
  3121. );
  3122. return queue.Push({});
  3123. },
  3124. ["Menu",STARTUP],
  3125. STARTUP.onLoad(),
  3126. function () {MathJax.isReady = true}, // indicates that MathJax is ready to process math
  3127. ["Typeset",STARTUP],
  3128. ["Hash",STARTUP],
  3129. ["MenuZoom",STARTUP],
  3130. ["Post",STARTUP.signal,"End"]
  3131. );
  3132. })("MathJax");
  3133. }}