Upgrade to ExtJS 4.0.2 - Released 06/09/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.core.Element
17  */
18 Ext.core.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/Mixed} maxDepth (optional) The max depth to search as a number or element (defaults to 50 || document.body)
23      * @param {Boolean} returnEl (optional) True to return a Ext.core.Element object instead of DOM node
24      * @return {HTMLElement} The matching DOM node (or null if no match was found)
25      */
26     findParent : function(simpleSelector, maxDepth, returnEl) {
27         var p = this.dom,
28             b = document.body,
29             depth = 0,
30             stopEl;
31
32         maxDepth = maxDepth || 50;
33         if (isNaN(maxDepth)) {
34             stopEl = Ext.getDom(maxDepth);
35             maxDepth = Number.MAX_VALUE;
36         }
37         while (p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl) {
38             if (Ext.DomQuery.is(p, simpleSelector)) {
39                 return returnEl ? Ext.get(p) : p;
40             }
41             depth++;
42             p = p.parentNode;
43         }
44         return null;
45     },
46     
47     /**
48      * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
49      * @param {String} selector The simple selector to test
50      * @param {Number/Mixed} maxDepth (optional) The max depth to
51             search as a number or element (defaults to 10 || document.body)
52      * @param {Boolean} returnEl (optional) True to return a Ext.core.Element object instead of DOM node
53      * @return {HTMLElement} The matching DOM node (or null if no match was found)
54      */
55     findParentNode : function(simpleSelector, maxDepth, returnEl) {
56         var p = Ext.fly(this.dom.parentNode, '_internal');
57         return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
58     },
59
60     /**
61      * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
62      * This is a shortcut for findParentNode() that always returns an Ext.core.Element.
63      * @param {String} selector The simple selector to test
64      * @param {Number/Mixed} maxDepth (optional) The max depth to
65             search as a number or element (defaults to 10 || document.body)
66      * @return {Ext.core.Element} The matching DOM node (or null if no match was found)
67      */
68     up : function(simpleSelector, maxDepth) {
69         return this.findParentNode(simpleSelector, maxDepth, true);
70     },
71
72     /**
73      * Creates a {@link Ext.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
74      * @param {String} selector The CSS selector
75      * @return {CompositeElement/CompositeElement} The composite element
76      */
77     select : function(selector) {
78         return Ext.core.Element.select(selector, false,  this.dom);
79     },
80
81     /**
82      * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
83      * @param {String} selector The CSS selector
84      * @return {Array} An array of the matched nodes
85      */
86     query : function(selector) {
87         return Ext.DomQuery.select(selector, this.dom);
88     },
89
90     /**
91      * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
92      * @param {String} selector The CSS selector
93      * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.core.Element (defaults to false)
94      * @return {HTMLElement/Ext.core.Element} The child Ext.core.Element (or DOM node if returnDom = true)
95      */
96     down : function(selector, returnDom) {
97         var n = Ext.DomQuery.selectNode(selector, this.dom);
98         return returnDom ? n : Ext.get(n);
99     },
100
101     /**
102      * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
103      * @param {String} selector The CSS selector
104      * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.core.Element (defaults to false)
105      * @return {HTMLElement/Ext.core.Element} The child Ext.core.Element (or DOM node if returnDom = true)
106      */
107     child : function(selector, returnDom) {
108         var node,
109             me = this,
110             id;
111         id = Ext.get(me).id;
112         // Escape . or :
113         id = id.replace(/[\.:]/g, "\\$0");
114         node = Ext.DomQuery.selectNode('#' + id + " > " + selector, me.dom);
115         return returnDom ? node : Ext.get(node);
116     },
117
118      /**
119      * Gets the parent node for this element, optionally chaining up trying to match a selector
120      * @param {String} selector (optional) Find a parent node that matches the passed simple selector
121      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.core.Element
122      * @return {Ext.core.Element/HTMLElement} The parent node or null
123      */
124     parent : function(selector, returnDom) {
125         return this.matchNode('parentNode', 'parentNode', selector, returnDom);
126     },
127
128      /**
129      * Gets the next sibling, skipping text nodes
130      * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
131      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.core.Element
132      * @return {Ext.core.Element/HTMLElement} The next sibling or null
133      */
134     next : function(selector, returnDom) {
135         return this.matchNode('nextSibling', 'nextSibling', selector, returnDom);
136     },
137
138     /**
139      * Gets the previous sibling, skipping text nodes
140      * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
141      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.core.Element
142      * @return {Ext.core.Element/HTMLElement} The previous sibling or null
143      */
144     prev : function(selector, returnDom) {
145         return this.matchNode('previousSibling', 'previousSibling', selector, returnDom);
146     },
147
148
149     /**
150      * Gets the first child, skipping text nodes
151      * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
152      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.core.Element
153      * @return {Ext.core.Element/HTMLElement} The first child or null
154      */
155     first : function(selector, returnDom) {
156         return this.matchNode('nextSibling', 'firstChild', selector, returnDom);
157     },
158
159     /**
160      * Gets the last child, skipping text nodes
161      * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
162      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.core.Element
163      * @return {Ext.core.Element/HTMLElement} The last child or null
164      */
165     last : function(selector, returnDom) {
166         return this.matchNode('previousSibling', 'lastChild', selector, returnDom);
167     },
168
169     matchNode : function(dir, start, selector, returnDom) {
170         if (!this.dom) {
171             return null;
172         }
173         
174         var n = this.dom[start];
175         while (n) {
176             if (n.nodeType == 1 && (!selector || Ext.DomQuery.is(n, selector))) {
177                 return !returnDom ? Ext.get(n) : n;
178             }
179             n = n[dir];
180         }
181         return null;
182     }
183 });
184