Skip to content

Use Monaco Editor and save code in submitpage.php when edit the content#989

Open
def-WA2025 wants to merge 13 commits into
devfrom
def-WA2025/monaco-editor-and-save-code
Open

Use Monaco Editor and save code in submitpage.php when edit the content#989
def-WA2025 wants to merge 13 commits into
devfrom
def-WA2025/monaco-editor-and-save-code

Conversation

@def-WA2025
Copy link
Copy Markdown
Member

@def-WA2025 def-WA2025 commented May 30, 2026

Inside the Monaco adapter's setSize, the catch fallback for the h === 'auto' branch contained a dead condition: typeof h === 'number' is always false because h must be 'auto' to reach that branch.

Change

  • XMOJ.user.js line 321 — replace the unreachable ternary with a direct '80px' fallback, consistent with the Math.max(80, …) floor used in the happy path above it:
// Before
} catch (e) { el.style.height = typeof h === 'number' ? h + 'px' : h; }

// After
} catch (e) { el.style.height = '80px'; }

Summary by Sourcery

Replace the submit page code editor with a Monaco-based implementation that persists code locally and update supporting editor utilities and snippets.

New Features:

  • Introduce a Monaco-based editor wrapper that loads the Monaco library on demand and exposes a CodeMirror-like adapter API.
  • Use Monaco as the primary code editor on the submit page, including keyboard shortcuts and automatic code persistence keyed to problem or contest identifiers.
  • Display a read-only Monaco (or plaintext fallback) snippet for freopen boilerplate within error messages.

Bug Fixes:

  • Ensure the Monaco editor auto-height fallback uses a fixed minimum height instead of an unreachable condition in the adapter's setSize logic.

Enhancements:

  • Refine the submit page header DOM structure for clearer, programmatically assembled problem and contest labels.

Build:

  • Bump script and package versions from 3.5.1 to 3.5.2 to reflect the new editor integration.

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented May 30, 2026

Reviewer's Guide

Integrates Monaco Editor as the primary code editor on submitpage.php (with local persistence and keyboard shortcuts), adds a CodeMirror-compatible shim backed by Monaco, updates error message code snippets to use Monaco when available, and fixes a minor height fallback bug in the Monaco adapter, with corresponding version bumps.

Sequence diagram for Monaco editor initialization on submitpage.php

sequenceDiagram
    participant Browser as Browser
    participant main as main
    participant createMonacoEditor as createMonacoEditor
    participant ensureMonaco as ensureMonaco
    participant Monaco as monaco.editor
    participant FallbackTA as CodeInput_textarea

    Browser->>main: main()
    main->>main: detect /submitpage.php
    main->>createMonacoEditor: createMonacoEditor('MonacoEditor', options)
    createMonacoEditor->>ensureMonaco: ensureMonaco()
    ensureMonaco-->>createMonacoEditor: monaco ready
    createMonacoEditor->>Monaco: monaco.editor.create(container, ...)
    Monaco-->>createMonacoEditor: editor
    createMonacoEditor-->>main: adapter (CodeMirrorElement)
    main->>Monaco: _monacoEditor.addCommand(Ctrl+Enter)
    main->>Monaco: _monacoEditor.addCommand(Ctrl+Space)

    alt Monaco load fails
        createMonacoEditor--x main: throw Error
        main->>FallbackTA: show textarea fallback
        main->>main: build fallback adapter
    end
Loading

File-Level Changes

Change Details Files
Introduce a reusable Monaco loader/editor factory plus a CodeMirror-compatible shim that wraps Monaco and provides adapters for normal and diff editors.
  • Added ensureMonaco() to lazily load Monaco via AMD loader.js from jsDelivr and configure the vs path, with timeouts and a minimal custom style for rounded editor corners and widgets.
  • Implemented createMonacoEditor(containerOrId, options) that creates a Monaco editor with configurable language, theme, minimap, layout, and read-only settings, while persisting content to localStorage under a computed key and exposing a small adapter API (get/set value, setSize with auto-height logic, focus, wrapper element, and helper actions like showFind/goToLine/selectRange).
  • Added a global CodeMirror shim that can wrap a textarea or selector, creating a placeholder adapter immediately, then asynchronously replacing its methods with those of a Monaco-backed editor, including a MergeView implementation that uses monaco.editor.createDiffEditor and distinct original/modified models with optional whitespace ignoring.
