AO3 Formatting Shortcuts

Keyboard shortcuts for HTML tags

  1. // ==UserScript==
  2. // @name AO3 Formatting Shortcuts
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.4.2
  5. // @license MIT
  6. // @description Keyboard shortcuts for HTML tags
  7. // @author Grumblesaur
  8. // @match https://archiveofourown.org/works/*
  9. // @match https://archiveofourown.org/comments/*
  10. // @match https://archiveofourown.org/chapters/*
  11. // @icon https://www.google.com/s2/favicons?sz=64&domain=archiveofourown.org
  12. // @grant none
  13. // ==/UserScript==
  14. /*
  15. * Introduces shortcuts to type HTML elements into Archive of our Own
  16. * (AO3) text boxes. The shortcuts are:
  17. * - Ctrl b: <b></b> – bold text
  18. * - Ctrl d: <details></details> – a hideable element
  19. * - Ctrl e: <em></em> – semantic emphatic italics
  20. * - Ctrl i: <i></i> – italics
  21. * - Ctrl k: <cite></cite> – semantic title italics
  22. * - Ctrl l: <li></li> – list item
  23. * - Ctrl m: <mark></mark> – highlighting
  24. * - Ctrl o: <ol></ol> – ordered list
  25. * - Ctrl p: <p></p> – paragraph
  26. * - Ctrl q: <q></q> – inline quote
  27. * - Ctrl s: <s></s> – strikethrough
  28. * - Ctrl u: <u></u> – underline
  29. *
  30. * - Ctrl Shift b: <blockquote></blockquote> – block quote
  31. * - Ctrl Shift c: <code></code> – monospace/code
  32. * - Ctrl Shift i: <img src="" alt="(image description here)" /> – image
  33. * - Ctrl Shift m: <summary></summary> – heading for a <details> element
  34. * - Ctrl Shift n: <br/> – forced line break
  35. * - Ctrl Shift s: <strong></strong> – semantic emphatic bold
  36. * - Ctrl Shift u: <ul></ul> – unordered list
  37. */
  38. function getTagMap() {
  39. return {
  40. 'shifted': {
  41. 'b' : ['<blockquote>', '</blockquote>'],
  42. 'c' : ['<code>', '</code>'],
  43. 'i' : ['<img src="', '" alt="(image description here)" />'],
  44. 'm' : ['<summary>', '</summary>'],
  45. 'n' : ['', '<br/>'],
  46. 's' : ['<strong>', '</strong>'],
  47. 'u' : ['<ul>', '</ul>']
  48. },
  49. 'normal': {
  50. 'b' : ['<b>', '</b>'],
  51. 'd' : ['<details>', '</details>'],
  52. 'e' : ['<em>', '</em>'],
  53. 'i' : ['<i>', '</i>'],
  54. 'k' : ['<cite>', '</cite>'],
  55. 'l' : ['<li>', '</li>'],
  56. 'm' : ['<mark>', '</mark>'],
  57. 'o' : ['<ol>', '</ol>'],
  58. 'p' : ['<p>', '</p>'],
  59. 'q' : ['<quote>', '</quote>'],
  60. 's' : ['<s>', '</s>'],
  61. 'u' : ['<u>', '</u>']
  62. }
  63. }
  64. }
  65. function localError(msg) {
  66. console.log("(AO3 Formatting Shortcuts): " + msg);
  67. }
  68. (function() {
  69. 'use strict';
  70. // Insert a pair of HTML tags into the active text area, and rewind the
  71. // cursor to sit between them.
  72. function typeInTextarea(opening, closing, el = document.activeElement) {
  73. const [start, end] = [el.selectionStart, el.selectionEnd];
  74. let selected = el.value.substring(start, end);
  75. el.setRangeText(opening + selected + closing, start, end, 'end');
  76. el.selectionStart -= closing.length;
  77. el.selectionEnd -= closing.length;
  78. }
  79. const tagMap = getTagMap();
  80. function formatting(event) {
  81. /* Separated shift key from capitalization to enable the use
  82. * of shortcuts when users have capslock on. */
  83. let shiftState = event.shiftKey ? 'shifted' : 'normal';
  84. let keyPress = event.key.toLowerCase();
  85. if (event.ctrlKey && Object.keys(tagMap[shiftState]).includes(keyPress)) {
  86. event.preventDefault();
  87. const tags = tagMap[shiftState][keyPress];
  88. if (tags.includes(null) || tags.includes(undefined)) {
  89. /* This shouldn't happen. */
  90. localError("Problem with command key: " + keyPress);
  91. return;
  92. }
  93. typeInTextarea(tags[0], tags[1]);
  94. }
  95. }
  96. document.addEventListener('keydown', formatting, false);
  97. })();