-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
- Loading branch information
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
// utils | ||
const util = { | ||
|
||
// https://github.com/jerryc127/hexo-theme-butterfly | ||
diffDate: (d, more = false) => { | ||
const dateNow = new Date() | ||
const datePost = new Date(d) | ||
const dateDiff = dateNow.getTime() - datePost.getTime() | ||
const minute = 1000 * 60 | ||
const hour = minute * 60 | ||
const day = hour * 24 | ||
|
||
let result | ||
if (more) { | ||
const dayCount = dateDiff / day | ||
const hourCount = dateDiff / hour | ||
const minuteCount = dateDiff / minute | ||
|
||
if (dayCount > 14) { | ||
result = null | ||
} else if (dayCount >= 1) { | ||
result = parseInt(dayCount) + ' ' + ctx.date_suffix.day | ||
} else if (hourCount >= 1) { | ||
result = parseInt(hourCount) + ' ' + ctx.date_suffix.hour | ||
} else if (minuteCount >= 1) { | ||
result = parseInt(minuteCount) + ' ' + ctx.date_suffix.min | ||
} else { | ||
result = ctx.date_suffix.just | ||
} | ||
} else { | ||
result = parseInt(dateDiff / day) | ||
} | ||
return result | ||
}, | ||
|
||
copy: (id, msg) => { | ||
const el = document.getElementById(id); | ||
if (el) { | ||
el.select(); | ||
document.execCommand("Copy"); | ||
if (msg && msg.length > 0) { | ||
hud.toast(msg, 2500); | ||
} | ||
} | ||
}, | ||
|
||
toggle: (id) => { | ||
const el = document.getElementById(id); | ||
if (el) { | ||
el.classList.toggle("display"); | ||
} | ||
}, | ||
|
||
scrollTop: () => { | ||
window.scrollTo({top: 0, behavior: "smooth"}); | ||
}, | ||
|
||
scrollComment: () => { | ||
document.getElementById('comments').scrollIntoView({behavior: "smooth"}); | ||
}, | ||
|
||
viewportLazyload: (target, func, enabled = true) => { | ||
if (!enabled || !("IntersectionObserver" in window)) { | ||
func(); | ||
return; | ||
} | ||
const observer = new IntersectionObserver((entries) => { | ||
if (entries[0].intersectionRatio > 0) { | ||
func(); | ||
observer.disconnect(); | ||
} | ||
}); | ||
observer.observe(target); | ||
} | ||
} | ||
|
||
const hud = { | ||
toast: (msg, duration) => { | ||
const d = Number(isNaN(duration) ? 2000 : duration); | ||
var el = document.createElement('div'); | ||
el.classList.add('toast'); | ||
el.classList.add('show'); | ||
el.innerHTML = msg; | ||
document.body.appendChild(el); | ||
|
||
setTimeout(function(){ document.body.removeChild(el) }, d); | ||
|
||
}, | ||
|
||
} | ||
|
||
// defines | ||
|
||
const l_body = document.querySelector('.l_body'); | ||
|
||
|
||
const init = { | ||
toc: () => { | ||
utils.jq(() => { | ||
const scrollOffset = 32; | ||
var segs = []; | ||
$("article.md-text :header").each(function (idx, node) { | ||
segs.push(node); | ||
}); | ||
function activeTOC() { | ||
var scrollTop = $(this).scrollTop(); | ||
var topSeg = null; | ||
for (var idx in segs) { | ||
var seg = $(segs[idx]); | ||
if (seg.offset().top > scrollTop + scrollOffset) { | ||
continue; | ||
} | ||
if (!topSeg) { | ||
topSeg = seg; | ||
} else if (seg.offset().top >= topSeg.offset().top) { | ||
topSeg = seg; | ||
} | ||
} | ||
if (topSeg) { | ||
$("#data-toc a.toc-link").removeClass("active"); | ||
var link = "#" + topSeg.attr("id"); | ||
if (link != '#undefined') { | ||
const highlightItem = $('#data-toc a.toc-link[href="' + encodeURI(link) + '"]'); | ||
if (highlightItem.length > 0) { | ||
highlightItem.addClass("active"); | ||
} | ||
} else { | ||
$('#data-toc a.toc-link:first').addClass("active"); | ||
} | ||
} | ||
} | ||
function scrollTOC() { | ||
const e0 = document.querySelector('#data-toc .toc'); | ||
const e1 = document.querySelector('#data-toc .toc a.toc-link.active'); | ||
if (e0 == null || e1 == null) { | ||
return; | ||
} | ||
const offsetBottom = e1.getBoundingClientRect().bottom - e0.getBoundingClientRect().bottom + 100; | ||
const offsetTop = e1.getBoundingClientRect().top - e0.getBoundingClientRect().top - 64; | ||
if (offsetTop < 0) { | ||
e0.scrollBy({top: offsetTop, behavior: "smooth"}); | ||
} else if (offsetBottom > 0) { | ||
e0.scrollBy({top: offsetBottom, behavior: "smooth"}); | ||
} | ||
} | ||
|
||
var timeout = null; | ||
window.addEventListener('scroll', function() { | ||
activeTOC(); | ||
if(timeout !== null) clearTimeout(timeout); | ||
timeout = setTimeout(function() { | ||
scrollTOC(); | ||
}.bind(this), 50); | ||
}); | ||
}) | ||
}, | ||
sidebar: () => { | ||
utils.jq(() => { | ||
$("#data-toc a.toc-link").click(function (e) { | ||
sidebar.dismiss(); | ||
}); | ||
}) | ||
}, | ||
relativeDate: (selector) => { | ||
selector.forEach(item => { | ||
const $this = item | ||
const timeVal = $this.getAttribute('datetime') | ||
let relativeValue = util.diffDate(timeVal, true) | ||
if (relativeValue) { | ||
$this.innerText = relativeValue | ||
} | ||
}) | ||
}, | ||
/** | ||
* Tabs tag listener (without twitter bootstrap). | ||
*/ | ||
registerTabsTag: function () { | ||
// Binding `nav-tabs` & `tab-content` by real time permalink changing. | ||
document.querySelectorAll('.tabs .nav-tabs .tab').forEach(element => { | ||
element.addEventListener('click', event => { | ||
event.preventDefault(); | ||
// Prevent selected tab to select again. | ||
if (element.classList.contains('active')) return; | ||
// Add & Remove active class on `nav-tabs` & `tab-content`. | ||
[...element.parentNode.children].forEach(target => { | ||
target.classList.toggle('active', target === element); | ||
}); | ||
// https://stackoverflow.com/questions/20306204/using-queryselector-with-ids-that-are-numbers | ||
const tActive = document.getElementById(element.querySelector('a').getAttribute('href').replace('#', '')); | ||
[...tActive.parentNode.children].forEach(target => { | ||
target.classList.toggle('active', target === tActive); | ||
}); | ||
// Trigger event | ||
tActive.dispatchEvent(new Event('tabs:click', { | ||
bubbles: true | ||
})); | ||
}); | ||
}); | ||
|
||
window.dispatchEvent(new Event('tabs:register')); | ||
}, | ||
|
||
} | ||
|
||
|
||
// init | ||
init.toc() | ||
init.sidebar() | ||
init.relativeDate(document.querySelectorAll('#post-meta time')) | ||
init.registerTabsTag() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
window.codeElements.forEach((codeElement) => { | ||
// 创建复制按钮 | ||
const codeCopyBtn = document.createElement('div'); | ||
codeCopyBtn.className = 'copy-btn'; | ||
codeCopyBtn.textContent = ctx.copycode.default_text; | ||
codeElement.appendChild(codeCopyBtn); | ||
|
||
// 添加点击事件监听 | ||
codeCopyBtn.addEventListener('click', async () => { | ||
const codeToCopy = codeElement.querySelector('pre')?.innerText || ''; | ||
if (navigator.clipboard) { | ||
try { | ||
await navigator.clipboard.writeText(codeToCopy); | ||
codeCopyBtn.textContent = ctx.copycode.success_text; | ||
codeCopyBtn.classList.add('success'); | ||
hud.toast(ctx.copycode.toast, 2500); | ||
} catch (error) { | ||
codeCopyBtn.textContent = '未获得用户许可'; | ||
codeCopyBtn.classList.add('warning'); | ||
} | ||
} else { | ||
codeCopyBtn.textContent = '浏览器不支持/非HTTPS'; | ||
codeCopyBtn.classList.add('warning'); | ||
} | ||
|
||
// 3秒后恢复默认文本 | ||
setTimeout(() => { | ||
codeCopyBtn.textContent = ctx.copycode.default_text; | ||
codeCopyBtn.classList.remove('success', 'warning'); | ||
}, 3000); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
utils.jq(() => { | ||
var $inputArea = $("input#search-input"); | ||
if ($inputArea.length === 0) { | ||
return; | ||
} | ||
|
||
var $resultArea = $("#search-result"); | ||
var $searchWrapper = $("#search-wrapper"); | ||
var client = algoliasearch(window.searchConfig.appId, window.searchConfig.apiKey); | ||
var index = client.initIndex(window.searchConfig.indexName); | ||
|
||
function filterResults(hits, filterPath) { | ||
if (!filterPath || filterPath === '/') return hits; | ||
var regex = new RegExp(filterPath); | ||
return hits.filter(hit => regex.test(hit.url)); | ||
} | ||
|
||
function displayResults(hits) { | ||
var $resultList = $("<ul>").addClass("search-result-list"); | ||
if (hits.length === 0) { | ||
$searchWrapper.addClass('noresult'); | ||
} else { | ||
$searchWrapper.removeClass('noresult'); | ||
hits.forEach(function(hit) { | ||
var contentSnippet = hit._snippetResult.content.value; | ||
var title = hit.hierarchy.lvl1 || 'Untitled'; | ||
var $item = $("<li>").html(`<a href="${hit.url}"><span class='search-result-title'>${title}</span><p class="search-result-content">${contentSnippet}</p></a>`); | ||
$resultList.append($item); | ||
}); | ||
} | ||
$resultArea.html($resultList); | ||
} | ||
|
||
$inputArea.on("input", function() { | ||
var query = $(this).val().trim(); | ||
var filterPath = $inputArea.data('filter'); | ||
|
||
if (query.length <= 0) { | ||
$searchWrapper.attr('searching', 'false'); | ||
$resultArea.empty(); | ||
return; | ||
} | ||
|
||
$searchWrapper.attr('searching', 'true'); | ||
|
||
index.search(query, { | ||
hitsPerPage: window.searchConfig.hitsPerPage, | ||
attributesToHighlight: ['content'], | ||
attributesToSnippet: ['content:30'], | ||
highlightPreTag: '<span class="search-keyword">', | ||
highlightPostTag: '</span>', | ||
restrictSearchableAttributes: ['content'] | ||
}).then(function(responses) { | ||
displayResults(filterResults(responses.hits, filterPath)); | ||
}); | ||
}); | ||
|
||
$inputArea.on("keydown", function(e) { | ||
if (e.which == 13) { | ||
e.preventDefault(); | ||
} | ||
}); | ||
|
||
var observer = new MutationObserver(function(mutationsList) { | ||
if (mutationsList.length === 1) { | ||
if (mutationsList[0].addedNodes.length) { | ||
$searchWrapper.removeClass('noresult'); | ||
} else if (mutationsList[0].removedNodes.length) { | ||
$searchWrapper.addClass('noresult'); | ||
} | ||
} | ||
}); | ||
|
||
observer.observe($resultArea[0], { childList: true }); | ||
}); |