From 0e9a151ce5dd8fd9139436112fc65a351f9a1188 Mon Sep 17 00:00:00 2001 From: ZhenShuo Leo <98386542+ZhenShuo2021@users.noreply.github.com> Date: Thu, 5 Feb 2026 21:44:07 +0800 Subject: [PATCH 1/2] refactor: gather firebase templates --- assets/js/firebase.js | 208 +++++++++++++++++++++++++++++++++++ assets/js/page.js | 131 ---------------------- assets/js/process.js | 70 ------------ layouts/_default/list.html | 16 --- layouts/_default/single.html | 17 --- layouts/_default/term.html | 8 -- layouts/_default/terms.html | 9 -- layouts/partials/footer.html | 6 - layouts/partials/head.html | 26 ----- layouts/partials/vendor.html | 61 ++++++++++ 10 files changed, 269 insertions(+), 283 deletions(-) create mode 100644 assets/js/firebase.js delete mode 100644 assets/js/page.js delete mode 100644 assets/js/process.js diff --git a/assets/js/firebase.js b/assets/js/firebase.js new file mode 100644 index 00000000..fb97bdd3 --- /dev/null +++ b/assets/js/firebase.js @@ -0,0 +1,208 @@ +const pageScriptElement = document.currentScript; +const configEl = document.getElementById("firebase-config"); + +if (!configEl?.textContent) { + console.error("Firebase config element not found"); + document + .querySelectorAll( + '[id^="views_"], [id^="likes_"], #button_likes_heart, #button_likes_emtpty_heart, #button_likes_text', + ) + .forEach((el) => el.remove()); +} else { + const data = JSON.parse(configEl.textContent); + const oid = data.oids?.views; + const oid_likes = data.oids?.likes; + + let liked_page = false; + const id = oid ? oid.replaceAll("/", "-") : oid; + const id_likes = oid_likes ? oid_likes.replaceAll("/", "-") : oid_likes; + + function numberWithCommas(x) { + return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); + } + + function toggleLoaders(node) { + var classesString = node.className; + if (classesString == "") return; + var classes = classesString.split(" "); + for (var i in classes) { + node.classList.toggle(classes[i]); + } + } + + var update_views = function (node, id) { + db.collection("views") + .doc(id) + .onSnapshot((doc) => { + var data = doc.data(); + if (data) { + node.innerText = numberWithCommas(data.views); + } else { + node.innerText = 0; + } + toggleLoaders(node); + }); + }; + + var update_likes = function (node, id) { + db.collection("likes") + .doc(id) + .onSnapshot((doc) => { + var data = doc.data(); + if (data) { + node.innerText = numberWithCommas(data.likes); + } else { + node.innerText = 0; + } + toggleLoaders(node); + }); + }; + + if (typeof auth !== "undefined") { + const viewed = localStorage.getItem(id); + + if (!viewed && id) { + auth + .signInAnonymously() + .then(() => { + const docRef = db.collection("views").doc(id); + localStorage.setItem(id, true); + docRef + .get() + .then((doc) => { + if (doc.exists) { + db.collection("views") + .doc(id) + .update({ + views: firebase.firestore.FieldValue.increment(1), + }); + } else { + db.collection("views").doc(id).set({ views: 1 }); + } + }) + .catch((error) => { + console.log("Error getting document:", error); + }); + }) + .catch((error) => { + const errorCode = error.code; + const errorMessage = error.message; + console.error(errorCode, errorMessage); + }); + } + + const liked = localStorage.getItem(id_likes); + + if (liked) { + liked_page = true; + document.querySelectorAll("span[id='button_likes_heart']")[0].style.display = ""; + document.querySelectorAll("span[id='button_likes_emtpty_heart']")[0].style.display = "none"; + document.querySelectorAll("span[id='button_likes_text']")[0].innerText = ""; + } + + auth + .signInAnonymously() + .then(() => { + var views_nodes = document.querySelectorAll("span[id^='views_']"); + + for (var i in views_nodes) { + var node = views_nodes[i]; + var id = node.id ? node.id.replaceAll("/", "-") : node.id; + if (id) { + update_views(node, id); + } + } + + var likes_nodes = document.querySelectorAll("span[id^='likes_']"); + + for (var i in likes_nodes) { + var node = likes_nodes[i]; + var id = node.id ? node.id.replaceAll("/", "-") : node.id; + if (id) { + update_likes(node, id); + } + } + }) + .catch((error) => { + var errorCode = error.code; + var errorMessage = error.message; + console.error(errorCode, errorMessage); + }); + } + + function like_article(id_likes) { + auth + .signInAnonymously() + .then(() => { + const docRef = db.collection("likes").doc(id_likes); + docRef + .get() + .then((doc) => { + liked_page = true; + localStorage.setItem(id_likes, true); + document.querySelectorAll("span[id='button_likes_heart']")[0].style.display = ""; + document.querySelectorAll("span[id='button_likes_emtpty_heart']")[0].style.display = "none"; + document.querySelectorAll("span[id='button_likes_text']")[0].innerText = ""; + if (doc.exists) { + db.collection("likes") + .doc(id_likes) + .update({ + likes: firebase.firestore.FieldValue.increment(1), + }); + } else { + db.collection("likes").doc(id_likes).set({ likes: 1 }); + } + }) + .catch((error) => { + console.log("Error getting document:", error); + }); + }) + .catch((error) => { + const errorCode = error.code; + const errorMessage = error.message; + console.error(errorCode, errorMessage); + }); + } + + function remove_like_article(id_likes) { + auth + .signInAnonymously() + .then(() => { + const docRef = db.collection("likes").doc(id_likes); + docRef + .get() + .then((doc) => { + liked_page = false; + localStorage.removeItem(id_likes); + document.querySelectorAll("span[id='button_likes_heart']")[0].style.display = "none"; + document.querySelectorAll("span[id='button_likes_emtpty_heart']")[0].style.display = ""; + document.querySelectorAll("span[id='button_likes_text']")[0].innerText = "\xa0Like"; + if (doc.exists) { + db.collection("likes") + .doc(id_likes) + .update({ + likes: firebase.firestore.FieldValue.increment(-1), + }); + } else { + db.collection("likes").doc(id_likes).set({ likes: 0 }); + } + }) + .catch((error) => { + console.log("Error getting document:", error); + }); + }) + .catch((error) => { + const errorCode = error.code; + const errorMessage = error.message; + console.error(errorCode, errorMessage); + }); + } + + window.process_article = function () { + if (!liked_page) { + like_article(id_likes); + } else { + remove_like_article(id_likes); + } + }; +} diff --git a/assets/js/page.js b/assets/js/page.js deleted file mode 100644 index 00eada1c..00000000 --- a/assets/js/page.js +++ /dev/null @@ -1,131 +0,0 @@ -const pageScriptElement = document.currentScript; -const oid = - pageScriptElement && pageScriptElement.getAttribute("data-oid") - ? pageScriptElement.getAttribute("data-oid") - : (console.error("data-oid is null"), null); -const oid_likes = - pageScriptElement && pageScriptElement.getAttribute("data-oid-likes") - ? pageScriptElement.getAttribute("data-oid-likes") - : (console.error("data-oid-likes is null"), null); -let liked_page = false; -const id = oid ? oid.replaceAll("/", "-") : oid; -const id_likes = oid_likes ? oid_likes.replaceAll("/", "-") : oid_likes; - -if (typeof auth !== "undefined") { - const viewed = localStorage.getItem(id); - - if (!viewed) { - auth - .signInAnonymously() - .then(() => { - const docRef = db.collection("views").doc(id); - localStorage.setItem(id, true); - docRef - .get() - .then((doc) => { - if (doc.exists) { - db.collection("views") - .doc(id) - .update({ - views: firebase.firestore.FieldValue.increment(1), - }); - } else { - db.collection("views").doc(id).set({ views: 1 }); - } - }) - .catch((error) => { - console.log("Error getting document:", error); - }); - }) - .catch((error) => { - const errorCode = error.code; - const errorMessage = error.message; - console.error(errorCode, errorMessage); - }); - } - - const liked = localStorage.getItem(id_likes); - - if (liked) { - liked_page = true; - document.querySelectorAll("span[id='button_likes_heart']")[0].style.display = ""; - document.querySelectorAll("span[id='button_likes_emtpty_heart']")[0].style.display = "none"; - document.querySelectorAll("span[id='button_likes_text']")[0].innerText = ""; - } -} - -function like_article(id_likes) { - auth - .signInAnonymously() - .then(() => { - const docRef = db.collection("likes").doc(id_likes); - docRef - .get() - .then((doc) => { - liked_page = true; - localStorage.setItem(id_likes, true); - document.querySelectorAll("span[id='button_likes_heart']")[0].style.display = ""; - document.querySelectorAll("span[id='button_likes_emtpty_heart']")[0].style.display = "none"; - document.querySelectorAll("span[id='button_likes_text']")[0].innerText = ""; - if (doc.exists) { - db.collection("likes") - .doc(id_likes) - .update({ - likes: firebase.firestore.FieldValue.increment(1), - }); - } else { - db.collection("likes").doc(id_likes).set({ likes: 1 }); - } - }) - .catch((error) => { - console.log("Error getting document:", error); - }); - }) - .catch((error) => { - const errorCode = error.code; - const errorMessage = error.message; - console.error(errorCode, errorMessage); - }); -} - -function remove_like_article(id_likes) { - auth - .signInAnonymously() - .then(() => { - const docRef = db.collection("likes").doc(id_likes); - docRef - .get() - .then((doc) => { - liked_page = false; - localStorage.removeItem(id_likes); - document.querySelectorAll("span[id='button_likes_heart']")[0].style.display = "none"; - document.querySelectorAll("span[id='button_likes_emtpty_heart']")[0].style.display = ""; - document.querySelectorAll("span[id='button_likes_text']")[0].innerText = "\xa0Like"; - if (doc.exists) { - db.collection("likes") - .doc(id_likes) - .update({ - likes: firebase.firestore.FieldValue.increment(-1), - }); - } else { - db.collection("likes").doc(id_likes).set({ likes: 0 }); - } - }) - .catch((error) => { - console.log("Error getting document:", error); - }); - }) - .catch((error) => { - const errorCode = error.code; - const errorMessage = error.message; - console.error(errorCode, errorMessage); - }); -} - -function process_article() { - if (!liked_page) { - like_article(id_likes); - } else { - remove_like_article(id_likes); - } -} diff --git a/assets/js/process.js b/assets/js/process.js deleted file mode 100644 index e8cb4fbf..00000000 --- a/assets/js/process.js +++ /dev/null @@ -1,70 +0,0 @@ -if (typeof auth !== "undefined") { - var viewsCollection = db.collection("views"); - var likesCollection = db.collection("likes"); - - function numberWithCommas(x) { - return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); - } - - function toggleLoaders(node) { - var classesString = node.className; - if (classesString == "") return; - var classes = classesString.split(" "); - for (var i in classes) { - node.classList.toggle(classes[i]); - } - } - - var update_views = function (node, id) { - viewsCollection.doc(id).onSnapshot((doc) => { - var data = doc.data(); - if (data) { - node.innerText = numberWithCommas(data.views); - } else { - node.innerText = 0; - } - toggleLoaders(node); - }); - }; - - var update_likes = function (node, id) { - likesCollection.doc(id).onSnapshot((doc) => { - var data = doc.data(); - if (data) { - node.innerText = numberWithCommas(data.likes); - } else { - node.innerText = 0; - } - toggleLoaders(node); - }); - }; - - auth - .signInAnonymously() - .then(() => { - var views_nodes = document.querySelectorAll("span[id^='views_']"); - - for (var i in views_nodes) { - var node = views_nodes[i]; - var id = node.id ? node.id.replaceAll("/", "-") : node.id; - if (id) { - update_views(node, id); - } - } - - var likes_nodes = document.querySelectorAll("span[id^='likes_']"); - - for (var i in likes_nodes) { - var node = likes_nodes[i]; - var id = node.id ? node.id.replaceAll("/", "-") : node.id; - if (id) { - update_likes(node, id); - } - } - }) - .catch((error) => { - var errorCode = error.code; - var errorMessage = error.message; - console.error(errorCode, errorMessage); - }); -} diff --git a/layouts/_default/list.html b/layouts/_default/list.html index f2fa8d63..640def99 100644 --- a/layouts/_default/list.html +++ b/layouts/_default/list.html @@ -22,22 +22,6 @@
{{ partial "article-meta/list.html" (dict "context" . "scope" "single") }}
- {{ $translations := .AllTranslations }} - {{ with .File }} - {{ $path := .Path }} - {{ range $translations }} - {{ $lang := print "." .Lang ".md" }} - {{ $path = replace $path $lang ".md" }} - {{ end }} - {{ $jsPage := resources.Get "js/page.js" }} - {{ $jsPage = $jsPage | resources.Minify | resources.Fingerprint (site.Params.fingerprintAlgorithm | default "sha512") }} - - {{ end }} {{/* Description (markdown content) */}} diff --git a/layouts/_default/single.html b/layouts/_default/single.html index 375b10f9..a6c78f9f 100644 --- a/layouts/_default/single.html +++ b/layouts/_default/single.html @@ -68,23 +68,6 @@ {{ partial "sharing-links.html" . }} {{ partial "related.html" . }} - - {{ $translations := .AllTranslations }} - {{ with .File }} - {{ $path := .Path }} - {{ range $translations }} - {{ $lang := print "." .Lang ".md" }} - {{ $path = replace $path $lang ".md" }} - {{ end }} - {{ $jsPage := resources.Get "js/page.js" }} - {{ $jsPage = $jsPage | resources.Minify | resources.Fingerprint (site.Params.fingerprintAlgorithm | default "sha512") }} - - {{ end }} {{/* Footer */}} diff --git a/layouts/_default/term.html b/layouts/_default/term.html index 75f8adb0..84d7d7cd 100644 --- a/layouts/_default/term.html +++ b/layouts/_default/term.html @@ -26,14 +26,6 @@
{{ .Content }}
- {{ $jsPage := resources.Get "js/page.js" }} - {{ $jsPage = $jsPage | resources.Minify | resources.Fingerprint (site.Params.fingerprintAlgorithm | default "sha512") }} - {{ end }} diff --git a/layouts/_default/terms.html b/layouts/_default/terms.html index 94851574..664d2bec 100644 --- a/layouts/_default/terms.html +++ b/layouts/_default/terms.html @@ -26,14 +26,6 @@ {{ .Content }} - {{ $jsPage := resources.Get "js/page.js" }} - {{ $jsPage = $jsPage | resources.Minify | resources.Fingerprint (site.Params.fingerprintAlgorithm | default "sha512") }} - {{ end }} {{ if site.Params.taxonomy.cardView }} @@ -50,5 +42,4 @@ {{ end }} {{ end }} - {{ end }} diff --git a/layouts/partials/footer.html b/layouts/partials/footer.html index 752e86bd..649f5bc0 100644 --- a/layouts/partials/footer.html +++ b/layouts/partials/footer.html @@ -69,12 +69,6 @@ }); {{ end }} - {{ $jsProcess := resources.Get "js/process.js" }} - {{ $jsProcess = $jsProcess | resources.Minify | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }} - {{/* Extend footer - eg. for extra scripts, etc. */}} {{ if templates.Exists "partials/extend-footer.html" }} {{ partialCached "extend-footer.html" . }} diff --git a/layouts/partials/head.html b/layouts/partials/head.html index 93c013cd..c7d4ccc0 100644 --- a/layouts/partials/head.html +++ b/layouts/partials/head.html @@ -200,32 +200,6 @@ {{ partial "extend-head-uncached.html" . }} {{ end }} - {{/* Firebase */}} - {{ with $.Site.Params.firebase }} - {{ if isset $.Site.Params "firebase" }} - - - - - {{ end }} - {{ end }} - {{/* Advertisement */}} {{ with .Site.Params.advertisement.adsense }} diff --git a/layouts/partials/vendor.html b/layouts/partials/vendor.html index 66b6a9c0..7c4e9601 100644 --- a/layouts/partials/vendor.html +++ b/layouts/partials/vendor.html @@ -153,3 +153,64 @@ {{ end }} {{ end }} + +{{ if site.Params.firebase.apiKey }} + {{ if in (slice "page" "section") .Kind }} + {{ $translations := .AllTranslations }} + {{ with .File }} + {{ $path := .Path }} + {{ range $translations }} + {{ $path = replace $path (print "." .Lang ".md") ".md" }} + {{ end }} + {{ partial "inline/firebase-config.html" (dict "views" (printf "views_%s" $path) "likes" (printf "likes_%s" $path)) }} + {{ end }} + {{ else if eq .Kind "term" }} + {{ partial "inline/firebase-config.html" (dict "views" (printf "views_term_%s" .Data.Term) "likes" (printf "likes_term_%s" .Data.Term)) }} + {{ else if eq .Kind "taxonomy" }} + {{ partial "inline/firebase-config.html" (dict "views" (printf "views_taxonomy_%s" .Data.Plural) "likes" (printf "likes_taxonomy_%s" .Data.Plural)) }} + {{ else if eq .Kind "home" }} + {{ partial "inline/firebase-config.html" (dict "views" (printf "views_home") "likes" (printf "likes_home")) }} + {{ end }} + + + + + + {{/* */}} + {{ $firebase := resources.Get "js/firebase.js" }} + {{ $firebase = $firebase | resources.Minify | resources.Fingerprint (site.Params.fingerprintAlgorithm | default "sha512") }} + +{{ end }} + +{{ define "partials/inline/firebase-config.html" }} + +{{ end }} From 99d329c7b08b1bd1ca6c393cd5553280bce40793 Mon Sep 17 00:00:00 2001 From: ZhenShuo Leo <98386542+ZhenShuo2021@users.noreply.github.com> Date: Fri, 6 Feb 2026 00:46:47 +0800 Subject: [PATCH 2/2] feat: reduce firebase blocking time - use esm format - defer loading with type="module" - upgrade from v8.10.0 to v9.23.0 - allow homepage/taxonomy/term log --- assets/js/button-likes.js | 4 - assets/js/firebase.js | 350 +++++++++++++++-------------------- layouts/partials/head.html | 1 - layouts/partials/vendor.html | 61 +++--- 4 files changed, 170 insertions(+), 246 deletions(-) delete mode 100644 assets/js/button-likes.js diff --git a/assets/js/button-likes.js b/assets/js/button-likes.js deleted file mode 100644 index 2ffc71be..00000000 --- a/assets/js/button-likes.js +++ /dev/null @@ -1,4 +0,0 @@ -document.getElementById("button_likes") && - document.getElementById("button_likes").addEventListener("click", () => { - process_article(); - }); diff --git a/assets/js/firebase.js b/assets/js/firebase.js index fb97bdd3..82550aa5 100644 --- a/assets/js/firebase.js +++ b/assets/js/firebase.js @@ -1,208 +1,154 @@ -const pageScriptElement = document.currentScript; -const configEl = document.getElementById("firebase-config"); +import { initializeApp } from "https://www.gstatic.com/firebasejs/9.23.0/firebase-app.js"; +import { + getFirestore, + doc, + getDoc, + setDoc, + updateDoc, + increment, + onSnapshot, +} from "https://www.gstatic.com/firebasejs/9.23.0/firebase-firestore.js"; +import { getAuth, signInAnonymously } from "https://www.gstatic.com/firebasejs/9.23.0/firebase-auth.js"; + +let app, db, auth, oids; +try { + const configEl = document.getElementById("firebase-config"); + if (!configEl?.textContent) { + throw new Error("Firebase config element not found"); + } -if (!configEl?.textContent) { - console.error("Firebase config element not found"); - document - .querySelectorAll( - '[id^="views_"], [id^="likes_"], #button_likes_heart, #button_likes_emtpty_heart, #button_likes_text', - ) - .forEach((el) => el.remove()); -} else { const data = JSON.parse(configEl.textContent); - const oid = data.oids?.views; - const oid_likes = data.oids?.likes; + app = initializeApp(data.config); - let liked_page = false; - const id = oid ? oid.replaceAll("/", "-") : oid; - const id_likes = oid_likes ? oid_likes.replaceAll("/", "-") : oid_likes; - - function numberWithCommas(x) { - return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); - } - - function toggleLoaders(node) { - var classesString = node.className; - if (classesString == "") return; - var classes = classesString.split(" "); - for (var i in classes) { - node.classList.toggle(classes[i]); - } - } - - var update_views = function (node, id) { - db.collection("views") - .doc(id) - .onSnapshot((doc) => { - var data = doc.data(); - if (data) { - node.innerText = numberWithCommas(data.views); - } else { - node.innerText = 0; - } - toggleLoaders(node); - }); + oids = { + views: configEl.getAttribute("data-views"), + likes: configEl.getAttribute("data-likes"), }; - var update_likes = function (node, id) { - db.collection("likes") - .doc(id) - .onSnapshot((doc) => { - var data = doc.data(); - if (data) { - node.innerText = numberWithCommas(data.likes); - } else { - node.innerText = 0; - } - toggleLoaders(node); - }); - }; - - if (typeof auth !== "undefined") { - const viewed = localStorage.getItem(id); - - if (!viewed && id) { - auth - .signInAnonymously() - .then(() => { - const docRef = db.collection("views").doc(id); - localStorage.setItem(id, true); - docRef - .get() - .then((doc) => { - if (doc.exists) { - db.collection("views") - .doc(id) - .update({ - views: firebase.firestore.FieldValue.increment(1), - }); - } else { - db.collection("views").doc(id).set({ views: 1 }); - } - }) - .catch((error) => { - console.log("Error getting document:", error); - }); - }) - .catch((error) => { - const errorCode = error.code; - const errorMessage = error.message; - console.error(errorCode, errorMessage); - }); - } - - const liked = localStorage.getItem(id_likes); - - if (liked) { - liked_page = true; - document.querySelectorAll("span[id='button_likes_heart']")[0].style.display = ""; - document.querySelectorAll("span[id='button_likes_emtpty_heart']")[0].style.display = "none"; - document.querySelectorAll("span[id='button_likes_text']")[0].innerText = ""; - } - - auth - .signInAnonymously() - .then(() => { - var views_nodes = document.querySelectorAll("span[id^='views_']"); - - for (var i in views_nodes) { - var node = views_nodes[i]; - var id = node.id ? node.id.replaceAll("/", "-") : node.id; - if (id) { - update_views(node, id); - } - } - - var likes_nodes = document.querySelectorAll("span[id^='likes_']"); - - for (var i in likes_nodes) { - var node = likes_nodes[i]; - var id = node.id ? node.id.replaceAll("/", "-") : node.id; - if (id) { - update_likes(node, id); - } - } - }) - .catch((error) => { - var errorCode = error.code; - var errorMessage = error.message; - console.error(errorCode, errorMessage); - }); - } - - function like_article(id_likes) { - auth - .signInAnonymously() - .then(() => { - const docRef = db.collection("likes").doc(id_likes); - docRef - .get() - .then((doc) => { - liked_page = true; - localStorage.setItem(id_likes, true); - document.querySelectorAll("span[id='button_likes_heart']")[0].style.display = ""; - document.querySelectorAll("span[id='button_likes_emtpty_heart']")[0].style.display = "none"; - document.querySelectorAll("span[id='button_likes_text']")[0].innerText = ""; - if (doc.exists) { - db.collection("likes") - .doc(id_likes) - .update({ - likes: firebase.firestore.FieldValue.increment(1), - }); - } else { - db.collection("likes").doc(id_likes).set({ likes: 1 }); - } - }) - .catch((error) => { - console.log("Error getting document:", error); - }); - }) - .catch((error) => { - const errorCode = error.code; - const errorMessage = error.message; - console.error(errorCode, errorMessage); - }); - } - - function remove_like_article(id_likes) { - auth - .signInAnonymously() - .then(() => { - const docRef = db.collection("likes").doc(id_likes); - docRef - .get() - .then((doc) => { - liked_page = false; - localStorage.removeItem(id_likes); - document.querySelectorAll("span[id='button_likes_heart']")[0].style.display = "none"; - document.querySelectorAll("span[id='button_likes_emtpty_heart']")[0].style.display = ""; - document.querySelectorAll("span[id='button_likes_text']")[0].innerText = "\xa0Like"; - if (doc.exists) { - db.collection("likes") - .doc(id_likes) - .update({ - likes: firebase.firestore.FieldValue.increment(-1), - }); - } else { - db.collection("likes").doc(id_likes).set({ likes: 0 }); - } - }) - .catch((error) => { - console.log("Error getting document:", error); - }); - }) - .catch((error) => { - const errorCode = error.code; - const errorMessage = error.message; - console.error(errorCode, errorMessage); - }); - } - - window.process_article = function () { - if (!liked_page) { - like_article(id_likes); - } else { - remove_like_article(id_likes); - } - }; + db = getFirestore(app); + auth = getAuth(app); +} catch (e) { + console.error("Firebase initialization failed:", e.message); + throw e; } + +const id = oids?.views?.replaceAll("/", "-"); +const id_likes = oids?.likes?.replaceAll("/", "-"); +let liked = false; +let authReady = false; + +function formatNumber(n) { + return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); +} + +function toggleLoaders(node) { + var classesString = node.className; + if (classesString == "") return; + var classes = classesString.split(" "); + for (var i in classes) { + node.classList.toggle(classes[i]); + } +} + +function updateDisplay(collection, nodeId) { + const node = document.getElementById(nodeId); + if (!node) return; + + const docId = nodeId.replaceAll("/", "-"); + onSnapshot( + doc(db, collection, docId), + (snapshot) => { + node.innerText = snapshot.exists() ? formatNumber(snapshot.data()[collection]) : 0; + toggleLoaders(node); + }, + (error) => { + console.error("Firebase snapshot update failed:", error); + }, + ); +} + +async function recordView(id) { + if (!id || localStorage.getItem(id)) return; + + try { + const ref = doc(db, "views", id); + const snap = await getDoc(ref); + + snap.exists() ? await updateDoc(ref, { views: increment(1) }) : await setDoc(ref, { views: 1 }); + + localStorage.setItem(id, true); + } catch (e) { + console.error("Record view operation failed:", e.message); + } +} + +function updateButton(isLiked) { + const hearts = document.querySelectorAll("span[id='button_likes_heart']"); + const empties = document.querySelectorAll("span[id='button_likes_emtpty_heart']"); + const texts = document.querySelectorAll("span[id='button_likes_text']"); + + hearts.forEach((el) => { + el.style.display = isLiked ? "" : "none"; + }); + empties.forEach((el) => { + el.style.display = isLiked ? "none" : ""; + }); + texts.forEach((el) => { + el.innerText = isLiked ? "" : "\xa0Like"; + }); +} + +async function toggleLike(add) { + if (!id_likes || !authReady) return; + + try { + const ref = doc(db, "likes", id_likes); + const snap = await getDoc(ref); + + liked = add; + add ? localStorage.setItem(id_likes, true) : localStorage.removeItem(id_likes); + updateButton(add); + + snap.exists() + ? await updateDoc(ref, { likes: increment(add ? 1 : -1) }) + : await setDoc(ref, { likes: add ? 1 : 0 }); + } catch (e) { + console.error("Like operation failed:", e.message); + liked = !add; + add ? localStorage.removeItem(id_likes) : localStorage.setItem(id_likes, true); + updateButton(!add); + } +} + +signInAnonymously(auth) + .then(() => { + authReady = true; + + document.querySelectorAll("span[id^='views_']").forEach((node) => { + if (node.id) updateDisplay("views", node.id); + }); + + document.querySelectorAll("span[id^='likes_']").forEach((node) => { + if (node.id) updateDisplay("likes", node.id); + }); + + recordView(id); + + if (id_likes && localStorage.getItem(id_likes)) { + liked = true; + updateButton(true); + } + + const likeButton = document.getElementById("button_likes"); + if (likeButton) { + likeButton.addEventListener("click", () => { + toggleLike(!liked); + }); + } + }) + .catch((error) => { + console.error("Firebase anonymous sign-in failed:", error.message); + authReady = false; + }); + +window.process_article = () => toggleLike(!liked); diff --git a/layouts/partials/head.html b/layouts/partials/head.html index c7d4ccc0..0652e82c 100644 --- a/layouts/partials/head.html +++ b/layouts/partials/head.html @@ -154,7 +154,6 @@ {{ if .Site.Params.rtl | default false }} {{ $jsResources = $jsResources | append (resources.Get "js/rtl.js") }} {{ end }} - {{ $jsResources = $jsResources | append (resources.Get "js/button-likes.js") }} {{ $jsResources = $jsResources | append (resources.Get "js/katex-render.js") }} {{ $jsResources = $jsResources | append (resources.Get "js/print-support.js") }} {{ if $jsResources }} diff --git a/layouts/partials/vendor.html b/layouts/partials/vendor.html index 7c4e9601..bb929306 100644 --- a/layouts/partials/vendor.html +++ b/layouts/partials/vendor.html @@ -154,7 +154,12 @@ {{ end }} {{ end }} +{{/* Firebase */}} {{ if site.Params.firebase.apiKey }} + {{ $firebase := resources.Get "js/firebase.js" }} + {{ $firebase = $firebase | resources.Minify | resources.Fingerprint (site.Params.fingerprintAlgorithm | default "sha512") }} + + {{ if in (slice "page" "section") .Kind }} {{ $translations := .AllTranslations }} {{ with .File }} @@ -169,48 +174,26 @@ {{ else if eq .Kind "taxonomy" }} {{ partial "inline/firebase-config.html" (dict "views" (printf "views_taxonomy_%s" .Data.Plural) "likes" (printf "likes_taxonomy_%s" .Data.Plural)) }} {{ else if eq .Kind "home" }} - {{ partial "inline/firebase-config.html" (dict "views" (printf "views_home") "likes" (printf "likes_home")) }} + {{ partial "inline/firebase-config.html" (dict "views" "views_home" "likes" "likes_home") }} {{ end }} - - - - - {{/* */}} - {{ $firebase := resources.Get "js/firebase.js" }} - {{ $firebase = $firebase | resources.Minify | resources.Fingerprint (site.Params.fingerprintAlgorithm | default "sha512") }} - {{ end }} -{{ define "partials/inline/firebase-config.html" }} - + } + {{ end }}