-
Notifications
You must be signed in to change notification settings - Fork 164
Selection API
Selection APIs help manage focus/selections. Selection APIs include a Position class and 4 related utilities.
Position class represents a position inside a DOM tree. It is a combination of a DOM node, a offset value, and some other properties:
class Position implements NodePosition {
readonly node: Node;
readonly element: HTMLElement;
readonly offset: number;
readonly isAtEnd: boolean;
...
}
NodePosition is the interface of Position class. We declare it in roosterjs-editor-types package so that other interfaces from this package can also use it.
For example, given this HTML segment:
<html>
<body>
<div id="div1">
<span id="span1">Text 1</span>
<span id="span2">Text 2</span>
</div>
</body>
</html>
node
is the DOM node of this position. It can be an HTML Element, or a Text node. With the HTML code above, if we want to have a position between the two SPAN nodes, then the node here will be DIV#div1.
offset
is a number, it represents the character count (for text node) or the child node count (for HTML element) from the beginning of node
to the position. With the HTML code above, if we want to have a position between the two SPAN nodes, then the offset here will be 1 since there is only one child node (SPAN#span1) before the position under node
.
isAtEnd
is a calculated value. When it is true, it means current position is at the end of node
. In most case this value can be calculated from offset
since we know the child node count/character count under current node. One exception is for void node (such as IMG, BR, INPUT, ...), they can never have child node, so we use isAtEnd
to specify whether the position is at the beginning or ending of the void node.
element
is a calculated value. Its value is set to the node
when node is an HTML element, or its parent element.
An instance of Position can be created from the several ways:
- Clone from an existing Position
class Position {
...
constructor(position: NodePosition);
}
This will create a cloned position from the existing position object.
- Normalize from an existing Position
class Position {
...
normalize(): NodePosition;
}
Position.normalize() will always go to the leaf node of the DOM tree.
With the HTML code above, if we want to normalize a position between the two SPAN nodes, the result will be the beginning of text node "Text 2".
- Create from a node and an offset value
class Position {
...
constructor(node: Node, offset: number);
}
This will create Position object with the given node and offset. Node must be a valid HTML node, and offset should be a valid number within [0, <Count of child nodes/characters>]. And the constructor will do a verification and make sure the final offset value must be valid.
For example with the HTML code above, if we want to create a position with node = DIV#div1 and offset = 1, the returned value will be the position between two SPANs, but if use offset = 3 instead, the final result will be node = DIV#div1 and offset = 2 because there are only 2 child nodes under DIV#div1.
- Create from a node and a PositionType value
class Position {
...
constructor(node: Node, positionType: PositionType);
}
const enum PositionType {
Begin = 0,
End = -1,
Before = -2,
After = -3,
}
Using PositionType can easily specify a position at beginning/ending of a node without calculating its child node/character count, or before/after a node with knowning its parent node, the constructor function will do these calculation for us.
For example with the HTML code above, if we create a position with node = DIV#div1 and positionType = PositionType.End, the returned value will be the position node = DIV#div1 and offset = 2 because there are only 2 child nodes under DIV#div1. The same result can also be created from node = SPAN#span2 and positionType = PositionType.After.
- Create from a Range with its start/end position
class Position {
...
static getStart(range: Range): NodePosition;
static getEnd(range: Range): NodePosition;
}
When we have a range object, using Position.getStart() / Position.getEnd() will be an easy way to get position with range.start/endContainer and range.start/endOffset.
Position class has 4 methods:
Normalize a position, use the leaf level node and offset to represent the same position.
Check if current position is equal to the given position.
Check if current position is after the given position.
Move the position with the given offset, and return the moved result. This will only move under the same container node. If the moving result is beyond current container node, the result will be a trimmed position still under the same node.
Note that a Position object is immutable. So that any methods changing current position will return a new one, and current position keeps no change.