Accesskeys for public-inbox

Faster access to the features on websites running public-inbox, like public-inbox.org and lore.kernel.org

  1. // ==UserScript==
  2. // @name Accesskeys for public-inbox
  3. // @namespace https://github.com/rybak
  4. // @description Faster access to the features on websites running public-inbox, like public-inbox.org and lore.kernel.org
  5. // @match https://lore.kernel.org/*
  6. // @match https://public-inbox.org/*
  7. // @version 8
  8. // @author Andrei Rybak
  9. // @license MIT
  10. // @grant GM_addStyle
  11. // ==/UserScript==
  12.  
  13. /*
  14. * Copyright (c) 2023 Andrei Rybak
  15. *
  16. * Permission is hereby granted, free of charge, to any person obtaining a copy
  17. * of this software and associated documentation files (the "Software"), to deal
  18. * in the Software without restriction, including without limitation the rights
  19. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  20. * copies of the Software, and to permit persons to whom the Software is
  21. * furnished to do so, subject to the following conditions:
  22. *
  23. * The above copyright notice and this permission notice shall be included in all
  24. * copies or substantial portions of the Software.
  25. *
  26. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  27. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  28. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  29. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  30. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  31. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  32. * SOFTWARE.
  33. */
  34.  
  35. (function() {
  36. 'use strict';
  37.  
  38. function setUpAccesskey(key, selector) {
  39. const element = document.querySelector(selector);
  40. if (element) {
  41. element.setAttribute("accesskey", key);
  42. }
  43. }
  44.  
  45. GM_addStyle(
  46. `a[accesskey]:hover:after {
  47. content: " [" attr(accesskey) "]";
  48. text-transform: uppercase;
  49. white-space: pre;
  50. font-family: monospace;
  51. margin-right: 0.5ex;
  52. }`
  53. );
  54.  
  55. // go to front page from a thread link
  56. setUpAccesskey("z", "body > pre > a[href$='../']");
  57. // "latest" link == go to front page from a next/prev pagination
  58. setUpAccesskey("z", "a[href='.'");
  59.  
  60. // search text field
  61. setUpAccesskey("s", "input[name='q']");
  62. // flat thread view link
  63. setUpAccesskey("f", "a[href^='../../'][href$='/T/#u'], a[href='T/#u']");
  64. // nested thread view link
  65. setUpAccesskey("n", "a[href^='../../'][href$='/t/#u'], a[href='t/#u']");
  66. // [thread overview] link on singular email view
  67. setUpAccesskey("t", "a[href='#r']");
  68.  
  69. // "next (older)" link and ...
  70. setUpAccesskey("n", "a[rel='next']");
  71. // ... "prev (newer)" link
  72. setUpAccesskey("p", "a[rel='prev']");
  73.  
  74. /*
  75. * In flat & nested thread views link for "jump to thread overview at the bottom"
  76. * can't be selected with pure CSS selectors, so an ad-hoc solution is needed.
  77. */
  78. for (const a of document.querySelectorAll("body > pre:nth-child(2) > a")) {
  79. const t = a.innerText;
  80. /*
  81. * Extra careful link text check to reduce likelihood of
  82. * false-positives.
  83. */
  84. if (t.includes('sibling') && /* also covers "siblings" */
  85. t.includes('repl') && /* "reply" and "replies" */
  86. (t.includes("messages in thread") || t.includes("only message in thread")))
  87. {
  88. a.setAttribute("accesskey", "t");
  89. break;
  90. }
  91. }
  92.  
  93. // for threads at the top of the page
  94. const threadLinks = document.querySelectorAll("body > pre > a[href$='T/#t']")
  95. for (let i = 0; i < threadLinks.length && i < 9; i++) {
  96. // 49 is ASCII code for '1'
  97. threadLinks[i].setAttribute("accesskey", String.fromCharCode(i + 49));
  98. }
  99. // tenth thread needs to be defined separately
  100. if (threadLinks.length >= 9) {
  101. threadLinks[9].setAttribute("accesskey", "0");
  102. }
  103. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址