MapperCache (engine/conversion)
@ckeditor/ckeditor5-engine/src/conversion/mapper
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>
module:engine/conversion/mapper~MapperCache#_cachedMapping
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 alsoMappingCache
andCacheItem
.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 byMapperCache
. When an item is no longer tracked, it is removed from this structure.Although
MappingCache
andCacheItem
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 samemodelOffset
. 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>
, offset2
). - for model:
-
private
_invalidateOnChildrenChangeCallback : GetCallback<ViewNodeChangeEvent>
module:engine/conversion/mapper~MapperCache#_invalidateOnChildrenChangeCallback
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>
module:engine/conversion/mapper~MapperCache#_invalidateOnTextChangeCallback
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>
module:engine/conversion/mapper~MapperCache#_nodeToCacheListIndex
When
MapperCache
saves view position -> model offset mapping, aCacheItem
is inserted into certainMappingCache#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 byMapperCache
. If all<p>
children were visited byMapperCache
, then<p>
cache list would have four items, related to following model offsets:0
,5
,9
,15
. Then, view node"Some "
would have index1
,<strong>
index2
, 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 offset0
(and view offset0
), and it is not related to any node.
Methods
-
inherited
delegate( events ) → EmitterMixinDelegateChain
module:engine/conversion/mapper~MapperCache#delegate
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
andemitterC
along withdata
:emitterA.fire( 'eventX', data );
and
eventY
is delegated (fired by)emitterC
along withdata
:emitterA.fire( 'eventY', data );
Parameters
events : Array<string>
Event names that will be delegated to another emitter.
Returns
-
inherited
fire( eventOrInfo, args ) → GetEventInfo<TEvent>[ 'return' ]
module:engine/conversion/mapper~MapperCache#fire
Fires an event, executing all callbacks registered for it.
The first parameter passed to callbacks is an
EventInfo
object, followed by the optionalargs
provided in thefire()
method call.Type parameters
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 theevt.return
's property (the event info is the first param of every callback).
-
getClosest( viewContainer, modelOffset ) → CacheItem
module:engine/conversion/mapper~MapperCache#getClosest
For given
modelOffset
inside a model element mapped to givenviewContainer
, 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 theMapperCache
, 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
module:engine/conversion/mapper~MapperCache#listenTo:BASE_EMITTER
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
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
-
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
-
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
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
module:engine/conversion/mapper~MapperCache#once
Registers a callback function to be executed on the next time the event is fired only. This is similar to calling
on
followed byoff
in the callback.Type parameters
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
module:engine/conversion/mapper~MapperCache#save
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 than0
).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
module:engine/conversion/mapper~MapperCache#startTracking
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 forchange
event fired byviewContainer
.MapperCache
listens tochange
event on the tracked elements to invalidate the stored cache.Parameters
viewContainer : Element | DocumentFragment
Returns
CacheItem
-
inherited
stopDelegating( [ event ], [ emitter ] ) → void
module:engine/conversion/mapper~MapperCache#stopDelegating
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 ofevent
to all emitters.
Returns
void
-
inherited
stopListening( [ emitter ], [ event ], [ callback ] ) → void
module:engine/conversion/mapper~MapperCache#stopListening:BASE_STOP
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 fromemitter
.[ callback ] : Function
(Requires the
event
) The function to be removed from the call list for the givenevent
.
Returns
void
-
stopTracking( viewContainer ) → void
module:engine/conversion/mapper~MapperCache#stopTracking
Stops tracking given
viewContainer
.It removes the cached data and stops listening to
change
event on theviewContainer
.Parameters
viewContainer : Element | DocumentFragment
Returns
void
-
private
_clearCacheAll( viewContainer ) → void
module:engine/conversion/mapper~MapperCache#_clearCacheAll
Clears all the cache for given tracked
viewContainer
.Parameters
viewContainer : Element | DocumentFragment
Returns
void
-
private
_clearCacheFromIndex( viewContainer, index ) → void
module:engine/conversion/mapper~MapperCache#_clearCacheFromIndex
Clears all the cache in the cache list related to given
viewContainer
, starting fromindex
(inclusive).Parameters
viewContainer : Element | DocumentFragment
index : number
Returns
void
-
private
_clearCacheInsideParent( viewParent, index ) → void
module:engine/conversion/mapper~MapperCache#_clearCacheInsideParent
Invalidates cache inside
viewParent
, starting from givenindex
in that parent.Parameters
viewParent : Element | DocumentFragment
index : number
Returns
void
-
private
_clearCacheStartingBefore( viewNode ) → void
module:engine/conversion/mapper~MapperCache#_clearCacheStartingBefore
Clears all the stored cache starting before given
viewNode
. TheviewNode
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
module:engine/conversion/mapper~MapperCache#_findInCacheList
Finds a cache item in the given cache list, which
modelOffset
is closest (but smaller or equal) to givenoffset
.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
module:engine/conversion/mapper~MapperCache#_hoistViewPosition
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
Every day, we work hard to keep our documentation complete. Have you spotted outdated information? Is something missing? Please report it via our issue tracker.
With the release of version 42.0.0, we have rewritten much of our documentation to reflect the new import paths and features. We appreciate your feedback to help us ensure its accuracy and completeness.