Skip to content

Commit

Permalink
Merge pull request #765 from mathjax/issue2718
Browse files Browse the repository at this point in the history
Move mml3 filter to an mmlFilter so that forceReparse isn't needed. (mathjax/MathJax#2718)
  • Loading branch information
dpvc authored Feb 2, 2022
2 parents 463cec3 + 118a1c1 commit d3f6a09
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 29 deletions.
2 changes: 1 addition & 1 deletion ts/input/mathml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export class MathML<N, T, D> extends AbstractInputJax<N, T, D> {
/**
* A list of functions to call on the parsed MathML DOM before conversion to internal structure
*/
protected mmlFilters: FunctionList;
public mmlFilters: FunctionList;

/**
* @override
Expand Down
25 changes: 17 additions & 8 deletions ts/input/mathml/mml3/mml3-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,19 @@
* @author dpvc@mathjax.org (Davide Cervone)
*/

import {MathDocument} from '../../../core/MathDocument.js';

/**
* Create the transform function that uses Saxon-js to perform the
* xslt transformation.
*
* @return {(mml: string) => string)} The transformation function
* @template N The HTMLElement node class
* @template T The Text node class
* @template D The Document class
*
* @return {(node: N, doc: MathDocument<N,T,D>) => N)} The transformation function
*/
export function createTransform(): (mml: string) => string {
export function createTransform<N, T, D>(): (node: N, doc: MathDocument<N, T, D>) => N {
/* tslint:disable-next-line:no-eval */
const nodeRequire = eval('require'); // get the actual require from node.
/* tslint:disable-next-line:no-eval */
Expand All @@ -43,24 +49,27 @@ export function createTransform(): (mml: string) => string {
const fs = nodeRequire('fs'); // use the real version from node.
const xsltFile = path.resolve(dirname, 'mml3.sef.json'); // load the preprocessed stylesheet.
const xslt = JSON.parse(fs.readFileSync(xsltFile)); // and parse it.
return (mml: string) => {
return (node: N, doc: MathDocument<N, T, D>) => {
const adaptor = doc.adaptor;
let mml = adaptor.outerHTML(node);
//
// Make sure the namespace is present
//
if (!mml.match(/ xmlns[=:]/)) {
mml = mml.replace(/<(?:(\w+)(:))?math/, '<$1$2math xmlns$2$1="http://www.w3.org/1998/Math/MathML"');
mml = mml.replace(/<(?:(\w+)(:))?math/, '<$1$2math xmlns$2$1="http://www.w3.org/1998/Math/MathML"');
}
let result;
//
// Try to run the transform, and if it fails, return the original MathML
//
let result;
try {
result = Saxon.transform({
result = adaptor.firstChild(adaptor.body(adaptor.parse(Saxon.transform({
stylesheetInternal: xslt,
sourceText: mml,
destination: 'serialized'
}).principalResult;
}).principalResult))) as N;
} catch (err) {
result = mml;
result = node;
}
return result;
};
Expand Down
52 changes: 32 additions & 20 deletions ts/input/mathml/mml3/mml3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,17 @@ import {MathDocument} from '../../../core/MathDocument.js';
import {Handler} from '../../../core/Handler.js';
import {OptionList} from '../../../util/Options.js';
import {createTransform} from './mml3-node.js';
import {MathML} from '../../mathml.js';


/**
* The data for a MathML prefilter.
*
* @template N The HTMLElement node class
* @template T The Text node class
* @template D The Document class
*/
export type FILTERDATA<N, T, D> = {math: MathItem<N, T, D>, document: MathDocument<N, T, D>, data: string};
export type FILTERDATA<N, T, D> = {math: MathItem<N, T, D>, document: MathDocument<N, T, D>, data: N};

/**
* Class that handles XSLT transform for MathML3 elementary math tags.
Expand All @@ -48,7 +53,7 @@ export class Mml3<N, T, D> {
* The function to convert serialized MathML using the XSLT.
* (Different for browser and node environments.)
*/
protected transform: (xml: string) => string;
protected transform: (node: N, doc: MathDocument<N, T, D>) => N;

/**
* @param {MathDocument} document The MathDocument for the transformation
Expand All @@ -67,22 +72,23 @@ export class Mml3<N, T, D> {
const processor = new XSLTProcessor();
const parsed = document.adaptor.parse(Mml3.XSLT, 'text/xml') as any as Node;
processor.importStylesheet(parsed);
this.transform = (mml: string) => {
const adaptor = document.adaptor;
const parsed = adaptor.parse(mml) as any as Node;
const xml = processor.transformToDocument(parsed) as any as D;
return adaptor.serializeXML(adaptor.body(xml));
this.transform = (node: N) => {
const div = document.adaptor.node('div', {}, [document.adaptor.clone(node)]);
const mml = processor.transformToDocument(div as any as Node) as any as N;
return document.adaptor.firstChild(mml) as N;
};
}
}

/**
* The prefilter for the MathML input jax
* The mathml filter for the MathML input jax
*
* @param {FILTERDATA} args The data from the pre-filter chain.
*/
public preFilter(args: FILTERDATA<N, T, D>) {
args.data = this.transform(args.data);
public mmlFilter(args: FILTERDATA<N, T, D>) {
if (args.document.options.enableMml3) {
args.data = this.transform(args.data, args.document);
}
}

}
Expand All @@ -92,6 +98,15 @@ export class Mml3<N, T, D> {
*/
export function Mml3Handler<N, T, D>(handler: Handler<N, T, D>): Handler<N, T, D> {
handler.documentClass = class extends handler.documentClass {

/**
* @override
*/
public static OPTIONS: OptionList = {
...handler.documentClass.OPTIONS,
enableMml3: true,
};

/**
* Add a prefilter to the MathML input jax, if there is one.
*
Expand All @@ -100,17 +115,14 @@ export function Mml3Handler<N, T, D>(handler: Handler<N, T, D>): Handler<N, T, D
*/
constructor(...args: any[]) {
super(...args);
const options = args[2] as OptionList;
if (options.InputJax) {
for (const jax of options.InputJax) {
if (jax.name === 'MathML') {
if (!jax.options._mml3) { // prevent filter being added twice (e.g., when a11y tools load)
const mml3 = new Mml3(this);
jax.preFilters.add(mml3.preFilter.bind(mml3));
jax.options._mml3 = true;
}
break;
for (const jax of this.inputJax || []) {
if (jax.name === 'MathML') {
if (!jax.options._mml3) { // prevent filter being added twice (e.g., when a11y tools load)
const mml3 = new Mml3(this);
(jax as MathML<N, T, D>).mmlFilters.add(mml3.mmlFilter.bind(mml3));
jax.options._mml3 = true;
}
break;
}
}
}
Expand Down

0 comments on commit d3f6a09

Please sign in to comment.