hexo-theme-stellar/source/js/main.js

387 lines
12 KiB
JavaScript
Raw Normal View History

2022-10-29 17:23:32 +08:00
console.log('\n' + '%c Stellar v' + stellar.version + ' %c\n' + stellar.github + '\n', 'color:#e8fafe;background:#03c7fa;padding:8px;border-radius:4px', 'margin-top:8px');
2021-02-21 17:27:48 +08:00
// utils
const util = {
2021-02-19 23:33:19 +08:00
2021-02-21 17:27:48 +08:00
// 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
2021-02-20 14:56:07 +08:00
}
2021-02-21 17:27:48 +08:00
} else {
result = parseInt(dateDiff / day)
2021-02-20 14:56:07 +08:00
}
2021-02-21 17:27:48 +08:00
return result
},
2021-02-27 20:08:36 +08:00
copy: (id, msg) => {
const el = document.getElementById(id);
2021-02-25 13:12:04 +08:00
if (el) {
el.select();
document.execCommand("Copy");
2021-02-27 21:50:18 +08:00
if (msg && msg.length > 0) {
hud.toast(msg);
}
2021-02-25 13:12:04 +08:00
}
},
2021-02-27 20:08:36 +08:00
toggle: (id) => {
const el = document.getElementById(id);
2021-02-25 13:12:04 +08:00
if (el) {
el.classList.toggle("display");
}
},
2021-02-19 23:33:19 +08:00
}
2021-02-27 20:08:36 +08:00
const hud = {
toast: (msg, duration) => {
2022-01-21 11:24:32 +08:00
duration = isNaN(duration) ? 2000 : duration;
2021-02-27 20:08:36 +08:00
var el = document.createElement('div');
el.classList.add('toast');
el.innerHTML = msg;
document.body.appendChild(el);
2022-01-21 11:24:32 +08:00
setTimeout(function () {
2021-02-27 20:08:36 +08:00
var d = 0.5;
el.style.webkitTransition = '-webkit-transform ' + d + 's ease-in, opacity ' + d + 's ease-in';
el.style.opacity = '0';
2022-01-21 11:24:32 +08:00
setTimeout(function () { document.body.removeChild(el) }, d * 1000);
2021-02-27 20:08:36 +08:00
}, duration);
},
}
2021-02-21 17:27:48 +08:00
// defines
const l_body = document.querySelector('.l_body');
const sidebar = {
toggle: () => {
if (l_body) {
l_body.classList.add('mobile');
l_body.classList.toggle("sidebar");
}
}
}
const init = {
toc: () => {
2021-03-13 23:31:52 +08:00
stellar.jQuery(() => {
2021-02-21 17:27:48 +08:00
const scrollOffset = 32;
var segs = [];
2022-11-23 22:44:11 +08:00
$("article.md-text :header").each(function (idx, node) {
2021-02-21 17:27:48 +08:00
segs.push(node)
});
2022-12-16 23:45:36 +08:00
// 定位到激活的目录树不如pjax体验好
// const widgets = document.querySelector('.widgets')
// const e1 = document.querySelector('.doc-tree-link.active')
// const offsetTop = e1.getBoundingClientRect().top - widgets.getBoundingClientRect().top - 100
// if (offsetTop > 0) {
// widgets.scrollBy({top: offsetTop, behavior: 'smooth'})
// }
2021-02-21 17:27:48 +08:00
// 滚动
2022-01-21 11:24:32 +08:00
$(document, window).scroll(function (e) {
2021-02-21 17:27:48 +08:00
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) {
2022-12-12 21:07:22 +08:00
$("#data-toc a.toc-link").removeClass("active")
2021-02-21 17:27:48 +08:00
var link = "#" + topSeg.attr("id")
if (link != '#undefined') {
2022-12-16 23:45:36 +08:00
const highlightItem = $('#data-toc a.toc-link[href="' + encodeURI(link) + '"]')
if (highlightItem.length > 0) {
highlightItem.addClass("active")
const e0 = document.querySelector('.widgets')
const e1 = document.querySelector('#data-toc a.toc-link[href="' + encodeURI(link) + '"]')
const offsetBottom = e1.getBoundingClientRect().bottom - e0.getBoundingClientRect().bottom + 100
const offsetTop = e1.getBoundingClientRect().top - e0.getBoundingClientRect().top - 80
if (offsetTop < 0) {
e0.scrollBy(0, offsetTop)
} else if (offsetBottom > 0) {
e0.scrollBy(0, offsetBottom)
}
}
2021-02-21 17:27:48 +08:00
} else {
2022-12-12 21:07:22 +08:00
$('#data-toc a.toc-link:first').addClass("active")
2021-02-21 17:27:48 +08:00
}
}
})
})
},
sidebar: () => {
2021-03-13 23:31:52 +08:00
stellar.jQuery(() => {
2022-12-12 21:07:22 +08:00
$("#data-toc a.toc-link").click(function (e) {
2021-02-21 17:27:48 +08:00
l_body.classList.remove("sidebar");
});
})
},
relativeDate: (selector) => {
selector.forEach(item => {
const $this = item
const timeVal = $this.getAttribute('datetime')
let relativeValue = util.diffDate(timeVal, true)
if (relativeValue) {
$this.innerText = relativeValue
}
})
2021-03-08 17:54:23 +08:00
},
/**
* Tabs tag listener (without twitter bootstrap).
*/
2022-01-21 11:24:32 +08:00
registerTabsTag: function () {
2021-03-08 17:54:23 +08:00
// Binding `nav-tabs` & `tab-content` by real time permalink changing.
2022-12-15 22:09:01 +08:00
document.querySelectorAll('.tabs .nav-tabs .tab').forEach(element => {
2021-03-08 17:54:23 +08:00
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'));
},
2021-02-21 17:27:48 +08:00
}
// init
init.toc()
init.sidebar()
init.relativeDate(document.querySelectorAll('#post-meta time'))
2021-03-08 17:54:23 +08:00
init.registerTabsTag()
2021-02-21 17:27:48 +08:00
// scrollreveal
if (stellar.plugins.scrollreveal) {
2021-03-13 23:31:52 +08:00
stellar.loadScript(stellar.plugins.scrollreveal.js).then(function () {
2021-02-21 17:27:48 +08:00
ScrollReveal().reveal("body .reveal", {
distance: stellar.plugins.scrollreveal.distance,
duration: stellar.plugins.scrollreveal.duration,
interval: stellar.plugins.scrollreveal.interval,
scale: stellar.plugins.scrollreveal.scale,
2021-07-13 22:25:24 +08:00
easing: "ease-out"
2021-02-21 17:27:48 +08:00
});
})
}
// lazyload
if (stellar.plugins.lazyload) {
2022-01-21 11:24:32 +08:00
stellar.loadScript(stellar.plugins.lazyload.js, { defer: true })
2021-02-21 17:27:48 +08:00
// https://www.npmjs.com/package/vanilla-lazyload
// Set the options globally
// to make LazyLoad self-initialize
window.lazyLoadOptions = {
2021-03-04 23:38:41 +08:00
elements_selector: ".lazy",
2021-02-21 17:27:48 +08:00
};
// 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 () {
2022-11-27 21:44:34 +08:00
window.lazyLoadInstance?.update();
2021-02-19 23:33:19 +08:00
});
}
2022-10-07 02:38:51 +08:00
// stellar js
if (stellar.plugins.stellar) {
for (let key of Object.keys(stellar.plugins.stellar)) {
let js = stellar.plugins.stellar[key];
2022-10-25 22:41:56 +08:00
if (key == 'linkcard') {
stellar.loadScript(js, { defer: true }).then(function () {
2022-11-03 22:25:08 +08:00
setCardLink(document.querySelectorAll('a.link-card[cardlink]'));
2022-10-25 22:41:56 +08:00
});
} else {
const els = document.getElementsByClassName('stellar-' + key + '-api');
if (els != undefined && els.length > 0) {
stellar.jQuery(() => {
stellar.loadScript(js, { defer: true });
if (key == 'timeline') {
stellar.loadScript(stellar.plugins.marked);
}
})
}
2022-10-07 02:38:51 +08:00
}
2022-10-05 17:34:16 +08:00
}
}
2021-02-20 14:56:07 +08:00
2021-02-21 17:27:48 +08:00
// swiper
if (stellar.plugins.swiper) {
const swiper_api = document.getElementById('swiper-api');
if (swiper_api != undefined) {
2021-03-13 23:31:52 +08:00
stellar.loadCSS(stellar.plugins.swiper.css);
2022-01-21 11:24:32 +08:00
stellar.loadScript(stellar.plugins.swiper.js, { defer: true }).then(function () {
2022-12-11 19:44:51 +08:00
const effect = swiper_api.getAttribute('effect') || '';
var swiper = new Swiper('.swiper#swiper-api', {
2021-02-21 17:27:48 +08:00
slidesPerView: 'auto',
spaceBetween: 8,
centeredSlides: true,
2022-12-11 19:44:51 +08:00
effect: effect,
2021-02-22 22:03:02 +08:00
loop: true,
2021-02-21 17:27:48 +08:00
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 == 'instant_page') {
2021-03-13 23:31:52 +08:00
stellar.loadScript(stellar.plugins.preload.instant_page, {
2021-02-21 18:48:38 +08:00
defer: true,
type: 'module',
2021-02-21 17:27:48 +08:00
integrity: 'sha384-OeDn4XE77tdHo8pGtE1apMPmAipjoxUQ++eeJa6EtJCfHlvijigWiJpD7VDPWXV1'
})
} else if (stellar.plugins.preload.service == 'flying_pages') {
window.FPConfig = {
delay: 0,
ignoreKeywords: [],
maxRPS: 5,
hoverDelay: 25
};
2022-01-21 11:24:32 +08:00
stellar.loadScript(stellar.plugins.preload.flying_pages, { defer: true })
2021-02-21 17:27:48 +08:00
}
}
2022-01-21 11:24:32 +08:00
// fancybox
if (stellar.plugins.fancybox) {
2022-01-27 13:46:11 +08:00
let selector = 'img[fancybox]:not(.error)';
if (stellar.plugins.fancybox.selector) {
selector += `, ${stellar.plugins.fancybox.selector}`
2022-01-21 11:24:32 +08:00
}
if (document.querySelectorAll(selector).length !== 0) {
stellar.loadCSS(stellar.plugins.fancybox.css);
stellar.loadScript(stellar.plugins.fancybox.js, { defer: true }).then(function () {
Fancybox.bind(selector, {
groupAll: true,
hideScrollbar: false,
Thumbs: {
autoStart: false,
},
caption: function (fancybox, carousel, slide) {
return slide.$trigger.alt || null
}
});
})
}
2022-01-27 13:46:11 +08:00
}
2022-03-02 14:50:45 +08:00
2022-11-27 17:16:38 +08:00
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");
2022-12-15 12:59:39 +08:00
if ($inputArea.length == 0) {
return;
}
2022-11-27 17:16:38 +08:00
var $resultArea = document.querySelector("div#search-result");
$inputArea.focus(function() {
2022-11-28 23:07:50 +08:00
var path = stellar.search[stellar.search.service]?.path || '/search.json';
2022-11-27 21:22:18 +08:00
if (!path.startsWith('/')) {
path = '/' + path;
}
2022-11-27 17:16:38 +08:00
const filter = $inputArea.attr('data-filter') || '';
searchFunc(path, filter, '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 });
});
})
}
}
2022-03-02 14:50:45 +08:00
// 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)();
2022-03-02 14:50:45 +08:00
stellar.plugins.heti.enable = false;
});
}