-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontent.js
More file actions
512 lines (431 loc) · 16 KB
/
content.js
File metadata and controls
512 lines (431 loc) · 16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
// Store hidden workflows in Chrome storage
let hiddenWorkflows = [];
// Check if we're on the Cloudflare Workflows page
function isWorkflowsPage() {
return window.location.href.includes('cloudflare.com') &&
window.location.href.includes('workers/workflows');
}
// Load hidden workflows from storage
function loadHiddenWorkflows() {
return new Promise((resolve) => {
console.log('Loading hidden workflows from storage');
chrome.storage.sync.get(['hiddenWorkflows'], function(result) {
if (result.hiddenWorkflows) {
hiddenWorkflows = result.hiddenWorkflows;
console.log('Loaded hidden workflows:', hiddenWorkflows);
applyHiddenWorkflows();
} else {
console.log('No hidden workflows found in storage');
hiddenWorkflows = [];
}
resolve(hiddenWorkflows);
});
});
}
// Save hidden workflows to storage
function saveHiddenWorkflows() {
chrome.storage.sync.set({hiddenWorkflows: hiddenWorkflows});
}
// Apply hiding to workflows in the table
function applyHiddenWorkflows() {
console.log('Applying hidden workflows:', hiddenWorkflows);
// Find all workflow rows in the table
const rows = document.querySelectorAll('table[role="table"] tbody tr');
console.log(`Found ${rows.length} rows to process for hiding`);
rows.forEach((row, index) => {
try {
// Get the workflow name from the first cell
const nameCell = row.querySelector('td:first-child');
if (!nameCell) {
console.log(`Row ${index}: No name cell found`);
return;
}
const nameLink = nameCell.querySelector('a');
if (!nameLink) {
console.log(`Row ${index}: No name link found`);
return;
}
const workflowName = nameLink.textContent.trim();
// If this workflow is in our hidden list, hide the row
if (hiddenWorkflows.includes(workflowName)) {
console.log(`Hiding row for workflow: ${workflowName}`);
row.style.cssText = 'display: none !important';
row.classList.add('workflow-hidden');
// Also update any hide buttons to show "Show" text
const hideBtn = row.querySelector('.workflow-hide-btn');
if (hideBtn) {
hideBtn.textContent = 'Show';
}
} else {
console.log(`Showing row for workflow: ${workflowName}`);
row.style.cssText = '';
row.classList.remove('workflow-hidden');
// Also update any hide buttons to show "Hide" text
const hideBtn = row.querySelector('.workflow-hide-btn');
if (hideBtn) {
hideBtn.textContent = 'Hide';
}
}
} catch (error) {
console.error(`Error processing row ${index} for hiding:`, error);
}
});
// Add a style tag to ensure hidden rows stay hidden
ensureHiddenStyle();
}
// Ensure we have a style tag for hidden rows
function ensureHiddenStyle() {
let styleTag = document.getElementById('workflow-hider-styles');
if (!styleTag) {
styleTag = document.createElement('style');
styleTag.id = 'workflow-hider-styles';
styleTag.textContent = `
.workflow-hidden {
display: none !important;
visibility: hidden !important;
}
`;
document.head.appendChild(styleTag);
console.log('Added style tag for hidden workflows');
}
}
// Add hide buttons to each workflow row
function addHideButtons() {
console.log('Adding hide buttons to workflow rows');
// Find the table - try different selectors
const table = document.querySelector('table[role="table"]');
if (!table) {
console.log('No table found on the page');
return;
}
console.log('Found table:', table);
// Find all rows in the table body
const tbody = table.querySelector('tbody');
if (!tbody) {
console.log('No table body found');
return;
}
const rows = tbody.querySelectorAll('tr');
console.log(`Found ${rows.length} rows`);
if (rows.length === 0) {
console.log('No rows found in the table');
return;
}
rows.forEach((row, index) => {
try {
// Get the workflow name from the first cell
const nameCell = row.querySelector('td:first-child');
if (!nameCell) {
console.log(`Row ${index}: No name cell found`);
return;
}
const nameLink = nameCell.querySelector('a');
if (!nameLink) {
console.log(`Row ${index}: No name link found`);
return;
}
const workflowName = nameLink.textContent.trim();
console.log(`Processing workflow: ${workflowName}`);
// Check if we already added a hide button to this row
if (row.querySelector('.workflow-hide-btn')) {
console.log(`Row ${index}: Hide button already exists for ${workflowName}`);
return;
}
// Get the last cell (actions cell)
const lastCell = row.querySelector('td:last-child');
if (!lastCell) {
console.log(`Row ${index}: No last cell found for ${workflowName}`);
return;
}
// Find the existing button in the actions cell
const existingButton = lastCell.querySelector('button');
if (!existingButton) {
console.log(`Row ${index}: No existing button found for ${workflowName}`);
// Try to find the actions container div
const actionsDiv = findActionsDiv(lastCell);
if (actionsDiv) {
addButtonToActionsDiv(actionsDiv, workflowName);
} else {
// If we can't find an actions div, create one
createActionsDiv(lastCell, workflowName);
}
} else {
console.log(`Row ${index}: Found existing button for ${workflowName}`);
// Get the parent div of the existing button
const parentDiv = existingButton.closest('div[class*="c_d"][class*="c_t"]');
if (parentDiv) {
// Add our button next to the existing button
addButtonNextToExisting(parentDiv, workflowName);
} else {
// If we can't find the parent div, add directly to the cell
addButtonToCell(lastCell, workflowName);
}
}
} catch (error) {
console.error(`Error processing row ${index}:`, error);
}
});
}
// Find the actions div in a cell
function findActionsDiv(cell) {
// Try specific selector first
let actionsDiv = cell.querySelector('div.c_d.c_t.c_nf.c_lb');
// If that doesn't work, try more generic selectors
if (!actionsDiv) {
const possibleSelectors = [
'div[class*="c_d"][class*="c_t"][class*="c_nf"]',
'div[class*="c_d"][class*="c_t"]',
'div[class*="c_nf"][class*="c_lb"]'
];
for (const selector of possibleSelectors) {
const divs = cell.querySelectorAll(selector);
if (divs.length > 0) {
// Use the first div that looks like an actions container
for (const div of divs) {
// Check if it has buttons or looks like an actions container
if (div.querySelector('button') ||
div.classList.contains('c_lb') ||
div.classList.contains('c_nf')) {
actionsDiv = div;
break;
}
}
if (actionsDiv) break;
}
}
}
return actionsDiv;
}
// Create an actions div in a cell
function createActionsDiv(cell, workflowName) {
const actionsDiv = document.createElement('div');
actionsDiv.className = 'c_d c_t c_nf c_lb';
cell.appendChild(actionsDiv);
addButtonToActionsDiv(actionsDiv, workflowName);
}
// Add a button to an actions div
function addButtonToActionsDiv(actionsDiv, workflowName) {
// Create hide button
const hideBtn = document.createElement('button');
// Use classes similar to the existing buttons for consistent styling
hideBtn.className = 'workflow-hide-btn c_ng c_nh c_ni c_ae c_nj c_t c_gr c_gs c_gt c_gu c_nk c_nl c_d';
hideBtn.textContent = hiddenWorkflows.includes(workflowName) ? 'Show' : 'Hide';
hideBtn.style.marginLeft = '10px'; // Add some spacing
// Add click event to toggle hiding
hideBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
// Find the row containing this button
const row = actionsDiv.closest('tr');
if (hiddenWorkflows.includes(workflowName)) {
// Remove from hidden list
hiddenWorkflows = hiddenWorkflows.filter(name => name !== workflowName);
hideBtn.textContent = 'Hide';
// Show the row immediately
if (row) row.style.display = '';
} else {
// Add to hidden list
hiddenWorkflows.push(workflowName);
hideBtn.textContent = 'Show';
// Hide the row immediately
if (row) row.style.display = 'none';
}
// Save and apply changes
saveHiddenWorkflows();
applyHiddenWorkflows();
});
// Add button to the actions div
actionsDiv.appendChild(hideBtn);
console.log(`Added hide button for ${workflowName}`);
}
// Add a button next to an existing button
function addButtonNextToExisting(parentDiv, workflowName) {
// Create hide button
const hideBtn = document.createElement('button');
// Use classes similar to the existing buttons for consistent styling
hideBtn.className = 'workflow-hide-btn c_ng c_nh c_ni c_ae c_nj c_t c_gr c_gs c_gt c_gu c_nk c_nl c_d';
hideBtn.textContent = hiddenWorkflows.includes(workflowName) ? 'Show' : 'Hide';
hideBtn.style.marginLeft = '10px'; // Add some spacing
// Add click event to toggle hiding
hideBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
// Find the row containing this button
const row = parentDiv.closest('tr');
if (hiddenWorkflows.includes(workflowName)) {
// Remove from hidden list
hiddenWorkflows = hiddenWorkflows.filter(name => name !== workflowName);
hideBtn.textContent = 'Hide';
// Show the row immediately
if (row) row.style.display = '';
} else {
// Add to hidden list
hiddenWorkflows.push(workflowName);
hideBtn.textContent = 'Show';
// Hide the row immediately
if (row) row.style.display = 'none';
}
// Save and apply changes
saveHiddenWorkflows();
applyHiddenWorkflows();
});
// Add button to the parent div
parentDiv.appendChild(hideBtn);
console.log(`Added hide button next to existing button for ${workflowName}`);
}
// Add a button directly to a cell
function addButtonToCell(cell, workflowName) {
// Create a container div for the button
const buttonContainer = document.createElement('div');
buttonContainer.className = 'c_d c_t c_nf c_lb';
buttonContainer.style.display = 'inline-block';
buttonContainer.style.marginLeft = '10px';
// Create hide button
const hideBtn = document.createElement('button');
// Use classes similar to the existing buttons for consistent styling
hideBtn.className = 'workflow-hide-btn c_ng c_nh c_ni c_ae c_nj c_t c_gr c_gs c_gt c_gu c_nk c_nl c_d';
hideBtn.textContent = hiddenWorkflows.includes(workflowName) ? 'Show' : 'Hide';
// Add click event to toggle hiding
hideBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
// Find the row containing this button
const row = cell.closest('tr');
if (hiddenWorkflows.includes(workflowName)) {
// Remove from hidden list
hiddenWorkflows = hiddenWorkflows.filter(name => name !== workflowName);
hideBtn.textContent = 'Hide';
// Show the row immediately
if (row) row.style.display = '';
} else {
// Add to hidden list
hiddenWorkflows.push(workflowName);
hideBtn.textContent = 'Show';
// Hide the row immediately
if (row) row.style.display = 'none';
}
// Save and apply changes
saveHiddenWorkflows();
applyHiddenWorkflows();
});
// Add button to the container div
buttonContainer.appendChild(hideBtn);
// Add container to the cell
cell.appendChild(buttonContainer);
console.log(`Added hide button directly to cell for ${workflowName}`);
}
// Main function to initialize the extension
function initExtension() {
console.log('Cloudflare Workflow Hider: Extension initialized');
// Only run on the Workflows page
if (!isWorkflowsPage()) {
console.log('Not on Workflows page, extension not running');
return;
}
console.log('On Workflows page, running extension');
// Load hidden workflows first, then add buttons and apply hiding
loadHiddenWorkflows().then(() => {
// Add hide buttons to the table and apply hiding
setTimeout(() => {
addHideButtons();
applyHiddenWorkflows(); // Apply hiding after adding buttons
console.log('Cloudflare Workflow Hider: Added hide buttons and applied hiding');
}, 1000); // Wait a bit for the page to fully load
// Try again after a longer delay to catch any late-loading content
setTimeout(() => {
addHideButtons();
applyHiddenWorkflows(); // Apply hiding again after a longer delay
console.log('Cloudflare Workflow Hider: Second attempt to add buttons and apply hiding');
}, 3000);
// Set up a mutation observer to handle dynamically loaded content
setupTableObserver();
});
}
// Set up a mutation observer specifically for the table
function setupTableObserver() {
console.log('Setting up table observer');
// Function to find the table and set up an observer for it
function findTableAndObserve() {
const table = document.querySelector('table[role="table"]');
if (table) {
console.log('Found table, setting up observer');
// Create an observer instance
const tableObserver = new MutationObserver((mutations) => {
console.log('Table mutation detected:', mutations.length, 'changes');
// When table changes, reapply hiding and add buttons
addHideButtons();
applyHiddenWorkflows();
});
// Start observing the table with all its child nodes
tableObserver.observe(table, {
childList: true,
subtree: true,
attributes: false,
characterData: false
});
console.log('Table observer set up successfully');
return true;
}
return false;
}
// Try to find the table immediately
if (!findTableAndObserve()) {
console.log('Table not found initially, setting up body observer');
// If table is not found, observe the body for changes
const bodyObserver = new MutationObserver((mutations) => {
console.log('Body mutation detected, checking for table');
if (findTableAndObserve()) {
// Once we've found the table and set up its observer, disconnect the body observer
bodyObserver.disconnect();
console.log('Body observer disconnected after finding table');
}
});
// Start observing the body
bodyObserver.observe(document.body, {
childList: true,
subtree: true,
attributes: false,
characterData: false
});
console.log('Body observer set up to find table');
}
}
// Run the extension when the page is loaded
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initExtension);
} else {
initExtension();
}
// Also listen for page changes via the History API
window.addEventListener('popstate', () => {
console.log('Navigation detected via popstate');
if (isWorkflowsPage()) {
setTimeout(() => {
console.log('Reapplying extension after navigation');
addHideButtons();
applyHiddenWorkflows();
setupTableObserver();
}, 1000);
}
});
// Listen for messages from the popup or background script
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
console.log('Message received:', request);
if (request.action === 'getHiddenWorkflows') {
// Return the list of hidden workflows
sendResponse({hiddenWorkflows: hiddenWorkflows});
} else if (request.action === 'clearAllHidden') {
// Clear all hidden workflows
hiddenWorkflows = [];
saveHiddenWorkflows();
applyHiddenWorkflows();
sendResponse({success: true});
} else if (request.action === 'forceAddButtons') {
// Force add hide buttons
addHideButtons();
applyHiddenWorkflows(); // Apply hiding after adding buttons
setupTableObserver(); // Re-setup the table observer
sendResponse({success: true});
}
return true; // Keep the message channel open for async response
});