File:  [LON-CAPA] / loncom / html / adm / jsMath / extensions / newcommand.js
Revision 1.2: download - view: text, annotated - select for diffs
Tue Oct 9 21:29:22 2007 UTC (17 years, 1 month ago) by albertel
Branches: MAIN
CVS tags: version_2_9_X, version_2_9_99_0, version_2_9_1, version_2_9_0, version_2_8_X, version_2_8_99_1, version_2_8_99_0, version_2_8_2, version_2_8_1, version_2_8_0, version_2_7_X, version_2_7_99_1, version_2_7_99_0, version_2_7_1, version_2_7_0, version_2_6_X, version_2_6_99_1, version_2_6_99_0, version_2_6_3, version_2_6_2, version_2_6_1, version_2_6_0, version_2_5_99_1, version_2_5_99_0, version_2_12_X, version_2_11_X, version_2_11_5_msu, version_2_11_5, version_2_11_4_uiuc, version_2_11_4_msu, version_2_11_4, version_2_11_3_uiuc, version_2_11_3_msu, version_2_11_3, version_2_11_2_uiuc, version_2_11_2_msu, version_2_11_2_educog, version_2_11_2, version_2_11_1, version_2_11_0_RC3, version_2_11_0_RC2, version_2_11_0_RC1, version_2_11_0, version_2_10_X, version_2_10_1, version_2_10_0_RC2, version_2_10_0_RC1, version_2_10_0, loncapaMITrelate_1, language_hyphenation_merge, language_hyphenation, bz6209-base, bz6209, bz5969, bz2851, PRINT_INCOMPLETE_base, PRINT_INCOMPLETE, HEAD, GCI_3, GCI_2, GCI_1, BZ5971-printing-apage, BZ5434-fox, BZ4492-merge, BZ4492-feature_horizontal_radioresponse
- jsMath 3.4e

    1: /*
    2:  *  extensions/newcommand.js
    3:  *  
    4:  *  Part of the jsMath package for mathematics on the web.
    5:  *
    6:  *  This file implements the \newcommand and \def macros.  It will be
    7:  *  loaded automatically when needed, or can be loaded by
    8:  *  
    9:  *    jsMath.Extension.Require('newcommand');
   10:  *
   11:  *  ---------------------------------------------------------------------
   12:  *
   13:  *  Copyright 2005-2006 by Davide P. Cervone
   14:  * 
   15:  *  Licensed under the Apache License, Version 2.0 (the "License");
   16:  *  you may not use this file except in compliance with the License.
   17:  *  You may obtain a copy of the License at
   18:  * 
   19:  *      http://www.apache.org/licenses/LICENSE-2.0
   20:  * 
   21:  *  Unless required by applicable law or agreed to in writing, software
   22:  *  distributed under the License is distributed on an "AS IS" BASIS,
   23:  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   24:  *  See the License for the specific language governing permissions and
   25:  *  limitations under the License.
   26:  */
   27: 
   28: /********************************************************************/
   29: 
   30: jsMath.Package(jsMath.Parser,{
   31:   
   32:   macros: {
   33:     newcommand: 'NewCommand',
   34:     newenvironment: 'NewEnvironment',
   35:     def: 'MacroDef'
   36:   },
   37:   
   38:   /*
   39:    *  Implement \newcommand{\name}[n]{...}
   40:    */
   41:   NewCommand: function (name) {
   42:     var cs = this.trimSpaces(this.GetArgument(this.cmd+name)); if (this.error) return;
   43:     var n = this.trimSpaces(this.GetBrackets(this.cmd+name)); if (this.error) return;
   44:     var def = this.GetArgument(this.cmd+name); if (this.error) return;
   45:     if (n == '') {n = null}
   46:     if (cs.charAt(0) == this.cmd) {cs = cs.substr(1)}
   47:     if (!cs.match(/^(.|[a-z]+)$/)) {this.Error("Illegal control sequence name for "+this.cmd+name); return}
   48:     if (n != null && !n.match(/^[0-9]+$/)) {this.Error("Illegal number of parameters specified in "+this.cmd+name); return}
   49:     jsMath.Parser.prototype.macros[cs] = ['Macro',def,n];
   50:   },
   51:   
   52:   /*
   53:    *  Implement \newenvironment{name}[n]{begincmd}{endcmd}
   54:    */
   55:   NewEnvironment: function (name) {
   56:     var env = this.trimSpaces(this.GetArgument(this.cmd+name)); if (this.error) return;
   57:     var n = this.trimSpaces(this.GetBrackets(this.cmd+name)); if (this.error) return;
   58:     var bdef = this.GetArgument(this.cmd+name); if (this.error) return;
   59:     var edef = this.GetArgument(this.cmd+name); if (this.error) return;
   60:     if (n == '') {n = null}
   61:     if (n != null && !n.match(/^[0-9]+$/)) {this.Error("Illegal number of parameters specified in "+this.cmd+name); return}
   62:     jsMath.Parser.prototype.environments[env] = ['Environment',bdef,edef,n];
   63:   },
   64:   
   65:   /*
   66:    *  Implement \def command
   67:    */
   68:   MacroDef: function (name) {
   69:     var cs = this.GetCSname(this.cmd+name); if (this.error) return;
   70:     var params = this.GetTemplate(this.cmd+name); if (this.error) return;
   71:     var def = this.GetArgument(this.cmd+name); if (this.error) return;
   72:     if (typeof(params) == 'number') {
   73:       jsMath.Parser.prototype.macros[cs] = ['Macro',def,params];
   74:     } else {
   75:       jsMath.Parser.prototype.macros[cs] = ['MacroWithTemplate',def,params[0],params[1]];
   76:     }
   77:   },
   78: 
   79:   /*
   80:    *  Get a CS name or give an error
   81:    */
   82:   GetCSname: function (cmd) {
   83:     var c = this.GetNext();
   84:     if (c != this.cmd) {this.Error(cmd+" must be followed by a control sequence"); return null}
   85:     var cs = this.trimSpaces(this.GetArgument(cmd)); if (this.error) {return null};
   86:     return cs.substr(1);
   87:   },
   88:   
   89:   /*
   90:    *  Get a \def parameter template
   91:    */
   92:   GetTemplate: function (cmd) {
   93:     var c; var params = []; var n = 0;
   94:     c = this.GetNext(); var i = this.i;
   95:     while (this.i < this.string.length) {
   96:       c = this.GetNext();
   97:       if (c == '#') {
   98:         if (i != this.i) {params[n] = this.string.substr(i,this.i-i)}
   99:         c = this.string.charAt(++this.i);
  100:         if (!c.match(/[1-9]/)) {this.Error("Illegal use of # in "+cmd); return null}
  101:         if (1*c != ++n) {this.Error("Parameters must be numbered sequentially"); return null}
  102:         i = this.i+1;
  103:       } else if (c == '{') {
  104:         if (i != this.i) {params[n] = this.string.substr(i,this.i-i)}
  105:         if (params.length > 0) {return [n,params]} else {return n}
  106:       }
  107:       this.i++;
  108:     }
  109:     this.Error("Missing replacement string for definition of "+cmd);
  110:     return null;
  111:   },
  112:   
  113:   /*
  114:    *  Process a macro with a parameter template
  115:    */
  116:   MacroWithTemplate: function (name,data) {
  117:     var text = data[0];
  118:     var n = data[1]; var params = data[2];
  119:     if (n) {
  120:       var args = []; var c = this.GetNext();
  121:       if (params[0] && !this.MatchParam(params[0]))
  122:         {this.Error("Use of "+this.cmd+name+" doesn't match its definition"); return}
  123:       for (var i = 0; i < n; i++) {
  124:         args[args.length] = this.GetParameter(this.cmd+name,params[i+1]);
  125:         if (this.error) return;
  126:       }
  127:       text = this.SubstituteArgs(args,text);
  128:     }
  129:     this.string = this.AddArgs(text,this.string.slice(this.i));
  130:     this.i = 0;
  131:   },
  132:   
  133:   /*
  134:    *  Process a user-defined environment
  135:    */
  136:   Environment: function (name,data) {
  137:     var bdef = data[0]; var edef = data[1]; var n = data[2];
  138:     if (n) {
  139:       var args = [];
  140:       for (var i = 0; i < n; i++) {
  141:         args[args.length] = this.GetArgument(this.cmd+"begin{"+name+"}"); if (this.error) return;
  142:       }
  143:       bdef = this.SubstituteArgs(args,bdef);
  144:     }
  145:     var text = this.GetEnd(name); if (this.error) return;
  146:     text = this.AddArgs(this.AddArgs(bdef,text),edef);
  147:     this.string = this.AddArgs(text,this.string.slice(this.i));
  148:     this.i = 0;
  149:   },
  150: 
  151:   /*
  152:    *  Find a single parameter delimited by a trailing template
  153:    */
  154:   GetParameter: function (name,param) {
  155:     if (param == null) {return this.GetArgument(name)}
  156:     var i = this.i; var j = 0; var hasBraces = 0;
  157:     while (this.i < this.string.length) {
  158:       if (this.string.charAt(this.i) == '{') {
  159:         if (this.i == i) {hasBraces = 1}
  160:         this.GetArgument(name); j = this.i - i;
  161:       } else if (this.MatchParam(param)) {
  162:         if (hasBraces) {i++; j -= 2}
  163:         return this.string.substr(i,j);
  164:       } else {
  165:         this.i++; j++; hasBraces = 0;
  166:       }
  167:     }
  168:     this.Error("Runaway argument for "+name+"?");
  169:     return null;
  170:   },
  171: 
  172:   /*
  173:    *  Check if a template is at the current location.
  174:    *  (The match must be exact, with no spacing differences.  TeX is
  175:    *   a little more forgiving about spaces after macro names)
  176:    */
  177:   MatchParam: function (param) {
  178:     if (this.string.substr(this.i,param.length) != param) {return 0}
  179:     this.i += param.length;
  180:     return 1;
  181:   }
  182:   
  183: });
  184: 
  185: /*
  186:  *  Define a jsMath.Environment() command similar to the
  187:  *  jsMath.Macro() command.
  188:  *  
  189:  *  Usage:  jsMath.Environment(name,begin,end[,n])
  190:  *  
  191:  *  where "name" is the name of the environment, "begin" is the
  192:  *  text that replaces the \begin{name} and "end" is the text that
  193:  *  replaces the \end{name}.  If "n" is provided, it is the number
  194:  *  of parameters that the \begin{name} accepts, and these are
  195:  *  used to replace #1, #2, etc within the "begin" text.
  196:  */
  197: 
  198: jsMath.Add(jsMath,{
  199:   Environment: function (name) {
  200:     var environments = jsMath.Parser.prototype.environments;
  201:     environments[name] = ['Environment'];
  202:     for (var i = 1; i < arguments.length; i++) 
  203:       {environments[name][environments[name].length] = arguments[i]}
  204:   }
  205: });

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>