www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 0891402b888237944e451de2c9e7e6307e3ebf31
parent 63c8bd4d838a88dd3cd3c848f04835c291b3e7bf
Author: Davide P. Cervone <dpvc@union.edu>
Date:   Mon, 29 Apr 2013 15:57:29 -0400

Merge branch 'issue359' into develop.  Improves MathML rendering for mfenced and mlabeldtr elements.

Diffstat:
Munpacked/extensions/TeX/AMSmath.js | 7+++++--
Munpacked/jax/input/MathML/config.js | 2+-
Munpacked/jax/input/MathML/jax.js | 9+++++++++
Munpacked/jax/input/TeX/jax.js | 29++++++++++++++++++++---------
Munpacked/jax/output/NativeMML/config.js | 2+-
Munpacked/jax/output/NativeMML/jax.js | 504+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
6 files changed, 505 insertions(+), 48 deletions(-)

diff --git a/unpacked/extensions/TeX/AMSmath.js b/unpacked/extensions/TeX/AMSmath.js @@ -1,3 +1,6 @@ +/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ + /************************************************************* * * MathJax/extensions/TeX/AMSmath.js @@ -22,7 +25,7 @@ */ MathJax.Extension["TeX/AMSmath"] = { - version: "2.1", + version: "2.1.1", number: 0, // current equation number startNumber: 0, // current starting equation number (for when equation is restarted) @@ -252,7 +255,7 @@ MathJax.Hub.Register.StartupHook("TeX Jax Ready",function () { var den = this.ParseArg(name); var frac = MML.mfrac(num,den); if (thick !== "") {frac.linethickness = thick} - if (left || right) {frac = MML.mfenced(frac).With({open: left, close: right})} + if (left || right) {frac = TEX.mfenced(left,frac,right)} if (style !== "") { var STYLE = (["D","T","S","SS"])[style]; if (STYLE == null) {TEX.Error("Bad math style for "+name)} diff --git a/unpacked/jax/input/MathML/config.js b/unpacked/jax/input/MathML/config.js @@ -24,7 +24,7 @@ MathJax.InputJax.MathML = MathJax.InputJax({ id: "MathML", - version: "2.1", + version: "2.1.1", directory: MathJax.InputJax.directory + "/MathML", extensionDir: MathJax.InputJax.extensionDir + "/MathML", entityDir: MathJax.InputJax.directory + "/MathML/entities", diff --git a/unpacked/jax/input/MathML/jax.js b/unpacked/jax/input/MathML/jax.js @@ -1,5 +1,6 @@ /* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */ /* vim: set ts=2 et sw=2 tw=80: */ + /************************************************************* * * MathJax/jax/input/MathML/jax.js @@ -151,6 +152,14 @@ {mml.Append.apply(mml,cmml.data); cmml.data = []} } } + if (mml.type === "mrow" && mml.data.length >= 2) { + var first = mml.data[0], last = mml.data[mml.data.length-1]; + if (first.type === "mo" && first.Get("fence") && + last.type === "mo" && last.Get("fence")) { + if (first.data[0]) {mml.open = first.data.join("")} + if (last.data[0]) {mml.close = last.data.join("")} + } + } }, // diff --git a/unpacked/jax/input/TeX/jax.js b/unpacked/jax/input/TeX/jax.js @@ -1,3 +1,6 @@ +/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ + /************************************************************* * * MathJax/jax/input/TeX/jax.js @@ -175,7 +178,7 @@ if (this.open || this.close) { mml.texClass = MML.TEXCLASS.INNER; mml.texWithDelims = true; - mml = MML.mfenced(mml).With({open: this.open, close: this.close}); + mml = TEX.mfenced(this.open,mml,this.close); } return [STACKITEM.mml(mml), item]; } @@ -188,10 +191,8 @@ type: "left", isOpen: true, delim: '(', stopError: "Extra \\left or missing \\right", checkItem: function (item) { - if (item.type === "right") { - var mml = MML.mfenced(this.data.length === 1 ? this.data[0] : MML.mrow.apply(MML,this.data)); - return STACKITEM.mml(mml.With({open: this.delim, close: item.delim})); - } + if (item.type === "right") + {return STACKITEM.mml(TEX.mfenced(this.delim,this.mmlData(),item.delim))} return this.SUPER(arguments).checkItem.call(this,item); } }); @@ -266,9 +267,7 @@ if ((this.arraydef.columnlines||"none") != "none" || (this.arraydef.rowlines||"none") != "none") {mml.padding = 0} // HTML-CSS jax implements this } - if (this.open || this.close) { - mml = MML.mfenced(mml).With({open: this.open, close: this.close}); - } + if (this.open || this.close) {mml = TEX.mfenced(this.open,mml,this.close)} mml = STACKITEM.mml(mml); if (this.requireClose) { if (item.type === 'close') {return mml} @@ -1052,7 +1051,7 @@ return this.stack.Top().data[0]; }, mmlToken: function (token) {return token}, // used by boldsymbol extension - + /************************************************************************/ /* * Handle various token classes @@ -2054,6 +2053,18 @@ TEXDEF.macros[name].isUser = true; }, + /* + * Create an mrow that represents the equivalent of an mfenced + */ + mfenced: function (open,mml,close) { + var mrow = MML.mrow(); + mrow.open = open; mrow.close = close; + if (open) {mrow.Append(MML.mo(open).With({fence:true, texClass:MML.TEXCLASS.OPEN}))} + if (mml.type === "mrow") {mrow.Append.apply(mrow,mml.data)} else {mrow.Append(mml)} + if (close) {mrow.Append(MML.mo(close).With({fence:true, texClass:MML.TEXCLASS.CLOSE}))} + return mrow; + }, + // // Combine adjacent <mo> elements that are relations // (since MathML treats the spacing very differently) diff --git a/unpacked/jax/output/NativeMML/config.js b/unpacked/jax/output/NativeMML/config.js @@ -24,7 +24,7 @@ MathJax.OutputJax.NativeMML = MathJax.OutputJax({ id: "NativeMML", - version: "2.1.1", + version: "2.1.2", directory: MathJax.OutputJax.directory + "/NativeMML", extensionDir: MathJax.OutputJax.extensionDir + "/NativeMML", diff --git a/unpacked/jax/output/NativeMML/jax.js b/unpacked/jax/output/NativeMML/jax.js @@ -1,3 +1,6 @@ +/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ + /************************************************************* * * MathJax/jax/output/NativeMML/jax.js @@ -29,6 +32,54 @@ HUB.Register.StartupHook("MathZoom Ready",function () {ZOOM = MathJax.Extension.MathZoom}); + var NOPADDING = function (side,obj) { + var span = HTML.Element("span"); side = "padding"+side; + if (obj) { + span.style.cssText = (obj.getAttribute("style")||""); + if (span.style.padding === "" && (span.style[side]||"") === "") { + span.style[side] = "0px"; obj.setAttribute("style",span.style.cssText) + } + } + }; + + var CELLSPACING = function (obj,rowSpacing,columnSpacing) { + // + // Webkit default padding on mtd cells is simply + // + // mtd {padding: 0.5ex;} + // + // Gecko default padding on mtd cells is + // + // mtd {padding-right: 0.4em; + // padding-left: 0.4em; + // padding-bottom: 0.5ex; + // padding-top: 0.5ex;} + // mtr:first-child > mtd {padding-top: 0ex;} + // mtr:last-child > mtd {padding-bottom: 0ex;} + // mtd:first-child {padding-left: 0em;} + // mtd:last-child {padding-right: 0em;} + // + // that is the columnspacing/rowspacing is split into two adjacent cells, + // and the periphery of boundary cells is set to zero. + // + // Here, we will set the left/top padding of each cell to + // rowSpacing/columnSpacing (or 0px for the leftmost/topmost cells) and + // reset the right/bottom padding to zero. + // + if (obj) { + var span = HTML.Element("span"); + span.style.cssText = (obj.getAttribute("style")||""); + if (span.style.padding === "") { + var padding = { paddingLeft: columnSpacing, paddingTop: rowSpacing, + paddingRight: "0px", paddingBottom: "0px" }; + for (var side in padding) {if (padding.hasOwnProperty(side)) { + if ((span.style[side]||"") === "") {span.style[side] = padding[side];} + }} + } + obj.setAttribute("style",span.style.cssText); + } + }; + nMML.Augment({ // // User can configure styles @@ -80,7 +131,7 @@ if (HUB.config.displayAlign !== "center") { var align = HUB.config.displayAlign, indent = HUB.config.displayIndent; var def = {"text-align": align+"!important"}; def["margin-"+align] = indent+"!important"; - MathJax.Hub.Insert(this.config.styles,{ + HUB.Insert(this.config.styles,{ "div.MathJax_MathML": def, "div.MathJax_MathML math": {"text-align": align}, "div.MathJax_MathContainer > span": {"text-align": align+"!important"} @@ -272,8 +323,10 @@ postTranslate: function (state) { if (this.forceReflow) { + // // Firefox messes up some mtable's when they are dynamically created // but gets them right on a reflow, so force reflow by toggling a stylesheet + // var sheet = (document.styleSheets||[])[0]||{}; sheet.disabled = true; sheet.disabled = false; } @@ -330,8 +383,10 @@ if (nMML[type] && nMML[type](event,this) === false) {return false} if (ZOOM && ZOOM.HandleEvent(event,type,this) === false) {return false} if (event.srcElement.className === "MathJax_MathPlayer_Overlay" && this.msieMath.fireEvent) { - // for now, ignore all other events. This will disable MathPlayer's zoom - // feature, but also its <maction> support. + // + // For now, ignore all other events. This will disable MathPlayer's zoom + // feature, but also its <maction> support. + // if (type === "ContextMenu" || type === "Mouseover" || type === "Mouseout") {this.msieMath.fireEvent("on"+event.type,event)} } @@ -470,7 +525,32 @@ if (this.data[i]) {this.data[i].toNativeMML(parent)} else {parent.appendChild(this.NativeMMLelement("mrow"))} } - } else { + } else if (nMML.stretchyMoBug && (this.open || this.close)) { + // + // This element contains opening and/or closing fences. Opera is not + // able to stretch <mo> operators, so let's use an <mfenced> element + // instead. + // + var mfenced = this.NativeMMLelement("mfenced"); + this.NativeMMLattributes(mfenced); + var i = 0, m = this.data.length; + if (this.open) { mfenced.setAttribute("open", this.open); i++; } + if (this.close) { mfenced.setAttribute("close", this.close); m--; } + var tag = mfenced; + if (m - i + 1 > 1) { + // + // If there are several children, put them in an <mrow> + // + tag = this.NativeMMLelement("mrow"); + parent.appendChild(mfenced); + parent = mfenced; + } + for (; i < m; i++) { + if (this.data[i]) {this.data[i].toNativeMML(tag)} + else {tag.appendChild(this.NativeMMLelement("mrow"))} + } + parent.appendChild(tag); + } else { this.SUPER(arguments).toNativeMML.call(this,parent); } } @@ -512,39 +592,239 @@ } }); - if (HUB.Browser.isFirefox) { - if (!HUB.Browser.versionAtLeast("13.0")) { - MML.mtable.Augment({ - toNativeMML: function (parent) { + if (!isMSIE) { + var SPLIT = MathJax.Hub.SplitList; + MML.mtable.Augment({ + toNativeMML: function (parent) { + var i, m; + if (nMML.tableSpacingBug) { + // + // Parse the rowspacing/columnspacing. For convenience, we convert + // them to a left/top padding value that will be applied to each + // cell. The leftmost/topmost cells will use "0px". + // + var values = this.getValues("rowspacing", "columnspacing"); + this.nMMLtopPadding = SPLIT("0px "+values.rowspacing); + this.nMMLleftPadding = SPLIT("0px "+values.columnspacing); // - // Firefox < 13 doesn't handle width, so put it in styles instead + // Transmit the top padding to each row. + // If this.parent.nMML.topPadding does not contain enough value, + // repeat the last one. // - if (this.width) { - var styles = (this.style||"").replace(/;\s*$/,"").split(";"); - if (styles[0] === "") {styles.shift()} - styles.push("width:"+this.width); - this.style = styles.join(";"); + var tp = this.nMMLtopPadding, M = tp.length; + for (i = 0, m = this.data.length; i < m; i++) { + if (this.data[i]) + {this.data[i].nMMLtopPadding = tp[i < M ? i : M-1]} } - this.SUPER(arguments).toNativeMML.call(this,parent); } - }); - } - if (!HUB.Browser.versionAtLeast("9.0")) { - MML.mlabeledtr.Augment({ - toNativeMML: function (parent) { + if (nMML.tableLabelBug) { // - // FF doesn't handle mlabeledtr, so remove the label + // Look for labeled rows so we know how to handle them // - var tag = this.NativeMMLelement("mtr"); - this.NativeMMLattributes(tag); - for (var i = 1, m = this.data.length; i < m; i++) { - if (this.data[i]) {this.data[i].toNativeMML(tag)} - else {tag.appendChild(this.NativeMMLelement("mrow"))} + for (i = 0, m = this.data.length; i < m; i++) { + if (this.data[i] && this.data[i].isa(MML.mlabeledtr)) { + var align = HUB.config.displayAlign.charAt(0), + side = this.Get("side").charAt(0); + this.nMMLhasLabels = true; + this.nMMLlaMatch = (align === side); + this.nMMLforceWidth = + (align === "c" || !!((this.width||"").match("%"))); + break; + } } - parent.appendChild(tag); } - }); - } + // + // Firefox < 13 doesn't handle width, so put it in styles instead + // + if (this.width && this.ffTableWidthBug) { + var styles = (this.style||"").replace(/;\s*$/,"").split(";"); + if (styles[0] === "") {styles.shift()} + styles.push("width:"+this.width); + this.style = styles.join(";"); + } + this.SUPER(arguments).toNativeMML.call(this,parent); + // + if (this.nMMLhasLabels) { + var mtable = parent.firstChild; + // + // Add column attributes on the left when extra columns where inserted + // + if (this.nMMLforceWidth || side !== "r") { + var n = (align !== "l" ? 1 : 0) + (side === "l" ? 1 : 0); + if (n) { + var attr = {columnalign:"left", columnwidth:"auto", + columnspacing:"0px", columnlines:"none"}; + for (var id in attr) {if (attr.hasOwnProperty(id) && this[id]) { + var cols = [attr[id],attr[id]].slice(2-n).join(" ")+" "; + mtable.setAttribute(id,cols+mtable.getAttribute(id)); + }} + } + } + // + // Force the table width to 100% when needed + // + if (this.nMMLforceWidth || !this.nMMLlaMatch) + {mtable.setAttribute("width","100%")} + } + } + }); + MML.mtr.Augment({ + toNativeMML: function (parent) { + this.SUPER(arguments).toNativeMML.call(this,parent); + var mtr = parent.lastChild; + if (nMML.tableSpacingBug) { + // + // Set the row/column spacing. If this.parent.nMMLleftPadding does + // not contain enough value, repeat the last one. + // + var lp = this.parent.nMMLleftPadding, M = lp.length; + for (var mtd = mtr.firstChild, i = 0; mtd; mtd = mtd.nextSibling, i++) { + CELLSPACING(mtd,this.nMMLtopPadding,lp[i < M ? i : M-1]); + } + } + + if (nMML.tableLabelBug) { + var forceWidth = this.parent.nMMLforceWidth, + side = this.parent.Get("side").charAt(0), + align = HUB.config.displayAlign.charAt(0); + + if (this.parent.nMMLhasLabels && mtr.firstChild) { + // + // If we add a label or padding column on the left of mlabeledtr, + // mirror that here and remove padding from first table mtd + // so the spacing is consistent with unlabeled equations + // + if (forceWidth || side !== "r") { + NOPADDING("Left",mtr.firstChild); + if (align !== "l") { + mtr.insertBefore(this.NativeMMLelement("mtd"),mtr.firstChild) + .setAttribute("style","padding:0"); + } + if (side === "l") { + mtr.insertBefore(this.NativeMMLelement("mtd"),mtr.firstChild) + .setAttribute("style","padding:0"); + } + } + // + // If columns were added on the right, remove mtd padding + // so that spacing is consistent with unlabled equations + // + if (forceWidth || side !== "l") {NOPADDING("Right",mtr.lastChild)} + } + } + } + }); + MML.mlabeledtr.Augment({ + toNativeMML: function (parent) { + var mtr = this.NativeMMLelement("mtr"); + this.NativeMMLattributes(mtr); + // + // Add row data + // + for (var i = 1, m = this.data.length; i < m; i++) { + if (this.data[i]) {this.data[i].toNativeMML(mtr)} + else {mtr.appendChild(this.NativeMMLelement("mtd"))} + } + + if (nMML.tableSpacingBug) { + // + // Set the row/column spacing. If this.parent.nMMLleftPadding does + // not contain enough value, repeat the last one. + // + var lp = this.parent.nMMLleftPadding, M = lp.length; + for (var mtd = mtr.firstChild, i = 0; mtd; mtd = mtd.nextSibling, i++) { + CELLSPACING(mtd,this.nMMLtopPadding,lp[i < M ? i : M-1]); + } + } + + if (nMML.tableLabelBug) { + var side = this.parent.Get("side").charAt(0), + align = HUB.config.displayAlign.charAt(0), + indent = HUB.config.displayIndent; + // + // Create label and either set the column width (if label is on the + // same side as the alignment), or use mpadded to hide the label + // width + // + this.data[0].toNativeMML(mtr); + var label = mtr.lastChild, pad = label; + if (side === align) { + label.setAttribute("style","width:"+indent); + label.setAttribute("columnalign",HUB.config.displayAlign); + } else { + pad = this.NativeMMLelement("mpadded"); + pad.setAttribute("style","width:0"); + pad.setAttribute("width","0px"); + pad.appendChild(label.firstChild); + label.appendChild(pad); + } + NOPADDING("",label); mtr.removeChild(label); + // + // Get spacing to use for separation of label from main table + // + var width = 100, forceWidth = this.parent.nMMLforceWidth; + if ((this.parent.width||"").match(/%/)) { + width -= parseFloat(this.parent.width) + }; + var w = width; + // + // Add spacing (and possibly label) at the left if needed + // + if (forceWidth || side !== "r") { + NOPADDING("Left",mtr.firstChild); + if (align !== "l") { + if (align === "c") {w /= 2}; width -= w; + mtr.insertBefore(this.NativeMMLelement("mtd"),mtr.firstChild) + .setAttribute("style","padding:0;width:"+w+"%"); + } + if (side === "l") {mtr.insertBefore(label,mtr.firstChild)} + } + // + // Add spacing (and possibly label) at the right if needed + // + if (forceWidth || side !== "l") { + NOPADDING("Right",mtr.lastChild); + if (align !== "r") { + mtr.appendChild(this.NativeMMLelement("mtd")) + .setAttribute("style","padding:0;width:"+width+"%"); + } + if (side === "r") { + if (side !== align) {pad.setAttribute("lspace","-1width")} + mtr.appendChild(label); + } + } + } + // + // Add row to table + // + parent.appendChild(mtr); + } + }); + + MML.mtd.Augment({ + toNativeMML: function (parent) { + var tag = parent.appendChild(this.NativeMMLelement(this.type)); + this.NativeMMLattributes(tag); + if (nMML.widthBug) {tag = tag.appendChild(this.NativeMMLelement("mrow"))} + for (var i = 0, m = this.data.length; i < m; i++) { + if (this.data[i]) {this.data[i].toNativeMML(tag)} + else {tag.appendChild(this.NativeMMLelement("mrow"))} + } + } + }); + + MML.mspace.Augment({ + toNativeMML: function (parent) { + this.SUPER(arguments).toNativeMML.call(this,parent); + if (nMML.spaceWidthBug && this.width) { + var mspace = parent.lastChild; + var width = mspace.getAttribute("width"); + var style = mspace.getAttribute("style") || ""; + if (style != "") {style += ";"} + mspace.setAttribute("style",style+"width:"+width); + } + } + }); var fontDir = MathJax.Ajax.fileURL(MathJax.OutputJax.fontDir+"/HTML-CSS/TeX/otf"); @@ -599,18 +879,47 @@ } MML.math.Augment({ - // - // Some browsers don't seem to add the xmlns attribute, so do it by hand. - // toNativeMML: function (parent) { var tag = this.NativeMMLelement(this.type), math = tag; + // + // Some browsers don't seem to add the xmlns attribute, so do it by hand. + // tag.setAttribute("xmlns",nMML.MMLnamespace); this.NativeMMLattributes(tag); + // + // Use an extra <mrow> in FF so that we can get the correct width + // (the math element doesn't always have an accurate one, see below) + // if (nMML.widthBug) {tag = tag.appendChild(this.NativeMMLelement("mrow"))} + // + // Add the children + // for (var i = 0, m = this.data.length; i < m; i++) { if (this.data[i]) {this.data[i].toNativeMML(tag)} else {tag.appendChild(this.NativeMMLelement("mrow"))} } + // + // Look for a top-level mtable and if it has labels + // Make sure the containers have 100% width, when needed + // If the label is on the same side as alignment, + // override the margin set by the stylesheet. + // + var mtable = ((this.data[0]||[]).data[0]||{}); + if (mtable.nMMLhasLabels) { + if (mtable.nMMLforceWidth || !mtable.nMMLlaMatch) { + tag.setAttribute("style","width:100%") + parent.style.width = parent.parentNode.style.width="100%"; + }; + if (mtable.nMMLlaMatch) { + if (parent.parentNode.parentNode.nodeName.toLowerCase() === "div") { + parent.parentNode.parentNode.style + .setProperty("margin-"+HUB.config.displayAlign,"0px","important"); + } + } + } + // + // Add the math to the page + // parent.appendChild(math); // // Firefox can't seem to get the width of <math> elements right, so @@ -618,7 +927,7 @@ // parent element to match. Even if we set the <math> width properly, // it doesn't seem to propagate up to the <span> correctly. // - if (nMML.widthBug) { + if (nMML.widthBug && !mtable.nMMLforceWidth && mtable.nMMLlaMatch) { // // Convert size to ex's so that it scales properly if the print media // has a different font size. @@ -628,6 +937,108 @@ } }); + MML.mfenced.Augment({ + toNativeMML: function (parent) { + if (!nMML.mfencedBug) { + this.SUPER(arguments).toNativeMML.call(this,parent); + return; + } + + // + // Some browsers do not handle <mfenced> very well. The MathML spec + // suggests this equivalent construction instead, so let's use it: + // <mrow> open, child1, sep1, child2, ... sep(N-1), childN, close</mrow> + // Opera is a bit special: it does not support stretchy <mo>, does not + // parse mfenced@open/mfenced@close very well, does not support + // mfenced@separators and only displays the first child of the <mfenced> + // element... For this browser, we will use this construction: + // <mfenced open="open" close="close"> + // <mrow>child1, sep1, child2, sep2, ..., sep(N-1), childN</mrow> + // </mfenced> + // + var isOpera = HUB.Browser.isOpera; + var i, m, operator; + + // + // parse the open, close and separators attributes. + // + var values = this.getValues("open","close","separators"); + values.open = values.open.replace(/^\s+/,"").replace(/\s+$/,""); + values.close = values.close.replace(/^\s+/,"").replace(/\s+$/,""); + values.separators = values.separators.replace(/\s+/g,"").split(""); + if (values.separators.length == 0) { + // + // No separators specified, do not use separators at all. + // + values.separators = null; + } else if (values.separators.length < this.data.length-1) { + // + // There are not enough separators, repeat the last one. + // + var s = values.separators[values.separators.length-1]; + for (i = this.data.length-1-values.separators.length; i > 0; i--) + {values.separators.push(s)} + } + + // + // Create an <mrow> container and attach the attributes of the + // <mfenced> element to it. Note: removeAttribute does not raise any + // exception when the attributes is absent. + // + var tag = this.NativeMMLelement(isOpera ? this.type : "mrow"); + this.NativeMMLattributes(tag); + tag.removeAttribute("separators"); + if (isOpera) { + tag.setAttribute("open", values.open); + tag.setAttribute("close", values.close); + if (this.data.length > 1) { + parent.appendChild(tag); parent = tag; + tag = this.NativeMMLelement("mrow"); + } + } else { + tag.removeAttribute("open"); + tag.removeAttribute("close"); + } + + if (!isOpera) { + // + // Append the opening fence + // + operator = this.NativeMMLelement("mo"); + operator.setAttribute("fence", "true"); + operator.textContent = values.open; + tag.appendChild(operator); + } + + // + // Append the content of the <mfenced> + // + for (i = 0, m = this.data.length; i < m; i++) { + if (values.separators && i > 0) { + operator = this.NativeMMLelement("mo"); + operator.setAttribute("separator", "true"); + operator.textContent = values.separators[i-1]; + tag.appendChild(operator); + } + if (this.data[i]) {this.data[i].toNativeMML(tag)} + else {tag.appendChild(this.NativeMMLelement("mrow"))} + } + + if (!isOpera) { + // + // Append the closing fence + // + operator = this.NativeMMLelement("mo"); + operator.setAttribute("fence", "true"); + operator.textContent = values.close; + tag.appendChild(operator); + } + + // finally, append the new element to the parent. + parent.appendChild(tag); + } + }); + MML.TeXAtom.Augment({ // // Convert TeXatom to an mrow @@ -698,10 +1109,33 @@ }, Opera: function (browser) { nMML.operaPositionBug = true; + nMML.stretchyMoBug = true; + nMML.tableLabelBug = true; + nMML.mfencedBug = true; }, Firefox: function (browser) { - nMML.forceReflow = true; - nMML.widthBug = true; + nMML.ffTableWidthBug = !browser.versionAtLeast("13.0"); // <mtable width="xx"> not implemented + nMML.forceReflow = true; // <mtable> with alignments set don't display properly without a reflow + nMML.widthBug = true; // <math> elements don't always get the correct width + + // In Firefox < 20, the intrinsic width of <mspace> is not computed + // correctly and thus the element is displayed incorrectly in <mtable>. + nMML.spaceWidthBug = !browser.versionAtLeast("20.0"); + + nMML.tableSpacingBug = true; // mtable@rowspacing/mtable@columnspacing not + // supported. + nMML.tableLabelBug = true; // mlabeledtr is not implemented. + nMML.mfencedBug = true; // mfenced not displayed correctly + }, + Chrome: function (browser) { + nMML.tableSpacingBug = true; + nMML.tableLabelBug = true; + nMML.mfencedBug = true; + }, + Safari: function (browser) { + nMML.tableSpacingBug = true; + nMML.tableLabelBug = true; + nMML.mfencedBug = true; } });