@ckeditor/ckeditor5-engine 35.0.1 → 35.1.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 (124) hide show
  1. package/CHANGELOG.md +4 -4
  2. package/package.json +30 -24
  3. package/src/controller/datacontroller.js +467 -561
  4. package/src/controller/editingcontroller.js +168 -204
  5. package/src/conversion/conversion.js +541 -565
  6. package/src/conversion/conversionhelpers.js +24 -28
  7. package/src/conversion/downcastdispatcher.js +457 -686
  8. package/src/conversion/downcasthelpers.js +1583 -1965
  9. package/src/conversion/mapper.js +518 -707
  10. package/src/conversion/modelconsumable.js +240 -283
  11. package/src/conversion/upcastdispatcher.js +372 -718
  12. package/src/conversion/upcasthelpers.js +707 -818
  13. package/src/conversion/viewconsumable.js +524 -581
  14. package/src/dataprocessor/basichtmlwriter.js +12 -16
  15. package/src/dataprocessor/dataprocessor.js +5 -0
  16. package/src/dataprocessor/htmldataprocessor.js +100 -116
  17. package/src/dataprocessor/htmlwriter.js +1 -18
  18. package/src/dataprocessor/xmldataprocessor.js +116 -137
  19. package/src/dev-utils/model.js +260 -352
  20. package/src/dev-utils/operationreplayer.js +106 -126
  21. package/src/dev-utils/utils.js +34 -51
  22. package/src/dev-utils/view.js +632 -753
  23. package/src/index.js +0 -11
  24. package/src/model/batch.js +111 -127
  25. package/src/model/differ.js +988 -1233
  26. package/src/model/document.js +340 -449
  27. package/src/model/documentfragment.js +327 -364
  28. package/src/model/documentselection.js +996 -1189
  29. package/src/model/element.js +306 -410
  30. package/src/model/history.js +224 -262
  31. package/src/model/item.js +5 -0
  32. package/src/model/liveposition.js +84 -145
  33. package/src/model/liverange.js +108 -185
  34. package/src/model/markercollection.js +379 -480
  35. package/src/model/model.js +883 -1034
  36. package/src/model/node.js +419 -463
  37. package/src/model/nodelist.js +175 -201
  38. package/src/model/operation/attributeoperation.js +153 -182
  39. package/src/model/operation/detachoperation.js +64 -83
  40. package/src/model/operation/insertoperation.js +135 -166
  41. package/src/model/operation/markeroperation.js +114 -140
  42. package/src/model/operation/mergeoperation.js +163 -191
  43. package/src/model/operation/moveoperation.js +157 -187
  44. package/src/model/operation/nooperation.js +28 -38
  45. package/src/model/operation/operation.js +106 -125
  46. package/src/model/operation/operationfactory.js +30 -34
  47. package/src/model/operation/renameoperation.js +109 -135
  48. package/src/model/operation/rootattributeoperation.js +155 -188
  49. package/src/model/operation/splitoperation.js +196 -232
  50. package/src/model/operation/transform.js +1833 -2204
  51. package/src/model/operation/utils.js +140 -204
  52. package/src/model/position.js +899 -1053
  53. package/src/model/range.js +910 -1028
  54. package/src/model/rootelement.js +77 -97
  55. package/src/model/schema.js +1189 -1835
  56. package/src/model/selection.js +745 -862
  57. package/src/model/text.js +90 -114
  58. package/src/model/textproxy.js +204 -240
  59. package/src/model/treewalker.js +316 -397
  60. package/src/model/typecheckable.js +16 -0
  61. package/src/model/utils/autoparagraphing.js +32 -44
  62. package/src/model/utils/deletecontent.js +334 -418
  63. package/src/model/utils/findoptimalinsertionrange.js +25 -36
  64. package/src/model/utils/getselectedcontent.js +96 -118
  65. package/src/model/utils/insertcontent.js +654 -773
  66. package/src/model/utils/insertobject.js +96 -119
  67. package/src/model/utils/modifyselection.js +120 -158
  68. package/src/model/utils/selection-post-fixer.js +153 -201
  69. package/src/model/writer.js +1305 -1474
  70. package/src/view/attributeelement.js +189 -225
  71. package/src/view/containerelement.js +75 -85
  72. package/src/view/document.js +172 -215
  73. package/src/view/documentfragment.js +200 -249
  74. package/src/view/documentselection.js +338 -367
  75. package/src/view/domconverter.js +1370 -1617
  76. package/src/view/downcastwriter.js +1747 -2076
  77. package/src/view/editableelement.js +81 -97
  78. package/src/view/element.js +739 -890
  79. package/src/view/elementdefinition.js +5 -0
  80. package/src/view/emptyelement.js +82 -92
  81. package/src/view/filler.js +35 -50
  82. package/src/view/item.js +5 -0
  83. package/src/view/matcher.js +260 -559
  84. package/src/view/node.js +274 -360
  85. package/src/view/observer/arrowkeysobserver.js +19 -28
  86. package/src/view/observer/bubblingemittermixin.js +120 -263
  87. package/src/view/observer/bubblingeventinfo.js +47 -55
  88. package/src/view/observer/clickobserver.js +7 -13
  89. package/src/view/observer/compositionobserver.js +14 -24
  90. package/src/view/observer/domeventdata.js +57 -67
  91. package/src/view/observer/domeventobserver.js +40 -64
  92. package/src/view/observer/fakeselectionobserver.js +81 -96
  93. package/src/view/observer/focusobserver.js +45 -61
  94. package/src/view/observer/inputobserver.js +7 -13
  95. package/src/view/observer/keyobserver.js +17 -27
  96. package/src/view/observer/mouseobserver.js +7 -14
  97. package/src/view/observer/mutationobserver.js +220 -315
  98. package/src/view/observer/observer.js +81 -102
  99. package/src/view/observer/selectionobserver.js +191 -246
  100. package/src/view/observer/tabobserver.js +23 -36
  101. package/src/view/placeholder.js +128 -173
  102. package/src/view/position.js +350 -401
  103. package/src/view/range.js +453 -513
  104. package/src/view/rawelement.js +85 -112
  105. package/src/view/renderer.js +874 -1018
  106. package/src/view/rooteditableelement.js +80 -90
  107. package/src/view/selection.js +608 -689
  108. package/src/view/styles/background.js +43 -44
  109. package/src/view/styles/border.js +220 -276
  110. package/src/view/styles/margin.js +8 -17
  111. package/src/view/styles/padding.js +8 -16
  112. package/src/view/styles/utils.js +127 -160
  113. package/src/view/stylesmap.js +728 -905
  114. package/src/view/text.js +102 -126
  115. package/src/view/textproxy.js +144 -170
  116. package/src/view/treewalker.js +383 -479
  117. package/src/view/typecheckable.js +19 -0
  118. package/src/view/uielement.js +166 -187
  119. package/src/view/upcastwriter.js +395 -449
  120. package/src/view/view.js +569 -664
  121. package/src/dataprocessor/dataprocessor.jsdoc +0 -64
  122. package/src/model/item.jsdoc +0 -14
  123. package/src/view/elementdefinition.jsdoc +0 -59
  124. package/src/view/item.jsdoc +0 -14
