@ckeditor/ckeditor5-engine 31.1.0 → 34.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/LICENSE.md +2 -2
- package/README.md +2 -1
- package/package.json +25 -25
- package/src/controller/datacontroller.js +65 -74
- package/src/controller/editingcontroller.js +83 -6
- package/src/conversion/conversion.js +15 -14
- package/src/conversion/conversionhelpers.js +1 -1
- package/src/conversion/downcastdispatcher.js +298 -367
- package/src/conversion/downcasthelpers.js +860 -81
- package/src/conversion/mapper.js +105 -60
- package/src/conversion/modelconsumable.js +85 -35
- package/src/conversion/upcastdispatcher.js +34 -7
- package/src/conversion/upcasthelpers.js +4 -2
- package/src/conversion/viewconsumable.js +1 -1
- package/src/dataprocessor/basichtmlwriter.js +1 -1
- package/src/dataprocessor/dataprocessor.jsdoc +1 -1
- package/src/dataprocessor/htmldataprocessor.js +9 -31
- package/src/dataprocessor/htmlwriter.js +1 -1
- package/src/dataprocessor/xmldataprocessor.js +1 -1
- package/src/dev-utils/model.js +16 -14
- package/src/dev-utils/operationreplayer.js +1 -1
- package/src/dev-utils/utils.js +1 -1
- package/src/dev-utils/view.js +1 -1
- package/src/index.js +8 -1
- package/src/model/batch.js +77 -10
- package/src/model/differ.js +115 -69
- package/src/model/document.js +13 -4
- package/src/model/documentfragment.js +1 -1
- package/src/model/documentselection.js +1 -1
- package/src/model/element.js +1 -1
- package/src/model/history.js +1 -1
- package/src/model/item.jsdoc +1 -1
- package/src/model/liveposition.js +1 -1
- package/src/model/liverange.js +1 -1
- package/src/model/markercollection.js +29 -5
- package/src/model/model.js +138 -12
- package/src/model/node.js +1 -1
- package/src/model/nodelist.js +1 -1
- package/src/model/operation/attributeoperation.js +1 -1
- package/src/model/operation/detachoperation.js +1 -1
- package/src/model/operation/insertoperation.js +1 -1
- package/src/model/operation/markeroperation.js +1 -1
- package/src/model/operation/mergeoperation.js +1 -1
- package/src/model/operation/moveoperation.js +1 -1
- package/src/model/operation/nooperation.js +1 -1
- package/src/model/operation/operation.js +1 -1
- package/src/model/operation/operationfactory.js +1 -1
- package/src/model/operation/renameoperation.js +1 -1
- package/src/model/operation/rootattributeoperation.js +1 -1
- package/src/model/operation/splitoperation.js +1 -1
- package/src/model/operation/transform.js +1 -1
- package/src/model/operation/utils.js +1 -1
- package/src/model/position.js +1 -1
- package/src/model/range.js +1 -1
- package/src/model/rootelement.js +1 -1
- package/src/model/schema.js +80 -11
- package/src/model/selection.js +1 -1
- package/src/model/text.js +1 -1
- package/src/model/textproxy.js +1 -1
- package/src/model/treewalker.js +3 -4
- package/src/model/utils/autoparagraphing.js +1 -1
- package/src/model/utils/deletecontent.js +16 -3
- package/src/model/utils/findoptimalinsertionrange.js +68 -0
- package/src/model/utils/getselectedcontent.js +1 -1
- package/src/model/utils/insertcontent.js +1 -1
- package/src/model/utils/insertobject.js +173 -0
- package/src/model/utils/modifyselection.js +15 -8
- package/src/model/utils/selection-post-fixer.js +1 -1
- package/src/model/writer.js +17 -27
- package/src/view/attributeelement.js +1 -11
- package/src/view/containerelement.js +1 -1
- package/src/view/document.js +3 -2
- package/src/view/documentfragment.js +1 -1
- package/src/view/documentselection.js +1 -1
- package/src/view/domconverter.js +55 -28
- package/src/view/downcastwriter.js +91 -50
- package/src/view/editableelement.js +1 -1
- package/src/view/element.js +1 -28
- package/src/view/elementdefinition.jsdoc +1 -1
- package/src/view/emptyelement.js +1 -4
- package/src/view/filler.js +1 -1
- package/src/view/item.jsdoc +1 -1
- package/src/view/matcher.js +3 -3
- package/src/view/node.js +1 -1
- package/src/view/observer/arrowkeysobserver.js +1 -1
- package/src/view/observer/bubblingemittermixin.js +1 -1
- package/src/view/observer/bubblingeventinfo.js +1 -1
- package/src/view/observer/clickobserver.js +1 -2
- package/src/view/observer/compositionobserver.js +1 -1
- package/src/view/observer/domeventdata.js +1 -1
- package/src/view/observer/domeventobserver.js +1 -1
- package/src/view/observer/fakeselectionobserver.js +1 -1
- package/src/view/observer/focusobserver.js +1 -1
- package/src/view/observer/inputobserver.js +2 -2
- package/src/view/observer/keyobserver.js +1 -1
- package/src/view/observer/mouseobserver.js +1 -1
- package/src/view/observer/mutationobserver.js +1 -1
- package/src/view/observer/observer.js +1 -1
- package/src/view/observer/selectionobserver.js +1 -1
- package/src/view/observer/tabobserver.js +68 -0
- package/src/view/placeholder.js +2 -2
- package/src/view/position.js +1 -1
- package/src/view/range.js +1 -1
- package/src/view/rawelement.js +1 -4
- package/src/view/renderer.js +3 -2
- package/src/view/rooteditableelement.js +1 -1
- package/src/view/selection.js +1 -1
- package/src/view/styles/background.js +1 -1
- package/src/view/styles/border.js +1 -1
- package/src/view/styles/margin.js +1 -1
- package/src/view/styles/padding.js +1 -1
- package/src/view/styles/utils.js +1 -1
- package/src/view/stylesmap.js +1 -1
- package/src/view/text.js +1 -1
- package/src/view/textproxy.js +1 -1
- package/src/view/treewalker.js +1 -1
- package/src/view/uielement.js +1 -4
- package/src/view/upcastwriter.js +1 -1
- package/src/view/view.js +5 -1
- package/theme/placeholder.css +10 -1
- package/theme/renderer.css +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Copyright (c) 2003-
|
|
2
|
+
* @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import ModelRange from '../model/range';
|
|
13
13
|
import ModelSelection from '../model/selection';
|
|
14
14
|
import ModelElement from '../model/element';
|
|
15
|
+
import ModelPosition from '../model/position';
|
|
15
16
|
|
|
16
17
|
import ViewAttributeElement from '../view/attributeelement';
|
|
17
18
|
import DocumentSelection from '../model/documentselection';
|
|
@@ -24,6 +25,8 @@ import toArray from '@ckeditor/ckeditor5-utils/src/toarray';
|
|
|
24
25
|
/**
|
|
25
26
|
* Downcast conversion helper functions.
|
|
26
27
|
*
|
|
28
|
+
* Learn more about {@glink framework/guides/deep-dive/conversion/downcast downcast helpers}.
|
|
29
|
+
*
|
|
27
30
|
* @extends module:engine/conversion/conversionhelpers~ConversionHelpers
|
|
28
31
|
*/
|
|
29
32
|
export default class DowncastHelpers extends ConversionHelpers {
|
|
@@ -60,42 +63,243 @@ export default class DowncastHelpers extends ConversionHelpers {
|
|
|
60
63
|
* }
|
|
61
64
|
* } );
|
|
62
65
|
*
|
|
63
|
-
* The element-to-element conversion supports the reconversion mechanism.
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
+
* The element-to-element conversion supports the reconversion mechanism. It can be enabled by using either the `attributes` or
|
|
67
|
+
* the `children` props on a model description. You will find a couple examples below.
|
|
68
|
+
*
|
|
69
|
+
* In order to reconvert an element if any of its direct children have been added or removed, use the `children` property on a `model`
|
|
70
|
+
* description. For example, this model:
|
|
71
|
+
*
|
|
72
|
+
* <box>
|
|
73
|
+
* <paragraph>Some text.</paragraph>
|
|
74
|
+
* </box>
|
|
75
|
+
*
|
|
76
|
+
* will be converted into this structure in the view:
|
|
77
|
+
*
|
|
78
|
+
* <div class="box" data-type="single">
|
|
79
|
+
* <p>Some text.</p>
|
|
80
|
+
* </div>
|
|
81
|
+
*
|
|
82
|
+
* But if more items were inserted in the model:
|
|
83
|
+
*
|
|
84
|
+
* <box>
|
|
85
|
+
* <paragraph>Some text.</paragraph>
|
|
86
|
+
* <paragraph>Other item.</paragraph>
|
|
87
|
+
* </box>
|
|
88
|
+
*
|
|
89
|
+
* it will be converted into this structure in the view (note the element `data-type` change):
|
|
90
|
+
*
|
|
91
|
+
* <div class="box" data-type="multiple">
|
|
92
|
+
* <p>Some text.</p>
|
|
93
|
+
* <p>Other item.</p>
|
|
94
|
+
* </div>
|
|
95
|
+
*
|
|
96
|
+
* Such a converter would look like this (note that the `paragraph` elements are converted separately):
|
|
66
97
|
*
|
|
67
98
|
* editor.conversion.for( 'downcast' ).elementToElement( {
|
|
68
|
-
* model:
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
99
|
+
* model: {
|
|
100
|
+
* name: 'box',
|
|
101
|
+
* children: true
|
|
102
|
+
* },
|
|
103
|
+
* view: ( modelElement, conversionApi ) => {
|
|
104
|
+
* const { writer } = conversionApi;
|
|
105
|
+
*
|
|
106
|
+
* return writer.createContainerElement( 'div', {
|
|
107
|
+
* class: 'box',
|
|
108
|
+
* 'data-type': modelElement.childCount == 1 ? 'single' : 'multiple'
|
|
109
|
+
* } );
|
|
110
|
+
* }
|
|
111
|
+
* } );
|
|
112
|
+
*
|
|
113
|
+
* In order to reconvert element if any of its attributes have been updated, use the `attributes` property on a `model`
|
|
114
|
+
* description. For example, this model:
|
|
115
|
+
*
|
|
116
|
+
* <heading level="2">Some text.</heading>
|
|
117
|
+
*
|
|
118
|
+
* will be converted into this structure in the view:
|
|
119
|
+
*
|
|
120
|
+
* <h2>Some text.</h2>
|
|
121
|
+
*
|
|
122
|
+
* But if the `heading` element's `level` attribute has been updated to `3` for example, then
|
|
123
|
+
* it will be converted into this structure in the view:
|
|
124
|
+
*
|
|
125
|
+
* <h3>Some text.</h3>
|
|
126
|
+
*
|
|
127
|
+
* Such a converter would look as follows:
|
|
128
|
+
*
|
|
129
|
+
* editor.conversion.for( 'downcast' ).elementToElement( {
|
|
130
|
+
* model: {
|
|
131
|
+
* name: 'heading',
|
|
132
|
+
* attributes: 'level'
|
|
133
|
+
* },
|
|
134
|
+
* view: ( modelElement, conversionApi ) => {
|
|
135
|
+
* const { writer } = conversionApi;
|
|
136
|
+
*
|
|
137
|
+
* return writer.createContainerElement( 'h' + modelElement.getAttribute( 'level' ) );
|
|
73
138
|
* }
|
|
74
139
|
* } );
|
|
75
140
|
*
|
|
76
141
|
* See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter
|
|
77
142
|
* to the conversion process.
|
|
78
143
|
*
|
|
79
|
-
* You can read more about element-to-element conversion in the
|
|
80
|
-
* {@glink framework/guides/deep-dive/conversion/
|
|
144
|
+
* You can read more about the element-to-element conversion in the
|
|
145
|
+
* {@glink framework/guides/deep-dive/conversion/downcast downcast conversion} guide.
|
|
81
146
|
*
|
|
82
147
|
* @method #elementToElement
|
|
83
148
|
* @param {Object} config Conversion configuration.
|
|
84
|
-
* @param {String} config.model The name of the model element to convert.
|
|
85
|
-
* @param {
|
|
86
|
-
* that
|
|
149
|
+
* @param {String|Object} config.model The description or a name of the model element to convert.
|
|
150
|
+
* @param {String|Array.<String>} [config.model.attributes] The list of attribute names that should be consumed while creating
|
|
151
|
+
* the view element. Note that the view will be reconverted if any of the listed attributes changes.
|
|
152
|
+
* @param {Boolean} [config.model.children] Specifies whether the view element requires reconversion if the list
|
|
153
|
+
* of the model child nodes changed.
|
|
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}
|
|
87
157
|
* as parameters and returns a view container element.
|
|
88
|
-
* @param {Object} [config.triggerBy] Reconversion triggers. At least one trigger must be defined.
|
|
89
|
-
* @param {Array.<String>} config.triggerBy.attributes The name of the element's attributes whose change will trigger element
|
|
90
|
-
* reconversion.
|
|
91
|
-
* @param {Array.<String>} config.triggerBy.children The name of direct children whose adding or removing will trigger element
|
|
92
|
-
* reconversion.
|
|
93
158
|
* @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}
|
|
94
159
|
*/
|
|
95
160
|
elementToElement( config ) {
|
|
96
161
|
return this.add( downcastElementToElement( config ) );
|
|
97
162
|
}
|
|
98
163
|
|
|
164
|
+
/**
|
|
165
|
+
* The model element to view structure (several elements) conversion helper.
|
|
166
|
+
*
|
|
167
|
+
* This conversion results in creating a view structure with one or more slots defined for the child nodes.
|
|
168
|
+
* For example, a model `<table>` may become this structure in the view:
|
|
169
|
+
*
|
|
170
|
+
* <figure class="table">
|
|
171
|
+
* <table>
|
|
172
|
+
* <tbody>${ slot for table rows }</tbody>
|
|
173
|
+
* </table>
|
|
174
|
+
* </figure>
|
|
175
|
+
*
|
|
176
|
+
* The children of the model's `<table>` element will be inserted into the `<tbody>` element.
|
|
177
|
+
* If the `elementToElement()` helper was used, the children would be inserted into the `<figure>`.
|
|
178
|
+
*
|
|
179
|
+
* An example converter that converts the following model structure:
|
|
180
|
+
*
|
|
181
|
+
* <wrappedParagraph>Some text.</wrappedParagraph>
|
|
182
|
+
*
|
|
183
|
+
* into this structure in the view:
|
|
184
|
+
*
|
|
185
|
+
* <div class="wrapper">
|
|
186
|
+
* <p>Some text.</p>
|
|
187
|
+
* </div>
|
|
188
|
+
*
|
|
189
|
+
* would look like this:
|
|
190
|
+
*
|
|
191
|
+
* editor.conversion.for( 'downcast' ).elementToStructure( {
|
|
192
|
+
* model: 'wrappedParagraph',
|
|
193
|
+
* view: ( modelElement, conversionApi ) => {
|
|
194
|
+
* const { writer } = conversionApi;
|
|
195
|
+
*
|
|
196
|
+
* const wrapperViewElement = writer.createContainerElement( 'div', { class: 'wrapper' } );
|
|
197
|
+
* const paragraphViewElement = writer.createContainerElement( 'p' );
|
|
198
|
+
*
|
|
199
|
+
* writer.insert( writer.createPositionAt( wrapperViewElement, 0 ), paragraphViewElement );
|
|
200
|
+
* writer.insert( writer.createPositionAt( paragraphViewElement, 0 ), writer.createSlot() );
|
|
201
|
+
*
|
|
202
|
+
* return wrapperViewElement;
|
|
203
|
+
* }
|
|
204
|
+
* } );
|
|
205
|
+
*
|
|
206
|
+
* The `slorFor()` function can also take a callback that allows filtering which children of the model element
|
|
207
|
+
* should be converted into this slot.
|
|
208
|
+
*
|
|
209
|
+
* Imagine a table feature where for this model structure:
|
|
210
|
+
*
|
|
211
|
+
* <table headingRows="1">
|
|
212
|
+
* <tableRow> ... table cells 1 ... </tableRow>
|
|
213
|
+
* <tableRow> ... table cells 2 ... </tableRow>
|
|
214
|
+
* <tableRow> ... table cells 3 ... </tableRow>
|
|
215
|
+
* <caption>Caption text</caption>
|
|
216
|
+
* </table>
|
|
217
|
+
*
|
|
218
|
+
* we want to generate this view structure:
|
|
219
|
+
*
|
|
220
|
+
* <figure class="table">
|
|
221
|
+
* <table>
|
|
222
|
+
* <thead>
|
|
223
|
+
* <tr> ... table cells 1 ... </tr>
|
|
224
|
+
* </thead>
|
|
225
|
+
* <tbody>
|
|
226
|
+
* <tr> ... table cells 2 ... </tr>
|
|
227
|
+
* <tr> ... table cells 3 ... </tr>
|
|
228
|
+
* </tbody>
|
|
229
|
+
* </table>
|
|
230
|
+
* <figcaption>Caption text</figcaption>
|
|
231
|
+
* </figure>
|
|
232
|
+
*
|
|
233
|
+
* The converter has to take the `headingRows` attribute into consideration when allocating the `<tableRow>` elements
|
|
234
|
+
* into the `<tbody>` and `<thead>` elements. Hence, we need two slots and need to define proper filter callbacks for them.
|
|
235
|
+
*
|
|
236
|
+
* Additionally, all elements other than `<tableRow>` should be placed outside the `<table>` tag.
|
|
237
|
+
* In the example above, this will handle the table caption.
|
|
238
|
+
*
|
|
239
|
+
* Such a converter would look like this:
|
|
240
|
+
*
|
|
241
|
+
* editor.conversion.for( 'downcast' ).elementToStructure( {
|
|
242
|
+
* model: {
|
|
243
|
+
* name: 'table',
|
|
244
|
+
* attributes: [ 'headingRows' ]
|
|
245
|
+
* },
|
|
246
|
+
* view: ( modelElement, conversionApi ) => {
|
|
247
|
+
* const { writer } = conversionApi;
|
|
248
|
+
*
|
|
249
|
+
* const figureElement = writer.createContainerElement( 'figure', { class: 'table' } );
|
|
250
|
+
* const tableElement = writer.createContainerElement( 'table' );
|
|
251
|
+
*
|
|
252
|
+
* writer.insert( writer.createPositionAt( figureElement, 0 ), tableElement );
|
|
253
|
+
*
|
|
254
|
+
* const headingRows = modelElement.getAttribute( 'headingRows' ) || 0;
|
|
255
|
+
*
|
|
256
|
+
* if ( headingRows > 0 ) {
|
|
257
|
+
* const tableHead = writer.createContainerElement( 'thead' );
|
|
258
|
+
*
|
|
259
|
+
* const headSlot = writer.createSlot( node => node.is( 'element', 'tableRow' ) && node.index < headingRows );
|
|
260
|
+
*
|
|
261
|
+
* writer.insert( writer.createPositionAt( tableElement, 'end' ), tableHead );
|
|
262
|
+
* writer.insert( writer.createPositionAt( tableHead, 0 ), headSlot );
|
|
263
|
+
* }
|
|
264
|
+
*
|
|
265
|
+
* if ( headingRows < tableUtils.getRows( table ) ) {
|
|
266
|
+
* const tableBody = writer.createContainerElement( 'tbody' );
|
|
267
|
+
*
|
|
268
|
+
* const bodySlot = writer.createSlot( node => node.is( 'element', 'tableRow' ) && node.index >= headingRows );
|
|
269
|
+
*
|
|
270
|
+
* writer.insert( writer.createPositionAt( tableElement, 'end' ), tableBody );
|
|
271
|
+
* writer.insert( writer.createPositionAt( tableBody, 0 ), bodySlot );
|
|
272
|
+
* }
|
|
273
|
+
*
|
|
274
|
+
* const restSlot = writer.createSlot( node => !node.is( 'element', 'tableRow' ) );
|
|
275
|
+
*
|
|
276
|
+
* writer.insert( writer.createPositionAt( figureElement, 'end' ), restSlot );
|
|
277
|
+
*
|
|
278
|
+
* return figureElement;
|
|
279
|
+
* }
|
|
280
|
+
* } );
|
|
281
|
+
*
|
|
282
|
+
* Note: The children of a model element that's being converted must be allocated in the same order in the view
|
|
283
|
+
* in which they are placed in the model.
|
|
284
|
+
*
|
|
285
|
+
* See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter
|
|
286
|
+
* to the conversion process.
|
|
287
|
+
*
|
|
288
|
+
* @method #elementToStructure
|
|
289
|
+
* @param {Object} config Conversion configuration.
|
|
290
|
+
* @param {String|Object} config.model The description or a name of the model element to convert.
|
|
291
|
+
* @param {String} [config.model.name] The name of the model element to convert.
|
|
292
|
+
* @param {String|Array.<String>} [config.model.attributes] The list of attribute names that should be consumed while creating
|
|
293
|
+
* the view structure. Note that the view will be reconverted if any of the listed attributes will change.
|
|
294
|
+
* @param {module:engine/conversion/downcasthelpers~StructureCreatorFunction} config.view A function
|
|
295
|
+
* that takes the model element and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast
|
|
296
|
+
* conversion API} as parameters and returns a view container element with slots for model child nodes to be converted into.
|
|
297
|
+
* @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}
|
|
298
|
+
*/
|
|
299
|
+
elementToStructure( config ) {
|
|
300
|
+
return this.add( downcastElementToStructure( config ) );
|
|
301
|
+
}
|
|
302
|
+
|
|
99
303
|
/**
|
|
100
304
|
* Model attribute to view element conversion helper.
|
|
101
305
|
*
|
|
@@ -174,7 +378,8 @@ export default class DowncastHelpers extends ConversionHelpers {
|
|
|
174
378
|
* @param {Object} config Conversion configuration.
|
|
175
379
|
* @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values }` object. `values` is an array
|
|
176
380
|
* of `String`s with possible values if the model attribute is an enumerable.
|
|
177
|
-
* @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
|
|
178
383
|
* that takes the model attribute value and
|
|
179
384
|
* {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API} as parameters and returns a view
|
|
180
385
|
* attribute element. If `config.model.values` is given, `config.view` should be an object assigning values from `config.model.values`
|
|
@@ -256,10 +461,11 @@ export default class DowncastHelpers extends ConversionHelpers {
|
|
|
256
461
|
* @param {Object} config Conversion configuration.
|
|
257
462
|
* @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values, [ name ] }` object describing
|
|
258
463
|
* the attribute key, possible values and, optionally, an element name to convert from.
|
|
259
|
-
* @param {String|Object|
|
|
260
|
-
*
|
|
261
|
-
*
|
|
262
|
-
*
|
|
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}
|
|
467
|
+
* as parameters and returns a `{ key, value }` object. If the `key` is `'class'`, the `value` can be a `String` or an
|
|
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`.
|
|
263
469
|
* If `config.model.values` is set, `config.view` should be an object assigning values from `config.model.values` to
|
|
264
470
|
* `{ key, value }` objects or a functions.
|
|
265
471
|
* @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.
|
|
@@ -272,14 +478,14 @@ export default class DowncastHelpers extends ConversionHelpers {
|
|
|
272
478
|
/**
|
|
273
479
|
* Model marker to view element conversion helper.
|
|
274
480
|
*
|
|
275
|
-
* **Note**: This method should be used mainly for editing downcast and it is recommended
|
|
276
|
-
* to use {@link #markerToData `#markerToData()`} helper instead.
|
|
481
|
+
* **Note**: This method should be used mainly for editing the downcast and it is recommended
|
|
482
|
+
* to use the {@link #markerToData `#markerToData()`} helper instead.
|
|
277
483
|
*
|
|
278
484
|
* This helper may produce invalid HTML code (e.g. a span between table cells).
|
|
279
|
-
* It should be used
|
|
485
|
+
* It should only be used when you are sure that the produced HTML will be semantically correct.
|
|
280
486
|
*
|
|
281
487
|
* This conversion results in creating a view element on the boundaries of the converted marker. If the converted marker
|
|
282
|
-
* is collapsed, only one element is created. For example, model marker set like this: `<paragraph>F[oo b]ar</paragraph>`
|
|
488
|
+
* is collapsed, only one element is created. For example, a model marker set like this: `<paragraph>F[oo b]ar</paragraph>`
|
|
283
489
|
* becomes `<p>F<span data-marker="search"></span>oo b<span data-marker="search"></span>ar</p>` in the view.
|
|
284
490
|
*
|
|
285
491
|
* editor.conversion.for( 'editingDowncast' ).markerToElement( {
|
|
@@ -321,7 +527,7 @@ export default class DowncastHelpers extends ConversionHelpers {
|
|
|
321
527
|
* {@link module:engine/view/uielement~UIElement view UI element}. The `data` object and
|
|
322
528
|
* {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi `conversionApi`} are passed from
|
|
323
529
|
* {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker}. Additionally,
|
|
324
|
-
* the `data.isOpening` parameter is passed, which is set to `true` for the marker start boundary element, and `false`
|
|
530
|
+
* the `data.isOpening` parameter is passed, which is set to `true` for the marker start boundary element, and `false` for
|
|
325
531
|
* the marker end boundary element.
|
|
326
532
|
*
|
|
327
533
|
* See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter
|
|
@@ -344,7 +550,7 @@ export default class DowncastHelpers extends ConversionHelpers {
|
|
|
344
550
|
* Model marker to highlight conversion helper.
|
|
345
551
|
*
|
|
346
552
|
* This conversion results in creating a highlight on view nodes. For this kind of conversion,
|
|
347
|
-
* {@link module:engine/conversion/downcasthelpers~HighlightDescriptor} should be provided.
|
|
553
|
+
* the {@link module:engine/conversion/downcasthelpers~HighlightDescriptor} should be provided.
|
|
348
554
|
*
|
|
349
555
|
* For text nodes, a `<span>` {@link module:engine/view/attributeelement~AttributeElement} is created and it wraps all text nodes
|
|
350
556
|
* in the converted marker range. For example, a model marker set like this: `<paragraph>F[oo b]ar</paragraph>` becomes
|
|
@@ -382,7 +588,7 @@ export default class DowncastHelpers extends ConversionHelpers {
|
|
|
382
588
|
*
|
|
383
589
|
* If a function is passed as the `config.view` parameter, it will be used to generate the highlight descriptor. The function
|
|
384
590
|
* receives the `data` object and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}
|
|
385
|
-
* as
|
|
591
|
+
* as the parameters and should return a
|
|
386
592
|
* {@link module:engine/conversion/downcasthelpers~HighlightDescriptor highlight descriptor}.
|
|
387
593
|
* The `data` object properties are passed from {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker}.
|
|
388
594
|
*
|
|
@@ -464,7 +670,7 @@ export default class DowncastHelpers extends ConversionHelpers {
|
|
|
464
670
|
* // Model:
|
|
465
671
|
* <blockQuote>[]<paragraph>Foo</paragraph></blockQuote>
|
|
466
672
|
*
|
|
467
|
-
*
|
|
673
|
+
* // View:
|
|
468
674
|
* <blockquote><p data-group-end-before="name" data-group-start-before="name">Foo</p></blockquote>
|
|
469
675
|
*
|
|
470
676
|
* Similarly, when a marker is collapsed after the last element:
|
|
@@ -530,7 +736,7 @@ export default class DowncastHelpers extends ConversionHelpers {
|
|
|
530
736
|
*/
|
|
531
737
|
export function insertText() {
|
|
532
738
|
return ( evt, data, conversionApi ) => {
|
|
533
|
-
if ( !conversionApi.consumable.consume( data.item,
|
|
739
|
+
if ( !conversionApi.consumable.consume( data.item, evt.name ) ) {
|
|
534
740
|
return;
|
|
535
741
|
}
|
|
536
742
|
|
|
@@ -542,6 +748,23 @@ export function insertText() {
|
|
|
542
748
|
};
|
|
543
749
|
}
|
|
544
750
|
|
|
751
|
+
/**
|
|
752
|
+
* Function factory that creates a default downcast converter for triggering attributes and children conversion.
|
|
753
|
+
*
|
|
754
|
+
* @returns {Function} The converter.
|
|
755
|
+
*/
|
|
756
|
+
export function insertAttributesAndChildren() {
|
|
757
|
+
return ( evt, data, conversionApi ) => {
|
|
758
|
+
conversionApi.convertAttributes( data.item );
|
|
759
|
+
|
|
760
|
+
// Start converting children of the current item.
|
|
761
|
+
// In case of reconversion children were already re-inserted or converted separately.
|
|
762
|
+
if ( !data.reconversion && data.item.is( 'element' ) && !data.item.isEmpty ) {
|
|
763
|
+
conversionApi.convertChildren( data.item );
|
|
764
|
+
}
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
|
|
545
768
|
/**
|
|
546
769
|
* Function factory that creates a default downcast converter for node remove changes.
|
|
547
770
|
*
|
|
@@ -565,7 +788,7 @@ export function remove() {
|
|
|
565
788
|
// After the range is removed, unbind all view elements from the model.
|
|
566
789
|
// Range inside view document fragment is used to unbind deeply.
|
|
567
790
|
for ( const child of conversionApi.writer.createRangeIn( removed ).getItems() ) {
|
|
568
|
-
conversionApi.mapper.unbindViewElement( child );
|
|
791
|
+
conversionApi.mapper.unbindViewElement( child, { defer: true } );
|
|
569
792
|
}
|
|
570
793
|
};
|
|
571
794
|
}
|
|
@@ -713,7 +936,7 @@ export function clearAttributes() {
|
|
|
713
936
|
}
|
|
714
937
|
|
|
715
938
|
/**
|
|
716
|
-
* Function factory that creates a converter which converts set/change/remove attribute changes from the model to the view.
|
|
939
|
+
* Function factory that creates a converter which converts the set/change/remove attribute changes from the model to the view.
|
|
717
940
|
* It can also be used to convert selection attributes. In that case, an empty attribute element will be created and the
|
|
718
941
|
* selection will be put inside it.
|
|
719
942
|
*
|
|
@@ -745,20 +968,22 @@ export function clearAttributes() {
|
|
|
745
968
|
*/
|
|
746
969
|
export function wrap( elementCreator ) {
|
|
747
970
|
return ( evt, data, conversionApi ) => {
|
|
971
|
+
if ( !conversionApi.consumable.test( data.item, evt.name ) ) {
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
|
|
748
975
|
// Recreate current wrapping node. It will be used to unwrap view range if the attribute value has changed
|
|
749
976
|
// or the attribute was removed.
|
|
750
|
-
const oldViewElement = elementCreator( data.attributeOldValue, conversionApi );
|
|
977
|
+
const oldViewElement = elementCreator( data.attributeOldValue, conversionApi, data );
|
|
751
978
|
|
|
752
979
|
// Create node to wrap with.
|
|
753
|
-
const newViewElement = elementCreator( data.attributeNewValue, conversionApi );
|
|
980
|
+
const newViewElement = elementCreator( data.attributeNewValue, conversionApi, data );
|
|
754
981
|
|
|
755
982
|
if ( !oldViewElement && !newViewElement ) {
|
|
756
983
|
return;
|
|
757
984
|
}
|
|
758
985
|
|
|
759
|
-
|
|
760
|
-
return;
|
|
761
|
-
}
|
|
986
|
+
conversionApi.consumable.consume( data.item, evt.name );
|
|
762
987
|
|
|
763
988
|
const viewWriter = conversionApi.writer;
|
|
764
989
|
const viewSelection = viewWriter.document.selection;
|
|
@@ -789,8 +1014,7 @@ export function wrap( elementCreator ) {
|
|
|
789
1014
|
* It is expected that the function returns an {@link module:engine/view/element~Element}.
|
|
790
1015
|
* The result of the function will be inserted into the view.
|
|
791
1016
|
*
|
|
792
|
-
* The converter automatically consumes the corresponding value from the consumables list
|
|
793
|
-
* {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}) and binds the model and view elements.
|
|
1017
|
+
* The converter automatically consumes the corresponding value from the consumables list and binds the model and view elements.
|
|
794
1018
|
*
|
|
795
1019
|
* downcastDispatcher.on(
|
|
796
1020
|
* 'insert:myElem',
|
|
@@ -806,24 +1030,88 @@ export function wrap( elementCreator ) {
|
|
|
806
1030
|
*
|
|
807
1031
|
* @protected
|
|
808
1032
|
* @param {Function} elementCreator Function returning a view element, which will be inserted.
|
|
1033
|
+
* @param {module:engine/conversion/downcasthelpers~ConsumerFunction} [consumer] Function defining element consumption process.
|
|
1034
|
+
* By default this function just consume passed item insertion.
|
|
809
1035
|
* @returns {Function} Insert element event converter.
|
|
810
1036
|
*/
|
|
811
|
-
export function insertElement( elementCreator ) {
|
|
1037
|
+
export function insertElement( elementCreator, consumer = defaultConsumer ) {
|
|
812
1038
|
return ( evt, data, conversionApi ) => {
|
|
813
|
-
|
|
1039
|
+
if ( !consumer( data.item, conversionApi.consumable, { preflight: true } ) ) {
|
|
1040
|
+
return;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
const viewElement = elementCreator( data.item, conversionApi, data );
|
|
814
1044
|
|
|
815
1045
|
if ( !viewElement ) {
|
|
816
1046
|
return;
|
|
817
1047
|
}
|
|
818
1048
|
|
|
819
|
-
|
|
1049
|
+
// Consume an element insertion and all present attributes that are specified as a reconversion triggers.
|
|
1050
|
+
consumer( data.item, conversionApi.consumable );
|
|
1051
|
+
|
|
1052
|
+
const viewPosition = conversionApi.mapper.toViewPosition( data.range.start );
|
|
1053
|
+
|
|
1054
|
+
conversionApi.mapper.bindElements( data.item, viewElement );
|
|
1055
|
+
conversionApi.writer.insert( viewPosition, viewElement );
|
|
1056
|
+
|
|
1057
|
+
// Convert attributes before converting children.
|
|
1058
|
+
conversionApi.convertAttributes( data.item );
|
|
1059
|
+
|
|
1060
|
+
// Convert children or reinsert previous view elements.
|
|
1061
|
+
reinsertOrConvertNodes( viewElement, data.item.getChildren(), conversionApi, { reconversion: data.reconversion } );
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
/**
|
|
1066
|
+
* Function factory that creates a converter which converts a single model node insertion to a view structure.
|
|
1067
|
+
*
|
|
1068
|
+
* It is expected that the passed element creator function returns an {@link module:engine/view/element~Element} with attached slots
|
|
1069
|
+
* created with `writer.createSlot()` to indicate where child nodes should be converted.
|
|
1070
|
+
*
|
|
1071
|
+
* @see module:engine/conversion/downcasthelpers~DowncastHelpers#elementToStructure
|
|
1072
|
+
*
|
|
1073
|
+
* @protected
|
|
1074
|
+
* @param {module:engine/conversion/downcasthelpers~StructureCreatorFunction} elementCreator Function returning a view structure,
|
|
1075
|
+
* which will be inserted.
|
|
1076
|
+
* @param {module:engine/conversion/downcasthelpers~ConsumerFunction} consumer A callback that is expected to consume all the consumables
|
|
1077
|
+
* that were used by the element creator.
|
|
1078
|
+
* @returns {Function} Insert element event converter.
|
|
1079
|
+
*/
|
|
1080
|
+
export function insertStructure( elementCreator, consumer ) {
|
|
1081
|
+
return ( evt, data, conversionApi ) => {
|
|
1082
|
+
if ( !consumer( data.item, conversionApi.consumable, { preflight: true } ) ) {
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
const slotsMap = new Map();
|
|
1087
|
+
|
|
1088
|
+
conversionApi.writer._registerSlotFactory( createSlotFactory( data.item, slotsMap, conversionApi ) );
|
|
1089
|
+
|
|
1090
|
+
// View creation.
|
|
1091
|
+
const viewElement = elementCreator( data.item, conversionApi, data );
|
|
1092
|
+
|
|
1093
|
+
conversionApi.writer._clearSlotFactory();
|
|
1094
|
+
|
|
1095
|
+
if ( !viewElement ) {
|
|
820
1096
|
return;
|
|
821
1097
|
}
|
|
822
1098
|
|
|
1099
|
+
// Check if all children are covered by slots and there is no child that landed in multiple slots.
|
|
1100
|
+
validateSlotsChildren( data.item, slotsMap, conversionApi );
|
|
1101
|
+
|
|
1102
|
+
// Consume an element insertion and all present attributes that are specified as a reconversion triggers.
|
|
1103
|
+
consumer( data.item, conversionApi.consumable );
|
|
1104
|
+
|
|
823
1105
|
const viewPosition = conversionApi.mapper.toViewPosition( data.range.start );
|
|
824
1106
|
|
|
825
1107
|
conversionApi.mapper.bindElements( data.item, viewElement );
|
|
826
1108
|
conversionApi.writer.insert( viewPosition, viewElement );
|
|
1109
|
+
|
|
1110
|
+
// Convert attributes before converting children.
|
|
1111
|
+
conversionApi.convertAttributes( data.item );
|
|
1112
|
+
|
|
1113
|
+
// Fill view slots with previous view elements or create new ones.
|
|
1114
|
+
fillSlots( viewElement, slotsMap, conversionApi, { reconversion: data.reconversion } );
|
|
827
1115
|
};
|
|
828
1116
|
}
|
|
829
1117
|
|
|
@@ -1056,7 +1344,7 @@ function removeMarkerData( viewCreator ) {
|
|
|
1056
1344
|
};
|
|
1057
1345
|
}
|
|
1058
1346
|
|
|
1059
|
-
// Function factory that creates a converter which converts set/change/remove attribute changes from the model to the view.
|
|
1347
|
+
// Function factory that creates a converter which converts the set/change/remove attribute changes from the model to the view.
|
|
1060
1348
|
//
|
|
1061
1349
|
// Attributes from the model are converted to the view element attributes in the view. You may provide a custom function to generate
|
|
1062
1350
|
// a key-value attribute pair to add/change/remove. If not provided, model attributes will be converted to view element
|
|
@@ -1087,17 +1375,19 @@ function removeMarkerData( viewCreator ) {
|
|
|
1087
1375
|
// @returns {Function} Set/change attribute converter.
|
|
1088
1376
|
function changeAttribute( attributeCreator ) {
|
|
1089
1377
|
return ( evt, data, conversionApi ) => {
|
|
1090
|
-
|
|
1091
|
-
const newAttribute = attributeCreator( data.attributeNewValue, conversionApi );
|
|
1092
|
-
|
|
1093
|
-
if ( !oldAttribute && !newAttribute ) {
|
|
1378
|
+
if ( !conversionApi.consumable.test( data.item, evt.name ) ) {
|
|
1094
1379
|
return;
|
|
1095
1380
|
}
|
|
1096
1381
|
|
|
1097
|
-
|
|
1382
|
+
const oldAttribute = attributeCreator( data.attributeOldValue, conversionApi, data );
|
|
1383
|
+
const newAttribute = attributeCreator( data.attributeNewValue, conversionApi, data );
|
|
1384
|
+
|
|
1385
|
+
if ( !oldAttribute && !newAttribute ) {
|
|
1098
1386
|
return;
|
|
1099
1387
|
}
|
|
1100
1388
|
|
|
1389
|
+
conversionApi.consumable.consume( data.item, evt.name );
|
|
1390
|
+
|
|
1101
1391
|
const viewElement = conversionApi.mapper.toViewElement( data.item );
|
|
1102
1392
|
const viewWriter = conversionApi.writer;
|
|
1103
1393
|
|
|
@@ -1106,7 +1396,7 @@ function changeAttribute( attributeCreator ) {
|
|
|
1106
1396
|
if ( !viewElement ) {
|
|
1107
1397
|
/**
|
|
1108
1398
|
* This error occurs when a {@link module:engine/model/textproxy~TextProxy text node's} attribute is to be downcasted
|
|
1109
|
-
* by {@link module:engine/conversion/conversion~Conversion#attributeToAttribute `Attribute to Attribute converter`}.
|
|
1399
|
+
* by an {@link module:engine/conversion/conversion~Conversion#attributeToAttribute `Attribute to Attribute converter`}.
|
|
1110
1400
|
* In most cases it is caused by converters misconfiguration when only "generic" converter is defined:
|
|
1111
1401
|
*
|
|
1112
1402
|
* editor.conversion.for( 'downcast' ).attributeToAttribute( {
|
|
@@ -1138,10 +1428,7 @@ function changeAttribute( attributeCreator ) {
|
|
|
1138
1428
|
*
|
|
1139
1429
|
* @error conversion-attribute-to-attribute-on-text
|
|
1140
1430
|
*/
|
|
1141
|
-
throw new CKEditorError(
|
|
1142
|
-
'conversion-attribute-to-attribute-on-text',
|
|
1143
|
-
[ data, conversionApi ]
|
|
1144
|
-
);
|
|
1431
|
+
throw new CKEditorError( 'conversion-attribute-to-attribute-on-text', conversionApi.dispatcher, data );
|
|
1145
1432
|
}
|
|
1146
1433
|
|
|
1147
1434
|
// First remove the old attribute if there was one.
|
|
@@ -1366,34 +1653,107 @@ function removeHighlight( highlightDescriptor ) {
|
|
|
1366
1653
|
// See {@link ~DowncastHelpers#elementToElement `.elementToElement()` downcast helper} for examples and config params description.
|
|
1367
1654
|
//
|
|
1368
1655
|
// @param {Object} config Conversion configuration.
|
|
1369
|
-
// @param {String} config.model
|
|
1370
|
-
// @param {
|
|
1371
|
-
// @param {
|
|
1372
|
-
// @param {
|
|
1373
|
-
//
|
|
1656
|
+
// @param {String|Object} config.model The description or a name of the model element to convert.
|
|
1657
|
+
// @param {String|Array.<String>} [config.model.attributes] List of attributes triggering element reconversion.
|
|
1658
|
+
// @param {Boolean} [config.model.children] Should reconvert element if the list of model child nodes changed.
|
|
1659
|
+
// @param {module:engine/view/elementdefinition~ElementDefinition|module:engine/conversion/downcasthelpers~ElementCreatorFunction}
|
|
1660
|
+
// config.view
|
|
1374
1661
|
// @returns {Function} Conversion helper.
|
|
1375
1662
|
function downcastElementToElement( config ) {
|
|
1376
1663
|
config = cloneDeep( config );
|
|
1377
1664
|
|
|
1665
|
+
config.model = normalizeModelElementConfig( config.model );
|
|
1378
1666
|
config.view = normalizeToElementConfig( config.view, 'container' );
|
|
1379
1667
|
|
|
1668
|
+
// Trigger reconversion on children list change if element is a subject to any reconversion.
|
|
1669
|
+
// This is required to be able to trigger Differ#refreshItem() on a direct child of the reconverted element.
|
|
1670
|
+
if ( config.model.attributes.length ) {
|
|
1671
|
+
config.model.children = true;
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1380
1674
|
return dispatcher => {
|
|
1381
|
-
dispatcher.on(
|
|
1675
|
+
dispatcher.on(
|
|
1676
|
+
'insert:' + config.model.name,
|
|
1677
|
+
insertElement( config.view, createConsumer( config.model ) ),
|
|
1678
|
+
{ priority: config.converterPriority || 'normal' }
|
|
1679
|
+
);
|
|
1680
|
+
|
|
1681
|
+
if ( config.model.children || config.model.attributes.length ) {
|
|
1682
|
+
dispatcher.on( 'reduceChanges', createChangeReducer( config.model ), { priority: 'low' } );
|
|
1683
|
+
}
|
|
1684
|
+
};
|
|
1685
|
+
}
|
|
1382
1686
|
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1687
|
+
// Model element to view structure conversion helper.
|
|
1688
|
+
//
|
|
1689
|
+
// See {@link ~DowncastHelpers#elementToStructure `.elementToStructure()` downcast helper} for examples and config params description.
|
|
1690
|
+
//
|
|
1691
|
+
// @param {Object} config Conversion configuration.
|
|
1692
|
+
// @param {String|Object} config.model
|
|
1693
|
+
// @param {String} [config.model.name]
|
|
1694
|
+
// @param {Array.<String>} [config.model.attributes]
|
|
1695
|
+
// @param {module:engine/conversion/downcasthelpers~StructureCreatorFunction} config.view
|
|
1696
|
+
// @returns {Function} Conversion helper.
|
|
1697
|
+
function downcastElementToStructure( config ) {
|
|
1698
|
+
config = cloneDeep( config );
|
|
1389
1699
|
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1700
|
+
config.model = normalizeModelElementConfig( config.model );
|
|
1701
|
+
config.view = normalizeToElementConfig( config.view, 'container' );
|
|
1702
|
+
|
|
1703
|
+
// Trigger reconversion on children list change because it always needs to use slots to put children in proper places.
|
|
1704
|
+
// This is required to be able to trigger Differ#refreshItem() on a direct child of the reconverted element.
|
|
1705
|
+
config.model.children = true;
|
|
1706
|
+
|
|
1707
|
+
return dispatcher => {
|
|
1708
|
+
if ( dispatcher._conversionApi.schema.checkChild( config.model.name, '$text' ) ) {
|
|
1709
|
+
/**
|
|
1710
|
+
* This error occurs when a {@link module:engine/model/element~Element model element} is downcasted
|
|
1711
|
+
* via {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToStructure} helper but the element was
|
|
1712
|
+
* allowed to host `$text` by the {@link module:engine/model/schema~Schema model schema}.
|
|
1713
|
+
*
|
|
1714
|
+
* For instance, this may be the result of `myElement` allowing the content of
|
|
1715
|
+
* {@glink framework/guides/deep-dive/schema#generic-items `$block`} in its schema definition:
|
|
1716
|
+
*
|
|
1717
|
+
* // Element definition in schema.
|
|
1718
|
+
* schema.register( 'myElement', {
|
|
1719
|
+
* allowContentOf: '$block',
|
|
1720
|
+
*
|
|
1721
|
+
* // ...
|
|
1722
|
+
* } );
|
|
1723
|
+
*
|
|
1724
|
+
* // ...
|
|
1725
|
+
*
|
|
1726
|
+
* // Conversion of myElement with the use of elementToStructure().
|
|
1727
|
+
* editor.conversion.for( 'downcast' ).elementToStructure( {
|
|
1728
|
+
* model: 'myElement',
|
|
1729
|
+
* view: ( modelElement, { writer } ) => {
|
|
1730
|
+
* // ...
|
|
1731
|
+
* }
|
|
1732
|
+
* } );
|
|
1733
|
+
*
|
|
1734
|
+
* In such case, {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`} helper
|
|
1735
|
+
* can be used instead to get around this problem:
|
|
1736
|
+
*
|
|
1737
|
+
* editor.conversion.for( 'downcast' ).elementToElement( {
|
|
1738
|
+
* model: 'myElement',
|
|
1739
|
+
* view: ( modelElement, { writer } ) => {
|
|
1740
|
+
* // ...
|
|
1741
|
+
* }
|
|
1742
|
+
* } );
|
|
1743
|
+
*
|
|
1744
|
+
* @error conversion-element-to-structure-disallowed-text
|
|
1745
|
+
* @param {String} elementName The name of the element the structure is to be created for.
|
|
1746
|
+
*/
|
|
1747
|
+
throw new CKEditorError( 'conversion-element-to-structure-disallowed-text', dispatcher, { elementName: config.model.name } );
|
|
1396
1748
|
}
|
|
1749
|
+
|
|
1750
|
+
dispatcher.on(
|
|
1751
|
+
'insert:' + config.model.name,
|
|
1752
|
+
insertStructure( config.view, createConsumer( config.model ) ),
|
|
1753
|
+
{ priority: config.converterPriority || 'normal' }
|
|
1754
|
+
);
|
|
1755
|
+
|
|
1756
|
+
dispatcher.on( 'reduceChanges', createChangeReducer( config.model ), { priority: 'low' } );
|
|
1397
1757
|
};
|
|
1398
1758
|
}
|
|
1399
1759
|
|
|
@@ -1404,10 +1764,11 @@ function downcastElementToElement( config ) {
|
|
|
1404
1764
|
// @param {Object} config Conversion configuration.
|
|
1405
1765
|
// @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values }` object. `values` is an array
|
|
1406
1766
|
// of `String`s with possible values if the model attribute is an enumerable.
|
|
1407
|
-
// @param {module:engine/view/elementdefinition~ElementDefinition|
|
|
1408
|
-
// that takes the model attribute value and
|
|
1409
|
-
// as parameters and returns a view attribute element.
|
|
1410
|
-
// 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.
|
|
1411
1772
|
// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.
|
|
1412
1773
|
// @returns {Function} Conversion helper.
|
|
1413
1774
|
function downcastAttributeToElement( config ) {
|
|
@@ -1442,9 +1803,10 @@ function downcastAttributeToElement( config ) {
|
|
|
1442
1803
|
// @param {Object} config Conversion configuration.
|
|
1443
1804
|
// @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values, [ name ] }` object describing
|
|
1444
1805
|
// the attribute key, possible values and, optionally, an element name to convert from.
|
|
1445
|
-
// @param {String|Object|
|
|
1446
|
-
//
|
|
1447
|
-
// 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`.
|
|
1448
1810
|
// If `config.model.values` is set, `config.view` should be an object assigning values from `config.model.values` to
|
|
1449
1811
|
// `{ key, value }` objects or a functions.
|
|
1450
1812
|
// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.
|
|
@@ -1541,6 +1903,31 @@ function downcastMarkerToHighlight( config ) {
|
|
|
1541
1903
|
};
|
|
1542
1904
|
}
|
|
1543
1905
|
|
|
1906
|
+
// Takes `config.model`, and converts it to an object with normalized structure.
|
|
1907
|
+
//
|
|
1908
|
+
// @param {String|Object} model Model configuration or element name.
|
|
1909
|
+
// @param {String} model.name
|
|
1910
|
+
// @param {Array.<String>} [model.attributes]
|
|
1911
|
+
// @param {Boolean} [model.children]
|
|
1912
|
+
// @returns {Object}
|
|
1913
|
+
function normalizeModelElementConfig( model ) {
|
|
1914
|
+
if ( typeof model == 'string' ) {
|
|
1915
|
+
model = { name: model };
|
|
1916
|
+
}
|
|
1917
|
+
|
|
1918
|
+
// List of attributes that should trigger reconversion.
|
|
1919
|
+
if ( !model.attributes ) {
|
|
1920
|
+
model.attributes = [];
|
|
1921
|
+
} else if ( !Array.isArray( model.attributes ) ) {
|
|
1922
|
+
model.attributes = [ model.attributes ];
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
// Whether a children insertion/deletion should trigger reconversion.
|
|
1926
|
+
model.children = !!model.children;
|
|
1927
|
+
|
|
1928
|
+
return model;
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1544
1931
|
// Takes `config.view`, and if it is an {@link module:engine/view/elementdefinition~ElementDefinition}, converts it
|
|
1545
1932
|
// to a function (because lower level converters accept only element creator functions).
|
|
1546
1933
|
//
|
|
@@ -1670,6 +2057,291 @@ function prepareDescriptor( highlightDescriptor, data, conversionApi ) {
|
|
|
1670
2057
|
return descriptor;
|
|
1671
2058
|
}
|
|
1672
2059
|
|
|
2060
|
+
// Creates a function that checks a single differ diff item whether it should trigger reconversion.
|
|
2061
|
+
//
|
|
2062
|
+
// @param {Object} model A normalized `config.model` converter configuration.
|
|
2063
|
+
// @param {String} model.name The name of element.
|
|
2064
|
+
// @param {Array.<String>} model.attributes The list of attribute names that should trigger reconversion.
|
|
2065
|
+
// @param {Boolean} [model.children] Whether the child list change should trigger reconversion.
|
|
2066
|
+
// @returns {Function}
|
|
2067
|
+
function createChangeReducerCallback( model ) {
|
|
2068
|
+
return ( node, change ) => {
|
|
2069
|
+
if ( !node.is( 'element', model.name ) ) {
|
|
2070
|
+
return false;
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
if ( change.type == 'attribute' ) {
|
|
2074
|
+
if ( model.attributes.includes( change.attributeKey ) ) {
|
|
2075
|
+
return true;
|
|
2076
|
+
}
|
|
2077
|
+
} else {
|
|
2078
|
+
/* istanbul ignore else: This is always true because otherwise it would not register a reducer callback. */
|
|
2079
|
+
if ( model.children ) {
|
|
2080
|
+
return true;
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
return false;
|
|
2085
|
+
};
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
// Creates a `reduceChanges` event handler for reconversion.
|
|
2089
|
+
//
|
|
2090
|
+
// @param {Object} model A normalized `config.model` converter configuration.
|
|
2091
|
+
// @param {String} model.name The name of element.
|
|
2092
|
+
// @param {Array.<String>} model.attributes The list of attribute names that should trigger reconversion.
|
|
2093
|
+
// @param {Boolean} [model.children] Whether the child list change should trigger reconversion.
|
|
2094
|
+
// @returns {Function}
|
|
2095
|
+
function createChangeReducer( model ) {
|
|
2096
|
+
const shouldReplace = createChangeReducerCallback( model );
|
|
2097
|
+
|
|
2098
|
+
return ( evt, data ) => {
|
|
2099
|
+
const reducedChanges = [];
|
|
2100
|
+
|
|
2101
|
+
if ( !data.reconvertedElements ) {
|
|
2102
|
+
data.reconvertedElements = new Set();
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
for ( const change of data.changes ) {
|
|
2106
|
+
// For attribute use node affected by the change.
|
|
2107
|
+
// For insert or remove use parent element because we need to check if it's added/removed child.
|
|
2108
|
+
const node = change.position ? change.position.parent : change.range.start.nodeAfter;
|
|
2109
|
+
|
|
2110
|
+
if ( !node || !shouldReplace( node, change ) ) {
|
|
2111
|
+
reducedChanges.push( change );
|
|
2112
|
+
|
|
2113
|
+
continue;
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
// If it's already marked for reconversion, so skip this change, otherwise add the diff items.
|
|
2117
|
+
if ( !data.reconvertedElements.has( node ) ) {
|
|
2118
|
+
data.reconvertedElements.add( node );
|
|
2119
|
+
|
|
2120
|
+
const position = ModelPosition._createBefore( node );
|
|
2121
|
+
|
|
2122
|
+
reducedChanges.push( {
|
|
2123
|
+
type: 'remove',
|
|
2124
|
+
name: node.name,
|
|
2125
|
+
position,
|
|
2126
|
+
length: 1
|
|
2127
|
+
}, {
|
|
2128
|
+
type: 'reinsert',
|
|
2129
|
+
name: node.name,
|
|
2130
|
+
position,
|
|
2131
|
+
length: 1
|
|
2132
|
+
} );
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
2135
|
+
|
|
2136
|
+
data.changes = reducedChanges;
|
|
2137
|
+
};
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
// Creates a function that checks if an element and its watched attributes can be consumed and consumes them.
|
|
2141
|
+
//
|
|
2142
|
+
// @param {Object} model A normalized `config.model` converter configuration.
|
|
2143
|
+
// @param {String} model.name The name of element.
|
|
2144
|
+
// @param {Array.<String>} model.attributes The list of attribute names that should trigger reconversion.
|
|
2145
|
+
// @param {Boolean} [model.children] Whether the child list change should trigger reconversion.
|
|
2146
|
+
// @returns {module:engine/conversion/downcasthelpers~ConsumerFunction}
|
|
2147
|
+
function createConsumer( model ) {
|
|
2148
|
+
return ( node, consumable, options = {} ) => {
|
|
2149
|
+
const events = [ 'insert' ];
|
|
2150
|
+
|
|
2151
|
+
// Collect all set attributes that are triggering conversion.
|
|
2152
|
+
for ( const attributeName of model.attributes ) {
|
|
2153
|
+
if ( node.hasAttribute( attributeName ) ) {
|
|
2154
|
+
events.push( `attribute:${ attributeName }` );
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
if ( !events.every( event => consumable.test( node, event ) ) ) {
|
|
2159
|
+
return false;
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2162
|
+
if ( !options.preflight ) {
|
|
2163
|
+
events.forEach( event => consumable.consume( node, event ) );
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
return true;
|
|
2167
|
+
};
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
// Creates a function that create view slots.
|
|
2171
|
+
//
|
|
2172
|
+
// @param {module:engine/model/element~Element} element
|
|
2173
|
+
// @param {Map.<module:engine/view/element~Element,Array.<module:engine/model/node~Node>>} slotsMap
|
|
2174
|
+
// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi
|
|
2175
|
+
// @returns {Function} Exposed by writer as createSlot().
|
|
2176
|
+
function createSlotFactory( element, slotsMap, conversionApi ) {
|
|
2177
|
+
return ( writer, modeOrFilter = 'children' ) => {
|
|
2178
|
+
const slot = writer.createContainerElement( '$slot' );
|
|
2179
|
+
|
|
2180
|
+
let children = null;
|
|
2181
|
+
|
|
2182
|
+
if ( modeOrFilter === 'children' ) {
|
|
2183
|
+
children = Array.from( element.getChildren() );
|
|
2184
|
+
} else if ( typeof modeOrFilter == 'function' ) {
|
|
2185
|
+
children = Array.from( element.getChildren() ).filter( element => modeOrFilter( element ) );
|
|
2186
|
+
} else {
|
|
2187
|
+
/**
|
|
2188
|
+
* Unknown slot mode was provided to `writer.createSlot()` in downcast converter.
|
|
2189
|
+
*
|
|
2190
|
+
* @error conversion-slot-mode-unknown
|
|
2191
|
+
*/
|
|
2192
|
+
throw new CKEditorError( 'conversion-slot-mode-unknown', conversionApi.dispatcher, { modeOrFilter } );
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
slotsMap.set( slot, children );
|
|
2196
|
+
|
|
2197
|
+
return slot;
|
|
2198
|
+
};
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
// Checks if all children are covered by slots and there is no child that landed in multiple slots.
|
|
2202
|
+
//
|
|
2203
|
+
// @param {module:engine/model/element~Element}
|
|
2204
|
+
// @param {Map.<module:engine/view/element~Element,Array.<module:engine/model/node~Node>>} slotsMap
|
|
2205
|
+
// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi
|
|
2206
|
+
function validateSlotsChildren( element, slotsMap, conversionApi ) {
|
|
2207
|
+
const childrenInSlots = Array.from( slotsMap.values() ).flat();
|
|
2208
|
+
const uniqueChildrenInSlots = new Set( childrenInSlots );
|
|
2209
|
+
|
|
2210
|
+
if ( uniqueChildrenInSlots.size != childrenInSlots.length ) {
|
|
2211
|
+
/**
|
|
2212
|
+
* Filters provided to `writer.createSlot()` overlap (at least two filters accept the same child element).
|
|
2213
|
+
*
|
|
2214
|
+
* @error conversion-slot-filter-overlap
|
|
2215
|
+
* @param {module:engine/model/element~Element} element The element of which children would not be properly
|
|
2216
|
+
* allocated to multiple slots.
|
|
2217
|
+
*/
|
|
2218
|
+
throw new CKEditorError( 'conversion-slot-filter-overlap', conversionApi.dispatcher, { element } );
|
|
2219
|
+
}
|
|
2220
|
+
|
|
2221
|
+
if ( uniqueChildrenInSlots.size != element.childCount ) {
|
|
2222
|
+
/**
|
|
2223
|
+
* Filters provided to `writer.createSlot()` are incomplete and exclude at least one children element (one of
|
|
2224
|
+
* the children elements would not be assigned to any of the slots).
|
|
2225
|
+
*
|
|
2226
|
+
* @error conversion-slot-filter-incomplete
|
|
2227
|
+
* @param {module:engine/model/element~Element} element The element of which children would not be properly
|
|
2228
|
+
* allocated to multiple slots.
|
|
2229
|
+
*/
|
|
2230
|
+
throw new CKEditorError( 'conversion-slot-filter-incomplete', conversionApi.dispatcher, { element } );
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
|
|
2234
|
+
// Fill slots with appropriate view elements.
|
|
2235
|
+
//
|
|
2236
|
+
// @param {module:engine/view/element~Element} viewElement
|
|
2237
|
+
// @param {Map.<module:engine/view/element~Element,Array.<module:engine/model/node~Node>>} slotsMap
|
|
2238
|
+
// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi
|
|
2239
|
+
// @param {Object} options
|
|
2240
|
+
// @param {Boolean} [options.reconversion]
|
|
2241
|
+
function fillSlots( viewElement, slotsMap, conversionApi, options ) {
|
|
2242
|
+
// Set temporary position mapping to redirect child view elements into a proper slots.
|
|
2243
|
+
conversionApi.mapper.on( 'modelToViewPosition', toViewPositionMapping, { priority: 'highest' } );
|
|
2244
|
+
|
|
2245
|
+
let currentSlot = null;
|
|
2246
|
+
let currentSlotNodes = null;
|
|
2247
|
+
|
|
2248
|
+
// Fill slots with nested view nodes.
|
|
2249
|
+
for ( [ currentSlot, currentSlotNodes ] of slotsMap ) {
|
|
2250
|
+
reinsertOrConvertNodes( viewElement, currentSlotNodes, conversionApi, options );
|
|
2251
|
+
|
|
2252
|
+
conversionApi.writer.move(
|
|
2253
|
+
conversionApi.writer.createRangeIn( currentSlot ),
|
|
2254
|
+
conversionApi.writer.createPositionBefore( currentSlot )
|
|
2255
|
+
);
|
|
2256
|
+
conversionApi.writer.remove( currentSlot );
|
|
2257
|
+
}
|
|
2258
|
+
|
|
2259
|
+
conversionApi.mapper.off( 'modelToViewPosition', toViewPositionMapping );
|
|
2260
|
+
|
|
2261
|
+
function toViewPositionMapping( evt, data ) {
|
|
2262
|
+
const element = data.modelPosition.nodeAfter;
|
|
2263
|
+
|
|
2264
|
+
// Find the proper offset within the slot.
|
|
2265
|
+
const index = currentSlotNodes.indexOf( element );
|
|
2266
|
+
|
|
2267
|
+
if ( index < 0 ) {
|
|
2268
|
+
return;
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2271
|
+
data.viewPosition = data.mapper.findPositionIn( currentSlot, index );
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2275
|
+
// Inserts view representation of `nodes` into the `viewElement` either by bringing back just removed view nodes
|
|
2276
|
+
// or by triggering conversion for them.
|
|
2277
|
+
//
|
|
2278
|
+
// @param {module:engine/view/element~Element} viewElement
|
|
2279
|
+
// @param {Iterable.<module:engine/model/element~Element>} modelNodes
|
|
2280
|
+
// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi
|
|
2281
|
+
// @param {Object} options
|
|
2282
|
+
// @param {Boolean} [options.reconversion]
|
|
2283
|
+
function reinsertOrConvertNodes( viewElement, modelNodes, conversionApi, options ) {
|
|
2284
|
+
// Fill with nested view nodes.
|
|
2285
|
+
for ( const modelChildNode of modelNodes ) {
|
|
2286
|
+
// Try reinserting the view node for the specified model node...
|
|
2287
|
+
if ( !reinsertNode( viewElement.root, modelChildNode, conversionApi, options ) ) {
|
|
2288
|
+
// ...or else convert the model element to the view.
|
|
2289
|
+
conversionApi.convertItem( modelChildNode );
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
|
|
2294
|
+
// Checks if the view for the given model element could be reused and reinserts it to the view.
|
|
2295
|
+
//
|
|
2296
|
+
// @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} viewRoot
|
|
2297
|
+
// @param {module:engine/model/element~Element} modelElement
|
|
2298
|
+
// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi
|
|
2299
|
+
// @param {Object} options
|
|
2300
|
+
// @param {Boolean} [options.reconversion]
|
|
2301
|
+
// @returns {Boolean} `false` if view element can't be reused.
|
|
2302
|
+
function reinsertNode( viewRoot, modelElement, conversionApi, options ) {
|
|
2303
|
+
const { writer, mapper } = conversionApi;
|
|
2304
|
+
|
|
2305
|
+
// Don't reinsert if this is not a reconversion...
|
|
2306
|
+
if ( !options.reconversion ) {
|
|
2307
|
+
return false;
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
const viewChildNode = mapper.toViewElement( modelElement );
|
|
2311
|
+
|
|
2312
|
+
// ...or there is no view to reinsert or it was already inserted to the view structure...
|
|
2313
|
+
if ( !viewChildNode || viewChildNode.root == viewRoot ) {
|
|
2314
|
+
return false;
|
|
2315
|
+
}
|
|
2316
|
+
|
|
2317
|
+
// ...or it was strictly marked as not to be reused.
|
|
2318
|
+
if ( !conversionApi.canReuseView( viewChildNode ) ) {
|
|
2319
|
+
return false;
|
|
2320
|
+
}
|
|
2321
|
+
|
|
2322
|
+
// Otherwise reinsert the view node.
|
|
2323
|
+
writer.move(
|
|
2324
|
+
writer.createRangeOn( viewChildNode ),
|
|
2325
|
+
mapper.toViewPosition( ModelPosition._createBefore( modelElement ) )
|
|
2326
|
+
);
|
|
2327
|
+
|
|
2328
|
+
return true;
|
|
2329
|
+
}
|
|
2330
|
+
|
|
2331
|
+
// The default consumer for insert events.
|
|
2332
|
+
// @param {module:engine/model/item~Item} item Model item.
|
|
2333
|
+
// @param {module:engine/conversion/modelconsumable~ModelConsumable} consumable The model consumable.
|
|
2334
|
+
// @param {Object} [options]
|
|
2335
|
+
// @param {Boolean} [options.preflight=false] Whether should consume or just check if can be consumed.
|
|
2336
|
+
// @returns {Boolean}
|
|
2337
|
+
function defaultConsumer( item, consumable, { preflight } = {} ) {
|
|
2338
|
+
if ( preflight ) {
|
|
2339
|
+
return consumable.test( item, 'insert' );
|
|
2340
|
+
} else {
|
|
2341
|
+
return consumable.consume( item, 'insert' );
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2344
|
+
|
|
1673
2345
|
/**
|
|
1674
2346
|
* An object describing how the marker highlight should be represented in the view.
|
|
1675
2347
|
*
|
|
@@ -1704,3 +2376,110 @@ function prepareDescriptor( highlightDescriptor, data, conversionApi ) {
|
|
|
1704
2376
|
* attribute element. If the descriptor is applied to an element, usually these attributes will be set on that element, however,
|
|
1705
2377
|
* this depends on how the element converts the descriptor.
|
|
1706
2378
|
*/
|
|
2379
|
+
|
|
2380
|
+
/**
|
|
2381
|
+
* A filtering function used to choose model child nodes to be downcasted into the specific view
|
|
2382
|
+
* {@link module:engine/view/downcastwriter~DowncastWriter#createSlot "slot"} while executing the
|
|
2383
|
+
* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToStructure `elementToStructure()`} converter.
|
|
2384
|
+
*
|
|
2385
|
+
* @callback module:engine/conversion/downcasthelpers~SlotFilter
|
|
2386
|
+
*
|
|
2387
|
+
* @param {module:engine/model/node~Node} node A model node.
|
|
2388
|
+
* @returns {Boolean} Whether the provided model node should be downcasted into this slot.
|
|
2389
|
+
*
|
|
2390
|
+
* @see module:engine/view/downcastwriter~DowncastWriter#createSlot
|
|
2391
|
+
* @see module:engine/conversion/downcasthelpers~DowncastHelpers#elementToStructure
|
|
2392
|
+
* @see module:engine/conversion/downcasthelpers~insertStructure
|
|
2393
|
+
*/
|
|
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
|
+
|
|
2412
|
+
/**
|
|
2413
|
+
* A function that takes the model element and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast
|
|
2414
|
+
* conversion API} as parameters and returns a view container element with slots for model child nodes to be converted into.
|
|
2415
|
+
*
|
|
2416
|
+
* @callback module:engine/conversion/downcasthelpers~StructureCreatorFunction
|
|
2417
|
+
* @param {module:engine/model/element~Element} element The model element to be converted to the view structure.
|
|
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.
|
|
2423
|
+
* @returns {module:engine/view/element~Element} The view structure with slots for model child nodes.
|
|
2424
|
+
*
|
|
2425
|
+
* @see module:engine/conversion/downcasthelpers~DowncastHelpers#elementToStructure
|
|
2426
|
+
* @see module:engine/conversion/downcasthelpers~insertStructure
|
|
2427
|
+
*/
|
|
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
|
+
|
|
2473
|
+
/**
|
|
2474
|
+
* A function that is expected to consume all the consumables that were used by the element creator.
|
|
2475
|
+
*
|
|
2476
|
+
* @callback module:engine/conversion/downcasthelpers~ConsumerFunction
|
|
2477
|
+
* @param {module:engine/model/element~Element} element The model element to be converted to the view structure.
|
|
2478
|
+
* @param {module:engine/conversion/modelconsumable~ModelConsumable} consumable The `ModelConsumable` same as in
|
|
2479
|
+
* {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi#consumable `DowncastConversionApi.consumable`}.
|
|
2480
|
+
* @param {Object} [options]
|
|
2481
|
+
* @param {Boolean} [options.preflight=false] Whether should consume or just check if can be consumed.
|
|
2482
|
+
* @returns {Boolean} `true` if all consumable values were available and were consumed, `false` otherwise.
|
|
2483
|
+
*
|
|
2484
|
+
* @see module:engine/conversion/downcasthelpers~insertStructure
|
|
2485
|
+
*/
|