// ==UserScript==
// @name SearchJumper
// @name:zh-CN 搜索酱
// @name:zh-TW 搜尋醬
// @name:ja SearchJumper
// @name:ru SearchJumper
// @namespace hoothin
// @version 1.9.33
// @description Instantly search selected text across multiple search engines. Highlight keywords and boost your research efficiency.
// @description:zh-CN 一键即时搜索选定文本或在多个搜索引擎之间快速切换,支持关键词高亮、拖拽搜索、以图搜图、页内查找与自定义引擎。
// @description:zh-TW 一鍵即時搜尋選定文字或在多個搜尋引擎之間快速切換,支援關鍵字高亮、拖曳搜尋、以圖搜圖、頁內尋找與自訂引擎。
// @description:ja 選択したテキストをワンクリックで即座に検索したり、キーワードの強調表示、ドラッグアンドドロップ検索、画像検索、ページ内検索、カスタムエンジンをサポートする複数の検索エンジン間で素早く切り替えたりできます。
// @description:ru Легко проводите поиск по выбранному тексту/изображению/ссылке. Быстро переходите к любому поисковому движку. Выделяйте искомый текст.
// @author hoothin
// @license MPL-2.0
// @match *://*/*
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAclBMVEUAAAD+/v7////+/v7+/v7////+/v79/f3////////+/v7////////////+/v79/f3////+/v7/rP8zMzP/2f/R0dHAwMD/zf+vr69ZWVlKSkry8vL/vv/+5/7r6+uRkZGcnJx8fHxwcHD+7/7f39+kpKTMxXKjAAAAEXRSTlMA4wrL9ICvkxk56nVVI9WgZNxdEUkAAAE2SURBVDjLfdPZloMgDAZgFtHR2uU3LnWrXd//FUfIHKRT7XfhUYIkhINYqPyoM0SZTnIlPu2PEbwo2f8LqwTvIvMW/9H4oH+WeCqxQu79/xKr5N8aSmOD5gkGm3YuQYRNkU3CG+ynCYH6VsEycwW8wJXoDK8narlOIXI4Z6IKi47ucNI5A6vCOC41mBEaX8VCAuVQFEXzQODRzENDaVsRoSwYAgUrIecJI38MCAw8NkLaFCibphyDMusKox0DoJci+6615fcA2q5fikz8b/QC0HWuKTX8NnM/wbWSyL86qW01u1D3xEQ04dLSE0z6w3ILz9rWPq/hefslUN3uL+B6v/kKMiVmO2w6CSfGhqNg6oBVWvlbxTO+XAy1kiVWInTK8EZyfQFlZBDeKbEiNfFBSh2bNBj8BZ8mNsZysMSsAAAAAElFTkSuQmCC
// @grant GM.getValue
// @grant GM_getValue
// @grant GM.setValue
// @grant GM_setValue
// @grant GM_addStyle
// @grant GM.addStyle
// @grant GM.deleteValue
// @grant GM_deleteValue
// @grant GM.registerMenuCommand
// @grant GM_registerMenuCommand
// @grant GM.xmlHttpRequest
// @grant GM_xmlhttpRequest
// @grant GM.notification
// @grant GM_notification
// @grant GM.setClipboard
// @grant GM_setClipboard
// @grant GM.openInTab
// @grant GM_openInTab
// @grant GM.info
// @grant GM_info
// @grant unsafeWindow
// @compatible edge tested with tm
// @compatible Chrome tested with tm
// @compatible Firefox tested with tm
// @compatible Opera untested
// @compatible Safari untested
// @compatible ios tested with userscript
// @compatible android tested with kiwi
// @supportURL https://github.com/hoothin/SearchJumper/issues
// @homepage https://github.com/hoothin/SearchJumper
// @require https://update.greasyfork.icu/scripts/484118/searchJumperDefaultConfig.js
// @connect global.bing.com
// @connect suggestqueries.google.com
// @connect api.bing.com
// @connect suggestion.baidu.com
// @connect webdav.hoothin.com
// @connect search.hoothin.com
// @connect *
// @run-at document-start
// @downloadURL none
// ==/UserScript==
(async function() {
'use strict';
const ext = false;
const _unsafeWindow = (typeof unsafeWindow == 'undefined') ? window : unsafeWindow;
if (_unsafeWindow.searchJumperInited) return;
_unsafeWindow.searchJumperInited = true;
const clipboard = navigator && navigator.clipboard;
const inIframe = window.top !== window.self;
if (inIframe) {
try {
if (window.name === 'pagetual-iframe' || (window.frameElement && window.frameElement.name === 'pagetual-iframe')) {
return;
} else if (window.self.innerWidth === 0 && window.self.innerHeight === 0) {
let ignore = await new Promise(resolve => {
window.addEventListener('load', e => {
setTimeout(() => {
resolve(window.self.innerWidth < 300 || window.self.innerHeight < 300);
}, 500);
});
});
if (ignore) return;
} else if (window.self.innerWidth < 300 || window.self.innerHeight < 300) {
return;
}
} catch(e) {
return;
}
}
const importPageReg = /^https:\/\/github\.com\/hoothin\/SearchJumper(\/(issue|discussions)|\/?$|#|\?)|^https:\/\/greasyfork\.org\/.*\/scripts\/445274[\-\/].*\/discussions/i;
const mobileUa = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1";
const homePage = 'https://search.hoothin.com/';
const githubPage = 'https://hoothin.github.io/SearchJumper';
const firstRunPage = homePage + "firstRun";
let configPage = homePage + 'config/';
let isAllPage = false;
let searchData = {};
searchData.sitesConfig = sitesConfig;
searchData.prefConfig = {
position: {
x: "left",
y: "top"
},
offset: {
x: "0",
y: "0"
},
firstRun: true,
openInNewTab: false,
enableInPage: true,
altKey: false,
ctrlKey: true,
shiftKey: false,
metaKey: false,
autoClose: false,
autoDelay: 1000,
shortcut: true,
initShow: false,
alwaysShow: false,
customSize: 100,
tilesZoom: 100,
tipsZoom: 100,
typeOpenTime: 250,
longPressTime: 500,
noIcons: false,
showSiteLists: true,
alwaysShowSiteLists: false,
cacheSwitch: false,
noAni: false,
quickAddRule: true,
multiline: 2,
multilineGap: 1000,
historyLength: 0,
dragToSearch: true,
hideDragHistory: false,
sortType: false,
sortSite: false,
autoHide: false,
autoHideAll: false,
showCurrent: true,
shortcutKey: 'Backquote',
showInSearchEngine: false,
showInSearchJumpPage: true,
limitInPageLen: 1,
limitPopupLen: 1,
ignoreWords: ["a", "in", "into", "the", "to", "on", "among", "between", "and", "an", "of", "by", "with", "about", "under", "or", "at", "as"],
inPageRule: {},
firstFiveWordsColor: [],
inPageWordsStyles: [],
altToHighlight: true,
defaultPicker: false,
disableInputOnWords: false,
disableTypeOpen: false,
callBarAlt: false,
callBarCtrl: false,
callBarShift: false,
callBarMeta: false,
defaultFindTab: true,
disableAutoOpen: false,
hideOnSearchEngine: false,
minSizeMode: false,
hidePopup: false,
minPopup: 0,
selectToShow: ext,
expandType: false,
rightMouse: true,
shiftLastUsedType: true,
mouseLeaveToHide: true,
currentTypeFirst: true,
switchSitesPreKey: 'ArrowLeft',
switchSitesNextKey: 'ArrowRight',
switchSitesCtrl: true,
switchSitesAlt: false,
switchSitesShift: true,
switchSitesMeta: false
};
function run() {
let lang = navigator.appName === "Netscape" ? navigator.language : navigator.userLanguage;
let config = {};
function setLang() {
switch (lang) {
case "zh-CN":
case "zh-SG":
config = {
import: '导入',
filter: '筛选',
selectAll: '全选',
importOrNot: '是否导入配置?',
settings: '配置脚本',
batchOpen: '批量打开',
batchOpenConfirm: '确定要批量打开吗?',
postOver: '发送成功:',
postError: '发送失败:',
copyOver: '复制成功',
keywords: '请输入搜索词',
targetUrl: '请输入搜索URL',
siteName: '站名',
siteDesc: '描述',
siteUrl: '地址',
siteIcon: '图标',
siteTest: '测试',
siteCancel: '取消',
siteAdd: '添加',
siteType: '分类',
siteExist: '已存在相同规则,是否添加为克隆项?',
siteAddOver: '站点添加成功',
multiline: '是否以换行符分隔多行搜索?',
multilineTooMuch: '行数超过10行,是否继续搜索?',
inputPlaceholder: '筛选引擎',
inputTitle: '筛选引擎,支持 * ? 通配符,$代表末尾,^代表开头,分组**站点 可筛选指定分组,例如 图片**baidu,tab 下一项',
inputKeywords: '输入搜索关键词',
inPageTips: '自定义分隔符:$c 加分隔符,例如 $c| search | jumper,默认空格作为分隔符\n原始文本不分隔:$o 加文本,例如$oopai liked by hero\n正则表达式:/re/,例如 $c, /google/i , /aPPle/\n添加提示文本:搜索文本$t{提示文本},例如 linux$t{linux is not unix}\n添加自定义样式:搜索文本$s{背景;其他},例如 google$s{#333333;color:red;}\n左键点击关键词跳转至下一个,右键点击关键词跳转至上一个',
inPagePlaceholder: '输入文字,按下回车进行页内查找',
pickerBtn: '抓取元素',
multiPickerBtn: '抓取元素,按住 Ctrl 或 Command 连续抓取',
editBtn: '编辑查找文字',
emptyBtn: '清空查找文字',
copyInPageBtn: '复制查找文字',
wordModeBtn: '单词模式',
copyEleBtn: '复制选中元素',
openLinkBtn: '打开选中链接',
maxEleBtn: '展开选中元素',
minEleBtn: '收起选中元素',
expandAll: '全部展开',
collapseAll: '全部合起',
rename: '重命名',
recoverBtn: '恢复查找文字',
pinBtn: '固定查找文字,在所有标签页中搜索',
locBtn: '定位侧边栏',
filterSites: '搜索引擎',
searchInPage: '页内查找',
removeBtn: '移除搜索词',
saveRuleBtn: '保存当前站点的搜索词',
wordContent: '搜索词内容',
wordHide: '隐藏父级元素',
wordHideTips: '元素深度,0为当前父级',
wordStyle: '搜索词样式',
wordTitle: '搜索词注释',
re: '正则',
ignoreCase: '不区分大小写',
filterLink: '筛选链接',
modify: '修改',
cancel: '取消',
modifyWord: '修改页内搜索词',
addSearchEngine: '添加搜索引擎',
noValidItemAsk: '未找到有效元素,是否手动编辑规则并添加?',
expand: '展开剩余站点',
add: '添加',
addWord: '添加新词语',
wordRange: '生效范围',
customInputFrame: '自定义搜索参数',
customSubmit: '提交搜索',
finalSearch: '目标搜索字串',
search: '搜索此项',
siteKeywords: '关键词(多个关键词以|分隔)',
siteMatch: '站点 URL 匹配正则',
openSelect: '打开选项',
openInDefault: '默认',
openInNewTab: '新标签页打开',
openInCurrent: '当前页打开',
currentType: '当前分类',
maxAddSiteBtn: '最大化',
minAddSiteBtn: '还原',
addAction: '添加操作',
crawlInfo: '模拟输入搜索',
inputAction: '输入',
clickAction: '点击',
sleepAction: '等待',
copyAction: '📄复制元素',
submitCrawl: '☑️完成操作',
inputOutput: '在元素#t1#内输入#t2#',
clickOutput: '点击元素#t#',
dblclickOutput: '双击元素#t#',
rclickOutput: '右击元素#t#',
copyOutput: '复制元素#t#',
sleepOutput: '休眠#t#毫秒',
inputNewValue: '请输入新值',
deleteConfirm: '确定要删除此项吗?',
sleepPrompt: '等待时间(毫秒)',
startCache: '开始缓存,请耐心等待缓存完毕,勿关闭配置页!',
cacheOver: '所有图标都已缓存完毕!',
cspDisabled: '脚本样式被当前站点的 CSP 阻止,因此无法显示,请尝试安装 Allow CSP: Content-Security-Policy 扩展获取权限',
Sunday: '星期日 (日)',
Monday: '星期一 (月)',
Tuesday: '星期二 (火)',
Wednesday: '星期三 (水)',
Thursday: '星期四 (木)',
Friday: '星期五 (金)',
Saturday: '星期六 (土)',
template: '请设置【#t#】的值',
recordAction: '⏺️录制操作',
startRecord: '开始录制操作,按回车键结束录制',
loopAction: '🔁开始循环',
loopActionEnd: '⏹️循环结束',
loopStart: '开始循环,循环次数为#t#',
loopEnd: '结束循环',
loopTimes: '循环次数,将遍历所有匹配元素并顺序执行',
loadingCollection: '正在加载合集,请稍候……',
emuInputTips: '在指定页面元素(例如输入框)内输入搜索词',
emuClickTips: '单击指定页面元素(例如按钮)',
emuWaitTips: '等待一段时间后继续执行,当某个操作需要一段时间才能完成时很有用',
emuCopyTips: '复制指定元素的文本到剪贴板',
emuRecordTips: '录制接下来的点击和输入操作',
emuLoopTips: '开始循环,接下来的操作将遍历所有找到的元素并且重复指定次数',
emuStopTips: '结束操作并生成规则'
};
break;
case "zh":
case "zh-TW":
case "zh-HK":
config = {
import: '導入',
filter: '篩選',
selectAll: '全選',
importOrNot: '是否導入配置?',
settings: '配置脚本',
batchOpen: '批量打開',
batchOpenConfirm: '確定要批量打開嗎?',
postOver: '發送成功:',
postError: '發送失敗:',
copyOver: '複製成功',
keywords: '請輸入搜尋詞',
targetUrl: '請輸入搜尋URL',
siteName: '站名',
siteDesc: '描述',
siteUrl: '地址',
siteIcon: '圖標',
siteTest: '測試',
siteCancel: '取消',
siteAdd: '添加',
siteType: '分類',
siteExist: '已存在相同規則,是否添加為克隆項?',
siteAddOver: '站點添加成功',
multiline: '是否以換行符分隔多行搜尋?',
multilineTooMuch: '行數超過10行,是否繼續搜尋?',
inputPlaceholder: '篩選引擎',
inputTitle: '篩選引擎,支援 * ? 通配符,$代表末尾,^代表開頭,分組**站點 可篩選指定分組,例如 圖片**google,tab 下一項',
inputKeywords: '輸入搜尋關鍵詞',
inPageTips: '自定義分隔符:$c 加分隔符,例如 $c| search | jumper,默認空格作為分隔符\n原始文本不分隔:$o 加文本,例如$oopai liked by hero\n正則表達式:/re/,例如 $c, /google/i , /aPPle/\n添加提示文本:搜尋文本$t{提示文本},例如 linux$t{linux is not unix}\n添加自定義樣式:搜尋文本$s{背景;其他},例如 google$s{#333333;color:red;}\n左鍵點擊關鍵詞跳轉至下一個,右鍵點擊關鍵詞跳轉至上一個',
inPagePlaceholder: '輸入文字,按下回車進行頁內查找',
pickerBtn: '抓取元素',
multiPickerBtn: '抓取元素,按住 Ctrl 或 Command 連續抓取',
editBtn: '編輯查找文字',
emptyBtn: '清空查找文字',
copyInPageBtn: '複製查找文字',
wordModeBtn: '單詞模式',
copyEleBtn: '複製選中元素',
openLinkBtn: '打開選中連結',
maxEleBtn: '展開選中元素',
minEleBtn: '收起選中元素',
expandAll: '全部展開',
collapseAll: '全部合起',
rename: '重命名',
recoverBtn: '恢復查找文字',
pinBtn: '固定查找文字,在所有標籤頁中搜尋',
locBtn: '定位側邊欄',
filterSites: '搜尋引擎',
searchInPage: '頁內查找',
removeBtn: '移除搜尋詞',
saveRuleBtn: '保存當前站點的搜尋詞',
wordContent: '搜尋詞內容',
wordHide: '隱藏父級元素',
wordHideTips: '元素深度,0為當前父級',
wordStyle: '搜尋詞樣式',
wordTitle: '搜尋詞注釋',
re: '正則',
ignoreCase: '不區分大小寫',
filterLink: '篩選鏈接',
modify: '修改',
cancel: '取消',
modifyWord: '修改頁內搜尋詞',
addSearchEngine: '添加搜尋引擎',
noValidItemAsk: '未找到有效元素,是否手動編輯規則並添加?',
expand: '展開剩餘站點',
add: '添加',
addWord: '添加新詞語',
wordRange: '生效範圍',
customInputFrame: '自定義搜尋參數',
customSubmit: '提交搜尋',
finalSearch: '目標搜尋字串',
search: '搜尋此項',
siteKeywords: '關鍵詞(多個關鍵詞以|分隔)',
siteMatch: '站點 URL 匹配正則',
openSelect: '打開選項',
openInDefault: '默認',
openInNewTab: '新標籤頁打開',
openInCurrent: '當前頁打開',
currentType: '當前分類',
maxAddSiteBtn: '最大化',
minAddSiteBtn: '還原',
addAction: '添加操作',
crawlInfo: '模擬輸入搜尋',
inputAction: '輸入',
clickAction: '點擊',
sleepAction: '等待',
copyAction: '📄複製元素',
submitCrawl: '☑️完成操作',
inputOutput: '在元素#t1#內輸入#t2#',
clickOutput: '點擊元素#t#',
dblclickOutput: '雙擊元素#t#',
rclickOutput: '右擊元素#t#',
copyOutput: '複製元素#t#',
sleepOutput: '休眠#t#毫秒',
inputNewValue: '請輸入新值',
deleteConfirm: '確定要刪除此項嗎? ',
sleepPrompt: '等待時間(毫秒)',
startCache: '開始緩存,請耐心等待緩存完畢,勿關閉配置頁!',
cacheOver: '所有圖標都已緩存完畢!',
cspDisabled: '腳本樣式被當前站點的 CSP 阻止,因此無法顯示,請嘗試安裝 Allow CSP: Content-Security-Policy 擴展獲取權限',
Sunday: '星期日 (日)',
Monday: '星期一 (月)',
Tuesday: '星期二 (火)',
Wednesday: '星期三 (水)',
Thursday: '星期四 (木)',
Friday: '星期五 (金)',
Saturday: '星期六 (土)',
template: '請設置【#t#】的值',
recordAction: '⏺️錄製動作',
startRecord: '開始錄製操作,按下回車鍵結束錄製',
loopAction: '🔁開始循環',
loopActionEnd: '⏹️循環結束',
loopStart: '開始循環,循環次數為#t#',
loopEnd: '結束循環',
loopTimes: '循環次數,將遍歷所有匹配元素並順序執行',
loadingCollection: '正在載入合集,請稍候……',
emuInputTips: '在指定頁面元素(例如輸入框)內輸入搜尋字詞',
emuClickTips: '點擊指定頁面元素(例如按鈕)',
emuWaitTips: '等待一段時間後繼續執行,當某個操作需要一段時間才能完成時很有用',
emuCopyTips: '複製指定元素的文字到剪貼簿',
emuRecordTips: '錄製接下來的點擊和輸入操作',
emuLoopTips: '開始循環,接下來的操作將遍歷所有找到的元素並且重複指定次數',
emuStopTips: '結束操作並產生規則'
};
break;
case 'ja':
config = {
import: 'インポート',
filter: 'フィルター',
selectAll: 'すべて選択',
importOrNot: '設定をインポートしますか? ',
settings: '構成スクリプト',
batchOpen: 'バッチオープン',
batchOpenConfirm: 'バッチオープンしてもよろしいですか? ',
postOver: '正常に送信されました:',
postError: '送信に失敗しました:',
copyOver: 'コピーに成功しました',
keywords: '検索語を入力してください',
targetUrl: '検索 URL を入力してください',
siteName: 'サイト名',
siteDesc: '説明',
siteUrl: 'アドレス',
siteIcon: 'アイコン',
siteTest: 'テスト',
siteCancel: 'キャンセル',
siteAdd: '追加',
siteType: 'カテゴリ',
siteExist: '同じルールがすでに存在します。クローンとして追加しますか? ',
siteAddOver: 'サイトは正常に追加されました',
multiline: '複数行の検索は改行で区切るべきですか? ',
multilineTooMuch: '行数が 10 行を超えています。検索を続けますか? ',
inputPlaceholder: 'フィルタリング エンジン',
inputTitle: 'フィルタリング エンジン、*? ワイルドカードをサポート、$ は終わりを表し、^ は始まりを表します、グループ ** サイトは写真などの指定されたグループをフィルターできます ** Google、次の項目をタブします',
inputKeywords: '検索キーワードを入力してください',
inPageTips: 'カスタム区切り文字: $c と区切り文字 ($c| 検索 | ジャンパーなど)、デフォルトのスペースを区切り文字として使用\n元のテキストは分離されていません: $o と文字 (ヒーローが好んだ $oopai など)\n正規表現 :/re/ 、$c、/google/i、/aPPle/ など\nプロンプト テキストの追加: 検索テキスト $t{プロンプト テキスト}、たとえば linux$t{Linux は Unix ではありません}\nカスタム スタイルの追加: 検索テキスト $s{背景;other}、例: google$s{#333333;color:red;}\nキーワードを左クリックすると次のキーワードにジャンプし、キーワードを右クリックすると前のキーワードにジャンプします',
inPagePlaceholder: 'ページ内を検索するには、テキストを入力して Enter キーを押してください',
pickerBtn: '要素の取得',
multiPickerBtn: '要素を取得するには、Ctrl または Command を押したまま継続的に取得します',
editBtn: '検索テキストを編集',
emptyBtn: '空の検索テキスト',
copyInPageBtn: '検索テキストをコピー',
wordModeBtn: 'ワードモード',
copyEleBtn: '選択した要素をコピー',
openLinkBtn: '選択したリンクを開く',
maxEleBtn: '選択した要素を展開',
minEleBtn: '選択した要素を折りたたむ',
expandAll: 'すべて展開',
collapseAll: 'すべて折り',
rename: '名前を変更',
reverseBtn: '検索テキストを復元',
pinBtn: '検索テキストを修正、すべてのタブで検索',
locBtn: 'サイドバーを検索',
filterSites: '検索エンジン',
searchInPage: 'ページ内を検索',
removeBtn: '検索語を削除',
saveRuleBtn: '現在のサイトの検索語を保存',
wordContent: '単語の内容を検索',
wordHide: '親要素を非表示',
wordHideTips: '要素の深さ、0 が現在の親',
wordStyle: '検索ワードスタイル',
wordTitle: '検索単語の注釈',
re: 'RegExp',
ignoreCase: '大文字と小文字は区別されません',
filterLink: 'フィルターリンク',
modify: '変更',
cancel: 'キャンセル',
modifyWord: 'ページ上の検索ワードを変更します',
addSearchEngine: '検索エンジンを追加',
noValidItemAsk: '有効な要素が見つかりません。ルールを手動で編集して追加しますか? ',
expand: '残りのサイトを展開します',
add: '追加',
addWord: '新しい単語を追加',
wordRange: '有効範囲',
customInputFrame: 'カスタム検索パラメータ',
customSubmit: '検索を送信',
finalSearch: '対象の検索文字列',
search: 'このアイテムを検索',
siteKeywords: 'キーワード (| で区切られた複数のキーワード)',
siteMatch: '通常のサイト URL と一致',
openSelect: 'オプションを開く',
openInDefault: 'デフォルト',
openInNewTab: '新しいタブが開きます',
openInCurrent: '現在のページが開いています',
currentType: '現在のカテゴリ',
maxAddSiteBtn: '最大化',
minAddSiteBtn: '復元',
addAction: 'アクションを追加',
rollInfo: '入力検索をシミュレート',
inputAction: '入力',
clickAction: 'クリック',
sleepAction: '待機',
copyAction: '📄要素のコピー',
submitCrawl: '☑️操作を完了',
inputOutput: '要素 #t1# 内に #t2# を入力します',
clickOutput: 'クリック#t#',
dblclickOutput: 'ダブルクリック#t#',
rclickOutput: '右クリック#t#',
copyOutput: 'コピー要素#t#',
sleepOutput: 'スリープ#t# ミリ秒',
inputNewValue: '新しい値を入力してください',
deleteconfirm: 'この項目を削除してもよろしいですか? ',
sleepPrompt: '待機時間 (ミリ秒)',
startCache: 'キャッシュを開始します。キャッシュが完了するまで辛抱強く待ってください。設定ページは閉じないでください。 ',
cacheOver: 'すべてのアイコンがキャッシュされました! ',
cspDisabled: 'スクリプト スタイルは現在のサイトの CSP によってブロックされているため、表示できません。許可を取得するには、Allow CSP: Content-Security-Policy 拡張機能をインストールしてみてください',
Sunday: '日曜日',
Monday: '月曜日',
Tuesday: '火曜日',
Wednesday: '水曜日',
Thursday: '木曜日',
Friday: '金曜日',
Saturday: '土曜日',
template: '[#t#]の値を設定してください',
recordAction: '⏺️記録操作',
startRecord: '記録操作を開始します。記録を終了するには Enter キーを押してください',
loopAction: '🔁ループの開始',
loopActionEnd: '⏹️ループの終了',
loopStart: 'ループを開始。ループ数は #t# です',
loopEnd: 'ループの終了',
loopTimes: 'ループの数。一致するすべての要素が走査され、順番に実行されます',
loadingCollection: 'コレクションを読み込み中...',
emuInputTips: '指定されたページ要素 (入力ボックスなど) に検索語を入力します',
emuClickTips: '指定されたページ要素 (ボタンなど) をクリックします',
emuWaitTips: '続行する前にしばらく待ってください。操作が完了するまでに時間がかかる場合に便利です',
emuCopyTips: '指定された要素のテキストをクリップボードにコピーします',
emuRecordTips: '次のクリックと入力操作を記録します',
emuLoopTips: 'ループを開始します。次の操作は見つかったすべての要素を走査し、指定された回数だけ繰り返します',
emuStopTips: '操作を終了してルールを生成'
};
break;
case 'ru':
config = {
import: 'Импортировать',
filter: 'Фильтровать',
selectAll: 'Выбрать всё',
importOrNot: 'Импортировать эту конфигурацию?',
settings: 'Настройки',
batchOpen: 'Групповой поиск',
batchOpenConfirm: 'Искать с помощью всех движков группы?',
postOver: 'Post over: ',
postError: 'Post fail: ',
copyOver: 'Скопировано успешно',
keywords: 'Input keywords',
targetUrl: 'Input URL',
siteName: 'Название',
siteDesc: 'Описание',
siteUrl: 'URL',
siteIcon: 'Иконка',
siteTest: 'Тест',
siteCancel: 'Отменить',
siteAdd: 'Добавить',
siteType: 'Группа',
siteExist: 'Движок уже существует. Добавить его как клон?',
siteAddOver: 'Движок успешно добавлен',
multiline: 'Использовать многострочный поиск?',
multilineTooMuch: 'Количество строк превышает 10. Продолжить поиск?',
inputPlaceholder: 'Фильтры',
inputTitle: 'Filter engines, support * ? wildcards, $ means end, ^ means start, type name**site name to filter type like "image**google", tab to next. ',
inputKeywords: 'Ввести ключевые слова поиска',
inPageTips: 'Custom delimiter: $c + delimiter, such as $c| search | jumper, space as delimiter by default\nOriginal text without delimited: $o + text, such as $oopai liked by hero\nRegular expression: /re/, such as $c, /google/i , /aPPle/\nTips text: search text$t{tips text}, such as linux$t{linux is not unix}\nCustom style: Search text$s{background;other}, such as google$s{#333333;color:red;}\nLeft-click keyword to jump to the next, right-click keyword to jump to the previous',
inPagePlaceholder: 'Для поиска введите текст и нажмите Enter',
pickerBtn: 'Выбрать область',
multiPickerBtn: 'Выбрать элемент или выбрать несколько элементов с помощью Ctrl или Command',
editBtn: 'Редактировать текст поиска',
emptyBtn: 'Очистить поле ввода',
copyInPageBtn: 'Скопировать текст поика',
wordModeBtn: 'Режим поиска по словам. В поле ввода можно ввести целое предложение, после чего на странице будут искаться все слова по отдельности из которого состоит предложение',
copyEleBtn: 'Скопировать выбранные элементы',
openLinkBtn: 'Открыть выбранные ссылки',
maxEleBtn: 'Расширить выбранные элементы',
minEleBtn: 'Сжать выбранные элементы',
expandAll: 'Развернуть всё',
collapseAll: 'Свернуть всё',
rename: 'Rename',
recoverBtn: 'Recover find text',
pinBtn: 'Выделить цветом текущие ключевые слова поиска по странице во всех открытых вкладках',
locBtn: 'Отображать совпадения справа на панели',
filterSites: 'Фильтровать движки',
searchInPage: 'Искать на странице',
removeBtn: 'Удалить правило поиска',
saveRuleBtn: 'Сохранить правило поиска текущего сайта',
wordContent: 'Слово или фраза для поиска',
wordHide: 'Hide parent element',
wordHideTips: 'Глубина элемента, 0 - это текущее значение',
wordStyle: 'Стиль выделения слова',
wordTitle: 'Аннотация к искомому слову',
re: 'RegExp',
ignoreCase: 'Игнорировать регистр',
filterLink: 'Фильтровать ссылку',
modify: 'Готово',
cancel: 'Отменить',
modifyWord: 'Изменить параметры',
addSearchEngine: 'Добавить движок',
noValidItemAsk: 'Не найден подходящий элемент. Хотите вручную добавить сайт?',
expand: 'Развернуть другие сайты',
add: 'Добавить',
addWord: 'Добавить новое слово',
wordRange: 'Выделить область поиска',
customInputFrame: 'Пользовательские параметры поиска',
customSubmit: 'Принять',
finalSearch: 'Целевая строка поиска',
search: 'Искать это',
siteKeywords: 'Ключевые слова (разделитель |)',
siteMatch: 'Regexp для соответствия URL сайта',
openSelect: 'Открыть в',
openInDefault: 'По умолчанию',
openInNewTab: 'Открыть в новой вкладке',
openInCurrent: 'Открыть в текущей вкладке',
currentType: 'Current',
maxAddSiteBtn: 'Развернуть',
minAddSiteBtn: 'Свернуть',
addAction: 'Добавить действия',
crawlInfo: 'Симуляция действий на сайте',
inputAction: 'Ввод',
clickAction: 'Клик мыши',
sleepAction: 'Ожидание',
copyAction: '📄Копировать элемент',
submitCrawl: '☑️Завешить действие',
inputOutput: 'Ввод #t2# в элемент #t1#',
clickOutput: 'Клик по элементу #t#',
dblclickOutput: 'Двойной клик #t#',
rclickOutput: 'щелкните ПКМ #t#',
copyOutput: 'Копировать элемент #t#',
sleepOutput: 'Ждать #t# миллисекунд',
inputNewValue: 'Введите новое значение',
deleteConfirm: 'Хотите удалить этот элемент? ',
sleepPrompt: 'Время ожидания (в миллисекундах)',
startCache: 'Началось кширование закрывайте страницу!',
cacheOver: 'Все иконки кэшированы!',
cspDisabled: 'The style of SearchJumper is blocked by the CSP of current site, please try to install the Allow CSP: Content-Security-Policy extension to obtain permission',
template: 'Установите значение "#t#"',
recordAction: '⏺️Записать действие',
startRecord: 'Сейчас начнется запись действия. После завершения нажмите Enter, чтобы вернуться в окно редактирования.',
loopAction: '🔁Начать цикл',
loopActionEnd: '⏹️Остановить цикл',
loopStart: 'Начать цикл #t# раз',
loopEnd: 'Остановить цикл',
loopTimes: 'Количество циклов, все совпадающие элементы будут пройдены и выполнены последовательно',
loadingCollection: 'Preparing collection for SearchJumper...',
emuInputTips: 'Ввести поисковые запросы в указанные элементы страницы (например, в поля ввода).',
emuClickTips: 'Кликнуть по указанному элементу страницы (например, по кнопке)',
emuWaitTips: 'Подождите некоторое время, прежде чем продолжить. Полезно, когда операция требует некоторого времени для завершения',
emuCopyTips: 'Копирование текста указанного элемента в буфер обмена',
emuRecordTips: 'Записать следующие нажатия и операции ввода',
emuLoopTips: 'Запустить цикл, следующая операция будет обходить все найденные элементы и повторяться указанное количество раз',
emuStopTips: 'Завершить операцию и создать правило'
};
break;
default:
config = {
import: 'Import',
filter: 'Filter',
selectAll: 'SelectAll',
importOrNot: 'Do you want to import this config?',
settings: 'Settings',
batchOpen: 'Batch open',
batchOpenConfirm: 'Batch open urls?',
postOver: 'Post over: ',
postError: 'Post fail: ',
copyOver: 'Copied successfully',
keywords: 'Input keywords',
targetUrl: 'Input URL',
siteName: 'Site Name',
siteDesc: 'Description',
siteUrl: 'Site Url',
siteIcon: 'Site Icon',
siteTest: 'Test',
siteCancel: 'Cancel',
siteAdd: 'Add',
siteType: 'Category',
siteExist: 'Site is already exist, add it as clone?',
siteAddOver: 'Site added successfully',
multiline: 'Search as multilines?',
multilineTooMuch: 'The number of lines exceeds 10, do you want to continue searching?',
inputPlaceholder: 'Filter engines',
inputTitle: 'Filter engines, support * ? wildcards, $ means end, ^ means start, type name**site name to filter type like "image**google", tab to next. ',
inputKeywords: 'Enter search keywords',
inPageTips: 'Custom delimiter: $c + delimiter, such as $c| search | jumper, space as delimiter by default\nOriginal text without delimited: $o + text, such as $oopai liked by hero\nRegular expression: /re/, such as $c, /google/i , /aPPle/\nTips text: search text$t{tips text}, such as linux$t{linux is not unix}\nCustom style: Search text$s{background;other}, such as google$s{#333333;color:red;}\nLeft-click keyword to jump to the next, right-click keyword to jump to the previous',
inPagePlaceholder: 'Input text, press Enter to find in the page',
pickerBtn: 'Pick a element',
multiPickerBtn: 'Pick a element, pick multi elements with Ctrl or Command',
editBtn: 'Edit search text',
emptyBtn: 'Empty search text',
copyInPageBtn: 'Copy search text',
wordModeBtn: 'Word mode',
copyEleBtn: 'Copy selected elements',
openLinkBtn: 'Open selected links',
maxEleBtn: 'Expand selected elements',
minEleBtn: 'Collapse selected elements',
expandAll: 'Expand All',
collapseAll: 'Collapse All',
rename: 'Rename',
recoverBtn: 'Recover find text',
pinBtn: 'Pin search text to search in all tabs',
locBtn: 'Sidebar to locate',
filterSites: 'Search engines',
searchInPage: 'Find in page',
removeBtn: 'Remove search term',
saveRuleBtn: 'Save the search term of the current site',
wordContent: 'Search word content',
wordHide: 'Hide parent element',
wordHideTips: 'Element depth, 0 means the current',
wordStyle: 'Search word style',
wordTitle: 'Search word annotation',
re: 'RegExp',
ignoreCase: 'Ignore case',
filterLink: 'Filter link',
modify: 'Modify',
cancel: 'Cancel',
modifyWord: 'Modify search word',
addSearchEngine: 'Add search engine',
noValidItemAsk: 'No valid element found, do you want to manually edit the rule and add it?',
expand: 'Expand other sites',
add: 'Add',
addWord: 'Add new word',
wordRange: 'Effective range',
customInputFrame: 'Custom search parameters',
customSubmit: 'Submit',
finalSearch: 'Target search string',
search: 'Search this',
siteKeywords: 'Keywords(split by |)',
siteMatch: 'Regexp to match site URL',
openSelect: 'Open option',
openInDefault: 'Default',
openInNewTab: 'Open a new tab',
openInCurrent: 'Open in current',
currentType: 'Current',
maxAddSiteBtn: 'Maximize',
minAddSiteBtn: 'Restore',
addAction: 'Add Actions',
crawlInfo: 'Analog input search',
inputAction: 'Input',
clickAction: 'Click',
sleepAction: 'Wait',
copyAction: '📄Copy element',
submitCrawl: '☑️Complete operation',
inputOutput: 'Input #t2# in the element #t1#',
clickOutput: 'Click on element #t#',
dblclickOutput: 'Double click #t#',
rclickOutput: 'Right click #t#',
copyOutput: 'Copy element #t#',
sleepOutput: 'Sleep for #t# milliseconds',
inputNewValue: 'Please enter a new value',
deleteConfirm: 'Are you sure you want to delete this item? ',
sleepPrompt: 'Wait time (milliseconds)',
startCache: 'Start cache icons of engines, do not close this page!',
cacheOver: 'All icons cached!',
cspDisabled: 'The style of SearchJumper is blocked by the CSP of current site, please try to install the Allow CSP: Content-Security-Policy extension to obtain permission',
template: 'Please set the value of "#t#"',
recordAction: '⏺️Record operation',
startRecord: 'Start to record operation, press Enter to end',
loopAction: '🔁Start loop',
loopActionEnd: '⏹️Stop loop',
loopStart: 'Start loop #t# times',
loopEnd: 'Stop loop',
loopTimes: 'Number of loops, all matching elements will be traversed and executed sequentially',
loadingCollection: 'Preparing collection for SearchJumper...',
emuInputTips: 'Enter search terms in specified page elements (such as input boxes)',
emuClickTips: 'Click on a specified page element (such as a button)',
emuWaitTips: 'Wait for a while before continuing, useful when an operation takes a while to complete',
emuCopyTips: 'Copy the text of the specified element to the clipboard',
emuRecordTips: 'Record the next clicks and input operations',
emuLoopTips: 'Start the loop, the next operation will traverse all found elements and repeat the specified number of times',
emuStopTips: 'End the operation and generate rules'
};
break;
}
}
function i18n(name, param) {
return config[name] ? (param ? config[name].replace(/#t#/g, param).replace(/#t1#/g, param[0]).replace(/#t2#/g, param[1]) : config[name]) : name;
};
const isMobile = ('ontouchstart' in document.documentElement);
var enableDebug = true;
var debug = (str, title) => {
if(enableDebug) {
console.log(
`%c【SearchJumper v.${_GM_info.script.version}】 ${title ? title : 'debug'}`,
'color: orange;font-size: large;font-weight: bold;',
str
);
}
};
var disabled = false;
var isInConfigPage = false;
var lastRequestUrl;
function createHTML(html = "", doc) {
const targetDoc = doc || document;
const fragment = targetDoc.createDocumentFragment();
if (html === null || html === undefined || html === '') return fragment;
parseHTMLToFragment(String(html), fragment, targetDoc);
return fragment;
}
let canDirectSetHTML = true;
let canPolicySetHTML = true;
let escapeHTMLPolicy;
let escapeHTMLCreator;
const MY_POLICY_NAME = 'searchjumper_default';
const SVG_NS = 'http://www.w3.org/2000/svg';
const VOID_TAGS = {
area: true,
base: true,
br: true,
col: true,
embed: true,
hr: true,
img: true,
input: true,
link: true,
meta: true,
param: true,
source: true,
track: true,
wbr: true
};
const RAW_TEXT_TAGS = {
script: true,
style: true,
textarea: true,
title: true,
xmp: true,
plaintext: true,
noscript: true
};
const HTML_ENTITIES = {
amp: '&',
lt: '<',
gt: '>',
quot: '"',
apos: "'",
nbsp: '\u00A0'
};
function decodeEntities(text) {
return text.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z]+);/g, function(_, code) {
if (code[0] === '#') {
const isHex = code[1] === 'x' || code[1] === 'X';
const num = parseInt(code.slice(isHex ? 2 : 1), isHex ? 16 : 10);
if (!isNaN(num)) {
try { return String.fromCodePoint(num); } catch(e) {}
}
return '&' + code + ';';
}
const key = code.toLowerCase();
return (key in HTML_ENTITIES) ? HTML_ENTITIES[key] : '&' + code + ';';
});
}
function parseHTMLToFragment(html, fragment, doc) {
const stack = [fragment];
const tokenRe = /|]*>|<\/?[a-zA-Z][^>]*>|[^<]+/gi;
let match;
while ((match = tokenRe.exec(html))) {
const token = match[0];
if (token[0] !== '<') {
const text = decodeEntities(token);
if (text) stack[stack.length - 1].appendChild(doc.createTextNode(text));
continue;
}
if (token.indexOf('