Draggable Reference Line

Designed for reading long articles, it helps remember the current reading progress.

目前为 2021-09-13 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Draggable Reference Line
  3. // @description Designed for reading long articles, it helps remember the current reading progress.
  4. // @version 1.0
  5. // @author Rui LIU (@liurui39660)
  6. // @match *://*/*
  7. // @icon https://icons.duckduckgo.com/ip2/example.com.ico
  8. // @run-at document-body
  9. // @namespace https://greasyfork.org/users/193469
  10. // ==/UserScript==
  11.  
  12. (function () {
  13. 'use strict';
  14.  
  15. const height = 2; // px, height of the visible line
  16. const padding = 2; // px, additional draggable area above and below the line, not the sum of them
  17. const color = 'red'; // or #-string
  18.  
  19. const initPos = -padding - height / 2;
  20. const body = document.getElementsByTagName('body')[0];
  21. const line = document.createElement('div');
  22. line.textContent = '#DraggableReferenceLine';
  23. line.style = `margin: 0; padding: ${padding}px 0; cursor: n-resize; font-size: 0; color: #fff0; background: ${color}; background-clip: content-box; width: 100vw; height: ${height}px; position: absolute; top: ${localStorage[`DraggableLine_${window.location.pathname}${window.location.search}`] || initPos}px; z-index: 10;`;
  24.  
  25. const reset = () => {
  26. line.style.top = `${initPos}px`;
  27. localStorage.removeItem(`DraggableLine_${window.location.pathname}${window.location.search}`);
  28. }
  29. const set = top => {
  30. line.style.top = `${top}px`;
  31. localStorage[`DraggableLine_${window.location.pathname}${window.location.search}`] = top;
  32. }
  33. let callbackMouseMove = ev => {
  34. line.style.top = `${ev.pageY + initPos}px`; // initPos is also the offset to line center
  35. };
  36. let callbackMouseUp = ev => {
  37. if (ev.detail === 1) { // Don't overwrite dblclick
  38. body.releasePointerCapture(ev.pointerId);
  39. body.style.cursor = null;
  40. const top = parseFloat(line.style.top);
  41. top > initPos ? set(top) : reset();
  42. [onmouseup, onmousemove, callbackMouseUp, callbackMouseMove] = [callbackMouseUp, callbackMouseMove, onmouseup, onmousemove];
  43. }
  44. };
  45. line.addEventListener('mousedown', ev => {
  46. if (ev.detail === 1) {
  47. ev.preventDefault(); // Don't select text
  48. body.setPointerCapture(ev.pointerId); // The cursor won't change back to pointer when out of browser
  49. body.style.cursor = 'n-resize';
  50. [onmouseup, onmousemove, callbackMouseUp, callbackMouseMove] = [callbackMouseUp, callbackMouseMove, onmouseup, onmousemove];
  51. }
  52. });
  53. line.addEventListener('dblclick', reset);
  54. body.appendChild(line);
  55. })();