add initial marp implementation with sample content and build configuration
This commit is contained in:
127
node_modules/mathjax-full/ts/ui/safe/SafeHandler.ts
generated
vendored
Normal file
127
node_modules/mathjax-full/ts/ui/safe/SafeHandler.ts
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
/*************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-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 MathItem, MathDocument, and Handler for the safe extension
|
||||
*
|
||||
* @author dpvc@mathjax.org (Davide Cervone)
|
||||
*/
|
||||
|
||||
import {MathItem} from '../../core/MathItem.js';
|
||||
import {MathDocument, MathDocumentConstructor} from '../../core/MathDocument.js';
|
||||
import {Handler} from '../../core/Handler.js';
|
||||
|
||||
import {Safe} from './safe.js';
|
||||
|
||||
/*==========================================================================*/
|
||||
|
||||
/**
|
||||
* Generic constructor for Mixins
|
||||
*/
|
||||
export type Constructor<T> = new(...args: any[]) => T;
|
||||
|
||||
/*==========================================================================*/
|
||||
|
||||
/**
|
||||
* The properties needed in the MathDocument for sanitizing the internal MathML
|
||||
*/
|
||||
export interface SafeMathDocument<N, T, D> extends MathDocument<N, T, D> {
|
||||
|
||||
/**
|
||||
* The Safe object for this document
|
||||
*/
|
||||
safe: Safe<N, T, D>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The mixin for adding safe render action to MathDocuments
|
||||
*
|
||||
* @param {B} BaseDocument The MathDocument class to be extended
|
||||
* @return {SafeMathDocument<N,T,D>} The extended MathDocument class
|
||||
*/
|
||||
export function SafeMathDocumentMixin<N, T, D, B extends MathDocumentConstructor<MathDocument<N, T, D>>>(
|
||||
BaseDocument: B
|
||||
): Constructor<SafeMathDocument<N, T, D>> & B {
|
||||
|
||||
return class extends BaseDocument {
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
public static OPTIONS = {
|
||||
...BaseDocument.OPTIONS,
|
||||
safeOptions: {
|
||||
...Safe.OPTIONS,
|
||||
},
|
||||
SafeClass: Safe
|
||||
};
|
||||
|
||||
/**
|
||||
* An instance of the Safe object
|
||||
*/
|
||||
public safe: Safe<N, T, D>;
|
||||
|
||||
/**
|
||||
* Extend the MathItem class used for this MathDocument
|
||||
*
|
||||
* @override
|
||||
* @constructor
|
||||
*/
|
||||
constructor(...args: any[]) {
|
||||
super(...args);
|
||||
this.safe = new this.options.SafeClass(this, this.options.safeOptions);
|
||||
const ProcessBits = (this.constructor as typeof BaseDocument).ProcessBits;
|
||||
if (!ProcessBits.has('safe')) {
|
||||
ProcessBits.allocate('safe');
|
||||
}
|
||||
for (const jax of this.inputJax) {
|
||||
if (jax.name.match(/MathML/)) {
|
||||
(jax as any).mathml.filterAttribute = this.safe.mmlAttribute.bind(this.safe);
|
||||
(jax as any).mathml.filterClassList = this.safe.mmlClassList.bind(this.safe);
|
||||
} else if (jax.name.match(/TeX/)) {
|
||||
jax.postFilters.add(this.sanitize.bind(jax), -5.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{document:SafeDocument<N,T,D>}} data The document to use for the filter
|
||||
* (note: this has been bound to the input jax)
|
||||
*/
|
||||
protected sanitize(data: {math: MathItem<N, T, D>, document: SafeMathDocument<N, T, D>}) {
|
||||
data.math.root = (this as any).parseOptions.root;
|
||||
data.document.safe.sanitize(data.math, data.document);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*==========================================================================*/
|
||||
|
||||
/**
|
||||
* Add context-menu support to a Handler instance
|
||||
*
|
||||
* @param {Handler} handler The Handler instance to enhance
|
||||
* @return {Handler} The handler that was modified (for purposes of chaining extensions)
|
||||
*/
|
||||
export function SafeHandler<N, T, D>(handler: Handler<N, T, D>): Handler<N, T, D> {
|
||||
handler.documentClass = SafeMathDocumentMixin(handler.documentClass);
|
||||
return handler;
|
||||
}
|
||||
288
node_modules/mathjax-full/ts/ui/safe/SafeMethods.ts
generated
vendored
Normal file
288
node_modules/mathjax-full/ts/ui/safe/SafeMethods.ts
generated
vendored
Normal file
@@ -0,0 +1,288 @@
|
||||
/*************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-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 Support functions for the safe extension
|
||||
*
|
||||
* @author dpvc@mathjax.org (Davide Cervone)
|
||||
*/
|
||||
|
||||
import {length2em} from '../../util/lengths.js';
|
||||
import {Safe, FilterFunction} from './safe.js';
|
||||
|
||||
/**
|
||||
* The default attribute-filtering functions
|
||||
*/
|
||||
export const SafeMethods: {[name: string]: FilterFunction<any, any, any>} = {
|
||||
|
||||
/**
|
||||
* Filter HREF URL's
|
||||
*
|
||||
* @param {Safe<N,T,D>} safe The Safe object being used
|
||||
* @param {string} url The URL being tested
|
||||
* @return {string|null} The URL if OK and null if not
|
||||
*
|
||||
* @template N The HTMLElement node class
|
||||
* @template T The Text node class
|
||||
* @template D The Document class
|
||||
*/
|
||||
filterURL<N, T, D>(safe: Safe<N, T, D>, url: string): string | null {
|
||||
const protocol = (url.match(/^\s*([a-z]+):/i) || [null, ''])[1].toLowerCase();
|
||||
const allow = safe.allow.URLs;
|
||||
return (allow === 'all' || (allow === 'safe' &&
|
||||
(safe.options.safeProtocols[protocol] || !protocol))) ? url : null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Filter a class list
|
||||
*
|
||||
* @param {Safe<N,T,D>} safe The Safe object being used
|
||||
* @param {string} list The class list being tested
|
||||
* @return {string|null} The class list if OK and null if not
|
||||
*
|
||||
* @template N The HTMLElement node class
|
||||
* @template T The Text node class
|
||||
* @template D The Document class
|
||||
*/
|
||||
filterClassList<N, T, D>(safe: Safe<N, T, D>, list: string): string | null {
|
||||
const classes = list.trim().replace(/\s\s+/g, ' ').split(/ /);
|
||||
return classes.map((name) => this.filterClass(safe, name) || '').join(' ').trim().replace(/\s\s+/g, '');
|
||||
},
|
||||
|
||||
/**
|
||||
* Filter a class name
|
||||
*
|
||||
* @param {Safe<N,T,D>} safe The Safe object being used
|
||||
* @param {string} CLASS The class being tested
|
||||
* @return {string|null} The class if OK and null if not
|
||||
*
|
||||
* @template N The HTMLElement node class
|
||||
* @template T The Text node class
|
||||
* @template D The Document class
|
||||
*/
|
||||
filterClass<N, T, D>(safe: Safe<N, T, D>, CLASS: string): string | null {
|
||||
const allow = safe.allow.classes;
|
||||
return (allow === 'all' || (allow === 'safe' && CLASS.match(safe.options.classPattern))) ? CLASS : null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Filter ids
|
||||
*
|
||||
* @param {Safe<N,T,D>} safe The Safe object being used
|
||||
* @param {string} id The id being tested
|
||||
* @return {string|null} The id if OK and null if not
|
||||
*
|
||||
* @template N The HTMLElement node class
|
||||
* @template T The Text node class
|
||||
* @template D The Document class
|
||||
*/
|
||||
filterID<N, T, D>(safe: Safe<N, T, D>, id: string): string | null {
|
||||
const allow = safe.allow.cssIDs;
|
||||
return (allow === 'all' || (allow === 'safe' && id.match(safe.options.idPattern))) ? id : null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Filter style strings
|
||||
*
|
||||
* @param {Safe<N,T,D>} safe The Safe object being used
|
||||
* @param {string} styles The style string being tested
|
||||
* @return {string} The sanitized style string
|
||||
*
|
||||
* @template N The HTMLElement node class
|
||||
* @template T The Text node class
|
||||
* @template D The Document class
|
||||
*/
|
||||
filterStyles<N, T, D>(safe: Safe<N, T, D>, styles: string): string {
|
||||
if (safe.allow.styles === 'all') return styles;
|
||||
if (safe.allow.styles !== 'safe') return null;
|
||||
const adaptor = safe.adaptor;
|
||||
const options = safe.options;
|
||||
try {
|
||||
//
|
||||
// Create div1 with styles set to the given styles, and div2 with blank styles
|
||||
//
|
||||
const div1 = adaptor.node('div', {style: styles});
|
||||
const div2 = adaptor.node('div');
|
||||
//
|
||||
// Check each allowed style and transfer OK ones to div2
|
||||
// If the style has Top/Right/Bottom/Left, look at all four separately
|
||||
//
|
||||
for (const style of Object.keys(options.safeStyles)) {
|
||||
if (options.styleParts[style]) {
|
||||
for (const sufix of ['Top', 'Right', 'Bottom', 'Left']) {
|
||||
const name = style + sufix;
|
||||
const value = this.filterStyle(safe, name, div1);
|
||||
if (value) {
|
||||
adaptor.setStyle(div2, name, value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const value = this.filterStyle(safe, style, div1);
|
||||
if (value) {
|
||||
adaptor.setStyle(div2, style, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// Return the div2 style string
|
||||
//
|
||||
styles = adaptor.allStyles(div2);
|
||||
} catch (err) {
|
||||
styles = '';
|
||||
}
|
||||
return styles;
|
||||
},
|
||||
|
||||
/**
|
||||
* Filter an individual name:value style pair
|
||||
*
|
||||
* @param {Safe<N,T,D>} safe The Safe object being used
|
||||
* @param {string} style The style name being tested
|
||||
* @param {N} div The temp DIV node containing the style object to be tested
|
||||
* @return {string|null} The sanitized style string or null if invalid
|
||||
*
|
||||
* @template N The HTMLElement node class
|
||||
* @template T The Text node class
|
||||
* @template D The Document class
|
||||
*/
|
||||
filterStyle<N, T, D>(safe: Safe<N, T, D>, style: string, div: N): string | null {
|
||||
const value = safe.adaptor.getStyle(div, style);
|
||||
if (typeof value !== 'string' || value === '' || value.match(/^\s*calc/) ||
|
||||
(value.match(/javascript:/) && !safe.options.safeProtocols.javascript) ||
|
||||
(value.match(/data:/) && !safe.options.safeProtocols.data)) {
|
||||
return null;
|
||||
}
|
||||
const name = style.replace(/Top|Right|Left|Bottom/, '');
|
||||
if (!safe.options.safeStyles[style] && !safe.options.safeStyles[name]) {
|
||||
return null;
|
||||
}
|
||||
return this.filterStyleValue(safe, style, value, div);
|
||||
},
|
||||
|
||||
/**
|
||||
* Filter a style's value, handling compound values (e.g., borders that have widths as well as styles and colors)
|
||||
*
|
||||
* @param {Safe<N,T,D>} safe The Safe object being used
|
||||
* @param {string} style The style name being tested
|
||||
* @param {string} value The value of the style to test
|
||||
* @param {N} div The temp DIV node containing the style object to be tested
|
||||
* @return {string|null} The sanitized style string or null if invalid
|
||||
*
|
||||
* @template N The HTMLElement node class
|
||||
* @template T The Text node class
|
||||
* @template D The Document class
|
||||
*/
|
||||
filterStyleValue<N, T, D>(safe: Safe<N, T, D>, style: string, value: string, div: N): string | null {
|
||||
const name = safe.options.styleLengths[style];
|
||||
if (!name) {
|
||||
return value;
|
||||
}
|
||||
if (typeof name !== 'string') {
|
||||
return this.filterStyleLength(safe, style, value);
|
||||
}
|
||||
const length = this.filterStyleLength(safe, name, safe.adaptor.getStyle(div, name));
|
||||
if (!length) {
|
||||
return null;
|
||||
}
|
||||
safe.adaptor.setStyle(div, name, length);
|
||||
return safe.adaptor.getStyle(div, style);
|
||||
},
|
||||
|
||||
/**
|
||||
* Filter a length value
|
||||
*
|
||||
* @param {Safe<N,T,D>} safe The Safe object being used
|
||||
* @param {string} style The style name being tested
|
||||
* @param {string} value The value of the style to test
|
||||
* @return {string|null} The sanitized length value
|
||||
*
|
||||
* @template N The HTMLElement node class
|
||||
* @template T The Text node class
|
||||
* @template D The Document class
|
||||
*/
|
||||
filterStyleLength<N, T, D>(safe: Safe<N, T, D>, style: string, value: string): string | null {
|
||||
if (!value.match(/^(.+)(em|ex|ch|rem|px|mm|cm|in|pt|pc|%)$/)) return null;
|
||||
const em = length2em(value, 1);
|
||||
const lengths = safe.options.styleLengths[style];
|
||||
const [m, M] = (Array.isArray(lengths) ? lengths : [-safe.options.lengthMax, safe.options.lengthMax]);
|
||||
return (m <= em && em <= M ? value : (em < m ? m : M).toFixed(3).replace(/\.?0+$/, '') + 'em');
|
||||
},
|
||||
|
||||
/**
|
||||
* Filter a font size
|
||||
*
|
||||
* @param {Safe<N,T,D>} safe The Safe object being used
|
||||
* @param {string} size The font size to test
|
||||
* @return {string|null} The sanitized style string or null if invalid
|
||||
*
|
||||
* @template N The HTMLElement node class
|
||||
* @template T The Text node class
|
||||
* @template D The Document class
|
||||
*/
|
||||
filterFontSize<N, T, D>(safe: Safe<N, T, D>, size: string): string | null {
|
||||
return this.filterStyleLength(safe, 'fontSize', size);
|
||||
},
|
||||
|
||||
/**
|
||||
* Filter scriptsizemultiplier
|
||||
*
|
||||
* @param {Safe<N,T,D>} safe The Safe object being used
|
||||
* @param {string} size The script size multiplier to test
|
||||
* @return {string} The sanitized size
|
||||
*
|
||||
* @template N The HTMLElement node class
|
||||
* @template T The Text node class
|
||||
* @template D The Document class
|
||||
*/
|
||||
filterSizeMultiplier<N, T, D>(safe: Safe<N, T, D>, size: string): string {
|
||||
const [m, M] = safe.options.scriptsizemultiplierRange || [-Infinity, Infinity];
|
||||
return Math.min(M, Math.max(m, parseFloat(size))).toString();
|
||||
},
|
||||
|
||||
/**
|
||||
* Filter scriptLevel
|
||||
*
|
||||
* @param {Safe<N,T,D>} safe The Safe object being used
|
||||
* @param {string} size The scriptlevel to test
|
||||
* @return {string|null} The sanitized scriptlevel or null
|
||||
*
|
||||
* @template N The HTMLElement node class
|
||||
* @template T The Text node class
|
||||
* @template D The Document class
|
||||
*/
|
||||
filterScriptLevel<N, T, D>(safe: Safe<N, T, D>, level: string): string | null {
|
||||
const [m, M] = safe.options.scriptlevelRange || [-Infinity, Infinity];
|
||||
return Math.min(M, Math.max(m, parseInt(level))).toString();
|
||||
},
|
||||
|
||||
/**
|
||||
* Filter a data-* attribute
|
||||
*
|
||||
* @param {Safe<N,T,D>} safe The Safe object being used
|
||||
* @param {string} value The attribute's value
|
||||
* @param {string} id The attribute's id (e.g., data-mjx-variant)
|
||||
* @return {number|null} The sanitized value or null
|
||||
*
|
||||
* @template N The HTMLElement node class
|
||||
* @template T The Text node class
|
||||
* @template D The Document class
|
||||
*/
|
||||
filterData<N, T, D>(safe: Safe<N, T, D>, value: string, id: string): string | null {
|
||||
return (id.match(safe.options.dataPattern) ? value : null);
|
||||
}
|
||||
|
||||
};
|
||||
270
node_modules/mathjax-full/ts/ui/safe/safe.ts
generated
vendored
Normal file
270
node_modules/mathjax-full/ts/ui/safe/safe.ts
generated
vendored
Normal file
@@ -0,0 +1,270 @@
|
||||
/*************************************************************
|
||||
*
|
||||
* Copyright (c) 2020-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 Support for the safe extension
|
||||
*
|
||||
* @author dpvc@mathjax.org (Davide Cervone)
|
||||
*/
|
||||
|
||||
import {Property} from '../../core/Tree/Node.js';
|
||||
import {MmlNode} from '../../core/MmlTree/MmlNode.js';
|
||||
import {MathItem} from '../../core/MathItem.js';
|
||||
import {MathDocument} from '../../core/MathDocument.js';
|
||||
import {OptionList, expandable} from '../../util/Options.js';
|
||||
import {DOMAdaptor} from '../../core/DOMAdaptor.js';
|
||||
import {SafeMethods} from './SafeMethods.js';
|
||||
|
||||
|
||||
/**
|
||||
* Function type for filtering attributes
|
||||
*
|
||||
* @template N The HTMLElement node class
|
||||
* @template T The Text node class
|
||||
* @template D The Document class
|
||||
*/
|
||||
export type FilterFunction<N, T, D> = (safe: Safe<N, T, D>, value: Property, ...args: any[]) => Property;
|
||||
|
||||
/**
|
||||
* The Safe object for sanitizing the internal MathML representation of an expression
|
||||
*
|
||||
* @template N The HTMLElement node class
|
||||
* @template T The Text node class
|
||||
* @template D The Document class
|
||||
*/
|
||||
export class Safe<N, T, D> {
|
||||
|
||||
/**
|
||||
* The options controlling the handling of the safe extension
|
||||
*/
|
||||
public static OPTIONS: OptionList = {
|
||||
allow: {
|
||||
//
|
||||
// Values can be "all", "safe", or "none"
|
||||
//
|
||||
URLs: 'safe', // safe are in safeProtocols below
|
||||
classes: 'safe', // safe start with mjx- (can be set by pattern below)
|
||||
cssIDs: 'safe', // safe start with mjx- (can be set by pattern below)
|
||||
styles: 'safe' // safe are in safeStyles below
|
||||
},
|
||||
//
|
||||
// Largest padding/border/margin, etc. in em's
|
||||
//
|
||||
lengthMax: 3,
|
||||
//
|
||||
// Valid range for scriptsizemultiplier
|
||||
//
|
||||
scriptsizemultiplierRange: [.6, 1],
|
||||
//
|
||||
// Valid range for scriptlevel
|
||||
//
|
||||
scriptlevelRange: [-2, 2],
|
||||
//
|
||||
// Pattern for allowed class names
|
||||
//
|
||||
classPattern: /^mjx-[-a-zA-Z0-9_.]+$/,
|
||||
//
|
||||
// Pattern for allowed ids
|
||||
//
|
||||
idPattern: /^mjx-[-a-zA-Z0-9_.]+$/,
|
||||
//
|
||||
// Pattern for data attributes
|
||||
//
|
||||
dataPattern: /^data-mjx-/,
|
||||
//
|
||||
// Which URL protocols are allowed
|
||||
//
|
||||
safeProtocols: expandable({
|
||||
http: true,
|
||||
https: true,
|
||||
file: true,
|
||||
javascript: false,
|
||||
data: false
|
||||
}),
|
||||
//
|
||||
// Which styles are allowed
|
||||
//
|
||||
safeStyles: expandable({
|
||||
color: true,
|
||||
backgroundColor: true,
|
||||
border: true,
|
||||
cursor: true,
|
||||
margin: true,
|
||||
padding: true,
|
||||
textShadow: true,
|
||||
fontFamily: true,
|
||||
fontSize: true,
|
||||
fontStyle: true,
|
||||
fontWeight: true,
|
||||
opacity: true,
|
||||
outline: true
|
||||
}),
|
||||
//
|
||||
// CSS styles that have Top/Right/Bottom/Left versions
|
||||
//
|
||||
styleParts: expandable({
|
||||
border: true,
|
||||
padding: true,
|
||||
margin: true,
|
||||
outline: true
|
||||
}),
|
||||
//
|
||||
// CSS styles that are lengths needing max/min testing
|
||||
// A string value means test that style value;
|
||||
// An array gives [min,max] in em's
|
||||
// Otherwise use [-lengthMax,lengthMax] from above
|
||||
//
|
||||
styleLengths: expandable({
|
||||
borderTop: 'borderTopWidth',
|
||||
borderRight: 'borderRightWidth',
|
||||
borderBottom: 'borderBottomWidth',
|
||||
borderLeft: 'borderLeftWidth',
|
||||
paddingTop: true,
|
||||
paddingRight: true,
|
||||
paddingBottom: true,
|
||||
paddingLeft: true,
|
||||
marginTop: true,
|
||||
marginRight: true,
|
||||
marginBottom: true,
|
||||
marginLeft: true,
|
||||
outlineTop: true,
|
||||
outlineRight: true,
|
||||
outlineBottom: true,
|
||||
outlineLeft: true,
|
||||
fontSize: [.707, 1.44]
|
||||
})
|
||||
};
|
||||
|
||||
/**
|
||||
* The attribute-to-filter-method mapping
|
||||
*/
|
||||
public filterAttributes: Map<string, string> = new Map([
|
||||
//
|
||||
// Methods called for MathML attribute processing
|
||||
//
|
||||
['href', 'filterURL'],
|
||||
['src', 'filterURL'],
|
||||
['altimg', 'filterURL'],
|
||||
['class', 'filterClassList'],
|
||||
['style', 'filterStyles'],
|
||||
['id', 'filterID'],
|
||||
['fontsize', 'filterFontSize'],
|
||||
['mathsize', 'filterFontSize'],
|
||||
['scriptminsize', 'filterFontSize'],
|
||||
['scriptsizemultiplier', 'filterSizeMultiplier'],
|
||||
['scriptlevel', 'filterScriptLevel'],
|
||||
['data-', 'filterData']
|
||||
]);
|
||||
|
||||
/**
|
||||
* The safe options from the document option list
|
||||
*/
|
||||
public options: OptionList;
|
||||
|
||||
/**
|
||||
* Shorthand for options.allow
|
||||
*/
|
||||
public allow: OptionList;
|
||||
|
||||
/**
|
||||
* The DOM adaptor from the document
|
||||
*/
|
||||
public adaptor: DOMAdaptor<N, T, D>;
|
||||
|
||||
/**
|
||||
* The methods for filtering the MathML attributes
|
||||
*/
|
||||
public filterMethods: {[name: string]: FilterFunction<N, T, D>} = {
|
||||
...SafeMethods
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {MathDocument<N,T,D>} document The MathDocument we are sanitizing
|
||||
* @param {OptionList} options The safeOptions from the document
|
||||
*/
|
||||
constructor(document: MathDocument<N, T, D>, options: OptionList) {
|
||||
this.adaptor = document.adaptor;
|
||||
this.options = options;
|
||||
this.allow = this.options.allow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize a MathItem's root MathML tree
|
||||
*
|
||||
* @param {MathItem<N,T,D>} math The MathItem to sanitize
|
||||
* @param {MathDocument<N,T,D>} document The MathDocument in which it lives
|
||||
*/
|
||||
public sanitize(math: MathItem<N, T, D>, document: MathDocument<N, T, D>) {
|
||||
try {
|
||||
math.root.walkTree(this.sanitizeNode.bind(this));
|
||||
} catch (err) {
|
||||
document.options.compileError(document, math, err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize a node's attributes
|
||||
*
|
||||
* @param {MmlNode} node The node to sanitize
|
||||
*/
|
||||
protected sanitizeNode(node: MmlNode) {
|
||||
const attributes = node.attributes.getAllAttributes();
|
||||
for (const id of Object.keys(attributes)) {
|
||||
const method = this.filterAttributes.get(id);
|
||||
if (method) {
|
||||
const value = this.filterMethods[method](this, attributes[id]);
|
||||
if (value) {
|
||||
if (value !== (typeof value === 'number' ? parseFloat(attributes[id] as string) : attributes[id])) {
|
||||
attributes[id] = value;
|
||||
}
|
||||
} else {
|
||||
delete attributes[id];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize a MathML input attribute
|
||||
*
|
||||
* @param {string} id The name of the attribute
|
||||
* @param {string} value The value of the attribute
|
||||
* @return {string|null} The sanitized value
|
||||
*/
|
||||
public mmlAttribute(id: string, value: string): string | null {
|
||||
if (id === 'class') return null;
|
||||
const method = this.filterAttributes.get(id);
|
||||
const filter = (method || (id.substr(0, 5) === 'data-' ? this.filterAttributes.get('data-') : null));
|
||||
if (!filter) {
|
||||
return value;
|
||||
}
|
||||
const result = this.filterMethods[filter](this, value, id);
|
||||
return (typeof result === 'number' || typeof result === 'boolean' ? String(result) : result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize a list of class names
|
||||
*
|
||||
* @param {string[]} list The list of class names
|
||||
* @return {string[]} The sanitized list
|
||||
*/
|
||||
public mmlClassList(list: string[]): string[] {
|
||||
return list.map((name) => this.filterMethods.filterClass(this, name) as string)
|
||||
.filter((value) => value !== null);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user