XMOJ.user.js
Replace the submitpage.php code editor with a Monaco-based editor (plus textarea fallback), and ensure code is saved/restored via Monaco’s adapter while preserving UX like titles, styling, and shortcuts.
  • Refactored the submit page header to be built via DOM APIs into a dedicated _submitPageHeader container, correctly handling both problem and contest submission labels and IDs.
  • Replaced the single CodeMirror textarea-based editor with a visible MonacoEditor div and hidden CodeInput textarea, creating a Monaco-backed CodeMirrorElement that stores code per-problem/contest in localStorage keyed by id/cid+pid and configures Ctrl+Enter (submit) and Ctrl+Space (suggest) shortcuts.
  • Added a robust fallback path when Monaco initialization fails that hides the MonacoEditor div, shows the original textarea with fixed dimensions, and wraps it in a minimal adapter implementing the same interface (get/set value, setSize, focus, etc.) so downstream code can still interact uniformly.
  • Adjusted editor sizing and border styling to use a fixed 400px height and respect the MonochromeUI setting while keeping width at 100%.
  • Ensured previously fetched code (e.g., via sid) will load into the new editor via the unified CodeMirrorElement interface, preserving existing submission flows.
XMOJ.user.js
Update the error message "freopen" code snippet display to use Monaco when available, with a graceful plain-text fallback.
  • Replaced the prior CodeMirror-based snippet field with a dynamically created div host sized to show a small code block, appended under #ErrorMessage.
  • When monaco is available, create a small read-only Monaco editor for the freopen snippet with cpp language, dark/light theme selection, automatic layout, disabled minimap, and line numbers; otherwise, append a plain pre element containing the same snippet text.
XMOJ.user.js
Fix a minor bug in the Monaco adapter size handler and bump script/package versions to 3.5.2.
  • Updated the adapter setSize() catch branch for h === 'auto' to use a direct '80px' height fallback instead of an unreachable ternary based on typeof h, aligning fallback behavior with the normal auto-height floor.
  • Bumped @Version in XMOJ.user.js and the package.json version from 3.5.1 to 3.5.2, and updated Update.json accordingly.
XMOJ.user.js
package.json
Update.json

Possibly linked issues

  • #[Feature Request] 提交时使用 Monaco Editor 编辑器: PR fulfills the issue by replacing submitpage textarea with Monaco Editor and auto-saving code locally.

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 May 30, 2026
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 30, 2026

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

Latest commit: ca1cdbe
Status: ✅  Deploy successful!
Preview URL: https://2d8054dd.xmoj-script-dev-channel.pages.dev
Branch Preview URL: https://def-wa2025-monaco-editor-and.xmoj-script-dev-channel.pages.dev

View logs

Copy link
Copy Markdown
Contributor

@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, 1 other issue, 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 document.querySelector("body > div > div.mt-3").innerHTML is an anti-pattern that can lead to XSS vulnerabilities (link)

General comments:

  • On submitpage.php the hidden #CodeInput textarea is no longer bound to the editor as it was with CodeMirror.fromTextArea; make sure you copy the Monaco editor content back into #CodeInput (e.g., in the submit handler) so the backend still receives the code.
  • In the freopen snippet error block you always append an empty div (codeHost) to #ErrorMessage and, in the fallback path, also append a
     directly to #ErrorMessage; consider either rendering the fallback 
     inside codeHost or skipping codeHost creation when Monaco is unavailable to avoid redundant markup.
  • The CodeMirror shim exposes _monacoEditor and callers reach into that to add commands; consider exposing a small public API (e.g., addCommand/triggerSuggest) on the adapter instead of using the private _monacoEditor field to keep the abstraction boundary cleaner.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- On submitpage.php the hidden #CodeInput textarea is no longer bound to the editor as it was with CodeMirror.fromTextArea; make sure you copy the Monaco editor content back into #CodeInput (e.g., in the submit handler) so the backend still receives the code.
- In the freopen snippet error block you always append an empty div (codeHost) to #ErrorMessage and, in the fallback path, also append a <pre> directly to #ErrorMessage; consider either rendering the fallback <pre> inside codeHost or skipping codeHost creation when Monaco is unavailable to avoid redundant markup.
- The CodeMirror shim exposes _monacoEditor and callers reach into that to add commands; consider exposing a small public API (e.g., addCommand/triggerSuggest) on the adapter instead of using the private _monacoEditor field to keep the abstraction boundary cleaner.

## Individual Comments

### Comment 1
<location path="XMOJ.user.js" line_range="374-383" />
<code_context>
+    shim.MergeView = function(container, options) {
</code_context>
<issue_to_address>
**suggestion (bug_risk):** MergeView hardcodes the language to C++, ignoring any mode/language passed in options.

The shim currently instantiates both models with language `'cpp'` and ignores `options.mode` (or any language option), which changes behavior compared to the CodeMirror-based MergeView for non-C++ content. Please derive the Monaco language from the provided mode (similar to `shim`/`createMonacoEditor`, mapping known CodeMirror modes and defaulting to C++) so other languages still get appropriate syntax handling.
</issue_to_address>

### Comment 2
<location path="XMOJ.user.js" line_range="3633-3638" />
<code_context>
                    document.querySelector("body > div > div.mt-3").innerHTML = `<center class="mb-3">` + `<h3>提交代码</h3>` + (SearchParams.get("id") != null ? `题目<span class="blue">${Number(SearchParams.get("id"))}</span>` : `比赛<span class="blue">${Number(SearchParams.get("cid")) + `</span>&emsp;题目<span class="blue">` + String.fromCharCode(65 + parseInt(SearchParams.get("pid")))}</span>`) + `</center>
    <div id="MonacoEditor" style="width:100%; height:400px;"></div>
    <textarea id="CodeInput" style="display:none"></textarea>
    <center class="mt-3">
        <input id="enable_O2" name="enable_O2" type="checkbox"><label for="enable_O2">打开O2开关</label>
        <br>
        <input id="Submit" class="btn btn-info mt-2" type="button" value="提交">
        <div id="ErrorElement" class="mt-2" style="display: none; text-align: left; padding: 10px;">
            <div id="ErrorMessage" style="white-space: pre; background-color: rgba(0, 0, 0, 0.1); padding: 10px; border-radius: 5px;"></div>
            <button id="PassCheck" class="btn btn-outline-secondary mt-2" style="display: none">强制提交</button>
        </div>
    </center>`;
</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 3
<location path="XMOJ.user.js" line_range="3633-3638" />
<code_context>
                    document.querySelector("body > div > div.mt-3").innerHTML = `<center class="mb-3">` + `<h3>提交代码</h3>` + (SearchParams.get("id") != null ? `题目<span class="blue">${Number(SearchParams.get("id"))}</span>` : `比赛<span class="blue">${Number(SearchParams.get("cid")) + `</span>&emsp;题目<span class="blue">` + String.fromCharCode(65 + parseInt(SearchParams.get("pid")))}</span>`) + `</center>
    <div id="MonacoEditor" style="width:100%; height:400px;"></div>
    <textarea id="CodeInput" style="display:none"></textarea>
    <center class="mt-3">
        <input id="enable_O2" name="enable_O2" type="checkbox"><label for="enable_O2">打开O2开关</label>
        <br>
        <input id="Submit" class="btn btn-info mt-2" type="button" value="提交">
        <div id="ErrorElement" class="mt-2" style="display: none; text-align: left; padding: 10px;">
            <div id="ErrorMessage" style="white-space: pre; background-color: rgba(0, 0, 0, 0.1); padding: 10px; border-radius: 5px;"></div>
            <button id="PassCheck" class="btn btn-outline-secondary mt-2" style="display: none">强制提交</button>
        </div>
    </center>`;
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-innerhtml):** User controlled data in a `document.querySelector("body > div > div.mt-3").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.

Comment thread XMOJ.user.js
Comment thread XMOJ.user.js Outdated
Comment thread XMOJ.user.js Outdated
Copy link
Copy Markdown
Contributor

@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.

New security issues found

Comment thread XMOJ.user.js Outdated
Comment thread XMOJ.user.js Outdated
Copy link
Copy Markdown
Contributor

@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.

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

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread package.json
Copy link
Copy Markdown
Contributor

@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.

3 issues found across 1 file

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread XMOJ.user.js Outdated
Comment thread XMOJ.user.js Outdated
Comment thread XMOJ.user.js Outdated
PythonSmall-Q

This comment was marked as outdated.

@PythonSmall-Q
Copy link
Copy Markdown
Member

@copilot fix all

Copy link
Copy Markdown
Contributor

Copilot AI commented May 31, 2026

@copilot fix all

Fixed all AI-detected bugs in commits ead432f and 95f5aad:

  1. Monaco bootstrap timeout – the polling fallback in ensureMonaco now rejects after 30 s instead of hanging forever.
  2. MergeView languageMergeView now derives the Monaco language from options.mode / options.language instead of always hardcoding 'cpp'.
  3. XSS via innerHTML – replaced the innerHTML assignment that embedded raw URL search params with safe DOM manipulation (createElement / textContent).
  4. Monaco init fallbackcreateMonacoEditor is now wrapped in try/catch; on failure the hidden <textarea> is shown as a functional fallback editor.
  5. package.json version – reverted the manual 3.5.2 bump back to 3.5.1 so the automated CI workflow can manage version syncing.

PythonSmall-Q and others added 2 commits May 31, 2026 16:20
Signed-off-by: Shan Wenxiao <seanoj_noreply@yeah.net>
Copilot AI changed the title Use Monaco Editor and save code in submitpage.php when edit the content. Fix always-false typeof h === 'number' check in Monaco adapter setSize May 31, 2026
@PythonSmall-Q PythonSmall-Q changed the title Fix always-false typeof h === 'number' check in Monaco adapter setSize Use Monaco Editor and save code in submitpage.php when edit the content May 31, 2026
@PythonSmall-Q
Copy link
Copy Markdown
Member

@sourcery-ai review

Copy link
Copy Markdown
Contributor

@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 left some high level feedback:

  • The CodeMirrorElement variable name is now misleading since it always wraps Monaco or a textarea fallback; consider renaming it (and related comments) to something editor-agnostic to avoid future confusion.
  • The submit page setup logic (header construction, editor creation, fallback handling, keyboard shortcuts) is quite long and nested in main; extracting this into a dedicated helper function would improve readability and make future changes to the submit page easier.
  • There are several repeated theme decisions using UtilityEnabled("DarkMode") ? 'vs-dark' : 'vs'; consider centralizing this into a small helper to ensure consistency and simplify future theme adjustments.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `CodeMirrorElement` variable name is now misleading since it always wraps Monaco or a textarea fallback; consider renaming it (and related comments) to something editor-agnostic to avoid future confusion.
- The submit page setup logic (header construction, editor creation, fallback handling, keyboard shortcuts) is quite long and nested in `main`; extracting this into a dedicated helper function would improve readability and make future changes to the submit page easier.
- There are several repeated theme decisions using `UtilityEnabled("DarkMode") ? 'vs-dark' : 'vs'`; consider centralizing this into a small helper to ensure consistency and simplify future theme adjustments.

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.

Copy link
Copy Markdown
Contributor

@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 (changes from recent commits).

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

Re-trigger cubic

Comment thread XMOJ.user.js Outdated
Comment thread XMOJ.user.js
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Signed-off-by: Shan Wenxiao <seanoj_noreply@yeah.net>
Copy link
Copy Markdown
Contributor

@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 3 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread XMOJ.user.js
Comment thread XMOJ.user.js Outdated
@PythonSmall-Q
Copy link
Copy Markdown
Member

@copilot fix new bugs found by ai

Copy link
Copy Markdown
Contributor

Copilot AI commented May 31, 2026

@copilot fix new bugs found by ai

Fixed all three open AI-detected bugs in commit Fix 3 AI review bugs: ignoreWhitespace newlines, setSize replay, fallback persistence:

  1. ignoreWhitespace collapses newlines — removed the replace(/\s+/g,' ') preprocessing that flattened multi-line code into a single line; replaced with Monaco's built-in ignoreTrimWhitespace diff-editor option.

  2. Pre-load setSize calls dropped — the shim placeholder now tracks the last setSize args in _lastSetSizeArgs and replays them on the real Monaco adapter immediately after it finishes loading.

  3. Textarea fallback drops draft persistence — the fallback now computes the same localStorageKey as Monaco would have used, restores any previously saved code on init, attaches a debounced oninput save, and exposes a real saveToLocal function.

@def-WA2025 def-WA2025 linked an issue May 31, 2026 that may be closed by this pull request
2 tasks
@cubic-dev-ai
Copy link
Copy Markdown
Contributor

cubic-dev-ai Bot commented May 31, 2026

You're iterating quickly on this pull request. To help protect your rate limits, cubic has paused automatic reviews on new pushes for now—when you're ready for another review, comment @cubic-dev-ai review.

@def-WA2025
Copy link
Copy Markdown
Member Author

@cubic-dev-ai review

@cubic-dev-ai
Copy link
Copy Markdown
Contributor

cubic-dev-ai Bot commented May 31, 2026

@cubic-dev-ai review

@def-WA2025 I have started the AI code review. It will take a few minutes to complete.

Copy link
Copy Markdown
Contributor

@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.

0 issues found across 1 file (changes from recent commits).

Re-trigger cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L 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.

[Feature Request] 提交时使用 Monaco Editor 编辑器

3 participants