Skip to content

Fix problem switcher not update#931

Closed
def-WA2025 wants to merge 37 commits intodevfrom
fix-problem-switcher-not-update
Closed

Fix problem switcher not update#931
def-WA2025 wants to merge 37 commits intodevfrom
fix-problem-switcher-not-update

Conversation

@def-WA2025
Copy link
Member

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

What does this PR aim to accomplish?

Fix *EX problems not display.

How does this PR accomplish the above?

Update list when click the refresh button. (The refresh button is located at the top of the problem switcher)


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

Ensure the contest problem switcher reflects the latest problem list and can be manually refreshed from the UI.

Bug Fixes:

  • Fix contest problem switcher not updating when the problem list changes.

Enhancements:

  • Extract contest problem list fetching/parsing into a reusable function exposed on unsafeWindow for use by the UI.
  • Add a refresh control to the contest problem switcher to reload and update the stored problem list.

Summary by cubic

Fixes the contest problem switcher not updating by adding a manual refresh and a shared fetcher that pulls the latest problem list. The switcher now reflects current contest problems.

  • Bug Fixes

    • Added GetContestProblemList(refresh) on unsafeWindow to fetch/parse contest problems, cache in localStorage, and optionally reload.
    • Added a "Refresh" link at the top of the switcher that calls GetContestProblemList(true).
    • On first load without a cached list, call GetContestProblemList(false).
  • Dependencies

    • Bumped version to 3.4.0 in package.json.
    • Updated Update.json prerelease entry for 3.4.0 with notes and timestamp.
    • Updated internal version metadata to 1.10.0.

Written for commit 9c5a57d. Summary will update on new commits.

boomzero and others added 26 commits February 8, 2025 09:15
Signed-off-by: Zhu Chenrui <boomzero_zcr@outlook.com>
Signed-off-by: Zhu Chenrui <boomzero_zcr@outlook.com>
(cherry picked from commit 07d7590)

Update feature.yml

Signed-off-by: Zhu Chenrui <boomzero_zcr@outlook.com>
(cherry picked from commit 1a99430)

Update docs.yml

Signed-off-by: Zhu Chenrui <boomzero_zcr@outlook.com>
(cherry picked from commit 6017bcf)
Signed-off-by: Shan Wenxiao <seanoj_noreply@yeah.net>
…ns[bot]

This prevents infinite loops where the bot commits version updates,
which triggers the workflow again, causing another commit.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The last-commit-author guard now only exits for non-edited events,
so PR title/body changes still update Update.json metadata even
when the branch tip is a github-actions[bot] commit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Exclude all bot actors (not just github-actions[bot]) from triggering
the UpdateVersion workflow, preventing loops from AI code review bots.
Allow edited events through the script-level guard so PR title/body
changes still update Update.json metadata.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sourcery-ai
Copy link

sourcery-ai bot commented Mar 12, 2026

Reviewer's Guide

Adds a reusable contest problem list fetcher and wires it into the problem switcher so that the list is populated from localStorage and can be refreshed on demand via a new UI control.

Sequence diagram for contest problem list refresh via problem switcher

sequenceDiagram
    actor User
    participant ProblemSwitcherUI
    participant GetContestProblemList
    participant XMOJServer
    participant DOMParser
    participant localStorage
    participant BrowserLocation

    User->>ProblemSwitcherUI: Click_refresh_link
    ProblemSwitcherUI->>GetContestProblemList: GetContestProblemList(true)
    activate GetContestProblemList
    GetContestProblemList->>XMOJServer: fetch(contest_php_with_cid)
    activate XMOJServer
    XMOJServer-->>GetContestProblemList: HTML_contest_page
    deactivate XMOJServer
    GetContestProblemList->>DOMParser: parseFromString(html, text_html)
    activate DOMParser
    DOMParser-->>GetContestProblemList: contest_DOM
    deactivate DOMParser
    GetContestProblemList->>GetContestProblemList: extract_problem_rows
    GetContestProblemList->>localStorage: setItem(UserScript_Contest_cid_ProblemList, problemList_json)
    alt RefreshList_is_true
        GetContestProblemList->>BrowserLocation: reload()
    end
    deactivate GetContestProblemList
Loading

File-Level Changes

Change Details Files
Introduce a reusable function to fetch and cache the contest problem list in localStorage, then use it from the main script.
  • Add unsafeWindow.GetContestProblemList async function that fetches the contest page, parses the problem table, builds a problem metadata array, and stores it in localStorage keyed by contest ID.
  • Guard fetching logic against contests that are not yet started or are private, logging errors to console on exceptions.
  • Replace inline contest problem list fetching logic in main() with a call to the new GetContestProblemList helper and subsequent read from localStorage.
XMOJ.user.js
Update the problem switcher UI to support manually refreshing the problem list so new problems (e.g., *EX) are shown.
  • After loading the contest problem list from localStorage, insert a centered refresh anchor at the top of the problem switcher that calls GetContestProblemList(true) when clicked.
  • Use the RefreshList flag in GetContestProblemList to reload the page after updating the cached problem list, ensuring the switcher reflects new problems.
XMOJ.user.js

Possibly linked issues

  • #unknown: PR updates and refreshes the contest problem list, directly fixing the problem switcher not updating described in issue.

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

@hendragon-bot hendragon-bot bot added the user-script This issue or pull request is related to the main user script label Mar 12, 2026
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 2 security issues, and left some high level feedback:

Security issues:

  • User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in a problemSwitcher.innerHTML is an anti-pattern that can lead to XSS vulnerabilities (link)

General comments:

  • The call to unsafeWindow.GetContestProblemList(false) in main is not awaited, so ContestProblemList = localStorage.getItem(...) will likely run before the async fetch completes; consider making GetContestProblemList return the list and await it instead of relying on localStorage side effects.
  • The new GetContestProblemList is exposed on unsafeWindow and triggered via an inline onclick string; wiring the refresh link with addEventListener and a locally scoped handler will avoid global pollution and string-based event handlers.
  • The contest URL (https://www.xmoj.tech/contest.php?cid= + SearchParams.get("cid")) is now duplicated between main and GetContestProblemList; consider centralizing this into a helper or constant to avoid divergence if the URL format changes.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The call to `unsafeWindow.GetContestProblemList(false)` in `main` is not awaited, so `ContestProblemList = localStorage.getItem(...)` will likely run before the async fetch completes; consider making `GetContestProblemList` return the list and `await` it instead of relying on localStorage side effects.
- The new `GetContestProblemList` is exposed on `unsafeWindow` and triggered via an inline `onclick` string; wiring the refresh link with `addEventListener` and a locally scoped handler will avoid global pollution and string-based event handlers.
- The contest URL (`https://www.xmoj.tech/contest.php?cid=` + `SearchParams.get("cid")`) is now duplicated between `main` and `GetContestProblemList`; consider centralizing this into a helper or constant to avoid divergence if the URL format changes.

## Individual Comments

### Comment 1
<location path="XMOJ.user.js" line_range="2320" />
<code_context>
                        problemSwitcher.innerHTML += `<a href="javascript:void(0)" onclick="GetContestProblemList(true)" title="刷新列表" class="mb-2" style="text-align: center;" active>刷新</a>`;
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-document-method):** User controlled data in methods like `innerHTML`, `outerHTML` or `document.write` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Comment 2
<location path="XMOJ.user.js" line_range="2320" />
<code_context>
                        problemSwitcher.innerHTML += `<a href="javascript:void(0)" onclick="GetContestProblemList(true)" title="刷新列表" class="mb-2" style="text-align: center;" active>刷新</a>`;
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-innerhtml):** User controlled data in a `problemSwitcher.innerHTML` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</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.

problemSwitcher.style.flexDirection = "column";

let problemList = JSON.parse(ContestProblemList);
problemSwitcher.innerHTML += `<a href="javascript:void(0)" onclick="GetContestProblemList(true)" title="刷新列表" class="mb-2" style="text-align: center;" active>刷新</a>`;
Copy link

