﻿/**
Author: Supersha
Email:supersha@foxmail.com
Copyright: Copyright 2009 Supersha.  All rights reserved.
Homepage: http://www.jsparadise.cn
Download: http://www.jsparadise.cn/download/cSelector.js
Created: 2009-11-27
Modified: 2009-11-28

++cSelector.js++
cSelector类主要是处理简单的通过css规则来选择Document文档中的DOM元素，支持的规则有：
/////////////////
#id,           //
.className,    //
tagName,       //
:first-child,  //
:last-child,   //
:nth-child,    //
:only-child,   //
>,             //
$=,            //
*=,            //
^=,            //
=,             //
[attr]         //
/////////////////
这些css selector可以多级嵌套使用

使用方式：
cSelector("#div");
cSelector("div h2");
cSelector("div p[title=test]");
cSelector("div > p span");
cSelector("#div:first-child");
cSelector(".div > p:nth-child(2n)");
...............

提示：如果选择器（selector）选择出来的只有一个DOM元素，则直接返回该元素，否则返回一个DOM元素数组
//////////////////////////////////////////////
 */
(function(){
    ////////////////////////////////////////////////////////////
    // core global object：核心选择器
    var core = {};
	//将参数转化成数组
    core.toArray = function(obj){
        var returnArr = [];
        for (var i = 0, c; c = obj[i++];) {
            returnArr.push(c);
        }
        return returnArr;
    }
	//这个方法是核心方法，css参数为selector
	//比如："div span","#div:nth-child(2n)"等等
    core.select = function(css){
        if (!css) return document;
		//temp参数的用途在于保存每一级所选择到的DOM元素
        var selectors = Selector.parse(css), temp = [], elems = [], len = selectors.length;
        if (len === 1) 
            elems = Selector.getElements(selectors[0], document, true);
        for (var i = 0; i < len; i++) {
            if (i === 0) {
                elems = Selector.getElements(selectors[0], document, true);
            } else {
                var j = 0, e;
                while (e = elems[j++]) {
                    temp = temp.concat(core.toArray(Selector.getElements(selectors[i], e, false)));
                }
                elems = temp;
                temp = [];
            }
        }
        return elems;
    }
    
    ////////////////////////////////////////
    //Selector object  ：格式化selector，执行指定的ElementsGetter对象的方法
    var Selector = {};
	//格式化selector字符串，并返回一个包含key,match,reg的数组
	//原理：将selectors分级。比如："div span:first-child",将分成"div","span",":first-child"三个级，每个级就是一个数组向，以此类推
    Selector.parse = function(css){
        var cssPasers = [], trans = Selector.transitions;
        var i = 0, c;
        while (c = trans[i++]) {
            css = css.replace(c[0], function(m, p){
                cssPasers.push([c[2], p, c[1]]);
                i = 0;
                return "";
            });
        }
        return cssPasers;
    }
	//编码所支持的css selector类别，格式是：[matchReg,reg,key]
    Selector.transitions = [
	    [/^\s?(#[\w_]+)/, /#([\w_]+)/, "#"], 
		[/^\s?(\.[\w_]+)/, /\.([\w_]+)/, "."], 
		[/^\s?(\w+)/, /(\w+)/, "tag"], 
		[/^\s?(>\s?[^\s:\.]+)/, />\s?([^\s:\.]+)/, ">"], 
		[/^\s?(:first-child)/, /(:first-child)/, ":first-child"], 
		[/^\s?(:last-child)/, /(:last-child)/, ":last-child"], 
		[/^\s?(:nth-child\([n\d]+\))/, /:nth-child\(([n\d]+)\)/, ":nth-child"], 
		[/^\s?(:only-child)/, /(:only-child)/, ":only-child"], 
		[/^\s?(\[[^\s]+\^=.+\])/, /\[([^\s]+)\^=(.+)\]/, "^="], 
		[/^\s?(\[[^\s]+\*=.+\])/, /\[([^\s]+)\*=(.+)\]/, "*="], 
		[/^\s?(\[[^\s]+\$=.+\])/, /\[([^\s]+)\$=(.+)\]/, "$="], 
		[/^\s?(\[[^\s]+=.+)/, /\[([^\s]+)=(.+)\]/, "="], 
		[/^\s?(\[[^\s]+\])/, /\[([^\s]+)\]/, "["]
	];
	//辅助core的select方式来进行选择DOM元素
	//arr是Selector.parse方法返回的selectors的一项，
	//elem是Element元素，
	//flag是用于区别是几级的selectors，比如：“div”为一级，“div span”为两级，"div span:first-child"为三级等等以此类推
    Selector.getElements = function(arr, elem, flag){
        var key = arr[0], match = arr[1], reg = arr[2], css = reg.test(match);
        if (flag) {  //如果只有一级selector
            return ElementsGetter[key](RegExp.$1, elem, null);
        } else {   //存在多级的selectors
            //根据Selector.transitions中key的判断来调用不同的函数
            if (".#tag".indexOf(key) !== -1) {
                return ElementsGetter[key](RegExp.$1, elem, null);
            } else if (/(child)|>/.test(key)) {
                return ElementsGetter[key === ">" ? ">" : "getByChild"](match, key, reg, elem);
            } else if (/=|\[/.test(key)) {
                //alert("true");
                return ElementsGetter["getByAttr"](match, key, reg, elem);
            }
        }
    }
    
    /////////////////////////////////////
    //ElementsGetter object：用于选择各项selector的DOM元素
    var ElementsGetter = {};
	//获取包含ID的DOM元素（数组的方式）
	//参数e，c是为了跟tag和.函数进行模块化执行，所以并没有意义
    ElementsGetter["#"] = function(id, e, c){
        return [typeof id === "string" ? document.getElementById(id) : id];
    }
	//获取通过tagName查询的DOM元素
	//参数c是为了跟#和.函数进行模块化执行，所以并没有意义
    ElementsGetter["tag"] = function(t, e, c){
        return (e || document).getElementsByTagName(t || "*");
    }
	//通过className获取DOM元素
	//c:className
	//e:Element
	//t:tagName
    ElementsGetter["."] = function(c, e, t){
        var returnElems = [], elems = this["tag"](t, e, c), reg = new RegExp("(^|\\s)" + c + "(\\s|$)");
        for (var i = 0, els; els = elems[i++];) {
            if (reg.test(els.className)) {
                returnElems.push(els);
            }
        }
        return returnElems;
    }
	//返回属性的值
    ElementsGetter.getAttr = function(elem, a){
		//处理class，for等特殊的情况
        var special = {"class": "className","for": "htmlFor"};
        a = special[a] ? spacial[a] : a;
        return elem[a];
    }
	//处理css selector "*=,$=,^=,=,[]"等选择符
	//attr:通过Selector.parse匹配到的每一级selector
	//key:Selector.transitions中的key列
	//reg:Selector.transitions中的匹配正则
	//e:Element
    ElementsGetter.getByAttr = function(attr, key, reg, e){
        var returnElems = [], getAttr = ElementsGetter.getAttr, r = reg.test(attr), attrStr = getAttr(e, RegExp.$1);
        if (attrStr) {
            var index = attrStr.indexOf(RegExp.$2);
            switch (key) {
                case "^=":
                    index === 0 ? returnElems.push(e) : null;
                    break;
                case "=":
                    attrStr === RegExp.$2 ? returnElems.push(e) : null;
                    break;
                case "*=":
                    index !== -1 ? returnElems.push(e) : null;
                    break;
                case "$=":
                    new RegExp(".*" + RegExp.$2 + "$").test(attrStr) ? returnElems.push(e) : null;
                    break;
                case "[":
                    getAttr(e, attr.replace(/\[|\]/g, "")) ? returnElems.push(e) : null;
                    break;
                default:
                    break;
            }
        }
        return returnElems;
    }
	//处理css selector "first-child,last-child,only-child"等选择符
    ElementsGetter.getByChild=function(attr,key,reg,e){
        var returnElems=[],el=null;
        switch(key){
	         case ":first-child":
	             el=e.firstChild;
	             while(el && el.nodeType !== 1) el=el.nextSibling;
	             returnElems.push(el);
	             break;
             case ":last-child":
	             el=e.lastChild;
	             while(el && el.nodeType !== 1) el=el.nextSibling;
	             returnElems.push(el);
	             break;
	         case ":only-child":
	             el=e.childNodes;
	             var i=0,ell=null;
	             while(ell = el[i++]) ell.nodeType === 1 ? returnElems.push(ell) : null;
	             break;
             case ":nth-child":
	             var t=reg.test(attr),r=RegExp.$1,s="",childs=e.childNodes,l=childs.length;
	             s = r.replace(/(\(?n)/,function(m, p){
				 	return r === p ? p : "*" + p;
				 });
	             eval("for(var n = 0;" + s + "< l; n++){if(childs[" + s + "].nodeType === 1){returnElems.push(childs[" + s + "]);}}");
	             break;
	        default:break;   
        }
        return returnElems;
    }
	//处理css selector ">"等选择符
    ElementsGetter[">"] = function(attr, key, reg, e){
        var returnElems = [], el = e.childNodes[0];
        while (el && el.nodeType === 1) {
            returnElems.push(el);
            el = el.nextSibling;
        }
        return returnElems;
    }
    
    ////////////////////////////
    //定义cSelector类
    try {cSelector}catch (e) { cSelector = core.select;}
})();
(function(global){
	global.Evt=!global.Evt ? {} :global.Evt;
	Evt.addListener=function(elem,type,fn){
		if(elem.addEventListener){
			elem.addEventListener(type,fn,false);
		}else if(elem.attachEvent){
			elem.attachEvent("on"+type,function(){fn.call(elem);});
		}else{
			elem["on"+type]=fn;
		}
	}
	
	Evt.on=function(type,fn,id,o){
		var els=cSelector(id);
		for(var i=0,l=els.length;i<l;i++){
			Evt.addListener(els[i],type,o ? function(){
				fn.call(o);
			} : fn);
		}
		return els;
	}
})(window);
