semantic-enrich.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /*************************************************************
  2. *
  3. * [Contrib]/a11y/semantic-enrich.js
  4. *
  5. * An extension that connects MathJax to the Speech-Rule-Engine
  6. * to produce semantically enriched MathML.
  7. *
  8. * ---------------------------------------------------------------------
  9. *
  10. * Copyright (c) 2016-2017 The MathJax Consortium
  11. *
  12. * Licensed under the Apache License, Version 2.0 (the "License");
  13. * you may not use this file except in compliance with the License.
  14. * You may obtain a copy of the License at
  15. *
  16. * http://www.apache.org/licenses/LICENSE-2.0
  17. *
  18. * Unless required by applicable law or agreed to in writing, software
  19. * distributed under the License is distributed on an "AS IS" BASIS,
  20. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  21. * See the License for the specific language governing permissions and
  22. * limitations under the License.
  23. */
  24. MathJax.Extension["semantic-enrich"] = {
  25. version: "1.2.3",
  26. config: MathJax.Hub.CombineConfig("semantic-enrich",{disabled: false}),
  27. dependents: [], // the extensions that depend on this one
  28. running: false,
  29. //
  30. // Names of attributes to force if set by mstyle
  31. // (so SRE doesn't have to look these up)
  32. //
  33. mstyleLookup: {
  34. mi: ["mathvariant"],
  35. mo: ["mathvariant","accent","largeop","form","fence","separator","movablelimits"],
  36. mn: ["mathvariant"],
  37. mtext: ["mathvariant"],
  38. ms: ["mathvariant"],
  39. mfrac: ["linethickness"],
  40. mfenced: ["open","close","separators"],
  41. menclose: ["notation"],
  42. munder: ["accentunder"],
  43. mover: ["accent"],
  44. munderover: ["accent","accentunder"]
  45. },
  46. //
  47. // If we are not disabled,
  48. // Get the enriched MathML and parse it into the jax root.
  49. // Mark the jax as enriched.
  50. //
  51. Filter: function (jax,id,script) {
  52. delete jax.enriched;
  53. if (this.config.disabled) return;
  54. try {
  55. this.running = true;
  56. var mml = sre.Enrich.semanticMathmlSync(jax.root.toMathML());
  57. jax.root = MathJax.InputJax.MathML.Parse.prototype.MakeMML(mml);
  58. jax.root.inputID = script.id;
  59. jax.enriched = true;
  60. this.running = false;
  61. } catch (err) {
  62. this.running = false;
  63. throw err;
  64. }
  65. },
  66. //
  67. // Functions to enable and disabled enrichment.
  68. //
  69. Enable: function (update,menu) {
  70. this.config.disabled = false;
  71. if (update) MathJax.Hub.Queue(["Reprocess",MathJax.Hub]);
  72. },
  73. Disable: function (update,menu) {
  74. this.config.disabled = true;
  75. for (var i = this.dependents.length-1; i >= 0; i--) {
  76. var dependent = this.dependents[i];
  77. if (dependent.Disable) dependent.Disable(false,menu);
  78. }
  79. if (update) MathJax.Hub.Queue(["Reprocess",MathJax.Hub]);
  80. },
  81. //
  82. // Register a dependent
  83. //
  84. Dependent: function (extension) {
  85. this.dependents.push(extension);
  86. }
  87. };
  88. (function () {
  89. //
  90. // Set up the a11y path,if it isn't already in place
  91. //
  92. var PATH = MathJax.Ajax.config.path;
  93. if (!PATH.a11y) PATH.a11y = HUB.config.root + "/extensions/a11y";
  94. //
  95. // Load SRE and use the signal to tell MathJax when it is loaded.
  96. // Since SRE waits for the mml element jax, load that too.
  97. //
  98. if (!PATH.SRE) PATH.SRE = MathJax.Ajax.fileURL(PATH.a11y);
  99. MathJax.Ajax.Load("[SRE]/mathjax-sre.js");
  100. MathJax.Hub.Register.StartupHook("Sre Ready",["loadComplete",MathJax.Ajax,"[SRE]/mathjax-sre.js"]);
  101. })();
  102. //
  103. // Make a queue so that the MathML jax and SRE are both loaded before
  104. // we install the filter and signal that we are ready. The MathML config.js
  105. // file must load before loading its jax.js file.
  106. //
  107. MathJax.Callback.Queue(
  108. //
  109. // Load mml jax
  110. //
  111. ["Require",MathJax.Ajax,"[MathJax]/jax/element/mml/jax.js"],
  112. //
  113. // Load MathML input jax (since we need Parse.MakeMML)
  114. //
  115. ["Require",MathJax.Ajax,"[MathJax]/jax/input/MathML/config.js"],
  116. ["Require",MathJax.Ajax,"[MathJax]/jax/input/MathML/jax.js"],
  117. //
  118. // Load toMathML extension (if it isn't already)
  119. //
  120. ["Require",MathJax.Ajax,"[MathJax]/extensions/toMathML.js"],
  121. //
  122. // Wait for SRE (which waits for mml jax) before modifying mbase
  123. //
  124. MathJax.Hub.Register.StartupHook("Sre Ready",function () {
  125. var MML = MathJax.ElementJax.mml,
  126. ENRICH = MathJax.Extension["semantic-enrich"];
  127. //
  128. // Override toMathML's attribute function to include additional
  129. // attributes inherited from mstyle (so SRE doesn't have to look them
  130. // up itself). Eventually, this should be moved to toMathML.js directly.
  131. //
  132. MML.mbase.Augment({
  133. toMathMLattributes: function () {
  134. var defaults = (this.type === "mstyle" ? MML.math.prototype.defaults : this.defaults);
  135. var names = (this.attrNames||MML.copyAttributeNames),
  136. skip = MML.skipAttributes, copy = MML.copyAttributes,
  137. lookup = (ENRICH.running ? ENRICH.mstyleLookup[this.type]||[] : []);
  138. var attr = [], ATTR = (this.attr||{});
  139. if (this.type === "math" && (!this.attr || !this.attr.xmlns))
  140. attr.push('xmlns="http://www.w3.org/1998/Math/MathML"');
  141. if (!this.attrNames) {
  142. for (var id in defaults) {if (!skip[id] && !copy[id] && defaults.hasOwnProperty(id)) {
  143. if (this[id] != null && this[id] !== defaults[id]) {
  144. if (this.Get(id,null,1) !== this[id]) this.toMathMLaddAttr(attr,id,this[id]);
  145. }
  146. }}
  147. }
  148. for (var i = 0, m = names.length; i < m; i++) {
  149. if (copy[names[i]] === 1 && !defaults.hasOwnProperty(names[i])) continue;
  150. value = ATTR[names[i]]; if (value == null) value = this[names[i]];
  151. if (value != null) this.toMathMLaddAttr(attr,names[i],value);
  152. }
  153. for (i = 0, m = lookup.length; i < m; i++) {
  154. id = lookup[i];
  155. if (defaults.hasOwnProperty(id) && !attr["_"+id]) {
  156. value = this.Get(id,1);
  157. if (value != null) this.toMathMLaddAttr(attr,id,value);
  158. }
  159. }
  160. this.toMathMLclass(attr);
  161. if (attr.length) return " "+attr.join(" "); else return "";
  162. },
  163. toMathMLaddAttr: function (attr,id,value) {
  164. attr.push(id+'="'+this.toMathMLquote(value)+'"');
  165. attr["_"+id] = 1;
  166. }
  167. });
  168. //
  169. // Adjust setTeXclass for <mo> so that added elements don't
  170. // cause unwanted space.
  171. //
  172. var TEXCLASS = MML.mo.prototype.setTeXclass;
  173. MML.mo.Augment({
  174. setTeXclass: function (prev) {
  175. var values = this.getValues("form","lspace","rspace"); // sets useMMLspacing
  176. if (this.useMMLspacing) {
  177. this.texClass = MML.TEXCLASS.NONE;
  178. return this;
  179. }
  180. if (this.attr && this.attr["data-semantic-added"]) {
  181. this.texClass = this.prevClass = MML.TEXCLASS.NONE;
  182. return prev;
  183. }
  184. return TEXCLASS.apply(this,arguments);
  185. }
  186. });
  187. }),
  188. function () {
  189. //
  190. // Install enrichment filter, and signal that we are ready.
  191. //
  192. MathJax.Hub.postInputHooks.Add(["Filter",MathJax.Extension["semantic-enrich"]],50);
  193. MathJax.Hub.Startup.signal.Post("Semantic Enrich Ready");
  194. MathJax.Ajax.loadComplete("[a11y]/semantic-enrich.js");
  195. }
  196. );