Here's a rough outline of how we set things up at MathOverflow. As I understand it, only SO Inc. employees can perform administrative tasks (including loading javascript in the footer) on SE 2.0 sites, so this won't actually be useful to many people. But it should be pretty easy for SO to make into an option for SE sites. Some of it is crufty javascript workarounds that could be better implemented server side. Some of it is probably simply crufty because I'm not a javascript ninja; improvements are welcome.
We are currently using jsMath, but we'll be switching to jsMath's successor, MathJax, in the near future. The details will change slightly, but the basic idea will be the same.
The footer of every MO page loads the footer javascript, which I'll explain here.
Function for loading scripts from elsewhere ... nothing to see here:
loadScript=function(url,text){
var e = document.createElement('script');
e.type = "text/javascript";
e.src = url;
if (!text) text="";
e.text = text;
document.getElementsByTagName('head')[0].appendChild(e);
}
Now decide if math on the current page should be rendered. Since math gets rendered by javascript, it could be annoying for people to see things jumping around as math is being rendered on the home page. We don't render math on the home page or questions page by default, but we provide a way to set a cookie so that math is always rendered.
var path = window.location.pathname;
var isMath =
($.cookie("alwaysRenderMath")=="yes") ||
/^\/questions\/\d+/.test(path) || // Any of the question pages
/^\/questions\/ask/.test(path) || // Ask page
/^\/posts\//.test(path) || // Any edit page
/^\/revisions\//.test(path) || // Any revisions page
/^\/faq/.test(path) || // The FAQ
/^\/tips/.test(path) || // The tips page
/^\/users\/\d+/.test(path) || // The user pages
/^\/tools\/.+/.test(path) || // Various tools pages
false;
If the current page is supposed to be handled by jsMath, then load all the appropriate scripts and walk through the page to render any math.
Note that our approach of loading a bunch of scripts by hand is a bad one, subject to weird timing issues. The right way to load jsMath is to use the easy loader and set a bunch of preferences in a config file that lives wherever the jsMath files live. This way is sensitive to the exact order in which the various files are loaded. For some reason I still don't understand, the easy loader didn't work for us. Hopefully we won't have any such problems with MathJax.
Also note that we have latex.mathoverflow.net point to a server we control. Obviously, if this approach were implemented on SE sites, the same server would host the jsMath files.
if (isMath) {
jsMath = { Controls: { cookie: {scale: 110}, CheckVersion: function () {} } };
jsMath.Parser = {prototype: {macros: {
mathfrak: ['Macro','{\\eufm #1}',1],
operatorname: ['Macro','\\mathop{\\\\rm #1}',1],
implies: ['Macro','\\Rightarrow'],
Diamond: ['Macro','\\diamondsuit'],
mod: ['Macro', '\\mathop{\\rm mod}']
}}};
document.write('<script type="text/javascript" src="http://latex.mathoverflow.net/jsMath/jsMath.js"><\/script>');
loadScript("http://latex.mathoverflow.net/jsMath/extensions/AMSsymbols.js");
loadScript("http://latex.mathoverflow.net/jsMath/extensions/AMSmath.js");
loadScript("http://latex.mathoverflow.net/jsMath/extensions/autobold.js");
loadScript("http://latex.mathoverflow.net/jsMath/extensions/boldsymbol.js");
loadScript("http://latex.mathoverflow.net/jsMath/extensions/moreArrows.js");
loadScript("http://latex.mathoverflow.net/jsMath/extensions/verb.js");
$(document).ready(function(){
jsMath.Setup.Script("plugins/tex2math.js");
jsMath.Font.Load("eufm10");
jsMath.ConvertTeX();
jsMath.Process(document);
});
}
If the current page has a WMD editor, overwrite it with a custom version that renders math in the live preview (let me know if you want to know more details). Also append a checkbox which sets a cookie in case the user doesn't want math rendered in the live preview (it gets slow for some people). If they have the live preview disabled, give them a one-shot preview button.
// if the editor loads, use custom wmd.js and include preview button
if (window.Attacklab) {
// Neuter the original WMD control
Attacklab = {wmdBase : function(){},
Util: {startEditor:function(){}}
};
loadScript("/custom/wmd.js");
if ($.cookie("mathPreview") == null) { $.cookie("mathPreview","yes",{expires:365, path:"/"}); }; // true by default
var mathPreview = ($.cookie("mathPreview")=="yes");
mathPreviewSpan = document.createElement("span");
mathPreviewSpan.innerHTML = '<input type="checkbox" id="math-preview-box"> Preview Math ';
document.getElementById("post-editor").appendChild(mathPreviewSpan);
mathPreviewBox = document.getElementById("math-preview-box");
mathPreviewBox.checked = mathPreview;
mathPreviewBox.onchange = function(){
mathPreview = mathPreviewBox.checked;
$.cookie("mathPreview",mathPreview?"yes":"no",{expires:365, path:"/"});
previewButton.style.display = mathPreview?"none":"inline";
Attacklab.previewManager();
}
previewButton = document.createElement("input");
previewButton.type = "button";
previewButton.id = "math-preview-button";
previewButton.onclick = function(){ jsMath.ConvertTeX('wmd-preview');jsMath.ProcessBeforeShowing('wmd-preview'); };
previewButton.value = "One-shot preview";
previewButton.style.display = mathPreview?"none":"inline";
mathPreviewSpan.appendChild(previewButton);
}
If you're on a page where extra comments might be loaded, overwrite the javascript comments function with one that renders math after fetching additional comments from the server (let me know if you want more details).
// load custom comments if needed
if (typeof(window.comments)!="undefined") {
loadScript("/custom/comments.js");
}
If you're on the preference page, add a checkbox to allow users to set a preference cookie to always render math.
// load preference box for math on the home page
if (/\/users\/\d+\?tab=preferences/.test(window.location.href)) {
var alwaysRenderMath = ($.cookie("alwaysRenderMath")=="yes");
$("#optInEmail+label+br").after('<input type="checkbox" id="always-render-math-box"> Render math <i>all</i> pages, including the home page and questions pages. (Note: this simply sets a cookie, so this preference will not be remembered across browsers.)');
alwaysRenderMathBox = document.getElementById("always-render-math-box");
alwaysRenderMathBox.checked = alwaysRenderMath;
alwaysRenderMathBox.onchange = function(){
alwaysRenderMath = alwaysRenderMathBox.checked;
$.cookie("alwaysRenderMath",alwaysRenderMath?"yes":"no",{expires:365, path:"/"});
}
}