From 093865e292fa819cb6b88dec5d91c14ae4f65c5b Mon Sep 17 00:00:00 2001 From: boomzero Date: Sat, 14 Mar 2026 22:03:44 +0800 Subject: [PATCH 1/5] feat: add refresh button to ProblemSwitcher to invalidate cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a ↻ button at the bottom of the ProblemSwitcher panel that clears all localStorage cache entries for the current contest and reloads the page, allowing users to force-fetch updated contest problem data. Co-Authored-By: Claude Sonnet 4.6 --- XMOJ.user.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/XMOJ.user.js b/XMOJ.user.js index 49538eed..d111a3be 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -2323,6 +2323,25 @@ async function main() { } problemSwitcher.innerHTML += `${buttonText}`; } + let refreshBtn = document.createElement("a"); + refreshBtn.title = "刷新缓存"; + refreshBtn.classList.add("btn", "btn-outline-secondary", "mt-2"); + refreshBtn.innerHTML = "↻"; + refreshBtn.href = "#"; + refreshBtn.addEventListener("click", function(e) { + e.preventDefault(); + let cid = SearchParams.get("cid"); + let keysToRemove = []; + for (let k = 0; k < localStorage.length; k++) { + let key = localStorage.key(k); + if (key && key.startsWith("UserScript-Contest-" + cid + "-")) { + keysToRemove.push(key); + } + } + keysToRemove.forEach(k => localStorage.removeItem(k)); + location.reload(); + }); + problemSwitcher.appendChild(refreshBtn); document.body.appendChild(problemSwitcher); } if (document.querySelector("body > div > div.mt-3 > h2") != null) { From 007ad5891ec770ee8010cbfef4954a1d8aa75b8c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 14 Mar 2026 14:04:33 +0000 Subject: [PATCH 2/5] 3.3.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9ffb1aa4..7a191097 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xmoj-script", - "version": "3.3.1", + "version": "3.3.2", "description": "an improvement script for xmoj.tech", "main": "AddonScript.js", "scripts": { From 6dba9917a234de8fad910f26055ce82770feaa0c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 14 Mar 2026 14:04:39 +0000 Subject: [PATCH 3/5] Update version info to 3.3.2 --- Update.json | 11 +++++++++++ XMOJ.user.js | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Update.json b/Update.json index e12d6229..b7e7170e 100644 --- a/Update.json +++ b/Update.json @@ -3433,6 +3433,17 @@ } ], "Notes": "No release notes were provided for this release." + }, + "3.3.2": { + "UpdateDate": 1773497073852, + "Prerelease": true, + "UpdateContents": [ + { + "PR": 934, + "Description": "feat: add refresh button to ProblemSwitcher" + } + ], + "Notes": "Added a refresh button (↻) to the ProblemSwitcher panel. Clicking it invalidates the cached contest problem list and reloads the page, useful when contest problems are updated mid-contest." } } } \ No newline at end of file diff --git a/XMOJ.user.js b/XMOJ.user.js index d111a3be..3c17e246 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -1,6 +1,6 @@ // ==UserScript== // @name XMOJ -// @version 3.3.1 +// @version 3.3.2 // @description XMOJ增强脚本 // @author @XMOJ-Script-dev, @langningchen and the community // @namespace https://github/langningchen From 852178b861ca4c380810ce3c133f07924d588581 Mon Sep 17 00:00:00 2001 From: boomzero Date: Sat, 14 Mar 2026 22:09:05 +0800 Subject: [PATCH 4/5] refactor: guard refresh button against null cid and deduplicate prefix - Capture cid at button-creation time from the outer null-checked scope instead of re-reading SearchParams inside the click handler - Hide the button (no-op) if cid is unexpectedly null, avoiding reliance on the prefix filter as an accidental-deletion guard - Extract a local `prefix` variable in the handler to avoid repeating the "UserScript-Contest-{cid}-" string literal Co-Authored-By: Claude Sonnet 4.6 --- XMOJ.user.js | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/XMOJ.user.js b/XMOJ.user.js index 3c17e246..6184b409 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -2323,24 +2323,29 @@ async function main() { } problemSwitcher.innerHTML += `${buttonText}`; } + let refreshCid = SearchParams.get("cid"); let refreshBtn = document.createElement("a"); refreshBtn.title = "刷新缓存"; refreshBtn.classList.add("btn", "btn-outline-secondary", "mt-2"); refreshBtn.innerHTML = "↻"; refreshBtn.href = "#"; - refreshBtn.addEventListener("click", function(e) { - e.preventDefault(); - let cid = SearchParams.get("cid"); - let keysToRemove = []; - for (let k = 0; k < localStorage.length; k++) { - let key = localStorage.key(k); - if (key && key.startsWith("UserScript-Contest-" + cid + "-")) { - keysToRemove.push(key); + if (refreshCid) { + refreshBtn.addEventListener("click", function(e) { + e.preventDefault(); + let prefix = "UserScript-Contest-" + refreshCid + "-"; + let keysToRemove = []; + for (let k = 0; k < localStorage.length; k++) { + let key = localStorage.key(k); + if (key && key.startsWith(prefix)) { + keysToRemove.push(key); + } } - } - keysToRemove.forEach(k => localStorage.removeItem(k)); - location.reload(); - }); + keysToRemove.forEach(k => localStorage.removeItem(k)); + location.reload(); + }); + } else { + refreshBtn.style.display = "none"; + } problemSwitcher.appendChild(refreshBtn); document.body.appendChild(problemSwitcher); } From 31a03198d9a1da3b2dbaceec9f0a4e69f06491e9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 14 Mar 2026 14:11:01 +0000 Subject: [PATCH 5/5] Update time and description of 3.3.2 --- Update.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Update.json b/Update.json index b7e7170e..e996c59c 100644 --- a/Update.json +++ b/Update.json @@ -3435,7 +3435,7 @@ "Notes": "No release notes were provided for this release." }, "3.3.2": { - "UpdateDate": 1773497073852, + "UpdateDate": 1773497456666, "Prerelease": true, "UpdateContents": [ {