style: 4 space indents to the JS files

This commit is contained in:
Cotes Chung 2022-10-25 19:26:44 +08:00
parent 1fd665bf49
commit 339293d0d7
No known key found for this signature in database
GPG key ID: 0D9E54843167A808
21 changed files with 913 additions and 912 deletions

View file

@ -2,10 +2,13 @@ root = true
[*]
charset = utf-8
# 2 space indentation
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
# Unix-style newlines with a newline ending every file
end_of_line = lf
insert_final_newline = true
[*.js]
indent_size = 4

View file

@ -1,20 +1,20 @@
/*
Reference: https://bootsnipp.com/snippets/featured/link-to-top-page
*/
/**
* Reference: https://bootsnipp.com/snippets/featured/link-to-top-page
*/
$(function() {
$(window).scroll(() => {
if ($(this).scrollTop() > 50 &&
$("#sidebar-trigger").css("display") === "none") {
$("#back-to-top").fadeIn();
} else {
$("#back-to-top").fadeOut();
}
});
$(window).scroll(() => {
if ($(this).scrollTop() > 50 &&
$("#sidebar-trigger").css("display") === "none") {
$("#back-to-top").fadeIn();
} else {
$("#back-to-top").fadeOut();
}
});
$("#back-to-top").click(() => {
$("body,html").animate({
scrollTop: 0
}, 800);
return false;
});
$("#back-to-top").click(() => {
$("body,html").animate({
scrollTop: 0
}, 800);
return false;
});
});

View file

