Improve Synchronization Between Mathlive and rawlatex input

This commit is contained in:
meinzzzz 2025-12-02 22:28:16 +01:00
parent f8d84814e0
commit acca22f3a1

View File

@ -48,8 +48,7 @@ export default class MainFormView extends View {
this.rawLatexInputView = new RawLatexInputView( locale ); this.rawLatexInputView = new RawLatexInputView( locale );
this.rawLatexInputView.label = t( 'LaTeX' ); this.rawLatexInputView.label = t( 'LaTeX' );
this.saveButtonView = this._createButton( t( 'Save' ), IconCheck, 'ck-button-save' ); this.saveButtonView = this._createButton( t( 'Save' ), IconCheck, 'ck-button-save', 'submit' );
this.saveButtonView.type = 'submit';
this.cancelButtonView = this._createButton( t( 'Cancel' ), IconCancel, 'ck-button-cancel' ); this.cancelButtonView = this._createButton( t( 'Cancel' ), IconCancel, 'ck-button-cancel' );
this.cancelButtonView.delegate( 'execute' ).to( this, 'cancel' ); this.cancelButtonView.delegate( 'execute' ).to( this, 'cancel' );
@ -150,58 +149,67 @@ export default class MainFormView extends View {
} }
/** /**
* Sets up split handlers for synchronization. * Checks if a view currently has focus.
*/
private _isViewFocused(view: View): boolean {
const el = view.element;
const active = document.activeElement;
return !!(el && active && el.contains(active));
}
/**
* Sets up synchronization with Focus Gating.
*/ */
private _setupInputSync(previewEnabled: boolean): void { private _setupInputSync(previewEnabled: boolean): void {
// Handler 1: MathLive -> Raw LaTeX const updatePreview = (eq: string) => {
if (previewEnabled && this.mathView && this.mathView.value !== eq) {
this.mathView.value = eq;
}
};
// Handler 1: MathLive -> Raw LaTeX + Preview
this.mathLiveInputView.on('change:value', () => { this.mathLiveInputView.on('change:value', () => {
let eq = (this.mathLiveInputView.value ?? '').trim(); let eq = (this.mathLiveInputView.value ?? '').trim();
// Delimiter Normalization // Strip delimiters if present (e.g. pasted content)
if (hasDelimiters(eq)) { if (hasDelimiters(eq)) {
const params = extractDelimiters(eq); const params = extractDelimiters(eq);
eq = params.equation; eq = params.equation;
this.displayButtonView.isOn = params.display; this.displayButtonView.isOn = params.display;
// UX Fix: If we stripped delimiters, update the source // Only strip delimiters if not actively editing
// so the visual editor doesn't show them. if (!this._isViewFocused(this.mathLiveInputView) && this.mathLiveInputView.value !== eq) {
if ( this.mathLiveInputView.value !== eq ) {
this.mathLiveInputView.value = eq; this.mathLiveInputView.value = eq;
} }
} }
// Sync to Raw LaTeX // Sync to Raw LaTeX only if user isn't typing there
if ( this.rawLatexInputView.value !== eq ) { if (!this._isViewFocused(this.rawLatexInputView) && this.rawLatexInputView.value !== eq) {
this.rawLatexInputView.value = eq; this.rawLatexInputView.value = eq;
} }
// Sync to Preview updatePreview(eq);
if ( previewEnabled && this.mathView && this.mathView.value !== eq ) {
this.mathView.value = eq;
}
}); });
// Handler 2: Raw LaTeX -> MathLive // Handler 2: Raw LaTeX -> MathLive + Preview
this.rawLatexInputView.on('change:value', () => { this.rawLatexInputView.on('change:value', () => {
const eq = (this.rawLatexInputView.value ?? '').trim(); const eq = (this.rawLatexInputView.value ?? '').trim();
const normalized = eq.length ? eq : null; const normalized = eq.length ? eq : null;
// Sync to MathLive // Sync to MathLive only if user isn't interacting with it
if ( this.mathLiveInputView.value !== normalized ) { if (!this._isViewFocused(this.mathLiveInputView) && this.mathLiveInputView.value !== normalized) {
this.mathLiveInputView.value = normalized; this.mathLiveInputView.value = normalized;
} }
// Sync to Preview updatePreview(eq);
if ( previewEnabled && this.mathView && this.mathView.value !== eq ) {
this.mathView.value = eq;
}
}); });
} }
private _createButton( label: string, icon: string, className: string ): ButtonView { private _createButton( label: string, icon: string, className: string, type?: 'submit' | 'button' ): ButtonView {
const btn = new ButtonView( this.locale ); const btn = new ButtonView( this.locale );
btn.set( { label, icon, tooltip: true } ); btn.set( { label, icon, tooltip: true } );
btn.extendTemplate( { attributes: { class: className } } ); btn.extendTemplate( { attributes: { class: className } } );
if (type) btn.type = type;
return btn; return btn;
} }