Instantly search selected text across multiple search engines. Highlight keywords and boost your research efficiency.
// ==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.org/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 // ==/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.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: false, 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: '在元素<span title="#t1#" class="element">#t1#</span>内输入<span title="#t2#">#t2#</span>', clickOutput: '点击元素<span title="#t#" class="element">#t#</span>', dblclickOutput: '双击元素<span title="#t#" class="element">#t#</span>', rclickOutput: '右击元素<span title="#t#" class="element">#t#</span>', copyOutput: '复制元素<span title="#t#" class="element">#t#</span>', sleepOutput: '休眠<span title="#t#">#t#</span>毫秒', 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: '开始循环,循环次数为<span title="#t#">#t#</span>', 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: '在元素<span title="#t1#" class="element">#t1#</span>內輸入<span title="#t2#">#t2#</span>', clickOutput: '點擊元素<span title="#t#" class="element">#t#</span>', dblclickOutput: '雙擊元素<span title="#t#" class="element">#t#</span>', rclickOutput: '右擊元素<span title="#t#" class="element">#t#</span>', copyOutput: '複製元素<span title="#t#" class="element">#t#</span>', sleepOutput: '休眠<span title="#t#">#t#</span>毫秒', 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: '開始循環,循環次數為<span title="#t#">#t#</span>', 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: '要素 <span title="#t1#" class="element">#t1#</span> 内に <span title="#t2#">#t2#</span> を入力します', clickOutput: 'クリック<span title="#t#" class="element">#t#</span>', dblclickOutput: 'ダブルクリック<span title="#t#" class="element">#t#</span>', rclickOutput: '右クリック<span title="#t#" class="element">#t#</span>', copyOutput: 'コピー要素<span title="#t#" class="element">#t#</span>', sleepOutput: 'スリープ<span title="#t#">#t#</span> ミリ秒', 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: 'ループを開始。ループ数は <span title="#t#">#t#</span> です', 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: 'Ввод <span title="#t2#">#t2#</span> в элемент <span title="#t1#" class="element">#t1#</span>', clickOutput: 'Клик по элементу <span title="#t#" class="element">#t#</span>', dblclickOutput: 'Двойной клик <span title="#t#" class="element">#t#</span>', rclickOutput: 'щелкните ПКМ <span title="#t#" class="element">#t#</span>', copyOutput: 'Копировать элемент <span title="#t#" class="element">#t#</span>', sleepOutput: 'Ждать <span title="#t#">#t#</span> миллисекунд', 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: 'Начать цикл <span title="#t#">#t#</span> раз', 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: 'Filter 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 <span title="#t2#">#t2#</span> in the element <span title="#t1#" class="element">#t1#</span>', clickOutput: 'Click on element <span title="#t#" class="element">#t#</span>', dblclickOutput: 'Double click <span title="#t#" class="element">#t#</span>', rclickOutput: 'Right click <span title="#t#" class="element">#t#</span>', copyOutput: 'Copy element <span title="#t#" class="element">#t#</span>', sleepOutput: 'Sleep for <span title="#t#">#t#</span> 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 <span title="#t#">#t#</span> 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 = "") { return escapeHTMLPolicy ? escapeHTMLPolicy.createHTML(html) : html; } var _GM_xmlhttpRequest, _GM_registerMenuCommand, _GM_notification, _GM_setClipboard, _GM_openInTab, _GM_addStyle, _GM_info, GM_fetch; if (typeof GM_xmlhttpRequest != 'undefined') { _GM_xmlhttpRequest = GM_xmlhttpRequest; GM_fetch = true; } else if (typeof GM != 'undefined' && typeof GM.xmlHttpRequest != 'undefined') { _GM_xmlhttpRequest = GM.xmlHttpRequest; GM_fetch = true; } else {//will not cross csp, it's safe! let res; _GM_xmlhttpRequest = (f) => {fetch(f.url, {method: f.method || 'GET', body: f.data, headers: f.headers}).then(response => { res = response; if (f.responseType === "blob") { return response.blob(); } return response.text(); }).then(data => { let doc = document.implementation.createHTMLDocument(''); doc.documentElement.innerHTML = createHTML(data); f.onload && f.onload({status: res.status, response: data, responseXML: doc}) }).catch(e => f.onerror && f.onerror(e))}; } if (GM_fetch) { GM_fetch = async (url, option) => { if (!url) return null; lastRequestUrl = url; return new Promise((resolve, reject) => { let isPost = option && /^post$/i.test(option.method); let requestOption = { method: (option && option.method) || 'GET', url: url, headers: (option && option.headers) || { referer: url, origin: url, "Content-Type": (isPost ? "application/x-www-form-urlencoded" : ""), 'X-Requested-With': (isPost ? 'XMLHttpRequest' : '') }, onload: function(d) { if (lastRequestUrl != url) return; let response = d.response; if (d.status >= 400 || !response) response = ""; let text = () => new Promise((r) => { r(response); }); let json = () => new Promise((r) => { try { r(JSON.parse(response)); } catch (e) { r(null); } }); resolve({text: text, json: json, finalUrl: (d.finalUrl || url)}); }, onerror: function(e) { debug(e); reject(e); }, ontimeout: function(e) { debug(e); reject(e); } }; if (option && option.body) { requestOption.data = option.body; } if (option && option.responseType === "stream") { requestOption.responseType = "stream"; delete requestOption.onload; requestOption.onloadstart = d => { if (!d || !d.response || !d.response.getReader) return; let bytes = [], callBack, buffer; const reader = d.response.getReader(); let json = () => { let result = ""; try { if (buffer) { result = buffer.trim(); if (/^data:/.test(result)) { result = "[" + result.replace(/^data:\s+\[DONE\]\s*/m, "").trim().replace(/\n+/g, "\n").split("\n").map(line => line.replace(/^data:/, "")).join(",") + "]"; } else if (/^({.*} *\n)* *{.*}$/.test(result)) { result = result.split("\n").pop(); } else if (/^\[[\s\S]+[^\]]$/.test(result)) { result = result + "]"; } } return JSON.parse(result); } catch (e) { return null; } }; reader.read().then(function readBytes({done, value}) { if (lastRequestUrl != url) return; if (done) { resolve({text: buffer, json: json, finalUrl: (d.finalUrl || url)}); return; } bytes = option.streamMode === "standalone" ? Array.from(value) : bytes.concat(Array.from(value)); try { buffer = new TextDecoder('utf-8').decode(new Uint8Array(bytes)); option.onstream({text: buffer, json: json, finalUrl: (d.finalUrl || url)}); } catch (e) { console.log(e); } return reader.read().then(readBytes); }); }; } _GM_xmlhttpRequest(requestOption); }); } } else GM_fetch = fetch; if (inIframe) { _GM_registerMenuCommand = (s, f) => {}; } else if (typeof GM_registerMenuCommand != 'undefined') { _GM_registerMenuCommand = GM_registerMenuCommand; } else if (typeof GM != 'undefined' && typeof GM.registerMenuCommand != 'undefined') { _GM_registerMenuCommand = GM.registerMenuCommand; } else { _GM_registerMenuCommand = (s, f) => {}; } if (ext) { _GM_openInTab = (s, t) => { chrome.runtime.sendMessage({action: "openInTab", detail: {url: s, incognito: t && t.incognito, active: t && t.active, close: t && t.close}}); }; } else if (typeof GM_openInTab != 'undefined') { _GM_openInTab = GM_openInTab; } else if (typeof GM != 'undefined' && typeof GM.openInTab != 'undefined') { _GM_openInTab = GM.openInTab; } else { _GM_openInTab = (s, t) => {window.open(s)}; } if (ext) { _GM_notification = s => { chrome.runtime.sendMessage({action: "notification", detail: {message: s}}); } } else if (typeof GM_notification != 'undefined') { _GM_notification = s => GM_notification({text: s, onclick: e => _GM_openInTab(configPage, {active: true})}); } else if (typeof GM != 'undefined' && typeof GM.notification != 'undefined') { _GM_notification = s => GM.notification({text: s, onclick: e => _GM_openInTab(configPage, {active: true})}); } else { _GM_notification = (s) => {}; } if (typeof GM_setClipboard != 'undefined') { _GM_setClipboard = GM_setClipboard; } else if (typeof GM != 'undefined' && typeof GM.setClipboard != 'undefined') { _GM_setClipboard = GM.setClipboard; } else { _GM_setClipboard = (s, i) => { try { clipboard.writeText(s) .then(() => { console.log('Text copied to clipboard'); }) .catch((error) => { document.execCommand('copy'); console.error('Failed to copy text: ', error); }); } catch (e) { document.execCommand('copy'); } }; } _GM_addStyle = cssStr => { cssStr = cssStr.replace(/\n\s*/g, ""); if (typeof GM_addStyle != 'undefined') { return GM_addStyle(cssStr); } else { let styleEle = document.createElement("style"); styleEle.innerHTML = createHTML(cssStr); document.head.appendChild(styleEle); return styleEle; } }; if (typeof GM_info != 'undefined') { _GM_info = GM_info; } else if (typeof GM != 'undefined' && typeof GM.info != 'undefined') { _GM_info = GM.info; } else { _GM_info = { script: {name: 'SearchJumper', version: 0} }; } if (!_unsafeWindow.searchJumperAddons) _unsafeWindow.searchJumperAddons = []; const curRef = document.referrer; let href = location.href.slice(0, 500); var storage = { supportGM: typeof GM_getValue == 'function' && typeof GM_getValue('a', 'b') != 'undefined', supportGMPromise: typeof GM != 'undefined' && typeof GM.getValue == 'function' && typeof GM.getValue('a','b') != 'undefined', supportCrossSave: function() { return this.supportGM || this.supportGMPromise; }, listItemCache: [], mxAppStorage: (function() { try { return window.external.mxGetRuntime().storage; } catch(e) { } })(), operaUJSStorage: (function() { try { return window.opera.scriptStorage; } catch(e) { } })(), setItem: function (key, value) { if (ext) { chrome.storage.local.set({ [key]: value }, () => {}); } else if (this.supportGMPromise) { GM.setValue(key, value); if(value === "" && typeof GM != 'undefined' && typeof GM.deleteValue != 'undefined'){ GM.deleteValue(key); } } else if (this.supportGM) { GM_setValue(key, value); if(value === "" && typeof GM_deleteValue != 'undefined'){ GM_deleteValue(key); } } else if (this.operaUJSStorage) { this.operaUJSStorage.setItem(key, value); } else if (this.mxAppStorage) { this.mxAppStorage.setConfig(key, value); } else if (window.localStorage) { window.localStorage.setItem(key, value); } }, getItem: async function (key, cb) { var value; if (ext) { let result = await chrome.storage.local.get([key]); value = result && result[key]; } else if (this.supportGMPromise) { value = await GM.getValue(key); } else if (this.supportGM) { value = GM_getValue(key); } else if (this.operaUJSStorage) { value = this.operaUJSStorage.getItem(key); } else if (this.mxAppStorage) { value = this.mxAppStorage.getConfig(key); } else if (window.localStorage) { value = window.localStorage.getItem(key); }; if(cb) cb(value); return value; }, getListItem: async function(list, key) { var listData = this.listItemCache[list]; if (typeof listData === 'undefined') { listData = await this.getItem(list); this.listItemCache[list] = listData || null; } if (!listData) return null; for(var i = 0; i < listData.length; i++) { let data = listData[i]; if (data.k == key) { return data.v; } } return null; }, setListItem: async function(list, key, value) { var listData = this.listItemCache[list]; if (typeof listData === 'undefined') { listData = await this.getItem(list); } if (!listData) listData = []; listData = listData.filter(data => data && data.k != key); if (value) { listData.unshift({k: key, v: value}); if (listData.length > 50) listData.pop(); } this.setItem(list, listData); this.listItemCache[list] = listData; } }; class WebDAV { constructor(webDAVUrl, username, password) { this.webDAVUrl = webDAVUrl; this.username = username; this.password = password; } init() { if (this.inited) return; this.inited = true; this.auth = btoa(`${this.username}:${this.password}`); } request(action, data, path, type, callback, headers) { if (ext) { chrome.runtime.sendMessage({action: "webDAV", detail: {method: action, body: data, path: path, type: type, headers: headers}}, function(r) { callback && callback(r); }); } else { this.init(); let url = this.webDAVUrl + path; let _headers = { referer: url, origin: url, "Content-Type": "text/xml; charset=UTF-8", "Authorization": `Basic ${this.auth}` }; for (let header in headers) { _headers[header] = headers[header]; } _GM_xmlhttpRequest({ method: action, url: url, data: data, headers: _headers, onload: function(d) { let response = d.response; if (d.status >= 400 || !response) response = ""; if (type == 'xml') { var xml = d.responseXML; if(xml) { response = xml.firstChild.nextSibling ? xml.firstChild.nextSibling : xml.firstChild; } } callback && callback(response); }, onerror: function(e) { debug(e); callback && callback(e); }, ontimeout: function(e) { debug(e); callback && callback(e); } }); } } GET(path, callback) { return this.request('GET', null, path, 'text', callback, {}); } PROPFIND(path, callback) { return this.request('PROPFIND', null, path, 'xml', callback, {Depth: "1"}); } MKCOL(path, callback) { return this.request('MKCOL', null, path, 'text', callback, {}); } DELETE(path, callback) { return this.request('DELETE', null, path, 'text', callback, {}); } PUT(path, data, callback) { return this.request('PUT', data, path, 'text', callback, {}); } async read(path) { let self = this; return new Promise((resolve) => { self.GET(path, resolve); }); } async write(path, data) { let self = this; return new Promise((resolve) => { self.PUT(path, data, resolve); }); } async rm(path) { let self = this; return new Promise((resolve) => { self.DELETE(path, resolve); }); } } var webDAV; async function dataChanged(callback, override) { if (shareEngines) return; let _searchData = await storage.getItem("searchData"); if (_searchData) searchData = _searchData; if (!webDAV) return callback && callback(); if (!override) { let _lastModified = await webDAV.read("lastModified"); if (_lastModified) { _lastModified = parseFloat(_lastModified); } if (_lastModified && (!searchData.lastModified || _lastModified > searchData.lastModified)) { searchData.lastModified = _lastModified; lastModified = searchData.lastModified; let sitesConfig = await webDAV.read("sitesConfig.json"); if (sitesConfig) { try { sitesConfig = JSON.parse(sitesConfig); searchData.sitesConfig = sitesConfig; } catch (e) { debug(e); } } let inPageRule = await webDAV.read("inPageRule.json"); if (inPageRule) { try { inPageRule = JSON.parse(inPageRule); searchData.prefConfig.inPageRule = inPageRule; } catch (e) { debug(e); } } } } callback && callback(); await webDAV.write("lastModified", "" + searchData.lastModified); await webDAV.write("sitesConfig.json", JSON.stringify(searchData.sitesConfig)); await webDAV.write("inPageRule.json", JSON.stringify(searchData.prefConfig.inPageRule)); } var escapeHTMLPolicy; if (_unsafeWindow.trustedTypes && _unsafeWindow.trustedTypes.createPolicy) { escapeHTMLPolicy = _unsafeWindow.trustedTypes.createPolicy('searchjumper_default', { createHTML: (string, sink) => string }); } const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor; if (typeof String.prototype.replaceAll != 'function') { String.prototype.replaceAll = function(search, replacement) { var target = this; return target.split(search).join(replacement); }; } if (typeof String.prototype.endsWith != 'function') { String.prototype.endsWith = function(search, this_len) { if (this_len === undefined || this_len > this.length) { this_len = this.length; } return this.substring(this_len - search.length, this_len) === search; }; } if (typeof String.prototype.startsWith != 'function') { String.prototype.startsWith = function(search, pos){ return this.slice(pos || 0, search.length) === search; }; } function getBody(doc) { return doc.body || doc.querySelector('body'); } function clientX(e) { if (e.type.indexOf('touch') === 0) { return e.changedTouches ? e.changedTouches[0].clientX : 0; } else { return e.clientX; } } function clientY(e) { if (e.type.indexOf('touch') === 0) { return e.changedTouches ? e.changedTouches[0].clientY : 0; } else { return e.clientY; } } function pageX(e) { if (e.type.indexOf('touch') === 0) { return e.changedTouches ? e.changedTouches[0].pageX : 0; } else { return e.pageX; } } function pageY(e) { if (e.type.indexOf('touch') === 0) { return e.changedTouches ? e.changedTouches[0].pageY : 0; } else { return e.pageY; } } function getAllElementsByXpath(xpath, contextNode, doc) { doc = doc || document; contextNode = contextNode || doc; var result = []; try { var query = doc.evaluate(xpath, contextNode, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); for (var i = 0; i < query.snapshotLength; i++) { var node = query.snapshotItem(i); if (node.nodeType === 1) result.push(node); } } catch (err) { debug(`Invalid xpath: ${xpath}`); } return result; } function getElementByXpath(xpath, contextNode, doc) { doc = doc || document; contextNode = contextNode || doc; try { let xpathNode = (s, d, n) => { let result = d.evaluate(s, n, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null); return result.singleNodeValue && result.singleNodeValue.nodeType === 1 && result.singleNodeValue; }; let selSplit = xpath.split(" =>> "); if (selSplit.length === 2) { let ele = xpathNode(selSplit[0], doc, contextNode); if (ele && ele.shadowRoot) { return xpathNode(selSplit[1], ele.shadowRoot, ele.shadowRoot); } } else { return xpathNode(xpath, doc, contextNode); } } catch (err) { debug(`Invalid xpath: ${xpath}`); return false; } } function isXPath(xpath) { if (!xpath) return false; return /^\(*(descendant::|\.\/|\/\/|id\()/.test(xpath); } function getAllElements(sel, doc, contextNode) { if (!doc) doc = document; try { if (!isXPath(sel)) { return doc.querySelectorAll(sel); } } catch(e) { debug(e, 'Error selector'); } return getAllElementsByXpath(sel, contextNode, doc); } function getElement(sel, doc) { if (!doc) doc = document; try { if (!isXPath(sel)) { let selSplit = sel.split(" =>> "); if (selSplit.length === 2) { let ele = doc.querySelector(selSplit[0]); return ele && ele.shadowRoot && ele.shadowRoot.querySelector(selSplit[1]); } else return doc.querySelector(sel); } } catch(e) { debug(e); } return getElementByXpath(sel, doc, doc); } function getElementTop(ele, targetIframe) { var actualTop = ele.offsetTop; var current = ele.offsetParent; while (current) { actualTop += current.offsetTop; current = current.offsetParent; } if (targetIframe) { current = targetIframe; while (current) { actualTop += current.offsetTop; current = current.offsetParent; } try { let currentWindow = targetIframe.contentWindow.parent; targetIframe = currentWindow.frameElement; while (targetIframe) { current = targetIframe; while (current) { actualTop += current.offsetTop; current = current.offsetParent; } currentWindow = currentWindow.parent; targetIframe = currentWindow.frameElement; } } catch(e) {} } return actualTop; } function getElementLeft(ele) { var actualLeft = ele.offsetLeft; var current = ele.offsetParent; while (current) { actualLeft += current.offsetLeft; current = current.offsetParent; } if (!document.isSameNode(ele.ownerDocument)) { let iframes = document.getElementsByTagName("iframe"); for (let i = 0; i < iframes.length; i++) { let iframe = iframes[i]; let iframeDoc; try { iframeDoc = iframe.contentDocument || iframe.contentWindow.document; } catch(e) { break; } if (iframeDoc.isSameNode(ele.ownerDocument)) { current = iframe; while (current) { actualLeft += current.offsetLeft; current = current.offsetParent; } break; } } } return actualLeft; } function getActiveElement(root) { const activeEl = root.activeElement; if (!activeEl) { return null; } if (activeEl.shadowRoot) { return getActiveElement(activeEl.shadowRoot); } else { return activeEl; } } function isInput(ele) { if (ele && ((/INPUT|TEXTAREA/i.test(ele.nodeName) && ele.getAttribute("aria-readonly") != "true" ) || ele.contentEditable == 'true' ) ) { return true; } else { while (ele && ele.nodeName) { if (ele.contentEditable == 'true') return true; if (ele.nodeName.toUpperCase() == 'BODY') { break; } ele = ele.parentNode; } } return false; } function inputActive(doc) { let activeEl = getActiveElement(doc); return isInput(activeEl); } async function waitForFontAwesome(callback) { while (document.hidden) { await sleep(500); } var retries = 100; var text = '\uf0c8'; var checkReady = function() { var canvas, context; retries -= 1; canvas = document.createElement('canvas'); canvas.width = 20; canvas.height = 20; context = canvas.getContext('2d', { willReadFrequently: true }); context.fillStyle = 'rgba(0,0,0,1.0)'; context.fillRect( 0, 0, 20, 20 ); context.font = '16pt FontAwesome'; context.textAlign = 'center'; context.fillStyle = 'rgba(255,255,255,1.0)'; context.fillText(text, 10, 18 ); var data = context.getImageData( 2, 10, 1, 1 ).data; if ( data[0] == 0 && data[1] == 0 && data[2] == 0 ) { context.font = '16pt "Font Awesome 6 Free"'; context.fillText(text, 10, 18 ); data = context.getImageData( 2, 10, 1, 1 ).data; if ( data[0] == 0 && data[1] == 0 && data[2] == 0 ) { if ( retries > 0 ) { setTimeout( checkReady, 150 ); } } else if ( typeof callback === 'function' ) { callback(); } } else { if ( typeof callback === 'function' ) { callback(); } } } setTimeout( checkReady, 100 ); } var logoBtn, searchBar, searchTypes = [], currentSite = false, disableState = false, cacheKeywords, cacheFilter, tipsStorage, localKeywords, lastSign, inPagePostParams, cacheIcon, historySites, historyType, sortTypeNames, sortSiteNames, cachePool = [], cacheFontPool = [], currentFormParams, globalInPageWords, navEnable, referrer, disableHighlight, lastHighlight, lastAddType, allPageNewMode = false, lastModified = 0, allPageBgUrl; const logoBtnSvg = `<svg class="search-jumper-logoBtnSvg" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><title>${_GM_info.script.name}</title><path d="M.736 510.464c0-281.942 228.335-510.5 510-510.5 135.26 0 264.981 53.784 360.625 149.522 95.643 95.737 149.375 225.585 149.375 360.978 0 281.94-228.335 510.5-510 510.5-281.665 0-510-228.56-510-510.5zm510-510.5v1021m-510-510.5h1020" fill="#fefefe"/><path d="M237.44 346.624a48.64 48.64 0 1 0 97.28 0 48.64 48.64 0 1 0-97.28 0zM699.904 346.624a48.64 48.64 0 1 0 97.28 0 48.64 48.64 0 1 0-97.28 0zM423.296 759.296c-64 0-115.712-52.224-115.712-115.712 0-26.624 9.216-52.224 25.6-72.704 9.216-11.776 26.112-13.312 37.888-4.096s13.312 26.112 4.096 37.888c-9.216 11.264-13.824 24.576-13.824 38.912 0 34.304 27.648 61.952 61.952 61.952s61.952-27.648 61.952-61.952c0-4.096-.512-8.192-1.024-11.776-2.56-14.848 6.656-28.672 21.504-31.744 14.848-2.56 28.672 6.656 31.744 21.504 1.536 7.168 2.048 14.336 2.048 22.016-.512 63.488-52.224 115.712-116.224 115.712z" fill="#333"/><path d="M602.08 760.296c-64 0-115.712-52.224-115.712-115.712 0-14.848 12.288-27.136 27.136-27.136s27.136 12.288 27.136 27.136c0 34.304 27.648 61.952 61.952 61.952s61.952-27.648 61.952-61.952c0-15.36-5.632-30.208-15.872-41.472-9.728-11.264-9.216-28.16 2.048-37.888 11.264-9.728 28.16-9.216 37.888 2.048 19.456 21.504 29.696 48.64 29.696 77.824 0 62.976-52.224 115.2-116.224 115.2z" fill="#333"/><ellipse ry="58" rx="125" cy="506.284" cx="201.183" fill="#faf"/><ellipse ry="58" rx="125" cy="506.284" cx="823.183" fill="#faf"/></svg>`; const logoBase64 = "data:image/svg+xml;base64,PHN2ZyBjbGFzcz0ic2VhcmNoLWp1bXBlci1sb2dvQnRuU3ZnIiB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0uNzM2IDUxMC40NjRjMC0yODEuOTQyIDIyOC4zMzUtNTEwLjUgNTEwLTUxMC41IDEzNS4yNiAwIDI2NC45ODEgNTMuNzg0IDM2MC42MjUgMTQ5LjUyMiA5NS42NDMgOTUuNzM3IDE0OS4zNzUgMjI1LjU4NSAxNDkuMzc1IDM2MC45NzggMCAyODEuOTQtMjI4LjMzNSA1MTAuNS01MTAgNTEwLjUtMjgxLjY2NSAwLTUxMC0yMjguNTYtNTEwLTUxMC41em01MTAtNTEwLjV2MTAyMW0tNTEwLTUxMC41aDEwMjAiIGZpbGw9IiNmZWZlZmUiLz48cGF0aCBkPSJNMjM3LjQ0IDM0Ni42MjRhNDguNjQgNDguNjQgMCAxIDAgOTcuMjggMCA0OC42NCA0OC42NCAwIDEgMC05Ny4yOCAwek02OTkuOTA0IDM0Ni42MjRhNDguNjQgNDguNjQgMCAxIDAgOTcuMjggMCA0OC42NCA0OC42NCAwIDEgMC05Ny4yOCAwek00MjMuMjk2IDc1OS4yOTZjLTY0IDAtMTE1LjcxMi01Mi4yMjQtMTE1LjcxMi0xMTUuNzEyIDAtMjYuNjI0IDkuMjE2LTUyLjIyNCAyNS42LTcyLjcwNCA5LjIxNi0xMS43NzYgMjYuMTEyLTEzLjMxMiAzNy44ODgtNC4wOTZzMTMuMzEyIDI2LjExMiA0LjA5NiAzNy44ODhjLTkuMjE2IDExLjI2NC0xMy44MjQgMjQuNTc2LTEzLjgyNCAzOC45MTIgMCAzNC4zMDQgMjcuNjQ4IDYxLjk1MiA2MS45NTIgNjEuOTUyczYxLjk1Mi0yNy42NDggNjEuOTUyLTYxLjk1MmMwLTQuMDk2LS41MTItOC4xOTItMS4wMjQtMTEuNzc2LTIuNTYtMTQuODQ4IDYuNjU2LTI4LjY3MiAyMS41MDQtMzEuNzQ0IDE0Ljg0OC0yLjU2IDI4LjY3MiA2LjY1NiAzMS43NDQgMjEuNTA0IDEuNTM2IDcuMTY4IDIuMDQ4IDE0LjMzNiAyLjA0OCAyMi4wMTYtLjUxMiA2My40ODgtNTIuMjI0IDExNS43MTItMTE2LjIyNCAxMTUuNzEyeiIgZmlsbD0iIzMzMyIvPjxwYXRoIGQ9Ik02MDIuMDggNzYwLjI5NmMtNjQgMC0xMTUuNzEyLTUyLjIyNC0xMTUuNzEyLTExNS43MTIgMC0xNC44NDggMTIuMjg4LTI3LjEzNiAyNy4xMzYtMjcuMTM2czI3LjEzNiAxMi4yODggMjcuMTM2IDI3LjEzNmMwIDM0LjMwNCAyNy42NDggNjEuOTUyIDYxLjk1MiA2MS45NTJzNjEuOTUyLTI3LjY0OCA2MS45NTItNjEuOTUyYzAtMTUuMzYtNS42MzItMzAuMjA4LTE1Ljg3Mi00MS40NzItOS43MjgtMTEuMjY0LTkuMjE2LTI4LjE2IDIuMDQ4LTM3Ljg4OCAxMS4yNjQtOS43MjggMjguMTYtOS4yMTYgMzcuODg4IDIuMDQ4IDE5LjQ1NiAyMS41MDQgMjkuNjk2IDQ4LjY0IDI5LjY5NiA3Ny44MjQgMCA2Mi45NzYtNTIuMjI0IDExNS4yLTExNi4yMjQgMTE1LjJ6IiBmaWxsPSIjMzMzIi8+PGVsbGlwc2Ugcnk9IjU4IiByeD0iMTI1IiBjeT0iNTA2LjI4NCIgY3g9IjIwMS4xODMiIGZpbGw9IiNmYWYiLz48ZWxsaXBzZSByeT0iNTgiIHJ4PSIxMjUiIGN5PSI1MDYuMjg0IiBjeD0iODIzLjE4MyIgZmlsbD0iI2ZhZiIvPjwvc3ZnPg=="; const noImgBase64 = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAyNCIgaGVpZ2h0PSIxMDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNNDI5LjAxMzMzMyA2NDBBMzIgMzIgMCAwIDEgMzg0IDU5NC45ODY2NjdsMzcuNzYtMzcuNzYtMjIuODI2NjY3LTIyLjYxMzMzNC0xMzUuNjggMTM1LjY4IDkwLjQ1MzMzNCA5MC40NTMzMzQgMTM1LjY4LTEzNS42OC0yMi42MTMzMzQtMjIuNjEzMzM0ek01MzQuNjEzMzMzIDM5OC45MzMzMzNsMjIuNjEzMzM0IDIyLjYxMzMzNEw1OTQuOTg2NjY3IDM4NEEzMiAzMiAwIDAgMSA2NDAgNDI5LjAxMzMzM2wtMzcuNzYgMzcuNzYgMjIuNjEzMzMzIDIyLjYxMzMzNCAxMzUuNjgtMTM1LjY4LTkwLjQ1MzMzMy05MC40NTMzMzR6IiBmaWxsPSIjNUU1QzVDIj48L3BhdGg+PHBhdGggZD0iTTUxMiAyMS4zMzMzMzNhNDkwLjY2NjY2NyA0OTAuNjY2NjY3IDAgMSAwIDQ5MC42NjY2NjcgNDkwLjY2NjY2N0E0OTAuNjY2NjY3IDQ5MC42NjY2NjcgMCAwIDAgNTEyIDIxLjMzMzMzM3ogbTMxNi44IDM1NC45ODY2NjdsLTE4MS4xMiAxODEuMTJhMzIgMzIgMCAwIDEtNDUuMjI2NjY3IDBMNTU3LjIyNjY2NyA1MTIgNTEyIDU1Ny4yMjY2NjdsNDUuMjI2NjY3IDQ1LjIyNjY2NmEzMiAzMiAwIDAgMSAwIDQ1LjIyNjY2N2wtMTgxLjEyIDE4MS4xMmEzMiAzMiAwIDAgMS00NS4yMjY2NjcgMGwtMTM1LjY4LTEzNS42OGEzMiAzMiAwIDAgMSAwLTQ1LjIyNjY2N2wxODEuMTItMTgxLjEyYTMyIDMyIDAgMCAxIDQ1LjIyNjY2NyAwTDQ2Ni43NzMzMzMgNTEyIDUxMiA0NjYuNzczMzMzbC00NS4yMjY2NjctNDUuMjI2NjY2YTMyIDMyIDAgMCAxIDAtNDUuMjI2NjY3bDE4MS4xMi0xODEuMTJhMzIgMzIgMCAwIDEgNDUuMjI2NjY3IDBsMTM1LjY4IDEzNS42OGEzMiAzMiAwIDAgMSAwIDQ1LjIyNjY2N3oiIGZpbGw9IiM1RTVDNUMiPjwvcGF0aD4KPC9zdmc+"; const closePath = '<path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64z m165.4 618.2l-66-0.3L512 563.4l-99.3 118.4-66.1 0.3c-4.4 0-8-3.5-8-8 0-1.9 0.7-3.7 1.9-5.2l130.1-155L340.5 359c-1.2-1.5-1.9-3.3-1.9-5.2 0-4.4 3.6-8 8-8l66.1 0.3L512 464.6l99.3-118.4 66-0.3c4.4 0 8 3.5 8 8 0 1.9-0.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"></path>'; const wordParam = "%s[lurest]?\\b"; const wordParamReg = new RegExp(wordParam); var targetElement, hoverElement, cssText, mainStyleEle; var inMinMode = false; function sloarToLunar(sy, sm, sd) { if (!sy && !sm && !sd) { let now = new Date(); let year = now.getFullYear(), month = now.getMonth(), date = now.getDate(); sy = now.getFullYear(); sm = now.getMonth() + 1; sd = now.getDate(); } let firstYear = 2000; let firsrMonth = 2; let firstDay = 5; let lunarYearArr = [ 0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, //2000-2009 0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, //2010-2019 0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, //2020-2029 0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, //2030-2039 0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, //2040-2049 0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, //2050-2059 0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, //2060-2069 0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, //2070-2079 0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, //2080-2089 0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, //2090-2099 0x0d520 //2100 ], lunarMonth = '正二三四五六七八九十冬臘', lunarDay = '一二三四五六七八九十初廿', tianGan = '甲乙丙丁戊己庚辛壬癸', diZhi = '子丑寅卯辰巳午未申酉戌亥', shengxiao = '鼠牛虎兔龍蛇馬羊猴雞狗豬'; function sloarToLunar(sy, sm, sd) { sm -= 1; let daySpan = (Date.UTC(sy, sm, sd) - Date.UTC(firstYear, firsrMonth - 1, firstDay)) / (24 * 60 * 60 * 1000) + 1; let ly, lm, ld; let lunarData; for (let j = 0; j < lunarYearArr.length; j++) { daySpan -= lunarYearDays(lunarYearArr[j]); if (daySpan <= 0) { ly = firstYear + j; lunarData = lunarYearArr[j]; daySpan += lunarYearDays(lunarData); break } } if (!lunarData) return null; for (let k = 0; k < lunarYearMonths(lunarData).length; k++) { daySpan -= lunarYearMonths(lunarData)[k]; if (daySpan <= 0) { if (hasLeapMonth(lunarData) && hasLeapMonth(lunarData) <= k) { if (hasLeapMonth(lunarData) < k) { lm = k; } else if (hasLeapMonth(lunarData) === k) { lm = '闰' + k; } else { lm = k + 1; } } else { lm = k + 1; } daySpan += lunarYearMonths(lunarData)[k]; break } } ld = daySpan; if (hasLeapMonth(lunarData) && (typeof (lm) === 'string' && lm.indexOf('闰') > -1)) { lm = `闰${lunarMonth[/\d/.exec(lm) - 1]}` } else { lm = lunarMonth[lm - 1]; } ly = getTianGan(ly) + getDiZhi(ly); if (ld < 11) { ld = `${lunarDay[10]}${lunarDay[ld-1]}` } else if (ld > 10 && ld < 20) { ld = `${lunarDay[9]}${lunarDay[ld-11]}` } else if (ld === 20) { ld = `${lunarDay[1]}${lunarDay[9]}` } else if (ld > 20 && ld < 30) { ld = `${lunarDay[11]}${lunarDay[ld-21]}` } else if (ld === 30) { ld = `${lunarDay[2]}${lunarDay[9]}` } return { lunarYear: ly, lunarMonth: lm, lunarDay: ld, } } function hasLeapMonth(ly) { if (ly & 0xf) { return ly & 0xf } else { return false } } function leapMonthDays(ly) { if (hasLeapMonth(ly)) { return (ly & 0xf0000) ? 30 : 29 } else { return 0 } } function lunarYearDays(ly) { let totalDays = 0; for (let i = 0x8000; i > 0x8; i >>= 1) { let monthDays = (ly & i) ? 30 : 29; totalDays += monthDays; } if (hasLeapMonth(ly)) { totalDays += leapMonthDays(ly); } return totalDays } function lunarYearMonths(ly) { let monthArr = []; for (let i = 0x8000; i > 0x8; i >>= 1) { monthArr.push((ly & i) ? 30 : 29); } if (hasLeapMonth(ly)) { monthArr.splice(hasLeapMonth(ly), 0, leapMonthDays(ly)); } return monthArr } function getTianGan(ly) { let tianGanKey = (ly - 3) % 10; if (tianGanKey === 0) tianGanKey = 10; return tianGan[tianGanKey - 1] } function getDiZhi(ly) { let diZhiKey = (ly - 3) % 12; if (diZhiKey === 0) diZhiKey = 12; diZhiKey--; return diZhi[diZhiKey] + ` (${shengxiao[diZhiKey]}) ` } return sloarToLunar(sy, sm, sd) } class SearchBar { constructor() { let self = this; this.scale = searchData.prefConfig.customSize / 100; this.tilesZoom = searchData.prefConfig.tilesZoom / 100; this.tipsZoom = searchData.prefConfig.tipsZoom / 100; cssText = ` #search-jumper { font-size: 16px; } #search-jumper-root { font-size: initial; } #search-jumper.search-jumper-showall { overflow-y: hidden; pointer-events: all; overscroll-behavior: contain; -ms-scroll-chaining: contain; flex-direction: unset; max-width: unset; max-height: unset; text-align: center; top: 0; bottom: unset; height: 100%; } #search-jumper.search-jumper-showall>.search-jumper-searchBar { display: none; } #search-jumper>.search-jumper-searchBar.grabbing>.search-jumper-type { display: none!important; } #search-jumper.search-jumper-showall #filterSites { background-color: #f5f5f5e0; border: none; height: 40px; margin-bottom: 0; padding: 5px; margin: 0 10px; box-shadow: #ddd 0px 0px 3px; outline: none; box-sizing: border-box; cursor: default; user-select: none; -webkit-user-select: none; -moz-user-select: none; -khtml-user-select: none; -ms-user-select: none; position: fixed; width: 80%; left: calc(10% - 10px); top: 1%; border-radius: 20px; pointer-events: all; } #search-jumper.search-jumper-showall #filterSites>input, #search-jumper.search-jumper-showall #filterSites>textarea { background-color: white; color: black; border: none; outline: none; box-sizing: border-box; font-size: 20px; cursor: text; } #search-jumper.search-jumper-showall #filterSites>span { display: none; } #search-jumper.search-jumper-showall #search-jumper-alllist .sitelist { visibility: visible!important; opacity: 1!important; pointer-events: all; text-align: left; position: static; display: block!important; height: fit-content; max-height: calc(100vh - 130px); overscroll-behavior: contain; -ms-scroll-chaining: contain; } #search-jumper.search-jumper-showall #search-jumper-alllist .sitelist>.sitelistCon { opacity: 1; } #search-jumper.search-jumper-showall #search-jumper-alllist .sitelist>.sitelistCon>p { pointer-events: all; cursor: pointer; margin: 0 auto; } #search-jumper.search-jumper-showall.searching #search-jumper-alllist .sitelist>.sitelistCon a { display: flex!important; } #search-jumper.search-jumper-showall #search-jumper-alllist .sitelist:hover { z-index: 1; } #search-jumper.search-jumper-showall.search-jumper-searchBarCon { -ms-overflow-style: unset; scrollbar-width: unset; overflow: hidden; } #search-jumper-alllist { display: none; top: 101px; position: absolute; width: 100%; overflow-x: auto; overflow-y: hidden; height: calc(100% - 101px); overscroll-behavior: contain; -ms-scroll-chaining: contain; } #search-jumper-alllist>.search-jumper-btn { position: fixed; top: 1%; right: 10%; filter: drop-shadow(1px 1px 3px #00000060); cursor: pointer; pointer-events: all; z-index: 1; width: 32px; height: 32px; } #search-jumper-alllist>.search-jumper-btn>svg { cursor: pointer; width: 32px; height: 32px; } .search-jumper-showallBg { display: none; position: fixed; left: 0; top: 0; width: 100%; height: 100%; z-index: -1; transform: translateZ(0); ${searchData.prefConfig.noAni ? "background-color: rgba(0, 0, 0, 0.1);" : ( "background-color: rgba(0, 0, 0, 0.1);" + //"backdrop-filter: blur(5px);" + //"-webkit-backdrop-filter: blur(5px);" + "transition:background-color .6s ease;")} } #search-jumper.search-jumper-showall>#search-jumper-alllist:hover~.search-jumper-showallBg { background-color: rgba(0, 0, 0, 0.8); } #search-jumper.search-jumper-showall>.search-jumper-showallBg { display: block; } #search-jumper>.groupTab { position: fixed; background: #ffffffee !important; left: 0; top: 0; overflow: hidden; height: 100%; overflow: auto; scrollbar-width: none; padding: 20px 0; box-sizing: border-box; display: none; z-index: 1; } #search-jumper.search-jumper-showall>#search-jumper-alllist.new-mode+.groupTab { display: block; } #search-jumper.search-jumper-showall>.groupTab::-webkit-scrollbar { width: 0 !important; height: 0 !important; } #search-jumper.search-jumper-showall>.groupTab>span { display: block; width: ${42 * this.scale}px; transition: all 0.25s ease; cursor: pointer; } #search-jumper.search-jumper-showall>.groupTab>span>span.search-jumper-word { opacity: 0.8; } #search-jumper.search-jumper-showall>.groupTab:hover>span { width: ${42 * this.scale + 150}px; } #search-jumper.search-jumper-showall>.groupTab>span:hover{ background: #f5f7fa !important; } #search-jumper.search-jumper-showall>.groupTab:hover>span::after { content: attr(data-type); color: #6b6e74; position: absolute; margin-top: -${21 * this.scale + 10}px; left: ${42 * this.scale + 5}px; white-space: nowrap; font-weight: bold; } .search-jumper-historylistcon { display: flex; position: fixed; width: 100%; max-width: 100%; overflow: auto; justify-content: center; left: 0; top: 60px; background: #ffffffee; border-bottom: 1px solid #ddd; pointer-events: all; min-height: 40px; -ms-overflow-style: unset; scrollbar-width: unset; } .search-jumper-historylistcon::-webkit-scrollbar { width: 0 !important; height: 0 !important; } .search-jumper-historylist { display: flex; max-width: 100%; } #search-jumper.search-jumper-showall #search-jumper-alllist { display: block; } #search-jumper-alllist>.sitelistBox { display: flex; min-width: 100%; justify-content: center; width: fit-content; min-height: 100%; position: initial; transition: all 0.3s ease; } #search-jumper-alllist>.timeInAll, #search-jumper-alllist>.dayInAll { position: fixed; bottom: 0; line-height: 1.5; color: white; opacity: 0.45; font-weight: bold; font-family: Arial,sans-serif,微软雅黑; overflow-wrap: normal; white-space: nowrap; margin: 20px; pointer-events: none; text-shadow: 0 0 5px black; background-image: initial; } #search-jumper-alllist>.dayInAll { left: 50px; font-size: ${lang.indexOf("zh") == 0 ? '1.5' : '2'}vw; } #search-jumper-alllist>.timeInAll { right: 50px; font-size: 2vw; } #search-jumper-alllist>.modeSwitch { position: fixed; top: 5px; right: 5px; width: 45px; height: 45px; border-radius: 50%; box-shadow: 0px 0px 5px 0px #7a7a7a; cursor: pointer; transition: transform 0.25s ease; } #search-jumper-alllist>.modeSwitch>* { pointer-events: none; } #search-jumper-alllist>.modeSwitch:hover { transform: scale(1.1); } #search-jumper-alllist.new-mode { overflow-x: hidden; overflow-y: auto; scrollbar-width: none; } #search-jumper-alllist.new-mode>.sitelistBox { flex-wrap: wrap; flex-direction: column; align-items: center; justify-content: flex-start; } #search-jumper.search-jumper-showall #search-jumper-alllist.new-mode .sitelist { width: 78%; max-height: unset; } #search-jumper.search-jumper-showall #search-jumper-alllist.new-mode .sitelist>.sitelistCon { display: flex; flex-wrap: wrap; padding: 0; } #search-jumper.search-jumper-showall #search-jumper-alllist.new-mode .sitelist>.sitelistCon>p { text-align: left; font-size: large; padding: 10px 30px; display: table-caption; width: 100%; } #search-jumper #search-jumper-alllist.new-mode .sitelist a { width: 240px; height: 100px; display: block!important; padding: 10px 8%; box-sizing: border-box; } #search-jumper.search-jumper-showall.searching #search-jumper-alllist.new-mode .sitelist>.sitelistCon a { display: block!important; } #search-jumper #search-jumper-alllist.new-mode .sitelist>.sitelistCon>div { padding: 0 10px; border-radius: 5px; transition: transform 0.25s ease, box-shadow 0.25s ease; box-shadow: 0 0 #0000, 0 0 #0000, 0 1px 3px #9e9e9e1a, 0 1px 2px -1px #9e9e9e1a; } #search-jumper #search-jumper-alllist.new-mode .sitelist>.sitelistCon>div:hover { transform: translateY(-6px); -webkit-transform: translateY(-6px); -moz-transform: translateY(-6px); box-shadow: 0 0 #0000, 0 0 #0000, 0 1px 3px #0000001a, 0 1px 2px -1px #0000001a; } #search-jumper #search-jumper-alllist.new-mode .sitelist>.sitelistCon>div:before { content: attr(title); margin-left: 41px; color: #abb0bd; font-size: 12px; height: 3em; line-height: 1.5em; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; margin-left: 62px; margin-top: 35px; width: 185px; position: absolute; pointer-events: none; } #search-jumper #search-jumper-alllist.new-mode .sitelist a>img { width: 48px; height: 48px; float: left; margin-left: -20px; } #search-jumper #search-jumper-alllist.new-mode .sitelist a>p { -webkit-line-clamp: 2; -webkit-box-orient: vertical; display: block; font-size: 16px; height: 21px; line-height: 21px; margin-bottom: 8px; margin-top: 0px; margin-left: 40px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } #search-jumper .sitelist a+p { display: none; } #search-jumper #search-jumper-alllist.new-mode .sitelist a+p { position: absolute; margin-top: -28px; color: white; width: 250px; max-width: calc(100% - 20px); display: flex; justify-content: space-evenly; overflow: hidden; opacity: 0; transition: .3s; border-top: 1px solid rgba(136,136,136,.2); padding-top: 3px; } #search-jumper #search-jumper-alllist.new-mode .sitelist a+p>span { flex-shrink: 0; font-size: 14px; padding: 2px 6px; background: rgb(160 160 160 / 10%); color: #888; border-radius: 10px; transition: .3s; cursor: pointer; } #search-jumper #search-jumper-alllist.new-mode .sitelist a+p>span:hover { color: white; background: rgb(160 160 160 / 30%); } #search-jumper #search-jumper-alllist.new-mode .sitelistCon>div:hover>p { opacity: 1; } #search-jumper #search-jumper-alllist.showbg>.inputGroup, #search-jumper #search-jumper-alllist.showbg>.search-jumper-btn, #search-jumper #search-jumper-alllist.showbg>.search-jumper-historylistcon, #search-jumper #search-jumper-alllist.showbg+.groupTab, #search-jumper #search-jumper-alllist.showbg>.sitelistBox { transition: .3s; opacity: 0; } #search-jumper.search-jumper-showall>#search-jumper-alllist.showbg:hover~.search-jumper-showallBg { background: unset; } .search-jumper-searchBarCon { all: unset; position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 2147483646; pointer-events: none; text-align: center; overflow: scroll; display: block; -ms-overflow-style: none; scrollbar-width: none; box-sizing: border-box; z-index: 2147483647; user-select: none; } .search-jumper-searchBar { z-index: 2147483647; overflow-wrap: break-word; background: #505050cc; border-radius: ${this.scale * 21}px!important; border: 1px solid #b3b3b3; display: inline-flex; pointer-events: all; margin-top: -${this.scale * 25}px; vertical-align: top; ${searchData.prefConfig.noAni ? "" : "opacity: 0.8;"} ${searchData.prefConfig.noAni ? "" : "transition:margin-top 1s ease, margin-left 1s, right 1s, opacity 1s, transform 1s;"} user-select: none; text-align: center; position: relative; box-sizing: border-box; } .hideAll>.search-jumper-searchBar { margin-top: -${this.scale * 40}px; } .search-jumper-searchBarCon:not(.search-jumper-showall)::-webkit-scrollbar { width: 0 !important; height: 0 !important; } .search-jumper-searchBarCon.search-jumper-scroll { overscroll-behavior: contain; -ms-scroll-chaining: contain; } .search-jumper-searchBarCon.search-jumper-scroll>.search-jumper-searchBar { pointer-events: all; } .search-jumper-scroll.search-jumper-bottom { overflow-y: hidden; } .search-jumper-scroll.search-jumper-right>.search-jumper-searchBar { position: absolute !important; top: 0; } .search-jumper-scroll.search-jumper-bottom>.search-jumper-searchBar { margin-top: 0px; } .search-jumper-scroll.search-jumper-bottom>.search-jumper-searchBar:hover, .search-jumper-scroll.search-jumper-bottom>.search-jumper-searchBar.initShow, .resizePage.search-jumper-scroll.search-jumper-bottom>.search-jumper-searchBar, .search-jumper-scroll.search-jumper-bottom.funcKeyCall>.search-jumper-searchBar, #search-jumper.in-input.search-jumper-scroll.search-jumper-bottom>.search-jumper-searchBar { margin-top: 0px; } .search-jumper-searchBar:hover { margin-top: 0; opacity: 1; ${searchData.prefConfig.noAni ? "" : "transition:margin-top 0.1s ease, margin-left 0.1s, right 0.1s, opacity 0.1s, transform 0.1s;"} } .search-jumper-searchBar.initShow, .resizePage>.search-jumper-searchBar { margin-top: 0; ${searchData.prefConfig.noAni ? "" : "transition:margin-top 0.25s ease, margin-left 0.25s, right 0.25s, opacity 0.25s, transform 0.25s;"} } .funcKeyCall>.search-jumper-searchBar.initShow { ${searchData.prefConfig.noAni ? "" : "transition:opacity 0.15s ease-out;"} } #search-jumper.funcKeyCall { overflow: visible; position: absolute; max-width: 100%; width: 100%; top: 0; } .funcKeyCall>.search-jumper-searchBar { position: absolute!important; background: none; border: none; max-width: unset!important; margin: unset; ${searchData.prefConfig.minPopup && !searchData.prefConfig.noAni ? 'transition: transform 0.25s ease;' : ''} ${searchData.prefConfig.minPopup ? 'transform: scale(0.7);' : ''} } .funcKeyCall>.search-jumper-searchBar:hover { ${searchData.prefConfig.minPopup ? 'transform: scale(1);' : ''} } .in-input>.search-jumper-searchBar, .funcKeyCall>.search-jumper-searchBar { opacity: 1; display: inline-flex!important; } .in-input.in-find { pointer-events: none; } .in-input.in-find>.searchJumperNavBar, .in-input.in-find>.search-jumper-input { pointer-events: all; } .in-input.in-find>.search-jumper-searchBar, .in-input>.rectSelecting.search-jumper-searchBar { opacity: 0!important; pointer-events: none; transition: none; } .in-input.in-find>.search-jumper-searchBar:hover { opacity: 1!important; } .in-input.in-find>.search-jumper-input { opacity: 0.6; transition:opacity 0.25s ease; } .in-input.in-find>.search-jumper-input:hover, .in-input.in-find>.search-jumper-input.active { opacity: 1; } .funcKeyCall>.search-jumper-searchBar { flex-direction: column; } #search-jumper.funcKeyCall>.search-jumper-searchBar>.search-jumper-type { height: ${searchData.prefConfig.minPopup ? (24 * this.tilesZoom + 'px') : 'auto'}!important; max-width: ${searchData.prefConfig.minPopup ? (24 * this.tilesZoom) : (40 * (searchData.prefConfig.numPerLine || 7) * this.tilesZoom)}px!important; width: auto!important; width: max-content!important; max-height: ${108 * this.tilesZoom + 10}px; flex-wrap: wrap!important; flex-direction: row; padding: 5px; box-shadow: #000000 0px 0px 10px; overflow: auto; scrollbar-width: none; transition: none; background: #d0d0d0d0; box-sizing: content-box; } ${searchData.prefConfig.hideTileType ? ` #search-jumper.funcKeyCall>.search-jumper-searchBar>.search-jumper-type:before { content: attr(data-type); position: absolute; background: #ffffffd0; color: black; margin-top: -${22 * this.tilesZoom}px; line-height: 1.2; font-size: ${13 * this.tilesZoom}px; font-weight: bold; border-radius: ${20 * this.tilesZoom}px; padding: 3px 6px; box-shadow: #000000 0px 0px 10px; opacity: 0; pointer-events: none; transition: all 0.5s ease; left: 50%; transform: translate(-50%, 0); z-index: 1; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } #search-jumper.funcKeyCall>.search-jumper-searchBar>.search-jumper-type>span.search-jumper-btn:first-child { display: none; } #search-jumper.funcKeyCall .search-jumper-type.search-jumper-open.not-expand>a:nth-of-type(${(searchData.prefConfig.expandTypeLength || 12)+1}) { display: grid!important; } #search-jumper.funcKeyCall>.search-jumper-searchBar>.search-jumper-type:hover:before { opacity: 1; } ` : ''} #search-jumper>.search-jumper-searchBar>.search-jumper-type.search-jumper-open { overflow: visible; } #search-jumper>.search-jumper-searchBar>.search-jumper-type.search-jumper-open.search-jumper-move:hover { width: fit-content!important; } #search-jumper.funcKeyCall>.search-jumper-searchBar>.search-jumper-type.search-jumper-open:not(.not-expand) { overflow: auto; } #search-jumper.search-jumper-left>.search-jumper-searchBar>.search-jumper-type.search-jumper-open.search-jumper-move:hover, #search-jumper.search-jumper-right>.search-jumper-searchBar>.search-jumper-type.search-jumper-open.search-jumper-move:hover { width: 100%!important; height: fit-content!important; } #search-jumper.search-jumper-bottom>.search-jumper-searchBar>.search-jumper-type.search-jumper-open.search-jumper-move:hover { align-items: flex-end; } #search-jumper.funcKeyCall>.search-jumper-searchBar>.search-jumper-type.search-jumper-open { overscroll-behavior: contain; -ms-scroll-chaining: contain; overflow: auto; } #search-jumper.funcKeyCall>.search-jumper-searchBar>.search-jumper-type>.sitelist { border-radius: 10px; box-shadow: 0px 0px 10px 0px #7a7a7a; } #search-jumper.funcKeyCall>.search-jumper-searchBar>.search-jumper-type>.sitelist>.sitelistCon { margin: 0; padding: 5px; } #search-jumper.funcKeyCall>.search-jumper-searchBar>.search-jumper-type>.sitelist>.sitelistCon>div { display: none; } #search-jumper.funcKeyCall>.search-jumper-searchBar>.search-jumper-type>.sitelist>.sitelistCon>div:nth-of-type(${searchData.prefConfig.expandTypeLength || 12})~div { display: block; } #search-jumper.funcKeyCall>.search-jumper-searchBar>.search-jumper-type>.sitelist>.sitelistCon>p { display: none; } #search-jumper.funcKeyCall>.search-jumper-searchBar>.search-jumper-type>.sitelist>.sitelistCon a>img { width: 20px; height: 20px; } ${searchData.prefConfig.minPopup && !searchData.prefConfig.hideTileType ? ` #search-jumper.funcKeyCall>.search-jumper-searchBar>.search-jumper-type>a.search-jumper-btn, #search-jumper.funcKeyCall>.search-jumper-searchBar>.search-jumper-type>.searchJumperExpand { display: none; } #search-jumper.funcKeyCall>.search-jumper-searchBar>.search-jumper-type:hover>a.search-jumper-btn, #search-jumper.funcKeyCall>.search-jumper-searchBar>.search-jumper-type:hover>.searchJumperExpand { display: grid; } ` : ''} ${searchData.prefConfig.minPopup == 2 ? ` .funcKeyCall:not(.targetInput)>.search-jumper-searchBar { transform: scale(1); } #search-jumper.funcKeyCall:not(.targetInput)>.search-jumper-searchBar>.search-jumper-type { height: auto!important; width: auto!important; width: max-content!important; max-width: ${40 * (searchData.prefConfig.numPerLine || 7) * this.tilesZoom}px!important; } #search-jumper.funcKeyCall>.search-jumper-searchBar>.search-jumper-type>a.search-jumper-btn { display: grid; } #search-jumper.funcKeyCall.targetInput>.search-jumper-searchBar>.search-jumper-type>a.search-jumper-btn { display: none; } #search-jumper.funcKeyCall.targetInput>.search-jumper-searchBar>.search-jumper-type:hover>a.search-jumper-btn { display: grid; } ` : ''} #search-jumper.funcKeyCall>.search-jumper-searchBar>.search-jumper-type:hover { height: auto!important; width: auto!important; width: max-content!important; max-width: ${40 * (searchData.prefConfig.numPerLine || 7) * this.tilesZoom}px!important; } #search-jumper.funcKeyCall>.search-jumper-searchBar>.search-jumper-type::-webkit-scrollbar { width: 0 !important; height: 0 !important; } .search-jumper-left, .search-jumper-left .search-jumper-type, .search-jumper-left>.search-jumper-searchBar, .search-jumper-right, .search-jumper-right .search-jumper-type, .search-jumper-right>.search-jumper-searchBar { flex-direction: column; max-width: ${42 * this.scale}px; max-height: unset; } .search-jumper-left .search-jumper-type, .search-jumper-right .search-jumper-type { max-width: ${40 * this.scale}px; } .search-jumper-left, .search-jumper-left>.search-jumper-searchBar, .search-jumper-right, .search-jumper-right>.search-jumper-searchBar { max-width: 100%; } .search-jumper-searchBar.grabbing { max-width: ${42 * this.scale}px; } .search-jumper-right .search-jumper-type { align-items: flex-end; } .search-jumper-left { height: 100%; text-align: initial; } .search-jumper-left:not(.search-jumper-showall) { width: initial; width: -webkit-fill-available; } .search-jumper-right { left: unset; right: 0; height: 100%; } .searchJumperExpand { opacity: 0.8; } .searchJumperExpand:hover { opacity: 1; } .searchJumperExpand>svg { transform: rotate(-90deg); border-radius: 20px; filter: drop-shadow(0px 0px 2px black); width: unset; height: unset; color: black; fill: black; } .search-jumper-type.search-jumper-open>span.search-jumper-word, #search-jumper.funcKeyCall .search-jumper-type>span.search-jumper-word { filter: drop-shadow(0px 0px 2px black); } .search-jumper-left .searchJumperExpand>svg, .search-jumper-right .searchJumperExpand>svg { transform: unset; } .search-jumper-bottom { top: unset; bottom: 0; height: ${this.scale * 42 * 2}px; max-height: ${this.scale * 43 * 2}px; overflow-y: hidden; } .search-jumper-left>.search-jumper-searchBar { width: fit-content; margin-top: 0; margin-left: -${this.scale * 20}px; } .hideAll.search-jumper-left>.search-jumper-searchBar { margin-left: -${this.scale * 40}px; } .search-jumper-right>.search-jumper-searchBar { margin-top: 0; right: -${this.scale * 20}px; position: fixed; } .hideAll.search-jumper-right>.search-jumper-searchBar { right: -${this.scale * 40}px; } .search-jumper-left>.search-jumper-searchBar:hover, .search-jumper-left>.search-jumper-searchBar.initShow, .resizePage.search-jumper-left>.search-jumper-searchBar, .search-jumper-left.funcKeyCall>.search-jumper-searchBar, #search-jumper.in-input.search-jumper-left>.search-jumper-searchBar { margin-top: unset; margin-left: 0; opacity: 1; } .search-jumper-right>.search-jumper-searchBar:hover, .search-jumper-right>.search-jumper-searchBar.initShow, .resizePage.search-jumper-right>.search-jumper-searchBar, .search-jumper-right.funcKeyCall>.search-jumper-searchBar, #search-jumper.in-input.search-jumper-right>.search-jumper-searchBar { margin-top: unset; right: 0; opacity: 1; } .search-jumper-bottom>.search-jumper-searchBar { position: relative; margin-top: 0px; top: ${this.scale * 42}px; } .hideAll.search-jumper-bottom>.search-jumper-searchBar { opacity: 0; } .search-jumper-bottom>.search-jumper-searchBar:hover, .search-jumper-bottom>.search-jumper-searchBar.initShow, .resizePage.search-jumper-bottom>.search-jumper-searchBar, .search-jumper-bottom.funcKeyCall>.search-jumper-searchBar, #search-jumper.in-input.search-jumper-bottom>.search-jumper-searchBar { margin-top: 0px; opacity: 1; } .search-jumper-btn { position: relative; display: grid; --scale: 1; padding: ${1 * this.scale}px!important; margin: ${3 * this.scale}px!important; cursor: pointer; box-sizing: content-box; ${searchData.prefConfig.noAni ? "" : "transition:margin-left 0.25s ease, width 0.25s, height 0.25s, transform 0.25s, background 0.25s;"} width: calc(${32 * this.scale}px * var(--scale)); height: calc(${32 * this.scale}px * var(--scale)); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-decoration:none; min-width: ${32 * this.scale}px; min-height: ${32 * this.scale}px; text-align: center; background-image: initial; filter: drop-shadow(1px 1px 3px #00000030); } #search-jumper.funcKeyCall .search-jumper-btn { padding: ${1 * this.tilesZoom}px!important; margin: ${3 * this.tilesZoom}px!important; width: ${32 * this.tilesZoom}px; height: ${32 * this.tilesZoom}px; min-width: ${32 * this.tilesZoom}px; min-height: ${32 * this.tilesZoom}px; border-radius: ${10 * this.tilesZoom}px; filter: drop-shadow(1px 1px 3px #00000060); } #search-jumper.funcKeyCall a.search-jumper-btn { background: #f7f7f7a0; } a.search-jumper-btn:not(.search-jumper-word)>span { position: absolute; text-align: center; width: 100%; bottom: 0px; color: black!important; font-family: Arial, sans-serif; text-shadow: 0 1px white, 1px 0 white, -1px 0 white, 0 -1px white; font-size: ${12 * this.scale}px; font-weight: normal; opacity: 0.8; } #search-jumper.funcKeyCall a.search-jumper-btn:not(.search-jumper-word)>span { font-size: ${12 * this.tilesZoom}px; } .search-jumper-type>a.search-jumper-btn.historySite { box-shadow: 0px 0px 8px 0px #00000080; } .search-jumper-btn>img { width: ${32 * this.scale}px; height: ${32 * this.scale}px; border: unset; } #search-jumper.funcKeyCall .search-jumper-btn>img { width: ${32 * this.tilesZoom}px; height: ${32 * this.tilesZoom}px; border-radius: unset; } .search-jumper-btn>b { line-height: ${32 * this.scale}px; font-size: ${14 * this.scale}px; letter-spacing: 0; color: white; opacity: 0.9; text-shadow: 0 0 1px #d9d9d9cc; } #search-jumper.funcKeyCall .search-jumper-btn>b { line-height: ${32 * this.tilesZoom}px; font-size: ${14 * this.tilesZoom}px; } .search-jumper-btn:hover>b { opacity: 1; } .search-jumper-btn>div { position: absolute; width: 100%; height: 100%; line-height: ${32 * this.scale}px; background: black; border-radius: ${20 * this.scale}px; font-size: ${30 * this.scale}px; color: wheat; display: none; } #search-jumper.funcKeyCall .search-jumper-btn>div { line-height: ${32 * this.tilesZoom}px; border-radius: ${20 * this.tilesZoom}px; font-size: ${30 * this.tilesZoom}px; } .search-jumper-isInPage .search-jumper-btn>div, .search-jumper-isTargetImg .search-jumper-btn>div, .search-jumper-isTargetAudio .search-jumper-btn>div, .search-jumper-isTargetVideo .search-jumper-btn>div, .search-jumper-isTargetLink .search-jumper-btn>div, .search-jumper-isTargetPage .search-jumper-btn>div { animation-name: changeOpacity; animation-duration: 2s; animation-iteration-count: 3; animation-delay: 0.1s; display: block; opacity: 0; } @keyframes changeOpacity { 0% {opacity: 0;} 10% {opacity: 0;} 50% {opacity: 0.75;} 80% {opacity: 0;} 100% {opacity: 0;} } @-webkit-keyframes loader-rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } @keyframes loader-rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .search-jumper-tips>.loader { border-width: 5px; border-style: solid; border-color: gainsboro gainsboro dodgerblue gainsboro; border-radius: 50%; display: block; width: 25px; float: left; height: 25px; margin-right: 10px; margin-top: 5px; -webkit-animation: loader-rotate 1.5s linear infinite; animation: loader-rotate 1.5s linear infinite; } .search-jumper-tips>.loader+font { font-size: 25px; line-height: 40px; } .search-jumper-tips>div { font-size: initial; line-height: initial; font-weight: normal; padding: 5px; cursor: initial; } .search-jumper-tips>div [data-read], .search-jumper-tips>div [data-close], .search-jumper-tips>div [data-paste], .search-jumper-tips>div [data-copy] { cursor: pointer; } .search-jumper-tips>div [data-search] { cursor: help; } .search-jumper-tips>div [data-close] { position: absolute; top: 0px; right: 0px; width: 20px; height: 20px; color: white; transition:all 0.2s ease; } .search-jumper-tips>div [data-close]:hover { color: red; } .search-jumper-tips>div [data-read] { color: #f9690e; } .search-jumper-tips>div [data-drag] { cursor: grab; } .search-jumper-tips.draging { cursor: grabbing; transition: none; } .search-jumper-tips.draging * { pointer-events: none; } .search-jumper-logoBtnSvg { width: ${32 * this.scale}px; height: ${32 * this.scale}px; overflow: hidden; vertical-align: top; cursor: grab; } #search-jumper.funcKeyCall .search-jumper-logoBtnSvg { height: ${32 * this.tilesZoom}px; width: ${32 * this.tilesZoom}px; } .search-jumper-type.search-jumper-targetImg, .search-jumper-type.search-jumper-targetAudio, .search-jumper-type.search-jumper-targetVideo, .search-jumper-type.search-jumper-targetLink, .search-jumper-type.search-jumper-targetPage, .search-jumper-isTargetImg>.search-jumper-type, .search-jumper-isTargetAudio>.search-jumper-type, .search-jumper-isTargetVideo>.search-jumper-type, .search-jumper-isTargetLink>.search-jumper-type, .search-jumper-searchBar:hover>.search-jumper-type.search-jumper-targetImg, .search-jumper-searchBar:hover>.search-jumper-type.search-jumper-targetAudio, .search-jumper-searchBar:hover>.search-jumper-type.search-jumper-targetVideo, .search-jumper-searchBar:hover>.search-jumper-type.search-jumper-targetLink, .search-jumper-searchBar:hover>.search-jumper-type.search-jumper-targetPage, .search-jumper-searchBar.search-jumper-isTargetImg:hover>.search-jumper-type, .search-jumper-searchBar.search-jumper-isTargetAudio:hover>.search-jumper-type, .search-jumper-searchBar.search-jumper-isTargetVideo:hover>.search-jumper-type, .search-jumper-searchBar.search-jumper-isTargetLink:hover>.search-jumper-type { display: none; } #search-jumper.in-input .search-jumper-type.search-jumper-open { width: auto!important; height: auto!important; } #search-jumper.in-input .sitelistCon>div:not(.input-hide)>a { display: flex!important; } #search-jumper .input-hide, #search-jumper.search-jumper-showall #search-jumper-alllist .sitelist.input-hide { display: none!important; } #search-jumper.in-input .search-jumper-type:not(.input-hide) { display: inline-flex!important; flex-wrap: nowrap!important; } #search-jumper.in-input .search-jumper-btn:not(.input-hide) { display: grid!important; } #search-jumper>.search-jumper-searchBar>.search-jumper-logo { display: inline-flex; background: unset; padding: 0px; } #search-jumper.funcKeyCall>.search-jumper-searchBar>.search-jumper-logo { display: none; } .search-jumper-searchBar>.search-jumper-type.search-jumper-targetAll, .search-jumper-searchBar:hover>.search-jumper-type.search-jumper-targetAll { display: inline-flex; } .search-jumper-isInPage>.search-jumper-type.search-jumper-needInPage, .search-jumper-isTargetImg>.search-jumper-type.search-jumper-targetImg, .search-jumper-isTargetAudio>.search-jumper-type.search-jumper-targetAudio, .search-jumper-isTargetVideo>.search-jumper-type.search-jumper-targetVideo, .search-jumper-isTargetLink>.search-jumper-type.search-jumper-targetLink, .search-jumper-isTargetPage>.search-jumper-type, .search-jumper-searchBar.search-jumper-isInPage:hover>.search-jumper-type.search-jumper-needInPage, .search-jumper-searchBar.search-jumper-isTargetImg:hover>.search-jumper-type.search-jumper-targetImg, .search-jumper-searchBar.search-jumper-isTargetAudio:hover>.search-jumper-type.search-jumper-targetAudio, .search-jumper-searchBar.search-jumper-isTargetVideo:hover>.search-jumper-type.search-jumper-targetVideo, .search-jumper-searchBar.search-jumper-isTargetLink:hover>.search-jumper-type.search-jumper-targetLink, .search-jumper-searchBar.search-jumper-isTargetPage:hover>.search-jumper-type.search-jumper-targetPage, .search-jumper-searchBar.search-jumper-isTargetPage:hover>.search-jumper-type { display: inline-flex; } .search-jumper-type, .search-jumper-logo { display: inline-flex; box-sizing: border-box; background: #d0d0d0; border-radius: ${20 * this.scale}px!important; overflow: hidden; padding: 0.2px; height: ${40 * this.scale}px; width: ${40 * this.scale}px; max-height: ${this.scale * 40}px; min-height: ${this.scale * 40}px; min-width: ${this.scale * 40}px; ${searchData.prefConfig.noAni ? "" : `transition:width ${searchData.prefConfig.typeOpenTime}ms ease, height ${searchData.prefConfig.typeOpenTime}ms;`} } #search-jumper.funcKeyCall .search-jumper-type, #search-jumper.funcKeyCall .search-jumper-logo { border-radius: ${20 * this.tilesZoom}px!important; height: ${40 * this.tilesZoom}px; width: ${40 * this.tilesZoom}px; max-height: ${this.tilesZoom * 40}px; min-height: ${this.tilesZoom * 40}px; min-width: ${this.tilesZoom * 40}px; } .search-jumper-right>.searchJumperNavBar { right: unset; left: 0; } .search-jumper-right>.searchJumperNavBar>#navMarks+div.navPointer { right: unset; left: 20px; transform: rotate(180deg); } .search-jumper-bottom>.search-jumper-input { bottom: unset; top: 80px; } #search-jumper .search-jumper-type.search-jumper-open.not-expand>a:nth-of-type(${searchData.prefConfig.expandTypeLength || 12})~a { display: none!important; } #search-jumper .sitelist { position: fixed; text-align: left; background: #00000000; max-height: calc(100vh - ${this.scale * 42}px); overflow: scroll; border: 0; pointer-events: none; opacity: 0; ${searchData.prefConfig.noAni ? "" : "transition:opacity 0.25s ease;"} scrollbar-width: none; box-sizing: content-box; overscroll-behavior: contain; -ms-scroll-chaining: contain; z-index: 1; } #search-jumper .search-jumper-type:hover>.sitelist { pointer-events: all; opacity: 1; } #search-jumper .sitelist>.sitelistCon { margin: 10px; border-radius: 10px; box-shadow: 0px 0px 10px 0px #7a7a7a; padding: 0 0 10px 0; background: #ffffffee; opacity: 1; border: 0; } #search-jumper .sitelist>.sitelistCon:hover { opacity: 1; } #search-jumper .sitelist::-webkit-scrollbar { width: 0 !important; height: 0 !important; } #search-jumper .sitelist>.sitelistCon>div { padding: 0 10px; } #search-jumper .sitelist>.sitelistCon>div:hover { background: #f5f7fa; } #search-jumper .sitelist a { display: flex; align-items: center; text-decoration: none; cursor: pointer; } #search-jumper .sitelist a>img { width: 20px; height: 20px; margin-right: 10px; margin-top: unset; max-width: unset; -moz-transition: transform 0.3s ease; -webkit-transition: transform 0.3s ease; transition: transform 0.3s ease; } #search-jumper .sitelist a>p { display: inline-block; font-size: 15px; font-family: Arial, sans-serif; line-height: 25px; margin: 5px auto; color: #6b6e74; flex: 1; text-align: left; white-space: nowrap; transform-origin: left; -moz-transition: transform 0.3s ease; -webkit-transition: transform 0.3s ease; transition: transform 0.3s ease; } #search-jumper .sitelist a.dragTarget>img { -webkit-transform:scale(1.5); -moz-transform:scale(1.5); transform:scale(1.5); } #search-jumper .sitelist a.dragTarget>p { -webkit-transform:scale(1.2); -moz-transform:scale(1.2); transform: scale(1.2); } #search-jumper .sitelist a * { pointer-events: none; } #search-jumper .sitelist>.sitelistCon>p { color: #565656; text-align: center; font-size: 16px; font-family: Arial, sans-serif; font-weight: bold; background: #f6f6f6; border-radius: 10px 10px 0 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; padding: 3px 10px; position: sticky; top: 0; pointer-events: none; margin: -1px 0 0 0; } .search-jumper-searchBar.disable-pointer>.search-jumper-type { pointer-events: none; } .search-jumper-word { background: black; color: #ffffff!important; font-family: Arial, sans-serif; font-weight: 500; font-size: ${13 * this.scale}px; line-height: calc(${32 * this.scale}px * var(--scale)); min-width: ${32 * this.scale}px; min-height: ${32 * this.scale}px; letter-spacing: 0px; text-shadow: unset; text-decoration: none; } span.search-jumper-word { border-radius: ${20 * this.scale}px!important; } a.search-jumper-word>span { border-radius: 50%!important; min-width: ${32 * this.tilesZoom}px; min-height: ${32 * this.tilesZoom}px; background: white; } #search-jumper.funcKeyCall .search-jumper-word { border-radius: ${10 * this.tilesZoom}px!important; font-size: ${14 * this.tilesZoom}px; line-height: ${32 * this.tilesZoom}px; width: ${32 * this.tilesZoom}px; height: ${32 * this.tilesZoom}px; min-width: ${32 * this.tilesZoom}px; min-height: ${32 * this.tilesZoom}px; } #search-jumper.funcKeyCall .search-jumper-word>span { background: unset; } .search-jumper-word:hover { font-weight: bold; text-shadow: 0px 0px 5px #d0d0d0; } a.search-jumper-word { color: #111111!important; background: unset; } .funcKeyCall a.search-jumper-word { background: #f7f7f7a0; } a.search-jumper-word>span { color: #222!important; border-radius: 20px; line-height: unset; text-align: center; text-shadow: 0 0 0.7px #787878dd; background-image: initial; } .search-jumper-type img { width: 100%; height: 100%; margin-top: unset; } #search-jumper.funcKeyCall .search-jumper-type img { width: ${32 * this.tilesZoom}px; height: ${32 * this.tilesZoom}px; } .funcKeyCall>.search-jumper-tips { position: absolute; } .search-jumper-tips { z-index: 2147483647; pointer-events: none; position: fixed; font-size: ${35 * this.tipsZoom}px; background: #f5f5f5f0; border-radius: ${10 * this.tipsZoom}px!important; padding: 6px; box-shadow: 0px 0px 10px 0px #000; font-weight: bold; ${searchData.prefConfig.noAni ? "" : "transition: all 0.2s ease;"} color: black; white-space: normal; max-width: 640px; max-width: min(80vw,640px); width: max-content; line-height: ${35 * this.tipsZoom}px; word-break: break-all; text-align: center; box-sizing: content-box; overflow: hidden; font-family: Roboto,arial,sans-serif; cursor: grab; max-height: 80vh; overscroll-behavior: contain; -ms-scroll-chaining: contain; } .search-jumper-tips:hover { overflow: auto; } .search-jumper-tips * { max-width: 640px; max-width: min(80vw,640px); margin: auto; } .search-jumper-tips .markdown { white-space: pre-wrap; line-height: 1.2; text-align: initial; margin: 10px; display: block; user-select: text; cursor: auto; } .search-jumper-tips iframe { border: unset; display: block; } .search-jumper-searchBar>.search-jumper-type { padding: 0px; ${searchData.prefConfig.disableTypeOpen ? "background: unset;" : ""} } .search-jumper-searchBar>.search-jumper-type:not(.search-jumper-open) { background: unset; border-radius: unset!important; } .minSizeMode.search-jumper-searchBar>.search-jumper-type:not(.search-jumper-open), .minSizeMode.search-jumper-searchBar:hover>.search-jumper-type:not(.search-jumper-open) { display: none; } .minSizeModeClose.minSizeMode.search-jumper-searchBar:hover>.search-jumper-type:not(.search-jumper-targetImg,.search-jumper-targetLink,.search-jumper-targetPage,.search-jumper-targetVideo,.search-jumper-targetAudio) { display: inline-flex; } .funcKeyCall>.search-jumper-searchBar>.search-jumper-type:not(.search-jumper-open) { display: none; border-radius: ${20 * this.tilesZoom}px!important; } span.search-jumper-word>img { width: ${20 * this.scale}px; height: ${20 * this.scale}px; margin: auto; } #search-jumper.funcKeyCall span.search-jumper-word>img { width: ${20 * this.tilesZoom}px; height: ${20 * this.tilesZoom}px; } .search-jumper-btn:hover { -webkit-transform:scale(1.1); -moz-transform:scale(1.1); transform:scale(1.1); color: white; text-decoration:none; filter: drop-shadow(1px 1px 3px #00000050); } .search-jumper-btn:active { -webkit-transform:scale(1.1); -moz-transform:scale(1.1); transform:scale(1.1); transition:unset; filter: drop-shadow(1px 1px 5px #000000a0); } .search-jumper-searchBar .search-jumper-btn.current { overflow: visible; } .search-jumper-searchBar .search-jumper-btn.current::before { content: ''; position: absolute; right: -2px; top: -2px; border: 1px solid #00000099; display: inline-block; width: 10px; height: 10px; border-radius: 50%; background: white; box-shadow: 0px 0px 3px 0px rgb(0 0 0 / 80%); ${searchData.prefConfig.noAni ? "" : "opacity: 0.8;"} } .in-input .search-jumper-input { display: block; box-sizing: content-box; } .lock-input .search-jumper-lock-input { float: left; font-size: 20px; top: 14px; left: 25px; color: darkgrey; position: absolute; border-right: 2px solid #32373a; padding-right: 10px; display: block; } .search-jumper-input { width: 50%; min-width: 500px; bottom: 2%; left: 50%; margin: 0 0 0 -25%; margin-left: min(-25%, -250px); position: fixed; font-family: Arial, sans-serif; text-align: left; box-shadow: 0px 2px 10px rgb(0 0 0 / 80%); border: 1px solid rgb(179 179 179 / 10%); border-radius: 28px; background-color: rgb(51 56 59 / 90%); padding: 5px; display: none; z-index: 2139999999; font-size: 20px; height: 36px; touch-action: none; } .inputGroup { cursor: grab; display: flex; } .inputGroup * { cursor: default; } .search-jumper-input input, .search-jumper-input textarea { background-color: #212022; color: #adadad; border: none; font-size: 16px; height: 35px; margin-bottom: 0; padding: 5px; margin: 0 10px; border-radius: 3px; box-shadow: #333 0px 0px 2px; width: calc(100% - 20px); outline: none; box-sizing: border-box; cursor: text; } #searchJumperInput, #searchJumperInputKeyWords { width: calc(100% - 11px); float: left; transition: 0.25s width ease; } #searchJumperInput { margin: 0 5px 0 10px; } #searchJumperInputKeyWords { margin: 0 10px 0 1px; } #searchJumperInputKeyWords:disabled { opacity: 0.5; max-width: 20%; min-width: 20%; } #filterSites>input:focus, #filterSites>textarea:focus { width: calc(400% - 20px); color: white; } .search-jumper-input * { box-sizing: border-box; } .search-jumper-input input[type="radio"] { display: none; } .search-jumper-input input:checked + label { background: #3a444add; opacity: 0.9; color: white; font-size: 14px; } .search-jumper-input input#filterSitesTab:checked ~ .line { left: 27px; } .search-jumper-input input#filterSitesTab:checked ~ .content-container #filterSites { opacity: 1; pointer-events: all; } .search-jumper-input input#searchInPageTab:checked ~ .line { left: 233px; } .search-jumper-input input#searchInPageTab:checked ~ .content-container #searchInPage { opacity: 1; pointer-events: all; } .search-jumper-input label { display: inline-block; font-size: 12px; height: 32px; line-height: 32px; width: 200px; text-align: center; background: #2a343acc; color: #959595; position: relative; transition: 0.25s background ease, 0.25s opacity ease; cursor: pointer; position: relative; top: -38px; left: 22px; border-radius: 5px 5px 0 0; user-select: none; pointer-events: all; max-width: 40%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; opacity: 0.6; } .search-jumper-input input:checked + label:hover, .search-jumper-input label:hover { background: #3a444a; opacity: 1; } .search-jumper-input label::after { content: ""; height: 1px; width: 100%; position: absolute; display: block; background: #ccc; bottom: 0; opacity: 0; left: 0; transition: 0.25s ease; } .search-jumper-input label:hover::after { opacity: 1; } .search-jumper-input .line { background: #1E88E5; width: 200px; height: 1px; top: -2px; left: 0; transition: 0.25s ease; position: absolute; } .inputGroup>.svgBtns { right: 16px; top: 5px; height: 35px; position: absolute; user-select: none; background: #212022; white-space: nowrap; overflow: hidden; display: flex; align-items: center; } .inputGroup>#addons { position: absolute; bottom: 41px; right: 110px; display: none; flex-direction: column; background: #212022; border-radius: 10px; opacity: 0; transition: 0.5s opacity ease; } .inputGroup>#addons>div { padding: 10px; } .inputGroup>#addons>div>input { float: left; width: 20px; height: 20px; margin: 0 10px 0 0; cursor: pointer; } .inputGroup:hover>#addons { display: flex; } .inputGroup>#addons:hover { opacity: 1; } .inputGroup>.svgBtns:hover+#addons { opacity: 1; } .inputGroup>#addons>div>label { color: white; display: inline; background: none; top: unset; left: unset; font-size: unset; line-height: 20px; max-width: unset; } .inputGroup>.svgBtns:hover { width: auto; } .inputGroup>.svgBtns>svg { margin: 0 2px; } .inputGroup svg.checked { fill: #1E88E5; } @media screen and (max-width: 2048px) { #search-jumper.search-jumper-showall #search-jumper-alllist.new-mode .sitelist { width: 1580px; } } @media screen and (max-width: 1920px) { #search-jumper.search-jumper-showall #search-jumper-alllist.new-mode .sitelist { width: 1320px; } } @media screen and (max-width: 1600px) { #search-jumper.search-jumper-showall #search-jumper-alllist.new-mode .sitelist { width: 1060px; } } @media screen and (max-width: 1300px) { #search-jumper.search-jumper-showall #search-jumper-alllist.new-mode .sitelist { width: 800px; } } @media screen and (max-width: 900px) { #search-jumper.search-jumper-showall #search-jumper-alllist.new-mode .sitelist { width: 540px; } } @media screen and (max-width: 600px) { #search-jumper.search-jumper-showall #search-jumper-alllist.new-mode .sitelist { width: 95vw; } #search-jumper.search-jumper-showall #search-jumper-alllist.new-mode .sitelist>.sitelistCon { width: calc(100% - 20px); } #search-jumper-alllist>.timeInAll, #search-jumper-alllist>.dayInAll { margin: 10px; } #search-jumper #search-jumper-alllist.new-mode .sitelist a { width: calc(50vw - 45px); } #search-jumper #search-jumper-alllist.new-mode .sitelist>.sitelistCon>div:before { width: 100px; margin-left: 68px; } #search-jumper #search-jumper-alllist.new-mode .sitelist a>img { margin-left: 0; } } @media screen and (max-width: 380px) { #search-jumper #search-jumper-alllist.new-mode .sitelist a { width: calc(100vw - 60px); } #search-jumper #search-jumper-alllist.new-mode .sitelist>.sitelistCon>div:before { width: calc(100vw - 150px); margin-left: 85px; } #search-jumper #search-jumper-alllist.new-mode .sitelist a+p { width: calc(100vw - 60px); } } @media screen and (max-width: 800px) { .search-jumper-input .line { display: none; } .search-jumper-input { min-width: 300px; margin-left: min(-25%, -150px); } .inputGroup>.svgBtns { width: 25px; } #search-jumper-alllist>.modeSwitch { width: 36px; height: 36px; right: 2px; top: 10px; } } @media screen and (max-width: 650px) { #search-jumper.search-jumper-showall>#search-jumper-alllist.new-mode+.groupTab { display: none; } } .search-jumper-input .content-container { background: #eee; position: static; font-size: 16px; } .search-jumper-input .content-container .inputGroup { position: absolute; padding: 5px; width: 100%; top: 0; left: 0; opacity: 0; pointer-events: none; transition: 0.25s ease; color: #333; } .search-jumper-input svg, .searchJumperNavBar svg { width: 25px; height: 25px; fill: white; cursor: pointer; opacity: 0.8; transition: 0.25s all ease; font-size: 0px; } .search-jumper-input .inputGroup:hover svg, .searchJumperNavBar.sjNavShow svg { pointer-events: all; } .search-jumper-input svg *, .searchJumperNavBar svg * { cursor: pointer; } .search-jumper-input svg:hover, .searchJumperNavBar svg:hover, .search-jumper-input>.closeBtn:hover, .searchJumperNavBar>div.minNavBtn:hover, .searchJumperNavBar>div.maxNavBtn:hover { -webkit-transform:scale(1.2); -moz-transform:scale(1.2); transform:scale(1.2); opacity: 1; } #search-jumper.selectedEle #filterSites>.svgBtns>svg { display: inline-block!important; } .search-jumper-input>.closeBtn { position: absolute; right: 0px; top: -35px; width: 30px; height: 30px; vertical-align: middle; overflow: hidden; background: rgb(51 56 59 / 90%); color: white; text-align: center; line-height: 30px; border-radius: 20px; pointer-events: all; transition: 0.25s all ease; opacity: 0.6; font-size: 26px; box-shadow: 0px 0px 2px rgb(0 0 0 / 80%); border: 1px solid rgb(179 179 179 / 20%); cursor: pointer; user-select: none; } #searchInPage>.lockWords { max-width: 50%; position: absolute; bottom: 4px; left: 16px; color: white; font-size: 18px; display: flex; flex-wrap: wrap-reverse; max-height: 38px; overflow: hidden; } #searchInPage>.lockWords:hover { overflow-y: auto; height: auto; max-height: 90vh; } #searchInPage>.lockWords>span { position: relative; padding: 5px; cursor: pointer; user-select: none; background: yellow; color: black; border: 1px solid; margin: 2px; display: flex; align-items: center; white-space: nowrap; max-width: 100%; line-height: initial; } #searchInPage>.lockWords>span>em { cursor: alias; } #searchInPage>.lockWords .lockWordTool { position: absolute; right: 0; top: 0; display: none; opacity: 0.3; height: 15px; width: 15px; text-align: center; line-height: 15px; border-radius: 50%; background: black; color: white; } #searchInPage>.lockWords .lockWordTool>span { cursor: pointer; font-size: 15px; } #searchInPage>.lockWords .modifyBtn { top: unset; bottom: 0; } #searchInPage>.lockWords .lockWordTool:hover { opacity: 1; } #searchInPage>.lockWords>span:hover .lockWordTool { display: block; pointer-events: all; } #searchInPage>.lockWords .lockWordTool>svg { width: 15px; height: 15px; fill: black; color: black; border: 1px solid white; border-radius: 10px; background: white; } #searchInPage>.lockWords>span>em { font-size: 12px; margin-right: 5px; color: unset; } .searchJumperNavBar { all: unset; top: 0px; bottom: 0px; right: 0px; position: fixed; width: 20px; z-index: 2147483647; background: #00000026; text-align: center; pointer-events: none; font-size: 0px; opacity: 0; transition: width 0.3s, background 0.3s; } .searchJumperNavBar:hover { width: 25px; background: #00000066; } .searchJumperNavBar.sjNavShow { pointer-events: all; opacity: 1; } .search-jumper-showall > .searchJumperNavBar.sjNavShow { opacity: 0; } .searchJumperNavBar>.closeNavBtn { width: 16px; height: 16px; fill: white; cursor: pointer; display: inline-block; } .searchJumperNavBar>.minNavBtn, .searchJumperNavBar>.maxNavBtn { font-size: 12px; font-weight: bold; font-family: system-ui; line-height: 16px; opacity: 0.1; background: white; color: black; border-radius: 10px; width: 16px; height: 16px; display: inline-block; cursor: pointer; transition: 0.25s opacity ease, 0.25s transform ease; } .searchJumperNavBar:hover>.minNavBtn, .searchJumperNavBar:hover>.maxNavBtn { opacity: 0.8; } #search-jumper>.searchJumperNavBar.minimize { background: transparent; pointer-events: none; } .searchJumperNavBar.minimize>.closeNavBtn, .searchJumperNavBar.minimize>.navPointer, .searchJumperNavBar.minimize>.maxNavBtn, .searchJumperNavBar.minimize>#navMarks { display: none; } .searchJumperNavBar.minimize>.minNavBtn { opacity: 1; box-shadow: 0px 0px 3px 1px #000; margin-left: -50px; margin-top: 5px; pointer-events: all; } .search-jumper-right>.searchJumperNavBar.minimize>.minNavBtn { margin-left: unset; margin-right: -50px; } #navMarks+.navPointer { pointer-events: none; position: absolute; right: 20px; text-shadow: #fff 1px 0 0, #fff 0 1px 0, #fff -1px 0 0, #fff 0 -1px 0; font-size: 30px; font-family: system-ui; line-height: 0px; border: 0; margin-top: 0; opacity: 0.8; color: black; transition: top 0.25s ease; animation-name: changeHor; animation-duration: 1s; animation-iteration-count: infinite; animation-timing-function: ease-in-out; } @keyframes changeHor { 0% {right: 20px;} 10% {right: 18px;} 80% {right: 25px;} 100% {right: 20px;} } #navMarks { height: calc(100% - 50px); width: 100%; position: relative; } #navMarks>span { height: 0.5vh; width: 100%; position: absolute; border: 1px solid #cccccc; min-height: 5px; box-sizing: border-box; left: 0; border-radius: 0px!important; cursor: alias; } .searchJumperPosBar { background: rgba(29, 93, 163, 0.3); position: absolute; min-height: 10px; min-width: 10px; animation-duration: 2s; z-index: 2147483647; margin: 0; opacity: 0; pointer-events: none; transition: 0.25s all ease; } .searchJumperPosBar.searchJumperPosW { width: 100%; left: 0; } .searchJumperPosBar.searchJumperPosH { height: 100%; top: 0; position: fixed; } @keyframes fadeit { 0% {opacity: 1;} 50% {opacity: 0.8;} 100% {opacity: 0;} } #rightSizeChange { top: 0; opacity: 0; height: 45px; width: 15px; position: absolute; cursor: e-resize; right: 0; pointer-events: all; } .searchJumper-hide { display: none!important; } .search-jumper-historylist>a.search-jumper-btn { filter: drop-shadow(0px 0px 3px #00000050); width: 32px; height: 32px; line-height: 32px; min-width: auto; min-height: auto; flex-shrink: 0; } .search-jumper-historylist>a.search-jumper-btn>img { width: 32px; height: 32px; } .search-jumper-historylist>a.search-jumper-btn:not(.search-jumper-word)>span { font-size: 12px; line-height: normal; } #search-jumper .listArrow { width: 0; height: 0; border: 10px solid transparent; pointer-events: none; border-bottom-color: white; position: fixed; opacity: 0; visibility: hidden; z-index: 2147483647; transition: opacity .3s ease, top .15s, bottom .15s, left .15s, right .15s; } #search-jumper.search-jumper-left .listArrow { border-bottom-color: transparent; border-right-color: white; } #search-jumper.search-jumper-right .listArrow { border-bottom-color: transparent; border-left-color: white; } #search-jumper.search-jumper-bottom .listArrow { border-bottom-color: transparent; border-top-color: white; } @media (prefers-color-scheme: dark) { /* 站点列表 */ #search-jumper .sitelist > .sitelistCon > p { background-color: #252B32 !important; } #search-jumper.search-jumper-showall #filterSites { background-color: #2a282cc0; } #search-jumper.search-jumper-showall #filterSites>input, #search-jumper.search-jumper-showall #filterSites>textarea { background-color: #000000; color: white; } #search-jumper .sitelist > .sitelistCon { background-color: #1C2127ee !important; } #search-jumper .sitelist > .sitelistCon > div:hover { background-color: #283C57 !important; } #search-jumper .sitelist > .sitelistCon > p, #search-jumper .sitelist a > p { color: #DADADA !important; } #search-jumper .listArrow { border-bottom-color: #1C2127; } #search-jumper.search-jumper-left .listArrow { border-bottom-color: transparent; border-right-color: #1C2127; } #search-jumper.search-jumper-right .listArrow { border-bottom-color: transparent; border-left-color: #1C2127; } #search-jumper.search-jumper-bottom .listArrow { border-bottom-color: transparent; border-top-color: #1C2127; } /* 历史列表 */ .search-jumper-historylistcon { background-color: #181C20e0 !important; } .search-jumper-historylist>a.search-jumper-btn { filter: drop-shadow(0px 0px 3px #ffffff50); } .search-jumper-showall a.search-jumper-word, .search-jumper-showall a.search-jumper-word > span { background-color: #292A2D !important; border-radius: 20px !important; } .search-jumper-tips { background-color: #3F4042f0; color: #DADADA; } .search-jumper-tips>*:not(font) { color: white; } .search-jumper-showall a.search-jumper-word > span { color: #DADADA !important; } .search-jumper-showall .search-jumper-word:hover { text-shadow: 0px 0px 5px #2374FF !important; } /* 类别 */ .search-jumper-showall .search-jumper-type, .search-jumper-showall .search-jumper-logo { background-color: #181C20 !important; } #search-jumper.search-jumper-showall>.groupTab { background: #1C2127ee !important; } #search-jumper.search-jumper-showall>.groupTab>span:hover{ background: #283C57 !important; } #search-jumper.search-jumper-showall>.groupTab:hover>span::after { color: white; } } `; this.inPageCss = ` mark.searchJumper, a.searchJumper { visibility: inherit; font-style: normal; box-shadow: rgba(0, 0, 0, 0.3) 1px 1px 3px; border-radius: 3px; text-decoration: none; padding: 1px 0; -webkit-text-fill-color: initial; text-shadow: initial; min-width: initial; display: inline; } mark.searchJumper:before, a.searchJumper:before, mark.searchJumper:after, a.searchJumper:after { all: unset; content: none!important; } mark.searchJumper[data-current=true], a.searchJumper[data-current=true] { border-bottom: 0.2em solid; border-bottom-left-radius: 0; border-bottom-right-radius: 0; animation: 0.5s linear 0s 5 normal none running currentMark; } @keyframes currentMark { from {border-color: unset} to {border-color: transparent;} } `; if (searchData.prefConfig.cssText) cssText += searchData.prefConfig.cssText; let logoCon = document.createElement("span"); logoCon.className = "search-jumper-logo"; logoBtn = document.createElement("span"); logoBtn.innerHTML = createHTML(logoBtnSvg); logoBtn.className = "search-jumper-btn"; logoCon.addEventListener('mouseenter', e => { if (this.preList) { this.preList.style.visibility = "hidden"; this.listArrow.style.cssText = ""; } }); logoCon.appendChild(logoBtn); let bar = document.createElement("span"); bar.className = "search-jumper-searchBar"; bar.appendChild(logoCon); let searchBarCon = document.createElement("div"); searchBarCon.id = "search-jumper"; searchBarCon.style.display = "none"; searchBarCon.className = "search-jumper-searchBarCon"; searchBarCon.appendChild(bar); searchBarCon.setAttribute("translate", "no"); let alllist = document.createElement("div"); alllist.id = "search-jumper-alllist"; searchBarCon.appendChild(alllist); this.alllist = alllist; let groupTab = document.createElement("span"); groupTab.className = "groupTab"; searchBarCon.appendChild(groupTab); this.groupTab = groupTab; let showallBg = document.createElement("div"); showallBg.className = "search-jumper-showallBg"; searchBarCon.appendChild(showallBg); let sitelistBox = document.createElement("div"); sitelistBox.className = "sitelistBox"; alllist.appendChild(sitelistBox); this.sitelistBox = sitelistBox; const tagReg = /#[^\s#]+/g; sitelistBox.addEventListener("mouseover", e => { if (!alllist.classList.contains("new-mode")) return; let target = e.target; if (target.parentNode && target.parentNode.dataset.name) { target = target.parentNode; } let title = target.title; if (!target.dataset.name || !title || target.initedTag) return; let tags = document.createElement("p"); let tagMatch = title.match(tagReg); if (tagMatch) { tagMatch.forEach(tag => { let tagEle = document.createElement("span"); tagEle.innerText = tag.slice(1); tagEle.addEventListener("click", e => { self.searchInput.value = tag; self.searchInput.dispatchEvent(new CustomEvent("input")); }); tags.appendChild(tagEle); }); target.appendChild(tags); } target.initedTag = true; }); let timeInAll = document.createElement("span"); timeInAll.className = "timeInAll"; alllist.appendChild(timeInAll); this.timeInAll = timeInAll; this.modeSwitch = document.createElement("div"); this.modeSwitch.className = "modeSwitch"; this.modeSwitch.innerHTML = createHTML(`<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" version="1.1"><rect height="450" width="520" y="287" x="253" fill="#fff"></rect><path d="m511.8,64.2c-247.5,0 -448.2,200.7 -448.2,448.2s200.7,448.2 448.2,448.2s448.2,-200.6 448.2,-448.2s-200.7,-448.2 -448.2,-448.2zm-260.4,353.9c0,-7.8 6.3,-14.2 14.2,-14.2l315.6,0l0,-102.5c0,-12.3 14.7,-18.8 23.7,-10.4l165.1,151.7c9.5,8.7 3.3,24.6 -9.6,24.6l-495,0c-7.8,0 -14.2,-6.3 -14.2,-14.2l0,-35l0.2,0zm523.2,188.5c0,7.8 -6.3,14.2 -14.2,14.2l-315.5,0l0,102.6c0,12.3 -14.7,18.8 -23.7,10.4l-165.2,-151.8c-9.5,-8.7 -3.3,-24.6 9.6,-24.6l495,0c7.8,0 14.2,6.3 14.2,14.2l0,35l-0.2,0z"></path></svg>`); alllist.appendChild(this.modeSwitch); this.modeSwitch.addEventListener("click", e => { e.preventDefault(); e.stopPropagation(); alllist.classList.toggle("new-mode"); alllist.classList.remove("showbg"); storage.setItem("allPageNewMode", alllist.classList.contains("new-mode")); }); this.modeSwitch.addEventListener("mouseenter", e => { if (allPageBgUrl) { e.preventDefault(); e.stopPropagation(); alllist.classList.add("showbg"); } }); this.modeSwitch.addEventListener("mouseleave", e => { if (allPageBgUrl) { e.preventDefault(); e.stopPropagation(); alllist.classList.remove("showbg"); } }); this.modeSwitch.addEventListener("contextmenu", e => { if (allPageBgUrl) { e.preventDefault(); e.stopPropagation(); alllist.classList.remove("showbg"); _GM_openInTab(allPageBgUrl, {active: true, insert: true}); } }); if (allPageNewMode) alllist.classList.add("new-mode"); let dayInAll = document.createElement("span"); dayInAll.className = "dayInAll"; alllist.appendChild(dayInAll); this.dayInAll = dayInAll; alllist.addEventListener(getSupportWheelEventName(), e => { self.tips.style.display = "none"; clearTimeout(self.requestShowTipsTimer); if (e.target != alllist && e.target != showallBg && e.target != sitelistBox) return; if (alllist.classList.contains("new-mode")) return; var deltaX, deltaY; if(e.type !== 'wheel'){ var x = 0, y = 0; if (typeof e.axis == 'number') { if (e.axis == 2) { y = e.detail; } else { x = e.detail; } } else { if (typeof e.wheelDeltaY == 'undefined' || e.wheelDeltaY != 0) { y = -e.wheelDelta / 40; } else { x = -e.wheelDelta / 40; }; }; deltaY = y; deltaX = x; } else { deltaX = e.deltaX; deltaY = e.deltaY; } e.preventDefault(); e.stopPropagation(); alllist.scrollLeft += deltaY; }, { passive: false, capture: false }); let logoConfigBtn = document.createElement("span"); logoConfigBtn.innerHTML = createHTML(logoBtnSvg); logoConfigBtn.className = "search-jumper-btn"; logoConfigBtn.addEventListener('click', e => { _GM_openInTab(configPage, {active: true, insert: true}); }); alllist.appendChild(logoConfigBtn); let historylistCon = document.createElement("div"); historylistCon.className = "search-jumper-historylistcon"; alllist.appendChild(historylistCon); let historylist = document.createElement("div"); historylist.className = "search-jumper-historylist"; historylistCon.appendChild(historylist); this.historylist = historylist; bar.addEventListener('mouseenter', e => { if (bar.classList.contains("grabbing")) return; if (this.hideTimeout) { clearTimeout(this.hideTimeout); } this.checkScroll(true); if (searchData.prefConfig.mouseLeaveToHide) { bar.classList.remove("initShow"); } }, false); bar.addEventListener('mouseleave', e => { if (searchData.prefConfig.mouseLeaveToHide) { if (bar.classList.contains("grabbing")) return; self.waitForHide(); } if (self.preList) { self.preList.style.visibility = "hidden"; self.listArrow.style.cssText = ""; } }, false); this.touched = true; if (searchData.prefConfig.initShow) { bar.classList.add("initShow"); } else { this.touched = false; } if (searchData.prefConfig.minSizeMode) { bar.classList.add("minSizeMode"); bar.classList.add("minSizeModeClose"); } if (isMobile && !searchData.prefConfig.resizePage) { let touchBodyHandler = e => { this.touched = false; bar.classList.remove("initShow"); }; let touchHandler = e => { if (this.touched || this.funcKeyCall) return; this.touched = true; bar.classList.add('disable-pointer'); e.stopPropagation(); setTimeout(() => { bar.classList.remove('disable-pointer'); }, 250); }; getBody(document).addEventListener("touchstart", touchBodyHandler, { passive: true, capture: false }); bar.addEventListener('touchstart', touchHandler, { passive: false, capture: true }); } this.bar = bar; this.con = searchBarCon; let tips = document.createElement("span"); tips.className = "search-jumper-tips"; tips.style.opacity = 0; searchBarCon.appendChild(tips); tips.addEventListener('mouseenter', e => { if (self.hideTimeout) { clearTimeout(self.hideTimeout); } }, false); tips.addEventListener('click', e => { let dataset = e.target.dataset; let text = e.target.innerText; if (!dataset) return; if (typeof dataset.read !== 'undefined') { let msg = new SpeechSynthesisUtterance(""); msg.volume = dataset.volume || 1; msg.rate = dataset.rate || 1; msg.pitch = dataset.pitch || 1; msg.lang = dataset.lang || ""; msg.text = dataset.read || text; window.speechSynthesis.speak(msg); } if (typeof dataset.copy !== 'undefined') { _GM_setClipboard(dataset.copy || text); } if (dataset.search) { extSelectionText = text; self.searchBySiteName(dataset.search); } if (typeof dataset.paste !== 'undefined') { if (targetElement && ((/INPUT|TEXTAREA/i.test(targetElement.nodeName) && targetElement.getAttribute("aria-readonly") != "true" ) || targetElement.contentEditable == 'true' ) ) { triggerPaste(targetElement, dataset.paste || text); } } if (typeof dataset.close !== 'undefined') { self.tips.style.opacity = 0; self.tips.style.display = "none"; self.tips.innerHTML = createHTML(""); } }, false); let startMouse, startPos, mouseMoveHandler = e => { let curX = clientX(e) - startMouse.x; let curY = clientY(e) - startMouse.y; if (Math.abs(curX) + Math.abs(curY) < 5) return; if (tips.style.right === "") { tips.style.setProperty("left", (startPos.left + curX) + "px", "important"); //tips.style.left = (startPos.left + curX) + "px!important"; } else { tips.style.setProperty("right", (startPos.right - curX) + "px", "important"); //tips.style.right = (startPos.right - curX) + "px!important"; } if (tips.style.bottom === "") { tips.style.setProperty("top", (startPos.top + curY) + "px", "important"); //tips.style.top = (startPos.top + curY) + "px!important"; } else { tips.style.setProperty("bottom", (startPos.bottom - curY) + "px", "important"); //tips.style.bottom = (startPos.bottom - curY) + "px!important"; } tips.classList.add("draging"); }; let mouseUpHandler = e => { document.removeEventListener('mouseup', mouseUpHandler, false); document.removeEventListener('mousemove', mouseMoveHandler, false); document.removeEventListener('touchend', mouseUpHandler, false); document.removeEventListener('touchmove', mouseMoveHandler, false); tips.classList.remove("draging"); }; let dragTips = (e, cb) => { if (!e.target) return; if (e.target !== tips && typeof e.target.dataset.drag === 'undefined') return; e.preventDefault(); e.stopPropagation(); startMouse = {x: clientX(e), y: clientY(e)}; let tipsStyle = getComputedStyle(tips); startPos = { left: parseFloat(tipsStyle.left), right: parseFloat(tipsStyle.right), top: parseFloat(tipsStyle.top), bottom: parseFloat(tipsStyle.bottom) }; cb && cb(); }; tips.addEventListener('mousedown', e => { dragTips(e, () => { document.addEventListener('mouseup', mouseUpHandler, false); document.addEventListener('mousemove', mouseMoveHandler, false); }); }, false); tips.addEventListener('touchstart', e => { dragTips(e, () => { document.addEventListener('touchend', mouseUpHandler, false); document.addEventListener('touchmove', mouseMoveHandler, false); }); }, { passive: false, capture: false }); this.tips = tips; //this.appendBar(); let searchJumperNavBar = document.createElement("div"); searchJumperNavBar.className = "searchJumperNavBar"; searchJumperNavBar.style.display = "none"; searchJumperNavBar.innerHTML = createHTML(` <svg class="closeNavBtn" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>Close navigation</title>${closePath}</svg> <div class="minNavBtn" title="Minimize navigation">-</div> <div id="navMarks"></div> <div class="maxNavBtn" title="Restore input"><img src="${logoBase64}" /></div> <div class="navPointer">></div> `); searchBarCon.appendChild(searchJumperNavBar); let searchJumperExpand = document.createElement("span"); searchJumperExpand.title = i18n('expand'); searchJumperExpand.className = "searchJumperExpand search-jumper-btn"; searchJumperExpand.innerHTML = createHTML(` <svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><rect height="450" width="600" y="300" x="200" fill="#fff"></rect><path d="M512 64C264.8 64 64 264.8 64 512s200.8 448 448 448 448-200.8 448-448S759.2 64 512 64z m0 640L240 432l45.6-45.6L512 613.6l226.4-226.4 45.6 45.6L512 704z"></path></svg> `); this.searchJumperExpand = searchJumperExpand; this.navMarks = searchJumperNavBar.querySelector("#navMarks"); this.closeNavBtn = searchJumperNavBar.querySelector(".closeNavBtn"); this.minNavBtn = searchJumperNavBar.querySelector(".minNavBtn"); this.maxNavBtn = searchJumperNavBar.querySelector(".maxNavBtn"); this.searchJumperNavBar = searchJumperNavBar; this.navPointer = searchJumperNavBar.querySelector(".navPointer"); this.navPointer.style.display = "none"; let searchInputDiv = document.createElement("div"); searchInputDiv.className = "search-jumper-input"; searchInputDiv.innerHTML = createHTML(`<span class="closeBtn">×</span> <input type="radio" id="filterSitesTab" name="tab" ${searchData.prefConfig.defaultFindTab? "" : "checked=\"checked\""} /> <label for="filterSitesTab">${i18n("filterSites")}</label> <input type="radio" id="searchInPageTab" name="tab" ${searchData.prefConfig.defaultFindTab? "checked=\"checked\"" : ""} /> <label for="searchInPageTab">${i18n("searchInPage")}</label> <div class="line"></div> <div class="content-container"> <div class="inputGroup" id="filterSites"> <input spellcheck="false" id="searchJumperInput" autocomplete="on" title="${i18n("inputTitle")}" placeholder="${i18n("inputPlaceholder")}" list="filterGlob" /> <input spellcheck="false" id="searchJumperInputKeyWords" autocomplete="on" placeholder="${i18n("inputKeywords")}" list="suggest" /> <datalist id="filterGlob"> </datalist> <datalist id="suggest"> </datalist> <span class="search-jumper-lock-input"></span> <span class="svgBtns"> <svg id="copyEleBtn" style="display:none;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>${i18n("copyEleBtn")}</title><path d="M706.5 188.4H190.2c-29.8 0-54 24.2-54 54v662.9c0 29.8 24.2 54 54 54h516.3c29.8 0 54-24.2 54-54V242.4c0-29.8-24.2-54-54-54z m-18 698.9H208.2V260.4h480.3v626.9zM313.7 512.2h275.2c19.9 0 36-16.1 36-36s-16.1-36-36-36H313.7c-19.9 0-36 16.1-36 36s16.1 36 36 36zM313.7 715.2h201.6c19.9 0 36-16.1 36-36s-16.1-36-36-36H313.7c-19.9 0-36 16.1-36 36s16.1 36 36 36zM837.2 64.7H302.9c-19.9 0-36 16.1-36 36s16.1 36 36 36h516.3v662.9c0 19.9 16.1 36 36 36s36-16.1 36-36V118.7c0-29.8-24.2-54-54-54z"></path></svg> <svg id="openLinkBtn" style="display:none;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>${i18n("openLinkBtn")}</title><path d="M429.013333 640A32 32 0 0 1 384 594.986667l37.76-37.76-22.826667-22.613334-135.68 135.68 90.453334 90.453334 135.68-135.68-22.613334-22.613334zM534.613333 398.933333l22.613334 22.613334L594.986667 384A32 32 0 0 1 640 429.013333l-37.76 37.76 22.613333 22.613334 135.68-135.68-90.453333-90.453334z"/><path d="M512 21.333333a490.666667 490.666667 0 1 0 490.666667 490.666667A490.666667 490.666667 0 0 0 512 21.333333z m316.8 354.986667l-181.12 181.12a32 32 0 0 1-45.226667 0L557.226667 512 512 557.226667l45.226667 45.226666a32 32 0 0 1 0 45.226667l-181.12 181.12a32 32 0 0 1-45.226667 0l-135.68-135.68a32 32 0 0 1 0-45.226667l181.12-181.12a32 32 0 0 1 45.226667 0L466.773333 512 512 466.773333l-45.226667-45.226666a32 32 0 0 1 0-45.226667l181.12-181.12a32 32 0 0 1 45.226667 0l135.68 135.68a32 32 0 0 1 0 45.226667z"/></svg> <svg id="maxEleBtn" style="display:none;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>${i18n("maxEleBtn")}</title><path d="M192 832h160a32 32 0 0 1 0 64H160a32 32 0 0 1-32-32V672a32 32 0 0 1 64 0zM182.72 886.72a32 32 0 0 1-45.44-45.44l224-224a32 32 0 0 1 45.44 45.44zM832 832V672a32 32 0 0 1 64 0v192a32 32 0 0 1-32 32H672a32 32 0 0 1 0-64zM886.72 841.28a32 32 0 0 1-45.44 45.44l-224-224a32 32 0 0 1 45.44-45.44zM192 192v160a32 32 0 0 1-64 0V160a32 32 0 0 1 32-32h192a32 32 0 0 1 0 64zM137.28 182.72a32 32 0 0 1 45.44-45.44l224 224a32 32 0 0 1-45.44 45.44zM832 192H672a32 32 0 0 1 0-64h192a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0zM841.28 137.28a32 32 0 1 1 45.44 45.44l-224 224a32 32 0 0 1-45.44-45.44z"></path></svg> <svg id="minEleBtn" style="display:none;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>${i18n("minEleBtn")}</title><path d="M672 352h160a32 32 0 0 1 0 64H640a32 32 0 0 1-32-32V192a32 32 0 0 1 64 0zM662.72 406.72a32 32 0 0 1-45.44-45.44l224-224a32 32 0 1 1 45.44 45.44zM352 352V192a32 32 0 0 1 64 0v192a32 32 0 0 1-32 32H192a32 32 0 0 1 0-64zM406.72 361.28a32 32 0 0 1-45.44 45.44l-224-224a32 32 0 0 1 45.44-45.44zM672 672v160a32 32 0 0 1-64 0V640a32 32 0 0 1 32-32h192a32 32 0 0 1 0 64zM617.28 662.72a32 32 0 0 1 45.44-45.44l224 224a32 32 0 0 1-45.44 45.44zM192 672a32 32 0 0 1 0-64h192a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0V672zM361.28 617.28a32 32 0 0 1 45.44 45.44l-224 224a32 32 0 0 1-45.44-45.44z"></path></svg> <svg id="pickerBtn" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>${i18n("multiPickerBtn")}</title><path d="M874.048 533.333333C863.424 716.629333 716.629333 863.424 533.333333 874.048V917.333333a21.333333 21.333333 0 0 1-42.666666 0v-43.285333C307.370667 863.424 160.576 716.629333 149.952 533.333333H106.666667a21.333333 21.333333 0 0 1 0-42.666666h43.285333C160.576 307.370667 307.370667 160.576 490.666667 149.952V106.666667a21.333333 21.333333 0 0 1 42.666666 0v43.285333c183.296 10.624 330.090667 157.418667 340.714667 340.714667h42.816a21.333333 21.333333 0 1 1 0 42.666666H874.026667z m-42.752 0h-127.786667a21.333333 21.333333 0 0 1 0-42.666666h127.786667C820.778667 330.922667 693.056 203.221333 533.333333 192.704V320a21.333333 21.333333 0 0 1-42.666666 0V192.704C330.922667 203.221333 203.221333 330.944 192.704 490.666667H320a21.333333 21.333333 0 0 1 0 42.666666H192.704c10.517333 159.744 138.24 287.445333 297.962667 297.962667V704a21.333333 21.333333 0 0 1 42.666666 0v127.296c159.744-10.517333 287.445333-138.24 297.962667-297.962667zM512 554.666667a42.666667 42.666667 0 1 1 0-85.333334 42.666667 42.666667 0 0 1 0 85.333334z"></path></svg> </span> </div> <div class="inputGroup" id="searchInPage"> <span class="lockWords"></span> <input spellcheck="false" id="searchJumperInPageInput" autocomplete="on" title="${i18n("inPageTips")}" placeholder="${i18n("inPagePlaceholder")}" /> <span class="svgBtns"> <svg id="editBtn" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>${i18n("editBtn")}</title><path d="M928 365.664a32 32 0 0 0-32 32V864a32 32 0 0 1-32 32H160a32 32 0 0 1-32-32V160a32 32 0 0 1 32-32h429.6a32 32 0 0 0 0-64H160a96 96 0 0 0-96 96v704a96 96 0 0 0 96 96h704a96 96 0 0 0 96-96V397.664a32 32 0 0 0-32-32z"></path><path d="M231.616 696.416a38.4 38.4 0 0 0 44.256 53.792l148-38.368L950.496 185.248 814.72 49.472 290.432 573.76l-58.816 122.656z m111.808-85.12L814.72 140l45.248 45.248-468.992 468.992-77.824 20.16 30.272-63.104z"></path></svg> <svg id="addWord" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>${i18n("addWord")}</title><path d="M821.364 962h-618.75C123.864 962 62 900.114 62 821.364v-618.75c0-78.75 61.864-140.635 140.614-140.635h618.75c78.75 0 140.636 61.885 140.636 140.635v618.75C962 900.114 900.114 962 821.364 962z m79.265-756.814c0-46.586-35.25-81.815-81.815-81.815H205.186c-46.843-0.214-84.557 34.758-83.165 82.393-0.128 14.4 1.35 613.05 1.35 613.05 0 46.565 35.25 81.815 81.815 81.815h613.628c46.565 0 81.815-35.25 81.815-81.815V205.186z m-173.55 347.657H552.843v174.236c0 16.95-13.736 30.685-30.686 30.685h-0.236a30.686 30.686 0 0 1-30.685-30.685V552.843H296.92a30.686 30.686 0 0 1-30.685-30.686v-0.236c0-16.95 13.735-30.685 30.685-30.685h194.315V296.92c0-16.95 13.735-30.685 30.685-30.685h0.236c16.95 0 30.686 13.735 30.686 30.685v194.315h174.236c16.95 0 30.685 13.735 30.685 30.685v0.236c0 16.95-13.735 30.686-30.685 30.686z"></path></svg> <svg id="emptyBtn" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>${i18n("emptyBtn")}</title><path d="m159.45829,231.40004l-48.83334,0a36.625,34.1375 0 0 1 0,-68.275l805.75004,0a36.625,34.1375 0 0 1 0,68.275l-683.6667,0l0,603.09581a61.04167,56.89583 0 0 0 61.04167,56.89584l439.50002,0a61.04167,56.89583 0 0 0 61.04167,-56.89584l0,-500.68332a36.625,34.1375 0 0 1 73.25,0l0,500.68332c0,69.12844 -60.12604,125.17084 -134.29167,125.17084l-439.50002,0c-74.16563,0 -134.29167,-56.0424 -134.29167,-125.17084l0,-603.09581zm256.37501,-113.79167a36.625,34.1375 0 0 1 0,-68.275l195.33334,0a36.625,34.1375 0 0 1 0,68.275l-195.33334,0zm-36.625,307.23749a36.625,34.1375 0 0 1 73.25,0l0,273.09999a36.625,34.1375 0 0 1 -73.25,0l0,-273.09999zm195.33334,0a36.625,34.1375 0 0 1 73.25,0l0,273.09999a36.625,34.1375 0 0 1 -73.25,0l0,-273.09999z"/></svg> <svg id="copyInPageBtn" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>${i18n("copyInPageBtn")}</title><path d="M706.5 188.4H190.2c-29.8 0-54 24.2-54 54v662.9c0 29.8 24.2 54 54 54h516.3c29.8 0 54-24.2 54-54V242.4c0-29.8-24.2-54-54-54z m-18 698.9H208.2V260.4h480.3v626.9zM313.7 512.2h275.2c19.9 0 36-16.1 36-36s-16.1-36-36-36H313.7c-19.9 0-36 16.1-36 36s16.1 36 36 36zM313.7 715.2h201.6c19.9 0 36-16.1 36-36s-16.1-36-36-36H313.7c-19.9 0-36 16.1-36 36s16.1 36 36 36zM837.2 64.7H302.9c-19.9 0-36 16.1-36 36s16.1 36 36 36h516.3v662.9c0 19.9 16.1 36 36 36s36-16.1 36-36V118.7c0-29.8-24.2-54-54-54z"></path></svg> <svg id="wordModeBtn" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>${i18n("wordModeBtn")}</title><path d="M832 128c38.4 0 64 25.6 64 64v640c0 38.4-25.6 64-64 64H192c-38.4 0-64-25.6-64-64V192c0-38.4 25.6-64 64-64h640m0-64H192c-70.4 0-128 57.6-128 128v640c0 70.4 57.6 128 128 128h640c70.4 0 128-57.6 128-128V192c0-70.4-57.6-128-128-128z"></path><path d="M736 812.8h-448c-19.2 0-32-12.8-32-32s12.8-32 32-32h448c19.2 0 32 12.8 32 32 0 12.8-12.8 32-32 32zM320 704c-19.2-6.4-25.6-25.6-19.2-44.8l185.6-454.4c6.4-12.8 25.6-19.2 38.4-12.8 19.2 6.4 25.6 25.6 19.2 44.8l-185.6 454.4c-6.4 12.8-25.6 19.2-38.4 12.8z"></path><path d="M704 691.2c19.2-6.4 25.6-25.6 19.2-44.8L544 211.2c-6.4-19.2-25.6-25.6-38.4-19.2-19.2 6.4-25.6 25.6-19.2 38.4l179.2 441.6c6.4 19.2 25.6 25.6 38.4 19.2z"></path><path d="M371.2 492.8h256v64h-256z"></path></svg> <svg id="recoverBtn" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>${i18n("recoverBtn")}</title><path d="M502.26 289.06c-0.02 16.95 13.26 30.94 30.18 31.8 123.47 8.79 236.97 70.94 310.89 170.21 73.92 99.28 100.91 225.84 73.93 346.65-41.65-181.74-195.38-316.12-381.05-333.08-8.89-0.6-17.63 2.55-24.09 8.7a31.798 31.798 0 0 0-9.86 23.64v85.15a32.343 32.343 0 0 1-50.67 26.41L114.21 413.02a32.341 32.341 0 0 1-14.46-26.95c0-10.84 5.43-20.96 14.46-26.95L451.6 124.68a32.358 32.358 0 0 1 33.28-2.03 32.355 32.355 0 0 1 17.39 28.44v137.97h-0.01z"></path></svg> <svg id="saveRuleBtn" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>${i18n("saveRuleBtn")}</title><path d="M579.7 291.4c18.8 0 34.1-15.3 34.1-34.1v-34.1c0-18.8-15.4-34.1-34.1-34.1-18.8 0-34.1 15.3-34.1 34.1v34.1c0 18.7 15.4 34.1 34.1 34.1zM944.7 216.3L808.2 79.9c-6.8-6.8-15.3-10.2-23.9-10.2H170.4c-56.3 0-102.3 46-102.3 102.3v682.1c0 56.3 46 102.3 102.3 102.3H852.5c56.3 0 102.3-46 102.3-102.3V240.2c0.1-8.5-3.3-17-10.1-23.9zM358 137.9h307v182.5c0 11.9-10.2 22.2-22.2 22.2H380.2c-11.9 0-22.2-10.2-22.2-22.2V137.9z m358.1 750.3H306.9V652.9c0-20.5 17.1-37.5 37.5-37.5h334.2c20.5 0 37.5 17 37.5 37.5v235.3z m170.6-34.1c0 18.8-15.3 34.1-34.1 34.1h-66.5V652.9c0-58-47.7-105.7-105.7-105.7h-336c-58 0-105.7 47.7-105.7 105.7v235.3h-68.2c-18.8 0-34.1-15.3-34.1-34.1V172c0-18.8 15.3-34.1 34.1-34.1h119.4v182.5c0 49.5 40.9 90.4 90.4 90.4h262.6c49.5 0 90.4-40.9 90.4-90.4V137.9h37.5l116 116v600.2z"></path></svg> <svg id="pinBtn" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>${i18n("pinBtn")}</title><path d="m674.8822,92.83803a81.61801,81.04246 0 0 1 25.30158,17.09996l213.75757,212.46631a81.61801,81.04246 0 0 1 -24.70304,131.36982l-75.74151,33.30845l-142.09696,141.257l-11.26329,155.3854a81.61801,81.04246 0 0 1 -139.13151,51.46196l-137.98885,-137.15085l-235.14149,234.56388l-57.83996,-57.18896l235.27751,-234.69896l-142.7499,-141.85131a81.61801,81.04246 0 0 1 51.6642,-138.09635l160.95072,-11.94025l139.5668,-138.74469l32.78324,-75.09935a81.61801,81.04246 0 0 1 107.35489,-42.14208zm-32.45675,74.36997l-38.95901,89.22775l-171.94193,170.99958l-191.25821,14.1284l338.46989,336.3262l13.43977,-185.47917l174.33607,-173.32279l89.69819,-39.44067l-213.78477,-212.43929z"></path></svg> <svg id="locBtn" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>${i18n("locBtn")}</title><path d="M357.6 832l-255.2 56c-20 4.8-39.2-10.4-39.2-31.2V569.6c0-15.2 10.4-28 24.8-31.2L243.2 504l53.6 53.6L139.2 592c-7.2 1.6-12.8 8-12.8 16v188c0 10.4 9.6 17.6 19.2 16l192.8-42.4 12.8-3.2 12.8 2.4 306.4 60.8 210.4-47.2c7.2-1.6 12.8-8 12.8-16V580c0-10.4-9.6-17.6-19.2-16L688 606.4l-12 2.4L760 524.8l160.8-36c20-4.8 39.2 10.4 39.2 31.2v286.4c0 15.2-10.4 28-24.8 31.2L672.8 896M512 128c-115.2 0-206.4 101.6-190.4 220 5.6 41.6 26.4 80 56 109.6l0.8 0.8L512 591.2l133.6-132.8 0.8-0.8c29.6-29.6 49.6-68 56-109.6C719.2 229.6 627.2 128 512 128m0-64c141.6 0 256 114.4 256 256 0 70.4-28 133.6-74.4 180L512 681.6 330.4 500C284.8 453.6 256 390.4 256 320 256 178.4 371.2 64 512 64z m64.8 193.6c0-35.2-28.8-64-64-64s-64 28.8-64 64 28.8 64 64 64 64-28 64-64z"></path></svg> </span> <div id="addons"></div> </div> </div> <div id="rightSizeChange"></div> `); searchBarCon.appendChild(searchInputDiv); this.searchInputDiv = searchInputDiv; this.searchInput = searchInputDiv.querySelector("#searchJumperInput"); this.searchJumperInputKeyWords = searchInputDiv.querySelector("#searchJumperInputKeyWords"); this.searchLockInput = searchInputDiv.querySelector(".search-jumper-lock-input"); this.searchJumperInPageInput = searchInputDiv.querySelector("#searchJumperInPageInput"); this.pickerBtn = searchInputDiv.querySelector("#pickerBtn"); this.minEleBtn = searchInputDiv.querySelector("#minEleBtn"); this.maxEleBtn = searchInputDiv.querySelector("#maxEleBtn"); this.copyEleBtn = searchInputDiv.querySelector("#copyEleBtn"); this.openLinkBtn = searchInputDiv.querySelector("#openLinkBtn"); this.editBtn = searchInputDiv.querySelector("#editBtn"); this.addWord = searchInputDiv.querySelector("#addWord"); this.recoverBtn = searchInputDiv.querySelector("#recoverBtn"); this.wordModeBtn = searchInputDiv.querySelector("#wordModeBtn"); this.saveRuleBtn = searchInputDiv.querySelector("#saveRuleBtn"); this.pinBtn = searchInputDiv.querySelector("#pinBtn"); this.locBtn = searchInputDiv.querySelector("#locBtn"); this.emptyBtn = searchInputDiv.querySelector("#emptyBtn"); this.copyInPageBtn = searchInputDiv.querySelector("#copyInPageBtn"); this.closeBtn = searchInputDiv.querySelector(".closeBtn"); this.filterSites = searchInputDiv.querySelector("#filterSites"); this.filterSitesTab = searchInputDiv.querySelector("#filterSitesTab"); this.searchInPageTab = searchInputDiv.querySelector("#searchInPageTab"); this.searchInPageLockWords = searchInputDiv.querySelector("#searchInPage>.lockWords"); this.contentContainer = searchInputDiv.querySelector(".content-container"); this.rightSizeChange = searchInputDiv.querySelector("#rightSizeChange"); this.filterGlob = searchInputDiv.querySelector("#filterGlob"); this.suggestDatalist = searchInputDiv.querySelector("#suggest"); this.addonsList = searchInputDiv.querySelector("#addons"); this.fakeTextareas = new Map(); this.addonCheckboxDict = {}; } showInPageSearch() { this.searchInPageTab.checked = true; this.showSearchInput(); this.initSetInPageWords(); this.searchJumperInPageInput.value = ""; this.initShowSearchInput = true; } showFilterSearch() { this.filterSitesTab.checked = true; this.showSearchInput(); } initSetInPageWords() { if (this.searchInPageTab.checked && !this.searchJumperInPageInput.value) { let words = getSelectStr() || this.searchJumperInputKeyWords.value.replace(/^\*/, "") || getKeywords(); if (words) { try { words = decodeURIComponent(words); } catch (e) {} } if (this.lockWords && this.lockWords.indexOf(words) !== -1) return; this.searchJumperInPageInput.value = words || globalInPageWords; if (!this.lockWords) { this.submitIgnoreSpace(this.searchJumperInPageInput.value); //this.submitInPageWords(); } } } anylizeInPageWords(words, init) { if (!words) return []; let self = this; let result = []; if (!this.lockWords) { if (words.indexOf("$c") === 0 && words.length > 2) { words = words.substr(3).trim(); } else if (words.indexOf("$o") === 0) { words = words.substr(2).trim(); } } if (this.splitSep) { let inWordMode = this.wordModeBtn.classList.contains("checked"); let splitSep = inWordMode ? new RegExp(`[\\${this.splitSep} ]`) : this.splitSep; words.split(splitSep).sort((a, b) => b.length - a.length).forEach(word => { let oriWord = word; word = word.trim(); if (!word) return; if (init) { if (word.length < (searchData.prefConfig.limitInPageLen || 1)) return; if ((searchData.prefConfig.ignoreWords || []).includes(word.toLowerCase())) return; } let title = ""; let style = ""; let popup = false; let hideParent; let link; let inRange; let isRe = false; let reCase = ""; let titleReg = /\$t{(.*?)}($|\$)/; let titleMatch = word.match(titleReg); let showTips = 0; if (titleMatch) { title = titleMatch[1]; word = word.replace(titleReg, "$2"); if (title == "\\$popup") title = "$popup"; else if (title == "\\@popup") title = "@popup"; else { let popupMatch = title.match(/^[\$@]popup(\((.*)\))?$/); if (popupMatch) { title = ""; popup = true; if (popupMatch[1]) { showTips = popupMatch[2] || "1"; } } } } let hideParentReg = /\$p{(.*?)}($|\$)/; let hideParentMatch = word.match(hideParentReg); if (hideParentMatch) { hideParent = parseInt(hideParentMatch[1]) || 0; word = word.replace(hideParentReg, "$2"); } let inRangeReg = /\$in{(.*?)}($|\$)/; let inRangeMatch = word.match(inRangeReg); if (inRangeMatch) { inRange = inRangeMatch[1] || ''; word = word.replace(inRangeReg, "$2"); } let styleReg = /\$s{(.*?)}($|\$)/; let styleMatch = word.match(styleReg); if (styleMatch) { let bg = styleMatch[1], otherCss = ""; styleMatch = styleMatch[1].match(/(.*?);(.*)/); if (styleMatch) { bg = styleMatch[1]; otherCss = styleMatch[2]; } style = self.getHighlightStyle(self.curWordIndex, bg, otherCss); word = word.replace(styleReg, "$2"); } else { style = self.getHighlightStyle(self.curWordIndex, "", ""); } let showWords = ""; if (word.indexOf("@") === 0) { showWords = word; let wordTemp = searchData.prefConfig.inPageRule && searchData.prefConfig.inPageRule[word]; if (wordTemp) word = wordTemp; //else return; } else { word = word.replace(/^\\@/, "@"); } let reMatch = word.match(/^\/(.*)\/([il]*)($|\$)/); if (reMatch) { isRe = true; word = reMatch[1]; reCase = reMatch[2].indexOf("i") != -1 ? "i" : ""; link = reMatch[2].indexOf("l") != -1; } if (!showWords) showWords = word; if (self.highlightSpans[showWords]) return; result.push({content: word, showWords: showWords, isRe: isRe, link: link, reCase: reCase, title: title, style: style, oriWord: oriWord, hideParent: hideParent, inRange: inRange, popup: popup, showTips: showTips, init: init}); self.curWordIndex++; }); } else { this.curWordIndex = 0; let word = (this.lockWords || "").replace(/^\$o/, "") + words; result = [{content: word, showWords: word, isRe: false, reCase: "", title: "", style: self.getHighlightStyle(self.curWordIndex, "", ""), init: init}]; } return result; } submitInPageWords(init) { let self = this; let words = this.searchJumperInPageInput.value; let wordSpans = []; if (!words) { if (!this.lockWords) { this.highlight(""); } else { this.highlight("insert"); for (let i in this.highlightSpans) { let span = this.highlightSpans[i]; let curList = this.marks[i]; this.setHighlightSpan(span, 0, curList); } } return wordSpans; } this.initHighlight = !!init; if (this.initHighlight) { setTimeout(() => { this.initHighlight = false; }, 500); } if (!this.lockWords) { if (words.indexOf("$c") === 0 && words.length > 2) { this.splitSep = words.substr(2, 1); } else if (words.indexOf("$o") === 0) { this.splitSep = null; } else this.splitSep = "◎"; this.curWordIndex = 0; } this.searchJumperInPageInput.value = ""; let targetWords = this.anylizeInPageWords(words, this.initHighlight); if (!targetWords || targetWords.length == 0) return wordSpans; if (this.lockWords) { this.lockWords += (this.lockWords.indexOf(this.splitSep) === this.lockWords.length - this.splitSep.length ? "" : this.splitSep) + words; } else this.lockWords = words; if (!this.splitSep) { this.searchInPageLockWords.innerHTML = createHTML(); this.highlight(""); } this.highlight(targetWords); targetWords.forEach(word => { if (!word) return; let wordSpan = document.createElement("span"); wordSpan.innerHTML = createHTML(word.showWords); wordSpan.title = word.title ? JSON.parse('"' + word.title + '"') : word.showWords; let background = word.style.match(/background: *(#?\w+)/); if (background && background[1].indexOf('unset') === -1) wordSpan.style.background = background[1]; let color = word.style.match(/color: *(#?\w+)/); if (color) wordSpan.style.color = color[1]; wordSpan.addEventListener("click", e => { e.stopPropagation(); e.preventDefault(); return false; }); wordSpan.oncontextmenu = e => { e.preventDefault(); }; wordSpan.addEventListener('dblclick', e => { e.stopPropagation(); e.preventDefault(); if (e.target.nodeName.toUpperCase() === 'EM') return; if (e.ctrlKey || e.shiftKey || e.altKey || e.metaKey) return; if (this.lockWords.indexOf(word.oriWord) === -1) { return; } this.showModifyWindow(word, wordSpan); }, true); wordSpan.addEventListener("mousedown", e => { if (e.button === 0) { this.focusHighlightByText(word.showWords, true, wordSpan); } else if (e.button === 2){ this.focusHighlightByText(word.showWords, false, wordSpan); } }); let wheelScrolling = false; wordSpan.addEventListener(getSupportWheelEventName(), e => { e.preventDefault(); e.stopPropagation(); if (wheelScrolling) return; wheelScrolling = true; setTimeout(() => { wheelScrolling = false; }, 100); let deltaY; if(e.type !== 'wheel'){ let y = 0; if (typeof e.axis == 'number') { if (e.axis == 2) { y = e.detail; } } else { if (typeof e.wheelDeltaY == 'undefined' || e.wheelDeltaY != 0) { y = -e.wheelDelta / 40; } }; deltaY = y; } else { deltaY = e.deltaY; } this.focusHighlightByText(word.showWords, deltaY > 0, wordSpan); }, { passive: false, capture: false }); wordSpan.addEventListener("editword", e => { wordSpan.parentNode.removeChild(wordSpan); this.removeHighlightWord(word); this.searchJumperInPageInput.value = word.content; }); let removeBtn = document.createElement("div"); removeBtn.addEventListener("mousedown", e => { e.stopPropagation(); e.preventDefault(); /*if (this.wordModeBtn.classList.contains("checked")) { this.wordModeBtn.classList.remove("checked"); if (this.lockWords) { this.refreshPageWords(this.lockWords); } return; }*/ wordSpan.parentNode.removeChild(wordSpan); this.removeHighlightWord(word); }); removeBtn.className = "lockWordTool"; removeBtn.innerHTML = createHTML(`<span title="${i18n("removeBtn")}">×</span>`); wordSpan.appendChild(removeBtn); let modifyBtn = document.createElement("div"); modifyBtn.addEventListener("mousedown", e => { e.stopPropagation(); e.preventDefault(); if (this.lockWords.indexOf(word.oriWord) === -1) { return; } this.showModifyWindow(word, wordSpan); }); modifyBtn.className = "lockWordTool modifyBtn"; modifyBtn.innerHTML = createHTML(`<span>+</span>`); wordSpan.appendChild(modifyBtn); let curList = this.marks[word.showWords]; this.setHighlightSpan(wordSpan, -1, curList); this.highlightSpans[word.showWords] = wordSpan; this.searchInPageLockWords.appendChild(wordSpan); wordSpans.push(wordSpan); }); if (this.searchInPageLockWords.scrollTop <= 0) this.searchInPageLockWords.scrollTop = this.searchInPageLockWords.scrollHeight; this.searchJumperInPageInput.style.paddingLeft = this.searchInPageLockWords.clientWidth + 3 + "px"; if (this.navMarks.innerHTML && this.con.style.display === "none") this.con.style.display = ""; return wordSpans; } async showCustomInputWindow(url, callback) { return new Promise((resolve) => { this.customInputCallback = callback; let geneFinalUrl = () => { let finalValue = this.finalSearch.dataset.url; [].forEach.call(this.customGroup.children, ele => { let value = ele.value; if (ele.className == "select") { value = ele.children[0].value; } else if (/^DIV$/i.test(ele.nodeName)) return; finalValue = finalValue.replace('◎', value || ''); }); this.finalSearch.value = finalValue; }; if (!this.customInputFrame) { let customInputCssText = ` .customInputFrame-body { width: 300px; min-height: 200px; position: fixed; text-align: left; left: 50%; top: 50%; margin-top: -160px; margin-left: -150px; z-index: 2147483647; background-color: #ffffff; border: 1px solid #afb3b6; border-radius: 10px; opacity: 0.95; filter: alpha(opacity=95); box-shadow: 5px 5px 20px 0px #000; color: #6e7070; font-size: initial; } .customInputFrame-body #customGroup { max-height: 50vh; overflow: auto; scrollbar-width: none; } .customInputFrame-body #customGroup::-webkit-scrollbar { width: 0 !important; height: 0 !important; } .customInputFrame-title { background: #458bd1!important; display: flex!important; align-items: center!important; justify-content: center!important; color: white!important; font-weight: bold; font-size: 18px!important; border-radius: 10px 10px 0 0!important; } .customInputFrame-title>img { margin: 5px; height: 32px; width: 32px; } .customInputFrame-input-title { font-size: 9pt; font-family: Arial, sans-serif; display: inline-block; background-color: white; position: relative; left: 20px; padding: 0px 4px; text-align: left; color: #646464; word-break: break-all; max-width: 85%; z-index: 1; } .customInputFrame-body input[type=text], .customInputFrame-body input[type=number], .customInputFrame-body textarea, .customInputFrame-body .select { resize: both; font-size: 11pt; font-weight: normal; border-radius: 4px; border: 1px solid rgba(0, 0, 0, 0.23); margin: 4px; font-family: inherit; background-color: #FFF; width: calc(100% - 8px); color: #4A4A4A; margin-top: -8px; padding: 4px; padding-top: 8px; box-sizing: border-box; } .customInputFrame-buttons { text-align: center; margin-bottom: 5px; display: flex; justify-content: space-evenly; } .customInputFrame-buttons>button { width: 32%; font-size: 16px; cursor: pointer; border: 1px solid #1976d2; border-radius: 4px; transition: all .3s; color: #fff; background-color: #458bd1; line-height: 25px; } .customInputFrame-buttons>button:hover { color: #e3f2fd; } .customInputFrame-body .select { height: 30px; position: relative; } .customInputFrame-body .select>input[type=text] { top: 0px; left: -7px; position: relative; border: unset!important; width: calc(100% - 25px); padding-bottom: 3px; margin-bottom: -30px; float: left; background: unset; height: 28px; } .customInputFrame-body .select>p { padding: 0; margin: 0; position: absolute; pointer-events: none; } .customInputFrame-body .select>.options { position: absolute; visibility: hidden; opacity: 0; transition: opacity .1s; background-color: #FFF; color: #4A4A4A; border: 1px solid rgba(0, 0, 0, 0.23); border-radius: 4px; z-index: 10; width: auto; max-width: 35%; right: calc(50% - 147px); margin-top: -10px; position: fixed; } .customInputFrame-body .select>input:focus+p { display: none; } .customInputFrame-body .select:hover>.options { visibility: visible; opacity: 1; } .customInputFrame-body .select>.options>p { cursor: pointer; min-height: 20px; padding: 3px 0; margin: 0; } .customInputFrame-body .select>.options>p:hover { background: aliceblue; } .customInputFrame-body div.select:after { content: "▼"; position: absolute; right: 6px; top: 8px; font-size: 9px; } @media (prefers-color-scheme: dark) { .customInputFrame-body, .customInputFrame-input-title, .customInputFrame-body input, .customInputFrame-body textarea, .customInputFrame-body .select { background-color: black!important; color: #d5d5d5!important; } .customInputFrame-body input:focus, .customInputFrame-body textarea:focus, .customInputFrame-body .select:focus { background-color: #1e1e1e!important; } .customInputFrame-body input, .customInputFrame-body textarea, .customInputFrame-body .select { border: 1px solid rgb(255 255 255 / 36%)!important; background-color: #0c0c0c!important; } .customInputFrame-title, .customInputFrame-buttons>button { background: #245d8f!important; } .customInputFrame-body .select>.options { border: 1px solid rgb(255 255 255 / 36%)!important; background-color: black; color: #d5d5d5; } .customInputFrame-body .select>.options>p:hover { background: #1e1e1e; } } `; let customInputCssEle = _GM_addStyle(customInputCssText); let customInputFrame = document.createElement("div"); this.customInputFrame = customInputFrame; customInputFrame.innerHTML = createHTML(` <div class="customInputFrame-body"> <a href="${configPage}" class="customInputFrame-title" target="_blank"> <img width="32px" height="32px" src="${logoBase64}" />${i18n("customInputFrame")} </a> <div id="customGroup"> </div> <div class="customInputFrame-input-title">${i18n("finalSearch")}</div> <textarea name="finalSearch" type="text"></textarea> <div class="customInputFrame-buttons"> <button id="cancel" type="button">${i18n("cancel")}</button> <button id="customSubmit" type="button">${i18n("customSubmit")}</button> </div> </div> `); if (!disabled) customInputFrame.appendChild(customInputCssEle); let cancelBtn = customInputFrame.querySelector("#cancel"); cancelBtn.addEventListener("click", e => { if (customInputFrame.parentNode) { customInputFrame.parentNode.removeChild(customInputFrame); } resolve(""); }); customInputFrame.addEventListener("keydown", e => { if (e.keyCode == 13) { customSubmit.click(); } }); let customGroup = this.customInputFrame.querySelector("#customGroup"); this.customGroup = customGroup; let finalSearch = this.customInputFrame.querySelector("[name='finalSearch']"); this.finalSearch = finalSearch; finalSearch.addEventListener("click", e => { geneFinalUrl(); }); let customSubmit = customInputFrame.querySelector("#customSubmit"); customSubmit.addEventListener("click", e => { geneFinalUrl(); if (finalSearch.value) { if (this.customInputCallback) this.customInputCallback(finalSearch.value); } resolve(finalSearch.value); if (customInputFrame.parentNode) { customInputFrame.parentNode.removeChild(customInputFrame); } }); } if (this.customInputFrame.parentNode) { this.customInputFrame.parentNode.removeChild(this.customInputFrame); } this.customGroup.innerHTML = createHTML(); let tempUrl = url; let inputMatch = tempUrl.match(/%input{(.*?[^\\])}/); while (inputMatch) { let param = inputMatch[1]; if (/^".*","/.test(param)) { param = param.substr(1, param.length - 2).split('","'); } else { param = param.replace(/\\,/g, "◎SJ").split(",").map(str => str.replace(/◎SJ/g, ",")); } if (param.length === 1) {//input param = param[0].replace(/\\\|/g, "◎SJ").split("|").map(str => str.replace(/◎SJ/g, "|")); let inputTitle = document.createElement('div'); inputTitle.className = 'customInputFrame-input-title'; inputTitle.innerText = param[0]; this.customGroup.appendChild(inputTitle); let paramInput = document.createElement('input'); paramInput.type = 'text'; if (param.length > 1) paramInput.title = param[1]; this.customGroup.appendChild(paramInput); } else if (param.length >= 2) {//select let titleSplit = param[0].replace(/\\}/g, "}"); if (/^'.*'\/'/.test(titleSplit)) { titleSplit = titleSplit.substr(1, titleSplit.length - 2).split("'/'"); } else { titleSplit = titleSplit.replace(/\\\//g, "◎SJ").split("/").map(str => str.replace(/◎SJ/g, "/")); } let optionSplit = param.slice(1).join(","); if (/^'.*'\/'/.test(optionSplit)) { optionSplit = optionSplit.substr(1, optionSplit.length - 2).split("'/'"); } else { optionSplit = optionSplit.replace(/\\\//g, "◎SJ").split("/").map(str => str.replace(/◎SJ/g, "/")); } let singleTitle = titleSplit.length === optionSplit.length + 1; let inputTitle = document.createElement('div'); inputTitle.className = 'customInputFrame-input-title'; inputTitle.innerText = titleSplit[0]; this.customGroup.appendChild(inputTitle); let paramSelectInput = document.createElement('input'); paramSelectInput.type = "text"; let paramSelect = document.createElement('div'); paramSelect.className = "select"; paramSelect.appendChild(paramSelectInput); let selectTips = document.createElement('p'); selectTips.innerText = 'Select option'; paramSelect.appendChild(selectTips); let options = document.createElement('div'); options.className = "options"; paramSelect.appendChild(options); let option = document.createElement("p"); option.setAttribute("value", ""); option.innerHTML = createHTML('<b>Select option</b>'); options.appendChild(option); option.addEventListener("click", e => { options.style.visibility = "hidden"; setTimeout(() => { options.style.visibility = ""; }, 0); paramSelectInput.value = ""; selectTips.innerText = 'Select option'; geneFinalUrl(); }); for (let i = 0; i < optionSplit.length; i++) { let value = optionSplit[i]; let option = document.createElement("p"); option.setAttribute("value", value); if (singleTitle) { let title = titleSplit[i + 1]; title = title.replace(/\\\|/g, "◎SJ").split("|").map(str => str.replace(/◎SJ/g, "|")); option.innerText = title[0]; if (title.length > 1) { option.title = title[1]; } } else { option.innerText = value; } option.addEventListener("click", e => { options.style.visibility = "hidden"; setTimeout(() => { options.style.visibility = ""; }, 0); paramSelectInput.value = option.getAttribute("value"); selectTips.innerText = ''; geneFinalUrl(); }); options.appendChild(option); } paramSelectInput.addEventListener("change", e => { selectTips.innerText = ''; }); paramSelect.addEventListener("mouseenter", e => { paramSelect.focus(); options.style.marginTop = - this.customGroup.scrollTop + 20 + "px"; }); this.customGroup.appendChild(paramSelect); } tempUrl = tempUrl.replace(inputMatch[0], '◎'); inputMatch = tempUrl.match(/%input{(.*?[^\\])}/); } this.finalSearch.dataset.url = tempUrl; this.finalSearch.value = tempUrl.replace(/◎/g, ''); this.addToShadow(this.customInputFrame); let frameBody = this.customInputFrame.children[0]; frameBody.style.marginTop = -frameBody.offsetHeight / 2 + "px"; }); } showModifyWindow(word, wordSpan) { let oriWord; this.modifyWord = {}; this.addNew = !word && !wordSpan; if (!this.addNew) { oriWord = word.oriWord; if (!oriWord) return; this.modifyWord = word; this.modifySpan = wordSpan; } if (!this.modifyFrame) { let modifyCssText = ` .searchJumperModify-body { width: 300px; min-height: 200px; position: fixed; text-align: left; left: 50%; top: 50%; margin-top: -160px; margin-left: -150px; z-index: 100000; background-color: #ffffff; border: 1px solid #afb3b6; border-radius: 10px; opacity: 0.95; filter: alpha(opacity=95); box-shadow: 5px 5px 20px 0px #000; color: #6e7070; } .searchJumperModify-title { background: #458bd1!important; display: flex!important; align-items: center!important; justify-content: center!important; color: white!important; font-weight: bold; font-size: 18px!important; border-radius: 10px 10px 0 0!important; } .searchJumperModify-title>img { margin: 5px; height: 32px; width: 32px; } .searchJumperModify-input-title { font-size: 9pt; font-family: Arial, sans-serif; display: inline-block; background-color: white; position: relative; left: 20px; padding: 0px 4px; text-align: left; color: #646464; } .searchJumperModify-body>input[type=text], .searchJumperModify-body>input[type=number], .searchJumperModify-body>textarea { resize: both; font-size: 11pt; font-weight: normal; border-radius: 4px; border: 1px solid rgba(0, 0, 0, 0.23); margin: 4px; font-family: inherit; background-color: #FFF; width: calc(100% - 8px); color: #4A4A4A; margin-top: -8px; padding: 4px; padding-top: 8px; box-sizing: border-box; } .searchJumperModify-buttons { text-align: center; margin-bottom: 5px; display: flex; justify-content: space-evenly; } .searchJumperModify-buttons>button { width: 32%; font-size: 16px; cursor: pointer; border: 1px solid #1976d2; border-radius: 4px; transition: all .3s; color: #fff; background-color: #458bd1; line-height: 25px; } .searchJumperModify-buttons>button:hover { color: #e3f2fd; } #rangePickerBtn { width: 28px; float: right; margin-top: -33px; margin-right: 6px; position: sticky; display: block; cursor: pointer; background: rgb(255 255 255 / 80%); } .searchJumperModify-checkGroup { margin: 5px; } #searchJumperModify-re + label ~ * { display: none; } #searchJumperModify-re:checked + label ~ * { display: inline; } @media (prefers-color-scheme: dark) { .searchJumperModify-body, .searchJumperModify-input-title, .searchJumperModify-body>input[type=text], .searchJumperModify-body>input[type=number], .searchJumperModify-body>textarea, .searchJumperModify-body>select { background-color: black!important; color: #d5d5d5!important; } .searchJumperModify-body>input:focus, .searchJumperModify-body>textarea:focus, .searchJumperModify-body>select:focus { background-color: #1e1e1e!important; } .searchJumperModify-body>input[type=text], .searchJumperModify-body>input[type=number], .searchJumperModify-body>textarea { border: 1px solid rgb(255 255 255 / 36%)!important; } .searchJumperModify-title, .searchJumperModify-buttons>button { background: #245d8f!important; } #rangePickerBtn { background: rgb(0 0 0 / 80%); fill: white; } } `; let modifyCssEle = _GM_addStyle(modifyCssText); let modifyFrame = document.createElement("div"); this.modifyFrame = modifyFrame; modifyFrame.id = "searchJumperModifyWord"; modifyFrame.innerHTML = createHTML(` <div class="searchJumperModify-body"> <a href="${configPage}" class="searchJumperModify-title" target="_blank"> <img onerror="this.style.display='none'" width="32px" height="32px" src="${logoBase64}" />${i18n("modifyWord")} </a> <div class="searchJumperModify-input-title">${i18n("wordContent")}</div> <input id="searchJumperHighlightWord" name="wordContent" placeholder="words" type="text"/> <div class="searchJumperModify-checkGroup"> <input id="searchJumperModify-re" type="checkbox"/> <label for="searchJumperModify-re">${i18n("re")}</label> <input id="searchJumperModify-case" type="checkbox"/> <label for="searchJumperModify-case">${i18n("ignoreCase")}</label> <input id="searchJumperModify-link" type="checkbox"/> <label for="searchJumperModify-link">${i18n("filterLink")}</label> </div> <div class="searchJumperModify-input-title">${i18n("wordHide")}</div> <input name="wordHide" min="0" placeholder="${i18n("wordHideTips")}" type="number" /> <div class="searchJumperModify-input-title">${i18n("wordRange")}</div> <input name="wordRange" placeholder="#main" type="text" /> <svg id="rangePickerBtn" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>${i18n("pickerBtn")}</title><path d="M874.048 533.333333C863.424 716.629333 716.629333 863.424 533.333333 874.048V917.333333a21.333333 21.333333 0 0 1-42.666666 0v-43.285333C307.370667 863.424 160.576 716.629333 149.952 533.333333H106.666667a21.333333 21.333333 0 0 1 0-42.666666h43.285333C160.576 307.370667 307.370667 160.576 490.666667 149.952V106.666667a21.333333 21.333333 0 0 1 42.666666 0v43.285333c183.296 10.624 330.090667 157.418667 340.714667 340.714667h42.816a21.333333 21.333333 0 1 1 0 42.666666H874.026667z m-42.752 0h-127.786667a21.333333 21.333333 0 0 1 0-42.666666h127.786667C820.778667 330.922667 693.056 203.221333 533.333333 192.704V320a21.333333 21.333333 0 0 1-42.666666 0V192.704C330.922667 203.221333 203.221333 330.944 192.704 490.666667H320a21.333333 21.333333 0 0 1 0 42.666666H192.704c10.517333 159.744 138.24 287.445333 297.962667 297.962667V704a21.333333 21.333333 0 0 1 42.666666 0v127.296c159.744-10.517333 287.445333-138.24 297.962667-297.962667zM512 554.666667a42.666667 42.666667 0 1 1 0-85.333334 42.666667 42.666667 0 0 1 0 85.333334z"></path></svg> <div class="searchJumperModify-input-title">${i18n("wordStyle")}</div> <input name="wordStyle" placeholder="orange or #333333;color:red;" type="text" /> <div class="searchJumperModify-input-title">${i18n("wordTitle")}</div> <textarea name="wordTitle" type="text" placeholder="Text comment, or @popup to popup, @popup(1) to popup 1st showTips, @popup(name) to popup showTips of target engine"></textarea> <div class="searchJumperModify-buttons"> <button id="cancel" type="button">${i18n("cancel")}</button> <button id="modify" type="button">${i18n("modify")}</button> </div> </div> `); if (!disabled) modifyFrame.appendChild(modifyCssEle); let cancelBtn = modifyFrame.querySelector("#cancel"); cancelBtn.addEventListener("click", e => { if (modifyFrame.parentNode) { modifyFrame.parentNode.removeChild(modifyFrame); } }); let rangePickerBtn = modifyFrame.querySelector("#rangePickerBtn"); rangePickerBtn.addEventListener("click", e => { picker.getSelector(selector => { wordRange.value = selector; modifyFrame.style.display = ''; }); modifyFrame.style.display = 'none'; }); let modifyBtn = modifyFrame.querySelector("#modify"); this.modifyBtn = modifyBtn; modifyBtn.addEventListener("click", e => { let newWord = wordContent.value; if (this.splitSep) newWord = newWord.replaceAll(this.splitSep, ""); if (!newWord) return; let contentChange = newWord !== this.modifyWord.showWords || wordReCase.checked !== this.modifyWord.isRe || wordLink.checked !== this.modifyWord.link; if (wordIsRe.checked && newWord.indexOf("@") !== 0) { newWord = `/${newWord}/${wordReCase.checked ? "i" : ""}${wordLink.checked ? "l" : ""}`; } let hide = wordHide.value; if (hide) { if (this.splitSep) hide = hide.replaceAll(this.splitSep, ""); hide = hide >= 0 ? hide : 0; newWord += `$p{${hide}}`; } let style = wordStyle.value; if (style) { if (this.splitSep) style = style.replaceAll(this.splitSep, ""); newWord += `$s{${style}}`; } let title = JSON.stringify(wordTitle.value).replace(/^"|"$/g, ""); if (title) { if (this.splitSep) title = title.replaceAll(this.splitSep, ""); newWord += `$t{${title}}`; } let range = wordRange.value; if (range) { if (this.splitSep) range = range.replaceAll(this.splitSep, ""); if (range !== this.modifyWord.inRange) contentChange = true; newWord += `$in{${range}}`; } if (this.addNew) { if (this.wordModeBtn.classList.contains("checked")) { this.wordModeBtn.classList.remove("checked"); if (this.lockWords) { this.refreshPageWords(this.lockWords); } } this.searchJumperInPageInput.value = newWord; this.submitInPageWords(); } else { this.replaceWord(this.modifyWord, newWord, this.modifySpan, contentChange); } if (modifyFrame.parentNode) { modifyFrame.parentNode.removeChild(modifyFrame); } }); } let wordContent = this.modifyFrame.querySelector("[name='wordContent']"), wordStyle = this.modifyFrame.querySelector("[name='wordStyle']"), wordTitle = this.modifyFrame.querySelector("[name='wordTitle']"), wordRange = this.modifyFrame.querySelector("[name='wordRange']"), wordHide = this.modifyFrame.querySelector("[name='wordHide']"), wordIsRe = this.modifyFrame.querySelector("#searchJumperModify-re"), wordReCase = this.modifyFrame.querySelector("#searchJumperModify-case"), wordLink = this.modifyFrame.querySelector("#searchJumperModify-link"); if (this.addNew) { wordContent.value = ""; wordStyle.value = ""; wordRange.value = ""; wordHide.value = ""; wordTitle.value = ""; wordIsRe.checked = false; wordReCase.checked = false; wordLink.checked = false; this.modifyBtn.innerText = i18n('add'); } else { this.modifyBtn.innerText = i18n('modify'); let style = ""; let styleReg = /\$s{(.*?)}($|\$)/; let styleMatch = oriWord.match(styleReg); if (styleMatch) { style = styleMatch[1]; } wordContent.value = word.showWords || ""; wordStyle.value = style || ""; wordRange.value = word.inRange || ""; wordIsRe.checked = !!word.isRe; wordReCase.checked = !!word.reCase; wordLink.checked = !!word.link; if (typeof word.hideParent !== 'undefined') wordHide.value = word.hideParent; try { if (word.popup) { wordTitle.value = "@popup"; if (word.showTips) { wordTitle.value = `@popup(${word.showTips})`; } } else { wordTitle.value = word.title !== word.showWords ? JSON.parse('"' + word.title + '"') : ""; } } catch (e) { debug(e); } } this.addToShadow(this.modifyFrame); } replaceWord(word, newWord, modifySpan, contentChange) { if (contentChange) { if (modifySpan.parentNode) modifySpan.parentNode.removeChild(modifySpan); this.removeHighlightWord(word); this.searchJumperInPageInput.value = newWord; this.submitInPageWords(); } else { let title = ""; let style = ""; let hideParent = -1; let titleReg = /\$t{(.*?)}($|\$)/; let titleMatch = newWord.match(titleReg); if (titleMatch) { title = titleMatch[1]; title = JSON.parse('"' + title + '"'); } word.title = title; modifySpan.title = title; let styleReg = /\$s{(.*?)}($|\$)/; let styleMatch = newWord.match(styleReg); if (styleMatch) { let bg = styleMatch[1], otherCss = ""; styleMatch = styleMatch[1].match(/(.*?);(.*)/); if (styleMatch) { bg = styleMatch[1]; otherCss = styleMatch[2]; } style = this.getHighlightStyle(this.curWordIndex, bg, otherCss); word.style = style; modifySpan.style = style; } let hideChange = false; let hideParentReg = /\$p{(.*?)}($|\$)/; let hideParentMatch = newWord.match(hideParentReg); if (hideParentMatch) { hideParent = parseInt(hideParentMatch[1]) || 0; hideChange = hideParent != word.hideParent; } else hideChange = typeof word.hideParent !== 'undefined'; if (hideChange) { [].forEach.call(document.querySelectorAll(".searchJumper-hide"), hide => { if (hide.dataset.content === word.showWords) { hide.classList.remove("searchJumper-hide"); hide.style.display = ""; hide.removeAttribute('data-content'); } }); } this.marks[word.showWords].forEach(mark => { if (mark) { mark.title = title; if (style) mark.style = style; if (hideChange && hideParent != -1) { let parentDepth = hideParent; let parent = mark.parentElement; while(parentDepth-- > 0 && parent) { parent = parent.parentElement; } if (parent) { parent.dataset.content = word.showWords; parent.classList.add("searchJumper-hide"); parent.innerHTML = createHTML(""); } } } }); if (hideParent == -1) { delete word.hideParent; } else word.hideParent = hideParent; this.lockWords = this.lockWords.replace(word.oriWord, newWord); word.oriWord = newWord; } } removeHighlightWord(word) { if (!this.lockWords) return; if (!this.splitSep) this.emptyInPageWords(); if (!word.oriWord) return; if (this.lockWords.indexOf(word.oriWord) === -1) return; let preStr = this.lockWords.match(/^\$(c.|o)/), findIndex, findNum = 0; preStr = preStr ? preStr[0] : ""; let targetArr = this.lockWords.replace(preStr, "").split(this.splitSep); findIndex = targetArr.indexOf(word.oriWord); if (this.wordModeBtn.classList.contains("checked")) { if (findIndex != -1) { targetArr.splice(findIndex, 1); findNum = 1; } for (let i = 0; i < targetArr.length; i++) { let wordArr = targetArr[i].split(/[ ]/); findIndex = wordArr.indexOf(word.oriWord); if (findIndex != -1) { findNum++; if (findNum == 1) { wordArr.splice(findIndex, 1); targetArr[i] = wordArr.join(" "); } else { break; } } } this.lockWords = preStr + targetArr.join(this.splitSep); } else { if (findIndex < 0) return; targetArr.splice(findIndex, 1); findNum = targetArr.indexOf(word.oriWord) != -1 ? 2 : 1; this.lockWords = preStr + targetArr.join(this.splitSep); } delete this.highlightSpans[word.showWords]; findIndex = this.curHighlightWords.indexOf(word); if (findIndex < 0) return; this.curHighlightWords.splice(findIndex, 1); this.searchJumperInPageInput.style.paddingLeft = this.searchInPageLockWords.clientWidth + 3 + "px"; if (findNum > 1) return; this.marks[word.showWords].forEach(mark => { if (mark.parentNode) { if (mark.dataset.block) { mark.parentNode && mark.parentNode.removeChild(mark); } else if (!/^MARK$/i.test(mark.nodeName)) { mark.classList.remove("searchJumper"); mark.style.cssText = mark.dataset.css || ""; delete mark.dataset.css; } else { let newNode = document.createTextNode(mark.firstChild.data); mark.parentNode.replaceChild(newNode, mark); newNode.parentNode.normalize(); } } }); delete this.marks[word.showWords]; let children = [].slice.call(this.navMarks.children); [].forEach.call(children, nav => { if (nav.dataset.content == word.showWords) { nav.parentNode.removeChild(nav); } }); } emptyInPageWords() { this.searchInPageLockWords.innerHTML = createHTML(); this.highlight(""); } focusHighlightByText(text, fw, span) { let curList = this.marks[text]; if (!curList || curList.length === 0) return; if (text != this.focusText) { this.focusIndex = 0; this.focusText = text; } else { if (fw) { if (this.focusIndex != curList.length - 1) { this.focusIndex = this.focusIndex + 1; } else this.focusIndex = 0; } else { if (this.focusIndex != 0) { this.focusIndex = this.focusIndex - 1; } else this.focusIndex = curList.length - 1; } } let newIndex = this.focusIndex; if (newIndex >= curList.length) newIndex = 0; if (fw) { while (!curList[newIndex].offsetParent || curList[newIndex].dataset.type) { if (newIndex != curList.length - 1) { newIndex = newIndex + 1; } else newIndex = 0; if (newIndex == this.focusIndex) break; } } else { while (!curList[newIndex].offsetParent || curList[newIndex].dataset.type) { if (newIndex != 0) { newIndex = newIndex - 1; } else newIndex = curList.length - 1; if (newIndex == this.focusIndex) break; } } this.focusIndex = newIndex; this.focusHighlight(curList[this.focusIndex]); this.setHighlightSpan(span, this.focusIndex, curList); } getRect(ele) { let eleBCR = ele.getBoundingClientRect(); let rect = { left: eleBCR.left, top: eleBCR.top, width: eleBCR.width, height: eleBCR.height }; let currentWindow = ele.ownerDocument && ele.ownerDocument.defaultView; let currentFrame = currentWindow && currentWindow.frameElement; while (currentFrame) { const frameRect = currentFrame.getBoundingClientRect(); rect.left += frameRect.left; rect.top += frameRect.top; currentWindow = currentWindow.parent; currentFrame = currentWindow.frameElement; } return rect; } focusHighlight(ele) { if (!ele) return; if (this.focusMark) this.focusMark.removeAttribute('data-current'); this.focusMark = ele; if (!this.wPosBar) { this.wPosBar = document.createElement("div"); this.hPosBar = document.createElement("div"); this.wPosBar.className = "searchJumperPosBar searchJumperPosW"; this.hPosBar.className = "searchJumperPosBar searchJumperPosH"; } if (!this.wPosBar.parentNode) { this.addToShadow(this.wPosBar); this.addToShadow(this.hPosBar); } let rect = this.getRect(ele); this.wPosBar.style.top = rect.top + document.documentElement.scrollTop + getBody(document).scrollTop + "px"; this.wPosBar.style.height = rect.height + "px"; this.hPosBar.style.left = rect.left + "px"; this.hPosBar.style.width = rect.width + "px"; this.wPosBar.style.animationName = ""; this.hPosBar.style.animationName = ""; let self = this; setTimeout(async () => { ele.scrollIntoView({behavior: "smooth", block: "center", inline: "nearest"}); ele.dataset.current = true; self.wPosBar.style.animationName = "fadeit"; self.hPosBar.style.animationName = "fadeit"; self.fixTimes = 0; let viewHeight = window.innerHeight || document.documentElement.clientHeight; function fixPosBar() { if (self.focusMark != ele) return; let rect = self.getRect(ele); self.wPosBar.style.top = rect.top + document.documentElement.scrollTop + getBody(document).scrollTop + "px"; self.hPosBar.style.left = rect.left + "px"; if (rect.top > viewHeight / 3 && rect.top < viewHeight / 3 * 2) return; if (++self.fixTimes == 5) { ele.scrollIntoView({behavior: "smooth", block: "center", inline: "nearest"}); } else if (self.fixTimes > 10) { ele.scrollIntoView({behavior: "smooth", block: "center", inline: "nearest"}); self.wPosBar.style.animationName = ""; self.hPosBar.style.animationName = ""; return; } setTimeout(() => { fixPosBar(); }, 200); } fixPosBar(); }, 0); } getHighlightSpanByText(text) { return this.highlightSpans[text]; } setHighlightSpan(span, index, list) { if (!span) return; let numEle = span.querySelector("em"); if (!numEle) { numEle = document.createElement("em"); span.insertBefore(numEle, span.firstChild); } index++; let len = 0; if (list && list.length) { len = 0; list.forEach(e => { if (!e.dataset.type) len++; }); } numEle.innerHTML = createHTML("[" + index + "/" + len + "]"); } getHighlightStyle(index, background, addCssText) { if (!background && !addCssText) { let setCss = searchData.prefConfig.inPageWordsStyles[index]; if (setCss) return setCss; } addCssText = addCssText || ""; function geneRandomColor() { let r, g, b; r = Math.floor(256 * Math.random()); g = Math.floor(256 * Math.random()); b = Math.floor(256 * Math.random()); r = r.toString(16); if (r.length === 1) r = "0" + r; g = g.toString(16); if (g.length === 1) g = "0" + g; b = b.toString(16); if (b.length === 1) b = "0" + b; return "#" + r + g + b; } function getWordColor(bg) { if (bg.indexOf("#") !== 0) return ""; if (bg === "#ffff00") return "black"; bg = bg.substr(1); let r, g, b; r = parseInt(bg.substr(0, 2), 16); g = parseInt(bg.substr(2, 2), 16); b = parseInt(bg.substr(4, 2), 16); let bgBrightness = r * 0.299 + g * 0.587 + b * 0.114; r = 255 - r; g = 255 - g; b = 255 - b; let wordBrightness = r * 0.299 + g * 0.587 + b * 0.114; let diff = Math.abs(wordBrightness - bgBrightness); if (diff <= 128) { if (bgBrightness > 158) { return "#000000"; } else { return "#FFFFFF"; } } r = r.toString(16); if (r.length === 1) r = "0" + r; g = g.toString(16); if (g.length === 1) g = "0" + g; b = b.toString(16); if (b.length === 1) b = "0" + b; return "#" + r + g + b; } if (!background) { background = searchData.prefConfig.firstFiveWordsColor[index]; } if (!background) { switch (index) { case 0: background = "#ffff00"; break; case 1: background = "#e91e63"; break; case 2: background = "#00bcd4"; break; case 3: background = "#008000"; break; case 4: background = "#800080"; break; default: background = geneRandomColor(); break; } } if (background) { let color = getWordColor(background); if (color) color = "color:" + color + "!important;"; background = `background:${background}!important;${color}`; } return `${background}${addCssText}`; } createNavMark(node, word, index, curList, scrollHeight) { let self = this; let navMark = document.createElement("span"); let top = getElementTop(node, self.targetIframe); navMark.title = word.title || word.showWords; navMark.dataset.top = top; navMark.dataset.content = word.showWords; navMark.style.top = top / scrollHeight * 100 + "%"; navMark.style.background = node.style.background || "yellow"; navMark.addEventListener("click", e => { e.stopPropagation(); e.preventDefault(); self.focusIndex = index; self.focusHighlight(node); self.setHighlightSpan(self.getHighlightSpanByText(word.showWords), index, curList); self.navPointer.style.display = ""; self.navPointer.style.top = navMark.offsetTop + 33 + "px"; return false; }, true); self.navMarks.appendChild(navMark); } anylizeDomWithTextPos(dom, result) { if (!result) result = {text: "", data:{}}; if (!dom || !dom.childNodes || !dom.childNodes.length || (dom.nodeType == 1 && !dom.offsetParent && !dom.offsetHeight)) { return result; } dom.childNodes.forEach(ele => { if ((ele.classList && ele.classList.contains("searchJumper")) || /^(img|svg|picture|br|hr|textarea)$/i.test(ele.nodeName)) { const start = result.text.length; result.text += "\n"; result.data[start] = {node: ele, text: "\n"}; } else if (ele.offsetParent || ele.offsetHeight) { if (/^(div|h\d|p|form|ul|li|ol|dl|address|menu|table|fieldset|td)$/i.test(ele.nodeName)) { let start = result.text.length; result.text += "\n"; result.data[start] = {node: {}, text: "\n"}; result = this.anylizeDomWithTextPos(ele, result); start = result.text.length; result.text += "\n"; result.data[start] = {node: {}, text: "\n"}; } else { result = this.anylizeDomWithTextPos(ele, result); } } else if (ele.nodeType === 3) { let textData; if (ele.parentNode.nodeType == 1 && ele.parentNode.childNodes.length == 1) { textData = ele.parentNode.innerText || ele.data; } else { textData = ele.data; } if (!textData || !textData.trim()) return; const start = result.text.length; result.text += textData; result.data[result.text.length - 1] = {node: ele, text: textData}; } }); return result; } highlightPopup(spannode, word) { let self = this; let targetShowTipsSite; let mouseMoveHandler = e => { if (targetShowTipsSite) { self.clingPos(spannode, self.tips); } }; spannode.addEventListener("mouseenter", e => { spannode.addEventListener("mousemove", mouseMoveHandler); if (targetElement != spannode || !self.funcKeyCall) { targetShowTipsSite = null; targetElement = spannode; if (word.showTips) { if (/^\d+$/.test(word.showTips)) { let firstType = self.autoGetFirstType(); let targetSites = firstType.querySelectorAll('a.search-jumper-btn[data-show-tips]:not(.notmatch)'); let index = parseInt(word.showTips) - 1; targetShowTipsSite = targetSites[index]; } else { targetShowTipsSite = self.getTargetSitesByName([word.showTips])[0]; } } self.setFuncKeyCall(true); if (targetShowTipsSite) { self.bar.style.setProperty("display", "none", "important"); targetShowTipsSite.dispatchEvent(new CustomEvent('showTips')); } else { self.showInPage(true, e); } } }); spannode.addEventListener("mouseleave", e => { spannode.removeEventListener("mousemove", mouseMoveHandler); }); } createHighlightMark(word, index, curList) { let self = this; let spannode = document.createElement("mark"); spannode.className = "searchJumper"; if (word.title) spannode.title = JSON.parse('"' + word.title + '"'); if (word.popup) { this.highlightPopup(spannode, word); } spannode.style.cssText = word.style; spannode.addEventListener("click", e => { if (!e.altKey) return; e.stopPropagation(); e.preventDefault(); return false; }); spannode.dataset.content = word.showWords; spannode.addEventListener("mousedown", e => { if (!e.altKey) return; let target; let newIndex = index; while (!target || target.dataset.type) { if (e.button === 0) { if (newIndex != curList.length - 1) { newIndex++; self.focusIndex = newIndex; } else self.focusIndex = 0; } else if (e.button === 2){ if (newIndex != 0) { newIndex--; self.focusIndex = newIndex; } else self.focusIndex = curList.length - 1; } target = curList[self.focusIndex]; if (newIndex == index) break; } self.focusHighlight(target); self.setHighlightSpan(self.getHighlightSpanByText(word.showWords), self.focusIndex, curList); self.focusText = word.showWords; }); return spannode; } createAddonSpan(name, data) { let index = "addon_" + this.addonsList.children.length, self = this; let con = document.createElement("div"); let checkbox = document.createElement("input"); checkbox.type = 'checkbox'; checkbox.id = index; checkbox.checked = !data.disable; checkbox.addEventListener("change", e => { searchData.prefConfig.disableAddon[name] = !checkbox.checked; data.disable = !checkbox.checked; if (checkbox.checked) { self.findInpageAddons.forEach(addon => { if (addon != data && addon.sort == data.sort) { addon.disable = true; let _name = addon.name || ("addon" + index++); self.addonCheckboxDict[_name].checked = false; searchData.prefConfig.disableAddon[_name] = true; } }); } storage.setItem("searchData", searchData); if (self.lockWords) { self.refreshPageWords(self.lockWords); } }); con.appendChild(checkbox); con.title = data.title || ""; let label = document.createElement("label"); label.setAttribute("for", index); label.innerText = name; con.appendChild(label); this.addonCheckboxDict[name] = checkbox; this.addonsList.appendChild(con); } findAccentedWord(text, searchWord, normalizeArray) { const searchLength = searchWord.length; let normalizedIndex = 0; let startIndex = -1; for (let i = 0; i < text.length; i++) { const normalized = normalizeArray[i]; if (normalized === "") { continue; } if (normalized === searchWord[normalizedIndex]) { if (normalizedIndex === 0) startIndex = i; normalizedIndex++; if (normalizedIndex === searchLength) { return { pos: startIndex, len: i - startIndex + 1 }; } } else { normalizedIndex = 0; startIndex = -1; if (normalized === searchWord[0]) { startIndex = i; normalizedIndex = 1; } } } startIndex = text.indexOf(searchWord); return {len: searchWord.length, pos: startIndex}; } findPosInStr(content, kw, contentUp, wordUp, normalizeArray) { if (!content) { return {len: 0, pos: -1}; } let len = 0, pos = -1, hasAddon = false; if (this.findInpageAddons.length) { for (let i = 0; i < this.findInpageAddons.length; i++) { let curAddon = this.findInpageAddons[i]; if (!curAddon || !curAddon.run || curAddon.disable) continue; hasAddon = true; let curData = curAddon.run(content, kw); if (curData && curData.matched) { len = curData.len; pos = curData.pos; break; } } } if (pos == -1 && !hasAddon) { return this.findAccentedWord(contentUp, wordUp, normalizeArray); } return {len: len, pos: pos}; } highlight(words, ele, root, iframe) { if (!words && (!this.curHighlightWords || this.curHighlightWords.length === 0)) return; if (!ele) { this.highlight(words, getBody(document), root); return; } [].forEach.call(ele.getElementsByTagName("iframe"), iframe => { if (!iframe.offsetParent) return; if (iframe.offsetHeight < 100 || iframe.offsetWidth < 100) return; let iframeDoc; try { iframeDoc = iframe.contentDocument || iframe.contentWindow.document; } catch(e) { return; } if (iframeDoc && getBody(iframeDoc)) { this.highlight(words, getBody(iframeDoc), root, iframe); } }); this.targetIframe = iframe || false; if (ele.id == "searchJumperModifyWord") return; ele = ele || getBody(document); let inWordMode = this.wordModeBtn.classList.contains("checked"); let preEles = []; let searchingPre = false; let self = this; if (words === "") { this.highlightSpans = {}; Object.values(this.marks).forEach(async markList => { if (!markList) return; let normalizeSet = new Set(); for (let mark of markList) { if (!mark.parentNode) continue; if (mark.dataset.block) { mark.parentNode && mark.parentNode.removeChild(mark); } else if (!/^MARK$/i.test(mark.nodeName)) { mark.classList.remove("searchJumper"); mark.style.cssText = mark.dataset.css || ""; delete mark.dataset.css; } else { let newNode = document.createTextNode(mark.firstChild.data); mark.parentNode.replaceChild(newNode, mark); normalizeSet.add(newNode.parentNode); } } normalizeSet.forEach(node => {node.normalize();}); }); [].forEach.call(ele.querySelectorAll(".searchJumper-hide"), hide => { hide.classList.remove("searchJumper-hide"); hide.style.display = ""; hide.removeAttribute('data-content'); }); this.navMarks.innerHTML = createHTML(); this.marks = {}; this.curHighlightWords = []; return; } if (!this.inPageStyle) { this.inPageStyle = _GM_addStyle(this.inPageCss); } if (!this.inPageStyle.parentNode) { document.head.appendChild(this.inPageStyle); } let insert = (words === "insert"); if (insert) { words = this.curHighlightWords; this.refreshNavMarks(); } else { this.curHighlightWords = (this.curHighlightWords || []).concat(words); } this.fakeTextareas = new Map(); let scrollHeight = Math.max(document.documentElement.scrollHeight, getBody(document).scrollHeight); this.navMarks.style.display = "none"; let navMarkParams = []; function searchWithinNode(node, word, start) { let len, pos = -1, skip, spannode, middlebit, middleclone; skip = 0; let pa = node.parentNode; if (node.nodeType == 1 && node.className && node.className.indexOf && node.className.indexOf("searchJumper") != -1) return 0; if (start && (node.nodeType == 1 || node.nodeType == 11)) { let domTextResult = self.anylizeDomWithTextPos(node); let textRes = domTextResult.text; let textResUp = textRes.toUpperCase(); let normalizeArray = []; for (let i = 0; i < textResUp.length; i++) { const normalized = textResUp[i].normalize("NFD").replace(/[\u0300-\u036f]/g, ""); normalizeArray.push(normalized); } let wordUp = word.content.toUpperCase(); let dataRes = domTextResult.data; let index = 0; let nodeAndPos = []; let validWord = (word.init || inWordMode) && /^[a-z]+$/i.test(word.content); function getNodePos(pos, len, matchedText) { let keys = Object.keys(domTextResult.data); let findNodes = [], leftLen = len; let pre = "", after = "", after2 = ""; for (let i = 0; i < keys.length; i++) { let end = parseInt(keys[i]); let curnode = domTextResult.data[end]; if (pos > end) continue; let curpos = pos - (end - curnode.text.length) - 1; let type = "full"; if (curpos < 0) { if (curnode.text.length < leftLen) { type = "middle"; } else { type = "end"; } } else { if (curnode.text.length - curpos < leftLen) { type = "start"; } } if (type === "full") matchedText = ""; if (validWord) { if (type == "full") { pre = curpos == 0 ? "\n" : curnode.text[curpos - 1]; after = (curpos + leftLen) == curnode.text.length ? "\n" : curnode.text[curpos + leftLen]; if (after !== "\n") { after2 = (curpos + leftLen + 1) == curnode.text.length ? "\n" : curnode.text[curpos + leftLen + 1]; } } else if (type == "start" && !pre) { pre = curpos == 0 ? "\n" : curnode.text[curpos - 1]; } else if ((type == "end" || type == "full") && !after) { after = (curpos + leftLen) == curnode.text.length ? "\n" : curnode.text[curpos + leftLen]; if (after !== "\n") { after2 = (curpos + leftLen + 1) == curnode.text.length ? "\n" : curnode.text[curpos + leftLen + 1]; } } if (pre && after) { if (/[a-z]/i.test(pre) || /[a-rt-z]/i.test(after) || (after.toLowerCase() == 's' && /[a-z]/i.test(after2))) { break; } } } if (curpos < 0) curpos = 0; let curlen = Math.min(leftLen, curnode.text.length - curpos); leftLen -= curlen; if (!curnode.text.trim()) { if (type === "start") pos += curnode.text.length; continue; } let nodeInfo; for (let j = 0; j < nodeAndPos.length; j++) { if (nodeAndPos[j].node == curnode.node) { nodeInfo = nodeAndPos[j]; break; } } if (!nodeInfo) nodeAndPos.push({node: curnode.node, text: curnode.text, match:[{pos: curpos, len: curlen, type: type, matched: matchedText}]}); else nodeInfo.match.push({pos: curpos, len: curlen, type: type, matched: matchedText}); if (leftLen <= 0) break; } } function getIndex() { pos = -1; if (word.isRe) { let wordMatch = textRes.match(new RegExp(word.content, word.reCase)); if (wordMatch) { let content = wordMatch[0]; len = content.length; pos = wordMatch.index; } } else { let result = self.findPosInStr(textRes, word.content, textResUp, wordUp, normalizeArray); len = result.len; pos = result.pos; } if (pos > -1) { let matchedText = textRes.slice(pos, pos + len); textRes = textRes.slice(pos + len); textResUp = textResUp.slice(pos + len); normalizeArray = normalizeArray.slice(pos + len); pos += index; index = pos + len; getNodePos(pos, len, matchedText); getIndex(); } } getIndex(); if (nodeAndPos.length) { nodeAndPos.forEach(data => { if (typeof word.hideParent !== 'undefined') { let parentDepth = word.hideParent; let parent = data.node.parentElement; while(parentDepth-- > 0 && parent) { parent = parent.parentElement; } if (parent && parent.classList && !parent.classList.contains("searchJumper-hide")) { parent.innerHTML = createHTML(""); parent.dataset.content = word.showWords; parent.classList.add("searchJumper-hide"); } } else { let curList = self.marks[word.showWords]; let index = curList.length; let spannode; let newTextNodeCon; let parentDisplay = ""; if (data.node.parentNode.nodeType == 1) { let parentStyle = getComputedStyle(data.node.parentNode); parentDisplay = parentStyle.display; } if (parentDisplay.indexOf("flex") != -1 || parentDisplay.indexOf("grid") != -1 || parentDisplay.indexOf("layer") != -1) { newTextNodeCon = document.createElement("span"); newTextNodeCon.style.all = "unset"; } else { newTextNodeCon = document.createDocumentFragment(); } let newTextNode = document.createTextNode(data.text); newTextNodeCon.appendChild(newTextNode); let matches = data.match.reverse(); let spannodes = []; matches.forEach(d => { spannode = self.createHighlightMark(word, index, curList); switch (d.type) { case "start": spannode.style.borderTopRightRadius = 0; spannode.style.borderBottomRightRadius = 0; break; case "middle": spannode.style.borderRadius = 0; break; case "end": spannode.style.borderTopLeftRadius = 0; spannode.style.borderBottomLeftRadius = 0; break; default: break; } middlebit = newTextNode.splitText(d.pos); if (d.type != 'start' && d.type != 'middle' && middlebit.data.length) { middlebit.splitText(d.len); } middleclone = middlebit.cloneNode(true); spannode.appendChild(middleclone); if (d.type != "full" && d.type != "start") { spannode.dataset.type = d.type; } if (d.matched) { spannode.dataset.matched = d.matched; } newTextNodeCon.replaceChild(spannode, middlebit); spannodes.unshift(spannode); }); data.node.parentNode.replaceChild(newTextNodeCon, data.node); self.marks[word.showWords].push(...spannodes); spannodes.forEach(n => { if (!n.dataset.type) { navMarkParams.push([n, word, index, curList, scrollHeight]); } }); } }); } } let checkChildren = true; if (word.link) { if (node.nodeType == 1 && node.href && node.href.match) { checkChildren = false; let wordMatch = node.href.match(new RegExp(word.content, word.reCase)); if (wordMatch) { if (typeof word.hideParent !== 'undefined') { let parentDepth = word.hideParent; let parent = node; while(parentDepth-- > 0 && parent) { parent = parent.parentElement; } if (parent) { parent.innerHTML = createHTML(""); parent.dataset.content = word.showWords; parent.classList.add("searchJumper-hide"); return 0; } } else { let curList = self.marks[word.showWords]; let index = curList.length; node.classList.add("searchJumper"); if (word.title) node.title = JSON.parse('"' + word.title + '"'); if (word.popup) { self.highlightPopup(node, word); } if (!node.dataset.css) node.dataset.css = node.style.cssText; if (word.style) { node.style.cssText += word.style; } node.addEventListener("click", e => { if (!e.altKey) return; e.stopPropagation(); e.preventDefault(); return false; }); node.dataset.content = word.showWords; node.addEventListener("mousedown", e => { if (!e.altKey) return; let target; if (e.button === 0) { if (index != curList.length - 1) { self.focusIndex = index + 1; } else self.focusIndex = 0; } else if (e.button === 2){ if (index != 0) { self.focusIndex = index - 1; } else self.focusIndex = curList.length - 1; } target = curList[self.focusIndex]; self.focusHighlight(target); self.setHighlightSpan(self.getHighlightSpanByText(word.showWords), self.focusIndex, curList); self.focusText = word.showWords; }); self.marks[word.showWords].push(node); navMarkParams.push([node, word, index, curList, scrollHeight]); } } } } else { let blockValue = ""; if (node.nodeType == 1 && node.value && (node.offsetParent || node.offsetHeight) && !word.init && /^(button|select|input|textarea)$/i.test(node.nodeName) && !/^(hidden|file|password|radio|range|checkbox|image)$/i.test(node.type)) { blockValue = node.value; } if (blockValue) { checkChildren = false; let wordMatch = false; let lastIndex = 0; let fakeTextarea = self.fakeTextareas.get(node); if (insert && fakeTextarea) return 0; let nodeStyle = getComputedStyle(node); let baseLeft = node.offsetLeft;//textareaLoc.left - textareaParentLoc.left; let baseTop = node.offsetTop//textareaLoc.top - textareaParentLoc.top; let blockValueUp = blockValue.toUpperCase(); let normalizeArray = []; for (let i = 0; i < blockValueUp.length; i++) { const normalized = blockValueUp[i].normalize("NFD").replace(/[\u0300-\u036f]/g, ""); normalizeArray.push(normalized); } let wordUp = word.content.toUpperCase(); while (true) { if (word.isRe) { wordMatch = blockValue.match(new RegExp(word.content, word.reCase)); if (wordMatch) { pos = wordMatch.index; wordMatch = wordMatch[0]; } } else { let result = self.findPosInStr(blockValue, word.content, blockValueUp, wordUp, normalizeArray); len = result.len; pos = result.pos; if ((word.init || inWordMode) && pos >= 0 && /^[a-z]+$/i.test(word.content)) { if (pos !== 0 && /[a-z]/i.test(blockValue[pos - 1])) { pos = -1; } if (pos + word.content.length !== blockValue.length && /[a-z]/i.test(blockValue[pos + len])) { pos = -1; } } wordMatch = (pos >= 0 ? blockValue.slice(pos, pos + len) : false); } if (wordMatch) { findTextInBlock(wordMatch, lastIndex + pos); lastIndex += (pos + wordMatch.length); blockValue = blockValue.slice(pos + wordMatch.length); blockValueUp = blockValueUp.slice(pos + wordMatch.length); normalizeArray = normalizeArray.slice(pos + wordMatch.length); } else break; } function findTextInBlock(curWord, pos) { if (curWord) { if (!fakeTextarea) { fakeTextarea = document.createElement("pre"); fakeTextarea.className = "searchJumper"; let textNode = document.createTextNode(blockValue); fakeTextarea.appendChild(textNode); let name, rstyle =/^(number|string)$/; let cssText = [], sStyle = node.style; for (name in sStyle) { if (!/^(content|outline|outlineWidth)$/.test(name)) { let val = nodeStyle[name]; if (val !=='' && rstyle.test(typeof val)) { name = name.replace(/([A-Z])/g, "-$1").toLowerCase(); cssText.push(name); cssText.push(':'); cssText.push(val); cssText.push(';'); }; }; }; cssText = cssText.join(''); fakeTextarea.style.cssText = cssText; fakeTextarea.style.position = "fixed"; fakeTextarea.style.left = "0px"; fakeTextarea.style.top = "0px"; fakeTextarea.style.margin = "0"; if (node.nodeName && node.nodeName.toLowerCase && node.nodeName.toLowerCase() !== "textarea") { fakeTextarea.style.display = "inline-grid"; fakeTextarea.style.lineHeight = fakeTextarea.style.height; if (fakeTextarea.style.boxSizing == "border-box") fakeTextarea.style.paddingTop = 0; } self.fakeTextareas.set(node, fakeTextarea); } document.body.appendChild(fakeTextarea); let range = document.createRange(); range.setStart(fakeTextarea.firstChild, Math.min(fakeTextarea.firstChild.length, pos)); range.setEnd(fakeTextarea.firstChild, Math.min(fakeTextarea.firstChild.length, pos + 1)); let rect = range.getBoundingClientRect(); document.body.removeChild(fakeTextarea); if (typeof word.hideParent !== 'undefined') { let parentDepth = word.hideParent; let parent = node.parentElement; while(parentDepth-- > 0 && parent) { parent = parent.parentElement; } if (parent) { parent.innerHTML = createHTML(""); parent.dataset.content = word.showWords; parent.classList.add("searchJumper-hide"); return 0; } } else { let curList = self.marks[word.showWords]; let index = curList.length; let spannode = document.createElement("mark"); spannode.className = "searchJumper"; spannode.dataset.block = true; if (word.title) spannode.title = JSON.parse('"' + word.title + '"'); spannode.style.cssText = word.style; spannode.dataset.content = word.showWords; spannode.innerText = curWord; spannode.style.padding = "0"; spannode.style.position = "absolute"; spannode.style.fontSize = fakeTextarea.style.fontSize; spannode.style.fontFamily = fakeTextarea.style.fontFamily; spannode.style.lineHeight = "1"; spannode.style.pointerEvents = "none"; node.parentNode.appendChild(spannode); let _baseLeft = rect.left + baseLeft; let _baseTop = rect.top + baseTop; spannode.style.left = _baseLeft + "px"; spannode.style.top = _baseTop + "px"; self.marks[word.showWords].push(spannode); navMarkParams.push([spannode, word, index, curList, scrollHeight]); if (node.nodeName && node.nodeName.toLowerCase && node.nodeName.toLowerCase() == "textarea") { let nodeScrollHandler = e => { if (!spannode.parentNode) { spannode.parentNode.removeChild(spannode); node.removeEventListener("scroll", nodeScrollHandler); } else { spannode.style.left = _baseLeft - node.scrollLeft + "px"; spannode.style.top = _baseTop - node.scrollTop + "px"; } } node.addEventListener("scroll", nodeScrollHandler); } } } } } } if (checkChildren && (!root || node === ele ) && (node.nodeType == 1 || node.nodeType == 11 ) && node.childNodes && !/^(SCRIPT|STYLE|MARK|SVG|TEXTAREA)$/i.test(node.nodeName) && (!word.init || (node.ariaHidden != 'true' && node.role != "search" && (!node.hasAttribute || node.hasAttribute('jsname') == false ) ) ) ) { if (!searchingPre && /^(PRE|CODE)$/i.test(node.nodeName)) { preEles.push(node); } else { for (var child = 0; child < node.childNodes.length; ++child) { child = child + searchWithinNode(node.childNodes[child], word); } try { if (node.shadowRoot) { child = child + searchWithinNode(node.shadowRoot, word, true); } } catch(e) { debug(e); } } } return skip; } words.forEach(w => { if (!self.marks[w.showWords]) { self.marks[w.showWords] = []; } if (w.inRange) { let searchEle = ele; if (ele.parentNode) searchEle = ele.parentNode; [].forEach.call(searchEle.querySelectorAll(w.inRange), e => { if (e == ele || ele.contains(e)) { searchWithinNode(e, w, true); } }) } else searchWithinNode(ele, w, true); }); navMarkParams.forEach(param => { self.createNavMark(...param); }); this.navMarks.style.display = ""; setTimeout(() => { self.navMarks.style.display = "none"; navMarkParams = []; searchingPre = true; words.forEach(w => { if (!self.marks[w.showWords]) { self.marks[w.showWords] = []; } preEles.forEach(e => { searchWithinNode(e, w, true); }); }); navMarkParams.forEach(param => { self.createNavMark(...param); }); self.navMarks.style.display = ""; }, 1000); if (this.navMarks.innerHTML != "") { this.searchJumperNavBar.classList.add("sjNavShow"); if (navEnable) { this.appendBar(); this.con.style.display = ""; this.setNav(true, true); } } } refreshPageWords(newWords) { this.lockWords = ""; this.searchJumperInPageInput.value = ""; this.searchInPageLockWords.innerHTML = createHTML(); this.searchJumperInPageInput.style.paddingLeft = ""; this.submitInPageWords(); let words = newWords || globalInPageWords; if (words) { this.searchJumperInPageInput.value = words; this.submitInPageWords(words == this.lastSearchEngineWords); this.appendBar(); } } refreshNav() { this.setNav(navEnable); } refreshNavMarks() { if (this.refreshNavMarksTimer) clearTimeout(this.refreshNavMarksTimer); this.refreshNavMarksTimer = setTimeout(() => { let scrollHeight = Math.max(document.documentElement.scrollHeight, getBody(document).scrollHeight); this.navPointer.style.display = "none"; this.navMarks.style.display = "none"; [].forEach.call(this.navMarks.children, m => { m.style.top = m.dataset.top / scrollHeight * 100 + "%"; }); this.navMarks.style.display = ""; }, 1000); } checkCharacterData(target) { setTimeout(() => { this.highlight("insert", target, true); }, 0); } removeMark(removedNode) { let content = removedNode.dataset.content; let markList = this.marks[content]; if (!markList) return; var index = markList.indexOf(removedNode); if (index === -1) return; markList.splice(index, 1); this.marks[content] = markList; let navMark = this.navMarks.querySelectorAll(`span[data-content="${content}"]`)[index]; if (navMark) this.navMarks.removeChild(navMark); } submitIgnoreSpace(value) { if (!value) return; if (!this.lockWords && value.indexOf("$c") !== 0 && value.indexOf("$o") !== 0 && value.indexOf(" ") !== -1) { this.splitSep = "◎"; } this.searchJumperInPageInput.value = value; this.submitInPageWords(); } siteBtnReturnHome(btn) { if (btn.parentNode) btn.parentNode.removeChild(btn); /*for (let i = 0; i < searchTypes.length; i++) { let typeBtn = searchTypes[i]; if (typeBtn.dataset.type == btn.dataset.type) { if (btn.dataset.id) { let curIndex = parseInt(btn.dataset.id); for (let j = 1; j < typeBtn.children.length; j++) { let targetIndex = parseInt(typeBtn.children[j].dataset.id); if (isNaN(targetIndex) || curIndex < targetIndex) { typeBtn.insertBefore(btn, typeBtn.children[j]); break; } else if (j == typeBtn.children.length - 1) { typeBtn.appendChild(btn); break; } } //typeBtn.insertBefore(btn, typeBtn.children[parseInt(btn.dataset.id) - parseInt(typeBtn.dataset.id) + 1]); } else typeBtn.insertBefore(btn, typeBtn.children[1]); break; } }*/ } closeShowAll() { if (!this.con.classList.contains("search-jumper-showall") || isAllPage) return; this.clearInputHide(); clearInterval(this.showAllTimeTimer); document.removeEventListener("mousedown", self.showAllMouseHandler); document.removeEventListener("keydown", self.showAllKeydownHandler); this.con.classList.remove("search-jumper-showall"); document.documentElement.style.scrollbarWidth = this.preScrollbarWidth; this.searchJumperInputKeyWords.value = ""; this.historylist.innerHTML = createHTML(); /*this.historySiteBtns.slice(0, 10).forEach(btn => { this.siteBtnReturnHome(btn); });*/ this.touched = false; this.initPos(); if (this.funcKeyCall) { this.setFuncKeyCall(false); } if (!searchData.prefConfig.disableAutoOpen && !searchData.prefConfig.disableTypeOpen) { let firstType = this.bar.querySelector('.search-jumper-type:nth-child(1)>span'); if (firstType && !firstType.classList.contains("search-jumper-open")) { if (firstType.onmousedown) { firstType.onmousedown(); } else { let mouseEvent = new PointerEvent("mousedown"); firstType.dispatchEvent(mouseEvent); } } } this.bar.style.display = ''; } toggleShowAll() { this.appendBar(); if (!this.con || !this.con.parentNode) return; if (this.con.classList.contains("search-jumper-showall")) { this.closeShowAll(); } else { this.showAllSites(); } } showAllSites() { if (!this.con || !this.con.parentNode || this.con.classList.contains("search-jumper-showall")) return; this.con.style.display = ""; this.clearInputHide(); this.alllist.appendChild(this.filterSites); this.filterGlob.innerHTML = createHTML(); let self = this; this.setFuncKeyCall(false); this.hideSearchInput(); this.con.classList.add("search-jumper-showall"); this.preScrollbarWidth = document.documentElement.style.scrollbarWidth || ""; document.documentElement.style.scrollbarWidth = "none"; clearInterval(this.showAllTimeTimer); const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; if (window.innerWidth < 1000) { self.timeInAll.style.fontSize = "15px"; self.dayInAll.style.fontSize = "15px"; } else { self.timeInAll.style.fontSize = ""; self.dayInAll.style.fontSize = ""; } let now = new Date(); let year = now.getFullYear(), month = now.getMonth(), date = now.getDate(); let dayLabelStr = i18n(days[now.getDay()]) + "<br/>" + year + '-' + (++month < 10 ? '0' + month : month) + '-' + (date < 10 ? '0' + date : date); if (lang.indexOf("zh") == 0) { let lunar = sloarToLunar(year, month, date); if (lunar) { let lunarStr = `${lunar.lunarYear}年${lunar.lunarMonth}月${lunar.lunarDay}`; dayLabelStr = dayLabelStr + "<br/>" + lunarStr; } } self.dayInAll.innerHTML = createHTML(dayLabelStr); let setTimeLabel = () => { let now = new Date(); let hour = now.getHours(), minute = now.getMinutes(), seconds = now.getSeconds(); self.timeInAll.innerText = (hour < 10 ? '0' + hour : hour) + ':' + (minute < 10 ? '0' + minute : minute) + ':' + (seconds < 10 ? '0' + seconds : seconds); }; this.showAllTimeTimer = setInterval(setTimeLabel, 1000); setTimeLabel(); searchTypes.forEach(type => { if (type.style.display != 'none') { let sitelist = type.querySelector('.sitelist'); if (sitelist) { self.sitelistBox.appendChild(sitelist); self.initList(sitelist); } } }); this.historySiteBtns.slice(0, 20).forEach(btn => { let siteImg = btn.querySelector('img'); if (siteImg && siteImg.dataset.src) { siteImg.src = siteImg.dataset.src; delete siteImg.dataset.src; } self.historylist.appendChild(btn); }); let targetKw = ""; if (targetElement && (targetElement.nodeName.toUpperCase() == 'A' || (targetElement.parentNode && targetElement.parentNode.nodeName.toUpperCase() == 'A'))) { targetKw = targetElement.textContent.trim(); } let kw = getKeywords() || targetKw || cacheKeywords; this.searchJumperInputKeyWords.value = kw; setTimeout(() => { if (!self.showAllMouseHandler) { self.showAllMouseHandler = e => { if (e.isTrusted == false || e.target.className === 'sitelistBox' || e.target.className === 'search-jumper-showallBg') { self.closeShowAll(); } }; } self.con.addEventListener("mousedown", self.showAllMouseHandler); if (!self.showAllKeydownHandler) { self.showAllKeydownHandler = e => { if (e.keyCode == 27) { self.closeShowAll(); } }; } document.addEventListener("keydown", self.showAllKeydownHandler, true); if (this.searchJumperInputKeyWords.value) { this.searchJumperInputKeyWords.focus(); this.searchJumperInputKeyWords.select(); } }, 0); } switchSite(next) { if (!currentSite || this.bar.style.display == "none") return; let siteEle = this.con.querySelector(".search-jumper-btn.current"); if (next) { siteEle = siteEle.nextElementSibling; while(siteEle) { if (!siteEle.classList.contains("notmatch") && siteEle.style.display != "none" && siteEle.dataset.current != "true" && siteEle.dataset.isPage == "true") { break; } siteEle = siteEle.nextElementSibling; } } else { siteEle = siteEle.previousElementSibling; while(siteEle) { if (!siteEle.classList.contains("notmatch") && siteEle.style.display != "none" && siteEle.dataset.current != "true" && siteEle.dataset.isPage == "true") { break; } siteEle = siteEle.previousElementSibling; } } if (siteEle) { this.openSiteBtn(siteEle, "_self"); } } clearInputHide() { searchTypes.forEach(type => { type.classList.remove("input-hide"); }); this.allSiteBtns.forEach(btn => { btn[0].classList.remove("input-hide"); }); this.allListBtns.forEach(listItem => { listItem.classList.remove("input-hide"); }); this.allLists.forEach(listCon => { listCon.classList.remove("input-hide"); }); } showSearchInput() { if (this.con && this.con.classList.contains("search-jumper-showall")) return; this.recoveHistory(); this.con.classList.add("in-input"); this.searchInput.value = ""; this.contentContainer.appendChild(this.filterSites); let selStr = getSelectStr(); if (selStr) { this.searchJumperInputKeyWords.value = selStr; } if (this.filterSitesTab.checked) { this.con.classList.remove("in-find"); if (searchData.prefConfig.defaultPicker) { this.togglePicker(); } if (!this.searchJumperInputKeyWords.value) { this.searchJumperInputKeyWords.value = getKeywords() || cacheKeywords; } let firstType = this.bar.querySelector('.search-jumper-needInPage:not(.notmatch)>span'); if (firstType && !firstType.parentNode.classList.contains('search-jumper-open')) { if (firstType.onmousedown) { firstType.onmousedown(); } else { let mouseEvent = new PointerEvent("mousedown"); firstType.dispatchEvent(mouseEvent); } } if (cacheFilter) { this.searchInput.value = cacheFilter; this.searchInput.dispatchEvent(new Event("input")); } this.searchJumperInputKeyWords.focus(); this.searchJumperInputKeyWords.select(); } else if (this.searchInPageTab.checked) { this.con.classList.add("in-find"); this.searchJumperInPageInput.focus(); setTimeout(() => { if (selStr && this.lockWords.indexOf(selStr) == -1) { this.searchJumperInPageInput.value = ""; if (!this.navMarks.innerHTML) { this.submitIgnoreSpace(selStr); } else { this.searchJumperInPageInput.value = selStr; this.submitInPageWords(); } } else if (this.searchJumperInPageInput.value) { this.submitInPageWords(); } else if (!this.initShowSearchInput && cacheKeywords && this.lockWords !== cacheKeywords) { this.searchJumperInPageInput.value = cacheKeywords; this.initShowSearchInput = true; this.searchJumperInPageInput.select(); } }, 10); } this.inInput = true; this.clearInputHide(); if (this.lockWords) this.searchJumperInPageInput.style.paddingLeft = this.searchInPageLockWords.clientWidth + 3 + "px"; else this.searchJumperInPageInput.style.paddingLeft = ""; if (searchData.prefConfig.altToHighlight) { document.removeEventListener("mouseup", this.checkSelHandler); document.addEventListener("mouseup", this.checkSelHandler); } } togglePicker() { this.pickerBtn.classList.toggle("checked"); this.con.classList.toggle("in-pick"); this.searchJumperInputKeyWords.disabled = !this.searchJumperInputKeyWords.disabled; picker.toggle(true); if (this.searchJumperInputKeyWords.disabled) { this.searchJumperInputKeyWords.value = ""; } } hideSearchInput() { this.inInput = false; this.clearInputHide(); this.con.classList.remove("in-find"); this.con.classList.remove("in-input"); this.con.classList.remove("lock-input"); this.bar.classList.remove("initShow"); this.searchInput.value = ""; this.searchJumperInputKeyWords.value = ""; this.pickerBtn.classList.remove("checked"); this.searchJumperInputKeyWords.disabled = false; picker.close(); document.removeEventListener("mouseup", this.checkSelHandler); this.setFuncKeyCall(false); this.closeOpenType(); } removeBar() { if (this.shadowContainer && this.shadowContainer.parentNode) { this.shadowContainer.parentNode.removeChild(this.shadowContainer); } if (this.con.parentNode) { this.con.parentNode.removeChild(this.con); } } async testCSP() { let self = this; let cspHandler = e => { if (!e.violatedDirective || e.violatedDirective.indexOf("style-src") == -1) return; disabled = true; }; window.addEventListener('securitypolicyviolation', cspHandler); let testStyleEle = _GM_addStyle(`html {color: #000;}`); this.addToShadow(testStyleEle); await sleep(0); window.removeEventListener('securitypolicyviolation', cspHandler); testStyleEle.parentNode && testStyleEle.parentNode.removeChild(testStyleEle); } addToShadow(ele) { if (!this.shadowContainer) { this.shadowContainer = document.createElement("div"); } if (!this.shadowContainer.parentNode) { if (shareEngines) { document.body.appendChild(this.shadowContainer); } else { document.documentElement.appendChild(this.shadowContainer); } } let shadow; if (disabled) { if (/^style$/i.test(ele.nodeName)) return true; shadow = this.shadowContainer; } else { if (this.shadowRoot) { shadow = this.shadowRoot; } else { //this.shadowContainer.setAttribute('contenteditable', 'true'); this.shadowContainer.className = "search-jumper-shadow"; let style = _GM_addStyle(` .search-jumper-shadow { display: block !important; width: 0px !important; height: 0px !important; margin: 0px !important; padding: 0px !important; border-width: initial !important; border-style: none !important; border-color: initial !important; border-image: initial !important; outline: none !important; position: unset !important; } `); this.shadowContainer.appendChild(style); let shadowRoot = this.shadowContainer.attachShadow({ mode: "closed" }); shadow = document.createElement("div"); shadow.id = "search-jumper-root"; shadow.style.display = "none"; shadow.setAttribute('contenteditable', 'false'); let hideShadowStyle = document.createElement("style"); hideShadowStyle.innerHTML = createHTML("#search-jumper-root{display: block!important;}"); shadow.appendChild(hideShadowStyle); shadowRoot.appendChild(shadow); this.shadowRoot = shadow; } } if (ele.parentNode != shadow) shadow.appendChild(ele); return true; } contains(ele) { return ele == this.shadowContainer || this.bar.contains(ele); } appendBar() { if (!mainStyleEle || !mainStyleEle.parentNode) { mainStyleEle = _GM_addStyle(cssText); if (!disabled) this.addToShadow(mainStyleEle); } if (this.addToShadow(this.con)) { let self = this; let checkZIndex = () => { setTimeout(() => { if (self.shadowContainer && !self.shadowContainer.parentNode) { if (shareEngines) { document.body.appendChild(self.shadowContainer); } else { document.documentElement.appendChild(self.shadowContainer); } checkZIndex(); return; } if (!isAllPage && self.con.parentNode) { if (getComputedStyle(self.con).zIndex != "2147483647") { this.removeBar(); if (disabled) { debug(i18n("cspDisabled")); } else { disabled = true; mainStyleEle = _GM_addStyle(cssText); self.shadowContainer.parentNode.removeChild(self.shadowContainer); self.shadowContainer = document.createElement("div"); self.shadowContainer.setAttribute('contenteditable', 'false'); document.documentElement.appendChild(self.shadowContainer); self.appendBar(); } } } }, 100); }; checkZIndex(); } } async searchBySiteName(siteName, e, selfTab) { if (!e) e = {}; if (e && e.type === 'drop') { this.closeShowAll(); } for (let [siteBtn, siteData] of this.allSiteBtns) { if (siteBtn.dataset.name == siteName) { if (siteBtn.dataset.showTips) { siteBtn.dispatchEvent(new CustomEvent('showTips')); return; } await this.siteSetUrl(siteBtn, {button: e.button, altKey: e.altKey, ctrlKey: e.ctrlKey, shiftKey: e.shiftKey, metaKey: e.metaKey}); let isPage = /^(https?|ftp):/.test(siteBtn.href); if (isPage) { siteBtn.setAttribute("target", selfTab ? "_self" : "_blank"); } siteBtn.click(); if (isPage) { siteBtn.setAttribute("target", siteBtn.dataset.target == 1 ? "_blank" : "_self"); } return; } } for (let i = searchTypes.length - 1; i >= 0; i--) { let typeEle = searchTypes[i]; if (typeEle.dataset.type == siteName) { typeEle.firstChild.onmousedown({button: 2}); return; } } } async searcAllhByTypeName(siteName) { for (let i = searchTypes.length - 1; i >= 0; i--) { let typeEle = searchTypes[i]; if (typeEle.dataset.type == siteName) { typeEle.firstChild.onmousedown({button: 2}); return; } } } autoGetFirstType() { if (!targetElement) targetElement = getBody(document); let firstType; switch (targetElement.nodeName.toUpperCase()) { case 'IMG': firstType = this.bar.querySelector('.search-jumper-targetImg:not(.notmatch)'); break; case 'AUDIO': firstType = this.bar.querySelector('.search-jumper-targetAudio:not(.notmatch)'); break; case 'VIDEO': firstType = this.bar.querySelector('.search-jumper-targetVideo:not(.notmatch)'); break; case 'A': if (getSelectStr()) { firstType = this.bar.querySelector('.search-jumper-needInPage:not(.notmatch)'); } else { firstType = this.bar.querySelector('.search-jumper-targetLink:not(.notmatch)'); } break; default: if (getSelectStr()) { firstType = this.bar.querySelector('.search-jumper-needInPage:not(.notmatch)'); } else if (targetElement.parentNode.nodeName.toUpperCase() === 'A') { firstType = this.bar.querySelector('.search-jumper-targetLink:not(.notmatch)'); } else { firstType = this.bar.querySelector('.search-jumper-targetPage:not(.notmatch)'); } break; } if (!firstType) firstType = this.bar.querySelector('.search-jumper-targetAll:not(.notmatch)') || this.bar.querySelector('.search-jumper-type'); if (firstType) { this.setFuncKeyCall(false); let mouseEvent = new PointerEvent("mousedown"); if (firstType.classList.contains('search-jumper-open')) { if (firstType.children[0].onmousedown) firstType.children[0].onmousedown(); else { firstType.children[0].dispatchEvent(mouseEvent); } } if (firstType.children[0].onmousedown) firstType.children[0].onmousedown(); else { firstType.children[0].dispatchEvent(mouseEvent); } } return firstType; } searchAuto(index, e) { if (!index) index = 0; let firstType = this.autoGetFirstType(); if (!firstType) return; let targetSites = firstType.querySelectorAll('a.search-jumper-btn:not(.notmatch)'); if (index < targetSites.length) { let targetSite = targetSites[index]; this.searchBySiteName(targetSite.dataset.name, e); } } setNav(enable, noSave) { if (!noSave && navEnable != enable) { storage.setItem("navEnable", enable || ""); navEnable = enable; } if (enable) { if (!noSave) this.locBtn.classList.add("checked"); this.searchJumperNavBar.style.display = ""; } else { if (!noSave) this.locBtn.classList.remove("checked"); this.searchJumperNavBar.style.display = "none"; this.navPointer.style.display = "none"; } } lockSearchInput(lockWords) { this.lockSiteKeywords = true; this.searchLockInput.innerText = lockWords; this.con.classList.add("lock-input"); this.searchInput.value = ""; this.searchInput.style.paddingLeft = `${15 + this.searchLockInput.scrollWidth}px`; this.searchInput.placeholder = i18n("inputKeywords"); } async initRun() { let self = this; this.siteIndex = 1; this.customInput = false; this.fontPool = []; this.allSiteBtns = []; this.allListBtns = []; this.allLists = []; this.dockerScaleBtns = []; this.bar.style.visibility = "hidden"; let sitesNum = 0; let bookmarkTypes = []; this.checkSelHandler = e => { if (!e.altKey) return; if (this.searchInPageTab.checked && window.getSelection().toString()) { this.showSearchInput(); } }; //Search in page this.splitSep = "◎"; this.lockWords = ""; this.marks = {}; this.initInPageWords = []; this.highlightSpans = {}; this.curHighlightWords = []; this.curWordIndex = 0; let editFunc = () => { this.searchJumperInPageInput.focus(); this.highlight(""); let words = this.lockWords.trim(); if (!words) { this.submitInPageWords(); return; } if (this.searchJumperInPageInput.value) words += this.splitSep + this.searchJumperInPageInput.value; this.lockWords = ""; this.searchJumperInPageInput.value = words; this.searchInPageLockWords.innerHTML = createHTML(); this.searchJumperInPageInput.style.paddingLeft = ""; }; document.addEventListener("keydown", e => { if (e.keyCode === 27) { if (isAllPage) { this.searchInput.value = ""; this.searchInput.dispatchEvent(new CustomEvent("input")); } else if (this.inInput) { this.hideSearchInput(); } else if (this.lockWords) { this.highlight(""); this.searchJumperInPageInput.value = this.lockWords; this.lockWords = ""; this.searchInPageLockWords.innerHTML = createHTML(); this.setNav(false, true); } else if (this.funcKeyCall) { this.removeBar(); } } }, true); this.searchJumperInPageInput.addEventListener("focus", e => { this.searchInputDiv.classList.add("active"); }); this.searchJumperInPageInput.addEventListener("blur", e => { this.searchInputDiv.classList.remove("active"); }); this.searchJumperInPageInput.addEventListener("keydown", e => { e.stopPropagation(); switch(e.keyCode) { case 8://退格 if (!this.searchJumperInPageInput.value) { let lastWordSpan = this.searchInPageLockWords.lastChild; if (lastWordSpan) { lastWordSpan.dispatchEvent(new CustomEvent("editword")); e.preventDefault(); } } break; case 9://tab e.preventDefault(); this.filterSitesTab.checked = true; this.con.classList.remove("in-find"); this.searchInput.focus(); break; case 13://回车 { //let spans = this.submitInPageWords(); let spans = this.searchJumperInPageInput.value ? this.submitInPageWords() : []; if (spans && spans.length > 0) { let lastSpan = spans.pop(); if (this.currentSearchInPageLockWords) { this.currentSearchInPageLockWords.firstChild.style.transform = ""; } this.currentSearchInPageLockWords = lastSpan; let mouseEvent = new PointerEvent("mousedown", {button: e.shiftKey ? 2 : 0}); lastSpan.dispatchEvent(mouseEvent); } else if (this.lockWords) { if (!this.currentSearchInPageLockWords) { this.currentSearchInPageLockWords = this.searchInPageLockWords.lastChild; this.currentSearchInPageLockWords.firstChild.style.transform = "scale(1.1)"; } let mouseEvent = new PointerEvent("mousedown", {button: e.shiftKey ? 2 : 0}); this.currentSearchInPageLockWords.dispatchEvent(mouseEvent); } } break; case 37://← if (this.searchJumperInPageInput.value == "" && this.lockWords) { if (!this.currentSearchInPageLockWords) { this.currentSearchInPageLockWords = this.searchInPageLockWords.lastChild; this.currentSearchInPageLockWords.firstChild.style.transform = "scale(1.1)"; } else if (this.currentSearchInPageLockWords.previousElementSibling){ this.currentSearchInPageLockWords.firstChild.style.transform = ""; this.currentSearchInPageLockWords = this.currentSearchInPageLockWords.previousElementSibling; this.currentSearchInPageLockWords.firstChild.style.transform = "scale(1.1)"; } } break; case 39://→ if (this.searchJumperInPageInput.value == "" && this.lockWords) { if (!this.currentSearchInPageLockWords) { this.currentSearchInPageLockWords = this.searchInPageLockWords.lastChild; this.currentSearchInPageLockWords.firstChild.style.transform = "scale(1.1)"; } else if (this.currentSearchInPageLockWords.nextElementSibling){ this.currentSearchInPageLockWords.firstChild.style.transform = ""; this.currentSearchInPageLockWords = this.currentSearchInPageLockWords.nextElementSibling; this.currentSearchInPageLockWords.firstChild.style.transform = "scale(1.1)"; } } break; default: break; } }, true); this.editBtn.addEventListener("click", e => { editFunc(); }); this.addWord.addEventListener("click", e => { this.showModifyWindow(); }); this.searchInPageTab.addEventListener("change", e => { this.initSetInPageWords(); this.searchJumperInPageInput.focus(); this.con.classList.add("in-find"); }); this.filterSitesTab.addEventListener("change", e => { this.searchInput.focus(); this.con.classList.remove("in-find"); }); if (globalInPageWords) { this.recoverBtn.addEventListener("click", e => { this.lockWords = ""; this.searchJumperInPageInput.value = globalInPageWords; this.searchInPageLockWords.innerHTML = createHTML(); this.highlight(""); this.submitInPageWords(); this.searchJumperInPageInput.focus(); }); this.pinBtn.classList.add("checked"); } else { this.recoverBtn.style.display = "none"; } this.pinBtn.addEventListener("click", e => { this.submitInPageWords(); if (this.pinBtn.classList.contains("checked")) { globalInPageWords = ""; this.pinBtn.classList.remove("checked"); } else if (this.lockWords) { globalInPageWords = this.lockWords; this.pinBtn.classList.add("checked"); } storage.setItem("globalInPageWords", globalInPageWords); }); this.wordModeBtn.addEventListener("click", e => { let inWordMode = this.wordModeBtn.classList.contains("checked"); if (inWordMode) { this.wordModeBtn.classList.remove("checked"); } else { this.wordModeBtn.classList.add("checked"); } if (this.lockWords) { this.refreshPageWords(this.lockWords); } }); this.saveRuleBtn.addEventListener("click", e => { if (!this.lockWords) return; if (shareEngines) return; dataChanged(() => { let inPageRule = searchData.prefConfig.inPageRule || {}; inPageRule[this.inPageRuleKey || href.replace(/([&\?]_i=|#).*/, "")] = this.lockWords; searchData.prefConfig.inPageRule = inPageRule; searchData.lastModified = new Date().getTime(); lastModified = searchData.lastModified; storage.setItem("searchData", searchData); _GM_notification(i18n("save completed")); }); }); this.emptyBtn.addEventListener("click", e => { this.lockWords = ""; this.searchJumperInPageInput.value = ""; this.searchInPageLockWords.innerHTML = createHTML(); this.searchJumperInPageInput.style.paddingLeft = ""; this.submitInPageWords(); this.searchJumperInPageInput.focus(); }); this.copyInPageBtn.addEventListener("click", e => { if (!this.lockWords) return; _GM_setClipboard(this.lockWords.replace(/◎/g, "\n")); _GM_notification('Copied successfully!'); }); this.setNav(navEnable); this.locBtn.addEventListener("click", e => { this.setNav(!this.locBtn.classList.contains("checked")); }); this.closeNavBtn.addEventListener("click", e => { if (this.lockWords) { this.searchJumperInPageInput.value = this.lockWords || ""; this.lockWords = ""; this.searchInPageLockWords.innerHTML = createHTML(); this.searchJumperInPageInput.style.paddingLeft = ""; this.highlight(""); this.searchJumperInPageInput.focus(); this.setNav(false, true); storage.setItem("disableHighlight", location.hostname); if (this.bar.style.display === "none") { this.removeBar(); } } else { this.setNav(false); } }); this.minNavBtn.addEventListener("click", e => { if (this.searchJumperNavBar.classList.contains("minimize")) { this.searchJumperNavBar.classList.remove("minimize"); if (this.lockWords.trim()) return; this.submitInPageWords(); } else { this.searchJumperNavBar.classList.add("minimize"); this.highlight(""); let words = this.lockWords.trim(); if (!words) return; if (this.searchJumperInPageInput.value) words += this.splitSep + this.searchJumperInPageInput.value; this.lockWords = ""; this.searchJumperInPageInput.value = words; this.searchInPageLockWords.innerHTML = createHTML(); this.searchJumperInPageInput.style.paddingLeft = ""; } }); this.maxNavBtn.addEventListener("click", e => { self.showInPage(); self.showInPageSearch(); }); this.navMarks.addEventListener("click", e => { let topPercent = e.offsetY / this.navMarks.clientHeight * 100; let sortedMarks = [].slice.call(this.navMarks.querySelectorAll("span")); sortedMarks.sort((a, b) => { a = parseFloat(a.style.top); b = parseFloat(b.style.top); if (a > b) return 1; if (a < b) return -1; return 0; }); let mark; for (let i = 0; i < sortedMarks.length; i++) { mark = sortedMarks[i]; let markTop = parseFloat(mark.style.top); if (markTop > topPercent) { if (i > 0) { let preMark = sortedMarks[i - 1]; let preMarkTop = parseFloat(preMark.style.top); if (markTop - topPercent > topPercent - preMarkTop) { mark = preMark; } } break; } } if (mark) { mark.click(); } }); this.bar.addEventListener("mousedown", e => { e && e.stopPropagation && e.stopPropagation(); e && e.preventDefault && e.preventDefault(); }); this.con.addEventListener('dblclick', e=>{ e.stopPropagation(); e.preventDefault(); }); //Search in page let expandTypeHandler = e => { e.stopPropagation(); e.preventDefault(); let typeEle = self.searchJumperExpand.parentNode; if (!typeEle || !typeEle.classList.contains('not-expand')) return; typeEle.classList.remove('not-expand'); typeEle.classList.remove('search-jumper-move'); let leftRight = self.con.classList.contains("search-jumper-left") || self.con.classList.contains("search-jumper-right"); typeEle.removeChild(self.searchJumperExpand); let scrollSize = Math.max(typeEle.scrollWidth, typeEle.scrollHeight) + 5 + "px"; if (leftRight) { typeEle.style.height = scrollSize; typeEle.style.width = ""; } else { typeEle.style.width = scrollSize; typeEle.style.height = ""; } setTimeout(() => { self.checkScroll(); typeEle.classList.add('search-jumper-move'); }, 251); }, showTimer; this.searchJumperExpand.addEventListener("click", expandTypeHandler, true); this.searchJumperExpand.addEventListener("contextmenu", expandTypeHandler, true); this.searchJumperExpand.addEventListener('mouseenter', e => { if (searchData.prefConfig.overOpen) { clearTimeout(showTimer); showTimer = setTimeout(() => { expandTypeHandler(e); }, 500); } let sitelistEvent = new CustomEvent("sitelist", { detail: { bind: e.currentTarget, } }); e.currentTarget.parentNode.dispatchEvent(sitelistEvent); }, false); if (searchData.prefConfig.overOpen) { this.searchJumperExpand.addEventListener('mouseleave', e => { clearTimeout(showTimer); }, false); } this.pickerBtn.addEventListener("click", e => { this.togglePicker(); }); this.maxEleBtn.addEventListener("click", e => { picker.expand(); }); this.minEleBtn.addEventListener("click", e => { picker.collapse(); }); this.copyEleBtn.addEventListener("click", e => { picker.copy(); }); this.openLinkBtn.addEventListener("click", e => { picker.openLinks(); }); let listArrow = document.createElement("div"); listArrow.className = "listArrow"; this.listArrow = listArrow; this.con.appendChild(listArrow); for (let siteConfig of searchData.sitesConfig) { let isBookmark = siteConfig.bookmark || siteConfig.sites.length > 100 || (/^BM/.test(siteConfig.type) && siteConfig.icon === "bookmark"); if (isBookmark) { bookmarkTypes.push(siteConfig); continue; } await this.createType(siteConfig); sitesNum += siteConfig.sites.length; if (sitesNum > 100) { await sleep(1); sitesNum = 0; } } this.initHistorySites(); this.initSort(); this.bar.style.visibility = ""; this.bar.style.display = "none"; this.searchInPageRule(); if (currentSite && wordParamReg.test(currentSite.url)) { this.inSearchEngine(); } else if (searchData.prefConfig.alwaysShow && !inIframe && !isInConfigPage) { this.bar.style.display = ""; this.initPos(); this.appendBar(); } if (lastSign) { targetElement = lastSign.target; this.batchOpen(lastSign.sites, {button: 2}); } lastSign = false; if (inPagePostParams) { this.submitAction(inPagePostParams); setTimeout(() => { storage.setListItem("inPagePostParams", location.hostname, ""); }, 10000); } let searchWithCurrentFilter = e => { clearTimeout(inputTimer); let siteEle, forceTarget = ""; if (currentSite && !self.searchInput.value) { siteEle = self.con.querySelector(".search-jumper-btn.current"); forceTarget = "_self"; } else { siteEle = self.con.querySelector(".search-jumper-type.search-jumper-open>a.search-jumper-btn:not(.input-hide)") || self.con.querySelector(".search-jumper-needInPage>a.search-jumper-btn:not(.input-hide)") || self.con.querySelector("a.search-jumper-btn:not(.input-hide)"); forceTarget = "_blank"; } if (siteEle) { self.openSiteBtn(siteEle, forceTarget, !e.ctrlKey); } }; let inputTimer; this.inInput = false; let saveCacheFilter = () => { if (cacheFilter !== self.searchInput.value) { cacheFilter = self.searchInput.value; storage.setItem("cacheFilter", cacheFilter); } }; this.searchInput.addEventListener("input", e => { clearTimeout(inputTimer); inputTimer = setTimeout(() => { self.searchSiteBtns(self.searchInput.value) }, 500); }); this.searchInput.addEventListener("click", e => { self.searchInput.select(); }); this.searchInput.addEventListener("blur", e => { saveCacheFilter(); }); this.searchInput.addEventListener("keydown", e => { e.stopPropagation(); switch(e.keyCode) { case 9: if (e.shiftKey) { e.preventDefault(); this.searchInPageTab.checked = true; this.con.classList.add("in-find"); this.searchJumperInPageInput.focus(); this.initSetInPageWords(); } break; case 13://回车 if (this.searchJumperInputKeyWords.disabled) { clearTimeout(inputTimer); let siteEle, forceTarget = ""; if (currentSite && !self.searchInput.value) { siteEle = self.con.querySelector(".search-jumper-btn.current"); forceTarget = "_self"; } else { siteEle = self.con.querySelector(".search-jumper-type.search-jumper-open>a.search-jumper-btn:not(.input-hide)") || self.con.querySelector(".search-jumper-needInPage>a.search-jumper-btn:not(.input-hide)") || self.con.querySelector("a.search-jumper-btn:not(.input-hide)"); forceTarget = "_blank"; } if (siteEle) { self.openSiteBtn(siteEle, forceTarget, !e.ctrlKey); } } else { if (this.searchJumperInputKeyWords.value) { searchWithCurrentFilter(e); } else { this.searchJumperInputKeyWords.focus(); } saveCacheFilter(); } break; case 8://退格 /*if (self.lockSiteKeywords && !self.searchInput.value) { self.searchInput.value = self.searchLockInput.innerText; self.searchLockInput.innerText = ""; self.lockSiteKeywords = false; self.con.classList.remove("lock-input"); self.searchInput.style.paddingLeft = ""; self.searchInput.placeholder = i18n("inputPlaceholder"); }*/ break; default: break; } }); this.searchJumperInputKeyWords.addEventListener("input", e => { clearTimeout(inputTimer); inputTimer = setTimeout(() => { self.getSuggest(self.searchJumperInputKeyWords.value) }, 200); }); this.searchJumperInputKeyWords.addEventListener("keydown", e => { if (e.keyCode !== 27) e.stopPropagation(); switch(e.keyCode) { case 9: if (!this.inInput) { e.preventDefault(); this.searchInput.focus(); } else if (!e.shiftKey) { e.preventDefault(); this.searchInPageTab.checked = true; this.con.classList.add("in-find"); this.searchJumperInPageInput.focus(); this.initSetInPageWords(); } break; case 13://回车 searchWithCurrentFilter(e); break; default: break; } }, true); this.closeBtn.addEventListener("mousedown", e => { self.hideSearchInput(); if (searchData.prefConfig.emptyAfterCloseInput) { self.highlight(""); self.searchJumperInPageInput.value = self.lockWords || ""; self.lockWords = ""; self.searchInPageLockWords.innerHTML = createHTML(); self.setNav(false, true); } }); let startLeft = window.innerWidth / 2; let startBottom; let currentGroup, startX, startY; let clientX = e => { if (e.type.indexOf('mouse') === 0) { return e.clientX; } else { return e.changedTouches[0].clientX; } }; let clientY = e => { if (e.type.indexOf('mouse') === 0) { return e.clientY; } else { return e.changedTouches[0].clientY; } }; let grabMousemoveHandler = e => { let halfContainerWidth = 0.25 * window.innerWidth; let left = startLeft + clientX(e) - startX; self.searchInputDiv.style.top = 'unset'; self.searchInputDiv.style.left = left + "px"; self.searchInputDiv.style.bottom = startBottom - (clientY(e) - startY) + "px"; if (left > window.innerWidth / 2) { let maxWidth = window.innerWidth - left + halfContainerWidth - 50; self.searchInputDiv.style.maxWidth = maxWidth + "px"; } else { let maxWidth = left + halfContainerWidth; if (left < halfContainerWidth) { left += halfContainerWidth - left; self.searchInputDiv.style.left = left + "px"; } self.searchInputDiv.style.maxWidth = maxWidth + "px"; } e.stopPropagation(); e.preventDefault(); }; let grabMouseupHandler = e => { document.removeEventListener("mouseup", grabMouseupHandler); document.removeEventListener("mousemove", grabMousemoveHandler); document.removeEventListener("touchend", grabMouseupHandler); document.removeEventListener("touchmove", grabMousemoveHandler); currentGroup.style.cursor = ""; startLeft += clientX(e) - startX; startBottom -= clientY(e) - startY; }; let setStartBottom = () => { if (!startBottom) startBottom = self.con.classList.contains('search-jumper-bottom') ? window.innerHeight * 0.95 - 60 : window.innerHeight * 0.03; }; let touchStart = false; this.searchInputDiv.addEventListener("touchstart", e => { touchStart = true; if (e.target.className === 'inputGroup' || e.target.nodeName.toUpperCase() === 'LABEL') { setStartBottom(); currentGroup = e.target; currentGroup.style.cursor = "grabbing"; startX = clientX(e); startY = clientY(e); document.addEventListener("touchend", grabMouseupHandler); document.addEventListener("touchmove", grabMousemoveHandler); } }, { passive: true, capture: false }); this.searchInputDiv.addEventListener("mousedown", e => { if (touchStart) { touchStart = false; return; } if (e.target.className === 'inputGroup' || e.target.nodeName.toUpperCase() === 'LABEL') { setStartBottom(); currentGroup = e.target; currentGroup.style.cursor = "grabbing"; startX = e.clientX; startY = e.clientY; document.addEventListener("mouseup", grabMouseupHandler); document.addEventListener("mousemove", grabMousemoveHandler); e.stopPropagation(); e.preventDefault(); } }); let initWidth, initX; let sizeChangeMouseMove = e => { let width = e.clientX - initX + initWidth + 20; this.searchInputDiv.style.width = width + "px"; }; let sizeChangeMouseUp = e => { document.removeEventListener("mousemove", sizeChangeMouseMove); document.removeEventListener("mouseup", sizeChangeMouseUp); }; this.rightSizeChange.addEventListener("mousedown", e => { initX = e.clientX; initWidth = this.searchInput.clientWidth * 2 + 2; document.addEventListener("mousemove", sizeChangeMouseMove); document.addEventListener("mouseup", sizeChangeMouseUp); e.stopPropagation(); e.preventDefault(); }); let dragSiteBtn; let dragOpenDropHandler = e => { if (!this.contains(e.target)){ let isPage = /^(https?|ftp):/.test(dragSiteBtn.href); if (isPage) { dragSiteBtn.setAttribute("target", "_blank"); } if (!isPage) { dragSiteBtn.click(); } else { _GM_openInTab(dragSiteBtn.href, {active: false, insert: true}); } if (isPage) { dragSiteBtn.setAttribute("target", dragSiteBtn.dataset.target == 1 ? "_blank" : "_self"); } } getBody(document).removeEventListener('dragover', dragOpenOverHandler); document.removeEventListener('drop', dragOpenDropHandler); document.removeEventListener('dragover', dragOpenOverHandler); }; let dragOpenOverHandler = e => { e.preventDefault(); }; let dragOpenEndHandler = e => { getBody(document).removeEventListener('dragover', dragOpenOverHandler); document.removeEventListener('drop', dragOpenDropHandler); document.removeEventListener('dragover', dragOpenOverHandler); }; this.bar.addEventListener("dragstart", e => { let target = e.target; let parentNode = target.parentNode; if (target.nodeName.toUpperCase() !== 'IMG' && target.nodeName.toUpperCase() !== 'A') return; if (target.classList && target.classList.contains('search-jumper-btn')) { dragSiteBtn = target; getBody(document).addEventListener('dragover', dragOpenOverHandler); document.addEventListener('drop', dragOpenDropHandler); document.addEventListener('dragend', dragOpenEndHandler); } else if (parentNode && parentNode.classList && parentNode.classList.contains('search-jumper-btn')) { dragSiteBtn = parentNode; getBody(document).addEventListener('dragover', dragOpenOverHandler); document.addEventListener('drop', dragOpenDropHandler); document.addEventListener('dragend', dragOpenEndHandler); } }, true); sitesNum = 0; let hasCurrent = currentSite !== false; for (let siteConfig of bookmarkTypes) { await this.createType(siteConfig); sitesNum += siteConfig.sites.length; if (sitesNum > 200) { await sleep(1); sitesNum = 0; } } if (!this.findInpageAddons) { this.findInpageAddons = _unsafeWindow.searchJumperAddons.filter( data => data.type == "findInPage" ).sort((a, b) => (a.sort || 0) - (b.sort || 0)); let self = this, index = 0, addonDict = {}; this.findInpageAddons.forEach(addon => { let name = addon.name || ("addon" + index++); if (addonDict[addon.sort]) addon.disable = true; else if (searchData.prefConfig.disableAddon[name] === true) { addon.disable = true; } else if (searchData.prefConfig.disableAddon[name] === false) { addon.disable = false; } else { addon.disable = ext ? true : false; } addonDict[addon.sort] = true; self.createAddonSpan(name, addon); }); } if (this.fontPool.length > 0 || isInConfigPage) { let linkEle = document.createElement("link"); linkEle.rel="stylesheet"; linkEle.href = searchData.prefConfig.fontAwesomeCss || "https://lib.baomitu.com/font-awesome/6.1.2/css/all.css"; document.documentElement.insertBefore(linkEle, document.documentElement.children[0]); this.addToShadow(linkEle.cloneNode()); waitForFontAwesome(() => { let hasFont = false; this.fontPool.forEach(font => { font.innerText = ''; font.style.fontSize = ''; font.style.color = ''; hasFont = true; cacheFontPool.unshift(font); }); if (hasFont && (isInConfigPage || href === firstRunPage)) { setTimeout(() => {cacheFontManager()}, 3000); } this.buildAllPageGroupTab(); }); } else { this.buildAllPageGroupTab(); } if (isAllPage) return; if (disableHighlight && disableHighlight != location.hostname && window.top == window.self) { storage.setItem("disableHighlight", ""); } await this.testCSP(); let foundKeyword = currentSite && wordParamReg.test(currentSite.url); if (!hasCurrent && foundKeyword) { this.inSearchEngine(); } else if (!currentSite && window.top == window.self) { this.checkSearchJump(); } let hasHighlightWords = this.initInPageWords && this.initInPageWords.length; if (inMinMode || (this.bar.style.display === "none" && (!navEnable || !hasHighlightWords))) { this.removeBar(); } } buildAllPageGroupTab() { let self = this; this.groupTab.innerHTML = createHTML(); searchTypes.forEach(type => { if (type.classList.contains("notmatch")) return; let typeName = type.dataset.type; let icon = type.firstElementChild.cloneNode(true); let groupSpan = document.createElement("span"); groupSpan.appendChild(icon); groupSpan.dataset.type = typeName; groupSpan.addEventListener("click", e => { let targetType = self.sitelistBox.querySelector(`[data-type="${typeName}"]`); if (targetType) targetType.scrollIntoView({behavior: "smooth", block: "start", inline: "center"}); }); self.groupTab.appendChild(groupSpan); }); } async refreshEngines() { if (!searchData) return; if (this.refreshing) return; this.refreshing = true; setTimeout(() => { this.refreshing = false; }, 500); lastModified = searchData.lastModified; this.removeBar(); if (searchTypes && searchTypes.length) { searchTypes.forEach(type => { type.parentNode && type.parentNode.removeChild(type); }); } searchTypes = []; this.allSiteBtns = []; this.allListBtns = []; this.allLists = []; this.historyTypeEle = null; for (let siteConfig of searchData.sitesConfig) { await this.createType(siteConfig); } this.initHistorySites(); this.initSort(); this.buildAllPageGroupTab(); if (isAllPage) { this.appendBar(); } } waitForHide(delay) { let self = this; if (this.bar.classList.contains("grabbing")) return; this.touched = false; var hideHandler = () => { //self.bar.classList.remove("search-jumper-isInPage"); self.bar.classList.remove("search-jumper-isTargetImg"); self.bar.classList.remove("search-jumper-isTargetAudio"); self.bar.classList.remove("search-jumper-isTargetVideo"); self.bar.classList.remove("search-jumper-isTargetLink"); //self.bar.classList.remove("search-jumper-isTargetPage"); self.bar.classList.remove("initShow"); self.tips.style.opacity = 0; self.tips.style.display = "none"; self.tips.innerHTML = createHTML(""); //self.recoveHistory(); if (self.funcKeyCall) { self.setFuncKeyCall(false); if ((currentSite && !currentSite.hideNotMatch && !searchData.prefConfig.hideOnSearchEngine) || self.con.classList.contains("resizePage")) { self.initPos(); let firstType = self.bar.querySelector('.search-jumper-type:nth-child(1)>span'); if (firstType && !firstType.classList.contains("search-jumper-open")) { if (firstType.onmousedown) { firstType.onmousedown(); } else { let mouseEvent = new PointerEvent("mousedown"); firstType.dispatchEvent(mouseEvent); } } } else { self.bar.style.display = 'none'; } } if (searchData.prefConfig.autoClose) { self.closeOpenType(); } self.hideTimeout = null; }; if (this.hideTimeout) { clearTimeout(this.hideTimeout); } let delayTime = typeof delay === 'undefined' ? (this.funcKeyCall ? 500 : (searchData.prefConfig.autoDelay || 1000)) : delay; if (delayTime) { this.hideTimeout = setTimeout(hideHandler, delayTime); } else hideHandler(); if (this.preList) { this.preList.style.visibility = "hidden"; this.listArrow.style.cssText = ""; } } searchEngineWords(words) { words = words.replace(/( |^)-\S+/g, ""); if (/".+"/.test(words)) { words = words.replace(/"(.+)"/g, (match, p, offset, string) => { return `◎${p}◎`; }).replace(/^◎|◎$/g, ""); } this.lastSearchEngineWords = words.replace(/['";]/g, ' '); return this.lastSearchEngineWords; } setInPageWords(inPageWords, cb) { this.initInPageWords.push(inPageWords); //this.searchInPageTab.checked = true; this.con.classList.add("in-find"); let beginHandler = () => { setTimeout(async () => { if (getBody(document).style.display === "none") getBody(document).style.display = ""; if (this.lockWords) { this.initInPageWords = []; } else { while (document.hidden) { await sleep(1000); } storage.setItem("lastHighlight", location.hostname); let word = this.initInPageWords.shift(); while (word) { this.searchJumperInPageInput.value = word; this.submitInPageWords(true); word = this.initInPageWords.shift(); } } if (cb) cb(); await sleep(100); storage.setItem("lastHighlight", ""); }, 300); }; if (document.readyState != "complete") { let loadHandler = e => { if (document.readyState == "complete") { document.removeEventListener("readystatechange", loadHandler); window.removeEventListener('load', loadHandler); beginHandler(); } }; document.addEventListener("readystatechange", loadHandler); window.addEventListener('load', loadHandler); } else { beginHandler(); } } searchInPageRule() { if (searchData.prefConfig.disableAutoHighlight) { let sites = searchData.prefConfig.disableAutoHighlight.trim().split("\n"); for (let i = 0; i < sites.length; i++) { let key = sites[i], isMatch = false; if (key.indexOf("/") === 0) { let keyMatch = key.match(/^\/(.*)\/([igm]*)$/); if (keyMatch) { isMatch = new RegExp(keyMatch[1], keyMatch[2]).test(href); } } else { isMatch = this.globMatch(key, href); } if (isMatch) { this.disableAutoHighlight = true; return; } } } if (lastHighlight === location.hostname) { this.disableAutoHighlight = true; } if (searchData.prefConfig.inPageRule) { let keys = Object.keys(searchData.prefConfig.inPageRule); for (let i = 0; i < keys.length; i++) { let key = keys[i]; if (!key) continue; let isMatch = false; if (key.indexOf("/") === 0) { let keyMatch = key.match(/^\/(.*)\/([igm]*)$/); if (keyMatch) { isMatch = new RegExp(keyMatch[1], keyMatch[2]).test(href); } } else { isMatch = this.globMatch(key, href); } if (isMatch) { let rule = searchData.prefConfig.inPageRule[key]; if (!rule) continue; this.inPageRuleKey = key; this.disableAutoHighlight = true; this.setInPageWords(rule); break; } } } } checkSearchJump() { if (this.inPageRuleKey || this.disableAutoHighlight) return; let inPageWords; if (searchData.prefConfig.showInSearchJumpPage && referrer && !disableHighlight) { if (curRef.indexOf(referrer) != -1) { if (cacheKeywords) { this.wordModeBtn.classList.add("checked"); } inPageWords = cacheKeywords; try { inPageWords = decodeURIComponent(inPageWords); inPageWords = this.searchEngineWords(inPageWords); } catch (e) {} //storage.setItem("referrer", location.hostname); } else { //storage.setItem("referrer", ""); } } inPageWords = inPageWords || globalInPageWords; if (inPageWords) { this.appendBar(); let self = this; this.setInPageWords(inPageWords, () => { if (!self.navMarks.innerHTML && self.bar.style.display === "none") self.removeBar(); }); } else if (!this.searchJumperInPageInput.value && curRef.indexOf(referrer) != -1 && cacheKeywords) { inPageWords = cacheKeywords; this.wordModeBtn.classList.add("checked"); try { inPageWords = decodeURIComponent(inPageWords); } catch (e) {} this.searchJumperInPageInput.value = inPageWords; } } inSearchEngine() { if (!this.currentType || !currentSite || inIframe || this.inPageRuleKey || this.disableAutoHighlight) return; if (!/sidesearch=(1|true)$/i.test(location.search)) { if (!/#p{/.test(currentSite.url) || currentSite.keywords) { this.appendBar(); if (this.currentType.classList.contains("search-jumper-needInPage")) { this.bar.classList.add("search-jumper-isTargetPage"); } else if (this.currentType.classList.contains("search-jumper-targetAll") || this.currentType.classList.contains("search-jumper-targetImg") || this.currentType.classList.contains("search-jumper-targetAudio") || this.currentType.classList.contains("search-jumper-targetVideo") || this.currentType.classList.contains("search-jumper-targetLink") || this.currentType.classList.contains("search-jumper-targetPage")) { return; } if (!searchData.prefConfig.hideOnSearchEngine) { this.bar.style.display = ""; this.initPos(); } } } this.insertHistory(this.currentType, true); this.wordModeBtn.classList.add("checked"); let inPageWords = searchData.prefConfig.showInSearchEngine ? this.searchEngineWords(localKeywords) : globalInPageWords; if (inPageWords) { this.setInPageWords(inPageWords); } } getSuggest(searchWords) { let suggestDatalist = this.suggestDatalist; suggestDatalist.innerHTML = createHTML(); if (!searchWords) return; let requestSuggest = (api, cb, charset) => { _GM_xmlhttpRequest({ method: 'GET', url: api, responseType: charset ? 'blob' : '', headers: { referer: api, origin: api }, onload: function(d) { let response = d.response; if (d.status >= 400 || !response) return; if (charset) { let reader = new FileReader(); reader.onload = () => { cb(reader.result); } reader.readAsText(response, charset); } else { cb(response); } }, onerror: function(e){ debug(e); }, ontimeout: function(e){ debug(e); } }); }; if (ext) { requestSuggest = (api, cb) => { chrome.runtime.sendMessage({action: "getSuggest", detail: {suggestType: searchData.prefConfig.suggestType, searchWords: searchWords}}, function(r) { cb(r); }); } } switch (searchData.prefConfig.suggestType) { case "google": requestSuggest("https://suggestqueries.google.com/complete/search?client=youtube&q=%s&jsonp=window.google.ac.h".replace("%s", searchWords), res => { res = res.match(/window.google.ac.h\((.*)\)$/, "$1"); if (res) { res = JSON.parse(res[1])[1]; for (let i in res) { let option = document.createElement('option'); option.value = res[i][0]; suggestDatalist.appendChild(option); } } }); break; case "baidu": requestSuggest("https://suggestion.baidu.com/su?wd=%s&cb=".replace("%s", searchWords), res => { res = res.match(/.*,s:(.*)}\);$/, "$1"); if (res) { res = JSON.parse(res[1]); for (let i in res) { let option = document.createElement('option'); option.value = res[i]; suggestDatalist.appendChild(option); } } }, "GBK"); break; case "bing": requestSuggest("https://api.bing.com/qsonhs.aspx?type=json&q=%s".replace("%s", searchWords), res => { if (res) { res = JSON.parse(res).AS.Results; for (let i in res) { let result = res[i].Suggests; for (let j in result) { let option = document.createElement('option'); option.value = result[j].Txt; suggestDatalist.appendChild(option); } } } }); break; default: break; } } searchSiteBtns(inputWords) { let checkIndex = inputWords.indexOf('**'), checkType = "", accurate = false; if (checkIndex > 0) { checkType = inputWords.slice(0, checkIndex); inputWords = inputWords.slice(checkIndex + 2); } if (inputWords.indexOf('^') === 0) { accurate = true; } else { checkType = checkType.toLowerCase(); inputWords = inputWords.toLowerCase(); } if (inputWords) { this.con.classList.add("searching"); } else { this.con.classList.remove("searching"); } let canCheckHost = !/[^\w\.\/\:\*\?\^\$]/.test(inputWords); this.allListBtns.forEach(listItem => { listItem.classList.add("input-hide"); }); searchTypes.forEach(type => { type.classList.add("input-hide"); }); let optionNum = 0; this.filterGlob.innerHTML = createHTML(); this.allSiteBtns.forEach(arr => { let btn = arr[0]; let data = arr[1]; let typeNode = btn.parentNode; let targetType = btn.dataset.type; let targetName = btn.dataset.name; let targetTitle = btn.title; if (!accurate) { targetType = targetType.toLowerCase(); targetName = targetName.toLowerCase(); targetTitle = targetTitle.toLowerCase(); } let globMatchName = ""; if (checkType) { let typeMatch = this.globMatch(checkType, targetType); if (!typeMatch) return; globMatchName = btn.dataset.type + "**"; } let canMatch = false; if (!btn.dataset.clone) { if (this.globMatch(inputWords, targetName)) { canMatch = true; globMatchName += '^' + btn.dataset.name + '$'; } else if (btn.title && this.globMatch(inputWords, targetTitle)) { canMatch = true; globMatchName += '^' + btn.title + '$'; } } if (!canMatch) { if (canCheckHost) { if (!btn.dataset.host) { let hostReg = /^https?:\/\/([^\/]*)\/[\s\S]*$/; let href = data.url; btn.dataset.host = hostReg.test(href) ? href.replace(hostReg, "$1") : href; if (btn.dataset.host) btn.dataset.host = btn.dataset.host.toLowerCase(); } canMatch = this.globMatch(inputWords, btn.dataset.host); } if (!canMatch) { btn.classList.add("input-hide"); } else { globMatchName += '^' + btn.dataset.host + '$'; } } if (canMatch) { btn.classList.remove("input-hide"); if (typeNode) typeNode.classList.remove("input-hide"); let listItem; for (let i = 0; i < this.allListBtns.length; i++) { if (this.allListBtns[i].id == "list" + btn.dataset.id) { listItem = this.allListBtns[i]; break; } } if (listItem) listItem.classList.remove("input-hide"); if (optionNum < 50 && inputWords && this.searchInput.value !== globMatchName) { optionNum++; let option = document.createElement('option'); option.value = globMatchName; this.filterGlob.appendChild(option); } } }); searchTypes.forEach(type => { let targetList; for (let i = 0; i < this.allLists.length; i++) { if (this.allLists[i].dataset.type == type.dataset.type) { targetList = this.allLists[i]; break; } } if (!targetList) return; if (type.classList.contains("input-hide")) { targetList.classList.add("input-hide"); } else targetList.classList.remove("input-hide"); }); let showType = this.bar.querySelector(".search-jumper-type:not(.input-hide)"); if (showType) { if (!showType.classList.contains("search-jumper-open")) { let typeBtn = showType.querySelector("span.search-jumper-btn"); if (typeBtn.onmousedown) { typeBtn.onmousedown(); } else { let mouseEvent = new PointerEvent("mousedown"); typeBtn.dispatchEvent(mouseEvent); } } if (this.searchJumperExpand.parentNode == showType) { let mouseEvent = new PointerEvent("click"); this.searchJumperExpand.dispatchEvent(mouseEvent); } } } globMatch(glob, target, inner) { if (target.length > 500) return false; try { if (glob.length == 0 || glob === '*') { return true; } if (glob.length === 1 && glob[0] === '$') { return !target || target.length === 0; } if (glob.length > 1 && glob[0] === '*' && (!target || target.length === 0)) { return false; } if (!inner) { inner = true; if (glob.length > 1 && glob[0] === '^' && target && target.length !== 0) { glob = glob.substring(1); if (glob[0] !== target[0]) { return false; } } else if (glob[0] !== '*') { glob = '*' + glob; } } if ((glob.length > 1 && glob[0] === '?') || (glob.length != 0 && target && target.length !== 0 && glob[0] === target[0])) { return this.globMatch(glob.substring(1), target.substring(1), !!inner); } if (glob.length > 0 && glob[0] === '*') { return this.globMatch(glob.substring(1), target, !!inner) || this.globMatch(glob, target && target.substring(1), !!inner); } } catch(e) { debug(e); } return false; } setCurrentSite(data, siteEle) { currentSite = data; siteEle.classList.add('current'); localKeywords = ""; if (!/#p{|^(showTips|find)/.test(data.url) && wordParamReg.test(data.url)) { this.updateCacheKeywords(); storage.setItem("referrer", location.hostname); } } updateCacheKeywords() { let keywords = getKeywords(); if (keywords && keywords != cacheKeywords) { cacheKeywords = keywords; storage.setItem("cacheKeywords", keywords); } } refresh() { if (this.refreshInPageTimer) { clearTimeout(this.refreshInPageTimer); } this.refreshInPageTimer = setTimeout(() => { let oldWords = this.curHighlightWords; this.highlight(""); this.highlight(oldWords); if (this.bar.style.display == "none") { currentSite = null; let typeData; for (let i in searchData.sitesConfig) { if (currentSite) break; typeData = searchData.sitesConfig[i]; if (!typeData) { continue; } let sites = typeData.sites; for (let j in sites) { if (currentSite) break; let data = sites[j]; if (!data || !data.url) { continue; } let currentData; if (data.match === '0') { } else if (data.match) { if (new RegExp(data.match).test(href)) { currentData = data; } } else if (data.url.indexOf(location.hostname) != -1) { if (data.url.indexOf("site") != -1) { let siteMatch = data.url.match(/site(%3A|:)([\s\S]+?)[\s%]/); if (siteMatch && href.indexOf(siteMatch[2]) != -1 && data.url.replace(siteMatch[0], "").indexOf(location.hostname) != -1) { currentData = data; } } else if (!currentSite && data.url.replace(/^https?:\/\//, "").replace(location.host, "").replace(/\/?[\?#][\s\S]*/, "") == location.pathname.replace(/\/$/, "")) { let urlReg = data.url.match(/[^\/\?&]+(?=%[stb])/g); if (urlReg) { urlReg = urlReg.join('.*'); if (new RegExp(urlReg).test(href)) { currentData = data; } } } } if (currentData) { let siteEle = this.getTargetSitesByName([currentData.name])[0]; this.currentType = siteEle.parentNode; this.setCurrentSite(currentData, siteEle); } } } if (currentSite && wordParamReg.test(currentSite.url) && (!/#p{/.test(currentSite.url) || currentSite.keywords) && !searchData.prefConfig.hideOnSearchEngine) { if (this.currentType.classList.contains("search-jumper-targetAll") || this.currentType.classList.contains("search-jumper-targetImg") || this.currentType.classList.contains("search-jumper-targetAudio") || this.currentType.classList.contains("search-jumper-targetVideo") || this.currentType.classList.contains("search-jumper-targetLink") || this.currentType.classList.contains("search-jumper-targetPage")) { return; } this.appendBar(); this.bar.style.display = ""; this.initPos(); let typeBtn = this.bar.querySelector(`.search-jumper-type[data-type="${typeData.type}"]>span`); if (typeBtn && !typeBtn.classList.contains("search-jumper-open")) { this.bar.insertBefore(typeBtn.parentNode, this.bar.children[0]); if (!searchData.prefConfig.disableAutoOpen && !searchData.prefConfig.disableTypeOpen) { if (typeBtn.onmousedown) { typeBtn.onmousedown(); } else { let mouseEvent = new PointerEvent("mousedown"); typeBtn.dispatchEvent(mouseEvent); } } } } } }, 500); } initSort() { if (searchData.prefConfig.shiftLastUsedType && this.historyTypeEle) { if (currentSite) { this.bar.insertBefore(this.historyTypeEle, this.bar.children[1]); } else { this.bar.insertBefore(this.historyTypeEle, this.bar.children[0]); } } if (searchData.prefConfig.sortType) { let self = this; searchTypes.sort((a, b) => { let aTypeValue = sortTypeNames[a.dataset.type] || 0; let bTypeValue = sortTypeNames[b.dataset.type] || 0; return bTypeValue - aTypeValue; }); let changed = false; let allHide = !self.bar.children[0].classList.contains("search-jumper-open"); for (let i = searchTypes.length - 1; i >= 0; i--) { let typeEle = searchTypes[i]; let curValue = sortTypeNames[typeEle.dataset.type] || 0; if (i == searchTypes.length - 1) { if (curValue > 0) { changed = true; sortTypeNames[typeEle.dataset.type] = 0; } } else { let preValue = sortTypeNames[searchTypes[i + 1].dataset.type] || 0; if (curValue - preValue > 10) { changed = true; sortTypeNames[typeEle.dataset.type] = preValue + 10; } } self.bar.insertBefore(typeEle, self.bar.children[allHide ? 0 : 1]); } if (changed) storage.setItem("sortTypeNames", sortTypeNames); } } initHistorySites() { this.historySiteBtns = []; this.txtHistorySiteBtns = []; this.imgHistorySiteBtns = []; this.linkHistorySiteBtns = []; this.videoHistorySiteBtns = []; this.audioHistorySiteBtns = []; let self = this; historySites.forEach(async n => { for (let siteConfig of searchData.sitesConfig) { let found = false; let isBookmark = siteConfig.bookmark || siteConfig.sites.length > 100 || (/^BM/.test(siteConfig.type) && siteConfig.icon === "bookmark"); for (let i = 0; i < siteConfig.sites.length; i++) { let site = siteConfig.sites[i]; if (site.name == n) { let siteBtn = await self.createSiteBtn((searchData.prefConfig.noIcons ? "0" : site.icon), site, true, isBookmark, siteConfig, true); siteBtn.classList.add("historySite"); self.historySiteBtns.push(siteBtn); if (!siteConfig.selectImg && !siteConfig.selectLink && !siteConfig.selectPage && !siteConfig.selectVideo && !siteConfig.selectAudio) { self.txtHistorySiteBtns.push(siteBtn); } if (siteConfig.selectImg) { self.imgHistorySiteBtns.push(siteBtn); } if (siteConfig.selectLink || siteConfig.selectPage) { self.linkHistorySiteBtns.push(siteBtn); } if (siteConfig.selectVideo) { self.videoHistorySiteBtns.push(siteBtn); } if (siteConfig.selectAudio) { self.audioHistorySiteBtns.push(siteBtn); } found = true; break; } } if (found) break; } }); } insertHistory(typeEle, init) { if (!searchData.prefConfig.historyLength) { return; } typeEle.style.width = "auto"; typeEle.style.height = "auto"; let self = this; this.historyInserted = true; let num = 0; let toFirst = !init && searchData.prefConfig.historyInsertFirst; let insertBefore = false, maxSiteNum = 0; if (!toFirst) { insertBefore = this.searchJumperExpand.parentNode == typeEle && !searchData.prefConfig.expandType; if (insertBefore) { maxSiteNum = (searchData.prefConfig.numPerLine || 7) - 1; maxSiteNum = searchData.prefConfig.historyLength < maxSiteNum ? (maxSiteNum + maxSiteNum - searchData.prefConfig.historyLength) : maxSiteNum; if (searchData.prefConfig.hideTileType) { maxSiteNum++; } } } let historySiteBtns = this.historySiteBtns; if (typeEle.classList.contains("search-jumper-needInPage")) { historySiteBtns = this.txtHistorySiteBtns; } else if (typeEle.classList.contains("search-jumper-targetImg")) { historySiteBtns = this.imgHistorySiteBtns; } else if (typeEle.classList.contains("search-jumper-targetAudio")) { historySiteBtns = this.audioHistorySiteBtns; } else if (typeEle.classList.contains("search-jumper-targetVideo")) { historySiteBtns = this.videoHistorySiteBtns; } else if (typeEle.classList.contains("search-jumper-targetLink") || typeEle.classList.contains("search-jumper-targetPage")) { historySiteBtns = this.linkHistorySiteBtns; } for (let i = 0; i < historySiteBtns.length; i++) { let btn = historySiteBtns[i]; if (btn.style.display == "none") continue; let siteImg = btn.querySelector('img'); if (siteImg && siteImg.dataset.src) { siteImg.src = siteImg.dataset.src; delete siteImg.dataset.src; } if (btn.parentNode != typeEle) { let sites = typeEle.querySelectorAll("a.search-jumper-btn"); let findSame = false; for (let j = 0; j < sites.length; j++) { let site = sites[j]; if ((site.dataset.oriName || site.dataset.name) == (btn.dataset.oriName || btn.dataset.name)) { findSame = true; break; } } if (findSame) continue; if (toFirst) { if (typeEle.children.length > 1) { typeEle.insertBefore(btn, typeEle.children[1]); } else typeEle.appendChild(btn); } else { if (insertBefore) { let siteBtns = typeEle.querySelectorAll("a.search-jumper-btn"); if (siteBtns.length > maxSiteNum) { typeEle.insertBefore(btn, siteBtns[maxSiteNum]); } else typeEle.insertBefore(btn, self.searchJumperExpand); } else typeEle.appendChild(btn); } if (++num >= searchData.prefConfig.historyLength) break; } else if (toFirst) { if (typeEle.children.length > 1) { typeEle.insertBefore(btn, typeEle.children[1]); } else typeEle.appendChild(btn); } } typeEle.style.width = typeEle.scrollWidth + "px"; typeEle.style.height = typeEle.scrollHeight + "px"; } recoveHistory() { if (!searchData.prefConfig.historyLength) return; if (!this.historyInserted) return; this.historyInserted = false; let self = this; let curParent; for (let i = 0; i < this.historySiteBtns.length; i++) { let btn = this.historySiteBtns[i]; if (!btn.classList.contains("historySite")) continue; curParent = btn.parentNode; this.siteBtnReturnHome(btn); } if (curParent && curParent.classList.contains("search-jumper-open")) { curParent.style.width = "auto"; curParent.style.height = "auto"; curParent.style.width = curParent.scrollWidth + "px"; curParent.style.height = curParent.scrollHeight + "px"; } } bindSite(a, siteEle) { if (a.getAttribute("bind")) return; a.setAttribute("bind", true); let self = this; if (siteEle.href) a.href = siteEle.href; a.style.display = siteEle.style.display; a.addEventListener('mousedown', async e => { if (siteEle.dataset.showTips) { if (self.con.classList.contains("search-jumper-showall")) { targetElement = a.parentNode; } else self.waitForHide(0); siteEle.dispatchEvent(new CustomEvent('showTips')); } else { await self.siteSetUrl(siteEle, {button: e.button, altKey: e.altKey, ctrlKey: e.ctrlKey, shiftKey: e.shiftKey, metaKey: e.metaKey}); if (siteEle.href) a.href = siteEle.href; a.setAttribute("target", siteEle.target); } if (!a.onclick) { a.onclick = e => { if (!siteEle.dataset.showTips) siteEle.click(); e.stopPropagation(); e.preventDefault(); return false; } } }, false); a.addEventListener("dragover", e => { e.preventDefault(); }, true); a.addEventListener("dragenter", e => { if (self.dragTarget) { self.dragTarget.classList.remove("dragTarget"); } self.dragTarget = a; self.dragTarget.classList.add("dragTarget"); clearTimeout(self.dragTimer); self.dragTimer = setTimeout(() => { a.scrollIntoView({behavior: "smooth", block: "center", inline: "center"}); }, 1000); }, true); a.addEventListener("dragleave", e => { a.classList.remove("dragTarget"); }, true); a.addEventListener("drop", e => { clearTimeout(self.dragTimer); if (self.dragTarget) { self.dragTarget.classList.remove("dragTarget"); } self.searchBySiteName(siteEle.dataset.name, e); }, true); } async createList(sites, type, batchSiteNames) { let self = this; let list = document.createElement("div"); list.className = "sitelist"; list.style.visibility = "hidden"; let con = document.createElement("div"); con.className = "sitelistCon"; list.appendChild(con); list.addEventListener('mouseenter', e => { self.listArrow.style.cssText = ""; }); let title = document.createElement("p"); title.innerText = type.dataset.title; title.title = i18n('batchOpen'); title.addEventListener('click', e => { self.batchOpen(batchSiteNames, {ctrlKey: e.ctrlKey, shiftKey: e.shiftKey, altKey: e.altKey, metaKey: e.metaKey, button: (e.ctrlKey || e.shiftKey || e.altKey || e.metaKey) ? 0 : 2}); }); list.dataset.type = type.dataset.type; con.appendChild(title); function createItem(siteEle, index) { let li = document.createElement("div"); li.id = "list" + index; let icon = siteEle.querySelector("img"); let a = document.createElement("a"); a.setAttribute("ref", "noopener noreferrer"); self.bindSite(a, siteEle); li.appendChild(a); self.allListBtns.push(li); if (icon && !searchData.prefConfig.noIcons) { let iconSrc = icon.src || icon.dataset.src; let img = document.createElement("img"); a.appendChild(img); img.onload = e => { img.style.width = ""; img.style.height = ""; img.style.display = ""; }; img.onerror = e => { img.src = noImgBase64; }; img.style.width = "1px"; img.style.height = "1px"; img.style.display = "none"; if (iconSrc) { if (!/^data:/.test(iconSrc)) { img.οnerrοr = e => { img.src = noImgBase64; img.onerror = null; img.style.width = ""; img.style.height = ""; img.style.display = ""; }; img.dataset.src = iconSrc; } else { img.dataset.src = iconSrc; } } else { img.dataset.src = noImgBase64; } } let p = document.createElement("p"); p.innerText = siteEle.dataset.name; li.title = siteEle.title; li.dataset.name = siteEle.dataset.name; a.appendChild(p); con.appendChild(li); } try { for (let [index, siteEle] of sites.entries()) { createItem(siteEle, siteEle.dataset.id); if (index%50 === 49) await sleep(1); } } catch(e) { for (let index = 0; index < sites.length; index++) { let siteEle = sites[index]; createItem(siteEle, siteEle.dataset.id); } } this.allLists.push(list); return list; } async initList(list) { if (!list.dataset.inited) { list.style.display = "none"; list.dataset.inited = true; [].forEach.call(list.querySelectorAll("div>a>img"), img => { if (img.dataset.src) { img.src = img.dataset.src; delete img.dataset.src; } }); await sleep(0); } } async listPos(ele, list) { //if (this.preList) { //this.preList.style.visibility = "hidden"; //} await this.initList(list); list.style = ""; this.preList = list; let ew = ele.clientWidth; let eh = ele.clientHeight; let clientX = ele.offsetLeft + ew / 2 - this.con.scrollLeft; let clientY = ele.offsetTop + eh / 2 - this.con.scrollTop; let current = ele.offsetParent; while (current !== null){ clientX += current.offsetLeft; clientY += current.offsetTop; current = current.offsetParent; } let viewWidth = window.innerWidth || document.documentElement.clientWidth; let viewHeight = window.innerHeight || document.documentElement.clientHeight; let arrowStyle = this.listArrow.style; arrowStyle.visibility = "visible"; arrowStyle.opacity = 1; if (this.funcKeyCall) { list.style.display = "block"; arrowStyle.opacity = 0; const clientRect = ele.getBoundingClientRect(); clientX = clientRect.x + ew / 2 - this.con.scrollLeft; clientY = clientRect.y + eh / 2 - this.con.scrollTop; clientX -= list.clientWidth / 2; let actualTop = ele.getBoundingClientRect().top; if (actualTop > viewHeight / 2) { if (actualTop < list.clientHeight + 10) { list.style.height = actualTop - 20 + "px"; } clientY -= (list.clientHeight + eh / 2 + 5); } else { clientY += (eh / 2 + 5); if (actualTop + list.clientHeight + eh + 10 > viewHeight) { list.style.height = viewHeight - actualTop - eh - 20 + "px"; } } if (clientX < 20) clientX = 20; let maxLeft = viewWidth - list.clientWidth - 30; if (clientX > maxLeft) { clientX = maxLeft; } list.style.left = clientX + "px"; list.style.top = clientY + "px"; list.style.display = ""; } else if (this.bar.clientWidth > this.bar.clientHeight) { //横 let arrowX = clientX; if (clientX < 30) { arrowX = 30; } else if (clientX > viewWidth - 40) { arrowX = viewWidth - 40; } arrowStyle.left = arrowX - 10 + "px"; if (clientY - eh / 2 < 100) { list.style.top = this.bar.clientHeight + "px"; arrowStyle.top = this.bar.clientHeight - 10 + "px"; } else { list.style.bottom = this.bar.clientHeight + "px"; arrowStyle.bottom = this.bar.clientHeight - 9 + "px"; } clientX -= list.scrollWidth / 2; if (clientX > viewWidth - list.scrollWidth - 10) clientX = viewWidth - list.scrollWidth - 10; if (clientX < 0) clientX = 0; list.style.left = clientX + "px"; } else { //竖 let arrowY = clientY; if (clientY < 30) { arrowY = 30; } else if (clientY > viewHeight - 30) { arrowY = viewHeight - 30; } arrowStyle.top = arrowY - 10 + "px"; if (clientX - ew / 2 < 100) { list.style.left = this.bar.clientWidth + "px"; arrowStyle.left = this.bar.clientWidth - 9 + "px"; } else { list.style.right = this.bar.clientWidth + "px"; arrowStyle.right = this.bar.clientWidth - 9 + "px"; } clientY -= list.scrollHeight / 2; if (clientY > viewHeight - list.scrollHeight) clientY = viewHeight - list.scrollHeight; if (clientY < 0) clientY = 0; list.style.top = clientY + "px"; list.style.maxHeight = "100vh"; } } clingPos(clingEle, target, close) { //if (this.preList) { //this.preList.style.visibility = "hidden"; //} let ew = clingEle.clientWidth || clingEle.offsetWidth; let eh = clingEle.clientHeight || clingEle.offsetHeight; /*let clientX = clingEle.offsetLeft + ew / 2 - this.con.scrollLeft; let clientY = clingEle.offsetTop + eh / 2 - this.con.scrollTop - clingEle.parentNode.scrollTop; let current = clingEle.offsetParent;*/ const clientRect = clingEle.getBoundingClientRect(); let clientX, clientY; let showall = this.con && this.con.classList.contains("search-jumper-showall"); /*while (current !== null){ clientX += current.offsetLeft; clientY += current.offsetTop; current = current.offsetParent; }*/ let viewWidth = window.innerWidth || document.documentElement.clientWidth; let viewHeight = window.innerHeight || document.documentElement.clientHeight; this.tips.style.position = ""; target.style.height = ""; if (!clingEle || /^(body|html)$/i.test(clingEle.nodeName)) { this.tips.style.transition = "none"; this.tips.style.position = "fixed"; target.style.right = ""; target.style.bottom = ""; target.style.left = (viewWidth - target.clientWidth) / 2 + "px"; target.style.top = "min(11%,110px)"; } else if (showall) { clientX = clientRect.x + ew / 2; clientY = clientRect.y + eh / 2; clientX -= target.clientWidth / 2 - this.con.scrollLeft; clientY += this.con.scrollTop; if (clientY > viewHeight / 2) clientY -= (target.clientHeight + eh / 2 + 10); else clientY += (eh / 2 + 10); target.style.right = ""; target.style.bottom = ""; target.style.left = clientX + "px"; target.style.top = clientY + "px"; } else if (this.funcKeyCall) { let scrollTop = window.pageYOffset || document.documentElement.scrollTop || getBody(document).scrollTop; let scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || getBody(document).scrollLeft; clientX = clientRect.x + ew / 2 - this.con.scrollLeft + scrollLeft; clientY = clientRect.y + eh / 2 - this.con.scrollTop + scrollTop; clientX -= target.clientWidth / 2; let actualTop = clingEle.getBoundingClientRect().top; if (actualTop > viewHeight / 2) { if (actualTop < target.clientHeight + 10) { target.style.height = actualTop - 20 + "px"; } clientY -= (target.clientHeight + eh / 2 + 5); } else { clientY += (eh / 2 + 5); if (actualTop + target.clientHeight + eh + 10 > viewHeight) { target.style.height = viewHeight - actualTop - eh - 20 + "px"; } } if (clientX < 20) clientX = 20; let maxLeft = viewWidth + scrollLeft - target.clientWidth - 30; if (clientX > maxLeft) { clientX = maxLeft; } target.style.right = ""; target.style.bottom = ""; target.style.left = clientX + "px"; target.style.top = clientY + "px"; } else { clientX = clingEle.offsetLeft + ew / 2 - this.con.scrollLeft - clingEle.parentNode.scrollLeft; clientY = clingEle.offsetTop + eh / 2 - this.con.scrollTop - clingEle.parentNode.scrollTop; let current = clingEle.offsetParent; while (current !== null){ clientX += current.offsetLeft; clientY += current.offsetTop; current = current.offsetParent; } if (clientY < eh) { clientX -= target.clientWidth / 2; clientY += target.clientHeight / 2; if (clientX < 5) { clientX = 5; target.style.left = "5px"; target.style.right = ""; target.style.bottom = ""; } else if (clientX > viewWidth - target.clientWidth) { target.style.left = ""; target.style.right = "5px"; target.style.bottom = ""; } else { target.style.left = clientX + "px"; target.style.right = ""; target.style.bottom = ""; } target.style.top = (close ? eh : eh + 20) + "px"; } else if (clientY > viewHeight - eh - 10) { clientX -= target.clientWidth / 2; if (clientX < 5) { target.style.left = "5px"; target.style.right = ""; target.style.top = ""; } else if (clientX > viewWidth - target.clientWidth) { target.style.left = ""; target.style.right = "5px"; target.style.top = ""; } else { target.style.left = clientX + "px"; target.style.right = ""; target.style.top = ""; } target.style.bottom = (close ? eh : eh + 20) + "px"; } else if (clientX > viewWidth - ew - 10) { target.style.left = ""; target.style.bottom = ""; clientY -= target.clientHeight / 2; if (clientY < 5) clientY = 5; target.style.right = (close ? ew : ew + 20) + "px"; target.style.top = clientY + "px"; } else if (clientX < ew) { target.style.right = ""; target.style.bottom = ""; clientY -= target.clientHeight / 2; if (clientY < 5) clientY = 5; target.style.left = (close ? ew : ew + 20) + "px"; target.style.top = clientY + "px"; } else { target.style.right = ""; target.style.bottom = ""; target.style.left = clientX + "px"; target.style.top = clientY + "px"; } } } tipsPos(ele, type) { this.tips.innerHTML = createHTML(type); this.tips.style.pointerEvents = ""; this.tips.style.display = ""; this.tips.style.opacity = 1; this.clingPos(ele, this.tips); clearTimeout(this.hideTips); if (this.tips.style.transition) { setTimeout(() => { this.tips.style.transition = ""; }, 1); } let self = this; [].forEach.call(this.tips.querySelectorAll('iframe'), iframe => { let html = iframe.innerHTML; if (html) { iframe.innerHTML = createHTML(); if (iframe.src) { iframe.addEventListener('load', e => { try { if (!iframe || !iframe.parentNode) return; let doc = iframe.contentDocument || iframe.contentWindow.document; let div = doc.createElement('div'); doc.body.appendChild(div); div.outerHTML = createHTML(html); } catch(e) {} }); } else { try { let doc = iframe.contentDocument || iframe.contentWindow.document; doc.open(); doc.write(html); doc.close(); } catch(e) {} } } }); [].forEach.call(this.tips.querySelectorAll('img,video'), media => { media.addEventListener('load', e => { self.clingPos(ele, self.tips); }); }); if (window.markdownit) { if (!self.md) { self.md = window.markdownit(); } [].forEach.call(this.tips.querySelectorAll('.markdown'), markdown => { markdown.innerHTML = createHTML(self.md.render(markdown.innerHTML)); }); } } checkKwFilter(kwFilter, checkKw) { if (checkKw.length > 600) { checkKw = checkKw.slice(0, 500) + checkKw.slice(checkKw.length - 10); } let selectorMatch = kwFilter.match(/^@{(.*?)}/); if (selectorMatch) { if (!targetElement) return false; let selector = selectorMatch[1]; let pass = [].some.call(getAllElements(selector, document), e => e === targetElement); if (!pass) return false; kwFilter = kwFilter.replace(selectorMatch[0], ""); } let kwRe, fullMatch = kwFilter.match(/^\/(.*)\/(\w*)$/); if (fullMatch) { kwRe = new RegExp(fullMatch[1], fullMatch[2]); } else { kwRe = new RegExp(kwFilter, "i"); } return (kwRe.test(checkKw || "")); } async createType(data) { let self = this; let type = data.type; let icon = data.icon; let inPage = data.selectTxt; let selectImg = data.selectImg; let selectAudio = data.selectAudio; let selectVideo = data.selectVideo; let selectLink = data.selectLink; let selectPage = data.selectPage; let sites = data.sites; let match = false; let openInNewTab = typeof data.openInNewTab === 'undefined' ? searchData.prefConfig.openInNewTab : data.openInNewTab; let siteEles = []; let ele = document.createElement("span"); ele.className = "search-jumper-type"; if (!searchData.prefConfig.expandType && sites.length > 10) ele.classList.add("not-expand"); if (data.match === '0') { ele.style.display = 'none'; ele.classList.add("notmatch"); } else if (data.match) { if (new RegExp(data.match).test(href) == false) { ele.style.display = 'none'; ele.classList.add("notmatch"); } else { match = true; } } if (typeof data.description !== 'undefined') { ele.dataset.title = type + " - " + data.description; } else { ele.dataset.title = type; } ele.dataset.type = type; let typeBtn = document.createElement("span"); let img = document.createElement("img"); let iEle = document.createElement("b"); if (type.length >= 3) { iEle.innerText = type.trim().substr(0, 4); if (!/^[\w \-]+$/.test(iEle.innerText.substr(0, 3))) iEle.innerText = iEle.innerText.substr(0, 2); } else iEle.innerText = type; typeBtn.appendChild(iEle); img.style.display = "none"; ele.appendChild(typeBtn); typeBtn.classList.add("search-jumper-word"); typeBtn.classList.add("search-jumper-btn"); typeBtn.classList.add("noIcon"); let isBookmark = /^BM/.test(type) && data.icon === "bookmark";//書簽就不緩存了 if (icon) { typeBtn.classList.remove("noIcon"); let isFontIcon = /^[a-z\- ]+$/.test(icon); img.onload = e => { img.style.display = ""; iEle.innerText = ''; iEle.style.display = 'none'; if (!isFontIcon) { typeBtn.classList.remove("search-jumper-word"); } }; if (isFontIcon) { let cache = cacheIcon[icon.trim().replace(/ /g, '_')]; if (cache === 'fail' || !cache) { iEle.className = icon.indexOf("fa") === 0 ? icon : "fa fa-" + icon; this.fontPool.push(iEle); } else { img.src = cache; img.style.width = '100%'; img.style.height = '100%'; typeBtn.appendChild(img); } } else { let isBase64 = /^data:/.test(icon); if (isBase64) { img.src = icon; } else { let cache = searchData.prefConfig.cacheSwitch && cacheIcon[icon]; if (cache === 'fail') { } else if (cache) { img.src = cache; } else { img.src = icon; if (!cacheIcon[icon] && !isBookmark) cachePool.push(img); } } typeBtn.appendChild(img); } } ele.addEventListener('mouseleave', e => { self.listArrow.style.cssText = ""; self.dockerScaleBtns.forEach(btn => { btn.style.setProperty("--scale", 1); }); }); let batchSiteNames = []; let batchOpenConfirm = (e) => { switch (searchData.prefConfig.batchOpenConfirm) { case 1: if (window.confirm(i18n('batchOpenConfirm'))) { self.batchOpen(batchSiteNames, e); } break; case 2: self.batchOpen(batchSiteNames, e); break; default: if (ele.classList.contains("search-jumper-open") || (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey) || window.confirm(i18n('batchOpenConfirm'))) { self.batchOpen(batchSiteNames, e); } break; } }; if (searchData.prefConfig.shortcut && data.shortcut && !ele.classList.contains("notmatch")) { let shortcurStr = data.shortcut.replace('Key', '').replace('Digit', '').toUpperCase(); if (shortcurStr.length == 1) ele.dataset.title += ` (${shortcurStr})`; document.addEventListener('keydown', e => { if (e.target.id === "searchJumperInput") return; if ((!data.ctrl == e.ctrlKey) || (!data.alt == e.altKey) || (!data.shift == e.shiftKey) || (!data.meta == e.metaKey)) { return; } if (!searchData.prefConfig.enableInInput && !data.ctrl && !data.alt && !data.shift && !data.meta) { if (inputActive(document)) return; } var key = (e.key || String.fromCharCode(e.keyCode)).toLowerCase(); if (data.shortcut == e.code || data.shortcut == key) { batchOpenConfirm(e); e.stopPropagation(); } }); } let shownSitesNum = 0; let baseSize = this.scale * 40; let taggleHide = (se, show) => { if (show) { se.style.display = ''; if (ele.children.length > 2) ele.insertBefore(se, ele.children[2]); } else { se.style.display = 'none'; if (self.searchJumperExpand.parentNode == ele) { ele.insertBefore(se, self.searchJumperExpand); } else ele.appendChild(se); } } let typeAction = e => { if (e) { if (e.button === 2) { batchOpenConfirm(e); return false; } if (e.button === 0 && (e.shiftKey || e.altKey || e.ctrlKey)) { return false; } } if (self.funcKeyCall) { self.showAllSites(); return false; } let leftRight = self.con.classList.contains("search-jumper-left") || self.con.classList.contains("search-jumper-right"); if (self.preList) { self.preList.style.visibility = "hidden"; self.listArrow.style.cssText = ""; } ele.classList.remove('search-jumper-move'); if (!ele.classList.contains("search-jumper-open")) { self.recoveHistory(); ele.classList.add("search-jumper-open"); if (searchData.prefConfig.minSizeMode) { self.bar.classList.remove("minSizeModeClose"); } let targetInput = false; if (targetElement) { targetInput = isInput(targetElement); } let href = targetElement && (targetElement.href || targetElement.src); let keyWords = getKeywords(); shownSitesNum = 0; siteEles.forEach((se, i) => { let data = sites[i]; let pass = true; if (data.kwFilter) { let checkKw; if (se.dataset.link) { checkKw = href || keyWords; } else { checkKw = se.dataset.txt ? (keyWords || (targetElement && targetElement.innerText) || "") : (href || keyWords || location.href); } pass = self.checkKwFilter(data.kwFilter, checkKw); } if (pass && se.dataset.paste) { pass = targetInput; taggleHide(se, pass); } else if (data.kwFilter) { taggleHide(se, pass); } let si = se.querySelector("img"); if (se.style.display != "none") { shownSitesNum++; } if (si && !si.src && si.dataset.src) { si.src = si.dataset.src; delete si.dataset.src; } }); if (shownSitesNum > (searchData.prefConfig.expandTypeLength || 12) && !searchData.prefConfig.expandType) { ele.classList.add("not-expand"); ele.appendChild(self.searchJumperExpand); } let scrollSize = Math.max(ele.scrollWidth, ele.scrollHeight) + 5 + "px"; if (searchData.prefConfig.disableTypeOpen) { scrollSize = baseSize + "px"; if (e) self.listPos(ele.children[0], siteList); } if (leftRight) { ele.style.height = scrollSize; ele.style.width = ""; } else { ele.style.width = scrollSize; ele.style.height = ""; } setTimeout(() => { if (ele.classList.contains("search-jumper-open")) { ele.style.flexWrap = "nowrap"; ele.classList.add('search-jumper-move'); } }, searchData.prefConfig.typeOpenTime); searchTypes.forEach(type => { if (ele != type) { type.classList.remove("search-jumper-open"); type.style.width = baseSize + "px"; type.style.height = baseSize + "px"; type.style.flexWrap = ""; } }); } else { if (searchData.prefConfig.minSizeMode) { self.bar.classList.add("minSizeModeClose"); } ele.classList.remove("search-jumper-open"); if (leftRight) { ele.style.height = baseSize + "px"; ele.style.width = ""; } else { ele.style.height = ""; ele.style.width = baseSize + "px"; } ele.style.flexWrap = ""; if (searchData.prefConfig.disableTypeOpen) { siteList.style.visibility = "hidden"; } } if (!searchData.prefConfig.disableTypeOpen) { setTimeout(() => { self.checkScroll(); }, searchData.prefConfig.typeOpenTime); } }; let draged = false, initMousePos, initTilePos; let mouseUpHandler = e => { document.removeEventListener('mouseup', mouseUpHandler); document.removeEventListener('mousemove', mouseMoveHandler); if (!draged) { typeAction(e); } draged = false; } let mouseMoveHandler = e => { if (!draged) { self.tips.style.opacity = 0; draged = true; initMousePos = {x: e.clientX, y: e.clientY}; initTilePos = {x: parseInt(self.bar.style.left), y: parseInt(self.bar.style.top)}; } else { self.bar.style.left = initTilePos.x + e.clientX - initMousePos.x + "px"; self.bar.style.top = initTilePos.y + e.clientY - initMousePos.y + "px"; } } typeBtn.onmouseup = function (e) { if (e && self.funcKeyCall && e.button === 0 && !(e.shiftKey || e.altKey || e.ctrlKey)) { draged = false; e.preventDefault && e.preventDefault(); document.addEventListener('mouseup', mouseUpHandler); document.addEventListener('mousemove', mouseMoveHandler); return; } typeAction(e); }; typeBtn.oncontextmenu = function (e) { e.preventDefault(); }; typeBtn.addEventListener('click', e => { self.batchOpen(batchSiteNames, e); return false; }, false); typeBtn.addEventListener('dblclick', e=>{ e.stopPropagation(); e.preventDefault(); }, true); let showTimer, siteList; let viewWidth = window.screen.availWidth || window.innerWidth || document.documentElement.clientWidth; let viewHeight = window.screen.availHeight || window.innerHeight || document.documentElement.clientHeight; let availableSize = !isMobile || (viewWidth > 600 && viewHeight > 600); ele.addEventListener('sitelist', async e => { ele.appendChild(siteList); await self.listPos(e.detail.bind, siteList); siteList.style.display = "block"; }, false); typeBtn.addEventListener('mouseenter', e => { if (draged) { return; } if (!self.funcKeyCall && searchData.prefConfig.showSiteLists && (searchData.prefConfig.alwaysShowSiteLists || !ele.classList.contains("search-jumper-open"))) { ele.appendChild(siteList); self.listPos(ele.children[0], siteList); } else if (availableSize) { self.tipsPos(typeBtn, ele.dataset.title); } if (searchData.prefConfig.overOpen) { if (ele.classList.contains("search-jumper-open")) return; clearTimeout(showTimer); showTimer = setTimeout(() => { typeAction(e); }, 500); } }, false); typeBtn.addEventListener('mouseleave', e => { self.tips.style.opacity = 0; if (searchData.prefConfig.overOpen) { clearTimeout(showTimer); } }, false); let isCurrent = false; let tooLoog = sites && sites.length > 200; ele.dataset.id = self.siteIndex; self.stopInput = false; async function createItem(site, i) { if (!site.name) return; let siteEle = await self.createSiteBtn((tooLoog || searchData.prefConfig.noIcons ? "0" : site.icon), site, openInNewTab, isBookmark, data); if (!siteEle) { return; } if (!siteEle.classList.contains("notmatch")) { shownSitesNum++; } siteEle.dataset.type = type; siteEle.dataset.id = self.siteIndex; self.siteIndex++; self.allSiteBtns.push([siteEle, site]); ele.appendChild(siteEle); siteEles.push(siteEle); if (!site.nobatch && site.match !== "0") batchSiteNames.push(site.name); if (!isCurrent && !currentSite && (siteEle.dataset.current || match) && !ele.classList.contains("notmatch")) { isCurrent = true; if (siteEle.dataset.current) { if (!searchData.prefConfig.showCurrent) { siteEle.style.display = 'none'; } self.setCurrentSite(site, siteEle); } self.currentType = ele; } } try { for (let [i, site] of sites.entries()) { await createItem(site, i); if (i % 100 === 99) await sleep(1); } } catch(e) { for (let i = 0; i < sites.length; i++) { createItem(sites[i], i); } await sleep(1); } if (searchData.prefConfig.sortSite && ele.children.length > 1) { siteEles.sort((a, b) => { let aSiteValue = sortSiteNames[a.dataset.name] || 0; let bSiteValue = sortSiteNames[b.dataset.name] || 0; return bSiteValue - aSiteValue; }); let changed = false; for (let i = siteEles.length - 1; i >= 0; i--) { let siteEle = siteEles[i]; let curValue = sortSiteNames[siteEle.dataset.name] || 0; if (i == siteEles.length - 1) { if (curValue > 0) { changed = true; sortSiteNames[siteEle.dataset.name] = 0; } } else { let preValue = sortSiteNames[siteEles[i + 1].dataset.name] || 0; if (curValue - preValue > 10) { changed = true; sortSiteNames[siteEle.dataset.name] = preValue + 10; } } ele.insertBefore(siteEle, ele.children[1]); } if (changed) storage.setItem("sortSiteNames", sortSiteNames); } siteEles.forEach(siteEle => { if (siteEle.classList.contains("notmatch")) { ele.appendChild(siteEle); } }); siteList = await self.createList(siteEles, ele, batchSiteNames); if (isCurrent) { if (searchData.prefConfig.currentTypeFirst) { self.bar.insertBefore(ele, self.bar.children[0]); } else { self.bar.insertBefore(ele, self.bar.children[self.bar.children.length - 1]); } if (!searchData.prefConfig.disableAutoOpen && !searchData.prefConfig.disableTypeOpen) { ele.classList.add("search-jumper-open"); ele.classList.add('search-jumper-move'); if (shownSitesNum > (searchData.prefConfig.expandTypeLength || 12) && !searchData.prefConfig.expandType) { ele.classList.add("not-expand"); ele.appendChild(self.searchJumperExpand); } let shownIconNum = -1, waitIconList = []; if (document.readyState !== 'complete') { shownIconNum = 3; let loadHandler = e => { if (document.readyState === "complete") { document.removeEventListener("readystatechange", loadHandler); window.removeEventListener('load', loadHandler); waitIconList.forEach(icon => { if (icon && !icon.src && icon.dataset.src) { icon.src = icon.dataset.src; delete icon.dataset.src; } }); waitIconList = []; } }; document.addEventListener("readystatechange", loadHandler); window.addEventListener('load', loadHandler); } siteEles.forEach((se, i) => { let si = se.querySelector("img"); let data = sites[i]; if (data && localKeywords && data.kwFilter) { let pass = self.checkKwFilter(data.kwFilter, localKeywords); if (pass) { se.style.display = ''; } else { se.style.display = 'none'; if (self.searchJumperExpand.parentNode == ele) { ele.insertBefore(se, self.searchJumperExpand); } else ele.appendChild(se); } } if (se.style.display != 'none' && si && !si.src && si.dataset.src) { if (shownIconNum >= 0 && !/^data/.test(si.dataset.src)) { if (shownIconNum !== 0) { shownIconNum--; } else { waitIconList.push(si); return; } } si.src = si.dataset.src; delete si.dataset.src; } }); } } else { if (!self.historyTypeEle) { if (historyType == type) { self.historyTypeEle = ele; } } self.bar.insertBefore(ele, self.bar.children[self.bar.children.length - 1]); } ele.style.width = ele.scrollHeight + "px"; ele.style.height = ele.scrollHeight + "px"; siteList.style.display = "none"; ele.appendChild(siteList); if (inPage && selectImg && selectAudio && selectVideo && selectLink && selectPage) { ele.classList.add("search-jumper-targetAll"); } else { if (inPage) { ele.classList.add("search-jumper-needInPage"); } if (selectImg) { ele.classList.add("search-jumper-targetImg"); } if (selectAudio) { ele.classList.add("search-jumper-targetAudio"); } if (selectVideo) { ele.classList.add("search-jumper-targetVideo"); } if (selectLink) { ele.classList.add("search-jumper-targetLink"); } if (selectPage) { ele.classList.add("search-jumper-targetPage"); } } searchTypes.push(ele); return ele; } async openSiteBtn(siteEle, forceTarget, active = false) { await this.siteSetUrl(siteEle); let isPage = siteEle.dataset.isPage; if (!forceTarget) forceTarget = "_blank"; if (isPage) { siteEle.setAttribute("target", forceTarget); } if (isPage && forceTarget == "_blank" && siteEle.href) { _GM_openInTab(siteEle.href, {active: active, insert: true}); } else { siteEle.click(); } siteEle.setAttribute("target", siteEle.dataset.target == 1 ? "_blank" : "_self"); } async batchOpen(siteNames, e, newTab) { let self = this; self.batchOpening = true; self.customInput = false; if (e.altKey && e.shiftKey) { let targetSites = self.getTargetSitesByName(siteNames); let viewWidth = window.innerWidth || document.documentElement.clientWidth; let html = '<title>SearchJumper Multi</title><style>body{background: black; margin: 0;}iframe{box-sizing: border-box;padding: 5px}</style>'; let c = window.open("", "_blank"), i = 1; for (let siteEle of targetSites) { if (siteEle.dataset.isPage) { await self.siteSetUrl(siteEle); if (self.stopInput) return; if (!siteEle.href) continue; let iframe = document.createElement('iframe'); iframe.width = targetSites.length <= 2 || viewWidth <= 1280 ? '50%' : '33%'; iframe.height = '100%'; iframe.frameBorder = '0'; iframe.sandbox = "allow-same-origin allow-scripts allow-popups allow-forms"; iframe.id = "searchJumper" + i++; iframe.style.display = "none"; html += iframe.outerHTML; _GM_xmlhttpRequest({ method: 'GET', url: siteEle.href, headers: { referer: siteEle.href, origin: siteEle.href, 'User-Agent': navigator.userAgent }, onload: function(d) { let curIframe = c.document.querySelector('iframe#' + iframe.id); let waitReady = () => { let doc = curIframe.contentDocument || (curIframe.contentWindow && curIframe.contentWindow.document); if (doc) { try { curIframe.style.display = ""; curIframe.src = siteEle.href; let base = `<base href="${siteEle.href.replace(/[^\/]*$/, "")}" />`; let docContent = d.response.indexOf("<head") !== -1 ? d.response.replace(/(\<head.*?\>)/, "$1" + base) : base + d.response; doc.write(docContent); } catch(e) { } } else { setTimeout(() => { waitReady(); }, 500); } }; if (curIframe) { waitReady(); } }, onerror: function(e){ debug(e); }, ontimeout: function(e){ debug(e); } }); } } c.document.write(html); c.document.close(); } else if ((e.ctrlKey || e.metaKey) && e.shiftKey) { let targetSites = self.getTargetSitesByName(siteNames); for (let siteEle of targetSites) { await self.siteSetUrl(siteEle); if (self.stopInput) return; if (siteEle.dataset.isPage && siteEle.href) { let target = {}; if (targetElement) { target = {src: targetElement.src || targetElement.href || '', title: targetElement.title || targetElement.alt}; } siteNames = siteNames.filter(n => n !== siteEle.dataset.name); storage.setItem("lastSign", {target: target, sites: siteNames}); setTimeout(() => { _GM_openInTab(siteEle.href, {incognito: true}); }, 300); setTimeout(() => { storage.setItem("lastSign", false); }, 2000); break; } } } else if (e.altKey) { let targetSites = self.getTargetSitesByName(siteNames); let urls=[]; for (let siteEle of targetSites) { if (siteEle.dataset.isPage) { await self.siteSetUrl(siteEle); if (self.stopInput) return; if (!siteEle.href) continue; urls.push(siteEle.href); } } let viewWidth = window.screen.availWidth || window.innerWidth || document.documentElement.clientWidth; let viewHeight = window.screen.availHeight || window.innerHeight || document.documentElement.clientHeight; let numPerLine = parseInt(viewWidth / 800); if (numPerLine > urls.length) numPerLine = urls.length; let _width = parseInt(viewWidth / numPerLine); let _height = viewHeight / (parseInt((urls.length - 1) / numPerLine) + 1) - 65; for (let i = 0; i < urls.length; i++) { let left = (i % numPerLine) * _width; let top = parseInt(i / numPerLine) * (_height + 70); window.open(urls[i] + "#searchJumperMin", "_blank", `width=${_width-10}, height=${_height}, location=0, resizable=1, status=0, toolbar=0, menubar=0, scrollbars=0, left=${left}, top=${top}`); } } else if (e.shiftKey) { let targetSites = self.getTargetSitesByName(siteNames); for (let siteEle of targetSites) { await self.siteSetUrl(siteEle); if (self.stopInput) return; if (siteEle.dataset.isPage && siteEle.href) { let target = {}; if (targetElement) { target = {src: targetElement.src || targetElement.href || '', title: targetElement.title || targetElement.alt}; } siteNames = siteNames.filter(n => n !== siteEle.dataset.name); storage.setItem("lastSign", {target: target, sites: siteNames}); window.open(siteEle.href, '_blank'); setTimeout(() => { storage.setItem("lastSign", false); }, 2000); break; } } } else if (e.ctrlKey || e.metaKey) { let targetSites = self.getTargetSitesByName(siteNames).reverse(); for (let siteEle of targetSites) { await self.siteSetUrl(siteEle); let isPage = siteEle.dataset.isPage; if (isPage && siteEle.href) { _GM_openInTab(siteEle.href, {active: false, insert: true}); continue; } if (self.stopInput) return; siteEle.click(); } } else if (e.button === 2) { let targetSites = self.getTargetSitesByName(siteNames); targetSites.reverse().forEach(siteEle => { if (siteEle.dataset.current) return; self.openSiteBtn(siteEle, "_blank", !!newTab); }); } self.batchOpening = false; } async siteSetUrl(siteEle, e) { return new Promise((resolve) => { let actionOverHandler = e => { siteEle.removeEventListener('actionOver', actionOverHandler); resolve(true); } siteEle.addEventListener('actionOver', actionOverHandler); let mouseDownEvent = new PointerEvent("mousedown", e); siteEle.dispatchEvent(mouseDownEvent); }); } getTargetSitesByName(siteNames, noPointer) { let self = this; let targetSites = []; siteNames.forEach(n => { for (let i = 0; i < self.allSiteBtns.length; i++) { let siteBtn = self.allSiteBtns[i][0]; if (siteBtn.dataset.name == n) { if (!noPointer && siteBtn.dataset.pointer) { if (siteBtn.dataset.oriName) { let oriBtn = self.getTargetSitesByName([siteBtn.dataset.oriName], true); if (oriBtn.length) { targetSites.push(...oriBtn); break; } } } else { targetSites.push(siteBtn); } break; } } }); return targetSites; } async submitAction(params) { params = params.slice(); if (document.readyState !== 'complete' && document.readyState !== 'interactive') { await sleep(300); this.submitAction(params); return; } let form, input, clicked = false, self = this, inLoop = false, loopTimes = 0, loopArr = []; let opened = false, copyList = []; let copyStore = await storage.getItem("copyStore"); if (copyStore) { copyList = JSON.parse(copyStore); } let singleAction = async (param, eleIndex) => { let result = true; if (param[0] === "sleep" || param[0] === "@sleep") { await sleep(param[1]); debug(`sleep ${param[1]}`); } else if (param[0] === "@click") { clicked = true; let _r = await emuClick(param[1], eleIndex); if (!_r) result = false; } else if (param[0] === "@dblclick") { clicked = true; let _r = await emuDblClick(param[1], eleIndex); if (!_r) result = false; } else if (param[0] === "@rclick") { clicked = true; let _r = await emuRClick(param[1], eleIndex); if (!_r) result = false; } else if (param[1] === 'click' && param[0].indexOf('@') === 0) { clicked = true; let _r = await emuClick(param[0].substr(1), eleIndex); if (!_r) result = false; } else if (param[0] === '@copy') { let _r = await returnElement(param[1], eleIndex); if (_r && _r !== true) { copyList.push(_r.innerText); if (!reachLast) { result = false; } } } else if (param[0] === '@call') { let engine = self.getTargetSitesByName([param[1]])[0]; if (engine) { extSelectionText = extSelectionText || getKeywords() || cacheKeywords; await self.siteSetUrl(engine); engine.click(); } else { let func = window[param[1]] || new AsyncFunction('"use strict";' + param[1]); if (func) await func(); } } else if (param[0] === '@open') { let btn = await waitForElement(param[1]); if (opened) { _GM_openInTab(btn.href); } else { opened = true; setTimeout(() => { location.href = btn.href; }, 50); } } else if (param[0] === '@reload') { } else if (param[0] === '@wait') { if (param[1].indexOf("!") === 0) { await waitForElementHide(param[1].slice(1)); } else { await waitForElement(param[1]); } } else { let inputStr = param[1]; if (!localKeywords) localKeywords = inputStr; if (inputStr.indexOf('%input{') !== -1) { let customInputStr = await self.showCustomInputWindow(inputStr); if (customInputStr) { inputStr = customInputStr; } else { storage.setListItem("inPagePostParams", location.hostname, ""); return true; } } let _r = await emuInput(param[0], inputStr, eleIndex); if (!_r) result = false; if (param[0] !== "@") { input = getElement(param[0]); } } return result; }; for (let param of params) { if (param[0] === "@loopStart") { inLoop = true; loopArr = []; loopTimes = parseInt(param[1]) || 1; } else if (param[0] === "@loopEnd") { inLoop = false; while (loopTimes-- > 0) { let allReady = false, eleIndex = 0; while (!allReady) { allReady = true; for (let param of loopArr) { let ready = await singleAction(param, eleIndex); if (!ready) allReady = false; } eleIndex++; } } } else if (inLoop) { loopArr.push(param); } else { await singleAction(param); } if (inPagePostParams) { inPagePostParams.shift(); if (inPagePostParams && inPagePostParams.length) { storage.setListItem("inPagePostParams", location.hostname, inPagePostParams); storage.setItem("copyStore", JSON.stringify(copyList)); } else { _GM_setClipboard(copyList.join("\n")); storage.setListItem("inPagePostParams", location.hostname, ""); storage.setItem("copyStore", ""); } if (param[0] === '@reload') { location.reload(!!param[1]); return; } } } if (inLoop) { inLoop = false; while (loopTimes-- > 0) { let allReady = false, eleIndex = 0; while (!allReady) { allReady = true; for (let param of loopArr) { let ready = await singleAction(param, eleIndex); if (!ready) allReady = false; } eleIndex++; } } } if (!clicked && input) { form = input.parentNode; while (form.nodeName.toUpperCase() != 'FORM') { form = form.parentNode; if (!form) break; } if (form) { let submitBtn = form.querySelector("[type=submit]"); if (submitBtn) submitBtn.click(); else form.submit(); } else { emuPress(); } } } getCloneData(siteName) { for (let i = 0; i < searchData.sitesConfig.length; i++) { let typeConfig = searchData.sitesConfig[i]; for (let j = 0; j < typeConfig.sites.length; j++) { let siteData = typeConfig.sites[j]; if (/^\[/.test(siteData.url)) continue; if (siteData.name == siteName) { return siteData; } } } return null; } async createSiteBtn(icon, data, openInNewTab, isBookmark, typeData, isHistoryBtn) { let self = this; let ele = document.createElement("a"); ele.setAttribute("ref", "noopener noreferrer"); ele.setAttribute("referrerPolicy", "no-referrer"); let name = data.name; let urlMatch = data.match; let showTips = false; let tipsData; let pointer = !isBookmark && /^\[/.test(data.url); let description = data.description; let shortcut = data.shortcut; if (typeof data.openInNewTab !== 'undefined') { openInNewTab = data.openInNewTab; } if (pointer) { ele.dataset.pointer = true; let siteNames = JSON.parse(data.url); if (siteNames.length === 1) { ele.dataset.clone = true; let cloneSite = this.getCloneData(siteNames[0]); if (cloneSite) { ele.dataset.oriName = cloneSite.name; data = cloneSite; if (data.icon && icon !== "0") icon = data.icon; if (data.description) description = data.description; } } } if (/^d:/.test(data.url)) { ele.setAttribute('download', ''); data.url = data.url.replace(/^d:/, ''); } else if (/^showTips:/.test(data.url)) { showTips = true; ele.dataset.showTips = true; } if (/^paste:/.test(data.url)) { ele.dataset.paste = true; } let isPage = /^(https?|ftp):/.test(data.url); if (isPage) ele.dataset.isPage = isPage; ele.className = "search-jumper-btn"; if (typeof description !== 'undefined') ele.title = description; ele.dataset.name = name; ele.classList.add("search-jumper-word"); ele.dataset.inPagePost = (data.url.indexOf("#p{") != -1) ? 't' : 'f'; let inPagePost = ele.dataset.inPagePost === 't'; if (urlMatch === '0') { ele.style.display = 'none'; ele.classList.add("notmatch"); } else if (!isBookmark && (!currentSite || data.hideNotMatch) && window.top == window.self) { if (urlMatch) { let urlRe, fullMatch = urlMatch.match(/^\/(.*)\/(\w*)$/); if (fullMatch) { urlRe = new RegExp(fullMatch[1], fullMatch[2]); } else { urlRe = new RegExp(urlMatch, "i"); } if (urlRe.test(href)) { ele.dataset.current = true; } } else if (!pointer && location.hostname && data.url.indexOf(location.hostname) != -1) { if (!this.inSiteMatch) this.inSiteMatch = /site(%3A|:)(.+?)[\s%]/; let match = data.url.match(this.inSiteMatch); if (match) { if (href.indexOf(match[2]) != -1 && data.url.replace(match[0], "").indexOf(location.hostname) != -1) { ele.dataset.current = true; } } else { if (!this.pathMatch) this.pathMatch = new RegExp("^https?://" + location.host + location.pathname + "?([\\?#].*|[%:#]p{|$)"); if (this.pathMatch.test(data.url)) { if (!this.postMatch) this.postMatch = /[#:%]p{/; if (this.postMatch.test(data.url)) { ele.dataset.current = true; } else { if (!this.paramMatch) this.paramMatch = /[^\/\?&]+(?=%[stb])/g; let urlReg = data.url.match(this.paramMatch); if (urlReg) { urlReg = urlReg.join('.*'); if (new RegExp(urlReg).test(href)) { ele.dataset.current = true; } } else { ele.dataset.current = true; } } } else if (data.url.indexOf("http") === 0 && data.url.indexOf("?") === -1) { if (!this.keywordMatch) this.keywordMatch = /%[stb][a-z]?\b/g; if (new RegExp(data.url.replace(/^https?/, "").replace(/[#%]\w+{.*/, "").replace(/\./g, "\\.").replace(this.keywordMatch, ".*")).test(href)) { ele.dataset.current = true; } } } } if (ele.dataset.current) { } else if (data.hideNotMatch) { ele.style.display = 'none'; ele.classList.add("notmatch"); } } let word = document.createElement("span"); if (!isBookmark && name.length >= 3) { word.innerText = name.substr(0, 4); if (!/^[\w \-]+$/.test(word.innerText.substr(0, 3))) word.innerText = word.innerText.substr(0, 2); } else word.innerText = name; ele.appendChild(word); let img = document.createElement("img"); img.style.display = "none"; ele.appendChild(img); if (!isHistoryBtn && searchData.prefConfig.shortcut && shortcut && !ele.dataset.clone && !ele.classList.contains("notmatch")) { let shortcutCover = document.createElement("div"); let shortcurStr = shortcut.replace('Key', '').replace('Digit', '').toUpperCase(); if (shortcurStr.length == 1) { shortcutCover.innerText = shortcurStr; ele.appendChild(shortcutCover); } document.addEventListener('keydown', async e => { if (e.target.id === "searchJumperInput") return; if (!self.hideTimeout) { if ((!data.ctrl == e.ctrlKey) || (!data.alt == e.altKey) || (!data.shift == e.shiftKey) || (!data.meta == e.metaKey)) { return; } } if (!self.bar.contains(ele)) return; if (!searchData.prefConfig.enableInInput && !data.ctrl && !data.alt && !data.shift && !data.meta) { if (inputActive(document)) return; } var key = (e.key || String.fromCharCode(e.keyCode)).toLowerCase(); if (shortcut == e.code || shortcut == key) { e.stopPropagation(); if (hoverElement) { targetElement = hoverElement; } if (showTips) { ele.dispatchEvent(new CustomEvent('showTips')); } else if (await action() !== false && !self.customInput) { ele.click(); } } }); } let imgSrc; if (icon == "0") { } else if (icon) { imgSrc = icon; } else if (!isBookmark && isPage) { imgSrc = data.url.replace(/\?.*/, "").replace(/^(https?:\/\/[^\/]*\/)[\s\S]*$/, "$1favicon.ico"); } else if (/^showTips:https?:\/\//.test(data.url)) { imgSrc = data.url.replace(/\?.*/, "").replace(/^showTips:(https?:\/\/[^\/]*\/)[\s\S]*$/, "$1favicon.ico"); } if (imgSrc) { img.onload = e => { ele.classList.remove("search-jumper-word"); if (word.parentNode && !searchData.prefConfig.showEngineWords) { word.parentNode.removeChild(word); } img.style.display = ""; }; let isBase64 = /^data:/.test(imgSrc); if (isBase64) { img.dataset.src = imgSrc; } else { let cache = searchData.prefConfig.cacheSwitch && cacheIcon[imgSrc]; if (cache === 'fail') { if (ele.dataset.current && imgSrc.indexOf(location.host) != -1) { img.dataset.src = imgSrc; cacheIcon[imgSrc] = ''; if (!isBookmark) { setTimeout(() => { cacheAction(img); }, 0); } } } else if (cache) { img.dataset.src = cache; } else { img.dataset.src = imgSrc; if (!isBookmark && !cacheIcon[imgSrc]) cachePool.push(img); } } } if (isPage) { if (openInNewTab) { ele.setAttribute("target", "_blank"); ele.dataset.target = 1; } else ele.setAttribute("target", "_self"); } let dataUrl = data.url; let hasWordParam = wordParamReg.test(dataUrl); if (hasWordParam) ele.dataset.txt = true; if (/%[tb]\b/i.test(dataUrl)) { ele.dataset.link = true; } let inputString; let getUrl = async (_keyWords) => { self.customInput = false; dataUrl = data.url; inputString = ""; let keywords = _keyWords || self.searchJumperInputKeyWords.value || getSelectStr(); if (!keywords && !draging && !self.bar.classList.contains("search-jumper-isTargetLink")) { keywords = getKeywords(); } if (keywords && !_keyWords) { if (keywords != cacheKeywords) { self.keywordIndex = 0; if (isPage) { cacheKeywords = keywords; storage.setItem("cacheKeywords", keywords); } } inputString = keywords; } let postMatch; if (inPagePost || /^c(opy)?:|^paste:/.test(dataUrl)) { if (dataUrl.indexOf('%input{') !== -1) { dataUrl = await new Promise(resolve => { self.showCustomInputWindow(dataUrl, _url => { resolve(_url); }); }); ele.dataset.url = ""; } postMatch = dataUrl.match(/#p{([\s\S]*[^\\])}/); } let host = location.host; let href = location.href; let customReplaceSingle = (str, key, value, after) => { if (str.indexOf(key + "[") !== -1) { let multiMatch = str.match(keyToReg(key, "", "\\[(.*?)(\\|(.+))?\\]")), valueArr; if (multiMatch) { if (multiMatch[3]) { valueArr = value.split(multiMatch[3]); } else { valueArr = value.split(/[\n\r]/); if (valueArr.length === 1) { valueArr = value.split(" "); } } if (!self.keywordIndex) self.keywordIndex = 0; switch(multiMatch[1]) { case "all": inputString = valueArr.join('\n'); break; case ""://next value = valueArr[self.keywordIndex]; if (++self.keywordIndex >= valueArr.length) { self.keywordIndex = 0; } break; case "-1"://prev if (--self.keywordIndex < 0) { self.keywordIndex = valueArr.length - 1; } value = valueArr[self.keywordIndex]; break; default://number value = valueArr[parseInt(multiMatch[1]) || 0]; break; } str = str.replace(multiMatch[0], key); } } return replaceSingle(str, key, value, after); }; let needDecode = (!/^showTips:h/i.test(dataUrl) && /^c(opy)?:|[#:%]P{|^javascript:|^showTips:/i.test(dataUrl)); let keywordsU = "", keywordsL = "", keywordsR = "", keywordsSC = "", keywordsTC = ""; let customReplaceKeywords = str => { let _str = str; _str = customReplaceSingle(_str, "%su", keywordsU); _str = customReplaceSingle(_str, "%sl", keywordsL); _str = customReplaceSingle(_str, "%sr", keywordsR); _str = customReplaceSingle(_str, "%S", cacheKeywords || keywordsR); _str = customReplaceSingle(_str, "%ss", keywordsSC); _str = customReplaceSingle(_str, "%st", keywordsTC); _str = customReplaceSingle(_str, "%se", escape ? escape(keywordsR) : keywordsR); _str = customReplaceSingle(_str, "%s", keywordsR, v => { return (needDecode ? v : encodeURIComponent(v)); }); if (/%bd\b/.test(_str)) { try { let debase64 = atob(keywordsR); _str = customReplaceSingle(_str, "%bd", debase64); } catch(e) { console.log(e); } } if (/%be\b/.test(_str)) { try { let enbase64 = btoa(keywordsR); _str = customReplaceSingle(_str, "%be", enbase64); } catch(e) { console.log(e); } } return _str; }; let customVariable = str => { let customMatch = str.match(/%element{(.*?)}(\.prop\((.*?)\))?/); let runTimes = 0; while (customMatch) { if (runTimes++ > 100) break; let selector = customMatch[1]; let prop = customMatch[3]; let value = ""; if (!selector) { try { let selectEles = window.getSelection(); let container = document.createElement('div'); for (let i = 0, len = selectEles.rangeCount; i < len; ++i) { container.appendChild(selectEles.getRangeAt(i).cloneContents()); } [].forEach.call(container.querySelectorAll("style,script,svg,canvas"), ele => { let textNode = document.createTextNode(''); ele.parentNode.replaceChild(textNode, ele); }); document.body.appendChild(container); if (prop) { for (let i = 0; i < container.childNodes.length; i++) { let childNode = container.childNodes[i]; if (childNode.nodeType == 3) { value += childNode.nodeValue; value += "\n"; } else if (childNode.nodeType == 1) { value += childNode.getAttribute(prop) || childNode[prop] || ""; value += "\n"; } } } else { [].forEach.call(container.querySelectorAll("img"), img => { if (!img.src) return; let textNode = document.createTextNode(` ![${(img.alt || "").replace(/[\n\r]/g, " ").trim()}](${img.src || ""}) `); img.parentNode.replaceChild(textNode, img); }); [].forEach.call(container.querySelectorAll("a"), a => { if (!a.href) return; let innerText = (a.innerText || "").replace(/[\n\r]+/g, "\n").trim(); if (!innerText) return; innerText = ` [${innerText}](${a.href || ""}) `; let newNode; if (innerText.indexOf("\n") == -1) { newNode = document.createTextNode(innerText); } else { newNode = document.createElement("pre"); newNode.innerHTML = createHTML(innerText); } a.parentNode.replaceChild(newNode, a); }); value = container.innerText; } if (value) { value = value.replace(/[\n\r]\s*/g, "\n"); } document.body.removeChild(container); } catch(e) { console.error(e); } } else { let ele = getElement(selector); if (ele) { if (prop) { value = ele.getAttribute(prop) || ele[prop]; } else { value = ele.innerText; } } } str = customReplaceSingle(str, customMatch[0], needDecode ? value : encodeURIComponent(value)); customMatch = str.match(/%element{(.*?)}(\.prop\((.*?)\))?/); } customMatch = str.match(/%date({(.*?)})?/); runTimes = 0; let curTime = new Date().getTime(); while (customMatch) { if (runTimes++ > 100) break; let timeEval = customMatch[2]; let value = curTime; if (timeEval) { timeEval = timeEval.replace(/\s/g, ''); let mathEval = timeEval.match(/(\D*)?(\d+)/); while (mathEval) { switch (mathEval[1]) { case "-": value -= parseInt(mathEval[2]); break; case "*": value *= parseInt(mathEval[2]); break; case "/": if (mathEval[2] && mathEval[2] != '0') { value = parseInt(value / parseInt(mathEval[2])); } break; default: value += parseInt(mathEval[2]); break; } timeEval = timeEval.replace(mathEval[0], ""); mathEval = timeEval.match(/(\D*)?(\d+)/); } } else { value = curTime; } str = str.replace(customMatch[0], value); customMatch = str.match(/%date({(.*?)})?/); } return str; } if (!ele.dataset.url) { let tempUrl = dataUrl; if (inPagePost) { tempUrl = tempUrl.replace(postMatch[0], ""); } ele.dataset.url = tempUrl.replace(/%e\b/g, document.characterSet).replace(/%c\b/g, (isMobile?"mobile":"pc")); } let targetUrl = '', targetLink = ''; let targetName = inputString || document.title; let imgBase64 = '', resultUrl = customVariable(ele.dataset.url); if (targetElement && targetElement.nodeName) { targetUrl = targetElement.href || (targetElement.parentNode && targetElement.parentNode.href) || ''; targetLink = targetUrl || (targetElement.parentNode && targetElement.parentNode.parentNode && targetElement.parentNode.parentNode.href) || ''; if ((typeData.selectImg || typeData.selectAudio || typeData.selectVideo) && targetElement.src) { targetUrl = targetElement.src; } if (targetElement.nodeName.toUpperCase() == "VIDEO" || targetElement.nodeName.toUpperCase() == "AUDIO") { if (!targetUrl) { let source = targetElement.querySelector("source"); if (source) targetUrl = source.src; } if (targetUrl) targetUrl = targetUrl.replace(/^blob:/, ""); } targetName = targetElement.title || targetElement.alt || document.title; if (targetElement.nodeName.toUpperCase() == 'IMG' && /%i\b/.test(dataUrl)) { if (targetElement.src) { if (/^data/.test(targetElement.src)) { imgBase64 = targetElement.src; } else { self.tipsPos(ele, "<span class='loader'></span><font>Loading...</font>"); imgBase64 = await image2Base64(targetElement); } resultUrl = resultUrl.replace(/%i\b/g, imgBase64); } } else if ((targetElement.nodeName.toUpperCase() == 'A' || (targetElement.parentNode && targetElement.parentNode.nodeName.toUpperCase() == 'A')) && hasWordParam && !keywords) { if (targetElement.textContent.trim()) keywords = targetElement.textContent.trim(); } } while (resultUrl.indexOf('%template{') !== -1) { let inputMatch = resultUrl.match(/%template{(.*?[^\\])}/); if (!inputMatch) return false; let templateName = inputMatch[1]; if (!searchData.prefConfig.templateData) searchData.prefConfig.templateData = {}; let templateResult = searchData.prefConfig.templateData[templateName]; if (!templateResult) { if (self.stopInput) return false; templateResult = window.prompt(i18n("template", templateName)) || ""; if (templateResult) { searchData.prefConfig.templateData[templateName] = templateResult; storage.setItem("searchData", searchData); } else return false; } resultUrl = resultUrl.replace(inputMatch[0], templateResult); } while (resultUrl.indexOf('%input{') !== -1) { let inputMatch = resultUrl.match(/%input{(.*?[^\\])}/); if (!inputMatch) return false; self.customInput = true; if (self.stopInput) return false; if (self.batchOpening) { let promptStr; if (inputMatch[1].indexOf("\"") === 0 && inputMatch[1].indexOf("\",\"") !== -1) { promptStr = inputMatch[1].substr(1, inputMatch[1].length - 2).split("\",\""); } else { promptStr = inputMatch[1].split(","); } if (promptStr.length === 2) { promptStr = window.prompt(promptStr[0], promptStr[1]); } else { promptStr = window.prompt(inputMatch[1]); } if (promptStr === null) return false; resultUrl = resultUrl.replace(inputMatch[0], promptStr); } else break; } if (targetUrl) { targetUrl = targetUrl.replace(/%(\w{2})/g, (match, letter) => `%${letter.toUpperCase()}`); } if (targetLink) { targetLink = targetLink.replace(/%(\w{2})/g, (match, letter) => `%${letter.toUpperCase()}`); } let targetBaseUrl = targetUrl.replace(/^https?:\/\//i, ""); if (!keywords) keywords = (currentSite && cacheKeywords); try { if (typeof navigator.clipboard.readText !== "undefined") { if (!keywords && hasWordParam) { keywords = await navigator.clipboard.readText(); if (keywords && !_keyWords) { inputString = keywords; } } if (!imgBase64 && /%i\b/.test(dataUrl)) { const permission = await navigator.permissions.query({ name: "clipboard-read", }); if (permission.state !== "denied") { const clipboardContents = await navigator.clipboard.read(); for (const item of clipboardContents) { if (item.types.includes("image/png")) { const blob = await item.getType("image/png"); imgBase64 = await new Promise(resolve => { const reader = new FileReader(); reader.onload = function (e) { resolve(e.target && e.target.result); }; reader.readAsDataURL(blob); }); if (imgBase64) resultUrl = resultUrl.replace(/%i\b/g, imgBase64); } } } if (!imgBase64) { self.customInput = true; let src = window.prompt(i18n("targetUrl"), "https://www.google.com/favicon.ico"); if (src) { self.tipsPos(ele, "<span class='loader'></span><font>Loading...</font>"); imgBase64 = await imageSrc2Base64(src); } else return false; } } } } catch(e) { console.error(e.message); } if (!keywords && hasWordParam) { self.customInput = true; if (self.con.classList.contains("search-jumper-showall")) return false; if (self.inInput || showTips) return false; if (self.stopInput) return false; let promptStr = window.prompt(i18n("keywords")); if (promptStr === null) return false; localKeywords = promptStr; setTimeout(() => {localKeywords = ''}, 1); keywords = promptStr; keywordsR = keywords; keywordsU = keywordsR.toUpperCase(); keywordsL = keywordsR.toLowerCase(); keywordsSC = _unsafeWindow.tc2sc ? _unsafeWindow.tc2sc(keywordsR) : keywordsR; keywordsTC = _unsafeWindow.sc2tc ? _unsafeWindow.sc2tc(keywordsR) : keywordsR; if (!needDecode) keywords = encodeURIComponent(keywords); resultUrl = customReplaceKeywords(resultUrl); } else if (keywords && (!keywordsU && !keywordsL && !keywordsR)) { keywordsR = keywords; keywordsU = keywordsR.toUpperCase(); keywordsL = keywordsR.toLowerCase(); keywordsSC = _unsafeWindow.tc2sc ? _unsafeWindow.tc2sc(keywordsR) : keywordsR; keywordsTC = _unsafeWindow.sc2tc ? _unsafeWindow.sc2tc(keywordsR) : keywordsR; if (!needDecode) keywords = encodeURIComponent(keywords); } if (targetUrl === '') { let canBeUrl = getSelectStr() || self.searchJumperInputKeyWords.value; if (!hasWordParam && canBeUrl && /^(http|ftp)/i.test(canBeUrl)) { targetUrl = canBeUrl; targetUrl = targetUrl.replace(/%(\w{2})/g, (match, letter) => `%${letter.toUpperCase()}`); } else { let promptStr = false; let getTargetUrl = () => { if (self.stopInput || showTips) return false; if (promptStr === false) { promptStr = window.prompt(i18n("targetUrl"), "https://www.google.com/favicon.ico"); if (promptStr) { promptStr = promptStr.replace(/%(\w{2})/g, (match, letter) => `%${letter.toUpperCase()}`); targetElement = {src: promptStr}; } } if (promptStr === null) return false; return true; }; if (/%t\b/.test(resultUrl)) { self.customInput = true; if (getTargetUrl() === false) return false; resultUrl = customReplaceSingle(resultUrl, "%t", promptStr); } if (/%T\b/.test(resultUrl)) { self.customInput = true; if (getTargetUrl() === false) return false; resultUrl = resultUrl.replace(/%T\b/g, encodeURIComponent(promptStr)); } if (/%τ\b/.test(resultUrl)) { self.customInput = true; if (getTargetUrl() === false) return false; resultUrl = resultUrl.replace(/%τ\b/g, encodeURIComponent(encodeURIComponent(promptStr))); } if (/%b\b/.test(resultUrl)) { self.customInput = true; if (getTargetUrl() === false) return false; resultUrl = resultUrl.replace(/%b\b/g, promptStr.replace(/^https?:\/\//i, "")); } if (/%B\b/.test(resultUrl)) { self.customInput = true; if (getTargetUrl() === false) return false; resultUrl = resultUrl.replace(/%B\b/g, encodeURIComponent(promptStr.replace(/^https?:\/\//i, ""))); } if (/%β\b/.test(resultUrl)) { self.customInput = true; if (getTargetUrl() === false) return false; resultUrl = resultUrl.replace(/%β\b/g, encodeURIComponent(encodeURIComponent(promptStr.replace(/^https?:\/\//i, "")))); } } } let _host = host; if ((targetLink || targetUrl) && !ele.dataset.link) { href = targetLink || targetUrl; _host = href.replace(/^\w+:\/\/([^\/]+).*/, "$1"); } if (inPagePost) { let postParams = [], hasCall = false; postMatch[1].replace(/([^\\])&/g, "$1SJ^PARAM").split("SJ^PARAM").forEach(pair => {//ios不支持零宽断言,哭唧唧 pair = pair.trim(); if (/^loopStart\(\d+\)$/.test(pair)) { let loopStart = pair.match(/loopStart\((.*)\)/); postParams.push(['@loopStart', loopStart[1]]); } else if (pair == "loopEnd") { postParams.push(['@loopEnd', '']); } else if (pair.startsWith("click(") && pair.endsWith(')')) { let click = pair.slice(6, pair.length - 1); if (click) { postParams.push(['@click', click.replace(/\\([\=&])/g, "$1").trim()]); } } else if (pair.startsWith("dblclick(") && pair.endsWith(')')) { let click = pair.slice(9, pair.length - 1); if (click) { postParams.push(['@dblclick', click.replace(/\\([\=&])/g, "$1").trim()]); } } else if (pair.startsWith("rclick(") && pair.endsWith(')')) { let click = pair.slice(7, pair.length - 1); if (click) { postParams.push(['@rclick', click.replace(/\\([\=&])/g, "$1").trim()]); } } else if (pair.startsWith("copy(") && pair.endsWith(')')) { let copy = pair.slice(5, pair.length - 1); if (copy) { postParams.push(['@copy', copy.replace(/\\([\=&])/g, "$1").trim()]); } } else if (pair.startsWith("call(") && pair.endsWith(')')) { let func = pair.slice(5, pair.length - 1); if (func) { postParams.push(['@call', func.replace(/\\([\=&])/g, "$1").trim()]); hasCall = true; } } else if (pair.startsWith("reload(") && pair.endsWith(')')) { let func = pair.slice(7, pair.length - 1); postParams.push(['@reload', func.trim()]); } else if (pair.startsWith("wait(") && pair.endsWith(')')) { let wait = pair.slice(5, pair.length - 1); postParams.push(['@wait', wait.replace(/\\([\=&])/g, "$1").trim()]); } else if (pair.startsWith("open(") && pair.endsWith(')')) { let open = pair.slice(5, pair.length - 1); if (open) { postParams.push(['@open', open.replace(/\\([\=&])/g, "$1").trim()]); } } else if (/^sleep\(\d+\)$/.test(pair)) { let sleep = pair.match(/sleep\((.*)\)/); if (sleep) { postParams.push(['@sleep', sleep[1]]); } } else { pair = pair.replace(/([^\\])\=/g, "$1SJ^PARAM").replace(/\\([\=&])/g, "$1"); let pairArr = pair.split("SJ^PARAM"); if (pairArr.length === 2) { let k = pairArr[0]; let v = customReplaceKeywords(pairArr[1].replace(/\\([\=&])/g, "$1").replace(/%e\b/g, document.characterSet).replace(/%i\b/g, imgBase64).replace(/%c\b/g, (isMobile?"mobile":"pc")).replace(/%U\b/g, encodeURIComponent(href)).replace(/%υ\b/g, encodeURIComponent(encodeURIComponent(href))).replace(/%h\b/g, _host).replace(/%T\b/g, encodeURIComponent(targetUrl)).replace(/%τ\b/g, encodeURIComponent(encodeURIComponent(targetUrl))).replace(/%b\b/g, targetBaseUrl).replace(/%B\b/g, encodeURIComponent(targetBaseUrl)).replace(/%β\b/g, encodeURIComponent(encodeURIComponent(targetBaseUrl))).replace(/%n\b/g, targetName)); v = customReplaceSingle(v, "%t", targetUrl); v = customReplaceSingle(v, "%u", href); postParams.push([k, v]); } else if (pair.endsWith('.click()') || pair.endsWith('.click')) { postParams.push(['@' + pair.replace(/\.click(\(\))?$/, ''), 'click']); } } }); if (hasCall) { self.updateCacheKeywords(); } if (resultUrl === "" || resultUrl === location.href) { inPagePostParams = postParams; this.submitAction(postParams); return false; } else { storage.setListItem("inPagePostParams", resultUrl.replace(/^https?:\/\/([^\/:]+).*/, "$1"), postParams); } } resultUrl = customReplaceSingle(resultUrl, "%h", _host); resultUrl = customReplaceSingle(resultUrl, "%t", targetUrl); resultUrl = customReplaceSingle(resultUrl, "%u", href); resultUrl = customReplaceKeywords(resultUrl.replace(/%U\b/g, encodeURIComponent(href)).replace(/%υ\b/g, encodeURIComponent(encodeURIComponent(href))).replace(/%T\b/g, encodeURIComponent(targetUrl)).replace(/%τ\b/g, encodeURIComponent(encodeURIComponent(targetUrl))).replace(/%b\b/g, targetBaseUrl).replace(/%B\b/g, encodeURIComponent(targetBaseUrl)).replace(/%β\b/g, encodeURIComponent(encodeURIComponent(targetBaseUrl))).replace(/%n\b/g, targetName)); if (openInNewTab && /^(https?|ftp):/.test(resultUrl)) { ele.setAttribute("target", "_blank"); ele.dataset.target = 1; } else { ele.dataset.target = 0; } return resultUrl; }; let targetUrlData; let clicked = false; let alt, ctrl, meta, shift; let action = async e => { delete ele.href; if (!e) e = {}; alt = e.altKey; ctrl = e.ctrlKey; meta = e.metaKey; shift = e.shiftKey; if (!alt && !ctrl && !meta && !shift) { if (e.button == 1 || e.button == 2) { alt = false; ctrl = true; meta = false; shift = false; } else if (openInNewTab === 2) {//隱身窗口 alt = false; ctrl = true; meta = false; shift = true; } else if (openInNewTab === 3) {//小窗口 alt = true; ctrl = false; meta = false; shift = false; } else if (openInNewTab === 4) {//后台标签页 alt = false; ctrl = true; meta = false; shift = false; } } if (showTips) { ele.removeAttribute("target"); if (tipsData) { if (/^(https?|ftp):/.test(tipsData)) { targetUrlData = tipsData; ele.href = targetUrlData; if (openInNewTab) { ele.setAttribute("target", "_blank"); } else { ele.setAttribute("target", "_self"); } } else { if (/^copy:/.test(tipsData)) { tipsData = tipsData.replace(/^copy:/, ""); } _GM_setClipboard(tipsData); } } ele.dispatchEvent(new Event("actionOver")); return; } clicked = false; targetUrlData = ""; targetUrlData = await getUrl(); if (/^(https?|ftp):/.test(targetUrlData)) { e.stopPropagation && e.stopPropagation(); } if (/^c(opy)?:|^paste:/.test(data.url) || /^javascript:/.test(data.url) || /^\[/.test(data.url) || /[:%]P{/.test(data.url) || (data.charset && data.charset != 'utf-8') || /[:%]p{/.test(data.url)) { if (e.button == 1 || e.button == 2) { clicked = true; } } else { if (!targetUrlData) { //wait for all input stoped if (!self.stopInput) { self.stopInput = true; setTimeout(() => { self.stopInput = false; }, 1); } return; } ele.href = targetUrlData; } if (self.customInput && targetUrlData) { clicked = true; } ele.dispatchEvent(new Event("actionOver")); if (clicked) { if (e.preventDefault) e.preventDefault(); ele.click(); } }; let addHistory = () => { let historyLength = Math.max(searchData.prefConfig.historyLength, 20); let isCurrent = ele.dataset.current; if (!data.hideNotMatch && !data.kwFilter && !ele.dataset.clone && !ele.dataset.paste && urlMatch !== '0' && historyLength && !isCurrent) { storage.getItem("historySites", data => { historySites = (data || []); historySites = historySites.filter(site => {return site && site != name}); historySites.unshift(name); if (historySites.length > historyLength) { historySites = historySites.slice(0, historyLength); } storage.setItem("historySites", historySites); //self.initHistorySites(); }); } if (searchData.prefConfig.shiftLastUsedType && !isCurrent) { let parent = ele.parentNode; let dismissHistory = parent && (parent.classList.contains("search-jumper-targetAll") || parent.classList.contains("search-jumper-targetImg") || parent.classList.contains("search-jumper-targetAudio") || parent.classList.contains("search-jumper-targetVideo") || parent.classList.contains("search-jumper-targetLink") || parent.classList.contains("search-jumper-targetPage") || parent.classList.contains("search-jumper-needInPage")); if (!dismissHistory && historyType != ele.dataset.type) { historyType = ele.dataset.type; storage.setItem("historyType", historyType); } } if (searchData.prefConfig.sortType) { storage.getItem("sortTypeNames", data => { sortTypeNames = (data || {}); if (!sortTypeNames[ele.dataset.type]) { sortTypeNames[ele.dataset.type] = 1; } else { sortTypeNames[ele.dataset.type] = sortTypeNames[ele.dataset.type] + 1; } storage.setItem("sortTypeNames", sortTypeNames); }); } if (searchData.prefConfig.sortSite) { storage.getItem("sortSiteNames", data => { sortSiteNames = (data || {}); if (!sortSiteNames[ele.dataset.name]) { sortSiteNames[ele.dataset.name] = 1; } else { sortSiteNames[ele.dataset.name] = sortSiteNames[ele.dataset.name] + 1; } storage.setItem("sortSiteNames", sortSiteNames); }); } }; let copyHandler = (inner, str) => { _GM_setClipboard(str); let target = ele; if (!inner) { self.appendBar(); self.closeOpenType(); self.con.style.display = ""; self.setFuncKeyCall(true); if (window.getSelection().toString()) { target = targetElement || ele; } else target = getBody(document); } self.tipsPos(target, i18n('copyOver')); clearTimeout(self.hideTips); self.hideTips = setTimeout(() => { if (self.tips.style.opacity == "1") { self.tips.style.opacity = 0; } }, 1500); }; let clickHandler = e => { e && e.stopPropagation && e.stopPropagation(); if (targetElement) { targetElement.focus && targetElement.focus(); } if (showTips && self.waitForShowTips) { showTipsHandler(ele, 0); e && e.preventDefault && e.preventDefault(); return false; } clicked = true; if (!targetUrlData) { e && e.preventDefault && e.preventDefault(); return false; } if (!e) e = {}; let isPage = /^(https?|ftp):/.test(targetUrlData); if (!self.batchOpening && !isBookmark) { addHistory(); } if (searchData.prefConfig.multiline == 1 || searchData.prefConfig.multiline == 2) { if (inputString && wordParamReg.test(ele.dataset.url) && inputString.indexOf("\n") !== -1 && !/^(c|show)/.test(ele.dataset.url)) { if (searchData.prefConfig.multiline == 1 || confirm(i18n("multiline"))) { let selStrArr = inputString.split("\n"); if (selStrArr.length > 10 && !confirm(i18n("multilineTooMuch"))) return; let searchIndex = 0; let defaultTarget = ele.target; ele.target = "_blank"; let searchByLine = async () => { targetUrlData = await getUrl(selStrArr[searchIndex++]); ele.href = targetUrlData; ele.click(); if (searchIndex < selStrArr.length) { setTimeout(() => { searchByLine(); }, searchData.prefConfig.multilineGap || 1000); } else ele.target = defaultTarget; }; searchByLine(); ele.href = ""; if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; } } } if (targetUrlData.indexOf('%input{') !== -1) { self.showCustomInputWindow(targetUrlData, _url => { targetUrlData = _url; ele.href = _url; ele.click(); }); if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return; } let findWordsMatch = targetUrlData.match(/^find(\.addto\((.*?)\))?:(.*)/); if (findWordsMatch) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); let addToGroup = findWordsMatch[2]; let findWords = findWordsMatch[3]; if (!findWords) { return false; } else { if (addToGroup && searchData.prefConfig.inPageRule) { if (addToGroup.indexOf("@") !== 0) addToGroup = "@" + addToGroup; } if (findWords.indexOf('%input{') !== -1) { self.showCustomInputWindow(findWords, _url => { if (addToGroup) { self.addToHighlightGroup(_url, addToGroup); } else { self.searchJumperInPageInput.value = _url; self.submitInPageWords(); self.waitForHide(0); } }); } else { if (addToGroup) { self.addToHighlightGroup(findWords, addToGroup); } else { self.searchJumperInPageInput.value = findWords; self.submitInPageWords(); self.waitForHide(0); } } } return false; } else if (/^javascript:/.test(data.url)) { if (ext) { _unsafeWindow.targetElement = targetElement; _unsafeWindow.keywords = getKeywords(); let func = (/^javascript:[_a-zA-Z0-9]+$/.test(targetUrlData) && _unsafeWindow[targetUrlData.replace("javascript:", "")]); if (func) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); func(); return false; } ele.href = targetUrlData; return; } if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); _unsafeWindow.targetElement = targetElement; _unsafeWindow.keywords = getKeywords(); targetUrlData = targetUrlData.replace(/^javascript:/, ''); try { targetUrlData = decodeURIComponent(targetUrlData); } catch(e) {} let func = (/^[_a-zA-Z0-9]+$/.test(targetUrlData) && _unsafeWindow[targetUrlData]) || new AsyncFunction(targetUrlData); if (func) func(); return false; } else if (/^c(opy)?:/.test(data.url)) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); if (!targetUrlData) { return false; } else if (targetUrlData.indexOf('%input{') !== -1) { self.showCustomInputWindow(targetUrlData, _url => { copyHandler(true, _url.replace(/^c(opy)?:/, "")); }); } else { copyHandler(e.isTrusted, targetUrlData.replace(/^c(opy)?:/, "")); } return false; } else if (/^paste:/.test(data.url)) { let targetInput = false; if (targetElement && (/INPUT|TEXTAREA/i.test(targetElement.nodeName) && targetElement.getAttribute("aria-readonly") != "true") ) { targetInput = true; } else { let parent = targetElement; while (parent) { targetInput = parent.contentEditable == 'true'; if (targetInput || parent.nodeName.toUpperCase() == 'BODY') { break; } parent = parent.parentNode; } } if (targetInput) { if (!targetUrlData) { return false; } targetUrlData = targetUrlData.replace(/^paste:/, ""); if (targetUrlData.indexOf('%input{') !== -1) { self.showCustomInputWindow(targetUrlData, _url => { triggerPaste(targetElement, _url); }); } else if (targetUrlData) { triggerPaste(targetElement, targetUrlData); } else if (typeof navigator.clipboard.readText !== "undefined") { navigator.clipboard.readText().then((clipboardValue) => { triggerPaste(targetElement, clipboardValue); }); } } } else if (/^\[/.test(data.url)) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); let siteNames = JSON.parse(data.url); self.batchOpen(siteNames, {button: 2, altKey: alt || e.altKey, ctrlKey: ctrl || e.ctrlKey, shiftKey: shift || e.shiftKey, metaKey: meta || e.metaKey}, openInNewTab === 1); return false; } else if (/[:%]P{/.test(data.url)) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); if (targetUrlData === false) return false; let postHandler = _url => { let postBody = _url.match(/[:%]P{(.*)}/), postParam = ""; if (postBody) { _url = _url.replace(postBody[0], ''); postBody = postBody[1]; if (postBody.charAt(0) === '"' && postBody.charAt(postBody.length - 1) === '"') { postParam = postBody.substring(1, postBody.length - 1); } else { postBody = new URLSearchParams(postBody); let postDict = {}; postBody.forEach((v, k) => { postDict[k] = v; }); postParam = JSON.stringify(postDict); } } _GM_xmlhttpRequest({ method: "POST", url: _url, data: postParam, onload: (d) => { debug(d); //_GM_notification(i18n("postOver") + d.statusText); }, onerror: (e) => { _GM_notification(i18n("postError") + (e.statusText || e.error)); }, ontimeout: (e) => { _GM_notification(i18n("postError") + (e.statusText || e.error)); } }); } if (targetUrlData.indexOf('%input{') !== -1) { self.showCustomInputWindow(targetUrlData, _url => { postHandler(_url); }); } else { postHandler(targetUrlData); } return false; } else if ((data.charset && data.charset != 'utf-8') || /[:%]p{/.test(data.url)) { if (targetUrlData === false) return false; let jumpFrom = data.url.match(/#(j(umpFrom|f)?|from){(.*?)}/); let processPostUrl = _url => { if (jumpFrom) { storage.setItem("postUrl", [_url, data.charset]); jumpFrom = jumpFrom[3]; if (jumpFrom.indexOf("http") !== 0) { jumpFrom = _url.replace(/(:\/\/.*?\/)[\s\S]*/, "$1" + jumpFrom); } _url = jumpFrom; } else { if (ext) { _url = `${jumpHtml}#jump{url=${encodeURIComponent(_url.replace(/[:%]p{[\s\S]*/, ''))}&charset=${data.charset}}`; //storage.setItem("postUrl", [_url + "#from{" + jumpHtml + "}", data.charset]); //_url = jumpHtml; } else { storage.setItem("postUrl", [_url, data.charset]); _url = _url.replace(/(:\/\/.*?)\/[\s\S]*/, "$1").replace(/[:%]p{[\s\S]*/, ''); } } return _url; }; if (targetUrlData.indexOf('%input{') !== -1) { self.showCustomInputWindow(targetUrlData, _url => { _url = processPostUrl(_url); if (!_url) return; ele.href = _url; if (ele.target === '_blank') { _GM_openInTab(ele.href, {active: true, insert: true}); } else { location.href = ele.href; } }); if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return; } else { targetUrlData = processPostUrl(targetUrlData); if (!targetUrlData) return; ele.href = targetUrlData; } } if (shift && !ctrl && !meta && !alt && e.isTrusted) return; if (/^(chrome|edge|about|extension|moz-extension)/.test(targetUrlData)) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); if (ctrl) { _GM_openInTab(targetUrlData, {active: false, insert: true}); } else { _GM_openInTab(targetUrlData, {active: true, insert: true, close: ele.getAttribute("target") !== "_blank"}); } return false; } else if ((alt || ctrl || meta || shift) && isPage) { if ((ctrl || meta) && shift) { _GM_openInTab(targetUrlData, {incognito: true}); } else if (ctrl || meta) { _GM_openInTab(targetUrlData, {active: false, insert: true}); } else if (alt) { if (data.match) { let match = data.match.replace(/\\/g, ""); let mobileMatch = match.match(/\((www)\|([^\)\|]+)/); while (mobileMatch) { targetUrlData = targetUrlData.replace(mobileMatch[1], mobileMatch[2]); match = match.replace(mobileMatch[0], ""); mobileMatch = match.match(/\(([^\)\|]+)\|([^\)\|]+)/); } } let viewWidth = window.screen.availWidth || window.innerWidth || document.documentElement.clientWidth; let viewHeight = window.screen.availHeight || window.innerHeight || document.documentElement.clientHeight; let showWidth = searchData.prefConfig.popupWidth, showHeight = searchData.prefConfig.popupHeight, left = searchData.prefConfig.popupLeft, top = searchData.prefConfig.popupTop; if (showHeight) { showHeight = parseFloat(showHeight); showHeight = viewHeight / 100 * showHeight; } else { showHeight = Math.max(viewHeight / 3 * 2, viewHeight - 250); } if (showWidth) { showWidth = parseFloat(showWidth); showWidth = viewWidth / 100 * showWidth; } else { showWidth = Math.min(viewWidth, 650); } if (left) { left = parseFloat(left); left = viewWidth / 100 * left - showWidth / 2; } else { left = viewWidth - showWidth - 30; } if (top) { top = parseFloat(top); top = viewHeight / 100 * top - showHeight / 2; } else { top = (viewHeight - showHeight) / 2; } self.closePopupWindow(); self.popupWindow = window.open(targetUrlData + "#searchJumperMin" + (/#p{/.test(data.url) ? 'Post' : ''), "_blank", `width=${showWidth}, height=${showHeight}, location=0, resizable=1, status=0, toolbar=0, menubar=0, scrollbars=0, left=${left}, top=${top}`); } else if (shift) { _GM_openInTab(targetUrlData, {active: true, insert: true}); } if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; } else if (isPage && ele.getAttribute("target") === "_blank" && !(alt || ctrl || meta || shift) && e.button === 0) { _GM_openInTab(targetUrlData, {active: true, insert: true}); if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; } }; //ele.href = data.url; ele.addEventListener('mousedown', action, true); ele.addEventListener('mouseup', e => { if (e.stopPropagation) e.stopPropagation(); }, true); ele.addEventListener('click', clickHandler, true); ele.addEventListener('auxclick', e => { if (clicked && e.preventDefault) { e.preventDefault(); return false; } }, true); ele.addEventListener('contextmenu', e => { if (clicked && e.preventDefault) { e.preventDefault(); return false; } }, true); let tipsStr = ele.dataset.name; if (shortcut) { tipsStr += ` (${data.ctrl ? "Ctrl + " : ""}${data.shift ? "Shift + " : ""}${data.alt ? "Alt + " : ""}${data.meta ? "Meta + " : ""}${shortcut.replace("Key", "")})`; } let anylizing = false, tipsShowing = false; let setTips = async (target, url, again) => { self.tipsPos(target, '<span class="loader"></span><font>Loading...</font>'); tipsShowing = false; if (url) { try { url = url.replace(/^showTips:/, ''); anylizing = true; let tipsResult = await self.anylizeShowTips(url, ele.dataset.name, target); anylizing = false; if (self.tips.style.opacity == 0 || self.tips.innerHTML.indexOf('<span class="loader">') !== 0) { tipsShowing = true; return; } if (Array && Array.isArray && Array.isArray(tipsResult)) { tipsData = tipsResult[1]; tipsResult = tipsResult[0]; } if (tipsResult) { if (tipsResult != "null" && tipsResult != "No result") { tipsResult = `<div>${tipsResult}</div>`; tipsShowing = true; } //self.tips.style.transition = "none"; self.tipsPos(target, tipsResult); addHistory(); setTimeout(() => { self.tips.style.pointerEvents = "all"; }, 100); } } catch(e) {debug(e)} } }; let showTipsHandler = async (target, time = 1000) => { if (!target || target.nodeType !== 1) return; if (self.preList) { self.preList.style.visibility = "hidden"; self.listArrow.style.cssText = ""; } tipsData = null; clearTimeout(self.requestShowTipsTimer); self.waitForShowTips = false; self.tipsPos(target, tipsStr); if (showTips) { self.stopInput = true; let url = await getUrl(); self.stopInput = false; if (url && self.lastUrl === url) { if (anylizing) { self.tipsPos(target, "<span class='loader'></span><font>Loading...</font>"); } else { setTips(target, url); } } else { self.waitForShowTips = true; self.requestShowTipsTimer = setTimeout(async () => { url = url || await getUrl(); if (!url) return; if (url.indexOf('%input{') !== -1) { self.showCustomInputWindow(url, _url => { url = _url; setTips(target, url); }); return; } self.lastUrl = url; setTips(target, url); self.waitForShowTips = false; }, time); } } } let touchend = false; ele.addEventListener('touchend', e => { if (e.stopPropagation) e.stopPropagation(); if (showTips) { touchend = true; self.waitForShowTips = true; } }, false); let scaleMove = e => { if (self.funcKeyCall || searchData.prefConfig.noAni) return; let leftRight = self.con.classList.contains("search-jumper-left") || self.con.classList.contains("search-jumper-right"); let newDockerScaleBtns = []; let curRect = ele.getBoundingClientRect(); let offset = leftRight ? Math.abs(e.clientY - curRect.top) / curRect.height : Math.abs(e.clientX - curRect.left) / curRect.width; let scale1st = 0.1; let scale2nd = 0.1; ele.style.setProperty("--scale", 1 + scale1st + scale2nd); newDockerScaleBtns.push(ele); let pre = ele.previousElementSibling; if (pre && /^A$/i.test(pre.nodeName)) { pre.style.setProperty("--scale", 1 + scale2nd + scale1st * (1 - offset)); newDockerScaleBtns.push(pre); let prepre = pre.previousElementSibling; if (prepre && /^A$/i.test(prepre.nodeName)) { prepre.style.setProperty("--scale", 1 + scale2nd * (1 - offset)); newDockerScaleBtns.push(prepre); } } let next = ele.nextElementSibling; if (next && /^A$/i.test(next.nodeName)) { next.style.setProperty("--scale", 1 + scale2nd + scale1st * offset); newDockerScaleBtns.push(next); let nextnext = next.nextElementSibling; if (nextnext && /^A$/i.test(nextnext.nodeName)) { nextnext.style.setProperty("--scale", 1 + scale2nd * offset); newDockerScaleBtns.push(nextnext); } } self.dockerScaleBtns.forEach(btn => { if (newDockerScaleBtns.indexOf(btn) === -1) { btn.style.setProperty("--scale", 1); } }); self.dockerScaleBtns = newDockerScaleBtns; }; ele.addEventListener('mouseenter', e => { if (e.stopPropagation) e.stopPropagation(); if (tipsShowing && self.lastTips === ele && self.tips.style.opacity == 1) { return; } self.lastTips = ele; if (showTips) { if (touchend) { touchend = false; return; } if (hasWordParam) { let keywords = self.searchJumperInputKeyWords.value || getKeywords(); if (!keywords) { self.waitForShowTips = true; self.tipsPos(ele, tipsStr); return; } } } showTipsHandler(ele); }, true); ele.addEventListener('mousemove', e => { scaleMove(e); self.clingPos(ele, self.tips); }, false); ele.addEventListener('showTips', e => { self.appendBar(); self.closeOpenType(); self.con.style.display = ""; self.setFuncKeyCall(true); showTipsHandler(targetElement, 0); }, false); ele.addEventListener('mouseleave', e => { if (!tipsShowing) { self.tips.style.opacity = 0; clearTimeout(self.requestShowTipsTimer); } }, false); ele.addEventListener('drop', e => { self.searchBySiteName(name, e); }, false); ele.addEventListener('dragover', e => { e.preventDefault(); }, false); return ele; } closePopupWindow() { if (!searchData.prefConfig.closePopupWhenClick) return; if (this.popupWindow) { this.popupWindow.close(); this.popupWindow = null; } } closeOpenType() { let openType = this.bar.querySelector('.search-jumper-type.search-jumper-open>span'); if (openType) { this.funcKeyCall = false; if (openType.onmouseup) { openType.onmouseup(); } else { let mouseEvent = new PointerEvent("mouseup"); openType.dispatchEvent(mouseEvent); } } } addToHighlightGroup(findWords, addToGroup) { let group = searchData.prefConfig.inPageRule[addToGroup]; if (group) { let groupMatch = group.match(/^\/(.*)\/([il]*)$/); if (groupMatch) { group = `/${groupMatch[1]}|${findWords}/${groupMatch[2] || ''}`; } else group = `/${group}|${findWords}/`; } else { group = `/${findWords}/`; } searchData.prefConfig.inPageRule[addToGroup] = group; storage.setItem("searchData", searchData); this.refreshPageWords(this.lockWords); } streamUpdate(data) { this.streamUpdateCallBack && this.streamUpdateCallBack(data); } async anylizeShowTips(data, name, target) { let tipsResult, self = this; try { const calcReg = /([^\\]|^)([\+\-*/])([\d\.]+)$/; const cacheReg = /\|cache\=(\d+)$/; const postReg = /%p(\{+)/; const headersReg = /#headers({.*?})/; const streamReg = /#stream({(.*?)})?/; const thenReg = /.then{(.*?)}/; data = data.replace(/^showTips:/, '').replace(/{name}/g, name).trim(); if (/^https?:/.test(data)) { let url = data.split("\n"); if (url.length == 1) url = data.split(" "); url = url[0]; data = data.replace(url, "").trim().replace(/\\{/g, "showTipsLeftBrace").replace(/\\}/g, "showTipsRightBrace").replace(/{url}/g, '【SEARCHJUMPERURL】'); let cache = url.match(cacheReg); if (cache) { cache = parseInt(cache[1]); url = url.replace(cacheReg, ""); } else cache = 7200; let now = Date.now() / 1000; let newTipsStorage = tipsStorage.filter(t => { if (now < t.time) { if (!tipsResult && t.url == url) { tipsResult = t.data; } return true; } return false; }); if (newTipsStorage.length != tipsStorage.length) { tipsStorage = newTipsStorage; storage.setItem("tipsStorage", tipsStorage); } let allValue = []; let calcJson = (json, template) => { let finalData = data, allFailed = true; while (template) { let templateArr = template[1].replace(/\\\|/g, "【searchJumperJsonSplit】").split("|"); let props = templateArr[0].replace(/【searchJumperJsonSplit】/g, "|").replace(/\[(\d+)\]/g, ".$1").replace(/\[all\]/g, ".all").split("."), value = json, arrayValue = null; props.shift(); props.forEach(prop => { if (arrayValue) { let tempArray = []; for (let i = 0; i < arrayValue.length; i++) { let curValue = arrayValue[i]; if (curValue) { if (Array.isArray(curValue)) { curValue = curValue.at ? curValue.at(prop) : curValue[prop]; } else curValue = curValue[prop]; } tempArray.push(curValue); } arrayValue = tempArray; } else { if (value) { if (Array.isArray(value)) { if (prop === 'all') { arrayValue = value; } else { value = value.at ? value.at(prop) : value[prop]; } } else value = value[prop]; } if (!value) return null; } }); if (arrayValue) { value = arrayValue.join(""); } if (templateArr.length != 1) { let calcStr = templateArr[1]; let needCalc = calcStr.match(calcReg); if (needCalc) { let calcArr = []; while (needCalc) { calcStr = calcStr.replace(calcReg, "$1"); calcArr.unshift([needCalc[2], needCalc[3]]); needCalc = calcStr.match(calcReg); } calcArr.forEach(calc => { let param = parseFloat(calc[1]); switch (calc[0]) { case "+": value += param; break; case "-": value -= param; break; case "*": value *= param; break; case "/": value /= param; break; } }); value = value.toFixed(2); } else { let fullReg = calcStr.match(/^\/(.*)\/(\w?)$/); let regGroup = fullReg ? new RegExp(fullReg[1], fullReg[2]) : new RegExp(calcStr); let valueMatch = value.match(regGroup); if (valueMatch) { value = valueMatch[1]; } } } if (!value) value = ""; else allFailed = false; allValue.push(value); finalData = finalData.replace(template[0], value); template = finalData.match(/{(.*?)}/); } if (allFailed) { console.log("Error:", json); } finalData = finalData.replace(/showTipsLeftBrace/g, "{").replace(/showTipsRightBrace/g, "}"); return finalData; } let template = data.match(/{(.*?)}/); if (tipsResult) { if (template && template[1].indexOf("json") === 0) { data = data.replace(/【SEARCHJUMPERURL】/g, url); tipsResult = calcJson(tipsResult, template); tipsResult = [tipsResult, "\n" + allValue.join(",")]; } } else { let storeData; let postMatch = url.match(postReg), fetchOption = {}, _url = url; if (postMatch) { let braceNum = postMatch[1].length; postMatch = url.match(new RegExp(`%p\{+(.*?)\}{${braceNum}}`)); if (postMatch) { let body = postMatch[1]; if (body.indexOf("%") === 0) { try { body = decodeURIComponent(body); } catch(e) {} } fetchOption.body = body; fetchOption.method = "POST"; _url = _url.replace(postMatch[0], ""); } } let headersMatch = url.match(headersReg); if (headersMatch) { let headers = headersMatch[1]; if (headers.indexOf("%") === 0 || headers.indexOf("%") === 1) { try { headers = decodeURIComponent(headers); } catch(e) {} } fetchOption.headers = JSON.parse(headers); _url = _url.replace(headersMatch[0], ""); } let failed = false, fetchData; let isJson = (template && template[1].indexOf("json") === 0); let streamMatch = url.match(streamReg); if (streamMatch) { fetchOption.responseType = "stream"; fetchOption.streamMode = streamMatch[2] || "concat"; _url = _url.replace(streamMatch[0], ""); tipsResult = await new Promise(resolve => { fetchOption.onstream = data => { let result; if (isJson) { result = data.json(); if (!result) return; result = calcJson(result, template); } else result = data.text; self.tipsPos(target, result); self.tips.style.pointerEvents = "all"; resolve && resolve(result); }; if (ext) { self.streamUpdateCallBack = data => { let result; if (isJson) { if (!data.json) return; result = calcJson(data.json, template); } else result = data.text; self.tipsPos(target, result); self.tips.style.pointerEvents = "all"; resolve && resolve(result); }; fetchData = new Promise((resolve) => { chrome.runtime.sendMessage({action: "showTips", detail: {from: url + `\n{${template[1]}}`}}, function(r) { data = data.replace(/【SEARCHJUMPERURL】/g, (r && r.finalUrl) || ""); resolve(isJson ? r.json : r.text); }); }); } else { fetchData = GM_fetch(_url, fetchOption).then(r => { data = data.replace(/【SEARCHJUMPERURL】/g, r.finalUrl); return isJson ? r.json() : r.text; }); } fetchData.then(r => { let finalData = isJson ? (r && calcJson(r, template)) : r; if (!finalData) return; self.tipsPos(target, finalData); resolve && resolve(finalData); }); }); if (!tipsResult) { tipsResult = "No result"; failed = true; } } else if (isJson) { let allValue = []; if (ext) { fetchData = new Promise((resolve) => { chrome.runtime.sendMessage({action: "showTips", detail: {from: url + `\n{${template[1]}}`}}, function(r) { data = data.replace(/【SEARCHJUMPERURL】/g, (r && r.finalUrl) || ""); resolve((r && r.data) || ""); }); }); } else { fetchData = GM_fetch(_url, fetchOption).then(r => { data = data.replace(/【SEARCHJUMPERURL】/g, r.finalUrl); return r.json(); }); } tipsResult = await fetchData.then(r => { if (!r) return null; storeData = r; let finalData = calcJson(r, template); return finalData; }); if (!tipsResult) { tipsResult = "No result"; failed = true; } tipsResult = [tipsResult, "\n" + allValue.join(",")]; } else { let hasData = false; let thenMatch = _url.match(thenReg), thenEleSelArr = []; while (thenMatch) { let thenEleSel = thenMatch[1]; thenEleSelArr.push(thenEleSel); _url = _url.replace(thenMatch[0], ""); thenMatch = _url.match(thenReg); } if (ext) { fetchData = new Promise((resolve) => { chrome.runtime.sendMessage({action: "showTips", detail: {from: url + `\n `}}, function(r) { if (data.indexOf('【SEARCHJUMPERURL】') != -1) { data = data.replace(/【SEARCHJUMPERURL】/g, (r && r.finalUrl) || ""); hasData = true; } resolve((r && r.data) || ""); }); }); while (thenEleSelArr.length) { let thenEleSel = thenEleSelArr.shift(); let thenUrl = await fetchData.then(r => { let doc = document.implementation.createHTMLDocument(''); doc.documentElement.innerHTML = createHTML(r); let ele = getElement(thenEleSel, doc); if (!ele) return null; let basepath = doc.querySelector("base"); return canonicalUri(ele.getAttribute("href"), (basepath ? basepath.href : _url)); }); if (thenUrl) { fetchData = new Promise((resolve) => { chrome.runtime.sendMessage({action: "showTips", detail: {from: thenUrl + `\n `}}, function(r) { resolve((r && r.data) || ""); }); }); } else return "No result"; } } else { fetchData = GM_fetch(_url, fetchOption).then(r => { if (data.indexOf('【SEARCHJUMPERURL】') != -1) { data = data.replace(/【SEARCHJUMPERURL】/g, r.finalUrl); hasData = true; } return r.text(); }); while (thenEleSelArr.length) { let thenEleSel = thenEleSelArr.shift(); let thenUrl = await fetchData.then(r => { let doc = document.implementation.createHTMLDocument(''); doc.documentElement.innerHTML = createHTML(r); let ele = getElement(thenEleSel, doc); if (!ele) return null; let basepath = doc.querySelector("base"); return canonicalUri(ele.getAttribute("href"), (basepath ? basepath.href : _url)); }); if (thenUrl) { fetchData = GM_fetch(thenUrl).then(r => { return r.text(); }); } else return "No result"; } } let title; tipsResult = await fetchData.then(r => { if (!data) { return r; } let doc = document.implementation.createHTMLDocument(''); doc.documentElement.innerHTML = createHTML(r); title = doc.title; let finalData = data; while (template) { let value = ""; if (template[1] == "title") { value = doc.title; } else { let selArr = template[1].split("|"); let eles = getAllElements(selArr[0], doc); if (eles && eles.length) { hasData = true; if (selArr.length == 1) { value = eles[0].innerText; } else { let key = selArr[1]; let forEachMatch = key.match(/\(.*?\)/g); if (forEachMatch) { [].forEach.call(eles, ele => { let _v = selArr[1]; forEachMatch.forEach(p => { if (p === "()") { _v = _v.replace(p, ele.innerText); } else { key = p.match(/\((.*)\)/)[1]; _v = _v.replace(p, ele.getAttribute(key) || ele[key]); } }); value += _v; }); } else { value = eles[0].getAttribute(key) || eles[0][key]; } } } } finalData = finalData.replace(template[0], value); template = finalData.match(/{(.*?)}/); } if (!hasData) return null; finalData = finalData.replace(/showTipsLeftBrace/g, "{").replace(/showTipsRightBrace/g, "}"); return finalData; }); if (!tipsResult) { tipsResult = "No result"; failed = true; } else { this.insertHistoryUrl(url, title); } tipsResult = [tipsResult, url]; storeData = tipsResult; } if (!failed) { tipsResult = this.calcResult(tipsResult); tipsStorage.push({url: url, data: storeData, time: Date.now() / 1000 + cache}); if (tipsStorage.length > 50) tipsStorage.shift(); storage.setItem("tipsStorage", tipsStorage); } } } else { tipsResult = /\breturn\b/.test(data) ? await new AsyncFunction('fetch', 'storage', 'name', '"use strict";' + data)(GM_fetch, storage, name) : data; tipsResult = this.calcResult(tipsResult); if (targetElement && targetElement.href) { let newTitle = targetElement.title || targetElement.alt || targetElement.innerText; this.insertHistoryUrl(targetElement.href, newTitle); } } } catch(e) {debug(e)} return tipsResult; } calcResult(result) { let isString = typeof result === 'string'; let str = isString ? result : result[0]; const calcRegFull = /{([\d\.]+)(([\+\-*/][\d\.]+)+)}/; const calcRegOperate = /([\+\-*/])([\d\.]+)/; let needCalc = str.match(calcRegFull); if (needCalc) { let calcArr = []; let fullMatch = needCalc[0]; let value = parseFloat(needCalc[1]); let calcStr = needCalc[2]; needCalc = calcStr.match(calcRegOperate); while (needCalc) { calcStr = calcStr.replace(needCalc[0], ""); calcArr.push([needCalc[1], needCalc[2]]); needCalc = calcStr.match(calcRegOperate); } calcArr.forEach(calc => { let param = parseFloat(calc[1]); switch (calc[0]) { case "+": value += param; break; case "-": value -= param; break; case "*": value *= param; break; case "/": value /= param; break; } }); value = value.toFixed(2); str = str.replace(fullMatch, value); } if (isString) { result = str; } else { result[0] = str; } return result; } insertHistoryUrl(url, title) { if (url.indexOf(location.host) === -1) return; let curUrl = location.href; let oldTitle = document.title; _unsafeWindow.history.pushState('', title, url); document.title = title; _unsafeWindow.history.replaceState('', oldTitle, curUrl); document.title = oldTitle; } checkScroll(noIntoView, noSmooth) { if (this.funcKeyCall || this.bar.style.display == "none") return; let viewWidth = window.innerWidth || document.documentElement.clientWidth; let viewHeight = window.innerHeight || document.documentElement.clientHeight; if (this.bar.scrollWidth > viewWidth || this.bar.scrollHeight > viewHeight) { if (!this.con.classList.contains("search-jumper-scroll")) { this.bar.style.cssText = ""; this.con.classList.add("search-jumper-scroll"); this.con.style.display = ""; } } else { if (this.con.classList.contains("search-jumper-scroll")) { this.bar.style.cssText = ""; this.con.classList.remove("search-jumper-scroll"); } } if (noIntoView) return; let firstType = this.bar.querySelector(".search-jumper-type.search-jumper-open"); if (firstType) { if (firstType.style.width === "0px") { firstType.style.width = "auto"; } if (firstType.style.height === "0px") { firstType.style.height = "auto"; } if (firstType != this.bar.firstElementChild) { setTimeout(() => { firstType.scrollIntoView(noSmooth ? {} : {behavior: "smooth"}); }, 0); } } } reopenType(type) { let mouseEvent = new PointerEvent("mouseup"); if (type.parentNode.classList.contains('search-jumper-open')) { if (type.onmouseup) type.onmouseup(); else { type.dispatchEvent(mouseEvent); } } if (type.onmouseup) type.onmouseup(); else { type.dispatchEvent(mouseEvent); } } showInPage(_funcKeyCall, e) { if (this.contains(targetElement) || (this.inInput && mainStyleEle) || (!_funcKeyCall && this.funcKeyCall)) { return; } if (!mainStyleEle || !mainStyleEle.parentNode) { mainStyleEle = _GM_addStyle(cssText); if (!disabled) this.addToShadow(mainStyleEle); } let selectStr = getSelectStr(); if (_funcKeyCall && selectStr && selectStr.length < (searchData.prefConfig.limitPopupLen || 1)) return; if (this.con && this.con.classList.contains("search-jumper-showall")) return; if (searchData.prefConfig.hidePopup) _funcKeyCall = false; if (!targetElement) targetElement = getBody(document); else if (!selectStr && targetElement != getBody(document) && (targetElement.className != "searchJumper" || !/^MARK$/i.test(targetElement.nodeName))) { let _targetElement = targetElement, children; while (_targetElement && _targetElement.nodeName) { if (/^(img|audio|video|a)$/i.test(_targetElement.nodeName)) break; if (_targetElement.parentNode) { if (/^(img|audio|video|a)$/i.test(_targetElement.parentNode.nodeName)) { _targetElement = _targetElement.parentNode; break; } children = _targetElement.parentNode.querySelectorAll("audio,video"); if (children && children.length !== 1) { children = _targetElement.parentNode.querySelectorAll("img"); } if (children && children.length !== 1) { children = _targetElement.parentNode.querySelectorAll("a"); } if (children && children.length === 1) { if (children[0].scrollHeight && _targetElement.scrollHeight / children[0].scrollHeight < 2) { _targetElement = children[0]; } break; } } _targetElement = _targetElement.parentNode; } if (_targetElement) targetElement = _targetElement; } this.appendBar(); let self = this; if (this.hideTimeout) { clearTimeout(this.hideTimeout); } var delay = searchData.prefConfig.autoDelay || 1000; var hideHandler = () => { self.bar.classList.remove("search-jumper-isInPage"); self.bar.classList.remove("search-jumper-isTargetImg"); self.bar.classList.remove("search-jumper-isTargetAudio"); self.bar.classList.remove("search-jumper-isTargetVideo"); self.bar.classList.remove("search-jumper-isTargetLink"); self.bar.classList.remove("search-jumper-isTargetPage"); self.bar.classList.remove("initShow"); self.hideTimeout = null; }; if (searchData.prefConfig.autoHide) this.hideTimeout = setTimeout(hideHandler, delay); this.bar.classList.remove("search-jumper-isInPage"); this.bar.classList.remove("search-jumper-isTargetImg"); this.bar.classList.remove("search-jumper-isTargetAudio"); this.bar.classList.remove("search-jumper-isTargetVideo"); this.bar.classList.remove("search-jumper-isTargetLink"); this.bar.classList.remove("search-jumper-isTargetPage"); this.bar.classList.remove("initShow"); this.tips.style.opacity = 0; this.tips.style.display = "none"; this.tips.style.transition = "none"; this.tips.innerHTML = createHTML(""); setTimeout(() => {this.bar.classList.add("initShow");}, 10); let typeSel = "", secondType = ""; if (selectStr) { this.bar.classList.add("search-jumper-isInPage"); if (this.bar.style.display == "none" || _funcKeyCall) { typeSel = "needInPage"; } else { let openType = this.bar.querySelector(".search-jumper-type.search-jumper-open"); if (!openType || openType.classList.contains('notmatch') || openType.classList.contains('search-jumper-targetPage') || openType.classList.contains('search-jumper-targetImg') || openType.classList.contains('search-jumper-targetAudio') || openType.classList.contains('search-jumper-targetVideo') || openType.classList.contains('search-jumper-targetLink')) { typeSel = "needInPage"; } } } else { if (targetElement.children.length == 1 && targetElement.children[0].nodeName.toUpperCase() === 'A') { targetElement = targetElement.children[0]; } switch (targetElement.nodeName.toUpperCase()) { case 'IMG': this.bar.classList.add("search-jumper-isTargetImg"); typeSel = "targetImg"; break; case 'AUDIO': this.bar.classList.add("search-jumper-isTargetAudio"); typeSel = "targetAudio"; break; case 'VIDEO': this.bar.classList.add("search-jumper-isTargetVideo"); typeSel = "targetVideo"; break; case 'A': this.bar.classList.add("search-jumper-isTargetLink"); typeSel = "targetLink"; break; default: break; } let parentNode = targetElement.parentNode; if (parentNode && parentNode.nodeName.toUpperCase() === 'A') { this.bar.classList.add("search-jumper-isTargetLink"); if (!typeSel) { typeSel = "targetLink"; } else secondType = "targetLink"; } if (!typeSel) { this.bar.classList.add("search-jumper-isTargetPage"); typeSel = "targetPage"; } if (!typeSel) { typeSel = "targetAll"; } } if (this.bar.style.display == "none") { this.bar.style.display = ""; } let firstType, targetSiteImgs; if (typeSel) { firstType = this.bar.querySelector(`.search-jumper-${typeSel}:not(.notmatch)>span`); targetSiteImgs = this.bar.querySelectorAll(`.search-jumper-${typeSel}:not(.notmatch)>a>img`); } self.setFuncKeyCall(false); if (firstType) { if ((!searchData.prefConfig.disableAutoOpen && !searchData.prefConfig.disableTypeOpen) || _funcKeyCall) { let targetTypes = this.bar.querySelectorAll(`.search-jumper-${typeSel}:not(.notmatch)>span:first-child`); [].forEach.call(targetTypes, type => { if (type !== firstType) { self.reopenType(type); } }); self.reopenType(firstType); self.insertHistory(firstType.parentNode); if (secondType) { targetTypes = this.bar.querySelectorAll(`.search-jumper-${secondType}:not(.notmatch)>span:first-child`); [].forEach.call(targetTypes, type => { if (type !== firstType) { self.reopenType(type); } }); self.reopenType(firstType); } } } if (!_funcKeyCall && (searchData.prefConfig.disableAutoOpen || searchData.prefConfig.disableTypeOpen)) { this.closeOpenType(); } self.setFuncKeyCall(_funcKeyCall); if (_funcKeyCall) { if (targetSiteImgs) { [].forEach.call(targetSiteImgs, siteImg => { if (siteImg.parentNode.style.display != "none" && siteImg.dataset.src) { siteImg.src = siteImg.dataset.src; delete siteImg.dataset.src; } }); } self.con.classList.remove("search-jumper-scroll"); self.bar.style.cssText = ""; self.con.style.cssText = ""; let viewWidth = window.innerWidth || document.documentElement.clientWidth; let scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft; let viewHeight = window.innerHeight || document.documentElement.clientHeight; let tileOffset = searchData.prefConfig.tileOffset || 0; let _clientX = pageX(e) - self.bar.clientWidth / 2 - (getComputedStyle(document.documentElement).position !== 'static' ? document.documentElement.offsetLeft : 0); if (_clientX < 0) _clientX = 5; else if (_clientX + self.bar.clientWidth > viewWidth + scrollLeft) _clientX = viewWidth + scrollLeft - self.bar.clientWidth - 20; let _clientY = pageY(e); if (clientY(e) > viewHeight / 5) _clientY -= (self.bar.clientHeight + 20 + tileOffset); else _clientY += (20 + tileOffset); if (clientX(e) < viewWidth / 2) { self.bar.style.left = _clientX + scrollLeft + "px"; self.bar.style.transformOrigin = '0 0'; } else { self.bar.style.right = viewWidth - _clientX - self.bar.clientWidth - 15 + "px"; self.bar.style.transformOrigin = '100% 0'; } self.bar.style.top = _clientY + "px"; self.removeBar(); self.bar.style.opacity = 0; setTimeout(() => { self.appendBar(); setTimeout(() => { self.bar.style.opacity = 1; setTimeout(() => { let saladict = document.querySelector('#saladict-saladbowl-root>.saladict-external'); if (saladict) { let saladbowl = saladict.shadowRoot.querySelector('.saladbowl'); saladbowl.style.transform = saladbowl.style.transform.replace(/\d+px\)/, `${e.clientY - 15}px)`); } }, 100); }, 1); }, 1); } else { self.bar.style.display = ""; self.initPos(); } } setFuncKeyCall(value) { this.funcKeyCall = value; if (!this.con.classList.contains("search-jumper-showall")) { if (value) { this.con.classList.add("funcKeyCall"); } else { this.con.classList.remove("funcKeyCall"); } } } initPos(relX, relY, posX, posY) { if (this.preList) { this.preList.style.visibility = "hidden"; this.preList.style.opacity = 0; this.listArrow.style.cssText = ""; } if (typeof relX === 'undefined') { relX = searchData.prefConfig.position.x; } if (typeof relY === 'undefined') { relY = searchData.prefConfig.position.y; } if (typeof posX === 'undefined') { posX = searchData.prefConfig.offset.x; } if (typeof posY === 'undefined') { posY = searchData.prefConfig.offset.y; } let self = this; let setClass = className => { self.bar.style.cssText = ""; self.con.style.cssText = ""; self.con.className = "search-jumper-searchBarCon " + className; if (searchData.prefConfig.resizePage) { if (typeof self.initBodyStyle == 'undefined') self.initBodyStyle = getBody(document).style.cssText; else getBody(document).style.cssText = self.initBodyStyle; self.con.classList.add("resizePage"); getBody(document).style.position = "absolute"; switch (className) { case "search-jumper-left": getBody(document).style.width = `calc(100vw - ${self.scale * 42}px)`; getBody(document).style.right = "0px"; break; case "search-jumper-right": getBody(document).style.width = `calc(100vw - ${self.scale * 42}px)`; getBody(document).style.left = "0px"; break; case "search-jumper-bottom": getBody(document).style.width = "100%"; getBody(document).style.height = `calc(100vh - ${self.scale * 42}px)`; getBody(document).style.top = "0px"; getBody(document).style.overflow = "auto"; break; default: getBody(document).style.width = "100%"; getBody(document).style.height = `calc(100vh - ${self.scale * 42}px)`; getBody(document).style.bottom = "0px"; getBody(document).style.overflow = "auto"; break; } } else if (searchData.prefConfig.autoHideAll) { self.con.classList.add("hideAll"); } let baseSize = self.scale * 40; setTimeout(() => { let leftRight = self.con.classList.contains("search-jumper-left") || self.con.classList.contains("search-jumper-right"); searchTypes.forEach(ele => { if (!ele.classList.contains("search-jumper-open")) { if (leftRight) { ele.style.width = ""; ele.style.height = baseSize + "px"; } else { ele.style.width = baseSize + "px"; ele.style.height = ""; } } else { let scrollSize = Math.max(ele.scrollWidth, ele.scrollHeight); if (scrollSize) { scrollSize += "px"; if (leftRight) { ele.style.width = ""; ele.style.height = scrollSize; } else { ele.style.width = scrollSize; ele.style.height = ""; } } } }); }, 1); }; if (posX < 0) { posX = 0; } if (posY < 0) { posY = 0; } if (relX == "center" && relY == "top") { //上中 setClass(""); self.bar.style.position = "relative"; } else if (relX == "left" && relY == "top") { if (posX > posY) { //上左 setClass(""); self.bar.style.position = "fixed"; self.bar.style.left = posX + "px"; } else { //左上 setClass("search-jumper-left"); self.bar.style.position = "fixed"; self.bar.style.top = posY + "px"; } } else if (relX == "right" && relY == "top") { if (posX > posY) { //上右 setClass(""); self.bar.style.position = "fixed"; self.bar.style.right = posX + "px"; } else { //右上 setClass("search-jumper-right"); self.bar.style.position = "fixed"; self.bar.style.top = posY + "px"; } } else if (relX == "center" && relY == "bottom") { //下中 setClass("search-jumper-bottom"); self.bar.style.position = "relative"; } else if (relX == "left" && relY == "bottom") { if (posX > posY) { //下左 setClass("search-jumper-bottom"); self.bar.style.position = "fixed"; self.bar.style.left = posX + "px"; self.bar.style.bottom = "0px"; self.bar.style.top = "unset"; } else { //左下 setClass("search-jumper-left"); self.bar.style.position = "fixed"; self.bar.style.bottom = posY + "px"; } } else if (relX == "right" && relY == "bottom") { if (posX > posY) { //下右 setClass("search-jumper-bottom"); self.bar.style.position = "fixed"; self.bar.style.right = posX + "px"; self.bar.style.bottom = "0px"; self.bar.style.top = "unset"; } else { //右下 setClass("search-jumper-right"); self.bar.style.position = "fixed"; self.bar.style.bottom = posY + "px"; } } else if (relX == "left" && relY == "center") { //左中 setClass("search-jumper-left"); self.bar.style.position = "relative"; self.bar.style.marginTop = posY + "px"; self.con.style.display = "flex"; self.con.style.justifyContent = "center"; } else if (relX == "right" && relY == "center") { //右中 setClass("search-jumper-right"); self.bar.style.position = "absolute"; self.bar.style.marginTop = posY + "px"; self.con.style.display = "flex"; self.con.style.justifyContent = "center"; self.con.style.alignItems = "flex-end"; } searchData.prefConfig.position.x = relX; searchData.prefConfig.position.y = relY; searchData.prefConfig.offset.x = posX; searchData.prefConfig.offset.y = posY; if (searchData.prefConfig.disableAutoOpen || searchData.prefConfig.disableTypeOpen) { self.checkScroll(false, true); } else { setTimeout(() => { let openType = self.bar.querySelector('.search-jumper-type.search-jumper-open'); if (openType) { openType.style.transition = "none"; openType.style.width = "auto"; openType.style.height = "auto"; setTimeout(() => { openType.style.width = openType.scrollWidth + "px"; openType.style.height = openType.scrollHeight + "px"; setTimeout(() => { openType.style.transition = ""; }, 1); self.checkScroll(false, true); }, 0); } }, 251); } } } class Picker { //static picker; constructor() { this.clickedIndex = 0; this.signList = [];//所有标记 this.clickedEles = {};//点击的元素 this.exact = true; this.accu = 0; this.wheelScrolling = false; } /*static getInstance() { if (!Picker.picker) { Picker.picker = new Picker(); } return Picker.picker; }*/ getSelector(callback, exact = true) { this.exact = exact; this.close(); this.toggle(); this.callback = callback; } init() { if (this.inited) return; this.inited = true; let self = this; let cssText = ` body.searchJumper-picker, body.searchJumper-picker *:hover, body.searchJumper-picker a:hover { cursor: crosshair !important; } .select-rect { position: fixed; z-index: 2147483647; background: none; border: 1px dashed rgba(120, 170, 210, 0.8); } .select-rect>.dot { width: 10px; height: 10px; border: 2px solid #000; border-radius: 50%; background-color: white; position: absolute; } .select-rect>.top-left { top: -5px; left: -5px; } .select-rect>.top-right { top: -5px; right: -5px; } .select-rect>.bottom-left { bottom: -5px; left: -5px; } .select-rect>.bottom-right { bottom: -5px; right: -5px; } .select-rect>.top { top: -5px; left: calc(50% - 5px); } .select-rect>.right { top: calc(50% - 5px); right: -5px; } .select-rect>.left { top: calc(50% - 5px); left: -5px; } .select-rect>.bottom { bottom: -5px; left: calc(50% - 5px); } `; _GM_addStyle(cssText); let clickTarget = target => { if (!target) return; if (self.callback) { if (target) { let sel = self.geneSelector(target, self.exact); self.callback(sel); self.close(); } return; } let sign = self.createSignDiv(); self.clickedEles[self.clickedIndex] = target; self.appendSign(sign, target, self.clickedIndex); self.clickedIndex++; searchBar.con.classList.add("selectedEle"); } let cleanTimer; this.initSelectRect(); this.mainSignDiv = this.createSignDiv(); this.setImportant(this.mainSignDiv, "pointer-events", "none"); this.setImportant(this.mainSignDiv, "background", "rgba(120, 170, 210, 0.3)"); this.moveHandler = e => { if (e.target === document) return; if (self.inPicker) { e.preventDefault(); } if (self.rectSelecting) { if (self.mainSignDiv.parentNode) self.mainSignDiv.parentNode.removeChild(self.mainSignDiv); if (!self.selectRect.parentNode) getBody(document).appendChild(self.selectRect); self.createSelectRect({x: e.clientX, y: e.clientY}); } else if (self.creatingRect) { return; } else { let target = self.getTarget(e.target); if (self.mainSignDiv.parentNode !== target.parentNode) target.parentNode.appendChild(self.mainSignDiv); self.adjustSignDiv(self.mainSignDiv, target); if (e.ctrlKey || e.metaKey) { clearTimeout(cleanTimer); cleanTimer = setTimeout(() => { let target = self.cleanTarget(e.target); clickTarget(target); }, 5); } } }; this.leaveHandler = e => { if (self.mainSignDiv.parentNode) self.mainSignDiv.parentNode.removeChild(self.mainSignDiv); }; this.clickHandler = e => { if (self.inPicker) { e.stopPropagation(); e.preventDefault(); } if (self.creatingRect) return; if (self.rectSelecting) { if (self.selectRect.parentNode) { self.selectRect.parentNode.removeChild(self.selectRect); } self.rectSelecting = false; searchBar.bar.classList.remove("rectSelecting"); return; } let target = self.getTarget(e.target); clickTarget(target); }; this.mouseDownHandler = e => { self.rectSelecting = true; searchBar.bar.classList.add("rectSelecting"); self.rectInitPos = {x: e.clientX, y: e.clientY}; e.stopPropagation(); e.preventDefault(); }; this.mouseUpHandler = e => { self.rectSelecting = false; searchBar.bar.classList.remove("rectSelecting"); if (self.creatingRect) return; if (self.selectRect.parentNode) { self.selectRect.parentNode.removeChild(self.selectRect); self.finishSelectRect(); e && e.stopPropagation && e.stopPropagation(); e && e.preventDefault && e.preventDefault(); } }; this.wheelHandler = e => { e.preventDefault(); e.stopPropagation(); if (self.wheelScrolling) return; self.wheelScrolling = true; setTimeout(() => { self.wheelScrolling = false; }, 100); let deltaY; if(e.type !== 'wheel'){ let y = 0; if (typeof e.axis == 'number') { if (e.axis == 2) { y = e.detail; } } else { if (typeof e.wheelDeltaY == 'undefined' || e.wheelDeltaY != 0) { y = -e.wheelDelta / 40; } }; deltaY = y; } else { deltaY = e.deltaY; } if (deltaY > 0) self.accu--; else self.accu++; if (self.accu < 0) self.accu = 0; else if (self.accu > 8) self.accu = 8; let target = self.getTarget(e.target); if (self.mainSignDiv.parentNode !== target.parentNode) target.parentNode.appendChild(self.mainSignDiv); self.adjustSignDiv(self.mainSignDiv, target); }; } initSelectRect() { this.waitToRemoveSigns = []; this.waitToAddSigns = []; let selectRect = document.createElement("div"); selectRect.innerHTML = createHTML(` <div class="dot top-left"></div> <div class="dot top-right"></div> <div class="dot bottom-left"></div> <div class="dot bottom-right"></div> <div class="dot top"></div> <div class="dot right"></div> <div class="dot left"></div> <div class="dot bottom"></div> `); selectRect.className = "select-rect"; this.selectRect = selectRect; } createSelectRect(pos) { this.rectToPos = pos; if (this.creatingRect) return; this.creatingRect = true; setTimeout(() => { this.creatingRect = false; this.selectRect.style.left = Math.min(this.rectToPos.x, this.rectInitPos.x) + "px"; this.selectRect.style.top = Math.min(this.rectToPos.y, this.rectInitPos.y) + "px"; this.selectRect.style.width = Math.abs(this.rectToPos.x - this.rectInitPos.x) + "px"; this.selectRect.style.height = Math.abs(this.rectToPos.y - this.rectInitPos.y) + "px"; this.checkRectAndSign(); if (!this.rectSelecting) this.mouseUpHandler(); }, 100); } finishSelectRect() { let self = this; this.waitToRemoveSigns.forEach(sign => { self.removeSign(sign); }); this.waitToAddSigns.forEach(sign => { delete sign.dataset.recttemp; }); this.waitToRemoveSigns = []; this.waitToAddSigns = []; if (this.signList.length) { searchBar.con.classList.add("selectedEle"); } else { searchBar.con.classList.remove("selectedEle"); } } checkRectAndSign() { if (!this.domInfo) return; let self = this; this.waitToRemoveSigns.forEach(sign => { sign.style.opacity = ""; }); this.waitToRemoveSigns = []; this.signList.forEach(signArr => { let sign = signArr[0]; if (sign.dataset.recttemp) return; let signRect = sign.getBoundingClientRect(); let curRect = self.selectRect.getBoundingClientRect(); if (self.compareRect(signRect, curRect)) { sign.style.opacity = "0"; self.waitToRemoveSigns.push(sign); } else { sign.style.opacity = ""; } }); this.waitToAddSigns.forEach(sign => { self.removeSign(sign); }); this.waitToAddSigns = []; if (this.waitToRemoveSigns.length === 0) { this.curRectInfo = {}; if (this.rectInitPos.x < this.rectToPos.x) { this.curRectInfo.left = this.rectInitPos.x; this.curRectInfo.right = this.rectToPos.x; } else { this.curRectInfo.left = this.rectToPos.x; this.curRectInfo.right = this.rectInitPos.x; } if (this.rectInitPos.y < this.rectToPos.y) { this.curRectInfo.top = this.rectInitPos.y; this.curRectInfo.bottom = this.rectToPos.y; } else { this.curRectInfo.top = this.rectToPos.y; this.curRectInfo.bottom = this.rectInitPos.y; } this.compareDomWithRect(this.domInfo); this.signDomWithRect(this.domInfo); } } compareDomWithRect(dom) { if (dom.children && dom.children.length > 0) { let matched = 0; for (let i = 0; i < dom.children.length; i++) { let child = dom.children[i]; if (this.compareDomWithRect(child)) { matched++; } } if (matched === dom.children.length) { let rect = dom.target.getBoundingClientRect(); if (rect.width && rect.height) { dom.sign = true; return true; } } } else { if (this.compareRect(this.curRectInfo, dom.target.getBoundingClientRect())) { dom.sign = true; return true; } } dom.sign = false; return false; } signDomWithRect(dom) { if (dom.sign) { let sign = this.createSignDiv(); sign.dataset.recttemp = 1; dom.target.parentNode.appendChild(sign); this.adjustSignDiv(sign, dom.target); this.signList.push([sign, dom.target]); this.waitToAddSigns.push(sign); } else if (dom.children && dom.children.length > 0) { for (let i = 0; i < dom.children.length; i++) { let child = dom.children[i]; this.signDomWithRect(child); } } } compareRect(rect1, rect2) { return ( rect2.width && rect2.height && rect1.left <= rect2.right && rect1.right >= rect2.left && rect1.top <= rect2.bottom && rect1.bottom >= rect2.top ); } cleanTarget(target) { if (!target || target.className == "searchJumperSign") return null; target = this.getTarget(target); if (!target) return null; for (let i in this.clickedEles) { let clickedEle = this.clickedEles[i]; try { if (clickedEle == target || clickedEle.contains(target) || target.contains(clickedEle)) return null; } catch (e) { return null; } } return target; } appendSign(sign, target, index) { if (target.dataset) { target.dataset.signNum = parseInt(target.dataset.signNum || 0) + 1; } sign.dataset.target = index; target.parentNode.appendChild(sign); this.adjustSignDiv(sign, target); this.signList.push([sign, target]); } removeSign(sign) { if (sign.parentNode) sign.parentNode.removeChild(sign); for (let i = 0; i < this.signList.length; i++) { let signArr = this.signList[i]; if (signArr[0] === sign) { this.signList.splice(i, 1); break; } } let targetIndex = sign.dataset.target; let target = this.clickedEles[targetIndex]; if (!target) return; let signNum = parseInt(target.dataset.signNum || 0) - 1; target.dataset.signNum = signNum; if (signNum <= 0) { delete this.clickedEles[targetIndex]; } } getTarget(ele) { let accu = this.accu; while (ele && accu) { let parentNode = ele.parentNode; if (!parentNode) break; ele = parentNode; accu--; } while (ele.parentNode && (ele.offsetWidth === 0 || ele.offsetHeight === 0)) { ele = ele.parentNode; } return ele; } close() { if (!this.mainSignDiv) return; if (this.rectSelecting) { if (this.selectRect.parentNode) { this.selectRect.parentNode.removeChild(this.selectRect); } this.finishSelectRect(); this.rectSelecting = false; } this.callback = null; this.domInfo = null; this.clearSigns(); this.clickedEles = {}; if (this.mainSignDiv.parentNode) this.mainSignDiv.parentNode.removeChild(this.mainSignDiv); getBody(document).classList.remove("searchJumper-picker"); searchBar.con.classList.remove("selectedEle"); searchBar.con.removeEventListener("mouseenter", this.leaveHandler, true); getBody(document).removeEventListener("mousemove", this.moveHandler, true); getBody(document).removeEventListener("click", this.clickHandler, true); getBody(document).removeEventListener("mousedown", this.mouseDownHandler, true); getBody(document).removeEventListener("mouseup", this.mouseUpHandler, true); getBody(document).removeEventListener(getSupportWheelEventName(), this.wheelHandler, { passive: false, capture: true }); this.inPicker = false; } setImportant(ele, prop, value) { ele.style.setProperty(prop, value, "important"); } createSignDiv() { let signDiv = document.createElement("div"); this.setImportant(signDiv, "position", "absolute"); this.setImportant(signDiv, "z-index", "2147483647"); this.setImportant(signDiv, "background", "rgba(120, 170, 210, 0.6)"); this.setImportant(signDiv, "transition", "all 0.15s ease-out"); this.setImportant(signDiv, "box-shadow", "rgb(0 0 0) 0px 0px 3px 0px"); this.setImportant(signDiv, "cursor", "pointer"); signDiv.className = "searchJumperSign"; signDiv.addEventListener("mouseenter", e => { if (this.mainSignDiv.parentNode) this.mainSignDiv.parentNode.removeChild(this.mainSignDiv); }, true); signDiv.addEventListener("mousedown", e => { e.stopPropagation(); e.preventDefault(); this.removeSign(signDiv); }, true); return signDiv; } adjustSignDiv(div, target) { this.setImportant(div, "width", target.offsetWidth + "px"); this.setImportant(div, "height", target.offsetHeight + "px"); let left = target.offsetLeft; let top = target.offsetTop; if (target.offsetParent && div.offsetParent && target.offsetParent !== div.offsetParent) { let rect1 = div.offsetParent.getBoundingClientRect(); let rect2 = target.offsetParent.getBoundingClientRect(); left += rect2.left - rect1.left; top += rect2.top - rect1.top; } this.setImportant(div, "left", left + "px"); this.setImportant(div, "top", top + "px"); } geneSelector(ele, id) { let selector = ele.nodeName.toLowerCase(); if (selector !== "html" && selector !== "body") { if (id && ele.id && /^[a-z\-_][\w\-_]+$/i.test(ele.id)) selector = '#' + ele.id; else { if (ele.className) { let classLen = ele.classList.length; selector += [].map.call(ele.classList, d => /^[a-z][\w]+$/i.test(d) || (classLen < 3 && /^[a-z\-_][\w\-_]+$/i.test(d)) ? ('.' + d) : "").join(''); } let parent = ele.parentElement; if (parent) { selector = this.geneSelector(parent, !!id) + ' > ' + selector; if (id && parent.children.length > 1 && !/^HTML$/i.test(parent.nodeName)) { let i, nth = 0, all = 0; for (i = 0; i < parent.children.length; i++) { if (parent.children[i].nodeName == ele.nodeName) { all++; if (parent.children[i] == ele) { nth = all; } if (nth > 0 && all > 1) break; } } selector += (all == 1 ? "" : `:nth-of-type(${nth})`); } } } } return selector; } copy() { let self = this; let html = "", text = ""; this.signList.forEach(sign => { text += "\n" + sign[1].innerText; html += sign[1].outerHTML; }); text = text.trim(); const htmlData = new Blob([html], {type: 'text/html'}) const textData = new Blob([text], {type: 'text/plain'}) try { const item = new ClipboardItem({'text/html': htmlData, 'text/plain': textData}); navigator.clipboard.write([item]).then( () => { _GM_notification('Copied successfully!'); }, (e) => { _GM_setClipboard(text); console.log(e); } ); } catch(e) { _GM_setClipboard(text); } } openLinks() { if (!window.confirm(i18n('batchOpenConfirm'))) return; let links = []; this.signList.forEach(sign => { let ele = sign[1]; if (ele.href) { if (/^(http|ftp)/i.test(ele.href) && links.indexOf(ele.href) === -1) { links.push(ele.href); } } else if (ele.parentNode && ele.parentNode.href) { if (/^(http|ftp)/i.test(ele.parentNode.href) && links.indexOf(ele.parentNode.href) === -1) { links.push(ele.parentNode.href); } } else if (ele.querySelectorAll) { [].forEach.call(ele.querySelectorAll('a[href]'), a => { if (/^(http|ftp)/i.test(a.href) && links.indexOf(a.href) === -1) { links.push(a.href); } }); } }); links.forEach(link => { _GM_openInTab(link, {active: false, insert: true}); }); } getPickerStr() { if (!this.inPicker) return ""; let resultStr = ""; this.signList.forEach(sign => { resultStr += "\n" + sign[1].innerText; }); return resultStr.trim(); } expand() { let self = this; this.clearSigns(); Object.keys(this.clickedEles).forEach(index => { let target = self.clickedEles[index]; let sel = self.geneSelector(target); target.dataset.signNum = 0; [].forEach.call(document.querySelectorAll(sel), ele => { let sign = self.createSignDiv(); getBody(document).appendChild(sign); self.appendSign(sign, ele, index); }); }); } collapse() { let self = this; this.clearSigns(); Object.keys(this.clickedEles).forEach(index => { let target = self.clickedEles[index]; target.dataset.signNum = 0; let sign = self.createSignDiv(); getBody(document).appendChild(sign); self.appendSign(sign, target, index); }); } clearSigns() { this.signList.forEach(sign => { sign = sign[0]; if (sign.parentNode) sign.parentNode.removeChild(sign); }); this.signList = []; } processNode(node, parent) { const nodeInfo = {}; nodeInfo.target = node; nodeInfo.children = []; if (node.nodeType === Node.ELEMENT_NODE) { const style = window.getComputedStyle(node); if (style.display === 'none' && style.visibility === 'hidden') return null; if (node.innerHTML.trim() === "") return null; } else if (node.nodeType !== Node.TEXT_NODE || node.textContent.trim() === "") { return null; } const childNodes = node.childNodes; if (childNodes.length > 0) { nodeInfo.target = node; parent.children.push(nodeInfo); for (const childNode of childNodes) { if (childNode.nodeType === Node.ELEMENT_NODE || childNode.nodeType === Node.TEXT_NODE) { this.processNode(childNode, nodeInfo); } } } else { if (node.nodeType === Node.TEXT_NODE) { const lines = node.textContent.split("\n"); const range = document.createRange(); range.selectNodeContents(node); let offset = 0; let parentNode = node.parentNode; let paRect = parentNode.getBoundingClientRect(); for (const line of lines) { if (line.trim() === '') { offset += (line.length + 1); continue; } range.setStart(node, offset); offset += line.length; range.setEnd(node, offset); offset++; const lineRect = range.getBoundingClientRect(); let offsetLeft = lineRect.left - paRect.left; let offsetTop = lineRect.top - paRect.top; let offsetWidth = lineRect.width; let offsetHeight = lineRect.height; let textNodeInfo = { target: {innerText: line, outerHTML: line, parentNode: parentNode, offsetLeft: offsetLeft + parentNode.offsetLeft, offsetTop: offsetTop + parentNode.offsetTop, offsetWidth: offsetWidth, offsetHeight: offsetHeight, getBoundingClientRect: () => { let paRect = parentNode.getBoundingClientRect(); return { left: paRect.left + offsetLeft, top: paRect.top + offsetTop, right: paRect.left + offsetLeft + offsetWidth, bottom: paRect.top + offsetTop + offsetHeight, width: offsetWidth, height: offsetHeight, }; }} }; parent.children.push(textNodeInfo); } } else if (node.nodeType === Node.ELEMENT_NODE) { nodeInfo.target = node; parent.children.push(nodeInfo); } } return nodeInfo; } toggle(rectSel) { this.init(); if (this.inPicker) { this.close(); return; } this.rectSel = !!rectSel; if (rectSel) { this.domInfo = this.processNode(getBody(document), {children: []}); getBody(document).addEventListener("mousedown", this.mouseDownHandler, true); getBody(document).addEventListener("mouseup", this.mouseUpHandler, true); } else { getBody(document).addEventListener(getSupportWheelEventName(), this.wheelHandler, { passive: false, capture: true }); } this.accu = 0; this.inPicker = true; getBody(document).classList.add("searchJumper-picker"); searchBar.con.addEventListener("mouseenter", this.leaveHandler, true); getBody(document).addEventListener("mousemove", this.moveHandler, true); getBody(document).addEventListener("click", this.clickHandler, true); } } const picker = new Picker(); function emuPress(v) { if (!targetElement) return; let eventParam = v || { key: "Enter", keyCode: 13, bubbles: true }; let event = new KeyboardEvent('keydown', eventParam); targetElement.dispatchEvent(event); event = new KeyboardEvent('keyup', eventParam); targetElement.dispatchEvent(event); event = new KeyboardEvent('keypress', eventParam); targetElement.dispatchEvent(event); debug(targetElement, `press ${v || 'Enter'}`); } async function waitForElement(sel) { return new Promise((resolve) => { let checkInv = setInterval(() => { let result = null; if (!sel) { result = document.readyState === "complete"; } else if (sel === "@") { result = targetElement; } else result = getElement(sel); if (result === false) return null; if (result) { clearInterval(checkInv); resolve(result); } }, 100); }); } async function waitForElementHide(sel) { if (!sel) return null; return new Promise((resolve) => { let checkInv = setInterval(() => { let result = getElement(sel); if (!result) { clearInterval(checkInv); resolve(null); } }, 100); }); } let reachLast = false; async function startInput(input, v) { if (!input) return true; targetElement = input; let event = new FocusEvent('focusin', { bubbles: true }); input.dispatchEvent(event); event = new Event('focus', { bubbles: true }); input.dispatchEvent(event); const selection = window.getSelection(); const range = selection.rangeCount ? selection.getRangeAt(0) : new Range(); range.selectNode(input); selection.removeAllRanges(); selection.addRange(range); await sleep(1); input.type !== 'file' && input.click && input.click(); let lastValue = input.value; if (input.type == 'file') { let file = v; if (file.indexOf('data:') == 0) { file = dataURLtoFile(file); } else { let blob = new Blob([file], { type: 'text/plain' }); file = new File([blob], 'noname.txt', { type: blob.type }) } let dataTransfer = new DataTransfer(); dataTransfer.items.add(file); input.files = dataTransfer.files; v = "c:/fakepath/fakefile"; } else if (/INPUT/i.test(input.nodeName)) { var nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set; nativeInputValueSetter.call(input, v); } else if (/SELECT/i.test(input.nodeName)) { var nativeSelectValueSetter = Object.getOwnPropertyDescriptor(window.HTMLSelectElement.prototype, "value").set; nativeSelectValueSetter.call(input, v); } else if (input.nodeName.toUpperCase() == "TEXTAREA") { var nativeTextareaValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, "value").set; nativeTextareaValueSetter.call(input, v); } else { let contentEditableParent = input; while (contentEditableParent && contentEditableParent.contentEditable !== 'true') { contentEditableParent = contentEditableParent.parentNode; } if (contentEditableParent) { contentEditableParent.dispatchEvent(new InputEvent('beforeinput', {inputType: "insertText", data: v})); await sleep(1); if (input.innerText !== v) { input.innerHTML = createHTML(v); } } else { let file = v; if (file.indexOf('data:') == 0) { file = dataURLtoFile(file); } else { let blob = new Blob([file], { type: 'text/plain' }); file = new File([blob], 'noname.txt', { type: blob.type }) } var pasteEvent = new ClipboardEvent('paste', { target: document.body, clipboardData: new DataTransfer() }); pasteEvent.clipboardData.items.add(file); input.dispatchEvent(pasteEvent); } } event = new Event('input', { bubbles: true }); let tracker = input._valueTracker; if (tracker) { tracker.setValue(lastValue); } input.dispatchEvent(event); event = new Event('change', { bubbles: true }); input.dispatchEvent(event); debug(input, `input`); } async function returnElement(sel, eleIndex = -1) { reachLast = false; let ele; if (eleIndex >= 0) { if (eleIndex === 0) await waitForElement(sel); let eles = getAllElements(sel); if (eles.length === 0) { return true; } if (eles.length === 1) { ele = eles[0]; reachLast = true; } else if (eles.length <= eleIndex) { return true; } else { ele = eles[eleIndex]; if (eles.length === eleIndex + 1) { reachLast = true; } } } else { ele = await waitForElement(sel); if (!ele) return true; } return ele; } async function emuInput(sel, v, eleIndex = -1) { let input = await returnElement(sel, eleIndex); if (input === true) return true; await startInput(input, v); return reachLast; } async function emuClick(sel, eleIndex = -1) { let btn = await returnElement(sel, eleIndex); if (btn === true) return true; targetElement = btn; if(!PointerEvent) return btn.click(); let eventParam = { isTrusted: true, altKey: false, azimuthAngle: 0, bubbles: true, button: 0, buttons: 0, clientX: 1, clientY: 1, cancelBubble: false, cancelable: true, composed: true, ctrlKey: false, defaultPrevented: false, detail: 1, eventPhase: 2, fromElement: null, height: 1, isPrimary: false, metaKey: false, pointerId: 1, pointerType: "mouse", pressure: 0, relatedTarget: null, returnValue: true, shiftKey: false, toElement: null, twist: 0, which: 1 }; btn.focus(); var mouseEvent = new PointerEvent("mouseover",eventParam); btn.dispatchEvent(mouseEvent); mouseEvent = new PointerEvent("pointerover",eventParam); btn.dispatchEvent(mouseEvent); mouseEvent = new PointerEvent("mousedown",eventParam); btn.dispatchEvent(mouseEvent); mouseEvent = new PointerEvent("pointerdown",eventParam); btn.dispatchEvent(mouseEvent); mouseEvent = new PointerEvent("mouseup",eventParam); btn.dispatchEvent(mouseEvent); mouseEvent = new PointerEvent("pointerup",eventParam); btn.dispatchEvent(mouseEvent); let dispatchTouchEvent = (ele, type) => { let touchEvent; try { touchEvent = document.createEvent('TouchEvent') touchEvent.initTouchEvent(type, true, true) } catch (err) { try { touchEvent = document.createEvent('UIEvent') touchEvent.initUIEvent(type, true, true) } catch (err) { touchEvent = document.createEvent('Event') touchEvent.initEvent(type, true, true) } } try { touchEvent.targetTouches = [{ pageX: 1, pageY: 1, clientX: 1, clientY: 1, target: btn }]; touchEvent.touches = [{ pageX: 1, pageY: 1, clientX: 1, clientY: 1, target: btn }]; touchEvent.changedTouches = [{ pageX: 1, pageY: 1, clientX: 1, clientY: 1, target: btn }]; } catch (err) {} ele.dispatchEvent(touchEvent); } dispatchTouchEvent(btn, "touchstart"); dispatchTouchEvent(btn, "touchend"); btn.click(); debug(btn, `click ${sel}`); return reachLast; } async function emuDblClick(sel, eleIndex = -1) { let btn = await returnElement(sel, eleIndex); if (btn === true) return true; targetElement = btn; let eventParam = { isTrusted: true, altKey: false, azimuthAngle: 0, bubbles: true, button: 0, buttons: 0, clientX: 1, clientY: 1, cancelBubble: false, cancelable: true, composed: true, ctrlKey: false, defaultPrevented: false, detail: 2, eventPhase: 2, fromElement: null, height: 1, isPrimary: false, metaKey: false, pointerId: 1, pointerType: "mouse", pressure: 0, relatedTarget: null, returnValue: true, shiftKey: false, toElement: null, twist: 0, which: 1 }; btn.focus(); var mouseEvent = new PointerEvent("mouseover",eventParam); btn.dispatchEvent(mouseEvent); mouseEvent = new PointerEvent("pointerover",eventParam); btn.dispatchEvent(mouseEvent); mouseEvent = new PointerEvent("mousedown",eventParam); btn.dispatchEvent(mouseEvent); mouseEvent = new PointerEvent("pointerdown",eventParam); btn.dispatchEvent(mouseEvent); mouseEvent = new PointerEvent("mouseup",eventParam); btn.dispatchEvent(mouseEvent); mouseEvent = new PointerEvent("pointerup",eventParam); btn.dispatchEvent(mouseEvent); btn.click(); btn.click(); mouseEvent = new MouseEvent("dblclick", { ...eventParam, view: _unsafeWindow }); btn.dispatchEvent(mouseEvent); debug(btn, `dblclick ${sel}`); return reachLast; } async function emuRClick(sel, eleIndex = -1) { let btn = await returnElement(sel, eleIndex); if (btn === true) return true; targetElement = btn; let eventParam = { isTrusted: true, altKey: false, azimuthAngle: 0, bubbles: true, button: 2, buttons: 0, clientX: 1, clientY: 1, cancelBubble: false, cancelable: true, composed: true, ctrlKey: false, defaultPrevented: false, detail: 0, eventPhase: 2, fromElement: null, height: 1, isPrimary: false, metaKey: false, pointerId: 1, pointerType: "mouse", pressure: 0, relatedTarget: null, returnValue: true, shiftKey: false, toElement: null, twist: 0, which: 3 }; btn.focus(); var mouseEvent = new PointerEvent("mouseover",eventParam); btn.dispatchEvent(mouseEvent); mouseEvent = new PointerEvent("pointerover",eventParam); btn.dispatchEvent(mouseEvent); mouseEvent = new PointerEvent("mousedown",eventParam); btn.dispatchEvent(mouseEvent); mouseEvent = new PointerEvent("pointerdown",eventParam); btn.dispatchEvent(mouseEvent); mouseEvent = new PointerEvent("mouseup",eventParam); btn.dispatchEvent(mouseEvent); mouseEvent = new PointerEvent("pointerup",eventParam); btn.dispatchEvent(mouseEvent); mouseEvent = new PointerEvent("contextmenu",eventParam); btn.dispatchEvent(mouseEvent); debug(btn, `rclick ${sel}`); return reachLast; } async function triggerPaste(element, value) { if (!targetElement) return; targetElement.focus(); if (typeof element.value !== "undefined") { const startPos = element.selectionStart; const endPos = element.selectionEnd; let newValue = element.value.substring(0, startPos) + value + element.value.substring(endPos, element.value.length); await startInput(element, newValue); element.selectionStart = startPos + value.length; element.selectionEnd = startPos + value.length; } else { const selection = window.getSelection(); const range = selection.getRangeAt(0); if (!selection.toString()) { range.selectNode(element.childNodes.length === 1 ? element.firstChild : element); } range.deleteContents(); range.insertNode(document.createTextNode(value)); selection.removeAllRanges(); selection.addRange(range); } } function submitByForm(charset, url, target) { url = url.replace(/#(j(umpFrom|f)?|from){(.*?)}/, ""); currentFormParams = {charset: charset, url: url, target: target}; if (url.indexOf("#submitBySearchJumper") !== -1) { currentFormParams = {charset: charset, url: url.replace("#submitBySearchJumper", ""), target: target}; jumpBySearchJumper(); return; } const formId ="searchJumper_form"; var form = document.getElementById(formId); if (!form) { form = document.createElement("form"); form.id = formId; form.style.display = "none"; document.documentElement.appendChild(form); } var params; let postBody = url.match(/[:%]p{(.*?)}/); let targetUrl = url; if (postBody) { targetUrl = url.replace(postBody[0], ''); postBody = postBody[1]; form.method = 'post'; params = new URLSearchParams(postBody); } else { form.method = 'get'; params = new URLSearchParams(new URL(targetUrl).search); } if (charset) { form.acceptCharset = charset; } form.innerHTML = createHTML(); form.target = target; form.action = targetUrl; params.forEach((v, k) => { let input = document.createElement("input"); input.name = k; input.value = v; form.appendChild(input); }); return form.submit(); } function dataURLtoFile(dataurl) { try { var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while(n--) { u8arr[n] = bstr.charCodeAt(n); } } catch(e) { debug(e); } let ext = mime.split("/"); ext = ext.length > 1 ? ext[1] : ext[0]; return new File([u8arr], "image." + ext, {type: mime}); } async function image2Base64(img) { if (!img) return null; if (img.dataset.src) { img.src = img.dataset.src; } if (!img.src) return null; let urlSplit = img.src.split("/"); if (urlSplit[2] == document.domain) { let imgStyle = getComputedStyle(img); var canvas = document.createElement("canvas"); var ctx = canvas.getContext("2d"); if (img.complete) { canvas.width = img.naturalWidth || img.width || parseInt(imgStyle.width); canvas.height = img.naturalHeight || img.height || parseInt(imgStyle.height); ctx.drawImage(img, 0, 0); try { return (canvas.toDataURL("image/png")); } catch (e) { return await imageSrc2Base64(img.src); } } else { return await new Promise((resolve) => { img.addEventListener("load", async e => { canvas.width = img.naturalWidth || img.width || parseInt(imgStyle.width); canvas.height = img.naturalHeight || img.height || parseInt(imgStyle.height); ctx.drawImage(img, 0, 0); try { resolve(canvas.toDataURL("image/png")); } catch (e) { resolve(await imageSrc2Base64(img.src)); } }); }); } } else { return await imageSrc2Base64(img.src); } } async function imageSrc2Base64(src) { let urlSplit = src.split("/"); return new Promise((resolve) => { if (ext) { chrome.runtime.sendMessage({action: "getImgBase64", detail: {img: src}}, function(r) { resolve(r); }); } else { _GM_xmlhttpRequest({ method: 'GET', url: src, responseType:'blob', headers: { origin: urlSplit[0] + "//" + urlSplit[2], referer: location.href, accept: "*/*" }, onload: function(d) { try { var blob = d.response; var fr = new FileReader(); fr.readAsDataURL(blob); fr.onload = function (e) { resolve(e.target.result); }; } catch(e) { resolve(null); } }, onerror: function(){ resolve(null); }, ontimeout: function(){ resolve(null); } }); } }); } function icon2Base64(icon) { let iconStyle = getComputedStyle(icon); let content = getComputedStyle(icon,':before').content.replace(/"/g, ''); if (!content) return false; var canvas = document.createElement("canvas"); canvas.width = icon.clientWidth || parseInt(iconStyle.lineHeight); canvas.height = icon.clientHeight || parseInt(iconStyle.lineHeight); var ctx = canvas.getContext("2d"); ctx.font = iconStyle.font; ctx.strokeStyle = iconStyle.color || "black"; ctx.fillStyle = iconStyle.color || "black"; ctx.textBaseline = "top"; let metrics = ctx.measureText(content); ctx.fillText(content, (canvas.width - metrics.width) / 2, (canvas.height - parseInt(iconStyle.fontSize)) / 2); return canvas.toDataURL("image/png"); } function cacheFontIcon(icon) { let iconName = icon.className.trim().replace('fa fa-', '').replace(/ /g, '_'); if (cacheIcon[iconName]) return; let cache = icon2Base64(icon); if (cache == 'data:,' || !cache) return; cacheIcon[iconName] = cache; storage.setItem("cacheIcon", cacheIcon); } async function cacheAction(target) { if (target.nodeName.toUpperCase() == 'IMG') { let src = target.src || target.dataset.src; if (src) { if (cacheIcon[src]) return; let cache = await image2Base64(target); if (cache == 'data:,' || !cache) cache = 'fail'; cacheIcon[src] = cache; storage.setItem("cacheIcon", cacheIcon); debug(src + " cached, left " + cachePool.length + " icons"); } } else { cacheFontIcon(target); } await new Promise((resolve) => { setTimeout(() => { resolve(true); }, 1); }); } async function cachePoolAction() { while (cachePool.length > 0) { await cacheAction(cachePool.shift()); } } async function cacheImgManager(noti) { if (searchData.prefConfig.cacheSwitch) { let needCache = cachePool.length > 0; await Promise.all([cachePoolAction(), cachePoolAction(), cachePoolAction(), cachePoolAction(), cachePoolAction()]); if (needCache) { if (noti) _GM_notification(i18n("cacheOver")); debug(i18n("cacheOver")); } } } async function cacheFontManager(noti) { if (!isAllPage) { searchBar.con.classList.add("in-input"); searchBar.con.style.visibility = "hidden"; searchBar.con.style.display = ""; searchBar.appendBar(); let needCache = cacheFontPool.length > 0; while (cacheFontPool.length > 0) { await cacheAction(cacheFontPool.shift()); } if (needCache) { let str = 'All font icons cached!'; debug(str); } } } function getSelectStr() { let selStr = extSelectionText || picker.getPickerStr() || window.getSelection().toString(); setTimeout(() => { extSelectionText = ""; }, 1); if (!selStr) { let tar = getActiveElement(document); if (tar && /^(TEXTAREA|INPUT)$/i.test(tar.nodeName)) { let start = tar.selectionStart; let finish = tar.selectionEnd; if (start || finish) selStr = tar.value.substring(start, finish); } } if (selStr) { selStr = selStr.trim(); if (selStr) { return selStr; } } else { if (targetElement && targetElement.className === "searchJumper" && /^MARK$/i.test(targetElement.nodeName)) { return targetElement.dataset.matched || targetElement.innerText; } } return ""; } function keyToReg(key, sign, more) { if (!more) { if (/\w$/.test(key)) { more = '(\\b|$)'; } else more = ''; } return new RegExp(key.replace(/([\*\.\?\+\$\^\[\]\(\)\{\}\|\\\/])/g, "\\$1") + more, sign); } function replaceSingle(str, key, value, after) { if (str.indexOf(key + ".replace(/") !== -1) { let replaceMatch = str.match(keyToReg(key, "", "\\.replace\\(/(.*?[^\\\\])/([gimsuyx]*),\\s*[\"'](.*?[^\\\\])??[\"']\\)")); if (!replaceMatch) return str.replace(keyToReg(key, "g"), (after ? after(value) : value)); value = value.replace(new RegExp(replaceMatch[1], replaceMatch[2]), replaceMatch[3] || ''); str = str.replace(replaceMatch[0], key); return replaceSingle(str, key, value, after); } else { return str.replace(keyToReg(key, "g"), (after ? after(value.replace(/\$/g, "$$$$")) : value.replace(/\$/g, "$$$$"))); } } function getKeywords() { let selStr = getSelectStr(); if (selStr) { return selStr; } if (!currentSite) return localKeywords || ''; //if (localKeywords === '' && cacheKeywords) return cacheKeywords; let keywordsMatch, keywords = '', isUtf8 = !currentSite.charset || currentSite.charset == 'UTF-8'; try { if (currentSite.keywords) { let rules = currentSite.keywords.split("\n"); for (let i = 0; i < rules.length; i++) { let rule = rules[i]; if (!rule || !rule.trim()) continue; let ruleMatch = rules[i].match(/^(.*?)\.replace\(\//); if (ruleMatch) rule = ruleMatch[1]; if (isUtf8) { if (/^\w[\w\|]*$/.test(rule)) { let keywordsList = rule.split("|"); let urlParams = new URLSearchParams(location.search); for (let i = 0; i < keywordsList.length; i++) { keywords = urlParams.get(keywordsList[i]); if (keywords) break; } } else if (/\(.+\)/.test(rule) && rule.indexOf("@") !== 0) { try { keywordsMatch = href.match(new RegExp(rule)); if (keywordsMatch) { keywords = keywordsMatch[1]; } if (keywords) { keywords = decodeURIComponent(keywords); } } catch (e) { keywords = ''; } } } if (!keywords && getBody(document)) { try { let targetEle = getElement(rule); if (targetEle) { keywords = targetEle.value || targetEle.innerText; } } catch (e) { keywords = ''; } } if (keywords && ruleMatch) { keywords = replaceSingle(rules[i], rule, keywords); } if (keywords) break; } } else if (isUtf8 && wordParamReg.test(currentSite.url) && !/[#:%]p{/.test(currentSite.url)) { if (href.indexOf("?") != -1) { keywordsMatch = currentSite.url.match(new RegExp(`[\\?&]([^&]*?)=${wordParam}.*`)); if (keywordsMatch) { keywords = new URLSearchParams(location.search).get(keywordsMatch[1]); } } if (!keywords) { keywordsMatch = currentSite.url.match(new RegExp(`https?://[^/]*/(.*)${wordParam}`)); if (keywordsMatch) { keywordsMatch = href.match(new RegExp((keywordsMatch[1].replace(/\?/g, "\\?") || (location.host.replace(/\./g, "\\.") + "/")) + "(.*?)(\/|$)")); if (keywordsMatch) { keywords = keywordsMatch[1]; } if (keywords) { try { keywords = decodeURIComponent(keywords); } catch (e) { keywords = ''; } } } } } if (keywords == '' && getBody(document)) { let firstInput = getBody(document).querySelector('input[type=text]:not([readonly]),input:not([type])'); if (firstInput) keywords = firstInput.value; } if (keywords) localKeywords = keywords; } catch(e) { debug(e); } return localKeywords || "";//!localKeywords ? cacheKeywords : localKeywords; } function eventSupported(eventName, elem) { elem = elem || document.createElement("div"); eventName = "on" + eventName; var isSupported = (eventName in elem); if (!isSupported) { if (!elem.setAttribute) { elem = document.createElement("div"); }; var setAttr; if (!elem.hasAttribute(eventName)) { setAttr = true; elem.setAttribute(eventName, "return;"); }; isSupported = typeof elem[eventName] == "function"; if (setAttr) elem.removeAttribute(eventName); } return isSupported; } function getSupportWheelEventName() { var ret = 'DOMMouseScroll'; if (eventSupported('wheel')) { ret = 'wheel'; } else if (eventSupported('mousewheel')) { ret = 'mousewheel'; } return ret; } let draging = false; let extSelectionText = ""; function initListener() { _GM_registerMenuCommand(i18n('settings'), () => { _GM_openInTab(configPage, {active: true, insert: true}); }); _GM_registerMenuCommand(i18n('searchInPage'), () => { searchBar.showInPage(); searchBar.showInPageSearch(); }); _GM_registerMenuCommand(i18n('search'), () => { searchBar.searchAuto(0, {}); }); _GM_registerMenuCommand(i18n('addSearchEngine'), () => { let openSearch = document.head.querySelector('[rel="search"]'); if (openSearch) { showSiteAddFromOpenSearch(openSearch.href, (type, e) => { if (type != 'load') { if (e) debug(e.statusText || e.error || e.response || e); let firstInput = getBody(document).querySelector('input[type=text]:not([readonly]),input[type=search]:not([readonly]),input:not([type])') || getBody(document).querySelector('textarea'); quickAddByInput(firstInput); } }); } else { let firstInput = getBody(document).querySelector('input[type=text]:not([readonly]),input[type=search]:not([readonly]),input:not([type])') || getBody(document).querySelector('textarea'); quickAddByInput(firstInput); } }); if (ext) { chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { if (request.selectionText) extSelectionText = request.selectionText; let validCommand = false; switch (request.command) { case "settings": validCommand = true; _GM_openInTab(configPage, {active: true, insert: true}); break; case "searchInPage": validCommand = true; searchBar.showInPage(); searchBar.showInPageSearch(); break; case "filterSearch": validCommand = true; searchBar.showInPage(); searchBar.showFilterSearch(); break; case "search": validCommand = true; if (request.name) { searchBar.searchBySiteName(request.name, request.key || {}); } else { searchBar.searchAuto(request.index || 0, request.key || {}); } break; case "searchAll": validCommand = true; if (request.name) { searchBar.searcAllhByTypeName(request.name); } break; case "toggle": validCommand = true; location.reload(); break; case "streamUpdate": validCommand = true; searchBar.streamUpdate(request.detail); break; case "showAll": validCommand = true; searchBar.toggleShowAll(); break; case "addSearchEngine": { validCommand = true; if (shareEngines) return; let openSearch = document.head.querySelector('[rel="search"]'); if (openSearch) { showSiteAddFromOpenSearch(openSearch.href, (type, e) => { if (type != 'load') { if (e) debug(e.statusText || e.error || e.response || e); let firstInput = getBody(document).querySelector('input[type=text]:not([readonly]),input[type=search]:not([readonly]),input:not([type])') || getBody(document).querySelector('textarea'); quickAddByInput(firstInput); } }); } else { let firstInput = getBody(document).querySelector('input[type=text]:not([readonly]),input[type=search]:not([readonly]),input:not([type])') || getBody(document).querySelector('textarea'); quickAddByInput(firstInput); } } break; default: break; } if (validCommand) { sendResponse({ msg: "ok" }); } }); } document.addEventListener('searchJumper', e => { switch (e.detail.action) { case "search": if (e.detail.name) { searchBar.searchBySiteName(e.detail.name, e.detail.key || {}); } else { searchBar.searchAuto(e.detail.index, e.detail.key || {}); } break; case "show": searchBar.setFuncKeyCall(false); searchBar.showInPage(); if (!searchData.prefConfig.disableInputOnWords || searchBar.inInput || !getSelectStr()) { searchBar.showSearchInput(); } break; case "showAll": searchBar.appendBar(); searchBar.showAllSites(); break; } }); targetElement = getBody(document); let logoSvg = logoBtn.children[0]; let grabState = 0;//0 未按下 1 已按下 2 已拖动 let hideTimer; let touchStart = false; let mouseUpHandler = e => { clearTimeout(hideTimer); searchBar.bar.classList.remove("grabbing"); document.removeEventListener('mouseup', mouseUpHandler, false); document.removeEventListener('mousemove', mouseMoveHandler, false); document.removeEventListener('touchend', mouseUpHandler, false); document.removeEventListener('touchmove', mouseMoveHandler, false); searchBar.bar.style.marginLeft = ""; searchBar.bar.style.marginTop = ""; searchBar.bar.style.transform = ""; if (grabState === 1) { grabState = 0; searchBar.showAllSites(); //_GM_openInTab(configPage, {active: true}); return; } grabState = 0; let viewWidth = window.innerWidth || document.documentElement.clientWidth; let viewHeight = window.innerHeight || document.documentElement.clientHeight; let baseWidth = viewWidth / 3; let baseHeight = viewHeight / 3; let relX, relY, posX, posY; let curX = clientX(e); let curY = clientY(e); if (curX < baseWidth) { relX = "left"; posX = parseInt(searchBar.bar.style.left) > 0 ? parseInt(searchBar.bar.style.left) : 0; } else if (curX < baseWidth * 2) { relX = "center"; posX = parseInt(searchBar.bar.style.left) - viewWidth / 2; } else { relX = "right"; posX = viewWidth - parseInt(searchBar.bar.style.left) - searchBar.bar.scrollWidth; } if (curY < viewHeight / 2) { relY = "top"; posY = parseInt(searchBar.bar.style.top); } else { relY = "bottom"; posY = viewHeight - parseInt(searchBar.bar.style.top) - searchBar.bar.scrollHeight; if (posY < 0) { posY = 0; } } logoSvg.style.cursor = ""; searchBar.closeOpenType(); searchBar.initPos(relX, relY, posX, posY); storage.setItem("searchData", searchData); }; let startPos = {x: 0, y: 0}; let mouseMoveHandler = e => { let curX = clientX(e); let curY = clientY(e); if (Math.abs(startPos.x - curX) + Math.abs(startPos.y - curY) < 50) return; if (grabState === 1) { clearTimeout(hideTimer); logoSvg.style.cursor = "grabbing"; searchBar.bar.style.position = "fixed"; searchBar.bar.style.marginLeft = "0"; searchBar.bar.style.marginTop = "0"; searchBar.bar.style.right = ""; searchBar.bar.style.bottom = ""; searchBar.bar.style.transform = "unset"; searchBar.con.classList.remove("search-jumper-scroll"); searchBar.bar.className = "search-jumper-searchBar grabbing"; } grabState = 2; searchBar.bar.style.left = curX - searchBar.bar.scrollWidth + 20 + "px"; searchBar.bar.style.top = curY - searchBar.bar.scrollHeight + 20 + "px"; }; logoBtn.oncontextmenu = function (event) { searchBar.bar.style.display = 'none'; event.preventDefault(); }; logoBtn.addEventListener('mousedown', e => { if (touchStart) { touchStart = false; return; } if (e.button === 2) { if (searchData.prefConfig.resizePage) { if (typeof searchBar.initBodyStyle != "undefined") getBody(document).style.cssText = searchBar.initBodyStyle; searchBar.con.classList.remove("resizePage"); } document.removeEventListener('mouseup', mouseUpHandler, false); document.removeEventListener('mousemove', mouseMoveHandler, false); document.removeEventListener('touchend', mouseUpHandler, false); document.removeEventListener('touchmove', mouseMoveHandler, false); return; } e.preventDefault(); e.stopPropagation(); if (searchBar.inInput || e.button === 1 || e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) { _GM_openInTab(configPage, {active: true, insert: true}); return; } grabState = 1; startPos = {x: clientX(e), y: clientY(e)}; document.addEventListener('mouseup', mouseUpHandler, false); setTimeout(() => { if (grabState === 1) { document.addEventListener('mousemove', mouseMoveHandler, false); } }, 100); hideTimer = setTimeout(() => { searchBar.bar.style.display = 'none'; document.removeEventListener('mouseup', mouseUpHandler, false); document.removeEventListener('mousemove', mouseMoveHandler, false); }, 2000); }, false); logoBtn.addEventListener('touchstart', e => { e.preventDefault(); e.stopPropagation(); touchStart = true; grabState = 1; startPos = {x: clientX(e), y: clientY(e)}; document.addEventListener('touchend', mouseUpHandler, false); setTimeout(() => { if (grabState === 1) { document.addEventListener('touchmove', mouseMoveHandler, false); } }, 100); hideTimer = setTimeout(() => { searchBar.bar.style.display = 'none'; if (searchData.prefConfig.resizePage) { if (typeof searchBar.initBodyStyle != "undefined") getBody(document).style.cssText = searchBar.initBodyStyle; searchBar.con.classList.remove("resizePage"); } document.removeEventListener('touchend', mouseUpHandler, false); document.removeEventListener('touchmove', mouseMoveHandler, false); }, 1500); }, { passive: false, capture: false }); searchBar.bar.addEventListener(getSupportWheelEventName(), e => { if (e.target.parentNode && (e.target.parentNode.className == "sitelistCon" || (e.target.parentNode.parentNode && e.target.parentNode.parentNode.className == "sitelistCon"))) return; let targetClassList = searchBar.con.classList; if (!targetClassList.contains('search-jumper-scroll')) return; if (targetClassList.contains('search-jumper-left') || targetClassList.contains('search-jumper-right')) return; var deltaX, deltaY; if(e.type !== 'wheel'){ var x = 0, y = 0; if (typeof e.axis == 'number') { if (e.axis == 2) { y = e.detail; } else { x = e.detail; } } else { if (typeof e.wheelDeltaY == 'undefined' || e.wheelDeltaY != 0) { y = -e.wheelDelta / 40; } else { x = -e.wheelDelta / 40; }; }; deltaY = y; deltaX = x; } else { deltaX = e.deltaX; deltaY = e.deltaY; } e.preventDefault(); e.stopPropagation(); searchBar.con.scrollLeft += deltaY; }, { passive: false, capture: false }); if (searchData.prefConfig.shortcut && (searchData.prefConfig.switchSitesPreKey || searchData.prefConfig.switchSitesNextKey || searchData.prefConfig.shortcutKey || searchData.prefConfig.showAllShortcutKey)) { let inputing = -1, key = false; let checkShortcutEnable = (e, _alt, _ctrl, _shift, _meta, _key) => { if ((_alt && !e.altKey) || (_ctrl && !e.ctrlKey) || (_shift && !e.shiftKey) || (_meta && !e.metaKey)) { return false; } if (!key) key = (e.key || String.fromCharCode(e.keyCode)).toLowerCase(); if (_key != key && _key != e.code) { return false; } if (!searchData.prefConfig.enableInInput && inputing == -1) { inputing = 1; if (!_ctrl && !_alt && !_shift && !_meta && inputActive(document)) return false; } inputing = 0; e.preventDefault(); e.stopPropagation(); return true; }; document.addEventListener('mouseenter', e => { if (e.target && !searchBar.contains(e.target)) { hoverElement = e.target; } }, true); document.addEventListener('keydown', e => { if (e.target.id === "searchJumperInput") return; inputing = -1; key = false; if (searchData.prefConfig.shortcutKey) { if (checkShortcutEnable(e, searchData.prefConfig.callBarAlt, searchData.prefConfig.callBarCtrl, searchData.prefConfig.callBarShift, searchData.prefConfig.callBarMeta, searchData.prefConfig.shortcutKey)) { searchBar.setFuncKeyCall(false); searchBar.showInPage(); if (!searchData.prefConfig.disableInputOnWords || searchBar.inInput || !getSelectStr()) { searchBar.showSearchInput(); } } } if (inputing == 1) return; if (searchData.prefConfig.showAllShortcutKey) { if (checkShortcutEnable(e, searchData.prefConfig.showAllAlt, searchData.prefConfig.showAllCtrl, searchData.prefConfig.showAllShift, searchData.prefConfig.showAllMeta, searchData.prefConfig.showAllShortcutKey)) { searchBar.appendBar(); searchBar.showAllSites(); } } if (currentSite && searchBar.bar.style.display !== "none") { if (searchData.prefConfig.switchSitesPreKey) { if (checkShortcutEnable(e, searchData.prefConfig.switchSitesAlt, searchData.prefConfig.switchSitesCtrl, searchData.prefConfig.switchSitesShift, searchData.prefConfig.switchSitesMeta, searchData.prefConfig.switchSitesPreKey)) { searchBar.switchSite(); return; } } if (searchData.prefConfig.switchSitesNextKey) { if (checkShortcutEnable(e, searchData.prefConfig.switchSitesAlt, searchData.prefConfig.switchSitesCtrl, searchData.prefConfig.switchSitesShift, searchData.prefConfig.switchSitesMeta, searchData.prefConfig.switchSitesNextKey)) { searchBar.switchSite(true); } } } }, true); } let clickHandler; if (searchData.prefConfig.enableInPage) { let shown = false; let showToolbarTimer; let tripleClick = false; let clientRect; document.addEventListener('selectionchange', (e) => { if (searchData.prefConfig.leftMouse || searchData.prefConfig.middleMouse) { if (window.getSelection().toString()) { const selection = window.getSelection(); const range = selection.getRangeAt(0); clientRect = range.getBoundingClientRect(); } else { clientRect = null; } } }); let waitForMouse = false; clickHandler = e => { if (shown) { e.preventDefault(); } shown = false; document.removeEventListener('click', clickHandler, true); }; function isTargetInput(target) { let targetInput = false; if (inputActive(document)) { targetInput = true; } else { let contentEditable = false; let parent = target; while (parent) { contentEditable = parent.contentEditable == 'true'; if (contentEditable || parent.nodeName.toUpperCase() == 'BODY') { break; } parent = parent.parentNode; } if (contentEditable) { targetInput = true; } } return targetInput; } let mouseDownHandler = e => { if ((waitForMouse && e.type === 'mousedown' && e.button === 0) || (e.target.classList && e.target.classList.contains('search-jumper-btn')) || searchBar.contains(e.target)) { return; } if (searchBar.bar.classList.contains("grabbing")) return; let targetInput = isTargetInput(e.target); let inputSign = !searchData.prefConfig.enableInInput && targetInput; if (inputSign && e.type === 'dblclick') return; if (searchData.prefConfig.minPopup == 2) { if (targetInput) { searchBar.con.classList.add("targetInput"); } else searchBar.con.classList.remove("targetInput"); } if (e.type === "touchstart") { if (searchData.prefConfig.selectToShow) { setTimeout(() => { if (getSelectStr()) { searchBar.showInPage(true, e); } else searchBar.waitForHide(0); }, 0); } return; } waitForMouse = true; setTimeout(() => { waitForMouse = false; }, 500); shown = false; targetElement = e.target; searchBar.closePopupWindow(); let matchKey = false; if ((searchData.prefConfig.altKey || searchData.prefConfig.ctrlKey || searchData.prefConfig.shiftKey || searchData.prefConfig.metaKey) && !((searchData.prefConfig.altKey && !e.altKey) || (searchData.prefConfig.ctrlKey && !e.ctrlKey) || (searchData.prefConfig.shiftKey && !e.shiftKey) || (searchData.prefConfig.metaKey && !e.metaKey))) { matchKey = true; } if (!searchData.prefConfig.selectToShow) { if ((e.button === 0 && !searchData.prefConfig.leftMouse) || (e.button === 1 && !searchData.prefConfig.middleMouse)) { searchBar.waitForHide(0); return; } } let startX = e.clientX; let startY = e.clientY; let moved = false; let inpageMouseMoveHandler = e => { if (Math.abs(startX - e.clientX) + Math.abs(startY - e.clientY) > 2) { clearTimeout(showToolbarTimer); document.removeEventListener('mousemove', inpageMouseMoveHandler, true); e.target.removeEventListener('scroll', scrollHandler); moved = true; } }; let scrollHandler = e => { clearTimeout(showToolbarTimer); document.removeEventListener('mousemove', inpageMouseMoveHandler, true); e.target.removeEventListener('scroll', scrollHandler); }; let inpageMouseUpHandler = e => { draging = false; if (searchBar.contains(e.target) || shown) { e.preventDefault(); } else { setTimeout(() => { if (shown) return; targetInput = isTargetInput(e.target); inputSign = !searchData.prefConfig.enableInInput && targetInput; if (!inputSign && ( (matchKey && e.button === 2) || ((moved || tripleClick) && e.button === 0 && searchData.prefConfig.selectToShow && getSelectStr()) )) { searchBar.showInPage(true, e); } else { waitForMouse = false; searchBar.waitForHide(0); } }, 0); } clearTimeout(showToolbarTimer); document.removeEventListener('mouseup', inpageMouseUpHandler, true); document.removeEventListener('mousemove', inpageMouseMoveHandler, true); e.target.removeEventListener('scroll', scrollHandler); }; if (e.type === 'dblclick') { if (getSelectStr() !== '') { shown = true; draging = false; document.removeEventListener('mouseup', inpageMouseUpHandler, true); document.removeEventListener('mousemove', inpageMouseMoveHandler, true); e.target.removeEventListener('scroll', scrollHandler); clearTimeout(showToolbarTimer); setTimeout(() => {//wait for triple click searchBar.showInPage(true, e); }, 200); } else { tripleClick = true; setTimeout(() => { tripleClick = false; }, 200); } return; } if (showToolbarTimer) clearTimeout(showToolbarTimer); showToolbarTimer = setTimeout(() => { if (draging) return; if (targetElement != e.target) return; if (e.button === 1 && !searchData.prefConfig.middleMouse) return; if (e.button === 2 && !searchData.prefConfig.rightMouse) return; if (e.button === 0 && !searchData.prefConfig.leftMouse) return; //if (e.button === 0 && getSelectStr() !== '') return; if (searchData.prefConfig.longPressTile) { searchBar.showInPage(true, e); } else { searchBar.setFuncKeyCall(false); searchBar.showInPage(); } shown = true; }, parseInt(searchData.prefConfig.longPressTime)); let canShow = false; if (e.button === 2) { if (matchKey) { canShow = true; } } else { if (e.button === 0) { if (searchData.prefConfig.leftMouse) { canShow = true; } } else if (e.button === 1) { if (searchData.prefConfig.middleMouse) { canShow = true; } } if (canShow) { if (inputSign) { canShow = false; } else if (!clientRect) { canShow = false; } else if (e.clientX < clientRect.left) { canShow = false; } else if (e.clientX > clientRect.left + clientRect.width) { canShow = false; } else if (e.clientY < clientRect.top) { canShow = false; } else if (e.clientY > clientRect.top + clientRect.height) { canShow = false; } } } if (canShow) { setTimeout(() => { if (!draging) { searchBar.showInPage(true, e); } document.removeEventListener('mousemove', inpageMouseMoveHandler, true); e.target.removeEventListener('scroll', scrollHandler); }, 200); shown = true; document.addEventListener('mouseup', inpageMouseUpHandler, true); document.addEventListener('click', clickHandler, true); return false; } document.addEventListener('mousemove', inpageMouseMoveHandler, true); document.addEventListener('mouseup', inpageMouseUpHandler, true); e.target.addEventListener('scroll', scrollHandler); }; document.addEventListener('mousedown', mouseDownHandler); document.addEventListener('dblclick', mouseDownHandler); if (searchData.prefConfig.selectToShow) { let touchTimer, touchstartEvent; let selectionchange = e => { clearTimeout(touchTimer); touchTimer = setTimeout(() => { if (window.getSelection().toString()) { mouseDownHandler(touchstartEvent); document.removeEventListener('selectionchange', selectionchange); } }, 300); }; document.addEventListener('touchstart', e => { if (e.isTrusted === false) return; touchstartEvent = e; document.addEventListener('selectionchange', selectionchange); }); } document.addEventListener('contextmenu', e => { if (shown) e.preventDefault(); shown = false; }); } if (searchData.prefConfig.dragToSearch && !isInConfigPage) { getBody(document).addEventListener('dragstart', e => { if (!e.isTrusted || (searchData.prefConfig.dragAlt && !e.altKey) || (searchData.prefConfig.dragCtrl && !e.ctrlKey) || (searchData.prefConfig.dragShift && !e.shiftKey) || (searchData.prefConfig.dragMeta && !e.metaKey)) { return; } if (!searchData.prefConfig.enableInInput && !e.altKey && !e.ctrlKey && !e.shiftKey && !e.metaKey && inputActive(document)) { return; } targetElement = e.target; if (targetElement.nodeType !== 1) targetElement = targetElement.parentNode; if (targetElement.shadowRoot) { targetElement = targetElement.shadowRoot.activeElement || targetElement; } if (targetElement.getAttribute && targetElement.getAttribute("draggable") == "true") return; if (targetElement.parentNode && targetElement.parentNode.getAttribute && targetElement.parentNode.getAttribute("draggable") == "true") return; searchBar.waitForHide(0); setTimeout(() => { showDragSearch(e.clientX, e.clientY); }, 2); if (clickHandler) document.removeEventListener('click', clickHandler, true); draging = true; }); } if (searchData.prefConfig.quickAddRule) { document.addEventListener('click', e => { if (!(((e.ctrlKey || e.metaKey) && e.shiftKey) || ((e.ctrlKey || e.metaKey) && e.altKey) || (e.altKey && e.shiftKey))) return; if (!/^(INPUT|TEXTAREA)$/i.test(e.target.nodeName)) return; if (/^INPUT$/i.test(e.target.nodeName) && e.target.type && e.target.type != 'text' && e.target.type != 'search') return; quickAddByInput(e.target); }, true); } let changeHandler = e => { setTimeout(() => { searchBar.refresh(); }, 100); } document.addEventListener("fullscreenchange", e => { if (document.fullscreenElement) { searchBar.bar.style.display = 'none'; } }); let waitForClick = false; let clickAHandler = e => { if (waitForClick) return; waitForClick = true; setTimeout(() => { waitForClick = false; }, 300); let _t = e.target; if (currentSite && _t) { if (_t.nodeName && _t.nodeName.toLowerCase && _t.nodeName.toLowerCase() == 'a') { searchBar.updateCacheKeywords(); } else { let _tp = _t.parentNode; if (_tp && _tp.nodeName && _tp.nodeName.toLowerCase && _tp.nodeName.toLowerCase() == 'a') { searchBar.updateCacheKeywords(); } } } }; getBody(document).addEventListener("auxclick", clickAHandler, true); getBody(document).addEventListener("click", clickAHandler, true); let _wr = function(type) { var orig = history[type]; return function() { var rv = orig.apply(this, arguments); let _href = location.href.slice(0, 500); if (href != _href) { href = _href; var e = new Event('sj_' + type); e.arguments = arguments; window.dispatchEvent(e); } return rv; }; }; history.pushState = _wr('pushState'); history.replaceState = _wr('replaceState'); window.addEventListener('sj_pushState', changeHandler); window.addEventListener('sj_replaceState', changeHandler); window.addEventListener('yt-navigate-finish', changeHandler); window.addEventListener("securitypolicyviolation", (e) => { if (e.violatedDirective === 'form-action') { jumpBySearchJumper(); } }); /*let headObserverOptions = { childList: true }; let checkCssEle = ele => { if (ele === mainStyleEle) { mainStyleEle = _GM_addStyle(cssText); } }; let headObserver = new MutationObserver((mutationsList, observer) => { for (let mutation of mutationsList) { if (mutation.type === 'childList' && mutation.removedNodes.length) { [].forEach.call(mutation.removedNodes, removedNode => { checkCssEle(removedNode); }); } } }); headObserver.observe(document.head, headObserverOptions);*/ let removeMark = node => searchBar.removeMark(node); let highlight = (words, node) => searchBar.highlight(words, node); let appendBar = () => searchBar.appendBar(); let bodyObserverOptions = { childList: true, characterData: true, subtree: true }; let highlightTimes = 0; let bodyObserver = new MutationObserver((mutationsList, observer) => { let lockWords = searchBar.lockWords; if (lockWords) { if (searchBar.initHighlight && highlightTimes > 100) return; for (let mutation of mutationsList) { if (mutation.type === "characterData") { let parentNode = mutation.target.parentNode; if (!parentNode || (mutation.target.previousElementSibling && mutation.target.previousElementSibling.className === "searchJumper") || (mutation.target.nextElementSibling && mutation.target.nextElementSibling.className === "searchJumper")) { return; } searchBar.checkCharacterData(parentNode); searchBar.initHighlight && highlightTimes++; } if (mutation.removedNodes.length) { [].forEach.call(mutation.removedNodes, removedNode => { if (removedNode.nodeType !== 1) return; if (removedNode.classList && removedNode.classList.contains("searchJumper")) { removeMark(removedNode); } else if (removedNode.children.length) { [].forEach.call(removedNode.querySelectorAll("mark.searchJumper,a.searchJumper,input.searchJumper,textarea.searchJumper"), node => { removeMark(node); }); } }); } if (mutation.addedNodes.length) { for (let i = 0; i < mutation.addedNodes.length; i++) { let addedNode = mutation.addedNodes[i], target; if (addedNode.nodeType === 1) { if (/^searchJumper$/.test(addedNode.className)) { continue; } target = addedNode; } else { if (addedNode.previousElementSibling && /^searchJumper$/.test(addedNode.previousElementSibling.className)) { continue; } else if (addedNode.nextElementSibling && /^searchJumper$/.test(addedNode.nextElementSibling.className)) { continue; } target = addedNode.parentNode; } if (target) { setTimeout(() => { highlight("insert", target); }, 0); searchBar.initHighlight && highlightTimes++; } } } } appendBar(); } }); bodyObserver.observe(getBody(document), bodyObserverOptions); } function canonicalUri(src, href) { if (!src) { return ""; } let origin, basePath; if (!href) { if (src.charAt(0) == "#") return location.href + src; if (src.charAt(0) == "?") return location.href.replace(/^([^\?#]+).*/, "$1" + src); origin = location.protocol + '//' + location.host; let base = document.querySelector("base"); basePath = base ? base.href : location.href; } else { origin = href.replace(/(^https?:\/\/.+)\/[^\/]*$/, "$1"); basePath = href; } let url = basePath || origin; url = url.replace(/(\?|#).*/, ""); if (/https?:\/\/[^\/]+$/.test(url)) url = url + '/'; if (url.indexOf("http") !== 0) url = origin + url; var root_page = /^[^\?#]*\//.exec(url)[0], root_domain = /^\w+\:\/\/\/?[^\/]+/.exec(root_page)[0], absolute_regex = /^\w+\:\/\//; while (src.indexOf("../") === 0) { src = src.substr(3); root_page = root_page.replace(/\/[^\/]+\/$/, "/"); } src = src.replace(/\.\//, ""); if (/^\/\/\/?/.test(src)) { src = location.protocol + src; } return (absolute_regex.test(src) ? src : ((src.charAt(0) == "/" ? root_domain : root_page) + src)); } function quickAddByInput(input) { if (shareEngines) return; let parentForm, url = location.href; if (input && input.name) { parentForm = input.parentNode; while (parentForm) { if (parentForm.nodeName.toUpperCase() === "FORM") { let target = parentForm.target; if (target && typeof target == "string" && target != '_blank' && target != '_self' && target != '_parent' && target != '_top') { let targetIframe = getBody(document).querySelector(target); if (!targetIframe) { parentForm = null; break; } } break; } parentForm = parentForm.parentNode; } } let fail = () => { if (window.confirm(i18n("noValidItemAsk"))) { return false; } return true; } if (parentForm) { url = canonicalUri(parentForm.getAttribute("action") || url); let params = []; let formData = new FormData(parentForm); for (let [key, value] of formData) { if (input.name === key) { value = "%s"; } else value = encodeURIComponent(value); params.push(key + "=" + value); } if (parentForm.method.toLowerCase() == "post") { url += "%p{" + params.join("&") + "}"; if (parentForm.action.indexOf(location.origin) == 0 && location.pathname && location.pathname !== "/") url += `#from{${location.pathname.slice(1)}}`; } else { let existParams = url.match(/\?(.*)/); if (existParams) { url = url.replace(existParams[0], ""); existParams[1].split("&").forEach(existParam => { let existSplit = existParam.split("="); let key = existSplit[0]; if (params.findIndex(p => p.indexOf(key + "=") === 0) !== -1) return; let value = existSplit[1]; if (value == input.value) value = "%s"; params.push(key + "=" + value); }); } url += "?" + params.join("&"); } } else if (input && input.value) { if (location.href.indexOf(input.value) !== -1) { url = location.href.replace(input.value, "%s"); } else { let encodeValue = encodeURIComponent(input.value); if (location.pathname.indexOf(encodeValue) !== -1 || location.search.indexOf(encodeValue) !== -1) { url = location.origin + location.pathname.replace(encodeValue, "%s") + location.search.replace(encodeValue, "%s"); } else { encodeValue = escape && escape(input.value); if (encodeValue && location.pathname.indexOf(encodeValue) !== -1 || location.search.indexOf(encodeValue) !== -1) { url = location.origin + location.pathname.replace(encodeValue, "%se") + location.search.replace(encodeValue, "%se"); } else { if (fail()) return; } } } } else { if (fail()) return; } let icons = []; [].forEach.call(document.querySelectorAll("link[rel='shortcut icon'],link[rel='icon'],link[rel='fluid-icon'],link[rel='apple-touch-icon']"), link => { if (icons.indexOf && icons.indexOf(link.href) !== -1) return; icons.push(link.href); }); showSiteAdd(document.title.replace(input ? input.value : "", "").replace(/^\s*[-_]\s*/, ""), "", url, icons, document.characterSet); } const jumpHtml = ext ? chrome.runtime.getURL('config/jump.html') : "https://hoothin.github.io/SearchJumper/jump.html"; function jumpBySearchJumper() { let jumpTo = `${jumpHtml}#jump{url=${encodeURIComponent(currentFormParams.url)}&charset=${currentFormParams.charset}}`; if (currentFormParams.target == '_self') { if (ext) { _GM_openInTab(jumpTo, {active: true, insert: true, close: true}); } else { location.href = jumpTo; } } else { _GM_openInTab(jumpTo, {active: true, insert: true}); } } function preAction() { if (href.indexOf(jumpHtml) != -1) { let submitParams = href.match(/#jump{url=(.*)&charset=(.*)}/); if (submitParams) { submitByForm(submitParams[2], decodeURIComponent(submitParams[1]), '_self'); } } } var shareEngines; async function checkConfigPage() { if (href.indexOf(configPage) === 0 || ((document.title === "SearchJumper" || document.querySelector('[name="from"][content="SearchJumper"]')) && document.querySelector('[name="author"][content="Hoothin"]'))) { shareEngines = document.querySelector('[name="engines"]'); let spotlight = document.getElementById("spotlight"); if (shareEngines) { try { shareEngines = shareEngines.getAttribute("content"); if (shareEngines.indexOf("http") === 0) { if (spotlight) { const loadingCollection = i18n("loadingCollection"); spotlight.innerText = loadingCollection; spotlight.setAttribute("spotlight", loadingCollection); } let config = await new Promise((resolve) => { if (ext) { chrome.runtime.sendMessage({action: "getShareEngines", detail: {engineUrl: shareEngines}}, function(r) { resolve(r); }); } else { _GM_xmlhttpRequest({ method: 'GET', url: shareEngines, onload: function(result) { var jsonData = null; try { jsonData = JSON.parse(result.responseText); resolve(jsonData); } catch (e) { console.log(e); resolve(false); } }, onerror: function(e) { console.log(e); resolve(false); }, ontimeout: function(e) { console.log(e); resolve(false); } }); } }); if (config) { searchData.sitesConfig = config; shareEngines = true; } else { shareEngines = false; } } else { searchData.sitesConfig = JSON.parse(decodeURI(shareEngines)); shareEngines = true; } } catch (e) { shareEngines = false; } } let trustSite = href.indexOf(configPage.replace(/\/config.*/, "")) === 0 || href.indexOf(homePage) === 0 || href.indexOf(githubPage) === 0 || location.hostname === "localhost"; if (trustSite) { isAllPage = !!shareEngines || /all(\.html)?$/.test(location.pathname); } if (spotlight) { spotlight.style.display = "none"; } else { setTimeout(() => { spotlight = document.getElementById("spotlight"); if (spotlight) { spotlight.style.display = "none"; } }, 500); } return trustSite; } return false; } async function initConfig() { isInConfigPage = await checkConfigPage(); if (!isInConfigPage && searchData.webdavConfig) { webDAV = new WebDAV(searchData.webdavConfig.host + "/SearchJumper" + (searchData.webdavConfig.path || "").replace(/^\/*/, "/").replace(/\/*$/, "/"), searchData.webdavConfig.username, searchData.webdavConfig.password); } if (isInConfigPage && !isAllPage) { let sendMessageTimer, received = false; let loadConfig = () => { sendMessageTimer = setTimeout(() => { if (!received) { loadConfig(); } }, 50); window.postMessage({ searchData: searchData, cacheIcon: cacheIcon, version: _GM_info.script.version || 0, command: 'loadConfig' }, '*'); } let delayTimeout = setTimeout(() => { if (received) return; location.reload(); }, 3000); document.addEventListener('received', e => { received = true; clearTimeout(sendMessageTimer); clearTimeout(delayTimeout); if (cachePool.length > 0 && searchData.prefConfig.cacheSwitch) { debug(`Start cache ${cachePool.length} icons!`); cacheImgManager(); } }); document.addEventListener('downloadCache', e => { downloadCache(); }); document.addEventListener('importCache', e => { let cacheData = e.detail ? e.detail.cacheData : e.cacheData; importCache(cacheData); _GM_notification('Cache imported successfully!'); }); document.addEventListener('showSiteAdd', e => { let siteData = e.detail ? e.detail.site : e.site; if (!siteData) return; if (siteData.url) { showSiteAdd(siteData.name, siteData.description, siteData.url, (siteData.icon ? [siteData.icon] : []), siteData.charset, siteData.kwFilter, siteData.match, siteData.hideNotMatch); } else { importFilter.open(siteData); } }); loadConfig(); document.addEventListener('dataChanged', e => { loadConfig(); }); let sendVerifyResult = (url, name, status, finalUrl) => { window.postMessage({ url: url, name: name, status: status, finalUrl: finalUrl, command: 'verifyResult' }, '*'); }; document.addEventListener('verifyUrl', e => { let targetUrl = (e.detail ? e.detail.url : e.url); let name = (e.detail ? e.detail.name : e.name); _GM_xmlhttpRequest({ method: 'GET', url: targetUrl, headers: { referer: targetUrl, 'User-Agent': navigator.userAgent }, onload: function(e) { sendVerifyResult(targetUrl, name, e && e.status, e && e.finalUrl); }, onerror: function(e){ sendVerifyResult(targetUrl, name, 'error', ''); }, ontimeout: function(e){ sendVerifyResult(targetUrl, name, 'timeout', ''); } }); }); let preSwitch = searchData.prefConfig.cacheSwitch; document.addEventListener('saveConfig', e => { searchData = (e.detail ? e.detail.searchData : e.searchData) || _unsafeWindow.searchData; storage.setItem("searchData", searchData); let newCache = {}, oldCacheLength = cacheIcon ? Object.keys(cacheIcon).length : 0; if (preSwitch == searchData.prefConfig.cacheSwitch) { searchData.sitesConfig.forEach(type => { if (/^[a-z\- ]+$/.test(type.icon || "") || /^http/.test(type.icon)) { let icon = type.icon.trim().replace(/ /g, '_'); let typeCache = cacheIcon[icon]; if (typeCache) { newCache[icon] = typeCache; } } type.sites.forEach(site => { let icon = site.icon; if (!icon) icon = site.url.replace(/^showTips:/, "").replace(/\?.*/, "").replace(/^(https?:\/\/[^\/]*\/)[\s\S]*$/, "$1favicon.ico"); if (/^http/.test(icon)) { let siteCache = cacheIcon[icon]; if (siteCache) { newCache[icon] = siteCache; } } }); }); if (oldCacheLength !== Object.keys(newCache).length) { cacheIcon = newCache; storage.setItem("cacheIcon", newCache); } } else { searchData.sitesConfig.forEach(type => { if (/^http/.test(type.icon)) { let typeCache = cacheIcon[type.icon]; if (typeCache) { if (typeCache === 'fail') { let img = document.createElement("img"); img.src = type.icon; cachePool.push(img); } else { newCache[type.icon] = typeCache; } } } type.sites.forEach(site => { let icon = site.icon; if (!icon) icon = site.url.replace(/^showTips:/, "").replace(/\?.*/, "").replace(/^(https?:\/\/[^\/]*\/)[\s\S]*$/, "$1favicon.ico"); if (/^http/.test(icon)) { let siteCache = cacheIcon[icon]; if (siteCache) { if (siteCache === 'fail') { let img = document.createElement("img"); img.src = icon; cachePool.push(img); } else { newCache[icon] = siteCache; } } } }); }); storage.setItem("cacheIcon", newCache); if (searchData.prefConfig.cacheSwitch) { if (cachePool.length > 0) { _GM_notification(i18n('startCache')); cacheImgManager(true); } cacheFontManager(); } } preSwitch = searchData.prefConfig.cacheSwitch; if (e.notification || (e.detail && e.detail.notification)) { _GM_notification('Configuration imported successfully!'); } }); document.addEventListener('copyConfig', e => { let copyTarget = searchData.sitesConfig.filter(type => {return type && !(/^BM/.test(type.type) && type.icon === "bookmark")}); _GM_setClipboard(JSON.stringify(copyTarget, null, 2)); _GM_notification('Configuration copied successfully!'); }); } else if (importPageReg.test(href)) { let importCss = _GM_addStyle(` #import-btns-con { position: absolute; display: block; font-size: 20px; left: 0px; top: 0px; width: 100%; height: 100%; } #import-btns-con.hide { pointer-events: none; } #import-btns-con>button { opacity: 0.5; } #import-btns-con>button:hover { opacity: 0.9; } #import-btn { position: absolute; display: block; font-size: 20px; right: 45px; top: 45px; pointer-events: all; } #filter-btn { position: absolute; display: none; font-size: 20px; left: 45px; top: 45px; pointer-events: all; } .filter>#filter-btn { display: block; } #import-btns-con>h3 { float: left; margin-left: 20px; } #import-btns-con.hide>h3 { display: none; } `); let targetPre, ruleType = 0; let importBtn = document.createElement("button"); importBtn.id = "import-btn"; importBtn.className = "btn Button--secondary Button"; let filterBtn = document.createElement("button"); filterBtn.id = "filter-btn"; filterBtn.className = "btn Button--secondary Button"; let ruleTitle = document.createElement("h3"); let btnsCon = document.createElement("div"); btnsCon.id = "import-btns-con"; btnsCon.appendChild(importCss); btnsCon.appendChild(importBtn); btnsCon.appendChild(filterBtn); btnsCon.appendChild(ruleTitle); btnsCon.addEventListener("click", e => { if (targetPre) targetPre.style.filter = ""; btnsCon.classList.add("hide"); }); importBtn.innerText = i18n("import"); importBtn.addEventListener("click", e => { if (shareEngines) return; if (!targetPre) return; let configTxt = targetPre.innerText.trim(), configData; if (!configTxt) return; try { configData = JSON.parse(configTxt); } catch (e) { _GM_notification(e.toString()); return; } switch (ruleType) { case 0: if (window.confirm(i18n("importOrNot"))) { if (btnsCon.parentNode) { btnsCon.parentNode.removeChild(btnsCon); } dataChanged(() => { searchData.sitesConfig = configData; searchData.lastModified = new Date().getTime(); storage.setItem("searchData", searchData); _GM_notification(i18n("siteAddOver")); searchBar.refreshEngines(); }, true); } break; case 1: showSiteAdd(configData.name, "", configData.url, (configData.icon ? [configData.icon] : []), configData.charset, configData.kwFilter, configData.match, configData.hideNotMatch); break; case 2: if (!searchData.prefConfig.inPageRule) searchData.prefConfig.inPageRule = {}; Object.keys(configData).forEach(key => { let value = configData[key]; if (!value) return; if (key.indexOf("@") === 0) { searchData.prefConfig.inPageRule[key] = value; return; } if (!value.words || value.words.length === 0) return; let pre = "", sep = value.sep || ""; if (sep) { pre = "$c" + sep; } else { sep = " "; if (value.words.length === 1) { let onlyWord = value.words[0]; if (onlyWord.indexOf(" ") !== -1) { sep = ""; pre = "$o"; } } } searchData.prefConfig.inPageRule[key] = pre + value.words.join(sep); }); storage.setItem("searchData", searchData); _GM_notification('Over!'); break; } }); filterBtn.innerText = i18n("filter"); filterBtn.addEventListener("click", e => { if (targetPre) { if (btnsCon.parentNode) { btnsCon.parentNode.removeChild(btnsCon); } let configTxt = targetPre.innerText.trim(), configData; if (!configTxt || configTxt.indexOf('[') !== 0) return; try { configData = JSON.parse(configTxt); importFilter.open(configData); } catch (e) { _GM_notification(e.toString()); } } }); let bindPre = target => { if (target == targetPre && btnsCon.parentNode) return; let top = target.offsetTop + 'px'; let innerText = target.innerText.trim(); if (!innerText) return; ruleTitle.innerText = ""; if (/^\[/.test(innerText)) { ruleType = 0; btnsCon.style.top = top; btnsCon.classList.add("filter"); } else if (/^\{\s*"name"/.test(innerText)) { ruleType = 1; btnsCon.style.top = top; btnsCon.classList.remove("filter"); ruleTitle.innerText = innerText.match(/"name":\s*"(.*)"/)[1]; } else if (/^\{/.test(innerText)) { ruleType = 2; btnsCon.style.top = top; btnsCon.classList.remove("filter"); } else return; if (targetPre) targetPre.style.filter = ""; target.parentNode.appendChild(btnsCon); target.style.filter = "blur(5px)"; targetPre = target; btnsCon.classList.remove("hide"); }; window.addEventListener("load", e => { if (!targetPre) { let _targetPre = document.querySelector('.highlight>pre'); if (_targetPre) { bindPre(_targetPre); } } }); document.addEventListener("mouseover", e => { if (importPageReg.test(href)) { if (e.target.nodeName === "PRE") { bindPre(e.target); } else { let target = e.target.children[0]; if (target && target.nodeName === "PRE") { bindPre(target); } } } }); } } class ImportFilter { //static importFilter; constructor() { this.inited = false; } /*static getInstance() { if (!ImportFilter.importFilter) { ImportFilter.importFilter = new ImportFilter(); } return ImportFilter.importFilter; }*/ init() { if (this.inited) return; this.inited = true; let self = this; this.openList = []; this.filterCss = ` #searchJumperFilter { width: 100%; height: 100%; position: fixed; top: 0; left: 0; display: flex; justify-content: center; align-items: center; z-index: 100000; background-color: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(5px); transform: translateZ(0); } .searchJumperFrame-body { width: 350px; text-align: left; background-color: #ffffff; border: 1px solid #afb3b6; border-radius: 10px; opacity: 0.95; filter: alpha(opacity=95); box-shadow: 5px 5px 20px 0px #000; color: #6e7070; transition: all 0.25s ease; border: 0; font-size: initial; } .searchJumperFrame-title { background: #458bd1!important; display: flex!important; align-items: center!important; justify-content: center!important; color: white!important; font-weight: bold; font-size: 18px!important; border-radius: 10px 10px 0 0!important; } .searchJumperFrame-title>img { margin: 5px; height: 32px; width: 32px; } .searchJumperFrame-buttons { text-align: center; margin: 5px; display: flex; justify-content: space-evenly; } .searchJumperFrame-buttons>button { width: 32%; font-size: 16px; cursor: pointer; border: 1px solid #1976d2; border-radius: 4px; transition: all .3s; color: #fff; background-color: #458bd1; line-height: 25px; padding: 3px; } .searchJumperFrame-buttons>button:hover { color: #e3f2fd; } .searchJumperFrame-body>.sitesCon { max-height: 70vh; overflow: auto; width: 100%; border-top: 1px solid rgba(0, 0, 0, 0.23); border-bottom: 1px solid rgba(0, 0, 0, 0.23); padding: 5px; user-select: none; white-space: nowrap; } .searchJumperFrame-body>.sitesCon>details>summary>span, .searchJumperFrame-body>.sitesCon>details>div>span { line-height: 25px; overflow: hidden; text-overflow: ellipsis; max-width: 180px; display: inline-block; vertical-align: middle; } .searchJumperFrame-body>.sitesCon>details>summary>button { display: none; position: absolute; } .searchJumperFrame-body>.sitesCon>details>summary:hover>button { display: inline-block; } .searchJumperFrame-body>.sitesCon input { margin: 2px 5px; width: 20px; height: 20px; vertical-align: sub; } .searchJumperFrame-body>.sitesCon div { margin-left: 32px; } .searchJumperFrame-body>.sitesCon div.exist { text-decoration:line-through; } @media (prefers-color-scheme: dark) { .searchJumperFrame-body, .searchJumperFrame-input-title, .searchJumperFrame-inputs>input, .searchJumperFrame-inputs>textarea, .searchJumperFrame-inputs>select, .searchJumperFrame-body select { background-color: black; color: #d5d5d5; } .searchJumperFrame-title, .searchJumperFrame-buttons>button { background: #245d8f!important; } } `; this.filterCssEle = _GM_addStyle(this.filterCss); this.filterFrame = document.createElement("div"); this.filterFrame.id = "searchJumperFilter"; this.filterFrame.innerHTML = createHTML(` <div class="searchJumperFrame-body"> <a href="${configPage}" class="searchJumperFrame-title" target="_blank"> <img onerror="this.style.display='none'" width="32px" height="32px" src="${logoBase64}" />${i18n("addSearchEngine")} </a> <div class="searchJumperFrame-buttons"> <button id="expandAll" type="button">${i18n("expandAll")}</button> <button id="collapseAll" type="button">${i18n("collapseAll")}</button> </div> <div class="sitesCon"></div> <div class="searchJumperFrame-buttons"> <button id="cancel" type="button">${i18n("siteCancel")}</button> <button id="selectAll" type="button">${i18n("selectAll")}</button> <button id="add" type="button">${i18n("import")}</button> </div> </div> `); this.sitesCon = this.filterFrame.querySelector(".sitesCon"); let add = this.filterFrame.querySelector("#add"); let selectAll = this.filterFrame.querySelector("#selectAll"); let expandAll = this.filterFrame.querySelector("#expandAll"); let collapseAll = this.filterFrame.querySelector("#collapseAll"); let checkMark = false; expandAll.addEventListener("click", e => { [].forEach.call(this.filterFrame.querySelectorAll("details"), details => { details.setAttribute("open", "open"); }); }); collapseAll.addEventListener("click", e => { [].forEach.call(this.filterFrame.querySelectorAll("details"), details => { details.removeAttribute("open"); }); }); selectAll.addEventListener("click", e => { checkMark = !checkMark; [].forEach.call(this.filterFrame.querySelectorAll("input[type=checkbox]"), checkbox => { checkbox.checked = checkMark; }); }); add.addEventListener("click", e => { if (shareEngines) return; dataChanged(() => { let canImport = false; [].forEach.call(this.filterFrame.querySelectorAll("details"), details => { let typeName = details.children[0].children[0]; let typeData = self.typeDict[typeName.title]; typeData.type = typeName.innerText.trim(); typeData.sites = []; [].forEach.call(details.querySelectorAll('div>[type="checkbox"]'), checkSite => { if (checkSite.checked) { canImport = true; let curData = self.siteDict[checkSite.parentNode.title]; let otherType = checkSite.nextElementSibling; if (!curData || !otherType) return; if (otherType.value === "0") { typeData.sites.push(curData); } else { let typeIndex = self.searchType(otherType.value); searchData.sitesConfig[typeIndex].sites.push(curData); } } }); if (typeData.sites.length) { let typeIndex = self.searchType(typeData.type); if (typeIndex === false) { searchData.sitesConfig.push(typeData); } else { searchData.sitesConfig[typeIndex].sites = searchData.sitesConfig[typeIndex].sites.concat(typeData.sites); } } }); if (canImport) { searchData.lastModified = new Date().getTime(); storage.setItem("searchData", searchData); _GM_notification(i18n("siteAddOver")); searchBar.refreshEngines(); this.close(); } }); }); this.filterFrame.addEventListener("click", e => { if (e.target.id == "searchJumperFilter" || e.target.id == "cancel") { this.close(); } }); } searchType(type) { for (let i = 0; i < searchData.sitesConfig.length; i++) { let typeData = searchData.sitesConfig[i]; if (typeData.type == type) return i; } return false; } searchUrl(url) { for (let i = 0; i < searchData.sitesConfig.length; i++) { let sites = searchData.sitesConfig[i].sites; for (let j = 0; j < sites.length; j++) { if (sites[j].url.replace(/^https?/, "") == url.replace(/^https?/, "")) return true; } } return false; } searchName(name) { for (let i = 0; i < searchData.sitesConfig.length; i++) { let sites = searchData.sitesConfig[i].sites; for (let j = 0; j < sites.length; j++) { if (sites[j].name == name) { let newName = name + "_1"; return this.searchName(newName); } } } return name; } anylizeType(typeData) { let self = this; let details = document.createElement("details"); let summary = document.createElement("summary"); let typeName = document.createElement("span"); typeName.title = typeData.type; typeName.innerText = typeData.type; summary.appendChild(typeName); let checkType = document.createElement("input"); checkType.type = 'checkbox'; summary.appendChild(checkType); let renameBtn = document.createElement("button"); renameBtn.innerText = i18n("rename"); renameBtn.addEventListener("click", e => { let newName = window.prompt(i18n('rename'), typeName.innerText); if (newName) typeName.innerText = newName; }); summary.appendChild(renameBtn); details.appendChild(summary); for (let i = 0; i < this.openList.length; i++) { if (this.openList[i] == typeData.type) { details.setAttribute("open", "open"); break; } } let sites = []; this.typeDict[typeData.type] = typeData; if (typeData.sites) { typeData.sites.forEach(siteData => { let siteCon = document.createElement("div"); let siteName = document.createElement("span"); siteName.innerText = siteData.name; siteData.name = self.searchName(siteData.name); siteCon.appendChild(siteName); siteCon.title = siteData.url; details.appendChild(siteCon); if (self.searchUrl(siteData.url)) { siteCon.classList.add("exist"); return; } let checkSite = document.createElement("input"); checkSite.type = 'checkbox'; checkSite.onclick = e => { if (!checkSite.checked) { checkType.checked = false; } else { let allchecked = true; for (let i = 0; i < sites.length; i++) { if (!sites[i].checked) { allchecked = false; break; } } if (allchecked) checkType.checked = true; } }; siteCon.appendChild(checkSite); siteCon.addEventListener("click", e => { if (e.target.nodeName.toUpperCase() == 'SPAN') { checkSite.click(); } }); let typeSelect = document.createElement("select"); let option = document.createElement("option"); option.value = 0; option.innerText = i18n("currentType"); typeSelect.appendChild(option); for (let i = 0; i < searchData.sitesConfig.length; i++) { let _type = searchData.sitesConfig[i]; if (_type.type != typeData.type) { let option = document.createElement("option"); option.value = _type.type; option.innerText = _type.type; typeSelect.appendChild(option); } } siteCon.appendChild(typeSelect); self.siteDict[siteData.url] = siteData; sites.push(checkSite); }); } if (sites.length == 0) { checkType.style.display = "none"; renameBtn.style.display = "none"; } checkType.addEventListener("click", e => { sites.forEach(checkSite => { checkSite.checked = checkType.checked; }); }); this.sitesCon.appendChild(details); } close() { this.openList = []; [].forEach.call(this.sitesCon.querySelectorAll("details"), details => { if (details.hasAttribute("open")) { this.openList.push(details.querySelector("summary").innerText); } }); if (this.filterFrame.parentNode) { this.filterFrame.parentNode.removeChild(this.filterFrame); } } open(configData) { this.init(); let self = this; this.siteDict = {}; this.typeDict = {}; if (!this.filterCssEle || !this.filterCssEle.parentNode) this.filterCssEle = _GM_addStyle(this.filterCss); document.documentElement.appendChild(this.filterFrame); this.sitesCon.innerHTML = createHTML(''); configData.forEach(type => { self.anylizeType(type); }); //storage.setItem("searchData", searchData); //_GM_notification('Over!'); } } const importFilter = new ImportFilter(); var dragRoundFrame, dragCon, dragSiteCurSpans, dragSiteHistorySpans, dragEndHandler, dragenterHandler, openAllTimer, dragScaleWidth, dragScaleHeight, zoomDrag; function showDragSearch(left, top) { if (!searchBar || !searchBar.bar) return; let preOpenType = searchBar.bar.querySelector('.search-jumper-type.search-jumper-open'); let removeFrame = () => { document.removeEventListener('dragend', dragEndHandler, true); document.removeEventListener('dragenter', dragenterHandler, true); if (dragCon.parentNode) { dragCon.parentNode.removeChild(dragCon); dragRoundFrame.style.opacity = ""; dragRoundFrame.style.transform = ''; } draging = false; clearTimeout(openAllTimer); if ((currentSite && !currentSite.hideNotMatch && !searchData.prefConfig.hideOnSearchEngine) || searchBar.con.classList.contains("resizePage")) { if (preOpenType && !preOpenType.classList.contains('search-jumper-open')) { if (preOpenType.children[0].onmousedown) preOpenType.children[0].onmousedown(); else { let mouseEvent = new PointerEvent("mousedown"); preOpenType.children[0].dispatchEvent(mouseEvent); } } } else { searchBar.bar.style.display = 'none'; } }; if (!dragScaleWidth && !dragScaleHeight) { zoomDrag = (searchData.prefConfig.zoomDrag || 100) / 100; dragScaleWidth = zoomDrag * 190; dragScaleHeight = zoomDrag * 190; } if (!dragRoundFrame) { let dragCssText = ` #dragCon { position: fixed; top: 0; left: 0; transform: scale(${zoomDrag}); z-index: 2147483647; -moz-transition:left 0.3s ease, top 0.3s; -webkit-transition:left 0.3s ease, top 0.3s; transition:left 0.3s ease, top 0.3s; } #searchJumperWrapper * { margin: 0; padding: 0; border: none; outline: none; user-select: none; box-sizing: content-box; font-size: 12px; line-height: normal; overflow: visible; background-image: initial; float: initial; } #searchJumperWrapper { position: fixed; height: 300px; width: 300px; padding: 20px; margin: 20px; background-color: #000000${searchData.prefConfig.hideDragHistory ? "10" : "9e"}; box-shadow: #000000 0px 0px 10px; border-radius: 50%; z-index: 2147483647; box-sizing: content-box; opacity: 0; transform: scale(.5); -moz-transition:opacity 0.3s ease, transform 0.15s; -webkit-transition:opacity 0.3s ease, transform 0.15s; transition:opacity 0.3s ease, transform 0.15s; } #searchJumperWrapper>.panel { position: relative; } #searchJumperWrapper .sector:nth-child(2n+1) .sector-inner { background: #454545; color: white; } #searchJumperWrapper .sector:nth-child(2n) .sector-inner { background: #ffffff; color: black; } #searchJumperWrapper .sector.out:nth-child(2n+1) .sector-inner { background: #353535; } #searchJumperWrapper .sector.out:nth-child(2n) .sector-inner { background: #eeeeee; } #searchJumperWrapper .sector { position: absolute; left: 150px; top: 50px; width: 100px; height: 200px; font-size: 14px; border-radius: 0px 100px 100px 0; overflow: hidden; transform-origin: left center; z-index: 1; -moz-transition:transform 0.3s ease; -webkit-transition:transform 0.3s ease; transition:transform 0.3s ease; pointer-events: none; } #searchJumperWrapper .sector.out { left: 150px; top: 0px; width: 150px; height: 300px; font-size: 14px; border-radius: 0px 150px 150px 0; overflow: hidden; transform-origin: left center; z-index: 0; ${searchData.prefConfig.hideDragHistory ? "display: none;" : ""} } #searchJumperWrapper .sector-inner { text-align: center; display: block; width: 40px; padding: 5px 3px 0 57px; height: 195px; transform: translateX(-100px) rotate(60deg); transform-origin: right center; border-radius: 100px 0 0 100px; } #searchJumperWrapper .sector.out>.sector-inner { text-align: center; display: block; width: 90px; height: 295px; transform: translateX(-150px) rotate(36deg); transform-origin: right center; border-radius: 150px 0 0 150px; } #searchJumperWrapper .sector-inner span { transform-origin: center; padding: 20px 0; pointer-events: all; opacity: 0.8; word-break: break-word; height: 55px; font-size: 12px; font-weight: bold; font-family: Arial, sans-serif; display: flex; flex-direction: column; align-items: center; justify-content: space-evenly; } #searchJumperWrapper .sector-inner span { width: 70px; margin-left: -15px; } #searchJumperWrapper .sector-inner span>p { max-width: 58px; } #searchJumperWrapper .sector.out>.sector-inner span { width: unset; margin-left: unset; } #searchJumperWrapper .over>.sector-inner span { opacity: 1; } #searchJumperWrapper .sector-inner span>img { width: 25px; height: 25px; } #searchJumperWrapper .sector-inner span:hover { opacity: 1; } #searchJumperWrapper .dragLogo { position: absolute; left: 150px; top: 150px; border-radius: 50%; box-shadow: #000000 0px 0px 10px; z-index: 10; font-size: 0; -moz-transition:transform 0.3s ease; -webkit-transition:transform 0.3s ease; transition:transform 0.3s ease; } .dragLogo>svg { width: 40px; height: 40px; pointer-events: none; } `; let dragCssEle = _GM_addStyle(dragCssText); dragSiteCurSpans = []; dragSiteHistorySpans = []; dragRoundFrame = document.createElement("div"); dragRoundFrame.id = "searchJumperWrapper"; dragRoundFrame.innerHTML = createHTML(` <div class="panel"></div> <div class="dragLogo">${logoBtnSvg}</div> `); if (!disabled) dragRoundFrame.appendChild(dragCssEle); const sector1Num = 6; const sector2Num = 10; let sectorCon = dragRoundFrame.querySelector(".panel"); let sector1Gap = 360 / sector1Num; let sector2Gap = 360 / sector2Num; let sector1Start = -sector1Gap / 2; let sector2Start = -sector2Gap / 2; let dragSector; let dragLogo = dragRoundFrame.querySelector(".dragLogo"); let removeTimer; dragLogo.addEventListener("dragover", e => { e.preventDefault(); }, true); dragLogo.addEventListener("dragenter", e => { clearTimeout(removeTimer); if (dragSector) { dragSector.style.transform = `rotate(${dragSector.dataset.deg}deg) ${searchData.prefConfig.hideDragHistory ? 'scale(1.2)' : ''}`; dragSector.classList.remove("over"); } dragSector = null; dragLogo.style.transform = `scale(1.35)`; e.preventDefault(); clearTimeout(openAllTimer); openAllTimer = setTimeout(() => { removeFrame(); searchBar.appendBar(); searchBar.showAllSites(); }, 1000); }, true); let geneSector = (className, deg, spanTransform) => { let sector = document.createElement("div"); sector.className = className; let sectorInner = document.createElement("div"); sectorInner.className = "sector-inner"; let sectorSpan = document.createElement("span"); sectorInner.appendChild(sectorSpan); sector.appendChild(sectorInner); let transform = `rotate(${deg}deg)`; sectorSpan.style.transform = spanTransform; sector.style.transform = transform + (searchData.prefConfig.hideDragHistory ? 'scale(1.2)' : ''); sector.dataset.deg = deg; sectorCon.appendChild(sector); sectorSpan.addEventListener("dragover", e => { if (e.clientX < 50) { dragCon.style.left = "0px"; } else if (e.clientX > document.documentElement.clientWidth - 50) { dragCon.style.left = document.documentElement.clientWidth - (dragScaleWidth<<1) + "px"; } if (e.clientY < 50) { dragCon.style.top = "0px"; } else if (e.clientY > document.documentElement.clientHeight - 50) { dragCon.style.top = document.documentElement.clientHeight - (dragScaleHeight<<1) + "px"; } e.preventDefault(); }, true); sectorSpan.addEventListener("dragenter", e => { clearTimeout(removeTimer); if (!sectorSpan.innerText) return; if (dragSector) { dragSector.style.transform = `rotate(${dragSector.dataset.deg}deg) ${searchData.prefConfig.hideDragHistory ? 'scale(1.2)' : ''}`; dragSector.classList.remove("over"); } dragLogo.style.transform = ""; sector.style.transform = `scale(${searchData.prefConfig.hideDragHistory ? '1.6' : '1.25'}) ${transform}`; sector.classList.add("over"); dragSector = sector; clearTimeout(openAllTimer); }, true); return sectorSpan; }; for (let i = 0; i < sector1Num; i++) { let sectorSpan = geneSector("sector", sector1Start + sector1Gap * i, `translateX(-10px) translateY(-10px) rotate(${sector1Start - sector1Gap * i}deg)`); dragSiteCurSpans.push(sectorSpan); } for (let i = 0; i < sector2Num; i++) { let sectorSpan = geneSector("sector out", sector2Start + sector2Gap * i, `translateX(12px) translateY(-15px) rotate(${sector2Start - sector2Gap * i}deg)`); dragSiteHistorySpans.push(sectorSpan); } dragEndHandler = e => { removeFrame(); } dragRoundFrame.addEventListener('click', e => { removeFrame(); }); dragRoundFrame.addEventListener('drop', e => { if (e.target === dragLogo) { searchBar.setFuncKeyCall(false); searchBar.showInPage(); } else if (dragSector) { removeFrame(); searchBar.searchBySiteName(dragSector.children[0].dataset.name, e); dragSector.style.transform = `rotate(${dragSector.dataset.deg}deg)`; dragSector.classList.remove("over"); dragSector = null; } e.preventDefault(); }); let minClientX, maxClientX, minClientY, maxClientY; dragenterHandler = e => { clearTimeout(removeTimer); if (!dragRoundFrame.contains(e.target)) { removeTimer = setTimeout(() => { removeFrame(); }, 300); } }; dragCon = document.createElement("div"); dragCon.id = "dragCon"; dragCon.appendChild(dragRoundFrame); } searchBar.recoveHistory(); let firstType = searchBar.autoGetFirstType(); let siteBtns = firstType.querySelectorAll("a.search-jumper-btn:not(.notmatch)"); let targetIndex = 0; let getTargetSiteBtn = () => { let result = null; for (let i = targetIndex; i < siteBtns.length; i++) { let btn = siteBtns[i]; if (btn.style.display !== 'none') { result = btn; targetIndex = i + 1; break; } } return result; }; const filldragSpan = (span, targetSite) => { span.parentNode.dataset.name = targetSite.dataset.name; let word = document.createElement("p"); word.innerText = targetSite.dataset.name.substr(0, 10).trim(); if (!/^\w+$/.test(word.innerText)) { let text = "", len = 0; for (let char of word.innerText) { text += char; if (/^\w+$/.test(char)) { len++; } else len += 2; if (len > 10) { text += "..."; break; } } word.innerText = text; } let img = document.createElement("img"); img.style.display = "none"; span.appendChild(img); span.appendChild(word); img.onload = e => { img.style.display = ""; }; let targetIcon = targetSite.querySelector("img"); if (targetIcon) { let src = targetIcon.src || targetIcon.dataset.src; if (src) img.src = src; } }; dragSiteCurSpans.forEach((span, i) => { span.innerHTML = createHTML(); let targetSite = getTargetSiteBtn(); if (!targetSite) { span.parentNode.parentNode.style.filter = 'contrast(0.5)'; return; } span.parentNode.parentNode.style.filter = ''; filldragSpan(span, targetSite); }); let findIndex = 0; let historySiteBtns; if (firstType.classList.contains("search-jumper-needInPage")) { historySiteBtns = searchBar.txtHistorySiteBtns; } else if (firstType.classList.contains("search-jumper-targetImg")) { historySiteBtns = searchBar.imgHistorySiteBtns; } else if (firstType.classList.contains("search-jumper-targetAudio")) { historySiteBtns = searchBar.audioHistorySiteBtns; } else if (firstType.classList.contains("search-jumper-targetVideo")) { historySiteBtns = searchBar.videoHistorySiteBtns; } else if (firstType.classList.contains("search-jumper-targetLink") || firstType.classList.contains("search-jumper-targetPage")) { historySiteBtns = searchBar.linkHistorySiteBtns; } if (historySiteBtns) { historySiteBtns = historySiteBtns.concat(searchBar.historySiteBtns); historySiteBtns = historySiteBtns.filter((value, index, self) => self.indexOf(value) === index); } else { historySiteBtns = searchBar.historySiteBtns; } let getHistorySiteBtn = () => { if (searchData.prefConfig.reuseDragHistory) { return getTargetSiteBtn(); } else if (searchData.prefConfig.hideDragHistory) { return false; } let result = null; for (let i = findIndex; i < historySiteBtns.length; i++) { let btn = historySiteBtns[i]; if (btn.style.display !== 'none') { result = btn; findIndex = i + 1; break; } } return result; }; dragSiteHistorySpans.forEach((span, i) => { let dragleaveEvent = new DragEvent("dragleave"); span.dispatchEvent(dragleaveEvent); span.innerHTML = createHTML(); span.parentNode.parentNode.style.opacity = 0.6; let targetSite = getHistorySiteBtn(); if (!targetSite) return; let siteImg = targetSite.querySelector('img'); if (siteImg && siteImg.dataset.src) { siteImg.src = siteImg.dataset.src; delete siteImg.dataset.src; } span.parentNode.parentNode.style.opacity = 1; filldragSpan(span, targetSite); }); dragCon.style.left = left - dragScaleWidth + "px"; dragCon.style.top = top - dragScaleHeight + "px"; dragRoundFrame.style.opacity = ""; dragRoundFrame.style.transform = ''; setTimeout(() => { document.addEventListener('dragend', dragEndHandler, true); searchBar.addToShadow(dragCon); setTimeout(() => { dragRoundFrame.style.opacity = 1; dragRoundFrame.style.transform = 'scale(1)'; }, 10); setTimeout(() => { if (getComputedStyle(dragRoundFrame).zIndex != "2147483647") { removeFrame(); } else { document.addEventListener('dragenter', dragenterHandler, true); } }, 100); }, 0); } var addFrame, nameInput, descInput, urlInput, iconInput, iconShow, iconsCon, typeSelect, testBtn, cancelBtn, addBtn, siteKeywords, siteMatch, openSelect, crawlBtn; function showSiteAdd(name, description, url, icons, charset, kwFilter, match, hideNotMatch) { self.kwFilter = kwFilter; self.charset = charset; self.hideNotMatch = hideNotMatch; self.match = match; if (!addFrame) { let addFrameCssText = ` .searchJumperFrame-body, .searchJumperFrame-crawlBody { width: 300px; min-height: 300px; position: fixed; text-align: left; left: 50%; top: 45%; margin-top: -250px; margin-left: -150px; z-index: 100000; background-color: #ffffff; border: 1px solid #afb3b6; border-radius: 10px; opacity: 0.95; filter: alpha(opacity=95); box-shadow: 5px 5px 20px 0px #000; color: #6e7070; transition: all 0.25s ease; border: 0; font-size: initial; } .searchJumperFrame-title { background: #458bd1!important; display: flex!important; align-items: center!important; justify-content: center!important; color: white!important; font-weight: bold; font-size: 18px!important; border-radius: 10px 10px 0 0!important; } .draging .searchJumperFrame-body, .draging .searchJumperFrame-crawlBody { transition: none; pointer-events: none; } .searchJumperFrame-title>img { margin: 5px; height: 32px; width: 32px; } .searchJumperFrame-input-title { font-size: 9pt; font-family: Arial, sans-serif; display: inline-block; background-color: white; position: relative; left: 20px; padding: 0px 4px; text-align: left; color: #646464; } .searchJumperFrame-inputs>input, .searchJumperFrame-inputs>textarea, .searchJumperFrame-inputs>select, .searchJumperFrame-body select { resize: both; font-size: 11pt; font-weight: normal; border-radius: 4px; border: 1px solid rgba(0, 0, 0, 0.23); margin: 4px; font-family: inherit; background-color: #FFF; width: calc(100% - 8px); min-width: calc(100% - 8px); max-width: calc(100% - 8px); color: #4A4A4A; margin-top: -8px; padding: 4px; padding-top: 8px; box-sizing: border-box; height: 36px; word-break: break-all; } .searchJumperFrame-inputs>input:focus, .searchJumperFrame-inputs>textarea:focus, .searchJumperFrame-inputs>select:focus, .searchJumperFrame-body select:focus { background-color: #FFF; } .searchJumperFrame-buttons { text-align: center; margin-bottom: 5px; display: flex; justify-content: space-evenly; } .searchJumperFrame-buttons>button { width: 32%; font-size: 16px; cursor: pointer; border: 1px solid #1976d2; border-radius: 4px; transition: all .3s; color: #fff; background-color: #458bd1; line-height: 25px; padding: 3px; } .searchJumperFrame-buttons>button:hover { color: #e3f2fd; } .searchJumperFrame-inputs>.sideIcon { float: right; margin-top: -38px; position: relative; right: 20px; opacity: 0.8; background: rgb(0 0 0 / 50%); border-radius: 5px; pointer-events: none; width: 27px; height: 27px; } .searchJumperFrame-inputs>svg.sideIcon { fill: white; pointer-events: all; cursor: pointer; transition: transform 0.25s ease; } .searchJumperFrame-inputs>svg.sideIcon:hover { transform: scale(1.2); opacity: 1; background: rgb(0 0 0); } .searchJumperFrame-body>.iconsCon { max-height: 150px; overflow: auto; width: 100%; border-top: 1px solid rgba(0, 0, 0, 0.23); border-bottom: 1px solid rgba(0, 0, 0, 0.23); } .searchJumperFrame-body>.iconsCon>img { margin: 5px; cursor: pointer; max-width: 120px; border: 2px solid #ffffff; box-sizing: border-box; background: #80808030; transition: background 0.25s ease; } .searchJumperFrame-body>.iconsCon>img:hover { border: 2px solid #4e91d3; background: gray; } .maxContent .searchJumperFrame-inputs { width: 50%; float: left; } .searchJumperFrame-body>.moreItem { display: none; } .maxContent>.searchJumperFrame-body>.moreItem { display: block; } .maxContent>.searchJumperFrame-body { width: 600px; margin-left: -300px; } .searchJumperFrame-maxBtn, .searchJumperFrame-closeBtn { position: absolute; right: 5px; top: 5px; color: white; width: 25px; cursor: pointer; transition:transform 0.25s ease; } .searchJumperFrame-maxBtn:hover, .searchJumperFrame-closeBtn:hover { transform: scale(1.2); } .searchJumperFrame-maxBtn>#maxBtn { display: block; } .searchJumperFrame-maxBtn>#minBtn { display: none; } .maxContent .searchJumperFrame-maxBtn>#maxBtn { display: none; } .maxContent .searchJumperFrame-maxBtn>#minBtn { display: block; } .crawling>.searchJumperFrame-body { display: none; } .searchJumperFrame-crawlBody { display: none; } .crawling>.searchJumperFrame-crawlBody { display: block; } .searchJumperFrame-buttons>button#submitCrawl, .searchJumperFrame-buttons>button#record, .searchJumperFrame-buttons>button#copy, .searchJumperFrame-buttons>button#loop { width: 100%; margin: 0 3px; } .searchJumperFrame-crawlBody>.actionCon { height: 200px; background: gray; border-radius: 10px; margin: 10px; padding: 0 10px 10px 10px; resize: auto; box-sizing: border-box; overflow: auto; } .searchJumperFrame-crawlBody>.actionCon>div { width: 100%; font-size: 16px; background: #000000cc; border-radius: 8px; color: white; margin: 3px 0; display: flex; justify-content: center; align-items: center; cursor: pointer; white-space: nowrap; } .searchJumperFrame-crawlBody>.actionCon>div>span { background: #275f90; border-radius: 5px; max-width: 40px; text-overflow: ellipsis; overflow: hidden; display: inline-block; margin: 0 3px; white-space: nowrap; } @media (prefers-color-scheme: dark) { .searchJumperFrame-body, .searchJumperFrame-crawlBody, .searchJumperFrame-input-title, .searchJumperFrame-inputs>input, .searchJumperFrame-inputs>textarea, .searchJumperFrame-inputs>select, .searchJumperFrame-body select { background-color: black!important; color: #d5d5d5!important; } .searchJumperFrame-inputs>input:focus, .searchJumperFrame-inputs>textarea:focus, .searchJumperFrame-inputs>select:focus, .searchJumperFrame-body select:focus { background-color: #1e1e1e!important; } .searchJumperFrame-inputs>input, .searchJumperFrame-inputs>textarea, .searchJumperFrame-inputs>select, .searchJumperFrame-body select { border: 1px solid rgb(255 255 255 / 36%); } .searchJumperFrame-title, .searchJumperFrame-buttons>button { background: #245d8f!important; } .searchJumperFrame-body>.iconsCon>img { border: 2px solid #000000; } } @media screen and (max-height: 600px) { .searchJumperFrame-body, .searchJumperFrame-crawlBody { top: 10px; margin-top: 0px; } } `; let addFrameCssEle = _GM_addStyle(addFrameCssText); addFrame = document.createElement("div"); addFrame.innerHTML = createHTML(` <div class="searchJumperFrame-body"> <a href="${configPage}" class="searchJumperFrame-title" target="_blank" draggable="false"> <img width="32px" height="32px" src="${logoBase64}" />${i18n("addSearchEngine")} </a> <div class="searchJumperFrame-maxBtn"> <svg id="maxBtn" fill="white" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>${i18n("maxAddSiteBtn")}</title><path d="M192 832h160a32 32 0 0 1 0 64H160a32 32 0 0 1-32-32V672a32 32 0 0 1 64 0zM182.72 886.72a32 32 0 0 1-45.44-45.44l224-224a32 32 0 0 1 45.44 45.44zM832 832V672a32 32 0 0 1 64 0v192a32 32 0 0 1-32 32H672a32 32 0 0 1 0-64zM886.72 841.28a32 32 0 0 1-45.44 45.44l-224-224a32 32 0 0 1 45.44-45.44zM192 192v160a32 32 0 0 1-64 0V160a32 32 0 0 1 32-32h192a32 32 0 0 1 0 64zM137.28 182.72a32 32 0 0 1 45.44-45.44l224 224a32 32 0 0 1-45.44 45.44zM832 192H672a32 32 0 0 1 0-64h192a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0zM841.28 137.28a32 32 0 1 1 45.44 45.44l-224 224a32 32 0 0 1-45.44-45.44z"></path></svg> <svg id="minBtn" fill="white" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>${i18n("minAddSiteBtn")}</title><path d="M672 352h160a32 32 0 0 1 0 64H640a32 32 0 0 1-32-32V192a32 32 0 0 1 64 0zM662.72 406.72a32 32 0 0 1-45.44-45.44l224-224a32 32 0 1 1 45.44 45.44zM352 352V192a32 32 0 0 1 64 0v192a32 32 0 0 1-32 32H192a32 32 0 0 1 0-64zM406.72 361.28a32 32 0 0 1-45.44 45.44l-224-224a32 32 0 0 1 45.44-45.44zM672 672v160a32 32 0 0 1-64 0V640a32 32 0 0 1 32-32h192a32 32 0 0 1 0 64zM617.28 662.72a32 32 0 0 1 45.44-45.44l224 224a32 32 0 0 1-45.44 45.44zM192 672a32 32 0 0 1 0-64h192a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0V672zM361.28 617.28a32 32 0 0 1 45.44 45.44l-224 224a32 32 0 0 1-45.44-45.44z"></path></svg> </div> <div class="searchJumperFrame-inputs"> <div class="searchJumperFrame-input-title">${i18n("siteName")}</div> <input name="siteName" type="text" /> <div class="searchJumperFrame-input-title">${i18n("siteUrl")}</div> <textarea name="url" type="text"></textarea> <svg id="crawlBtn" class="sideIcon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>${i18n("crawlInfo")}</title><path d="M385 926.3c-11 0-21.4-4.3-29.2-12l-0.6-0.6c-0.7-0.7-65.6-70.4-108.4-112.7-42.8-42.3-118.6-111.4-119.3-112.1l-0.6-0.5c-15.9-15.7-24.6-36.6-24.5-58.8s9-43.1 25-58.6c28.6-27.7 72.2-31 104.6-8.2l90.5 44-83.1-290.1c-4.9-17.1-4.2-34.9 2.1-51.6 6.3-16.6 17.5-30.5 32.5-40.1 22-14.1 47.7-17.7 70.3-10 22.6 7.7 40.7 26.3 49.5 50.9L431 369.8V176.9c0-43.4 35.3-78.7 78.7-78.7 20.7 0 40.2 7.9 55 22.4 14.8 14.4 23.2 33.8 23.7 54.4v0.2l2.4 165.5L625 229.1l0.1-0.4c8.2-23.2 26.2-41.1 49.4-49.3 23.2-8.2 48.5-5.5 69.4 7.3 15.6 9.6 27.7 24.3 33.9 41.6s6.4 36.3 0.6 53.7L736 409.5l42.9-48.6 0.3-0.3c15.7-16.2 34.4-25.7 54.1-27.3 19.8-1.6 39.1 4.7 56 18.1 33 26.4 40.8 60.1 22.7 97.5l-0.5 1.1-0.6 1c-41.8 65.2-107.1 171.9-115.8 199-12.4 38.6-41 140.7-41.3 141.7l-0.2 0.7-34.5 107.2-0.6 1.2c-6.8 14.3-21.5 23.7-37.4 23.8l-295.9 1.6c0 0.1-0.1 0.1-0.2 0.1z"></path></svg> <div class="searchJumperFrame-input-title">${i18n("siteDesc")}</div> <textarea name="description" type="text"></textarea> <div class="searchJumperFrame-input-title">${i18n("siteIcon")}</div> <textarea name="icon" type="text"></textarea> <img class="sideIcon" width="27px" height="27px" /> </div> <div class="searchJumperFrame-inputs moreItem"> <div class="searchJumperFrame-input-title">${i18n("siteKeywords")}</div> <input name="siteKeywords" placeholder="kw|key" type="text" /> <div class="searchJumperFrame-input-title">${i18n("siteMatch")}</div> <input name="siteMatch" placeholder="(www|m)\\.google\\.com" type="text" /> <div class="searchJumperFrame-input-title">${i18n("openSelect")}</div> <select name="openSelect"> <option value="-1">${i18n("openInDefault")}</option> <option value="true">${i18n("openInNewTab")}</option> <option value="false">${i18n("openInCurrent")}</option> </select> </div> <div class="iconsCon"></div> <div class="searchJumperFrame-input-title">${i18n("siteType")}</div> <select name="typeSelect"> </select> <div class="searchJumperFrame-buttons"> <button id="test" type="button">${i18n("siteTest")}</button> <button id="cancel" type="button">${i18n("siteCancel")}</button> <button id="add" type="button">${i18n("siteAdd")}</button> </div> </div> <div class="searchJumperFrame-crawlBody searchJumperFrame-hide"> <a href="${configPage}" class="searchJumperFrame-title" target="_blank"> <img width="32px" height="32px" src="${logoBase64}" />${i18n("addAction")} </a> <svg class="searchJumperFrame-closeBtn" fill="white" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>Close crawl</title>${closePath}</svg> <div class="actionCon"></div> <div class="searchJumperFrame-buttons"> <button id="input" type="button" title="${i18n("emuInputTips")}">${i18n("inputAction")}</button> <button id="click" type="button" title="${i18n("emuClickTips")}">${i18n("clickAction")}</button> <button id="sleep" type="button" title="${i18n("emuWaitTips")}">${i18n("sleepAction")}</button> </div> <div class="searchJumperFrame-buttons"> <button id="copy" type="button" title="${i18n("emuCopyTips")}">${i18n("copyAction")}</button> </div> <div class="searchJumperFrame-buttons"> <button id="record" type="button" title="${i18n("emuRecordTips")}">${i18n("recordAction")}</button> </div> <div class="searchJumperFrame-buttons"> <button id="loop" type="button" title="${i18n("emuLoopTips")}">${i18n("loopAction")}</button> </div> <div class="searchJumperFrame-buttons"> <button id="submitCrawl" type="button" title="${i18n("emuStopTips")}">${i18n("submitCrawl")}</button> </div> </div> `); if (!disabled) addFrame.appendChild(addFrameCssEle); let addBody = addFrame.children[0]; nameInput = addFrame.querySelector("[name='siteName']"); descInput = addFrame.querySelector("[name='description']"); urlInput = addFrame.querySelector("[name='url']"); iconInput = addFrame.querySelector("[name='icon']"); iconShow = addFrame.querySelector(".searchJumperFrame-inputs>img"); iconsCon = addFrame.querySelector(".iconsCon"); testBtn = addFrame.querySelector("#test"); cancelBtn = addFrame.querySelector("#cancel"); addBtn = addFrame.querySelector("#add"); typeSelect = addFrame.querySelector("select[name='typeSelect']"); siteKeywords = addFrame.querySelector("[name='siteKeywords']"); siteMatch = addFrame.querySelector("[name='siteMatch']"); openSelect = addFrame.querySelector("select[name='openSelect']"); let title = addFrame.querySelector(".searchJumperFrame-title"); let initMousePos, initFramePos, moving = false; let dragTitleMove = e => { if (!moving) { addFrame.classList.add("draging"); moving = true; } let x = e.clientX - initMousePos.x + initFramePos.x; let y = e.clientY - initMousePos.y + initFramePos.y; addBody.style.marginLeft = x + "px"; addBody.style.marginTop = y + "px"; }; let dragTitleUp = e => { e.preventDefault(); e.stopPropagation(); addFrame.classList.remove("draging"); document.removeEventListener("mousemove", dragTitleMove); document.removeEventListener("mouseup", dragTitleUp); }; title.addEventListener("mousedown", e => { e.preventDefault(); e.stopPropagation(); moving = false; initMousePos = {x: e.clientX, y: e.clientY}; let addBodyStyle = getComputedStyle(addBody); initFramePos = {x: parseInt(addBodyStyle.marginLeft || 0), y: parseInt(addBodyStyle.marginTop || 0)}; document.addEventListener("mousemove", dragTitleMove); document.addEventListener("mouseup", dragTitleUp); }); iconShow.onload = e => { iconShow.style.display = ""; } let maxBtn = addFrame.querySelector("#maxBtn"); maxBtn.addEventListener("click", e => { addFrame.classList.add("maxContent"); }); let minBtn = addFrame.querySelector("#minBtn"); minBtn.addEventListener("click", e => { addFrame.classList.remove("maxContent"); }); for (let i = 0; i < searchData.sitesConfig.length; i++) { let typeConfig = searchData.sitesConfig[i]; let option = document.createElement("option"); option.value = i; if (lastAddType !== "" && lastAddType == i) { option.selected = "selected"; } option.innerText = typeConfig.type; typeSelect.appendChild(option); } testBtn.addEventListener("click", e => { if (/#p{/.test(urlInput.value)) { let actionParams = urlInput.value.match(/#p{(.*)}/); if (!actionParams) return; let postParams = []; actionParams[1].replace(/([^\\])&/g, "$1SJ^PARAM").split("SJ^PARAM").forEach(pair => {//ios不支持零宽断言,哭唧唧 pair = pair.trim(); if (/^loopStart\(\d+\)$/.test(pair)) { let loopStart = pair.match(/loopStart\((.*)\)/); postParams.push(['@loopStart', loopStart[1]]); } else if (pair == "loopEnd") { postParams.push(['@loopEnd', '']); } else if (pair.startsWith("click(") && pair.endsWith(')')) { let click = pair.slice(6, pair.length - 1); if (click) { postParams.push(['@click', click.replace(/\\([\=&])/g, "$1").trim()]); } } else if (pair.startsWith("dblclick(") && pair.endsWith(')')) { let click = pair.slice(9, pair.length - 1); if (click) { postParams.push(['@dblclick', click.replace(/\\([\=&])/g, "$1").trim()]); } } else if (pair.startsWith("rclick(") && pair.endsWith(')')) { let click = pair.slice(7, pair.length - 1); if (click) { postParams.push(['@rclick', click.replace(/\\([\=&])/g, "$1").trim()]); } } else if (pair.startsWith("copy(") && pair.endsWith(')')) { let copy = pair.slice(5, pair.length - 1); if (copy) { postParams.push(['@copy', copy.replace(/\\([\=&])/g, "$1").trim()]); } } else if (pair.startsWith("call(") && pair.endsWith(')')) { let func = pair.slice(5, pair.length - 1); if (func) { postParams.push(['@call', func.replace(/\\([\=&])/g, "$1").trim()]); } } else if (pair.startsWith("wait(") && pair.endsWith(')')) { let wait = pair.slice(5, pair.length - 1); postParams.push(['@wait', wait.replace(/\\([\=&])/g, "$1").trim()]); } else if (/^sleep\(\d+\)$/.test(pair)) { let sleep = pair.match(/sleep\((.*)\)/); if (sleep) { postParams.push(['@sleep', sleep[1]]); } } else if (/^reload\(\d?\)$/.test(pair)) { let reload = pair.match(/reload\((.*)\)/); postParams.push(['@reload', reload[1]]); } else { pair = pair.replace(/([^\\])\=/g, "$1SJ^PARAM").replace(/\\([\=&])/g, "$1"); let pairArr = pair.split("SJ^PARAM"); if (pairArr.length === 2) { let k = pairArr[0]; let v = pairArr[1].replace(/\\([\=&])/g, "$1"); postParams.push([k, v]); } else if (pair.endsWith('.click()') || pair.endsWith('.click')) { postParams.push(['@' + pair.replace(/\.click(\(\))?$/, ''), 'click']); } } }); inPagePostParams = postParams; searchBar.submitAction(postParams); } else if (/[:%]p{/.test(urlInput.value) || (charset && charset.toLowerCase() != 'utf-8')) { submitByForm(charset, urlInput.value.replace(/%se?\b/g, "searchJumper"), "_blank"); } else { _GM_openInTab(urlInput.value.replace(/%se?\b/g, "searchJumper"), {active: true, insert: true}); } }); cancelBtn.addEventListener("click", e => { if (addFrame.parentNode) { addFrame.parentNode.removeChild(addFrame); } }); addBtn.addEventListener("click", e => { if (shareEngines) return; dataChanged(() => { let siteObj = null; for (let i = 0; i < searchData.sitesConfig.length; i++) { let typeConfig = searchData.sitesConfig[i]; for (let j = 0; j < typeConfig.sites.length; j++) { let curSite = typeConfig.sites[j]; if (curSite.url == urlInput.value) { if (i == parseInt(typeSelect.value)) { alert('Already added!'); return; } if (window.confirm(i18n("siteExist"))) { siteObj = { name: curSite.name + " - " + typeConfig.type, url: `["${curSite.name}"]` }; } else return; } } } if (siteObj == null) { siteObj = { name: nameInput.value, url: urlInput.value }; if (iconInput.value && iconInput.value != urlInput.value.replace(/\?.*/, "").replace(/^(https?:\/\/[^\/]*\/)[\s\S]*$/, "$1favicon.ico")) { siteObj.icon = iconInput.value; } if (descInput.value && descInput.value != nameInput.value) { siteObj.description = descInput.value; } if (siteKeywords.value) { siteObj.keywords = siteKeywords.value; } if (siteMatch.value) { siteObj.match = siteMatch.value; } if (openSelect.value && openSelect.value != '-1') { siteObj.openInNewTab = openSelect.value === 'true'; } if (self.charset && charset.toLowerCase() != 'utf-8') { siteObj.charset = self.charset; } if (self.kwFilter) { siteObj.kwFilter = self.kwFilter; } if (self.match) { siteObj.match = self.match; } if (self.hideNotMatch) { siteObj.hideNotMatch = self.hideNotMatch; } } searchData.sitesConfig[typeSelect.value].sites.push(siteObj); searchData.lastModified = new Date().getTime(); storage.setItem("lastAddType", typeSelect.value); storage.setItem("searchData", searchData); _GM_notification(i18n("siteAddOver")); if (addFrame.parentNode) { addFrame.parentNode.removeChild(addFrame); } window.postMessage({ searchData: searchData, version: _GM_info.script.version || 0, command: 'loadConfig' }, '*'); searchBar.refreshEngines(); }); }); crawlBtn = addFrame.querySelector("#crawlBtn"); let closeCrawlBtn = addFrame.querySelector(".searchJumperFrame-closeBtn"); let actionCon = addFrame.querySelector(".actionCon"); let inputAction = addFrame.querySelector("#input"); let clickAction = addFrame.querySelector("#click"); let sleepAction = addFrame.querySelector("#sleep"); let copyAction = addFrame.querySelector("#copy"); let submitCrawl = addFrame.querySelector("#submitCrawl"); let recordBtn = addFrame.querySelector("#record"); let loopBtn = addFrame.querySelector("#loop"); let dragDiv; let addAction = (type, sel = '', val = '') => { let div = document.createElement("div"); let words = type; switch(type) { case "input": words = i18n('inputOutput', [sel, val]); break; case "click": words = i18n('clickOutput', sel); break; case "dblclick": words = i18n('dblclickOutput', sel); break; case "rclick": words = i18n('rclickOutput', sel); break; case "copy": words = i18n('copyOutput', sel); break; case "loopStart": words = i18n('loopStart', val); break; case "loopEnd": words = i18n('loopEnd'); break; case "sleep": words = i18n('sleepOutput', val); break; default: break; } if (words) { div.innerHTML = createHTML(words); div.dataset.type = type; div.dataset.sel = sel; div.dataset.val = val; div.draggable = "true"; div.ondragover = e => { e.preventDefault(); }; div.ondragstart = e => { dragDiv = div; } div.ondrop = e => { actionCon.insertBefore(dragDiv, div); } div.onclick = e => { let target = e.target; if (target.nodeName.toUpperCase() == 'SPAN') { if (target.className == 'element') { picker.getSelector(selector => { target.innerText = selector; target.title = selector; addFrame.style.display = ''; div.dataset.sel = selector; }); addFrame.style.display = 'none'; } else { let newValue = prompt(i18n('inputNewValue'), target.innerText); if (newValue) { target.innerText = newValue; target.title = newValue; div.dataset.val = newValue; } } } else if (confirm(i18n('deleteConfirm'))) { actionCon.removeChild(div); } } div.oncontextmenu = e => { let target = e.target; if (target.nodeName.toUpperCase() == 'SPAN') { e.preventDefault(); if (target.className == 'element') { let newValue = prompt('Selector', target.innerText); if (newValue) { target.innerText = newValue; target.title = newValue; div.dataset.sel = newValue; } } else { let newValue = prompt(i18n('inputNewValue'), target.innerText); if (newValue) { target.innerText = newValue; target.title = newValue; div.dataset.val = newValue; } } } } actionCon.appendChild(div); } }; let anylizeEmuUrl = () => { actionCon.innerHTML = createHTML(); let actionParams = urlInput.value.match(/#p{(.*)}/); if (!actionParams) return; actionParams[1].replace(/([^\\])&/g, "$1SJ^PARAM").split("SJ^PARAM").forEach(pair => { pair = pair.trim(); if (/^loopStart\(\d+\)$/.test(pair)) { let loopStart = pair.match(/loopStart\((.*)\)/); addAction('loopStart', '', loopStart[1]); } else if (pair == "loopEnd") { addAction('loopEnd'); } else if (pair.startsWith("click(") && pair.endsWith(')')) { let click = pair.slice(6, pair.length - 1); if (click) { addAction('click', click.replace(/\\([\=&])/g, "$1").trim()); } } else if (pair.startsWith("dblclick(") && pair.endsWith(')')) { let click = pair.slice(9, pair.length - 1); if (click) { addAction('dblclick', click.replace(/\\([\=&])/g, "$1").trim()); } } else if (pair.startsWith("rclick(") && pair.endsWith(')')) { let click = pair.slice(7, pair.length - 1); if (click) { addAction('rclick', click.replace(/\\([\=&])/g, "$1").trim()); } } else if (pair.startsWith("copy(") && pair.endsWith(')')) { let copy = pair.slice(5, pair.length - 1); if (copy) { addAction('copy', copy.replace(/\\([\=&])/g, "$1").trim()); } } else if (pair.startsWith("call(") && pair.endsWith(')')) { let func = pair.slice(5, pair.length - 1); if (func) { addAction('call', '', func.replace(/\\([\=&])/g, "$1").trim()); } } else if (pair.startsWith("wait(") && pair.endsWith(')')) { let func = pair.slice(5, pair.length - 1); if (func) { addAction('wait', '', func.replace(/\\([\=&])/g, "$1").trim()); } } else if (pair.startsWith("open(") && pair.endsWith(')')) { let func = pair.slice(5, pair.length - 1); if (func) { addAction('open', '', func.replace(/\\([\=&])/g, "$1").trim()); } } else if (/^sleep\(\d+\)$/.test(pair)) { let sleep = pair.match(/sleep\((.*)\)/); if (sleep) { addAction('sleep', '', sleep[1]); } } else if (/^reload\(\d?\)$/.test(pair)) { let reload = pair.match(/reload\((.*)\)/); addAction('reload', '', reload[1]); } else { pair = pair.replace(/([^\\])\=/g, "$1SJ^PARAM").replace(/\\([\=&])/g, "$1"); let pairArr = pair.split("SJ^PARAM"); if (pairArr.length === 2) { addAction('input', pairArr[0], pairArr[1].replace(/\\([\=&])/g, "$1")); } else if (pair.endsWith('.click()') || pair.endsWith('.click')) { addAction('click', pair.replace(/\.click(\(\))?$/, '')); } } }); }; let geneUrl = () => { let actions = []; [].forEach.call(actionCon.children, action => { if (!action) return; let sel = action.dataset.sel; let val = action.dataset.val || ''; switch(action.dataset.type) { case "click": actions.push(`click(${sel.replace(/([=&])/g, '\\$1')})`); break; case "dblclick": actions.push(`dblclick(${sel.replace(/([=&])/g, '\\$1')})`); break; case "rclick": actions.push(`rclick(${sel.replace(/([=&])/g, '\\$1')})`); break; case "copy": actions.push(`copy(${sel.replace(/([=&])/g, '\\$1')})`); break; case "input": actions.push(`${sel.replace(/([=&])/g, '\\$1')}=${val}`); break; case "sleep": actions.push(`sleep(${val})`); break; case "loopEnd": actions.push('loopEnd'); break; default: actions.push(`${action.dataset.type}(${val.replace(/([=&])/g, '\\$1')})`); break; } }); return actions.join('&'); }; crawlBtn.addEventListener("click", e => { anylizeEmuUrl(); addFrame.classList.add("crawling"); }); closeCrawlBtn.addEventListener("click", e => { addFrame.classList.remove("crawling"); }); let targetInput; let clickTimer; let clickSthHandler = e => { if (addFrame.style.display === '') return; if (/INPUT|TEXTAREA|SELECT|OPTION/i.test(e.target.nodeName)) { return; } clearTimeout(clickTimer); clickTimer = setTimeout(() => { addAction('click', picker.geneSelector(e.target, true)); }, 300); }; let dblclickSthHandler = e => { if (addFrame.style.display === '') return; if (/INPUT|TEXTAREA|SELECT|OPTION/i.test(e.target.nodeName)) { return; } clearTimeout(clickTimer); addAction('dblclick', picker.geneSelector(e.target, true)); }; let rclickSthHandler = e => { if (addFrame.style.display === '') return; if (/INPUT|TEXTAREA|SELECT|OPTION/i.test(e.target.nodeName)) { return; } e.preventDefault(); clearTimeout(clickTimer); addAction('rclick', picker.geneSelector(e.target, true)); }; let changeHandler = e => { if (addFrame.style.display === '') return; addAction('input', picker.geneSelector(e.target, true), e.target.value); }; let keydownHandler = e => { if (addFrame.style.display === '') return; let quit = false; if (e.keyCode == 27) { quit = true; } else if (e.keyCode == 13) { //enter e.preventDefault(); e.stopPropagation(); e.target && e.target.blur && e.target.blur(); quit = true; } if (quit) { addFrame.style.display = ''; document.removeEventListener('keydown', keydownHandler, true); document.removeEventListener('click', clickSthHandler); document.removeEventListener('dblclick', dblclickSthHandler); document.removeEventListener('contextmenu', rclickSthHandler); document.removeEventListener('change', changeHandler); } }; recordBtn.addEventListener("click", e => { alert(i18n("startRecord")); addFrame.style.display = 'none'; setTimeout(() => { document.addEventListener('keydown', keydownHandler, true); document.addEventListener('click', clickSthHandler); document.addEventListener('dblclick', dblclickSthHandler); document.addEventListener('contextmenu', rclickSthHandler); document.addEventListener('change', changeHandler); }, 100); }); let inLoop = false; loopBtn.addEventListener("click", e => { if (inLoop) { addAction('loopEnd'); loopBtn.innerText = i18n("loopAction"); } else { let loopTimes = prompt(i18n('loopTimes'), 1); if (!loopTimes) return; addAction('loopStart', '', loopTimes || '1'); loopBtn.innerText = i18n("loopActionEnd"); } inLoop = !inLoop; }); inputAction.addEventListener("click", e => { picker.getSelector(selector => { addAction('input', selector, '%s'); addFrame.style.display = ''; }, !inLoop); addFrame.style.display = 'none'; }); copyAction.addEventListener("click", e => { picker.getSelector(selector => { addAction('copy', selector, '%s'); addFrame.style.display = ''; }, !inLoop); addFrame.style.display = 'none'; }); clickAction.addEventListener("dblclick", e => { clearTimeout(clickTimer); e.preventDefault(); e.stopPropagation(); picker.getSelector(selector => { addAction('dblclick', selector); addFrame.style.display = ''; }, !inLoop); addFrame.style.display = 'none'; }); clickAction.addEventListener("contextmenu", e => { clearTimeout(clickTimer); e.preventDefault(); e.stopPropagation(); picker.getSelector(selector => { addAction('rclick', selector); addFrame.style.display = ''; }, !inLoop); addFrame.style.display = 'none'; }); clickAction.addEventListener("click", e => { clearTimeout(clickTimer); clickTimer = setTimeout(() => { picker.getSelector(selector => { addAction('click', selector); addFrame.style.display = ''; }, !inLoop); addFrame.style.display = 'none'; }, 250); }); sleepAction.addEventListener("click", e => { let sleepTime = prompt(i18n('sleepPrompt'), 1000); sleepTime = sleepTime && parseInt(sleepTime); if (sleepTime) addAction('sleep', '', sleepTime); }); submitCrawl.addEventListener("click", e => { let actionUrl = geneUrl(); if (actionUrl) { urlInput.value = location.href + '#p{' + actionUrl + '}'; } addFrame.classList.remove("crawling"); }); } searchBar.addToShadow(addFrame); siteKeywords.value = ""; siteMatch.value = ""; nameInput.value = name || ""; descInput.value = description || ""; urlInput.value = url || ""; if (icons && icons[0]) { iconShow.style.display = ""; if (url.indexOf(location.origin) === 0) { iconShow.onerror = e => { iconShow.onerror = null; iconInput.value = icons[0]; iconShow.src = icons[0]; } iconShow.src = location.origin + "/favicon.ico"; } else { iconInput.value = icons[0]; iconShow.src = icons[0]; } } else { iconShow.style.display = "none"; iconShow.src = (/^(showTips:)?https?:/.test(url) ? url.split('\n')[0].replace(/\?.*/, "").replace(/^(showTips:)?(https?:\/\/[^\/]+).*/, '$2') : location.origin) + "/favicon.ico"; } iconsCon.innerHTML = createHTML(); if (icons && icons.length > 1) { iconsCon.style.opacity = ""; icons.forEach(iconSrc => { let curIcon = document.createElement("img"); curIcon.src = iconSrc; curIcon.addEventListener("click", e => { iconInput.value = iconSrc; iconShow.src = iconSrc; }); curIcon.onload = e => { curIcon.title = curIcon.naturalWidth + " x " + curIcon.naturalHeight + "\n" + iconSrc.replace(/.*\/([^\/]+)/, "$1"); }; iconsCon.appendChild(curIcon); }); } else { iconsCon.style.opacity = 0; } } function downloadCache() { let downloadEle = document.createElement('a'); downloadEle.download = "searchJumperCache.json"; downloadEle.target = "_blank"; let blobStr = [JSON.stringify({sortTypeNames: sortTypeNames, cacheIcon: cacheIcon, sortSiteNames: sortSiteNames}, null , 4)]; let myBlob = new Blob(blobStr, { type: "application/json" }); downloadEle.href = window.URL.createObjectURL(myBlob); downloadEle.click(); } function importCache(cacheData) { if (cacheData.cacheIcon) { cacheIcon = cacheData.cacheIcon; storage.setItem("cacheIcon", cacheIcon); cachePool = []; searchData.prefConfig.cacheSwitch = true; storage.setItem("searchData", searchData); } if (cacheData.sortTypeNames) { sortTypeNames = cacheData.sortTypeNames; storage.setItem("sortTypeNames", sortTypeNames); } if (cacheData.sortSiteNames) { sortSiteNames = cacheData.sortSiteNames; storage.setItem("sortSiteNames", sortSiteNames); } } function showSiteAddFromOpenSearch(url, callback) { _GM_xmlhttpRequest({ method: "GET", url: url, headers: { referer: url, origin: url }, onload: (d) => { let urlparam = d && d.responseXML && d.responseXML.querySelector('Url[type="text/html"]'); if (!urlparam) { callback('error', d); return; } let shortName = d.responseXML.querySelector("ShortName"); let description = d.responseXML.querySelector("Description"); let image = d.responseXML.querySelector("Image"); let inputEncoding = d.responseXML.querySelector("InputEncoding"); let postParams = urlparam.querySelectorAll("Param"); let name = shortName && shortName.textContent; let desc = description && description.textContent; let url = urlparam.getAttribute("template"); let ico = image && image.textContent; let charset = inputEncoding && inputEncoding.textContent; if (postParams.length > 0) { let params = []; [].forEach.call(postParams, postParam => { params.push(`${postParam.getAttribute("name")}=${postParam.getAttribute("value")}`); }); url += `%p{${params.join("&")}}`; } showSiteAdd(name, desc, url.replace(/{searchTerms\??}/g, "%s").replace(/{startPage\??}/g, '1').replace(/{count\??}/g, '10').replace(/{startIndex\??}/g, '1').replace(/{startPage\??}/g, '1').replace(/{language\??}/g, '*').replace(/{inputEncoding\??}/g, 'UTF-8').replace(/{outputEncoding\??}/g, 'UTF-8'), [ico], charset); callback('load', d); }, onerror: (e) => { callback('error', e); }, ontimeout: (e) => { callback('error', e); } }); } function initMycroft() { if (location.hostname !== "mycroftproject.com") return; _GM_addStyle(` .searchJumper-loading { animation-name: changeScale; animation-duration: 2.5s; animation-iteration-count: infinite; } @keyframes changeScale { 0% { -webkit-transform:rotate(0deg) scale(1); -moz-transform:rotate(0deg) scale(1); transform:rotate(0deg) scale(1); } 50% { -webkit-transform:rotate(180deg) scale(1.5); -moz-transform:rotate(180deg) scale(1.5); transform:rotate(180deg) scale(1.5); } 100% { -webkit-transform:rotate(360deg) scale(1); -moz-transform:rotate(360deg) scale(1); transform:rotate(360deg) scale(1); } } `); let checkLinks = () => { let installLinks = document.querySelectorAll("img.icon~a[href^='/install']"); if (installLinks.length <= 0) return; let isLoading = false; [].forEach.call(installLinks, installLink => { if (installLink.previousElementSibling && installLink.previousElementSibling.classList.contains("searchJumperIcon")) return; if (installLink.previousElementSibling && installLink.previousElementSibling.previousElementSibling && installLink.previousElementSibling.previousElementSibling.classList.contains("searchJumperIcon")) return; let urlMatch = installLink.href.match(/\?id=(\d+)&basename=(.+?)&/); if (urlMatch === null) { return; } let icon = document.createElement("img"); icon.className = "icon searchJumperIcon"; icon.style.cssText = "border: 1px solid #4c4c4c; border-radius: 9px; box-sizing: border-box; margin-right: 4px; cursor: pointer;"; icon.title = "Add to SearchJumper"; icon.src = logoBase64; installLink.parentNode.insertBefore(icon, installLink); icon.onclick = e => { if (isLoading) return; isLoading = true; icon.classList.add("searchJumper-loading"); showSiteAddFromOpenSearch(`https://mycroftproject.com/installos.php/${urlMatch[1]}/${urlMatch[2]}.xml`, (type, e) => { isLoading = false; icon.classList.remove("searchJumper-loading"); if (type != 'load') { _GM_notification(e.statusText || e.error); } }); }; }); }; checkLinks(); let checkInterval = setInterval(() => { checkLinks(); }, 1000); window.addEventListener("load", e => { clearInterval(checkInterval); checkLinks(); }); } function initView() { searchBar = new SearchBar(); } function initAllPage() { if (!isAllPage) return; searchBar.appendBar(); searchBar.showAllSites(); setTimeout(() => { searchBar.con.style.zIndex = 0; }, 5); if (location.hash) { let hash = location.hash.slice(1); try { hash = decodeURIComponent(hash); } catch (e) {} searchBar.searchJumperInputKeyWords.value = hash; } else if (location.search) { let search = location.search.slice(1).split("&"); let _keyWords, _engine, _self; search.forEach(s => { let sArr = s.split("="); let k = sArr[0], v = sArr[1]; try { v = decodeURIComponent(v); } catch (e) {} switch(k) { case "kw": _keyWords = v; break; case "engine": _engine = v; break; case "self": _self = v; break; } }); if (_keyWords) { searchBar.searchJumperInputKeyWords.value = _keyWords || ""; } if (_engine) { searchBar.searchBySiteName(_engine, {}, !!_self); } } getBody(document).style.cssText = ` zoom: 1; margin: 0; padding: 0; width: 100vw; height: 100vh; background-position: center 0; background-repeat: no-repeat; background-size: cover; -webkit-background-size: cover; -o-background-size: cover; overflow: hidden; `; if (searchData.prefConfig.bgUrl) { allPageBgUrl = searchData.prefConfig.bgUrl; if (allPageBgUrl.length) { getBody(document).style.backgroundImage = `url("${allPageBgUrl}")`; return; } } storage.getItem("allPageBg", allPageBg => { if (allPageBg) { allPageBgUrl = allPageBg.url; getBody(document).style.backgroundImage = `url("${allPageBg.base64 || allPageBgUrl}")`; } else allPageBg = {url: ""}; if (ext) { chrome.runtime.sendMessage({action: "getBingBG", detail: {curBgUrl: allPageBg.url}}, function(r) { if (r) { allPageBg = r; storage.setItem("allPageBg", allPageBg); allPageBgUrl = allPageBg.url; getBody(document).style.backgroundImage = `url("${allPageBg.base64 || allPageBgUrl}")`; } }); return; } _GM_xmlhttpRequest({ method: 'GET', url: "https://global.bing.com/HPImageArchive.aspx?format=js&idx=0&pid=hp&video=1&n=1", onload: function(result) { var jsonData = null; try { jsonData = JSON.parse(result.responseText); var bgUrl = jsonData.images[0].url; if (!/^https?:\/\//.test(bgUrl)) { bgUrl = "https://global.bing.com" + bgUrl; } allPageBgUrl = bgUrl; if (bgUrl == allPageBg.url) return; _GM_xmlhttpRequest({ method: 'GET', url: bgUrl, responseType: "blob", onload: function(r) { var blob = r.response; var fr = new FileReader(); fr.readAsDataURL(blob); fr.onload = function (e) { var base64ImgData = e.target.result; allPageBg = {url: bgUrl, base64: base64ImgData}; storage.setItem("allPageBg", allPageBg); }; } }); if (!allPageBg.base64) getBody(document).style.backgroundImage = `url("${bgUrl}")`; } catch (e) { console.log(e); } } }); }); } async function initRun() { await searchBar.initRun(); initListener(); initAllPage(); } async function sleep(time) { await new Promise((resolve) => { setTimeout(() => { resolve(); }, time); }) } async function initData() { let _searchData = await new Promise((resolve) => { storage.getItem("searchData", data => { resolve(data); }); }); cacheKeywords = await new Promise((resolve) => { storage.getItem("cacheKeywords", data => { resolve(data || ''); }); }); cacheFilter = await new Promise((resolve) => { storage.getItem("cacheFilter", data => { resolve(data || ''); }); }); disableState = await new Promise((resolve) => { storage.getItem("disableState", data => { resolve(data || false); }); }); tipsStorage = await new Promise((resolve) => { storage.getItem("tipsStorage", data => { resolve(data || []); }); }); lastSign = await new Promise((resolve) => { storage.getItem("lastSign", data => { resolve(data || false); }); }); storage.setItem("lastSign", false); inPagePostParams = await storage.getListItem("inPagePostParams", location.hostname); cacheIcon = await new Promise((resolve) => { storage.getItem("cacheIcon", data => { resolve(data || {}); }); }); historySites = await new Promise((resolve) => { storage.getItem("historySites", data => { resolve(data || []); }); }); historyType = await new Promise((resolve) => { storage.getItem("historyType", data => { resolve(data || ''); }); }); sortTypeNames = await new Promise((resolve) => { storage.getItem("sortTypeNames", data => { resolve(data || {}); }); }); sortSiteNames = await new Promise((resolve) => { storage.getItem("sortSiteNames", data => { resolve(data || {}); }); }); globalInPageWords = await new Promise((resolve) => { storage.getItem("globalInPageWords", data => { resolve(data || ''); }); }); navEnable = await new Promise((resolve) => { storage.getItem("navEnable", data => { resolve(typeof data === "undefined" ? true : data); }); }); referrer = await new Promise((resolve) => { storage.getItem("referrer", data => { resolve(data || ""); }); }); disableHighlight = await new Promise((resolve) => { storage.getItem("disableHighlight", data => { resolve(data || ""); }); }); lastHighlight = await new Promise((resolve) => { storage.getItem("lastHighlight", data => { resolve(data || ""); }); }); allPageNewMode = await new Promise((resolve) => { storage.getItem("allPageNewMode", data => { resolve(data || false); }); }); lastAddType = await new Promise((resolve) => { storage.getItem("lastAddType", data => { resolve(data || ""); }); }); if (_searchData) { searchData = _searchData; lastModified = searchData.lastModified; } if (!searchData.lastModified) { searchData.sitesConfig = sitesConfig; } if (searchData.prefConfig.lang && searchData.prefConfig.lang != '0') { lang = searchData.prefConfig.lang; } setLang(); if (searchData.prefConfig.firstRun && (ext || storage.supportCrossSave())) { searchData.prefConfig.firstRun = false; storage.setItem("searchData", searchData); setTimeout(() => { storage.getItem("searchData", data => { if (data.prefConfig.firstRun === false) { _GM_openInTab(firstRunPage, {active: true, insert: true}); } }); }, 100); } //旧版兼容 if (typeof searchData.prefConfig.customSize === "undefined") { searchData.prefConfig.customSize = 100; } if (typeof searchData.prefConfig.tilesZoom === "undefined") { searchData.prefConfig.tilesZoom = 100; } if (typeof searchData.prefConfig.tipsZoom === "undefined") { searchData.prefConfig.tipsZoom = 100; } if (typeof searchData.prefConfig.typeOpenTime === "undefined") { searchData.prefConfig.typeOpenTime = 250; } if (typeof searchData.prefConfig.longPressTime === "undefined") { searchData.prefConfig.longPressTime = 500; } if (typeof searchData.prefConfig.cacheSwitch === "undefined") { searchData.prefConfig.cacheSwitch = false; } if (typeof searchData.prefConfig.noIcons === "undefined") { searchData.prefConfig.noIcons = false; } if (typeof searchData.prefConfig.noAni === "undefined") { searchData.prefConfig.noAni = false; } if (typeof searchData.prefConfig.quickAddRule === "undefined") { searchData.prefConfig.quickAddRule = true; } if (typeof searchData.prefConfig.multiline === "undefined") { searchData.prefConfig.multiline = 2; } if (typeof searchData.prefConfig.multilineGap === "undefined") { searchData.prefConfig.multilineGap = 1000; } if (typeof searchData.prefConfig.historyLength === "undefined") { searchData.prefConfig.historyLength = 0; } if (typeof searchData.prefConfig.dragToSearch === "undefined") { searchData.prefConfig.dragToSearch = true; } if (typeof searchData.prefConfig.firstFiveWordsColor === "undefined") { searchData.prefConfig.firstFiveWordsColor = []; } if (typeof searchData.prefConfig.inPageWordsStyles === "undefined") { searchData.prefConfig.inPageWordsStyles = []; } if (typeof searchData.prefConfig.rightMouse === "undefined") { searchData.prefConfig.rightMouse = true; } if (typeof searchData.prefConfig.mouseLeaveToHide === "undefined") { searchData.prefConfig.mouseLeaveToHide = true; } if (typeof searchData.prefConfig.currentTypeFirst === "undefined") { searchData.prefConfig.currentTypeFirst = true; } if (typeof searchData.prefConfig.disableAddon === "undefined") { searchData.prefConfig.disableAddon = {}; } if (typeof searchData.prefConfig.suggestType === "undefined") { if (lang === "zh-CN") { searchData.prefConfig.suggestType = "baidu"; } else searchData.prefConfig.suggestType = "google"; } if (typeof searchData.prefConfig.syncBuild === "undefined") { searchData.prefConfig.syncBuild = true; } if (searchData.prefConfig.minSizeMode) { searchData.prefConfig.disableAutoOpen = false; searchData.prefConfig.disableTypeOpen = false; } if (ext) { configPage = chrome.runtime.getURL('config/index.html'); if (!searchData.prefConfig.configPage) { searchData.prefConfig.configPage = configPage; } } else if (searchData.prefConfig.configPage) { configPage = searchData.prefConfig.configPage; } else { searchData.prefConfig.configPage = configPage; } } function globMatch(first, second) { if (first === '*') { return true; } if (first.length == 0 && second.length == 0){ return true; } if (first.length > 1 && first[0] == '*' && second.length == 0){ return false; } if ((first.length > 1 && first[0] == '?') || (first.length != 0 && second.length != 0 && first[0] == second[0])){ return globMatch(first.substring(1), second.substring(1)); } if (first.length > 0 && first[0] == '*'){ return globMatch(first.substring(1), second) || globMatch(first, second.substring(1)); } return false; } if (href.indexOf("#searchJumperMin") != -1) { inMinMode = true; if (href.indexOf("#searchJumperMinPost") != -1) { window.history.replaceState(null, '', href.replace(/#searchJumperMin(Post)?/, "")); } else { if (href.indexOf("#searchJumperMinMobile") != -1) { Object.defineProperty(Object.getPrototypeOf(navigator), 'userAgent', { get:function() { return mobileUa }}); _GM_xmlhttpRequest({ method: 'GET', url: location.href, headers: { referer: location.href, "User-Agent": mobileUa }, onload: function(d) { document.open(); document.write(d.response); document.close(); }, onerror: function(){ }, ontimeout: function(){ } }); return; } window.history.replaceState(null, '', location.href.replace(/#searchJumperMin(Mobile)?/, "")); } } if (document.title == 'SearchJumper Multi') return; var inited = false; var checkGlobalIntv, flashTitleIntv, defaultTitle; async function init(cb) { if (inited) { if (cb) cb(); return; } inited = true; preAction(); await initData(); if (disableState) return; if (searchData.prefConfig.blacklist && searchData.prefConfig.blacklist.length > 0) { let commentStart = false; for (let i = 0; i < searchData.prefConfig.blacklist.length; i++) { let curGlob = searchData.prefConfig.blacklist[i]; if (!curGlob) continue; if (curGlob.indexOf("//") == 0) continue; if (commentStart) { if (/\*\/$/.test(curGlob)) { commentStart = false; } continue; } if (curGlob.indexOf("/*") == 0) { commentStart = true; continue; } if (curGlob.indexOf("/") == 0) { let regMatch = curGlob.match(/^\/(.*)\/(\w*)$/); if (regMatch && new RegExp(regMatch[1], regMatch[2]).test(href)) { return; } } else if (globMatch(curGlob, href)) { return; } } } initView(); await initConfig(); initMycroft(); initRun(); if (cb) cb(); defaultTitle = document.title; } function checkVisibility() { if (document.hidden) { if (searchBar) searchBar.closeShowAll(); else return; if (!searchData.prefConfig.globalSearchNow) return; checkGlobalIntv = setInterval(async () => { let oldGlobalInPageWords = globalInPageWords; globalInPageWords = await storage.getItem("globalInPageWords"); if ((oldGlobalInPageWords || '') == (globalInPageWords || '')) return; searchBar.refreshPageWords(); if (searchBar.navMarks.innerHTML) { clearInterval(checkGlobalIntv); clearInterval(flashTitleIntv); defaultTitle = document.title; flashTitleIntv = setInterval(() => { document.title = document.title == defaultTitle ? '🚩' : defaultTitle; }, 500); } }, parseInt(500 + Math.random() * 500)); return; } init(async () => { if (isInConfigPage || searchData.prefConfig.syncBuild) { searchData = await storage.getItem("searchData"); if (searchBar && searchData.lastModified && lastModified != searchData.lastModified) { searchBar.refreshEngines(); document.dispatchEvent(new Event('dataChanged')); } } let oldGlobalInPageWords = globalInPageWords || ''; storage.getItem("globalInPageWords", data => { globalInPageWords = (data || ''); if (oldGlobalInPageWords != globalInPageWords) { if (searchBar) searchBar.refreshPageWords(); } }); let oldNavEnable = navEnable || false; storage.getItem("navEnable", data => { navEnable = (typeof data === "undefined" ? true : data); if (oldNavEnable != navEnable) { if (searchBar) searchBar.refreshNav(); } }); }); } var waiting = false; function visibilitychangeHandler() { if (!document.head || !getBody(document) || inIframe || disableState) return; if (searchData.prefConfig.globalSearchNow) { clearInterval(checkGlobalIntv); clearInterval(flashTitleIntv); if (document.hidden) { defaultTitle = document.title; } else if (defaultTitle) document.title = defaultTitle; } if (waiting) return; waiting = true; setTimeout(() => { checkVisibility(); waiting = false; }, 500); } storage.getItem("postUrl", postUrl => { if (postUrl && postUrl[0].indexOf(location.hostname.replace(/.*\.(\w+\.\w+)/, "$1")) != -1) { storage.setItem("postUrl", ''); submitByForm(postUrl[1], postUrl[0], '_self'); } else { if (document.head && getBody(document)) { init(); } else { let checkReady = () => { if (document.head && getBody(document)) { init(); } else { setTimeout(() => { checkReady(); }, 10); } }; checkReady(); } document.addEventListener('visibilitychange', visibilitychangeHandler); } }); } if (document && document.documentElement) { run(); } else { let checkReady = () => { if (document && document.documentElement) { run(); } else { setTimeout(() => { checkReady(); }, 10); } }; checkReady(); } })();