···
2
+
// @name Slack Allow HTTP OAuth urls
3
+
// @namespace https://tangled.sh/@dunkirk.sh/bunplayground/slack-http-allowed
6
+
// @author Kieran Klukas
7
+
// @match https://api.slack.com/apps/*/oauth*
9
+
// @run-at document-end
13
+
// Track HTTP inputs to avoid redundant processing
14
+
const httpInputs = new Set();
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;
23
+
.p-url_table_editor__fields {
24
+
width: calc(100% - 176px) !important;
27
+
document.head.appendChild(styleEl);
30
+
function watchForHTTPEntries() {
31
+
const urlInputs = document.querySelectorAll(
32
+
"[data-url-table-editor-input]",
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;
39
+
input.hasHttpListener = true;
40
+
input.addEventListener("input", function () {
41
+
const row = this.closest("[data-row]");
44
+
const saveButton = row.querySelector(
45
+
'[data-js-url-editor="save-create"]',
47
+
if (!saveButton) return;
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 😈";
56
+
// Add to tracking set
57
+
httpInputs.add(this);
59
+
// Reset to default state if not http://
60
+
saveButton.textContent = "Add";
62
+
// Remove from tracking set
63
+
httpInputs.delete(this);
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", "");
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);
84
+
const row = input.closest("[data-row]");
86
+
httpInputs.delete(input);
90
+
const saveButton = row.querySelector(
91
+
'[data-js-url-editor="save-create"]',
94
+
httpInputs.delete(input);
98
+
// Force the button to stay enabled
99
+
saveButton.classList.remove("disabled");
100
+
saveButton.removeAttribute("disabled");
101
+
saveButton.textContent = "add 😈";
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) {
110
+
mutation.type === "attributes" &&
111
+
(mutation.attributeName === "disabled" ||
112
+
mutation.attributeName === "class")
114
+
const button = mutation.target;
115
+
const row = button.closest("[data-row]");
116
+
if (!row) continue;
118
+
const input = row.querySelector("[data-url-table-editor-input]");
119
+
if (!input || !input.value.trim().startsWith("http://")) continue;
121
+
// This is an HTTP input with a button that was just disabled
122
+
// Re-enable it immediately
124
+
button.classList.contains("disabled") ||
125
+
button.hasAttribute("disabled")
127
+
button.classList.remove("disabled");
128
+
button.removeAttribute("disabled");
129
+
button.textContent = "add 😈";
135
+
// Observe all save buttons for attribute changes
136
+
const saveButtons = document.querySelectorAll(
137
+
'[data-js-url-editor="save-create"]',
139
+
for (const button of saveButtons) {
140
+
buttonObserver.observe(button, { attributes: true });
143
+
return buttonObserver;
146
+
// Run the CSS additions immediately
149
+
// Run the function immediately
150
+
watchForHTTPEntries();
152
+
const buttonObserver = watchButtonAttributes();
154
+
// Then run it again after a delay to ensure DOM is fully loaded
156
+
watchForHTTPEntries();
160
+
// Run the button fix less frequently to reduce browser lag
161
+
setInterval(fixHttpButtons, 1000);
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;
170
+
let hasNewInputs = false;
171
+
let hasNewButtons = false;
173
+
for (const mutation of mutations) {
174
+
if (mutation.addedNodes.length) {
175
+
hasNewInputs = true;
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"]')
184
+
if (newButtons.length > 0) hasNewButtons = true;
190
+
if (hasNewInputs) {
191
+
watchForHTTPEntries();
194
+
if (hasNewButtons) {
195
+
// Observe any new buttons
196
+
const newSaveButtons = document.querySelectorAll(
197
+
'[data-js-url-editor="save-create"]',
199
+
for (const button of newSaveButtons) {
200
+
if (!button.hasAttributeObserver) {
201
+
buttonObserver.observe(button, { attributes: true });
202
+
button.hasAttributeObserver = true;
208
+
inputObserver.isProcessing = false;
212
+
// Start observing the document with fewer things to watch
213
+
inputObserver.observe(document.body, {