3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
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.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * This is code is also distributed under MIT license for use
17 * with jQuery and prototype JavaScript libraries.
21 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
23 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/#selectors">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
26 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
28 <h4>Element Selectors:</h4>
30 <li> <b>*</b> any element</li>
31 <li> <b>E</b> an element with the tag E</li>
32 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
33 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
34 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
35 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
37 <h4>Attribute Selectors:</h4>
38 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
40 <li> <b>E[foo]</b> has an attribute "foo"</li>
41 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
42 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
43 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
44 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
45 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
46 <li> <b>E[foo!=bar]</b> attribute "foo" does not equal "bar"</li>
48 <h4>Pseudo Classes:</h4>
50 <li> <b>E:first-child</b> E is the first child of its parent</li>
51 <li> <b>E:last-child</b> E is the last child of its parent</li>
52 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
53 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
54 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
55 <li> <b>E:only-child</b> E is the only child of its parent</li>
56 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
57 <li> <b>E:first</b> the first E in the resultset</li>
58 <li> <b>E:last</b> the last E in the resultset</li>
59 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
60 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
61 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
62 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
63 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
64 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
65 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
66 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
67 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
68 <li> <b>E:any(S1|S2|S2)</b> an E element which matches any of the simple selectors S1, S2 or S3//\\</li>
70 <h4>CSS Value Selectors:</h4>
72 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
73 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
74 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
75 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
76 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
77 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
83 Ext.core.DomQuery = Ext.DomQuery = function(){
88 trimRe = /^\s+|\s+$/g,
90 modeRe = /^(\s?[\/>+~]\s?|\s|$)/,
91 tagTokenRe = /^(#)?([\w-\*]+)/,
92 nthRe = /(\d*)n\+?(\d*)/,
94 // This is for IE MSXML which does not support expandos.
95 // IE runs the same speed using setAttribute, however FF slows way down
96 // and Safari completely fails so they need to continue to use expandos.
97 isIE = window.ActiveXObject ? true : false,
100 // this eval is stop the compressor from
101 // renaming the variable to something shorter
102 eval("var batch = 30803;");
104 // Retrieve the child node from a particular
105 // parent at the specified index.
106 function child(parent, index){
108 n = parent.firstChild;
120 // retrieve the next element node
122 while((n = n.nextSibling) && n.nodeType != 1);
126 // retrieve the previous element node
128 while((n = n.previousSibling) && n.nodeType != 1);
132 // Mark each child node with a nodeIndex skipping and
133 // removing empty text nodes.
134 function children(parent){
135 var n = parent.firstChild,
139 nextNode = n.nextSibling;
140 // clean worthless empty nodes.
141 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
142 parent.removeChild(n);
144 // add an expando nodeIndex
145 n.nodeIndex = ++nodeIndex;
153 // nodeSet - array of nodes
155 function byClassName(nodeSet, cls){
159 var result = [], ri = -1;
160 for(var i = 0, ci; ci = nodeSet[i]; i++){
161 if((' '+ci.className+' ').indexOf(cls) != -1){
168 function attrValue(n, attr){
169 // if its an array, use the first node.
170 if(!n.tagName && typeof n.length != "undefined"){
180 if(attr == "class" || attr == "className"){
183 return n.getAttribute(attr) || n[attr];
189 // mode - false, /, >, +, ~
190 // tagName - defaults to "*"
191 function getNodes(ns, mode, tagName){
192 var result = [], ri = -1, cs;
196 tagName = tagName || "*";
198 if(typeof ns.getElementsByTagName != "undefined"){
202 // no mode specified, grab all elements by tagName
205 for(var i = 0, ni; ni = ns[i]; i++){
206 cs = ni.getElementsByTagName(tagName);
207 for(var j = 0, ci; ci = cs[j]; j++){
211 // Direct Child mode (/ or >)
212 // E > F or E/F all direct children elements of E that have the tag
213 } else if(mode == "/" || mode == ">"){
214 var utag = tagName.toUpperCase();
215 for(var i = 0, ni, cn; ni = ns[i]; i++){
217 for(var j = 0, cj; cj = cn[j]; j++){
218 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
223 // Immediately Preceding mode (+)
224 // E + F all elements with the tag F that are immediately preceded by an element with the tag E
225 }else if(mode == "+"){
226 var utag = tagName.toUpperCase();
227 for(var i = 0, n; n = ns[i]; i++){
228 while((n = n.nextSibling) && n.nodeType != 1);
229 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
234 // E ~ F all elements with the tag F that are preceded by a sibling element with the tag E
235 }else if(mode == "~"){
236 var utag = tagName.toUpperCase();
237 for(var i = 0, n; n = ns[i]; i++){
238 while((n = n.nextSibling)){
239 if (n.nodeName == utag || n.nodeName == tagName || tagName == '*'){
248 function concat(a, b){
252 for(var i = 0, l = b.length; i < l; i++){
258 function byTag(cs, tagName){
259 if(cs.tagName || cs == document){
265 var result = [], ri = -1;
266 tagName = tagName.toLowerCase();
267 for(var i = 0, ci; ci = cs[i]; i++){
268 if(ci.nodeType == 1 && ci.tagName.toLowerCase() == tagName){
275 function byId(cs, id){
276 if(cs.tagName || cs == document){
282 var result = [], ri = -1;
283 for(var i = 0, ci; ci = cs[i]; i++){
284 if(ci && ci.id == id){
292 // operators are =, !=, ^=, $=, *=, %=, |= and ~=
294 function byAttribute(cs, attr, value, op, custom){
297 useGetStyle = custom == "{",
298 fn = Ext.DomQuery.operators[op],
303 for(var i = 0, ci; ci = cs[i]; i++){
304 // skip non-element nodes.
305 if(ci.nodeType != 1){
308 // only need to do this for the first node
310 xml = Ext.DomQuery.isXml(ci);
314 // we only need to change the property names if we're dealing with html nodes, not XML
317 a = Ext.DomQuery.getStyle(ci, attr);
318 } else if (attr == "class" || attr == "className"){
320 } else if (attr == "for"){
322 } else if (attr == "href"){
323 // getAttribute href bug
324 // http://www.glennjones.net/Post/809/getAttributehrefbug.htm
325 a = ci.getAttribute("href", 2);
327 a = ci.getAttribute(attr);
330 a = ci.getAttribute(attr);
332 if((fn && fn(a, value)) || (!fn && a)){
339 function byPseudo(cs, name, value){
340 return Ext.DomQuery.pseudos[name](cs, value);
343 function nodupIEXml(cs){
346 cs[0].setAttribute("_nodup", d);
348 for(var i = 1, len = cs.length; i < len; i++){
350 if(!c.getAttribute("_nodup") != d){
351 c.setAttribute("_nodup", d);
355 for(var i = 0, len = cs.length; i < len; i++){
356 cs[i].removeAttribute("_nodup");
365 var len = cs.length, c, i, r = cs, cj, ri = -1;
366 if(!len || typeof cs.nodeType != "undefined" || len == 1){
369 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
370 return nodupIEXml(cs);
374 for(i = 1; c = cs[i]; i++){
379 for(var j = 0; j < i; j++){
382 for(j = i+1; cj = cs[j]; j++){
394 function quickDiffIEXml(c1, c2){
397 for(var i = 0, len = c1.length; i < len; i++){
398 c1[i].setAttribute("_qdiff", d);
400 for(var i = 0, len = c2.length; i < len; i++){
401 if(c2[i].getAttribute("_qdiff") != d){
405 for(var i = 0, len = c1.length; i < len; i++){
406 c1[i].removeAttribute("_qdiff");
411 function quickDiff(c1, c2){
412 var len1 = c1.length,
418 if(isIE && typeof c1[0].selectSingleNode != "undefined"){
419 return quickDiffIEXml(c1, c2);
421 for(var i = 0; i < len1; i++){
424 for(var i = 0, len = c2.length; i < len; i++){
425 if(c2[i]._qdiff != d){
432 function quickId(ns, mode, root, id){
434 var d = root.ownerDocument || root;
435 return d.getElementById(id);
437 ns = getNodes(ns, mode, "*");
442 getStyle : function(el, name){
443 return Ext.fly(el).getStyle(name);
446 * Compiles a selector/xpath query into a reusable function. The returned function
447 * takes one parameter "root" (optional), which is the context node from where the query should start.
448 * @param {String} selector The selector/xpath query
449 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
452 compile : function(path, type){
453 type = type || "select";
456 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"],
459 matchers = Ext.DomQuery.matchers,
460 matchersLn = matchers.length,
462 // accept leading mode switch
463 lmode = path.match(modeRe);
465 if(lmode && lmode[1]){
466 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
467 path = path.replace(lmode[1], "");
470 // strip leading slashes
471 while(path.substr(0, 1)=="/"){
472 path = path.substr(1);
475 while(path && lastPath != path){
477 var tokenMatch = path.match(tagTokenRe);
478 if(type == "select"){
481 if(tokenMatch[1] == "#"){
482 fn[fn.length] = 'n = quickId(n, mode, root, "'+tokenMatch[2]+'");';
484 fn[fn.length] = 'n = getNodes(n, mode, "'+tokenMatch[2]+'");';
486 path = path.replace(tokenMatch[0], "");
487 }else if(path.substr(0, 1) != '@'){
488 fn[fn.length] = 'n = getNodes(n, mode, "*");';
493 if(tokenMatch[1] == "#"){
494 fn[fn.length] = 'n = byId(n, "'+tokenMatch[2]+'");';
496 fn[fn.length] = 'n = byTag(n, "'+tokenMatch[2]+'");';
498 path = path.replace(tokenMatch[0], "");
501 while(!(modeMatch = path.match(modeRe))){
503 for(var j = 0; j < matchersLn; j++){
505 var m = path.match(t.re);
507 fn[fn.length] = t.select.replace(tplRe, function(x, i){
510 path = path.replace(m[0], "");
515 // prevent infinite loop on bad selector
519 sourceClass: 'Ext.DomQuery',
520 sourceMethod: 'compile',
521 msg: 'Error parsing selector. Parsing failed at "' + path + '"'
527 fn[fn.length] = 'mode="'+modeMatch[1].replace(trimRe, "")+'";';
528 path = path.replace(modeMatch[1], "");
532 fn[fn.length] = "return nodup(n);\n}";
534 // eval fn and return it
540 * Selects an array of DOM nodes using JavaScript-only implementation.
542 * Use {@link #select} to take advantage of browsers built-in support for CSS selectors.
544 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
545 * @param {Node/String} root (optional) The start of the query (defaults to document).
546 * @return {Array} An Array of DOM elements which match the selector. If there are
547 * no matches, and empty Array is returned.
549 jsSelect: function(path, root, type){
550 // set root to doc if not specified.
551 root = root || document;
553 if(typeof root == "string"){
554 root = document.getElementById(root);
556 var paths = path.split(","),
559 // loop over each selector
560 for(var i = 0, len = paths.length; i < len; i++){
561 var subPath = paths[i].replace(trimRe, "");
562 // compile and place in cache
564 cache[subPath] = Ext.DomQuery.compile(subPath);
568 sourceClass: 'Ext.DomQuery',
569 sourceMethod: 'jsSelect',
570 msg: subPath + ' is not a valid selector'
575 var result = cache[subPath](root);
576 if(result && result != document){
577 results = results.concat(result);
581 // if there were multiple selectors, make sure dups
583 if(paths.length > 1){
584 return nodup(results);
589 isXml: function(el) {
590 var docEl = (el ? el.ownerDocument || el : 0).documentElement;
591 return docEl ? docEl.nodeName !== "HTML" : false;
595 * Selects an array of DOM nodes by CSS/XPath selector.
597 * Uses [document.querySelectorAll][0] if browser supports that, otherwise falls back to
598 * {@link #jsSelect} to do the work.
600 * Aliased as {@link Ext#query}.
602 * [0]: https://developer.mozilla.org/en/DOM/document.querySelectorAll
604 * @param {String} path The selector/xpath query
605 * @param {Node} root (optional) The start of the query (defaults to document).
606 * @return {Array} An array of DOM elements (not a NodeList as returned by `querySelectorAll`).
607 * Empty array when no matches.
610 select : document.querySelectorAll ? function(path, root, type) {
611 root = root || document;
612 if (!Ext.DomQuery.isXml(root)) {
614 var cs = root.querySelectorAll(path);
615 return Ext.Array.toArray(cs);
619 return Ext.DomQuery.jsSelect.call(this, path, root, type);
620 } : function(path, root, type) {
621 return Ext.DomQuery.jsSelect.call(this, path, root, type);
625 * Selects a single element.
626 * @param {String} selector The selector/xpath query
627 * @param {Node} root (optional) The start of the query (defaults to document).
628 * @return {Element} The DOM element which matched the selector.
630 selectNode : function(path, root){
631 return Ext.DomQuery.select(path, root)[0];
635 * Selects the value of a node, optionally replacing null with the defaultValue.
636 * @param {String} selector The selector/xpath query
637 * @param {Node} root (optional) The start of the query (defaults to document).
638 * @param {String} defaultValue
641 selectValue : function(path, root, defaultValue){
642 path = path.replace(trimRe, "");
643 if(!valueCache[path]){
644 valueCache[path] = Ext.DomQuery.compile(path, "select");
646 var n = valueCache[path](root), v;
649 // overcome a limitation of maximum textnode size
650 // Rumored to potentially crash IE6 but has not been confirmed.
651 // http://reference.sitepoint.com/javascript/Node/normalize
652 // https://developer.mozilla.org/En/DOM/Node.normalize
653 if (typeof n.normalize == 'function') n.normalize();
655 v = (n && n.firstChild ? n.firstChild.nodeValue : null);
656 return ((v === null||v === undefined||v==='') ? defaultValue : v);
660 * Selects the value of a node, parsing integers and floats. Returns the defaultValue, or 0 if none is specified.
661 * @param {String} selector The selector/xpath query
662 * @param {Node} root (optional) The start of the query (defaults to document).
663 * @param {Number} defaultValue
666 selectNumber : function(path, root, defaultValue){
667 var v = Ext.DomQuery.selectValue(path, root, defaultValue || 0);
668 return parseFloat(v);
672 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
673 * @param {String/HTMLElement/Array} el An element id, element or array of elements
674 * @param {String} selector The simple selector to test
677 is : function(el, ss){
678 if(typeof el == "string"){
679 el = document.getElementById(el);
681 var isArray = Ext.isArray(el),
682 result = Ext.DomQuery.filter(isArray ? el : [el], ss);
683 return isArray ? (result.length == el.length) : (result.length > 0);
687 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
688 * @param {Array} el An array of elements to filter
689 * @param {String} selector The simple selector to test
690 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
691 * the selector instead of the ones that match
692 * @return {Array} An Array of DOM elements which match the selector. If there are
693 * no matches, and empty Array is returned.
695 filter : function(els, ss, nonMatches){
696 ss = ss.replace(trimRe, "");
697 if(!simpleCache[ss]){
698 simpleCache[ss] = Ext.DomQuery.compile(ss, "simple");
700 var result = simpleCache[ss](els);
701 return nonMatches ? quickDiff(result, els) : result;
705 * Collection of matching regular expressions and code snippets.
706 * Each capture group within () will be replace the {} in the select
707 * statement as specified by their index.
711 select: 'n = byClassName(n, " {1} ");'
713 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
714 select: 'n = byPseudo(n, "{1}", "{2}");'
716 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
717 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
720 select: 'n = byId(n, "{1}");'
723 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
728 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
729 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
732 "=" : function(a, v){
735 "!=" : function(a, v){
738 "^=" : function(a, v){
739 return a && a.substr(0, v.length) == v;
741 "$=" : function(a, v){
742 return a && a.substr(a.length-v.length) == v;
744 "*=" : function(a, v){
745 return a && a.indexOf(v) !== -1;
747 "%=" : function(a, v){
750 "|=" : function(a, v){
751 return a && (a == v || a.substr(0, v.length+1) == v+'-');
753 "~=" : function(a, v){
754 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
759 Object hash of "pseudo class" filter functions which are used when filtering selections.
760 Each function is passed two parameters:
763 An Array of DOM elements to filter.
766 The argument (if any) supplied in the selector.
768 A filter function returns an Array of DOM elements which conform to the pseudo class.
769 In addition to the provided pseudo classes listed above such as `first-child` and `nth-child`,
770 developers may add additional, custom psuedo class filters to select elements according to application-specific requirements.
772 For example, to filter `a` elements to only return links to __external__ resources:
774 Ext.DomQuery.pseudos.external = function(c, v){
776 for(var i = 0, ci; ci = c[i]; i++){
777 // Include in result set only if it's a link to an external resource
778 if(ci.hostname != location.hostname){
785 Then external links could be gathered with the following statement:
787 var externalLinks = Ext.select("a:external");
792 "first-child" : function(c){
793 var r = [], ri = -1, n;
794 for(var i = 0, ci; ci = n = c[i]; i++){
795 while((n = n.previousSibling) && n.nodeType != 1);
803 "last-child" : function(c){
804 var r = [], ri = -1, n;
805 for(var i = 0, ci; ci = n = c[i]; i++){
806 while((n = n.nextSibling) && n.nodeType != 1);
814 "nth-child" : function(c, a) {
816 m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a),
817 f = (m[1] || 1) - 0, l = m[2] - 0;
818 for(var i = 0, n; n = c[i]; i++){
819 var pn = n.parentNode;
820 if (batch != pn._batch) {
822 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
823 if(cn.nodeType == 1){
830 if (l == 0 || n.nodeIndex == l){
833 } else if ((n.nodeIndex + l) % f == 0){
841 "only-child" : function(c){
842 var r = [], ri = -1;;
843 for(var i = 0, ci; ci = c[i]; i++){
844 if(!prev(ci) && !next(ci)){
851 "empty" : function(c){
853 for(var i = 0, ci; ci = c[i]; i++){
854 var cns = ci.childNodes, j = 0, cn, empty = true;
857 if(cn.nodeType == 1 || cn.nodeType == 3){
869 "contains" : function(c, v){
871 for(var i = 0, ci; ci = c[i]; i++){
872 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
879 "nodeValue" : function(c, v){
881 for(var i = 0, ci; ci = c[i]; i++){
882 if(ci.firstChild && ci.firstChild.nodeValue == v){
889 "checked" : function(c){
891 for(var i = 0, ci; ci = c[i]; i++){
892 if(ci.checked == true){
899 "not" : function(c, ss){
900 return Ext.DomQuery.filter(c, ss, true);
903 "any" : function(c, selectors){
904 var ss = selectors.split('|'),
906 for(var i = 0, ci; ci = c[i]; i++){
907 for(var j = 0; s = ss[j]; j++){
908 if(Ext.DomQuery.is(ci, s)){
918 return this["nth-child"](c, "odd");
921 "even" : function(c){
922 return this["nth-child"](c, "even");
925 "nth" : function(c, a){
929 "first" : function(c){
933 "last" : function(c){
934 return c[c.length-1] || [];
937 "has" : function(c, ss){
938 var s = Ext.DomQuery.select,
940 for(var i = 0, ci; ci = c[i]; i++){
941 if(s(ss, ci).length > 0){
948 "next" : function(c, ss){
949 var is = Ext.DomQuery.is,
951 for(var i = 0, ci; ci = c[i]; i++){
960 "prev" : function(c, ss){
961 var is = Ext.DomQuery.is,
963 for(var i = 0, ci; ci = c[i]; i++){
976 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Ext.DomQuery#select}
977 * @param {String} path The selector/xpath query
978 * @param {Node} root (optional) The start of the query (defaults to document).
983 Ext.query = Ext.DomQuery.select;