diff --git a/Makefile b/Makefile index f96edcca..ba101d56 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ test: ## Run the pure-PHP test suites php tests/QuotesTest.php php tests/RevisionOverridesTest.php php tests/IgnoreHtmlClassTest.php + php tests/JsDefaultsTest.php phpcs: vendor/autoload.php ## parallel-lint + minus-x + phpcs against the MediaWiki coding standard composer test diff --git a/resources/ext.SimpleMathJax.js b/resources/ext.SimpleMathJax.js index d772ce13..c949ff5f 100644 --- a/resources/ext.SimpleMathJax.js +++ b/resources/ext.SimpleMathJax.js @@ -3,6 +3,39 @@ mw.libs.smj = mw.libs.smj || {}; var loaded = false; var scriptLoadPromise = null; +// Defaults match extension.json. The page HTML that carries these settings +// can be cached (CDN, reverse proxy) separately from this module, so after an +// upgrade the two may come from different versions; fall back instead of +// failing to render any formula. +var defaults = { + wgSmjCdnEnabled: true, + wgSmjCdnVersion: '4', + wgSmjDelimitersEnabled: false, + wgSmjDelimitersInlineMath: [], + wgSmjDelimitersDisplayMath: [], + wgSmjIgnoreHtmlClass: 'mathjax_ignore|comment|diff-(context|addedline|deletedline)', + wgSmjScale: 1 +}; + +// Pre-1.0 names of settings that were only renamed (see docs/mig-1.0.md), +// consulted for pages cached before the upgrade. Settings whose meaning or +// default changed in 1.0 (e.g. delimiters) are not mapped. +var legacyNames = { + wgSmjCdnEnabled: 'wgSmjUseCdn' +}; + +function isSet(value) { + return value !== null && value !== undefined; +} + +function config(name) { + var value = mw.config.get(name); + if (!isSet(value) && legacyNames[name]) { + value = mw.config.get(legacyNames[name]); + } + return isSet(value) ? value : defaults[name]; +} + function ensureLoaded() { if (loaded) { return; @@ -10,11 +43,11 @@ function ensureLoaded() { loaded = true; window.MathJax = { tex: { - inlineMath: mw.config.get('wgSmjDelimitersInlineMath').concat([['[math]','[/math]']]), - displayMath: mw.config.get('wgSmjDelimitersDisplayMath'), + inlineMath: config('wgSmjDelimitersInlineMath').concat([['[math]','[/math]']]), + displayMath: config('wgSmjDelimitersDisplayMath'), processEnvironments: true, - processRefs: mw.config.get('wgSmjDelimitersEnabled'), - processEscapes: mw.config.get('wgSmjDelimitersEnabled'), + processRefs: config('wgSmjDelimitersEnabled'), + processEscapes: config('wgSmjDelimitersEnabled'), packages: mw.config.exists('smjPreloadChem') ? {'[+]': ['autoload','mhchem']} : {'[+]': ['autoload']}, macros: { AA: "{\u00c5}", @@ -124,17 +157,17 @@ function ensureLoaded() { } }, options: { - ignoreHtmlClass: mw.config.get('wgSmjIgnoreHtmlClass'), + ignoreHtmlClass: config('wgSmjIgnoreHtmlClass'), processHtmlClass: "mathjax_process|smj-container" }, chtml: { - scale: mw.config.get('wgSmjScale'), + scale: config('wgSmjScale'), }, loader: { load: ['ui/safe','[tex]/autoload'].concat(mw.config.exists('smjPreloadChem') ? ['[tex]/mhchem'] : []) }, startup: { - elements: mw.config.get('wgSmjDelimitersEnabled') ? null : ["span.smj-container"], + elements: config('wgSmjDelimitersEnabled') ? null : ["span.smj-container"], pageReady: () => { return MathJax.startup.defaultPageReady().then(() => { document.querySelectorAll("span.smj-container > .MathJax").forEach((mjx) => { @@ -146,8 +179,8 @@ function ensureLoaded() { }; var script = document.createElement('script'); - script.src = mw.config.get('wgSmjCdnEnabled') - ? 'https://cdn.jsdelivr.net/npm/mathjax@' + mw.config.get('wgSmjCdnVersion') + '/tex-chtml.js' + script.src = config('wgSmjCdnEnabled') + ? 'https://cdn.jsdelivr.net/npm/mathjax@' + config('wgSmjCdnVersion') + '/tex-chtml.js' : mw.config.get('wgExtensionAssetsPath') + '/SimpleMathJax/resources/MathJax/tex-chtml.js'; script.async = true; scriptLoadPromise = new Promise((resolve, reject) => { @@ -183,7 +216,7 @@ mw.hook('wikipage.content').add(function ($content) { return; } var $containers = $content.filter('.smj-container').add($content.find('.smj-container')); - var delimitersEnabled = mw.config.get('wgSmjDelimitersEnabled'); + var delimitersEnabled = config('wgSmjDelimitersEnabled'); if (!delimitersEnabled && !$containers.length) { return; } diff --git a/tests/JsDefaultsTest.php b/tests/JsDefaultsTest.php new file mode 100644 index 00000000..0d61e515 --- /dev/null +++ b/tests/JsDefaultsTest.php @@ -0,0 +1,62 @@ + $value ) { + $key = substr( $name, 2 ); + $expected = $extension['config'][$key]['value'] ?? null; + assert_same( "$name default matches extension.json", $expected, $value ); +} + +// Legacy names are only for settings the migration guide lists as renamed. +if ( preg_match( '/var legacyNames = (\{.*?\});/s', $js, $m ) ) { + preg_match_all( "/(\w+): '(\w+)'/", $m[1], $pairs, PREG_SET_ORDER ); + $guide = file_get_contents( __DIR__ . '/../docs/mig-1.0.md' ); + foreach ( $pairs as [ , $name, $legacy ] ) { + assert_same( "$name has a client default", true, array_key_exists( $name, $defaults ?? [] ) ); + assert_same( + "$legacy -> $name is a rename in docs/mig-1.0.md", + 1, + preg_match( '/\| `\$' . $legacy . '` \| `\$' . $name . '` \|/', $guide ) + ); + } +} + +echo $failures === 0 ? "\nAll tests passed.\n" : "\n$failures test(s) FAILED.\n"; +exit( $failures === 0 ? 0 : 1 );