diff --git a/scripts/AnimeNotifier.ts b/scripts/AnimeNotifier.ts index 82eed8af..61622040 100644 --- a/scripts/AnimeNotifier.ts +++ b/scripts/AnimeNotifier.ts @@ -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) diff --git a/scripts/Application.ts b/scripts/Application.ts index 7489d0f6..54f60e7f 100644 --- a/scripts/Application.ts +++ b/scripts/Application.ts @@ -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) diff --git a/scripts/Diff.ts b/scripts/Diff.ts index d77eac83..394d06dd 100644 --- a/scripts/Diff.ts +++ b/scripts/Diff.ts @@ -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) } } \ No newline at end of file diff --git a/scripts/actions.ts b/scripts/actions.ts index 04503c7c..ea847eab 100644 --- a/scripts/actions.ts +++ b/scripts/actions.ts @@ -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)) diff --git a/scripts/main.ts b/scripts/main.ts index 32c2304f..05af48fb 100644 --- a/scripts/main.ts +++ b/scripts/main.ts @@ -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)) \ No newline at end of file +window.addEventListener("popstate", arn.onPopState.bind(arn)) \ No newline at end of file diff --git a/scripts/utils.ts b/scripts/utils.ts index 560d25ad..41ebc19e 100644 --- a/scripts/utils.ts +++ b/scripts/utils.ts @@ -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 }