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 = /|\/>)/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 = ''; $resultContent.innerHTML = ""; let str = '
'; 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, '' + keyword + ""); dataTitle = dataTitle.replace(regS, '' + keyword + ""); }); str += '
'; if (oneImage) { str += `
${dataTitle}`; } else { str += '
'; } str += "
"; if (oneImage) { str += '
' + dataTitle + ""; } else { str += '
' + dataTitle + ""; } count += 1; if (dataContent !== "") { str += '

' + pre + matchContent + post + "

"; } if (dataTags.length) { str += '
'; for (let i = 0; i < dataTags.length; i++) { const element = dataTags[i].trim(); str += '#' + element + ""; } str += "
"; } } str += "
"; } }); if (count === 0) { str += '
' + GLOBAL_CONFIG.localSearch.languages.hits_empty.replace(/\$\{query}/, this.value.trim()) + "
"; } str += "
"; $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(); }); });