Skip to content

sync: dev to extern-contrib#990

Open
github-actions[bot] wants to merge 1 commit into
extern-contribfrom
dev
Open

sync: dev to extern-contrib#990
github-actions[bot] wants to merge 1 commit into
extern-contribfrom
dev

Conversation

@github-actions

@github-actions github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

sync-branches: New code has just landed in dev, so let's bring extern-contrib up to speed!

Summary by Sourcery

Switch the XMOJ userscript code viewing and submission experience to a Monaco-based editor while keeping a CodeMirror-compatible shim and update metadata to 3.5.2.

Enhancements:

  • Load Monaco editor from a CDN and provide helper utilities to create auto-resizing, theme-aware editors with localStorage-backed content persistence.
  • Introduce a CodeMirror-compatible shim backed by Monaco, including diff/merge views and small read-only editors for inline snippets such as freopen hints.
  • Replace the submission page textarea/CodeMirror editor with a Monaco-based editor (with Ctrl+Enter submit and autosave) plus a textarea fallback when Monaco fails to load.
  • Render compile error output, problem standard solutions, and various read-only code blocks with a Monaco-themed (vs-dark) CodeMirror configuration and guard against inaccessible or missing pages before rendering.
  • Add disposal logic for transient Monaco editors created in error messages to avoid leaks and stale instances.

Build:

  • Bump script and package version from 3.5.1 to 3.5.2.

Summary by cubic

Replaced the submit editor with monaco-editor for a faster, more reliable coding experience, with autosave and a responsive layout. Added safe fallbacks and improved error displays; bumped version to 3.5.2.

  • New Features

    • Use monaco-editor on submitpage.php with localStorage autosave, Ctrl+Enter submit, and auto-fit height.
    • CodeMirror shim backed by Monaco (editor + diff/merge) and a centered loading state.
    • Read-only snippets (e.g., freopen hints) render with Monaco; graceful textarea fallback with persistence.
    • Unified dark theme to vs-dark.
  • Bug Fixes

    • Robust Monaco loading (timeout handling) and proper editor/model disposal.
    • Correct language detection in MergeView; improved setSize behavior and replay.
    • Safer CE/STD page handling and overlay cleanup to avoid bad states.
    • Reliable fallback editor persistence and keyboard shortcuts.

Written for commit 1ca8d17. Summary will update on new commits.

Review in cubic

