mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Math
synced 2024-12-20 19:32:39 +00:00
310 lines
12 KiB
JavaScript
310 lines
12 KiB
JavaScript
|
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
|
||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||
|
|
||
|
/*************************************************************
|
||
|
*
|
||
|
* MathJax/extensions/MatchWebFonts.js
|
||
|
*
|
||
|
* Adds code to the output jax so that if web fonts are used on the page,
|
||
|
* MathJax will be able to detect their arrival and update the math to
|
||
|
* accommodate the change in font. For the NativeMML output, this works
|
||
|
* both for web fonts in main text, and for web fonts in the math as well.
|
||
|
*
|
||
|
* ---------------------------------------------------------------------
|
||
|
*
|
||
|
* Copyright (c) 2013 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.
|
||
|
*/
|
||
|
|
||
|
(function (HUB,AJAX) {
|
||
|
var VERSION = "2.3";
|
||
|
|
||
|
var CONFIG = MathJax.Hub.CombineConfig("MatchWebFonts",{
|
||
|
matchFor: {
|
||
|
"HTML-CSS": true,
|
||
|
NativeMML: true,
|
||
|
SVG: true
|
||
|
},
|
||
|
fontCheckDelay: 500, // initial delay for the first check for web fonts
|
||
|
fontCheckTimeout: 15 * 1000, // how long to keep looking for fonts (15 seconds)
|
||
|
});
|
||
|
|
||
|
var MATCH = MathJax.Extension.MatchWebFonts = {
|
||
|
version: VERSION,
|
||
|
config: CONFIG
|
||
|
};
|
||
|
|
||
|
HUB.Register.StartupHook("HTML-CSS Jax Ready",function () {
|
||
|
var HTMLCSS = MathJax.OutputJax["HTML-CSS"];
|
||
|
var POSTTRANSLATE = HTMLCSS.postTranslate;
|
||
|
|
||
|
HTMLCSS.Augment({
|
||
|
postTranslate: function (state,partial) {
|
||
|
if (!partial && CONFIG.matchFor["HTML-CSS"] && this.config.matchFontHeight) {
|
||
|
//
|
||
|
// Check for changes in the web fonts that might affect the font
|
||
|
// size for math elements. This is a periodic check that goes on
|
||
|
// until a timeout is reached.
|
||
|
//
|
||
|
AJAX.timer.start(AJAX,["checkFonts",this,state.jax[this.id]],
|
||
|
CONFIG.fontCheckDelay,CONFIG.fontCheckTimeout);
|
||
|
}
|
||
|
return POSTTRANSLATE.apply(this,arguments); // do the original function
|
||
|
},
|
||
|
|
||
|
checkFonts: function (check,scripts) {
|
||
|
if (check.time(function () {})) return;
|
||
|
var size = [], i, m, retry = false;
|
||
|
//
|
||
|
// Add the elements used for testing ex and em sizes
|
||
|
//
|
||
|
for (i = 0, m = scripts.length; i < m; i++) {
|
||
|
script = scripts[i];
|
||
|
if (script.parentNode && script.MathJax.elementJax) {
|
||
|
script.parentNode.insertBefore(this.EmExSpan.cloneNode(true),script);
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// Check to see if anything has changed
|
||
|
//
|
||
|
for (i = 0, m = scripts.length; i < m; i++) {
|
||
|
script = scripts[i]; if (!script.parentNode) continue; retry = true;
|
||
|
var jax = script.MathJax.elementJax; if (!jax) continue;
|
||
|
var span = document.getElementById(jax.inputID+"-Frame");
|
||
|
//
|
||
|
// Check if ex or mex has changed
|
||
|
//
|
||
|
var test = script.previousSibling;
|
||
|
var ex = test.firstChild.offsetHeight/60;
|
||
|
var em = test.lastChild.lastChild.offsetHeight/60;
|
||
|
if (ex === 0 || ex === "NaN") {ex = this.defaultEx; em = this.defaultEm}
|
||
|
if (ex !== jax.HTMLCSS.ex || em !== jax.HTMLCSS.em) {
|
||
|
var scale = ex/this.TeX.x_height/em;
|
||
|
scale = Math.floor(Math.max(this.config.minScaleAdjust/100,scale)*this.config.scale);
|
||
|
if (scale/100 !== jax.scale) {size.push(script); scripts[i] = {}}
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// Remove markers
|
||
|
//
|
||
|
for (i = 0, m = scripts.length; i < m; i++) {
|
||
|
script = scripts[i];
|
||
|
if (script.parentNode && script.MathJax.elementJax) {
|
||
|
script.parentNode.removeChild(script.previousSibling);
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// Rerender the changed items
|
||
|
//
|
||
|
if (size.length) {HUB.Queue(["Rerender",HUB,[size],{}])}
|
||
|
//
|
||
|
// Try again later
|
||
|
//
|
||
|
if (retry) {setTimeout(check,check.delay)}
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
|
||
|
HUB.Register.StartupHook("SVG Jax Ready",function () {
|
||
|
var SVG = MathJax.OutputJax.SVG;
|
||
|
var POSTTRANSLATE = SVG.postTranslate;
|
||
|
|
||
|
SVG.Augment({
|
||
|
postTranslate: function (state,partial) {
|
||
|
if (!partial && CONFIG.matchFor.SVG) {
|
||
|
//
|
||
|
// Check for changes in the web fonts that might affect the font
|
||
|
// size for math elements. This is a periodic check that goes on
|
||
|
// until a timeout is reached.
|
||
|
//
|
||
|
AJAX.timer.start(AJAX,["checkFonts",this,state.jax[this.id]],
|
||
|
CONFIG.fontCheckDelay,CONFIG.fontCheckTimeout);
|
||
|
}
|
||
|
return POSTTRANSLATE.apply(this,arguments); // do the original function
|
||
|
},
|
||
|
|
||
|
checkFonts: function (check,scripts) {
|
||
|
if (check.time(function () {})) return;
|
||
|
var size = [], i, m, retry = false;
|
||
|
//
|
||
|
// Add the elements used for testing ex and em sizes
|
||
|
//
|
||
|
for (i = 0, m = scripts.length; i < m; i++) {
|
||
|
script = scripts[i];
|
||
|
if (script.parentNode && script.MathJax.elementJax) {
|
||
|
script.parentNode.insertBefore(this.ExSpan.cloneNode(true),script);
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// Check to see if anything has changed
|
||
|
//
|
||
|
for (i = 0, m = scripts.length; i < m; i++) {
|
||
|
script = scripts[i]; if (!script.parentNode) continue; retry = true;
|
||
|
var jax = script.MathJax.elementJax; if (!jax) continue;
|
||
|
var span = document.getElementById(jax.inputID+"-Frame");
|
||
|
//
|
||
|
// Check if ex or mex has changed
|
||
|
//
|
||
|
var test = script.previousSibling;
|
||
|
var ex = test.firstChild.offsetHeight/60;
|
||
|
if (ex === 0 || ex === "NaN") {ex = this.defaultEx; em = this.defaultEm}
|
||
|
if (ex !== jax.SVG.ex) {size.push(script); scripts[i] = {}}
|
||
|
}
|
||
|
//
|
||
|
// Remove markers
|
||
|
//
|
||
|
for (i = 0, m = scripts.length; i < m; i++) {
|
||
|
script = scripts[i];
|
||
|
if (script.parentNode && script.MathJax.elementJax) {
|
||
|
script.parentNode.removeChild(script.previousSibling);
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// Rerender the changed items
|
||
|
//
|
||
|
if (size.length) {HUB.Queue(["Rerender",HUB,[size],{}])}
|
||
|
//
|
||
|
// Try again later (if not all the scripts are null)
|
||
|
//
|
||
|
|
||
|
if (retry) setTimeout(check,check.delay);
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
|
||
|
HUB.Register.StartupHook("NativeMML Jax Ready",function () {
|
||
|
var nMML = MathJax.OutputJax.NativeMML;
|
||
|
var POSTTRANSLATE = nMML.postTranslate;
|
||
|
|
||
|
nMML.Augment({
|
||
|
postTranslate: function (state) {
|
||
|
if (!HUB.Browser.isMSIE && CONFIG.matchFor.NativeMML) {
|
||
|
//
|
||
|
// Check for changes in the web fonts that might affect the sizes
|
||
|
// of math elements. This is a periodic check that goes on until
|
||
|
// a timeout is reached.
|
||
|
//
|
||
|
AJAX.timer.start(AJAX,["checkFonts",this,state.jax[this.id]],
|
||
|
CONFIG.fontCheckDelay,CONFIG.fontCheckTimeout);
|
||
|
}
|
||
|
POSTTRANSLATE.apply(this,arguments); // do the original routine
|
||
|
},
|
||
|
|
||
|
//
|
||
|
// Check to see if web fonts have been loaded that change the ex size
|
||
|
// of the surrounding font, the ex size within the math, or the widths
|
||
|
// of math elements. We do this by rechecking the ex and mex sizes
|
||
|
// (to see if the font scaling needs adjusting) and by checking the
|
||
|
// size of the inner mrow of math elements and mtd elements. The
|
||
|
// sizes of these have been stored in the NativeMML object of the
|
||
|
// element jax so that we can check for them here.
|
||
|
//
|
||
|
checkFonts: function (check,scripts) {
|
||
|
if (check.time(function () {})) return;
|
||
|
var adjust = [], mtd = [], size = [], i, m, script;
|
||
|
//
|
||
|
// Add the elements used for testing ex and em sizes
|
||
|
//
|
||
|
for (i = 0, m = scripts.length; i < m; i++) {
|
||
|
script = scripts[i];
|
||
|
if (script.parentNode && script.MathJax.elementJax) {
|
||
|
script.parentNode.insertBefore(this.EmExSpan.cloneNode(true),script);
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// Check to see if anything has changed
|
||
|
//
|
||
|
for (i = 0, m = scripts.length; i < m; i++) {
|
||
|
script = scripts[i]; if (!script.parentNode) continue;
|
||
|
var jax = script.MathJax.elementJax; if (!jax) continue;
|
||
|
var span = document.getElementById(jax.inputID+"-Frame");
|
||
|
var math = span.getElementsByTagName("math")[0]; if (!math) continue;
|
||
|
jax = jax.NativeMML;
|
||
|
//
|
||
|
// Check if ex or mex has changed
|
||
|
//
|
||
|
var test = script.previousSibling;
|
||
|
var ex = test.firstChild.offsetWidth/60;
|
||
|
var mex = test.lastChild.offsetWidth/60;
|
||
|
if (ex === 0 || ex === "NaN") {ex = this.defaultEx; mex = this.defaultMEx}
|
||
|
var newEx = (ex !== jax.ex);
|
||
|
if (newEx || mex != jax.mex) {
|
||
|
var scale = (this.config.matchFontHeight && mex > 1 ? ex/mex : 1);
|
||
|
scale = Math.floor(Math.max(this.config.minScaleAdjust/100,scale) * this.config.scale);
|
||
|
if (scale/100 !== jax.scale) {size.push([span.style,scale])}
|
||
|
jax.scale = scale/100; jax.fontScale = scale+"%"; jax.ex = ex; jax.mex = mex;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check width of math elements
|
||
|
//
|
||
|
if ("scrollWidth" in jax && (newEx || jax.scrollWidth !== math.firstChild.scrollWidth)) {
|
||
|
jax.scrollWidth = math.firstChild.scrollWidth;
|
||
|
adjust.push([math.parentNode.style,jax.scrollWidth/jax.ex/jax.scale]);
|
||
|
}
|
||
|
//
|
||
|
// Check widths of mtd elements
|
||
|
//
|
||
|
if (math.MathJaxMtds) {
|
||
|
for (j = 0, n = math.MathJaxMtds.length; j < n; j++) {
|
||
|
if (!math.MathJaxMtds[j].parentNode) continue;
|
||
|
if (newEx || math.MathJaxMtds[j].firstChild.scrollWidth !== jax.mtds[j]) {
|
||
|
jax.mtds[j] = math.MathJaxMtds[j].firstChild.scrollWidth;
|
||
|
mtd.push([math.MathJaxMtds[j],jax.mtds[j]/jax.ex]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// Remove markers
|
||
|
//
|
||
|
for (i = 0, m = scripts.length; i < m; i++) {
|
||
|
script = scripts[i];
|
||
|
if (script.parentNode && script.MathJax.elementJax) {
|
||
|
script.parentNode.removeChild(script.previousSibling);
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// Adjust scaling factor
|
||
|
//
|
||
|
for (i = 0, m = size.length; i < m; i++) {
|
||
|
size[i][0].fontSize = size[i][1] + "%";
|
||
|
}
|
||
|
//
|
||
|
// Adjust width of spans containing math elements that have changed
|
||
|
//
|
||
|
for (i = 0, m = adjust.length; i < m; i++) {
|
||
|
adjust[i][0].width = adjust[i][1].toFixed(3)+"ex";
|
||
|
}
|
||
|
//
|
||
|
// Adjust widths of mtd elements that have changed
|
||
|
//
|
||
|
for (i = 0, m = mtd.length; i < m; i++) {
|
||
|
var style = mtd[i][0].getAttribute("style");
|
||
|
style = style.replace(/(($|;)\s*min-width:).*?ex/,"$1 "+mtd[i][1].toFixed(3)+"ex");
|
||
|
mtd[i][0].setAttribute("style",style);
|
||
|
}
|
||
|
//
|
||
|
// Try again later
|
||
|
//
|
||
|
setTimeout(check,check.delay);
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
|
||
|
HUB.Startup.signal.Post("MathWebFont Extension Ready");
|
||
|
AJAX.loadComplete("[MathJax]/extensions/MatchWebFonts.js");
|
||
|
|
||
|
})(MathJax.Hub,MathJax.Ajax);
|