@formulaxjs/ckeditor5 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -87,6 +87,24 @@ await ClassicEditor.create(document.querySelector('#editor')!, {
87
87
 
88
88
  Then users can click the `FormulaX` toolbar button to insert a formula. Existing formulas can be updated by double-clicking them, or by selecting them and executing the same command again.
89
89
 
90
+ ## Custom model names
91
+
92
+ The default CKEditor 5 model name is `formulaX`.
93
+
94
+ If the host editor already uses that model name, pass a custom `name` in the `formulaX` config:
95
+
96
+ ```ts
97
+ await ClassicEditor.create(document.querySelector('#editor')!, {
98
+ plugins: [Essentials, Paragraph, FormulaX],
99
+ toolbar: ['formulaX'],
100
+ formulaX: {
101
+ name: 'inlineMath',
102
+ },
103
+ } as any);
104
+ ```
105
+
106
+ If CKEditor 5 detects that the configured model name is already registered, the plugin logs a `console.error` and skips registration so the editor does not silently create a conflicting schema definition.
107
+
90
108
  ## Programmatic opening
91
109
 
92
110
  The plugin registers a command whose name matches `buttonName`. With the default configuration:
@@ -147,6 +165,7 @@ The editing view renders formula SVG at runtime from the persisted LaTeX. The ex
147
165
 
148
166
  ```ts
149
167
  interface FormulaXCKEditor5Options {
168
+ name?: string;
150
169
  buttonName?: string;
151
170
  toolbarText?: string;
152
171
  tooltip?: string;
@@ -173,6 +192,7 @@ interface FormulaXCKEditor5Options {
173
192
 
174
193
  | Option | Default | Description |
175
194
  | --- | --- | --- |
195
+ | `name` | `formulaX` | CKEditor 5 model/schema element name used for persisted formula nodes. |
176
196
  | `buttonName` | `formulaX` | CKEditor 5 toolbar button name and command name. |
177
197
  | `toolbarText` | `FormulaX` | Toolbar button label. |
178
198
  | `tooltip` | `Insert or edit formula` | Toolbar button tooltip. |
@@ -210,6 +230,7 @@ interface FormulaXCKEditor5Options {
210
230
  | `FormulaXCommand` | Command implementation used by the plugin. |
211
231
  | `resolveOptions` | Resolves user options into required defaults. |
212
232
  | `openFormulaXModal` | Opens the FormulaX modal directly. |
233
+ | `DEFAULT_MODEL_NAME` | Default CKEditor 5 model name. |
213
234
  | `DEFAULT_BUTTON_NAME` | Default CKEditor 5 command and toolbar button name. |
214
235
  | `DEFAULT_FORMULA_ATTRIBUTE` | Default LaTeX persistence attribute name. |
215
236
  | `DEFAULT_FORMULA_CLASS` | Default CSS class for formula nodes. |
package/README.zh-CN.md CHANGED
@@ -87,6 +87,24 @@ await ClassicEditor.create(document.querySelector('#editor')!, {
87
87
 
88
88
  之后用户可以点击 `FormulaX` 工具栏按钮插入公式。已有公式可以通过双击更新,也可以先选中后再次执行同一个命令进行更新。
89
89
 
90
+ ## 自定义 model 名称
91
+
92
+ 默认的 CKEditor 5 model 名称是 `formulaX`。
93
+
94
+ 如果宿主编辑器里已经存在同名 model,可以在 `formulaX` 配置里传入自定义 `name`:
95
+
96
+ ```ts
97
+ await ClassicEditor.create(document.querySelector('#editor')!, {
98
+ plugins: [Essentials, Paragraph, FormulaX],
99
+ toolbar: ['formulaX'],
100
+ formulaX: {
101
+ name: 'inlineMath',
102
+ },
103
+ } as any);
104
+ ```
105
+
106
+ 如果 CKEditor 5 检测到配置的 model 名称已经被注册,插件会输出一条 `console.error`,并跳过本次注册,避免悄悄创建冲突的 schema 定义。
107
+
90
108
  ## 代码中主动打开
91
109
 
92
110
  插件注册的命令名与 `buttonName` 保持一致。默认配置下可直接调用:
@@ -147,6 +165,7 @@ CKEditor 5 的 model 层只保存公式的 LaTeX 源内容:
147
165
 
148
166
  ```ts
149
167
  interface FormulaXCKEditor5Options {
168
+ name?: string;
150
169
  buttonName?: string;
151
170
  toolbarText?: string;
152
171
  tooltip?: string;
@@ -173,6 +192,7 @@ interface FormulaXCKEditor5Options {
173
192
 
174
193
  | 配置项 | 默认值 | 说明 |
175
194
  | --- | --- | --- |
195
+ | `name` | `formulaX` | 用于持久化公式节点的 CKEditor 5 model/schema 元素名。 |
176
196
  | `buttonName` | `formulaX` | CKEditor 5 的工具栏按钮名,同时也是命令名。 |
177
197
  | `toolbarText` | `FormulaX` | 工具栏按钮显示文本。 |
178
198
  | `tooltip` | `Insert or edit formula` | 工具栏按钮 tooltip。 |
@@ -210,6 +230,7 @@ interface FormulaXCKEditor5Options {
210
230
  | `FormulaXCommand` | 插件内部使用的命令实现。 |
211
231
  | `resolveOptions` | 将用户配置与默认配置合并为完整配置。 |
212
232
  | `openFormulaXModal` | 直接打开 FormulaX 弹窗。 |
233
+ | `DEFAULT_MODEL_NAME` | 默认的 CKEditor 5 model 名称。 |
213
234
  | `DEFAULT_BUTTON_NAME` | 默认的 CKEditor 5 命令名和工具栏按钮名。 |
214
235
  | `DEFAULT_FORMULA_ATTRIBUTE` | 默认的 LaTeX 持久化属性名。 |
215
236
  | `DEFAULT_FORMULA_CLASS` | 默认的公式节点 CSS class。 |
package/dist/index.cjs CHANGED
@@ -23,6 +23,7 @@ __export(index_exports, {
23
23
  DEFAULT_BUTTON_NAME: () => DEFAULT_BUTTON_NAME,
24
24
  DEFAULT_FORMULA_ATTRIBUTE: () => import_editor3.DEFAULT_FORMULA_ATTRIBUTE,
25
25
  DEFAULT_FORMULA_CLASS: () => import_editor3.DEFAULT_FORMULA_CLASS,
26
+ DEFAULT_MODEL_NAME: () => DEFAULT_MODEL_NAME,
26
27
  FORMULA_FLAG_ATTRIBUTE: () => import_editor3.FORMULA_FLAG_ATTRIBUTE,
27
28
  FormulaX: () => FormulaX,
28
29
  FormulaXCommand: () => FormulaXCommand,
@@ -133,8 +134,10 @@ function openFormulaXModal(input) {
133
134
 
134
135
  // src/plugin.ts
135
136
  var DEFAULT_BUTTON_NAME = "formulaX";
137
+ var DEFAULT_MODEL_NAME = "formulaX";
136
138
  function resolveOptions(options = {}) {
137
139
  return {
140
+ name: options.name ?? DEFAULT_MODEL_NAME,
138
141
  buttonName: options.buttonName ?? DEFAULT_BUTTON_NAME,
139
142
  toolbarText: options.toolbarText ?? "FormulaX",
140
143
  tooltip: options.tooltip ?? "Insert or edit formula",
@@ -169,7 +172,7 @@ var FormulaXCommand = class extends import_ckeditor5.Command {
169
172
  }
170
173
  execute() {
171
174
  const editor = this.editor;
172
- const selectedFormula = getSelectedFormulaModelElement(editor);
175
+ const selectedFormula = getSelectedFormulaModelElement(editor, this.options.name);
173
176
  const initialLatex = String(selectedFormula?.getAttribute("latex") ?? "");
174
177
  void openFormulaXModal({
175
178
  initialLatex,
@@ -177,7 +180,7 @@ var FormulaXCommand = class extends import_ckeditor5.Command {
177
180
  options: this.options
178
181
  }).then((payload) => {
179
182
  if (!payload) return;
180
- applyFormulaPayload(editor, selectedFormula, payload);
183
+ applyFormulaPayload(editor, selectedFormula, payload, this.options.name);
181
184
  editor.editing.view.focus();
182
185
  });
183
186
  }
@@ -192,8 +195,14 @@ var FormulaX = class extends import_ckeditor5.Plugin {
192
195
  init() {
193
196
  const editor = this.editor;
194
197
  const options = resolveOptions(editor.config.get("formulaX"));
198
+ if (hasRegisteredFormulaModelName(editor, options.name)) {
199
+ console.error(
200
+ `[FormulaX] CKEditor5 model name "${options.name}" is already registered. Pass a unique "name" option to avoid schema collisions.`
201
+ );
202
+ return;
203
+ }
195
204
  (0, import_editor2.ensureFormulaXModalStyles)(document);
196
- defineFormulaSchema(editor);
205
+ defineFormulaSchema(editor, options.name);
197
206
  defineFormulaConverters(editor, options);
198
207
  editor.editing.mapper.on(
199
208
  "viewToModelPosition",
@@ -214,7 +223,7 @@ var FormulaX = class extends import_ckeditor5.Plugin {
214
223
  });
215
224
  }
216
225
  };
217
- function applyFormulaPayload(editor, selectedFormula, payload) {
226
+ function applyFormulaPayload(editor, selectedFormula, payload, modelName) {
218
227
  editor.model.change((writer) => {
219
228
  if (selectedFormula) {
220
229
  if (!payload.latex.trim()) {
@@ -225,14 +234,30 @@ function applyFormulaPayload(editor, selectedFormula, payload) {
225
234
  return;
226
235
  }
227
236
  if (!payload.latex.trim()) return;
228
- const formula = writer.createElement("formulaX", {
237
+ const formula = writer.createElement(modelName, {
229
238
  latex: payload.latex
230
239
  });
231
240
  editor.model.insertObject(formula, null, null, { setSelection: "after" });
232
241
  });
233
242
  }
234
- function defineFormulaSchema(editor) {
235
- editor.model.schema.register("formulaX", {
243
+ function hasRegisteredFormulaModelName(editor, modelName) {
244
+ const schema = editor?.model?.schema;
245
+ if (!schema) {
246
+ return false;
247
+ }
248
+ if (typeof schema.isRegistered === "function") {
249
+ return Boolean(schema.isRegistered(modelName));
250
+ }
251
+ if (typeof schema.getDefinition === "function") {
252
+ return Boolean(schema.getDefinition(modelName));
253
+ }
254
+ if (schema._sourceDefinitions?.has) {
255
+ return Boolean(schema._sourceDefinitions.has(modelName));
256
+ }
257
+ return Boolean(schema._definitions?.[modelName]);
258
+ }
259
+ function defineFormulaSchema(editor, modelName) {
260
+ editor.model.schema.register(modelName, {
236
261
  allowWhere: "$text",
237
262
  isInline: true,
238
263
  isObject: true,
@@ -247,25 +272,25 @@ function defineFormulaConverters(editor, options) {
247
272
  [import_editor2.FORMULA_FLAG_ATTRIBUTE]: true
248
273
  }
249
274
  },
250
- model: (viewElement, { writer }) => writer.createElement("formulaX", {
275
+ model: (viewElement, { writer }) => writer.createElement(options.name, {
251
276
  latex: readFormulaLatexFromView(viewElement, options)
252
277
  })
253
278
  });
254
279
  editor.conversion.for("dataDowncast").elementToElement({
255
- model: createFormulaConverterModelDefinition(),
280
+ model: createFormulaConverterModelDefinition(options.name),
256
281
  view: (modelElement, { writer }) => createFormulaRawElement(writer, modelElement, options)
257
282
  });
258
283
  editor.conversion.for("editingDowncast").elementToElement({
259
- model: createFormulaConverterModelDefinition(),
284
+ model: createFormulaConverterModelDefinition(options.name),
260
285
  view: (modelElement, { writer }) => {
261
286
  const widgetElement = createFormulaWidgetElement(writer, modelElement, options, editor);
262
287
  return (0, import_ckeditor5.toWidget)(widgetElement, writer, { label: "FormulaX formula" });
263
288
  }
264
289
  });
265
290
  }
266
- function createFormulaConverterModelDefinition() {
291
+ function createFormulaConverterModelDefinition(modelName) {
267
292
  return {
268
- name: "formulaX",
293
+ name: modelName,
269
294
  attributes: ["latex"]
270
295
  };
271
296
  }
@@ -347,9 +372,9 @@ function extractInnerHtml(markup) {
347
372
  wrapper.innerHTML = markup;
348
373
  return wrapper.firstElementChild?.innerHTML ?? "";
349
374
  }
350
- function getSelectedFormulaModelElement(editor) {
375
+ function getSelectedFormulaModelElement(editor, modelName) {
351
376
  const selectedElement = editor.model.document.selection.getSelectedElement();
352
- return selectedElement?.is?.("element", "formulaX") ? selectedElement : null;
377
+ return selectedElement?.is?.("element", modelName) ? selectedElement : null;
353
378
  }
354
379
  function isFormulaWidgetView(node) {
355
380
  return Boolean(node?.is?.("element") && node.hasAttribute?.(import_editor2.FORMULA_FLAG_ATTRIBUTE));
@@ -425,6 +450,7 @@ function renderFormulaSvgMarkup(latex, options) {
425
450
  DEFAULT_BUTTON_NAME,
426
451
  DEFAULT_FORMULA_ATTRIBUTE,
427
452
  DEFAULT_FORMULA_CLASS,
453
+ DEFAULT_MODEL_NAME,
428
454
  FORMULA_FLAG_ATTRIBUTE,
429
455
  FormulaX,
430
456
  FormulaXCommand,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/plugin.ts","../src/modal.ts"],"sourcesContent":["export {\n DEFAULT_FORMULA_ATTRIBUTE,\n DEFAULT_FORMULA_CLASS,\n FORMULA_FLAG_ATTRIBUTE,\n} from '@formulaxjs/editor';\n\nexport {\n DEFAULT_BUTTON_NAME,\n FormulaX,\n FormulaXCommand,\n resolveOptions,\n} from './plugin';\n\nexport type {\n FormulaXCKEditor5Options,\n FormulaXPayload,\n RequiredFormulaXCKEditor5Options,\n} from './types';\n\nexport { openFormulaXModal } from './modal';\n\nexport { FormulaX as default } from './plugin';\n","import {\n ButtonView,\n Command,\n Plugin,\n Widget,\n toWidget,\n viewToModelPositionOutsideModelElement,\n} from 'ckeditor5';\nimport {\n DEFAULT_FORMULA_ATTRIBUTE,\n DEFAULT_FORMULA_CLASS,\n FORMULA_FLAG_ATTRIBUTE,\n createFormulaMarkup,\n ensureFormulaXModalStyles,\n mountFormulaXKityEditor,\n} from '@formulaxjs/editor';\nimport { openFormulaXModal } from './modal';\nimport type {\n FormulaXCKEditor5Options,\n FormulaXPayload,\n RequiredFormulaXCKEditor5Options,\n} from './types';\n\nconst DEFAULT_BUTTON_NAME = 'formulaX';\n\nexport { DEFAULT_BUTTON_NAME };\n\nexport function resolveOptions(options: FormulaXCKEditor5Options = {}): RequiredFormulaXCKEditor5Options {\n return {\n buttonName: options.buttonName ?? DEFAULT_BUTTON_NAME,\n toolbarText: options.toolbarText ?? 'FormulaX',\n tooltip: options.tooltip ?? 'Insert or edit formula',\n cursorStyle: options.cursorStyle ?? 'pointer',\n formulaClassName: options.formulaClassName ?? DEFAULT_FORMULA_CLASS,\n formulaAttributeName: options.formulaAttributeName ?? DEFAULT_FORMULA_ATTRIBUTE,\n modal: {\n title: options.modal?.title ?? 'FormulaX Editor',\n insertText: options.modal?.insertText ?? 'Insert',\n updateText: options.modal?.updateText ?? 'Update',\n cancelText: options.modal?.cancelText ?? 'Cancel',\n closeOnBackdrop: options.modal?.closeOnBackdrop ?? true,\n },\n editor: {\n height: options.editor?.height ?? '100%',\n autofocus: options.editor?.autofocus ?? true,\n assets: options.editor?.assets ?? {},\n render: {\n fontsize: options.editor?.render?.fontsize ?? 40,\n },\n },\n };\n}\n\nexport class FormulaXCommand extends Command {\n private readonly options: RequiredFormulaXCKEditor5Options;\n\n constructor(editor: unknown, options: RequiredFormulaXCKEditor5Options) {\n super(editor as any);\n this.options = options;\n }\n\n override refresh(): void {\n this.isEnabled = true;\n }\n\n override execute(): void {\n const editor = this.editor as any;\n const selectedFormula = getSelectedFormulaModelElement(editor);\n const initialLatex = String(selectedFormula?.getAttribute('latex') ?? '');\n\n void openFormulaXModal({\n initialLatex,\n isUpdate: Boolean(selectedFormula),\n options: this.options,\n }).then((payload) => {\n if (!payload) return;\n applyFormulaPayload(editor, selectedFormula, payload);\n editor.editing.view.focus();\n });\n }\n}\n\nexport class FormulaX extends Plugin {\n static get pluginName(): string {\n return 'FormulaX';\n }\n\n static get requires(): readonly [typeof Widget] {\n return [Widget];\n }\n\n init(): void {\n const editor = this.editor as any;\n const options = resolveOptions(editor.config.get('formulaX') as FormulaXCKEditor5Options | undefined);\n\n ensureFormulaXModalStyles(document);\n defineFormulaSchema(editor);\n defineFormulaConverters(editor, options);\n editor.editing.mapper.on(\n 'viewToModelPosition',\n viewToModelPositionOutsideModelElement(editor.model, isFormulaWidgetView),\n );\n\n const command = new FormulaXCommand(editor, options);\n editor.commands.add(options.buttonName, command);\n\n editor.ui.componentFactory.add(options.buttonName, (locale: unknown) => {\n const button = new ButtonView(locale as any);\n\n button.set({\n label: options.toolbarText,\n tooltip: options.tooltip,\n withText: true,\n });\n\n button.bind('isEnabled').to(command, 'isEnabled');\n this.listenTo(button, 'execute', () => editor.execute(options.buttonName));\n\n return button;\n });\n }\n}\n\nexport default FormulaX;\n\nfunction applyFormulaPayload(editor: any, selectedFormula: any, payload: FormulaXPayload): void {\n editor.model.change((writer: any) => {\n if (selectedFormula) {\n if (!payload.latex.trim()) {\n writer.remove(selectedFormula);\n return;\n }\n\n writer.setAttribute('latex', payload.latex, selectedFormula);\n return;\n }\n\n if (!payload.latex.trim()) return;\n\n const formula = writer.createElement('formulaX', {\n latex: payload.latex,\n });\n\n editor.model.insertObject(formula, null, null, { setSelection: 'after' });\n });\n}\n\nfunction defineFormulaSchema(editor: any): void {\n editor.model.schema.register('formulaX', {\n allowWhere: '$text',\n isInline: true,\n isObject: true,\n allowAttributes: ['latex'],\n });\n}\n\nfunction defineFormulaConverters(editor: any, options: RequiredFormulaXCKEditor5Options): void {\n editor.conversion.for('upcast').elementToElement({\n view: {\n name: 'span',\n attributes: {\n [FORMULA_FLAG_ATTRIBUTE]: true,\n },\n },\n model: (viewElement: any, { writer }: any) => writer.createElement('formulaX', {\n latex: readFormulaLatexFromView(viewElement, options),\n }),\n });\n\n editor.conversion.for('dataDowncast').elementToElement({\n model: createFormulaConverterModelDefinition(),\n view: (modelElement: any, { writer }: any) => createFormulaRawElement(writer, modelElement, options),\n });\n\n editor.conversion.for('editingDowncast').elementToElement({\n model: createFormulaConverterModelDefinition(),\n view: (modelElement: any, { writer }: any) => {\n const widgetElement = createFormulaWidgetElement(writer, modelElement, options, editor);\n return toWidget(widgetElement, writer, { label: 'FormulaX formula' });\n },\n });\n}\n\nfunction createFormulaConverterModelDefinition(): {\n name: string;\n attributes: string[];\n} {\n return {\n name: 'formulaX',\n attributes: ['latex'],\n };\n}\n\nfunction createFormulaRawElement(\n writer: any,\n modelElement: any,\n options: RequiredFormulaXCKEditor5Options,\n): any {\n const latex = String(modelElement.getAttribute('latex') ?? '');\n\n const element = writer.createContainerElement(\n 'span',\n createFormulaViewAttributes(latex, options),\n );\n\n writer.insert(\n writer.createPositionAt(element, 0),\n writer.createText(latex || '\\\\square'),\n );\n\n return element;\n}\n\nfunction createFormulaWidgetElement(\n writer: any,\n modelElement: any,\n options: RequiredFormulaXCKEditor5Options,\n editor: any,\n): any {\n const latex = String(modelElement.getAttribute('latex') ?? '');\n const widgetElement = writer.createContainerElement(\n 'span',\n createFormulaViewAttributes(latex, options),\n );\n const contentElement = writer.createRawElement(\n 'span',\n {\n class: `${options.formulaClassName}__content`,\n 'aria-hidden': 'true',\n },\n (domElement: HTMLElement) => {\n domElement.innerHTML = createFormulaFallbackMarkup(latex, options);\n void renderFormulaIntoElement(domElement, latex, options);\n bindFormulaWidgetDomEvents(domElement, editor, modelElement, options.buttonName);\n },\n );\n\n writer.insert(writer.createPositionAt(widgetElement, 0), contentElement);\n\n return widgetElement;\n}\n\nfunction createFormulaViewAttributes(\n latex: string,\n options: RequiredFormulaXCKEditor5Options,\n): Record<string, string> {\n return {\n class: options.formulaClassName,\n [FORMULA_FLAG_ATTRIBUTE]: 'true',\n [options.formulaAttributeName]: latex,\n 'data-latex': latex,\n contenteditable: 'false',\n role: 'button',\n style: `cursor: ${options.cursorStyle}`,\n tabindex: '0',\n };\n}\n\nfunction bindFormulaWidgetDomEvents(\n domElement: HTMLElement,\n editor: any,\n modelElement: any,\n commandName: string,\n): void {\n domElement.onclick = (event) => {\n event.preventDefault();\n selectFormulaModelElement(editor, modelElement);\n };\n\n domElement.ondblclick = (event) => {\n event.preventDefault();\n event.stopPropagation();\n selectFormulaModelElement(editor, modelElement);\n editor.execute(commandName);\n };\n}\n\nfunction selectFormulaModelElement(editor: any, modelElement: any): void {\n if (!modelElement?.is?.('element', 'formulaX')) {\n return;\n }\n\n editor.editing.view.focus();\n editor.model.change((writer: any) => {\n writer.setSelection(modelElement, 'on');\n });\n}\n\nfunction createFormulaFallbackMarkup(\n latex: string,\n options: RequiredFormulaXCKEditor5Options,\n): string {\n const markup = createFormulaMarkup(latex, {\n attributeName: options.formulaAttributeName,\n className: options.formulaClassName,\n });\n return extractInnerHtml(markup);\n}\n\nfunction extractInnerHtml(markup: string): string {\n const wrapper = document.createElement('span');\n wrapper.innerHTML = markup;\n return wrapper.firstElementChild?.innerHTML ?? '';\n}\n\nfunction getSelectedFormulaModelElement(editor: any): any | null {\n const selectedElement = editor.model.document.selection.getSelectedElement();\n return selectedElement?.is?.('element', 'formulaX') ? selectedElement : null;\n}\n\nfunction isFormulaWidgetView(node: any): boolean {\n return Boolean(node?.is?.('element') && node.hasAttribute?.(FORMULA_FLAG_ATTRIBUTE));\n}\n\nfunction readFormulaLatexFromView(viewElement: any, options: RequiredFormulaXCKEditor5Options): string {\n return String(\n viewElement.getAttribute(options.formulaAttributeName)\n ?? viewElement.getAttribute('data-latex')\n ?? '',\n );\n}\n\nconst formulaRenderCache = new Map<string, Promise<string>>();\n\nasync function renderFormulaIntoElement(\n domElement: HTMLElement,\n latex: string,\n options: RequiredFormulaXCKEditor5Options,\n): Promise<void> {\n const trimmedLatex = latex.trim();\n const renderToken = `${trimmedLatex}::${Date.now()}::${Math.random().toString(36).slice(2, 8)}`;\n domElement.dataset.renderToken = renderToken;\n\n if (!trimmedLatex) {\n return;\n }\n\n try {\n const markup = await renderFormulaSvgMarkup(trimmedLatex, options);\n if (domElement.dataset.renderToken !== renderToken) {\n return;\n }\n\n domElement.innerHTML = markup;\n } catch (error) {\n if (domElement.dataset.renderToken !== renderToken) {\n return;\n }\n\n console.error('[FormulaX] Failed to render CKEditor5 formula widget:', error);\n }\n}\n\nfunction renderFormulaSvgMarkup(\n latex: string,\n options: RequiredFormulaXCKEditor5Options,\n): Promise<string> {\n const cached = formulaRenderCache.get(latex);\n if (cached) {\n return cached;\n }\n\n const pending = (async () => {\n const host = document.createElement('div');\n host.style.position = 'fixed';\n host.style.left = '-100000px';\n host.style.top = '0';\n host.style.width = '1px';\n host.style.height = '1px';\n host.style.opacity = '0';\n host.style.pointerEvents = 'none';\n host.setAttribute('aria-hidden', 'true');\n document.body.appendChild(host);\n\n const mounted = mountFormulaXKityEditor(host, {\n initialLatex: latex,\n height: options.editor.height,\n autofocus: false,\n assets: options.editor.assets,\n render: {\n fontsize: options.editor.render.fontsize,\n },\n });\n\n try {\n return await mounted.getRenderHtml();\n } finally {\n mounted.destroy();\n host.remove();\n }\n })();\n\n formulaRenderCache.set(latex, pending);\n pending.catch(() => {\n if (formulaRenderCache.get(latex) === pending) {\n formulaRenderCache.delete(latex);\n }\n });\n return pending;\n}\n","import {\n ensureFormulaXModalStyles,\n escapeAttribute,\n escapeHtml,\n mountFormulaXKityEditor,\n} from '@formulaxjs/editor';\nimport type { FormulaXPayload, RequiredFormulaXCKEditor5Options } from './types';\n\nexport interface OpenFormulaXModalInput {\n initialLatex: string;\n isUpdate: boolean;\n options: RequiredFormulaXCKEditor5Options;\n}\n\nexport function openFormulaXModal(input: OpenFormulaXModalInput): Promise<FormulaXPayload | null> {\n ensureFormulaXModalStyles(document);\n\n const root = document.createElement('div');\n root.className = 'fx-formula-modal-root';\n root.setAttribute('data-formulax-modal', 'true');\n\n const submitText = input.isUpdate ? input.options.modal.updateText : input.options.modal.insertText;\n\n root.innerHTML = `\n <div class=\"fx-formula-modal-backdrop\" data-action=\"backdrop\"></div>\n <div class=\"fx-formula-modal\" role=\"dialog\" aria-modal=\"true\" aria-label=\"${escapeAttribute(input.options.modal.title)}\">\n <header class=\"fx-formula-modal__header\">\n <h2 class=\"fx-formula-modal__title\">${escapeHtml(input.options.modal.title)}</h2>\n <button class=\"fx-formula-modal__close\" type=\"button\" data-action=\"close\" aria-label=\"Close\">×</button>\n </header>\n <section class=\"fx-formula-modal__body\">\n <div class=\"fx-formula-editor-host\"></div>\n </section>\n <footer class=\"fx-formula-modal__footer\">\n <button class=\"fx-formula-modal__button\" type=\"button\" data-action=\"cancel\">${escapeHtml(input.options.modal.cancelText)}</button>\n <button class=\"fx-formula-modal__button fx-formula-modal__button--primary\" type=\"button\" data-action=\"submit\">${escapeHtml(submitText)}</button>\n </footer>\n </div>\n `;\n\n document.body.appendChild(root);\n document.body.classList.add('fx-formula-modal-open');\n\n const host = root.querySelector<HTMLElement>('.fx-formula-editor-host');\n if (!host) {\n root.remove();\n return Promise.reject(new Error('[FormulaX] CKEditor 5 modal host not found.'));\n }\n\n const mounted = mountFormulaXKityEditor(host, {\n initialLatex: input.initialLatex,\n height: input.options.editor.height,\n autofocus: input.options.editor.autofocus,\n assets: input.options.editor.assets,\n render: {\n fontsize: input.options.editor.render.fontsize,\n },\n });\n let closed = false;\n\n return new Promise((resolve) => {\n const close = (payload: FormulaXPayload | null): void => {\n if (closed) return;\n closed = true;\n\n mounted.destroy();\n root.removeEventListener('click', onClick);\n document.removeEventListener('keydown', onKeydown, true);\n root.remove();\n document.body.classList.remove('fx-formula-modal-open');\n resolve(payload);\n };\n\n const submit = async (): Promise<void> => {\n try {\n const latex = await mounted.getLatex();\n close({ latex });\n } catch (error) {\n host.innerHTML = `\n <div class=\"fx-formula-editor-error\">\n Failed to read FormulaX editor content.\n <pre>${escapeHtml(error instanceof Error ? error.message : String(error))}</pre>\n </div>\n `;\n }\n };\n\n function onClick(event: MouseEvent): void {\n const action = (event.target as HTMLElement).closest<HTMLElement>('[data-action]')?.dataset.action;\n if (!action) return;\n\n if (action === 'submit') {\n void submit();\n return;\n }\n\n if (action === 'cancel' || action === 'close') {\n close(null);\n return;\n }\n\n if (action === 'backdrop' && input.options.modal.closeOnBackdrop) {\n close(null);\n }\n }\n\n function onKeydown(event: KeyboardEvent): void {\n if (event.key === 'Escape') {\n event.preventDefault();\n close(null);\n }\n }\n\n root.addEventListener('click', onClick);\n document.addEventListener('keydown', onKeydown, true);\n\n queueMicrotask(() => {\n mounted.root.focus();\n });\n });\n}\n"],"mappings":"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","names":["import_editor","import_editor"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/plugin.ts","../src/modal.ts"],"sourcesContent":["export {\n DEFAULT_FORMULA_ATTRIBUTE,\n DEFAULT_FORMULA_CLASS,\n FORMULA_FLAG_ATTRIBUTE,\n} from '@formulaxjs/editor';\n\nexport {\n DEFAULT_BUTTON_NAME,\n DEFAULT_MODEL_NAME,\n FormulaX,\n FormulaXCommand,\n resolveOptions,\n} from './plugin';\n\nexport type {\n FormulaXCKEditor5Options,\n FormulaXPayload,\n RequiredFormulaXCKEditor5Options,\n} from './types';\n\nexport { openFormulaXModal } from './modal';\n\nexport { FormulaX as default } from './plugin';\n","import {\n ButtonView,\n Command,\n Plugin,\n Widget,\n toWidget,\n viewToModelPositionOutsideModelElement,\n} from 'ckeditor5';\nimport {\n DEFAULT_FORMULA_ATTRIBUTE,\n DEFAULT_FORMULA_CLASS,\n FORMULA_FLAG_ATTRIBUTE,\n createFormulaMarkup,\n ensureFormulaXModalStyles,\n mountFormulaXKityEditor,\n} from '@formulaxjs/editor';\nimport { openFormulaXModal } from './modal';\nimport type {\n FormulaXCKEditor5Options,\n FormulaXPayload,\n RequiredFormulaXCKEditor5Options,\n} from './types';\n\nconst DEFAULT_BUTTON_NAME = 'formulaX';\nconst DEFAULT_MODEL_NAME = 'formulaX';\n\nexport { DEFAULT_BUTTON_NAME, DEFAULT_MODEL_NAME };\n\nexport function resolveOptions(options: FormulaXCKEditor5Options = {}): RequiredFormulaXCKEditor5Options {\n return {\n name: options.name ?? DEFAULT_MODEL_NAME,\n buttonName: options.buttonName ?? DEFAULT_BUTTON_NAME,\n toolbarText: options.toolbarText ?? 'FormulaX',\n tooltip: options.tooltip ?? 'Insert or edit formula',\n cursorStyle: options.cursorStyle ?? 'pointer',\n formulaClassName: options.formulaClassName ?? DEFAULT_FORMULA_CLASS,\n formulaAttributeName: options.formulaAttributeName ?? DEFAULT_FORMULA_ATTRIBUTE,\n modal: {\n title: options.modal?.title ?? 'FormulaX Editor',\n insertText: options.modal?.insertText ?? 'Insert',\n updateText: options.modal?.updateText ?? 'Update',\n cancelText: options.modal?.cancelText ?? 'Cancel',\n closeOnBackdrop: options.modal?.closeOnBackdrop ?? true,\n },\n editor: {\n height: options.editor?.height ?? '100%',\n autofocus: options.editor?.autofocus ?? true,\n assets: options.editor?.assets ?? {},\n render: {\n fontsize: options.editor?.render?.fontsize ?? 40,\n },\n },\n };\n}\n\nexport class FormulaXCommand extends Command {\n private readonly options: RequiredFormulaXCKEditor5Options;\n\n constructor(editor: unknown, options: RequiredFormulaXCKEditor5Options) {\n super(editor as any);\n this.options = options;\n }\n\n override refresh(): void {\n this.isEnabled = true;\n }\n\n override execute(): void {\n const editor = this.editor as any;\n const selectedFormula = getSelectedFormulaModelElement(editor, this.options.name);\n const initialLatex = String(selectedFormula?.getAttribute('latex') ?? '');\n\n void openFormulaXModal({\n initialLatex,\n isUpdate: Boolean(selectedFormula),\n options: this.options,\n }).then((payload) => {\n if (!payload) return;\n applyFormulaPayload(editor, selectedFormula, payload, this.options.name);\n editor.editing.view.focus();\n });\n }\n}\n\nexport class FormulaX extends Plugin {\n static get pluginName(): string {\n return 'FormulaX';\n }\n\n static get requires(): readonly [typeof Widget] {\n return [Widget];\n }\n\n init(): void {\n const editor = this.editor as any;\n const options = resolveOptions(editor.config.get('formulaX') as FormulaXCKEditor5Options | undefined);\n\n if (hasRegisteredFormulaModelName(editor, options.name)) {\n console.error(\n `[FormulaX] CKEditor5 model name \"${options.name}\" is already registered. ` +\n 'Pass a unique \"name\" option to avoid schema collisions.',\n );\n return;\n }\n\n ensureFormulaXModalStyles(document);\n defineFormulaSchema(editor, options.name);\n defineFormulaConverters(editor, options);\n editor.editing.mapper.on(\n 'viewToModelPosition',\n viewToModelPositionOutsideModelElement(editor.model, isFormulaWidgetView),\n );\n\n const command = new FormulaXCommand(editor, options);\n editor.commands.add(options.buttonName, command);\n\n editor.ui.componentFactory.add(options.buttonName, (locale: unknown) => {\n const button = new ButtonView(locale as any);\n\n button.set({\n label: options.toolbarText,\n tooltip: options.tooltip,\n withText: true,\n });\n\n button.bind('isEnabled').to(command, 'isEnabled');\n this.listenTo(button, 'execute', () => editor.execute(options.buttonName));\n\n return button;\n });\n }\n}\n\nexport default FormulaX;\n\nfunction applyFormulaPayload(\n editor: any,\n selectedFormula: any,\n payload: FormulaXPayload,\n modelName: string,\n): void {\n editor.model.change((writer: any) => {\n if (selectedFormula) {\n if (!payload.latex.trim()) {\n writer.remove(selectedFormula);\n return;\n }\n\n writer.setAttribute('latex', payload.latex, selectedFormula);\n return;\n }\n\n if (!payload.latex.trim()) return;\n\n const formula = writer.createElement(modelName, {\n latex: payload.latex,\n });\n\n editor.model.insertObject(formula, null, null, { setSelection: 'after' });\n });\n}\n\nfunction hasRegisteredFormulaModelName(editor: any, modelName: string): boolean {\n const schema = editor?.model?.schema;\n\n if (!schema) {\n return false;\n }\n\n if (typeof schema.isRegistered === 'function') {\n return Boolean(schema.isRegistered(modelName));\n }\n\n if (typeof schema.getDefinition === 'function') {\n return Boolean(schema.getDefinition(modelName));\n }\n\n if (schema._sourceDefinitions?.has) {\n return Boolean(schema._sourceDefinitions.has(modelName));\n }\n\n return Boolean(schema._definitions?.[modelName]);\n}\n\nfunction defineFormulaSchema(editor: any, modelName: string): void {\n editor.model.schema.register(modelName, {\n allowWhere: '$text',\n isInline: true,\n isObject: true,\n allowAttributes: ['latex'],\n });\n}\n\nfunction defineFormulaConverters(editor: any, options: RequiredFormulaXCKEditor5Options): void {\n editor.conversion.for('upcast').elementToElement({\n view: {\n name: 'span',\n attributes: {\n [FORMULA_FLAG_ATTRIBUTE]: true,\n },\n },\n model: (viewElement: any, { writer }: any) => writer.createElement(options.name, {\n latex: readFormulaLatexFromView(viewElement, options),\n }),\n });\n\n editor.conversion.for('dataDowncast').elementToElement({\n model: createFormulaConverterModelDefinition(options.name),\n view: (modelElement: any, { writer }: any) => createFormulaRawElement(writer, modelElement, options),\n });\n\n editor.conversion.for('editingDowncast').elementToElement({\n model: createFormulaConverterModelDefinition(options.name),\n view: (modelElement: any, { writer }: any) => {\n const widgetElement = createFormulaWidgetElement(writer, modelElement, options, editor);\n return toWidget(widgetElement, writer, { label: 'FormulaX formula' });\n },\n });\n}\n\nfunction createFormulaConverterModelDefinition(modelName: string): {\n name: string;\n attributes: string[];\n} {\n return {\n name: modelName,\n attributes: ['latex'],\n };\n}\n\nfunction createFormulaRawElement(\n writer: any,\n modelElement: any,\n options: RequiredFormulaXCKEditor5Options,\n): any {\n const latex = String(modelElement.getAttribute('latex') ?? '');\n\n const element = writer.createContainerElement(\n 'span',\n createFormulaViewAttributes(latex, options),\n );\n\n writer.insert(\n writer.createPositionAt(element, 0),\n writer.createText(latex || '\\\\square'),\n );\n\n return element;\n}\n\nfunction createFormulaWidgetElement(\n writer: any,\n modelElement: any,\n options: RequiredFormulaXCKEditor5Options,\n editor: any,\n): any {\n const latex = String(modelElement.getAttribute('latex') ?? '');\n const widgetElement = writer.createContainerElement(\n 'span',\n createFormulaViewAttributes(latex, options),\n );\n const contentElement = writer.createRawElement(\n 'span',\n {\n class: `${options.formulaClassName}__content`,\n 'aria-hidden': 'true',\n },\n (domElement: HTMLElement) => {\n domElement.innerHTML = createFormulaFallbackMarkup(latex, options);\n void renderFormulaIntoElement(domElement, latex, options);\n bindFormulaWidgetDomEvents(domElement, editor, modelElement, options.buttonName);\n },\n );\n\n writer.insert(writer.createPositionAt(widgetElement, 0), contentElement);\n\n return widgetElement;\n}\n\nfunction createFormulaViewAttributes(\n latex: string,\n options: RequiredFormulaXCKEditor5Options,\n): Record<string, string> {\n return {\n class: options.formulaClassName,\n [FORMULA_FLAG_ATTRIBUTE]: 'true',\n [options.formulaAttributeName]: latex,\n 'data-latex': latex,\n contenteditable: 'false',\n role: 'button',\n style: `cursor: ${options.cursorStyle}`,\n tabindex: '0',\n };\n}\n\nfunction bindFormulaWidgetDomEvents(\n domElement: HTMLElement,\n editor: any,\n modelElement: any,\n commandName: string,\n): void {\n domElement.onclick = (event) => {\n event.preventDefault();\n selectFormulaModelElement(editor, modelElement);\n };\n\n domElement.ondblclick = (event) => {\n event.preventDefault();\n event.stopPropagation();\n selectFormulaModelElement(editor, modelElement);\n editor.execute(commandName);\n };\n}\n\nfunction selectFormulaModelElement(editor: any, modelElement: any): void {\n if (!modelElement?.is?.('element', 'formulaX')) {\n return;\n }\n\n editor.editing.view.focus();\n editor.model.change((writer: any) => {\n writer.setSelection(modelElement, 'on');\n });\n}\n\nfunction createFormulaFallbackMarkup(\n latex: string,\n options: RequiredFormulaXCKEditor5Options,\n): string {\n const markup = createFormulaMarkup(latex, {\n attributeName: options.formulaAttributeName,\n className: options.formulaClassName,\n });\n return extractInnerHtml(markup);\n}\n\nfunction extractInnerHtml(markup: string): string {\n const wrapper = document.createElement('span');\n wrapper.innerHTML = markup;\n return wrapper.firstElementChild?.innerHTML ?? '';\n}\n\nfunction getSelectedFormulaModelElement(editor: any, modelName: string): any | null {\n const selectedElement = editor.model.document.selection.getSelectedElement();\n return selectedElement?.is?.('element', modelName) ? selectedElement : null;\n}\n\nfunction isFormulaWidgetView(node: any): boolean {\n return Boolean(node?.is?.('element') && node.hasAttribute?.(FORMULA_FLAG_ATTRIBUTE));\n}\n\nfunction readFormulaLatexFromView(viewElement: any, options: RequiredFormulaXCKEditor5Options): string {\n return String(\n viewElement.getAttribute(options.formulaAttributeName)\n ?? viewElement.getAttribute('data-latex')\n ?? '',\n );\n}\n\nconst formulaRenderCache = new Map<string, Promise<string>>();\n\nasync function renderFormulaIntoElement(\n domElement: HTMLElement,\n latex: string,\n options: RequiredFormulaXCKEditor5Options,\n): Promise<void> {\n const trimmedLatex = latex.trim();\n const renderToken = `${trimmedLatex}::${Date.now()}::${Math.random().toString(36).slice(2, 8)}`;\n domElement.dataset.renderToken = renderToken;\n\n if (!trimmedLatex) {\n return;\n }\n\n try {\n const markup = await renderFormulaSvgMarkup(trimmedLatex, options);\n if (domElement.dataset.renderToken !== renderToken) {\n return;\n }\n\n domElement.innerHTML = markup;\n } catch (error) {\n if (domElement.dataset.renderToken !== renderToken) {\n return;\n }\n\n console.error('[FormulaX] Failed to render CKEditor5 formula widget:', error);\n }\n}\n\nfunction renderFormulaSvgMarkup(\n latex: string,\n options: RequiredFormulaXCKEditor5Options,\n): Promise<string> {\n const cached = formulaRenderCache.get(latex);\n if (cached) {\n return cached;\n }\n\n const pending = (async () => {\n const host = document.createElement('div');\n host.style.position = 'fixed';\n host.style.left = '-100000px';\n host.style.top = '0';\n host.style.width = '1px';\n host.style.height = '1px';\n host.style.opacity = '0';\n host.style.pointerEvents = 'none';\n host.setAttribute('aria-hidden', 'true');\n document.body.appendChild(host);\n\n const mounted = mountFormulaXKityEditor(host, {\n initialLatex: latex,\n height: options.editor.height,\n autofocus: false,\n assets: options.editor.assets,\n render: {\n fontsize: options.editor.render.fontsize,\n },\n });\n\n try {\n return await mounted.getRenderHtml();\n } finally {\n mounted.destroy();\n host.remove();\n }\n })();\n\n formulaRenderCache.set(latex, pending);\n pending.catch(() => {\n if (formulaRenderCache.get(latex) === pending) {\n formulaRenderCache.delete(latex);\n }\n });\n return pending;\n}\n","import {\n ensureFormulaXModalStyles,\n escapeAttribute,\n escapeHtml,\n mountFormulaXKityEditor,\n} from '@formulaxjs/editor';\nimport type { FormulaXPayload, RequiredFormulaXCKEditor5Options } from './types';\n\nexport interface OpenFormulaXModalInput {\n initialLatex: string;\n isUpdate: boolean;\n options: RequiredFormulaXCKEditor5Options;\n}\n\nexport function openFormulaXModal(input: OpenFormulaXModalInput): Promise<FormulaXPayload | null> {\n ensureFormulaXModalStyles(document);\n\n const root = document.createElement('div');\n root.className = 'fx-formula-modal-root';\n root.setAttribute('data-formulax-modal', 'true');\n\n const submitText = input.isUpdate ? input.options.modal.updateText : input.options.modal.insertText;\n\n root.innerHTML = `\n <div class=\"fx-formula-modal-backdrop\" data-action=\"backdrop\"></div>\n <div class=\"fx-formula-modal\" role=\"dialog\" aria-modal=\"true\" aria-label=\"${escapeAttribute(input.options.modal.title)}\">\n <header class=\"fx-formula-modal__header\">\n <h2 class=\"fx-formula-modal__title\">${escapeHtml(input.options.modal.title)}</h2>\n <button class=\"fx-formula-modal__close\" type=\"button\" data-action=\"close\" aria-label=\"Close\">×</button>\n </header>\n <section class=\"fx-formula-modal__body\">\n <div class=\"fx-formula-editor-host\"></div>\n </section>\n <footer class=\"fx-formula-modal__footer\">\n <button class=\"fx-formula-modal__button\" type=\"button\" data-action=\"cancel\">${escapeHtml(input.options.modal.cancelText)}</button>\n <button class=\"fx-formula-modal__button fx-formula-modal__button--primary\" type=\"button\" data-action=\"submit\">${escapeHtml(submitText)}</button>\n </footer>\n </div>\n `;\n\n document.body.appendChild(root);\n document.body.classList.add('fx-formula-modal-open');\n\n const host = root.querySelector<HTMLElement>('.fx-formula-editor-host');\n if (!host) {\n root.remove();\n return Promise.reject(new Error('[FormulaX] CKEditor 5 modal host not found.'));\n }\n\n const mounted = mountFormulaXKityEditor(host, {\n initialLatex: input.initialLatex,\n height: input.options.editor.height,\n autofocus: input.options.editor.autofocus,\n assets: input.options.editor.assets,\n render: {\n fontsize: input.options.editor.render.fontsize,\n },\n });\n let closed = false;\n\n return new Promise((resolve) => {\n const close = (payload: FormulaXPayload | null): void => {\n if (closed) return;\n closed = true;\n\n mounted.destroy();\n root.removeEventListener('click', onClick);\n document.removeEventListener('keydown', onKeydown, true);\n root.remove();\n document.body.classList.remove('fx-formula-modal-open');\n resolve(payload);\n };\n\n const submit = async (): Promise<void> => {\n try {\n const latex = await mounted.getLatex();\n close({ latex });\n } catch (error) {\n host.innerHTML = `\n <div class=\"fx-formula-editor-error\">\n Failed to read FormulaX editor content.\n <pre>${escapeHtml(error instanceof Error ? error.message : String(error))}</pre>\n </div>\n `;\n }\n };\n\n function onClick(event: MouseEvent): void {\n const action = (event.target as HTMLElement).closest<HTMLElement>('[data-action]')?.dataset.action;\n if (!action) return;\n\n if (action === 'submit') {\n void submit();\n return;\n }\n\n if (action === 'cancel' || action === 'close') {\n close(null);\n return;\n }\n\n if (action === 'backdrop' && input.options.modal.closeOnBackdrop) {\n close(null);\n }\n }\n\n function onKeydown(event: KeyboardEvent): void {\n if (event.key === 'Escape') {\n event.preventDefault();\n close(null);\n }\n }\n\n root.addEventListener('click', onClick);\n document.addEventListener('keydown', onKeydown, true);\n\n queueMicrotask(() => {\n mounted.root.focus();\n });\n });\n}\n"],"mappings":"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","names":["import_editor","import_editor"]}
@@ -19969,6 +19969,7 @@ var FormulaX = (() => {
19969
19969
  DEFAULT_BUTTON_NAME: () => DEFAULT_BUTTON_NAME,
19970
19970
  DEFAULT_FORMULA_ATTRIBUTE: () => DEFAULT_FORMULA_ATTRIBUTE,
19971
19971
  DEFAULT_FORMULA_CLASS: () => DEFAULT_FORMULA_CLASS,
19972
+ DEFAULT_MODEL_NAME: () => DEFAULT_MODEL_NAME,
19972
19973
  FORMULA_FLAG_ATTRIBUTE: () => FORMULA_FLAG_ATTRIBUTE,
19973
19974
  FormulaX: () => FormulaX,
19974
19975
  FormulaXCommand: () => FormulaXCommand,
@@ -20262,31 +20263,31 @@ var FormulaX = (() => {
20262
20263
  };
20263
20264
  var parseLatex = (input) => new LatexParser(input).parse();
20264
20265
 
20265
- // ../kity-assets/public/assets/images/toolbar/btn.png
20266
+ // ../kity-runtime/public/assets/images/toolbar/btn.png
20266
20267
  var btn_default = "./btn-5DANP6JY.png";
20267
20268
 
20268
- // ../kity-assets/public/assets/images/toolbar/other.png
20269
+ // ../kity-runtime/public/assets/images/toolbar/other.png
20269
20270
  var other_default = "./other-OMWJFGL5.png";
20270
20271
 
20271
- // ../kity-assets/public/assets/styles/editor.css?url
20272
+ // ../kity-runtime/public/assets/styles/editor.css?url
20272
20273
  var editor_default = "./editor-JT5KLVXX.css?url";
20273
20274
 
20274
- // ../kity-assets/public/resource/KF_AMS_BB.woff
20275
+ // ../kity-runtime/public/resource/KF_AMS_BB.woff
20275
20276
  var KF_AMS_BB_default = "./KF_AMS_BB-5QF7FUSO.woff";
20276
20277
 
20277
- // ../kity-assets/public/resource/KF_AMS_CAL.woff
20278
+ // ../kity-runtime/public/resource/KF_AMS_CAL.woff
20278
20279
  var KF_AMS_CAL_default = "./KF_AMS_CAL-NXRNLAZN.woff";
20279
20280
 
20280
- // ../kity-assets/public/resource/KF_AMS_FRAK.woff
20281
+ // ../kity-runtime/public/resource/KF_AMS_FRAK.woff
20281
20282
  var KF_AMS_FRAK_default = "./KF_AMS_FRAK-CO33WWN4.woff";
20282
20283
 
20283
- // ../kity-assets/public/resource/KF_AMS_MAIN.woff
20284
+ // ../kity-runtime/public/resource/KF_AMS_MAIN.woff
20284
20285
  var KF_AMS_MAIN_default = "./KF_AMS_MAIN-25QJVAWY.woff";
20285
20286
 
20286
- // ../kity-assets/public/resource/KF_AMS_ROMAN.woff
20287
+ // ../kity-runtime/public/resource/KF_AMS_ROMAN.woff
20287
20288
  var KF_AMS_ROMAN_default = "./KF_AMS_ROMAN-243BR7HH.woff";
20288
20289
 
20289
- // ../kity-assets/src/index.ts
20290
+ // ../kity-runtime/src/asset-manifest.ts
20290
20291
  var kityFontAssets = {
20291
20292
  KF_AMS_BB: KF_AMS_BB_default,
20292
20293
  KF_AMS_CAL: KF_AMS_CAL_default,
@@ -62003,8 +62004,10 @@ Original error: ${originalError.name}: ${originalError.message}` : "";
62003
62004
 
62004
62005
  // src/plugin.ts
62005
62006
  var DEFAULT_BUTTON_NAME = "formulaX";
62007
+ var DEFAULT_MODEL_NAME = "formulaX";
62006
62008
  function resolveOptions(options = {}) {
62007
62009
  return {
62010
+ name: options.name ?? DEFAULT_MODEL_NAME,
62008
62011
  buttonName: options.buttonName ?? DEFAULT_BUTTON_NAME,
62009
62012
  toolbarText: options.toolbarText ?? "FormulaX",
62010
62013
  tooltip: options.tooltip ?? "Insert or edit formula",
@@ -62039,7 +62042,7 @@ Original error: ${originalError.name}: ${originalError.message}` : "";
62039
62042
  }
62040
62043
  execute() {
62041
62044
  const editor = this.editor;
62042
- const selectedFormula = getSelectedFormulaModelElement(editor);
62045
+ const selectedFormula = getSelectedFormulaModelElement(editor, this.options.name);
62043
62046
  const initialLatex = String(selectedFormula?.getAttribute("latex") ?? "");
62044
62047
  void openFormulaXModal({
62045
62048
  initialLatex,
@@ -62047,7 +62050,7 @@ Original error: ${originalError.name}: ${originalError.message}` : "";
62047
62050
  options: this.options
62048
62051
  }).then((payload) => {
62049
62052
  if (!payload) return;
62050
- applyFormulaPayload(editor, selectedFormula, payload);
62053
+ applyFormulaPayload(editor, selectedFormula, payload, this.options.name);
62051
62054
  editor.editing.view.focus();
62052
62055
  });
62053
62056
  }
@@ -62062,8 +62065,14 @@ Original error: ${originalError.name}: ${originalError.message}` : "";
62062
62065
  init() {
62063
62066
  const editor = this.editor;
62064
62067
  const options = resolveOptions(editor.config.get("formulaX"));
62068
+ if (hasRegisteredFormulaModelName(editor, options.name)) {
62069
+ console.error(
62070
+ `[FormulaX] CKEditor5 model name "${options.name}" is already registered. Pass a unique "name" option to avoid schema collisions.`
62071
+ );
62072
+ return;
62073
+ }
62065
62074
  ensureFormulaXModalStyles(document);
62066
- defineFormulaSchema(editor);
62075
+ defineFormulaSchema(editor, options.name);
62067
62076
  defineFormulaConverters(editor, options);
62068
62077
  editor.editing.mapper.on(
62069
62078
  "viewToModelPosition",
@@ -62084,7 +62093,7 @@ Original error: ${originalError.name}: ${originalError.message}` : "";
62084
62093
  });
62085
62094
  }
62086
62095
  };
62087
- function applyFormulaPayload(editor, selectedFormula, payload) {
62096
+ function applyFormulaPayload(editor, selectedFormula, payload, modelName) {
62088
62097
  editor.model.change((writer) => {
62089
62098
  if (selectedFormula) {
62090
62099
  if (!payload.latex.trim()) {
@@ -62095,14 +62104,30 @@ Original error: ${originalError.name}: ${originalError.message}` : "";
62095
62104
  return;
62096
62105
  }
62097
62106
  if (!payload.latex.trim()) return;
62098
- const formula = writer.createElement("formulaX", {
62107
+ const formula = writer.createElement(modelName, {
62099
62108
  latex: payload.latex
62100
62109
  });
62101
62110
  editor.model.insertObject(formula, null, null, { setSelection: "after" });
62102
62111
  });
62103
62112
  }
62104
- function defineFormulaSchema(editor) {
62105
- editor.model.schema.register("formulaX", {
62113
+ function hasRegisteredFormulaModelName(editor, modelName) {
62114
+ const schema = editor?.model?.schema;
62115
+ if (!schema) {
62116
+ return false;
62117
+ }
62118
+ if (typeof schema.isRegistered === "function") {
62119
+ return Boolean(schema.isRegistered(modelName));
62120
+ }
62121
+ if (typeof schema.getDefinition === "function") {
62122
+ return Boolean(schema.getDefinition(modelName));
62123
+ }
62124
+ if (schema._sourceDefinitions?.has) {
62125
+ return Boolean(schema._sourceDefinitions.has(modelName));
62126
+ }
62127
+ return Boolean(schema._definitions?.[modelName]);
62128
+ }
62129
+ function defineFormulaSchema(editor, modelName) {
62130
+ editor.model.schema.register(modelName, {
62106
62131
  allowWhere: "$text",
62107
62132
  isInline: true,
62108
62133
  isObject: true,
@@ -62117,25 +62142,25 @@ Original error: ${originalError.name}: ${originalError.message}` : "";
62117
62142
  [FORMULA_FLAG_ATTRIBUTE]: true
62118
62143
  }
62119
62144
  },
62120
- model: (viewElement, { writer }) => writer.createElement("formulaX", {
62145
+ model: (viewElement, { writer }) => writer.createElement(options.name, {
62121
62146
  latex: readFormulaLatexFromView(viewElement, options)
62122
62147
  })
62123
62148
  });
62124
62149
  editor.conversion.for("dataDowncast").elementToElement({
62125
- model: createFormulaConverterModelDefinition(),
62150
+ model: createFormulaConverterModelDefinition(options.name),
62126
62151
  view: (modelElement, { writer }) => createFormulaRawElement(writer, modelElement, options)
62127
62152
  });
62128
62153
  editor.conversion.for("editingDowncast").elementToElement({
62129
- model: createFormulaConverterModelDefinition(),
62154
+ model: createFormulaConverterModelDefinition(options.name),
62130
62155
  view: (modelElement, { writer }) => {
62131
62156
  const widgetElement = createFormulaWidgetElement(writer, modelElement, options, editor);
62132
62157
  return toWidget(widgetElement, writer, { label: "FormulaX formula" });
62133
62158
  }
62134
62159
  });
62135
62160
  }
62136
- function createFormulaConverterModelDefinition() {
62161
+ function createFormulaConverterModelDefinition(modelName) {
62137
62162
  return {
62138
- name: "formulaX",
62163
+ name: modelName,
62139
62164
  attributes: ["latex"]
62140
62165
  };
62141
62166
  }
@@ -62217,9 +62242,9 @@ Original error: ${originalError.name}: ${originalError.message}` : "";
62217
62242
  wrapper.innerHTML = markup;
62218
62243
  return wrapper.firstElementChild?.innerHTML ?? "";
62219
62244
  }
62220
- function getSelectedFormulaModelElement(editor) {
62245
+ function getSelectedFormulaModelElement(editor, modelName) {
62221
62246
  const selectedElement = editor.model.document.selection.getSelectedElement();
62222
- return selectedElement?.is?.("element", "formulaX") ? selectedElement : null;
62247
+ return selectedElement?.is?.("element", modelName) ? selectedElement : null;
62223
62248
  }
62224
62249
  function isFormulaWidgetView(node) {
62225
62250
  return Boolean(node?.is?.("element") && node.hasAttribute?.(FORMULA_FLAG_ATTRIBUTE));