@ckeditor/ckeditor5-engine 42.0.2 → 43.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/CHANGELOG.md +1 -820
  2. package/dist/dev-utils/model.d.ts +2 -0
  3. package/dist/dev-utils/view.d.ts +1 -0
  4. package/dist/index.d.ts +3 -1
  5. package/dist/index.js +466 -271
  6. package/dist/index.js.map +1 -1
  7. package/dist/model/schema.d.ts +149 -51
  8. package/dist/view/observer/focusobserver.d.ts +12 -0
  9. package/dist/view/observer/mutationobserver.d.ts +34 -5
  10. package/dist/view/observer/selectionobserver.d.ts +1 -2
  11. package/dist/view/renderer.d.ts +12 -0
  12. package/dist/view/view.d.ts +1 -4
  13. package/package.json +2 -2
  14. package/src/conversion/upcasthelpers.js +0 -7
  15. package/src/dev-utils/model.d.ts +2 -0
  16. package/src/dev-utils/model.js +4 -2
  17. package/src/dev-utils/utils.js +7 -0
  18. package/src/dev-utils/view.d.ts +1 -0
  19. package/src/dev-utils/view.js +3 -0
  20. package/src/index.d.ts +3 -1
  21. package/src/index.js +2 -0
  22. package/src/model/model.js +1 -5
  23. package/src/model/schema.d.ts +149 -51
  24. package/src/model/schema.js +200 -70
  25. package/src/model/utils/insertcontent.js +21 -65
  26. package/src/view/domconverter.js +13 -9
  27. package/src/view/observer/compositionobserver.js +2 -0
  28. package/src/view/observer/focusobserver.d.ts +12 -0
  29. package/src/view/observer/focusobserver.js +55 -25
  30. package/src/view/observer/inputobserver.js +7 -5
  31. package/src/view/observer/mutationobserver.d.ts +34 -5
  32. package/src/view/observer/mutationobserver.js +8 -11
  33. package/src/view/observer/selectionobserver.d.ts +1 -2
  34. package/src/view/observer/selectionobserver.js +27 -9
  35. package/src/view/renderer.d.ts +12 -0
  36. package/src/view/renderer.js +111 -63
  37. package/src/view/view.d.ts +1 -4
  38. package/src/view/view.js +9 -0
