zoukankan      html  css  js  c++  java
  • 我的第四代选择器Rage

    Rage其实已经完成了半年多了,一直在内部使用。它的实现原理与Sizzle一致,都是通过最右近的表达式得到一个种子集,然后不断往左边切割,过滤种子集中不符合的元素,将它们置为flase,最后去掉这些false元素,就得到最后结果了。

    支持CSS选择器类型,除jQuery自定义的位置伪类外,一切CSS选择器类型都支持。

    由于Sizzle已经在这领域开发很久了,因此很难赶上其速度。

    即使如此,我还是很有收获,如更深入了解Sizzle的运作,一些去重排序的算法(主要来自JK的帮助),新的子元素过滤伪类的算法,querySelectorAll的用法改进等等。

    不过,第四代选择器最大的特色是其权重体系,它把所有选择器类型分为五类:

               index : {//构建权重体系
                    "#":12,
                    ".":23,
                    "[":34,
                    ":":55
                    //tagName:41
                },
                apis: {
                    12 : "getElementById",
                    23 : "getElementsByClassName",
                    34 : "getElementsByName",
                    41 : "getElementsByTagName" ,
                    55 : ""
                },
    

    查找时用这些数字的十位数,过滤时用这些数字的个位数,之所以速度慢下来,是从右到左的实现太复杂了,暂时还无法掌控它。但这东西迟早会应用我新一代选择器中。

    使用方法,dom.query(expr,context),不过它是依赖于lang模块的

    ;
    (function(global,DOC){
        var dom = global[DOC.URL.replace(/(#.+|\W)/g,'')];
        dom.log("已加载query模块")
        dom.define("query", "lang",function(){
            dom.mix(dom,{
                //http://www.cnblogs.com/rubylouvre/archive/2010/03/14/1685360.
                isXML : function(el){
                    var doc = el.ownerDocument || el
                    return doc.createElement("p").nodeName !== doc.createElement("P").nodeName;
                },
                //获取某个节点的文本,如果此节点为元素节点,则取其childNodes的所有文本,
                //为了让结果在所有浏览器下一致,忽略所有空白节点,因此它非元素的innerText或textContent
                getText : function( nodes ) {
                    var ret = "", elem;
                    for ( var i = 0; nodes[i]; i++ ) {
                        elem = nodes[i];
                        // 对得文本节点与CDATA的内容
                        if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
                            ret += elem.nodeValue;
                        //取得元素节点的内容
                        } else if ( elem.nodeType !== 8 ) {
                            ret += this.getText( elem.childNodes );
                        }
                    }
                    return ret;
                }
    
            });
    
            var reg_split = /^(?:[-\w\*]|[^\x00-\xa0]|\\.)+|[#:](?:[-\w]|[^\x00-\xa0]|\\.)+(?:\([^\)]*\))?|\.(?:[-\w*\.]|[^\x00-\xa0]|\\.)+|\[[^\]]*\]|(?:\s*)([>+~,\s])(?:\s*)(?=\S)/
            var reg_attr  = /\[\s*((?:[-\w]|[^\x00-\xa0]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/;
            var reg_pseudo = /^:(\w[-\w]*)(?:\((['"]*)(.*)\2\))?$/;
            var reg_name  = /\[name=['"]*((?:[-\w]|[^\x00-\xa0]|\\.)+)['"]*\]/;
            var reg_escape =/([\/\[\]\:])/g
            var reg_class = /\.([^.]+)/g;
            var reg_ltrim = /^\s+/;
            var reg_rtrim = /\s+$/;
            var reg_input = /input|select|textarea|button/i;
            var reg_slash = /\\/g
            // CSS3 user action pseudo-classes
            var one_action = dom.oneObject('target,active,hover,focus', 2);
            var one_url = dom.oneObject('action,cite,codebase,data,href,longdesc,lowsrc,src,usemap', 2);
            //According to the W3C spec, document.querySelectorAll('[selected=selected]')
            //should return the same NodeList as document.querySelectorAll('[selected]'),
            var one_bool = dom.oneObject('checked,disabled,defer,ismap,multiple,readonly,selected');
            var one_relative = dom.oneObject([" ", ">", "+", "~"]);
            var child_pseudo = "nth-child,nth-last-child";
            var one_child = dom.oneObject((child_pseudo+","+child_pseudo.replace(/child/g,"of-type")));
            var sort_type = function(a,b){
                return a.charAt(1) - b.charAt(1);
            }
            var one_link = dom.oneObject(["a","A","area","AREA","link","LINK"])
            var flag_repeat = false;
            var defaults = {
                value: 'defaultValue',
                checked: 'defaultChecked',
                selected: 'defaultSelected'
            }
            var props = dom.attrMap = {};
            var to_s = {}.toString;
            var str = "accessKey|allowTransparency|bgColor|cellPadding|cellSpacing|codeBase|codeType|colSpan|dateTime|defaultChecked|defaultSelected|defaultValue|frameBorder|"+
            "isMap|longDesc|maxLength|marginWidth|marginHeight|noHref|noResize|noShade|readOnly|rowSpan|tabIndex|useMap|vSpace|valueType|vAlign"
            str.replace(/\w+/g, function(name){
                props[name.toLowerCase()] = name;
            });
            dom.mix(props, {
                "accept-charset": "acceptCharset",
                "char": "ch",
                charoff: "chOff",
                "class": "className",
                "for": "htmlFor",
                "http-equiv": "httpEquiv"
            });
            var Query = dom.query = function(token, context, result, seed){
                result = result || [];
                context = context || DOC;
                if (context.nodeType !== 1 && context.nodeType !== 9) {
                    return result;
                }
                Query.queryTime = new Date-0;//.replace(reg_rltrim,'')
                var right = token.replace(reg_ltrim,'').replace(reg_rtrim,''), loop = [], types = [],relative = one_relative,nodes, match, part;
                //将CSS表达式转换成二重数组,并根据'种子选择器取得候选集
                do{
                    match = right.match(reg_split);
                    right = RegExp.rightContext;
                    part = match[1] || match[0];
                    if(part == ","){
                        break
                    }else if(relative[part]){
                        loop.push(types,part);
                        types = [];
                    }else if(part){
                        (types[types.length] = new String(Query.index[part.charAt(0)] || 41))._ = part;
                    }
                }while(right);
                //   dom.log(types)
                match =  seed ? {
                    types: types,
                    nodes: dom.slice(seed)//nte
                } :Query.getSeed(types, context);//取得种子集
    
                types = match.types;
                nodes = match.nodes;
    
                var flag_xml = dom.isXML(context);
                if ( types.length) {//缩窄种子集的范围
                    nodes = to_s.call(nodes) === "[object Array]" ? nodes : dom.slice(nodes);
                    //  dom.log(types+" "+nodes);
                    nodes = Query.sameLevelSift(types, nodes, flag_xml);
                }
                var i = 0, n = nodes.length;
                if(loop.length ){//处理左边选择器
                    var set = dom.slice(nodes);//复制一份构造映射集
                    while ( loop.length ) {
                        part = types = loop.pop();
                        if ( relative[ part ] ) {
                            types = loop.pop();
                        } else {
                            part = " ";//默认为后代选择器
                        }
                        Query.iterator[ part ]( types, set, flag_xml );
                    }
                    for(; i < n; i++){
                        if(set[i]){
                            result[result.length] = nodes[i];//合并两个结果集
                        }
                    }
                }
                else{
                    for(; i < n; i++){
                        result[result.length] = nodes[i]
                    }
                }
                if ( right ) {
                    Query( right, context, result,seed );
                    return result.length < 2 ? [] : dom.unique( result );
                }
                return result;
            }
            dom.mix(Query, {
                index : {//构建权重体系
                    "#":12,
                    ".":23,
                    "[":34,
                    ":":55
                    //tagName:41
                },
                apis: {
                    12 : "getElementById",
                    23 : "getElementsByClassName",
                    34 : "getElementsByName",
                    41 : "getElementsByTagName" ,
                    55 : ""
                },
                getAttribute : function(node, attribute) {
                    return node.getAttribute(attribute) || '';
                } ,
                hasAttribute : function(node, attr) {
                    return node.hasAttribute(attr);
                },
                getElementById:function(expr){
                    var el =  this.getElementById(expr.slice(1).replace(reg_slash,''));
                    return el && [el] || [];
                },
                getElementsByClassName:function(expr){
                    return this.getElementsByClassName(expr.slice(1).replace(reg_slash,'').replace(/\./g, ' '));
                },
                getElementsByName:function(expr){
                    var match = expr.match(reg_name);
                    return match && this.getElementsByName(match[1].replace(reg_slash,''));
                },
                getElementsByTagName:function(expr){
                    return this.getElementsByTagName(expr.replace(reg_slash,''));
                },
                isLink:function(node){
                    return Query.hasAttribute(node,'href') && one_link[node.nodeName];
                },
                cacheNTH:{},
                parseNTH:function(expr){
                    var a =  (expr === "even" && "2n0" || expr === "odd" && "2n1" || !/n/.test(expr) && ("0n"+expr) || expr.replace(/(^|\D+)n/g,"$11n") ).split(/n/);
                    return (Query.cacheNTH[expr] = [a[0]|0,a[1]|0]);
                },
                /*************************获取候选集***************************/
                getSeed: function (types, context) {
                    types.sort();
                    var i =0, type, api, nodes;
                    for(; type = types[i]; i++){
                        api = Query.apis[type];
                        nodes = context[api] && Query[api].call(context,type._);
                        if(nodes){
                            types.splice(i, 1);
                            break;
                        }
                    }
                    if (!nodes) {
                        nodes = context.getElementsByTagName("*");
                    }
                    return {
                        nodes: nodes,
                        types: types
                    }
                },
                //flag_false,是否将不符合条件的元素置换为false,默认直接去掉此元素
                sameLevelSift:function(types, nodes, flag_xml, flag_false, flag_not){//平级过滤
                    types.sort(sort_type);
                    var i = 0, type, n, ii , node, match, filter, t = 0
                    while ((type = types.shift())) {
                        n = nodes.length;
                        match = Query.preSift[ type ]( type._, flag_xml, flag_false, flag_not, nodes, n  );//加工参数
                        if(!match)
                            continue;
                        filter = Query.filters[type];
                        for (i = ii = 0; i < n; i++) {
                            if ((node = nodes[i])) {
                                if (filter.call( node, match ) ^ flag_not) {//这里只处理ID CLASS TAG ATTR
                                    if(!flag_false){
                                        nodes[ii++] = node;
                                    }
                                } else if (flag_false) {
                                    nodes[i] = false;//过滤种子集
                                }
                            }
                        }
                        if (!flag_false) {
                            nodes.length = n = ii;
                        }
                    }
                    return nodes;
                },
    
                //表达式的类型 待检测的节点集合 是否为XML 测试值 目标元素的属性
                crossLevelSift:function(type, nodes, flag_xml, check, prop){//越级过滤
                    var i = 0, n = nodes.length, time = Query.queryTime ++,STAR = "*",NIL, node, val;
                    for (; i < n; i++) {
                        if ((node = nodes[i])) {
                            val = false;
                            while ((node = node[prop])) {
                                if (node.nodeType === 1) {
                                    if (node.queryTime === time) {
                                        val = nodes[node.queryIndex];
                                        break;
                                    }
                                    if (check === node.nodeName || (check === NIL && Query.sameLevelSift([type], [node], flag_xml, false).length) || check === STAR) {
                                        node.queryTime = time;
                                        node.queryIndex = i;
                                        val = node;
                                        break;
                                    }
                                }
                            }
                            nodes[i] = val;
                        }
                    }
                },
                preSift:{
                    12: function( expr ) {//ID
                        return expr.slice(1).replace(reg_slash,'');
                    },
                    23: function( expr, flag_xml, flag_false, flag_not, nodes, n ) {//CLASS
                        var  i = 0, ii = 0, node, src = expr.replace(reg_escape, '\\$1').replace(reg_class, '(?=[ \\s\\S]*(?:^|\\s)$1(?: \\s|$))'),
                        reg = new RegExp(src);
                        if ( flag_xml ) {
                            return reg;
                        }
                        for ( ; i < n ; i++ ) {
                            if((node = nodes[i])){
                                if(node.className && reg.test(node.className) ^ flag_not){
                                    if(!flag_false){
                                        nodes[ii++] = node;
                                    }
                                } else if ( flag_false ) { //不符合的置换为false
                                    nodes[i] = false;
                                }
                            }
                        }
                        if ( !flag_false )
                            nodes.length = ii;
                        return false;
                    },
                    34:function(expr){//ATTR
                        var match = expr.match(reg_attr), name = match[1].replace(reg_slash,'');
                        var value = (match[4]||"").replace(reg_slash,'');
                        if ( match[2] === "~=" ) {
                            value = " " + value + " ";
                        }
                        return [name,match[2],value];
                    },
                    41:function(expr, flag_xml){//TAG
                        expr = expr.replace(reg_slash,'');
                        if (expr === "*")
                            return false;
                        return flag_xml ? expr : expr.toUpperCase()
                    },
                    55:function(value, flag_xml, flag_false, flag_not, nodes, n){//PSEUDO
                        var match = value.match(reg_pseudo),expr = (match[3] || "").replace(reg_ltrim,'').replace(reg_rtrim,''),
                        type = match[1] ,i = 0, ii = 0, node, args = [];
                        if((type === "nth-child" || type === "nth-last-child") && expr === "n")
                            return false;
                        if(one_child[type]){//拥有表达式的子元素过滤伪类
                            expr = expr.replace(/\s/g,'');
                            args = Query.cacheNTH[expr] || Query.parseNTH(expr);
                        }else if(one_action[type]){//目标伪类
                            args = [!flag_xml];
                        }else if(type === "lang"){//语言伪类
                            args = [new RegExp("^(" + expr + "$|" + expr + "-)", "i")];
                        }else if(type == "contains"){//内容伪类
                            args = [expr, flag_xml];
                        }else if(type === "not"){
                            var check = 0, whiterat = expr+"";
                            while(whiterat){
                                whiterat.match(reg_split);
                                whiterat = RegExp.rightContext;
                                if(check==2)
                                    break;
                                check++;
                            }
                            //  if(check === 1 && expr.charAt(0) !== ":" && expr.slice(-1) !== ")")
                            if(check > 1){//复杂
                                var els = Query(expr, null, null, nodes), hash = {},  j = 0, uuid;
                                while((node = els[j++])){
                                    uuid = node.uniqueNumber || (node.uniqueNumber = dom["@uuid"]++);
                                    hash[uuid] = 1;
                                }
                                args = [hash];
                            }else {
                                (args[0] = new String(Query.index[expr.charAt(0)] || 41))._ = expr;
                                Query.sameLevelSift(args, nodes, flag_xml, flag_false, true ^ flag_not);
                                return false;
                            }
                        }
                        var filter = Query.filters[type];
                        for ( ; i < n ; i++ ) {
                            if((node = nodes[i])){
                                if(filter.apply(node, args) ^ flag_not){
                                    if(!flag_false){
                                        nodes[ii++] = node;
                                    }
                                } else if ( flag_false ) { //不符合的置换为false
                                    nodes[i] = false;
                                }
                            }
                        }
                        if ( !flag_false )
                            nodes.length = ii;
                        return false;
                    }
                },
                iterator:{
                    " ":function (types, nodes, flag_xml) {
                        types.sort(sort_type);
                        var prop = "parentNode", type = types.shift(), expr = type._, check ;
                        if(type == "41"){
                            check = flag_xml ? expr : expr.toUpperCase();
                        }
                        Query.crossLevelSift(type, nodes, flag_xml, check, prop);//越级过滤
                        types.length && Query.sameLevelSift(types, nodes,flag_xml, true);//平级过滤
                    },
                    "~":function (types, nodes, flag_xml) {
                        types.sort(sort_type);
                        var prop = "previousSibling", type = types.shift(), expr = type._, check;
                        if(type == "41"){
                            check = flag_xml ? expr : expr.toUpperCase();
                        }
                        Query.crossLevelSift(type, nodes, flag_xml, check, prop);//越级过滤
                        types.length && Query.sameLevelSift(types, nodes, flag_xml, true);//平级过滤
                    },
                    ">" : function(types, nodes, flag_xml) {
                        types.sort(sort_type);
                        var type = types[0], expr = type._, check , node;
                        if(type == "41" && types.shift()){
                            check = flag_xml ? expr : expr.toUpperCase();
                        }
                        for (var i = 0, n = nodes.length; i < n; i++) {
                            if ((node = nodes[i])) {
                                node = node.parentNode;
                                nodes[i] = (check && node) ? node.nodeName === check && node : node;
                            }
                        }
                        types.length && Query.sameLevelSift(types, nodes, flag_xml, true);//平级过滤
                    },
                    "+" : function(types, nodes, flag_xml) {
                        types.sort(sort_type);
                        var type = types[0], expr = type._, check , node;
                        if(type == "41" && types.shift()){
                            check = flag_xml ? expr : expr.toUpperCase();
                        }
                        for (var i = 0, n = nodes.length; i < n; i++) {
                            if ((node = nodes[i])) {
                                while ((node = node.previousSibling) && node.nodeType !== 1) {};
                                nodes[i] = (check && node) ? node.nodeName === check && node : node;
                            }
                        }
                        types.length && Query.sameLevelSift(types, nodes, flag_xml, true);//平级过滤
                    }
                },
                filters:{
                    12:function(id){//这里用于XML
                        return id ===  this.getAttribute("id");
                    },
                    41: function (nodeName ) {
                        return  this.nodeName === nodeName;
                    },
                    23: function( reg ) {//这里用于XML
                        return reg.test(this.getAttribute("class"));
                    },
                    34:function(match){
                        var name = match[0], operator = match[1], value = match[2];
                        if(!operator){
                            return   Query.hasAttribute(this,name);
                        }
                        var attrib = Query.getAttribute(this, name, true);
                        if( match[2] === "" ){//目标值不能为空字串
                            return false;
                        }
                        switch (operator) {
                            case "=":
                                return attrib === value;
                            case "!=":
                                return attrib !== value;
                            case "~=":
                                return attrib  && (" " + attrib + " ").indexOf(value) !== -1;
                            case "^=":
                                return attrib  && attrib.indexOf(value) === 0;
                            case "$=":
                                return attrib  && attrib.lastIndexOf(value) + value.length === attrib.length;
                            case "*=":
                                return attrib  && attrib.indexOf(value) !== -1;
                            case "|=":
                                return attrib === value || attrib.substring(0, value.length + 1) === value + "-";
                        }
                    },
                    //CSS3属性伪类
                    enabled: function(){
                        return this.disabled === false && this.type !== "hidden";
                    },
                    //CSS3属性伪类
                    disabled: function(){
                        return this.disabled === true;
                    },
                    //CSS3属性伪类
                    checked: function(){
                        return this.checked = true;
                    },
                    //CSS3属性伪类
                    indeterminate:function(){
                        return this.indeterminate === true && this.type === "checkbox" ;
                    },
                    //自定义属性伪类
                    selected: function () {
                        this.parentNode.selectedIndex; //处理safari的bug
                        return this.selected === true;
                    },
                    //CSS3结构伪类(子元素过滤伪类)
                    empty: function(){
                        var child = this.firstChild;
                        return !(child && child.nodeType == 1) && !(this.innerText || this.textContent || '').length;
                    },
                    //自定义可见性伪类
                    target: function (flag_html) { //CSS2.1目标标准
                        var id = location.hash.slice(1),
                        check = this.id || flag_html && this.name;
                        return check === id;
                    },
                    link: function(){
                        return Query.isLink(this) && !this.visited
                    },
                    visited: function(){
                        return Query.isLink(this) && this.visited
                    },
                    active: function(flag_html){
                        return flag_html && this === this.ownerDocument.activeElement;
                    },
                    hover: function(flag_html){
                        return flag_html && this === this.ownerDocument.hoverElement;
                    },
                    focus:function(flag_html){
                        return flag_html && (this.type|| this.href) && this === this.ownerDocument.activeElement;
                    },
                    //CSS2链接伪类
                    lang: function (reg) { //CSS3语言伪类
                        var node = this;
                        while (!node.getAttribute("lang") && (node = node.parentNode)) {};
                        return reg.test(node.getAttribute("lang"));
                    },
                    header: function(){
                        return /h\d/i.test( this.nodeName )
                    },
                    //自定义属性伪类
                    button: function(){
                        return this.type === "button" || this.nodeName === "BUTTON"
                    },
                    //自定义属性伪类
                    input: function(){
                        return reg_input.test(this.nodeName)
                    },
    
                    parent: function(){
                        return !!this.firstChild;
                    },
                    //自定义内容伪类
                    contains:function(text, flag_xml){
                        return (this.textContent || this.innerText || (flag_xml ? dom.getText([ this ]) : "")).indexOf(text) >= 0;
                    },
                    //自定义结构伪类
                    has: function (exp, flag_xml) { //自定义结构伪类(子元素过滤伪类,根据子节点的选择器情况进行筛选)
                        return !!dom.query(exp, this, flag_xml).length;
                    },
                    not: function (hash) { //CSS3反选伪类
                        return !hash[this.uniqueNumber];
                    },
                    hidden:function(  ) {
                        var width = this.offsetWidth,
                        height = this.offsetHeight;
                        return width === 0 || height === 0 || (!dom.support.reliableHiddenOffsets && (this.style.display || dom.css( this, "display" )) === "none");
                    }
                }
            });
            
            dom.query.filters.visible = function(  ) {
                return !dom.query.filters.hidden.call(this)
            };
            var queryPseudoNoExp = function (name, isLast, isOnly) {
                var head = "var node = this;{0} while((node=node.{1}))  if(node.{2} === {3}) return false;";
                var body = "var prev = this;while ((prev = prev.previousSibling)) if (prev.{2} === {3}) return false;";
                var foot = "return true;"
                var start = isLast ? "nextSibling" : "previousSibling";
                var fills = {
                    type: ["var tagName = this.nodeName;", start, "nodeName", "tagName"],
                    child: ["", start, "nodeType", "1"]
                }
                [name];
                var fn = isOnly ? head + body + foot : head + foot;
                return new Function(fn.replace(/{(\d)}/g, function ($, $1) {
                    return fills[$1];
                }));
            }
            var queryPseudoHasExp = function(child, sibling, ofType,cache){
                return function(a,b){
                    var uid = this.uniqueNumber || (this.uniqueNumber = dom["@uuid"]++), uuid
                    if (!cache[uid]){
                        var parent = this.parentNode;
                        if (!parent) return false;
                        var node = parent[child], count = 1,
                        checkName = ofType ? "nodeName" : "nodeType",
                        checkValue = ofType ? this.nodeName : 1;
                        do {
                            if (node[checkName] != checkValue) continue;
                            uuid = node.uniqueNumber || (node.uniqueNumber = dom["@uuid"]++);
                            cache[uuid] = count++;
                        } while ((node = node[sibling]));
                    }
                    var pos = cache[uid];
                    if (a == 0) return b == pos;
                    if (a > 0){
                        if (pos < b) return false;
                    } else {
                        if (b < pos) return false;
                    }
                    return ((pos - b) % a) == 0;
                };
            };
            dom.mix(Query.filters, {
                "first-child"     : queryPseudoNoExp("child", false, false),
                "last-child"      : queryPseudoNoExp("child", true,  false),
                "only-child"      : queryPseudoNoExp("child", true,  true),
                "first-of-type"   : queryPseudoNoExp("type",  false, false),
                "last-of-type"    : queryPseudoNoExp("type",  true,  false),
                "only-of-type"    : queryPseudoNoExp("type",  true,  true), //CSS3子元素过滤伪类
                "nth-child"       : queryPseudoHasExp("firstChild", "nextSibling", false, {}),
                "nth-last-child"  : queryPseudoHasExp("lastChild", "previousSibling", false, {}),
                "nth-of-type"     : queryPseudoHasExp("firstChild", "nextSibling", true, {}),
                "nth-last-of-type": queryPseudoHasExp("lastChild", "previousSibling", true, {})
            });
            "text|radio|checkbox|file|password|submit|image|reset".replace(/\w+/g, function(name){
                Query.filters[name] = function(){//自定义属性伪类
                    return "form" in this && this.type === name;
                }
            });
    
            dom.unique = function(nodes){
                var self = dom.unique;
                var n = nodes.length;
                var lists = self.getLists(nodes);
                lists.sort(function(a,b){
                    return a.length - b.length;
                });//按长度排序
                var depth = lists[0].length, length = lists.length, parent, cut, ii = 0;
                for(var i =0; i < depth; i++){
                    parent = lists[0][i];//假设这个为LCA
                    cut = true;
                    for(var j = 1;j <  length; j++){//与其他祖先树相比
                        if(parent !== lists[j][i]){
                            cut = false;
                            break;
                        }
                    }
                    if(cut){
                        ii++
                    }else{
                        break;
                    }
                }
                var LCA = lists[0][ii-1];
                lists = self.sliceLists(lists,ii);
                lists.sort(self.sortLists);
                var list, i = 0, result = [];
                while((list = lists[i++])){
                    result[result.length] = list.pop();
                }
                if(result.length !== n){
                    result.unshift(LCA);
                    if(result.length != n){
                        flag_repeat = true;
                    }
                    if ( flag_repeat ) {
                        for ( i = 1; i < result.length; i++ ) {
                            if ( result[i] === result[ i - 1 ] ) {
                                result.splice( i--, 1 );
                            }
                        }
                    }
                }
                return result;
            }
            dom.mix(dom.unique,{
                getList : function(node){//取得所有父元素
                    var list = [];
                    while(node){
                        if(node.nodeType === 9){
                            break;
                        }
                        list.unshift(node);
                        node = node.parentNode;
                    }
                    return list;
                },
                getLists : function(nodes){//取得所有祖先的树
                    var lists = [], getList = this.getList, i=0, node;
                    while((node = nodes[i++])){
                        lists[ lists.length ] = getList(node);
                    }
                    return lists;
                },
                sliceLists : function(lists,num){
                    var result = [], i = 0, list;
                    while((list = lists[i++])){
                        list = list.slice(num);
                        if(list.length){
                            result[ result.length ] = list;
                        }
                    }
                    return result;
                },
                sortLists : function(a,b){
                    var n = Math.min(a.length,b.length),ap,bp;
                    for(var i=0; i < n; i++){
                        ap = a[i],bp = b[i]
                        if(ap !== bp){
                            while(ap = ap.nextSibling){
                                if(ap === bp){
                                    return -1;
                                }
                            }
                            return 1;
                        }
                    }
                    return a.length-b.length;
                }
            },false);
    
            /************************根据浏览器特征重写部分函数**************************/
            if ( reg_ltrim.test( "\xA0" ) ) {
                reg_ltrim = /^[\s\xA0]+/;
                reg_rtrim = /[\s\xA0]+$/;
            }
            var HTML = dom.html,
            whiterat = DOC.createElement("div"),id = "WHITERAT";
            whiterat.innerHTML = '<a name="'+id+'"></a><b id="'+id+'"></b>';
            HTML.insertBefore(whiterat, HTML.firstChild);
            //IE的getElementsById无法区分name与id
            if( DOC.getElementById(id) === whiterat.firstChild){
                Query.filters["12"] = function(id){
                    return this.getAttributeNode("id").nodeValue === id;
                }
            }
            if(!whiterat.hasAttribute){
                Query.hasAttribute = function(node, attribute) {
                    attribute = attribute in props ?//处理HTML非对称的属性
                    props[attribute] : attribute;
                    if (defaults[attribute] in node) {//处理default前缀的属性
                        return !!node[defaults[attribute]];
                    }
                    node = node.getAttributeNode(attribute);
                    return !!(node && (node.specified || node.nodeValue));
                }
            }
            var input;
            //IE6/7/8(Q)中元素的attribute与property内部实现是不分的,IE8部分分离,IE9实现彻底分离了
            //http://www.javaeye.com/topic/757522
            (input = DOC.createElement('input')).setAttribute('value', '5');
            if( input.defaultValue != 5){
                Query.getAttribute = function(node, attr, use_in_query) {
                    if (defaults[attr] in node) {
                        return node[defaults[attr]] || '';
                    }
                    var result = ""
                    if(one_url[attr]){
                        result = node.getAttribute(attr, 2)
                    }else if(use_in_query && one_bool[attr]){
                        result = node.getAttribute(attr) ? attr : ''
                    }else{
                        result = (node = node.getAttributeNode(attr)) && node.value
                    }
                    return result || "";
                }
            }
            //IE6/7/8的getElementsByName有严重bug,只支持搜索表单元素(6-7),并无法区分id与name
            if(DOC.getElementsByName(id).length === 0){//IE9返回正确的长度:2
                delete Query.apis["34"];
            }
            //如果支持sourceIndex我们将使用更为高效的节点排序
            //http://www.cnblogs.com/jkisjk/archive/2011/01/28/array_quickly_sortby.html
            if(whiterat.sourceIndex){
                dom.unique = function(nodes){
                    var result = [], array = [], uniq = {}, node ,index, ri = 0;
                    for(var i = 0 , n = nodes.length; i< n; i++){
                        node = nodes[i];
                        index = node.sourceIndex+1e8;
                        if(!uniq[index]){
                            (array[ri++] = new String(index))._ = node;
                            uniq[index] = 1
                        }
                    }
                    array.sort();
                    while( ri )
                        result[--ri] = array[ri]._;
                    return result;
                }
            }
            //如果支持querySelectorAll
            var one_qsa = {
                1:1,//只使用第一个分支
                2:0,
                9:1
            }
            if ( whiterat.querySelectorAll) {
                if (DOC.documentMode === 8){
                    one_qsa = {
                        1:0,
                        2:1,
                        9:1
                    }
                };
                (function(){
                    var oldQuery = Query;
                    // Safari can't handle uppercase or unicode characters when in quirks mode.
                    if (  whiterat.querySelectorAll("#"+id).length === 0 ) {
                        return;
                    }
                    Query = dom.query = function( expr, context, result, seed ) {
                        context = context || DOC;
                        //http://bugs.jquery.com/ticket/7949
                        if ( !seed && !dom.isXML(context) && !/\:lang\(/.test(expr) ) {
                            expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
                            if ( one_qsa[context.nodeType] ) {// 1 9
                                try {
                                    return dom.slice( context.querySelectorAll(expr) );
                                } catch(e) {}
                            }
                            if ( one_qsa[context.nodeType+1] ) {//2 10
                                var id = context.getAttribute( "id" ),uuid = context.uniqueID
                                if ( !id ) {
                                    context.setAttribute( "id", uuid );
                                }
                                try {
                                    return context.querySelectorAll( "#" + uuid + " " + expr );
                                } catch(e) {
                                } finally {
                                    if ( id == context.uniqueID ) {
                                        context.removeAttribute( "id" );
                                    }
                                }
                            }
                        }
                        return oldQuery(expr, context, result, seed);
                    };
                    for ( var prop in oldQuery ) {
                        Query[ prop ] = oldQuery[ prop ];
                    }
                })();
            }
    
            HTML.removeChild(whiterat);
    
        });
    
    })(this,this.document);
    //2011.9.27  uniqueID改为uniqueNumber 
    //2011.10.20 添加visible与hidden伪类
    //2011.10.21 Fix visible BUG
    
  • 相关阅读:
    zoj 1671 Walking Ant【简单bfs】
    hdoj 2717 Catch That Cow【bfs】
    hdoj 1010 Tempter of the Bone【dfs查找能否在规定步数时从起点到达终点】【奇偶剪枝】
    poj 1321 棋盘问题【dfs】
    [LC] 124. Binary Tree Maximum Path Sum
    [LC] 113. Path Sum II
    [LC] 112. Path Sum
    [LC] 98. Validate Binary Search Tree
    [LC] 39. Combination Sum
    [LC] 159. Longest Substring with At Most Two Distinct Characters
  • 原文地址:https://www.cnblogs.com/rubylouvre/p/2243707.html
Copyright © 2011-2022 走看看