// import { MutationQueue, CustomMutationQueue } from "./MutationQueue" // export class Diff { // static persistentClasses = new Set() // static persistentAttributes = new Set() // // Reuse container for diffs to avoid memory allocation // static container: HTMLElement // static rootContainer: HTMLElement // static mutations: CustomMutationQueue = new CustomMutationQueue() // // Callbacks // static onStart: () => void // static onMutationsQueued: (elem: HTMLElement) => void // // innerHTML will diff the element with the given HTML string and apply DOM mutations. // static innerHTML(aRoot: HTMLElement, html: string): Promise { // return new Promise((resolve, reject) => { // if(!Diff.container) { // Diff.container = document.createElement("main") // } // Diff.container.innerHTML = html // if(Diff.onStart) { // Diff.onStart() // } // Diff.childNodes(aRoot, Diff.container) // this.mutations.wait(resolve) // }) // } // // root will diff the document root element with the given HTML string and apply DOM mutations. // static root(aRoot: HTMLElement, html: string) { // return new Promise((resolve, reject) => { // if(!Diff.rootContainer) { // Diff.rootContainer = document.createElement("html") // } // Diff.rootContainer.innerHTML = html.replace("", "") // if(Diff.onStart) { // Diff.onStart() // } // Diff.childNodes(aRoot.getElementsByTagName("body")[0], Diff.rootContainer.getElementsByTagName("body")[0]) // this.mutations.wait(resolve) // }) // } // // childNodes diffs the child nodes of 2 given elements and applies DOM mutations. // static childNodes(aRoot: Node, bRoot: Node) { // let aChild = [...aRoot.childNodes] // let bChild = [...bRoot.childNodes] // let numNodes = Math.max(aChild.length, bChild.length) // for(let i = 0; i < numNodes; i++) { // let a = aChild[i] // // Remove nodes at the end of a that do not exist in b // if(i >= bChild.length) { // this.mutations.queue(() => aRoot.removeChild(a)) // continue // } // let b = bChild[i] // // If a doesn't have that many nodes, simply append at the end of a // if(i >= aChild.length) { // this.mutations.queue(() => aRoot.appendChild(b)) // if(Diff.onMutationsQueued && b.nodeType === Node.ELEMENT_NODE) { // Diff.onMutationsQueued(b as HTMLElement) // } // continue // } // // If it's a completely different HTML tag or node type, replace it // if(a.nodeName !== b.nodeName || a.nodeType !== b.nodeType) { // this.mutations.queue(() => aRoot.replaceChild(b, a)) // if(Diff.onMutationsQueued && b.nodeType === Node.ELEMENT_NODE) { // Diff.onMutationsQueued(b as HTMLElement) // } // continue // } // // Text node: // // We don't need to check for b to be a text node as well because // // we eliminated different node types in the previous condition. // if(a.nodeType === Node.TEXT_NODE) { // this.mutations.queue(() => a.textContent = b.textContent) // continue // } // // HTML element: // if(a.nodeType === Node.ELEMENT_NODE) { // let elemA = a as HTMLElement // let elemB = b as HTMLElement // let removeAttributes: Attr[] = [] // for(let x = 0; x < elemA.attributes.length; x++) { // let attrib = elemA.attributes[x] // if(attrib.specified) { // if(!elemB.hasAttribute(attrib.name) && !Diff.persistentAttributes.has(attrib.name)) { // removeAttributes.push(attrib) // } // } // } // this.mutations.queue(() => { // for(let attr of removeAttributes) { // elemA.removeAttributeNode(attr) // } // }) // for(let x = 0; x < elemB.attributes.length; x++) { // let attrib = elemB.attributes[x] // if(!attrib.specified) { // continue // } // // If the attribute value is exactly the same, skip this attribute. // if(elemA.getAttribute(attrib.name) === attrib.value) { // continue // } // if(attrib.name === "class") { // let classesA = elemA.classList // let classesB = elemB.classList // let removeClasses: string[] = [] // for(let className of classesA) { // if(!classesB.contains(className) && !Diff.persistentClasses.has(className)) { // removeClasses.push(className) // } // } // this.mutations.queue(() => { // for(let className of removeClasses) { // classesA.remove(className) // } // for(let className of classesB) { // if(!classesA.contains(className)) { // classesA.add(className) // } // } // }) // continue // } // this.mutations.queue(() => elemA.setAttribute(attrib.name, attrib.value)) // } // // Special case: Apply state of input elements // if(elemA !== document.activeElement && elemA instanceof HTMLInputElement && elemB instanceof HTMLInputElement) { // this.mutations.queue(() => { // (elemA as HTMLInputElement).value = (elemB as HTMLInputElement).value // }) // } // } // Diff.childNodes(a, b) // if(Diff.onMutationsQueued && a.nodeType === Node.ELEMENT_NODE) { // Diff.onMutationsQueued(a as HTMLElement) // } // } // } // }