@@ -37,6 +37,24 @@ export default class Schema extends /* #__PURE__ */ Schema_base {
37
37
  * A dictionary containing attribute properties.
38
38
  */
39
39
  private readonly _attributeProperties;
40
+ /**
41
+ * Stores additional callbacks registered for schema items, which are evaluated when {@link ~Schema#checkChild} is called.
42
+ *
43
+ * Keys are schema item names for which the callbacks are registered. Values are arrays with the callbacks.
44
+ *
45
+ * Some checks are added under {@link ~Schema#_genericCheckSymbol} key, these are evaluated for every {@link ~Schema#checkChild} call.
46
+ */
47
+ private readonly _customChildChecks;
48
+ /**
49
+ * Stores additional callbacks registered for attribute names, which are evaluated when {@link ~Schema#checkAttribute} is called.
50
+ *
51
+ * Keys are schema attribute names for which the callbacks are registered. Values are arrays with the callbacks.
52
+ *
53
+ * Some checks are added under {@link ~Schema#_genericCheckSymbol} key, these are evaluated for every
54
+ * {@link ~Schema#checkAttribute} call.
55
+ */
56
+ private readonly _customAttributeChecks;
57
+ private readonly _genericCheckSymbol;
40
58
  private _compiledDefinitions?;
41
59
  /**
42
60
  * Creates a schema instance.
@@ -213,7 +231,7 @@ export default class Schema extends /* #__PURE__ */ Schema_base {
213
231
  */
214
232
  isContent(item: string | Item | DocumentFragment | SchemaContextItem): boolean;
215
233
  /**
216
- * Checks whether the given node (`child`) can be a child of the given context.
234
+ * Checks whether the given node can be a child of the given context.
217
235
  *
218
236
  * ```ts
219
237
  * schema.checkChild( model.document.getRoot(), paragraph ); // -> false
@@ -221,13 +239,20 @@ export default class Schema extends /* #__PURE__ */ Schema_base {
221
239
  * schema.register( 'paragraph', {
222
240
  * allowIn: '$root'
223
241
  * } );
242
+ *
224
243
  * schema.checkChild( model.document.getRoot(), paragraph ); // -> true
225
244
  * ```
226
245
  *
227
- * Note: When verifying whether the given node can be a child of the given context, the
228
- * schema also verifies the entire context – from its root to its last element. Therefore, it is possible
229
- * for `checkChild()` to return `false` even though the context's last element can contain the checked child.
230
- * It happens if one of the context's elements does not allow its child.
246
+ * Both {@link module:engine/model/schema~Schema#addChildCheck callback checks} and declarative rules (added when
247
+ * {@link module:engine/model/schema~Schema#register registering} and {@link module:engine/model/schema~Schema#extend extending} items)
248
+ * are evaluated when this method is called.
249
+ *
250
+ * Note that callback checks have bigger priority than declarative rules checks and may overwrite them.
251
+ *
252
+ * Note that when verifying whether the given node can be a child of the given context, the schema also verifies the entire
253
+ * context – from its root to its last element. Therefore, it is possible for `checkChild()` to return `false` even though
254
+ * the `context` last element can contain the checked child. It happens if one of the `context` elements does not allow its child.
255
+ * When `context` is verified, {@link module:engine/model/schema~Schema#addChildCheck custom checks} are considered as well.
231
256
  *
232
257
  * @fires checkChild
233
258
  * @param context The context in which the child will be checked.
@@ -235,8 +260,7 @@ export default class Schema extends /* #__PURE__ */ Schema_base {
235
260
  */
236
261
  checkChild(context: SchemaContextDefinition, def: string | Node | DocumentFragment): boolean;
237
262
  /**
238
- * Checks whether the given attribute can be applied in the given context (on the last
239
- * item of the context).
263
+ * Checks whether the given attribute can be applied in the given context (on the last item of the context).
240
264
  *
241
265
  * ```ts
242
266
  * schema.checkAttribute( textNode, 'bold' ); // -> false
@@ -244,116 +268,152 @@ export default class Schema extends /* #__PURE__ */ Schema_base {
244
268
  * schema.extend( '$text', {
245
269
  * allowAttributes: 'bold'
246
270
  * } );
271
+ *
247
272
  * schema.checkAttribute( textNode, 'bold' ); // -> true
248
273
  * ```
249
274
  *
275
+ * Both {@link module:engine/model/schema~Schema#addAttributeCheck callback checks} and declarative rules (added when
276
+ * {@link module:engine/model/schema~Schema#register registering} and {@link module:engine/model/schema~Schema#extend extending} items)
277
+ * are evaluated when this method is called.
278
+ *
279
+ * Note that callback checks have bigger priority than declarative rules checks and may overwrite them.
280
+ *
250
281
  * @fires checkAttribute
251
282
  * @param context The context in which the attribute will be checked.
283
+ * @param attributeName Name of attribute to check in the given context.
252
284
  */
253
285
  checkAttribute(context: SchemaContextDefinition, attributeName: string): boolean;
254
- /**
255
- * Checks whether the given element (`elementToMerge`) can be merged with the specified base element (`positionOrBaseElement`).
256
- *
257
- * In other words – whether `elementToMerge`'s children {@link #checkChild are allowed} in the `positionOrBaseElement`.
258
- *
259
- * This check ensures that elements merged with {@link module:engine/model/writer~Writer#merge `Writer#merge()`}
260
- * will be valid.
261
- *
262
- * Instead of elements, you can pass the instance of the {@link module:engine/model/position~Position} class as the
263
- * `positionOrBaseElement`. It means that the elements before and after the position will be checked whether they can be merged.
264
- *
265
- * @param positionOrBaseElement The position or base element to which the `elementToMerge` will be merged.
266
- * @param elementToMerge The element to merge. Required if `positionOrBaseElement` is an element.
267
- */
268
- checkMerge(positionOrBaseElement: Position | Element, elementToMerge: Element): boolean;
286
+ checkMerge(position: Position): boolean;
287
+ checkMerge(baseElement: Element, elementToMerge: Element): boolean;
269
288
  /**
270
289
  * Allows registering a callback to the {@link #checkChild} method calls.
271
290
  *
272
291
  * Callbacks allow you to implement rules which are not otherwise possible to achieve
273
292
  * by using the declarative API of {@link module:engine/model/schema~SchemaItemDefinition}.
274
- * For example, by using this method you can disallow elements in specific contexts.
275
293
  *
276
- * This method is a shorthand for using the {@link #event:checkChild} event. For even better control,
277
- * you can use that event instead.
294
+ * Note that callback checks have bigger priority than declarative rules checks and may overwrite them.
278
295
  *
279
- * Example:
296
+ * For example, by using this method you can disallow elements in specific contexts:
280
297
  *
281
298
  * ```ts
282
- * // Disallow heading1 directly inside a blockQuote.
299
+ * // Disallow `heading1` inside a `blockQuote` that is inside a table.
283
300
  * schema.addChildCheck( ( context, childDefinition ) => {
284
- * if ( context.endsWith( 'blockQuote' ) && childDefinition.name == 'heading1' ) {
301
+ * if ( context.endsWith( 'tableCell blockQuote' ) ) {
285
302
  * return false;
286
303
  * }
304
+ * }, 'heading1' );
305
+ * ```
306
+ *
307
+ * You can skip the optional `itemName` parameter to evaluate the callback for every `checkChild()` call.
308
+ *
309
+ * ```ts
310
+ * // Inside specific custom element, allow only children, which allows for a specific attribute.
311
+ * schema.addChildCheck( ( context, childDefinition ) => {
312
+ * if ( context.endsWith( 'myElement' ) ) {
313
+ * return childDefinition.allowAttributes.includes( 'myAttribute' );
314
+ * }
287
315
  * } );
288
316
  * ```
289
317
  *
290
- * Which translates to:
318
+ * Please note that the generic callbacks may affect the editor performance and should be avoided if possible.
319
+ *
320
+ * When one of the callbacks makes a decision (returns `true` or `false`) the processing is finished and other callbacks are not fired.
321
+ * Callbacks are fired in the order they were added, however generic callbacks are fired before callbacks added for a specified item.
322
+ *
323
+ * You can also use `checkChild` event, if you need even better control. The result from the example above could also be
324
+ * achieved with following event callback:
291
325
  *
292
326
  * ```ts
293
327
  * schema.on( 'checkChild', ( evt, args ) => {
294
328
  * const context = args[ 0 ];
295
329
  * const childDefinition = args[ 1 ];
296
330
  *
297
- * if ( context.endsWith( 'blockQuote' ) && childDefinition && childDefinition.name == 'heading1' ) {
331
+ * if ( context.endsWith( 'myElement' ) ) {
298
332
  * // Prevent next listeners from being called.
299
333
  * evt.stop();
300
- * // Set the checkChild()'s return value.
301
- * evt.return = false;
334
+ * // Set the `checkChild()` return value.
335
+ * evt.return = childDefinition.allowAttributes.includes( 'myAttribute' );
302
336
  * }
303
337
  * }, { priority: 'high' } );
304
338
  * ```
305
339
  *
340
+ * Note that the callback checks and declarative rules checks are processed on `normal` priority.
341
+ *
342
+ * Adding callbacks this way can also negatively impact editor performance.
343
+ *
306
344
  * @param callback The callback to be called. It is called with two parameters:
307
345
  * {@link module:engine/model/schema~SchemaContext} (context) instance and
308
- * {@link module:engine/model/schema~SchemaCompiledItemDefinition} (child-to-check definition).
309
- * The callback may return `true/false` to override `checkChild()`'s return value. If it does not return
310
- * a boolean value, the default algorithm (or other callbacks) will define `checkChild()`'s return value.
346
+ * {@link module:engine/model/schema~SchemaCompiledItemDefinition} (definition). The callback may return `true/false` to override
347
+ * `checkChild()`'s return value. If it does not return a boolean value, the default algorithm (or other callbacks) will define
348
+ * `checkChild()`'s return value.
349
+ * @param itemName Name of the schema item for which the callback is registered. If specified, the callback will be run only for
350
+ * `checkChild()` calls which `def` parameter matches the `itemName`. Otherwise, the callback will run for every `checkChild` call.
311
351
  */
312
- addChildCheck(callback: SchemaChildCheckCallback): void;
352
+ addChildCheck(callback: SchemaChildCheckCallback, itemName?: string): void;
313
353
  /**
314
354
  * Allows registering a callback to the {@link #checkAttribute} method calls.
315
355
  *
316
356
  * Callbacks allow you to implement rules which are not otherwise possible to achieve
317
357
  * by using the declarative API of {@link module:engine/model/schema~SchemaItemDefinition}.
318
- * For example, by using this method you can disallow attribute if node to which it is applied
319
- * is contained within some other element (e.g. you want to disallow `bold` on `$text` within `heading1`).
320
358
  *
321
- * This method is a shorthand for using the {@link #event:checkAttribute} event. For even better control,
322
- * you can use that event instead.
359
+ * Note that callback checks have bigger priority than declarative rules checks and may overwrite them.
360
+ *
361
+ * For example, by using this method you can disallow setting attributes on nodes in specific contexts:
362
+ *
363
+ * ```ts
364
+ * // Disallow setting `bold` on text inside `heading1` element:
365
+ * schema.addAttributeCheck( context => {
366
+ * if ( context.endsWith( 'heading1 $text' ) ) {
367
+ * return false;
368
+ * }
369
+ * }, 'bold' );
370
+ * ```
323
371
  *
324
- * Example:
372
+ * You can skip the optional `attributeName` parameter to evaluate the callback for every `checkAttribute()` call.
325
373
  *
326
374
  * ```ts
327
- * // Disallow bold on $text inside heading1.
375
+ * // Disallow formatting attributes on text inside custom `myTitle` element:
328
376
  * schema.addAttributeCheck( ( context, attributeName ) => {
329
- * if ( context.endsWith( 'heading1 $text' ) && attributeName == 'bold' ) {
377
+ * if ( context.endsWith( 'myTitle $text' ) && schema.getAttributeProperties( attributeName ).isFormatting ) {
330
378
  * return false;
331
379
  * }
332
380
  * } );
333
381
  * ```
334
382
  *
335
- * Which translates to:
383
+ * Please note that the generic callbacks may affect the editor performance and should be avoided if possible.
384
+ *
385
+ * When one of the callbacks makes a decision (returns `true` or `false`) the processing is finished and other callbacks are not fired.
386
+ * Callbacks are fired in the order they were added, however generic callbacks are fired before callbacks added for a specified item.
387
+ *
388
+ * You can also use {@link #event:checkAttribute} event, if you need even better control. The result from the example above could also
389
+ * be achieved with following event callback:
336
390
  *
337
391
  * ```ts
338
392
  * schema.on( 'checkAttribute', ( evt, args ) => {
339
393
  * const context = args[ 0 ];
340
394
  * const attributeName = args[ 1 ];
341
395
  *
342
- * if ( context.endsWith( 'heading1 $text' ) && attributeName == 'bold' ) {
396
+ * if ( context.endsWith( 'myTitle $text' ) && schema.getAttributeProperties( attributeName ).isFormatting ) {
343
397
  * // Prevent next listeners from being called.
344
398
  * evt.stop();
345
- * // Set the checkAttribute()'s return value.
399
+ * // Set the `checkAttribute()` return value.
346
400
  * evt.return = false;
347
401
  * }
348
402
  * }, { priority: 'high' } );
349
403
  * ```
350
404
  *
405
+ * Note that the callback checks and declarative rules checks are processed on `normal` priority.
406
+ *
407
+ * Adding callbacks this way can also negatively impact editor performance.
408
+ *
351
409
  * @param callback The callback to be called. It is called with two parameters:
352
- * {@link module:engine/model/schema~SchemaContext} (context) instance and attribute name.
353
- * The callback may return `true/false` to override `checkAttribute()`'s return value. If it does not return
354
- * a boolean value, the default algorithm (or other callbacks) will define `checkAttribute()`'s return value.
410
+ * {@link module:engine/model/schema~SchemaContext `context`} and attribute name. The callback may return `true` or `false`, to
411
+ * override `checkAttribute()`'s return value. If it does not return a boolean value, the default algorithm (or other callbacks)
412
+ * will define `checkAttribute()`'s return value.
413
+ * @param attributeName Name of the attribute for which the callback is registered. If specified, the callback will be run only for
414
+ * `checkAttribute()` calls with matching `attributeName`. Otherwise, the callback will run for every `checkAttribute()` call.
355
415
  */
356
- addAttributeCheck(callback: SchemaAttributeCheckCallback): void;
416
+ addAttributeCheck(callback: SchemaAttributeCheckCallback, attributeName?: string): void;
357
417
  /**
358
418
  * This method allows assigning additional metadata to the model attributes. For example,
359
419
  * {@link module:engine/model/schema~AttributeProperties `AttributeProperties#isFormatting` property} is
@@ -496,6 +556,22 @@ export default class Schema extends /* #__PURE__ */ Schema_base {
496
556
  private _clearCache;
497
557
  private _compile;
498
558
  private _checkContextMatch;
559
+ /**
560
+ * Calls child check callbacks to decide whether `def` is allowed in `context`. It uses both generic and specific (defined for `def`
561
+ * item) callbacks. If neither callback makes a decision, `undefined` is returned.
562
+ *
563
+ * Note that the first callback that makes a decision "wins", i.e., if any callback returns `true` or `false`, then the processing
564
+ * is over and that result is returned.
565
+ */
566
+ private _evaluateChildChecks;
567
+ /**
568
+ * Calls attribute check callbacks to decide whether `attributeName` can be set on the last element of `context`. It uses both
569
+ * generic and specific (defined for `attributeName`) callbacks. If neither callback makes a decision, `undefined` is returned.
570
+ *
571
+ * Note that the first callback that makes a decision "wins", i.e., if any callback returns `true` or `false`, then the processing
572
+ * is over and that result is returned.
573
+ */
574
+ private _evaluateAttributeChecks;
499
575
  /**
500
576
  * Takes a flat range and an attribute name. Traverses the range recursively and deeply to find and return all ranges
501
577
  * inside the given range on which the attribute can be applied.
@@ -875,22 +951,32 @@ export interface SchemaItemDefinition {
875
951
  disallowAttributes?: string | Array<string>;
876
952
  /**
877
953
  * Inherits "allowed children" from other items.
954
+ *
955
+ * Note that the item's "own" rules take precedence over "inherited" rules and can overwrite them.
878
956
  */
879
957
  allowContentOf?: string | Array<string>;
880
958
  /**
881
959
  * Inherits "allowed in" from other items.
960
+ *
961
+ * Note that the item's "own" rules take precedence over "inherited" rules and can overwrite them.
882
962
  */
883
963
  allowWhere?: string | Array<string>;
884
964
  /**
885
965
  * Inherits "allowed attributes" from other items.
966
+ *
967
+ * Note that the item's "own" rules take precedence over "inherited" rules and can overwrite them.
886
968
  */
887
969
  allowAttributesOf?: string | Array<string>;
888
970
  /**
889
971
  * Inherits `is*` properties of other items.
972
+ *
973
+ * Note that the item's "own" rules take precedence over "inherited" rules and can overwrite them.
890
974
  */
891
975
  inheritTypesFrom?: string | Array<string>;
892
976
  /**
893
977
  * A shorthand for `allowContentOf`, `allowWhere`, `allowAttributesOf`, `inheritTypesFrom`.
978
+ *
979
+ * Note that the item's "own" rules take precedence over "inherited" rules and can overwrite them.
894
980
  */
895
981
  inheritAllFrom?: string;
896
982
  /**
@@ -1060,6 +1146,18 @@ export declare class SchemaContext implements Iterable<SchemaContextItem> {
1060
1146
  * @returns A new schema context instance with an additional item.
1061
1147
  */
1062
1148
  push(item: string | Node): SchemaContext;
1149
+ /**
1150
+ * Returns a new schema context that is based on this context but has the last item removed.
1151
+ *
1152
+ * ```ts
1153
+ * const ctxParagraph = new SchemaContext( [ '$root', 'blockQuote', 'paragraph' ] );
1154
+ * const ctxBlockQuote = ctxParagraph.trimLast(); // Items in `ctxBlockQuote` are: `$root` an `blockQuote`.
1155
+ * const ctxRoot = ctxBlockQuote.trimLast(); // Items in `ctxRoot` are: `$root`.
1156
+ * ```
1157
+ *
1158
+ * @returns A new reduced schema context instance.
1159
+ */
1160
+ trimLast(): SchemaContext;
1063
1161
  /**
1064
1162
  * Gets an item on the given index.
1065
1163
  */
@@ -1109,7 +1207,7 @@ export declare class SchemaContext implements Iterable<SchemaContextItem> {
1109
1207
  * * By defining an **array of node names** (potentially, mixed with real nodes) – The same as **name of node**
1110
1208
  * but it is possible to create a path.
1111
1209
  * * By defining a {@link module:engine/model/schema~SchemaContext} instance - in this case the same instance as provided
1112
- * will be return.
1210
+ * will be returned.
1113
1211
  *
1114
1212
  * Examples of context definitions passed to the {@link module:engine/model/schema~Schema#checkChild `Schema#checkChild()`}
1115
1213
  * method: