123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498 |
- /*************************************************************
- *
- * [Contrib]/a11y/auto-collapse.js
- *
- * Implements the ability to have long expressions collapse
- * automatically on screen size changes.
- *
- * ---------------------------------------------------------------------
- *
- * 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 SETTINGS = HUB.config.menuSettings;
- var COOKIE = {}; // replaced when menu is available
-
- //
- // 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 Collapse = MathJax.Extension["auto-collapse"] = {
- version: "1.2.3",
- config: HUB.CombineConfig("auto-collapse",{
- disabled: false
- }),
- dependents: [], // the extensions that depend on this one
- /*****************************************************************/
- Enable: function (update,menu) {
- SETTINGS.autocollapse = true;
- if (menu) COOKIE.autocollapse = true
- this.config.disabled = false;
- MathJax.Extension.collapsible.Enable(false,menu);
- if (update) {
- HUB.Queue(
- ["Reprocess",HUB],
- ["CollapseWideMath",this]
- );
- }
- },
- Disable: function (update,menu) {
- SETTINGS.autocollapse = false;
- if (menu) COOKIE.autocollapse = 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(["Rerender",HUB]);
- },
-
- //
- // Register a dependent
- //
- Dependent: function (extension) {
- this.dependents.push(extension);
- },
- Startup: function () {
- //
- // Inform collapsible extension that we are a dependent
- //
- var Collapsible = MathJax.Extension.collapsible;
- if (Collapsible) Collapsible.Dependent(this);
- //
- // Add the filter into the post-input hooks (priority 150, so other
- // hooks run first, in particular, the enrichment and complexity hooks).
- //
- HUB.postInputHooks.Add(["Filter",Collapse],150);
- //
- // Add the auto-collapsing
- //
- HUB.Queue(function () {return Collapse.CollapseWideMath()});
- //
- // Add a resize handler to check for math that needs
- // to be collapsed or expanded.
- //
- if (window.addEventListener) window.addEventListener("resize",Collapse.resizeHandler,false);
- else if (window.attachEvent) window.attachEvent("onresize",Collapse.resizeHandler);
- else window.onresize = Collapse.resizeHandler;
- },
- //
- // If the math is block-level (or in an element "by itself"), then
- // add the SRE actions for this element.
- //
- Filter: function (jax,id,script) {
- if (!jax.enriched || this.config.disabled) return;
- if (jax.root.Get("display") === "block" ||
- script.parentNode.childNodes.length <= 3) {
- jax.root.SRE = {action: this.Actions(jax.root)};
- }
- },
- //
- // Produce an array of collapsible actions
- // sorted by depth and complexity
- //
- Actions: function (node) {
- var actions = [];
- this.getActions(node,0,actions);
- return this.sortActions(actions);
- },
- getActions: function (node,depth,actions) {
- if (node.isToken || !node.data) return;
- depth++;
- for (var i = 0, m = node.data.length; i < m; i++) {
- if (node.data[i]) {
- var child = node.data[i];
- if (child.collapsible) {
- if (!actions[depth]) actions[depth] = [];
- actions[depth].push(child);
- this.getActions(child.data[1],depth,actions);
- } else {
- this.getActions(child,depth,actions);
- }
- }
- }
- },
- sortActions: function (actions) {
- var ACTIONS = [];
- for (var i = 0, m = actions.length; i < m; i++) {
- if (actions[i]) ACTIONS = ACTIONS.concat(actions[i].sort(this.sortActionsBy));
- }
- return ACTIONS;
- },
- sortActionsBy: function (a,b) {
- a = a.data[1].complexity; b = b.data[1].complexity;
- return (a < b ? -1 : a > b ? 1 : 0);
- },
-
- /*****************************************************************/
- /*
- * These routines implement the automatic collapsing of equations
- * based on container widths.
- */
- //
- // Find math that is too wide and collapse it.
- //
- CollapseWideMath: function (element) {
- if (this.config.disabled) return;
- this.GetContainerWidths(element);
- var jax = HUB.getAllJax(element);
- var state = {collapse: [], jax: jax, m: jax.length, i: 0, changed:false};
- return this.collapseState(state);
- },
- collapseState: function (state) {
- var collapse = state.collapse;
- while (state.i < state.m) {
- var jax = state.jax[state.i];
- var SRE = jax.root.SRE; state.changed = false;
- if (SRE && SRE.action.length) {
- if (SRE.cwidth < SRE.m || SRE.cwidth > SRE.M) {
- var restart = this.getActionWidths(jax,state); if (restart) return restart;
- this.collapseActions(SRE,state);
- if (state.changed) collapse.push(jax.SourceElement());
- }
- }
- state.i++;
- }
- if (collapse.length === 0) return;
- if (collapse.length === 1) collapse = collapse[0];
- return HUB.Rerender(collapse);
- },
-
- //
- // Find the actions that need to be collapsed to acheive
- // the correct width, and retain the sizes that would cause
- // the equation to be expanded or collapsed further.
- //
- collapseActions: function (SRE,state) {
- var w = SRE.width, m = w, M = 1000000;
- for (var j = SRE.action.length-1; j >= 0; j--) {
- var action = SRE.action[j], selection = action.selection;
- if (w > SRE.cwidth) {
- action.selection = 1;
- m = action.SREwidth; M = w;
- } else {
- action.selection = 2;
- }
- w = action.SREwidth;
- if (SRE.DOMupdate) {
- document.getElementById(action.id).setAttribute("selection",action.selection);
- } else if (action.selection !== selection) {
- state.changed = true;
- }
- }
- SRE.m = m; SRE.M = M;
- },
- //
- // Get the widths of the different collapsings,
- // trapping any restarts, and restarting the process
- // when the event has occurred.
- //
- getActionWidths: function (jax,state) {
- if (!jax.root.SRE.actionWidths) {
- MathJax.OutputJax[jax.outputJax].getMetrics(jax);
- try {this.computeActionWidths(jax)} catch (err) {
- if (!err.restart) throw err;
- return MathJax.Callback.After(["collapseState",this,state],err.restart);
- }
- state.changed = true;
- }
- return null;
- },
- //
- // Compute the action widths by collapsing each maction,
- // and recording the width of the complete equation.
- //
- computeActionWidths: function (jax) {
- var SRE = jax.root.SRE, actions = SRE.action, j, state = {};
- SRE.width = jax.sreGetRootWidth(state);
- for (j = actions.length-1; j >= 0; j--) actions[j].selection = 2;
- for (j = actions.length-1; j >= 0; j--) {
- var action = actions[j];
- if (action.SREwidth == null) {
- action.selection = 1;
- action.SREwidth = jax.sreGetActionWidth(state,action);
- }
- }
- SRE.actionWidths = true;
- },
- //
- // Get the widths of the containers of tall the math elements
- // that can be collapsed (so we can tell which ones NEED to be
- // collapsed). Do this in a way that only causes two reflows.
- //
- GetContainerWidths: function (element) {
- var JAX = HUB.getAllJax(element);
- var i, m, script, span = MathJax.HTML.Element("span",{style:{display:"block"}});
- var math = [], jax, root;
- for (i = 0, m = JAX.length; i < m; i++) {
- jax = JAX[i], root = jax.root, SRE = root.SRE;
- if (SRE && SRE.action.length) {
- if (SRE.width == null) {
- jax.sreGetMetrics();
- SRE.m = SRE.width; SRE.M = 1000000;
- }
- script = jax.SourceElement();
- script.previousSibling.style.display = "none";
- script.parentNode.insertBefore(span.cloneNode(false),script);
- math.push([jax,script]);
- }
- }
- for (i = 0, m = math.length; i < m; i++) {
- jax = math[i][0], script = math[i][1];
- if (script.previousSibling.offsetWidth)
- jax.root.SRE.cwidth = script.previousSibling.offsetWidth * jax.root.SRE.em;
- }
- for (i = 0, m = math.length; i < m; i++) {
- jax = math[i][0], script = math[i][1];
- script.parentNode.removeChild(script.previousSibling);
- script.previousSibling.style.display = "";
- }
- },
- /*****************************************************************/
- //
- // A resize handler that can be tied to the window resize event
- // to collapse math automatically on resize.
- //
- timer: null,
- running: false,
- retry: false,
- saved_delay: 0,
-
- resizeHandler: function (event) {
- if (Collapse.config.disabled) return;
- if (Collapse.running) {Collapse.retry = true; return}
- if (Collapse.timer) clearTimeout(Collapse.timer);
- Collapse.timer = setTimeout(Collapse.resizeAction, 100);
- },
- resizeAction: function () {
- Collapse.timer = null;
- Collapse.running = true;
- HUB.Queue(
- function () {
- //
- // Prevent flicker between input and output phases.
- //
- Collapse.saved_delay = HUB.processSectionDelay;
- HUB.processSectionDelay = 0;
- },
- ["CollapseWideMath",Collapse],
- ["resizeCheck",Collapse]
- );
- },
- resizeCheck: function () {
- Collapse.running = false;
- HUB.processSectionDelay = Collapse.saved_delay;
- if (Collapse.retry) {
- Collapse.retry = false;
- setTimeout(Collapse.resizeHandler,0);
- }
- }
- };
- HUB.Register.StartupHook("End Extensions", function () {
- if (SETTINGS.autocollapse == null) {
- SETTINGS.autocollapse = !Collapse.config.disabled;
- } else {
- Collapse.config.disabled = !SETTINGS.autocollapse;
- }
- HUB.Register.StartupHook("MathMenu Ready", function () {
- COOKIE = MathJax.Menu.cookie;
- var Switch = function(menu) {
- Collapse[SETTINGS.autocollapse ? "Enable" : "Disable"](true,true);
- MathJax.Menu.saveCookie();
- };
- var ITEM = MathJax.Menu.ITEM,
- MENU = MathJax.Menu.menu;
- var menu = ITEM.CHECKBOX(
- ['AutoCollapse','Auto Collapse'], 'autocollapse', {action: Switch}
- );
- var submenu = (MENU.FindId('Accessibility')||{}).submenu, index;
- if (submenu) {
- index = submenu.IndexOfId('AutoCollapse');
- if (index !== null) {
- submenu.items[index] = menu;
- } else {
- index = submenu.IndexOfId('CollapsibleMath');
- submenu.items.splice(index+1,0,menu);
- }
- } else {
- index = MENU.IndexOfId('CollapsibleMath');
- MENU.items.splice(index+1,0,menu);
- }
- var init = function () {Collapse[SETTINGS.autocollapse ? "Enable" : "Disable"]()};
- if (MathJax.Extension.collapse) init();
- else MathJax.Hub.Register.StartupHook("Auto Collapse Ready", init);
- },25); // after Assistive-Explore
- },25);
- })(MathJax.Hub);
- /*****************************************************************/
- /*
- * Add methods to the ElementJax and OutputJax to get the
- * widths of the collapsed elements.
- */
- //
- // Add SRE methods to ElementJax.
- //
- MathJax.ElementJax.Augment({
- sreGetMetrics: function () {
- MathJax.OutputJax[this.outputJax].sreGetMetrics(this,this.root.SRE);
- },
- sreGetRootWidth: function (state) {
- return MathJax.OutputJax[this.outputJax].sreGetRootWidth(this,state);
- },
- sreGetActionWidth: function (state,action) {
- return MathJax.OutputJax[this.outputJax].sreGetActionWidth(this,state,action);
- }
- });
- //
- // Add default methods to base OutputJax class.
- //
- MathJax.OutputJax.Augment({
- getMetrics: function () {}, // make sure it is defined
- sreGetMetrics: function (jax,SRE) {SRE.cwidth = 1000000; SRE.width = 0; SRE.em = 12},
- sreGetRootWidth: function (jax,state) {return 0},
- sreGetActionWidth: function (jax,state,action) {return 0}
- });
- //
- // Specific implementations for HTML-CSS output.
- //
- MathJax.Hub.Register.StartupHook("HTML-CSS Jax Ready",function () {
- MathJax.OutputJax["HTML-CSS"].Augment({
- sreGetMetrics: function (jax,SRE) {
- SRE.width = jax.root.data[0].HTMLspanElement().parentNode.bbox.w;
- SRE.em = 1 / jax.HTMLCSS.em / jax.HTMLCSS.scale;
- },
- sreGetRootWidth: function (jax,state) {
- var html = jax.root.data[0].HTMLspanElement();
- state.box = html.parentNode;
- return state.box.bbox.w;
- },
- sreGetActionWidth: function (jax,state,action) {
- return jax.root.data[0].toHTML(state.box).bbox.w;
- }
- });
- });
- //
- // Specific implementations for SVG output.
- //
- MathJax.Hub.Register.StartupHook("SVG Jax Ready",function () {
- MathJax.OutputJax.SVG.Augment({
- getMetrics: function (jax) {
- this.em = MathJax.ElementJax.mml.mbase.prototype.em = jax.SVG.em; this.ex = jax.SVG.ex;
- this.linebreakWidth = jax.SVG.lineWidth; this.cwidth = jax.SVG.cwidth;
- },
- sreGetMetrics: function (jax,SRE) {
- SRE.width = jax.root.SVGdata.w/1000;
- SRE.em = 1/jax.SVG.em;
- },
- sreGetRootWidth: function (jax,state) {
- state.span = document.getElementById(jax.inputID+"-Frame");
- return jax.root.SVGdata.w/1000;
- },
- sreGetActionWidth: function (jax,state,action) {
- this.mathDiv = state.span;
- state.span.appendChild(this.textSVG);
- try {var svg = jax.root.data[0].toSVG()} catch(err) {var error = err}
- state.span.removeChild(this.textSVG);
- if (error) throw error; // can happen when a restart is needed
- return jax.root.data[0].SVGdata.w/1000;
- }
- });
- });
- //
- // Specific implementations for CommonHTML output.
- //
- MathJax.Hub.Register.StartupHook("CommonHTML Jax Ready",function () {
- MathJax.OutputJax.CommonHTML.Augment({
- sreGetMetrics: function (jax,SRE) {
- SRE.width = jax.root.CHTML.w;
- SRE.em = 1 / jax.CHTML.em / jax.CHTML.scale;
- },
- sreGetRootWidth: function (jax,state) {
- state.span = document.getElementById(jax.inputID+"-Frame").firstChild;
- state.tmp = document.createElement("span");
- state.tmp.className = state.span.className;
- return jax.root.CHTML.w / jax.CHTML.scale;
- },
- sreGetActionWidth: function (jax,state,action) {
- state.span.parentNode.replaceChild(state.tmp,state.span);
- MathJax.OutputJax.CommonHTML.CHTMLnode = state.tmp;
- try {jax.root.data[0].toCommonHTML(state.tmp)} catch (err) {var error = err}
- state.tmp.parentNode.replaceChild(state.span,state.tmp);
- if (error) throw error; // can happen when a restart is needed
- return jax.root.data[0].CHTML.w / jax.CHTML.scale;
- }
- });
- });
- //
- // Specific implementations for NativeMML output.
- //
- MathJax.Hub.Register.StartupHook("NativeMML Jax Ready",function () {
- MathJax.OutputJax.NativeMML.Augment({
- sreGetMetrics: function (jax,SRE) {
- var span = document.getElementById(jax.inputID+"-Frame");
- SRE.width = span.offsetWidth;
- SRE.em = 1; SRE.DOMupdate = true;
- },
- sreGetRootWidth: function (jax,state) {
- state.span = document.getElementById(jax.inputID+"-Frame").firstChild;
- return state.span.offsetWidth;
- },
- sreGetActionWidth: function (jax,state,action) {
- var maction = document.getElementById(action.id);
- maction.setAttribute("selection",1);
- var w = state.span.offsetWidth;
- return w;
- }
- });
- });
- /*****************************************************************/
- //
- // Load the collapsible extension and
- // signal the start up when that has loaded.
- //
- MathJax.Ajax.Require("[a11y]/collapsible.js");
- MathJax.Hub.Register.StartupHook("Collapsible Ready", function () {
- MathJax.Extension["auto-collapse"].Startup(); // Initialize the collapsing process
- MathJax.Hub.Startup.signal.Post("Auto Collapse Ready");
- MathJax.Ajax.loadComplete("[a11y]/auto-collapse.js");
- });
|