Drag upwards to open in new tab

Click and drag a link upwards (20 pixels or more) to open it in a new tab. This script is particularly convenient if you override links to open in current tab by default using an extension or a script like https://greatest.deepsurf.us/scripts/4416

  1. // ==UserScript==
  2. // @name Drag upwards to open in new tab
  3. // @description Click and drag a link upwards (20 pixels or more) to open it in a new tab. This script is particularly convenient if you override links to open in current tab by default using an extension or a script like https://greatest.deepsurf.us/scripts/4416
  4. // @match *://*/*
  5. // @grant none
  6. // @run-at document-start
  7. // @namespace https://greatest.deepsurf.us/en/users/2159-woxxom
  8. // @author wOxxOm
  9. // @version 1.0.0
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. let timer, a, x, y, evtMove, evtEnd, isDragging;
  14.  
  15. addEventListener('mousedown', start, true);
  16. addEventListener('dragstart', start, true);
  17.  
  18. function start(e) {
  19. stop();
  20. if ((a = !isDragging && !e.button && e.composedPath().find(el => el.localName === 'a'))) {
  21. evtMove = /drag/.test(e.type) ? 'dragover' : 'mousemove';
  22. addEventListener(evtMove, observe);
  23. startTimer();
  24. x = e.clientX;
  25. y = e.clientY;
  26. }
  27. }
  28.  
  29. function startTimer() {
  30. if (timer)
  31. clearTimeout(timer);
  32. timer = setTimeout(stop, 1000);
  33. }
  34.  
  35. function observe(e) {
  36. if (!a)
  37. return stop();
  38. e.preventDefault();
  39. if (Math.abs(e.clientX - x) / Math.abs(y - e.clientY || 1) > .5 || e.clientY > y) {
  40. stop();
  41. } else if (!isDragging && y - e.clientY > 20) {
  42. isDragging = true;
  43. a.style.outline = 'green solid 2px';
  44. a.style.outlineOffset = '5px';
  45. evtEnd = /drag/.test(e.type) ? 'dragend' : 'mouseup';
  46. addEventListener(evtEnd, open);
  47. }
  48. }
  49.  
  50. function open(e) {
  51. if (isDragging && e.screenY > 0 && e.clientY > 0)
  52. Object.assign(a.cloneNode(), {target: '_blank'}).click();
  53. stop();
  54. }
  55.  
  56. function stop() {
  57. if (timer)
  58. clearTimeout(timer);
  59. if (isDragging) {
  60. isDragging = false;
  61. a.style.outline = '';
  62. a.style.outlineOffset = '';
  63. }
  64. removeEventListener(evtMove, observe);
  65. removeEventListener(evtEnd, open);
  66. }