diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..81467c5 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "useTabs": false, + "endOfLine": "auto", + "tabWidth": 2, + "printWidth": 100, + "singleQuote": true, + "trailingComma": "none", + "bracketSpacing": true, + "semi": false +} diff --git a/package.json b/package.json index a16d060..6fe16ad 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "description": "A simple and elegant theme for Hexo.", "scripts": { "npm:publish": "npm publish", - "lint:style": "stylelint --fix source/css/**/**/**/*.styl", + "format": "prettier --write ./source/js/*.js ./scripts", + "lint:style": "stylelint --fix ./source/css", "git:push": "git push --tag && git push -u origin dev", "git:add": "npm run lint:style && git add ." }, @@ -29,6 +30,7 @@ }, "homepage": "https://github.com/XPoet/hexo-theme-keep#readme", "devDependencies": { + "prettier": "^2.7.1", "stylelint": "^14.13.0", "stylelint-config-rational-order": "^0.1.2", "stylelint-stylus": "^0.17.0" diff --git a/scripts/filters/lazyload-handle.js b/scripts/filters/lazyload-handle.js index 2e6c9c1..2dd4af2 100644 --- a/scripts/filters/lazyload-handle.js +++ b/scripts/filters/lazyload-handle.js @@ -2,14 +2,14 @@ hexo.extend.filter.register( 'after_post_render', function (data) { - const theme = hexo.theme.config; - if (!theme.lazyload || !theme.lazyload.enable) return; + const theme = hexo.theme.config + if (!theme.lazyload || !theme.lazyload.enable) return data.content = data.content.replace( // Match 'img' tags width the src attribute. /]*)src="([^"]*)"([^>\/]*)\/?\s*>/gim, function (match, attrBegin, src, attrEnd) { // Exit if the src doesn't exists. - if (!src) return match; + if (!src) return match return `]*)href="([^"]*)"([^>]*)>([^<]*)<\/a>/gim - data.content = data.content.replace(regPureATag, function ( - match, - attrBegin, - href, - attrEnd, - html - ) { - // Exit if the href attribute doesn't exists. - if (!href) return match; + data.content = data.content.replace( + regPureATag, + function (match, attrBegin, href, attrEnd, html) { + // Exit if the href attribute doesn't exists. + if (!href) return match - let link = ''; - try { - link = new URL(href); - } catch (e) { - // Invalid url, e.g. Anchor link. - return match; + let link = '' + try { + link = new URL(href) + } catch (e) { + // Invalid url, e.g. Anchor link. + return match + } + + // Exit if the url has same host with `config.url`, which means isn't an external link. + if (!link.protocol || link.hostname === siteHost) return match + + return `${html}` } - - // Exit if the url has same host with `config.url`, which means isn't an external link. - if (!link.protocol || link.hostname === siteHost) return match; - - return ( - `${html}` - ) - }) + ) }, 0 ) diff --git a/scripts/helpers/export-config.js b/scripts/helpers/export-config.js index 7ad4aad..eb1e47b 100644 --- a/scripts/helpers/export-config.js +++ b/scripts/helpers/export-config.js @@ -1,40 +1,38 @@ /* global hexo */ -'use strict'; +'use strict' -const url = require('url'); -const fs = require('fs'); -const path = require('path'); -const yaml = require('js-yaml'); +const url = require('url') +const fs = require('fs') +const path = require('path') +const yaml = require('js-yaml') /** * Export theme config to js */ hexo.extend.helper.register('export_config', function () { - - const { config, theme } = this; + const { config, theme } = this // ------------------------ export language to js ------------------------ - const languageDir = path.join(__dirname, '../../languages'); - let file = fs.readdirSync(languageDir).find(v => v === `${config.language}.yml`); - file = languageDir + '/' + (file ? file : 'en.yml'); - let languageContent = fs.readFileSync(file, 'utf8'); + const languageDir = path.join(__dirname, '../../languages') + let file = fs.readdirSync(languageDir).find((v) => v === `${config.language}.yml`) + file = languageDir + '/' + (file ? file : 'en.yml') + let languageContent = fs.readFileSync(file, 'utf8') try { - languageContent = yaml.load(languageContent); + languageContent = yaml.load(languageContent) } catch (err) { - console.log(err); + console.log(err) } // ----------------------------------------------------------------------- - let hexo_config = { hostname: url.parse(config.url).hostname || config.url, root: config.root, language: config.language - }; + } if (config.search) { - hexo_config.path = config.search.path; + hexo_config.path = config.search.path } let theme_config = { @@ -55,5 +53,5 @@ hexo.extend.helper.register('export_config', function () { KEEP.theme_config = ${JSON.stringify(theme_config)}; KEEP.language_ago = ${JSON.stringify(languageContent['ago'])}; KEEP.language_code_block = ${JSON.stringify(languageContent['code_block'])}; - `; -}); + ` +}) diff --git a/scripts/helpers/helper.js b/scripts/helpers/helper.js index 3f91650..8c26c39 100644 --- a/scripts/helpers/helper.js +++ b/scripts/helpers/helper.js @@ -2,103 +2,102 @@ 'use strict' -const url = require('url'); +const url = require('url') hexo.extend.helper.register('isInHomePaging', function (pagePath, route) { if (pagePath.length > 5 && route === '/') { - return pagePath.slice(0, 5) === 'page/'; + return pagePath.slice(0, 5) === 'page/' } else { - return false; + return false } -}); +}) hexo.extend.helper.register('createNewArchivePosts', function (posts) { - const postList = [], postYearList = []; - posts.forEach(post => postYearList.push(post.date.year())); - Array.from(new Set(postYearList)).forEach(year => { + const postList = [], + postYearList = [] + posts.forEach((post) => postYearList.push(post.date.year())) + Array.from(new Set(postYearList)).forEach((year) => { postList.push({ year: year, postList: [] }) - }); + }) postList.sort((a, b) => b.year - a.year) - postList.forEach(item => { - posts.forEach(post => item.year === post.date.year() && item.postList.push(post)) - }); - postList.forEach(item => item.postList.sort((a, b) => b.date.unix() - a.date.unix())); - return postList; -}); + postList.forEach((item) => { + posts.forEach((post) => item.year === post.date.year() && item.postList.push(post)) + }) + postList.forEach((item) => item.postList.sort((a, b) => b.date.unix() - a.date.unix())) + return postList +}) hexo.extend.helper.register('getAuthorLabel', function (postCount, isAuto, labelList) { - - let level = Math.floor(Math.log2(postCount)); - level = level < 2 ? 1 : level - 1; + let level = Math.floor(Math.log2(postCount)) + level = level < 2 ? 1 : level - 1 if (isAuto === false && Array.isArray(labelList) && labelList.length > 0) { - return level > labelList.length ? labelList[labelList.length - 1] : labelList[level - 1]; + return level > labelList.length ? labelList[labelList.length - 1] : labelList[level - 1] } else { - return `Lv${level}`; + return `Lv${level}` } - -}); +}) hexo.extend.helper.register('getPostUrl', function (rootUrl, path) { if (rootUrl) { - let { href } = url.parse(rootUrl); + let { href } = url.parse(rootUrl) if (href.substr(href.length - 1, 1) !== '/') { - href = href + '/'; + href = href + '/' } - return href + path; + return href + path } else { - return path; + return path } -}); +}) const getSourceCdnUrl = (tyle, themeConfig, path) => { - const version = require('../../package.json').version; - const { provider = 'jsdelivr' } = themeConfig?.cdn; + const version = require('../../package.json').version + const { provider = 'jsdelivr' } = themeConfig?.cdn - let urlPrefix = ''; + let urlPrefix = '' switch (provider.toLocaleLowerCase()) { case 'jsdelivr': urlPrefix = '//cdn.jsdelivr.net/npm/hexo-theme-keep' if (tyle === 'js') { - return ``; + return `` } else { - return ``; + return `` } case 'unpkg': urlPrefix = '//unpkg.com/hexo-theme-keep' if (tyle === 'js') { - return ``; + return `` } else { - return ``; + return `` } } } hexo.extend.helper.register('__js', function (path) { const { enable } = this.theme.cdn - const _js = hexo.extend.helper.get('js').bind(hexo); + const _js = hexo.extend.helper.get('js').bind(hexo) const cdnPathHandle = (pa) => { - return enable ? getSourceCdnUrl('js', this.theme, pa) : _js(pa); + return enable ? getSourceCdnUrl('js', this.theme, pa) : _js(pa) } - let t = ``; + let t = `` if (Array.isArray(path)) { for (const p of path) { - t += cdnPathHandle(p); + t += cdnPathHandle(p) } } else { - t = cdnPathHandle(path); + t = cdnPathHandle(path) } - return t; -}); + return t +}) hexo.extend.helper.register('__css', function (path) { const { enable } = this.theme.cdn - const _css = hexo.extend.helper.get('css').bind(hexo); - return enable ? getSourceCdnUrl('css', this.theme, path) : _css(path); -}); + const _css = hexo.extend.helper.get('css').bind(hexo) + return enable ? getSourceCdnUrl('css', this.theme, path) : _css(path) +}) diff --git a/scripts/use-source-data.js b/scripts/use-source-data.js index d617596..9e95b58 100644 --- a/scripts/use-source-data.js +++ b/scripts/use-source-data.js @@ -1,26 +1,21 @@ hexo.on('generateBefore', function () { - if (hexo.locals.get) { - const data = hexo.locals.get('data'); + const data = hexo.locals.get('data') if (data) { - // theme config file handle if (data._config) { - hexo.theme.config = data._config; - + hexo.theme.config = data._config } else if (data.keep) { - hexo.theme.config = data.keep; - + hexo.theme.config = data.keep } else if (data._keep) { - hexo.theme.config = data._keep; + hexo.theme.config = data._keep } // friends link file handle if (data.links || data.link) { - hexo.theme.config.links = (data.links || data.link); + hexo.theme.config.links = data.links || data.link } - } } -}); +}) diff --git a/source/js/back2top.js b/source/js/back2top.js index 0a71a6f..0a55150 100644 --- a/source/js/back2top.js +++ b/source/js/back2top.js @@ -1,55 +1,52 @@ /* global KEEP */ KEEP.initBack2Top = () => { - KEEP.utils = { - ...KEEP.utils, back2BottomButton_dom: document.querySelector('.tool-scroll-to-bottom'), back2top() { const scrollTopTimer = setInterval(function () { - let top = document.body.scrollTop || document.documentElement.scrollTop; - let speed = top / 2; + let top = document.body.scrollTop || document.documentElement.scrollTop + let speed = top / 2 if (document.body.scrollTop !== 0) { - document.body.scrollTop -= speed; + document.body.scrollTop -= speed } else { - document.documentElement.scrollTop -= speed; + document.documentElement.scrollTop -= speed } if (top === 0) { - clearInterval(scrollTopTimer); + clearInterval(scrollTopTimer) } - }, 50); + }, 50) }, back2Bottom() { - let scrollHeight = document.body.scrollHeight || document.documentElement.scrollHeight; - let scrollTop = document.body.scrollTop || document.documentElement.scrollTop; + let scrollHeight = document.body.scrollHeight || document.documentElement.scrollHeight + let scrollTop = document.body.scrollTop || document.documentElement.scrollTop const scrollBottomTimer = setInterval(function () { - if (!scrollTop) scrollTop = 10; - scrollTop = Math.floor(scrollTop + scrollTop / 2); - window.scrollTo(0, scrollTop); + if (!scrollTop) scrollTop = 10 + scrollTop = Math.floor(scrollTop + scrollTop / 2) + window.scrollTo(0, scrollTop) if (scrollTop >= scrollHeight) { - clearInterval(scrollBottomTimer); + clearInterval(scrollBottomTimer) } - }, 50); + }, 50) }, initBack2Top() { this.back2TopButton_dom.addEventListener('click', () => { - this.back2top(); - }); + this.back2top() + }) }, initBack2Bottom() { this.back2BottomButton_dom.addEventListener('click', () => { - this.back2Bottom(); - }); - }, + this.back2Bottom() + }) + } } - KEEP.utils.initBack2Top(); - KEEP.utils.initBack2Bottom(); - + KEEP.utils.initBack2Top() + KEEP.utils.initBack2Bottom() } diff --git a/source/js/code-block-tools.js b/source/js/code-block-tools.js index e397066..6199979 100644 --- a/source/js/code-block-tools.js +++ b/source/js/code-block-tools.js @@ -2,25 +2,31 @@ KEEP.initCodeBlockTools = () => { HTMLElement.prototype.wrap = function (wrapper) { - this.parentNode.insertBefore(wrapper, this); - this.parentNode.removeChild(this); - wrapper.appendChild(this); - }; + this.parentNode.insertBefore(wrapper, this) + this.parentNode.removeChild(this) + wrapper.appendChild(this) + } - const { style: codeCopyStyle } = KEEP.theme_config?.code_copy; - const { style: codeBlockStyle } = KEEP.theme_config?.code_block_tools; - const isMac = (codeBlockStyle || codeCopyStyle || 'default') === 'mac'; - const foldedIconClassName = isMac ? 'fas fa-chevron-left' : 'fas fa-chevron-right'; - const { copy: copyLang, copied: copiedLang, fold: foldLang, folded: foldedLang } = KEEP.language_code_block; + const { style: codeCopyStyle } = KEEP.theme_config?.code_copy + const { style: codeBlockStyle } = KEEP.theme_config?.code_block_tools + const isMac = (codeBlockStyle || codeCopyStyle || 'default') === 'mac' + const foldedIconClassName = isMac ? 'fas fa-chevron-left' : 'fas fa-chevron-right' + const { + copy: copyLang, + copied: copiedLang, + fold: foldLang, + folded: foldedLang + } = KEEP.language_code_block const foldDom = `` - document.querySelectorAll('figure.highlight').forEach(element => { - let codeLang = element.classList.length ? element.classList[1].toUpperCase() : ''; - if (codeLang === 'PLAINTEXT') { codeLang = '' } - const highlightContainer = document.createElement('div'); - highlightContainer.classList.add('highlight-container'); - element.wrap(highlightContainer); - + document.querySelectorAll('figure.highlight').forEach((element) => { + let codeLang = element.classList.length ? element.classList[1].toUpperCase() : '' + if (codeLang === 'PLAINTEXT') { + codeLang = '' + } + const highlightContainer = document.createElement('div') + highlightContainer.classList.add('highlight-container') + element.wrap(highlightContainer) const codeLangDom = `${codeLang ? '' + codeLang + '' : ''}` @@ -30,72 +36,74 @@ KEEP.initCodeBlockTools = () => { ${isMac ? foldDom + codeLangDom : '' + foldDom + codeLangDom + ''} ` - ); - const codeToolsBox = element.parentNode.querySelector('.code-tools-box'); - const copyDom = codeToolsBox.querySelector('.copy'); - const targetFoldDom = codeToolsBox.querySelector('.fold'); + ) + const codeToolsBox = element.parentNode.querySelector('.code-tools-box') + const copyDom = codeToolsBox.querySelector('.copy') + const targetFoldDom = codeToolsBox.querySelector('.fold') - copyDom.addEventListener('click', event => { - const target = event.currentTarget; - const code = [...element.querySelectorAll('.code .line')].map(line => line.innerText).join('\n'); - const tta = document.createElement('textarea'); - tta.style.top = window.scrollY + 'px'; - tta.style.position = 'absolute'; - tta.style.opacity = '0'; - tta.readOnly = true; - tta.value = code; - document.body.append(tta); - const selection = document.getSelection(); - const selected = selection.rangeCount > 0 ? selection.getRangeAt(0) : false; - tta.select(); - tta.setSelectionRange(0, code.length); - tta.readOnly = false; - const result = document.execCommand('copy'); + copyDom.addEventListener('click', (event) => { + const target = event.currentTarget + const code = [...element.querySelectorAll('.code .line')] + .map((line) => line.innerText) + .join('\n') + const tta = document.createElement('textarea') + tta.style.top = window.scrollY + 'px' + tta.style.position = 'absolute' + tta.style.opacity = '0' + tta.readOnly = true + tta.value = code + document.body.append(tta) + const selection = document.getSelection() + const selected = selection.rangeCount > 0 ? selection.getRangeAt(0) : false + tta.select() + tta.setSelectionRange(0, code.length) + tta.readOnly = false + const result = document.execCommand('copy') - const copyIconDom = target.querySelector('i'); - const copyTooltipDom = codeToolsBox.querySelector('.copy .tooltip-content'); + const copyIconDom = target.querySelector('i') + const copyTooltipDom = codeToolsBox.querySelector('.copy .tooltip-content') if (result) { - copyIconDom.className = 'fas fa-check'; - copyTooltipDom && (copyTooltipDom.innerHTML = copiedLang); + copyIconDom.className = 'fas fa-check' + copyTooltipDom && (copyTooltipDom.innerHTML = copiedLang) } else { - copyIconDom.className = 'fas fa-times'; + copyIconDom.className = 'fas fa-times' } - tta.blur(); - target.blur(); + tta.blur() + target.blur() if (selected) { - selection.removeAllRanges(); - selection.addRange(selected); + selection.removeAllRanges() + selection.addRange(selected) } - document.body.removeChild(tta); - }); + document.body.removeChild(tta) + }) - copyDom.addEventListener('mouseleave', event => { + copyDom.addEventListener('mouseleave', (event) => { setTimeout(() => { - event.target.querySelector('i').className = 'fas fa-copy'; - const copyTooltipDom = codeToolsBox.querySelector('.copy .tooltip-content'); - copyTooltipDom && (copyTooltipDom.innerHTML = copyLang); - }, 500); - }); + event.target.querySelector('i').className = 'fas fa-copy' + const copyTooltipDom = codeToolsBox.querySelector('.copy .tooltip-content') + copyTooltipDom && (copyTooltipDom.innerHTML = copyLang) + }, 500) + }) let isFold = false - targetFoldDom.addEventListener('click', event => { - const target = event.currentTarget; - const icon = target.querySelector('i'); - const foldTooltipDom = codeToolsBox.querySelector('.fold .tooltip-content'); - isFold = !isFold; + targetFoldDom.addEventListener('click', (event) => { + const target = event.currentTarget + const icon = target.querySelector('i') + const foldTooltipDom = codeToolsBox.querySelector('.fold .tooltip-content') + isFold = !isFold if (isFold) { - icon.className = foldedIconClassName; - element.classList.add('folded'); - codeToolsBox.classList.add('folded'); + icon.className = foldedIconClassName + element.classList.add('folded') + codeToolsBox.classList.add('folded') foldTooltipDom && (foldTooltipDom.innerHTML = foldedLang) } else { - icon.className = 'fas fa-chevron-down'; - element.classList.remove('folded'); - codeToolsBox.classList.remove('folded'); + icon.className = 'fas fa-chevron-down' + element.classList.remove('folded') + codeToolsBox.classList.remove('folded') foldTooltipDom && (foldTooltipDom.innerHTML = foldLang) } - }); - }); + }) + }) } diff --git a/source/js/dark-light-toggle.js b/source/js/dark-light-toggle.js index 0cb5f5b..694113d 100644 --- a/source/js/dark-light-toggle.js +++ b/source/js/dark-light-toggle.js @@ -1,58 +1,56 @@ /* global KEEP */ KEEP.initModeToggle = () => { - KEEP.utils.modeToggle = { - modeToggleButton_dom: document.querySelector('.tool-dark-light-toggle'), iconDom: document.querySelector('.tool-dark-light-toggle i'), enableLightMode() { - document.body.classList.remove('dark-mode'); - document.body.classList.add('light-mode'); - this.iconDom.className = 'fas fa-moon'; - KEEP.styleStatus.isDark = false; - KEEP.setStyleStatus(); + document.body.classList.remove('dark-mode') + document.body.classList.add('light-mode') + this.iconDom.className = 'fas fa-moon' + KEEP.styleStatus.isDark = false + KEEP.setStyleStatus() }, enableDarkMode() { - document.body.classList.add('dark-mode'); - document.body.classList.remove('light-mode'); - this.iconDom.className = 'fas fa-sun'; - KEEP.styleStatus.isDark = true; - KEEP.setStyleStatus(); + document.body.classList.add('dark-mode') + document.body.classList.remove('light-mode') + this.iconDom.className = 'fas fa-sun' + KEEP.styleStatus.isDark = true + KEEP.setStyleStatus() }, isDarkPrefersColorScheme() { - return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)'); + return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)') }, initModeStatus() { - const styleStatus = KEEP.getStyleStatus(); + const styleStatus = KEEP.getStyleStatus() if (styleStatus) { - styleStatus.isDark ? this.enableDarkMode() : this.enableLightMode(); + styleStatus.isDark ? this.enableDarkMode() : this.enableLightMode() } else { - this.isDarkPrefersColorScheme().matches ? this.enableDarkMode() : this.enableLightMode(); + this.isDarkPrefersColorScheme().matches ? this.enableDarkMode() : this.enableLightMode() } }, initModeToggleButton() { this.modeToggleButton_dom.addEventListener('click', () => { - const isDark = document.body.classList.contains('dark-mode'); - isDark ? this.enableLightMode() : this.enableDarkMode(); - }); + const isDark = document.body.classList.contains('dark-mode') + isDark ? this.enableLightMode() : this.enableDarkMode() + }) }, initModeAutoTrigger() { - const isDarkMode = this.isDarkPrefersColorScheme(); - isDarkMode.addEventListener('change', e => { - e.matches ? this.enableDarkMode() : this.enableLightMode(); - }); + const isDarkMode = this.isDarkPrefersColorScheme() + isDarkMode.addEventListener('change', (e) => { + e.matches ? this.enableDarkMode() : this.enableLightMode() + }) } } - KEEP.utils.modeToggle.initModeStatus(); - KEEP.utils.modeToggle.initModeToggleButton(); - KEEP.utils.modeToggle.initModeAutoTrigger(); -}; + KEEP.utils.modeToggle.initModeStatus() + KEEP.utils.modeToggle.initModeToggleButton() + KEEP.utils.modeToggle.initModeAutoTrigger() +} diff --git a/source/js/header-shrink.js b/source/js/header-shrink.js index a4c9c45..ae2938d 100644 --- a/source/js/header-shrink.js +++ b/source/js/header-shrink.js @@ -6,43 +6,45 @@ KEEP.initHeaderShrink = () => { isHeaderShrink: false, init() { - this.headerHeight = this.headerDom.getBoundingClientRect().height; + this.headerHeight = this.headerDom.getBoundingClientRect().height }, headerShrink() { - const scrollTop = document.body.scrollTop || document.documentElement.scrollTop; - const headerWrapperDom = document.querySelector('.header-wrapper'); - const { enable, header_transparent } = KEEP.theme_config.style.first_screen; + const scrollTop = document.body.scrollTop || document.documentElement.scrollTop + const headerWrapperDom = document.querySelector('.header-wrapper') + const { enable, header_transparent } = KEEP.theme_config.style.first_screen if (!this.isHeaderShrink && scrollTop > this.headerHeight) { - this.isHeaderShrink = true; - document.body.classList.add('header-shrink'); + this.isHeaderShrink = true + document.body.classList.add('header-shrink') if (enable === true && header_transparent === true) { - headerWrapperDom.classList.add('transparent-2'); + headerWrapperDom.classList.add('transparent-2') } } else if (this.isHeaderShrink && scrollTop <= this.headerHeight) { - this.isHeaderShrink = false; - document.body.classList.remove('header-shrink'); + this.isHeaderShrink = false + document.body.classList.remove('header-shrink') if (enable === true && header_transparent === true) { - headerWrapperDom.classList.remove('transparent-2'); + headerWrapperDom.classList.remove('transparent-2') } } }, toggleHeaderDrawerShow() { - const domList = [document.querySelector('.window-mask'), document.querySelector('.menu-bar')]; + const domList = [document.querySelector('.window-mask'), document.querySelector('.menu-bar')] if (KEEP.theme_config.pjax.enable === true) { - domList.push(...document.querySelectorAll('.header-drawer .drawer-menu-list .drawer-menu-item')); + domList.push( + ...document.querySelectorAll('.header-drawer .drawer-menu-list .drawer-menu-item') + ) } - domList.forEach(v => { + domList.forEach((v) => { v.addEventListener('click', () => { - document.body.classList.toggle('header-drawer-show'); - }); - }); + document.body.classList.toggle('header-drawer-show') + }) + }) } } - KEEP.utils.headerShrink.init(); - KEEP.utils.headerShrink.headerShrink(); - KEEP.utils.headerShrink.toggleHeaderDrawerShow(); + KEEP.utils.headerShrink.init() + KEEP.utils.headerShrink.headerShrink() + KEEP.utils.headerShrink.toggleHeaderDrawerShow() } diff --git a/source/js/lazyload.js b/source/js/lazyload.js index e75b95b..8b7cddf 100644 --- a/source/js/lazyload.js +++ b/source/js/lazyload.js @@ -1,43 +1,42 @@ /* global KEEP */ KEEP.initLazyLoad = () => { - const imgs = document.querySelectorAll('img'); - let now = Date.now(); - let needLoad = true; + const imgs = document.querySelectorAll('img') + let now = Date.now() + let needLoad = true function lazyload(imgs) { - now = Date.now(); - needLoad = Array.from(imgs).some(i => i.hasAttribute('lazyload')); + now = Date.now() + needLoad = Array.from(imgs).some((i) => i.hasAttribute('lazyload')) - const h = window.innerHeight; - const s = document.documentElement.scrollTop || document.body.scrollTop; + const h = window.innerHeight + const s = document.documentElement.scrollTop || document.body.scrollTop - imgs.forEach(img => { + imgs.forEach((img) => { if (img.hasAttribute('lazyload') && !img.hasAttribute('loading')) { - - if ((h + s) > img.offsetTop) { - img.setAttribute('loading', true); + if (h + s > img.offsetTop) { + img.setAttribute('loading', true) const loadImageTimeout = setTimeout(() => { - const temp = new Image(); - const src = img.getAttribute('data-src'); - temp.src = src; + const temp = new Image() + const src = img.getAttribute('data-src') + temp.src = src temp.onload = () => { - img.src = src; - img.removeAttribute('lazyload'); - img.removeAttribute('loading'); - clearTimeout(loadImageTimeout); + img.src = src + img.removeAttribute('lazyload') + img.removeAttribute('loading') + clearTimeout(loadImageTimeout) } - }, 500); + }, 500) } } - }); + }) } - lazyload(imgs); + lazyload(imgs) window.onscroll = () => { if (Date.now() - now > 50 && needLoad) { - lazyload(imgs); + lazyload(imgs) } } } diff --git a/source/js/left-side-toggle.js b/source/js/left-side-toggle.js index e6c34e5..d83e217 100644 --- a/source/js/left-side-toggle.js +++ b/source/js/left-side-toggle.js @@ -2,7 +2,6 @@ function initLeftSideToggle() { KEEP.utils.leftSideToggle = { - toggleBar: document.querySelector('.page-aside-toggle'), pageTopDom: document.querySelector('.page-main-content-top'), containerDom: document.querySelector('.page-container'), @@ -12,33 +11,35 @@ function initLeftSideToggle() { isOpenPageAside: false, initToggleBarButton() { - this.toggleBar && this.toggleBar.addEventListener('click', () => { - this.isOpenPageAside = !this.isOpenPageAside; - KEEP.styleStatus.isOpenPageAside = this.isOpenPageAside; - KEEP.setStyleStatus(); - this.changePageLayoutWhenOpenToggle(this.isOpenPageAside); - }); + this.toggleBar && + this.toggleBar.addEventListener('click', () => { + this.isOpenPageAside = !this.isOpenPageAside + KEEP.styleStatus.isOpenPageAside = this.isOpenPageAside + KEEP.setStyleStatus() + this.changePageLayoutWhenOpenToggle(this.isOpenPageAside) + }) }, changePageLayoutWhenOpenToggle(isOpen) { - this.toggleBarIcon && (this.toggleBarIcon.className = isOpen ? 'fas fa-outdent' : 'fas fa-indent'); - const pageAsideWidth = KEEP.theme_config.style.left_side_width || '260px'; - this.containerDom.style.paddingLeft = isOpen ? pageAsideWidth : '0'; - this.pageTopDom.style.paddingLeft = isOpen ? pageAsideWidth : '0'; - this.leftAsideDom.style.left = isOpen ? '0' : `-${pageAsideWidth}`; + this.toggleBarIcon && + (this.toggleBarIcon.className = isOpen ? 'fas fa-outdent' : 'fas fa-indent') + const pageAsideWidth = KEEP.theme_config.style.left_side_width || '260px' + this.containerDom.style.paddingLeft = isOpen ? pageAsideWidth : '0' + this.pageTopDom.style.paddingLeft = isOpen ? pageAsideWidth : '0' + this.leftAsideDom.style.left = isOpen ? '0' : `-${pageAsideWidth}` }, pageAsideHandleOfTOC(isOpen) { - this.toggleBar.style.display = 'flex'; - this.isOpenPageAside = isOpen; - this.changePageLayoutWhenOpenToggle(isOpen); + this.toggleBar.style.display = 'flex' + this.isOpenPageAside = isOpen + this.changePageLayoutWhenOpenToggle(isOpen) } } - KEEP.utils.leftSideToggle.initToggleBarButton(); + KEEP.utils.leftSideToggle.initToggleBarButton() } if (KEEP.theme_config.pjax.enable === true && KEEP.utils) { - initLeftSideToggle(); + initLeftSideToggle() } else { - window.addEventListener('DOMContentLoaded', initLeftSideToggle); + window.addEventListener('DOMContentLoaded', initLeftSideToggle) } diff --git a/source/js/local-search.js b/source/js/local-search.js index 620174e..f7e43e5 100644 --- a/source/js/local-search.js +++ b/source/js/local-search.js @@ -1,68 +1,69 @@ -KEEP.initLocalSearch = () => { +/* global KEEP */ +KEEP.initLocalSearch = () => { // Search DB path - let searchPath = KEEP.hexo_config.path; + let searchPath = KEEP.hexo_config.path if (!searchPath) { // Search DB path - console.warn('`hexo-generator-searchdb` plugin is not installed!'); - return; + console.warn('`hexo-generator-searchdb` plugin is not installed!') + return } // Popup Window - let isfetched = false; - let datas; - let isXml = true; + let isfetched = false + let datas + let isXml = true if (searchPath.length === 0) { - searchPath = 'search.xml'; + searchPath = 'search.xml' } else if (searchPath.endsWith('json')) { - isXml = false; + isXml = false } - const searchInputDom = document.querySelector('.search-input'); - const resultContent = document.getElementById('search-result'); + const searchInputDom = document.querySelector('.search-input') + const resultContent = document.getElementById('search-result') const getIndexByWord = (word, text, caseSensitive) => { - let wordLen = word.length; - if (wordLen === 0) return []; - let startPosition = 0; - let position = []; - let index = []; + let wordLen = word.length + if (wordLen === 0) return [] + let startPosition = 0 + let position = [] + let index = [] if (!caseSensitive) { - text = text.toLowerCase(); - word = word.toLowerCase(); + text = text.toLowerCase() + word = word.toLowerCase() } while ((position = text.indexOf(word, startPosition)) > -1) { - index.push({position, word}); - startPosition = position + wordLen; + index.push({ position, word }) + startPosition = position + wordLen } - return index; - }; + return index + } // Merge hits into slices const mergeIntoSlice = (start, end, index, searchText) => { - let item = index[index.length - 1]; - let {position, word} = item; - let hits = []; - let searchTextCountInSlice = 0; + let item = index[index.length - 1] + let { position, word } = item + let hits = [] + let searchTextCountInSlice = 0 while (position + word.length <= end && index.length !== 0) { if (word === searchText) { - searchTextCountInSlice++; + searchTextCountInSlice++ } hits.push({ position, length: word.length - }); - let wordEnd = position + word.length; + }) + let wordEnd = position + word.length // Move to next position of hit - index.pop(); + index.pop() while (index.length !== 0) { - item = index[index.length - 1]; - position = item.position; - word = item.word; + item = index[index.length - 1] + position = item.position + word = item.word if (wordEnd > position) { - index.pop(); + index.pop() } else { - break; + break } } } @@ -71,212 +72,228 @@ KEEP.initLocalSearch = () => { start, end, searchTextCount: searchTextCountInSlice - }; - }; + } + } // Highlight title and content const highlightKeyword = (text, slice) => { - let result = ''; - let prevEnd = slice.start; - slice.hits.forEach(hit => { - result += text.substring(prevEnd, hit.position); - let end = hit.position + hit.length; - result += `${text.substring(hit.position, end)}`; - prevEnd = end; - }); - result += text.substring(prevEnd, slice.end); - return result; - }; + let result = '' + let prevEnd = slice.start + slice.hits.forEach((hit) => { + result += text.substring(prevEnd, hit.position) + let end = hit.position + hit.length + result += `${text.substring(hit.position, end)}` + prevEnd = end + }) + result += text.substring(prevEnd, slice.end) + return result + } const inputEventFunction = () => { - if (!isfetched) return; - let searchText = searchInputDom.value.trim().toLowerCase(); - let keywords = searchText.split(/[-\s]+/); + if (!isfetched) return + let searchText = searchInputDom.value.trim().toLowerCase() + let keywords = searchText.split(/[-\s]+/) if (keywords.length > 1) { - keywords.push(searchText); + keywords.push(searchText) } - let resultItems = []; + let resultItems = [] if (searchText.length > 0) { // Perform local searching - datas.forEach(({title, content, url}) => { - let titleInLowerCase = title.toLowerCase(); - let contentInLowerCase = content.toLowerCase(); - let indexOfTitle = []; - let indexOfContent = []; - let searchTextCount = 0; - keywords.forEach(keyword => { - indexOfTitle = indexOfTitle.concat(getIndexByWord(keyword, titleInLowerCase, false)); - indexOfContent = indexOfContent.concat(getIndexByWord(keyword, contentInLowerCase, false)); - }); + datas.forEach(({ title, content, url }) => { + let titleInLowerCase = title.toLowerCase() + let contentInLowerCase = content.toLowerCase() + let indexOfTitle = [] + let indexOfContent = [] + let searchTextCount = 0 + keywords.forEach((keyword) => { + indexOfTitle = indexOfTitle.concat(getIndexByWord(keyword, titleInLowerCase, false)) + indexOfContent = indexOfContent.concat(getIndexByWord(keyword, contentInLowerCase, false)) + }) // Show search results if (indexOfTitle.length > 0 || indexOfContent.length > 0) { - let hitCount = indexOfTitle.length + indexOfContent.length; + let hitCount = indexOfTitle.length + indexOfContent.length // Sort index by position of keyword - [indexOfTitle, indexOfContent].forEach(index => { + ;[indexOfTitle, indexOfContent].forEach((index) => { index.sort((itemLeft, itemRight) => { if (itemRight.position !== itemLeft.position) { - return itemRight.position - itemLeft.position; + return itemRight.position - itemLeft.position } - return itemLeft.word.length - itemRight.word.length; - }); - }); + return itemLeft.word.length - itemRight.word.length + }) + }) - let slicesOfTitle = []; + let slicesOfTitle = [] if (indexOfTitle.length !== 0) { - let tmp = mergeIntoSlice(0, title.length, indexOfTitle, searchText); - searchTextCount += tmp.searchTextCountInSlice; - slicesOfTitle.push(tmp); + let tmp = mergeIntoSlice(0, title.length, indexOfTitle, searchText) + searchTextCount += tmp.searchTextCountInSlice + slicesOfTitle.push(tmp) } - let slicesOfContent = []; + let slicesOfContent = [] while (indexOfContent.length !== 0) { - let item = indexOfContent[indexOfContent.length - 1]; - let {position, word} = item; + let item = indexOfContent[indexOfContent.length - 1] + let { position, word } = item // Cut out 100 characters - let start = position - 20; - let end = position + 80; + let start = position - 20 + let end = position + 80 if (start < 0) { - start = 0; + start = 0 } if (end < position + word.length) { - end = position + word.length; + end = position + word.length } if (end > content.length) { - end = content.length; + end = content.length } - let tmp = mergeIntoSlice(start, end, indexOfContent, searchText); - searchTextCount += tmp.searchTextCountInSlice; - slicesOfContent.push(tmp); + let tmp = mergeIntoSlice(start, end, indexOfContent, searchText) + searchTextCount += tmp.searchTextCountInSlice + slicesOfContent.push(tmp) } // Sort slices in content by search text's count and hits' count slicesOfContent.sort((sliceLeft, sliceRight) => { if (sliceLeft.searchTextCount !== sliceRight.searchTextCount) { - return sliceRight.searchTextCount - sliceLeft.searchTextCount; + return sliceRight.searchTextCount - sliceLeft.searchTextCount } else if (sliceLeft.hits.length !== sliceRight.hits.length) { - return sliceRight.hits.length - sliceLeft.hits.length; + return sliceRight.hits.length - sliceLeft.hits.length } - return sliceLeft.start - sliceRight.start; - }); + return sliceLeft.start - sliceRight.start + }) // Select top N slices in content - let upperBound = parseInt(KEEP.theme_config.local_search.top_n_per_article ? KEEP.theme_config.local_search.top_n_per_article : 1, 10); + let upperBound = parseInt( + KEEP.theme_config.local_search.top_n_per_article + ? KEEP.theme_config.local_search.top_n_per_article + : 1, + 10 + ) if (upperBound >= 0) { - slicesOfContent = slicesOfContent.slice(0, upperBound); + slicesOfContent = slicesOfContent.slice(0, upperBound) } - let resultItem = ''; + let resultItem = '' if (slicesOfTitle.length !== 0) { - resultItem += `
  • ${highlightKeyword(title, slicesOfTitle[0])}`; + resultItem += `
  • ${highlightKeyword( + title, + slicesOfTitle[0] + )}` } else { - resultItem += `
  • ${title}`; + resultItem += `
  • ${title}` } - slicesOfContent.forEach(slice => { - resultItem += `

    ${highlightKeyword(content, slice)}...

    `; - }); + slicesOfContent.forEach((slice) => { + resultItem += `

    ${highlightKeyword( + content, + slice + )}...

    ` + }) - resultItem += '
  • '; + resultItem += '' resultItems.push({ item: resultItem, id: resultItems.length, hitCount, searchTextCount - }); + }) } - }); + }) } if (keywords.length === 1 && keywords[0] === '') { - resultContent.innerHTML = '
    '; + resultContent.innerHTML = '
    ' } else if (resultItems.length === 0) { - resultContent.innerHTML = '
    '; + resultContent.innerHTML = '
    ' } else { resultItems.sort((resultLeft, resultRight) => { if (resultLeft.searchTextCount !== resultRight.searchTextCount) { - return resultRight.searchTextCount - resultLeft.searchTextCount; + return resultRight.searchTextCount - resultLeft.searchTextCount } else if (resultLeft.hitCount !== resultRight.hitCount) { - return resultRight.hitCount - resultLeft.hitCount; + return resultRight.hitCount - resultLeft.hitCount } - return resultRight.id - resultLeft.id; - }); - let searchResultList = ''; - resultContent.innerHTML = searchResultList; - window.pjax && window.pjax.refresh(resultContent); + return resultRight.id - resultLeft.id + }) + let searchResultList = '' + resultContent.innerHTML = searchResultList + window.pjax && window.pjax.refresh(resultContent) } - }; + } const fetchData = () => { fetch(KEEP.hexo_config.root + searchPath) - .then(response => response.text()) - .then(res => { + .then((response) => response.text()) + .then((res) => { // Get the contents from search data - isfetched = true; - datas = isXml ? [...new DOMParser().parseFromString(res, 'text/xml').querySelectorAll('entry')].map(element => { - return { - title: element.querySelector('title').textContent, - content: element.querySelector('content').textContent, - url: element.querySelector('url').textContent - }; - }) : JSON.parse(res); + isfetched = true + datas = isXml + ? [...new DOMParser().parseFromString(res, 'text/xml').querySelectorAll('entry')].map( + (element) => { + return { + title: element.querySelector('title').textContent, + content: element.querySelector('content').textContent, + url: element.querySelector('url').textContent + } + } + ) + : JSON.parse(res) // Only match articles with not empty titles - datas = datas.filter(data => data.title).map(data => { - data.title = data.title.trim(); - data.content = data.content ? data.content.trim().replace(/<[^>]+>/g, '') : ''; - data.url = decodeURIComponent(data.url).replace(/\/{2,}/g, '/'); - return data; - }); + datas = datas + .filter((data) => data.title) + .map((data) => { + data.title = data.title.trim() + data.content = data.content ? data.content.trim().replace(/<[^>]+>/g, '') : '' + data.url = decodeURIComponent(data.url).replace(/\/{2,}/g, '/') + return data + }) // Remove loading animation - const noResultDom = document.querySelector('#no-result'); - noResultDom && (noResultDom.innerHTML = ''); - }); - }; + const noResultDom = document.querySelector('#no-result') + noResultDom && (noResultDom.innerHTML = '') + }) + } if (KEEP.theme_config.local_search.preload) { - fetchData(); + fetchData() } if (searchInputDom) { - searchInputDom.addEventListener('input', inputEventFunction); + searchInputDom.addEventListener('input', inputEventFunction) } // Handle and trigger popup window - document.querySelectorAll('.search-popup-trigger').forEach(element => { + document.querySelectorAll('.search-popup-trigger').forEach((element) => { element.addEventListener('click', () => { - document.body.style.overflow = 'hidden'; - document.querySelector('.search-pop-overlay').classList.add('active'); - setTimeout(() => searchInputDom.focus(), 500); - if (!isfetched) fetchData(); - }); - }); + document.body.style.overflow = 'hidden' + document.querySelector('.search-pop-overlay').classList.add('active') + setTimeout(() => searchInputDom.focus(), 500) + if (!isfetched) fetchData() + }) + }) // Monitor main search box const onPopupClose = () => { - document.body.style.overflow = ''; - document.querySelector('.search-pop-overlay').classList.remove('active'); - }; + document.body.style.overflow = '' + document.querySelector('.search-pop-overlay').classList.remove('active') + } - document.querySelector('.search-pop-overlay').addEventListener('click', event => { + document.querySelector('.search-pop-overlay').addEventListener('click', (event) => { if (event.target === document.querySelector('.search-pop-overlay')) { - onPopupClose(); + onPopupClose() } - }); + }) document.querySelector('.search-input-field-pre').addEventListener('click', () => { - searchInputDom.value = ''; - searchInputDom.focus(); - inputEventFunction(); - }); - document.querySelector('.close-popup-btn').addEventListener('click', onPopupClose); - window.addEventListener('pjax:success', onPopupClose); - window.addEventListener('keyup', event => { + searchInputDom.value = '' + searchInputDom.focus() + inputEventFunction() + }) + document.querySelector('.close-popup-btn').addEventListener('click', onPopupClose) + window.addEventListener('pjax:success', onPopupClose) + window.addEventListener('keyup', (event) => { if (event.key === 'Escape') { - onPopupClose(); + onPopupClose() } - }); - + }) } diff --git a/source/js/main.js b/source/js/main.js index 0eb149a..3a07398 100644 --- a/source/js/main.js +++ b/source/js/main.js @@ -9,7 +9,7 @@ window.addEventListener('DOMContentLoaded', () => { repository: 'https://github.com/XPoet/hexo-theme-keep' } - KEEP.localStorageKey = 'KEEP-THEME-STATUS'; + KEEP.localStorageKey = 'KEEP-THEME-STATUS' KEEP.styleStatus = { isExpandPageWidth: false, @@ -22,48 +22,49 @@ window.addEventListener('DOMContentLoaded', () => { KEEP.printThemeInfo = () => { console.log( `\n %c ${KEEP.themeInfo.theme} %c ${KEEP.themeInfo.repository} \n`, - `color: #fadfa3; background: #333; padding: 6px 0;`, `padding: 6px 0;` - ); + `color: #fadfa3; background: #333; padding: 6px 0;`, + `padding: 6px 0;` + ) } // set styleStatus to localStorage KEEP.setStyleStatus = () => { - localStorage.setItem(KEEP.localStorageKey, JSON.stringify(KEEP.styleStatus)); + localStorage.setItem(KEEP.localStorageKey, JSON.stringify(KEEP.styleStatus)) } // get styleStatus from localStorage KEEP.getStyleStatus = () => { - let temp = localStorage.getItem(KEEP.localStorageKey); + let temp = localStorage.getItem(KEEP.localStorageKey) if (temp) { - temp = JSON.parse(temp); + temp = JSON.parse(temp) for (let key in KEEP.styleStatus) { - KEEP.styleStatus[key] = temp[key]; + KEEP.styleStatus[key] = temp[key] } - return temp; + return temp } else { - return null; + return null } } KEEP.refresh = () => { - KEEP.initUtils(); - KEEP.initHeaderShrink(); - KEEP.initModeToggle(); - KEEP.initBack2Top(); + KEEP.initUtils() + KEEP.initHeaderShrink() + KEEP.initModeToggle() + KEEP.initBack2Top() if (local_search?.enable === true) { - KEEP.initLocalSearch(); + KEEP.initLocalSearch() } if (code_block_tools?.enable === true || code_copy?.enable === true) { - KEEP.initCodeBlockTools(); + KEEP.initCodeBlockTools() } if (lazyload?.enable === true) { - KEEP.initLazyLoad(); + KEEP.initLazyLoad() } } - KEEP.printThemeInfo(); - KEEP.refresh(); -}); + KEEP.printThemeInfo() + KEEP.refresh() +}) diff --git a/source/js/toc.js b/source/js/toc.js index b2190bc..f895742 100644 --- a/source/js/toc.js +++ b/source/js/toc.js @@ -1,106 +1,111 @@ /* global KEEP */ + function initTOC() { - KEEP.utils.navItems = document.querySelectorAll('.post-toc-wrap .post-toc li'); + KEEP.utils.navItems = document.querySelectorAll('.post-toc-wrap .post-toc li') if (KEEP.utils.navItems.length > 0) { - KEEP.utils = { - ...KEEP.utils, findActiveIndexByTOC() { - if (!Array.isArray(KEEP.utils.sections)) return; - let index = KEEP.utils.sections.findIndex(element => { - return element && element.getBoundingClientRect().top - 20 > 0; - }); + if (!Array.isArray(KEEP.utils.sections)) return + let index = KEEP.utils.sections.findIndex((element) => { + return element && element.getBoundingClientRect().top - 20 > 0 + }) if (index === -1) { - index = KEEP.utils.sections.length - 1; + index = KEEP.utils.sections.length - 1 } else if (index > 0) { - index--; + index-- } - this.activateNavByIndex(index); + this.activateNavByIndex(index) }, registerSidebarTOC() { - KEEP.utils.sections = [...document.querySelectorAll('.post-toc li a.nav-link')].map(element => { - const target = document.getElementById(decodeURI(element.getAttribute('href')).replace('#', '')); - element.addEventListener('click', event => { - event.preventDefault(); - const offset = target.getBoundingClientRect().top + window.scrollY; - window.anime({ - targets: document.scrollingElement, - duration: 500, - easing: 'linear', - scrollTop: offset - 10, - complete: function () { - setTimeout(() => { - KEEP.utils.pageTop_dom.classList.add('hide'); - }, 100) - } - }); - }); - return target; - }); + KEEP.utils.sections = [...document.querySelectorAll('.post-toc li a.nav-link')].map( + (element) => { + const target = document.getElementById( + decodeURI(element.getAttribute('href')).replace('#', '') + ) + element.addEventListener('click', (event) => { + event.preventDefault() + const offset = target.getBoundingClientRect().top + window.scrollY + window.anime({ + targets: document.scrollingElement, + duration: 500, + easing: 'linear', + scrollTop: offset - 10, + complete: function () { + setTimeout(() => { + KEEP.utils.pageTop_dom.classList.add('hide') + }, 100) + } + }) + }) + return target + } + ) }, activateNavByIndex(index) { - const target = document.querySelectorAll('.post-toc li a.nav-link')[index]; - if (!target || target.classList.contains('active-current')) return; + const target = document.querySelectorAll('.post-toc li a.nav-link')[index] + if (!target || target.classList.contains('active-current')) return - document.querySelectorAll('.post-toc .active').forEach(element => { - element.classList.remove('active', 'active-current'); - }); - target.classList.add('active', 'active-current'); - let parent = target.parentNode; + document.querySelectorAll('.post-toc .active').forEach((element) => { + element.classList.remove('active', 'active-current') + }) + target.classList.add('active', 'active-current') + let parent = target.parentNode while (!parent.matches('.post-toc')) { - if (parent.matches('li')) parent.classList.add('active'); - parent = parent.parentNode; + if (parent.matches('li')) parent.classList.add('active') + parent = parent.parentNode } // Scrolling to center active TOC element if TOC content is taller then viewport. - const tocElement = document.querySelector('.post-toc-wrap'); + const tocElement = document.querySelector('.post-toc-wrap') window.anime({ targets: tocElement, duration: 200, easing: 'linear', - scrollTop: tocElement.scrollTop - (tocElement.offsetHeight / 2) + target.getBoundingClientRect().top - tocElement.getBoundingClientRect().top - }); + scrollTop: + tocElement.scrollTop - + tocElement.offsetHeight / 2 + + target.getBoundingClientRect().top - + tocElement.getBoundingClientRect().top + }) }, showPageAsideWhenHasTOC() { - const openHandle = () => { - const styleStatus = KEEP.getStyleStatus(); - const key = 'isOpenPageAside'; + const styleStatus = KEEP.getStyleStatus() + const key = 'isOpenPageAside' if (styleStatus && styleStatus.hasOwnProperty(key)) { - KEEP.utils.leftSideToggle.pageAsideHandleOfTOC(styleStatus[key]); + KEEP.utils.leftSideToggle.pageAsideHandleOfTOC(styleStatus[key]) } else { - KEEP.utils.leftSideToggle.pageAsideHandleOfTOC(true); + KEEP.utils.leftSideToggle.pageAsideHandleOfTOC(true) } } - const initOpenKey = 'init_open'; + const initOpenKey = 'init_open' if (KEEP.theme_config.toc.hasOwnProperty(initOpenKey)) { - KEEP.theme_config.toc[initOpenKey] ? openHandle() : KEEP.utils.leftSideToggle.pageAsideHandleOfTOC(false); - + KEEP.theme_config.toc[initOpenKey] + ? openHandle() + : KEEP.utils.leftSideToggle.pageAsideHandleOfTOC(false) } else { - openHandle(); + openHandle() } - } } - KEEP.utils.showPageAsideWhenHasTOC(); - KEEP.utils.registerSidebarTOC(); - + KEEP.utils.showPageAsideWhenHasTOC() + KEEP.utils.registerSidebarTOC() } else { - const pageAsideDom = document.querySelector('.page-aside'); - pageAsideDom && KEEP.utils.pageContainer_dom.removeChild(pageAsideDom); + const pageAsideDom = document.querySelector('.page-aside') + pageAsideDom && KEEP.utils.pageContainer_dom.removeChild(pageAsideDom) } } if (KEEP.theme_config.pjax.enable === true && KEEP.utils) { - initTOC(); + initTOC() } else { - window.addEventListener('DOMContentLoaded', initTOC); + window.addEventListener('DOMContentLoaded', initTOC) } diff --git a/source/js/utils.js b/source/js/utils.js index 3aec326..21a9d8d 100644 --- a/source/js/utils.js +++ b/source/js/utils.js @@ -1,7 +1,6 @@ /* global KEEP */ KEEP.initUtils = () => { - KEEP.utils = { html_root_dom: document.querySelector('html'), pageContainer_dom: document.querySelector('.page-container'), @@ -22,56 +21,55 @@ KEEP.initUtils = () => { isHeaderTransparent: false, initData() { - const { scroll, first_screen } = KEEP.theme_config.style; - this.isHasScrollProgressBar = scroll.progress_bar.enable === true; - this.isHasScrollPercent = scroll.percent.enable === true; - const { enable, header_transparent } = first_screen; - this.isHeaderTransparent = enable === true && header_transparent === true; + const { scroll, first_screen } = KEEP.theme_config.style + this.isHasScrollProgressBar = scroll.progress_bar.enable === true + this.isHasScrollPercent = scroll.percent.enable === true + const { enable, header_transparent } = first_screen + this.isHeaderTransparent = enable === true && header_transparent === 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 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); + 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}%`; + 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'); + const percent_dom = this.back2TopButton_dom.querySelector('.percent') if (percent === 0 || percent === undefined) { - this.back2TopButton_dom.classList.remove('show'); - + this.back2TopButton_dom.classList.remove('show') } else { - this.back2TopButton_dom.classList.add('show'); - percent_dom.innerHTML = percent.toFixed(0); + 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'); + this.pageTop_dom.classList.add('hide') if (this.isHeaderTransparent) { - this.headerWrapper_dom.classList.remove('transparent-1', 'transparent-2'); + this.headerWrapper_dom.classList.remove('transparent-1', 'transparent-2') } } else { - this.pageTop_dom.classList.remove('hide'); + this.pageTop_dom.classList.remove('hide') if (this.isHeaderTransparent) { if (scrollTop <= this.headerWrapper_dom.getBoundingClientRect().height) { - this.headerWrapper_dom.classList.remove('transparent-2'); - this.headerWrapper_dom.classList.add('transparent-1'); + this.headerWrapper_dom.classList.remove('transparent-2') + this.headerWrapper_dom.classList.add('transparent-1') } else if (scrollTop < this.innerHeight) { - this.headerWrapper_dom.classList.add('transparent-2'); + this.headerWrapper_dom.classList.add('transparent-2') } } } - this.prevScrollValue = scrollTop; + this.prevScrollValue = scrollTop }, // register window scroll event @@ -79,182 +77,183 @@ KEEP.initUtils = () => { window.addEventListener('scroll', () => { // style handle when scroll if (this.isHasScrollPercent || this.isHasScrollProgressBar) { - this.styleHandleWhenScroll(); + this.styleHandleWhenScroll() } // TOC scroll handle if (KEEP.theme_config.toc.enable && KEEP.utils.hasOwnProperty('findActiveIndexByTOC')) { - KEEP.utils.findActiveIndexByTOC(); + KEEP.utils.findActiveIndexByTOC() } // header shrink - KEEP.utils.headerShrink.headerShrink(); - }); + KEEP.utils.headerShrink.headerShrink() + }) }, // toggle show tools list toggleShowToolsList() { document.querySelector('.tool-toggle-show').addEventListener('click', () => { - document.querySelector('.side-tools-list').classList.toggle('show'); - }); + 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 fontSize = document.defaultView.getComputedStyle(document.body).fontSize + const fs = parseFloat(fontSize) const initFontSize = () => { - const styleStatus = KEEP.getStyleStatus(); + const styleStatus = KEEP.getStyleStatus() if (styleStatus) { - this.fontSizeLevel = styleStatus.fontSizeLevel; - setFontSize(this.fontSizeLevel); + 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(); + this.html_root_dom.style.fontSize = `${fs * (1 + fontSizeLevel * 0.05)}px` + KEEP.styleStatus.fontSizeLevel = fontSizeLevel + KEEP.setStyleStatus() } - initFontSize(); + initFontSize() document.querySelector('.tool-font-adjust-plus').addEventListener('click', () => { - if (this.fontSizeLevel === 5) return; - this.fontSizeLevel++; - setFontSize(this.fontSizeLevel); - }); + 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); - }); + 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 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; + const defaultMaxWidth = KEEP.theme_config.style.content_max_width || '1000px' + const expandMaxWidth = '90%' + let headerMaxWidth = defaultMaxWidth - let isExpand = false; + let isExpand = false - if (KEEP.theme_config.style.first_screen.enable === true && window.location.pathname === '/') { - headerMaxWidth = parseInt(defaultMaxWidth) * 1.2 + 'px'; + 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(); + KEEP.styleStatus.isExpandPageWidth = isExpand + KEEP.setStyleStatus() if (isExpand) { - iconDom.classList.remove('fa-up-right-and-down-left-from-center'); - iconDom.classList.add('fa-down-left-and-up-right-to-center'); - headerContentDom.style.maxWidth = expandMaxWidth; - mainContentDom.style.maxWidth = expandMaxWidth; + iconDom.classList.remove('fa-up-right-and-down-left-from-center') + iconDom.classList.add('fa-down-left-and-up-right-to-center') + headerContentDom.style.maxWidth = expandMaxWidth + mainContentDom.style.maxWidth = expandMaxWidth } else { - iconDom.classList.remove('fa-down-left-and-up-right-to-center'); - iconDom.classList.add('fa-up-right-and-down-left-from-center'); - headerContentDom.style.maxWidth = headerMaxWidth; - mainContentDom.style.maxWidth = defaultMaxWidth; + iconDom.classList.remove('fa-down-left-and-up-right-to-center') + iconDom.classList.add('fa-up-right-and-down-left-from-center') + headerContentDom.style.maxWidth = headerMaxWidth + mainContentDom.style.maxWidth = defaultMaxWidth } } const initPageWidth = () => { - const styleStatus = KEEP.getStyleStatus(); + const styleStatus = KEEP.getStyleStatus() if (styleStatus) { - isExpand = styleStatus.isExpandPageWidth; - setPageWidth(isExpand); + isExpand = styleStatus.isExpandPageWidth + setPageWidth(isExpand) } } - initPageWidth(); + initPageWidth() toolExpandDom.addEventListener('click', () => { - isExpand = !isExpand; + isExpand = !isExpand setPageWidth(isExpand) - }); - - + }) }, // go comment anchor goComment() { - this.goComment_dom = document.querySelector('.go-comment'); + this.goComment_dom = document.querySelector('.go-comment') if (this.goComment_dom) { this.goComment_dom.addEventListener('click', () => { - document.querySelector('#comment-anchor').scrollIntoView(); - }); + document.querySelector('#comment-anchor').scrollIntoView() + }) } - }, // get dom element height getElementHeight(selectors) { - const dom = document.querySelector(selectors); - return dom ? dom.getBoundingClientRect().height : 0; + 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'); + 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 (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); + const marginTopValue = Math.floor(innerHeight - allDomHeight) if (marginTopValue > 0) { - pb_dom.style.marginTop = `${marginTopValue - 2}px`; + pb_dom.style.marginTop = `${marginTopValue - 2}px` } } }, // big image viewer imageViewer() { - let isBigImage = false; + let isBigImage = false const showHandle = (maskDom, isShow) => { - document.body.style.overflow = isShow ? 'hidden' : 'auto'; + document.body.style.overflow = isShow ? 'hidden' : 'auto' if (isShow) { - maskDom.classList.add('active'); + maskDom.classList.add('active') } else { - maskDom.classList.remove('active'); + 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 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'); + const imgDoms = document.querySelectorAll('.markdown-body img') if (imgDoms.length) { - imgDoms.forEach(img => { + imgDoms.forEach((img) => { img.addEventListener('click', () => { - isBigImage = true; - showHandle(imageViewerDom, isBigImage); - targetImg.setAttribute('src', img.getAttribute('src')); - }); - }); + isBigImage = true + showHandle(imageViewerDom, isBigImage) + targetImg.setAttribute('src', img.getAttribute('src')) + }) + }) } else { - this.pageContainer_dom.removeChild(imageViewerDom); + this.pageContainer_dom.removeChild(imageViewerDom) } }, @@ -264,140 +263,134 @@ KEEP.initUtils = () => { }, getHowLongAgo(timestamp) { - const lang = 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); + const lang = 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, lang.year); - + return this.setHowLongAgoLanguage(__Y, lang.year) } else if (__M > 0) { - return this.setHowLongAgoLanguage(__M, lang.month); - + return this.setHowLongAgoLanguage(__M, lang.month) } else if (__W > 0) { - return this.setHowLongAgoLanguage(__W, lang.week); - + return this.setHowLongAgoLanguage(__W, lang.week) } else if (__d > 0) { - return this.setHowLongAgoLanguage(__d, lang.day); - + return this.setHowLongAgoLanguage(__d, lang.day) } else if (__h > 0) { - return this.setHowLongAgoLanguage(__h, lang.hour); - + return this.setHowLongAgoLanguage(__h, lang.hour) } else if (__m > 0) { - return this.setHowLongAgoLanguage(__m, lang.minute); - + return this.setHowLongAgoLanguage(__m, lang.minute) } else if (__s > 0) { - return this.setHowLongAgoLanguage(__s, lang.second); + return this.setHowLongAgoLanguage(__s, lang.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)); - }); + 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); + this.pjaxProgressBarTimer && clearInterval(this.pjaxProgressBarTimer) if (this.isHasScrollProgressBar) { - this.scrollProgressBar_dom.classList.add('hide'); + this.scrollProgressBar_dom.classList.add('hide') } - this.pjaxProgressBar_dom.style.width = '0'; - this.pjaxProgressIcon_dom.classList.add('show'); + this.pjaxProgressBar_dom.style.width = '0' + this.pjaxProgressIcon_dom.classList.add('show') - let width = 1; - const maxWidth = 99; + let width = 1 + const maxWidth = 99 - this.pjaxProgressBar_dom.classList.add('show'); - this.pjaxProgressBar_dom.style.width = width + '%'; + 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); + 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%'; + 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'); + this.pjaxProgressBar_dom.classList.remove('show') + this.pjaxProgressIcon_dom.classList.remove('show') if (this.isHasScrollProgressBar) { - this.scrollProgressBar_dom.classList.remove('hide'); + this.scrollProgressBar_dom.classList.remove('hide') } const temp_2 = setTimeout(() => { - this.pjaxProgressBar_dom.style.width = '0'; - clearTimeout(temp_1), clearTimeout(temp_2); - }, 200); - - }, 200); + this.pjaxProgressBar_dom.style.width = '0' + clearTimeout(temp_1), clearTimeout(temp_2) + }, 200) + }, 200) }, // insert tooltip content dom insertTooltipContent() { const init = () => { - document.querySelectorAll('.tooltip').forEach(element => { - const { content } = element.dataset; + document.querySelectorAll('.tooltip').forEach((element) => { + const { content } = element.dataset if (content) { element.insertAdjacentHTML( 'afterbegin', `${content}` - ); + ) } - }); + }) } setTimeout(() => { - init(); - }, 1000); + init() + }, 1000) } } // init data - KEEP.utils.initData(); + KEEP.utils.initData() // init scroll - KEEP.utils.registerWindowScroll(); + KEEP.utils.registerWindowScroll() // toggle show tools list - KEEP.utils.toggleShowToolsList(); + KEEP.utils.toggleShowToolsList() // global font adjust - KEEP.utils.globalFontAdjust(); + KEEP.utils.globalFontAdjust() // adjust content area width - KEEP.utils.contentAreaWidthAdjust(); + KEEP.utils.contentAreaWidthAdjust() // go comment - KEEP.utils.goComment(); + KEEP.utils.goComment() // init page height handle - KEEP.utils.initPageHeightHandle(); + KEEP.utils.initPageHeightHandle() // init first screen height - KEEP.utils.initFirstScreenHeight(); + KEEP.utils.initFirstScreenHeight() // big image viewer handle - KEEP.utils.imageViewer(); + KEEP.utils.imageViewer() // set how long age in home article block - KEEP.utils.setHowLongAgoInHome(); + KEEP.utils.setHowLongAgoInHome() // insert tooltip content dom - KEEP.utils.insertTooltipContent(); + KEEP.utils.insertTooltipContent() }