改为真正的换行符 \n
// 处理并push到全局数据容器中
for(let item of search_data_line) {
item.title = callBeforeParse.recovery(item.title);
item.desc = callBeforeParse.recovery(item.desc);
item.resource = callBeforeParse.recovery(item.resource);
if(item.vassal != null ) item.vassal = callBeforeParse.recovery(item.vassal);
}
// 加入到push到全局的搜索数据队列中,等待加入到全局数据容器中
searchDataController.pushToGlobal(search_data_line);
// 触发搜索数据改变事件(做缓存等操作,观察者模式)
for(let fun of registry.searchData.dataChange) {
fun(search_data_line);
}
}
})
}
// 根据fetchFun名返回字符串函数
function getFetchFunGetByName(fetchFunName) {
for(let fetchFunData of globalFetchFun) {
if(fetchFunData.name == fetchFunName) {
return fetchFunData.fetchFun;
}
}
}
// 检查是否已经执行初始化
function checkIsInitializedAndSetInitialized(secondTime) {
let key = "DATA_INIT";
let value = cache.cookieGet(key);
if(value != null && value != "") return true;
cache.cookieSet(key,key,1000*secondTime);
return false;
}
// 【数据初始化主函数】
// 调用下面函数自动初始化数据,刚进来直接检查更新(如果数据已过期就更新数据)
function dataInitFun() {
// 从缓存中获取数据,判断是否还有效
// cache.remove(SEARCH_DATA_KEY)
let dataPackage = cache.get(registry.searchData.SEARCH_DATA_KEY);
if(dataPackage != null) {
// 缓存信息不为空,深入判断是否使用缓存的数据
let dataExpireTime = dataPackage.expire;
let currentTime = new Date().getTime();
// console.logout("缓存的数据:",dataBox.data)
// 数据多大时,才开启缓存
const TRIGGER_CACHE_DATA_LENGTH = 300;
// 判断是否有效,有效的话放到全局容器中
let isValid = (dataExpireTime != null && dataExpireTime > currentTime && dataPackage.data != null && dataPackage.data.length > 0);
// 如果网站比较特殊,忽略数据过期时间
if(!isValid && window.location.host.toUpperCase().indexOf("GITHUB.COM") >= 0) {
isValid = true;
}
// 挂载数据
// 从缓存中将挂载数据挂载 (条件是视图已经初始化)
if(registry.view.initialized) registry.searchData.data = dataPackage.data;
// 如果数据过期,或数据量不满足缓存大小,会去请求数据
// 检查是否已经执行初始化
if(isValid && dataPackage.data.length >= TRIGGER_CACHE_DATA_LENGTH ) {
console.logout(`${registry.view.initialized?'数据加载':'数据检查'}:数据有效期还有${parseInt((dataExpireTime - currentTime)/1000/60)} 分钟!`,dataPackage.data);
return
};
}
// 在去网络请求获取数据前-检查是否已经执行初始化-防止多页面同时加载导致的数据重复加载
if(! askIsExpiredByTopic("SEARCH_DATA_INIT",10*1000)) return;
// 内部将使用递归,解析出信息
dataSourceHandle(dataSources,null);
}
// 检查数据有效性,且只有数据无效时挂载到数据
dataInitFun();
// 当视图第一次显示时,再执行
registry.view.onViewFirstShow.push(dataInitFun);
// 该函数作用是为了防止一个页面多次加载数据,导致页面一直在加载
function checkIsCanInit() {
let initFlagKey = "initFlagKey";
let initFlagValue = cache.get(initFlagKey)??0;
let currentTime = new Date().getTime();
let vailTime = 8*1000;
console.logout("是否过期(为负过期):",initFlagValue , currentTime,initFlagValue +vailTime - currentTime)
let b = initFlagValue == 0 || initFlagValue + vailTime < currentTime;
if(b) cache.set(initFlagKey,currentTime);
return b;
}
const refreshNewData = function (searchData) {
console.log("==3:数据对比==")
// 新数据加载完成-进行数据对比
// 旧数据,也就是上一次数据,用于与本次比较,得出新添加数据
let oldSearchData = cache.get(registry.searchData.OLD_SEARCH_DATA_KEY)??[];
console.log("当前tt:",searchData)
// 当前时间戳
let currentTime = new Date().getTime();
// 准备一个存储新数据项的容器
let newDataItems = [];
// 只要 oldSearchData 与 searchData有就可以比较,得到新数据
if( oldSearchData != null && oldSearchData.length != 0 && searchData != null && searchData.length != 0 ) {
console.logout("开始差异对比(上次与这次数据):",oldSearchData.length,searchData.length)
// 这里没有旧的
newDataItems = searchData.diff(oldSearchData,registry.searchData.idFun,1);
// 给新添加的过期时间(新数据有效期)
let dayNumber = registry.searchData.NEW_DATA_EXPIRE_DAY_NUM;
newDataItems.forEach(item=>item.expires=(currentTime++) + (1000*60*60*24*dayNumber));
console.log("新差异项:",JSON.parse(JSON.stringify(newDataItems)));
}
// 过滤掉新数据中带有“带注释”的项
newDataItems = newDataItems.filter(item=> !item.title.startsWith("#"));
// 以前的新增数据
let oldNewItems = cache.get(registry.searchData.SEARCH_NEW_ITEMS_KEY)??[];
// 确保oldNewItems是合法值
if( ! oldNewItems instanceof Array) oldNewItems = [];
// 如果还没有过期的,保留下来放在最新数据中
for(let item of oldNewItems) {
if(item != null && item.expires > currentTime) newDataItems.push(item);
}
// 总新增去重 (标记 - 过滤标记的 )
newDataItems = removeDuplicates(newDataItems,(item)=>item.title+item.desc);
// 忽略新数据条件 (下面不满足条件直接进入老数据 或说清空总新数据)
if( newDataItems.length/searchData.length < 0.3 && newDataItems.length <= registry.searchData.showSize ) {
// 重新缓存“New Data”
cache.set(registry.searchData.SEARCH_NEW_ITEMS_KEY,newDataItems);
// 为全局数据(注册表中)的新数据添加新数据标签
for(let nItem of newDataItems) {
for(let cItem of searchData) {
if(nItem.title === cItem.title && nItem.desc === cItem.desc) {
// 修改全局搜索数据中New Data数据添加“新数据”标签
if (! cItem.title.startsWith(registry.searchData.NEW_ITEMS_FLAG)) {
cItem.title = registry.searchData.NEW_ITEMS_FLAG+cItem.title;
}
break;
}
}
}
}else {
// 清空数据,不清掉,又不缓存新数据的索引将失效
cache.set(registry.searchData.SEARCH_NEW_ITEMS_KEY,[]);
}
return searchData;
}
// ############ 使用用户操作的规则对加载出来的数据过滤:(责任链中的一块)
registry.searchData.USDRC.add({weight:300 ,fun:refreshNewData});
// 解析出传入的所有项标签数据
function parseFlags(data = [],selecterFun = (_item)=>_item) {
let isArray = Array.isArray(data);
let items = isArray?data:[data];
let flagsMap = {
/*
"程序员": {
name: "程序员",
status: 0/1, // 1正常,0禁搜
visible: false/true
}
*/
}
// 解析 item.name中包含的标签
items.forEach(function(item) {
let captureGroups = captureRegEx(/\[\s*(([^'\]\s]*)\s*')?\s*([^'\]]*)\s*'?\s*]/gm,selecterFun(item));
captureGroups.forEach(function(group) {
let params = group[2]??"";
let label = group[3];
// 判断是否已经存在
if(label != null && flagsMap[label] == null ) {
let currentHandleFlagObj = flagsMap[label] = {
name: label,
status: 1, // 正常
//visible: params.includes("h"), // 参数中包含h字符表示可见
count: 1
//params: params
//items: [item]
}
// 如果传入的不是一个数组,那设置下面参数才有意义
if(! isArray) {
currentHandleFlagObj.params = params;
}
}else {
if(flagsMap[label] != null) {
flagsMap[label].count++;
//flagsMap[label].items.push(item);
}
}
})
});
// 这里不能是不是数组(上面的isArray)都返回flag数组,因为一项也可能有多个标签
return Object.values(flagsMap);
}
const refreshFlags = function (searchData){
console.log("==1:解析出数据标签==")
// 将现有的所有标签提取出来
// 解析
let dataItemFlags = parseFlags(searchData,(_item=>_item.title));
// 缓存
if(dataItemFlags.length > 0) {
cache.set(registry.searchData.DATA_ITEM_FLAGS_CACHE_KEY,dataItemFlags)
}
return searchData;
}
// ################# 执行顺序从大到小 1000 -> 500
registry.searchData.USDRC.add({weight:500 ,fun:refreshFlags});
// 清理标签(参数中有h的)
function clearHideFlag(data,get = (item)=>item.title,set = (item,cleaned)=>{item.title=cleaned}) {
let isArray = Array.isArray(data);
let items = isArray?data:[data];
for(let item of items) {
let target = get(item);
const regex = /\[\s*[^:\]]*h[^:\]]*\s*'\s*[^'\]]*\s*'\s*]/gm;
let cleanedTarget = target.replace(regex, '');
set(item,cleanedTarget);
}
return isArray?items:items[0];
}
const filterSearchData = function (searchData) {
const filterDataByUserUnfollowList = (itemsData,userUnfollowList = []) => {
var userUnfollowMap = userUnfollowList.reduce(function(result, item) {
result[item] = '';
return result;
}, {});
// 开始过滤
return itemsData.filter(item=>{
let flags = parseFlags(item.title);
for(let flag of flags){
if(userUnfollowMap[flag.name] != null){
// 被过滤
return false;
}
}
return true;
})
}
console.log("==2:去除用户不关注的数据项==")
// 用户维护的取消关注标签列表
let userUnfollowList = cache.get(registry.searchData.USER_UNFOLLOW_LIST_CACHE_KEY)?? registry.searchData.USER_DEFAULT_UNFOLLOW;
// 利用用户维护的取消关注标签列表 过滤 搜索数据
let filteredSearchData = filterDataByUserUnfollowList(searchData,userUnfollowList);
// 去标签(参数h),清理每个item中title属性的flag
let clearedSearchData = clearHideFlag(filteredSearchData);
return clearedSearchData;
}
// ############### 执行顺序从大到小 1000 -> 500
registry.searchData.USDRC.add({weight:400 ,fun:filterSearchData});
const refreshIndex = function (searchData) {
// 当前最新数据,用于搜索
let newDataItems = cache.get(registry.searchData.SEARCH_NEW_ITEMS_KEY);
// 将 index 给 newDataItems ,不然new中的我们选择与实际选择的不一致问题 !
// 给全局数据创建索引
searchData.forEach((item,index)=>{item.index=index});
// 给NEW建索引
newDataItems.forEach(NItem=>{
for(let CItem of searchData) {
if( CItem.title.includes(NItem.title) && NItem.desc === CItem.desc) {
NItem.index = CItem.index;
break;
}
}
})
// 忽略新数据条件
if( newDataItems.length/searchData.length < 0.3 || newDataItems.length < 10 ) {
// 重新缓存“New Data”
cache.set(registry.searchData.SEARCH_NEW_ITEMS_KEY,newDataItems);
}else {
// 清空数据,不清掉,又不缓存新数据的索引将失效
cache.set(registry.searchData.SEARCH_NEW_ITEMS_KEY,[]);
}
return searchData;
}
// ############### 执行顺序从大到小 1000 -> 500
registry.searchData.USDRC.add({weight:0 ,fun:refreshIndex});
registry.searchData.USDRC.add({weight:0 ,fun:refreshIndex});
// 模块二
registry.view.viewVisibilityController = (function() {
// 整个视图对象
let viewDocument = null;
let searchInputDocument = null;
let matchItems = null;
let searchBox = null;
let isInitializedView = false;
let controlButton = null;
let textShow = null;
let matchResult = null;
let initView = function () {
// 初始化视图
let view = document.createElement("div")
view.id = "my_search_box";
let menu_icon = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB0PSIxNjc3MDgxNTk3NzA3IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjEzNDYxIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyMDAiPjxwYXRoIGQ9Ik0yMjQuMiA0NzIuM2MtMTMtNS43LTMuNy0yMy41IDguMi0xOSA5MSAzNCAxNDYuOCAxMDguNyAxODIuNCAxMzguNSA1LjYgNC43IDE0IDIuOSAxNy4zLTMuNSAxNi44LTMyIDQ1LjgtMTEzLjctNTcuMS0xNjguNi04Ny4zLTQ2LjUtMTg4LTUzLjYtMjQ3LjMtODIuMi0xNC41LTctMzEuMSA0LjYtMjkuOSAyMC43IDUgNjkuNyAyOC45IDEyNC43IDYyLjMgMTgxLjUgNjcuMyAxMTQuMyAxNDAuNiAxMzIuOSAyMTYuNiAxMDQgMi4yLTAuOSA0LjUtMS44IDctMyA3LTMuNCA4LjMtMTIuOSAyLjUtMTguMSAwLjEgMC00NS43LTY5LjMtMTYyLTE1MC4zeiIgZmlsbD0iI0ZGRDQwMSIgcC1pZD0iMTM0NjIiPjwvcGF0aD48cGF0aCBkPSJNMjgyLjcgODQ5LjljNzkuNS0xMzcgMTcyLjQtMjYzLjEgMzg1LjQtNDAxLjMgOS44LTYuNCAyLjEtMjEuNS04LjktMTcuNEM0OTcuNyA0OTIuOCA0MjkuNyA1ODUgMzczLjMgNjQwLjhjLTguNyA4LjctMjMuNCA2LjMtMjkuMS00LjYtMjcuMi01MS44LTY5LjUtMTc0LjEgOTcuMy0yNjMuMSAxNDcuNy03OC44IDMxOS45LTkxLjQgNDI5LjctOTMuMyAxOC45LTAuMyAzMS41IDE5LjQgMjMuMyAzNi40Qzg2My43IDM4MCA4NDIuNiA0NzggNzg5LjkgNTY3LjYgNjgwLjggNzUzLjEgNTQ1LjUgNzY2LjcgNDIyLjIgNzE5LjhjLTguOC0zLjQtMTguOC0wLjItMjQgNy43LTE2LjYgMjUuMi01MC4zIDgwLjEtNTguNyAxMjIuNC0xMS40IDU2LjgtODIuMiA0My45LTU2LjggMHoiIGZpbGw9IiM4QkMwM0MiIHAtaWQ9IjEzNDYzIj48L3BhdGg+PHBhdGggZD0iTTM3NSA0MTkuNmMtMzAuMSAyOC4yLTQ1LjggNTcuNy01Mi40IDg2LjEgNDAuNiAzMi40IDcwLjIgNjcuNyA5Mi4xIDg1LjkgMS4yIDEgMi41IDEuNiAzLjkgMi4xIDYuNS02LjcgMTMuMy0xMy43IDIwLjQtMjAuNyAxNS4yLTM3LjkgMjUuMy0xMDUuNy02NC0xNTMuNHpNMzE4LjggNTQ4LjJjMS42IDM2LjEgMTQuNyA2Ny42IDI1LjUgODguMSA1LjcgMTAuOSAyMC4zIDEzLjMgMjkuMSA0LjYgNC45LTQuOSAxMC0xMCAxNS4xLTE1LjQtMC42LTEtMS4zLTItMi4yLTIuOCAwLTAuMS0yMC4xLTMwLjUtNjcuNS03NC41eiIgZmlsbD0iIzhCQTAwMCIgcC1pZD0iMTM0NjQiPjwvcGF0aD48L3N2Zz4=";
view.innerHTML = (`
`)
// 设置样式
view.style = `
position: fixed;top:50px;
border:2px solid #cecece;z-index:2147383656;
background: #ffffff;
overflow: hidden;
`;
// 挂载到文档中
document.body.appendChild(view)
// 整个视图对象放在组件全局中/注册表中
registry.view.viewDocument = viewDocument = view;
// 搜索框对象
searchInputDocument = $("#my_search_input")
matchItems = $("#matchItems");
searchBox = $("#searchBox")
controlButton = $("#controlButton")
textShow = $("#text_show")
matchResult = $("#matchResult");
// 菜单函数(点击输入框右边按钮时会调用)
controlButton.click( function () {
registry.view.menuActive = true;
// alert("小彩蛋:可以搜索一下“系统项”了解脚本基本使用哦~");
// 调用手动触发搜索函数,如果已经搜索过,搜索空串(清理)
let keyword = "[系统项]";
registry.searchData.triggerSearchHandle(searchInputDocument.val()==keyword?'':keyword);
setTimeout(function(){ registry.view.menuActive = false;},registry.view.delayedHideTime+100);
})
searchBox.css({
"height": "45px",
"background": "#ffffff",
"padding": "0px",
"box-sizing": " border-box",
"z-index": "10001",
"position":"relative",
"display": "flex",
"justify-content": "space-between",
"align-items": "center",
"flex-wrap": "nowrap"
})
searchInputDocument.css({
"width": "100%",
"height": "100%",
"border": "none",
"outline": "none",
"font-size": "15px",
"background": "#fff",
"padding": "0px 10px",
"box-sizing": " border-box",
"color":"rgba(0,0,0,.87)",
"font-weight":"400",
"margin":"0px"
})
$("#matchResult").css({
"display":"none"
})
$("#matchResult > ol").css({
"margin": "0px",
"padding": "0px 15px 5px"
})
textShow.css({
"display":"none",
"width":"100%",
"box-sizing": "border-box",
"padding": "5px 10px 7px",
"font-size": "15px",
"line-height":"25px",
"max-height":"450px",
"overflow": "auto",
"text-align":"left",
"color":"#000000"
})
// 图片放大/还原
textShow.on("click","img",function(e) {
let target = e.target;
if(target.isEnlarge??false) {
$(this).animate({
width: "100%"
});
// 还原
target.isEnlarge = false;
}else {
$(this).animate({
width: "900px"
});
target.isEnlarge = true;
}
});
// 设置视图已经初始化
registry.view.initialized = true;
// 在搜索的结果集中上下选择移动然后回车(相当点击)
searchInputDocument.keyup(function(event){
let keyword = $(event.target).val().trim();
// 当不为空时,放到全局keyword中
if(keyword != "" && keyword != null) {
registry.searchData.keyword = event.target.value;
}
// 处理keyword中的":"字符
if(keyword.endsWith("::") || keyword.endsWith("::")) {
keyword = keyword.replace(/::|::/,registry.searchData.searchBoundary).replace(/\s+/," ");
// 每次要形成一个" : "的时候去掉重复的" : : " -> " : "
keyword = keyword.replace(/((\s{1,2}:)+ )/,registry.searchData.searchBoundary);
$(event.target).val(keyword.toUpperCase());
}
});
// shift+tab处理事件(取消搜索pro模式)
document.addEventListener('keydown', function(event) {
if (event.shiftKey && event.keyCode === 9 ) {
if(registry.searchData.isSearchPro()) {
// 在这里编写按下shift+tab键时要执行的代码
let input = event.target;
input.value = input.value.split(registry.searchData.searchBoundary)[0]
event.target.value = event.target.value.toLowerCase();
}
event.preventDefault();
}
});
// 这个监听用来处理其它键(非上下选择)的。
searchInputDocument.keydown(function (event){
// 判断一个输入框的东西,如果如果按下的是删除,判断一下是不是"搜索模式"
let keyword = $(event.target).val();
let input = event.target;
if(event.key == "Backspace" ) {
// 按的是删除键
if(keyword.endsWith(registry.searchData.searchBoundary)) {
// 取消默认事件-删除
event.preventDefault();
return;
}
}else if ( ! event.shiftKey && event.keyCode === 9 ) { // Tab键
if(! registry.searchData.isSearchPro()) {
// 转大写
event.target.value = event.target.value.toUpperCase()
// 添加搜索pro模式分隔符
event.target.value += registry.searchData.searchBoundary
// 阻止默认行为,避免跳转到下一个元素
registry.searchData.triggerSearchHandle();
}
event.preventDefault();
}
})
// 这个监听用来处理上下选择范围的操作
searchInputDocument.keydown(function (event){
let e = event || window.event || arguments.callee.caller.arguments[0];
if(e && e.keyCode!=38 && e.keyCode!=40 && e.keyCode!=13) return;
if(e && e.keyCode==38){ // 上
registry.searchData.pos --;
}
if(e && e.keyCode==40){ //下
registry.searchData.pos ++;
}
// 如果是回车 && registry.searchData.pos == 0 时,设置 registry.searchData.pos = 1 (这样是为了搜索后回车相当于点击第一个)
if(e && e.keyCode==13 && registry.searchData.pos == 0){ // 回车选择的元素
registry.searchData.pos = 1;
}
// 当指针位置越出时,位置重定向
if(registry.searchData.pos < 1 || registry.searchData.pos > registry.searchData.searchData.length ) {
if(registry.searchData.pos < 1) {
// 回到最后一个
registry.searchData.pos = registry.searchData.searchData.length;
}else {
// 回到第一个
registry.searchData.pos = 1;
}
}
// 设置显示样式
let activeItem = $($("#matchItems > li")[registry.searchData.pos-1]);
// if(activeItem == null) return;
// 设置活跃背景颜色
let activeBackgroundColor = "#dee2e6";
//let activeFontColor = "rgb(26, 13, 171)";
// 如果是搜索项,可用别的颜色
//if(activeItem.find("a").attr("href").indexOf("keyword") != -1) activeFontColor = "rgb(251,182,54)"
activeItem.css({
"background":activeBackgroundColor
})
/*activeItem.find("a").css({
"color":activeFontColor
})*/
// 设置其它子元素背景为默认统一背景
activeItem.siblings().css({
"background":"#fff"
})
if(e && e.keyCode==13 && activeItem.find("a").length > 0){ // 回车
// 点击当前活跃的项,点击
activeItem.find("a")[0].click();
}
// 取消冒泡
e.stopPropagation();
// 取消默认事件
e.preventDefault();
});
// 将输入框的控制按钮设置可见性函数公开放注册表中
registry.view.setButtonVisibility = function (buttonVisibility = false) {
// registry.view.setButtonVisibility
controlButton.css({
"display": buttonVisibility?"block":"none"
})
}
// 向搜索事件(只会触发一个)中添加一个“NEW”搜索关键词
registry.searchData.searchEven.event["NEW"] = function() {
let showNewData = null;
let activeSearchData = registry.searchData.data;
// 如果当前注册表中全局搜索数据为空,使用缓存的数据
if(activeSearchData == null ) {
let cacheAllSearchData = cache.get(registry.searchData.SEARCH_DATA_KEY);
if(cacheAllSearchData != null && cacheAllSearchData.data != null) activeSearchData = cacheAllSearchData.data;
}
// 如果最新数据都没有,使用旧数据(上一次)
if(activeSearchData == null ) {
let oldCacheAllSearchData = cache.get(registry.searchData.OLD_SEARCH_DATA_KEY);
if(oldCacheAllSearchData != null) activeSearchData = oldCacheAllSearchData;
}
// 只展示 newItems 数据中data也存在的项
let newItems = cache.get(registry.searchData.SEARCH_NEW_ITEMS_KEY)??[];
if(newItems.length > 0 && activeSearchData.length > 0) {
// 返回的showNewData是左边的(activeSearchData),而不是右边的(newItems),但newItems多出来 的属性也会合并到activeSearchData的item
showNewData = activeSearchData.diff(newItems,registry.searchData.idFun,0)
}
if(showNewData == null) return [];
// 对数据进行排序
showNewData.sort(function(item1, item2){return item2.expires - item1.expires});
// 将最新的一条由“新”改为“最新一条”
showNewData[0].title = showNewData[0].title.toReplaceAll(registry.searchData.NEW_ITEMS_FLAG,"[最新一条]")
// 添加“几天前”
showNewData.map((item,index)=>{
let dayNumber = registry.searchData.NEW_DATA_EXPIRE_DAY_NUM;
item.title = item.title + " | " + Math.floor( (Date.now() - (item.expires - 1000*60*60*24*dayNumber) )/(1000*60*60*24) )+"天前"; //toDateString
return item;
})
return showNewData;
}
// 将【搜索项】放到上面
function searchItemToTop(items) {
// 只有是搜索PRO模式 才干扰排序
if(!registry.searchData.isSearchPro()) return false;
let searchableItem = [];
let noSearchableItem = [];
let currentTop = 0;
for(let i = 0; i < items.length; i++) {
let item = items[i];
if(item.title.trim().indexOf(registry.searchData.searchProFlag) != -1 ) {
// 替换
let tmp = items[currentTop];
items[currentTop] = items[i];
items[i] = tmp;
currentTop++;
}
}
return true;
}
function searchUnitHandler(beforeData = [],keyword = "") {
// 触发搜索事件
for(let e of registry.searchData.onSearch) e(keyword);
// 如果没有搜索内容,返回空数据
keyword = keyword.trim().toUpperCase();
if(keyword == "" || registry.searchData.data.length == 0 ) return [];
// 看有没有观察者想要直接返回结果
let showItemData = registry.searchData.searchEven.send(registry.searchData.keyword);
let isSendSuccess = showItemData != null && showItemData instanceof Array;
//if( isSendSuccess ) registry.searchData.isSearchAll = true;
if( isSendSuccess ) return showItemData;
// registry.searchData.isSearchAll = false;
// 切割搜索内容以空格隔开,得到多个 keyword
let searchUnits = keyword.split(/\s+/);
// 弹出一个 keyword
keyword = searchUnits.pop();
// 本次搜索的总数据容器
let searchResultData = [];
let searchLevelData = [
[],[],[] // 分别是匹配标题/desc/url 的结果
]
// 数据出来的总数据
//let searchData = []
// 前置处理函数,这里使用观察者模式
// searchPreFun(keyword);
// 搜索操作
// 为实现当关键词只有一位时,不使用转拼音搜索,后面搜索涉及到的转拼音操作要使用它,而不是直接调用toPinyin
function getPinyinByKeyword(str,isOnlyFomCacheFind=false) {
if(registry.searchData.keyword.length > 1 ) return str.toPinyin(isOnlyFomCacheFind)??"";
return str??"";
}
let pinyinKeyword = getPinyinByKeyword(keyword);
let searchBegin = new Date().getTime();
for (let dataItem of beforeData) {
/* 取消注释会导致虽然是15条,但有些匹配度高的依然不能匹配
// 如果已达到搜索要显示的条数,则不再搜索 && 已经是本次最后一次过滤了 => 就不要扫描全部数据了,只搜出15条即可
let currentMeetConditionItemSize = searchLevelData[0].length + searchLevelData[1].length + searchLevelData[2].length;
if(currentMeetConditionItemSize >= registry.searchData.showSize && searchUnits.length == 0 && registry.searchData.isSearchPro() ) break;
*/
// 将数据放在指定搜索层级数据上
if (
(( getPinyinByKeyword(dataItem.title,true).indexOf(pinyinKeyword) >= 0 || dataItem.title.toUpperCase().indexOf(keyword) >= 0 ) && searchLevelData[0].push(dataItem) )
|| (( getPinyinByKeyword(dataItem.desc,true).indexOf(pinyinKeyword) >= 0 || dataItem.desc.toUpperCase().indexOf(keyword) >= 0) && searchLevelData[1].push(dataItem) )
|| ( (dataItem.resource+dataItem.vassal).length <= 1000 && (dataItem.resource+dataItem.vassal).toUpperCase().indexOf(keyword) >= 0 && searchLevelData[2].push(dataItem) )
) {
// 向满足条件的数据对象添加在总数据中的索引
}
}
let searchEnd = new Date().getTime();
console.logout("搜索主逻辑耗时:"+(searchEnd - searchBegin ) +"ms");
console.log("搜索:",searchLevelData,searchResultData)
// 将上面层级数据放在总容器中
searchResultData.push(...searchLevelData[0]);
searchResultData.push(...searchLevelData[1]);
// 搜索PRO模式时会干扰排序 , 如果不是前面的模式进行普通排序
if( searchItemToTop(searchResultData) || DataWeightScorer.sort(searchResultData,registry.searchData.idFun)) {}
searchResultData.push(...searchLevelData[2]);
if(searchUnits.length > 0 && searchUnits[searchUnits.length-1].trim() != ":") {
// 递归搜索
searchResultData = searchUnitHandler(searchResultData,searchUnits.join(" "));
}
return searchResultData;
}
// 给输入框加事件
// 执行 debounce 函数返回新函数
let handler = function (e) {
let key = e.target.value.trim().split(/\s+/).reverse().join(" ");
// 过滤
// 数据出来的总数据
let searchData = []
// 递归搜索,根据空字符切换出来的多个keyword
let searchResultData = searchUnitHandler(registry.searchData.data,key)
// console.logout("搜索总数据:",searchResultData)
// 放到视图上
// 置空内容
matchItems.html("")
// 最多显示条数
let show_item_number = registry.searchData.showSize ;
function getFlag(searchResultItem) {
let resource = searchResultItem.resource.trim();
let isSketch = ! isUrlNoUrlText(resource);
let sketchFavicon = "data:image/png;base64,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";
if(isSketch) return `
`;
function loaded() {
alert("loaded!")
}
return `
`
}
/* $("#matchItems").on("load","li img", function (){
alert("加载完成!")
})*/
// 标题flag颜色选择器
function titleFlagColorMatchHandler(flagValue) {
let vcObj = {
"系统项":"background:rgb(0,210,13);",
"非最佳":"background:#fbbc05;",
"推荐":"background:#ea4335;",
"装机必备":"background:#9933E5;",
"好物":"background:rgb(247,61,3);",
"安卓应用":"background:#73bb56;",
"Adults only": "background:rgb(244,201,13);",
"可搜索":"background:#4c89fb;border-radius:0px !important;",
"新":"background:#f70000;",
"最新一条":"background:#f70000;"
}
let resultFlagColor = "background:#5eb95e;";
Object.getOwnPropertyNames(vcObj).forEach(function(key){
if(key == flagValue) {
resultFlagColor = vcObj[key];
}
});
return resultFlagColor;
}
// 标题内容处理程序
function titleFlagHandler(title) {
if(!(/[\[]?/.test(title) && /[\]]?/.test(title))) return -1;
// 格式是:[flag]title(desc):resource 这种的
const regex = /(\[[^\[\]]*\])/gm;
let m;
let resultTitle = title;
while ((m = regex.exec(title)) !== null) {
// 这对于避免零宽度匹配的无限循环是必要的
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
let flag = m[0];
if(flag == null || flag.length == 0) return -1;
let flagCore = flag.substring(1,flag.length - 1);
// 正确提取
let style = `
;${titleFlagColorMatchHandler(flagCore)};
color: #fff;
height: 21.5px;
line-height: 21.5px;
font-size: 10px;
padding: 0px 6px;
border-radius: 5px;
font-weight: 700;
box-sizing: border-box;
margin-right: 3.5px;
box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 1px;
`;
resultTitle = resultTitle.toReplaceAll(flag,`${flagCore}`);
}
return resultTitle;
}
// 标题前面带“#”的titleHandler
function title井Handler(title) {
// 去掉flag
title = title.replace(/\[.*\]/,"").trim();
if(title.indexOf("#") == 0) {
let style = `text-decoration:line-through;color:#a8a8a8;`;
return `${title.replace("#","")}`;
}
return -1;
}
function titleHandler(title) {
let titleHandlerFuns = registry.view.titleHandlerFuns;
for(let titleHandlerFun of titleHandlerFuns) {
let result = titleHandlerFun(title.trim());
if(result != -1) return result;
}
return title;
}
// 添加标题处理器 title井Handler (优化级较高)
registry.view.titleHandlerFuns.push(title井Handler);
// 添加标题处理器 titleFlagHandler
registry.view.titleHandlerFuns.push(titleFlagHandler);
for(let searchResultItem of searchResultData ) {
// 限制条数
if(show_item_number-- <= 0 && !registry.searchData.isSearchAll) {
break;
}
// 显示时清理标签-虽然在加载数据时已经清理了,但这是保障方案
clearHideFlag(searchResultItem);
// 将数据放入局部容器中
searchData.push(searchResultItem)
console.log(registry.searchData.data)
let isSketch = !isUrlNoUrlText(searchResultItem.resource);// searchResultItem.resource.trim().toUpperCase().indexOf("HTTP") != 0;
let vassalSvg = ``;
// 将符合的数据装载到视图 //
let item = `
${getFlag(searchResultItem)}
${titleHandler(searchResultItem.title)}
(${searchResultItem.desc})
${searchResultItem.vassal !=null?''+vassalSvg+'':''}
`
matchItems.html(matchItems.html() + item);
}
let loadErrorFlagIcon = "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDIwMCAyMDAiIHdpZHRoPSIyMDAiIGhlaWdodD0iMjAwIj4KCTx0aXRsZT5hcDh6Yy12cm1kbzwvdGl0bGU+Cgk8ZGVmcz4KCQk8aW1hZ2UgIHdpZHRoPSIxOTQiIGhlaWdodD0iMTk0IiBpZD0iaW1nMSIgaHJlZj0iZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFNSUFBQURDQ0FZQUFBQWI0UjB4QUFBQUFYTlNSMElCMmNrc2Z3QUFIWjFKUkVGVWVKenRYUXU0SkVWMXZzUmdpQ1lLdmpVKzhCRk5RREJDZ3ZMNTJnQVNnV0FJNXFyTDNlbnFxYTQ3M1QzTDFTV0o4YTJicUtnSmo1QVk4a0dJSmlDSjhqSVFKUVlSQ0JCV1dJS0NLQVo1aU1ndVlGWjJlY2d1N0M0NXA3cm0zcDY1M1QzZFBWVjlxbnU2disvLzdtVjFvYnZPK2F0T1ZaM3puNW1abE9lSko1NW9NUUc2M1lXWkR2ZG5HQTltbUVENE00NEhQejM0TS9rekgrVGZnYi92Q3Z3OWxQL3N3TC9UeFg4djc4OXdIczY0cmt2K3ZYVkg2a1A5WW5VQjUzeW0wdzNCV1FHOG1KUHJSeWpod3UvZHJqK3pkdTFhOHZHcEMxb2lGSVRyd293c0ltZHpTSjArRHlKaTRtclNCZlI2UGZMeHN4VXRFY1pnQmN5cUR1K0I0MVBQOXBxZ1FpeGN3YWpIMWlhMFJFakE3T3h4VVd6UEIrR0dCUTVzQ0xoYXVHNjdVclJFVU1CNE9wcjFHekx6bHlTRjU2MG10MFZMQkFJSUlhSlFvYVR6ZExzTHorNXcvN2RoOVhnSGhCMS93b1IvTXV3ZHpnUkNmUlgrOTNXQVd3RWJBVDlUMkFaNFF1SEJ3Wi9EMy9rUi9QMmJ3Qm12Z1BjNUgvNzVkSWNIZitIeVlKN3gvcUdjaDY5eVhYZTNTa2lCcXdTTXlZb3AybXhQTFJGY1VjejVPZWUvMnVtR2I0SFllalhqL21ud1o5Y29SMzZpWXR3SjRkcEZnT05ody83dWJ0ZmZDMWF6WHpCRkNvZUhzRXA0NVBacWlhRDVZMlg0STNLRUNXNndweVBDVmVCc2Z3ZXo4M2ZnejdZVE9IMU8rQS9BejR0aE5mbG9Wd1FIOVhxOXArZ2xSSFEwN016UGs5dXdKY0lFaU9ML1VHMStrd0Zod0M4NnZQZEdJTXBuNEordnAzZnVpZkFva1AwYkVHSzlIMWF3L2ZXU3dvZEp3aWUzYVV1RWdzQ2xQYzJvczdQSC9iS003WGx3THN4NkQxdmd3S1p3SzZ3V24zTGQzajVhU2RHZ2U0bkdFc0ZOQ1g4d25vWlovMjB3czUzRmFHSjhhbndQUXlqUFcvMFNMV1RnUVNQMkVJMGpRcmZiVDd6eEZVSThWNFlLWG5DN0JjNW9BM1pnK0FRaDR5eUdoWk1TQWsvZVptZG55ZTAvOVVUQTlJR2t5eTlYaEsrSG4rY0FIclBBK1d6RjNSQkNmZ2htOW1kTVNnamNRMUQ3d3RRU2dZMWNoTUd6QzRRL1IrS01aNEdUMVFpd1QrTCthYzc4L0NzbkpjVEttdTBmYWswRTExMHpsUEVaeGYvaE1SQzMza0x2VkxYRzQ3aUhjbDMvMXljaVJJM3ltV3BMaE5Fa09GamFENEdmTjFqZ1JFM0NEb1poWmEvMzh2SmtxTWZxVURzaVlCRktuQVN1Q0ZiQXovVVdPRTJUc1ExVzJWTW0yVU80d3U2OVE2MklnRm1TZzcxQXQ5dC9VWlRURSt5MHdGR21CVC9EazdmWjJka25seUtEeFNkTHRTRUNsanJpcVZDVVBoQWV6L0QybE40eHBoWGZnd25wNERKa1FEZ1doa3JXRTJIRllucTBQSnA3TStCL0xYQ0VGaEhPZ2ZqL1dlVUlZVmVvWkRVUlZzcTdBVXlBVzdPN3l2aHN3eUQ3c0ltSnNGZUdESGp4U2UxajFoTUI4MWdjR1ZkaU9vVE01NmMyZUlzc2lPQ0NVcXNERDZ6WU4xaEpCSWRqaHFPN204b0UzVUZ1NUJaNWNhOHIvTU1Ma3dIMmZxZ0cwaElodmhKd1dVTzdEOFNRTjF0ZzJCYkZzZFAxd2hQTG5DdzVEbDJacUZWRWtDZER3bC9aOEpUb2FjRjZwOWQ3Y1ZFeWNIN3NkQk1CTXlCVktFUnR3QmI2Y0gveFk5WndwaVBFZEJKQmJiS3V0TUJ3TGZUamNjY0xqczFIZ2lWVXJhWkJUZ1RNWTRHQitvRUZCbXRoRWp3NEJmWU5UeHBIZ0RpcURKTklpZUJ3LzBBbWwwOExETldpQW9UL2dXb2dTVTZmQmhSVGJqUVJaSzJ3RjJ5bE4wNkxpbkd0NDZ4K0ppdEFoaW8wVzBtSUVKME1ZYzQ3dVZGYTBPRDdFUGE4Z0JVZ2crbEx0OHFKSUpYYjJrdXlGbDU0UjBlSWx6SkwwakVxSllMTC9RWFc1Z3VaeGxad21xOHhFYndIa3hRZEovaTFZOEp3RHhRdjZIWjcrN2xld0pVazVRTVd2T3VkaGRRMGhEa3lWRVlFeHdzRmEwbGdFdmVnOWlyRTAwL1BOU21oamlxRXFFckZqL0s5YnlzU0ptRk5RMjJKQUJ2ak9kYUdRNmF3RlFqdzRZV0ZoVjhxNlFDN29MUWxvMDFzL0I2S0tlY2hBcFBIcXZySllKd0l3T0NqV0xzeE5vVnJPNkwvbTFyczVLN1pIVmFIZjJSMHEvWU51SnJsSVFMdUYrYm05QjZyR2lXQ085Ly9IWGp4Unl4d21NWUI0M3lVck5ROU14SVhQMTJlTjFsUGQ0aGtqQWl3ZkwwTVFxTDdxQjJtZ2RnT29WQ29td0J4Uk9Xdy9pY1lRVG1zV3BWeWJwNzFrY0VJRWFUYVFhc3RaQUpiWGVFZmJaSUVRNnVEbEhIQlhnd1ZmeWZzZWZLU1laWFh0NU1JTXAra1ZaZ3pBRlNoNng5YUZRbmlRUExCTzJ5bzhIdDNxcjFsWlRmUDJvbmc4T0RUOUU3VE1Jamc1OWl0aDRJRUErQmRSTVdiNlMzWUxpc1BFVndOOXd0YWllQUkvdzhxSEtocHdXT3dHaHhCU1lJNHF0eE1ZMWJ5M056QzAzS1JZY0pWUVJzUmxFN21GZ3NjcDBuWWpyTHQxTTQvaWs2bjgxUjR0MU9yR0FQNC9pL2xJUUlXOUt5ZG9QbWhGaUpBakxZcmJJNnZzOEJ4bW9UdFRJUmRhcWZQblB4UWNOa0xIakkrRmpBT2Vjamc4dkphU1ZxSWdHMkpMSENjSm1Henc4UERxQjA5RHpwZThHcDQzN3NNajhlRHE3eitLOGFUd1M5ZHZ6QXhFYkFCSDdPNjQyVHRjQnUyaktWMjhDSlkxZXM5bjVsWElsOHZJdzlEZHdzVEVTR0tGY003TEhDZXB1QlN2SU9oZHV3eWtPa1Joc05qN1AwMmxnaVlnbEdDREJNUkFmNmpKMW5nUEUzQUR0UUNRaVVQYW9lZUJFbzIva2FENDdUVjdmVitZendaaXU4VlNoUEI4WUlEV0JzU2FVQjRCL1VkZ1U1MGd1QTU4RjAvTkRoZVYyRm5wSEZrY0FwbXFKWWlndXJDMkhhbm1RdzdVZGdZaTltcG5WYzMxRVhZWmxOajUzSS9HRWNFUkpHOWJpa2lZQUdJQlk1VVkvZzNZNnNyYW9jMUNXYysrSDFtckFiRmZ5QlAvWUxEODk4NEZ5YUNXdnFNc2IyaHdNYm1HQzZjaHc0Q3c3c0x0YU5XQWJXNU5UT21Jdno3Y1VSQTVMMWtLMHdFMWFlQTJyRnN3K095NUZHRVowVEx0bit3SThKOXNWNjRiT1ZZRTRBSm1FQ0dLd3lOK1hZYzQzRkV5TnU3clJBUk9QZGZ3OW9OY2h6cjBQR3h1b3ZhNld3RjlycGoyRXpFeVBqN2w0MGpBc3NaSGhVaUFpcVZXZUI4MU1DSjRBdTZTaVNuQVNxTjI0Zzk4QVorSEJuY0hQY0t1WW1nYnBDcG5aQWExN0w1MVh0VE8xWWRBYUhqMllac2NqM3V1YkxKb0pFSThDKzgzQUpISkFOSzFzdVkxN0ltZUhXQmtubTgxNFJ0SEI3OFlUWVJzUGxNdHQxeUVVRjF0U2QzUmlMc1VPcDhha0R0YVlCWE55aTlXeE0yK3U2NFN6Wm56S1k1RnhFTTd2enRod2hYeHdlMENrSGFKb09KNE1zbTdLVDJJWm1yd3NKQ2VtYnFXQ0lvU1JaNmh5UWhRZkRGMGNHMG9RTmtuZUc2L2VjeEUvZFFVY0pmZG5qa3BhL21ZNGtBLzRKenlCMlNCZytwSkxLaHdleDBPdVRPVkhjd3ovOVRFelp6UmZpbUxDSmszVFJuRWtHcEZVL252WUVJejBnYXpHNVhqM3pJTkVQbXFvbmdKdjEyazlJejJXa1hUaklaTW9rQVM4bGZrenNrRVZ6UFB6SnBJQ0ZVSkhla0prQTFHZFJ0dDUycWRqNmREQ21LRjZrUHlna3lZemVDOXNOMWd6MFRpV0JJalhrYUFXVDRxbTY3T2NML3kwd2lwT3dUVWgvSEN4bTFNMUlpclN5d1NFWmppMnlvZW1mZG9mZjltTitWUllTa2pwMnBEL3lGZGRUT1NJbDBNZHIyUWswbmxHaVlWdHRCU1AvdUxDSWtkZDlKZkJSVHlaMlJFa3E3SjNFZ3V3WTd0MHdibkY3dnhUQ20yM1RhRGxidGIyb2hBdXkrajZkMlJHcW9yTW4wd1p5ZkozZWlwb0J4Ly9PYTdiY0RVK0JUN1Nmd1B1aTRzVVRBQktiYnFCMlJHdTU4LzdleWlCQWhyTFFwZGxPaFNqdjFWclBKSG5KWmwydkRJZTZ5WjZwdmt1TkU4TUxaOFVRWTNqc3d0ZXhpWGdzV2p6dndaM2pLaEduQWFlZlhMU0pBWFA5dm1tMTR6VGliWlJQQkMwK2tka0lib0ZTOUN4QWhQenJkTmw5cE9SSGt2WTFPRys0YzE3RXprd2pNcUJSSG5lRGZiSW9JQStES2dRKzFFOW9BcFl5aXRRY0RyTTdIWm8xL1BJRnllRFdJYnVVc2NFSTcwQlhCUWNiSm9NS3Fic0lHYnRxZ094cVIvYWF6OWdteDA3L2gxU0RhWUpBN29FVzQyNW1mZjZWcE1peUhML2NWMDVicGloMkJ0TnBQQkQ5WEdSTEprMUJNQkd4NFJlREIxeTF3UHR1d2hYbmhSNG8weFRaQkRCUzNiWG9ZRlRVeDFOdkFFUFllYjBzZFY1NndJc2hyYVdDUUJZNW5LN0FUME8xS09lRWNXSFpQeDd3V21GVSs1SGgrSDNzRllCcHc1dm0xRG9oUVNwUTBOWXlDYjd4U3M5MU9TaHZMK01YYTR1TncvMEFMbkswcEFNSUVwM2E2dmRkcGNmNUVRcWc0RjFhTEZSTjBpckVOS3YxZHB5MnV6UnJId1lRUzN4KzBNbzVtY0FQMmxwc1pxN1F3R1RBWjBIWHJueUtPSzZ6bThYOU1oVnlwSyt6d2l1Q0Y1MXZnTkkyRlZNTHovRS9nU1ZUV0JtNVNPRjV5TGsxZDRJaHdsZTZ4ZDBXd0ltMjhCdVdiOGZ1RGpkVE9Na1hBRGVIbFFJeVA0YjRpUGROMUFzQUt3UXRLbzlzQUpjMmlkYnpWS3BNeVZ2NFNFZFNKQ0xWelRETWVBVndDUnZrZ0xOWDc2dzJqL0ltNlRWWlBCS2xjcDNkOGVYQnU2dmp3R0JFNjg4SHZXZUFNTFphd1FRb0tDLzlvSFdGVWxucURiVEJSd29uOW10UEdabEJvcGU0UHd2ZFpZUHdXU1lpT3RNL0JYQnlWaGxDS0RERFprVHQ1SHFoemY5M2p1RDFyUWxra0FzdysvMHh1OEJaNWNBL01ZQjlYMmtDTlhCVVlEOTl1Wk93ZzVFd2JteVVpZU1IMUZoaTVSWDVzUTFGZHdHdlRqRHVLK2hBaGVLZUpNWVB2NzZTTkRXcFZEWWp3ZnhZWXQwVng3QURIK1JmT3c1ZWxHWGtSSmZzUFYwNkVTR0xUd0ZqNUgwc2JHOVNxbXNGbWRoWVl0TVZrMklhR3poTENyVU1sbmV1NmVJcnpPU05qRkpXREpxK1c4LzIyVUw5SmdPWC9uNUtOYmJmeVJzZUxhak1Va2U4eU1UYlpCZjMrektEN0lia1JXK2lCT2dvZlBpSzBqQWdRaGNqRVFUekRIM3BQNGIvTDROamNQam91QTJDK0ZzWmtQV3JqdGRBSEpkTTVaR2hxS1h2WFhTTm5mQ2I4bEJrNWlHUmRlSENmd2JGNU5PMi9qYmZ3V0tYekFXcmp0ZENIWlVUZ2RLdEJ0eHVKRjZRNjRHQkdkbnY3T0Y3d0k5TmprNnBWaFNXendJWVRxSTNYUWlORTJCMHlNdEZxZ0tkVWlVNDNSQUIzTjVpSTE4THZXNnNZbXpTdEtoZFhCQVBpU2kzb3NETmVTVWNoV0l6NS9Vbk94a1lJb0xSMWI2MXlmTkswcWlRUkRPakp0Q0NELysyNGdic1Z5OFpndHV0QTN5a0plRUtwMUtxSjdxMWtIbFBpSFF2K2NnbTlBVnZvZ09QNTc0MGJ1RW9TT1BQQk1oTGdIWlVyL01QVjNjQ2QxT09UMXZOaXNGbStndm9GVzJqQmc3MWU3K2xMeHExbWt4eGxKdmdxNUZtek8xYmp3ZWJ6WkJhbDdkalZiU25xNnBsd2ZCcXRDTmVRdjJBTERVYVdzKzZpY1dmNzVzczJjVC9neUJETTN3dWM2VXVzb2sxdmFRaC9KVXNnZ2hSYVkyM0NYUk93bmZWNkwyY1Zoa1dvNVlvaGhicUgwaXJyYmdxd0tYWlpBaEV3UlIxL3VaSDZCVnRNYU9Cb05vNFoxK3hwRVc3Q1ZYNy9GNmkvdmRBNHhSckh4eUZ6alpnSS9vZjZCVnRNQm5ETS9VYU5hMHIzQ05YaG9teFhlVUpGL3UyRk1IckhFcnRyd1YrbXVrVlVBN0JPYWh5SndWSGcwcEdnYnNsSXh2c3FOODEvd0lMdkxnNGV6TEhFZTQwMWtnaTZsY1dvc1JNekRWM3VMK0FGQ2pZRlBDWU05NWdUNG9WU0lRRnYwa1h3RGZqLzNXL0J1Mm93cnU4TmIyQm5wYml0TkxCQUkrdlpMMFNDQXY0SG1lNkdIaFVpcmVmRm9Dam5VdW9YMUlTTllQaFA0YVl4cjNHRkVNL2wzSDhOMXNsaUJSTktOenBlK0g3Wk9vc0hwNmdTMW90VkdHQ2ozTTBqcy8zK3J5U0dNUEVVaHdLNnFaaWdoNkVDa2dnM2tYaTBpUHNCcklpejRIc25nanphVFNDQ0pMcUpYcmVWZnB3WC9BQ2NWNkIycThrTjRvQTRRSklqd01uK3huQ21aRjVjbmhuS2pKeVZZM3dmbDRmRWs1OUJVaHltR1NRNWlkUnk1Y0YxRm56cnhFaEtVV2N4SXB4Ri9ZSWxjUU9HT2xqTVlab0FLVFBucnJDSzhDcXlKdE1SWHBTWENHV2dOdUZhbTNkUVFyVkZXelpCU0NLb3RGM3lsOHdMcVZIRGczZGl6RXBCZ0ZISUJMSklTZTBoZ3ZHNEY4T1dwUGRhaFNIT0JDU0Fiem9FZmo1SWJXK3RHTGxyWWQ1U1U4RVpWZFJNLzVJNWpJNGJROVQyb1hiK0ZNZDdQZ3pxWitBOWYxend1NUJBRzVRSTFmVUtWOHNOZlJ4ZWNHSHM5L1dMRXY2d2o0RU44cE9XclFZcG9VNHVSQTA3N0w0bExnRk1BVm4ycldJUUdobFREZENHeDNIamluazAxTTZlQnhpcXVXNndKODZvS25RNkZqZmdDSG1TNVlYSG9CQXd0dW5DMWFUc2Z3ZWRYNG5iM29yNVl2amZIQ0pDU1JKZ2tReUVYQTliWUhmdGZwUWtwVGxvSGorampwU29YeklONjJCanVpKzFjOXNNSEI4MVZsdnd3bWdRTW81emVOempZS2lBWk1KTkpQcUI4b1ZUQVk5WllIdmQySkEwRHAxQUVRRm1yQU1zZU1sUmJJZFo2Yzl0RFlOc0E0dmRpWUF6Znd0WG83ZzhKSjc4d0o4ZkJiOS9VclVIdTR2WmxobHFIdXVTaURBWVEzVWtTUDZTaTFDbk1HOFlmZEVXbVVUWWxEQ1d1TkZGNVlaV3ZNMUx5c2NhSVlLTW0renBuYllPbHFybnhGOTAyanBMRmdWdTBpMndtL1ZRQnhtWlJNQVRobHVvWHhSdmIrZm1GcDQyK3FLcmlLVkliSWNwcmRER1FRVGhNaUtNZHRXMG9XNVpiZm9TenJOYkltUVN3UXYrbHRwMmRVQlM4M2k4V1I4aUF2YjJJbjdSVFVra2tDOUxvTVJRSnpDWkMwWHZhTFpqTk9SbUkvdlBxSkdnV2FtOVBOaVNSb1RSRjI0eERCWDdranVhNWJoM21WK0pCQ0pnelNueGkyNUxKWUlJR3Q5eGZpSWlSRTFEa2s2TldpemgwbEcvR28wMDVLUE9uQitsZkZtOEtVMGpnOFBiVlNHVERNSi9LOE1iZUhxSHN4VW5qZnJVbkJETGlSRHRFOEtyS0Y5V0hRT21oRWUrc2RMRHBrQVYwZSswd09uc1EzU3lsaG9XalJBaCtDemx5enE4OThaMElrUk50T3ZVSnBVQ21OZlVraUhCdDdDbUl1NUxZcm5tMCtLanFuZm9YamJTd3N4T0NBT3NhTW1RQ1pmN0FhdHhPYVVCM0xuTWo3SldoSlc5M3JNWTdXenlEK09JTUFBMm1xQjJPSnVCR2E2czNUTkVFTUVYUi8wbktWdGg2SUZZL0diQ0YvNUo3bzd6WEY5UmVsT2h5REQxS3dPVzhjWjl4MGxwcWpoQ2hQQ3ZTRjhhVlNaeXJncURqOEtOOU56Y0FybmoyUWhXTXdFdUUwRDFrbEcvR1VzRWRRMU4rT0wrelZrZDBuT1JRKzBsVU8wTkZacXAyeWFSRWtFRUYxQTdJaWxFY05Pb2Y2VGRTUTA5RURzOW1SSFhxWUlqbjVuVkpyVWN3cG1GaGVsYU5Wd2VyaUYzUkdLb1hneER4L0JwNDdYc3NXRVd3VGFwOGNJU1hjamFaTE5Zc2J0VDg5TXAxR2xpMDFkNHM5eVBvbExXUmJ0NjN1b2lSSkRTMmVRZkFiaEVOVVBYUmdRWk5zMHZ5YVd2UkNHcmxHWjNxQUZFN2RCbHdIbjRxdHBLTXVyRnh0RnNoYXh4Vy9hZ2NocjhwVWNzK0JDOEVid09pOUoxa2lGT2l1ei9qMTI5aWZOQUdmNEdjcnRaQUNuQ0ZyZDN3aVZhSmhHaTA2UGdIT29QaVdGTDlGSCttNU1LZDB6QkdUT0QyQWhYK0VkYllDOWJzRmp1bXlmVVRYd3NIbEM4OEx1SG9jcWRGM3dOOXhLd0VmNElLalQzZXIybjZDUkNIVmNFR0pQVExiQ1JEYmhyNkU0cTRTWTVGeEZRUjVUVlR5MzZJYndIVWUrdVpVV29XNzIwRXYraXRvTUZrSVZtaTdic2REcmxpSUNQT25xeTRLTUs0K3JNVFhZays0Y0podXR4VlJsM09rWHQzSVdJMEJDeDNnbXh3L05XdjJUSmh2bFc5dFFIbGRoWVRUTVp3Y0cvRXhkOHhUd3FKVjZGWlkxRGFRY09Edy9MSWdLZUt2R2FuQ0NCMFMrakhuc0xjUEdTL2NKRkFhL1NSSWdHdHZhOUV6WW9uYVFNUWt2dDExeDdCdHNKQWU5NW5nVmpUb3A0RHdTM3dENHZrd2dxOTRmODQ0d09YTFRCekwxM2NIbitwaHNFUkpocVJRdWM5SVlWL3RJdjBBb1JRYVU2ZkovNkE4MUNOa29wdHBrV2R1WXd1U0w0QVAxNEVrSUU3eG5ZS0tubW9EUVI1Q3dUbFFEU2Y2UWg0Q3lTVlMrZENtNmZxQURqdmtNOW5vVFkxT2wwbmpxd1Q5R0phaXdSVUxxY1JYSVkxQjlxRXNlbE9ueFdtRFRtdHJKcU9DSmNaY0ZZRW1IcHlOVGx4ZTB5bGdoeXBvbTZLVnJ3c2Nhd0UwVmlvenlkQWtTdzdIZ1Z3b0dQV2pDV0JBZ2ZqZ3Q0bGJuL3lVVUVsWDlVdHd1Mk10aU9QZVdpaHRvNWlPRDJ0VGl3THNBN2ZkZUNNYXdjY1lGZmg1ZXpTUzRpeUdXWCszOU0vY0VWNGhITTU1OFpVenBLN2ZoRDlpRVdYeURFWnNkWi9VeW05bTFseHk4M0VWVGwyRDBXZkhoMUVNR1gwM0tZOGx6YlZ3VWx2SEEzK1hnUkFNTEJ0VXpkODB5aW5KNmJDQWdsRlVMKzhaV0NCLzgrdWpLNEtRWGdGRkJIM05NcUJQeFQ3SzBuYlRLaEdtSWhJc2pMaXFnT2xIb0FLb1dTVkZ4TXVhQjIvamlVcUJmNUdKSFlKWnFZcFYzU2ZOWUlFUkN3QkIxTVBRQ1ZEN2dYY0J6c0tDUFZIdWxKRmE1dW5PejdzSnJOL3dyOC9xK0FhMWw5RGtWdUhOei91TzdreDlpRmlhREk4QlVMQnFJcVBLb1VwN0dNbGR6NWgrd1E5VU11LzIzYy81emNBNDJFRmJLdkhnL2Z6cnp3K0NpUno3NTJzdzd2LzY2MFNZazdBMzFFd0ZSbWUvcXVtY2Fpa3JKdFlSRjJIcDNndXo2NytGMWowaEdpUzlYd0NGZ1J6MlkyaUlieDRGeW0rZVN1RkJFUTJFQ2JmRURNNDdiNHRUM3o3Q3JoaE5uNlA4dDlWM2pWVUZwSmdieWNxQ0c1YkU5TFpCUC9nWUZ5dXVkNTlFU0lzdno4YjF2Z3JLYXd3eFhobTlqSXNhbWoyUUNURVNINGFZbnZlckFqeEV2WjBDbFlNWEl6RWU1UFpSZVhCL1BTRHBwQ29vbUpFQnVRUm9yTlFoaDA0aWdKRnNrQU1YVzNTeXNZcHFxd1NuemJjQmtqSzdIS3FTTkxDcnY4MTR4c2g2dy9SSjJJQ05Hc2hCc3Flc2ZWaVNnamRiejBaS2RMdDJjb21XbjZhRkpUdmFKRWNIaDRDSUZkSHNLcVNWT2g2Y1JFZ05saFYzako5ZFRPcXhYQ1Aza2NDWllRWWcrNjZvbFFSbkludHNrY3hTb3ZmNDRPM3JoWGJoUHVlOHpnOGZYRVJKQXp4UHo4SzIwOFlpc0x6RVROVDRUQmhoTUpVVTBTbnRLbzNWTDR1NkxDblpSdnlFZm1UcmYzT2xiOXlkRjVqdUVrUnkxRWtHU0lkT2pKblZnVEhvZUJQNkF3R1ZBK3NvTDBDOVJ4S3ZWZHNRcXVKSXduSUlTTDFXY1czTzE1M2pQWWZQNnlTMUlpUkdRSXpyVEFpYlVBOXduU0FJWEpVT3c0c2d6S1htZ3VKYWlsSEFKa2tBRnZid2tFeExZNTNEK3dDaDFhclVUQVcwcVVVcUYyWW0xazRNRi9kN3NMenk1RGh0bSttV1ZjM3ZwNndXT2x2aWU2RU10ODc0RmlOQ3Ayb0Y2bzdFNkV2U1lvVm53UnJoNm5XV29sRWRRQVlsSEx6NmlkV0NOdTczVER0eFFsZ3FsYmFKZ2RQMVQyVzVTMFRXRlNLM24xYlZXT08wWVhvMDNCYTBVRWhOTG5iOWo5UW5oUnQrdnZWY1NCSmgzSFVjZ1luUWYzVGZJZHE3eitLNHA4ZzlvclZkMDhaajErYTFVa01FWUVTWVptMWk0OERzdjFHZDF1LzBWNW5NalZITnRpcURENU44ajY4N3duWVhoaHVxbktNY1pWQzVNY3F5U0JVU0pJd3hFM0p6U0g4R0hsbE9OblZLNUgvd2huU0JYYVRQcitOK1o3YnludTlsREZZN3VaemEvZXUyb1NHQ2VDcXA2eXFkZUNYb2pndzNtY2FwSVN3cVZKUlVwVGFubHZJTlJyMDk1VjNkNmVUVENlMi9ER21vSUV4b21BUUpsMmx3ZGZKM2RhTTNoRUtYeU1JWU0va2NTOHlpdlMyY1hvbW9GaU5CNXVPTUovRit3OVRvQU4vcmNZamZEemRuaUhQNklpUVNWRVFPQ3hxaXVDS3l4d1hPMVFqYjF6eGR3bERiUUwxazFUZjZkQjdIQzhrRkdTb0RJaUlMQm5nWnB4cUFkZU42NmVHU1A3TWtEUm9uOXNpY3NpRlQ3cWJ6U0ZuWTduOTZsSlVDa1JFQ3A5OTJvTERLQVZMZy9mbDRjSW1JSXhONWN2ZlJ2REtkWGpvZEx6KzRwSjhGNXFBcEFRQVlFeHRjT0RiMXBnQ0oxNHpPRzlOK1lodzdnMFl0ZGRJMjl6VldlZnB1cEliYmNoSENJbEFpTHFjOVk0QVlDTmd4TENjVUFOSHB6eE1VRVBrOGxrSGc5WC8reGgwUS9lVTRSM1dQQk5KckNOZW1Oc0RSRVFzbzZCKzUrM3dEQWE0VjlXU21JK3ZtTElsUGJnaC9UZllnU2JLWTlJclNUQ0FOZ2VsdFcwVjFzS1BsbWFDRkpDSmRoc3dUZVl3RjBkTDNnMXRjTmJTd1JKQmg3TXdVQnR0Y0JZT3JBOXFlZy9DeGdxcWk2bVRab1E0cmdldzBacVo3ZWVDQWh3bnRlenhnalpobmZNelMwOExSOFJwSEpnZytYYy9iUHdIb25hMFd0REJJUXFMTCtjM25pVFkxeVRRdGRkczN2RCt5SnZRMTFXYWdldkpSRVFVaStKQnlldytvY0pHMXdldUhMR3h5ek8rZFY3eXp3ZTdoK29Fdlp1dGVBZHpVQUVQNEdmYjZCMjdsb1RZUUFsR2RMVWMvVG1RZ1FYWU9NT2F2OXBEQkVRcWt6eVFuTGp0c2hEZ0ovYmRGUGNLQ0tvRjl4RnlmdzE5Vml4Q2JnUzd6K29mYVhSUkJoQVNiTTN0N2FobnRpTXF3RFduVkQ3eDlRUVlaRVF3ajlhYmNhb25XQ3E0WGpoK1p3Zit3SnFmNWhhSWlCVWZjUGFLZXJSWUE5NGNJdkR3OE9vZmFBbFFneHpRcnhRaVlyVi9haTFEdGlFWVJBZWIxUGJ2U1ZDQ3FRZVo3T3J1QWdSUG93TnZZOEp3ejJvN2R3U0lTZkFjRytJZW41Uk8wOGpzSlZ4L3pSVTFxTzJhMHVFMG9UQS9KMnliWldtSGRobE16eWVRbHVvSllJaE9DTGNWKzBoU21tRlRoazI0Z0VFNWtCUjI2MGxnaUhJVFRVUFBnN0cvckVGRG1jVGRzaVZrd2Z2d0VJcGFqdTFSS2dJV0QwVzlSWUlMMkxUdlVyY0F4UERwMUhUaU5vbXRtQnFIendGa1gzSW90T21oZ2tXSjJJVGhvbXU1eCtKUjZEVTQ5OCtGajR5ZlVPRVBjeWNaTlVyUHhzRE9QNFBzQitjSy95M3RzN2ZQb1VlN0UvV0ZjRkJlSGFPalVKWXZVcElOMkREUUJUTndyQ0hlaXpicDBHUDY3cTdLYzJpUDJPWTlNZURXNWdkb2RSbTJPdGNCVDlQZGIyZzB6cCsrMVQrWUxGOXQ5dmJ6eEhoS25VYTlRVjFrWGM3MDZwTTV6K2dXbkZkQ0FROHhlWGhHZ2h6RG5kNnZSZFRqMEg3dE0vWVIrcTh1c0dlc2tTVDl3OTF2WEJXQWtzMzVWNGtEbitsK3QrUGt1b1hzcVN6L3p3TTBhaS9ZNXFlL3dmaFNwMGVHdnoyYkFBQUFBQkpSVTVFcmtKZ2dnPT0iLz4KCTwvZGVmcz4KCTxzdHlsZT4KCTwvc3R5bGU+Cgk8dXNlIGlkPSJCYWNrZ3JvdW5kIiBocmVmPSIjaW1nMSIgeD0iNiIgeT0iMCIvPgo8L3N2Zz4=";
//let loadErrorFlagIcon = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB0PSIxNjc1NzkxNTQ0MDA3IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjgxNjUiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCI+PHBhdGggZD0iTTMyIDQwNy41ODRhMjc5LjU4NCAyNzkuNTg0IDAgMCAxIDQ4MC0xOTQuOTQ0IDI3OS41ODQgMjc5LjU4NCAwIDAgMSA0ODAgMTk0Ljk0NCAyNzguMTQ0IDI3OC4xNDQgMCAwIDEtMTEzLjAyNCAyMjQuNTEyTDU2Mi41OTIgODkyLjhhOTYgOTYgMCAwIDEtMTI0LjQxNi0xLjk1MmwtMzA4LjE2LTI3MC42ODhBMjc4Ljk3NiAyNzguOTc2IDAgMCAxIDMyIDQwNy41ODR6IiBmaWxsPSIjZDgxZTA2IiBwLWlkPSI4MTY2Ij48L3BhdGg+PC9zdmc+";
// 给刚才添加的img添加事件
for(let imgObj of $("#matchItems").find('img')) {
// 加载完成事件,去除加载背景
imgObj.onload = function(e) {
$(e.target).css({
"background": "rgba(0,0,0,0)"
})
}
// 加载失败,设置自定义失败的本地图片
imgObj.onerror = function(e,a,b,c) {
$(e.target).attr("src",loadErrorFlagIcon)
}
}
// 隐藏文本显示视图
textShow.css({
"display":"none"
})
// 让搜索结果显示
let matchResultDisplay = "block";
if(searchResultData.length < 1) matchResultDisplay="none";
matchResult.css({
"display":matchResultDisplay,
"overflow":"hidden"
})
// 将搜索的数据放入全局容器中
registry.searchData.searchData = searchData;
// 指令归位(置零)
registry.searchData.pos = 0;
// 设置li样式
$("#matchResult li").css({
"line-height": "30px",
"height": "30px",
"color": "#0088cc",
"list-style": "none", //decimal
"width":"100%",
"margin":"0px",
"display":"flex",
"justify-content":"space-between",
"align-items":"center",
"padding":"0px",
"margin":"0px"
})
$("#matchResult li>a").css({
"display":"inline-block",
"font-size":"15px",
"color": "#1a0dab",
"text-decoration":"none",
"text-align":"left",
"cursor":"pointer",
"font-weight":"400",
"background":"rgb(255 255 255 / 0%)",
"overflow":"hidden",
"text-overflow":"ellipsis",
"white-space":"nowrap"
})
$("#matchResult .desc").css({
"color":"#4d5156",
"overflow":"hidden",
"text-overflow":"ellipsis",
"white-space":"nowrap"
})
$("#matchResult img").css({
"display": "inline-block",
"width": "22px",
"height":"22px",
"margin":"0px 7px 0px 5px",
"box-shadow": "0 0 2px rgba(0,0,0,0.5)",
"border-radius": "30%",
"box-sizing": " border-box",
"border":"3px solid #fff0",
"flex-shrink":"0" // 当容量不够时,不压缩图片的大小
})
}
// 简述内容转markdown前
function sketchResourceToHtmlBefore(txtStr = "") {
// 1、“换行”转无意义中间值
txtStr = txtStr.replace(/<\s*br\s*\/\s*>/gm,"?br?"); // 单行简述下的换行,注意要在"<",">"转意前就要做了,注意顺序
// 2、特殊字符 转无意义中间值
txtStr = txtStr.replace(//gm,"?gt?").replace(/"/gm,"?quot?").replace(/'/gm,"?#39?");
return txtStr;
}
//简述内容转markdown
function sketchResourceToHtmlAfter(txtStr = "") {
// 1、链接变超链接,这里必需要使用“先匹配再替换”
const regexParam = /[^("?>]\s*(https?:\/\/[^\s()()\[\]<>"`]+)/gm;
let m;
let textStrClone = txtStr;
while ((m = regexParam.exec(textStrClone)) !== null) {
// 这对于避免零宽度匹配的无限循环是必要的
if (m.index === regexParam.lastIndex) {
regexParam.lastIndex++;
}
let match = m[0];
// 为简讯内容的url添加可链接
const regex = /(https?:\/\/[^\s()()\[\] `]+)/gm;
const subst = `$1`;
// 被替换的值将包含在结果变量中
let aTab = match.replace(regex, subst);
txtStr = txtStr.replace(match, aTab);
}
// 2、无意义中间值 转有意符
function revert(text) {
let obj = {
"?lt?":"<",
"?gt?":">",
"?quot?":""",
"?#39?":"'",
"?br?":"
"
}
for(let key in obj) {
text = text.toReplaceAll(key,obj[key]);
}
return text;
}
txtStr = revert(txtStr);
return txtStr;
}
$("#matchItems").on("click","li > a",function(e) {
let targetObj = e.target;
// 如果当前标签是svg标签,那委托给父节点
while ( targetObj != null && !/^(a|A)$/.test(targetObj.tagName)) {
targetObj = targetObj.parentNode
}
// 取消默认事件,全部都是手动操作
e.preventDefault();
// 取消冒泡
window.event? window.event.cancelBubble = true : e.stopPropagation();
// 设置为阅读模式
// $("#my_search_input").val(":read");
// 获取当前结果在搜索数组中的索引
let dataIndex = parseInt($(targetObj).attr("index"));
let itemData = registry.searchData.data[dataIndex];
if(itemData == null) {
// 索引出现问题-启动后备方案-全局搜索
let title = $(targetObj).find(".title").text();
let desc = $(targetObj).find(".desc").text();
itemData = registry.searchData.findSearchDataItem(title,desc)
}
// 给选择的item加分,便于后面调整排序 (这里的idFun使用注册表中已经有的,也是我们确认item唯一的函数)
if(itemData != null) DataWeightScorer.select(itemData,registry.searchData.idFun);
// 如果是简述搜索信息,那就取消a标签的默认跳转事件
let hasVassal = $(targetObj).attr("vassal") != null;
if( ! isUrlNoUrlText(itemData.resource) || hasVassal ) {
// 取消默认事件
//e.preventDefault();
matchResult.css({
"display": "none"
})
textShow.css({
"display":"block"
})
textShow.html(`标题:${itemData.title}
描述:${hasVassal?'主项的相关内容':itemData.desc}
简述内容:
${sketchResourceToHtmlAfter(converter.makeHtml(sketchResourceToHtmlBefore(hasVassal?itemData.vassal:itemData.resource)))} `);
textShow.find("img").css({"width":"100%"})
/*使用code代码块样式*/
document.querySelectorAll('#text_show pre code').forEach((el) => {
hljs.highlightElement(el);
});
return;
}
// 隐藏视图
registry.view.viewVisibilityController(false)
const initUrl = itemData.resource;//$(targetObj).attr("href"); // 不作改变的URL
let url = initUrl; // 进行修改,形成要跳转的真正url
let temNum = url.matchFetch(/\[\[[^\[\]]*\]\]/gm, function (matchStr,index) { // temNum是url中有几个 "[[...]]", 得到后,就已经得到解析了
let templateStr = matchStr;
// 使用全局的keyword, 构造出真正的keyword
let keyword = registry.searchData.keyword.split(":").reverse();
keyword.pop();
keyword = keyword.reverse().join(":").trim();
let parseAfterStr = matchStr.replace(/{keyword}/g,keyword).replace(/\[\[+|\]\]+/g,"");
url = url.replace(templateStr,parseAfterStr);
});
// 如果搜索的真正keyword为空字符串,则去掉模板跳转
if( registry.searchData.keyword.split(registry.searchData.searchBoundary).length < 2
|| registry.searchData.keyword.split(registry.searchData.searchBoundary)[1].trim() == "" ) {
url = registry.searchData.clearUrlSearchTemplate(initUrl);
}
// 跳转(url如果有模板,可能已经去掉模板,取决于是“搜索模式”)
window.open(url);
})
//registry.searchData.searchHandle = handler;
const refresh = debounce(handler, 460)
// 第一次触发 scroll 执行一次 fn,后续只有在停止滑动 1 秒后才执行函数 fn
searchBox.on('input', refresh)
// 初始化后将isInitializedView变量设置为true
isInitializedView = true;
}
let hideView = function () {
// 隐藏视图
// 如果视图还没有初始化,直接退出
if (!isInitializedView) return;
// 如果正在查看查看“简讯”,先退出简讯
if($("#text_show").css("display")=="block") {
// 让简讯隐藏
$("#text_show").css({"display":"none"})
// 让搜索结果显示
$("#matchResult").css({
"display":"block",
"overflow": "hidden",
})
return;
}
// 让视图隐藏
viewDocument.style.display = "none";
// 将输入框内容置空,在置空前将值备份,好让未好得及的操作它
searchInputDocument.val("")
// 将之前搜索结果置空
matchItems.html("")
// 隐藏文本显示视图
textShow.css({
"display":"none"
})
// 让搜索结果显示
matchResult.css({
"display":"none"
})
}
let showView = function () {
// 让视图可见
viewDocument.style.display = "block";
//聚焦
searchInputDocument.focus()
// 当输入框失去焦点时,隐藏视图
searchInputDocument.blur(function() {
setTimeout(function(){
// 判断输入框的内容是不是":debug"或是否正处于阅读模式,如果是,不隐藏
if(isInstructions(searchInputDocument.val(),"debug") || isInstructions(searchInputDocument.val(),"read")) return;
// 当前视图是否在展示数据,如搜索结果,简述内容?如果在展示不隐藏
let isNotExhibition = (($("#matchResult").css("display") == "none" || $("#matchItems > li").length == 0 ) && ($("#text_show").css("display") == "none" || $("#text_show").text().trim() == "") );
if(!isNotExhibition || registry.view.menuActive ) return;
registry.view.viewVisibilityController(false);
},registry.view.delayedHideTime)
});
}
// 返回给外界控制视图显示与隐藏
return function (isSetViewVisibility) {
if (isSetViewVisibility) {
// 让视图可见 >>>
// 如果还没初始化先初始化 // 初始化数据 initData();
if (!isInitializedView) {
// 初始化视图
initView();
// 初始化数据
// initData();
}
// 让视图可见
showView();
} else {
// 隐藏视图 >>>
if (isInitializedView) hideView();
}
}
})();
// 触发策略——快捷键
let useKeyTrigger = function (viewVisibilityController) {
let isFirstShow = true;
// 将视图与触发策略绑定
function showFun() {
// 让视图可见
viewVisibilityController(true);
// 触发视图首次显示事件
if(isFirstShow) {
for(let e of registry.view.onViewFirstShow) e();
isFirstShow = false;
}
}
window.addEventListener('message', event => {
console.log("父容器接收到了信息~~")
if(event.data == MY_SEARCH_SCRIPT_VIEW_SHOW_EVENT) showFun();
});
triggerAndEvent("ctrl+alt+s", showFun)
triggerAndEvent("Escape", function () {
// 如果视图还没有初始化,就跳过
if(registry.view.viewDocument == null ) return;
// 让视图不可见
viewVisibilityController(false);
})
}
// 触发策略组
let trigger_group = [useKeyTrigger];
// 初始化入选的触发策略
(function () {
for (let trigger of trigger_group) {
trigger(registry.view.viewVisibilityController);
}
})();
// 打开视图进行配置
// 显示配置视图
// 是否显示进度 - 进度控制
GM_registerMenuCommand("订阅管理",function() {
showConfigView();
});
GM_registerMenuCommand("清理缓存",function() {
cache.remove(registry.searchData.SEARCH_DATA_KEY);
});
// 显示配置规则视图
function giveFlagsStatus(flagsOfData,userUnfollowList) {
// 赋予flags一个是否选中状态
// 将 userUnfollowList 转为以key为userUnfollowList的item.name值是Item的方便检索
let userUnfollowMap = userUnfollowList.reduce(function(result, item) {
result[item] = '';
return result;
}, {});
flagsOfData.forEach(item=>{
if(userUnfollowMap[item.name] != null ) {
// 默认都是选中状态,如果item在userUnfollowList上将此flag状态改为未选中状态
item.status = 0;
}
})
return flagsOfData;
}
function showConfigView() {
// 剃除已转关注的,添加新关注的
function reshapeUnfollowList(userUnfollowList,userFollowList,newUserUnfollowList) {
// 剃除已转关注的
userUnfollowList = userUnfollowList.filter(item => !userFollowList.includes(item));
// 添加新关注的
userUnfollowList = userUnfollowList.concat(newUserUnfollowList.filter(item => !userUnfollowList.includes(item)));
return userUnfollowList;
}
if($("#subscribe_save")[0] != null) return;
// 显示视图
var configViewContainer = document.createElement("div");
// 用户维护的取消关注标签列表
let userUnfollowList = cache.get(registry.searchData.USER_UNFOLLOW_LIST_CACHE_KEY)?? registry.searchData.USER_DEFAULT_UNFOLLOW;
// 当前数据所有的标签
let flagsOfData = cache.get(registry.searchData.DATA_ITEM_FLAGS_CACHE_KEY);
// 使用 userUnfollowList 给 flagsOfData中的标签一个是否选中状态,在userUnfollowList中不选中,不在选中,添加一个属性到flagsOfData用boolean表达
flagsOfData = giveFlagsStatus(flagsOfData,userUnfollowList);
// 生成多选框html
let flagsCheckboxHtml = "";
flagsOfData.forEach(item=>{
flagsCheckboxHtml += `
`
})
configViewContainer.style=`
width: 500px;
max-height: 100%;
max-width:100%; background:pink;
position: fixed;right: 0px; top: 0px;
z-index:2147383656;
padding: 20px;
box-sizing: border-box;
border-radius: 14px;
text-align: left;
`
configViewContainer.innerHTML = `
X
订阅总览:
关注标签(说明):
${flagsCheckboxHtml}
`;
// 设置样式
document.body.appendChild(configViewContainer);
$("#topController_close").css({
"font-sise":"15px"
})
$("._title").css({
"margin-bottom": "10px",
"font-size":"16px"
})
$("._topController").css({
"width": "100%",
"position": "absolute",
"top": "0px",
"right": "0px",
"text-align": "right",
"padding": "15px 15px 0px",
"box-sizing":"border-box"
})
$("._topController>*").css({
"cursor": "pointer"
})
$(".flagsCheckBoxDiv > div").css({
"width":"32%",
"display": "inline-block",
"margin": "0px",
"padding": "0px",
// 超出隐藏
"overflow": "hidden",
"text-overflow":"ellipsis",
"white-space": "nowrap"
})
let subscribe_text = document.getElementById("all_subscribe");
let subscribe_save = document.getElementById("subscribe_save")
subscribe_text.style="width:100%;height:150px;box-sizing: border-box;border: 4px solid #f5f5f5;";
subscribe_save.style=" margin-top: 20px; border: none; border-radius: 3px; padding: 4px 17px; cursor: pointer;background: #fff;border: 1px solid #f5f5f5;box-sizing: border-box;";
// 回显
subscribe_text.value = getSubscribe();
// 保存
function configViewClose() {
configViewContainer.remove();
}
subscribe_save.onclick=function() {
// 保存用户选择的关注标签(维护数据)
// 获取所有多选框元素
var checkboxes = document.querySelectorAll(".flagsCheckBoxDiv input");
// 初始化已选中和未选中的数组
var userFollowList = [];
var newUserUnfollowList = [];
// 遍历多选框元素,将选中的元素的value值添加到checkedValues数组中,
// 未选中的元素的value值添加到uncheckedValues数组中
for (var i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].checked) {
userFollowList.push(checkboxes[i].value);
} else {
newUserUnfollowList.push(checkboxes[i].value);
}
}
// 剃除已转关注的,添加新关注的
newUserUnfollowList = reshapeUnfollowList( userUnfollowList,userFollowList,newUserUnfollowList);
cache.set(registry.searchData.USER_UNFOLLOW_LIST_CACHE_KEY,newUserUnfollowList);
// 保存到对象
let allSubscribe = document.getElementById("all_subscribe").value;
let validCount = editSubscribe(allSubscribe);
// 清除视图
configViewClose();
alert("保存配置成功!有效订阅数:"+validCount);
}
// 关闭
$("#topController_close").click(configViewClose)
}
})();