Open links in current tab

Open links in current tab regardless of _target or site's preferences. Ctrl-click: background tab, Ctrl-Shift-click: foreground tab, Shift-click: new window, Alt-click: force open in current tab

当前为 2017-06-30 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Open links in current tab
  3. // @author wOxxOm
  4. // @description Open links in current tab regardless of _target or site's preferences. Ctrl-click: background tab, Ctrl-Shift-click: foreground tab, Shift-click: new window, Alt-click: force open in current tab
  5. // @namespace http://target._blank.is.retarded
  6. // @version 2.2.7
  7. // @include *
  8. // @run-at document-start
  9. // @grant GM_openInTab
  10. // ==/UserScript==
  11.  
  12. if (window == top) {
  13. window.addEventListener('message', function(e) {
  14. // some stupid sites choke on object data
  15. if (!/^\{/.test(e.data))
  16. return;
  17. var data = tryParse(e.data);
  18. if (data.name == GM_info.script.name)
  19. navigate(data.url);
  20. });
  21. }
  22.  
  23. var suppressing, clickedElement;
  24. window.addEventListener('mousedown', function(e) {
  25. clickedElement = e.target;
  26. }, true);
  27.  
  28. window.addEventListener('mouseup', function(e) {
  29. if (e.button > 1 || e.target != clickedElement)
  30. return;
  31. var link = pierceShadow(e);
  32. if (!link
  33. || (link.getAttribute('href') || '').match(/^(javascript|#|$)/)
  34. || !document.contains(link))
  35. return;
  36. var b = e.button, c = e.ctrlKey, a = e.altKey, s = e.shiftKey, m = e.metaKey;
  37. if (b == 1 || c && !a && !m)
  38. GM_openInTab(link.href, !s || b == 1);
  39. else if (window.chrome && b === 0 && s && !c && !a && !m)
  40. link.cloneNode().dispatchEvent(new MouseEvent('click', {shiftKey: true}));
  41. else if (!c && !s && !m && !a) {
  42. if (link.target == '_blank')
  43. link.target = '';
  44. blockWindowOpenAndMutations(link);
  45. return;
  46. }
  47. else
  48. return;
  49. suppressing = true;
  50. prevent(e);
  51. }, true);
  52.  
  53. window.addEventListener('click', prevent, true);
  54. window.addEventListener('auxclick', prevent, true);
  55.  
  56. function prevent(e) {
  57. if (!suppressing)
  58. return;
  59. e.preventDefault();
  60. e.stopPropagation();
  61. e.stopImmediatePropagation();
  62. setTimeout(function() {
  63. suppressing = false;
  64. }, 50);
  65. }
  66.  
  67. function blockWindowOpenAndMutations(link) {
  68. var observer = new MutationObserver(function() {
  69. if (link.target == '_blank') {
  70. link.removeAttribute('target');
  71. console.log('[Open links in current tab] prevented dynamic target=_blank for', link.href);
  72. navigate(link.href);
  73. }
  74. });
  75. observer.observe(link, {attributes:true, attributeFilter:['target'], characterData:true});
  76.  
  77. var _open = unsafeWindow.open;
  78. var timeout = setTimeout(function() {
  79. unsafeWindow.open = _open;
  80. observer.disconnect();
  81. }, 50);
  82. unsafeWindow.open = exportFunction(function(url, name, features) {
  83. if (!features) {
  84. console.log('[Open links in current tab] prevented window.open for', url);
  85. navigate(link.href);
  86. } else
  87. _open(url, name, features);
  88. unsafeWindow.open = _open;
  89. clearTimeout(timeout);
  90. }, unsafeWindow);
  91. }
  92.  
  93. function pierceShadow(e) {
  94. var el = e.target;
  95. while (el.shadowRoot)
  96. el = el.shadowRoot.elementFromPoint(e.clientX, e.clientY);
  97. return el.closest('a');
  98. }
  99.  
  100. function navigate(url) {
  101. if (window == top) {
  102. var link = document.createElement('a');
  103. link.href = url;
  104. link.dispatchEvent(new MouseEvent('click'));
  105. } else
  106. top.postMessage(JSON.stringify({name: GM_info.script.name, url: url}), '*');
  107. }
  108.  
  109. function tryParse(str) {
  110. try { return JSON.parse(str); }
  111. catch(e) {}
  112. }