742 lines
24 KiB
JavaScript
742 lines
24 KiB
JavaScript
/*************************************************************
|
|
*
|
|
* [Contrib]/a11y/collapsible.js
|
|
*
|
|
* A filter to add maction elements to the enriched MathML for parts that
|
|
* can be collapsed. We determine this based on a "complexity" value and
|
|
* collapse those terms that exceed a given complexity.
|
|
*
|
|
* The parameters controlling the complexity measure still need work.
|
|
*
|
|
* ---------------------------------------------------------------------
|
|
*
|
|
* Copyright (c) 2016-2017 The MathJax Consortium
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
(function (HUB) {
|
|
var MML;
|
|
|
|
var SETTINGS = HUB.config.menuSettings;
|
|
var COOKIE = {}; // replaced when menu is available
|
|
|
|
var NOCOLLAPSE = 10000000; // really big complexity
|
|
var COMPLEXATTR = "data-semantic-complexity";
|
|
|
|
//
|
|
// Set up the a11y path,if it isn't already in place
|
|
//
|
|
var PATH = MathJax.Ajax.config.path;
|
|
if (!PATH.a11y) PATH.a11y = HUB.config.root + "/extensions/a11y";
|
|
|
|
var Collapsible = MathJax.Extension.collapsible = {
|
|
version: "1.2.2",
|
|
config: HUB.CombineConfig("collapsible",{
|
|
disabled: false
|
|
}),
|
|
dependents: [], // the extensions that depend on this one
|
|
COMPLEXATTR: COMPLEXATTR, // attribute name for the complexity value
|
|
|
|
/*****************************************************************/
|
|
|
|
//
|
|
// Complexity values to use for different structures
|
|
//
|
|
COMPLEXITY: {
|
|
TEXT: .5, // each character of a token element adds this to complexity
|
|
TOKEN: .5, // each toekn element gets this additional complexity
|
|
CHILD: 1, // child nodes add this to their parent node's complexity
|
|
|
|
SCRIPT: .8, // script elements reduce their complexity by this factor
|
|
SQRT: 2, // sqrt adds this extra complexity
|
|
SUBSUP: 2, // sub-sup adds this extra complexity
|
|
UNDEROVER: 2, // under-over adds this extra complexity
|
|
FRACTION: 2, // fractions add this extra complexity
|
|
ACTION: 2, // maction adds this extra complexity
|
|
PHANTOM: 0, // mphantom makes complexity 0?
|
|
XML: 2, // Can't really measure complexity of annotation-xml, so punt
|
|
GLYPH: 2 // Can't really measure complexity of mglyph, to punt
|
|
},
|
|
//
|
|
// These are the cut-off complexity values for when
|
|
// the structure should collapse
|
|
//
|
|
COLLAPSE: {
|
|
identifier: 3,
|
|
number: 3,
|
|
text: 10,
|
|
infixop: 15,
|
|
relseq: 15,
|
|
multirel: 15,
|
|
fenced: 18,
|
|
bigop: 20,
|
|
integral: 20,
|
|
fraction: 12,
|
|
sqrt: 9,
|
|
root: 12,
|
|
vector: 15,
|
|
matrix: 15,
|
|
cases: 15,
|
|
superscript: 9,
|
|
subscript: 9,
|
|
subsup: 9,
|
|
punctuated: {
|
|
endpunct: NOCOLLAPSE,
|
|
startpunct: NOCOLLAPSE,
|
|
default: 12
|
|
}
|
|
},
|
|
//
|
|
// These are the characters to use for the various collapsed elements
|
|
// (if an object, then semantic-role is used to get the character
|
|
// from the object)
|
|
//
|
|
MARKER: {
|
|
identifier: "x",
|
|
number: "#",
|
|
text: "...",
|
|
appl: {
|
|
"limit function": "lim",
|
|
default: "f()"
|
|
},
|
|
fraction: "/",
|
|
sqrt: "\u221A",
|
|
root: "\u221A",
|
|
superscript: "\u25FD\u02D9",
|
|
subscript: "\u25FD.",
|
|
subsup:"\u25FD:",
|
|
vector: {
|
|
binomial: "(:)",
|
|
determinant: "|:|",
|
|
default: "\u27E8:\u27E9"
|
|
},
|
|
matrix: {
|
|
squarematrix: "[::]",
|
|
rowvector: "\u27E8\u22EF\u27E9",
|
|
columnvector: "\u27E8\u22EE\u27E9",
|
|
determinant: "|::|",
|
|
default: "(::)"
|
|
},
|
|
cases: "{:",
|
|
infixop: {
|
|
addition: "+",
|
|
subtraction: "\u2212",
|
|
multiplication: "\u22C5",
|
|
implicit: "\u22C5",
|
|
default: "+"
|
|
},
|
|
punctuated: {
|
|
text: "...",
|
|
default: ","
|
|
}
|
|
},
|
|
|
|
/*****************************************************************/
|
|
|
|
Enable: function (update,menu) {
|
|
SETTINGS.collapsible = true;
|
|
if (menu) COOKIE.collapsible = true;
|
|
this.config.disabled = false;
|
|
MathJax.Extension["semantic-enrich"].Enable(false,menu);
|
|
if (update) HUB.Queue(["Reprocess",HUB]);
|
|
},
|
|
Disable: function (update,menu) {
|
|
SETTINGS.collapsible = false;
|
|
if (menu) COOKIE.collapsible = false;
|
|
this.config.disabled = true;
|
|
for (var i = this.dependents.length-1; i >= 0; i--) {
|
|
var dependent = this.dependents[i];
|
|
if (dependent.Disable) dependent.Disable(false,menu);
|
|
}
|
|
if (update) HUB.Queue(["Reprocess",HUB]);
|
|
},
|
|
|
|
//
|
|
// Register a dependent
|
|
//
|
|
Dependent: function (extension) {
|
|
this.dependents.push(extension);
|
|
},
|
|
|
|
Startup: function () {
|
|
MML = MathJax.ElementJax.mml;
|
|
//
|
|
// Inform semantic-enrich extension that we are a dependent
|
|
//
|
|
var Enrich = MathJax.Extension["semantic-enrich"];
|
|
if (Enrich) Enrich.Dependent(this);
|
|
//
|
|
// Add the filter into the post-input hooks (priority 100, so other
|
|
// hooks run first, in particular, the enrichment hook).
|
|
//
|
|
HUB.postInputHooks.Add(["Filter",Collapsible],100);
|
|
},
|
|
|
|
//
|
|
// The main filter: add mactions for collapsing the math.
|
|
//
|
|
Filter: function (jax,id,script) {
|
|
if (!jax.enriched || this.config.disabled) return;
|
|
jax.root = jax.root.Collapse();
|
|
jax.root.inputID = script.id;
|
|
},
|
|
|
|
/*****************************************************************/
|
|
|
|
//
|
|
// Create a marker from a given string of characters
|
|
// (several possibilities are commented out)
|
|
//
|
|
// Marker: function (c) {return MML.mtext("\u25C3"+c+"\u25B9").With({mathcolor:"blue",attr:{},attrNames:[]})},
|
|
// Marker: function (c) {return MML.mtext("\u25B9"+c+"\u25C3").With({mathcolor:"blue",attr:{},attrNames:[]})},
|
|
Marker: function (c) {return MML.mtext("\u25C2"+c+"\u25B8").With({mathcolor:"blue",attr:{},attrNames:[]})},
|
|
// Marker: function (c) {return MML.mtext("\u25B8"+c+"\u25C2").With({mathcolor:"blue",attr:{},attrNames:[]})},
|
|
// Marker: function (c) {return MML.mtext("\u27EA"+c+"\u27EB").With({mathcolor:"blue",attr:{},attrNames:[]})},
|
|
|
|
|
|
|
|
/*****************************************************************/
|
|
|
|
//
|
|
// Make a collapsible element using maction that contains
|
|
// an appropriate marker, and the expanded MathML.
|
|
// If the MathML is a <math> node, make an mrow to use instead,
|
|
// and move the semantic data to it (I guess it would have been
|
|
// easier to have had that done initially, oh well).
|
|
//
|
|
MakeAction: function (collapse,mml) {
|
|
var maction = MML.maction(collapse).With({
|
|
id:this.getActionID(), actiontype:"toggle",
|
|
complexity:collapse.getComplexity(), collapsible:true,
|
|
attrNames:["id","actiontype","selection",COMPLEXATTR], attr:{}, selection:2
|
|
});
|
|
maction.attr[COMPLEXATTR] = maction.complexity;
|
|
if (mml.type === "math") {
|
|
var mrow = MML.mrow().With({
|
|
data: mml.data,
|
|
complexity: mml.complexity,
|
|
attrNames: [], attr: {}
|
|
});
|
|
for (var i = mml.attrNames.length-1, name; name = mml.attrNames[i]; i--) {
|
|
if (name.substr(0,14) === "data-semantic-") {
|
|
mrow.attr[name] = mml.attr[name];
|
|
mrow.attrNames.push(name);
|
|
delete mml.attr[name];
|
|
mml.attrNames.splice(i,1);
|
|
}
|
|
}
|
|
mrow.complexity = mml.complexity;
|
|
maction.Append(mrow); mml.data = []; mml.Append(maction);
|
|
mml.complexity = maction.complexity; maction = mml;
|
|
} else {
|
|
maction.Append(mml);
|
|
}
|
|
return maction;
|
|
},
|
|
|
|
actionID: 1,
|
|
getActionID: function () {return "MJX-Collapse-"+this.actionID++},
|
|
|
|
/*****************************************************************/
|
|
|
|
//
|
|
// If there is a specific routine for the type, do that, otherwise
|
|
// check if there is a complexity cut-off and marker for this type.
|
|
// If so, check if the complexity exceeds the cut off, and
|
|
// collapse using the appropriate marker for the type
|
|
// Return the (possibly modified) MathML
|
|
//
|
|
Collapse: function (mml) {
|
|
mml.getComplexity();
|
|
var type = (mml.attr||{})["data-semantic-type"];
|
|
if (type) {
|
|
if (this["Collapse_"+type]) mml = (this["Collapse_"+type])(mml);
|
|
else if (this.COLLAPSE[type] && this.MARKER[type]) {
|
|
var role = mml.attr["data-semantic-role"];
|
|
var complexity = this.COLLAPSE[type];
|
|
if (typeof(complexity) !== "number") complexity = complexity[role] || complexity.default;
|
|
if (mml.complexity > complexity) {
|
|
var marker = this.MARKER[type];
|
|
if (typeof(marker) !== "string") marker = marker[role] || marker.default;
|
|
mml = this.MakeAction(this.Marker(marker),mml);
|
|
}
|
|
}
|
|
}
|
|
return mml;
|
|
},
|
|
|
|
//
|
|
// If a parent is going to be collapsible, if can call this
|
|
// to put back a collapsed child (rather than have too many
|
|
// nested collapsings)
|
|
//
|
|
UncollapseChild: function (mml,n,m) {
|
|
if (m == null) m = 1;
|
|
if (this.SplitAttribute(mml,"children").length === m) {
|
|
var child = (mml.data.length === 1 && mml.data[0].inferred ? mml.data[0] : mml);
|
|
if (child && child.data[n] && child.data[n].collapsible) {
|
|
child.SetData(n,child.data[n].data[1]);
|
|
mml.complexity = child.complexity = null; mml.getComplexity();
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
},
|
|
|
|
//
|
|
// Locate child node and return its text
|
|
//
|
|
FindChildText: function (mml,id) {
|
|
var child = this.FindChild(mml,id);
|
|
return (child ? (child.CoreMO()||child).data.join("") : "?");
|
|
},
|
|
FindChild: function (mml,id) {
|
|
if (mml) {
|
|
if (mml.attr && mml.attr["data-semantic-id"] === id) return mml;
|
|
if (!mml.isToken) {
|
|
for (var i = 0, m = mml.data.length; i < m; i++) {
|
|
var child = this.FindChild(mml.data[i],id);
|
|
if (child) return child;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
|
|
//
|
|
// Split a data attribute at commas
|
|
//
|
|
SplitAttribute: function (mml,id) {
|
|
return (mml.attr["data-semantic-"+id]||"").split(/,/);
|
|
},
|
|
|
|
/*****************************************************************/
|
|
/*
|
|
* These routines implement the collapsing of the various semantic types
|
|
*/
|
|
|
|
//
|
|
// For fenced elements, if the contents are collapsed,
|
|
// collapse the fence instead.
|
|
//
|
|
Collapse_fenced: function (mml) {
|
|
this.UncollapseChild(mml,1);
|
|
if (mml.complexity > this.COLLAPSE.fenced) {
|
|
if (mml.attr["data-semantic-role"] === "leftright") {
|
|
var marker = mml.data[0].data.join("") + mml.data[mml.data.length-1].data.join("");
|
|
mml = this.MakeAction(this.Marker(marker),mml);
|
|
}
|
|
}
|
|
return mml;
|
|
},
|
|
|
|
//
|
|
// Collapse function applications if the argument is collapsed
|
|
// (Handle role="limit function" a bit better?)
|
|
//
|
|
Collapse_appl: function (mml) {
|
|
if (this.UncollapseChild(mml,2,2)) {
|
|
var marker = this.MARKER.appl;
|
|
marker = marker[mml.attr["data-semantic-role"]] || marker.default;
|
|
mml = this.MakeAction(this.Marker(marker),mml);
|
|
}
|
|
return mml;
|
|
},
|
|
|
|
//
|
|
// For sqrt elements, if the contents are collapsed,
|
|
// collapse the sqrt instead.
|
|
//
|
|
Collapse_sqrt: function (mml) {
|
|
this.UncollapseChild(mml,0);
|
|
if (mml.complexity > this.COLLAPSE.sqrt)
|
|
mml = this.MakeAction(this.Marker(this.MARKER.sqrt),mml);
|
|
return mml;
|
|
},
|
|
Collapse_root: function (mml) {
|
|
this.UncollapseChild(mml,0);
|
|
if (mml.complexity > this.COLLAPSE.sqrt)
|
|
mml = this.MakeAction(this.Marker(this.MARKER.sqrt),mml);
|
|
return mml;
|
|
},
|
|
|
|
//
|
|
// For enclose, include enclosure in collapsed child, if any
|
|
//
|
|
Collapse_enclose: function (mml) {
|
|
if (this.SplitAttribute(mml,"children").length === 1) {
|
|
var child = (mml.data.length === 1 && mml.data[0].inferred ? mml.data[0] : mml);
|
|
if (child.data[0] && child.data[0].collapsible) {
|
|
//
|
|
// Move menclose into the maction element
|
|
//
|
|
var maction = child.data[0];
|
|
child.SetData(0,maction.data[1]);
|
|
maction.SetData(1,mml);
|
|
mml = maction;
|
|
}
|
|
}
|
|
return mml;
|
|
},
|
|
|
|
//
|
|
// For bigops, get the character to use from the largeop at its core.
|
|
//
|
|
Collapse_bigop: function (mml) {
|
|
if (mml.complexity > this.COLLAPSE.bigop || mml.data[0].type !== "mo") {
|
|
var id = this.SplitAttribute(mml,"content").pop();
|
|
var op = Collapsible.FindChildText(mml,id);
|
|
mml = this.MakeAction(this.Marker(op),mml);
|
|
}
|
|
return mml;
|
|
},
|
|
Collapse_integral: function (mml) {
|
|
if (mml.complexity > this.COLLAPSE.integral || mml.data[0].type !== "mo") {
|
|
var id = this.SplitAttribute(mml,"content")[0];
|
|
var op = Collapsible.FindChildText(mml,id);
|
|
mml = this.MakeAction(this.Marker(op),mml);
|
|
}
|
|
return mml;
|
|
},
|
|
|
|
//
|
|
// For multirel and relseq, use proper symbol
|
|
//
|
|
Collapse_relseq: function (mml) {
|
|
if (mml.complexity > this.COLLAPSE.relseq) {
|
|
var content = this.SplitAttribute(mml,"content");
|
|
var marker = Collapsible.FindChildText(mml,content[0]);
|
|
if (content.length > 1) marker += "\u22EF";
|
|
mml = this.MakeAction(this.Marker(marker),mml);
|
|
}
|
|
return mml;
|
|
},
|
|
Collapse_multirel: function (mml) {
|
|
if (mml.complexity > this.COLLAPSE.multirel) {
|
|
var content = this.SplitAttribute(mml,"content");
|
|
var marker = Collapsible.FindChildText(mml,content[0]) + "\u22EF";
|
|
mml = this.MakeAction(this.Marker(marker),mml);
|
|
}
|
|
return mml;
|
|
},
|
|
|
|
//
|
|
// Include super- and subscripts into a collapsed base
|
|
//
|
|
Collapse_superscript: function (mml) {
|
|
this.UncollapseChild(mml,0,2);
|
|
if (mml.complexity > this.COLLAPSE.superscript)
|
|
mml = this.MakeAction(this.Marker(this.MARKER.superscript),mml);
|
|
return mml;
|
|
},
|
|
Collapse_subscript: function (mml) {
|
|
this.UncollapseChild(mml,0,2);
|
|
if (mml.complexity > this.COLLAPSE.subscript)
|
|
mml = this.MakeAction(this.Marker(this.MARKER.subscript),mml);
|
|
return mml;
|
|
},
|
|
Collapse_subsup: function (mml) {
|
|
this.UncollapseChild(mml,0,3);
|
|
if (mml.complexity > this.COLLAPSE.subsup)
|
|
mml = this.MakeAction(this.Marker(this.MARKER.subsup),mml);
|
|
return mml;
|
|
}
|
|
};
|
|
|
|
HUB.Register.StartupHook("End Extensions", function () {
|
|
if (SETTINGS.collapsible == null) {
|
|
SETTINGS.collapsible = !Collapsible.config.disabled;
|
|
} else {
|
|
Collapsible.config.disabled = !SETTINGS.collapsible;
|
|
}
|
|
HUB.Register.StartupHook("MathMenu Ready", function () {
|
|
COOKIE = MathJax.Menu.cookie;
|
|
var Switch = function(menu) {
|
|
Collapsible[SETTINGS.collapsible ? "Enable" : "Disable"](true,true);
|
|
MathJax.Menu.saveCookie();
|
|
};
|
|
var ITEM = MathJax.Menu.ITEM,
|
|
MENU = MathJax.Menu.menu;
|
|
var menu = ITEM.CHECKBOX(
|
|
['CollapsibleMath','Collapsible Math'], 'collapsible', {action: Switch}
|
|
);
|
|
var submenu = (MENU.FindId('Accessibility')||{}).submenu, index;
|
|
if (submenu) {
|
|
index = submenu.IndexOfId('CollapsibleMath');
|
|
if (index !== null) {
|
|
submenu.items[index] = menu;
|
|
} else {
|
|
submenu.items.push(ITEM.RULE(),menu);
|
|
}
|
|
} else {
|
|
index = MENU.IndexOfId('About');
|
|
MENU.items.splice(index,0,menu,ITEM.RULE());
|
|
}
|
|
},15); // before explorer extension
|
|
},15);
|
|
|
|
})(MathJax.Hub);
|
|
|
|
|
|
/*****************************************************************/
|
|
/*
|
|
* Add Collapse() and getComplexity() methods to the internal
|
|
* MathML elements, and override these in the elements that need
|
|
* special handling.
|
|
*/
|
|
|
|
MathJax.Ajax.Require("[a11y]/semantic-enrich.js");
|
|
MathJax.Hub.Register.StartupHook("Semantic Enrich Ready", function () {
|
|
var MML = MathJax.ElementJax.mml,
|
|
Collapsible = MathJax.Extension.collapsible,
|
|
COMPLEXITY = Collapsible.COMPLEXITY,
|
|
COMPLEXATTR = Collapsible.COMPLEXATTR;
|
|
|
|
Collapsible.Startup(); // Initialize the collapsing process
|
|
|
|
MML.mbase.Augment({
|
|
//
|
|
// Just call the Collapse() method from the extension by default
|
|
// (but can be overridden)
|
|
//
|
|
Collapse: function () {return Collapsible.Collapse(this)},
|
|
//
|
|
// If we don't have a cached complexity value,
|
|
// For token elements, just use the data length,
|
|
// Otherwise
|
|
// Add up the complexities of the (collapsed) children
|
|
// and add the child complexity based on the number of children
|
|
// Cache the complexity result
|
|
// return the complexity
|
|
//
|
|
getComplexity: function () {
|
|
if (this.complexity == null) {
|
|
var complexity = 0;
|
|
if (this.isToken) {
|
|
complexity = COMPLEXITY.TEXT * this.data.join("").length + COMPLEXITY.TOKEN;
|
|
} else {
|
|
for (var i = 0, m = this.data.length; i < m; i++) {
|
|
if (this.data[i]) {
|
|
this.SetData(i,this.data[i].Collapse());
|
|
complexity += this.data[i].complexity;
|
|
}
|
|
}
|
|
if (m > 1) complexity += m * COMPLEXITY.CHILD;
|
|
}
|
|
if (this.attrNames && !("complexity" in this)) this.attrNames.push(COMPLEXATTR);
|
|
if (this.attr) this.attr[COMPLEXATTR] = complexity;
|
|
this.complexity = complexity;
|
|
}
|
|
return this.complexity;
|
|
},
|
|
reportComplexity: function () {
|
|
if (this.attr && this.attrNames && !(COMPLEXATTR in this.attr)) {
|
|
this.attrNames.push(COMPLEXATTR);
|
|
this.attr[COMPLEXATTR] = this.complexity;
|
|
}
|
|
}
|
|
});
|
|
|
|
//
|
|
// For fractions, scale the complexity of the parts, and add
|
|
// a complexity for fractions.
|
|
//
|
|
MML.mfrac.Augment({
|
|
getComplexity: function () {
|
|
if (this.complexity == null) {
|
|
this.SUPER(arguments).getComplexity.call(this);
|
|
this.complexity *= COMPLEXITY.SCRIPT;
|
|
this.complexity += COMPLEXITY.FRACTION;
|
|
this.attr[COMPLEXATTR] = this.complexity;
|
|
}
|
|
return this.complexity;
|
|
}
|
|
});
|
|
|
|
//
|
|
// Square roots add extra complexity
|
|
//
|
|
MML.msqrt.Augment({
|
|
getComplexity: function () {
|
|
if (this.complexity == null) {
|
|
this.SUPER(arguments).getComplexity.call(this);
|
|
this.complexity += COMPLEXITY.SQRT;
|
|
this.attr[COMPLEXATTR] = this.complexity;
|
|
}
|
|
return this.complexity;
|
|
}
|
|
});
|
|
MML.mroot.Augment({
|
|
getComplexity: function () {
|
|
if (this.complexity == null) {
|
|
this.SUPER(arguments).getComplexity.call(this);
|
|
this.complexity -= (1-COMPLEXITY.SCRIPT) * this.data[1].getComplexity();
|
|
this.complexity += COMPLEXITY.SQRT;
|
|
this.attr[COMPLEXATTR] = this.complexity;
|
|
}
|
|
return this.complexity;
|
|
}
|
|
});
|
|
|
|
//
|
|
// For msubsup, use the script complexity factor,
|
|
// take the maximum of the scripts,
|
|
// and add the sub-sup complexity
|
|
//
|
|
MML.msubsup.Augment({
|
|
getComplexity: function () {
|
|
if (this.complexity == null) {
|
|
var C = 0;
|
|
if (this.data[this.sub]) C = this.data[this.sub].getComplexity() + COMPLEXITY.CHILD;
|
|
if (this.data[this.sup]) C = Math.max(this.data[this.sup].getComplexity(),C);
|
|
C *= COMPLEXITY.SCRIPT;
|
|
if (this.data[this.sub]) C += COMPLEXITY.CHILD;
|
|
if (this.data[this.sup]) C += COMPLEXITY.CHILD;
|
|
if (this.data[this.base]) C += this.data[this.base].getComplexity() + COMPLEXITY.CHILD;
|
|
this.complexity = C + COMPLEXITY.SUBSUP;
|
|
this.reportComplexity();
|
|
}
|
|
return this.complexity;
|
|
}
|
|
});
|
|
|
|
//
|
|
// For munderover, use the script complexity factor,
|
|
// take the maximum of the scripts and the base,
|
|
// and add the under-over complexity
|
|
//
|
|
MML.munderover.Augment({
|
|
getComplexity: function () {
|
|
if (this.complexity == null) {
|
|
var C = 0;
|
|
if (this.data[this.sub]) C = this.data[this.sub].getComplexity() + COMPLEXITY.CHILD;
|
|
if (this.data[this.sup]) C = Math.max(this.data[this.sup].getComplexity(),C);
|
|
C *= COMPLEXITY.SCRIPT;
|
|
if (this.data[this.base]) C = Math.max(this.data[this.base].getComplexity(),C);
|
|
if (this.data[this.sub]) C += COMPLEXITY.CHILD;
|
|
if (this.data[this.sup]) C += COMPLEXITY.CHILD;
|
|
if (this.data[this.base]) C += COMPLEXITY.CHILD;
|
|
this.complexity = C + COMPLEXITY.UNDEROVER;
|
|
this.reportComplexity();
|
|
}
|
|
return this.complexity;
|
|
}
|
|
});
|
|
|
|
//
|
|
// For mphantom, complexity is 0?
|
|
//
|
|
MML.mphantom.Augment({
|
|
getComplexity: function () {
|
|
this.complexity = COMPLEXITY.PHANTOM;
|
|
this.reportComplexity();
|
|
return this.complexity;
|
|
}
|
|
});
|
|
|
|
//
|
|
// For ms, add width of quotes. Don't cache the result, since
|
|
// mstyle above it could affect the result.
|
|
//
|
|
MML.ms.Augment({
|
|
getComplexity: function () {
|
|
this.SUPER(arguments).getComplexity.call(this);
|
|
this.complexity += this.Get("lquote").length * COMPLEXITY.TEXT;
|
|
this.complexity += this.Get("rquote").length * COMPLEXITY.TEXT;
|
|
this.attr[COMPLEXATTR] = this.complexity;
|
|
return this.complexity;
|
|
}
|
|
});
|
|
|
|
// ### FIXME: getComplexity special cases:
|
|
// mtable, mfenced, mmultiscript
|
|
|
|
//
|
|
// For menclose, complexity goes up by a fixed amount
|
|
//
|
|
MML.menclose.Augment({
|
|
getComplexity: function () {
|
|
if (this.complexity == null) {
|
|
this.SUPER(arguments).getComplexity.call(this);
|
|
this.complexity += COMPLEXITY.ACTION;
|
|
this.attr[COMPLEXATTR] = this.complexity;
|
|
}
|
|
return this.complexity;
|
|
}
|
|
});
|
|
|
|
//
|
|
// For maction, complexity is complexity of selected element
|
|
//
|
|
MML.maction.Augment({
|
|
getComplexity: function () {
|
|
//
|
|
// Don't cache it, since selection can change.
|
|
//
|
|
this.complexity = (this.collapsible ? this.data[0] : this.selected()).getComplexity();
|
|
this.reportComplexity();
|
|
return this.complexity;
|
|
}
|
|
});
|
|
|
|
//
|
|
// For semantics, complexity is complexity of first child
|
|
//
|
|
MML.semantics.Augment({
|
|
getComplexity: function () {
|
|
if (this.complexity == null) {
|
|
this.complexity = (this.data[0] ? this.data[0].getComplexity() : 0);
|
|
this.reportComplexity();
|
|
}
|
|
return this.complexity;
|
|
}
|
|
});
|
|
|
|
//
|
|
// Use fixed complexity, since we can't really measure it
|
|
//
|
|
MML["annotation-xml"].Augment({
|
|
getComplexity: function () {
|
|
this.complexity = COMPLEXITY.XML;
|
|
this.reportComplexity();
|
|
return this.complexity;
|
|
}
|
|
});
|
|
MML.annotation.Augment({
|
|
getComplexity: function () {
|
|
this.complexity = COMPLEXITY.XML;
|
|
this.reportComplexity();
|
|
return this.complexity;
|
|
}
|
|
});
|
|
|
|
//
|
|
// Use fixed complexity, since we can't really measure it
|
|
//
|
|
MML.mglyph.Augment({
|
|
getComplexity: function () {
|
|
this.complexity = COMPLEXITY.GLYPH;
|
|
this.reportComplexity();
|
|
return this.complexity;
|
|
}
|
|
});
|
|
|
|
//
|
|
// Signal that we are ready
|
|
//
|
|
MathJax.Hub.Startup.signal.Post("Collapsible Ready");
|
|
MathJax.Ajax.loadComplete("[a11y]/collapsible.js");
|
|
});
|
|
|