-
-
Notifications
You must be signed in to change notification settings - Fork 227
Replace Ace Editor with Monaco Editor #801
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
- Add most configuration options - Dispose and create editor depending on whether in view - Fix sizing issue
This comment was marked as outdated.
This comment was marked as outdated.
modules/backend/controllers/preferences/_field_editor_preview.php
Outdated
Show resolved
Hide resolved
…wip/monaco-editor
… events for editor
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 12
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
modules/backend/assets/ui/js/ajax/Handler.js (1)
40-54: Critical: Duplicate event registrations will cause double render events.The
ready()method has accidental code duplication:
delegate('render')is called twice (lines 40 and 43)- The
$renderlistener is registered twice (lines 44-46 and 51-54)This will cause the
renderSnowboard global event to fire multiple times per render cycle, potentially triggering widget double-initialization and degraded performance.🔎 Proposed fix to remove duplicate registrations
ready() { if (!window.jQuery) { return; } - delegate('render'); // Add global event for rendering in Snowboard delegate('render'); document.addEventListener('$render', () => { this.snowboard.globalEvent('render'); }); // Add "render" event for backwards compatibility window.jQuery(document).trigger('render'); - - // Add global event for rendering in Snowboard - document.addEventListener('$render', () => { - this.snowboard.globalEvent('render'); - }); }
♻️ Duplicate comments (1)
modules/backend/formwidgets/codeeditor/assets/less/codeeditor.less (1)
87-109: Codicon CSS inclusion is acceptable given Monaco's architecture.Per the previous discussion, the codicon CSS is bundled inline because Monaco doesn't export it as a separate importable module. The MIT license header is correctly preserved.
One consideration: this adds ~520 lines of icon definitions. If only a subset of icons is used, a future optimization could trim unused glyphs, though this may not be worth the maintenance overhead given these are stable definitions.
🧹 Nitpick comments (14)
modules/backend/formwidgets/codeeditor/assets/less/codeeditor.less (1)
23-28: Consider using flex shorthand for brevity.The
flex-growandflex-shrinkproperties can be combined using theflexshorthand, which is more concise and commonly used.🔎 Suggested simplification
.editor-container { - flex-grow: 1; - flex-shrink: 1; + flex: 1 1 auto; height: 100%; width: 100%; }modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/744.js (2)
1-8: Consider excluding generated bundles from source control.This appears to be a minified webpack bundle output (note the
/build/directory and minified content). Committing generated/built artifacts can increase repository size, cause merge conflicts, and complicate code reviews.Consider:
- Adding
modules/backend/formwidgets/codeeditor/assets/js/build/to.gitignore- Documenting the build process for generating these bundles
- Building assets during the deployment/CI pipeline
If there's a specific reason to commit built assets (e.g., simplified deployment without build tools), please document this decision.
2-7: Update Monaco Editor to current version.The bundle includes Monaco Editor v0.34.1 from 2022. The current stable version is 0.55.1 (November 2025). While no security vulnerabilities have been reported for v0.34.1, updating to the latest version is recommended to benefit from 3+ years of bug fixes and improvements before merging.
modules/backend/controllers/preferences/_field_editor_preview_lang.php (1)
1-8: Consider usinghref="javascript:void(0)"orrole="button"for non-navigating links.Using
href="#"can cause the page to scroll to the top when clicked (if JavaScript fails or before it captures the event). Consider usinghref="javascript:void(0)"or addingrole="button"with a proper event handler pattern to improve UX.Additionally, the inline style
margin-top: -15pxcould be moved to a CSS class for better maintainability.🔎 Suggested improvement
-<p class="help-block" style="margin-top: -15px"> +<p class="help-block preview-lang-switcher"> Preview language: - <a href="#" data-switch-lang="css">CSS</a> | - <a href="#" data-switch-lang="html">HTML</a> | - <a href="#" data-switch-lang="javascript">JavaScript</a> | - <a href="#" data-switch-lang="twig">Twig</a> | - <a href="#" data-switch-lang="php">PHP</a> + <a href="javascript:void(0)" data-switch-lang="css">CSS</a> | + <a href="javascript:void(0)" data-switch-lang="html">HTML</a> | + <a href="javascript:void(0)" data-switch-lang="javascript">JavaScript</a> | + <a href="javascript:void(0)" data-switch-lang="twig">Twig</a> | + <a href="javascript:void(0)" data-switch-lang="php">PHP</a> </p>modules/backend/formwidgets/codeeditor/assets/themes/github.tmTheme (2)
163-175: Duplicate theme rule detected.This "Built-in constant" rule for scope
constant.language(lines 163-175) duplicates an identical rule defined earlier at lines 140-151. While this doesn't break functionality (the later rule simply takes precedence), one of these entries could be removed for cleaner theme definition.🔎 Proposed fix - remove duplicate entry
Remove lines 163-175 as they duplicate the earlier definition:
</dict> - <dict> - <key>name</key> - <string>Built-in constant</string> - <key>scope</key> - <string>constant.language</string> - <key>settings</key> - <dict> - <key>fontStyle</key> - <string>bold</string> - <key>foreground</key> - <string>#000000</string> - </dict> - </dict> <dict>
200-212: Minor typo in rule name.Line 202: "Inherited class seperator" should be "Inherited class separator". This is cosmetic and doesn't affect functionality since only the
scopevalue matters for theme matching.modules/backend/formwidgets/codeeditor/assets/themes/solarized_dark.tmTheme (1)
1003-1013: Minor typo in rule name.Line 1005: "PHP: Numberic Constant" should be "PHP: Numeric Constant". This is cosmetic only.
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/.gitignore (1)
1-2: Appropriate .gitignore for development chunks.This correctly excludes development-only webpack chunks while allowing production bundles to be tracked.
Consider also ignoring source maps if they're generated during development:
🔎 Optional: extend pattern to include source maps
# Ignore dev chunks node_modules_*.js +*.js.mapmodules/backend/formwidgets/codeeditor/assets/themes/ambiance.tmTheme (2)
5-6: Theme name mismatch with filename.The file is named
ambiance.tmThemebut the theme's internal name is "Amy" (by William D. Neumann). This mismatch may cause confusion in the UI if the theme name is displayed to users, as they might expect an "Ambiance" theme but see "Amy" instead.Consider either:
- Renaming the file to
amy.tmThemeto match the theme name, or- Updating the theme name to "Ambiance" if that's the intended display name
507-519: Minor typo in scope name.Line 509 has "depricated" instead of "deprecated". While this is likely from the original theme source and won't affect functionality (it's just a label), it's a minor blemish.
modules/backend/formwidgets/codeeditor/assets/themes/chaos.tmTheme (1)
5-6: Theme name mismatch with filename.Similar to
ambiance.tmTheme, this file is namedchaos.tmThemebut the internal theme name is "[ Argonaut ]". This inconsistency may cause confusion in the theme selection UI.Consider aligning the filename with the theme name or vice versa for clarity.
modules/backend/formwidgets/codeeditor/assets/themes/chrome.tmTheme (2)
5-6: Theme name mismatch with filename.The file is named
chrome.tmThemebut the internal theme name is "CSSEdit". This is the third such mismatch in this batch (along withambiance.tmTheme→ "Amy" andchaos.tmTheme→ "[ Argonaut ]").Consider a consistent approach across all theme files to avoid user confusion in the theme picker.
59-198: Minimal styling with many empty scope entries.Several scope entries have empty
<dict/>settings (e.g., Built-in constant, User-defined constant, Variable, Storage, etc.). While valid (they'll inherit defaults), if these scopes aren't intended to be styled differently, they could be removed to reduce file size. However, keeping them may be intentional for future customization or consistency with other themes.modules/backend/formwidgets/codeeditor/assets/js/index.js (1)
674-676: Consider using console.error for theme loading failures.Using
console.logfor error conditions makes debugging harder. Considerconsole.errorfor consistency with error logging elsewhere in the codebase (e.g., line 850).🔎 Proposed fix
error: () => { - console.log(`Unable to load theme "${newTheme}"`); + console.error(`Unable to load theme "${newTheme}"`); },
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (13)
modules/backend/formwidgets/codeeditor/assets/fonts/codicon.ttfis excluded by!**/*.ttfmodules/backend/formwidgets/colorpicker/assets/js/dist/colorpicker.jsis excluded by!**/dist/**modules/backend/formwidgets/iconpicker/assets/js/dist/iconpicker.jsis excluded by!**/dist/**modules/backend/formwidgets/markdowneditor/assets/js/dist/markdowneditor.jsis excluded by!**/dist/**modules/backend/formwidgets/sensitive/assets/js/dist/sensitive.jsis excluded by!**/dist/**modules/system/assets/ui/font/fa-brands-400.ttfis excluded by!**/*.ttfmodules/system/assets/ui/font/fa-brands-400.woff2is excluded by!**/*.woff2modules/system/assets/ui/font/fa-regular-400.ttfis excluded by!**/*.ttfmodules/system/assets/ui/font/fa-regular-400.woff2is excluded by!**/*.woff2modules/system/assets/ui/font/fa-solid-900.ttfis excluded by!**/*.ttfmodules/system/assets/ui/font/fa-solid-900.woff2is excluded by!**/*.woff2modules/system/assets/ui/font/fa-v4compatibility.ttfis excluded by!**/*.ttfmodules/system/assets/ui/font/fa-v4compatibility.woff2is excluded by!**/*.woff2
📒 Files selected for processing (130)
modules/backend/ServiceProvider.phpmodules/backend/assets/js/preferences/preferences.jsmodules/backend/assets/ui/js/ajax/Handler.jsmodules/backend/assets/ui/js/build/backend.jsmodules/backend/assets/ui/js/build/manifest.jsmodules/backend/assets/ui/js/build/vendor.jsmodules/backend/assets/ui/js/pages/Preferences.jsmodules/backend/controllers/Preferences.phpmodules/backend/controllers/preferences/_example_code.phpmodules/backend/controllers/preferences/_field_editor_preview.phpmodules/backend/controllers/preferences/_field_editor_preview_lang.phpmodules/backend/formwidgets/CodeEditor.phpmodules/backend/formwidgets/MarkdownEditor.phpmodules/backend/formwidgets/codeeditor/assets/css/codeeditor.cssmodules/backend/formwidgets/codeeditor/assets/js/build-min.jsmodules/backend/formwidgets/codeeditor/assets/js/build.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/.gitignoremodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/114.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/129.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/133.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/134.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/2.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/202.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/237.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/257.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/294.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/309.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/326.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/342.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/362.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/39.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/504.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/54.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/566.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/612.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/641.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/683.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/70.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/726.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/74.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/744.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/754.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/758.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/832.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/847.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/851.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/897.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/910.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/919.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/952.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/99.jsmodules/backend/formwidgets/codeeditor/assets/js/build/css.worker.jsmodules/backend/formwidgets/codeeditor/assets/js/build/editor.worker.jsmodules/backend/formwidgets/codeeditor/assets/js/build/html.worker.jsmodules/backend/formwidgets/codeeditor/assets/js/build/json.worker.jsmodules/backend/formwidgets/codeeditor/assets/js/build/ts.worker.jsmodules/backend/formwidgets/codeeditor/assets/js/codeeditor.old.jsmodules/backend/formwidgets/codeeditor/assets/js/index.jsmodules/backend/formwidgets/codeeditor/assets/less/codeeditor.lessmodules/backend/formwidgets/codeeditor/assets/themes/ambiance.tmThememodules/backend/formwidgets/codeeditor/assets/themes/behave.tmThememodules/backend/formwidgets/codeeditor/assets/themes/chaos.tmThememodules/backend/formwidgets/codeeditor/assets/themes/chrome.tmThememodules/backend/formwidgets/codeeditor/assets/themes/clouds.tmThememodules/backend/formwidgets/codeeditor/assets/themes/clouds_midnight.tmThememodules/backend/formwidgets/codeeditor/assets/themes/cobalt.tmThememodules/backend/formwidgets/codeeditor/assets/themes/dawn.tmThememodules/backend/formwidgets/codeeditor/assets/themes/dreamweaver.tmThememodules/backend/formwidgets/codeeditor/assets/themes/eclipse.tmThememodules/backend/formwidgets/codeeditor/assets/themes/github.tmThememodules/backend/formwidgets/codeeditor/assets/themes/idle_fingers.tmThememodules/backend/formwidgets/codeeditor/assets/themes/iplastic.tmThememodules/backend/formwidgets/codeeditor/assets/themes/katzenmilch.tmThememodules/backend/formwidgets/codeeditor/assets/themes/kr_theme.tmThememodules/backend/formwidgets/codeeditor/assets/themes/kuroir.tmThememodules/backend/formwidgets/codeeditor/assets/themes/merbivore.tmThememodules/backend/formwidgets/codeeditor/assets/themes/merbivore_soft.tmThememodules/backend/formwidgets/codeeditor/assets/themes/mono_industrial.tmThememodules/backend/formwidgets/codeeditor/assets/themes/monokai.tmThememodules/backend/formwidgets/codeeditor/assets/themes/pastel_on_dark.tmThememodules/backend/formwidgets/codeeditor/assets/themes/solarized_dark.tmThememodules/backend/formwidgets/codeeditor/assets/themes/solarized_light.tmThememodules/backend/formwidgets/codeeditor/assets/themes/sqlserver.tmThememodules/backend/formwidgets/codeeditor/assets/themes/terminal.tmThememodules/backend/formwidgets/codeeditor/assets/themes/textmate.tmThememodules/backend/formwidgets/codeeditor/assets/themes/tomorrow.tmThememodules/backend/formwidgets/codeeditor/assets/themes/tomorrow_night.tmThememodules/backend/formwidgets/codeeditor/assets/themes/tomorrow_night_blue.tmThememodules/backend/formwidgets/codeeditor/assets/themes/tomorrow_night_bright.tmThememodules/backend/formwidgets/codeeditor/assets/themes/tomorrow_night_eighties.tmThememodules/backend/formwidgets/codeeditor/assets/themes/twilight.tmThememodules/backend/formwidgets/codeeditor/assets/themes/vibrant_ink.tmThememodules/backend/formwidgets/codeeditor/assets/themes/xcode.tmThememodules/backend/formwidgets/codeeditor/assets/winter.mix.jsmodules/backend/formwidgets/codeeditor/partials/_codeeditor.phpmodules/backend/formwidgets/markdowneditor/assets/css/markdowneditor.cssmodules/backend/formwidgets/markdowneditor/assets/js/markdowneditor.old.jsmodules/backend/formwidgets/markdowneditor/assets/js/src/EditorAction.jsmodules/backend/formwidgets/markdowneditor/assets/js/src/MarkdownEditor.jsmodules/backend/formwidgets/markdowneditor/assets/js/src/actions/Bold.jsmodules/backend/formwidgets/markdowneditor/assets/js/src/actions/Italic.jsmodules/backend/formwidgets/markdowneditor/assets/less/markdowneditor.lessmodules/backend/formwidgets/markdowneditor/partials/_markdowneditor.phpmodules/backend/lang/en/lang.phpmodules/backend/models/Preference.phpmodules/backend/models/preference/fields.yamlmodules/backend/package.jsonmodules/backend/winter.mix.jsmodules/cms/assets/js/winter.cmspage.jsmodules/cms/assets/js/winter.dragcomponents.jsmodules/cms/controllers/Index.phpmodules/system/assets/css/styles.cssmodules/system/assets/js/build/manifest.jsmodules/system/assets/js/build/system.debug.jsmodules/system/assets/js/build/system.jsmodules/system/assets/js/snowboard/build/snowboard.base.debug.jsmodules/system/assets/js/snowboard/build/snowboard.base.jsmodules/system/assets/js/snowboard/build/snowboard.data-attr.jsmodules/system/assets/js/snowboard/build/snowboard.extras.jsmodules/system/assets/js/snowboard/build/snowboard.request.jsmodules/system/assets/js/snowboard/build/snowboard.vendor.jsmodules/system/assets/js/snowboard/extras/StripeLoader.jsmodules/system/assets/js/snowboard/main/Snowboard.jsmodules/system/assets/ui/icons.cssmodules/system/assets/ui/storm.cssmodules/system/assets/ui/vendor/select2/css/select2.cssmodules/system/classes/asset/PackageManager.phppackage.jsonthemes/demo/pages/ajax.htm
💤 Files with no reviewable changes (2)
- modules/backend/formwidgets/codeeditor/assets/js/build.js
- modules/backend/controllers/preferences/_field_editor_preview.php
🧰 Additional context used
🧬 Code graph analysis (14)
modules/backend/assets/ui/js/build/backend.js (1)
modules/system/assets/js/snowboard/main/Snowboard.js (1)
Snowboard(21-595)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/134.js (2)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/133.js (23)
t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/39.js (13)
t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)a(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)
modules/backend/formwidgets/MarkdownEditor.php (1)
modules/system/traits/AssetMaker.php (2)
addJs(122-149)addCss(157-176)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/952.js (4)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/754.js (11)
e(1-1)e(1-1)t(1-1)n(1-1)n(1-1)n(1-1)n(1-1)n(1-1)n(1-1)n(1-1)i(1-1)modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/309.js (23)
t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/683.js (19)
t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/74.js (13)
t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/129.js (2)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/309.js (23)
t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/683.js (20)
t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)a(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/237.js (4)
modules/backend/formwidgets/codeeditor/assets/js/build/editor.worker.js (14)
e(1-1)e(1-1)e(1-1)e(1-1)e(1-1)e(1-1)e(1-1)e(1-1)e(1-1)e(1-1)e(1-1)e(1-1)e(1-1)e(1-1)modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/309.js (23)
t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/683.js (19)
t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/74.js (13)
t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)
modules/backend/ServiceProvider.php (1)
modules/system/classes/asset/PackageManager.php (3)
PackageManager(24-414)registerCallback(185-188)registerPackage(289-361)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/897.js (2)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/309.js (23)
t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/683.js (20)
t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)a(7-7)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/504.js (2)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/683.js (12)
t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/74.js (13)
t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/54.js (3)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/133.js (23)
t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/257.js (20)
t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/39.js (13)
t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)a(7-7)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/641.js (3)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/309.js (14)
t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/683.js (12)
t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/74.js (13)
t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/754.js (2)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/309.js (23)
t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)n(7-7)n(7-7)n(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/683.js (20)
t(7-7)t(7-7)t(7-7)t(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)n(7-7)n(7-7)n(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)a(7-7)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/257.js (1)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/39.js (20)
t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)a(7-7)
modules/backend/formwidgets/codeeditor/assets/js/index.js (1)
modules/backend/formwidgets/CodeEditor.php (1)
CodeEditor(15-258)
🪛 Biome (2.1.2)
modules/backend/assets/ui/js/build/manifest.js
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/74.js
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/683.js
[error] 7-7: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 7-7: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 7-7: This case is falling through to the next case.
Add a break or return statement to the end of this case to prevent fallthrough.
(lint/suspicious/noFallthroughSwitchClause)
[error] 7-7: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/39.js
[error] 7-7: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 7-7: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 7-7: This case is falling through to the next case.
Add a break or return statement to the end of this case to prevent fallthrough.
(lint/suspicious/noFallthroughSwitchClause)
[error] 7-7: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/133.js
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/309.js
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
modules/backend/assets/js/preferences/preferences.js
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/257.js
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/99.js
Outdated
Show resolved
Hide resolved
| document.addEventListener('click', this.callbacks.click, { | ||
| capture: true, | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Click listener accumulates on repeated visibility changes.
The click listener is added each time attachListeners() runs (via createEditor()), but only removed in destruct(), not in dispose(). Since the IntersectionObserver calls dispose()/createEditor() as the element enters/exits the viewport, multiple click listeners can accumulate.
🔎 Proposed fix
Move click listener cleanup to dispose():
dispose() {
if (this.disposables.length > 0) {
this.disposables.forEach((disposable) => {
disposable.dispose();
});
this.disposables = [];
}
if (this.resizeListener) {
window.removeEventListener('resize', this.callbacks.resize);
this.resizeListener = false;
}
+ if (this.clickListener) {
+ document.removeEventListener('click', this.callbacks.click, { capture: true });
+ this.clickListener = false;
+ }
if (this.editor) {
this.editor.dispose();
this.editor = null;
}
this.events.fire('dispose', this, this.editor);
}And track the listener in attachListeners():
document.addEventListener('click', this.callbacks.click, {
capture: true,
});
+ this.clickListener = true;Committable suggestion skipped: line range outside the PR's diff.
| <key>name</key> | ||
| <string>Coda</string> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Theme name mismatch with filename.
The file is named eclipse.tmTheme but the internal theme name is "Coda". This inconsistency may cause confusion when users select themes in the UI, as the displayed name won't match the expected theme.
Consider either:
- Renaming the file to
coda.tmTheme, or - Updating the internal name to "Eclipse"
🤖 Prompt for AI Agents
In modules/backend/formwidgets/codeeditor/assets/themes/eclipse.tmTheme around
lines 5 to 6, the internal theme name is "Coda" but the filename is
eclipse.tmTheme; update the inconsistency by either renaming the file to
coda.tmTheme everywhere it’s referenced (including asset imports, build scripts,
and any theme selection UI entries) or change the <string> value at these lines
to "Eclipse" so the internal name matches the filename; ensure references and
any documentation are updated accordingly and run a quick UI/theme load check to
verify the chosen approach works.
| <key>name</key> | ||
| <string>Tango</string> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Theme name mismatch with filename.
The file is named katzenmilch.tmTheme but the internal theme name is "Tango" (authored by Chris Thomas). Similar to dreamweaver.tmTheme, this inconsistency may cause confusion in theme selection.
Consider aligning the filename with the theme name for consistency across the theme assets.
🤖 Prompt for AI Agents
In modules/backend/formwidgets/codeeditor/assets/themes/katzenmilch.tmTheme
around lines 7-8, the theme's internal <string> value is "Tango" while the
filename is katzenmilch.tmTheme; update one to match the other for consistency:
either rename the file to tango.tmTheme (and adjust any references) or change
the <string> name to "Katzenmilch" (and update author/metadata if needed),
ensuring all references and packaging/manifest entries are updated accordingly.
| <dict> | ||
| <key>name</key> | ||
| <string>StringNumber</string> | ||
| <key>scope</key> | ||
| <string>string</string> | ||
| <key>settings</key> | ||
| <dict> | ||
| <key>foreground</key> | ||
| <string>#586E75</string> | ||
| </dict> | ||
| </dict> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential scope mismatch in theme rule.
The rule named "StringNumber" uses scope string, which seems inconsistent with its name. This will override the earlier "String" rule (lines 37-47) that also targets scope string, causing strings to appear in color #586E75 instead of #2AA198.
If this is intentional, the first "String" rule is redundant. If "StringNumber" was meant to target numeric values, the scope should likely be constant.numeric or similar.
🔎 Potential fixes
Option 1: If strings should be #2AA198, remove the "StringNumber" rule (lines 48-58).
Option 2: If "StringNumber" was meant for numbers, fix the scope:
<dict>
<key>name</key>
<string>StringNumber</string>
<key>scope</key>
- <string>string</string>
+ <string>constant.numeric</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#586E75</string>
</dict>
</dict>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <dict> | |
| <key>name</key> | |
| <string>StringNumber</string> | |
| <key>scope</key> | |
| <string>string</string> | |
| <key>settings</key> | |
| <dict> | |
| <key>foreground</key> | |
| <string>#586E75</string> | |
| </dict> | |
| </dict> | |
| <dict> | |
| <key>name</key> | |
| <string>StringNumber</string> | |
| <key>scope</key> | |
| <string>constant.numeric</string> | |
| <key>settings</key> | |
| <dict> | |
| <key>foreground</key> | |
| <string>#586E75</string> | |
| </dict> | |
| </dict> |
🤖 Prompt for AI Agents
In modules/backend/formwidgets/codeeditor/assets/themes/solarized_dark.tmTheme
around lines 48 to 58, the "StringNumber" rule uses scope "string" which
overrides the earlier "String" rule and causes strings to use #586E75; either
remove this redundant "StringNumber" block if strings should remain #2AA198, or
change its scope to a numeric scope such as "constant.numeric" (or
"constant.numeric, constant.integer, constant.float") so it only applies to
numbers and not general strings.
| <dict> | ||
| <key>name</key> | ||
| <string>String</string> | ||
| <key>scope</key> | ||
| <string>string</string> | ||
| <key>settings</key> | ||
| <dict> | ||
| <key>foreground</key> | ||
| <string>#2AA198</string> | ||
| </dict> | ||
| </dict> | ||
| <dict> | ||
| <key>name</key> | ||
| <string>StringNumber</string> | ||
| <key>scope</key> | ||
| <string>string</string> | ||
| <key>settings</key> | ||
| <dict> | ||
| <key>foreground</key> | ||
| <string>#586E75</string> | ||
| </dict> | ||
| </dict> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicate string scope definition may cause unintended behavior.
Lines 37-47 define string scope with foreground #2AA198 (cyan), but lines 48-58 redefine the same string scope with foreground #586E75 (base gray). The second definition will override the first, making the cyan color unused for plain strings.
If the cyan color is intended for strings, consider removing or renaming the "StringNumber" scope. If this is intentional (perhaps from the original Solarized theme source), you can ignore this note.
🤖 Prompt for AI Agents
In modules/backend/formwidgets/codeeditor/assets/themes/solarized_light.tmTheme
around lines 37 to 58 there are duplicate entries targeting the same scope
"string" (one with foreground #2AA198 and a second labeled "StringNumber" with
foreground #586E75), so the latter will override the former; fix by either
removing the redundant second dict if cyan is the intended string color, or
change the second dict's scope to the correct specific scope (e.g.,
string.number, constant.numeric.string, or another language-specific scope) or
rename the key so it targets numbers inside strings rather than the generic
"string" scope, ensuring no two dictionaries declare the identical scope.
| <key>name</key> | ||
| <string>BBEdit</string> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Theme name mismatch with filename.
The file is named sqlserver.tmTheme but the internal theme name is "BBEdit". This is the third theme file with a naming discrepancy (along with dreamweaver.tmTheme→"Eiffel" and katzenmilch.tmTheme→"Tango").
Consider a bulk renaming pass to align filenames with internal theme names across all theme assets for consistency and to avoid user confusion during theme selection.
🤖 Prompt for AI Agents
modules/backend/formwidgets/codeeditor/assets/themes/sqlserver.tmTheme around
lines 5–6: the internal theme name is "BBEdit" but the filename is
sqlserver.tmTheme; update the <string> value to match the filename (e.g.,
"sqlserver" or "SQL Server" following project naming conventions) so the
internal name and filename align, and while here run a quick pass over other
theme files (dreamweaver.tmTheme, katzenmilch.tmTheme, etc.) to fix similar
mismatches for consistency.
# Conflicts: # modules/backend/formwidgets/codeeditor/assets/css/codeeditor.css # modules/system/assets/ui/storm.css
…as well as codeeditor
Also improved the UX for previewing the code editor settings, added one-dark-pro and winter themes, renamed codeeditor's source JS file to codeeditor.js, fixed a bug with alt key binding, and removed unused code from the Preferences controller.
RichEditor is currently using Froala v2.9.3 which is difficult to customize as we don't have the original DRM files anymore. Ideally we would like to replace the codeeditor view of Froala with Monaco, but for now we'll retain ace for this use case.
…less/markdowneditor.less
…s/_markdowneditor.php
Markdown editor needs some more work, we might look at using TipTap or Milkdown / Crepe in the future.
Interacting with the PackageManager triggers a need to use the database connection to get the active theme, the database connection is not available until the boot process.
…educe issues caused by timing issues with webpack loading
For anyone else trying to track down self being clobbered, this is very handy:
(function () {
try {
const desc = Object.getOwnPropertyDescriptor(window, 'self');
console.log('window.self descriptor:', desc);
let _selfValue = window;
Object.defineProperty(window, 'self', {
configurable: true,
get() { return _selfValue; },
set(v) {
console.error('window.self set to:', v);
console.trace('stack:'); // <- prints the exact script/line
_selfValue = v;
},
});
} catch (e) {
console.warn('Failed to trap window.self:', e);
}
})();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
♻️ Duplicate comments (3)
modules/backend/formwidgets/codeeditor/assets/js/codeeditor.js (3)
196-212: Click listener cleanup missing indispose()— issue persists from prior review.The click listener is added each time
attachListeners()runs (viacreateEditor()), but cleanup only happens indestruct(), notdispose(). SinceIntersectionObservertriggersdispose()/createEditor()cycles, multiple click listeners can accumulate.🔎 Proposed fix
dispose() { if (this.disposables.length > 0) { this.disposables.forEach((disposable) => { disposable.dispose(); }); this.disposables = []; } if (this.resizeListener) { window.removeEventListener('resize', this.callbacks.resize); this.resizeListener = false; } + if (this.clickListener) { + document.removeEventListener('click', this.callbacks.click, { capture: true }); + this.clickListener = false; + } if (this.editor) { this.editor.dispose(); this.editor = null; } this.events.fire('dispose', this, this.editor); }And in
attachListeners()(around line 401-403):document.addEventListener('click', this.callbacks.click, { capture: true, }); + this.clickListener = true;
1497-1508: Null pointer dereference whenresolveris not provided — issue persists.When
addCodeLensis called without a resolver (using the defaultnull), line 1504 throws a TypeError becauseresolver(...)is invoked before the nullish coalescing operator evaluates.🔎 Proposed fix
addCodeLens(language, provider, resolver = null) { this.disposables.push( monaco.languages.registerCodeLensProvider(language, { provideCodeLenses: (model, token) => { return provider(model, token); }, resolveCodeLens: (model, codeLens, token) => { - return resolver(model, codeLens, token) ?? codeLens; + return resolver ? resolver(model, codeLens, token) : codeLens; }, }) ); }
401-411: MissingclickListenerflag update.The
clickListenerproperty is initialized but never set totruewhen the listener is added, making the flag useless for tracking.🔎 Proposed fix
document.addEventListener('click', this.callbacks.click, { capture: true, }); + this.clickListener = true;
🧹 Nitpick comments (8)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_less_less_js.js (1)
1-187: Auto-generated Monaco Editor language bundle — LGTM with one consideration.This is a webpack-generated chunk from the official
monaco-editorpackage (v0.34.1) providing LESS language support. The tokenizer and configuration are maintained upstream by Microsoft.One optional consideration: the inline base64 source map on line 187 increases bundle size. If source maps aren't needed for debugging Monaco's internal language definitions in production, consider configuring webpack to externalize or omit source maps for these vendor chunks.
modules/backend/assets/less/layout/fancylayout.less (1)
440-442: Consider using a LESS variable instead of hardcoded color.The hardcoded
#000000value reduces maintainability. For consistency with the rest of the file (which uses variables like@color-fancy-master-tabs-active-text), consider defining a variable for this color value.🔎 Suggested refactor
Define a variable (e.g.,
@color-fancy-secondary-tabs-icon-default) and use it here:.tab-collapse-icon.primary { - color: #000000; + color: @color-fancy-secondary-tabs-icon-default; }modules/backend/controllers/Preferences.php (1)
4-11: Imports look good, butApplicationExceptionandFileappear unused.The explicit facade imports are appropriate. However,
ApplicationException(line 9) andFile(line 10) are imported but not used in the visible controller code.🔎 Consider removing unused imports
use Backend\Facades\Backend; use Backend\Facades\BackendMenu; use Backend\Models\Preference as PreferenceModel; use Illuminate\Support\Facades\Lang; use System\Classes\SettingsManager; -use Winter\Storm\Exception\ApplicationException; -use Winter\Storm\Support\Facades\File; use Winter\Storm\Support\Facades\Flash;modules/backend/assets/vendor/ace-codeeditor/codeeditor.js (1)
247-263: Variable redeclaration in nested loops.The static analysis correctly identifies that
iandlenare redeclared in the second loop (line 255) after being declared in the first loop (line 251). While JavaScript hoistsvardeclarations and this works at runtime, it's a code smell that can cause confusion.🔎 Proposed fix to eliminate redeclaration
CodeEditor.prototype.disposeAttachedControls = function() { this.editor.destroy() var keys = Object.keys(this.editor.renderer) - for (var i=0, len=keys.length; i<len; i++) + for (var i=0, len=keys.length; i<len; i++) { this.editor.renderer[keys[i]] = null + } keys = Object.keys(this.editor) - for (var i=0, len=keys.length; i<len; i++) + for (i=0, len=keys.length; i<len; i++) { this.editor[keys[i]] = null + } this.editor = nullmodules/backend/formwidgets/codeeditor/assets/js/codeeditor.js (4)
28-35: Consider revoking blob URLs to prevent memory leaks.Blob URLs created via
URL.createObjectURLshould ideally be revoked after use. However, since these worker URLs are typically loaded once and cached by the browser, the impact is minimal.🔎 Proposed improvement (if workers are loaded multiple times)
// Cross-origin: create blob URL wrapper const script = `importScripts('${workerUrl}');`; const blob = new Blob([script], { type: 'application/javascript' }); - return URL.createObjectURL(blob); + const blobUrl = URL.createObjectURL(blob); + // Note: Cannot revoke immediately as worker needs the URL + // Consider caching blob URLs if workers are recreated frequently + return blobUrl;
435-446: Consider null checks for model access.
getValue()andsetValue()accessthis.modeldirectly. If called when the editor is disposed (e.g., element out of viewport), this will throw.🔎 Proposed defensive check
getValue() { + if (!this.model) { + return this.valueBag?.value ?? ''; + } return this.model.getValue(); } setValue(value) { + if (!this.model) { + if (this.valueBag) { + this.valueBag.value = value; + } + return; + } this.model.setValue(value); }
1029-1039: Early return added — redundant regex match remains.The past review issue is fixed with the early return at line 1034. However, the regex is matched twice (lines 1032 and 1036), which is inefficient.
🔎 Proposed optimization
if (color.length === 9) { return color; } - if (!color.match(/^#(..)(..)(..)(..)$/)) { + const rgbaMatch = color.match(/^#(..)(..)(..)(..)$/); + if (!rgbaMatch) { // Invalid color format - return original color return color; } - const rgba = color.match(/^#(..)(..)(..)(..)$/).slice(1).map((c) => parseInt(c, 16)); + const rgba = rgbaMatch.slice(1).map((c) => parseInt(c, 16)); rgba[3] = (rgba[3] / 0xFF).toPrecision(2); return `rgba(${rgba.join(', ')})`;
1047-1056: Missing null checks for regex matches could cause runtime errors.Both regex matches on lines 1052 and 1055 could return
nullif the color format is unexpected, causing.slice(1)to throw.🔎 Proposed defensive fix
rgbColor(color) { if (typeof color === 'object') { return color; } if (color[0] === '#') { - return color.match(/^#(..)(..)(..)/).slice(1).map((c) => parseInt(c, 16)); + const match = color.match(/^#(..)(..)(..)$/); + return match ? match.slice(1).map((c) => parseInt(c, 16)) : [0, 0, 0]; } - - return color.match(/\(([^,]+),([^,]+),([^,]+)/).slice(1).map((c) => parseInt(c, 10)); + const match = color.match(/\(([^,]+),\s*([^,]+),\s*([^,)]+)/); + return match ? match.slice(1).map((c) => parseInt(c, 10)) : [0, 0, 0]; }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (3)
modules/backend/formwidgets/colorpicker/assets/js/dist/colorpicker.jsis excluded by!**/dist/**modules/backend/formwidgets/iconpicker/assets/js/dist/iconpicker.jsis excluded by!**/dist/**modules/backend/formwidgets/sensitive/assets/js/dist/sensitive.jsis excluded by!**/dist/**
📒 Files selected for processing (135)
modules/backend/ServiceProvider.phpmodules/backend/assets/.gitignoremodules/backend/assets/css/winter.cssmodules/backend/assets/js/preferences/preferences.jsmodules/backend/assets/less/layout/fancylayout.lessmodules/backend/assets/ui/js/build/backend.jsmodules/backend/assets/ui/js/build/manifest.jsmodules/backend/assets/ui/js/build/vendor.jsmodules/backend/assets/vendor/ace-codeeditor/build-min.jsmodules/backend/assets/vendor/ace-codeeditor/build.jsmodules/backend/assets/vendor/ace-codeeditor/codeeditor.jsmodules/backend/assets/vendor/ace/ace.jsmodules/backend/assets/vendor/ace/ext-emmet.jsmodules/backend/assets/vendor/ace/ext-language_tools.jsmodules/backend/assets/vendor/ace/ext-searchbox.jsmodules/backend/assets/vendor/ace/mode-css.jsmodules/backend/assets/vendor/ace/mode-html.jsmodules/backend/assets/vendor/ace/mode-javascript.jsmodules/backend/assets/vendor/ace/mode-less.jsmodules/backend/assets/vendor/ace/mode-markdown.jsmodules/backend/assets/vendor/ace/mode-php.jsmodules/backend/assets/vendor/ace/mode-plain_text.jsmodules/backend/assets/vendor/ace/mode-sass.jsmodules/backend/assets/vendor/ace/mode-scss.jsmodules/backend/assets/vendor/ace/mode-twig.jsmodules/backend/assets/vendor/ace/mode-yaml.jsmodules/backend/assets/vendor/ace/snippets/css.jsmodules/backend/assets/vendor/ace/snippets/html.jsmodules/backend/assets/vendor/ace/snippets/javascript.jsmodules/backend/assets/vendor/ace/snippets/markdown.jsmodules/backend/assets/vendor/ace/snippets/php-inline.jsmodules/backend/assets/vendor/ace/snippets/php.jsmodules/backend/assets/vendor/ace/snippets/plain_text.jsmodules/backend/assets/vendor/ace/snippets/sass.jsmodules/backend/assets/vendor/ace/snippets/scss.jsmodules/backend/assets/vendor/ace/snippets/text.jsmodules/backend/assets/vendor/ace/snippets/twig.jsmodules/backend/assets/vendor/ace/snippets/yaml.jsmodules/backend/assets/vendor/ace/theme-ambiance.jsmodules/backend/assets/vendor/ace/theme-chaos.jsmodules/backend/assets/vendor/ace/theme-chrome.jsmodules/backend/assets/vendor/ace/theme-clouds.jsmodules/backend/assets/vendor/ace/theme-clouds_midnight.jsmodules/backend/assets/vendor/ace/theme-cobalt.jsmodules/backend/assets/vendor/ace/theme-crimson_editor.jsmodules/backend/assets/vendor/ace/theme-dawn.jsmodules/backend/assets/vendor/ace/theme-dreamweaver.jsmodules/backend/assets/vendor/ace/theme-eclipse.jsmodules/backend/assets/vendor/ace/theme-github.jsmodules/backend/assets/vendor/ace/theme-idle_fingers.jsmodules/backend/assets/vendor/ace/theme-iplastic.jsmodules/backend/assets/vendor/ace/theme-katzenmilch.jsmodules/backend/assets/vendor/ace/theme-kr_theme.jsmodules/backend/assets/vendor/ace/theme-kuroir.jsmodules/backend/assets/vendor/ace/theme-merbivore.jsmodules/backend/assets/vendor/ace/theme-merbivore_soft.jsmodules/backend/assets/vendor/ace/theme-mono_industrial.jsmodules/backend/assets/vendor/ace/theme-monokai.jsmodules/backend/assets/vendor/ace/theme-pastel_on_dark.jsmodules/backend/assets/vendor/ace/theme-solarized_dark.jsmodules/backend/assets/vendor/ace/theme-solarized_light.jsmodules/backend/assets/vendor/ace/theme-sqlserver.jsmodules/backend/assets/vendor/ace/theme-terminal.jsmodules/backend/assets/vendor/ace/theme-textmate.jsmodules/backend/assets/vendor/ace/theme-tomorrow.jsmodules/backend/assets/vendor/ace/theme-tomorrow_night.jsmodules/backend/assets/vendor/ace/theme-tomorrow_night_blue.jsmodules/backend/assets/vendor/ace/theme-tomorrow_night_bright.jsmodules/backend/assets/vendor/ace/theme-tomorrow_night_eighties.jsmodules/backend/assets/vendor/ace/theme-twilight.jsmodules/backend/assets/vendor/ace/theme-vibrant_ink.jsmodules/backend/assets/vendor/ace/theme-xcode.jsmodules/backend/assets/vendor/ace/worker-css.jsmodules/backend/assets/vendor/ace/worker-html.jsmodules/backend/assets/vendor/ace/worker-javascript.jsmodules/backend/assets/vendor/ace/worker-php.jsmodules/backend/assets/vendor/emmet/emmet.jsmodules/backend/controllers/Preferences.phpmodules/backend/controllers/preferences/_field_editor_preview_lang.phpmodules/backend/formwidgets/CodeEditor.phpmodules/backend/formwidgets/MarkdownEditor.phpmodules/backend/formwidgets/RichEditor.phpmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/133.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/257.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/39.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/851.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_css_css_js.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_html_html_js.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_ini_ini_js.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_javascript_javascript_js.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_less_less_js.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_markdown_markdown_js.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_mysql_mysql_js.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_php_php_js.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_scss_scss_js.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_twig_twig_js.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_typescript_typescript_js.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_xml_xml_js.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_yaml_yaml_js.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_language_css_cssMode_js.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_language_html_htmlMode_js.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_language_json_jsonMode_js.jsmodules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_language_typescript_tsMode_js.jsmodules/backend/formwidgets/codeeditor/assets/js/build/css.worker.jsmodules/backend/formwidgets/codeeditor/assets/js/build/editor.worker.jsmodules/backend/formwidgets/codeeditor/assets/js/build/html.worker.jsmodules/backend/formwidgets/codeeditor/assets/js/build/json.worker.jsmodules/backend/formwidgets/codeeditor/assets/js/build/ts.worker.jsmodules/backend/formwidgets/codeeditor/assets/js/codeeditor.jsmodules/backend/formwidgets/codeeditor/assets/themes/one-dark-pro.jsonmodules/backend/formwidgets/codeeditor/assets/themes/winter.jsonmodules/backend/formwidgets/codeeditor/assets/winter.mix.jsmodules/backend/formwidgets/markdowneditor/partials/_markdowneditor.phpmodules/backend/formwidgets/richeditor/partials/_richeditor.phpmodules/backend/lang/en/lang.phpmodules/backend/layouts/_head.phpmodules/backend/layouts/auth.phpmodules/backend/models/Preference.phpmodules/backend/models/preference/fields.yamlmodules/backend/widgets/table/assets/js/build-min.jsmodules/backend/widgets/table/assets/js/table.processor.dropdown.jsmodules/backend/winter.mix.jsmodules/cms/ServiceProvider.phpmodules/cms/controllers/Index.phpmodules/system/ServiceProvider.phpmodules/system/assets/js/build/manifest.jsmodules/system/assets/js/build/system.debug.jsmodules/system/assets/js/build/system.jsmodules/system/assets/js/snowboard/build/snowboard.base.debug.jsmodules/system/assets/js/snowboard/build/snowboard.base.jsmodules/system/assets/js/snowboard/build/snowboard.data-attr.jsmodules/system/assets/js/snowboard/build/snowboard.extras.jsmodules/system/assets/js/snowboard/build/snowboard.request.jspackage.json
✅ Files skipped from review due to trivial changes (3)
- modules/backend/assets/vendor/ace-codeeditor/build.js
- modules/backend/formwidgets/codeeditor/assets/themes/one-dark-pro.json
- modules/backend/assets/.gitignore
🚧 Files skipped from review as they are similar to previous changes (2)
- modules/backend/assets/ui/js/build/backend.js
- modules/backend/controllers/preferences/_field_editor_preview_lang.php
🧰 Additional context used
🧬 Code graph analysis (7)
modules/backend/formwidgets/MarkdownEditor.php (2)
modules/backend/facades/BackendAuth.php (1)
BackendAuth(16-27)modules/system/traits/AssetMaker.php (1)
addJs(122-149)
modules/backend/formwidgets/RichEditor.php (2)
modules/backend/facades/BackendAuth.php (1)
BackendAuth(16-27)modules/system/traits/AssetMaker.php (1)
addJs(122-149)
modules/backend/assets/vendor/ace-codeeditor/codeeditor.js (3)
modules/backend/formwidgets/CodeEditor.php (1)
CodeEditor(15-271)modules/backend/classes/FormField.php (1)
options(228-246)modules/cms/assets/js/winter.cmspage.js (1)
$form(268-268)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/133.js (1)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/39.js (21)
t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)a(7-7)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/39.js (2)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/133.js (23)
t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/257.js (20)
t(7-7)t(7-7)t(7-7)t(7-7)t(7-7)n(7-7)n(7-7)n(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)r(7-7)i(7-7)i(7-7)i(7-7)i(7-7)i(7-7)
modules/backend/ServiceProvider.php (1)
modules/system/classes/asset/PackageManager.php (2)
PackageManager(24-414)registerCallback(185-188)
modules/backend/controllers/Preferences.php (3)
modules/backend/facades/BackendMenu.php (1)
BackendMenu(30-41)modules/backend/models/Preference.php (1)
Preference(21-323)modules/system/classes/SettingsManager.php (1)
SettingsManager(14-417)
🪛 Biome (2.1.2)
modules/backend/assets/ui/js/build/manifest.js
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
modules/backend/assets/vendor/ace-codeeditor/codeeditor.js
[error] 255-255: Shouldn't redeclare 'i'. Consider to delete it or rename it.
'i' is defined here:
(lint/suspicious/noRedeclare)
[error] 255-255: Shouldn't redeclare 'len'. Consider to delete it or rename it.
'len' is defined here:
(lint/suspicious/noRedeclare)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/133.js
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/39.js
[error] 7-7: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 7-7: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 7-7: This case is falling through to the next case.
Add a break or return statement to the end of this case to prevent fallthrough.
(lint/suspicious/noFallthroughSwitchClause)
[error] 7-7: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/257.js
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 7-7: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
modules/backend/assets/js/preferences/preferences.js
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
🔇 Additional comments (37)
modules/backend/assets/ui/js/build/manifest.js (1)
1-1: This file is a committed build artifact—build artifacts are intentionally tracked in Winter CMS.The functional change adding chunk 908 tracking for the Monaco editor is correct and aligns with Winter CMS's established practice of committing compiled build artifacts to version control. No changes are needed.
Note: Static analysis warnings about variables being used before declaration are false positives typical of minified webpack bundles and can be safely ignored.
Likely an incorrect or invalid review comment.
modules/backend/assets/css/winter.css (1)
1024-1025: Compiled CSS output looks correct.These changes introduce explicit color handling for the tab collapse icon in both collapsed and non-collapsed states, which improves visual distinction. The compiled output correctly reflects the source LESS changes.
Note: Since this is compiled CSS, the substantive review should focus on the LESS source file (fancylayout.less).
modules/backend/assets/less/layout/fancylayout.less (1)
444-447: Good improvement using a LESS variable.Changing from hardcoded
whiteto@color-fancy-master-tabs-active-textimproves maintainability and consistency with the rest of the codebase. This makes it easier to update the color scheme in the future.modules/backend/formwidgets/MarkdownEditor.php (2)
1-11: LGTM! Explicit facade imports and namespace updates.The imports are now using fully-qualified Winter\Storm facades (
Html,Markdown) andBackend\Facades\BackendAuth, which aligns with the codebase conventions shown in the relevant code snippets.
92-97: Intentional retention of ACE for MarkdownEditor.The asset path update to
/modules/backend/assets/vendor/ace-codeeditor/build-min.jscorrectly keeps ACE for the Markdown editor while Monaco is adopted elsewhere. This aligns with the PR discussion noting that Monaco integration for Markdown is deferred.modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_ini_ini_js.js (1)
1-88: LGTM! Standard Monaco INI language bundle.This is a webpack-generated Monaco Editor basic language module for INI files. The bundle correctly exports
confandlanguagebindings following the established Monaco language definition pattern used across other language bundles in this PR.modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_mysql_mysql_js.js (1)
1-895: LGTM! Standard Monaco MySQL language bundle.This is a webpack-generated Monaco Editor basic language module for MySQL. The comprehensive SQL syntax support including keywords, operators, built-in functions, and tokenizer states follows the standard Monaco language definition pattern.
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_scss_scss_js.js (1)
1-262: LGTM! Standard Monaco SCSS language bundle.This is a webpack-generated Monaco Editor basic language module for SCSS. The tokenizer correctly handles SCSS-specific constructs including variables, mixins, functions, control statements, and nested properties.
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_php_php_js.js (1)
1-491: LGTM! Standard Monaco PHP language bundle.This is a webpack-generated Monaco Editor basic language module for PHP with comprehensive support for mixed PHP/HTML content. The tokenizer correctly handles embedded contexts (JavaScript in
<script>, CSS in<style>) and PHP block transitions, which is essential for Winter CMS template editing.modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_twig_twig_js.js (1)
1-343: LGTM! Standard Monaco Twig language bundle.This is a webpack-generated Monaco Editor basic language module for Twig. The tokenizer correctly handles Twig-specific delimiters (
{# #},{% %},{{ }}), verbatim blocks, and embedded HTML/JavaScript/CSS contexts. This is particularly valuable for Winter CMS template editing.modules/backend/controllers/Preferences.php (1)
34-42: LGTM! Asset loading simplified for preferences.The constructor correctly removes direct code editor asset loading. The code editor assets are now managed centrally through the ServiceProvider's asset bundle registration, and only the preferences-specific JavaScript remains.
modules/backend/formwidgets/RichEditor.php (1)
1-14: LGTM! Import additions are all used.All newly added facade imports (Backend, BackendAuth, App, Lang, Request, Config, Event, File) are verified as used within the file, which improves code clarity and follows best practices.
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_css_css_js.js (1)
1-204: Vendor bundle looks correct.This is an auto-generated webpack bundle containing the standard Monaco Editor CSS language definition (v0.34.1). The module correctly exports
confandlanguagefor CSS syntax highlighting support.modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_xml_xml_js.js (1)
1-127: Vendor bundle looks correct.Standard Monaco Editor XML language definition bundle with proper tokenizer states and editor configuration.
modules/backend/ServiceProvider.php (3)
94-94: Ace editor bundle retained for backward compatibility.Adding the
ace-codeeditorbundle aligns with the PR description stating that Ace is being retained for RichEditor and MarkdownEditor while Monaco is introduced for the primary code editor.
114-117: Package registration follows established naming convention.The file exists at the specified path, and the registration pattern using
PackageManager::instance()->registerCallbackis consistent with other callback registrations in this file (MailManager, CombineAssets, BackendMenu, BackendAuth, and SettingsManager).
56-57: Asset bundle registration in boot() method is correct.
registerAssetBundles()is appropriately placed in theboot()method where all asset bundle callbacks are registered. This is consistent with the pattern in the cms and system modules and aligns with Laravel's service provider lifecycle, whereboot()executes after all services are registered.modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_yaml_yaml_js.js (1)
1-216: Vendor bundle looks correct.Standard Monaco Editor YAML language definition with comprehensive tokenization support for YAML-specific constructs including anchors, tags, and flow collections.
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_markdown_markdown_js.js (1)
1-222: Vendor bundle looks correct.Standard Monaco Editor Markdown language definition with support for tables, fenced code blocks, and embedded HTML/CSS/JavaScript content.
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_html_html_js.js (1)
1-314: Vendor bundle looks correct.Standard Monaco Editor HTML language definition with comprehensive support for embedded script/style content, proper handling of empty elements, and type-aware language embedding.
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_javascript_javascript_js.js (1)
1-449: Vendor bundle looks correct.Standard Monaco Editor JavaScript/TypeScript language definitions. The JavaScript module appropriately extends the TypeScript configuration while maintaining its own keyword list without TypeScript-specific keywords.
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/node_modules_monaco-editor_esm_vs_basic-languages_typescript_typescript_js.js (1)
1-359: Vendor bundle - LGTM.This is an auto-generated webpack bundle for Monaco Editor's TypeScript language support (v0.34.1). The static analysis warnings about "variable used before declaration" are false positives caused by webpack's bundling patterns and the module re-export mechanism on line 39. These patterns are valid at runtime.
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/133.js (1)
1-2: Minified vendor bundle - LGTM.This is a minified Monaco Editor HTML language service integration bundle. The static analysis warnings on line 7 are false positives caused by webpack's minification and module bundling patterns. The code correctly implements WorkerManager with idle timeout handling and comprehensive language service adapters.
modules/backend/formwidgets/CodeEditor.php (2)
250-270: Preference migration logic handles backwards compatibility well.The fallback logic
$preferences->editor_enable_folding ?? ($preferences->editor_code_folding !== 'manual')gracefully handles migration from the old string-basededitor_code_foldingpreference to the new booleaneditor_enable_folding.The new preference mappings (
showMinimap,bracketColors,showColors) follow the established pattern.
240-244: Asset bundle path updated correctly.The change from
js/build-min.jstojs/build/codeeditor.bundle.jsaligns with the Monaco Editor integration. Bundle file exists at the expected path, along with associated chunk files and CSS assets.modules/backend/assets/vendor/ace-codeeditor/codeeditor.js (2)
446-448: Data control attribute correctly differentiated.The initialization now uses
data-control="ace-codeeditor"which properly distinguishes this ACE-based editor from the new Monaco-baseddata-control="codeeditor". This allows both editors to coexist during the transition period.
453-466: Emmet twig syntax fix retained.The Emmet extension fix that normalizes
twigsyntax tohtmlis preserved, ensuring backwards compatibility with existing Twig template editing workflows.modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/39.js (1)
1-7: Minified vendor bundle - LGTM.This is a minified Monaco Editor JSON language service bundle. The static analysis warnings (switch fallthrough, switch declarations, variables used before declaration) are false positives caused by:
- The minified JSON tokenizer implementation which legitimately uses switch fallthroughs for lexer state transitions
- Webpack's module bundling patterns
These patterns are intentional and valid in the Monaco Editor source.
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/257.js (1)
1-7: Minified vendor bundle - LGTM.This is a minified Monaco Editor CSS language service bundle. It correctly creates a web worker for CSS language features and exposes the standard set of language adapters. The static analysis warnings about variables used before declaration are false positives from webpack bundling patterns.
modules/backend/formwidgets/codeeditor/assets/js/build/codeeditor.bundle/851.js (1)
1-7: TypeScript/JavaScript language service bundle - LGTM.This minified bundle provides comprehensive TypeScript and JavaScript language support for Monaco, including:
- Definition and reference navigation via
LibFileshandling- InlayHints support for parameter and type hints
- Code actions and formatting
- Diagnostics with support for
onlyVisiblemodeThe bundle correctly manages TypeScript library files (
lib.d.ts,lib.es*.d.ts, etc.) and handles the worker lifecycle with extra libs synchronization.modules/backend/formwidgets/codeeditor/assets/js/codeeditor.js (7)
61-99: LGTM!The constructor is well-structured with proper initialization of all state variables, event callbacks, and observer setup. The defensive approach of checking for
statusBarbefore accessing its child elements is good practice.
220-236: LGTM!Good use of
IntersectionObserverfor lazy loading and memory management. The editor is properly disposed when out of view and recreated when visible.
241-263: LGTM!Good approach to force a fixed height to prevent Monaco's resize issues. The jQuery backward compatibility for the Builder plugin is a thoughtful touch.
583-624: LGTM!The
wrap()andunwrap()methods correctly handle the empty selection case and use Monaco'spushEditOperationsfor atomic edits.
768-810: LGTM!Good caching strategy for themes. The silent fallback on error is acceptable since theme loading failure is non-critical and the default theme will remain active.
1291-1297: LGTM!Good memory management by disposing the editor when the tab/window is hidden. Works in conjunction with the IntersectionObserver for comprehensive visibility handling.
1308-1340: LGTM!Clever use of
constrained-editor-pluginto hide preamble content while maintaining correct line numbering. The custom line numbering function correctly adjusts displayed line numbers.
| }) | ||
|
|
||
| }) | ||
| "use strict";(self.webpackChunk_wintercms_wn_backend_module=self.webpackChunk_wintercms_wn_backend_module||[]).push([[429],{449:function(e,t,i){var n=i(171);(e=>{class t extends e.Singleton{construct(){this.widget=null}listens(){return{"backend.widget.initialized":"onWidgetInitialized"}}onWidgetInitialized(e,t){e===document.getElementById("CodeEditor-formEditorPreview-_editor_preview")&&(this.widget=t,this.enablePreferences())}enablePreferences(){(0,n.M)("change");Object.entries({show_gutter:"showGutter",highlight_active_line:"highlightActiveLine",use_hard_tabs:"!useSoftTabs",display_indent_guides:"displayIndentGuides",show_invisibles:"showInvisibles",show_print_margin:"showPrintMargin",show_minimap:"showMinimap",enable_folding:"codeFolding",bracket_colors:"bracketColors",show_colors:"showColors"}).forEach(([e,t])=>{this.element(e).addEventListener("change",e=>{this.widget.setConfig(t.replace(/^!/,""),/^!/.test(t)?!e.target.checked:e.target.checked)})}),this.element("theme").addEventListener("$change",e=>{this.widget.loadTheme(e.target.value)}),this.element("font_size").addEventListener("$change",e=>{this.widget.setConfig("fontSize",e.target.value)}),this.element("tab_size").addEventListener("$change",e=>{this.widget.setConfig("tabSize",e.target.value)}),this.element("word_wrap").addEventListener("$change",e=>{const{value:t}=e.target;switch(t){case"off":this.widget.setConfig("wordWrap",!1);break;case"fluid":this.widget.setConfig("wordWrap","fluid");break;default:this.widget.setConfig("wordWrap",parseInt(t,10))}}),document.querySelectorAll("[data-switch-lang]").forEach(e=>{e.addEventListener("click",t=>{t.preventDefault();const i=e.dataset.switchLang,n=document.querySelector(`[data-lang-snippet="${i}"]`);n&&(this.widget.setValue(n.textContent.trim()),this.widget.setLanguage(i))})}),this.widget.events.once("create",()=>{const e=new MouseEvent("click");document.querySelector('[data-switch-lang="css"]').dispatchEvent(e)})}element(e){return document.getElementById(`Form-field-Preference-editor_${e}`)}}e.addPlugin("backend.preferences",t)})(window.Snowboard)}},function(e){e.O(0,[810],function(){return t=449,e(e.s=t);var t});e.O()}]); No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if there are source files that generate this bundle and verify build configuration
# Look for webpack config files
echo "=== Webpack Config Files ==="
fd -t f 'webpack\.config\.(js|ts|mjs|cjs)'
# Check for build scripts in package.json
echo -e "\n=== Build Scripts ==="
fd -t f 'package\.json' --max-depth 3 --exec jq -r '.scripts // {} | select(length > 0) | to_entries[] | select(.key | test("build|bundle|compile|watch")) | "\(.key): \(.value)"' {} \;
# Look for source files in the same directory
echo -e "\n=== Files in modules/backend/assets/js/preferences/ ==="
ls -la modules/backend/assets/js/preferences/ 2>/dev/null || echo "Directory not found"
# Look for .gitignore entries related to build output
echo -e "\n=== .gitignore entries for build output ==="
rg -n 'dist|build|bundle|/assets/' .gitignore 2>/dev/null | head -20
# Check if there's a source version of this file
echo -e "\n=== Looking for source versions ==="
fd -t f 'preferences' modules/backend/assets -E 'node_modules'
# Check the git history to see if this file was ever different
echo -e "\n=== Git info on the file ==="
git log --oneline -5 -- modules/backend/assets/js/preferences/preferences.js 2>/dev/null || echo "No git history available"Repository: wintercms/winter
Length of output: 146
🏁 Script executed:
#!/bin/bash
# Simpler check for webpack config and build setup
# Look for webpack config files (faster)
echo "=== Webpack Config Files ==="
find . -maxdepth 3 -name "webpack.config.*" -type f 2>/dev/null | head -10
# Look for package.json and extract build scripts
echo -e "\n=== Build Scripts in package.json ==="
find . -maxdepth 3 -name "package.json" -type f 2>/dev/null | head -5 | while read pf; do
echo "File: $pf"
jq '.scripts | to_entries[] | select(.key | test("build|bundle|compile")) | "\(.key): \(.value)"' "$pf" 2>/dev/null
done
# Check .gitignore
echo -e "\n=== .gitignore content (first 50 lines) ==="
head -50 .gitignore 2>/dev/null || echo ".gitignore not found"
# Check directory structure of the assets folder
echo -e "\n=== Files in modules/backend/assets/js/preferences/ ==="
find modules/backend/assets/js/preferences/ -type f 2>/dev/null | head -20
# Look for any source files nearby
echo -e "\n=== Nearby source JavaScript files ==="
find modules/backend/assets/js/ -name "*.js" -type f 2>/dev/null | head -20Repository: wintercms/winter
Length of output: 1863
🏁 Script executed:
#!/bin/bash
# Check actual build scripts and look for source files
echo "=== ./modules/backend/package.json ==="
cat ./modules/backend/package.json
echo -e "\n=== Looking for src or source directories ==="
find modules/backend -maxdepth 3 -type d \( -name "src" -o -name "source" -o -name "ts" \) 2>/dev/null
echo -e "\n=== Looking for TypeScript files ==="
find modules/backend -name "*.ts" -o -name "*.tsx" 2>/dev/null | head -10
echo -e "\n=== Check if preferences file is truly the only one in that dir ==="
stat modules/backend/assets/js/preferences/preferences.js 2>/dev/null | grep -E "File|Access|Modify|Change"
echo -e "\n=== Look for any .js source (non-minified) in assets ==="
find modules/backend/assets/js -name "*.js" ! -name "*.min.js" -type f 2>/dev/null | head -20Repository: wintercms/winter
Length of output: 2550
🏁 Script executed:
#!/bin/bash
# Look for laravel-mix config and any preferences source files
echo "=== Looking for webpack.mix.js or laravel-mix config ==="
find . -maxdepth 3 -name "webpack.mix.js" -o -name "mix.js" 2>/dev/null
echo -e "\n=== Looking for ANY source files with 'preferences' in the name ==="
find . -type f \( -name "*preferences*" -o -name "*preference*" \) ! -path "*/node_modules/*" 2>/dev/null
echo -e "\n=== Check root directory for build config ==="
ls -la webpack.* laravel-* mix.* 2>/dev/null || echo "No webpack/mix files in root"
echo -e "\n=== Check modules/backend root for build config ==="
ls -la modules/backend/webpack.* modules/backend/laravel-* modules/backend/mix.* 2>/dev/null || echo "No webpack/mix files in modules/backend"
echo -e "\n=== Looking for vue or .js source files that might compile to preferences.js ==="
find modules/backend -type f \( -name "*.vue" \) ! -path "*/node_modules/*" 2>/dev/null | head -20Repository: wintercms/winter
Length of output: 570
🏁 Script executed:
#!/bin/bash
# Check recent file modifications to understand context
echo "=== Check when preferences.js was last modified ==="
stat modules/backend/assets/js/preferences/preferences.js 2>/dev/null | grep -E "Modify|Access|File"
echo -e "\n=== Look at the file size ==="
wc -c < modules/backend/assets/js/preferences/preferences.js
echo -e "\n=== Check for any build scripts in package.json ==="
jq '.scripts' ./modules/backend/package.json
echo -e "\n=== Check root package.json for build scripts ==="
jq '.scripts' ./package.json 2>/dev/null | head -30
echo -e "\n=== Check if there's a resources or src directory at repo root ==="
find . -maxdepth 2 -type d \( -name "resources" -o -name "src" \) ! -path "*/node_modules/*" 2>/dev/nullRepository: wintercms/winter
Length of output: 329
Minified webpack bundle without source files must be removed from source control.
This is a webpack-generated bundle (self.webpackChunk_wintercms_wn_backend_module), but critically, no source file exists anywhere in the repository. The package.json includes laravel-mix as a devDependency but defines no build scripts and no webpack configuration file is present.
Committing minified build artifacts to source control causes several problems:
- Impossible to review: Minified code cannot be meaningfully reviewed for correctness or security.
- Unmaintainable: Changes must be made in missing source files; this committed artifact is redundant.
- Merge conflicts: Minified files frequently create difficult-to-resolve conflicts.
- No build process: Without build configuration, this file cannot be regenerated.
Required actions:
- Locate or reconstruct the original source file for this module.
- Set up the webpack/laravel-mix build configuration.
- Remove
modules/backend/assets/js/preferences/preferences.jsfrom source control and add build output to.gitignore. - Ensure the build process generates this file during CI/CD or deployment.
🧰 Tools
🪛 Biome (2.1.2)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
| 'yaml_emit_file|yaml_parse|yaml_parse_file|yaml_parse_url|yaz_addinfo|yaz_ccl_conf|yaz_ccl_parse|yaz_close|yaz_connect|yaz_database|'+'yaz_element|yaz_errno|yaz_error|yaz_es|yaz_es_result|yaz_get_option|yaz_hits|yaz_itemorder|yaz_present|yaz_range|yaz_record|yaz_scan|'+'yaz_scan_result|yaz_schema|yaz_search|yaz_set_option|yaz_sort|yaz_syntax|yaz_wait|yp_all|yp_cat|yp_err_string|yp_errno|yp_first|'+'yp_get_default_domain|yp_master|yp_match|yp_next|yp_order|zend_logo_guid|zend_thread_id|zend_version|zip_close|zip_entry_close|'+'zip_entry_compressedsize|zip_entry_compressionmethod|zip_entry_filesize|zip_entry_name|zip_entry_open|zip_entry_read|zip_open|zip_read|'+'ziparchive|ziparchive_addemptydir|ziparchive_addfile|ziparchive_addfromstring|ziparchive_close|ziparchive_deleteindex|'+'ziparchive_deletename|ziparchive_extractto|ziparchive_getarchivecomment|ziparchive_getcommentindex|ziparchive_getcommentname|'+ | ||
| 'ziparchive_getfromindex|ziparchive_getfromname|ziparchive_getnameindex|ziparchive_getstatusstring|ziparchive_getstream|'+'ziparchive_locatename|ziparchive_open|ziparchive_renameindex|ziparchive_renamename|ziparchive_setCommentName|ziparchive_setarchivecomment|'+'ziparchive_setcommentindex|ziparchive_statindex|ziparchive_statname|ziparchive_unchangeall|ziparchive_unchangearchive|'+'ziparchive_unchangeindex|ziparchive_unchangename|zlib_get_coding_type').split('|'));var keywords=lang.arrayToMap(('abstract|and|array|as|break|case|catch|class|clone|const|continue|declare|default|do|else|elseif|enddeclare|endfor|endforeach|endif|'+'endswitch|endwhile|extends|final|for|foreach|function|global|goto|if|implements|interface|instanceof|namespace|new|or|private|protected|'+'public|static|switch|throw|trait|try|use|var|while|xor').split('|'));var languageConstructs=lang.arrayToMap(('die|echo|empty|exit|eval|include|include_once|isset|list|require|require_once|return|print|unset').split('|'));var builtinConstants=lang.arrayToMap( | ||
| ('true|TRUE|false|FALSE|null|NULL|__CLASS__|__DIR__|../vendor/ace/mode-php.js|__LINE__|__METHOD__|__FUNCTION__|__NAMESPACE__').split('|'));var builtinVariables=lang.arrayToMap(('$GLOBALS|$_SERVER|$_GET|$_POST|$_FILES|$_REQUEST|$_SESSION|$_ENV|$_COOKIE|$php_errormsg|$HTTP_RAW_POST_DATA|'+'$http_response_header|$argc|$argv').split('|'));var builtinFunctionsDeprecated=lang.arrayToMap(('key_exists|cairo_matrix_create_scale|cairo_matrix_create_translate|call_user_method|call_user_method_array|com_addref|com_get|'+'com_invoke|com_isenum|com_load|com_release|com_set|connection_timeout|cubrid_load_from_glo|cubrid_new_glo|cubrid_save_to_glo|'+'cubrid_send_glo|define_syslog_variables|dl|ereg|ereg_replace|eregi|eregi_replace|hw_documentattributes|hw_documentbodytag|'+'hw_documentsize|hw_outputdocument|imagedashedline|maxdb_bind_param|maxdb_bind_result|maxdb_client_encoding|maxdb_close_long_data|'+ | ||
| ('true|TRUE|false|FALSE|null|NULL|__CLASS__|__DIR__|../ace/mode-php.js|__LINE__|__METHOD__|__FUNCTION__|__NAMESPACE__').split('|'));var builtinVariables=lang.arrayToMap(('$GLOBALS|$_SERVER|$_GET|$_POST|$_FILES|$_REQUEST|$_SESSION|$_ENV|$_COOKIE|$php_errormsg|$HTTP_RAW_POST_DATA|'+'$http_response_header|$argc|$argv').split('|'));var builtinFunctionsDeprecated=lang.arrayToMap(('key_exists|cairo_matrix_create_scale|cairo_matrix_create_translate|call_user_method|call_user_method_array|com_addref|com_get|'+'com_invoke|com_isenum|com_load|com_release|com_set|connection_timeout|cubrid_load_from_glo|cubrid_new_glo|cubrid_save_to_glo|'+'cubrid_send_glo|define_syslog_variables|dl|ereg|ereg_replace|eregi|eregi_replace|hw_documentattributes|hw_documentbodytag|'+'hw_documentsize|hw_outputdocument|imagedashedline|maxdb_bind_param|maxdb_bind_result|maxdb_client_encoding|maxdb_close_long_data|'+ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical: File path incorrectly placed in PHP builtinConstants array.
The string ../ace/mode-php.js appears in the builtinConstants array, which should only contain PHP magic constants like __CLASS__, __DIR__, __FILE__, etc. This looks like the __FILE__ constant was accidentally replaced during a find-replace operation when updating asset paths.
This will break syntax highlighting and code intelligence for the __FILE__ magic constant in PHP code.
🔎 Proposed fix
-('true|TRUE|false|FALSE|null|NULL|__CLASS__|__DIR__|../ace/mode-php.js|__LINE__|__METHOD__|__FUNCTION__|__NAMESPACE__').split('|'));
+('true|TRUE|false|FALSE|null|NULL|__CLASS__|__DIR__|__FILE__|__LINE__|__METHOD__|__FUNCTION__|__NAMESPACE__').split('|'));📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ('true|TRUE|false|FALSE|null|NULL|__CLASS__|__DIR__|../ace/mode-php.js|__LINE__|__METHOD__|__FUNCTION__|__NAMESPACE__').split('|'));var builtinVariables=lang.arrayToMap(('$GLOBALS|$_SERVER|$_GET|$_POST|$_FILES|$_REQUEST|$_SESSION|$_ENV|$_COOKIE|$php_errormsg|$HTTP_RAW_POST_DATA|'+'$http_response_header|$argc|$argv').split('|'));var builtinFunctionsDeprecated=lang.arrayToMap(('key_exists|cairo_matrix_create_scale|cairo_matrix_create_translate|call_user_method|call_user_method_array|com_addref|com_get|'+'com_invoke|com_isenum|com_load|com_release|com_set|connection_timeout|cubrid_load_from_glo|cubrid_new_glo|cubrid_save_to_glo|'+'cubrid_send_glo|define_syslog_variables|dl|ereg|ereg_replace|eregi|eregi_replace|hw_documentattributes|hw_documentbodytag|'+'hw_documentsize|hw_outputdocument|imagedashedline|maxdb_bind_param|maxdb_bind_result|maxdb_client_encoding|maxdb_close_long_data|'+ | |
| ('true|TRUE|false|FALSE|null|NULL|__CLASS__|__DIR__|__FILE__|__LINE__|__METHOD__|__FUNCTION__|__NAMESPACE__').split('|'));var builtinVariables=lang.arrayToMap(('$GLOBALS|$_SERVER|$_GET|$_POST|$_FILES|$_REQUEST|$_SESSION|$_ENV|$_COOKIE|$php_errormsg|$HTTP_RAW_POST_DATA|'+'$http_response_header|$argc|$argv').split('|'));var builtinFunctionsDeprecated=lang.arrayToMap(('key_exists|cairo_matrix_create_scale|cairo_matrix_create_translate|call_user_method|call_user_method_array|com_addref|com_get|'+'com_invoke|com_isenum|com_load|com_release|com_set|connection_timeout|cubrid_load_from_glo|cubrid_new_glo|cubrid_save_to_glo|'+'cubrid_send_glo|define_syslog_variables|dl|ereg|ereg_replace|eregi|eregi_replace|hw_documentattributes|hw_documentbodytag|'+'hw_documentsize|hw_outputdocument|imagedashedline|maxdb_bind_param|maxdb_bind_result|maxdb_client_encoding|maxdb_close_long_data|'+ |
🤖 Prompt for AI Agents
In modules/backend/assets/vendor/ace-codeeditor/build-min.js around line 1442,
the builtinConstants array contains an incorrect token "../ace/mode-php.js"
instead of the PHP magic constant "__FILE__"; remove the erroneous path entry
and restore the correct "__FILE__" token in the array so only PHP magic
constants remain (ensure formatting/quoting matches surrounding entries and
update any adjacent concatenation so the split('|') still produces the correct
list).
| $(document).render(function(){$('[data-control="ace-codeeditor"]').codeEditor()});+function(exports){if(exports.ace&&typeof exports.ace.require=='function'){var emmetExt=exports.ace.require('ace/ext/emmet') | ||
| if(emmetExt&&emmetExt.AceEmmetEditor&&emmetExt.AceEmmetEditor.prototype.getSyntax){var coreGetSyntax=emmetExt.AceEmmetEditor.prototype.getSyntax | ||
| emmetExt.AceEmmetEditor.prototype.getSyntax=function(){var $syntax=$.proxy(coreGetSyntax,this)() | ||
| return $syntax=='twig'?'html':$syntax};}}}(window)}(window.jQuery); No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# Search for data-control attributes related to code editors across the codebase
rg -n 'data-control\s*=\s*["\'].*codeeditor' --type-list | grep -E '\.(php|js|html|vue)' -q && echo "Has codeeditor references" || true
rg -n 'data-control\s*=\s*["\'].*codeeditor' -C 2
# Also search for Monaco references to understand migration context
rg -n 'monaco|Monaco' --type-list | head -20Repository: wintercms/winter
Length of output: 282
🏁 Script executed:
# Search for references to the old 'codeeditor' data attribute without ace prefix
rg -n 'data-control=["\']codeeditor["\']' -C 2
# Search for 'ace-codeeditor' references to confirm new selector usage
rg -n 'ace-codeeditor' -C 1Repository: wintercms/winter
Length of output: 128
🏁 Script executed:
# Check for JavaScript initialization code that may reference these selectors
rg -n '\$.*codeeditor|\$.*ace-codeeditor|codeEditor\(\)' --type=js -C 3 | head -100Repository: wintercms/winter
Length of output: 50372
🏁 Script executed:
# Search for old 'codeeditor' selector in data-control attributes specifically (case-insensitive)
rg 'data-control\s*=\s*["\']codeeditor["\']' -i
# Search for all data-control selectors to see what's registered
rg 'data-control\s*=\s*["\']' | grep -E '(ace-|monaco|codeeditor)' | head -20Repository: wintercms/winter
Length of output: 224
🏁 Script executed:
# Check if there are any form widget definitions that might reference old selectors
fd -e php -e js | xargs rg -l 'codeeditor|code-editor' | head -20Repository: wintercms/winter
Length of output: 989
🏁 Script executed:
# Simple search for old selector pattern (without ace- prefix)
rg 'data-control.*codeeditor' --no-config | grep -v 'ace-codeeditor'
# Also check the form widget class definition
cat modules/backend/formwidgets/CodeEditor.php | head -50Repository: wintercms/winter
Length of output: 1965
🏁 Script executed:
# Check the partial template file to see what selector is used
cat modules/backend/formwidgets/codeeditor/partials/_codeeditor.phpRepository: wintercms/winter
Length of output: 2288
🏁 Script executed:
# Verify the Emmet integration code in the source file
sed -n '444,455p' modules/backend/assets/vendor/ace-codeeditor/codeeditor.jsRepository: wintercms/winter
Length of output: 459
Selector mismatch breaks the Ace code editor initialization.
The vendored Ace code attempts to initialize elements with data-control="ace-codeeditor" (lines 2311-2314), but the form widget template at modules/backend/formwidgets/codeeditor/partials/_codeeditor.php still renders data-control="codeeditor". This mismatch prevents the initialization from working. Additionally, other parts of the codebase still reference the old [data-control="codeeditor"] selector (e.g., modules/cms/assets/js/winter.cmspage.js, modules/system/assets/ui/js/drag.value.js), creating potential breakage across multiple features.
The form widget template must be updated to use data-control="ace-codeeditor", and any dependent selectors in related modules must be updated accordingly.
| /** | ||
| * Loads a theme via AJAX. | ||
| * Supports both tmTheme (XML) and JSON formats. | ||
| */ | ||
| public function onLoadTheme() | ||
| { | ||
| $theme = post('theme'); | ||
|
|
||
| if (empty($theme)) { | ||
| throw new ApplicationException('No theme specified'); | ||
| } | ||
| if (!preg_match('/^[a-z\-\_]+$/i', $theme)) { | ||
| throw new ApplicationException('Invalid theme name'); | ||
| } | ||
|
|
||
| $themeDir = __DIR__ . '/codeeditor/assets/themes/'; | ||
|
|
||
| // Try JSON format first (modern), then fall back to tmTheme (legacy) | ||
| $jsonPath = $themeDir . $theme . '.json'; | ||
| $tmThemePath = $themeDir . $theme . '.tmTheme'; | ||
|
|
||
| if (File::exists($jsonPath)) { | ||
| return [ | ||
| 'format' => 'json', | ||
| 'data' => File::get($jsonPath), | ||
| ]; | ||
| } elseif (File::exists($tmThemePath)) { | ||
| return [ | ||
| 'format' => 'tmTheme', | ||
| 'data' => File::get($tmThemePath), | ||
| ]; | ||
| } | ||
|
|
||
| throw new ApplicationException(sprintf('Theme "%s" not found', $theme)); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
find modules/backend/formwidgets/codeeditor/assets/themes/ -type f \( -name "*.json" -o -name "*.tmTheme" \) 2>/dev/null | sortRepository: wintercms/winter
Length of output: 2650
Theme loading needs case-normalization to work reliably on case-sensitive filesystems.
The onLoadTheme() method validates input appropriately and constructs paths safely, but has a case-sensitivity issue: the regex /^[a-z\-\_]+$/i (with the i flag) accepts mixed-case input like "Monokai" or "THEMES", but all theme files in the directory are lowercase (e.g., monokai.tmTheme, one-dark-pro.json, kr_theme.tmTheme).
On case-sensitive filesystems (Linux), theme loading fails if users provide mixed-case input. On case-insensitive filesystems (Windows/macOS), it works by accident.
Fix: Convert the theme name to lowercase before path construction:
$theme = strtolower(post('theme'));This ensures consistent behavior across all filesystems.
🤖 Prompt for AI Agents
In modules/backend/formwidgets/CodeEditor.php around lines 201 to 235, the
onLoadTheme() handler accepts mixed-case theme names (regex uses /i) but theme
files are lowercase, causing failures on case-sensitive filesystems; normalize
the input by lowercasing the posted theme before validation/path construction
(e.g., call strtolower on post('theme')) and then proceed with the existing
validation and File::exists checks so paths match actual filenames.
| findAll(search, matchCase) { | ||
| const searchString = (search instanceof RegExp) ? search.source : search; | ||
| const matches = this.model.findMatches(searchString, true, (search instanceof RegExp), matchCase || false, null, true, 1); | ||
|
|
||
| // CODEEDITOR NO CONFLICT | ||
| // ================= | ||
| return matches; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
findAll() only returns one match due to limit parameter.
The findMatches() call has limitResultCount set to 1, which contradicts the method's purpose of finding all matches.
🔎 Proposed fix
findAll(search, matchCase) {
const searchString = (search instanceof RegExp) ? search.source : search;
- const matches = this.model.findMatches(searchString, true, (search instanceof RegExp), matchCase || false, null, true, 1);
+ const matches = this.model.findMatches(searchString, true, (search instanceof RegExp), matchCase || false, null, true);
return matches;
}Note: Omitting the last parameter removes the limit, returning all matches.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| findAll(search, matchCase) { | |
| const searchString = (search instanceof RegExp) ? search.source : search; | |
| const matches = this.model.findMatches(searchString, true, (search instanceof RegExp), matchCase || false, null, true, 1); | |
| // CODEEDITOR NO CONFLICT | |
| // ================= | |
| return matches; | |
| } | |
| findAll(search, matchCase) { | |
| const searchString = (search instanceof RegExp) ? search.source : search; | |
| const matches = this.model.findMatches(searchString, true, (search instanceof RegExp), matchCase || false, null, true); | |
| return matches; | |
| } |
🤖 Prompt for AI Agents
In modules/backend/formwidgets/codeeditor/assets/js/codeeditor.js around lines
644 to 649, the call to this.model.findMatches sets the last parameter
limitResultCount to 1, causing findAll() to return only one match; remove the
final numeric argument (i.e., omit the limitResultCount parameter) so
findMatches is called without a limit and returns all matches.
| return this.model.pushEditOperations( | ||
| this.editor.getSelections(), | ||
| [ | ||
| { | ||
| forceMoveMarkers: false, | ||
| range: new monaco.Range(found.range.startLineNumber, found.range.startColumn, found.range.endLineNumber, found.range.endColumn), | ||
| text: (align) ? this.alignText(replace, search.startColumn) : replace, | ||
| }, | ||
| ], | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incorrect property access for alignment when search is String/RegExp.
On line 685, search.startColumn is used for alignment, but when search is a String or RegExp (not a Range), this property is undefined, causing the alignment to fail silently.
🔎 Proposed fix
return this.model.pushEditOperations(
this.editor.getSelections(),
[
{
forceMoveMarkers: false,
range: new monaco.Range(found.range.startLineNumber, found.range.startColumn, found.range.endLineNumber, found.range.endColumn),
- text: (align) ? this.alignText(replace, search.startColumn) : replace,
+ text: (align) ? this.alignText(replace, found.range.startColumn) : replace,
},
],
);🤖 Prompt for AI Agents
In modules/backend/formwidgets/codeeditor/assets/js/codeeditor.js around lines
679 to 689, the code uses search.startColumn for alignment which is undefined
when search is a String or RegExp; replace that usage with the actual matched
range column (e.g., found.range.startColumn) so alignment always gets a valid
column value; update the align call to pass found.range.startColumn (or
otherwise guard by checking for a Range and fallback to found.range.startColumn)
instead of search.startColumn.
| enableStatusBarActions() { | ||
| if (!this.statusBar) { | ||
| return; | ||
| } | ||
|
|
||
| const fullscreen = this.statusBar.querySelector('[data-full-screen]'); | ||
| fullscreen.addEventListener('click', () => { | ||
| if (!this.fullscreen) { | ||
| this.element.requestFullscreen({ | ||
| navigationUI: 'hide', | ||
| }).then(() => { | ||
| this.fullscreen = true; | ||
| fullscreen.classList.add('active'); | ||
| this.element.addEventListener('fullscreenchange', this.callbacks.fullScreenChange); | ||
| // Use Monaco's layout() instead of refresh() to avoid disposing the editor | ||
| if (this.editor) { | ||
| window.requestAnimationFrame(() => { | ||
| this.editor.layout(); | ||
| }); | ||
| } | ||
| }); | ||
| } else { | ||
| document.exitFullscreen(); | ||
| } | ||
| }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Click listener on fullscreen button accumulates on editor recreation.
enableStatusBarActions() is called every time createEditor() runs (on visibility changes), but there's no cleanup of the previous click listener on the fullscreen button. This causes multiple listeners to accumulate.
🔎 Proposed fix
Track and clean up the fullscreen listener:
+ // In construct(), add:
+ this.fullscreenClickHandler = null;
enableStatusBarActions() {
if (!this.statusBar) {
return;
}
const fullscreen = this.statusBar.querySelector('[data-full-screen]');
+
+ // Remove previous listener if exists
+ if (this.fullscreenClickHandler) {
+ fullscreen.removeEventListener('click', this.fullscreenClickHandler);
+ }
+
+ this.fullscreenClickHandler = () => {
- fullscreen.addEventListener('click', () => {
if (!this.fullscreen) {
// ... existing code
} else {
document.exitFullscreen();
}
- });
+ };
+
+ fullscreen.addEventListener('click', this.fullscreenClickHandler);
}| normalizeKeyBinding(keyCode) { | ||
| let keyBinding = { | ||
| key: null, | ||
| ctrl: false, | ||
| alt: false, | ||
| shift: false, | ||
| }; | ||
|
|
||
| if (typeof keyCode === 'string') { | ||
| if (keyCode.startsWith('Shift+Ctrl+')) { | ||
| keyBinding.key = keyCode.replace('Shift+Ctrl+', ''); | ||
| keyBinding.shift = true; | ||
| keyBinding.ctrl = true; | ||
| } else if (keyCode.startsWith('Shift+Alt+')) { | ||
| keyBinding.key = keyCode.replace('Shift+Alt+', ''); | ||
| keyBinding.shift = true; | ||
| keyBinding.alt = true; | ||
| } else if (keyCode.startsWith('Ctrl+')) { | ||
| keyBinding.key = keyCode.replace('Ctrl+', ''); | ||
| keyBinding.ctrl = true; | ||
| } else if (keyCode.startsWith('Alt+')) { | ||
| keyBinding.key = keyCode.replace('Alt+', ''); | ||
| keyBinding.alt = true; | ||
| } | ||
| } else { | ||
| keyBinding = { ...keyBinding, ...keyCode }; | ||
| } | ||
|
|
||
| return keyBinding; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incomplete keybinding parsing for some combinations.
The parser doesn't handle:
- Plain keys without modifiers (e.g.,
"Escape") —keyremainsnull Shift+alone without Ctrl/AltCtrl+Alt+combinations- Alternative orderings like
Ctrl+Shift+
🔎 Proposed fix
normalizeKeyBinding(keyCode) {
let keyBinding = {
key: null,
ctrl: false,
alt: false,
shift: false,
};
if (typeof keyCode === 'string') {
- if (keyCode.startsWith('Shift+Ctrl+')) {
- keyBinding.key = keyCode.replace('Shift+Ctrl+', '');
- keyBinding.shift = true;
- keyBinding.ctrl = true;
- } else if (keyCode.startsWith('Shift+Alt+')) {
- keyBinding.key = keyCode.replace('Shift+Alt+', '');
- keyBinding.shift = true;
- keyBinding.alt = true;
- } else if (keyCode.startsWith('Ctrl+')) {
- keyBinding.key = keyCode.replace('Ctrl+', '');
- keyBinding.ctrl = true;
- } else if (keyCode.startsWith('Alt+')) {
- keyBinding.key = keyCode.replace('Alt+', '');
- keyBinding.alt = true;
- }
+ const parts = keyCode.split('+');
+ keyBinding.key = parts.pop(); // Last part is the key
+ parts.forEach((mod) => {
+ const modifier = mod.toLowerCase();
+ if (modifier === 'ctrl' || modifier === 'cmd') keyBinding.ctrl = true;
+ else if (modifier === 'alt') keyBinding.alt = true;
+ else if (modifier === 'shift') keyBinding.shift = true;
+ });
} else {
keyBinding = { ...keyBinding, ...keyCode };
}
return keyBinding;
}🤖 Prompt for AI Agents
In modules/backend/formwidgets/codeeditor/assets/js/codeeditor.js around lines
1419 to 1448, the normalizeKeyBinding function fails to parse many valid string
keybindings (plain keys like "Escape", single "Shift+Key", "Ctrl+Alt+Key", and
modifier permutations like "Ctrl+Shift+Key"), so replace the current startsWith
chain with a robust parser: split the input string on '+' into parts, iterate
parts to set ctrl/alt/shift flags when matching modifier names
(case-insensitive), and treat the remaining non-modifier part (if any) as the
key; ensure empty or missing key parts result in key = null and preserve
existing behavior for non-string inputs by merging the parsed result into the
default keyBinding object.
| } | ||
|
|
||
| $this->addJs('/modules/backend/formwidgets/codeeditor/assets/js/build-min.js', 'core'); | ||
| $this->addJs('/modules/backend/assets/vendor/ace-codeeditor/build-min.js', 'core'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify the ace-codeeditor asset exists at the new path
# Check if the ace-codeeditor build file exists
if [ -f "modules/backend/assets/vendor/ace-codeeditor/build-min.js" ]; then
echo "✓ Asset file exists at modules/backend/assets/vendor/ace-codeeditor/build-min.js"
ls -lh "modules/backend/assets/vendor/ace-codeeditor/build-min.js"
else
echo "✗ Asset file NOT found at modules/backend/assets/vendor/ace-codeeditor/build-min.js"
echo "Searching for ace-codeeditor files in the repository..."
fd -t f "build-min.js" modules/backend/assets/vendor/
fi
# Check if there are any open issues or TODOs tracking the migration of RichEditor to Monaco
echo ""
echo "Checking for TODOs or FIXMEs related to RichEditor and Monaco migration..."
rg -i "TODO|FIXME" modules/backend/formwidgets/RichEditor.phpRepository: wintercms/winter
Length of output: 323
🏁 Script executed:
#!/bin/bash
# Search for tracking of temporary Ace retention in the codebase
echo "=== Searching for Ace/Monaco migration tracking in backend formwidgets ==="
rg -i "temporary|temp|ace.*monaco|monaco.*ace|fixme|todo" modules/backend/formwidgets/ -A 2 -B 2
echo ""
echo "=== Searching in RichEditor.php for any comments about Ace vs Monaco ==="
cat -n modules/backend/formwidgets/RichEditor.php | head -200
echo ""
echo "=== Checking commit messages or PR history for migration context ==="
rg "temporary.*ace|ace.*retained" --max-count=10 -iRepository: wintercms/winter
Length of output: 50375
🏁 Script executed:
#!/bin/bash
# Read RichEditor.php to check for comments about Ace editor
cat -n modules/backend/formwidgets/RichEditor.php | head -180
# Also search for any comments mentioning Ace, Monaco, or temporary
echo ""
echo "=== Searching for comments about Ace/Monaco in RichEditor.php ==="
rg -i "ace|monaco|editor|temporary" modules/backend/formwidgets/RichEditor.php -B 2 -A 2Repository: wintercms/winter
Length of output: 11446
🏁 Script executed:
#!/bin/bash
# Search for any migration tracking across the entire codebase
echo "=== Searching for Monaco/Ace migration references ==="
rg -i "monaco|ace.*temporary|temporary.*ace" --max-count=20
echo ""
echo "=== Checking MarkdownEditor for similar Ace loading ==="
rg -A 5 -B 5 "ace-codeeditor" modules/backend/formwidgets/MarkdownEditor.php
echo ""
echo "=== Looking for any issue/TODO tracking in commit messages or PR files ==="
rg -i "TODO|FIXME|issue" modules/backend/formwidgets/ -l | head -10Repository: wintercms/winter
Length of output: 50374
The Ace editor asset path is correct, but document that this Ace retention is temporary.
The asset file at /modules/backend/assets/vendor/ace-codeeditor/build-min.js exists and loads correctly. However, RichEditor still retains Ace instead of migrating to Monaco, with no inline documentation or tracking indicating this is a temporary measure. Add a comment in the code or create/link a follow-up issue to ensure this temporary retention doesn't become permanent technical debt.
🤖 Prompt for AI Agents
In modules/backend/formwidgets/RichEditor.php around line 157, the code adds the
Ace editor asset but lacks documentation that keeping Ace is a temporary
measure; add a clear inline comment on that line stating that Ace is retained
temporarily pending migration to Monaco, include the rationale and expected
timeline or milestone, and either add a TODO with a tracker/issue ID (or create
one and reference it) so the retention is traceable and won't become permanent
technical debt.
Fixes #431. Related: wintercms/wn-builder-plugin#73



This PR introduces the Monaco editor in replacement of the Ace Editor. At this stage for the PR, we are aiming for parity with the functionality previously provided by Ace, with the intention of increasing the functionality after this PR is merged.
Still to do:
Changes:
Summary by CodeRabbit
New Features
Style
✏️ Tip: You can customize this high-level summary in your review settings.