Skip to content

fix: 修复异常页面的 TypeError,并兼容新版 /web/contest 比赛页面 - #1028

Merged
boomzero merged 60 commits into
devfrom
claude/issue-1009-u2n0g5
Sep 28, 2026
Merged

boomzero merged 60 commits into
devfrom
claude/issue-1009-u2n0g5

Conversation

@boomzero

@boomzero boomzero commented Sep 27, 2026 •

Copy link
Copy Markdown
Member

What does this PR aim to accomplish?:

Closes #1009
Closes #1029

  1. [Bug] TypeError: Cannot read properties of undefined (reading 'xxx') #1009: pages whose DOM differs from what the script expects (403/404 pages, multi-subtask test point pages, etc.) throw TypeErrors, which DebugMode shows as an "internal error" popup.
  2. New /web/contest/ pages break XMOJ-Script navigation and layout #1029: the new client-rendered contest pages under /web/contest/ (a Vue app mounted on #app) break the script's navigation and layout. The site no longer links to the old contest pages.

How does this PR accomplish the above?:

Error fixes (#1009)

  • Every dereferenced querySelector result is checked for null. Page branches that rebuild their own container skip the page when it is missing.
  • Paths that send requests stop instead of sending empty values: profile save, AutoCheat, ImproveACRate, ApplyData and GetUserInfo.
  • The multi-subtask test point page (reinfo.php) goes through every result group and skips elements without a test point's structure. This fixes the "Cannot read properties of undefined" error reported in the issue.
  • The old contest 403/404 pages now redirect to /web, which handles them itself.

New contest pages (#1029)

  • /web gets the same Bootstrap 5 and skin setup as the legacy pages; the site's Bootstrap 3 CSS is removed there too.
    • The app's Bootstrap 3 markup is mapped to Bootstrap 5 classes on every render: navbar, dropdown, buttons, pagination and badges.
    • The legacy navbar behavior is shared rather than copied: the floating top bar (NavbarStyler), the ResetType user menu, Translate and RemoveUseless.
  • InitializeContestWebApp re-applies the script's enhancements after async renders and in-app route changes. Vue's own elements are never replaced.
    • Countdowns.
    • Problem IDs and discussion links.
    • Copy buttons.
    • Open all / unsolved problems.
    • AutoCheat.
    • Read-only code editors.
    • Rank header translation.
    • The left-edge problem switcher, built from the contest API response.
  • Contest problem IDs and I/O file names come from the new /api/contest/... JSON API. The submit page's fallback to the original problem after a contest ends no longer reads legacy contest HTML.

Old contest pages redirect to /web, and their handlers are removed

The site no longer links to these pages. The script redirects them at document-start:

Old page New page
contest.php, contest.php?cid=X /web/contest, /web/contest/X
problem.php?cid=X&pid=N /web/contest/X/<letter>
problem_std.php, problem_solution.php …/std, …/solution
contestrank-correct.php?cid=X /web/contest/X/rank-correct

The handlers for those pages are removed (about 450 lines). problem.php?id=…, contestrank-oi.php, submitpage.php and status.php are still in use and unchanged. On ordinary problem pages the problem ID now comes from id. It was previously read from the contest cache, which gave null, so the I/O file name and the discussion count used the wrong problem.

Loading: fewer flashes and layout shifts

  • While loading, pages hide the body instead of making the root transparent. A transparent root showed the browser's white canvas in dark mode.
  • The canvas uses the active skin's background and color-scheme.
  • A page is shown only once its navbar is converted and the top bar applied. There is a safety fallback: 1.5 s after main() starts, 4 s after DOMContentLoaded at the latest.
  • The top bar is applied immediately instead of up to a second later.
  • Measured in dark mode (headless Chromium, every 10 ms during each navigation): pages are first shown fully styled, with no navbar or content movement afterwards, where dev had 2–4 jumps per load.
  • Server-rendered .php pages can still paint before a userscript manager injects the script.

Other fixes

  • Monochrome skin: links in table headers were the same color as the header background (1:1 contrast), for example the problem letters in rank tables. They now reach 13.8:1 in dark mode and 21:1 in light.

Tests

  • npm test runs tests/contest-web.test.cjs (9 tests), and a new Test workflow runs it on pull requests and on pushes to dev and master. The tests cover:
    • Route parsing.
    • The old-page redirect mapping.
    • Letter-to-index problem mapping.
    • API error handling.
    • Theme and canvas selection.
  • tests/userscript-harness.cjs runs the script on the live site in Chromium the way a userscript manager does. It checks each /web page, the redirects, legacy pages and both user menus, and saves screenshots. Credentials come only from environment variables. The script's backend and all submit/modify/login/logout POSTs are blocked. See the header of the file for usage.

Verification

  • The harness passes on the live site (logged in) for the /web contest pages, all six redirects, and the legacy problem and problem-set pages, in both the default and monochrome skins.
  • Not verified in a real Tampermonkey install: it installs under automation, but Chrome did not run any user script there. A maintainer should still try the new and the classic UI by hand before ticking the box below.

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.
  3. I have tested my changes.
  4. I am willing to help maintain this change if there are issues with it later.
  5. It is compatible with the GNU General Public License v3.0
  6. I have squashed any insignificant commits. (git rebase)
  7. I have checked that another pull request for this purpose does not exist.
  8. I have considered and confirmed that this submission will be valuable to others.
  9. I accept that this submission may not be used, and the pull request can be closed at the will of the maintainer.
  10. I give this submission freely and claim no ownership to its content.
  11. I have verified that my changes work correctly in both the new UI and the old/classic UI.

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

🤖 Generated with Claude Code

https://claude.ai/code/session_0135Ggqqp6xktQZytLRJQ9nc

在每个对 querySelector 结果取属性/调用方法的地方先判断是否为 null,
避免在 403/404 等页面结构不同时抛出 TypeError。
- 语句:前面加 if (xxx.querySelector(...) != null)
- 条件:在条件中加 xxx.querySelector(...) != null &&
- 变量声明/赋值:为 null 时使用空值([] / "" / 0)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0135Ggqqp6xktQZytLRJQ9nc
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

Deploying xmoj-script-dev-channel with  Cloudflare Pages  Cloudflare Pages

Latest commit: 9840c3b
Status: ✅  Deploy successful!
Preview URL: https://94145503.xmoj-script-dev-channel.pages.dev
Branch Preview URL: https://claude-issue-1009-u2n0g5.xmoj-script-dev-channel.pages.dev

View logs

@sourcery-ai

sourcery-ai Bot commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Reviewer's Guide

This PR systematically hardens XMOJ.user.js against missing DOM nodes by guarding querySelector dereferences and supplying safe fallbacks across page-specific features, including parsed response documents. It addresses null-related TypeErrors but does not fix errors caused by indexed collections or deeper child chains, and browser validation remains necessary for both UI variants.

Sequence diagram for guarded DOM updates

sequenceDiagram
    participant Script
    participant DOM
    participant Element

    Script->>DOM: querySelector(selector)
    DOM-->>Script: Element or null
    alt element exists
        Script->>Element: Set property or call method
    else element missing
        Script->>Script: Skip update or use fallback value
    end
Loading

Flow diagram for null-safe DOM manipulation

flowchart TD
    A[Page or parsed response has varying DOM] --> B{querySelector returns an element?}
    B -->|Yes| C[Read property or modify element]
    B -->|No| D[Skip operation or use safe fallback]
    D --> E[Continue page script without null TypeError]
    C --> E
Loading

File-Level Changes

Change Details Files
Added null guards around querySelector results throughout the userscript to prevent property access and method calls on missing DOM elements.
  • Guarded direct DOM mutations, event handlers, and conditional property reads on document and parsed documents.
  • Added empty-value fallbacks for missing collections, text, script contents, and rating values.
  • Updated multi-line conditions and selected nested-document operations while leaving unrelated indexed-element dereferences unchanged.
XMOJ.user.js
Applied defensive handling across page-specific features and UI variants.
  • Covered navigation, problem and contest pages, rankings, submission/captcha flows, user profiles, discussions, video pages, and auxiliary tools.
  • Added guards for both new Bootstrap UI and classic/legacy DOM selectors.
XMOJ.user.js

Possibly linked issues


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 Sep 27, 2026
@boomzero

Copy link
Copy Markdown
Member Author

@zsTree0830 测试一下吧

sourcery-ai[bot]
sourcery-ai Bot previously approved these changes Sep 27, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sourcery assessment

Approved.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

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 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="XMOJ.user.js" line_range="4397" />
<code_context>
                         const RequestID = ++CaptchaRequestID;
                         const CaptchaInput = document.querySelector("#vcode");
-                        document.querySelector("#CaptchaElement").style.display = "block";
+                        if (document.querySelector("#CaptchaElement") != null) document.querySelector("#CaptchaElement").style.display = "block";
                         CaptchaInput.value = "";
                         SetCaptchaStatus(StatusMessage || "");
</code_context>
<issue_to_address>
**issue (broader_impact):** The new guard protects only `#CaptchaElement`; `RefreshCaptcha` still immediately executes `CaptchaInput.value = ""` even when `document.querySelector("#vcode")` returned `null`, so captcha refresh still throws the same null-property TypeError.

**Triggers:** When the submit page has no `#vcode` input but the captcha refresh path runs.

**Suggested fix:** Check `CaptchaInput` for null before accessing it, or return from `RefreshCaptcha` when the input is absent.
</issue_to_address>

### Comment 2
<location path="XMOJ.user.js" line_range="3914" />
<code_context>
                 return null;
             }
             const ParsedDocument = new DOMParser().parseFromString(Response, "text/html");
-            let Rating = (parseInt(ParsedDocument.querySelector("#statics > tbody > tr:nth-child(4) > td:nth-child(2)").innerText.trim()) / parseInt(ParsedDocument.querySelector("#statics > tbody > tr:nth-child(3) > td:nth-child(2)").innerText.trim())).toFixed(3) * 1000;
</code_context>
<issue_to_address>
**issue (bug_risk):** When the outer container is absent, the new guard skips rebuilding the required DOM, but execution continues into code that assumes the rebuilt elements exist: rank handling indexes `HeaderCells[0]`, and the open-contest path passes a missing textarea from `querySelector` to `CodeMirror.fromTextArea`. The malformed page therefore still crashes instead of being safely ignored.

**Triggers:** When the page lacks the container matched by the guarded selector.

**Suggested fix:** Return from the page-specific branch when its required container is missing, or guard every downstream operation that depends on the generated DOM.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 2 findings to address first, and most changes only turn selector failures into no-ops, but the profile-edit path now substitutes empty strings for missing form fields and can send those values to the account-modification endpoint, potentially persisting incorrect account data. Reverting prevents further occurrences, but values already written would need to be repaired separately.

Blocking findings: XMOJ.user.js:4397, XMOJ.user.js:3914


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread XMOJ.user.js
Comment thread XMOJ.user.js

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 3 files

Re-trigger cubic

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0303ba78d8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread XMOJ.user.js
Comment thread XMOJ.user.js
Comment thread XMOJ.user.js Outdated
Comment thread XMOJ.user.js
claude and others added 5 commits September 27, 2026 09:28
- 各页面在所需容器缺失时(如403/404页面)直接跳过处理,
  避免后续代码使用未生成的元素(排名表头、CodeMirror 文本框等)
- RefreshCaptcha: #vcode 缺失时直接返回
- 修改个人信息: 表单元素缺失时不提交,避免用空值覆盖用户信息
- 自动提交/刷AC率/获取数据: 找不到提交记录时跳过,避免提交错误代码或无限轮询
- 恢复发帖板块 ID 的原写法(前面已有 null 检查)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0135Ggqqp6xktQZytLRJQ9nc
- GetUserInfo: #statics 表格缺失时返回默认值且不写入缓存,避免索引空数组
- ImproveACRate: 没有解析到已通过的题目时保持按钮禁用,避免用无效题号提交

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0135Ggqqp6xktQZytLRJQ9nc

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

New security issues found

Comment thread XMOJ.user.js
Comment thread XMOJ.user.js
Comment thread XMOJ.user.js
Comment thread XMOJ.user.js
Comment thread XMOJ.user.js
Comment thread XMOJ.user.js
Comment thread XMOJ.user.js
Comment thread XMOJ.user.js
Comment thread XMOJ.user.js
Comment thread XMOJ.user.js
@sourcery-ai
sourcery-ai Bot dismissed their stale review September 27, 2026 09:30

Sourcery withdrew this approval because the latest commits introduced blocking findings.

sourcery-ai[bot]
sourcery-ai Bot previously approved these changes Sep 27, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sourcery assessment

Approved.

- 新版比赛应用(/web/*)不再运行旧版 DOM 改写和 Bootstrap 替换,
  改为在页面异步渲染及站内切换后应用主题、倒计时、复制、讨论入口、
  批量打开题目、代码阅读器等增强功能
- 主题在 Vue、接口数据和字体加载前同步应用,保留站点 Bootstrap 3 样式
- 比赛题号、题目列表和文件输入输出信息改为通过新版 API 获取,
  题目切换器和比赛结束后回退提交不再依赖旧版比赛 HTML
- 图片放大功能提取为 InitializeImageEnlarger,供新旧页面共用
- 新增 tests/contest-web.test.cjs 覆盖路由解析、题号映射和主题应用

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0135Ggqqp6xktQZytLRJQ9nc
@sourcery-ai
sourcery-ai Bot dismissed their stale review September 27, 2026 10:03

Sourcery withdrew this approval because it has stopped reviewing this pull request.

@sourcery-ai

sourcery-ai Bot commented Sep 27, 2026

Copy link
Copy Markdown
Contributor

Sourcery has withdrawn its approval of this pull request. It auto-reviews a pull request 5 times, and this push is past that limit, so the approval no longer reflects code Sourcery has read.

Comment @sourcery-ai review to get a fresh review, which can approve again.

Re-reviews, rate limits and approvals

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 4 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread tests/contest-web.test.cjs
Comment thread tests/contest-web.test.cjs Outdated
claude and others added 3 commits September 27, 2026 10:38
- /web 页面与旧版页面一样移除站点的 Bootstrap 3 样式,改用 Bootstrap 5 和脚本皮肤;
  新版应用渲染的 Bootstrap 3 标记在每次渲染后映射为 Bootstrap 5 类名
  (导航栏、下拉菜单、按钮、分页、徽章等),修复出现原始“Toggle navigation”按钮的问题
- 脚本添加的按钮使用旧版页面的 btn-outline-secondary / copy-btn 样式
- 新版顶部导航栏复用 NavbarStyler,NavbarStyler 移到脚本顶层以便共用
- ResetType 用户菜单提取为 CreateUserMenuItems / InitializeUserMenu,新旧页面共用
- Translate 与 RemoveUseless 在新版页面上与旧版行为一致
- 比赛列表创建者和标程列与旧版一样使用普通链接

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0135Ggqqp6xktQZytLRJQ9nc

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

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">
P1: This line renders the `GetNotice` response directly into `innerHTML` after removing `PurifyHTML`. Marked preserves raw HTML, so a malicious or compromised notice can inject event-handler or unsafe-link markup; restore sanitization before the mention replacement.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread tests/userscript-harness.cjs Dismissed

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

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">
P1: This removes the sanitizer from notice rendering and allows HTML/event-handler XSS from `GetNotice` content. Keep `PurifyHTML` around `marked.parse` before applying the mention replacement.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

@boomzero

Copy link
Copy Markdown
Member Author

@sourcery-ai review

@sourcery-ai

sourcery-ai Bot commented Sep 27, 2026

Copy link
Copy Markdown
Contributor

Sorry @boomzero, your pull request is larger than the review limit of 150,000 diff characters

claude and others added 3 commits September 27, 2026 12:11
The load-time hide used visibility: hidden on the body, and innerText
skips invisible text, so the score captured before the reveal was empty.
Hide with opacity instead and read the score with textContent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0135Ggqqp6xktQZytLRJQ9nc

@zsTree0830 zsTree0830 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

例如按钮等的适配没那么好欸,比例很奇怪
还有比赛题目页下面多出来老 UI 脚本没有的按钮 & 样例输入输出炸了
还有刷新时怎么 topbar 一直在缩小

…king

- Problem page buttons are full size and outlined, as on the legacy page.
- With RemoveUseless, hide the repeated buttons below the statement, as
  the legacy page does.
- Sample input/output uses the legacy layout: side by side cards with the
  copy button on the right; file names are no longer oversized headings.
- The early block now also removes old stylesheet links that were parsed
  before it ran. They set the root font size to 10px/14px until
  DOMContentLoaded, so the navbar shrank and grew back on reload.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0135Ggqqp6xktQZytLRJQ9nc

Copy link
Copy Markdown
Member Author

@zsTree0830 感谢测试!三个问题都已在 3a74844 中修复:

  1. 按钮比例:比赛题目页的 提交/状态/题解/讨论 改为和旧版题目页一样的普通尺寸 btn-outline-secondary(之前是 btn-sm 加 btn-primary)。输入/输出文件名不再是大号 h3 标题,改为和旧版一样的普通文字行。
  2. 底部多出的按钮和样例:新版应用会在题面下方再渲染一排按钮。旧版脚本在开启“去除多余内容”(RemoveUseless) 时会删掉这一排,现在 /web 也一样把它隐藏。样例输入输出改用旧版题目页的样式:输入和输出左右并排显示在卡片里,复制按钮在右侧。
  3. 刷新时 topbar 缩小:原因是脚本启动时 <head> 可能已经解析完,旧的 bootstrap 3 / white.css / semantic.min.css 链接已经在页面里。早期的 MutationObserver 只能拦截之后新加入的链接,所以这些样式会一直生效到 DOMContentLoaded。在此期间根字号被改成 10px/14px,导航栏也随之先缩小再恢复。现在早期代码启动时会把已有的旧样式链接一并移除,实测多次刷新时根字号始终保持 16px,品牌字号保持 20px。

已在真实站点上对比旧版 problem.php 截图验证,麻烦再测一下 🙏


Generated by Claude Code

@boomzero
boomzero requested a review from zsTree0830 September 27, 2026 14:24

@zsTree0830 zsTree0830 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

我建议是和原来页面diff一下

包括页面:

  • 比赛题目页 /web/contest/******
  • 订正排名 /web/contest/******/rank-correct
  • 题目详情页 /web/contest/******/***

还有比赛列表的搜索

@boomzero

Copy link
Copy Markdown
Member Author

这两个渲染方式都不同,不可能完全一样啊

@boomzero

boomzero commented Sep 27, 2026 •

Copy link
Copy Markdown
Member Author

经测试,我其实觉得问题不大

@zsTree0830

Copy link
Copy Markdown
Member

只是觉得对手机端兼容性不太好
按钮太小了

@zsTree0830

Copy link
Copy Markdown
Member

还有 /web/contest/****** 标签页切回去就要刷新一下

@zsTree0830

Copy link
Copy Markdown
Member

原来 /web/contest 变成 SPA 了吗

@zsTree0830
zsTree0830 self-requested a review September 28, 2026 13:50
@boomzero
boomzero merged commit 97546b4 into dev Sep 28, 2026
9 of 11 checks passed
@boomzero
boomzero deleted the claude/issue-1009-u2n0g5 branch September 28, 2026 22:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

GitHub-related size/XXL 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.

4 participants