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(content, slice)}...
`; - }); + slicesOfContent.forEach((slice) => { + resultItem += `${highlightKeyword( + content, + slice + )}...
` + }) - resultItem += '