// ==UserScript==
// @name SearchEngineJumpPlus International
// @author KParthSingh & NLF & 锐经(修改) & iqxin(修改) & MUTED64(修改)
// @contributor KParthSingh
// @description This is like a International version of original chinese SearchEngineJumpPlus by https://github.com/MUTED64/SearchEngineJumpPlus
// @version 1.3
// @namespace https://greasyfork.org/en/scripts/484068-searchenginejumpplus/
// @homepage https://github.com/KParthSingh/SearchEngineJumpPlus-International
// @require https://greasyfork.org/scripts/408009-togbk/code/toGBK.js?version=832799
// @require https://update.greasyfork.org/scripts/484066/EngineListForSearchEngineJumpPlus.js
// @require https://update.greasyfork.org/scripts/484072/RulesForSearchEngineJumpPlus.js
// @resource GLOBAL_STYLE https://raw.githubusercontent.com/KParthSingh/SearchEngineJumpPlus-International/master/GlobalStyle.css
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAFSElEQVR4nMWXX4hdVxXGf2vfe89kJg61ia0DYzMTMWnoQ0FJtKmtJsFixT8DBSmYtGMLgq0PCqMEKwmxYzSGyUPBB7XRNi0FC6JtwYovgcS0klJD8SHakoExYhLQFkwn9/aeOfv7fDi3SStJ5o4muN4O7L32b33rz94H/s8WS10cvR3yVQaY++wnkESkwDK2sMy1EwXDtzRRziBhu+dGDG48smSA5kUP//wmAFIkrNwiGMOsBzYAQwTzEEeBY8BJO1fYtF+4laGPv/i/Afz1C1sAYwngZiKmsDcDI0DrHUtL4DRwMGAmUnVcCtpHPsrQbS/1DZDe+VFHblKziIjYBjwD3Iu5ARBwBjgJnAkwMAa+z+ZZqXEX8VZg0T784aUDzH3uk0DtVQvlVsMjwGpMB3gauAu8ieB2YDPwxR5gF/gQ+MeoNUFzACI4d+imvgDOp0BVRWo2AW62eRi8wvY/wNtrgGhDL+7a/gIcBLYBu4HrsPdSzr8K/JlcLk2BaCQstSxN2VptuYO93an7WES0UyORGg1Wfu0QKivyQhfb56yhn4B3Ynew1kD1oDTfJF20vi8NYBvjMVubbWHrOdtPhwaAYPVvfs8Hf1u32bJbDtXVbgFvAj4AOgTGzhPhGMdV/wCvbtmAJSyttzRiuWv7CdttAlY/f/iimwdvfQGiAfmtczg/jnOJ8/txtRbnvgAu6FSPtg1AC3wGPAvgWGRYqiSowLwC1Ru4GoFyFPc3ZM8DfGPLB1jZXlhe74sS6AAc+O6vL+tg6LaX2LP/SSA6tkpcYeee36/0D/C7Ve9BwZs97iLMEMDAE5N07z1wSQebvl/y3KkAGDIUsrHpRp8ACeDGw38kZdPMPtrILhvZ1yZ5TZJxvnwuW40GzSSaDa1vJq1oJXVbKZ9qpv5qoO6Cqr5ULB+zfNrygOX7LS+PlCgeu+eimz/1w0yWaTTScIqYTEERcDoiXovFauddAAA22CeRDyKD/Bnkbd32PNgUj09S/GwrUMt+x14hiWVFI1LEVyPidggi4hfOnuv3nr8AEGC5sj1j+4TtAcu7i4HlDwLLqRawMmtmnidn6JYLGIa7C/mbwHeAgYATQexPjVCVxcZd7SUACDCEfRyznXoMr8Sawf4lcDdwI7AKWAdss/0r2dOyr6kFpCn7hiyPRlDY5mM7z10W4F1KFT+/p6ZwDkgT2HuN19Tz3yXWG+NnJ8uR9h0FSStSRAFBwAmbpu3xbP/T9rzkp2zvtt2RzcvfG15EAaC8/8m6FkgmpWdsTyD/COtv9esnj1haZXvEtiXP2d5jc6es+3qHv8/2uO1v2d4hedA2H/n2vxZX4LwS+78E1PcDqprAOPZao9Gxs5PNkc6dXUKnIuI1Z8+lRijLo8AR2+OWqeeBS8n7bE8bd2x4Zc97FwcAaP307vqyiXi7QzBi7OyXGel8GkJEBAFUWUREIXlnL/LCvgBheZ9h2lLHyvxp5rrFAZZiG3e16zliBm3vsD0lu6i5ja0awppWrjrKmeOPjAL/UQP/rf1h11BPJHckT/dkL+vDjeXC0pRy3qGcB22x9oHZKwcAcPTh5UimzrWnexGXlrCFlAvlakq5eiiX3eLtSXnFAABe3j1c/0PgTp1z77NUKmesjHMulKuttq9X/eq+sgAAx35wTZ0OqWNrWqr2KVelqoqcF3DOL1r5dStfHQCoW03K9ApuWrnam/PCnHN+StZDRHSK1jLgCnXBpeymr/8dS+SFbmH7eiu/TkQnNRrkqmL20XVXFwBg7QOzRASSsDJFaxndssPso+uu9tH92b8BowSyPc/iZtEAAAAASUVORK5CYII=
// @license MIT
// @noframes
// @match *://**/*
// @exclude *://mega.nz/*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_addStyle
// @grant GM_deleteValue
// @grant GM_setClipboard
// @grant GM_registerMenuCommand
// @grant GM_openInTab
// @grant GM_getResourceText
// @grant GM_info
// @grant window.onurlchange
// @run-at document-idle
// ==/UserScript==
(function () {
"use strict";
startScript();
listenUrlChange();
// For some websites with iframe and some websites need delay to load
function startScript() {
if (window.self != window.top) return;
console.info(
`\n%c ${GM_info.script.name} v${GM_info.script.version} \n%c 问题反馈(GitHub):\t\thttps://github.com/MUTED64/SearchEngineJumpPlus/issues/new\t\t\t\t\t\t\t\n%c 问题反馈(GreasyFork):\thttps://greasyfork.org/scripts/454280-searchenginejumpplus-搜索引擎快捷跳转/feedback\t\n`,
"color:#eee;background:#444;padding:6px 0;border-radius:6px 6px 0 0;",
"color:#444;background:#eee;padding:6px 0;border-radius:0 6px 0 0",
"color:#444;background:#eee;padding:6px 0;border-radius:0 0 6px 6px;"
);
const delayList = [
/^https?:\/\/google\.infinitynewtab\.com\/\?q/,
/^https?:\/\/www\.zhihu\.com\/search\?/,
/^https?:\/\/www\.iciba\.com\/word\?/,
/^https?:\/\/neeva\.com\/search\?/i,
/^https?:\/\/s\.taobao\.com\/search/,
/^https?:\/\/y\.qq\.com\/n\/ryqq\/search/i,
/^https?:\/\/www\.quora\.com\/search\?/i,
/^https?:\/\/search\.bilibili\.com\/*/,
/^https?:\/\/github\.com/i,
/^https?:\/\/(www\.)?baidu\.com/i,
];
const needDelay = delayList.some(
(delaySite) => location.href.search(delaySite) !== -1
);
if (needDelay) {
setTimeout(function () {
const isRunning = document.querySelector("sejspan");
if (isRunning) {
return;
} else {
mainLogic();
}
}, 1000);
} else {
mainLogic();
}
}
// For SPA websites with javascript router
function listenUrlChange() {
if (window.onurlchange === null) {
let lastURL = decodeURI(location.href).replaceAll(" ", "+");
window.addEventListener("urlchange", (e) => {
const newURL = decodeURI(e.url).replaceAll(" ", "+");
if (lastURL === newURL) return;
lastURL = newURL;
document.querySelectorAll("sejspan")?.forEach((i) => i.remove());
startScript();
});
}
}
function mainLogic() {
const rules = searchEngineJumpPlusRules;
let engineList = searchEngineJumpPlusEngines;
// 有些图标需要重复使用
const icon = {
edit: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAACDklEQVR4nJXVzUtUURjH8Y/mSNKkki2iwiApxHQ1q/6C+gusoCB6oxbRRqFNL4sWtRKqhVSLIDe1CqpNiwjKIilKLKKFEr2Z2qI0xxHN0+LOm+PMOPOc1T2H7/f5ncO991BdNer30zmxKrl0xV2zKJjRoy6aqkkvbbdVLPuUq+8+5uGXnVILki7qsxgtNDtrTNLcijHvrdYsft0/wQ8DZgSzeqMUDW4IJceYHcvwCd1ies0KZvWI1TnhIH6574Olgg0E74zmhZ902j304by4Cxp5LPjtQNmjy3XPVK2rgmCBCcGgdVXhdBgUBCMEwVMNVeIvBMFLifKC8vgrndFBlRJUhJcWFMd3ZfGuzFRxwWrdu3KTxQQVhi8lqApfKVhf0d4bc2/OckG9Pkur7r3TEw+1FRO0GxdM2Vc2/HHBgr1If935UTfigbt5+C27MeSo9+m5GJYitlCwWR2G8oQZ/FgWX1aFgnZMG852v5nFR4rhMn+2dDVJYFpKqy0SDksUhF9FsE0bWgyIa9bIanihoEUcDTrSz4ueOVMOLxQkzVkrZcaoNz755rmpcnihYNghm3w26Ys/5cGcIKgRBJDyqCIquj8C1PqKZvHK+qVrJ5bMRwmGterU64pkkZupWO3RjXkzUZj9+jVZMGK6IsEaHTbgjpOSUYZL/pa5m4qPIbtyznpHvJaqGB53O33h4T/3VzLuzDhE6AAAAABJRU5ErkJggg==",
del: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAADAFBMVEUAAADsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVH///9VVVVWVlZXV1dYWFhZWVlaWlpbW1tcXFxdXV1eXl5fX19gYGBhYWFiYmJjY2NkZGRlZWVmZmZnZ2doaGhpaWlqampra2tsbGxtbW1ubm5vb29wcHBxcXFycnJzc3N0dHR1dXV2dnZ3d3d4eHh5eXl6enp7e3t8fHx9fX1+fn5/f3+AgICBgYGCgoKDg4OEhISFhYWGhoaHh4eIiIiJiYmKioqLi4uMjIyNjY2Ojo6Pj4+QkJCRkZGSkpKTk5OUlJSVlZWWlpaXl5eYmJiZmZmampqbm5ucnJydnZ2enp6fn5+goKChoaGioqKjo6OkpKSlpaWmpqanp6eoqKipqamqqqqrq6usrKytra2urq6vr6+wsLCxsbGysrKzs7O0tLS1tbW2tra3t7e4uLi5ubm6urq7u7u8vLy9vb2+vr6/v7/AwMDBwcHCwsLDw8PExMTFxcXGxsbHx8fIyMjJycnKysrLy8vMzMzNzc3Ozs7Pz8/Q0NDR0dHS0tLT09PU1NTV1dXW1tbX19fY2NjZ2dna2trb29vc3Nzd3d3e3t7f39/g4ODh4eHi4uLj4+Pk5OTl5eXm5ubn5+fo6Ojp6enq6urr6+vs7Ozt7e3u7u7v7+/w8PDx8fHy8vLz8/P09PT19fX29vb39/f4+Pj5+fn6+vr7+/v8/Pz9/f3+/v7///8dej9TAAAAU3RSTlMAAABm7P/sZgAAABPO////zhQAAB/i/////////+IfAAAe4fvk4AAAAAAd/+Q3GxwAFR85FQBjz+LPY+v////r6//////rZM/h4c9jABUdHRUAAP0EcPoAAAEuSURBVHic7ZRnc8IwDIbdEUZHGB0kDsMOMcOMttBBB93Qvcj//y9VjB0Czh13/dz3ixT5OVmSYyMktLK6tm74oYxEMpVGUW1sbm2bM8DMZHP5OWBnd2+/YNnYAWHbKhRL5cocQKjrWFWPuSDmVS3HpUQu1eoNQkiTM9xqd7oHoG6n3cKMNyHcqNfQ4VGPUsr7nh0FbK/PIdw7PkGnZwOZNrqF9AfnF+jyaigLixYp/eH1Dbq9u4eAHyOAHh5HaPz0DCnjANjm5fUNvX98QoGCxyo5Fjmh0K/vH2hzAi0KnqnymMgJrU6gzemQBM+DZpX1/XBYUyAYTTAuZTUg+Aw8Zf+BvwJLR730sPTjXgD0H2YB0BUClXKpGAeE1y+fy2ZMfX12gdOpZMLQAfkE/AL7e5vGZF+dOQAAAABJRU5ErkJggg==",
setting: `<svg style="width: 16px;" class="icon" id="sej-setting-button" viewBox="0 0 512 512"><path d="M262.29 192.31a64 64 0 1057.4 57.4 64.13 64.13 0 00-57.4-57.4zM416.39 256a154.34 154.34 0 01-1.53 20.79l45.21 35.46a10.81 10.81 0 012.45 13.75l-42.77 74a10.81 10.81 0 01-13.14 4.59l-44.9-18.08a16.11 16.11 0 00-15.17 1.75A164.48 164.48 0 01325 400.8a15.94 15.94 0 00-8.82 12.14l-6.73 47.89a11.08 11.08 0 01-10.68 9.17h-85.54a11.11 11.11 0 01-10.69-8.87l-6.72-47.82a16.07 16.07 0 00-9-12.22 155.3 155.3 0 01-21.46-12.57 16 16 0 00-15.11-1.71l-44.89 18.07a10.81 10.81 0 01-13.14-4.58l-42.77-74a10.8 10.8 0 012.45-13.75l38.21-30a16.05 16.05 0 006-14.08c-.36-4.17-.58-8.33-.58-12.5s.21-8.27.58-12.35a16 16 0 00-6.07-13.94l-38.19-30A10.81 10.81 0 0149.48 186l42.77-74a10.81 10.81 0 0113.14-4.59l44.9 18.08a16.11 16.11 0 0015.17-1.75A164.48 164.48 0 01187 111.2a15.94 15.94 0 008.82-12.14l6.73-47.89A11.08 11.08 0 01213.23 42h85.54a11.11 11.11 0 0110.69 8.87l6.72 47.82a16.07 16.07 0 009 12.22 155.3 155.3 0 0121.46 12.57 16 16 0 0015.11 1.71l44.89-18.07a10.81 10.81 0 0113.14 4.58l42.77 74a10.8 10.8 0 01-2.45 13.75l-38.21 30a16.05 16.05 0 00-6.05 14.08c.33 4.14.55 8.3.55 12.47z" fill="none" stroke="var(--font-color-qxin)" stroke-linecap="round" stroke-linejoin="round" stroke-width="42"/></svg>`,
};
const scriptSettingData = {
status: 1,
message:
"$相关说明$(status: 这个在将来或许很重要)..." +
"(version: 若有新功能加入,靠这个版本号识别)..." +
"(addSearchItems: 允许更新时,添加新的搜索网站到你的搜索列表)..." +
"(modifySearchItems: 允许更新时,修改你的搜索列表中的项目)..." +
"(closeBtn: 设置页面右上角的“关闭”按钮是否显示。true显示,false隐藏)..." +
"(newtab: 新标签页打开。0为默认设置,1为新标签页打开)..." +
"(foldlist: 折叠当前搜索分类列表。true为折叠,false为展开。)..." +
"(setBtnOpacity: 设置按钮的透明度,值为0-1之间的数,0为透明,1为完全显示,中间值半透明。注:-1为直接关闭按钮,关闭之前请确定自己知道如何再次打开它)..." +
"(debug: debug模式,开启后,控制台会输出一些信息,“关闭并保存”按钮将不会在刷新页面)..." +
"(fixedTop: 将搜索栏固定到顶端。 true开启,false关闭)..." +
"(fixedTopUpward: 固定顶端后,搜索栏下拉不会出现,只有上拉时才出现。 true开启,false关闭)..." +
"(baiduOffset: 在百度页面鼠标划过的菜单会出现位移,若有使用其他的style样式,可以修改这个来修复二级菜单的偏移)..." +
"(getIcon: 自己添加搜索后获取图标的方式。0为自动,能连接谷歌的情况下用谷歌获取,无法连接的情况下,域名加favicon.ico获取;1为域名加favicon获取,2为使用谷歌获取,3为使用dnspot的服务获取(不建议使用)。或者添加网址,关键字使用%s代替,未测试)..." +
"(allOpen:一键搜索,点击相关分类后,打开该分类下的所有搜索)..." +
"(HideTheSameLink:隐藏同站链接。默认开启,百度页面会隐藏百度搜索。如果想在同一个搜索网站,但是想通过不同语言来搜索, 可以选择false来实现)..." +
"(center:是否居中显示,主要是为了兼容脚本 ac 百度 : 0 不居中,强制在左。 1, 强制居中 。 2,自动判断)..." +
"(icon: 图标的显示方式, 0 关闭文字, 只保留图标, 1 显示网站图标,2 显示抽象图标。当脚本中不存在抽象图标时,显示网站图标)..." +
"(transtion: 是否有动画效果, true为开启所有动画效果,false关闭所有动画(包括模糊效果)。)" +
"(selectSearch: 划词搜索功能, true为开启划词搜索,false关闭)" +
"(engineDetails: 第一个值为分类列表标题名称,第二个值与enginelist相关联,必须匹配,第三个值true为显示列表,false为禁用列表。排列顺序与跳转栏上的显示顺序相同,可以用它将分类列表按自己喜欢排序)..." +
"(engineList: 各个搜索的相关信息)" +
"(rules: 已弃用--将搜索样式插入到目标网页,同脚本中的rules设置相同,优先级高于脚本中自带的规则。自带了360搜索,可仿写)...",
version: GM_info.script.version,
addSearchItems: true,
modifySearchItems: true,
closeBtn: true,
newtab: 0,
foldlist: true,
setBtnOpacity: 0.7,
debug: false,
fixedTop: true,
fixedTopUpward: false,
baiduOffset: -120,
getIcon: 0,
allOpen: false,
HideTheSameLink: true,
center: 2,
icon: 1,
transtion: true,
selectSearch: true,
engineDetails: [
["Search", "web", true],
["Translate", "translate", true],
["Video", "video", true],
["Music", "music", true],
["Social", "sociality", true],
["Knowledge", "knowledge", true],
["Image", "image", true],
["Shopping", "shopping", true],
["News", "news", true],
["Other", "mine", false],
["Placeholder", "download", false],
],
engineList: engineList,
};
// --------------------可设置项结束------------------------
class Settings {
#storedSettingData = GM_getValue("searchEngineJumpData");
#scriptSettingData = scriptSettingData;
settingData;
constructor() {
this.initSettings();
}
#isVersionOutdated(storedSettingVersion, currentVersion) {
storedSettingVersion = storedSettingVersion.toString();
currentVersion = currentVersion.toString();
const arr1 = storedSettingVersion.split(".");
const arr2 = currentVersion.split(".");
const length1 = arr1.length;
const length2 = arr2.length;
const minlength = Math.min(length1, length2);
let i = 0;
for (i; i < minlength; i++) {
let a = parseInt(arr1[i]);
let b = parseInt(arr2[i]);
if (a > b) {
return false; // 版本超前
} else if (a < b) {
return true; // 版本过时
}
}
if (length1 > length2) {
for (let j = i; j < length1; j++) {
if (parseInt(arr1[j]) != 0) {
return false; // 版本超前
}
}
return false; // 版本相同
} else if (length1 < length2) {
for (let j = i; j < length2; j++) {
if (parseInt(arr2[j]) != 0) {
return true; // 版本过时
}
}
return false; // 版本相同
}
return false; // 版本相同
}
#checkSettingDataIntegrity() {
for (const value in this.#scriptSettingData) {
if (!this.settingData.hasOwnProperty(value)) {
console.warn(`属性不存在:${value}`);
this.settingData[value] = this.#scriptSettingData[value];
GM_setValue("searchEngineJumpData", this.settingData);
}
}
}
#checkUpdate() {
if (
this.#isVersionOutdated(
this.#storedSettingData.version,
this.#scriptSettingData.version
)
) {
this.settingData.version = this.#scriptSettingData.version;
this.settingData.message = this.#scriptSettingData.message;
// 5.29.9 更新
if (
this.settingData.setBtnOpacity === "0.2" &&
this.#isVersionOutdated(this.#storedSettingData.version, "5.29.9")
) {
this.settingData.setBtnOpacity = "0.7";
}
// 5.30.2 更新
if (
this.#isVersionOutdated(this.#storedSettingData.version, "5.30.2")
) {
this.deleteOutdatedSearchItems(["https://so.letv.com/s?wd=%s"]);
this.modifyOutdatedSearchItems(
"https://s.weibo.com/weibo/%s",
"https://s.weibo.com/weibo/?q=%s"
);
}
// 5.30.4 更新
if (
this.#isVersionOutdated(this.#storedSettingData.version, "5.30.4")
) {
this.modifyOutdatedSearchItems(
"https://www.startpage.com/do/asearch$post$query",
"https://www.startpage.com/sp/search$post$query"
);
}
// 5.31.1 更新
if (
this.#isVersionOutdated(this.#storedSettingData.version, "5.31.1")
) {
this.modifyOutdatedSearchItemsTarget("https://zh.moegirl.org/%s");
this.modifyOutdatedSearchItemsTarget(
"https://tieba.baidu.com/f?kw=%s&ie=utf-8"
);
this.modifyOutdatedSearchItemsTarget(
"https://github.com/search?utf8=✓&q=%s"
);
}
// 5.31.8 更新
if (
this.#isVersionOutdated(this.#storedSettingData.version, "5.31.8")
) {
this.modifyOutdatedSearchItems(
"https://cn.bing.com/search?q=%s",
"https://www.bing.com/search?q=%s"
);
}
console.info(
`\n%c ${GM_info.script.name} 设置已更新 \n%c 本地设置版本号:\t\t${
this.#storedSettingData.version
}\t\t\t\t\t\t\t\n%c 当前版本号:\t\t\t${
this.settingData.version
}\t\t\t\t\t\t\t\n`,
"color:#eee;background:#444;padding:6px 0;border-radius:6px 6px 0 0;",
"color:#444;background:#eee;padding:6px 0;border-radius:0 6px 0 0",
"color:#444;background:#eee;padding:6px 0;border-radius:0 0 6px 6px;"
);
GM_setValue("searchEngineJumpData", this.settingData);
}
}
initSettings() {
if (this.#storedSettingData) {
this.settingData = Object.assign({}, this.#storedSettingData);
this.#checkSettingDataIntegrity();
this.#checkUpdate();
} else {
this.settingData = this.#scriptSettingData;
GM_setValue("searchEngineJumpData", this.settingData);
}
this.initEngineCategories();
}
initEngineCategories() {
this.settingData.engineList.engineCategories = [];
for (
let engineCategoryIndex = 0;
engineCategoryIndex < this.settingData.engineDetails.length;
engineCategoryIndex++
) {
if (this.settingData.engineDetails[engineCategoryIndex][2]) {
this.settingData.engineList.engineCategories[engineCategoryIndex] =
this.settingData.engineDetails[engineCategoryIndex];
} else {
this.settingData.engineList.engineCategories[-engineCategoryIndex] =
this.settingData.engineDetails[engineCategoryIndex];
}
}
}
getMatchedRule() {
for (const rule of [...rules]) {
if (rule.url.test(location.href)) {
return rule;
}
}
return null;
}
addSearchItem(newItem, category) {
this.settingData.engineList[category].push(newItem);
}
// 更新已过期的搜索链接
modifyOutdatedSearchItems(oldURL, newURL) {
for (const value in this.settingData.engineList) {
var item = this.settingData.engineList[value];
for (let i = 0; i < item.length; i++) {
if (item[i].url === oldURL) {
item[i].url = newURL;
}
}
}
}
// 更新搜索target 不为 _blank
modifyOutdatedSearchItemsTarget(url) {
for (const value in this.settingData.engineList) {
var item = this.settingData.engineList[value];
for (let i = 0; i < item.length; i++) {
if (item[i].url === url) {
delete item[i].blank;
}
}
}
}
deleteOutdatedSearchItems(urlList) {
for (const value in this.settingData.engineList) {
var item = this.settingData.engineList[value];
for (let i = 0; i < item.length; i++) {
if (urlList.includes(item[i].url)) {
console.warn("删除搜索引擎:" + item[i].name);
item.splice(i, 1);
}
}
}
}
// 更新图标
modifyOutdatedSearchItemsIcon(url, newIcon) {
for (let i = 0; i < this.settingData.engineList.length; i++) {
if (this.settingData.engineList[i].url == url) {
//用户可能自己更改网站名称,所以此处用url来匹配
this.settingData.engineList[i].favicon = newIcon;
}
}
}
// 更新本地 rule
modifyOutdatedSearchItemsRule(name, value) {
var oldRule = this.settingData.rules;
for (let item in oldRule) {
if (oldRule[item].name == name) {
console.log("匹配成功, 更新 rule : ", name);
oldRule[item] = value;
}
}
}
}
class DropDownList {
zIndex = 100000001;
hidden = true;
showDelay = 233;
hideDelay = 233;
aShownClass = "sej-drop-list-trigger-shown";
constructor(a, list) {
this.a = a;
this.list = list;
this.init();
}
init() {
var a = this.a;
var list = this.list;
var self = this;
// 关闭动画
if (!settingData.transtion) {
this.showDelay = 0;
this.hideDelay = 0;
}
// 进入显示
a.addEventListener("mouseenter", function () {
clearTimeout(self.hideTimerId);
if (self.hidden) {
self.showTimerId = setTimeout(function () {
self.show();
}, self.showDelay);
} else {
var style = list.style;
style.top = parseFloat(list.style.top) - 6 + "px";
style.zIndex = this.zIndex + 1;
style.opacity = 1;
}
});
// 离开隐藏
a.addEventListener("mouseleave", function () {
clearTimeout(self.showTimerId);
if (!self.hidden) {
list.style.top = parseFloat(list.style.top) + 6 + "px";
list.style.opacity = 0.04;
self.hideTimerId = setTimeout(function () {
self.hide();
}, self.hideDelay);
}
});
list.addEventListener("mouseenter", function () {
clearTimeout(self.hideTimerId);
var style = list.style;
style.zIndex = this.zIndex + 1;
style.opacity = 1;
style.top = parseFloat(list.style.top) - 6 + "px";
});
list.addEventListener("mouseleave", function () {
list.style.opacity = 0.04;
list.style.top = parseFloat(list.style.top) + 6 + "px";
self.hideTimerId = setTimeout(function () {
self.hide();
}, self.hideDelay);
});
}
show() {
if (!this.hidden) return;
this.hidden = false;
var scrolled = this.#getScrolled();
var aBCRect = this.a.getBoundingClientRect();
var thisBCRect = this.a.parentNode.getBoundingClientRect();
var style = this.list.style;
var top = scrolled.y + aBCRect.bottom;
var left = scrolled.x + aBCRect.left;
style.top = top + 6 + "px";
style.left = left + "px";
style.zIndex = this.zIndex - 1;
style.display = "block";
// 二级搜索居中显示
style.left =
left -
(this.list.getBoundingClientRect().width - aBCRect.width) / 2 +
"px";
setTimeout(function () {
style.opacity = 1;
style.top = top + "px";
}, 30);
this.a.classList.add(this.aShownClass);
}
hide() {
if (this.hidden) return;
this.hidden = true;
var style = this.list.style;
style.display = "none";
style.opacity = 0.2;
this.a.classList.remove(this.aShownClass);
}
// 获取已滚动的距离
#getScrolled(container) {
if (container) {
return {
x: container.scrollLeft,
y: container.scrollTop,
};
}
return {
x:
"scrollX" in window
? window.scrollX
: "pageXOffset" in window
? window.pageXOffset
: document.documentElement.scrollLeft || document.body.scrollLeft,
y:
"scrollY" in window
? window.scrollY
: "pageYOffset" in window
? window.pageYOffset
: document.documentElement.scrollTop || document.body.scrollTop,
};
}
}
class SettingButton {
settingButtonElement;
constructor(jumpBarContainer, settingData) {
this.parentJumpBarContainer = jumpBarContainer;
this.settingData = settingData;
this.#addButtonToJumpBar();
this.settingButtonElement?.addEventListener("click", () =>
this.#activateSettingButton()
);
GM_registerMenuCommand("Settings", () => this.#activateSettingButton());
}
#addButtonToJumpBar() {
if (this.settingData.setBtnOpacity >= 0) {
this.settingButtonElement = document.createElement("span");
this.settingButtonElement.id = "setBtn";
this.settingButtonElement.title = "Settings";
GM_addStyle(`#setBtn{opacity: ${this.settingData.setBtnOpacity};}`);
this.settingButtonElement.innerHTML = icon.setting;
this.parentJumpBarContainer.appendChild(this.settingButtonElement);
}
}
#activateSettingButton() {
if (!this.settingPanel) {
document.querySelector("#settingLayerMask")?.remove();
this.settingPanel = new SettingPanel();
}
this.settingPanel.show();
}
}
class JumpBar {
engineButtonTemplate =
'<a class="sej-engine" target="$blank$" data-iqxincategory="$category$" encoding="$encoding$" gbk="$gbk$" url="$url$"><img src="$favicon$" class="sej-engine-icon" />$name$</a>';
dropDownLists = [];
container;
inputTarget;
insertTarget;
insertPositionLabel;
matchedRule;
engineList;
settingData;
constructor(engineList, settingData, matchedRule) {
this.engineList = engineList;
this.settingData = settingData;
this.matchedRule = matchedRule;
const inited = this.#initContainer();
if (inited === false) return;
this.#initEngines();
this.#addEnginesToDOM();
this.#addStyle();
if (this.settingData.fixedTop && this.matchedRule) {
const originalContainerDistanceTop =
this.container.getBoundingClientRect().top + window.scrollY;
// 判断是否需要只在向上滚动时显示
if (this.settingData.fixedTopUpward) {
window.onwheel = document.onwheel = (e) => {
e.wheelDelta > 0
? this.#fixedToTop(
this.matchedRule.fixedTop,
this.matchedRule.fixedTopColor,
originalContainerDistanceTop
)
: {};
};
} else {
window.onscroll = () => {
this.#fixedToTop(
this.matchedRule.fixedTop,
this.matchedRule.fixedTopColor,
originalContainerDistanceTop
);
};
}
}
document.querySelectorAll("sejspan a.sej-engine").forEach((engine) => {
engine.addEventListener("mousedown", (e) => {
this.#jumpToSelectedEngine(e);
});
});
}
#initContainer() {
if (this.matchedRule?.enabled) {
this.inputTarget = this.#getInputTarget();
this.insertTarget = this.#getInsertTarget();
this.insertPositionLabel = this.#getInsertPositionLabel();
if (this.inputTarget && this.insertTarget) {
this.#createContainerDOM();
} else {
console.warn(
`未找到输入框或插入位置,跳过初始化:\n输入框:${this.inputTarget}\n插入位置:${this.insertTarget}`
);
}
} else if (this.#isOnSelectSearchMode()) {
this.inputTarget = {};
this.insertTarget = document.body;
this.insertPositionLabel = "beforeend";
this.#createContainerDOM();
this.container.classList.add("selectSearch");
document.addEventListener("selectionchange", () =>
this.#toggleSelectSearchJumpBar()
);
} else {
console.info("未启用搜索跳转,跳过初始化");
return false;
}
this.matchedRule?.class
? (this.container.className += ` ${this.matchedRule.class}`)
: {};
// 由于与要插入网页的样式无法很好的兼容,更改源网页的样式
if (this.matchedRule?.stylish) {
GM_addStyle(this.matchedRule.stylish);
}
return true;
}
#createContainerDOM() {
this.container = document.createElement("sejspan");
this.container.id = "sej-container";
this.container.className = "rwl-exempt";
if (
this.matchedRule?.style.includes("sticky") ||
this.matchedRule?.style.includes("fixed")
) {
this.containerWrapper = this.container;
} else {
this.containerWrapper = document.createElement("sejspan");
this.containerWrapper.id = "sej-container-wrapper";
this.containerWrapper.appendChild(this.container);
}
}
#toggleSelectSearchJumpBar() {
const selection = getSelection();
if (selection.isCollapsed) {
this.container.style.top = "-50px";
} else {
this.inputTarget.textContent = selection.toString();
this.container.style.top = "2px";
}
}
#isOnSelectSearchMode() {
if (
(!this.matchedRule || !this.matchedRule.enabled) &&
this.settingData.selectSearch
) {
return true;
}
}
#getInputTarget() {
return typeof this.matchedRule?.insertIntoDoc.keyword == "function"
? this.matchedRule.insertIntoDoc.keyword
: this.#getElementBySelector(this.matchedRule?.insertIntoDoc.keyword);
}
#getInsertTarget() {
return typeof this.matchedRule?.insertIntoDoc.target == "function"
? this.matchedRule.insertIntoDoc.target()
: this.#getElementBySelector(this.matchedRule?.insertIntoDoc.target);
}
#getInsertPositionLabel() {
return this.matchedRule?.insertIntoDoc.where.toLowerCase();
}
#initEngines() {
const self = this;
this.engineList.engineCategories.forEach(function (item) {
// console.log(item); // 搜索菜单 ["search", "web", true]
const category = item[1]; // "web"
const cName = item[0]; // "search"
let engines = [];
self.engineList[category].forEach(function (engine) {
const engineUrl = engine.url;
if (engine.disable) return;
if (
self.settingData.HideTheSameLink &&
self.matchedRule?.url.test(engineUrl)
)
return; // 去掉跳转到当前引擎的引擎
let engineListButton = self.engineButtonTemplate
.replace("$encoding$", (engine.encoding || "utf-8").toLowerCase())
.replace("$url$", engineUrl)
.replace("$name$", engine.name)
.replace("$category$", category);
// 图标
if (engine.favicon) {
engineListButton = engineListButton.replace(
"$favicon$",
engine.favicon
);
} else {
engineListButton = engineListButton.replace(
'src="$favicon$"',
""
);
}
// gbk编码
if (engine.gbk) {
engineListButton = engineListButton.replace("$gbk$", engine.gbk);
} else {
engineListButton = engineListButton.replace('gbk="$gbk$"', "");
}
// 新标签页
if (settingData.newtab || engine.blank) {
engineListButton = engineListButton.replace("$blank$", "_blank");
} else {
engineListButton = engineListButton.replace(
'target="$blank$"',
""
);
}
engines.push(engineListButton);
});
// 非空列表
if (!engines.length) return;
engines = engines.join("");
// 展开当前搜索分类列表
if (
!self.settingData.foldlist &&
category == self.matchedRule?.engineList
) {
self.container.innerHTML = engines;
} else {
const dropDownList = document.createElement("sejspan");
dropDownList.className = "sej-drop-list rwl-exempt";
dropDownList.innerHTML = engines;
// a:主搜索菜单
// dropList: 搜索子菜单
const jumpBarButton =
dropDownList.firstElementChild.cloneNode(true);
jumpBarButton.className =
jumpBarButton.className + " sej-drop-list-trigger";
// 隐藏主搜索菜单的图标
if (!self.settingData.icon) {
cName = "";
}
jumpBarButton.lastChild.nodeValue = cName;
self.dropDownLists.push([jumpBarButton, dropDownList]);
}
});
}
#addEnginesToDOM() {
this.dropDownLists.forEach((item) => {
this.container.appendChild(item[0]); //将搜索列表放入主搜索
document.body.appendChild(item[1]); // 插入搜索子菜单
new DropDownList(item[0], item[1]);
});
switch (this.insertPositionLabel) {
case "beforebegin": // 'beforeBegin'(插入到给定元素的前面) ;
this.insertTarget.parentNode.insertBefore(
this.containerWrapper,
this.insertTarget
);
break;
case "afterbegin": // 'afterBegin'(作为给定元素的第一个子元素) ;
if (this.insertTarget.firstChild) {
this.insertTarget.insertBefore(
this.containerWrapper,
this.insertTarget.firstChild
);
} else {
this.insertTarget.appendChild(this.container);
}
break;
case "beforeend": // 'beforeEnd' (作为给定元素的最后一个子元素) ;
this.insertTarget.appendChild(this.containerWrapper);
break;
case "afterend": // 'afterEnd'(插入到给定元素的后面);.
if (this.insertTarget.nextSibling) {
this.insertTarget.parentNode.insertBefore(
this.containerWrapper,
this.insertTarget.nextSibling
);
} else {
this.insertTarget.parentNode.appendChild(this.container);
}
break;
default:
this.insertTarget.appendChild(this.containerWrapper);
break;
}
}
#addStyle() {
if (this.matchedRule?.style) {
// 判断是否存在脚本 “AC-baidu:重定向优化百度搜狗谷歌搜索_去广告_favicon_双列”
if (this.settingData.center == 2) {
// 自动判断是否添加
if (
document.querySelector(".AC-style-logo") &&
this.matchedRule.style_ACBaidu
) {
this.matchedRule.style = this.matchedRule.style_ACBaidu;
}
} else if (this.settingData.center == 1) {
// 强制添加
this.matchedRule.style = this.matchedRule.style_ACBaidu
? this.matchedRule.style_ACBaidu
: this.matchedRule.style;
} //
// 判断是否存在脚本“知乎排版优化”
if (document.getElementById("SearchMain")) {
if (
document.getElementById("SearchMain").style.marginLeft == "150px"
) {
this.matchedRule.style = this.matchedRule.style_ZhihuChenglinz;
this.matchedRule.fixedTop = null;
}
}
this.container.style.cssText = this.matchedRule.style;
}
//兼容ac百度中lite选项, fixedtop和正常的不一样
setTimeout(function () {
if (
document.querySelector(".AC-baiduLiteStyle") &&
matchedRule.fixedTop2
) {
matchedRule.fixedTop = matchedRule.fixedTop2;
}
}, 2500);
// 吸附顶部时的占位
if (
getComputedStyle(this.container).position !== "sticky" &&
this.containerWrapper !== this.container &&
!this.#isOnSelectSearchMode()
) {
this.containerWrapper.style.height =
this.container.offsetHeight +
parseFloat(getComputedStyle(this.container).marginTop) +
parseFloat(getComputedStyle(this.container).marginBottom) +
"px";
this.containerWrapper.style.position = "relative";
this.containerWrapper.style.display = "flow-root";
}
}
#fixedToTop(fixedTop, color, originalContainerDistanceTop) {
if (!this.container) {
return;
}
fixedTop = fixedTop ? fixedTop : 0;
if (this.container.style.position != "sticky") {
const rect = this.container.getBoundingClientRect();
if (originalContainerDistanceTop - window.scrollY <= fixedTop) {
this.container.style.position = "fixed";
this.container.style.top = fixedTop + "px";
this.container.style.left = rect.left + "px";
this.container.style.padding = "0";
this.container.style.margin = "0";
this.container.style.backgroundColor = color;
} else {
this.container.style.cssText = matchedRule.style;
}
}
}
#jumpToSelectedEngine(e) {
const target = e.target;
if (!target) return;
if (!target.classList.contains("sej-engine")) return;
let searchKeyword;
if (typeof this.inputTarget == "function") {
searchKeyword = this.inputTarget();
} else {
if (this.inputTarget.nodeName == "INPUT") {
searchKeyword = this.inputTarget.value;
} else {
searchKeyword = this.inputTarget.textContent;
}
}
// 如果搜索内容是通过某一网站搜索, 就去掉。 例: 0 site:zhihu.com 只保留0, 后面的网站会去掉
if (!this.settingData.HideTheSameLink) {
searchKeyword = searchKeyword.replace(/site:[^\s]+/, "");
}
// 编码 解码
// 对搜索词编码 (未做解码处理,浏览器自动处理) 网站1688采用gbk编码
const ogbk = target.getAttribute("gbk");
if (ogbk) {
searchKeyword = toGBK(searchKeyword);
} else {
searchKeyword = encodeURIComponent(searchKeyword);
}
let targetURL = target.getAttribute("url");
// 一键搜索
if (
this.settingData.allOpen &&
target.classList.contains("sej-drop-list-trigger")
) {
var list = this.engineList[target.dataset.iqxincategory];
for (var i = 0; i < list.length; i++) {
if (
list[i].url.indexOf("site:") < 0 &&
matchedRule?.url.test(list[i].url)
)
continue;
if (list[i].disable) continue;
var href = list[i].url.replaceAll("%s", searchKeyword);
GM_openInTab(href);
}
target.setAttribute("onclick", "return false;");
return;
}
// 如果有post请求
var postSign = targetURL?.indexOf("$post$");
if (postSign && postSign !== -1) {
target.addEventListener("click", function (e) {
e.preventDefault();
});
var f = this.#getEngineJumpPostForm(
targetURL.substring(0, postSign),
[
targetURL.substring(postSign + 6),
decodeURIComponent(searchKeyword),
],
target.getAttribute("target")
);
document.body.appendChild(f);
f.submit();
} else {
target.href = target
.getAttribute("url")
.replaceAll("%s", searchKeyword);
}
if (this.#isOnSelectSearchMode()) {
target.target = "_blank";
}
if (target?.target !== "_blank") {
target.target = "_top";
}
}
#getElementBySelector(selector) {
if (selector?.startsWith("css;")) {
return document.querySelector(selector.slice(4));
} else {
return document.evaluate(selector, document, null, 9, null)
.singleNodeValue;
}
}
#getEngineJumpPostForm(url, value, newTab) {
const postForm = document.createElement("form");
postForm.method = "post";
postForm.action = url;
postForm.style.cssText = "display:none;";
postForm.innerHTML = `<input type="hidden" name="${value[0]}" value="${value[1]}"/>`;
newTab ? (postForm.target = "_blank") : {};
return postForm;
}
}
class SettingPanel {
static dragEl = null;
aPatternParent = "<div></div>";
ele = document.createElement("div");
mask = document.createElement("div");
parentTemp = null;
editTemp = null;
online = null;
constructor() {
this.init();
}
init() {
// console.log("init...");
var that = this;
this.ele.id = "settingLayer";
this.mask.id = "settingLayerMask";
this.addGlobalStyle();
this.addContent();
this.mask.addEventListener("click", function () {
that.hide();
});
this.ele.addEventListener("click", function (e) {
e.stopPropagation();
});
this.mask.appendChild(this.ele);
document.body.appendChild(this.mask);
// 绑定事件
this.ele.addEventListener("click", that.domClick.bind(this), false);
this.dragEvent();
this.setDragNode(this.ele); //设置拖动
// input[range]
that.rangeChange(true);
document
.querySelector("#setBtnOpacityRange")
.addEventListener("input", that.rangeChange);
document
.querySelector("#xin-save")
.addEventListener("click", function () {
that.saveData();
that.hide();
that.reloadSet();
});
document
.querySelector("#xin-addDel")
.addEventListener("click", function (e) {
that.addDel(e);
});
document
.querySelector("#xin-modification")
.addEventListener("click", function () {
that.editCodeBox();
});
window.addEventListener("resize", this.windowResize.bind(this));
}
dragEvent() {
var that = this;
var odivsdrag = document.querySelectorAll(".drag");
[].forEach.call(odivsdrag, function (odiv) {
odiv.addEventListener("dragstart", that.domdragstart, false);
odiv.addEventListener("dragenter", that.domdragenter, false);
odiv.addEventListener("dragover", that.domdragover, false);
odiv.addEventListener("dragleave", that.domdragleave, false);
odiv.addEventListener("drop", that.domdrop, false);
odiv.addEventListener("dragend", that.domdropend, false);
});
}
addContent() {
var aPattern =
'<span draggable="true" class="drag">' +
'<span class="sej-engine"' +
' data-xin="$xin$" ' +
' data-iqxinimg="$img$" ' +
' data-iqxintitle="$title$" ' +
' data-iqxinlink="$link$" ' +
' data-iqxintarget="$blank$" ' +
' data-iqxindisabled="$disabled$" ' +
' data-iqxingbk="$gbk$" ' +
'><img src="$favicon$" class="sej-engine-icon"/><span>$name$</span></span>' +
' <span class="iqxin-set-edit" title="Edit"><img class="sej-engine-icon" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAACDklEQVR4nJXVzUtUURjH8Y/mSNKkki2iwiApxHQ1q/6C+gusoCB6oxbRRqFNL4sWtRKqhVSLIDe1CqpNiwjKIilKLKKFEr2Z2qI0xxHN0+LOm+PMOPOc1T2H7/f5ncO991BdNer30zmxKrl0xV2zKJjRoy6aqkkvbbdVLPuUq+8+5uGXnVILki7qsxgtNDtrTNLcijHvrdYsft0/wQ8DZgSzeqMUDW4IJceYHcvwCd1ies0KZvWI1TnhIH6574Olgg0E74zmhZ902j304by4Cxp5LPjtQNmjy3XPVK2rgmCBCcGgdVXhdBgUBCMEwVMNVeIvBMFLifKC8vgrndFBlRJUhJcWFMd3ZfGuzFRxwWrdu3KTxQQVhi8lqApfKVhf0d4bc2/OckG9Pkur7r3TEw+1FRO0GxdM2Vc2/HHBgr1If935UTfigbt5+C27MeSo9+m5GJYitlCwWR2G8oQZ/FgWX1aFgnZMG852v5nFR4rhMn+2dDVJYFpKqy0SDksUhF9FsE0bWgyIa9bIanihoEUcDTrSz4ueOVMOLxQkzVkrZcaoNz755rmpcnihYNghm3w26Ys/5cGcIKgRBJDyqCIquj8C1PqKZvHK+qVrJ5bMRwmGterU64pkkZupWO3RjXkzUZj9+jVZMGK6IsEaHTbgjpOSUYZL/pa5m4qPIbtyznpHvJaqGB53O33h4T/3VzLuzDhE6AAAAABJRU5ErkJggg=="/></span>' +
' <span class="iqxin-set-del" title="Delete"><img class="sej-engine-icon" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAADAFBMVEUAAADsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVHsbVH///9VVVVWVlZXV1dYWFhZWVlaWlpbW1tcXFxdXV1eXl5fX19gYGBhYWFiYmJjY2NkZGRlZWVmZmZnZ2doaGhpaWlqampra2tsbGxtbW1ubm5vb29wcHBxcXFycnJzc3N0dHR1dXV2dnZ3d3d4eHh5eXl6enp7e3t8fHx9fX1+fn5/f3+AgICBgYGCgoKDg4OEhISFhYWGhoaHh4eIiIiJiYmKioqLi4uMjIyNjY2Ojo6Pj4+QkJCRkZGSkpKTk5OUlJSVlZWWlpaXl5eYmJiZmZmampqbm5ucnJydnZ2enp6fn5+goKChoaGioqKjo6OkpKSlpaWmpqanp6eoqKipqamqqqqrq6usrKytra2urq6vr6+wsLCxsbGysrKzs7O0tLS1tbW2tra3t7e4uLi5ubm6urq7u7u8vLy9vb2+vr6/v7/AwMDBwcHCwsLDw8PExMTFxcXGxsbHx8fIyMjJycnKysrLy8vMzMzNzc3Ozs7Pz8/Q0NDR0dHS0tLT09PU1NTV1dXW1tbX19fY2NjZ2dna2trb29vc3Nzd3d3e3t7f39/g4ODh4eHi4uLj4+Pk5OTl5eXm5ubn5+fo6Ojp6enq6urr6+vs7Ozt7e3u7u7v7+/w8PDx8fHy8vLz8/P09PT19fX29vb39/f4+Pj5+fn6+vr7+/v8/Pz9/f3+/v7///8dej9TAAAAU3RSTlMAAABm7P/sZgAAABPO////zhQAAB/i/////////+IfAAAe4fvk4AAAAAAd/+Q3GxwAFR85FQBjz+LPY+v////r6//////rZM/h4c9jABUdHRUAAP0EcPoAAAEuSURBVHic7ZRnc8IwDIbdEUZHGB0kDsMOMcOMttBBB93Qvcj//y9VjB0Czh13/dz3ixT5OVmSYyMktLK6tm74oYxEMpVGUW1sbm2bM8DMZHP5OWBnd2+/YNnYAWHbKhRL5cocQKjrWFWPuSDmVS3HpUQu1eoNQkiTM9xqd7oHoG6n3cKMNyHcqNfQ4VGPUsr7nh0FbK/PIdw7PkGnZwOZNrqF9AfnF+jyaigLixYp/eH1Dbq9u4eAHyOAHh5HaPz0DCnjANjm5fUNvX98QoGCxyo5Fjmh0K/vH2hzAi0KnqnymMgJrU6gzemQBM+DZpX1/XBYUyAYTTAuZTUg+Aw8Zf+BvwJLR730sPTjXgD0H2YB0BUClXKpGAeE1y+fy2ZMfX12gdOpZMLQAfkE/AL7e5vGZF+dOQAAAABJRU5ErkJggg=="></span>' +
"</span>";
var details = engineList.engineCategories;
// 若根据数组长度获取,负数引导的为属性,不再length长度之内,所以来个大体的数字,当都为空时,结束循环
// var detailsLength = details.length;
var detailsLength = 99;
for (let i = 0; i < detailsLength; i++) {
var j = i;
j = details[j] ? j : -j;
if (!details[j]) {
break;
}
var odiv = document.createElement("div");
odiv.id = details[j][1]; // "web"
odiv.classList.add("iqxin-items");
var oDivTitle = document.createElement("div");
oDivTitle.classList.add("sejtitle", "drag");
oDivTitle.setAttribute("draggable", "true");
oDivTitle.dataset.iqxintitle = details[j][1];
oDivTitle.dataset.xin = j;
oDivTitle.innerHTML =
'<span class="iqxin-pointer-events">' +
details[j][0] +
"</span>" +
'<span class="iqxin-title-edit" title="Edit"><img class="sej-engine-icon" src="' +
icon.edit +
'"/></span>' +
' <span class="iqxin-set-title-del" title="Delete"><img class="sej-engine-icon" src="' +
icon.del +
'"></span>';
odiv.appendChild(oDivTitle);
var oDivCon = document.createElement("div");
oDivCon.classList.add("sejcon");
var oDivConStr = "";
var engineListItem = engineList[details[j][1]];
var itemLength = engineListItem.length;
for (let ii = 0; ii < itemLength; ii++) {
var jj = ii;
if (!engineListItem[jj]) {
break;
}
var a = aPattern
.replace("$name$", engineListItem[jj].name)
.replace("$favicon$", engineListItem[jj].favicon)
.replace("$xin$", jj);
// 添加属性
a = a
.replace("$img$", engineListItem[jj].favicon)
.replace("$title$", engineListItem[jj].name)
.replace("$link$", engineListItem[jj].url);
if (engineListItem[jj].blank) {
a = a.replace("$blank$", "_blank");
} else {
a = a.replace('data-iqxintarget="$blank$"', "");
}
if (engineListItem[jj].disable) {
a = a.replace("$disabled$", "true");
} else {
a = a.replace('data-iqxindisabled="$disabled$"', "");
}
if (engineListItem[jj].gbk) {
a = a.replace("$gbk$", "true");
} else {
a = a.replace('data-iqxingbk="$gbk$"', "");
}
oDivConStr += a;
}
oDivConStr += "<span class='iqxin-additem'>+</span>";
oDivCon.innerHTML = oDivConStr;
odiv.appendChild(oDivCon);
this.ele.appendChild(odiv);
}
// 更多设置 菜单
var btnEle2 = document.createElement("div");
btnEle2.id = "btnEle2";
var fixedTop_checked = settingData.fixedTop ? "checked" : "";
var fixedTopUpward_checked = settingData.fixedTopUpward
? "checked"
: "";
var transition_checked = settingData.transtion ? "checked" : "";
var selectSearch_checked = settingData.selectSearch ? "checked" : "";
var foldlist_checked = settingData.foldlist ? "checked" : "";
var allOpen_checked = settingData.allOpen ? "checked" : "";
var HideTheSameLink_checked = settingData.HideTheSameLink
? "checked"
: "";
var btnStr2 =
"<div>" +
"<span id='xin-modification' title='Share or delete configuration file'>Configuration file</span>" +
// "<span id='xin-importing' title='importing 导入更为专业的搜索引擎'>导入</span>" +
"<span id='xin-selectSearch' title='Only non-search pages will take effect, Requires to refresh the page'>" +
"<label>Word search<input id='iqxin-selectSearch' type='checkbox' name='' " +
selectSearch_checked +
" style='vertical-align:middle;'></label>" +
"</span>" +
"<span id='xin-transtion' title='Requires to refresh the page'>" +
"<label>Animations<input id='iqxin-transtion' type='checkbox' name='' " +
transition_checked +
" style='vertical-align:middle;'></label>" +
"</span>" +
"<span id='xin-foldlists' title='Collapse the current search categories'>" +
"<label>Hide current category<input id='iqxin-foldlist' type='checkbox' name='' " +
foldlist_checked +
" style='vertical-align:middle;'></label>" +
"</span>" +
"<span id='iqxin-fixedTopS' title='Dev note I am not sure what exactly this option is supposed to accomplish.'>" +
"<label>pin to top<input id='iqxin-fixedTop' type='checkbox' name='' " +
fixedTop_checked +
" style='vertical-align:middle;'></label>" +
"</span>" +
"<span id='iqxin-fixedTopUpward' title='After it is fixed to the top, it will only be displayed when scrolling upwards, Requires to refresh the page'>" +
"<label>Pull-up display only<input id='iqxin-fixedTopUpward-item' type='checkbox' name='' " +
fixedTopUpward_checked +
" style='vertical-align:middle;'></label>" +
"</span>" +
"<span id='xin-HideTheSameLink' title='Hide same-site links. If you want to search on the same search site but in different languages, you can uncheck this option.'>" +
"<label>Hide same links<input id='iqxin-HideTheSameLink' type='checkbox' name='' " +
HideTheSameLink_checked +
" style='vertical-align:middle;'></label>" +
"</span>" +
"<span id='xin-setBtnOpacity' title='Setting button transparency, Requires to refresh the page'>Transparency<input type='range' step='0.05' min='0' max='1' value='" +
(settingData.setBtnOpacity < 0
? -settingData.setBtnOpacity
: settingData.setBtnOpacity) +
"' id='setBtnOpacityRange'><i style='display:inline-block;width:3em;text-align:center;' class='iqxin-setBtnOpacityRangeValue' title='按钮 显示/隐藏(非透明)),请确定知道自己如何再次打开; 火狐非高级玩家建议别禁用'></i></span>" +
"</div>";
// "<div><span>test</span></div>";
btnEle2.innerHTML = btnStr2;
this.ele.appendChild(btnEle2);
// 添加按钮
var btnEle = document.createElement("div");
btnEle.id = "btnEle";
var btnStr =
"<div class='btnEleLayer'>" +
"<span class='feedback' title='Give feedback on Github'><a target='_blank' href='https://github.com/KParthSingh/SearchEngineJumpPlus/'>GitHub</a></span>" +
"<span class='feedback' title='Give feedback on Greasy Fork'><a target='_blank' href='https://greasyfork.org/en/scripts/484068-searchenginejumpplus'>Greasy Fork</a></span>" +
"<span id='xin-allOpen' title='Open all of the sites in this search category in the background'>" +
"<label>One click search<input id='iqxin-allOpen-item' type='checkbox' name='' " +
allOpen_checked +
" style='vertical-align:middle;'></label>" +
"</span>" +
"<span id='xin-centerDisplay' title='Force mode always keeps the toolbar centered'>Center:" +
"<select id='iqxin-center'>" +
"<option value='original'" +
(settingData.center == 0 ? "selected" : "") +
">default</option>" +
"<option value='force'" +
(settingData.center == 1 ? "selected" : "") +
">force</option>" +
"<option value='auto'" +
(settingData.center == 2 ? "selected" : "") +
">Automatic</option>" +
"</select>" +
"</span> " +
"<span id='xin-newtab' title='Choose whether you want to open in a new tab or in the current page'>Open in:" +
"<select id='iqxin-globalNewtab'>" +
"<option value='globalDef'>current page</option>" +
"<option value='globalNewtab'" +
(settingData.newtab ? "selected" : "") +
">new tab</option>" +
"</select>" +
"</span> " +
"<span id='xin-addDel' title='Add new or remove existing searches'>Add / Delete</span> " +
"<span id='xin-reset' title='Be careful. This option resets settings'>Reset</span>" +
"<span id='moreSet' title='More settings'>Settings</span>" +
"<span id='xin-save' title='Save & Close'>Save & Close</span>" +
"</div>";
btnEle.innerHTML = btnStr;
this.ele.appendChild(btnEle);
// 可以拖动的顶栏
var dragDom = document.createElement("div");
dragDom.id = "dragDom";
dragDom.style.cssText =
"height:16px;width:97%;position:absolute;top:0;cursor:move;";
this.ele.appendChild(dragDom);
var nSearchList = document.createElement("div");
// Set the id for the created div element
nSearchList.id = "nSearchList";
// Set the inner HTML content
nSearchList.innerHTML = "new list";
// Append the div element to a parent element (assuming `this.ele` is the parent element)
this.ele.appendChild(nSearchList);
// Add CSS styles to the created div element
nSearchList.style.visibility = "hidden";
nSearchList.style.opacity = "0";
nSearchList.style.transition = "all 0.3s ease 0s";
nSearchList.style.position = "absolute";
nSearchList.style.bottom = "17%";
nSearchList.style.right = "2%";
nSearchList.style.padding = "6px 10px";
nSearchList.style.borderRadius = "4px";
nSearchList.style.border = "1px solid rgb(255, 0, 2)";
nSearchList.style.color = "rgb(255, 255, 255)";
nSearchList.style.cursor = "pointer";
nSearchList.style.background = "rgb(255, 0, 1)";
// Add hover animation through JavaScript
nSearchList.addEventListener("mouseenter", function() {
nSearchList.style.background = "rgb(255, 255, 255)";
nSearchList.style.color = "rgb(255, 0, 1)";
});
nSearchList.addEventListener("mouseleave", function() {
nSearchList.style.color = "rgb(255, 255, 255)";
nSearchList.style.background = "rgb(255, 0, 1)";
});
// 关闭按钮
if (settingData.closeBtn) {
var closebtnELe = document.createElement("span");
closebtnELe.id = "xin-close";
closebtnELe.setAttribute("title", "Close");
this.ele.appendChild(closebtnELe);
}
}
show() {
var style = this.mask.style;
var eleStyle = this.ele.style;
style.display = "flex";
eleStyle.transform = "translateY(-20%)";
document.body.style.overflow = "hidden";
this.windowResize();
setTimeout(function () {
style.opacity = 1;
eleStyle.transform = "none";
}, 30);
}
hide() {
this.allBoxClose(); // 关闭所有次级窗口、菜单
var style = this.mask.style;
this.ele.style.transform = "translateY(20%)";
style.opacity = 0;
setTimeout(function () {
style.display = "none";
document.body.style.overflow = "auto";
}, 500);
}
reset() {
if (confirm("User settings will be reset!")) {
GM_deleteValue("searchEngineJumpData");
location.reload();
}
}
// 增加 “添加删除框”
addDel(e) {
if (e.target.classList.contains("iqxin-btn-active")) {
this.addDelremove();
} else {
// console.log("不存在,增加增加");
var obtn = document.querySelector("#xin-addDel");
obtn.classList.add("iqxin-btn-active");
var odom = document.querySelectorAll(".iqxin-set-del");
[].forEach.call(odom, function (div) {
div.classList.add("iqxin-set-active");
});
// 标题添加删除框
var odom = document.querySelectorAll(".iqxin-set-title-del");
[].forEach.call(odom, function (div) {
// console.log(div);
div.classList.add("iqxin-set-active");
});
// 增加单个搜索
var oitemAdd = document.querySelectorAll(".iqxin-additem");
[].forEach.call(oitemAdd, function (div) {
// console.log(div);
div.classList.add("iqxin-set-active");
});
// 添加搜索列表
var olistAdd = document.querySelector("#nSearchList");
olistAdd.classList.add("iqxin-set-active");
}
}
// 关闭 “添加删除框”
addDelremove(bool) {
var obtn = document.querySelector(".iqxin-btn-active");
if (obtn) {
obtn.classList.remove("iqxin-btn-active");
var odom = document.querySelectorAll(".iqxin-set-active");
[].forEach.call(odom, function (div) {
div.classList.remove("iqxin-set-active");
});
var oitemAdd = document.querySelectorAll(".iqxin-additem");
[].forEach.call(oitemAdd, function (div) {
div.classList.remove("iqxin-set-active");
});
}
this.addItemBoxRemove();
}
// 界面,框:添加新的搜索
addItemBox() {
this.isOnline();
this.addItemBoxRemove();
var newDiv = document.createElement("div");
newDiv.id = "newSearchBox";
newDiv.style.cssText = `
top: 43%;
background-color: #f5f5f5; /* Light background color */
color: #333; /* Dark text color */
/* Add other light mode styles here */
`;
// Check for dark mode
if (this.isDarkMode()) {
newDiv.style.backgroundColor = '#333'; // Dark background color
newDiv.style.color = '#fff'; // Light text color
}
newDiv.innerHTML = `<span>Name : </span><input id='iqxin-newTitle' placeholder='Name required' onfocus='this.select()' /> <br/><br/>
<span>URL  : </span><input id='iqxin-newLink' placeholder='URL required' onfocus='this.select()' /> <br/><br/>
<span>Logo : </span><input id='iqxin-newIcon' placeholder='Optional, leave it blank to get it automatically.' onfocus='this.select()' /> <br/><br/>
<span>Open in :
<select id="iqxin-newTarget" style="border-radius: 4px;border: none;padding: 2px 0 2px 2px">
<option value="default">Current page</option>
<option value="newtab">New Tab</option>
<select>
</span>
<br/><br/>
<span><a target='_blank' style='color:#999;' href='https://github.com/KParthSingh/SearchEngineJumpPlus'>Instructions</a></span>
 
<button id='addItemBoxEnter' class='addItemBoxEnter addItemBoxBtn iqxin-enterBtn'>Save</button>     
<button id='addItemBoxCancel' class='addItemBoxCancel addItemBoxBtn iqxin-closeBtn'>Close</button>`;
this.ele.appendChild(newDiv);
document.querySelector("#iqxin-newTitle").focus();
}
// Function to check if the page is in dark mode
isDarkMode() {
function getContrastYIQ(rgbColor) {
let r, g, b, a;
rgbColor = rgbColor.match(/rgba?\(([^)]+)\)/)[1];
rgbColor = rgbColor.split(/ *, */).map(Number);
[r, g, b, a] = rgbColor;
if (a < 0.5) {
return false;
}
const yiq = (r * 299 + g * 587 + b * 114) / 1000;
return yiq < 128;
}
return (
document.getElementsByTagName("meta")?.["color-scheme"]?.content === "dark" ||
getContrastYIQ(getComputedStyle(document.body).backgroundColor)
);
}
// 内部逻辑,:添加新的搜索
addItemEnger() {
var otitle, olink, oimg, oblank;
otitle = document.querySelector("#iqxin-newTitle").value;
olink = document.querySelector("#iqxin-newLink").value;
oimg = document.querySelector("#iqxin-newIcon").value;
oblank = document.querySelector("#iqxin-newTarget").selectedIndex;
if (!oimg) {
oimg = this.getICON(olink);
}
var a =
'<span class="sej-engine"' +
' data-iqxinimg="$img$" ' +
' data-iqxintitle="$title$" ' +
' data-iqxinlink="$link$" ' +
' data-iqxintarget="$blank$" ' +
'><img src="$favicon$" class="sej-engine-icon" />$name$</span>' +
'<span class="iqxin-set-edit" title="Edit">' +
'<img class="sej-engine-icon" src="' +
icon.edit +
'">' +
"</span> " +
'<span class="iqxin-set-del iqxin-set-active" title="Delete">' +
'<img class="sej-engine-icon" src="' +
icon.del +
'">' +
"</span>";
a = a
.replace("$img$", oimg)
.replace("$title$", otitle)
.replace(
"$link$",
olink.indexOf("://") === -1 ? "https://" + olink : olink
);
if (oblank) {
a = a.replace('data-iqxintarget="$blank$"', "");
} else {
a = a.replace("$blank$", "_blank");
}
a = a.replace("$name$", otitle).replace("$favicon$", oimg);
var ospan = document.createElement("span");
ospan.className = "drag";
ospan.innerHTML = a;
this.parentNode.insertBefore(ospan, this.parentNode.lastChild);
// 添加完成,移除添加框
this.addItemBoxRemove();
}
addItemBoxRemove(ele) {
ele = ele ? ele : "#newSearchBox";
var newBox = document.querySelector(ele);
if (newBox) {
// newBox.style.transform = "translateY(30%)";
newBox.style.top = "60%";
newBox.style.opacity = "0";
setTimeout(function () {
newBox.parentNode.removeChild(newBox);
}, 550);
}
}
// 获取图标
getICON(olink) {
let ourl;
let mark;
let protocol;
let host;
if (olink.indexOf("://") !== -1) {
protocol = olink.split("://")[0] ? olink.split("://")[0] : "https";
host = olink.split("://")[1].split("/")[0];
} else {
protocol = "https";
host = olink.split("/")[0];
}
const siteURL = protocol + "://" + host;
if (isNaN(settingData.getIcon)) {
ourl = settingData.getIcon;
} else {
mark = parseInt(settingData.getIcon);
switch (mark) {
case 1:
ourl = siteURL + "/favicon.ico";
break;
case 2:
ourl = "https://www.google.com/s2/favicons?domain=" + siteURL;
break;
case 3:
ourl =
"https://statics.dnspod.cn/proxy_favicon/_/favicon?domain=" +
host;
break;
}
}
if (ourl) {
ourl = ourl.replace("%s", siteURL);
return ourl;
}
if (this.online) {
ourl = "https://www.google.com/s2/favicons?domain=" + host;
return ourl;
} else {
ourl = protocol + "://" + host + "/favicon.ico";
return ourl;
}
}
// 界面, 框: 添加新的搜索列表
addSearchListBox() {
var odiv = document.querySelector("#newSearchListBox");
if (odiv) {
this.boxClose("#newSearchListBox");
return;
}
var newDiv = document.createElement("div");
newDiv.id = "newSearchListBox";
newDiv.style.cssText = `
background-color: #f5f5f5; /* Lighter background color */
color: #333; /* Dark text color */
/* Add other light mode styles here */
`;
// Check for dark mode
if (this.isDarkMode()) {
newDiv.style.backgroundColor = '#333'; // Dark background color
newDiv.style.color = '#fff'; // Light text color
// Add other dark mode styles here
}
var myDate = new Date();
var hash = "user" + myDate.getTime();
newDiv.innerHTML =
"" +
"<span>List Name: </span><input id='iqxin-newSearchListName' onfocus='this.select()'>" +
"<br><br>" +
"<span>Internal Name: </span><input id='iqxin-newSearchListInnerName' onfocus='this.select()' value='" +
hash +
"'>" +
"<br><br>" +
"<button id='addSearchListBoxEnter' class='addSearchListBoxEnter addItemBoxBtn iqxin-enterBtn'>Save</button>     " +
"<button id='addSearchListBoxCancel' class='addSearchListBoxCancel addItemBoxBtn iqxin-closeBtn'>Close</button>" +
"";
this.ele.appendChild(newDiv);
document.querySelector("#iqxin-newSearchListName").focus();
}
addSearchListEnger() {
var name = document.querySelector("#iqxin-newSearchListName").value;
var innerName = document.querySelector("#iqxin-newSearchListInnerName").value;
if (innerName.length === 0) {
alert("内部名称不能为空");
return;
}
if (name.length === 0) {
name = innerName;
}
var odiv = document.createElement("div");
odiv.id = innerName;
odiv.className = "iqxin-items";
odiv.innerHTML =
"" +
'<div class="sejtitle" data-iqxintitle="' +
innerName +
'" data-xin="99">' +
'<span class="iqxin-pointer-events">' +
name +
"</span>" +
'<span class="iqxin-title-edit" title="Edit">' +
'<img class="sej-engine-icon" src="' +
icon.edit +
'">' +
"</span> " +
'<span class="iqxin-set-title-del iqxin-set-active" title="Delete">' +
'<img class="sej-engine-icon" src="' +
icon.del +
'">' +
"</span>" +
"</div>" +
'<div class="sejcon">' +
'<span class="iqxin-additem iqxin-set-active">+</span>' +
"</div>" +
"";
this.addItemBoxRemove("#newSearchListBox");
var btnEle = document.querySelector("#btnEle");
btnEle.parentNode.insertBefore(odiv, btnEle);
}
boxClose(ele) {
var odiv = document.querySelector(ele);
if (odiv) {
odiv.parentNode.removeChild(odiv);
}
}
// 界面 框:修改框
addEditBox(e) {
this.addItemBoxRemove();
var target = e.target.parentNode.firstChild;
var otitle = target.dataset.iqxintitle;
var olink = target.dataset.iqxinlink;
var oicon = target.dataset.iqxinimg;
var otarget = target.dataset.iqxintarget;
var odisabled = target.dataset.iqxindisabled;
let oGBK = target.dataset.iqxingbk;
this.editTemp = target;
var strblank;
if (otarget) {
strblank =
'<option value="default">Current page</option><option value="newtab">New Tab</option> ';
} else {
strblank =
'<option value="default">Current page</option><option value="newtab" selected="selected">New Tab</option>';
}
var strGBK = "";
if (oGBK) {
strGBK = "checked='checked'";
}
var newDiv = document.createElement("div");
newDiv.id = "newSearchBox";
newDiv.style.cssText = `
top: 43%;
background-color: #f5f5f5; /* Lighter background color */
color: #333; /* Dark text color */
/* Add other light mode styles here */
`;
// Check for dark mode
if (this.isDarkMode()) {
newDiv.style.backgroundColor = '#333'; // Dark background color
newDiv.style.color = '#fff'; // Light text color
// Add other dark mode styles here
}
var innerHTML = `
<span>Name : </span><input id="iqxin-newTitle" placeholder="Name required" onfocus="this.select()" value="${otitle}" /> <br/><br/>
<span>URL  : </span><input id="iqxin-newLink" placeholder="URL required" onfocus="this.select()" value="${olink}" /> <br/><br/>
<span>Logo : </span><input id="iqxin-newIcon" placeholder="Optional, leave it blank to get it automatically." onfocus="this.select()" value="${oicon}" /> <br/><br/>
<span>Open in :
<select id="iqxin-newTarget" style="border-radius: 4px;border: none;padding: 2px 0 2px 2px">
${strblank}
<select>
</span>
<br/><br/>
<span style=""><label>GBK Encoding:<input type="checkbox" name="" id="iqxin-newGBK" ${strGBK} style="vertical-align:middle;"></label></span>
<button id="editItemBoxEnter" class="editItemBoxEnter addItemBoxBtn iqxin-enterBtn">Save</button>     
<button id="addItemBoxCancel" class="addItemBoxCancel addItemBoxBtn iqxin-closeBtn">Close</button>
`;
newDiv.innerHTML = innerHTML;
this.ele.appendChild(newDiv);
document.querySelector("#iqxin-newTitle").focus();
}
addEditBoxEnger() {
var otitle, olink, oimg, oblank, ogbk;
otitle = document.querySelector("#iqxin-newTitle").value;
olink = document.querySelector("#iqxin-newLink").value;
oimg = document.querySelector("#iqxin-newIcon").value;
oblank = document.querySelector("#iqxin-newTarget").selectedIndex;
ogbk = document.querySelector("#iqxin-newGBK").checked;
this.editTemp.dataset.iqxintitle = otitle;
this.editTemp.lastChild.innerText = otitle; //文本节点
this.editTemp.dataset.iqxinlink = olink;
this.editTemp.dataset.iqxinimg = oimg;
this.editTemp.firstChild.src = oimg;
// 是否新标签页打开
if (oblank) {
this.editTemp.removeAttribute("data-iqxintarget");
} else {
this.editTemp.dataset.iqxintarget = "_blank";
}
// 是否禁用
if (ogbk) {
this.editTemp.dataset.iqxingbk = "true";
} else {
this.editTemp.removeAttribute("data-iqxingbk");
}
// 修改完成,移除添加框
this.addItemBoxRemove();
}
// 标题编辑
addTitleEditBox(e) {
this.addItemBoxRemove();
var element = e.target.parentNode.firstChild;
element.classList.remove("iqxin-pointer-events");
var flag = document.querySelector("#titleEdit");
// 存在编辑的标题 && 之前的编辑的节点与点击的节点是同一个节点
if (flag && flag.parentNode == element) {
element.innerHTML = element.firstChild.value
? element.firstChild.value
: "空";
element.classList.add("iqxin-pointer-events");
} else {
// 存在编辑的标题,但与点击的不是同一个节点
if (flag) {
flag.parentNode.innerHTML = flag.parentNode.firstChild.value;
}
var oldhtml = element.innerHTML;
var newobj = document.createElement("input");
newobj.id = "titleEdit";
newobj.type = "text";
newobj.value = oldhtml;
// newobj.onblur = function(){
// element.innerHTML = this.value?this.value:oldhtml;
// }
newobj.onkeydown = function (e) {
if ((e.keyCode || e.which) == 13) {
element.innerHTML = this.value ? this.value : oldhtml;
} else if ((e.keyCode || e.which) == 27) {
element.innerHTML = oldhtml;
}
element.classList.add("iqxin-pointer-events");
};
element.innerHTML = "";
element.appendChild(newobj);
newobj.select();
}
}
addTitleEditBoxRemove() {
var odiv = document.querySelector("#titleEdit");
if (odiv) {
odiv.parentNode.innerHTML = odiv.value ? odiv.value : "空";
}
}
editCodeBox() {
console.log("原始数据: ", settingData);
var userSetting = GM_getValue("searchEngineJumpData");
var editbox = document.createElement("div");
editbox.id = "iqxin-editCodeBox";
var darkMode = new Style().isDarkMode();
// Modify styles based on dark mode
if (darkMode) {
editbox.style.cssText =
"position:fixed;" +
"top:50%;left:50%;" +
"transform:translate(-50%,-50%);" +
"background:#333333;" +
"border-radius:10px;" +
"padding:10px 20px;";
} else {
// Styles for the default theme (light mode)
editbox.style.cssText =
"position:fixed;" +
"top:50%;left:50%;" +
"transform:translate(-50%,-50%);" +
"background:#DFDFDF;" +
"border-radius:10px;" +
"padding:10px 20px;";
}
var innerH =
" " +
"<p><span style='color:red;font-size:1.2em;'>! ! !</span></br>" +
"Here you have more options and more freedom,</br>" +
"but incorrect settings can cause the script to fail to run." +
"</p>" +
"<textarea wrap='off' cols='45' rows='20' style='overflow:auto;border-radius:4px;'>" +
JSON.stringify(userSetting, null, 4) +
"</textarea>" +
"<br>" +
"<button id='xin-reset'>Reset</button> " +
"<button id='xin-copyCode'>Copy</button> " +
"<button id='codeboxclose' class='iqxin-closeBtn'>Close</button> " +
"<button id='xin-codeboxsave' class='iqxin-enterBtn'>Save</button> " +
"<button id='exportJson'>Export</button>"; // Include Export button
editbox.innerHTML = innerH;
// Attach exportConfig function to the Export button
editbox.querySelector('#exportJson').addEventListener('click', function () {
var jsonData = JSON.stringify(userSetting, null, 4);
var blob = new Blob([jsonData], { type: "application/json" });
var url = URL.createObjectURL(blob);
var a = document.createElement("a");
a.href = url;
a.download = "SEjumpbar.txt";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
});
this.ele.appendChild(editbox);
}
editCodeBoxSave() {
var codevalue = document.querySelector(
"#iqxin-editCodeBox textarea"
).value;
if (codevalue) {
GM_setValue("searchEngineJumpData", JSON.parse(codevalue));
// 刷新页面
setTimeout(function () {
location.reload();
}, 300);
} else {
// alert("输入为空");
this.reset();
}
}
editCodeBoxClose() {
var box = document.querySelector("#iqxin-editCodeBox");
if (box) {
box.parentNode.removeChild(box);
}
}
// “设置按钮” 透明度
setBtnOpacityFun() {
if (~window.navigator.userAgent.indexOf("Chrome")) {
var odom = document.querySelector("#setBtnOpacityRange");
var odomV = odom.value;
// odom.style.backgroundSize = odom.value*100 +"% 100%";
console.log(odomV, settingData.setBtnOpacity);
if (settingData.setBtnOpacity < 0) {
document.querySelector(".iqxin-setBtnOpacityRangeValue").innerHTML =
odomV.toString().padEnd(4, "0");
odom.style.background =
"-webkit-linear-gradient(left,#3ABDC1,#83e7ea) no-repeat, #fff";
} else {
document.querySelector(".iqxin-setBtnOpacityRangeValue").innerHTML =
"禁用";
odom.style.background =
"-webkit-linear-gradient(left,#bdbdbd,#c6c7c7) no-repeat, #fff";
}
odom.style.backgroundSize = odom.value * 100 + "% 100%";
settingData.setBtnOpacity = -settingData.setBtnOpacity;
} else {
this.showPopUp("抱歉,目前只支持chrome类浏览器", 2500);
}
}
// 标题点击 (开关搜索列表)(可以并入到下面的点击事件)
titleClick(e) {
var target = e.target;
target.dataset.xin = -parseInt(target.dataset.xin);
target.dataset.xin > 0
? this.showPopUp("Enabled")
: this.showPopUp("Disabled");
}
// 点击事件 此处的 if 需要根据实际情况替换成 elseif (switch)
domClick(e) {
var targetClass = e.target.className;
var targetid = e.target.id;
// 删除搜索
if (~e.target.className.indexOf("iqxin-set-del")) {
// console.log(e.target);
e.target.parentNode.parentNode.removeChild(e.target.parentNode);
}
// 删除搜索列表
if (~e.target.className.indexOf("iqxin-set-title-del")) {
// console.log(e.target, e.target.parentNode.parentNode);
e.target.parentNode.parentNode.parentNode.removeChild(
e.target.parentNode.parentNode
);
}
if (~e.target.className.indexOf("iqxin-additem")) {
this.parentNode = e.target.parentNode;
this.addItemBox();
}
if (e.target.className === "sej-engine") {
e.target.dataset.iqxindisabled = e.target.dataset.iqxindisabled
? ""
: "true";
e.target.dataset.iqxindisabled
? this.showPopUp("Disabled")
: this.showPopUp("Enabled");
}
if (~targetClass.indexOf("addItemBoxCancel")) {
this.addItemBoxRemove();
}
// 添加新的搜索 确定
if (~targetClass.indexOf("addItemBoxEnter")) {
this.addItemEnger();
}
// 添加新的搜索列表 确定
if (targetid === "nSearchList") {
this.addSearchListBox();
}
if (targetid === "addSearchListBoxEnter") {
this.addSearchListEnger();
}
if (targetid === "addSearchListBoxCancel") {
this.addItemBoxRemove("#newSearchListBox");
}
// 修改搜索 确定
if (~targetClass.indexOf("editItemBoxEnter")) {
this.addEditBoxEnger();
}
// 编辑框
if (~e.target.className.indexOf("iqxin-set-edit")) {
this.addEditBox(e);
}
// 标题编辑框
if (~targetClass.indexOf("iqxin-title-edit")) {
e.stopPropagation();
this.addTitleEditBox(e);
}
if (~targetClass.indexOf("sejtitle")) {
this.titleClick(e);
}
// codebox 源代码编辑框
if (targetid === "codeboxclose") {
this.editCodeBoxClose();
} else if (targetid === "xin-reset") {
this.reset();
} else if (targetid === "xin-codeboxsave") {
this.editCodeBoxSave();
} else if (targetid === "xin-copyCode") {
GM_setClipboard(JSON.stringify(settingData, false, 4));
this.showPopUp("Copied successfully");
}
// 点击更多菜单
if (targetid === "moreSet") {
document.querySelector("#btnEle2").classList.toggle("btnEle2active");
// iqxin-btn-active
e.target.classList.toggle("iqxin-btn-active");
}
// 关闭"设置菜单按钮"
if (targetClass === "iqxin-setBtnOpacityRangeValue") {
this.setBtnOpacityFun();
}
// 关闭设置菜单
if (targetid === "xin-close") {
this.hide();
}
// 空白地方点击
if (
~targetClass.indexOf("iqxin-items") ||
targetid === "settingLayer" ||
targetClass === "btnEleLayer"
) {
this.allBoxClose();
}
}
// 关闭所有次级窗口、菜单
allBoxClose() {
this.addItemBoxRemove(); // 新的搜索添加框
this.addDelremove(); // 增加/删除界面
this.editCodeBoxClose(); // code编辑框
this.addTitleEditBoxRemove(); //标题编辑框
this.addItemBoxRemove("#newSearchListBox"); // 添加新的搜索列表
this.boxClose("#iqxin-sortBox"); // 搜索列表排序
this.addItemBoxRemove("#importingBox"); //导入框
document.querySelector("#btnEle2").classList.remove("btnEle2active"); // 更多设置
}
// 窗口位置拖动
setDragNode(ele) {
var node = document.querySelector("#dragDom");
node.addEventListener("mousedown", function (event) {
ele.style.transition = "null";
// offsetLeft 距离 body 的位置, 得到的 dis 即鼠标到窗口左上角的位置
var disX = event.clientX - ele.offsetLeft;
var disY = event.clientY - ele.offsetTop;
var move = function (event) {
//鼠标的位置减去到左上角的位置 即窗口的位置
// console.log(event.clientX - disX,event.clientY - disY)
ele.style.left = event.clientX - disX + "px";
ele.style.top = event.clientY - disY + "px";
};
document.addEventListener("mousemove", move);
document.addEventListener("mouseup", function () {
ele.style.transition = "0.5s";
document.removeEventListener("mousemove", move);
});
});
}
// 拖动
domdragstart(e) {
if (~this.className.indexOf("sejtitle")) {
SettingPanel.dragEl = this.parentNode;
} else {
SettingPanel.dragEl = this;
}
e.dataTransfer.effectAllowed = "move";
e.dataTransfer.setData("text/html", SettingPanel.dragEl.innerHTML);
}
domdragenter(e) {
var target = e.target;
var targetClass = target.className;
if (~targetClass.indexOf("sejtitle")) {
target = target.parentNode;
}
target.classList.add("drop-over");
}
domdragover(e) {
if (e.preventDefault) {
e.preventDefault();
}
e.dataTransfer.dropEffect = "move";
return false;
}
domdragleave(e) {
var target = e.target;
var targetClass = target.className;
if (~targetClass.indexOf("sejtitle")) {
target = target.parentNode;
}
target.classList.remove("drop-over");
}
domdrop(e) {
var _this = e.target;
var that = _this.parentNode;
var pparentNode = that.parentNode;
// 防止跨区域移动
SettingPanel.prototype.domdropend();
if (SettingPanel.dragEl.className != that.className) {
console.log("移动对象 之前,现在: ", SettingPanel.dragEl.className);
console.log(that.className);
return;
}
// Sortable.js https://github.com/RubaXa/Sortable
var targetRect = _this.getBoundingClientRect(); //
var width = targetRect.right - targetRect.left; //目标节点的宽
var height = targetRect.bottom - targetRect.top; //目标节点的高
var domPosition = null;
if (~_this.className.indexOf("sejtitle")) {
if ((e.clientX - targetRect.left) / width > 0.5) {
domPosition = true;
} else {
domPosition = false;
}
} else {
if ((e.clientY - targetRect.top) / height > 0.5) {
domPosition = true;
} else {
domPosition = false;
}
}
SettingPanel.dragEl.style.transformOrigin = "top center";
SettingPanel.dragEl.style.animation = "sejopen 0.3s";
if (domPosition) {
if (pparentNode.lastChild == that) {
pparentNode.insertBefore(SettingPanel.dragEl, that);
} else {
pparentNode.insertBefore(
SettingPanel.dragEl,
that.nextElementSibling
);
}
} else {
that.parentNode.insertBefore(SettingPanel.dragEl, that);
}
// 重新绑定拖拽事件
SettingPanel.prototype.dragEvent();
return false;
}
domdropend() {
var dom = document.querySelector(".drop-over");
if (dom) {
dom.classList.remove("drop-over");
}
}
// 判断是否能连接至google
isOnline() {
console.log("this.online", this.online);
if (this.online) return;
var that = this;
var myImage = new Image();
myImage.src =
"https://www.google.com/s2/favicons?domain=www.baidu.com&" +
Math.random();
setTimeout(function () {
// console.log("取消加载");
console.log(myImage.width);
if (myImage.width) {
that.online = true;
} else {
myImage.src = undefined;
}
}, 2000);
}
// 重新加载工具
reloadSet() {
var elems = document.querySelectorAll(
"#sej-container, #settingLayerMask, sejspan.sej-drop-list"
);
if (!elems) return;
console.log("elems: " + elems);
// return;
[].forEach.call(elems, function (elem) {
elem.parentNode.removeChild(elem);
});
mainLogic();
this.showPopUp("Saved");
}
// 设置按钮透明度设置
rangeChange(bool) {
var odom = document.querySelector("#setBtnOpacityRange");
if (settingData.setBtnOpacity < 0) {
odom.style.background =
"-webkit-linear-gradient(left,#bdbdbd,#c6c7c7) no-repeat, #fff";
odom.style.backgroundSize = odom.value * 100 + "% 100%";
document.querySelector(".iqxin-setBtnOpacityRangeValue").innerHTML =
"禁用";
settingData.setBtnOpacity = -odom.value;
} else {
odom.style.background =
"-webkit-linear-gradient(left,#3ABDC1,#83e7ea) no-repeat, #fff";
odom.style.backgroundSize = odom.value * 100 + "% 100%";
let value = odom.value;
let valueStr = "";
if (value == 0) {
valueStr = "0.00";
} else if (value == 1) {
valueStr = "1.00";
} else {
valueStr = odom.value.toString().padEnd(4, "0");
}
document.querySelector(".iqxin-setBtnOpacityRangeValue").innerHTML =
valueStr;
settingData.setBtnOpacity = odom.value;
}
}
// 窗口大小改变
windowResize() {
var eleStyle = window.getComputedStyle(this.ele, null);
var w = parseInt(eleStyle.width);
var h = parseInt(eleStyle.height) + 54;
var ww = document.documentElement.clientWidth;
var wh = document.documentElement.clientHeight;
var maskStyle = this.mask.style;
if (w >= ww) {
maskStyle.justifyContent = "stretch";
} else {
maskStyle.justifyContent = "center";
}
if (h >= wh) {
maskStyle.alignItems = "stretch";
} else {
maskStyle.alignItems = "center";
}
}
saveData() {
this.addTitleEditBoxRemove(); //标题栏处于编辑状态
var obj = {};
var parentdiv = document.querySelectorAll("#settingLayer .iqxin-items");
for (let i = 0; i < parentdiv.length; i++) {
var data = parentdiv[i].querySelectorAll(".sej-engine");
var id = parentdiv[i].id;
obj[id] = [];
for (let ii = 0; ii < data.length; ii++) {
if (data[ii].dataset.xin < 0) {
var ij = -ii;
} else {
ij = ii;
}
obj[id][ij] = {};
obj[id][ij].favicon = data[ii].dataset.iqxinimg;
obj[id][ij].name = data[ii].dataset.iqxintitle;
obj[id][ij].url = data[ii].dataset.iqxinlink;
if (data[ii].dataset.iqxintarget) {
obj[id][ij].blank = data[ii].dataset.iqxintarget;
}
if (data[ii].dataset.iqxindisabled) {
obj[id][ij].disable = data[ii].dataset.iqxindisabled;
}
if (data[ii].dataset.iqxingbk) {
obj[id][ij].gbk = data[ii].dataset.iqxingbk;
}
}
}
// 分类名称
var engineDetails = [];
// 分类排序
var odetails = document.querySelectorAll(".sejtitle");
var odetailsLength = odetails.length;
for (let i = 0; i < odetailsLength; i++) {
engineDetails[i] = [];
engineDetails[i][0] = odetails[i].firstChild.innerHTML;
engineDetails[i][1] = odetails[i].dataset.iqxintitle;
engineDetails[i][2] = odetails[i].dataset.xin >= 0 ? true : false;
}
// 新标签页全局设置
var onewtab = document.querySelector(
"#iqxin-globalNewtab"
).selectedIndex;
var foldlist = document.querySelector("#iqxin-foldlist").checked;
// 以防不测,重新获取本地配置文件
var getData = GM_getValue("searchEngineJumpData");
getData.newtab = onewtab;
getData.foldlist = foldlist;
getData.setBtnOpacity = settingData.setBtnOpacity;
getData.center = document.querySelector("#iqxin-center").selectedIndex;
getData.fixedTop = document.querySelector("#iqxin-fixedTop").checked;
getData.allOpen = document.querySelector("#iqxin-allOpen-item").checked;
getData.fixedTopUpward = document.querySelector(
"#iqxin-fixedTopUpward-item"
).checked;
getData.transtion = document.querySelector("#iqxin-transtion").checked;
getData.HideTheSameLink = document.querySelector(
"#iqxin-HideTheSameLink"
).checked;
getData.selectSearch = document.querySelector(
"#iqxin-selectSearch"
).checked;
getData.engineDetails = engineDetails;
getData.engineList = obj;
GM_setValue("searchEngineJumpData", getData);
}
// 此处的样式主要是设置界面
addGlobalStyle() {
// 关闭设置菜单中的所有动画效果
if (!settingData.transtion) {
GM_addStyle(
"#settingLayer," +
"#btnEle span," +
"#btnEle2," +
".iqxin-set-del," +
"span.iqxin-additem," +
"#newSearchBox," +
".addItemBoxBtn," +
"#xin-close," +
"#settingLayerMask{" +
"transition:none;" +
"}" +
"#settingLayerMask{" +
"backdrop-filter:none;" +
// "background-color: rgba(0,0,0,.7);" +
"}" +
""
);
}
}
showPopUp(text, duration) {
new PopUp(text, duration);
}
}
class PopUp {
constructor(text, duration = 1500) {
this.popUp = document.createElement("iqxinDiv");
this.popUp.id = "iqixn-global-tip";
this.show(text);
setTimeout(() => {
this.destroy();
}, duration);
}
show(text) {
this.popUp.innerText = text;
document.body.appendChild(this.popUp);
this.popUp.style.opacity = 1;
}
destroy() {
this.popUp.style.opacity = 0;
const transitionTime =
parseFloat(getComputedStyle(this.popUp).transitionDuration) * 1000;
setTimeout(() => {
this.popUp.remove();
}, transitionTime);
}
}
class Style {
constructor() {
this.globalStyle = GM_getResourceText("GLOBAL_STYLE");
this.nonTransitionStyle = `.sej-engine,.sej-drop-list-trigger,.sej-drop-list{transition:none!important;}#sej-container{animation:none!important;}.sej-drop-list {backdrop-filter:none!important;}`;
this.addStyle(this.globalStyle);
if (!settingData.transtion) {
this.addStyle(this.nonTransitionStyle);
}
if (this.isDarkMode()) {
document.body.setAttribute("qxintheme", "dark");
}
}
addStyle(style) {
GM_addStyle(style);
}
isDarkMode() {
if (document.documentElement.hasAttribute("dark")) return true;
if (window.location.hostname.includes("spotify.com")) return true;
if (window.location.hostname.includes("discord.com")) return true;
if (document.documentElement.classList.contains("theme-dark")) return true;
if (window.matchMedia('(color-scheme: light)').matches) return false;
function getContrastYIQ(rgbColor) {
let r, g, b, a;
rgbColor = rgbColor.match(/rgba?\(([^)]+)\)/)[1];
rgbColor = rgbColor.split(/ *, */).map(Number);
[r, g, b, a] = rgbColor;
if (a < 0.5) {
return false;
}
const yiq = (r * 299 + g * 587 + b * 114) / 1000;
return yiq < 128;
}
return (
document.getElementsByTagName("meta")?.["color-scheme"]?.content ===
"dark" ||
getContrastYIQ(getComputedStyle(document.body).backgroundColor)
);
}
}
const settings = new Settings();
const settingData = settings.settingData;
engineList = settingData.engineList;
const matchedRule = settings.getMatchedRule();
const style = new Style();
const jumpBar = new JumpBar(engineList, settingData, matchedRule);
if (jumpBar.container) {
new SettingButton(jumpBar.container, settingData);
} else {
return;
}
}
})();