Precise DOM morphing
morphing typescript dom
at main 84 lines 2.2 kB view raw
1export function dom(html: string): HTMLElement { 2 const tmp = document.createElement("div") 3 tmp.innerHTML = html.trim() 4 return tmp.firstChild as HTMLElement 5} 6 7export class Mutations { 8 records: Array<MutationRecord> = [] 9 10 push(...records: MutationRecord[]) { 11 this.records.push(...records) 12 } 13 14 get count(): number { 15 return this.records.length 16 } 17 18 get childListChanges(): number { 19 return this.records.filter((m) => m.type === "childList").length 20 } 21 22 get elementsAdded(): number { 23 return this.records.filter( 24 (m) => m.type === "childList" && Array.from(m.addedNodes).some((n) => n.nodeType === Node.ELEMENT_NODE), 25 ).length 26 } 27 28 get elementsRemoved(): number { 29 return this.records.filter( 30 (m) => m.type === "childList" && Array.from(m.removedNodes).some((n) => n.nodeType === Node.ELEMENT_NODE), 31 ).length 32 } 33 34 get textNodesAdded(): number { 35 return this.records.filter( 36 (m) => m.type === "childList" && Array.from(m.addedNodes).some((n) => n.nodeType === Node.TEXT_NODE), 37 ).length 38 } 39 40 get textNodesRemoved(): number { 41 return this.records.filter( 42 (m) => m.type === "childList" && Array.from(m.removedNodes).some((n) => n.nodeType === Node.TEXT_NODE), 43 ).length 44 } 45 46 get nodesAdded(): number { 47 return this.records.filter((m) => m.type === "childList" && m.addedNodes.length > 0).length 48 } 49 50 get nodesRemoved(): number { 51 return this.records.filter((m) => m.type === "childList" && m.removedNodes.length > 0).length 52 } 53 54 get attributeChanges(): number { 55 return this.records.filter((m) => m.type === "attributes").length 56 } 57 58 get characterDataChanges(): number { 59 return this.records.filter((m) => m.type === "characterData").length 60 } 61} 62 63export function observeMutations(target: Node, callback: () => void): Mutations { 64 const mutations = new Mutations() 65 const observer = new MutationObserver((records) => { 66 mutations.push(...records) 67 }) 68 69 observer.observe(target, { 70 childList: true, 71 attributes: true, 72 characterData: true, 73 subtree: true, 74 }) 75 76 callback() 77 78 // Flush any pending mutations 79 const records = observer.takeRecords() 80 mutations.push(...records) 81 82 observer.disconnect() 83 return mutations 84}