@@ -2,17 +2,13 @@
2
2
  * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
-
6
5
  /**
7
6
  * @module engine/view/attributeelement
8
7
  */
9
-
10
8
  import Element from './element';
11
9
  import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
12
-
13
10
  // Default attribute priority.
14
11
  const DEFAULT_PRIORITY = 10;
15
-
16
12
  /**
17
13
  * Attribute elements are used to represent formatting elements in the view (think – `<b>`, `<span style="font-size: 2em">`, etc.).
18
14
  * Most often they are created when downcasting model text attributes.
@@ -27,238 +23,206 @@ const DEFAULT_PRIORITY = 10;
27
23
  * @extends module:engine/view/element~Element
28
24
  */
29
25
  export default class AttributeElement extends Element {
30
- /**
31
- * Creates an attribute element.
32
- *
33
- * @see module:engine/view/downcastwriter~DowncastWriter#createAttributeElement
34
- * @see module:engine/view/element~Element
35
- * @protected
36
- * @param {module:engine/view/document~Document} document The document instance to which this element belongs.
37
- * @param {String} name Node name.
38
- * @param {Object|Iterable} [attrs] Collection of attributes.
39
- * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]
40
- * A list of nodes to be inserted into created element.
41
- */
42
- constructor( document, name, attrs, children ) {
43
- super( document, name, attrs, children );
44
-
45
- /**
46
- * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed.
47
- *
48
- * @method #getFillerOffset
49
- * @returns {Number|null} Block filler offset or `null` if block filler is not needed.
50
- */
51
- this.getFillerOffset = getFillerOffset;
52
-
53
- /**
54
- * Element priority. Decides in what order elements are wrapped by {@link module:engine/view/downcastwriter~DowncastWriter}.
55
- *
56
- * @protected
57
- * @member {Number}
58
- */
59
- this._priority = DEFAULT_PRIORITY;
60
-
61
- /**
62
- * Element identifier. If set, it is used by {@link module:engine/view/element~Element#isSimilar},
63
- * and then two elements are considered similar if, and only if they have the same `_id`.
64
- *
65
- * @protected
66
- * @member {String|Number}
67
- */
68
- this._id = null;
69
-
70
- /**
71
- * Keeps all the attribute elements that have the same {@link module:engine/view/attributeelement~AttributeElement#id ids}
72
- * and still exist in the view tree.
73
- *
74
- * This property is managed by {@link module:engine/view/downcastwriter~DowncastWriter}.
75
- *
76
- * @protected
77
- * @member {Set.<module:engine/view/attributeelement~AttributeElement>|null}
78
- */
79
- this._clonesGroup = null;
80
- }
81
-
82
- /**
83
- * Element priority. Decides in what order elements are wrapped by {@link module:engine/view/downcastwriter~DowncastWriter}.
84
- *
85
- * @readonly
86
- * @type {Number}
87
- */
88
- get priority() {
89
- return this._priority;
90
- }
91
-
92
- /**
93
- * Element identifier. If set, it is used by {@link module:engine/view/element~Element#isSimilar},
94
- * and then two elements are considered similar if, and only if they have the same `id`.
95
- *
96
- * @readonly
97
- * @type {String|Number}
98
- */
99
- get id() {
100
- return this._id;
101
- }
102
-
103
- /**
104
- * Returns all {@link module:engine/view/attributeelement~AttributeElement attribute elements} that has the
105
- * same {@link module:engine/view/attributeelement~AttributeElement#id id} and are in the view tree (were not removed).
106
- *
107
- * Note: If this element has been removed from the tree, returned set will not include it.
108
- *
109
- * Throws {@link module:utils/ckeditorerror~CKEditorError attribute-element-get-elements-with-same-id-no-id}
110
- * if this element has no `id`.
111
- *
112
- * @returns {Set.<module:engine/view/attributeelement~AttributeElement>} Set containing all the attribute elements
113
- * with the same `id` that were added and not removed from the view tree.
114
- */
115
- getElementsWithSameId() {
116
- if ( this.id === null ) {
117
- /**
118
- * Cannot get elements with the same id for an attribute element without id.
119
- *
120
- * @error attribute-element-get-elements-with-same-id-no-id
121
- */
122
- throw new CKEditorError(
123
- 'attribute-element-get-elements-with-same-id-no-id',
124
- this
125
- );
126
- }
127
-
128
- return new Set( this._clonesGroup );
129
- }
130
-
131
- /**
132
- * Checks whether this object is of the given.
133
- *
134
- * attributeElement.is( 'attributeElement' ); // -> true
135
- * attributeElement.is( 'element' ); // -> true
136
- * attributeElement.is( 'node' ); // -> true
137
- * attributeElement.is( 'view:attributeElement' ); // -> true
138
- * attributeElement.is( 'view:element' ); // -> true
139
- * attributeElement.is( 'view:node' ); // -> true
140
- *
141
- * attributeElement.is( 'model:element' ); // -> false
142
- * attributeElement.is( 'documentFragment' ); // -> false
143
- *
144
- * Assuming that the object being checked is an attribute element, you can also check its
145
- * {@link module:engine/view/attributeelement~AttributeElement#name name}:
146
- *
147
- * attributeElement.is( 'element', 'b' ); // -> true if this is a bold element
148
- * attributeElement.is( 'attributeElement', 'b' ); // -> same as above
149
- * text.is( 'element', 'b' ); -> false
150
- *
151
- * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.
152
- *
153
- * @param {String} type Type to check.
154
- * @param {String} [name] Element name.
155
- * @returns {Boolean}
156
- */
157
- is( type, name = null ) {
158
- if ( !name ) {
159
- return type === 'attributeElement' || type === 'view:attributeElement' ||
160
- // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
161
- type === 'element' || type === 'view:element' ||
162
- type === 'node' || type === 'view:node';
163
- } else {
164
- return name === this.name && (
165
- type === 'attributeElement' || type === 'view:attributeElement' ||
166
- // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
167
- type === 'element' || type === 'view:element'
168
- );
169
- }
170
- }
171
-
172
- /**
173
- * Checks if this element is similar to other element.
174
- *
175
- * If none of elements has set {@link module:engine/view/attributeelement~AttributeElement#id}, then both elements
176
- * should have the same name, attributes and priority to be considered as similar. Two similar elements can contain
177
- * different set of children nodes.
178
- *
179
- * If at least one element has {@link module:engine/view/attributeelement~AttributeElement#id} set, then both
180
- * elements have to have the same {@link module:engine/view/attributeelement~AttributeElement#id} value to be
181
- * considered similar.
182
- *
183
- * Similarity is important for {@link module:engine/view/downcastwriter~DowncastWriter}. For example:
184
- *
185
- * * two following similar elements can be merged together into one, longer element,
186
- * * {@link module:engine/view/downcastwriter~DowncastWriter#unwrap} checks similarity of passed element and processed element to
187
- * decide whether processed element should be unwrapped,
188
- * * etc.
189
- *
190
- * @param {module:engine/view/element~Element} otherElement
191
- * @returns {Boolean}
192
- */
193
- isSimilar( otherElement ) {
194
- // If any element has an `id` set, just compare the ids.
195
- if ( this.id !== null || otherElement.id !== null ) {
196
- return this.id === otherElement.id;
197
- }
198
-
199
- return super.isSimilar( otherElement ) && this.priority == otherElement.priority;
200
- }
201
-
202
- /**
203
- * Clones provided element with priority.
204
- *
205
- * @protected
206
- * @param {Boolean} deep If set to `true` clones element and all its children recursively. When set to `false`,
207
- * element will be cloned without any children.
208
- * @returns {module:engine/view/attributeelement~AttributeElement} Clone of this element.
209
- */
210
- _clone( deep ) {
211
- const cloned = super._clone( deep );
212
-
213
- // Clone priority too.
214
- cloned._priority = this._priority;
215
-
216
- // And id too.
217
- cloned._id = this._id;
218
-
219
- return cloned;
220
- }
26
+ /**
27
+ * Creates an attribute element.
28
+ *
29
+ * @see module:engine/view/downcastwriter~DowncastWriter#createAttributeElement
30
+ * @see module:engine/view/element~Element
31
+ * @protected
32
+ * @param {module:engine/view/document~Document} document The document instance to which this element belongs.
33
+ * @param {String} name Node name.
34
+ * @param {Object|Iterable} [attrs] Collection of attributes.
35
+ * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]
36
+ * A list of nodes to be inserted into created element.
37
+ */
38
+ constructor(...args) {
39
+ super(...args);
40
+ /**
41
+ * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed.
42
+ *
43
+ * @method #getFillerOffset
44
+ * @returns {Number|null} Block filler offset or `null` if block filler is not needed.
45
+ */
46
+ this.getFillerOffset = getFillerOffset;
47
+ /**
48
+ * Element priority. Decides in what order elements are wrapped by {@link module:engine/view/downcastwriter~DowncastWriter}.
49
+ *
50
+ * @protected
51
+ * @member {Number}
52
+ */
53
+ this._priority = DEFAULT_PRIORITY;
54
+ /**
55
+ * Element identifier. If set, it is used by {@link module:engine/view/element~Element#isSimilar},
56
+ * and then two elements are considered similar if, and only if they have the same `_id`.
57
+ *
58
+ * @protected
59
+ * @member {String|Number}
60
+ */
61
+ this._id = null;
62
+ /**
63
+ * Keeps all the attribute elements that have the same {@link module:engine/view/attributeelement~AttributeElement#id ids}
64
+ * and still exist in the view tree.
65
+ *
66
+ * This property is managed by {@link module:engine/view/downcastwriter~DowncastWriter}.
67
+ *
68
+ * @protected
69
+ * @member {Set.<module:engine/view/attributeelement~AttributeElement>|null}
70
+ */
71
+ this._clonesGroup = null;
72
+ }
73
+ /**
74
+ * Element priority. Decides in what order elements are wrapped by {@link module:engine/view/downcastwriter~DowncastWriter}.
75
+ *
76
+ * @readonly
77
+ * @type {Number}
78
+ */
79
+ get priority() {
80
+ return this._priority;
81
+ }
82
+ /**
83
+ * Element identifier. If set, it is used by {@link module:engine/view/element~Element#isSimilar},
84
+ * and then two elements are considered similar if, and only if they have the same `id`.
85
+ *
86
+ * @readonly
87
+ * @type {String|Number}
88
+ */
89
+ get id() {
90
+ return this._id;
91
+ }
92
+ /**
93
+ * Returns all {@link module:engine/view/attributeelement~AttributeElement attribute elements} that has the
94
+ * same {@link module:engine/view/attributeelement~AttributeElement#id id} and are in the view tree (were not removed).
95
+ *
96
+ * Note: If this element has been removed from the tree, returned set will not include it.
97
+ *
98
+ * Throws {@link module:utils/ckeditorerror~CKEditorError attribute-element-get-elements-with-same-id-no-id}
99
+ * if this element has no `id`.
100
+ *
101
+ * @returns {Set.<module:engine/view/attributeelement~AttributeElement>} Set containing all the attribute elements
102
+ * with the same `id` that were added and not removed from the view tree.
103
+ */
104
+ getElementsWithSameId() {
105
+ if (this.id === null) {
106
+ /**
107
+ * Cannot get elements with the same id for an attribute element without id.
108
+ *
109
+ * @error attribute-element-get-elements-with-same-id-no-id
110
+ */
111
+ throw new CKEditorError('attribute-element-get-elements-with-same-id-no-id', this);
112
+ }
113
+ return new Set(this._clonesGroup);
114
+ }
115
+ /**
116
+ * Checks if this element is similar to other element.
117
+ *
118
+ * If none of elements has set {@link module:engine/view/attributeelement~AttributeElement#id}, then both elements
119
+ * should have the same name, attributes and priority to be considered as similar. Two similar elements can contain
120
+ * different set of children nodes.
121
+ *
122
+ * If at least one element has {@link module:engine/view/attributeelement~AttributeElement#id} set, then both
123
+ * elements have to have the same {@link module:engine/view/attributeelement~AttributeElement#id} value to be
124
+ * considered similar.
125
+ *
126
+ * Similarity is important for {@link module:engine/view/downcastwriter~DowncastWriter}. For example:
127
+ *
128
+ * * two following similar elements can be merged together into one, longer element,
129
+ * * {@link module:engine/view/downcastwriter~DowncastWriter#unwrap} checks similarity of passed element and processed element to
130
+ * decide whether processed element should be unwrapped,
131
+ * * etc.
132
+ *
133
+ * @param {module:engine/view/element~Element} otherElement
134
+ * @returns {Boolean}
135
+ */
136
+ isSimilar(otherElement) {
137
+ // If any element has an `id` set, just compare the ids.
138
+ if (this.id !== null || otherElement.id !== null) {
139
+ return this.id === otherElement.id;
140
+ }
141
+ return super.isSimilar(otherElement) && this.priority == otherElement.priority;
142
+ }
143
+ /**
144
+ * Clones provided element with priority.
145
+ *
146
+ * @protected
147
+ * @param {Boolean} deep If set to `true` clones element and all its children recursively. When set to `false`,
148
+ * element will be cloned without any children.
149
+ * @returns {module:engine/view/attributeelement~AttributeElement} Clone of this element.
150
+ */
151
+ _clone(deep = false) {
152
+ const cloned = super._clone(deep);
153
+ // Clone priority too.
154
+ cloned._priority = this._priority;
155
+ // And id too.
156
+ cloned._id = this._id;
157
+ return cloned;
158
+ }
221
159
  }
