Creates a position.
Root of the position.
Position path. See module:engine/model/position~ModelPosition#path.
Optionalstickiness: ModelPositionStickinessPosition stickiness. See module:engine/model/position~ModelPositionStickiness.
ReadonlypathPosition of the node in the tree. Path contains offsets, not indexes.
Position can be placed before, after or in a module:engine/model/node~ModelNode node if that node has
module:engine/model/node~ModelNode#offsetSize greater than 1. Items in position path are
module:engine/model/node~ModelNode#startOffset starting offsets of position ancestors, starting from direct root children,
down to the position offset in it's parent.
ROOT
|- P before: [ 0 ] after: [ 1 ]
|- UL before: [ 1 ] after: [ 2 ]
|- LI before: [ 1, 0 ] after: [ 1, 1 ]
| |- foo before: [ 1, 0, 0 ] after: [ 1, 0, 3 ]
|- LI before: [ 1, 1 ] after: [ 1, 2 ]
|- bar before: [ 1, 1, 0 ] after: [ 1, 1, 3 ]
foo and bar are representing module:engine/model/text~ModelText text nodes. Since text nodes has offset size
greater than 1 you can place position offset between their start and end:
ROOT
|- P
|- UL
|- LI
| |- f^o|o ^ has path: [ 1, 0, 1 ] | has path: [ 1, 0, 2 ]
|- LI
|- b^a|r ^ has path: [ 1, 1, 1 ] | has path: [ 1, 1, 2 ]
ReadonlyrootRoot of the position path.
Position stickiness. See module:engine/model/position~ModelPositionStickiness.
Position module:engine/model/position~ModelPosition#offset offset converted to an index in position's parent node. It is equal to the module:engine/model/node~ModelNode#index index of a node after this position. If position is placed in text node, position index is equal to the index of that text node.
Is true if position is at the end of its module:engine/model/position~ModelPosition#parent parent, false otherwise.
Is true if position is at the beginning of its module:engine/model/position~ModelPosition#parent parent, false otherwise.
Node directly after this position. Returns null if this position is at the end of its parent, or if it is in a text node.
Node directly before this position. Returns null if this position is at the start of its parent, or if it is in a text node.
Offset at which this position is located in its module:engine/model/position~ModelPosition#parent parent. It is equal to the last item in position module:engine/model/position~ModelPosition#path path.
Parent element of this position.
Keep in mind that parent value is calculated when the property is accessed.
If module:engine/model/position~ModelPosition#path position path
leads to a non-existing element, parent property will throw error.
Also it is a good idea to cache parent property if it is used frequently in an algorithm (i.e. in a long loop).
Returns module:engine/model/text~ModelText text node instance in which this position is placed or null if this
position is not in a text node.
InternalReturns a new position that is a combination of this position and given positions.
The combined position is a copy of this position transformed by moving a range starting at source position
to the target position. It is expected that this position is inside the moved range.
Example:
let original = model.createPositionFromPath( root, [ 2, 3, 1 ] );
let source = model.createPositionFromPath( root, [ 2, 2 ] );
let target = model.createPositionFromPath( otherRoot, [ 1, 1, 3 ] );
original._getCombined( source, target ); // path is [ 1, 1, 4, 1 ], root is `otherRoot`
Explanation:
We have a position [ 2, 3, 1 ] and move some nodes from [ 2, 2 ] to [ 1, 1, 3 ]. The original position
was inside moved nodes and now should point to the new place. The moved nodes will be after
positions [ 1, 1, 3 ], [ 1, 1, 4 ], [ 1, 1, 5 ]. Since our position was in the second moved node,
the transformed position will be in a sub-tree of a node at [ 1, 1, 4 ]. Looking at original path, we
took care of [ 2, 3 ] part of it. Now we have to add the rest of the original path to the transformed path.
Finally, the transformed position will point to [ 1, 1, 4, 1 ].
Beginning of the moved range.
Position where the range is moved.
Combined position.
InternalReturns a copy of this position that is updated by removing howMany nodes starting from deletePosition.
It may happen that this position is in a removed node. If that is the case, null is returned instead.
Position before the first removed node.
How many nodes are removed.
Transformed position or null.
InternalReturns a copy of this position that is updated by inserting howMany nodes at insertPosition.
Position where nodes are inserted.
How many nodes are inserted.
Transformed position.
InternalReturns a copy of this position transformed by an insert operation.
InternalReturns a copy of this position transformed by merge operation.
InternalReturns a copy of this position that is updated by moving howMany nodes from sourcePosition to targetPosition.
Position before the first element to move.
Position where moved elements will be inserted.
How many consecutive nodes to move, starting from sourcePosition.
Transformed position.
InternalReturns a copy of this position transformed by a move operation.
InternalReturns a copy of this position transformed by a split operation.
Returns a new position that is equal to current position.
Checks whether this position is before or after given position.
This method is safe to use it on non-existing positions (for example during operational transformation).
Returns the parent element of the given name. Returns null if the position is not inside the desired parent.
The name of the parent element to find.
Returns ancestors array of this position, that is this position's parent and its ancestors.
Array with ancestors.
Returns an module:engine/model/element~ModelElement or module:engine/model/documentfragment~ModelDocumentFragment which is a common ancestor of both positions. The #root roots of these two positions must be identical.
The second position.
Returns the slice of two position #path paths which is identical. The #root roots of these two paths must be identical.
This method is safe to use it on non-existing positions (for example during operational transformation).
The second position.
The common path.
Gets the farthest position which matches the callback using module:engine/model/treewalker~ModelTreeWalker TreeWalker.
For example:
getLastMatchingPosition( value => value.type == 'text' );
// <paragraph>[]foo</paragraph> -> <paragraph>foo[]</paragraph>
getLastMatchingPosition( value => value.type == 'text', { direction: 'backward' } );
// <paragraph>foo[]</paragraph> -> <paragraph>[]foo</paragraph>
getLastMatchingPosition( value => false );
// Do not move the position.
Callback function. Gets module:engine/model/treewalker~ModelTreeWalkerValue and should
return true if the value should be skipped or false if not.
Optionaloptions: ModelTreeWalkerOptionsObject with configuration options. See module:engine/model/treewalker~ModelTreeWalker.
The position after the last item which matches the skip callback test.
Returns a path to this position's parent. Parent path is equal to position module:engine/model/position~ModelPosition#path path but without the last item.
This method is safe to use it on non-existing positions (for example during operational transformation).
Path to the parent.
Returns a new instance of Position, that has same #parent parent but it's offset
is shifted by shift value (can be a negative value).
This method is safe to use it on non-existing positions (for example during operational transformation).
Offset shift. Can be a negative value.
Shifted position.
Returns a copy of this position that is transformed by given operation.
The new position's parameters are updated accordingly to the effect of the operation.
For example, if n nodes are inserted before the position, the returned position ~ModelPosition#offset will be
increased by n. If the position was in a merged element, it will be accordingly moved to the new element, etc.
This method is safe to use it on non-existing positions (for example during operational transformation).
Operation to transform by.
Transformed position.
Checks if two positions are in the same parent.
This method is safe to use it on non-existing positions (for example during operational transformation).
Position to compare with.
true if positions have the same parent, false otherwise.
Checks whether the object is of type module:engine/model/node~ModelNode or its subclass.
This method is useful when processing model objects that are of unknown type. For example, a function may return a module:engine/model/documentfragment~ModelDocumentFragment or a module:engine/model/node~ModelNode that can be either a text node or an element. This method can be used to check what kind of object is returned.
someObject.is( 'element' ); // -> true if this is an element
someObject.is( 'node' ); // -> true if this is a node (a text node or an element)
someObject.is( 'documentFragment' ); // -> true if this is a document fragment
Since this method is also available on a range of view objects, you can prefix the type of the object with
model: or view: to check, for example, if this is the model's or view's element:
modelElement.is( 'model:element' ); // -> true
modelElement.is( 'view:element' ); // -> false
By using this method it is also possible to check a name of an element:
imageElement.is( 'element', 'imageBlock' ); // -> true
imageElement.is( 'element', 'imageBlock' ); // -> same as above
imageElement.is( 'model:element', 'imageBlock' ); // -> same as above, but more precise
Checks whether the object is of type module:engine/model/element~ModelElement or its subclass.
element.is( 'element' ); // -> true
element.is( 'node' ); // -> true
element.is( 'model:element' ); // -> true
element.is( 'model:node' ); // -> true
element.is( 'view:element' ); // -> false
element.is( 'documentSelection' ); // -> false
Assuming that the object being checked is an element, you can also check its module:engine/model/element~ModelElement#name name:
element.is( 'element', 'imageBlock' ); // -> true if this is an <imageBlock> element
text.is( 'element', 'imageBlock' ); -> false
Checks whether the object is of type module:engine/model/rootelement~ModelRootElement.
rootElement.is( 'rootElement' ); // -> true
rootElement.is( 'element' ); // -> true
rootElement.is( 'node' ); // -> true
rootElement.is( 'model:rootElement' ); // -> true
rootElement.is( 'model:element' ); // -> true
rootElement.is( 'model:node' ); // -> true
rootElement.is( 'view:element' ); // -> false
rootElement.is( 'documentFragment' ); // -> false
Assuming that the object being checked is an element, you can also check its module:engine/model/element~ModelElement#name name:
rootElement.is( 'rootElement', '$root' ); // -> same as above
Checks whether the object is of type module:engine/model/text~ModelText.
text.is( '$text' ); // -> true
text.is( 'node' ); // -> true
text.is( 'model:$text' ); // -> true
text.is( 'model:node' ); // -> true
text.is( 'view:$text' ); // -> false
text.is( 'documentSelection' ); // -> false
Note: Until version 20.0.0 this method wasn't accepting '$text' type. The legacy 'text' type is still
accepted for backward compatibility.
Checks whether the object is of type module:engine/model/position~ModelPosition or its subclass.
position.is( 'position' ); // -> true
position.is( 'model:position' ); // -> true
position.is( 'view:position' ); // -> false
position.is( 'documentSelection' ); // -> false
Checks whether the object is of type module:engine/model/liveposition~ModelLivePosition.
livePosition.is( 'position' ); // -> true
livePosition.is( 'model:position' ); // -> true
livePosition.is( 'liveposition' ); // -> true
livePosition.is( 'model:livePosition' ); // -> true
livePosition.is( 'view:position' ); // -> false
livePosition.is( 'documentSelection' ); // -> false
Checks whether the object is of type module:engine/model/range~ModelRange or its subclass.
range.is( 'range' ); // -> true
range.is( 'model:range' ); // -> true
range.is( 'view:range' ); // -> false
range.is( 'documentSelection' ); // -> false
Checks whether the object is of type module:engine/model/liverange~ModelLiveRange.
liveRange.is( 'range' ); // -> true
liveRange.is( 'model:range' ); // -> true
liveRange.is( 'liveRange' ); // -> true
liveRange.is( 'model:liveRange' ); // -> true
liveRange.is( 'view:range' ); // -> false
liveRange.is( 'documentSelection' ); // -> false
Checks whether the object is of type module:engine/model/documentfragment~ModelDocumentFragment.
docFrag.is( 'documentFragment' ); // -> true
docFrag.is( 'model:documentFragment' ); // -> true
docFrag.is( 'view:documentFragment' ); // -> false
docFrag.is( 'element' ); // -> false
docFrag.is( 'node' ); // -> false
Checks whether the object is of type module:engine/model/selection~ModelSelection or module:engine/model/documentselection~ModelDocumentSelection.
selection.is( 'selection' ); // -> true
selection.is( 'model:selection' ); // -> true
selection.is( 'view:selection' ); // -> false
selection.is( 'range' ); // -> false
Checks whether the object is of type module:engine/model/documentselection~ModelDocumentSelection.
selection.is( 'selection' ); // -> true
selection.is( 'documentSelection' ); // -> true
selection.is( 'model:selection' ); // -> true
selection.is( 'model:documentSelection' ); // -> true
selection.is( 'view:selection' ); // -> false
selection.is( 'element' ); // -> false
selection.is( 'node' ); // -> false
Checks whether the object is of type module:engine/model/markercollection~Marker.
marker.is( 'marker' ); // -> true
marker.is( 'model:marker' ); // -> true
marker.is( 'view:element' ); // -> false
marker.is( 'documentSelection' ); // -> false
Checks whether the object is of type module:engine/model/textproxy~ModelTextProxy.
textProxy.is( '$textProxy' ); // -> true
textProxy.is( 'model:$textProxy' ); // -> true
textProxy.is( 'view:$textProxy' ); // -> false
textProxy.is( 'range' ); // -> false
Note: Until version 20.0.0 this method wasn't accepting '$textProxy' type. The legacy 'textProxt' type is still
accepted for backward compatibility.
Checks whether the object is of type module:engine/model/element~ModelElement or its subclass and has the specified name.
element.is( 'element', 'imageBlock' ); // -> true if this is an <imageBlock> element
text.is( 'element', 'imageBlock' ); -> false
Checks whether the object is of type module:engine/model/rootelement~ModelRootElement and has the specified name.
rootElement.is( 'rootElement', '$root' );
Checks whether this position is after given position.
This method is safe to use it on non-existing positions (for example during operational transformation).
Position to compare with.
True if this position is after given position.
Checks whether this position is before given position.
Note: watch out when using negation of the value returned by this method, because the negation will also
be true if positions are in different roots and you might not expect this. You should probably use
a.isAfter( b ) || a.isEqual( b ) or !a.isBefore( p ) && a.root == b.root in most scenarios. If your
condition uses multiple isAfter and isBefore checks, build them so they do not use negated values, i.e.:
if ( a.isBefore( b ) && c.isAfter( d ) ) {
// do A.
} else {
// do B.
}
or, if you have only one if-branch:
if ( !( a.isBefore( b ) && c.isAfter( d ) ) {
// do B.
}
rather than:
if ( !a.isBefore( b ) || && !c.isAfter( d ) ) {
// do B.
} else {
// do A.
}
This method is safe to use it on non-existing positions (for example during operational transformation).
Position to compare with.
True if this position is before given position.
Checks whether this position is equal to given position.
This method is safe to use it on non-existing positions (for example during operational transformation).
Position to compare with.
True if positions are same.
Checks whether this position is touching given position. Positions touch when there are no text nodes or empty nodes in a range between them. Technically, those positions are not equal but in many cases they are very similar or even indistinguishable.
Position to compare with.
True if positions touch.
Checks whether the position is valid in current model tree, that is whether it points to an existing place in the model.
Static_InternalCreates a new position, after given module:engine/model/item~ModelItem model item.
Item after which the position should be placed.
Optionalstickiness: ModelPositionStickinessPosition stickiness.
Static_InternalCreates position at the given location. The location can be specified as:
0),'end' (sets position at the end of that element),'before' or 'after' (sets position before or after given model item).This method is a shortcut to other factory methods such as:
Optionaloffset: ModelPositionOffsetOffset or one of the flags. Used only when the first parameter is a module:engine/model/item~ModelItem model item.
Optionalstickiness: ModelPositionStickinessPosition stickiness. Used only when the first parameter is a module:engine/model/item~ModelItem model item.
Static_InternalCreates a new position, before the given module:engine/model/item~ModelItem model item.
Item before which the position should be placed.
Optionalstickiness: ModelPositionStickinessPosition stickiness.
StaticfromCreates a Position instance from given plain object (i.e. parsed JSON string).
Plain object to be converted to Position.
Document object that will be position owner.
Position instance created using given plain object.
Represents a position in the model tree.
A position is represented by its module:engine/model/position~ModelPosition#root and a module:engine/model/position~ModelPosition#path in that root.
You can create position instances via its constructor or the
createPosition*()factory methods of module:engine/model/model~Model and module:engine/model/writer~ModelWriter.Note: Position is based on offsets, not indexes. This means that a position between two text nodes
fooandbarhas offset3, not1. See module:engine/model/position~ModelPosition#path for more information.Since a position in the model is represented by a module:engine/model/position~ModelPosition#root position root and module:engine/model/position~ModelPosition#path position path it is possible to create positions placed in non-existing places. This requirement is important for operational transformation algorithms.
Also, module:engine/model/operation/operation~Operation operations kept in the module:engine/model/document~ModelDocument#history document history are storing positions (and ranges) which were correct when those operations were applied, but may not be correct after the document has changed.
When changes are applied to the model, it may also happen that module:engine/model/position~ModelPosition#parent position parent will change even if position path has not changed. Keep in mind, that if a position leads to non-existing element, module:engine/model/position~ModelPosition#parent and some other properties and methods will throw errors.
In most cases, position with wrong path is caused by an error in code, but it is sometimes needed, as described above.