Class

MapperCache (engine/conversion)

@ckeditor/ckeditor5-engine/src/conversion/mapper

class internal

Cache mechanism for Mapper.

MapperCache improves performance for model-to-view position mapping, which is the main Mapper task. Asking for a mapping is much more frequent than actually performing changes, and even if the change happens, we can still partially keep the cache. This makes caching a useful strategy for Mapper.

MapperCache will store some data for view elements or view document fragments that are mapped by the Mapper. These view items are "tracked" by the MapperCache. For such view items, we will keep entries of model offsets inside their mapped counterpart. For the cached model offsets, we will keep a view position that is inside the tracked item. This allows us to either get the mapping instantly, or at least in less steps than when calculating it from the beginning.

Important problem related to caching is invalidating the cache. The cache must be invalidated each time the tracked view item changes. Additionally, we should invalidate as small part of the cache as possible. Since all the logic is encapsulated inside MapperCache, the MapperCache listens to view items change event and reacts to it. Then, it invalidates just the part of the cache that is "after" the changed part of the view.

As mentioned, MapperCache currently is used only for model-to-view position mapping as it was much bigger problem than view-to-model mapping. However, it should be possible to use it also for view-to-model.

The main assumptions regarding MapperCache are:

  • it is an internal tool, used by Mapper, transparent to the outside (no additional effort when developing a plugin or a converter),
  • it stores all the necessary data internally, which makes it easier to disable or debug,
  • it is optimized for initial downcast process (long insertions), which is crucial for editor init and data save,
  • it does not save all possible positions for memory considerations, although it is a possible improvement, which may have increase performance, as well as simplify some parts of the MapperCache logic.

Filtering

