PageUp and PageDown buttons

PageUp and PageDown buttons on the side of each page. Hold to scroll to top/bottom. Mainly useful for reading web pages on e-ink devices, but can be handy for other touch devices.

  1. // ==UserScript==
  2. // @name PageUp and PageDown buttons
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.2.4
  5. // @description PageUp and PageDown buttons on the side of each page. Hold to scroll to top/bottom. Mainly useful for reading web pages on e-ink devices, but can be handy for other touch devices.
  6. // @author xiaq
  7. // @match *://*/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net
  9. // @grant none
  10. // @license BSD 2-clause
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. const scrollFactor = 0.8; // How much of the page PageUp/PageDown scrolls by
  17. const opacity = 0.5; // Opacity of all buttons. 0 = transparent, 1 = opaque
  18. const right = true; // true = right side, false = left side
  19. const holdMs = 1000; // how long to hold to trigger scrolling to top/bottom, in milliseconds
  20. const sideGapPx = 8; // Gap between each button with the left/right side of the page
  21. const buttonsGapPx = 12; // Gap between PageUp and PageDown buttons
  22. const boxSizePx = 48;
  23. const fontSizePx = 32;
  24.  
  25. const commonStyle = `
  26. opacity: ${opacity};
  27. width: ${boxSizePx}px;
  28. height: ${boxSizePx}px;
  29. font-size: ${fontSizePx}px;
  30. border: 1px solid black;
  31. display: flex;
  32. align-items: center;
  33. justify-content: center;
  34. position: fixed;
  35. ${right? 'right' : 'left'}: ${sideGapPx}px;
  36. `;
  37.  
  38. const distance = `calc(50% + ${buttonsGapPx / 2}px)`;
  39. // PageUp
  40. addButton('▲', 'bottom:' + distance,
  41. () => { window.scrollBy(0, -scrollFactor * document.documentElement.clientHeight) },
  42. () => { window.scrollTo(0, 0); });
  43. // PageDown
  44. addButton('▼', 'top:' + distance,
  45. () => { window.scrollBy(0, scrollFactor * document.documentElement.clientHeight) },
  46. () => { window.scrollTo(0, document.body.scrollHeight); });
  47.  
  48. function addButton(text, style, press, hold) {
  49. const button = document.createElement('button');
  50. button.innerText = text;
  51. button.style = commonStyle + style;
  52. button.onclick = press;
  53.  
  54. let holdTimeout;
  55. const start = () => {
  56. holdTimeout = setTimeout(() => {
  57. hold();
  58. holdTimeout = undefined;
  59. }, holdMs);
  60. }
  61. const cancel = () => {
  62. if (holdTimeout) {
  63. clearTimeout(holdTimeout);
  64. holdTimeout = undefined;
  65. }
  66. };
  67. button.onmousedown = start;
  68. button.onmouseup = cancel;
  69. button.onmouseleave = cancel;
  70.  
  71. button.ontouchstart = start;
  72. button.ontouchend = cancel;
  73. button.ontouchcancel = cancel;
  74.  
  75. document.body.appendChild(button);
  76. }
  77. })();