Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/AutoLabelIssue.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Generate a token
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/CodeQL.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: github/codeql-action/init@v3
with:
languages: "javascript"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/DependencyScan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: actions/dependency-review-action@v4
2 changes: 1 addition & 1 deletion .github/workflows/Prerelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
with:
node-version: 16
registry-url: https://registry.npmjs.org/
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Publish to npm
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/Release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
with:
node-version: 16
registry-url: https://registry.npmjs.org/
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Get version
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/UpdateToRelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
pull-requests: write
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Update to release
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/UpdateVersion.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ jobs:
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Update version
run: node ./Update/UpdateVersion.js ${{ steps.generate_token.outputs.token }} ${{ github.event.number }} "${{ github.event.pull_request.title }}"
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ jobs:
pull-requests: write
checks: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v5
with:
ref: ${{ github.event.pull_request.head.sha }} # to check out the actual pull request commit, not the merge commit
fetch-depth: 0 # a full history is required for pull request analysis
- name: 'Qodana Scan'
uses: JetBrains/qodana-action@v2024.3
uses: JetBrains/qodana-action@v2025.2
env:
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}
2 changes: 1 addition & 1 deletion .github/workflows/sync-to-extern-contrib.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
name: Syncing branches
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v5
- name: Set up Node
uses: actions/setup-node@v4
with:
Expand Down
33 changes: 33 additions & 0 deletions Update.json
Original file line number Diff line number Diff line change
Expand Up @@ -2969,6 +2969,39 @@
}
],
"Notes": "No release notes were provided for this release."
},
"2.1.1": {
"UpdateDate": 1754911555185,
"Prerelease": true,
"UpdateContents": [
{
"PR": 829,
"Description": "Update diff-match-patch library source URL"
}
],
"Notes": "No release notes were provided for this release."
},
"2.1.2": {
"UpdateDate": 1755589063111,
"Prerelease": true,
"UpdateContents": [
{
"PR": 834,
"Description": "feat: use credential management api"
}
],
"Notes": "No release notes were provided for this release."
},
"2.1.3": {
"UpdateDate": 1755596470421,
"Prerelease": true,
"UpdateContents": [
{
"PR": 835,
"Description": "feat: add user-selectable theme"
}
],
"Notes": "No release notes were provided for this release."
}
}
}
106 changes: 90 additions & 16 deletions XMOJ.user.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// ==UserScript==
// @name XMOJ
// @version 2.1.0
// @version 2.1.3
// @description XMOJ增强脚本
// @author @XMOJ-Script-dev, @langningchen and the community
// @namespace https://github/langningchen
Expand All @@ -10,7 +10,7 @@
// @require https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/codemirror.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/mode/clike/clike.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/addon/merge/merge.min.js
// @require https://cdn.jsdelivr.net/gh/google/diff-match-patch@master/javascript/diff_match_patch_uncompressed.js
// @require https://gitee.com/mirrors_google/diff-match-patch/raw/master/javascript/diff_match_patch_uncompressed.js
// @require https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.0.2/purify.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/marked/4.3.0/marked.min.js
Expand Down Expand Up @@ -441,6 +441,35 @@ let UtilityEnabled = (Name) => {
}
}
};
let storeCredential = async (username, password) => {
if ('credentials' in navigator && window.PasswordCredential) {
try {
const credential = new PasswordCredential({ id: username, password: password });
await navigator.credentials.store(credential);
} catch (e) {
console.error(e);
}
}
};
let getCredential = async () => {
if ('credentials' in navigator && window.PasswordCredential) {
try {
return await navigator.credentials.get({ password: true, mediation: 'optional' });
} catch (e) {
console.error(e);
}
}
return null;
};
let clearCredential = async () => {
if ('credentials' in navigator && window.PasswordCredential) {
try {
await navigator.credentials.preventSilentAccess();
} catch (e) {
console.error(e);
}
}
};
let RequestAPI = (Action, Data, CallBack) => {
try {
let Session = "";
Expand Down Expand Up @@ -523,6 +552,24 @@ let CurrentUsername = document.querySelector("#profile").innerText;
CurrentUsername = CurrentUsername.replaceAll(/[^a-zA-Z0-9]/g, "");
let IsAdmin = AdminUserList.indexOf(CurrentUsername) !== -1;

const prefersDark = window.matchMedia("(prefers-color-scheme: dark)");
const applyTheme = (theme) => {
document.querySelector("html").setAttribute("data-bs-theme", theme);
localStorage.setItem("UserScript-Setting-DarkMode", theme === "dark" ? "true" : "false");
};
const applySystemTheme = (e) => applyTheme(e.matches ? "dark" : "light");
let initTheme = () => {
const saved = localStorage.getItem("UserScript-Setting-Theme") || "auto";
if (saved === "auto") {
applyTheme(prefersDark.matches ? "dark" : "light");
prefersDark.addEventListener("change", applySystemTheme);
} else {
applyTheme(saved);
prefersDark.removeEventListener("change", applySystemTheme);
}
};
initTheme();


class NavbarStyler {
constructor() {
Expand Down Expand Up @@ -962,8 +1009,7 @@ async function main() {
location.href = "https://www.xmoj.tech/modifypage.php?ByUserScript=1";
});
PopupUL.children[5].addEventListener("click", () => {
localStorage.removeItem("UserScript-Username");
localStorage.removeItem("UserScript-Password");
clearCredential();
document.cookie = "PHPSESSID=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/"; //This is how you remove a cookie?
location.href = "https://www.xmoj.tech/logout.php";
});
Expand Down Expand Up @@ -1331,7 +1377,32 @@ async function main() {
} else if (Data[i].Type == "D") {
Row.classList.add("list-group-item-danger");
}
if (Data[i].Children == undefined) {
if (Data[i].ID == "Theme") {
let Label = document.createElement("label");
Label.classList.add("me-2");
Label.htmlFor = "UserScript-Setting-Theme";
Label.innerText = Data[i].Name;
Row.appendChild(Label);
let Select = document.createElement("select");
Select.classList.add("form-select", "form-select-sm", "w-auto", "d-inline");
Select.id = "UserScript-Setting-Theme";
[
["light", "亮色"],
["dark", "暗色"],
["auto", "跟随系统"]
].forEach(opt => {
let option = document.createElement("option");
option.value = opt[0];
option.innerText = opt[1];
Select.appendChild(option);
});
Select.value = localStorage.getItem("UserScript-Setting-Theme") || "auto";
Select.addEventListener("change", () => {
localStorage.setItem("UserScript-Setting-Theme", Select.value);
initTheme();
});
Row.appendChild(Select);
} else if (Data[i].Children == undefined) {
let CheckBox = document.createElement("input");
CheckBox.classList.add("form-check-input");
CheckBox.classList.add("me-1");
Expand Down Expand Up @@ -1389,7 +1460,7 @@ async function main() {
}, {"ID": "ResetType", "Type": "F", "Name": "重新排版*"}, {
"ID": "AddColorText", "Type": "A", "Name": "增加彩色文字"
}, {"ID": "AddUnits", "Type": "A", "Name": "状态界面内存与耗时添加单位"}, {
"ID": "DarkMode", "Type": "A", "Name": "使用暗色模式"
"ID": "Theme", "Type": "A", "Name": "界面主题"
}, {"ID": "AddAnimation", "Type": "A", "Name": "增加动画"}, {
"ID": "ReplaceYN", "Type": "F", "Name": "题目前状态提示替换为好看的图标"
}, {"ID": "RemoveAlerts", "Type": "D", "Name": "去除多余反复的提示"}, {
Expand Down Expand Up @@ -3213,12 +3284,11 @@ async function main() {
.then((Response) => {
return Response.text();
})
.then((Response) => {
.then(async (Response) => {
if (UtilityEnabled("LoginFailed")) {
if (Response.indexOf("history.go(-2);") != -1) {
if (UtilityEnabled("SavePassword")) {
localStorage.setItem("UserScript-Username", Username);
localStorage.setItem("UserScript-Password", Password);
await storeCredential(Username, Password);
}
let NewPage = localStorage.getItem("UserScript-LastPage");
if (NewPage == null) {
Expand All @@ -3227,8 +3297,7 @@ async function main() {
location.href = NewPage;
} else {
if (UtilityEnabled("SavePassword")) {
localStorage.removeItem("UserScript-Username");
localStorage.removeItem("UserScript-Password");
clearCredential();
}
Response = Response.substring(Response.indexOf("alert('") + 7);
Response = Response.substring(0, Response.indexOf("');"));
Expand All @@ -3244,10 +3313,15 @@ async function main() {
});
}
});
if (UtilityEnabled("SavePassword") && localStorage.getItem("UserScript-Username") != null && localStorage.getItem("UserScript-Password") != null) {
document.querySelector("#login > div:nth-child(1) > div > input").value = localStorage.getItem("UserScript-Username");
document.querySelector("#login > div:nth-child(2) > div > input").value = localStorage.getItem("UserScript-Password");
LoginButton.click();
if (UtilityEnabled("SavePassword")) {
(async () => {
let Credential = await getCredential();
if (Credential) {
document.querySelector("#login > div:nth-child(1) > div > input").value = Credential.id;
document.querySelector("#login > div:nth-child(2) > div > input").value = Credential.password;
LoginButton.click();
}
})();
}
} else if (location.pathname == "/contest_video.php" || location.pathname == "/problem_video.php") {
let ScriptData = document.querySelector("body > div > div.mt-3 > center > script").innerHTML;
Expand Down Expand Up @@ -3814,7 +3888,7 @@ int main()
AddUser.disabled = true;
RequestAPI("SendMail", {
"ToUser": String(UsernameData),
"Content": String("您好,我是" + localStorage.getItem("UserScript-Username"))
"Content": String("您好,我是" + CurrentUsername)
}, (ResponseData) => {
AddUser.children[0].style.display = "none";
AddUser.disabled = false;
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "xmoj-script",
"version": "2.1.0",
"version": "2.1.3",
"description": "an improvement script for xmoj.tech",
"main": "AddonScript.js",
"scripts": {
Expand Down
Loading