/** * A Traversable mixin. * @private */Ext.define('Ext.mixin.Traversable', { extend: 'Ext.Mixin', mixinConfig: { id: 'traversable' }, setParent: function(parent) { this.parent = parent; return this; }, /** * Returns `true` if this component has a parent. * @return {Boolean} `true` if this component has a parent. */ hasParent: function() { return Boolean(this.getParent()); }, /** * @template * Selector processing function for use by {@link #nextSibling},{@link #previousibling}, * {@link #nextNode},and {@link #previousNode}, to filter candidate nodes. * * The base implementation returns true. Classes which mix in `Traversable` may implement * their own implementations. `@link{Ext.Widget}` does this to implement * {@link Ext.ComponentQuery} based filterability. * @returns {boolean} */ is: function() { return true; }, /** * Returns the parent of this component, if it has one. * @return {Ext.Component} The parent of this component. */ getParent: function() { return this.parent || this.$initParent; }, getAncestors: function() { var ancestors = [], parent = this.getParent(); while (parent) { ancestors.push(parent); parent = parent.getParent(); } return ancestors; }, getAncestorIds: function() { var ancestorIds = [], parent = this.getParent(); while (parent) { ancestorIds.push(parent.getId()); parent = parent.getParent(); } return ancestorIds; }, /** * Returns the previous node in the Component tree in tree traversal order. * * Note that this is not limited to siblings, and if invoked upon a node with no matching * siblings, will walk the tree in reverse order to attempt to find a match. Contrast with * {@link #previousSibling}. * @param {String} [selector] A {@link Ext.ComponentQuery ComponentQuery} selector to filter * the preceding nodes. * @param includeSelf (private) * @return {Ext.Component} The previous node (or the previous node which matches the selector). * Returns `null` if there is no matching node. */ previousNode: function(selector, includeSelf) { var node = this, parent = node.getRefOwner(), result, it, i, sibling; // If asked to include self, test me if (includeSelf && node.is(selector)) { return node; } if (parent) { for (it = parent.items.items, i = Ext.Array.indexOf(it, node) - 1; i > -1; i--) { sibling = it[i]; if (sibling.query) { result = sibling.query(selector); result = result[result.length - 1]; if (result) { return result; } } if (!selector || sibling.is(selector)) { return sibling; } } return parent.previousNode(selector, true); } return null; }, /** * Returns the previous sibling of this Component. * * Optionally selects the previous sibling which matches the passed * {@link Ext.ComponentQuery ComponentQuery} selector. * * May also be referred to as **`prev()`** * * Note that this is limited to siblings, and if no siblings of the item match, `null` * is returned. Contrast with {@link #previousNode} * @param {String} [selector] A {@link Ext.ComponentQuery ComponentQuery} selector to filter * the preceding items. * @return {Ext.Component} The previous sibling (or the previous sibling which matches * the selector). Returns `null` if there is no matching sibling. */ previousSibling: function(selector) { var parent = this.getRefOwner(), it, idx, sibling; if (parent) { it = parent.items; idx = it.indexOf(this); if (idx !== -1) { if (selector) { for (--idx; idx >= 0; idx--) { if ((sibling = it.getAt(idx)).is(selector)) { return sibling; } } } else { if (idx) { return it.getAt(--idx); } } } } return null; }, /** * Returns the next node in the Component tree in tree traversal order. * * Note that this is not limited to siblings, and if invoked upon a node with no matching * siblings, will walk the tree to attempt to find a match. Contrast with {@link #nextSibling}. * @param {String} [selector] A {@link Ext.ComponentQuery ComponentQuery} selector to filter * the following nodes. * @param includeSelf (private) * @return {Ext.Component} The next node (or the next node which matches the selector). * Returns `null` if there is no matching node. */ nextNode: function(selector, includeSelf) { var node = this, parent = node.getRefOwner(), result, it, len, i, sibling; // If asked to include self, test me if (includeSelf && node.is(selector)) { return node; } if (parent) { // eslint-disable-next-line max-len for (it = parent.items.items, i = Ext.Array.indexOf(it, node) + 1, len = it.length; i < len; i++) { sibling = it[i]; if (!selector || sibling.is(selector)) { return sibling; } if (sibling.down) { result = sibling.down(selector); if (result) { return result; } } } return parent.nextNode(selector); } return null; }, /** * Returns the next sibling of this Component. * * Optionally selects the next sibling which matches the passed * {@link Ext.ComponentQuery ComponentQuery} selector. * * May also be referred to as **`next()`** * * Note that this is limited to siblings, and if no siblings of the item match, `null` * is returned. Contrast with {@link #nextNode} * @param {String} [selector] A {@link Ext.ComponentQuery ComponentQuery} selector to filter * the following items. * @return {Ext.Component} The next sibling (or the next sibling which matches the selector). * Returns `null` if there is no matching sibling. */ nextSibling: function(selector) { var parent = this.getRefOwner(), it, last, idx, sibling; if (parent) { it = parent.items; idx = it.indexOf(this) + 1; if (idx) { if (selector) { for (last = it.getCount(); idx < last; idx++) { if ((sibling = it.getAt(idx)).is(selector)) { return sibling; } } } else { if (idx < it.getCount()) { return it.getAt(idx); } } } } return null; }});