AssistiveMML.js (5942B)
1 /* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 4 /************************************************************* 5 * 6 * MathJax/extensions/AssistiveMML.js 7 * 8 * Implements an extension that inserts hidden MathML into the 9 * page for screen readers or other asistive technology. 10 * 11 * --------------------------------------------------------------------- 12 * 13 * Copyright (c) 2015 The MathJax Consortium 14 * 15 * Licensed under the Apache License, Version 2.0 (the "License"); 16 * you may not use this file except in compliance with the License. 17 * You may obtain a copy of the License at 18 * 19 * http://www.apache.org/licenses/LICENSE-2.0 20 * 21 * Unless required by applicable law or agreed to in writing, software 22 * distributed under the License is distributed on an "AS IS" BASIS, 23 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 * See the License for the specific language governing permissions and 25 * limitations under the License. 26 */ 27 28 (function (AJAX,CALLBACK,HUB,HTML) { 29 var SETTINGS = HUB.config.menuSettings; 30 31 var AssistiveMML = MathJax.Extension["AssistiveMML"] = { 32 version: "2.6.1", 33 34 config: HUB.CombineConfig("AssistiveMML",{ 35 disabled: false, 36 styles: { 37 ".MJX_Assistive_MathML": { 38 position:"absolute!important", 39 top: 0, left: 0, 40 clip: (HUB.Browser.isMSIE && (document.documentMode||0) < 8 ? 41 "rect(1px 1px 1px 1px)" : "rect(1px, 1px, 1px, 1px)"), 42 padding: "1px 0 0 0!important", 43 border: "0!important", 44 height: "1px!important", 45 width: "1px!important", 46 overflow: "hidden!important", 47 display:"block!important", 48 // 49 // Don't allow the assistive MathML become part of the selection 50 // 51 "-webkit-touch-callout": "none", 52 "-webkit-user-select": "none", 53 "-khtml-user-select": "none", 54 "-moz-user-select": "none", 55 "-ms-user-select": "none", 56 "user-select": "none" 57 }, 58 ".MJX_Assistive_MathML.MJX_Assistive_MathML_Block": { 59 width: "100%!important" 60 } 61 } 62 }), 63 64 Config: function () { 65 if (!this.config.disabled && SETTINGS.assistiveMML == null) 66 HUB.Config({menuSettings:{assistiveMML:true}}); 67 AJAX.Styles(this.config.styles); 68 HUB.Register.MessageHook("End Math",function (msg) { 69 if (SETTINGS.assistiveMML) return AssistiveMML.AddAssistiveMathML(msg[1]) 70 }); 71 }, 72 73 // 74 // This sets up a state object that lists the jax and index into the jax, 75 // and a dummy callback that is used to synchronizing with MathJax. 76 // It will be called when the jax are all processed, and that will 77 // let the MathJax queue continue (it will block until then). 78 // 79 AddAssistiveMathML: function (node) { 80 var state = { 81 jax: HUB.getAllJax(node), i: 0, 82 callback: MathJax.Callback({}) 83 }; 84 this.HandleMML(state); 85 return state.callback; 86 }, 87 88 // 89 // This removes the data-mathml attribute and the assistive MathML from 90 // all the jax. 91 // 92 RemoveAssistiveMathML: function (node) { 93 var jax = HUB.getAllJax(node), frame; 94 for (var i = 0, m = jax.length; i < m; i++) { 95 frame = document.getElementById(jax[i].inputID+"-Frame"); 96 if (frame && frame.getAttribute("data-mathml")) { 97 frame.removeAttribute("data-mathml"); 98 if (frame.lastChild && frame.lastChild.className.match(/MJX_Assistive_MathML/)) 99 frame.removeChild(frame.lastChild); 100 } 101 } 102 }, 103 104 // 105 // For each jax in the state, look up the frame. 106 // If the jax doesn't use NativeMML and hasn't already been handled: 107 // Get the MathML for the jax, taking resets into account. 108 // Add a data-mathml attribute to the frame, and 109 // Create a span that is not visible on screen and put the MathML in it, 110 // and add it to the frame. 111 // When all the jax are processed, call the callback. 112 // 113 HandleMML: function (state) { 114 var m = state.jax.length, jax, mml, frame, span; 115 while (state.i < m) { 116 jax = state.jax[state.i]; 117 frame = document.getElementById(jax.inputID+"-Frame"); 118 if (jax.outputJax !== "NativeMML" && frame && !frame.getAttribute("data-mathml")) { 119 try { 120 mml = jax.root.toMathML("").replace(/\n */g,"").replace(/<!--.*?-->/g,""); 121 } catch (err) { 122 if (!err.restart) throw err; // an actual error 123 return MathJax.Callback.After(["HandleMML",this,state],err.restart); 124 } 125 frame.setAttribute("data-mathml",mml); 126 span = HTML.addElement(frame,"span",{ 127 isMathJax: true, unselectable: "on", 128 className: "MJX_Assistive_MathML" 129 + (jax.root.Get("display") === "block" ? " MJX_Assistive_MathML_Block" : "") 130 }); 131 span.innerHTML = mml; 132 frame.style.position = "relative"; 133 frame.setAttribute("role","presentation"); 134 frame.firstChild.setAttribute("aria-hidden","true"); 135 span.setAttribute("role","presentation"); 136 } 137 state.i++; 138 } 139 state.callback(); 140 } 141 142 }; 143 144 HUB.Startup.signal.Post("AssistiveMML Ready"); 145 146 })(MathJax.Ajax,MathJax.Callback,MathJax.Hub,MathJax.HTML); 147 148 // 149 // Make sure the toMathML extension is loaded before we signal 150 // the load complete for this extension. Then wait for the end 151 // of the user configuration before configuring this extension. 152 // 153 MathJax.Callback.Queue( 154 ["Require",MathJax.Ajax,"[MathJax]/extensions/toMathML.js"], 155 ["loadComplete",MathJax.Ajax,"[MathJax]/extensions/AssistiveMML.js"], 156 function () { 157 MathJax.Hub.Register.StartupHook("End Config",["Config",MathJax.Extension.AssistiveMML]); 158 } 159 ); 160