Properties

  • private

    _cachedMapping : WeakMap<Element | DocumentFragment, MappingCache>

    For every view element or document fragment tracked by MapperCache, it holds currently cached data, or more precisely, model offset to view position mappings. See also MappingCache and CacheItem.

    If an item is tracked by MapperCache it has an entry in this structure, so this structure can be used to check which items are tracked by MapperCache. When an item is no longer tracked, it is removed from this structure.

    Although MappingCache and CacheItem structures allows for caching any model offsets and view positions, we only cache values for model offsets that are after a view node. So, in essence, positions inside text nodes are not cached. However, it takes from one to at most a few steps, to get from a cached position to a position that is inside a view text node.

    Additionally, only one item per modelOffset is cached. There can be several view nodes that "end" at the same modelOffset. In this case, we favour positions that are closer to the mapped item. For example

    • for model: <paragraph>Some <$text bold=true italic=true>formatted</$text> text.</paragraph>,
    • and view: <p>Some <em><strong>formatted</strong></em> text.</p>,

    for model offset 14 (after "d"), we store view position after <em> element (i.e. view position: at <p>, offset 2).

  • private

    _invalidateOnChildrenChangeCallback : GetCallback<ViewNodeChangeEvent>

    Callback fired whenever there is a direct or indirect children change in tracked view element or tracked view document fragment.

    This is specified as a property to make it easier to set as an event callback and to later turn off that event.

  • private

    _invalidateOnTextChangeCallback : GetCallback<ViewNodeChangeEvent>

    Callback fired whenever a view text node directly or indirectly inside a tracked view element or tracked view document fragment changes its text data.

    This is specified as a property to make it easier to set as an event callback and to later turn off that event.

  • private

    _nodeToCacheListIndex : WeakMap<Node, number>

    When MapperCache saves view position -> model offset mapping, a CacheItem is inserted into certain MappingCache#cacheList at some index. Additionally, we store that index with the view node that is before the cached view position.

    This allows to quickly get a cache list item related to certain view node, and hence, for fast cache invalidation.

    For example, consider view: <p>Some <strong>bold</strong> text.</p>, where <p> is a view element tracked by MapperCache. If all <p> children were visited by MapperCache, then <p> cache list would have four items, related to following model offsets: 0, 5, 9, 15. Then, view node "Some " would have index 1, <strong> index 2, and " text." index 3`.

    Note that the index related with a node is always greater than 0. The first item in cache list is always for model offset 0 (and view offset 0), and it is not related to any node.

Methods

  • inherited

    constructor()

  • inherited

    delegate( events ) → EmitterMixinDelegateChain

    Delegates selected events to another Emitter. For instance:

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

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

    emitterA.fire( 'eventX', data );
    

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

    emitterA.fire( 'eventY', data );
    

    Parameters

    events : Array<string>

    Event names that will be delegated to another emitter.

    Returns

    EmitterMixinDelegateChain
  • inherited

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

    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).

  • getClosest( viewContainer, modelOffset ) → CacheItem

    For given modelOffset inside a model element mapped to given viewContainer, it returns the closest saved cache item (view position and related model offset) to the requested one.

    It can be exactly the requested mapping, or it can be mapping that is the closest starting point to look for the requested mapping.

    viewContainer must be a view element or document fragment that is mapped by the Mapper.

    If viewContainer is not yet tracked by the MapperCache, it will be automatically tracked after calling this method.

    Note: this method will automatically "hoist" cached positions, i.e. it will return a position that is closest to the tracked element.

    For example, if <p> is tracked element, and ^ is cached position:

    <p>This is <strong>some <em>heavily <u>formatted</u>^</em></strong> text.</p>
    

    If this position would be returned, instead, a position directly in <p> would be returned:

    <p>This is <strong>some <em>heavily <u>formatted</u></em></strong>^ text.</p>
    

    Note, that modelOffset for both positions is the same.

    Parameters

    viewContainer : Element | DocumentFragment

    Tracked view element or document fragment, which cache will be used.

    modelOffset : number

    Model offset in a model element or document fragment, which is mapped to viewContainer.

    Returns

    CacheItem
  • inherited

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

    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' );
    

    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
  • inherited

    off( event, callback ) → void

    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
  • inherited

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

    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
  • inherited

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

    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
  • save( viewParent, viewOffset, viewContainer, modelOffset ) → void

    Saves cache for given view position mapping <-> model offset mapping. The view position should be after a node (i.e. it cannot be the first position inside its parent, or in other words, viewOffset must be greater than 0).

    Parameters

    viewParent : Element | DocumentFragment

    View position parent.

    viewOffset : number

    View position offset. Must be greater than 0.

    viewContainer : Element | DocumentFragment

    Tracked view position ascendant (it may be the direct parent of the view position).

    modelOffset : number

    Model offset in the model element or document fragment which is mapped to viewContainer.

    Returns

    void
  • startTracking( viewContainer ) → CacheItem

    Starts tracking given viewContainer, which must be mapped to a model element or model document fragment.

    Note, that this method is automatically called by MapperCache#getClosest() and there is no need to call it manually.

    This method initializes the cache for viewContainer and adds callbacks for change event fired by viewContainer. MapperCache listens to change event on the tracked elements to invalidate the stored cache.

    Parameters

    viewContainer : Element | DocumentFragment

    Returns

    CacheItem
  • inherited

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

    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
  • inherited

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

    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
  • stopTracking( viewContainer ) → void

    Stops tracking given viewContainer.

    It removes the cached data and stops listening to change event on the viewContainer.

    Parameters

    viewContainer : Element | DocumentFragment

    Returns

    void
  • private

    _clearCacheAll( viewContainer ) → void

    Clears all the cache for given tracked viewContainer.

    Parameters

    viewContainer : Element | DocumentFragment

    Returns

    void
  • private

    _clearCacheFromIndex( viewContainer, index ) → void

    Clears all the cache in the cache list related to given viewContainer, starting from index (inclusive).

    Parameters

    viewContainer : Element | DocumentFragment
    index : number

    Returns

    void
  • private

    _clearCacheInsideParent( viewParent, index ) → void

    Invalidates cache inside viewParent, starting from given index in that parent.

    Parameters

    viewParent : Element | DocumentFragment
    index : number

    Returns

    void
  • private

    _clearCacheStartingBefore( viewNode ) → void

    Clears all the stored cache starting before given viewNode. The viewNode can be any node that is inside a tracked view element or view document fragment.

    Parameters

    viewNode : Node

    Returns

    void
  • private

    _findInCacheList( cacheList, offset ) → CacheItem

    Finds a cache item in the given cache list, which modelOffset is closest (but smaller or equal) to given offset.

    Since cacheList is a sorted array, this uses binary search to retrieve the item quickly.

    Parameters

    cacheList : Array<CacheItem>
    offset : number

    Returns

    CacheItem
  • private

    _hoistViewPosition( viewPosition ) → Position

    Moves a view position to a preferred location.

    The view position is moved up from a non-tracked view element as long as it remains at the end of its current parent.

    See example below to understand when it is important:

    Starting state:

    <p>This is <strong>some <em>heavily <u>formatted</u>^ piece of</em></strong> text.</p>
    

    Then we remove " piece of " and invalidate some cache:

    <p>This is <strong>some <em>heavily <u>formatted</u>^</em></strong> text.</p>
    

    Now, if we ask for model offset after letter "d" in "formatted", we should get a position in " text", but we will get in <em>. For this scenario, we need to hoist the position.

    <p>This is <strong>some <em>heavily <u>formatted</u></em></strong>^ text.</p>
    

    Parameters

    viewPosition : Position

    Returns

    Position