ckeditor5-phoenix 1.27.1 → 1.28.0
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/dist/hooks/editable.d.ts.map +1 -1
- package/dist/hooks/editor/editor.d.ts.map +1 -1
- package/dist/hooks/editor/utils/assign-editor-roots-to-config.d.ts +14 -0
- package/dist/hooks/editor/utils/assign-editor-roots-to-config.d.ts.map +1 -0
- package/dist/hooks/editor/utils/index.d.ts +1 -2
- package/dist/hooks/editor/utils/index.d.ts.map +1 -1
- package/dist/hooks/editor/utils/query-all-editor-editables.d.ts +1 -16
- package/dist/hooks/editor/utils/query-all-editor-editables.d.ts.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +244 -277
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/hooks/editable.test.ts +29 -0
- package/src/hooks/editable.ts +3 -1
- package/src/hooks/editor/editor.test.ts +94 -0
- package/src/hooks/editor/editor.ts +22 -42
- package/src/hooks/editor/plugins/sync-editor-with-phoenix.ts +1 -1
- package/src/hooks/editor/utils/assign-editor-roots-to-config.ts +58 -0
- package/src/hooks/editor/utils/index.ts +1 -2
- package/src/hooks/editor/utils/query-all-editor-editables.ts +12 -35
- package/test-utils/editor/create-editable-html-element.ts +5 -0
- package/test-utils/editor/create-editor-html-element.ts +5 -0
- package/dist/hooks/editor/utils/assign-initial-data-to-editor-config.d.ts +0 -10
- package/dist/hooks/editor/utils/assign-initial-data-to-editor-config.d.ts.map +0 -1
- package/dist/hooks/editor/utils/assign-source-elements-to-editor-config.d.ts +0 -12
- package/dist/hooks/editor/utils/assign-source-elements-to-editor-config.d.ts.map +0 -1
- package/src/hooks/editor/utils/assign-initial-data-to-editor-config.ts +0 -47
- package/src/hooks/editor/utils/assign-source-elements-to-editor-config.ts +0 -60
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ckeditor5-phoenix",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.28.0",
|
|
4
4
|
"description": "CKEditor 5 integration for Phoenix Framework",
|
|
5
5
|
"author": "Mateusz Bagiński <cziken58@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"test-utils"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"ckeditor5": "^48.
|
|
28
|
-
"ckeditor5-premium-features": "^48.
|
|
27
|
+
"ckeditor5": "^48.2.0",
|
|
28
|
+
"ckeditor5-premium-features": "^48.2.0",
|
|
29
29
|
"phoenix_live_view": "^1.0.17"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
@@ -105,6 +105,35 @@ describe('editable hook', () => {
|
|
|
105
105
|
|
|
106
106
|
expect(editor.getData({ rootName: 'foo' })).toBe('<p>Foo</p>');
|
|
107
107
|
});
|
|
108
|
+
|
|
109
|
+
it('should set proper root element name on initial added root', async () => {
|
|
110
|
+
const editable = createEditableHtmlElement({
|
|
111
|
+
name: 'foo',
|
|
112
|
+
initialValue: '<p>Foo</p>',
|
|
113
|
+
modelElement: '$inlineRoot',
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
document.body.appendChild(editable);
|
|
117
|
+
|
|
118
|
+
const editor = await appendMultirootEditor();
|
|
119
|
+
EditableHook.mounted.call({ el: editable });
|
|
120
|
+
|
|
121
|
+
expect(editor.model.document.getRoot('foo')?.name).to.be.equal('$inlineRoot');
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should set proper root element name on lazy added root', async () => {
|
|
125
|
+
const editor = await appendMultirootEditor();
|
|
126
|
+
const editable = createEditableHtmlElement({
|
|
127
|
+
name: 'foo',
|
|
128
|
+
initialValue: '<p>Foo</p>',
|
|
129
|
+
modelElement: '$inlineRoot',
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
document.body.appendChild(editable);
|
|
133
|
+
EditableHook.mounted.call({ el: editable });
|
|
134
|
+
|
|
135
|
+
expect(editor.model.document.getRoot('foo')?.name).to.be.equal('$inlineRoot');
|
|
136
|
+
});
|
|
108
137
|
});
|
|
109
138
|
|
|
110
139
|
describe('value synchronization', () => {
|
package/src/hooks/editable.ts
CHANGED
|
@@ -22,6 +22,7 @@ class EditableHookImpl extends ClassHook {
|
|
|
22
22
|
editableId: this.el.getAttribute('id')!,
|
|
23
23
|
editorId: this.el.getAttribute('data-cke-editor-id') || null,
|
|
24
24
|
rootName: this.el.getAttribute('data-cke-editable-root-name')!,
|
|
25
|
+
modelElement: this.el.getAttribute('data-cke-editable-root-model-element-name') || null,
|
|
25
26
|
initialValue: this.el.getAttribute('data-cke-editable-initial-value') || '',
|
|
26
27
|
};
|
|
27
28
|
|
|
@@ -39,7 +40,7 @@ class EditableHookImpl extends ClassHook {
|
|
|
39
40
|
* Mounts the editable component.
|
|
40
41
|
*/
|
|
41
42
|
override mounted() {
|
|
42
|
-
const { editableId, editorId, rootName, initialValue } = this.attrs;
|
|
43
|
+
const { editableId, editorId, rootName, initialValue, modelElement } = this.attrs;
|
|
43
44
|
|
|
44
45
|
const unmountEffect = EditorsRegistry.the.mountEffect(editorId, (editor: MultiRootEditor | DecoupledEditor) => {
|
|
45
46
|
const contentElement = this.el.querySelector('[data-cke-editable-content]') as HTMLElement;
|
|
@@ -57,6 +58,7 @@ class EditableHookImpl extends ClassHook {
|
|
|
57
58
|
editor.addRoot(rootName, {
|
|
58
59
|
isUndoable: false,
|
|
59
60
|
initialData: initialValue,
|
|
61
|
+
modelElement: modelElement || '$root',
|
|
60
62
|
});
|
|
61
63
|
|
|
62
64
|
const editable = ui.view.createEditable(rootName, contentElement);
|
|
@@ -111,6 +111,19 @@ describe('editor hook', () => {
|
|
|
111
111
|
|
|
112
112
|
expect(isEditorShown()).toBe(true);
|
|
113
113
|
});
|
|
114
|
+
|
|
115
|
+
it('should be possible to specify root element name', async () => {
|
|
116
|
+
const hookElement = createEditorHtmlElement({
|
|
117
|
+
modelElement: '$inlineRoot',
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
document.body.appendChild(hookElement);
|
|
121
|
+
EditorHook.mounted.call({ el: hookElement });
|
|
122
|
+
|
|
123
|
+
const editor = await waitForTestEditor();
|
|
124
|
+
|
|
125
|
+
expect(editor.model.document.getRoot()?.name).to.be.equal('$inlineRoot');
|
|
126
|
+
});
|
|
114
127
|
});
|
|
115
128
|
|
|
116
129
|
describe('decoupled', () => {
|
|
@@ -249,6 +262,57 @@ describe('editor hook', () => {
|
|
|
249
262
|
expect(editor).toBeInstanceOf(DecoupledEditor);
|
|
250
263
|
expect(editor.getData()).toBe('<p>XD</p>');
|
|
251
264
|
});
|
|
265
|
+
|
|
266
|
+
it('should be possible to specify root element name using global config (if editable model element not specified)', async () => {
|
|
267
|
+
const hookElement = createEditorHtmlElement({
|
|
268
|
+
preset: createEditorPreset('decoupled'),
|
|
269
|
+
modelElement: '$inlineRoot',
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
document.body.appendChild(hookElement);
|
|
273
|
+
document.body.appendChild(createEditableHtmlElement());
|
|
274
|
+
|
|
275
|
+
EditorHook.mounted.call({ el: hookElement });
|
|
276
|
+
|
|
277
|
+
const editor = await waitForTestEditor();
|
|
278
|
+
|
|
279
|
+
expect(editor.model.document.getRoot()?.name).toEqual('$inlineRoot');
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it('should be possible to specify root element name using editable config alone', async () => {
|
|
283
|
+
const hookElement = createEditorHtmlElement({
|
|
284
|
+
preset: createEditorPreset('decoupled'),
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
document.body.appendChild(hookElement);
|
|
288
|
+
document.body.appendChild(createEditableHtmlElement({
|
|
289
|
+
modelElement: '$inlineRoot',
|
|
290
|
+
}));
|
|
291
|
+
|
|
292
|
+
EditorHook.mounted.call({ el: hookElement });
|
|
293
|
+
|
|
294
|
+
const editor = await waitForTestEditor();
|
|
295
|
+
|
|
296
|
+
expect(editor.model.document.getRoot()?.name).toEqual('$inlineRoot');
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('should use editable root element name config if both specified', async () => {
|
|
300
|
+
const hookElement = createEditorHtmlElement({
|
|
301
|
+
preset: createEditorPreset('decoupled'),
|
|
302
|
+
modelElement: '$miamia',
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
document.body.appendChild(hookElement);
|
|
306
|
+
document.body.appendChild(createEditableHtmlElement({
|
|
307
|
+
modelElement: '$inlineRoot',
|
|
308
|
+
}));
|
|
309
|
+
|
|
310
|
+
EditorHook.mounted.call({ el: hookElement });
|
|
311
|
+
|
|
312
|
+
const editor = await waitForTestEditor();
|
|
313
|
+
|
|
314
|
+
expect(editor.model.document.getRoot()?.name).toEqual('$inlineRoot');
|
|
315
|
+
});
|
|
252
316
|
});
|
|
253
317
|
|
|
254
318
|
describe('inline', () => {
|
|
@@ -313,6 +377,36 @@ describe('editor hook', () => {
|
|
|
313
377
|
'<p>Third root</p>',
|
|
314
378
|
);
|
|
315
379
|
});
|
|
380
|
+
|
|
381
|
+
it('should create a multiroot editor with inline editables', async () => {
|
|
382
|
+
const hookElement = createEditorHtmlElement({
|
|
383
|
+
preset: createEditorPreset('multiroot'),
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
document.body.appendChild(hookElement);
|
|
387
|
+
document.body.appendChild(
|
|
388
|
+
createEditableHtmlElement({
|
|
389
|
+
name: 'second',
|
|
390
|
+
initialValue: '<p>Second root</p>',
|
|
391
|
+
modelElement: '$inlineRoot',
|
|
392
|
+
}),
|
|
393
|
+
);
|
|
394
|
+
|
|
395
|
+
document.body.appendChild(
|
|
396
|
+
createEditableHtmlElement({
|
|
397
|
+
name: 'third',
|
|
398
|
+
initialValue: '<p>Third root</p>',
|
|
399
|
+
modelElement: '$inlineRoot',
|
|
400
|
+
}),
|
|
401
|
+
);
|
|
402
|
+
|
|
403
|
+
EditorHook.mounted.call({ el: hookElement });
|
|
404
|
+
|
|
405
|
+
const editor = await waitForTestEditor();
|
|
406
|
+
|
|
407
|
+
expect(editor.model.document.getRoot('second')?.name).toEqual('$inlineRoot');
|
|
408
|
+
expect(editor.model.document.getRoot('third')?.name).toEqual('$inlineRoot');
|
|
409
|
+
});
|
|
316
410
|
});
|
|
317
411
|
});
|
|
318
412
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { EditorId } from './typings';
|
|
2
|
+
import type { EditableItem } from './utils';
|
|
2
3
|
|
|
3
4
|
import { isEmptyObject, parseIntIfNotNull, waitFor } from '../../shared';
|
|
4
5
|
import { ClassHook, makeHook } from '../../shared/hook';
|
|
@@ -11,8 +12,7 @@ import {
|
|
|
11
12
|
createSyncEditorWithPhoenixPlugin,
|
|
12
13
|
} from './plugins';
|
|
13
14
|
import {
|
|
14
|
-
|
|
15
|
-
assignSourceElementsToEditorConfig,
|
|
15
|
+
assignEditorRootsToConfig,
|
|
16
16
|
cleanupOrphanEditorElements,
|
|
17
17
|
createEditorInContext,
|
|
18
18
|
isSingleRootEditor,
|
|
@@ -20,8 +20,7 @@ import {
|
|
|
20
20
|
loadEditorConstructor,
|
|
21
21
|
loadEditorPlugins,
|
|
22
22
|
normalizeCustomTranslations,
|
|
23
|
-
|
|
24
|
-
queryEditablesSnapshotContent,
|
|
23
|
+
queryAllEditorEditables,
|
|
25
24
|
readPresetOrThrow,
|
|
26
25
|
resolveEditorConfigElementReferences,
|
|
27
26
|
resolveEditorConfigTranslations,
|
|
@@ -234,34 +233,16 @@ class EditorHookImpl extends ClassHook {
|
|
|
234
233
|
]
|
|
235
234
|
.filter(translations => !isEmptyObject(translations));
|
|
236
235
|
|
|
237
|
-
//
|
|
238
|
-
let
|
|
236
|
+
// Query all editable elements along with their initial values in one pass.
|
|
237
|
+
let editables = queryAllEditorEditables(editorId);
|
|
238
|
+
const requiredRoots = Object.keys(editables);
|
|
239
239
|
|
|
240
240
|
if (isSingleRootEditor(type)) {
|
|
241
|
-
|
|
241
|
+
requiredRoots.push('main');
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
// Handle special case when user specified `initialData` of several root elements, but editable components
|
|
248
|
-
// are not yet present in the DOM. In other words - editor is initialized before attaching root elements.
|
|
249
|
-
if (!(sourceElements instanceof HTMLElement) && !('main' in sourceElements)) {
|
|
250
|
-
const requiredRoots = (
|
|
251
|
-
type === 'decoupled'
|
|
252
|
-
? ['main']
|
|
253
|
-
: Object.keys(initialData as Record<string, string>)
|
|
254
|
-
);
|
|
255
|
-
|
|
256
|
-
if (!checkIfAllRootsArePresent(sourceElements, requiredRoots)) {
|
|
257
|
-
sourceElements = await waitForAllRootsToBePresent(editorId, requiredRoots);
|
|
258
|
-
initialData = queryEditablesSnapshotContent(editorId);
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// If single root editor, unwrap the element from the object.
|
|
263
|
-
if (isSingleRootEditor(type) && 'main' in sourceElements) {
|
|
264
|
-
sourceElements = sourceElements['main'];
|
|
244
|
+
if (!checkIfAllRootsArePresent(editables, requiredRoots)) {
|
|
245
|
+
editables = await waitForAllRootsToBePresent(editorId, requiredRoots);
|
|
265
246
|
}
|
|
266
247
|
|
|
267
248
|
// Do some postprocessing on received configuration.
|
|
@@ -277,8 +258,7 @@ class EditorHookImpl extends ClassHook {
|
|
|
277
258
|
|
|
278
259
|
resolvedConfig = resolveEditorConfigElementReferences(resolvedConfig);
|
|
279
260
|
resolvedConfig = resolveEditorConfigTranslations([...mixedTranslations].reverse(), language.ui, resolvedConfig);
|
|
280
|
-
resolvedConfig =
|
|
281
|
-
resolvedConfig = assignInitialDataToEditorConfig(initialData, resolvedConfig);
|
|
261
|
+
resolvedConfig = assignEditorRootsToConfig(Constructor, editables, resolvedConfig);
|
|
282
262
|
|
|
283
263
|
const editor = await (async () => {
|
|
284
264
|
if (!context) {
|
|
@@ -337,42 +317,42 @@ class EditorHookImpl extends ClassHook {
|
|
|
337
317
|
}
|
|
338
318
|
|
|
339
319
|
/**
|
|
340
|
-
* Checks if all required root elements are present in the
|
|
320
|
+
* Checks if all required root elements are present in the editables map.
|
|
341
321
|
*
|
|
342
|
-
* @param
|
|
343
|
-
* @param requiredRoots The list of required root
|
|
322
|
+
* @param editables The editables map keyed by root name.
|
|
323
|
+
* @param requiredRoots The list of required root names.
|
|
344
324
|
* @returns True if all required roots are present, false otherwise.
|
|
345
325
|
*/
|
|
346
|
-
function checkIfAllRootsArePresent(
|
|
347
|
-
return requiredRoots.every(rootId =>
|
|
326
|
+
function checkIfAllRootsArePresent(editables: Record<string, EditableItem>, requiredRoots: string[]): boolean {
|
|
327
|
+
return requiredRoots.every(rootId => editables[rootId]);
|
|
348
328
|
}
|
|
349
329
|
|
|
350
330
|
/**
|
|
351
331
|
* Waits for all required root elements to be present in the DOM.
|
|
352
332
|
*
|
|
353
333
|
* @param editorId The editor's ID.
|
|
354
|
-
* @param requiredRoots The list of required root
|
|
355
|
-
* @returns A promise that resolves to the
|
|
334
|
+
* @param requiredRoots The list of required root names.
|
|
335
|
+
* @returns A promise that resolves to the map of editable items.
|
|
356
336
|
*/
|
|
357
337
|
async function waitForAllRootsToBePresent(
|
|
358
338
|
editorId: EditorId,
|
|
359
339
|
requiredRoots: string[],
|
|
360
|
-
): Promise<Record<string,
|
|
340
|
+
): Promise<Record<string, EditableItem>> {
|
|
361
341
|
return waitFor(
|
|
362
342
|
() => {
|
|
363
|
-
const
|
|
343
|
+
const editables = queryAllEditorEditables(editorId);
|
|
364
344
|
|
|
365
|
-
if (!checkIfAllRootsArePresent(
|
|
345
|
+
if (!checkIfAllRootsArePresent(editables, requiredRoots)) {
|
|
366
346
|
throw new Error(
|
|
367
347
|
'It looks like not all required root elements are present yet.\n'
|
|
368
348
|
+ '* If you want to wait for them, ensure they are registered before editor initialization.\n'
|
|
369
349
|
+ '* If you want lazy initialize roots, consider removing root values from the `initialData` config '
|
|
370
350
|
+ 'and assign initial data in editable components.\n'
|
|
371
|
-
+ `Missing roots: ${requiredRoots.filter(rootId => !
|
|
351
|
+
+ `Missing roots: ${requiredRoots.filter(rootId => !editables[rootId]).join(', ')}.`,
|
|
372
352
|
);
|
|
373
353
|
}
|
|
374
354
|
|
|
375
|
-
return
|
|
355
|
+
return editables;
|
|
376
356
|
},
|
|
377
357
|
{ timeOutAfter: 2000, retryAfter: 100 },
|
|
378
358
|
);
|
|
@@ -168,7 +168,7 @@ function getEditorRootsValues(editor: Editor) {
|
|
|
168
168
|
return roots.reduce<Record<string, string>>((acc, rootName) => {
|
|
169
169
|
acc[rootName] = editor.getData({ rootName });
|
|
170
170
|
return acc;
|
|
171
|
-
}, Object.create(
|
|
171
|
+
}, Object.create(null));
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
/**
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { EditorConfig } from 'ckeditor5';
|
|
2
|
+
|
|
3
|
+
import type { EditorRelaxedConstructor } from '../types/editor-relaxed-constructor.type';
|
|
4
|
+
import type { EditableItem } from './query-all-editor-editables';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Assigns DOM elements and initial data to the editor configuration in a way that is compatible
|
|
8
|
+
* with the specific editor type.
|
|
9
|
+
*
|
|
10
|
+
* @param Editor Constructor of the editor used to determine the location of element config entry.
|
|
11
|
+
* @param editables Map of editable items (element + initial value) keyed by root name.
|
|
12
|
+
* @param config Config of the editor.
|
|
13
|
+
* @returns The updated configuration object.
|
|
14
|
+
*/
|
|
15
|
+
export function assignEditorRootsToConfig<C extends EditorConfig>(
|
|
16
|
+
Editor: EditorRelaxedConstructor,
|
|
17
|
+
editables: Record<string, EditableItem>,
|
|
18
|
+
config: C,
|
|
19
|
+
): C {
|
|
20
|
+
const isClassicEditor = !Editor.editorName || Editor.editorName === 'ClassicEditor';
|
|
21
|
+
const allRootsKeys = new Set([
|
|
22
|
+
...Object.keys(editables),
|
|
23
|
+
...Object.keys(config.roots ?? {}),
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
const rootsConfig = Array.from(allRootsKeys).reduce((acc, rootKey) => ({
|
|
27
|
+
...acc,
|
|
28
|
+
[rootKey]: {
|
|
29
|
+
/* v8 ignore next 1 */
|
|
30
|
+
...config.roots?.[rootKey],
|
|
31
|
+
...rootKey === 'main' ? config.root : {},
|
|
32
|
+
|
|
33
|
+
/* v8 ignore start */
|
|
34
|
+
...rootKey in editables
|
|
35
|
+
? {
|
|
36
|
+
initialData: editables[rootKey]!.initialValue,
|
|
37
|
+
modelElement: editables[rootKey]!.modelElement || '$root',
|
|
38
|
+
...!isClassicEditor && {
|
|
39
|
+
element: editables[rootKey]!.content,
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
: {},
|
|
43
|
+
/* v8 ignore end */
|
|
44
|
+
},
|
|
45
|
+
}), { ...config.roots || {} });
|
|
46
|
+
|
|
47
|
+
const mappedConfig: C = {
|
|
48
|
+
...config,
|
|
49
|
+
roots: rootsConfig,
|
|
50
|
+
...isClassicEditor && {
|
|
51
|
+
attachTo: editables['main']?.content,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
delete mappedConfig.root;
|
|
56
|
+
|
|
57
|
+
return mappedConfig;
|
|
58
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
export * from './assign-
|
|
2
|
-
export * from './assign-source-elements-to-editor-config';
|
|
1
|
+
export * from './assign-editor-roots-to-config';
|
|
3
2
|
export * from './cleanup-orphan-editor-elements';
|
|
4
3
|
export * from './create-editor-in-context';
|
|
5
4
|
export * from './is-multiroot-editor-instance';
|
|
@@ -1,34 +1,5 @@
|
|
|
1
1
|
import type { EditorId } from '../typings';
|
|
2
2
|
|
|
3
|
-
import { filterObjectValues, mapObjectValues } from '../../../shared';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Gets the initial root elements for the editor based on its type.
|
|
7
|
-
*
|
|
8
|
-
* @param editorId The editor's ID.
|
|
9
|
-
* @returns The root element(s) for the editor.
|
|
10
|
-
*/
|
|
11
|
-
export function queryEditablesElements(editorId: EditorId) {
|
|
12
|
-
const editables = queryAllEditorEditables(editorId);
|
|
13
|
-
|
|
14
|
-
return mapObjectValues(editables, ({ content }) => content);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Gets the initial data for the roots of the editor. If the editor is a single editing-like editor,
|
|
19
|
-
* it retrieves the initial value from the element's attribute. Otherwise, it returns an object mapping
|
|
20
|
-
* editable names to their initial values.
|
|
21
|
-
*
|
|
22
|
-
* @param editorId The editor's ID.
|
|
23
|
-
* @returns The initial values for the editor's roots.
|
|
24
|
-
*/
|
|
25
|
-
export function queryEditablesSnapshotContent(editorId: EditorId) {
|
|
26
|
-
const editables = queryAllEditorEditables(editorId);
|
|
27
|
-
const values = mapObjectValues(editables, ({ initialValue }) => initialValue);
|
|
28
|
-
|
|
29
|
-
return filterObjectValues(values, value => typeof value === 'string') as Record<string, string>;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
3
|
/**
|
|
33
4
|
* Queries all editable elements within a specific editor instance.
|
|
34
5
|
*
|
|
@@ -49,6 +20,7 @@ export function queryAllEditorEditables(editorId: EditorId): Record<string, Edit
|
|
|
49
20
|
.from(iterator)
|
|
50
21
|
.reduce<Record<string, EditableItem>>((acc, element) => {
|
|
51
22
|
const name = element.getAttribute('data-cke-editable-root-name');
|
|
23
|
+
const modelElement = element.getAttribute('data-cke-editable-root-model-element-name') || null;
|
|
52
24
|
const initialValue = element.getAttribute('data-cke-editable-initial-value') || '';
|
|
53
25
|
const content = element.querySelector('[data-cke-editable-content]') as HTMLElement;
|
|
54
26
|
|
|
@@ -61,9 +33,10 @@ export function queryAllEditorEditables(editorId: EditorId): Record<string, Edit
|
|
|
61
33
|
[name]: {
|
|
62
34
|
content,
|
|
63
35
|
initialValue,
|
|
36
|
+
modelElement,
|
|
64
37
|
},
|
|
65
38
|
};
|
|
66
|
-
}, Object.create(
|
|
39
|
+
}, Object.create(null))
|
|
67
40
|
);
|
|
68
41
|
|
|
69
42
|
const rootEditorElement = document.querySelector<HTMLElement>(`[phx-hook="CKEditor5"][id="${editorId}"]`);
|
|
@@ -72,26 +45,29 @@ export function queryAllEditorEditables(editorId: EditorId): Record<string, Edit
|
|
|
72
45
|
return acc;
|
|
73
46
|
}
|
|
74
47
|
|
|
48
|
+
const rootEditorModelElement = rootEditorElement.getAttribute('data-cke-root-model-element-name');
|
|
75
49
|
const initialRootEditableValue = rootEditorElement.getAttribute('data-cke-initial-value') || '';
|
|
76
|
-
const contentElement = rootEditorElement.querySelector<HTMLElement>(`#${editorId}_editor `);
|
|
77
|
-
const currentMain = acc['main'];
|
|
78
50
|
|
|
79
|
-
if (
|
|
51
|
+
if (acc['main']) {
|
|
80
52
|
return {
|
|
81
53
|
...acc,
|
|
82
54
|
main: {
|
|
83
|
-
...
|
|
84
|
-
|
|
55
|
+
...acc['main'],
|
|
56
|
+
modelElement: acc['main'].modelElement || rootEditorModelElement,
|
|
57
|
+
initialValue: acc['main'].initialValue || initialRootEditableValue,
|
|
85
58
|
},
|
|
86
59
|
};
|
|
87
60
|
}
|
|
88
61
|
|
|
62
|
+
const contentElement = rootEditorElement.querySelector<HTMLElement>(`#${editorId}_editor `);
|
|
63
|
+
|
|
89
64
|
if (contentElement) {
|
|
90
65
|
return {
|
|
91
66
|
...acc,
|
|
92
67
|
main: {
|
|
93
68
|
content: contentElement,
|
|
94
69
|
initialValue: initialRootEditableValue,
|
|
70
|
+
modelElement: rootEditorElement.getAttribute('data-cke-root-model-element-name') || '$root',
|
|
95
71
|
},
|
|
96
72
|
};
|
|
97
73
|
}
|
|
@@ -105,4 +81,5 @@ export function queryAllEditorEditables(editorId: EditorId): Record<string, Edit
|
|
|
105
81
|
export type EditableItem = {
|
|
106
82
|
content: HTMLElement;
|
|
107
83
|
initialValue: string;
|
|
84
|
+
modelElement: string | null;
|
|
108
85
|
};
|
|
@@ -12,12 +12,14 @@ export function createEditableHtmlElement(
|
|
|
12
12
|
editorId,
|
|
13
13
|
initialValue,
|
|
14
14
|
withInput = false,
|
|
15
|
+
modelElement,
|
|
15
16
|
}: {
|
|
16
17
|
id?: string;
|
|
17
18
|
editorId?: EditorId;
|
|
18
19
|
name?: string;
|
|
19
20
|
initialValue?: string;
|
|
20
21
|
withInput?: boolean;
|
|
22
|
+
modelElement?: string;
|
|
21
23
|
} = {},
|
|
22
24
|
) {
|
|
23
25
|
return html.div(
|
|
@@ -30,6 +32,9 @@ export function createEditableHtmlElement(
|
|
|
30
32
|
...initialValue && {
|
|
31
33
|
'data-cke-editable-initial-value': initialValue,
|
|
32
34
|
},
|
|
35
|
+
...modelElement && {
|
|
36
|
+
'data-cke-editable-root-model-element-name': modelElement,
|
|
37
|
+
},
|
|
33
38
|
},
|
|
34
39
|
html.div({
|
|
35
40
|
'class': 'editable-content',
|
|
@@ -20,6 +20,7 @@ export function createEditorHtmlElement(
|
|
|
20
20
|
readyEvent = false,
|
|
21
21
|
watchdog = false,
|
|
22
22
|
saveDebounceMs = undefined,
|
|
23
|
+
modelElement,
|
|
23
24
|
language,
|
|
24
25
|
hookAttrs,
|
|
25
26
|
}: EditorCreatorAttrs = {},
|
|
@@ -63,6 +64,9 @@ export function createEditorHtmlElement(
|
|
|
63
64
|
...contextId && {
|
|
64
65
|
'data-cke-context-id': contextId,
|
|
65
66
|
},
|
|
67
|
+
...modelElement && {
|
|
68
|
+
'data-cke-root-model-element-name': modelElement,
|
|
69
|
+
},
|
|
66
70
|
...hookAttrs,
|
|
67
71
|
},
|
|
68
72
|
!['multiroot', 'decoupled'].includes(preset.type) && html.div({ id: `${id}_editor` }),
|
|
@@ -91,5 +95,6 @@ type EditorCreatorAttrs = {
|
|
|
91
95
|
watchdog?: boolean;
|
|
92
96
|
saveDebounceMs?: number;
|
|
93
97
|
hookAttrs?: Record<string, string>;
|
|
98
|
+
modelElement?: string;
|
|
94
99
|
language?: { ui?: string; content?: string; };
|
|
95
100
|
};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { EditorConfig } from 'ckeditor5';
|
|
2
|
-
/**
|
|
3
|
-
* Assigns initial data to specified editor config.
|
|
4
|
-
*
|
|
5
|
-
* @param dataOrMap Initial data to be assigned to config.
|
|
6
|
-
* @param config Config of the editor.
|
|
7
|
-
* @returns The updated configuration object.
|
|
8
|
-
*/
|
|
9
|
-
export declare function assignInitialDataToEditorConfig<C extends EditorConfig>(dataOrMap: string | Record<string, string>, config: C): C;
|
|
10
|
-
//# sourceMappingURL=assign-initial-data-to-editor-config.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"assign-initial-data-to-editor-config.d.ts","sourceRoot":"","sources":["../../../../src/hooks/editor/utils/assign-initial-data-to-editor-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAAC,CAAC,SAAS,YAAY,EACpE,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC1C,MAAM,EAAE,CAAC,GACR,CAAC,CA8BH"}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { EditorConfig } from 'ckeditor5';
|
|
2
|
-
import { EditorRelaxedConstructor } from '../types/editor-relaxed-constructor.type';
|
|
3
|
-
/**
|
|
4
|
-
* Assigns a DOM element to the editor configuration in a way that is compatible with the specific editor type.
|
|
5
|
-
*
|
|
6
|
-
* @param Editor Constructor of the editor used to determine the location of element config entry.
|
|
7
|
-
* @param elementOrMap Element to be assigned to config.
|
|
8
|
-
* @param config Config of the editor.
|
|
9
|
-
* @returns The updated configuration object.
|
|
10
|
-
*/
|
|
11
|
-
export declare function assignSourceElementsToEditorConfig<C extends EditorConfig>(Editor: EditorRelaxedConstructor, elementOrMap: HTMLElement | Record<string, HTMLElement>, config: C): C;
|
|
12
|
-
//# sourceMappingURL=assign-source-elements-to-editor-config.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"assign-source-elements-to-editor-config.d.ts","sourceRoot":"","sources":["../../../../src/hooks/editor/utils/assign-source-elements-to-editor-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0CAA0C,CAAC;AAEzF;;;;;;;GAOG;AACH,wBAAgB,kCAAkC,CAAC,CAAC,SAAS,YAAY,EACvE,MAAM,EAAE,wBAAwB,EAChC,YAAY,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACvD,MAAM,EAAE,CAAC,GACR,CAAC,CAuCH"}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import type { EditorConfig } from 'ckeditor5';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Assigns initial data to specified editor config.
|
|
5
|
-
*
|
|
6
|
-
* @param dataOrMap Initial data to be assigned to config.
|
|
7
|
-
* @param config Config of the editor.
|
|
8
|
-
* @returns The updated configuration object.
|
|
9
|
-
*/
|
|
10
|
-
export function assignInitialDataToEditorConfig<C extends EditorConfig>(
|
|
11
|
-
dataOrMap: string | Record<string, string>,
|
|
12
|
-
config: C,
|
|
13
|
-
): C {
|
|
14
|
-
const dataMap = toDataMap(dataOrMap);
|
|
15
|
-
const allRootsKeys = new Set([
|
|
16
|
-
...Object.keys(dataMap),
|
|
17
|
-
...Object.keys(config.roots ?? {}),
|
|
18
|
-
]);
|
|
19
|
-
|
|
20
|
-
const rootsConfig = Array.from(allRootsKeys).reduce((acc, rootKey) => ({
|
|
21
|
-
...acc,
|
|
22
|
-
[rootKey]: {
|
|
23
|
-
...config.roots?.[rootKey],
|
|
24
|
-
...rootKey === 'main' ? config.root : {},
|
|
25
|
-
|
|
26
|
-
/* v8 ignore next 5 */
|
|
27
|
-
...rootKey in dataMap
|
|
28
|
-
? {
|
|
29
|
-
initialData: dataMap[rootKey],
|
|
30
|
-
}
|
|
31
|
-
: {},
|
|
32
|
-
},
|
|
33
|
-
}), Object.create(config.roots || {}));
|
|
34
|
-
|
|
35
|
-
const mappedConfig: C = {
|
|
36
|
-
...config,
|
|
37
|
-
roots: rootsConfig,
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
delete mappedConfig.root;
|
|
41
|
-
|
|
42
|
-
return mappedConfig;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function toDataMap(element: string | Record<string, string>): Record<string, string> {
|
|
46
|
-
return typeof element === 'string' ? { main: element } : { ...element };
|
|
47
|
-
}
|