From 262ec45fe0bdab615e83a7adb2e956e509d264fa Mon Sep 17 00:00:00 2001 From: SiriusXT <1160925501@qq.com> Date: Fri, 23 May 2025 17:03:07 +0800 Subject: [PATCH 1/3] feat(math): support multi-line formula editing --- packages/ckeditor5-math/src/mathui.ts | 20 +++++++++ .../ckeditor5-math/src/ui/mainformview.ts | 6 +-- packages/ckeditor5-math/src/ui/mathview.ts | 2 +- packages/ckeditor5-math/src/utils.ts | 45 +------------------ 4 files changed, 25 insertions(+), 48 deletions(-) diff --git a/packages/ckeditor5-math/src/mathui.ts b/packages/ckeditor5-math/src/mathui.ts index f3c86af49..cc402c1e6 100644 --- a/packages/ckeditor5-math/src/mathui.ts +++ b/packages/ckeditor5-math/src/mathui.ts @@ -110,6 +110,26 @@ export default class MathUI extends Plugin { cancel(); } ); + // Allow pressing Enter to submit changes, and use Shift+Enter to insert a new line + formView.keystrokes.set('enter', (data, cancel) => { + if (!data.shiftKey) { + formView.fire('submit'); + cancel(); + } + }); + + // Allow the textarea to be resizable + formView.mathInputView.fieldView.once('render', () => { + const textarea = formView.mathInputView.fieldView.element; + if (!textarea) return; + textarea.focus(); + Object.assign(textarea.style, { + resize: 'both', + height: '100px', + minWidth: '100%', + }); + }); + return formView; } diff --git a/packages/ckeditor5-math/src/ui/mainformview.ts b/packages/ckeditor5-math/src/ui/mainformview.ts index af86fd77c..751c3c679 100644 --- a/packages/ckeditor5-math/src/ui/mainformview.ts +++ b/packages/ckeditor5-math/src/ui/mainformview.ts @@ -1,16 +1,16 @@ -import { ButtonView, createLabeledInputText, FocusCycler, LabelView, LabeledFieldView, submitHandler, SwitchButtonView, View, ViewCollection, type InputTextView, type FocusableView, Locale, FocusTracker, KeystrokeHandler } from 'ckeditor5'; +import { ButtonView, createLabeledTextarea, FocusCycler, LabelView, LabeledFieldView, submitHandler, SwitchButtonView, View, ViewCollection, type TextareaView, type FocusableView, Locale, FocusTracker, KeystrokeHandler } from 'ckeditor5'; import { IconCheck, IconCancel } from "@ckeditor/ckeditor5-icons"; import { extractDelimiters, hasDelimiters } from '../utils.js'; import MathView from './mathview.js'; import '../../theme/mathform.css'; import type { KatexOptions } from '../typings-external.js'; -class MathInputView extends LabeledFieldView { +class MathInputView extends LabeledFieldView { public value: null | string = null; public isReadOnly = false; constructor( locale: Locale ) { - super( locale, createLabeledInputText ); + super( locale, createLabeledTextarea ); } } diff --git a/packages/ckeditor5-math/src/ui/mathview.ts b/packages/ckeditor5-math/src/ui/mathview.ts index 541227e43..fab16262e 100644 --- a/packages/ckeditor5-math/src/ui/mathview.ts +++ b/packages/ckeditor5-math/src/ui/mathview.ts @@ -49,7 +49,7 @@ export default class MathView extends View { this.setTemplate( { tag: 'div', attributes: { - class: [ 'ck', 'ck-math-preview' ] + class: [ 'ck', 'ck-math-preview', 'ck-reset_all-excluded' ] } } ); } diff --git a/packages/ckeditor5-math/src/utils.ts b/packages/ckeditor5-math/src/utils.ts index 3a29d3fc2..2e120b6c2 100644 --- a/packages/ckeditor5-math/src/utils.ts +++ b/packages/ckeditor5-math/src/utils.ts @@ -94,7 +94,6 @@ export async function renderEquation( el => { renderMathJax3( equation, el, display, () => { if ( preview ) { - moveAndScaleElement( element, el ); el.style.visibility = 'visible'; } } ); @@ -115,7 +114,6 @@ export async function renderEquation( if ( preview && isMathJaxVersion2( MathJax ) ) { // eslint-disable-next-line new-cap MathJax.Hub.Queue( () => { - moveAndScaleElement( element, el ); el.style.visibility = 'visible'; } ); } @@ -139,7 +137,6 @@ export async function renderEquation( } ); } if ( preview ) { - moveAndScaleElement( element, el ); el.style.visibility = 'visible'; } } @@ -295,47 +292,7 @@ function getPreviewElement( previewEl.setAttribute( 'id', previewUid ); previewEl.classList.add( ...previewClassName ); previewEl.style.visibility = 'hidden'; - document.body.appendChild( previewEl ); - - let ticking = false; - - const renderTransformation = () => { - if ( !ticking ) { - window.requestAnimationFrame( () => { - if ( previewEl ) { - moveElement( element, previewEl ); - ticking = false; - } - } ); - - ticking = true; - } - }; - - // Create scroll listener for following - window.addEventListener( 'resize', renderTransformation ); - window.addEventListener( 'scroll', renderTransformation ); + element.appendChild( previewEl ); } return previewEl; } - -function moveAndScaleElement( parent: HTMLElement, child: HTMLElement ) { - // Move to right place - moveElement( parent, child ); - - // Scale parent element same as preview - const domRect = child.getBoundingClientRect(); - parent.style.width = domRect.width + 'px'; - parent.style.height = domRect.height + 'px'; -} - -function moveElement( parent: HTMLElement, child: HTMLElement ) { - const domRect = parent.getBoundingClientRect(); - const left = window.scrollX + domRect.left; - const top = window.scrollY + domRect.top; - child.style.position = 'absolute'; - child.style.left = left + 'px'; - child.style.top = top + 'px'; - child.style.zIndex = 'var(--ck-z-panel)'; - child.style.pointerEvents = 'none'; -} From aff5a9c31d716b84cd44d449e52bd21e57e5df1f Mon Sep 17 00:00:00 2001 From: SiriusXT <1160925501@qq.com> Date: Mon, 26 May 2025 16:05:27 +0800 Subject: [PATCH 2/3] style(math): Set the default width of the math formula editing dialog --- packages/ckeditor5-math/src/mathui.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ckeditor5-math/src/mathui.ts b/packages/ckeditor5-math/src/mathui.ts index cc402c1e6..851c86e63 100644 --- a/packages/ckeditor5-math/src/mathui.ts +++ b/packages/ckeditor5-math/src/mathui.ts @@ -126,6 +126,7 @@ export default class MathUI extends Plugin { Object.assign(textarea.style, { resize: 'both', height: '100px', + width: '400px', minWidth: '100%', }); }); From 32fd575cc46c63d0fdb0328082912d020a1d3468 Mon Sep 17 00:00:00 2001 From: SiriusXT <1160925501@qq.com> Date: Mon, 26 May 2025 17:17:18 +0800 Subject: [PATCH 3/3] fix(math edit): preserve line breaks --- packages/ckeditor5-math/src/mathediting.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/ckeditor5-math/src/mathediting.ts b/packages/ckeditor5-math/src/mathediting.ts index bfd08ed37..0c51653c3 100644 --- a/packages/ckeditor5-math/src/mathediting.ts +++ b/packages/ckeditor5-math/src/mathediting.ts @@ -27,6 +27,18 @@ export default class MathEditing extends Plugin { public init(): void { const editor = this.editor; + + const originalProcessor = editor.data.processor; + const originalToView = originalProcessor.toView.bind(originalProcessor); + const mathSpanRegex = /([\s\S]*?)<\/span>/g; + originalProcessor.toView = (data: string) => { + // Preprocessing: preserve line breaks inside math formulas by replacing \n with + const processedData = data.replace(mathSpanRegex, (_, content) => + `${content.replace(/\n/g, '___MATH_TEX_LF___')}` + ); + return originalToView(processedData); + }; + editor.commands.add( 'math', new MathCommand( editor ) ); this._defineSchema(); @@ -120,8 +132,7 @@ export default class MathEditing extends Plugin { model: ( viewElement, { writer } ) => { const child = viewElement.getChild( 0 ); if ( child?.is( '$text' ) ) { - const equation = child.data.trim(); - + const equation = child.data.trim().replace(/___MATH_TEX_LF___/g, '\n'); const params = Object.assign( extractDelimiters( equation ), { type: mathConfig.forceOutputType ? mathConfig.outputType :