Add Keyboard Shortcut for Generic Next/Previous Page

Add CTRL+ArrowLeft and CTRL+ArrowRight for generic next/previous page. It will click the last found link/button whose text starts/ends with e.g. "Next", "Prev", "Back", or "Previous".

目前为 2022-01-07 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Add Keyboard Shortcut for Generic Next/Previous Page
  3. // @namespace AddKeyboardShortcutForGenericNextPreviousPage
  4. // @version 1.0.16
  5. // @license GNU AGPLv3
  6. // @author jcunews
  7. // @description Add CTRL+ArrowLeft and CTRL+ArrowRight for generic next/previous page. It will click the last found link/button whose text starts/ends with e.g. "Next", "Prev", "Back", or "Previous".
  8. // @website https://greasyfork.org/en/users/85671-jcunews
  9. // @include *://*/*
  10. // @include *:*
  11. // @grant none
  12. // ==/UserScript==
  13.  
  14. /*
  15. The link/button text more specifically, are those which starts with (non case sesitive) "Next", "Prev", "Previous";
  16. or ends with "Prev", "Back", "Previous", "Next". e.g. "Next", "> Next", "Next Page", "Prev", "< Prev", "< Previous", etc.
  17. but not "< Prev Page" because the word "prev" or "previous" is not at the start/end of text.
  18.  
  19. This script doesn't take into account of links whose contents is an image rather than text, or whose text is a CSS text contents.
  20.  
  21. If next/previous navigation link is specified in the HTML metadata, it will be used as a priority.
  22. */
  23.  
  24. (function(rxPrev, rxNext, ts) {
  25. rxPrevious = /\u00ab|\b(?:back|prev(ious)?)\b/i;
  26. rxNext = /\u00bb|\bnext\b/i;
  27. rxCarousel = /carousel/i;
  28.  
  29. addEventListener("keydown", function(ev, e) {
  30.  
  31. function clickLink(rx, e, i, l, r, rx2) {
  32. rx2 = new RegExp("[a-z].*?(" + rx.source + ")", "i");
  33. e = document.querySelectorAll('a,button,input[type="button"],input[type="submit"]');
  34. for (i = e.length - 1; i >= 0; i--) {
  35. if (
  36. (
  37. ((e[i].tagName === "A") && rx.test(e[i].rel) && !rx2.test(e[i].rel)) ||
  38. ((e[i].tagName === "A") && Array.from(e[i].classList).some(cl => rx.test(cl) && !rx2.test(cl))) ||
  39. ((e[i].tagName === "INPUT") && rx.test(e[i].value) && !rx2.test(e[i].value)) ||
  40. (rx.test(e[i].textContent) && !rx2.test(e[i].textContent))
  41. ) && (!rxCarousel.test(e[i].className))
  42. ) {
  43. ev.preventDefault();
  44. e[i].click();
  45. return true;
  46. }
  47. }
  48. return false;
  49. }
  50.  
  51. if (ev.ctrlKey && !ev.altKey && !ev.shiftKey) {
  52. if (document.activeElement && (
  53. (/^(INPUT|TEXTAREA)$/).test(document.activeElement.tagName) ||
  54. document.activeElement.isContentEditable)) return;
  55. switch (ev.key) {
  56. case "ArrowLeft": //previous
  57. if (e = document.querySelector('link[rel="prev"][href]')) {
  58. ev.preventDefault();
  59. location.href = e.href;
  60. return;
  61. }
  62. if (clickLink(rxPrevious)) return;
  63. break;
  64. case "ArrowRight": //next
  65. if (e = document.querySelector('link[rel="next"][href]')) {
  66. ev.preventDefault();
  67. location.href = e.href;
  68. return;
  69. }
  70. if (clickLink(rxNext)) return;
  71. break;
  72. }
  73. }
  74. }, true);
  75. })();