@ -1,13 +1,13 @@
/*
/**
* Listener for theme mode toggle
*/
$(function() {
$(".mode-toggle").click((e) => {
const $target = $(e.target);
let $btn = ($target.prop("tagName") === "button".toUpperCase() ?
$target : $target.parent());
$(function () {
$(".mode-toggle").click((e) => {
const $target = $(e.target);
let $btn = ($target.prop("tagName") === "button".toUpperCase() ?
$target : $target.parent());
$btn.blur(); // remove the clicking outline
flipMode();
});
$btn.blur(); // remove the clicking outline
flipMode();
});
});

View file

@ -2,35 +2,37 @@
* A tool for smooth scrolling and topbar switcher
*/
const ScrollHelper = (function () {
const $body = $("body");
const ATTR_TOPBAR_VISIBLE = "data-topbar-visible";
const topbarHeight = $("#topbar-wrapper").outerHeight();
const $body = $("body");
const ATTR_TOPBAR_VISIBLE = "data-topbar-visible";
const topbarHeight = $("#topbar-wrapper").outerHeight();
let scrollUpCount = 0; // the number of times the scroll up was triggered by ToC or anchor
let topbarLocked = false;
let orientationLocked = false;
let scrollUpCount = 0; // the number of times the scroll up was triggered by ToC or anchor
let topbarLocked = false;
let orientationLocked = false;
return {
hideTopbar: () => $body.attr(ATTR_TOPBAR_VISIBLE, false),
showTopbar: () => $body.attr(ATTR_TOPBAR_VISIBLE, true),
return {
hideTopbar: () => $body.attr(ATTR_TOPBAR_VISIBLE, false),
showTopbar: () => $body.attr(ATTR_TOPBAR_VISIBLE, true),
// scroll up
// scroll up
addScrollUpTask: () => {
scrollUpCount += 1;
if (!topbarLocked) { topbarLocked = true; }
},
popScrollUpTask: () => scrollUpCount -= 1,
hasScrollUpTask: () => scrollUpCount > 0,
topbarLocked: () => topbarLocked === true,
unlockTopbar: () => topbarLocked = false,
getTopbarHeight: () => topbarHeight,
addScrollUpTask: () => {
scrollUpCount += 1;
if (!topbarLocked) {
topbarLocked = true;
}
},
popScrollUpTask: () => scrollUpCount -= 1,
hasScrollUpTask: () => scrollUpCount > 0,
topbarLocked: () => topbarLocked === true,
unlockTopbar: () => topbarLocked = false,
getTopbarHeight: () => topbarHeight,
// orientation change
// orientation change
orientationLocked: () => orientationLocked === true,
lockOrientation: () => orientationLocked = true,
unLockOrientation: () => orientationLocked = false
};
orientationLocked: () => orientationLocked === true,
lockOrientation: () => orientationLocked = true,
unLockOrientation: () => orientationLocked = false
};
}());

View file

@ -1,129 +1,129 @@
/*
* This script make #search-result-wrapper switch to unloaded or shown automatically.
*/
/**
* This script make #search-result-wrapper switch to unloaded or shown automatically.
*/
$(function() {
const btnSbTrigger = $("#sidebar-trigger");
const btnSearchTrigger = $("#search-trigger");
const btnCancel = $("#search-cancel");
const main = $("#main");
const topbarTitle = $("#topbar-title");
const searchWrapper = $("#search-wrapper");
const resultWrapper = $("#search-result-wrapper");
const results = $("#search-results");
const input = $("#search-input");
const hints = $("#search-hints");
$(function () {
const btnSbTrigger = $("#sidebar-trigger");
const btnSearchTrigger = $("#search-trigger");
const btnCancel = $("#search-cancel");
const main = $("#main");
const topbarTitle = $("#topbar-title");
const searchWrapper = $("#search-wrapper");
const resultWrapper = $("#search-result-wrapper");
const results = $("#search-results");
const input = $("#search-input");
const hints = $("#search-hints");
const scrollBlocker = (function () {
let offset = 0;
return {
block() {
offset = window.scrollY;
$("html,body").scrollTop(0);
},
release() {
$("html,body").scrollTop(offset);
},
getOffset() {
return offset;
}
};
}());
const scrollBlocker = (function () {
let offset = 0;
return {
block() {
offset = window.scrollY;
$("html,body").scrollTop(0);
},
release() {
$("html,body").scrollTop(offset);
},
getOffset() {
return offset;
}
};
}());
/*--- Actions in mobile screens (Sidebar hidden) ---*/
/*--- Actions in mobile screens (Sidebar hidden) ---*/
const mobileSearchBar = (function () {
return {
on() {
btnSbTrigger.addClass("unloaded");
topbarTitle.addClass("unloaded");
btnSearchTrigger.addClass("unloaded");
searchWrapper.addClass("d-flex");
btnCancel.addClass("loaded");
},
off() {
btnCancel.removeClass("loaded");
searchWrapper.removeClass("d-flex");
btnSbTrigger.removeClass("unloaded");
topbarTitle.removeClass("unloaded");
btnSearchTrigger.removeClass("unloaded");
}
};
}());
const mobileSearchBar = (function () {
return {
on() {
btnSbTrigger.addClass("unloaded");
topbarTitle.addClass("unloaded");
btnSearchTrigger.addClass("unloaded");
searchWrapper.addClass("d-flex");
btnCancel.addClass("loaded");
},
off() {
btnCancel.removeClass("loaded");
searchWrapper.removeClass("d-flex");
btnSbTrigger.removeClass("unloaded");
topbarTitle.removeClass("unloaded");
btnSearchTrigger.removeClass("unloaded");
}
};
}());
const resultSwitch = (function () {
let visible = false;
const resultSwitch = (function () {
let visible = false;
return {
on() {
if (!visible) {
// the block method must be called before $(#main) unloaded.
scrollBlocker.block();
resultWrapper.removeClass("unloaded");
main.addClass("unloaded");
visible = true;
}
},
off() {
if (visible) {
results.empty();
if (hints.hasClass("unloaded")) {
hints.removeClass("unloaded");
}
resultWrapper.addClass("unloaded");
main.removeClass("unloaded");
return {
on() {
if (!visible) {
// the block method must be called before $(#main) unloaded.
scrollBlocker.block();
resultWrapper.removeClass("unloaded");
main.addClass("unloaded");
visible = true;
}
},
off() {
if (visible) {
results.empty();
if (hints.hasClass("unloaded")) {
hints.removeClass("unloaded");
}
resultWrapper.addClass("unloaded");
main.removeClass("unloaded");
// now the release method must be called after $(#main) display
scrollBlocker.release();
// now the release method must be called after $(#main) display
scrollBlocker.release();
input.val("");
visible = false;
}
},
isVisible() {
return visible;
}
};
input.val("");
visible = false;
}
},
isVisible() {
return visible;
}
};
}());
}());
function isMobileView() {
return btnCancel.hasClass("loaded");
}
btnSearchTrigger.click(function() {
mobileSearchBar.on();
resultSwitch.on();
input.focus();
});
btnCancel.click(function() {
mobileSearchBar.off();
resultSwitch.off();
});
input.focus(function() {
searchWrapper.addClass("input-focus");
});
input.focusout(function() {
searchWrapper.removeClass("input-focus");
});
input.on("input", () => {
if (input.val() === "") {
if (isMobileView()) {
hints.removeClass("unloaded");
} else {
resultSwitch.off();
}
} else {
resultSwitch.on();
if (isMobileView()) {
hints.addClass("unloaded");
}
function isMobileView() {
return btnCancel.hasClass("loaded");
}
});
btnSearchTrigger.click(function () {
mobileSearchBar.on();
resultSwitch.on();
input.focus();
});
btnCancel.click(function () {
mobileSearchBar.off();
resultSwitch.off();
});
input.focus(function () {
searchWrapper.addClass("input-focus");
});
input.focusout(function () {
searchWrapper.removeClass("input-focus");
});
input.on("input", () => {
if (input.val() === "") {
if (isMobileView()) {
hints.removeClass("unloaded");
} else {
resultSwitch.off();
}
} else {
resultSwitch.on();
if (isMobileView()) {
hints.addClass("unloaded");
}
}
});
});

View file

@ -2,29 +2,27 @@
* Expand or close the sidebar in mobile screens.
*/
$(function() {
$(function () {
const sidebarUtil = (function () {
const ATTR_DISPLAY = "sidebar-display";
let isExpanded = false;
const body = $("body");
const sidebarUtil = (function () {
const ATTR_DISPLAY = "sidebar-display";
let isExpanded = false;
const body = $("body");
return {
toggle() {
if (isExpanded === false) {
body.attr(ATTR_DISPLAY, "");
} else {
body.removeAttr(ATTR_DISPLAY);
}
return {
toggle() {
if (isExpanded === false) {
body.attr(ATTR_DISPLAY, "");
} else {
body.removeAttr(ATTR_DISPLAY);
}
isExpanded = !isExpanded;
}
};
isExpanded = !isExpanded;
}
};
}());
}());
$("#sidebar-trigger").click(sidebarUtil.toggle);
$("#mask").click(sidebarUtil.toggle);
$("#sidebar-trigger").click(sidebarUtil.toggle);
$("#mask").click(sidebarUtil.toggle);
});

View file

@ -1,6 +1,6 @@
/**
* Initial Bootstrap Tooltip.
*/
*/
$(function () {
$("[data-toggle=\"tooltip\"]").tooltip();
$("[data-toggle=\"tooltip\"]").tooltip();
});

View file

@ -1,90 +1,89 @@
/*
/**
* Hide Header on scroll down
*/
$(function() {
const $searchInput = $("#search-input");
const delta = ScrollHelper.getTopbarHeight();
$(function () {
const $searchInput = $("#search-input");
const delta = ScrollHelper.getTopbarHeight();
let didScroll;
let lastScrollTop = 0;
let didScroll;
let lastScrollTop = 0;
function hasScrolled() {
let st = $(this).scrollTop();
function hasScrolled() {
let st = $(this).scrollTop();
/* Make sure they scroll more than delta */
if (Math.abs(lastScrollTop - st) <= delta) {
return;
}
if (st > lastScrollTop ) { // Scroll Down
ScrollHelper.hideTopbar();
if ($searchInput.is(":focus")) {
$searchInput.blur(); /* remove focus */
}
} else { // Scroll up
// has not yet scrolled to the bottom of the screen, that is, there is still space for scrolling
if (st + $(window).height() < $(document).height()) {
if (ScrollHelper.hasScrollUpTask()) {
return;
/* Make sure they scroll more than delta */
if (Math.abs(lastScrollTop - st) <= delta) {
return;
}
if (ScrollHelper.topbarLocked()) { // avoid redundant scroll up event from smooth scrolling
ScrollHelper.unlockTopbar();
} else {
if (ScrollHelper.orientationLocked()) { // avoid device auto scroll up on orientation change
ScrollHelper.unLockOrientation();
} else {
ScrollHelper.showTopbar();
}
if (st > lastScrollTop) { // Scroll Down
ScrollHelper.hideTopbar();
if ($searchInput.is(":focus")) {
$searchInput.blur(); /* remove focus */
}
} else { // Scroll up
// has not yet scrolled to the bottom of the screen, that is, there is still space for scrolling
if (st + $(window).height() < $(document).height()) {
if (ScrollHelper.hasScrollUpTask()) {
return;
}
if (ScrollHelper.topbarLocked()) { // avoid redundant scroll up event from smooth scrolling
ScrollHelper.unlockTopbar();
} else {
if (ScrollHelper.orientationLocked()) { // avoid device auto scroll up on orientation change
ScrollHelper.unLockOrientation();
} else {
ScrollHelper.showTopbar();
}
}
}
}
}
lastScrollTop = st;
} // hasScrolled()
function handleLandscape() {
if ($(window).scrollTop() === 0) {
return;
}
ScrollHelper.lockOrientation();
ScrollHelper.hideTopbar();
}
lastScrollTop = st;
if (screen.orientation) {
screen.orientation.onchange = () => {
const type = screen.orientation.type;
if (type === "landscape-primary" || type === "landscape-secondary") {
handleLandscape();
}
};
} // hasScrolled()
function handleLandscape() {
if ($(window).scrollTop() === 0) {
return;
} else {
// for the browsers that not support `window.screen.orientation` API
$(window).on("orientationchange", () => {
if ($(window).width() < $(window).height()) { // before rotating, it is still in portrait mode.
handleLandscape();
}
});
}
ScrollHelper.lockOrientation();
ScrollHelper.hideTopbar();
}
if (screen.orientation) {
screen.orientation.onchange = () => {
const type = screen.orientation.type;
if (type === "landscape-primary" || type === "landscape-secondary") {
handleLandscape();
}
};
} else {
// for the browsers that not support `window.screen.orientation` API
$(window).on("orientationchange",() => {
if ($(window).width() < $(window).height()) { // before rotating, it is still in portrait mode.
handleLandscape();
}
$(window).scroll(() => {
if (didScroll) {
return;
}
didScroll = true;
});
}
$(window).scroll(() => {
if (didScroll) {
return;
}
didScroll = true;
});
setInterval(() => {
if (didScroll) {
hasScrolled();
didScroll = false;
}
}, 250);
setInterval(() => {
if (didScroll) {
hasScrolled();
didScroll = false;
}
}, 250);
});

View file

@ -1,67 +1,67 @@
/*
/**
* Top bar title auto change while scrolling up/down in mobile screens.
*/
*/
$(function() {
const titleSelector = "div.post>h1:first-of-type";
const $pageTitle = $(titleSelector);
const $topbarTitle = $("#topbar-title");
$(function () {
const titleSelector = "div.post>h1:first-of-type";
const $pageTitle = $(titleSelector);
const $topbarTitle = $("#topbar-title");
if ($pageTitle.length === 0 /* on Home page */
|| $pageTitle.hasClass("dynamic-title")
|| $topbarTitle.is(":hidden")) {/* not in mobile views */
return;
}
const defaultTitleText = $topbarTitle.text().trim();
let pageTitleText = $pageTitle.text().trim();
let hasScrolled = false;
let lastScrollTop = 0;
if ($("#page-category").length || $("#page-tag").length) {
/* The title in Category or Tag page will be "<title> <count_of_posts>" */
if (/\s/.test(pageTitleText)) {
pageTitleText = pageTitleText.replace(/[0-9]/g, "").trim();
}
}
// When the page is scrolled down and then refreshed, the topbar title needs to be initialized
if ($pageTitle.offset().top < $(window).scrollTop()) {
$topbarTitle.text(pageTitleText);
}
let options = {
rootMargin: '-48px 0px 0px 0px', // 48px equals to the topbar height (3rem)
threshold: [0, 1]
};
let observer = new IntersectionObserver((entries) => {
if (!hasScrolled) {
hasScrolled = true;
return;
if ($pageTitle.length === 0 /* on Home page */
|| $pageTitle.hasClass("dynamic-title")
|| $topbarTitle.is(":hidden")) {/* not in mobile views */
return;
}
let curScrollTop = $(window).scrollTop();
let isScrollDown = lastScrollTop < curScrollTop;
lastScrollTop = curScrollTop;
let heading = entries[0];
const defaultTitleText = $topbarTitle.text().trim();
let pageTitleText = $pageTitle.text().trim();
let hasScrolled = false;
let lastScrollTop = 0;
if (isScrollDown) {
if (heading.intersectionRatio === 0) {
if ($("#page-category").length || $("#page-tag").length) {
/* The title in Category or Tag page will be "<title> <count_of_posts>" */
if (/\s/.test(pageTitleText)) {
pageTitleText = pageTitleText.replace(/[0-9]/g, "").trim();
}
}
// When the page is scrolled down and then refreshed, the topbar title needs to be initialized
if ($pageTitle.offset().top < $(window).scrollTop()) {
$topbarTitle.text(pageTitleText);
}
} else {
if (heading.intersectionRatio === 1) {
$topbarTitle.text(defaultTitleText);
}
}
}, options);
observer.observe(document.querySelector(titleSelector));
let options = {
rootMargin: '-48px 0px 0px 0px', // 48px equals to the topbar height (3rem)
threshold: [0, 1]
};
/* Click title will scroll to top */
$topbarTitle.click(function() {
$("body,html").animate({scrollTop: 0}, 800);
});
let observer = new IntersectionObserver((entries) => {
if (!hasScrolled) {
hasScrolled = true;
return;
}
let curScrollTop = $(window).scrollTop();
let isScrollDown = lastScrollTop < curScrollTop;
lastScrollTop = curScrollTop;
let heading = entries[0];
if (isScrollDown) {
if (heading.intersectionRatio === 0) {
$topbarTitle.text(pageTitleText);
}
} else {
if (heading.intersectionRatio === 1) {
$topbarTitle.text(defaultTitleText);
}
}
}, options);
observer.observe(document.querySelector(titleSelector));
/* Click title will scroll to top */
$topbarTitle.click(function () {
$("body,html").animate({scrollTop: 0}, 800);
});
});

View file

@ -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");
}
});
});

View file

@ -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);
});
});

View file

@ -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');
});

View file

@ -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);
});
});

View file

@ -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();
}
}
}
});