Choose a reason for hiding this comment

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

security (javascript.browser.security.insecure-document-method): User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

problemSwitcher.style.flexDirection = "column";

let problemList = JSON.parse(ContestProblemList);
problemSwitcher.innerHTML += `<a href="javascript:void(0)" onclick="GetContestProblemList(true)" title="刷新列表" class="mb-2" style="text-align: center;" active>刷新</a>`;
Copy link

Choose a reason for hiding this comment

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

security (javascript.browser.security.insecure-innerhtml): User controlled data in a problemSwitcher.innerHTML is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

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.

2 issues found across 2 files

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:2296">
P2: Await the async `GetContestProblemList` call before reading from localStorage, otherwise the list can still be null and `JSON.parse` will throw.</violation>
</file>

<file name="Update.json">

<violation number="1" location="Update.json:2940">
P2: Do not manually edit Update.json version keys; version updates are fully automated and must stay in sync with the workflow.</violation>
</file>

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

localStorage.setItem("UserScript-Contest-" + SearchParams.get("cid") + "-ProblemList", JSON.stringify(problemList));
ContestProblemList = JSON.stringify(problemList);
}
unsafeWindow.GetContestProblemList(false);
Copy link

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

Choose a reason for hiding this comment

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

P2: Await the async GetContestProblemList call before reading from localStorage, otherwise the list can still be null and JSON.parse will throw.

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

<comment>Await the async `GetContestProblemList` call before reading from localStorage, otherwise the list can still be null and `JSON.parse` will throw.</comment>

<file context>
@@ -2270,22 +2293,8 @@ async function main() {
-                                localStorage.setItem("UserScript-Contest-" + SearchParams.get("cid") + "-ProblemList", JSON.stringify(problemList));
-                                ContestProblemList = JSON.stringify(problemList);
-                            }
+                            unsafeWindow.GetContestProblemList(false);
+                            ContestProblemList = localStorage.getItem("UserScript-Contest-" + SearchParams.get("cid") + "-ProblemList");
                         }
</file context>
Suggested change
unsafeWindow.GetContestProblemList(false);
await unsafeWindow.GetContestProblemList(false);
Fix with Cubic

def-WA2025 and others added 9 commits March 13, 2026 00:12
Updated version from 3.3.1 to 3.4.0 in Update.json.

Signed-off-by: zsTree <wa2025666@gmail.com>
Signed-off-by: zsTree <wa2025666@gmail.com>
Signed-off-by: zsTree <wa2025666@gmail.com>
Signed-off-by: zsTree <wa2025666@gmail.com>
Signed-off-by: zsTree <wa2025666@gmail.com>
Signed-off-by: zsTree <wa2025666@gmail.com>
Signed-off-by: zsTree <wa2025666@gmail.com>
Signed-off-by: zsTree <wa2025666@gmail.com>
@def-WA2025
Copy link
Member Author

@boomzero

@PythonSmall-Q
Copy link
Member

PythonSmall-Q commented Mar 12, 2026 via email

@PythonSmall-Q
Copy link
Member

PythonSmall-Q commented Mar 12, 2026 via email

@PythonSmall-Q
Copy link
Member

PythonSmall-Q commented Mar 12, 2026 via email

@PythonSmall-Q
Copy link
Member

版本号应该是3.3.2吧(?

"Prerelease": true,
"UpdateContents": [
{
"PR": 924,
Copy link
Member

Choose a reason for hiding this comment

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

Emm, ?

@def-WA2025
Copy link
Member Author

似乎没看到有3.3.1版本?

@def-WA2025
Copy link
Member Author

ooo PR里面找到了

@def-WA2025
Copy link
Member Author

PR里找到了

@def-WA2025 def-WA2025 requested a review from boomzero March 13, 2026 15:19
@def-WA2025 def-WA2025 closed this Mar 13, 2026
@def-WA2025 def-WA2025 deleted the fix-problem-switcher-not-update branch March 13, 2026 15:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/M user-script This issue or pull request is related to the main user script

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants