Conversation
why: CKEditor 5 v47 renamed several engine types to carry explicit Model/View prefixes. The old short names are no longer exported. what: - DowncastWriter -> ViewDowncastWriter (mathediting.ts) - LivePosition -> ModelLivePosition (automath.ts) - LiveRange -> ModelLiveRange (automath.ts) - Element -> ModelElement (mathediting.ts, utils.ts) - DocumentSelection -> ModelDocumentSelection (utils.ts) - icons.check / icons.cancel -> IconCheck / IconCancel (mainformview.ts; icons object removed in v47, individual named exports from @ckeditor/ckeditor5-icons used instead) - tsconfig.dist.json: add outDir and fix types path for bundler moduleResolution required by dev-build-tools v55 - typings/types/index.d.ts: add directory to satisfy typeRoots resolution under TypeScript 5.5
e9123af to
d1ee5cd
Compare
kenny-siu
left a comment
There was a problem hiding this comment.
There's the one quibble, but I don't imagine it would happen all that much.
| editor.model.document.on( 'change:data', () => { | ||
| for ( const change of editor.model.document.differ.getChanges() ) { | ||
| if ( change.type === 'insert' ) { | ||
| const item = change.position.nodeAfter; | ||
| if ( item && ( | ||
| item.is( 'element', 'mathtex-inline' ) || | ||
| item.is( 'element', 'mathtex-display' ) | ||
| ) ) { | ||
| editor.editing.reconvertItem( item ); | ||
| } | ||
| } | ||
| } | ||
| } ); |
There was a problem hiding this comment.
According to claude there's some sort of double-processing that happens here when you past something.
I am really tired right now and can't figure it out, but maybe you can 😅
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
| } | ||
| } | ||
| } | ||
| } ); |
There was a problem hiding this comment.
Reconversion on every math insert causes double-processing
Medium Severity
The change:data listener calls editor.editing.reconvertItem() for every math element insertion — not just drag-drop. This means paste, undo, and MathCommand.execute() all trigger a second full conversion cycle. reconvertItem() internally calls model.change(), which after the original cycle completes opens a new change block → destroys the just-rendered view element → re-downcasts and re-renders it. With async engines like MathJax this can cause visible flickering. CKEditor's recommended pattern is registerPostFixer with differ.refreshItem(), which processes reconversion within the same cycle. Kenny flagged this exact concern in the PR discussion.
3dff340 to
01baaf3
Compare
why: CKEditor 47 development tooling requires the newer package-tools stack and a newer TypeScript baseline than this repo was still pinned to. what: - bump @ckeditor/ckeditor5-dev-build-tools 43.0.0 -> 55.2.0 - bump @ckeditor/ckeditor5-package-tools ^2.1.0 -> ^5.1.0 - bump @ckeditor/ckeditor5-inspector >=4.1.0 -> >=5.0.0 - bump eslint-config-ckeditor5 >=7.1.0 -> 9.1.0 - bump stylelint-config-ckeditor5 >=7.1.0 -> 10.0.0 - bump typescript 5.0.4 -> ~5.5 to match CKEditor 47's supported range - keep mocha-scoped resolutions for debug/diff/minimatch to avoid ESLint 7 CJS loading breakage from ESM-only brace-expansion hoisting See also: - https://www.npmjs.com/package/@ckeditor/ckeditor5-dev-build-tools - https://www.npmjs.com/package/@ckeditor/ckeditor5-package-tools - https://www.npmjs.com/package/typescript
why: Move the package onto the CKEditor 47 line so the rest of the branch can adapt the plugin to the newer runtime and APIs. what: - update devDependencies.ckeditor5 from "latest" to "^47.6.1" - raise peerDependencies.ckeditor5 from ">=43.2.0 || ^0.0.0-nightly" to ">=47.0.0" - refresh yarn.lock to resolve ckeditor5 via the pinned 47.6.1 range See also: - https://www.npmjs.com/package/ckeditor5 - https://github.com/ckeditor/ckeditor5 - https://ckeditor.com/docs/ckeditor5/latest/updating/guides/update-to-47.html Release History (newest -> oldest): - 47.6.1 (March 11, 2026): - https://github.com/ckeditor/ckeditor5/releases/tag/v47.6.1 - 47.0.0 (October 2025): - https://ckeditor.com/docs/ckeditor5/latest/updating/guides/update-to-47.html - 46.0.0 (July 2025): - https://ckeditor.com/docs/ckeditor5/latest/updating/guides/update-to-46.html - 45.0.0 (April 2025): - https://ckeditor.com/docs/ckeditor5/latest/updating/guides/update-to-45.html - 44.0.0 (January 2025): - https://ckeditor.com/docs/ckeditor5/latest/updating/guides/update-to-44.html - 43.2.0 (November 2024): - https://github.com/ckeditor/ckeditor5/releases/tag/v43.2.0
why: CKEditor 47 tooling requires Node >=24.11.0. The branch had already moved CI to Node 24.x, but local version files and package engines still lagged behind and left development setup inconsistent with the tested runtime. what: - bump GitHub Actions workflows from Node 20.x -> 24.x - bump .nvmrc to 24.14.1 - bump .tool-versions to nodejs 24.14.1 and keep Yarn 1.22.22 - raise package.json engines.node to >=24.11.0 See also: - https://ckeditor.com/docs/ckeditor5/latest/framework/contributing/development-environment.html - https://nodejs.org/en/blog/release/v24.14.1 - https://www.npmjs.com/package/@ckeditor/ckeditor5-dev-build-tools
why: CKEditor v47's @ckeditor/ckeditor5-core throws license-key-missing (a hard error, not a warning) when no licenseKey is set. Without it, ClassicEditor.create() rejects and the editor never renders — the page shows plain browser-rendered static HTML. Key sourced from ariel's webpack.common.ts DefinePlugin (dev key, same commercial license). what: - sample/ckeditor.ts: add licenseKey to ClassicEditor.create() options
why: CKEditor 47 changed config.get() to return null-prototype objects, which breaks KaTeX macro handling, and the newer auto-render script now throws if it runs before document.body exists. Together they left the dev sample rendering broken. what: - shallow-copy katexRenderOptions.macros before calling katex.render so KaTeX receives an object with Object.prototype - bump the sample KaTeX CDN from 0.13.5 -> 0.16.43 and drop local-only SRI hashes - move auto-render.min.js to the end of body so it runs after the DOM is ready - keep katex.min.js in head so the plugin still sees the katex global early See also: - https://www.npmjs.com/package/katex - https://github.com/KaTeX/KaTeX
why: CKEditor v47's `.ck-reset_all :not(.ck-reset_all-excluded *)` reset rule (specificity 0,2,0) zeroes out padding on all descendants inside the balloon panel. Our `.ck.ck-math-form` selector has the same specificity (0,2,0), so the reset wins by source order in the v47 CSS bundle. This was not an issue in v43 where the reset rule had lower specificity. what: - Prefix form selector with `form` element type (`.ck.ck-math-form` → `form.ck.ck-math-form`) to boost specificity to 0,2,1 - Add flex column layout with gap to `.ck-math-view` so stacked children (input, display toggle, preview label, equation preview) have uniform vertical spacing via `gap: var(--ck-spacing-standard)` - Add explicit padding to `.ck-math-preview` for the equation preview area inside the balloon form
why: CKEditor 47 drag-move behavior exposed two issues in the math widget: the inner UIElement could start a native browser drag that bypassed CKEditor's DnD pipeline, and Differ move optimization reused the widget view without rerunning its KaTeX render callback. The result was either deleted or visually empty widgets after a move. what: - mark the inner KaTeX UIElement as draggable="false" so only CKEditor's outer widget container participates in drag-and-drop - reconvert inserted math elements on change:data after a move so the UIElement is recreated and katex.render() runs again at the new location - extend mathdragdrop.ts with clipboard roundtrip and DOM rendering regression tests for both inline and display math widgets
why: Browsers sanitize <script> tags from DataTransfer HTML during
drag-and-drop. The default outputType ('script') serializes equations as
<script type="math/tex">, which is stripped by the browser on drop,
causing equations to disappear. Ariel's production integration avoids
this by using outputType: 'span' with forceOutputType: true, which
serializes as <span class="math-tex"> — preserved by DataTransfer.
what:
- Add radio toggle to sample/index.html to switch between span and
script output types with corresponding HTML templates
- Default sample to span mode (matching ariel's working config)
- Refactor sample/ckeditor.ts to support destroy/recreate on toggle,
extract shared config into constants
- Add outputType/forceOutputType test suites to mathdragdrop.ts:
- span mode: downcast format, forced type on upcast from script tags,
clipboard roundtrip, drag-drop simulation
- script mode: downcast format for inline/display, type preservation
for both span and script source HTML
why: Record the CKEditor 47.6.1 prerelease in the changelog using the repo's usual version-section format. what: - add a v47.6.1-next.0 section directly under Current - summarize the CKEditor 47.6.1 compatibility fixes, sample updates, and Node 24 minimum - leave the Current placeholder intact for future unreleased changes
why: Keep the release metadata split consistent with recent repo history by bumping the prerelease version in its own commit after the changelog update. what: - change package.json version from 43.2.0-next.2 to 47.6.1-next.0 - leave dependency, Node minimum, and changelog content unchanged
01baaf3 to
6aaf111
Compare


Resolves LOB-1950
Summary
Upgrades
@multiverse-io/ckeditor5-mathfrom CKEditor 5 v43.2.0 → v47.6.1, fixes three equation rendering bugs (two pre-existing, one introduced by the upgrade), adds anoutputTypetoggle to the dev sample, and adds comprehensive drag-drop and output-type test coverage.What changed
1. CKEditor 5 v43 → v47 core upgrade
Breaking API renames — CKEditor 5 v46 introduced a unified exports system that renamed engine types to carry explicit
Model/Viewprefixes:DowncastWriterViewDowncastWritermathediting.tsLivePositionModelLivePositionautomath.tsLiveRangeModelLiveRangeautomath.tsElementModelElementmathediting.ts,utils.tsDocumentSelectionModelDocumentSelectionutils.tsicons.check/icons.cancelIconCheck/IconCancelmainformview.tsSee: Update to v46.x · Update to v47.x · Migrating imports (v46+)
Dev tooling bumps:
@ckeditor/ckeditor5-dev-build-tools43.0.055.2.0@ckeditor/ckeditor5-package-tools^2.1.0^5.1.0@ckeditor/ckeditor5-inspector>=4.1.0>=5.0.0eslint-config-ckeditor5>=7.1.09.1.0stylelint-config-ckeditor5>=7.1.010.0.0typescript5.0.4~5.5ckeditor5latest^47.6.1TypeScript / build config:
tsconfig.dist.jsonupdated withoutDir,include, and correctedtypespath for dev-build-tools v55 + TypeScript 5.5. Addedtypings/types/index.d.tsSVG module shim.CI: Node.js
20.x→24.x(@ckeditor/ckeditor5-dev-build-toolsv55 requires Node ≥24).2. KaTeX rendering fixes (
src/utils.ts,sample/index.html)Null-prototype macros — CKEditor v47's
config.get()returns objects created viaObject.create(null). KaTeX's internalNamespaceclass callsthis.current.hasOwnProperty()directly on the user macros object, which throwsTypeError: this.current.hasOwnProperty is not a functionon null-prototype objects. Fix: shallow-copykatexRenderOptions.macrosbefore passing tokatex.render()to restore theObject.prototypechain.See: CKEditor Config API
Auto-render DOM timing — KaTeX 0.16.x added an explicit null guard in
renderMathInElementthat throws"No element provided to render"when called with a null element. The<script onload>in<head>fires beforedocument.bodyexists. Fix: keepkatex.min.jsin<head>(must be global before CKEditor init), move onlyauto-render.min.jsto end of<body>.KaTeX CDN bump —
0.13.5→0.16.43. SRI hashes dropped (unnecessary for dev sample). See: KaTeX releases · KaTeX CHANGELOG3. Balloon form CSS padding fix (
theme/mathform.css)CKEditor v47's
.ck-reset_all :not(.ck-reset_all-excluded *)CSS reset (specificity0,2,0) zeroes padding on all descendants inside the balloon panel. Our.ck.ck-math-formselector has the same specificity and loses by source order.Fix:
formelement type →form.ck.ck-math-form(specificity0,2,1, beats the reset)display: flex; flex-direction: column; gapto.ck-math-viewfor vertical spacing between stacked children.ck-math-previewfor the equation preview area4. Drag-and-drop equation fix (
src/mathediting.ts)Two independent bugs cause equations to disappear after drag-and-drop:
Bug A — UIElement render callback not re-invoked: CKEditor's Differ optimizes model moves by repositioning existing view elements. The UIElement's render callback (which calls
katex.render()) only fires once. After move, the KaTeX HTML is lost.Fix: Add a
change:datalistener that callseditor.editing.reconvertItem()on insertedmathtex-inline/mathtex-displayelements. This follows CKEditor's own pattern used inckeditor5-image,ckeditor5-table, andckeditor5-list.Bug B — Browser sanitizes
<script>from DataTransfer: WhenoutputTypeis'script'(the default), equations serialize as<script type="math/tex">. Browsers strip<script>tags fromDataTransferHTML for security. On drop, the upcast finds no math element and the equation data is entirely lost. This is version-independent — it affects v43 too.This is why ariel's production integration (which uses
outputType: 'span'+forceOutputType: true) never exhibited this bug —<span class="math-tex">survives DataTransfer sanitization.See: HTML Sanitizer API (MDN) · DataTransfer API (web.dev)
5. Dev sample
outputTypetoggle (sample/index.html,sample/ckeditor.ts)Added a radio toggle above the editor to switch between:
span(default) —outputType: 'span',forceOutputType: true, HTML templates use<span class="math-tex">script—outputType: 'script',forceOutputType: false, HTML templates use<script type="math/tex">Toggling destroys and recreates the editor with the matching config and HTML template. Default is
spanto match ariel's production config and avoid the DataTransfer drag-drop bug.6. Dev sample license key (
sample/ckeditor.ts)CKEditor v47 requires a
licenseKey— without one,ClassicEditor.create()rejects withlicense-key-missing. The key in this PR is a CKEditor development license (non-secret, non-billable):Development keys are free to obtain, restricted to
localhost/*.test/*.local/ private IPs, and do not consume editor loads. They are explicitly designed for local development, CI, and E2E tests. The key carries no commercial entitlements and cannot be used in production.See: License key and activation · Obtaining the license key
7. Tests (
tests/mathdragdrop.ts)Added 460 lines of test coverage:
outputType: 'span'+forceOutputType: true— Downcast format, forced type on upcast from<script>tags, clipboard roundtrip, drag-drop simulationoutputType: 'script'+forceOutputType: false— Downcast format for inline/display, type preservation from both<span>and<script>source HTMLNote:
ckeditor5-package-toolsv5 dropped thetesttask. Tests are written against mocha/chai but need a runner configuration to execute (tracked separately).Screenshots
Files changed
src/mathediting.tsreconvertItem()listener for drag-dropsrc/automath.tsLivePosition/LiveRange→ModelLivePosition/ModelLiveRangesrc/utils.tsObject.prototypesrc/ui/mainformview.tsicons.check/cancel→IconCheck/IconCanceltheme/mathform.css.ck-math-viewflex column + preview paddingsample/ckeditor.tsoutputTypetoggle, destroy/recreate, license keysample/index.html<template>blocks for span/scripttests/mathdragdrop.tspackage.json.github/workflows/*.ymltsconfig.dist.jsontypings/types/index.d.tsyarn.lockTest plan
yarn lint— 0 errorsyarn stylelint— 0 errorsyarn build:dist— NPM + browser builds passtsc -p tsconfig.release.json— no type errorsbuild (24.x)— greenlocalhost:8084loads with 0 console errors, all 4 equations renderhasKatex: true, 1117 chars)outputTyperadio toggle destroys/recreates editor with correct configspanmode — equation survivesscriptmode — equation reconverts (model survives via reconvertItem, but DataTransfer may strip<script>)Note
High Risk
High due to a major CKEditor dependency/toolchain upgrade (v43→v47) plus changes in editor conversion/rendering paths (
reconvertItemon model changes) that can affect data serialization and widget behavior across paste/undo/drag-drop.Overview
Upgrades the package to CKEditor 47.6.1 (and related tooling like
ckeditor5-dev-build-tools,ckeditor5-package-tools, lint configs, and TypeScript), bumps the package version/peer range, and raises the minimum/CI Node.js version to 24.11+.Fixes several rendering/regression issues: forces math widgets to reconvert after model inserts to restore equation rendering after drag-drop/paste/undo, prevents native dragging by setting
draggable="false"on the UI element, and hardens KaTeX rendering by cloningkatexRenderOptions(notablymacros) to avoid null-prototype pitfalls.Refreshes the dev sample to CKEditor 47 requirements (adds a dev
licenseKey, updates KaTeX CDN and script placement) and adds anoutputType(span vs script) toggle; adds a comprehensive newtests/mathdragdrop.tssuite covering clipboard roundtrips, drag-drop simulations, DOM re-rendering, andoutputType/forceOutputTypebehavior. Also updates build TS config (tsconfig.dist.json) and adds an SVG module typing shim.Written by Cursor Bugbot for commit 6aaf111. This will update automatically on new commits. Configure here.