123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- /* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
- /* vim: set ts=2 et sw=2 tw=80: */
- /*************************************************************
- *
- * MathJax/extensions/TeX/begingroup.js
- *
- * Implements \begingroup and \endgroup commands that make local
- * definitions possible and are removed when the \endgroup occurs.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (c) 2011-2013 The MathJax Consortium
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- MathJax.Extension["TeX/begingroup"] = {
- version: "2.2"
- };
- MathJax.Hub.Register.StartupHook("TeX Jax Ready",function () {
- var TEX = MathJax.InputJax.TeX,
- TEXDEF = TEX.Definitions;
- /****************************************************/
- //
- // A namespace for localizing macros and environments
- // (\begingroup and \endgroup create and destroy these)
- //
- var NSFRAME = MathJax.Object.Subclass({
- macros: null, // the local macro definitions
- environments: null, // the local environments
- Init: function (macros,environments) {
- this.macros = (macros || {});
- this.environments = (environments || {});
- },
- //
- // Find a macro or environment by name
- //
- Find: function (name,type) {if (this[type][name]) {return this[type][name]}},
- //
- // Define or remove a macro or environment
- //
- Def: function (name,value,type) {this[type][name] = value},
- Undef: function (name,type) {delete this[type][name]},
- //
- // Merge two namespaces (used when the equation namespace is combined with the root one)
- //
- Merge: function (frame) {
- MathJax.Hub.Insert(this.macros,frame.macros);
- MathJax.Hub.Insert(this.environments,frame.environments);
- },
- //
- // Move global macros to the stack (globally) and remove from the frame
- //
- MergeGlobals: function (stack) {
- var macros = this.macros;
- for (var cs in macros) {if (macros.hasOwnProperty(cs) && macros[cs].global) {
- stack.Def(cs,macros[cs],"macros",true);
- delete macros[cs].global; delete macros[cs];
- }}
- },
- //
- // Clear the macro and environment lists
- // (but not global macros unless "all" is true)
- //
- Clear: function (all) {
- this.environments = {};
- if (all) {this.macros = {}} else {
- var macros = this.macros;
- for (var cs in macros) {
- if (macros.hasOwnProperty(cs) && !macros[cs].global) {delete macros[cs]}
- }
- }
- return this;
- }
- });
- /****************************************************/
- //
- // A Stack of namespace frames
- //
- var NSSTACK = TEX.nsStack = MathJax.Object.Subclass({
- stack: null, // the namespace frames
- top: 0, // the current top one (we don't pop for real until the equation completes)
- isEqn: false, // true if this is the equation stack (not the global one)
- //
- // Set up the initial stack frame
- //
- Init: function (eqn) {
- this.isEqn = eqn; this.stack = [];
- if (!eqn) {this.Push(NSFRAME(TEXDEF.macros,TEXDEF.environment))}
- else {this.Push(NSFRAME())}
- },
- //
- // Define a macro or environment in the top frame
- //
- Def: function (name,value,type,global) {
- var n = this.top-1;
- if (global) {
- //
- // Define global macros in the base frame and remove that cs
- // from all other frames. Mark the global ones in equations
- // so they can be made global when merged with the root stack.
- //
- while (n > 0) {this.stack[n].Undef(name,type); n--}
- if (!(value instanceof Array)) {value = [value]}
- if (this.isEqn) {value.global = true}
- }
- this.stack[n].Def(name,value,type);
- },
- //
- // Push a new namespace frame on the stack
- //
- Push: function (frame) {
- this.stack.push(frame);
- this.top = this.stack.length;
- },
- //
- // Pop the top stack frame
- // (if it is the root, just keep track of the pop so we can
- // reset it if the equation is reprocessed)
- //
- Pop: function () {
- var top;
- if (this.top > 1) {
- top = this.stack[--this.top];
- if (this.isEqn) {this.stack.pop()}
- } else if (this.isEqn) {
- this.Clear();
- }
- return top;
- },
- //
- // Search the stack from top to bottom for the first
- // definition of the given control sequence in the given type
- //
- Find: function (name,type) {
- for (var i = this.top-1; i >= 0; i--) {
- var def = this.stack[i].Find(name,type);
- if (def) {return def}
- }
- return null;
- },
- //
- // Combine the equation stack with the global one
- // (The bottom frame of the equation goes with the top frame of the global one,
- // and the remainder are pushed on the global stack, truncated to the
- // position where items were poped from it.)
- //
- Merge: function (stack) {
- stack.stack[0].MergeGlobals(this);
- this.stack[this.top-1].Merge(stack.stack[0]);
- var data = [this.top,this.stack.length-this.top].concat(stack.stack.slice(1));
- this.stack.splice.apply(this.stack,data);
- this.top = this.stack.length;
- },
- //
- // Put back the temporarily poped items
- //
- Reset: function () {this.top = this.stack.length},
- //
- // Clear the stack and start with a blank frame
- //
- Clear: function (all) {
- this.stack = [this.stack[0].Clear()];
- this.top = this.stack.length;
- }
- },{
- nsFrame: NSFRAME
- });
- /****************************************************/
- //
- // Define the new macros
- //
- TEXDEF.Add({
- macros: {
- begingroup: "BeginGroup",
- endgroup: "EndGroup",
- global: ["Extension","newcommand"],
- gdef: ["Extension","newcommand"]
- }
- },null,true);
-
- TEX.Parse.Augment({
- //
- // Implement \begingroup
- //
- BeginGroup: function (name) {
- TEX.eqnStack.Push(NSFRAME());
- },
- //
- // Implements \endgroup
- //
- EndGroup: function (name) {
- //
- // If the equation has pushed frames, pop one,
- // Otherwise clear the equation stack and pop the top global one
- //
- if (TEX.eqnStack.top > 1) {
- TEX.eqnStack.Pop();
- } else if (TEX.rootStack.top === 1) {
- TEX.Error(["ExtraEndMissingBegin","Extra %1 or missing \\begingroup",name]);
- } else {
- TEX.eqnStack.Clear();
- TEX.rootStack.Pop();
- }
- },
- //
- // Replace the original routines with ones that looks through the
- // equation and root stacks for the given name
- //
- csFindMacro: function (name) {
- return (TEX.eqnStack.Find(name,"macros") || TEX.rootStack.Find(name,"macros"));
- },
- envFindName: function (name) {
- return (TEX.eqnStack.Find(name,"environments") || TEX.rootStack.Find(name,"environments"));
- }
- });
- /****************************************************/
- TEX.rootStack = NSSTACK(); // the global namespace stack
- TEX.eqnStack = NSSTACK(true); // the equation stack
- //
- // Reset the global stack and clear the equation stack
- // (this gets us back to the initial stack state as it was
- // before the equation was first processed, in case the equation
- // get restarted due to an autoloaded file)
- //
- TEX.prefilterHooks.Add(function () {TEX.rootStack.Reset(); TEX.eqnStack.Clear(true)});
-
- //
- // We only get here if there were no errors and the equation is fully
- // processed (all restarts are complete). So we merge the equation
- // stack into the global stack, thus making the changes from this
- // equation permanent.
- //
- TEX.postfilterHooks.Add(function () {TEX.rootStack.Merge(TEX.eqnStack)});
-
- /*********************************************************/
- MathJax.Hub.Register.StartupHook("TeX newcommand Ready",function () {
- //
- // Add the commands that depend on the newcommand code
- //
- TEXDEF.Add({
- macros: {
- global: "Global",
- gdef: ["Macro","\\global\\def"]
- }
- },null,true);
- TEX.Parse.Augment({
- //
- // Modify the way macros and environments are defined
- // to make them go into the equation namespace stack
- //
- setDef: function (name,value) {
- value.isUser = true;
- TEX.eqnStack.Def(name,value,"macros",this.stack.env.isGlobal);
- delete this.stack.env.isGlobal;
- },
- setEnv: function (name,value) {
- value.isUser = true;
- TEX.eqnStack.Def(name,value,"environments")
- },
- //
- // Implement \global (for \global\let, \global\def and \global\newcommand)
- //
- Global: function (name) {
- var i = this.i; var cs = this.GetCSname(name); this.i = i;
- if (cs !== "let" && cs !== "def" && cs !== "newcommand") {
- TEX.Error(["GlobalNotFollowedBy",
- "%1 not followed by \\let, \\def, or \\newcommand",name]);
- }
- this.stack.env.isGlobal = true;
- }
- });
- });
- MathJax.Hub.Startup.signal.Post("TeX begingroup Ready");
- });
- MathJax.Ajax.loadComplete("[MathJax]/extensions/TeX/begingroup.js");
|