Sign up (with export icon)

Mapper

Api-class icon class

Maps elements, positions and markers between the view and the model.

The instance of the Mapper used for the editing pipeline is available in editor.editing.mapper.

Mapper uses bound elements to find corresponding elements and positions, so, to get proper results, all model elements should be bound.

To map the complex model to/from view relations, you may provide custom callbacks for the modelToViewPosition event and viewToModelPosition event that are fired whenever a position mapping request occurs. Those events are fired by the toViewPosition and toModelPosition methods. Mapper adds its own default callbacks with 'lowest' priority. To override default Mapper mapping, add custom callback with higher priority and stop the event.

Properties

Methods

  • Creates an instance of the mapper.

  • Chevron-right icon

    bindElementToMarker( element, name ) → void

    Binds the given marker name with the given view element. The element will be added to the current set of elements bound with the given marker name.

    Parameters

    element : ViewElement

    Element to bind.

    name : string

    Marker name.

    Returns

    void
  • Chevron-right icon

    bindElements( modelElement, viewElement ) → void

    Marks model and view elements as corresponding. Corresponding elements can be retrieved by using the toModelElement and toViewElement methods. The information that elements are bound is also used to translate positions.

    Parameters

    modelElement : ModelElement | ModelDocumentFragment

    Model element.

    viewElement : ViewElement | ViewDocumentFragment

    View element.

    Returns

    void
  • Chevron-right icon

    clearBindings() → void

    Removes all model to view and view to model bindings.

    Returns

    void
  • Chevron-right icon

    delegate( events ) → EmitterMixinDelegateChain
    inherited

    Delegates selected events to another Emitter. For instance:

    emitterA.delegate( 'eventX' ).to( emitterB );
    emitterA.delegate( 'eventX', 'eventY' ).to( emitterC );
    
    Copy code

    then eventX is delegated (fired by) emitterB and emitterC along with data:

    emitterA.fire( 'eventX', data );
    
    Copy code

    and eventY is delegated (fired by) emitterC along with data:

    emitterA.fire( 'eventY', data );
    
    Copy code

    Parameters

    events : Array<string>

    Event names that will be delegated to another emitter.

    Returns

    EmitterMixinDelegateChain
  • Chevron-right icon

    findMappedViewAncestor( viewPosition ) → ViewElement

    For the given viewPosition, finds and returns the closest ancestor of this position that has a mapping to the model.

    Parameters

    viewPosition : ViewPosition

    Position for which a mapped ancestor should be found.

    Returns

    ViewElement
  • Chevron-right icon

    findPositionIn( viewContainer, modelOffset ) → ViewPosition

    Finds the position in a view element or view document fragment node (or in its children) with the expected model offset.

    If the passed viewContainer is bound to model, Mapper will use caching mechanism to improve performance.

    Parameters

    viewContainer : ViewElement | ViewDocumentFragment

    Tree view element in which we are looking for the position.

    modelOffset : number

    Expected offset.

    Returns

    ViewPosition

    Found position.

  • Chevron-right icon

    fire( eventOrInfo, args ) → GetEventInfo<TEvent>[ 'return' ]
    inherited

    Fires an event, executing all callbacks registered for it.

    The first parameter passed to callbacks is an EventInfo object, followed by the optional args provided in the fire() method call.

    Type parameters

    TEvent : extends BaseEvent

    The type describing the event. See BaseEvent.

    Parameters

    eventOrInfo : GetNameOrEventInfo<TEvent>

    The name of the event or EventInfo object if event is delegated.

    args : TEvent[ 'args' ]

    Additional arguments to be passed to the callbacks.

    Returns

    GetEventInfo<TEvent>[ 'return' ]

    By default the method returns undefined. However, the return value can be changed by listeners through modification of the evt.return's property (the event info is the first param of every callback).

  • Chevron-right icon

    Unbinds all deferred binding removals of view elements that in the meantime were not re-attached to some root or document fragment.

    See: unbindViewElement().

    Returns

    void
  • Chevron-right icon

    flushUnboundMarkerNames() → Array<string>

    Returns all marker names of markers which have changed due to unbinding a view element (so it is assumed that the view element has been removed, moved or renamed) since the last flush. After returning, the marker names list is cleared.

    Returns

    Array<string>
  • Chevron-right icon

    getModelLength( viewNode ) → number

    Gets the length of the view element in the model.

    The length is calculated as follows:

    • if a length mapping callback is provided for the given viewNode, it is used to evaluate the model length (viewNode is used as first and only parameter passed to the callback),
    • length of a text node is equal to the length of its data,
    • length of a ui element is equal to 0,
    • length of a mapped element is equal to 1,
    • length of a non-mapped element is equal to the length of its children.

    Examples:

    foo                          -> 3 // Text length is equal to its data length.
    <p>foo</p>                   -> 1 // Length of an element which is mapped is by default equal to 1.
    <b>foo</b>                   -> 3 // Length of an element which is not mapped is a length of its children.
    <div><p>x</p><p>y</p></div>  -> 2 // Assuming that <div> is not mapped and <p> are mapped.
    
    Copy code

    Parameters

    viewNode : ViewNode | ViewDocumentFragment

    View node.

    Returns

    number

    Length of the node in the tree model.

  • Chevron-right icon

    listenTo( emitter, event, callback, [ options ] ) → void
    inherited

    Registers a callback function to be executed when an event is fired in a specific (emitter) object.

    Events can be grouped in namespaces using :. When namespaced event is fired, it additionally fires all callbacks for that namespace.

    // myEmitter.on( ... ) is a shorthand for myEmitter.listenTo( myEmitter, ... ).
    myEmitter.on( 'myGroup', genericCallback );
    myEmitter.on( 'myGroup:myEvent', specificCallback );
    
    // genericCallback is fired.
    myEmitter.fire( 'myGroup' );
    // both genericCallback and specificCallback are fired.
    myEmitter.fire( 'myGroup:myEvent' );
    // genericCallback is fired even though there are no callbacks for "foo".
    myEmitter.fire( 'myGroup:foo' );
    
    Copy code

    An event callback can stop the event and set the return value of the fire method.

    Type parameters

    TEvent : extends BaseEvent

    The type describing the event. See BaseEvent.

    Parameters

    emitter : Emitter

    The object that fires the event.

    event : TEvent[ 'name' ]

    The name of the event.

    callback : GetCallback<TEvent>

    The function to be called on event.

    [ options ] : GetCallbackOptions<TEvent>

    Additional options.

    Returns

    void
  • Chevron-right icon

    markerNameToElements( name ) → null | Set<ViewElement>

    Gets all view elements bound to the given marker name.

    Parameters

    name : string

    Marker name.

    Returns

    null | Set<ViewElement>

    View elements bound with the given marker name or null if no elements are bound to the given marker name.

  • Chevron-right icon

    off( event, callback ) → void
    inherited

    Stops executing the callback on the given event. Shorthand for this.stopListening( this, event, callback ).

    Parameters

    event : string

    The name of the event.

    callback : Function

    The function to stop being called.

    Returns

    void
  • Chevron-right icon

    on( event, callback, [ options ] ) → void
    inherited

    Registers a callback function to be executed when an event is fired.

    Shorthand for this.listenTo( this, event, callback, options ) (it makes the emitter listen on itself).

    Type parameters

    TEvent : extends BaseEvent

    The type descibing the event. See BaseEvent.

    Parameters

    event : TEvent[ 'name' ]

    The name of the event.

    callback : GetCallback<TEvent>

    The function to be called on event.

    [ options ] : GetCallbackOptions<TEvent>

    Additional options.

    Returns

    void
  • Chevron-right icon

    once( event, callback, [ options ] ) → void
    inherited

    Registers a callback function to be executed on the next time the event is fired only. This is similar to calling on followed by off in the callback.

    Type parameters

    TEvent : extends BaseEvent

    The type descibing the event. See BaseEvent.

    Parameters

    event : TEvent[ 'name' ]

    The name of the event.

    callback : GetCallback<TEvent>

    The function to be called on event.

    [ options ] : GetCallbackOptions<TEvent>

    Additional options.

    Returns

    void
  • Chevron-right icon

    registerViewToModelLength( viewElementName, lengthCallback ) → void
    deprecated

    This method is deprecated and will be removed in one of the future CKEditor 5 releases.

    Using this method will turn off Mapper caching system and may degrade performance when operating on bigger documents.

    Registers a callback that evaluates the length in the model of a view element with the given name.

    The callback is fired with one argument, which is a view element instance. The callback is expected to return a number representing the length of the view element in the model.

    // List item in view may contain nested list, which have other list items. In model though,
    // the lists are represented by flat structure. Because of those differences, length of list view element
    // may be greater than one. In the callback it's checked how many nested list items are in evaluated list item.
    
    function getViewListItemLength( element ) {
    	let length = 1;
    
    	for ( let child of element.getChildren() ) {
    		if ( child.name == 'ul' || child.name == 'ol' ) {
    			for ( let item of child.getChildren() ) {
    				length += getViewListItemLength( item );
    			}
    		}
    	}
    
    	return length;
    }
    
    mapper.registerViewToModelLength( 'li', getViewListItemLength );
    
    Copy code

    Parameters

    viewElementName : string

    Name of view element for which callback is registered.

    lengthCallback : ( element: ViewElement ) => number

    Function return a length of view element instance in model.

    Returns

    void
  • Chevron-right icon

    stopDelegating( [ event ], [ emitter ] ) → void
    inherited

    Stops delegating events. It can be used at different levels:

    • To stop delegating all events.
    • To stop delegating a specific event to all emitters.
    • To stop delegating a specific event to a specific emitter.

    Parameters

    [ event ] : string

    The name of the event to stop delegating. If omitted, stops it all delegations.

    [ emitter ] : Emitter

    (requires event) The object to stop delegating a particular event to. If omitted, stops delegation of event to all emitters.

    Returns

    void
  • Chevron-right icon

    stopListening( [ emitter ], [ event ], [ callback ] ) → void
    inherited

    Stops listening for events. It can be used at different levels:

    • To stop listening to a specific callback.
    • To stop listening to a specific event.
    • To stop listening to all events fired by a specific object.
    • To stop listening to all events fired by all objects.

    Parameters

    [ emitter ] : Emitter

    The object to stop listening to. If omitted, stops it for all objects.

    [ event ] : string

    (Requires the emitter) The name of the event to stop listening to. If omitted, stops it for all events from emitter.

    [ callback ] : Function

    (Requires the event) The function to be removed from the call list for the given event.

    Returns

    void
  • Chevron-right icon

    toModelElement( viewDocumentFragment ) → undefined | ModelDocumentFragment

    Gets the corresponding model document fragment.

    Parameters

    viewDocumentFragment : ViewDocumentFragment

    View document fragment.

    Returns

    undefined | ModelDocumentFragment

    Corresponding model document fragment or undefined if not found.

  • Chevron-right icon

    toModelElement( viewElement ) → undefined | ModelElement

    Gets the corresponding model element.

    Note: ViewUIElement does not have corresponding element in model.

    Parameters

    viewElement : ViewElement

    View element.

    Returns

    undefined | ModelElement

    Corresponding model element or undefined if not found.

  • Chevron-right icon

    toModelPosition( viewPosition ) → ModelPosition

    Gets the corresponding model position.

    Parameters

    viewPosition : ViewPosition

    View position.

    Returns

    ModelPosition

    Corresponding model position.

    Fires

  • Chevron-right icon

    toModelRange( viewRange ) → ModelRange

    Gets the corresponding model range.

    Parameters

    viewRange : ViewRange

    View range.

    Returns

    ModelRange

    Corresponding model range.

  • Chevron-right icon

    toViewElement( modelDocumentFragment ) → undefined | ViewDocumentFragment

    Gets the corresponding view document fragment.

    Parameters

    modelDocumentFragment : ModelDocumentFragment

    Model document fragment.

    Returns

    undefined | ViewDocumentFragment

    Corresponding view document fragment or undefined if not found.

  • Chevron-right icon

    toViewElement( modelElement ) → undefined | ViewElement

    Gets the corresponding view element.

    Parameters

    modelElement : ModelElement

    Model element.

    Returns

    undefined | ViewElement

    Corresponding view element or undefined if not found.

  • Chevron-right icon

    toViewPosition( modelPosition, options = { [options.isPhantom] } ) → ViewPosition

    Gets the corresponding view position.

    Parameters

    modelPosition : ModelPosition

    Model position.

    options : object

    Additional options for position mapping process.

    Properties
    [ options.isPhantom ] : boolean

    Should be set to true if the model position to map is pointing to a place in model tree which no longer exists. For example, it could be an end of a removed model range.

    Defaults to {}

    Returns

    ViewPosition

    Corresponding view position.

    Fires

  • Chevron-right icon

    toViewRange( modelRange ) → ViewRange

    Gets the corresponding view range.

    Parameters

    modelRange : ModelRange

    Model range.

    Returns

    ViewRange

    Corresponding view range.

  • Chevron-right icon

    unbindElementFromMarkerName( element, name ) → void

    Unbinds an element from given marker name.

    Parameters

    element : ViewElement

    Element to unbind.

    name : string

    Marker name.

    Returns

    void
  • Chevron-right icon

    unbindModelElement( modelElement ) → void

    Unbinds the given model element from the map.

    Note: the model-to-view binding will be removed, if it existed. However, the corresponding view-to-model binding will be removed only if the view element is still bound to the passed modelElement.

    This behavior lets for re-binding view element to another model element without fear of losing the new binding when the previously bound model element is unbound.

    Parameters

    modelElement : ModelElement

    Model element to unbind.

    Returns

    void
  • Chevron-right icon

    unbindViewElement( viewElement, options = { [options.defer] } ) → void

    Unbinds the given view element from the map.

    Note: view-to-model binding will be removed, if it existed. However, corresponding model-to-view binding will be removed only if model element is still bound to the passed viewElement.

    This behavior allows for re-binding model element to another view element without fear of losing the new binding when the previously bound view element is unbound.

    Parameters

    viewElement : ViewElement

    View element to unbind.

    options : object

    The options object.

    Properties
    [ options.defer ] : boolean

    Controls whether the binding should be removed immediately or deferred until a flushDeferredBindings() call.

    Defaults to {}

    Returns

    void
  • Chevron-right icon

    _findPositionStartingFrom( startViewPosition, startModelOffset, targetModelOffset, viewContainer, useCache ) → ViewPosition
    Lock icon private

    Performs most of the logic for Mapper#findPositionIn().

    It allows to start looking for the requested model offset from a given starting position, to enable caching. Using the cache, you can set the starting point and skip all the calculations that were already previously done.

    This method uses recursion to find positions inside deep structures. Example:

    <p>fo<b>bar</b>bom</p>  -> target offset: 4
    <p>|fo<b>bar</b>bom</p> -> target offset: 4, traversed offset: 0
    <p>fo|<b>bar</b>bom</p> -> target offset: 4, traversed offset: 2
    <p>fo<b>bar</b>|bom</p> -> target offset: 4, traversed offset: 5 -> we are too far, look recursively in <b>.
    
    <p>fo<b>|bar</b>bom</p> -> target offset: 4, traversed offset: 2
    <p>fo<b>bar|</b>bom</p> -> target offset: 4, traversed offset: 5 -> we are too far, look inside "bar".
    
    <p>fo<b>ba|r</b>bom</p> -> target offset: 4, traversed offset: 2 -> position is inside text node at offset 4-2 = 2.
    
    Copy code

    Parameters

    startViewPosition : ViewPosition

    View position to start looking from.

    startModelOffset : number

    Model offset related to startViewPosition.

    targetModelOffset : number

    Target model offset to find.

    viewContainer : ViewElement | ViewDocumentFragment

    Mapped ancestor of startViewPosition. startModelOffset is the offset inside a model element or model document fragment mapped to viewContainer.

    useCache : boolean

    Whether Mapper should cache positions while traversing the view tree looking for expectedModelOffset.

    Returns

    ViewPosition

    View position mapped to targetModelOffset.

  • Chevron-right icon

    _getModelLengthAndCache( viewNode, viewContainer, modelOffset ) → number
    Lock icon private

    Gets the length of the view element in the model and updates cache values after each view item it visits.

    See also getModelLength.

    Parameters

    viewNode : ViewNode

    View node.

    viewContainer : ViewElement | ViewDocumentFragment

    Ancestor of viewNode that is a mapped view element.

    modelOffset : number

    Model offset at which the viewNode starts.

    Returns

    number

    Length of the node in the tree model.

  • Chevron-right icon

    _moveViewPositionToTextNode( viewPosition ) → ViewPosition
    Lock icon private

    Because we prefer positions in the text nodes over positions next to text nodes, if the view position was next to a text node, it moves it into the text node instead.

    <p>[]<b>foo</b></p> -> <p>[]<b>foo</b></p> // do not touch if position is not directly next to text
    <p>foo[]<b>foo</b></p> -> <p>foo{}<b>foo</b></p> // move to text node
    <p><b>[]foo</b></p> -> <p><b>{}foo</b></p> // move to text node
    
    Copy code

    Parameters

    viewPosition : ViewPosition

    Position potentially next to the text node.

    Returns

    ViewPosition

    Position in the text node if possible.

  • Chevron-right icon

    _toModelOffset( viewParent, viewOffset, viewBlock ) → number
    Lock icon private

    Calculates model offset based on the view position and the block element.

    Example:

    <p>foo<b>ba|r</b></p> // _toModelOffset( b, 2, p ) -> 5
    
    Copy code

    Is a sum of:

    <p>foo|<b>bar</b></p> // _toModelOffset( p, 3, p ) -> 3
    <p>foo<b>ba|r</b></p> // _toModelOffset( b, 2, b ) -> 2
    
    Copy code

    Parameters

    viewParent : ViewElement

    Position parent.

    viewOffset : number

    Position offset.

    viewBlock : ViewElement | ViewDocumentFragment

    Block used as a base to calculate offset.

    Returns

    number

    Offset in the model.

