Onestep Search - 一键快搜

无缝集成 划词搜索 + 快捷键搜索 + 搜索跳转 + 网址导航, 享受丝滑搜索体验

目前为 2022-08-17 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Onestep Search - 一键快搜
  3. // @namespace https://gf.qytechs.cn/zh-CN/scripts/440000
  4. // @version 2.0.2
  5. // @author eyinwei
  6. // @description 无缝集成 划词搜索 + 快捷键搜索 + 搜索跳转 + 网址导航, 享受丝滑搜索体验
  7. // @homepageURL none
  8. // @icon https://s2.loli.net/2022/08/16/kwm38v2TxY4OtCs.png
  9. // @match *://*/*
  10. // @grant GM_openInTab
  11. // @grant GM_setClipboard
  12. // @grant GM_getValue
  13. // @grant GM_setValue
  14. // @grant GM_xmlhttpRequest
  15. // @run-at document-end
  16. // @license MIT
  17. // @original-author smallx
  18. // ==/UserScript==
  19.  
  20.  
  21.  
  22. (function () {
  23. 'use strict';
  24.  
  25. ///////////////////////////////////////////////////////////////////
  26. // 配置
  27. ///////////////////////////////////////////////////////////////////
  28.  
  29.  
  30. //=========================定义网站数据=======================================
  31. function SiteInfo(_name, _url, _homepage, _icon) {
  32. this.name = _name;
  33. this.url = _url;
  34. this.home = _homepage;
  35. this.icon = _icon;
  36.  
  37. this.callSiteInformation = function (_enable = true) {
  38. return {
  39. name: _name,
  40. url: _url,
  41. home: _homepage,
  42. icon: _icon,
  43. enable: _enable,
  44. };
  45. };
  46. // this.callSiteInformationNoHomepage = function (_enable = true) {
  47. // return {
  48. // name: _name,
  49. // url: _url,
  50. // icon: _icon,
  51. // enable: _enable,
  52. // };
  53. // };
  54. };
  55. // 百度系列
  56. const Baidu = new SiteInfo('百度', 'https://www.baidu.com/s?wd=%s&ie=utf-8', 'https://www.baidu.com/', 'https://www.baidu.com/favicon.ico');
  57. const Baidufanyi = new SiteInfo('百度翻译', 'https://fanyi.baidu.com/#auto/zh/%s', 'https://fanyi.baidu.com/', 'https://fanyi-cdn.cdn.bcebos.com/webStatic/translation/img/favicon/favicon.ico');
  58. const Baiduwangpan = new SiteInfo('百度网盘', 'https://pan.baidu.com/disk/home?#/search?key=%s', 'https://pan.baidu.com/', 'https://nd-static.bdstatic.com/m-static/v20-main/favicon-main.ico');
  59. const Baidubaike = new SiteInfo('百度百科', 'https://baike.baidu.com/search/word?pic=1&sug=1&word=%s', 'https://baike.baidu.com/', 'https://baike.baidu.com/favicon.ico');
  60. const Baiduzhidao = new SiteInfo('百度知道', 'https://zhidao.baidu.com/search?word=%s', 'https://zhidao.baidu.com/', 'https://www.baidu.com/favicon.ico?t=20171027');
  61. const Baiduxinwen = new SiteInfo('百度新闻', 'https://www.baidu.com/s?rtt=1&bsst=1&cl=2&tn=news&rsv_dl=ns_pc&word=%s', 'http://news.baidu.com/', 'https://www.baidu.com/favicon.ico');
  62. const Baiduwenku = new SiteInfo('百度文库', 'https://wenku.baidu.com/search?word=%s', '', 'https://www.baidu.com/favicon.ico');
  63. const Baidumap = new SiteInfo('百度地图', 'https://map.baidu.com/search?querytype=s&wd=%s', '', 'https://map.baidu.com/favicon.ico');
  64. const Baidutupian = new SiteInfo('百度图片', 'https://image.baidu.com/search/index?tn=baiduimage&ie=utf-8&word=%s', '', 'https://www.baidu.com/favicon.ico');
  65. const Baiduxueshu = new SiteInfo('百度学术', 'http://xueshu.baidu.com/s?wd=%s', '', 'https://www.baidu.com/favicon.ico');
  66. const Baidutieba = new SiteInfo('贴吧', 'https://tieba.baidu.com/f?kw=%s&ie=utf-8', 'https://tieba.baidu.com/', 'https://www.baidu.com/favicon.ico');
  67.  
  68.  
  69. // 谷歌系列
  70. const Google = new SiteInfo('谷歌', 'https://www.google.com/search?q=%s&ie=utf-8&oe=utf-8', 'https://www.google.com/', 'https://s2.loli.net/2022/08/16/QUL3cvA4t7Tx5sE.png');
  71. const Googlefanyi = new SiteInfo('谷歌翻译', 'https://translate.google.com/?q=%s', '', 'https://ssl.gstatic.com/translate/favicon.ico');
  72. const Googlemap = new SiteInfo('谷歌地图', 'https://www.google.com/maps/search/%s', 'https://www.google.com/maps/', 'https://s2.loli.net/2022/08/17/SloXZzf9nC6LPbq.png');
  73. const Googleearth = new SiteInfo('谷歌地球', 'https://earth.google.com/web/search/%s', 'https://earth.google.com/web/', 'https://s2.loli.net/2022/08/17/IOiPDl7YX3QnmsC.png');
  74. const Googlexueshu = new SiteInfo('谷歌学术', 'https://scholar.google.com/scholar?hl=zh-CN&q=%s', '', 'https://s2.loli.net/2022/08/17/4BaC1Acu2ebXJR9.png');
  75. const Googlepic = new SiteInfo('谷歌图片', 'https://www.google.com/search?q=%s&tbm=isch', 'https://www.google.com/imghp?hl=zh-CN', Google.icon);
  76. const Googlenews = new SiteInfo('谷歌新闻', 'https://news.google.com/search?q=%s&hl=zh-CN&gl=CN&ceid=CN:zh-Hans', 'https://news.google.com/topstories?hl=zh-CN&gl=CN&ceid=CN:zh-Hans', 'https://s2.loli.net/2022/08/17/RTdZQMD2Aw8eobn.png');
  77.  
  78.  
  79. const StackOverflow = new SiteInfo('StackOverflow', 'https://stackoverflow.com/search?q=%s', '', 'https://s2.loli.net/2022/08/16/mgMHa8UTekYIdV4.png');
  80. const Zhihu = new SiteInfo('知乎', 'https://www.zhihu.com/search?q=%s', 'https://www.zhihu.com/', 'https://static.zhihu.com/heifetz/favicon.ico');
  81. const Bing = new SiteInfo('必应', 'https://cn.bing.com/search?q=%s', 'https://cn.bing.com/', 'https://s2.loli.net/2022/08/16/3uWMUjDVAlS8c9T.png');
  82. const Bilibili = new SiteInfo('哔哩哔哩', 'https://search.bilibili.com/all?keyword=%s', 'https://www.bilibili.com/', 'https://www.bilibili.com/favicon.ico?v=1');
  83. const Taobao = new SiteInfo('淘宝', 'https://s.taobao.com/search?q=%s', 'https://www.taobao.com/', 'https://www.taobao.com/favicon.ico');
  84. const Jingdong = new SiteInfo('京东', 'https://search.jd.com/Search?keyword=%s&enc=utf-8', 'https://www.jd.com/', 'https://search.jd.com/favicon.ico');
  85. const Tianmao = new SiteInfo('天猫', 'https://list.tmall.com/search_product.htm?q=%s', 'https://www.tmall.com/', 'https://www.tmall.com/favicon.ico');
  86. const Maimai = new SiteInfo('脉脉', 'https://maimai.cn/web/search_center?type=gossip&query=%s&highlight=true', 'https://maimai.cn/feed_list', 'https://maimai.cn/favicon.ico');
  87. const Weibo = new SiteInfo('微博', 'https://s.weibo.com/weibo/%s', 'https://weibo.com/', 'https://s.weibo.com/favicon.ico');
  88. const GitHub = new SiteInfo('GitHub', 'https://github.com/search?q=%s','https://github.com/', 'https://s2.loli.net/2022/08/17/OedrPVhtkn5Mug4.png');
  89.  
  90. //=========================定义网站数据=======================================
  91.  
  92. const defaultConf = {
  93. //
  94. // 基本配置
  95. //
  96. showToolbar: true, // 显示划词工具条
  97. showFrequentEngines: true, // 显示常用搜索引擎
  98. showClassifiedEngines: true, // 显示分类搜索引擎
  99. showPlaceholder: false, // 显示使用方式提示信息(如搜索框placeholder)
  100. enableOnInput: true, // 是否在input/textarea上启用划词和快捷键
  101. autoCopyToClipboard: false, // 划词时自动复制到剪贴板(内容为文本格式)
  102. //
  103. // 搜索建议配置
  104. //
  105. // 可选值baidu|google, 可根据需要调整顺序
  106. engineSuggestions: [
  107. {
  108. name: 'google',
  109. showCount: 5,
  110. enable: false
  111. },
  112. {
  113. name: 'baidu',
  114. showCount: 5,
  115. enable: false
  116. },
  117. ],
  118. //
  119. // 搜索框默认搜索引擎
  120. // 属性:
  121. // - name 搜索引擎名称
  122. // - url 搜索引擎搜索url
  123. // - home 搜索引擎主页url
  124. //
  125. defaultEngine: {
  126. name: Bing.name,
  127. url: Bing.url,
  128. home: Bing.home,
  129.  
  130. },
  131. //
  132. // 绑定快捷键的搜索引擎列表
  133. // 属性:
  134. // - name 搜索引擎名称
  135. // - url 搜索引擎搜索url
  136. // - home 搜索引擎主页url
  137. // - hotkeys 快捷键列表, 仅支持配置单字符按键的code值, 实际起作用的是Alt+单字符键, S/D/F/L键已被脚本征用
  138. // - enable 是否启用
  139. //
  140. hotkeyEngines: [
  141. {
  142. name: '百度百科',
  143. url: 'https://baike.baidu.com/search/word?pic=1&sug=1&word=%s',
  144. home: 'https://baike.baidu.com/',
  145. hotkeys: ['KeyW'],
  146. enable: true,
  147. },
  148. {
  149. name: '百度翻译',
  150. url: 'https://fanyi.baidu.com/#auto/zh/%s',
  151. home: 'https://fanyi.baidu.com/',
  152. hotkeys: ['KeyE'],
  153. enable: true,
  154. },
  155. {
  156. name: '百度',
  157. url: Baidu.url,
  158. home: Baidu.home,
  159. hotkeys: ['KeyB'],
  160. enable: true,
  161. },
  162. {
  163. name: 'Google',
  164. url: Google.url,
  165. home: Google.home,
  166. hotkeys: ['KeyG'],
  167. enable: true,
  168. },
  169. ],
  170. //
  171. // 常用搜索引擎列表
  172. // 属性:
  173. // - name 搜索引擎名称
  174. // - url 搜索引擎搜索url
  175. // - home 搜索引擎主页url
  176. // - icon 搜索引擎图标, base64编码
  177. // - enable 是否启用
  178. //
  179. frequentEngines: [
  180. Baidu.callSiteInformation(),
  181. Google.callSiteInformation(),
  182. Bing.callSiteInformation(),
  183. Baidufanyi.callSiteInformation(),
  184.  
  185. GitHub.callSiteInformation(false),
  186.  
  187. Zhihu.callSiteInformation(),
  188. Googlenews.callSiteInformation(false),
  189.  
  190.  
  191. Bilibili.callSiteInformation(),
  192. Taobao.callSiteInformation(false),
  193. Jingdong.callSiteInformation(),
  194. Tianmao.callSiteInformation(false),
  195. Baiduwangpan.callSiteInformation(false),
  196. Maimai.callSiteInformation(false),
  197. ],
  198. //
  199. // 分类搜索引擎列表, 二维数组, 默认认为该配置包含了所有已配置搜索引擎
  200. // 一级分类属性:
  201. // - name 分类名称
  202. // - enable 该分类是否启用
  203. // - engines 该分类下的搜索引擎列表
  204. // 二级搜索引擎属性:
  205. // - name 搜索引擎名称
  206. // - url 搜索引擎搜索url
  207. // - home 搜索引擎主页url
  208. // - icon 搜索引擎图标, base64编码
  209. // - enable 搜索引擎是否启用
  210. //
  211. classifiedEngines: [
  212. {
  213. name: '搜索引擎',
  214. enable: true,
  215. engines: [
  216. Baidu.callSiteInformation(),
  217. Google.callSiteInformation(),
  218. Bing.callSiteInformation(),
  219. {
  220. name: '搜狗',
  221. url: 'https://www.sogou.com/web?query=%s',
  222. icon: 'https://dlweb.sogoucdn.com/translate/favicon.ico?v=20180424',
  223. enable: true
  224. },
  225. {
  226. name: '360',
  227. url: 'https://www.so.com/s?ie=utf-8&q=%s',
  228. icon: 'https://s.ssl.qhimg.com/static/121a1737750aa53d.ico',
  229. enable: true
  230. }
  231. ]
  232. },
  233. {
  234. name: '知识',
  235. enable: true,
  236. engines: [
  237. Zhihu.callSiteInformation(),
  238. StackOverflow.callSiteInformation(),
  239.  
  240. Maimai.callSiteInformation(),
  241. {
  242. name: 'Quora',
  243. url: 'https://www.quora.com/search?q=%s',
  244. icon: 'data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAA81JREFUWAntVluIjFEc/51vlkUiLMot7LBo5ZoSudSSOyu7s6554EFC8iBFNg/a8uTysOVSbmlG7bh7cC0PiiKXbMsMDyRWucsuu3P8zuR8e+acb8Ymb/bUdP6X3/9/fud3vu98A7SN/10B0VoBLoXR5YuHUjRjlgTGsrA353zWv6WdFAJXEEK8vA51re2pcH8kEJuIjvIdtkqJjcR3y9WczQhDvL2H7YufoTYXVudyEoiFMYIdo2xa7BcIPCDtI8LDY6rxnfG+KYm5VGAFsXkKx6YqvimSxEHl5xpZCaQXB26xaXfdgIvuF6Oxufw0l7ZGrBDjUuAxGCp5AtvKE6iyoBluIIGaYejxswkPuHhfA30rksBU7pSCBA+SXkA1zppZkl4WeYZTZsy0PdPR9o+f2G0tDhHCrlyLq1ru9hz1v6/7pGeJvRdGZn92HALxMAopy9qMJsAHMQo3rFigS5JxM8GN9PzagC1mzLQdAj+ACDW2j+Ze0LmbjbQtUrirbX+WWOrbluEQ4AnPtjDKTQbEsoUSTkJicKwIRU6cAZcAMMAGUo6PdiyrL/ApKCebMTAo7hIQ6G0DpUCDHcvm54eCsXwWnL6qh0tA4r3dnAqoK7dVo1GiSxCQD+fboLhLQOClA5To6sSyBbyWi8uEtMvDC9PXdvrq1I6a+QZc5zTBjPGdKNR+dCjmyBRWU5UhjHUm/jnzNV4BjpXfxne+Bb001p+5qdIKJFDpR3zDUSAv5N5aXGSMrIR3tgh9eAmfI8synulo/sK0ZyKFalmPO/FhGJhKYbzf/bfBRQ6JSqIChkNgSR0eEleTgZUoiJ3E5IV1eC09rOeOq6hAxmeXJIsbm3ApTcgo5tm/y+uEaiOUYbKPO84Uon8j8IhN/bMn8Cq/bjM0+sY0dKh/heNUYYmO2TNrpBfC3LKnuGzntO8ooBKLknjJwvlsoD6r6UEyJdEwqtRRqMD0m2jo1Q8raSrFnMHaZu5+fa7FVRFx2Ud0CKZwh6coax+NYtM7vBfS/wdof5ZNmEfMbp3XMxuXUrEz2k8T3wnJGu6lZeQkoGDnh6LgWzP2sND/w9FSnsMSOFyRwBqF4JtTwpvwCs1rFUmUmFV/JKDBvMsHsckq+rP4G8tdt1c5NnjD6QmNSYxlXFjMXVSK8fFfxX2rr+w+qrJJ1enRagK6QM/6Gz/vET6oGI9rB++HXTofOAuMoyr3zNxfEzCbKDtWhpC8j6NUYbmdS/sCB7j4Bjv3zwioxupBi57AUiGxjkcynLKHONfyvamOPMVRe/E2v00BpcAvNM8U1IpUANcAAAAASUVORK5CYII=',
  245. enable: false
  246. },
  247.  
  248. Baiduzhidao.callSiteInformation(),
  249. {
  250. name: '维基百科',
  251. url: 'https://zh.wikipedia.org/wiki/%s',
  252. icon: 'https://s2.loli.net/2022/08/17/uycfXb6FIGRV5mN.png',
  253. enable: true
  254. },
  255.  
  256. Baidubaike.callSiteInformation(),
  257. {
  258. name: '萌娘百科',
  259. url: 'https://zh.moegirl.org/%s',
  260. icon: 'data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAogB2AMkAFgAAAAAAAAAAALUAMgCrAIIAAAAAAAAAAAAAAAAAAAAAAKwASgCbAK0AnAC3AK0AYAD/AAEA/wAbAI0A/wCnADYAAAAAAAAAAACoAFUAlgDeAAAAAAAAAAAAAAAAAMMAPgCVAPsAqACJAKMAdgCWAPEAsQBXAKwAHACMAP8AyQAsAAAAAAAAAAAAsAA7AJQA+wD/AAMAAAAAAAAAAACXAH0AnQC2AAAAAAAAAAAApQB4AJsAvgDPADUAjQD/AKYAgQCkAIUAmwB/ANcAKwCOAP8A2AAdAAAAAAAAAAAAjwCBAKEAqgDkAAwA/AAQALQARACXAOoAoAA2AI4A/wCWAK4AlwCoAKAAlADwABQAkwD7AK8ANQAAAAAAAAAAAJEAgQCQAP0AjwD/AKMA1ADFADIAjQDuALYATQCQAPcA/wACAAAAAAAAAAAAAAAAAJgA5QCmAE4AAAAAAAAAAACjAHkAmwDUALgAJgD/AAYAtAA8AJEA7wCfAFIAkQD/AJsA0QCRANoAlQDYAPMAIACUAMoApQBlAAAAAAAAAAAAowBeAJkA5gDeABUA/wABAKwAjgCZAMIApQBiAJMA7QCkAGAAowBSALUAMwD/AAEAngDFAJEAZgAAAAAAAAAAAMkAJQCaANcAlQDzAJwAywCWAPQAsAA3AKcAbwCOAPsAoACjALIAQgD/ABQAyQAxAJUA6wChAF8AAAAAAAAAAAAAAAAA/wACAK0AQQCgAFoAxgAcAAAAAACwAEMAnwCOAJ4AsQCRAPoAjQD/AI8A/wCiAL0A4wAOAAAAAAAAAAAAAAAAAAAAAAD/AC4A/wC9ALIAswD/AG8AAAAAAAAAAAD/AAEAogDmAM4AVADVABEAAAAAAAAAAAAAAAAAAAAAAKwAhQCfALsAyQDBAOwA/wDqAP8A8gD9AMkApQCPAGkAlwBqAJcA8QChAKsAqwBkAJAATgCvADsAAAAAAAAAAAC0AEsAmQB8AMoAlQDzAPYA/wD/APkA6gCgALcAngDCAJQAwgCSANwAkAD9AJcA0QCcAN0AqACfAAAAAAAAAAAAAAAAAAAAAAAAAAAAoQCVAK0AnAD/AB8AAAAAAAAAAAAAAAAAwgAqAJgA+AD/AAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOEADgD4AAoAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAoA/wABAAAAAAAAAAAAAAAA//+sQf8zrEHAM6xBgDGsQZgBrEGAAaxBgDmsQYABrEGAAaxBgAGsQcIBrEHhh6xBgAGsQYABrEHxx6xB8+esQQ==',
  261. enable: false
  262. },
  263.  
  264.  
  265. {
  266. name: '豆丁文档',
  267. url: 'https://www.docin.com/search.do?searchcat=2&searchType_banner=p&nkey=%s',
  268. icon: 'https://st.douding.cn/images_cn/topic/favicon.ico?rand=24220809',
  269. enable: true
  270. },
  271. {
  272. name: '豆瓣读书',
  273. url: 'https://search.douban.com/book/subject_search?search_text=%s',
  274. home: 'https://book.douban.com/',
  275. icon: 'https://www.douban.com/favicon.ico',
  276. enable: true
  277. },
  278. {
  279. name: '微信(搜狗)',
  280. url: 'https://weixin.sogou.com/weixin?ie=utf8&type=2&query=%s',
  281. icon: 'https://dlweb.sogoucdn.com/translate/favicon.ico?v=20180424',
  282. enable: true
  283. },
  284. {
  285. name: '果壳',
  286. url: 'https://www.guokr.com/search/all/?wd=%s',
  287. icon: 'https://www.guokr.com/favicon.ico',
  288. enable: false
  289. }
  290. ]
  291. },
  292. {
  293. name: '开发',
  294. enable: true,
  295. engines: [
  296.  
  297. StackOverflow.callSiteInformation(),
  298. {
  299. name: 'Apache Issues',
  300. url: 'https://issues.apache.org/jira/secure/QuickSearch.jspa?searchString=%s',
  301. home: 'https://issues.apache.org/jira/',
  302. icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAABE0AAARNAES6f7VAAAAB3RJTUUH4QIJEAkJojze8AAAA1xJREFUWMPdl0tonVUQx38z5/vubaPmJqZV+8JrJWmjQqXRGAUXFiwKgqsWV4UqqNSVYEVLuxJ1IdKVj67EjYauBLEU8YVUY9OilSZi2pReCLWJrXmQ1+V+35lxoVvtzW2uAQfO6syZ/+/MmTOHIyyzzb9/Z1nw94DHLBPyqrzetn/04D/563KKXz3U2WpV2e8uO4FFSUCEF/5tTbJc4r+9tDXJFvwZgj1dbGdKEl/lEdwZ+08A4pw8KgmH3LVm0TMN0u4RHD5oOkBlz91r4jyvaeqtnvk5z3yjJK6SAPj3TQeozegBTenR3M5qpOBRbpLUkcRPaJDzTQUY3nHvU7bAi57YFS/qpOU8rIkhqSCJH9HAdNMABjr6Omrj2cHCzdEl1YuYdUqOeipoznER+ax8dMiaBpC02rP5vHYDV9M2m/dM10uKg17ymhye+K4wfc0YjYoPlnvLDntQ0WwxjFqmm91BxAWlTYS4g5N+rTgNNyJHnnOnCxjDGbdMNnoEywSvycdWkx/rymIj4ifKDz0Y8V2CqbifFmQbEHAAH3Gnv/fiqammAHxRfiSJxCcdu0PRMcVawTb/NSsGcgp8uO46Wvr+w+05+oBgqtgvinUrxt/jMnCsrzI40TSAjHCXQHfAZg3LFbtFMAKOYlGx8SXdpKU4f1p+ohDxHvBbHTkdYJ2jRcVwzAUd2E7lm6YBZKRrBe8THCOOGGGnYKIYAZsQeLdUqXgzATYo3ivYoCJrDSspiuLRsaOPV459u9QjrasPvNH1smy4/7JMa+umRSm2R8KVnGRLRlowwpwj/RnFNxvqpvU1HQ/7Zg7fNxNKPbmlc2mcKimsD+Rf1Sh8PRnah56/cGS8aQCCG0hLLrp3TldPgLcL/nNVimeiJPc40t/we1KP02xooejZiLqfjxJKk7oq4LZNsFLA97167q3RRgHqqoHEI5mk22uadNQkXMpE1kXV1EQ/iejAdb2o9ThVQ+FGNd+i8JOIVAS7YG4fjRbafug/+4o3HcDQhTzoh2r2axD98vNNndUzx3dfl/CSADJJouBl1/DH20MHFhlm2ayuGpBQTHNNbquKnlvun1RdGfg9zq5WVFvDDdMrAjCaTbQoMn1y6J24IgCzvrjGYYGVsq1de3fzf7U/AU7ddxqLiUogAAAAAElFTkSuQmCC',
  303. enable: true
  304. },
  305. GitHub.callSiteInformation(),
  306. {
  307. name: 'Maven',
  308. url: 'https://mvnrepository.com/search?q=%s',
  309. icon: 'data:image/x-icon;base64,AAABAAEAEBAAAAAAAABoBQAAFgAAACgAAAAQAAAAIAAAAAEACAAAAAAAAAEAAAAAAAAAAAAAAAEAAAAAAAAAAAAA49nPALqwpgDWdBgA13UZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAAABAQEBAQEBAQEBAQEBAQAAAEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAQAAAQAAAQAAAQABAAEAAIEAgAEAgQEAAAEBAQEBAAEBAQABAQEBAAABAQEBAQABAIEAAQEBAQAAAQEAAQEAAQABAAEBAAEAAAEAAAABAAEAAQABAAABAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAAAEBAQEBAQEBAQEBAQEBAAAAwMDAwMDAwMDAwQEBAQAAAAAAAAAAAAAAAAAAAAAAP//AACAAQAAgAEAAIABAAD//wAAu20AAKohAACCIQAAgiEAAJKlAAC6rQAA//8AAIABAACAAQAAgAEAAP//AAA=',
  310. enable: true
  311. }
  312. ]
  313. },
  314. {
  315. name: '翻译',
  316. enable: true,
  317. engines: [
  318.  
  319. Baidufanyi.callSiteInformation(),
  320. Googlefanyi.callSiteInformation(),
  321.  
  322. {
  323. name: '有道词典',
  324. url: 'https://youdao.com/w/%s',
  325. icon: 'https://shared-https.ydstatic.com/images/favicon.ico',
  326. enable: true
  327. },
  328. {
  329. name: '必应翻译',
  330. url: 'https://cn.bing.com/dict/search?q=%s',
  331. home: 'https://www.bing.com/dict',
  332. icon: Bing.icon,
  333. enable: true
  334. },
  335. {
  336. name: '海词词典',
  337. url: 'http://dict.cn/%s',
  338. icon: 'http://i1.haidii.com/favicon.ico',
  339. enable: true
  340. },
  341. {
  342. name: 'CNKI翻译',
  343. url: 'http://dict.cnki.net/dict_result.aspx?scw=%s',
  344. icon: 'https://epub.cnki.net/favicon.ico',
  345. enable: false
  346. },
  347. {
  348. name: '汉典',
  349. url: 'https://www.zdic.net/hans/%s',
  350. icon: 'https://www.zdic.net/favicon.ico',
  351. enable: false
  352. },
  353. {
  354. name: 'deepL',
  355. url: 'https://www.deepl.com/translator#en/zh/%s',
  356. icon: 'https://s2.loli.net/2022/08/17/m3H5BdLRAexbVsz.png',
  357. enable: true
  358. },
  359. ]
  360. },
  361. {
  362. name: '地图',
  363. enable: true,
  364. engines: [
  365.  
  366. Baidumap.callSiteInformation(),
  367. {
  368. name: '高德地图',
  369. url: 'https://www.amap.com/search?query=%s',
  370. icon: 'https://a.amap.com/pc/static/favicon.ico',
  371. enable: true
  372. },
  373. Googlemap.callSiteInformation(),
  374. Googleearth.callSiteInformation()
  375.  
  376. ]
  377. },
  378. {
  379. name: '图片',
  380. enable: true,
  381. engines: [
  382.  
  383. Baidutupian.callSiteInformation(),
  384. {
  385. name: '搜狗图片',
  386. url: 'https://pic.sogou.com/pics?query=%s',
  387. icon: 'https://dlweb.sogoucdn.com/translate/favicon.ico?v=20180424',
  388. enable: true
  389. },
  390. Googlepic.callSiteInformation(),
  391.  
  392. {
  393. name: '必应图片',
  394. url: 'https://www.bing.com/images/search?q=%s',
  395. home: 'https://www.bing.com/images/trending',
  396. icon: Bing.icon,
  397. enable: true
  398. },
  399. {
  400. name: 'pixiv',
  401. url: 'https://www.pixiv.net/tags/%s',
  402. icon: 'https://s2.loli.net/2022/08/17/OxGZLn26TlWyQt9.png',
  403. enable: true
  404. },
  405. {
  406. name: 'flickr',
  407. url: 'https://www.flickr.com/search/?q=%s',
  408. icon: 'https://combo.staticflickr.com/pw/favicon.ico',
  409. enable: true
  410. },
  411. {
  412. name: '花瓣',
  413. url: 'https://huaban.com/search/?q=%s',
  414. icon: 'https://huaban.com/favicon.ico',
  415. enable: true
  416. }
  417. ]
  418. },
  419. {
  420. name: '音乐',
  421. enable: true,
  422. engines: [
  423. {
  424. name: '网易云音乐',
  425. url: 'https://music.163.com/#/search/m/?s=%s',
  426. icon: 'https://s1.music.126.net/style/favicon.ico?v20180823',
  427. enable: true
  428. },
  429. {
  430. name: 'QQ音乐',
  431. url: 'https://y.qq.com/portal/search.html#page=1&searchid=1&remoteplace=txt.yqq.top&t=song&w=%s',
  432. icon: 'https://y.qq.com/favicon.ico?max_age=2592000',
  433. enable: true
  434. },
  435. {
  436. name: '酷我音乐',
  437. url: 'http://www.kuwo.cn/search/list?type=all&key=%s',
  438. icon: 'http://www.kuwo.cn/favicon.ico',
  439. enable: true
  440. },
  441.  
  442. {
  443. name: '咪咕音乐',
  444. url: 'https://music.migu.cn/v3',
  445. icon: 'https://music.migu.cn/favicon.ico',
  446. enable: true
  447. },
  448. {
  449. name: '酷狗5sing',
  450. url: 'http://search.5sing.kugou.com/?keyword=%s',
  451. home: 'http://5sing.kugou.com/index.html',
  452. icon: 'http://5sing.kugou.com/favicon.ico',
  453. enable: true
  454. }
  455. ]
  456. },
  457.  
  458. {
  459. name: '购物',
  460. enable: true,
  461. engines: [
  462.  
  463. Taobao.callSiteInformation(),
  464. Jingdong.callSiteInformation(),
  465. Tianmao.callSiteInformation(),
  466.  
  467. {
  468. name: '当当',
  469. url: 'http://search.dangdang.com/?key=%s&act=input',
  470. home: 'http://www.dangdang.com/',
  471. icon: 'http://www.dangdang.com/favicon.ico',
  472. enable: false
  473. },
  474. {
  475. name: '苏宁',
  476. url: 'https://search.suning.com/%s/',
  477. home: 'https://www.suning.com/',
  478. icon: 'https://www.suning.com/favicon.ico',
  479. enable: false
  480. },
  481. {
  482. name: '亚马逊',
  483. url: 'https://www.amazon.cn/s?k=%s',
  484. icon: 'https://www.amazon.cn/favicon.ico',
  485. enable: false
  486. }
  487. ]
  488. },
  489.  
  490. /*{
  491. name: '自定义',
  492. enable: true,
  493. engines: [
  494. Baiduwangpan.callSiteInformation(),
  495. ]
  496. },*/
  497. {
  498. name: '学术',
  499. enable: true,
  500. engines: [
  501. Googlexueshu.callSiteInformation(),
  502.  
  503.  
  504. Baiduxueshu.callSiteInformation(),
  505. {
  506. name: '知网',
  507. url: 'http://epub.cnki.net/kns/brief/default_result.aspx?txt_1_value1=%s&dbPrefix=SCDB&db_opt=CJFQ%2CCJFN%2CCDFD%2CCMFD%2CCPFD%2CIPFD%2CCCND%2CCCJD%2CHBRD&singleDB=SCDB&action=scdbsearch',
  508. icon: 'https://epub.cnki.net/favicon.ico',
  509. enable: true
  510. },
  511. {
  512. name: '万方',
  513. url: 'http://www.wanfangdata.com.cn/search/searchList.do?searchType=all&searchWord=%s',
  514. icon: 'https://cdn.s.wanfangdata.com.cn/favicon.ico',
  515. enable: true
  516. },
  517. {
  518. name: 'WOS',
  519. url: 'http://apps.webofknowledge.com/UA_GeneralSearch.do?fieldCount=3&action=search&product=UA&search_mode=GeneralSearch&max_field_count=25&max_field_notice=Notice%3A+You+cannot+add+another+field.&input_invalid_notice=Search+Error%3A+Please+enter+a+search+term.&input_invalid_notice_limits=+%3Cbr%2F%3ENote%3A+Fields+displayed+in+scrolling+boxes+must+be+combined+with+at+least+one+other+search+field.&sa_img_alt=Select+terms+from+the+index&value(input1)=%s&value%28select1%29=TI&value%28hidInput1%29=initVoid&value%28hidShowIcon1%29=0&value%28bool_1_2%29=AND&value%28input2%29=&value%28select2%29=AU&value%28hidInput2%29=initAuthor&value%28hidShowIcon2%29=1&value%28bool_2_3%29=AND&value%28input3%29=&value%28select3%29=SO&value%28hidInput3%29=initSource&value%28hidShowIcon3%29=1&limitStatus=collapsed&expand_alt=Expand+these+settings&expand_title=Expand+these+settings&collapse_alt=Collapse+these+settings&collapse_title=Collapse+these+settings&SinceLastVisit_UTC=&SinceLastVisit_DATE=×panStatus=display%3A+block&timeSpanCollapsedListStatus=display%3A+none&period=Range+Selection&range=ALL&ssStatus=display%3Anone&ss_lemmatization=On&ss_query_language=&rsStatus=display%3Anone&rs_rec_per_page=10&rs_sort_by=PY.D%3BLD.D%3BVL.D%3BSO.A%3BPG.A%3BAU.A&rs_refinePanel=visibility%3Ashow',
  520. icon: 'data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAABEpJREFUWAmdVl1sFFUUPmfY2S3QVoMI7XYhUSsmGqttjRZqtCIBEoT4YGrQPuiDoSXCA4nRREPqi/ENSYWiUVQSSRNSS9Q3I0GFtmoN8aeJQbQrrNAaq7S2pWS7c/3OtjPO7N6ZzuxJzt57v3PuOd/92TOXqURpr1LvsaIUGdQbL6O+gyM8VkooLmVSR5XaphR9as9FEEsxnTEUHbsnRcd2fcdZ27ZYG5nAnlpVmZ2iYZLV64TpIuDXzXI62nWBr+tc3JjhHoTpz03RK77JJYCitdDDIHmho1q1K4W9CZBAY+G8F29VN0xM0yXgFYU2vzEzfZEgeuaNUU7rfCLtwOQMtSNI6OSSEHfl4VlFP+yuVs/pCBTuwHY4PQAth4I4zUKnoBnor+2rVSfaZmhJgmQny0x66kCGr9kBCgkMw3CnbSxoT2H86O6UqqU52oyVbVFEjwCLtCNI2I+lPdZ9kf+R+G4ClRgL6Hcse2B7E+rIW43KPHeZdrBF+0GmzjEs0sG9GI4toa1df3DGTWAj5n0eMPc22H7T2eWmP5+kx615IvfqfAoxkDjXPcoN7tXK2fvJnzBok8sEZlaHrnDf4VFqwHAnVnVV8CCBT4/Y3QSCmH8bFMy2CZEjY9yTYKrH4X5j45p2bJUxf5xuAis1jjYk//3QIv/5+hp6EBMO+Ex6rfMyz4jNTeAmH2eB/wqwaU3yPcBu7MNW7y1wGNj4EB2yMTeBFTaoacc1WCioe4y7DKYXxBlkJmNET7ee4JxushQc/Ju02qabEAVDJXwZ34aiOCDkiOn0ijsTxVA05OPe+AQ+SzFa753nPoJ8ZfKanVHQBXWc/DqpwXibxeog6kXXmqGE1BNH3AT+dtDiTnUxFA5JDprPWpb1Pg5WcpVbWet4i2pxdj4sgWS4dP97SXVM9sf24610FOgS2wL8/l8Gz0pZz0tYApF2INVfuSI1YH6CDK8u5PE0IPFS3ferlwvoJvCzx8s7uMs79B8lB+JPWjwzjL/TNn8vWjU+PZ6vD24CQeX2DgRbGxCQagbNppqB2GekrB6cd1WQr9gU8xPSOpcB/aDaLb6boe9Ix5bGoUbzSvanrUy5vcpSm2x8sRbfjB+NhLmdKOt5D8g8+erd7BPgBPDWdUMVK6/NXW+2lNqCdbTiYRJUwjWh+Kv40uU70vVX819MVEePdGB0N7RiQefQji7oeWxxBxK2YFyS4A3Qa1al2tK3pOWplxf3EQjQPQ/7/tbC0uJr9TMwTRqK92XWZ98lSnu83JfQY9ANWC07gkOb1tn8MGzxqUQiVpfZIMmLJRKBzIZJVEuWwrKo4KJdMgzehVVvGmmY/d1vQiQCEsRQSzvRyGXVC/OIJL6xcl1tpin7tryS9I7zaOElDPJ1bGu+ju/M5azjDkCUwwX7Ervzwe1NzR+e5tNyeUNJSQQkMup8H5Li+ccfLTPLTp6/79/IryaJ8x9KSDhA8t6n2QAAAABJRU5ErkJggg==',
  521. enable: true
  522. },
  523.  
  524. {
  525. name: 'Springer',
  526. url: 'http://rd.springer.com/search?query=%s',
  527. icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAlVJREFUeNrsVz1SwkAUXhw7G7xBPEBGPIHhBqRMBZwAUlsAhXX0BIGKUjxB4ATgcADjCUxjrS+7X5g1f+wuYcbCN/OMLLt53/vet2+XFjMx27Po74A8IZ+z/TJhhnapGTgN2ibfkU8w2ie/MwXQ0gTwnRtZkzvkPnlM3iF/0mHkQhPwDoGyAAs8A/IXsBISUOdcALLAzxIgxnXA2Ayfe+QRgdiSvzQHwPY6oDghiqf07NIzA/DBx/bLVAs35CvM7WHdiQDES0IIUGS/X67xbRdaYBiPyV36bwjGojoQLcXgW3yKueD2y5UicIcDEKVZ0LonEwb6eA5R57Zy2QRLM5Sjr18C22tDVGkGFspwX5mtaFB5EFMwZ+F9WgyECJwpPBXesGJuhO5YZhlzPfVOaHtjLJgfrXlJZjlbIZkJzU3k913UCC9A1n7hHCiq2sn1hXwZEoCwjjMgsgkPwiu21YjTaXuuNDaSWnOVvUl6qtVAANWuKpS7Qz0jyR0+v/4MyMBZ1QAEtQNMTgqU2V540IVoQK7Unn3FzTmqYyA7aFIgr+QbCvqJ4D2Am/OdIPZ4H2z4vAOqmVMNQFDYlbbgRGo8AcD5BTZKOlyNPddrQBww7q+OZ3uB1A8YP+lkNvRsfbwRCXpdqa5jaXGEEpkEZ2VbUedGFPJbkaBfd+0Aa99N7wPOYYeclnnX9EY0kk5FE7vFZSY2BeAg+9gQQKesVatcSKL83m3AZjimlX4XLHhDatbW7N/+ih0V4efDVXY8N2mL68evuaoIO2fYBRvTn2aN248AAwDlS8jXdEymWAAAAABJRU5ErkJggg==',
  528. enable: true
  529. },
  530. {
  531. name: 'Letpub',
  532. url: 'https://www.letpub.com.cn/index.php?page=journalapp&view=search&searchsort=relevance&searchname=%s',
  533. home: 'https://www.letpub.com.cn/',
  534. icon: 'https://www.letpub.com.cn/images/favicon.ico',
  535. enable: true
  536. },
  537. {
  538. name: '科研通',
  539. url: 'https://www.ablesci.com/journal/index?keywords=%s',
  540. home: 'https://www.ablesci.com/',
  541. icon: 'https://www.ablesci.com/favicon.ico/',
  542. enable: true
  543. }
  544. ]
  545. },
  546. {
  547. name: '社交',
  548. enable: true,
  549. engines: [
  550. Weibo.callSiteInformation(),
  551.  
  552. Baidutieba.callSiteInformation(),
  553.  
  554. Zhihu.callSiteInformation(),
  555.  
  556. {
  557. name: '豆瓣',
  558. url: 'https://www.douban.com/search?q=%s',
  559. home: 'https://www.douban.com/',
  560. icon: 'https://www.douban.com/favicon.ico',
  561. enable: true
  562. },
  563. {
  564. name: 'Twitter',
  565. url: 'https://twitter.com/search?q=%s',
  566. icon: 'https://s2.loli.net/2022/08/17/rsbLXJA1lG5hmfe.png',
  567. enable: false
  568. },
  569. {
  570. name: 'Facebook',
  571. url: 'https://www.facebook.com/search/results.php?q=%s',
  572. icon: 'https://s2.loli.net/2022/08/17/69R4ObX3kUctNvM.png',
  573. enable: false
  574. }
  575. ]
  576. },
  577. {
  578. name: '新闻',
  579. enable: false,
  580. engines: [
  581. Googlenews.callSiteInformation(),
  582. Baiduxinwen.callSiteInformation(),
  583. {
  584. name: '今日头条',
  585. url: 'https://www.toutiao.com/search/?keyword=%s',
  586. icon: 'https://lf3-search.searchpstatp.com/obj/card-system/favicon_5995b44.ico',
  587. enable: true
  588. },
  589. Weibo.callSiteInformation(),
  590. Zhihu.callSiteInformation()
  591.  
  592. ]
  593. }
  594. ],
  595. };
  596.  
  597. ///////////////////////////////////////////////////////////////////
  598. // css样式
  599. ///////////////////////////////////////////////////////////////////
  600.  
  601. const sheet = `
  602. /*
  603. 注意: 为了避免网页style对该工具的影响, 所有样式均进行初始化并加入!important,
  604. js中设置style时也要注意将其设置为important, 否则不能生效.
  605. */
  606. /* 划词工具条 */
  607. .qs-toolbar {
  608. /* 初始化所有style, 避免被网页本身的style影响 */
  609. all: initial !important;
  610. position: absolute !important;
  611. display: block !important;
  612. height: 26px !important;
  613. padding: 2px !important;
  614. white-space: nowrap !important;
  615. border: 1px solid #F5F5F5 !important;
  616. box-shadow: 0px 0px 2px #BBB !important;
  617. background-color: #FFF !important;
  618. z-index: 10000 !important;
  619. }
  620. .qs-toolbar-icon {
  621. all: initial !important;
  622. display: inline-block !important;
  623. margin: 0px !important;
  624. padding: 2px !important;
  625. width: 20px !important;
  626. height: 20px !important;
  627. border: 1px solid #FFF !important;
  628. cursor: pointer !important;
  629. }
  630. .qs-toolbar-icon:hover {
  631. border: 1px solid #CCC !important;
  632. }
  633.  
  634. /* 快搜主窗口背景层 */
  635. .qs-main-background-layer {
  636. all: initial !important;
  637. position: fixed !important;
  638. display: block !important;
  639. top: 0px !important;
  640. left: 0px !important;
  641. width: 100% !important;
  642. height: 100% !important;
  643. border: 0px !important;
  644. background-color: rgba(255,255,255,0.3) !important;
  645. /* 使背景层背后的所有元素虚化 */
  646. backdrop-filter: blur(5px) !important;
  647. z-index: 20000 !important;
  648. }
  649.  
  650. /* 快搜主窗口 */
  651. .qs-mainbox {
  652. all: initial !important;
  653. position: fixed !important;
  654. display: block !important;
  655. text-align: center !important;
  656. overflow: scroll !important;
  657. left: 50% !important;
  658. top: 50% !important;
  659. transform: translate(-50%, -50%) !important;
  660. /* 宽度优先展示 */
  661. width: max-content !important;
  662. min-width: 500px !important;
  663. max-width: 1400px !important;
  664. min-height: 75px !important;
  665. max-height: 650px !important;
  666. padding: 10px !important;
  667. border: 1px solid #F5F5F5 !important;
  668. box-shadow: 0px 0px 6px #BBB !important;
  669. border-radius: 10px !important;
  670. background-color: #FFF !important;
  671. opacity: 1 !important;
  672. z-index: 30000 !important;
  673. }
  674. /* 快搜主窗口搜索框 */
  675. .qs-main-search-box {
  676. all: initial !important;
  677. display: block !important;
  678. text-align: center !important;
  679. width: 100% !important;
  680. margin: 5px 0px !important;
  681. border: 0px !important;
  682. }
  683. .qs-main-search-input {
  684. all: initial !important;
  685. text-align: left !important;
  686. width: 80% !important;
  687. min-width: 400px !important;
  688. max-width: 600px !important;
  689. height: 40px !important;
  690. padding: 0px 13px !important;
  691. font: 17px/20px arial !important;
  692. border: 2px solid #C4C7CE !important;
  693. border-radius: 10px !important;
  694. outline: none !important;
  695. }
  696. .qs-main-search-input:hover, .qs-main-search-input:focus {
  697. border-color: #4E71F2 !important;
  698. }
  699. .qs-main-search-input::selection {
  700. color: #FFF !important;
  701. background-color: #425d78 !important;
  702. }
  703. .qs-main-search-input::placeholder {
  704. color: #DDD !important;
  705. opacity: 1 !important;
  706. }
  707. /* 快搜主窗口常用搜索引擎列表 */
  708. .qs-main-frequent-box {
  709. all: initial !important;
  710. display: block !important;
  711. text-align: center !important;
  712. width: 100% !important;
  713. height: 38px !important;
  714. margin: 15px 0px 5px 0px !important;
  715. white-space: nowrap !important;
  716. border: 0px !important;
  717. }
  718. .qs-main-frequent-icon {
  719. all: initial !important;
  720. display: inline-block !important;
  721. width: 28px !important;
  722. height: 28px !important;
  723. margin: 0px 6px !important;
  724. padding: 3px !important;
  725. border: 2px solid #FFF !important;
  726. cursor: pointer !important;
  727. }
  728. .qs-main-frequent-icon:hover {
  729. border: 2px solid #CCC !important;
  730. }
  731. /* 快搜主窗口分类搜索引擎列表 */
  732. .qs-main-classified-box {
  733. all: initial !important;
  734. display: block !important;
  735. text-align: center !important;
  736. width: 100% !important;
  737. margin-top: 15px !important;
  738. padding-top: 5px !important;
  739. border: 0px !important;
  740. border-top: 1px solid #DDD !important;
  741. }
  742. .qs-main-classified-family-box {
  743. all: initial !important;
  744. display: inline-block !important;
  745. text-align: left !important;
  746. vertical-align: top !important;
  747. min-width: 50px !important;
  748. max-width: 150px !important;
  749. height: 100% !important;
  750. margin: 5px 3px !important;
  751. border: 0px !important;
  752. }
  753. .qs-main-classified-family-title {
  754. all: initial !important;
  755. display: block !important;
  756. text-align: left !important;
  757. margin: 5px 4px !important;
  758. font-size: 18px !important;
  759. font-weight: 300 !important;
  760. color: #777 !important;
  761. border: 0px !important;
  762. }
  763. .qs-main-classified-family-engine {
  764. all: initial !important;
  765. display: block !important;
  766. text-align: left !important;
  767. vertical-align: middle !important;
  768. height: 26px !important;
  769. border: 2px solid #FFF !important;
  770. cursor: pointer !important;
  771. }
  772. .qs-main-classified-family-engine:hover {
  773. border: 2px solid #CCC !important;
  774. }
  775. .qs-main-classified-family-engine-icon {
  776. all: initial !important;
  777. display: inline-block !important;
  778. vertical-align: middle !important;
  779. width: 16px !important;
  780. height: 16px !important;
  781. margin: 0px 3px 0px 2px !important;
  782. border: 0px !important;
  783. cursor: pointer !important;
  784. }
  785. .qs-main-classified-family-engine-name {
  786. all: initial !important;
  787. display: inline-block !important;
  788. vertical-align: middle !important;
  789. margin-right: 2px !important;
  790. font-size: 13px !important;
  791. font-family: arial,sans-serif !important;
  792. font-weight: 400 !important;
  793. color: #5F5F5F !important;
  794. border: 0px !important;
  795. cursor: pointer !important;
  796. }
  797. .qs-main-help-info-box {
  798. all: initial !important;
  799. display: block !important;
  800. text-align: center !important;
  801. width: 100% !important;
  802. margin: 5px 0px !important;
  803. border: 0px !important;
  804. }
  805. .qs-main-help-info-item {
  806. all: initial !important;
  807. margin: 0px 10px !important;
  808. font-size: 8px !important;
  809. color: #DDD !important;
  810. cursor: pointer !important;
  811. text-decoration: none !important;
  812. }
  813. .qs-main-help-info-item:hover {
  814. color: #4E71F2 !important;
  815. }
  816.  
  817. /* 设置窗口 */
  818. .qs-setting-box {
  819. all: initial !important;
  820. position: fixed !important;
  821. display: block !important;
  822. left: 50% !important;
  823. top: 50% !important;
  824. transform: translate(-50%, -50%) !important;
  825. width: fit-content !important;
  826. height: fit-content !important;
  827. padding: 10px !important;
  828. border: 1px solid #F5F5F5 !important;
  829. box-shadow: 0px 0px 6px #BBB !important;
  830. border-radius: 10px !important;
  831. background-color: #FFF !important;
  832. opacity: 1 !important;
  833. z-index: 40000 !important;
  834. }
  835. .qs-setting-config-textarea {
  836. all: initial !important;
  837. display: block !important;
  838. width: 800px !important;
  839. height: 650px !important;
  840. padding: 5px !important;
  841. white-space: pre !important;
  842. overflow-wrap: normal !important;
  843. font: 400 13.3333px Arial !important;
  844. border: 1px solid #CCC !important;
  845. border-radius: 5px !important;
  846. }
  847. .qs-setting-config-textarea:focus {
  848. border-color: #4E71F2 !important;
  849. }
  850. .qs-setting-button-bar {
  851. all: initial !important;
  852. display: block !important;
  853. width: 100% !important;
  854. text-align: right !important;
  855. border: 0px !important;
  856. }
  857. .qs-setting-button {
  858. all: initial !important;
  859. display: inline-block !important;
  860. width: 60px !important;
  861. margin: 10px 0px 5px 20px !important;
  862. font-size: 13px !important;
  863. color: #555 !important;
  864. border: 0px !important;
  865. cursor: pointer !important;
  866. }
  867. .qs-setting-button:hover {
  868. color: #4E71F2 !important;
  869. }
  870.  
  871. /* 信息提示浮层 */
  872. .qs-info-tips-layer {
  873. all: initial !important;
  874. position: fixed !important;
  875. display: block !important;
  876. overflow: hidden !important;
  877. bottom: 30px !important;
  878. right: 30px !important;
  879. width: fit-content !important;
  880. height: fit-content !important;
  881. padding: 10px !important;
  882. font-size: 13px !important;
  883. color: #FFF !important;
  884. border: 0px !important;
  885. border-radius: 3px !important;
  886. background-color: rgba(0,0,0,0.7) !important;
  887. z-index: 50000 !important;
  888. }
  889.  
  890. /* 搜索建议浮层 */
  891. .qs-suggestions-layer {
  892. all: initial !important;
  893. position: fixed !important;
  894. display: block !important;
  895. overflow: hidden !important;
  896. height: fit-content !important;
  897. border: 1px solid #F5F5F5 !important;
  898. z-index: 30001 !important;
  899. }
  900. .qs-suggestion-item, .qs-suggestion-item-selected {
  901. all: initial !important;
  902. display: block !important;
  903. text-align: left !important;
  904. vertical-align: middle !important;
  905. width: 100% !important;
  906. height: 33px !important;
  907. line-height: 33px !important;
  908. padding-left: 13px !important;
  909. font-size: 15px !important;
  910. font-family: arial,sans-serif !important;
  911. font-weight: 400 !important;
  912. color: #555 !important;
  913. border: 0px !important;
  914. background-color: rgba(255,255,255,0.9) !important;
  915. }
  916. .qs-suggestion-item-selected {
  917. background-color: rgba(230,230,230,0.9) !important;
  918. }
  919. .qs-suggestion-item:hover {
  920. cursor: pointer !important;
  921. background-color: rgba(230,230,230,0.9) !important;
  922. }
  923. `;
  924.  
  925. ///////////////////////////////////////////////////////////////////
  926. // 全局变量
  927. ///////////////////////////////////////////////////////////////////
  928.  
  929. var conf = GM_getValue('qs-conf', defaultConf);
  930.  
  931. var hotkey2Engine = {}; // 自定义快捷键搜索的hotkey到engine的映射表
  932.  
  933. var qsPageLock = false; // 是否在当前页面锁定快搜所有功能, 锁定之后仅响应解锁快捷键
  934.  
  935. var qsToolbar = null; // 快搜划词工具条
  936. var qsBackgroundLayer = null; // 快搜主窗口背景层
  937. var qsMainBox = null; // 快搜主窗口
  938. var qsSearchInput = null; // 快搜主窗口搜索框
  939. var qsSettingBox = null; // 快搜设置窗口
  940. var qsConfigTextarea = null; // 快搜设置窗口配置框
  941. var qsInfoTipsLayer = null; // 快搜信息提示浮层
  942. var qsSuggestionsLayer = null; // 快搜搜索建议浮层
  943. var qsSuggestionItems = []; // 快搜搜索建议所有item元素(不一定都显示)
  944.  
  945. ///////////////////////////////////////////////////////////////////
  946. // 版本升级更新配置
  947. ///////////////////////////////////////////////////////////////////
  948.  
  949. //
  950. // for 1.1 -> 1.2
  951. //
  952. if (!conf.engineSuggestions) {
  953. conf.engineSuggestions = defaultConf.engineSuggestions;
  954. GM_setValue('qs-conf', conf);
  955. }
  956.  
  957. ///////////////////////////////////////////////////////////////////
  958. // 功能函数
  959. ///////////////////////////////////////////////////////////////////
  960.  
  961. // 获取元素style属性, 包括css中的
  962. function getStyleByElement(e, styleProp) {
  963. if (window.getComputedStyle) {
  964. return document.defaultView.getComputedStyle(e, null).getPropertyValue(styleProp);
  965. } else if (e.currentStyle) {
  966. return e.currentStyle[styleProp];
  967. }
  968. }
  969.  
  970. // 计算元素在文档(页面)中的绝对位置
  971. function getElementPosition(e) {
  972. return {
  973. top: e.getBoundingClientRect().top + window.scrollY, // 元素顶部相对于文档顶部距离
  974. bottom: e.getBoundingClientRect().bottom + window.scrollY, // 元素底部相对于文档顶部距离
  975. left: e.getBoundingClientRect().left + window.scrollX, // 元素左边相对于文档左侧距离
  976. right: e.getBoundingClientRect().right + window.scrollX // 元素右边相对于文档左侧距离
  977. };
  978. }
  979.  
  980. // 获取可视窗口在文档(页面)中的绝对位置
  981. function getWindowPosition() {
  982. return {
  983. top: window.scrollY,
  984. bottom: window.scrollY + window.innerHeight,
  985. left: window.scrollX,
  986. right: window.scrollX + window.innerWidth
  987. };
  988. }
  989.  
  990. // 判断元素在文档(页面)中是否可见
  991. function isVisualOnPage(ele) {
  992. if (getStyleByElement(ele, 'display') == 'none'
  993. || getStyleByElement(ele, 'visibility') == 'hidden'
  994. || getStyleByElement(ele, 'opacity') == '0') {
  995. return false;
  996. }
  997. if (getStyleByElement(ele, 'position') != 'fixed'
  998. && ele.offsetParent == null) {
  999. return false;
  1000. }
  1001. var elePos = getElementPosition(ele);
  1002. if (elePos.bottom - elePos.top == 0 || elePos.right - elePos.left == 0
  1003. || elePos.bottom <= 0 || elePos.right <= 0) {
  1004. return false;
  1005. }
  1006. return true;
  1007. }
  1008.  
  1009. // 获取选中文本
  1010. function getSelection() {
  1011. return window.getSelection().toString().trim();
  1012. }
  1013.  
  1014. // 获取当前页面匹配的 搜索引擎 及 其在同类别的搜索引擎列表中的索引 及 同类别的搜索引擎列表.
  1015. //
  1016. // TODO 目前只是简单地匹配域名, 待完善.
  1017. function getMatchedEngineInfo() {
  1018. var hostname = window.location.hostname;
  1019. hostname = hostname.replace(/^(www\.)/, '');
  1020.  
  1021. // 因为想要在循环中返回最终结果, 因此不能使用forEach语法
  1022. for (var classEngines of conf.classifiedEngines) {
  1023. for (var i = 0; i < classEngines.engines.length; i++) {
  1024. var engine = classEngines.engines[i];
  1025. var engineHostname = new URL(engine.url).hostname;
  1026. engineHostname = engineHostname.replace(/^(www\.)/, '');
  1027. if (hostname == engineHostname) {
  1028. return {
  1029. engine: engine,
  1030. index: i,
  1031. classEngines: classEngines
  1032. };
  1033. }
  1034. }
  1035. }
  1036.  
  1037. return null;
  1038. }
  1039.  
  1040. // 获取搜索引擎url中query的key
  1041. function getUrlQueryKey(engine) {
  1042. var params = new URL(engine.url).searchParams;
  1043. for (var param of params) {
  1044. if (param[1].includes('%s')) {
  1045. return param[0];
  1046. }
  1047. }
  1048. return null;
  1049. }
  1050.  
  1051. // 移除url中的domain(protocol+host)
  1052. function removeUrlDomain(url) {
  1053. var u = new URL(url);
  1054. var domain = `${u.protocol}//${u.host}`;
  1055. return url.substring(domain.length);
  1056. }
  1057.  
  1058. // 获取当前页面url中的搜索词.
  1059. // 返回值为经过URI解码的明文文本.
  1060. //
  1061. // 如果当前页面在配置的搜索引擎列表中, 尝试从url中解析参数, 分为engine.url中含有问号(?)和不含问号(?)两种情况.
  1062. // 如果没有解析到或者当前页面不在配置的搜索引擎列表中, 尝试获取文本(纯数字除外)在url中完整出现的input/textarea的值.
  1063. // 如果还是没有, 则认为当前页面url中没有搜索词.
  1064. function getUrlQuery() {
  1065.  
  1066. var urlTail = removeUrlDomain(window.location.href);
  1067. var engineInfo = getMatchedEngineInfo();
  1068. var engine = engineInfo ? engineInfo.engine : null;
  1069.  
  1070. // 尝试利用配置的搜索引擎信息从url中获取搜索词
  1071. if (engine && engine.url.includes('%s')) {
  1072. if (engine.url.includes('?')) { // engine.url中含有问号(?)
  1073. var queryKey = getUrlQueryKey(engine);
  1074. var params = new URLSearchParams(window.location.search);
  1075. var query = params.get(queryKey);
  1076. if (query) {
  1077. console.log(`Quick Search: get query by URL-KV, engine is ${engine.url}`);
  1078. return query; // URLSearchParams已经decode过了
  1079. }
  1080. } else { // engine.url中没有问号(?)
  1081. var parts = removeUrlDomain(engine.url).split('%s');
  1082. if (parts.length == 2 && urlTail.startsWith(parts[0]) && urlTail.endsWith(parts[1])) {
  1083. var query = urlTail.substring(parts[0].length, urlTail.length - parts[1].length);
  1084. var index = query.search(/[\/\?\=\&\#]/); // 是否含有 / ? = & #
  1085. if (index != -1) {
  1086. query = query.substring(0, index);
  1087. }
  1088. if (query) {
  1089. console.log(`Quick Search: get query by URL-PART, engine is ${engine.url}`);
  1090. return decodeURIComponent(query);
  1091. }
  1092. }
  1093. }
  1094. }
  1095.  
  1096. // 尝试获取文本(纯数字除外)在url中完整出现的input/textarea的值
  1097. var eles = document.querySelectorAll('input, textarea');
  1098. for (var ele of eles) {
  1099. if (isVisualOnPage(ele) && !qsMainBox.contains(ele) && !qsSettingBox.contains(ele)) {
  1100. var eleValue = ele.value.trim();
  1101. if (eleValue && !/^\d+$/.test(eleValue)) {
  1102. var encodedEleValue = encodeURIComponent(eleValue);
  1103. var index = urlTail.indexOf(encodedEleValue);
  1104. if (index != -1) {
  1105. var leftChar = urlTail[index - 1];
  1106. var rightChar = urlTail[index + encodedEleValue.length];
  1107. if ((!leftChar || /[\/\=\#]/.test(leftChar))
  1108. && (!rightChar || /[\/\?\&\#]/.test(rightChar))) {
  1109. console.log(`Quick Search: get query by ${ele.tagName}[id='${ele.id}'], engine is ${engine ? engine.url : 'NULL'}`);
  1110. return eleValue;
  1111. }
  1112. }
  1113. }
  1114. }
  1115. }
  1116.  
  1117. console.log(`Quick Search: query is NULL, engine is ${engine ? engine.url : 'NULL'}`);
  1118. return null;
  1119. }
  1120.  
  1121. // 判断是否允许工具条
  1122. function isAllowToolbar(event) {
  1123. var target = event.target;
  1124. if (!conf.showToolbar || qsPageLock) {
  1125. return false;
  1126. }
  1127. if (!conf.enableOnInput && (target.tagName == 'INPUT' || target.tagName == 'TEXTAREA')) {
  1128. return false;
  1129. }
  1130. if (qsMainBox && qsMainBox.contains(target)
  1131. || qsSettingBox && qsSettingBox.contains(target)) {
  1132. return false;
  1133. }
  1134. return true;
  1135. }
  1136.  
  1137. // 判断是否允许响应当前按键
  1138. // 默认只响应: 单字符的Escape / Alt+单字符 / Cmd/Ctrl+Alt+单字符
  1139. function isAllowHotkey(event) {
  1140. var target = event.target;
  1141. if (!qsPageLock && event.code == 'Escape') {
  1142. return true;
  1143. }
  1144. if (!event.altKey) {
  1145. return false;
  1146. }
  1147. if (event.shiftKey) {
  1148. return false;
  1149. }
  1150. if (qsPageLock && event.code != 'KeyL') {
  1151. return false;
  1152. }
  1153. if ((target.tagName == 'INPUT' || target.tagName == 'TEXTAREA') && !conf.enableOnInput) {
  1154. return false;
  1155. }
  1156. if (qsSettingBox && qsSettingBox.contains(target)) {
  1157. return false;
  1158. }
  1159. return true;
  1160. }
  1161.  
  1162. // 获取搜索引擎主页url
  1163. function getEngineHome(engine) {
  1164. if (engine.home) {
  1165. return engine.home;
  1166. } else {
  1167. var url = new URL(engine.url);
  1168. return `${url.protocol}//${url.hostname}/`;
  1169. }
  1170. }
  1171.  
  1172. // 获取直达的网址. 网址优先级: 搜索框已有网址(若快搜主窗口可见) > 网页中选中网址
  1173. // 返回 网址 及 网址来源
  1174. function getUrl() {
  1175. var url, source;
  1176.  
  1177. if (isMainBoxVisual()) {
  1178. url = qsSearchInput.value.trim();
  1179. source = 'mainbox';
  1180. } else {
  1181. url = getSelection();
  1182. source = 'selection';
  1183. }
  1184.  
  1185. // 补全网址
  1186. if (url && !url.includes('://')) {
  1187. var dotCount = (url.match(/\./g) || []).length;
  1188. if (dotCount == 0) {
  1189. url = 'www.' + url + '.com';
  1190. } else if (dotCount == 1) {
  1191. url = 'www.' + url;
  1192. }
  1193. url = 'http://' + url;
  1194. }
  1195.  
  1196. if (!url) {
  1197. source = null;
  1198. }
  1199. return {
  1200. url: url,
  1201. source: source
  1202. };
  1203. }
  1204.  
  1205. // 获取搜索词. 文本优先级: 搜索框已有文本(若快搜主窗口可见) > 网页中选中文本 > 当前页面搜索词
  1206. // 返回 搜索词 及 搜索词来源
  1207. function getQuery() {
  1208. var query, source;
  1209.  
  1210. if (isMainBoxVisual()) {
  1211. query = qsSearchInput.value.trim();
  1212. source = 'mainbox';
  1213. } else {
  1214. query = getSelection();
  1215. source = 'selection';
  1216. if (!query) {
  1217. query = getUrlQuery();
  1218. source = 'url';
  1219. }
  1220. }
  1221.  
  1222. if (!query) {
  1223. source = null;
  1224. }
  1225. return {
  1226. query: query,
  1227. source: source
  1228. };
  1229. }
  1230.  
  1231. // 打开url.
  1232. // 当按下Cmd(Mac系统)/Ctrl(Windows/Linux系统), 则后台打开url.
  1233. function openUrl(url, event) {
  1234. // console.log(`Quick Search: open url, url is ${url}`);
  1235. if (!url) return;
  1236. if (event.metaKey || event.ctrlKey) {
  1237. GM_openInTab(url, true);
  1238. } else {
  1239. GM_openInTab(url, false);
  1240. }
  1241. }
  1242.  
  1243. // 打开engine搜索结果或engine主页.
  1244. function openEngine(engine, query, event) {
  1245. // console.log(`Quick Search: open engine, engine is ${engine.url}, query is ${query}`);
  1246. if (!engine) return;
  1247. if (query) {
  1248. var url = engine.url.replace('%s', encodeURIComponent(query));
  1249. openUrl(url, event);
  1250. } else {
  1251. openUrl(getEngineHome(engine), event);
  1252. }
  1253. }
  1254.  
  1255. // 快捷键搜索.
  1256. // 同样, 当query为空时打开引擎主页, 否则正常搜索.
  1257. function openEngineOnKey(engine, query, event) {
  1258. openEngine(engine, query, event);
  1259. }
  1260.  
  1261. // 点击搜索引擎.
  1262. // 当按下Alt, 则忽略查询词打开引擎主页, 否则正常搜索.
  1263. function openEngineOnClick(engine, query, event) {
  1264. if (event.altKey) {
  1265. openEngine(engine, null, event);
  1266. } else {
  1267. openEngine(engine, query, event);
  1268. }
  1269. }
  1270.  
  1271. // 点击划词工具条搜索引擎.
  1272. function openEngineOnClickToolbar(engine, event) {
  1273. var query = getSelection();
  1274. openEngineOnClick(engine, query, event);
  1275. }
  1276.  
  1277. // 点击快搜主窗口搜索引擎.
  1278. function openEngineOnClickMainBox(engine, event) {
  1279. var query = qsSearchInput.value.trim();
  1280. openEngineOnClick(engine, query, event);
  1281. }
  1282.  
  1283. // 切换快搜page lock状态
  1284. function toggleQuickSearchPageLock() {
  1285. qsPageLock = qsPageLock ? false : true;
  1286. if (qsPageLock) {
  1287. hideToolbar();
  1288. hideMainBox();
  1289. showInfoTipsLayer('已禁用(🔒)');
  1290. } else {
  1291. showInfoTipsLayer('已启用(🚀)');
  1292. }
  1293. }
  1294.  
  1295. ///////////////////////////////////////////////////////////////////
  1296. // 元素创建 与 元素事件响应
  1297. ///////////////////////////////////////////////////////////////////
  1298.  
  1299. // 加载css样式
  1300. function loadSheet() {
  1301. var css = document.createElement('style');
  1302. css.type = 'text/css';
  1303. css.id = 'qs-css';
  1304. css.textContent = sheet;
  1305. document.getElementsByTagName('head')[0].appendChild(css);
  1306. }
  1307.  
  1308. // 初始化热键映射表
  1309. function initHotkeyEngineMapping() {
  1310. conf.hotkeyEngines.forEach(engine => {
  1311. if (!engine.enable) return; // 此处return搭配forEach, 请勿改为其他形式循环
  1312. engine.hotkeys.forEach(key => {
  1313. hotkey2Engine[key] = engine;
  1314. });
  1315. });
  1316. }
  1317.  
  1318. //
  1319. // 划词工具条
  1320. //
  1321.  
  1322. // 创建划词工具条
  1323. function createToolbar() {
  1324. // 工具条container
  1325. var toolbar = document.createElement('div');
  1326. toolbar.id = 'qs-toolbar';
  1327. toolbar.className = 'qs-toolbar';
  1328. toolbar.style.setProperty('display', 'none', 'important');
  1329. document.body.appendChild(toolbar);
  1330.  
  1331. // 常用搜索引擎按钮
  1332. conf.frequentEngines.forEach((engine, index) => {
  1333. if (!engine.enable) return; // 此处return搭配forEach, 请勿改为其他形式循环
  1334. var icon = document.createElement('img');
  1335. icon.id = 'qs-toolbar-icon-' + index;
  1336. icon.className = 'qs-toolbar-icon';
  1337. icon.src = engine.icon;
  1338. icon.addEventListener('click', function (e) {
  1339. openEngineOnClickToolbar(engine, e);
  1340. }, false);
  1341. toolbar.appendChild(icon);
  1342. });
  1343.  
  1344. // 直达网址按钮
  1345. var icon = document.createElement('img');
  1346. icon.id = 'qs-toolbar-icon-url';
  1347. icon.className = 'qs-toolbar-icon';
  1348. icon.src = 'data:image/x-icon;base64,AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFxcXABcXFwAXFxcAFxcXE1cXFzIXFxc81xcXN1cXFx0XFxcCVxcXABcXFwAXFxcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABcXFwAXFxcAFxcXABcXFxXXFxc51xcXMpcXFyLXFxcsVxcXPFcXFyHXFxcCFxcXABcXFwAXFxcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXFxcAFxcXABcXFwAXFxcWFxcXOxcXFytXFxcGlxcXABcXFwIXFxcfVxcXPRcXFyJXFxcCFxcXABcXFwAXFxcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABcXFwAXFxcAFxcXFhcXFzsXFxcrVxcXBZcXFwAXFxcAFxcXABcXFwFXFxcfFxcXPRcXFyJXFxcCFxcXABcXFwAXFxcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFxcXABcXFxXXFxc7FxcXK1cXFwWXFxcAFxcXABcXFwAXFxcAFxcXABcXFwFXFxcfFxcXPRcXFyJXFxcCFxcXABcXFwAXFxcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXFxcUVxcXOhcXFytXFxcFlxcXABcXFwAXFxcAFxcXABcXFwAXFxcAFxcXABcXFwFXFxcfFxcXPRcXFyJXFxcCFxcXABcXFwAXFxcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABcXFzQXFxcxlxcXBlcXFwAXFxcAFxcXABcXFwCXFxcFVxcXARcXFwAXFxcAFxcXABcXFwFXFxce1xcXPRcXFyKXFxcCFxcXABcXFwAXFxcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFxcXPtcXFyAXFxcAFxcXABcXFwAXFxcAFxcXBpcXFzAXFxcelxcXAVcXFwAXFxcAFxcXABcXFwFXFxce1xcXPRcXFyKXFxcCVxcXABcXFwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXFxc6lxcXKNcXFwDXFxcAFxcXABcXFwAXFxcB1xcXIpcXFz0XFxce1xcXARcXFwAXFxcAFxcXABcXFwFXFxce1xcXPRcXFx9XFxcAlxcXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABcXFyGXFxc8VxcXGxcXFwBXFxcAFxcXABcXFwAXFxcCVxcXIpcXFz0XFxce1xcXARcXFwAXFxcAFxcXABcXFwEXFxcj1xcXOZcXFwpXFxcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFxcXA9cXFyYXFxc8lxcXGxcXFwCXFxcAFxcXABcXFwAXFxcCFxcXIpcXFz0XFxce1xcXAVcXFwAXFxcAFxcXABcXFw8XFxc8FxcXE1cXFwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXFxcAFxcXA1cXFyZXFxc8lxcXGxcXFwCXFxcAFxcXABcXFwAXFxcCFxcXIpcXFz0XFxce1xcXAVcXFwAXFxcAFxcXF1cXFzwXFxcPVxcXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABcXFwAXFxcAFxcXA5cXFyZXFxc8lxcXGxcXFwCXFxcAFxcXABcXFwAXFxcCFxcXIpcXFz0XFxce1xcXARcXFwOXFxcxVxcXLlcXFwOXFxcAFxcXABcXFwAXFxcAFxcXABcXFwAXFxcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFxcXABcXFwAXFxcAFxcXA1cXFyZXFxc8lxcXGxcXFwCXFxcAFxcXABcXFwAXFxcCFxcXIpcXFz0XFxce1xcXAtcXFxRXFxcKVxc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XG5cXFwCXFxcAFxcXABcXFwAXFxcAFxcXABcXFwXXFxcrlxcXOxcXFxXXFxcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFxcXABcXFwAXFxcAFxcXA1cXFyXXFxc8lxcXG5cXFwCXFxcAFxcXABcXFwAXFxcF1xcXK5cXFzsXFxcV1xcXABcXFwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFxcXABcXFwAXFxcAFxcXA1cXFyXXFxc8lxcXG9cXFwEXFxcAFxcXBlcXFyuXFxc61xcXFdcXFwAXFxcAFxcXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFxcXABcXFwAXFxcAFxcXA1cXFyVXFxc8VxcXKZcXFyCXFxcyFxcXOhcXFxWXFxcAFxcXABcXFwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFxcXABcXFwAXFxcAFxcXA5cXFyDXFxc51xcXPlcXFzNXFxcT1xcXABcXFwAXFxcAAAAAAAAAAAAwAP//4AB//8AAP//AAB//wAAP/8AAB//AAAP/wAAD/8AAA//AAAP/wAAD/8AAA//AAAAPwAAAB+AAAAPwAAAB+AAAAPwAAAB+AAAAPwAAAD/8AAA//AAAP/wAAD/8AAA//AAAP/wAAD/+AAA//wAAP/+AAD//wAA//+AAf//wAM=';
  1349. icon.addEventListener('click', function (e) {
  1350. openUrl(getUrl().url, e);
  1351. }, false);
  1352. toolbar.appendChild(icon);
  1353.  
  1354. // 更多按钮
  1355. var icon = document.createElement('img');
  1356. icon.id = 'qs-toolbar-icon-more';
  1357. icon.className = 'qs-toolbar-icon';
  1358. icon.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAMAAADDpiTIAAABYmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS40LjAiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgIHRpZmY6T3JpZW50YXRpb249IjYiLz4KIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+Cjw/eHBhY2tldCBlbmQ9InIiPz7UGE7IAAACClBMVEX///9VYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBVYIBzg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79zg79VYIBzg79VYIBzg79zg79VYIBzg79zg79zg79VYIBVYIBVYIBzg79VYIBVYIBzg79VYIBVYIBzg79z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';
  1359. icon.addEventListener('click', function (e) {
  1360. showMainBox();
  1361. hideToolbar();
  1362. }, false);
  1363. toolbar.appendChild(icon);
  1364.  
  1365. qsToolbar = toolbar;
  1366. }
  1367.  
  1368. // 划词工具条是否处于显示状态
  1369. function isToolbarVisual() {
  1370. return qsToolbar && qsToolbar.style.display == 'block';
  1371. }
  1372.  
  1373. // 显示划词工具条
  1374. function showToolbar(event) {
  1375.  
  1376. ensureQuickSearchAlive();
  1377.  
  1378. if (!qsToolbar || isToolbarVisual()) {
  1379. return;
  1380. }
  1381.  
  1382. var toolbar = qsToolbar;
  1383.  
  1384. toolbar.style.setProperty('top', '-10000px', 'important');
  1385. toolbar.style.setProperty('left', '-10000px', 'important');
  1386. toolbar.style.setProperty('display', 'block', 'important');
  1387.  
  1388. var toolbarClientRect = toolbar.getBoundingClientRect();
  1389. var toolbarWidth = toolbarClientRect.right - toolbarClientRect.left;
  1390. var toolbarHeight = toolbarClientRect.bottom - toolbarClientRect.top;
  1391.  
  1392. var toolbarNewTop = event.pageY + 15;
  1393. var toolbarNewLeft = event.pageX - (toolbarWidth / 2);
  1394. var windowPos = getWindowPosition();
  1395. if (toolbarNewTop + toolbarHeight > windowPos.bottom) {
  1396. toolbarNewTop = event.pageY - toolbarHeight - 15;
  1397. }
  1398. if (toolbarNewLeft < windowPos.left) {
  1399. toolbarNewLeft = windowPos.left;
  1400. } else if (toolbarNewLeft + toolbarWidth > windowPos.right) {
  1401. toolbarNewLeft = windowPos.right - toolbarWidth;
  1402. }
  1403.  
  1404. toolbar.style.setProperty('top', toolbarNewTop + 'px', 'important');
  1405. toolbar.style.setProperty('left', toolbarNewLeft + 'px', 'important');
  1406. }
  1407.  
  1408. // 隐藏划词工具条
  1409. function hideToolbar() {
  1410. if (qsToolbar) {
  1411. qsToolbar.style.setProperty('display', 'none', 'important');
  1412. }
  1413. }
  1414.  
  1415. //
  1416. // 快搜主窗口
  1417. //
  1418.  
  1419. // 创建快搜主窗口
  1420. function createMainBox() {
  1421. // 快搜主窗口背景层
  1422. //
  1423. // 随快搜主窗口一同显示/隐藏, 铺满整个可视窗口. 其作用主要是:
  1424. // 1. 想要实现点击快搜主窗口外面就隐藏快搜主窗口, 但如果点击target是页面中的cross-domain iframe的话,
  1425. // 当前window就不能捕获到该iframe的click事件, 所以覆盖一层作为以便捕获点击事件.
  1426. // 2. 也可以做背景虚化/遮罩效果.
  1427. var backgroundLayer = document.createElement('div');
  1428. backgroundLayer.id = 'qs-main-background-layer';
  1429. backgroundLayer.className = 'qs-main-background-layer';
  1430. backgroundLayer.style.setProperty('display', 'none', 'important');
  1431. document.body.appendChild(backgroundLayer);
  1432.  
  1433. // 快搜主窗口container
  1434. var mainBox = document.createElement('div');
  1435. mainBox.id = 'qs-mainbox';
  1436. mainBox.className = 'qs-mainbox';
  1437. mainBox.style.setProperty('display', 'none', 'important');
  1438. document.body.appendChild(mainBox);
  1439.  
  1440. // 搜索框
  1441. var searchBox = document.createElement('div');
  1442. searchBox.id = 'qs-main-search-box';
  1443. searchBox.className = 'qs-main-search-box';
  1444. mainBox.appendChild(searchBox);
  1445. var searchInput = document.createElement('input');
  1446. searchInput.id = 'qs-main-search-input';
  1447. searchInput.className = 'qs-main-search-input';
  1448. searchInput.addEventListener('keydown', function (e) {
  1449. if (e.code == 'Enter') { // 回车键
  1450. openEngineOnClickMainBox(conf.defaultEngine, e);
  1451. }
  1452. }, false);
  1453. if (conf.showPlaceholder) {
  1454. searchInput.placeholder = `回车以使用${conf.defaultEngine.name}搜索`;
  1455. }
  1456. searchBox.appendChild(searchInput);
  1457.  
  1458. // 常用搜索引擎
  1459. if (conf.showFrequentEngines) {
  1460. var frequentBox = document.createElement('div');
  1461. frequentBox.id = 'qs-main-frequent-box';
  1462. frequentBox.className = 'qs-main-frequent-box';
  1463. mainBox.appendChild(frequentBox);
  1464. conf.frequentEngines.forEach((engine, index) => {
  1465. if (!engine.enable) return; // 此处return搭配forEach, 请勿改为其他形式循环
  1466. var icon = document.createElement('img');
  1467. icon.id = 'qs-main-frequent-icon-' + index;
  1468. icon.className = 'qs-main-frequent-icon';
  1469. icon.src = engine.icon;
  1470. icon.addEventListener('click', function (e) {
  1471. openEngineOnClickMainBox(engine, e);
  1472. }, false);
  1473. frequentBox.appendChild(icon);
  1474. });
  1475. }
  1476.  
  1477. // 分类搜索引擎
  1478. if (conf.showClassifiedEngines) {
  1479. var classifiedBox = document.createElement('div');
  1480. classifiedBox.id = 'qs-main-classified-box';
  1481. classifiedBox.className = 'qs-main-classified-box';
  1482. mainBox.appendChild(classifiedBox);
  1483. conf.classifiedEngines.forEach((family, fIndex) => {
  1484. if (!family.enable) return; // 此处return搭配forEach, 请勿改为其他形式循环
  1485. // 一个分类一列
  1486. var familyBox = document.createElement('div');
  1487. familyBox.id = 'qs-main-classified-family-box-' + fIndex;
  1488. familyBox.className = 'qs-main-classified-family-box';
  1489. classifiedBox.appendChild(familyBox);
  1490. // 分类标题
  1491. var familyTitle = document.createElement('div');
  1492. familyTitle.id = 'qs-main-classified-family-title-' + fIndex;
  1493. familyTitle.className = 'qs-main-classified-family-title';
  1494. familyTitle.textContent = family.name;
  1495. familyBox.appendChild(familyTitle);
  1496. family.engines.forEach((engine, eIndex) => {
  1497. if (!engine.enable) return; // 此处return搭配forEach, 请勿改为其他形式循环
  1498. // 搜索引擎
  1499. var engineBox = document.createElement('div');
  1500. engineBox.id = 'qs-main-classified-family-engine-' + fIndex + '-' + eIndex;
  1501. engineBox.className = 'qs-main-classified-family-engine';
  1502. engineBox.addEventListener('click', function (e) {
  1503. openEngineOnClickMainBox(engine, e);
  1504. }, false);
  1505. familyBox.appendChild(engineBox);
  1506. // 搜索引擎icon
  1507. var engineIcon = document.createElement('img');
  1508. engineIcon.id = 'qs-main-classified-family-engine-icon-' + fIndex + '-' + eIndex;
  1509. engineIcon.className = 'qs-main-classified-family-engine-icon';
  1510. engineIcon.src = engine.icon;
  1511. engineBox.appendChild(engineIcon);
  1512. // 搜索引擎name
  1513. var engineName = document.createElement('span');
  1514. engineName.id = 'qs-main-classified-family-engine-name-' + fIndex + '-' + eIndex;
  1515. engineName.className = 'qs-main-classified-family-engine-name';
  1516. engineName.textContent = engine.name;
  1517. engineBox.appendChild(engineName);
  1518. });
  1519. });
  1520. }
  1521.  
  1522. // 帮助信息
  1523. var helpInfoBox = document.createElement('div');
  1524. helpInfoBox.id = 'qs-main-help-info-box';
  1525. helpInfoBox.className = 'qs-main-help-info-box';
  1526. mainBox.appendChild(helpInfoBox);
  1527. // 主页
  1528. var homeLink = document.createElement('a');
  1529. homeLink.id = 'qs-main-help-info-home';
  1530. homeLink.className = 'qs-main-help-info-item';
  1531. homeLink.textContent = '主页';
  1532. homeLink.href = 'https://github.com/eyinwei/Quick_Search';
  1533. homeLink.target = '_blank';
  1534. helpInfoBox.appendChild(homeLink);
  1535. // 帮助
  1536. var helpLink = document.createElement('a');
  1537. helpLink.id = 'qs-main-help-info-help';
  1538. helpLink.className = 'qs-main-help-info-item';
  1539. helpLink.textContent = '帮助';
  1540. helpLink.href = 'https://github.com/eyinwei/Quick_Search/README.md';
  1541. helpLink.target = '_blank';
  1542. helpInfoBox.appendChild(helpLink);
  1543. // 设置
  1544. var settingLink = document.createElement('a');
  1545. settingLink.id = 'qs-main-help-info-setting';
  1546. settingLink.className = 'qs-main-help-info-item';
  1547. settingLink.textContent = '设置';
  1548. settingLink.onclick = function (e) {
  1549. showSettingBox();
  1550. };
  1551. helpInfoBox.appendChild(settingLink);
  1552.  
  1553. qsBackgroundLayer = backgroundLayer;
  1554. qsMainBox = mainBox;
  1555. qsSearchInput = searchInput;
  1556. }
  1557.  
  1558. // 快搜主窗口是否处于显示状态
  1559. function isMainBoxVisual() {
  1560. return qsMainBox.style.display == 'block';
  1561. }
  1562.  
  1563. // 显示快搜主窗口.
  1564. // 可选输入text为没有经过URI编码的明文文本, 该参数一般在iframe发来消息时使用.
  1565. // 快搜主窗口中搜索框的文本优先级: 参数指定文本 > 网页选中文本 > 搜索框已有文本 > 当前页面搜索词
  1566. function showMainBox(text) {
  1567.  
  1568. ensureQuickSearchAlive();
  1569.  
  1570. // 快搜主窗口在iframe中不显示
  1571. if (isMainBoxVisual() || window.self != window.top) {
  1572. return;
  1573. }
  1574.  
  1575. // 设置搜索框内容
  1576. var query = text;
  1577. if (!query) {
  1578. query = getSelection();
  1579. }
  1580. if (!query) {
  1581. query = qsSearchInput.value.trim();
  1582. }
  1583. if (!query) {
  1584. query = getUrlQuery();
  1585. }
  1586. qsSearchInput.value = query;
  1587.  
  1588. qsBackgroundLayer.style.setProperty('display', 'block', 'important');
  1589. qsMainBox.style.setProperty('display', 'block', 'important');
  1590.  
  1591. // 选中搜索框文本
  1592. qsSearchInput.select();
  1593.  
  1594. // 隐藏划词工具条
  1595. if (isToolbarVisual()) {
  1596. hideToolbar();
  1597. }
  1598. }
  1599.  
  1600. // 隐藏快搜主窗口
  1601. function hideMainBox() {
  1602. destroySuggestions();
  1603. qsBackgroundLayer.style.setProperty('display', 'none', 'important');
  1604. qsMainBox.style.setProperty('display', 'none', 'important');
  1605. }
  1606.  
  1607. //
  1608. // 设置窗口
  1609. //
  1610.  
  1611. // 创建设置窗口
  1612. function createSettingBox() {
  1613. // 设置窗口container
  1614. var settingBox = document.createElement('div');
  1615. settingBox.id = 'qs-setting-box';
  1616. settingBox.className = 'qs-setting-box';
  1617. settingBox.style.setProperty('display', 'none', 'important');
  1618. document.body.appendChild(settingBox);
  1619. // 配置文本框
  1620. var configTextarea = document.createElement('textarea');
  1621. configTextarea.id = 'qs-setting-config-textarea';
  1622. configTextarea.className = 'qs-setting-config-textarea';
  1623. settingBox.appendChild(configTextarea);
  1624. // 底部按钮container
  1625. var buttonBar = document.createElement('div');
  1626. buttonBar.id = 'qs-setting-button-bar';
  1627. buttonBar.className = 'qs-setting-button-bar';
  1628. settingBox.appendChild(buttonBar);
  1629. // 重置按钮
  1630. var resetButton = document.createElement('button');
  1631. resetButton.id = 'qs-setting-button-reset';
  1632. resetButton.className = 'qs-setting-button';
  1633. resetButton.type = 'button';
  1634. resetButton.textContent = '重置';
  1635. resetButton.onclick = function (e) {
  1636. configTextarea.value = JSON.stringify(defaultConf, null, 4);
  1637. }
  1638. buttonBar.appendChild(resetButton);
  1639. // 关闭按钮
  1640. var closeButton = document.createElement('button');
  1641. closeButton.id = 'qs-setting-button-close';
  1642. closeButton.className = 'qs-setting-button';
  1643. closeButton.type = 'button';
  1644. closeButton.textContent = '取消';
  1645. closeButton.onclick = function (e) {
  1646. hideSettingBox();
  1647. }
  1648. buttonBar.appendChild(closeButton);
  1649. // 保存按钮
  1650. var saveButton = document.createElement('button');
  1651. saveButton.id = 'qs-setting-button-save';
  1652. saveButton.className = 'qs-setting-button';
  1653. saveButton.type = 'button';
  1654. saveButton.textContent = '保存';
  1655. saveButton.onclick = function (e) {
  1656. var newConf = JSON.parse(configTextarea.value);
  1657. GM_setValue('qs-conf', newConf);
  1658. hideSettingBox();
  1659. // 需用户手动刷新页面重新加载配置使其生效
  1660. alert('设置已保存, 刷新页面后生效.');
  1661. }
  1662. buttonBar.appendChild(saveButton);
  1663.  
  1664. qsSettingBox = settingBox;
  1665. qsConfigTextarea = configTextarea;
  1666. }
  1667.  
  1668. // 设置窗口是否处于显示状态
  1669. function isSettingBoxVisual() {
  1670. return qsSettingBox.style.display == 'block';
  1671. }
  1672.  
  1673. // 显示设置窗口
  1674. function showSettingBox() {
  1675.  
  1676. ensureQuickSearchAlive();
  1677.  
  1678. if (isSettingBoxVisual()) {
  1679. return;
  1680. }
  1681.  
  1682. var confStr = JSON.stringify(conf, null, 4);
  1683. qsConfigTextarea.value = confStr;
  1684. qsSettingBox.style.setProperty('display', 'block', 'important');
  1685. }
  1686.  
  1687. // 隐藏设置窗口
  1688. function hideSettingBox() {
  1689. qsSettingBox.style.setProperty('display', 'none', 'important');
  1690. }
  1691.  
  1692. //
  1693. // 信息提示浮层
  1694. //
  1695.  
  1696. // 创建信息提示浮层
  1697. function createInfoTipsLayer() {
  1698. var infoTipsLayer = document.createElement('div');
  1699. infoTipsLayer.id = 'qs-info-tips-layer';
  1700. infoTipsLayer.className = 'qs-info-tips-layer';
  1701. infoTipsLayer.style.setProperty('display', 'none', 'important');
  1702. document.body.appendChild(infoTipsLayer);
  1703.  
  1704. qsInfoTipsLayer = infoTipsLayer;
  1705. }
  1706.  
  1707. // 显示信息提示浮层
  1708. var idOfSettimeout = null;
  1709. function showInfoTipsLayer(info) {
  1710. qsInfoTipsLayer.textContent = 'Quick Search: ' + info;
  1711. qsInfoTipsLayer.style.setProperty('display', 'block', 'important');
  1712. if (idOfSettimeout) {
  1713. clearTimeout(idOfSettimeout);
  1714. }
  1715. idOfSettimeout = setTimeout(function () {
  1716. qsInfoTipsLayer.style.setProperty('display', 'none', 'important');
  1717. }, 2000);
  1718. }
  1719.  
  1720. //
  1721. // 搜索建议
  1722. //
  1723.  
  1724. var rawInputQuery = null; // 输入框中的原始查询
  1725. var multiEngineSuggestions = []; // 多个搜索引擎的建议, 每个一个子数组
  1726. var suggestionCount = 0; // 多个搜索引擎的实际建议的总数
  1727. var selectedSuggestionIndex = -1; // 用户选中的搜索建议项对应的index
  1728.  
  1729. // 搜索建议最大条数, 用于事先创建好相应元素
  1730. function getMaxSuggestionCount() {
  1731. var count = 0;
  1732. conf.engineSuggestions.forEach(es => {
  1733. if (!es.enable) return;
  1734. count += es.showCount;
  1735. });
  1736. return count;
  1737. }
  1738.  
  1739. // 创建搜索建议浮层
  1740. function createSuggestionsLayer() {
  1741.  
  1742. var maxSuggestionCount = getMaxSuggestionCount();
  1743. if (maxSuggestionCount == 0) {
  1744. return;
  1745. }
  1746.  
  1747. // 搜索建议浮层
  1748. var suggestionsLayer = document.createElement('div');
  1749. suggestionsLayer.id = 'qs-suggestions-layer';
  1750. suggestionsLayer.className = 'qs-suggestions-layer';
  1751. suggestionsLayer.style.setProperty('display', 'none', 'important');
  1752. document.body.appendChild(suggestionsLayer);
  1753.  
  1754. // 搜索建议条目
  1755. for (var i = 0; i < maxSuggestionCount; i++) {
  1756. var suggestionItem = document.createElement('div');
  1757. suggestionItem.id = 'qs-suggestion-item-' + i;
  1758. suggestionItem.className = 'qs-suggestion-item';
  1759. suggestionItem.addEventListener('click', function (e) {
  1760. qsSearchInput.value = this.textContent;
  1761. openEngineOnClickMainBox(conf.defaultEngine, e);
  1762. }, true);
  1763. suggestionsLayer.appendChild(suggestionItem);
  1764.  
  1765. qsSuggestionItems.push(suggestionItem);
  1766. }
  1767.  
  1768. // 向搜索框添加响应函数
  1769. qsSearchInput.addEventListener('input', function (e) {
  1770. var query = qsSearchInput.value.trim();
  1771. if (query) {
  1772. triggerSuggestions(query);
  1773. } else {
  1774. destroySuggestions();
  1775. }
  1776. }, true);
  1777. qsSearchInput.addEventListener('mousedown', function (e) {
  1778. var query = qsSearchInput.value.trim();
  1779. if (query) {
  1780. triggerSuggestions(query);
  1781. }
  1782. }, true);
  1783. qsSearchInput.addEventListener('keydown', function (e) {
  1784. if (e.code == 'ArrowDown' && isSuggestionsLayerVisual()) {
  1785. e.preventDefault();
  1786. selectSuggestionItem(selectedSuggestionIndex + 1);
  1787. return;
  1788. }
  1789. if (e.code == 'ArrowUp' && isSuggestionsLayerVisual()) {
  1790. e.preventDefault();
  1791. selectSuggestionItem(selectedSuggestionIndex - 1);
  1792. return;
  1793. }
  1794. if (e.code == 'Tab' && isSuggestionsLayerVisual()) {
  1795. e.preventDefault();
  1796. if (e.shiftKey) {
  1797. selectSuggestionItem(selectedSuggestionIndex - 1);
  1798. } else {
  1799. selectSuggestionItem(selectedSuggestionIndex + 1);
  1800. }
  1801. return;
  1802. }
  1803. }, true);
  1804.  
  1805. qsSuggestionsLayer = suggestionsLayer;
  1806. }
  1807.  
  1808. // 判断搜索建议浮层是否显示
  1809. function isSuggestionsLayerVisual() {
  1810. return qsSuggestionsLayer && qsSuggestionsLayer.style.display == 'block';
  1811. }
  1812.  
  1813. // 显示搜索建议浮层
  1814. function _showSuggestionsLayer() {
  1815. if (!qsSuggestionsLayer || isSuggestionsLayerVisual()) {
  1816. return;
  1817. }
  1818.  
  1819. var inputPos = qsSearchInput.getBoundingClientRect();
  1820. var top = inputPos.bottom + 'px';
  1821. var left = inputPos.left + 'px';
  1822. var width = (inputPos.right - inputPos.left) + 'px';
  1823. qsSuggestionsLayer.style.setProperty('top', top, 'important');
  1824. qsSuggestionsLayer.style.setProperty('left', left, 'important');
  1825. qsSuggestionsLayer.style.setProperty('width', width, 'important');
  1826.  
  1827. qsSuggestionsLayer.style.setProperty('display', 'block', 'important');
  1828. }
  1829.  
  1830. // 隐藏搜索建议浮层
  1831. function _hideSuggestionsLayer() {
  1832. if (qsSuggestionsLayer) {
  1833. qsSuggestionsLayer.style.setProperty('display', 'none', 'important');
  1834. }
  1835. }
  1836.  
  1837. //
  1838. // 请求百度搜索建议
  1839. //
  1840. const baiduSuggestionUrl = {
  1841. 'http:': 'http://suggestion.baidu.com/su?wd=%s&cb=callback',
  1842. 'https:': 'https://suggestion.baidu.com/su?wd=%s&cb=callback',
  1843. }[window.location.protocol];
  1844.  
  1845. // 油猴脚本的GM_xmlhttpRequest可以直接跨域请求, 不受同源策略限制, 这样就不用通过jQuery来发送jsonp请求了.
  1846. function requestBaiduSuggestions(query, index, count) {
  1847.  
  1848. function callback(res) {
  1849. multiEngineSuggestions[index] = res.s.slice(0, count);
  1850. loadSuggestions();
  1851. }
  1852.  
  1853. var url = baiduSuggestionUrl.replace('%s', encodeURIComponent(query));
  1854. GM_xmlhttpRequest({
  1855. method: 'GET',
  1856. url: url,
  1857. timeout: 3000,
  1858. onload: response => {
  1859. if (response.status == 200) {
  1860. eval(response.responseText);
  1861. } else {
  1862. console.log(`Quick Search: Baidu Suggestions: code ${response.status}`);
  1863. }
  1864. }
  1865. });
  1866. }
  1867.  
  1868. //
  1869. // 请求Google搜索建议
  1870. //
  1871. const googleSuggestionUrl = {
  1872. 'http:': 'http://suggestqueries.google.com/complete/search?client=firefox&q=%s&jsonp=callback',
  1873. 'https:': 'https://suggestqueries.google.com/complete/search?client=firefox&q=%s&jsonp=callback',
  1874. }[window.location.protocol];
  1875.  
  1876. function requestGoogleSuggestions(query, index, count) {
  1877.  
  1878. function callback(res) {
  1879. multiEngineSuggestions[index] = res[1].slice(0, count);
  1880. loadSuggestions();
  1881. }
  1882.  
  1883. var url = googleSuggestionUrl.replace('%s', encodeURIComponent(query));
  1884. GM_xmlhttpRequest({
  1885. method: 'GET',
  1886. url: url,
  1887. timeout: 3000,
  1888. onload: response => {
  1889. if (response.status == 200) {
  1890. eval(response.responseText);
  1891. } else {
  1892. console.log(`Quick Search: Google Suggestions: code ${response.status}`);
  1893. }
  1894. }
  1895. });
  1896. }
  1897.  
  1898. var suggestionHandlers = {
  1899. 'baidu': requestBaiduSuggestions,
  1900. 'google': requestGoogleSuggestions,
  1901. }
  1902.  
  1903. // 选中搜索建议项
  1904. function selectSuggestionItem(newSelectedIndex) {
  1905. if (qsSuggestionItems[selectedSuggestionIndex]) {
  1906. qsSuggestionItems[selectedSuggestionIndex].className = 'qs-suggestion-item';
  1907. }
  1908. selectedSuggestionIndex = newSelectedIndex;
  1909. selectedSuggestionIndex = selectedSuggestionIndex < -1 ? suggestionCount - 1 : selectedSuggestionIndex;
  1910. selectedSuggestionIndex = selectedSuggestionIndex >= suggestionCount ? -1 : selectedSuggestionIndex;
  1911. if (selectedSuggestionIndex == -1) {
  1912. qsSearchInput.value = rawInputQuery;
  1913. } else {
  1914. qsSearchInput.value = qsSuggestionItems[selectedSuggestionIndex].textContent;
  1915. qsSuggestionItems[selectedSuggestionIndex].className = 'qs-suggestion-item-selected';
  1916. }
  1917. }
  1918.  
  1919. // 触发搜索建议
  1920. function triggerSuggestions(query) {
  1921. rawInputQuery = query;
  1922. if (selectedSuggestionIndex != -1) {
  1923. selectSuggestionItem(-1);
  1924. }
  1925.  
  1926. var index = 0;
  1927. conf.engineSuggestions.forEach(es => {
  1928. if (!es.enable) return;
  1929. suggestionHandlers[es.name](query, index, es.showCount);
  1930. index++;
  1931. })
  1932. }
  1933.  
  1934. // 装载搜索建议
  1935. function loadSuggestions() {
  1936. // 由于装载是异步延迟的, 若用户已经删光了输入框内容, 则不显示搜索建议
  1937. if (!qsSearchInput.value.trim()) {
  1938. destroySuggestions();
  1939. return;
  1940. }
  1941.  
  1942. // 多个搜索引擎的建议合并并去重
  1943. var allSuggestions = multiEngineSuggestions.flat(1).filter((x, i, a) => a.indexOf(x) == i);
  1944. suggestionCount = allSuggestions.length;
  1945.  
  1946. allSuggestions.forEach((suggestion, i) => {
  1947. qsSuggestionItems[i].textContent = suggestion;
  1948. qsSuggestionItems[i].style.setProperty('display', 'block', 'important');
  1949. });
  1950. for (var i = allSuggestions.length; i < qsSuggestionItems.length; i++) {
  1951. qsSuggestionItems[i].style.setProperty('display', 'none', 'important');
  1952. }
  1953. if (!isSuggestionsLayerVisual()) {
  1954. _showSuggestionsLayer();
  1955. }
  1956. }
  1957.  
  1958. // 销毁搜索建议
  1959. function destroySuggestions() {
  1960. _hideSuggestionsLayer();
  1961. rawInputQuery = null;
  1962. multiEngineSuggestions = [];
  1963. suggestionCount = 0;
  1964. selectedSuggestionIndex = -1;
  1965. }
  1966.  
  1967. //
  1968. // 创建以上所有东东
  1969. //
  1970.  
  1971. function initQuickSearch() {
  1972. loadSheet();
  1973. initHotkeyEngineMapping();
  1974. if (conf.showToolbar) {
  1975. createToolbar();
  1976. }
  1977. createMainBox();
  1978. createSettingBox();
  1979. createInfoTipsLayer();
  1980. createSuggestionsLayer();
  1981. }
  1982.  
  1983. // 百度等网页会在不刷新页面的情况下改变网页内容, 导致quick search除了js脚本之外的东东全部没了.
  1984. // 此函数用于确保quick search处于可用状态, 需在toolbar或mainbox等窗口每次显示时调用.
  1985. function ensureQuickSearchAlive() {
  1986. var css = document.querySelector('#qs-css');
  1987. var mainbox = document.querySelector('#qs-mainbox');
  1988. if (!css || !mainbox) {
  1989. initQuickSearch();
  1990. }
  1991. }
  1992.  
  1993. initQuickSearch();
  1994.  
  1995. ///////////////////////////////////////////////////////////////////
  1996. // 全局事件响应
  1997. //
  1998. // 我们将全局事件绑定在捕获阶段执行, 避免事件响应被网页自带的脚本拦截掉.
  1999. ///////////////////////////////////////////////////////////////////
  2000.  
  2001. //
  2002. // top window和iframe共用的事件处理逻辑
  2003. //
  2004.  
  2005. window.addEventListener('mousedown', function (e) {
  2006. var target = e.target;
  2007. // 隐藏工具条
  2008. if (isToolbarVisual() && !qsToolbar.contains(target)) {
  2009. hideToolbar();
  2010. }
  2011. }, true);
  2012.  
  2013. window.addEventListener('mouseup', function (e) {
  2014. var target = e.target;
  2015. // 显示/隐藏工具条
  2016. if (isAllowToolbar(e)) {
  2017. var selection = getSelection();
  2018. if (selection && !isToolbarVisual()) {
  2019. showToolbar(e);
  2020. }
  2021. if (!selection && isToolbarVisual()) {
  2022. hideToolbar();
  2023. }
  2024. }
  2025.  
  2026. // 划词时自动复制文本到剪贴板
  2027. if (conf.autoCopyToClipboard
  2028. && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA'
  2029. && !qsMainBox.contains(target) && !qsSettingBox.contains(target)) {
  2030. var selection = getSelection();
  2031. if (selection) {
  2032. GM_setClipboard(selection, 'text/plain');
  2033. }
  2034. }
  2035. }, true);
  2036.  
  2037. // 有时候selectionchange发生在mouseup之后, 导致没有selection时toolbar依然显示.
  2038. // 故再添加selectionchange事件以隐藏toolbar.
  2039. // 由于在鼠标划词拖动过程中会不停触发selectionchange事件, 所以最好不要以此事件来显示/调整toolbar位置.
  2040. document.addEventListener('selectionchange', function (e) {
  2041. var selection = getSelection();
  2042. if (!selection && isToolbarVisual()) {
  2043. hideToolbar();
  2044. }
  2045. }, true);
  2046.  
  2047. window.addEventListener('keydown', function (e) {
  2048.  
  2049. if (!isAllowHotkey(e)) {
  2050. return;
  2051. }
  2052.  
  2053. // Alt+S键, 超级快搜. 优先级如下:
  2054. // 1. 快搜主窗口可见, 使用默认搜索引擎搜索搜索框文本.
  2055. // 2. 网页有选中文本, 使用默认搜索引擎搜索文本.
  2056. // 3. 当前页面url中有搜索词, 挑选当前搜索引擎分类中的另一个搜索引擎搜索该词.
  2057. // 4. 都没有则打开快搜主窗口.
  2058. if (e.code == 'KeyS') {
  2059. e.preventDefault();
  2060.  
  2061. var engine = null;
  2062. var query = getQuery();
  2063. if (query.source == 'mainbox' || query.source == 'selection') {
  2064. engine = conf.defaultEngine;
  2065. } else if (query.source == 'url') {
  2066. var nowEngineInfo = getMatchedEngineInfo();
  2067. if (nowEngineInfo) {
  2068. var nowClassEngines = nowEngineInfo.classEngines.engines;
  2069. nowClassEngines.forEach((eng, i) => {
  2070. if (!engine && eng.enable && i != nowEngineInfo.index) {
  2071. engine = eng;
  2072. }
  2073. });
  2074. }
  2075. }
  2076.  
  2077. if (engine && query.query) {
  2078. openEngineOnKey(engine, query.query, e);
  2079. } else if (!isMainBoxVisual()) {
  2080. showMainBox();
  2081. } else {
  2082. hideMainBox();
  2083. }
  2084.  
  2085. return;
  2086. }
  2087.  
  2088. // Alt+D键, 网址直达. 网址优先级: 搜索框已有网址(若快搜主窗口可见) > 网页中选中网址
  2089. if (e.code == 'KeyD') {
  2090. e.preventDefault();
  2091. openUrl(getUrl().url, e);
  2092. return;
  2093. }
  2094.  
  2095. // Alt+自定义快捷键搜索. 文本优先级: 搜索框已有文本(若快搜主窗口可见) > 网页中选中文本 > 当前页面搜索词
  2096. if (hotkey2Engine[e.code]) {
  2097. e.preventDefault();
  2098. var engine = hotkey2Engine[e.code];
  2099. var query = getQuery();
  2100. openEngineOnKey(engine, query.query, e);
  2101. return;
  2102. }
  2103. }, true);
  2104.  
  2105. //
  2106. // 只在top window中使用的事件处理逻辑
  2107. //
  2108.  
  2109. if (window.self == window.top) {
  2110. window.addEventListener('mousedown', function (e) {
  2111. var target = e.target;
  2112. // 隐藏快搜主窗口
  2113. if (isMainBoxVisual()
  2114. && !isSettingBoxVisual()
  2115. && !qsMainBox.contains(target)
  2116. && !qsSuggestionsLayer.contains(target)) {
  2117. hideMainBox();
  2118. }
  2119.  
  2120. // 隐藏搜索建议浮层
  2121. if (isSuggestionsLayerVisual()
  2122. && !qsSuggestionsLayer.contains(target)
  2123. && !qsSearchInput.contains(target)) {
  2124. destroySuggestions();
  2125. }
  2126. }, true);
  2127.  
  2128. window.addEventListener('keydown', function (e) {
  2129.  
  2130. if (!isAllowHotkey(e)) {
  2131. return;
  2132. }
  2133.  
  2134. // Alt+F键, 显示/隐藏快搜主窗口
  2135. if (e.code == 'KeyF') {
  2136. e.preventDefault();
  2137. if (!isMainBoxVisual()) {
  2138. showMainBox();
  2139. } else {
  2140. hideMainBox();
  2141. }
  2142. return;
  2143. }
  2144.  
  2145. // Esc键, 隐藏快搜主窗口
  2146. if (e.code == 'Escape') {
  2147. if (isMainBoxVisual() && !isSettingBoxVisual()) {
  2148. hideMainBox();
  2149. }
  2150. return;
  2151. }
  2152.  
  2153. // Alt+L键, 锁定/解锁快搜所有功能.
  2154. if (e.code == 'KeyL') {
  2155. e.preventDefault();
  2156. toggleQuickSearchPageLock();
  2157. return;
  2158. }
  2159. }, true);
  2160.  
  2161. // 处理iframe发来的消息
  2162. window.addEventListener('message', function (e) {
  2163. if (e.data.source != 'qs-iframe') {
  2164. return;
  2165. }
  2166.  
  2167. if (e.data.keydown) {
  2168. if (e.data.keydown == 'Alt+KeyF') {
  2169. if (!qsPageLock) {
  2170. if (!isMainBoxVisual()) {
  2171. showMainBox(e.data.query);
  2172. } else {
  2173. hideMainBox();
  2174. }
  2175. }
  2176. }
  2177. if (e.data.keydown == 'Alt+KeyL') {
  2178. toggleQuickSearchPageLock();
  2179. }
  2180. }
  2181. }, true);
  2182. }
  2183.  
  2184. //
  2185. // 只在iframe中使用的事件处理逻辑
  2186. //
  2187.  
  2188. if (window.self != window.top) {
  2189. // 向top窗口发送消息
  2190. window.addEventListener('keydown', function (e) {
  2191. if (e.altKey && e.code == 'KeyF') {
  2192. var query = getSelection();
  2193. // 跨域iframe中不能执行window.top.origin, 故此处使用*
  2194. window.top.postMessage({
  2195. source: 'qs-iframe',
  2196. keydown: 'Alt+KeyF',
  2197. query: query
  2198. }, '*');
  2199. }
  2200. if (e.altKey && e.code == 'KeyL') {
  2201. window.top.postMessage({
  2202. source: 'qs-iframe',
  2203. keydown: 'Alt+KeyL'
  2204. }, '*');
  2205. }
  2206. }, true);
  2207. }
  2208. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址