@ckeditor/ckeditor5-engine 27.1.0 → 29.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +1 -1
- package/README.md +3 -3
- package/package.json +22 -21
- package/src/controller/datacontroller.js +28 -7
- package/src/controller/editingcontroller.js +1 -1
- package/src/conversion/conversion.js +4 -4
- package/src/conversion/downcastdispatcher.js +6 -2
- package/src/conversion/downcasthelpers.js +48 -39
- package/src/conversion/mapper.js +1 -0
- package/src/conversion/modelconsumable.js +10 -5
- package/src/conversion/upcastdispatcher.js +6 -6
- package/src/conversion/upcasthelpers.js +34 -30
- package/src/dataprocessor/dataprocessor.jsdoc +5 -5
- package/src/dataprocessor/htmldataprocessor.js +38 -9
- package/src/dataprocessor/xmldataprocessor.js +5 -5
- package/src/index.js +1 -0
- package/src/model/element.js +3 -3
- package/src/model/liveposition.js +1 -1
- package/src/model/model.js +5 -5
- package/src/model/node.js +3 -3
- package/src/model/range.js +5 -3
- package/src/model/schema.js +103 -39
- package/src/model/selection.js +1 -1
- package/src/model/treewalker.js +3 -4
- package/src/model/utils/deletecontent.js +17 -4
- package/src/model/utils/insertcontent.js +15 -15
- package/src/model/utils/selection-post-fixer.js +1 -1
- package/src/view/documentselection.js +2 -2
- package/src/view/domconverter.js +150 -72
- package/src/view/downcastwriter.js +2 -1
- package/src/view/element.js +3 -2
- package/src/view/filler.js +4 -4
- package/src/view/matcher.js +419 -93
- package/src/view/observer/focusobserver.js +7 -3
- package/src/view/observer/mouseobserver.js +1 -1
- package/src/view/renderer.js +9 -1
- package/src/view/selection.js +2 -2
- package/src/view/styles/background.js +2 -0
- package/src/view/styles/border.js +107 -21
- package/src/view/styles/utils.js +1 -1
- package/src/view/stylesmap.js +45 -5
- package/src/view/upcastwriter.js +12 -11
- package/src/view/view.js +5 -0
package/src/model/schema.js
CHANGED
|
@@ -18,23 +18,23 @@ import Text from './text';
|
|
|
18
18
|
import TreeWalker from './treewalker';
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
* The model's schema. It defines allowed and disallowed structures of nodes as well as nodes' attributes.
|
|
22
|
-
* The schema is usually defined by features and based on them the editing framework and features
|
|
23
|
-
* make decisions how to change and process the model.
|
|
21
|
+
* The model's schema. It defines the allowed and disallowed structures of nodes as well as nodes' attributes.
|
|
22
|
+
* The schema is usually defined by the features and based on them, the editing framework and features
|
|
23
|
+
* make decisions on how to change and process the model.
|
|
24
24
|
*
|
|
25
25
|
* The instance of schema is available in {@link module:engine/model/model~Model#schema `editor.model.schema`}.
|
|
26
26
|
*
|
|
27
27
|
* Read more about the schema in:
|
|
28
28
|
*
|
|
29
|
-
* * {@glink framework/guides/architecture/editing-engine#schema
|
|
30
|
-
* {@glink framework/guides/architecture/editing-engine Introduction to the Editing engine architecture}.
|
|
31
|
-
* * {@glink framework/guides/deep-dive/schema Schema deep dive} guide.
|
|
29
|
+
* * The {@glink framework/guides/architecture/editing-engine#schema schema section} of the
|
|
30
|
+
* {@glink framework/guides/architecture/editing-engine Introduction to the Editing engine architecture} guide.
|
|
31
|
+
* * The {@glink framework/guides/deep-dive/schema Schema deep dive} guide.
|
|
32
32
|
*
|
|
33
33
|
* @mixes module:utils/observablemixin~ObservableMixin
|
|
34
34
|
*/
|
|
35
35
|
export default class Schema {
|
|
36
36
|
/**
|
|
37
|
-
* Creates schema instance.
|
|
37
|
+
* Creates a schema instance.
|
|
38
38
|
*/
|
|
39
39
|
constructor() {
|
|
40
40
|
this._sourceDefinitions = {};
|
|
@@ -61,7 +61,7 @@ export default class Schema {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
|
-
* Registers schema item. Can only be called once for every item name.
|
|
64
|
+
* Registers a schema item. Can only be called once for every item name.
|
|
65
65
|
*
|
|
66
66
|
* schema.register( 'paragraph', {
|
|
67
67
|
* inheritAllFrom: '$block'
|
|
@@ -205,6 +205,7 @@ export default class Schema {
|
|
|
205
205
|
* schema.isRegistered( 'foo' ); // -> false
|
|
206
206
|
*
|
|
207
207
|
* @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item
|
|
208
|
+
* @returns {Boolean}
|
|
208
209
|
*/
|
|
209
210
|
isRegistered( item ) {
|
|
210
211
|
return !!this.getDefinition( item );
|
|
@@ -220,10 +221,11 @@ export default class Schema {
|
|
|
220
221
|
* const paragraphElement = writer.createElement( 'paragraph' );
|
|
221
222
|
* schema.isBlock( paragraphElement ); // -> true
|
|
222
223
|
*
|
|
223
|
-
* See the {@glink framework/guides/deep-dive/schema#block-elements Block elements} section of
|
|
224
|
-
* guide for more details.
|
|
224
|
+
* See the {@glink framework/guides/deep-dive/schema#block-elements Block elements} section of
|
|
225
|
+
* the {@glink framework/guides/deep-dive/schema Schema deep dive} guide for more details.
|
|
225
226
|
*
|
|
226
227
|
* @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item
|
|
228
|
+
* @returns {Boolean}
|
|
227
229
|
*/
|
|
228
230
|
isBlock( item ) {
|
|
229
231
|
const def = this.getDefinition( item );
|
|
@@ -243,12 +245,13 @@ export default class Schema {
|
|
|
243
245
|
* schema.isLimit( 'paragraph' ); // -> false
|
|
244
246
|
* schema.isLimit( '$root' ); // -> true
|
|
245
247
|
* schema.isLimit( editor.model.document.getRoot() ); // -> true
|
|
246
|
-
* schema.isLimit( '
|
|
248
|
+
* schema.isLimit( 'imageBlock' ); // -> true
|
|
247
249
|
*
|
|
248
|
-
* See the {@glink framework/guides/deep-dive/schema#limit-elements Limit elements} section of
|
|
249
|
-
* guide for more details.
|
|
250
|
+
* See the {@glink framework/guides/deep-dive/schema#limit-elements Limit elements} section of
|
|
251
|
+
* the {@glink framework/guides/deep-dive/schema Schema deep dive} guide for more details.
|
|
250
252
|
*
|
|
251
253
|
* @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item
|
|
254
|
+
* @returns {Boolean}
|
|
252
255
|
*/
|
|
253
256
|
isLimit( item ) {
|
|
254
257
|
const def = this.getDefinition( item );
|
|
@@ -269,15 +272,16 @@ export default class Schema {
|
|
|
269
272
|
* was set to `true`.
|
|
270
273
|
*
|
|
271
274
|
* schema.isObject( 'paragraph' ); // -> false
|
|
272
|
-
* schema.isObject( '
|
|
275
|
+
* schema.isObject( 'imageBlock' ); // -> true
|
|
273
276
|
*
|
|
274
|
-
* const imageElement = writer.createElement( '
|
|
277
|
+
* const imageElement = writer.createElement( 'imageBlock' );
|
|
275
278
|
* schema.isObject( imageElement ); // -> true
|
|
276
279
|
*
|
|
277
|
-
* See the {@glink framework/guides/deep-dive/schema#object-elements Object elements} section of
|
|
278
|
-
* guide for more details.
|
|
280
|
+
* See the {@glink framework/guides/deep-dive/schema#object-elements Object elements} section of
|
|
281
|
+
* the {@glink framework/guides/deep-dive/schema Schema deep dive} guide for more details.
|
|
279
282
|
*
|
|
280
283
|
* @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item
|
|
284
|
+
* @returns {Boolean}
|
|
281
285
|
*/
|
|
282
286
|
isObject( item ) {
|
|
283
287
|
const def = this.getDefinition( item );
|
|
@@ -301,10 +305,11 @@ export default class Schema {
|
|
|
301
305
|
* const text = writer.createText( 'foo' );
|
|
302
306
|
* schema.isInline( text ); // -> true
|
|
303
307
|
*
|
|
304
|
-
* See the {@glink framework/guides/deep-dive/schema#inline-elements Inline elements} section of
|
|
305
|
-
* guide for more details.
|
|
308
|
+
* See the {@glink framework/guides/deep-dive/schema#inline-elements Inline elements} section of
|
|
309
|
+
* the {@glink framework/guides/deep-dive/schema Schema deep dive} guide for more details.
|
|
306
310
|
*
|
|
307
311
|
* @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item
|
|
312
|
+
* @returns {Boolean}
|
|
308
313
|
*/
|
|
309
314
|
isInline( item ) {
|
|
310
315
|
const def = this.getDefinition( item );
|
|
@@ -318,16 +323,17 @@ export default class Schema {
|
|
|
318
323
|
*
|
|
319
324
|
* schema.isSelectable( 'paragraph' ); // -> false
|
|
320
325
|
* schema.isSelectable( 'heading1' ); // -> false
|
|
321
|
-
* schema.isSelectable( '
|
|
326
|
+
* schema.isSelectable( 'imageBlock' ); // -> true
|
|
322
327
|
* schema.isSelectable( 'tableCell' ); // -> true
|
|
323
328
|
*
|
|
324
329
|
* const text = writer.createText( 'foo' );
|
|
325
330
|
* schema.isSelectable( text ); // -> false
|
|
326
331
|
*
|
|
327
|
-
* See the {@glink framework/guides/deep-dive/schema#selectable-elements Selectable elements
|
|
328
|
-
* guide for more details.
|
|
332
|
+
* See the {@glink framework/guides/deep-dive/schema#selectable-elements Selectable elements section} of
|
|
333
|
+
* the {@glink framework/guides/deep-dive/schema Schema deep dive} guide for more details.
|
|
329
334
|
*
|
|
330
335
|
* @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item
|
|
336
|
+
* @returns {Boolean}
|
|
331
337
|
*/
|
|
332
338
|
isSelectable( item ) {
|
|
333
339
|
const def = this.getDefinition( item );
|
|
@@ -345,16 +351,17 @@ export default class Schema {
|
|
|
345
351
|
*
|
|
346
352
|
* schema.isContent( 'paragraph' ); // -> false
|
|
347
353
|
* schema.isContent( 'heading1' ); // -> false
|
|
348
|
-
* schema.isContent( '
|
|
354
|
+
* schema.isContent( 'imageBlock' ); // -> true
|
|
349
355
|
* schema.isContent( 'horizontalLine' ); // -> true
|
|
350
356
|
*
|
|
351
357
|
* const text = writer.createText( 'foo' );
|
|
352
358
|
* schema.isContent( text ); // -> true
|
|
353
359
|
*
|
|
354
|
-
* See the {@glink framework/guides/deep-dive/schema#content-elements Content elements
|
|
355
|
-
* guide for more details.
|
|
360
|
+
* See the {@glink framework/guides/deep-dive/schema#content-elements Content elements section} of
|
|
361
|
+
* the {@glink framework/guides/deep-dive/schema Schema deep dive} guide for more details.
|
|
356
362
|
*
|
|
357
363
|
* @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item
|
|
364
|
+
* @returns {Boolean}
|
|
358
365
|
*/
|
|
359
366
|
isContent( item ) {
|
|
360
367
|
const def = this.getDefinition( item );
|
|
@@ -384,6 +391,7 @@ export default class Schema {
|
|
|
384
391
|
* @fires checkChild
|
|
385
392
|
* @param {module:engine/model/schema~SchemaContextDefinition} context The context in which the child will be checked.
|
|
386
393
|
* @param {module:engine/model/node~Node|String} def The child to check.
|
|
394
|
+
* @returns {Boolean}
|
|
387
395
|
*/
|
|
388
396
|
checkChild( context, def ) {
|
|
389
397
|
// Note: context and child are already normalized here to a SchemaContext and SchemaCompiledItemDefinition.
|
|
@@ -408,6 +416,7 @@ export default class Schema {
|
|
|
408
416
|
* @fires checkAttribute
|
|
409
417
|
* @param {module:engine/model/schema~SchemaContextDefinition} context The context in which the attribute will be checked.
|
|
410
418
|
* @param {String} attributeName
|
|
419
|
+
* @returns {Boolean}
|
|
411
420
|
*/
|
|
412
421
|
checkAttribute( context, attributeName ) {
|
|
413
422
|
const def = this.getDefinition( context.last );
|
|
@@ -883,6 +892,10 @@ export default class Schema {
|
|
|
883
892
|
compiledDefinitions[ itemName ] = compileBaseItemRule( sourceRules[ itemName ], itemName );
|
|
884
893
|
}
|
|
885
894
|
|
|
895
|
+
for ( const itemName of itemNames ) {
|
|
896
|
+
compileAllowChildren( compiledDefinitions, itemName );
|
|
897
|
+
}
|
|
898
|
+
|
|
886
899
|
for ( const itemName of itemNames ) {
|
|
887
900
|
compileAllowContentOf( compiledDefinitions, itemName );
|
|
888
901
|
}
|
|
@@ -898,6 +911,7 @@ export default class Schema {
|
|
|
898
911
|
|
|
899
912
|
for ( const itemName of itemNames ) {
|
|
900
913
|
cleanUpAllowIn( compiledDefinitions, itemName );
|
|
914
|
+
setupAllowChildren( compiledDefinitions, itemName );
|
|
901
915
|
cleanUpAllowAttributes( compiledDefinitions, itemName );
|
|
902
916
|
}
|
|
903
917
|
|
|
@@ -1090,6 +1104,7 @@ mix( Schema, ObservableMixin );
|
|
|
1090
1104
|
* You can define the following rules:
|
|
1091
1105
|
*
|
|
1092
1106
|
* * {@link ~SchemaItemDefinition#allowIn `allowIn`} – Defines in which other items this item will be allowed.
|
|
1107
|
+
* * {@link ~SchemaItemDefinition#allowChildren `allowChildren`} – Defines which other items are allowed inside this item.
|
|
1093
1108
|
* * {@link ~SchemaItemDefinition#allowAttributes `allowAttributes`} – Defines allowed attributes of the given item.
|
|
1094
1109
|
* * {@link ~SchemaItemDefinition#allowContentOf `allowContentOf`} – Inherits "allowed children" from other items.
|
|
1095
1110
|
* * {@link ~SchemaItemDefinition#allowWhere `allowWhere`} – Inherits "allowed in" from other items.
|
|
@@ -1112,7 +1127,7 @@ mix( Schema, ObservableMixin );
|
|
|
1112
1127
|
* In other words, all actions that happen inside a limit element are limited to its content.
|
|
1113
1128
|
* All objects are treated as limit elements, too.
|
|
1114
1129
|
* * {@link ~SchemaItemDefinition#isObject `isObject`} – Whether an item is "self-contained" and should be treated as a whole.
|
|
1115
|
-
* Examples of object elements: `
|
|
1130
|
+
* Examples of object elements: `imageBlock`, `table`, `video`, etc. An object is also a limit, so
|
|
1116
1131
|
* {@link module:engine/model/schema~Schema#isLimit `isLimit()`} returns `true` for object elements automatically.
|
|
1117
1132
|
*
|
|
1118
1133
|
* Read more about the meaning of these types in the
|
|
@@ -1157,21 +1172,29 @@ mix( Schema, ObservableMixin );
|
|
|
1157
1172
|
* isBlock: true
|
|
1158
1173
|
* } );
|
|
1159
1174
|
*
|
|
1160
|
-
*
|
|
1175
|
+
* Allow `paragraph` inside a `$root` and allow `$text` as a `paragraph` child:
|
|
1176
|
+
*
|
|
1177
|
+
* schema.register( 'paragraph', {
|
|
1178
|
+
* allowIn: '$root',
|
|
1179
|
+
* allowChildren: '$text',
|
|
1180
|
+
* isBlock: true
|
|
1181
|
+
* } );
|
|
1182
|
+
*
|
|
1183
|
+
* Make `imageBlock` a block object, which is allowed everywhere where `$block` is.
|
|
1161
1184
|
* Also, allow `src` and `alt` attributes in it:
|
|
1162
1185
|
*
|
|
1163
|
-
* schema.register( '
|
|
1186
|
+
* schema.register( 'imageBlock', {
|
|
1164
1187
|
* allowWhere: '$block',
|
|
1165
1188
|
* allowAttributes: [ 'src', 'alt' ],
|
|
1166
1189
|
* isBlock: true,
|
|
1167
1190
|
* isObject: true
|
|
1168
1191
|
* } );
|
|
1169
1192
|
*
|
|
1170
|
-
* Make `caption` allowed in `
|
|
1193
|
+
* Make `caption` allowed in `imageBlock` and make it allow all the content of `$block`s (usually, `$text`).
|
|
1171
1194
|
* Also, mark it as a limit element so it cannot be split:
|
|
1172
1195
|
*
|
|
1173
1196
|
* schema.register( 'caption', {
|
|
1174
|
-
* allowIn: '
|
|
1197
|
+
* allowIn: 'imageBlock',
|
|
1175
1198
|
* allowContentOf: '$block',
|
|
1176
1199
|
* isLimit: true
|
|
1177
1200
|
* } );
|
|
@@ -1205,6 +1228,7 @@ mix( Schema, ObservableMixin );
|
|
|
1205
1228
|
* @typedef {Object} module:engine/model/schema~SchemaItemDefinition
|
|
1206
1229
|
*
|
|
1207
1230
|
* @property {String|Array.<String>} allowIn Defines in which other items this item will be allowed.
|
|
1231
|
+
* @property {String|Array.<String>} allowChildren Defines which other items are allowed inside this item.
|
|
1208
1232
|
* @property {String|Array.<String>} allowAttributes Defines allowed attributes of the given item.
|
|
1209
1233
|
* @property {String|Array.<String>} allowContentOf Inherits "allowed children" from other items.
|
|
1210
1234
|
* @property {String|Array.<String>} allowWhere Inherits "allowed in" from other items.
|
|
@@ -1219,14 +1243,15 @@ mix( Schema, ObservableMixin );
|
|
|
1219
1243
|
* Most block type items will inherit from `$block` (through `inheritAllFrom`).
|
|
1220
1244
|
*
|
|
1221
1245
|
* Read more about the block elements in the
|
|
1222
|
-
* {@glink framework/guides/deep-dive/schema#block-elements Block elements
|
|
1246
|
+
* {@glink framework/guides/deep-dive/schema#block-elements Block elements section} of
|
|
1247
|
+
* the {@glink framework/guides/deep-dive/schema Schema deep dive}.
|
|
1223
1248
|
*
|
|
1224
1249
|
* @property {Boolean} isInline
|
|
1225
1250
|
* Whether an item is "text-like" and should be treated as an inline node. Examples of inline elements:
|
|
1226
1251
|
* `$text`, `softBreak` (`<br>`), etc.
|
|
1227
1252
|
*
|
|
1228
1253
|
* Read more about the inline elements in the
|
|
1229
|
-
* {@glink framework/guides/deep-dive/schema#inline-elements Inline elements
|
|
1254
|
+
* {@glink framework/guides/deep-dive/schema#inline-elements Inline elements section} of the Schema deep dive guide.
|
|
1230
1255
|
*
|
|
1231
1256
|
* @property {Boolean} isLimit
|
|
1232
1257
|
* It can be understood as whether this element should not be split by <kbd>Enter</kbd>.
|
|
@@ -1234,36 +1259,40 @@ mix( Schema, ObservableMixin );
|
|
|
1234
1259
|
* a limit element are limited to its content.
|
|
1235
1260
|
*
|
|
1236
1261
|
* Read more about the limit elements in the
|
|
1237
|
-
* {@glink framework/guides/deep-dive/schema#limit-elements Limit elements
|
|
1262
|
+
* {@glink framework/guides/deep-dive/schema#limit-elements Limit elements section} of
|
|
1263
|
+
* the {@glink framework/guides/deep-dive/schema Schema deep dive} guide.
|
|
1238
1264
|
*
|
|
1239
1265
|
* @property {Boolean} isObject
|
|
1240
1266
|
* Whether an item is "self-contained" and should be treated as a whole. Examples of object elements:
|
|
1241
|
-
* `
|
|
1267
|
+
* `imageBlock`, `table`, `video`, etc.
|
|
1242
1268
|
*
|
|
1243
1269
|
* **Note:** An object is also a limit, so
|
|
1244
1270
|
* {@link module:engine/model/schema~Schema#isLimit `isLimit()`} returns `true` for object elements automatically.
|
|
1245
1271
|
*
|
|
1246
1272
|
* Read more about the object elements in the
|
|
1247
|
-
* {@glink framework/guides/deep-dive/schema#object-elements Object elements
|
|
1273
|
+
* {@glink framework/guides/deep-dive/schema#object-elements Object elements section} of the Schema deep dive guide.
|
|
1248
1274
|
*
|
|
1249
1275
|
* @property {Boolean} isSelectable
|
|
1250
|
-
* `true` when an element should be selectable as a whole by the user. Examples of selectable elements: `
|
|
1276
|
+
* `true` when an element should be selectable as a whole by the user. Examples of selectable elements: `imageBlock`, `table`, `tableCell`,
|
|
1277
|
+
* etc.
|
|
1251
1278
|
*
|
|
1252
1279
|
* **Note:** An object is also a selectable element, so
|
|
1253
1280
|
* {@link module:engine/model/schema~Schema#isSelectable `isSelectable()`} returns `true` for object elements automatically.
|
|
1254
1281
|
*
|
|
1255
1282
|
* Read more about selectable elements in the
|
|
1256
|
-
* {@glink framework/guides/deep-dive/schema#selectable-elements Selectable elements
|
|
1283
|
+
* {@glink framework/guides/deep-dive/schema#selectable-elements Selectable elements section} of
|
|
1284
|
+
* the {@glink framework/guides/deep-dive/schema Schema deep dive} guide.
|
|
1257
1285
|
*
|
|
1258
1286
|
* @property {Boolean} isContent
|
|
1259
1287
|
* An item is a content when it always finds its way to the editor data output regardless of the number and type of its descendants.
|
|
1260
|
-
* Examples of content elements: `$text`, `
|
|
1288
|
+
* Examples of content elements: `$text`, `imageBlock`, `table`, etc. (but not `paragraph`, `heading1` or `tableCell`).
|
|
1261
1289
|
*
|
|
1262
1290
|
* **Note:** An object is also a content element, so
|
|
1263
1291
|
* {@link module:engine/model/schema~Schema#isContent `isContent()`} returns `true` for object elements automatically.
|
|
1264
1292
|
*
|
|
1265
1293
|
* Read more about content elements in the
|
|
1266
|
-
* {@glink framework/guides/deep-dive/schema#content-elements Content elements
|
|
1294
|
+
* {@glink framework/guides/deep-dive/schema#content-elements Content elements section} of
|
|
1295
|
+
* the {@glink framework/guides/deep-dive/schema Schema deep dive} guide.
|
|
1267
1296
|
*/
|
|
1268
1297
|
|
|
1269
1298
|
/**
|
|
@@ -1280,6 +1309,7 @@ mix( Schema, ObservableMixin );
|
|
|
1280
1309
|
* * The `name` property,
|
|
1281
1310
|
* * The `is*` properties,
|
|
1282
1311
|
* * The `allowIn` array,
|
|
1312
|
+
* * The `allowChildren` array,
|
|
1283
1313
|
* * The `allowAttributes` array.
|
|
1284
1314
|
*
|
|
1285
1315
|
* @typedef {Object} module:engine/model/schema~SchemaCompiledItemDefinition
|
|
@@ -1562,6 +1592,8 @@ function compileBaseItemRule( sourceItemRules, itemName ) {
|
|
|
1562
1592
|
allowAttributes: [],
|
|
1563
1593
|
allowAttributesOf: [],
|
|
1564
1594
|
|
|
1595
|
+
allowChildren: [],
|
|
1596
|
+
|
|
1565
1597
|
inheritTypesFrom: []
|
|
1566
1598
|
};
|
|
1567
1599
|
|
|
@@ -1574,6 +1606,8 @@ function compileBaseItemRule( sourceItemRules, itemName ) {
|
|
|
1574
1606
|
copyProperty( sourceItemRules, itemRule, 'allowAttributes' );
|
|
1575
1607
|
copyProperty( sourceItemRules, itemRule, 'allowAttributesOf' );
|
|
1576
1608
|
|
|
1609
|
+
copyProperty( sourceItemRules, itemRule, 'allowChildren' );
|
|
1610
|
+
|
|
1577
1611
|
copyProperty( sourceItemRules, itemRule, 'inheritTypesFrom' );
|
|
1578
1612
|
|
|
1579
1613
|
makeInheritAllWork( sourceItemRules, itemRule );
|
|
@@ -1581,6 +1615,25 @@ function compileBaseItemRule( sourceItemRules, itemName ) {
|
|
|
1581
1615
|
return itemRule;
|
|
1582
1616
|
}
|
|
1583
1617
|
|
|
1618
|
+
function compileAllowChildren( compiledDefinitions, itemName ) {
|
|
1619
|
+
const item = compiledDefinitions[ itemName ];
|
|
1620
|
+
|
|
1621
|
+
for ( const allowChildrenItem of item.allowChildren ) {
|
|
1622
|
+
const allowedChildren = compiledDefinitions[ allowChildrenItem ];
|
|
1623
|
+
|
|
1624
|
+
// The allowChildren property may point to an unregistered element.
|
|
1625
|
+
if ( !allowedChildren ) {
|
|
1626
|
+
continue;
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
allowedChildren.allowIn.push( itemName );
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
// The allowIn property already includes correct items, reset the allowChildren property
|
|
1633
|
+
// to avoid duplicates later when setting up compilation results.
|
|
1634
|
+
item.allowChildren.length = 0;
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1584
1637
|
function compileAllowContentOf( compiledDefinitions, itemName ) {
|
|
1585
1638
|
for ( const allowContentOfItemName of compiledDefinitions[ itemName ].allowContentOf ) {
|
|
1586
1639
|
// The allowContentOf property may point to an unregistered element.
|
|
@@ -1654,6 +1707,17 @@ function cleanUpAllowIn( compiledDefinitions, itemName ) {
|
|
|
1654
1707
|
itemRule.allowIn = Array.from( new Set( existingItems ) );
|
|
1655
1708
|
}
|
|
1656
1709
|
|
|
1710
|
+
// Setup allowChildren items based on allowIn.
|
|
1711
|
+
function setupAllowChildren( compiledDefinitions, itemName ) {
|
|
1712
|
+
const itemRule = compiledDefinitions[ itemName ];
|
|
1713
|
+
|
|
1714
|
+
for ( const allowedParentItemName of itemRule.allowIn ) {
|
|
1715
|
+
const allowedParentItem = compiledDefinitions[ allowedParentItemName ];
|
|
1716
|
+
|
|
1717
|
+
allowedParentItem.allowChildren.push( itemName );
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1657
1721
|
function cleanUpAllowAttributes( compiledDefinitions, itemName ) {
|
|
1658
1722
|
const itemRule = compiledDefinitions[ itemName ];
|
|
1659
1723
|
|
package/src/model/selection.js
CHANGED
|
@@ -71,7 +71,7 @@ export default class Selection {
|
|
|
71
71
|
* // Creates backward selection.
|
|
72
72
|
* const selection = writer.createSelection( range, { backward: true } );
|
|
73
73
|
*
|
|
74
|
-
* @param {module:engine/model/selection~Selectable} selectable
|
|
74
|
+
* @param {module:engine/model/selection~Selectable} [selectable]
|
|
75
75
|
* @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.
|
|
76
76
|
* @param {Object} [options]
|
|
77
77
|
* @param {Boolean} [options.backward] Sets this selection instance to be backward.
|
package/src/model/treewalker.js
CHANGED
|
@@ -382,10 +382,9 @@ function formatReturnValue( type, item, previousPosition, nextPosition, length )
|
|
|
382
382
|
/**
|
|
383
383
|
* Type of the step made by {@link module:engine/model/treewalker~TreeWalker}.
|
|
384
384
|
* Possible values: `'elementStart'` if walker is at the beginning of a node, `'elementEnd'` if walker is at the end of node,
|
|
385
|
-
*
|
|
386
|
-
* character merging mode, see {@link module:engine/model/treewalker~TreeWalker#constructor}).
|
|
385
|
+
* or `'text'` if walker traversed over text.
|
|
387
386
|
*
|
|
388
|
-
* @typedef {'elementStart'|'elementEnd'|'
|
|
387
|
+
* @typedef {'elementStart'|'elementEnd'|'text'} module:engine/model/treewalker~TreeWalkerValueType
|
|
389
388
|
*/
|
|
390
389
|
|
|
391
390
|
/**
|
|
@@ -404,7 +403,7 @@ function formatReturnValue( type, item, previousPosition, nextPosition, length )
|
|
|
404
403
|
* the position after the item.
|
|
405
404
|
* * Backward iteration: For `'elementEnd'` it is last position inside element. For all other types it is the position
|
|
406
405
|
* before the item.
|
|
407
|
-
* @property {Number} [length] Length of the item. For `'elementStart'`
|
|
406
|
+
* @property {Number} [length] Length of the item. For `'elementStart'` it is 1. For `'text'` it is
|
|
408
407
|
* the length of the text. For `'elementEnd'` it is `undefined`.
|
|
409
408
|
*/
|
|
410
409
|
|
|
@@ -45,7 +45,7 @@ import DocumentSelection from '../documentselection';
|
|
|
45
45
|
* @param {Boolean} [options.doNotAutoparagraph=false] Whether to create a paragraph if after content deletion selection is moved
|
|
46
46
|
* to a place where text cannot be inserted.
|
|
47
47
|
*
|
|
48
|
-
* For example `<paragraph>x</paragraph>[<
|
|
48
|
+
* For example `<paragraph>x</paragraph>[<imageBlock src="foo.jpg"></imageBlock>]` will become:
|
|
49
49
|
*
|
|
50
50
|
* * `<paragraph>x</paragraph><paragraph>[]</paragraph>` with the option disabled (`doNotAutoparagraph == false`)
|
|
51
51
|
* * `<paragraph>x</paragraph>[]` with the option enabled (`doNotAutoparagraph == true`).
|
|
@@ -53,9 +53,9 @@ import DocumentSelection from '../documentselection';
|
|
|
53
53
|
* If you use this option you need to make sure to handle invalid selections yourself or leave
|
|
54
54
|
* them to the selection post-fixer (may not always work).
|
|
55
55
|
*
|
|
56
|
-
* **Note:**
|
|
56
|
+
* **Note:** If there is no valid position for the selection, the paragraph will always be created:
|
|
57
57
|
*
|
|
58
|
-
* `[<
|
|
58
|
+
* `[<imageBlock src="foo.jpg"></imageBlock>]` -> `<paragraph>[]</paragraph>`.
|
|
59
59
|
*/
|
|
60
60
|
export default function deleteContent( model, selection, options = {} ) {
|
|
61
61
|
if ( selection.isCollapsed ) {
|
|
@@ -148,7 +148,20 @@ function getLivePositionsForSelectedBlocks( range ) {
|
|
|
148
148
|
// This is how modifySelection works and here we are making use of it.
|
|
149
149
|
model.modifySelection( selection, { direction: 'backward' } );
|
|
150
150
|
|
|
151
|
-
|
|
151
|
+
const newEndPosition = selection.getLastPosition();
|
|
152
|
+
|
|
153
|
+
// For such a model and selection:
|
|
154
|
+
// <paragraph>A[</paragraph><imageBlock></imageBlock><paragraph>]B</paragraph>
|
|
155
|
+
//
|
|
156
|
+
// After modifySelection(), we would end up with this:
|
|
157
|
+
// <paragraph>A[</paragraph>]<imageBlock></imageBlock><paragraph>B</paragraph>
|
|
158
|
+
//
|
|
159
|
+
// So we need to check if there is no content in the skipped range (because we want to include the <imageBlock>).
|
|
160
|
+
const skippedRange = model.createRange( newEndPosition, endPosition );
|
|
161
|
+
|
|
162
|
+
if ( !model.hasContent( skippedRange, { ignoreMarkers: true } ) ) {
|
|
163
|
+
endPosition = newEndPosition;
|
|
164
|
+
}
|
|
152
165
|
}
|
|
153
166
|
}
|
|
154
167
|
|
|
@@ -698,7 +698,7 @@ class Insertion {
|
|
|
698
698
|
// Do not autoparagraph if the paragraph won't be allowed there,
|
|
699
699
|
// cause that would lead to an infinite loop. The paragraph would be rejected in
|
|
700
700
|
// the next _handleNode() call and we'd be here again.
|
|
701
|
-
if ( this._getAllowedIn(
|
|
701
|
+
if ( this._getAllowedIn( this.position.parent, paragraph ) && this.schema.checkChild( paragraph, node ) ) {
|
|
702
702
|
paragraph._appendChild( node );
|
|
703
703
|
this._handleNode( paragraph );
|
|
704
704
|
}
|
|
@@ -747,7 +747,7 @@ class Insertion {
|
|
|
747
747
|
* `false` is returned if the node isn't allowed at any position up in the tree, `true` if was.
|
|
748
748
|
*/
|
|
749
749
|
_checkAndSplitToAllowedPosition( node ) {
|
|
750
|
-
const allowedIn = this._getAllowedIn(
|
|
750
|
+
const allowedIn = this._getAllowedIn( this.position.parent, node );
|
|
751
751
|
|
|
752
752
|
if ( !allowedIn ) {
|
|
753
753
|
return false;
|
|
@@ -759,11 +759,6 @@ class Insertion {
|
|
|
759
759
|
}
|
|
760
760
|
|
|
761
761
|
while ( allowedIn != this.position.parent ) {
|
|
762
|
-
// If a parent which we'd need to leave is a limit element, break.
|
|
763
|
-
if ( this.schema.isLimit( this.position.parent ) ) {
|
|
764
|
-
return false;
|
|
765
|
-
}
|
|
766
|
-
|
|
767
762
|
if ( this.position.isAtStart ) {
|
|
768
763
|
// If insertion position is at the beginning of the parent, move it out instead of splitting.
|
|
769
764
|
// <p>^Foo</p> -> ^<p>Foo</p>
|
|
@@ -806,19 +801,24 @@ class Insertion {
|
|
|
806
801
|
* Gets the element in which the given node is allowed. It checks the passed element and all its ancestors.
|
|
807
802
|
*
|
|
808
803
|
* @private
|
|
809
|
-
* @param {module:engine/model/
|
|
810
|
-
* @param {module:engine/model/
|
|
804
|
+
* @param {module:engine/model/element~Element} contextElement The element in which context the node should be checked.
|
|
805
|
+
* @param {module:engine/model/node~Node} childNode The node to check.
|
|
811
806
|
* @returns {module:engine/model/element~Element|null}
|
|
812
807
|
*/
|
|
813
|
-
_getAllowedIn(
|
|
814
|
-
if ( this.schema.checkChild(
|
|
815
|
-
return
|
|
808
|
+
_getAllowedIn( contextElement, childNode ) {
|
|
809
|
+
if ( this.schema.checkChild( contextElement, childNode ) ) {
|
|
810
|
+
return contextElement;
|
|
816
811
|
}
|
|
817
812
|
|
|
818
|
-
|
|
819
|
-
|
|
813
|
+
// If the child wasn't allowed in the context element and the element is a limit there's no point in
|
|
814
|
+
// checking any further towards the root. This is it: the limit is unsplittable and there's nothing
|
|
815
|
+
// we can do about it. Without this check, the algorithm will analyze parent of the limit and may create
|
|
816
|
+
// an illusion of the child being allowed. There's no way to insert it down there, though. It results in
|
|
817
|
+
// infinite loops.
|
|
818
|
+
if ( this.schema.isLimit( contextElement ) ) {
|
|
819
|
+
return null;
|
|
820
820
|
}
|
|
821
821
|
|
|
822
|
-
return
|
|
822
|
+
return this._getAllowedIn( contextElement.parent, childNode );
|
|
823
823
|
}
|
|
824
824
|
}
|
|
@@ -24,7 +24,7 @@ import Position from '../position';
|
|
|
24
24
|
* boundary (a range must be rooted within one limit element).
|
|
25
25
|
* * Only {@link module:engine/model/schema~Schema#isSelectable selectable elements} can be selected from the outside
|
|
26
26
|
* (e.g. `[<paragraph>foo</paragraph>]` is invalid). This rule applies independently to both selection ends, so this
|
|
27
|
-
* selection is correct: `<paragraph>f[oo</paragraph><
|
|
27
|
+
* selection is correct: `<paragraph>f[oo</paragraph><imageBlock></imageBlock>]`.
|
|
28
28
|
*
|
|
29
29
|
* If the position is not correct, the post-fixer will automatically correct it.
|
|
30
30
|
*
|
|
@@ -98,7 +98,7 @@ export default class DocumentSelection {
|
|
|
98
98
|
* Returns true if selection instance is marked as `fake`.
|
|
99
99
|
*
|
|
100
100
|
* @see #_setTo
|
|
101
|
-
* @
|
|
101
|
+
* @type {Boolean}
|
|
102
102
|
*/
|
|
103
103
|
get isFake() {
|
|
104
104
|
return this._selection.isFake;
|
|
@@ -108,7 +108,7 @@ export default class DocumentSelection {
|
|
|
108
108
|
* Returns fake selection label.
|
|
109
109
|
*
|
|
110
110
|
* @see #_setTo
|
|
111
|
-
* @
|
|
111
|
+
* @type {String}
|
|
112
112
|
*/
|
|
113
113
|
get fakeSelectionLabel() {
|
|
114
114
|
return this._selection.fakeSelectionLabel;
|