222
-
160
+ AttributeElement.DEFAULT_PRIORITY = DEFAULT_PRIORITY;
223
161
  /**
224
- * Default attribute priority.
162
+ * Checks whether this object is of the given.
163
+ *
164
+ * attributeElement.is( 'attributeElement' ); // -> true
165
+ * attributeElement.is( 'element' ); // -> true
166
+ * attributeElement.is( 'node' ); // -> true
167
+ * attributeElement.is( 'view:attributeElement' ); // -> true
168
+ * attributeElement.is( 'view:element' ); // -> true
169
+ * attributeElement.is( 'view:node' ); // -> true
170
+ *
171
+ * attributeElement.is( 'model:element' ); // -> false
172
+ * attributeElement.is( 'documentFragment' ); // -> false
173
+ *
174
+ * Assuming that the object being checked is an attribute element, you can also check its
175
+ * {@link module:engine/view/attributeelement~AttributeElement#name name}:
225
176
  *
226
- * @member {Number} module:engine/view/attributeelement~AttributeElement.DEFAULT_PRIORITY
177
+ * attributeElement.is( 'element', 'b' ); // -> true if this is a bold element
178
+ * attributeElement.is( 'attributeElement', 'b' ); // -> same as above
179
+ * text.is( 'element', 'b' ); -> false
180
+ *
181
+ * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.
182
+ *
183
+ * @param {String} type Type to check.
184
+ * @param {String} [name] Element name.
185
+ * @returns {Boolean}
227
186
  */
228
- AttributeElement.DEFAULT_PRIORITY = DEFAULT_PRIORITY;
229
-
187
+ AttributeElement.prototype.is = function (type, name) {
188
+ if (!name) {
189
+ return type === 'attributeElement' || type === 'view:attributeElement' ||
190
+ // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
191
+ type === 'element' || type === 'view:element' ||
192
+ type === 'node' || type === 'view:node';
193
+ }
194
+ else {
195
+ return name === this.name && (type === 'attributeElement' || type === 'view:attributeElement' ||
196
+ // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
197
+ type === 'element' || type === 'view:element');
198
+ }
199
+ };
230
200
  // Returns block {@link module:engine/view/filler~Filler filler} offset or `null` if block filler is not needed.
231
201
  //
232
202
  // @returns {Number|null} Block filler offset or `null` if block filler is not needed.
233
203
  function getFillerOffset() {
234
- // <b>foo</b> does not need filler.
235
- if ( nonUiChildrenCount( this ) ) {
236
- return null;
237
- }
238
-
239
- let element = this.parent;
240
-
241
- // <p><b></b></p> needs filler -> <p><b><br></b></p>
242
- while ( element && element.is( 'attributeElement' ) ) {
243
- if ( nonUiChildrenCount( element ) > 1 ) {
244
- return null;
245
- }
246
-
247
- element = element.parent;
248
- }
249
-
250
- if ( !element || nonUiChildrenCount( element ) > 1 ) {
251
- return null;
252
- }
253
-
254
- // Render block filler at the end of element (after all ui elements).
255
- return this.childCount;
204
+ // <b>foo</b> does not need filler.
205
+ if (nonUiChildrenCount(this)) {
206
+ return null;
207
+ }
208
+ let element = this.parent;
209
+ // <p><b></b></p> needs filler -> <p><b><br></b></p>
210
+ while (element && element.is('attributeElement')) {
211
+ if (nonUiChildrenCount(element) > 1) {
212
+ return null;
213
+ }
214
+ element = element.parent;
215
+ }
216
+ if (!element || nonUiChildrenCount(element) > 1) {
217
+ return null;
218
+ }
219
+ // Render block filler at the end of element (after all ui elements).
220
+ return this.childCount;
256
221
  }
