475 lines
17 KiB
JavaScript
Executable File
475 lines
17 KiB
JavaScript
Executable File
/*
|
|
* autoload.js
|
|
*
|
|
* Part of the jsMath package for mathematics on the web.
|
|
*
|
|
* This file is a plugin that checks if a page contains any math
|
|
* that must be processed by jsMath, and only loads jsMath.js
|
|
* when there is.
|
|
*
|
|
* You can control the items to look for via the variables
|
|
*
|
|
* jsMath.Autoload.findTeXstrings
|
|
* jsMath.Autoload.findLaTeXstrings
|
|
* jsMath.Autoload.findCustomStrings
|
|
* jsMath.Autoload.findCustomSettings
|
|
*
|
|
* which control whether to look for TeX strings that will be converted
|
|
* by jsMath.ConvertTeX(), or LaTeX strings that will be converted by
|
|
* jsMath.ConvertLaTeX(). By default, the first is true and the second
|
|
* and third are false. The findCustomStrings can be used to specify your
|
|
* own delimiters for in-line and display mathematics, e.g.
|
|
*
|
|
* jsMath.Autoload.findCustomStrings = [
|
|
* '[math],'[/math]', // start and end in-line math
|
|
* '[display]','[/display]' // start and end display math
|
|
* ];
|
|
*
|
|
* Finally, findCustomSettings can be set to an object reference whose
|
|
* name:value pairs control the individual search settings for tex2math.
|
|
* (See the plugins/tex2math.js file for more details).
|
|
*
|
|
* If any math strings are found, jsMath.js will be loaded automatically,
|
|
* but not loaded otherwise. If any of the last four are set and TeX math
|
|
* strings are found, then plugins/tex2ath.js will be loaded
|
|
* automatically. jsMath.Autoload.needsJsMath will be set to true or
|
|
* false depending on whether jsMath needed to be loaded.
|
|
*
|
|
* The value of jsMath.Autoload.checkElement controls the element to be
|
|
* searched by the autoload plug-in. If unset, the complete document will
|
|
* be searched. If set to a string, the element with that name will be
|
|
* searched. If set to a DOM object, that object and its children will
|
|
* be searched.
|
|
*
|
|
* Finally, there are two additional parameters that control files to
|
|
* be loaded after jsMath.js, should it be needed. These are
|
|
*
|
|
* jsMath.Autoload.loadFonts
|
|
* jsMath.Autoload.loadFiles
|
|
*
|
|
* If jsMath.js is loaded, the fonts contained in the loadFonts array
|
|
* will be loaded, and the JavaScript files listed in the loadFiles array
|
|
* will be run. Relative URL's are loaded based from the URL containing
|
|
* jsMath.js.
|
|
*
|
|
* The autoload plugin can be loaded in the document HEAD or in the BODY.
|
|
* If it is loaded in the HEAD, you will need to call jsMath.Autoload.Check()
|
|
* at the end of the BODY (say in the window.onload handler) in order to
|
|
* get it to check the page for math that needs to be tagged, otherwise load
|
|
* the file at the bottom of the BODY and it will run the check automatically.
|
|
*
|
|
* You can call jsMath.Autoload.Run() after the check has been performed
|
|
* in order to call the appropriate tex2math routines for the given Autoload
|
|
* settings. You can call jsMath.Autoload.Run() even when jsMath isn't loaded.
|
|
*
|
|
* ---------------------------------------------------------------------
|
|
*
|
|
* Copyright 2004-2006 by Davide P. Cervone
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
/*************************************************************************/
|
|
|
|
/*
|
|
* Make sure jsMath.Autoload is available
|
|
*/
|
|
if (!window.jsMath) {window.jsMath = {}}
|
|
if (jsMath.Autoload == null) {jsMath.Autoload = {}}
|
|
jsMath.Add = function (dst,src) {for (var id in src) {dst[id] = src[id]}};
|
|
jsMath.document = document; // tex2math needs this
|
|
|
|
jsMath.Add(jsMath.Autoload,{
|
|
|
|
Script: {
|
|
|
|
request: null, // XMLHttpRequest object (if we can get it)
|
|
iframe: null, // the hidden iframe (if not)
|
|
operaXMLHttpRequestBug: (window.opera != null), // is Opera browser
|
|
|
|
/*
|
|
* Get XMLHttpRequest object, if possible, and look up the URL root
|
|
* (MSIE can't use xmlReuest to load local files, so avoid that)
|
|
*/
|
|
Init: function () {
|
|
this.Root();
|
|
if (window.XMLHttpRequest) {
|
|
try {this.request = new XMLHttpRequest} catch (err) {}
|
|
// MSIE and FireFox3 can't use xmlRequest on local files,
|
|
// but we don't have jsMath.browser yet to tell, so use this check
|
|
if (this.request && window.location.protocol == "file:") {
|
|
try {
|
|
this.request.open("GET",jsMath.Autoload.root+"plugins/autoload.js",false);
|
|
this.request.send(null);
|
|
} catch (err) {
|
|
this.request = null;
|
|
// Firefox3 has window.postMessage for inter-window communication.
|
|
// It can be used to handle the new file:// security model,
|
|
// so set up the listener.
|
|
if (window.postMessage && window.addEventListener) {
|
|
this.mustPost = 1;
|
|
window.addEventListener("message",jsMath.Autoload.Post.Listener,false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!this.request && window.ActiveXObject && !this.mustPost) {
|
|
var xml = ["MSXML2.XMLHTTP.5.0","MSXML2.XMLHTTP.4.0","MSXML2.XMLHTTP.3.0",
|
|
"MSXML2.XMLHTTP","Microsoft.XMLHTTP"];
|
|
for (var i = 0; i < xml.length && !this.request; i++) {
|
|
try {this.request = new ActiveXObject(xml[i])} catch (err) {}
|
|
}
|
|
}
|
|
},
|
|
|
|
/*
|
|
* Load an external JavaScript file
|
|
*/
|
|
Load: function (url) {
|
|
if (this.request && !(this.operaXMLHttpRequestBug && url == 'jsMath.js')) {
|
|
setTimeout(function () {jsMath.Autoload.Script.xmlLoad(url)},1);
|
|
} else {
|
|
this.startLoad(url);
|
|
}
|
|
},
|
|
|
|
/*
|
|
* Load an external JavaScript file via XMLHttpRequest
|
|
*/
|
|
xmlLoad: function (url) {
|
|
try {
|
|
this.request.open("GET",jsMath.Autoload.root+url,false);
|
|
this.request.send(null);
|
|
} catch (err) {
|
|
throw Error("autoload: can't load the file '"+url+"'\n"
|
|
+ "Message: "+err.message);
|
|
}
|
|
if (this.request.status && this.request.status >= 400) {
|
|
throw Error("autoload: can't load the file '"+url+"'\n"
|
|
+ "Error status: "+this.request.status);
|
|
}
|
|
window.eval(this.request.responseText);
|
|
this.endLoad();
|
|
},
|
|
|
|
/*
|
|
* Load an external JavaScript file via jsMath-autoload.html
|
|
*/
|
|
startLoad: function (url) {
|
|
this.iframe = document.createElement('iframe');
|
|
this.iframe.style.visibility = 'hidden';
|
|
this.iframe.style.position = 'absolute';
|
|
this.iframe.style.width = '0px';
|
|
this.iframe.style.height = '0px';
|
|
if (document.body.firstChild) {
|
|
document.body.insertBefore(this.iframe,document.body.firstChild);
|
|
} else {
|
|
document.body.appendChild(this.iframe);
|
|
}
|
|
this.url = url; setTimeout('jsMath.Autoload.Script.setURL()',100);
|
|
},
|
|
endLoad: function () {setTimeout('jsMath.Autoload.Script.AfterLoad()',1)},
|
|
|
|
/*
|
|
* Use location.replace() to avoid browsers placing the file in
|
|
* the history (and messing up the BACK button action). Not
|
|
* completely effective in Firefox 1.0.x. Safari won't handle
|
|
* replace() if the document is local (not sure if that's really
|
|
* the issue, but that's the only time I see it).
|
|
*/
|
|
setURL: function () {
|
|
if (this.mustPost) {
|
|
this.iframe.src = jsMath.Autoload.Post.startLoad(this.url,this.iframe);
|
|
} else {
|
|
var url = jsMath.Autoload.root+"jsMath-autoload.html";
|
|
var doc = this.iframe.contentDocument;
|
|
if (!doc && this.iframe.contentWindow) {doc = this.iframe.contentWindow.document}
|
|
if (navigator.vendor == "Apple Computer, Inc." &&
|
|
document.location.protocol == 'file:') {doc = null}
|
|
if (doc) {doc.location.replace(url)} else {this.iframe.src = url}
|
|
}
|
|
},
|
|
|
|
/*
|
|
* Queue items that need to be postponed until jsMath has run
|
|
*/
|
|
queue: [],
|
|
Push: function (name,data) {this.queue[this.queue.length] = [name,data]},
|
|
RunStack: function () {
|
|
if (this.tex2math) {jsMath.Autoload.Check2(); return}
|
|
for (var i = 0; i < this.queue.length; i++) {
|
|
var name = this.queue[i][0];
|
|
var data = this.queue[i][1];
|
|
if (data.length == 1) {jsMath[name](data[0])}
|
|
else {jsMath[name](data[0],data[1],data[2],data[3])}
|
|
}
|
|
this.queue = [];
|
|
},
|
|
|
|
AfterLoad: function () {jsMath.Autoload.Script.RunStack()},
|
|
|
|
/*
|
|
* Look up the jsMath root directory, if it is not already supplied
|
|
*/
|
|
Root: function () {
|
|
if (jsMath.Autoload.root) return;
|
|
var script = document.getElementsByTagName('script');
|
|
if (script) {
|
|
for (var i = 0; i < script.length; i++) {
|
|
var src = script[i].src;
|
|
if (src && src.match('(^|/|\\\\)plugins/autoload.js$')) {
|
|
jsMath.Autoload.root = src.replace(/plugins\/autoload.js$/,'');
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
},
|
|
|
|
/*
|
|
* Handle window.postMessage() events in Firefox3
|
|
*/
|
|
Post: {
|
|
window: null, // iframe we are ing to
|
|
|
|
Listener: function (event) {
|
|
if (event.source != jsMath.Autoload.Post.window) return;
|
|
var domain = event.origin.replace(/^file:\/\//,'');
|
|
var ddomain = document.domain.replace(/^file:\/\//,'');
|
|
if (domain == null || domain == "" || domain == "null") {domain = "localhost"}
|
|
if (ddomain == null || ddomain == "" || ddomain == "null") {ddomain = "localhost"}
|
|
if (domain != ddomain || event.data.substr(0,6) != "jsMAL:") return;
|
|
var type = event.data.substr(6,3).replace(/ /g,'');
|
|
var message = event.data.substr(10);
|
|
if (jsMath.Autoload.Post.Commands[type]) (jsMath.Autoload.Post.Commands[type])(message);
|
|
// cancel event?
|
|
},
|
|
|
|
/*
|
|
* Commands that can be performed by the listener
|
|
*/
|
|
Commands: {
|
|
SCR: function (message) {window.eval(message)},
|
|
ERR: function (message) {jsMath.Autoload.Script.endLoad()},
|
|
END: function (message) {jsMath.Autoload.Script.endLoad()}
|
|
},
|
|
|
|
startLoad: function (url,iframe) {
|
|
this.window = iframe.contentWindow;
|
|
return jsMath.Autoload.root+"jsMath-loader-post.html?autoload="+url;
|
|
},
|
|
|
|
endLoad: function () {
|
|
this.window = null;
|
|
}
|
|
},
|
|
|
|
|
|
/**************************************************************/
|
|
|
|
/*
|
|
* Load tex2math first (so we can call its search functions
|
|
* to look to see if anything needs to be turned into math)
|
|
* if it is needed, otherwise go on to the second check.
|
|
*/
|
|
Check: function () {
|
|
if (this.checked) return; this.checked = 1;
|
|
if ((this.findTeXstrings || this.findLaTeXstrings ||
|
|
this.findCustomStrings || this.findCustomSettings) &&
|
|
(!jsMath.tex2math || !jsMath.tex2math.loaded)) {
|
|
this.Script.tex2math = 1;
|
|
this.Script.Load('plugins/tex2math.js');
|
|
} else {
|
|
if (!jsMath.tex2math) {jsMath.tex2math = {}}
|
|
this.Check2();
|
|
}
|
|
},
|
|
ReCheck: function () {
|
|
if (jsMath.loaded) return;
|
|
this.InitStubs();
|
|
this.checked = 0;
|
|
this.Script.queue = [];
|
|
this.Check();
|
|
},
|
|
|
|
/*
|
|
* Once tex2math is loaded, use it to check for math that
|
|
* needs to be tagged for jsMath, and load jsMath if it is needed
|
|
*/
|
|
Check2: function () {
|
|
this.Script.tex2math = 0; this.needsJsMath = 0;
|
|
if (this.checkElement == null) {this.checkElement = null}
|
|
|
|
if (this.findTeXstrings) {jsMath.tex2math.ConvertTeX(this.checkElement)}
|
|
if (this.findLaTeXstrings) {jsMath.tex2math.ConvertLaTeX(this.checkElement)}
|
|
if (this.findCustomSettings) {jsMath.tex2math.Convert(this.checkElement,this.findCustomSettings)}
|
|
if (this.findCustomStrings) {
|
|
var s = this.findCustomStrings;
|
|
jsMath.tex2math.CustomSearch(s[0],s[1],s[2],s[3]);
|
|
jsMath.tex2math.ConvertCustom(this.checkElement);
|
|
}
|
|
|
|
this.needsJsMath = this.areMathElements(this.checkElement);
|
|
if (this.needsJsMath) {
|
|
this.LoadJsMath();
|
|
} else {
|
|
jsMath.Process = function () {};
|
|
jsMath.ProcessBeforeShowing = function () {};
|
|
jsMath.ProcessElement = function () {};
|
|
jsMath.ConvertTeX = function () {};
|
|
jsMath.ConvertTeX2 = function () {};
|
|
jsMath.ConvertLaTeX = function () {};
|
|
jsMath.ConvertCustom = function () {};
|
|
jsMath.CustomSearch = function () {};
|
|
jsMath.Macro = function () {};
|
|
jsMath.Synchronize = function (code,data) {
|
|
if (typeof(code) == 'string') {eval(code)} else {code(data)}
|
|
};
|
|
jsMath.Autoload.Script.RunStack(); // perform pending commands
|
|
jsMath.Autoload.setMessage();
|
|
}
|
|
},
|
|
|
|
/*
|
|
* A callback used in the tex2math searches to signal that
|
|
* some math has been found.
|
|
*/
|
|
tex2mathCallback: function () {
|
|
jsMath.Autoload.needsJsMath = 1;
|
|
return false;
|
|
},
|
|
|
|
/*
|
|
* jsMath.Autoload.Run() is now longer needed
|
|
*/
|
|
Run: function (data) {},
|
|
|
|
/*
|
|
* Look to see if there are SPAN or DIV elements of class "math".
|
|
*/
|
|
areMathElements: function (obj) {
|
|
if (!obj) {obj = document}
|
|
if (typeof(obj) == 'string') {obj = document.getElementById(obj)}
|
|
if (!obj.getElementsByTagName) {return false}
|
|
var math = obj.getElementsByTagName('div');
|
|
for (var k = 0; k < math.length; k++)
|
|
{if (math[k].className.match(/(^| )math( |$)/)) {return true}}
|
|
math = obj.getElementsByTagName('span');
|
|
for (var k = 0; k < math.length; k++)
|
|
{if (math[k].className.match(/(^| )math( |$)/)) {return true}}
|
|
return false;
|
|
},
|
|
|
|
/*
|
|
* When math tags are found, load the jsMath.js file,
|
|
* and afterward, load any auxiliary files or fonts,
|
|
* and then do any pending commands.
|
|
*/
|
|
LoadJsMath: function () {
|
|
if (this.loading) return;
|
|
if (jsMath.loaded) {this.afterLoad(); return}
|
|
if (this.root) {
|
|
this.loading = 1;
|
|
this.setMessage('Loading jsMath...');
|
|
this.Script.AfterLoad = this.afterLoad;
|
|
this.Script.Load('jsMath.js');
|
|
} else {
|
|
alert("Can't determine URL for jsMath.js");
|
|
}
|
|
},
|
|
afterLoad: function () {
|
|
jsMath.Autoload.loading = 0;
|
|
//
|
|
// Handle MSIE bug where jsMath.window both is and is not the actual window
|
|
//
|
|
if (jsMath.tex2math.window) {jsMath.tex2math.window.jsMath = jsMath}
|
|
if (jsMath.browser == 'MSIE') {window.onscroll = jsMath.window.onscroll};
|
|
var fonts = jsMath.Autoload.loadFonts;
|
|
if (fonts) {
|
|
if (typeof(fonts) != 'object') {fonts = [fonts]}
|
|
for (var i = 0; i < fonts.length; i++) {jsMath.Font.Load(fonts[i])}
|
|
}
|
|
var files = jsMath.Autoload.loadFiles;
|
|
if (files) {
|
|
if (typeof(files) != 'object') {files = [files]}
|
|
for (var i = 0; i < files.length; i++) {jsMath.Setup.Script(files[i])}
|
|
}
|
|
var macros = jsMath.Autoload.macros;
|
|
if (macros) {
|
|
for (var id in macros) {
|
|
if (typeof(macros[id]) == 'string') {
|
|
jsMath.Macro(id,macros[id]);
|
|
} else {
|
|
jsMath.Macro(id,macros[id][0],macros[id][1]);
|
|
}
|
|
}
|
|
}
|
|
jsMath.Synchronize(function () {jsMath.Autoload.Script.RunStack()});
|
|
jsMath.Autoload.setMessage();
|
|
},
|
|
|
|
/*
|
|
* Display a message in a small box at the bottom of the screen
|
|
*/
|
|
setMessage: function (message) {
|
|
if (message) {
|
|
this.div = document.createElement('div');
|
|
if (!document.body.hasChildNodes) {document.body.appendChild(this.div)}
|
|
else {document.body.insertBefore(this.div,document.body.firstChild)}
|
|
var style = {
|
|
position:'fixed', bottom:'1px', left:'2px',
|
|
backgroundColor:'#E6E6E6', border:'solid 1px #959595',
|
|
margin:'0px', padding:'1px 8px', zIndex:102,
|
|
color:'black', fontSize:'75%', width:'auto'
|
|
};
|
|
for (var id in style) {this.div.style[id] = style[id]}
|
|
this.div.id = "jsMath_message";
|
|
this.div.appendChild(jsMath.document.createTextNode(message));
|
|
} else if (this.div) {
|
|
this.div.firstChild.nodeValue = "";
|
|
this.div.style.visibility = 'hidden';
|
|
}
|
|
},
|
|
|
|
/*
|
|
* Queue these so we can do them after jsMath has been loaded
|
|
*/
|
|
stubs: {
|
|
Process: function (data) {jsMath.Autoload.Script.Push('Process',[data])},
|
|
ProcessBeforeShowing: function (data) {jsMath.Autoload.Script.Push('ProcessBeforeShowing',[data])},
|
|
ProcessElement: function (data) {jsMath.Autoload.Script.Push('ProcessElement',[data])},
|
|
ConvertTeX: function (data) {jsMath.Autoload.Script.Push('ConvertTeX',[data])},
|
|
ConvertTeX2: function (data) {jsMath.Autoload.Script.Push('ConvertTeX2',[data])},
|
|
ConvertLaTeX: function (data) {jsMath.Autoload.Script.Push('ConvertLaTeX',[data])},
|
|
ConvertCustom: function (data) {jsMath.Autoload.Script.Push('ConvertCustom',[data])},
|
|
CustomSearch: function (d1,d2,d3,d4) {jsMath.Autoload.Script.Push('CustomSearch',[d1,d2,d3,d4])},
|
|
Synchronize: function (data) {jsMath.Autoload.Script.Push('Synchronize',[data])},
|
|
Macro: function (cs,def,params) {jsMath.Autoload.Script.Push('Macro',[cs,def,params])}
|
|
},
|
|
|
|
InitStubs: function () {jsMath.Add(jsMath,jsMath.Autoload.stubs)}
|
|
|
|
});
|
|
|
|
/*
|
|
* Initialize
|
|
*/
|
|
|
|
if (jsMath.Autoload.findTeXstrings == null) {jsMath.Autoload.findTeXstrings = 0}
|
|
if (jsMath.Autoload.findLaTeXstrings == null) {jsMath.Autoload.findLaTeXstrings = 0}
|
|
|
|
jsMath.Autoload.Script.Init();
|
|
jsMath.Autoload.InitStubs();
|
|
if (document.body && !jsMath.Autoload.delayCheck) {jsMath.Autoload.Check()}
|