Skip to content

Fix problem switcher not update#928

Closed
def-WA2025 wants to merge 2 commits intoXMOJ-Script-dev:masterfrom
def-WA2025:Fix-ProblemSwitcher-Not-Update
Closed

Fix problem switcher not update#928
def-WA2025 wants to merge 2 commits intoXMOJ-Script-dev:masterfrom
def-WA2025:Fix-ProblemSwitcher-Not-Update

Conversation

@def-WA2025
Copy link
Collaborator

@def-WA2025 def-WA2025 commented Mar 9, 2026

What does this PR aim to accomplish?

Fix *EX problems not display.

How does this PR accomplish the above?

Update contestProblemList when the page reload.


By submitting this pull request, I confirm the following:

  1. I have read and understood the contributor's guide, as well as this entire template. I understand which branch to base my commits and Pull Requests against.
  2. I have commented on my proposed changes within the code and I have tested my changes.
  3. I am willing to help maintain this change if there are issues with it later.
  4. It is compatible with the GNU General Public License v3.0
  5. I have squashed any insignificant commits. (git rebase)
  6. I have checked that another pull request for this purpose does not exist.
  7. I have considered and confirmed that this submission will be valuable to others.
  8. I accept that this submission may not be used, and the pull request can be closed at the will of the maintainer.
  9. I give this submission freely and claim no ownership to its content.

  • I have read the above and my PR is ready for review. Check this box to confirm

Summary by Sourcery

Bug Fixes:

  • Fix contest problem switcher not updating when contest problems change due to relying on stale cached data.

Summary by cubic

Fixes the Problem Switcher not updating after reload by always refreshing the contest problem list from the server so all problems show up.

  • Bug Fixes
    • Always fetch the contest page and rebuild the problem list, then overwrite localStorage key UserScript-Contest-<cid>-ProblemList to avoid stale cache.

Written for commit 76fb133. Summary will update on new commits.

@sourcery-ai
Copy link

sourcery-ai bot commented Mar 9, 2026

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Always refresh and persist the contest problem list from the server so the problem switcher reflects the latest problems on page reload, instead of reusing potentially stale data from localStorage.

Sequence diagram for refreshed contest problem list on page reload

sequenceDiagram
    actor User
    participant BrowserPage
    participant XMOJScript
    participant LocalStorage
    participant XMOJServer

    User->>BrowserPage: Reload contest problem page
    BrowserPage->>XMOJScript: Execute main

    XMOJScript->>LocalStorage: getItem(UserScript-Contest-cid-ProblemList)
    LocalStorage-->>XMOJScript: ContestProblemList (ignored, set to null)

    XMOJScript->>XMOJServer: GET /contest.php?cid
    XMOJServer-->>XMOJScript: HTML contest page

    XMOJScript->>XMOJScript: Parse HTML and extract problemset rows
    XMOJScript->>XMOJScript: Build problemList array

    XMOJScript->>LocalStorage: setItem(UserScript-Contest-cid-ProblemList, JSON(problemList))
    LocalStorage-->>XMOJScript: Persisted problemList

    XMOJScript->>BrowserPage: Create and render problemSwitcher using fresh ContestProblemList
    BrowserPage-->>User: Display updated contest problems in switcher
Loading

File-Level Changes

Change Details Files
Always re-fetch and rebuild the contest problem list from the contest page instead of conditionally using a cached localStorage value, ensuring the problem switcher stays up to date.
  • Remove the null-check guard that previously skipped fetching when a contest problem list existed in localStorage.
  • Unconditionally issue a fetch to the contest page for the current contest ID and parse the HTML to extract the problem rows.
  • Rebuild the problem metadata array from the parsed table rows and write it back into localStorage for future use.
  • Set the in-memory ContestProblemList variable from the freshly built problem list JSON so downstream code uses the updated data.
XMOJ.user.js

Possibly linked issues

  • 更新脚本icon #183: PR refreshes ContestProblemList on reload, fixing the issue where problem switcher missed *EX problems.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • You’re now forcing a network request on every page load by setting ContestProblemList = null unconditionally; consider keeping the cache check and adding an explicit refresh strategy (e.g., timestamp-based invalidation or a manual refresh) instead of always re-fetching.
  • The initial localStorage.getItem assignment to ContestProblemList is immediately overwritten with null, so that read can be removed or the logic restructured to avoid dead code and make the intent of the cache/update behavior clearer.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- You’re now forcing a network request on every page load by setting `ContestProblemList = null` unconditionally; consider keeping the cache check and adding an explicit refresh strategy (e.g., timestamp-based invalidation or a manual refresh) instead of always re-fetching.
- The initial `localStorage.getItem` assignment to `ContestProblemList` is immediately overwritten with `null`, so that read can be removed or the logic restructured to avoid dead code and make the intent of the cache/update behavior clearer.

## Individual Comments

### Comment 1
<location path="XMOJ.user.js" line_range="2271" />
<code_context>
                             document.getElementsByTagName("h2")[0].innerHTML += " (" + pid + ")";
                         }
                         let ContestProblemList = localStorage.getItem("UserScript-Contest-" + SearchParams.get("cid") + "-ProblemList");
