TEXT   270   0
   577 5.97 KB    233

FlagRandomizer.js

By Script_Filly
Created: 2022-01-19 02:15:55
Updated: 2022-01-25 11:34:59
Expiry: Never

  1. 1.
    // ==UserScript==
  2. 2.
    // @name Flag Randomizer
  3. 3.
  4. 4.
  5. 5.
  6. 6.
    // @grant none
  7. 7.
    // @version 0.2.3
  8. 8.
    // @author Fillyanon, ScriptFilly, RandomSchmuck, Marker
  9. 9.
    // @description Adds a flag randomizer to the Board.
  10. 10.
    // ==/UserScript==
  11. 11.
     
  12. 12.
    "use strict";
  13. 13.
     
  14. 14.
    // Possible values are: Submit, Keystroke, Timer
  15. 15.
    const changeFlagOn = "Submit";
  16. 16.
     
  17. 17.
    const flags = Object.freeze({
  18. 18.
    MISC: ["4CC", "AN"],
  19. 19.
     
  20. 20.
    G4: [
  21. 21.
    "AJ",
  22. 22.
    "ANF",
  23. 23.
    "APB",
  24. 24.
    "AU",
  25. 25.
    "BB",
  26. 26.
    "BM",
  27. 27.
    "BP",
  28. 28.
    "BS",
  29. 29.
    "CB",
  30. 30.
    "CG",
  31. 31.
    "CHE",
  32. 32.
    "CL",
  33. 33.
    "CO",
  34. 34.
    "DAY",
  35. 35.
    "DD",
  36. 36.
    "DER",
  37. 37.
    "DIS",
  38. 38.
    "DT",
  39. 39.
    "FAU",
  40. 40.
    "FL",
  41. 41.
    "FLE",
  42. 42.
    "GI",
  43. 43.
    "LI",
  44. 44.
    "LT",
  45. 45.
    "LY",
  46. 46.
    "MA",
  47. 47.
    "MAU",
  48. 48.
    "MIN",
  49. 49.
    "NI",
  50. 50.
    "NUR",
  51. 51.
    "OCT",
  52. 52.
    "PAR",
  53. 53.
    "PC",
  54. 54.
    "PCE",
  55. 55.
    "PI",
  56. 56.
    "PLU",
  57. 57.
    "PM",
  58. 58.
    "QC",
  59. 59.
    "RAR",
  60. 60.
    "RD",
  61. 61.
    "RLU",
  62. 62.
    "S1L",
  63. 63.
    "SCO",
  64. 64.
    "SHI",
  65. 65.
    "SIL",
  66. 66.
    "SP",
  67. 67.
    "SPI",
  68. 68.
    "STA",
  69. 69.
    "STL",
  70. 70.
    "SUN",
  71. 71.
    "SUS",
  72. 72.
    "SWB",
  73. 73.
    "TS",
  74. 74.
    "TWI",
  75. 75.
    "TX",
  76. 76.
    "VS",
  77. 77.
    "ZE",
  78. 78.
    ],
  79. 79.
     
  80. 80.
    G5: ["HT", "IZ", "PP", "SPT", "ZS", "SS"],
  81. 81.
     
  82. 82.
    EQG: [
  83. 83.
    "ADA",
  84. 84.
    "AB",
  85. 85.
    "SON",
  86. 86.
    "EQA",
  87. 87.
    "EQF",
  88. 88.
    "EQP",
  89. 89.
    "EQR",
  90. 90.
    "EQT",
  91. 91.
    "EQI",
  92. 92.
    "EQS",
  93. 93.
    "ERA",
  94. 94.
    ],
  95. 95.
     
  96. 96.
    TFH: ["TFA", "TFO", "TFP", "TFS", "TFT", "TFV", "TP"],
  97. 97.
    });
  98. 98.
     
  99. 99.
    const allFlags = Object.values(flags).flat();
  100. 100.
     
  101. 101.
    const getRand = (coll) => {
  102. 102.
    return coll[Math.floor(Math.random() * coll.length)];
  103. 103.
    };
  104. 104.
     
  105. 105.
    const getPost = () => {
  106. 106.
    const use4chanX = document.getElementById("qr");
  107. 107.
    const quickReply = document.getElementById("qrForm");
  108. 108.
    const qrForm = use4chanX ?? quickReply;
  109. 109.
    return qrForm ?? document.forms.post;
  110. 110.
    };
  111. 111.
     
  112. 112.
    const changeFlag = () => {
  113. 113.
    if (selector.value == "OFF") return;
  114. 114.
    const post = getPost();
  115. 115.
    const flagSelector = post.querySelector(".flagSelector");
  116. 116.
    const origValue = flagSelector.value;
  117. 117.
    flagSelector.value = (selector.value != "ALL") ? getRand(flags[selector.value]) : getRand(allFlags);
  118. 118.
     
  119. 119.
    // Workaround for 4chanX issue where its flag selector is 3 missing flags.
  120. 120.
    // Attempting to assign a Selector to an option that doesn't exist would
  121. 121.
    // reset it's value to "".
  122. 122.
    // When this happens, we restore it to its initial value.
  123. 123.
    if (flagSelector.value == "") flagSelector.value = origValue;
  124. 124.
    };
  125. 125.
     
  126. 126.
    const makeOpt = (option) => {
  127. 127.
    const opt = document.createElement("option");
  128. 128.
    opt.value = opt.innerText = option;
  129. 129.
    selector.appendChild(opt);
  130. 130.
    };
  131. 131.
     
  132. 132.
    const selector = document.createElement('select');
  133. 133.
    const botLine = document.querySelector('.navLinksBot');
  134. 134.
    selector.style.marginLeft = '1rem';
  135. 135.
    Object.keys(flags).forEach(key => makeOpt(key));
  136. 136.
    makeOpt('ALL');
  137. 137.
    makeOpt('OFF');
  138. 138.
    selector.addEventListener('change', () => {
  139. 139.
    window.localStorage.setItem("flagGroup", selector.value);
  140. 140.
    });
  141. 141.
    selector.value = window.localStorage.getItem("flagGroup") ?? "G4";
  142. 142.
    botLine.appendChild(selector);
  143. 143.
     
  144. 144.
    // Setup Randomizer Functions
  145. 145.
     
  146. 146.
    const creationObserver = (function () {
  147. 147.
    const observedNodes = [];
  148. 148.
    const callbacks = [];
  149. 149.
    const executeCallback = (fn, node) => {
  150. 150.
    if (observedNodes.includes(node))
  151. 151.
    return;
  152. 152.
    observedNodes.push(node);
  153. 153.
    fn(node);
  154. 154.
    };
  155. 155.
    const obs = new MutationObserver(mutationRecords => {
  156. 156.
    mutationRecords.forEach(mutation => {
  157. 157.
    mutation.addedNodes.forEach(node => {
  158. 158.
    if (!(node instanceof HTMLElement))
  159. 159.
    return;
  160. 160.
    callbacks.forEach(([selector, fn]) => {
  161. 161.
    if (node.matches(selector))
  162. 162.
    executeCallback(fn, node);
  163. 163.
    node.querySelectorAll(selector).forEach(childNode => executeCallback(fn, childNode));
  164. 164.
    });
  165. 165.
    });
  166. 166.
    });
  167. 167.
    });
  168. 168.
    obs.observe(document.body, { childList: true, subtree: true });
  169. 169.
    return function (selector, fn) {
  170. 170.
    document.querySelectorAll(selector).forEach(node => executeCallback(fn, node));
  171. 171.
    callbacks.push([selector, fn]);
  172. 172.
    };
  173. 173.
    })();
  174. 174.
     
  175. 175.
    const selectors = [
  176. 176.
    'form[name="post"]', // 4chan default post
  177. 177.
    'form[name="qrPost"]', // 4chanNX quick reply form
  178. 178.
    'div#qr form', // 4chanX quick reply form
  179. 179.
    ].join(', ');
  180. 180.
     
  181. 181.
    // Keystroke
  182. 182.
    function debounce(func, wait, immediate) {
  183. 183.
    let timeout;
  184. 184.
    return function () {
  185. 185.
    const context = this, args = arguments;
  186. 186.
    const later = function () {
  187. 187.
    timeout = null;
  188. 188.
    if (!immediate) func.apply(context, args);
  189. 189.
    };
  190. 190.
    const callNow = immediate && !timeout;
  191. 191.
    clearTimeout(timeout);
  192. 192.
    timeout = setTimeout(later, wait);
  193. 193.
    if (callNow) func.apply(context, args);
  194. 194.
    };
  195. 195.
    }
  196. 196.
    const changeAfterKeystroke = debounce(changeFlag, 250, false);
  197. 197.
    const config = {attributes: true, childList: true, subtree: true};
  198. 198.
     
  199. 199.
    // Randomize the flag
  200. 200.
    if (changeFlagOn === "Keystroke") {
  201. 201.
    const keystrokeHandler = function() {
  202. 202.
    const is4chanXQrActive = document.getElementById("qr");
  203. 203.
    const post = getPost();
  204. 204.
     
  205. 205.
    // update the flag
  206. 206.
    const reply = (is4chanXQrActive)
  207. 207.
    ? post.querySelector("textarea[data-name=\"com\"]")
  208. 208.
    : post.querySelector("textarea[name=\"com\"]");
  209. 209.
    reply.addEventListener("input", changeAfterKeystroke);
  210. 210.
    }
  211. 211.
    creationObserver(selectors, form => {
  212. 212.
    if (!(form instanceof HTMLFormElement))
  213. 213.
    return;
  214. 214.
    keystrokeHandler();
  215. 215.
    });
  216. 216.
    } else if (changeFlagOn === "Timer") {
  217. 217.
    setInterval(() => {
  218. 218.
    changeFlag();
  219. 219.
    }, 500);
  220. 220.
    } else if (changeFlagOn === "Submit") {
  221. 221.
    const submitHandler = (event) => {
  222. 222.
    const target = event.target;
  223. 223.
    if (!target.matches('input[type="submit"]'))
  224. 224.
    return;
  225. 225.
    const form = event.currentTarget;
  226. 226.
    changeFlag(form);
  227. 227.
    }
  228. 228.
    creationObserver(selectors, form => {
  229. 229.
    if (!(form instanceof HTMLFormElement))
  230. 230.
    return;
  231. 231.
    form.addEventListener('click', submitHandler, { capture: true });
  232. 232.
    });
  233. 233.
    }

FlagRandomizer.js

by Script_Filly