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