Slightly improved diff performance
This commit is contained in:
parent
d8367b6172
commit
44369cb916
@ -1,5 +1,4 @@
|
|||||||
.anime-list-container
|
.anime-list-container
|
||||||
vertical
|
|
||||||
width 100%
|
width 100%
|
||||||
max-width 800px
|
max-width 800px
|
||||||
margin 0 auto
|
margin 0 auto
|
||||||
|
@ -9,8 +9,11 @@ export function load(arn: AnimeNotifier, element: HTMLElement) {
|
|||||||
// Diff
|
// Diff
|
||||||
export function diff(arn: AnimeNotifier, element: HTMLElement) {
|
export function diff(arn: AnimeNotifier, element: HTMLElement) {
|
||||||
let url = element.dataset.url || (element as HTMLAnchorElement).getAttribute("href")
|
let url = element.dataset.url || (element as HTMLAnchorElement).getAttribute("href")
|
||||||
|
|
||||||
arn.diff(url)
|
arn.diff(url)
|
||||||
.then(() => arn.scrollTo(element))
|
.then(() => {
|
||||||
|
// Avoid instant layout thrashing
|
||||||
|
arn.requestIdleCallback(() => arn.scrollTo(element))
|
||||||
|
})
|
||||||
.catch(console.error)
|
.catch(console.error)
|
||||||
}
|
}
|
@ -294,6 +294,10 @@ export class AnimeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
countUp() {
|
countUp() {
|
||||||
|
if(!this.app.currentPath.includes("/paypal/success")) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
for(let element of findAll("count-up")) {
|
for(let element of findAll("count-up")) {
|
||||||
let final = parseInt(element.innerText)
|
let final = parseInt(element.innerText)
|
||||||
let duration = 2000.0
|
let duration = 2000.0
|
||||||
@ -384,9 +388,7 @@ export class AnimeNotifier {
|
|||||||
return Promise.resolve(response)
|
return Promise.resolve(response)
|
||||||
})
|
})
|
||||||
.then(response => response.text())
|
.then(response => response.text())
|
||||||
.then(html => {
|
.then(html => Diff.root(document.documentElement, html))
|
||||||
Diff.root(document.documentElement, html)
|
|
||||||
})
|
|
||||||
.then(() => this.app.emit("DOMContentLoaded"))
|
.then(() => this.app.emit("DOMContentLoaded"))
|
||||||
.then(() => this.loading(false)) // Because our loading element gets reset due to full page diff
|
.then(() => this.loading(false)) // Because our loading element gets reset due to full page diff
|
||||||
}
|
}
|
||||||
@ -605,9 +607,7 @@ export class AnimeNotifier {
|
|||||||
let request = fetch(path, {
|
let request = fetch(path, {
|
||||||
credentials: "same-origin"
|
credentials: "same-origin"
|
||||||
})
|
})
|
||||||
.then(response => {
|
.then(response => response.text())
|
||||||
return response.text()
|
|
||||||
})
|
|
||||||
|
|
||||||
history.pushState(url, null, url)
|
history.pushState(url, null, url)
|
||||||
this.app.currentPath = url
|
this.app.currentPath = url
|
||||||
@ -617,7 +617,7 @@ export class AnimeNotifier {
|
|||||||
|
|
||||||
// Delay by transition-speed
|
// Delay by transition-speed
|
||||||
return delay(200).then(() => request)
|
return delay(200).then(() => request)
|
||||||
.then(html => this.app.setContent(html, true))
|
.then(html => Diff.innerHTML(this.app.content, html))
|
||||||
.then(() => this.app.emit("DOMContentLoaded"))
|
.then(() => this.app.emit("DOMContentLoaded"))
|
||||||
.then(() => this.loading(false))
|
.then(() => this.loading(false))
|
||||||
.catch(console.error)
|
.catch(console.error)
|
||||||
@ -664,9 +664,11 @@ export class AnimeNotifier {
|
|||||||
const contentPadding = 24
|
const contentPadding = 24
|
||||||
|
|
||||||
let scrollHandle: number
|
let scrollHandle: number
|
||||||
let oldScroll = this.app.content.parentElement.scrollTop
|
|
||||||
let newScroll = 0
|
let newScroll = 0
|
||||||
let finalScroll = Math.max(target.offsetTop - contentPadding, 0)
|
let finalScroll = Math.max(target.offsetTop - contentPadding, 0)
|
||||||
|
|
||||||
|
// Calculating scrollTop will force a layout - careful!
|
||||||
|
let oldScroll = this.app.content.parentElement.scrollTop
|
||||||
let scrollDistance = finalScroll - oldScroll
|
let scrollDistance = finalScroll - oldScroll
|
||||||
|
|
||||||
if(scrollDistance > 0 && scrollDistance < 4) {
|
if(scrollDistance > 0 && scrollDistance < 4) {
|
||||||
|
@ -39,7 +39,7 @@ export class Application {
|
|||||||
this.lastRequest.abort()
|
this.lastRequest.abort()
|
||||||
this.lastRequest = null
|
this.lastRequest = null
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let request = new XMLHttpRequest()
|
let request = new XMLHttpRequest()
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ export class Application {
|
|||||||
if(options.addToHistory === undefined) {
|
if(options.addToHistory === undefined) {
|
||||||
options.addToHistory = true
|
options.addToHistory = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set current path
|
// Set current path
|
||||||
this.currentPath = url
|
this.currentPath = url
|
||||||
|
|
||||||
@ -85,14 +85,14 @@ export class Application {
|
|||||||
if(e.target !== this.content) {
|
if(e.target !== this.content) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove listener after we finally got the correct event.
|
// Remove listener after we finally got the correct event.
|
||||||
this.content.removeEventListener("transitionend", onTransitionEnd)
|
this.content.removeEventListener("transitionend", onTransitionEnd)
|
||||||
|
|
||||||
// Wait for the network request to end.
|
// Wait for the network request to end.
|
||||||
request.then(html => {
|
request.then(html => {
|
||||||
// Set content
|
// Set content
|
||||||
this.setContent(html, false)
|
this.setContent(html)
|
||||||
this.scrollToTop()
|
this.scrollToTop()
|
||||||
|
|
||||||
// Fade animations
|
// Fade animations
|
||||||
@ -113,19 +113,15 @@ export class Application {
|
|||||||
return request
|
return request
|
||||||
}
|
}
|
||||||
|
|
||||||
setContent(html: string, diff: boolean) {
|
setContent(html: string) {
|
||||||
if(diff) {
|
this.content.innerHTML = html
|
||||||
Diff.innerHTML(this.content, html)
|
|
||||||
} else {
|
|
||||||
this.content.innerHTML = html
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
markActiveLinks(element?: HTMLElement) {
|
markActiveLinks(element?: HTMLElement) {
|
||||||
if(element === undefined)
|
if(element === undefined)
|
||||||
element = document.body
|
element = document.body
|
||||||
|
|
||||||
let links = element.querySelectorAll("a")
|
let links = element.getElementsByTagName("a")
|
||||||
|
|
||||||
for(let i = 0; i < links.length; i++) {
|
for(let i = 0; i < links.length; i++) {
|
||||||
let link = links[i]
|
let link = links[i]
|
||||||
@ -165,7 +161,7 @@ export class Application {
|
|||||||
|
|
||||||
if(!url || url === self.currentPath)
|
if(!url || url === self.currentPath)
|
||||||
return
|
return
|
||||||
|
|
||||||
// Load requested page
|
// Load requested page
|
||||||
self.load(url)
|
self.load(url)
|
||||||
}
|
}
|
||||||
|
@ -7,23 +7,35 @@ export class Diff {
|
|||||||
static rootContainer: HTMLElement
|
static rootContainer: HTMLElement
|
||||||
|
|
||||||
// innerHTML will diff the element with the given HTML string and apply DOM mutations.
|
// innerHTML will diff the element with the given HTML string and apply DOM mutations.
|
||||||
static innerHTML(aRoot: HTMLElement, html: string) {
|
static innerHTML(aRoot: HTMLElement, html: string): Promise<void> {
|
||||||
if(!Diff.container) {
|
if(!Diff.container) {
|
||||||
Diff.container = document.createElement("main")
|
Diff.container = document.createElement("main")
|
||||||
}
|
}
|
||||||
|
|
||||||
Diff.container.innerHTML = html
|
Diff.container.innerHTML = html
|
||||||
Diff.childNodes(aRoot, Diff.container)
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
Diff.childNodes(aRoot, Diff.container)
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// root will diff the document root element with the given HTML string and apply DOM mutations.
|
// root will diff the document root element with the given HTML string and apply DOM mutations.
|
||||||
static root(aRoot: HTMLElement, html: string) {
|
static root(aRoot: HTMLElement, html: string) {
|
||||||
if(!Diff.rootContainer) {
|
return new Promise((resolve, reject) => {
|
||||||
Diff.rootContainer = document.createElement("html")
|
if(!Diff.rootContainer) {
|
||||||
}
|
Diff.rootContainer = document.createElement("html")
|
||||||
|
}
|
||||||
Diff.rootContainer.innerHTML = html.replace("<!DOCTYPE html>", "")
|
|
||||||
Diff.childNodes(aRoot.getElementsByTagName("body")[0], Diff.rootContainer.getElementsByTagName("body")[0])
|
Diff.rootContainer.innerHTML = html.replace("<!DOCTYPE html>", "")
|
||||||
|
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
Diff.childNodes(aRoot.getElementsByTagName("body")[0], Diff.rootContainer.getElementsByTagName("body")[0])
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// childNodes diffs the child nodes of 2 given elements and applies DOM mutations.
|
// childNodes diffs the child nodes of 2 given elements and applies DOM mutations.
|
||||||
@ -31,7 +43,7 @@ export class Diff {
|
|||||||
let aChild = [...aRoot.childNodes]
|
let aChild = [...aRoot.childNodes]
|
||||||
let bChild = [...bRoot.childNodes]
|
let bChild = [...bRoot.childNodes]
|
||||||
let numNodes = Math.max(aChild.length, bChild.length)
|
let numNodes = Math.max(aChild.length, bChild.length)
|
||||||
|
|
||||||
for(let i = 0; i < numNodes; i++) {
|
for(let i = 0; i < numNodes; i++) {
|
||||||
let a = aChild[i]
|
let a = aChild[i]
|
||||||
|
|
||||||
@ -69,7 +81,7 @@ export class Diff {
|
|||||||
let elemB = b as HTMLElement
|
let elemB = b as HTMLElement
|
||||||
|
|
||||||
let removeAttributes: Attr[] = []
|
let removeAttributes: Attr[] = []
|
||||||
|
|
||||||
for(let x = 0; x < elemA.attributes.length; x++) {
|
for(let x = 0; x < elemA.attributes.length; x++) {
|
||||||
let attrib = elemA.attributes[x]
|
let attrib = elemA.attributes[x]
|
||||||
|
|
||||||
@ -119,7 +131,7 @@ export class Diff {
|
|||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
elemA.setAttribute(attrib.name, attrib.value)
|
elemA.setAttribute(attrib.name, attrib.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user