@ckeditor/ckeditor5-editor-multi-root 47.6.1 → 48.0.0-alpha.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/LICENSE.md +1 -1
- package/{src → dist}/augmentation.d.ts +25 -10
- package/dist/index.css +3 -0
- package/dist/index.css.map +1 -0
- package/{src → dist}/index.d.ts +1 -1
- package/dist/index.js +141 -310
- package/dist/index.js.map +1 -1
- package/{src → dist}/multirooteditor.d.ts +258 -25
- package/{src → dist}/multirooteditorui.d.ts +2 -2
- package/{src → dist}/multirooteditoruiview.d.ts +3 -3
- package/package.json +23 -44
- package/build/editor-multi-root.js +0 -4
- package/src/index.js +0 -11
- package/src/multirooteditor.js +0 -838
- package/src/multirooteditorui.js +0 -180
- package/src/multirooteditoruiview.js +0 -138
- /package/{src/augmentation.js → dist/legacyerrors.d.ts} +0 -0
package/dist/index.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
4
4
|
*/
|
|
5
|
-
import { Editor, secureSourceElement } from '@ckeditor/ckeditor5-core/dist/index.js';
|
|
6
|
-
import {
|
|
5
|
+
import { Editor, normalizeMultiRootEditorConstructorParams, normalizeRootsConfig, secureSourceElement } from '@ckeditor/ckeditor5-core/dist/index.js';
|
|
6
|
+
import { logWarning, CKEditorError, decodeLicenseKey, isFeatureBlockedByLicenseKey, setDataInElement } from '@ckeditor/ckeditor5-utils/dist/index.js';
|
|
7
7
|
import { EditorUI, EditorUIView, ToolbarView, MenuBarView, InlineEditableUIView } from '@ckeditor/ckeditor5-ui/dist/index.js';
|
|
8
8
|
import { enableViewPlaceholder } from '@ckeditor/ckeditor5-engine/dist/index.js';
|
|
9
9
|
import { isElement as isElement$1 } from 'es-toolkit/compat';
|
|
@@ -147,10 +147,7 @@ import { isElement as isElement$1 } from 'es-toolkit/compat';
|
|
|
147
147
|
* {@link module:core/editor/editorconfig~EditorConfig#placeholder editor configuration} will be used (if it was provided).
|
|
148
148
|
*/ _initPlaceholder(editable, placeholder) {
|
|
149
149
|
if (!placeholder) {
|
|
150
|
-
|
|
151
|
-
if (configPlaceholder) {
|
|
152
|
-
placeholder = typeof configPlaceholder === 'string' ? configPlaceholder : configPlaceholder[editable.name];
|
|
153
|
-
}
|
|
150
|
+
placeholder = this.editor.config.get('roots')[editable.name]?.placeholder;
|
|
154
151
|
}
|
|
155
152
|
const editingView = this.editor.editing.view;
|
|
156
153
|
const editingRoot = editingView.document.getRoot(editable.name);
|
|
@@ -214,7 +211,7 @@ import { isElement as isElement$1 } from 'es-toolkit/compat';
|
|
|
214
211
|
this.editables = {};
|
|
215
212
|
// Create `InlineEditableUIView` instance for each editable.
|
|
216
213
|
for (const editableName of editableNames){
|
|
217
|
-
const editableElement = options.editableElements
|
|
214
|
+
const editableElement = options.editableElements?.[editableName];
|
|
218
215
|
let { label } = options;
|
|
219
216
|
if (typeof label === 'object') {
|
|
220
217
|
label = label[editableName];
|
|
@@ -314,47 +311,49 @@ import { isElement as isElement$1 } from 'es-toolkit/compat';
|
|
|
314
311
|
* The elements on which the editor has been initialized.
|
|
315
312
|
*/ sourceElements;
|
|
316
313
|
/**
|
|
317
|
-
* Holds attributes keys that were passed in
|
|
318
|
-
*
|
|
314
|
+
* Holds attributes keys that were passed in
|
|
315
|
+
* {@link module:core/editor/editorconfig~EditorConfig#roots `config.roots.<rootName>.modelAttributes`}
|
|
316
|
+
* and should be returned by {@link #getRootsAttributes}.
|
|
319
317
|
*/ _registeredRootsAttributesKeys = new Set();
|
|
320
318
|
/**
|
|
321
319
|
* A set of lock IDs for enabling or disabling particular root.
|
|
322
320
|
*/ _readOnlyRootLocks = new Map();
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
* or the editor's initial data. The editor will initialize multiple roots with names according to the keys in the passed object.
|
|
331
|
-
* For more information see {@link module:editor-multi-root/multirooteditor~MultiRootEditor.create `MultiRootEditor.create()`}.
|
|
332
|
-
* @param config The editor configuration.
|
|
333
|
-
*/ constructor(sourceElementsOrData, config = {}){
|
|
334
|
-
const rootNames = Object.keys(sourceElementsOrData);
|
|
335
|
-
const sourceIsData = rootNames.length === 0 || typeof sourceElementsOrData[rootNames[0]] === 'string';
|
|
336
|
-
if (sourceIsData && config.initialData !== undefined && Object.keys(config.initialData).length > 0) {
|
|
337
|
-
// Documented in core/editor/editorconfig.jsdoc.
|
|
338
|
-
// eslint-disable-next-line ckeditor5-rules/ckeditor-error-message
|
|
339
|
-
throw new CKEditorError('editor-create-initial-data', null);
|
|
321
|
+
constructor(sourceElementsOrDataOrConfig, config = {}){
|
|
322
|
+
const { sourceElementsOrData, editorConfig } = normalizeMultiRootEditorConstructorParams(sourceElementsOrDataOrConfig, config);
|
|
323
|
+
super(editorConfig);
|
|
324
|
+
normalizeRootsConfig(sourceElementsOrData, this.config, false);
|
|
325
|
+
if (isElement(this.config.get('attachTo'))) {
|
|
326
|
+
// Documented in core/editor/editorconfig.ts.
|
|
327
|
+
logWarning('editor-create-attachto-ignored');
|
|
340
328
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
329
|
+
if (this.config.get('lazyRoots')) {
|
|
330
|
+
/**
|
|
331
|
+
* Using deprecated `config.lazyRoots` configuration option.
|
|
332
|
+
* Use `config.roots.<rootName>.lazyLoad` instead.
|
|
333
|
+
*
|
|
334
|
+
* @error multi-root-editor-root-deprecated-config-lazy-roots
|
|
335
|
+
*/ throw new CKEditorError('multi-root-editor-root-deprecated-config-lazy-roots', null);
|
|
346
336
|
}
|
|
347
|
-
if (this.config.get('
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
337
|
+
if (this.config.get('rootsAttributes')) {
|
|
338
|
+
/**
|
|
339
|
+
* Using deprecated `config.rootsAttributes` configuration option.
|
|
340
|
+
* Use `config.roots.<rootName>.modelAttributes` instead.
|
|
341
|
+
*
|
|
342
|
+
* @error multi-root-editor-root-deprecated-config-roots-attributes
|
|
343
|
+
*/ throw new CKEditorError('multi-root-editor-root-deprecated-config-roots-attributes', null);
|
|
354
344
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
345
|
+
// From this point use only normalized `roots.<rootName>.element`, etc.
|
|
346
|
+
const rootsConfig = Object.entries(this.config.get('roots'));
|
|
347
|
+
this.sourceElements = {};
|
|
348
|
+
for (const [rootName, { element }] of rootsConfig){
|
|
349
|
+
if (isElement(element)) {
|
|
350
|
+
if (element.tagName === 'TEXTAREA') {
|
|
351
|
+
// Documented in core/editor/editor.js
|
|
352
|
+
// eslint-disable-next-line ckeditor5-rules/ckeditor-error-message
|
|
353
|
+
throw new CKEditorError('editor-wrong-element', null);
|
|
354
|
+
}
|
|
355
|
+
this.sourceElements[rootName] = element;
|
|
356
|
+
secureSourceElement(this, element);
|
|
358
357
|
}
|
|
359
358
|
}
|
|
360
359
|
this.editing.view.document.roots.on('add', (evt, viewRoot)=>{
|
|
@@ -376,54 +375,57 @@ import { isElement as isElement$1 } from 'es-toolkit/compat';
|
|
|
376
375
|
}
|
|
377
376
|
});
|
|
378
377
|
});
|
|
379
|
-
for (const rootName of
|
|
378
|
+
for (const [rootName, rootConfig] of rootsConfig){
|
|
380
379
|
// Create root and `UIView` element for each editable container.
|
|
381
|
-
this.model.document.createRoot('$root', rootName);
|
|
382
|
-
|
|
383
|
-
if (this.config.get('lazyRoots')) {
|
|
384
|
-
for (const rootName of this.config.get('lazyRoots')){
|
|
385
|
-
const root = this.model.document.createRoot('$root', rootName);
|
|
380
|
+
const root = this.model.document.createRoot('$root', rootName);
|
|
381
|
+
if (rootConfig.lazyLoad) {
|
|
386
382
|
root._isLoaded = false;
|
|
387
383
|
}
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
const rootsAttributes = this.config.get('rootsAttributes');
|
|
391
|
-
for (const [rootName, attributes] of Object.entries(rootsAttributes)){
|
|
392
|
-
if (!this.model.document.getRoot(rootName)) {
|
|
393
|
-
/**
|
|
394
|
-
* Trying to set attributes on a non-existing root.
|
|
395
|
-
*
|
|
396
|
-
* Roots specified in {@link module:core/editor/editorconfig~EditorConfig#rootsAttributes} do not match initial
|
|
397
|
-
* editor roots.
|
|
398
|
-
*
|
|
399
|
-
* @error multi-root-editor-root-attributes-no-root
|
|
400
|
-
*/ throw new CKEditorError('multi-root-editor-root-attributes-no-root', null);
|
|
401
|
-
}
|
|
384
|
+
const attributes = rootConfig.modelAttributes;
|
|
385
|
+
if (attributes) {
|
|
402
386
|
for (const key of Object.keys(attributes)){
|
|
403
387
|
this.registerRootAttribute(key);
|
|
404
388
|
}
|
|
405
389
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
390
|
+
}
|
|
391
|
+
// Registering `$rootEditableOptions` attribute to make it available in the editor model.
|
|
392
|
+
// This allows to store editable options for each root in the model, and make them available on other RTC clients.
|
|
393
|
+
// We do not use `registerRootAttribute()` method here, as this attribute is used internally
|
|
394
|
+
// and should not be returned by `getRootsAttributes()` method.
|
|
395
|
+
this.editing.model.schema.extend('$root', {
|
|
396
|
+
allowAttributes: '$rootEditableOptions'
|
|
397
|
+
});
|
|
398
|
+
this.data.on('init', ()=>{
|
|
399
|
+
this.model.enqueueChange({
|
|
400
|
+
isUndoable: false
|
|
401
|
+
}, (writer)=>{
|
|
402
|
+
for (const [rootName, rootConfig] of rootsConfig){
|
|
403
|
+
const root = this.model.document.getRoot(rootName);
|
|
404
|
+
for (const [key, value] of Object.entries(rootConfig.modelAttributes || {})){
|
|
405
|
+
if (value !== null) {
|
|
406
|
+
writer.setAttribute(key, value, root);
|
|
416
407
|
}
|
|
417
408
|
}
|
|
418
|
-
|
|
409
|
+
// Set editable config for consistency with `addRoot()` method. This will allow features
|
|
410
|
+
// to use the same configuration for both initially loaded and dynamically added roots.
|
|
411
|
+
const rootEditableOptions = {
|
|
412
|
+
...rootConfig.placeholder && {
|
|
413
|
+
placeholder: rootConfig.placeholder
|
|
414
|
+
},
|
|
415
|
+
...rootConfig.label && {
|
|
416
|
+
label: rootConfig.label
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
writer.setAttribute('$rootEditableOptions', rootEditableOptions, root);
|
|
420
|
+
}
|
|
419
421
|
});
|
|
420
|
-
}
|
|
422
|
+
});
|
|
421
423
|
const options = {
|
|
422
424
|
shouldToolbarGroupWhenFull: !this.config.get('toolbar.shouldNotGroupWhenFull'),
|
|
423
|
-
editableElements:
|
|
424
|
-
label: this.config.get('label')
|
|
425
|
+
editableElements: this.sourceElements,
|
|
426
|
+
label: extractRootsConfigField(this.config.get('roots'), 'label')
|
|
425
427
|
};
|
|
426
|
-
const view = new MultiRootEditorUIView(this.locale, this.editing.view,
|
|
428
|
+
const view = new MultiRootEditorUIView(this.locale, this.editing.view, getNonLazyLoadRootsNames(rootsConfig), options);
|
|
427
429
|
this.ui = new MultiRootEditorUI(this, view);
|
|
428
430
|
this.model.document.on('change:data', ()=>{
|
|
429
431
|
const changedRoots = this.model.document.differ.getChangedRoots();
|
|
@@ -544,90 +546,36 @@ import { isElement as isElement$1 } from 'es-toolkit/compat';
|
|
|
544
546
|
}
|
|
545
547
|
});
|
|
546
548
|
}
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
* All root names must be unique. An error will be thrown if you will try to create a root with the name same as
|
|
557
|
-
* an already existing, attached root. However, you can call this method for a detached root. See also {@link #detachRoot}.
|
|
558
|
-
*
|
|
559
|
-
* Whenever a root is added, the editor instance will fire {@link #event:addRoot `addRoot` event}. The event is also called when
|
|
560
|
-
* the root is added indirectly, e.g. by the undo feature or on a remote client during real-time collaboration.
|
|
561
|
-
*
|
|
562
|
-
* Note, that this method only adds a root to the editor model. It **does not** create a DOM editable element for the new root.
|
|
563
|
-
* Until such element is created (and attached to the root), the root is "virtual": it is not displayed anywhere and its data can
|
|
564
|
-
* be changed only using the editor API.
|
|
565
|
-
*
|
|
566
|
-
* To create a DOM editable element for the root, listen to {@link #event:addRoot `addRoot` event} and call {@link #createEditable}.
|
|
567
|
-
* Then, insert the DOM element in a desired place, that will depend on the integration with your application and your requirements.
|
|
568
|
-
*
|
|
569
|
-
* ```ts
|
|
570
|
-
* editor.on( 'addRoot', ( evt, root ) => {
|
|
571
|
-
* const editableElement = editor.createEditable( root );
|
|
572
|
-
*
|
|
573
|
-
* // You may want to create a more complex DOM structure here.
|
|
574
|
-
* //
|
|
575
|
-
* // Alternatively, you may want to create a DOM structure before
|
|
576
|
-
* // calling `editor.addRoot()` and only append `editableElement` at
|
|
577
|
-
* // a proper place.
|
|
578
|
-
*
|
|
579
|
-
* document.querySelector( '#editors' ).appendChild( editableElement );
|
|
580
|
-
* } );
|
|
581
|
-
*
|
|
582
|
-
* // ...
|
|
583
|
-
*
|
|
584
|
-
* editor.addRoot( 'myRoot' ); // Will create a root, a DOM editable element and append it to `#editors` container element.
|
|
585
|
-
* ```
|
|
586
|
-
*
|
|
587
|
-
* You can set root attributes on the new root while you add it:
|
|
588
|
-
*
|
|
589
|
-
* ```ts
|
|
590
|
-
* // Add a collapsed root at fourth position from top.
|
|
591
|
-
* // Keep in mind that these are just examples of attributes. You need to provide your own features that will handle the attributes.
|
|
592
|
-
* editor.addRoot( 'myRoot', { attributes: { isCollapsed: true, index: 4 } } );
|
|
593
|
-
* ```
|
|
594
|
-
*
|
|
595
|
-
* Note that attributes added together with a root are automatically registered.
|
|
596
|
-
*
|
|
597
|
-
* See also {@link ~MultiRootEditor#registerRootAttribute `MultiRootEditor#registerRootAttribute()`} and
|
|
598
|
-
* {@link module:core/editor/editorconfig~EditorConfig#rootsAttributes `config.rootsAttributes` configuration option}.
|
|
599
|
-
*
|
|
600
|
-
* By setting `isUndoable` flag to `true`, you can allow for detaching the root using the undo feature.
|
|
601
|
-
*
|
|
602
|
-
* Additionally, you can group adding multiple roots in one undo step. This can be useful if you add multiple roots that are
|
|
603
|
-
* combined into one, bigger UI element, and want them all to be undone together.
|
|
604
|
-
*
|
|
605
|
-
* ```ts
|
|
606
|
-
* let rowId = 0;
|
|
607
|
-
*
|
|
608
|
-
* editor.model.change( () => {
|
|
609
|
-
* editor.addRoot( 'left-row-' + rowId, { isUndoable: true } );
|
|
610
|
-
* editor.addRoot( 'center-row-' + rowId, { isUndoable: true } );
|
|
611
|
-
* editor.addRoot( 'right-row-' + rowId, { isUndoable: true } );
|
|
612
|
-
*
|
|
613
|
-
* rowId++;
|
|
614
|
-
* } );
|
|
615
|
-
* ```
|
|
616
|
-
*
|
|
617
|
-
* @param rootName Name of the root to add.
|
|
618
|
-
* @param options Additional options for the added root.
|
|
619
|
-
*/ addRoot(rootName, { data = '', attributes = {}, elementName = '$root', isUndoable = false } = {}) {
|
|
549
|
+
addRoot(rootName, options = {}) {
|
|
550
|
+
const initialData = options.initialData || options.data || '';
|
|
551
|
+
const modelAttributes = options.modelAttributes || options.attributes || {};
|
|
552
|
+
const modelElement = options.elementName || '$root';
|
|
553
|
+
if (isElement(options.element)) {
|
|
554
|
+
/**
|
|
555
|
+
* The `element` option is not supported in {@link #addRoot `addRoot()`} method, and will be ignored.
|
|
556
|
+
*/ logWarning('multi-root-editor-add-root-element-option-ignored');
|
|
557
|
+
}
|
|
620
558
|
const _addRoot = (writer)=>{
|
|
621
|
-
const root = writer.addRoot(rootName,
|
|
622
|
-
if (
|
|
623
|
-
writer.insert(this.data.parse(
|
|
559
|
+
const root = writer.addRoot(rootName, modelElement);
|
|
560
|
+
if (initialData) {
|
|
561
|
+
writer.insert(this.data.parse(initialData, root), root, 0);
|
|
624
562
|
}
|
|
625
|
-
for (const key of Object.keys(
|
|
563
|
+
for (const key of Object.keys(modelAttributes)){
|
|
626
564
|
this.registerRootAttribute(key);
|
|
627
|
-
writer.setAttribute(key,
|
|
565
|
+
writer.setAttribute(key, modelAttributes[key], root);
|
|
628
566
|
}
|
|
567
|
+
// Storing editable options as a root attribute to make them available on other RTC clients.
|
|
568
|
+
const rootEditableOptions = {
|
|
569
|
+
...options.placeholder && {
|
|
570
|
+
placeholder: options.placeholder
|
|
571
|
+
},
|
|
572
|
+
...options.label && {
|
|
573
|
+
label: options.label
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
writer.setAttribute('$rootEditableOptions', rootEditableOptions, root);
|
|
629
577
|
};
|
|
630
|
-
if (isUndoable) {
|
|
578
|
+
if (options.isUndoable) {
|
|
631
579
|
this.model.change(_addRoot);
|
|
632
580
|
} else {
|
|
633
581
|
this.model.enqueueChange({
|
|
@@ -697,19 +645,17 @@ import { isElement as isElement$1 } from 'es-toolkit/compat';
|
|
|
697
645
|
}, (writer)=>writer.detachRoot(rootName));
|
|
698
646
|
}
|
|
699
647
|
}
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
const editable = this.ui.view.createEditable(root.rootName, undefined, label);
|
|
712
|
-
this.ui.addEditable(editable, placeholder);
|
|
648
|
+
createEditable(root, optionsOrPlaceholder, label) {
|
|
649
|
+
let placeholder;
|
|
650
|
+
if (!optionsOrPlaceholder || typeof optionsOrPlaceholder === 'string') {
|
|
651
|
+
placeholder = optionsOrPlaceholder;
|
|
652
|
+
} else {
|
|
653
|
+
placeholder = optionsOrPlaceholder?.placeholder;
|
|
654
|
+
label = optionsOrPlaceholder?.label;
|
|
655
|
+
}
|
|
656
|
+
const rootEditableConfig = root.getAttribute('$rootEditableOptions') || {};
|
|
657
|
+
const editable = this.ui.view.createEditable(root.rootName, undefined, label || rootEditableConfig.label);
|
|
658
|
+
this.ui.addEditable(editable, placeholder || rootEditableConfig.placeholder);
|
|
713
659
|
this.editing.view.forceRender();
|
|
714
660
|
return editable.element;
|
|
715
661
|
}
|
|
@@ -726,8 +672,8 @@ import { isElement as isElement$1 } from 'es-toolkit/compat';
|
|
|
726
672
|
return editable.element;
|
|
727
673
|
}
|
|
728
674
|
/**
|
|
729
|
-
* Loads a root that has previously been declared in
|
|
730
|
-
* configuration option.
|
|
675
|
+
* Loads a root that has previously been declared in
|
|
676
|
+
* {@link module:core/editor/editorconfig~EditorConfig#roots `config.roots.<rootName>.lazyLoad`} configuration option.
|
|
731
677
|
*
|
|
732
678
|
* **Important! Lazy roots loading is an experimental feature, and may become deprecated. Be advised of the following
|
|
733
679
|
* known limitations:**
|
|
@@ -756,7 +702,7 @@ import { isElement as isElement$1 } from 'es-toolkit/compat';
|
|
|
756
702
|
* Note that attributes loaded together with a root are automatically registered.
|
|
757
703
|
*
|
|
758
704
|
* See also {@link ~MultiRootEditor#registerRootAttribute `MultiRootEditor#registerRootAttribute()`} and
|
|
759
|
-
* {@link module:core/editor/editorconfig~EditorConfig#
|
|
705
|
+
* {@link module:core/editor/editorconfig~EditorConfig#roots `config.roots.<rootName>.modelAttributes` configuration option}.
|
|
760
706
|
*
|
|
761
707
|
* When this method is used in real-time collaboration environment, its effects become asynchronous as the editor will first synchronize
|
|
762
708
|
* with the remote editing session, before the root is added to the editor.
|
|
@@ -835,9 +781,10 @@ import { isElement as isElement$1 } from 'es-toolkit/compat';
|
|
|
835
781
|
* {@link ~MultiRootEditor#getRootAttributes `getRootAttributes()`} and
|
|
836
782
|
* {@link ~MultiRootEditor#getRootsAttributes `getRootsAttributes()`}.
|
|
837
783
|
*
|
|
838
|
-
* Note: attributes passed in
|
|
839
|
-
*
|
|
840
|
-
*
|
|
784
|
+
* Note: attributes passed in
|
|
785
|
+
* {@link module:core/editor/editorconfig~EditorConfig#roots `config.roots.<rootName>.modelAttributes`}
|
|
786
|
+
* are automatically registered as the editor is initialized. However, registering the same attribute twice does not have any
|
|
787
|
+
* negative impact, so it is recommended to use this method in any feature that uses roots attributes.
|
|
841
788
|
*/ registerRootAttribute(key) {
|
|
842
789
|
if (this._registeredRootsAttributesKeys.has(key)) {
|
|
843
790
|
return;
|
|
@@ -924,149 +871,21 @@ import { isElement as isElement$1 } from 'es-toolkit/compat';
|
|
|
924
871
|
locksForGivenRoot.delete(lockId);
|
|
925
872
|
}
|
|
926
873
|
}
|
|
927
|
-
|
|
928
|
-
* Creates a new multi-root editor instance.
|
|
929
|
-
*
|
|
930
|
-
* **Note:** remember that `MultiRootEditor` does not append the toolbar element to your web page, so you have to do it manually
|
|
931
|
-
* after the editor has been initialized.
|
|
932
|
-
*
|
|
933
|
-
* There are a few different ways to initialize the multi-root editor.
|
|
934
|
-
*
|
|
935
|
-
* # Using existing DOM elements:
|
|
936
|
-
*
|
|
937
|
-
* ```ts
|
|
938
|
-
* MultiRootEditor.create( {
|
|
939
|
-
* intro: document.querySelector( '#editor-intro' ),
|
|
940
|
-
* content: document.querySelector( '#editor-content' ),
|
|
941
|
-
* sidePanelLeft: document.querySelector( '#editor-side-left' ),
|
|
942
|
-
* sidePanelRight: document.querySelector( '#editor-side-right' ),
|
|
943
|
-
* outro: document.querySelector( '#editor-outro' )
|
|
944
|
-
* } )
|
|
945
|
-
* .then( editor => {
|
|
946
|
-
* console.log( 'Editor was initialized', editor );
|
|
947
|
-
*
|
|
948
|
-
* // Append the toolbar inside a provided DOM element.
|
|
949
|
-
* document.querySelector( '#toolbar-container' ).appendChild( editor.ui.view.toolbar.element );
|
|
950
|
-
* } )
|
|
951
|
-
* .catch( err => {
|
|
952
|
-
* console.error( err.stack );
|
|
953
|
-
* } );
|
|
954
|
-
* ```
|
|
955
|
-
*
|
|
956
|
-
* The elements' content will be used as the editor data and elements will become editable elements.
|
|
957
|
-
*
|
|
958
|
-
* # Creating a detached editor
|
|
959
|
-
*
|
|
960
|
-
* Alternatively, you can initialize the editor by passing the initial data directly as strings.
|
|
961
|
-
* In this case, you will have to manually append both the toolbar element and the editable elements to your web page.
|
|
962
|
-
*
|
|
963
|
-
* ```ts
|
|
964
|
-
* MultiRootEditor.create( {
|
|
965
|
-
* intro: '<p><strong>Exciting</strong> intro text to an article.</p>',
|
|
966
|
-
* content: '<p>Lorem ipsum dolor sit amet.</p>',
|
|
967
|
-
* sidePanelLeft: '<blockquote>Strong quotation from article.</blockquote>',
|
|
968
|
-
* sidePanelRight: '<p>List of similar articles...</p>',
|
|
969
|
-
* outro: '<p>Closing text.</p>'
|
|
970
|
-
* } )
|
|
971
|
-
* .then( editor => {
|
|
972
|
-
* console.log( 'Editor was initialized', editor );
|
|
973
|
-
*
|
|
974
|
-
* // Append the toolbar inside a provided DOM element.
|
|
975
|
-
* document.querySelector( '#toolbar-container' ).appendChild( editor.ui.view.toolbar.element );
|
|
976
|
-
*
|
|
977
|
-
* // Append DOM editable elements created by the editor.
|
|
978
|
-
* const editables = editor.ui.view.editables;
|
|
979
|
-
* const container = document.querySelector( '#editable-container' );
|
|
980
|
-
*
|
|
981
|
-
* container.appendChild( editables.intro.element );
|
|
982
|
-
* container.appendChild( editables.content.element );
|
|
983
|
-
* container.appendChild( editables.outro.element );
|
|
984
|
-
* } )
|
|
985
|
-
* .catch( err => {
|
|
986
|
-
* console.error( err.stack );
|
|
987
|
-
* } );
|
|
988
|
-
* ```
|
|
989
|
-
*
|
|
990
|
-
* This lets you dynamically append the editor to your web page whenever it is convenient for you. You may use this method if your
|
|
991
|
-
* web page content is generated on the client side and the DOM structure is not ready at the moment when you initialize the editor.
|
|
992
|
-
*
|
|
993
|
-
* # Using an existing DOM element (and data provided in `config.initialData`)
|
|
994
|
-
*
|
|
995
|
-
* You can also mix these two ways by providing a DOM element to be used and passing the initial data through the configuration:
|
|
996
|
-
*
|
|
997
|
-
* ```ts
|
|
998
|
-
* MultiRootEditor.create( {
|
|
999
|
-
* intro: document.querySelector( '#editor-intro' ),
|
|
1000
|
-
* content: document.querySelector( '#editor-content' ),
|
|
1001
|
-
* sidePanelLeft: document.querySelector( '#editor-side-left' ),
|
|
1002
|
-
* sidePanelRight: document.querySelector( '#editor-side-right' ),
|
|
1003
|
-
* outro: document.querySelector( '#editor-outro' )
|
|
1004
|
-
* }, {
|
|
1005
|
-
* initialData: {
|
|
1006
|
-
* intro: '<p><strong>Exciting</strong> intro text to an article.</p>',
|
|
1007
|
-
* content: '<p>Lorem ipsum dolor sit amet.</p>',
|
|
1008
|
-
* sidePanelLeft '<blockquote>Strong quotation from article.</blockquote>':
|
|
1009
|
-
* sidePanelRight '<p>List of similar articles...</p>':
|
|
1010
|
-
* outro: '<p>Closing text.</p>'
|
|
1011
|
-
* }
|
|
1012
|
-
* } )
|
|
1013
|
-
* .then( editor => {
|
|
1014
|
-
* console.log( 'Editor was initialized', editor );
|
|
1015
|
-
*
|
|
1016
|
-
* // Append the toolbar inside a provided DOM element.
|
|
1017
|
-
* document.querySelector( '#toolbar-container' ).appendChild( editor.ui.view.toolbar.element );
|
|
1018
|
-
* } )
|
|
1019
|
-
* .catch( err => {
|
|
1020
|
-
* console.error( err.stack );
|
|
1021
|
-
* } );
|
|
1022
|
-
* ```
|
|
1023
|
-
*
|
|
1024
|
-
* This method can be used to initialize the editor on an existing element with the specified content in case if your integration
|
|
1025
|
-
* makes it difficult to set the content of the source element.
|
|
1026
|
-
*
|
|
1027
|
-
* Note that an error will be thrown if you pass the initial data both as the first parameter and also in the configuration.
|
|
1028
|
-
*
|
|
1029
|
-
* # Configuring the editor
|
|
1030
|
-
*
|
|
1031
|
-
* See the {@link module:core/editor/editorconfig~EditorConfig editor configuration documentation} to learn more about
|
|
1032
|
-
* customizing plugins, toolbar and more.
|
|
1033
|
-
*
|
|
1034
|
-
* @param sourceElementsOrData The DOM elements that will be the source for the created editor
|
|
1035
|
-
* or the editor's initial data. The editor will initialize multiple roots with names according to the keys in the passed object.
|
|
1036
|
-
*
|
|
1037
|
-
* If DOM elements are passed, their content will be automatically loaded to the editor upon initialization and the elements will be
|
|
1038
|
-
* used as the editor's editable areas. The editor data will be set back to the original element once the editor is destroyed if the
|
|
1039
|
-
* {@link module:core/editor/editorconfig~EditorConfig#updateSourceElementOnDestroy updateSourceElementOnDestroy} option
|
|
1040
|
-
* is set to `true`.
|
|
1041
|
-
*
|
|
1042
|
-
* If the initial data is passed, a detached editor will be created. For each entry in the passed object, one editor root and one
|
|
1043
|
-
* editable DOM element will be created. You will need to attach the editable elements into the DOM manually. The elements are available
|
|
1044
|
-
* through the {@link module:editor-multi-root/multirooteditorui~MultiRootEditorUI#getEditableElement `editor.ui.getEditableElement()`}
|
|
1045
|
-
* method.
|
|
1046
|
-
* @param config The editor configuration.
|
|
1047
|
-
* @returns A promise resolved once the editor is ready. The promise resolves with the created editor instance.
|
|
1048
|
-
*/ static create(sourceElementsOrData, config = {}) {
|
|
874
|
+
static create(sourceElementsOrDataOrConfig, config = {}) {
|
|
1049
875
|
return new Promise((resolve)=>{
|
|
1050
|
-
|
|
1051
|
-
if (isElement(sourceItem) && sourceItem.tagName === 'TEXTAREA') {
|
|
1052
|
-
// Documented in core/editor/editor.js
|
|
1053
|
-
// eslint-disable-next-line ckeditor5-rules/ckeditor-error-message
|
|
1054
|
-
throw new CKEditorError('editor-wrong-element', null);
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
const editor = new this(sourceElementsOrData, config);
|
|
876
|
+
const editor = new this(sourceElementsOrDataOrConfig, config);
|
|
1058
877
|
resolve(editor.initPlugins().then(()=>editor.ui.init()).then(()=>{
|
|
878
|
+
const initialData = extractRootsConfigField(editor.config.get('roots'), 'initialData');
|
|
1059
879
|
// This is checked directly before setting the initial data,
|
|
1060
880
|
// as plugins may change `EditorConfig#initialData` value.
|
|
1061
|
-
editor._verifyRootsWithInitialData();
|
|
1062
|
-
return editor.data.init(
|
|
881
|
+
editor._verifyRootsWithInitialData(initialData);
|
|
882
|
+
return editor.data.init(initialData);
|
|
1063
883
|
}).then(()=>editor.fire('ready')).then(()=>editor));
|
|
1064
884
|
});
|
|
1065
885
|
}
|
|
1066
886
|
/**
|
|
1067
887
|
* @internal
|
|
1068
|
-
*/ _verifyRootsWithInitialData() {
|
|
1069
|
-
const initialData = this.config.get('initialData');
|
|
888
|
+
*/ _verifyRootsWithInitialData(initialData) {
|
|
1070
889
|
// Roots that are not in the initial data.
|
|
1071
890
|
for (const rootName of this.model.document.getRootNames()){
|
|
1072
891
|
if (!(rootName in initialData)) {
|
|
@@ -1095,8 +914,20 @@ import { isElement as isElement$1 } from 'es-toolkit/compat';
|
|
|
1095
914
|
}
|
|
1096
915
|
}
|
|
1097
916
|
}
|
|
1098
|
-
|
|
1099
|
-
|
|
917
|
+
/**
|
|
918
|
+
* Returns names of roots that are not lazy-loaded.
|
|
919
|
+
*/ function getNonLazyLoadRootsNames(rootsConfig) {
|
|
920
|
+
return rootsConfig.filter(([, { lazyLoad }])=>!lazyLoad).map(([rootName])=>rootName);
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* Collects a specific field from the editor configuration for all roots.
|
|
924
|
+
* Returns a simple map of root names and values of the specified field.
|
|
925
|
+
* If a root does not have the specified field defined, it is not included in the returned object.
|
|
926
|
+
*/ function extractRootsConfigField(rootsConfig, key) {
|
|
927
|
+
return Object.fromEntries(Object.entries(rootsConfig).filter(([, config])=>!config.lazyLoad).map(([rootName, config])=>[
|
|
928
|
+
rootName,
|
|
929
|
+
config[key]
|
|
930
|
+
]).filter(([, value])=>value !== undefined));
|
|
1100
931
|
}
|
|
1101
932
|
function isElement(value) {
|
|
1102
933
|
return isElement$1(value);
|