代码改变世界

mootools Selectors.js

2009-05-15 10:48  贪婪的小猪  阅读(248)  评论(0编辑  收藏  举报
/*
Script: Selectors.js
    Adds advanced CSS Querying capabilities for targeting elements. Also includes pseudoselectors support.

License:
    MIT-style license.
*/


Native.implement([Document, Element], 
{

    getElements: 
function(expression, nocash){
        expression 
= expression.split(',');
        
var items, local = {};
        
for (var i = 0, l = expression.length; i < l; i++){
            
var selector = expression[i], elements = Selectors.Utils.search(this, selector, local);
            
if (i != 0 && elements.item) elements = $A(elements);
            items 
= (i == 0? elements : (items.item) ? $A(items).concat(elements) : items.concat(elements);
        }

        
return new Elements(items, {ddup: (expression.length > 1), cash: !nocash});
    }


}
);

Element.implement(
{

    match: 
function(selector){
        
if (!selector || (selector == this)) return true;
        
var tagid = Selectors.Utils.parseTagAndID(selector);
        
var tag = tagid[0], id = tagid[1];    //只有tag 将返回false  ,只有id tag将被设置为'*'
        if (!Selectors.Filters.byID(this, id) || !Selectors.Filters.byTag(this, tag)) return false;
        
var parsed = Selectors.Utils.parseSelector(selector);
        
return (parsed) ? Selectors.Utils.filter(this, parsed, {}) : true;//有匹配直接返回true
    }


}
);

var Selectors = {Cache: {nth: {}, parsed: {}}};

Selectors.RegExps 
= {
    id: (
/#([\w-]+)/),
    tag: (
/^(\w+|\*)/),//
    quick: (/^(\w+|\*)$/),
    splitter: (
/\s*([+>~\s])\s*([a-zA-Z#.*:\[])/g),// # +a s>:>[+. .\ne
    combined: (/\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)(["']?)([^\4]*?)\4)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g)
}
;                        //( .w .-.u.qq) | [a!='qe'] [ddq|=''] [eewq$='#21d'] | :dw('dwq1') :s() :w<--:w在最后一个才成立

Selectors.Utils 
= {

    chk: 
function(item, uniques){
        
if (!uniques) return true;
        
var uid = $uid(item);
        
if (!uniques[uid]) return uniques[uid] = true;
        
return false;
    }
,

    parseNthArgument: 
function(argument){
        
if (Selectors.Cache.nth[argument]) return Selectors.Cache.nth[argument];
        
var parsed = argument.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/);//+33 +2a-33
        if (!parsed) return false;
        
var inta = parseInt(parsed[1], 10);
        
var a = (inta || inta === 0? inta : 1;
        
var special = parsed[2|| false;
        
var b = parseInt(parsed[3], 10|| 0;
        
if (a != 0){//-33n-2 -33!=0   33n-2
            b--;//-2-- 
            while (b < 1) b += a;//说明a不可能是负数 要不就是死循环  b=-3+33=30 
            while (b >= a) b -= a;//30<33     b要大于1小于a
        }
 else {//+0a-33
            a = b;//a=-33 b=-33
            special = 'index';
        }

        
switch (special){
            
case 'n': parsed = {a: a, b: b, special: 'n'}break;
            
case 'odd': parsed = {a: 2, b: 0, special: 'n'}break;
            
case 'even': parsed = {a: 2, b: 1, special: 'n'}break;
            
case 'first': parsed = {a: 0, special: 'index'}break;
            
case 'last': parsed = {special: 'last-child'}break;
            
case 'only': parsed = {special: 'only-child'}break;
            
default: parsed = {a: (a - 1), special: 'index'};
        }


        
return Selectors.Cache.nth[argument] = parsed;
    }
,

    parseSelector: 
function(selector){
        
if (Selectors.Cache.parsed[selector]) return Selectors.Cache.parsed[selector];
        
var m, parsed = {classes: [], pseudos: [], attributes: []};
        
while ((m = Selectors.RegExps.combined.exec(selector))){
            
var cn = m[1], an = m[2], ao = m[3], av = m[5], pn = m[6], pa = m[7];
            
if (cn){
                parsed.classes.push(cn);
            }
 else if (pn){
                
var parser = Selectors.Pseudo.get(pn);
                
if (parser) parsed.pseudos.push({parser: parser, argument: pa});
                
else parsed.attributes.push({name: pn, operator: '=', value: pa});
            }
 else if (an){
                parsed.attributes.push(
{name: an, operator: ao, value: av});
            }

        }

        
if (!parsed.classes.length) delete parsed.classes;
        
if (!parsed.attributes.length) delete parsed.attributes;
        
if (!parsed.pseudos.length) delete parsed.pseudos;
        
if (!parsed.classes && !parsed.attributes && !parsed.pseudos) parsed = null;
        
return Selectors.Cache.parsed[selector] = parsed;
    }
,

    parseTagAndID: 
function(selector){//www#dsa 这样tag和id都有值 记住www一定要顶格写
        var tag = selector.match(Selectors.RegExps.tag);
        
var id = selector.match(Selectors.RegExps.id);
        
return [(tag) ? tag[1] : '*', (id) ? id[1] : false];
    }
,

    filter: 
function(item, parsed, local){
        
var i;
        
if (parsed.classes){
            
for (i = parsed.classes.length; i--; i){
                
var cn = parsed.classes[i];
                
if (!Selectors.Filters.byClass(item, cn)) return false;
            }

        }

        
if (parsed.attributes){
            
for (i = parsed.attributes.length; i--; i){
                
var att = parsed.attributes[i];
                
if (!Selectors.Filters.byAttribute(item, att.name, att.operator, att.value)) return false;
            }

        }

        
if (parsed.pseudos){
            
for (i = parsed.pseudos.length; i--; i){
                
var psd = parsed.pseudos[i];
                
if (!Selectors.Filters.byPseudo(item, psd.parser, psd.argument, local)) return false;
            }

        }

        
return true;
    }
,

    getByTagAndID: 
function(ctx, tag, id){
        
if (id){
            
var item = (ctx.getElementById) ? ctx.getElementById(id, true) : Element.getElementById(ctx, id, true);
            
return (item && Selectors.Filters.byTag(item, tag)) ? [item] : [];
        }
 else {
            
return ctx.getElementsByTagName(tag);
        }

    }
,

    search: 
function(self, expression, local){
        
var splitters = [];
                                            
//(/\s*([+>~\s])\s*([a-zA-Z#.*:\[])/g),//( # +a s>:>[+. .\ne)
        var selectors = expression.trim().replace(Selectors.RegExps.splitter, function(m0, m1, m2){
            splitters.push(m1);
            
return ':)' + m2;//把+>~\s都去掉
        }
).split(':)');

        
var items, filtered, item;

        
for (var i = 0, l = selectors.length; i < l; i++){

            
var selector = selectors[i];
                                    
//(/^(\w+|\*)$/) 
            if (i == 0 && Selectors.RegExps.quick.test(selector)){
                items 
= self.getElementsByTagName(selector);
                
continue;
            }


            
var splitter = splitters[i - 1];

            
var tagid = Selectors.Utils.parseTagAndID(selector);//(tag #id)格式
            var tag = tagid[0], id = tagid[1];

            
if (i == 0){
                items 
= Selectors.Utils.getByTagAndID(self, tag, id);
            }
 else {
                
var uniques = {}, found = [];
                
for (var j = 0, k = items.length; j < k; j++) found = Selectors.Getters[splitter](found, items[j], tag, id, uniques);
                items 
= found;
            }


            
var parsed = Selectors.Utils.parseSelector(selector);

            
if (parsed){
                filtered 
= [];
                
for (var m = 0, n = items.length; m < n; m++){
                    item 
= items[m];
                    
if (Selectors.Utils.filter(item, parsed, local)) filtered.push(item);
                }

                items 
= filtered;
            }


        }


        
return items;

    }


}
;

Selectors.Getters 
= {

    
' 'function(found, self, tag, id, uniques){//found=[],uniques={}
        var items = Selectors.Utils.getByTagAndID(self, tag, id);
        
for (var i = 0, l = items.length; i < l; i++){
            
var item = items[i];//没有 就添加
            if (Selectors.Utils.chk(item, uniques)) found.push(item);//没有uniques或没有uniques[$uid(item)]就返回true和uniques[$uid(item)]=true
        }

        
return found;
    }
,

    
'>'function(found, self, tag, id, uniques){
        
var children = Selectors.Utils.getByTagAndID(self, tag, id);
        
for (var i = 0, l = children.length; i < l; i++){
            
var child = children[i];//是其子元素 且 没有 就添加
            if (child.parentNode == self && Selectors.Utils.chk(child, uniques)) found.push(child);
        }

        
return found;
    }
,

    
'+'function(found, self, tag, id, uniques){
        
while ((self = self.nextSibling)){//下一个兄弟节点
            if (self.nodeType == 1){//是节点元素 且没有 且 id和tag都吻合   才添加
                if (Selectors.Utils.chk(self, uniques) && Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self);
                
break;
            }

        }

        
return found;
    }
,

    
'~'function(found, self, tag, id, uniques){
        
while ((self = self.nextSibling)){//下一个兄弟节点
            if (self.nodeType == 1){//是节点元素
                if (!Selectors.Utils.chk(self, uniques)) break;//有就跳出 结束
                if (Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self);
            }
                        //且id 和 tag吻合才添加
        }

        
return found;
    }


}
;

Selectors.Filters 
= {

    byTag: 
function(self, tag){
        
return (tag == '*' || (self.tagName && self.tagName.toLowerCase() == tag));
    }
,

    byID: 
function(self, id){
        
return (!id || (self.id && self.id == id));
    }
,

    byClass: 
function(self, klass){
        
return (self.className && self.className.contains(klass, ' '));
    }
,

    byPseudo: 
function(self, parser, argument, local){
        
return parser.call(self, argument, local);
    }
,

    byAttribute: 
function(self, name, operator, value){
        
var result = Element.prototype.getProperty.call(self, name);
        
if (!result) return (operator == '!=');
        
if (!operator || value == undefined) return true;
        
switch (operator){
            
case '='return (result == value);
            
case '*='return (result.contains(value));
            
case '^='return (result.substr(0, value.length) == value);
            
case '$='return (result.substr(result.length - value.length) == value);
            
case '!='return (result != value);
            
case '~='return result.contains(value, ' ');
            
case '|='return result.contains(value, '-');
        }

        
return false;
    }


}
;

Selectors.Pseudo 
= new Hash({

    
// w3c pseudo selectors

    checked: 
function(){
        
return this.checked;
    }
,
    
    empty: 
function(){
        
return !(this.innerText || this.textContent || '').length;
    }
,

    not: 
function(selector){
        
return !Element.match(this, selector);
    }
,

    contains: 
function(text){
        
return (this.innerText || this.textContent || '').contains(text);
    }
,

    
'first-child'function(){
        
return Selectors.Pseudo.index.call(this0);
    }
,

    
'last-child'function(){
        
var element = this;
        
while ((element = element.nextSibling)){
            
if (element.nodeType == 1return false;
        }

        
return true;
    }
,

    
'only-child'function(){
        
var prev = this;
        
while ((prev = prev.previousSibling)){
            
if (prev.nodeType == 1return false;
        }

        
var next = this;
        
while ((next = next.nextSibling)){
            
if (next.nodeType == 1return false;
        }

        
return true;
    }
,

    
'nth-child'function(argument, local){//
        argument = (argument == undefined) ? 'n' : argument;
        
var parsed = Selectors.Utils.parseNthArgument(argument);
        
if (parsed.special != 'n'return Selectors.Pseudo[parsed.special].call(this, parsed.a, local);
        
var count = 0;//当parsed.special=='n'时 才继续实行下面的
        local.positions = local.positions || {};
        
var uid = $uid(this);
        
if (!local.positions[uid]){//如果没有 就执行{}内的
            var self = this;
            
while ((self = self.previousSibling)){//如果有上一个兄弟节点
                if (self.nodeType != 1continue;//要是元素节点才继续
                count ++;
                
var position = local.positions[$uid(self)];
                
if (position != undefined){//如果 就跳出   -里面标记了还有多少个  杀一个兄弟节点 就不用在count++了 
                    count = position + count;
                    
break;
                }

            }

            local.positions[uid] 
= count;//
        }

        
return (local.positions[uid] % parsed.a == parsed.b);//上面的元素节点数%a   余数是否等于b
    }
,

    
// custom pseudo selectors

    index: 
function(index){
        
var element = this, count = 0;
        
while ((element = element.previousSibling)){
            
if (element.nodeType == 1 && ++count > index) return false;
        }

        
return (count == index);
    }
,

    even: 
function(argument, local){
        
return Selectors.Pseudo['nth-child'].call(this'2n+1', local);
    }
,

    odd: 
function(argument, local){
        
return Selectors.Pseudo['nth-child'].call(this'2n', local);
    }
,
    
    selected: 
function() {
        
return this.selected;
    }


}
);
js格式化工具 js格式化工具