Report an issue
Class

Position (engine/model)

@ckeditor/ckeditor5-engine/src/model/position

class

Represents a position in the model tree.

Note: Position is based on offsets, not indexes. This means that position in element containing two text nodes with data foo and bar, position between them has offset 3, not 1. See path for more.

Since position in a model is represented by a position root and position path it is possible to create positions placed in non-existing elements. This requirement is important for operational transformation.

Also, operations kept in document history are storing positions (and ranges) which were correct when those operations were applied, but may not be correct after document got changed.

When changes are applied to model, it may also happen that position parent will change even if position path has not changed. Keep in mind, that if a position leads to non-existing element, 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.

Filtering

Properties

  • index : Number

    readonly

    Position offset converted to an index in position's parent node. It is equal to the 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.

  • isAtEnd : Boolean

    readonly

    Is true if position is at the end of its parent, false otherwise.

  • isAtStart : Boolean

    readonly

    Is true if position is at the beginning of its parent, false otherwise.

  • nodeAfter : Node | null

    readonly

    Node directly after this position or null if this position is in text node.

  • nodeBefore : Node

    readonly

    Node directly before this position or null if this position is in text node.

  • offset

  • parent : Element

    readonly

    Parent element of this position.

    Keep in mind that parent value is calculated when the property is accessed. If 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).

  • path : Array.<Number>

    readonly

    Position of the node in the tree. Path contains offsets, not indexes.

    Position can be placed before, after or in a node if that node has offsetSize greater than 1. Items in position path are 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 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 ]
  • root : Element | DocumentFragment

    readonly

    Root of the position path.

  • textNode : Text | null

    readonly

    Returns text node instance in which this position is placed or null if this position is not in a text node.

