Greasy Fork 支持简体中文。

Alternative search engines 2

Adds search on other sites for google, bing, yandex, duckduckgo

目前為 2024-02-14 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Alternative search engines 2
  3. // @description Adds search on other sites for google, bing, yandex, duckduckgo
  4. // @namespace 2k1dmg@userscript
  5. // @license GPL version 3 or any later version; http://www.gnu.org/licenses/gpl.html
  6. // @version 0.2.7
  7. // @grant none
  8. // @noframes
  9. // @include https://yandex.tld/*
  10. // @include https://ya.ru/*
  11. // @include https://www.google.tld/*
  12. // @include https://www.bing.com/*
  13. // @include https://duckduckgo.com/*
  14. // @exclude /^https://(yandex|www\.google)\.(net|org)/.*$/
  15. // ==/UserScript==
  16.  
  17. // 2024-02-14
  18.  
  19. var SEARCH_ON = '• ';
  20. var SEARCH_ON_END = ' •';
  21. var LINK_BOX_ID = 'oeid-box';
  22. var ENGINES_SEPARATOR = ' - ';
  23. var POSITION = 'left';
  24.  
  25. var ENGINES = {
  26. Yandex: 'https://yandex.ru/yandsearch?text=',
  27. Ya: 'https://ya.ru/yandsearch?text=',
  28. Google: 'https://www.google.com/search?q=',
  29. Bing: 'https://www.bing.com/search?q=',
  30. DuckDuckGo: 'https://duckduckgo.com/?q='
  31. };
  32.  
  33. var PLACEHOLDER_SELECTORS = [
  34. '.content__left', // yandex
  35. '.content__left', // ya
  36. '#result-stats', // google
  37. '.sb_count', // bing
  38. '.results--main' // duckduckgo
  39. ].join(',');
  40.  
  41. var INPUT_FIELD_SELECTORS = [
  42. '.HeaderDesktopForm-Input', // yandex
  43. '.HeaderDesktopForm-Input', // ya
  44. 'textarea.gLFyf', // google
  45. '#sb_form_q', // bing
  46. '#search_form_input' // duckduckgo
  47. ].join(',');
  48.  
  49. function onClick(event) {
  50. var link = event.target;
  51. if(link.nodeName.toLowerCase() !== 'a')
  52. return;
  53. var engineSource = ENGINES[link.engineName];
  54. var engineURL;
  55. var engineParam = '';
  56. if(Array.isArray(engineSource)) {
  57. engineParam = engineSource[1];
  58. engineURL = engineSource[0];
  59. }
  60. else if(typeof engineSource === 'string') {
  61. engineURL = engineSource;
  62. }
  63. else {
  64. return;
  65. }
  66. var searchText = document.querySelector(INPUT_FIELD_SELECTORS);
  67. if(engineURL && searchText && searchText.value.length > 0) {
  68. var url = engineURL + encodeURIComponent(searchText.value) + engineParam;
  69. window.open(url, '_blank');
  70. }
  71. }
  72.  
  73. function addCSSStyle() {
  74. var cssStyle = document.createElement('style');
  75. cssStyle.type = 'text/css';
  76. cssStyle.textContent = [
  77. '#' + LINK_BOX_ID + ' {',
  78. ' display: inline-block;',
  79. ' padding-right: 10px;',
  80. ' padding-bottom: 10px;',
  81. ' color: rgb(115, 115, 115);' ,
  82. ' font-family: Verdana,sans-serif;',
  83. ' font-size: 9pt;',
  84. ' text-align: ' + POSITION + ';',
  85. ' z-index: 10000;',
  86. '}',
  87. '#' + LINK_BOX_ID + ' > a {',
  88. ' text-decoration: none;',
  89. '}'
  90. ].join('\n');
  91. document.head.appendChild(cssStyle);
  92. }
  93.  
  94. var createFragment = (function() {
  95. var setCommon = function(node, sAttr, reason) {
  96. var aAttr = sAttr.split(',');
  97. aAttr.forEach(function(attr) {
  98. var attrSource = /:=/.test(attr) ? attr.split(':=') : [attr, ''];
  99. var attrName = attrSource[0].trim();
  100. var attrValue = attrSource[1].trim().replace(/^(['"])([^\1]*)\1$/, '$2');
  101. if(reason === 'a') {
  102. node.setAttribute(attrName, attrValue);
  103. }
  104. else {
  105. node[attrName] = attrValue;
  106. }
  107. });
  108. return node;
  109. };
  110. var setAttr = function(node, sAttr) {
  111. return setCommon(node, sAttr, 'a');
  112. };
  113. var setProp = function(node, sAttr) {
  114. return setCommon(node, sAttr, 'p');
  115. };
  116. var createFragmentInner = function(data, fragment) {
  117. if(data.n) {
  118. var node = document.createElement(data.n);
  119. if(data.a)
  120. node = setAttr(node, data.a);
  121. if(data.p)
  122. node = setProp(node, data.p);
  123. if(data.s)
  124. node.style.cssText = data.s;
  125. fragment.appendChild(node);
  126. }
  127. if(data.c) {
  128. data.c.forEach(function(cn) {
  129. createFragmentInner(cn, node || fragment);
  130. });
  131. }
  132. if(data.t && node) {
  133. node.appendChild(document.createTextNode(data.t));
  134. }
  135. if(data.tc) {
  136. fragment.appendChild(document.createTextNode(data.tc));
  137. }
  138. if(data.dn) {
  139. fragment.appendChild(data.dn);
  140. }
  141. return fragment;
  142. };
  143. return function(data) {
  144. var fragment = document.createDocumentFragment();
  145. return createFragmentInner({c:data}, fragment);
  146. };
  147. })();
  148.  
  149. function createLinkBox() {
  150. return createFragment([
  151. {n:'div',a:'id:="'+LINK_BOX_ID+'"',c:(function() {
  152. var domain = document.domain.split('.').splice(-2, 2)[0];
  153. var aLinks = [{tc:SEARCH_ON}];
  154. for(var engine in ENGINES) {
  155. if(domain == engine.toLowerCase())
  156. continue;
  157. aLinks.push(
  158. {n:'a',a:'href:="javascript:void(0)"',p:'engineName:="'+engine+'"',t:engine},
  159. {tc:ENGINES_SEPARATOR}
  160. );
  161. }
  162. aLinks[aLinks.length-1] = {tc:SEARCH_ON_END};
  163. return aLinks;
  164. })()}
  165. ]);
  166. }
  167.  
  168. function onDOMLoad() {
  169. var results = document.querySelector(PLACEHOLDER_SELECTORS);
  170. if(!results)
  171. return;
  172. if(document.getElementById(LINK_BOX_ID))
  173. return;
  174. addCSSStyle();
  175. var fragment = createLinkBox();
  176. var linkBox = fragment.querySelector('#'+LINK_BOX_ID);
  177. linkBox.onclick = onClick;
  178. results.insertBefore(fragment, results.firstChild);
  179. }
  180.  
  181. function addObserver(target, config, callback) {
  182. var observer = new MutationObserver(function(mutations) {
  183. mutations.forEach(function(mutation) {
  184. callback.call(this, mutation);
  185. });
  186. });
  187. observer.observe(target, config);
  188. return observer;
  189. }
  190.  
  191. function removeObserver(observer) {
  192. observer.disconnect();
  193. }
  194.  
  195. function getNodes() {
  196. var _slice = Array.slice || Function.prototype.call.bind(Array.prototype.slice);
  197. var trg = document.body;
  198. var params = { childList: true, subtree: true };
  199. var getNode = function(mut) {
  200. var addedNodes = mut.addedNodes;
  201. var nodes = _slice(addedNodes);
  202. nodes.forEach(function(node) {
  203. if(node.querySelector &&
  204. node.querySelector(PLACEHOLDER_SELECTORS)) {
  205. onDOMLoad();
  206. }
  207. });
  208. };
  209. var observer = addObserver(trg, params, getNode);
  210. window.addEventListener('unload', function(event) {
  211. removeObserver(observer);
  212. }, false);
  213. }
  214.  
  215. onDOMLoad();
  216. getNodes();