Skip to content

Commit

Permalink
Use a function list to make path resolving more flexible, and add a f…
Browse files Browse the repository at this point in the history
…ilter for entities to load the full entity component when MathML input is used. (mathjax/MathJax#2650)
  • Loading branch information
dpvc committed Mar 19, 2021
1 parent 4451bc0 commit 7106c48
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 28 deletions.
10 changes: 10 additions & 0 deletions components/src/input/mml/mml.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,13 @@ if (MathJax.startup) {
MathJax.startup.registerConstructor('mml', MathML);
MathJax.startup.useInput('mml');
}
if (MathJax.loader) {
//
// Install a path-filter to cause loading of an entity file to load all entities,
// since the individual files don't have individual components.
//
MathJax.loader.pathFilters.add((data) => {
data.name = data.name.replace(/\/util\/entities\/.*?\.js/, '/input/mml/entities.js');
return true;
});
}
62 changes: 62 additions & 0 deletions ts/components/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,20 @@ import {Package, PackageError, PackageReady, PackageFailed} from './package.js';
export {Package, PackageError, PackageReady, PackageFailed} from './package.js';
export {MathJaxLibrary} from './global.js';

import {FunctionList} from '../util/FunctionList.js';

/*
* The current directory (for webpack), and the browser document (if any)
*/
declare var __dirname: string;
declare var document: Document;

/**
* Function used to determine path to a given package.
*/
export type PathFilterFunction = (data: {name: string, original: string, addExtension: boolean}) => boolean;
export type PathFilterList = {[name: string]: PathFilterFunction};

/**
* Update the configuration structure to include the loader configuration
*/
Expand Down Expand Up @@ -65,10 +73,53 @@ export interface MathJaxObject extends MJObject {
preLoad: (...names: string[]) => void; // Indicate that packages are already loaded by hand
defaultReady: () => void; // The function performed when all packages are loaded
getRoot: () => string; // Find the root URL for the MathJax files
pathFilters: PathFilterList; // the filters to use for looking for package paths
};
startup?: any;
}

/**
* Functions to used to filter the path to a package
*/
export const PathFilters: {[name: string]: PathFilterFunction} = {
/**
* Look up the path in the configuration's source list
*/
source: (data) => {
if (CONFIG.source.hasOwnProperty(data.name)) {
data.name = CONFIG.source[data.name];
}
return true;
},

/**
* Add [mathjax] before any relative path, and add .js if needed
*/
normalize: (data) => {
const name = data.name;
if (!name.match(/^(?:[a-z]+:\/)?\/|[a-z]:\\|\[/i)) {
data.name = '[mathjax]/' + name.replace(/^\.\//, '');
}
if (data.addExtension && !name.match(/\.[^\/]+$/)) {
data.name += '.js';
}
return true;
},

/**
* Revursively replace path prefixes (e.g., [mathjax], [tex], etc.)
*/
prefix: (data) => {
let match;
while ((match = data.name.match(/^\[([^\]]*)\]/))) {
if (!CONFIG.paths.hasOwnProperty(match[1])) break;
data.name = CONFIG.paths[match[1]] + data.name.substr(match[0].length);
}
return true;
}
};


/**
* The implementation of the dynamic loader
*/
Expand Down Expand Up @@ -157,6 +208,17 @@ export namespace Loader {
return root;
}

/**
* The filters to use to modify the paths used to obtain the packages
*/
export const pathFilters = new FunctionList();

/**
* The default filters to use.
*/
pathFilters.add(PathFilters.source, 1);
pathFilters.add(PathFilters.normalize, 2);
pathFilters.add(PathFilters.prefix, 5);
}

/**
Expand Down
34 changes: 6 additions & 28 deletions ts/components/package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
* @author [email protected] (Davide Cervone)
*/

import {CONFIG} from './loader.js';
import {CONFIG, Loader} from './loader.js';

/*
* The browser document (for creating scripts to load components)
Expand Down Expand Up @@ -61,10 +61,9 @@ export interface PackageConfig {
ready?: PackageReady; // Function to call when package is loaded successfully
failed?: PackageFailed; // Function to call when package fails to load
checkReady?: () => Promise<void>; // Function called to see if package is fully loaded
// (may cause additional packages to load, for example)
// (may cause additional packages to load, for example)
}


/**
* The Package class for handling individual components
*/
Expand Down Expand Up @@ -145,37 +144,16 @@ export class Package {
}

/**
* Compute the path for a package.
*
* First, look for a configured source for the package.
* Then, if the path doesn't look like the start of a URI, or
* an absolute file path, and doesn't have a [path] prefix,
* prepend [mathjax]
* Add .js if there isn't already a file type
* While the path begins with a [path] prefix
* Look for the prefix in the path configuration and
* replace the [path] with the actual path
* (this is done recursively, so paths can refer to other paths)
* return the result
* Compute the path for a package using the loader's path filters
*
* @param {string} name The name of the package to resolve
* @param {boolean} addExtension True if .js should be added automatically
* @return {string} The path (file or URL) for this package
*/
public static resolvePath(name: string, addExtension: boolean = true): string {
let file = CONFIG.source[name] || name;
if (!file.match(/^(?:[a-z]+:\/)?\/|[a-z]:\\|\[/i)) {
file = '[mathjax]/' + file.replace(/^\.\//, '');
}
if (addExtension && !file.match(/\.[^\/]+$/)) {
file += '.js';
}
let match;
while ((match = file.match(/^\[([^\]]*)\]/))) {
if (!CONFIG.paths.hasOwnProperty(match[1])) break;
file = CONFIG.paths[match[1]] + file.substr(match[0].length);
}
return file;
const data = {name, addExtension};
Loader.pathFilters.execute(data);
return data.name;
}

/**
Expand Down

0 comments on commit 7106c48

Please sign in to comment.