random bun scripts that dont fit anywhere else
1// ==UserScript==
2// @name Slack Allow HTTP OAuth urls
3// @namespace https://tangled.sh/@dunkirk.sh/bunplayground/slack-http-allowed
4// @version 0.1
5// @description
6// @author Kieran Klukas
7// @match https://api.slack.com/apps/*/oauth*
8// @grant none
9// @run-at document-end
10// ==/UserScript==
11
12(() => {
13 // Track HTTP inputs to avoid redundant processing
14 const httpInputs = new Set();
15
16 // Add CSS to style the editor table layout
17 function addCustomStyles() {
18 const styleEl = document.createElement("style");
19 styleEl.textContent = `
20 .p-url_table_editor__actions {
21 width: 176px !important;
22 }
23 .p-url_table_editor__fields {
24 width: calc(100% - 176px) !important;
25 }
26 `;
27 document.head.appendChild(styleEl);
28 }
29
30 function watchForHTTPEntries() {
31 const urlInputs = document.querySelectorAll(
32 "[data-url-table-editor-input]",
33 );
34
35 // Add event listeners to each input field that doesn't already have one
36 for (const input of urlInputs) {
37 if (input.hasHttpListener) continue;
38
39 input.hasHttpListener = true;
40 input.addEventListener("input", function () {
41 const row = this.closest("[data-row]");
42 if (!row) return;
43
44 const saveButton = row.querySelector(
45 '[data-js-url-editor="save-create"]',
46 );
47 if (!saveButton) return;
48
49 // Check if input contains http:// (non-https URL)
50 if (this.value.trim().startsWith("http://")) {
51 // Make the button sassy and green
52 saveButton.classList.remove("disabled");
53 saveButton.removeAttribute("disabled");
54 saveButton.textContent = "add 😈";
55
56 // Add to tracking set
57 httpInputs.add(this);
58 } else {
59 // Reset to default state if not http://
60 saveButton.textContent = "Add";
61
62 // Remove from tracking set
63 httpInputs.delete(this);
64
65 // Only re-disable if empty (assuming that's the original logic)
66 if (!this.value.trim()) {
67 saveButton.classList.add("disabled");
68 saveButton.setAttribute("disabled", "");
69 }
70 }
71 });
72 }
73 }
74
75 // Function to specifically fix HTTP buttons that might have been disabled
76 function fixHttpButtons() {
77 // Only process inputs we know have HTTP URLs
78 for (const input of httpInputs) {
79 if (!input.value.trim().startsWith("http://")) {
80 httpInputs.delete(input);
81 continue;
82 }
83
84 const row = input.closest("[data-row]");
85 if (!row) {
86 httpInputs.delete(input);
87 continue;
88 }
89
90 const saveButton = row.querySelector(
91 '[data-js-url-editor="save-create"]',
92 );
93 if (!saveButton) {
94 httpInputs.delete(input);
95 continue;
96 }
97
98 // Force the button to stay enabled
99 saveButton.classList.remove("disabled");
100 saveButton.removeAttribute("disabled");
101 saveButton.textContent = "add 😈";
102 }
103 }
104
105 // Watch for attribute changes on buttons to detect when they're disabled again
106 function watchButtonAttributes() {
107 const buttonObserver = new window.MutationObserver((mutations) => {
108 for (const mutation of mutations) {
109 if (
110 mutation.type === "attributes" &&
111 (mutation.attributeName === "disabled" ||
112 mutation.attributeName === "class")
113 ) {
114 const button = mutation.target;
115 const row = button.closest("[data-row]");
116 if (!row) continue;
117
118 const input = row.querySelector("[data-url-table-editor-input]");
119 if (!input || !input.value.trim().startsWith("http://")) continue;
120
121 // This is an HTTP input with a button that was just disabled
122 // Re-enable it immediately
123 if (
124 button.classList.contains("disabled") ||
125 button.hasAttribute("disabled")
126 ) {
127 button.classList.remove("disabled");
128 button.removeAttribute("disabled");
129 button.textContent = "add 😈";
130 }
131 }
132 }
133 });
134
135 // Observe all save buttons for attribute changes
136 const saveButtons = document.querySelectorAll(
137 '[data-js-url-editor="save-create"]',
138 );
139 for (const button of saveButtons) {
140 buttonObserver.observe(button, { attributes: true });
141 }
142
143 return buttonObserver;
144 }
145
146 // Run the CSS additions immediately
147 addCustomStyles();
148
149 // Run the function immediately
150 watchForHTTPEntries();
151 fixHttpButtons();
152 const buttonObserver = watchButtonAttributes();
153
154 // Then run it again after a delay to ensure DOM is fully loaded
155 setTimeout(() => {
156 watchForHTTPEntries();
157 fixHttpButtons();
158 }, 1000);
159
160 // Run the button fix less frequently to reduce browser lag
161 setInterval(fixHttpButtons, 1000);
162
163 // Observer for new inputs
164 const inputObserver = new window.MutationObserver((mutations) => {
165 // Throttle the observer callback
166 if (inputObserver.isProcessing) return;
167 inputObserver.isProcessing = true;
168
169 setTimeout(() => {
170 let hasNewInputs = false;
171 let hasNewButtons = false;
172
173 for (const mutation of mutations) {
174 if (mutation.addedNodes.length) {
175 hasNewInputs = true;
176
177 // Check if any new save buttons were added
178 for (const node of mutation.addedNodes) {
179 if (node.nodeType === 1) {
180 // Node.ELEMENT_NODE is 1
181 const newButtons = node.querySelectorAll
182 ? node.querySelectorAll('[data-js-url-editor="save-create"]')
183 : [];
184 if (newButtons.length > 0) hasNewButtons = true;
185 }
186 }
187 }
188 }
189
190 if (hasNewInputs) {
191 watchForHTTPEntries();
192 }
193
194 if (hasNewButtons) {
195 // Observe any new buttons
196 const newSaveButtons = document.querySelectorAll(
197 '[data-js-url-editor="save-create"]',
198 );
199 for (const button of newSaveButtons) {
200 if (!button.hasAttributeObserver) {
201 buttonObserver.observe(button, { attributes: true });
202 button.hasAttributeObserver = true;
203 }
204 }
205 }
206
207 fixHttpButtons();
208 inputObserver.isProcessing = false;
209 }, 200);
210 });
211
212 // Start observing the document with fewer things to watch
213 inputObserver.observe(document.body, {
214 childList: true,
215 subtree: true,
216 });
217})();