@ckeditor/ckeditor5-engine 33.0.0 → 34.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 +2 -2
- package/README.md +2 -1
- package/package.json +22 -22
- package/src/conversion/downcasthelpers.js +90 -19
- package/src/conversion/mapper.js +2 -2
- package/src/conversion/upcastdispatcher.js +31 -1
- package/src/conversion/upcasthelpers.js +23 -1
- package/src/index.js +11 -0
- package/src/model/differ.js +33 -15
- package/src/model/document.js +20 -28
- package/src/model/history.js +160 -22
- package/src/model/model.js +120 -3
- package/src/model/schema.js +79 -10
- package/src/model/treewalker.js +2 -3
- package/src/model/utils/deletecontent.js +15 -2
- package/src/model/utils/findoptimalinsertionrange.js +68 -0
- package/src/model/utils/insertobject.js +173 -0
- package/src/view/attributeelement.js +0 -10
- package/src/view/domconverter.js +27 -4
- package/src/view/downcastwriter.js +5 -49
- package/src/view/element.js +2 -26
- package/src/view/emptyelement.js +0 -3
- package/src/view/filler.js +1 -1
- package/src/view/matcher.js +2 -2
- package/src/view/observer/clickobserver.js +0 -1
- package/src/view/observer/inputobserver.js +1 -1
- package/src/view/observer/tabobserver.js +68 -0
- package/src/view/placeholder.js +1 -1
- package/src/view/rawelement.js +0 -3
- package/src/view/renderer.js +4 -0
- package/src/view/uielement.js +0 -3
- package/src/view/view.js +4 -0
package/LICENSE.md
CHANGED
|
@@ -2,7 +2,7 @@ Software License Agreement
|
|
|
2
2
|
==========================
|
|
3
3
|
|
|
4
4
|
**CKEditor 5 editing engine** – https://github.com/ckeditor/ckeditor5-engine <br>
|
|
5
|
-
Copyright (c) 2003-2022, [CKSource
|
|
5
|
+
Copyright (c) 2003-2022, [CKSource Holding sp. z o.o.](https://cksource.com) All rights reserved.
|
|
6
6
|
|
|
7
7
|
Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html).
|
|
8
8
|
|
|
@@ -14,4 +14,4 @@ Where not otherwise indicated, all CKEditor content is authored by CKSource engi
|
|
|
14
14
|
Trademarks
|
|
15
15
|
----------
|
|
16
16
|
|
|
17
|
-
**CKEditor** is a trademark of [CKSource
|
|
17
|
+
**CKEditor** is a trademark of [CKSource Holding sp. z o.o.](https://cksource.com) All other brand and product names are trademarks, registered trademarks or service marks of their respective holders.
|
package/README.md
CHANGED
|
@@ -3,7 +3,8 @@ CKEditor 5 editing engine
|
|
|
3
3
|
|
|
4
4
|
[](https://www.npmjs.com/package/@ckeditor/ckeditor5-engine)
|
|
5
5
|
[](https://coveralls.io/github/ckeditor/ckeditor5?branch=master)
|
|
6
|
-
[](https://travis-ci.com/ckeditor/ckeditor5)
|
|
6
|
+
[](https://app.travis-ci.com/github/ckeditor/ckeditor5)
|
|
7
|
+

|
|
7
8
|
|
|
8
9
|
The CKEditor 5 editing engine implements a flexible MVC-based architecture for creating rich text editing features.
|
|
9
10
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ckeditor/ckeditor5-engine",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "34.2.0",
|
|
4
4
|
"description": "The editing engine of CKEditor 5 – the best browser-based rich text editor.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"wysiwyg",
|
|
@@ -23,30 +23,30 @@
|
|
|
23
23
|
],
|
|
24
24
|
"main": "src/index.js",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@ckeditor/ckeditor5-utils": "^
|
|
26
|
+
"@ckeditor/ckeditor5-utils": "^34.2.0",
|
|
27
27
|
"lodash-es": "^4.17.15"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@ckeditor/ckeditor5-basic-styles": "^
|
|
31
|
-
"@ckeditor/ckeditor5-block-quote": "^
|
|
32
|
-
"@ckeditor/ckeditor5-clipboard": "^
|
|
33
|
-
"@ckeditor/ckeditor5-cloud-services": "^
|
|
34
|
-
"@ckeditor/ckeditor5-core": "^
|
|
35
|
-
"@ckeditor/ckeditor5-editor-classic": "^
|
|
36
|
-
"@ckeditor/ckeditor5-enter": "^
|
|
37
|
-
"@ckeditor/ckeditor5-essentials": "^
|
|
38
|
-
"@ckeditor/ckeditor5-heading": "^
|
|
39
|
-
"@ckeditor/ckeditor5-image": "^
|
|
40
|
-
"@ckeditor/ckeditor5-link": "^
|
|
41
|
-
"@ckeditor/ckeditor5-list": "^
|
|
42
|
-
"@ckeditor/ckeditor5-mention": "^
|
|
43
|
-
"@ckeditor/ckeditor5-paragraph": "^
|
|
44
|
-
"@ckeditor/ckeditor5-table": "^
|
|
45
|
-
"@ckeditor/ckeditor5-theme-lark": "^
|
|
46
|
-
"@ckeditor/ckeditor5-typing": "^
|
|
47
|
-
"@ckeditor/ckeditor5-ui": "^
|
|
48
|
-
"@ckeditor/ckeditor5-undo": "^
|
|
49
|
-
"@ckeditor/ckeditor5-widget": "^
|
|
30
|
+
"@ckeditor/ckeditor5-basic-styles": "^34.2.0",
|
|
31
|
+
"@ckeditor/ckeditor5-block-quote": "^34.2.0",
|
|
32
|
+
"@ckeditor/ckeditor5-clipboard": "^34.2.0",
|
|
33
|
+
"@ckeditor/ckeditor5-cloud-services": "^34.2.0",
|
|
34
|
+
"@ckeditor/ckeditor5-core": "^34.2.0",
|
|
35
|
+
"@ckeditor/ckeditor5-editor-classic": "^34.2.0",
|
|
36
|
+
"@ckeditor/ckeditor5-enter": "^34.2.0",
|
|
37
|
+
"@ckeditor/ckeditor5-essentials": "^34.2.0",
|
|
38
|
+
"@ckeditor/ckeditor5-heading": "^34.2.0",
|
|
39
|
+
"@ckeditor/ckeditor5-image": "^34.2.0",
|
|
40
|
+
"@ckeditor/ckeditor5-link": "^34.2.0",
|
|
41
|
+
"@ckeditor/ckeditor5-list": "^34.2.0",
|
|
42
|
+
"@ckeditor/ckeditor5-mention": "^34.2.0",
|
|
43
|
+
"@ckeditor/ckeditor5-paragraph": "^34.2.0",
|
|
44
|
+
"@ckeditor/ckeditor5-table": "^34.2.0",
|
|
45
|
+
"@ckeditor/ckeditor5-theme-lark": "^34.2.0",
|
|
46
|
+
"@ckeditor/ckeditor5-typing": "^34.2.0",
|
|
47
|
+
"@ckeditor/ckeditor5-ui": "^34.2.0",
|
|
48
|
+
"@ckeditor/ckeditor5-undo": "^34.2.0",
|
|
49
|
+
"@ckeditor/ckeditor5-widget": "^34.2.0",
|
|
50
50
|
"webpack": "^5.58.1",
|
|
51
51
|
"webpack-cli": "^4.9.0"
|
|
52
52
|
},
|
|
@@ -151,8 +151,9 @@ export default class DowncastHelpers extends ConversionHelpers {
|
|
|
151
151
|
* the view element. Note that the view will be reconverted if any of the listed attributes changes.
|
|
152
152
|
* @param {Boolean} [config.model.children] Specifies whether the view element requires reconversion if the list
|
|
153
153
|
* of the model child nodes changed.
|
|
154
|
-
* @param {module:engine/view/elementdefinition~ElementDefinition|
|
|
155
|
-
* that takes the model element and
|
|
154
|
+
* @param {module:engine/view/elementdefinition~ElementDefinition|module:engine/conversion/downcasthelpers~ElementCreatorFunction}
|
|
155
|
+
* config.view A view element definition or a function that takes the model element and
|
|
156
|
+
* {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}
|
|
156
157
|
* as parameters and returns a view container element.
|
|
157
158
|
* @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}
|
|
158
159
|
*/
|
|
@@ -377,7 +378,8 @@ export default class DowncastHelpers extends ConversionHelpers {
|
|
|
377
378
|
* @param {Object} config Conversion configuration.
|
|
378
379
|
* @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values }` object. `values` is an array
|
|
379
380
|
* of `String`s with possible values if the model attribute is an enumerable.
|
|
380
|
-
* @param {module:engine/view/elementdefinition~ElementDefinition|
|
|
381
|
+
* @param {module:engine/view/elementdefinition~ElementDefinition|Object|
|
|
382
|
+
* module:engine/conversion/downcasthelpers~AttributeElementCreatorFunction} config.view A view element definition or a function
|
|
381
383
|
* that takes the model attribute value and
|
|
382
384
|
* {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API} as parameters and returns a view
|
|
383
385
|
* attribute element. If `config.model.values` is given, `config.view` should be an object assigning values from `config.model.values`
|
|
@@ -459,8 +461,9 @@ export default class DowncastHelpers extends ConversionHelpers {
|
|
|
459
461
|
* @param {Object} config Conversion configuration.
|
|
460
462
|
* @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values, [ name ] }` object describing
|
|
461
463
|
* the attribute key, possible values and, optionally, an element name to convert from.
|
|
462
|
-
* @param {String|Object|
|
|
463
|
-
*
|
|
464
|
+
* @param {String|Object|module:engine/conversion/downcasthelpers~AttributeCreatorFunction} config.view A view attribute key,
|
|
465
|
+
* or a `{ key, value }` object or a function that takes the model attribute value and
|
|
466
|
+
* {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}
|
|
464
467
|
* as parameters and returns a `{ key, value }` object. If the `key` is `'class'`, the `value` can be a `String` or an
|
|
465
468
|
* array of `String`s. If the `key` is `'style'`, the `value` is an object with key-value pairs. In other cases, `value` is a `String`.
|
|
466
469
|
* If `config.model.values` is set, `config.view` should be an object assigning values from `config.model.values` to
|
|
@@ -971,10 +974,10 @@ export function wrap( elementCreator ) {
|
|
|
971
974
|
|
|
972
975
|
// Recreate current wrapping node. It will be used to unwrap view range if the attribute value has changed
|
|
973
976
|
// or the attribute was removed.
|
|
974
|
-
const oldViewElement = elementCreator( data.attributeOldValue, conversionApi );
|
|
977
|
+
const oldViewElement = elementCreator( data.attributeOldValue, conversionApi, data );
|
|
975
978
|
|
|
976
979
|
// Create node to wrap with.
|
|
977
|
-
const newViewElement = elementCreator( data.attributeNewValue, conversionApi );
|
|
980
|
+
const newViewElement = elementCreator( data.attributeNewValue, conversionApi, data );
|
|
978
981
|
|
|
979
982
|
if ( !oldViewElement && !newViewElement ) {
|
|
980
983
|
return;
|
|
@@ -1037,7 +1040,7 @@ export function insertElement( elementCreator, consumer = defaultConsumer ) {
|
|
|
1037
1040
|
return;
|
|
1038
1041
|
}
|
|
1039
1042
|
|
|
1040
|
-
const viewElement = elementCreator( data.item, conversionApi );
|
|
1043
|
+
const viewElement = elementCreator( data.item, conversionApi, data );
|
|
1041
1044
|
|
|
1042
1045
|
if ( !viewElement ) {
|
|
1043
1046
|
return;
|
|
@@ -1085,7 +1088,7 @@ export function insertStructure( elementCreator, consumer ) {
|
|
|
1085
1088
|
conversionApi.writer._registerSlotFactory( createSlotFactory( data.item, slotsMap, conversionApi ) );
|
|
1086
1089
|
|
|
1087
1090
|
// View creation.
|
|
1088
|
-
const viewElement = elementCreator( data.item, conversionApi );
|
|
1091
|
+
const viewElement = elementCreator( data.item, conversionApi, data );
|
|
1089
1092
|
|
|
1090
1093
|
conversionApi.writer._clearSlotFactory();
|
|
1091
1094
|
|
|
@@ -1376,8 +1379,8 @@ function changeAttribute( attributeCreator ) {
|
|
|
1376
1379
|
return;
|
|
1377
1380
|
}
|
|
1378
1381
|
|
|
1379
|
-
const oldAttribute = attributeCreator( data.attributeOldValue, conversionApi );
|
|
1380
|
-
const newAttribute = attributeCreator( data.attributeNewValue, conversionApi );
|
|
1382
|
+
const oldAttribute = attributeCreator( data.attributeOldValue, conversionApi, data );
|
|
1383
|
+
const newAttribute = attributeCreator( data.attributeNewValue, conversionApi, data );
|
|
1381
1384
|
|
|
1382
1385
|
if ( !oldAttribute && !newAttribute ) {
|
|
1383
1386
|
return;
|
|
@@ -1653,7 +1656,8 @@ function removeHighlight( highlightDescriptor ) {
|
|
|
1653
1656
|
// @param {String|Object} config.model The description or a name of the model element to convert.
|
|
1654
1657
|
// @param {String|Array.<String>} [config.model.attributes] List of attributes triggering element reconversion.
|
|
1655
1658
|
// @param {Boolean} [config.model.children] Should reconvert element if the list of model child nodes changed.
|
|
1656
|
-
// @param {module:engine/view/elementdefinition~ElementDefinition|
|
|
1659
|
+
// @param {module:engine/view/elementdefinition~ElementDefinition|module:engine/conversion/downcasthelpers~ElementCreatorFunction}
|
|
1660
|
+
// config.view
|
|
1657
1661
|
// @returns {Function} Conversion helper.
|
|
1658
1662
|
function downcastElementToElement( config ) {
|
|
1659
1663
|
config = cloneDeep( config );
|
|
@@ -1760,10 +1764,11 @@ function downcastElementToStructure( config ) {
|
|
|
1760
1764
|
// @param {Object} config Conversion configuration.
|
|
1761
1765
|
// @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values }` object. `values` is an array
|
|
1762
1766
|
// of `String`s with possible values if the model attribute is an enumerable.
|
|
1763
|
-
// @param {module:engine/view/elementdefinition~ElementDefinition|
|
|
1764
|
-
// that takes the model attribute value and
|
|
1765
|
-
// as parameters and returns a view attribute element.
|
|
1766
|
-
// given, `config.view` should be an object assigning values from `config.model.values` to view element
|
|
1767
|
+
// @param {module:engine/view/elementdefinition~ElementDefinition|module:engine/conversion/downcasthelpers~AttributeElementCreatorFunction|
|
|
1768
|
+
// Object} config.view A view element definition or a function that takes the model attribute value and
|
|
1769
|
+
// {@link module:engine/view/downcastwriter~DowncastWriter view downcast writer} as parameters and returns a view attribute element.
|
|
1770
|
+
// If `config.model.values` is given, `config.view` should be an object assigning values from `config.model.values` to view element
|
|
1771
|
+
// definitions or functions.
|
|
1767
1772
|
// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.
|
|
1768
1773
|
// @returns {Function} Conversion helper.
|
|
1769
1774
|
function downcastAttributeToElement( config ) {
|
|
@@ -1798,9 +1803,10 @@ function downcastAttributeToElement( config ) {
|
|
|
1798
1803
|
// @param {Object} config Conversion configuration.
|
|
1799
1804
|
// @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values, [ name ] }` object describing
|
|
1800
1805
|
// the attribute key, possible values and, optionally, an element name to convert from.
|
|
1801
|
-
// @param {String|Object|
|
|
1802
|
-
//
|
|
1803
|
-
// array of `String`s. If `key` is `'style'`, `value` is an object with
|
|
1806
|
+
// @param {String|Object|module:engine/conversion/downcasthelpers~AttributeCreatorFunction} config.view A view attribute key,
|
|
1807
|
+
// or a `{ key, value }` object or a function that takes the model attribute value and returns a `{ key, value }` object.
|
|
1808
|
+
// If `key` is `'class'`, `value` can be a `String` or an array of `String`s. If `key` is `'style'`, `value` is an object with
|
|
1809
|
+
// key-value pairs. In other cases, `value` is a `String`.
|
|
1804
1810
|
// If `config.model.values` is set, `config.view` should be an object assigning values from `config.model.values` to
|
|
1805
1811
|
// `{ key, value }` objects or a functions.
|
|
1806
1812
|
// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.
|
|
@@ -2386,6 +2392,23 @@ function defaultConsumer( item, consumable, { preflight } = {} ) {
|
|
|
2386
2392
|
* @see module:engine/conversion/downcasthelpers~insertStructure
|
|
2387
2393
|
*/
|
|
2388
2394
|
|
|
2395
|
+
/**
|
|
2396
|
+
* A view element creator function that takes the model element and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi
|
|
2397
|
+
* downcast conversion API} as parameters and returns a view container element.
|
|
2398
|
+
*
|
|
2399
|
+
* @callback module:engine/conversion/downcasthelpers~ElementCreatorFunction
|
|
2400
|
+
* @param {module:engine/model/element~Element} element The model element to be converted to the view structure.
|
|
2401
|
+
* @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi The conversion interface.
|
|
2402
|
+
* @param {Object} data Additional information about the change (same as for
|
|
2403
|
+
* {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert `insert`} event).
|
|
2404
|
+
* @param {module:engine/model/item~Item} data.item Inserted item.
|
|
2405
|
+
* @param {module:engine/model/range~Range} data.range Range spanning over inserted item.
|
|
2406
|
+
* @returns {module:engine/view/element~Element} The view element.
|
|
2407
|
+
*
|
|
2408
|
+
* @see module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement
|
|
2409
|
+
* @see module:engine/conversion/downcasthelpers~insertElement
|
|
2410
|
+
*/
|
|
2411
|
+
|
|
2389
2412
|
/**
|
|
2390
2413
|
* A function that takes the model element and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast
|
|
2391
2414
|
* conversion API} as parameters and returns a view container element with slots for model child nodes to be converted into.
|
|
@@ -2393,12 +2416,60 @@ function defaultConsumer( item, consumable, { preflight } = {} ) {
|
|
|
2393
2416
|
* @callback module:engine/conversion/downcasthelpers~StructureCreatorFunction
|
|
2394
2417
|
* @param {module:engine/model/element~Element} element The model element to be converted to the view structure.
|
|
2395
2418
|
* @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi The conversion interface.
|
|
2419
|
+
* @param {Object} data Additional information about the change (same as for
|
|
2420
|
+
* {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert `insert`} event).
|
|
2421
|
+
* @param {module:engine/model/item~Item} data.item Inserted item.
|
|
2422
|
+
* @param {module:engine/model/range~Range} data.range Range spanning over inserted item.
|
|
2396
2423
|
* @returns {module:engine/view/element~Element} The view structure with slots for model child nodes.
|
|
2397
2424
|
*
|
|
2398
2425
|
* @see module:engine/conversion/downcasthelpers~DowncastHelpers#elementToStructure
|
|
2399
2426
|
* @see module:engine/conversion/downcasthelpers~insertStructure
|
|
2400
2427
|
*/
|
|
2401
2428
|
|
|
2429
|
+
/**
|
|
2430
|
+
* A view element creator function that takes the model attribute value and
|
|
2431
|
+
* {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API} as parameters and returns a view
|
|
2432
|
+
* attribute element.
|
|
2433
|
+
*
|
|
2434
|
+
* @callback module:engine/conversion/downcasthelpers~AttributeElementCreatorFunction
|
|
2435
|
+
* @param {*} attributeValue The model attribute value to be converted to the view attribute element.
|
|
2436
|
+
* @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi The conversion interface.
|
|
2437
|
+
* @param {Object} data Additional information about the change (same as for
|
|
2438
|
+
* {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute `attribute`} event).
|
|
2439
|
+
* @param {module:engine/model/item~Item|module:engine/model/documentselection~DocumentSelection} data.item Changed item
|
|
2440
|
+
* or converted selection.
|
|
2441
|
+
* @param {module:engine/model/range~Range} data.range Range spanning over changed item or selection range.
|
|
2442
|
+
* @param {String} data.attributeKey Attribute key.
|
|
2443
|
+
* @param {*} data.attributeOldValue Attribute value before the change. This is `null` when selection attribute is converted.
|
|
2444
|
+
* @param {*} data.attributeNewValue New attribute value.
|
|
2445
|
+
* @returns {module:engine/view/attributeelement~AttributeElement} The view attribute element.
|
|
2446
|
+
*
|
|
2447
|
+
* @see module:engine/conversion/downcasthelpers~DowncastHelpers#attributeToElement
|
|
2448
|
+
* @see module:engine/conversion/downcasthelpers~wrap
|
|
2449
|
+
*/
|
|
2450
|
+
|
|
2451
|
+
/**
|
|
2452
|
+
* A function that takes the model attribute value and
|
|
2453
|
+
* {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}
|
|
2454
|
+
* as parameters.
|
|
2455
|
+
*
|
|
2456
|
+
* @callback module:engine/conversion/downcasthelpers~AttributeCreatorFunction
|
|
2457
|
+
* @param {*} attributeValue The model attribute value to be converted to the view attribute element.
|
|
2458
|
+
* @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi The conversion interface.
|
|
2459
|
+
* @param {Object} data Additional information about the change (same as for
|
|
2460
|
+
* {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute `attribute`} event).
|
|
2461
|
+
* @param {module:engine/model/item~Item|module:engine/model/documentselection~DocumentSelection} data.item Changed item
|
|
2462
|
+
* or converted selection.
|
|
2463
|
+
* @param {module:engine/model/range~Range} data.range Range spanning over changed item or selection range.
|
|
2464
|
+
* @param {String} data.attributeKey Attribute key.
|
|
2465
|
+
* @param {*} data.attributeOldValue Attribute value before the change. This is `null` when selection attribute is converted.
|
|
2466
|
+
* @param {*} data.attributeNewValue New attribute value.
|
|
2467
|
+
* @returns {Object|null} A `{ key, value }` object. If `key` is `'class'`, `value` can be a `String` or an
|
|
2468
|
+
* array of `String`s. If `key` is `'style'`, `value` is an object with key-value pairs. In other cases, `value` is a `String`.
|
|
2469
|
+
*
|
|
2470
|
+
* @see module:engine/conversion/downcasthelpers~DowncastHelpers#attributeToAttribute
|
|
2471
|
+
*/
|
|
2472
|
+
|
|
2402
2473
|
/**
|
|
2403
2474
|
* A function that is expected to consume all the consumables that were used by the element creator.
|
|
2404
2475
|
*
|
package/src/conversion/mapper.js
CHANGED
|
@@ -121,9 +121,9 @@ export default class Mapper {
|
|
|
121
121
|
*
|
|
122
122
|
* Make sure that the model element is correctly converted to the view.
|
|
123
123
|
*
|
|
124
|
-
* @error mapping-
|
|
124
|
+
* @error mapping-model-position-view-parent-not-found
|
|
125
125
|
*/
|
|
126
|
-
throw new CKEditorError( 'mapping-
|
|
126
|
+
throw new CKEditorError( 'mapping-model-position-view-parent-not-found', this, { modelPosition: data.modelPosition } );
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
data.viewPosition = this.findPositionIn( viewContainer, data.modelPosition.offset );
|
|
@@ -151,6 +151,16 @@ export default class UpcastDispatcher {
|
|
|
151
151
|
*/
|
|
152
152
|
this._modelCursor = null;
|
|
153
153
|
|
|
154
|
+
/**
|
|
155
|
+
* The list of elements that were created during the splitting but should not get removed on conversion end even if they are empty.
|
|
156
|
+
*
|
|
157
|
+
* The list is cleared after the conversion process.
|
|
158
|
+
*
|
|
159
|
+
* @private
|
|
160
|
+
* @type {Set.<module:engine/model/element~Element>}
|
|
161
|
+
*/
|
|
162
|
+
this._emptyElementsToKeep = new Set();
|
|
163
|
+
|
|
154
164
|
/**
|
|
155
165
|
* An interface passed by the dispatcher to the event callbacks.
|
|
156
166
|
*
|
|
@@ -167,6 +177,7 @@ export default class UpcastDispatcher {
|
|
|
167
177
|
// Advanced API - use only if custom position handling is needed.
|
|
168
178
|
this.conversionApi.splitToAllowedParent = this._splitToAllowedParent.bind( this );
|
|
169
179
|
this.conversionApi.getSplitParts = this._getSplitParts.bind( this );
|
|
180
|
+
this.conversionApi.keepEmptyElement = this._keepEmptyElement.bind( this );
|
|
170
181
|
}
|
|
171
182
|
|
|
172
183
|
/**
|
|
@@ -226,6 +237,7 @@ export default class UpcastDispatcher {
|
|
|
226
237
|
// Clear split elements & parents lists.
|
|
227
238
|
this._splitParts.clear();
|
|
228
239
|
this._cursorParents.clear();
|
|
240
|
+
this._emptyElementsToKeep.clear();
|
|
229
241
|
|
|
230
242
|
// Clear conversion API.
|
|
231
243
|
this.conversionApi.writer = null;
|
|
@@ -451,6 +463,15 @@ export default class UpcastDispatcher {
|
|
|
451
463
|
return parts;
|
|
452
464
|
}
|
|
453
465
|
|
|
466
|
+
/**
|
|
467
|
+
* Mark an element that were created during the splitting to not get removed on conversion end even if it is empty.
|
|
468
|
+
*
|
|
469
|
+
* @private
|
|
470
|
+
*/
|
|
471
|
+
_keepEmptyElement( element ) {
|
|
472
|
+
this._emptyElementsToKeep.add( element );
|
|
473
|
+
}
|
|
474
|
+
|
|
454
475
|
/**
|
|
455
476
|
* Checks if there are any empty elements created while splitting and removes them.
|
|
456
477
|
*
|
|
@@ -463,7 +484,7 @@ export default class UpcastDispatcher {
|
|
|
463
484
|
let anyRemoved = false;
|
|
464
485
|
|
|
465
486
|
for ( const element of this._splitParts.keys() ) {
|
|
466
|
-
if ( element.isEmpty ) {
|
|
487
|
+
if ( element.isEmpty && !this._emptyElementsToKeep.has( element ) ) {
|
|
467
488
|
this.conversionApi.writer.remove( element );
|
|
468
489
|
this._splitParts.delete( element );
|
|
469
490
|
|
|
@@ -757,6 +778,15 @@ function createContextTree( contextDefinition, writer ) {
|
|
|
757
778
|
* @returns {Array.<module:engine/model/element~Element>}
|
|
758
779
|
*/
|
|
759
780
|
|
|
781
|
+
/**
|
|
782
|
+
* Mark an element that was created during splitting to not get removed on conversion end even if it is empty.
|
|
783
|
+
*
|
|
784
|
+
* **Note:** This is an advanced method. For most cases you will not need to keep the split empty element.
|
|
785
|
+
*
|
|
786
|
+
* @method #keepEmptyElement
|
|
787
|
+
* @param {module:engine/model/element~Element} element
|
|
788
|
+
*/
|
|
789
|
+
|
|
760
790
|
/**
|
|
761
791
|
* Stores information about what parts of the processed view item are still waiting to be handled. After a piece of view item
|
|
762
792
|
* was converted, an appropriate consumable value should be
|
|
@@ -465,6 +465,11 @@ export function convertText() {
|
|
|
465
465
|
return;
|
|
466
466
|
}
|
|
467
467
|
|
|
468
|
+
// Do not auto-paragraph whitespaces.
|
|
469
|
+
if ( data.viewItem.data.trim().length == 0 ) {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
|
|
468
473
|
position = wrapInParagraph( position, writer );
|
|
469
474
|
}
|
|
470
475
|
|
|
@@ -867,6 +872,13 @@ function prepareToAttributeConverter( config, shallow ) {
|
|
|
867
872
|
const matcher = new Matcher( config.view );
|
|
868
873
|
|
|
869
874
|
return ( evt, data, conversionApi ) => {
|
|
875
|
+
// Converting an attribute of an element that has not been converted to anything does not make sense
|
|
876
|
+
// because there will be nowhere to set that attribute on. At this stage, the element should've already
|
|
877
|
+
// been converted (https://github.com/ckeditor/ckeditor5/issues/11000).
|
|
878
|
+
if ( !data.modelRange && shallow ) {
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
|
|
870
882
|
const match = matcher.match( data.viewItem );
|
|
871
883
|
|
|
872
884
|
// If there is no match, this callback should not do anything.
|
|
@@ -877,7 +889,8 @@ function prepareToAttributeConverter( config, shallow ) {
|
|
|
877
889
|
if ( onlyViewNameIsDefined( config.view, data.viewItem ) ) {
|
|
878
890
|
match.match.name = true;
|
|
879
891
|
} else {
|
|
880
|
-
// Do not test
|
|
892
|
+
// Do not test `name` consumable because it could get consumed already while upcasting some other attribute
|
|
893
|
+
// on the same element (for example <span class="big" style="color: red">foo</span>).
|
|
881
894
|
delete match.match.name;
|
|
882
895
|
}
|
|
883
896
|
|
|
@@ -908,6 +921,15 @@ function prepareToAttributeConverter( config, shallow ) {
|
|
|
908
921
|
// It may happen that a converter will try to set an attribute that is not allowed in the given context.
|
|
909
922
|
// In such a situation we cannot consume the attribute. See: https://github.com/ckeditor/ckeditor5/pull/9249#issuecomment-815658459.
|
|
910
923
|
if ( attributeWasSet ) {
|
|
924
|
+
// Verify if the element itself wasn't consumed yet. It could be consumed already while upcasting some other attribute
|
|
925
|
+
// on the same element (for example <span class="big" style="color: red">foo</span>).
|
|
926
|
+
// We need to consume it so other features (especially GHS) won't try to convert it.
|
|
927
|
+
// Note that it's not tested by the other element-to-attribute converters whether an element was consumed before
|
|
928
|
+
// (in case of converters that the element itself is just a context and not the primary information to convert).
|
|
929
|
+
if ( conversionApi.consumable.test( data.viewItem, { name: true } ) ) {
|
|
930
|
+
match.match.name = true;
|
|
931
|
+
}
|
|
932
|
+
|
|
911
933
|
conversionApi.consumable.consume( data.viewItem, match.match );
|
|
912
934
|
}
|
|
913
935
|
};
|
package/src/index.js
CHANGED
|
@@ -28,11 +28,22 @@ export { default as LivePosition } from './model/liveposition';
|
|
|
28
28
|
export { default as Model } from './model/model';
|
|
29
29
|
export { default as TreeWalker } from './model/treewalker';
|
|
30
30
|
export { default as Element } from './model/element';
|
|
31
|
+
export { default as Position } from './model/position';
|
|
32
|
+
export { default as DocumentFragment } from './model/documentfragment';
|
|
31
33
|
export { default as History } from './model/history';
|
|
34
|
+
export { default as Text } from './model/text';
|
|
32
35
|
|
|
33
36
|
export { default as DomConverter } from './view/domconverter';
|
|
34
37
|
export { default as Renderer } from './view/renderer';
|
|
35
38
|
export { default as ViewDocument } from './view/document';
|
|
39
|
+
export { default as ViewText } from './view/text';
|
|
40
|
+
export { default as ViewElement } from './view/element';
|
|
41
|
+
export { default as ViewContainerElement } from './view/containerelement';
|
|
42
|
+
export { default as ViewAttributeElement } from './view/attributeelement';
|
|
43
|
+
export { default as ViewEmptyElement } from './view/emptyelement';
|
|
44
|
+
export { default as ViewRawElement } from './view/rawelement';
|
|
45
|
+
export { default as ViewUIElement } from './view/uielement';
|
|
46
|
+
export { default as ViewDocumentFragment } from './view/documentfragment';
|
|
36
47
|
|
|
37
48
|
export { getFillerOffset } from './view/containerelement';
|
|
38
49
|
export { default as Observer } from './view/observer/observer';
|
package/src/model/differ.js
CHANGED
|
@@ -336,23 +336,27 @@ export default class Differ {
|
|
|
336
336
|
* @returns {Boolean}
|
|
337
337
|
*/
|
|
338
338
|
hasDataChanges() {
|
|
339
|
+
if ( this._changesInElement.size > 0 ) {
|
|
340
|
+
return true;
|
|
341
|
+
}
|
|
342
|
+
|
|
339
343
|
for ( const { newMarkerData, oldMarkerData } of this._changedMarkers.values() ) {
|
|
340
344
|
if ( newMarkerData.affectsData !== oldMarkerData.affectsData ) {
|
|
341
345
|
return true;
|
|
342
346
|
}
|
|
343
347
|
|
|
344
348
|
if ( newMarkerData.affectsData ) {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
}
|
|
349
|
+
const markerAdded = newMarkerData.range && !oldMarkerData.range;
|
|
350
|
+
const markerRemoved = !newMarkerData.range && oldMarkerData.range;
|
|
351
|
+
const markerChanged = newMarkerData.range && oldMarkerData.range && !newMarkerData.range.isEqual( oldMarkerData.range );
|
|
349
352
|
|
|
350
|
-
|
|
353
|
+
if ( markerAdded || markerRemoved || markerChanged ) {
|
|
354
|
+
return true;
|
|
355
|
+
}
|
|
351
356
|
}
|
|
352
357
|
}
|
|
353
358
|
|
|
354
|
-
|
|
355
|
-
return this._changesInElement.size > 0;
|
|
359
|
+
return false;
|
|
356
360
|
}
|
|
357
361
|
|
|
358
362
|
/**
|
|
@@ -419,12 +423,12 @@ export default class Differ {
|
|
|
419
423
|
for ( const action of actions ) {
|
|
420
424
|
if ( action === 'i' ) {
|
|
421
425
|
// Generate diff item for this element and insert it into the diff set.
|
|
422
|
-
diffSet.push( this._getInsertDiff( element, i, elementChildren[ i ]
|
|
426
|
+
diffSet.push( this._getInsertDiff( element, i, elementChildren[ i ] ) );
|
|
423
427
|
|
|
424
428
|
i++;
|
|
425
429
|
} else if ( action === 'r' ) {
|
|
426
430
|
// Generate diff item for this element and insert it into the diff set.
|
|
427
|
-
diffSet.push( this._getRemoveDiff( element, i, snapshotChildren[ j ]
|
|
431
|
+
diffSet.push( this._getRemoveDiff( element, i, snapshotChildren[ j ] ) );
|
|
428
432
|
|
|
429
433
|
j++;
|
|
430
434
|
} else if ( action === 'a' ) {
|
|
@@ -925,14 +929,15 @@ export default class Differ {
|
|
|
925
929
|
* @private
|
|
926
930
|
* @param {module:engine/model/element~Element} parent The element in which the change happened.
|
|
927
931
|
* @param {Number} offset The offset at which change happened.
|
|
928
|
-
* @param {
|
|
932
|
+
* @param {Object} elementSnapshot The snapshot of the removed element a character.
|
|
929
933
|
* @returns {Object} The diff item.
|
|
930
934
|
*/
|
|
931
|
-
_getInsertDiff( parent, offset,
|
|
935
|
+
_getInsertDiff( parent, offset, elementSnapshot ) {
|
|
932
936
|
return {
|
|
933
937
|
type: 'insert',
|
|
934
938
|
position: Position._createAt( parent, offset ),
|
|
935
|
-
name,
|
|
939
|
+
name: elementSnapshot.name,
|
|
940
|
+
attributes: new Map( elementSnapshot.attributes ),
|
|
936
941
|
length: 1,
|
|
937
942
|
changeCount: this._changeCount++
|
|
938
943
|
};
|
|
@@ -944,14 +949,15 @@ export default class Differ {
|
|
|
944
949
|
* @private
|
|
945
950
|
* @param {module:engine/model/element~Element} parent The element in which change happened.
|
|
946
951
|
* @param {Number} offset The offset at which change happened.
|
|
947
|
-
* @param {
|
|
952
|
+
* @param {Object} elementSnapshot The snapshot of the removed element a character.
|
|
948
953
|
* @returns {Object} The diff item.
|
|
949
954
|
*/
|
|
950
|
-
_getRemoveDiff( parent, offset,
|
|
955
|
+
_getRemoveDiff( parent, offset, elementSnapshot ) {
|
|
951
956
|
return {
|
|
952
957
|
type: 'remove',
|
|
953
958
|
position: Position._createAt( parent, offset ),
|
|
954
|
-
name,
|
|
959
|
+
name: elementSnapshot.name,
|
|
960
|
+
attributes: new Map( elementSnapshot.attributes ),
|
|
955
961
|
length: 1,
|
|
956
962
|
changeCount: this._changeCount++
|
|
957
963
|
};
|
|
@@ -1229,6 +1235,12 @@ function _changesInGraveyardFilter( entry ) {
|
|
|
1229
1235
|
* @member {String} module:engine/model/differ~DiffItemInsert#name
|
|
1230
1236
|
*/
|
|
1231
1237
|
|
|
1238
|
+
/**
|
|
1239
|
+
* Map of attributes that were set on the item while it was inserted.
|
|
1240
|
+
*
|
|
1241
|
+
* @member {Map.<String,*>} module:engine/model/differ~DiffItemInsert#attributes
|
|
1242
|
+
*/
|
|
1243
|
+
|
|
1232
1244
|
/**
|
|
1233
1245
|
* The position where the node was inserted.
|
|
1234
1246
|
*
|
|
@@ -1260,6 +1272,12 @@ function _changesInGraveyardFilter( entry ) {
|
|
|
1260
1272
|
* @member {String} module:engine/model/differ~DiffItemRemove#name
|
|
1261
1273
|
*/
|
|
1262
1274
|
|
|
1275
|
+
/**
|
|
1276
|
+
* Map of attributes that were set on the item while it was removed.
|
|
1277
|
+
*
|
|
1278
|
+
* @member {Map.<String,*>} module:engine/model/differ~DiffItemRemove#attributes
|
|
1279
|
+
*/
|
|
1280
|
+
|
|
1263
1281
|
/**
|
|
1264
1282
|
* The position where the node was removed.
|
|
1265
1283
|
*
|
package/src/model/document.js
CHANGED
|
@@ -52,24 +52,13 @@ export default class Document {
|
|
|
52
52
|
*/
|
|
53
53
|
this.model = model;
|
|
54
54
|
|
|
55
|
-
/**
|
|
56
|
-
* The document version. It starts from `0` and every operation increases the version number. It is used to ensure that
|
|
57
|
-
* operations are applied on a proper document version.
|
|
58
|
-
*
|
|
59
|
-
* If the {@link module:engine/model/operation/operation~Operation#baseVersion base version} does not match the document version,
|
|
60
|
-
* a {@link module:utils/ckeditorerror~CKEditorError model-document-applyoperation-wrong-version} error is thrown.
|
|
61
|
-
*
|
|
62
|
-
* @type {Number}
|
|
63
|
-
*/
|
|
64
|
-
this.version = 0;
|
|
65
|
-
|
|
66
55
|
/**
|
|
67
56
|
* The document's history.
|
|
68
57
|
*
|
|
69
58
|
* @readonly
|
|
70
59
|
* @type {module:engine/model/history~History}
|
|
71
60
|
*/
|
|
72
|
-
this.history = new History(
|
|
61
|
+
this.history = new History();
|
|
73
62
|
|
|
74
63
|
/**
|
|
75
64
|
* The selection in this document.
|
|
@@ -115,21 +104,6 @@ export default class Document {
|
|
|
115
104
|
// Graveyard tree root. Document always have a graveyard root, which stores removed nodes.
|
|
116
105
|
this.createRoot( '$root', graveyardName );
|
|
117
106
|
|
|
118
|
-
// First, if the operation is a document operation check if it's base version is correct.
|
|
119
|
-
this.listenTo( model, 'applyOperation', ( evt, args ) => {
|
|
120
|
-
const operation = args[ 0 ];
|
|
121
|
-
|
|
122
|
-
if ( operation.isDocumentOperation && operation.baseVersion !== this.version ) {
|
|
123
|
-
/**
|
|
124
|
-
* Only operations with matching versions can be applied.
|
|
125
|
-
*
|
|
126
|
-
* @error model-document-applyoperation-wrong-version
|
|
127
|
-
* @param {module:engine/model/operation/operation~Operation} operation
|
|
128
|
-
*/
|
|
129
|
-
throw new CKEditorError( 'model-document-applyoperation-wrong-version', this, { operation } );
|
|
130
|
-
}
|
|
131
|
-
}, { priority: 'highest' } );
|
|
132
|
-
|
|
133
107
|
// Then, still before an operation is applied on model, buffer the change in differ.
|
|
134
108
|
this.listenTo( model, 'applyOperation', ( evt, args ) => {
|
|
135
109
|
const operation = args[ 0 ];
|
|
@@ -144,7 +118,6 @@ export default class Document {
|
|
|
144
118
|
const operation = args[ 0 ];
|
|
145
119
|
|
|
146
120
|
if ( operation.isDocumentOperation ) {
|
|
147
|
-
this.version++;
|
|
148
121
|
this.history.addOperation( operation );
|
|
149
122
|
}
|
|
150
123
|
}, { priority: 'low' } );
|
|
@@ -179,6 +152,25 @@ export default class Document {
|
|
|
179
152
|
} );
|
|
180
153
|
}
|
|
181
154
|
|
|
155
|
+
/**
|
|
156
|
+
* The document version. Every applied operation increases the version number. It is used to
|
|
157
|
+
* ensure that operations are applied on a proper document version.
|
|
158
|
+
*
|
|
159
|
+
* This property is equal to {@link module:engine/model/history~History#version `model.Document#history#version`}.
|
|
160
|
+
*
|
|
161
|
+
* If the {@link module:engine/model/operation/operation~Operation#baseVersion base version} does not match the document version,
|
|
162
|
+
* a {@link module:utils/ckeditorerror~CKEditorError model-document-applyoperation-wrong-version} error is thrown.
|
|
163
|
+
*
|
|
164
|
+
* @type {Number}
|
|
165
|
+
*/
|
|
166
|
+
get version() {
|
|
167
|
+
return this.history.version;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
set version( version ) {
|
|
171
|
+
this.history.version = version;
|
|
172
|
+
}
|
|
173
|
+
|
|
182
174
|
/**
|
|
183
175
|
* The graveyard tree root. A document always has a graveyard root that stores removed nodes.
|
|
184
176
|
*
|