12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317 |
- /* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
- /* vim: set ts=2 et sw=2 tw=80: */
- /*************************************************************
- *
- * MathJax.js
- *
- * The main support code for the MathJax Hub, including the
- * Ajax, Callback, Messaging, and Object-Oriented Programming
- * libraries, as well as the base Jax classes, and startup
- * processing code.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (c) 2009-2017 The MathJax Consortium
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- //
- // Check if browser can support MathJax (no one fails this nowadays)
- //
- if (document.getElementById && document.childNodes && document.createElement) {
- //
- // Skip if MathJax is already loaded
- //
- if (!(window.MathJax && MathJax.Hub)) {
- //
- // Get author configuration from MathJax variable, if any
- //
- if (window.MathJax) {window.MathJax = {AuthorConfig: window.MathJax}}
- else {window.MathJax = {}}
- // MathJax.isPacked = true; // This line is uncommented by the packer.
- MathJax.version = "2.7.2";
- MathJax.fileversion = "2.7.2";
- MathJax.cdnVersion = "2.7.2"; // specifies a revision to break caching
- MathJax.cdnFileVersions = {}; // can be used to specify revisions for individual files
- /**********************************************************/
- (function (BASENAME) {
- var BASE = window[BASENAME];
- if (!BASE) {BASE = window[BASENAME] = {}}
- var PROTO = []; // a static object used to indicate when a prototype is being created
- var OBJECT = function (def) {
- var obj = def.constructor; if (!obj) {obj = function () {}}
- for (var id in def) {if (id !== 'constructor' && def.hasOwnProperty(id)) {obj[id] = def[id]}}
- return obj;
- };
- var CONSTRUCTOR = function () {
- return function () {return arguments.callee.Init.call(this,arguments)};
- };
- BASE.Object = OBJECT({
- constructor: CONSTRUCTOR(),
- Subclass: function (def,classdef) {
- var obj = CONSTRUCTOR();
- obj.SUPER = this; obj.Init = this.Init;
- obj.Subclass = this.Subclass; obj.Augment = this.Augment;
- obj.protoFunction = this.protoFunction;
- obj.can = this.can; obj.has = this.has; obj.isa = this.isa;
- obj.prototype = new this(PROTO);
- obj.prototype.constructor = obj; // the real constructor
- obj.Augment(def,classdef);
- return obj;
- },
- Init: function (args) {
- var obj = this;
- if (args.length === 1 && args[0] === PROTO) {return obj}
- if (!(obj instanceof args.callee)) {obj = new args.callee(PROTO)}
- return obj.Init.apply(obj,args) || obj;
- },
- Augment: function (def,classdef) {
- var id;
- if (def != null) {
- for (id in def) {if (def.hasOwnProperty(id)) {this.protoFunction(id,def[id])}}
- // MSIE doesn't list toString even if it is not native so handle it separately
- if (def.toString !== this.prototype.toString && def.toString !== {}.toString)
- {this.protoFunction('toString',def.toString)}
- }
- if (classdef != null) {
- for (id in classdef) {if (classdef.hasOwnProperty(id)) {this[id] = classdef[id]}}
- }
- return this;
- },
- protoFunction: function (id,def) {
- this.prototype[id] = def;
- if (typeof def === "function") {def.SUPER = this.SUPER.prototype}
- },
- prototype: {
- Init: function () {},
- SUPER: function (fn) {return fn.callee.SUPER},
- can: function (method) {return typeof(this[method]) === "function"},
- has: function (property) {return typeof(this[property]) !== "undefined"},
- isa: function (obj) {return (obj instanceof Object) && (this instanceof obj)}
- },
- can: function (method) {return this.prototype.can.call(this,method)},
- has: function (property) {return this.prototype.has.call(this,property)},
- isa: function (obj) {
- var constructor = this;
- while (constructor) {
- if (constructor === obj) {return true} else {constructor = constructor.SUPER}
- }
- return false;
- },
- SimpleSUPER: OBJECT({
- constructor: function (def) {return this.SimpleSUPER.define(def)},
- define: function (src) {
- var dst = {};
- if (src != null) {
- for (var id in src) {if (src.hasOwnProperty(id)) {dst[id] = this.wrap(id,src[id])}}
- // MSIE doesn't list toString even if it is not native so handle it separately
- if (src.toString !== this.prototype.toString && src.toString !== {}.toString)
- {dst.toString = this.wrap('toString',src.toString)}
- }
- return dst;
- },
- wrap: function (id,f) {
- if (typeof(f) !== 'function' || !f.toString().match(/\.\s*SUPER\s*\(/)) {return f}
- var fn = function () {
- this.SUPER = fn.SUPER[id];
- try {var result = f.apply(this,arguments)} catch (err) {delete this.SUPER; throw err}
- delete this.SUPER;
- return result;
- }
- fn.toString = function () {return f.toString.apply(f,arguments)}
- return fn;
- }
- })
- });
- BASE.Object.isArray = Array.isArray || function (obj) {
- return Object.prototype.toString.call(obj) === "[object Array]";
- };
- BASE.Object.Array = Array;
- })("MathJax");
- /**********************************************************/
- /*
- * Create a callback function from various forms of data:
- *
- * MathJax.Callback(fn) -- callback to a function
- *
- * MathJax.Callback([fn]) -- callback to function
- * MathJax.Callback([fn,data...])
- * -- callback to function with given data as arguments
- * MathJax.Callback([object,fn])
- * -- call fn with object as "this"
- * MathJax.Callback([object,fn,data...])
- * -- call fn with object as "this" and data as arguments
- * MathJax.Callback(["method",object])
- * -- call method of object wth object as "this"
- * MathJax.Callback(["method",object,data...])
- * -- as above, but with data as arguments to method
- *
- * MathJax.Callback({hook: fn, data: [...], object: this})
- * -- give function, data, and object to act as "this" explicitly
- *
- * MathJax.Callback("code") -- callback that compiles and executes a string
- *
- * MathJax.Callback([...],i)
- * -- use slice of array starting at i and interpret
- * result as above. (Used for passing "arguments" array
- * and trimming initial arguments, if any.)
- */
- /*
- * MathJax.Callback.After([...],cb1,cb2,...)
- * -- make a callback that isn't called until all the other
- * ones are called first. I.e., wait for a union of
- * callbacks to occur before making the given callback.
- */
- /*
- * MathJax.Callback.Queue([callback,...])
- * -- make a synchronized queue of commands that process
- * sequentially, waiting for those that return uncalled
- * callbacks.
- */
- /*
- * MathJax.Callback.Signal(name)
- * -- finds or creates a names signal, to which listeners
- * can be attached and are signaled by messages posted
- * to the signal. Responses can be asynchronous.
- */
- (function (BASENAME) {
- var BASE = window[BASENAME];
- if (!BASE) {BASE = window[BASENAME] = {}}
- var isArray = BASE.Object.isArray;
- //
- // Create a callback from an associative array
- //
- var CALLBACK = function (data) {
- var cb = function () {return arguments.callee.execute.apply(arguments.callee,arguments)};
- for (var id in CALLBACK.prototype) {
- if (CALLBACK.prototype.hasOwnProperty(id)) {
- if (typeof(data[id]) !== 'undefined') {cb[id] = data[id]}
- else {cb[id] = CALLBACK.prototype[id]}
- }
- }
- cb.toString = CALLBACK.prototype.toString;
- return cb;
- };
- CALLBACK.prototype = {
- isCallback: true,
- hook: function () {},
- data: [],
- object: window,
- execute: function () {
- if (!this.called || this.autoReset) {
- this.called = !this.autoReset;
- return this.hook.apply(this.object,this.data.concat([].slice.call(arguments,0)));
- }
- },
- reset: function () {delete this.called},
- toString: function () {return this.hook.toString.apply(this.hook,arguments)}
- };
- var ISCALLBACK = function (f) {
- return (typeof(f) === "function" && f.isCallback);
- }
- //
- // Evaluate a string in global context
- //
- var EVAL = function (code) {return eval.call(window,code)}
- var TESTEVAL = function () {
- EVAL("var __TeSt_VaR__ = 1"); // check if it works in global context
- if (window.__TeSt_VaR__) {
- try { delete window.__TeSt_VaR__; } // NOTE IE9 throws when in IE7 mode
- catch (error) { window.__TeSt_VaR__ = null; }
- } else {
- if (window.execScript) {
- // IE
- EVAL = function (code) {
- BASE.__code = code;
- code = "try {"+BASENAME+".__result = eval("+BASENAME+".__code)} catch(err) {"+BASENAME+".__result = err}";
- window.execScript(code);
- var result = BASE.__result; delete BASE.__result; delete BASE.__code;
- if (result instanceof Error) {throw result}
- return result;
- }
- } else {
- // Safari2
- EVAL = function (code) {
- BASE.__code = code;
- code = "try {"+BASENAME+".__result = eval("+BASENAME+".__code)} catch(err) {"+BASENAME+".__result = err}";
- var head = (document.getElementsByTagName("head"))[0]; if (!head) {head = document.body}
- var script = document.createElement("script");
- script.appendChild(document.createTextNode(code));
- head.appendChild(script); head.removeChild(script);
- var result = BASE.__result; delete BASE.__result; delete BASE.__code;
- if (result instanceof Error) {throw result}
- return result;
- }
- }
- }
- TESTEVAL = null;
- };
- //
- // Create a callback from various types of data
- //
- var USING = function (args,i) {
- if (arguments.length > 1) {
- if (arguments.length === 2 && !(typeof arguments[0] === 'function') &&
- arguments[0] instanceof Object && typeof arguments[1] === 'number')
- {args = [].slice.call(args,i)}
- else {args = [].slice.call(arguments,0)}
- }
- if (isArray(args) && args.length === 1 && typeof(args[0]) === 'function') {args = args[0]}
- if (typeof args === 'function') {
- if (args.execute === CALLBACK.prototype.execute) {return args}
- return CALLBACK({hook: args});
- } else if (isArray(args)) {
- if (typeof(args[0]) === 'string' && args[1] instanceof Object &&
- typeof args[1][args[0]] === 'function') {
- return CALLBACK({hook: args[1][args[0]], object: args[1], data: args.slice(2)});
- } else if (typeof args[0] === 'function') {
- return CALLBACK({hook: args[0], data: args.slice(1)});
- } else if (typeof args[1] === 'function') {
- return CALLBACK({hook: args[1], object: args[0], data: args.slice(2)});
- }
- } else if (typeof(args) === 'string') {
- if (TESTEVAL) TESTEVAL();
- return CALLBACK({hook: EVAL, data: [args]});
- } else if (args instanceof Object) {
- return CALLBACK(args);
- } else if (typeof(args) === 'undefined') {
- return CALLBACK({});
- }
- throw Error("Can't make callback from given data");
- };
- //
- // Wait for a given time to elapse and then perform the callback
- //
- var DELAY = function (time,callback) {
- callback = USING(callback);
- callback.timeout = setTimeout(callback,time);
- return callback;
- };
- //
- // Callback used by AFTER, QUEUE, and SIGNAL to check if calls have completed
- //
- var WAITFOR = function (callback,signal) {
- callback = USING(callback);
- if (!callback.called) {WAITSIGNAL(callback,signal); signal.pending++}
- };
- var WAITEXECUTE = function () {
- var signals = this.signal; delete this.signal;
- this.execute = this.oldExecute; delete this.oldExecute;
- var result = this.execute.apply(this,arguments);
- if (ISCALLBACK(result) && !result.called) {WAITSIGNAL(result,signals)} else {
- for (var i = 0, m = signals.length; i < m; i++) {
- signals[i].pending--;
- if (signals[i].pending <= 0) {signals[i].call()}
- }
- }
- };
- var WAITSIGNAL = function (callback,signals) {
- if (!isArray(signals)) {signals = [signals]}
- if (!callback.signal) {
- callback.oldExecute = callback.execute;
- callback.execute = WAITEXECUTE;
- callback.signal = signals;
- } else if (signals.length === 1) {callback.signal.push(signals[0])}
- else {callback.signal = callback.signal.concat(signals)}
- };
- //
- // Create a callback that is called when a collection of other callbacks have
- // all been executed. If the callback gets called immediately (i.e., the
- // others are all already called), check if it returns another callback
- // and return that instead.
- //
- var AFTER = function (callback) {
- callback = USING(callback);
- callback.pending = 0;
- for (var i = 1, m = arguments.length; i < m; i++)
- {if (arguments[i]) {WAITFOR(arguments[i],callback)}}
- if (callback.pending === 0) {
- var result = callback();
- if (ISCALLBACK(result)) {callback = result}
- }
- return callback;
- };
- //
- // An array of prioritized hooks that are executed sequentially
- // with a given set of data.
- //
- var HOOKS = MathJax.Object.Subclass({
- //
- // Initialize the array and the auto-reset status
- //
- Init: function (reset) {
- this.hooks = [];
- this.remove = []; // used when hooks are removed during execution of list
- this.reset = reset;
- this.running = false;
- },
- //
- // Add a callback to the list, in priority order (default priority is 10)
- //
- Add: function (hook,priority) {
- if (priority == null) {priority = 10}
- if (!ISCALLBACK(hook)) {hook = USING(hook)}
- hook.priority = priority;
- var i = this.hooks.length;
- while (i > 0 && priority < this.hooks[i-1].priority) {i--}
- this.hooks.splice(i,0,hook);
- return hook;
- },
- Remove: function (hook) {
- for (var i = 0, m = this.hooks.length; i < m; i++) {
- if (this.hooks[i] === hook) {
- if (this.running) {this.remove.push(i)}
- else {this.hooks.splice(i,1)}
- return;
- }
- }
- },
- //
- // Execute the list of callbacks, resetting them if requested.
- // If any return callbacks, return a callback that will be
- // executed when they all have completed.
- // Remove any hooks that requested being removed during processing.
- //
- Execute: function () {
- var callbacks = [{}];
- this.running = true;
- for (var i = 0, m = this.hooks.length; i < m; i++) {
- if (this.reset) {this.hooks[i].reset()}
- var result = this.hooks[i].apply(window,arguments);
- if (ISCALLBACK(result) && !result.called) {callbacks.push(result)}
- }
- this.running = false;
- if (this.remove.length) {this.RemovePending()}
- if (callbacks.length === 1) {return null}
- if (callbacks.length === 2) {return callbacks[1]}
- return AFTER.apply({},callbacks);
- },
- //
- // Remove hooks that asked to be removed during execution of list
- //
- RemovePending: function () {
- this.remove = this.remove.sort();
- for (var i = this.remove.length-1; i >= 0; i--) {this.hooks.splice(i,1)}
- this.remove = [];
- }
- });
- //
- // Run an array of callbacks passing them the given data.
- // (Legacy function, since this has been replaced by the HOOKS object).
- //
- var EXECUTEHOOKS = function (hooks,data,reset) {
- if (!hooks) {return null}
- if (!isArray(hooks)) {hooks = [hooks]}
- if (!isArray(data)) {data = (data == null ? [] : [data])}
- var handler = HOOKS(reset);
- for (var i = 0, m = hooks.length; i < m; i++) {handler.Add(hooks[i])}
- return handler.Execute.apply(handler,data);
- };
- //
- // Command queue that performs commands in order, waiting when
- // necessary for commands to complete asynchronousely
- //
- var QUEUE = BASE.Object.Subclass({
- //
- // Create the queue and push any commands that are specified
- //
- Init: function () {
- this.pending = this.running = 0;
- this.queue = [];
- this.Push.apply(this,arguments);
- },
- //
- // Add commands to the queue and run them. Adding a callback object
- // (rather than a callback specification) queues a wait for that callback.
- // Return the final callback for synchronization purposes.
- //
- Push: function () {
- var callback;
- for (var i = 0, m = arguments.length; i < m; i++) {
- callback = USING(arguments[i]);
- if (callback === arguments[i] && !callback.called)
- {callback = USING(["wait",this,callback])}
- this.queue.push(callback);
- }
- if (!this.running && !this.pending) {this.Process()}
- return callback;
- },
- //
- // Process the command queue if we aren't waiting on another command
- //
- Process: function (queue) {
- while (!this.running && !this.pending && this.queue.length) {
- var callback = this.queue[0];
- queue = this.queue.slice(1); this.queue = [];
- this.Suspend(); var result = callback(); this.Resume();
- if (queue.length) {this.queue = queue.concat(this.queue)}
- if (ISCALLBACK(result) && !result.called) {WAITFOR(result,this)}
- }
- },
- //
- // Suspend/Resume command processing on this queue
- //
- Suspend: function () {this.running++},
- Resume: function () {if (this.running) {this.running--}},
- //
- // Used by WAITFOR to restart the queue when an action completes
- //
- call: function () {this.Process.apply(this,arguments)},
- wait: function (callback) {return callback}
- });
- //
- // Create a named signal that listeners can attach to, to be signaled by
- // postings made to the signal. Posts are queued if they occur while one
- // is already in process.
- //
- var SIGNAL = QUEUE.Subclass({
- Init: function (name) {
- QUEUE.prototype.Init.call(this);
- this.name = name;
- this.posted = []; // the messages posted so far
- this.listeners = HOOKS(true); // those with interest in this signal
- this.posting = false;
- this.callback = null;
- },
- //
- // Post a message to the signal listeners, with callback for when complete
- //
- Post: function (message,callback,forget) {
- callback = USING(callback);
- if (this.posting || this.pending) {
- this.Push(["Post",this,message,callback,forget]);
- } else {
- this.callback = callback; callback.reset();
- if (!forget) {this.posted.push(message)}
- this.Suspend(); this.posting = true;
- var result = this.listeners.Execute(message);
- if (ISCALLBACK(result) && !result.called) {WAITFOR(result,this)}
- this.Resume(); this.posting = false;
- if (!this.pending) {this.call()}
- }
- return callback;
- },
- //
- // Clear the post history (so new listeners won't get old messages)
- //
- Clear: function (callback) {
- callback = USING(callback);
- if (this.posting || this.pending) {
- callback = this.Push(["Clear",this,callback]);
- } else {
- this.posted = [];
- callback();
- }
- return callback;
- },
- //
- // Call the callback (all replies are in) and process the command queue
- //
- call: function () {this.callback(this); this.Process()},
- //
- // A listener calls this to register interest in the signal (so it will be called
- // when posts occur). If ignorePast is true, it will not be sent the post history.
- //
- Interest: function (callback,ignorePast,priority) {
- callback = USING(callback);
- this.listeners.Add(callback,priority);
- if (!ignorePast) {
- for (var i = 0, m = this.posted.length; i < m; i++) {
- callback.reset();
- var result = callback(this.posted[i]);
- if (ISCALLBACK(result) && i === this.posted.length-1) {WAITFOR(result,this)}
- }
- }
- return callback;
- },
- //
- // A listener calls this to remove itself from a signal
- //
- NoInterest: function (callback) {
- this.listeners.Remove(callback);
- },
- //
- // Hook a callback to a particular message on this signal
- //
- MessageHook: function (msg,callback,priority) {
- callback = USING(callback);
- if (!this.hooks) {this.hooks = {}; this.Interest(["ExecuteHooks",this])}
- if (!this.hooks[msg]) {this.hooks[msg] = HOOKS(true)}
- this.hooks[msg].Add(callback,priority);
- for (var i = 0, m = this.posted.length; i < m; i++)
- {if (this.posted[i] == msg) {callback.reset(); callback(this.posted[i])}}
- callback.msg = msg; // keep track so we can remove it
- return callback;
- },
- //
- // Execute the message hooks for the given message
- //
- ExecuteHooks: function (msg) {
- var type = (isArray(msg) ? msg[0] : msg);
- if (!this.hooks[type]) {return null}
- return this.hooks[type].Execute(msg);
- },
- //
- // Remove a hook safely
- //
- RemoveHook: function (hook) {
- this.hooks[hook.msg].Remove(hook);
- }
- },{
- signals: {}, // the named signals
- find: function (name) {
- if (!SIGNAL.signals[name]) {SIGNAL.signals[name] = new SIGNAL(name)}
- return SIGNAL.signals[name];
- }
- });
- //
- // The main entry-points
- //
- BASE.Callback = BASE.CallBack = USING;
- BASE.Callback.Delay = DELAY;
- BASE.Callback.After = AFTER;
- BASE.Callback.Queue = QUEUE;
- BASE.Callback.Signal = SIGNAL.find;
- BASE.Callback.Hooks = HOOKS;
- BASE.Callback.ExecuteHooks = EXECUTEHOOKS;
- })("MathJax");
- /**********************************************************/
- (function (BASENAME) {
- var BASE = window[BASENAME];
- if (!BASE) {BASE = window[BASENAME] = {}}
- var isSafari2 = (navigator.vendor === "Apple Computer, Inc." &&
- typeof navigator.vendorSub === "undefined");
- var sheets = 0; // used by Safari2
- //
- // Update sheets count and look up the head object
- //
- var HEAD = function (head) {
- if (document.styleSheets && document.styleSheets.length > sheets)
- {sheets = document.styleSheets.length}
- if (!head) {
- head = document.head || ((document.getElementsByTagName("head"))[0]);
- if (!head) {head = document.body}
- }
- return head;
- };
- //
- // Remove scripts that are completed so they don't clutter up the HEAD.
- // This runs via setTimeout since IE7 can't remove the script while it is running.
- //
- var SCRIPTS = []; // stores scripts to be removed after a delay
- var REMOVESCRIPTS = function () {
- for (var i = 0, m = SCRIPTS.length; i < m; i++) {BASE.Ajax.head.removeChild(SCRIPTS[i])}
- SCRIPTS = [];
- };
- var PATH = {};
- PATH[BASENAME] = ""; // empty path gets the root URL
- PATH.a11y = '[MathJax]/extensions/a11y'; // a11y extensions
- PATH.Contrib = "https://cdn.mathjax.org/mathjax/contrib"; // the third-party extensions
- BASE.Ajax = {
- loaded: {}, // files already loaded
- loading: {}, // files currently in process of loading
- loadHooks: {}, // hooks to call when files are loaded
- timeout: 15*1000, // timeout for loading of files (15 seconds)
- styleDelay: 1, // delay to use before styles are available
- config: {
- root: "", // URL of root directory to load from
- path: PATH // paths to named URL's (e.g., [MathJax]/...)
- },
- params: {}, // filled in from MathJax.js?...
- STATUS: {
- OK: 1, // file is loading or did load OK
- ERROR: -1 // file timed out during load
- },
- //
- // Return a complete URL to a file (replacing any root names)
- //
- fileURL: function (file) {
- var match;
- while ((match = file.match(/^\[([-._a-z0-9]+)\]/i)) && PATH.hasOwnProperty(match[1])) {
- file = (PATH[match[1]]||this.config.root) + file.substr(match[1].length+2);
- }
- return file;
- },
- //
- // Replace root names if URL includes one
- //
- fileName: function (url) {
- var root = this.config.root;
- if (url.substr(0,root.length) === root) {url = "["+BASENAME+"]"+url.substr(root.length)}
- do {
- var recheck = false;
- for (var id in PATH) {if (PATH.hasOwnProperty(id) && PATH[id]) {
- if (url.substr(0,PATH[id].length) === PATH[id]) {
- url = "["+id+"]"+url.substr(PATH[id].length);
- recheck = true;
- break;
- }
- }}
- } while (recheck);
- return url;
- },
- //
- // Cache-breaking revision number for file
- //
- fileRev: function (file) {
- var V = BASE.cdnFileVersions[file] || BASE.cdnVersion || '';
- if (V) {V = "?V="+V}
- return V;
- },
- urlRev: function (file) {return this.fileURL(file)+this.fileRev(file)},
- //
- // Load a file if it hasn't been already.
- // Make sure the file URL is "safe"?
- //
- Require: function (file,callback) {
- callback = BASE.Callback(callback); var type;
- if (file instanceof Object) {
- for (var i in file)
- {if (file.hasOwnProperty(i)) {type = i.toUpperCase(); file = file[i]}}
- } else {type = file.split(/\./).pop().toUpperCase()}
- if (this.params.noContrib && file.substr(0,9) === "[Contrib]") {
- callback(this.STATUS.ERROR);
- } else {
- file = this.fileURL(file);
- // FIXME: check that URL is OK
- if (this.loaded[file]) {
- callback(this.loaded[file]);
- } else {
- var FILE = {}; FILE[type] = file;
- this.Load(FILE,callback);
- }
- }
- return callback;
- },
- //
- // Load a file regardless of where it is and whether it has
- // already been loaded.
- //
- Load: function (file,callback) {
- callback = BASE.Callback(callback); var type;
- if (file instanceof Object) {
- for (var i in file)
- {if (file.hasOwnProperty(i)) {type = i.toUpperCase(); file = file[i]}}
- } else {type = file.split(/\./).pop().toUpperCase()}
- file = this.fileURL(file);
- if (this.loading[file]) {
- this.addHook(file,callback);
- } else {
- this.head = HEAD(this.head);
- if (this.loader[type]) {this.loader[type].call(this,file,callback)}
- else {throw Error("Can't load files of type "+type)}
- }
- return callback;
- },
- //
- // Register a load hook for a particular file (it will be called when
- // loadComplete() is called for that file)
- //
- LoadHook: function (file,callback,priority) {
- callback = BASE.Callback(callback);
- if (file instanceof Object)
- {for (var i in file) {if (file.hasOwnProperty(i)) {file = file[i]}}}
- file = this.fileURL(file);
- if (this.loaded[file]) {callback(this.loaded[file])}
- else {this.addHook(file,callback,priority)}
- return callback;
- },
- addHook: function (file,callback,priority) {
- if (!this.loadHooks[file]) {this.loadHooks[file] = MathJax.Callback.Hooks()}
- this.loadHooks[file].Add(callback,priority);
- callback.file = file;
- },
- removeHook: function (hook) {
- if (this.loadHooks[hook.file]) {
- this.loadHooks[hook.file].Remove(hook);
- if (!this.loadHooks[hook.file].hooks.length) {delete this.loadHooks[hook.file]}
- }
- },
- //
- // Used when files are combined in a preloading configuration file
- //
- Preloading: function () {
- for (var i = 0, m = arguments.length; i < m; i++) {
- var file = this.fileURL(arguments[i]);
- if (!this.loading[file]) {this.loading[file] = {preloaded: true}}
- }
- },
- //
- // Code used to load the various types of files
- // (JS for JavaScript, CSS for style sheets)
- //
- loader: {
- //
- // Create a SCRIPT tag to load the file
- //
- JS: function (file,callback) {
- var name = this.fileName(file);
- var script = document.createElement("script");
- var timeout = BASE.Callback(["loadTimeout",this,file]);
- this.loading[file] = {
- callback: callback,
- timeout: setTimeout(timeout,this.timeout),
- status: this.STATUS.OK,
- script: script
- };
- //
- // Add this to the structure above after it is created to prevent recursion
- // when loading the initial localization file (before loading messsage is available)
- //
- this.loading[file].message = BASE.Message.File(name);
- script.onerror = timeout; // doesn't work in IE and no apparent substitute
- script.type = "text/javascript";
- script.src = file+this.fileRev(name);
- this.head.appendChild(script);
- },
- //
- // Create a LINK tag to load the style sheet
- //
- CSS: function (file,callback) {
- var name = this.fileName(file);
- var link = document.createElement("link");
- link.rel = "stylesheet"; link.type = "text/css";
- link.href = file+this.fileRev(name);
- this.loading[file] = {
- callback: callback,
- message: BASE.Message.File(name),
- status: this.STATUS.OK
- };
- this.head.appendChild(link);
- this.timer.create.call(this,[this.timer.file,file],link);
- }
- },
- //
- // Timing code for checking when style sheets are available.
- //
- timer: {
- //
- // Create the timing callback and start the timing loop.
- // We use a delay because some browsers need it to allow the styles
- // to be processed.
- //
- create: function (callback,node) {
- callback = BASE.Callback(callback);
- if (node.nodeName === "STYLE" && node.styleSheet &&
- typeof(node.styleSheet.cssText) !== 'undefined') {
- callback(this.STATUS.OK); // MSIE processes style immediately, but doesn't set its styleSheet!
- } else if (window.chrome && node.nodeName === "LINK") {
- callback(this.STATUS.OK); // Chrome doesn't give access to cssRules for stylesheet in
- // a link node, so we can't detect when it is loaded.
- } else if (isSafari2) {
- this.timer.start(this,[this.timer.checkSafari2,sheets++,callback],this.styleDelay);
- } else {
- this.timer.start(this,[this.timer.checkLength,node,callback],this.styleDelay);
- }
- return callback;
- },
- //
- // Start the timer for the given callback checker
- //
- start: function (AJAX,check,delay,timeout) {
- check = BASE.Callback(check);
- check.execute = this.execute; check.time = this.time;
- check.STATUS = AJAX.STATUS; check.timeout = timeout || AJAX.timeout;
- check.delay = check.total = delay || 0;
- if (delay) {setTimeout(check,delay)} else {check()}
- },
- //
- // Increment the time total, increase the delay
- // and test if we are past the timeout time.
- //
- time: function (callback) {
- this.total += this.delay;
- this.delay = Math.floor(this.delay * 1.05 + 5);
- if (this.total >= this.timeout) {callback(this.STATUS.ERROR); return 1}
- return 0;
- },
- //
- // For JS file loads, call the proper routine according to status
- //
- file: function (file,status) {
- if (status < 0) {BASE.Ajax.loadTimeout(file)} else {BASE.Ajax.loadComplete(file)}
- },
- //
- // Call the hook with the required data
- //
- execute: function () {this.hook.call(this.object,this,this.data[0],this.data[1])},
- //
- // Safari2 doesn't set the link's stylesheet, so we need to look in the
- // document.styleSheets array for the new sheet when it is created
- //
- checkSafari2: function (check,length,callback) {
- if (check.time(callback)) return;
- if (document.styleSheets.length > length &&
- document.styleSheets[length].cssRules &&
- document.styleSheets[length].cssRules.length)
- {callback(check.STATUS.OK)} else {setTimeout(check,check.delay)}
- },
- //
- // Look for the stylesheets rules and check when they are defined
- // and no longer of length zero. (This assumes there actually ARE
- // some rules in the stylesheet.)
- //
- checkLength: function (check,node,callback) {
- if (check.time(callback)) return;
- var isStyle = 0; var sheet = (node.sheet || node.styleSheet);
- try {if ((sheet.cssRules||sheet.rules||[]).length > 0) {isStyle = 1}} catch(err) {
- if (err.message.match(/protected variable|restricted URI/)) {isStyle = 1}
- else if (err.message.match(/Security error/)) {
- // Firefox3 gives "Security error" for missing files, so
- // can't distinguish that from OK files on remote servers.
- // or OK files in different directory from local files.
- isStyle = 1; // just say it is OK (can't really tell)
- }
- }
- if (isStyle) {
- // Opera 9.6 requires this setTimeout
- setTimeout(BASE.Callback([callback,check.STATUS.OK]),0);
- } else {
- setTimeout(check,check.delay);
- }
- }
- },
- //
- // JavaScript code must call this when they are completely initialized
- // (this allows them to perform asynchronous actions before indicating
- // that they are complete).
- //
- loadComplete: function (file) {
- file = this.fileURL(file);
- var loading = this.loading[file];
- if (loading && !loading.preloaded) {
- BASE.Message.Clear(loading.message);
- clearTimeout(loading.timeout);
- if (loading.script) {
- if (SCRIPTS.length === 0) {setTimeout(REMOVESCRIPTS,0)}
- SCRIPTS.push(loading.script);
- }
- this.loaded[file] = loading.status; delete this.loading[file];
- this.addHook(file,loading.callback);
- } else {
- if (loading) {delete this.loading[file]}
- this.loaded[file] = this.STATUS.OK;
- loading = {status: this.STATUS.OK}
- }
- if (!this.loadHooks[file]) {return null}
- return this.loadHooks[file].Execute(loading.status);
- },
- //
- // If a file fails to load within the timeout period (or the onerror handler
- // is called), this routine runs to signal the error condition.
- //
- loadTimeout: function (file) {
- if (this.loading[file].timeout) {clearTimeout(this.loading[file].timeout)}
- this.loading[file].status = this.STATUS.ERROR;
- this.loadError(file);
- this.loadComplete(file);
- },
- //
- // The default error hook for file load failures
- //
- loadError: function (file) {
- BASE.Message.Set(["LoadFailed","File failed to load: %1",file],null,2000);
- BASE.Hub.signal.Post(["file load error",file]);
- },
- //
- // Defines a style sheet from a hash of style declarations (key:value pairs
- // where the key is the style selector and the value is a hash of CSS attributes
- // and values).
- //
- Styles: function (styles,callback) {
- var styleString = this.StyleString(styles);
- if (styleString === "") {
- callback = BASE.Callback(callback);
- callback();
- } else {
- var style = document.createElement("style"); style.type = "text/css";
- this.head = HEAD(this.head);
- this.head.appendChild(style);
- if (style.styleSheet && typeof(style.styleSheet.cssText) !== 'undefined') {
- style.styleSheet.cssText = styleString;
- } else {
- style.appendChild(document.createTextNode(styleString));
- }
- callback = this.timer.create.call(this,callback,style);
- }
- return callback;
- },
- //
- // Create a stylesheet string from a style declaration object
- //
- StyleString: function (styles) {
- if (typeof(styles) === 'string') {return styles}
- var string = "", id, style;
- for (id in styles) {if (styles.hasOwnProperty(id)) {
- if (typeof styles[id] === 'string') {
- string += id + " {"+styles[id]+"}\n";
- } else if (BASE.Object.isArray(styles[id])) {
- for (var i = 0; i < styles[id].length; i++) {
- style = {}; style[id] = styles[id][i];
- string += this.StyleString(style);
- }
- } else if (id.substr(0,6) === '@media') {
- string += id + " {"+this.StyleString(styles[id])+"}\n";
- } else if (styles[id] != null) {
- style = [];
- for (var name in styles[id]) {if (styles[id].hasOwnProperty(name)) {
- if (styles[id][name] != null)
- {style[style.length] = name + ': ' + styles[id][name]}
- }}
- string += id +" {"+style.join('; ')+"}\n";
- }
- }}
- return string;
- }
- };
- })("MathJax");
- /**********************************************************/
- MathJax.HTML = {
- //
- // Create an HTML element with given attributes and content.
- // The def parameter is an (optional) object containing key:value pairs
- // of the attributes and their values, and contents is an (optional)
- // array of strings to be inserted as text, or arrays of the form
- // [type,def,contents] that describes an HTML element to be inserted
- // into the current element. Thus the contents can describe a complete
- // HTML snippet of arbitrary complexity. E.g.:
- //
- // MathJax.HTML.Element("span",{id:"mySpan",style{"font-style":"italic"}},[
- // "(See the ",["a",{href:"http://www.mathjax.org"},["MathJax home page"]],
- // " for more details.)"]);
- //
- Element: function (type,def,contents) {
- var obj = document.createElement(type), id;
- if (def) {
- if (def.hasOwnProperty("style")) {
- var style = def.style; def.style = {};
- for (id in style) {if (style.hasOwnProperty(id))
- {def.style[id.replace(/-([a-z])/g,this.ucMatch)] = style[id]}}
- }
- MathJax.Hub.Insert(obj,def);
- for (id in def) {
- if (id === "role" || id.substr(0,5) === "aria-") obj.setAttribute(id,def[id]);
- }
- }
- if (contents) {
- if (!MathJax.Object.isArray(contents)) {contents = [contents]}
- for (var i = 0, m = contents.length; i < m; i++) {
- if (MathJax.Object.isArray(contents[i])) {
- obj.appendChild(this.Element(contents[i][0],contents[i][1],contents[i][2]));
- } else if (type === "script") { // IE throws an error if script is added as a text node
- this.setScript(obj, contents[i]);
- } else {
- obj.appendChild(document.createTextNode(contents[i]));
- }
- }
- }
- return obj;
- },
- ucMatch: function (match,c) {return c.toUpperCase()},
- addElement: function (span,type,def,contents) {return span.appendChild(this.Element(type,def,contents))},
- TextNode: function (text) {return document.createTextNode(text)},
- addText: function (span,text) {return span.appendChild(this.TextNode(text))},
- //
- // Set and get the text of a script
- //
- setScript: function (script,text) {
- if (this.setScriptBug) {script.text = text} else {
- while (script.firstChild) {script.removeChild(script.firstChild)}
- this.addText(script,text);
- }
- },
- getScript: function (script) {
- var text = (script.text === "" ? script.innerHTML : script.text);
- return text.replace(/^\s+/,"").replace(/\s+$/,"");
- },
- //
- // Manage cookies
- //
- Cookie: {
- prefix: "mjx",
- expires: 365,
- //
- // Save an object as a named cookie
- //
- Set: function (name,def) {
- var keys = [];
- if (def) {
- for (var id in def) {if (def.hasOwnProperty(id)) {
- keys.push(id+":"+def[id].toString().replace(/&/g,"&&"));
- }}
- }
- var cookie = this.prefix+"."+name+"="+escape(keys.join('&;'));
- if (this.expires) {
- var time = new Date(); time.setDate(time.getDate() + this.expires);
- cookie += '; expires='+time.toGMTString();
- }
- try {document.cookie = cookie+"; path=/"} catch (err) {} // ignore errors saving cookies
- },
- //
- // Get the contents of a named cookie and incorporate
- // it into the given object (or return a fresh one)
- //
- Get: function (name,obj) {
- if (!obj) {obj = {}}
- var pattern = new RegExp("(?:^|;\\s*)"+this.prefix+"\\."+name+"=([^;]*)(?:;|$)");
- var match;
- try {match = pattern.exec(document.cookie)} catch (err) {}; // ignore errors reading cookies
- if (match && match[1] !== "") {
- var keys = unescape(match[1]).split('&;');
- for (var i = 0, m = keys.length; i < m; i++) {
- match = keys[i].match(/([^:]+):(.*)/);
- var value = match[2].replace(/&&/g,'&');
- if (value === "true") {value = true} else if (value === "false") {value = false}
- else if (value.match(/^-?(\d+(\.\d+)?|\.\d+)$/)) {value = parseFloat(value)}
- obj[match[1]] = value;
- }
- }
- return obj;
- }
- }
- };
- /**********************************************************/
- MathJax.Localization = {
- locale: "en",
- directory: "[MathJax]/localization",
- strings: {
- // Currently, this list is not modified by the MathJax-i18n script. You can
- // run the following command in MathJax/unpacked/localization to update it:
- //
- // find . -name "*.js" | xargs grep menuTitle\: | grep -v qqq | sed 's/^\.\/\(.*\)\/.*\.js\: / "\1"\: \{/' | sed 's/,$/\},/' | sed 's/"English"/"English", isLoaded: true/' > tmp ; sort tmp > tmp2 ; sed '$ s/,$//' tmp2 ; rm tmp*
- //
- // This only takes languages with localization data so you must also add
- // the languages that use a remap but are not translated at all.
- //
- "ar": {menuTitle: "\u0627\u0644\u0639\u0631\u0628\u064A\u0629"},
- "ast": {menuTitle: "asturianu"},
- "bg": {menuTitle: "\u0431\u044A\u043B\u0433\u0430\u0440\u0441\u043A\u0438"},
- "bcc": {menuTitle: "\u0628\u0644\u0648\u0686\u06CC"},
- "br": {menuTitle: "brezhoneg"},
- "ca": {menuTitle: "catal\u00E0"},
- "cdo": {menuTitle: "M\u00ECng-d\u0115\u0324ng-ng\u1E73\u0304"},
- "cs": {menuTitle: "\u010De\u0161tina"},
- "da": {menuTitle: "dansk"},
- "de": {menuTitle: "Deutsch"},
- "diq": {menuTitle: "Zazaki"},
- "en": {menuTitle: "English", isLoaded: true},
- "eo": {menuTitle: "Esperanto"},
- "es": {menuTitle: "espa\u00F1ol"},
- "fa": {menuTitle: "\u0641\u0627\u0631\u0633\u06CC"},
- "fi": {menuTitle: "suomi"},
- "fr": {menuTitle: "fran\u00E7ais"},
- "gl": {menuTitle: "galego"},
- "he": {menuTitle: "\u05E2\u05D1\u05E8\u05D9\u05EA"},
- "ia": {menuTitle: "interlingua"},
- "it": {menuTitle: "italiano"},
- "ja": {menuTitle: "\u65E5\u672C\u8A9E"},
- "kn": {menuTitle: "\u0C95\u0CA8\u0CCD\u0CA8\u0CA1"},
- "ko": {menuTitle: "\uD55C\uAD6D\uC5B4"},
- "lb": {menuTitle: "L\u00EBtzebuergesch"},
- "lki": {menuTitle: "\u0644\u06D5\u06A9\u06CC"},
- "lt": {menuTitle: "lietuvi\u0173"},
- "mk": {menuTitle: "\u043C\u0430\u043A\u0435\u0434\u043E\u043D\u0441\u043A\u0438"},
- "nl": {menuTitle: "Nederlands"},
- "oc": {menuTitle: "occitan"},
- "pl": {menuTitle: "polski"},
- "pt": {menuTitle: "portugu\u00EAs"},
- "pt-br": {menuTitle: "portugu\u00EAs do Brasil"},
- "ru": {menuTitle: "\u0440\u0443\u0441\u0441\u043A\u0438\u0439"},
- "sco": {menuTitle: "Scots"},
- "scn": {menuTitle: "sicilianu"},
- "sk": {menuTitle: "sloven\u010Dina"},
- "sl": {menuTitle: "sloven\u0161\u010Dina"},
- "sv": {menuTitle: "svenska"},
- "th": {menuTitle: "\u0E44\u0E17\u0E22"},
- "tr": {menuTitle: "T\u00FCrk\u00E7e"},
- "uk": {menuTitle: "\u0443\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u0430"},
- "vi": {menuTitle: "Ti\u1EBFng Vi\u1EC7t"},
- "zh-hans": {menuTitle: "\u4E2D\u6587\uFF08\u7B80\u4F53\uFF09"},
- "zh-hant": {menuTitle: "\u6C49\u8BED"}
- },
- //
- // The pattern for substitution escapes:
- // %n or %{n} or %{plural:%n|option1|option1|...} or %c
- //
- pattern: /%(\d+|\{\d+\}|\{[a-z]+:\%\d+(?:\|(?:%\{\d+\}|%.|[^\}])*)+\}|.)/g,
- SPLIT: ("axb".split(/(x)/).length === 3 ?
- function (string,regex) {return string.split(regex)} :
- //
- // IE8 and below don't do split() correctly when the pattern includes
- // parentheses (the split should include the matched exrepssions).
- // So implement it by hand here.
- //
- function (string,regex) {
- var result = [], match, last = 0;
- regex.lastIndex = 0;
- while ((match = regex.exec(string))) {
- result.push(string.substr(last,match.index-last));
- result.push.apply(result,match.slice(1));
- last = match.index + match[0].length;
- }
- result.push(string.substr(last));
- return result;
- }),
- _: function (id,phrase) {
- if (MathJax.Object.isArray(phrase)) {return this.processSnippet(id,phrase)}
- return this.processString(this.lookupPhrase(id,phrase),[].slice.call(arguments,2));
- },
- processString: function (string,args,domain) {
- //
- // Process arguments for substitution
- // If the argument is a snippet (and we are processing snippets) do so,
- // Otherwise, if it is a number, convert it for the lacale
- //
- var i, m, isArray = MathJax.Object.isArray;
- for (i = 0, m = args.length; i < m; i++) {
- if (domain && isArray(args[i])) {args[i] = this.processSnippet(domain,args[i])}
- }
- //
- // Split string at escapes and process them individually
- //
- var parts = this.SPLIT(string,this.pattern);
- for (i = 1, m = parts.length; i < m; i += 2) {
- var c = parts[i].charAt(0); // first char will be { or \d or a char to be kept literally
- if (c >= "0" && c <= "9") { // %n
- parts[i] = args[parts[i]-1];
- if (typeof parts[i] === "number") parts[i] = this.number(parts[i]);
- } else if (c === "{") { // %{n} or %{plural:%n|...}
- c = parts[i].substr(1);
- if (c >= "0" && c <= "9") { // %{n}
- parts[i] = args[parts[i].substr(1,parts[i].length-2)-1];
- if (typeof parts[i] === "number") parts[i] = this.number(parts[i]);
- } else { // %{plural:%n|...}
- var match = parts[i].match(/^\{([a-z]+):%(\d+)\|(.*)\}$/);
- if (match) {
- if (match[1] === "plural") {
- var n = args[match[2]-1];
- if (typeof n === "undefined") {
- parts[i] = "???"; // argument doesn't exist
- } else {
- n = this.plural(n) - 1; // index of the form to use
- var plurals = match[3].replace(/(^|[^%])(%%)*%\|/g,"$1$2%\uEFEF").split(/\|/); // the parts (replacing %| with a special character)
- if (n >= 0 && n < plurals.length) {
- parts[i] = this.processString(plurals[n].replace(/\uEFEF/g,"|"),args,domain);
- } else {
- parts[i] = "???"; // no string for this index
- }
- }
- } else {parts[i] = "%"+parts[i]} // not "plural", put back the % and leave unchanged
- }
- }
- }
- if (parts[i] == null) {parts[i] = "???"}
- }
- //
- // If we are not forming a snippet, return the completed string
- //
- if (!domain) {return parts.join("")}
- //
- // We need to return an HTML snippet, so buld it from the
- // broken up string with inserted parts (that could be snippets)
- //
- var snippet = [], part = "";
- for (i = 0; i < m; i++) {
- part += parts[i]; i++; // add the string and move on to substitution result
- if (i < m) {
- if (isArray(parts[i])) { // substitution was a snippet
- snippet.push(part); // add the accumulated string
- snippet = snippet.concat(parts[i]); // concatenate the substution snippet
- part = ""; // start accumulating a new string
- } else { // substitution was a string
- part += parts[i]; // add to accumulating string
- }
- }
- }
- if (part !== "") {snippet.push(part)} // add final string
- return snippet;
- },
- processSnippet: function (domain,snippet) {
- var result = []; // the new snippet
- //
- // Look through the original snippet for
- // strings or snippets to translate
- //
- for (var i = 0, m = snippet.length; i < m; i++) {
- if (MathJax.Object.isArray(snippet[i])) {
- //
- // This could be a sub-snippet:
- // ["tag"] or ["tag",{properties}] or ["tag",{properties},snippet]
- // Or it could be something to translate:
- // [id,string,args] or [domain,snippet]
- var data = snippet[i];
- if (typeof data[1] === "string") { // [id,string,args]
- var id = data[0]; if (!MathJax.Object.isArray(id)) {id = [domain,id]}
- var phrase = this.lookupPhrase(id,data[1]);
- result = result.concat(this.processMarkdown(phrase,data.slice(2),domain));
- } else if (MathJax.Object.isArray(data[1])) { // [domain,snippet]
- result = result.concat(this.processSnippet.apply(this,data));
- } else if (data.length >= 3) { // ["tag",{properties},snippet]
- result.push([data[0],data[1],this.processSnippet(domain,data[2])]);
- } else { // ["tag"] or ["tag",{properties}]
- result.push(snippet[i]);
- }
- } else { // a string
- result.push(snippet[i]);
- }
- }
- return result;
- },
- markdownPattern: /(%.)|(\*{1,3})((?:%.|.)+?)\2|(`+)((?:%.|.)+?)\4|\[((?:%.|.)+?)\]\(([^\s\)]+)\)/,
- // %c or *bold*, **italics**, ***bold-italics***, or `code`, or [link](url)
- processMarkdown: function (phrase,args,domain) {
- var result = [], data;
- //
- // Split the string by the Markdown pattern
- // (the text blocks are separated by
- // c,stars,star-text,backtics,code-text,link-text,URL).
- // Start with teh first text string from the split.
- //
- var parts = phrase.split(this.markdownPattern);
- var string = parts[0];
- //
- // Loop through the matches and process them
- //
- for (var i = 1, m = parts.length; i < m; i += 8) {
- if (parts[i+1]) { // stars (for bold/italic)
- //
- // Select the tag to use by number of stars (three stars requires two tags)
- //
- data = this.processString(parts[i+2],args,domain);
- if (!MathJax.Object.isArray(data)) {data = [data]}
- data = [["b","i","i"][parts[i+1].length-1],{},data]; // number of stars determines type
- if (parts[i+1].length === 3) {data = ["b",{},data]} // bold-italic
- } else if (parts[i+3]) { // backtics (for code)
- //
- // Remove one leading or trailing space, and process substitutions
- // Make a <code> tag
- //
- data = this.processString(parts[i+4].replace(/^\s/,"").replace(/\s$/,""),args,domain);
- if (!MathJax.Object.isArray(data)) {data = [data]}
- data = ["code",{},data];
- } else if (parts[i+5]) { // hyperlink
- //
- // Process the link text, and make an <a> tag with the URL
- //
- data = this.processString(parts[i+5],args,domain);
- if (!MathJax.Object.isArray(data)) {data = [data]}
- data = ["a",{href:this.processString(parts[i+6],args),target:"_blank"},data];
- } else {
- //
- // Escaped character (%c) gets added into the string.
- //
- string += parts[i]; data = null;
- }
- //
- // If there is a tag to insert,
- // Add any pending string, then push the tag
- //
- if (data) {
- result = this.concatString(result,string,args,domain);
- result.push(data); string = "";
- }
- //
- // Process the string that follows matches pattern
- //
- if (parts[i+7] !== "") {string += parts[i+7]}
- };
- //
- // Add any pending string and return the resulting snippet
- //
- result = this.concatString(result,string,args,domain);
- return result;
- },
- concatString: function (result,string,args,domain) {
- if (string != "") {
- //
- // Process the substutions.
- // If the result is not a snippet, turn it into one.
- // Then concatenate the snippet to the current one
- //
- string = this.processString(string,args,domain);
- if (!MathJax.Object.isArray(string)) {string = [string]}
- result = result.concat(string);
- }
- return result;
- },
- lookupPhrase: function (id,phrase,domain) {
- //
- // Get the domain and messageID
- //
- if (!domain) {domain = "_"}
- if (MathJax.Object.isArray(id)) {domain = (id[0] || "_"); id = (id[1] || "")}
- //
- // Check if the data is available and if not,
- // load it and throw a restart error so the calling
- // code can wait for the load and try again.
- //
- var load = this.loadDomain(domain);
- if (load) {MathJax.Hub.RestartAfter(load)}
- //
- // Look up the message in the localization data
- // (if not found, the original English is used)
- //
- var localeData = this.strings[this.locale];
- if (localeData) {
- if (localeData.domains && domain in localeData.domains) {
- var domainData = localeData.domains[domain];
- if (domainData.strings && id in domainData.strings)
- {phrase = domainData.strings[id]}
- }
- }
- //
- // return the translated phrase
- //
- return phrase;
- },
- //
- // Load a langauge data file from the proper
- // directory and file.
- //
- loadFile: function (file,data,callback) {
- callback = MathJax.Callback(callback);
- file = (data.file || file); // the data's file name or the default name
- if (!file.match(/\.js$/)) {file += ".js"} // add .js if needed
- //
- // Add the directory if the file doesn't
- // contain a full URL already.
- //
- if (!file.match(/^([a-z]+:|\[MathJax\])/)) {
- var dir = (this.strings[this.locale].directory ||
- this.directory + "/" + this.locale ||
- "[MathJax]/localization/" + this.locale);
- file = dir + "/" + file;
- }
- //
- // Load the file and mark the data as loaded (even if it
- // failed to load, so we don't continue to try to load it
- // over and over).
- //
- var load = MathJax.Ajax.Require(file,function () {data.isLoaded = true; return callback()});
- //
- // Return the callback if needed, otherwise null.
- //
- return (load.called ? null : load);
- },
- //
- // Check to see if the localization data are loaded
- // for the given domain; if not, load the data file,
- // and return a callback for the loading operation.
- // Otherwise return null (data are loaded).
- //
- loadDomain: function (domain,callback) {
- var load, localeData = this.strings[this.locale];
- if (localeData) {
- if (!localeData.isLoaded) {
- load = this.loadFile(this.locale,localeData);
- if (load) {
- return MathJax.Callback.Queue(
- load,["loadDomain",this,domain] // call again to load domain
- ).Push(callback||{});
- }
- }
- if (localeData.domains && domain in localeData.domains) {
- var domainData = localeData.domains[domain];
- if (!domainData.isLoaded) {
- load = this.loadFile(domain,domainData);
- if (load) {return MathJax.Callback.Queue(load).Push(callback)}
- }
- }
- }
- // localization data are loaded, so just do the callback
- return MathJax.Callback(callback)();
- },
- //
- // Perform a function, properly handling
- // restarts due to localization file loads.
- //
- // Note that this may return before the function
- // has been called successfully, so you should
- // consider fn as running asynchronously. (Callbacks
- // can be used to synchronize it with other actions.)
- //
- Try: function (fn) {
- fn = MathJax.Callback(fn); fn.autoReset = true;
- try {fn()} catch (err) {
- if (!err.restart) {throw err}
- MathJax.Callback.After(["Try",this,fn],err.restart);
- }
- },
- //
- // Reset the current language
- //
- resetLocale: function(locale) {
- // Selection algorithm:
- // 1) Downcase locale name (e.g. "en-US" => "en-us")
- // 2) Try a parent language (e.g. "en-us" => "en")
- // 3) Try the fallback specified in the data (e.g. "pt" => "pt-br")
- // 4) Otherwise don't change the locale.
- if (!locale) return;
- locale = locale.toLowerCase();
- while (!this.strings[locale]) {
- var dashPos = locale.lastIndexOf("-");
- if (dashPos === -1) return;
- locale = locale.substring(0, dashPos);
- }
- var remap = this.strings[locale].remap;
- this.locale = remap ? remap : locale;
- },
- //
- // Set the current language
- //
- setLocale: function(locale) {
- this.resetLocale(locale);
- if (MathJax.Menu) {this.loadDomain("MathMenu")}
- },
- //
- // Add or update a language or domain
- //
- addTranslation: function (locale,domain,definition) {
- var data = this.strings[locale], isNew = false;
- if (!data) {data = this.strings[locale] = {}; isNew = true}
- if (!data.domains) {data.domains = {}}
- if (domain) {
- if (!data.domains[domain]) {data.domains[domain] = {}}
- data = data.domains[domain];
- }
- MathJax.Hub.Insert(data,definition);
- if (isNew && MathJax.Menu.menu) {MathJax.Menu.CreateLocaleMenu()}
- },
- //
- // Set CSS for an element based on font requirements
- //
- setCSS: function (div) {
- var locale = this.strings[this.locale];
- if (locale) {
- if (locale.fontFamily) {div.style.fontFamily = locale.fontFamily}
- if (locale.fontDirection) {
- div.style.direction = locale.fontDirection;
- if (locale.fontDirection === "rtl") {div.style.textAlign = "right"}
- }
- }
- return div;
- },
- //
- // Get the language's font family or direction
- //
- fontFamily: function () {
- var locale = this.strings[this.locale];
- return (locale ? locale.fontFamily : null);
- },
- fontDirection: function () {
- var locale = this.strings[this.locale];
- return (locale ? locale.fontDirection : null);
- },
- //
- // Get the language's plural index for a number
- //
- plural: function (n) {
- var locale = this.strings[this.locale];
- if (locale && locale.plural) {return locale.plural(n)}
- // default
- if (n == 1) {return 1} // one
- return 2; // other
- },
- //
- // Convert a number to language-specific form
- //
- number: function(n) {
- var locale = this.strings[this.locale];
- if (locale && locale.number) {return locale.number(n)}
- // default
- return n;
- }
- };
- /**********************************************************/
- MathJax.Message = {
- ready: false, // used to tell when the styles are available
- log: [{}], current: null,
- textNodeBug: (navigator.vendor === "Apple Computer, Inc." &&
- typeof navigator.vendorSub === "undefined") ||
- (window.hasOwnProperty && window.hasOwnProperty("konqueror")), // Konqueror displays some gibberish with text.nodeValue = "..."
- styles: {
- "#MathJax_Message": {
- position: "fixed", left: "1px", bottom: "2px",
- 'background-color': "#E6E6E6", border: "1px solid #959595",
- margin: "0px", padding: "2px 8px",
- 'z-index': "102", color: "black", 'font-size': "80%",
- width: "auto", 'white-space': "nowrap"
- },
- "#MathJax_MSIE_Frame": {
- position: "absolute",
- top:0, left: 0, width: "0px", 'z-index': 101,
- border: "0px", margin: "0px", padding: "0px"
- }
- },
- browsers: {
- MSIE: function (browser) {
- MathJax.Message.msieFixedPositionBug = ((document.documentMode||0) < 7);
- if (MathJax.Message.msieFixedPositionBug)
- {MathJax.Hub.config.styles["#MathJax_Message"].position = "absolute"}
- MathJax.Message.quirks = (document.compatMode === "BackCompat");
- },
- Chrome: function (browser) {
- MathJax.Hub.config.styles["#MathJax_Message"].bottom = "1.5em";
- MathJax.Hub.config.styles["#MathJax_Message"].left = "1em";
- }
- },
- Init: function (styles) {
- if (styles) {this.ready = true}
- if (!document.body || !this.ready) {return false}
- //
- // ASCIIMathML replaces the entire page with a copy of itself (@#!#%@!!)
- // so check that this.div is still part of the page, otherwise look up
- // the copy and use that.
- //
- if (this.div && this.div.parentNode == null) {
- this.div = document.getElementById("MathJax_Message");
- if (this.div) {this.text = this.div.firstChild}
- }
- if (!this.div) {
- var frame = document.body;
- if (this.msieFixedPositionBug && window.attachEvent) {
- frame = this.frame = this.addDiv(document.body); frame.removeAttribute("id");
- frame.style.position = "absolute";
- frame.style.border = frame.style.margin = frame.style.padding = "0px";
- frame.style.zIndex = "101"; frame.style.height = "0px";
- frame = this.addDiv(frame);
- frame.id = "MathJax_MSIE_Frame";
- window.attachEvent("onscroll",this.MoveFrame);
- window.attachEvent("onresize",this.MoveFrame);
- this.MoveFrame();
- }
- this.div = this.addDiv(frame); this.div.style.display = "none";
- this.text = this.div.appendChild(document.createTextNode(""));
- }
- return true;
- },
- addDiv: function (parent) {
- var div = document.createElement("div");
- div.id = "MathJax_Message";
- if (parent.firstChild) {parent.insertBefore(div,parent.firstChild)}
- else {parent.appendChild(div)}
- return div;
- },
- MoveFrame: function () {
- var body = (MathJax.Message.quirks ? document.body : document.documentElement);
- var frame = MathJax.Message.frame;
- frame.style.left = body.scrollLeft + 'px';
- frame.style.top = body.scrollTop + 'px';
- frame.style.width = body.clientWidth + 'px';
- frame = frame.firstChild;
- frame.style.height = body.clientHeight + 'px';
- },
- localize: function (message) {
- return MathJax.Localization._(message,message);
- },
- filterText: function (text,n,id) {
- if (MathJax.Hub.config.messageStyle === "simple") {
- if (id === "LoadFile") {
- if (!this.loading) {this.loading = this.localize("Loading") + " "}
- text = this.loading; this.loading += ".";
- } else if (id === "ProcessMath") {
- if (!this.processing) {this.processing = this.localize("Processing") + " "}
- text = this.processing; this.processing += ".";
- } else if (id === "TypesetMath") {
- if (!this.typesetting) {this.typesetting = this.localize("Typesetting") + " "}
- text = this.typesetting; this.typesetting += ".";
- }
- }
- return text;
- },
- clearCounts: function () {
- delete this.loading;
- delete this.processing;
- delete this.typesetting;
- },
- Set: function (text,n,clearDelay) {
- if (n == null) {n = this.log.length; this.log[n] = {}}
- //
- // Translate message if it is [id,message,arguments]
- //
- var id = "";
- if (MathJax.Object.isArray(text)) {
- id = text[0]; if (MathJax.Object.isArray(id)) {id = id[1]}
- //
- // Localization._() will throw a restart error if a localization file
- // needs to be loaded, so trap that and redo the Set() call
- // after it is loaded.
- //
- try {
- text = MathJax.Localization._.apply(MathJax.Localization,text);
- } catch (err) {
- if (!err.restart) {throw err}
- if (!err.restart.called) {
- //
- // Mark it so we can tell if the Clear() comes before the message is displayed
- //
- if (this.log[n].restarted == null) {this.log[n].restarted = 0}
- this.log[n].restarted++; delete this.log[n].cleared;
- MathJax.Callback.After(["Set",this,text,n,clearDelay],err.restart);
- return n;
- }
- }
- }
- //
- // Clear the timout timer.
- //
- if (this.timer) {clearTimeout(this.timer); delete this.timer}
- //
- // Save the message and filtered message.
- //
- this.log[n].text = text; this.log[n].filteredText = text = this.filterText(text,n,id);
- //
- // Hook the message into the message list so we can tell
- // what message to put up when this one is removed.
- //
- if (typeof(this.log[n].next) === "undefined") {
- this.log[n].next = this.current;
- if (this.current != null) {this.log[this.current].prev = n}
- this.current = n;
- }
- //
- // Show the message if it is the currently active one.
- //
- if (this.current === n && MathJax.Hub.config.messageStyle !== "none") {
- if (this.Init()) {
- if (this.textNodeBug) {this.div.innerHTML = text} else {this.text.nodeValue = text}
- this.div.style.display = "";
- if (this.status) {window.status = ""; delete this.status}
- } else {
- window.status = text;
- this.status = true;
- }
- }
- //
- // Check if the message was resetarted to load a localization file
- // and if it has been cleared in the meanwhile.
- //
- if (this.log[n].restarted) {
- if (this.log[n].cleared) {clearDelay = 0}
- if (--this.log[n].restarted === 0) {delete this.log[n].cleared}
- }
- //
- // Check if we need to clear the message automatically.
- //
- if (clearDelay) {setTimeout(MathJax.Callback(["Clear",this,n]),clearDelay)}
- else if (clearDelay == 0) {this.Clear(n,0)}
- //
- // Return the message number.
- //
- return n;
- },
- Clear: function (n,delay) {
- //
- // Detatch the message from the active list.
- //
- if (this.log[n].prev != null) {this.log[this.log[n].prev].next = this.log[n].next}
- if (this.log[n].next != null) {this.log[this.log[n].next].prev = this.log[n].prev}
- //
- // If it is the current message, get the next one to show.
- //
- if (this.current === n) {
- this.current = this.log[n].next;
- if (this.text) {
- if (this.div.parentNode == null) {this.Init()} // see ASCIIMathML comments above
- if (this.current == null) {
- //
- // If there are no more messages, remove the message box.
- //
- if (this.timer) {clearTimeout(this.timer); delete this.timer}
- if (delay == null) {delay = 600}
- if (delay === 0) {this.Remove()}
- else {this.timer = setTimeout(MathJax.Callback(["Remove",this]),delay)}
- } else if (MathJax.Hub.config.messageStyle !== "none") {
- //
- // If there is an old message, put it in place
- //
- if (this.textNodeBug) {this.div.innerHTML = this.log[this.current].filteredText}
- else {this.text.nodeValue = this.log[this.current].filteredText}
- }
- if (this.status) {window.status = ""; delete this.status}
- } else if (this.status) {
- window.status = (this.current == null ? "" : this.log[this.current].text);
- }
- }
- //
- // Clean up the log data no longer needed
- //
- delete this.log[n].next; delete this.log[n].prev;
- delete this.log[n].filteredText;
- //
- // If this is a restarted localization message, mark that it has been cleared
- // while waiting for the file to load.
- //
- if (this.log[n].restarted) {this.log[n].cleared = true}
- },
- Remove: function () {
- // FIXME: do a fade out or something else interesting?
- this.text.nodeValue = "";
- this.div.style.display = "none";
- },
- File: function (file) {
- return this.Set(["LoadFile","Loading %1",file],null,null);
- },
- Log: function () {
- var strings = [];
- for (var i = 1, m = this.log.length; i < m; i++) {strings[i] = this.log[i].text}
- return strings.join("\n");
- }
- };
- /**********************************************************/
- MathJax.Hub = {
- config: {
- root: "",
- config: [], // list of configuration files to load
- styleSheets: [], // list of CSS files to load
- styles: { // styles to generate in-line
- ".MathJax_Preview": {color: "#888"}
- },
- jax: [], // list of input and output jax to load
- extensions: [], // list of extensions to load
- preJax: null, // pattern to remove from before math script tag
- postJax: null, // pattern to remove from after math script tag
- displayAlign: 'center', // how to align displayed equations (left, center, right)
- displayIndent: '0', // indentation for displayed equations (when not centered)
- preRemoveClass: 'MathJax_Preview', // class of objects to remove preceeding math script
- showProcessingMessages: true, // display "Processing math: nn%" messages or not
- messageStyle: "normal", // set to "none" or "simple" (for "Loading..." and "Processing...")
- delayStartupUntil: "none", // set to "onload" to delay setup until the onload handler runs
- // set to "configured" to delay startup until MathJax.Hub.Configured() is called
- // set to a Callback to wait for before continuing with the startup
- skipStartupTypeset: false, // set to true to skip PreProcess and Process during startup
- elements: [], // array of elements to process when none is given explicitly
- positionToHash: true, // after initial typeset pass, position to #hash location?
- showMathMenu: true, // attach math context menu to typeset math?
- showMathMenuMSIE: true, // separtely determine if MSIE should have math menu
- // (since the code for that is a bit delicate)
- menuSettings: {
- zoom: "None", // when to do MathZoom
- CTRL: false, // require CTRL for MathZoom?
- ALT: false, // require Alt or Option?
- CMD: false, // require CMD?
- Shift: false, // require Shift?
- discoverable: false, // make math menu discoverable on hover?
- zscale: "200%", // the scaling factor for MathZoom
- renderer: null, // set when Jax are loaded
- font: "Auto", // what font HTML-CSS should use
- context: "MathJax", // or "Browser" for pass-through to browser menu
- locale: null, // the language to use for messages
- mpContext: false, // true means pass menu events to MathPlayer in IE
- mpMouse: false, // true means pass mouse events to MathPlayer in IE
- texHints: true, // include class names for TeXAtom elements
- FastPreview: null, // use PreviewHTML output as preview?
- assistiveMML: null, // include hidden MathML for screen readers?
- inTabOrder: true, // set to false if math elements should be included in the tabindex
- semantics: false // add semantics tag with original form in MathML output
- },
- errorSettings: {
- // localized HTML snippet structure for message to use
- message: ["[",["MathProcessingError","Math Processing Error"],"]"],
- style: {color: "#CC0000", "font-style":"italic"} // style for message
- },
- ignoreMMLattributes: {} // attributes not to copy to HTML-CSS or SVG output
- // from MathML input (in addition to the ones in MML.nocopyAttributes).
- // An id set to true will be ignored, one set to false will
- // be allowed (even if other criteria normally would prevent
- // it from being copied); use false carefully!
- },
- preProcessors: MathJax.Callback.Hooks(true), // list of callbacks for preprocessing (initialized by extensions)
- inputJax: {}, // mime-type mapped to input jax (by registration)
- outputJax: {order:{}}, // mime-type mapped to output jax list (by registration)
- processSectionDelay: 50, // pause between input and output phases of processing
- processUpdateTime: 250, // time between screen updates when processing math (milliseconds)
- processUpdateDelay: 10, // pause between screen updates to allow other processing (milliseconds)
- signal: MathJax.Callback.Signal("Hub"), // Signal used for Hub events
- Config: function (def) {
- this.Insert(this.config,def);
- if (this.config.Augment) {this.Augment(this.config.Augment)}
- },
- CombineConfig: function (name,def) {
- var config = this.config, id, parent; name = name.split(/\./);
- for (var i = 0, m = name.length; i < m; i++) {
- id = name[i]; if (!config[id]) {config[id] = {}}
- parent = config; config = config[id];
- }
- parent[id] = config = this.Insert(def,config);
- return config;
- },
- Register: {
- PreProcessor: function () {return MathJax.Hub.preProcessors.Add.apply(MathJax.Hub.preProcessors,arguments)},
- MessageHook: function () {return MathJax.Hub.signal.MessageHook.apply(MathJax.Hub.signal,arguments)},
- StartupHook: function () {return MathJax.Hub.Startup.signal.MessageHook.apply(MathJax.Hub.Startup.signal,arguments)},
- LoadHook: function () {return MathJax.Ajax.LoadHook.apply(MathJax.Ajax,arguments)}
- },
- UnRegister: {
- PreProcessor: function (hook) {MathJax.Hub.preProcessors.Remove(hook)},
- MessageHook: function (hook) {MathJax.Hub.signal.RemoveHook(hook)},
- StartupHook: function (hook) {MathJax.Hub.Startup.signal.RemoveHook(hook)},
- LoadHook: function (hook) {MathJax.Ajax.removeHook(hook)}
- },
- getAllJax: function (element) {
- var jax = [], scripts = this.elementScripts(element);
- for (var i = 0, m = scripts.length; i < m; i++) {
- if (scripts[i].MathJax && scripts[i].MathJax.elementJax)
- {jax.push(scripts[i].MathJax.elementJax)}
- }
- return jax;
- },
- getJaxByType: function (type,element) {
- var jax = [], scripts = this.elementScripts(element);
- for (var i = 0, m = scripts.length; i < m; i++) {
- if (scripts[i].MathJax && scripts[i].MathJax.elementJax &&
- scripts[i].MathJax.elementJax.mimeType === type)
- {jax.push(scripts[i].MathJax.elementJax)}
- }
- return jax;
- },
- getJaxByInputType: function (type,element) {
- var jax = [], scripts = this.elementScripts(element);
- for (var i = 0, m = scripts.length; i < m; i++) {
- if (scripts[i].MathJax && scripts[i].MathJax.elementJax &&
- scripts[i].type && scripts[i].type.replace(/ *;(.|\s)*/,"") === type)
- {jax.push(scripts[i].MathJax.elementJax)}
- }
- return jax;
- },
- getJaxFor: function (element) {
- if (typeof(element) === 'string') {element = document.getElementById(element)}
- if (element && element.MathJax) {return element.MathJax.elementJax}
- if (this.isMathJaxNode(element)) {
- if (!element.isMathJax) {element = element.firstChild} // for NativeMML output
- while (element && !element.jaxID) {element = element.parentNode}
- if (element) {return MathJax.OutputJax[element.jaxID].getJaxFromMath(element)}
- }
- return null;
- },
- isJax: function (element) {
- if (typeof(element) === 'string') {element = document.getElementById(element)}
- if (this.isMathJaxNode(element)) {return 1}
- if (element && (element.tagName||"").toLowerCase() === 'script') {
- if (element.MathJax)
- {return (element.MathJax.state === MathJax.ElementJax.STATE.PROCESSED ? 1 : -1)}
- if (element.type && this.inputJax[element.type.replace(/ *;(.|\s)*/,"")]) {return -1}
- }
- return 0;
- },
- isMathJaxNode: function (element) {
- return !!element && (element.isMathJax || (element.className||"") === "MathJax_MathML");
- },
- setRenderer: function (renderer,type) {
- if (!renderer) return;
- if (!MathJax.OutputJax[renderer]) {
- this.config.menuSettings.renderer = "";
- var file = "[MathJax]/jax/output/"+renderer+"/config.js";
- return MathJax.Ajax.Require(file,["setRenderer",this,renderer,type]);
- } else {
- this.config.menuSettings.renderer = renderer;
- if (type == null) {type = "jax/mml"}
- var jax = this.outputJax;
- if (jax[type] && jax[type].length) {
- if (renderer !== jax[type][0].id) {
- jax[type].unshift(MathJax.OutputJax[renderer]);
- return this.signal.Post(["Renderer Selected",renderer]);
- }
- }
- return null;
- }
- },
- Queue: function () {
- return this.queue.Push.apply(this.queue,arguments);
- },
- Typeset: function (element,callback) {
- if (!MathJax.isReady) return null;
- var ec = this.elementCallback(element,callback);
- if (ec.count) {
- var queue = MathJax.Callback.Queue(
- ["PreProcess",this,ec.elements],
- ["Process",this,ec.elements]
- );
- }
- return queue.Push(ec.callback);
- },
- PreProcess: function (element,callback) {
- var ec = this.elementCallback(element,callback);
- var queue = MathJax.Callback.Queue();
- if (ec.count) {
- var elements = (ec.count === 1 ? [ec.elements] : ec.elements);
- queue.Push(["Post",this.signal,["Begin PreProcess",ec.elements]]);
- for (var i = 0, m = elements.length; i < m; i++) {
- if (elements[i]) {queue.Push(["Execute",this.preProcessors,elements[i]])}
- }
- queue.Push(["Post",this.signal,["End PreProcess",ec.elements]]);
- }
- return queue.Push(ec.callback);
- },
- Process: function (element,callback) {return this.takeAction("Process",element,callback)},
- Update: function (element,callback) {return this.takeAction("Update",element,callback)},
- Reprocess: function (element,callback) {return this.takeAction("Reprocess",element,callback)},
- Rerender: function (element,callback) {return this.takeAction("Rerender",element,callback)},
- takeAction: function (action,element,callback) {
- var ec = this.elementCallback(element,callback);
- var elements = ec.elements;
- var queue = MathJax.Callback.Queue(["Clear",this.signal]);
- var state = {
- scripts: [], // filled in by prepareScripts
- start: new Date().getTime(), // timer for processing messages
- i: 0, j: 0, // current script, current jax
- jax: {}, // scripts grouped by output jax
- jaxIDs: [] // id's of jax used
- };
- if (ec.count) {
- var delay = ["Delay",MathJax.Callback,this.processSectionDelay];
- if (!delay[2]) {delay = {}}
- queue.Push(
- ["clearCounts",MathJax.Message],
- ["Post",this.signal,["Begin "+action,elements]],
- ["Post",this.signal,["Begin Math",elements,action]],
- ["prepareScripts",this,action,elements,state],
- ["Post",this.signal,["Begin Math Input",elements,action]],
- ["processInput",this,state],
- ["Post",this.signal,["End Math Input",elements,action]],
- delay,
- ["prepareOutput",this,state,"preProcess"],
- delay,
- ["Post",this.signal,["Begin Math Output",elements,action]],
- ["processOutput",this,state],
- ["Post",this.signal,["End Math Output",elements,action]],
- delay,
- ["prepareOutput",this,state,"postProcess"],
- delay,
- ["Post",this.signal,["End Math",elements,action]],
- ["Post",this.signal,["End "+action,elements]],
- ["clearCounts",MathJax.Message]
- );
- }
- return queue.Push(ec.callback);
- },
- scriptAction: {
- Process: function (script) {},
- Update: function (script) {
- var jax = script.MathJax.elementJax;
- if (jax && jax.needsUpdate()) {jax.Remove(true); script.MathJax.state = jax.STATE.UPDATE}
- else {script.MathJax.state = jax.STATE.PROCESSED}
- },
- Reprocess: function (script) {
- var jax = script.MathJax.elementJax;
- if (jax) {jax.Remove(true); script.MathJax.state = jax.STATE.UPDATE}
- },
- Rerender: function (script) {
- var jax = script.MathJax.elementJax;
- if (jax) {jax.Remove(true); script.MathJax.state = jax.STATE.OUTPUT}
- }
- },
- prepareScripts: function (action,element,state) {
- if (arguments.callee.disabled) return;
- var scripts = this.elementScripts(element);
- var STATE = MathJax.ElementJax.STATE;
- for (var i = 0, m = scripts.length; i < m; i++) {
- var script = scripts[i];
- if (script.type && this.inputJax[script.type.replace(/ *;(.|\n)*/,"")]) {
- if (script.MathJax) {
- if (script.MathJax.elementJax && script.MathJax.elementJax.hover) {
- MathJax.Extension.MathEvents.Hover.ClearHover(script.MathJax.elementJax);
- }
- if (script.MathJax.state !== STATE.PENDING) {this.scriptAction[action](script)}
- }
- if (!script.MathJax) {script.MathJax = {state: STATE.PENDING}}
- if (script.MathJax.error) delete script.MathJax.error;
- if (script.MathJax.state !== STATE.PROCESSED) {state.scripts.push(script)}
- }
- }
- },
- checkScriptSiblings: function (script) {
- if (script.MathJax.checked) return;
- var config = this.config, pre = script.previousSibling;
- if (pre && pre.nodeName === "#text") {
- var preJax,postJax, post = script.nextSibling;
- if (post && post.nodeName !== "#text") {post = null}
- if (config.preJax) {
- if (typeof(config.preJax) === "string") {config.preJax = new RegExp(config.preJax+"$")}
- preJax = pre.nodeValue.match(config.preJax);
- }
- if (config.postJax && post) {
- if (typeof(config.postJax) === "string") {config.postJax = new RegExp("^"+config.postJax)}
- postJax = post.nodeValue.match(config.postJax);
- }
- if (preJax && (!config.postJax || postJax)) {
- pre.nodeValue = pre.nodeValue.replace
- (config.preJax,(preJax.length > 1? preJax[1] : ""));
- pre = null;
- }
- if (postJax && (!config.preJax || preJax)) {
- post.nodeValue = post.nodeValue.replace
- (config.postJax,(postJax.length > 1? postJax[1] : ""));
- }
- if (pre && !pre.nodeValue.match(/\S/)) {pre = pre.previousSibling}
- }
- if (config.preRemoveClass && pre && pre.className === config.preRemoveClass)
- {script.MathJax.preview = pre}
- script.MathJax.checked = 1;
- },
- processInput: function (state) {
- var jax, STATE = MathJax.ElementJax.STATE;
- var script, prev, m = state.scripts.length;
- try {
- //
- // Loop through the scripts
- //
- while (state.i < m) {
- script = state.scripts[state.i]; if (!script) {state.i++; continue}
- //
- // Remove previous error marker, if any
- //
- prev = script.previousSibling;
- if (prev && prev.className === "MathJax_Error") {prev.parentNode.removeChild(prev)}
- //
- // Check if already processed or needs processing
- //
- if (!script.parentNode || !script.MathJax || script.MathJax.state === STATE.PROCESSED) {state.i++; continue};
- if (!script.MathJax.elementJax || script.MathJax.state === STATE.UPDATE) {
- this.checkScriptSiblings(script); // remove preJax/postJax etc.
- var type = script.type.replace(/ *;(.|\s)*/,""); // the input jax type
- var input = this.inputJax[type]; // the input jax itself
- jax = input.Process(script,state); // run the input jax
- if (typeof jax === 'function') { // if a callback was returned
- if (jax.called) continue; // go back and call Process() again
- this.RestartAfter(jax); // wait for the callback
- }
- jax = jax.Attach(script,input.id); // register the jax on the script
- this.saveScript(jax,state,script,STATE); // add script to state
- this.postInputHooks.Execute(jax,input.id,script); // run global jax filters
- } else if (script.MathJax.state === STATE.OUTPUT) {
- this.saveScript(script.MathJax.elementJax,state,script,STATE); // add script to state
- }
- //
- // Go on to the next script, and check if we need to update the processing message
- //
- state.i++; var now = new Date().getTime();
- if (now - state.start > this.processUpdateTime && state.i < state.scripts.length)
- {state.start = now; this.RestartAfter(MathJax.Callback.Delay(1))}
- }
- } catch (err) {return this.processError(err,state,"Input")}
- //
- // Put up final message, reset the state and return
- //
- if (state.scripts.length && this.config.showProcessingMessages)
- {MathJax.Message.Set(["ProcessMath","Processing math: %1%%",100],0)}
- state.start = new Date().getTime(); state.i = state.j = 0;
- return null;
- },
- postInputHooks: MathJax.Callback.Hooks(true), // hooks to run after element jax is created
- saveScript: function (jax,state,script,STATE) {
- //
- // Check that output jax exists
- //
- if (!this.outputJax[jax.mimeType]) {
- script.MathJax.state = STATE.UPDATE;
- throw Error("No output jax registered for "+jax.mimeType);
- }
- //
- // Record the output jax
- // and put this script in the queue for that jax
- //
- jax.outputJax = this.outputJax[jax.mimeType][0].id;
- if (!state.jax[jax.outputJax]) {
- if (state.jaxIDs.length === 0) {
- // use original array until we know there are more (rather than two copies)
- state.jax[jax.outputJax] = state.scripts;
- } else {
- if (state.jaxIDs.length === 1) // get the script so far for the existing jax
- {state.jax[state.jaxIDs[0]] = state.scripts.slice(0,state.i)}
- state.jax[jax.outputJax] = []; // start a new array for the new jax
- }
- state.jaxIDs.push(jax.outputJax); // save the ID of the jax
- }
- if (state.jaxIDs.length > 1) {state.jax[jax.outputJax].push(script)}
- //
- // Mark script as needing output
- //
- script.MathJax.state = STATE.OUTPUT;
- },
- //
- // Pre- and post-process scripts by jax
- // (to get scaling factors, hide/show output, and so on)
- // Since this can cause the jax to load, we need to trap restarts
- //
- prepareOutput: function (state,method) {
- while (state.j < state.jaxIDs.length) {
- var id = state.jaxIDs[state.j], JAX = MathJax.OutputJax[id];
- if (JAX[method]) {
- try {
- var result = JAX[method](state);
- if (typeof result === 'function') {
- if (result.called) continue; // go back and try again
- this.RestartAfter(result);
- }
- } catch (err) {
- if (!err.restart) {
- MathJax.Message.Set(["PrepError","Error preparing %1 output (%2)",id,method],null,600);
- MathJax.Hub.lastPrepError = err;
- state.j++;
- }
- return MathJax.Callback.After(["prepareOutput",this,state,method],err.restart);
- }
- }
- state.j++;
- }
- return null;
- },
- processOutput: function (state) {
- var result, STATE = MathJax.ElementJax.STATE, script, m = state.scripts.length;
- try {
- //
- // Loop through the scripts
- //
- while (state.i < m) {
- //
- // Check that there is an element jax
- //
- script = state.scripts[state.i];
- if (!script || !script.parentNode || !script.MathJax || script.MathJax.error) {state.i++; continue}
- var jax = script.MathJax.elementJax; if (!jax) {state.i++; continue}
- //
- // Call the output Jax's Process method (which will be its Translate()
- // method once loaded). Mark it as complete and remove the preview unless
- // the Process() call returns an explicit false value (in which case, it will
- // handle this later during the postProcess phase, as HTML-CSS does).
- //
- result = MathJax.OutputJax[jax.outputJax].Process(script,state);
- if (result !== false) {
- script.MathJax.state = STATE.PROCESSED;
- if (script.MathJax.preview) {
- script.MathJax.preview.innerHTML = "";
- script.MathJax.preview.style.display = "none";
- }
- //
- // Signal that new math is available
- //
- this.signal.Post(["New Math",jax.inputID]); // FIXME: wait for this? (i.e., restart if returns uncalled callback)
- }
- //
- // Go on to next math expression
- //
- state.i++;
- //
- // Update the processing message, if needed
- //
- var now = new Date().getTime();
- if (now - state.start > this.processUpdateTime && state.i < state.scripts.length)
- {state.start = now; this.RestartAfter(MathJax.Callback.Delay(this.processUpdateDelay))}
- }
- } catch (err) {return this.processError(err,state,"Output")}
- //
- // Put up the typesetting-complete message
- //
- if (state.scripts.length && this.config.showProcessingMessages) {
- MathJax.Message.Set(["TypesetMath","Typesetting math: %1%%",100],0);
- MathJax.Message.Clear(0);
- }
- state.i = state.j = 0;
- return null;
- },
- processMessage: function (state,type) {
- var m = Math.floor(state.i/(state.scripts.length)*100);
- var message = (type === "Output" ? ["TypesetMath","Typesetting math: %1%%"] :
- ["ProcessMath","Processing math: %1%%"]);
- if (this.config.showProcessingMessages) {MathJax.Message.Set(message.concat(m),0)}
- },
- processError: function (err,state,type) {
- if (!err.restart) {
- if (!this.config.errorSettings.message) {throw err}
- this.formatError(state.scripts[state.i],err); state.i++;
- }
- this.processMessage(state,type);
- return MathJax.Callback.After(["process"+type,this,state],err.restart);
- },
- formatError: function (script,err) {
- var LOCALIZE = function (id,text,arg1,arg2) {return MathJax.Localization._(id,text,arg1,arg2)};
- //
- // Get the error message, URL, and line, and save it for
- // reporting in the Show Math As Error menu
- //
- var message = LOCALIZE("ErrorMessage","Error: %1",err.message)+"\n";
- if (err.sourceURL||err.fileName) message += "\n"+LOCALIZE("ErrorFile","file: %1",err.sourceURL||err.fileName);
- if (err.line||err.lineNumber) message += "\n"+LOCALIZE("ErrorLine","line: %1",err.line||err.lineNumber);
- message += "\n\n"+LOCALIZE("ErrorTips","Debugging tips: use %1, inspect %2 in the browser console","'unpacked/MathJax.js'","'MathJax.Hub.lastError'");
- script.MathJax.error = MathJax.OutputJax.Error.Jax(message,script);
- if (script.MathJax.elementJax)
- script.MathJax.error.inputID = script.MathJax.elementJax.inputID;
- //
- // Create the [Math Processing Error] span
- //
- var errorSettings = this.config.errorSettings;
- var errorText = LOCALIZE(errorSettings.messageId,errorSettings.message);
- var error = MathJax.HTML.Element("span", {
- className:"MathJax_Error", jaxID:"Error", isMathJax:true,
- id: script.MathJax.error.inputID+"-Frame"
- },[["span",null,errorText]]);
- //
- // Attach the menu events
- //
- MathJax.Ajax.Require("[MathJax]/extensions/MathEvents.js",function () {
- var EVENT = MathJax.Extension.MathEvents.Event,
- HUB = MathJax.Hub;
- error.oncontextmenu = EVENT.Menu;
- error.onmousedown = EVENT.Mousedown;
- error.onkeydown = EVENT.Keydown;
- error.tabIndex = HUB.getTabOrder(HUB.getJaxFor(script));
- });
- //
- // Insert the error into the page and remove any preview
- //
- var node = document.getElementById(error.id);
- if (node) node.parentNode.removeChild(node);
- if (script.parentNode) script.parentNode.insertBefore(error,script);
- if (script.MathJax.preview) {
- script.MathJax.preview.innerHTML = "";
- script.MathJax.preview.style.display = "none";
- }
- //
- // Save the error for debugging purposes
- // Report the error as a signal
- //
- this.lastError = err;
- this.signal.Post(["Math Processing Error",script,err]);
- },
- RestartAfter: function (callback) {
- throw this.Insert(Error("restart"),{restart: MathJax.Callback(callback)});
- },
- elementCallback: function (element,callback) {
- if (callback == null && (MathJax.Object.isArray(element) || typeof element === 'function'))
- {try {MathJax.Callback(element); callback = element; element = null} catch(e) {}}
- if (element == null) {element = this.config.elements || []}
- if (this.isHTMLCollection(element)) {element = this.HTMLCollection2Array(element)}
- if (!MathJax.Object.isArray(element)) {element = [element]}
- element = [].concat(element); // make a copy so the original isn't changed
- for (var i = 0, m = element.length; i < m; i++)
- {if (typeof(element[i]) === 'string') {element[i] = document.getElementById(element[i])}}
- if (!document.body) {document.body = document.getElementsByTagName("body")[0]}
- if (element.length == 0) {element.push(document.body)}
- if (!callback) {callback = {}}
- return {
- count: element.length,
- elements: (element.length === 1 ? element[0] : element),
- callback: callback
- };
- },
- elementScripts: function (element) {
- var scripts = [];
- if (MathJax.Object.isArray(element) || this.isHTMLCollection(element)) {
- for (var i = 0, m = element.length; i < m; i++) {
- var alreadyDone = 0;
- for (var j = 0; j < i && !alreadyDone; j++)
- {alreadyDone = element[j].contains(element[i])}
- if (!alreadyDone) scripts.push.apply(scripts,this.elementScripts(element[i]));
- }
- return scripts;
- }
- if (typeof(element) === 'string') {element = document.getElementById(element)}
- if (!document.body) {document.body = document.getElementsByTagName("body")[0]}
- if (element == null) {element = document.body}
- if (element.tagName != null && element.tagName.toLowerCase() === "script") {return [element]}
- scripts = element.getElementsByTagName("script");
- if (this.msieHTMLCollectionBug) {scripts = this.HTMLCollection2Array(scripts)}
- return scripts;
- },
- //
- // IE8 fails to check "obj instanceof HTMLCollection" for some values of obj.
- //
- isHTMLCollection: function (obj) {
- return ("HTMLCollection" in window && typeof(obj) === "object" && obj instanceof HTMLCollection);
- },
- //
- // IE8 doesn't deal with HTMLCollection as an array, so convert to array
- //
- HTMLCollection2Array: function (nodes) {
- if (!this.msieHTMLCollectionBug) {return [].slice.call(nodes)}
- var NODES = [];
- for (var i = 0, m = nodes.length; i < m; i++) {NODES[i] = nodes[i]}
- return NODES;
- },
- Insert: function (dst,src) {
- for (var id in src) {if (src.hasOwnProperty(id)) {
- // allow for concatenation of arrays?
- if (typeof src[id] === 'object' && !(MathJax.Object.isArray(src[id])) &&
- (typeof dst[id] === 'object' || typeof dst[id] === 'function')) {
- this.Insert(dst[id],src[id]);
- } else {
- dst[id] = src[id];
- }
- }}
- return dst;
- },
- getTabOrder: function(script) {
- return this.config.menuSettings.inTabOrder ? 0 : -1;
- },
- // Old browsers (e.g. Internet Explorer <= 8) do not support trim().
- SplitList: ("trim" in String.prototype ?
- function (list) {return list.trim().split(/\s+/)} :
- function (list) {return list.replace(/^\s+/,'').
- replace(/\s+$/,'').split(/\s+/)})
- };
- MathJax.Hub.Insert(MathJax.Hub.config.styles,MathJax.Message.styles);
- MathJax.Hub.Insert(MathJax.Hub.config.styles,{".MathJax_Error":MathJax.Hub.config.errorSettings.style});
- //
- // Storage area for extensions and preprocessors
- //
- MathJax.Extension = {};
- //
- // Hub Startup code
- //
- MathJax.Hub.Configured = MathJax.Callback({}); // called when configuration is complete
- MathJax.Hub.Startup = {
- script: "", // the startup script from the SCRIPT call that loads MathJax.js
- queue: MathJax.Callback.Queue(), // Queue used for startup actions
- signal: MathJax.Callback.Signal("Startup"), // Signal used for startup events
- params: {},
- //
- // Load the configuration files
- //
- Config: function () {
- this.queue.Push(["Post",this.signal,"Begin Config"]);
- //
- // Make sure root is set before loading any files
- //
- if (MathJax.AuthorConfig && MathJax.AuthorConfig.root)
- MathJax.Ajax.config.root = MathJax.AuthorConfig.root;
- //
- // If a locale is given as a parameter,
- // set the locale and the default menu value for the locale
- //
- if (this.params.locale) {
- MathJax.Localization.resetLocale(this.params.locale);
- MathJax.Hub.config.menuSettings.locale = this.params.locale;
- }
- //
- // Run the config files, if any are given in the parameter list
- //
- if (this.params.config) {
- var files = this.params.config.split(/,/);
- for (var i = 0, m = files.length; i < m; i++) {
- if (!files[i].match(/\.js$/)) {files[i] += ".js"}
- this.queue.Push(["Require",MathJax.Ajax,this.URL("config",files[i])]);
- }
- }
- //
- // Perform author configuration from in-line MathJax = {...}
- //
- this.queue.Push(["Config",MathJax.Hub,MathJax.AuthorConfig]);
- //
- // Run the deprecated configuration script, if any (ignoring return value)
- // Wait for the startup delay signal
- // Run the mathjax-config blocks
- // Load the files in the configuration's config array
- //
- if (this.script.match(/\S/)) {this.queue.Push(this.script+";\n1;")}
- this.queue.Push(
- ["ConfigDelay",this],
- ["ConfigBlocks",this],
- [function (THIS) {return THIS.loadArray(MathJax.Hub.config.config,"config",null,true)},this],
- ["Post",this.signal,"End Config"]
- );
- },
- //
- // Return the delay callback
- //
- ConfigDelay: function () {
- var delay = this.params.delayStartupUntil || MathJax.Hub.config.delayStartupUntil;
- if (delay === "onload") {return this.onload}
- if (delay === "configured") {return MathJax.Hub.Configured}
- return delay;
- },
- //
- // Run the scripts of type=text/x-mathjax-config
- //
- ConfigBlocks: function () {
- var scripts = document.getElementsByTagName("script");
- var queue = MathJax.Callback.Queue();
- for (var i = 0, m = scripts.length; i < m; i++) {
- var type = String(scripts[i].type).replace(/ /g,"");
- if (type.match(/^text\/x-mathjax-config(;.*)?$/) && !type.match(/;executed=true/)) {
- scripts[i].type += ";executed=true";
- queue.Push(scripts[i].innerHTML+";\n1;");
- }
- }
- return queue.Push(function () {MathJax.Ajax.config.root = MathJax.Hub.config.root});
- },
- //
- // Read cookie and set up menu defaults
- // (set the locale according to the cookie)
- // (adjust the jax to accommodate renderer preferences)
- //
- Cookie: function () {
- return this.queue.Push(
- ["Post",this.signal,"Begin Cookie"],
- ["Get",MathJax.HTML.Cookie,"menu",MathJax.Hub.config.menuSettings],
- [function (config) {
- var SETTINGS = config.menuSettings;
- if (SETTINGS.locale) MathJax.Localization.resetLocale(SETTINGS.locale);
- var renderer = config.menuSettings.renderer, jax = config.jax;
- if (renderer) {
- var name = "output/"+renderer; jax.sort();
- for (var i = 0, m = jax.length; i < m; i++) {
- if (jax[i].substr(0,7) === "output/") break;
- }
- if (i == m-1) {jax.pop()} else {
- while (i < m) {if (jax[i] === name) {jax.splice(i,1); break}; i++}
- }
- jax.unshift(name);
- }
- if (SETTINGS.CHTMLpreview != null) {
- if (SETTINGS.FastPreview == null) SETTINGS.FastPreview = SETTINGS.CHTMLpreview;
- delete SETTINGS.CHTMLpreview;
- }
- if (SETTINGS.FastPreview && !MathJax.Extension["fast-preview"])
- MathJax.Hub.config.extensions.push("fast-preview.js");
- if (config.menuSettings.assistiveMML && !MathJax.Extension.AssistiveMML)
- MathJax.Hub.config.extensions.push("AssistiveMML.js");
- },MathJax.Hub.config],
- ["Post",this.signal,"End Cookie"]
- );
- },
- //
- // Setup stylesheets and extra styles
- //
- Styles: function () {
- return this.queue.Push(
- ["Post",this.signal,"Begin Styles"],
- ["loadArray",this,MathJax.Hub.config.styleSheets,"config"],
- ["Styles",MathJax.Ajax,MathJax.Hub.config.styles],
- ["Post",this.signal,"End Styles"]
- );
- },
- //
- // Load the input and output jax
- //
- Jax: function () {
- var config = MathJax.Hub.config, jax = MathJax.Hub.outputJax;
- // Save the order of the output jax since they are loading asynchronously
- for (var i = 0, m = config.jax.length, k = 0; i < m; i++) {
- var name = config.jax[i].substr(7);
- if (config.jax[i].substr(0,7) === "output/" && jax.order[name] == null)
- {jax.order[name] = k; k++}
- }
- var queue = MathJax.Callback.Queue();
- return queue.Push(
- ["Post",this.signal,"Begin Jax"],
- ["loadArray",this,config.jax,"jax","config.js"],
- ["Post",this.signal,"End Jax"]
- );
- },
- //
- // Load the extensions
- //
- Extensions: function () {
- var queue = MathJax.Callback.Queue();
- return queue.Push(
- ["Post",this.signal,"Begin Extensions"],
- ["loadArray",this,MathJax.Hub.config.extensions,"extensions"],
- ["Post",this.signal,"End Extensions"]
- );
- },
- //
- // Initialize the Message system
- //
- Message: function () {
- MathJax.Message.Init(true);
- },
- //
- // Set the math menu renderer, if it isn't already
- // (this must come after the jax are loaded)
- //
- Menu: function () {
- var menu = MathJax.Hub.config.menuSettings, jax = MathJax.Hub.outputJax, registered;
- for (var id in jax) {if (jax.hasOwnProperty(id)) {
- if (jax[id].length) {registered = jax[id]; break}
- }}
- if (registered && registered.length) {
- if (menu.renderer && menu.renderer !== registered[0].id)
- {registered.unshift(MathJax.OutputJax[menu.renderer])}
- menu.renderer = registered[0].id;
- }
- },
- //
- // Set the location to the designated hash position
- //
- Hash: function () {
- if (MathJax.Hub.config.positionToHash && document.location.hash &&
- document.body && document.body.scrollIntoView) {
- var name = document.location.hash.substr(1);
- var target = document.getElementById(name);
- if (!target) {
- var a = document.getElementsByTagName("a");
- for (var i = 0, m = a.length; i < m; i++)
- {if (a[i].name === name) {target = a[i]; break}}
- }
- if (target) {
- while (!target.scrollIntoView) {target = target.parentNode}
- target = this.HashCheck(target);
- if (target && target.scrollIntoView)
- {setTimeout(function () {target.scrollIntoView(true)},1)}
- }
- }
- },
- HashCheck: function (target) {
- var jax = MathJax.Hub.getJaxFor(target);
- if (jax && MathJax.OutputJax[jax.outputJax].hashCheck)
- {target = MathJax.OutputJax[jax.outputJax].hashCheck(target)}
- return target;
- },
- //
- // Load the Menu and Zoom code, if it hasn't already been loaded.
- // This is called after the initial typeset, so should no longer be
- // competing with other page loads, but will make these available
- // if needed later on.
- //
- MenuZoom: function () {
- if (MathJax.Hub.config.showMathMenu) {
- if (!MathJax.Extension.MathMenu) {
- setTimeout(
- function () {
- MathJax.Callback.Queue(
- ["Require",MathJax.Ajax,"[MathJax]/extensions/MathMenu.js",{}],
- ["loadDomain",MathJax.Localization,"MathMenu"]
- )
- },1000
- );
- } else {
- setTimeout(
- MathJax.Callback(["loadDomain",MathJax.Localization,"MathMenu"]),
- 1000
- );
- }
- if (!MathJax.Extension.MathZoom) {
- setTimeout(
- MathJax.Callback(["Require",MathJax.Ajax,"[MathJax]/extensions/MathZoom.js",{}]),
- 2000
- );
- }
- }
- },
- //
- // Setup the onload callback
- //
- onLoad: function () {
- var onload = this.onload =
- MathJax.Callback(function () {MathJax.Hub.Startup.signal.Post("onLoad")});
- if (document.body && document.readyState)
- if (MathJax.Hub.Browser.isMSIE) {
- // IE can change from loading to interactive before
- // full page is ready, so go with complete (even though
- // that means we may have to wait longer).
- if (document.readyState === "complete") {return [onload]}
- } else if (document.readyState !== "loading") {return [onload]}
- if (window.addEventListener) {
- window.addEventListener("load",onload,false);
- if (!this.params.noDOMContentEvent)
- {window.addEventListener("DOMContentLoaded",onload,false)}
- }
- else if (window.attachEvent) {window.attachEvent("onload",onload)}
- else {window.onload = onload}
- return onload;
- },
- //
- // Perform the initial typesetting (or skip if configuration says to)
- //
- Typeset: function (element,callback) {
- if (MathJax.Hub.config.skipStartupTypeset) {return function () {}}
- return this.queue.Push(
- ["Post",this.signal,"Begin Typeset"],
- ["Typeset",MathJax.Hub,element,callback],
- ["Post",this.signal,"End Typeset"]
- );
- },
- //
- // Create a URL in the MathJax hierarchy
- //
- URL: function (dir,name) {
- if (!name.match(/^([a-z]+:\/\/|\[|\/)/)) {name = "[MathJax]/"+dir+"/"+name}
- return name;
- },
- //
- // Load an array of files, waiting for all of them
- // to be loaded before going on
- //
- loadArray: function (files,dir,name,synchronous) {
- if (files) {
- if (!MathJax.Object.isArray(files)) {files = [files]}
- if (files.length) {
- var queue = MathJax.Callback.Queue(), callback = {}, file;
- for (var i = 0, m = files.length; i < m; i++) {
- file = this.URL(dir,files[i]);
- if (name) {file += "/" + name}
- if (synchronous) {queue.Push(["Require",MathJax.Ajax,file,callback])}
- else {queue.Push(MathJax.Ajax.Require(file,callback))}
- }
- return queue.Push({}); // wait for everything to finish
- }
- }
- return null;
- }
- };
- /**********************************************************/
- (function (BASENAME) {
- var BASE = window[BASENAME], ROOT = "["+BASENAME+"]";
- var HUB = BASE.Hub, AJAX = BASE.Ajax, CALLBACK = BASE.Callback;
- var JAX = MathJax.Object.Subclass({
- JAXFILE: "jax.js",
- require: null, // array of files to load before jax.js is complete
- config: {},
- //
- // Make a subclass and return an instance of it.
- // (FIXME: should we replace config with a copy of the constructor's
- // config? Otherwise all subclasses share the same config structure.)
- //
- Init: function (def,cdef) {
- if (arguments.length === 0) {return this}
- return (this.constructor.Subclass(def,cdef))();
- },
- //
- // Augment by merging with class definition (not replacing)
- //
- Augment: function (def,cdef) {
- var cObject = this.constructor, ndef = {};
- if (def != null) {
- for (var id in def) {if (def.hasOwnProperty(id)) {
- if (typeof def[id] === "function")
- {cObject.protoFunction(id,def[id])} else {ndef[id] = def[id]}
- }}
- // MSIE doesn't list toString even if it is not native so handle it separately
- if (def.toString !== cObject.prototype.toString && def.toString !== {}.toString)
- {cObject.protoFunction('toString',def.toString)}
- }
- HUB.Insert(cObject.prototype,ndef);
- cObject.Augment(null,cdef);
- return this;
- },
- Translate: function (script,state) {
- throw Error(this.directory+"/"+this.JAXFILE+" failed to define the Translate() method");
- },
- Register: function (mimetype) {},
- Config: function () {
- this.config = HUB.CombineConfig(this.id,this.config);
- if (this.config.Augment) {this.Augment(this.config.Augment)}
- },
- Startup: function () {},
- loadComplete: function (file) {
- if (file === "config.js") {
- return AJAX.loadComplete(this.directory+"/"+file);
- } else {
- var queue = CALLBACK.Queue();
- queue.Push(
- HUB.Register.StartupHook("End Config",{}), // wait until config complete
- ["Post",HUB.Startup.signal,this.id+" Jax Config"],
- ["Config",this],
- ["Post",HUB.Startup.signal,this.id+" Jax Require"],
- // Config may set the required and extensions array,
- // so use functions to delay making the reference until needed
- [function (THIS) {return MathJax.Hub.Startup.loadArray(THIS.require,this.directory)},this],
- [function (config,id) {return MathJax.Hub.Startup.loadArray(config.extensions,"extensions/"+id)},this.config||{},this.id],
- ["Post",HUB.Startup.signal,this.id+" Jax Startup"],
- ["Startup",this],
- ["Post",HUB.Startup.signal,this.id+" Jax Ready"]
- );
- if (this.copyTranslate) {
- queue.Push(
- [function (THIS) {
- THIS.preProcess = THIS.preTranslate;
- THIS.Process = THIS.Translate;
- THIS.postProcess = THIS.postTranslate;
- },this.constructor.prototype]
- );
- }
- return queue.Push(["loadComplete",AJAX,this.directory+"/"+file]);
- }
- }
- },{
- id: "Jax",
- version: "2.7.2",
- directory: ROOT+"/jax",
- extensionDir: ROOT+"/extensions"
- });
- /***********************************/
- BASE.InputJax = JAX.Subclass({
- elementJax: "mml", // the element jax to load for this input jax
- sourceMenuTitle: /*_(MathMenu)*/ ["Original","Original Form"],
- copyTranslate: true,
- Process: function (script,state) {
- var queue = CALLBACK.Queue(), file;
- // Load any needed element jax
- var jax = this.elementJax; if (!BASE.Object.isArray(jax)) {jax = [jax]}
- for (var i = 0, m = jax.length; i < m; i++) {
- file = BASE.ElementJax.directory+"/"+jax[i]+"/"+this.JAXFILE;
- if (!this.require) {this.require = []}
- else if (!BASE.Object.isArray(this.require)) {this.require = [this.require]};
- this.require.push(file); // so Startup will wait for it to be loaded
- queue.Push(AJAX.Require(file));
- }
- // Load the input jax
- file = this.directory+"/"+this.JAXFILE;
- var load = queue.Push(AJAX.Require(file));
- if (!load.called) {
- this.constructor.prototype.Process = function () {
- if (!load.called) {return load}
- throw Error(file+" failed to load properly");
- }
- }
- // Load the associated output jax
- jax = HUB.outputJax["jax/"+jax[0]];
- if (jax) {queue.Push(AJAX.Require(jax[0].directory+"/"+this.JAXFILE))}
- return queue.Push({});
- },
- needsUpdate: function (jax) {
- var script = jax.SourceElement();
- return (jax.originalText !== BASE.HTML.getScript(script));
- },
- Register: function (mimetype) {
- if (!HUB.inputJax) {HUB.inputJax = {}}
- HUB.inputJax[mimetype] = this;
- }
- },{
- id: "InputJax",
- version: "2.7.2",
- directory: JAX.directory+"/input",
- extensionDir: JAX.extensionDir
- });
- /***********************************/
- BASE.OutputJax = JAX.Subclass({
- copyTranslate: true,
- preProcess: function (state) {
- var load, file = this.directory+"/"+this.JAXFILE;
- this.constructor.prototype.preProcess = function (state) {
- if (!load.called) {return load}
- throw Error(file+" failed to load properly");
- }
- load = AJAX.Require(file);
- return load;
- },
- Register: function (mimetype) {
- var jax = HUB.outputJax;
- if (!jax[mimetype]) {jax[mimetype] = []}
- // If the output jax is earlier in the original configuration list, put it first here
- if (jax[mimetype].length && (this.id === HUB.config.menuSettings.renderer ||
- (jax.order[this.id]||0) < (jax.order[jax[mimetype][0].id]||0)))
- {jax[mimetype].unshift(this)} else {jax[mimetype].push(this)}
- // Make sure the element jax is loaded before Startup is called
- if (!this.require) {this.require = []}
- else if (!BASE.Object.isArray(this.require)) {this.require = [this.require]};
- this.require.push(BASE.ElementJax.directory+"/"+(mimetype.split(/\//)[1])+"/"+this.JAXFILE);
- },
- Remove: function (jax) {}
- },{
- id: "OutputJax",
- version: "2.7.2",
- directory: JAX.directory+"/output",
- extensionDir: JAX.extensionDir,
- fontDir: ROOT+(BASE.isPacked?"":"/..")+"/fonts",
- imageDir: ROOT+(BASE.isPacked?"":"/..")+"/images"
- });
- /***********************************/
- BASE.ElementJax = JAX.Subclass({
- // make a subclass, not an instance
- Init: function (def,cdef) {return this.constructor.Subclass(def,cdef)},
- inputJax: null,
- outputJax: null,
- inputID: null,
- originalText: "",
- mimeType: "",
- sourceMenuTitle: /*_(MathMenu)*/ ["MathMLcode","MathML Code"],
- Text: function (text,callback) {
- var script = this.SourceElement();
- BASE.HTML.setScript(script,text);
- script.MathJax.state = this.STATE.UPDATE;
- return HUB.Update(script,callback);
- },
- Reprocess: function (callback) {
- var script = this.SourceElement();
- script.MathJax.state = this.STATE.UPDATE;
- return HUB.Reprocess(script,callback);
- },
- Update: function (callback) {return this.Rerender(callback)},
- Rerender: function (callback) {
- var script = this.SourceElement();
- script.MathJax.state = this.STATE.OUTPUT;
- return HUB.Process(script,callback);
- },
- Remove: function (keep) {
- if (this.hover) {this.hover.clear(this)}
- BASE.OutputJax[this.outputJax].Remove(this);
- if (!keep) {
- HUB.signal.Post(["Remove Math",this.inputID]); // wait for this to finish?
- this.Detach();
- }
- },
- needsUpdate: function () {
- return BASE.InputJax[this.inputJax].needsUpdate(this);
- },
- SourceElement: function () {return document.getElementById(this.inputID)},
- Attach: function (script,inputJax) {
- var jax = script.MathJax.elementJax;
- if (script.MathJax.state === this.STATE.UPDATE) {
- jax.Clone(this);
- } else {
- jax = script.MathJax.elementJax = this;
- if (script.id) {this.inputID = script.id}
- else {script.id = this.inputID = BASE.ElementJax.GetID(); this.newID = 1}
- }
- jax.originalText = BASE.HTML.getScript(script);
- jax.inputJax = inputJax;
- if (jax.root) {jax.root.inputID = jax.inputID}
- return jax;
- },
- Detach: function () {
- var script = this.SourceElement(); if (!script) return;
- try {delete script.MathJax} catch(err) {script.MathJax = null}
- if (this.newID) {script.id = ""}
- },
- Clone: function (jax) {
- var id;
- for (id in this) {
- if (!this.hasOwnProperty(id)) continue;
- if (typeof(jax[id]) === 'undefined' && id !== 'newID') {delete this[id]}
- }
- for (id in jax) {
- if (!jax.hasOwnProperty(id)) continue;
- if (typeof(this[id]) === 'undefined' || (this[id] !== jax[id] && id !== 'inputID'))
- {this[id] = jax[id]}
- }
- }
- },{
- id: "ElementJax",
- version: "2.7.2",
- directory: JAX.directory+"/element",
- extensionDir: JAX.extensionDir,
- ID: 0, // jax counter (for IDs)
- STATE: {
- PENDING: 1, // script is identified as math but not yet processed
- PROCESSED: 2, // script has been processed
- UPDATE: 3, // elementJax should be updated
- OUTPUT: 4 // output should be updated (input is OK)
- },
- GetID: function () {this.ID++; return "MathJax-Element-"+this.ID},
- Subclass: function () {
- var obj = JAX.Subclass.apply(this,arguments);
- obj.loadComplete = this.prototype.loadComplete;
- return obj;
- }
- });
- BASE.ElementJax.prototype.STATE = BASE.ElementJax.STATE;
- //
- // Some "Fake" jax used to allow menu access for "Math Processing Error" messages
- //
- BASE.OutputJax.Error = {
- id: "Error", version: "2.7.2", config: {}, errors: 0,
- ContextMenu: function () {return BASE.Extension.MathEvents.Event.ContextMenu.apply(BASE.Extension.MathEvents.Event,arguments)},
- Mousedown: function () {return BASE.Extension.MathEvents.Event.AltContextMenu.apply(BASE.Extension.MathEvents.Event,arguments)},
- getJaxFromMath: function (math) {return (math.nextSibling.MathJax||{}).error},
- Jax: function (text,script) {
- var jax = MathJax.Hub.inputJax[script.type.replace(/ *;(.|\s)*/,"")];
- this.errors++;
- return {
- inputJax: (jax||{id:"Error"}).id, // Use Error InputJax as fallback
- outputJax: "Error",
- inputID: "MathJax-Error-"+this.errors,
- sourceMenuTitle: /*_(MathMenu)*/ ["ErrorMessage","Error Message"],
- sourceMenuFormat: "Error",
- originalText: MathJax.HTML.getScript(script),
- errorText: text
- }
- }
- };
- BASE.InputJax.Error = {
- id: "Error", version: "2.7.2", config: {},
- sourceMenuTitle: /*_(MathMenu)*/ ["Original","Original Form"]
- };
- })("MathJax");
- /**********************************************************/
- (function (BASENAME) {
- var BASE = window[BASENAME];
- if (!BASE) {BASE = window[BASENAME] = {}}
- var HUB = BASE.Hub; var STARTUP = HUB.Startup; var CONFIG = HUB.config;
- var HEAD = document.head || (document.getElementsByTagName("head")[0]);
- if (!HEAD) {HEAD = document.childNodes[0]};
- var scripts = (document.documentElement || document).getElementsByTagName("script");
- if (scripts.length === 0 && HEAD.namespaceURI)
- scripts = document.getElementsByTagNameNS(HEAD.namespaceURI,"script");
- var namePattern = new RegExp("(^|/)"+BASENAME+"\\.js(\\?.*)?$");
- for (var i = scripts.length-1; i >= 0; i--) {
- if ((scripts[i].src||"").match(namePattern)) {
- STARTUP.script = scripts[i].innerHTML;
- if (RegExp.$2) {
- var params = RegExp.$2.substr(1).split(/\&/);
- for (var j = 0, m = params.length; j < m; j++) {
- var KV = params[j].match(/(.*)=(.*)/);
- if (KV) {STARTUP.params[unescape(KV[1])] = unescape(KV[2])}
- else {STARTUP.params[params[j]] = true}
- }
- }
- CONFIG.root = scripts[i].src.replace(/(^|\/)[^\/]*(\?.*)?$/,'');
- BASE.Ajax.config.root = CONFIG.root;
- BASE.Ajax.params = STARTUP.params;
- break;
- }
- }
- var AGENT = navigator.userAgent;
- var BROWSERS = {
- isMac: (navigator.platform.substr(0,3) === "Mac"),
- isPC: (navigator.platform.substr(0,3) === "Win"),
- isMSIE: ("ActiveXObject" in window && "clipboardData" in window),
- isEdge: ("MSGestureEvent" in window && "chrome" in window &&
- window.chrome.loadTimes == null),
- isFirefox: (!!AGENT.match(/Gecko\//) && !AGENT.match(/like Gecko/)),
- isSafari: (!!AGENT.match(/ (Apple)?WebKit\//) && !AGENT.match(/ like iPhone /) &&
- (!window.chrome || window.chrome.app == null)),
- isChrome: ("chrome" in window && window.chrome.loadTimes != null),
- isOpera: ("opera" in window && window.opera.version != null),
- isKonqueror: ("konqueror" in window && navigator.vendor == "KDE"),
- versionAtLeast: function (v) {
- var bv = (this.version).split('.'); v = (new String(v)).split('.');
- for (var i = 0, m = v.length; i < m; i++)
- {if (bv[i] != v[i]) {return parseInt(bv[i]||"0") >= parseInt(v[i])}}
- return true;
- },
- Select: function (choices) {
- var browser = choices[HUB.Browser];
- if (browser) {return browser(HUB.Browser)}
- return null;
- }
- };
- var xAGENT = AGENT
- .replace(/^Mozilla\/(\d+\.)+\d+ /,"") // remove initial Mozilla, which is never right
- .replace(/[a-z][-a-z0-9._: ]+\/\d+[^ ]*-[^ ]*\.([a-z][a-z])?\d+ /i,"") // remove linux version
- .replace(/Gentoo |Ubuntu\/(\d+\.)*\d+ (\([^)]*\) )?/,""); // special case for these
- HUB.Browser = HUB.Insert(HUB.Insert(new String("Unknown"),{version: "0.0"}),BROWSERS);
- for (var browser in BROWSERS) {if (BROWSERS.hasOwnProperty(browser)) {
- if (BROWSERS[browser] && browser.substr(0,2) === "is") {
- browser = browser.slice(2);
- if (browser === "Mac" || browser === "PC") continue;
- HUB.Browser = HUB.Insert(new String(browser),BROWSERS);
- var VERSION = new RegExp(
- ".*(Version/| Trident/.*; rv:)((?:\\d+\\.)+\\d+)|" + // for Safari, Opera10, and IE11+
- ".*("+browser+")"+(browser == "MSIE" ? " " : "/")+"((?:\\d+\\.)*\\d+)|"+ // for one of the main browsers
- "(?:^|\\(| )([a-z][-a-z0-9._: ]+|(?:Apple)?WebKit)/((?:\\d+\\.)+\\d+)"); // for unrecognized browser
- var MATCH = VERSION.exec(xAGENT) || ["","","","unknown","0.0"];
- HUB.Browser.name = (MATCH[1] != "" ? browser : (MATCH[3] || MATCH[5]));
- HUB.Browser.version = MATCH[2] || MATCH[4] || MATCH[6];
- break;
- }
- }};
- //
- // Initial browser-specific info (e.g., touch up version or name, check for MathPlayer, etc.)
- // Wrap in try/catch just in case of error (see issue #1155).
- //
- try {HUB.Browser.Select({
- Safari: function (browser) {
- var v = parseInt((String(browser.version).split("."))[0]);
- if (v > 85) {browser.webkit = browser.version}
- if (v >= 538) {browser.version = "8.0"}
- else if (v >= 537) {browser.version = "7.0"}
- else if (v >= 536) {browser.version = "6.0"}
- else if (v >= 534) {browser.version = "5.1"}
- else if (v >= 533) {browser.version = "5.0"}
- else if (v >= 526) {browser.version = "4.0"}
- else if (v >= 525) {browser.version = "3.1"}
- else if (v > 500) {browser.version = "3.0"}
- else if (v > 400) {browser.version = "2.0"}
- else if (v > 85) {browser.version = "1.0"}
- browser.webkit = (navigator.appVersion.match(/WebKit\/(\d+)\./))[1];
- browser.isMobile = (navigator.appVersion.match(/Mobile/i) != null);
- browser.noContextMenu = browser.isMobile;
- },
- Firefox: function (browser) {
- if ((browser.version === "0.0" || AGENT.match(/Firefox/) == null) &&
- navigator.product === "Gecko") {
- var rv = AGENT.match(/[\/ ]rv:(\d+\.\d.*?)[\) ]/);
- if (rv) {browser.version = rv[1]}
- else {
- var date = (navigator.buildID||navigator.productSub||"0").substr(0,8);
- if (date >= "20111220") {browser.version = "9.0"}
- else if (date >= "20111120") {browser.version = "8.0"}
- else if (date >= "20110927") {browser.version = "7.0"}
- else if (date >= "20110816") {browser.version = "6.0"}
- else if (date >= "20110621") {browser.version = "5.0"}
- else if (date >= "20110320") {browser.version = "4.0"}
- else if (date >= "20100121") {browser.version = "3.6"}
- else if (date >= "20090630") {browser.version = "3.5"}
- else if (date >= "20080617") {browser.version = "3.0"}
- else if (date >= "20061024") {browser.version = "2.0"}
- }
- }
- browser.isMobile = (navigator.appVersion.match(/Android/i) != null ||
- AGENT.match(/ Fennec\//) != null ||
- AGENT.match(/Mobile/) != null);
- },
- Chrome: function (browser) {
- browser.noContextMenu = browser.isMobile = !!navigator.userAgent.match(/ Mobile[ \/]/);
- },
- Opera: function (browser) {browser.version = opera.version()},
- Edge: function (browser) {
- browser.isMobile = !!navigator.userAgent.match(/ Phone/);
- },
- MSIE: function (browser) {
- browser.isMobile = !!navigator.userAgent.match(/ Phone/);
- browser.isIE9 = !!(document.documentMode && (window.performance || window.msPerformance));
- MathJax.HTML.setScriptBug = !browser.isIE9 || document.documentMode < 9;
- MathJax.Hub.msieHTMLCollectionBug = (document.documentMode < 9);
- //
- // MathPlayer doesn't function properly in IE10, and not at all in IE11,
- // so don't even try to load it.
- //
- if (document.documentMode < 10 && !STARTUP.params.NoMathPlayer) {
- try {
- new ActiveXObject("MathPlayer.Factory.1");
- browser.hasMathPlayer = true;
- } catch (err) {}
- try {
- if (browser.hasMathPlayer) {
- var mathplayer = document.createElement("object");
- mathplayer.id = "mathplayer"; mathplayer.classid = "clsid:32F66A20-7614-11D4-BD11-00104BD3F987";
- HEAD.appendChild(mathplayer);
- document.namespaces.add("m","http://www.w3.org/1998/Math/MathML");
- browser.mpNamespace = true;
- if (document.readyState && (document.readyState === "loading" ||
- document.readyState === "interactive")) {
- document.write('<?import namespace="m" implementation="#MathPlayer">');
- browser.mpImported = true;
- }
- } else {
- // Adding any namespace avoids a crash in IE9 in IE9-standards mode
- // (any reference to document.namespaces before document.readyState is
- // "complete" causes an "unspecified error" to be thrown)
- document.namespaces.add("mjx_IE_fix","http://www.w3.org/1999/xlink");
- }
- } catch (err) {}
- }
- }
- });} catch (err) {
- console.error(err.message);
- }
- HUB.Browser.Select(MathJax.Message.browsers);
- if (BASE.AuthorConfig && typeof BASE.AuthorConfig.AuthorInit === "function") {BASE.AuthorConfig.AuthorInit()}
- HUB.queue = BASE.Callback.Queue();
- HUB.queue.Push(
- ["Post",STARTUP.signal,"Begin"],
- ["Config",STARTUP],
- ["Cookie",STARTUP],
- ["Styles",STARTUP],
- ["Message",STARTUP],
- function () {
- // Do Jax and Extensions in parallel, but wait for them all to complete
- var queue = BASE.Callback.Queue(
- STARTUP.Jax(),
- STARTUP.Extensions()
- );
- return queue.Push({});
- },
- ["Menu",STARTUP],
- STARTUP.onLoad(),
- function () {MathJax.isReady = true}, // indicates that MathJax is ready to process math
- ["Typeset",STARTUP],
- ["Hash",STARTUP],
- ["MenuZoom",STARTUP],
- ["Post",STARTUP.signal,"End"]
- );
- })("MathJax");
- }}
|