zoukankan      html  css  js  c++  java
  • jsADS的库(待更新)

    /**
     * project:javascript DOM Advanced
     */
    (function () {
        'use strict';
        //ADS命名空间
        //判断ADS对象是否存在,否则创建
        if (!window.ADS) {
            window.ADS = {};
        }
    
        //确定当前浏览器是否与整个库兼容
        function isCompatible(other) {
            //使用能力检测来检查必要条件
            if (other === false || !Array.prototype.push || !Object.hasOwnProperty || !document.createElement || !document.getElementsByTagName) {
                return false;
            }
            return true;
        }
    
        window.ADS.isCompatible = isCompatible;
    
        function $() {
            var elements = [];
            //查找作为参数提供的所有元素
            for (var i = 0; i < arguments.length; i++) {
                var element = arguments[i];
                //如果这参数是一个字符串那假设它是一个id
                if (typeof element === "string") {
                    element = document.getElementById(element);
                }
                //如果只提供一个参数
                //则立即返回这个元素
                if (arguments.length === 1) {
                    return element;
                }
                //否则,将它添加到数组中
                elements.push(element);
            }
            //返回包含多个被请求元素的数组
            return elements;
        }
    
        window.ADS.$ = $;
    
        /**
         * addEvent(node, type, listener)   添加事件程序处理
         * @param node DOM节点元素
         * @param type 事件类型
         * @param listener 事件函数
         * @return {Boolean}
         */
        function addEvent(node, type, listener) {
            //使用方法检查兼容性以保证平稳退化
            if (!isCompatible()) {
                return false;
            }
            //检查是不是DOM对象的引用
            if (!(node = $(node))) {
                return false;
            }
            if (node.addEventListener) {
                //W3C的方法
                node.addEventListener(type, listener, false);       //第三个参数为true时则启用捕获阶段
                return true;
            } else {
                //MSIE的方法
                //修正ie事件中this指向window的问题
                //把执行函数赋给自定义对象属性
                node["e" + type + listener] = listener;
                //把事件函数赋给自定义对象属性
                node[type + listener] = function () {
                    node["e" + type + listener](window.event);
                };
                node.attachEvent("on" + type, node[type + listener]);
                return true;
            }
            //若两种方法都不具备则返回false
            return false;
        }
    
        window.ADS.addEvent = addEvent;
    
        /**
         * load事件在嵌入图像载入完成之前运行
         * @param {Function} loadEvent
         * @param {Boolean} waitForImages 当为true时,调用原始的addEvent()方法,等待加载完毕后才执行
         * demo:
         *      ADS.addLoadEvent(function(w3cEvent){
         *          //...
         *      });
         */
        function addLoadEvent(loadEvent, waitForImages) {
            if (!isCompatible()) {
                return false;
            }
    
            //如果等待标记是true则使用常规的添加事件的方法
            if (waitForImages) {
                return addEvent(window, 'load', loadEvent);
            }
    
            //否则使用一些不同的方式包装loadEvent()方法
            //以便为this关键字制定正确的内容,同时确定
            //事件不会被执行两次
            var init = function () {
                //如果这个函数已经被调用过了则返回
                if (init.done) {
                    return;
                }
    
                //标记这个函数以便检测它是否运行过
                init.done = true;
    
                //在document的环境中运行载入事件
                loadEvent.apply(document, arguments);
            };
    
            //为DOMContentLoaded事件注册事件侦听器
            if (document.addEventListener) {
                document.addEventListener('DOMContentLoaded', init, false);
            }
    
            //对于safari,使用setInterval()函数检测
            //document是否载入完成
            if (/WebKit/i.test(navigator.userAgent)) {
                var _timer = setInterval(function () {
                    if (/loaded|complete/.test(document.readyState)) {
                        clearInterval(_timer);
                        init();
                    }
                }, 10);
            }
    
            //对于IE(使用条件注释)
            //附加一个在载入过程最后执行的脚本
            //并检测该脚本是否载入完成
            /*@cc_on @*/
            /*@if (@_win32)
             document.write("<script id=_ie_onload defer src=javascript:void(0)><\/script>");
             var script = document.getElementById('_ie_onload');
             script.onreadystatechange = function(){
             if((this.readyState === 'complete') || this.readyState === 'loaded'){
             init();
             }
             };
             /*@end @*/
            return true;
        }
    
        window.ADS.addLoadEvent = addLoadEvent;
    
        function removeEvent(node, type, listener) {
            if (!(node = $(node))) {
                return false;
            }
            if (node.removeEventListener) {
                //W3C 方法
                node.removeEventListener(type, listener, false);
                return true;
            } else if (node.detachEvent) {
                //MSIE方法
                node.detachEvent("on" + type, node[type + listener]);
                node[type + listener] = null;
                return true;
            }
            //若两种方法都不具备则返回false
            return false;
        }
    
        window.ADS.removeEvent = removeEvent;
    
        /**
         * 获取event事件对象
         * @param w3cEvent
         * @return {*|Event}
         */
        function getEventObject(w3cEvent) {
            return w3cEvent || window.event;
        }
    
        window.ADS.getEventObject = getEventObject;
    
        function getTarget(event) {
            event = event || getEventObject(event);
    
            //如果是w3c或MSIE的模型
            var target = event.target || event.srcElement;
    
            //如果像Safari中一样是一个文本节点
            //重新将目标对象指定为父元素
            if (target.nodeType === 3) {
                target = target.parentNode;
            }
    
            return target;
        }
    
        window.ADS.getTarget = getTarget;
    
        function getMouseButton(event) {
            event = event || getEventObject(event);
    
            //使用适当的属性初始化一个对象变量
            var buttons = {
                left: false,
                middle: false,
                right: false
            };
    
            //检查event对象的toString()方法的值
            //w3c有toString方法并且此时该方法的
            // 返回应该是MouseEvent
            if (event.toString() && event.toString().indexOf('MouseEvent') !== -1) {
                //w3c
                switch (event.button) {
                    case 0:
                        buttons.left = true;
                        break;
                    case 1:
                        buttons.middle = true;
                        break;
                    case 2:
                        buttons.right = true;
                        break;
                    default:
                        break;
                }
            } else if (event.button) {
                //MSIE
                switch (event.button) {
                    case 1:
                        buttons.left = true;
                        break;
                    case 2:
                        buttons.right = true;
                        break;
                    case 3:
                        buttons.left = true;
                        buttons.right = true;
                        break;
                    case 4:
                        buttons.middle = true;
                        break;
                    case 5:
                        buttons.left = true;
                        buttons.middle = true;
                        break;
                    case 6:
                        buttons.middle = true;
                        buttons.right = true;
                        break;
                    case 7:
                        buttons.left = true;
                        buttons.middle = true;
                        buttons.right = true;
                        break;
                    default:
                        break;
    
                }
            } else {
                return false;
            }
            return buttons;
        }
    
        window.ADS.getMouseButton = getMouseButton;
    
        /**
         * 光标相对于文档原点的位置
         * @param {event} event
         * @return {Object}
         */
        function getPointerPositionInDocument(event) {
            event = event || getEventObject(event);
            var x = event.pageX || (event.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft));
            var y = event.pageY || (event.clientY + (document.documentElement.scrollTop || document.body.scrollTop));
            //现在x和y中包含着鼠标
            //相对于文档原点的坐标
            return {
                x: x,
                y: y
            };
        }
    
        window.ADS.getPointerPositionInDocument = getPointerPositionInDocument;
    
        /**
         * 获取键盘按键的Unicode值
         * @param event
         * @return {Object}
         */
        function getKeyPressed(event) {
            event = event || getEventObject(event);
    
            //charCode for FF
            var code = (typeof event.charCode === 'number') ? event.charCode : event.keyCode;
            var value = String.fromCharCode(code);
            return {
                code: code,
                value: value
            };
        }
    
        window.ADS.getKeyPressed = getKeyPressed;
    
        /**
         * getElementsByClassName(className, tag, parent)    获取class为className的DOM元素
         * @param searchClass 类名 (第二个函数可实现多类名查询)
         * @param node DOM元素
         * @param tag 标签名
         * @return {*}
         */
        /*原书
         function getElementsByClassName(className, tag, parent) {
         parent = parent || document;
         if (!(parent = $(parent))) {
         return false;
         }
         //查找所有匹配的标签
         //由于IE5不支持document.getElementsByTagName("*"),要使用分支document.all以防错误
         var allTags = (tag == "*" && parent.all) ? parent.all : parent.getElementsByTagName(tag);
         var matchingElements = [];
         //创建一个正则表达式,来判断className是否正确
         className = className.replace(/\-/g, "\\-");
         var regex = new RegExp("(^|\\s)" + className + "(\\s|$)");
         var element;
         if (document.getElementsByClassName) {
         return document.getElementsByClassName(className);
         } else {
         //检查每个元素
         for (var i = 0; i < allTags.length; i++) {
         element = allTags[i];
         if (regex.test(element.className)) {
         matchingElements.push(element);
         }
         }
         //返回任何匹配的元素
         return matchingElements;
         }
         }*/
        function getElementsByClassName(searchClass, tag, node) {
            node = node || document;
            tag = tag || "*";
            if (!(node = $(node))) {
                return false;
            }
            //如果支持原生getElementsByClassName
            if (document.getElementsByClassName) {
                //获取所有匹配的className的DOM元素
                var nodes = node.getElementsByClassName(searchClass),
                    result = nodes;
                //如果tag被定义了
                if (tag !== '*') {
                    result = [];
                    for (var i = 0; node = nodes[i]; i++) {
                        //匹配标签名为非“*”的标签
                        if (node.tagName.toLowerCase() === tag.toLowerCase()) {
                            result.push(node);
                        }
                    }
                }
                return result;
            } else {
                //不支持原生getElementsByClassName的
                var classes = searchClass.split(" "), //要查询的所有className
                    elements = (tag === "*" && node.all) ? node.all : node.getElementsByTagName(tag), //获取所有匹配的标签DOM元素
                    patterns = [],
                    returnElements = [],
                    current,
                    match;
                var i = classes.length;
                while (--i >= 0) {
                    patterns.push(new RegExp("(^|\\s)" + classes[i] + "(\\s|$)"));
                }
                var j = elements.length;
                while (--j >= 0) {
                    current = elements[j];
                    match = false;
                    //每个元素的className分别和要查询的className对比
                    for (var k = 0, kl = patterns.length; k < kl; k++) {
                        match = patterns[k].test(current.className);
                        if (!match) {
                            break;
                        }
                    }
                    if (match) {
                        returnElements.push(current);
                    }
                }
                return returnElements;
            }
        }
    
        window.ADS.getElementsByClassName = getElementsByClassName;
        //运用:var a = ADS.getElementsByClassName("li", "li", document);
    
        function toggleDisplay(node, value) {
            if (!(node = $(node))) {
                return false;
            }
            if (node.style.display !== "none") {
                node.style.display = "none";
            } else {
                node.style.display = value || "";
            }
            return true;
        }
    
        window.ADS.toggleDisplay = toggleDisplay;
    
        /**
         * DOM操作:将节点插入到目标节点之后
         * @param node 新节点
         * @param referenceNode 目标节点
         * @return {*}
         * etc: ADS.insertAfter("l1","l2");
         */
        function insertAfter(node, referenceNode) {
            if (!(node = $(node))) {
                return false;
            }
            if (!(referenceNode = $(referenceNode))) {
                return false;
            }
            return referenceNode.parentNode.insertBefore(node, referenceNode.nextSibling);
        }
    
        window.ADS.insertAfter = insertAfter;
    
        /**
         * 删除所有子节点
         * @param parent 父节点
         * @return {*}
         */
        function removeChildren(parent) {
            if (!(parent = $(parent))) {
                return false;
            }
            //当存在子节点时删除该子节点
            while (parent.firstChild) {
                parent.firstChild.parentNode.removeChild(parent.firstChild);
            }
            //再返回父元素,以便实现方法连缀
            return parent;
        }
    
        window.ADS.removeChildren = removeChildren;
    
        /**
         * 添加为节点第一个子节点
         * @param parent 父节点
         * @param newChild 新节点
         * @return {*}
         */
        function prependChild(parent, newChild) {
            if (!(parent = $(parent))) {
                return false;
            }
            if (!(newChild = $(newChild))) {
                return false;
            }
            if (parent.firstChild) {
                //如果存在一个子节点,则在这个字节点之前插入
                parent.insertBefore(newChild, parent.firstChild);
            } else {
                //如果没有子节点则直接添加
                parent.appendChild(newChild);
            }
            //再返回父元素,以便实现方法连缀
            return parent;
        }
    
        window.ADS.prependChild = prependChild;
    
        /**
         * 绑定函数到指定作用域
         * @param obj 对象
         * @param func 函数
         * @return {Function}
         */
        function bindFunction(obj, func) {
            return function () {
                //调用func函数,指定环境为obj,添加arguments参数
                func.apply(obj, arguments);
            };
        }
    
        window.ADS.bindFunction = bindFunction;
    
        /**
         * 获取浏览器窗口大小
         * @return {Object}
         */
        function getWinSize() {
            var de = document.documentElement;
            return {
                'width': (window.innerWidth || (de && de.clientWidth) || document.body.clientWidth),
                'height': (window.innerHeight || (de && de.clientHeight) || document.body.clientHeight)
    
            };
        }
    
        window.ADS.getWinSize = getWinSize;
    
        /**
         * 定义DOM常量
         * @type {Object}
         */
        window.ADS.node = {
            ELEMENT_NODE: 1,
            ATTRIBUTE_NODE: 2,
            TEXT_NODE: 3,
            CDATA_SECTION_NODE: 4,
            ENTITY_REFERENCE_NODE: 5,
            ENTITY_NODE: 6,
            PROCESSING_INSTRUCTION_NODE: 7,
            COMMENT_NODE: 8,
            DOCUMENT_NODE: 9,
            DOCUMENT_TYPE_NODE: 10,
            DOCUMENT_FRAGMENT_NODE: 11,
            NOTATION_NODE: 12
        };
    
        /**
         * 遍历DOM,并调用函数(效率最慢)
         * @param {Function} func
         * @param {Node} node
         */
        function walkElementsLinear(func, node) {
            var root = node || window.document;
            var nodes = root.getElementsByTagName('*');
            for (var i = 0, len = nodes.length; i < len; i++) {
                func.call(nodes[i]);
            }
        }
    
        window.ADS.walkElementsLinear = walkElementsLinear;
    
        /**
         * 迭代DOM
         * @param {Function} func
         * @param {Node} node
         * @param {Number} depth
         * @param returnedFromParent
         */
        function walkTheDOMRecursive(func, node, depth, returnedFromParent) {
            var root = node || window.document;
            //父节点调用函数的返回值,作为子节点调用函数时候的参数
            returnedFromParent = func.call(root, depth++, returnedFromParent);
            node = root.firstChild;
            while (node) {
                //迭代该节点后代元素
                walkTheDOMRecursive(func, node, depth, returnedFromParent);
                //移向下一个子节点
                node = node.nextSibling;
            }
        }
    
        window.ADS.walkTheDOMRecursive = walkTheDOMRecursive;
    
        /**
         * 迭代DOM节点的属性
         * @param {Node} node
         * @param {Function} func
         * @param {Number} depth
         * @param returnedFromParent
         */
        function walkTheDOMWithAttributes(node, func, depth, returnedFromParent) {
            var root = node || window.document;
            returnedFromParent = func(root, depth++, returnedFromParent);
            if (root.attributes) {
                for (var i = 0; i < root.attributes.length; i++) {
                    walkTheDOMWithAttributes(root.attributes[i], func, depth - 1, returnedFromParent);
                }
            }
            if (root.nodeType !== window.ADS.node.ATTRIBUTE_NODE) {
                node = root.firstChild;
                while (node) {
                    walkTheDOMWithAttributes(node, func, depth, returnedFromParent);
                    node = node.nextSibling;
                }
            }
        }
    
        window.ADS.walkTheDOMWithAttributes = walkTheDOMWithAttributes;
    
        function walkTheDOM(node, func) {
            func(node);
            node = node.firstChild;
            while (node) {
                walkTheDOM(node, func);
                node = node.nextSibling;
            }
        }
    
        window.ADS.walkTheDOM = walkTheDOM;
    
        /**
         * 把word-word转换为wordWord
         * @param {String} s
         * @return {String|XML|void}
         */
        function camelize(s) {
            return s.replace(/-(\w)/g, function (strMatch, p1) {    //strMatch为正则匹配的字符
                //p1为\w匹配的一个字符
                return p1.toUpperCase();
            });
        }
    
        window.ADS.camelize = camelize;
    
        /**
         * 阻止事件冒泡
         * @param {event} eventObject
         */
        function stopPropagation(eventObject) {
            eventObject = eventObject || getEventObject(eventObject);
            if (eventObject.stopPropagation) {
                eventObject.stopPropagation();
            } else {
                eventObject.cancelBubble = true;
            }
        }
    
        window.ADS.stopPropagation = stopPropagation;
    
        /**
         * 取消默认事件
         * @param {event} eventObject
         * 可被取消的DOM事件:
         * click, mousedown, mouseup, mouseover, mouseout, submit, DOMActive及键盘事件
         */
        function preventDefault(eventObject) {
            eventObject = eventObject || getEventObject(eventObject);
            if (eventObject.preventDefault) {
                eventObject.preventDefault();
            } else {
                eventObject.returnValue = false;
            }
        }
    
        window.ADS.preventDefault = preventDefault;
    
        function uncamelize(property, splitChar) {
            return property.replace(/([a-z])([A-Z])/, '$1' + splitChar + '$2').toLowerCase();
        }
    
        window.ADS.uncamelize = uncamelize;
    
        /**
         * 用过ID修改单个元素的样式
         * @param {Node} element 元素节点
         * @param {Object} styles 样式对象
         */
        function setStyleById(element, styles) {
            //取得对象的引用
            if (!(element = $(element))) {
                return false;
            }
            //循环遍历styles对象并应用每个属性
            for (var property in styles) {
                //检测是否是样式属性
                if (!styles.hasOwnProperty(property)) {
                    continue;
                }
    
                try {
                    //DOM2样式规范方法
                    element.style.setProperty(uncamelize(property, '-'), styles[property], null);
                } catch (ex) {
                    //备用方法
                    element.style[camelize(property)] = styles[property];
                }
            }
            return true;
        }
    
        window.ADS.setStyle = setStyleById;
        window.ADS.setStyleById = setStyleById;
    
    
        /**
         * 通过类名修改多个元素的样式
         * @param {Node} parent
         * @param {String} tag
         * @param {String} className
         * @param {Object} styles
         */
        function setStylesByClassName(parent, tag, className, styles) {
            if (!(parent = $(parent))) {
                return false;
            }
            var elements = getElementsByClassName(className, parent, tag);
            for (var i = 0; i < elements.length; i++) {
                setStyleById(elements[i], styles);
            }
            return true;
        }
    
        window.ADS.setStylesByClassName = setStylesByClassName;
    
        /**
         * 涌过标签名修改多个元素的样式
         * @param {String} tagname
         * @param {Object} styles
         * @param {Node} parent
         */
        function setStylesByTagName(tagname, styles, parent) {
            parent = $(parent) || document;
            var elements = parent.getElementsByTagName(tagname);
            for (var i = 0, len = elements.length; i < len; i++) {
                setStyleById(elements[i], styles);
            }
        }
    
        window.ADS.setStylesByTagName = setStylesByTagName;
    
        /**
         * 取得包含元素className的数组
         * @param {Node} element
         */
        function getClassName(element) {
            if (!(element = $(element))) {
                return false;
            }
            return element.className.replace(/\s+/g, ' ').split(' ');
        }
    
        window.ADS.getClassName = getClassName;
    
        /**
         * 检察院苏中是否存在某个className
         * @param {Node} element
         * @param {String} className
         * @return {Boolean}
         */
        function hasClassName(element, className) {
            if (!(element = $(element))) {
                return false;
            }
            var classes = getClassName(element);
            for (var i = 0; i < classes.length; i++) {
                //检测className是否匹配,如果是则返回true
                if (classes[i] === className) {
                    return true;
                }
            }
            return false;
        }
    
        window.ADS.hasClassName = hasClassName;
    
        /**
         * 为元素添加className
         * @param element
         * @param className
         * @return {Boolean}
         */
        function addClassName(element, className) {
            if (!(element = $(element))) {
                return false;
            }
            //将className添加到当前className的末尾
            //如果没有className,则不包含空格
            element.className += (element.className ? ' ' : '') + className;
            return true;
        }
    
        window.ADS.addClassName = addClassName;
    
        /**
         * 删除一个或多个类名
         * @param element
         * @param className
         * @return {Boolean}
         */
        function removeClassName(element, className) {
            if (!(element = $(element))) {
                return false;
            }
            className = (className || '').trim().replace(/\s+/g, ' ');
            if (className === '') {
                //未定义或者空的情况为删除所有类名
                element.className = '';
            } else if (className.indexOf(' ') !== -1) {
                //对多个以空格为分隔的类名进行处理,然后迭代
                var classarr = className.split(' ');
                for (var i = 0; i < classarr.length; i++) {
                    removeClassName(element, classarr[i]);
                }
            } else {
                //对单个类名的处理
                className = (' ' + className + ' ');
                var elemClass = ' ' + element.className + ' ';
                if (elemClass.indexOf(className) !== -1) {
                    element.className = elemClass.replace(className, ' ').replace(/\s+/g, ' ').trim();
                } else {
                    return false;
                }
            }
            return true;
        }
    
        window.ADS.removeClassName = removeClassName;
    
        /**
         * 切换类名
         * @param element
         * @param className
         */
        function toggleClassName(element, className) {
            if (!hasClassName(element, className)) {
                addClassName(element, className);
            } else {
                removeClassName(element, className);
            }
        }
    
        window.ADS.toggleClassName = toggleClassName;
    
        /**
         * 添加样式表
         * @param {String} url url地址
         * @param {String} media 媒介类型
         */
        function addStyleSheet(url, media) {
            media = media || 'screen';
            var link = document.createElement('link');
            link.setAttribute('rel', 'stylesheet');
            link.setAttribute('type', 'stylesheet');
            link.setAttribute('href', url);
            link.setAttribute('media', media);
            link.disabled = false;
            document.getElementsByTagName('head')[0].appendChild(link);
        }
    
        window.ADS.addStyleSheet = addStyleSheet;
    
        /**
         * 禁用样式表
         * @param url
         * @param media
         */
        function removeStyleSheet(url, media) {
            var styles = getStyleSheets(url, media);
            for (var i = 0; i < styles.length; i++) {
                // for standard and IE
                var node = styles[i].ownerNode || styles[i].owningElement;
                //禁用样式表
                styles[i].disabled = true;
                //移除节点
                node.parentNode.removeChild(node);
            }
        }
    
        window.ADS.removeStyleSheet = removeStyleSheet;
    
        /**
         * 通过URL取得包含所有样式表的数组
         * @param url
         * @param media
         * @return {Array}
         */
        function getStyleSheets(url, media) {
            var sheets = [];
            for (var i = 0; i < document.styleSheets.length; i++) {
                if (url && document.styleSheets[i].href.indexOf(url) === -1) {
                    continue;
                }
                if (media) {
                    //规范化media字符串
                    media = media.replace(/,\s*/, ',');
                    var sheetMedia;
    
                    if (document.styleSheets[i].media.mediaText) {
                        //DOM方法
                        sheetMedia = document.styleSheets[i].media.mediaText.replace(/,\s*/, ',');
                        //Safari会添加额外的都好和空格
                        sheetMedia = sheetMedia.replace(/,\s*$/, '');
                    } else {
                        // MSIE
                        sheetMedia = document.styleSheets[i].media.replace(/,\s*/, ',');
                    }
    
                    //如果media不匹配则跳过
                    if (media !== sheetMedia) {
                        continue;
                    }
                }
                sheets.push(document.styleSheets[i]);
            }
            return sheets;
        }
    
        window.ADS.getStyleSheets = getStyleSheets;
    
        /**
         * 编辑一条样式规则
         * @param {String} selector 选择器
         * @param {Object} styles 样式对象
         * @param {String || Array} url url地址或者styleSheets数组
         * @param {String} media 媒介查询
         */
        function editCSSRule(selector, styles, url, media) {
    
            var styleSheets = (typeof url === 'array') ? url : getStyleSheets(url, media);
    
            for (var i = 0; i < styleSheets.length; i++) {
                // 取得规则列表
                // DOM2样式规范方法是styleSheets[i].cssRules
                // MSIE方法是styleSheets[i].rules
                var rules = styleSheets[i].cssRules || styleSheets[i].rules;
                if (!rules) {
                    continue;
                }
    
                // 由于MSIE默认使用大写故转换为大写形式
                // 如果拟使用的是区分大小写的id,则可能会
                // 导致冲突
                selector = selector.toUpperCase();
    
                for (var j = 0; j < rules.length; j++) {
                    // 检查是否匹配
                    if (rules[i].selectorText.toUpperCase() === selector) {
                        for (var property in styles) {
                            if (!styles.hasOwnProperty(property)) {
                                continue;
                            }
                            // 设置新的样式属性
                            rules[i].style[camelize(property)] = styles[property];
                        }
                    }
                }
            }
        }
    
        window.ADS.editCSSRule = editCSSRule;
    
        /**
         * 添加一条css规则
         * @param selector
         * @param styles
         * @param {Number} index 列表规则的序号
         * @param url
         * @param media
         */
        function addCSSRule(selector, styles, index, url, media) {
            var declaration = '';
    
            // 根据styles参数(样式对象)构建声明字符串
            for (var property in styles) {
                if (!styles.hasOwnProperty(property)) {
                    continue;
                }
                declaration += property + ':' + styles[property] + ';';
            }
    
            var styleSheets = (typeof url === 'array') ? url : getStyleSheets(url, media);
            var newIndex;
            for (var i = 0; i < styleSheets.length; i++) {
                // 添加规则
                if (styleSheets[i].insertRule) {
                    // DOM2样式规范方法
                    // index = length 是列表末尾
                    newIndex = (index >= 0 ? index : styleSheets[i].cssRules.length);
                    styleSheets[i].insertRule(
                        selector + ' { ' + declaration + ' } ',
                        newIndex
                    );
                } else if (styleSheets[i].addRule) {
                    // MSIE的方法
                    // index = -1 是列表末尾
                    newIndex = (index >= 0 ? index : -1);
                    styleSheets[i].addRule(selector, declaration, newIndex);
                }
            }
        }
    
        window.ADS.addCSSRule = addCSSRule;
    
        /**
         * 取得一个元素的计算样式
         * @param {Node} element 元素节点
         * @param {String} property css属性
         *      格式:font-size
         * @return {*}
         */
        function getStyle(element, property) {
            if (!(element = $(element)) || !property) {
                return false;
            }
            // 检测元素style属性中的值
            // 只能获取嵌入方式定义的样式
            var value = element.style[camelize(property)];
            if (!value) {
                // 取得计算的样式值
                if (document.defaultView && document.defaultView.getComputedStyle) {
                    // DOM方法
                    var css = document.defaultView.getComputedStyle(element, null);
                    // 也可以使用css[camelize(property)]
                    value = css ? css.getPropertyValue(property) : null;
                } else if (element.currentStyle) {
                    // MSIE方法
                    value = element.currentStyle[camelize(property)];
                }
            }
            // 返回字符串不包括auto的值
            return value === 'auto' ? '' : value;
        }
    
        window.ADS.getStyle = getStyle;
        window.ADS.getStyleById = getStyle;
    
        /**
         * 检查JSON文本,确保安全
         * @param {String} s JSON字符串
         * @param {Function} filter 过滤方法
         * @return {*}
         */
        function parseJSON(s, filter) {
            var j;
    
            /**
             * 递归地遍历了新生成的结构
             而且将每个名/值对传递给一个过滤函数,以便进行
             可能的转换
             * @param k
             * @param v
             * @return {*}
             */
            function walk(k, v) {
                if (v && typeof v === 'object') {
                    for (var i in v) {
                        if (v.hasOwnProperty(i)) {
                            v[i] = walk(i, v[i]);
                        }
                    }
                }
                return filter(k, v);
            }
    
            /*
             解析通过3个阶段进行。第一阶段,通过正则表达式
             检测JSON文本,查找非JSON字符串。其中,特别关注
             “()”和"new",因为它们会引起语句的调用,还有“=”,
             因为它会导致变量的值发生改变。不过,为安全起见
             这里会拒绝所有不希望出现的字符串
             */
            /*
             首先这个串分成两部分,看中间的或符号(|)
             "(\\.|[^\\\n\r])*?"和[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]
             先分解"(\\.|[^\\\n\r])*?"
             它匹配一个双引号的字符串,两边引号不说了括号内一个“|”又分成两段 “\\.“匹配一个转义字符
             比如js字符串里的\n,\r,\',\"等。[^\\\n\r]匹配一个非\,回车换行的字符 其实它就是js里字符串的规则---不包含回车换行,回车换行用 \n\r表示,\后面跟一个字符表示转义
             其次看[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]
             它匹配一个单个字符,这个字符可以是 ,,:,{,},[,],数字,除 "\n" 之外的任何单个字符,-,+,E,a,e,f,l,n,r-u之间的字符,回车,换行,制表符,
             */
            if (/^("(\\.|[^"\\\n\r])*?"|[,:\{\}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(s)) {
                /*
                 第二阶段,使用eval()函数将JSON文本编译为js
                 结构。其中的“{”操作符具有语法上的二义性,即它可
                 以定义一个语句块,也可以表示对象字面量。这里将
                 JSON文本用括号括起来是为了消除这种二义性
                 */
                try {
                    j = eval('(' + s + ')');
                } catch (e) {
                    throw new SyntaxError('parseJSON');
                }
            } else {
                throw new SyntaxError('parseJSON');
            }
    
            /*
             在可选的第三阶段,代码递归地遍历了新生成的结构
             而且将每个名/值对传递给一个过滤函数,以便进行
             可能的转换
             */
            if (typeof filter === 'function') {
                j = walk('', j);
            }
            return j;
        }
    
        /**
         * 设置XMLHttpRequest对象的各个不同的部分
         * @param url
         * @param options
         *      参数options的成员属性
         *      method, 适用于请求的方法,默认为GET。
         *      send, 是一个包含在XMLHttpRequest.send()中的可选字符串,默认为null。
         *      loadListener, 是当readyState为1时调用的onreadystatechange侦听器
         *      loadedListener, 是当readyState为2时调用的onreadystatechange侦听器。
         *      interactiveListener, 是当readyState为3时调用的onreadystatechange侦听器。
         *      jsResponseListener, 是当请求成功并且响应的Content-Type为application/javascript或text/javascript时调用的侦听器,这个侦听器将从响应中取得js字符串作为其第一个参数。如果要执行该js字符串,必须使用eval()方法。
         *      jsonResponseListener, 是当请求成功并且响应的Content-Type为application/json时调用的侦听器。这个侦听器将从响应中取得JSON对象作为其第一个参数。
         *      xmlResponseListener, 是当请求成功并且响应的Content-Type为application/xml或application/xhtml+xml时调用的侦听器。这个侦听器将从响应中取得的XML DOM文档作为其第一个参数。
         *      htmlResponseListener, 是当请求成功并且响应的content-Type为text/html时调用的侦听器。这个侦听器将从响应中取得的HTML字符串作为其第一个参数。
         *      completeListener, 是当上面所列的针对Content-Type的响应侦听器调用之后被调用的侦听器。这个方法总是在成功的响应最后被调用,也就是说如果相应中没有适当的Content-Type头部信息,那么你可以制定这个方法作为兜底儿的侦听器。
         *      errorListener, 是当响应状态值不是200也不是0时被调用的侦听器。如果是在不会提供适当响应代码的系统上运行(如硬盘驱动器中的本地文件系统)XMLHttpRequest,那么状态值将始终为0.在这种情况下,只有completeListener会被调用。
         */
        /*
         demo:
         ADS.ajaxRequest('/path/to/script/',{
         method:'GET',
         completeListener:function(){
         alert(this.responseText);
         }
         });
         */
        // 因为使用了call和apply方法,此时的this引用的是
        // 请求对象而不是onreadystatechange方法。
        function getRequestObject(url, options) {
            // 初始化请求对象
            var req = false;
            if (window.XMLHttpRequest) {
                req = getRequestObject.req = new window.XMLHttpRequest();
            } else if (window.ActiveXObject) {
                req = getRequestObject.req = new ActiveXObject('Microsoft.XMLHTTP');
            }
    
            if (!req) {
                return false;
            }
    
            // 定义默认的选项
            options = options || {};
            options.method = options.method || 'GET';
            options.send = options.send || null;
    
            // 为请求的每个阶段定义不同的侦听器
            req.onreadystatechange = function () {
                switch (req.readyState) {
                    case 1:
                        // 载入中
                        if (options.loadListener) {
                            options.loadListener.apply(req, arguments);
                        }
                        break;
                    case 2:
                        // 载入完成
                        if (options.loadedListener) {
                            options.loadedListener.apply(req, arguments);
                        }
                        break;
                    case 3:
                        // 交互
                        if (options.interactiveListener) {
                            options.interactiveListener.apply(req, arguments);
                        }
                        break;
                    case 4:
                        // 完成
                        // 如果失败则抛出错误
                        try {
                            if (req.status && (req.status >= 200 && req.status < 300) || req.status === 304) {
                                // 针对Content-type的特殊侦听器
                                // 由于Content-Type头部中可能包含字符集,如:
                                // Content-Type: text/html; charset=ISO-8859-4
                                // 因此通过正则表达式提取出所需的部分
                                var contentType = req.getResponseHeader('Content-Type');
                                var mimeType = contentType.match(/\s*([^;]+)\s*(;|$)/i)[1];
                                switch (mimeType) {
                                    case 'text/javascript':
                                    case 'application/javascript':
                                        // 响应时javascript,因此以
                                        // req.responseText作为回调函数
                                        if (options.jsResponseListener) {
                                            options.jsResponseListener.call(req, req.responseText);
                                        }
                                        break;
                                    case 'application/json':
                                        // 响应是JSON,因此需要用匿名函数对
                                        // req.responseText进行解析
                                        // 已返回作为回调参数的JSON对象
                                        if (options.jsonResponseListener) {
                                            var json;
                                            try {
                                                json = parseJSON(req.responseText);
                                            } catch (e) {
                                                json = false;
                                            }
                                            options.jsonResponseListener.call(req, json);
                                        }
                                        break;
                                    case 'text/xml':
                                    case 'application/xml':
                                    case 'application/xhtml+xml':
                                        // 响应是XML,因此以
                                        // req.responseXML作为
                                        // 回调的参数
                                        // 此时是Document对象
                                        if (options.xmlResponseListener) {
                                            options.xmlResponseListener.call(req, req.responseText);
                                        }
                                        break;
                                    case 'text/html':
                                        // 响应是HTML,因此以
                                        // req.responseText作为
                                        // 回调的参数
                                        if (options.htmlResponseListener) {
                                            options.htmlResponseListener.call(req, req.responseText);
                                        }
                                        break;
                                    default:
                                        break;
                                }
    
                                // 针对响应成功完成的侦听器
                                if (options.completeListener) {
                                    options.completeListener.apply(req, arguments);
                                }
                            } else {
                                // 相应完成但却存在错误
                                if (options.errorListener) {
                                    options.errorListener.apply(req, arguments);
                                }
                            }
                        } catch (e) {
                            // 忽略错误
                        }
                        break;
                }
            };
    
            // 开启请求
            req.open(options.method, url, true);
            // 添加特殊的头部信息以标识请求
            req.setRequestHeader('X-ADS-Ajax-Request', 'AjaxRequest');
            return req;
        }
    
        window.ADS.getRequestObject = getRequestObject;
    
        // 通过简单的包装getRequestObject()和send()
        // 方法发送XMLHttpRequest对象的请求
        function ajaxRequest(url, options) {
            var req = getRequestObject(url, options);
            req.send(options.send);
            return req;
        }
    
        window.ADS.ajaxRequest = ajaxRequest;
    
    
        /**
         * 此处的XssHttpRequest对象在模拟了某些XMLHttpRequest对象属性的基础上,还添加了以下一些属性
         * responseJSON。 包含相应的结果,这个属性已经是一个js对象了,因此不需要再使用eval();
         * status. 在这里可能的值有如下两个
         *      1: 表示成功
         *      2: 表示存在错误
         * statusText。 包含错误的原因。
         * 可以通过在下列侦听器内使用this关键字来访问以上属性
         * loadedListener。 当对象处于载入完成状态时调用。
         * waitListener。 当对象等待响应时调用。
         * completeListener。 当对象取得成功的响应后调用。
         * errorListener。 当脚本载入外部脚本失败或载入的脚本格式不正确时调用。
         *
         * 为了保证对象正确运行,相应必须要调用GET变量中所引用的js函数,一般而言,最好的方式就是想这个函数中传递一个JSON对象,但如果你想传递XML文件或其他信息,也可以简单的将这些信息包含在JSON对象中,然后用过响应侦听器来按照需要解析这些信息。
         */
        // XssHttpRequest对象的计数器
        var XssHttpRequestCount = 0;
        // XssHttpRequest对象的一个
        // 跨站点<script>标签的实现
        var XssHttpRequest = function () {
            this.requestID = 'XSS_HTTP_REQUEST_' + (++XssHttpRequestCount);
        };
        XssHttpRequest.prototype = {
            url: null,
            scriptObject: null,
            responseJSON: null,
            status: 0,
            readyState: 0,
            timeout: 30000,
            onreadystatechange: function () {
            },
            setReadyState: function (newReadyState) {
                // 如果比当前状态更新
                // 则只更新就绪状态
                if (this.readyState < newReadyState || newReadyState === 0) {
                    this.readyState = newReadyState;
                    this.onreadystatechange();
                }
            },
            open: function (url, timeout) {
                this.timeout = timeout || this.timeout;
                // 将以革名为XSS_HTTP_REQUEST_CALLBACK
                // 的特殊变量附加给URL,其中包含本次请求的
                // 回调函数的名称
                this.url = url +
                    ((url.indexOf('?') !== -1) ? '&' : '?') +
                    'XSS_HTTP_REQUEST_CALLBACK=' +
                    this.requestID +
                    '_CALLBACK';
                this.setReadyState(0);
            },
            send: function () {
                var requestObject = this;
                // 创建一个载入外部数据的新script对象
                this.scriptObject = document.createElement('script');
                this.scriptObject.setAttribute('id', this.requestID);
                this.scriptObject.setAttribute('type', 'text/javascript');
                // 汕尾设置src属性,也先不降其添加到文档
    
                // 创建一个在给定的毫秒数之后触发的
                // setTimeout()方法。如果在给定的时间
                // 内脚本没有载入完成,则取消载入
                var timeoutWatcher = setTimeout(function () {
                    // 在脚本晚于我们假定的停止时间之后载入的情况下
                    // 通过一个空方法来重新为window方法赋值
                    window[requestObject.requestID + '_CALLBACK'] = function () {
                    };
    
                    // 移除脚本以防止进一步载入
                    requestObject.scriptObject.parentNode.removeChild(requestObject.scriptObject);
    
                    // 将状态设置为错误
                    requestObject.status = 2;
                    requestObject.statusText = 'Timeout after: ' +
                        requestObject.timeout +
                        ' milliseconds.';
    
                    // 更新就绪状态
                    requestObject.setReadyState(2);
                    requestObject.setReadyState(3);
                    requestObject.setReadyState(4);
                }, this.timeout);
    
                // 在window对象中创建一个与
                // 请求中的回调方法匹配的方法
                // 在调用时负责处理请求的其他部分
                window[this.requestID + '_CALLBACK'] = function (JSON) {
                    // 当脚本载入时将执行这个方法
                    // 同时传入预期的JSON对象
    
                    // 在请求载入成功时
                    // 清除timeoutWatcher方法
                    clearTimeout(timeoutWatcher);
    
                    // 更新就绪状态
                    requestObject.setReadyState(2);
                    requestObject.setReadyState(3);
    
                    // 将状态设置为成功
                    requestObject.responseJSON = JSON;
                    requestObject.status = 1;
                    requestObject.statusText = 'Loaded.';
    
                    // 更新就绪状态
                    requestObject.setReadyState(4);
                };
    
                // 设置初始就绪状态
                this.setReadyState(1);
    
                // 现在再设置src属性并将其添加
                // 到文档头部。这样会载入脚本
                this.scriptObject.setAttribute('src', this.url);
                var head = document.getElementsByTagName('head')[0];
                head.appendChild(this.scriptObject);
            }
        };
    
        window.ADS.XssHttpRequest = XssHttpRequest;
    
        // 设置XssHttpRequest对象的不同部分
        function getXssRequestObject(url, options) {
            var req = new XssHttpRequest();
    
            options = options || {};
            // 默认中断时间为30秒
            options.timeout = options.timeout || 30000;
            req.onreadystatechange = function () {
                switch (req.readyState) {
                    // 载入中
                    case 1:
                        if (options.loadListener) {
                            options.loadListener.apply(req, arguments);
                        }
                        break;
                    case 2:
                        // 载入完成
                        if (options.loadedListener) {
                            options.loadedListener.apply(req, arguments);
                        }
                        break;
                    case 3:
                        // 交互
                        if (options.interactiveListener) {
                            options.interactiveListener.apply(req, arguments);
                        }
                        break;
                    case 4:
                        // 完成
                        if (req.status === 1) {
                            if (options.completeListener) {
                                options.completeListener.apply(req, arguments);
                            }
                        } else {
                            if (options.errorListener) {
                                options.errorListener.apply(req, arguments);
                            }
                        }
                        break;
                    default:
                        break;
                }
            };
            req.open(url, options.timeout);
    
            return req;
    
        }
    
        window.ADS.getXssRequestObject = getXssRequestObject;
    
        // 发送XssHttpRequest请求
        function xssRequest(url, options) {
            var req = getXssRequestObject(url, options);
            req.send(null);
            return req;
        }
    
        window.ADS.xssRequest = xssRequest;
    
        //跟踪hash地址变化
    
        /* 声称回调函数的一个辅助方法 */
        function makeCallback(method, target) {
            return function () {
                method.apply(target, arguments);
            };
        }
    
        /* 一个用来基于hash触发注册的方法的URL hash侦听器 */
        var actionPager = {
            // 前一个hash
            lastHash: '',
            // 为hash模式注册的方法列表
            callbacks: [],
            // Safari历史记录列表
            safariHistory: false,
            // 对为IE准备的iframe的引用
            msieHistory: false,
            // 应该被转换的链接的类名
            ajaxifyClassName: '',
            // 应用程序的根目录。当创建hash时
            // 它将是被清理后的URL
            ajaxifyRoot: '',
    
            /**
             * 初始化页面(pager)功能
             * @param {String} ajaxifyClass 预定义的类名,只有符合该类名的链接才具备功能,默认为 ADSActionLink
             * @param {String} ajaxifyRoot 预定义的根路径
             * @param {String} startingHash 预定义的hash值,默认为start
             * @example actionPager.init();
             */
            init: function (ajaxifyClass, ajaxifyRoot, startingHash) {
    
                this.ajaxifyClassName = ajaxifyClass || 'ADSActionLink';
                this.ajaxifyRoot = ajaxifyRoot || '';
    
                var ua = navigator.userAgent;
                if (/Safari/i.test(ua) && /Version\/3/.test(ua)) {
                    this.safariHistory = [];
                } else if (/MSIE/i.test(ua) && (parseInt(ua.split('MSIE')[1],10) < 8)) {
                    // 如果是MSIE 6/7,添加一个iframe以便
                    // 跟踪重写(override)后退按钮
                    this.msieHistory = document.createElement('iframe');
                    this.msieHistory.setAttribute('id', 'msieHistory');
                    this.msieHistory.setAttribute('name', 'msieHistory');
                    this.msieHistory.setAttribute('src', 'fakepage');
                    setStyleById(this.msieHistory, {
                        'width': '100px',
                        'height': '100px',
                        'border': '1px solid black',
                        'display': 'none',
                        'z-index': -1
                    });
                    document.body.appendChild(this.msieHistory);
                    this.msieHistory = frames.msieHistory;
                }
    
                // 将链接转换为Ajax链接
                this.ajaxifyLinks();
    
                // 取得当前的地址
                var locat = this.getLocation();
    
                // 检测地址中是否包含hash(来自书签)
                // 或者是否已经提供了hash
                if (!locat.hash && !startingHash) {
                    startingHash = 'start';
                }
    
                // 按照需要保存hash
                var ajaxHash = this.getHashFromURL(window.location.href) || startingHash;
                this.addBackButtonHash(ajaxHash);
    
                // 添加监视事件以观察地址栏中的变化
                var watcherCallback = makeCallback(this.watchLocationForChange, this);
    
                if (/MSIE/i.test(ua) && (parseInt(ua.split('MSIE')[1],10) < 8)) {
                    window.setInterval(watcherCallback, 200);
                } else {
                    addEvent(window, 'hashchange', watcherCallback);
                }
    
            },
    
            /**
             * 会自动将任何带标识的锚标签转换为页面(pager)可以识别的链接
             */
            ajaxifyLinks: function () {
                // 将链接转换为锚以便Ajax进行处理
                var links = getElementsByClassName(this.ajaxifyClassName, 'a');
                for (var i = 0, len = links.length; i < len; i++) {
                    var curLink = links[i];
                    if (hasClassName(curLink, 'ADSActionPagerModified')) {
                        continue;
                    }
    
                    // 将href属性转换为#value形式
                    curLink.setAttribute('href', this.convertURLToHash(curLink.getAttribute('href')));
                    addClassName(curLink, 'ADSActionPagerModified');
    
                    // 注册单击事件以便在必要时添加历史纪录
                    addEvent(curLink, 'click', function () {
                        if (this.href && this.href.indexOf('#') > -1) {
                            actionPager.addBackButtonHash(actionPager.getHashFromURL(this.href));
                        }
                    });
                }
            },
    
            /**
             * 记录后退行为
             * @param {String} ajaxHash hash值
             * @return {Boolean}
             */
            addBackButtonHash: function (ajaxHash) {
                // 保存hash
                if (!ajaxHash) {
                    return false;
                }
                if (this.safariHistory) {
                    // 为Safari使用特殊数组
                    if (this.safariHistory.length === 0) {
                        this.safariHistory[window.history.length] = ajaxHash;
                    } else {
                        this.safariHistory[window.history.length + 1] = ajaxHash;
                    }
                    return true;
                } else if (this.msieHistory) {
                    // 在MSIE中通过导航iframe
                    this.msieHistory.document.execCommand('Stop');
                    this.msieHistory.location.href = '/fakepage?hash=' +
                        ajaxHash +
                        '&title=' +
                        document.title;
                    return true;
                } else {
                    // 通过改变地址的值
                    // 使用makeCallback包装函数
                    // 以便在超时方法内部使this
                    // 引用actionPager
                    var timeoutCallback = makeCallback(function () {
                        if (this.getHashFromURL(window.location.href) !== ajaxHash) {
                            location.replace(location.href + '#' + ajaxHash);
                        }
                    }, this);
                    setTimeout(timeoutCallback, 200);
                    return true;
                }
                return false;
            },
    
            /**
             * 间隔地检测hash的变化,还可执行注册的侦听器
             */
            watchLocationForChange: function () {
                var newHash;
                // 取得新的hash值
                if (this.safariHistory) {
                    // 在Safari中从历史记录数组中取得
                    if (this.safariHistory[history.length]) {
                        newHash = this.safariHistory[history.length];
                    }
                } else if (this.msieHistory) {
                    // 在MSIE中从iframe的地址中取得
                    newHash = this.msieHistory.location.href.split('&')[0].split('=')[1];
                } else if (location.hash !== '') {
                    // 对其他浏览器从window.location中取得
                    newHash = this.getHashFromURL(window.location.href);
                }
    
                // 如果新hash与最后一次的hash不相同,则更新页面
                if (newHash && this.lastHash !== newHash) {
                    if (this.msieHistory && this.getHashFromURL(window.location.href) !== newHash) {
                        // 修复MSIE中的地址栏
                        // 以便能适当地加上标签(或加入收藏夹)
                        location.hash = newHash;
                    }
    
                    // 在发生异常的情况下使用try/catch
                    // 结构尝试执行任何注册的侦听器
                    try {
                        if (this.callbacks.length) {
                            this.executeListeners(newHash);
                        }
                        // 在通过处理程序添加任何
                        // 新链接的情况下进行更新
                        this.ajaxifyLinks();
                    } catch (ex) {
                        // 这里将捕获到回调函数中的任何异常JS
                        alert(ex);
                    }
    
                    // 将其保存为最后一个hash
                    this.lastHash = newHash;
                }
            },
    
            /**
             * 用于根据特殊的hash来注册侦听器
             * @param {RegExp || String} regex 正则表达式
             * @param {Function} method 执行的方法
             * @param {Object || Element} context 执行环境,上下文
             */
            register: function (regex, method, context) {
                var obj = {'regex': regex};
                context = context || window;
                // 一个已经指定的环境
                obj.callback = function (matches) {
                    method.apply(context, matches);
                };
    
                // 将侦听器添加到回调函数数则中
                this.callbacks.push(obj);
            },
    
            /**
             * 把链接的URL地址转换为hash值
             * @param {String} url
             * @return {*}
             */
            convertURLToHash: function (url) {
                if (!url) {
                    // 没有url,因而返回一个'#'
                    return '#';
                } else if (url.indexOf('#') > -1) {
                    // 存在hash,因而返回它
                    return '#' + url.split('#')[1];
                } else {
                    // ie67会自动添加域名
                    // 如果URL中包含域名(MSIE)则去掉它
                    if (url.indexOf('://') > -1) {
                        url = url.match(/:\/\/[^\/]+(.*)/)[1];
                    }
                    // 按照init()约定去掉根目录
                    return '#' + url.substring(this.ajaxifyRoot.length);
                }
            },
    
            /**
             * 从指定的URL中提取出hash值
             * @param url
             * @return {*}
             */
            getHashFromURL: function (url) {
                if (!url || url.indexOf('#') === -1) {
                    return '';
                }
                return url.split('#')[1];
            },
    
            /**
             * 获取当前URL地址
             * @return {*}
             */
            getLocation: function () {
                // 检查hash
                if (!window.location.hash) {
                    // 没有则生成一个
                    var url = {
                        domain: null,
                        hash: null
                    };
                    if (window.location.href.indexOf('#') > -1) {
                        var parts = window.location.href.split('#')[1];
                        url.domain = parts[0];
                        url.hash = parts[1];
                    } else {
                        url.domain = window.location;
                    }
                    return url;
                }
                return window.location;
            },
    
            /**
             * 执行侦听器
             * @param hash
             */
            executeListeners: function (hash) {
                var matches;
                // 执行与hash匹配的任何侦听器
                for (var i = 0, len = this.callbacks.length; i < len; i++) {
                    if ((matches = hash.match(this.callbacks[i].regex))) {
                        this.callbacks[i].callback(matches);
                    }
                }
    
            }
        };
    
        window.ADS.actionPager = actionPager;
    
        /* 一个复制对象的辅助方法 */
        function clone(myObj) {
            if (typeof myObj !== 'object') {
                return myObj;
            }
            if (myObj === null) {
                return myObj;
            }
            var myNewObj = {};
            for (var i in myObj) {
                myNewObj[i] = clone(myObj[i]);
            }
            return myNewObj;
        }
    
        /* 用于保存队列的数组 */
        var requestQueue = [];
    
        /**
         * 为ADS.ajaxRequest方法启用排队功能的包装对象
         * @param url
         * @param options
         * @param queue
         * @example
         *      ADS.ajaxRequestQueue('/your/script/', {
         *          completeListener: function(){
         *              alert(this.responseText);
         *          }
         *      }, 'Queue1');
         */
        function ajaxRequestQueue(url, options, queue) {
            queue = queue || 'default';
    
            // 这个对象将把可选的侦听器包装在另一个函数中
            // 因此,可选的对象必须唯一。否则,如果该方法
            // 被调用时使用的是共享的可选对象,那么会导致
            // 陷入递归中
            options = clone(options) || {};
            if (!requestQueue[queue]) {
                requestQueue[queue] = [];
            }
    
            // 当前一次请求完成时,需要使用completeListener
            // 调用队列中的下一次请求。如果完成侦听器已经
            // 有定义,那么需要首先调用它
    
            // 取得旧侦听器
            var userCompleteListener = options.completeListener;
    
            // 添加新侦听器
            options.completeListener = function () {
                // 如果存在旧的侦听器则首先调用它
                if (userCompleteListener) {
                    // this引用的是情求对象
                    userCompleteListener.apply(this, arguments);
                }
    
                // 从队列中移除这个请求
                requestQueue[queue].shift();
    
                // 调用队列中的下一项
                if (requestQueue[queue][0]) {
                    // 请求保存在req属性中,但为防止它是
                    // 一个POST请求,故也需包含send选项
                    var q = requestQueue[queue][0].req.send(
                        requestQueue[queue][0].send
                    );
                }
            };
    
            // 如果发生了错误,应该通过调用相应的
            // 错误处理方法取消队列中的其他请求
    
            // 取得旧侦听器
            var userErrorListener = options.errorListener;
    
            // 添加新侦听器
            options.errorListener = function () {
                if (userErrorListener) {
                    userErrorListener.apply(this, arguments);
                }
    
                // 由于已经调用了错误侦听器
                // 股从队列中移除这个请求
                requestQueue[queue].shift();
    
                // 由于出错需要取消队列中的其余请求,但首先要调用
                // 每个请求的errorListener。通过调用队列中
                // 下一项的错误侦听器就会才清楚所有排队的请求,因为在
                // 链中的调研那个是一次发生的
    
                // 检测队列中是否还存在请求
                if (requestQueue[queue].length) {
                    // 取得下一项
                    var q = requestQueue[queue].shift();
    
                    // 中断请求
                    q.req.abort();
    
                    // 伪造请求对象,以便errorListener
                    // 认为请求已经完成并相应地运行
    
                    var fakeRequest = {};
    
                    // 将status设置为0,将readyState设置为4
                    // 就好像请求虽然完成但却失败了一样
                    fakeRequest.status = 0;
                    fakeRequest.readyState = 4;
    
                    fakeRequest.responseText = null;
                    fakeRequest.responseXML = null;
    
                    // 设置错误信息,以便需要时显示
                    fakeRequest.statusText = 'A request in the queue received an error';
    
                    // 调用状态改变,如果readyState是4,而
                    // status不是200,则会调用errorListener
                    q.error.apply(fakeRequest);
                }
            };
    
            // 将这个请求添加到队列中
            requestQueue[queue].push({
                req: getRequestObject(url, options),
                send: options.send,
                error: options.errorListener
            });
    
            // 如果队列的长度表明只有一个
            // 项(即第一个)则调用请求
            if (requestQueue[queue].length === 1) {
                ajaxRequest(url, options);
            }
        }
    
        window.ADS.ajaxRequestQueue = ajaxRequestQueue;
    
        //客户端检测
        var client = (function(){
            //呈现引擎
            var engine = {
                ie: 0,
                gecko: 0,
                webkit: 0,
                khtml: 0,
                opera: 0,
                ver: null           //具体版本号
            };
    
            //浏览器
            var browser = {
                //主要浏览器
                ie: 0,
                firefox: 0,
                kong: 0,
                opera: 0,
                chrome: 0,
                safari: 0,
                ver: null      //具体的版本
            };
    
            //平台,设备和操作系统
            var system = {
                win: false,
                mac: false,
                x11: false,
    
                //移动设备
                iphone: false,
                ipod: false,
                nokiaN: false,
                winMobile: false,
                macMobile: false,
    
                //游戏系统
                wii: false,
                ps: false
            };
    
            //在此检测呈现引擎,平台和设备
            var ua = navigator.userAgent;
    
            if (window.opera) {
    
                //第一步检测opera,因为它的用户代理字符串有可能完全模仿其他浏览器
                //要识别Opera,必须的检测window.opera对象
                engine.ver = browser.ver = window.opera.version();
                engine.opera = browser.opera = parseFloat(engine.ver);
            } else if (/AppleWebkit\/(\S+)/.test(ua)) {
    
                //第二个要检测的是Webkit,因为Webkit的永华代理字符串中包含“Gecko”和“KHTML”
                //Webkit的用户代理字符串中的“AppleWebkit”是独一无二的
                engine.ver = RegExp.$1;
                engine.webkit = parseFloat(engine.ver);
    
                //确定是Chrome还是Safari
                if (/Chrome\/(\S+)/.test(ua)) {
                    browser.ver = RegExp.$1;
                    browser.chrome = parseFloat(browser.ver);
                } else if (/Version\/(\S+)/.test(ua)) {
                    browser.ver = RegExp.$1;
                    browser.safari = parseFloat(browser.ver);
                } else {
                    //近似地确定版本号
                    var safariVersion = 1;
                    if (engine.webkit < 100) {
                        safariVersion = 1;
                    } else if (engine.webkit < 312) {
                        safariVersion = 1.2;
                    } else if (engine.webkit < 412) {
                        safariVersion = 1.3;
                    } else {
                        safariVersion = 2;
                    }
                    browser.safari = browser.ver = safariVersion;
                }
    
            } else if (/KHTML\/(\S+)/.test(ua) || /Konqueror\/([^;]+)/.test(ua)) {
    
                //接下来测试KHTML,KHTML的用户代理字符串也包含“Gecko”
                //使用Konqueror检测Konqueror3.1及更早版本
                engine.ver = browser.ver = RegExp.$1;
                engine.khtml = browser.kong = parseFloat(engine.ver);
    
            } else if (/rv:([^\)]+)\) Gecko\/\d{8}/.test(ua)) {
    
                //检测Gecko,Gecko版本号会出现在字符串"rv:"的后面
                engine.ver = RegExp.$1;
                engine.gecko = parseFloat(engine.ver);
    
                //确定是不是Firefox
                if (/Firefox\/(\S+)/.test(ua)) {
                    browser.ver = RegExp.$1;
                    browser.firefox = parseFloat(browser.ver);
                }
    
            } else if (/MSIE ([^;]+)/.test(ua)) {
    
                //检测IE,IE版本号位于字符串“MSIE”之后,一个分号的前面
                engine.ver = browser.ver = RegExp.$1;
                engine.ie = browser.ie = parseFloat(engine.ver);
    
            }
    
            //检测浏览器
            browser.ie = engine.ie;
            browser.opera = engine.opera;
    
            //识别平台
            var p = navigator.platform;
            system.win = p.indexOf("Win") > -1;
            system.mac = p.indexOf("Mac") > -1;
            system.x11 = (p.indexOf("x11") > -1) || (p.indexOf("Linux") > -1);
    
            //识别windows操作系统
            if (system.win) {
                if (/Win(?:dows )?([^do]{2})\s?(\d+\.\d+)?/.test(ua)) {
                    if (RegExp.$1 === "NT") {
                        switch (RegExp.$2) {
                            case "5.0":
                                system.win = "2000";
                                break;
                            case "5.1":
                                system.win = "XP";
                                break;
                            case "6.0":
                                system.win = "Vista";
                                break;
                            case "6.1":
                                system.win = "WIN7";
                                break;
                            default:
                                system.win = "NT";
                                break;
                        }
                    } else if (RegExp.$1 === "9x") {
                        system.win = "ME";
                    } else {
                        system.win = RegExp.$1;
                    }
                }
            }
    
    
            system.iphone = ua.indexOf('iPhone') > -1;
            system.ipod = ua.indexOf('iPod') > -1;
            system.ipad = ua.indexOf('iPad') > -1;
            system.nokiaN = ua.indexOf('NokiaN') > -1;
    
            // windows mobile
            if (system.win === 'CE') {
                system.winMobile = system.win;
            } else if (system.win === 'Ph') {
                if (/Windows Phone OS (\d+\.\d+)/.test(ua)) {
                    system.win = 'Phone';
                    system.winMobile = parseFloat(RegExp.$1);
                }
            }
    
            // 检测IOS版本
            if (system.mac && ua.indexOf('Mobile') > -1) {
                if (/CPU (?:iPhone )?OS (\d+_\d+)/.test(ua)) {
                    system.ios = parseFloat(RegExp.$1.replace('_', '.'));
                } else {
                    // 不能真正检测出来,所以只能猜测
                    system.ios = 2;
                }
            }
    
            // 检测android版本
            if (/Android (\d+\.\d+)/.test(ua)) {
                system.android = parseFloat(RegExp.$1);
            }
    
            // 游戏系统
            system.wil = ua.indexOf('Wii') > -1;
            system.ps = /playstation/i.test(ua);
    
            // 返回这些对象
            return {
                engine: engine,
                browser: browser,
                system: system
            };
        })();
    
        window.ADS.client = client;
    
        //对非DOM元素实现自定义事件
        function EventTarget() {
            //存储事件处理程序的属性对象
            this.handlers = {};
        }
    
        EventTarget.prototype = {
            //重新将constructor指向EventTarget构造函数
            constructor: EventTarget,
            /**
             * 注册给定类型的事件处理程序
             * @param type 自定义的事件类型
             * @param handler 处理该事件类型的函数
             */
            addHandler: function (type, handler) {
                //如果handlers属性中没有存在一个针对该事件类型的数组
                //则创建一个新的。(一个事件类型可以对应多个事件处理函数,因此要用数组保存)
                //然后使用push()将该处理程序添加到数组的末尾
                if (typeof this.handlers[type] === "undefined") {
                    this.handlers[type] = [];
                }
                this.handlers[type].push(handler);
            },
            /**
             * 触发事件
             * @param event 一个至少包含type属性的对象
             */
            fire: function (event) {
                //给event对象设置一个target属性
                if (!event.target) {
                    event.target = this;
                }
                //如果该事件类型的执行函数存在,
                //调用各个函数,并给出event对象
                if (this.handlers[event.type] instanceof Array) {
                    var handlers = this.handlers[event.type];
                    for (var i = 0, len = handlers.length; i < len; i++) {
                        handlers[i](event);
                    }
                }
            },
            /**
             * 注销事件类型的事件处理程序
             * @param type 事件类型
             * @param handler 执行的函数
             */
            removeHandler: function (type, handler) {
                if (this.handlers[type] instanceof Array) {
                    var handlers = this.handlers[type];
                    //搜索事件处理程序的数组找到要删除的处理程序的位置
                    //找到了就退出循环,然后将该项目丛数组中删除
                    for (var i = 0, len = handlers.length; i < len; i++) {
                        if (handlers[i] === handler) {
                            break;
                        }
                    }
                    handlers.splice(i, 1);
                }
            }
        };
    
        window.ADS.EventTarget = EventTarget;
    
        /**
         * 封装cookie的操作
         * @type {Object}
         */
        var CookieUtil = {
            /**
             * 根据cookie的名字获取相应的值
             * @param name cookie名字
             * @return {*}
             */
            get: function (name) {
                //对name进行URL编码
                var cookieName = encodeURIComponent(name) + '=',
                    cookieStart = document.cookie.indexOf(cookieName),
                    cookieValue = null;
                //找到cookieName
                if (cookieStart > -1) {
                    //以cookieStart为起点找到最近的";"
                    var cookieEnd = document.cookie.indexOf(';', cookieStart);
                    //没找到";",则是document.cookie的最后一个值
                    if (cookieEnd === -1) {
                        cookieEnd = document.cookie.length;
                    }
                    //提取相应value字段
                    cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.length, cookieEnd));
                }
                //返回
                return cookieValue;
            },
            /**
             * 设置一个cookie
             * @param name cookie名字
             * @param value 相应的值
             * @param expire 生存周期 Date
             * @param path 路径
             * @param domain 域名
             * @param secure Boolean
             */
            set: function (name, value, expire, path, domain, secure) {
                //必须先进行URL编码
                var cookieText = encodeURIComponent(name) + '=' + encodeURIComponent(value);
                if (expire instanceof Date) {
                    //toGMTString()方法正确格式化Date对象
                    cookieText += '; expire=' + expire.toGMTString();
                }
                if (path) {
                    cookieText += '; path=' + path;
                }
                if (domain) {
                    cookieText += '; domain=' + domain;
                }
                if (secure) {
                    cookieText += '; secure';
                }
                document.cookie = cookieText;
            },
            /**
             * 删除cookie
             * @param name
             * @param path
             * @param domain
             * @param secure
             */
            unset: function (name, path, domain, secure) {
                this.set(name, '', new Date(0), path, domain, secure);
            }
        };
    
        window.ADS.CookieUtil = CookieUtil;
    
    //子cookie的操作
    //为了绕开浏览器的单域名下的cookie数限制
    //子cookie是存放在单个cookie中的更小段的数据
        var SubCookieUtil = {
            /**
             * 获取单个子cookie的值
             * @param name cookie名称
             * @param subName 子cookie名称
             * @return {*}
             */
            get: function (name, subName) {
                var subCookies = this.getAll(name);
                if (subCookies) {
                    return subCookies(subName);
                } else {
                    return null;
                }
            },
            /**
             * 获取所有子cookie并将它们放入一个对象中返回
             * @param name cookie名称
             * @return {*} 返回对象或null
             */
            getAll: function (name) {
                var cookieName = encodeURIComponent(name) + "=",
                    cookieStart = document.cookie.indexOf(cookieName),
                    cookieValue = null,
                    result = {};
                if (cookieStart > -1) {
                    var cookieEnd = document.cookie.indexOf(";", cookieName);
                    if (cookieEnd === -1) {
                        cookieEnd = document.cookie.length;
                    }
                    //没有进行解码,因为要对子cookie分离操作
                    cookieValue = document.cookie.substring(cookieStart + cookieName.length, cookieEnd);
                    //
                    if (cookieValue.length > 0) {
                        //分离出子cookie的对象
                        var subCookies = cookieValue.split("&");
                        //遍历分隔出子cookie的名称和值,解码后返回对象
                        for (var i = 0, len = subCookies.length; i < len; i++) {
                            var parts = subCookies[i].split("=");
                            result[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
                        }
                        return result;
                    }
                }
                //没找到,返回空
                return null;
            },
            /**
             * 存储单个子cookie
             * @param name cookie名称
             * @param subName 子cookie名称
             * @param value 子cookie值
             * @param expires 失效日期
             * @param path 路径
             * @param domain 域名
             * @param secure Boolean安全作用域
             */
            set: function (name, subName, value, expires, path, domain, secure) {
                //获取name名称的所有子cookie,没有则创建空对象
                var subcookies = this.getAll(name) || {};
                //给对象添加属性和值
                subcookies[subName] = value;
                //调用setAll()方法
                this.setAll(name, subcookies, expires, path, domain, secure);
            },
            /**
             * 存储所有子cookie
             * @param name cookie名称
             * @param subcookies 子cookie名称
             * @param expires 失效日期
             * @param path 路径
             * @param domain 域名
             * @param secure Boolean安全作用域
             */
            setAll: function (name, subcookies, expires, path, domain, secure) {
                var cookieText = encodeURIComponent(name) + "=";
                //创建数组,用于保存子cookie
                var subcookieParts = [];
                //遍历对象属性
                for (var subName in subcookies) {
                    //如果存在,则把编码后的名称和值保存到数组
                    if (subName.length > 0 && subcookies.hasOwnProperty(subName)) {
                        subcookieParts.push(encodeURIComponent(subName) + "=" + encodeURIComponent(subcookies[subName]));
                    }
                }
                //存在子cookie
                if (subcookieParts.length > 0) {
                    //连接子cookie
                    cookieText += subcookieParts.join("& ");
                    if (expires instanceof Date) {
                        cookieText += ";expires=" + expires.toGMTString();
                    }
                    if (path) {
                        cookieText += ";path=" + path;
                    }
                    if (domain) {
                        cookieText += ";domain=" + domain;
                    }
                    if (secure) {
                        cookieText += ";secure";
                    }
                } else {
                    //相当于删除cookie操作
                    cookieText += ";expires=" + (new Date(0)).toGMTString();
                }
                document.cookie = cookieText;
            },
            /**
             * 删除单个子cookie的名称和值
             * @param name
             * @param subName
             * @param path
             * @param domain
             * @param secure
             */
            unset: function (name, subName, path, domain, secure) {
                var subcookies = this.getAll(name);
                if (subcookies) {
                    //删除对应的属性和值
                    delete subcookies[subName];
                    //重新设置cookie
                    this.setAll(name, subcookies, null, path, domain, secure);
                }
            },
            /**
             * 删除所有子cookie
             * @param name
             * @param path
             * @param domain
             * @param secure
             */
            unsetAll: function (name, path, domain, secure) {
                this.setAll(name, null, new Date(0), path, domain, secure);
            }
        };
    
        window.ADS.SubCookieUtil = SubCookieUtil;
    })();
    
    //重复一个字符串
    if (!String.repeat) {
        String.prototype.repeat = function (times) {
            return new Array(times + 1).join(this);
        };
    }
    
    //清除结尾和开头处的空白符
    if (!String.trim) {
        String.prototype.trim = function () {
            return this.replace(/^\s+|\s+$/g, '');
        };
    }
    
    // 扩展链式调用方法
    Function.prototype.method = function (name, fn) {
        this.prototype[name] = fn;
        return this;
    };
    
    // 扩展数组方法
    if (!Array.prototype.forEach) {
        Array.method('forEach', function (fn, thisObj) {
            var scope = thisObj || window;
            for (var i = 0, len = this.length; i < len; i++) {
                fn.call(scope, this[i], i, this);
            }
        });
    }
    
    if (!Array.prototype.filter) {
        Array.method('filter', function (fn, thisObj) {
            var scope = thisObj || window;
            var a = [];
            for (var i = 0, len = this.length; i < len; i++) {
                if (!fn.call(scope, this[i], i, this)) {
                    continue;
                }
                a.push(this[i]);
            }
            return a;
        });
    }
    
    /* Object-oriented Helper functions. */
    function clone(object) {
        function F() {
        }
    
        F.prototype = object;
        return new F();
    }
    
    function extend(subClass, superClass) {
        var F = function () {
        };
        F.prototype = superClass.prototype;
        subClass.prototype = new F();
        subClass.prototype.constructor = subClass;
    
        subClass.superclass = superClass.prototype;
        if (superClass.prototype.constructor === Object.prototype.constructor) {
            superClass.prototype.constructor = superClass;
        }
    }
    
    function augment(receivingClass, givingClass) {
        if (arguments[2]) { // Only give certain methods.
            for (var i = 2, len = arguments.length; i < len; i++) {
                receivingClass.prototype[arguments[i]] = givingClass.prototype[arguments[i]];
            }
        }
        else { // Give all methods.
            for (var methodName in givingClass.prototype) {
                if (!receivingClass.prototype[methodName]) {
                    receivingClass.prototype[methodName] = givingClass.prototype[methodName];
                }
            }
        }
    }
  • 相关阅读:
    14_java之变量|参数|返回值|修饰符
    NYOJ 202 红黑树 (二叉树)
    NYOJ 138 找球号(二) (哈希)
    NYOJ 136 等式 (哈希)
    NYOJ 133 子序列 (离散化)
    NYOJ 129 树的判定 (并查集)
    NYOJ 117 求逆序数 (树状数组)
    NYOJ 93 汉诺塔 (数学)
    HDU 2050 折线分割平面 (数学)
    天梯赛L2-008 最长对称子串 (字符串处理)
  • 原文地址:https://www.cnblogs.com/webFrontDev/p/2820399.html
Copyright © 2011-2022 走看看