From 778dd98a8ac279f5a906fd2c664bbfde3540b6a7 Mon Sep 17 00:00:00 2001 From: boomzero Date: Sun, 22 Feb 2026 14:07:40 +0800 Subject: [PATCH 01/16] Fix contest ranking table styling for dark mode Clear inline background/color styles from XMOJ server on header and data rows so Bootstrap dark theme applies correctly. Force black background with white text on all header cells including problem letter links. Also fix rgb -> rgba for solved cell background alpha channel, and add missing text color styling for contestrank-correct.php cells. Co-Authored-By: Claude Opus 4.6 --- XMOJ.user.js | 53 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/XMOJ.user.js b/XMOJ.user.js index 74e4ef53..55581363 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -2994,11 +2994,21 @@ async function main() { document.querySelector("#rank").innerText = "比赛暂时还没有排名"; } else { document.querySelector("body > div > div.mt-3 > center > h3").innerText = document.querySelector("body > div > div.mt-3 > center > h3").innerText.substring(document.querySelector("body > div > div.mt-3 > center > h3").innerText.indexOf(" -- ") + 4) + "(OI排名)"; - document.querySelector("#rank > thead > tr > :nth-child(1)").innerText = "排名"; - document.querySelector("#rank > thead > tr > :nth-child(2)").innerText = "用户"; - document.querySelector("#rank > thead > tr > :nth-child(3)").innerText = "昵称"; - document.querySelector("#rank > thead > tr > :nth-child(4)").innerText = "AC数"; - document.querySelector("#rank > thead > tr > :nth-child(5)").innerText = "得分"; + let HeaderCells = document.querySelectorAll("#rank > thead > tr > *"); + HeaderCells[0].innerText = "排名"; + HeaderCells[1].innerText = "用户"; + HeaderCells[2].innerText = "昵称"; + HeaderCells[3].innerText = "AC数"; + HeaderCells[4].innerText = "得分"; + for (let j = 0; j < HeaderCells.length; j++) { + HeaderCells[j].removeAttribute("bgcolor"); + HeaderCells[j].style.setProperty("background-color", "black", "important"); + HeaderCells[j].style.setProperty("color", "white", "important"); + let Links = HeaderCells[j].querySelectorAll("a"); + for (let k = 0; k < Links.length; k++) { + Links[k].style.setProperty("color", "white", "important"); + } + } let RefreshOIRank = async () => { await fetch(location.href) .then((Response) => { @@ -3009,6 +3019,7 @@ async function main() { TidyTable(ParsedDocument.getElementById("rank")); let Temp = ParsedDocument.getElementById("rank").rows; for (var i = 1; i < Temp.length; i++) { + Temp[i].style.backgroundColor = ""; let MetalCell = Temp[i].cells[0]; let Metal = document.createElement("span"); Metal.innerText = MetalCell.innerText; @@ -3018,6 +3029,10 @@ async function main() { GetUsernameHTML(Temp[i].cells[1], Temp[i].cells[1].innerText); Temp[i].cells[2].innerHTML = Temp[i].cells[2].innerText; Temp[i].cells[3].innerHTML = Temp[i].cells[3].innerText; + for (let j = 0; j < 5 && j < Temp[i].cells.length; j++) { + Temp[i].cells[j].style.backgroundColor = ""; + Temp[i].cells[j].style.color = ""; + } for (let j = 5; j < Temp[i].cells.length; j++) { let InnerText = Temp[i].cells[j].innerText; let BackgroundColor = Temp[i].cells[j].style.backgroundColor; @@ -3038,7 +3053,7 @@ async function main() { } else if (FirstBlood) { BackgroundColor = "rgb(127, 127, 255)"; } else if (Solved) { - BackgroundColor = "rgb(0, 255, 0, " + Math.max(1 / 10 * (10 - ErrorCount), 0.2) + ")"; + BackgroundColor = "rgba(0, 255, 0, " + Math.max(1 / 10 * (10 - ErrorCount), 0.2) + ")"; if (ErrorCount != 0) { InnerText += " (" + (ErrorCount == 5 ? "4+" : ErrorCount) + ")"; } @@ -3080,11 +3095,21 @@ async function main() { document.querySelector("body > div > div.mt-3 > center > h3").innerText = document.querySelector("body > div > div.mt-3 > center > h3").innerText.substring(document.querySelector("body > div > div.mt-3 > center > h3").innerText.indexOf(" -- ") + 4) + "(订正排名)"; document.querySelector("body > div > div.mt-3 > center > a").remove(); } - document.querySelector("#rank > thead > tr > :nth-child(1)").innerText = "排名"; - document.querySelector("#rank > thead > tr > :nth-child(2)").innerText = "用户"; - document.querySelector("#rank > thead > tr > :nth-child(3)").innerText = "昵称"; - document.querySelector("#rank > thead > tr > :nth-child(4)").innerText = "AC数"; - document.querySelector("#rank > thead > tr > :nth-child(5)").innerText = "得分"; + let HeaderCells = document.querySelectorAll("#rank > thead > tr > *"); + HeaderCells[0].innerText = "排名"; + HeaderCells[1].innerText = "用户"; + HeaderCells[2].innerText = "昵称"; + HeaderCells[3].innerText = "AC数"; + HeaderCells[4].innerText = "得分"; + for (let j = 0; j < HeaderCells.length; j++) { + HeaderCells[j].removeAttribute("bgcolor"); + HeaderCells[j].style.setProperty("background-color", "black", "important"); + HeaderCells[j].style.setProperty("color", "white", "important"); + let Links = HeaderCells[j].querySelectorAll("a"); + for (let k = 0; k < Links.length; k++) { + Links[k].style.setProperty("color", "white", "important"); + } + } let RefreshCorrectRank = async () => { await fetch(location.href) .then((Response) => { @@ -3095,6 +3120,7 @@ async function main() { TidyTable(ParsedDocument.getElementById("rank")); let Temp = ParsedDocument.getElementById("rank").rows; for (var i = 1; i < Temp.length; i++) { + Temp[i].style.backgroundColor = ""; let MetalCell = Temp[i].cells[0]; let Metal = document.createElement("span"); Metal.innerText = MetalCell.innerText; @@ -3104,6 +3130,10 @@ async function main() { GetUsernameHTML(Temp[i].cells[1], Temp[i].cells[1].innerText); Temp[i].cells[2].innerHTML = Temp[i].cells[2].innerText; Temp[i].cells[3].innerHTML = Temp[i].cells[3].innerText; + for (let j = 0; j < 5 && j < Temp[i].cells.length; j++) { + Temp[i].cells[j].style.backgroundColor = ""; + Temp[i].cells[j].style.color = ""; + } for (let j = 5; j < Temp[i].cells.length; j++) { let InnerText = Temp[i].cells[j].innerText; let BackgroundColor = Temp[i].cells[j].style.backgroundColor; @@ -3136,6 +3166,7 @@ async function main() { } Temp[i].cells[j].innerHTML = InnerText; Temp[i].cells[j].style.backgroundColor = BackgroundColor; + Temp[i].cells[j].style.color = (UtilityEnabled("DarkMode") ? "white" : "black"); } } document.querySelector("#rank > tbody").innerHTML = ParsedDocument.querySelector("#rank > tbody").innerHTML; From ce2b7844929573a6ee001bcbb7951a3633c4acb7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 22 Feb 2026 06:09:46 +0000 Subject: [PATCH 02/16] 3.2.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9dd923ed..33bff641 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xmoj-script", - "version": "3.2.0", + "version": "3.2.1", "description": "an improvement script for xmoj.tech", "main": "AddonScript.js", "scripts": { From ba94e6f60af850b31bfbb6dc8c9b8d4d88067565 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 22 Feb 2026 06:09:52 +0000 Subject: [PATCH 03/16] Update version info to 3.2.1 --- Update.json | 11 +++++++++++ XMOJ.user.js | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Update.json b/Update.json index 467e4c56..a732b808 100644 --- a/Update.json +++ b/Update.json @@ -3385,6 +3385,17 @@ } ], "Notes": "No release notes were provided for this release." + }, + "3.2.1": { + "UpdateDate": 1771740586846, + "Prerelease": true, + "UpdateContents": [ + { + "PR": 916, + "Description": "Fix contest ranking table styling for dark mode" + } + ], + "Notes": "Fix contest ranking table colors in dark mode (contestrank-oi.php and contestrank-correct.php)" } } } \ No newline at end of file diff --git a/XMOJ.user.js b/XMOJ.user.js index 55581363..f442f8af 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -1,6 +1,6 @@ // ==UserScript== // @name XMOJ -// @version 3.2.0 +// @version 3.2.1 // @description XMOJ增强脚本 // @author @XMOJ-Script-dev, @langningchen and the community // @namespace https://github/langningchen From 455cec1a7aeb3d6cd31b657ebe2605976bcff91a Mon Sep 17 00:00:00 2001 From: boomzero Date: Mon, 23 Feb 2026 20:06:47 +0800 Subject: [PATCH 04/16] Allow metadata updates on edited PRs after bot version commit 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 --- .github/workflows/UpdateVersion.yml | 2 +- Update/UpdateVersion.js | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/UpdateVersion.yml b/.github/workflows/UpdateVersion.yml index 74a49224..b8409176 100644 --- a/.github/workflows/UpdateVersion.yml +++ b/.github/workflows/UpdateVersion.yml @@ -26,4 +26,4 @@ jobs: - name: Update version env: PR_BODY: ${{ github.event.pull_request.body }} - run: node ./Update/UpdateVersion.js ${{ steps.generate_token.outputs.token }} ${{ github.event.number }} "${{ github.event.pull_request.title }}" "$PR_BODY" + run: node ./Update/UpdateVersion.js ${{ steps.generate_token.outputs.token }} ${{ github.event.number }} "${{ github.event.pull_request.title }}" "$PR_BODY" "${{ github.event.action }}" diff --git a/Update/UpdateVersion.js b/Update/UpdateVersion.js index cd744cd8..891d2c46 100644 --- a/Update/UpdateVersion.js +++ b/Update/UpdateVersion.js @@ -8,9 +8,14 @@ execSync("gh pr checkout " + PRNumber); console.info("PR #" + PRNumber + " has been checked out."); // Check if the last commit was made by github-actions[bot] +// Only skip for synchronize events (push-triggered) to prevent infinite loops. +// For edited events (PR title/body changes), allow metadata updates even when +// the branch tip is a bot commit. +const eventAction = String(process.argv[6] || ""); const lastCommitAuthor = execSync("git log -1 --pretty=format:'%an'").toString().trim(); console.log("Last commit author: " + lastCommitAuthor); -if (lastCommitAuthor === "github-actions[bot]") { +console.log("Event action : " + eventAction); +if (lastCommitAuthor === "github-actions[bot]" && eventAction !== "edited") { console.log("Last commit was made by github-actions[bot]. Skipping to prevent infinite loop."); process.exit(0); } From 39b96b60bc328a3d272cea166ab0914616c395f1 Mon Sep 17 00:00:00 2001 From: boomzero Date: Mon, 23 Feb 2026 20:12:55 +0800 Subject: [PATCH 05/16] Gate WebSocket toast notifications by per-feature popup settings The WebSocket handler called CreateAndShowBBSMentionToast and CreateAndShowMailMentionToast unconditionally, ignoring the user's BBSPopup/MessagePopup toggle. This made behavior differ from the polling fallback, which already checks UtilityEnabled() per type. Co-Authored-By: Claude Opus 4.6 --- XMOJ.user.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/XMOJ.user.js b/XMOJ.user.js index f442f8af..c22ae7aa 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -650,11 +650,13 @@ function HandleNotificationMessage(event) { console.log("WebSocket: Server confirmed connection at timestamp", notification.timestamp); } } else if (notification.type === 'bbs_mention') { - // Backend now provides all data needed for immediate display - CreateAndShowBBSMentionToast(notification.data); + if (UtilityEnabled("BBSPopup")) { + CreateAndShowBBSMentionToast(notification.data); + } } else if (notification.type === 'mail_mention') { - // Backend now provides all data needed for immediate display - CreateAndShowMailMentionToast(notification.data); + if (UtilityEnabled("MessagePopup")) { + CreateAndShowMailMentionToast(notification.data); + } } else if (notification.type === 'pong') { if (UtilityEnabled("DebugMode")) { console.log("WebSocket: Received pong"); From b29e467fc852fe180c399255ce64eef827d6b406 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 12:14:01 +0000 Subject: [PATCH 06/16] 3.2.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 33bff641..48211b03 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xmoj-script", - "version": "3.2.1", + "version": "3.2.2", "description": "an improvement script for xmoj.tech", "main": "AddonScript.js", "scripts": { From 242ac896ea205ae4a7e35d27fc658388219ff06c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 12:14:07 +0000 Subject: [PATCH 07/16] Update version info to 3.2.2 --- Update.json | 11 +++++++++++ XMOJ.user.js | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Update.json b/Update.json index a732b808..9245a746 100644 --- a/Update.json +++ b/Update.json @@ -3396,6 +3396,17 @@ } ], "Notes": "Fix contest ranking table colors in dark mode (contestrank-oi.php and contestrank-correct.php)" + }, + "3.2.2": { + "UpdateDate": 1771848841818, + "Prerelease": true, + "UpdateContents": [ + { + "PR": 919, + "Description": "Gate WebSocket toast notifications by per-feature popup settings" + } + ], + "Notes": "Fix WebSocket notification toasts ignoring per-feature popup settings (BBSPopup/MessagePopup)." } } } \ No newline at end of file diff --git a/XMOJ.user.js b/XMOJ.user.js index c22ae7aa..76c959ad 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -1,6 +1,6 @@ // ==UserScript== // @name XMOJ -// @version 3.2.1 +// @version 3.2.2 // @description XMOJ增强脚本 // @author @XMOJ-Script-dev, @langningchen and the community // @namespace https://github/langningchen From 4e02591743c505eb2c9d3514bf30e1ae4e075920 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 12:14:19 +0000 Subject: [PATCH 08/16] Update time and description of 3.2.2 --- Update.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Update.json b/Update.json index 9245a746..fd2ce19d 100644 --- a/Update.json +++ b/Update.json @@ -3398,7 +3398,7 @@ "Notes": "Fix contest ranking table colors in dark mode (contestrank-oi.php and contestrank-correct.php)" }, "3.2.2": { - "UpdateDate": 1771848841818, + "UpdateDate": 1771848859037, "Prerelease": true, "UpdateContents": [ { From b36a7af18b99e02eb0ccc69544199f9e5065d912 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 12:14:56 +0000 Subject: [PATCH 09/16] Update time and description of 3.2.2 --- Update.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Update.json b/Update.json index fd2ce19d..5e83125a 100644 --- a/Update.json +++ b/Update.json @@ -3398,7 +3398,7 @@ "Notes": "Fix contest ranking table colors in dark mode (contestrank-oi.php and contestrank-correct.php)" }, "3.2.2": { - "UpdateDate": 1771848859037, + "UpdateDate": 1771848890966, "Prerelease": true, "UpdateContents": [ { From d40408e137069062715512b5b6e0973fba64d233 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 12:15:09 +0000 Subject: [PATCH 10/16] Update time and description of 3.2.2 --- Update.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Update.json b/Update.json index 5e83125a..4fde1618 100644 --- a/Update.json +++ b/Update.json @@ -3398,7 +3398,7 @@ "Notes": "Fix contest ranking table colors in dark mode (contestrank-oi.php and contestrank-correct.php)" }, "3.2.2": { - "UpdateDate": 1771848890966, + "UpdateDate": 1771848908637, "Prerelease": true, "UpdateContents": [ { From 4525aad96ee645caea449960b770eb2735ee5605 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 12:15:43 +0000 Subject: [PATCH 11/16] Update time and description of 3.2.2 --- Update.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Update.json b/Update.json index 4fde1618..b125dda8 100644 --- a/Update.json +++ b/Update.json @@ -3398,7 +3398,7 @@ "Notes": "Fix contest ranking table colors in dark mode (contestrank-oi.php and contestrank-correct.php)" }, "3.2.2": { - "UpdateDate": 1771848908637, + "UpdateDate": 1771848938055, "Prerelease": true, "UpdateContents": [ { From 525a7223e5e86e3886287196d30b0dd9186ad616 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 12:15:52 +0000 Subject: [PATCH 12/16] Update time and description of 3.2.2 --- Update.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Update.json b/Update.json index b125dda8..d7851a41 100644 --- a/Update.json +++ b/Update.json @@ -3398,7 +3398,7 @@ "Notes": "Fix contest ranking table colors in dark mode (contestrank-oi.php and contestrank-correct.php)" }, "3.2.2": { - "UpdateDate": 1771848938055, + "UpdateDate": 1771848951250, "Prerelease": true, "UpdateContents": [ { From f63b4d312a0702e4708775ba3498521df37a5e28 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 12:16:38 +0000 Subject: [PATCH 13/16] Update time and description of 3.2.2 --- Update.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Update.json b/Update.json index d7851a41..3cde5c6c 100644 --- a/Update.json +++ b/Update.json @@ -3398,7 +3398,7 @@ "Notes": "Fix contest ranking table colors in dark mode (contestrank-oi.php and contestrank-correct.php)" }, "3.2.2": { - "UpdateDate": 1771848951250, + "UpdateDate": 1771848993140, "Prerelease": true, "UpdateContents": [ { From d6ecb25b8bb83a100f10a694963f5012281ac7d9 Mon Sep 17 00:00:00 2001 From: boomzero Date: Mon, 23 Feb 2026 20:06:47 +0800 Subject: [PATCH 14/16] Allow metadata updates on edited PRs after bot version commit 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 --- .github/workflows/UpdateVersion.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/UpdateVersion.yml b/.github/workflows/UpdateVersion.yml index b8409176..6112841f 100644 --- a/.github/workflows/UpdateVersion.yml +++ b/.github/workflows/UpdateVersion.yml @@ -14,7 +14,7 @@ jobs: pull-requests: write contents: write runs-on: ubuntu-latest - if: github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'github-actions[bot]' + if: github.event.pull_request.head.repo.full_name == github.repository && !endsWith(github.actor, '[bot]') steps: - name: Generate a token id: generate_token From 539166db849b05ebd8a29261b3ff19b4b62f00d4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 27 Feb 2026 13:00:58 +0000 Subject: [PATCH 15/16] 3.3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 48211b03..33385212 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xmoj-script", - "version": "3.2.2", + "version": "3.3.0", "description": "an improvement script for xmoj.tech", "main": "AddonScript.js", "scripts": { From 89e401fbdf22e93fc89bc343f7ac72b418d14c4c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 27 Feb 2026 13:00:58 +0000 Subject: [PATCH 16/16] Update to release 3.3.0 --- Update.json | 15 +++++++++++++++ XMOJ.user.js | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Update.json b/Update.json index 3cde5c6c..38e5a669 100644 --- a/Update.json +++ b/Update.json @@ -3407,6 +3407,21 @@ } ], "Notes": "Fix WebSocket notification toasts ignoring per-feature popup settings (BBSPopup/MessagePopup)." + }, + "3.3.0": { + "UpdateDate": 1772197258188, + "Prerelease": false, + "UpdateContents": [ + { + "PR": 916, + "Description": "Fix contest ranking table styling for dark mode" + }, + { + "PR": 919, + "Description": "Gate WebSocket toast notifications by per-feature popup settings" + } + ], + "Notes": "Bug 修复
\n- 修复了暗色模式下比赛排名表(contestrank-oi.php 和 contestrank-correct.php)颜色显示异常的问题(#916)
\n- 修复了 WebSocket 弹窗通知未遵循各功能独立弹窗开关(BBSPopup/MessagePopup)的问题(#919)" } } } \ No newline at end of file diff --git a/XMOJ.user.js b/XMOJ.user.js index 76c959ad..4c9d072c 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -1,6 +1,6 @@ // ==UserScript== // @name XMOJ -// @version 3.2.2 +// @version 3.3.0 // @description XMOJ增强脚本 // @author @XMOJ-Script-dev, @langningchen and the community // @namespace https://github/langningchen