AbstractCreates a model node.
This is an abstract class, so this constructor should not be used directly.
Optionalattrs: ModelNodeAttributesNode's attributes. See module:utils/tomap~toMap for a list of accepted values.
Internal_Index of this node in its parent or null if the node has no parent.
Internal_Offset at which this node starts in its parent or null if the node has no parent.
ReadonlyparentParent of this node. It could be module:engine/model/element~ModelElement
or module:engine/model/documentfragment~ModelDocumentFragment.
Equals to null if the node has no parent.
ReadonlyrootUnique root name used to identify this root element by module:engine/model/document~ModelDocument.
module:engine/model/document~ModelDocument Document that owns this root element.
Offset at which this node ends in its parent. It is equal to the sum of this node's
module:engine/model/node~ModelNode#startOffset start offset and #offsetSize offset size.
Equals to null if the node has no parent.
Index of this node in its parent or null if the node has no parent.
Node's next sibling or null if the node is a last child of it's parent or if the node has no parent.
Offset size of this node.
Represents how much "offset space" is occupied by the node in its parent. It is important for
module:engine/model/position~ModelPosition position. When node has offsetSize greater
than 1, position can be placed between that node start and end. offsetSize greater than 1 is for
nodes that represents more than one entity, i.e. a module:engine/model/text~ModelText text node.
Node's previous sibling or null if the node is a first child of it's parent or if the node has no parent.
The top-most ancestor of the node. If node has no parent it is the root itself. If the node is a part
of module:engine/model/documentfragment~ModelDocumentFragment, it's root is equal to that DocumentFragment.
Offset at which this node starts in its parent. It is equal to the sum of #offsetSize offsetSize
of all its previous siblings. Equals to null if node has no parent.
InternalCreates a copy of this node, that is a node with exactly same attributes, and returns it.
Optional_deep: booleanNode with same attributes as this node.
InternalRemoves all attributes from the node and sets given attributes.
Attributes to set. See module:utils/tomap~toMap for a list of accepted values.
Returns ancestors array of this node.
Optionaloptions: { includeSelf?: boolean; parentFirst?: boolean }Options object.
OptionalincludeSelf?: booleanWhen set to true this node will be also included in parent's array.
OptionalparentFirst?: booleanWhen set to true, array will be sorted from node's parent to root element,
otherwise root element will be the first item in the array.
Array with ancestors.
Gets an attribute value for given key or undefined if that attribute is not set on node.
Key of attribute to look for.
Attribute value or undefined.
Returns iterator that iterates over this node's attribute keys.
Returns iterator that iterates over this node's attributes.
Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.
This format is accepted by native Map object and also can be passed in Node constructor.
Returns a module:engine/model/element~ModelElement or module:engine/model/documentfragment~ModelDocumentFragment which is a common ancestor of both nodes.
The second node.
Optionaloptions: { includeSelf?: boolean }Options object.
OptionalincludeSelf?: booleanWhen set to true both nodes will be considered "ancestors" too.
Which means that if e.g. node A is inside B, then their common ancestor will be B.
Gets path to the node. The path is an array containing starting offsets of consecutive ancestors of this node, beginning from module:engine/model/node~ModelNode#root root, down to this node's starting offset. The path can be used to create module:engine/model/position~ModelPosition Position instance.
const abc = new Text( 'abc' );
const foo = new Text( 'foo' );
const h1 = new ModelElement( 'h1', null, new Text( 'header' ) );
const p = new ModelElement( 'p', null, [ abc, foo ] );
const div = new ModelElement( 'div', null, [ h1, p ] );
foo.getPath(); // Returns [ 1, 3 ]. `foo` is in `p` which is in `div`. `p` starts at offset 1, while `foo` at 3.
h1.getPath(); // Returns [ 0 ].
div.getPath(); // Returns [].
Checks if the node has an attribute with given key.
Key of attribute to check.
true if attribute with given key is set on node, 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' );
Returns whether this node is after given node. false is returned if nodes are in different trees (for example,
in different module:engine/model/documentfragment~ModelDocumentFragments).
Node to compare with.
Returns true if the node is inside a document root that is attached to the document.
Returns whether this node is before given node. false is returned if nodes are in different trees (for example,
in different module:engine/model/documentfragment~ModelDocumentFragments).
Node to compare with.
Converts Node to plain object and returns it.
Node converted to plain object.
Model node. Most basic structure of model tree.
This is an abstract class that is a base for other classes representing different nodes in model.
Note: If a node is detached from the model tree, you can manipulate it using it's API. However, it is very important that nodes already attached to model tree should be only changed through module:engine/model/writer~ModelWriter Writer API.
Changes done by
Nodemethods, like module:engine/model/element~ModelElement#_insertChild _insertChild or module:engine/model/node~ModelNode#_setAttribute _setAttribute do not generate module:engine/model/operation/operation~Operation operations which are essential for correct editor work if you modify nodes in module:engine/model/document~ModelDocument document root.The flow of working on
Node(and classes that inherits from it) is as such:Nodeinstance, modify it using it's API.Nodeto the model usingBatchAPI.Nodethat was already added to the model usingBatchAPI.Similarly, you cannot use
BatchAPI on a node that has not been added to the model tree, with the exception of module:engine/model/writer~ModelWriter#insert inserting that node to the model tree.Be aware that using module:engine/model/writer~ModelWriter#remove remove from Batch API does not allow to use
NodeAPI because the information aboutNodeis still kept in model document.In case of module:engine/model/element~ModelElement element node, adding and removing children also counts as changing a node and follows same rules.