From 72a15ea03e076e081eaffca76c0bb84899b59c5e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Sep 2025 02:57:05 +0000 Subject: [PATCH 01/18] Initial plan From a53cbba2cf520e4e224635ec141d17fe539dc919 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Sep 2025 03:01:42 +0000 Subject: [PATCH 02/18] Add retry mechanism and skip user interactions setting Co-authored-by: ZaxLofful <33877007+ZaxLofful@users.noreply.github.com> --- powerdeletesuite.js | 93 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 17 deletions(-) diff --git a/powerdeletesuite.js b/powerdeletesuite.js index bfca90d..c28d01a 100644 --- a/powerdeletesuite.js +++ b/powerdeletesuite.js @@ -359,6 +359,7 @@ var pd = { .first() .text("Power Delete Suite v" + pd.version); pd.setup.applySubList(); + pd.setup.addSkipInteractionsUI(); pd.setup.bindUI(); pd.helpers.restoreSettings(); }, @@ -407,6 +408,18 @@ var pd = { ).prepend("[M]"); }); }, + addSkipInteractionsUI: function () { + // Add the skip interactions checkbox after the remember settings checkbox + var rememberSection = $("#pd__remember").closest("div"); + if (rememberSection.length > 0) { + rememberSection.after( + '
' + + '' + + '' + + '
' + ); + } + }, createProcessStream: function () { window.pd_processing = true; pd.exportItems = []; @@ -445,6 +458,7 @@ var pd = { isRemovingComments: $("#pd__comments").is(":checked"), isEditing: $("#pd__comments-edit").is(":checked"), editText: $("#pd__comments-edit-text").val(), + skipUserInteractions: $("#pd__skip-interactions").is(":checked"), }, paths: { sections: @@ -732,6 +746,7 @@ var pd = { } else { pd.task.info.errors++; if ( + pd.task.config.skipUserInteractions || confirm( "Reddit seems to be under heavy load. Would you like to continue processing?" ) @@ -746,6 +761,7 @@ var pd = { function () { pd.task.info.errors++; if ( + pd.task.config.skipUserInteractions || confirm( "Error getting " + pd.task.paths.sections[0] + @@ -872,6 +888,11 @@ var pd = { }, }, delete: function (item) { + // Initialize retry counter if not present + if (!item.pdDeleteRetries) { + item.pdDeleteRetries = 0; + } + setTimeout(() => { if (pd.performActions) { $.ajax({ @@ -890,17 +911,34 @@ var pd = { }, function () { pd.task.info.errors++; - if ( - confirm( - "Error deleting " + - (item.kind == "t3" ? "post" : "comment") + - ", would you like to retry?" - ) - ) { - pd.actions.children.handleSingle(); - } else { + item.pdDeleteRetries++; + + // Retry up to 3 times before asking user + if (item.pdDeleteRetries < 3) { + pd.actions.delete(item); + return; + } + + // After 3 retries, check skip interactions setting + if (pd.task.config.skipUserInteractions) { + // Skip user interaction, continue with next item pd.actions.children.finishItem(); pd.actions.children.handleGroup(); + } else { + // Show confirmation dialog as before + if ( + confirm( + "Error deleting " + + (item.kind == "t3" ? "post" : "comment") + + " after 3 attempts, would you like to continue with the next item?" + ) + ) { + pd.actions.children.finishItem(); + pd.actions.children.handleGroup(); + } else { + // User chose to stop processing + pd.ui.done(); + } } } ); @@ -912,6 +950,11 @@ var pd = { }, 5000); }, edit: function (item) { + // Initialize retry counter if not present + if (!item.pdEditRetries) { + item.pdEditRetries = 0; + } + setTimeout(() => { if (pd.performActions) { var editString = pd.task.config.editText || @@ -934,16 +977,32 @@ var pd = { }, function () { pd.task.info.errors++; - if ( - !confirm( - "Error editing " + - (item.kind == "t3" ? "post" : "comment") + - ", would you like to retry?" - ) - ) { + item.pdEditRetries++; + + // Retry up to 3 times before asking user + if (item.pdEditRetries < 3) { + pd.actions.edit(item); + return; + } + + // After 3 retries, check skip interactions setting + if (pd.task.config.skipUserInteractions) { + // Skip user interaction, mark as edited and continue item.pdEdited = true; + pd.actions.children.handleSingle(); + } else { + // Show confirmation dialog as before + if ( + !confirm( + "Error editing " + + (item.kind == "t3" ? "post" : "comment") + + " after 3 attempts, would you like to continue with the next item?" + ) + ) { + item.pdEdited = true; + } + pd.actions.children.handleSingle(); } - pd.actions.children.handleSingle(); } ); } else { From e9c4c54ad581022ce28c52fc76e1f901d1324e95 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Sep 2025 03:07:14 +0000 Subject: [PATCH 03/18] Update version to 1.4.12 and finalize retry mechanism and skip interactions features Co-authored-by: ZaxLofful <33877007+ZaxLofful@users.noreply.github.com> --- powerdeletesuite.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerdeletesuite.js b/powerdeletesuite.js index c28d01a..3fbe186 100644 --- a/powerdeletesuite.js +++ b/powerdeletesuite.js @@ -1,5 +1,5 @@ var pd = { - version: "1.4.11", + version: "1.4.12", bookmarkver: "1.4", editStrings: [ "I love ice cream.", From 1a16a952794aa62765d5d1f5d0b06f898f59ea1c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Sep 2025 03:25:30 +0000 Subject: [PATCH 04/18] Add customizable retry mechanism and improve skip interactions behavior Co-authored-by: ZaxLofful <33877007+ZaxLofful@users.noreply.github.com> --- powerdeletesuite.js | 58 ++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/powerdeletesuite.js b/powerdeletesuite.js index 3fbe186..60ff05b 100644 --- a/powerdeletesuite.js +++ b/powerdeletesuite.js @@ -409,13 +409,21 @@ var pd = { }); }, addSkipInteractionsUI: function () { - // Add the skip interactions checkbox after the remember settings checkbox + // Add the retry and skip interactions options after the remember settings checkbox var rememberSection = $("#pd__remember").closest("div"); if (rememberSection.length > 0) { rememberSection.after( + '
' + + '' + + '' + + '
' + + '
' + + '' + + '' + + '
' + '
' + '' + - '' + + '' + '
' ); } @@ -459,6 +467,8 @@ var pd = { isEditing: $("#pd__comments-edit").is(":checked"), editText: $("#pd__comments-edit-text").val(), skipUserInteractions: $("#pd__skip-interactions").is(":checked"), + enableRetries: $("#pd__enable-retries").is(":checked"), + retryCount: parseInt($("#pd__retry-count").val()) || 3, }, paths: { sections: @@ -913,26 +923,26 @@ var pd = { pd.task.info.errors++; item.pdDeleteRetries++; - // Retry up to 3 times before asking user - if (item.pdDeleteRetries < 3) { + // Check if retries are enabled and we haven't exceeded the limit + if (pd.task.config.enableRetries && item.pdDeleteRetries < pd.task.config.retryCount) { pd.actions.delete(item); return; } - // After 3 retries, check skip interactions setting + // After max retries (or if retries disabled), check skip interactions setting if (pd.task.config.skipUserInteractions) { // Skip user interaction, continue with next item pd.actions.children.finishItem(); pd.actions.children.handleGroup(); } else { - // Show confirmation dialog as before - if ( - confirm( - "Error deleting " + - (item.kind == "t3" ? "post" : "comment") + - " after 3 attempts, would you like to continue with the next item?" - ) - ) { + // Show confirmation dialog + var message = "Error deleting " + (item.kind == "t3" ? "post" : "comment"); + if (pd.task.config.enableRetries) { + message += " after " + pd.task.config.retryCount + " attempts"; + } + message += ", would you like to continue with the next item?"; + + if (confirm(message)) { pd.actions.children.finishItem(); pd.actions.children.handleGroup(); } else { @@ -979,26 +989,26 @@ var pd = { pd.task.info.errors++; item.pdEditRetries++; - // Retry up to 3 times before asking user - if (item.pdEditRetries < 3) { + // Check if retries are enabled and we haven't exceeded the limit + if (pd.task.config.enableRetries && item.pdEditRetries < pd.task.config.retryCount) { pd.actions.edit(item); return; } - // After 3 retries, check skip interactions setting + // After max retries (or if retries disabled), check skip interactions setting if (pd.task.config.skipUserInteractions) { // Skip user interaction, mark as edited and continue item.pdEdited = true; pd.actions.children.handleSingle(); } else { - // Show confirmation dialog as before - if ( - !confirm( - "Error editing " + - (item.kind == "t3" ? "post" : "comment") + - " after 3 attempts, would you like to continue with the next item?" - ) - ) { + // Show confirmation dialog + var message = "Error editing " + (item.kind == "t3" ? "post" : "comment"); + if (pd.task.config.enableRetries) { + message += " after " + pd.task.config.retryCount + " attempts"; + } + message += ", would you like to continue with the next item?"; + + if (!confirm(message)) { item.pdEdited = true; } pd.actions.children.handleSingle(); From c9113e0ac025963e8218af5ba74e6db87820e32c Mon Sep 17 00:00:00 2001 From: Zax Lofful Date: Sun, 14 Sep 2025 23:12:41 -0700 Subject: [PATCH 05/18] copilot instras --- .github/copilot-instructions.md | 49 +++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 .github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..612d8f6 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,49 @@ +## PowerDeleteSuite — Copilot instructions + +Short, focused notes to help an AI agent be immediately productive editing this repo. + +1) Big picture (what this code does) + - Single-page client-side bookmarklet / userscript that runs on old.reddit.com user overview. + - Main app is the global `pd` object in `powerdeletesuite.js`. There is no backend — all actions use Reddit JSON endpoints. + - UI markup is pulled at runtime from the subreddit wiki (`/r/PowerDeleteSuite/wiki/centralform.json`) and CSS is fetched from a raw JSON stylesheet URL. + +2) Key files to read first + - `powerdeletesuite.js` — the entire app (init, settings, endpoints, UI binders, filters, deletion/edit flows). + - `bookmarklet.js` and `powerdeletesuite.user.js` — wrappers / distribution formats (bookmarklet and userscript headers). + - `README.md` — install & usage instructions and the bookmarklet snippet users copy. + - `stylesheet.json` — repository copy of stylesheet data referenced by the app. + +3) Architecture & runtime patterns (concrete) + - Global object `pd` holds version (pd.version), bookmarklet version (pd.bookmarkver), config, endpoints, and runtime state. + - Uses jQuery (`$`) and `$.ajax(...).then(success, failure)` style rather than fetch/async/await. + - Reddit integration: calls to endpoints like `/user//comments/.json`, `/user//submitted/.json`, and `/search.json`. + - Settings and simple persistence: `localStorage` keys (e.g., `pd_ver`) and DOM parsing to extract Reddit modhash (`#config`). + +4) Developer workflows / testing (how to verify changes) + - No build step. Edit `powerdeletesuite.js` directly. + - Typical dev checklist when changing behavior: + - bump `pd.version` (and optionally `pd.bookmarkver` if bookmarklet string changes) + - update the README bookmarklet snippet if you changed the hosted/URL behavior + - smoke test on `https://old.reddit.com/u/me/overview` and exercise: load comments, run filter, attempt an edit and a delete flow + +5) Conventions and fragile/important details (do not change lightly) + - Identity check: `pd.checks.location()` compares DOM username text to header link. If you change selectors, tests will break. + - `pd.setup.applyCentral()` and `pd.setup.applyStyles()` fetch remote wiki and stylesheet JSON — UI is wiki-driven. Be aware of CORS and network failures. + - `pd.editStrings` is the in-file list of candidate edit texts; changing it affects edit behavior. + - Modhash extraction uses `#config` innerHTML parsing — this is brittle; prefer keeping the same extraction if possible. + +6) Helpful code examples (copy/paste pointers) + - Where endpoints are defined: in `powerdeletesuite.js` -> `pd.setup.basicSettings()` (look for `pd.endpoints`). + - Where UI is filled from the wiki: `pd.setup.applyCentral()`. + - Where CSS is injected: `pd.setup.applyStyles()` — it expects JSON with `data.stylesheet`. + +7) Common failure modes to watch for + - Empty or changed Reddit DOM selectors (username, #config) — will make the script refuse to run. + - Remote wiki or stylesheet fetch failures — script alerts on failure; add robust fallbacks if needed. + - Running on the wrong reddit domain (new reddit) — script explicitly checks for `old.reddit.com` style overview path. + +8) Pull request checklist for code changes + - Update `pd.version` for user-facing changes; bump `pd.bookmarkver` only when bookmarklet install string in `README.md` must change. + - Mention in PR description how you tested on `old.reddit.com/u/me/overview` and what flows you exercised (comments, submissions, search, edit+delete order). + +If anything above is unclear or you'd like me to add quick local launch scripts (or a tiny test runner that simulates Reddit JSON responses), tell me which part to expand and I will update this file. From 795955f68bc8d797933d2ef779b8a9252dd4ff94 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Sep 2025 09:29:37 +0000 Subject: [PATCH 06/18] Initial plan From 9c43fefd3538551363da72dbde4d282537d844f1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Sep 2025 09:35:06 +0000 Subject: [PATCH 07/18] Reorganize settings UI: separate Advanced Settings section above process button Co-authored-by: ZaxLofful <33877007+ZaxLofful@users.noreply.github.com> --- powerdeletesuite.js | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/powerdeletesuite.js b/powerdeletesuite.js index 60ff05b..4752033 100644 --- a/powerdeletesuite.js +++ b/powerdeletesuite.js @@ -1,5 +1,5 @@ var pd = { - version: "1.4.12", + version: "1.4.13", bookmarkver: "1.4", editStrings: [ "I love ice cream.", @@ -409,23 +409,32 @@ var pd = { }); }, addSkipInteractionsUI: function () { - // Add the retry and skip interactions options after the remember settings checkbox - var rememberSection = $("#pd__remember").closest("div"); - if (rememberSection.length > 0) { - rememberSection.after( - '
' + + // Add the retry and skip interactions options in a separate section above the process button + var processButton = $("#pd__form input[type='submit'], #pd__form button[type='submit']"); + if (processButton.length === 0) { + // Fallback: look for the form itself and append before it ends + processButton = $("#pd__form").children().last(); + } + + if (processButton.length > 0) { + var settingsSection = + '
' + + '

Advanced Settings

' + + '
' + '' + '' + - '
' + - '
' + + '' + '' + - '' + + '' + + '' + '
' + '
' + '' + '' + - '
' - ); + '
' + + '
'; + + processButton.before(settingsSection); } }, createProcessStream: function () { @@ -468,7 +477,7 @@ var pd = { editText: $("#pd__comments-edit-text").val(), skipUserInteractions: $("#pd__skip-interactions").is(":checked"), enableRetries: $("#pd__enable-retries").is(":checked"), - retryCount: parseInt($("#pd__retry-count").val()) || 3, + retryCount: parseInt($("#pd__retry-count").val()) || 2, }, paths: { sections: From 95846fb36dbc4f9f62e9467bf3785f47462aa5f5 Mon Sep 17 00:00:00 2001 From: Zax Lofful Date: Mon, 15 Sep 2025 02:37:28 -0700 Subject: [PATCH 08/18] Instructions updates --- .github/copilot-instructions.md | 92 ++++++++++++++++----------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 612d8f6..fed5110 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,49 +1,49 @@ ## PowerDeleteSuite — Copilot instructions -Short, focused notes to help an AI agent be immediately productive editing this repo. - -1) Big picture (what this code does) - - Single-page client-side bookmarklet / userscript that runs on old.reddit.com user overview. - - Main app is the global `pd` object in `powerdeletesuite.js`. There is no backend — all actions use Reddit JSON endpoints. - - UI markup is pulled at runtime from the subreddit wiki (`/r/PowerDeleteSuite/wiki/centralform.json`) and CSS is fetched from a raw JSON stylesheet URL. - -2) Key files to read first - - `powerdeletesuite.js` — the entire app (init, settings, endpoints, UI binders, filters, deletion/edit flows). - - `bookmarklet.js` and `powerdeletesuite.user.js` — wrappers / distribution formats (bookmarklet and userscript headers). - - `README.md` — install & usage instructions and the bookmarklet snippet users copy. - - `stylesheet.json` — repository copy of stylesheet data referenced by the app. - -3) Architecture & runtime patterns (concrete) - - Global object `pd` holds version (pd.version), bookmarklet version (pd.bookmarkver), config, endpoints, and runtime state. - - Uses jQuery (`$`) and `$.ajax(...).then(success, failure)` style rather than fetch/async/await. - - Reddit integration: calls to endpoints like `/user//comments/.json`, `/user//submitted/.json`, and `/search.json`. - - Settings and simple persistence: `localStorage` keys (e.g., `pd_ver`) and DOM parsing to extract Reddit modhash (`#config`). - -4) Developer workflows / testing (how to verify changes) - - No build step. Edit `powerdeletesuite.js` directly. - - Typical dev checklist when changing behavior: - - bump `pd.version` (and optionally `pd.bookmarkver` if bookmarklet string changes) - - update the README bookmarklet snippet if you changed the hosted/URL behavior - - smoke test on `https://old.reddit.com/u/me/overview` and exercise: load comments, run filter, attempt an edit and a delete flow - -5) Conventions and fragile/important details (do not change lightly) - - Identity check: `pd.checks.location()` compares DOM username text to header link. If you change selectors, tests will break. - - `pd.setup.applyCentral()` and `pd.setup.applyStyles()` fetch remote wiki and stylesheet JSON — UI is wiki-driven. Be aware of CORS and network failures. - - `pd.editStrings` is the in-file list of candidate edit texts; changing it affects edit behavior. - - Modhash extraction uses `#config` innerHTML parsing — this is brittle; prefer keeping the same extraction if possible. - -6) Helpful code examples (copy/paste pointers) - - Where endpoints are defined: in `powerdeletesuite.js` -> `pd.setup.basicSettings()` (look for `pd.endpoints`). - - Where UI is filled from the wiki: `pd.setup.applyCentral()`. - - Where CSS is injected: `pd.setup.applyStyles()` — it expects JSON with `data.stylesheet`. - -7) Common failure modes to watch for - - Empty or changed Reddit DOM selectors (username, #config) — will make the script refuse to run. - - Remote wiki or stylesheet fetch failures — script alerts on failure; add robust fallbacks if needed. - - Running on the wrong reddit domain (new reddit) — script explicitly checks for `old.reddit.com` style overview path. - -8) Pull request checklist for code changes - - Update `pd.version` for user-facing changes; bump `pd.bookmarkver` only when bookmarklet install string in `README.md` must change. - - Mention in PR description how you tested on `old.reddit.com/u/me/overview` and what flows you exercised (comments, submissions, search, edit+delete order). - +Concise, actionable notes to help an AI agent be immediately productive in this repo. + +- Big picture + - Single-page client-side bookmarklet / userscript that runs on old.reddit.com (user overview). No backend; all actions call Reddit JSON endpoints. + - Runtime entry is `powerdeletesuite.js`. The app exposes a global `pd` object (state, settings, endpoints, helpers). + - UI is mostly wiki-driven: markup comes from the subreddit's wiki JSON and CSS from a JSON `stylesheet` resource. + +- Key files to read first + - `powerdeletesuite.js` — full app (init, settings, endpoints, UI binders, filters, edit/delete flows). Primary edit target. + - `bookmarklet.js`, `powerdeletesuite.user.js` — packaging/wrappers (bookmarklet string and userscript headers). + - `README.md` — install/bookmarklet snippet and usage notes you must keep in sync with `pd.bookmarkver`. + - `stylesheet.json` — local copy of stylesheet payload used by `pd.setup.applyStyles()`. + +- Concrete runtime patterns & conventions + - Global API: `pd` contains `pd.version`, `pd.bookmarkver`, `pd.endpoints`, `pd.setup.*`, `pd.checks.*`, and `pd.editStrings`. + - Networking: uses jQuery (`$`) and `$.ajax(...).then(success, failure)`. Expect callback style, not async/await. + - Reddit endpoints used: `/user//comments/.json`, `/user//submitted/.json`, `/search.json`, and post/edit/delete JSON endpoints. + - Persisted settings live in `localStorage` (keys like `pd_ver`); UI and behavior depend on those keys. + - Modhash / CSRF token extraction reads `#config` innerHTML. This is fragile — do not change selector logic lightly. + +- Developer workflow and verification + - No build step. Edit `powerdeletesuite.js` and other files directly. Changes are validated by manual smoke tests. + - Manual test steps: install bookmarklet/userscript or load `powerdeletesuite.js` on `https://old.reddit.com/u/me/overview`, then: + 1. Load comments/submissions (use filters). + 2. Run an edit flow (use `pd.editStrings` candidates). + 3. Run a delete flow. + - Typical PR checklist: + - Bump `pd.version` for changes; bump `pd.bookmarkver` only if the bookmarklet string in `README.md` must change. + - Update `README.md` if distribution/install string changes. + - Describe which flows you tested on `old.reddit.com/u/me/overview`. + +- Fragile areas and common failure modes + - DOM selectors: `pd.checks.location()` compares username text to header link — changing selectors breaks the startup guard. + - Remote wiki/CSS fetch: `pd.setup.applyCentral()` and `pd.setup.applyStyles()` fetch external JSON; network/CORS failures cause visible alerts. + - Modhash extraction: parsing `#config` innerHTML is brittle and required for authenticated actions. + +- Where to make common edits (quick pointers) + - Endpoints and defaults: `pd.setup.basicSettings()` (search for `pd.endpoints`). + - Wiki-driven UI: `pd.setup.applyCentral()` — how forms and labels are populated. + - Stylesheet injection: `pd.setup.applyStyles()` expects `data.stylesheet` JSON. + - Edit text candidates: `pd.editStrings` array in `powerdeletesuite.js`. + +- Small tips + - Preserve jQuery patterns; convert to Promises only if you update all call sites. + +If anything here is unclear or you want a short test harness that simulates Reddit JSON responses for automated tests, tell me which flows to emulate and I'll add it. If anything above is unclear or you'd like me to add quick local launch scripts (or a tiny test runner that simulates Reddit JSON responses), tell me which part to expand and I will update this file. From c71799b9b16d0412c83847330a4486d97ca56e1c Mon Sep 17 00:00:00 2001 From: Zax Lofful Date: Mon, 15 Sep 2025 02:43:16 -0700 Subject: [PATCH 09/18] Updats to styles --- .github/copilot-instructions.md | 5 +---- powerdeletesuite.js | 37 ++++++++++++++++++--------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index fed5110..71869ce 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -43,7 +43,4 @@ Concise, actionable notes to help an AI agent be immediately productive in this - Edit text candidates: `pd.editStrings` array in `powerdeletesuite.js`. - Small tips - - Preserve jQuery patterns; convert to Promises only if you update all call sites. - -If anything here is unclear or you want a short test harness that simulates Reddit JSON responses for automated tests, tell me which flows to emulate and I'll add it. -If anything above is unclear or you'd like me to add quick local launch scripts (or a tiny test runner that simulates Reddit JSON responses), tell me which part to expand and I will update this file. + - Preserve jQuery patterns; convert to Promises only if you update all call sites. \ No newline at end of file diff --git a/powerdeletesuite.js b/powerdeletesuite.js index 4752033..f768519 100644 --- a/powerdeletesuite.js +++ b/powerdeletesuite.js @@ -415,25 +415,28 @@ var pd = { // Fallback: look for the form itself and append before it ends processButton = $("#pd__form").children().last(); } - + if (processButton.length > 0) { - var settingsSection = - '
' + - '

Advanced Settings

' + - '
' + - '' + - '' + - '' + - '' + - '' + - '' + - '
' + - '
' + - '' + - '' + - '
' + + // Use the same section class other parts of the UI use so it inherits sizing/padding + // Collapsible pattern: hidden checkbox (.xt) + label + following .xtr-section + var settingsSection = + '' + + '' + + '
' + + '
' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '
' + + '
' + + ' ' + + ' ' + + '
' + '
'; - + processButton.before(settingsSection); } }, From 8d6d6c01cd0f3243cc94b53057c0204bb0f8495b Mon Sep 17 00:00:00 2001 From: Zax Lofful Date: Mon, 15 Sep 2025 02:43:50 -0700 Subject: [PATCH 10/18] Change version --- powerdeletesuite.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerdeletesuite.js b/powerdeletesuite.js index f768519..9fdcfdc 100644 --- a/powerdeletesuite.js +++ b/powerdeletesuite.js @@ -1,5 +1,5 @@ var pd = { - version: "1.4.13", + version: "1.4.14", bookmarkver: "1.4", editStrings: [ "I love ice cream.", From 453392ab5f977b9e30cb2ab7e60083b7f13e916b Mon Sep 17 00:00:00 2001 From: Zax Lofful Date: Mon, 15 Sep 2025 02:45:19 -0700 Subject: [PATCH 11/18] Fix up strings --- powerdeletesuite.js | 330 ++++++++++++++++++++++---------------------- 1 file changed, 165 insertions(+), 165 deletions(-) diff --git a/powerdeletesuite.js b/powerdeletesuite.js index 9fdcfdc..896ffff 100644 --- a/powerdeletesuite.js +++ b/powerdeletesuite.js @@ -22,8 +22,8 @@ var pd = { "I find peace in long walks.", "I enjoy the sound of rain.", "I love the smell of fresh bread.", - "random string 1", - "random string 2", + "Random String 1", + "Random String 2", "I like watching movies.", "I enjoy learning new languages.", "I love painting.", @@ -45,171 +45,171 @@ var pd = { "My favorite season is autumn.", "I like playing board games.", "I enjoy star gazing.", -"I love watching documentaries.", -"I like making crafts.", -"I enjoy attending concerts.", -"My favorite food is sushi.", -"I like trying new restaurants.", -"I enjoy going to the beach.", -"I love practicing mindfulness.", -"I like learning about history.", -"I enjoy playing the piano.", -"My favorite drink is tea.", -"I like volunteering in my community.", -"I enjoy visiting museums.", -"I love taking road trips.", -"I like working on DIY projects.", -"I enjoy playing with my pets.", -"My favorite dessert is cheesecake.", -"I like listening to audiobooks.", -"I enjoy doing crossword puzzles.", -"I love spending time in nature.", -"I like visiting art galleries.", -"I enjoy attending theater plays.", -"My favorite flower is the sunflower.", -"I like practicing meditation.", -"I enjoy cooking new recipes.", -"I love exploring national parks.", -"I like collecting stamps.", -"I enjoy attending festivals.", -"My favorite tree is the oak.", -"I like gardening in my backyard.", -"I enjoy learning new skills.", -"I love making pottery.", -"I like watching wildlife.", -"I enjoy going to farmers markets.", -"My favorite animal is the dolphin.", -"I like playing tennis.", -"I enjoy going on picnics.", -"I love watching the stars.", -"I like bird watching.", -"I enjoy making jewelry.", -"My favorite place is the mountains.", -"I like trying new hobbies.", -"I enjoy going on adventures.", + "I love watching documentaries.", + "I like making crafts.", + "I enjoy attending concerts.", + "My favorite food is sushi.", + "I like trying new restaurants.", + "I enjoy going to the beach.", + "I love practicing mindfulness.", + "I like learning about history.", + "I enjoy playing the piano.", + "My favorite drink is tea.", + "I like volunteering in my community.", + "I enjoy visiting museums.", + "I love taking road trips.", + "I like working on DIY projects.", + "I enjoy playing with my pets.", + "My favorite dessert is cheesecake.", + "I like listening to audiobooks.", + "I enjoy doing crossword puzzles.", + "I love spending time in nature.", + "I like visiting art galleries.", + "I enjoy attending theater plays.", + "My favorite flower is the sunflower.", + "I like practicing meditation.", + "I enjoy cooking new recipes.", + "I love exploring national parks.", + "I like collecting stamps.", + "I enjoy attending festivals.", + "My favorite tree is the oak.", + "I like gardening in my backyard.", + "I enjoy learning new skills.", + "I love making pottery.", + "I like watching wildlife.", + "I enjoy going to farmers markets.", + "My favorite animal is the dolphin.", + "I like playing tennis.", + "I enjoy going on picnics.", + "I love watching the stars.", + "I like bird watching.", + "I enjoy making jewelry.", + "My favorite place is the mountains.", + "I like trying new hobbies.", + "I enjoy going on adventures.", "I love sailing on the lake.", -"I like attending sports events.", -"I enjoy taking dance classes.", -"My favorite book is Pride and Prejudice.", -"I like doing photography walks.", -"I enjoy visiting historical sites.", -"I love learning about astronomy.", -"I like playing with children.", -"I enjoy taking bubble baths.", -"My favorite band is The Beatles.", -"I like creating digital art.", -"I enjoy practicing archery.", -"I love watching animated movies.", -"I like doing science experiments.", -"I enjoy learning about marine life.", -"My favorite snack is popcorn.", -"I like building model airplanes.", -"I enjoy doing tai chi.", -"I love attending wine tastings.", -"I like knitting scarves.", -"I enjoy going to amusement parks.", -"My favorite TV show is Friends.", -"I like making homemade gifts.", -"I enjoy exploring caves.", -"I love listening to classical music.", -"I like making soap.", -"I enjoy trying new cuisines.", -"My favorite superhero is Spider-Man.", -"I like going to book clubs.", -"I enjoy doing escape rooms.", -"I love learning about different cultures.", -"I like practicing calligraphy.", -"I enjoy attending art workshops.", -"My favorite fruit is mango.", -"I like making candles.", -"I enjoy playing frisbee.", -"I love visiting botanical gardens.", -"I like going to the zoo.", -"I enjoy watching ballet.", -"My favorite author is J.K. Rowling.", -"I like practicing magic tricks.", -"I enjoy rock climbing.", -"I love learning about physics.", -"I like doing community service.", -"I enjoy making flower arrangements.", -"My favorite comedian is Robin Williams.", -"I like doing woodwork.", -"I enjoy going on nature hikes.", -"I love listening to jazz.", -"I like playing with Legos.", -"I enjoy attending live shows.", -"My favorite instrument is the violin.", -"I like learning new software.", -"I enjoy doing pottery classes.", -"I love participating in trivia nights.", -"I like going to the planetarium.", -"I enjoy learning about geology.", -"My favorite holiday is Christmas.", -"I like watching foreign films.", -"I enjoy writing poetry.", -"I love exploring abandoned places.", + "I like attending sports events.", + "I enjoy taking dance classes.", + "My favorite book is Pride and Prejudice.", + "I like doing photography walks.", + "I enjoy visiting historical sites.", + "I love learning about astronomy.", + "I like playing with children.", + "I enjoy taking bubble baths.", + "My favorite band is The Beatles.", + "I like creating digital art.", + "I enjoy practicing archery.", + "I love watching animated movies.", + "I like doing science experiments.", + "I enjoy learning about marine life.", + "My favorite snack is popcorn.", + "I like building model airplanes.", + "I enjoy doing tai chi.", + "I love attending wine tastings.", + "I like knitting scarves.", + "I enjoy going to amusement parks.", + "My favorite TV show is Friends.", + "I like making homemade gifts.", + "I enjoy exploring caves.", + "I love listening to classical music.", + "I like making soap.", + "I enjoy trying new cuisines.", + "My favorite superhero is Spider-Man.", + "I like going to book clubs.", + "I enjoy doing escape rooms.", + "I love learning about different cultures.", + "I like practicing calligraphy.", + "I enjoy attending art workshops.", + "My favorite fruit is mango.", + "I like making candles.", + "I enjoy playing frisbee.", + "I love visiting botanical gardens.", + "I like going to the zoo.", + "I enjoy watching ballet.", + "My favorite author is J.K. Rowling.", + "I like practicing magic tricks.", + "I enjoy rock climbing.", + "I love learning about physics.", + "I like doing community service.", + "I enjoy making flower arrangements.", + "My favorite comedian is Robin Williams.", + "I like doing woodwork.", + "I enjoy going on nature hikes.", + "I love listening to jazz.", + "I like playing with Legos.", + "I enjoy attending live shows.", + "My favorite instrument is the violin.", + "I like learning new software.", + "I enjoy doing pottery classes.", + "I love participating in trivia nights.", + "I like going to the planetarium.", + "I enjoy learning about geology.", + "My favorite holiday is Christmas.", + "I like watching foreign films.", + "I enjoy writing poetry.", + "I love exploring abandoned places.", "I like practicing martial arts.", -"I enjoy doing mindfulness exercises.", -"I love learning about space exploration.", -"I like going to flea markets.", -"I enjoy collecting vintage items.", -"My favorite painter is Van Gogh.", -"I like making origami.", -"I enjoy going to car shows.", -"I love learning about ancient civilizations.", -"I like watching magic shows.", -"I enjoy doing jigsaw puzzles.", -"My favorite vegetable is broccoli.", -"I like attending science fairs.", -"I enjoy playing card games.", -"I love visiting aquariums.", -"I like practicing playing drums.", -"I enjoy making scrapbooks.", -"My favorite poet is Robert Frost.", -"I like visiting bookstores.", -"I enjoy doing improv comedy.", -"I love learning about psychology.", -"I like attending lectures.", -"I enjoy going on scenic drives.", -"My favorite cuisine is Italian.", -"I like creating comic strips.", -"I enjoy going to the opera.", -"I love watching musicals.", -"I like practicing parkour.", -"I enjoy learning about architecture.", -"My favorite drink is hot chocolate.", -"I like attending workshops.", -"I enjoy playing darts.", -"I love exploring forests.", -"I like learning about meteorology.", -"I enjoy going to the circus.", -"My favorite gemstone is sapphire.", -"I like practicing public speaking.", -"I enjoy doing charity work.", -"I love watching wildlife documentaries.", -"I like learning about mythology.", -"I enjoy doing metalworking.", -"My favorite planet is Saturn.", -"I like creating graphic designs.", -"I enjoy going to comedy clubs.", -"I love learning about economics.", -"I like making quilts.", -"I enjoy going to music festivals.", -"My favorite sculpture is The Thinker.", -"I like practicing yoga.", -"I enjoy attending cultural festivals.", -"I love learning about world history.", -"I like visiting libraries.", -"I enjoy doing voice acting.", -"My favorite dance is the tango.", -"I like making paper crafts.", -"I enjoy going to food tastings.", -"I love learning about anthropology.", -"I like attending art exhibitions.", -"I enjoy going to street fairs.", -"My favorite insect is the butterfly.", -"I like creating video content.", -"I enjoy participating in hackathons." + "I enjoy doing mindfulness exercises.", + "I love learning about space exploration.", + "I like going to flea markets.", + "I enjoy collecting vintage items.", + "My favorite painter is Van Gogh.", + "I like making origami.", + "I enjoy going to car shows.", + "I love learning about ancient civilizations.", + "I like watching magic shows.", + "I enjoy doing jigsaw puzzles.", + "My favorite vegetable is broccoli.", + "I like attending science fairs.", + "I enjoy playing card games.", + "I love visiting aquariums.", + "I like practicing playing drums.", + "I enjoy making scrapbooks.", + "My favorite poet is Robert Frost.", + "I like visiting bookstores.", + "I enjoy doing improv comedy.", + "I love learning about psychology.", + "I like attending lectures.", + "I enjoy going on scenic drives.", + "My favorite cuisine is Italian.", + "I like creating comic strips.", + "I enjoy going to the opera.", + "I love watching musicals.", + "I like practicing parkour.", + "I enjoy learning about architecture.", + "My favorite drink is hot chocolate.", + "I like attending workshops.", + "I enjoy playing darts.", + "I love exploring forests.", + "I like learning about meteorology.", + "I enjoy going to the circus.", + "My favorite gemstone is sapphire.", + "I like practicing public speaking.", + "I enjoy doing charity work.", + "I love watching wildlife documentaries.", + "I like learning about mythology.", + "I enjoy doing metalworking.", + "My favorite planet is Saturn.", + "I like creating graphic designs.", + "I enjoy going to comedy clubs.", + "I love learning about economics.", + "I like making quilts.", + "I enjoy going to music festivals.", + "My favorite sculpture is The Thinker.", + "I like practicing yoga.", + "I enjoy attending cultural festivals.", + "I love learning about world history.", + "I like visiting libraries.", + "I enjoy doing voice acting.", + "My favorite dance is the tango.", + "I like making paper crafts.", + "I enjoy going to food tastings.", + "I love learning about anthropology.", + "I like attending art exhibitions.", + "I enjoy going to street fairs.", + "My favorite insect is the butterfly.", + "I like creating video content.", + "I enjoy participating in hackathons." ], init: function () { pd.checks.versions(); From 93b54806a2906ea69230b66659b02382d09082ac Mon Sep 17 00:00:00 2001 From: Zax Lofful Date: Mon, 15 Sep 2025 02:46:53 -0700 Subject: [PATCH 12/18] show 2 --- powerdeletesuite.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/powerdeletesuite.js b/powerdeletesuite.js index 896ffff..0250601 100644 --- a/powerdeletesuite.js +++ b/powerdeletesuite.js @@ -680,6 +680,15 @@ var pd = { } $(".gt-toggle").not(":checked").change(); } + // Ensure the retry-count field displays the default value so user knows the default + try { + var $retry = $("#pd__retry-count"); + if ($retry.length && ($retry.val() === "" || typeof $retry.val() === "undefined")) { + $retry.val("2"); + } + } catch (e) { + /* ignore if element not present */ + } }, saveSettings: function () { if ($("#pd__remember").is(":checked")) { From cf458cd2ab499bf8e13f64dd2f90c4364ccc7a9a Mon Sep 17 00:00:00 2001 From: Zax Lofful Date: Mon, 15 Sep 2025 02:49:21 -0700 Subject: [PATCH 13/18] Visual Test --- powerdeletesuite.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powerdeletesuite.js b/powerdeletesuite.js index 0250601..d3c85cd 100644 --- a/powerdeletesuite.js +++ b/powerdeletesuite.js @@ -420,7 +420,7 @@ var pd = { // Use the same section class other parts of the UI use so it inherits sizing/padding // Collapsible pattern: hidden checkbox (.xt) + label + following .xtr-section var settingsSection = - '' + + '' + '' + '
' + '
' + @@ -428,7 +428,7 @@ var pd = { ' ' + ' ' + ' ' + - ' ' + + ' ' + ' ' + '
' + '
' + From 7db049d410a93f648bebfdf22a2059e4a9e7e8cf Mon Sep 17 00:00:00 2001 From: Zax Lofful Date: Mon, 15 Sep 2025 02:55:04 -0700 Subject: [PATCH 14/18] Show retries --- powerdeletesuite.js | 51 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/powerdeletesuite.js b/powerdeletesuite.js index d3c85cd..666cd14 100644 --- a/powerdeletesuite.js +++ b/powerdeletesuite.js @@ -937,6 +937,10 @@ var pd = { }, }).then( function () { + // clear retry status for this item on success + if (pd.task && pd.task.info) { + pd.task.info.retrying = null; + } pd.task.items[0].pdDeleted = true; pd.actions.children.handleSingle(); }, @@ -946,6 +950,16 @@ var pd = { // Check if retries are enabled and we haven't exceeded the limit if (pd.task.config.enableRetries && item.pdDeleteRetries < pd.task.config.retryCount) { + // update retrying status so UI can show attempts/remaining + if (pd.task && pd.task.info) { + pd.task.info.retrying = { + kind: "delete", + id: item.data.id, + attempted: item.pdDeleteRetries, + remaining: pd.task.config.retryCount - item.pdDeleteRetries, + }; + } + pd.ui.updateDisplay(); pd.actions.delete(item); return; } @@ -953,6 +967,7 @@ var pd = { // After max retries (or if retries disabled), check skip interactions setting if (pd.task.config.skipUserInteractions) { // Skip user interaction, continue with next item + if (pd.task && pd.task.info) pd.task.info.retrying = null; pd.actions.children.finishItem(); pd.actions.children.handleGroup(); } else { @@ -964,6 +979,7 @@ var pd = { message += ", would you like to continue with the next item?"; if (confirm(message)) { + if (pd.task && pd.task.info) pd.task.info.retrying = null; pd.actions.children.finishItem(); pd.actions.children.handleGroup(); } else { @@ -1003,6 +1019,10 @@ var pd = { }, }).then( function () { + // clear retry status for this item on success + if (pd.task && pd.task.info) { + pd.task.info.retrying = null; + } pd.task.items[0].pdEdited = true; pd.actions.children.handleSingle(); }, @@ -1012,6 +1032,16 @@ var pd = { // Check if retries are enabled and we haven't exceeded the limit if (pd.task.config.enableRetries && item.pdEditRetries < pd.task.config.retryCount) { + // update retrying status so UI can show attempts/remaining + if (pd.task && pd.task.info) { + pd.task.info.retrying = { + kind: "edit", + id: item.data.id, + attempted: item.pdEditRetries, + remaining: pd.task.config.retryCount - item.pdEditRetries, + }; + } + pd.ui.updateDisplay(); pd.actions.edit(item); return; } @@ -1019,6 +1049,7 @@ var pd = { // After max retries (or if retries disabled), check skip interactions setting if (pd.task.config.skipUserInteractions) { // Skip user interaction, mark as edited and continue + if (pd.task && pd.task.info) pd.task.info.retrying = null; item.pdEdited = true; pd.actions.children.handleSingle(); } else { @@ -1032,6 +1063,7 @@ var pd = { if (!confirm(message)) { item.pdEdited = true; } + if (pd.task && pd.task.info) pd.task.info.retrying = null; pd.actions.children.handleSingle(); } } @@ -1059,6 +1091,25 @@ var pd = { pd.task.paths.timeframes[0] + "" ); + // Retry status: show attempted and remaining retries for current item when present + try { + if (pd.task && pd.task.info && pd.task.info.retrying) { + var r = pd.task.info.retrying; + var txt = (r.kind === "delete" ? "Deleting" : "Editing") + + " item " + (r.id || "") + + ": attempt " + r.attempted + + " (" + r.remaining + " left)"; + if (document.getElementById("pd__retry-status")) { + $("#pd__retry-status").text(txt).show(); + } else { + $("#pd__central .processing").first().before('
' + txt + '
'); + } + } else { + $("#pd__retry-status").hide(); + } + } catch (e) { + // ignore DOM errors + } pd.task.info.numPages = pd.task.info.donePages + (pd.task.paths.sections.length - 1) * 4 + From 24b36c3fe9f6c2e27012413cb4769bec26aeae99 Mon Sep 17 00:00:00 2001 From: Zax Lofful Date: Mon, 15 Sep 2025 02:55:51 -0700 Subject: [PATCH 15/18] Latest features require update version --- powerdeletesuite.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerdeletesuite.js b/powerdeletesuite.js index 666cd14..424a48b 100644 --- a/powerdeletesuite.js +++ b/powerdeletesuite.js @@ -1,5 +1,5 @@ var pd = { - version: "1.4.14", + version: "1.5.0", bookmarkver: "1.4", editStrings: [ "I love ice cream.", From 54b42e78254ff38e7cdfd2a671a5dfd891495a31 Mon Sep 17 00:00:00 2001 From: Zax Lofful Date: Mon, 15 Sep 2025 03:04:18 -0700 Subject: [PATCH 16/18] update version to 1.5.1 --- powerdeletesuite.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerdeletesuite.js b/powerdeletesuite.js index 424a48b..546d5bd 100644 --- a/powerdeletesuite.js +++ b/powerdeletesuite.js @@ -1,5 +1,5 @@ var pd = { - version: "1.5.0", + version: "1.5.1", bookmarkver: "1.4", editStrings: [ "I love ice cream.", From cdbc802c67633b6672a9bb28e86bf81e8762188b Mon Sep 17 00:00:00 2001 From: Zax Lofful Date: Mon, 15 Sep 2025 03:07:56 -0700 Subject: [PATCH 17/18] set the box to the right length --- powerdeletesuite.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerdeletesuite.js b/powerdeletesuite.js index 546d5bd..97c9661 100644 --- a/powerdeletesuite.js +++ b/powerdeletesuite.js @@ -428,7 +428,7 @@ var pd = { ' ' + ' ' + ' ' + - ' ' + + ' ' + ' ' + '
' + '
' + From 32970caf567fb46adb5a31a4626a3877d263e11f Mon Sep 17 00:00:00 2001 From: Zax Lofful Date: Mon, 15 Sep 2025 23:57:57 -0700 Subject: [PATCH 18/18] get rid of empty lines --- .github/copilot-instructions.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 71869ce..fc1a526 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,7 +1,3 @@ -## PowerDeleteSuite — Copilot instructions - -Concise, actionable notes to help an AI agent be immediately productive in this repo. - - Big picture - Single-page client-side bookmarklet / userscript that runs on old.reddit.com (user overview). No backend; all actions call Reddit JSON endpoints. - Runtime entry is `powerdeletesuite.js`. The app exposes a global `pd` object (state, settings, endpoints, helpers).