Methods

  • constructor( root, path )

    Creates a position.

    Parameters

    root : Element | DocumentFragment

    Root of the position.

    path : Array.<Number>

    Position path. See path.

  • compareWith( otherPosition ) → PositionRelation

    Checks whether this position is before or after given position.

    Parameters

    otherPosition : Position

    Position to compare with.

    Returns

    PositionRelation
  • getAncestors() → Array.<Item>

    Returns ancestors array of this position, that is this position's parent and its ancestors.

    Returns

    Array.<Item>

    Array with ancestors.

  • getCommonAncestor( position ) → Element | DocumentFragment | null

    Returns an Element or DocumentFragment which is a common ancestor of both positions. The roots of these two positions must be identical.

    Parameters

    position : Position

    The second position.

    Returns

    Element | DocumentFragment | null
  • getCommonPath( position ) → Array.<Number>

    Returns the slice of two position paths which is identical. The roots of these two paths must be identical.

    Parameters

    position : Position

    The second position.

    Returns

    Array.<Number>

    The common path.

  • getLastMatchingPosition( skip, options ) → Position

    Gets the farthest position which matches the callback using 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.

    Parameters

    skip : function

    Callback function. Gets TreeWalkerValue and should return true if the value should be skipped or false if not.

    options : Object

    Object with configuration options. See TreeWalker.

    Returns

    Position

    The position after the last item which matches the skip callback test.

  • getParentPath() → Array.<Number>

    Returns a path to this position's parent. Parent path is equal to position path but without the last item.

    This method returns the parent path even if the parent does not exists.

    Returns

    Array.<Number>

    Path to the parent.

  • getShiftedBy( shift ) → Position

    Returns a new instance of Position, that has same parent but it's offset is shifted by shift value (can be a negative value).

    Parameters

    shift : Number

    Offset shift. Can be a negative value.

    Returns

    Position

    Shifted position.

  • isAfter( otherPosition ) → Boolean

    Checks whether this position is after given position.

    Parameters

    otherPosition : Position

    Position to compare with.

    Returns

    Boolean

    True if this position is after given position.

  • isBefore( otherPosition ) → Boolean

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

    Parameters

    otherPosition : Position

    Position to compare with.

    Returns

    Boolean

    True if this position is before given position.

  • isEqual( otherPosition ) → Boolean

    Checks whether this position is equal to given position.

    Parameters

    otherPosition : Position

    Position to compare with.

    Returns

    Boolean

    True if positions are same.

  • isTouching( otherPosition ) → Boolean

    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.

    Note: this method traverses model document so it can be only used when range is up-to-date with model document.

    Parameters

    otherPosition : Position

    Position to compare with.

    Returns

    Boolean

    True if positions touch.

  • _getCombined( source, target ) → Position

    protected

    Returns 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 = new Position( root, [ 2, 3, 1 ] );
    let source = new Position( root, [ 2, 2 ] );
    let target = new Position( 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 ].

    Parameters

    source : Position

    Beginning of the moved range.

    target : Position

    Position where the range is moved.

    Returns

    Position

    Combined position.

  • _getTransformedByDeletion( deletePosition, howMany ) → Position | null

    protected

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

    Parameters

    deletePosition : Position

    Position before the first removed node.

    howMany : Number

    How many nodes are removed.

    Returns

    Position | null

    Transformed position or null.

  • _getTransformedByInsertion( insertPosition, howMany, insertBefore ) → Position

    protected

    Returns a copy of this position that is updated by inserting howMany nodes at insertPosition.

    Parameters

    insertPosition : Position

    Position where nodes are inserted.

    howMany : Number

    How many nodes are inserted.

    insertBefore : Boolean

    Flag indicating whether nodes are inserted before or after insertPosition. This is important only when insertPosition and this position are same. If that is the case and the flag is set to true, this position will get transformed. If the flag is set to false, it won't.

    Returns

    Position

    Transformed position.

  • _getTransformedByMove( sourcePosition, targetPosition, howMany, insertBefore, [ sticky ] ) → Position

    protected

    Returns a copy of this position that is updated by moving howMany nodes from sourcePosition to targetPosition.

    Parameters

    sourcePosition : Position

    Position before the first element to move.

    targetPosition : Position

    Position where moved elements will be inserted.

    howMany : Number

    How many consecutive nodes to move, starting from sourcePosition.

    insertBefore : Boolean

    Flag indicating whether moved nodes are pasted before or after insertPosition. This is important only when targetPosition and this position are same. If that is the case and the flag is set to true, this position will get transformed by range insertion. If the flag is set to false, it won't.

    [ sticky ] : Boolean

    Flag indicating whether this position "sticks" to range, that is if it should be moved with the moved range if it is equal to one of range's boundaries.

    Returns

    Position

    Transformed position.

Static methods

  • createAfter( item ) → Position

    static

    Creates a new position, after given model item.

    Parameters

    item : Item

    Item after which the position should be placed.

    Returns

    Position
  • createAt( itemOrPosition, [ offset ] )

    static

    Creates position at the given location. The location can be specified as:

    • a position,
    • parent element and offset (offset defaults to 0),
    • parent element and 'end' (sets position at the end of that element),
    • model item and 'before' or 'after' (sets position before or after given model item).

    This method is a shortcut to other constructors such as:

    Parameters

    itemOrPosition : Item | Position
    [ offset ] : Number | 'end' | 'before' | 'after'

    Offset or one of the flags. Used only when first parameter is a model item.

    Defaults to 0

  • createBefore( item ) → Position

    static

    Creates a new position, before the given model item.

    Parameters

    item : Item

    Item before which the position should be placed.

    Returns

    Position
  • createFromParentAndOffset( parent, offset ) → Position

    static

    Creates a new position from the parent element and an offset in that element.

    Parameters

    parent : Element | DocumentFragment

    Position's parent.

    offset : Number

    Position's offset.

    Returns

    Position
  • createFromPosition( position ) → Position

    static

    Creates a new position, which is equal to passed position.

    Parameters

    position : Position

    Position to be cloned.

    Returns

    Position
  • fromJSON( json ) → Position

    static

    Creates a Position instance from given plain object (i.e. parsed JSON string).

    Parameters

    json : Object

    Plain object to be converted to Position.

    Returns

    Position

    Position instance created using given plain object.