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];
                }
            }
        }
    }
  • 相关阅读:
    bzoj 2002 [Hnoi2010]Bounce 弹飞绵羊
    【无图慎入】Link Cut Tree 总结
    cogs1889 [SDOI2008]Cave 洞穴勘测 link-cut tree
    Codeforces Round #452 (Div. 2)
    【正经向】NOIP2017烤后总结
    cogs1772 [国家集训队2010]小Z的袜子
    noip2017普及题解
    noip2017 TG 游记
    noip2017 PJ AK记
    jzoj5341 捕老鼠
  • 原文地址:https://www.cnblogs.com/webFrontDev/p/2820399.html
Copyright © 2011-2022 走看看