jljlpch 发表于 2013-1-27 05:14:57

Ext.DomQuery源码

/* * 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.DomQueryProvides 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</b> has an attribute "foo"</li>    <li> <b>E</b> has an attribute "foo" that equals "bar"</li>    <li> <b>E</b> has an attribute "foo" that starts with "bar"</li>    <li> <b>E</b> has an attribute "foo" that ends with "bar"</li>    <li> <b>E</b> has an attribute "foo" that contains the substring "bar"</li>    <li> <b>E</b> has an attribute "foo" that is evenly divisible by 2</li>    <li> <b>E</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+ 3not 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++){         //v在不在ci.className中?            if((' '+ci.className+' ').indexOf(v) != -1){                r[++ri] = ci;            }      }      return r;    };   // n: [{tagName:div,htmlFor:xxx,className:xxx}]node    //从n中元素找到attr的属性值    function attrValue(n, attr){      if(!n.tagName && typeof n.length != "undefined"){            n = n;      }      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;    };         //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 = ;//转换成数组      }      //mode不存在或为空等,返回其下所有的与tagName相同的元素      if(!mode){            for(var i = 0, ni; ni = ns; i++){            //找到ni下面所有tagName的子标签                cs = ni.getElementsByTagName(tagName);                //把找到的所有cs的Element存在result                for(var j = 0, ci; ci = cs; 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++){            //ni的所有直接子节点,IE/FF兼容,                cn = ni.children || ni.childNodes;                for(var j = 0, cj; cj = cn; 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++){            //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++){            //下一个兄弟存在,同时不是元素或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),argumentsis array-like.                      if(b.slice){            return a.concat(b);      }      //把b中所有元素追加到a中。      for(var i = 0, l = b.length; i < l; i++){            a = b;      }      return a;    }    //通过tagName在cs中找到与之相同tagName的所有元素    function byTag(cs, tagName){      if(cs.tagName || cs == document){            cs = ;      }      if(!tagName){            return cs;      }      var r = [], ri = -1;      tagName = tagName.toLowerCase();      for(var i = 0, ci; ci = cs; 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 = ;      }      if(!id){            return cs;      }      var r = [], ri = -1;      for(var i = 0,ci; ci = cs; 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;//Dom的操作符      for(var i = 0, ci; ci = cs; 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(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.setAttribute("_nodup", d);      var r = ];      for(var i = 1, len = cs.length; i < len; i++){            var c = cs;            if(!c.getAttribute("_nodup") != d){                c.setAttribute("_nodup", d);                r = c;            }      }      //去掉已经加上的属性      for(var i = 0, len = cs.length; i < len; i++){            cs.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.selectSingleNode != "undefined"){            return nodupIEXml(cs);      }      var d = ++key;      //cs的元素有可能在Cs中多处出现,也就是说数组中不是唯一的元素。      cs._nodup = d;      for(i = 1; c = cs; i++){            if(c._nodup != d){                c._nodup = d;            }else{                r = [];                //找到c._nodup = d的元素前面的所有元素,存起来                for(var j = 0; j < i; j++){                  r[++ri] = cs;                }                //跳过c._nodup==d的元素                //找到c._nodup = d的元素后面的所有元素,如果其_nodup != d,设定为d,存起来                for(j = i+1; cj = cs; 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.setAttribute("_qdiff", d);      }      var r = [];      for(var i = 0, len = c2.length; i < len; i++){            if(c2.getAttribute("_qdiff") != d){                r = c2;            }      }      for(var i = 0, len = c1.length; i < len; i++){         c1.removeAttribute("_qdiff");      }      return r;    }    //返回C2中不在C1中出现过的元素    function quickDiff(c1, c2){      var len1 = c1.length;      if(!len1){            return c2;      }      if(isIE && c1.selectSingleNode){            return quickDiffIEXml(c1, c2);      }      var d = ++key;      for(var i = 0; i < len1; i++){      //因为c1是元素,也就是为元素设值            c1._qdiff = d;      }      //如果c2中元素在c1中出现过,那么值就会相等      var r = [];      for(var i = 0, len = c2.length; i < len; i++){            if(c2._qdiff != d){                r = c2;            }      }      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){                            fn = 'mode="'+lmode.replace(trimRe, "")+'";';                               q = q.replace(lmode, "");            }                        // 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 == "#"){                                                    fn = 'n = quickId(n, mode, root, "'+tm+'");';                        }else{                                                    fn = 'n = getNodes(n, mode, "'+tm+'");';                        }                                             q = q.replace(tm, "");                  }                                        else if(q.substr(0, 1) != '@'){                  //会处理到分隔开来的特殊字符开头的,如. :一些不是字符或数字的。 .xxx,或其它的。                        fn = 'n = getNodes(n, mode, "*");';                  }                }else{//simple                  if(tm){                        if(tm == "#"){                        //n = byId(n, null, "userNameId");                            fn = 'n = byId(n, null, "'+tm+'");';                        }else{                        //n = byTag(n, "p");                            fn = 'n = byTag(n, "'+tm+'");';                        }                                                q = q.replace(tm, "");                  }                }                                              //不是结束,也不是空格,也不是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"}四部分                     * 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;                                                 var m = q.match(t.re);                        if(m){                              fn = t.select.replace(tplRe, function(x, i){                                                    return m;                                                });                            q = q.replace(m, "");                            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){                  fn = 'mode="'+mm.replace(trimRe, "")+'";';                  q = q.replace(mm, "");                }            }            fn = "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.replace(trimRe, "");                //cache 已经编译的select                if(!cache){                //编译                  cache = Ext.DomQuery.compile(p);                  if(!cache){                        throw p + " is not a valid selector";                  }                }                //运行编译的函数                var result = cache(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);      },      /**         * 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){                valueCache = Ext.DomQuery.compile(path, "select");            }             //运行编译的函数            var n = valueCache(root);            n = n ? n : 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 : , 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){                simpleCache = Ext.DomQuery.compile(ss, "simple");            }            var result = simpleCache(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++){                  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++){                  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) - 0, l = m - 0;                for(var i = 0, n; n = c; 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++){                  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++){                  var cns = ci.childNodes, j = 0, cn, empty = true;                  while(cn = cns){                        ++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++){                  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++){                  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++){                  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++){                  for(var j = 0; s = ss; 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 || [];            },            "first" : function(c){                return c || [];            },            "last" : function(c){                return c || [];            },            "has" : function(c, ss){                var s = Ext.DomQuery.select;                var r = [], ri = -1;                for(var i = 0, ci; ci = c; 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++){                  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++){                  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; 
页: [1]
查看完整版本: Ext.DomQuery源码