`
jljlpch
  • 浏览: 318942 次
  • 性别: Icon_minigender_1
  • 来自: 南昌
社区版块
存档分类
最新评论

Ext.DomQuery源码

    博客分类:
  • Ext
阅读更多
/*
 * author:prk
 * date:2008-08-03
 * comment:analyse for Ext.DomQuery 
 * 
 */
/*
 * Ext JS Library 2.0.2
 * Copyright(c) 2006-2008, Ext JS, LLC.
 * licensing@extjs.com
 * 
 * http://extjs.com/license
 */

/*
 * This is code is also distributed under MIT license for use
 * with jQuery and prototype JavaScript libraries.
 */
/**
 * @class Ext.DomQuery
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).
<p>
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>

<p>
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.
</p>
<h4>Element Selectors:</h4>
<ul class="list">
    <li> <b>*</b> any element</li>
    <li> <b>E</b> an element with the tag E</li>
    <li> <b>E F</b> All descendent elements of E that have the tag F</li>
    <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
    <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
    <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
</ul>
<h4>Attribute Selectors:</h4>
<p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
<ul class="list">
    <li> <b>E[foo]</b> has an attribute "foo"</li>
    <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
    <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
    <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
    <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
    <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
    <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
</ul>
<h4>Pseudo Classes:</h4>
<ul class="list">
    <li> <b>E:first-child</b> E is the first child of its parent</li>
    <li> <b>E:last-child</b> E is the last child of its parent</li>
    <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>
    <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
    <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
    <li> <b>E:only-child</b> E is the only child of its parent</li>
    <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>
    <li> <b>E:first</b> the first E in the resultset</li>
    <li> <b>E:last</b> the last E in the resultset</li>
    <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
    <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
    <li> <b>E:even</b> shortcut for :nth-child(even)</li>
    <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
    <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
    <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
    <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
    <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
    <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
</ul>
<h4>CSS Value Selectors:</h4>
<ul class="list">
    <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
    <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
    <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
    <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
    <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
    <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
</ul>
 * @singleton
 */
 
 /*
    Element Node.ELEMENT_NODE 1 
    Text Node.TEXT_NODE 3 
    Document Node.DOCUMENT_NODE 9 
    Comment Node.COMMENT_NODE 8 
    DocumentFragment Node.DOCUMENT_FRAGMENT_NODE 11 
    Attr Node.ATTRIBUTE_NODE 2
  */
Ext.DomQuery = function(){
    var cache = {}, simpleCache = {}, valueCache = {};
    var nonSpace = /\S/;
    var trimRe = /^\s+|\s+$/g;
    //{2}
    var tplRe = /\{(\d+)\}/g;
    //' [/>+~] ' | ' ' | ''
    var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
    // '#xxx'|'*'|p|a
    var tagTokenRe = /^(#)?([\w-\*]+)/;
    //3 n+ 3  not digit  
    var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
    
     //E:nth-child(n) 找到p的第index个孩子节点(element)
    function child(p, index){
        var i = 0;
        var n = p.firstChild;
        while(n){
        	//nodeType == 1:Element
            if(n.nodeType == 1){
               if(++i == index){
                   return n;
               }
            }
            n = n.nextSibling;
        }
        return null;
    };
    
    //E:next(S) 找到n的下一个节点(element)
    function next(n){
        while((n = n.nextSibling) && n.nodeType != 1);
        return n;
    };
    
   //E:prev(S)  找到n的前一个节点(element)
    function prev(n){
        while((n = n.previousSibling) && n.nodeType != 1);
        return n;
    };
    
     //为节点的子节点标上顺序号,同时删除空白字符的节点
    function children(d){
        var n = d.firstChild, ni = -1;
 	    while(n){
 	        var nx = n.nextSibling;
 	        //Text 类型同时文本为空
 	        if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
 	        	//删除空白字符的节点。FF,IE兼容
 	            d.removeChild(n);
 	        }else{
 	        	//为节点加上index
 	            n.nodeIndex = ++ni;
 	        }
 	        n = nx;
 	    }
 	    return this;
 	};
    //c:element, v:value=class   a:attr没用到   byClassName(n,null,"foo")
 	//通过class名字在C中找class相同或相容的所有元素
    function byClassName(c, a, v){
       //value is not exist
    	if(!v){
            return c;
        }
        var r = [], ri = -1, cn;
        for(var i = 0, ci; ci = c[i]; i++){
        	 //v在不在ci.className中?
            if((' '+ci.className+' ').indexOf(v) != -1){
                r[++ri] = ci;
            }
        }
        return r;
    };
   // n: [{tagName:div,htmlFor:xxx,className:xxx}]  node
    //从n[0]中元素找到attr的属性值
    function attrValue(n, attr){
        if(!n.tagName && typeof n.length != "undefined"){
            n = n[0];
        }
        if(!n){
            return null;
        }
        if(attr == "for"){
            return n.htmlFor;
        }
        if(attr == "class" || attr == "className"){
            return n.className;
        }
        //n可以是Element,也可以是{}
        return n.getAttribute(attr) || n[attr];

    };
     
    //ns ;nodes   Element Selectors
    //通过tagName在ns中找tagName与之相同且符合mode运算条件的所有元素
    function getNodes(ns, mode, tagName){
        var result = [], ri = -1, cs;
        if(!ns){
            return result;
        }
        tagName = tagName || "*";
        //支持单个元素,转换成统一的数组形式,便于操作
        if(typeof ns.getElementsByTagName != "undefined"){
            ns = [ns];//转换成数组
        }
        //mode不存在或为空等,返回其下所有的与tagName相同的元素
        if(!mode){
            for(var i = 0, ni; ni = ns[i]; i++){
            	//找到ni下面所有tagName的子标签
                cs = ni.getElementsByTagName(tagName);
                //把找到的所有cs的Element存在result
                for(var j = 0, ci; ci = cs[j]; j++){
                    result[++ri] = ci;
                }
            }
        }
        // E > F or E/F 返回e所有tagName相同的直接子节点或全部子节点      
        else if(mode == "/" || mode == ">"){
            var utag = tagName.toUpperCase();
            for(var i = 0, ni, cn; ni = ns[i]; i++){
            	//ni的所有直接子节点,IE/FF兼容,
                cn = ni.children || ni.childNodes;
                for(var j = 0, cj; cj = cn[j]; j++){
                	//tagName相等或tagName == '*'
                    if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
                        //把找到的所有cs的Element存在result
                        result[++ri] = cj;
                    }
                }
            }
        }
        // E + F 返回e的第一个后续兄弟节点(element)。其tagName必须等于F或*。        
        else if(mode == "+"){
            var utag = tagName.toUpperCase();
            for(var i = 0, n; n = ns[i]; i++){
            	//n的下一个兄弟不是element的,
                while((n = n.nextSibling) && n.nodeType != 1);
                //找到n的下一个兄弟是Element的。
                if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
                    result[++ri] = n;
                }
            }
        }
         //E ~ F 返回e的所有后续兄弟节点(element),其tagName必须等于F或*。  
        ///E节点后面的所有兄弟节点F
        else if(mode == "~"){
            for(var i = 0, n; n = ns[i]; i++){
            	//下一个兄弟存在,同时不是元素或tagName == '*'或tagName不相同
                while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
               
                //下一个兄弟存在,是元素同时(tagName != '*'或tagName相同)
                if(n){
                    result[++ri] = n;
                }
            }
        }
        return result;
    };
   
    function concat(a, b){
    	//有可能是节点集合,node Collection(getElementsByTagName),  arguments  is array-like  .    	          
        if(b.slice){
            return a.concat(b);
        }
        //把b中所有元素追加到a中。
        for(var i = 0, l = b.length; i < l; i++){
            a[a.length] = b[i];
        }
        return a;
    }
    //通过tagName在cs中找到与之相同tagName的所有元素
    function byTag(cs, tagName){
        if(cs.tagName || cs == document){
            cs = [cs];
        }
        if(!tagName){
            return cs;
        }
        var r = [], ri = -1;
        tagName = tagName.toLowerCase();
        for(var i = 0, ci; ci = cs[i]; i++){
            if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
                r[++ri] = ci;
            }
        }
        return r;
    };
    
 
  //通过id在cs中找到与之相同的id的所有元素
    function byId(cs, attr, id){
        if(cs.tagName || cs == document){
            cs = [cs];
        }
        if(!id){
            return cs;
        }
        var r = [], ri = -1;
        for(var i = 0,ci; ci = cs[i]; i++){
            if(ci && ci.id == id){
                r[++ri] = ci;
                return r;
            }
        }
        return r;
    };
    //CSS selector,and attribute Selector   
    //通过CSS属性或自身的属性找到value相同且符合op操作关系的所有CS中元素
    function byAttribute(cs, attr, value, op, custom){
        var r = [], ri = -1, st = custom=="{";//表示从style中取属性做比较,CSS Value Selectors
        var f = Ext.DomQuery.operators[op];//Dom的操作符
        for(var i = 0, ci; ci = cs[i]; i++){
            var a;
           //找到attr的属性值
            if(st){//CSS Value Selectors
                a = Ext.DomQuery.getStyle(ci, attr);
            }
            //纯的Attribute Selectors,
            else if(attr == "class" || attr == "className"){
                a = ci.className;
            }else if(attr == "for"){
                a = ci.htmlFor;
            }else if(attr == "href"){
                a = ci.getAttribute("href", 2);
            }else{
                a = ci.getAttribute(attr);
            }
            //如果能找到操作符,说明不是单一属性,不能彩采用找到attr的属性值来做比较
            //如果能找到操作符,运算看看是否满足条件,满足的话,就表明当前的ci是要寻找的。
            //如果不能找到操作符,说明采用attr的属性名来做比较
            if((f && f(a, value)) || (!f && a)){
                r[++ri] = ci;
            }
        }
        return r;
    };

    function byPseudo(cs, name, value){
        return Ext.DomQuery.pseudos[name](cs, value);
    };

    // This is for IE MSXML which does not support expandos.
    // IE runs the same speed using setAttribute, however FF slows way down
    // and Safari completely fails so they need to continue to use expandos.
    var isIE = window.ActiveXObject ? true : false;

    // this eval is stop the compressor from
    // renaming the variable to something shorter
    eval("var batch = 30803;");

    var key = 30803;
    
    //找到不重复的元素,重新组成数组返回,IE为元素加属性只能通过setAttribute
    function nodupIEXml(cs){
        var d = ++key;
        cs[0].setAttribute("_nodup", d);
        var r = [cs[0]];
        for(var i = 1, len = cs.length; i < len; i++){
            var c = cs[i];
            if(!c.getAttribute("_nodup") != d){
                c.setAttribute("_nodup", d);
                r[r.length] = c;
            }
        }
        //去掉已经加上的属性
        for(var i = 0, len = cs.length; i < len; i++){
            cs[i].removeAttribute("_nodup");
        }
        return r;
    }
    //在数组中取不重复的元素的集合
    function nodup(cs){
        if(!cs){
            return [];
        }
        var len = cs.length, c, i, r = cs, cj, ri = -1;
        //elements no length or length==1
        if(!len || typeof cs.nodeType != "undefined" || len == 1){
            return cs;
        }
        if(isIE && typeof cs[0].selectSingleNode != "undefined"){
            return nodupIEXml(cs);
        }
        var d = ++key;
        //cs[0]的元素有可能在Cs中多处出现,也就是说数组中不是唯一的元素。
        cs[0]._nodup = d;
        for(i = 1; c = cs[i]; i++){
            if(c._nodup != d){
                c._nodup = d;
            }else{
                r = [];
                //找到c._nodup = d的元素前面的所有元素,存起来
                for(var j = 0; j < i; j++){
                    r[++ri] = cs[j];
                }
                //跳过c._nodup==d的元素
                //找到c._nodup = d的元素后面的所有元素,如果其_nodup != d,设定为d,存起来
                for(j = i+1; cj = cs[j]; j++){
                    if(cj._nodup != d){
                        cj._nodup = d;
                        r[++ri] = cj;
                    }
                }
                return r;
            }
        }
        return r;
    }
    
     //针对IE的操作
    function quickDiffIEXml(c1, c2){
        var d = ++key;
        for(var i = 0, len = c1.length; i < len; i++){
            c1[i].setAttribute("_qdiff", d);
        }
        var r = [];
        for(var i = 0, len = c2.length; i < len; i++){
            if(c2[i].getAttribute("_qdiff") != d){
                r[r.length] = c2[i];
            }
        }
        for(var i = 0, len = c1.length; i < len; i++){
           c1[i].removeAttribute("_qdiff");
        }
        return r;
    }
    //返回C2中不在C1中出现过的元素
    function quickDiff(c1, c2){
        var len1 = c1.length;
        if(!len1){
            return c2;
        }
        if(isIE && c1[0].selectSingleNode){
            return quickDiffIEXml(c1, c2);
        }
        var d = ++key;
        for(var i = 0; i < len1; i++){
        	//因为c1[i]是元素,也就是为元素设值
            c1[i]._qdiff = d;
        }
        //如果c2中元素在c1中出现过,那么值就会相等
        var r = [];
        for(var i = 0, len = c2.length; i < len; i++){
            if(c2[i]._qdiff != d){
                r[r.length] = c2[i];
            }
        }
        return r;
    }
   
    //快速通过Id找到elements
    function quickId(ns, mode, root, id){
        if(ns == root){
           var d = root.ownerDocument || root;
           return d.getElementById(id);
        }
        //从ns找到所有符合mode关系的元素
        ns = getNodes(ns, mode, "*");
        return byId(ns, null, id);
    }

    return {
    	//获得el的style中为name的属性值
        getStyle : function(el, name){
            return Ext.fly(el).getStyle(name);
        },
        /**
         * Compiles a selector/xpath query into a reusable function. The returned function
         * takes one parameter "root" (optional), which is the context node from where the query should start.
         * @param {String} selector The selector/xpath query
         * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
         * @return {Function}
         */
        
        /**
         * div.foo:nth-child(odd)[@foo=bar]#aId{display=none} > a
         * 
         * fn's content:
         * var f = function(root){
         * var mode; ++batch;
         * var n = root || document;
         * n = getNodes(n, mode, "div");
         * n = byClassName(n, null, "foo");
         * n = byPseudo(n, "nth-child", "odd");
         * n = byAttribute(n, "foo", "bar", "=", "[");
         * n = quickId(n, mode, root, "aId");
         * n = byAttribute(n, "display", "none", "=", "{");
         * mode=">";
         * n = getNodes(n, mode, "a");
         * return nodup(n);
         * }
         */
        compile : function(path, type){
        	
        	//默认是select
            type = type || "select";

            var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
            var q = path, mode, lq;
            var tk = Ext.DomQuery.matchers;
            var tklen = tk.length;
            var mm;
                      
            // accept leading mode switch            
            //var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;  element selector           
            var lmode = q.match(modeRe);
            if(lmode && lmode[1]){            	
                fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';               
                q = q.replace(lmode[1], "");
            }            
            // strip leading slashes
            while(path.substr(0, 1)=="/"){
                path = path.substr(1);
            }
           
            //q存在,且q发生变化
            while(q && lq != q){
                lq = q;               
                // /^(#)?([\w-\*]+)/;
                var tm = q.match(tagTokenRe);
                if(type == "select"){
                    if(tm){
                        if(tm[1] == "#"){                        	
                            fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
                        }else{                        	
                            fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
                        }                       
                        q = q.replace(tm[0], "");
                    }                    
                    else if(q.substr(0, 1) != '@'){
                    	//会处理到分隔开来的特殊字符开头的,如. :一些不是字符或数字的。 .xxx,或其它的。
                        fn[fn.length] = 'n = getNodes(n, mode, "*");';
                    }
                }else{//simple
                    if(tm){
                        if(tm[1] == "#"){
                        	//n = byId(n, null, "userNameId");
                            fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
                        }else{
                        	//n = byTag(n, "p");
                            fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
                        }                        
                        q = q.replace(tm[0], "");
                    }
                }       
                       
                //不是结束,也不是空格,也不是mode的符号          与主标识连在一起的。如div.foo,div:first-child     
                while(!(mm = q.match(modeRe))){     
                    var matched = false;
                    /**
                     * 这里就是实现用regexp找到符合的子项去填充生成调用的函数的参数。如下例:
                     * 原正则表达式:  re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/
                     * 其对应的select为:'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
                                                                        
                     * 它的 四个子项  {"([\[\{])"  "([\w-]+)"  "(=|.=)"  "(.*?)"}
                     * 可以把  E[foo$=bar] 分成 {"[" "foo"  "$="  "bar"}  四部分
                     * var m = q.match(t.re)可以得出    m=['[','foo','$','bar'];                                
                                                                   
                     * 接下来t.select.replace可以把'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
                     * 分成四次调用function(x, i){},其参数为{ x: 1:{2},2:{4},3:{3},4:{1}  i: 1:2,2:4,3:3,4:1 }  
                                             
                     * 得出的结果:n = byAttribute(n, "foo", "bar", "$=", "[");                        
                     */
                   
                    for(var j = 0; j < tklen; j++){
                        var t = tk[j];                         
                        var m = q.match(t.re);
                        if(m){    
                            fn[fn.length] = t.select.replace(tplRe, function(x, i){
                                                    return m[i];
                                                });
                            q = q.replace(m[0], "");
                            matched = true;
                            break;
                        }
                    }
                    // prevent infinite loop on bad selector
                    if(!matched){
                        throw 'Error parsing selector, parsing failed at "' + q + '"';
                    }
                }
                //如果mode能找到值 加上:mode="~"同时remove q中找到的字符串。
                if(mm[1]){
                    fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
                    q = q.replace(mm[1], "");
                }
            }
            fn[fn.length] = "return nodup(n);\n}";
            eval(fn.join(""));
            return f;
        },

        /**
         * Selects a group of elements.
         * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
         * @param {Node} root (optional) The start of the query (defaults to document).
         * @return {Array}
         */
        select : function(path, root, type){
        	//默认把document当做root
            if(!root || root == document){
                root = document;
            }
            //支持root采用string id的形式
            if(typeof root == "string"){
                root = document.getElementById(root);
            }
            //支持多个path
            var paths = path.split(",");
            var results = [];
            for(var i = 0, len = paths.length; i < len; i++){
            	//去string前后的空格
                var p = paths[i].replace(trimRe, "");
                //cache 已经编译的select
                if(!cache[p]){
                	//编译
                    cache[p] = Ext.DomQuery.compile(p);
                    if(!cache[p]){
                        throw p + " is not a valid selector";
                    }
                }
                //运行编译的函数
                var result = cache[p](root);
                if(result && result != document){
                    results = results.concat(result);
                }
            }
            //去掉重复的元素
            if(paths.length > 1){
                return nodup(results);
            }
            return results;
        },

        /**
         * Selects a single element.
         * @param {String} selector The selector/xpath query
         * @param {Node} root (optional) The start of the query (defaults to document).
         * @return {Element}
         */
        //返回查询结果中的第一个。
        selectNode : function(path, root){
            return Ext.DomQuery.select(path, root)[0];
        },

        /**
         * Selects the value of a node, optionally replacing null with the defaultValue.
         * @param {String} selector The selector/xpath query
         * @param {Node} root (optional) The start of the query (defaults to document).
         * @param {String} defaultValue
         */
        selectValue : function(path, root, defaultValue){
        	//trim(path)
            path = path.replace(trimRe, "");
            //编译path
            if(!valueCache[path]){
                valueCache[path] = Ext.DomQuery.compile(path, "select");
            }
             //运行编译的函数
            var n = valueCache[path](root);
            n = n[0] ? n[0] : n;
            //返回节点第一个孩子的节点值。
            var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
            return ((v === null||v === undefined||v==='') ? defaultValue : v);
        },

        /**
         * Selects the value of a node, parsing integers and floats.
         * @param {String} selector The selector/xpath query
         * @param {Node} root (optional) The start of the query (defaults to document).
         * @param {Number} defaultValue
         * @return {Number}
         */
        selectNumber : function(path, root, defaultValue){
            var v = Ext.DomQuery.selectValue(path, root, defaultValue || 0);
            return parseFloat(v);
        },

        /**
         * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
         * @param {String/HTMLElement/Array} el An element id, element or array of elements
         * @param {String} selector The simple selector to test
         * @return {Boolean}
         */
        is : function(el, ss){
            if(typeof el == "string"){
                el = document.getElementById(el);
            }
            //支持el参数为非数组的元素
            var isArray = Ext.isArray(el);
            var result = Ext.DomQuery.filter(isArray ? el : [el], ss);
            return isArray ? (result.length == el.length) : (result.length > 0);
        },

        /**
         * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
         * @param {Array} el An array of elements to filter
         * @param {String} selector The simple selector to test
         * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
         * the selector instead of the ones that match
         * @return {Array}
         */
        //找到els中与ss找到els中相配或不相配的元素集合
        filter : function(els, ss, nonMatches){
            ss = ss.replace(trimRe, "");
            if(!simpleCache[ss]){
                simpleCache[ss] = Ext.DomQuery.compile(ss, "simple");
            }
            var result = simpleCache[ss](els);
            return nonMatches ? quickDiff(result, els) : result;
        },

        /**
         * Collection of matching regular expressions and code snippets.
         */
        matchers : [{
                re: /^\.([\w-]+)/, //div.foo
                select: 'n = byClassName(n, null, " {1} ");'
            }, {
                re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
                select: 'n = byPseudo(n, "{1}", "{2}");'
            },{
            	//支持CSS,属性两种形式的selector            	
                re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
                select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
            }, {
                re: /^#([\w-]+)/,//#aid
                select: 'n = byId(n, null, "{1}");'
            },{
                re: /^@([\w-]+)/,//div@xxx
                select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
            }
        ],

        /**
         * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
         * 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, > <.
         */
        operators : {
            "=" : function(a, v){
                return a == v;
            },
            "!=" : function(a, v){
                return a != v;
            },
            "^=" : function(a, v){
                return a && a.substr(0, v.length) == v;
            },
            "$=" : function(a, v){
                return a && a.substr(a.length-v.length) == v;
            },
            "*=" : function(a, v){
                return a && a.indexOf(v) !== -1;
            },
            "%=" : function(a, v){
                return (a % v) == 0;
            },
            "|=" : function(a, v){
                return a && (a == v || a.substr(0, v.length+1) == v+'-');
            },
            "~=" : function(a, v){
                return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
            }
        },

        /**
         * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
         * and the argument (if any) supplied in the selector.
         */
        pseudos : {
            "first-child" : function(c){
                var r = [], ri = -1, n;
                for(var i = 0, ci; ci = n = c[i]; i++){
                    while((n = n.previousSibling) && n.nodeType != 1);
                    if(!n){
                        r[++ri] = ci;
                    }
                }
                return r;
            },

            "last-child" : function(c){
                var r = [], ri = -1, n;
                for(var i = 0, ci; ci = n = c[i]; i++){
                    while((n = n.nextSibling) && n.nodeType != 1);
                    if(!n){
                        r[++ri] = ci;
                    }
                }
                return r;
            },

            "nth-child" : function(c, a) {
                var r = [], ri = -1;
                var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
                var f = (m[1] || 1) - 0, l = m[2] - 0;
                for(var i = 0, n; n = c[i]; i++){
                    var pn = n.parentNode;
                    if (batch != pn._batch) {
                        var j = 0;
                        for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
                            if(cn.nodeType == 1){
                               cn.nodeIndex = ++j;
                            }
                        }
                        pn._batch = batch;
                    }
                    if (f == 1) {
                        if (l == 0 || n.nodeIndex == l){
                            r[++ri] = n;
                        }
                    } else if ((n.nodeIndex + l) % f == 0){
                        r[++ri] = n;
                    }
                }

                return r;
            },

            "only-child" : function(c){
                var r = [], ri = -1;;
                for(var i = 0, ci; ci = c[i]; i++){
                    if(!prev(ci) && !next(ci)){
                        r[++ri] = ci;
                    }
                }
                return r;
            },

            "empty" : function(c){
                var r = [], ri = -1;
                for(var i = 0, ci; ci = c[i]; i++){
                    var cns = ci.childNodes, j = 0, cn, empty = true;
                    while(cn = cns[j]){
                        ++j;
                        if(cn.nodeType == 1 || cn.nodeType == 3){
                            empty = false;
                            break;
                        }
                    }
                    if(empty){
                        r[++ri] = ci;
                    }
                }
                return r;
            },

            "contains" : function(c, v){
                var r = [], ri = -1;
                for(var i = 0, ci; ci = c[i]; i++){
                    if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
                        r[++ri] = ci;
                    }
                }
                return r;
            },

            "nodeValue" : function(c, v){
                var r = [], ri = -1;
                for(var i = 0, ci; ci = c[i]; i++){
                    if(ci.firstChild && ci.firstChild.nodeValue == v){
                        r[++ri] = ci;
                    }
                }
                return r;
            },

            "checked" : function(c){
                var r = [], ri = -1;
                for(var i = 0, ci; ci = c[i]; i++){
                    if(ci.checked == true){
                        r[++ri] = ci;
                    }
                }
                return r;
            },

            "not" : function(c, ss){
                return Ext.DomQuery.filter(c, ss, true);
            },

            "any" : function(c, selectors){
                var ss = selectors.split('|');
                var r = [], ri = -1, s;
                for(var i = 0, ci; ci = c[i]; i++){
                    for(var j = 0; s = ss[j]; j++){
                        if(Ext.DomQuery.is(ci, s)){
                            r[++ri] = ci;
                            break;
                        }
                    }
                }
                return r;
            },

            "odd" : function(c){
                return this["nth-child"](c, "odd");
            },

            "even" : function(c){
                return this["nth-child"](c, "even");
            },

            "nth" : function(c, a){
                return c[a-1] || [];
            },

            "first" : function(c){
                return c[0] || [];
            },

            "last" : function(c){
                return c[c.length-1] || [];
            },

            "has" : function(c, ss){
                var s = Ext.DomQuery.select;
                var r = [], ri = -1;
                for(var i = 0, ci; ci = c[i]; i++){
                    if(s(ss, ci).length > 0){
                        r[++ri] = ci;
                    }
                }
                return r;
            },

            "next" : function(c, ss){
                var is = Ext.DomQuery.is;
                var r = [], ri = -1;
                for(var i = 0, ci; ci = c[i]; i++){
                    var n = next(ci);
                    if(n && is(n, ss)){
                        r[++ri] = ci;
                    }
                }
                return r;
            },

            "prev" : function(c, ss){
                var is = Ext.DomQuery.is;
                var r = [], ri = -1;
                for(var i = 0, ci; ci = c[i]; i++){
                    var n = prev(ci);
                    if(n && is(n, ss)){
                        r[++ri] = ci;
                    }
                }
                return r;
            }
        }
    };
}();

/**
 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Ext.DomQuery#select}
 * @param {String} path The selector/xpath query
 * @param {Node} root (optional) The start of the query (defaults to document).
 * @return {Array}
 * @member Ext
 * @method query
 */
Ext.query = Ext.DomQuery.select;

 

分享到:
评论
2 楼 damoqiongqiu 2010-11-18  
呃,,,不过我有2个问题,一个是var key = 30803;  另一个是eval("var batch = 30803;"); 
为什么key一定是从30803开始?而batch 这个东东在后面也没用上啊?求大师解答。
1 楼 damoqiongqiu 2010-11-18  
注释得很好,再多一些说明就好了,比如nodup()这些方法,源码里面都没有注释的

相关推荐

    EXT核心API详解

    7、Ext.Element类 ………………………… 7 8、Ext.DomQuery类 ………………… 13 9、Ext.DomHelper类 …………………… 14 10、Ext.Template类 …………………… 14 11、Ext.EventManager类 ……………… 15 12、Ext...

    ExtJS入门教程(超级详细)

    7、Ext.Element类 ………………………… 7 8、Ext.DomQuery类 ………………… 13 9、Ext.DomHelper类 …………………… 14 10、Ext.Template类 …………………… 14 11、Ext.EventManager类 ……………… 15 12、Ext...

    Ext Js权威指南(.zip.001

    6.1 ext js的选择器:ext.domquery / 215 6.1.1 选择器的作用 / 215 6.1.2 使用ext.query选择页面元素 / 215 6.1.3 基本选择符 / 223 6.1.4 属性选择符 / 229 6.1.5 css属性值选择符 / 234 6.1.6 伪类选择符 ...

    ExtJSWeb应用程序开发指南(第2版)

    6.4 Ext.core.DomQuery 6.4.1 compile() 6.4.2 filter() 6.4.3 is() 6.4.4 jsSelect() 6.4.5 selectNode() 6.5 Ext.util.CSS 6.5.1 createStyleSheet() 6.5.2 getRule() 6.5.3 ...

    精通JS脚本之ExtJS框架.part1.rar

    6.4 DomQuery入门 6.4.1 元素选择符Selector 6.4.2 属性选择符Attributes Selectors 6.4.3 CSS值元素选择符 6.4.4 Ext.query与Ext.select 6.5 应用模板 6.5.1 Ext.Template 6.5.2 Ext.XTemplate 第7章 设计...

    EXTjs组件解释文档

    包括从基础到深入的EXTjs组件解释,EXTjs实例,EXT核心API详解,Ext.DomQuery类

    Ext深入浅出 数据传输

    11.1.10 Ext.DomQuery ....................269 11.2 用DomHelper和Template动态 生成HTML.............................................272 11.2.1 用DomHelper生成小片段..272 11.2.2 Ext.DomHelper. applyStyles...

    Ext+JS高级程序设计.rar

    1.3 DomQuery详解 20 1.4 模板介绍 23 1.5 实用功能 24 1.6 定时执行代码 25 1.7 本章小结 26 第2章 Ext Core实例系统设计 27 2.1 需求分析 27 2.2 系统设计 28 2.3 功能结构图 29 2.4 开发与运行环境 31 2.5 数据库...

    精通JS脚本之ExtJS框架.part2.rar

    6.4 DomQuery入门 6.4.1 元素选择符Selector 6.4.2 属性选择符Attributes Selectors 6.4.3 CSS值元素选择符 6.4.4 Ext.query与Ext.select 6.5 应用模板 6.5.1 Ext.Template 6.5.2 Ext.XTemplate 第7章 设计...

    EXTJS 中文手册 电子书

    EXT源码概述 ......................................................................................................... 13 揭示源代码 .......................................................................

    Ext官方中文教程(可打包下载)

    Ext源码概述 Ext与RESTful Web Services 程序设计: 如何合理地规划一个应用程序 如何本地化ext的教程 xtype的含义 扩展Ext中的组件 扩展与插件之间的区别 扩展Ext的新手教程 Ext的类继承 从源码生成Ext 基础用法...

    Ext 学习中文手册

    发布Ext源码时的一些细节 12 我应该从哪里开始? 13 适配器Adapters 13 核心Core 13 Javascript中的作用域(scope) 13 事前准备 13 定义 13 正式开始 14 window对象 14 理解作用域 15 变量的可见度 15 EXT程序规划...

    EXT简体中文参考手册(PDF&CHM电子档)

    发布Ext源码时的一些细节 12 我应该从哪里开始? 13 适配器Adapters 13 核心Core 13 Javascript中的作用域(scope) 13 事前准备 13 定义 13 正式开始 14 window对象 14 理解作用域 15 变量的可见度 15 EXT程序规划...

    EXT 中文帮助手册

    4 Element:Ext的核心 4 获取多个DOM的节点 5 响应事件 5 使用Widgets 7 使用Ajax 9 EXT源码概述 11 揭示源代码 11 发布Ext源码时的一些细节 12 我应该从哪里开始? 13 适配器...

    EXT 中文手册

    4 Element:Ext的核心 4 获取多个DOM的节点 5 响应事件 5 使用Widgets 7 使用Ajax 9 EXT源码概述 11 揭示源代码 11 发布Ext源码时的一些细节 12 我应该从哪里开始? 13 适配器...

    React-Flux-Pages-Boilerplate

    –React+助焊剂+通天塔– Gulp – domquery(用于dom操作) – TweenMax TimelineMax –十字路口+哈希器(用于路由) – lodash –大小元素(获取dom元素的宽度和高度) $ bower install $ npm install // For ...

    幻影:无头基于Chromium的Web性能指标收集器和监视工具

    幻影 基于的模块化Web性能指标收集器。 为什么是幻影? 好吧,:)要求 12以上安装通过npm npm install phantomas这将安装puppeteer模块支持 。通过Docker 您可以使用: docker pull macbre/phantomas:latest支持 您...

Global site tag (gtag.js) - Google Analytics