Events

  • Chevron-right icon

    modelToViewPosition( eventInfo, <anonymous> )

    Fired for each model-to-view position mapping request. The purpose of this event is to enable custom model-to-view position mapping. Callbacks added to this event take model position and are expected to calculate the view position. The calculated view position should be added as a viewPosition value in the data object that is passed as one of parameters to the event callback.

    // Assume that "captionedImage" model element is converted to <img> and following <span> elements in view,
    // and the model element is bound to <img> element. Force mapping model positions inside "captionedImage" to that
    // <span> element.
    mapper.on( 'modelToViewPosition', ( evt, data ) => {
    	const positionParent = modelPosition.parent;
    
    	if ( positionParent.name == 'captionedImage' ) {
    		const viewImg = data.mapper.toViewElement( positionParent );
    		const viewCaption = viewImg.nextSibling; // The <span> element.
    
    		data.viewPosition = new ViewPosition( viewCaption, modelPosition.offset );
    
    		// Stop the event if other callbacks should not modify calculated value.
    		evt.stop();
    	}
    } );
    
    Copy code

    Note: keep in mind that sometimes a "phantom" model position is being converted. A "phantom" model position is a position that points to a nonexistent place in model. Such a position might still be valid for conversion, though (it would point to a correct place in the view when converted). One example of such a situation is when a range is removed from the model, there may be a need to map the range's end (which is no longer a valid model position). To handle such situations, check the data.isPhantom flag:

    // Assume that there is a "customElement" model element and whenever the position is before it,
    // we want to move it to the inside of the view element bound to "customElement".
    mapper.on( 'modelToViewPosition', ( evt, data ) => {
    	if ( data.isPhantom ) {
    		return;
    	}
    
    	// Below line might crash for phantom position that does not exist in model.
    	const sibling = data.modelPosition.nodeBefore;
    
    	// Check if this is the element we are interested in.
    	if ( !sibling.is( 'element', 'customElement' ) ) {
    		return;
    	}
    
    	const viewElement = data.mapper.toViewElement( sibling );
    
    	data.viewPosition = new ViewPosition( sibling, 0 );
    
    	evt.stop();
    } );
    
    Copy code

    Note: the default mapping callback is provided with a low priority setting and does not cancel the event, so it is possible to attach a custom callback after a default callback and also use data.viewPosition calculated by the default callback (for example to fix it).

    Note: the default mapping callback will not fire if data.viewPosition is already set.

    Note: these callbacks are called very often. For efficiency reasons, it is advised to use them only when position mapping between the given model and view elements is unsolvable by using just elements mapping and default algorithm. Also, the condition that checks if a special case scenario happened should be as simple as possible.

    Parameters

    eventInfo : EventInfo

    An object containing information about the fired event.

    <anonymous> : MapperModelToViewPositionEventData
  • Chevron-right icon

    viewToModelPosition( eventInfo, <anonymous> )

    Fired for each view-to-model position mapping request. See event-modelToViewPosition.

    // See example in `modelToViewPosition` event description.
    // This custom mapping will map positions from <span> element next to <img> to the "captionedImage" element.
    mapper.on( 'viewToModelPosition', ( evt, data ) => {
    	const positionParent = viewPosition.parent;
    
    	if ( positionParent.hasClass( 'image-caption' ) ) {
    		const viewImg = positionParent.previousSibling;
    		const modelImg = data.mapper.toModelElement( viewImg );
    
    		data.modelPosition = new ModelPosition( modelImg, viewPosition.offset );
    		evt.stop();
    	}
    } );
    
    Copy code

    Note: the default mapping callback is provided with a low priority setting and does not cancel the event, so it is possible to attach a custom callback after the default callback and also use data.modelPosition calculated by the default callback (for example to fix it).

    Note: the default mapping callback will not fire if data.modelPosition is already set.

    Note: these callbacks are called very often. For efficiency reasons, it is advised to use them only when position mapping between the given model and view elements is unsolvable by using just elements mapping and default algorithm. Also, the condition that checks if special case scenario happened should be as simple as possible.

    Parameters

    eventInfo : EventInfo

    An object containing information about the fired event.

    <anonymous> : MapperViewToModelPositionEventData