From c60eaeb53510978427107bfa0f758e37094d0da9 Mon Sep 17 00:00:00 2001 From: Reorx Date: Sat, 28 May 2022 02:10:33 +0800 Subject: [PATCH] instantclick: support updating head tags only for meta and link (not stylesheet) tags --- assets/js/instantclick.js | 60 ++++++++++++++++++++++++++++++++++-- layouts/partials/footer.html | 3 ++ layouts/partials/header.html | 3 +- 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/assets/js/instantclick.js b/assets/js/instantclick.js index 0787beb..356fc2d 100644 --- a/assets/js/instantclick.js +++ b/assets/js/instantclick.js @@ -17,6 +17,7 @@ var InstantClick = function(document, location) { $title = false, $mustRedirect = false, $body = false, + $head = false, $timing = {}, $isPreloading = false, $isWaitingForCompletion = false, @@ -125,12 +126,15 @@ var InstantClick = function(document, location) { return returnValue } - function changePage(title, body, newUrl, scrollY) { + function changePage(title, body, headCache, newUrl, scrollY) { document.documentElement.replaceChild(body, document.body) /* We cannot just use `document.body = doc.body`, it causes Safari (tested 5.1, 6.0 and Mobile 7.0) to execute script tags directly. */ + // updateHead + updateHead(headCache) + if (newUrl) { history.pushState(null, null, newUrl) @@ -190,6 +194,51 @@ var InstantClick = function(document, location) { return html.replace(//gi, '') } + const stylesheetRegex = /stylesheet/ + + function loopHeadTags(head, callback) { + for (const i of head.children) { + let v + switch (i.tagName) { + case 'LINK': + const rel = i.getAttribute('rel') || '' + if (rel && !stylesheetRegex.test(rel)) { + v = rel + } + break; + case 'META': + const name = i.getAttribute('name') || '' + const property = i.getAttribute('property') || '' + if (name || property) { + v = `${name}-${property}` + } + break; + } + + if (v) { + callback(i, `${i.tagName}-${v}`) + } + } + } + + function makeHeadCache(head) { + const cache = {} + loopHeadTags(head, (i, key) => { + cache[key] = i.outerHTML + }) + return cache + } + + function updateHead(headCache) { + // console.log('update head', headCache) + loopHeadTags(document.head, (i, key) => { + const headTag = headCache[key] + if (headTag) { + i.outerHTML = headTag + } + }) + } + ////////// EVENT HANDLERS ////////// @@ -292,6 +341,7 @@ var InstantClick = function(document, location) { doc.documentElement.innerHTML = removeNoscriptTags($xhr.responseText) $title = doc.title $body = doc.body + $head = makeHeadCache(doc.head) var alteredOnReceive = triggerPageEvent('receive', $url, $body, $title) if (alteredOnReceive) { @@ -304,9 +354,11 @@ var InstantClick = function(document, location) { } var urlWithoutHash = removeHash($url) + // console.log('set history 2', urlWithoutHash, $head) $history[urlWithoutHash] = { body: $body, title: $title, + head: $head, scrollY: urlWithoutHash in $history ? $history[urlWithoutHash].scrollY : 0 } @@ -493,7 +545,7 @@ var InstantClick = function(document, location) { } $history[$currentLocationWithoutHash].scrollY = pageYOffset setPreloadingAsHalted() - changePage($title, $body, $url) + changePage($title, $body, $head, $url) } @@ -695,8 +747,10 @@ var InstantClick = function(document, location) { $history[$currentLocationWithoutHash] = { body: document.body, title: document.title, + head: makeHeadCache(document.head), scrollY: pageYOffset } + // console.log('set history 1', $currentLocationWithoutHash) var elems = document.head.children, elem, @@ -736,7 +790,7 @@ var InstantClick = function(document, location) { $history[$currentLocationWithoutHash].scrollY = pageYOffset $currentLocationWithoutHash = loc - changePage($history[loc].title, $history[loc].body, false, $history[loc].scrollY) + changePage($history[loc].title, $history[loc].body, $history[loc].head, false, $history[loc].scrollY) }) } diff --git a/layouts/partials/footer.html b/layouts/partials/footer.html index a38931d..2f7f3e2 100644 --- a/layouts/partials/footer.html +++ b/layouts/partials/footer.html @@ -147,6 +147,9 @@ {{- /* InstantClick.js */}} {{- if (.Param "EnableInstantClick") }} {{- $instantclick := resources.Get "js/instantclick.js" }} +{{- if hugo.IsProduction }} + {{- $instantclick = minify $instantclick }} +{{- end }} diff --git a/layouts/partials/header.html b/layouts/partials/header.html index 166eee1..0ed0b20 100644 --- a/layouts/partials/header.html +++ b/layouts/partials/header.html @@ -30,7 +30,7 @@ function setPrefTheme(theme) { const toggleThemeCallbacks = [] toggleThemeCallbacks.push((isDark) => { - // console.log('window toggle-theme') + // console.log('window toggle-theme 1') if (isDark) { setPrefTheme('light'); } else { @@ -42,6 +42,7 @@ toggleThemeCallbacks.push((isDark) => { // because window is never changed by InstantClick, // we add the listener to window to ensure the event is always received window.addEventListener('toggle-theme', function() { + // console.log('window toggle-theme') const isDark = isDarkTheme() toggleThemeCallbacks.forEach(callback => callback(isDark)) });