UNPKG

ember-material-icons

Version:

Google Material icons for your ember-cli app

108 lines (83 loc) 3.65 kB
import { Bounds } from '../bounds'; import { DOMChanges, DOMTreeConstruction } from '../dom/helper'; import { Option } from '@glimmer/util'; // Patch: Adjacent text node merging fix // Browsers: IE, Edge, Firefox w/o inspector open // Reason: These browsers will merge adjacent text nodes. For exmaple given // <div>Hello</div> with div.insertAdjacentHTML(' world') browsers // with proper behavior will populate div.childNodes with two items. // These browsers will populate it with one merged node instead. // Fix: Add these nodes to a wrapper element, then iterate the childNodes // of that wrapper and move the nodes to their target location. Note // that potential SVG bugs will have been handled before this fix. // Note that this fix must only apply to the previous text node, as // the base implementation of `insertHTMLBefore` already handles // following text nodes correctly. export function domChanges(document: Option<Document>, DOMChangesClass: typeof DOMChanges): typeof DOMChanges { if (!document) return DOMChangesClass; if (!shouldApplyFix(document)) { return DOMChangesClass; } return class DOMChangesWithTextNodeMergingFix extends DOMChangesClass { private uselessComment: Comment; constructor(document: Document) { super(document); this.uselessComment = document.createComment(''); } insertHTMLBefore(parent: HTMLElement, nextSibling: Node, html: string): Bounds { if (html === null) { return super.insertHTMLBefore(parent, nextSibling, html); } let didSetUselessComment = false; let nextPrevious = nextSibling ? nextSibling.previousSibling : parent.lastChild; if (nextPrevious && nextPrevious instanceof Text) { didSetUselessComment = true; parent.insertBefore(this.uselessComment, nextSibling); } let bounds = super.insertHTMLBefore(parent, nextSibling, html); if (didSetUselessComment) { parent.removeChild(this.uselessComment); } return bounds; } }; } export function treeConstruction(document: Option<Document>, TreeConstructionClass: typeof DOMTreeConstruction): typeof DOMTreeConstruction { if (!document) return TreeConstructionClass; if (!shouldApplyFix(document)) { return TreeConstructionClass; } return class TreeConstructionWithTextNodeMergingFix extends TreeConstructionClass { private uselessComment: Comment; constructor(document: Document) { super(document); this.uselessComment = this.createComment('') as Comment; } insertHTMLBefore(parent: HTMLElement, html: string, reference: Node): Bounds { if (html === null) { return super.insertHTMLBefore(parent, html, reference); } let didSetUselessComment = false; let nextPrevious = reference ? reference.previousSibling : parent.lastChild; if (nextPrevious && nextPrevious instanceof Text) { didSetUselessComment = true; parent.insertBefore(this.uselessComment, reference); } let bounds = super.insertHTMLBefore(parent, html, reference); if (didSetUselessComment) { parent.removeChild(this.uselessComment); } return bounds; } }; } function shouldApplyFix(document: Document) { let mergingTextDiv: HTMLDivElement = document.createElement('div'); mergingTextDiv.innerHTML = 'first'; mergingTextDiv.insertAdjacentHTML('beforeEnd', 'second'); if (mergingTextDiv.childNodes.length === 2) { // It worked as expected, no fix required return false; } return true; }