257
-
258
222
  // Returns total count of children that are not {@link module:engine/view/uielement~UIElement UIElements}.
259
223
  //
260
224
  // @param {module:engine/view/element~Element} element
261
225
  // @returns {Number}
262
- function nonUiChildrenCount( element ) {
263
- return Array.from( element.getChildren() ).filter( element => !element.is( 'uiElement' ) ).length;
226
+ function nonUiChildrenCount(element) {
227
+ return Array.from(element.getChildren()).filter(element => !element.is('uiElement')).length;
264
228
  }
@@ -2,13 +2,10 @@
2
2
  * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
-
6
5
  /**
7
6
  * @module engine/view/containerelement
8
7
  */
9
-
10
8
  import Element from './element';
11
-
12
9
  /**
13
10
  * Containers are elements which define document structure. They define boundaries for
14
11
  * {@link module:engine/view/attributeelement~AttributeElement attributes}. They are mostly used for block elements like `<p>` or `<div>`.
@@ -31,93 +28,86 @@ import Element from './element';
31
28
  * @extends module:engine/view/element~Element
32
29
  */
33
30
  export default class ContainerElement extends Element {
34
- /**
35
- * Creates a container element.
36
- *
37
- * @see module:engine/view/downcastwriter~DowncastWriter#createContainerElement
38
- * @see module:engine/view/element~Element
39
- * @protected
40
- * @param {module:engine/view/document~Document} document The document instance to which this element belongs.
41
- * @param {String} name Node name.
42
- * @param {Object|Iterable} [attrs] Collection of attributes.
43
- * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]
44
- * A list of nodes to be inserted into created element.
45
- */
46
- constructor( document, name, attrs, children ) {
47
- super( document, name, attrs, children );
48
-
49
- /**
50
- * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed.
51
- *
52
- * @method #getFillerOffset
53
- * @returns {Number|null} Block filler offset or `null` if block filler is not needed.
54
- */
55
- this.getFillerOffset = getFillerOffset;
56
- }
57
-
58
- /**
59
- * Checks whether this object is of the given.
60
- *
61
- * containerElement.is( 'containerElement' ); // -> true
62
- * containerElement.is( 'element' ); // -> true
63
- * containerElement.is( 'node' ); // -> true
64
- * containerElement.is( 'view:containerElement' ); // -> true
65
- * containerElement.is( 'view:element' ); // -> true
66
- * containerElement.is( 'view:node' ); // -> true
67
- *
68
- * containerElement.is( 'model:element' ); // -> false
69
- * containerElement.is( 'documentFragment' ); // -> false
70
- *
71
- * Assuming that the object being checked is a container element, you can also check its
72
- * {@link module:engine/view/containerelement~ContainerElement#name name}:
73
- *
74
- * containerElement.is( 'element', 'div' ); // -> true if this is a div container element
75
- * containerElement.is( 'contaienrElement', 'div' ); // -> same as above
76
- * text.is( 'element', 'div' ); -> false
77
- *
78
- * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.
79
- *
80
- * @param {String} type Type to check.
81
- * @param {String} [name] Element name.
82
- * @returns {Boolean}
83
- */
84
- is( type, name = null ) {
85
- if ( !name ) {
86
- return type === 'containerElement' || type === 'view:containerElement' ||
87
- // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
88
- type === 'element' || type === 'view:element' ||
89
- type === 'node' || type === 'view:node';
90
- } else {
91
- return name === this.name && (
92
- type === 'containerElement' || type === 'view:containerElement' ||
93
- // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
94
- type === 'element' || type === 'view:element'
95
- );
96
- }
97
- }
31
+ /**
32
+ * Creates a container element.
33
+ *
34
+ * @see module:engine/view/downcastwriter~DowncastWriter#createContainerElement
35
+ * @see module:engine/view/element~Element
36
+ * @protected
37
+ * @param {module:engine/view/document~Document} document The document instance to which this element belongs.
38
+ * @param {String} name Node name.
39
+ * @param {Object|Iterable} [attrs] Collection of attributes.
40
+ * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]
41
+ * A list of nodes to be inserted into created element.
42
+ */
43
+ constructor(...args) {
44
+ super(...args);
45
+ /**
46
+ * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed.
47
+ *
48
+ * @method #getFillerOffset
49
+ * @returns {Number|null} Block filler offset or `null` if block filler is not needed.
50
+ */
51
+ this.getFillerOffset = getFillerOffset;
52
+ }
98
53
  }
99
-
54
+ /**
55
+ * Checks whether this object is of the given.
56
+ *
57
+ * containerElement.is( 'containerElement' ); // -> true
58
+ * containerElement.is( 'element' ); // -> true
59
+ * containerElement.is( 'node' ); // -> true
60
+ * containerElement.is( 'view:containerElement' ); // -> true
61
+ * containerElement.is( 'view:element' ); // -> true
62
+ * containerElement.is( 'view:node' ); // -> true
63
+ *
64
+ * containerElement.is( 'model:element' ); // -> false
65
+ * containerElement.is( 'documentFragment' ); // -> false
66
+ *
67
+ * Assuming that the object being checked is a container element, you can also check its
68
+ * {@link module:engine/view/containerelement~ContainerElement#name name}:
69
+ *
70
+ * containerElement.is( 'element', 'div' ); // -> true if this is a div container element
71
+ * containerElement.is( 'contaienrElement', 'div' ); // -> same as above
72
+ * text.is( 'element', 'div' ); -> false
73
+ *
74
+ * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.
75
+ *
76
+ * @param {String} type Type to check.
77
+ * @param {String} [name] Element name.
78
+ * @returns {Boolean}
79
+ */
80
+ ContainerElement.prototype.is = function (type, name) {
81
+ if (!name) {
82
+ return type === 'containerElement' || type === 'view:containerElement' ||
83
+ // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
84
+ type === 'element' || type === 'view:element' ||
85
+ type === 'node' || type === 'view:node';
86
+ }
87
+ else {
88
+ return name === this.name && (type === 'containerElement' || type === 'view:containerElement' ||
89
+ // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
90
+ type === 'element' || type === 'view:element');
91
+ }
92
+ };
100
93
  /**
101
94
  * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed.
102
95
  *
103
96
  * @returns {Number|null} Block filler offset or `null` if block filler is not needed.
104
97
  */
105
98
  export function getFillerOffset() {
106
- const children = [ ...this.getChildren() ];
107
- const lastChild = children[ this.childCount - 1 ];
108
-
109
- // Block filler is required after a `<br>` if it's the last element in its container. See #1422.
110
- if ( lastChild && lastChild.is( 'element', 'br' ) ) {
111
- return this.childCount;
112
- }
113
-
114
- for ( const child of children ) {
115
- // If there's any non-UI element – don't render the bogus.
116
- if ( !child.is( 'uiElement' ) ) {
117
- return null;
118
- }
119
- }
120
-
121
- // If there are only UI elements – render the bogus at the end of the element.
122
- return this.childCount;
99
+ const children = [...this.getChildren()];
100
+ const lastChild = children[this.childCount - 1];
101
+ // Block filler is required after a `<br>` if it's the last element in its container. See #1422.
102
+ if (lastChild && lastChild.is('element', 'br')) {
103
+ return this.childCount;
104
+ }
105
+ for (const child of children) {
106
+ // If there's any non-UI element – don't render the bogus.
107
+ if (!child.is('uiElement')) {
108
+ return null;
109
+ }
110
+ }
111
+ // If there are only UI elements – render the bogus at the end of the element.
112
+ return this.childCount;
123
113
  }