Added a basic DOM diff algorithm
This commit is contained in:
parent
9bd5e71205
commit
b4a4e78c96
@ -1,4 +1,5 @@
|
||||
import { Application } from "./Application"
|
||||
import { Diff } from "./Diff"
|
||||
import { findAll } from "./utils"
|
||||
import * as actions from "./actions"
|
||||
|
||||
@ -23,6 +24,14 @@ export class AnimeNotifier {
|
||||
this.app.run()
|
||||
}
|
||||
|
||||
reloadContent() {
|
||||
return fetch("/_" + this.app.currentPath, {
|
||||
credentials: "same-origin"
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(html => Diff.innerHTML(this.app.content, html))
|
||||
}
|
||||
|
||||
loading(isLoading: boolean) {
|
||||
if(isLoading) {
|
||||
this.app.loading.classList.remove(this.app.fadeOutClass)
|
||||
|
@ -109,6 +109,7 @@ export class Application {
|
||||
}
|
||||
|
||||
setContent(html: string) {
|
||||
// Diff.innerHTML(this.content, html)
|
||||
this.content.innerHTML = html
|
||||
this.ajaxify(this.content)
|
||||
this.markActiveLinks(this.content)
|
||||
|
@ -1,5 +1,63 @@
|
||||
export class Diff {
|
||||
static update(element: HTMLElement, html: string) {
|
||||
element.innerHTML = html
|
||||
static childNodes(aRoot: HTMLElement, bRoot: HTMLElement) {
|
||||
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] as HTMLElement
|
||||
|
||||
if(i >= bChild.length) {
|
||||
aRoot.removeChild(a)
|
||||
continue
|
||||
}
|
||||
|
||||
let b = bChild[i] as HTMLElement
|
||||
|
||||
if(i >= aChild.length) {
|
||||
aRoot.appendChild(b)
|
||||
continue
|
||||
}
|
||||
|
||||
if(a.nodeName !== b.nodeName || a.nodeType !== b.nodeType) {
|
||||
aRoot.replaceChild(b, a)
|
||||
continue
|
||||
}
|
||||
|
||||
if(a.nodeType === Node.ELEMENT_NODE) {
|
||||
let removeAttributes: Attr[] = []
|
||||
|
||||
for(let x = 0; x < a.attributes.length; x++) {
|
||||
let attrib = a.attributes[x]
|
||||
|
||||
if(attrib.specified) {
|
||||
if(!b.hasAttribute(attrib.name)) {
|
||||
removeAttributes.push(attrib)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(let attr of removeAttributes) {
|
||||
a.removeAttributeNode(attr)
|
||||
}
|
||||
|
||||
for(let x = 0; x < b.attributes.length; x++) {
|
||||
let attrib = b.attributes[x]
|
||||
|
||||
if(attrib.specified) {
|
||||
a.setAttribute(attrib.name, b.getAttribute(attrib.name))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Diff.childNodes(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
static innerHTML(aRoot: HTMLElement, html: string) {
|
||||
let bRoot = document.createElement("main")
|
||||
bRoot.innerHTML = html
|
||||
|
||||
Diff.childNodes(aRoot, bRoot)
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
import { Application } from "./Application"
|
||||
import { AnimeNotifier } from "./AnimeNotifier"
|
||||
import { Diff } from "./Diff"
|
||||
|
||||
// Save new data from an input field
|
||||
export function save(arn: AnimeNotifier, input: HTMLInputElement | HTMLTextAreaElement) {
|
||||
@ -108,11 +107,7 @@ export function addAnimeToCollection(arn: AnimeNotifier, button: HTMLElement) {
|
||||
throw body
|
||||
}
|
||||
|
||||
return fetch("/_" + arn.app.currentPath, {
|
||||
credentials: "same-origin"
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(html => Diff.update(arn.app.content, html))
|
||||
return arn.reloadContent()
|
||||
})
|
||||
.catch(console.error)
|
||||
.then(() => arn.loading(false))
|
||||
|
@ -4,9 +4,7 @@ import { AnimeNotifier } from "./AnimeNotifier"
|
||||
let app = new Application()
|
||||
let arn = new AnimeNotifier(app)
|
||||
|
||||
document.addEventListener("DOMContentLoaded", arn.onContentLoaded.bind(arn))
|
||||
document.addEventListener("readystatechange", arn.onReadyStateChange.bind(arn))
|
||||
document.addEventListener("DOMContentLoaded", arn.onContentLoaded.bind(arn))
|
||||
document.addEventListener("keydown", arn.onKeyDown.bind(arn), false)
|
||||
|
||||
window.addEventListener("popstate", arn.onPopState.bind(arn))
|
||||
// window.addEventListener("resize", arn.onResize.bind(arn))
|
||||
window.addEventListener("popstate", arn.onPopState.bind(arn))
|
@ -1,6 +1,8 @@
|
||||
export function* findAll(className: string) {
|
||||
let elements = document.getElementsByClassName(className)
|
||||
|
||||
// getElementsByClassName failed for some reason.
|
||||
// TODO: Test getElementsByClassName again.
|
||||
let elements = document.querySelectorAll("." + className)
|
||||
|
||||
for(let i = 0; i < elements.length; ++i) {
|
||||
yield elements[i] as HTMLElement
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user