AO3: Autocomplete in Menu Search Field

Turns the general search in the menu bar into an autocomplete for any canonical tags

  1. // ==UserScript==
  2. // @name AO3: Autocomplete in Menu Search Field
  3. // @namespace https://greasyfork.org/en/users/906106-escctrl
  4. // @description Turns the general search in the menu bar into an autocomplete for any canonical tags
  5. // @author escctrl
  6. // @version 1.0
  7. // @match *://*.archiveofourown.org/*
  8. // @grant none
  9. // @require https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js
  10. // @require https://update.greasyfork.org/scripts/491888/1355841/Light%20or%20Dark.js
  11. // @license MIT
  12. // ==/UserScript==
  13.  
  14. /* eslint-disable no-multi-spaces */
  15. /* global jQuery, lightOrDark */
  16.  
  17. (function($) {
  18. 'use strict';
  19.  
  20. // styling the autocomplete (because #header has some CSS that interferes we have to set it explicitly)
  21. let border, bg, text, bgHover, textHover = "";
  22.  
  23. // official site skins are <link>'ed, default with various medias, others with media="all"; user site skins are inserted directly with <style>
  24. var skin = $('link[href^="/stylesheets/skins/"][media="all"]');
  25. // default site skin means there's no media="all", for others there should be exactly one
  26. if (skin.length === 1) skin = $(skin).attr("href").match(/skin_(\d+)_/);
  27. skin = skin[1] || "";
  28.  
  29. // In case of non-public site skins, checks if using a dark mode by calculating the 'brightness' of the page background color
  30. if (skin === "") skin = lightOrDark(window.getComputedStyle(document.body).backgroundColor);
  31.  
  32. switch (skin) {
  33. case "929": // reversi
  34. case "dark":
  35. border = "#222";
  36. bg = "rgb(42, 42, 42)";
  37. text = "#fff";
  38. bgHover = "rgb(17, 17, 17)";
  39. textHover = "#fff";
  40. break;
  41. case "932": // snow blue
  42. case "891": // low vision
  43. case "light":
  44. default: // default site skin
  45. border = "#888";
  46. bg = "#ddd";
  47. text = "#2a2a2a";
  48. bgHover = "rgba(255, 255, 255, 0.25)";
  49. textHover = "#111";
  50. break;
  51. }
  52.  
  53. $('header').append(`<style type="text/css">
  54. #general_search_autocomplete { width: 20em; margin-right: 1em; padding: 0.125em; border-radius: 1em; }
  55. #header .search li.input { margin: 0; }
  56. #header .autocomplete.dropdown { display: block; border: 1px solid ${border}; background-color: ${bg}; }
  57. #header .autocomplete.dropdown ul { box-shadow: none; border: 0; background-color: transparent; }
  58. #header .autocomplete.dropdown li { display: list-item; float: none; text-align: left; padding: 0.125em 0.25em; color: ${text}; }
  59. #header .autocomplete.dropdown li:hover { color: ${textHover}; background-color: ${bgHover}; cursor: pointer; }
  60. </style>`);
  61.  
  62. // grab the <li> in which general search sits
  63. let liSearch = $('#header').find('nav[aria-label="Site"] li.search');
  64.  
  65. // replace the general search form with an autocomplete field for any canonical tag
  66. $(liSearch).html(`<form>
  67. <input class="autocomplete" data-autocomplete-method="/autocomplete/tag" data-autocomplete-hint-text="Start typing to search for a tag!"
  68. data-autocomplete-no-results-text="(No suggestions found)" data-autocomplete-min-chars="1" data-autocomplete-searching-text="Searching..." type="text"
  69. data-autocomplete-token-limit="1" data-autocomplete-value="" id="general_search" style="width: 20em;">
  70. </form>`);
  71.  
  72. // listen to the autocomplete - if a tag is selected, we navigate to its /works page
  73. $(liSearch).on('blur', '#general_search_autocomplete', function(e) {
  74. let liAddedTag = $(liSearch).find('li.added.tag').toArray();
  75.  
  76. // if there's actually a tag that was selected, we can continue
  77. if (liAddedTag.length !== 0) {
  78. let tagName = liAddedTag[0].firstChild.textContent.trim(); // pure tagname without the x delete link
  79. tagName = tagName.replaceAll("/", "*s*").replaceAll(".", "*d*").replaceAll("?", "*q*").replace("#", "*h*").replace('"', '&quot;'); // replacing the AO3 specific stuff in URLs
  80.  
  81. window.location.assign(`${window.location.origin}/tags/${tagName}/works`);
  82. }
  83. });
  84.  
  85.  
  86. })(jQuery);