Open Links in NEW BACKGROUND Tab

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

当前为 2022-12-26 提交的版本,查看 最新版本

  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.3
  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. function attachHandler(nodes) {
  26. nodes.forEach(function(node) {
  27. // href will be auto expanded with window.location.origin, such as href="#" --> "https://example.com/#"
  28. // search-engine-a: more compatible with Search Engine Switcher script
  29. if ( (node.target != '_blank') && (node.href) && (!node.href.includes("javascript:")) && (!node.href.startsWith(window.location.origin)) && (node.className!="search-engine-a") ) {
  30. node.onclick = clickHandler;
  31. node.addEventListener('click', clickHandler);
  32. }
  33. });
  34. }
  35.  
  36. /*
  37. https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons
  38. MouseEvent.buttons
  39. 0: No button or un-initialized
  40. 1: Primary button (usually the left button)
  41. 2: Secondary button (usually the right button)
  42. 4: Auxiliary button (usually the mouse wheel button or middle button)
  43. 8: 4th button (typically the "Browser Back" button)
  44. 16 : 5th button (typically the "Browser Forward" button)
  45.  
  46. https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent
  47. KeyboardEvent.metaKey
  48. e.metaKey
  49.  
  50. https://stackoverflow.com/a/35936912/2292993
  51. e is short for event
  52. the element on which you clicked (event.target)
  53.  
  54. https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation
  55. 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().
  56. */
  57. function clickHandler(e) {
  58. if (e.button > 1)
  59. return;
  60. e.preventDefault();
  61. e.stopPropagation();
  62. e.stopImmediatePropagation();
  63. // GM_openInTab(this.href, e.button || e.ctrlKey);
  64. GM_openInTab(this.href, true); // open in background
  65. }
  66.  
  67.  
  68.  
  69.  
  70. // https://greasyfork.org/scripts/12228/code/setMutationHandler.js
  71. // ==UserScript==
  72. // @name setMutationHandler
  73. // @description MutationObserver wrapper to wait for the specified CSS selector
  74. // @namespace wOxxOm.scripts
  75. // @author wOxxOm
  76. // @grant none
  77. // @version 3.0.2
  78. // ==/UserScript==
  79.  
  80. function setMutationHandler(target, selector, handler, options) {
  81. // or setMutationHandler(selector, handler, options) {
  82. // or setMutationHandler(options) {
  83. if (typeof arguments[0] == 'string') {
  84. options = arguments[2] || {};
  85. handler = arguments[1];
  86. selector = arguments[0];
  87. target = document;
  88. } else if (arguments.length == 1 && target && typeof target.handler == 'function') {
  89. options = arguments[0];
  90. handler = options.handler;
  91. selector = options.selector;
  92. target = options.target || document;
  93. } else if (!(target instanceof Node)) {
  94. throw 'Bad params for setMutationHandler.\n' +
  95. 'A: [optional Node] target, [String] selector, [Function] handler, [optional Object] options\n' +
  96. 'B: [Object] options\n' +
  97. 'Options: target, selector, handler, processExisting, childList, attributes, characterData, subtree, attributeOldValue, characterDataOldValue, attributeFilter';
  98. } else
  99. options = options || {};
  100.  
  101. if (options.processExisting && target.querySelector(selector))
  102. handler.call(null, Array.prototype.slice.call(target.querySelectorAll(selector)));
  103. if (!options.attributes && !options.characterData && !options.childList && options.subtree === undefined)
  104. options.childList = options.subtree = true;
  105.  
  106. var cb;
  107. if (/^#[\w\d-]+$/.test(selector)) {
  108. selector = selector.substr(1);
  109. cb = MOhandlerForId;
  110. } else {
  111. cb = MOhandler;
  112. }
  113. var observer = new MutationObserver(cb);
  114. observer.observe(target, options || {subtree:true, childList:true});
  115. return observer;
  116.  
  117. function MOhandler(mutations) {
  118. if (mutations.length > 100 && !document.querySelector(selector))
  119. return;
  120. var found = [];
  121. for (var i=0, m; (m = mutations[i++]); ) {
  122. switch (m.type) {
  123. case 'childList':
  124. var nodes = m.addedNodes, nl = nodes.length;
  125. var textNodesOnly = true;
  126. for (var j=0; j < nl; j++) {
  127. var n = nodes[j];
  128. textNodesOnly &= n.nodeType == 3; // TEXT_NODE
  129. if (n.nodeType != 1) // ELEMENT_NODE
  130. continue;
  131. if (n.matches(selector))
  132. found.push(n);
  133. else if (n.querySelector(selector)) {
  134. n = n.querySelectorAll(selector);
  135. if (n.length < 1000)
  136. found.push.apply(found, n);
  137. else
  138. found = found.concat(found.slice.call(n));
  139. }
  140. }
  141. if (textNodesOnly && m.target.matches(selector))
  142. found.push(m.target);
  143. break;
  144. case 'attributes':
  145. if (m.target.matches(selector))
  146. found.push(m.target);
  147. break;
  148. case 'characterData':
  149. if (m.target.parentNode && m.target.parentNode.matches(selector))
  150. found.push(m.target.parentNode);
  151. break;
  152. }
  153. }
  154. if (!found.length)
  155. return;
  156. if (handler.call(observer, found) === false)
  157. observer.disconnect();
  158. }
  159.  
  160. function MOhandlerForId(mutations) {
  161. var el = document.getElementById(selector);
  162. if (el && target.contains(el))
  163. if (handler.call(observer, [el]) === false)
  164. observer.disconnect();
  165. }
  166. }
  167.