Open Links in NEW BACKGROUND Tab

Open links (esp. from different domains) in NEW BACKGROUND tab with normal left click

目前为 2023-01-17 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Open Links in NEW BACKGROUND Tab
  3. // @author Jerry
  4. // @description Open links (esp. from different domains) in NEW BACKGROUND tab with normal left click
  5. // @grant GM_openInTab
  6. // @include http*://*
  7. // @namespace https://greasyfork.org/users/28298
  8. // @run-at document-start
  9. // @version 0.5
  10. // @license GNU GPLv3
  11. // ==/UserScript==
  12.  
  13.  
  14. // source:
  15. // https://greasyfork.org/en/scripts/20694-all-links-open-all-in-new-background-tab/code
  16. // https://greasyfork.org/en/scripts/12367-open-links-in-new-tab/code
  17.  
  18. attachHandler([].slice.call(document.getElementsByTagName('a')));
  19.  
  20. setMutationHandler(document, 'a', function(nodes) {
  21. attachHandler(nodes);
  22. return true;
  23. });
  24.  
  25. // https://stackoverflow.com/a/26269087/2292993
  26. // ugly fix duckduckgo rightside bar search results
  27. //document.addEventListener ("DOMContentLoaded", FnReady);
  28. window.addEventListener ("load", FnReady);
  29. function FnReady () {
  30. if (location.href.startsWith('https://duckduckgo.com')) {
  31. var nodes = document.getElementsByTagName('a');
  32. for (var i=0; i<nodes.length; i++) {
  33. var node = nodes[i];
  34. if (node.className.includes("js-about-item")) {
  35. node.replaceWith(node.cloneNode(true));
  36. }
  37. }
  38. }
  39. }
  40.  
  41. function attachHandler(nodes) {
  42. nodes.forEach(function(node) {
  43. // href will be auto expanded with window.location.origin, such as href="#" --> "https://example.com/#"
  44. var cond = (node.target != '_blank') && (node.href) && (!node.href.includes("javascript:")) && (!node.href.startsWith(window.location.origin));
  45. cond = cond && (node.className!="search-engine-a"); // search-engine-a: more compatible with Search Engine Switcher script
  46. cond = cond && (!node.href.includes("stackexchange.com")); // stackoverflow
  47. if ( cond ) {
  48. node.onclick = clickHandler;
  49. node.addEventListener('click', clickHandler);
  50. }
  51. });
  52. }
  53.  
  54. /*
  55. https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons
  56. MouseEvent.buttons
  57. 0: No button or un-initialized
  58. 1: Primary button (usually the left button)
  59. 2: Secondary button (usually the right button)
  60. 4: Auxiliary button (usually the mouse wheel button or middle button)
  61. 8: 4th button (typically the "Browser Back" button)
  62. 16 : 5th button (typically the "Browser Forward" button)
  63.  
  64. https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent
  65. KeyboardEvent.metaKey
  66. e.metaKey
  67.  
  68. https://stackoverflow.com/a/35936912/2292993
  69. e is short for event
  70. the element on which you clicked (event.target)
  71.  
  72. https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation
  73. The stopPropagation() method of the Event interface prevents further propagation of the current event in the capturing and bubbling phases. It does not, however, prevent any default behaviors from occurring; for instance, clicks on links are still processed. If you want to stop those behaviors, see the preventDefault() method. It also does not prevent immediate propagation to other event-handlers. If you want to stop those, see stopImmediatePropagation().
  74. */
  75. function clickHandler(e) {
  76. if (e.button > 1)
  77. return;
  78. e.preventDefault();
  79. e.stopPropagation();
  80. e.stopImmediatePropagation();
  81. // GM_openInTab(this.href, e.button || e.ctrlKey);
  82. GM_openInTab(this.href, true); // open in background
  83. }
  84.  
  85.  
  86.  
  87.  
  88. // https://greasyfork.org/scripts/12228/code/setMutationHandler.js
  89. // ==UserScript==
  90. // @name setMutationHandler
  91. // @description MutationObserver wrapper to wait for the specified CSS selector
  92. // @namespace wOxxOm.scripts
  93. // @author wOxxOm
  94. // @grant none
  95. // @version 3.0.2
  96. // ==/UserScript==
  97.  
  98. function setMutationHandler(target, selector, handler, options) {
  99. // or setMutationHandler(selector, handler, options) {
  100. // or setMutationHandler(options) {
  101. if (typeof arguments[0] == 'string') {
  102. options = arguments[2] || {};
  103. handler = arguments[1];
  104. selector = arguments[0];
  105. target = document;
  106. } else if (arguments.length == 1 && target && typeof target.handler == 'function') {
  107. options = arguments[0];
  108. handler = options.handler;
  109. selector = options.selector;
  110. target = options.target || document;
  111. } else if (!(target instanceof Node)) {
  112. throw 'Bad params for setMutationHandler.\n' +
  113. 'A: [optional Node] target, [String] selector, [Function] handler, [optional Object] options\n' +
  114. 'B: [Object] options\n' +
  115. 'Options: target, selector, handler, processExisting, childList, attributes, characterData, subtree, attributeOldValue, characterDataOldValue, attributeFilter';
  116. } else
  117. options = options || {};
  118.  
  119. if (options.processExisting && target.querySelector(selector))
  120. handler.call(null, Array.prototype.slice.call(target.querySelectorAll(selector)));
  121. if (!options.attributes && !options.characterData && !options.childList && options.subtree === undefined)
  122. options.childList = options.subtree = true;
  123.  
  124. var cb;
  125. if (/^#[\w\d-]+$/.test(selector)) {
  126. selector = selector.substr(1);
  127. cb = MOhandlerForId;
  128. } else {
  129. cb = MOhandler;
  130. }
  131. var observer = new MutationObserver(cb);
  132. observer.observe(target, options || {subtree:true, childList:true});
  133. return observer;
  134.  
  135. function MOhandler(mutations) {
  136. if (mutations.length > 100 && !document.querySelector(selector))
  137. return;
  138. var found = [];
  139. for (var i=0, m; (m = mutations[i++]); ) {
  140. switch (m.type) {
  141. case 'childList':
  142. var nodes = m.addedNodes, nl = nodes.length;
  143. var textNodesOnly = true;
  144. for (var j=0; j < nl; j++) {
  145. var n = nodes[j];
  146. textNodesOnly &= n.nodeType == 3; // TEXT_NODE
  147. if (n.nodeType != 1) // ELEMENT_NODE
  148. continue;
  149. if (n.matches(selector))
  150. found.push(n);
  151. else if (n.querySelector(selector)) {
  152. n = n.querySelectorAll(selector);
  153. if (n.length < 1000)
  154. found.push.apply(found, n);
  155. else
  156. found = found.concat(found.slice.call(n));
  157. }
  158. }
  159. if (textNodesOnly && m.target.matches(selector))
  160. found.push(m.target);
  161. break;
  162. case 'attributes':
  163. if (m.target.matches(selector))
  164. found.push(m.target);
  165. break;
  166. case 'characterData':
  167. if (m.target.parentNode && m.target.parentNode.matches(selector))
  168. found.push(m.target.parentNode);
  169. break;
  170. }
  171. }
  172. if (!found.length)
  173. return;
  174. if (handler.call(observer, found) === false)
  175. observer.disconnect();
  176. }
  177.  
  178. function MOhandlerForId(mutations) {
  179. var el = document.getElementById(selector);
  180. if (el && target.contains(el))
  181. if (handler.call(observer, [el]) === false)
  182. observer.disconnect();
  183. }
  184. }
  185.