From aad1400be9675c433918d3f11be0934fe789325d Mon Sep 17 00:00:00 2001
From: zsTree <233546082+def-WA2025@users.noreply.github.com>
Date: Sat, 30 May 2026 23:13:50 +0800
Subject: [PATCH 01/13] Use Monaco Editor and save code in submitpage.php when
edit the content.
---
XMOJ.user.js | 221 ++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 194 insertions(+), 27 deletions(-)
diff --git a/XMOJ.user.js b/XMOJ.user.js
index 8b13e45a..56474dfc 100644
--- a/XMOJ.user.js
+++ b/XMOJ.user.js
@@ -240,6 +240,162 @@ let GetUserBadge = async (Username) => {
}
}
};
+async function ensureMonaco() {
+ if (typeof monaco !== 'undefined') return;
+ const loaderUrl = 'https://cdn.jsdelivr.net/npm/monaco-editor@0.55.1/min/vs/loader.js';
+ if (typeof require === 'undefined' || typeof require.config === 'undefined') {
+ await new Promise((resolve, reject) => {
+ const s = document.createElement('script');
+ s.src = loaderUrl;
+ s.onload = () => {
+ try { require.config({ paths: { vs: 'https://cdn.jsdelivr.net/npm/monaco-editor@0.55.1/min/vs' } }); } catch (e) {}
+ resolve();
+ };
+ s.onerror = reject;
+ document.head.appendChild(s);
+ });
+ } else {
+ try { require.config({ paths: { vs: 'https://cdn.jsdelivr.net/npm/monaco-editor@0.55.1/min/vs' } }); } catch (e) {}
+ }
+ await new Promise((resolve) => {
+ try {
+ require(['vs/editor/editor.main'], function() { resolve(); });
+ } catch (e) {
+ const check = setInterval(() => { if (typeof monaco !== 'undefined') { clearInterval(check); resolve(); } }, 50);
+ }
+ });
+ if (!document.getElementById('monaco-custom-style')) {
+ const style = document.createElement('style');
+ style.id = 'monaco-custom-style';
+ style.textContent = `
+/* rounded corners + find/replace/goto UI tweaks */
+.monaco-editor, .monaco-editor .margin, .monaco-editor .overflow-guard, .monaco-editor .monaco-editor-background {
+ border-radius: 8px !important;
+}
+.monaco-editor .find-widget, .monaco-editor .replace-widget, .monaco-editor .gotoLine-widget {
+ border-radius: 8px !important;
+ overflow: hidden;
+}
+.monaco-editor .monaco-scrollable-element .monaco-editor-background {
+ border-radius: 8px !important;
+}
+ `;
+ document.head.appendChild(style);
+ }
+}
+
+async function createMonacoEditor(containerOrId, options = {}) {
+ await ensureMonaco();
+ let container = null;
+ if (typeof containerOrId === 'string') container = document.getElementById(containerOrId);
+ else container = containerOrId;
+ if (!container) throw new Error('Monaco container not found');
+ if (!container.id) container.id = 'monaco-' + Math.random().toString(36).slice(2,9);
+ const key = options.localStorageKey || ('XMOJ-Monaco-' + location.pathname + ':' + container.id);
+ const theme = options.theme || (typeof UtilityEnabled === 'function' && UtilityEnabled("DarkMode") ? 'vs-dark' : 'vs');
+ const readOnly = !!options.readOnly;
+ const language = options.language || (options.mode === 'text/x-c++src' ? 'cpp' : (options.mode || 'cpp'));
+ const editor = monaco.editor.create(container, {
+ value: options.value || '',
+ language: language,
+ automaticLayout: !!options.automaticLayout,
+ theme: theme,
+ minimap: (typeof options.minimap !== 'undefined' ? options.minimap : { enabled: false }),
+ readOnly: readOnly,
+ lineNumbers: typeof options.lineNumbers !== 'undefined' ? options.lineNumbers : 'on',
+ tabSize: options.tabSize || 4
+ });
+ try {
+ if (options.restoreOnLoad !== false) {
+ const saved = localStorage.getItem(key);
+ if (saved !== null && saved !== 'null') editor.setValue(saved);
+ }
+ } catch (e) {}
+ let saveTimer = null;
+ const doSave = () => { try { localStorage.setItem(key, editor.getValue()); } catch (e) {} };
+ editor.onDidChangeModelContent(() => { if (saveTimer) clearTimeout(saveTimer); saveTimer = setTimeout(doSave, options.saveDebounce || 500); });
+ const adapter = {
+ getValue: () => editor.getValue(),
+ setValue: (v) => { editor.setValue(v); },
+ setSize: (w, h) => { const el = container; if (w) el.style.width = w; if (h) { if (h === 'auto') { try { const lines = editor.getModel().getLineCount(); el.style.height = Math.max(80, Math.min(1200, lines * 18)) + 'px'; } catch (e) { el.style.height = typeof h === 'number' ? h + 'px' : h; } } else el.style.height = h; } try { editor.layout(); } catch (e) {} },
+ getWrapperElement: () => container,
+ focus: () => { try { editor.focus(); } catch (e) {} },
+ _monacoEditor: editor,
+ showFind: () => { try { editor.trigger('', 'editor.action.startFindReplaceAction'); } catch (e) {} },
+ goToLine: (line) => { try { editor.setPosition({ lineNumber: parseInt(line) || 1, column: 1 }); editor.revealPositionInCenter({ lineNumber: parseInt(line) || 1, column: 1 }); editor.focus(); } catch (e) {} },
+ selectRange: (sLine, sCol, eLine, eCol) => { try { editor.setSelection({ startLineNumber: sLine, startColumn: sCol, endLineNumber: eLine, endColumn: eCol }); editor.revealRangeInCenter({ startLineNumber: sLine, startColumn: sCol, endLineNumber: eLine, endColumn: eCol }); } catch (e) {} },
+ saveToLocal: doSave,
+ localStorageKey: key
+ };
+ return adapter;
+}
+
+(function() {
+ const shim = function(containerOrTextArea, options) {
+ let container = containerOrTextArea;
+ let initialValue = '';
+ if (container && container.tagName && container.tagName.toLowerCase() === 'textarea') {
+ initialValue = container.value || container.textContent || '';
+ const div = document.createElement('div');
+ div.className = 'codemirror-shim-host';
+ container.parentNode.replaceChild(div, container);
+ container = div;
+ } else if (typeof containerOrTextArea === 'string') {
+ container = document.querySelector(containerOrTextArea) || document.getElementById(containerOrTextArea);
+ }
+ if (!container) { container = document.createElement('div'); document.body.appendChild(container); }
+ container._cmValue = (options && options.value) ? options.value : initialValue;
+ const placeholderAdapter = {
+ getValue: () => container._cmValue || '',
+ setValue: (v) => { container._cmValue = v; if (container._cmEditor) try { container._cmEditor.setValue(v); } catch (e) {} },
+ setSize: (w, h) => { if (w) container.style.width = w; if (h) { if (h === 'auto') container.style.height = 'auto'; else container.style.height = h; } if (container._cmEditor) try { container._cmEditor.layout(); } catch (e) {} },
+ getWrapperElement: () => container,
+ focus: () => { if (container._cmEditor) try { container._cmEditor.focus(); } catch (e) {} },
+ _monacoEditor: null
+ };
+ (async () => {
+ try {
+ const opts = options || {};
+ await ensureMonaco();
+ const lang = opts.mode === 'text/x-c++src' || (opts.mode && opts.mode.indexOf('c++') !== -1) ? 'cpp' : (opts.language || 'cpp');
+ const monacoAdapter = await createMonacoEditor(container, Object.assign({ language: lang, value: container._cmValue || '', readOnly: !!opts.readOnly, theme: (typeof UtilityEnabled === 'function' && UtilityEnabled("DarkMode") ? 'vs-dark' : 'vs') }, opts));
+ container._cmEditor = monacoAdapter._monacoEditor;
+ placeholderAdapter.getValue = monacoAdapter.getValue;
+ placeholderAdapter.setValue = monacoAdapter.setValue;
+ placeholderAdapter.setSize = monacoAdapter.setSize;
+ placeholderAdapter.getWrapperElement = monacoAdapter.getWrapperElement;
+ placeholderAdapter.focus = monacoAdapter.focus;
+ placeholderAdapter._monacoEditor = monacoAdapter._monacoEditor;
+ } catch (e) { console.error(e); }
+ })();
+ return placeholderAdapter;
+ };
+ shim.fromTextArea = function(textarea, options) { return shim(textarea, options); };
+ shim.MergeView = function(container, options) {
+ let el = container;
+ if (typeof container === 'string') el = document.getElementById(container) || document.querySelector(container);
+ if (!el) { el = document.createElement('div'); document.body.appendChild(el); }
+ const wrapper = { ignoreWhitespace: !!(options && options.ignoreWhitespace), _diffEditor: null, _originalModel: null, _modifiedModel: null };
+ (async () => {
+ try {
+ await ensureMonaco();
+ const diffEditor = monaco.editor.createDiffEditor(el, { readOnly: !!(options && options.readOnly), theme: (typeof UtilityEnabled === 'function' && UtilityEnabled("DarkMode") ? 'vs-dark' : 'vs'), minimap: { enabled: false }, automaticLayout: true });
+ const orig = options && options.value ? options.value : '';
+ const mod = options && options.orig ? options.orig : '';
+ const origVal = wrapper.ignoreWhitespace ? orig.replace(/\s+/g,' ') : orig;
+ const modVal = wrapper.ignoreWhitespace ? mod.replace(/\s+/g,' ') : mod;
+ const originalModel = monaco.editor.createModel(origVal, 'cpp');
+ const modifiedModel = monaco.editor.createModel(modVal, 'cpp');
+ diffEditor.setModel({ original: originalModel, modified: modifiedModel });
+ wrapper._diffEditor = diffEditor;
+ wrapper._originalModel = originalModel;
+ wrapper._modifiedModel = modifiedModel;
+ } catch (e) { console.error(e); }
+ })();
+ return wrapper;
+ };
+ window.CodeMirror = shim;
+})();
/**
* Sets the HTML content of an element to display a username with optional additional information.
* @param {HTMLElement} Element - The element to set the HTML content.
@@ -3475,7 +3631,8 @@ async function main() {
} else if (location.pathname == "/submitpage.php") {
document.title = "提交代码: " + (SearchParams.get("id") != null ? "题目" + Number(SearchParams.get("id")) : "比赛" + Number(SearchParams.get("cid")));
document.querySelector("body > div > div.mt-3").innerHTML = `
` + `提交代码
` + (SearchParams.get("id") != null ? `题目${Number(SearchParams.get("id"))}` : `比赛${Number(SearchParams.get("cid")) + ` 题目` + String.fromCharCode(65 + parseInt(SearchParams.get("pid")))}`) + `
-
+
+
@@ -3489,24 +3646,21 @@ async function main() {
document.querySelector("#enable_O2").checked = true;
}
let CodeMirrorElement;
- (() => {
- CodeMirrorElement = CodeMirror.fromTextArea(document.querySelector("#CodeInput"), {
- lineNumbers: true,
- matchBrackets: true,
- mode: "text/x-c++src",
- indentUnit: 4,
- indentWithTabs: true,
- enterMode: "keep",
- tabMode: "shift",
- theme: (UtilityEnabled("DarkMode") ? "darcula" : "default"),
- extraKeys: {
- "Ctrl-Space": "autocomplete", "Ctrl-Enter": function (instance) {
- Submit.click();
- }
- }
- })
- })();
- CodeMirrorElement.setSize("100%", "auto");
+ CodeMirrorElement = await createMonacoEditor('MonacoEditor', {
+ language: 'cpp',
+ value: '',
+ automaticLayout: true,
+ theme: (UtilityEnabled("DarkMode") ? 'vs-dark' : 'vs'),
+ minimap: { enabled: false },
+ lineNumbers: 'on',
+ tabSize: 4,
+ localStorageKey: (SearchParams.get("id") != null ? ('XMOJ-Submit-id-' + SearchParams.get("id")) : ('XMOJ-Submit-cid-' + SearchParams.get("cid") + '-pid-' + SearchParams.get("pid")))
+ });
+ try {
+ CodeMirrorElement._monacoEditor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter, function() { Submit.click(); });
+ CodeMirrorElement._monacoEditor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.Space, function() { CodeMirrorElement._monacoEditor.trigger('keyboard', 'editor.action.triggerSuggest', {}); });
+ } catch (e) {}
+ CodeMirrorElement.setSize("100%", "400px");
CodeMirrorElement.getWrapperElement().style.border = UtilityEnabled("MonochromeUI") ? "2px solid var(--mono-black)" : "1px solid #ddd";
if (SearchParams.get("sid") !== null) {
@@ -3641,14 +3795,27 @@ async function main() {
}, 1500);
});
document.getElementById('ErrorMessage').appendChild(copyFreopenButton);
- let freopenCodeField = CodeMirror(document.getElementById('ErrorMessage'), {
- value: 'freopen("' + IOFilename + '.in", "r", stdin);\nfreopen("' + IOFilename + '.out", "w", stdout);',
- mode: 'text/x-c++src',
- theme: (UtilityEnabled("DarkMode") ? "darcula" : "default"),
- readOnly: true,
- lineNumbers: true
- });
- freopenCodeField.setSize("100%", "auto");
+ // create a small read-only Monaco editor or fallback text for the freopen snippet
+ let codeHost = document.createElement('div');
+ codeHost.style.width = '100%';
+ codeHost.style.height = '80px';
+ codeHost.style.marginTop = '10px';
+ document.getElementById('ErrorMessage').appendChild(codeHost);
+ if (typeof monaco !== 'undefined') {
+ monaco.editor.create(codeHost, {
+ value: 'freopen("' + IOFilename + '.in", "r", stdin);\nfreopen("' + IOFilename + '.out", "w", stdout);',
+ language: 'cpp',
+ readOnly: true,
+ theme: (UtilityEnabled("DarkMode") ? 'vs-dark' : 'vs'),
+ automaticLayout: true,
+ minimap: { enabled: false },
+ lineNumbers: 'on'
+ });
+ } else {
+ const pre = document.createElement('pre');
+ pre.textContent = 'freopen("' + IOFilename + '.in", "r", stdin);\nfreopen("' + IOFilename + '.out", "w", stdout);';
+ document.getElementById('ErrorMessage').appendChild(pre);
+ }
document.querySelector("#Submit").disabled = false;
document.querySelector("#Submit").value = "提交";
return false;
From 9a6993160fa36c9ee858e5113dd1a64ed863cab8 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
Date: Sat, 30 May 2026 15:17:17 +0000
Subject: [PATCH 02/13] 3.5.2
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 9538b928..b1f5181a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "xmoj-script",
- "version": "3.5.1",
+ "version": "3.5.2",
"description": "an improvement script for xmoj.tech",
"main": "AddonScript.js",
"scripts": {
From 6f7cc75c9013efae091c31a1407822af22e4ef1a Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
Date: Sat, 30 May 2026 15:17:24 +0000
Subject: [PATCH 03/13] Update version info to 3.5.2
---
Update.json | 11 +++++++++++
XMOJ.user.js | 2 +-
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/Update.json b/Update.json
index 4eebcd48..bd6c62ea 100644
--- a/Update.json
+++ b/Update.json
@@ -3627,6 +3627,17 @@
}
],
"Notes": "No release notes were provided for this release."
+ },
+ "3.5.2": {
+ "UpdateDate": 1780154238096,
+ "Prerelease": true,
+ "UpdateContents": [
+ {
+ "PR": 989,
+ "Description": "Use Monaco Editor and save code in submitpage.php when edit the content."
+ }
+ ],
+ "Notes": "Use Monaco Editor and save code in submitpage.php when edit the content."
}
}
}
\ No newline at end of file
diff --git a/XMOJ.user.js b/XMOJ.user.js
index 56474dfc..0b12cd3c 100644
--- a/XMOJ.user.js
+++ b/XMOJ.user.js
@@ -1,6 +1,6 @@
// ==UserScript==
// @name XMOJ
-// @version 3.5.1
+// @version 3.5.2
// @description XMOJ增强脚本
// @author @XMOJ-Script-dev, @langningchen and the community
// @namespace https://github/langningchen
From 2623c04432507520923c7911ee2928a970840a4d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 31 May 2026 08:17:53 +0000
Subject: [PATCH 04/13] Fix AI-detected bugs: Monaco timeout, MergeView
language, XSS, fallback editor, package.json version
---
XMOJ.user.js | 80 +++++++++++++++++++++++++++++++++++++++-------------
package.json | 2 +-
2 files changed, 62 insertions(+), 20 deletions(-)
diff --git a/XMOJ.user.js b/XMOJ.user.js
index 0b12cd3c..2ee4c03f 100644
--- a/XMOJ.user.js
+++ b/XMOJ.user.js
@@ -257,11 +257,12 @@ async function ensureMonaco() {
} else {
try { require.config({ paths: { vs: 'https://cdn.jsdelivr.net/npm/monaco-editor@0.55.1/min/vs' } }); } catch (e) {}
}
- await new Promise((resolve) => {
+ await new Promise((resolve, reject) => {
try {
require(['vs/editor/editor.main'], function() { resolve(); });
} catch (e) {
const check = setInterval(() => { if (typeof monaco !== 'undefined') { clearInterval(check); resolve(); } }, 50);
+ setTimeout(() => { clearInterval(check); reject(new Error('Monaco load timeout')); }, 30000);
}
});
if (!document.getElementById('monaco-custom-style')) {
@@ -384,8 +385,9 @@ async function createMonacoEditor(containerOrId, options = {}) {
const mod = options && options.orig ? options.orig : '';
const origVal = wrapper.ignoreWhitespace ? orig.replace(/\s+/g,' ') : orig;
const modVal = wrapper.ignoreWhitespace ? mod.replace(/\s+/g,' ') : mod;
- const originalModel = monaco.editor.createModel(origVal, 'cpp');
- const modifiedModel = monaco.editor.createModel(modVal, 'cpp');
+ const lang = (options && options.mode === 'text/x-c++src') || (options && options.mode && options.mode.indexOf('c++') !== -1) ? 'cpp' : (options && options.language || 'cpp');
+ const originalModel = monaco.editor.createModel(origVal, lang);
+ const modifiedModel = monaco.editor.createModel(modVal, lang);
diffEditor.setModel({ original: originalModel, modified: modifiedModel });
wrapper._diffEditor = diffEditor;
wrapper._originalModel = originalModel;
@@ -3630,7 +3632,7 @@ async function main() {
}
} else if (location.pathname == "/submitpage.php") {
document.title = "提交代码: " + (SearchParams.get("id") != null ? "题目" + Number(SearchParams.get("id")) : "比赛" + Number(SearchParams.get("cid")));
- document.querySelector("body > div > div.mt-3").innerHTML = `` + `提交代码
` + (SearchParams.get("id") != null ? `题目${Number(SearchParams.get("id"))}` : `比赛${Number(SearchParams.get("cid")) + ` 题目` + String.fromCharCode(65 + parseInt(SearchParams.get("pid")))}`) + `
+ document.querySelector("body > div > div.mt-3").innerHTML = `
@@ -3642,26 +3644,66 @@ async function main() {
`;
+ (function() {
+ const _header = document.getElementById('_submitPageHeader');
+ const _h3 = document.createElement('h3');
+ _h3.textContent = '提交代码';
+ _header.appendChild(_h3);
+ if (SearchParams.get("id") != null) {
+ _header.appendChild(document.createTextNode('题目'));
+ const _idSpan = document.createElement('span');
+ _idSpan.className = 'blue';
+ _idSpan.textContent = String(Number(SearchParams.get("id")));
+ _header.appendChild(_idSpan);
+ } else {
+ _header.appendChild(document.createTextNode('比赛'));
+ const _cidSpan = document.createElement('span');
+ _cidSpan.className = 'blue';
+ _cidSpan.textContent = String(Number(SearchParams.get("cid")));
+ _header.appendChild(_cidSpan);
+ _header.appendChild(document.createTextNode('\u2003题目'));
+ const _pidSpan = document.createElement('span');
+ _pidSpan.className = 'blue';
+ _pidSpan.textContent = String.fromCharCode(65 + parseInt(SearchParams.get("pid")));
+ _header.appendChild(_pidSpan);
+ }
+ })();
if (UtilityEnabled("AutoO2")) {
document.querySelector("#enable_O2").checked = true;
}
let CodeMirrorElement;
- CodeMirrorElement = await createMonacoEditor('MonacoEditor', {
- language: 'cpp',
- value: '',
- automaticLayout: true,
- theme: (UtilityEnabled("DarkMode") ? 'vs-dark' : 'vs'),
- minimap: { enabled: false },
- lineNumbers: 'on',
- tabSize: 4,
- localStorageKey: (SearchParams.get("id") != null ? ('XMOJ-Submit-id-' + SearchParams.get("id")) : ('XMOJ-Submit-cid-' + SearchParams.get("cid") + '-pid-' + SearchParams.get("pid")))
- });
try {
- CodeMirrorElement._monacoEditor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter, function() { Submit.click(); });
- CodeMirrorElement._monacoEditor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.Space, function() { CodeMirrorElement._monacoEditor.trigger('keyboard', 'editor.action.triggerSuggest', {}); });
- } catch (e) {}
- CodeMirrorElement.setSize("100%", "400px");
- CodeMirrorElement.getWrapperElement().style.border = UtilityEnabled("MonochromeUI") ? "2px solid var(--mono-black)" : "1px solid #ddd";
+ CodeMirrorElement = await createMonacoEditor('MonacoEditor', {
+ language: 'cpp',
+ value: '',
+ automaticLayout: true,
+ theme: (UtilityEnabled("DarkMode") ? 'vs-dark' : 'vs'),
+ minimap: { enabled: false },
+ lineNumbers: 'on',
+ tabSize: 4,
+ localStorageKey: (SearchParams.get("id") != null ? ('XMOJ-Submit-id-' + SearchParams.get("id")) : ('XMOJ-Submit-cid-' + SearchParams.get("cid") + '-pid-' + SearchParams.get("pid")))
+ });
+ try {
+ CodeMirrorElement._monacoEditor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter, function() { Submit.click(); });
+ CodeMirrorElement._monacoEditor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.Space, function() { CodeMirrorElement._monacoEditor.trigger('keyboard', 'editor.action.triggerSuggest', {}); });
+ } catch (e) {}
+ CodeMirrorElement.setSize("100%", "400px");
+ CodeMirrorElement.getWrapperElement().style.border = UtilityEnabled("MonochromeUI") ? "2px solid var(--mono-black)" : "1px solid #ddd";
+ } catch (e) {
+ const _fallbackTA = document.getElementById('CodeInput');
+ document.getElementById('MonacoEditor').style.display = 'none';
+ _fallbackTA.style.display = '';
+ _fallbackTA.style.width = '100%';
+ _fallbackTA.style.height = '400px';
+ CodeMirrorElement = {
+ getValue: () => _fallbackTA.value,
+ setValue: (v) => { _fallbackTA.value = v; },
+ setSize: (w, h) => { if (w) _fallbackTA.style.width = w; if (h) _fallbackTA.style.height = h; },
+ getWrapperElement: () => _fallbackTA,
+ focus: () => _fallbackTA.focus(),
+ _monacoEditor: null
+ };
+ }
if (SearchParams.get("sid") !== null) {
await fetch("https://www.xmoj.tech/getsource.php?id=" + SearchParams.get("sid"))
diff --git a/package.json b/package.json
index b1f5181a..9538b928 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "xmoj-script",
- "version": "3.5.2",
+ "version": "3.5.1",
"description": "an improvement script for xmoj.tech",
"main": "AddonScript.js",
"scripts": {
From a400ee2008f13e15edfceee299430ba46ae4b8f8 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 31 May 2026 08:19:11 +0000
Subject: [PATCH 05/13] Fix code review issues: MergeView language expression,
em space comment, fallback interface stubs
---
XMOJ.user.js | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/XMOJ.user.js b/XMOJ.user.js
index 2ee4c03f..0d4ec838 100644
--- a/XMOJ.user.js
+++ b/XMOJ.user.js
@@ -385,7 +385,8 @@ async function createMonacoEditor(containerOrId, options = {}) {
const mod = options && options.orig ? options.orig : '';
const origVal = wrapper.ignoreWhitespace ? orig.replace(/\s+/g,' ') : orig;
const modVal = wrapper.ignoreWhitespace ? mod.replace(/\s+/g,' ') : mod;
- const lang = (options && options.mode === 'text/x-c++src') || (options && options.mode && options.mode.indexOf('c++') !== -1) ? 'cpp' : (options && options.language || 'cpp');
+ const isCpp = (options && options.mode === 'text/x-c++src') || (options && options.mode && options.mode.indexOf('c++') !== -1);
+ const lang = isCpp ? 'cpp' : (options && options.language || 'cpp');
const originalModel = monaco.editor.createModel(origVal, lang);
const modifiedModel = monaco.editor.createModel(modVal, lang);
diffEditor.setModel({ original: originalModel, modified: modifiedModel });
@@ -3661,7 +3662,7 @@ async function main() {
_cidSpan.className = 'blue';
_cidSpan.textContent = String(Number(SearchParams.get("cid")));
_header.appendChild(_cidSpan);
- _header.appendChild(document.createTextNode('\u2003题目'));
+ _header.appendChild(document.createTextNode('\u2003题目')); // \u2003 = em space
const _pidSpan = document.createElement('span');
_pidSpan.className = 'blue';
_pidSpan.textContent = String.fromCharCode(65 + parseInt(SearchParams.get("pid")));
@@ -3701,6 +3702,11 @@ async function main() {
setSize: (w, h) => { if (w) _fallbackTA.style.width = w; if (h) _fallbackTA.style.height = h; },
getWrapperElement: () => _fallbackTA,
focus: () => _fallbackTA.focus(),
+ showFind: () => {},
+ goToLine: () => {},
+ selectRange: () => {},
+ saveToLocal: () => {},
+ localStorageKey: null,
_monacoEditor: null
};
}
From 99a34a6b150d016ebf36a39335db3c1cac74f908 Mon Sep 17 00:00:00 2001
From: Shan Wenxiao
Date: Sun, 31 May 2026 16:20:34 +0800
Subject: [PATCH 06/13] Bump version from 3.5.1 to 3.5.2
Signed-off-by: Shan Wenxiao
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 9538b928..b1f5181a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "xmoj-script",
- "version": "3.5.1",
+ "version": "3.5.2",
"description": "an improvement script for xmoj.tech",
"main": "AddonScript.js",
"scripts": {
From 61f2fd25737966f0f51f28efbcafb9648616861e Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
Date: Sun, 31 May 2026 08:20:59 +0000
Subject: [PATCH 07/13] Update time and description of 3.5.2
---
Update.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Update.json b/Update.json
index bd6c62ea..65a29c87 100644
--- a/Update.json
+++ b/Update.json
@@ -3629,7 +3629,7 @@
"Notes": "No release notes were provided for this release."
},
"3.5.2": {
- "UpdateDate": 1780154238096,
+ "UpdateDate": 1780215653791,
"Prerelease": true,
"UpdateContents": [
{
From 07c6694c717cb3a6cbfa9969a3ef0ca40708191b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 31 May 2026 08:23:44 +0000
Subject: [PATCH 08/13] Fix constant condition: replace dead typeof check with
fallback '80px' in setSize
---
XMOJ.user.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/XMOJ.user.js b/XMOJ.user.js
index 0d4ec838..45dd7140 100644
--- a/XMOJ.user.js
+++ b/XMOJ.user.js
@@ -318,7 +318,7 @@ async function createMonacoEditor(containerOrId, options = {}) {
const adapter = {
getValue: () => editor.getValue(),
setValue: (v) => { editor.setValue(v); },
- setSize: (w, h) => { const el = container; if (w) el.style.width = w; if (h) { if (h === 'auto') { try { const lines = editor.getModel().getLineCount(); el.style.height = Math.max(80, Math.min(1200, lines * 18)) + 'px'; } catch (e) { el.style.height = typeof h === 'number' ? h + 'px' : h; } } else el.style.height = h; } try { editor.layout(); } catch (e) {} },
+ setSize: (w, h) => { const el = container; if (w) el.style.width = w; if (h) { if (h === 'auto') { try { const lines = editor.getModel().getLineCount(); el.style.height = Math.max(80, Math.min(1200, lines * 18)) + 'px'; } catch (e) { el.style.height = '80px'; } } else el.style.height = h; } try { editor.layout(); } catch (e) {} },
getWrapperElement: () => container,
focus: () => { try { editor.focus(); } catch (e) {} },
_monacoEditor: editor,
From ed9cda4fc7dd24bf85ece21a11fc71b243a8aec1 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
Date: Sun, 31 May 2026 08:25:49 +0000
Subject: [PATCH 09/13] Update time and description of 3.5.2
---
Update.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Update.json b/Update.json
index 65a29c87..14c73eb8 100644
--- a/Update.json
+++ b/Update.json
@@ -3629,12 +3629,12 @@
"Notes": "No release notes were provided for this release."
},
"3.5.2": {
- "UpdateDate": 1780215653791,
+ "UpdateDate": 1780215944157,
"Prerelease": true,
"UpdateContents": [
{
"PR": 989,
- "Description": "Use Monaco Editor and save code in submitpage.php when edit the content."
+ "Description": "Use Monaco Editor and save code in submitpage.php when edit the content"
}
],
"Notes": "Use Monaco Editor and save code in submitpage.php when edit the content."
From 92ddf2b1f184ae569351b107789387adc3993bdd Mon Sep 17 00:00:00 2001
From: Shan Wenxiao
Date: Sun, 31 May 2026 16:30:07 +0800
Subject: [PATCH 10/13] Update XMOJ.user.js
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Signed-off-by: Shan Wenxiao
---
XMOJ.user.js | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/XMOJ.user.js b/XMOJ.user.js
index 45dd7140..2ac9f7e8 100644
--- a/XMOJ.user.js
+++ b/XMOJ.user.js
@@ -258,11 +258,13 @@ async function ensureMonaco() {
try { require.config({ paths: { vs: 'https://cdn.jsdelivr.net/npm/monaco-editor@0.55.1/min/vs' } }); } catch (e) {}
}
await new Promise((resolve, reject) => {
+ let check = null;
+ const done = () => { if (check) clearInterval(check); clearTimeout(timeout); resolve(); };
+ const timeout = setTimeout(() => { if (check) clearInterval(check); reject(new Error('Monaco load timeout')); }, 30000);
try {
- require(['vs/editor/editor.main'], function() { resolve(); });
+ require(['vs/editor/editor.main'], function() { done(); });
} catch (e) {
- const check = setInterval(() => { if (typeof monaco !== 'undefined') { clearInterval(check); resolve(); } }, 50);
- setTimeout(() => { clearInterval(check); reject(new Error('Monaco load timeout')); }, 30000);
+ check = setInterval(() => { if (typeof monaco !== 'undefined') done(); }, 50);
}
});
if (!document.getElementById('monaco-custom-style')) {
From f3dfa90d90cbaef0bbb523b763efd3042608bf4d Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
Date: Sun, 31 May 2026 08:30:34 +0000
Subject: [PATCH 11/13] Update time and description of 3.5.2
---
Update.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Update.json b/Update.json
index 14c73eb8..f6661c30 100644
--- a/Update.json
+++ b/Update.json
@@ -3629,7 +3629,7 @@
"Notes": "No release notes were provided for this release."
},
"3.5.2": {
- "UpdateDate": 1780215944157,
+ "UpdateDate": 1780216228797,
"Prerelease": true,
"UpdateContents": [
{
From 680c4a888d04de205bd32a65788416b739cebf8c Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 31 May 2026 08:34:17 +0000
Subject: [PATCH 12/13] Fix 3 AI review bugs: ignoreWhitespace newlines,
setSize replay, fallback persistence
---
XMOJ.user.js | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/XMOJ.user.js b/XMOJ.user.js
index 2ac9f7e8..d5bf7ebd 100644
--- a/XMOJ.user.js
+++ b/XMOJ.user.js
@@ -348,10 +348,11 @@ async function createMonacoEditor(containerOrId, options = {}) {
}
if (!container) { container = document.createElement('div'); document.body.appendChild(container); }
container._cmValue = (options && options.value) ? options.value : initialValue;
+ let _lastSetSizeArgs = null;
const placeholderAdapter = {
getValue: () => container._cmValue || '',
setValue: (v) => { container._cmValue = v; if (container._cmEditor) try { container._cmEditor.setValue(v); } catch (e) {} },
- setSize: (w, h) => { if (w) container.style.width = w; if (h) { if (h === 'auto') container.style.height = 'auto'; else container.style.height = h; } if (container._cmEditor) try { container._cmEditor.layout(); } catch (e) {} },
+ setSize: (w, h) => { _lastSetSizeArgs = [w, h]; if (w) container.style.width = w; if (h) { if (h === 'auto') container.style.height = 'auto'; else container.style.height = h; } if (container._cmEditor) try { container._cmEditor.layout(); } catch (e) {} },
getWrapperElement: () => container,
focus: () => { if (container._cmEditor) try { container._cmEditor.focus(); } catch (e) {} },
_monacoEditor: null
@@ -369,6 +370,7 @@ async function createMonacoEditor(containerOrId, options = {}) {
placeholderAdapter.getWrapperElement = monacoAdapter.getWrapperElement;
placeholderAdapter.focus = monacoAdapter.focus;
placeholderAdapter._monacoEditor = monacoAdapter._monacoEditor;
+ if (_lastSetSizeArgs) monacoAdapter.setSize(_lastSetSizeArgs[0], _lastSetSizeArgs[1]);
} catch (e) { console.error(e); }
})();
return placeholderAdapter;
@@ -382,15 +384,13 @@ async function createMonacoEditor(containerOrId, options = {}) {
(async () => {
try {
await ensureMonaco();
- const diffEditor = monaco.editor.createDiffEditor(el, { readOnly: !!(options && options.readOnly), theme: (typeof UtilityEnabled === 'function' && UtilityEnabled("DarkMode") ? 'vs-dark' : 'vs'), minimap: { enabled: false }, automaticLayout: true });
+ const diffEditor = monaco.editor.createDiffEditor(el, { readOnly: !!(options && options.readOnly), theme: (typeof UtilityEnabled === 'function' && UtilityEnabled("DarkMode") ? 'vs-dark' : 'vs'), minimap: { enabled: false }, automaticLayout: true, ignoreTrimWhitespace: !!wrapper.ignoreWhitespace });
const orig = options && options.value ? options.value : '';
const mod = options && options.orig ? options.orig : '';
- const origVal = wrapper.ignoreWhitespace ? orig.replace(/\s+/g,' ') : orig;
- const modVal = wrapper.ignoreWhitespace ? mod.replace(/\s+/g,' ') : mod;
const isCpp = (options && options.mode === 'text/x-c++src') || (options && options.mode && options.mode.indexOf('c++') !== -1);
const lang = isCpp ? 'cpp' : (options && options.language || 'cpp');
- const originalModel = monaco.editor.createModel(origVal, lang);
- const modifiedModel = monaco.editor.createModel(modVal, lang);
+ const originalModel = monaco.editor.createModel(orig, lang);
+ const modifiedModel = monaco.editor.createModel(mod, lang);
diffEditor.setModel({ original: originalModel, modified: modifiedModel });
wrapper._diffEditor = diffEditor;
wrapper._originalModel = originalModel;
@@ -3698,6 +3698,11 @@ async function main() {
_fallbackTA.style.display = '';
_fallbackTA.style.width = '100%';
_fallbackTA.style.height = '400px';
+ const _fallbackKey = SearchParams.get("id") != null ? ('XMOJ-Submit-id-' + SearchParams.get("id")) : ('XMOJ-Submit-cid-' + SearchParams.get("cid") + '-pid-' + SearchParams.get("pid"));
+ try { const _saved = localStorage.getItem(_fallbackKey); if (_saved !== null && _saved !== 'null') _fallbackTA.value = _saved; } catch (_e) {}
+ let _fallbackTimer = null;
+ const _fallbackSave = () => { try { localStorage.setItem(_fallbackKey, _fallbackTA.value); } catch (_e) {} };
+ _fallbackTA.addEventListener('input', () => { if (_fallbackTimer) clearTimeout(_fallbackTimer); _fallbackTimer = setTimeout(_fallbackSave, 500); });
CodeMirrorElement = {
getValue: () => _fallbackTA.value,
setValue: (v) => { _fallbackTA.value = v; },
@@ -3707,8 +3712,8 @@ async function main() {
showFind: () => {},
goToLine: () => {},
selectRange: () => {},
- saveToLocal: () => {},
- localStorageKey: null,
+ saveToLocal: _fallbackSave,
+ localStorageKey: _fallbackKey,
_monacoEditor: null
};
}
From ca1cdbedbfba6a0702f758e954a80d2146cc344c Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
Date: Sun, 31 May 2026 08:58:52 +0000
Subject: [PATCH 13/13] Update time and description of 3.5.2
---
Update.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Update.json b/Update.json
index f6661c30..ee7882f6 100644
--- a/Update.json
+++ b/Update.json
@@ -3629,7 +3629,7 @@
"Notes": "No release notes were provided for this release."
},
"3.5.2": {
- "UpdateDate": 1780216228797,
+ "UpdateDate": 1780217926990,
"Prerelease": true,
"UpdateContents": [
{