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 }}