/* global CONFIG */
window.addEventListener('DOMContentLoaded', () => {
// Popup Window
let isfetched = false;
let datas;
let isXml = true;
// Search DB path
let searchPath = CONFIG.path;
if (searchPath.length === 0) {
searchPath = 'search.xml';
} else if (/json$/i.test(searchPath)) {
isXml = false;
}
const path = CONFIG.root + searchPath;
const input = document.getElementById('search-input');
const resultContent = document.getElementById('search-result');
// Ref: https://github.com/ForbesLindesay/unescape-html
const unescapeHtml = html => {
return String(html)
.replace(/"/g, '"')
.replace(/'/g, '\'')
.replace(/:/g, ':')
// Replace all the other &#x; chars
.replace(/&#(\d+);/g, (m, p) => {
return String.fromCharCode(p);
})
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/&/g, '&');
};
const getIndexByWord = (word, text, caseSensitive) => {
let wordLen = word.length;
if (wordLen === 0) {
return [];
}
let startPosition = 0;
let position = [];
let index = [];
if (!caseSensitive) {
text = text.toLowerCase();
word = word.toLowerCase();
}
while ((position = text.indexOf(word, startPosition)) > -1) {
index.push({
position: position,
word : word
});
startPosition = position + wordLen;
}
return index;
};
// Merge hits into slices
const mergeIntoSlice = (start, end, index, searchText) => {
let item = index[index.length - 1];
let position = item.position;
let word = item.word;
let hits = [];
let searchTextCountInSlice = 0;
while (position + word.length <= end && index.length !== 0) {
if (word === searchText) {
searchTextCountInSlice++;
}
hits.push({
position: position,
length : word.length
});
let wordEnd = position + word.length;
// Move to next position of hit
index.pop();
while (index.length !== 0) {
item = index[index.length - 1];
position = item.position;
word = item.word;
if (wordEnd > position) {
index.pop();
} else {
break;
}
}
}
return {
hits : hits,
start : start,
end : 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;
};
const inputEventFunction = () => {
let searchText = input.value.trim().toLowerCase();
let keywords = searchText.split(/[-\s]+/);
if (keywords.length > 1) {
keywords.push(searchText);
}
let resultItems = [];
if (searchText.length > 0) {
// Perform local searching
console.log(datas);
datas.forEach(data => {
// Only match articles with not empty titles
if (!data.title) {
return;
}
let searchTextCount = 0;
let title = data.title.trim();
let titleInLowerCase = title.toLowerCase();
console.log(data.content);
let content = data.content ? data.content.trim().replace(/<(\/|\!|\?|[a-zA-Z])([^>]*)>/g, '') : '';
console.log(content);
if (CONFIG.localsearch.unescape) {
content = unescapeHtml(content);
}
let contentInLowerCase = content.toLowerCase();
let articleUrl = decodeURIComponent(data.url).replace(/\/{2,}/g, '/');
let indexOfTitle = [];
let indexOfContent = [];
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;
// Sort index by position of keyword
[indexOfTitle, indexOfContent].forEach(index => {
index.sort((itemLeft, itemRight) => {
if (itemRight.position !== itemLeft.position) {
return itemRight.position - itemLeft.position;
}
return itemLeft.word.length - itemRight.word.length;
});
});
let slicesOfTitle = [];
if (indexOfTitle.length !== 0) {
let tmp = mergeIntoSlice(0, title.length, indexOfTitle, searchText);
searchTextCount += tmp.searchTextCountInSlice;
slicesOfTitle.push(tmp);
}
let slicesOfContent = [];
while (indexOfContent.length !== 0) {
let item = indexOfContent[indexOfContent.length - 1];
let position = item.position;
let word = item.word;
// Cut out 100 characters
let start = position - 20;
let end = position + 80;
if (start < 0) {
start = 0;
}
if (end < position + word.length) {
end = position + word.length;
}
if (end > content.length) {
end = content.length;
}
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;
} else if (sliceLeft.hits.length !== sliceRight.hits.length) {
return sliceRight.hits.length - sliceLeft.hits.length;
}
return sliceLeft.start - sliceRight.start;
});
// Select top N slices in content
let upperBound = parseInt(CONFIG.localsearch.top_n_per_article, 10);
if (upperBound >= 0) {
slicesOfContent = slicesOfContent.slice(0, upperBound);
}
let resultItem = '';
if (slicesOfTitle.length !== 0) {
resultItem += `<li><a href="${articleUrl}" class="search-result-title">${highlightKeyword(title, slicesOfTitle[0])}</a>`;
} else {
resultItem += `<li><a href="${articleUrl}" class="search-result-title">${title}</a>`;
}
slicesOfContent.forEach(slice => {
resultItem += `<a href="${articleUrl}"><p class="search-result">${highlightKeyword(content, slice)}...</p></a>`;
});
resultItem += '</li>';
resultItems.push({
item : resultItem,
searchTextCount: searchTextCount,
hitCount : hitCount,
id : resultItems.length
});
}
});
}
if (keywords.length === 1 && keywords[0] === '') {
resultContent.innerHTML = '<div id="no-result"><i class="fa fa-search fa-5x"></i></div>';
} else if (resultItems.length === 0) {
resultContent.innerHTML = '<div id="no-result"><i class="fa fa-frown-o fa-5x"></i></div>';
} else {
resultItems.sort((resultLeft, resultRight) => {
if (resultLeft.searchTextCount !== resultRight.searchTextCount) {
return resultRight.searchTextCount - resultLeft.searchTextCount;
} else if (resultLeft.hitCount !== resultRight.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);
}
};
const fetchData = callback => {
fetch(path)
.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(item => {
return {//textContent
title : item.querySelector('title').innerHTML,
content: item.querySelector('content').textContent,
url : item.querySelector('url').innerHTML
};
}) : JSON.parse(res);
// Remove loading animation
document.querySelector('.search-pop-overlay').innerHTML = '';
document.body.style.overflow = '';
if (callback) {
callback();
}
});
};
if (CONFIG.localsearch.preload) {
fetchData();
}
const proceedSearch = () => {
document.body.style.overflow = 'hidden';
document.querySelector('.search-pop-overlay').style.display = 'block';
document.querySelector('.popup').style.display = 'block';
document.getElementById('search-input').focus();
};
// Search function
const searchFunc = () => {
document.querySelector('.search-pop-overlay').style.display = '';
document.querySelector('.search-pop-overlay').innerHTML = '<div class="search-loading-icon"><i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i></div>';
fetchData(proceedSearch);
};
if (CONFIG.localsearch.trigger === 'auto') {
input.addEventListener('input', inputEventFunction);
} else {
document.querySelector('.search-icon').addEventListener('click', inputEventFunction);
input.addEventListener('keypress', event => {
if (event.keyCode === 13) {
inputEventFunction();
}
});
}
// Handle and trigger popup window
document.querySelector('.popup-trigger').addEventListener('click', () => {
if (isfetched === false) {
searchFunc();
} else {
proceedSearch();
}
});
// Monitor main search box
const onPopupClose = () => {
document.body.style.overflow = '';
document.querySelector('.search-pop-overlay').style.display = 'none';
document.querySelector('.popup').style.display = 'none';
};
document.querySelector('.search-pop-overlay').addEventListener('click', onPopupClose);
document.querySelector('.popup-btn-close').addEventListener('click', onPopupClose);
window.addEventListener('pjax:success', onPopupClose);
window.addEventListener('keyup', event => {
if (event.which === 27) {
onPopupClose();
}
});
});
相关推荐
hexo-generator-searchdb:each适用于Hexo的Seach数据生成器插件
hexo-generator-searchdb 搜索Hexo的数据生成器插件。 该插件用于生成搜索索引文件,其中包含文章的所有必要数据,可用于为博客编写本地搜索引擎。 支持XML和JSON格式输出。 安装 $ npm install hexo-generator-searchdb 选项 您可以在根_config.yml配置此插件。 所有参数都是可选的。 search : path : search.xml field : post content : true format : html path-文件路径。 默认情况下是search.xml 。 如果文件扩展名为.json ,则输出格式为JSON。 否则,将导出XML格式的文件。 字段-您要搜索的搜索范围,可以选择: 帖子(默认)-仅覆盖您博客的所有帖子。 页面-仅覆盖博客的所有页面。 全部-将覆盖您博客的
Hexo骚操作:主题配置|搜索|评论|统计|图床
前言 相信各位在看过上一篇blog手把手教你使用hexo搭建属于你的个人博客后已经初步搭建了属于自己的博客,不过细心的你可能已经发现这样的博客还是缺点什么,现在就来说说Hexo的骚操作:添加主题、统计、评论、SEO等等等等。 承接上篇最后说过的:根目录下的_config.yml叫做站点配置文件,主题下文件夹的_config.yml叫做主题配置文件。好了,现在进入正题,今天我们要对Hexo进行
hexo-generator-search:一个为Hexo生成搜索数据的插件
六元发生器搜索 生成Hexo 3.x和4.x的搜索数据。 此插件用于生成搜索索引文件,其中包含您文章的所有必要数据,可用于为博客编写本地搜索引擎。 支持XML和JSON格式输出。 -试用此站点中的搜索引擎。 安装 $ npm install hexo-generator-search --save 选项 您可以在根_config.yml配置此插件。 search : path : search.xml field : post content : true template : ./search.xml path-文件路径。 默认情况下是search.xml 。 如果文件扩展名为.json ,则输出格式为JSON。 否则,将导出XML格式的文件。 字段-您要搜索的搜索范围,可以选择: 帖子(默认)-仅涵盖您博客的所有帖子。 页面-仅覆盖博客的所有页面。 全部
博客搭建之路:hexo增加搜索功能
时,algolia会多条合并进行提交,而免费的algolia会有大小的限制,可以看到超过10000字节就不行了,algolia默认会50条合并提交,可以设置几条进行合并。前期还好,后来随着我的文章越来越多,search.json文件已经达到了十几M,每次加载页面都需要花费几分钟来加载search.json文件,使用体验很不好。作为一个博客,没有搜索功能,如何在大批文章中找到自己想要的,那在hexo中如何增加搜索功能呢?本地搜索走不通,那就只能使用远程搜索了,还好hexo提供了algolia搜索。
初识机会网络仿真器ONE中ExternalMovement移动模型(导入外部移动数据)
最近半个月一直在研究ONE中关于ExternalMovement移动模型的源代码,在网上几乎没有找到相关的资料,很是苦恼,如果有共同研究方向的小伙伴欢迎联系我,共同讨论进步。 下面记录一下几点感悟: 1、使用外部数据的前提是在ONE的配置文件中增加及修改相关代码: Group.movementModel = ExternalMovement ExternalMovement.file = move...
数模【Mathematica(安装、入门方法、基本计算、基本图形、创建互动模型、利用数据、幻灯片演示、完整实例)】
Mathematica(安装and激活、入门方法、基本计算、基本图形、创建互动模型、利用数据、幻灯片演示、完整实例) Mathematica_11.3.0 安装教程 Mathematica11.3 激活 P1 笔记本 P2 入门方法 P3 基本计算 P4 基本图形 P5 创建互动模型 P6 利用数据 P7 演示 P8 完整实例
HEXO博客系统添加搜索功能
Hexo 可以通过接入第三方搜索引擎来为博客添加搜索功能。这里给出一种基于 Algolia 搜索引擎的实现方式。
【Python实战解析】从数据爬取到房价预测:一个完整的数据科学项目流程拆解
本文详细拆解了一个完整的Python数据科学项目流程,从爬取长沙二手房数据到房价预测模型构建。通过实战案例,介绍了数据爬取、清洗、可视化及模型优化的关键技巧,帮助开发者掌握Python在数据分析中的应用,提升程序开发能力。
hexo 搜索功能
搜索功能真心好用,当文章多起来的时候,标签提供的作用已经很少了,只能简单索引,搜索却能精确查找,这里我用的依旧是最简单的本地站内搜索。 安装插件 npm install hexo-generator-searchdb --save 修改 站点配置 文件 search: path: search.xml field: post format: html limit:
RK3588网络调试笔记:当我把默认RTL8211F PHY换成另一款时,踩了哪些坑?
本文详细记录了在RK3588平台上将默认RTL8211F PHY芯片替换为其他型号的全过程,包括硬件设计验证、内核驱动适配、复位时序配置等关键步骤。通过实际案例分享,提供了从驱动调试到硬件优化的系统性解决方案,帮助开发者高效完成PHY芯片替换,确保网络接口稳定性。
HarmonyOS应用开发者基础认证
B. 自定义组件:可复用的 UI 单元,可组合其它组件。D. 内置组件:ArkTS中默认内置的基本组件和布局组件,开发者可以直接调用,如Column、Text、Divider、Button等。E. 属性方法:用于组件属性的配置,统一通过属性方法进行设置,如fontSize()、width()、height()、color() 等。在Column和Row容器组件中,justifyContent用于设置子组件在主轴方向上的对齐格式,alignItems用于设置子组件在交叉轴方向上的对齐格式。
探索 Hexo 的强大插件:Hexo-Generator-Search
探索 Hexo 的强大插件:Hexo-Generator-Search 项目简介 是一个为 Hexo 构建的搜索引擎生成器。如果你是 Hexo 博客的用户,想要在你的站点中添加一个高效、自托管的搜索功能,那么这个项目就是你需要的解决方案。 技术分析 该插件基于lunr.js,一个轻量级的全文搜索引擎库,可以在客户端进行高效的文本检索。它的工作原理是在 Hexo 渲染博客文章时,会将每篇文章的关键信...
GitLab CI/CD .gitlab-ci.yml 关键词(十一):发布版本 release
本篇文章介绍使用GitLab CI/CD 发布一个版本,对外发布。并填写一些发布的信息。
hexo-generator-search插件教程
hexo-generator-search插件教程 项目介绍 hexo-generator-search 是一个专为 Hexo 博客框架设计的开源插件,旨在生成JSON格式的搜索引擎数据文件,从而提高博客站点的搜索体验。它允许博主轻松集成自定义搜索引擎,让站内内容的查找更加便捷高效。这个插件简化了索引创建过程,无需外部依赖即可在Hexo构建流程中自动生成所需的搜索数据。 项目快速启动 安装插件...
《UDS协议从入门到精通》系列——图解0x2E:通过ID写数据
图解数据包格式+直观的通信示例,迅速认识0x2E服务!!
QT应用编程: Win10系统下QT5.12搭建Android开发环境(配件齐全)
在win10系统下,搭建QT5.12.6 的Android开发环境。
【亲测免费】 为Hexo博客打造本地搜索功能:hexo-generator-search
为Hexo博客打造本地搜索功能:hexo-generator-search 项目介绍 hexo-generator-search 是一个专为 Hexo 3.x 和 4.x 版本设计的插件,旨在为你的博客生成一个搜索索引文件。这个插件能够提取你博客中的所有必要数据,帮助你构建一个高效的本地搜索引擎。无论是XML还是JSON格式的输出,hexo-generator-search 都能轻松应对,让你的博...
Statistics and Machine Learning Toolbox
Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具
Hexo-Generator-Search 项目教程
Hexo-Generator-Search 项目教程 1. 项目的目录结构及介绍 Hexo-Generator-Search 项目的目录结构如下: hexo-generator-search/ ├── demo_output/ ├── lib/ ├── templates/ ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── in...
C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片
基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正
最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版
Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。
【亲测免费】 Hexo Generator Search 文档指南
Hexo Generator Search 文档指南 1. 目录结构及介绍 此开源项目 hexo-generator-search 是专为 Hexo 博客框架设计的一个插件,用于生成站内搜索功能所需的索引文件。其基本目录结构如下: hexo-generator-search ├── package.json - 包含项目元数据和依赖关系 ├── README.md ...
廖雪峰Python教程[完整版]
廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白
hexo-generator-search项目常见问题解决方案
hexo-generator-search项目常见问题解决方案 hexo-generator-search 是一个为 Hexo 博客生成搜索索引文件的开源插件,它允许开发者创建本地的搜索功能。该项目的编程语言主要是 JavaScript。 新手常见问题及解决步骤 问题一:如何安装hexo-generator-search插件? 解决步骤: 确保您的系统中已经安装了Node.js。 在您的Hexo...
探秘Hexo-Generator-Search:打造高效博客搜索引擎
探秘Hexo-Generator-Search:打造高效博客搜索引擎 是一个针对Hexo框架的插件,它旨在为你的静态博客提供强大的本地搜索功能。如果你正在使用Hexo构建个人博客,并且希望让你的读者能够更方便地找到他们感兴趣的内容,那么这个项目绝对值得你关注。 项目简介 Hexo是一个快速、简洁且高效的静态站点生成器,而Hexo-Generator-Search则是在此基础上增添的一把利剑。这个插...
Vue Router 命名路由(Named Routes)完全指南:定义、链接与底层实现
命名路由(Named Routes)是 Vue Router 为每条路由赋予一个稳定名称的机制,让你在模板中用 `<router-link>` 声明式跳转、或在组件中调用 `router.push()` 进行编程式导航时,不必再硬编码长长的路径字符串,尤其适合包含动态参数(如 `/user/:userId`)的路由场景。阅读本文后,你将掌握如何在 `routes` 配置中定义命名路由、通过 `{
Hexo+Butterfly主题引入Local search 本地搜索
引入Local search 本地搜索 效果 安装hexo-generator-search npm install hexo-generator-search --save 添加配置 在全局配置文件_config.yml文件中添加配置: search: path: search.xml field: post # post:文章范围、page:页面范围、all:覆盖所有 conte...
我的Hexo博客搭好了12 - 自动提交URL到搜索引擎(IndexNow + Google Search Console)
快速索引:新文章可能在几分钟到几小时内被索引智能提交:只提交有变化的 URL,节省资源覆盖全面:同时支持 Google、Bing、Yandex 等搜索引擎完全自动:每次部署自动执行,无需手动操作详细日志:清晰显示提交的 URL 和结果再也不用担心新文章迟迟不被搜索引擎收录了!
Hexo个人博客NexT主题添加Local Search本地搜索
添加本地自定义站点内容搜索,可以通过文字标题或文字内容关键字搜索出相应文章 安装hexo-generator-searchdb,在站点的根目录下执行以下命令: $ npm install hexo-generator-searchdb --save 编辑站点配置文件,新增以下内容到任意位置: search: path: search.xml field: p...
hexo+next 增加搜索功能
1、安装本地搜索插件 hexo-generator-search 在博客根目录安装搜索插件 # 安装插件,用于生成博客索引数据(在博客根目录下执行下列命令): npm install hexo-generator-search --save 安装之后,会在站点目录的 public 文件夹下创建一个 search.xml 文件。(如果没有 search.xml 文件,请继续往下看) 2、修改站点配置文件(如果上一步没有找到 search.xml文件 则可以跳过 ) 在主题配置文件中的 _config
1717



被折叠的 条评论
为什么被折叠?



