@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/LICENSE.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Software License Agreement
|
|
2
2
|
==========================
|
|
3
3
|
|
|
4
|
-
**CKEditor 5
|
|
4
|
+
**CKEditor 5 editing engine** – https://github.com/ckeditor/ckeditor5-engine <br>
|
|
5
5
|
Copyright (c) 2003-2021, [CKSource](http://cksource.com) Frederico Knabben. 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).
|
package/README.md
CHANGED
|
@@ -2,8 +2,8 @@ CKEditor 5 editing engine
|
|
|
2
2
|
========================================
|
|
3
3
|
|
|
4
4
|
[](https://www.npmjs.com/package/@ckeditor/ckeditor5-engine)
|
|
5
|
-
[](https://coveralls.io/github/ckeditor/ckeditor5?branch=master)
|
|
6
|
+
[](https://travis-ci.com/ckeditor/ckeditor5)
|
|
7
7
|
|
|
8
8
|
The CKEditor 5 editing engine implements a flexible MVC-based architecture for creating rich text editing features.
|
|
9
9
|
|
|
@@ -21,7 +21,7 @@ The CKEditor 5 editing engine implements a flexible MVC-based architecture for c
|
|
|
21
21
|
|
|
22
22
|
## Documentation
|
|
23
23
|
|
|
24
|
-
For a general introduction see the [Overview of CKEditor 5 Framework](https://ckeditor.com/docs/ckeditor5/latest/framework/guides/overview.html) guide and then the [Editing engine architecture](https://ckeditor.com/docs/ckeditor5/latest/framework/guides/architecture/editing-engine.html)
|
|
24
|
+
For a general introduction see the [Overview of CKEditor 5 Framework](https://ckeditor.com/docs/ckeditor5/latest/framework/guides/overview.html) guide and then the [Editing engine architecture guide](https://ckeditor.com/docs/ckeditor5/latest/framework/guides/architecture/editing-engine.html).
|
|
25
25
|
|
|
26
26
|
Additionally, refer to the [`@ckeditor/ckeditor5-engine` package](https://ckeditor.com/docs/ckeditor5/latest/api/engine.html) page in [CKEditor 5 documentation](https://ckeditor.com/docs/ckeditor5/latest/) for even more information.
|
|
27
27
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ckeditor/ckeditor5-engine",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "29.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,28 +23,28 @@
|
|
|
23
23
|
],
|
|
24
24
|
"main": "src/index.js",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@ckeditor/ckeditor5-utils": "^
|
|
26
|
+
"@ckeditor/ckeditor5-utils": "^29.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-core": "^
|
|
34
|
-
"@ckeditor/ckeditor5-editor-classic": "^
|
|
35
|
-
"@ckeditor/ckeditor5-enter": "^
|
|
36
|
-
"@ckeditor/ckeditor5-essentials": "^
|
|
37
|
-
"@ckeditor/ckeditor5-heading": "^
|
|
38
|
-
"@ckeditor/ckeditor5-image": "^
|
|
39
|
-
"@ckeditor/ckeditor5-link": "^
|
|
40
|
-
"@ckeditor/ckeditor5-list": "^
|
|
41
|
-
"@ckeditor/ckeditor5-paragraph": "^
|
|
42
|
-
"@ckeditor/ckeditor5-table": "^
|
|
43
|
-
"@ckeditor/ckeditor5-theme-lark": "^
|
|
44
|
-
"@ckeditor/ckeditor5-typing": "^
|
|
45
|
-
"@ckeditor/ckeditor5-ui": "^
|
|
46
|
-
"@ckeditor/ckeditor5-undo": "^
|
|
47
|
-
"@ckeditor/ckeditor5-widget": "^
|
|
30
|
+
"@ckeditor/ckeditor5-basic-styles": "^29.2.0",
|
|
31
|
+
"@ckeditor/ckeditor5-block-quote": "^29.2.0",
|
|
32
|
+
"@ckeditor/ckeditor5-clipboard": "^29.2.0",
|
|
33
|
+
"@ckeditor/ckeditor5-core": "^29.2.0",
|
|
34
|
+
"@ckeditor/ckeditor5-editor-classic": "^29.2.0",
|
|
35
|
+
"@ckeditor/ckeditor5-enter": "^29.2.0",
|
|
36
|
+
"@ckeditor/ckeditor5-essentials": "^29.2.0",
|
|
37
|
+
"@ckeditor/ckeditor5-heading": "^29.2.0",
|
|
38
|
+
"@ckeditor/ckeditor5-image": "^29.2.0",
|
|
39
|
+
"@ckeditor/ckeditor5-link": "^29.2.0",
|
|
40
|
+
"@ckeditor/ckeditor5-list": "^29.2.0",
|
|
41
|
+
"@ckeditor/ckeditor5-paragraph": "^29.2.0",
|
|
42
|
+
"@ckeditor/ckeditor5-table": "^29.2.0",
|
|
43
|
+
"@ckeditor/ckeditor5-theme-lark": "^29.2.0",
|
|
44
|
+
"@ckeditor/ckeditor5-typing": "^29.2.0",
|
|
45
|
+
"@ckeditor/ckeditor5-ui": "^29.2.0",
|
|
46
|
+
"@ckeditor/ckeditor5-undo": "^29.2.0",
|
|
47
|
+
"@ckeditor/ckeditor5-widget": "^29.2.0",
|
|
48
48
|
"webpack": "^4.43.0",
|
|
49
49
|
"webpack-cli": "^3.3.11"
|
|
50
50
|
},
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
"files": [
|
|
65
65
|
"lang",
|
|
66
66
|
"src",
|
|
67
|
-
"theme"
|
|
67
|
+
"theme",
|
|
68
|
+
"ckeditor5-metadata.json"
|
|
68
69
|
]
|
|
69
70
|
}
|
|
@@ -251,6 +251,7 @@ export default class DataController {
|
|
|
251
251
|
// For document fragment, simply take the markers assigned to this document fragment.
|
|
252
252
|
// For model root, all markers in that root will be taken.
|
|
253
253
|
// For model element, we need to check which markers are intersecting with this element and relatively modify the markers' ranges.
|
|
254
|
+
// Collapsed markers at element boundary, although considered as not intersecting with the element, will also be returned.
|
|
254
255
|
const markers = modelElementOrFragment.is( 'documentFragment' ) ?
|
|
255
256
|
Array.from( modelElementOrFragment.markers ) :
|
|
256
257
|
_getMarkersRelativeToElement( modelElementOrFragment );
|
|
@@ -347,11 +348,19 @@ export default class DataController {
|
|
|
347
348
|
*
|
|
348
349
|
* dataController.set( { main: '<p>Foo</p>', title: '<h1>Bar</h1>' } ); // Sets data on the `main` and `title` roots.
|
|
349
350
|
*
|
|
351
|
+
* To set the data with preserved undo stacks and set the current change to this stack, use the `{ batchType: 'default' }` option.
|
|
352
|
+
*
|
|
353
|
+
* dataController.set( '<p>Foo</p>', { batchType: 'default' } ); // Sets data as a new change.
|
|
354
|
+
*
|
|
350
355
|
* @fires set
|
|
351
356
|
* @param {String|Object.<String,String>} data Input data as a string or an object containing `rootName` - `data`
|
|
352
357
|
* pairs to set data on multiple roots at once.
|
|
358
|
+
* @param {Object} [options={}] Options for setting data.
|
|
359
|
+
* @param {'default'|'transparent'} [options.batchType='default'] The batch type that will be used to create a batch for the changes.
|
|
360
|
+
* When set to `default`, the undo and redo stacks will be preserved. Note that when not set, the undo feature (when present) will
|
|
361
|
+
* override it to `transparent` and all undo steps will be lost.
|
|
353
362
|
*/
|
|
354
|
-
set( data ) {
|
|
363
|
+
set( data, options = {} ) {
|
|
355
364
|
let newData = {};
|
|
356
365
|
|
|
357
366
|
if ( typeof data === 'string' ) {
|
|
@@ -375,7 +384,9 @@ export default class DataController {
|
|
|
375
384
|
throw new CKEditorError( 'datacontroller-set-non-existent-root', this );
|
|
376
385
|
}
|
|
377
386
|
|
|
378
|
-
|
|
387
|
+
const batchType = options.batchType || 'default';
|
|
388
|
+
|
|
389
|
+
this.model.enqueueChange( batchType, writer => {
|
|
379
390
|
writer.setSelection( null );
|
|
380
391
|
writer.removeSelectionAttribute( this.model.document.selection.getAttributeKeys() );
|
|
381
392
|
|
|
@@ -518,8 +529,9 @@ mix( DataController, ObservableMixin );
|
|
|
518
529
|
|
|
519
530
|
// Helper function for downcast conversion.
|
|
520
531
|
//
|
|
521
|
-
// Takes a document element (element that is added to a model document) and checks which markers are inside it
|
|
522
|
-
//
|
|
532
|
+
// Takes a document element (element that is added to a model document) and checks which markers are inside it. If the marker is collapsed
|
|
533
|
+
// at element boundary, it is considered as contained inside the element and marker range is returned. Otherwise, if the marker is
|
|
534
|
+
// intersecting with the element, the intersection is returned.
|
|
523
535
|
function _getMarkersRelativeToElement( element ) {
|
|
524
536
|
const result = [];
|
|
525
537
|
const doc = element.root.document;
|
|
@@ -531,10 +543,19 @@ function _getMarkersRelativeToElement( element ) {
|
|
|
531
543
|
const elementRange = ModelRange._createIn( element );
|
|
532
544
|
|
|
533
545
|
for ( const marker of doc.model.markers ) {
|
|
534
|
-
const
|
|
546
|
+
const markerRange = marker.getRange();
|
|
535
547
|
|
|
536
|
-
|
|
537
|
-
|
|
548
|
+
const isMarkerCollapsed = markerRange.isCollapsed;
|
|
549
|
+
const isMarkerAtElementBoundary = markerRange.start.isEqual( elementRange.start ) || markerRange.end.isEqual( elementRange.end );
|
|
550
|
+
|
|
551
|
+
if ( isMarkerCollapsed && isMarkerAtElementBoundary ) {
|
|
552
|
+
result.push( [ marker.name, markerRange ] );
|
|
553
|
+
} else {
|
|
554
|
+
const updatedMarkerRange = elementRange.getIntersection( markerRange );
|
|
555
|
+
|
|
556
|
+
if ( updatedMarkerRange ) {
|
|
557
|
+
result.push( [ marker.name, updatedMarkerRange ] );
|
|
558
|
+
}
|
|
538
559
|
}
|
|
539
560
|
}
|
|
540
561
|
|
|
@@ -104,7 +104,7 @@ export default class EditingController {
|
|
|
104
104
|
this.downcastDispatcher.on( 'remove', remove(), { priority: 'low' } );
|
|
105
105
|
|
|
106
106
|
// Attach default model selection converters.
|
|
107
|
-
this.downcastDispatcher.on( 'selection', clearAttributes(), { priority: '
|
|
107
|
+
this.downcastDispatcher.on( 'selection', clearAttributes(), { priority: 'high' } );
|
|
108
108
|
this.downcastDispatcher.on( 'selection', convertRangeSelection(), { priority: 'low' } );
|
|
109
109
|
this.downcastDispatcher.on( 'selection', convertCollapsedSelection(), { priority: 'low' } );
|
|
110
110
|
|
|
@@ -448,8 +448,8 @@ export default class Conversion {
|
|
|
448
448
|
}
|
|
449
449
|
|
|
450
450
|
/**
|
|
451
|
-
* Sets up converters between the model and the view that convert a model attribute to a view attribute (and vice versa).
|
|
452
|
-
*
|
|
451
|
+
* Sets up converters between the model and the view that convert a model attribute to a view attribute (and vice versa). For example,
|
|
452
|
+
* `<imageBlock src='foo.jpg'></imageBlock>` is converted to `<img src='foo.jpg'></img>` (the same attribute key and value).
|
|
453
453
|
* This type of converters is intended to be used with {@link module:engine/model/element~Element model element} nodes.
|
|
454
454
|
* To convert text attributes {@link module:engine/conversion/conversion~Conversion#attributeToElement `attributeToElement converter`}
|
|
455
455
|
* should be set up.
|
|
@@ -460,7 +460,7 @@ export default class Conversion {
|
|
|
460
460
|
* // Attribute values are strictly specified.
|
|
461
461
|
* editor.conversion.attributeToAttribute( {
|
|
462
462
|
* model: {
|
|
463
|
-
* name: '
|
|
463
|
+
* name: 'imageInline',
|
|
464
464
|
* key: 'aside',
|
|
465
465
|
* values: [ 'aside' ]
|
|
466
466
|
* },
|
|
@@ -476,7 +476,7 @@ export default class Conversion {
|
|
|
476
476
|
* // Set the style attribute.
|
|
477
477
|
* editor.conversion.attributeToAttribute( {
|
|
478
478
|
* model: {
|
|
479
|
-
* name: '
|
|
479
|
+
* name: 'imageInline',
|
|
480
480
|
* key: 'aside',
|
|
481
481
|
* values: [ 'aside' ]
|
|
482
482
|
* },
|
|
@@ -88,7 +88,7 @@ import mix from '@ckeditor/ckeditor5-utils/src/mix';
|
|
|
88
88
|
* // You will convert inserting a "paragraph" model element into the model.
|
|
89
89
|
* downcastDispatcher.on( 'insert:paragraph', ( evt, data, conversionApi ) => {
|
|
90
90
|
* // Remember to check whether the change has not been consumed yet and consume it.
|
|
91
|
-
* if ( conversionApi.consumable.consume( data.item, 'insert' ) ) {
|
|
91
|
+
* if ( !conversionApi.consumable.consume( data.item, 'insert' ) ) {
|
|
92
92
|
* return;
|
|
93
93
|
* }
|
|
94
94
|
*
|
|
@@ -341,6 +341,8 @@ export default class DowncastDispatcher {
|
|
|
341
341
|
this.fire( 'selection', { selection }, this.conversionApi );
|
|
342
342
|
|
|
343
343
|
if ( !selection.isCollapsed ) {
|
|
344
|
+
this._clearConversionApi();
|
|
345
|
+
|
|
344
346
|
return;
|
|
345
347
|
}
|
|
346
348
|
|
|
@@ -414,6 +416,8 @@ export default class DowncastDispatcher {
|
|
|
414
416
|
// Do not fire events for each item inside the range if the range got consumed.
|
|
415
417
|
//
|
|
416
418
|
if ( !consumable.test( markerRange, eventName ) ) {
|
|
419
|
+
this._clearConversionApi();
|
|
420
|
+
|
|
417
421
|
return;
|
|
418
422
|
}
|
|
419
423
|
|
|
@@ -736,7 +740,7 @@ export default class DowncastDispatcher {
|
|
|
736
740
|
* `name` is either `'$text'` if change was on {@link module:engine/model/text~Text a text node},
|
|
737
741
|
* or the {@link module:engine/model/element~Element#name name} of element which attribute has changed.
|
|
738
742
|
*
|
|
739
|
-
* This way listeners can either listen to a general `attribute:bold` event or specific event (for example `attribute:src:
|
|
743
|
+
* This way listeners can either listen to a general `attribute:bold` event or specific event (for example `attribute:src:imageBlock`).
|
|
740
744
|
*
|
|
741
745
|
* @event attribute
|
|
742
746
|
* @param {Object} data Additional information about the change.
|
|
@@ -190,7 +190,7 @@ export default class DowncastHelpers extends ConversionHelpers {
|
|
|
190
190
|
* Model attribute to view attribute conversion helper.
|
|
191
191
|
*
|
|
192
192
|
* This conversion results in adding an attribute to a view node, basing on an attribute from a model node. For example,
|
|
193
|
-
* `<
|
|
193
|
+
* `<imageInline src='foo.jpg'></imageInline>` is converted to `<img src='foo.jpg'></img>`.
|
|
194
194
|
*
|
|
195
195
|
* editor.conversion.for( 'downcast' ).attributeToAttribute( {
|
|
196
196
|
* model: 'source',
|
|
@@ -205,7 +205,7 @@ export default class DowncastHelpers extends ConversionHelpers {
|
|
|
205
205
|
*
|
|
206
206
|
* editor.conversion.for( 'downcast' ).attributeToAttribute( {
|
|
207
207
|
* model: {
|
|
208
|
-
* name: '
|
|
208
|
+
* name: 'imageInline',
|
|
209
209
|
* key: 'source'
|
|
210
210
|
* },
|
|
211
211
|
* view: 'src'
|
|
@@ -272,8 +272,11 @@ export default class DowncastHelpers extends ConversionHelpers {
|
|
|
272
272
|
/**
|
|
273
273
|
* Model marker to view element conversion helper.
|
|
274
274
|
*
|
|
275
|
-
* **Note**: This method should be used
|
|
276
|
-
* {@link #markerToData `#markerToData()`}
|
|
275
|
+
* **Note**: This method should be used mainly for editing downcast and it is recommended
|
|
276
|
+
* to use {@link #markerToData `#markerToData()`} helper instead.
|
|
277
|
+
*
|
|
278
|
+
* This helper may produce invalid HTML code (e.g. a span between table cells).
|
|
279
|
+
* It should be used only when you are sure that the produced HTML will be semantically correct.
|
|
277
280
|
*
|
|
278
281
|
* This conversion results in creating a view element on the boundaries of the converted marker. If the converted marker
|
|
279
282
|
* is collapsed, only one element is created. For example, model marker set like this: `<paragraph>F[oo b]ar</paragraph>`
|
|
@@ -349,8 +352,8 @@ export default class DowncastHelpers extends ConversionHelpers {
|
|
|
349
352
|
*
|
|
350
353
|
* {@link module:engine/view/containerelement~ContainerElement} may provide a custom way of handling highlight. Most often,
|
|
351
354
|
* the element itself is given classes and attributes described in the highlight descriptor (instead of being wrapped in `<span>`).
|
|
352
|
-
* For example, a model marker set like this:
|
|
353
|
-
* in the view.
|
|
355
|
+
* For example, a model marker set like this:
|
|
356
|
+
* `[<imageInline src="foo.jpg"></imageInline>]` becomes `<img src="foo.jpg" class="comment"></img>` in the view.
|
|
354
357
|
*
|
|
355
358
|
* For container elements, the conversion is two-step. While the converter processes the highlight descriptor and passes it
|
|
356
359
|
* to a container element, it is the container element instance itself that applies values from the highlight descriptor.
|
|
@@ -405,34 +408,33 @@ export default class DowncastHelpers extends ConversionHelpers {
|
|
|
405
408
|
*
|
|
406
409
|
* This conversion creates a representation for model marker boundaries in the view:
|
|
407
410
|
*
|
|
408
|
-
* * If the marker boundary is
|
|
409
|
-
*
|
|
410
|
-
* * In other cases, a specified attribute is set on a view element that is before or after the marker boundary.
|
|
411
|
+
* * If the marker boundary is before or after a model element, a view attribute is set on a corresponding view element.
|
|
412
|
+
* * In other cases, a view element with the specified tag name is inserted at the corresponding view position.
|
|
411
413
|
*
|
|
412
|
-
* Typically, marker names use the `group:uniqueId:otherData` convention. For example: `comment:e34zfk9k2n459df53sjl34:zx32c`.
|
|
414
|
+
* Typically, the marker names use the `group:uniqueId:otherData` convention. For example: `comment:e34zfk9k2n459df53sjl34:zx32c`.
|
|
413
415
|
* The default configuration for this conversion is that the first part is the `group` part and the rest of
|
|
414
416
|
* the marker name becomes the `name` part.
|
|
415
417
|
*
|
|
416
418
|
* Tag and attribute names and values are generated from the marker name:
|
|
417
419
|
*
|
|
418
|
-
* *
|
|
420
|
+
* * The templates for attributes are `data-[group]-start-before="[name]"`, `data-[group]-start-after="[name]"`,
|
|
419
421
|
* `data-[group]-end-before="[name]"` and `data-[group]-end-after="[name]"`.
|
|
420
|
-
* *
|
|
422
|
+
* * The templates for view elements are `<[group]-start name="[name]">` and `<[group]-end name="[name]">`.
|
|
421
423
|
*
|
|
422
424
|
* Attributes mark whether the given marker's start or end boundary is before or after the given element.
|
|
423
|
-
*
|
|
425
|
+
* The `data-[group]-start-before` and `data-[group]-end-after` attributes are favored.
|
|
424
426
|
* The other two are used when the former two cannot be used.
|
|
425
427
|
*
|
|
426
428
|
* The conversion configuration can take a function that will generate different group and name parts.
|
|
427
|
-
* If such function is set as the `config.view` parameter, it is passed a marker name and it is expected to return an object with two
|
|
429
|
+
* If such a function is set as the `config.view` parameter, it is passed a marker name and it is expected to return an object with two
|
|
428
430
|
* properties: `group` and `name`. If the function returns a falsy value, the conversion will not take place.
|
|
429
431
|
*
|
|
430
432
|
* Basic usage:
|
|
431
433
|
*
|
|
432
434
|
* // Using the default conversion.
|
|
433
|
-
* // In this case, all markers
|
|
435
|
+
* // In this case, all markers with names starting with 'comment:' will be converted.
|
|
434
436
|
* // The `group` parameter will be set to `comment`.
|
|
435
|
-
* // The `name` parameter will be the rest of the marker name (without `:`).
|
|
437
|
+
* // The `name` parameter will be the rest of the marker name (without the `:`).
|
|
436
438
|
* editor.conversion.for( 'dataDowncast' ).markerToData( {
|
|
437
439
|
* model: 'comment'
|
|
438
440
|
* } );
|
|
@@ -442,7 +444,7 @@ export default class DowncastHelpers extends ConversionHelpers {
|
|
|
442
444
|
*
|
|
443
445
|
* // Model:
|
|
444
446
|
* <paragraph>Foo[bar</paragraph>
|
|
445
|
-
* <
|
|
447
|
+
* <imageBlock src="abc.jpg"></imageBlock>]
|
|
446
448
|
*
|
|
447
449
|
* // View:
|
|
448
450
|
* <p>Foo<comment-start name="commentId:uid"></comment-start>bar</p>
|
|
@@ -455,7 +457,7 @@ export default class DowncastHelpers extends ConversionHelpers {
|
|
|
455
457
|
* <p>Foo <myMarker-start></myMarker-start>bar</p>
|
|
456
458
|
* <figure data-myMarker-end-after="" class="image"><img src="abc.jpg" /></figure>
|
|
457
459
|
*
|
|
458
|
-
* **Note:** A situation where some markers have the `name` part and some do not
|
|
460
|
+
* **Note:** A situation where some markers have the `name` part and some do not, is incorrect and should be avoided.
|
|
459
461
|
*
|
|
460
462
|
* Examples where `data-group-start-after` and `data-group-end-before` are used:
|
|
461
463
|
*
|
|
@@ -499,14 +501,14 @@ export default class DowncastHelpers extends ConversionHelpers {
|
|
|
499
501
|
*
|
|
500
502
|
* This kind of conversion is useful for saving data into the database, so it should be used in the data conversion pipeline.
|
|
501
503
|
*
|
|
502
|
-
* See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to
|
|
503
|
-
* to the conversion process.
|
|
504
|
+
* See the {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} API guide to learn how to
|
|
505
|
+
* add a converter to the conversion process.
|
|
504
506
|
*
|
|
505
507
|
* @method #markerToData
|
|
506
508
|
* @param {Object} config Conversion configuration.
|
|
507
|
-
* @param {String} config.model The name of the model marker (or model marker group) to convert.
|
|
509
|
+
* @param {String} config.model The name of the model marker (or the model marker group) to convert.
|
|
508
510
|
* @param {Function} [config.view] A function that takes the model marker name and
|
|
509
|
-
* {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API} as
|
|
511
|
+
* {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API} as the parameters
|
|
510
512
|
* and returns an object with the `group` and `name` properties.
|
|
511
513
|
* @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.
|
|
512
514
|
* @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}
|
|
@@ -549,7 +551,7 @@ export function insertText() {
|
|
|
549
551
|
*/
|
|
550
552
|
export function remove() {
|
|
551
553
|
return ( evt, data, conversionApi ) => {
|
|
552
|
-
// Find view range start position by mapping model position at which the remove happened.
|
|
554
|
+
// Find the view range start position by mapping the model position at which the remove happened.
|
|
553
555
|
const viewStart = conversionApi.mapper.toViewPosition( data.position );
|
|
554
556
|
|
|
555
557
|
const modelEnd = data.position.getShiftedBy( data.length );
|
|
@@ -570,7 +572,7 @@ export function remove() {
|
|
|
570
572
|
|
|
571
573
|
/**
|
|
572
574
|
* Creates a `<span>` {@link module:engine/view/attributeelement~AttributeElement view attribute element} from the information
|
|
573
|
-
* provided by the {@link module:engine/conversion/downcasthelpers~HighlightDescriptor highlight descriptor} object. If
|
|
575
|
+
* provided by the {@link module:engine/conversion/downcasthelpers~HighlightDescriptor highlight descriptor} object. If the priority
|
|
574
576
|
* is not provided in the descriptor, the default priority will be used.
|
|
575
577
|
*
|
|
576
578
|
* @param {module:engine/view/downcastwriter~DowncastWriter} writer
|
|
@@ -584,7 +586,7 @@ export function createViewElementFromHighlightDescriptor( writer, descriptor ) {
|
|
|
584
586
|
viewElement._addClass( descriptor.classes );
|
|
585
587
|
}
|
|
586
588
|
|
|
587
|
-
if ( descriptor.priority ) {
|
|
589
|
+
if ( typeof descriptor.priority === 'number' ) {
|
|
588
590
|
viewElement._priority = descriptor.priority;
|
|
589
591
|
}
|
|
590
592
|
|
|
@@ -945,33 +947,40 @@ function insertMarkerData( viewCreator ) {
|
|
|
945
947
|
// Helper function for `insertMarkerData()` that marks a marker boundary at the beginning or end of given `range`.
|
|
946
948
|
function handleMarkerBoundary( range, isStart, conversionApi, data, viewMarkerData ) {
|
|
947
949
|
const modelPosition = isStart ? range.start : range.end;
|
|
948
|
-
const
|
|
949
|
-
|
|
950
|
-
if ( canInsertElement ) {
|
|
951
|
-
const viewPosition = conversionApi.mapper.toViewPosition( modelPosition );
|
|
950
|
+
const elementAfter = modelPosition.nodeAfter && modelPosition.nodeAfter.is( 'element' ) ? modelPosition.nodeAfter : null;
|
|
951
|
+
const elementBefore = modelPosition.nodeBefore && modelPosition.nodeBefore.is( 'element' ) ? modelPosition.nodeBefore : null;
|
|
952
952
|
|
|
953
|
-
|
|
954
|
-
} else {
|
|
953
|
+
if ( elementAfter || elementBefore ) {
|
|
955
954
|
let modelElement;
|
|
956
955
|
let isBefore;
|
|
957
956
|
|
|
958
957
|
// If possible, we want to add `data-group-start-before` and `data-group-end-after` attributes.
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
if ( isStart && modelPosition.nodeAfter || !isStart && !modelPosition.nodeBefore ) {
|
|
964
|
-
modelElement = modelPosition.nodeAfter;
|
|
958
|
+
if ( isStart && elementAfter || !isStart && !elementBefore ) {
|
|
959
|
+
// [<elementAfter>...</elementAfter> -> <elementAfter data-group-start-before="...">...</elementAfter>
|
|
960
|
+
// <parent>]<elementAfter> -> <parent><elementAfter data-group-end-before="...">
|
|
961
|
+
modelElement = elementAfter;
|
|
965
962
|
isBefore = true;
|
|
966
963
|
} else {
|
|
967
|
-
|
|
964
|
+
// <elementBefore>...</elementBefore>] -> <elementBefore data-group-end-after="...">...</elementBefore>
|
|
965
|
+
// </elementBefore>[</parent> -> </elementBefore data-group-start-after="..."></parent>
|
|
966
|
+
modelElement = elementBefore;
|
|
968
967
|
isBefore = false;
|
|
969
968
|
}
|
|
970
969
|
|
|
971
970
|
const viewElement = conversionApi.mapper.toViewElement( modelElement );
|
|
972
971
|
|
|
973
|
-
|
|
972
|
+
// In rare circumstances, the model element may be not mapped to any view element and that would cause an error.
|
|
973
|
+
// One of those situations is a soft break inside code block.
|
|
974
|
+
if ( viewElement ) {
|
|
975
|
+
insertMarkerAsAttribute( viewElement, isStart, isBefore, conversionApi, data, viewMarkerData );
|
|
976
|
+
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
974
979
|
}
|
|
980
|
+
|
|
981
|
+
const viewPosition = conversionApi.mapper.toViewPosition( modelPosition );
|
|
982
|
+
|
|
983
|
+
insertMarkerAsElement( viewPosition, isStart, conversionApi, data, viewMarkerData );
|
|
975
984
|
}
|
|
976
985
|
|
|
977
986
|
// Helper function for `insertMarkerData()` that marks a marker boundary in the view as an attribute on a view element.
|
package/src/conversion/mapper.js
CHANGED
|
@@ -35,6 +35,7 @@ import mix from '@ckeditor/ckeditor5-utils/src/mix';
|
|
|
35
35
|
* and {@link module:engine/conversion/mapper~Mapper#toModelPosition toModelPosition} methods. `Mapper` adds it's own default callbacks
|
|
36
36
|
* with `'lowest'` priority. To override default `Mapper` mapping, add custom callback with higher priority and
|
|
37
37
|
* stop the event.
|
|
38
|
+
* @mixes module:utils/emittermixin~EmitterMixin
|
|
38
39
|
*/
|
|
39
40
|
export default class Mapper {
|
|
40
41
|
/**
|
|
@@ -38,12 +38,12 @@ import TextProxy from '../model/textproxy';
|
|
|
38
38
|
*
|
|
39
39
|
* Consuming multiple values in a single callback:
|
|
40
40
|
*
|
|
41
|
-
* // Converter for custom `
|
|
41
|
+
* // Converter for custom `imageBlock` element that might have a `caption` element inside which changes
|
|
42
42
|
* // how the image is displayed in the view:
|
|
43
43
|
* //
|
|
44
44
|
* // Model:
|
|
45
45
|
* //
|
|
46
|
-
* // [
|
|
46
|
+
* // [imageBlock]
|
|
47
47
|
* // └─ [caption]
|
|
48
48
|
* // └─ foo
|
|
49
49
|
* //
|
|
@@ -53,8 +53,8 @@ import TextProxy from '../model/textproxy';
|
|
|
53
53
|
* // ├─ <img />
|
|
54
54
|
* // └─ <caption>
|
|
55
55
|
* // └─ foo
|
|
56
|
-
* modelConversionDispatcher.on( 'insert:
|
|
57
|
-
* // First, consume the `
|
|
56
|
+
* modelConversionDispatcher.on( 'insert:imageBlock', ( evt, data, conversionApi ) => {
|
|
57
|
+
* // First, consume the `imageBlock` element.
|
|
58
58
|
* conversionApi.consumable.consume( data.item, 'insert' );
|
|
59
59
|
*
|
|
60
60
|
* // Just create normal image element for the view.
|
|
@@ -63,7 +63,7 @@ import TextProxy from '../model/textproxy';
|
|
|
63
63
|
* const insertPosition = conversionApi.mapper.toViewPosition( data.range.start );
|
|
64
64
|
* const viewWriter = conversionApi.writer;
|
|
65
65
|
*
|
|
66
|
-
* // Check if the `
|
|
66
|
+
* // Check if the `imageBlock` element has children.
|
|
67
67
|
* if ( data.item.childCount > 0 ) {
|
|
68
68
|
* const modelCaption = data.item.getChild( 0 );
|
|
69
69
|
*
|
|
@@ -320,5 +320,10 @@ export default class ModelConsumable {
|
|
|
320
320
|
function _normalizeConsumableType( type ) {
|
|
321
321
|
const parts = type.split( ':' );
|
|
322
322
|
|
|
323
|
+
// Markers are identified by the whole name (otherwise we would consume the whole markers group).
|
|
324
|
+
if ( parts[ 0 ] == 'addMarker' || parts[ 0 ] == 'removeMarker' ) {
|
|
325
|
+
return type;
|
|
326
|
+
}
|
|
327
|
+
|
|
323
328
|
return parts.length > 1 ? parts[ 0 ] + ':' + parts[ 1 ] : parts[ 0 ];
|
|
324
329
|
}
|
|
@@ -635,11 +635,11 @@ function createContextTree( contextDefinition, writer ) {
|
|
|
635
635
|
*
|
|
636
636
|
* Otherwise, ancestors are split.
|
|
637
637
|
*
|
|
638
|
-
* For instance, if `<
|
|
638
|
+
* For instance, if `<imageBlock>` is not allowed in `<paragraph>` but is allowed in `$root`:
|
|
639
639
|
*
|
|
640
640
|
* <paragraph>foo[]bar</paragraph>
|
|
641
641
|
*
|
|
642
|
-
* -> safe insert for `<
|
|
642
|
+
* -> safe insert for `<imageBlock>` will split ->
|
|
643
643
|
*
|
|
644
644
|
* <paragraph>foo</paragraph>[]<paragraph>bar</paragraph>
|
|
645
645
|
*
|
|
@@ -696,11 +696,11 @@ function createContextTree( contextDefinition, writer ) {
|
|
|
696
696
|
*
|
|
697
697
|
* Otherwise, ancestors are split and an object with a position and the copy of the split element is returned.
|
|
698
698
|
*
|
|
699
|
-
* For instance, if `<
|
|
699
|
+
* For instance, if `<imageBlock>` is not allowed in `<paragraph>` but is allowed in `$root`:
|
|
700
700
|
*
|
|
701
701
|
* <paragraph>foo[]bar</paragraph>
|
|
702
702
|
*
|
|
703
|
-
* -> split for `<
|
|
703
|
+
* -> split for `<imageBlock>` ->
|
|
704
704
|
*
|
|
705
705
|
* <paragraph>foo</paragraph>[]<paragraph>bar</paragraph>
|
|
706
706
|
*
|
|
@@ -722,8 +722,8 @@ function createContextTree( contextDefinition, writer ) {
|
|
|
722
722
|
* Returns all the split parts of the given `element` that were created during upcasting through using {@link #splitToAllowedParent}.
|
|
723
723
|
* It enables you to easily track these elements and continue processing them after they are split during the conversion of their children.
|
|
724
724
|
*
|
|
725
|
-
* <paragraph>Foo<
|
|
726
|
-
* <paragraph>Foo</paragraph><
|
|
725
|
+
* <paragraph>Foo<imageBlock />bar<imageBlock />baz</paragraph> ->
|
|
726
|
+
* <paragraph>Foo</paragraph><imageBlock /><paragraph>bar</paragraph><imageBlock /><paragraph>baz</paragraph>
|
|
727
727
|
*
|
|
728
728
|
* For a reference to any of above paragraphs, the function will return all three paragraphs (the original element included),
|
|
729
729
|
* sorted in the order of their creation (the original element is the first one).
|