Alternative search engines 2

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

当前为 2022-01-29 提交的版本,查看 最新版本

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