@ckeditor/ckeditor5-engine 37.0.0-alpha.2 → 37.0.0-rc.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.
Files changed (55) hide show
  1. package/package.json +23 -23
  2. package/src/controller/datacontroller.d.ts +3 -0
  3. package/src/controller/datacontroller.js +16 -1
  4. package/src/index.d.ts +4 -2
  5. package/src/index.js +4 -0
  6. package/src/model/differ.d.ts +52 -8
  7. package/src/model/differ.js +104 -4
  8. package/src/model/document.d.ts +17 -7
  9. package/src/model/document.js +44 -5
  10. package/src/model/documentfragment.d.ts +4 -0
  11. package/src/model/documentfragment.js +6 -0
  12. package/src/model/node.d.ts +4 -4
  13. package/src/model/node.js +9 -5
  14. package/src/model/operation/attributeoperation.d.ts +1 -1
  15. package/src/model/operation/attributeoperation.js +1 -1
  16. package/src/model/operation/insertoperation.d.ts +1 -1
  17. package/src/model/operation/insertoperation.js +1 -1
  18. package/src/model/operation/mergeoperation.d.ts +1 -1
  19. package/src/model/operation/mergeoperation.js +1 -1
  20. package/src/model/operation/moveoperation.d.ts +1 -1
  21. package/src/model/operation/moveoperation.js +1 -1
  22. package/src/model/operation/operation.d.ts +1 -1
  23. package/src/model/operation/operation.js +1 -1
  24. package/src/model/operation/operationfactory.js +2 -0
  25. package/src/model/operation/rootattributeoperation.d.ts +7 -11
  26. package/src/model/operation/rootattributeoperation.js +6 -6
  27. package/src/model/operation/rootoperation.d.ts +75 -0
  28. package/src/model/operation/rootoperation.js +108 -0
  29. package/src/model/operation/splitoperation.d.ts +1 -1
  30. package/src/model/operation/splitoperation.js +1 -1
  31. package/src/model/operation/transform.js +8 -0
  32. package/src/model/rootelement.d.ts +15 -1
  33. package/src/model/rootelement.js +17 -1
  34. package/src/model/writer.d.ts +29 -1
  35. package/src/model/writer.js +74 -1
  36. package/src/view/matcher.d.ts +2 -2
  37. package/src/view/matcher.js +2 -2
  38. package/src/view/observer/arrowkeysobserver.d.ts +4 -0
  39. package/src/view/observer/arrowkeysobserver.js +4 -0
  40. package/src/view/observer/domeventobserver.d.ts +4 -0
  41. package/src/view/observer/domeventobserver.js +6 -0
  42. package/src/view/observer/fakeselectionobserver.d.ts +4 -0
  43. package/src/view/observer/fakeselectionobserver.js +4 -0
  44. package/src/view/observer/mutationobserver.d.ts +4 -0
  45. package/src/view/observer/mutationobserver.js +16 -2
  46. package/src/view/observer/observer.d.ts +7 -2
  47. package/src/view/observer/selectionobserver.d.ts +4 -0
  48. package/src/view/observer/selectionobserver.js +6 -0
  49. package/src/view/observer/tabobserver.d.ts +4 -0
  50. package/src/view/observer/tabobserver.js +4 -0
  51. package/src/view/placeholder.js +3 -3
  52. package/src/view/renderer.d.ts +4 -4
  53. package/src/view/renderer.js +17 -25
  54. package/src/view/view.d.ts +21 -3
  55. package/src/view/view.js +21 -3
package/src/model/node.js CHANGED
@@ -63,7 +63,7 @@ export default class Node extends TypeCheckable {
63
63
  return null;
64
64
  }
