Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / src / core / src / dom / Element.traversal.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @class Ext.Element
17  */
18 Ext.Element.addMethods({
19     /**
20      * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
21      * @param {String} selector The simple selector to test
22      * @param {Number/String/HTMLElement/Ext.Element} maxDepth (optional)
23      * The max depth to search as a number or element (defaults to 50 || document.body)
24      * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
25      * @return {HTMLElement} The matching DOM node (or null if no match was found)
26      */
27     findParent : function(simpleSelector, maxDepth, returnEl) {
28         var p = this.dom,
29             b = document.body,
30             depth = 0,
31             stopEl;
32
33         maxDepth = maxDepth || 50;
34         if (isNaN(maxDepth)) {
35             stopEl = Ext.getDom(maxDepth);
36             maxDepth = Number.MAX_VALUE;
37         }
38         while (p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl) {
39             if (Ext.DomQuery.is(p, simpleSelector)) {
40                 return returnEl ? Ext.get(p) : p;
41             }
42             depth++;
43             p = p.parentNode;
44         }
45         return null;
46     },
47
48     /**
49      * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
50      * @param {String} selector The simple selector to test
51      * @param {Number/String/HTMLElement/Ext.Element} maxDepth (optional)
52      * The max depth to search as a number or element (defaults to 10 || document.body)
53      * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
54      * @return {HTMLElement} The matching DOM node (or null if no match was found)
55      */
56     findParentNode : function(simpleSelector, maxDepth, returnEl) {
57         var p = Ext.fly(this.dom.parentNode, '_internal');
58         return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
59     },
60
61     /**
62      * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
63      * This is a shortcut for findParentNode() that always returns an Ext.Element.
64      * @param {String} selector The simple selector to test
65      * @param {Number/String/HTMLElement/Ext.Element} maxDepth (optional)
66      * The max depth to search as a number or element (defaults to 10 || document.body)
67      * @return {Ext.Element} The matching DOM node (or null if no match was found)
68      */
69     up : function(simpleSelector, maxDepth) {
70         return this.findParentNode(simpleSelector, maxDepth, true);
71     },
72
73     /**
74      * Creates a {@link Ext.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
75      * @param {String} selector The CSS selector
76      * @return {Ext.CompositeElement/Ext.CompositeElement} The composite element
77      */
78     select : function(selector) {
79         return Ext.Element.select(selector, false,  this.dom);
80     },
81
82     /**
83      * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
84      * @param {String} selector The CSS selector
85      * @return {HTMLElement[]} An array of the matched nodes
86      */
87     query : function(selector) {
88         return Ext.DomQuery.select(selector, this.dom);
89     },
90
91     /**
92      * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
93      * @param {String} selector The CSS selector
94      * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.Element (defaults to false)
95      * @return {HTMLElement/Ext.Element} The child Ext.Element (or DOM node if returnDom = true)
96      */
97     down : function(selector, returnDom) {
98         var n = Ext.DomQuery.selectNode(selector, this.dom);
99         return returnDom ? n : Ext.get(n);
100     },
101
102     /**
103      * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
104      * @param {String} selector The CSS selector
105      * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.Element (defaults to false)
106      * @return {HTMLElement/Ext.Element} The child Ext.Element (or DOM node if returnDom = true)
107      */
108     child : function(selector, returnDom) {
109         var node,
110             me = this,
111             id;
112         id = Ext.get(me).id;
113         // Escape . or :
114         id = id.replace(/[\.:]/g, "\\$0");
115         node = Ext.DomQuery.selectNode('#' + id + " > " + selector, me.dom);
116         return returnDom ? node : Ext.get(node);
117     },
118
119      /**
120      * Gets the parent node for this element, optionally chaining up trying to match a selector
121      * @param {String} selector (optional) Find a parent node that matches the passed simple selector
122      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
123      * @return {Ext.Element/HTMLElement} The parent node or null
124      */
125     parent : function(selector, returnDom) {
126         return this.matchNode('parentNode', 'parentNode', selector, returnDom);
127     },
128
129      /**
130      * Gets the next sibling, skipping text nodes
131      * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
132      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
133      * @return {Ext.Element/HTMLElement} The next sibling or null
134      */
135     next : function(selector, returnDom) {
136         return this.matchNode('nextSibling', 'nextSibling', selector, returnDom);
137     },
138
139     /**
140      * Gets the previous sibling, skipping text nodes
141      * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
142      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
143      * @return {Ext.Element/HTMLElement} The previous sibling or null
144      */
145     prev : function(selector, returnDom) {
146         return this.matchNode('previousSibling', 'previousSibling', selector, returnDom);
147     },
148
149
150     /**
151      * Gets the first child, skipping text nodes
152      * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
153      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
154      * @return {Ext.Element/HTMLElement} The first child or null
155      */
156     first : function(selector, returnDom) {
157         return this.matchNode('nextSibling', 'firstChild', selector, returnDom);
158     },
159
160     /**
161      * Gets the last child, skipping text nodes
162      * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
163      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
164      * @return {Ext.Element/HTMLElement} The last child or null
165      */
166     last : function(selector, returnDom) {
167         return this.matchNode('previousSibling', 'lastChild', selector, returnDom);
168     },
169
170     matchNode : function(dir, start, selector, returnDom) {
171         if (!this.dom) {
172             return null;
173         }
174
175         var n = this.dom[start];
176         while (n) {
177             if (n.nodeType == 1 && (!selector || Ext.DomQuery.is(n, selector))) {
178                 return !returnDom ? Ext.get(n) : n;
179             }
180             n = n[dir];
181         }
182         return null;
183     }
184 });
185