2 * extensions/eqn-number.js
4 * Part of the jsMath package for mathematics on the web.
6 * This file causes jsMath to add equation numbers to displayed
7 * equations. These are displayed at the right, but the styles can
8 * be controlled through the jsMath.EqnNumber object. Equations
9 * are numbered if they include a \label{xxx} call, and the macro
10 * \ref{xxx} can be used to refer to the equation number elsewhere
11 * in the document (it must appear by itself in a math formula,
12 * e.g., $\ref{xxx}$). The "label-ref" CSS style can be used to
13 * style the references.
15 * If jsMath.EqnNumber.autonumber is set to 1, then ALL displayed
16 * equations will be numberd. Use the \nolabel macro to prevent
17 * equation numbering on an equation.
19 * You can activate eqn-numbering by calling
21 * jsMath.Extension.Require('eqn-number');
23 * once jsMath.js has been loaded, or by adding "extensions/eqn-number.js"
24 * to the loadFiles array in jsMath/easy/load.js.
26 * ---------------------------------------------------------------------
28 * Copyright 2008 by Davide P. Cervone
30 * Licensed under the Apache License, Version 2.0 (the "License");
31 * you may not use this file except in compliance with the License.
32 * You may obtain a copy of the License at
34 * http://www.apache.org/licenses/LICENSE-2.0
36 * Unless required by applicable law or agreed to in writing, software
37 * distributed under the License is distributed on an "AS IS" BASIS,
38 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
39 * See the License for the specific language governing permissions and
40 * limitations under the License.
43 /********************************************************************/
45 if (jsMath.EqnNumber) {jsMath.EqnNumber_old = jsMath.EqnNumber}
50 '.jsMath_displayBox, .tex2math_div': {position: 'relative'},
53 right: '2em', top: '50%', 'margin-top': '-.5em',
54 height: 'auto', width: 'auto'
56 '.jsMath_ref': {'text-decoration': 'none'}
59 autonumber: 0, // set to 1 to have ALL equations numbered
62 format: function (n) {return n},
63 formatLabel: function (n) {return '<A NAME="eqn-'+n+'">('+n+')</A>'},
64 formatRef: function (n) {return '(<A CLASS="jsMath_ref" HREF="#eqn-'+n+'">'+n+'</A>)'},
66 _label: null, // flag set when \label{x} is used
67 _labels: {}, // stores label-name => label-value pairs
68 _refs: {}, // stores elements referring to undefined labels
69 _nolabel: 0, // set by \nolabel
71 nextNumber: function () {
72 var ref = this.format(++this.number);
74 this._labels[this._label] = ref;
75 if (this._refs[this._label]) this.fixRefs(this._label);
77 return this.formatLabel(ref);
80 isRef: function (element) {
81 var tex = element.innerHTML;
82 var result = tex.match(/^\s*\\ref\s*\{([^\}]+)\}\s*$/);
83 if (!result) {return 0}
85 if (this._labels[ref]) {
86 this.setRef(element,ref);
88 if (!this._refs[ref]) {this._refs[ref] = []}
89 this._refs[ref][this._refs[ref].length] = element;
94 setRef: function (element,ref) {
95 element.innerHTML = this.formatRef(this._labels[ref]);
96 element.className = "label-ref";
99 fixRefs: function (label) {
100 for (var i = 0; i < this._refs[label].length; i++)
101 {this.setRef(this._refs[label][i],label)}
102 delete this._refs[label];
105 badRefs: function () {
106 for (var label in this._refs) {
107 for (var i = 0; i < this._refs[label].length; i++) {
108 var element = this._refs[label][i];
109 element.className = "typeset";
110 element.innerHTML = "<span class='error'>Reference '"+label+"' is undefined</span>";
115 makeDIV: function (element) {
116 var div = document.createElement('div');
117 div.className = 'jsMath_displayBox';
118 div.innerHTML = '<div class="jsMath_number">' + this.nextNumber() + '</div>';
119 element.parentNode.insertBefore(div,element);
120 element.parentNode.removeChild(element);
121 div.appendChild(element);
124 makeSPAN: function (element) {
125 var span = document.createElement('span');
126 span.className = 'jsMath_number';
127 span.style.display = 'inline-block';
128 span.innerHTML = jsMath.EqnNumber.nextNumber();
129 element.parentNode.insertBefore(span,element);
132 ConvertMath: function (style,element,nocache) {
133 var EqnNumber = jsMath.EqnNumber;
134 if (EqnNumber.isRef(element)) return;
135 EqnNumber._label = null; EqnNumber._nolabel = 0;
136 this.ConvertMath_old(style,element,nocache);
137 if (EqnNumber._label || (EqnNumber.autonumber && !EqnNumber._nolabel)) {
138 if (element.tagName.toLowerCase() == 'div') {
139 EqnNumber.makeDIV(element);
140 } else if (element.parentNode.className == 'tex2math_div') {
141 EqnNumber.makeSPAN(element);
146 ProcessComplete: function () {
147 jsMath.EqnNumber.badRefs();
148 this.ProcessComplete_old.apply(this,arguments);
152 jsMath.Setup.Styles(this.styles);
153 jsMath.Translate.ConvertMath_old = jsMath.Translate.ConvertMath;
154 jsMath.Translate.ConvertMath = this.ConvertMath;
155 jsMath.Translate.ProcessComplete_old = jsMath.Translate.ProcessComplete;
156 jsMath.Translate.ProcessComplete = this.ProcessComplete;
165 align: ['StarExtension','AMSmath'],
166 multline: ['StarExtension','AMSmath'],
167 gather: ['StarExtension','AMSmath']
170 ResetStarEnvironments: function () {
171 var Nenv = jsMath.EqnNumber.environments;
172 var Penv = jsMath.Parser.prototype.environments;
173 for (var name in Nenv) {
174 if (name.match(/\*$/)) {Penv[name] = Nenv[name]}
180 if (jsMath.EqnNumber_old) {
181 jsMath.Insert(jsMath.EqnNumber,jsMath.EqnNumber_old);
182 delete jsMath.EqnNumber_old;
185 jsMath.Package(jsMath.Parser,{
193 environments: jsMath.EqnNumber.environments,
195 Label: function (name) {
196 var label = this.GetArgument(this.cmd+name); if (this.error) return;
197 var EqnNumber = jsMath.EqnNumber;
198 if (!EqnNumber._label) {
199 if (!EqnNumber._labels[label]) {
200 EqnNumber._label = label;
201 EqnNumber._nolabel = 0;
203 this.Error("Label '"+label+"' is already defined");
206 this.Error(this.cmd+name+' can only be used once in an equation');
210 NoLabel: function (name) {
211 var EqnNumber = jsMath.EqnNumber;
212 EqnNumber._label = null; EqnNumber._nolabel = 1;
215 Ref: function (name) {
216 this.Error(this.cmd+name+' must be used by itself');
219 Star: function (name) {
221 var cmd = this.environments[name.substr(0,name.length-1)];
222 if (typeof(cmd) === 'string') {cmd = [cmd]}
223 this[cmd[0]](name,cmd.slice(1));
226 StarExtension: function (name,data) {
227 try {this.Extension(name,data)} catch (e) {}
228 jsMath.Synchronize(jsMath.EqnNumber.ResetStarEnvironments);
234 jsMath.EqnNumber.Init();