65
65
  /**
66
- * Index of this node in it's parent or `null` if the node has no parent.
66
+ * Index of this node in its parent or `null` if the node has no parent.
67
67
  *
68
68
  * Accessing this property throws an error if this node's parent element does not contain it.
69
69
  * This means that model tree got broken.
@@ -79,8 +79,8 @@ export default class Node extends TypeCheckable {
79
79
  return pos;
80
80
  }
81
81
  /**
82
- * Offset at which this node starts in it's parent. It is equal to the sum of {@link #offsetSize offsetSize}
83
- * of all it's previous siblings. Equals to `null` if node has no parent.
82
+ * Offset at which this node starts in its parent. It is equal to the sum of {@link #offsetSize offsetSize}
83
+ * of all its previous siblings. Equals to `null` if node has no parent.
84
84
  *
85
85
  * Accessing this property throws an error if this node's parent element does not contain it.
86
86
  * This means that model tree got broken.
@@ -142,10 +142,14 @@ export default class Node extends TypeCheckable {
142
142
  return root;
143
143
  }
144
144
  /**
145
- * Returns true if the node is in a tree rooted in the document (is a descendant of one of its roots).
145
+ * Returns `true` if the node is inside a document root that is attached to the document.
146
146
  */
147
147
  isAttached() {
148
- return this.root.is('rootElement');
148
+ // If the node has no parent it means that it is a root.
149
+ // But this is not a `RootElement`, so it means that it is not attached.
150
+ //
151
+ // If this is not the root, check if this element's root is attached.
152
+ return this.parent === null ? false : this.root.isAttached();
149
153
  }
150
154
  /**
151
155
  * Gets path to the node. The path is an array containing starting offsets of consecutive ancestors of this node,
@@ -89,7 +89,7 @@ export default class AttributeOperation extends Operation {
89
89
  */
90
90
  static get className(): string;
91
91
  /**
92
- * Creates `AttributeOperation` object from deserilized object, i.e. from parsed JSON string.
92
+ * Creates `AttributeOperation` object from deserialized object, i.e. from parsed JSON string.
93
93
  *
94
94
  * @param json Deserialized JSON object.
95
95
  * @param document Document on which this operation will be applied.
@@ -131,7 +131,7 @@ export default class AttributeOperation extends Operation {
131
131
  return 'AttributeOperation';
132
132
  }
133
133
  /**
134
- * Creates `AttributeOperation` object from deserilized object, i.e. from parsed JSON string.
134
+ * Creates `AttributeOperation` object from deserialized object, i.e. from parsed JSON string.
135
135
  *
136
136
  * @param json Deserialized JSON object.
137
137
  * @param document Document on which this operation will be applied.
@@ -76,7 +76,7 @@ export default class InsertOperation extends Operation {
76
76
  */
77
77
  static get className(): string;
78
78
  /**
79
- * Creates `InsertOperation` object from deserilized object, i.e. from parsed JSON string.
79
+ * Creates `InsertOperation` object from deserialized object, i.e. from parsed JSON string.
80
80
  *
81
81
  * @param json Deserialized JSON object.
82
82
  * @param document Document on which this operation will be applied.
@@ -105,7 +105,7 @@ export default class InsertOperation extends Operation {
105
105
  return 'InsertOperation';
106
106
  }
107
107
  /**
108
- * Creates `InsertOperation` object from deserilized object, i.e. from parsed JSON string.
108
+ * Creates `InsertOperation` object from deserialized object, i.e. from parsed JSON string.
109
109
  *
110
110
  * @param json Deserialized JSON object.
111
111
  * @param document Document on which this operation will be applied.
@@ -86,7 +86,7 @@ export default class MergeOperation extends Operation {
86
86
  */
87
87
  static get className(): string;
88
88
  /**
89
- * Creates `MergeOperation` object from deserilized object, i.e. from parsed JSON string.
89
+ * Creates `MergeOperation` object from deserialized object, i.e. from parsed JSON string.
90
90
  *
91
91
  * @param json Deserialized JSON object.
92
92
  * @param document Document on which this operation will be applied.
@@ -141,7 +141,7 @@ export default class MergeOperation extends Operation {
141
141
  return 'MergeOperation';
142
142
  }
143
143
  /**
144
- * Creates `MergeOperation` object from deserilized object, i.e. from parsed JSON string.
144
+ * Creates `MergeOperation` object from deserialized object, i.e. from parsed JSON string.
145
145
  *
146
146
  * @param json Deserialized JSON object.
147
147
  * @param document Document on which this operation will be applied.
@@ -82,7 +82,7 @@ export default class MoveOperation extends Operation {
82
82
  */
83
83
  static get className(): string;
