fix theme...
This commit is contained in:
192
themes/anzhiyu/source/js/search/algolia.js
Normal file
192
themes/anzhiyu/source/js/search/algolia.js
Normal file
@@ -0,0 +1,192 @@
|
||||
window.addEventListener("load", () => {
|
||||
const $searchMask = document.getElementById("search-mask");
|
||||
const $searchDialog = document.querySelector("#algolia-search .search-dialog");
|
||||
|
||||
const openSearch = () => {
|
||||
anzhiyu.animateIn($searchMask, "to_show 0.5s");
|
||||
$searchDialog.style.display = "block";
|
||||
setTimeout(() => {
|
||||
document.querySelector("#algolia-search .ais-SearchBox-input").focus();
|
||||
}, 100);
|
||||
|
||||
// shortcut: ESC
|
||||
document.addEventListener("keydown", function f(event) {
|
||||
if (event.code === "Escape") {
|
||||
closeSearch();
|
||||
document.removeEventListener("keydown", f);
|
||||
}
|
||||
});
|
||||
|
||||
fixSafariHeight();
|
||||
window.addEventListener("resize", fixSafariHeight);
|
||||
};
|
||||
|
||||
// shortcut: shift+S
|
||||
if (anzhiyu_keyboard) {
|
||||
window.addEventListener("keydown", function (event) {
|
||||
if (event.keyCode == 83 && event.shiftKey) {
|
||||
console.info(selectTextNow);
|
||||
if (selectTextNow) {
|
||||
openSearch();
|
||||
const t = document.querySelector("#algolia-search-input > div > form > input");
|
||||
t.value = selectTextNow;
|
||||
t.dispatchEvent(new Event("input"));
|
||||
setTimeout(() => {
|
||||
document.querySelector("#algolia-search-input > div > form > button.ais-SearchBox-submit").click();
|
||||
}, 64);
|
||||
} else {
|
||||
openSearch();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const closeSearch = () => {
|
||||
anzhiyu.animateOut($searchDialog, "search_close .5s");
|
||||
anzhiyu.animateOut($searchMask, "to_hide 0.5s");
|
||||
window.removeEventListener("resize", fixSafariHeight);
|
||||
};
|
||||
|
||||
// fix safari
|
||||
const fixSafariHeight = () => {
|
||||
if (window.innerWidth < 768) {
|
||||
$searchDialog.style.setProperty("--search-height", window.innerHeight + "px");
|
||||
}
|
||||
};
|
||||
|
||||
const searchClickFn = () => {
|
||||
anzhiyu.addEventListenerPjax(document.querySelector("#search-button > .search"), "click", openSearch);
|
||||
};
|
||||
|
||||
const searchFnOnce = () => {
|
||||
$searchMask.addEventListener("click", closeSearch);
|
||||
document.querySelector("#algolia-search .search-close-button").addEventListener("click", closeSearch);
|
||||
};
|
||||
|
||||
const algolia = GLOBAL_CONFIG.algolia;
|
||||
const isAlgoliaValid = algolia.appId && algolia.apiKey && algolia.indexName;
|
||||
if (!isAlgoliaValid) {
|
||||
return console.error("Algolia setting is invalid!");
|
||||
}
|
||||
|
||||
const search = instantsearch({
|
||||
indexName: algolia.indexName,
|
||||
/* global algoliasearch */
|
||||
searchClient: algoliasearch(algolia.appId, algolia.apiKey),
|
||||
searchFunction(helper) {
|
||||
if (helper.state.query) {
|
||||
let innerLoading = '<i class="anzhiyufont anzhiyu-icon-spinner anzhiyu-spin"></i>';
|
||||
document.getElementById("algolia-hits").innerHTML = innerLoading;
|
||||
helper.search();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const configure = instantsearch.widgets.configure({
|
||||
hitsPerPage: algolia.hits.per_page ?? 5,
|
||||
});
|
||||
|
||||
const searchBox = instantsearch.widgets.searchBox({
|
||||
container: "#algolia-search-input",
|
||||
showReset: false,
|
||||
showSubmit: false,
|
||||
placeholder: algolia.languages.input_placeholder,
|
||||
showLoadingIndicator: true,
|
||||
searchOnEnterKeyPressOnly: true,
|
||||
searchAsYouType: false,
|
||||
});
|
||||
|
||||
const hits = instantsearch.widgets.hits({
|
||||
container: "#algolia-hits",
|
||||
templates: {
|
||||
item(data) {
|
||||
const link = data.permalink ? data.permalink : GLOBAL_CONFIG.root + data.path;
|
||||
const result = data._highlightResult;
|
||||
const loadingLogo = document.querySelector("#algolia-hits .anzhiyu-spin");
|
||||
if (loadingLogo) {
|
||||
loadingLogo.style.display = "none";
|
||||
}
|
||||
setTimeout(() => {
|
||||
document.querySelector("#algolia-search .ais-SearchBox-input").focus();
|
||||
}, 200);
|
||||
return `
|
||||
<a href="${link}" class="algolia-hit-item-link">
|
||||
<span class="algolia-hits-item-title">${result.title.value || "no-title"}</span>
|
||||
</a>`;
|
||||
},
|
||||
empty: function (data) {
|
||||
const loadingLogo = document.querySelector("#algolia-hits .anzhiyu-spin");
|
||||
console.info(loadingLogo);
|
||||
if (loadingLogo) {
|
||||
loadingLogo.style.display = "none";
|
||||
}
|
||||
setTimeout(() => {
|
||||
document.querySelector("#algolia-search .ais-SearchBox-input").focus();
|
||||
}, 200);
|
||||
return (
|
||||
'<div id="algolia-hits-empty">' +
|
||||
GLOBAL_CONFIG.algolia.languages.hits_empty.replace(/\$\{query}/, data.query) +
|
||||
"</div>"
|
||||
);
|
||||
},
|
||||
},
|
||||
cssClasses: {
|
||||
item: "algolia-hit-item",
|
||||
},
|
||||
});
|
||||
|
||||
const stats = instantsearch.widgets.stats({
|
||||
container: "#algolia-info > .algolia-stats",
|
||||
templates: {
|
||||
text: function (data) {
|
||||
const stats = GLOBAL_CONFIG.algolia.languages.hits_stats
|
||||
.replace(/\$\{hits}/, data.nbHits)
|
||||
.replace(/\$\{time}/, data.processingTimeMS);
|
||||
return `<hr>${stats}`;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const powerBy = instantsearch.widgets.poweredBy({
|
||||
container: "#algolia-info > .algolia-poweredBy",
|
||||
});
|
||||
|
||||
const pagination = instantsearch.widgets.pagination({
|
||||
container: "#algolia-pagination",
|
||||
totalPages: algolia.hits.per_page ?? 5,
|
||||
templates: {
|
||||
first: '<i class="anzhiyufont anzhiyu-icon-angle-double-left"></i>',
|
||||
last: '<i class="anzhiyufont anzhiyu-icon-angle-double-right"></i>',
|
||||
previous: '<i class="anzhiyufont anzhiyu-icon-angle-left"></i>',
|
||||
next: '<i class="anzhiyufont anzhiyu-icon-angle-right"></i>',
|
||||
},
|
||||
scrollTo: false,
|
||||
showFirstLast: false,
|
||||
cssClasses: {
|
||||
root: "pagination",
|
||||
item: "pagination-item",
|
||||
link: "page-number",
|
||||
active: "current",
|
||||
disabled: "disabled-item",
|
||||
},
|
||||
});
|
||||
|
||||
search.addWidgets([configure, searchBox, hits, stats, powerBy, pagination]); // add the widgets to the instantsearch instance
|
||||
|
||||
search.start();
|
||||
|
||||
searchClickFn();
|
||||
searchFnOnce();
|
||||
|
||||
window.addEventListener("pjax:complete", () => {
|
||||
!anzhiyu.isHidden($searchMask) && closeSearch();
|
||||
searchClickFn();
|
||||
});
|
||||
|
||||
window.pjax &&
|
||||
search.on("render", () => {
|
||||
window.pjax.refresh(document.getElementById("algolia-hits"));
|
||||
});
|
||||
});
|
||||
270
themes/anzhiyu/source/js/search/local-search.js
Normal file
270
themes/anzhiyu/source/js/search/local-search.js
Normal file
@@ -0,0 +1,270 @@
|
||||
window.addEventListener("load", () => {
|
||||
let loadFlag = false;
|
||||
let dataObj = [];
|
||||
const $searchMask = document.getElementById("search-mask");
|
||||
|
||||
const openSearch = () => {
|
||||
const bodyStyle = document.body.style;
|
||||
bodyStyle.width = "100%";
|
||||
bodyStyle.overflow = "hidden";
|
||||
anzhiyu.animateIn($searchMask, "to_show 0.5s");
|
||||
anzhiyu.animateIn(document.querySelector("#local-search .search-dialog"), "titleScale 0.5s");
|
||||
setTimeout(() => {
|
||||
document.querySelector("#local-search-input input").focus();
|
||||
}, 100);
|
||||
if (!loadFlag) {
|
||||
search();
|
||||
loadFlag = true;
|
||||
}
|
||||
// shortcut: ESC
|
||||
document.addEventListener("keydown", function f(event) {
|
||||
if (event.code === "Escape") {
|
||||
closeSearch();
|
||||
document.removeEventListener("keydown", f);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const closeSearch = () => {
|
||||
const bodyStyle = document.body.style;
|
||||
bodyStyle.width = "";
|
||||
bodyStyle.overflow = "";
|
||||
anzhiyu.animateOut(document.querySelector("#local-search .search-dialog"), "search_close .5s");
|
||||
anzhiyu.animateOut($searchMask, "to_hide 0.5s");
|
||||
};
|
||||
|
||||
const searchClickFn = () => {
|
||||
document.querySelector("#search-button > .search").addEventListener("click", openSearch);
|
||||
document.querySelector("#menu-search").addEventListener("click", openSearch);
|
||||
};
|
||||
|
||||
const searchClickFnOnce = () => {
|
||||
document.querySelector("#local-search .search-close-button").addEventListener("click", closeSearch);
|
||||
$searchMask.addEventListener("click", closeSearch);
|
||||
if (GLOBAL_CONFIG.localSearch.preload) dataObj = fetchData(GLOBAL_CONFIG.localSearch.path);
|
||||
};
|
||||
|
||||
// check url is json or not
|
||||
const isJson = url => {
|
||||
const reg = /\.json$/;
|
||||
return reg.test(url);
|
||||
};
|
||||
|
||||
const fetchData = async path => {
|
||||
let data = [];
|
||||
const response = await fetch(path);
|
||||
if (isJson(path)) {
|
||||
data = await response.json();
|
||||
} else {
|
||||
const res = await response.text();
|
||||
const t = await new window.DOMParser().parseFromString(res, "text/xml");
|
||||
const a = await t;
|
||||
|
||||
data = [...a.querySelectorAll("entry")].map(item => {
|
||||
let tagsArr = [];
|
||||
if (item.querySelector("tags") && item.querySelector("tags").getElementsByTagName("tag")) {
|
||||
Array.prototype.forEach.call(item.querySelector("tags").getElementsByTagName("tag"), function (item, index) {
|
||||
tagsArr.push(item.textContent);
|
||||
});
|
||||
}
|
||||
let content = item.querySelector("content") && item.querySelector("content").textContent;
|
||||
let imgReg = /<img.*?(?:>|\/>)/gi; //匹配图片中的img标签
|
||||
let srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/i; // 匹配图片中的src
|
||||
let arr = content.match(imgReg); //筛选出所有的img
|
||||
|
||||
let srcArr = [];
|
||||
if (arr) {
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
let src = arr[i].match(srcReg);
|
||||
// 获取图片地址
|
||||
if (!src[1].indexOf("http")) srcArr.push(src[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
title: item.querySelector("title").textContent,
|
||||
content: content,
|
||||
url: item.querySelector("url").textContent,
|
||||
tags: tagsArr,
|
||||
oneImage: srcArr && srcArr[0],
|
||||
};
|
||||
});
|
||||
}
|
||||
if (response.ok) {
|
||||
const $loadDataItem = document.getElementById("loading-database");
|
||||
$loadDataItem.nextElementSibling.style.display = "block";
|
||||
$loadDataItem.remove();
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
const search = () => {
|
||||
if (!GLOBAL_CONFIG.localSearch.preload) {
|
||||
dataObj = fetchData(GLOBAL_CONFIG.localSearch.path);
|
||||
}
|
||||
const $input = document.querySelector("#local-search-input input");
|
||||
const $resultContent = document.getElementById("local-search-results");
|
||||
const $loadingStatus = document.getElementById("loading-status");
|
||||
|
||||
$input.addEventListener("input", function () {
|
||||
const keywords = this.value.trim().toLowerCase().split(/[\s]+/);
|
||||
if (keywords[0] !== "")
|
||||
$loadingStatus.innerHTML = '<i class="anzhiyufont anzhiyu-icon-spinner anzhiyu-pulse-icon"></i>';
|
||||
|
||||
$resultContent.innerHTML = "";
|
||||
let str = '<div class="search-result-list">';
|
||||
if (keywords.length <= 0) return;
|
||||
let count = 0;
|
||||
// perform local searching
|
||||
dataObj.then(data => {
|
||||
data.forEach(data => {
|
||||
let isMatch = true;
|
||||
let dataTitle = data.title ? data.title.trim().toLowerCase() : "";
|
||||
let dataTags = data.tags;
|
||||
let oneImage = data.oneImage ?? "";
|
||||
const dataContent = data.content
|
||||
? data.content
|
||||
.trim()
|
||||
.replace(/<[^>]+>/g, "")
|
||||
.toLowerCase()
|
||||
: "";
|
||||
const dataUrl = data.url.startsWith("/") ? data.url : GLOBAL_CONFIG.root + data.url;
|
||||
let indexTitle = -1;
|
||||
let indexContent = -1;
|
||||
let firstOccur = -1;
|
||||
// only match articles with not empty titles and contents
|
||||
if (dataTitle !== "" || dataContent !== "") {
|
||||
keywords.forEach((keyword, i) => {
|
||||
indexTitle = dataTitle.indexOf(keyword);
|
||||
indexContent = dataContent.indexOf(keyword);
|
||||
if (indexTitle < 0 && indexContent < 0) {
|
||||
isMatch = false;
|
||||
} else {
|
||||
if (indexContent < 0) {
|
||||
indexContent = 0;
|
||||
}
|
||||
if (i === 0) {
|
||||
firstOccur = indexContent;
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
isMatch = false;
|
||||
}
|
||||
|
||||
// show search results
|
||||
if (isMatch) {
|
||||
if (firstOccur >= 0) {
|
||||
// cut out 130 characters
|
||||
// let start = firstOccur - 30 < 0 ? 0 : firstOccur - 30
|
||||
// let end = firstOccur + 50 > dataContent.length ? dataContent.length : firstOccur + 50
|
||||
let start = firstOccur - 30;
|
||||
let end = firstOccur + 100;
|
||||
let pre = "";
|
||||
let post = "";
|
||||
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
}
|
||||
|
||||
if (start === 0) {
|
||||
end = 100;
|
||||
} else {
|
||||
pre = "...";
|
||||
}
|
||||
|
||||
if (end > dataContent.length) {
|
||||
end = dataContent.length;
|
||||
} else {
|
||||
post = "...";
|
||||
}
|
||||
|
||||
let matchContent = dataContent.substring(start, end);
|
||||
|
||||
// highlight all keywords
|
||||
keywords.forEach(keyword => {
|
||||
const regS = new RegExp(keyword, "gi");
|
||||
matchContent = matchContent.replace(regS, '<span class="search-keyword">' + keyword + "</span>");
|
||||
dataTitle = dataTitle.replace(regS, '<span class="search-keyword">' + keyword + "</span>");
|
||||
});
|
||||
|
||||
str += '<div class="local-search__hit-item">';
|
||||
if (oneImage) {
|
||||
str += `<div class="search-left"><img src=${oneImage} alt=${dataTitle} data-fancybox='gallery'>`;
|
||||
} else {
|
||||
str += '<div class="search-left" style="width:0">';
|
||||
}
|
||||
|
||||
str += "</div>";
|
||||
|
||||
if (oneImage) {
|
||||
str +=
|
||||
'<div class="search-right"><a href="' +
|
||||
dataUrl +
|
||||
'" class="search-result-title">' +
|
||||
dataTitle +
|
||||
"</a>";
|
||||
} else {
|
||||
str +=
|
||||
'<div class="search-right" style="width: 100%"><a href="' +
|
||||
dataUrl +
|
||||
'" class="search-result-title">' +
|
||||
dataTitle +
|
||||
"</a>";
|
||||
}
|
||||
|
||||
count += 1;
|
||||
|
||||
if (dataContent !== "") {
|
||||
str +=
|
||||
'<p class="search-result" onclick="pjax.loadUrl(`' +
|
||||
dataUrl +
|
||||
'`)">' +
|
||||
pre +
|
||||
matchContent +
|
||||
post +
|
||||
"</p>";
|
||||
}
|
||||
if (dataTags.length) {
|
||||
str += '<div class="search-result-tags">';
|
||||
|
||||
for (let i = 0; i < dataTags.length; i++) {
|
||||
const element = dataTags[i].trim();
|
||||
|
||||
str +=
|
||||
'<a class="tag-list" href="/tags/' +
|
||||
element +
|
||||
'/" data-pjax-state="" one-link-mark="yes">#' +
|
||||
element +
|
||||
"</a>";
|
||||
}
|
||||
|
||||
str += "</div>";
|
||||
}
|
||||
}
|
||||
str += "</div></div>";
|
||||
}
|
||||
});
|
||||
if (count === 0) {
|
||||
str +=
|
||||
'<div id="local-search__hits-empty">' +
|
||||
GLOBAL_CONFIG.localSearch.languages.hits_empty.replace(/\$\{query}/, this.value.trim()) +
|
||||
"</div>";
|
||||
}
|
||||
str += "</div>";
|
||||
$resultContent.innerHTML = str;
|
||||
if (keywords[0] !== "") $loadingStatus.innerHTML = "";
|
||||
window.pjax && window.pjax.refresh($resultContent);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
searchClickFn();
|
||||
searchClickFnOnce();
|
||||
|
||||
// pjax
|
||||
window.addEventListener("pjax:complete", () => {
|
||||
!anzhiyu.isHidden($searchMask) && closeSearch();
|
||||
searchClickFn();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user