mirror of
https://github.com/cotes2020/jekyll-theme-chirpy.git
synced 2025-12-24 08:37:13 +00:00
style: 4 space indents to the JS files
This commit is contained in:
@@ -1,30 +1,30 @@
|
||||
/*
|
||||
/**
|
||||
* Tab 'Categories' expand/close effect.
|
||||
*/
|
||||
|
||||
$(function() {
|
||||
const childPrefix = "l_";
|
||||
const parentPrefix = "h_";
|
||||
const collapse = $(".collapse");
|
||||
$(function () {
|
||||
const childPrefix = "l_";
|
||||
const parentPrefix = "h_";
|
||||
const collapse = $(".collapse");
|
||||
|
||||
/* close up top-category */
|
||||
collapse.on("hide.bs.collapse", function () { /* Bootstrap collapse events. */
|
||||
const parentId = parentPrefix + $(this).attr("id").substring(childPrefix.length);
|
||||
if (parentId) {
|
||||
$(`#${parentId} .far.fa-folder-open`).attr("class", "far fa-folder fa-fw");
|
||||
$(`#${parentId} i.fas`).addClass("rotate");
|
||||
$(`#${parentId}`).removeClass("hide-border-bottom");
|
||||
}
|
||||
});
|
||||
/* close up top-category */
|
||||
collapse.on("hide.bs.collapse", function () { /* Bootstrap collapse events. */
|
||||
const parentId = parentPrefix + $(this).attr("id").substring(childPrefix.length);
|
||||
if (parentId) {
|
||||
$(`#${parentId} .far.fa-folder-open`).attr("class", "far fa-folder fa-fw");
|
||||
$(`#${parentId} i.fas`).addClass("rotate");
|
||||
$(`#${parentId}`).removeClass("hide-border-bottom");
|
||||
}
|
||||
});
|
||||
|
||||
/* expand the top category */
|
||||
collapse.on("show.bs.collapse", function() {
|
||||
const parentId = parentPrefix + $(this).attr("id").substring(childPrefix.length);
|
||||
if (parentId) {
|
||||
$(`#${parentId} .far.fa-folder`).attr("class", "far fa-folder-open fa-fw");
|
||||
$(`#${parentId} i.fas`).removeClass("rotate");
|
||||
$(`#${parentId}`).addClass("hide-border-bottom");
|
||||
}
|
||||
});
|
||||
/* expand the top category */
|
||||
collapse.on("show.bs.collapse", function () {
|
||||
const parentId = parentPrefix + $(this).attr("id").substring(childPrefix.length);
|
||||
if (parentId) {
|
||||
$(`#${parentId} .far.fa-folder`).attr("class", "far fa-folder-open fa-fw");
|
||||
$(`#${parentId} i.fas`).removeClass("rotate");
|
||||
$(`#${parentId}`).addClass("hide-border-bottom");
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/**
|
||||
* Clipboard functions
|
||||
*
|
||||
* Dependencies:
|
||||
@@ -6,128 +6,128 @@
|
||||
* - clipboard.js (https://github.com/zenorocha/clipboard.js)
|
||||
*/
|
||||
|
||||
$(function() {
|
||||
const btnSelector = '.code-header>button';
|
||||
const ICON_SUCCESS = 'fas fa-check';
|
||||
const ATTR_TIMEOUT = 'timeout';
|
||||
const ATTR_TITLE_SUCCEED = 'data-title-succeed';
|
||||
const ATTR_TITLE_ORIGIN = 'data-original-title';
|
||||
const TIMEOUT = 2000; // in milliseconds
|
||||
$(function () {
|
||||
const btnSelector = '.code-header>button';
|
||||
const ICON_SUCCESS = 'fas fa-check';
|
||||
const ATTR_TIMEOUT = 'timeout';
|
||||
const ATTR_TITLE_SUCCEED = 'data-title-succeed';
|
||||
const ATTR_TITLE_ORIGIN = 'data-original-title';
|
||||
const TIMEOUT = 2000; // in milliseconds
|
||||
|
||||
function isLocked(node) {
|
||||
if ($(node)[0].hasAttribute(ATTR_TIMEOUT)) {
|
||||
let timeout = $(node).attr(ATTR_TIMEOUT);
|
||||
if (Number(timeout) > Date.now()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function lock(node) {
|
||||
$(node).attr(ATTR_TIMEOUT, Date.now() + TIMEOUT);
|
||||
}
|
||||
|
||||
function unlock(node) {
|
||||
$(node).removeAttr(ATTR_TIMEOUT);
|
||||
}
|
||||
|
||||
/* --- Copy code block --- */
|
||||
|
||||
// Initial the clipboard.js object
|
||||
const clipboard = new ClipboardJS(btnSelector, {
|
||||
target(trigger) {
|
||||
let codeBlock = trigger.parentNode.nextElementSibling;
|
||||
return codeBlock.querySelector('code .rouge-code');
|
||||
}
|
||||
});
|
||||
|
||||
$(btnSelector).tooltip({
|
||||
trigger: 'hover',
|
||||
placement: 'left'
|
||||
});
|
||||
|
||||
function getIcon(btn) {
|
||||
let iconNode = $(btn).children();
|
||||
return iconNode.attr('class');
|
||||
}
|
||||
|
||||
const ICON_DEFAULT = getIcon(btnSelector);
|
||||
|
||||
function showTooltip(btn) {
|
||||
const succeedTitle = $(btn).attr(ATTR_TITLE_SUCCEED);
|
||||
$(btn).attr(ATTR_TITLE_ORIGIN, succeedTitle).tooltip('show');
|
||||
}
|
||||
|
||||
function hideTooltip(btn) {
|
||||
$(btn).tooltip('hide').removeAttr(ATTR_TITLE_ORIGIN);
|
||||
}
|
||||
|
||||
function setSuccessIcon(btn) {
|
||||
let btnNode = $(btn);
|
||||
let iconNode = btnNode.children();
|
||||
iconNode.attr('class', ICON_SUCCESS);
|
||||
}
|
||||
|
||||
function resumeIcon(btn) {
|
||||
let btnNode = $(btn);
|
||||
let iconNode = btnNode.children();
|
||||
iconNode.attr('class', ICON_DEFAULT);
|
||||
}
|
||||
|
||||
clipboard.on('success', (e) => {
|
||||
e.clearSelection();
|
||||
|
||||
const trigger = e.trigger;
|
||||
if (isLocked(trigger)) {
|
||||
return;
|
||||
function isLocked(node) {
|
||||
if ($(node)[0].hasAttribute(ATTR_TIMEOUT)) {
|
||||
let timeout = $(node).attr(ATTR_TIMEOUT);
|
||||
if (Number(timeout) > Date.now()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
setSuccessIcon(trigger);
|
||||
showTooltip(trigger);
|
||||
lock(trigger);
|
||||
|
||||
setTimeout(() => {
|
||||
hideTooltip(trigger);
|
||||
resumeIcon(trigger);
|
||||
unlock(trigger);
|
||||
}, TIMEOUT);
|
||||
|
||||
});
|
||||
|
||||
/* --- Post link sharing --- */
|
||||
|
||||
$('#copy-link').click((e) => {
|
||||
|
||||
let target = $(e.target);
|
||||
|
||||
if (isLocked(target)) {
|
||||
return;
|
||||
function lock(node) {
|
||||
$(node).attr(ATTR_TIMEOUT, Date.now() + TIMEOUT);
|
||||
}
|
||||
|
||||
// Copy URL to clipboard
|
||||
function unlock(node) {
|
||||
$(node).removeAttr(ATTR_TIMEOUT);
|
||||
}
|
||||
|
||||
const url = window.location.href;
|
||||
const $temp = $("<input>");
|
||||
/* --- Copy code block --- */
|
||||
|
||||
$("body").append($temp);
|
||||
$temp.val(url).select();
|
||||
document.execCommand("copy");
|
||||
$temp.remove();
|
||||
// Initial the clipboard.js object
|
||||
const clipboard = new ClipboardJS(btnSelector, {
|
||||
target(trigger) {
|
||||
let codeBlock = trigger.parentNode.nextElementSibling;
|
||||
return codeBlock.querySelector('code .rouge-code');
|
||||
}
|
||||
});
|
||||
|
||||
// Switch tooltip title
|
||||
$(btnSelector).tooltip({
|
||||
trigger: 'hover',
|
||||
placement: 'left'
|
||||
});
|
||||
|
||||
const defaultTitle = target.attr(ATTR_TITLE_ORIGIN);
|
||||
const succeedTitle = target.attr(ATTR_TITLE_SUCCEED);
|
||||
function getIcon(btn) {
|
||||
let iconNode = $(btn).children();
|
||||
return iconNode.attr('class');
|
||||
}
|
||||
|
||||
target.attr(ATTR_TITLE_ORIGIN, succeedTitle).tooltip('show');
|
||||
lock(target);
|
||||
const ICON_DEFAULT = getIcon(btnSelector);
|
||||
|
||||
setTimeout(() => {
|
||||
target.attr(ATTR_TITLE_ORIGIN, defaultTitle);
|
||||
unlock(target);
|
||||
}, TIMEOUT);
|
||||
function showTooltip(btn) {
|
||||
const succeedTitle = $(btn).attr(ATTR_TITLE_SUCCEED);
|
||||
$(btn).attr(ATTR_TITLE_ORIGIN, succeedTitle).tooltip('show');
|
||||
}
|
||||
|
||||
});
|
||||
function hideTooltip(btn) {
|
||||
$(btn).tooltip('hide').removeAttr(ATTR_TITLE_ORIGIN);
|
||||
}
|
||||
|
||||
function setSuccessIcon(btn) {
|
||||
let btnNode = $(btn);
|
||||
let iconNode = btnNode.children();
|
||||
iconNode.attr('class', ICON_SUCCESS);
|
||||
}
|
||||
|
||||
function resumeIcon(btn) {
|
||||
let btnNode = $(btn);
|
||||
let iconNode = btnNode.children();
|
||||
iconNode.attr('class', ICON_DEFAULT);
|
||||
}
|
||||
|
||||
clipboard.on('success', (e) => {
|
||||
e.clearSelection();
|
||||
|
||||
const trigger = e.trigger;
|
||||
if (isLocked(trigger)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setSuccessIcon(trigger);
|
||||
showTooltip(trigger);
|
||||
lock(trigger);
|
||||
|
||||
setTimeout(() => {
|
||||
hideTooltip(trigger);
|
||||
resumeIcon(trigger);
|
||||
unlock(trigger);
|
||||
}, TIMEOUT);
|
||||
|
||||
});
|
||||
|
||||
/* --- Post link sharing --- */
|
||||
|
||||
$('#copy-link').click((e) => {
|
||||
|
||||
let target = $(e.target);
|
||||
|
||||
if (isLocked(target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy URL to clipboard
|
||||
|
||||
const url = window.location.href;
|
||||
const $temp = $("<input>");
|
||||
|
||||
$("body").append($temp);
|
||||
$temp.val(url).select();
|
||||
document.execCommand("copy");
|
||||
$temp.remove();
|
||||
|
||||
// Switch tooltip title
|
||||
|
||||
const defaultTitle = target.attr(ATTR_TITLE_ORIGIN);
|
||||
const succeedTitle = target.attr(ATTR_TITLE_SUCCEED);
|
||||
|
||||
target.attr(ATTR_TITLE_ORIGIN, succeedTitle).tooltip('show');
|
||||
lock(target);
|
||||
|
||||
setTimeout(() => {
|
||||
target.attr(ATTR_TITLE_ORIGIN, defaultTitle);
|
||||
unlock(target);
|
||||
}, TIMEOUT);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -1,47 +1,46 @@
|
||||
/**
|
||||
Lazy load images (https://github.com/ApoorvSaxena/lozad.js)
|
||||
and popup when clicked (https://github.com/dimsemenov/Magnific-Popup)
|
||||
*/
|
||||
Lazy load images (https://github.com/ApoorvSaxena/lozad.js)
|
||||
and popup when clicked (https://github.com/dimsemenov/Magnific-Popup)
|
||||
*/
|
||||
|
||||
$(function() {
|
||||
$(function () {
|
||||
const IMG_SCOPE = '#main > div.row:first-child > div:first-child';
|
||||
|
||||
const IMG_SCOPE = '#main > div.row:first-child > div:first-child';
|
||||
|
||||
if ($(`${IMG_SCOPE} img`).length <= 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* lazy loading */
|
||||
|
||||
const imgList = document.querySelectorAll(`${IMG_SCOPE} img[data-src]`);
|
||||
const observer = lozad(imgList);
|
||||
observer.observe();
|
||||
|
||||
/* popup */
|
||||
|
||||
$(`${IMG_SCOPE} p > img[data-src],${IMG_SCOPE} img[data-src].preview-img`).each(
|
||||
function() {
|
||||
let nextTag = $(this).next();
|
||||
const title = nextTag.prop('tagName') === 'EM' ? nextTag.text() : '';
|
||||
const src = $(this).attr('data-src'); // created by lozad.js
|
||||
|
||||
$(this).wrap(`<a href="${src}" title="${title}" class="popup"></a>`);
|
||||
if ($(`${IMG_SCOPE} img`).length <= 0) {
|
||||
return;
|
||||
}
|
||||
);
|
||||
|
||||
$('.popup').magnificPopup({
|
||||
type: 'image',
|
||||
closeOnContentClick: true,
|
||||
showCloseBtn: false,
|
||||
zoom: {
|
||||
enabled: true,
|
||||
duration: 300,
|
||||
easing: 'ease-in-out'
|
||||
}
|
||||
});
|
||||
/* lazy loading */
|
||||
|
||||
/* markup the image links */
|
||||
const imgList = document.querySelectorAll(`${IMG_SCOPE} img[data-src]`);
|
||||
const observer = lozad(imgList);
|
||||
observer.observe();
|
||||
|
||||
$(`${IMG_SCOPE} a`).has('img').addClass('img-link');
|
||||
/* popup */
|
||||
|
||||
$(`${IMG_SCOPE} p > img[data-src], ${IMG_SCOPE} img[data-src].preview-img`).each(
|
||||
function () {
|
||||
let nextTag = $(this).next();
|
||||
const title = nextTag.prop('tagName') === 'EM' ? nextTag.text() : '';
|
||||
const src = $(this).attr('data-src'); // created by lozad.js
|
||||
|
||||
$(this).wrap(`<a href="${src}" title="${title}" class="popup"></a>`);
|
||||
}
|
||||
);
|
||||
|
||||
$('.popup').magnificPopup({
|
||||
type: 'image',
|
||||
closeOnContentClick: true,
|
||||
showCloseBtn: false,
|
||||
zoom: {
|
||||
enabled: true,
|
||||
duration: 300,
|
||||
easing: 'ease-in-out'
|
||||
}
|
||||
});
|
||||
|
||||
/* markup the image links */
|
||||
|
||||
$(`${IMG_SCOPE} a`).has('img').addClass('img-link');
|
||||
|
||||
});
|
||||
|
||||
@@ -6,38 +6,38 @@
|
||||
|
||||
/* A tool for locale datetime */
|
||||
const LocaleHelper = (function () {
|
||||
const locale = $('html').attr('lang').substr(0, 2);
|
||||
const attrTimestamp = 'data-ts';
|
||||
const attrDateFormat = 'data-df';
|
||||
const locale = $('html').attr('lang').substr(0, 2);
|
||||
const attrTimestamp = 'data-ts';
|
||||
const attrDateFormat = 'data-df';
|
||||
|
||||
return {
|
||||
locale: () => locale,
|
||||
attrTimestamp: () => attrTimestamp,
|
||||
attrDateFormat: () => attrDateFormat,
|
||||
getTimestamp: ($elem) => Number($elem.attr(attrTimestamp)), // unix timestamp
|
||||
getDateFormat: ($elem) => $elem.attr(attrDateFormat)
|
||||
};
|
||||
return {
|
||||
locale: () => locale,
|
||||
attrTimestamp: () => attrTimestamp,
|
||||
attrDateFormat: () => attrDateFormat,
|
||||
getTimestamp: ($elem) => Number($elem.attr(attrTimestamp)), // unix timestamp
|
||||
getDateFormat: ($elem) => $elem.attr(attrDateFormat)
|
||||
};
|
||||
|
||||
}());
|
||||
|
||||
$(function() {
|
||||
dayjs.locale(LocaleHelper.locale());
|
||||
dayjs.extend(window.dayjs_plugin_localizedFormat);
|
||||
$(function () {
|
||||
dayjs.locale(LocaleHelper.locale());
|
||||
dayjs.extend(window.dayjs_plugin_localizedFormat);
|
||||
|
||||
$(`[${LocaleHelper.attrTimestamp()}]`).each(function () {
|
||||
const date = dayjs.unix(LocaleHelper.getTimestamp($(this)));
|
||||
const text = date.format(LocaleHelper.getDateFormat($(this)));
|
||||
$(this).text(text);
|
||||
$(this).removeAttr(LocaleHelper.attrTimestamp());
|
||||
$(this).removeAttr(LocaleHelper.attrDateFormat());
|
||||
$(`[${LocaleHelper.attrTimestamp()}]`).each(function () {
|
||||
const date = dayjs.unix(LocaleHelper.getTimestamp($(this)));
|
||||
const text = date.format(LocaleHelper.getDateFormat($(this)));
|
||||
$(this).text(text);
|
||||
$(this).removeAttr(LocaleHelper.attrTimestamp());
|
||||
$(this).removeAttr(LocaleHelper.attrDateFormat());
|
||||
|
||||
// setup tooltips
|
||||
const tooltip = $(this).attr('data-toggle');
|
||||
if (typeof tooltip === 'undefined' || tooltip !== 'tooltip') {
|
||||
return;
|
||||
}
|
||||
// setup tooltips
|
||||
const tooltip = $(this).attr('data-toggle');
|
||||
if (typeof tooltip === 'undefined' || tooltip !== 'tooltip') {
|
||||
return;
|
||||
}
|
||||
|
||||
const tooltipText = date.format('llll'); // see: https://day.js.org/docs/en/display/format#list-of-localized-formats
|
||||
$(this).attr('data-original-title', tooltipText);
|
||||
});
|
||||
const tooltipText = date.format('llll'); // see: https://day.js.org/docs/en/display/format#list-of-localized-formats
|
||||
$(this).attr('data-original-title', tooltipText);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/**
|
||||
* Count page views form GA or local cache file.
|
||||
*
|
||||
* Dependencies:
|
||||
@@ -7,244 +7,244 @@
|
||||
*/
|
||||
|
||||
const getInitStatus = (function () {
|
||||
let hasInit = false;
|
||||
return () => {
|
||||
let ret = hasInit;
|
||||
if (!hasInit) {
|
||||
hasInit = true;
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
let hasInit = false;
|
||||
return () => {
|
||||
let ret = hasInit;
|
||||
if (!hasInit) {
|
||||
hasInit = true;
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
}());
|
||||
|
||||
const PvOpts = (function () {
|
||||
function getContent(selector) {
|
||||
return $(selector).attr("content");
|
||||
}
|
||||
|
||||
function hasContent(selector) {
|
||||
let content = getContent(selector);
|
||||
return (typeof content !== "undefined" && content !== false);
|
||||
}
|
||||
|
||||
return {
|
||||
getProxyMeta() {
|
||||
return getContent("meta[name=pv-proxy-endpoint]");
|
||||
},
|
||||
getLocalMeta() {
|
||||
return getContent("meta[name=pv-cache-path]");
|
||||
},
|
||||
hasProxyMeta() {
|
||||
return hasContent("meta[name=pv-proxy-endpoint]");
|
||||
},
|
||||
hasLocalMeta() {
|
||||
return hasContent("meta[name=pv-cache-path]");
|
||||
function getContent(selector) {
|
||||
return $(selector).attr("content");
|
||||
}
|
||||
};
|
||||
|
||||
function hasContent(selector) {
|
||||
let content = getContent(selector);
|
||||
return (typeof content !== "undefined" && content !== false);
|
||||
}
|
||||
|
||||
return {
|
||||
getProxyMeta() {
|
||||
return getContent("meta[name=pv-proxy-endpoint]");
|
||||
},
|
||||
getLocalMeta() {
|
||||
return getContent("meta[name=pv-cache-path]");
|
||||
},
|
||||
hasProxyMeta() {
|
||||
return hasContent("meta[name=pv-proxy-endpoint]");
|
||||
},
|
||||
hasLocalMeta() {
|
||||
return hasContent("meta[name=pv-cache-path]");
|
||||
}
|
||||
};
|
||||
|
||||
}());
|
||||
|
||||
const PvStorage = (function () {
|
||||
const Keys = {
|
||||
KEY_PV: "pv",
|
||||
KEY_PV_SRC: "pv_src",
|
||||
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"
|
||||
};
|
||||
const Source = {
|
||||
LOCAL: "same-origin",
|
||||
PROXY: "cors"
|
||||
};
|
||||
|
||||
function get(key) {
|
||||
return localStorage.getItem(key);
|
||||
}
|
||||
|
||||
function set(key, val) {
|
||||
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(Keys.KEY_PV) !== null);
|
||||
},
|
||||
getCache() {
|
||||
return JSON.parse(localStorage.getItem(Keys.KEY_PV));
|
||||
},
|
||||
saveLocalCache(pv) {
|
||||
saveCache(pv, Source.LOCAL);
|
||||
},
|
||||
saveProxyCache(pv) {
|
||||
saveCache(pv, Source.PROXY);
|
||||
},
|
||||
isExpired() {
|
||||
let date = new Date(get(Keys.KEY_CREATION));
|
||||
date.setHours(date.getHours() + 1); // per hour
|
||||
return Date.now() >= date.getTime();
|
||||
},
|
||||
isFromLocal() {
|
||||
return get(Keys.KEY_PV_SRC) === Source.LOCAL;
|
||||
},
|
||||
isFromProxy() {
|
||||
return get(Keys.KEY_PV_SRC) === Source.PROXY;
|
||||
},
|
||||
newerThan(pv) {
|
||||
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 Keys.KEY_PV:
|
||||
case Keys.KEY_PV_SRC:
|
||||
case Keys.KEY_CREATION:
|
||||
break;
|
||||
default:
|
||||
localStorage.clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
function get(key) {
|
||||
return localStorage.getItem(key);
|
||||
}
|
||||
};
|
||||
|
||||
function set(key, val) {
|
||||
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(Keys.KEY_PV) !== null);
|
||||
},
|
||||
getCache() {
|
||||
return JSON.parse(localStorage.getItem(Keys.KEY_PV));
|
||||
},
|
||||
saveLocalCache(pv) {
|
||||
saveCache(pv, Source.LOCAL);
|
||||
},
|
||||
saveProxyCache(pv) {
|
||||
saveCache(pv, Source.PROXY);
|
||||
},
|
||||
isExpired() {
|
||||
let date = new Date(get(Keys.KEY_CREATION));
|
||||
date.setHours(date.getHours() + 1); // per hour
|
||||
return Date.now() >= date.getTime();
|
||||
},
|
||||
isFromLocal() {
|
||||
return get(Keys.KEY_PV_SRC) === Source.LOCAL;
|
||||
},
|
||||
isFromProxy() {
|
||||
return get(Keys.KEY_PV_SRC) === Source.PROXY;
|
||||
},
|
||||
newerThan(pv) {
|
||||
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 Keys.KEY_PV:
|
||||
case Keys.KEY_PV_SRC:
|
||||
case Keys.KEY_CREATION:
|
||||
break;
|
||||
default:
|
||||
localStorage.clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}()); /* PvStorage */
|
||||
|
||||
function countUp(min, max, destId) {
|
||||
if (min < max) {
|
||||
let numAnim = new CountUp(destId, min, max);
|
||||
if (!numAnim.error) {
|
||||
numAnim.start();
|
||||
} else {
|
||||
console.error(numAnim.error);
|
||||
if (min < max) {
|
||||
let numAnim = new CountUp(destId, min, max);
|
||||
if (!numAnim.error) {
|
||||
numAnim.start();
|
||||
} else {
|
||||
console.error(numAnim.error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function countPV(path, rows) {
|
||||
let count = 0;
|
||||
let count = 0;
|
||||
|
||||
if (typeof rows !== "undefined" ) {
|
||||
for (let i = 0; i < rows.length; ++i) {
|
||||
const gaPath = rows[parseInt(i, 10)][0];
|
||||
if (gaPath === path) { /* path format see: site.permalink */
|
||||
count += parseInt(rows[parseInt(i, 10)][1], 10);
|
||||
break;
|
||||
}
|
||||
if (typeof rows !== "undefined") {
|
||||
for (let i = 0; i < rows.length; ++i) {
|
||||
const gaPath = rows[parseInt(i, 10)][0];
|
||||
if (gaPath === path) { /* path format see: site.permalink */
|
||||
count += parseInt(rows[parseInt(i, 10)][1], 10);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
return count;
|
||||
}
|
||||
|
||||
function tacklePV(rows, path, elem, hasInit) {
|
||||
let count = countPV(path, rows);
|
||||
count = (count === 0 ? 1 : count);
|
||||
let count = countPV(path, rows);
|
||||
count = (count === 0 ? 1 : count);
|
||||
|
||||
if (!hasInit) {
|
||||
elem.text(new Intl.NumberFormat().format(count));
|
||||
} else {
|
||||
const initCount = parseInt(elem.text().replace(/,/g, ""), 10);
|
||||
if (count > initCount) {
|
||||
countUp(initCount, count, elem.attr("id"));
|
||||
if (!hasInit) {
|
||||
elem.text(new Intl.NumberFormat().format(count));
|
||||
} else {
|
||||
const initCount = parseInt(elem.text().replace(/,/g, ""), 10);
|
||||
if (count > initCount) {
|
||||
countUp(initCount, count, elem.attr("id"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function displayPageviews(data) {
|
||||
if (typeof data === "undefined") {
|
||||
return;
|
||||
}
|
||||
if (typeof data === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
let hasInit = getInitStatus();
|
||||
const rows = data.rows; /* could be undefined */
|
||||
let hasInit = getInitStatus();
|
||||
const rows = data.rows; /* could be undefined */
|
||||
|
||||
if ($("#post-list").length > 0) { /* the Home page */
|
||||
$(".post-preview").each(function() {
|
||||
const path = $(this).find("a").attr("href");
|
||||
tacklePV(rows, path, $(this).find(".pageviews"), hasInit);
|
||||
});
|
||||
if ($("#post-list").length > 0) { /* the Home page */
|
||||
$(".post-preview").each(function () {
|
||||
const path = $(this).find("a").attr("href");
|
||||
tacklePV(rows, path, $(this).find(".pageviews"), hasInit);
|
||||
});
|
||||
|
||||
} else if ($(".post").length > 0) { /* the post */
|
||||
const path = window.location.pathname;
|
||||
tacklePV(rows, path, $("#pv"), hasInit);
|
||||
}
|
||||
} else if ($(".post").length > 0) { /* the post */
|
||||
const path = window.location.pathname;
|
||||
tacklePV(rows, path, $("#pv"), hasInit);
|
||||
}
|
||||
}
|
||||
|
||||
function fetchProxyPageviews() {
|
||||
if (PvOpts.hasProxyMeta()) {
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: PvOpts.getProxyMeta(),
|
||||
dataType: "jsonp",
|
||||
jsonpCallback: "displayPageviews",
|
||||
success: (data) => {
|
||||
PvStorage.saveProxyCache(JSON.stringify(data));
|
||||
},
|
||||
error: (jqXHR, textStatus, errorThrown) => {
|
||||
console.log("Failed to load pageviews from proxy server: " + errorThrown);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (PvOpts.hasProxyMeta()) {
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: PvOpts.getProxyMeta(),
|
||||
dataType: "jsonp",
|
||||
jsonpCallback: "displayPageviews",
|
||||
success: (data) => {
|
||||
PvStorage.saveProxyCache(JSON.stringify(data));
|
||||
},
|
||||
error: (jqXHR, textStatus, errorThrown) => {
|
||||
console.log("Failed to load pageviews from proxy server: " + errorThrown);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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 (PvStorage.isFromProxy() && PvStorage.newerThan(data)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
displayPageviews(data);
|
||||
PvStorage.saveLocalCache(JSON.stringify(data));
|
||||
});
|
||||
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 (PvStorage.isFromProxy() && PvStorage.newerThan(data)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
displayPageviews(data);
|
||||
PvStorage.saveLocalCache(JSON.stringify(data));
|
||||
});
|
||||
}
|
||||
|
||||
$(function() {
|
||||
if ($(".pageviews").length <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
PvStorage.inspectKeys();
|
||||
|
||||
if (PvStorage.hasCache()) {
|
||||
displayPageviews(PvStorage.getCache());
|
||||
|
||||
if (PvStorage.isExpired()) {
|
||||
if (PvOpts.hasLocalMeta()) {
|
||||
fetchLocalPageviews(true).then(fetchProxyPageviews);
|
||||
} else {
|
||||
fetchProxyPageviews();
|
||||
}
|
||||
|
||||
} else {
|
||||
if (PvStorage.isFromLocal()) {
|
||||
fetchProxyPageviews();
|
||||
}
|
||||
$(function () {
|
||||
if ($(".pageviews").length <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
} else { // no cached
|
||||
PvStorage.inspectKeys();
|
||||
|
||||
if (PvOpts.hasLocalMeta()) {
|
||||
fetchLocalPageviews().then(fetchProxyPageviews);
|
||||
} else {
|
||||
fetchProxyPageviews();
|
||||
if (PvStorage.hasCache()) {
|
||||
displayPageviews(PvStorage.getCache());
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -1,96 +1,96 @@
|
||||
/*
|
||||
Safari doesn't support CSS `scroll-behavior: smooth`,
|
||||
so here is a compatible solution for all browser to smooth scrolling
|
||||
/**
|
||||
Safari doesn't support CSS `scroll-behavior: smooth`,
|
||||
so here is a compatible solution for all browser to smooth scrolling
|
||||
|
||||
See: <https://css-tricks.com/snippets/jquery/smooth-scrolling/>
|
||||
See: <https://css-tricks.com/snippets/jquery/smooth-scrolling/>
|
||||
|
||||
Warning: It must be called after all `<a>` tags (e.g., the dynamic TOC) are ready.
|
||||
*/
|
||||
Warning: It must be called after all `<a>` tags (e.g., the dynamic TOC) are ready.
|
||||
*/
|
||||
|
||||
$(function() {
|
||||
const $topbarTitle = $("#topbar-title");
|
||||
const REM = 16; // in pixels
|
||||
const ATTR_SCROLL_FOCUS = "scroll-focus";
|
||||
$(function () {
|
||||
const $topbarTitle = $("#topbar-title");
|
||||
const REM = 16; // in pixels
|
||||
const ATTR_SCROLL_FOCUS = "scroll-focus";
|
||||
|
||||
$("a[href*='#']")
|
||||
.not("[href='#']")
|
||||
.not("[href='#0']")
|
||||
.click(function(event) {
|
||||
if (this.pathname.replace(/^\//, "") !==
|
||||
location.pathname.replace(/^\//, "")) {
|
||||
return;
|
||||
}
|
||||
$("a[href*='#']")
|
||||
.not("[href='#']")
|
||||
.not("[href='#0']")
|
||||
.click(function (event) {
|
||||
if (this.pathname.replace(/^\//, "") !==
|
||||
location.pathname.replace(/^\//, "")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (location.hostname !== this.hostname) {
|
||||
return;
|
||||
}
|
||||
if (location.hostname !== this.hostname) {
|
||||
return;
|
||||
}
|
||||
|
||||
const hash = decodeURI(this.hash);
|
||||
let toFootnoteRef = RegExp(/^#fnref:/).test(hash);
|
||||
let toFootnote = toFootnoteRef ? false : RegExp(/^#fn:/).test(hash);
|
||||
let selector = hash.includes(":") ? hash.replace(/:/g, "\\:") : hash;
|
||||
let $target = $(selector);
|
||||
const hash = decodeURI(this.hash);
|
||||
let toFootnoteRef = RegExp(/^#fnref:/).test(hash);
|
||||
let toFootnote = toFootnoteRef ? false : RegExp(/^#fn:/).test(hash);
|
||||
let selector = hash.includes(":") ? hash.replace(/:/g, "\\:") : hash;
|
||||
let $target = $(selector);
|
||||
|
||||
let isMobileViews = $topbarTitle.is(":visible");
|
||||
let isPortrait = $(window).width() < $(window).height();
|
||||
let isMobileViews = $topbarTitle.is(":visible");
|
||||
let isPortrait = $(window).width() < $(window).height();
|
||||
|
||||
if (typeof $target === "undefined") {
|
||||
return;
|
||||
}
|
||||
if (typeof $target === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
event.preventDefault();
|
||||
|
||||
if (history.pushState) { /* add hash to URL */
|
||||
history.pushState(null, null, hash);
|
||||
}
|
||||
if (history.pushState) { /* add hash to URL */
|
||||
history.pushState(null, null, hash);
|
||||
}
|
||||
|
||||
let curOffset = $(window).scrollTop();
|
||||
let destOffset = $target.offset().top -= REM / 2;
|
||||
let curOffset = $(window).scrollTop();
|
||||
let destOffset = $target.offset().top -= REM / 2;
|
||||
|
||||
if (destOffset < curOffset) { // scroll up
|
||||
ScrollHelper.hideTopbar();
|
||||
ScrollHelper.addScrollUpTask();
|
||||
if (destOffset < curOffset) { // scroll up
|
||||
ScrollHelper.hideTopbar();
|
||||
ScrollHelper.addScrollUpTask();
|
||||
|
||||
if (isMobileViews && isPortrait) {
|
||||
destOffset -= ScrollHelper.getTopbarHeight();
|
||||
}
|
||||
if (isMobileViews && isPortrait) {
|
||||
destOffset -= ScrollHelper.getTopbarHeight();
|
||||
}
|
||||
|
||||
} else { // scroll down
|
||||
if (isMobileViews && isPortrait) {
|
||||
destOffset -= ScrollHelper.getTopbarHeight();
|
||||
}
|
||||
}
|
||||
} else { // scroll down
|
||||
if (isMobileViews && isPortrait) {
|
||||
destOffset -= ScrollHelper.getTopbarHeight();
|
||||
}
|
||||
}
|
||||
|
||||
$("html").animate({
|
||||
scrollTop: destOffset
|
||||
}, 500, () => {
|
||||
$target.focus();
|
||||
$("html").animate({
|
||||
scrollTop: destOffset
|
||||
}, 500, () => {
|
||||
$target.focus();
|
||||
|
||||
/* clean up old scroll mark */
|
||||
if ($(`[${ATTR_SCROLL_FOCUS}=true]`).length) {
|
||||
$(`[${ATTR_SCROLL_FOCUS}=true]`).attr(ATTR_SCROLL_FOCUS, false);
|
||||
}
|
||||
/* clean up old scroll mark */
|
||||
if ($(`[${ATTR_SCROLL_FOCUS}=true]`).length) {
|
||||
$(`[${ATTR_SCROLL_FOCUS}=true]`).attr(ATTR_SCROLL_FOCUS, false);
|
||||
}
|
||||
|
||||
/* Clean :target links */
|
||||
if ($(":target").length) { /* element that visited by the URL with hash */
|
||||
$(":target").attr(ATTR_SCROLL_FOCUS, false);
|
||||
}
|
||||
/* Clean :target links */
|
||||
if ($(":target").length) { /* element that visited by the URL with hash */
|
||||
$(":target").attr(ATTR_SCROLL_FOCUS, false);
|
||||
}
|
||||
|
||||
/* set scroll mark to footnotes */
|
||||
if (toFootnote || toFootnoteRef) {
|
||||
$target.attr(ATTR_SCROLL_FOCUS, true);
|
||||
}
|
||||
/* set scroll mark to footnotes */
|
||||
if (toFootnote || toFootnoteRef) {
|
||||
$target.attr(ATTR_SCROLL_FOCUS, true);
|
||||
}
|
||||
|
||||
if ($target.is(":focus")) { /* Checking if the target was focused */
|
||||
return false;
|
||||
} else {
|
||||
$target.attr("tabindex", "-1"); /* Adding tabindex for elements not focusable */
|
||||
$target.focus(); /* Set focus again */
|
||||
}
|
||||
if ($target.is(":focus")) { /* Checking if the target was focused */
|
||||
return false;
|
||||
} else {
|
||||
$target.attr("tabindex", "-1"); /* Adding tabindex for elements not focusable */
|
||||
$target.focus(); /* Set focus again */
|
||||
}
|
||||
|
||||
if (ScrollHelper.hasScrollUpTask()) {
|
||||
ScrollHelper.popScrollUpTask();
|
||||
}
|
||||
});
|
||||
}); /* click() */
|
||||
if (ScrollHelper.hasScrollUpTask()) {
|
||||
ScrollHelper.popScrollUpTask();
|
||||
}
|
||||
});
|
||||
}); /* click() */
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user