JAVASCRIPT   51

asciimath2jax js

Guest on 2nd August 2022 03:53:19 PM

  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/asciimath2jax.js
  7.  *  
  8.  *  Implements the AsciiMath to Jax preprocessor that locates AsciiMath
  9.  *  code within the text of a document and replaces it with SCRIPT tags for
  10.  *  processing by MathJax.
  11.  *
  12.  *  Modified by David Lippman, based on tex2jax.js.
  13.  *  Additional work by Davide P. Cervone.
  14.  *  
  15.  *  ---------------------------------------------------------------------
  16.  *  
  17.  *  Copyright (c)  The MathJax Consortium
  18.  *
  19.  *  Licensed under the Apache License, Version 2.0 (the "License");
  20.  *  you may not use this file except in compliance with the License.
  21.  *  You may obtain a copy of the License at
  22.  *
  23.  *      http://www.apache.org/licenses/LICENSE-2.0
  24.  *
  25.  *  Unless required by applicable law or agreed to in writing, software
  26.  *  distributed under the License is distributed on an "AS IS" BASIS,
  27.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  28.  *  See the License for the specific language governing permissions and
  29.  *  limitations under the License.
  30.  */
  31.  
  32. MathJax.Extension.asciimath2jax = {
  33.   version: "2.6.0",
  34.   config: {
  35.     delimiters: [['`','`']],   // The star/stop delimiter pairs for asciimath code
  36.  
  37.     skipTags: ["script","noscript","style","textarea","pre","code","annotation","annotation-xml"],
  38.                                // The names of the tags whose contents will not be
  39.                                // scanned for math delimiters
  40.  
  41.     ignoreClass: "asciimath2jax_ignore",   // the class name of elements whose contents should
  42.                                            // NOT be processed by asciimath2jax.  Note that this
  43.                                            // is a regular expression, so be sure to quote any
  44.                                            // regexp special characters
  45.  
  46.     processClass: "asciimath2jax_process", // the class name of elements whose contents SHOULD
  47.                                            // be processed when they appear inside ones that
  48.                                            // are ignored.  Note that this is a regular expression,
  49.                                            // so be sure to quote any regexp special characters
  50.  
  51.     preview: "AsciiMath"        // set to "none" to not insert MathJax_Preview spans
  52.                                //   or set to an array specifying an HTML snippet
  53.                                //   to use the same preview for every equation.
  54.  
  55.   },
  56.  
  57.   PreProcess: function (element) {
  58.     if (!this.configured) {
  59.       this.config = MathJax.Hub.CombineConfig("asciimath2jax",this.config);
  60.       if (this.config.Augment) {MathJax.Hub.Insert(this,this.config.Augment)}
  61.       this.configured = true;
  62.     }
  63.     if (typeof(element) === "string") {element = document.getElementById(element)}
  64.     if (!element) {element = document.body}
  65.     if (this.createPatterns()) {this.scanElement(element,element.nextSibling)}
  66.   },
  67.  
  68.   createPatterns: function () {
  69.     var starts = [], i, m, config = this.config; this.match = {};
  70.     if (config.delimiters.length === 0) {return false}
  71.     for (i = 0, m = config.delimiters.length; i < m; i++) {
  72.       starts.push(this.patternQuote(config.delimiters[i][0]));
  73.       this.match[config.delimiters[i][0]] = {
  74.         mode: "",
  75.         end: config.delimiters[i][1],
  76.         pattern: this.endPattern(config.delimiters[i][1])
  77.       };
  78.     }
  79.     this.start = new RegExp(starts.sort(this.sortLength).join("|"),"g");
  80.     this.skipTags = new RegExp("^("+config.skipTags.join("|")+")$","i");
  81.     var ignore = [];
  82.     if (MathJax.Hub.config.preRemoveClass) {ignore.push(MathJax.Hub.config.preRemoveClass)}
  83.     if (config.ignoreClass) {ignore.push(config.ignoreClass)}
  84.     this.ignoreClass = (ignore.length ? new RegExp("(^| )("+ignore.join("|")+")( |$)") : /^$/);
  85.     this.processClass = new RegExp("(^| )("+config.processClass+")( |$)");
  86.     return true;
  87.   },
  88.  
  89.   patternQuote: function (s) {return s.replace(/([\^$(){}+*?\-|\[\]\:\\])/g,'\\$1')},
  90.  
  91.   endPattern: function (end) {
  92.     return new RegExp(this.patternQuote(end)+"|\\\\.","g");
  93.   },
  94.  
  95.   sortLength: function (a,b) {
  96.     if (a.length !== b.length) {return b.length - a.length}
  97.     return (a == b ? 0 : (a < b ? -1 : 1));
  98.   },
  99.  
  100.   scanElement: function (element,stop,ignore) {
  101.     var cname, tname, ignoreChild, process;
  102.     while (element && element != stop) {
  103.       if (element.nodeName.toLowerCase() === '#text') {
  104.         if (!ignore) {element = this.scanText(element)}
  105.       } else {
  106.         cname = (typeof(element.className) === "undefined" ? "" : element.className);
  107.         tname = (typeof(element.tagName)   === "undefined" ? "" : element.tagName);
  108.         if (typeof(cname) !== "string") {cname = String(cname)} // jsxgraph uses non-string class names!
  109.         process = this.processClass.exec(cname);
  110.         if (element.firstChild && !cname.match(/(^| )MathJax/) &&
  111.             (process || !this.skipTags.exec(tname))) {
  112.           ignoreChild = (ignore || this.ignoreClass.exec(cname)) && !process;
  113.           this.scanElement(element.firstChild,stop,ignoreChild);
  114.         }
  115.       }
  116.       if (element) {element = element.nextSibling}
  117.     }
  118.   },
  119.  
  120.   scanText: function (element) {
  121.     if (element.nodeValue.replace(/\s+/,'') == '') {return element}
  122.     var match, prev;
  123.     this.search = {start: true};
  124.     this.pattern = this.start;
  125.     while (element) {
  126.       this.pattern.lastIndex = 0;
  127.       while (element && element.nodeName.toLowerCase() === '#text' &&
  128.             (match = this.pattern.exec(element.nodeValue))) {
  129.         if (this.search.start) {element = this.startMatch(match,element)}
  130.                           else {element = this.endMatch(match,element)}
  131.       }
  132.       if (this.search.matched) {element = this.encloseMath(element)}
  133.       if (element) {
  134.         do {prev = element; element = element.nextSibling}
  135.           while (element && (element.nodeName.toLowerCase() === 'br' ||
  136.                              element.nodeName.toLowerCase() === '#comment'));
  137.         if (!element || element.nodeName !== '#text') {return prev}
  138.       }
  139.     }
  140.     return element;
  141.   },
  142.  
  143.   startMatch: function (match,element) {
  144.     var delim = this.match[match[0]];
  145.     if (delim != null) {
  146.       this.search = {
  147.         end: delim.end, mode: delim.mode,
  148.         open: element, olen: match[0].length,
  149.         opos: this.pattern.lastIndex - match[0].length
  150.       };
  151.       this.switchPattern(delim.pattern);
  152.     }
  153.     return element;
  154.   },
  155.  
  156.   endMatch: function (match,element) {
  157.     if (match[0] == this.search.end) {
  158.       this.search.close = element;
  159.       this.search.cpos = this.pattern.lastIndex;
  160.       this.search.clen = (this.search.isBeginEnd ? 0 : match[0].length);
  161.       this.search.matched = true;
  162.       element = this.encloseMath(element);
  163.       this.switchPattern(this.start);
  164.     }
  165.     return element;
  166.   },
  167.  
  168.   switchPattern: function (pattern) {
  169.     pattern.lastIndex = this.pattern.lastIndex;
  170.     this.pattern = pattern;
  171.     this.search.start = (pattern === this.start);
  172.   },
  173.  
  174.   encloseMath: function (element) {
  175.     var search = this.search, close = search.close, CLOSE, math;
  176.     if (search.cpos === close.length) {close = close.nextSibling}
  177.        else {close = close.splitText(search.cpos)}
  178.     if (!close) {CLOSE = close = MathJax.HTML.addText(search.close.parentNode,"")}
  179.     search.close = close;
  180.     math = (search.opos ? search.open.splitText(search.opos) : search.open);
  181.     while (math.nextSibling && math.nextSibling !== close) {
  182.       if (math.nextSibling.nodeValue !== null) {
  183.         if (math.nextSibling.nodeName === "#comment") {
  184.           math.nodeValue += math.nextSibling.nodeValue.replace(/^\[CDATA\[((.|\n|\r)*)\]\]$/,"$1");
  185.         } else {
  186.           math.nodeValue += math.nextSibling.nodeValue;
  187.         }
  188.       } else if (this.msieNewlineBug) {
  189.         math.nodeValue += (math.nextSibling.nodeName.toLowerCase() === "br" ? "\n" : " ");
  190.       } else {
  191.         math.nodeValue += " ";
  192.       }
  193.       math.parentNode.removeChild(math.nextSibling);
  194.     }
  195.     var AM = math.nodeValue.substr(search.olen,math.nodeValue.length-search.olen-search.clen);
  196.     math.parentNode.removeChild(math);
  197.     if (this.config.preview !== "none") {this.createPreview(search.mode,AM)}
  198.     math = this.createMathTag(search.mode,AM);
  199.     this.search = {}; this.pattern.lastIndex = 0;
  200.     if (CLOSE) {CLOSE.parentNode.removeChild(CLOSE)}
  201.     return math;
  202.   },
  203.  
  204.   insertNode: function (node) {
  205.     var search = this.search;
  206.     search.close.parentNode.insertBefore(node,search.close);
  207.   },
  208.  
  209.   createPreview: function (mode,asciimath) {
  210.     var preview = this.config.preview;
  211.     if (preview === "none") return;
  212.     if (preview === "AsciiMath") {preview = [this.filterPreview(asciimath)]}
  213.     if (preview) {
  214.       preview = MathJax.HTML.Element("span",{className:MathJax.Hub.config.preRemoveClass},preview);
  215.       this.insertNode(preview);
  216.     }
  217.   },
  218.  
  219.   createMathTag: function (mode,asciimath) {
  220.     var script = document.createElement("script");
  221.     script.type = "math/asciimath" + mode;
  222.     MathJax.HTML.setScript(script,asciimath);
  223.     this.insertNode(script);
  224.     return script;
  225.   },
  226.  
  227.   filterPreview: function (asciimath) {return asciimath},
  228.  
  229.   msieNewlineBug: (MathJax.Hub.Browser.isMSIE && (document.documentMode||0) < 9)
  230.  
  231. };
  232.  
  233. // We register the preprocessors with the following priorities:
  234. // - mml2jax.js: 5
  235. // - jsMath2jax.js: 8
  236. // - asciimath2jax.js, tex2jax.js: 10 (default)
  237. // See issues 18 and 484 and the other *2jax.js files.
  238. MathJax.Hub.Register.PreProcessor(["PreProcess",MathJax.Extension.asciimath2jax]);
  239. MathJax.Ajax.loadComplete("[MathJax]/extensions/asciimath2jax.js");

Raw Paste


Login or Register to edit or fork this paste. It's free.