--- loncom/html/adm/jsMath/jsMath.js 2005/02/25 04:57:49 1.1 +++ loncom/html/adm/jsMath/jsMath.js 2005/12/07 18:57:45 1.2 @@ -2,8 +2,6 @@ * * jsMath: Mathematics on the Web * - * Version: 1.7e - * * This jsMath package makes it possible to display mathematics in HTML pages * that are viewable by a wide range of browsers on both the Mac and the IBM PC, * including browsers that don't process MathML. See @@ -33,7 +31,8 @@ /* * Prevent running everything again if this file is loaded twice */ -if (!window.jsMath) { +if (!jsMath || !jsMath.loaded) { +var jsMath_old = jsMath; // save user customizations // // debugging routine @@ -66,80 +65,19 @@ if (!document.getElementById || !documen /***************************************************************************/ var jsMath = { - + + version: "2.4b", // change this if you edit the file + // // Name of image files // blank: "blank.gif", - black: "black.gif", - - // - // The TeX font parameters - // - TeX: { - thinmuskip: 3/18, - medmuskip: 4/18, - thickmuskip: 5/18, - - x_height: .430554, - quad: 1, - num1: .676508, - num2: .393732, - num3: .44373, - denom1: .685951, - denom2: .344841, - sup1: .412892, - sup2: .362892, - sup3: .288888, - sub1: .15, - sub2: .247217, - sup_drop: .386108, - sub_drop: .05, - delim1: 2.39, - delim2: 1.0, - axis_height: .25, - default_rule_thickness: .04, - big_op_spacing1: .111111, - big_op_spacing2: .166666, - big_op_spacing3: .2, - big_op_spacing4: .6, - big_op_spacing5: .1, - - integer: 6553.6, // conversion of em's to TeX internal integer - scriptspace: .05, - nulldelimiterspace: .12, - delimiterfactor: 901, - delimitershortfall: .5, - scale: 1 // scaling factor for font dimensions - }, + defaultH: 0, // default height for characters with none specified + // Font sizes for \tiny, \small, etc. (must match styles below) sizes: [50, 60, 70, 85, 100, 120, 144, 173, 207, 249], - allowAbsolute: 1, // tells if browser can nest absolutely positioned - // SPANs inside relative SPANs - absoluteOffsetY: 0, // vertical adjustment when absolute position is used - allowAbsoluteDelim: 0, // OK to use absolute placement for building delims? - renameOK: 1, // tells if brower will find a tag whose name - // has been set via setAttributes - separateNetgativeSkips: 0, // MSIE doesn't do negative left margins - separateSkips: 0, // Netscape doesn't combine skips well - noEmptySpans: 0, // empty spans are/aren't allowed - msieSpaceFix: '', // for MSIE spacing bug fix - - delay: 1, // delay for asynchronous math processing - - defaultH: 0, // default height for characters with no height specified - - // - // Debugging flags - // - show: { - BBox: false, - Baseline: false, - Top: false - }, - // // The styles needed for the TeX fonts // @@ -155,37 +93,55 @@ var jsMath = { '.size8': 'font-size: 207%', // huge '.size9': 'font-size: 249%', // Huge - '.cmr10': 'font-family: cmr10', + '.cmr10': 'font-family: cmr10, serif', '.cmbx10': 'font-family: cmbx10, cmr10', '.cmti10': 'font-family: cmti10, cmr10', '.cmmi10': 'font-family: cmmi10', '.cmsy10': 'font-family: cmsy10', '.cmex10': 'font-family: cmex10', - '.arial': 'font-family: Arial unicode MS', // for MSIE - - '.normal': 'font-family: serif; font-style: normal', - '.math': 'font-family: serif; font-style: normal', - '.typeset': 'font-family: serif; font-style: normal', - 'span.typeset': 'font-family: serif; font-style: normal', - 'div.typeset': 'font-family: serif; font-style: normal; text-align: center; margin-top: 1em; margin-bottom: 1em', + + '.math': 'font-family: serif; font-style: normal; font-weight: normal', + '.typeset': 'font-family: serif; font-style: normal; font-weight: normal', + '.normal': 'font-family: serif; font-style: normal; font-weight: normal; ' + + 'padding:0px; border:0px; margin:0px;', + 'span.typeset': '', + 'div.typeset': 'text-align: center; margin: 1em 0px;', '.mathlink': 'text-decoration: none', - '.mathHD': 'border-width: 0; width: 1px; margin-right: -1px', + '.mathHD': 'border-width:0px; width: 1px; margin-right: -1px', '.error': 'font-size: 10pt; font-style: italic; ' - + 'background-color: #FFFFCC; padding: 1; ' - + 'border-width: 1; border-style: solid; border-color: #CC0000' - }, + + 'background-color: #FFFFCC; padding: 1px; ' + + 'border: 1px solid #CC0000', + '.jsM_panel': 'position:fixed; bottom:1.5em; right:1.5em; padding: 10px 20px; ' + + 'background-color:#DDDDDD; border: outset 2px; ' + + 'z-index:103; width:auto;', + '.jsM_button': 'position:fixed; bottom:1px; right:2px; background-color:white; ' + + 'border: solid 1px #959595; margin:0px; padding: 0px 3px 1px 3px; ' + + 'z-index:102; color:black; text-decoration:none; font-size:x-small; width:auto;', + '.jsM_float': 'position:absolute; top:0px; left:0px; max-width:80%; ' + + 'z-index:101; width:auto; height:auto;', + '.jsM_drag': 'background-color:#DDDDDD; border: outset 1px; height:12px; font-size: 1px;', + '.jsM_close': 'background-color:#E6E6E6; border: inset 1px; width:8px; height:8px; margin: 1px 2px;', + '.jsM_source': 'background-color:#E2E2E2; border: outset 1px; ' + + 'width:auto; height:auto; padding: 8px 15px; ' + + 'font-family: courier, fixed; font-size: 90%', + '.jsM_noFont': 'text-align: center; padding: 10px 20px; border: 3px solid #DD0000; ' + + ' background-color: #FFF8F8; color: #AA0000; font-size:small; width:auto;', + '.jsM_fontLink': 'padding: 0px 5px 2px 5px; text-decoration:none; color:black;' + + ' border: 2px outset; background-color:#E8E8E8; font-size:80%; width:auto;' + }, + /***************************************************************************/ /* * Get the width and height (in pixels) of an HTML string */ BBoxFor: function (s) { - this.hidden.innerHTML = s; + this.hidden.innerHTML = ''+s+''; var bbox = {w: this.hidden.offsetWidth, h: this.hidden.offsetHeight}; - this.hidden.innerHTML = ''; // avoid MSIE bug on the Mac + this.hidden.innerHTML = ''; return bbox; }, @@ -198,155 +154,237 @@ var jsMath = { }, /* - * Determine if the "top" of a is always at the same height - * or varies with the height of the rest of the line (MSIE). + * For browsers that don't handle sizes of italics properly (MSIE) */ - TestSpanHeight: function () { - this.hidden.innerHTML = ''; - var span = this.hidden.getElementsByTagName('SPAN')[0]; - var img = this.hidden.getElementsByTagName('IMG')[0]; - this.spanHeightVaries = (span.offsetHeight == img.offsetHeight); - this.hidden.innerHTML = ''; + EmBoxForItalics: function (s) { + var bbox = this.BBoxFor(s); + if (s.match(/|CLASS="icm/i)) { + bbox.w = this.BBoxFor(s+jsMath.Browser.italicString).w + - jsMath.Browser.italicCorrection; + } + return {w: bbox.w/this.em, h: bbox.h/this.em}; }, - + /* - * Determine if the NAME attribute of a tag can be changed - * using the setAttribute function, and then be properly - * returned by getElementByName. + * Initialize jsMath. This determines the em size, and a variety + * of other parameters used throughout jsMath. */ - TestRenameOK: function () { - this.hidden.innerHTML = ''; - var test = document.getElementById('jsMath.test'); - test.setAttribute('NAME','jsMath_test'); - this.renameOK = (document.getElementsByName('jsMath_test').length > 0); - this.hidden.innerHTML = ''; - }, + Init: function () { + if (jsMath.Setup.inited != 1) { + if (jsMath.Setup.inited) { + alert("It looks like jsMath failed to set up properly."); + } else { + alert("You must call jsMath.Setup.Body() explicitly when jsMath is" + + "loaded as part of the section"); + } + jsMath.Setup.Init(); // may fail to load fallback files properly + } + this.em = this.BBoxFor('').w/10; + if (jsMath.Browser.italicString) + jsMath.Browser.italicCorrection = jsMath.BBoxFor(jsMath.Browser.italicString).w; + if (jsMath.Browser.hiddenSpace != '') { + jsMath.Browser.spaceWidth = + this.EmBoxFor(jsMath.Browser.hiddenSpace + + jsMath.Browser.hiddenSpace + + jsMath.Browser.hiddenSpace + + jsMath.Browser.hiddenSpace + + jsMath.Browser.hiddenSpace).w/5; + } + var bb = this.BBoxFor('x'); var h = bb.h; + var d = this.BBoxFor('x').h - h; + this.h = (h-d)/this.em; this.d = d/this.em; + this.hd = this.h + this.d; + this.xWidth = bb.w; // used to tell if scale has changed + + this.Setup.TeXfonts(); + + var x_height = this.EmBoxFor('M').w/2; + this.TeX.M_height = x_height*(26/14); + this.TeX.h = this.h; this.TeX.d = this.d; this.TeX.hd = this.hd; + + this.Img.Scale(); + if (!this.initialized) { + this.Setup.Sizes(); + this.Img.UpdateFonts(); + } + + // factor for \big and its brethren + this.p_height = (this.TeX.cmex10[0].h + this.TeX.cmex10[0].d) / .85; + this.initialized = 1; + }, + /* - * Look to see if a font is found. HACK! - * Check the character in the '|' position, and see if it is - * wider than the usual '|'. + * Get the xWidth size and if it has changed, reinitialize the sizes */ - TestFont: function (name,n,factor) { - if (n == null) {n = 124}; if (factor == null) {factor = 2} - var wh1 = this.BBoxFor(''+this.TeX[name][n].c+''); - var wh2 = this.BBoxFor(''+this.TeX[name][n].c+''); - return (wh1.w > factor*wh2.w && wh1.h != 0); + ReInit: function () { + var w = this.BBoxFor('x').w; + if (w != this.xWidth) {this.Init()} }, - - TestFont2: function (name,n,factor) { - if (n == null) {n = 124}; if (factor == null) {factor = 2} - var wh1 = this.BBoxFor(''+this.TeX[name][n].c+''); - var wh2 = this.BBoxFor(''+this.TeX[name][n].c+''); - return (wh2.w > factor*wh1.w && wh1.h != 0); + + /* + * Mark jsMath as loaded and copy any user-provided overrides + */ + Loaded: function () { + this.Insert(jsMath,jsMath_old); + jsMath_old = null; + jsMath.loaded = 1; }, /* - * Check for the availability of TeX fonts. We do this by looking at - * the width and height of a character in the cmex10 font. The cmex10 - * font has depth considerably greater than most characters' widths (the - * whole font has the depth of the character with greatest depth). This - * is not the case for most fonts, so if we can access cmex10, the - * height of a character should be much bigger than the width. - * Otherwise, if we don't have cmex10, we'll get a character in another - * font with normal height and width. In this case, we insert a message - * pointing the user to the jsMath site, and load one of the fallback - * definitions. + * Manage JavaScript objects: * - */ - CheckFonts: function () { - jsMath.nofonts = 0; - var wh = this.BBoxFor(''+this.TeX.cmex10[1].c+''); - if (wh.w*3 < wh.h && wh.h != 0) return; - if (this.TestFont('cmr10')) return; - if (window.NoFontMessage) {window.NoFontMessage()} else {this.NoFontMessage()} - if (navigator.platform == 'Win32') { - document.writeln(''); - } else if (navigator.platform == 'MacPPC') { - document.writeln(''); - } else { - // default to unix? Is there a better way to tell if unix? - document.writeln(''); + * Add: add/replace items in an object + * Insert: add items to an object + * Package: add items to an object prototype + */ + Add: function (dst,src) {for (var id in src) {dst[id] = src[id]}}, + Insert: function (dst,src) { + for (var id in src) { + if (dst[id] && typeof(src[id]) == 'object' + && (typeof(dst[id]) == 'object' + || typeof(dst[id]) == 'function')) { + this.Insert(dst[id],src[id]); + } else { + dst[id] = src[id]; + } } - jsMath.nofonts = 1; }, + Package: function (obj,def) {this.Insert(obj.prototype,def)} + +} +/***************************************************************************/ + +/* + * Miscellaneous setup and initialization + */ +jsMath.Setup = { + /* - * The message for when no TeX fonts. You can eliminate this message - * by including - * - * - * - * in your HTML file, if you want. But this means the user may not know - * that he or she can get a better version of your page. + * Insert a DIV at the top of the page with given ID, + * attributes, and style settings */ - NoFontMessage: function () { - document.writeln - ('
' - +'Warning:\n' - +'It looks like you don\'t have the TeX math fonts installed.\n' - +'The mathematics on this page may not look right without them.\n' - +'The ' - +'jsMath Home Page has information on how to download the\n' - +'needed fonts. In the meantime, we will do the best we can\n' - +'with the fonts you have, but it may not be pretty and some equations\n' - +'may not be rendered correctly.\n' - +'


'); + TopHTML: function (id,attributes,styles) { + try { + var div = document.createElement('div'); + div.setAttribute("id",'jsMath.'+id); + for (var i in attributes) { + div.setAttribute(i,attributes[i]); + if (i == "class") {div.setAttribute('className',attributes[i])} // MSIE + } + for (var i in styles) {div.style[i]= styles[i]} + if (!document.body.hasChildNodes) {document.body.appendChild(div)} + else {document.body.insertBefore(div,document.body.firstChild)} + } catch (err) { + var html = '

