diff options
Diffstat (limited to 'js/mathjax/extensions/a11y/explorer.js')
-rw-r--r-- | js/mathjax/extensions/a11y/explorer.js | 827 |
1 files changed, 827 insertions, 0 deletions
diff --git a/js/mathjax/extensions/a11y/explorer.js b/js/mathjax/extensions/a11y/explorer.js new file mode 100644 index 0000000..bba3edd --- /dev/null +++ b/js/mathjax/extensions/a11y/explorer.js @@ -0,0 +1,827 @@ +// @license magnet:?xt=urn:btih:8e4f440f4c65981c5bf93c76d35135ba5064d8b7dn=apache-2.0.txt Apache-2.0 +/************************************************************* + * + * [Contrib]/a11y/explorer.js + * + * Implements expression exploration via the SRE explorer. + * + * --------------------------------------------------------------------- + * + * 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. + */ + +MathJax.Hub.Register.StartupHook('Sre Ready', function() { + var FALSE, KEY; + var SETTINGS = MathJax.Hub.config.menuSettings; + var COOKIE = {}; // replaced when menu is available + + MathJax.Hub.Register.StartupHook('MathEvents Ready', function() { + FALSE = MathJax.Extension.MathEvents.Event.False; + KEY = MathJax.Extension.MathEvents.Event.KEY; + }); + + var Assistive = MathJax.Extension.explorer = { + version: '1.6.0', + dependents: [], // the extensions that depend on this one + // + // Default configurations. + // + defaults: { + walker: 'table', + highlight: 'none', + background: 'blue', + foreground: 'black', + speech: true, + generation: 'lazy', + subtitle: false, + ruleset: 'mathspeak-default' + }, + eagerComplexity: 80, + prefix: 'Assistive-', + hook: null, + locHook: null, + oldrules: null, + addMenuOption: function(key, value) { + SETTINGS[Assistive.prefix + key] = value; + }, + + addDefaults: function() { + var defaults = MathJax.Hub.CombineConfig('explorer', Assistive.defaults); + var keys = Object.keys(defaults); + for (var i = 0, key; key = keys[i]; i++) { + if (typeof(SETTINGS[Assistive.prefix + key]) === 'undefined') { + Assistive.addMenuOption(key, defaults[key]); + } + } + Assistive.setSpeechOption(); + Explorer.Reset(); + }, + + setOption: function(key, value) { + if (SETTINGS[Assistive.prefix + key] === value) return; + Assistive.addMenuOption(key, value); + Explorer.Reset(); + }, + + getOption: function(key) { + return SETTINGS[Assistive.prefix + key]; + }, + + speechOption: function(msg) { + if (Assistive.oldrules === msg.value) return; + Assistive.setSpeechOption(); + Explorer.Regenerate(); + }, + + setSpeechOption: function() { + var ruleset = SETTINGS[Assistive.prefix + 'ruleset']; + var cstr = ruleset.split('-'); + sre.System.getInstance().setupEngine({ + locale: MathJax.Localization.locale, + domain: Assistive.Domain(cstr[0]), + style: cstr[1] + }); + Assistive.oldrules = ruleset; + }, + + Domain: function(domain) { + switch (domain) { + case 'chromevox': + return 'default'; + case 'clearspeak': + return 'clearspeak'; + case 'mathspeak': + default: + return 'mathspeak'; + } + }, + + hook: null, + locHook: null, + Enable: function(update, menu) { + SETTINGS.explorer = true; + if (menu) COOKIE.explorer = true; + MathJax.Extension.collapsible.Enable(false, menu); + if (MathJax.Extension.AssistiveMML) { + MathJax.Extension.AssistiveMML.config.disabled = true; + SETTINGS.assistiveMML = false; + if (menu) COOKIE.assistiveMML = false; + } + this.DisableMenus(false); + if (!this.hook) { + this.hook = MathJax.Hub.Register.MessageHook( + 'New Math', ['Register', this.Explorer]); + } + if (!this.locHook) { + this.locHook = MathJax.Hub.Register.MessageHook( + 'Locale Reset', ['RemoveSpeech', this.Explorer]); + } + if (update) MathJax.Hub.Queue(['Reprocess', MathJax.Hub]); + }, + Disable: function(update, menu) { + SETTINGS.explorer = false; + if (menu) COOKIE.explorer = false; + this.DisableMenus(true); + if (this.hook) { + MathJax.Hub.UnRegister.MessageHook(this.hook); + this.hook = null; + } + for (var i = this.dependents.length - 1; i >= 0; i--) { + var dependent = this.dependents[i]; + if (dependent.Disable) dependent.Disable(false, menu); + } + // Reprocess on update? I don't think it is necessary + // (now that we check for being enabled in the event handlers) + }, + DisableMenus: function(state) { + if (MathJax.Menu) { + var menu = MathJax.Menu.menu.FindId('Accessibility', 'Explorer'); + if (menu) { + menu = menu.submenu; + var items = menu.items; + for (var i = 2, item; item = items[i]; i++) item.disabled = state; + if (!state && menu.FindId('SpeechOutput') && !SETTINGS[Assistive.prefix + 'speech']) { + menu.FindId('Subtitles').disabled = true; + } + } + } + }, + // + // Register a dependent + // + Dependent: function(extension) { + this.dependents.push(extension); + } + }; + + var LiveRegion = MathJax.Object.Subclass({ + div: null, + inner: null, + Init: function() { + this.div = LiveRegion.Create('assertive'); + this.inner = MathJax.HTML.addElement(this.div, 'div'); + }, + // + // Adds the speech div. + // + Add: function() { + if (LiveRegion.added) return; + document.body.appendChild(this.div); + LiveRegion.added = true; + }, + // + // Shows the live region as a subtitle of a node. + // + Show: function(node, highlighter) { + this.div.classList.add('MJX_LiveRegion_Show'); + var rect = node.getBoundingClientRect(); + var bot = rect.bottom + 10 + window.pageYOffset; + var left = rect.left + window.pageXOffset; + this.div.style.top = bot + 'px'; + this.div.style.left = left + 'px'; + var color = highlighter.colorString(); + this.inner.style.backgroundColor = color.background; + this.inner.style.color = color.foreground; + }, + // + // Takes the live region out of the page flow. + // + Hide: function(node) { + this.div.classList.remove('MJX_LiveRegion_Show'); + }, + // + // Clears the speech div. + // + Clear: function() { + this.Update(''); + this.inner.style.top = ''; + this.inner.style.backgroundColor = ''; + }, + // + // Speaks a string by poking it into the speech div. + // + Update: function(speech) { + if (Assistive.getOption('speech')) { + LiveRegion.Update(this.inner, speech); + } + } + }, { + ANNOUNCE: 'Navigatable Math in page. Explore with enter or shift space and arrow' + + ' keys. Expand or collapse elements hitting enter.', + announced: false, + added: false, + styles: {'.MJX_LiveRegion': + { + position: 'absolute', top: '0', height: '1px', width: '1px', + padding: '1px', overflow: 'hidden' + }, + '.MJX_LiveRegion_Show': + { + top: '0', position: 'absolute', width: 'auto', height: 'auto', + padding: '0px 0px', opacity: 1, 'z-index': '202', + left: 0, right: 0, 'margin': '0 auto', + 'background-color': 'white', 'box-shadow': '0px 10px 20px #888', + border: '2px solid #CCCCCC' + } + }, + // + // Creates a live region with a particular type. + // + Create: function(type) { + var element = MathJax.HTML.Element( + 'div', {className: 'MJX_LiveRegion'}); + element.setAttribute('aria-live', type); + return element; + }, + // + // Updates a live region's text content. + // + Update: MathJax.Hub.Browser.isPC ? + function(div, speech) { + div.textContent = ''; + setTimeout(function() {div.textContent = speech;}, 100); + } : function(div, speech) { + div.textContent = ''; + div.textContent = speech; + }, + // + // Speaks the announce string. + // + Announce: function() { + if (!Assistive.getOption('speech')) return; + LiveRegion.announced = true; + MathJax.Ajax.Styles(LiveRegion.styles); + var div = LiveRegion.Create('polite'); + document.body.appendChild(div); + LiveRegion.Update(div, LiveRegion.ANNOUNCE); + setTimeout(function() {document.body.removeChild(div);}, 1000); + } + }); + MathJax.Extension.explorer.LiveRegion = LiveRegion; + + var A11Y_PATH = MathJax.Ajax.fileURL(MathJax.Ajax.config.path.a11y); + + var Explorer = MathJax.Extension.explorer.Explorer = { + liveRegion: LiveRegion(), + walker: null, + highlighter: null, + hoverer: null, + flamer: null, + speechDiv: null, + earconFile: A11Y_PATH + '/invalid_keypress' + + (['Firefox', 'Chrome', 'Opera'].indexOf(MathJax.Hub.Browser.name) !== -1 ? + '.ogg' : '.mp3'), + expanded: false, + focusoutEvent: MathJax.Hub.Browser.isFirefox ? 'blur' : 'focusout', + focusinEvent: 'focus', + ignoreFocusOut: false, + jaxCache: {}, + messageID: null, + // + // Resets the explorer, rerunning methods not triggered by events. + // + Reset: function() { + Explorer.FlameEnriched(); + }, + // + // Registers new Maths and adds a key event if it is enriched. + // + Register: function(msg) { + if (!Assistive.hook) return; + var script = document.getElementById(msg[1]); + if (script && script.id) { + var jax = MathJax.Hub.getJaxFor(script.id); + if (jax && jax.enriched) { + Explorer.StateChange(script.id, jax); + Explorer.liveRegion.Add(); + Explorer.AddEvent(script); + } + } + }, + StateChange: function(id, jax) { + Explorer.GetHighlighter(.2); + var oldJax = Explorer.jaxCache[id]; + if (oldJax && oldJax === jax.root) return; + if (oldJax) { + sre.Walker.resetState(id + '-Frame'); + } + Explorer.jaxCache[id] = jax.root; + }, + // + // Adds Aria attributes. + // + AddAria: function(math) { + math.setAttribute('role', 'application'); + math.setAttribute('aria-label', 'Math'); + }, + // + // Add hook to run at End Math to restart walking on an expansion element. + // + AddHook: function(jax) { + Explorer.RemoveHook(); + Explorer.hook = MathJax.Hub.Register.MessageHook( + 'End Math', function(message) { + var newid = message[1].id + '-Frame'; + var math = document.getElementById(newid); + if (jax && newid === Explorer.expanded) { + Explorer.ActivateWalker(math, jax); + math.focus(); + Explorer.expanded = false; + } + }); + }, + // + // Remove and unregister the explorer hook. + // + RemoveHook: function() { + if (Explorer.hook) { + MathJax.Hub.UnRegister.MessageHook(Explorer.hook); + Explorer.hook = null; + } + }, + AddMessage: function() { + return MathJax.Message.Set('Generating Speech Output'); + }, + RemoveMessage: function(id) { + if (id) MathJax.Message.Clear(id); + }, + // + // Adds a key event to an enriched jax. + // + AddEvent: function(script) { + var id = script.id + '-Frame'; + var sibling = script.previousSibling; + if (!sibling) return; + var math = sibling.id !== id ? sibling.firstElementChild : sibling; + Explorer.AddAria(math); + Explorer.AddMouseEvents(math); + if (math.className === 'MathJax_MathML') { + math = math.firstElementChild; + } + if (!math) return; + math.onkeydown = Explorer.Keydown; + Explorer.Flame(math); + math.addEventListener( + Explorer.focusinEvent, + function(event) { + if (!Assistive.hook) return; + if (!LiveRegion.announced) LiveRegion.Announce(); + }); + math.addEventListener( + Explorer.focusoutEvent, + function(event) { + if (!Assistive.hook) return; + // A fix for Edge. + if (Explorer.ignoreFocusOut) { + Explorer.ignoreFocusOut = false; + if (Explorer.walker.moved === 'enter') { + event.target.focus(); + return; + } + } + if (Explorer.walker) Explorer.DeactivateWalker(); + }); + // + if (Assistive.getOption('speech')) { + Explorer.AddSpeech(math); + } + // + }, + // + // Add speech output. + // + AddSpeech: function(math) { + var id = math.id; + var jax = MathJax.Hub.getJaxFor(id); + var mathml = jax.root.toMathML(); + if (!math.getAttribute('haslabel')) { + Explorer.AddMathLabel(mathml, id); + } + if (math.getAttribute('hasspeech')) return; + switch (MathJax.Hub.config.explorer.generation) { + case 'eager': + Explorer.AddSpeechEager(mathml, id); + break; + case 'mixed': + var complexity = math.querySelectorAll('[data-semantic-complexity]'); + if (complexity.length >= Assistive.eagerComplexity) { + Explorer.AddSpeechEager(mathml, id); + } + break; + case 'lazy': + default: + break; + } + }, + AddSpeechLazy: function(math) { + var generator = new sre.TreeSpeechGenerator(); + generator.setRebuilt(Explorer.walker.getRebuilt()); + generator.getSpeech(Explorer.walker.rootNode, Explorer.walker.getXml()); + math.setAttribute('hasspeech', 'true'); + }, + // + // + // Adds speech strings to the node using a web worker. + // + AddSpeechEager: function(mathml, id) { + Explorer.MakeSpeechTask( + mathml, id, sre.TreeSpeechGenerator, + function(math, speech) {math.setAttribute('hasspeech', 'true');}, 5); + }, + // + // Attaches the Math expression as an aria label. + // + AddMathLabel: function(mathml, id) { + Explorer.MakeSpeechTask( + mathml, id, sre.SummarySpeechGenerator, + function(math, speech) { + math.setAttribute('haslabel', 'true'); + math.setAttribute('aria-label', speech);}, + 5); + }, + // + // The actual speech task generator. + // + MakeSpeechTask: function(mathml, id, constructor, onSpeech, time) { + var messageID = Explorer.AddMessage(); + setTimeout(function() { + var speechGenerator = new constructor(); + var math = document.getElementById(id); + var dummy = new sre.DummyWalker( + math, speechGenerator, Explorer.highlighter, mathml); + var speech = dummy.speech(); + if (speech) { + onSpeech(math, speech); + } + Explorer.RemoveMessage(messageID); + }, time); + }, + // + // Event execution on keydown. Subsumes the same method of MathEvents. + // + Keydown: function(event) { + var code = event.keyCode; + if (code === KEY.ESCAPE) { + if (!Explorer.walker) return; + Explorer.RemoveHook(); + Explorer.DeactivateWalker(); + FALSE(event); + return; + } + // If walker is active we redirect there. + if (Explorer.walker && Explorer.walker.isActive()) { + // Maps the return key to dash for SRE v3. + code = code === KEY.RETURN ? KEY.DASH : code; + if (typeof(Explorer.walker.modifier) !== 'undefined') { + Explorer.walker.modifier = event.shiftKey; + } + var move = Explorer.walker.move(code); + if (move === null) return; + if (move) { + if (Explorer.walker.moved === 'expand') { + Explorer.expanded = Explorer.walker.node.id; + // This sometimes blurs in Edge and sometimes it does not. + if (MathJax.Hub.Browser.isEdge) { + Explorer.ignoreFocusOut = true; + Explorer.DeactivateWalker(); + return; + } + // This does not blur in FF, IE. + if (MathJax.Hub.Browser.isFirefox || MathJax.Hub.Browser.isMSIE) { + Explorer.DeactivateWalker(); + return; + } + } + Explorer.liveRegion.Update(Explorer.walker.speech()); + Explorer.Highlight(); + } else { + Explorer.PlayEarcon(); + } + FALSE(event); + return; + } + var math = event.target; + if (code === KEY.SPACE && !event.shiftKey) { + MathJax.Extension.MathEvents.Event.ContextMenu(event, math); + FALSE(event); + return; + } + if (Assistive.hook && (code === KEY.RETURN || + (code === KEY.SPACE && event.shiftKey))) { + var jax = MathJax.Hub.getJaxFor(math); + Explorer.ActivateWalker(math, jax); + Explorer.AddHook(jax); + FALSE(event); + return; + } + }, + GetHighlighter: function(alpha) { + Explorer.highlighter = sre.HighlighterFactory.highlighter( + {color: Assistive.getOption('background'), alpha: alpha}, + {color: Assistive.getOption('foreground'), alpha: 1}, + {renderer: MathJax.Hub.outputJax['jax/mml'][0].id, + browser: MathJax.Hub.Browser.name} + ); + }, + // + // Adds mouse events to maction items in an enriched jax. + // + AddMouseEvents: function(node) { + sre.HighlighterFactory.addEvents( + node, + {'mouseover': Explorer.MouseOver, + 'mouseout': Explorer.MouseOut}, + {renderer: MathJax.Hub.outputJax['jax/mml'][0].id, + browser: MathJax.Hub.Browser.name} + ); + }, + MouseOver: function(event) { + if (Assistive.getOption('highlight') === 'none') return; + if (Assistive.getOption('highlight') === 'hover') { + var frame = event.currentTarget; + Explorer.GetHighlighter(.1); + Explorer.highlighter.highlight([frame]); + Explorer.hoverer = true; + } + FALSE(event); + }, + MouseOut: function(event) { + if (Explorer.hoverer) { + Explorer.highlighter.unhighlight(); + Explorer.hoverer = false; + } + return FALSE(event); + }, + // + // Activates Flaming + // + Flame: function(node) { + if (Assistive.getOption('highlight') === 'flame') { + Explorer.GetHighlighter(.05); + Explorer.highlighter.highlightAll(node); + Explorer.flamer = true; + return; + } + }, + UnFlame: function() { + if (Explorer.flamer) { + Explorer.highlighter.unhighlightAll(); + Explorer.flamer = null; + } + }, + FlameEnriched: function() { + Explorer.UnFlame(); + for (var i = 0, all = MathJax.Hub.getAllJax(), jax; jax = all[i]; i++) { + Explorer.Flame(jax.SourceElement().previousSibling); + } + }, + // + // Activates the walker. + // + Walkers: { + 'syntactic': sre.SyntaxWalker, + 'table': sre.TableWalker, + 'semantic': sre.SemanticWalker, + 'none': sre.DummyWalker + }, + ActivateWalker: function(math, jax) { + var speechOn = Assistive.getOption('speech'); + var constructor = Assistive.getOption('walker') ? + Explorer.Walkers[MathJax.Hub.config.explorer.walker] : + Explorer.Walkers['none']; + var speechGenerator = speechOn ? new sre.DirectSpeechGenerator() : + new sre.DummySpeechGenerator(); + var options = sre.System.getInstance().engineSetup(); + speechGenerator.setOptions({ + locale: options.locale, domain: options.domain, + style: options.style, modality: 'speech'}); + Explorer.GetHighlighter(.2); + Explorer.walker = new constructor( + math, speechGenerator, Explorer.highlighter, jax.root.toMathML()); + if (speechOn && !math.getAttribute('hasspeech')) { + Explorer.AddSpeechLazy(math); + } + Explorer.walker.activate(); + if (speechOn) { + if (Assistive.getOption('subtitle')) { + Explorer.liveRegion.Show(math, Explorer.highlighter); + } + Explorer.liveRegion.Update(Explorer.walker.speech()); + } + Explorer.Highlight(); + // A fix for Edge. + if (Explorer.ignoreFocusOut) { + setTimeout(function() {Explorer.ignoreFocusOut = false;}, 500); + } + }, + // + // Deactivates the walker. + // + DeactivateWalker: function() { + var setup = sre.System.getInstance().engineSetup(); + var domain = setup.domain; + var style = domain === 'clearspeak' ? 'default' : setup.style; + Assistive.setOption('ruleset', setup.domain + '-' + style); + Explorer.liveRegion.Clear(); + Explorer.liveRegion.Hide(); + Explorer.Unhighlight(); + Explorer.currentHighlight = null; + Explorer.walker.deactivate(); + Explorer.walker = null; + }, + // + // Highlights the focused nodes. + // + Highlight: function() { + Explorer.Unhighlight(); + Explorer.highlighter.highlight(Explorer.walker.getFocus().getNodes()); + }, + // + // Unhighlights the old nodes. + // + Unhighlight: function() { + Explorer.highlighter.unhighlight(); + }, + // + // Plays the earcon. + // + // Every time we make new Audio element, as some browsers do not allow to + // play audio elements more than once (e.g., Safari). + // + PlayEarcon: function() { + var audio = new Audio(Explorer.earconFile); + audio.play(); + }, + // + // Toggle speech output. + // + SpeechOutput: function() { + Explorer.Reset(); + var speechItems = ['Subtitles']; + speechItems.forEach( + function(x) { + var item = MathJax.Menu.menu.FindId('Accessibility', 'Explorer', x); + if (item) { + item.disabled = !item.disabled; + }}); + Explorer.Regenerate(); + }, + // + // Remove speech and resets SRE options. + // + RemoveSpeech: function() { + Assistive.setSpeechOption(); + for (var i = 0, all = MathJax.Hub.getAllJax(), jax; jax = all[i]; i++) { + var math = document.getElementById(jax.inputID + '-Frame'); + if (math) { + math.removeAttribute('hasspeech'); + math.removeAttribute('haslabel'); + } + } + }, + // + // Regenerates speech. + // + Regenerate: function() { + for (var i = 0, all = MathJax.Hub.getAllJax(), jax; jax = all[i]; i++) { + var math = document.getElementById(jax.inputID + '-Frame'); + if (math) { + math.removeAttribute('hasspeech'); + Explorer.AddSpeech(math); + } + } + }, + Startup: function() { + var Collapsible = MathJax.Extension.collapsible; + if (Collapsible) Collapsible.Dependent(Assistive); + Assistive.addDefaults(); + } + }; + + MathJax.Hub.Register.StartupHook('End Extensions', function() { + Assistive[SETTINGS.explorer === false ? 'Disable' : 'Enable'](); + MathJax.Hub.Startup.signal.Post('Explorer Ready'); + MathJax.Hub.Register.StartupHook('MathMenu Ready', function() { + COOKIE = MathJax.Menu.cookie; + var Switch = function(menu) { + Assistive[SETTINGS.explorer ? 'Enable' : 'Disable'](true, true); + MathJax.Menu.saveCookie(); + }; + var ITEM = MathJax.Menu.ITEM, + MENU = MathJax.Menu.menu; + var reset = {action: Explorer.Reset}; + var speech = {action: Assistive.speechOption}; + var explorerMenu = + ITEM.SUBMENU(['Explorer', 'Explorer'], + ITEM.CHECKBOX(['Active', 'Active'], 'explorer', {action: Switch}), + ITEM.RULE(), + ITEM.CHECKBOX(['Walker', 'Walker'], 'Assistive-walker'), + ITEM.SUBMENU(['Highlight', 'Highlight'], + ITEM.RADIO(['none', 'None'], 'Assistive-highlight', reset), + ITEM.RADIO(['hover', 'Hover'], 'Assistive-highlight', reset), + ITEM.RADIO(['flame', 'Flame'], 'Assistive-highlight', reset) + ), + ITEM.SUBMENU(['Background', 'Background'], + ITEM.RADIO(['blue', 'Blue'], 'Assistive-background', reset), + ITEM.RADIO(['red', 'Red'], 'Assistive-background', reset), + ITEM.RADIO(['green', 'Green'], 'Assistive-background', reset), + ITEM.RADIO(['yellow', 'Yellow'], 'Assistive-background', reset), + ITEM.RADIO(['cyan', 'Cyan'], 'Assistive-background', reset), + ITEM.RADIO(['magenta', 'Magenta'], 'Assistive-background', reset), + ITEM.RADIO(['white', 'White'], 'Assistive-background', reset), + ITEM.RADIO(['black', 'Black'], 'Assistive-background', reset) + ), + ITEM.SUBMENU(['Foreground', 'Foreground'], + ITEM.RADIO(['black', 'Black'], 'Assistive-foreground', reset), + ITEM.RADIO(['white', 'White'], 'Assistive-foreground', reset), + ITEM.RADIO(['magenta', 'Magenta'], 'Assistive-foreground', reset), + ITEM.RADIO(['cyan', 'Cyan'], 'Assistive-foreground', reset), + ITEM.RADIO(['yellow', 'Yellow'], 'Assistive-foreground', reset), + ITEM.RADIO(['green', 'Green'], 'Assistive-foreground', reset), + ITEM.RADIO(['red', 'Red'], 'Assistive-foreground', reset), + ITEM.RADIO(['blue', 'Blue'], 'Assistive-foreground', reset) + ), + ITEM.RULE(), + ITEM.CHECKBOX(['SpeechOutput', 'Speech Output'], + 'Assistive-speech', {action: Explorer.SpeechOutput}), + ITEM.CHECKBOX(['Subtitles', 'Subtitles'], 'Assistive-subtitle', + {disabled: !SETTINGS['Assistive-speech']}), + ITEM.RULE(), + ITEM.SUBMENU(['Mathspeak', 'Mathspeak Rules'], + ITEM.RADIO(['mathspeak-default', 'Verbose'], + 'Assistive-ruleset', speech), + ITEM.RADIO(['mathspeak-brief', 'Brief'], 'Assistive-ruleset', speech), + ITEM.RADIO(['mathspeak-sbrief', 'Superbrief'], + 'Assistive-ruleset', speech) + ), + ITEM.RADIO(['clearspeak-default', 'Clearspeak Rules'], + 'Assistive-ruleset', speech), + ITEM.SUBMENU(['Chromevox', 'ChromeVox Rules'], + ITEM.RADIO(['chromevox-default', 'Verbose'], + 'Assistive-ruleset', speech), + ITEM.RADIO(['chromevox-alternative', 'Alternative'], + 'Assistive-ruleset', speech) + ) + ); + var submenu = (MENU.FindId('Accessibility') || {}).submenu, index; + if (submenu) { + index = submenu.IndexOfId('Explorer'); + if (index !== null) { + submenu.items[index] = explorerMenu; + } else { + index = submenu.IndexOfId('CollapsibleMath'); + submenu.items.splice(index + 1, 0, explorerMenu); + } + } else { + index = MENU.IndexOfId('CollapsibleMath'); + MENU.items.splice(index + 1, 0, explorerMenu); + } + if (!SETTINGS.explorer) Assistive.DisableMenus(true); + },20); // Between collapsible and auto-collapse extensions + },20); + +}); + +// +// Patch problem with SVG getJaxForMath when used from explorer +// (can be removed after the next release of MathJax). +// +MathJax.Hub.Register.StartupHook("SVG Jax Ready",function () { + MathJax.Hub.Config({SVG: {addMMLclasses: true}}); + var SVG = MathJax.OutputJax.SVG; + if (parseFloat(SVG.version) < 2.7) { + var JAXFROMMATH = SVG.getJaxFromMath; + SVG.Augment({ + getJaxFromMath: function (math) { + if (math.parentNode.className.match(/MathJax_SVG_Display/)) math = math.parentNode; + return JAXFROMMATH.call(this,math); + } + }); + } +}); + +// +// Set up the a11y path,if it isn't already in place +// +if (!MathJax.Ajax.config.path.a11y) { + MathJax.Ajax.config.path.a11y = MathJax.Hub.config.root + "/extensions/a11y"; +} + +MathJax.Ajax.Require('[a11y]/collapsible.js'); +MathJax.Hub.Register.StartupHook('Collapsible Ready', function() { + MathJax.Extension.explorer.Explorer.Startup(); + MathJax.Ajax.loadComplete('[a11y]/explorer.js'); +}); +// @license-end |