419 lines
12 KiB
JavaScript
419 lines
12 KiB
JavaScript
// utils
|
|
const util = {
|
|
|
|
// https://github.com/jerryc127/hexo-theme-butterfly
|
|
diffDate: (d, more = false) => {
|
|
const dateNow = new Date()
|
|
const datePost = new Date(d)
|
|
const dateDiff = dateNow.getTime() - datePost.getTime()
|
|
const minute = 1000 * 60
|
|
const hour = minute * 60
|
|
const day = hour * 24
|
|
const month = day * 30
|
|
|
|
let result
|
|
if (more) {
|
|
const monthCount = dateDiff / month
|
|
const dayCount = dateDiff / day
|
|
const hourCount = dateDiff / hour
|
|
const minuteCount = dateDiff / minute
|
|
|
|
if (monthCount > 12) {
|
|
result = null
|
|
} else if (monthCount >= 1) {
|
|
result = parseInt(monthCount) + ' ' + stellar.config.date_suffix.month
|
|
} else if (dayCount >= 1) {
|
|
result = parseInt(dayCount) + ' ' + stellar.config.date_suffix.day
|
|
} else if (hourCount >= 1) {
|
|
result = parseInt(hourCount) + ' ' + stellar.config.date_suffix.hour
|
|
} else if (minuteCount >= 1) {
|
|
result = parseInt(minuteCount) + ' ' + stellar.config.date_suffix.min
|
|
} else {
|
|
result = stellar.config.date_suffix.just
|
|
}
|
|
} else {
|
|
result = parseInt(dateDiff / day)
|
|
}
|
|
return result
|
|
},
|
|
|
|
copy: (id, msg) => {
|
|
const el = document.getElementById(id);
|
|
if (el) {
|
|
el.select();
|
|
document.execCommand("Copy");
|
|
if (msg && msg.length > 0) {
|
|
hud.toast(msg, 2500);
|
|
}
|
|
}
|
|
},
|
|
|
|
toggle: (id) => {
|
|
const el = document.getElementById(id);
|
|
if (el) {
|
|
el.classList.toggle("display");
|
|
}
|
|
},
|
|
|
|
scrollTop: () => {
|
|
window.scrollTo({top: 0, behavior: "smooth"});
|
|
},
|
|
}
|
|
|
|
const hud = {
|
|
toast: (msg, duration) => {
|
|
const d = Number(isNaN(duration) ? 2000 : duration);
|
|
var el = document.createElement('div');
|
|
el.classList.add('toast');
|
|
el.classList.add('show');
|
|
el.innerHTML = msg;
|
|
document.body.appendChild(el);
|
|
|
|
setTimeout(function(){ document.body.removeChild(el) }, d);
|
|
|
|
},
|
|
|
|
}
|
|
|
|
// defines
|
|
|
|
const l_body = document.querySelector('.l_body');
|
|
|
|
const sidebar = {
|
|
leftbar: () => {
|
|
if (l_body) {
|
|
l_body.toggleAttribute('leftbar');
|
|
l_body.removeAttribute('rightbar');
|
|
}
|
|
},
|
|
rightbar: () => {
|
|
if (l_body) {
|
|
l_body.toggleAttribute('rightbar');
|
|
l_body.removeAttribute('leftbar');
|
|
}
|
|
},
|
|
dismiss: () => {
|
|
if (l_body) {
|
|
l_body.removeAttribute('leftbar');
|
|
l_body.removeAttribute('rightbar');
|
|
}
|
|
},
|
|
toggleTOC: () => {
|
|
document.querySelector('#data-toc').classList.toggle('collapse');
|
|
}
|
|
}
|
|
|
|
const init = {
|
|
toc: () => {
|
|
stellar.jQuery(() => {
|
|
const scrollOffset = 32;
|
|
var segs = [];
|
|
$("article.md-text :header").each(function (idx, node) {
|
|
segs.push(node);
|
|
});
|
|
function activeTOC() {
|
|
var scrollTop = $(this).scrollTop();
|
|
var topSeg = null;
|
|
for (var idx in segs) {
|
|
var seg = $(segs[idx]);
|
|
if (seg.offset().top > scrollTop + scrollOffset) {
|
|
continue;
|
|
}
|
|
if (!topSeg) {
|
|
topSeg = seg;
|
|
} else if (seg.offset().top >= topSeg.offset().top) {
|
|
topSeg = seg;
|
|
}
|
|
}
|
|
if (topSeg) {
|
|
$("#data-toc a.toc-link").removeClass("active");
|
|
var link = "#" + topSeg.attr("id");
|
|
if (link != '#undefined') {
|
|
const highlightItem = $('#data-toc a.toc-link[href="' + encodeURI(link) + '"]');
|
|
if (highlightItem.length > 0) {
|
|
highlightItem.addClass("active");
|
|
}
|
|
} else {
|
|
$('#data-toc a.toc-link:first').addClass("active");
|
|
}
|
|
}
|
|
}
|
|
function scrollTOC() {
|
|
const e0 = document.querySelector('#data-toc .toc');
|
|
const e1 = document.querySelector('#data-toc .toc a.toc-link.active');
|
|
if (e0 == null || e1 == null) {
|
|
return;
|
|
}
|
|
const offsetBottom = e1.getBoundingClientRect().bottom - e0.getBoundingClientRect().bottom + 100;
|
|
const offsetTop = e1.getBoundingClientRect().top - e0.getBoundingClientRect().top - 64;
|
|
if (offsetTop < 0) {
|
|
e0.scrollBy({top: offsetTop, behavior: "smooth"});
|
|
} else if (offsetBottom > 0) {
|
|
e0.scrollBy({top: offsetBottom, behavior: "smooth"});
|
|
}
|
|
}
|
|
|
|
var timeout = null;
|
|
window.addEventListener('scroll', function() {
|
|
activeTOC();
|
|
if(timeout !== null) clearTimeout(timeout);
|
|
timeout = setTimeout(function() {
|
|
scrollTOC();
|
|
}.bind(this), 300);
|
|
});
|
|
})
|
|
},
|
|
leftbar: () => {
|
|
stellar.jQuery(() => {
|
|
$("#data-toc a.toc-link").click(function (e) {
|
|
l_body.classList.remove("leftbar");
|
|
});
|
|
})
|
|
},
|
|
relativeDate: (selector) => {
|
|
selector.forEach(item => {
|
|
const $this = item
|
|
const timeVal = $this.getAttribute('datetime')
|
|
let relativeValue = util.diffDate(timeVal, true)
|
|
if (relativeValue) {
|
|
$this.innerText = relativeValue
|
|
}
|
|
})
|
|
},
|
|
/**
|
|
* Tabs tag listener (without twitter bootstrap).
|
|
*/
|
|
registerTabsTag: function () {
|
|
// Binding `nav-tabs` & `tab-content` by real time permalink changing.
|
|
document.querySelectorAll('.tabs .nav-tabs .tab').forEach(element => {
|
|
element.addEventListener('click', event => {
|
|
event.preventDefault();
|
|
// Prevent selected tab to select again.
|
|
if (element.classList.contains('active')) return;
|
|
// Add & Remove active class on `nav-tabs` & `tab-content`.
|
|
[...element.parentNode.children].forEach(target => {
|
|
target.classList.toggle('active', target === element);
|
|
});
|
|
// https://stackoverflow.com/questions/20306204/using-queryselector-with-ids-that-are-numbers
|
|
const tActive = document.getElementById(element.querySelector('a').getAttribute('href').replace('#', ''));
|
|
[...tActive.parentNode.children].forEach(target => {
|
|
target.classList.toggle('active', target === tActive);
|
|
});
|
|
// Trigger event
|
|
tActive.dispatchEvent(new Event('tabs:click', {
|
|
bubbles: true
|
|
}));
|
|
});
|
|
});
|
|
|
|
window.dispatchEvent(new Event('tabs:register'));
|
|
},
|
|
|
|
}
|
|
|
|
|
|
// init
|
|
init.toc()
|
|
init.leftbar()
|
|
init.relativeDate(document.querySelectorAll('#post-meta time'))
|
|
init.registerTabsTag()
|
|
|
|
// scrollreveal
|
|
if (stellar.plugins.scrollreveal) {
|
|
stellar.loadScript(stellar.plugins.scrollreveal.js).then(function () {
|
|
const slideUp = {
|
|
distance: stellar.plugins.scrollreveal.distance,
|
|
duration: stellar.plugins.scrollreveal.duration,
|
|
interval: stellar.plugins.scrollreveal.interval,
|
|
scale: stellar.plugins.scrollreveal.scale,
|
|
opacity: 0,
|
|
easing: "ease-out"
|
|
}
|
|
ScrollReveal().reveal('.l_left .slide-up', slideUp)
|
|
ScrollReveal().reveal('.l_main .slide-up', slideUp)
|
|
})
|
|
}
|
|
|
|
// lazyload
|
|
if (stellar.plugins.lazyload) {
|
|
stellar.loadScript(stellar.plugins.lazyload.js, { defer: true })
|
|
// https://www.npmjs.com/package/vanilla-lazyload
|
|
// Set the options globally
|
|
// to make LazyLoad self-initialize
|
|
window.lazyLoadOptions = {
|
|
elements_selector: ".lazy",
|
|
};
|
|
// Listen to the initialization event
|
|
// and get the instance of LazyLoad
|
|
window.addEventListener(
|
|
"LazyLoad::Initialized",
|
|
function (event) {
|
|
window.lazyLoadInstance = event.detail.instance;
|
|
},
|
|
false
|
|
);
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
window.lazyLoadInstance?.update();
|
|
});
|
|
}
|
|
|
|
// stellar js
|
|
if (stellar.plugins.stellar) {
|
|
for (let key of Object.keys(stellar.plugins.stellar)) {
|
|
let js = stellar.plugins.stellar[key];
|
|
if (key == 'linkcard') {
|
|
stellar.loadScript(js, { defer: true }).then(function () {
|
|
setCardLink(document.querySelectorAll('a.link-card[cardlink]'));
|
|
});
|
|
} else {
|
|
const els = document.getElementsByClassName('stellar-' + key + '-api');
|
|
if (els != undefined && els.length > 0) {
|
|
stellar.jQuery(() => {
|
|
if (key == 'timeline' || 'memos' || 'marked') {
|
|
stellar.loadScript(stellar.plugins.marked).then(function () {
|
|
stellar.loadScript(js, { defer: true });
|
|
});
|
|
} else {
|
|
stellar.loadScript(js, { defer: true });
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// swiper
|
|
if (stellar.plugins.swiper) {
|
|
const swiper_api = document.getElementById('swiper-api');
|
|
if (swiper_api != undefined) {
|
|
stellar.loadCSS(stellar.plugins.swiper.css);
|
|
stellar.loadScript(stellar.plugins.swiper.js, { defer: true }).then(function () {
|
|
const effect = swiper_api.getAttribute('effect') || '';
|
|
var swiper = new Swiper('.swiper#swiper-api', {
|
|
slidesPerView: 'auto',
|
|
spaceBetween: 8,
|
|
centeredSlides: true,
|
|
effect: effect,
|
|
loop: true,
|
|
pagination: {
|
|
el: '.swiper-pagination',
|
|
clickable: true,
|
|
},
|
|
navigation: {
|
|
nextEl: '.swiper-button-next',
|
|
prevEl: '.swiper-button-prev',
|
|
},
|
|
});
|
|
})
|
|
}
|
|
}
|
|
|
|
// preload
|
|
if (stellar.plugins.preload) {
|
|
if (stellar.plugins.preload.service == 'flying_pages') {
|
|
window.FPConfig = {
|
|
delay: 0,
|
|
ignoreKeywords: [],
|
|
maxRPS: 5,
|
|
hoverDelay: 25
|
|
};
|
|
stellar.loadScript(stellar.plugins.preload.flying_pages, { defer: true })
|
|
}
|
|
}
|
|
|
|
// fancybox
|
|
if (stellar.plugins.fancybox) {
|
|
let selector = '[data-fancybox]:not(.error)';
|
|
if (stellar.plugins.fancybox.selector) {
|
|
selector += `, ${stellar.plugins.fancybox.selector}`
|
|
}
|
|
var needFancybox = document.querySelectorAll(selector).length !== 0;
|
|
if (!needFancybox) {
|
|
const els = document.getElementsByClassName('stellar-memos-api');
|
|
if (els != undefined && els.length > 0) {
|
|
needFancybox = true;
|
|
}
|
|
}
|
|
if (needFancybox) {
|
|
stellar.loadCSS(stellar.plugins.fancybox.css);
|
|
stellar.loadScript(stellar.plugins.fancybox.js, { defer: true }).then(function () {
|
|
Fancybox.bind(selector, {
|
|
hideScrollbar: false,
|
|
Thumbs: {
|
|
autoStart: false,
|
|
},
|
|
caption: (fancybox, slide) => {
|
|
return slide.triggerEl.alt || null
|
|
}
|
|
});
|
|
})
|
|
}
|
|
}
|
|
|
|
|
|
if (stellar.search.service) {
|
|
if (stellar.search.service == 'local_search') {
|
|
stellar.jQuery(() => {
|
|
stellar.loadScript('/js/search/local-search.js', { defer: true }).then(function () {
|
|
var $inputArea = $("input#search-input");
|
|
if ($inputArea.length == 0) {
|
|
return;
|
|
}
|
|
var $resultArea = document.querySelector("div#search-result");
|
|
$inputArea.focus(function() {
|
|
var path = stellar.search[stellar.search.service]?.path || '/search.json';
|
|
if (path.startsWith('/')) {
|
|
path = path.substring(1);
|
|
}
|
|
path = stellar.config.root + path;
|
|
const filter = $inputArea.attr('data-filter') || '';
|
|
searchFunc(path, filter, 'search-wrapper', 'search-input', 'search-result');
|
|
});
|
|
$inputArea.keydown(function(e) {
|
|
if (e.which == 13) {
|
|
e.preventDefault();
|
|
}
|
|
});
|
|
var observer = new MutationObserver(function(mutationsList, observer) {
|
|
if (mutationsList.length == 1) {
|
|
if (mutationsList[0].addedNodes.length) {
|
|
$('.search-wrapper').removeClass('noresult');
|
|
} else if (mutationsList[0].removedNodes.length) {
|
|
$('.search-wrapper').addClass('noresult');
|
|
}
|
|
}
|
|
});
|
|
observer.observe($resultArea, { childList: true });
|
|
});
|
|
})
|
|
}
|
|
}
|
|
|
|
|
|
// heti
|
|
if (stellar.plugins.heti) {
|
|
stellar.loadCSS(stellar.plugins.heti.css);
|
|
stellar.loadScript(stellar.plugins.heti.js, { defer: true }).then(function () {
|
|
const heti = new Heti('.heti');
|
|
|
|
// Copied from heti.autoSpacing() without DOMContentLoaded.
|
|
// https://github.com/sivan/heti/blob/eadee6a3b748b3b7924a9e7d5b395d4bce479c9a/js/heti-addon.js
|
|
//
|
|
// We managed to minimize the code modification to ensure .autoSpacing()
|
|
// is synced with upstream; therefore, we use `.bind()` to emulate the
|
|
// behavior of .autoSpacing() so we can even modify almost no code.
|
|
void (function () {
|
|
const $$rootList = document.querySelectorAll(this.rootSelector)
|
|
|
|
for (let $$root of $$rootList) {
|
|
this.spacingElement($$root)
|
|
}
|
|
}).bind(heti)();
|
|
|
|
stellar.plugins.heti.enable = false;
|
|
});
|
|
}
|
|
|
|
if (stellar.plugins.copycode) {
|
|
stellar.loadScript(stellar.plugins.copycode.js, { defer: true })
|
|
} |