Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/client/src/translations/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -2084,6 +2084,8 @@
},
"editorfeatures": {
"title": "Features",
"mathlive_enabled": "MathLive visual editor",
"mathlive_description": "Math equations can be edited using a visual editor.",
"emoji_completion_enabled": "Emoji auto-completion",
"emoji_completion_description": "Emojis can be easily inserted into text by typing `:`, followed by the name of an emoji.",
"note_completion_enabled": "Note auto-completion",
Expand Down
9 changes: 9 additions & 0 deletions apps/client/src/widgets/type_widgets/options/text_notes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,21 @@ function ToolbarIcon({ wide }: { wide?: boolean }) {
}

function EditorFeatures() {
const [mathFieldEnabled, setMathFieldEnabled] = useTriliumOptionBool("mathFieldEnabled");
const [emojiCompletionEnabled, setEmojiCompletionEnabled] = useTriliumOptionBool("textNoteEmojiCompletionEnabled");
const [noteCompletionEnabled, setNoteCompletionEnabled] = useTriliumOptionBool("textNoteCompletionEnabled");
const [slashCommandsEnabled, setSlashCommandsEnabled] = useTriliumOptionBool("textNoteSlashCommandsEnabled");

return (
<OptionsSection title={t("editorfeatures.title")}>
<OptionsRowWithToggle
name="mathlive-enabled"
label={t("editorfeatures.mathlive_enabled")}
description={t("editorfeatures.mathlive_description")}
currentValue={mathFieldEnabled}
onChange={setMathFieldEnabled}
/>

<OptionsRowWithToggle
name="emoji-completion-enabled"
label={t("editorfeatures.emoji_completion_enabled")}
Expand Down
1 change: 1 addition & 0 deletions apps/client/src/widgets/type_widgets/text/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export async function buildConfig(opts: BuildEditorOptions): Promise<EditorConfi
(window as any).katex = (await import("../../../services/math.js")).default;
},
forceOutputType: false, // forces output to use outputType
enableMathField: options.get("mathFieldEnabled") !== "false",
enablePreview: true // Enable preview view
},
mermaid: {
Expand Down
1 change: 1 addition & 0 deletions apps/server/src/routes/api/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ const ALLOWED_OPTIONS = new Set<OptionNames>([
"textNoteEmojiCompletionEnabled",
"textNoteCompletionEnabled",
"textNoteSlashCommandsEnabled",
"mathFieldEnabled",
"includeNoteDefaultBoxSize",
"layoutOrientation",
"backgroundEffects",
Expand Down
1 change: 1 addition & 0 deletions apps/server/src/services/options_init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ const defaultOptions: DefaultOption[] = [
{ name: "textNoteEmojiCompletionEnabled", value: "true", isSynced: true },
{ name: "textNoteCompletionEnabled", value: "true", isSynced: true },
{ name: "textNoteSlashCommandsEnabled", value: "true", isSynced: true },
{ name: "mathFieldEnabled", value: "true", isSynced: true },
{ name: "includeNoteDefaultBoxSize", value: "medium", isSynced: true },

// HTML import configuration
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@
"pnpm": {
"patchedDependencies": {
"@ckeditor/ckeditor5-mention": "patches/@ckeditor__ckeditor5-mention.patch",
"@ckeditor/ckeditor5-code-block": "patches/@ckeditor__ckeditor5-code-block.patch"
"@ckeditor/ckeditor5-code-block": "patches/@ckeditor__ckeditor5-code-block.patch",
"mathlive@0.109.1": "patches/mathlive@0.109.1.patch"
},
"overrides": {
"@codemirror/language": "6.12.3",
Expand Down
1 change: 1 addition & 0 deletions packages/ckeditor5-math/src/augmentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ declare module 'ckeditor5' {
className?: string | undefined;
forceOutputType?: boolean | undefined;
enablePreview?: boolean | undefined;
enableMathField?: boolean | undefined;
previewClassName?: Array<string> | undefined;
popupClassName?: Array<string> | undefined;
katexRenderOptions?: Partial<KatexOptions> | undefined;
Expand Down
1 change: 1 addition & 0 deletions packages/ckeditor5-math/src/mathediting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export default class MathEditing extends Plugin {
className: 'math-tex',
forceOutputType: false,
enablePreview: true,
enableMathField: true,
previewClassName: [],
popupClassName: [],
katexRenderOptions: {}
Expand Down
3 changes: 2 additions & 1 deletion packages/ckeditor5-math/src/mathui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ export default class MathUI extends Plugin {
katexRenderOptions: mathConfig.katexRenderOptions!
},
mathConfig.enablePreview,
mathConfig.popupClassName!
mathConfig.popupClassName!,
mathConfig.enableMathField
);

formView.mathInputView.bind( 'value' ).to( mathCommand, 'value' );
Expand Down
5 changes: 3 additions & 2 deletions packages/ckeditor5-math/src/ui/mainformview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ export default class MainFormView extends View {
locale: Locale,
mathViewOptions: MathViewOptions,
previewEnabled = false,
popupClassName: Array<string> = []
popupClassName: Array<string> = [],
enableMathField = true
) {
super( locale );
const t = locale.t;

// Create views
this.mathInputView = new MathInputView( locale );
this.mathInputView = new MathInputView( locale, enableMathField );
this.saveButtonView = this._createButton( t( 'Save' ), IconCheck, 'ck-button-save', 'submit' );
this.cancelButtonView = this._createButton( t( 'Cancel' ), IconCancel, 'ck-button-cancel' );
this.cancelButtonView.delegate( 'execute' ).to( this, 'cancel' );
Expand Down
52 changes: 28 additions & 24 deletions packages/ckeditor5-math/src/ui/mathinputview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,6 @@ import { View, type Locale, type FocusableView } from 'ckeditor5';
import 'mathlive/fonts.css'; // Auto-bundles offline fonts
import 'mathlive/static.css'; // Static styles for mathlive

declare global {
interface Window {
mathVirtualKeyboard?: {
visible: boolean;
show: () => void;
hide: () => void;
addEventListener: ( event: string, cb: () => void ) => void;
removeEventListener: ( event: string, cb: () => void ) => void;
};
}
}

interface MathFieldElement extends HTMLElement {
value: string;
readOnly: boolean;
Expand Down Expand Up @@ -64,21 +52,28 @@ export default class MathInputView extends View {
private _destroyed = false;
private _vkGeometryHandler?: () => void;
private _updating = false;
private _enableMathField: boolean;
private static _configured = false;

constructor( locale: Locale ) {
constructor( locale: Locale, enableMathField = true ) {
super( locale );
this._enableMathField = enableMathField;
this.latexTextAreaView = new LatexTextAreaView( locale );
this.mathFieldFocusableView = new MathFieldFocusableView( locale, this );
this.set( 'value', null );
this.set( 'isReadOnly', false );
const children: Array<any> = [];
// Only include the MathLive container in the DOM when the feature is enabled
if ( this._enableMathField ) {
children.push( { tag: 'div', attributes: { class: [ 'ck-mathlive-container' ] } } );
}
children.push(
{ tag: 'label', attributes: { class: [ 'ck-latex-label' ] }, children: [ locale.t( 'LaTeX' ) ] },
{ tag: 'div', attributes: { class: [ 'ck-latex-wrapper' ] }, children: [ this.latexTextAreaView ] }
);
this.setTemplate( {
tag: 'div', attributes: { class: [ 'ck', 'ck-math-input' ] },
children: [
{ tag: 'div', attributes: { class: [ 'ck-mathlive-container' ] } },
{ tag: 'label', attributes: { class: [ 'ck-latex-label' ] }, children: [ locale.t( 'LaTeX' ) ] },
{ tag: 'div', attributes: { class: [ 'ck-latex-wrapper' ] }, children: [ this.latexTextAreaView ] }
]
children
} );
}

Expand Down Expand Up @@ -135,7 +130,7 @@ export default class MathInputView extends View {
} );

// Handle virtual keyboard geometry changes
const vk = window.mathVirtualKeyboard;
const vk = (window as any).mathVirtualKeyboard;
if ( vk && !this._vkGeometryHandler ) {
this._vkGeometryHandler = () => {
if ( vk.visible && this.mathfield ) {
Expand All @@ -149,7 +144,9 @@ export default class MathInputView extends View {
if ( textarea.value !== initial ) {
textarea.value = initial;
}
this._loadMathLive();
if ( this._enableMathField ) {
this._loadMathLive();
}
}

// Loads the MathLive library dynamically
Expand Down Expand Up @@ -198,7 +195,10 @@ export default class MathInputView extends View {
// Set shortcuts after mounting (accessing inlineShortcuts requires mounted element)
try {
if ( mf.inlineShortcuts ) {
mf.inlineShortcuts = { ...mf.inlineShortcuts, dx: 'dx', dy: 'dy', dt: 'dt' };
// Allows external listeners to inject custom MathLive shortcuts by mutating event.detail.
const customShortcuts: Record<string, string> = {};
document.dispatchEvent( new CustomEvent( 'mathlive:custom-shortcuts', { detail: customShortcuts } ) );
mf.inlineShortcuts = { ...mf.inlineShortcuts, dx: 'dx', dy: 'dy', dt: 'dt', ...customShortcuts };
}
} catch {
// Inline shortcut configuration is optional; ignore failures to avoid breaking the math field.
Expand Down Expand Up @@ -247,16 +247,20 @@ export default class MathInputView extends View {
}

public hideKeyboard(): void {
window.mathVirtualKeyboard?.hide();
(window as any).mathVirtualKeyboard?.hide();
}

public focus(): void {
this.mathfield?.focus();
if ( this.mathfield ) {
this.mathfield.focus();
} else {
this.latexTextAreaView.focus();
}
}

public override destroy(): void {
this._destroyed = true;
const vk = window.mathVirtualKeyboard;
const vk = (window as any).mathVirtualKeyboard;
if ( vk && this._vkGeometryHandler ) {
vk.removeEventListener( 'geometrychange', this._vkGeometryHandler );
this._vkGeometryHandler = undefined;
Expand Down
2 changes: 2 additions & 0 deletions packages/commons/src/lib/options_interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ export interface OptionDefinitions extends KeyboardShortcutsOptions<KeyboardActi
textNoteCompletionEnabled: boolean;
/** Whether keyboard auto-completion for editing commands is triggered when typing `/`. */
textNoteSlashCommandsEnabled: boolean;
/** Whether the MathLive visual editor is shown when editing math. If false, only the LaTeX textarea is used. */
mathFieldEnabled: boolean;
backgroundEffects: boolean;
newLayout: boolean;

Expand Down
67 changes: 67 additions & 0 deletions patches/mathlive@0.109.1.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
diff --git a/mathlive.js b/mathlive.js
index 2c1c90a0963e0e02d311be907c471a5bb3a171ad..03703507ef82b112b8e133307b7bdfd341d78f41 100644
--- a/mathlive.js
+++ b/mathlive.js
@@ -39036,9 +39036,9 @@ data-command='[\"setEnvironment\",\"pmatrix\"]'>
if (offset < first || offset > last) return false;
if (!atom.hasChildren) return true;
const firstChild = includeFirstAtoms ? atom.firstChild : firstNonFirstChild(atom);
- if (!firstChild) return false;
+ if (!firstChild) return true;
const lastChild = includeFirstAtoms ? atom.lastChild : lastNonFirstChild(atom);
- if (!lastChild) return false;
+ if (!lastChild) return true;
const firstOffset = model.offsetOf(firstChild);
if (firstOffset >= first && firstOffset <= last) {
const lastOffset = model.offsetOf(lastChild);
diff --git a/mathlive.mjs b/mathlive.mjs
index 16bde454e19b5e83bbc60cd98f0bd1ea5e2359b1..72a64a4f4feb646d89d9b9b2ec331f608a012d20 100644
--- a/mathlive.mjs
+++ b/mathlive.mjs
@@ -38996,9 +38996,9 @@ function atomIsInRange(model, atom, first, last, includeFirstAtoms) {
if (offset < first || offset > last) return false;
if (!atom.hasChildren) return true;
const firstChild = includeFirstAtoms ? atom.firstChild : firstNonFirstChild(atom);
- if (!firstChild) return false;
+ if (!firstChild) return true;
const lastChild = includeFirstAtoms ? atom.lastChild : lastNonFirstChild(atom);
- if (!lastChild) return false;
+ if (!lastChild) return true;
const firstOffset = model.offsetOf(firstChild);
if (firstOffset >= first && firstOffset <= last) {
const lastOffset = model.offsetOf(lastChild);
diff --git a/package.json b/package.json
index 343841095cbfcb883d0530ae77809db996a206db..a9aee5cf1f66a8504d82b4c66f412742b284b814 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,7 @@
"mathquill"
],
"main": "./mathlive.min.js",
- "module": "./mathlive.min.mjs",
+ "module": "./mathlive.mjs",
"types": "./types/mathlive.d.ts",
"exports": {
"./vue": "./vue-mathlive.mjs",
@@ -39,8 +39,8 @@
"browser": {
"production": {
"types": "./types/mathlive.d.ts",
- "import": "./mathlive.min.mjs",
- "require": "./mathlive.min.js"
+ "import": "./mathlive.mjs",
+ "require": "./mathlive.js"
},
"development": {
"types": "./types/mathlive.d.ts",
@@ -54,8 +54,8 @@
},
"default": {
"types": "./types/mathlive.d.ts",
- "import": "./mathlive.min.mjs",
- "require": "./mathlive.min.js"
+ "import": "./mathlive.mjs",
+ "require": "./mathlive.js"
}
},
"./ssr": {
7 changes: 5 additions & 2 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading