JAVASCRIPT   15

MatchWebFonts js

Guest on 2nd August 2022 03:48:58 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/MatchWebFonts.js
  7.  *  
  8.  *  Adds code to the output jax so that if web fonts are used on the page,
  9.  *  MathJax will be able to detect their arrival and update the math to
  10.  *  accommodate the change in font.  For the NativeMML output, this works
  11.  *  both for web fonts in main text, and for web fonts in the math as well.
  12.  *
  13.  *  ---------------------------------------------------------------------
  14.  *  
  15.  *  Copyright (c)  The MathJax Consortium
  16.  *
  17.  *  Licensed under the Apache License, Version 2.0 (the "License");
  18.  *  you may not use this file except in compliance with the License.
  19.  *  You may obtain a copy of the License at
  20.  *
  21.  *      http://www.apache.org/licenses/LICENSE-2.0
  22.  *
  23.  *  Unless required by applicable law or agreed to in writing, software
  24.  *  distributed under the License is distributed on an "AS IS" BASIS,
  25.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  26.  *  See the License for the specific language governing permissions and
  27.  *  limitations under the License.
  28.  */
  29.  
  30. (function (HUB,AJAX) {
  31.   var VERSION = "2.6.0";
  32.  
  33.   var CONFIG = MathJax.Hub.CombineConfig("MatchWebFonts",{
  34.     matchFor: {
  35.       "HTML-CSS": true,
  36.       NativeMML: true,
  37.       SVG: true
  38.     },
  39.     fontCheckDelay: 500,          // initial delay for the first check for web fonts
  40.     fontCheckTimeout: 15 * 1000,  // how long to keep looking for fonts (15 seconds)
  41.   });
  42.  
  43.   MathJax.Extension.MatchWebFonts = {
  44.     version: VERSION,
  45.     config: CONFIG
  46.   };
  47.  
  48.   HUB.Register.StartupHook("HTML-CSS Jax Ready",function () {
  49.     var HTMLCSS = MathJax.OutputJax["HTML-CSS"];
  50.     var POSTTRANSLATE = HTMLCSS.postTranslate;
  51.  
  52.     HTMLCSS.Augment({
  53.       postTranslate: function (state,partial) {
  54.         if (!partial && CONFIG.matchFor["HTML-CSS"] && this.config.matchFontHeight) {
  55.           //
  56.           //  Check for changes in the web fonts that might affect the font
  57.           //  size for math elements.  This is a periodic check that goes on
  58.           //  until a timeout is reached.
  59.           //
  60.           AJAX.timer.start(AJAX,["checkFonts",this,state.jax[this.id]],
  61.                            CONFIG.fontCheckDelay,CONFIG.fontCheckTimeout);
  62.         }
  63.         return POSTTRANSLATE.apply(this,arguments); // do the original function
  64.       },
  65.      
  66.       checkFonts: function (check,scripts) {
  67.         if (check.time(function () {})) return;
  68.         var size = [], i, m, retry = false;
  69.         //
  70.         //  Add the elements used for testing ex and em sizes
  71.         //
  72.         for (i = 0, m = scripts.length; i < m; i++) {
  73.           script = scripts[i];
  74.           if (script.parentNode && script.MathJax.elementJax) {
  75.             script.parentNode.insertBefore(this.EmExSpan.cloneNode(true),script);
  76.           }
  77.         }
  78.         //
  79.         //  Check to see if anything has changed
  80.         //
  81.         for (i = 0, m = scripts.length; i < m; i++) {
  82.           script = scripts[i]; if (!script.parentNode) continue; retry = true;
  83.           var jax = script.MathJax.elementJax; if (!jax) continue;
  84.           //
  85.           //  Check if ex or mex has changed
  86.           //
  87.           var test = script.previousSibling;
  88.           var ex = test.firstChild.offsetHeight/60;
  89.           var em = test.lastChild.lastChild.offsetHeight/60;
  90.           if (ex === 0 || ex === "NaN") {ex = this.defaultEx; em = this.defaultEm}
  91.           if (ex !== jax.HTMLCSS.ex || em !== jax.HTMLCSS.em) {
  92.             var scale = ex/this.TeX.x_height/em;
  93.             scale = Math.floor(Math.max(this.config.minScaleAdjust/100,scale)*this.config.scale);
  94.             if (scale/100 !== jax.scale) {size.push(script); scripts[i] = {}}
  95.           }
  96.         }
  97.         //
  98.         //  Remove markers
  99.         //
  100.         scripts = scripts.concat(size);  // some scripts have been moved to the size array
  101.         for (i = 0, m = scripts.length; i < m; i++) {
  102.           script = scripts[i];
  103.           if (script && script.parentNode && script.MathJax.elementJax) {
  104.             script.parentNode.removeChild(script.previousSibling);
  105.           }
  106.         }
  107.         //
  108.         //  Rerender the changed items
  109.         //
  110.         if (size.length) {HUB.Queue(["Rerender",HUB,[size],{}])}
  111.         //
  112.         //  Try again later
  113.         //
  114.         if (retry) {setTimeout(check,check.delay)}
  115.       }
  116.     });
  117.   });
  118.  
  119.   HUB.Register.StartupHook("SVG Jax Ready",function () {
  120.     var SVG = MathJax.OutputJax.SVG;
  121.     var POSTTRANSLATE = SVG.postTranslate;
  122.  
  123.     SVG.Augment({
  124.       postTranslate: function (state,partial) {
  125.         if (!partial && CONFIG.matchFor.SVG) {
  126.           //
  127.           //  Check for changes in the web fonts that might affect the font
  128.           //  size for math elements.  This is a periodic check that goes on
  129.           //  until a timeout is reached.
  130.           //
  131.           AJAX.timer.start(AJAX,["checkFonts",this,state.jax[this.id]],
  132.                            CONFIG.fontCheckDelay,CONFIG.fontCheckTimeout);
  133.         }
  134.         return POSTTRANSLATE.apply(this,arguments); // do the original function
  135.       },
  136.      
  137.       checkFonts: function (check,scripts) {
  138.         if (check.time(function () {})) return;
  139.         var size = [], i, m, retry = false;
  140.         //
  141.         //  Add the elements used for testing ex and em sizes
  142.         //
  143.         for (i = 0, m = scripts.length; i < m; i++) {
  144.           script = scripts[i];
  145.           if (script.parentNode && script.MathJax.elementJax) {
  146.             script.parentNode.insertBefore(this.ExSpan.cloneNode(true),script);
  147.           }
  148.         }
  149.         //
  150.         //  Check to see if anything has changed
  151.         //
  152.         for (i = 0, m = scripts.length; i < m; i++) {
  153.           script = scripts[i]; if (!script.parentNode) continue; retry = true;
  154.           var jax = script.MathJax.elementJax; if (!jax) continue;
  155.           //
  156.           //  Check if ex or mex has changed
  157.           //
  158.           var test = script.previousSibling;
  159.           var ex = test.firstChild.offsetHeight/60;
  160.           if (ex === 0 || ex === "NaN") {ex = this.defaultEx}
  161.           if (ex !== jax.SVG.ex) {size.push(script); scripts[i] = {}}
  162.         }
  163.         //
  164.         //  Remove markers
  165.         //
  166.         scripts = scripts.concat(size);  // some scripts have been moved to the size array
  167.         for (i = 0, m = scripts.length; i < m; i++) {
  168.           script = scripts[i];
  169.           if (script.parentNode && script.MathJax.elementJax) {
  170.             script.parentNode.removeChild(script.previousSibling);
  171.           }
  172.         }
  173.         //
  174.         //  Rerender the changed items
  175.         //
  176.         if (size.length) {HUB.Queue(["Rerender",HUB,[size],{}])}
  177.         //
  178.         //  Try again later (if not all the scripts are null)
  179.         //
  180.  
  181.         if (retry) setTimeout(check,check.delay);
  182.       }
  183.     });
  184.   });
  185.  
  186.   HUB.Register.StartupHook("NativeMML Jax Ready",function () {
  187.     var nMML = MathJax.OutputJax.NativeMML;
  188.     var POSTTRANSLATE = nMML.postTranslate;
  189.    
  190.     nMML.Augment({
  191.       postTranslate: function (state) {
  192.         if (!HUB.Browser.isMSIE && CONFIG.matchFor.NativeMML) {
  193.           //
  194.           //  Check for changes in the web fonts that might affect the sizes
  195.           //  of math elements.  This is a periodic check that goes on until
  196.           //  a timeout is reached.
  197.           //
  198.           AJAX.timer.start(AJAX,["checkFonts",this,state.jax[this.id]],
  199.                            CONFIG.fontCheckDelay,CONFIG.fontCheckTimeout);
  200.         }
  201.         POSTTRANSLATE.apply(this,arguments); // do the original routine
  202.       },
  203.      
  204.       //
  205.       //  Check to see if web fonts have been loaded that change the ex size
  206.       //  of the surrounding font, the ex size within the math, or the widths
  207.       //  of math elements.  We do this by rechecking the ex and mex sizes
  208.       //  (to see if the font scaling needs adjusting) and by checking the
  209.       //  size of the inner mrow of math elements and mtd elements.  The
  210.       //  sizes of these have been stored in the NativeMML object of the
  211.       //  element jax so that we can check for them here.
  212.       //
  213.       checkFonts: function (check,scripts) {
  214.         if (check.time(function () {})) return;
  215.         var adjust = [], mtd = [], size = [], i, m, script;
  216.         //
  217.         //  Add the elements used for testing ex and em sizes
  218.         //
  219.         for (i = 0, m = scripts.length; i < m; i++) {
  220.           script = scripts[i];
  221.           if (script.parentNode && script.MathJax.elementJax) {
  222.             script.parentNode.insertBefore(this.EmExSpan.cloneNode(true),script);
  223.           }
  224.         }
  225.         //
  226.         //  Check to see if anything has changed
  227.         //
  228.         for (i = 0, m = scripts.length; i < m; i++) {
  229.           script = scripts[i]; if (!script.parentNode) continue;
  230.           var jax = script.MathJax.elementJax; if (!jax) continue;
  231.           var span = document.getElementById(jax.inputID+"-Frame");
  232.           var math = span.getElementsByTagName("math")[0]; if (!math) continue;
  233.           jax = jax.NativeMML;
  234.           //
  235.           //  Check if ex or mex has changed
  236.           //
  237.           var test = script.previousSibling;
  238.           var ex = test.firstChild.offsetWidth/60;
  239.           var mex = test.lastChild.offsetWidth/60;
  240.           if (ex === 0 || ex === "NaN") {ex = this.defaultEx; mex = this.defaultMEx}
  241.           var newEx = (ex !== jax.ex);
  242.           if (newEx || mex != jax.mex) {
  243.             var scale = (this.config.matchFontHeight && mex > 1 ? ex/mex : 1);
  244.             scale = Math.floor(Math.max(this.config.minScaleAdjust/100,scale) * this.config.scale);
  245.             if (scale/100 !== jax.scale) {size.push([span.style,scale])}
  246.             jax.scale = scale/100; jax.fontScale = scale+"%"; jax.ex = ex; jax.mex = mex;
  247.           }
  248.          
  249.           //
  250.           //  Check width of math elements
  251.           //
  252.           if ("scrollWidth" in jax && (newEx || jax.scrollWidth !== math.firstChild.scrollWidth)) {
  253.             jax.scrollWidth = math.firstChild.scrollWidth;
  254.             adjust.push([math.parentNode.style,jax.scrollWidth/jax.ex/jax.scale]);
  255.           }
  256.           //
  257.           //  Check widths of mtd elements
  258.           //
  259.           if (math.MathJaxMtds) {
  260.             for (var j = 0, n = math.MathJaxMtds.length; j < n; j++) {
  261.               if (!math.MathJaxMtds[j].parentNode) continue;
  262.               if (newEx || math.MathJaxMtds[j].firstChild.scrollWidth !== jax.mtds[j]) {
  263.                 jax.mtds[j] = math.MathJaxMtds[j].firstChild.scrollWidth;
  264.                 mtd.push([math.MathJaxMtds[j],jax.mtds[j]/jax.ex]);
  265.               }
  266.             }
  267.           }
  268.         }
  269.         //
  270.         //  Remove markers
  271.         //
  272.         for (i = 0, m = scripts.length; i < m; i++) {
  273.           script = scripts[i];
  274.           if (script.parentNode && script.MathJax.elementJax) {
  275.             script.parentNode.removeChild(script.previousSibling);
  276.           }
  277.         }
  278.         //
  279.         //  Adjust scaling factor
  280.         //
  281.         for (i = 0, m = size.length; i < m; i++) {
  282.           size[i][0].fontSize = size[i][1] + "%";
  283.         }
  284.         //
  285.         //  Adjust width of spans containing math elements that have changed
  286.         //
  287.         for (i = 0, m = adjust.length; i < m; i++) {
  288.           adjust[i][0].width = adjust[i][1].toFixed(3)+"ex";
  289.         }
  290.         //
  291.         //  Adjust widths of mtd elements that have changed
  292.         //
  293.         for (i = 0, m = mtd.length; i < m; i++) {
  294.           var style = mtd[i][0].getAttribute("style");
  295.           style = style.replace(/(($|;)\s*min-width:).*?ex/,"$1 "+mtd[i][1].toFixed(3)+"ex");
  296.           mtd[i][0].setAttribute("style",style);
  297.         }
  298.         //
  299.         //  Try again later
  300.         //
  301.         setTimeout(check,check.delay);
  302.       }
  303.     });
  304.   });
  305.  
  306.   HUB.Startup.signal.Post("MatchWebFonts Extension Ready");
  307.   AJAX.loadComplete("[MathJax]/extensions/MatchWebFonts.js");
  308.  
  309. })(MathJax.Hub,MathJax.Ajax);

Raw Paste


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