AssistiveMML.js 5.9 KB

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