diff --git a/framework/core/js/package.json b/framework/core/js/package.json index 6e8909151e..bb2ce5580d 100644 --- a/framework/core/js/package.json +++ b/framework/core/js/package.json @@ -18,7 +18,8 @@ "nanoid": "^3.1.30", "punycode": "^2.1.1", "textarea-caret": "^3.1.0", - "throttle-debounce": "^3.0.1" + "throttle-debounce": "^3.0.1", + "xslt-polyfill": "^1.0.16" }, "devDependencies": { "@flarum/jest-config": "^2.0.0", diff --git a/framework/core/src/Formatter/Formatter.php b/framework/core/src/Formatter/Formatter.php index 51019bfe47..5a4e921060 100644 --- a/framework/core/src/Formatter/Formatter.php +++ b/framework/core/src/Formatter/Formatter.php @@ -190,10 +190,61 @@ protected function getRenderer(): Renderer /** * Get the formatter JavaScript. + * + * Injects XSLT polyfill inline before s9e code to support browsers + * that have removed native XSLT support (Chrome 155+, Nov 2026). + * + * @TODO: Remove polyfill injection when s9e/textformatter has a solution for XSLT removal. + * @see https://github.com/s9e/TextFormatter/issues/250 */ public function getJs(): string { - return $this->getComponent('js'); + $s9eJs = $this->getComponent('js'); + + // Try to load XSLT polyfill + // Path 1: Published package (core/js/node_modules) + $polyfillPath = __DIR__.'/../../js/node_modules/xslt-polyfill/xslt-polyfill.min.js'; + + if (! file_exists($polyfillPath)) { + // Path 2: Monorepo hoisted (framework/node_modules) + $polyfillPath = __DIR__.'/../../../../node_modules/xslt-polyfill/xslt-polyfill.min.js'; + } + + if (! file_exists($polyfillPath)) { + // Polyfill not available, return s9e JS without it + return $s9eJs; + } + + $polyfillJs = file_get_contents($polyfillPath); + + // Inject polyfill inline before s9e code + return <<