@ckeditor/ckeditor5-engine 32.0.0 → 33.0.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/package.json +22 -22
- package/src/controller/datacontroller.js +58 -66
- package/src/controller/editingcontroller.js +82 -5
- package/src/conversion/conversion.js +14 -13
- package/src/conversion/downcastdispatcher.js +297 -366
- package/src/conversion/downcasthelpers.js +770 -62
- package/src/conversion/mapper.js +104 -59
- package/src/conversion/modelconsumable.js +84 -34
- package/src/conversion/upcastdispatcher.js +2 -5
- package/src/conversion/upcasthelpers.js +3 -1
- package/src/dataprocessor/htmldataprocessor.js +1 -1
- package/src/dev-utils/model.js +13 -11
- package/src/index.js +1 -0
- package/src/model/batch.js +12 -12
- package/src/model/differ.js +86 -58
- package/src/model/document.js +12 -3
- package/src/model/markercollection.js +28 -4
- package/src/model/model.js +2 -1
- package/src/model/utils/modifyselection.js +14 -7
- package/src/model/writer.js +16 -26
- package/src/view/document.js +2 -1
- package/src/view/domconverter.js +31 -10
- package/src/view/downcastwriter.js +88 -3
- package/theme/placeholder.css +9 -0
|
@@ -9,14 +9,13 @@
|
|
|
9
9
|
|
|
10
10
|
import Consumable from './modelconsumable';
|
|
11
11
|
import Range from '../model/range';
|
|
12
|
-
import Position, { getNodeAfterPosition, getTextNodeAtPosition } from '../model/position';
|
|
13
12
|
|
|
14
13
|
import EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';
|
|
15
14
|
import mix from '@ckeditor/ckeditor5-utils/src/mix';
|
|
16
15
|
|
|
17
16
|
/**
|
|
18
17
|
* The downcast dispatcher is a central point of downcasting (conversion from the model to the view), which is a process of reacting
|
|
19
|
-
* to changes in the model and firing a set of events.
|
|
18
|
+
* to changes in the model and firing a set of events. The callbacks listening to these events are called converters. The
|
|
20
19
|
* converters' role is to convert the model changes to changes in view (for example, adding view nodes or
|
|
21
20
|
* changing attributes on view elements).
|
|
22
21
|
*
|
|
@@ -25,7 +24,7 @@ import mix from '@ckeditor/ckeditor5-utils/src/mix';
|
|
|
25
24
|
* for example: "a node has been inserted" or "an attribute has changed". This is in contrary to upcasting (a view-to-model conversion)
|
|
26
25
|
* where you convert the view state (view nodes) to a model tree.
|
|
27
26
|
*
|
|
28
|
-
* The events are prepared basing on a diff created by {@link module:engine/model/differ~Differ Differ}, which buffers them
|
|
27
|
+
* The events are prepared basing on a diff created by the {@link module:engine/model/differ~Differ Differ}, which buffers them
|
|
29
28
|
* and then passes to the downcast dispatcher as a diff between the old model state and the new model state.
|
|
30
29
|
*
|
|
31
30
|
* Note that because the changes are converted, there is a need to have a mapping between the model structure and the view structure.
|
|
@@ -42,27 +41,28 @@ import mix from '@ckeditor/ckeditor5-utils/src/mix';
|
|
|
42
41
|
*
|
|
43
42
|
* For {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert `insert`}
|
|
44
43
|
* and {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute `attribute`},
|
|
45
|
-
* downcast dispatcher generates {@link module:engine/conversion/modelconsumable~ModelConsumable consumables}.
|
|
44
|
+
* the downcast dispatcher generates {@link module:engine/conversion/modelconsumable~ModelConsumable consumables}.
|
|
46
45
|
* These are used to have control over which changes have already been consumed. It is useful when some converters
|
|
47
46
|
* overwrite others or convert multiple changes (for example, it converts an insertion of an element and also converts that
|
|
48
47
|
* element's attributes during the insertion).
|
|
49
48
|
*
|
|
50
49
|
* Additionally, downcast dispatcher fires events for {@link module:engine/model/markercollection~Marker marker} changes:
|
|
51
50
|
*
|
|
52
|
-
* * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker} – If a marker was added.
|
|
53
|
-
* * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:removeMarker} – If a marker was
|
|
51
|
+
* * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker `addMarker`} – If a marker was added.
|
|
52
|
+
* * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:removeMarker `removeMarker`} – If a marker was
|
|
53
|
+
* removed.
|
|
54
54
|
*
|
|
55
55
|
* Note that changing a marker is done through removing the marker from the old range and adding it to the new range,
|
|
56
|
-
* so both events are fired.
|
|
56
|
+
* so both of these events are fired.
|
|
57
57
|
*
|
|
58
|
-
* Finally, downcast dispatcher also handles firing events for the {@link module:engine/model/selection model selection}
|
|
58
|
+
* Finally, a downcast dispatcher also handles firing events for the {@link module:engine/model/selection model selection}
|
|
59
59
|
* conversion:
|
|
60
60
|
*
|
|
61
|
-
* * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:selection}
|
|
61
|
+
* * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:selection `selection`}
|
|
62
62
|
* – Converts the selection from the model to the view.
|
|
63
|
-
* * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute}
|
|
63
|
+
* * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute `attribute`}
|
|
64
64
|
* – Fired for every selection attribute.
|
|
65
|
-
* * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker}
|
|
65
|
+
* * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker `addMarker`}
|
|
66
66
|
* – Fired for every marker that contains a selection.
|
|
67
67
|
*
|
|
68
68
|
* Unlike the model tree and the markers, the events for selection are not fired for changes but for a selection state.
|
|
@@ -70,18 +70,15 @@ import mix from '@ckeditor/ckeditor5-utils/src/mix';
|
|
|
70
70
|
* When providing custom listeners for a downcast dispatcher, remember to check whether a given change has not been
|
|
71
71
|
* {@link module:engine/conversion/modelconsumable~ModelConsumable#consume consumed} yet.
|
|
72
72
|
*
|
|
73
|
-
* When providing custom listeners for downcast dispatcher, keep in mind that
|
|
74
|
-
*
|
|
75
|
-
* converted the change should also stop the event (for efficiency purposes).
|
|
73
|
+
* When providing custom listeners for a downcast dispatcher, keep in mind that you **should not** stop the event. If you stop it,
|
|
74
|
+
* then the default converter at the `lowest` priority will not trigger the conversion of this node's attributes and child nodes.
|
|
76
75
|
*
|
|
77
|
-
* When providing custom listeners for downcast dispatcher, remember to use the provided
|
|
76
|
+
* When providing custom listeners for a downcast dispatcher, remember to use the provided
|
|
78
77
|
* {@link module:engine/view/downcastwriter~DowncastWriter view downcast writer} to apply changes to the view document.
|
|
79
78
|
*
|
|
80
|
-
* You can read more about conversion in the following
|
|
79
|
+
* You can read more about conversion in the following guide:
|
|
81
80
|
*
|
|
82
|
-
* * {@glink framework/guides/deep-dive/conversion/
|
|
83
|
-
* * {@glink framework/guides/deep-dive/conversion/conversion-extending-output Extending the editor output }
|
|
84
|
-
* * {@glink framework/guides/deep-dive/conversion/custom-element-conversion Custom element conversion}
|
|
81
|
+
* * {@glink framework/guides/deep-dive/conversion/downcast Downcast conversion}
|
|
85
82
|
*
|
|
86
83
|
* An example of a custom converter for the downcast dispatcher:
|
|
87
84
|
*
|
|
@@ -103,9 +100,6 @@ import mix from '@ckeditor/ckeditor5-utils/src/mix';
|
|
|
103
100
|
*
|
|
104
101
|
* // Add the newly created view element to the view.
|
|
105
102
|
* conversionApi.writer.insert( viewPosition, viewElement );
|
|
106
|
-
*
|
|
107
|
-
* // Remember to stop the event propagation.
|
|
108
|
-
* evt.stop();
|
|
109
103
|
* } );
|
|
110
104
|
*/
|
|
111
105
|
export default class DowncastDispatcher {
|
|
@@ -118,206 +112,102 @@ export default class DowncastDispatcher {
|
|
|
118
112
|
*/
|
|
119
113
|
constructor( conversionApi ) {
|
|
120
114
|
/**
|
|
121
|
-
*
|
|
115
|
+
* A template for an interface passed by the dispatcher to the event callbacks.
|
|
122
116
|
*
|
|
117
|
+
* @protected
|
|
123
118
|
* @member {module:engine/conversion/downcastdispatcher~DowncastConversionApi}
|
|
124
119
|
*/
|
|
125
|
-
this.
|
|
120
|
+
this._conversionApi = { dispatcher: this, ...conversionApi };
|
|
126
121
|
|
|
127
122
|
/**
|
|
128
|
-
*
|
|
123
|
+
* A map of already fired events for a given `ModelConsumable`.
|
|
129
124
|
*
|
|
130
|
-
* @type {Map<String, String>}
|
|
131
125
|
* @private
|
|
126
|
+
* @member {WeakMap.<module:engine/conversion/downcastdispatcher~DowncastConversionApi,Map>}
|
|
132
127
|
*/
|
|
133
|
-
this.
|
|
128
|
+
this._firedEventsMap = new WeakMap();
|
|
134
129
|
}
|
|
135
130
|
|
|
136
131
|
/**
|
|
137
|
-
*
|
|
132
|
+
* Converts changes buffered in the given {@link module:engine/model/differ~Differ model differ}
|
|
133
|
+
* and fires conversion events based on it.
|
|
138
134
|
*
|
|
135
|
+
* @fires insert
|
|
136
|
+
* @fires remove
|
|
137
|
+
* @fires attribute
|
|
138
|
+
* @fires addMarker
|
|
139
|
+
* @fires removeMarker
|
|
140
|
+
* @fires reduceChanges
|
|
139
141
|
* @param {module:engine/model/differ~Differ} differ The differ object with buffered changes.
|
|
140
|
-
* @param {module:engine/model/markercollection~MarkerCollection} markers Markers
|
|
142
|
+
* @param {module:engine/model/markercollection~MarkerCollection} markers Markers related to the model fragment to convert.
|
|
141
143
|
* @param {module:engine/view/downcastwriter~DowncastWriter} writer The view writer that should be used to modify the view document.
|
|
142
144
|
*/
|
|
143
145
|
convertChanges( differ, markers, writer ) {
|
|
146
|
+
const conversionApi = this._createConversionApi( writer, differ.getRefreshedItems() );
|
|
147
|
+
|
|
144
148
|
// Before the view is updated, remove markers which have changed.
|
|
145
149
|
for ( const change of differ.getMarkersToRemove() ) {
|
|
146
|
-
this.
|
|
150
|
+
this._convertMarkerRemove( change.name, change.range, conversionApi );
|
|
147
151
|
}
|
|
148
152
|
|
|
149
|
-
|
|
153
|
+
// Let features modify the change list (for example to allow reconversion).
|
|
154
|
+
const changes = this._reduceChanges( differ.getChanges() );
|
|
150
155
|
|
|
151
156
|
// Convert changes that happened on model tree.
|
|
152
157
|
for ( const entry of changes ) {
|
|
153
158
|
if ( entry.type === 'insert' ) {
|
|
154
|
-
this.
|
|
159
|
+
this._convertInsert( Range._createFromPositionAndShift( entry.position, entry.length ), conversionApi );
|
|
160
|
+
} else if ( entry.type === 'reinsert' ) {
|
|
161
|
+
this._convertReinsert( Range._createFromPositionAndShift( entry.position, entry.length ), conversionApi );
|
|
155
162
|
} else if ( entry.type === 'remove' ) {
|
|
156
|
-
this.
|
|
157
|
-
} else if ( entry.type === 'reconvert' ) {
|
|
158
|
-
this.reconvertElement( entry.element, writer );
|
|
163
|
+
this._convertRemove( entry.position, entry.length, entry.name, conversionApi );
|
|
159
164
|
} else {
|
|
160
165
|
// Defaults to 'attribute' change.
|
|
161
|
-
this.
|
|
166
|
+
this._convertAttribute( entry.range, entry.attributeKey, entry.attributeOldValue, entry.attributeNewValue, conversionApi );
|
|
162
167
|
}
|
|
163
168
|
}
|
|
164
169
|
|
|
165
|
-
for ( const markerName of
|
|
170
|
+
for ( const markerName of conversionApi.mapper.flushUnboundMarkerNames() ) {
|
|
166
171
|
const markerRange = markers.get( markerName ).getRange();
|
|
167
172
|
|
|
168
|
-
this.
|
|
169
|
-
this.
|
|
173
|
+
this._convertMarkerRemove( markerName, markerRange, conversionApi );
|
|
174
|
+
this._convertMarkerAdd( markerName, markerRange, conversionApi );
|
|
170
175
|
}
|
|
171
176
|
|
|
172
177
|
// After the view is updated, convert markers which have changed.
|
|
173
178
|
for ( const change of differ.getMarkersToAdd() ) {
|
|
174
|
-
this.
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Starts a conversion of a range insertion.
|
|
180
|
-
*
|
|
181
|
-
* For each node in the range, {@link #event:insert `insert` event is fired}. For each attribute on each node,
|
|
182
|
-
* {@link #event:attribute `attribute` event is fired}.
|
|
183
|
-
*
|
|
184
|
-
* @fires insert
|
|
185
|
-
* @fires attribute
|
|
186
|
-
* @param {module:engine/model/range~Range} range The inserted range.
|
|
187
|
-
* @param {module:engine/view/downcastwriter~DowncastWriter} writer The view writer that should be used to modify the view document.
|
|
188
|
-
*/
|
|
189
|
-
convertInsert( range, writer ) {
|
|
190
|
-
this.conversionApi.writer = writer;
|
|
191
|
-
|
|
192
|
-
// Create a list of things that can be consumed, consisting of nodes and their attributes.
|
|
193
|
-
this.conversionApi.consumable = this._createInsertConsumable( range );
|
|
194
|
-
|
|
195
|
-
// Fire a separate insert event for each node and text fragment contained in the range.
|
|
196
|
-
for ( const data of Array.from( range ).map( walkerValueToEventData ) ) {
|
|
197
|
-
this._convertInsertWithAttributes( data );
|
|
179
|
+
this._convertMarkerAdd( change.name, change.range, conversionApi );
|
|
198
180
|
}
|
|
199
181
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Fires conversion of a single node removal. Fires {@link #event:remove remove event} with provided data.
|
|
205
|
-
*
|
|
206
|
-
* @param {module:engine/model/position~Position} position Position from which node was removed.
|
|
207
|
-
* @param {Number} length Offset size of removed node.
|
|
208
|
-
* @param {String} name Name of removed node.
|
|
209
|
-
* @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify view document.
|
|
210
|
-
*/
|
|
211
|
-
convertRemove( position, length, name, writer ) {
|
|
212
|
-
this.conversionApi.writer = writer;
|
|
213
|
-
|
|
214
|
-
this.fire( 'remove:' + name, { position, length }, this.conversionApi );
|
|
182
|
+
// Remove mappings for all removed view elements.
|
|
183
|
+
conversionApi.mapper.flushDeferredBindings();
|
|
215
184
|
|
|
216
|
-
|
|
185
|
+
// Verify if all insert consumables were consumed.
|
|
186
|
+
conversionApi.consumable.verifyAllConsumed( 'insert' );
|
|
217
187
|
}
|
|
218
188
|
|
|
219
189
|
/**
|
|
220
|
-
* Starts a conversion of
|
|
221
|
-
*
|
|
222
|
-
* For each node in the given `range`, {@link #event:attribute attribute event} is fired with the passed data.
|
|
223
|
-
*
|
|
224
|
-
* @fires attribute
|
|
225
|
-
* @param {module:engine/model/range~Range} range Changed range.
|
|
226
|
-
* @param {String} key Key of the attribute that has changed.
|
|
227
|
-
* @param {*} oldValue Attribute value before the change or `null` if the attribute has not been set before.
|
|
228
|
-
* @param {*} newValue New attribute value or `null` if the attribute has been removed.
|
|
229
|
-
* @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify view document.
|
|
230
|
-
*/
|
|
231
|
-
convertAttribute( range, key, oldValue, newValue, writer ) {
|
|
232
|
-
this.conversionApi.writer = writer;
|
|
233
|
-
|
|
234
|
-
// Create a list with attributes to consume.
|
|
235
|
-
this.conversionApi.consumable = this._createConsumableForRange( range, `attribute:${ key }` );
|
|
236
|
-
|
|
237
|
-
// Create a separate attribute event for each node in the range.
|
|
238
|
-
for ( const value of range ) {
|
|
239
|
-
const item = value.item;
|
|
240
|
-
const itemRange = Range._createFromPositionAndShift( value.previousPosition, value.length );
|
|
241
|
-
const data = {
|
|
242
|
-
item,
|
|
243
|
-
range: itemRange,
|
|
244
|
-
attributeKey: key,
|
|
245
|
-
attributeOldValue: oldValue,
|
|
246
|
-
attributeNewValue: newValue
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
this._testAndFire( `attribute:${ key }`, data );
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
this._clearConversionApi();
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Starts the reconversion of an element. It will:
|
|
257
|
-
*
|
|
258
|
-
* * Fire an {@link #event:insert `insert` event} for the element to reconvert.
|
|
259
|
-
* * Fire an {@link #event:attribute `attribute` event} for element attributes.
|
|
260
|
-
*
|
|
261
|
-
* This will not reconvert children of the element if they have existing (already converted) views. For newly inserted child elements
|
|
262
|
-
* it will behave the same as {@link #convertInsert}.
|
|
263
|
-
*
|
|
264
|
-
* Element reconversion is defined by the `triggerBy` configuration for the
|
|
265
|
-
* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`} conversion helper.
|
|
190
|
+
* Starts a conversion of a model range and the provided markers.
|
|
266
191
|
*
|
|
267
192
|
* @fires insert
|
|
268
193
|
* @fires attribute
|
|
269
|
-
* @
|
|
194
|
+
* @fires addMarker
|
|
195
|
+
* @param {module:engine/model/range~Range} range The inserted range.
|
|
196
|
+
* @param {Map<String,module:engine/model/range~Range>} markers The map of markers that should be down-casted.
|
|
270
197
|
* @param {module:engine/view/downcastwriter~DowncastWriter} writer The view writer that should be used to modify the view document.
|
|
198
|
+
* @param {Object} [options] Optional options object passed to `convertionApi.options`.
|
|
271
199
|
*/
|
|
272
|
-
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
this.conversionApi.writer = writer;
|
|
276
|
-
|
|
277
|
-
// Create a list of things that can be consumed, consisting of nodes and their attributes.
|
|
278
|
-
this.conversionApi.consumable = this._createInsertConsumable( elementRange );
|
|
279
|
-
|
|
280
|
-
const mapper = this.conversionApi.mapper;
|
|
281
|
-
const currentView = mapper.toViewElement( element );
|
|
282
|
-
|
|
283
|
-
// Remove the old view but do not remove mapper mappings - those will be used to revive existing elements.
|
|
284
|
-
writer.remove( currentView );
|
|
285
|
-
|
|
286
|
-
// Convert the element - without converting children.
|
|
287
|
-
this._convertInsertWithAttributes( {
|
|
288
|
-
item: element,
|
|
289
|
-
range: elementRange
|
|
290
|
-
} );
|
|
291
|
-
|
|
292
|
-
const convertedViewElement = mapper.toViewElement( element );
|
|
200
|
+
convert( range, markers, writer, options = {} ) {
|
|
201
|
+
const conversionApi = this._createConversionApi( writer, undefined, options );
|
|
293
202
|
|
|
294
|
-
|
|
295
|
-
for ( const value of Range._createIn( element ) ) {
|
|
296
|
-
const { item } = value;
|
|
203
|
+
this._convertInsert( range, conversionApi );
|
|
297
204
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
// ...either bring back previously converted view...
|
|
301
|
-
if ( view ) {
|
|
302
|
-
// Do not move views that are already in converted element - those might be created by the main element converter in case
|
|
303
|
-
// when main element converts also its direct children.
|
|
304
|
-
if ( view.root !== convertedViewElement.root ) {
|
|
305
|
-
writer.move(
|
|
306
|
-
writer.createRangeOn( view ),
|
|
307
|
-
mapper.toViewPosition( Position._createBefore( item ) )
|
|
308
|
-
);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
// ... or by converting newly inserted elements.
|
|
312
|
-
else {
|
|
313
|
-
this._convertInsertWithAttributes( walkerValueToEventData( value ) );
|
|
314
|
-
}
|
|
205
|
+
for ( const [ name, range ] of markers ) {
|
|
206
|
+
this._convertMarkerAdd( name, range, conversionApi );
|
|
315
207
|
}
|
|
316
208
|
|
|
317
|
-
//
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
this._clearConversionApi();
|
|
209
|
+
// Verify if all insert consumables were consumed.
|
|
210
|
+
conversionApi.consumable.verifyAllConsumed( 'insert' );
|
|
321
211
|
}
|
|
322
212
|
|
|
323
213
|
/**
|
|
@@ -335,21 +225,20 @@ export default class DowncastDispatcher {
|
|
|
335
225
|
convertSelection( selection, markers, writer ) {
|
|
336
226
|
const markersAtSelection = Array.from( markers.getMarkersAtPosition( selection.getFirstPosition() ) );
|
|
337
227
|
|
|
338
|
-
|
|
339
|
-
this.conversionApi.consumable = this._createSelectionConsumable( selection, markersAtSelection );
|
|
228
|
+
const conversionApi = this._createConversionApi( writer );
|
|
340
229
|
|
|
341
|
-
this.
|
|
230
|
+
this._addConsumablesForSelection( conversionApi.consumable, selection, markersAtSelection );
|
|
342
231
|
|
|
343
|
-
|
|
344
|
-
this._clearConversionApi();
|
|
232
|
+
this.fire( 'selection', { selection }, conversionApi );
|
|
345
233
|
|
|
234
|
+
if ( !selection.isCollapsed ) {
|
|
346
235
|
return;
|
|
347
236
|
}
|
|
348
237
|
|
|
349
238
|
for ( const marker of markersAtSelection ) {
|
|
350
239
|
const markerRange = marker.getRange();
|
|
351
240
|
|
|
352
|
-
if ( !shouldMarkerChangeBeConverted( selection.getFirstPosition(), marker,
|
|
241
|
+
if ( !shouldMarkerChangeBeConverted( selection.getFirstPosition(), marker, conversionApi.mapper ) ) {
|
|
353
242
|
continue;
|
|
354
243
|
}
|
|
355
244
|
|
|
@@ -359,8 +248,8 @@ export default class DowncastDispatcher {
|
|
|
359
248
|
markerRange
|
|
360
249
|
};
|
|
361
250
|
|
|
362
|
-
if (
|
|
363
|
-
this.fire( 'addMarker:' + marker.name, data,
|
|
251
|
+
if ( conversionApi.consumable.test( selection, 'addMarker:' + marker.name ) ) {
|
|
252
|
+
this.fire( 'addMarker:' + marker.name, data, conversionApi );
|
|
364
253
|
}
|
|
365
254
|
}
|
|
366
255
|
|
|
@@ -374,130 +263,218 @@ export default class DowncastDispatcher {
|
|
|
374
263
|
};
|
|
375
264
|
|
|
376
265
|
// Do not fire event if the attribute has been consumed.
|
|
377
|
-
if (
|
|
378
|
-
this.fire( 'attribute:' + data.attributeKey + ':$text', data,
|
|
266
|
+
if ( conversionApi.consumable.test( selection, 'attribute:' + data.attributeKey ) ) {
|
|
267
|
+
this.fire( 'attribute:' + data.attributeKey + ':$text', data, conversionApi );
|
|
379
268
|
}
|
|
380
269
|
}
|
|
270
|
+
}
|
|
381
271
|
|
|
382
|
-
|
|
272
|
+
/**
|
|
273
|
+
* Fires insertion conversion of a range of nodes.
|
|
274
|
+
*
|
|
275
|
+
* For each node in the range, {@link #event:insert `insert` event is fired}. For each attribute on each node,
|
|
276
|
+
* {@link #event:attribute `attribute` event is fired}.
|
|
277
|
+
*
|
|
278
|
+
* @protected
|
|
279
|
+
* @fires insert
|
|
280
|
+
* @fires attribute
|
|
281
|
+
* @param {module:engine/model/range~Range} range The inserted range.
|
|
282
|
+
* @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi The conversion API object.
|
|
283
|
+
* @param {Object} [options]
|
|
284
|
+
* @param {Boolean} [options.doNotAddConsumables=false] Whether the ModelConsumable should not get populated
|
|
285
|
+
* for items in the provided range.
|
|
286
|
+
*/
|
|
287
|
+
_convertInsert( range, conversionApi, options = {} ) {
|
|
288
|
+
if ( !options.doNotAddConsumables ) {
|
|
289
|
+
// Collect a list of things that can be consumed, consisting of nodes and their attributes.
|
|
290
|
+
this._addConsumablesForInsert( conversionApi.consumable, Array.from( range ) );
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Fire a separate insert event for each node and text fragment contained in the range.
|
|
294
|
+
for ( const data of Array.from( range.getWalker( { shallow: true } ) ).map( walkerValueToEventData ) ) {
|
|
295
|
+
this._testAndFire( 'insert', data, conversionApi );
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Fires conversion of a single node removal. Fires {@link #event:remove remove event} with provided data.
|
|
301
|
+
*
|
|
302
|
+
* @protected
|
|
303
|
+
* @param {module:engine/model/position~Position} position Position from which node was removed.
|
|
304
|
+
* @param {Number} length Offset size of removed node.
|
|
305
|
+
* @param {String} name Name of removed node.
|
|
306
|
+
* @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi The conversion API object.
|
|
307
|
+
*/
|
|
308
|
+
_convertRemove( position, length, name, conversionApi ) {
|
|
309
|
+
this.fire( 'remove:' + name, { position, length }, conversionApi );
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Starts a conversion of an attribute change on a given `range`.
|
|
314
|
+
*
|
|
315
|
+
* For each node in the given `range`, {@link #event:attribute attribute event} is fired with the passed data.
|
|
316
|
+
*
|
|
317
|
+
* @protected
|
|
318
|
+
* @fires attribute
|
|
319
|
+
* @param {module:engine/model/range~Range} range Changed range.
|
|
320
|
+
* @param {String} key Key of the attribute that has changed.
|
|
321
|
+
* @param {*} oldValue Attribute value before the change or `null` if the attribute has not been set before.
|
|
322
|
+
* @param {*} newValue New attribute value or `null` if the attribute has been removed.
|
|
323
|
+
* @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi The conversion API object.
|
|
324
|
+
*/
|
|
325
|
+
_convertAttribute( range, key, oldValue, newValue, conversionApi ) {
|
|
326
|
+
// Create a list with attributes to consume.
|
|
327
|
+
this._addConsumablesForRange( conversionApi.consumable, range, `attribute:${ key }` );
|
|
328
|
+
|
|
329
|
+
// Create a separate attribute event for each node in the range.
|
|
330
|
+
for ( const value of range ) {
|
|
331
|
+
const data = {
|
|
332
|
+
item: value.item,
|
|
333
|
+
range: Range._createFromPositionAndShift( value.previousPosition, value.length ),
|
|
334
|
+
attributeKey: key,
|
|
335
|
+
attributeOldValue: oldValue,
|
|
336
|
+
attributeNewValue: newValue
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
this._testAndFire( `attribute:${ key }`, data, conversionApi );
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Fires re-insertion conversion (with a `reconversion` flag passed to `insert` events)
|
|
345
|
+
* of a range of elements (only elements on the range depth, without children).
|
|
346
|
+
*
|
|
347
|
+
* For each node in the range on its depth (without children), {@link #event:insert `insert` event} is fired.
|
|
348
|
+
* For each attribute on each node, {@link #event:attribute `attribute` event} is fired.
|
|
349
|
+
*
|
|
350
|
+
* @protected
|
|
351
|
+
* @fires insert
|
|
352
|
+
* @fires attribute
|
|
353
|
+
* @param {module:engine/model/range~Range} range The range to reinsert.
|
|
354
|
+
* @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi The conversion API object.
|
|
355
|
+
*/
|
|
356
|
+
_convertReinsert( range, conversionApi ) {
|
|
357
|
+
// Convert the elements - without converting children.
|
|
358
|
+
const walkerValues = Array.from( range.getWalker( { shallow: true } ) );
|
|
359
|
+
|
|
360
|
+
// Collect a list of things that can be consumed, consisting of nodes and their attributes.
|
|
361
|
+
this._addConsumablesForInsert( conversionApi.consumable, walkerValues );
|
|
362
|
+
|
|
363
|
+
// Fire a separate insert event for each node and text fragment contained shallowly in the range.
|
|
364
|
+
for ( const data of walkerValues.map( walkerValueToEventData ) ) {
|
|
365
|
+
this._testAndFire( 'insert', { ...data, reconversion: true }, conversionApi );
|
|
366
|
+
}
|
|
383
367
|
}
|
|
384
368
|
|
|
385
369
|
/**
|
|
386
370
|
* Converts the added marker. Fires the {@link #event:addMarker `addMarker`} event for each item
|
|
387
371
|
* in the marker's range. If the range is collapsed, a single event is dispatched. See the event description for more details.
|
|
388
372
|
*
|
|
373
|
+
* @protected
|
|
389
374
|
* @fires addMarker
|
|
390
375
|
* @param {String} markerName Marker name.
|
|
391
376
|
* @param {module:engine/model/range~Range} markerRange The marker range.
|
|
392
|
-
* @param {module:engine/
|
|
377
|
+
* @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi The conversion API object.
|
|
393
378
|
*/
|
|
394
|
-
|
|
379
|
+
_convertMarkerAdd( markerName, markerRange, conversionApi ) {
|
|
395
380
|
// Do not convert if range is in graveyard.
|
|
396
381
|
if ( markerRange.root.rootName == '$graveyard' ) {
|
|
397
382
|
return;
|
|
398
383
|
}
|
|
399
384
|
|
|
400
|
-
this.conversionApi.writer = writer;
|
|
401
|
-
|
|
402
385
|
// In markers' case, event name == consumable name.
|
|
403
386
|
const eventName = 'addMarker:' + markerName;
|
|
404
387
|
|
|
405
388
|
//
|
|
406
389
|
// First, fire an event for the whole marker.
|
|
407
390
|
//
|
|
408
|
-
|
|
409
|
-
consumable.add( markerRange, eventName );
|
|
410
|
-
|
|
411
|
-
this.conversionApi.consumable = consumable;
|
|
391
|
+
conversionApi.consumable.add( markerRange, eventName );
|
|
412
392
|
|
|
413
|
-
this.fire( eventName, { markerName, markerRange },
|
|
393
|
+
this.fire( eventName, { markerName, markerRange }, conversionApi );
|
|
414
394
|
|
|
415
395
|
//
|
|
416
396
|
// Do not fire events for each item inside the range if the range got consumed.
|
|
397
|
+
// Also consume the whole marker consumable if it wasn't consumed.
|
|
417
398
|
//
|
|
418
|
-
if ( !consumable.
|
|
419
|
-
this._clearConversionApi();
|
|
420
|
-
|
|
399
|
+
if ( !conversionApi.consumable.consume( markerRange, eventName ) ) {
|
|
421
400
|
return;
|
|
422
401
|
}
|
|
423
402
|
|
|
424
403
|
//
|
|
425
404
|
// Then, fire an event for each item inside the marker range.
|
|
426
405
|
//
|
|
427
|
-
this.conversionApi.consumable
|
|
406
|
+
this._addConsumablesForRange( conversionApi.consumable, markerRange, eventName );
|
|
428
407
|
|
|
429
408
|
for ( const item of markerRange.getItems() ) {
|
|
430
409
|
// Do not fire event for already consumed items.
|
|
431
|
-
if ( !
|
|
410
|
+
if ( !conversionApi.consumable.test( item, eventName ) ) {
|
|
432
411
|
continue;
|
|
433
412
|
}
|
|
434
413
|
|
|
435
414
|
const data = { item, range: Range._createOn( item ), markerName, markerRange };
|
|
436
415
|
|
|
437
|
-
this.fire( eventName, data,
|
|
416
|
+
this.fire( eventName, data, conversionApi );
|
|
438
417
|
}
|
|
439
|
-
|
|
440
|
-
this._clearConversionApi();
|
|
441
418
|
}
|
|
442
419
|
|
|
443
420
|
/**
|
|
444
421
|
* Fires the conversion of the marker removal. Fires the {@link #event:removeMarker `removeMarker`} event with the provided data.
|
|
445
422
|
*
|
|
423
|
+
* @protected
|
|
446
424
|
* @fires removeMarker
|
|
447
425
|
* @param {String} markerName Marker name.
|
|
448
426
|
* @param {module:engine/model/range~Range} markerRange The marker range.
|
|
449
|
-
* @param {module:engine/
|
|
427
|
+
* @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi The conversion API object.
|
|
450
428
|
*/
|
|
451
|
-
|
|
429
|
+
_convertMarkerRemove( markerName, markerRange, conversionApi ) {
|
|
452
430
|
// Do not convert if range is in graveyard.
|
|
453
431
|
if ( markerRange.root.rootName == '$graveyard' ) {
|
|
454
432
|
return;
|
|
455
433
|
}
|
|
456
434
|
|
|
457
|
-
this.conversionApi
|
|
458
|
-
|
|
459
|
-
this.fire( 'removeMarker:' + markerName, { markerName, markerRange }, this.conversionApi );
|
|
460
|
-
|
|
461
|
-
this._clearConversionApi();
|
|
435
|
+
this.fire( 'removeMarker:' + markerName, { markerName, markerRange }, conversionApi );
|
|
462
436
|
}
|
|
463
437
|
|
|
464
438
|
/**
|
|
465
|
-
*
|
|
466
|
-
*
|
|
467
|
-
* * For "attribute" change event, it should include the main element name, i.e: `'attribute:attributeName:elementName'`.
|
|
468
|
-
* * For child node change events, these should use the child event name as well, i.e:
|
|
469
|
-
* * For adding a node: `'insert:childElementName'`.
|
|
470
|
-
* * For removing a node: `'remove:childElementName'`.
|
|
439
|
+
* Fires the reduction of changes buffered in the {@link module:engine/model/differ~Differ `Differ`}.
|
|
471
440
|
*
|
|
472
|
-
*
|
|
473
|
-
*
|
|
441
|
+
* Features can replace selected {@link module:engine/model/differ~DiffItem `DiffItem`}s with `reinsert` entries to trigger
|
|
442
|
+
* reconversion. The {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToStructure
|
|
443
|
+
* `DowncastHelpers.elementToStructure()`} is using this event to trigger reconversion.
|
|
474
444
|
*
|
|
475
|
-
* @
|
|
476
|
-
* @
|
|
477
|
-
* @param {
|
|
445
|
+
* @private
|
|
446
|
+
* @fires reduceChanges
|
|
447
|
+
* @param {Iterable.<module:engine/model/differ~DiffItem>} changes
|
|
448
|
+
* @returns {Iterable.<module:engine/model/differ~DiffItem>}
|
|
478
449
|
*/
|
|
479
|
-
|
|
480
|
-
|
|
450
|
+
_reduceChanges( changes ) {
|
|
451
|
+
const data = { changes };
|
|
452
|
+
|
|
453
|
+
this.fire( 'reduceChanges', data );
|
|
454
|
+
|
|
455
|
+
return data.changes;
|
|
481
456
|
}
|
|
482
457
|
|
|
483
458
|
/**
|
|
484
|
-
*
|
|
459
|
+
* Populates provided {@link module:engine/conversion/modelconsumable~ModelConsumable} with values to consume from a given range,
|
|
485
460
|
* assuming that the range has just been inserted to the model.
|
|
486
461
|
*
|
|
487
462
|
* @private
|
|
488
|
-
* @param {module:engine/
|
|
463
|
+
* @param {module:engine/conversion/modelconsumable~ModelConsumable} consumable The consumable.
|
|
464
|
+
* @param {Iterable.<module:engine/model/treewalker~TreeWalkerValue>} walkerValues The walker values for the inserted range.
|
|
489
465
|
* @returns {module:engine/conversion/modelconsumable~ModelConsumable} The values to consume.
|
|
490
466
|
*/
|
|
491
|
-
|
|
492
|
-
const
|
|
493
|
-
|
|
494
|
-
for ( const value of range ) {
|
|
467
|
+
_addConsumablesForInsert( consumable, walkerValues ) {
|
|
468
|
+
for ( const value of walkerValues ) {
|
|
495
469
|
const item = value.item;
|
|
496
470
|
|
|
497
|
-
consumable
|
|
471
|
+
// Add consumable if it wasn't there yet.
|
|
472
|
+
if ( consumable.test( item, 'insert' ) === null ) {
|
|
473
|
+
consumable.add( item, 'insert' );
|
|
498
474
|
|
|
499
|
-
|
|
500
|
-
|
|
475
|
+
for ( const key of item.getAttributeKeys() ) {
|
|
476
|
+
consumable.add( item, 'attribute:' + key );
|
|
477
|
+
}
|
|
501
478
|
}
|
|
502
479
|
}
|
|
503
480
|
|
|
@@ -505,16 +482,15 @@ export default class DowncastDispatcher {
|
|
|
505
482
|
}
|
|
506
483
|
|
|
507
484
|
/**
|
|
508
|
-
*
|
|
485
|
+
* Populates provided {@link module:engine/conversion/modelconsumable~ModelConsumable} with values to consume for a given range.
|
|
509
486
|
*
|
|
510
487
|
* @private
|
|
488
|
+
* @param {module:engine/conversion/modelconsumable~ModelConsumable} consumable The consumable.
|
|
511
489
|
* @param {module:engine/model/range~Range} range The affected range.
|
|
512
490
|
* @param {String} type Consumable type.
|
|
513
491
|
* @returns {module:engine/conversion/modelconsumable~ModelConsumable} The values to consume.
|
|
514
492
|
*/
|
|
515
|
-
|
|
516
|
-
const consumable = new Consumable();
|
|
517
|
-
|
|
493
|
+
_addConsumablesForRange( consumable, range, type ) {
|
|
518
494
|
for ( const item of range.getItems() ) {
|
|
519
495
|
consumable.add( item, type );
|
|
520
496
|
}
|
|
@@ -523,16 +499,15 @@ export default class DowncastDispatcher {
|
|
|
523
499
|
}
|
|
524
500
|
|
|
525
501
|
/**
|
|
526
|
-
*
|
|
502
|
+
* Populates provided {@link module:engine/conversion/modelconsumable~ModelConsumable} with selection consumable values.
|
|
527
503
|
*
|
|
528
504
|
* @private
|
|
505
|
+
* @param {module:engine/conversion/modelconsumable~ModelConsumable} consumable The consumable.
|
|
529
506
|
* @param {module:engine/model/selection~Selection} selection The selection to create the consumable from.
|
|
530
507
|
* @param {Iterable.<module:engine/model/markercollection~Marker>} markers Markers that contain the selection.
|
|
531
508
|
* @returns {module:engine/conversion/modelconsumable~ModelConsumable} The values to consume.
|
|
532
509
|
*/
|
|
533
|
-
|
|
534
|
-
const consumable = new Consumable();
|
|
535
|
-
|
|
510
|
+
_addConsumablesForSelection( consumable, selection, markers ) {
|
|
536
511
|
consumable.add( selection, 'selection' );
|
|
537
512
|
|
|
538
513
|
for ( const marker of markers ) {
|
|
@@ -547,152 +522,97 @@ export default class DowncastDispatcher {
|
|
|
547
522
|
}
|
|
548
523
|
|
|
549
524
|
/**
|
|
550
|
-
* Tests
|
|
525
|
+
* Tests whether given event wasn't already fired and if so, fires it.
|
|
551
526
|
*
|
|
552
527
|
* @private
|
|
553
528
|
* @fires insert
|
|
554
529
|
* @fires attribute
|
|
555
530
|
* @param {String} type Event type.
|
|
556
531
|
* @param {Object} data Event data.
|
|
532
|
+
* @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi The conversion API object.
|
|
557
533
|
*/
|
|
558
|
-
_testAndFire( type, data ) {
|
|
559
|
-
|
|
560
|
-
|
|
534
|
+
_testAndFire( type, data, conversionApi ) {
|
|
535
|
+
const eventName = getEventName( type, data );
|
|
536
|
+
const itemKey = data.item.is( '$textProxy' ) ? conversionApi.consumable._getSymbolForTextProxy( data.item ) : data.item;
|
|
537
|
+
|
|
538
|
+
const eventsFiredForConversion = this._firedEventsMap.get( conversionApi );
|
|
539
|
+
const eventsFiredForItem = eventsFiredForConversion.get( itemKey );
|
|
540
|
+
|
|
541
|
+
if ( !eventsFiredForItem ) {
|
|
542
|
+
eventsFiredForConversion.set( itemKey, new Set( [ eventName ] ) );
|
|
543
|
+
} else if ( !eventsFiredForItem.has( eventName ) ) {
|
|
544
|
+
eventsFiredForItem.add( eventName );
|
|
545
|
+
} else {
|
|
561
546
|
return;
|
|
562
547
|
}
|
|
563
548
|
|
|
564
|
-
this.fire(
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
/**
|
|
568
|
-
* Clears the conversion API object.
|
|
569
|
-
*
|
|
570
|
-
* @private
|
|
571
|
-
*/
|
|
572
|
-
_clearConversionApi() {
|
|
573
|
-
delete this.conversionApi.writer;
|
|
574
|
-
delete this.conversionApi.consumable;
|
|
549
|
+
this.fire( eventName, data, conversionApi );
|
|
575
550
|
}
|
|
576
551
|
|
|
577
552
|
/**
|
|
578
|
-
*
|
|
553
|
+
* Fires not already fired events for setting attributes on just inserted item.
|
|
579
554
|
*
|
|
580
555
|
* @private
|
|
581
|
-
* @
|
|
582
|
-
* @
|
|
583
|
-
* @param {Object} data Event data.
|
|
556
|
+
* @param {module:engine/model/item~Item} item The model item to convert attributes for.
|
|
557
|
+
* @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi The conversion API object.
|
|
584
558
|
*/
|
|
585
|
-
|
|
586
|
-
|
|
559
|
+
_testAndFireAddAttributes( item, conversionApi ) {
|
|
560
|
+
const data = {
|
|
561
|
+
item,
|
|
562
|
+
range: Range._createOn( item )
|
|
563
|
+
};
|
|
587
564
|
|
|
588
|
-
// Fire a separate addAttribute event for each attribute that was set on inserted items.
|
|
589
|
-
// This is important because most attributes converters will listen only to add/change/removeAttribute events.
|
|
590
|
-
// If we would not add this part, attributes on inserted nodes would not be converted.
|
|
591
565
|
for ( const key of data.item.getAttributeKeys() ) {
|
|
592
566
|
data.attributeKey = key;
|
|
593
567
|
data.attributeOldValue = null;
|
|
594
568
|
data.attributeNewValue = data.item.getAttribute( key );
|
|
595
569
|
|
|
596
|
-
this._testAndFire( `attribute:${ key }`, data );
|
|
570
|
+
this._testAndFire( `attribute:${ key }`, data, conversionApi );
|
|
597
571
|
}
|
|
598
572
|
}
|
|
599
573
|
|
|
600
574
|
/**
|
|
601
|
-
*
|
|
602
|
-
*
|
|
603
|
-
* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`} conversion helper.
|
|
604
|
-
*
|
|
605
|
-
* This method will remove every mapped insert or remove change with a single "reconvert" change.
|
|
606
|
-
*
|
|
607
|
-
* For instance: Having a `triggerBy()` configuration defined for the `<complex>` element that issues this element reconversion on
|
|
608
|
-
* `foo` and `bar` attributes change, and a set of changes for this element:
|
|
609
|
-
*
|
|
610
|
-
* const differChanges = [
|
|
611
|
-
* { type: 'attribute', attributeKey: 'foo', ... },
|
|
612
|
-
* { type: 'attribute', attributeKey: 'bar', ... },
|
|
613
|
-
* { type: 'attribute', attributeKey: 'baz', ... }
|
|
614
|
-
* ];
|
|
615
|
-
*
|
|
616
|
-
* This method will return:
|
|
575
|
+
* Builds an instance of the {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi} from a template and a given
|
|
576
|
+
* {@link module:engine/view/downcastwriter~DowncastWriter `DowncastWriter`} and options object.
|
|
617
577
|
*
|
|
618
|
-
* const updatedChanges = [
|
|
619
|
-
* { type: 'reconvert', element: complexElementInstance },
|
|
620
|
-
* { type: 'attribute', attributeKey: 'baz', ... }
|
|
621
|
-
* ];
|
|
622
|
-
*
|
|
623
|
-
* In the example above, the `'baz'` attribute change will fire an {@link #event:attribute attribute event}
|
|
624
|
-
*
|
|
625
|
-
* @param {module:engine/model/differ~Differ} differ The differ object with buffered changes.
|
|
626
|
-
* @returns {Array.<Object>} Updated set of changes.
|
|
627
578
|
* @private
|
|
579
|
+
* @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify the view document.
|
|
580
|
+
* @param {Set.<module:engine/model/element~Element>} [refreshedItems] A set of model elements that should not reuse their
|
|
581
|
+
* previous view representations.
|
|
582
|
+
* @param {Object} [options] Optional options passed to `convertionApi.options`.
|
|
583
|
+
* @return {module:engine/conversion/downcastdispatcher~DowncastConversionApi} The conversion API object.
|
|
628
584
|
*/
|
|
629
|
-
|
|
630
|
-
const
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
const element = entry.type === 'attribute' ? getNodeAfterPosition( position, positionParent, null ) : positionParent;
|
|
647
|
-
|
|
648
|
-
// Case of text node set directly in root. For now used only in tests but can be possible when enabled in paragraph-like roots.
|
|
649
|
-
// See: https://github.com/ckeditor/ckeditor5/issues/762.
|
|
650
|
-
if ( element.is( '$text' ) ) {
|
|
651
|
-
updated.push( entry );
|
|
652
|
-
|
|
653
|
-
continue;
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
let eventName;
|
|
657
|
-
|
|
658
|
-
if ( entry.type === 'attribute' ) {
|
|
659
|
-
eventName = `attribute:${ entry.attributeKey }:${ element.name }`;
|
|
660
|
-
} else {
|
|
661
|
-
eventName = `${ entry.type }:${ entry.name }`;
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
if ( this._isReconvertTriggerEvent( eventName, element.name ) ) {
|
|
665
|
-
if ( itemsToReconvert.has( element ) ) {
|
|
666
|
-
// Element is already reconverted, so skip this change.
|
|
667
|
-
continue;
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
itemsToReconvert.add( element );
|
|
671
|
-
|
|
672
|
-
// Add special "reconvert" change.
|
|
673
|
-
updated.push( { type: 'reconvert', element } );
|
|
674
|
-
} else {
|
|
675
|
-
updated.push( entry );
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
return updated;
|
|
585
|
+
_createConversionApi( writer, refreshedItems = new Set(), options = {} ) {
|
|
586
|
+
const conversionApi = {
|
|
587
|
+
...this._conversionApi,
|
|
588
|
+
consumable: new Consumable(),
|
|
589
|
+
writer,
|
|
590
|
+
options,
|
|
591
|
+
convertItem: item => this._convertInsert( Range._createOn( item ), conversionApi ),
|
|
592
|
+
convertChildren: element => this._convertInsert( Range._createIn( element ), conversionApi, { doNotAddConsumables: true } ),
|
|
593
|
+
convertAttributes: item => this._testAndFireAddAttributes( item, conversionApi ),
|
|
594
|
+
canReuseView: viewElement => !refreshedItems.has( conversionApi.mapper.toModelElement( viewElement ) )
|
|
595
|
+
};
|
|
596
|
+
|
|
597
|
+
this._firedEventsMap.set( conversionApi, new Map() );
|
|
598
|
+
|
|
599
|
+
return conversionApi;
|
|
680
600
|
}
|
|
681
601
|
|
|
682
602
|
/**
|
|
683
|
-
*
|
|
684
|
-
*
|
|
685
|
-
*
|
|
686
|
-
* {@link module:engine/
|
|
687
|
-
*
|
|
688
|
-
* @
|
|
689
|
-
*
|
|
690
|
-
*
|
|
691
|
-
*
|
|
603
|
+
* Fired to enable reducing (transforming) changes buffered in the {@link module:engine/model/differ~Differ `Differ`} before
|
|
604
|
+
* {@link #convertChanges `convertChanges()`} will fire any conversion events.
|
|
605
|
+
*
|
|
606
|
+
* For instance, a feature can replace selected {@link module:engine/model/differ~DiffItem `DiffItem`}s with a `reinsert` entry
|
|
607
|
+
* to trigger reconversion of an element when e.g. its attribute has changes.
|
|
608
|
+
* The {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToStructure
|
|
609
|
+
* `DowncastHelpers.elementToStructure()`} helper is using this event to trigger reconversion of an element when the element,
|
|
610
|
+
* its attributes or direct children changed.
|
|
611
|
+
*
|
|
612
|
+
* @param {Object} data
|
|
613
|
+
* @param {Iterable.<module:engine/model/differ~DiffItem>} data.changes A buffered changes to get reduced.
|
|
614
|
+
* @event reduceChanges
|
|
692
615
|
*/
|
|
693
|
-
_isReconvertTriggerEvent( eventName, elementName ) {
|
|
694
|
-
return this._reconversionEventsMapping.get( eventName ) === elementName;
|
|
695
|
-
}
|
|
696
616
|
|
|
697
617
|
/**
|
|
698
618
|
* Fired for inserted nodes.
|
|
@@ -701,24 +621,24 @@ export default class DowncastDispatcher {
|
|
|
701
621
|
* `insert:name`. `name` is either `'$text'`, when {@link module:engine/model/text~Text a text node} has been inserted,
|
|
702
622
|
* or {@link module:engine/model/element~Element#name name} of inserted element.
|
|
703
623
|
*
|
|
704
|
-
* This way listeners can either listen to a general `insert` event or specific event (for example `insert:paragraph`).
|
|
624
|
+
* This way, the listeners can either listen to a general `insert` event or specific event (for example `insert:paragraph`).
|
|
705
625
|
*
|
|
706
626
|
* @event insert
|
|
707
627
|
* @param {Object} data Additional information about the change.
|
|
708
|
-
* @param {module:engine/model/item~Item} data.item
|
|
628
|
+
* @param {module:engine/model/item~Item} data.item The inserted item.
|
|
709
629
|
* @param {module:engine/model/range~Range} data.range Range spanning over inserted item.
|
|
710
630
|
* @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface
|
|
711
|
-
* to be used by callback, passed in `DowncastDispatcher` constructor.
|
|
631
|
+
* to be used by callback, passed in the `DowncastDispatcher` constructor.
|
|
712
632
|
*/
|
|
713
633
|
|
|
714
634
|
/**
|
|
715
635
|
* Fired for removed nodes.
|
|
716
636
|
*
|
|
717
637
|
* `remove` is a namespace for a class of events. Names of actually called events follow this pattern:
|
|
718
|
-
* `remove:name`. `name` is either `'$text'`, when {@link module:engine/model/text~Text a text node} has been removed,
|
|
638
|
+
* `remove:name`. `name` is either `'$text'`, when a {@link module:engine/model/text~Text a text node} has been removed,
|
|
719
639
|
* or the {@link module:engine/model/element~Element#name name} of removed element.
|
|
720
640
|
*
|
|
721
|
-
* This way listeners can either listen to a general `remove` event or specific event (for example `remove:paragraph`).
|
|
641
|
+
* This way, listeners can either listen to a general `remove` event or specific event (for example `remove:paragraph`).
|
|
722
642
|
*
|
|
723
643
|
* @event remove
|
|
724
644
|
* @param {Object} data Additional information about the change.
|
|
@@ -733,7 +653,7 @@ export default class DowncastDispatcher {
|
|
|
733
653
|
*
|
|
734
654
|
* * when an attribute has been added, changed, or removed from a node,
|
|
735
655
|
* * when a node with an attribute is inserted,
|
|
736
|
-
* * when collapsed model selection attribute is converted.
|
|
656
|
+
* * when a collapsed model selection attribute is converted.
|
|
737
657
|
*
|
|
738
658
|
* `attribute` is a namespace for a class of events. Names of actually called events follow this pattern:
|
|
739
659
|
* `attribute:attributeKey:name`. `attributeKey` is the key of added/changed/removed attribute.
|
|
@@ -857,17 +777,6 @@ function walkerValueToEventData( value ) {
|
|
|
857
777
|
};
|
|
858
778
|
}
|
|
859
779
|
|
|
860
|
-
function elementOrTextProxyToView( item, mapper ) {
|
|
861
|
-
if ( item.is( 'textProxy' ) ) {
|
|
862
|
-
const mappedPosition = mapper.toViewPosition( Position._createBefore( item ) );
|
|
863
|
-
const positionParent = mappedPosition.parent;
|
|
864
|
-
|
|
865
|
-
return positionParent.is( '$text' ) ? positionParent : null;
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
return mapper.toViewElement( item );
|
|
869
|
-
}
|
|
870
|
-
|
|
871
780
|
/**
|
|
872
781
|
* Conversion interface that is registered for given {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}
|
|
873
782
|
* and is passed as one of parameters when {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher dispatcher}
|
|
@@ -907,6 +816,28 @@ function elementOrTextProxyToView( item, mapper ) {
|
|
|
907
816
|
* @member {module:engine/view/downcastwriter~DowncastWriter} #writer
|
|
908
817
|
*/
|
|
909
818
|
|
|
819
|
+
/**
|
|
820
|
+
* Triggers conversion of a specified item.
|
|
821
|
+
* This conversion is triggered within (as a separate process of) the parent conversion.
|
|
822
|
+
*
|
|
823
|
+
* @method #convertItem
|
|
824
|
+
* @param {module:engine/model/item~Item} item The model item to trigger nested insert conversion on.
|
|
825
|
+
*/
|
|
826
|
+
|
|
827
|
+
/**
|
|
828
|
+
* Triggers conversion of children of a specified element.
|
|
829
|
+
*
|
|
830
|
+
* @method #convertChildren
|
|
831
|
+
* @param {module:engine/model/element~Element} element The model element to trigger children insert conversion on.
|
|
832
|
+
*/
|
|
833
|
+
|
|
834
|
+
/**
|
|
835
|
+
* Triggers conversion of attributes of a specified item.
|
|
836
|
+
*
|
|
837
|
+
* @method #convertAttributes
|
|
838
|
+
* @param {module:engine/model/item~Item} item The model item to trigger attribute conversion on.
|
|
839
|
+
*/
|
|
840
|
+
|
|
910
841
|
/**
|
|
911
842
|
* An object with an additional configuration which can be used during the conversion process. Available only for data downcast conversion.
|
|
912
843
|
*
|