…nt (#989)

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

* 3.5.2

* Update version info to 3.5.2

* Fix AI-detected bugs: Monaco timeout, MergeView language, XSS, fallback editor, package.json version

* Fix code review issues: MergeView language expression, em space comment, fallback interface stubs

* Bump version from 3.5.1 to 3.5.2

Signed-off-by: Shan Wenxiao <seanoj_noreply@yeah.net>

* Update time and description of 3.5.2

* Fix constant condition: replace dead typeof check with fallback '80px' in setSize

* Update time and description of 3.5.2

* 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 <seanoj_noreply@yeah.net>

* Update time and description of 3.5.2

* Fix 3 AI review bugs: ignoreWhitespace newlines, setSize replay, fallback persistence

* Update time and description of 3.5.2

* Remove rounded corners style from Monaco editor

Removed custom style for rounded corners in the Monaco editor.

Signed-off-by: zsTree <233546082+def-WA2025@users.noreply.github.com>

* Update time and description of 3.5.2

* Update time and description of 3.5.2

* Update XMOJ.user.js

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
Signed-off-by: zsTree <233546082+def-WA2025@users.noreply.github.com>

* Update time and description of 3.5.2

* Increase Monaco editor and fallback textarea height

Updated the size of the Monaco editor and fallback textarea to 550px.

Signed-off-by: zsTree <wa2025666@gmail.com>

* Update time and description of 3.5.2

* Fix typo in FileSaver.js URL

Signed-off-by: zsTree <wa2025666@gmail.com>

* Update time and description of 3.5.2

* Enhance localStorage handling and editor dimensions

Added fallback key logic for localStorage retrieval and adjusted Monaco editor height.

Signed-off-by: zsTree <wa2025666@gmail.com>

* Update time and description of 3.5.2

* Fix condition for checking saved localStorage value

Signed-off-by: zsTree <wa2025666@gmail.com>

* Update time and description of 3.5.2

* Implement auto-fit for Monaco editor and loading UI

Enhance Monaco editor integration with auto-fit feature and loading placeholder

Signed-off-by: zsTree <wa2025666@gmail.com>

* Update time and description of 3.5.2

* Refactor options handling for improved clarity

Signed-off-by: zsTree <wa2025666@gmail.com>

* Update time and description of 3.5.2

* Update XMOJ.user.js

Signed-off-by: zsTree <wa2025666@gmail.com>

* Update time and description of 3.5.2

* Define options in createMonacoEditor function

Ensure options is always defined in createMonacoEditor.

Signed-off-by: zsTree <wa2025666@gmail.com>

* Update time and description of 3.5.2

* Refactor options handling in Monaco editor functions

Signed-off-by: zsTree <wa2025666@gmail.com>

* Update time and description of 3.5.2

* Enhance dispose function for better resource management

Refactor dispose function to include editor cleanup and model disposal.

Signed-off-by: zsTree <wa2025666@gmail.com>

* Update time and description of 3.5.2

* Refactor Monaco editor initialization and disposal

Removed the creation of a custom style element for Monaco editor. Added error handling for disposing transient Monaco editors in various functions.

Signed-off-by: zsTree <wa2025666@gmail.com>

* Update time and description of 3.5.2

* Simplify error message editor disposal logic

Signed-off-by: zsTree <wa2025666@gmail.com>

* Update time and description of 3.5.2

* Modify applyAutoFit function to accept editor parameter

Signed-off-by: zsTree <wa2025666@gmail.com>

* Update time and description of 3.5.2

* Update theme from 'darcula' to 'vs-dark' & Use Cloudflare cdnjs

Signed-off-by: zsTree <wa2025666@gmail.com>

* Update time and description of 3.5.2

* Simplify submission key retrieval logic

Removed unused localStorage fallback logic for submission key.

Signed-off-by: zsTree <wa2025666@gmail.com>

* Update time and description of 3.5.2

* Improve error handling and user feedback

Enhanced error handling by adding console error logging and user alerts in DebugMode for various operations.

Signed-off-by: zsTree <wa2025666@gmail.com>

* Update time and description of 3.5.2

---------

Signed-off-by: Shan Wenxiao <seanoj_noreply@yeah.net>
Signed-off-by: zsTree <233546082+def-WA2025@users.noreply.github.com>
Signed-off-by: zsTree <wa2025666@gmail.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Shan Wenxiao <seanoj_noreply@yeah.net>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
@sourcery-ai

sourcery-ai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Replaces most CodeMirror usage with a Monaco-based editor integration for code submission and viewing, including dynamic Monaco loading, viewport-fitting layout, localStorage-backed persistence, and safer CE/standard-solution rendering, while bumping the script version to 3.5.2.

Sequence diagram for Monaco editor initialization on submit page

sequenceDiagram
    actor User
    participant Browser
    participant XMOJ_main as main
    participant ensureMonaco
    participant MonacoCDN
    participant createMonacoEditor
    participant monaco as monaco.editor
    participant FallbackTA as CodeInput_textarea

    User->>Browser: Open /submitpage.php
    Browser->>XMOJ_main: execute main()
    XMOJ_main->>Browser: Set submit page HTML (MonacoEditor, CodeInput)
    XMOJ_main->>createMonacoEditor: await createMonacoEditor('MonacoEditor', editorOptions)
    createMonacoEditor->>ensureMonaco: await ensureMonaco()
    alt monaco not loaded
        ensureMonaco->>MonacoCDN: load loader.js
        MonacoCDN-->>ensureMonaco: loader.js loaded
        ensureMonaco->>Browser: require.config({ paths: { vs: MonacoCDN } })
        ensureMonaco->>Browser: require(['vs/editor/editor.main'])
        Browser-->>ensureMonaco: monaco defined
    else monaco already available
        ensureMonaco-->>createMonacoEditor: return
    end
    createMonacoEditor->>Browser: monaco.editor.create(innerHost, options)
    Browser-->>createMonacoEditor: editor instance
    createMonacoEditor-->>XMOJ_main: Monaco adapter (CodeMirrorElement)
    XMOJ_main->>monaco: addCommand(Ctrl+Enter, Submit.click)
    XMOJ_main->>Browser: remove loadEditor placeholder

    rect rgb(245,245,245)
    alt Monaco initialization throws
        createMonacoEditor--x XMOJ_main: throw error
        XMOJ_main->>Browser: hide MonacoEditor, show CodeInput
        XMOJ_main->>FallbackTA: attach input/keydown handlers
        XMOJ_main-->>User: Fallback plain textarea editor
    end
    end
Loading

Sequence diagram for CE error message Monaco snippet lifecycle

sequenceDiagram
    participant Submit as Submit_button
    participant XMOJ_main as main
    participant _xmoj_dispose as _xmoj_disposeErrorMessageEditors
    participant ErrorMessage
    participant monaco as monaco.editor

    Submit->>XMOJ_main: Submit code
    XMOJ_main-->>Submit: Receive compile error (Response.stderr)
    XMOJ_main->>ErrorMessage: show error text
    XMOJ_main->>_xmoj_dispose: _xmoj_disposeErrorMessageEditors()
    _xmoj_dispose->>_xmoj_dispose: dispose window._xmoj_temp_error_editors
    _xmoj_dispose->>_xmoj_dispose: clean hosts with data-xmoj-error-editor

    XMOJ_main->>ErrorMessage: append copyFreopenButton
    XMOJ_main->>ErrorMessage: append codeHost div
    alt monaco available
        XMOJ_main->>monaco: monaco.editor.create(codeHost, { readOnly: true, language: 'cpp' })
        monaco-->>XMOJ_main: _tmpErrEditor
        XMOJ_main->>_xmoj_dispose: push _tmpErrEditor to window._xmoj_temp_error_editors
        XMOJ_main->>ErrorMessage: mark host data-xmoj-error-editor
    else monaco not available
        XMOJ_main->>ErrorMessage: append pre with freopen snippet
    end
Loading

File-Level Changes

Change Details Files
Introduce Monaco editor integration with async loader, auto-fit layout, and a CodeMirror-compatible shim, then use it on the submit page and for small error-snippet editors.
  • Add MonacoCDN constant and async ensureMonaco() loader that configures AMD loader and waits for monaco to be ready with error handling and timeout.
  • Implement createMonacoEditor() helper that creates a Monaco editor with optional viewport-fitting layout, localStorage-backed content persistence, and an adapter API (get/set value, size, focus, search, navigation, dispose).
  • Define a global CodeMirror shim that wraps textareas/divs and internally uses Monaco, including MergeView-style diff editors, with loading placeholders and fallbacks when Monaco fails.
  • Refactor /submitpage.php editor initialization to build a new header DOM structure, create a centered Monaco editor container with loading text, wire Ctrl+Enter/Ctrl+Space shortcuts using Monaco commands, and fall back to a plain textarea with localStorage if Monaco fails.
  • Add small transient Monaco editors in the error-message area for freopen snippets, plus _xmoj_disposeErrorMessageEditors() to clean up models/editors and associated DOM attributes.
XMOJ.user.js
Adjust theming and behaviors of existing CodeMirror-based viewers to align with Monaco’s dark theme and improve safety around CE/std solution pages.
  • Change various CodeMirror theme options from the legacy "darcula" to "vs-dark" when DarkMode is enabled so Monaco and CodeMirror visuals are consistent.
  • On ceinfo.php, only render CE content via CodeMirror when the jumbotron does not contain the unauthorized-view message, avoiding empty/forbidden states.
  • On problem_std.php, only render standard solutions if the page does not report "No such Problem!", and remove an overlay element when content is successfully shown.
  • Wrap compare view container (#CompareElement) with explicit width/height and centering styles to better host the Monaco-based MergeView shim.
XMOJ.user.js
Version bump for script and npm package metadata.
  • Update @Version metadata in XMOJ.user.js from 3.5.1 to 3.5.2.
  • Update package.json version field from 3.5.1 to 3.5.2.
XMOJ.user.js
package.json

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

@cloudflare-workers-and-pages

Copy link
Copy Markdown

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

Latest commit: 1ca8d17
Status: ✅  Deploy successful!
Preview URL: https://183dcf7d.xmoj-script-dev-channel.pages.dev

View logs

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

  • There is a large amount of duplicated try/catch + UtilityEnabled('DebugMode') + SmartAlert(...) error handling throughout the new Monaco integration; consider extracting this into a small helper (e.g. logDebugError(e, context)) to reduce repetition and make future changes to the message or behavior centralized.
  • ensureMonaco assumes a global require/AMD loader and calls require.config directly; it may be safer to guard against other libraries’ require implementations or namespace Monaco’s loader to avoid conflicts in pages that define require for other purposes.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- There is a large amount of duplicated try/catch + `UtilityEnabled('DebugMode')` + `SmartAlert(...)` error handling throughout the new Monaco integration; consider extracting this into a small helper (e.g. `logDebugError(e, context)`) to reduce repetition and make future changes to the message or behavior centralized.
- `ensureMonaco` assumes a global `require`/AMD loader and calls `require.config` directly; it may be safer to guard against other libraries’ `require` implementations or namespace Monaco’s loader to avoid conflicts in pages that define `require` for other purposes.

## Individual Comments

### Comment 1
<location path="XMOJ.user.js" line_range="5476" />
<code_context>
-                            let Temp = ParsedDocument.getElementsByTagName("pre");
-                            document.querySelector("body > div > div.mt-3").innerHTML = "";
-                            for (let i = 0; i < Temp.length; i++) {
+                            if (!ParsedDocument.getElementsByClassName("jumbotron")[0].innerHTML.includes('I am sorry, You could not view this message!')) {
+                                document.querySelector("body > div > div.mt-3").innerHTML = "";
                                 let CodeElement = document.createElement("div");
</code_context>
<issue_to_address>
**issue (bug_risk):** Guard against missing `.jumbotron` elements before accessing `[0].innerHTML`.

This assumes `getElementsByClassName("jumbotron")[0]` always exists. If the CEInfo layout changes or the element is missing, `[0]` will be `undefined` and accessing `.innerHTML` will throw. Instead, assign it to a variable and guard before use, e.g.

```js
const jumbo = ParsedDocument.getElementsByClassName("jumbotron")[0];
if (!jumbo || jumbo.innerHTML.includes('I am sorry, You could not view this message!')) {
    return; // handle restricted view / missing jumbotron
}
```

Apply the same defensive check for the `problem_std.php` usage as well.
</issue_to_address>

### Comment 2
<location path="XMOJ.user.js" line_range="5496" />
<code_context>
+                            return Response.text();
+                        }).then((Response) => {
+                            let ParsedDocument = new DOMParser().parseFromString(Response, "text/html");
+                            if (!ParsedDocument.getElementsByClassName("jumbotron")[0].innerHTML.includes('No such Problem!')) {
+                                let Temp = ParsedDocument.getElementsByTagName("pre");
+                                document.querySelector("body > div > div.mt-3").innerHTML = "";
</code_context>
<issue_to_address>
**issue:** Add a null check for the `jumbotron` element on the problem_std page.

This code assumes `getElementsByClassName("jumbotron")[0]` always exists. If the element is missing or the class changes, this will throw. Consider guarding the lookup:

```js
const jumbo = ParsedDocument.getElementsByClassName("jumbotron")[0];
if (!jumbo || jumbo.innerHTML.includes('No such Problem!')) {
    return;
}
```

This preserves the early return while preventing a null access error.
</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
let Temp = ParsedDocument.getElementsByTagName("pre");
document.querySelector("body > div > div.mt-3").innerHTML = "";
for (let i = 0; i < Temp.length; i++) {
if (!ParsedDocument.getElementsByClassName("jumbotron")[0].innerHTML.includes('I am sorry, You could not view this message!')) {

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.

issue (bug_risk): Guard against missing .jumbotron elements before accessing [0].innerHTML.

This assumes getElementsByClassName("jumbotron")[0] always exists. If the CEInfo layout changes or the element is missing, [0] will be undefined and accessing .innerHTML will throw. Instead, assign it to a variable and guard before use, e.g.

const jumbo = ParsedDocument.getElementsByClassName("jumbotron")[0];
if (!jumbo || jumbo.innerHTML.includes('I am sorry, You could not view this message!')) {
    return; // handle restricted view / missing jumbotron
}

Apply the same defensive check for the problem_std.php usage as well.

Comment thread XMOJ.user.js
return Response.text();
}).then((Response) => {
let ParsedDocument = new DOMParser().parseFromString(Response, "text/html");
if (!ParsedDocument.getElementsByClassName("jumbotron")[0].innerHTML.includes('No such Problem!')) {

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.

issue: Add a null check for the jumbotron element on the problem_std page.

This code assumes getElementsByClassName("jumbotron")[0] always exists. If the element is missing or the class changes, this will throw. Consider guarding the lookup:

const jumbo = ParsedDocument.getElementsByClassName("jumbotron")[0];
if (!jumbo || jumbo.innerHTML.includes('No such Problem!')) {
    return;
}

This preserves the early return while preventing a null access error.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant