hexo-theme-keep/source/js/utils.js

385 lines
12 KiB
JavaScript

/* global KEEP */
KEEP.initUtils = () => {
KEEP.utils = {
html_root_dom: document.querySelector('html'),
pageContainer_dom: document.querySelector('.page-container'),
pageTop_dom: document.querySelector('.page-main-content-top'),
firstScreen_dom: document.querySelector('.first-screen-container'),
scrollProgressBar_dom: document.querySelector('.scroll-progress-bar'),
pjaxProgressBar_dom: document.querySelector('.pjax-progress-bar'),
pjaxProgressIcon_dom: document.querySelector('.pjax-progress-icon'),
back2TopButton_dom: document.querySelector('.tool-scroll-to-top'),
innerHeight: window.innerHeight,
pjaxProgressBarTimer: null,
prevScrollValue: 0,
fontSizeLevel: 0,
isHasScrollProgressBar: KEEP.theme_config.style.scroll.progress_bar.enable === true,
isHasScrollPercent: KEEP.theme_config.style.scroll.percent.enable === true,
// Scroll Style Handle
styleHandleWhenScroll() {
const scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
const scrollHeight = document.body.scrollHeight || document.documentElement.scrollHeight;
const clientHeight = window.innerHeight || document.documentElement.clientHeight;
const percent = Math.round(scrollTop / (scrollHeight - clientHeight) * 100);
if (this.isHasScrollProgressBar) {
const ProgressPercent = (scrollTop / (scrollHeight - clientHeight) * 100).toFixed(3);
this.scrollProgressBar_dom.style.visibility = percent === 0 ? 'hidden' : 'visible';
this.scrollProgressBar_dom.style.width = `${ProgressPercent}%`;
}
if (this.isHasScrollPercent) {
const percent_dom = this.back2TopButton_dom.querySelector('.percent');
if (percent === 0 || percent === undefined) {
this.back2TopButton_dom.classList.remove('show');
} else {
this.back2TopButton_dom.classList.add('show');
percent_dom.innerHTML = percent.toFixed(0);
}
}
// hide header handle
if (scrollTop > this.prevScrollValue && scrollTop > this.innerHeight) {
this.pageTop_dom.classList.add('hide');
} else {
this.pageTop_dom.classList.remove('hide');
}
this.prevScrollValue = scrollTop;
},
// register window scroll event
registerWindowScroll() {
window.addEventListener('scroll', () => {
// style handle when scroll
if (this.isHasScrollPercent || this.isHasScrollProgressBar) {
this.styleHandleWhenScroll();
}
// TOC scroll handle
if (KEEP.theme_config.toc.enable && KEEP.utils.hasOwnProperty('findActiveIndexByTOC')) {
KEEP.utils.findActiveIndexByTOC();
}
// header shrink
KEEP.utils.headerShrink.headerShrink();
});
},
// toggle show tools list
toggleShowToolsList() {
document.querySelector('.tool-toggle-show').addEventListener('click', () => {
document.querySelector('.side-tools-list').classList.toggle('show');
});
},
// global font adjust
globalFontAdjust() {
const fontSize = document.defaultView.getComputedStyle(document.body).fontSize;
const fs = parseFloat(fontSize);
const initFontSize = () => {
const styleStatus = KEEP.getStyleStatus();
if (styleStatus) {
this.fontSizeLevel = styleStatus.fontSizeLevel;
setFontSize(this.fontSizeLevel);
}
}
const setFontSize = (fontSizeLevel) => {
this.html_root_dom.style.fontSize = `${fs * (1 + fontSizeLevel * 0.05)}px`;
KEEP.styleStatus.fontSizeLevel = fontSizeLevel;
KEEP.setStyleStatus();
}
initFontSize();
document.querySelector('.tool-font-adjust-plus').addEventListener('click', () => {
if (this.fontSizeLevel === 5) return;
this.fontSizeLevel++;
setFontSize(this.fontSizeLevel);
});
document.querySelector('.tool-font-adjust-minus').addEventListener('click', () => {
if (this.fontSizeLevel <= 0) return;
this.fontSizeLevel--;
setFontSize(this.fontSizeLevel);
});
},
// toggle content area width
contentAreaWidthAdjust() {
const toolExpandDom = document.querySelector('.tool-expand-width');
const headerContentDom = document.querySelector('.header-content');
const mainContentDom = document.querySelector('.main-content');
const iconDom = toolExpandDom.querySelector('i');
const defaultMaxWidth = KEEP.theme_config.style.content_max_width || '1000px';
const expandMaxWidth = '90%';
let headerMaxWidth = defaultMaxWidth;
let isExpand = false;
if (KEEP.theme_config.style.first_screen.enable === true && window.location.pathname === '/') {
headerMaxWidth = parseInt(defaultMaxWidth) * 1.2 + 'px';
}
const setPageWidth = (isExpand) => {
KEEP.styleStatus.isExpandPageWidth = isExpand;
KEEP.setStyleStatus();
if (isExpand) {
iconDom.classList.remove('fa-arrows-alt-h');
iconDom.classList.add('fa-compress-arrows-alt');
headerContentDom.style.maxWidth = expandMaxWidth;
mainContentDom.style.maxWidth = expandMaxWidth;
} else {
iconDom.classList.remove('fa-compress-arrows-alt');
iconDom.classList.add('fa-arrows-alt-h');
headerContentDom.style.maxWidth = headerMaxWidth;
mainContentDom.style.maxWidth = defaultMaxWidth;
}
}
const initPageWidth = () => {
const styleStatus = KEEP.getStyleStatus();
if (styleStatus) {
isExpand = styleStatus.isExpandPageWidth;
setPageWidth(isExpand);
}
}
initPageWidth();
toolExpandDom.addEventListener('click', () => {
isExpand = !isExpand;
setPageWidth(isExpand)
});
},
// go comment anchor
goComment() {
this.goComment_dom = document.querySelector('.go-comment');
if (this.goComment_dom) {
this.goComment_dom.addEventListener('click', () => {
document.querySelector('#comment-anchor').scrollIntoView();
});
}
},
// get dom element height
getElementHeight(selectors) {
const dom = document.querySelector(selectors);
return dom ? dom.getBoundingClientRect().height : 0;
},
// init first screen height
initFirstScreenHeight() {
this.firstScreen_dom && (this.firstScreen_dom.style.height = this.innerHeight + 'px');
},
// init page height handle
initPageHeightHandle() {
if (this.firstScreen_dom) return;
const temp_h1 = this.getElementHeight('.page-main-content-top');
const temp_h2 = this.getElementHeight('.page-main-content-middle');
const temp_h3 = this.getElementHeight('.page-main-content-bottom');
const allDomHeight = temp_h1 + temp_h2 + temp_h3;
const innerHeight = window.innerHeight;
const pb_dom = document.querySelector('.page-main-content-bottom');
if (allDomHeight < innerHeight) {
const marginTopValue = Math.floor(innerHeight - allDomHeight);
if (marginTopValue > 0) {
pb_dom.style.marginTop = `${marginTopValue - 2}px`;
}
}
},
// big image viewer
imageViewer() {
let isBigImage = false;
const showHandle = (maskDom, isShow) => {
document.body.style.overflow = isShow ? 'hidden' : 'auto';
if (isShow) {
maskDom.classList.add('active');
} else {
maskDom.classList.remove('active');
}
}
const imageViewerDom = document.querySelector('.image-viewer-container');
const targetImg = document.querySelector('.image-viewer-container img');
imageViewerDom && imageViewerDom.addEventListener('click', () => {
isBigImage = false;
showHandle(imageViewerDom, isBigImage);
});
const imgDoms = document.querySelectorAll('.markdown-body img');
if (imgDoms.length) {
imgDoms.forEach(img => {
img.addEventListener('click', () => {
isBigImage = true;
showHandle(imageViewerDom, isBigImage);
targetImg.setAttribute('src', img.getAttribute('src'));
});
});
} else {
this.pageContainer_dom.removeChild(imageViewerDom);
}
},
// set how long ago language
setHowLongAgoLanguage(p1, p2) {
return p2.replace(/%s/g, p1)
},
getHowLongAgo(timestamp) {
const l = KEEP.language_ago;
const __Y = Math.floor(timestamp / (60 * 60 * 24 * 30) / 12);
const __M = Math.floor(timestamp / (60 * 60 * 24 * 30));
const __W = Math.floor(timestamp / (60 * 60 * 24) / 7);
const __d = Math.floor(timestamp / (60 * 60 * 24));
const __h = Math.floor(timestamp / (60 * 60) % 24);
const __m = Math.floor(timestamp / 60 % 60);
const __s = Math.floor(timestamp % 60);
if (__Y > 0) {
return this.setHowLongAgoLanguage(__Y, l.year);
} else if (__M > 0) {
return this.setHowLongAgoLanguage(__M, l.month);
} else if (__W > 0) {
return this.setHowLongAgoLanguage(__W, l.week);
} else if (__d > 0) {
return this.setHowLongAgoLanguage(__d, l.day);
} else if (__h > 0) {
return this.setHowLongAgoLanguage(__h, l.hour);
} else if (__m > 0) {
return this.setHowLongAgoLanguage(__m, l.minute);
} else if (__s > 0) {
return this.setHowLongAgoLanguage(__s, l.second);
}
},
setHowLongAgoInHome() {
const post = document.querySelectorAll('.home-article-meta-info .home-article-date');
post && post.forEach(v => {
const nowDate = Date.now();
const postDate = new Date(v.dataset.date.split(' GMT')[0]).getTime();
v.innerHTML = this.getHowLongAgo(Math.floor((nowDate - postDate) / 1000));
});
},
// loading progress bar start
pjaxProgressBarStart() {
this.pjaxProgressBarTimer && clearInterval(this.pjaxProgressBarTimer);
if (this.isHasScrollProgressBar) {
this.scrollProgressBar_dom.classList.add('hide');
}
this.pjaxProgressBar_dom.style.width = '0';
this.pjaxProgressIcon_dom.classList.add('show');
let width = 1;
const maxWidth = 99;
this.pjaxProgressBar_dom.classList.add('show');
this.pjaxProgressBar_dom.style.width = width + '%';
this.pjaxProgressBarTimer = setInterval(() => {
width += 5;
if (width > maxWidth) width = maxWidth;
this.pjaxProgressBar_dom.style.width = width + '%';
}, 100);
},
// loading progress bar end
pjaxProgressBarEnd() {
this.pjaxProgressBarTimer && clearInterval(this.pjaxProgressBarTimer);
this.pjaxProgressBar_dom.style.width = '100%';
const temp_1 = setTimeout(() => {
this.pjaxProgressBar_dom.classList.remove('show');
this.pjaxProgressIcon_dom.classList.remove('show');
if (this.isHasScrollProgressBar) {
this.scrollProgressBar_dom.classList.remove('hide');
}
const temp_2 = setTimeout(() => {
this.pjaxProgressBar_dom.style.width = '0';
clearTimeout(temp_1), clearTimeout(temp_2);
}, 200);
}, 200);
},
// loading hitokoto
initHitokoto() {
if (KEEP.theme_config.style.first_screen.enable === true && KEEP.theme_config.style.first_screen.hitokoto && window.location.pathname === '/') {
fetch(KEEP.theme_config.style.first_screen.hitokoto)
.then((res) => {
return res.json();
})
.then((data) => {
this.firstScreen_dom.querySelector('.description').innerText = data.hitokoto;
})
.catch((err) => {
console.error(err);
})
}
}
}
// init scroll
KEEP.utils.registerWindowScroll();
// toggle show tools list
KEEP.utils.toggleShowToolsList();
// global font adjust
KEEP.utils.globalFontAdjust();
// adjust content area width
KEEP.utils.contentAreaWidthAdjust();
// go comment
KEEP.utils.goComment();
// init page height handle
KEEP.utils.initPageHeightHandle();
// init first screen height
KEEP.utils.initFirstScreenHeight();
// big image viewer handle
KEEP.utils.imageViewer();
// set how long age in home article block
KEEP.utils.setHowLongAgoInHome();
// loading hitokoto
KEEP.utils.initHitokoto();
}