-                        if (ContestProblemList == null) {
-                            const contestReq = await fetch("https://www.xmoj.tech/contest.php?cid=" + SearchParams.get("cid"));
</code_context>
<issue_to_address>
**suggestion:** The value read from localStorage is immediately discarded and never used.

After reading `ContestProblemList` from localStorage, it’s immediately set to `null` and the data is always fetched from the network, so the `localStorage.getItem(...)` call has no effect. Either remove the `getItem` if you always want a fresh fetch, or keep the conditional logic to retain caching behavior.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@@ -2269,23 +2269,22 @@ async function main() {
document.getElementsByTagName("h2")[0].innerHTML += " (" + pid + ")";
}
let ContestProblemList = localStorage.getItem("UserScript-Contest-" + SearchParams.get("cid") + "-ProblemList");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: The value read from localStorage is immediately discarded and never used.

After reading ContestProblemList from localStorage, it’s immediately set to null and the data is always fetched from the network, so the localStorage.getItem(...) call has no effect. Either remove the getItem if you always want a fresh fetch, or keep the conditional logic to retain caching behavior.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="XMOJ.user.js">

<violation number="1" location="XMOJ.user.js:2272">
P2: Don't clear the cached problem list before the refresh succeeds; otherwise a failed contest fetch breaks the switcher path instead of using the last cached list.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Add one-off context when rerunning by tagging @cubic-dev-ai with guidance or docs links (including llms.txt)
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment on lines +2272 to 2288
ContestProblemList = null;
const contestReq = await fetch("https://www.xmoj.tech/contest.php?cid=" + SearchParams.get("cid"));
const res = await contestReq.text();
if (contestReq.status === 200 && res.indexOf("比赛尚未开始或私有,不能查看题目。") === -1) {
const parser = new DOMParser();
const dom = parser.parseFromString(res, "text/html");
const rows = (dom.querySelector("#problemset > tbody")).rows;
let problemList = [];
for (let i = 0; i < rows.length; i++) {
problemList.push({
"title": rows[i].children[2].innerText,
"url": rows[i].children[2].children[0].href
});
}
localStorage.setItem("UserScript-Contest-" + SearchParams.get("cid") + "-ProblemList", JSON.stringify(problemList));
ContestProblemList = JSON.stringify(problemList);
}
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Don't clear the cached problem list before the refresh succeeds; otherwise a failed contest fetch breaks the switcher path instead of using the last cached list.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At XMOJ.user.js, line 2272:

<comment>Don't clear the cached problem list before the refresh succeeds; otherwise a failed contest fetch breaks the switcher path instead of using the last cached list.</comment>

<file context>
@@ -2269,23 +2269,22 @@ async function main() {
-                                }
-                                localStorage.setItem("UserScript-Contest-" + SearchParams.get("cid") + "-ProblemList", JSON.stringify(problemList));
-                                ContestProblemList = JSON.stringify(problemList);
+                        ContestProblemList = null;
+                        const contestReq = await fetch("https://www.xmoj.tech/contest.php?cid=" + SearchParams.get("cid"));
+                        const res = await contestReq.text();
</file context>
Suggested change
ContestProblemList = null;
const contestReq = await fetch("https://www.xmoj.tech/contest.php?cid=" + SearchParams.get("cid"));
const res = await contestReq.text();
if (contestReq.status === 200 && res.indexOf("比赛尚未开始或私有,不能查看题目。") === -1) {
const parser = new DOMParser();
const dom = parser.parseFromString(res, "text/html");
const rows = (dom.querySelector("#problemset > tbody")).rows;
let problemList = [];
for (let i = 0; i < rows.length; i++) {
problemList.push({
"title": rows[i].children[2].innerText,
"url": rows[i].children[2].children[0].href
});
}
localStorage.setItem("UserScript-Contest-" + SearchParams.get("cid") + "-ProblemList", JSON.stringify(problemList));
ContestProblemList = JSON.stringify(problemList);
}
const contestReq = await fetch("https://www.xmoj.tech/contest.php?cid=" + SearchParams.get("cid"));
const res = await contestReq.text();
if (contestReq.status === 200 && res.indexOf("比赛尚未开始或私有,不能查看题目。") === -1) {
const parser = new DOMParser();
const dom = parser.parseFromString(res, "text/html");
const rows = (dom.querySelector("#problemset > tbody")).rows;
let problemList = [];
for (let i = 0; i < rows.length; i++) {
problemList.push({
"title": rows[i].children[2].innerText,
"url": rows[i].children[2].children[0].href
});
}
localStorage.setItem("UserScript-Contest-" + SearchParams.get("cid") + "-ProblemList", JSON.stringify(problemList));
ContestProblemList = JSON.stringify(problemList);
} else if (ContestProblemList == null) {
ContestProblemList = "[]";
}
Fix with Cubic

@def-WA2025 def-WA2025 closed this Mar 10, 2026
@def-WA2025 def-WA2025 deleted the Fix-ProblemSwitcher-Not-Update branch March 10, 2026 14:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant