Skip to content

Commit 30ec141

Browse files
authored
Merge pull request #1080 from mathjax/font-extension-support
Allow tex packages that load font extensions to work better with \require and renderer changes.
2 parents 0d185be + 4c43415 commit 30ec141

File tree

13 files changed

+118
-62
lines changed

13 files changed

+118
-62
lines changed
Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,16 @@
11
import {combineDefaults} from '#js/components/global.js';
22

33
export function fontExtension(id, name, pkg = `@mathjax/${name}`) {
4-
if (MathJax.config?.loader) {
5-
const FONTPATH = (typeof document === 'undefined' ? pkg :
6-
`https://cdn.jsdelivr.net/npm/${name}`);
4+
if (MathJax.loader) {
5+
const FONTPATH = (typeof document === 'undefined' ? pkg : `https://cdn.jsdelivr.net/npm/${name}`);
76
const path = name.replace(/-font-extension$/, '-extension');
87
const extension = name.replace(/-font-extension$/, '');
8+
const jax = (MathJax.config?.startup?.output || 'chtml');
99
combineDefaults(MathJax.config.loader, 'paths', {[path]: FONTPATH});
10-
combineDefaults(MathJax.config.loader, 'dependencies', {
11-
[`[${path}]/chtml`]: ['output/chtml'],
12-
[`[${path}]/svg`]: ['output/svg']
10+
combineDefaults(MathJax.config.loader, 'dependencies', {[`[${path}]/${jax}`]: [`output/${jax}`]});
11+
MathJax.loader.addPackageData(id, {
12+
extraLoads: [`[${path}]/${jax}`],
13+
rendererExtensions: [path]
1314
});
14-
MathJax.config.loader[id] = {
15-
checkReady() {
16-
return MathJax.loader.load(
17-
`[${path}]/${MathJax.config?.startup?.output || 'chtml'}`
18-
).then(() => {
19-
MathJax.startup.document?.outputJax?.addExtension(extension);
20-
});
21-
}
22-
};
2315
}
2416
}

components/mjs/output/chtml/config.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@
55
"output/chtml.ts",
66
"output/chtml",
77
"output/common"
8-
],
9-
"exclude": [
10-
"output/chtml/ts5",
11-
"output/chtml/ts6"
128
]
139
},
1410
"webpack": {

components/mjs/output/chtml/nofont.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ export class DefaultFont extends ChtmlFontData {};
44
export const fontName = 'nofont';
55

66
DefaultFont.OPTIONS = {fontURL: '.'};
7+
8+
export const Font = {fontName, DefaultFont};

components/mjs/output/svg/config.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@
55
"output/svg.ts",
66
"output/svg",
77
"output/common"
8-
],
9-
"exclude": [
10-
"output/svg/ts5",
11-
"output/svg/ts6"
128
]
139
},
1410
"webpack": {

components/mjs/output/svg/nofont.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@ import {SvgFontData} from '#js/output/svg/FontData.js';
22

33
export class DefaultFont extends SvgFontData {};
44
export const fontName = 'nofont';
5+
6+
export const Font = {fontName, DefaultFont};

components/mjs/output/util.js

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,15 @@ export const OutputUtil = {
3131

3232
if (name !== defaultFont) {
3333

34-
combineDefaults(MathJax.config.loader, `output/${jax}`, {
35-
checkReady() {
36-
return MathJax.loader.load(`${font}/${jax}`).catch(err => console.log(err));
37-
}
38-
});
34+
MathJax.loader.addPackageData(`output/${jax}`, {extraLoads: [`${font}/${jax}`]});
3935

4036
} else {
4137

38+
const extraLoads = MathJax.config.loader[`${font}/${jax}`]?.extraLoads;
39+
if (extraLoads) {
40+
MathJax.loader.addPackageData(`output/${jax}`, {extraLoads});
41+
}
42+
4243
combineWithMathJax({_: {
4344
output: {
4445
fonts: {
@@ -78,14 +79,12 @@ export const OutputUtil = {
7879

7980
loadFont(startup, jax, font, preload) {
8081
if (!MathJax.loader) {
81-
return Promise.resolve();
82+
return startup;
8283
}
8384
if (preload) {
8485
MathJax.loader.preLoad(`[${font}]/${jax}`);
8586
}
86-
const check = MathJax.config.loader[`output/${jax}`];
87-
const start = (check && check.checkReady ? check.checkReady().then(startup) : startup());
88-
return start.catch(err => console.log(err));
87+
return Package.loadPromise(`output/${jax}`).then(startup);
8988
}
9089

9190
};

ts/components/loader.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
import {MathJax as MJGlobal, MathJaxObject as MJObject, MathJaxLibrary,
2727
MathJaxConfig as MJConfig, combineWithMathJax, combineDefaults} from './global.js';
28-
import {Package, PackageError, PackageReady, PackageFailed} from './package.js';
28+
import {Package, PackageError, PackageReady, PackageFailed, PackageConfig} from './package.js';
2929
import {FunctionList} from '../util/FunctionList.js';
3030
import {mjxRoot} from '#root/root.js';
3131

@@ -73,7 +73,8 @@ export interface MathJaxObject extends MJObject {
7373
getRoot: () => string; // Find the root URL for the MathJax files
7474
checkVersion: (name: string, version: string) => boolean; // Check the version of an extension
7575
saveVersion: (name: string) => void; // Set the version for a combined component
76-
pathFilters: FunctionList; // the filters to use for looking for package paths
76+
pathFilters: FunctionList; // The filters to use for looking for package paths
77+
addPackageData: (name: string, data: PackageConfig) => void; // Add more package data for a package
7778
};
7879
startup?: any;
7980
}
@@ -199,6 +200,30 @@ export namespace Loader {
199200
}
200201
}
201202

203+
/**
204+
* Insert options into a package configuration
205+
*
206+
* @param {string} name The package whose configuration is being augmented
207+
* @param {PackageConfig} data The extra configuraiton information to add
208+
*/
209+
export function addPackageData(name: string, data: PackageConfig) {
210+
let config = CONFIG[name];
211+
if (!config) {
212+
config = CONFIG[name] = {};
213+
}
214+
for (const [key, value] of Object.entries(data)) {
215+
if (Array.isArray(value)) {
216+
if (!config[key]) {
217+
config[key] = [];
218+
}
219+
const set = new Set([...config[key], ...value]);
220+
config[key] = [...set];
221+
} else {
222+
config[key] = value;
223+
}
224+
}
225+
}
226+
202227
/**
203228
* The default function to perform when all the packages are loaded
204229
*/

ts/components/package.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ export interface PackageConfig {
6262
failed?: PackageFailed; // Function to call when package fails to load
6363
checkReady?: () => Promise<void>; // Function called to see if package is fully loaded
6464
// (may cause additional packages to load, for example)
65+
extraLoads?: string[]; // Extra packages to load after this one
66+
rendererExtensions?: string[]; // Font extensions to load when renderer changes
6567
}
6668

6769
/**
@@ -143,6 +145,16 @@ export class Package {
143145
return this.dependencyCount === 0 && !this.noLoad && !this.isLoading && !this.hasFailed;
144146
}
145147

148+
/**
149+
* @param {string} name A promise for when extra files and checkReady have been fulfilled
150+
*/
151+
public static loadPromise(name: string): Promise<void> {
152+
const config = (CONFIG[name] || {}) as PackageConfig;
153+
const promise = Promise.all((config.extraLoads || []).map((name) => Loader.load(name)));
154+
const checkReady = config.checkReady || (() => Promise.resolve());
155+
return promise.then(() => checkReady()) as Promise<void>;
156+
}
157+
146158
/**
147159
* Compute the path for a package using the loader's path filters
148160
*
@@ -344,18 +356,16 @@ export class Package {
344356
/**
345357
* Check if a package is really ready to be marked as loaded
346358
* (When it is loaded, it may set its own checkReady() function
347-
* as a means of loading additional packages. E.g., an output
348-
* jax may load a font package, dependent on its configuration.)
359+
* or extraLoads array as a means of loading additional packages.
360+
* E.g., an output jax may load a font package, dependent on its
361+
* configuration.)
349362
*
350363
* The configuration's checkReady() function returns a promise
351364
* that allows the loader to wait for addition actions to finish
352365
* before marking the file as loaded (or failing to load).
353366
*/
354367
protected checkLoad() {
355-
const config = (CONFIG[this.name] || {}) as PackageConfig;
356-
const checkReady = config.checkReady || (() => Promise.resolve());
357-
checkReady().then(() => this.loaded())
358-
.catch((message) => this.failed(message));
368+
Package.loadPromise(this.name).then(() => this.loaded()).catch((message) => this.failed(message));
359369
}
360370

361371
/**

ts/input/tex/require/RequireConfiguration.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,12 @@ import {ParseMethod} from '../Types.js';
3131
import TexError from '../TexError.js';
3232
import {TeX} from '../../tex.js';
3333

34-
import {MathJax} from '../../../components/global.js';
34+
import {MathJax} from '../../../components/startup.js';
3535
import {Package} from '../../../components/package.js';
3636
import {Loader, CONFIG as LOADERCONFIG} from '../../../components/loader.js';
3737
import {mathjax} from '../../../mathjax.js';
3838
import {expandable} from '../../../util/Options.js';
39+
import {MenuMathDocument} from '../../../ui/menu/MenuHandler.js';
3940

4041
/**
4142
* The MathJax configuration block (for looking up user-defined package options)
@@ -149,11 +150,12 @@ export function RequireLoad(parser: TexParser, name: string) {
149150
if (!allowed) {
150151
throw new TexError('BadRequire', 'Extension "%1" is not allowed to be loaded', extension);
151152
}
152-
if (Package.packages.has(extension)) {
153-
RegisterExtension(parser.configuration.packageData.get('require').jax, extension);
154-
} else {
153+
if (!Package.packages.has(extension)) {
155154
mathjax.retryAfter(Loader.load(extension));
156155
}
156+
const require = LOADERCONFIG[extension]?.rendererExtensions;
157+
(MathJax.startup.document as MenuMathDocument)?.menu?.addRequiredExtensions?.(require);
158+
RegisterExtension(parser.configuration.packageData.get('require').jax, extension);
157159
}
158160

159161
/**

ts/output/chtml.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import {MathItem} from '../core/MathItem.js';
3131
import {ChtmlWrapper, ChtmlWrapperClass} from './chtml/Wrapper.js';
3232
import {ChtmlWrapperFactory} from './chtml/WrapperFactory.js';
3333
import {ChtmlCharOptions, ChtmlVariantData, ChtmlDelimiterData,
34-
ChtmlFontData, ChtmlFontDataClass} from './chtml/FontData.js';
34+
ChtmlFontData, ChtmlFontDataClass, FontExtensionData} from './chtml/FontData.js';
3535
import {Usage} from './chtml/Usage.js';
3636
import * as LENGTHS from '../util/lengths.js';
3737
import {unicodeChars} from '../util/string.js';
@@ -165,8 +165,11 @@ CommonOutputJax<
165165
/**
166166
* @override
167167
*/
168-
public addExtension(name: string): string[] {
169-
const css = super.addExtension(name);
168+
public addExtension(
169+
font: FontExtensionData<ChtmlCharOptions, ChtmlDelimiterData>,
170+
prefix: string = ''
171+
): string[] {
172+
const css = super.addExtension(font, prefix);
170173
if (css.length && this.options.adaptiveCSS && this.chtmlStyles) {
171174
this.adaptor.insertRules(this.chtmlStyles, css);
172175
}

0 commit comments

Comments
 (0)