84
84
  /**
85
- * Creates `MoveOperation` object from deserilized object, i.e. from parsed JSON string.
85
+ * Creates `MoveOperation` object from deserialized object, i.e. from parsed JSON string.
86
86
  *
87
87
  * @param json Deserialized JSON object.
88
88
  * @param document Document on which this operation will be applied.
@@ -142,7 +142,7 @@ export default class MoveOperation extends Operation {
142
142
  return 'MoveOperation';
143
143
  }
144
144
  /**
145
- * Creates `MoveOperation` object from deserilized object, i.e. from parsed JSON string.
145
+ * Creates `MoveOperation` object from deserialized object, i.e. from parsed JSON string.
146
146
  *
147
147
  * @param json Deserialized JSON object.
148
148
  * @param document Document on which this operation will be applied.
@@ -80,7 +80,7 @@ export default abstract class Operation {
80
80
  */
81
81
  static get className(): string;
82
82
  /**
83
- * Creates Operation object from deserilized object, i.e. from parsed JSON string.
83
+ * Creates `Operation` object from deserialized object, i.e. from parsed JSON string.
84
84
  *
85
85
  * @param json Deserialized JSON object.
86
86
  * @param doc Document on which this operation will be applied.
@@ -51,7 +51,7 @@ export default class Operation {
51
51
  return 'Operation';
52
52
  }
53
53
  /**
54
- * Creates Operation object from deserilized object, i.e. from parsed JSON string.
54
+ * Creates `Operation` object from deserialized object, i.e. from parsed JSON string.
55
55
  *
56
56
  * @param json Deserialized JSON object.
57
57
  * @param doc Document on which this operation will be applied.
@@ -13,6 +13,7 @@ import NoOperation from './nooperation';
13
13
  import Operation from './operation';
14
14
  import RenameOperation from './renameoperation';
15
15
  import RootAttributeOperation from './rootattributeoperation';
16
+ import RootOperation from './rootoperation';
16
17
  import SplitOperation from './splitoperation';
17
18
  import MergeOperation from './mergeoperation';
18
19
  const operations = {};
@@ -24,6 +25,7 @@ operations[NoOperation.className] = NoOperation;
24
25
  operations[Operation.className] = Operation;
25
26
  operations[RenameOperation.className] = RenameOperation;
26
27
  operations[RootAttributeOperation.className] = RootAttributeOperation;
28
+ operations[RootOperation.className] = RootOperation;
27
29
  operations[SplitOperation.className] = SplitOperation;
28
30
  operations[MergeOperation.className] = MergeOperation;
29
31
  /**
@@ -21,24 +21,20 @@ import type RootElement from '../rootelement';
21
21
  export default class RootAttributeOperation extends Operation {
22
22
  /**
23
23
  * Root element to change.
24
- *
25
- * @readonly
26
24
  */
27
- root: RootElement;
25
+ readonly root: RootElement;
28
26
  /**
29
27
  * Key of an attribute to change or remove.
30
- *
31
- * @readonly
32
28
  */
33
- key: string;
29
+ readonly key: string;
34
30
  /**
35
- * Old value of the attribute with given key or `null` if adding a new attribute.
31
+ * Old value of the attribute with given key or `null`, if attribute was not set before.
36
32
  *
37
33
  * @readonly
38
34
  */
39
35
  oldValue: unknown;
40
36
  /**
41
- * New value to set for the attribute. If `null`, then the operation just removes the attribute.
37
+ * New value of the attribute with given key or `null`, if operation should remove attribute.
42
38
  *
43
39
  * @readonly
44
40
  */
