stuff
This commit is contained in:
parent
bc92231240
commit
b8225c639e
11904 changed files with 1472749 additions and 133 deletions
130
node_modules/mathjax-full/ts/input/mathml/FindMathML.ts
generated
vendored
Normal file
130
node_modules/mathjax-full/ts/input/mathml/FindMathML.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
/*************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2022 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Implements the MathML version of the FindMath object
|
||||
*
|
||||
* @author dpvc@mathjax.org (Davide Cervone)
|
||||
*/
|
||||
|
||||
import {AbstractFindMath} from '../../core/FindMath.js';
|
||||
import {DOMAdaptor} from '../../core/DOMAdaptor.js';
|
||||
import {OptionList} from '../../util/Options.js';
|
||||
import {ProtoItem} from '../../core/MathItem.js';
|
||||
|
||||
/**
|
||||
* The MathML namespace
|
||||
*/
|
||||
const NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
|
||||
|
||||
|
||||
/*****************************************************************/
|
||||
/**
|
||||
* Implements the FindMathML object (extends AbstractFindMath)
|
||||
*
|
||||
* @template N The HTMLElement node class
|
||||
* @template T The Text node class
|
||||
* @template D The Document class
|
||||
*/
|
||||
export class FindMathML<N, T, D> extends AbstractFindMath<N, T, D> {
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
public static OPTIONS: OptionList = {};
|
||||
|
||||
/**
|
||||
* The DOMAdaptor for the document being processed
|
||||
*/
|
||||
public adaptor: DOMAdaptor<N, T, D>;
|
||||
|
||||
/**
|
||||
* Locates math nodes, possibly with namespace prefixes.
|
||||
* Store them in a set so that if found more than once, they will only
|
||||
* appear in the list once.
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
public findMath(node: N) {
|
||||
let set = new Set<N>();
|
||||
this.findMathNodes(node, set);
|
||||
this.findMathPrefixed(node, set);
|
||||
const html = this.adaptor.root(this.adaptor.document);
|
||||
if (this.adaptor.kind(html) === 'html' && set.size === 0) {
|
||||
this.findMathNS(node, set);
|
||||
}
|
||||
return this.processMath(set);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find plain <math> tags
|
||||
*
|
||||
* @param {N} node The container to seaerch for math
|
||||
* @param {Set<N>} set The set in which to store the math nodes
|
||||
*/
|
||||
protected findMathNodes(node: N, set: Set<N>) {
|
||||
for (const math of this.adaptor.tags(node, 'math')) {
|
||||
set.add(math);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find <m:math> tags (or whatever prefixes there are)
|
||||
*
|
||||
* @param {N} node The container to seaerch for math
|
||||
* @param {NodeSet} set The set in which to store the math nodes
|
||||
*/
|
||||
protected findMathPrefixed(node: N, set: Set<N>) {
|
||||
let html = this.adaptor.root(this.adaptor.document);
|
||||
for (const attr of this.adaptor.allAttributes(html)) {
|
||||
if (attr.name.substr(0, 6) === 'xmlns:' && attr.value === NAMESPACE) {
|
||||
let prefix = attr.name.substr(6);
|
||||
for (const math of this.adaptor.tags(node, prefix + ':math')) {
|
||||
set.add(math);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find namespaced math in XHTML documents (is this really needed?)
|
||||
*
|
||||
* @param {N} node The container to seaerch for math
|
||||
* @param {NodeSet} set The set in which to store the math nodes
|
||||
*/
|
||||
protected findMathNS(node: N, set: Set<N>) {
|
||||
for (const math of this.adaptor.tags(node, 'math', NAMESPACE)) {
|
||||
set.add(math);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce the array of proto math items from the node set
|
||||
*/
|
||||
protected processMath(set: Set<N>) {
|
||||
let math: ProtoItem<N, T>[] = [];
|
||||
for (const mml of Array.from(set)) {
|
||||
let display = (this.adaptor.getAttribute(mml, 'display') === 'block' ||
|
||||
this.adaptor.getAttribute(mml, 'mode') === 'display');
|
||||
let start = {node: mml, n: 0, delim: ''};
|
||||
let end = {node: mml, n: 0, delim: ''};
|
||||
math.push({math: this.adaptor.outerHTML(mml), start, end, display});
|
||||
}
|
||||
return math;
|
||||
}
|
||||
|
||||
}
|
||||
336
node_modules/mathjax-full/ts/input/mathml/MathMLCompile.ts
generated
vendored
Normal file
336
node_modules/mathjax-full/ts/input/mathml/MathMLCompile.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,336 @@
|
|||
/*************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2022 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Implementation of the Compile function for the MathML input jax
|
||||
*
|
||||
* @author dpvc@mathjax.org (Davide Cervone)
|
||||
*/
|
||||
|
||||
import {MmlFactory} from '../../core/MmlTree/MmlFactory.js';
|
||||
import {MmlNode, TextNode, XMLNode, AbstractMmlNode, AbstractMmlTokenNode, TEXCLASS}
|
||||
from '../../core/MmlTree/MmlNode.js';
|
||||
import {userOptions, defaultOptions, OptionList} from '../../util/Options.js';
|
||||
import * as Entities from '../../util/Entities.js';
|
||||
import {DOMAdaptor} from '../../core/DOMAdaptor.js';
|
||||
|
||||
/********************************************************************/
|
||||
/**
|
||||
* The class for performing the MathML DOM node to
|
||||
* internal MmlNode conversion.
|
||||
*
|
||||
* @template N The HTMLElement node class
|
||||
* @template T The Text node class
|
||||
* @template D The Document class
|
||||
*/
|
||||
export class MathMLCompile<N, T, D> {
|
||||
|
||||
/**
|
||||
* The default options for this object
|
||||
*/
|
||||
public static OPTIONS: OptionList = {
|
||||
MmlFactory: null, // The MmlFactory to use (defaults to a new MmlFactory)
|
||||
fixMisplacedChildren: true, // True if we want to use heuristics to try to fix
|
||||
// problems with the tree based on HTML not handling
|
||||
// self-closing tags properly
|
||||
verify: { // Options to pass to verifyTree() controlling MathML verification
|
||||
...AbstractMmlNode.verifyDefaults
|
||||
},
|
||||
translateEntities: true // True means translate entities in text nodes
|
||||
};
|
||||
|
||||
/**
|
||||
* The DOMAdaptor for the document being processed
|
||||
*/
|
||||
public adaptor: DOMAdaptor<N, T, D>;
|
||||
|
||||
/**
|
||||
* The instance of the MmlFactory object and
|
||||
*/
|
||||
protected factory: MmlFactory;
|
||||
/**
|
||||
* The options (the defaults with the user options merged in)
|
||||
*/
|
||||
protected options: OptionList;
|
||||
|
||||
/**
|
||||
* Merge the user options into the defaults, and save them
|
||||
* Create the MmlFactory object
|
||||
*
|
||||
* @param {OptionList} options The options controlling the conversion
|
||||
*/
|
||||
constructor(options: OptionList = {}) {
|
||||
const Class = this.constructor as typeof MathMLCompile;
|
||||
this.options = userOptions(defaultOptions({}, Class.OPTIONS), options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param{MmlFactory} mmlFactory The MathML factory to use for new nodes
|
||||
*/
|
||||
public setMmlFactory(mmlFactory: MmlFactory) {
|
||||
this.factory = mmlFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a MathML DOM tree to internal MmlNodes
|
||||
*
|
||||
* @param {N} node The <math> node to convert to MmlNodes
|
||||
* @return {MmlNode} The MmlNode at the root of the converted tree
|
||||
*/
|
||||
public compile(node: N): MmlNode {
|
||||
let mml = this.makeNode(node);
|
||||
mml.verifyTree(this.options['verify']);
|
||||
mml.setInheritedAttributes({}, false, 0, false);
|
||||
mml.walkTree(this.markMrows);
|
||||
return mml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively convert nodes and their children, taking MathJax classes
|
||||
* into account.
|
||||
*
|
||||
* FIXME: we should use data-* attributes rather than classes for these
|
||||
*
|
||||
* @param {N} node The node to convert to an MmlNode
|
||||
* @return {MmlNode} The converted MmlNode
|
||||
*/
|
||||
public makeNode(node: N): MmlNode {
|
||||
const adaptor = this.adaptor;
|
||||
let limits = false;
|
||||
let kind = adaptor.kind(node).replace(/^.*:/, '');
|
||||
let texClass = adaptor.getAttribute(node, 'data-mjx-texclass') || '';
|
||||
if (texClass) {
|
||||
texClass = this.filterAttribute('data-mjx-texclass', texClass) || '';
|
||||
}
|
||||
let type = texClass && kind === 'mrow' ? 'TeXAtom' : kind;
|
||||
for (const name of this.filterClassList(adaptor.allClasses(node))) {
|
||||
if (name.match(/^MJX-TeXAtom-/) && kind === 'mrow') {
|
||||
texClass = name.substr(12);
|
||||
type = 'TeXAtom';
|
||||
} else if (name === 'MJX-fixedlimits') {
|
||||
limits = true;
|
||||
}
|
||||
}
|
||||
this.factory.getNodeClass(type) || this.error('Unknown node type "' + type + '"');
|
||||
let mml = this.factory.create(type);
|
||||
if (type === 'TeXAtom' && texClass === 'OP' && !limits) {
|
||||
mml.setProperty('movesupsub', true);
|
||||
mml.attributes.setInherited('movablelimits', true);
|
||||
}
|
||||
if (texClass) {
|
||||
mml.texClass = (TEXCLASS as {[name: string]: number})[texClass];
|
||||
mml.setProperty('texClass', mml.texClass);
|
||||
}
|
||||
this.addAttributes(mml, node);
|
||||
this.checkClass(mml, node);
|
||||
this.addChildren(mml, node);
|
||||
return mml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the attributes from a MathML node to an MmlNode.
|
||||
*
|
||||
* @param {MmlNode} mml The MmlNode to which attributes will be added
|
||||
* @param {N} node The MathML node whose attributes to copy
|
||||
*/
|
||||
protected addAttributes(mml: MmlNode, node: N) {
|
||||
let ignoreVariant = false;
|
||||
for (const attr of this.adaptor.allAttributes(node)) {
|
||||
let name = attr.name;
|
||||
let value = this.filterAttribute(name, attr.value);
|
||||
if (value === null || name === 'xmlns') {
|
||||
continue;
|
||||
}
|
||||
if (name.substr(0, 9) === 'data-mjx-') {
|
||||
switch (name.substr(9)) {
|
||||
case 'alternate':
|
||||
mml.setProperty('variantForm', true);
|
||||
break;
|
||||
case 'variant':
|
||||
mml.attributes.set('mathvariant', value);
|
||||
ignoreVariant = true;
|
||||
break;
|
||||
case 'smallmatrix':
|
||||
mml.setProperty('scriptlevel', 1);
|
||||
mml.setProperty('useHeight', false);
|
||||
break;
|
||||
case 'accent':
|
||||
mml.setProperty('mathaccent', value === 'true');
|
||||
break;
|
||||
case 'auto-op':
|
||||
mml.setProperty('autoOP', value === 'true');
|
||||
break;
|
||||
case 'script-align':
|
||||
mml.setProperty('scriptalign', value);
|
||||
break;
|
||||
}
|
||||
} else if (name !== 'class') {
|
||||
let val = value.toLowerCase();
|
||||
if (val === 'true' || val === 'false') {
|
||||
mml.attributes.set(name, val === 'true');
|
||||
} else if (!ignoreVariant || name !== 'mathvariant') {
|
||||
mml.attributes.set(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a hook for the Safe extension to filter attribute values.
|
||||
*
|
||||
* @param {string} name The name of an attribute to filter
|
||||
* @param {string} value The value to filter
|
||||
*/
|
||||
protected filterAttribute(_name: string, value: string) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a hook for the Safe extension to filter class names.
|
||||
*
|
||||
* @param {string[]} list The list of class names to filter
|
||||
*/
|
||||
protected filterClassList(list: string[]) {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the children of the MathML node and add them to the MmlNode
|
||||
*
|
||||
* @param {MmlNode} mml The MmlNode to which children will be added
|
||||
* @param {N} node The MathML node whose children are to be copied
|
||||
*/
|
||||
protected addChildren(mml: MmlNode, node: N) {
|
||||
if (mml.arity === 0) {
|
||||
return;
|
||||
}
|
||||
const adaptor = this.adaptor;
|
||||
for (const child of adaptor.childNodes(node) as N[]) {
|
||||
const name = adaptor.kind(child);
|
||||
if (name === '#comment') {
|
||||
continue;
|
||||
}
|
||||
if (name === '#text') {
|
||||
this.addText(mml, child);
|
||||
} else if (mml.isKind('annotation-xml')) {
|
||||
mml.appendChild((this.factory.create('XML') as XMLNode).setXML(child, adaptor));
|
||||
} else {
|
||||
let childMml = mml.appendChild(this.makeNode(child)) as MmlNode;
|
||||
if (childMml.arity === 0 && adaptor.childNodes(child).length) {
|
||||
if (this.options['fixMisplacedChildren']) {
|
||||
this.addChildren(mml, child);
|
||||
} else {
|
||||
childMml.mError('There should not be children for ' + childMml.kind + ' nodes',
|
||||
this.options['verify'], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add text to a token node
|
||||
*
|
||||
* @param {MmlNode} mml The MmlNode to which text will be added
|
||||
* @param {N} child The text node whose contents is to be copied
|
||||
*/
|
||||
protected addText(mml: MmlNode, child: N) {
|
||||
let text = this.adaptor.value(child);
|
||||
if ((mml.isToken || mml.getProperty('isChars')) && mml.arity) {
|
||||
if (mml.isToken) {
|
||||
text = Entities.translate(text);
|
||||
text = this.trimSpace(text);
|
||||
}
|
||||
mml.appendChild((this.factory.create('text') as TextNode).setText(text));
|
||||
} else if (text.match(/\S/)) {
|
||||
this.error('Unexpected text node "' + text + '"');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for special MJX values in the class and process them
|
||||
*
|
||||
* @param {MmlNode} mml The MmlNode to be modified according to the class markers
|
||||
* @param {N} node The MathML node whose class is to be processed
|
||||
*/
|
||||
protected checkClass(mml: MmlNode, node: N) {
|
||||
let classList = [];
|
||||
for (const name of this.filterClassList(this.adaptor.allClasses(node))) {
|
||||
if (name.substr(0, 4) === 'MJX-') {
|
||||
if (name === 'MJX-variant') {
|
||||
mml.setProperty('variantForm', true);
|
||||
} else if (name.substr(0, 11) !== 'MJX-TeXAtom') {
|
||||
mml.attributes.set('mathvariant', this.fixCalligraphic(name.substr(3)));
|
||||
}
|
||||
} else {
|
||||
classList.push(name);
|
||||
}
|
||||
}
|
||||
if (classList.length) {
|
||||
mml.attributes.set('class', classList.join(' '));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix the old incorrect spelling of calligraphic.
|
||||
*
|
||||
* @param {string} variant The mathvariant name
|
||||
* @return {string} The corrected variant
|
||||
*/
|
||||
protected fixCalligraphic(variant: string): string {
|
||||
return variant.replace(/caligraphic/, 'calligraphic');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if an mrow has delimiters at both ends (so looks like an mfenced structure).
|
||||
*
|
||||
* @param {MmlNode} mml The node to check for mfenced structure
|
||||
*/
|
||||
protected markMrows(mml: MmlNode) {
|
||||
if (mml.isKind('mrow') && !mml.isInferred && mml.childNodes.length >= 2) {
|
||||
let first = mml.childNodes[0] as MmlNode;
|
||||
let last = mml.childNodes[mml.childNodes.length - 1] as MmlNode;
|
||||
if (first.isKind('mo') && first.attributes.get('fence') && first.attributes.get('stretchy') &&
|
||||
last.isKind('mo') && last.attributes.get('fence') && last.attributes.get('stretchy')) {
|
||||
if (first.childNodes.length) {
|
||||
mml.setProperty('open', (first as AbstractMmlTokenNode).getText());
|
||||
}
|
||||
if (last.childNodes.length) {
|
||||
mml.setProperty('close', (last as AbstractMmlTokenNode).getText());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text The text to have leading/trailing spaced removed
|
||||
* @return {string} The trimmed text
|
||||
*/
|
||||
protected trimSpace(text: string): string {
|
||||
return text.replace(/[\t\n\r]/g, ' ') // whitespace to spaces
|
||||
.replace(/^ +/, '') // initial whitespace
|
||||
.replace(/ +$/, '') // trailing whitespace
|
||||
.replace(/ +/g, ' '); // internal multiple whitespace
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} message The error message to produce
|
||||
*/
|
||||
protected error(message: string) {
|
||||
throw new Error(message);
|
||||
}
|
||||
}
|
||||
76
node_modules/mathjax-full/ts/input/mathml/mml3/mml3-node.ts
generated
vendored
Normal file
76
node_modules/mathjax-full/ts/input/mathml/mml3/mml3-node.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2022 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Auxiliary function for elementary MathML3 support (experimental)
|
||||
* using David Carlisle's XLST transform.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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<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 */
|
||||
const dirname = eval('__dirname'); // get the actual __dirname
|
||||
try {
|
||||
nodeRequire.resolve('saxon-js'); // check if saxon-js is installed.
|
||||
} catch (err) {
|
||||
throw Error('Saxon-js not found. Run the command:\n npm install saxon-js\nand try again.');
|
||||
}
|
||||
const Saxon = nodeRequire('saxon-js'); // dynamically load Saxon-JS.
|
||||
const path = nodeRequire('path'); // use the real version from node.
|
||||
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 (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"');
|
||||
}
|
||||
//
|
||||
// Try to run the transform, and if it fails, return the original MathML
|
||||
//
|
||||
let result;
|
||||
try {
|
||||
result = adaptor.firstChild(adaptor.body(adaptor.parse(Saxon.transform({
|
||||
stylesheetInternal: xslt,
|
||||
sourceText: mml,
|
||||
destination: 'serialized'
|
||||
}).principalResult))) as N;
|
||||
} catch (err) {
|
||||
result = node;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
1
node_modules/mathjax-full/ts/input/mathml/mml3/mml3.sef.json
generated
vendored
Normal file
1
node_modules/mathjax-full/ts/input/mathml/mml3/mml3.sef.json
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
807
node_modules/mathjax-full/ts/input/mathml/mml3/mml3.ts
generated
vendored
Normal file
807
node_modules/mathjax-full/ts/input/mathml/mml3/mml3.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,807 @@
|
|||
/*************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2022 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Implements the elementary MathML3 support (experimental)
|
||||
* using David Carlisle's XLST transform.
|
||||
*
|
||||
* @author dpvc@mathjax.org (Davide Cervone)
|
||||
*/
|
||||
|
||||
import {MathItem} from '../../../core/MathItem.js';
|
||||
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: N};
|
||||
|
||||
/**
|
||||
* Class that handles XSLT transform for MathML3 elementary math tags.
|
||||
*/
|
||||
export class Mml3<N, T, D> {
|
||||
|
||||
/**
|
||||
* The XSLT transform as a string;
|
||||
*/
|
||||
public static XSLT: string; // added below (it is huge)
|
||||
|
||||
/**
|
||||
* The function to convert serialized MathML using the XSLT.
|
||||
* (Different for browser and node environments.)
|
||||
*/
|
||||
protected transform: (node: N, doc: MathDocument<N, T, D>) => N;
|
||||
|
||||
/**
|
||||
* @param {MathDocument} document The MathDocument for the transformation
|
||||
* @constructor
|
||||
*/
|
||||
constructor(document: MathDocument<N, T, D>) {
|
||||
if (typeof XSLTProcessor === 'undefined') {
|
||||
//
|
||||
// For Node, get the trasnform from the external module
|
||||
//
|
||||
this.transform = createTransform();
|
||||
} else {
|
||||
//
|
||||
// For in-browser use, use the browser's XSLTProcessor
|
||||
//
|
||||
const processor = new XSLTProcessor();
|
||||
const parsed = document.adaptor.parse(Mml3.XSLT, 'text/xml') as any as Node;
|
||||
processor.importStylesheet(parsed);
|
||||
this.transform = (node: N) => {
|
||||
const adaptor = document.adaptor;
|
||||
const div = adaptor.node('div', {}, [adaptor.clone(node)]);
|
||||
const mml = processor.transformToDocument(div as any as Node) as any as N;
|
||||
return adaptor.tags(mml, 'math')[0];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The mathml filter for the MathML input jax
|
||||
*
|
||||
* @param {FILTERDATA} args The data from the pre-filter chain.
|
||||
*/
|
||||
public mmlFilter(args: FILTERDATA<N, T, D>) {
|
||||
if (args.document.options.enableMml3) {
|
||||
args.data = this.transform(args.data, args.document);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Mml3 support into the handler.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @override
|
||||
* @constructor
|
||||
*/
|
||||
constructor(...args: any[]) {
|
||||
super(...args);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return handler;
|
||||
}
|
||||
|
||||
//
|
||||
// The actual XSLT transform
|
||||
//
|
||||
Mml3.XSLT = `
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:m="http://www.w3.org/1998/Math/MathML"
|
||||
xmlns:c="http://exslt.org/common"
|
||||
exclude-result-prefixes="m c">
|
||||
<xsl:output indent="yes" omit-xml-declaration="yes"/>
|
||||
<xsl:output indent="yes" omit-xml-declaration="yes"/>
|
||||
<xsl:template match="*">
|
||||
<xsl:copy>
|
||||
<xsl:copy-of select="@*"/>
|
||||
<xsl:apply-templates/>
|
||||
</xsl:copy>
|
||||
</xsl:template>
|
||||
<xsl:template match="m:*[@dir='rtl']" priority="10">
|
||||
<xsl:apply-templates mode="rtl" select="."/>
|
||||
</xsl:template>
|
||||
<xsl:template match="@*" mode="rtl">
|
||||
<xsl:copy-of select="."/>
|
||||
<xsl:attribute name="dir">ltr</xsl:attribute>
|
||||
</xsl:template>
|
||||
<xsl:template match="*" mode="rtl">
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates select="@*" mode="rtl"/>
|
||||
<xsl:for-each select="node()">
|
||||
<xsl:sort data-type="number" order="descending" select="position()"/>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:apply-templates mode="rtl" select="."/>
|
||||
</xsl:for-each>
|
||||
</xsl:copy>
|
||||
</xsl:template>
|
||||
<xsl:template match="@open" mode="rtl">
|
||||
<xsl:attribute name="close"><xsl:value-of select="."/></xsl:attribute>
|
||||
</xsl:template>
|
||||
<xsl:template match="@open[.='(']" mode="rtl">
|
||||
<xsl:attribute name="close">)</xsl:attribute>
|
||||
</xsl:template>
|
||||
<xsl:template match="@open[.=')']" mode="rtl">
|
||||
<xsl:attribute name="close">(</xsl:attribute>
|
||||
</xsl:template>
|
||||
<xsl:template match="@open[.='[']" mode="rtl">
|
||||
<xsl:attribute name="close">]</xsl:attribute>
|
||||
</xsl:template>
|
||||
<xsl:template match="@open[.=']']" mode="rtl">
|
||||
<xsl:attribute name="close">[</xsl:attribute>
|
||||
</xsl:template>
|
||||
<xsl:template match="@open[.='{']" mode="rtl">
|
||||
<xsl:attribute name="close">}</xsl:attribute>
|
||||
</xsl:template>
|
||||
<xsl:template match="@open[.='}']" mode="rtl">
|
||||
<xsl:attribute name="close">{</xsl:attribute>
|
||||
</xsl:template>
|
||||
<xsl:template match="@close" mode="rtl">
|
||||
<xsl:attribute name="open"><xsl:value-of select="."/></xsl:attribute>
|
||||
</xsl:template>
|
||||
<xsl:template match="@close[.='(']" mode="rtl">
|
||||
<xsl:attribute name="open">)</xsl:attribute>
|
||||
</xsl:template>
|
||||
<xsl:template match="@close[.=')']" mode="rtl">
|
||||
<xsl:attribute name="open">(</xsl:attribute>
|
||||
</xsl:template>
|
||||
<xsl:template match="@close[.='[']" mode="rtl">
|
||||
<xsl:attribute name="open">]</xsl:attribute>
|
||||
</xsl:template>
|
||||
<xsl:template match="@close[.=']']" mode="rtl">
|
||||
<xsl:attribute name="open">[</xsl:attribute>
|
||||
</xsl:template>
|
||||
<xsl:template match="@close[.='{']" mode="rtl">
|
||||
<xsl:attribute name="open">}</xsl:attribute>
|
||||
</xsl:template>
|
||||
<xsl:template match="@close[.='}']" mode="rtl">
|
||||
<xsl:attribute name="open">{</xsl:attribute>
|
||||
</xsl:template>
|
||||
<xsl:template match="m:mfrac[@bevelled='true']" mode="rtl">
|
||||
<m:mrow>
|
||||
<m:msub><m:mi></m:mi><xsl:apply-templates select="*[2]" mode="rtl"/></m:msub>
|
||||
<m:mo>\</m:mo>
|
||||
<m:msup><m:mi></m:mi><xsl:apply-templates select="*[1]" mode="rtl"/></m:msup>
|
||||
</m:mrow>
|
||||
</xsl:template>
|
||||
<xsl:template match="m:mfrac" mode="rtl">
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates mode="rtl" select="@*|*"/>
|
||||
</xsl:copy>
|
||||
</xsl:template>
|
||||
<xsl:template match="m:mroot" mode="rtl">
|
||||
<m:msup>
|
||||
<m:menclose notation="top right">
|
||||
<xsl:apply-templates mode="rtl" select="@*|*[1]"/>
|
||||
</m:menclose>
|
||||
<xsl:apply-templates mode="rtl" select="*[2]"/>
|
||||
</m:msup>
|
||||
</xsl:template>
|
||||
<xsl:template match="m:msqrt" mode="rtl">
|
||||
<m:menclose notation="top right">
|
||||
<xsl:apply-templates mode="rtl" select="@*|*[1]"/>
|
||||
</m:menclose>
|
||||
</xsl:template>
|
||||
<xsl:template match="m:mtable|m:munder|m:mover|m:munderover" mode="rtl" priority="2">
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates select="@*" mode="rtl"/>
|
||||
<xsl:apply-templates mode="rtl">
|
||||
</xsl:apply-templates>
|
||||
</xsl:copy>
|
||||
</xsl:template>
|
||||
<xsl:template match="m:msup" mode="rtl" priority="2">
|
||||
<m:mmultiscripts>
|
||||
<xsl:apply-templates select="*[1]" mode="rtl"/>
|
||||
<m:mprescripts/>
|
||||
<m:none/>
|
||||
<xsl:apply-templates select="*[2]" mode="rtl"/>
|
||||
</m:mmultiscripts>
|
||||
</xsl:template>
|
||||
<xsl:template match="m:msub" mode="rtl" priority="2">
|
||||
<m:mmultiscripts>
|
||||
<xsl:apply-templates select="*[1]" mode="rtl"/>
|
||||
<m:mprescripts/>
|
||||
<xsl:apply-templates select="*[2]" mode="rtl"/>
|
||||
<m:none/>
|
||||
</m:mmultiscripts>
|
||||
</xsl:template>
|
||||
<xsl:template match="m:msubsup" mode="rtl" priority="2">
|
||||
<m:mmultiscripts>
|
||||
<xsl:apply-templates select="*[1]" mode="rtl"/>
|
||||
<m:mprescripts/>
|
||||
<xsl:apply-templates select="*[2]" mode="rtl"/>
|
||||
<xsl:apply-templates select="*[3]" mode="rtl"/>
|
||||
</m:mmultiscripts>
|
||||
</xsl:template>
|
||||
<xsl:template match="m:mmultiscripts" mode="rtl" priority="2">
|
||||
<m:mmultiscripts>
|
||||
<xsl:apply-templates select="*[1]" mode="rtl"/>
|
||||
<xsl:for-each select="m:mprescripts/following-sibling::*[position() mod 2 = 1]">
|
||||
<xsl:sort data-type="number" order="descending" select="position()"/>
|
||||
<xsl:apply-templates select="." mode="rtl"/>
|
||||
<xsl:apply-templates select="following-sibling::*[1]" mode="rtl"/>
|
||||
</xsl:for-each>
|
||||
<m:mprescripts/>
|
||||
<xsl:for-each select="m:mprescripts/preceding-sibling::*[position()!=last()][position() mod 2 = 0]">
|
||||
<xsl:sort data-type="number" order="descending" select="position()"/>
|
||||
<xsl:apply-templates select="." mode="rtl"/>
|
||||
<xsl:apply-templates select="following-sibling::*[1]" mode="rtl"/>
|
||||
</xsl:for-each>
|
||||
</m:mmultiscripts>
|
||||
</xsl:template>
|
||||
<xsl:template match="m:mmultiscripts[not(m:mprescripts)]" mode="rtl" priority="3">
|
||||
<m:mmultiscripts>
|
||||
<xsl:apply-templates select="*[1]" mode="rtl"/>
|
||||
<m:mprescripts/>
|
||||
<xsl:for-each select="*[position() mod 2 = 0]">
|
||||
<xsl:sort data-type="number" order="descending" select="position()"/>
|
||||
<xsl:apply-templates select="." mode="rtl"/>
|
||||
<xsl:apply-templates select="following-sibling::*[1]" mode="rtl"/>
|
||||
</xsl:for-each>
|
||||
</m:mmultiscripts>
|
||||
</xsl:template>
|
||||
<xsl:template match="text()[.='(']" mode="rtl">)</xsl:template>
|
||||
<xsl:template match="text()[.=')']" mode="rtl">(</xsl:template>
|
||||
<xsl:template match="text()[.='{']" mode="rtl">}</xsl:template>
|
||||
<xsl:template match="text()[.='}']" mode="rtl">{</xsl:template>
|
||||
<xsl:template match="text()[.='<']" mode="rtl">></xsl:template>
|
||||
<xsl:template match="text()[.='>']" mode="rtl"><</xsl:template>
|
||||
<xsl:template match="text()[.='∈']" mode="rtl">∋</xsl:template>
|
||||
<xsl:template match="text()[.='∋']" mode="rtl">∈</xsl:template>
|
||||
<xsl:template match="@notation[.='radical']" mode="rtl">
|
||||
<xsl:attribute name="notation">top right</xsl:attribute>
|
||||
</xsl:template>
|
||||
<xsl:template match="m:mlongdiv|m:mstack" mode="rtl">
|
||||
<m:mrow dir="ltr">
|
||||
<xsl:apply-templates select="."/>
|
||||
</m:mrow>
|
||||
</xsl:template>
|
||||
<xsl:template match="m:mstack" priority="11">
|
||||
<xsl:variable name="m">
|
||||
<m:mtable columnspacing="0em" rowspacing="0em">
|
||||
<xsl:copy-of select="@align"/>
|
||||
<xsl:variable name="t">
|
||||
<xsl:apply-templates select="*" mode="mstack1">
|
||||
<xsl:with-param name="p" select="0"/>
|
||||
</xsl:apply-templates>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="maxl">
|
||||
<xsl:for-each select="c:node-set($t)/*/@l">
|
||||
<xsl:sort data-type="number" order="descending"/>
|
||||
<xsl:if test="position()=1">
|
||||
<xsl:value-of select="."/>
|
||||
</xsl:if>
|
||||
</xsl:for-each>
|
||||
</xsl:variable>
|
||||
<xsl:for-each select="c:node-set($t)/*[not(@class='mscarries') or following-sibling::*[1]/@class='mscarries']">
|
||||
<xsl:variable name="c" select="preceding-sibling::*[1][@class='mscarries']"/>
|
||||
<xsl:text> </xsl:text>
|
||||
<m:mtr>
|
||||
<xsl:copy-of select="@class[.='msline']"/>
|
||||
<xsl:variable name="offset" select="$maxl - @l"/>
|
||||
<xsl:choose>
|
||||
<xsl:when test="@class='msline' and @l='*'">
|
||||
<xsl:variable name="msl" select="*[1]"/>
|
||||
<xsl:for-each select="(//node())[position()<=$maxl]">
|
||||
<xsl:copy-of select="$msl"/>
|
||||
</xsl:for-each>
|
||||
</xsl:when>
|
||||
<xsl:when test="$c">
|
||||
<xsl:variable name="ldiff" select="$c/@l - @l"/>
|
||||
<xsl:variable name="loffset" select="$maxl - $c/@l"/>
|
||||
<xsl:for-each select="(//*)[position()<= $offset]">
|
||||
<xsl:variable name="pn" select="position()"/>
|
||||
<xsl:variable name="cy" select="$c/*[position()=$pn - $loffset]"/>
|
||||
<m:mtd>
|
||||
<xsl:if test="$cy/*">
|
||||
<m:mover><m:mphantom><m:mn>0</m:mn></m:mphantom><m:mpadded width="0em" lspace="-0.5width">
|
||||
<xsl:copy-of select="$cy/*"/></m:mpadded></m:mover>
|
||||
</xsl:if>
|
||||
</m:mtd>
|
||||
</xsl:for-each>
|
||||
<xsl:for-each select="*">
|
||||
<xsl:variable name="pn" select="position()"/>
|
||||
<xsl:variable name="cy" select="$c/*[position()=$pn + $ldiff]"/>
|
||||
<xsl:copy>
|
||||
<xsl:copy-of select="@*"/>
|
||||
<xsl:variable name="b">
|
||||
<xsl:choose>
|
||||
<xsl:when test="not(string($cy/@crossout) or $cy/@crossout='none')"><xsl:copy-of select="*"/></xsl:when>
|
||||
<xsl:otherwise>
|
||||
<m:menclose notation="{$cy/@crossout}"><xsl:copy-of select="*"/></m:menclose>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:choose>
|
||||
<xsl:when test="$cy/m:none or not($cy/*)"><xsl:copy-of select="$b"/></xsl:when>
|
||||
<xsl:when test="not(string($cy/@location)) or $cy/@location='n'">
|
||||
<m:mover>
|
||||
<xsl:copy-of select="$b"/><m:mpadded width="0em" lspace="-0.5width">
|
||||
<xsl:copy-of select="$cy/*"/>
|
||||
</m:mpadded>
|
||||
</m:mover>
|
||||
</xsl:when>
|
||||
<xsl:when test="$cy/@location='nw'">
|
||||
<m:mmultiscripts><xsl:copy-of select="$b"/><m:mprescripts/><m:none/><m:mpadded lspace="-1width" width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded></m:mmultiscripts>
|
||||
</xsl:when>
|
||||
<xsl:when test="$cy/@location='s'">
|
||||
<m:munder><xsl:copy-of select="$b"/><m:mpadded width="0em" lspace="-0.5width"><xsl:copy-of select="$cy/*"/></m:mpadded></m:munder>
|
||||
</xsl:when>
|
||||
<xsl:when test="$cy/@location='sw'">
|
||||
<m:mmultiscripts><xsl:copy-of select="$b"/><m:mprescripts/><m:mpadded lspace="-1width" width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded><m:none/></m:mmultiscripts>
|
||||
</xsl:when>
|
||||
<xsl:when test="$cy/@location='ne'">
|
||||
<m:msup><xsl:copy-of select="$b"/><m:mpadded width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded></m:msup>
|
||||
</xsl:when>
|
||||
<xsl:when test="$cy/@location='se'">
|
||||
<m:msub><xsl:copy-of select="$b"/><m:mpadded width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded></m:msub>
|
||||
</xsl:when>
|
||||
<xsl:when test="$cy/@location='w'">
|
||||
<m:msup><m:mrow/><m:mpadded lspace="-1width" width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded></m:msup>
|
||||
<xsl:copy-of select="$b"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="$cy/@location='e'">
|
||||
<xsl:copy-of select="$b"/>
|
||||
<m:msup><m:mrow/><m:mpadded width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded></m:msup>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:copy-of select="$b"/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:copy>
|
||||
</xsl:for-each>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:for-each select="(//*)[position()<= $offset]"><m:mtd/></xsl:for-each>
|
||||
<xsl:copy-of select="*"/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</m:mtr>
|
||||
</xsl:for-each>
|
||||
</m:mtable>
|
||||
</xsl:variable>
|
||||
<xsl:apply-templates mode="ml" select="c:node-set($m)"/>
|
||||
</xsl:template>
|
||||
<xsl:template match="m:none" mode="ml">
|
||||
<m:mrow/>
|
||||
</xsl:template>
|
||||
<xsl:template match="*" mode="ml">
|
||||
<xsl:copy>
|
||||
<xsl:copy-of select="@*"/>
|
||||
<xsl:apply-templates mode="ml"/>
|
||||
</xsl:copy>
|
||||
</xsl:template>
|
||||
<xsl:template mode="ml" match="m:mtr[following-sibling::*[1][@class='msline']]">
|
||||
<m:mtr>
|
||||
<xsl:copy-of select="@*"/>
|
||||
<xsl:variable name="m" select="following-sibling::*[1]/m:mtd"/>
|
||||
<xsl:for-each select="m:mtd">
|
||||
<xsl:variable name="p" select="position()"/>
|
||||
<m:mtd>
|
||||
<xsl:copy-of select="@*"/>
|
||||
<xsl:choose>
|
||||
<xsl:when test="$m[$p]/m:mpadded">
|
||||
<m:mpadded depth="+.2em">
|
||||
<m:menclose notation="bottom">
|
||||
<m:mpadded depth=".1em" height=".8em" width=".8em">
|
||||
<m:mspace width=".15em"/>
|
||||
<xsl:copy-of select="*"/>
|
||||
</m:mpadded>
|
||||
</m:menclose>
|
||||
</m:mpadded>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:copy-of select="*"/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</m:mtd>
|
||||
</xsl:for-each>
|
||||
</m:mtr>
|
||||
</xsl:template>
|
||||
<xsl:template mode="ml" match="m:mtr[not(preceding-sibling::*)][@class='msline']" priority="3">
|
||||
<m:mtr>
|
||||
<xsl:copy-of select="@*"/>
|
||||
<xsl:for-each select="m:mtd">
|
||||
<m:mtd>
|
||||
<xsl:copy-of select="@*"/>
|
||||
<xsl:if test="m:mpadded">
|
||||
<m:menclose notation="bottom">
|
||||
<m:mpadded depth=".1em" height="1em" width=".5em">
|
||||
<m:mspace width=".2em"/>
|
||||
</m:mpadded>
|
||||
</m:menclose>
|
||||
</xsl:if>
|
||||
</m:mtd>
|
||||
</xsl:for-each>
|
||||
</m:mtr>
|
||||
</xsl:template>
|
||||
<xsl:template mode="ml" match="m:mtr[@class='msline']" priority="2"/>
|
||||
<xsl:template mode="mstack1" match="*">
|
||||
<xsl:param name="p"/>
|
||||
<xsl:param name="maxl" select="0"/>
|
||||
<m:mtr l="{1 + $p}">
|
||||
<xsl:if test="ancestor::mstack[1]/@stackalign='left'">
|
||||
<xsl:attribute name="l"><xsl:value-of select="$p"/></xsl:attribute>
|
||||
</xsl:if>
|
||||
<m:mtd><xsl:apply-templates select="."/></m:mtd>
|
||||
</m:mtr>
|
||||
</xsl:template>
|
||||
<xsl:template mode="mstack1" match="m:msrow">
|
||||
<xsl:param name="p"/>
|
||||
<xsl:param name="maxl" select="0"/>
|
||||
<xsl:variable name="align1" select="ancestor::m:mstack[1]/@stackalign"/>
|
||||
<xsl:variable name="align">
|
||||
<xsl:choose>
|
||||
<xsl:when test="string($align1)=''">decimalpoint</xsl:when>
|
||||
<xsl:otherwise><xsl:value-of select="$align1"/></xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="row">
|
||||
<xsl:apply-templates mode="mstack1" select="*">
|
||||
<xsl:with-param name="p" select="0"/>
|
||||
</xsl:apply-templates>
|
||||
</xsl:variable>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:variable name="l1">
|
||||
<xsl:choose>
|
||||
<xsl:when test="$align='decimalpoint' and m:mn">
|
||||
<xsl:for-each select="c:node-set($row)/m:mtr[m:mtd/m:mn][1]">
|
||||
<xsl:value-of select="number(sum(@l))+count(preceding-sibling::*/@l)"/>
|
||||
</xsl:for-each>
|
||||
</xsl:when>
|
||||
<xsl:when test="$align='right' or $align='decimalpoint'">
|
||||
<xsl:value-of select="count(c:node-set($row)/m:mtr/m:mtd)"/>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:value-of select="0"/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<m:mtr class="msrow" l="{number($l1) + number(sum(@position)) +$p}">
|
||||
<xsl:copy-of select="c:node-set($row)/m:mtr/*"/>
|
||||
</m:mtr>
|
||||
</xsl:template>
|
||||
<xsl:template mode="mstack1" match="m:mn">
|
||||
<xsl:param name="p"/>
|
||||
<xsl:variable name="align1" select="ancestor::m:mstack[1]/@stackalign"/>
|
||||
<xsl:variable name="dp1" select="ancestor::*[@decimalpoint][1]/@decimalpoint"/>
|
||||
<xsl:variable name="align">
|
||||
<xsl:choose>
|
||||
<xsl:when test="string($align1)=''">decimalpoint</xsl:when>
|
||||
<xsl:otherwise><xsl:value-of select="$align1"/></xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="dp">
|
||||
<xsl:choose>
|
||||
<xsl:when test="string($dp1)=''">.</xsl:when>
|
||||
<xsl:otherwise><xsl:value-of select="$dp1"/></xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<m:mtr l="$p">
|
||||
<xsl:variable name="mn" select="normalize-space(.)"/>
|
||||
<xsl:variable name="len" select="string-length($mn)"/>
|
||||
<xsl:choose>
|
||||
<xsl:when test="$align='right' or ($align='decimalpoint' and not(contains($mn,$dp)))">
|
||||
<xsl:attribute name="l"><xsl:value-of select="$p + $len"/></xsl:attribute>
|
||||
</xsl:when>
|
||||
<xsl:when test="$align='center'">
|
||||
<xsl:attribute name="l"><xsl:value-of select="round(($p + $len) div 2)"/></xsl:attribute>
|
||||
</xsl:when>
|
||||
<xsl:when test="$align='decimalpoint'">
|
||||
<xsl:attribute name="l"><xsl:value-of select="$p + string-length(substring-before($mn,$dp))"/></xsl:attribute>
|
||||
</xsl:when>
|
||||
</xsl:choose>
|
||||
<xsl:for-each select="(//node())[position() <=$len]">
|
||||
<xsl:variable name="pos" select="position()"/>
|
||||
<xsl:variable name="digit" select="substring($mn,$pos,1)"/>
|
||||
<m:mtd>
|
||||
<xsl:if test="$digit='.' or $digit=','">
|
||||
<m:mspace width=".15em"/>
|
||||
</xsl:if>
|
||||
<m:mn><xsl:value-of select="$digit"/></m:mn>
|
||||
</m:mtd>
|
||||
</xsl:for-each>
|
||||
</m:mtr>
|
||||
</xsl:template>
|
||||
<xsl:template match="m:msgroup" mode="mstack1">
|
||||
<xsl:param name="p"/>
|
||||
<xsl:variable name="s" select="number(sum(@shift))"/>
|
||||
<xsl:variable name="thisp" select="number(sum(@position))"/>
|
||||
<xsl:for-each select="*">
|
||||
<xsl:apply-templates mode="mstack1" select=".">
|
||||
<xsl:with-param name="p" select="number($p)+$thisp+(position()-1)*$s"/>
|
||||
</xsl:apply-templates>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
<xsl:template match="m:msline" mode="mstack1">
|
||||
<xsl:param name="p"/>
|
||||
<xsl:variable name="align1" select="ancestor::m:mstack[1]/@stackalign"/>
|
||||
<xsl:variable name="align">
|
||||
<xsl:choose>
|
||||
<xsl:when test="string($align1)=''">decimalpoint</xsl:when>
|
||||
<xsl:otherwise><xsl:value-of select="$align1"/></xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<m:mtr class="msline">
|
||||
<xsl:attribute name="l">
|
||||
<xsl:choose>
|
||||
<xsl:when test="not(string(@length)) or @length=0">*</xsl:when>
|
||||
<xsl:when test="string($align)='right' or string($align)='decimalpoint' "><xsl:value-of select="$p+ @length"/></xsl:when>
|
||||
<xsl:otherwise><xsl:value-of select="$p"/></xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:attribute>
|
||||
<xsl:variable name="w">
|
||||
<xsl:choose>
|
||||
<xsl:when test="@mslinethickness='thin'">0.1em</xsl:when>
|
||||
<xsl:when test="@mslinethickness='medium'">0.15em</xsl:when>
|
||||
<xsl:when test="@mslinethickness='thick'">0.2em</xsl:when>
|
||||
<xsl:when test="@mslinethickness"><xsl:value-of select="@mslinethickness"/></xsl:when>
|
||||
<xsl:otherwise>0.15em</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:choose>
|
||||
<xsl:when test="not(string(@length)) or @length=0">
|
||||
<m:mtd class="mslinemax">
|
||||
<m:mpadded lspace="-0.2em" width="0em" height="0em">
|
||||
<m:mfrac linethickness="{$w}">
|
||||
<m:mspace width=".5em"/>
|
||||
<m:mrow/>
|
||||
</m:mfrac>
|
||||
</m:mpadded>
|
||||
</m:mtd>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:variable name="l" select="@length"/>
|
||||
<xsl:for-each select="(//node())[position()<=$l]">
|
||||
<m:mtd class="msline">
|
||||
<m:mpadded lspace="-0.2em" width="0em" height="0em">
|
||||
<m:mfrac linethickness="{$w}">
|
||||
<m:mspace width=".5em"/>
|
||||
<m:mrow/>
|
||||
</m:mfrac>
|
||||
</m:mpadded>
|
||||
</m:mtd>
|
||||
</xsl:for-each>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</m:mtr>
|
||||
</xsl:template>
|
||||
<xsl:template match="m:mscarries" mode="mstack1">
|
||||
<xsl:param name="p"/>
|
||||
<xsl:variable name="align1" select="ancestor::m:mstack[1]/@stackalign"/>
|
||||
<xsl:variable name="l1">
|
||||
<xsl:choose>
|
||||
<xsl:when test="string($align1)='left'">0</xsl:when>
|
||||
<xsl:otherwise><xsl:value-of select="count(*)"/></xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<m:mtr class="mscarries" l="{$p + $l1 + sum(@position)}">
|
||||
<xsl:apply-templates select="*" mode="msc"/>
|
||||
</m:mtr>
|
||||
</xsl:template>
|
||||
<xsl:template match="*" mode="msc">
|
||||
<m:mtd>
|
||||
<xsl:copy-of select="../@location|../@crossout"/>
|
||||
<xsl:choose>
|
||||
<xsl:when test="../@scriptsizemultiplier">
|
||||
<m:mstyle mathsize="{round(../@scriptsizemultiplier div .007)}%">
|
||||
<xsl:apply-templates select="."/>
|
||||
</m:mstyle>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</m:mtd>
|
||||
</xsl:template>
|
||||
<xsl:template match="m:mscarry" mode="msc">
|
||||
<m:mtd>
|
||||
<xsl:copy-of select="@location|@crossout"/>
|
||||
<xsl:choose>
|
||||
<xsl:when test="../@scriptsizemultiplier">
|
||||
<m:mstyle mathsize="{round(../@scriptsizemultiplier div .007)}%">
|
||||
<xsl:apply-templates/>
|
||||
</m:mstyle>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:apply-templates/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</m:mtd>
|
||||
</xsl:template>
|
||||
<xsl:template match="m:mlongdiv" priority="11">
|
||||
<xsl:variable name="ms">
|
||||
<m:mstack>
|
||||
<xsl:copy-of select="(ancestor-or-self::*/@decimalpoint)[last()]"/>
|
||||
<xsl:choose>
|
||||
<xsl:when test="@longdivstyle='left)(right'">
|
||||
<m:msrow>
|
||||
<m:mrow><xsl:copy-of select="*[1]"/></m:mrow>
|
||||
<m:mo>)</m:mo>
|
||||
<xsl:copy-of select="*[3]"/>
|
||||
<m:mo>(</m:mo>
|
||||
<xsl:copy-of select="*[2]"/>
|
||||
</m:msrow>
|
||||
</xsl:when>
|
||||
<xsl:when test="@longdivstyle='left/\right'">
|
||||
<m:msrow>
|
||||
<m:mrow><xsl:copy-of select="*[1]"/></m:mrow>
|
||||
<m:mo>/</m:mo>
|
||||
<xsl:copy-of select="*[3]"/>
|
||||
<m:mo>\</m:mo>
|
||||
<xsl:copy-of select="*[2]"/>
|
||||
</m:msrow>
|
||||
</xsl:when>
|
||||
<xsl:when test="@longdivstyle=':right=right'">
|
||||
<m:msrow>
|
||||
<xsl:copy-of select="*[3]"/>
|
||||
<m:mo>:</m:mo>
|
||||
<xsl:copy-of select="*[1]"/>
|
||||
<m:mo>=</m:mo>
|
||||
<xsl:copy-of select="*[2]"/>
|
||||
</m:msrow>
|
||||
</xsl:when>
|
||||
<xsl:when test="@longdivstyle='stackedrightright'
|
||||
or @longdivstyle='mediumstackedrightright'
|
||||
or @longdivstyle='shortstackedrightright'
|
||||
or @longdivstyle='stackedleftleft'
|
||||
">
|
||||
<xsl:attribute name="align">top</xsl:attribute>
|
||||
<xsl:copy-of select="*[3]"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="@longdivstyle='stackedleftlinetop'">
|
||||
<xsl:copy-of select="*[2]"/>
|
||||
<m:msline length="{string-length(*[3])}"/>
|
||||
<m:msrow>
|
||||
<m:mrow>
|
||||
<m:menclose notation="bottom right">
|
||||
<xsl:copy-of select="*[1]"/>
|
||||
</m:menclose>
|
||||
</m:mrow>
|
||||
<xsl:copy-of select="*[3]"/>
|
||||
</m:msrow>
|
||||
</xsl:when>
|
||||
<xsl:when test="@longdivstyle='righttop'">
|
||||
<xsl:copy-of select="*[2]"/>
|
||||
<m:msline length="{string-length(*[3])}"/>
|
||||
<m:msrow>
|
||||
<xsl:copy-of select="*[3]"/>
|
||||
<m:menclose notation="top left bottom">
|
||||
<xsl:copy-of select="*[1]"/></m:menclose>
|
||||
</m:msrow>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:copy-of select="*[2]"/>
|
||||
<m:msline length="{string-length(*[3])+1}"/>
|
||||
<m:msrow>
|
||||
<m:mrow><xsl:copy-of select="*[1]"/><m:mspace width=".2em"/></m:mrow>
|
||||
<m:mpadded voffset=".1em" lspace="-.15em" depth="-.2em" height="-.2em">
|
||||
<m:mo minsize="1.2em">)</m:mo>
|
||||
</m:mpadded>
|
||||
<xsl:copy-of select="*[3]"/>
|
||||
</m:msrow>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<xsl:copy-of select="*[position()>3]"/>
|
||||
</m:mstack>
|
||||
</xsl:variable>
|
||||
<xsl:choose>
|
||||
<xsl:when test="@longdivstyle='stackedrightright'">
|
||||
<m:menclose notation="right">
|
||||
<xsl:apply-templates select="c:node-set($ms)"/>
|
||||
</m:menclose>
|
||||
<m:mtable align="top">
|
||||
<m:mtr>
|
||||
<m:menclose notation="bottom">
|
||||
<xsl:copy-of select="*[1]"/>
|
||||
</m:menclose>
|
||||
</m:mtr>
|
||||
<m:mtr>
|
||||
<mtd><xsl:copy-of select="*[2]"/></mtd>
|
||||
</m:mtr>
|
||||
</m:mtable>
|
||||
</xsl:when>
|
||||
<xsl:when test="@longdivstyle='mediumstackedrightright'">
|
||||
<xsl:apply-templates select="c:node-set($ms)"/>
|
||||
<m:menclose notation="left">
|
||||
<m:mtable align="top">
|
||||
<m:mtr>
|
||||
<m:menclose notation="bottom">
|
||||
<xsl:copy-of select="*[1]"/>
|
||||
</m:menclose>
|
||||
</m:mtr>
|
||||
<m:mtr>
|
||||
<mtd><xsl:copy-of select="*[2]"/></mtd>
|
||||
</m:mtr>
|
||||
</m:mtable>
|
||||
</m:menclose>
|
||||
</xsl:when>
|
||||
<xsl:when test="@longdivstyle='shortstackedrightright'">
|
||||
<xsl:apply-templates select="c:node-set($ms)"/>
|
||||
<m:mtable align="top">
|
||||
<m:mtr>
|
||||
<m:menclose notation="left bottom">
|
||||
<xsl:copy-of select="*[1]"/>
|
||||
</m:menclose>
|
||||
</m:mtr>
|
||||
<m:mtr>
|
||||
<mtd><xsl:copy-of select="*[2]"/></mtd>
|
||||
</m:mtr>
|
||||
</m:mtable>
|
||||
</xsl:when>
|
||||
<xsl:when test="@longdivstyle='stackedleftleft'">
|
||||
<m:mtable align="top">
|
||||
<m:mtr>
|
||||
<m:menclose notation="bottom">
|
||||
<xsl:copy-of select="*[1]"/>
|
||||
</m:menclose>
|
||||
</m:mtr>
|
||||
<m:mtr>
|
||||
<mtd><xsl:copy-of select="*[2]"/></mtd>
|
||||
</m:mtr>
|
||||
</m:mtable>
|
||||
<m:menclose notation="left">
|
||||
<xsl:apply-templates select="c:node-set($ms)"/>
|
||||
</m:menclose>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:apply-templates select="c:node-set($ms)"/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
<xsl:template match="m:menclose[@notation='madruwb']" mode="rtl">
|
||||
<m:menclose notation="bottom right">
|
||||
<xsl:apply-templates mode="rtl"/>
|
||||
</m:menclose>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
`;
|
||||
Loading…
Add table
Add a link
Reference in a new issue