| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- /**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
- 'use strict';
- import clone from '../lib/lodash/clone.js';
- import utils from '../utils.js';
- import CKEditorError from '../ckeditorerror.js';
- /**
- * Tree model node. This is an abstract class for other classes representing different nodes in Tree Model.
- *
- * @memberOf core.treeModel
- */
- export default class Node {
- /**
- * Creates a tree node.
- *
- * This is an abstract class, so this constructor should not be used directly.
- *
- * @param {Iterable|Object} attrs Iterable collection of attributes.
- * @abstract
- */
- constructor( attrs ) {
- /**
- * Parent element. Null by default. Set by {@link core.treeModel.Element#insertChildren}.
- *
- * @readonly
- * @member {core.treeModel.Element|null} core.treeModel.Node#parent
- */
- this.parent = null;
- /**
- * List of attributes set on this node.
- *
- * **Note:** It is **important** that attributes of nodes already attached to the document must be changed
- * only by an {@link core.treeModel.operation.AttributeOperation}. Do not set attributes of such nodes
- * using {@link core.treeModel.Node} methods.
- *
- * @protected
- * @member {Map} core.treeModel.Node#_attrs
- */
- this._attrs = utils.toMap( attrs );
- }
- /**
- * Depth of the node, which equals to total number of its parents.
- *
- * @readonly
- * @type {Number}
- */
- get depth() {
- let depth = 0;
- let parent = this.parent;
- while ( parent ) {
- depth++;
- parent = parent.parent;
- }
- return depth;
- }
- /**
- * Nodes next sibling or `null` if it is the last child.
- *
- * @readonly
- * @type {core.treeModel.Node|null}
- */
- get nextSibling() {
- const index = this.getIndex();
- return ( index !== null && this.parent.getChild( index + 1 ) ) || null;
- }
- /**
- * Nodes previous sibling or null if it is the last child.
- *
- * @readonly
- * @type {core.treeModel.Node|null}
- */
- get previousSibling() {
- const index = this.getIndex();
- return ( index !== null && this.parent.getChild( index - 1 ) ) || null;
- }
- /**
- * The top parent for the node. If node has no parent it is the root itself.
- *
- * @readonly
- * @type {Number}
- */
- get root() {
- let root = this;
- while ( root.parent ) {
- root = root.parent;
- }
- return root;
- }
- /**
- * Index of the node in the parent element or null if the node has no parent.
- *
- * Throws error if the parent element does not contain this node.
- *
- * @returns {Number|Null} Index of the node in the parent element or null if the node has not parent.
- */
- getIndex() {
- let pos;
- if ( !this.parent ) {
- return null;
- }
- if ( ( pos = this.parent.getChildIndex( this ) ) == -1 ) {
- /**
- * The node's parent does not contain this node.
- *
- * @error node-not-found-in-parent
- */
- throw new CKEditorError( 'node-not-found-in-parent: The node\'s parent does not contain this node.' );
- }
- return pos;
- }
- /**
- * Gets path to the node. For example if the node is the second child of the first child of the root then the path
- * will be `[ 1, 2 ]`. This path can be used as a parameter of {@link core.treeModel.Position}.
- *
- * @returns {Number[]} The path.
- */
- getPath() {
- const path = [];
- let node = this;
- while ( node.parent ) {
- path.unshift( node.getIndex() );
- node = node.parent;
- }
- return path;
- }
- /**
- * Checks if the node has an attribute for given key.
- *
- * @param {String} key Key of attribute to check.
- * @returns {Boolean} `true` if attribute with given key is set on node, `false` otherwise.
- */
- hasAttribute( key ) {
- return this._attrs.has( key );
- }
- /**
- * Gets an attribute value for given key or undefined if that attribute is not set on node.
- *
- * @param {String} key Key of attribute to look for.
- * @returns {*} Attribute value or null.
- */
- getAttribute( key ) {
- return this._attrs.get( key );
- }
- /**
- * Returns iterator that iterates over this node attributes.
- *
- * @returns {Iterable.<*>}
- */
- getAttributes() {
- return this._attrs[ Symbol.iterator ]();
- }
- /**
- * Custom toJSON method to solve child-parent circular dependencies.
- *
- * @returns {Object} Clone of this object with the parent property replaced with its name.
- */
- toJSON() {
- const json = clone( this );
- // Due to circular references we need to remove parent reference.
- json.parent = this.parent ? this.parent.name : null;
- return json;
- }
- }
|