那就清空掉输入框
searchInputDocument.val('')
// keyword重置为空字符后触发搜索
registry.searchData.triggerSearchHandle();
event.preventDefault();
return;
}
}else if ( ! event.shiftKey && event.keyCode === 9 ) { // Tab键
if(! registry.searchData.subSearch.isSubSearchMode()) {
// 转大写
event.target.value = event.target.value.toUpperCase()
// 添加搜索pro模式分隔符
event.target.value += registry.searchData.subSearch.searchBoundary
// 阻止默认行为,避免跳转到下一个元素
registry.searchData.triggerSearchHandle();
}
event.preventDefault();
}else if (event.shiftKey && event.keyCode === 9 ) { // 按下shift + tab键时取消搜索模式
if(registry.searchData.subSearch.isSubSearchMode()) {
// 在这里编写按下shift+tab键时要执行的代码
let input = event.target;
input.value = input.value.split(registry.searchData.subSearch.searchBoundary)[0]
event.target.value = event.target.value.toLowerCase();
// 手动触发输入事件
input.dispatchEvent(new Event("input", { bubbles: true }));
}
event.preventDefault();
}
})
// searchInputDocument.keydown:这个监听用来处理上下选择范围的操作
searchInputDocument.keydown(function (event){
let e = event || window.event;
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){ // 回车选择的元素
// 如果当前是在搜索中就忽略回车这个操作
if(registry.searchData.searchEven.isSearching) return;
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]);
// 设置活跃背景颜色
let activeBackgroundColor = "#dee2e6";
activeItem.css({
"background":activeBackgroundColor
})
// 设置其它子元素背景为默认统一背景
activeItem.siblings().css({
"background":"#fff"
})
// 看是不是item detail内容显示中,如果是回车发送send事件,否则才是结果集显示的回车选择
if(e && e.keyCode==13 && activeItem.find("a").length > 0 && !registry.script.tryRunTextViewHandler()){ // 回车
// 点击当前活跃的项,点击
activeItem.find("a")[0].click();
}
// 取消冒泡
e.stopPropagation();
// 取消默认事件
e.preventDefault();
});
// 将输入框的控制按钮设置可见性函数公开放注册表中
registry.view.setButtonVisibility = function (buttonVisibility = false) {
// registry.view.setButtonVisibility
logoButton.css({
"display": buttonVisibility?"block":"none"
})
}
// 高权重项特殊搜索关键词直达
registry.searchData.searchEven.event[registry.searchData.specialKeyword.highFrequency] = function(search,rawKeyword) {
return DataWeightScorer.highFrequency(45);
}
// 历史记录特殊搜索关键词直达
registry.searchData.searchEven.event[registry.searchData.specialKeyword.history] = function(search,rawKeyword) {
return SelectHistoryRecorder.history(15);
}
// 向搜索事件(只会触发一个)中添加一个“NEW”搜索关键词
registry.searchData.searchEven.event["new|"+registry.searchData.specialKeyword.new] = function(search,rawKeyword) {
let showNewData = null;
let activeSearchData = registry.searchData.getData();
// 如果当前注册表中全局搜索数据为空,使用缓存的数据
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 = compareArrayDiff(activeSearchData,newItems,registry.searchData.idFun,0)
}
if(showNewData == null) return [];
// 对数据进行排序
showNewData.sort(function(item1, item2){return item2.expires - item1.expires});
showNewData.map((item,index)=>{
let dayNumber = registry.searchData.NEW_DATA_EXPIRE_DAY_NUM;
// 去掉[新] 再都加[新],使得就算没有也在显示时也是有新标签的
item.title = registry.searchData.NEW_ITEMS_TAG+item.title.toReplaceAll(registry.searchData.NEW_ITEMS_TAG,"")
// 添加“几天前”
item.title = item.title + " | " + Math.floor( (Date.now() - (item.expires - 1000*60*60*24*dayNumber) )/(1000*60*60*24) )+"天前"; //toDateString
return item;
})
// 将最新的一条由“新”改为“最新一条”
showNewData[0].title = showNewData[0].title.toReplaceAll(registry.searchData.NEW_ITEMS_TAG,"[最新一条]")
return showNewData;
}
// 可填充搜索模式优先路由(key是正则字符串,value为字符串类型是转发,如果是函数,是自定义搜索逻辑)
const searchableSpecialRouting = {
"^\\s*$": "问AI",
"^问AI$": async (search,rawKeyword,keywordForFill0)=>{
return await search(keywordForFill0,{isAccurateSearch : true});
}
}
// 返回undfind表示没有定义匹配对应的SpecialRouting,执行通用路由 | null表示跳过 | 返回数组表示SpecialRouting执行搜索得到的结果
const searchableSpecialRoutingHandler = async function(search,rawKeyword){
const keywordForFill0 = registry.searchData.subSearch.getParentKeyword(rawKeyword);
for(let key of Object.keys(searchableSpecialRouting)) {
if(isMatch(key,keywordForFill0)) {
const value = searchableSpecialRouting[key];
if(typeof value === "string") {
registry.searchData.triggerSearchHandle(value+registry.searchData.subSearch.searchBoundary)
return [];
}
if(typeof value === "function") return await value(search,rawKeyword,keywordForFill0);
}
}
// 表示没有匹配到SpecialRouting
return undefined;
}
registry.searchData.searchEven.event[".*"+registry.searchData.subSearch.searchBoundary+".*"] = async function(search,rawKeyword) {
const specialRoutinResult = await searchableSpecialRoutingHandler(search,rawKeyword)
// 当没有优先Result, 只搜索“可搜索”项
return Array.isArray(specialRoutinResult)
? specialRoutinResult
: await search(`${registry.searchData.searchProTag} ${registry.searchData.subSearch.getParentKeyword()}`);
}
// 搜索AOP
async function searchAOP(search,rawKeyword) {
// 转发到对应的AOP处理器中(keyword规则订阅者)
let data = registry.searchData.getData();
console.log("搜索data:",data)
return await registry.searchData.searchEven.send(search,rawKeyword);
}
function searchUnitHandler(beforeData = [],keyword = "") {
// 触发搜索事件
for(let e of registry.searchData.onSearch) e(keyword);
// 如果没有搜索内容,返回空数据
keyword = keyword.trim().toUpperCase();
if(keyword == "" || registry.searchData.getData().length == 0 ) return [];
// 切割搜索内容以空格隔开,得到多个 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 = Date.now()
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.subSearch.isSubSearchMode() ) break;
*/
// 将数据放在指定搜索层级数据上
if (
(( getPinyinByKeyword(dataItem.title,true).includes(pinyinKeyword) || dataItem.title.toUpperCase().includes(keyword) ) && searchLevelData[0].push(dataItem) )
|| (( getPinyinByKeyword(dataItem.desc,true).includes(pinyinKeyword) || dataItem.desc.toUpperCase().includes(keyword)) && searchLevelData[1].push(dataItem) )
|| ( `${dataItem.links && registry.searchData.links.stringifyForSearch(dataItem.links)}${dataItem.resource}${dataItem.vassal}`.substring(0, 4096).toUpperCase().includes(keyword) && searchLevelData[2].push(dataItem) )
) {
// 向满足条件的数据对象添加在总数据中的索引
}
}
let searchEnd = Date.now();
console.logout("常规搜索主逻辑耗时:"+(searchEnd - searchBegin ) +"ms");
// 将上面层级数据进行权重排序然后放在总容器中
searchResultData.push(...DataWeightScorer.sort(searchLevelData[0],registry.searchData.idFun));
searchResultData.push(...DataWeightScorer.sort(searchLevelData[1],registry.searchData.idFun));
searchResultData.push(...DataWeightScorer.sort(searchLevelData[2],registry.searchData.idFun));
if(searchUnits.length > 0 && searchUnits[searchUnits.length-1].trim() != registry.searchData.subSearch.searchBoundary.trim()) {
// 递归搜索
searchResultData = searchUnitHandler(searchResultData,searchUnits.join(" "));
}
return searchResultData;
}
// ==标题tag处理==
// 1、标题tag颜色选择器
function titleTagColorMatchHandler(tagValue) {
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;",
"精选好课":"background:#221109;color:#fccd64 !important;"
};
let resultTagColor = "background:#5eb95e;";
Object.getOwnPropertyNames(vcObj).forEach(function(key){
if(key == tagValue) {
resultTagColor = vcObj[key];
}
});
return resultTagColor;
}
// 2、标题内容处理程序
function titleTagHandler(title) {
if(!(/[\[]?/.test(title) && /[\]]?/.test(title))) return -1;
// 格式是:[tag]title 这种的
const regex = /(\[[^\[\]]*\])/gm;
let m;
let resultTitle = title;
while ((m = regex.exec(title)) !== null) {
// 这对于避免零宽度匹配的无限循环是必要的
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
let tag = m[0];
if(tag == null || tag.length == 0) return -1;
let tagCore = tag.substring(1,tag.length - 1);
// 正确提取
resultTitle = resultTitle.toReplaceAll(tag,`${tagCore}`);
}
return resultTitle;
}
// 3、添加标题处理器 titleTagHandler
registry.view.titleTagHandler.handlers.push(titleTagHandler)
// 给输入框加事件
// 执行 debounce 函数返回新函数
let handler = async function (e) {
// 搜索使用的数据版本
let version = registry.searchData.version;
let rawKeyword = e.target.value;
// 在本次搜索加入到历史前检查(如果之前是子搜索模式且现在还是子搜索模式那就跳过搜索,因为内是子搜索内容被修改不进行搜索)
if(registry.searchData.subSearch.isEnteredSubSearchMode && registry.searchData.subSearch.isSubSearchMode()
&& registry.searchData.searchHistory.seeCurrentEqualsLastByRealKeyword()) return;
// 添加到搜索历史(维护这个历史有用是为了子搜索模式的“进”-“出”)
registry.searchData.searchHistory.add(rawKeyword)
// 字符串重叠匹配度搜索(类AI搜索)
async function stringOverlapMatchingDegreeSearch(rawKeyword) {
const endTis = registry.view.tis.beginTis("(;`O´)o 匹配度模式搜索中...")
// 这里为什么要用异步,不果不会那上面设置的tis会得不到渲染,先保证上面已经渲染完成再执行下面函数
return await new Promise((resolve,reject)=>{
waitViewRenderingComplete(() => {
try {
// 搜索逻辑开始
// `registry.searchData.getData()`会被排序desc
// 为什么需要拷贝data,因为全局的搜索位置不能改变!!
const searchBegin = Date.now();
let searchResult = overlapMatchingDegreeForObjectArray(rawKeyword.toUpperCase(),[...registry.searchData.getData()], (item)=>{
const str2ScopeMap = {}
const { tags , cleaned } = extractTagsAndCleanContent(`${item.title}`);
str2ScopeMap[cleaned.toUpperCase()] = 4;
str2ScopeMap[`${item.describe}${tags.join()}`.toUpperCase()] = 2;
str2ScopeMap[`${item.links && registry.searchData.links.stringifyForSearch(item.links)}${item.resource}${item.vassal}`.substring(0, 4096).toUpperCase()] = 1;
return str2ScopeMap;
},"desc",{sort:"desc",onlyHasScope:true});
const searchEnd = Date.now();
console.log("启动类AI搜索结果 :",searchResult)
console.logout("类AI搜索主逻辑耗时:"+(searchEnd - searchBegin ) +"ms");
resolve(searchResult)
}catch (e) {
console.error("类AI搜索异常!",e)
resolve([])
}finally {
endTis()
}
})
})
}
// 常规方式搜索(搜索逻辑入口)
async function search(rawKeyword,{isAccurateSearch = false} = {}) {
let processedKeyword = rawKeyword.trim().split(/\s+/).reverse().join(" ");
version = registry.searchData.version;
// 常规搜索
let searchResult = searchUnitHandler(registry.searchData.getData(),processedKeyword);
// 如果常规搜索不到使用类AI搜索(不能是精确搜索 && 常规搜索没有结果 && 搜索keyword不为空串)
if(!isAccurateSearch && (searchResult == null || searchResult.length === 0) && `${rawKeyword}`.trim().length > 0 ) {
searchResult = await stringOverlapMatchingDegreeSearch(rawKeyword)
}
return searchResult;
}
// 搜索AOP或说搜索代理
// 递归搜索,根据空字符切换出来的多个keyword
// let searchResultData = searchUnitHandler(registry.searchData.data,key)
let searchResultData = await searchAOP(search,rawKeyword);
// 如果搜索的内容无效,跳过内容的显示
if(searchResultData == null) return;
// 放到视图上
// 置空内容
matchItems.html("")
// 最多显示条数
let show_item_number = registry.searchData.showSize ;
function getFaviconImgHtml(searchResultItem) {
if(searchResultItem == null) return null;
let resource = searchResultItem.resource.trim();
let customIcon = null;
if(searchResultItem.icon != null) {
customIcon = searchResultItem.icon;
}else {
let type = searchResultItem.type;
// 如果不是url,那其它类型就需要自定义图标
let typesAndImg = {
"sketch":"data:image/png;base64,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",
"script":"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB0PSIxNjkyMzU4NTM5NjI1IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9Ijc2MjUiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCI+PHBhdGggZD0iTTk1OC4xNyA0NDcuNEw3NjAuNjkgMjQ5LjkybC02NS44MiA2NS44MyAxOTcuNDcgMTk3LjQ3TDY5NC44NyA3MTAuN2w2NS44MiA2NS44MiAxOTcuNDgtMTk3LjQ3IDY1LjgzLTY1Ljgzek0yNjMuMyAyNDkuOTJMNjUuODIgNDQ3LjQgMCA1MTMuMjJsNjUuODIgNjUuODNMMjYzLjMgNzc2LjUybDY1LjgyLTY1LjgyLTE5Ny40Ny0xOTcuNDggMTk3LjQ3LTE5Ny40N3pNMzQzLjI0NyA5NDkuNDgzTDU5MC45NiA1Mi4xOWw4OS43MiAyNC43NjgtMjQ3LjcxMyA4OTcuMjk1eiIgZmlsbD0iIzIzMTgxNSIgcC1pZD0iNzYyNiI+PC9wYXRoPjwvc3ZnPg=="
}
// url与sketch类型可互转,主要看resource
type = (type == "url" || type == "sketch")?(isUrl(resource)?"url":"sketch"):type;
if(type != "url") customIcon = typesAndImg[type];
}
if(customIcon != null) {
return `
`
}else {
return `
`
}
}
// 标题内容处理器
function titleContentHandler(title) {
// 对标题去掉所有tag
const { cleaned } = extractTagsAndCleanContent(title)
title = cleaned
// 如果带#将加上删除线,通过加obsolete类名方式
return `${title.replace(/^#/,"")}`;
}
let matchItemsHtml = "";
// 真正渲染到列表的数据项
let searchData = []
for(let searchResultItem of searchResultData ) {
// 限制条数
if(show_item_number-- <= 0 && !registry.searchData.isSearchAll) {
break;
}
// 显示时清理标签-虽然在加载数据时已经清理了,但这是后备方案
// clearHideTag(searchResultItem);
// 将数据放入局部容器中
searchData.push(searchResultItem)
let isSketch = !isUrl(searchResultItem.resource);// searchResultItem.resource.trim().toUpperCase().indexOf("HTTP") != 0;
let vassalSvg = ``;
// 构建快捷link html
function buildRelatedLinksHtml(links) {
if (links == null || links.length === 0) return '';
let html = `';
return html;
}
// 将符合的数据装载到视图
let item = `
${getFaviconImgHtml(searchResultItem)}
${registry.view.titleTagHandler.execute(clearHideTagForTitle(searchResultItem.title))}${titleContentHandler(searchResultItem.title)}
(${searchResultItem.desc})
${buildRelatedLinksHtml(searchResultItem.links)}
${searchResultItem.vassal !=null?''+vassalSvg+'':''}
`
matchItemsHtml += item;
}
matchItems.html(matchItemsHtml);
let loadErrorTagIcon = "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDIwMCAyMDAiIHdpZHRoPSIyMDAiIGhlaWdodD0iMjAwIj4KCTx0aXRsZT5hcDh6Yy12cm1kbzwvdGl0bGU+Cgk8ZGVmcz4KCQk8aW1hZ2UgIHdpZHRoPSIxOTQiIGhlaWdodD0iMTk0IiBpZD0iaW1nMSIgaHJlZj0iZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFNSUFBQURDQ0FZQUFBQWI0UjB4QUFBQUFYTlNSMElCMmNrc2Z3QUFIWjFKUkVGVWVKenRYUXU0SkVWMXZzUmdpQ1lLdmpVKzhCRk5RREJDZ3ZMNTJnQVNnV0FJNXFyTDNlbnFxYTQ3M1QzTDFTV0o4YTJicUtnSmo1QVk4a0dJSmlDSjhqSVFKUVlSQ0JCV1dJS0NLQVo1aU1ndVlGWjJlY2d1N0M0NXA3cm0zcDY1M1QzZFBWVjlxbnU2disvLzdtVjFvYnZPK2F0T1ZaM3puNW1abE9lSko1NW9NUUc2M1lXWkR2ZG5HQTltbUVENE00NEhQejM0TS9rekgrVGZnYi92Q3Z3OWxQL3N3TC9UeFg4djc4OXdIczY0cmt2K3ZYVkg2a1A5WW5VQjUzeW0wdzNCV1FHOG1KUHJSeWpod3UvZHJqK3pkdTFhOHZHcEMxb2lGSVRyd293c0ltZHpTSjArRHlKaTRtclNCZlI2UGZMeHN4VXRFY1pnQmN5cUR1K0I0MVBQOXBxZ1FpeGN3YWpIMWlhMFJFakE3T3h4VVd6UEIrR0dCUTVzQ0xoYXVHNjdVclJFVU1CNE9wcjFHekx6bHlTRjU2MG10MFZMQkFJSUlhSlFvYVR6ZExzTHorNXcvN2RoOVhnSGhCMS93b1IvTXV3ZHpnUkNmUlgrOTNXQVd3RWJBVDlUMkFaNFF1SEJ3Wi9EMy9rUi9QMmJ3Qm12Z1BjNUgvNzVkSWNIZitIeVlKN3gvcUdjaDY5eVhYZTNTa2lCcXdTTXlZb3AybXhQTFJGY1VjejVPZWUvMnVtR2I0SFllalhqL21ud1o5Y29SMzZpWXR3SjRkcEZnT05ody83dWJ0ZmZDMWF6WHpCRkNvZUhzRXA0NVBacWlhRDVZMlg0STNLRUNXNndweVBDVmVCc2Z3ZXo4M2ZnejdZVE9IMU8rQS9BejR0aE5mbG9Wd1FIOVhxOXArZ2xSSFEwN016UGs5dXdKY0lFaU9ML1VHMStrd0Zod0M4NnZQZEdJTXBuNEordnAzZnVpZkFva1AwYkVHSzlIMWF3L2ZXU3dvZEp3aWUzYVV1RWdzQ2xQYzJvczdQSC9iS003WGx3THN4NkQxdmd3S1p3SzZ3V24zTGQzajVhU2RHZ2U0bkdFc0ZOQ1g4d25vWlovMjB3czUzRmFHSjhhbndQUXlqUFcvMFNMV1RnUVNQMkVJMGpRcmZiVDd6eEZVSThWNFlLWG5DN0JjNW9BM1pnK0FRaDR5eUdoWk1TQWsvZVptZG55ZTAvOVVUQTlJR2t5eTlYaEsrSG4rY0FIclBBK1d6RjNSQkNmZ2htOW1kTVNnamNRMUQ3d3RRU2dZMWNoTUd6QzRRL1IrS01aNEdUMVFpd1QrTCthYzc4L0NzbkpjVEttdTBmYWswRTExMHpsUEVaeGYvaE1SQzMza0x2VkxYRzQ3aUhjbDMvMXljaVJJM3ltV3BMaE5Fa09GamFENEdmTjFqZ1JFM0NEb1poWmEvMzh2SmtxTWZxVURzaVlCRktuQVN1Q0ZiQXovVVdPRTJUc1ExVzJWTW0yVU80d3U2OVE2MklnRm1TZzcxQXQ5dC9VWlRURSt5MHdGR21CVC9EazdmWjJka25seUtEeFNkTHRTRUNsanJpcVZDVVBoQWV6L0QybE40eHBoWGZnd25wNERKa1FEZ1doa3JXRTJIRllucTBQSnA3TStCL0xYQ0VGaEhPZ2ZqL1dlVUlZVmVvWkRVUlZzcTdBVXlBVzdPN3l2aHN3eUQ3c0ltSnNGZUdESGp4U2UxajFoTUI4MWdjR1ZkaU9vVE01NmMyZUlzc2lPQ0NVcXNERDZ6WU4xaEpCSWRqaHFPN204b0UzVUZ1NUJaNWNhOHIvTU1Ma3dIMmZxZ0cwaElodmhKd1dVTzdEOFNRTjF0ZzJCYkZzZFAxd2hQTG5DdzVEbDJacUZWRWtDZER3bC9aOEpUb2FjRjZwOWQ3Y1ZFeWNIN3NkQk1CTXlCVktFUnR3QmI2Y0gveFk5WndwaVBFZEJKQmJiS3V0TUJ3TGZUamNjY0xqczFIZ2lWVXJhWkJUZ1RNWTRHQitvRUZCbXRoRWp3NEJmWU5UeHBIZ0RpcURKTklpZUJ3LzBBbWwwOExETldpQW9UL2dXb2dTVTZmQmhSVGJqUVJaSzJ3RjJ5bE4wNkxpbkd0NDZ4K0ppdEFoaW8wVzBtSUVKME1ZYzQ3dVZGYTBPRDdFUGE4Z0JVZ2crbEx0OHFKSUpYYjJrdXlGbDU0UjBlSWx6SkwwakVxSllMTC9RWFc1Z3VaeGxad21xOHhFYndIa3hRZEovaTFZOEp3RHhRdjZIWjcrN2xld0pVazVRTVd2T3VkaGRRMGhEa3lWRVlFeHdzRmEwbGdFdmVnOWlyRTAwL1BOU21oamlxRXFFckZqL0s5YnlzU0ptRk5RMjJKQUJ2ak9kYUdRNmF3RlFqdzRZV0ZoVjhxNlFDN29MUWxvMDFzL0I2S0tlY2hBcFBIcXZySllKd0l3T0NqV0xzeE5vVnJPNkwvbTFyczVLN1pIVmFIZjJSMHEvWU51SnJsSVFMdUYrYm05QjZyR2lXQ085Ly9IWGp4Unl4d21NWUI0M3lVck5ROU14SVhQMTJlTjFsUGQ0aGtqQWl3ZkwwTVFxTDdxQjJtZ2RnT29WQ29td0J4Uk9Xdy9pY1lRVG1zV3BWeWJwNzFrY0VJRWFUYVFhc3RaQUpiWGVFZmJaSUVRNnVEbEhIQlhnd1ZmeWZzZWZLU1laWFh0NU1JTXAra1ZaZ3pBRlNoNng5YUZRbmlRUExCTzJ5bzhIdDNxcjFsWlRmUDJvbmc4T0RUOUU3VE1Jamc1OWl0aDRJRUErQmRSTVdiNlMzWUxpc1BFVndOOXd0YWllQUkvdzhxSEtocHdXT3dHaHhCU1lJNHF0eE1ZMWJ5M056QzAzS1JZY0pWUVJzUmxFN21GZ3NjcDBuWWpyTHQxTTQvaWs2bjgxUjR0MU9yR0FQNC9pL2xJUUlXOUt5ZG9QbWhGaUpBakxZcmJJNnZzOEJ4bW9UdFRJUmRhcWZQblB4UWNOa0xIakkrRmpBT2Vjamc4dkphU1ZxSWdHMkpMSENjSm1Henc4UERxQjA5RHpwZThHcDQzN3NNajhlRHE3eitLOGFUd1M5ZHZ6QXhFYkFCSDdPNjQyVHRjQnUyaktWMjhDSlkxZXM5bjVsWElsOHZJdzlEZHdzVEVTR0tGY003TEhDZXB1QlN2SU9oZHV3eWtPa1Joc05qN1AwMmxnaVlnbEdDREJNUkFmNmpKMW5nUEUzQUR0UUNRaVVQYW9lZUJFbzIva2FENDdUVjdmVitZendaaXU4VlNoUEI4WUlEV0JzU2FVQjRCL1VkZ1U1MGd1QTU4RjAvTkRoZVYyRm5wSEZrY0FwbXFKWWlndXJDMkhhbm1RdzdVZGdZaTltcG5WYzMxRVhZWmxOajUzSS9HRWNFUkpHOWJpa2lZQUdJQlk1VVkvZzNZNnNyYW9jMUNXYysrSDFtckFiRmZ5QlAvWUxEODk4NEZ5YUNXdnFNc2IyaHdNYm1HQzZjaHc0Q3c3c0x0YU5XQWJXNU5UT21Jdno3Y1VSQTVMMWtLMHdFMWFlQTJyRnN3K095NUZHRVowVEx0bit3SThKOXNWNjRiT1ZZRTRBSm1FQ0dLd3lOK1hZYzQzRkV5TnU3clJBUk9QZGZ3OW9OY2h6cjBQR3h1b3ZhNld3RjlycGoyRXpFeVBqN2w0MGpBc3NaSGhVaUFpcVZXZUI4MU1DSjRBdTZTaVNuQVNxTjI0Zzk4QVorSEJuY0hQY0t1WW1nYnBDcG5aQWExN0w1MVh0VE8xWWRBYUhqMllac2NqM3V1YkxKb0pFSThDKzgzQUpISkFOSzFzdVkxN0ltZUhXQmtubTgxNFJ0SEI3OFlUWVJzUGxNdHQxeUVVRjF0U2QzUmlMc1VPcDhha0R0YVlCWE55aTlXeE0yK3U2NFN6Wm56S1k1RnhFTTd2enRod2hYeHdlMENrSGFKb09KNE1zbTdLVDJJWm1yd3NKQ2VtYnFXQ0lvU1JaNmh5UWhRZkRGMGNHMG9RTmtuZUc2L2VjeEUvZFFVY0pmZG5qa3BhL21ZNGtBLzRKenlCMlNCZytwSkxLaHdleDBPdVRPVkhjd3ovOVRFelp6UmZpbUxDSmszVFJuRWtHcEZVL252WUVJejBnYXpHNVhqM3pJTkVQbXFvbmdKdjEyazlJejJXa1hUaklaTW9rQVM4bGZrenNrRVZ6UFB6SnBJQ0ZVSkhla0prQTFHZFJ0dDUycWRqNmREQ21LRjZrUHlna3lZemVDOXNOMWd6MFRpV0JJalhrYUFXVDRxbTY3T2NML3kwd2lwT3dUVWgvSEN4bTFNMUlpclN5d1NFWmppMnlvZW1mZG9mZjltTitWUllTa2pwMnBEL3lGZGRUT1NJbDBNZHIyUWswbmxHaVlWdHRCU1AvdUxDSWtkZDlKZkJSVHlaMlJFa3E3SjNFZ3V3WTd0MHdibkY3dnhUQ20yM1RhRGxidGIyb2hBdXkrajZkMlJHcW9yTW4wd1p5ZkozZWlwb0J4Ly9PYTdiY0RVK0JUN1Nmd1B1aTRzVVRBQktiYnFCMlJHdTU4LzdleWlCQWhyTFFwZGxPaFNqdjFWclBKSG5KWmwydkRJZTZ5WjZwdmt1TkU4TUxaOFVRWTNqc3d0ZXhpWGdzV2p6dndaM2pLaEduQWFlZlhMU0pBWFA5dm1tMTR6VGliWlJQQkMwK2tka0lib0ZTOUN4QWhQenJkTmw5cE9SSGt2WTFPRys0YzE3RXprd2pNcUJSSG5lRGZiSW9JQStES2dRKzFFOW9BcFl5aXRRY0RyTTdIWm8xL1BJRnllRFdJYnVVc2NFSTcwQlhCUWNiSm9NS3Fic0lHYnRxZ094cVIvYWF6OWdteDA3L2gxU0RhWUpBN29FVzQyNW1mZjZWcE1peUhML2NWMDVicGloMkJ0TnBQQkQ5WEdSTEprMUJNQkd4NFJlREIxeTF3UHR1d2hYbmhSNG8weFRaQkRCUzNiWG9ZRlRVeDFOdkFFUFllYjBzZFY1NndJc2hyYVdDUUJZNW5LN0FUME8xS09lRWNXSFpQeDd3V21GVSs1SGgrSDNzRllCcHc1dm0xRG9oUVNwUTBOWXlDYjd4U3M5MU9TaHZMK01YYTR1TncvMEFMbkswcEFNSUVwM2E2dmRkcGNmNUVRcWc0RjFhTEZSTjBpckVOS3YxZHB5MnV6UnJId1lRUzN4KzBNbzVtY0FQMmxwc1pxN1F3R1RBWjBIWHJueUtPSzZ6bThYOU1oVnlwSyt6d2l1Q0Y1MXZnTkkyRlZNTHovRS9nU1ZUV0JtNVNPRjV5TGsxZDRJaHdsZTZ4ZDBXd0ltMjhCdVdiOGZ1RGpkVE9Na1hBRGVIbFFJeVA0YjRpUGROMUFzQUt3UXRLbzlzQUpjMmlkYnpWS3BNeVZ2NFNFZFNKQ0xWelRETWVBVndDUnZrZ0xOWDc2dzJqL0ltNlRWWlBCS2xjcDNkOGVYQnU2dmp3R0JFNjg4SHZXZUFNTFphd1FRb0tDLzlvSFdGVWxucURiVEJSd29uOW10UEdabEJvcGU0UHd2ZFpZUHdXU1lpT3RNL0JYQnlWaGxDS0RERFprVHQ1SHFoemY5M2p1RDFyUWxra0FzdysvMHh1OEJaNWNBL01ZQjlYMmtDTlhCVVlEOTl1Wk93ZzVFd2JteVVpZU1IMUZoaTVSWDVzUTFGZHdHdlRqRHVLK2hBaGVLZUpNWVB2NzZTTkRXcFZEWWp3ZnhZWXQwVng3QURIK1JmT3c1ZWxHWGtSSmZzUFYwNkVTR0xUd0ZqNUgwc2JHOVNxbXNGbWRoWVl0TVZrMklhR3poTENyVU1sbmV1NmVJcnpPU05qRkpXREpxK1c4LzIyVUw5SmdPWC9uNUtOYmJmeVJzZUxhak1Va2U4eU1UYlpCZjMrektEN0lia1JXK2lCT2dvZlBpSzBqQWdRaGNqRVFUekRIM3BQNGIvTDROamNQam91QTJDK0ZzWmtQV3JqdGRBSEpkTTVaR2hxS1h2WFhTTm5mQ2I4bEJrNWlHUmRlSENmd2JGNU5PMi9qYmZ3V0tYekFXcmp0ZENIWlVUZ2RLdEJ0eHVKRjZRNjRHQkdkbnY3T0Y3d0k5TmprNnBWaFNXendJWVRxSTNYUWlORTJCMHlNdEZxZ0tkVWlVNDNSQUIzTjVpSTE4THZXNnNZbXpTdEtoZFhCQVBpU2kzb3NETmVTVWNoV0l6NS9Vbk94a1lJb0xSMWI2MXlmTkswcWlRUkRPakp0Q0NELysyNGdic1Z5OFpndHV0QTN5a0plRUtwMUtxSjdxMWtIbFBpSFF2K2NnbTlBVnZvZ09QNTc0MGJ1RW9TT1BQQk1oTGdIWlVyL01QVjNjQ2QxT09UMXZOaXNGbStndm9GVzJqQmc3MWU3K2xMeHExbWt4eGxKdmdxNUZtek8xYmp3ZWJ6WkJhbDdkalZiU25xNnBsd2ZCcXRDTmVRdjJBTERVYVdzKzZpY1dmNzVzczJjVC9neUJETTN3dWM2VXVzb2sxdmFRaC9KVXNnZ2hSYVkyM0NYUk93bmZWNkwyY1Zoa1dvNVlvaGhicUgwaXJyYmdxd0tYWlpBaEV3UlIxL3VaSDZCVnRNYU9Cb05vNFoxK3hwRVc3Q1ZYNy9GNmkvdmRBNHhSckh4eUZ6alpnSS9vZjZCVnRNQm5ETS9VYU5hMHIzQ05YaG9teFhlVUpGL3UyRk1IckhFcnRyd1YrbXVrVlVBN0JPYWh5SndWSGcwcEdnYnNsSXh2c3FOODEvd0lMdkxnNGV6TEhFZTQwMWtnaTZsY1dvc1JNekRWM3VMK0FGQ2pZRlBDWU05NWdUNG9WU0lRRnYwa1h3RGZqLzNXL0J1Mm93cnU4TmIyQm5wYml0TkxCQUkrdlpMMFNDQXY0SG1lNkdIaFVpcmVmRm9Dam5VdW9YMUlTTllQaFA0YVl4cjNHRkVNL2wzSDhOMXNsaUJSTktOenBlK0g3Wk9vc0hwNmdTMW90VkdHQ2ozTTBqcy8zK3J5U0dNUEVVaHdLNnFaaWdoNkVDa2dnM2tYaTBpUHNCcklpejRIc25nanphVFNDQ0pMcUpYcmVWZnB3WC9BQ2NWNkIycThrTjRvQTRRSklqd01uK3huQ21aRjVjbmhuS2pKeVZZM3dmbDRmRWs1OUJVaHltR1NRNWlkUnk1Y0YxRm56cnhFaEtVV2N4SXB4Ri9ZSWxjUU9HT2xqTVlab0FLVFBucnJDSzhDcXlKdE1SWHBTWENHV2dOdUZhbTNkUVFyVkZXelpCU0NLb3RGM3lsOHdMcVZIRGczZGl6RXBCZ0ZISUJMSklTZTBoZ3ZHNEY4T1dwUGRhaFNIT0JDU0Fiem9FZmo1SWJXK3RHTGxyWWQ1U1U4RVpWZFJNLzVJNWpJNGJROVQyb1hiK0ZNZDdQZ3pxWitBOWYxend1NUJBRzVRSTFmVUtWOHNOZlJ4ZWNHSHM5L1dMRXY2d2o0RU44cE9XclFZcG9VNHVSQTA3N0w0bExnRk1BVm4ycldJUUdobFREZENHeDNIamluazAxTTZlQnhpcXVXNndKODZvS25RNkZqZmdDSG1TNVlYSG9CQXd0dW5DMWFUc2Z3ZWRYNG5iM29yNVl2amZIQ0pDU1JKZ2tReUVYQTliWUhmdGZwUWtwVGxvSGorampwU29YeklONjJCanVpKzFjOXNNSEI4MVZsdnd3bWdRTW81emVOempZS2lBWk1KTkpQcUI4b1ZUQVk5WllIdmQySkEwRHAxQUVRRm1yQU1zZU1sUmJJZFo2Yzl0RFlOc0E0dmRpWUF6Znd0WG83ZzhKSjc4d0o4ZkJiOS9VclVIdTR2WmxobHFIdXVTaURBWVEzVWtTUDZTaTFDbk1HOFlmZEVXbVVUWWxEQ1d1TkZGNVlaV3ZNMUx5c2NhSVlLTW0renBuYllPbHFybnhGOTAyanBMRmdWdTBpMndtL1ZRQnhtWlJNQVRobHVvWHhSdmIrZm1GcDQyK3FLcmlLVkliSWNwcmRER1FRVGhNaUtNZHRXMG9XNVpiZm9TenJOYkltUVN3UXYrbHRwMmRVQlM4M2k4V1I4aUF2YjJJbjdSVFVra2tDOUxvTVJRSnpDWkMwWHZhTFpqTk9SbUkvdlBxSkdnV2FtOVBOaVNSb1RSRjI0eERCWDdranVhNWJoM21WK0pCQ0pnelNueGkyNUxKWUlJR3Q5eGZpSWlSRTFEa2s2TldpemgwbEcvR28wMDVLUE9uQitsZkZtOEtVMGpnOFBiVlNHVERNSi9LOE1iZUhxSHN4VW5qZnJVbkJETGlSRHRFOEtyS0Y5V0hRT21oRWUrc2RMRHBrQVYwZSswd09uc1EzU3lsaG9XalJBaCtDemx5enE4OThaMElrUk50T3ZVSnBVQ21OZlVraUhCdDdDbUl1NUxZcm5tMCtLanFuZm9YamJTd3N4T0NBT3NhTW1RQ1pmN0FhdHhPYVVCM0xuTWo3SldoSlc5M3JNWTdXenlEK09JTUFBMm1xQjJPSnVCR2E2czNUTkVFTUVYUi8wbktWdGg2SUZZL0diQ0YvNUo3bzd6WEY5UmVsT2h5REQxS3dPVzhjWjl4MGxwcWpoQ2hQQ3ZTRjhhVlNaeXJncURqOEtOOU56Y0FybmoyUWhXTXdFdUUwRDFrbEcvR1VzRWRRMU4rT0wrelZrZDBuT1JRKzBsVU8wTkZacXAyeWFSRWtFRUYxQTdJaWxFY05Pb2Y2VGRTUTA5RURzOW1SSFhxWUlqbjVuVkpyVWN3cG1GaGVsYU5Wd2VyaUYzUkdLb1hneER4L0JwNDdYc3NXRVd3VGFwOGNJU1hjamFaTE5Zc2J0VDg5TXAxR2xpMDFkNHM5eVBvbExXUmJ0NjN1b2lSSkRTMmVRZkFiaEVOVVBYUmdRWk5zMHZ5YVd2UkNHcmxHWjNxQUZFN2RCbHdIbjRxdHBLTXVyRnh0RnNoYXh4Vy9hZ2NocjhwVWNzK0JDOEVid09pOUoxa2lGT2l1ei9qMTI5aWZOQUdmNEdjcnRaQUNuQ0ZyZDN3aVZhSmhHaTA2UGdIT29QaVdGTDlGSCttNU1LZDB6QkdUT0QyQWhYK0VkYllDOWJzRmp1bXlmVVRYd3NIbEM4OEx1SG9jcWRGM3dOOXhLd0VmNElLalQzZXIybjZDUkNIVmNFR0pQVExiQ1JEYmhyNkU0cTRTWTVGeEZRUjVUVlR5MzZJYndIVWUrdVpVV29XNzIwRXYraXRvTUZrSVZtaTdic2REcmxpSUNQT25xeTRLTUs0K3JNVFhZays0Y0podXR4VlJsM09rWHQzSVdJMEJDeDNnbXh3L05XdjJUSmh2bFc5dFFIbGRoWVRUTVp3Y0cvRXhkOHhUd3FKVjZGWlkxRGFRY09Edy9MSWdLZUt2R2FuQ0NCMFMrakhuc0xjUEdTL2NKRkFhL1NSSWdHdHZhOUV6WW9uYVFNUWt2dDExeDdCdHNKQWU5NW5nVmpUb3A0RHdTM3dENHZrd2dxOTRmODQ0d09YTFRCekwxM2NIbitwaHNFUkpocVJRdWM5SVlWL3RJdjBBb1JRYVU2ZkovNkE4MUNOa29wdHBrV2R1WXd1U0w0QVAxNEVrSUU3eG5ZS0tubW9EUVI1Q3dUbFFEU2Y2UWg0Q3lTVlMrZENtNmZxQURqdmtNOW5vVFkxT2wwbmpxd1Q5R0phaXdSVUxxY1JYSVkxQjlxRXNlbE9ueFdtRFRtdHJKcU9DSmNaY0ZZRW1IcHlOVGx4ZTB5bGdoeXBvbTZLVnJ3c2Nhd0UwVmlvenlkQWtTdzdIZ1Z3b0dQV2pDV0JBZ2ZqZ3Q0bGJuL3lVVUVsWDlVdHd1Mk10aU9QZVdpaHRvNWlPRDJ0VGl3THNBN2ZkZUNNYXdjY1lGZmg1ZXpTUzRpeUdXWCszOU0vY0VWNGhITTU1OFpVenBLN2ZoRDlpRVdYeURFWnNkWi9VeW05bTFseHk4M0VWVGwyRDBXZkhoMUVNR1gwM0tZOGx6YlZ3VWx2SEEzK1hnUkFNTEJ0VXpkODB5aW5KNmJDQWdsRlVMKzhaV0NCLzgrdWpLNEtRWGdGRkJIM05NcUJQeFQ3SzBuYlRLaEdtSWhJc2pMaXFnT2xIb0FLb1dTVkZ4TXVhQjIvamlVcUJmNUdKSFlKWnFZcFYzU2ZOWUlFUkN3QkIxTVBRQ1ZEN2dYY0J6c0tDUFZIdWxKRmE1dW5PejdzSnJOL3dyOC9xK0FhMWw5RGtWdUhOei91TzdreDlpRmlhREk4QlVMQnFJcVBLb1VwN0dNbGR6NWgrd1E5VU11LzIzYy81emNBNDJFRmJLdkhnL2Z6cnp3K0NpUno3NTJzdzd2LzY2MFNZazdBMzFFd0ZSbWUvcXVtY2Fpa3JKdFlSRjJIcDNndXo2NytGMWowaEdpUzlYd0NGZ1J6MlkyaUlieDRGeW0rZVN1RkJFUTJFQ2JmRURNNDdiNHRUM3o3Q3JoaE5uNlA4dDlWM2pWVUZwSmdieWNxQ0c1YkU5TFpCUC9nWUZ5dXVkNTlFU0lzdno4YjF2Z3JLYXd3eFhobTlqSXNhbWoyUUNURVNINGFZbnZlckFqeEV2WjBDbFlNWEl6RWU1UFpSZVhCL1BTRHBwQ29vbUpFQnVRUm9yTlFoaDA0aWdKRnNrQU1YVzNTeXNZcHFxd1NuemJjQmtqSzdIS3FTTkxDcnY4MTR4c2g2dy9SSjJJQ05Hc2hCc3Flc2ZWaVNnamRiejBaS2RMdDJjb21XbjZhRkpUdmFKRWNIaDRDSUZkSHNLcVNWT2g2Y1JFZ05saFYzako5ZFRPcXhYQ1Aza2NDWllRWWcrNjZvbFFSbkludHNrY3hTb3ZmNDRPM3JoWGJoUHVlOHpnOGZYRVJKQXp4UHo4SzIwOFlpc0x6RVROVDRUQmhoTUpVVTBTbnRLbzNWTDR1NkxDblpSdnlFZm1UcmYzT2xiOXlkRjVqdUVrUnkxRWtHU0lkT2pKblZnVEhvZUJQNkF3R1ZBK3NvTDBDOVJ4S3ZWZHNRcXVKSXduSUlTTDFXY1czTzE1M2pQWWZQNnlTMUlpUkdRSXpyVEFpYlVBOXduU0FJWEpVT3c0c2d6S1htZ3VKYWlsSEFKa2tBRnZid2tFeExZNTNEK3dDaDFhclVUQVcwcVVVcUYyWW0xazRNRi9kN3NMenk1RGh0bSttV1ZjM3ZwNndXT2x2aWU2RU10ODc0RmlOQ3Ayb0Y2bzdFNkV2U1lvVm53UnJoNm5XV29sRWRRQVlsSEx6NmlkV0NOdTczVER0eFFsZ3FsYmFKZ2RQMVQyVzVTMFRXRlNLM24xYlZXT08wWVhvMDNCYTBVRWhOTG5iOWo5UW5oUnQrdnZWY1NCSmgzSFVjZ1luUWYzVGZJZHE3eitLNHA4ZzlvclZkMDhaajErYTFVa01FWUVTWVptMWk0OERzdjFHZDF1LzBWNW5NalZITnRpcURENU44ajY4N3duWVhoaHVxbktNY1pWQzVNY3F5U0JVU0pJd3hFM0p6U0g4R0hsbE9OblZLNUgvd2huU0JYYVRQcitOK1o3YnludTlsREZZN3VaemEvZXUyb1NHQ2VDcXA2eXFkZUNYb2pndzNtY2FwSVN3cVZKUlVwVGFubHZJTlJyMDk1VjNkNmVUVENlMi9ER21vSUV4b21BUUpsMmx3ZGZKM2RhTTNoRUtYeU1JWU0va2NTOHlpdlMyY1hvbW9GaU5CNXVPTUovRit3OVRvQU4vcmNZamZEemRuaUhQNklpUVNWRVFPQ3hxaXVDS3l4d1hPMVFqYjF6eGR3bERiUUwxazFUZjZkQjdIQzhrRkdTb0RJaUlMQm5nWnB4cUFkZU42NmVHU1A3TWtEUm9uOXNpY3NpRlQ3cWJ6U0ZuWTduOTZsSlVDa1JFQ3A5OTJvTERLQVZMZy9mbDRjSW1JSXhONWN2ZlJ2REtkWGpvZEx6KzRwSjhGNXFBcEFRQVlFeHRjT0RiMXBnQ0oxNHpPRzlOK1lodzdnMFl0ZGRJMjl6VldlZnB1cEliYmNoSENJbEFpTHFjOVk0QVlDTmd4TENjVUFOSHB6eE1VRVBrOGxrSGc5WC8reGgwUS9lVTRSM1dQQk5KckNOZW1Oc0RSRVFzbzZCKzUrM3dEQWE0VjlXU21JK3ZtTElsUGJnaC9UZllnU2JLWTlJclNUQ0FOZ2VsdFcwVjFzS1BsbWFDRkpDSmRoc3dUZVl3RjBkTDNnMXRjTmJTd1JKQmg3TXdVQnR0Y0JZT3JBOXFlZy9DeGdxcWk2bVRab1E0cmdldzBacVo3ZWVDQWh3bnRlenhnalpobmZNelMwOExSOFJwSEpnZytYYy9iUHdIb25hMFd0REJJUXFMTCtjM25pVFkxeVRRdGRkczN2RCt5SnZRMTFXYWdldkpSRVFVaStKQnlldytvY0pHMXdldUhMR3h5ek8rZFY3eXp3ZTdoK29Fdlp1dGVBZHpVQUVQNEdmYjZCMjdsb1RZUUFsR2RMVWMvVG1RZ1FYWU9NT2F2OXBEQkVRcWt6eVFuTGp0c2hEZ0ovYmRGUGNLQ0tvRjl4RnlmdzE5Vml4Q2JnUzd6K29mYVhSUkJoQVNiTTN0N2FobnRpTXF3RFduVkQ3eDlRUVlaRVF3ajlhYmNhb25XQ3E0WGpoK1p3Zit3SnFmNWhhSWlCVWZjUGFLZXJSWUE5NGNJdkR3OE9vZmFBbFFneHpRcnhRaVlyVi9haTFEdGlFWVJBZWIxUGJ2U1ZDQ3FRZVo3T3J1QWdSUG93TnZZOEp3ejJvN2R3U0lTZkFjRytJZW41Uk8wOGpzSlZ4L3pSVTFxTzJhMHVFMG9UQS9KMnliWldtSGRobE16eWVRbHVvSllJaE9DTGNWKzBoU21tRlRoazI0Z0VFNWtCUjI2MGxnaUhJVFRVUFBnN0cvckVGRG1jVGRzaVZrd2Z2d0VJcGFqdTFSS2dJV0QwVzlSWUlMMkxUdlVyY0F4UERwMUhUaU5vbXRtQnFIendGa1gzSW90T21oZ2tXSjJJVGhvbXU1eCtKUjZEVTQ5OCtGajR5ZlVPRVBjeWNaTlVyUHhzRE9QNFBzQitjSy95M3RzN2ZQb1VlN0UvV0ZjRkJlSGFPalVKWXZVcElOMkREUUJUTndyQ0hlaXpicDBHUDY3cTdLYzJpUDJPWTlNZURXNWdkb2RSbTJPdGNCVDlQZGIyZzB6cCsrMVQrWUxGOXQ5dmJ6eEhoS25VYTlRVjFrWGM3MDZwTTV6K2dXbkZkQ0FROHhlWGhHZ2h6RG5kNnZSZFRqMEg3dE0vWVIrcTh1c0dlc2tTVDl3OTF2WEJXQWtzMzVWNGtEbitsK3QrUGt1b1hzcVN6L3p3TTBhaS9ZNXFlL3dmaFNwMGVHdnoyYkFBQUFBQkpSVTVFcmtKZ2dnPT0iLz4KCTwvZGVmcz4KCTxzdHlsZT4KCTwvc3R5bGU+Cgk8dXNlIGlkPSJCYWNrZ3JvdW5kIiBocmVmPSIjaW1nMSIgeD0iNiIgeT0iMCIvPgo8L3N2Zz4=";
// 给刚才添加的img添加事件
for(let imgObj of $("#matchItems").find('img')) {
// 加载完成事件,去除加载背景
imgObj.onload = function(e) {
$(e.target).css({
"background": "#fff"
})
}
// 加载失败,设置自定义失败的本地图片
imgObj.onerror = function(e,a,b,c) {
let currentErrorImg = $(e.target);
let standbyFaviconAttr = "standbyFavicon";
let standbyFavicon = currentErrorImg.attr(standbyFaviconAttr);
if(standbyFavicon != null) {
// 如果备用favicon使用
currentErrorImg.attr("src",standbyFavicon)
currentErrorImg.removeAttr(standbyFaviconAttr)
}else {
// 如果备用favicon直接使用加载失败图标base64
currentErrorImg.attr("src",loadErrorTagIcon)
}
}
}
// 隐藏文本显示视图
textView.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;
}
$("#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 dataVersion = parseInt($(targetObj).attr("version"));
let currentSearchDataVersion = registry.searchData.version;
let itemData = registry.searchData.getData()[dataIndex];
if(itemData == null || dataVersion != currentSearchDataVersion ) {
console.log("后备方案(没有找到了?"+(itemData == null)+",数据版本改变了?"+(dataVersion != currentSearchDataVersion)+")")
// 索引出现问题-启动后备方案-全局搜索
let title = $(targetObj).parent().find(".item_title").text();
let desc = $(targetObj).parent().find(".item_desc").text();
// 从全局数据中根据title与desc进行匹配
itemData = registry.searchData.findSearchDataItem(title,desc)
// 从历史数据中找,根据title与desc进行匹配
if(itemData == null) itemData = registry.searchData.findSearchDataItem(title,desc,SelectHistoryRecorder.history)
}
// 给选择的item加分,便于后面调整排序 (这里的idFun使用注册表中已经有的,也是我们确认item唯一的函数)
if(itemData != null) DataWeightScorer.select(itemData,registry.searchData.idFun);
// 记录选择的item项
SelectHistoryRecorder.select(itemData,registry.searchData.idFun);
// === 如果是简述搜索信息,那就取消a标签的默认跳转事件===
let hasVassal = $(targetObj).attr("vassal") != null;
// 初始化textView注册表中的对象
function showTextPage(title,desc,body) {
registry.view.textView.show(`标题:${title}
描述:${desc}
简述内容:
${md2html(body)} `)
}
if(hasVassal) {
showTextPage(itemData.title,"主项的相关/附加内容",itemData.vassal);
return;
}else if(itemData.type == "script"){
// 是脚本,执行脚本
let callBeforeParse = new CallBeforeParse();
let jscript = ( itemData.resourceObj == null || itemData.resourceObj.script == null ) ?"function (obj) {alert('- _ - 脚本异常!')}":itemData.resourceObj.script;
// 调用里面的函数,传入注册表对象
// 打开网址函数
function open(url) {
let openUrl = url;
return {
simulator(operate = (click, roll, dimension) => {}) { // 模拟器
if(openUrl == null || operate == null || typeof operate != 'function') return;
let pageSimulatorScript = operate.toString();
addPageSimulatorScript(openUrl,pageSimulatorScript); // 保存模拟操作,模拟脚本将在指定时间内打开指定网址有效
window.open(openUrl); // 打开网址
return this;
}
}
}
let view = {
beforeCallback: null,
afterCallback: null,
mountBefore(handle) {
this.beforeCallback = handle;
return this;
},
mountAfter(handle) {
this.afterCallback = handle;
return this;
},
// mount是脚本项-脚本js调用
mount() {
// 看脚本js是否给beforeCallback ,如果有在此执行
if(this.beforeCallback != null) this.beforeCallback();
// 挂载MS_SCRIPT_ENV 实现系统脚本API到视图
registry.script.openSessionForMSSE();
// 挂载视图
let viewHtml = itemData.resourceObj['view:html'];
let viewCss = itemData.resourceObj['view:css'];
let viewJs = itemData.resourceObj['view:js'];
registry.view.textView.show(viewHtml,viewCss,viewJs);
// wait view complate alfter ...
waitViewRenderingComplete(()=>{
registry.script.tryRunTextViewHandler();
// 看脚本js是否给afterCallback ,如果有在此执行
if(this.afterCallback != null) this.afterCallback();
})
}
}
// 设置logo为运行图标
registry.view.logo.change("data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDM5IDM5IiB3aWR0aD0iMzkiIGhlaWdodD0iMzkiPgoJPHRpdGxlPuW+ruS/oeaIquWbvl8yMDIzMDgxODIzMDIxNzwvdGl0bGU+Cgk8ZGVmcz4KCQk8aW1hZ2UgIHdpZHRoPSIyMyIgaGVpZ2h0PSIyMyIgaWQ9ImltZzEiIGhyZWY9ImRhdGE6aW1hZ2UvcG5nO2Jhc2U2NCxpVkJPUncwS0dnb0FBQUFOU1VoRVVnQUFBQmNBQUFBWEFRTUFBQURhNUViakFBQUFBWE5TUjBJQjJja3Nmd0FBQUFOUVRGUkZ4MVJRaGlaMHV3QUFBQXhKUkVGVWVKeGpZS0FkQUFBQVhBQUJZNkd4Z1FBQUFBQkpSVTVFcmtKZ2dnPT0iLz4KCTwvZGVmcz4KCTxzdHlsZT4KCTwvc3R5bGU+Cgk8dXNlIGlkPSJCYWNrZ3JvdW5kIiBocmVmPSIjaW1nMSIgeD0iOCIgeT0iOCIvPgo8L3N2Zz4=")
try {
Function('obj',`(${jscript})(obj)`)({registry,cache,$,open,view})
} catch (error) {
setTimeout(()=>{alert("Ծ‸Ծ 你选择的是脚本项,而当前页面安全策略不允许此操作所依赖的函数!这种情况是极少数的,请换个页面试试!")},20)
console.logout("脚本执行失败!",error);
}
// logo图标还原
setTimeout(()=>{registry.view.logo.reset();},200)
return;
}else if(! isUrl(itemData.resource)) {
showTextPage(itemData.title,itemData.desc,itemData.resource)
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.subSearch.searchBoundary).length < 2
|| registry.searchData.keyword.split(registry.searchData.subSearch.searchBoundary)[1].trim() == "" ) {
url = registry.searchData.clearUrlSearchTemplate(initUrl);
}
// 跳转(url如果有模板,可能已经去掉模板,取决于是“搜索模式”)
window.open(url);
})
//registry.searchData.searchHandle = handler;
const refresh = debounce(handler, 300)
// 第一次触发 scroll 执行一次 fn,后续只有在停止滑动 1 秒后才执行函数 fn
searchInputDocument.on('input', refresh)
// 初始化后将isInitializedView变量设置为true
isInitializedView = true;
}
function ensureViewHide() {
// 隐藏视图
// 如果视图还没有初始化,直接退出
if (!isInitializedView) return;
// 如果正在查看查看“简讯”,先退出简讯
const nowMode = registry.view.seeNowMode();
if(nowMode === registry.view.modeEnum.SHOW_ITEM_DETAIL) {
// 让简讯隐藏
registry.view.element.textView.css({"display":"none"})
// 让搜索结果显示
registry.view.element.matchResult.css({ display:"block",overflow: "hidden" })
// 通知简讯back事件
registry.view.itemDetailBackAfterEventListener.forEach(listener=>listener())
return;
}
// 让视图隐藏
viewDocument.style.display = "none";
// 将输入框内容置空,在置空前将值备份,好让未好得及的操作它
searchInputDocument.val("")
// 将之前搜索结果置空
matchItems.html("")
// 隐藏文本显示视图
textView.css({
"display":"none"
})
// 让搜索结果隐藏
matchResult.css({
"display":"none"
})
// 视图隐藏-清理旧数据
registry.searchData.clearData();
// 触发视图隐藏事件
registry.view.viewHideEventAfterListener.forEach(fun=>fun());
}
function showView() {
// 让视图可见
viewDocument.style.display = "block";
//聚焦
searchInputDocument.focus()
// 当输入框失去焦点时,隐藏视图
searchInputDocument.blur(function() {
const isLogoButtonPressedRef = registry.view.logo.isLogoButtonPressedRef
if(isLogoButtonPressedRef.value) {
console.logout("隐藏跳过,因为isLogoButtonPressedRef")
return
};
setTimeout(function(){
const isDebuging = isInstructions("debug");
const isSearching = registry.searchData.searchEven.isSearching;
// 当前视图是否在展示数据,如搜索结果,简述内容?如果在展示不隐藏
let isWaitSearch = registry.view.seeNowMode() === registry.view.modeEnum.WAIT_SEARCH;
if(isDebuging || isSearching || !isWaitSearch || isLogoButtonPressedRef.value) {
console.logout("隐藏跳过,条件列表不满足!")
return
};
registry.view.viewVisibilityController(false);
},registry.view.delayedHideTime)
});
}
// 返回给外界控制视图显示与隐藏
return function (isSetViewVisibility) {
if (isSetViewVisibility) {
// 让视图可见 >>>
// 如果还没初始化先初始化 // 初始化数据 initData();
if (!isInitializedView) {
// 初始化视图
initView();
// 初始化数据
// initData();
}
// 让视图可见
showView();
} else {
// 隐藏视图 >>>
ensureViewHide();
}
}
})();
// 触发策略——快捷键
let useKeyTrigger = function (viewVisibilityController) {
let isFirstShow = true;
// 将视图与触发策略绑定
function showFun() {
// 让视图可见
viewVisibilityController(true);
// 触发视图首次显示事件
if(isFirstShow) {
for(let e of registry.view.viewFirstShowEventListener) 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);
}
})();
// 打开视图进行配置
// 显示配置视图
// 是否显示进度 - 进度控制
function clearCache() {
cache.remove(registry.searchData.SEARCH_DATA_KEY);
// 如果处于debug模式,也清理其它的
if(isInstructions("debug")) {
cache.remove(registry.searchData.CACHE_FAVICON_SOURCE_KEY);
}
// 触发缓存被清理事件
for(let fun of registry.searchData.dataCacheRemoveEventListener) fun();
}
GM_registerMenuCommand("订阅管理",function() {
showConfigView();
});
GM_registerMenuCommand("清理缓存",function() {
clearCache();
});
function giveTagsStatus(tagsOfData,userUnfollowList) {
// 赋予tags一个是否选中状态
// 将 userUnfollowList 转为以key为userUnfollowList的item.name值是Item的方便检索
let userUnfollowMap = userUnfollowList.reduce(function(result, item) {
result[item] = '';
return result;
}, {});
tagsOfData.forEach(item=>{
if(userUnfollowMap[item.name] != null ) {
// 默认都是选中状态,如果item在userUnfollowList上将此tag状态改为未选中状态
item.status = 0;
}
})
return tagsOfData;
}
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;
// 显示视图
// 用户维护的取消关注标签列表
let userUnfollowList = cache.get(registry.searchData.USER_UNFOLLOW_LIST_CACHE_KEY)?? registry.searchData.USER_DEFAULT_UNFOLLOW;
// 当前数据所有的标签
let tagsOfData = cache.get(registry.searchData.DATA_ITEM_TAGS_CACHE_KEY);
// 使用 userUnfollowList 给 tagsOfData中的标签一个是否选中状态,在userUnfollowList中不选中,不在选中,添加一个属性到tagsOfData用boolean表达
tagsOfData = giveTagsStatus(tagsOfData,userUnfollowList);
// 生成多选框html
let tagsCheckboxHtml = "";
tagsOfData.forEach(item=>{
tagsCheckboxHtml += `
`
})
DivPage(`
#my-search-view {
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;
button {
cursor: pointer;
}
._topController {
width: 100%;
position: absolute;
top: 0px;
right: 0px;
text-align: right;
padding: 15px 15px 0px;
box-sizing: border-box;
* {
cursor: pointer;
}
#topController_close {
font-sise: 15px;
color: #e8221e;
}
}
.page {
.control_title {
margin: 10px 0px 5px;
font-size: 17px;
color: black;
}
}
.home {
.submitable {
color: #3CB371;
}
.tagsCheckBoxDiv > div {
width: 32%;
display: inline-block;
margin: 0px;
padding: 0px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
#all_subscribe {
width: 100%;
height: 150px;
box-sizing: border-box;
border: 4px solid #f5f5f5;
}
#subscribe_save {
margin-top: 20px;
border: none;
border-radius: 3px;
padding: 4px 17px;
cursor: pointer;
box-sizing: border-box;
background: #6161bb;
color: #fff;
}
.view-base-button {
background: #fff;
border: none;
font-size: 15px;
padding: 1px 10px;
cursor: pointer;
margin: 2px;
color: black;
}
._topController span {
color: #3CB371;
}
.home label {
font-size: 13px;
}
}
.tis-hub {
.logo-search {
display: flex;
flex-direction: column;
align-items: center;
img {
display: block;
width: 40px;
height: 40px;
}
.keyword {
display: flex;
font-size: 12px;
width: 70%;
margin-top: 5px;
input {
border: none;
padding: 0 6px;
min-width: 100px;
line-height: 25px;
height: 25px;
flex-grow: 1;
}
button {
padding: 0 12px;
border: none;
background: #f0f0f0;
line-height: 25px;
height: 25px;
}
}
}
.search-type {
display: flex;
padding: 10px 0;
label {
display: flex;
align-items: center;
margin-right: 20px;
font-size: 14px;
input {
padding: 0;
margin: 0 3px 0 0;
}
}
}
.result-list {
min-height: 300px;
padding-top: 15px;
.hub-tis {
display: flex;
justify-content: space-between;
margin-bottom: 12px;
align-items: center;
button {
font-size: 10px;
line-height: 22px;
height: 22px;
padding: 0 15px;
border-radius: 3px;
border: none;
}
.tis-info {
display: flex;
flex-direction: column;
.title {
font-size: 14px;
font-weight: bold;
color: rgb(103, 0, 0);
}
.describe {
font-size: 12px;
font-weight: 400;
display: block;
font-size: smaller;
margin: 0.5em 0px;
color: #333333;
}
}
}
}
}
}
`,`
X
公共仓库:
关注标签:
${tagsCheckboxHtml}
`,function (selector,remove) {
let subscribe_text = selector("#all_subscribe");
let subscribe_save = selector("#subscribe_save");
let topController_close = selector("#topController_close");
let openTisHub = selector("#openTisHub");
let tisHubLink = "https://github.com/My-Search/TisHub/issues";
let pushTis = selector("#pushTis");
let commitableTisList = null;
let clearToken = selector("#clearToken");
let mySearchView = selector("#my-search-view");
let currentPage = setPage(); // 默认显示的是home页
// 刷新页
function setPage(page = "home") {
$(mySearchView).find('.page').hide().filter(`.${page}`).show();
}
setPage("home");
// 刷新视图状态
async function refreshViewState() {
// 更新token状态
$(clearToken).css({"display":GithubAPI.getToken() == null?"none":"inline-block"})
// 更新可提交数
let tisList = await TisHub.getTisHubAllTis();
if(tisList != null && tisList.length != 0) {
commitableTisList = TisHub.tisFilter(subscribe_text.value,tisList)??[]
$(pushTis).find("span").text(commitableTisList.length);
}
}
// 初始化subscribe_text的值
subscribe_text.value = getSubscribe();
// 初始化其它状态,通过调用refreshViewState()
refreshViewState();
// 当SubscribeText多行输入框内容发生改变时,刷新更新可提交数,通过调用refreshViewState()
let refreshSubscribeText = debounce(()=>{refreshViewState() }, 300)
subscribe_text.oninput = ()=>{refreshSubscribeText();}
// 保存
function configViewClose() {
remove();
}
// 点击保存时
subscribe_save.onclick=function() {
// 保存用户选择的关注标签(维护数据)
// 获取所有多选框元素
var checkboxes = selector(".tagsCheckBoxDiv input",true);
// 初始化已选中和未选中的数组
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 = subscribe_text.value;
let validCount = editSubscribe(allSubscribe);
// 清除视图
configViewClose();
// 清理缓存,让数据重新加载
clearCache();
alert("保存配置成功!有效订阅数:"+validCount);
}
// 打开TitHub
openTisHub.onclick = function() {
// window.open(tisHubLink, "_blank");
setPage("tis-hub");
}
// push到TisHub公共仓库中
pushTis.onclick =async function () {
if(! confirm("是否确认要提交到TisHub公共仓库?")) return;
if(commitableTisList == null || commitableTisList.length == 0) {
alert("经过与TisHub中订阅的比较,本地没有可提交的订阅!")
return;
}
if(GithubAPI.getToken(true) == null) {
alert("获取token失败,无法继续!");
return;
}
// 组装提交的body
let body = (()=>{
let _body = "";
for(let tis of commitableTisList) _body+=tis;
return _body;
})();
if ( body == "") return;
let userInfo = await GithubAPI.setToken().getUserInfo();
if(userInfo == null) {
alert("提交异常,请检查网络或提交的Token信息!")
return;
}
GithubAPI.commitIssues({
"title": userInfo.name+"的订阅",
"body": body
}).then(response=>{
refreshViewState();
alert("提交成功(issues)!感谢您的参与,脚本因你而更加精彩。")
}).catch(error=>alert("提交失败~"))
}
// 清理token
clearToken.onclick = function(){
GithubAPI.clearToken(); // 清理token
refreshViewState(); // 刷新视图变量
};
// 关闭
$(topController_close).click(configViewClose)
// 点击搜索tis-hub
let installedList = cache.get(registry.searchData.USE_INSTALL_TISHUB_CACHE_KEY) || []; // [ {name: "官方订阅",describe: "这是官方订阅...", body: "",status: ""} ] status: disable enable installable
let tisSearchInput = $(".tis-hub .keyword input");
let tisSearchBtn = $("#search-tishub");
let searchFun = async function() {
const keyword = tisSearchInput.val()?.trim() || '';
// 搜索类型(installed | market)
const searchType = $('.search-type input[name="search-type"]:checked').val();
let resultTisList = installedList.filter(item => keyword === "" || item.name.includes(keyword));
if(searchType === "market") {
let marketResult = await TisHub.getClosedIssuesTis({keyword})
marketResult = marketResult.map(hubTisInfo => {
return {
name: hubTisInfo.title,
describe: hubTisInfo.describe,
body: hubTisInfo.tisList.join('\n') || '',
state: "installable"
}
})
const installedMap = resultTisList.reduce((map, item) => {
map[item.name] = item;
return map;
}, {});
// 看本地是否已安装,如果已安装state就取已安装的项state
(resultTisList = marketResult).forEach(hubTis =>{
if(installedMap[hubTis.name]) hubTis.state = installedMap[hubTis.name].state;
});
}
// 列表渲染
const resultElement = $(".tis-hub .result-list > .list-rol");
resultElement.html('')
// 转状态名
function stateAsName(state) {
return (state === "disable" && "移除(未启用)") || (state === "enable" && "移除") || "安装";
}
for(let tis of resultTisList) {
// tis 有该订阅的名 tis.name
// tisMetaInfo 是tis.body 包含描述信息 tisMetaInfo.describe
const tisMetaInfo = new PageTextHandleChains(tis.body).parseAllDesignatedSingTags("tis")[0];
// 自己的搜索逻辑
if(! `${tis.name}`.includes(keyword) && (tisMetaInfo != null && ! `${tisMetaInfo.describe}`.includes(keyword))) return;
// 渲染到页面
resultElement.append(`
${tis.name}
${tisMetaInfo.describe || '订阅没有描述信息,请确认订阅安全或信任后再安装!'}
`)
}
// 当点击tis-button按钮时
$(".hub-tis .tis-button").click(function() {
// 使用 $(this) 获取当前被点击的元素
const button = $(this);
const tisName = button.attr("tis-name");
let tis = installedList.find(item=>item.name === tisName);
if(tis != null) {
// 移除
installedList = installedList.filter(item => item.name !== tisName);
tis.state = "installable";
}else {
// 安装
const hubTis = resultTisList.find(item=>item.name === tisName);
hubTis.state = "enable";
installedList.unshift(tis = hubTis);
}
// 更新状态
button.html(stateAsName(tis.state));
// 保存
console.log("保存:",installedList)
cache.set(registry.searchData.USE_INSTALL_TISHUB_CACHE_KEY,installedList);
// 清理缓存
clearCache()
});
}
// 点击搜索
const searchButton = tisSearchBtn.click(searchFun).click();
// 回车键触发搜索
tisSearchInput.on("keydown", function(event) {
if (event.key === "Enter") {
searchFun(); // 调用搜索功能
}
});
// 单选框值改变时,搜索
const radioButtons = document.querySelectorAll('input[name="search-type"]');
radioButtons.forEach(radio => {
radio.addEventListener('change', function() {
if (this.checked) {
searchButton.click();
}
});
});
})
}
})(unsafeWindow);
// unsafeWindow是真实的window,作为参数传入