Alternative search engines 2

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

当前为 2024-04-13 提交的版本,查看 最新版本

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