').w/20; - var h = this.BBoxFor('x').h; // Line height and depth to baseline - var d = this.BBoxFor('x').h - h; - this.h = (h-d)/this.em; this.d = d/this.em; - this.hd = this.h + this.d; - this.ph = h-d; this.pd = d; - - this.InitTeXfonts(); - - var x_height = this.EmBoxFor('M').w/2; - this.TeX.M_height = x_height*(26/14); - this.TeX.h = this.h; this.TeX.d = this.d; this.TeX.hd = this.hd; - // factor for \big and its brethren - this.p_height = (this.TeX.cmex10[0].h+this.TeX.cmex10[0].d) / .85; - - this.InitSizes(); - - this.initialized = 1; + Script: function (file) { + if (!file.match('^([a-zA-Z]+:/)?/')) {file = jsMath.root + file} + document.write(''); + }, + + /* + * Use a hidden
for measuring the BBoxes of things + */ + HTML: function () { + jsMath.hidden = this.TopHTML("Hidden",{'class':"normal"},{ + position:"absolute", top:0, left:0, border:0, padding:0, margin:0 + }); + jsMath.hiddenTop = jsMath.hidden; + return; }, /* * Find the root URL for the jsMath files (so we can load - * the other .js and .gif files + * the other .js and .gif files) */ - InitSource: function () { + Source: function () { var script = document.getElementsByTagName('SCRIPT'); - var src = script[script.length-1].getAttribute('SRC'); - if (src.match('(^|/)jsMath.js$')) { - this.root = src.replace(/jsMath.js$/,''); - this.blank = this.root + this.blank; - this.black = this.root + this.black; + if (script) { + for (var i = 0; i < script.length; i++) { + var src = script[i].src; + if (src && src.match('(^|/)jsMath.js$')) { + jsMath.root = src.replace(/jsMath.js$/,''); + jsMath.Img.root = jsMath.root + "fonts/"; + jsMath.blank = jsMath.root + jsMath.blank; + this.Domain(); + return; + } + } + } + jsMath.root = ''; jsMath.Img.root = "fonts/"; + }, + + /* + * Find the most restricted common domain for the main + * page and jsMath. Report an error if jsMath is outside + * the domain of the calling page. + */ + Domain: function () { + var jsDomain = ''; var pageDomain = document.domain; + if (jsMath.root.match('://([^/]*)/')) {jsDomain = RegExp.$1} + jsDomain = jsDomain.replace(/:\d+$/,''); + if (jsDomain == "" || jsDomain == pageDomain) return; + // + // MSIE on the Mac can't change document.domain and 'try' won't + // catch the error (Grrr!), so exit for them + // + if (navigator.appName == 'Microsoft Internet Explorer' && + navigator.platform == 'MacPPC' && navigator.onLine && + navigator.userProfile && document.all) return; + jsDomain = jsDomain.split(/\./); pageDomain = pageDomain.split(/\./); + if (jsDomain.length < 2 || pageDomain.length < 2 || + jsDomain[jsDomain.length-1] != pageDomain[pageDomain.length-1] || + jsDomain[jsDomain.length-2] != pageDomain[pageDomain.length-2]) { + this.DomainWarning(); + return; } + var domain = jsDomain[jsDomain.length-2] + '.' + jsDomain[jsDomain.length-1]; + for (var i = 3; i <= jsDomain.length && i <= pageDomain.length; i++) { + if (jsDomain[jsDomain.length-i] != pageDomain[pageDomain.length-i]) break; + domain = jsDomain[jsDomain.length-i] + '.' + domain; + } + document.domain = domain; + }, + + DomainWarning: function () { + alert("In order for jsMath to be able to load the additional " + + "components that it may need, the jsMath.js file must be " + + "loaded from a server in the same domain as the page that " + + "contains it. Because that is not the case for this page, " + + "the mathematics displayed here may not appear correctly."); }, /* * Look up the default height and depth for a TeX font * and set the skewchar */ - InitTeXfont: function (name) { - var font = this.TeX[name]; - var WH = this.EmBoxFor(''+font[65].c+''); + TeXfont: function (name) { + var font = jsMath.TeX[name]; + var WH = jsMath.EmBoxFor(''+font[65].c+''); font.hd = WH.h; - font.d = this.EmBoxFor(''+ font[65].c + - '').h + font.d = jsMath.EmBoxFor(''+ font[65].c + + '').h - font.hd; font.h = font.hd - font.d; - font.dh = .05; + font.dh = .05; if (jsMath.browser == 'Safari') {font.hd *= 2}; if (name == 'cmmi10') {font.skewchar = 0177} else if (name == 'cmsy10') {font.skewchar = 060} }, @@ -354,75 +392,265 @@ var jsMath = { /* * Init all the TeX fonts */ - InitTeXfonts: function () { - for (var i = 0; i < this.TeX.fam.length; i++) - {if (this.TeX.fam[i]) {this.InitTeXfont(this.TeX.fam[i])}} + TeXfonts: function () { + for (var i = 0; i < jsMath.TeX.fam.length; i++) + {if (jsMath.TeX.fam[i]) {this.TeXfont(jsMath.TeX.fam[i])}} }, /* * Compute font parameters for various sizes */ - InitSizes: function () { - this.TeXparams = []; - for (var j=0; j < this.sizes.length; j++) {this.TeXparams[j] = {}} - for (var i in this.TeX) { - if (typeof(this.TeX[i]) != 'object') { - for (var j=0; j < this.sizes.length; j++) { - this.TeXparams[j][i] = this.sizes[j]*this.TeX[i]/100; + Sizes: function () { + jsMath.TeXparams = []; + for (var j=0; j < jsMath.sizes.length; j++) {jsMath.TeXparams[j] = {}} + for (var i in jsMath.TeX) { + if (typeof(jsMath.TeX[i]) != 'object') { + for (var j=0; j < jsMath.sizes.length; j++) { + jsMath.TeXparams[j][i] = jsMath.sizes[j]*jsMath.TeX[i]/100; } } } }, + /* - * Test for browser characteristics, and adjust the font table + * Send the style definitions to the browser (these may be adjusted + * by the browser-specific code) + */ + Styles: function (styles) { + if (!styles) { + styles = jsMath.styles; + styles['.jsM_scale'] = 'font-size:'+jsMath.Controls.cookie.scale+'%'; + } + document.writeln(''); + }, + + /* + * Do the initialization that requires the BODY to be in place. + * (called automatically if the jsMath.js file is loaded in the + * BODY, but must be called explicitly if it is in the HEAD). + */ + Body: function () { + if (this.inited) return; + + this.inited = -1; + + jsMath.Setup.HTML(); + jsMath.Setup.Source(); + jsMath.Browser.Init(); + jsMath.Controls.Init(); + jsMath.Click.Init(); + jsMath.Setup.Styles(); + + jsMath.Setup.User(); // do user-specific initialization + + //make sure browser-specific loads are done before this + document.write(''); + + this.inited = 1; + }, + + /* + * Web page author can override this to do initialization + * that must be done before the font check is performed + */ + User: function () {} + +}; + +jsMath.Update = { + + /* + * Update specific parameters for a limited number of font entries + */ + TeXfonts: function (change) { + for (var font in change) { + for (var code in change[font]) { + for (var id in change[font][code]) { + jsMath.TeX[font][code][id] = change[font][code][id]; + } + } + } + }, + + /* + * Update the character code for every character in a list + * of fonts + */ + TeXfontCodes: function (change) { + for (var font in change) { + for (var i = 0; i < change[font].length; i++) { + jsMath.TeX[font][i].c = change[font][i]; + } + } + }, + + /* + * Add a collection of styles to the style list + */ + Styles: function (styles) { + for (var i in styles) {jsMath.styles[i] = styles[i]} + } + +}; + +/***************************************************************************/ + +/* + * Implement browser-specific checks + */ + +jsMath.Browser = { + + allowAbsolute: 1, // tells if browser can nest absolutely positioned + // SPANs inside relative SPANs + allowAbsoluteDelim: 0, // OK to use absolute placement for building delims? + separateSkips: 0, // MSIE doesn't do negative left margins, and + // Netscape doesn't combine skips well + + msieSpaceFix: '', // for MSIE spacing bug fix + msieCenterBugFix: '', // for MSIE centering bug with image fonts + msieInlineBlockFix: '', // for MSIE alignment bug in non-quirks mode + imgScale: 1, // MSI scales images for 120dpi screens, so compensate + + renameOK: 1, // tells if brower will find a tag whose name + // has been set via setAttributes + + delay: 1, // delay for asynchronous math processing + + spaceWidth: 0, // Konqueror space fix + hiddenSpace: "", // ditto + valignBug: 0, // Konqueror doesn't nest vertical-align + + operaHiddenFix: '', // for Opera to fix bug with math in tables + + /* + * Determine if the "top" of a is always at the same height + * or varies with the height of the rest of the line (MSIE). + */ + TestSpanHeight: function () { + jsMath.hidden.innerHTML = ''; + var span = jsMath.hidden.getElementsByTagName('SPAN')[0]; + var img = jsMath.hidden.getElementsByTagName('IMG')[0]; + this.spanHeightVaries = (span.offsetHeight == img.offsetHeight); + jsMath.hidden.innerHTML = ''; + }, + + /* + * Determine if the NAME attribute of a tag can be changed + * using the setAttribute function, and then be properly + * returned by getElementByName. + */ + TestRenameOK: function () { + jsMath.hidden.innerHTML = ''; + var test = document.getElementById('jsMath.test'); + test.setAttribute('NAME','jsMath_test'); + this.renameOK = (document.getElementsByName('jsMath_test').length > 0); + jsMath.hidden.innerHTML = ''; + }, + + /* + * Test for browser characteristics, and adjust things * to overcome specific browser bugs */ - InitBrowser: function () { + Init: function () { jsMath.browser = 'unknown'; - this.isSafari = navigator.userAgent.match(/Safari/); this.TestSpanHeight(); this.TestRenameOK(); + this.MSIE(); + this.Mozilla(); + this.Opera(); + this.OmniWeb(); + this.Safari(); + this.Konqueror(); + // - // Check for bug-filled Internet Explorer - // + // Change some routines depending on the browser + // + if (this.allowAbsoluteDelim) { + jsMath.Box.DelimExtend = jsMath.Box.DelimExtendAbsolute; + jsMath.Box.Layout = jsMath.Box.LayoutAbsolute; + } else { + jsMath.Box.DelimExtend = jsMath.Box.DelimExtendRelative; + jsMath.Box.Layout = jsMath.Box.LayoutRelative; + } + + if (this.separateSkips) { + jsMath.HTML.Place = jsMath.HTML.PlaceSeparateSkips; + jsMath.Typeset.prototype.Place = jsMath.Typeset.prototype.PlaceSeparateSkips; + } + }, + + // + // Handle bug-filled Internet Explorer + // + MSIE: function () { if (this.spanHeightVaries) { jsMath.browser = 'MSIE'; if (navigator.platform == 'Win32') { - this.UpdateTeXfonts({ + jsMath.Update.TeXfonts({ cmr10: {'10': {c: 'Ω', tclass: 'normal'}}, cmmi10: { - '10': {c: 'Ω', tclass: 'normal'}, - '126': {c: '~'} - }, - cmsy10: {'10': {c: '⊗', tclass: 'arial'}}, + '10': {c: 'Ω', tclass: 'normal'}, + '126': {c: '~'} + }, + cmsy10: { + '10': {c: '⊗', tclass: 'arial'}, + '55': {c: '7'} + }, cmex10: {'10': {c: 'D'}}, cmti10: {'10': {c: 'Ω', tclass: 'normal'}}, cmbx10: {'10': {c: 'Ω', tclass: 'normal'}} }); this.allowAbsoluteDelim = 1; - this.separateSkips = 1; + this.separateSkips = 1; + this.buttonCheck = 1; + this.msieDivWidthBug = 1; this.msieFontBug = 1; this.msieIntegralBug = 1; + this.msieAlphaBug = 1; this.alphaPrintBug = 1; + this.msieCenterBugFix = 'position:relative; '; this.msieSpaceFix = ''; + this.msieInlineBlockFix = ' display: inline-block;'; jsMath.Macro('joinrel','\\mathrel{\\kern-5mu}'), - jsMath.Macro('mapsto','\\mapstochar\\kern-.54em\\rightarrow'); - jsMath.Macro('longmapsto','\\mapstochar\\kern-.54em\\char{cmsy10}{0}\\joinrel\\rightarrow'); + jsMath.styles['.arial'] = "font-family: 'Arial unicode MS'"; + // MSIE doesn't implement fixed positioning, so use absolute + jsMath.styles['.jsM_panel'] = + jsMath.styles['.jsM_panel'].replace(/position:fixed/,"position:absolute").replace(/width:auto/,""); + jsMath.styles['.jsM_button'] = 'width:1px; ' + + jsMath.styles['.jsM_button'].replace(/position:fixed/,"position:absolute").replace(/width:auto/,""); + window.onscroll = jsMath.Controls.MoveButton; + // MSIE will rescale images if the DPIs differ + if (screen.deviceXDPI && screen.logicalXDPI + && screen.deviceXDPI != screen.logicalXDPI) { + this.imgScale *= screen.logicalXDPI/screen.deviceXDPI; + jsMath.Controls.cookie.alpha = 0; + } + // Handle bug with getting width of italic text + this.italicString = 'x'; + jsMath.EmBoxFor = jsMath.EmBoxForItalics; } else if (navigator.platform == 'MacPPC') { - document.writeln(''); + this.msieAbsoluteBug = 1; this.msieButtonBug = 1; + this.msieDivWidthBug = 1; + jsMath.Setup.Script('jsMath-msie-mac.js'); jsMath.Parser.prototype.macros.angle = ['Replace','ord','','normal']; - jsMath.msieAbsoluteBug = 1; + jsMath.styles['.jsM_panel'] = 'width:25em; ' + jsMath.styles['.jsM_panel'].replace(/width:auto/,""); + jsMath.styles['.jsM_button'] = 'width:1px; ' + jsMath.styles['.jsM_button'].replace(/width:auto/,""); } jsMath.Macro('not','\\mathrel{\\rlap{\\kern3mu/}}'); } + }, - // - // Look for Netscape/Mozilla (any flavor) - // - if (this.hidden.ATTRIBUTE_NODE) { + // + // Handle Netscape/Mozilla (any flavor) + // + Mozilla: function () { + if (jsMath.hidden.ATTRIBUTE_NODE) { jsMath.browser = 'Mozilla'; if (navigator.platform == 'MacPPC') { - this.UpdateTeXfonts({ + jsMath.Update.TeXfonts({ cmr10: {'10': {c: 'Ω', tclass: 'normal'}}, cmmi10: {'10': {c: 'Ω', tclass: 'normal'}}, cmsy10: {'10': {c: '⊗', tclass: 'normal'}}, @@ -431,32 +659,38 @@ var jsMath = { cmbx10: {'10': {c: 'Ω', tclass: 'normal'}} }); } else { - document.writeln(''); + jsMath.Setup.Script('jsMath-mozilla.js'); + this.alphaPrintBug = 1; } - for (var i = 0; i < this.TeX.fam.length; i++) { - if (this.TeX.fam[i]) - {this.styles['.'+this.TeX.fam[i]] += '; position: relative'} + for (var i = 0; i < jsMath.TeX.fam.length; i++) { + if (jsMath.TeX.fam[i]) + {jsMath.styles['.'+jsMath.TeX.fam[i]] += '; position: relative'} } this.allowAbsoluteDelim = 1; this.separateSkips = 1; jsMath.Macro('not','\\mathrel{\\rlap{\\kern3mu/}}'); } - - // - // Look for OmniWeb - // + }, + + // + // Handle OmniWeb + // + OmniWeb: function () { if (navigator.accentColorName) { jsMath.browser = 'OmniWeb'; - this.allowAbsolute = 0; + this.allowAbsolute = !navigator.userAgent.match("OmniWeb/v4"); + this.allowAbsoluteDelim = this.allowAbsolute; + this.buttonCheck = 1; } + }, - // - // Look for Opera - // - if (navigator.userAgent.search(" Opera ") >= 0) { + // + // Handle Opera + // + Opera: function () { + if (navigator.appName == 'Opera' || navigator.userAgent.match(" Opera ")) { jsMath.browser = 'Opera'; - this.isOpera = 1; - this.UpdateTeXfonts({ + jsMath.Update.TeXfonts({ cmr10: { '10': {c: 'Ω', tclass: 'normal'}, '20': {c: 'ˇ', tclass: 'normal'} @@ -483,109 +717,620 @@ var jsMath = { } }); this.allowAbsolute = 0; - jsMath.delay = 10; + this.delay = 10; + this.operaHiddenFix = '[Processing Math]'; } + }, - // - // Look for Safari - // - if (this.isSafari) { + // + // Handle Safari + // + Safari: function () { + if (navigator.appVersion.match(/Safari\//)) { jsMath.browser = 'Safari'; - var version = navigator.userAgent.match("Safari/([0-9]+)")[1]; - if (version < 125) {this.allowAbsolute = 0; this.oldSafari = 1} - for (var i = 0; i < this.TeX.fam.length; i++) - {if (this.TeX.fam[i] != '') {this.TeX[this.TeX.fam[i]].dh = .1}} - this.absoluteOffsetY = -.05; - this.TeX.axis_height += .05; - this.allowAbsoluteDelim = ! this.oldSafari; + var version = navigator.userAgent.match("Safari/([0-9]+)"); + version = (version)? version[1] : 200; // FIXME: hack until I get Tiger + for (var i = 0; i < jsMath.TeX.fam.length; i++) + {if (jsMath.TeX.fam[i]) {jsMath.TeX[jsMath.TeX.fam[i]].dh = .1}} + jsMath.TeX.axis_height += .05; + this.allowAbsoluteDelim = version >= 125; + this.safariIFRAMEbug = version >= 312; // FIXME: find out if they fixed it + this.safariImgBug = 1; + this.buttonCheck = 1; + } + }, + + // + // Handle Konqueror + // + Konqueror: function () { + if (navigator.product && navigator.product.match("Konqueror")) { + jsMath.browser = 'Konqueror'; + jsMath.Update.TeXfonts({ + cmr10: {'20': {c: 'ˇ', tclass: 'normal'}}, + cmmi10: {'20': {c: 'κ', tclass: 'normal'}}, + cmsy10: {'20': {c: '≤', tclass: 'normal'}}, + cmex10: {'20': {c: '"'}}, + cmti10: {'20': {c: 'ˇ', tclass: 'normal'}}, + cmbx10: {'20': {c: 'ˇ', tclass: 'normal'}} + }); + this.allowAbsolute = 0; + this.allowAbsoluteDelim = 0; + if (navigator.userAgent.match(/Konqueror\/(\d+)\.(\d+)/)) { + if (RegExp.$1 < 3 || (RegExp.$1 == 3 && RegExp.$2 < 3)) { + this.separateSkips = 1; + this.valignBug = 1; + this.hiddenSpace = ' '; + jsMath.Box.prototype.Remeasured = function () {return this}; + } + } } + } - // - // Change some routines depending on the browser - // - if (this.allowAbsoluteDelim) { - jsMath.Box.DelimExtend = jsMath.Box.DelimExtendAbsolute; - jsMath.Box.Layout = jsMath.Box.LayoutAbsolute; +}; + +/***************************************************************************/ + +/* + * Implement font check and messages + */ +jsMath.Font = { + + fallback: "symbol", // the default fallback method + + // the HTML for the missing font message + message: + 'No TeX fonts found -- using image fonts instead.
\n' + + 'These may be slow and might not print well.
\n' + + 'Use the jsMath control panel to get additional information.', + + extra_message: + 'Extra TeX fonts not found:
' + + 'Using image fonts instead. This may be slow and might not print well.
\n' + + 'Use the jsMath control panel to get additional information.', + + /* + * Look to see if a font is found. HACK! + * Check the character in a given position, and see if it is + * wider than the usual one in that position. + */ + Test1: function (name,n,factor) { + if (n == null) {n = 124}; if (factor == null) {factor = 2} + var wh1 = jsMath.BBoxFor(''+jsMath.TeX[name][n].c+''); + var wh2 = jsMath.BBoxFor(''+jsMath.TeX[name][n].c+''); + //alert([wh1.w,wh2.w,wh1.h,factor*wh2.w]); + return (wh1.w > factor*wh2.w && wh1.h != 0); + }, + + Test2: function (name,n,factor) { + if (n == null) {n = 124}; if (factor == null) {factor = 2} + var wh1 = jsMath.BBoxFor(''+jsMath.TeX[name][n].c+''); + var wh2 = jsMath.BBoxFor(''+jsMath.TeX[name][n].c+''); + //alert([wh2.w,wh1.w,wh1.h,factor*wh1.w]); + return (wh2.w > factor*wh1.w && wh1.h != 0); + }, + + /* + * Check for the availability of TeX fonts. We do this by looking at + * the width and height of a character in the cmex10 font. The cmex10 + * font has depth considerably greater than most characters' widths (the + * whole font has the depth of the character with greatest depth). This + * is not the case for most fonts, so if we can access cmex10, the + * height of a character should be much bigger than the width. + * Otherwise, if we don't have cmex10, we'll get a character in another + * font with normal height and width. In this case, we insert a message + * pointing the user to the jsMath site, and load one of the fallback + * definitions. + * + */ + Check: function () { + var cookie = jsMath.Controls.cookie; + var wh = jsMath.BBoxFor(''+jsMath.TeX.cmex10[1].c+''); + jsMath.nofonts = ((wh.w*3 > wh.h || wh.h == 0) && !this.Test1('cmr10')); + if (jsMath.nofonts) { + if (cookie.autofont || cookie.font == 'tex') { + cookie.font = this.fallback; + if (cookie.warn) { + jsMath.nofontMessage = 1; + cookie.warn = 0; jsMath.Controls.SetCookie(0); + if (window.NoFontMessage) {window.NoFontMessage()} + else {this.Message(this.message)} + } + } } else { - jsMath.Box.DelimExtend = jsMath.Box.DelimExtendRelative; - jsMath.Box.Layout = jsMath.Box.LayoutRelative; + if (cookie.autofont) {cookie.font = 'tex'} + if (cookie.font == 'tex') return; } - - if (this.separateNegativeSkips) { - jsMath.HTML.Place = jsMath.HTML.PlaceSeparateNegative; - jsMath.Typeset.prototype.Place = jsMath.Typeset.prototype.PlaceSeparateNegative; - } else if (this.separateSkips) { - jsMath.HTML.Place = jsMath.HTML.PlaceSeparateSkips; - jsMath.Typeset.prototype.Place = jsMath.Typeset.prototype.PlaceSeparateSkips; + if (jsMath.noImgFonts) {cookie.font = 'unicode'} + if (cookie.font == 'unicode') { + var platform = ({Win32: 'pc', MacPPC: 'mac'})[navigator.platform] || 'unix'; + jsMath.Setup.Script('jsMath-fallback-'+platform+'.js'); + return; } - - if (this.noEmptySpans) {jsMath.HTML.Spacer = jsMath.HTML.SpacerImage} + if (cookie.font == 'symbol') { + jsMath.Setup.Script('jsMath-fallback-symbols.js'); + return; + } + jsMath.Img.SetFont({ + cmr10: ['all'], cmmi10: ['all'], cmsy10: ['all'], + cmex10: ['all'], cmbx10: ['all'], cmti10: ['all'] + }); + jsMath.Img.LoadFont('cm-fonts'); + }, + /* + * The message for when no TeX fonts. You can eliminate this message + * by including + * + * + * + * in your HTML file, before loading jsMath.js, if you want. But this + * means the user may not know that he or she can get a better version + * of your page. + */ + Message: function (message) { + if(jsMath.Element("Warning")) return; + var div = jsMath.Setup.TopHTML("Warning",{'class':'jsM_Warning'},{}); + div.innerHTML = + '
' + + '
' + message + + '
' + + 'jsMath Control Panel' + + '' + + 'Hide this Message' + + '

' + + '
' + + '

'; + }, + + HideMessage: function () { + var message = jsMath.Element("Warning"); + if (message) {message.style.display = "none"} }, /* - * Define some styles + * Register an extra font so jsMath knows about it + */ + Register: function (data) { + if (typeof(data) == 'string') {data = {name: data}} + var fontname = data.name; var name = fontname.replace(/10$/,''); + var fontfam = jsMath.TeX.fam.length; + if (!data.style) {data.style = "font-family: "+fontname+", serif"} + if (!data.styles) {data.styles = {}} + if (!data.macros) {data.macros = {}} + /* + * Register font family + */ + jsMath.TeX.fam[fontfam] = fontname; + data.macros[name] = ['HandleFont',fontfam]; + jsMath.Add(jsMath.Parser.prototype.macros,data.macros); + /* + * Set up styles + */ + data.styles['.'+fontname] = data.style; + jsMath.Setup.Styles(data.styles); + jsMath.Setup.TeXfont(fontname); + /* + * Check for font and give message if missing + */ + var hasTeXfont = !jsMath.nofonts && + data.test(fontname,data.testChar,data.testFactor); + if (hasTeXfont && jsMath.Controls.cookie.font == 'tex') { + if (data.tex) {data.tex(fontname,fontfam)} + return; + } + if (!hasTeXfont && jsMath.Controls.cookie.warn && + jsMath.Controls.cookie.font == 'tex' && !jsMath.nofonts) { + if (!jsMath.Element("Warning")) this.Message(this.extra_message); + var extra = jsMath.Element("ExtraFonts"); + if (extra) { + if (extra.innerHTML != "") {extra.innerHTML += ','} + extra.innerHTML += " " + fontname; + } + } + if (jsMath.Controls.cookie.font == 'unicode') { + if (data.fallback) {data.fallback(fontname,fontfam)} + return; + } + // Image fonts + var font = {}; font[fontname] = ['all']; + jsMath.Img.SetFont(font); + jsMath.Img.LoadFont(fontname); + }, + + /* + * Load a font */ - WriteStyles: function (styles) { - document.writeln(''); + Load: function (name) {jsMath.Setup.Script("fonts/"+name+"/def.js")} + +}; + +/***************************************************************************/ + +/* + * Implements the jsMath control panel. + * Much of the code is in jsMath-controls.html, which is + * loaded into a hidden IFRAME on demand + */ +jsMath.Controls = { + + // Data stored in the jsMath cookie + cookie: { + scale: 100, + font: 'tex', autofont: 1, scaleImg: 0, alpha: 1, + warn: 1, button: 1, + print: 0, keep: '0D' }, + cookiePath: '/', // can also set cookieDomain + + /* - * Send the style definitions to the browser (these may be adjusted - * by the browser-specific code) + * Load the control panel */ - InitStyles: function () {this.WriteStyles(this.styles)}, + Panel: function () { + if (!this.panel) {this.panel = jsMath.Element("Controls")} + if (this.loaded) {this.Main()} else { + this.openMain = 1; + if (!this.iframe) {this.iframe = jsMath.Element("Frame")} + this.iframe.src = jsMath.root+"jsMath-controls.html"; + } + }, /* - * Update specific parameters for a limited number of font entries + * Create the control panel button */ - UpdateTeXfonts: function (change) { - for (var font in change) { - for (var code in change[font]) { - for (var id in change[font][code]) { - this.TeX[font][code][id] = change[font][code][id]; - } + Button: function () { + var button = jsMath.Setup.TopHTML("jsMath",{'class':'jsM_button'},{}); + button.innerHTML = + '' + + 'jsMath' + if (!this.cookie.button) {button.style.display = "none"} + }, + + /* + * MSIE doesn't implement position:fixed, so redraw the button on scrolls. + */ + MoveButton: function () { + if (!this.button) {this.button = jsMath.Element("jsMath")} + this.button.style.visibility = "hidden"; + this.button.style.visibility = "visible"; + }, + + /* + * Create the HTML needed for control panel + */ + Init: function () { + this.document = document; + this.panel = jsMath.Setup.TopHTML("Controls", {'class':"jsM_panel"},{display:'none'}); + if (!jsMath.Browser.msieButtonBug) {this.Button()} + else {setTimeout("jsMath.Controls.Button()",500)} + if (jsMath.Browser.safariIFRAMEbug) { + document.write( + '\n'); + return; + } + try { + var frame = document.createElement('iframe'); + frame.setAttribute('scrolling','no'); + frame.style.border = '0px'; + frame.style.width = '0px'; + frame.style.height = '0px'; + document.body.insertBefore(frame,this.panel); + this.iframe = frame; + } catch (err) { + document.write('\n'); + } + }, + + /* + * Get the cookie data from the browser + * (for file: references, use url '?' syntax) + */ + GetCookie: function () { + var cookies = document.cookie; + if (window.location.protocol == 'file:') + {cookies = unescape(window.location.search.substr(1))} + if (cookies.match(/jsMath=([^;]*)/)) { + var data = RegExp.$1.split(/,/); + for (var i = 0; i < data.length; i++) { + var x = data[i].match(/(.*):(.*)/); + if (x[2].match(/^\d+$/)) {x[2] = 1*x[2]} // convert from string + this.cookie[x[1]] = x[2]; } } }, /* - * Update the character code for every character in a list - * of fonts + * Save the cookie data in the browser + * (for file: urls, append data like CGI reference) */ - UpdateTeXfontCodes: function (change) { - for (var font in change) { - for (var i = 0; i < change[font].length; i++) { - this.TeX[font][i].c = change[font][i]; + SetCookie: function (warn) { + var cookie = []; + for (var id in this.cookie) {cookie[cookie.length] = id + ':' + this.cookie[id]} + cookie = cookie.join(','); + if (window.location.protocol == 'file:') { + if (!warn) return; + this.loaded = 0; + var href = window.location.href; + href = href.replace(/\?.*/,"") + '?jsMath=' + escape(cookie); + if (href != window.location.href) {window.location.replace(href)} + } else { + if (this.cookiePath) {cookie += '; path='+this.cookiePath} + if (this.cookieDomain) {cookie += '; domain='+this.cookieDomain} + if (this.cookie.keep != '0D') { + var ms = { + D: 1000*60*60*24, + W: 1000*60*60*24*7, + M: 1000*60*60*24*30, + Y: 1000*60*60*24*365 + }; + var exp = new Date; + exp.setTime(exp.getTime() + + this.cookie.keep.substr(0,1) * ms[this.cookie.keep.substr(1,1)]); + cookie += '; expires=' + exp.toGMTString(); } + document.cookie = 'jsMath='+cookie; + var cookies = document.cookie; + if (warn && !cookies.match(/jsMath=/)) + {alert("Cookies must be enabled in order to save jsMath options")} + } + } + +}; + +/***************************************************************************/ + +/* + * Implements the actions for clicking and double-clicking + * on math formulas + */ +jsMath.Click = { + + dragging: 0, + + /* + * Create the hidden DIV used for the tex source window + */ + Init: function () { + this.source = jsMath.Setup.TopHTML("Source",{'class':'jsM_float'},{display:'none'}); + this.source.innerHTML = + '
' + + '
'; + this.drag = this.source.firstChild; + this.tex = this.drag.nextSibling.firstChild; + this.drag.firstChild.onclick = jsMath.Click.CloseSource; + this.drag.onmousedown = jsMath.Click.StartDragging; + this.drag.ondragstart = jsMath.Click.False; + this.drag.onselectstart = jsMath.Click.False; + this.source.onclick = jsMath.Click.CheckClose; + }, + False: function () {return false}, + + /* + * Handle clicking on math to get control panel + */ + CheckClick: function (event) { + if (!event) {event = window.event} + if (event.altKey) jsMath.Controls.Panel(); + }, + + /* + * Handle double-click for seeing TeX code + */ + CheckDblClick: function (event) { + if (!event) {event = window.event} + var event = jsMath.Click.Event(event); + + var source = jsMath.Click.source + var tex = jsMath.Click.tex; + + source.style.visibility = 'hidden'; + source.style.display = ''; source.style.width = ''; + source.style.left = ''; source.style.top = ''; + tex.innerHTML = ''; + + var TeX = this.alt; + TeX = TeX.replace(/^\s+|\s+$/g,''); + TeX = TeX.replace(/&/g,'&'); + TeX = TeX.replace(//g,'>'); + TeX = TeX.replace(/\n/g,'
'); + tex.innerHTML = TeX; + + var h = source.offsetHeight; var w; + if (jsMath.Browser.msieDivWidthBug) { + tex.className = 'jsM_source'; // Work around MSIE bug where + w = tex.offsetWidth + 5; // DIV's don't collapse to + tex.className = ''; // their natural widths + } else { + w = source.offsetWidth; } + w = Math.max(50,Math.min(w,.8*event.W,event.W-40)); + var x = Math.floor(event.x-w/2); var y = Math.floor(event.y-h/2); + x = event.X + Math.max(Math.min(x,event.W-w-20),20); + y = event.Y + Math.max(Math.min(y,event.H-h-5),5); + + source.style.left = x+'px'; source.style.top = y+'px'; + source.style.width = w+'px'; + source.style.visibility = ''; + jsMath.Click.left = x + event.X; jsMath.Click.top = y + event.Y; + jsMath.Click.w = w; jsMath.Click.h = source.offsetHeight; + + jsMath.Click.DeselectText(x,y); + return false; + }, + + /* + * Get window width, height, and offsets plus + * position of pointer relative to the window + */ + Event: function (event) { + var W = window.innerWidth || document.body.clientWidth; + var H = window.innerHeight || document.body.clientHeight; + var X = window.pageXOffset; var Y = window.pageYOffset; + if (X == null) {X = document.body.clientLeft; Y = document.body.clientTop} + var x = event.pageX; var y = event.pageY; + if (x == null) { + x = event.clientX; y = event.clientY; + if (jsMath.browser == 'MSIE' && document.compatMode == 'CSS1Compat') { + X = document.documentElement.scrollLeft; + Y = document.documentElement.scrollTop; + W = document.documentElement.clientWidth; + H = document.documentElement.clientHeight; + } else { + X = document.body.scrollLeft; + Y = document.body.scrollTop; + } + } else {x -= X; y -= Y} + + return {x: x, y: y, W: W, H: H, X: X, Y: Y}; }, /* - * Add a collection of styles to the style list + * Unselect whatever text is selected (since double-clicking + * usually selects something) */ - UpdateStyles: function (styles) { - for (var i in styles) {this.styles[i] = styles[i]} + DeselectText: function (x,y) { + if (window.getSelection && window.getSelection().removeAllRanges) + {window.getSelection().removeAllRanges()} + else if (document.getSelection && document.getSelection().removeAllRanges) + {document.getSelection().removeAllRanges()} + else if (document.selection && document.selection.empty) + {document.selection.empty()} + else { + /* Hack to deselect the text in Opera and Safari */ + if (jsMath.browser == 'MSIE') return; // don't try it if MISE on Mac + jsMath.hiddenTop.innerHTML = + ''; + jsMath.hiddenTop.firstChild.style.position = 'absolute'; + jsMath.hiddenTop.firstChild.style.left = x+'px'; + jsMath.hiddenTop.firstChild.style.top = y+'px'; + setTimeout(jsMath.Click.SelectHidden,1); + } + }, + SelectHidden: function () { + jsMath.hiddenTop.firstChild.focus(); + jsMath.hiddenTop.firstChild.select(); + jsMath.hiddenTop.innerHTML = ''; }, /* - * Manage JavaScript objects: - * - * Add: simply add items to an object - * Package: add items to an object prototype + * Close the TeX source window */ - Add: function (obj,def) {for (var id in def) {obj[id] = def[id]}}, - Package: function (obj,def) {this.Add(obj.prototype,def)} + CloseSource: function () { + jsMath.Click.tex.innerHTML = ''; + jsMath.Click.source.style.display = 'none'; + jsMath.Click.source.style.visibility = 'hidden'; + jsMath.Click.StopDragging(); + return false; + }, + CheckClose: function (event) { + if (!event) {event = window.event} + if (event.altKey) {jsMath.Click.CloseSource(); return false} + }, -} + /* + * Set up for dragging the source panel + */ + StartDragging: function (event) { + if (!event) {event = window.event} + if (jsMath.Click.dragging) {jsMath.Click.StopDragging(event)} + var event = jsMath.Click.Event(event); + jsMath.Click.dragging = 1; + jsMath.Click.x = event.x + 2*event.X - jsMath.Click.left; + jsMath.Click.y = event.y + 2*event.Y - jsMath.Click.top; + jsMath.Click.oldonmousemove = document.body.onmousemove; + jsMath.Click.oldonmouseup = document.body.onmouseup; + document.body.onmousemove = jsMath.Click.DragSource; + document.body.onmouseup = jsMath.Click.StopDragging; + return false; + }, + + /* + * Stop dragging the source window + */ + StopDragging: function (event) { + if (jsMath.Click.dragging) { + document.body.onmousemove = jsMath.Click.oldonmousemove; + document.body.onmouseup = jsMath.Click.oldonmouseup; + jsMath.Click.oldonmousemove = null; + jsMath.Click.oldonmouseup = null; + jsMath.Click.dragging = 0; + } + return false; + }, + + /* + * Move the source window (but stay within the browser window) + */ + DragSource: function (event) { + if (!event) {event = window.event} + if (jsMath.Browser.buttonCheck && !event.button) {return jsMath.Click.StopDragging(event)} + event = jsMath.Click.Event(event); + var x = event.x + event.X - jsMath.Click.x; + var y = event.y + event.Y - jsMath.Click.y; + x = Math.max(event.X,Math.min(event.W+event.X-jsMath.Click.w,x)); + y = Math.max(event.Y,Math.min(event.H+event.Y-jsMath.Click.h,y)); + jsMath.Click.source.style.left = x + 'px'; + jsMath.Click.source.style.top = y + 'px'; + jsMath.Click.left = x + event.X; jsMath.Click.top = y + event.Y; + return false; + } +}; /***************************************************************************/ -jsMath.Add(jsMath.TeX,{ +/* + * The TeX font information + */ +jsMath.TeX = { + // + // The TeX font parameters + // + thinmuskip: 3/18, + medmuskip: 4/18, + thickmuskip: 5/18, + + x_height: .430554, + quad: 1, + num1: .676508, + num2: .393732, + num3: .44373, + denom1: .685951, + denom2: .344841, + sup1: .412892, + sup2: .362892, + sup3: .288888, + sub1: .15, + sub2: .247217, + sup_drop: .386108, + sub_drop: .05, + delim1: 2.39, + delim2: 1.0, + axis_height: .25, + default_rule_thickness: .04, + big_op_spacing1: .111111, + big_op_spacing2: .166666, + big_op_spacing3: .2, + big_op_spacing4: .6, + big_op_spacing5: .1, + + integer: 6553.6, // conversion of em's to TeX internal integer + scriptspace: .05, + nulldelimiterspace: .12, + delimiterfactor: 901, + delimitershortfall: .5, + scale: 1, // scaling factor for font dimensions + // The TeX math atom types (see Appendix G of the TeXbook) atom: ['ord', 'op', 'bin', 'rel', 'open', 'close', 'punct', 'ord'], @@ -596,7 +1341,7 @@ jsMath.Add(jsMath.TeX,{ * The following are the TeX font mappings and metrics. The metric * information comes directly from the TeX .tfm files, and the * character mappings are for the TrueType TeX fonts. Browser-specific - * adjustments are made to these tables in the InitBrowser() routine + * adjustments are made to these tables in the Browser.Init() routine */ cmr10: [ // 00 - 0F @@ -1431,7 +2176,125 @@ jsMath.Add(jsMath.TeX,{ {c: '~', h: 0.694, w: 0.575}, {c: 'Ä', h: 0.694, w: 0.575} ] -}); +}; + +/***************************************************************************/ + +/* + * Implement image-based fonts for fallback method + */ +jsMath.Img = { + + // font sizes available + fonts: [50, 60, 70, 85, 100, 120, 144, 173, 207, 249, 298, 358, 430], + + // em widths for the various font size directories + w: {'50': 6.9, '60': 8.3, '70': 9.7, '85': 11.8, '100': 13.9, + '120': 16.7, '144': 20.0, '173': 24.0, '207': 28.8, '249': 34.6, + '298': 41.4, '358': 49.8, '430': 59.8}, + + // index of best font size in the fonts list + best: 4, + + // fonts to update (see UpdateFonts below) + update: {}, + + // factor by which to shrink images (for better printing) + factor: 1, + + // image fonts are loaded + loaded: 0, + + // add characters to be drawn using images + SetFont: function (change) { + for (var font in change) { + if (!this.update[font]) {this.update[font] = []} + this.update[font] = this.update[font].concat(change[font]); + } + }, + + /* + * Called by the exta-font definition files to add an image font + * into the mix + */ + AddFont: function (size,def) { + if (!jsMath.Img[size]) {jsMath.Img[size] = {}}; + jsMath.Add(jsMath.Img[size],def); + }, + + /* + * Update font(s) to use image data rather than native fonts + * It looks in the jsMath.Img.update array to find the names + * of the fonts to udpate, and the arrays of character codes + * to set (or 'all' to change every character); + */ + UpdateFonts: function () { + var change = this.update; if (!this.loaded) return; + var best = this[jsMath.Img.fonts[this.best]]; + for (var font in change) { + for (var i = 0; i < change[font].length; i++) { + var c = change[font][i]; + if (c == 'all') {for (c in jsMath.TeX[font]) {jsMath.TeX[font][c].img = {}}} + else {jsMath.TeX[font][c].img = {}} + } + } + this.update = {}; + }, + + /* + * Find the font size that best fits our current font + * (this is the directory name for the img files used + * in some fallback modes). + */ + BestSize: function () { + var w = jsMath.em * this.factor; + var m = this.w[this.fonts[0]]; + for (var i = 1; i < this.fonts.length; i++) { + if (w < (this.w[this.fonts[i]] + 2*m) / 3) {return i-1} + m = this.w[this.fonts[i]]; + } + return i-1; + }, + + /* + * Get the scaling factor for the image fonts + */ + Scale: function () { + if (!this.loaded) return; + this.best = this.BestSize(); + this.em = jsMath.Img.w[this.fonts[this.best]]; + this.scale = (jsMath.em/this.em); + if (Math.abs(this.scale - 1) < .12) {this.scale = 1} + }, + + /* + * Get URL to directory for given font and size, based on the + * user's alpha/plain setting + */ + URL: function (name,size,C) { + var type = (jsMath.Controls.cookie.alpha) ? '/alpha/': '/plain/'; + if (C == null) {C = "def.js"} else {C = 'char'+C+'.png'} + if (size != "") {size += '/'} + return this.root+name+type+size+C; + }, + + /* + * Laod the data for an image font + */ + LoadFont: function (name) { + if (jsMath.Controls.cookie.print) { + jsMath.Controls.cookie.print = 0; + var button = jsMath.Element("jsMath"); + if (button) {button.style.display = "none"} + this.factor *= 3; + if (window.location.protocol != 'file:') {jsMath.Controls.SetCookie(0)} + if (jsMath.Browser.alphaPrintBug) {jsMath.Controls.cookie.alpha = 0} + } + document.writeln(''); + this.loaded = 1; + } + +}; /***************************************************************************/ @@ -1459,17 +2322,10 @@ jsMath.HTML = { */ Spacer: function (w) { if (w == 0) {return ''}; - return jsMath.msieSpaceFix - + ''; - }, - - /* - * Use an image to create a horizontal space of width w - */ - SpacerImage: function (w) { - if (w == 0) {return ''}; - return ''; + return jsMath.Browser.msieSpaceFix + + '' + + jsMath.Browser.hiddenSpace + ''; }, /* @@ -1485,25 +2341,13 @@ jsMath.HTML = { {pos = 'relative; margin-right: '+this.Em(-(w+2/jsMath.em))+'; '} return ''; - }, - - /* - * Create a 1-pixel-high horizontal line at a particular - * position, width and color. - */ - Line: function (x,y,w,c,pos) { - if (!c) {c = 'black'}; - if (pos) {pos = 'absolute;'} else - {pos = 'relative; margin-right: '+this.Em(-w)+'; '} - return ''; + + 'width:' +this.Em(w*jsMath.Browser.imgScale)+'; ' + + 'height:'+this.Em(h*jsMath.Browser.imgScale)+'; ' + + 'border: 1px solid '+c+';">'; }, /* - * Create a black rule line for fractions, etc. + * Create a rule line for fractions, etc. * Height is converted to pixels (with a minimum of 1), so that * the line will not disappear at small font sizes. This means that * the thickness will not change if you change the font size, or @@ -1512,23 +2356,15 @@ jsMath.HTML = { Rule: function (w,h) { if (h == null) {h = jsMath.TeX.default_rule_thickness} if (w == 0 || h == 0) return; // should make an invisible box? - h = Math.round(h*jsMath.em); - if (h < 1) {h = 1} - return ''; - }, - - /* - * Create a colored block of a specific size (won't always print - * correctly). - */ - Block: function (w,h,c) { - if (c == null) {c = 'black'} + w *= jsMath.Browser.imgScale; + h = Math.round(h*jsMath.em*jsMath.Browser.imgScale+.25); + if (h < 1) {h = 1}; return ''; + + 'STYLE="width:'+this.Em(w)+'; height:1px; ' + + 'vertical-align:-1px; ' + + 'border:0px none; border-top:'+h+'px solid">'; }, - + /* * Add a tag to activate a specific CSS class */ @@ -1555,34 +2391,19 @@ jsMath.HTML = { /* * For MSIE on Windows, backspacing must be done in a separate - * , otherwise the contents will be clipped. - */ - PlaceSeparateNegative: function (html,x,y) { - if (Math.abs(x) < .0001) {x = 0} - if (Math.abs(y) < .0001) {y = 0} - if (x > 0 || y) { - var span = '' + html + ''; - } - if (x < 0) { - html = jsMath.msieSpaceFix - + '' + html; - } - return html; - }, - - /* - * Here the x and y positioning is done in separate tags + * , otherwise the contents will be clipped. Netscape + * also doesn't combine vertical and horizontal spacing well. + * Here the x and y positioning are done in separate tags */ PlaceSeparateSkips: function (html,x,y) { if (Math.abs(x) < .0001) {x = 0} if (Math.abs(y) < .0001) {y = 0} if (y) {html = '' + html + ''} - if (x) {html = jsMath.msieSpaceFix - + '' + html} + if (x) {html = jsMath.Browser.msieSpaceFix + + '' + + jsMath.Browser.hiddenSpace + '' + html} return html; }, @@ -1600,7 +2421,7 @@ jsMath.HTML = { Absolute: function(html,w,h,d,y,H) { var align = ""; - if (d) {align = ' vertical-align: '+jsMath.HTML.Em(-d)+';'} + if (d && d != "none") {align = ' vertical-align: '+jsMath.HTML.Em(-d)+';'} if (y != "none") { if (Math.abs(y) < .0001) {y = 0} html = ''; - if (jsMath.msieAbsoluteBug) {// for MSIE (Mac) + html += ''; + if (jsMath.Browser.msieAbsoluteBug) { // for MSIE (Mac) html = '' + html + ''; } html = '' + html + ''; @@ -1671,9 +2494,10 @@ jsMath.Add(jsMath.Box,{ * The box is a text box (like the ones above), so that characters from * the same font can be combined. */ - TeX: function (c,font,style,size) { - c = jsMath.TeX[font][c]; + TeX: function (C,font,style,size) { + var c = jsMath.TeX[font][C]; if (c.d == null) {c.d = 0}; if (c.h == null) {c.h = 0} + if (c.img != null && c.c != '') this.TeXIMG(font,C,jsMath.Typeset.StyleSize(style,size)); var scale = jsMath.Typeset.TeX(style,size).scale; var h = c.h + jsMath.TeX[font].dh var box = new jsMath.Box('text',c.c,c.w*scale,h*scale,c.d*scale); @@ -1686,15 +2510,80 @@ jsMath.Add(jsMath.Box,{ box.tclass = font; box.bh = scale*jsMath.TeX[font].h; box.bd = scale*jsMath.TeX[font].d; - if (jsMath.msieFontBug) { + if (jsMath.Browser.msieFontBug) { // hack to avoid Font changing back to the default // font when a unicode reference is not followed // by a letter or number box.html += 'x' } } + if (c.img != null) { + box.bh = c.img.bh; box.bd = c.img.bd; + box.tclass = "normal"; + } return box; }, + + /* + * Set the character's string to the appropriate image file + */ + TeXIMG: function (font,C,size) { + var c = jsMath.TeX[font][C]; + if (c.img.size != null && c.img.size == size && + c.img.best != null && c.img.best == jsMath.Img.best) return; + var mustScale = (jsMath.Img.scale != 1); + var id = jsMath.Img.best + size - 4; + if (id < 0) {id = 0; mustScale = 1} else + if (id >= jsMath.Img.fonts.length) {id = jsMath.Img.fonts.length-1; mustScale = 1} + var imgFont = jsMath.Img[jsMath.Img.fonts[id]]; + var img = imgFont[font][C]; + var scale = 1/jsMath.Img.w[jsMath.Img.fonts[id]]; + if (id != jsMath.Img.best + size - 4) { + if (c.w != null) {scale = c.w/img[0]} else { + scale *= jsMath.Img.fonts[size]/jsMath.Img.fonts[4] + * jsMath.Img.fonts[jsMath.Img.best]/jsMath.Img.fonts[id]; + } + } + var w = img[0]*scale; var h = img[1]*scale; var d = -img[2]*scale; var v; + var wadjust = (c.w == null || Math.abs(c.w-w) < .01)? "" : " margin-right:"+jsMath.HTML.Em(c.w-w)+';'; + var resize = ""; C = this.HexCode(C); + if (!mustScale && !jsMath.Controls.cookie.scaleImg) { + if (2*w < h || (jsMath.Browser.msieAlphaBug && jsMath.Controls.cookie.alpha)) + {resize = "height:"+(img[1]*jsMath.Browser.imgScale)+'px;'} + resize += " width:"+(img[0]*jsMath.Browser.imgScale)+'px;' + v = -img[2]+'px'; + } else { + if (2*w < h || (jsMath.Browser.msieAlphaBug && jsMath.Controls.cookie.alpha)) + {resize = "height:"+jsMath.HTML.Em(h*jsMath.Browser.imgScale)+';'} + resize += " width:"+jsMath.HTML.Em(w*jsMath.Browser.imgScale)+';' + v = jsMath.HTML.Em(d); + } + var vadjust = (Math.abs(d) < .01 && !jsMath.Browser.valignBug)? + "": " vertical-align:"+v+';'; + var URL = jsMath.Img.URL(font,jsMath.Img.fonts[id],C); + if (jsMath.Browser.msieAlphaBug && jsMath.Controls.cookie.alpha) { + c.c = ''; + } else { + c.c = ''; + } + c.tclass = "normal"; + c.img.bh = h+d; c.img.bd = -d; + c.img.size = size; c.img.best = jsMath.Img.best; + }, + + /* + * Get a two-character hex code (some browsers don't know toString(16)) + */ + HexCode: function (C) { + var codes = '0123456789ABCDEF'; + var h = Math.floor(C/16); var l = C - 16*h; + return codes.charAt(h)+codes.charAt(l); + }, /* * A box containing a spacer of a specific width @@ -1713,18 +2602,12 @@ jsMath.Add(jsMath.Box,{ }, /* - * A box containing a colored block - */ - Block: function (w,h,c) { - return new jsMath.Box('html',jsMath.HTML.Block(w,h,c),w,h,0); - }, - - /* * Get a character from a TeX font, and make sure that it has * its metrics specified. */ GetChar: function (code,font) { var c = jsMath.TeX[font][code]; + if (c.img != null) {this.TeXIMG(font,code,4)} if (c.tclass == null) {c.tclass = font} if (!c.computedW) { c.w = jsMath.EmBoxFor(jsMath.Typeset.AddClass(c.tclass,c.c)).w; @@ -1856,9 +2739,10 @@ jsMath.Add(jsMath.Box,{ Delimiter: function (H,delim,style,nocenter) { var size = 4; //### pass this? var TeX = jsMath.Typeset.TeX(style,size); - var CFSH = this.DelimBestFit(H,(delim&0xFF000)>>12,(delim&0xF00000)>>20,style); + if (!delim) {return this.Space(TeX.nulldelimiterspace)} + var CFSH = this.DelimBestFit(H,delim[2],delim[1],style); if (CFSH == null || CFSH[3] < H) - {CFSH = this.DelimBestFit(H,(delim&0xFF),(delim&0xF00)>>8,style)} + {CFSH = this.DelimBestFit(H,delim[4],delim[3],style)} if (CFSH == null) {return this.Space(TeX.nulldelimiterspace)} if (CFSH[2] == '') {return this.DelimExtend(H,CFSH[0],CFSH[1],TeX.axis_height,nocenter)} @@ -1875,9 +2759,10 @@ jsMath.Add(jsMath.Box,{ * is specified. */ GetCharCode: function (code) { - var font = jsMath.TeX.fam[(code&0xF00)>>8]; + var font = jsMath.TeX.fam[code[0]]; var Font = jsMath.TeX[font]; - var c = Font[code & 0xFF]; + var c = Font[code[1]]; + if (c.img != null) {this.TeXIMG(font,code[1],4)} if (c.w == null) {c.w = jsMath.EmBoxFor(jsMath.Typeset.AddClass(c.tclass,c.c)).w} if (c.font == null) {c.font = font} return c; @@ -1901,7 +2786,7 @@ jsMath.Add(jsMath.Box,{ Leaders: function (W,leader) { var h; var d; var w; var html; var font; if (leader.lmid) {// braces - font = jsMath.TeX.fam[(leader.left & 0xF00) >> 8]; + font = jsMath.TeX.fam[leader.left[0]]; var left = this.GetCharCode(leader.left); var right = this.GetCharCode(leader.right); var lmid = this.GetCharCode(leader.lmid); @@ -1914,7 +2799,7 @@ jsMath.Add(jsMath.Box,{ + jsMath.HTML.Rule(w,right.h) + this.AddClass(right.tclass,right.c,right.font); } else { //arrows - font = jsMath.TeX.fam[(leader.rep &0xF00) >> 8]; + font = jsMath.TeX.fam[leader.rep[0]]; var left = this.GetCharCode(leader.left? leader.left: leader.rep); var rep = this.GetCharCode(leader.rep); var right = this.GetCharCode(leader.right? leader.right: leader.rep); @@ -1928,7 +2813,7 @@ jsMath.Add(jsMath.Box,{ html += this.AddClass(rep.tclass,ehtml,rep.font) + jsMath.HTML.Spacer(w); ehtml = ''; for (var i = m; i < n; i++) {ehtml += ext}; html += this.AddClass(rep.tclass,ehtml,rep.font); - if (jsMath.msieFontBug) {html += 'x'} + if (jsMath.Browser.msieFontBug) {html += 'x'} html += jsMath.HTML.Place(this.AddClass(right.tclass,right.c,right.font),-.4,0); } w = jsMath.EmBoxFor(html).w; @@ -2075,7 +2960,7 @@ jsMath.Add(jsMath.Box,{ for (i = 0; i < W.length; i++) {w += W[i] + cspacing[i]} html = jsMath.HTML.Spacer(scale/6)+html+jsMath.HTML.Spacer(scale/6); - if (jsMath.spanHeightVaries) {y = h-jsMath.h} else {y = 0} + if (jsMath.Browser.spanHeightVaries) {y = h-jsMath.h} else {y = 0} html = jsMath.HTML.Absolute(html,w,h+d,d,y,H[0]); var box = new jsMath.Box('html',html,w+scale/3,h,d); return box; @@ -2085,7 +2970,7 @@ jsMath.Add(jsMath.Box,{ * Look for math within \hbox and other non-math text */ InternalMath: function (text,size) { - if (!text.match(/\$|\\\(/)) {return this.Text(text,'nonmath','T',size).Styled()} + if (!text.match(/\$|\\\(/)) {return this.Text(text,'normal','T',size).Styled()} var i = 0; var k = 0; var c; var match = ''; var mlist = []; var parse; var html; var box; @@ -2102,13 +2987,13 @@ jsMath.Add(jsMath.Box,{ } match = ''; k = i; } else { - mlist[mlist.length] = this.Text(text.slice(k,i-1),'nonmath','T',size,1,1); + mlist[mlist.length] = this.Text(text.slice(k,i-1),'normal','T',size,1,1); match = '$'; k = i; } } else if (c == '\\') { c = text.charAt(i++); if (c == '(' && match == '') { - mlist[mlist.length] = this.Text(text.slice(k,i-2),'nonmath','T',size,1,1); + mlist[mlist.length] = this.Text(text.slice(k,i-2),'normal','T',size,1,1); match = ')'; k = i; } else if (c == ')' && match == ')') { parse = jsMath.Parse(text.slice(k,i-2),null,size); @@ -2122,7 +3007,7 @@ jsMath.Add(jsMath.Box,{ } } } - mlist[mlist.length] = this.Text(text.slice(k),'nonmath','T',size,1,1); + mlist[mlist.length] = this.Text(text.slice(k),'normal','T',size,1,1); return this.SetList(mlist,'T',size); }, @@ -2188,10 +3073,8 @@ jsMath.Package(jsMath.Box,{ * Recompute the box width to make it more accurate. */ Remeasured: function () { - if (this.w > 0) { - if (!jsMath.spanHeightVaries || !this.html.match(/position: ?absolute/)) - {this.w = jsMath.EmBoxFor(this.html).w} - } + if (this.w > 0 && !this.html.match(/position: ?absolute/)) + {this.w = jsMath.EmBoxFor(this.html).w} return this; } @@ -2201,7 +3084,7 @@ jsMath.Package(jsMath.Box,{ /***************************************************************************/ /* - * mItems are the buiulding blocks of mLists (math lists) used to + * mItems are the building blocks of mLists (math lists) used to * store the information about a mathematical expression. These are * basically the items listed in the TeXbook in Appendix G (plus some * minor extensions). @@ -2429,7 +3312,7 @@ jsMath.Package(jsMath.mList,{ /* * For a list that has boundary delimiters as its first and last * entries, we replace the boundary atoms by open and close - * atoms whose nuclei are the specified delimiters properly sized + * atoms whose nuclii are the specified delimiters properly sized * for the contents of the list. (Rule 19) */ AddDelimiters: function(style,size) { @@ -2656,7 +3539,7 @@ jsMath.Add(jsMath.mList.prototype.Atomiz var t = TeX.default_rule_thickness; var p = t; if (style == 'D' || style == "D'") {p = TeX.x_height} var r = t + p/4; - var surd = jsMath.Box.Delimiter(box.h+box.d+r+t,0x270370,style,1); + var surd = jsMath.Box.Delimiter(box.h+box.d+r+t,[0,2,0x70,3,0x70],style,1); t = surd.h; // thickness of rule is height of surd character if (surd.d > box.h+box.d+r) {r = (r+surd.d-box.h-box.d)/2} surd.y = box.h+r; @@ -2665,10 +3548,12 @@ jsMath.Add(jsMath.mList.prototype.Atomiz var Cr = jsMath.Typeset.UpStyle(jsMath.Typeset.UpStyle(style)); var root = jsMath.Box.Set(mitem.root,Cr,size).Remeasured(); if (mitem.root) { - root.y = .55*(box.h+box.d+3*t+r)-box.d; surd.x = -(11/18)*surd.w; - root.x = Math.max((11/18)*surd.w - root.w, 0); + root.y = .55*(box.h+box.d+3*t+r)-box.d; + surd.x = Math.max(root.w-(11/18)*surd.w,0); + rule.x = (7/18)*surd.w; + root.x = -(root.w+rule.x); } - mitem.nuc = jsMath.Box.SetList([root,surd,rule,box],style,size); + mitem.nuc = jsMath.Box.SetList([surd,root,rule,box],style,size); mitem.type = 'ord'; jsMath.mList.prototype.Atomize.SupSub(style,size,mitem); }, @@ -2688,8 +3573,8 @@ jsMath.Add(jsMath.mList.prototype.Atomiz } if (s == null) {s = 0} - var c = mitem.accent & 0xFF; - var font = jsMath.TeX.fam[(mitem.accent&0xF00)>>8]; Font = jsMath.TeX[font]; + var c = mitem.accent[2]; + var font = jsMath.TeX.fam[mitem.accent[1]]; Font = jsMath.TeX[font]; while (Font[c].n && Font[Font[c].n].w <= u) {c = Font[c].n} var delta = Math.min(box.h,TeX.x_height); @@ -2728,11 +3613,11 @@ jsMath.Add(jsMath.mList.prototype.Atomiz box = jsMath.Box.Set(mitem.nuc,style,size); if (C.ic) { mitem.delta = C.ic * TeX.scale; - if (mitem.limits || !mitem.sub || jsMath.msieIntegralBug) + if (mitem.limits || !mitem.sub || jsMath.Browser.msieIntegralBug) {box = jsMath.Box.SetList([box,jsMath.mItem.Space(mitem.delta)],style,size)} } box.y = -((box.h+box.d)/2 - box.d - TeX.axis_height); - if (Math.abs(box.y) < .0001) (box.y = 0) + if (Math.abs(box.y) < .0001) {box.y = 0} } if (!box) {box = jsMath.Box.Set(mitem.nuc,style,size).Remeasured()} @@ -2760,7 +3645,7 @@ jsMath.Add(jsMath.mList.prototype.Atomiz mitem.nuc = jsMath.Box.SetList(mlist,style,size); mitem.nuc.h += dh; mitem.nuc.d += dd; } else { - if (jsMath.msieIntegralBug && mitem.sub && C && C.ic) + if (jsMath.Browser.msieIntegralBug && mitem.sub && C && C.ic) {mitem.nuc = jsMath.Box.SetList([box,jsMath.Box.Space(-C.ic*TeX.scale)],style,size)} else if (box.y) {mitem.nuc = jsMath.Box.SetList([box],style,size)} jsMath.mList.prototype.Atomize.SupSub(style,size,mitem); @@ -2968,6 +3853,15 @@ jsMath.Add(jsMath.Typeset,{ if (style == "SS" || style == "SS'") {return .5*v} return v; }, + + /* + * Return the size associated with a given style and size + */ + StyleSize: function (style,size) { + if (style == "S" || style == "S'") {size = Math.max(0,size-2)} + else if (style == "SS" || style == "SS'") {size = Math.max(0,size-4)} + return size; + }, /* * Return the font parameter table for the given style @@ -3123,7 +4017,7 @@ jsMath.Package(jsMath.Typeset,{ } this.FlushClassed(); // make sure scaling is included - if (this.dx) {this.hbuf += jsMath.HTML.Spacer(this.dx)} + if (this.dx) {this.hbuf += jsMath.HTML.Spacer(this.dx); this.w += this.dx} if (this.hbuf == '') {return jsMath.Box.Null} if (this.h == unset) {this.h = 0} if (this.d == unset) {this.d = 0} @@ -3156,9 +4050,9 @@ jsMath.Package(jsMath.Typeset,{ /* * Add a to position an item's HTML, and - * adjust the items height and depth. + * adjust the item's height and depth. * (This may be replaced buy one of the following browser-specific - * versions by InitBrowser().) + * versions by Browser.Init().) */ Place: function (item) { var html = ''+html} - if (item.x > 0) {html += ' margin-left:'+jsMath.HTML.Em(item.x)+';'} - if (item.y) {html += ' top:'+jsMath.HTML.Em(-item.y)+';'} - item.html = html + '">' + item.html + ''; - item.h += item.y; item.d -= item.y; - item.x = 0; item.y = 0; - }, - - /* - * Here, the horizontal spacing is always done separately. + * For MSIE on Windows, backspacing must be done in a separate + * , otherwise the contents will be clipped. Netscape + * also doesn't combine vertical and horizontal spacing well. + * Here, the horizontal and vertical spacing are done separately. */ PlaceSeparateSkips: function (item) { - if (item.y) - {item.html = '' + item.html + ''} + if (item.y) { + if (item.html.match(/^]*>(<\/SPAN>)?$/i) && !item.html.match(/top:/)) { + item.html = item.html.replace(/STYLE="/, + 'STYLE="position:relative; top:'+jsMath.HTML.Em(-item.y)+';'); + } else { + item.html = '' + item.html + '' + } + } if (item.x) - {item.html = jsMath.msieSpaceFix - + '' - + '' + item.html} + {item.html = jsMath.Browser.msieSpaceFix + + '' + + jsMath.Browser.hiddenSpace + '' + item.html} item.h += item.y; item.d -= item.y; item.x = 0; item.y = 0; } @@ -3236,26 +4124,26 @@ jsMath.Package(jsMath.Parser,{ // the \mathchar definitions (see Appendix B of the TeXbook). mathchar: { - '!': 0x5021, - '(': 0x4028, - ')': 0x5029, - '*': 0x2203, // \ast - '+': 0x202B, - ',': 0x613B, - '-': 0x2200, - '.': 0x013A, - '/': 0x013D, - ':': 0x303A, - ';': 0x603B, - '<': 0x313C, - '=': 0x303D, - '>': 0x313E, - '?': 0x503F, - '[': 0x405B, - ']': 0x505D, -// '{': 0x4266, -// '}': 0x5267, - '|': 0x026A + '!': [5,0,0x21], + '(': [4,0,0x28], + ')': [5,0,0x29], + '*': [2,2,0x03], // \ast + '+': [2,0,0x2B], + ',': [6,1,0x3B], + '-': [2,2,0x00], + '.': [0,1,0x3A], + '/': [0,1,0x3D], + ':': [3,0,0x3A], + ';': [6,0,0x3B], + '<': [3,1,0x3C], + '=': [3,0,0x3D], + '>': [3,1,0x3E], + '?': [5,0,0x3F], + '[': [4,0,0x5B], + ']': [5,0,0x5D], +// '{': [4,2,0x66], +// '}': [5,2,0x67], + '|': [0,2,0x6A] }, // handle special \catcode characters @@ -3274,244 +4162,244 @@ jsMath.Package(jsMath.Parser,{ // the \mathchardef table (see Appendix B of the TeXbook). mathchardef: { // brace parts - braceld: 0x37A, - bracerd: 0x37B, - bracelu: 0x37C, - braceru: 0x37D, + braceld: [0,3,0x7A], + bracerd: [0,3,0x7B], + bracelu: [0,3,0x7C], + braceru: [0,3,0x7D], // Greek letters - alpha: 0x010B, - beta: 0x010C, - gamma: 0x010D, - delta: 0x010E, - epsilon: 0x010F, - zeta: 0x0110, - eta: 0x0111, - theta: 0x0112, - iota: 0x0113, - kappa: 0x0114, - lambda: 0x0115, - mu: 0x0116, - nu: 0x0117, - xi: 0x0118, - pi: 0x0119, - rho: 0x011A, - sigma: 0x011B, - tau: 0x011C, - upsilon: 0x011D, - phi: 0x011E, - chi: 0x011F, - psi: 0x0120, - omega: 0x0121, - varepsilon: 0x0122, - vartheta: 0x0123, - varpi: 0x0124, - varrho: 0x0125, - varsigma: 0x0126, - varphi: 0x0127, + alpha: [0,1,0x0B], + beta: [0,1,0x0C], + gamma: [0,1,0x0D], + delta: [0,1,0x0E], + epsilon: [0,1,0x0F], + zeta: [0,1,0x10], + eta: [0,1,0x11], + theta: [0,1,0x12], + iota: [0,1,0x13], + kappa: [0,1,0x14], + lambda: [0,1,0x15], + mu: [0,1,0x16], + nu: [0,1,0x17], + xi: [0,1,0x18], + pi: [0,1,0x19], + rho: [0,1,0x1A], + sigma: [0,1,0x1B], + tau: [0,1,0x1C], + upsilon: [0,1,0x1D], + phi: [0,1,0x1E], + chi: [0,1,0x1F], + psi: [0,1,0x20], + omega: [0,1,0x21], + varepsilon: [0,1,0x22], + vartheta: [0,1,0x23], + varpi: [0,1,0x24], + varrho: [0,1,0x25], + varsigma: [0,1,0x26], + varphi: [0,1,0x27], - Gamma: 0x7000, - Delta: 0x7001, - Theta: 0x7002, - Lambda: 0x7003, - Xi: 0x7004, - Pi: 0x7005, - Sigma: 0x7006, - Upsilon: 0x7007, - Phi: 0x7008, - Psi: 0x7009, - Omega: 0x700A, + Gamma: [7,0,0x00], + Delta: [7,0,0x01], + Theta: [7,0,0x02], + Lambda: [7,0,0x03], + Xi: [7,0,0x04], + Pi: [7,0,0x05], + Sigma: [7,0,0x06], + Upsilon: [7,0,0x07], + Phi: [7,0,0x08], + Psi: [7,0,0x09], + Omega: [7,0,0x0A], // Ord symbols - aleph: 0x0240, - imath: 0x017B, - jmath: 0x017C, - ell: 0x0160, - wp: 0x017D, - Re: 0x023C, - Im: 0x023D, - partial: 0x0140, - infty: 0x0231, - prime: 0x0230, - emptyset: 0x023B, - nabla: 0x0272, - surd: 0x1270, - top: 0x023E, - bot: 0x023F, - triangle: 0x0234, - forall: 0x0238, - exists: 0x0239, - neg: 0x023A, - lnot: 0x023A, - flat: 0x015B, - natural: 0x015C, - sharp: 0x015D, - clubsuit: 0x027C, - diamondsuit: 0x027D, - heartsuit: 0x027E, - spadesuit: 0x027F, + aleph: [0,2,0x40], + imath: [0,1,0x7B], + jmath: [0,1,0x7C], + ell: [0,1,0x60], + wp: [0,1,0x7D], + Re: [0,2,0x3C], + Im: [0,2,0x3D], + partial: [0,1,0x40], + infty: [0,2,0x31], + prime: [0,2,0x30], + emptyset: [0,2,0x3B], + nabla: [0,2,0x72], + surd: [1,2,0x70], + top: [0,2,0x3E], + bot: [0,2,0x3F], + triangle: [0,2,0x34], + forall: [0,2,0x38], + exists: [0,2,0x39], + neg: [0,2,0x3A], + lnot: [0,2,0x3A], + flat: [0,1,0x5B], + natural: [0,1,0x5C], + sharp: [0,1,0x5D], + clubsuit: [0,2,0x7C], + diamondsuit: [0,2,0x7D], + heartsuit: [0,2,0x7E], + spadesuit: [0,2,0x7F], // big ops - coprod: 0x1360, - bigvee: 0x1357, - bigwedge: 0x1356, - biguplus: 0x1355, - bigcap: 0x1354, - bigcup: 0x1353, - intop: 0x1352, - prod: 0x1351, - sum: 0x1350, - bigotimes: 0x134E, - bigoplus: 0x134C, - bigodot: 0x134A, - ointop: 0x1348, - bigsqcup: 0x1346, - smallint: 0x1273, + coprod: [1,3,0x60], + bigvee: [1,3,0x57], + bigwedge: [1,3,0x56], + biguplus: [1,3,0x55], + bigcap: [1,3,0x54], + bigcup: [1,3,0x53], + intop: [1,3,0x52], + prod: [1,3,0x51], + sum: [1,3,0x50], + bigotimes: [1,3,0x4E], + bigoplus: [1,3,0x4C], + bigodot: [1,3,0x4A], + ointop: [1,3,0x48], + bigsqcup: [1,3,0x46], + smallint: [1,2,0x73], // binary operations - triangleleft: 0x212F, - triangleright: 0x212E, - bigtriangleup: 0x2234, - bigtriangledown: 0x2235, - wedge: 0x225E, - land: 0x225E, - vee: 0x225F, - lor: 0x225F, - cap: 0x225C, - cup: 0x225B, - ddagger: 0x227A, - dagger: 0x2279, - sqcap: 0x2275, - sqcup: 0x2274, - uplus: 0x225D, - amalg: 0x2271, - diamond: 0x2205, - bullet: 0x220F, - wr: 0x226F, - div: 0x2204, - odot: 0x220C, - oslash: 0x220B, - otimes: 0x220A, - ominus: 0x2209, - oplus: 0x2208, - mp: 0x2207, - pm: 0x2206, - circ: 0x220E, - bigcirc: 0x220D, - setminus: 0x226E, // for set difference A\setminus B - cdot: 0x2201, - ast: 0x2203, - times: 0x2202, - star: 0x213F, + triangleleft: [2,1,0x2F], + triangleright: [2,1,0x2E], + bigtriangleup: [2,2,0x34], + bigtriangledown: [2,2,0x35], + wedge: [2,2,0x5E], + land: [2,2,0x5E], + vee: [2,2,0x5F], + lor: [2,2,0x5F], + cap: [2,2,0x5C], + cup: [2,2,0x5B], + ddagger: [2,2,0x7A], + dagger: [2,2,0x79], + sqcap: [2,2,0x75], + sqcup: [2,2,0x74], + uplus: [2,2,0x5D], + amalg: [2,2,0x71], + diamond: [2,2,0x05], + bullet: [2,2,0x0F], + wr: [2,2,0x6F], + div: [2,2,0x04], + odot: [2,2,0x0C], + oslash: [2,2,0x0B], + otimes: [2,2,0x0A], + ominus: [2,2,0x09], + oplus: [2,2,0x08], + mp: [2,2,0x07], + pm: [2,2,0x06], + circ: [2,2,0x0E], + bigcirc: [2,2,0x0D], + setminus: [2,2,0x6E], // for set difference A\setminus B + cdot: [2,2,0x01], + ast: [2,2,0x03], + times: [2,2,0x02], + star: [2,1,0x3F], // Relations - propto: 0x322F, - sqsubseteq: 0x3276, - sqsupseteq: 0x3277, - parallel: 0x326B, - mid: 0x326A, - dashv: 0x3261, - vdash: 0x3260, - leq: 0x3214, - le: 0x3214, - geq: 0x3215, - ge: 0x3215, - succ: 0x321F, - prec: 0x321E, - approx: 0x3219, - succeq: 0x3217, - preceq: 0x3216, - supset: 0x321B, - subset: 0x321A, - supseteq: 0x3213, - subseteq: 0x3212, - 'in': 0x3232, - ni: 0x3233, - owns: 0x3233, - gg: 0x321D, - ll: 0x321C, - not: 0x3236, - sim: 0x3218, - simeq: 0x3227, - perp: 0x323F, - equiv: 0x3211, - asymp: 0x3210, - smile: 0x315E, - frown: 0x315F, + propto: [3,2,0x2F], + sqsubseteq: [3,2,0x76], + sqsupseteq: [3,2,0x77], + parallel: [3,2,0x6B], + mid: [3,2,0x6A], + dashv: [3,2,0x61], + vdash: [3,2,0x60], + leq: [3,2,0x14], + le: [3,2,0x14], + geq: [3,2,0x15], + ge: [3,2,0x15], + succ: [3,2,0x1F], + prec: [3,2,0x1E], + approx: [3,2,0x19], + succeq: [3,2,0x17], + preceq: [3,2,0x16], + supset: [3,2,0x1B], + subset: [3,2,0x1A], + supseteq: [3,2,0x13], + subseteq: [3,2,0x12], + 'in': [3,2,0x32], + ni: [3,2,0x33], + owns: [3,2,0x33], + gg: [3,2,0x1D], + ll: [3,2,0x1C], + not: [3,2,0x36], + sim: [3,2,0x18], + simeq: [3,2,0x27], + perp: [3,2,0x3F], + equiv: [3,2,0x11], + asymp: [3,2,0x10], + smile: [3,1,0x5E], + frown: [3,1,0x5F], // Arrows - Leftrightarrow: 0x322C, - Leftarrow: 0x3228, - Rightarrow: 0x3229, - leftrightarrow: 0x3224, - leftarrow: 0x3220, - gets: 0x3220, - rightarrow: 0x3221, - to: 0x3221, - mapstochar: 0x3237, - leftharpoonup: 0x3128, - leftharpoondown: 0x3129, - rightharpoonup: 0x312A, - rightharpoondown: 0x312B, - nearrow: 0x3225, - searrow: 0x3226, - nwarrow: 0x322D, - swarrow: 0x322E, - - hbarchar: 0x0016, // for \hbar - lhook: 0x312C, - rhook: 0x312D, - - ldotp: 0x613A, // ldot as a punctuation mark - cdotp: 0x6201, // cdot as a punctuation mark - colon: 0x603A, // colon as a punctuation mark - - '#': 0x7023, - '$': 0x7024, - '%': 0x7025, - '&': 0x7026 + Leftrightarrow: [3,2,0x2C], + Leftarrow: [3,2,0x28], + Rightarrow: [3,2,0x29], + leftrightarrow: [3,2,0x24], + leftarrow: [3,2,0x20], + gets: [3,2,0x20], + rightarrow: [3,2,0x21], + to: [3,2,0x21], + mapstochar: [3,2,0x37], + leftharpoonup: [3,1,0x28], + leftharpoondown: [3,1,0x29], + rightharpoonup: [3,1,0x2A], + rightharpoondown: [3,1,0x2B], + nearrow: [3,2,0x25], + searrow: [3,2,0x26], + nwarrow: [3,2,0x2D], + swarrow: [3,2,0x2E], + + hbarchar: [0,0,0x16], // for \hbar + lhook: [3,1,0x2C], + rhook: [3,1,0x2D], + + ldotp: [6,1,0x3A], // ldot as a punctuation mark + cdotp: [6,2,0x01], // cdot as a punctuation mark + colon: [6,0,0x3A], // colon as a punctuation mark + + '#': [7,0,0x23], + '$': [7,0,0x24], + '%': [7,0,0x25], + '&': [7,0,0x26] }, // The delimiter table (see Appendix B of the TeXbook) delimiter: { - '(': 0x0028300, - ')': 0x0029301, - '[': 0x005B302, - ']': 0x005D303, - '<': 0x026830A, - '>': 0x026930B, - '/': 0x002F30E, - '|': 0x026A30C, - '.': 0x0000000, - '\\': 0x026E30F, - '\\lmoustache': 0x437A340, // top from (, bottom from ) - '\\rmoustache': 0x537B341, // top from ), bottom from ( - '\\lgroup': 0x462833A, // extensible ( with sharper tips - '\\rgroup': 0x562933B, // extensible ) with sharper tips - '\\arrowvert': 0x026A33C, // arrow without arrowheads - '\\Arrowvert': 0x026B33D, // double arrow without arrowheads -// '\\bracevert': 0x077C33E, // the vertical bar that extends braces - '\\bracevert': 0x026A33E, // we don't load tt, so use | instead - '\\Vert': 0x026B30D, - '\\|': 0x026B30D, - '\\vert': 0x026A30C, - '\\uparrow': 0x3222378, - '\\downarrow': 0x3223379, - '\\updownarrow': 0x326C33F, - '\\Uparrow': 0x322A37E, - '\\Downarrow': 0x322B37F, - '\\Updownarrow': 0x326D377, - '\\backslash': 0x026E30F, // for double coset G\backslash H - '\\rangle': 0x526930B, - '\\langle': 0x426830A, - '\\rbrace': 0x5267309, - '\\lbrace': 0x4266308, - '\\}': 0x5267309, - '\\{': 0x4266308, - '\\rceil': 0x5265307, - '\\lceil': 0x4264306, - '\\rfloor': 0x5263305, - '\\lfloor': 0x4262304 + '(': [0,0,0x28,3,0x00], + ')': [0,0,0x29,3,0x01], + '[': [0,0,0x5B,3,0x02], + ']': [0,0,0x5D,3,0x03], + '<': [0,2,0x68,3,0x0A], + '>': [0,2,0x69,3,0x0B], + '/': [0,0,0x2F,3,0x0E], + '|': [0,2,0x6A,3,0x0C], + '.': [0,0,0x00,0,0x00], + '\\': [0,2,0x6E,3,0x0F], + '\\lmoustache': [4,3,0x7A,3,0x40], // top from (, bottom from ) + '\\rmoustache': [5,3,0x7B,3,0x41], // top from ), bottom from ( + '\\lgroup': [4,6,0x28,3,0x3A], // extensible ( with sharper tips + '\\rgroup': [5,6,0x29,3,0x3B], // extensible ) with sharper tips + '\\arrowvert': [0,2,0x6A,3,0x3C], // arrow without arrowheads + '\\Arrowvert': [0,2,0x6B,3,0x3D], // double arrow without arrowheads +// '\\bracevert': [0,7,0x7C,3,0x3E], // the vertical bar that extends braces + '\\bracevert': [0,2,0x6A,3,0x3E], // we don't load tt, so use | instead + '\\Vert': [0,2,0x6B,3,0x0D], + '\\|': [0,2,0x6B,3,0x0D], + '\\vert': [0,2,0x6A,3,0x0C], + '\\uparrow': [3,2,0x22,3,0x78], + '\\downarrow': [3,2,0x23,3,0x79], + '\\updownarrow': [3,2,0x6C,3,0x3F], + '\\Uparrow': [3,2,0x2A,3,0x7E], + '\\Downarrow': [3,2,0x2B,3,0x7F], + '\\Updownarrow': [3,2,0x6D,3,0x77], + '\\backslash': [0,2,0x6E,3,0x0F], // for double coset G\backslash H + '\\rangle': [5,2,0x69,3,0x0B], + '\\langle': [4,2,0x68,3,0x0A], + '\\rbrace': [5,2,0x67,3,0x09], + '\\lbrace': [4,2,0x66,3,0x08], + '\\}': [5,2,0x67,3,0x09], + '\\{': [4,2,0x66,3,0x08], + '\\rceil': [5,2,0x65,3,0x07], + '\\lceil': [4,2,0x64,3,0x06], + '\\rfloor': [5,2,0x63,3,0x05], + '\\lfloor': [4,2,0x62,3,0x04] }, /* @@ -3621,7 +4509,7 @@ jsMath.Package(jsMath.Parser,{ doteq: ['Macro','\\buildrel\\textstyle.\\over='], ldots: ['Macro','\\mathinner{\\ldotp\\ldotp\\ldotp}'], cdots: ['Macro','\\mathinner{\\cdotp\\cdotp\\cdotp}'], - vdots: ['Macro','\\mathinner{\\rlap{\\raise8pt{\\rule 0pt 6pt 0pt .}}\\rlap{\\raise4pt{.}}.}'], + vdots: ['Macro','\\mathinner{\\rlap{\\raise8pt{.\\rule 0pt 6pt 0pt}}\\rlap{\\raise4pt{.}}.}'], ddots: ['Macro','\\mathinner{\\kern1mu\\raise7pt{\\rule 0pt 7pt 0pt .}\\kern2mu\\raise4pt{.}\\kern2mu\\raise1pt{.}\\kern1mu}'], joinrel: ['Macro','\\mathrel{\\kern-4mu}'], relbar: ['Macro','\\mathrel{\\smash-}'], // \smash, because - has the same height as + @@ -3663,7 +4551,7 @@ jsMath.Package(jsMath.Parser,{ hskip: 'Hskip', kern: 'Hskip', - rule: ['Rule','black'], + rule: ['Rule','colored'], space: ['Rule','blank'], big: ['MakeBig','ord',0.85], @@ -3707,18 +4595,18 @@ jsMath.Package(jsMath.Parser,{ hphantom: ['Phantom',0,1], smash: 'Smash', - acute: ['MathAccent', 0x7013], - grave: ['MathAccent', 0x7012], - ddot: ['MathAccent', 0x707F], - tilde: ['MathAccent', 0x707E], - bar: ['MathAccent', 0x7016], - breve: ['MathAccent', 0x7015], - check: ['MathAccent', 0x7014], - hat: ['MathAccent', 0x705E], - vec: ['MathAccent', 0x017E], - dot: ['MathAccent', 0x705F], - widetilde: ['MathAccent', 0x0365], - widehat: ['MathAccent', 0x0362], + acute: ['MathAccent', [7,0,0x13]], + grave: ['MathAccent', [7,0,0x12]], + ddot: ['MathAccent', [7,0,0x7F]], + tilde: ['MathAccent', [7,0,0x7E]], + bar: ['MathAccent', [7,0,0x16]], + breve: ['MathAccent', [7,0,0x15]], + check: ['MathAccent', [7,0,0x14]], + hat: ['MathAccent', [7,0,0x5E]], + vec: ['MathAccent', [0,1,0x7E]], + dot: ['MathAccent', [7,0,0x5F]], + widetilde: ['MathAccent', [0,3,0x65]], + widehat: ['MathAccent', [0,3,0x62]], '_': ['Replace','ord','_','normal',-.4,.1], ' ': ['Replace','ord',' ','normal'], @@ -3754,8 +4642,7 @@ jsMath.Package(jsMath.Parser,{ unicode: 'Unicode', // debugging and test routines - 'char': 'Char', - test: 'Test' + 'char': 'Char' }, /* @@ -3777,10 +4664,10 @@ jsMath.Package(jsMath.Parser,{ * The horizontally stretchable delimiters */ leaders: { - downbrace: {left: 0x37A, lmid: 0x37D, rmid: 0x37C, right: 0x37B}, - upbrace: {left: 0x37C, lmid: 0x37B, rmid: 0x37A, right: 0x37D}, - leftarrow: {left: 0x220, rep: 0x200}, - rightarrow: {rep: 0x200, right: 0x221} + downbrace: {left: [3,0x7A], lmid: [3,0x7D], rmid: [3,0x7C], right: [3,0x7B]}, + upbrace: {left: [3,0x7C], lmid: [3,0x7B], rmid: [3,0x7A], right: [3,0x7D]}, + leftarrow: {left: [2,0x20], rep: [2,0x00]}, + rightarrow: {rep: [2,0x00], right: [2,0x21]} }, @@ -3894,11 +4781,20 @@ jsMath.Package(jsMath.Parser,{ * converted when typeset. */ GetDimen: function (name,nomu) { - var rest = this.string.slice(this.i); + var rest; var advance = 0; + if (this.nextIsSpace()) {this.i++} + if (this.string.charAt(this.i) == '{') { + rest = this.GetArgument(name); + } else { + rest = this.string.slice(this.i); + advance = 1; + } var match = rest.match(/^\s*([-+]?(\.\d+|\d+(\.\d*)?))(pt|em|ex|mu|px)/); if (!match) {this.Error("Missing dimension or its units for "+name); return} - this.i += match[0].length; - if (this.nextIsSpace()) {this.i++} + if (advance) { + this.i += match[0].length; + if (this.nextIsSpace()) {this.i++} + } var d = match[1]-0; if (match[4] == 'px') {d /= jsMath.em} else if (match[4] == 'pt') {d /= 10} @@ -4275,23 +5171,6 @@ jsMath.Package(jsMath.Parser,{ }, /* - * Debugging routine to test stretchable delimiters - */ - Test: function () { - var delim = this.GetDelimiter(this.cmd+'test'); if (this.error) return; - var H = this.GetArgument(this.cmd+'test'); if (this.error) return; - this.mlist.Add(jsMath.mItem.Typeset(jsMath.Box.Delimiter(H,delim,'T'))); - return; - - var leader = this.GetArgument(this.cmd+'test'); if (this.error) return; - var W = this.GetArgument(this.cmd+'test'); if (this.error) return; - if (this.leaders[leader] == null) - {this.Error('Unknown leaders "'+leader+'"'); return} - this.mlist.Add(jsMath.mItem.Typeset(jsMath.Box.Leaders(W,this.leaders[leader]))); - return; - }, - - /* * Add a fixed amount of horizontal space */ Spacer: function (name,w) { @@ -4335,15 +5214,27 @@ jsMath.Package(jsMath.Parser,{ * This replaces \hrule and \vrule * @@@ not a standard TeX command, and all three parameters must be given @@@ */ - Rule: function (name,gif) { + Rule: function (name,style) { var w = this.GetDimen(this.cmd+name,1); if (this.error) return; var h = this.GetDimen(this.cmd+name,1); if (this.error) return; var d = this.GetDimen(this.cmd+name,1); if (this.error) return; - h += d; + h += d; var html; if (h != 0) {h = Math.max(1.05/jsMath.em,h)} - if (h == 0 || w == 0) {gif = "blank"} - var html = ''; + if (h == 0 || w == 0) {style = "blank"} + if (w == 0) { + html = ''; + } else if (style == "blank") { + html = ''; + } else { + html = ''; + } if (d) { html = '' + html + ''; @@ -4485,10 +5376,7 @@ jsMath.Package(jsMath.Parser,{ * Process the character associated with a specific \mathcharcode */ HandleMathCode: function (name,code) { - var type = (code & 0xF000) >> 12; - var font = (code & 0x0F00) >> 8; - var code = code & 0x00FF; - this.HandleTeXchar(type,font,code); + this.HandleTeXchar(code[0],code[1],code[2]); }, /* @@ -4566,7 +5454,7 @@ jsMath.Package(jsMath.Parser,{ return; } if (this.delimiter[this.cmd+cmd]) { - this.HandleMathCode(cmd,this.delimiter[this.cmd+cmd]>>12) + this.HandleMathCode(cmd,this.delimiter[this.cmd+cmd].slice(0,3)) return; } this.Error("Unknown control sequence '"+this.cmd+cmd+"'"); @@ -4682,52 +5570,40 @@ jsMath.Package(jsMath.Parser,{ * results. We also include an image to force the results to take up * the right amount of space. The results may need to be vertically * adjusted to make the baseline appear in the correct place. - * - * This is where the touchiest browser-dependent code appears. */ Typeset: function () { var data = this.mlist.init; var box = this.typeset = this.mlist.Typeset(data.style,data.size); if (this.error) {return ''+this.error+''} if (box.format == 'null') {return ''}; - var rules = ''; var html box.Styled().Remeasured(); var isSmall = 0; var isBig = 0; - var w = box.w; var h = box.bh; var d = box.bd; if (box.bh > box.h && box.bh > jsMath.h+.001) {isSmall = 1} if (box.bd > box.d && box.bd > jsMath.d+.001) {isSmall = 1} - if (box.h > jsMath.h) {isBig = 1; h = box.h} - if (box.d > jsMath.d) {isBig = 1; d = box.d} + if (box.h > jsMath.h || box.d > jsMath.d) {isBig = 1} - if (jsMath.show.BBox) {rules += jsMath.HTML.Frame(0,-box.d,w,box.h+box.d,'green')} - if (jsMath.show.Top) {rules += jsMath.HTML.Line(0,box.h,w,'red')} - if (jsMath.show.Baseline) {rules += jsMath.HTML.Line(0,0,w,'blue')} - - html = box.html; + var html = box.html; if (isSmall) {// hide the extra size - if (jsMath.allowAbsolute) { - var y = jsMath.absoluteOffsetY; - if (jsMath.absoluteHeightVaries || box.bh > jsMath.h+.001) {y += (jsMath.h - box.bh)} - html = jsMath.HTML.Absolute(html,w,jsMath.h,0,y,jsMath.h); - isBig = 1; h = box.h; d = box.d; - } else {// remove line height and try to hide the depth + if (jsMath.Browser.allowAbsolute) { + var y = 0; + if (box.bh > jsMath.h+.001) {y = jsMath.h - box.bh} + html = jsMath.HTML.Absolute(html,box.w,jsMath.h,0,y,jsMath.h); + } else if (!jsMath.Browser.valignBug) { + // remove line height and try to hide the depth var dy = jsMath.HTML.Em(Math.max(0,box.bd-jsMath.hd)/3); html = '' - + html - + ''; + + ' position:relative; top:'+dy+'; vertical-align:'+dy + + '">' + html + ''; } + isBig = 1; } - html = '' + rules + html; if (isBig) {// add height and depth to the line (force a little // extra to separate lines if needed) - html += '' + html += '' } - html += '' - return html; + return ''+html+''; } }); @@ -4760,7 +5636,7 @@ jsMath.Parser.prototype.AddSpecial({ * requires. These are substituted for #1, #2, etc. within the * replacement string of the macro. For example * - * + * * * would make \x1 produce {\vec x}_{1} and \x{i+1} produce {\vec x}_{i+1}. * @@ -4812,7 +5688,6 @@ jsMath.Add(jsMath,{ /* * Typeset a string in \displaystyle and return the HTML for it - * ### need to give more control over whether to center, etc. ### */ DisplayMode: function (s) { var parse = jsMath.Parse(s,null,null,'D'); @@ -4826,13 +5701,11 @@ jsMath.Add(jsMath,{ */ GetElementText: function (element) { var text = element.innerText; - if (text == null) { - text = element.textContent; - if (text == null) { - text = element.innerHTML; - } + if (text == null || text == "") { + try {text = element.textContent} catch (err) {} + if (text == null || text == "") {text = element.innerHTML} } - if (text.search('&')) { + if (text.search('&') >= 0) { text = text.replace(/</g,'<'); text = text.replace(/>/g,'>'); text = text.replace(/"/g,'"'); @@ -4842,12 +5715,28 @@ jsMath.Add(jsMath,{ }, /* + * Move hidden to the location of the math element to be + * processed and reinitialize sizes for that location. + */ + ResetHidden: function (element) { + element.innerHTML = + '' + + jsMath.Browser.operaHiddenFix; // needed by Opera in tables + element.className=''; + jsMath.hidden = element.firstChild; + jsMath.ReInit(); + }, + + + /* * Typeset the contents of an element in \textstyle */ ConvertText: function (element) { var text = this.GetElementText(element); + this.ResetHidden(element); element.innerHTML = this.TextMode(text); element.className = 'typeset'; + element.alt = text; }, /* @@ -4855,35 +5744,34 @@ jsMath.Add(jsMath,{ */ ConvertDisplay: function (element) { var text = this.GetElementText(element); + this.ResetHidden(element); element.innerHTML = this.DisplayMode(text); element.className = 'typeset'; - }, - - /* - * Call this at the bottom of your HTML page to have the - * mathematics typeset before the page is displayed. - * This can take a long time, so the user could cancel the - * page before it is complete; use it with caution, and only - * when there is a relatively small amount of math on the page. - */ - ProcessBeforeShowing: function () { - if (!jsMath.initialized) {jsMath.Init()} - var element = jsMath.GetMathElements(); - for (var i = 0; i < element.length; i++) - {jsMath.ProcessElement(element[i])} - jsMath.ProcessComplete(); + element.alt = text; }, /* * Process a math element */ ProcessElement: function (element) { - window.status = 'Processing Math...'; - if (element.tagName == 'DIV') { - this.ConvertDisplay(element); - } else if (element.tagName == 'SPAN') { - this.ConvertText(element); - } + try { + if (element.tagName == 'DIV') { + this.ConvertDisplay(element); + } else if (element.tagName == 'SPAN') { + this.ConvertText(element); + // + // Overcome a bug in MSIE where were tex2math can't insert DIV's inside + // some elements, so fake it with SPANs, but can't fake the centering, + // so do that here. + // + if (element.parentNode.className == 'jsMath.recenter') { + element.parentNode.style.marginLeft = + Math.floor((element.parentNode.offsetWidth - element.offsetWidth)/2)+"px"; + } + } + element.onclick = jsMath.Click.CheckClick; + element.ondblclick = jsMath.Click.CheckDblClick; + } catch (err) {} }, /* @@ -4895,7 +5783,7 @@ jsMath.Add(jsMath,{ this.ProcessComplete(); } else { this.ProcessElement(this.element[k]) - setTimeout('jsMath.ProcessElements('+(k+1)+')',jsMath.delay); + setTimeout('jsMath.ProcessElements('+(k+1)+')',jsMath.Browser.delay); } }, @@ -4905,11 +5793,27 @@ jsMath.Add(jsMath,{ * start reading the mathematics while the rest of the page * is being processed. */ - Process: function () { + Process: function (obj) { if (!jsMath.initialized) {jsMath.Init()} - this.element = this.GetMathElements(); + this.element = this.GetMathElements(obj); window.status = 'Processing Math...'; - setTimeout('jsMath.ProcessElements(0)',jsMath.delay); + setTimeout('jsMath.ProcessElements(0)',jsMath.Browser.delay); + }, + + /* + * Call this at the bottom of your HTML page to have the + * mathematics typeset before the page is displayed. + * This can take a long time, so the user could cancel the + * page before it is complete; use it with caution, and only + * when there is a relatively small amount of math on the page. + */ + ProcessBeforeShowing: function (obj) { + if (!jsMath.initialized) {jsMath.Init()} + var element = jsMath.GetMathElements(obj); + window.status = 'Processing Math...'; + for (var i = 0; i < element.length; i++) + {jsMath.ProcessElement(element[i])} + jsMath.ProcessComplete(); }, element: [], // the list of math elements on the page @@ -4918,25 +5822,30 @@ jsMath.Add(jsMath,{ * Look up all the math elements on the page and * put them in a list sorted from top to bottom of the page */ - GetMathElements: function () { + GetMathElements: function (obj) { var element = []; - var math = document.getElementsByTagName('DIV'); + if (!obj) {obj = document} + if (typeof(obj) == 'string') {obj = document.getElementById(obj)} + if (!obj.getElementsByTagName) return + var math = obj.getElementsByTagName('DIV'); for (var k = 0; k < math.length; k++) { if (math[k].className == 'math') { - if (jsMath.renameOK) {math[k].setAttribute('NAME','_jsMath_')} + if (jsMath.Browser.renameOK && obj.getElementsByName) + {math[k].setAttribute('NAME','_jsMath_')} else {element[element.length] = math[k]} } } - math = document.getElementsByTagName('SPAN'); + math = obj.getElementsByTagName('SPAN'); for (var k = 0; k < math.length; k++) { if (math[k].className == 'math') { - if (jsMath.renameOK) {math[k].setAttribute('NAME','_jsMath_')} + if (jsMath.Browser.renameOK && obj.getElementsByName) + {math[k].setAttribute('NAME','_jsMath_')} else {element[element.length] = math[k]} } } // this gets the SPAN and DIV elements interleaved in order - if (jsMath.renameOK) { - element = document.getElementsByName('_jsMath_') + if (jsMath.Browser.renameOK && obj.getElementsByName) { + element = obj.getElementsByName('_jsMath_'); } else if (jsMath.hidden.sourceIndex) { element.sort(function (a,b) {return a.sourceIndex - b.sourceIndex}); } @@ -4948,42 +5857,39 @@ jsMath.Add(jsMath,{ * and clean up any marked or
tags */ ProcessComplete: function () { - if (jsMath.renameOK) { + if (jsMath.Browser.renameOK) { var element = document.getElementsByName('_jsMath_'); for (var i = element.length-1; i >= 0; i--) { element[i].removeAttribute('NAME'); } } + jsMath.hidden = jsMath.hiddenTop; jsMath.element = []; window.status = 'Done'; - } - + if (jsMath.Browser.safariImgBug && + (jsMath.Controls.cookie.font == 'symbol' || + jsMath.Controls.cookie.font == 'image')) { + // + // For Safari, the images don't always finish + // updating, so nudge the window to cause a + // redraw. (Hack!) + // + setTimeout("window.resizeBy(-1,0); window.resizeBy(1,0);",2000); + } + }, + + Element: function (name) {return document.getElementById('jsMath.'+name)} + }); -/***************************************************************************/ -/* - * We use a hidden
for measuring the BBoxes of things - */ -jsMath.hidden = '
'; -if (document.body.insertAdjacentHTML) { - document.body.insertAdjacentHTML('AfterBegin',jsMath.hidden); -} else { - document.write(jsMath.hidden); -} -jsMath.hidden = document.getElementById("jsMath.Hidden"); +/***************************************************************************/ /* * Initialize everything */ -jsMath.InitSource(); -jsMath.InitBrowser(); -jsMath.InitStyles(); +jsMath.Loaded(); +jsMath.Controls.GetCookie(); +if (document.body) {jsMath.Setup.Body()} -//make sure browser-specific loads are done before this -document.write(''); - -} - -} +}}