@@ -152,8 +152,7 @@ class ModelConverterBuilder {
152152 }
153153
154154 /**
155- * Registers what type of non-collapsed marker should be converted. For collapsed markers conversion, see
156- * {@link #fromCollapsedMarker}.
155+ * Registers what type of marker should be converted.
157156 *
158157 * @chainable
159158 * @param {String } markerName Name of marker to convert.
@@ -163,27 +162,7 @@ class ModelConverterBuilder {
163162 this . _from = {
164163 type : 'marker' ,
165164 name : markerName ,
166- priority : null ,
167- collapsed : false
168- } ;
169-
170- return this ;
171- }
172-
173- /**
174- * Registers what type of collapsed marker should be converted. For non-collapsed markers conversion,
175- * see {@link #fromMarker}.
176- *
177- * @chainable
178- * @param {String } markerName Name of marker to convert.
179- * @returns {module:engine/conversion/buildmodelconverter~ModelConverterBuilder }
180- */
181- fromCollapsedMarker ( markerName ) {
182- this . _from = {
183- type : 'marker' ,
184- name : markerName ,
185- priority : null ,
186- collapsed : true
165+ priority : null
187166 } ;
188167
189168 return this ;
@@ -265,22 +244,76 @@ class ModelConverterBuilder {
265244
266245 dispatcher . on ( 'selectionAttribute:' + this . _from . key , convertSelectionAttribute ( element ) , { priority } ) ;
267246 } else {
268- if ( this . _from . collapsed ) {
269- // From collapsed marker to view element -> insertUIElement, removeUIElement.
270- element = typeof element == 'string' ? new ViewUIElement ( element ) : element ;
247+ element = typeof element == 'string' ? new ViewAttributeElement ( element ) : element ;
271248
272- dispatcher . on ( 'addMarker:' + this . _from . name , insertUIElement ( element ) , { priority } ) ;
273- dispatcher . on ( 'removeMarker:' + this . _from . name , removeUIElement ( element ) , { priority } ) ;
274- } else {
275- // From non-collapsed marker to view element -> wrapRange and unwrapRange.
276- element = typeof element == 'string' ? new ViewAttributeElement ( element ) : element ;
249+ dispatcher . on ( 'addMarker:' + this . _from . name , wrapRange ( element ) , { priority } ) ;
250+ dispatcher . on ( 'removeMarker:' + this . _from . name , unwrapRange ( element ) , { priority } ) ;
277251
278- dispatcher . on ( 'addMarker:' + this . _from . name , wrapRange ( element ) , { priority } ) ;
279- dispatcher . on ( 'removeMarker:' + this . _from . name , unwrapRange ( element ) , { priority } ) ;
252+ dispatcher . on ( 'selectionMarker:' + this . _from . name , convertSelectionMarker ( element ) , { priority } ) ;
253+ }
254+ }
255+ }
280256
281- dispatcher . on ( 'selectionMarker:' + this . _from . name , convertSelectionMarker ( element ) , { priority } ) ;
282- }
257+ /**
258+ * Registers what view stamp will be created by converter to mark marker range bounds. Separate elements will be
259+ * created at the beginning and at the end of the range. If range is collapsed then only one element will be created.
260+ *
261+ * Method accepts various ways of providing how the view element will be created. You can pass view element name as
262+ * `string`, view element instance which will be cloned and used, or creator function which returns view element that
263+ * will be used. Keep in mind that when you provide view element instance or creator function, it has to be/return a
264+ * proper type of view element: {@link module:engine/view/uielement~UIElement UIElement}.
265+ *
266+ * buildModelConverter().for( dispatcher ).fromMarker( 'search' ).toStamp( 'span' );
267+ *
268+ * buildModelConverter().for( dispatcher )
269+ * .fromMarker( 'search' )
270+ * .toStamp( new UIElement( 'span', { 'data-name': 'search' } ) );
271+ *
272+ * buildModelConverter().for( dispatcher )
273+ * .fromMarker( 'search' )
274+ * .toStamp( ( data ) => new UIElement( 'span', { 'data-name': data.marker.getName() ) );
275+ *
276+ * Creator function provides additional `data.isOpening` parameter which defined if currently converted element is
277+ * a beginning or end of the marker range. This makes possible to create different opening and closing stamp.
278+ *
279+ * buildModelConverter().for( dispatcher )
280+ * .fromMarker( 'search' )
281+ * .toStamp( ( data ) => {
282+ * if ( data.isOpening ) {
283+ * return new UIElement( 'span', { 'data-name': data.marker.getName(), 'data-start': true ) );
284+ * }
285+ *
286+ * return new UIElement( 'span', { 'data-name': data.marker.getName(), 'data-end': true ) );
287+ * }
288+ *
289+ * Creator function provides
290+ * {@link module:engine/conversion/buildmodelconverter~ModelConverterBuilder#StampCreatorData} parameters.
291+ *
292+ * See how markers {module:engine/model/buildviewconverter~ViewConverterBuilder#toMarker view -> model serialization}
293+ * works to find out what view element format is the best for you.
294+ *
295+ * @param {String|module:engine/view/element~UIElement|Function } element UIElement created by converter or
296+ * a function that returns view element.
297+ */
298+ toStamp ( element ) {
299+ for ( let dispatcher of this . _dispatchers ) {
300+ if ( this . _from . type != 'marker' ) {
301+ /**
302+ * To-stamp conversion is supported only for model markers.
303+ *
304+ * @error build-model-converter-element-to-stamp
305+ */
306+ throw new CKEditorError (
307+ 'build-model-converter-non-marker-to-stamp: To-stamp conversion is supported only from model markers.'
308+ ) ;
283309 }
310+
311+ const priority = this . _from . priority === null ? 'normal' : this . _from . priority ;
312+
313+ element = typeof element == 'string' ? new ViewUIElement ( element ) : element ;
314+
315+ dispatcher . on ( 'addMarker:' + this . _from . name , insertUIElement ( element ) , { priority } ) ;
316+ dispatcher . on ( 'removeMarker:' + this . _from . name , removeUIElement ( element ) , { priority } ) ;
284317 }
285318 }
286319
@@ -321,7 +354,6 @@ class ModelConverterBuilder {
321354 * To-attribute conversion is supported only for model attributes.
322355 *
323356 * @error build-model-converter-element-to-attribute
324- * @param {module:engine/model/range~Range } range
325357 */
326358 throw new CKEditorError ( 'build-model-converter-non-attribute-to-attribute: ' +
327359 'To-attribute conversion is supported only from model attributes.' ) ;
@@ -370,3 +402,13 @@ class ModelConverterBuilder {
370402export default function buildModelConverter ( ) {
371403 return new ModelConverterBuilder ( ) ;
372404}
405+
406+ /**
407+ * @typedef {StampCreatorData } {module:engine/conversion/buildmodelconverter~ModelConverterBuilder#StampCreatorData }
408+ * @param {Object } data Additional information about the change.
409+ * @param {String } data.name Marker name.
410+ * @param {module:engine/model/range~Range } data.range Marker range.
411+ * @param {Boolean } data.isOpening Defines if currently converted element is a beginning or end of the marker range.
412+ * @param {module:engine/conversion/modelconsumable~ModelConsumable } consumable Values to consume.
413+ * @param {Object } conversionApi Conversion interface to be used by callback, passed in `ModelConversionDispatcher` constructor.
414+ */
0 commit comments