From b50a8e2580fb713459dc37885226688042a5b70f Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Fri, 31 Oct 2025 15:52:04 -0400 Subject: [PATCH] Have browsers fixed this yet? --- .../runtime/lib/compat/svg-inner-html-fix.ts | 118 ------------------ packages/@glimmer/runtime/lib/dom/api.ts | 7 -- packages/@glimmer/runtime/lib/dom/helper.ts | 3 - 3 files changed, 128 deletions(-) delete mode 100644 packages/@glimmer/runtime/lib/compat/svg-inner-html-fix.ts diff --git a/packages/@glimmer/runtime/lib/compat/svg-inner-html-fix.ts b/packages/@glimmer/runtime/lib/compat/svg-inner-html-fix.ts deleted file mode 100644 index ad5c0c879c..0000000000 --- a/packages/@glimmer/runtime/lib/compat/svg-inner-html-fix.ts +++ /dev/null @@ -1,118 +0,0 @@ -import type { - Bounds, - Nullable, - SimpleDocument, - SimpleElement, - SimpleNode, -} from '@glimmer/interfaces'; -import { INSERT_AFTER_BEGIN, INSERT_BEFORE_END, NS_SVG } from '@glimmer/constants'; -import { castToBrowser, localAssert, unwrap } from '@glimmer/debug-util'; -import { clearElement } from '@glimmer/util'; - -import type { DOMOperations } from '../dom/operations'; - -import { moveNodesBefore } from '../dom/operations'; - -// Patch: insertAdjacentHTML on SVG Fix -// Browsers: Safari, IE, Edge, Firefox ~33-34 -// Reason: insertAdjacentHTML does not exist on SVG elements in Safari. It is -// present but throws an exception on IE and Edge. Old versions of -// Firefox create nodes in the incorrect namespace. -// Fix: Since IE and Edge silently fail to create SVG nodes using -// innerHTML, and because Firefox may create nodes in the incorrect -// namespace using innerHTML on SVG elements, an HTML-string wrapping -// approach is used. A pre/post SVG tag is added to the string, then -// that whole string is added to a div. The created nodes are plucked -// out and applied to the target location on DOM. -export function applySVGInnerHTMLFix( - document: Nullable, - DOMClass: typeof DOMOperations, - svgNamespace: typeof NS_SVG -): typeof DOMOperations { - if (!document) return DOMClass; - - if (!shouldApplyFix(document, svgNamespace)) { - return DOMClass; - } - - const div = document.createElement('div'); - - return class DOMChangesWithSVGInnerHTMLFix extends DOMClass { - override insertHTMLBefore( - parent: SimpleElement, - nextSibling: Nullable, - html: string - ): Bounds { - if (html === '') { - return super.insertHTMLBefore(parent, nextSibling, html); - } - - if (parent.namespaceURI !== svgNamespace) { - return super.insertHTMLBefore(parent, nextSibling, html); - } - - return fixSVG(parent, div, html, nextSibling); - } - }; -} - -function fixSVG( - parent: SimpleElement, - div: SimpleElement, - html: string, - reference: Nullable -): Bounds { - localAssert(html !== '', 'html cannot be empty'); - - let source: SimpleNode; - - // This is important, because descendants of the integration - // point are parsed in the HTML namespace - if (parent.tagName.toUpperCase() === 'FOREIGNOBJECT') { - // IE, Edge: also do not correctly support using `innerHTML` on SVG - // namespaced elements. So here a wrapper is used. - const wrappedHtml = '' + html + ''; - - clearElement(div); - div.insertAdjacentHTML(INSERT_AFTER_BEGIN, wrappedHtml); - - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- @fixme - source = div.firstChild!.firstChild!; - } else { - // IE, Edge: also do not correctly support using `innerHTML` on SVG - // namespaced elements. So here a wrapper is used. - const wrappedHtml = '' + html + ''; - - clearElement(div); - div.insertAdjacentHTML(INSERT_AFTER_BEGIN, wrappedHtml); - - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- @fixme - source = div.firstChild!; - } - - return moveNodesBefore(source, parent, reference); -} - -function shouldApplyFix(document: SimpleDocument, svgNamespace: typeof NS_SVG) { - const svg = document.createElementNS(svgNamespace, 'svg'); - - try { - svg.insertAdjacentHTML(INSERT_BEFORE_END, ''); - } catch { - // IE, Edge: Will throw, insertAdjacentHTML is unsupported on SVG - // Safari: Will throw, insertAdjacentHTML is not present on SVG - } finally { - // FF: Old versions will create a node in the wrong namespace - if ( - svg.childNodes.length === 1 && - castToBrowser(unwrap(svg.firstChild), 'SVG').namespaceURI === NS_SVG - ) { - // The test worked as expected, no fix required - // eslint-disable-next-line no-unsafe-finally - return false; - } - - // eslint-disable-next-line no-unsafe-finally - return true; - } -} diff --git a/packages/@glimmer/runtime/lib/dom/api.ts b/packages/@glimmer/runtime/lib/dom/api.ts index 90339aac1c..ad2b1ee988 100644 --- a/packages/@glimmer/runtime/lib/dom/api.ts +++ b/packages/@glimmer/runtime/lib/dom/api.ts @@ -6,10 +6,8 @@ import type { SimpleDocument, SimpleElement, } from '@glimmer/interfaces'; -import { NS_SVG } from '@glimmer/constants'; import { castToSimple } from '@glimmer/debug-util'; -import { applySVGInnerHTMLFix } from '../compat/svg-inner-html-fix'; import { applyTextNodeMergingFix } from '../compat/text-node-merging-fix'; import { DOMOperations } from './operations'; @@ -40,11 +38,6 @@ appliedTreeConstruction = applyTextNodeMergingFix( doc, appliedTreeConstruction ) as typeof TreeConstruction; -appliedTreeConstruction = applySVGInnerHTMLFix( - doc, - appliedTreeConstruction, - NS_SVG -) as typeof TreeConstruction; export const DOMTreeConstruction = appliedTreeConstruction; export type DOMTreeConstruction = TreeConstruction; diff --git a/packages/@glimmer/runtime/lib/dom/helper.ts b/packages/@glimmer/runtime/lib/dom/helper.ts index 2e37101861..3f72d85557 100644 --- a/packages/@glimmer/runtime/lib/dom/helper.ts +++ b/packages/@glimmer/runtime/lib/dom/helper.ts @@ -5,10 +5,8 @@ import type { SimpleElement, SimpleNode, } from '@glimmer/interfaces'; -import { NS_SVG } from '@glimmer/constants'; import { castToSimple } from '@glimmer/debug-util'; -import { applySVGInnerHTMLFix } from '../compat/svg-inner-html-fix'; import { applyTextNodeMergingFix } from '../compat/text-node-merging-fix'; import { BLACKLIST_TABLE, DOMOperations } from './operations'; @@ -93,7 +91,6 @@ export class DOMChangesImpl extends DOMOperations implements GlimmerTreeChanges let helper = DOMChangesImpl; helper = applyTextNodeMergingFix(doc, helper) as typeof DOMChangesImpl; -helper = applySVGInnerHTMLFix(doc, helper, NS_SVG) as typeof DOMChangesImpl; export const DOMChanges = helper; export { DOMTreeConstruction } from './api';