@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/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 { CKEditorError, logWarning, decodeLicenseKey, isFeatureBlockedByLicenseKey, setDataInElement, getDataFromElement } from '@ckeditor/ckeditor5-utils/dist/index.js';
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
- const configPlaceholder = this.editor.config.get('placeholder');
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 ? options.editableElements[editableName] : undefined;
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 {@link module:core/editor/editorconfig~EditorConfig#rootsAttributes `rootsAttributes`}
318
- * config property and should be returned by {@link #getRootsAttributes}.
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
- * Creates an instance of the multi-root editor.
325
- *
326
- * **Note:** Do not use the constructor to create editor instances. Use the static
327
- * {@link module:editor-multi-root/multirooteditor~MultiRootEditor.create `MultiRootEditor.create()`} method instead.
328
- *
329
- * @param sourceElementsOrData The DOM elements that will be the source for the created editor
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
- super(config);
342
- if (!sourceIsData) {
343
- this.sourceElements = sourceElementsOrData;
344
- } else {
345
- this.sourceElements = {};
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('initialData') === undefined) {
348
- // Create initial data object containing data from all roots.
349
- const initialData = {};
350
- for (const rootName of rootNames){
351
- initialData[rootName] = getInitialData(sourceElementsOrData[rootName]);
352
- }
353
- this.config.set('initialData', initialData);
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
- if (!sourceIsData) {
356
- for (const rootName of rootNames){
357
- secureSourceElement(this, sourceElementsOrData[rootName]);
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 rootNames){
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
- if (this.config.get('rootsAttributes')) {
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
- this.data.on('init', ()=>{
407
- this.model.enqueueChange({
408
- isUndoable: false
409
- }, (writer)=>{
410
- for (const [name, attributes] of Object.entries(rootsAttributes)){
411
- const root = this.model.document.getRoot(name);
412
- for (const [key, value] of Object.entries(attributes)){
413
- if (value !== null) {
414
- writer.setAttribute(key, value, root);
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: sourceIsData ? undefined : sourceElementsOrData,
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, rootNames, options);
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
- * Adds a new root to the editor.
549
- *
550
- * ```ts
551
- * editor.addRoot( 'myRoot', { data: '<p>Initial root data.</p>' } );
552
- * ```
553
- *
554
- * After a root is added, you will be able to modify and retrieve its data.
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, elementName);
622
- if (data) {
623
- writer.insert(this.data.parse(data, root), root, 0);
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(attributes)){
563
+ for (const key of Object.keys(modelAttributes)){
626
564
  this.registerRootAttribute(key);
627
- writer.setAttribute(key, attributes[key], root);
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
- * Creates and returns a new DOM editable element for the given root element.
702
- *
703
- * The new DOM editable is attached to the model root and can be used to modify the root content.
704
- *
705
- * @param root Root for which the editable element should be created.
706
- * @param placeholder Placeholder for the editable element. If not set, placeholder value from the
707
- * {@link module:core/editor/editorconfig~EditorConfig#placeholder editor configuration} will be used (if it was provided).
708
- * @param label The accessible label text describing the editable to the assistive technologies.
709
- * @returns The created DOM element. Append it in a desired place in your application.
710
- */ createEditable(root, placeholder, label) {
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 {@link module:core/editor/editorconfig~EditorConfig#lazyRoots `lazyRoots`}
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#rootsAttributes `config.rootsAttributes` configuration option}.
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 {@link module:core/editor/editorconfig~EditorConfig#rootsAttributes `config.rootsAttributes`} are
839
- * automatically registered as the editor is initialized. However, registering the same attribute twice does not have any negative
840
- * impact, so it is recommended to use this method in any feature that uses roots attributes.
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
- for (const sourceItem of Object.values(sourceElementsOrData)){
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(editor.config.get('initialData'));
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
- function getInitialData(sourceElementOrData) {
1099
- return isElement(sourceElementOrData) ? getDataFromElement(sourceElementOrData) : sourceElementOrData;
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);