View file

@ -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() */
});

View file

@ -5,51 +5,50 @@ layout: compress
---
const resource = [
/* --- CSS --- */
'{{ "/assets/css/style.css" | relative_url }}',
/* --- CSS --- */
'{{ "/assets/css/style.css" | relative_url }}',
/* --- PWA --- */
'{{ "/app.js" | relative_url }}',
'{{ "/sw.js" | relative_url }}',
/* --- PWA --- */
'{{ "/app.js" | relative_url }}',
'{{ "/sw.js" | relative_url }}',
/* --- HTML --- */
'{{ "/index.html" | relative_url }}',
'{{ "/404.html" | relative_url }}',
/* --- HTML --- */
'{{ "/index.html" | relative_url }}',
'{{ "/404.html" | relative_url }}',
{% for tab in site.tabs %}
'{{ tab.url | relative_url }}',
{% endfor %}
/* --- Favicons & compressed JS --- */
{% assign cache_list = site.static_files | where: 'swcache', true %}
{% for file in cache_list %}
'{{ file.path | relative_url }}'{%- unless forloop.last -%},{%- endunless -%}
{% endfor %}
{% for tab in site.tabs %}
'{{ tab.url | relative_url }}',
{% endfor %}
/* --- Favicons & compressed JS --- */
{% assign cache_list = site.static_files | where: 'swcache', true %}
{% for file in cache_list %}
'{{ file.path | relative_url }}'{%- unless forloop.last -%},{%- endunless -%}
{% endfor %}
];
/* The request url with below domain will be cached */
const allowedDomains = [
{% if site.google_analytics.id != empty and site.google_analytics.id %}
'www.googletagmanager.com',
'www.google-analytics.com',
{% endif %}
{% if site.google_analytics.id != empty and site.google_analytics.id %}
'www.googletagmanager.com',
'www.google-analytics.com',
{% endif %}
'{{ site.url | split: "//" | last }}',
'{{ site.url | split: "//" | last }}',
{% if site.img_cdn contains '//' and site.img_cdn %}
'{{ site.img_cdn | split: '//' | last | split: '/' | first }}',
{% endif %}
{% if site.img_cdn contains '//' and site.img_cdn %}
'{{ site.img_cdn | split: '//' | last | split: '/' | first }}',
{% endif %}
'fonts.gstatic.com',
'fonts.googleapis.com',
'cdn.jsdelivr.net',
'polyfill.io'
'fonts.gstatic.com',
'fonts.googleapis.com',
'cdn.jsdelivr.net',
'polyfill.io'
];
/* Requests that include the following path will be banned */
const denyUrls = [
{% if site.google_analytics.pv.cache_path %}
'{{ site.google_analytics.pv.cache_path | absolute_url }}'
{% endif %}
{% if site.google_analytics.pv.cache_path %}
'{{ site.google_analytics.pv.cache_path | absolute_url }}'
{% endif %}
];

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -7,41 +7,41 @@ const $notification = $('#notification');
const $btnRefresh = $('#notification .toast-body>button');
if ('serviceWorker' in navigator) {
/* Registering Service Worker */
navigator.serviceWorker.register('{{ "/sw.js" | relative_url }}')
.then(registration => {
/* Registering Service Worker */
navigator.serviceWorker.register('{{ "/sw.js" | relative_url }}')
.then(registration => {
/* in case the user ignores the notification */
if (registration.waiting) {
$notification.toast('show');
}
registration.addEventListener('updatefound', () => {
registration.installing.addEventListener('statechange', () => {
if (registration.waiting) {
if (navigator.serviceWorker.controller) {
$notification.toast('show');
/* in case the user ignores the notification */
if (registration.waiting) {
$notification.toast('show');
}
}
registration.addEventListener('updatefound', () => {
registration.installing.addEventListener('statechange', () => {
if (registration.waiting) {
if (navigator.serviceWorker.controller) {
$notification.toast('show');
}
}
});
});
$btnRefresh.click(() => {
if (registration.waiting) {
registration.waiting.postMessage('SKIP_WAITING');
}
$notification.toast('hide');
});
});
});
$btnRefresh.click(() => {
if (registration.waiting) {
registration.waiting.postMessage('SKIP_WAITING');
let refreshing = false;
/* Detect controller change and refresh all the opened tabs */
navigator.serviceWorker.addEventListener('controllerchange', () => {
if (!refreshing) {
window.location.reload();
refreshing = true;
}
$notification.toast('hide');
});
}
);
let refreshing = false;
/* Detect controller change and refresh all the opened tabs */
navigator.serviceWorker.addEventListener('controllerchange', () => {
if (!refreshing) {
window.location.reload();
refreshing = true;
}
});
});
}

View file

@ -9,81 +9,82 @@ self.importScripts('{{ "/assets/js/data/swcache.js" | relative_url }}');
const cacheName = 'chirpy-{{ "now" | date: "%Y%m%d.%H%M%S" }}';
function verifyDomain(url) {
for (const domain of allowedDomains) {
const regex = RegExp(`^http(s)?:\/\/${domain}\/`);
if (regex.test(url)) {
return true;
for (const domain of allowedDomains) {
const regex = RegExp(`^http(s)?:\/\/${domain}\/`);
if (regex.test(url)) {
return true;
}
}
}
return false;
return false;
}
function isExcluded(url) {
for (const item of denyUrls) {
if (url === item) {
return true;
for (const item of denyUrls) {
if (url === item) {
return true;
}
}
}
return false;
return false;
}
self.addEventListener('install', event => {
event.waitUntil(
caches.open(cacheName).then(cache => {
return cache.addAll(resource);
})
);
event.waitUntil(
caches.open(cacheName).then(cache => {
return cache.addAll(resource);
})
);
});
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(keyList => {
return Promise.all(
keyList.map(key => {
if (key !== cacheName) {
return caches.delete(key);
}
event.waitUntil(
caches.keys().then(keyList => {
return Promise.all(
keyList.map(key => {
if (key !== cacheName) {
return caches.delete(key);
}
})
);
})
);
})
);
);
});
self.addEventListener('message', (event) => {
if (event.data === 'SKIP_WAITING') {
self.skipWaiting();
}
if (event.data === 'SKIP_WAITING') {
self.skipWaiting();
}
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
if (response) {
return response;
}
event.respondWith(
caches.match(event.request).then(response => {
if (response) {
return response;
}
return fetch(event.request).then(response => {
const url = event.request.url;
return fetch(event.request).then(response => {
const url = event.request.url;
if (event.request.method !== 'GET' ||
!verifyDomain(url) ||
isExcluded(url)) {
return response;
}
if (event.request.method !== 'GET' ||
!verifyDomain(url) ||
isExcluded(url)) {
return response;
}
/*
see: <https://developers.google.com/web/fundamentals/primers/service-workers#cache_and_return_requests>
*/
let responseToCache = response.clone();
/*
see: <https://developers.google.com/web/fundamentals/primers/service-workers#cache_and_return_requests>
*/
let responseToCache = response.clone();
caches.open(cacheName).then(cache => {
/* console.log('[sw] Caching new resource: ' + event.request.url); */
cache.put(event.request, responseToCache);
});
caches.open(cacheName).then(cache => {
/* console.log('[sw] Caching new resource: ' + event.request.url); */
cache.put(event.request, responseToCache);
});
return response;
});
})
);
return response;
});
})
);
});

View file

@ -4,9 +4,9 @@ permalink: '/unregister.js'
---
if ('serviceWorker' in navigator) {
navigator.serviceWorker.getRegistrations().then((registrations) => {
for (let reg of registrations) {
reg.unregister();
}
});
navigator.serviceWorker.getRegistrations().then((registrations) => {
for (let reg of registrations) {
reg.unregister();
}
});
}