build(deps): use prettier to format js code
This commit is contained in:
parent
622f5d1b2b
commit
300b709c52
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"useTabs": false,
|
||||
"endOfLine": "auto",
|
||||
"tabWidth": 2,
|
||||
"printWidth": 100,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"bracketSpacing": true,
|
||||
"semi": false
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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.
|
||||
/<img([^>]*)src="([^"]*)"([^>\/]*)\/?\s*>/gim,
|
||||
function (match, attrBegin, src, attrEnd) {
|
||||
// Exit if the src doesn't exists.
|
||||
if (!src) return match;
|
||||
if (!src) return match
|
||||
|
||||
return `<img ${attrBegin}
|
||||
lazyload
|
||||
|
@ -21,4 +21,4 @@ hexo.extend.filter.register(
|
|||
)
|
||||
},
|
||||
1
|
||||
);
|
||||
)
|
||||
|
|
|
@ -2,40 +2,36 @@
|
|||
|
||||
'use strict'
|
||||
|
||||
hexo.extend.filter.register('after_post_render', function (data) {
|
||||
|
||||
const config = this.config;
|
||||
const url = new URL(config.url);
|
||||
const siteHost = url.hostname || config.url;
|
||||
hexo.extend.filter.register(
|
||||
'after_post_render',
|
||||
function (data) {
|
||||
const config = this.config
|
||||
const url = new URL(config.url)
|
||||
const siteHost = url.hostname || config.url
|
||||
|
||||
// Match 'a' tags that don't contain html children.
|
||||
const regPureATag = /<a([^>]*)href="([^"]*)"([^>]*)>([^<]*)<\/a>/gim
|
||||
|
||||
data.content = data.content.replace(regPureATag, function (
|
||||
match,
|
||||
attrBegin,
|
||||
href,
|
||||
attrEnd,
|
||||
html
|
||||
) {
|
||||
data.content = data.content.replace(
|
||||
regPureATag,
|
||||
function (match, attrBegin, href, attrEnd, html) {
|
||||
// Exit if the href attribute doesn't exists.
|
||||
if (!href) return match;
|
||||
if (!href) return match
|
||||
|
||||
let link = '';
|
||||
let link = ''
|
||||
try {
|
||||
link = new URL(href);
|
||||
link = new URL(href)
|
||||
} catch (e) {
|
||||
// Invalid url, e.g. Anchor link.
|
||||
return match;
|
||||
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;
|
||||
if (!link.protocol || link.hostname === siteHost) return match
|
||||
|
||||
return (
|
||||
`<a class="link" ${attrBegin} href="${href}" ${attrEnd}>${html}<i class="fas fa-external-link-alt"></i></a>`
|
||||
return `<a class="link" ${attrBegin} href="${href}" ${attrEnd}>${html}<i class="fas fa-external-link-alt"></i></a>`
|
||||
}
|
||||
)
|
||||
})
|
||||
},
|
||||
0
|
||||
)
|
||||
|
|
|
@ -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'])};
|
||||
</script>`;
|
||||
});
|
||||
</script>`
|
||||
})
|
||||
|
|
|
@ -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 `<script src="${urlPrefix}@${version}/source/${path}"></script>`;
|
||||
return `<script src="${urlPrefix}@${version}/source/${path}"></script>`
|
||||
} else {
|
||||
return `<link rel="stylesheet" href="${urlPrefix}@${version}/source/${path}">`;
|
||||
return `<link rel="stylesheet" href="${urlPrefix}@${version}/source/${path}">`
|
||||
}
|
||||
case 'unpkg':
|
||||
urlPrefix = '//unpkg.com/hexo-theme-keep'
|
||||
if (tyle === 'js') {
|
||||
return `<script src="${urlPrefix}@${version}/source/${path}"></script>`;
|
||||
return `<script src="${urlPrefix}@${version}/source/${path}"></script>`
|
||||
} else {
|
||||
return `<link rel="stylesheet" href="${urlPrefix}@${version}/source/${path}">`;
|
||||
return `<link rel="stylesheet" href="${urlPrefix}@${version}/source/${path}">`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
})
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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 = `<span class="tool fold tooltip" data-content="${foldLang}"><i class="fas fa-chevron-down"></i></span>`
|
||||
|
||||
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 ? '<span class="code-lang">' + codeLang + '</span>' : ''}`
|
||||
|
||||
|
@ -30,72 +36,74 @@ KEEP.initCodeBlockTools = () => {
|
|||
${isMac ? foldDom + codeLangDom : '<span>' + foldDom + codeLangDom + '</span>'}
|
||||
<span class="tool copy tooltip" data-content="${copyLang}"><i class="fas fa-copy"></i></span>
|
||||
</div>`
|
||||
);
|
||||
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)
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 += `<b class="search-keyword">${text.substring(hit.position, end)}</b>`;
|
||||
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 += `<b class="search-keyword">${text.substring(hit.position, end)}</b>`
|
||||
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 += `<li><a href="${url}" class="search-result-title">${highlightKeyword(title, slicesOfTitle[0])}</a>`;
|
||||
resultItem += `<li><a href="${url}" class="search-result-title">${highlightKeyword(
|
||||
title,
|
||||
slicesOfTitle[0]
|
||||
)}</a>`
|
||||
} else {
|
||||
resultItem += `<li><a href="${url}" class="search-result-title">${title}</a>`;
|
||||
resultItem += `<li><a href="${url}" class="search-result-title">${title}</a>`
|
||||
}
|
||||
|
||||
slicesOfContent.forEach(slice => {
|
||||
resultItem += `<a href="${url}"><p class="search-result">${highlightKeyword(content, slice)}...</p></a>`;
|
||||
});
|
||||
slicesOfContent.forEach((slice) => {
|
||||
resultItem += `<a href="${url}"><p class="search-result">${highlightKeyword(
|
||||
content,
|
||||
slice
|
||||
)}...</p></a>`
|
||||
})
|
||||
|
||||
resultItem += '</li>';
|
||||
resultItem += '</li>'
|
||||
resultItems.push({
|
||||
item: resultItem,
|
||||
id: resultItems.length,
|
||||
hitCount,
|
||||
searchTextCount
|
||||
});
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
if (keywords.length === 1 && keywords[0] === '') {
|
||||
resultContent.innerHTML = '<div id="no-result"><i class="fas fa-search fa-5x"></i></div>';
|
||||
resultContent.innerHTML = '<div id="no-result"><i class="fas fa-search fa-5x"></i></div>'
|
||||
} else if (resultItems.length === 0) {
|
||||
resultContent.innerHTML = '<div id="no-result"><i class="fas fa-box-open fa-5x"></i></div>';
|
||||
resultContent.innerHTML = '<div id="no-result"><i class="fas fa-box-open fa-5x"></i></div>'
|
||||
} 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 = '<ul class="search-result-list">'
|
||||
resultItems.forEach((result) => {
|
||||
searchResultList += result.item
|
||||
})
|
||||
searchResultList += '</ul>'
|
||||
resultContent.innerHTML = searchResultList
|
||||
window.pjax && window.pjax.refresh(resultContent)
|
||||
}
|
||||
return resultRight.id - resultLeft.id;
|
||||
});
|
||||
let searchResultList = '<ul class="search-result-list">';
|
||||
resultItems.forEach(result => {
|
||||
searchResultList += result.item;
|
||||
});
|
||||
searchResultList += '</ul>';
|
||||
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 => {
|
||||
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);
|
||||
}
|
||||
}
|
||||
)
|
||||
: 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 = '<i class="fas fa-search fa-5x"></i>');
|
||||
});
|
||||
};
|
||||
const noResultDom = document.querySelector('#no-result')
|
||||
noResultDom && (noResultDom.innerHTML = '<i class="fas fa-search fa-5x"></i>')
|
||||
})
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
});
|
||||
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
})
|
||||
|
|
103
source/js/toc.js
103
source/js/toc.js
|
@ -1,32 +1,34 @@
|
|||
/* 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;
|
||||
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,
|
||||
|
@ -34,73 +36,76 @@ function initTOC() {
|
|||
scrollTop: offset - 10,
|
||||
complete: function () {
|
||||
setTimeout(() => {
|
||||
KEEP.utils.pageTop_dom.classList.add('hide');
|
||||
KEEP.utils.pageTop_dom.classList.add('hide')
|
||||
}, 100)
|
||||
}
|
||||
});
|
||||
});
|
||||
return target;
|
||||
});
|
||||
})
|
||||
})
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -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',
|
||||
`<span class="tooltip-content">${content}</span>`
|
||||
);
|
||||
)
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
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()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue