AO3: Add Paragraph Breaks

Convert line breaks to paragraphs on Archive of our Own fics

  1. // ==UserScript==
  2. // @name AO3: Add Paragraph Breaks
  3. // @description Convert line breaks to paragraphs on Archive of our Own fics
  4. // @author the_wanlorn
  5. // @version 1.0
  6. // @license MIT
  7. // @grant GM_getValue
  8. // @grant GM_setValue
  9. // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js
  10. // @require https://openuserjs.org/src/libs/sizzle/GM_config.js
  11. // @include https://archiveofourown.org/works/*
  12. // @include https://archiveofourown.org/*/works/*
  13. // @include http://archiveofourown.org/works/*
  14. // @include http://archiveofourown.org/*/works/*
  15. // @namespace https://greasyfork.org/users/844343
  16. // ==/UserScript==
  17.  
  18. (function ($) {
  19. var frame = document.createElement('div');
  20. document.body.appendChild(frame);
  21.  
  22. var gmc = new GM_configStruct({
  23. 'id': 'ao3_add_paragraphs',
  24. 'title': 'AO3: Add Paragraphs Settings',
  25. 'fields': {
  26. 'autoFormat': {
  27. 'label': 'Auto-Format Fics',
  28. 'type': 'checkbox',
  29. 'default': false
  30. },
  31. 'doubleBreaks': {
  32. 'label': 'Convert single paragraph breaks to double paragraph breaks',
  33. 'type': 'checkbox',
  34. 'default': false
  35. }
  36. },
  37. 'frame': frame,
  38. 'events': {
  39. 'open': addStyling,
  40. 'save': function () { gmc.close(); },
  41. 'close': initFormat,
  42. 'reset': function () { gmc.save(); }
  43. }
  44. });
  45.  
  46. initFormat();
  47.  
  48. /**
  49. * Add UI elements and potentially format the page, if autoformatting is
  50. * turned on.
  51. */
  52. function initFormat() {
  53. var auto_format = gmc.get('autoFormat'),
  54. double_breaks = gmc.get('doubleBreaks');
  55.  
  56. if (auto_format) {
  57. formatPage(double_breaks);
  58. }
  59.  
  60. addLinks(auto_format);
  61. }
  62.  
  63. /**
  64. * Add UI elements
  65. *
  66. * @param {bool} auto_format Whether the page is to be formatted automatically.
  67. */
  68. function addLinks(auto_format) {
  69. var $header_menu = $('ul.primary.navigation.actions'),
  70. $menu_link = $('.ao3_add_pars_settings'),
  71. $format_button = $('.ao3_add_pars');
  72.  
  73. // If we don't already have a menu link there, add it.
  74. if ($menu_link.length === 0) {
  75. $menu_link = $('<li class="ao3_add_pars_settings dropdown"></li>').html('<a>Format Settings</a>');
  76. $header_menu.find('li.search').before($menu_link);
  77. $menu_link.on('click', function () {
  78. // Remove the open class since it's not actually a dropdown, we're just
  79. // cribbing the styling.
  80. $(this).toggleClass('open');
  81. // Open the settings dialogue
  82. gmc.open();
  83. });
  84. }
  85.  
  86. // If we're not autoformatting the page, add a button to trigger it.
  87. if (!auto_format && $format_button.length === 0) {
  88. $format_button = $('<input class="button ao3_add_pars" type="button" value="Format Page"></input>');
  89. $format_button.css('marginLeft', '1em').css('marginRight', '1em');
  90. $header_menu.find('#search').prepend($format_button);
  91. $format_button.on('click', function() {
  92. var double_breaks = gmc.get('doubleBreaks');
  93. formatPage(double_breaks);
  94. });
  95. }
  96. // Otherwise, if we are autoformatting, get rid of the button.
  97. else if (auto_format && $format_button) {
  98. $format_button.remove();
  99. }
  100. }
  101.  
  102. /**
  103. * Replace the current tags with the new tags.
  104. *
  105. * @param {bool} double Whether to add a double <br> tag to already-existing <p> tags.
  106. */
  107. function formatPage(double) {
  108. var $chapters = $('#chapters'),
  109. html_string = $chapters.html();
  110.  
  111. if (double) {
  112. html_string = html_string.replaceAll('</p>', '<dblbrkspc></p>');
  113. }
  114.  
  115. html_string = html_string.replaceAll('<br>', '</p><p>');
  116.  
  117. if (double) {
  118. html_string = html_string.replaceAll('<dblbrkspc>', '<br /><br />');
  119. }
  120.  
  121. $chapters.html(html_string);
  122. }
  123.  
  124. /**
  125. * Add the required styling to the settings dialogue.
  126. *
  127. * @param {Object} document The document the given frame is in.
  128. * @param {Object} window The window of the given frame.
  129. * @param {Object} frame The frame to add styling to.
  130. */
  131. function addStyling(document, window, frame) {
  132. var frame_style = 'border: 1px solid #000; left: 50%; position: fixed; '
  133. + 'top: 50%; width: 310px; z-index: 9999; transform: translate(-50%, -50%);',
  134. $frame_obj = $(frame);
  135.  
  136. $frame_obj.attr('style', frame_style);
  137. $frame_obj.find('#ao3_add_paragraphs_closeBtn').hide();
  138. $frame_obj.find('.field_label').css({"font-size": "1em", "font-weight": "400"});
  139. $frame_obj.find('.config_header').css({"font-size": "2em", "paddingBottom": "1em"});
  140. $frame_obj.find('.config_var').css({"margin": "0 0 10px 40px", "position": "relative"});
  141. $frame_obj.find('input[type="checkbox"]').css({"position": "absolute", "left": "-25px", "top": "0"});
  142. }
  143. })(jQuery);