From ec04842d9354fc9bca55ddf1b2ef812d5c7fff75 Mon Sep 17 00:00:00 2001 From: "Davide P. Cervone" Date: Wed, 2 Sep 2026 10:29:08 -0400 Subject: [PATCH] Use the ui/safe data URL filter for the values used in `\data` TeX macros --- ts/handlers/html/HTMLDomStrings.ts | 5 ++--- ts/input/mathml.ts | 13 +++++++++++++ ts/input/mathml/MathMLCompile.ts | 14 ++++++++++++++ ts/input/tex/html/HtmlMethods.ts | 7 ++++++- ts/ui/safe/SafeHandler.ts | 13 +++++++------ ts/ui/safe/SafeMethods.ts | 2 +- 6 files changed, 43 insertions(+), 11 deletions(-) diff --git a/ts/handlers/html/HTMLDomStrings.ts b/ts/handlers/html/HTMLDomStrings.ts index 13c742bbe8..046324309f 100644 --- a/ts/handlers/html/HTMLDomStrings.ts +++ b/ts/handlers/html/HTMLDomStrings.ts @@ -250,8 +250,8 @@ export class HTMLDomStrings { /** * Handle an arbitrary DOM node: * Check the class to see if it matches the processHtmlClass regex - * If the node has a child and is not marked as created by MathJax (data-MJX) - * and either it is marked as restarting processing or is not a tag to be skipped, then + * If the node has a child and either it is marked as restarting processing + * or is not a tag to be skipped, then * Save the next node (if there is one) and whether we are currently ignoring content * Move to the first child node * Update whether we are ignoring content @@ -271,7 +271,6 @@ export class HTMLDomStrings { let next; if ( this.adaptor.firstChild(node) && - !this.adaptor.getAttribute(node, 'data-MJX') && (process || !this.skipHtmlTags.exec(tname)) ) { if (this.adaptor.next(node)) { diff --git a/ts/input/mathml.ts b/ts/input/mathml.ts index d1ab25d50e..ef743a2b1b 100644 --- a/ts/input/mathml.ts +++ b/ts/input/mathml.ts @@ -152,6 +152,19 @@ export class MathML extends AbstractInputJax< this.mathml.setMmlFactory(mmlFactory); } + /** + * Set the filter functions for the Safe extension in the MathCompile class. + * + * @param {(string, string) => string} filterAttribute The function to filter attributes + * @param {(list: string[]) => string[]} filterClassList The function to filter classes + */ + public setFilters( + filterAttribute: (name: string, value: string) => string, + filterClassList: (list: string[]) => string[], + ) : void { + this.mathml.setFilters(filterAttribute, filterClassList); + } + /** * Don't process strings (process nodes) * diff --git a/ts/input/mathml/MathMLCompile.ts b/ts/input/mathml/MathMLCompile.ts index a525c7a6a1..ae84c2d9d0 100644 --- a/ts/input/mathml/MathMLCompile.ts +++ b/ts/input/mathml/MathMLCompile.ts @@ -287,6 +287,20 @@ export class MathMLCompile { return list; } + /** + * Set the filter functions for the Safe extension. + * + * @param {(string, string) => string} filterAttribute The function to filter attributes + * @param {(list: string[]) => string[]} filterClassList The function to filter classes + */ + public setFilters( + filterAttribute: (name: string, value: string) => string, + filterClassList: (list: string[]) => string[], + ) : void { + this.filterAttribute = filterAttribute; + this.filterClassList = filterClassList; + } + /** * Convert the children of the MathML node and add them to the MmlNode * diff --git a/ts/input/tex/html/HtmlMethods.ts b/ts/input/tex/html/HtmlMethods.ts index 10c9b38e68..fd4f850586 100644 --- a/ts/input/tex/html/HtmlMethods.ts +++ b/ts/input/tex/html/HtmlMethods.ts @@ -67,7 +67,12 @@ const HtmlMethods: { [key: string]: ParseMethod } = { if (!isLegalAttributeName(key)) { texError(COMPONENT, 'InvalidHTMLAttr', `data-${key}`); } - NodeUtil.setAttribute(arg, `data-${key}`, data[key]); + const safe = parser.configuration.packageData.get('safe'); + const id = `data-${key}`; + const value = safe ? safe.filterMethods.filterData(safe, data[key], id) : data[key]; + if (value) { + NodeUtil.setAttribute(arg, id, value); + } } parser.Push(arg); }, diff --git a/ts/ui/safe/SafeHandler.ts b/ts/ui/safe/SafeHandler.ts index 7549026337..de7ae579f1 100644 --- a/ts/ui/safe/SafeHandler.ts +++ b/ts/ui/safe/SafeHandler.ts @@ -29,6 +29,8 @@ import { } from '../../core/MathDocument.js'; import { Handler } from '../../core/Handler.js'; import { DOM, DOM_TYPES, Constructor } from '../../types/Types.js'; +import type { MathML } from '../../input/mathml.js'; +import type { TeX } from '../../input/tex.js'; import { Safe } from './safe.js'; @@ -140,13 +142,12 @@ export function SafeMathDocumentMixin< this.safe = new this.options.SafeClass(this, this.options.safeOptions); 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 + (jax as MathML).setFilters( + this.safe.mmlAttribute.bind(this.safe), + this.safe.mmlClassList.bind(this.safe) ); } else if (jax.name.match(/TeX/)) { + (jax as TeX).parseOptions.packageData.set('safe', this.safe); jax.postFilters.add(this.sanitize.bind(jax), -5.5); } } @@ -156,7 +157,7 @@ export function SafeMathDocumentMixin< * @param {object} data The argument containing math item and document * @param {MathItem} data.math The math item to sanitize * @param {SafeMathDocument} data.document The document to use for the - * filter (note: this has been bound to the input jax) + * filter (note: `this` has been bound to the input jax) */ protected sanitize(data: { math: MathItem; diff --git a/ts/ui/safe/SafeMethods.ts b/ts/ui/safe/SafeMethods.ts index d8cb4442a0..3d61ddb2f2 100644 --- a/ts/ui/safe/SafeMethods.ts +++ b/ts/ui/safe/SafeMethods.ts @@ -319,7 +319,7 @@ export const SafeMethods: { [name: string]: FilterFunction } = { * @param {Safe} 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) - * @returns {number|null} The sanitized value or null + * @returns {string|null} The sanitized value or null * * @template N The HTMLElement node class * @template T The Text node class