From aa54e901b1f7dd078d3a56e73864a38c9fdae43c Mon Sep 17 00:00:00 2001 From: Cotes Chung <11371340+cotes2020@users.noreply.github.com> Date: Sat, 10 Apr 2021 19:50:55 +0800 Subject: [PATCH] Resume the pv cache source & add validation for the number of localStorage keys --- assets/js/_utils/pageviews.js | 134 +++++++++++++++++++++------------ assets/js/dist/pvreport.min.js | 2 +- 2 files changed, 88 insertions(+), 48 deletions(-) diff --git a/assets/js/_utils/pageviews.js b/assets/js/_utils/pageviews.js index 63db5af..b647c34 100644 --- a/assets/js/_utils/pageviews.js +++ b/assets/js/_utils/pageviews.js @@ -18,30 +18,42 @@ const getInitStatus = (function () { }()); const PvOpts = (function () { + function getContent(selector) { + return $(selector).attr("content"); + } + function hasContent(selector) { - let content = $(selector).attr("content"); + let content = getContent(selector); return (typeof content !== "undefined" && content !== false); } return { - getProxyEndpoint() { - return $("meta[name=pv-proxy-endpoint]").attr("content"); + getProxyMeta() { + return getContent("meta[name=pv-proxy-endpoint]"); }, - getLocalData() { - return $("meta[name=pv-cache-path]").attr("content"); + getLocalMeta() { + return getContent("meta[name=pv-cache-path]"); }, - hasProxyEndpoint() { + hasProxyMeta() { return hasContent("meta[name=pv-proxy-endpoint]"); }, - hasLocalData() { + hasLocalMeta() { return hasContent("meta[name=pv-cache-path]"); } } }()); const PvStorage = (function () { - const KEY_PV = "pv"; - const KEY_CREATION = "pv_created_date"; + const Keys = { + KEY_PV: "pv", + KEY_PV_SRC: "pv_src", + KEY_CREATION: "pv_created_date" + }; + + const Source = { + LOCAL: "same-origin", + PROXY: "cors" + }; function get(key) { return localStorage.getItem(key); @@ -51,35 +63,54 @@ const PvStorage = (function () { localStorage.setItem(key, val); } + function saveCache(pv, src) { + set(Keys.KEY_PV, pv); + set(Keys.KEY_PV_SRC, src); + set(Keys.KEY_CREATION, new Date().toJSON()); + } + return { + keysCount() { + return Object.keys(Keys).length; + }, hasCache() { - return (localStorage.getItem(KEY_PV) !== null); + return (localStorage.getItem(Keys.KEY_PV) !== null); }, getCache() { - // get data from browser cache - return JSON.parse(localStorage.getItem(KEY_PV)); + return JSON.parse(localStorage.getItem(Keys.KEY_PV)); }, - saveCache(pv) { - set(KEY_PV, pv); - set(KEY_CREATION, new Date().toJSON()); + saveLocalCache(pv) { + saveCache(pv, Source.LOCAL); + }, + saveProxyCache(pv) { + saveCache(pv, Source.PROXY); }, isExpired() { - let date = new Date(get(KEY_CREATION)); - date.setHours(date.getHours() + 1); // per hour + let date = new Date(get(Keys.KEY_CREATION)); + date.setHours(date.getHours() + 1); // per hour return Date.now() >= date.getTime(); }, - getAllPageviews() { - return PvStorage.getCache().totalsForAllResults["ga:pageviews"]; + isFromLocal() { + return get(Keys.KEY_PV_SRC) === Source.LOCAL; + }, + isFromProxy() { + return get(Keys.KEY_PV_SRC) === Source.PROXY; }, newerThan(pv) { - return PvStorage.getAllPageviews() > pv.totalsForAllResults["ga:pageviews"]; + return PvStorage.getCache().totalsForAllResults["ga:pageviews"] > pv.totalsForAllResults["ga:pageviews"]; }, inspectKeys() { + if (localStorage.length !== PvStorage.keysCount()) { + localStorage.clear(); + return; + } + for(let i = 0; i < localStorage.length; i++){ const key = localStorage.key(i); switch (key) { - case KEY_PV: - case KEY_CREATION: + case Keys.KEY_PV: + case Keys.KEY_PV_SRC: + case Keys.KEY_CREATION: break; default: localStorage.clear(); @@ -152,14 +183,14 @@ function displayPageviews(data) { } function fetchProxyPageviews() { - if (PvOpts.hasProxyEndpoint()) { + if (PvOpts.hasProxyMeta()) { $.ajax({ type: "GET", - url: PvOpts.getProxyEndpoint(), + url: PvOpts.getProxyMeta(), dataType: "jsonp", jsonpCallback: "displayPageviews", - success: (data, textStatus, jqXHR) => { - PvStorage.saveCache(JSON.stringify(data)); + success: (data) => { + PvStorage.saveProxyCache(JSON.stringify(data)); }, error: (jqXHR, textStatus, errorThrown) => { console.log("Failed to load pageviews from proxy server: " + errorThrown); @@ -168,26 +199,19 @@ function fetchProxyPageviews() { } } -function loadPageviews(hasCache = false) { - if (PvOpts.hasLocalData()) { - fetch(PvOpts.getLocalData()) - .then((response) => response.json()) - .then((data) => { +function fetchLocalPageviews(hasCache = false) { + return fetch(PvOpts.getLocalMeta()) + .then(response => response.json()) + .then(data => { + if (hasCache) { // The cache from the proxy will sometimes be more recent than the local one - if (hasCache && PvStorage.newerThan(data)) { + if (PvStorage.isFromProxy() && PvStorage.newerThan(data)) { return; } - displayPageviews(data); - PvStorage.saveCache(JSON.stringify(data)); - }) - .then(() => { - fetchProxyPageviews(); - }); - - } else { - fetchProxyPageviews(); - } - + } + displayPageviews(data); + PvStorage.saveLocalCache(JSON.stringify(data)); + }); } $(function() { @@ -199,11 +223,27 @@ $(function() { if (PvStorage.hasCache()) { displayPageviews(PvStorage.getCache()); - if (!PvStorage.isExpired()) { - return; + + if (PvStorage.isExpired()) { + if (PvOpts.hasLocalMeta()) { + fetchLocalPageviews(true).then(fetchProxyPageviews); + } else { + fetchProxyPageviews(); + } + + } else { + if (PvStorage.isFromLocal()) { + fetchProxyPageviews(); + } + } + + } else { // no cached + + if (PvOpts.hasLocalMeta()) { + fetchLocalPageviews().then(fetchProxyPageviews); + } else { + fetchProxyPageviews(); } } - loadPageviews(PvStorage.hasCache()); - }); diff --git a/assets/js/dist/pvreport.min.js b/assets/js/dist/pvreport.min.js index 904bc37..72f8da3 100644 --- a/assets/js/dist/pvreport.min.js +++ b/assets/js/dist/pvreport.min.js @@ -3,4 +3,4 @@ * © 2019 Cotes Chung * MIT Licensed */ -const getInitStatus=function(){let t=!1;return()=>{var e=t;return t=t||!0,e}}(),PvOpts=function(){function e(e){e=$(e).attr("content");return void 0!==e&&!1!==e}return{getProxyEndpoint(){return $("meta[name=pv-proxy-endpoint]").attr("content")},getLocalData(){return $("meta[name=pv-cache-path]").attr("content")},hasProxyEndpoint(){return e("meta[name=pv-proxy-endpoint]")},hasLocalData(){return e("meta[name=pv-cache-path]")}}}(),PvStorage=function(){const t="pv",a="pv_created_date";function r(e,t){localStorage.setItem(e,t)}return{hasCache(){return null!==localStorage.getItem(t)},getCache(){return JSON.parse(localStorage.getItem(t))},saveCache(e){r(t,e),r(a,(new Date).toJSON())},isExpired(){let e=new Date((t=a,localStorage.getItem(t)));var t;return e.setHours(e.getHours()+1),Date.now()>=e.getTime()},getAllPageviews(){return PvStorage.getCache().totalsForAllResults["ga:pageviews"]},newerThan(e){return PvStorage.getAllPageviews()>e.totalsForAllResults["ga:pageviews"]},inspectKeys(){for(let e=0;er&&countUp(r,n,a.attr("id"))):a.text((new Intl.NumberFormat).format(n))}function displayPageviews(e){if(void 0!==e){let t=getInitStatus();const a=e.rows;0<$("#post-list").length?$(".post-preview").each(function(){var e=$(this).find("a").attr("href");tacklePV(a,e,$(this).find(".pageviews"),t)}):0<$(".post").length&&(e=window.location.pathname,tacklePV(a,e,$("#pv"),t))}}function fetchProxyPageviews(){PvOpts.hasProxyEndpoint()&&$.ajax({type:"GET",url:PvOpts.getProxyEndpoint(),dataType:"jsonp",jsonpCallback:"displayPageviews",success:(e,t,a)=>{PvStorage.saveCache(JSON.stringify(e))},error:(e,t,a)=>{console.log("Failed to load pageviews from proxy server: "+a)}})}function loadPageviews(t=!1){PvOpts.hasLocalData()?fetch(PvOpts.getLocalData()).then(e=>e.json()).then(e=>{t&&PvStorage.newerThan(e)||(displayPageviews(e),PvStorage.saveCache(JSON.stringify(e)))}).then(()=>{fetchProxyPageviews()}):fetchProxyPageviews()}$(function(){$(".pageviews").length<=0||(PvStorage.inspectKeys(),PvStorage.hasCache()&&(displayPageviews(PvStorage.getCache()),!PvStorage.isExpired())||loadPageviews(PvStorage.hasCache()))}); \ No newline at end of file +const getInitStatus=function(){let t=!1;return()=>{var e=t;return t=t||!0,e}}(),PvOpts=function(){function t(e){return $(e).attr("content")}function e(e){e=t(e);return void 0!==e&&!1!==e}return{getProxyMeta(){return t("meta[name=pv-proxy-endpoint]")},getLocalMeta(){return t("meta[name=pv-cache-path]")},hasProxyMeta(){return e("meta[name=pv-proxy-endpoint]")},hasLocalMeta(){return e("meta[name=pv-cache-path]")}}}(),PvStorage=function(){const a={KEY_PV:"pv",KEY_PV_SRC:"pv_src",KEY_CREATION:"pv_created_date"},t={LOCAL:"same-origin",PROXY:"cors"};function r(e){return localStorage.getItem(e)}function o(e,t){localStorage.setItem(e,t)}function n(e,t){o(a.KEY_PV,e),o(a.KEY_PV_SRC,t),o(a.KEY_CREATION,(new Date).toJSON())}return{keysCount(){return Object.keys(a).length},hasCache(){return null!==localStorage.getItem(a.KEY_PV)},getCache(){return JSON.parse(localStorage.getItem(a.KEY_PV))},saveLocalCache(e){n(e,t.LOCAL)},saveProxyCache(e){n(e,t.PROXY)},isExpired(){let e=new Date(r(a.KEY_CREATION));return e.setHours(e.getHours()+1),Date.now()>=e.getTime()},isFromLocal(){return r(a.KEY_PV_SRC)===t.LOCAL},isFromProxy(){return r(a.KEY_PV_SRC)===t.PROXY},newerThan(e){return PvStorage.getCache().totalsForAllResults["ga:pageviews"]>e.totalsForAllResults["ga:pageviews"]},inspectKeys(){if(localStorage.length===PvStorage.keysCount())for(let e=0;er&&countUp(r,o,a.attr("id"))):a.text((new Intl.NumberFormat).format(o))}function displayPageviews(e){if(void 0!==e){let t=getInitStatus();const a=e.rows;0<$("#post-list").length?$(".post-preview").each(function(){var e=$(this).find("a").attr("href");tacklePV(a,e,$(this).find(".pageviews"),t)}):0<$(".post").length&&(e=window.location.pathname,tacklePV(a,e,$("#pv"),t))}}function fetchProxyPageviews(){PvOpts.hasProxyMeta()&&$.ajax({type:"GET",url:PvOpts.getProxyMeta(),dataType:"jsonp",jsonpCallback:"displayPageviews",success:e=>{PvStorage.saveProxyCache(JSON.stringify(e))},error:(e,t,a)=>{console.log("Failed to load pageviews from proxy server: "+a)}})}function fetchLocalPageviews(t=!1){return fetch(PvOpts.getLocalMeta()).then(e=>e.json()).then(e=>{t&&PvStorage.isFromProxy()&&PvStorage.newerThan(e)||(displayPageviews(e),PvStorage.saveLocalCache(JSON.stringify(e)))})}$(function(){$(".pageviews").length<=0||(PvStorage.inspectKeys(),PvStorage.hasCache()?(displayPageviews(PvStorage.getCache()),PvStorage.isExpired()?PvOpts.hasLocalMeta()?fetchLocalPageviews(!0).then(fetchProxyPageviews):fetchProxyPageviews():PvStorage.isFromLocal()&&fetchProxyPageviews()):PvOpts.hasLocalMeta()?fetchLocalPageviews().then(fetchProxyPageviews):fetchProxyPageviews())}); \ No newline at end of file