@@ -49,8 +45,8 @@ export default class RootAttributeOperation extends Operation {
49
45
  * @see module:engine/model/operation/attributeoperation~AttributeOperation
50
46
  * @param root Root element to change.
51
47
  * @param key Key of an attribute to change or remove.
52
- * @param oldValue Old value of the attribute with given key or `null` if adding a new attribute.
53
- * @param newValue New value to set for the attribute. If `null`, then the operation just removes the attribute.
48
+ * @param oldValue Old value of the attribute with given key or `null`, if attribute was not set before.
49
+ * @param newValue New value of the attribute with given key or `null`, if operation should remove attribute.
54
50
  * @param baseVersion Document {@link module:engine/model/document~Document#version} on which operation
55
51
  * can be applied or `null` if the operation operates on detached (non-document) tree.
56
52
  */
@@ -88,7 +84,7 @@ export default class RootAttributeOperation extends Operation {
88
84
  */
89
85
  static get className(): string;
90
86
  /**
91
- * Creates RootAttributeOperation object from deserilized object, i.e. from parsed JSON string.
87
+ * Creates `RootAttributeOperation` object from deserialized object, i.e. from parsed JSON string.
92
88
  *
93
89
  * @param json Deserialized JSON object.
94
90
  * @param document Document on which this operation will be applied.
@@ -24,8 +24,8 @@ export default class RootAttributeOperation extends Operation {
24
24
  * @see module:engine/model/operation/attributeoperation~AttributeOperation
25
25
  * @param root Root element to change.
26
26
  * @param key Key of an attribute to change or remove.
27
- * @param oldValue Old value of the attribute with given key or `null` if adding a new attribute.
28
- * @param newValue New value to set for the attribute. If `null`, then the operation just removes the attribute.
27
+ * @param oldValue Old value of the attribute with given key or `null`, if attribute was not set before.
28
+ * @param newValue New value of the attribute with given key or `null`, if operation should remove attribute.
29
29
  * @param baseVersion Document {@link module:engine/model/document~Document#version} on which operation
30
30
  * can be applied or `null` if the operation operates on detached (non-document) tree.
31
31
  */
@@ -33,8 +33,8 @@ export default class RootAttributeOperation extends Operation {
33
33
  super(baseVersion);
34
34
  this.root = root;
35
35
  this.key = key;
36
- this.oldValue = oldValue;
37
- this.newValue = newValue;
36
+ this.oldValue = oldValue === undefined ? null : oldValue;
37
+ this.newValue = newValue === undefined ? null : newValue;
38
38
  }
39
39
  /**
40
40
  * @inheritDoc
@@ -82,7 +82,7 @@ export default class RootAttributeOperation extends Operation {
82
82
  }
83
83
  if (this.oldValue !== null && this.root.getAttribute(this.key) !== this.oldValue) {
84
84
  /**
85
- * The attribute which should be removed does not exists for the given node.
85
+ * The attribute which should be removed does not exist for the given node.
86
86
  *
87
87
  * @error rootattribute-operation-wrong-old-value
88
88
  * @param root
@@ -129,7 +129,7 @@ export default class RootAttributeOperation extends Operation {
129
129
  return 'RootAttributeOperation';
130
130
  }
131
131
  /**
132
- * Creates RootAttributeOperation object from deserilized object, i.e. from parsed JSON string.
132
+ * Creates `RootAttributeOperation` object from deserialized object, i.e. from parsed JSON string.
133
133
  *
134
134
  * @param json Deserialized JSON object.
135
135
  * @param document Document on which this operation will be applied.
@@ -0,0 +1,75 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module engine/model/operation/rootoperation
7
+ */
8
+ import Operation from './operation';
9
+ import type Document from '../document';
10
+ /**
11
+ * Operation that creates (or attaches) or detaches a root element.
12
+ */
13
+ export default class RootOperation extends Operation {
14
+ /**
15
+ * Root name to create or detach.
16
+ */
17
+ readonly rootName: string;
18
+ /**
19
+ * Root element name.
20
+ */
21
+ readonly elementName: string;
22
+ /**
23
+ * Specifies whether the operation adds (`true`) or detaches the root (`false`).
24
+ */
25
+ readonly isAdd: boolean;
26
+ /**
27
+ * Document which owns the root.
28
+ */
29
+ private readonly _document;
30
+ /**
31
+ * Creates an operation that creates or removes a root element.
32
+ *
33
+ * @param rootName Root name to create or detach.
34
+ * @param elementName Root element name.
35
+ * @param isAdd Specifies whether the operation adds (`true`) or detaches the root (`false`).
36
+ * @param document Document which owns the root.
37
+ * @param baseVersion Document {@link module:engine/model/document~Document#version} on which operation can be applied.
38
+ */
39
+ constructor(rootName: string, elementName: string, isAdd: boolean, document: Document, baseVersion: number);
40
+ /**
41
+ * @inheritDoc
42
+ */
43
+ get type(): 'addRoot' | 'detachRoot';
44
+ /**
45
+ * @inheritDoc
46
+ */
47
+ clone(): RootOperation;
48
+ /**
49
+ * @inheritDoc
50
+ */
51
+ getReversed(): RootOperation;
52
+ /**
53
+ * @inheritDoc
54
+ */
55
+ _validate(): void;
56
+ /**
57
+ * @inheritDoc
58
+ */
59
+ _execute(): void;
60
+ /**
61
+ * @inheritDoc
62
+ */
63
+ toJSON(): unknown;
64
+ /**
65
+ * @inheritDoc
66
+ */
67
+ static get className(): string;
68
+ /**
69
+ * Creates `RootOperation` object from deserialized object, i.e. from parsed JSON string.
70
+ *
71
+ * @param json Deserialized JSON object.
72
+ * @param document Document on which this operation will be applied.
73
+ */
74
+ static fromJSON(json: any, document: Document): RootOperation;
75
+ }
@@ -0,0 +1,108 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module engine/model/operation/rootoperation
7
+ */
8
+ import Operation from './operation';
9
+ import { CKEditorError } from '@ckeditor/ckeditor5-utils';
10
+ /**
11
+ * Operation that creates (or attaches) or detaches a root element.
12
+ */
13
+ export default class RootOperation extends Operation {
14
+ /**
15
+ * Creates an operation that creates or removes a root element.
16
+ *
17
+ * @param rootName Root name to create or detach.
18
+ * @param elementName Root element name.
19
+ * @param isAdd Specifies whether the operation adds (`true`) or detaches the root (`false`).
20
+ * @param document Document which owns the root.
21
+ * @param baseVersion Document {@link module:engine/model/document~Document#version} on which operation can be applied.
22
+ */
23
+ constructor(rootName, elementName, isAdd, document, baseVersion) {
24
+ super(baseVersion);
25
+ this.rootName = rootName;
26
+ this.elementName = elementName;
27
+ this.isAdd = isAdd;
28
+ this._document = document;
29
+ // Make sure that the root exists ASAP, this is important for RTC.
30
+ // If the root was dynamically added, there will be more operations that operate on/in this root.
31
+ // These operations will require root element instance (in operation property or in position instance).
32
+ // If the root is not created ahead of time, instantiating such operations may fail.
33
+ if (!this._document.getRoot(this.rootName)) {
34
+ const root = this._document.createRoot(this.elementName, this.rootName);
35
+ root._isAttached = false;
36
+ }
37
+ }
38
+ /**
39
+ * @inheritDoc
40
+ */
41
+ get type() {
42
+ return this.isAdd ? 'addRoot' : 'detachRoot';
43
+ }
44
+ /**
45
+ * @inheritDoc
46
+ */
47
+ clone() {
48
+ return new RootOperation(this.rootName, this.elementName, this.isAdd, this._document, this.baseVersion);
49
+ }
50
+ /**
51
+ * @inheritDoc
52
+ */
53
+ getReversed() {
54
+ return new RootOperation(this.rootName, this.elementName, !this.isAdd, this._document, this.baseVersion + 1);
55
+ }
56
+ /**
57
+ * @inheritDoc
58
+ */
59
+ _validate() {
60
+ // Keep in mind that at this point the root will always exist as it was created in the `constructor()`, even for detach operation.
61
+ const root = this._document.getRoot(this.rootName);
62
+ if (root.isAttached() && this.isAdd) {
63
+ /**
64
+ * Trying to attach a root that is already attached.
65
+ *
66
+ * @error root-operation-root-attached
67
+ */
68
+ throw new CKEditorError('root-operation-root-attached', this);
69
+ }
70
+ else if (!root.isAttached() && !this.isAdd) {
71
+ /**
72
+ * Trying to detach a root that is already detached.
73
+ *
74
+ * @error root-operation-root-detached
75
+ */
76
+ throw new CKEditorError('root-operation-root-detached', this);
77
+ }
78
+ }
79
+ /**
80
+ * @inheritDoc
81
+ */
82
+ _execute() {
83
+ this._document.getRoot(this.rootName)._isAttached = this.isAdd;
84
+ }
85
+ /**
86
+ * @inheritDoc
87
+ */
88
+ toJSON() {
89
+ const json = super.toJSON();
90
+ delete json._document;
91
+ return json;
92
+ }
93
+ /**
94
+ * @inheritDoc
95
+ */
96
+ static get className() {
97
+ return 'RootOperation';
98
+ }
99
+ /**
100
+ * Creates `RootOperation` object from deserialized object, i.e. from parsed JSON string.
101
+ *
102
+ * @param json Deserialized JSON object.
103
+ * @param document Document on which this operation will be applied.
104
+ */
105
+ static fromJSON(json, document) {
106
+ return new RootOperation(json.rootName, json.elementName, json.isAdd, document, json.baseVersion);
107
+ }
108
+ }
@@ -95,7 +95,7 @@ export default class SplitOperation extends Operation {
95
95
  */
96
96
  static getInsertionPosition(splitPosition: Position): Position;
97
97
  /**
98
- * Creates `SplitOperation` object from deserilized object, i.e. from parsed JSON string.
98
+ * Creates `SplitOperation` object from deserialized object, i.e. from parsed JSON string.
99
99
  *
100
100
  * @param json Deserialized JSON object.
101
101
  * @param document Document on which this operation will be applied.
@@ -166,7 +166,7 @@ export default class SplitOperation extends Operation {
166
166
  return new Position(splitPosition.root, path, 'toPrevious');
167
167
  }
168
168
  /**
169
- * Creates `SplitOperation` object from deserilized object, i.e. from parsed JSON string.
169
+ * Creates `SplitOperation` object from deserialized object, i.e. from parsed JSON string.
170
170
  *
171
171
  * @param json Deserialized JSON object.
172
172
  * @param document Document on which this operation will be applied.
@@ -8,6 +8,7 @@ import RenameOperation from './renameoperation';
8
8
  import MarkerOperation from './markeroperation';
9
9
  import MoveOperation from './moveoperation';
10
10
  import RootAttributeOperation from './rootattributeoperation';
11
+ import RootOperation from './rootoperation';
11
12
  import MergeOperation from './mergeoperation';
12
13
  import SplitOperation from './splitoperation';
13
14
  import NoOperation from './nooperation';
@@ -1640,6 +1641,13 @@ setTransformation(RootAttributeOperation, RootAttributeOperation, (a, b, context
1640
1641
  return [a];
1641
1642
  });
1642
1643
  // -----------------------
1644
+ setTransformation(RootOperation, RootOperation, (a, b, context) => {
1645
+ if (a.rootName === b.rootName && a.isAdd === b.isAdd && !context.bWasUndone) {
1646
+ return [new NoOperation(0)];
1647
+ }
1648
+ return [a];
1649
+ });
1650
+ // -----------------------
1643
1651
  setTransformation(SplitOperation, InsertOperation, (a, b) => {
1644
1652
  // The default case.
1645
1653
  //
@@ -19,6 +19,10 @@ export default class RootElement extends Element {
19
19
  * Document that is an owner of this root.
20
20
  */
21
21
  private readonly _document;
22
+ /**
23
+ * @internal
24
+ */
25
+ _isAttached: boolean;
22
26
  /**
23
27
  * Creates root element.
24
28
  *
@@ -32,7 +36,17 @@ export default class RootElement extends Element {
32
36
  */
33
37
  get document(): Document;
34
38
  /**
35
- * Converts `RootElement` instance to `string` containing it's name.
39
+ * Informs if the root element is currently attached to the document, or not.
40
+ *
41
+ * A detached root is equivalent to being removed and cannot contain any children or markers.
42
+ *
43
+ * By default, a newly added root is attached. It can be detached using
44
+ * {@link module:engine/model/writer~Writer#detachRoot `Writer#detachRoot`}. A detached root can be re-attached again using
45
+ * {@link module:engine/model/writer~Writer#addRoot `Writer#addRoot`}.
46
+ */
47
+ isAttached(): boolean;
48
+ /**
49
+ * Converts `RootElement` instance to `string` containing its name.
36
50
  *
37
51
  * @returns `RootElement` instance converted to `string`.
38
52
  */
@@ -19,6 +19,10 @@ export default class RootElement extends Element {
19
19
  */
20
20
  constructor(document, name, rootName = 'main') {
21
21
  super(name);
22
+ /**
23
+ * @internal
24
+ */
25
+ this._isAttached = true;
22
26
  this._document = document;
23
27
  this.rootName = rootName;
24
28
  }
@@ -29,7 +33,19 @@ export default class RootElement extends Element {
29
33
  return this._document;
30
34
  }
31
35
  /**
32
- * Converts `RootElement` instance to `string` containing it's name.
36
+ * Informs if the root element is currently attached to the document, or not.
37
+ *
38
+ * A detached root is equivalent to being removed and cannot contain any children or markers.
39
+ *
40
+ * By default, a newly added root is attached. It can be detached using
41
+ * {@link module:engine/model/writer~Writer#detachRoot `Writer#detachRoot`}. A detached root can be re-attached again using
42
+ * {@link module:engine/model/writer~Writer#addRoot `Writer#addRoot`}.
43
+ */
44
+ isAttached() {
45
+ return this._isAttached;
46
+ }
47
+ /**
48
+ * Converts `RootElement` instance to `string` containing its name.
33
49
  *
34
50
  * @returns `RootElement` instance converted to `string`.
35
51
  */
@@ -6,6 +6,7 @@ import DocumentFragment from './documentfragment';
6
6
  import Element from './element';
7
7
  import Position, { type PositionOffset, type PositionStickiness } from './position';
8
8
  import Range from './range';
9
+ import RootElement from './rootelement';
9
10
  import Text from './text';
10
11
  import type { Marker } from './markercollection';
11
12
  import type { default as Selection, PlaceOrOffset, Selectable } from './selection';
@@ -366,7 +367,7 @@ export default class Writer {
366
367
  * writer.move( sourceRange, image, 'after' );
367
368
  * ```
368
369
  *
369
- * These parameters works the same way as {@link #createPositionAt `writer.createPositionAt()`}.
370
+ * These parameters work the same way as {@link #createPositionAt `writer.createPositionAt()`}.
370
371
  *
371
372
  * Note that items can be moved only within the same tree. It means that you can move items within the same root
372
373
  * (element or document fragment) or between {@link module:engine/model/document~Document#roots documents roots},
@@ -623,6 +624,33 @@ export default class Writer {
623
624
  * @param markerOrName Marker or marker name to remove.
624
625
  */
625
626
  removeMarker(markerOrName: string | Marker): void;
627
+ /**
628
+ * Adds a new root to the document (or re-attaches a {@link #detachRoot detached root}).
629
+ *
630
+ * Throws an error, if trying to add a root that is already added and attached.
631
+ *
632
+ * @param rootName Name of the added root.
633
+ * @param elementName The element name. Defaults to `'$root'` which also has some basic schema defined
634
+ * (e.g. `$block` elements are allowed inside the `$root`). Make sure to define a proper schema if you use a different name.
635
+ * @returns The added root element.
636
+ */
637
+ addRoot(rootName: string, elementName?: string): RootElement;
638
+ /**
639
+ * Detaches the root from the document.
640
+ *
641
+ * All content and markers are removed from the root upon detaching. New content and new markers cannot be added to the root, as long
642
+ * as it is detached.
643
+ *
644
+ * A root cannot be fully removed from the document, it can be only detached. A root is permanently removed only after you
645
+ * re-initialize the editor and do not specify the root in the initial data.
646
+ *
647
+ * A detached root can be re-attached using {@link #addRoot}.
648
+ *
649
+ * Throws an error if the root does not exist or the root is already detached.
650
+ *
651
+ * @param rootOrName Name of the detached root.
652
+ */
653
+ detachRoot(rootOrName: string | RootElement): void;
626
654
  /**
627
655
  * Sets the document's selection (ranges and direction) to the specified location based on the given
628
656
  * {@link module:engine/model/selection~Selectable selectable} or creates an empty selection if no arguments were passed.