import { Bounds, ConcreteBounds } from '../bounds';
import { moveNodesBefore, DOMChanges, DOMTreeConstruction } from '../dom/helper';
import { Option } from '@glimmer/util';
interface Wrapper {
depth: number;
before: string;
after: string;
}
let innerHTMLWrapper = {
colgroup: { depth: 2, before: '
' },
table: { depth: 1, before: '' },
tbody: { depth: 2, before: '' },
tfoot: { depth: 2, before: '' },
thead: { depth: 2, before: '' },
tr: { depth: 3, before: '' }
};
// Patch: innerHTML Fix
// Browsers: IE9
// Reason: IE9 don't allow us to set innerHTML on col, colgroup, frameset,
// html, style, table, tbody, tfoot, thead, title, tr.
// Fix: Wrap the innerHTML we are about to set in its parents, apply the
// wrapped innerHTML on a div, then move the unwrapped nodes into the
// target position.
export function domChanges(document: Option, DOMChangesClass: typeof DOMChanges): typeof DOMChanges {
if (!document) return DOMChangesClass;
if (!shouldApplyFix(document)) {
return DOMChangesClass;
}
let div = document.createElement('div');
return class DOMChangesWithInnerHTMLFix extends DOMChangesClass {
insertHTMLBefore(parent: HTMLElement, nextSibling: Node, html: string): Bounds {
if (html === null || html === '') {
return super.insertHTMLBefore(parent, nextSibling, html);
}
let parentTag = parent.tagName.toLowerCase();
let wrapper = innerHTMLWrapper[parentTag];
if(wrapper === undefined) {
return super.insertHTMLBefore(parent, nextSibling, html);
}
return fixInnerHTML(parent, wrapper, div, html, nextSibling);
}
};
}
export function treeConstruction(document: Option, DOMTreeConstructionClass: typeof DOMTreeConstruction): typeof DOMTreeConstruction {
if (!document) return DOMTreeConstructionClass;
if (!shouldApplyFix(document)) {
return DOMTreeConstructionClass;
}
let div = document.createElement('div');
return class DOMTreeConstructionWithInnerHTMLFix extends DOMTreeConstructionClass {
insertHTMLBefore(parent: HTMLElement, html: string, reference: Node): Bounds {
if (html === null || html === '') {
return super.insertHTMLBefore(parent, html, reference);
}
let parentTag = parent.tagName.toLowerCase();
let wrapper = innerHTMLWrapper[parentTag];
if(wrapper === undefined) {
return super.insertHTMLBefore(parent, html, reference);
}
return fixInnerHTML(parent, wrapper, div, html, reference);
}
};
}
function fixInnerHTML(parent: HTMLElement, wrapper: Wrapper, div: HTMLElement, html: string, reference: Node): Bounds {
let wrappedHtml = wrapper.before + html + wrapper.after;
div.innerHTML = wrappedHtml;
let parentNode: Node = div;
for (let i=0; i