AO3: [Wrangling] Rainbow Tables

adds CSS classes to style table rows as a rainbow, and updates dynamically when filters are applied

  1. // ==UserScript==
  2. // @name AO3: [Wrangling] Rainbow Tables
  3. // @namespace https://greasyfork.org/en/users/906106-escctrl
  4. // @description adds CSS classes to style table rows as a rainbow, and updates dynamically when filters are applied
  5. // @author escctrl
  6. // @version 6.0
  7. // @match *://*.archiveofourown.org/tag_wranglers/*
  8. // @match *://*.archiveofourown.org/tags/*/wrangle?*
  9. // @match *://*.archiveofourown.org/tags/search?*
  10. // @require https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js
  11. // @license MIT
  12. // ==/UserScript==
  13. // CONFIGURATION
  14. // choose if you want to use your AO3 skin to define the colors (skin), or if you'll add the css in this script (script)
  15. // if you use a skin, note that the classes are added to the table rows (tr) and named .rainbow0 through .rainbow5
  16. const SOURCE = 'script';
  17. // choose if you'd like the rainbow coloring on the wrangling homepage and/or on the bins
  18. const ONHOMEPAGE = true;
  19. const ONBINS = true;
  20. const ONSEARCH = true;
  21. // set the six different background colors here, for example "rgba(255, 21, 164, 0.86)" or "#ff15a4"
  22. // tip: rgba let's you define the color in order red-green-blue. the fourth number (alpha) is transparency between 0 (transparent) and 1 (opaque)
  23. const RAINBOW = ["rgba(246, 48, 63, .2)",
  24. "rgba(241, 137, 4, .2)",
  25. "rgba(253, 221, 0, .2)",
  26. "rgba(119, 189, 30, .2)",
  27. "rgba( 1, 152, 207, .2)",
  28. "rgba(114, 32, 130, .2)" ];
  29. const TEXT = "#000000"; // color of the link text in the table
  30. const BORDER = "#FFFFFF"; // color of the borders in the table
  31. const HIGHLIGHT = "#FFFFFF"; // background color of the highlighted row (on mouseover)
  32. (function($) {
  33. 'use strict';
  34.  
  35. let main = $('#main');
  36. // quit script if this page is disabled
  37. if (ONHOMEPAGE === false && $(main).hasClass('tag_wranglers-show')) return;
  38. if (ONBINS === false && $(main).hasClass('tags-wrangle')) return;
  39. if (ONSEARCH === false && $(main).hasClass('tags-search')) return;
  40. if (SOURCE == 'script') {
  41. var fullCSS = RAINBOW.map((e, i) => ".rainbow"+i+" { background-color: "+e+"; color: inherit !important }" );
  42. $('head').append(`<style type="text/css">
  43. .assigned thead th, #wrangulator thead th { text-align: center; vertical-align: bottom; }
  44. .assigned thead, #wrangulator thead, #resulttable thead { border-bottom: 0px; }
  45. .assigned tbody th { background: transparent !important; border: 1px solid ${BORDER}; vertical-align: middle; padding: 0.2em 0.5em; }
  46. .assigned tbody td { vertical-align: middle; border: 1px solid ${BORDER}; padding: 0.2em 0.5em; text-align: right; }
  47. #wrangulator tbody th, #resulttable tbody th { background: transparent !important; border: 1px solid ${BORDER}; vertical-align: middle; }
  48. #wrangulator tbody td, #resulttable tbody td { vertical-align: middle; border: 1px solid ${BORDER}; }
  49. .assigned tbody tr:hover, #wrangulator tbody tr:hover, #resulttable tr:hover { background-color: ${HIGHLIGHT}; }
  50. .assigned tbody a, #wrangulator tbody a, #resulttable tbody a,
  51. .assigned tbody a:hover, #wrangulator tbody a:hover, #resulttable tbody a:hover,
  52. .assigned tbody a:visited, #wrangulator tbody a:visited, #resulttable tbody a:visited,
  53. .assigned tbody a:active, #wrangulator tbody a:active, #resulttable tbody a:active {
  54. color: ${TEXT}; border-bottom: 0; }
  55. #resulttable tbody a:hover { background-color: unset; }
  56. ${fullCSS.join(' ')}
  57. </style>`);
  58. }
  59. function resetRainbow() {
  60. $('.assigned tbody tr, #wrangulator tbody tr, #resulttable tbody tr').removeClass('rainbow0 rainbow1 rainbow2 rainbow3 rainbow4 rainbow5');
  61. $('.assigned tbody tr:visible, #wrangulator tbody tr:visible, #resulttable tbody tr').each( (it, row) => $(row).addClass('rainbow'+it%6) );
  62. }
  63. if (ONHOMEPAGE === true && $(main).hasClass('tag_wranglers-show')) {
  64. // add events for dynamic updates of the CSS classes when filters are applied. delegated to allow any script order
  65. $(document).on('click', 'p:contains(Show only fandoms with) a', resetRainbow); // Standard (doesn't specify a p#id so we have to go by text content)
  66. $(document).on('click', '#filter-fandoms *', resetRainbow); // Redux
  67. $(document).on('click', '#media-filter a, #source-filter a, #fandom-filter a, #setup-filter a, #reset-filter a', resetRainbow); // N-in-1
  68. $(document).on('click', '#sortunwrangled, #sortname, #sortchars, #sortrels, #sortff', resetRainbow); // Sorting by Total Unwrangled
  69. $(document).on('click', 'p:contains(Show:) a, tr a:contains([Snooze])', resetRainbow); // Snooze fandom buttons/filters
  70. // Search
  71. $(document).on('keyup', '#fandom_search', resetRainbow);
  72. }
  73. if (ONBINS === true && $(main).hasClass('tags-wrangle')) {
  74. // Snooze "Drafts" button is "slow" because it loads a bunch of pages in the background, and needs a little bit of a delay
  75. // has to use document for delegation because the snooze script removes the button before it bubbles up to #wrangulator (!?!?)
  76. $(document).on('click', 'a#snooze_drafts', function(e) { setTimeout(resetRainbow, 500); });
  77. // other snooze buttons/filters are pretty instantaneous
  78. $('#wrangulator').on('click', 'td[title="snooze"] a, p:contains(Show:) a', function(e) { setTimeout(resetRainbow, 10); } );
  79. }
  80. if (ONSEARCH === true && $(main).hasClass('tags-search')) {
  81. // Fetch All Tag Info script still allows some reordering within the results page
  82. $(document).on('click', '#resulttable thead th', resetRainbow);
  83. }
  84. $(document).ready(function() {
  85. // executes on page load for initial coloring
  86. resetRainbow();
  87. });
  88. })(jQuery);