Skip to content

Instantly share code, notes, and snippets.

@iblueer
Created November 30, 2022 03:07
Show Gist options
  • Save iblueer/4208cc76c00d0b7066c3e4b374fee9be to your computer and use it in GitHub Desktop.
Save iblueer/4208cc76c00d0b7066c3e4b374fee9be to your computer and use it in GitHub Desktop.
从ancc.org.cn网站上发现的
/*
* zCool 1.0 - Javascript
*
* Copyright (c) 2008 - 2013 Zhou BaiMin ( http://jscaler.appspot.com/ )
* Dual licensed under the MIT (MIT-LICENSE.txt)
* and GPL (GPL-LICENSE.txt) licenses.
*
* $Date: 2013-06-29 01:25:00 BeiJing $
* $Revision: 604 $
*/
(function(window, undefined) {
// 将核心对
var $ = function( selector, context, callback ) {
// 返回原型 init 方法构造的对象
return new init( selector, context, callback );
},
// 当前版本号
zcool = '1.0',
// 创建zCool对象的初始化构造函数
init = function( selector, context, callback ) {
// 匹配 $(''), $(null), $(undefined)
if ( !selector ) return this;
switch( typeof selector ){
// 若为字符串(选择器 或 创建节点)
case 'string':
// 若为HTML字符串,创建节点集
if( rHtmlTag.test(selector) ){
createNodes(selector, this, RegExp.$1);
return this;
}
this.selector = selector;
// 若根为本文档
if( !context || typeof context === 'function' ){
context && (callback = context);
this.context = DOC;
if( this[0] = ONLY_ELEMENT[ selector ] ){
this.length = 1;
callback && callback(this[0]);
return this;
}
push.apply(this, jscaler(selector, DOC, callback));
return this;
}
// 若根为节点
if( context.nodeType ){
push.apply(this, jscaler(selector, this.context = context, callback ));
return this;
}
// 若根为其他元素集合
return $( context ).find(selector, callback);
// 若为对象 $(object)
case 'object':
// window.frames === window
// <form> elements || <select> options (ie8- bug)
if( selector === context ){
selector.nodeType && (this.context = selector);
return callback ? concatNodesCall(this, selector, callback) : concatNodes(this, selector);
}
typeof context === 'function' && (callback = context);
// 若构造器为 zCool 自身 $(zCool)
if (selector instanceof $) {
return callback ? selector.each( callback ) : selector;
}
if ( isArray(selector) ) {
callback ? concatNodesCall(this, selector, callback) : push.apply(this, selector);
return this;
}
// 若为节点
if( selector.nodeType || selector === window || isWindow(selector) ){
this.context = this[0] = selector;
this.length = 1;
callback && callback(selector);
return this;
}
// 匹配nodes集合
if (typeof selector.length === 'number') {
// 可能为类似zCool对象
if(typeof selector.selector === 'string'){
this.selector = selector.selector;
this.context = selector.context;
}
return callback ? concatNodesCall(this, selector, callback) : concatNodes(this, selector);
}
// 若为函数 $(function)
case 'function':
// lt safari6 typeof nodeList bug
if( BUGGY_TYPEOF_NODELIST && toString.call(selector) !== '[object Function]' ){
if( selector !== context && typeof context === 'function'){
callback = context;
}
return callback ? concatNodesCall(this, selector, callback) : concatNodes(this, selector);
}
return $( DOC ).DOMReady( selector );
// 其他判断
default:
// 否则返回一个空的zCool对象
return this;
}
},
_zCool = window.zCool,
_$ = window.$,
/*---------------------------------------- DOM 存储 ----------------------------------------*/
// 文档对象
DOC = window.document,
_DOC = DOC,
// 文档根元素
ROOT = DOC.documentElement,
_ROOT = ROOT,
// HTML文档HEAD元素
HEAD = DOC.getElementsByTagName('head')[0],
BODY = DOC.body,
// 确定HTML/XML文档中唯一的元素
ONLY_ELEMENT = {
':root': ROOT
,html: ROOT, HTML: ROOT
,head: HEAD, HEAD: HEAD
,body: BODY, BODY: BODY
},
// 当前窗口页面地址
location = window.location,
op = Object.prototype,
AP = Array.prototype,
SP = String.prototype,
FP = Function.prototype,
sNativeCode = (AP.pop + '').replace('pop', ''),
// 检测是否支持原生方法
isNative = function(m, o) {
return !!(o = (o || window)[m]) && sNativeCode === String(o).replace(m, '');
},
/*---------------------------------------- 常用正则表达式 ----------------------------------------*/
// 驼峰标记法:连字符 + 小(大)写字母 -> 大写字母
rHyphen = /-+([a-zA-Z])/g,
camelCase = function(m, $1){ return $1.toUpperCase() },
// 反驼峰标记法:大写字母 -> 连字符 + 小写字母
rUpperCase = /([A-Z])/g,
// 匹配后缀名
rSuffix = /\.(css|js)(?=|\?.*)$/,
rURIScheme = /^[a-zA-Z]+:[\\\/]/,
rURIPath = /([^?#]+)(?=\/)/,
// URI字符转义替换
rUrlParam = /=\?(&|$)/,
rQuery = /\?/,
rTimeStamp = /(\?|&)_=.*?(&|$)/,
rUrl = /^(\w+:)?\/\/([^\/?#]+)/,
r20 = /%20/g,
rNotSpace = /\S/,
rTrimLeft = /^\s+/,
rTrimRight = /\s+$/,
rTrim = /^\s+|\s+$/,
rSpace = /\s/,
rSpaceG = /\s/g,
rSpaces = /\s+/,
rSpacesG = /\s+/g,
rSpacesX20G = /\x20+/g,
rSpacesrntfG = /[\r\n\t\f]+/g,
reDots = /\./g,
// 匹配HTML字符串,并捕获标签名
rHtmlTag = /^[^<]*<(\w+)[\d\D]+>[^>]*$/m,
// http://www.w3.org/TR/css3-syntax/#characters
// unicode/ISO 10646 characters 161 and higher
characters = '(?:[-\\w]|[^\\x00-\\xa0]|\\\\.)+',
// 字符捕获匹配
encoding = '((?:[-\\w]|[^\\x00-\\xa0]|\\\\.)+)',
// 匹配括弧对 ( ) 或 [ ]
brackets = '(?:\\[.*\\]|\\(.*\\))',
// 匹配简单选择器
rSimple = new RegExp('^(?:\\*|[.#]?' + encoding + ')$'),
// 选择器分组,确保正确的逗号分割
rSplitGroup = /([^,\\()[\]]+|\([^()]+\)|\(.*\)|\[(?:\[[^[\]]*\]|["'][^'"]*["']|[^'"[\]]+)+\]|\[.*\]|\\.)+/g,
// 分割 右向或末尾, 选择器标记分组
rSplitToken = /([^ >+~,\\()[\]]+|\([^()]+\)|\(.*\)|\[[^[\]]+\]|\[.*\]|\\.)+/g,
rClassValue = /([-\w]+)/,
rIdSelector = /#([-\w]+)$/,
// 匹配上下文选择符(首/末)字符
rContext = /[>+~]/,
rLeftContext = /^\s*[>+~]+/,
rLeftParentContext = /^\s*[>+]/,
rRightContext = /[>+~]+\s*$/,
// 选择器匹配过滤无效字符
rValidator = /^\s*(\*|[.:#](?:[a-zA-Z-]|[^\x00-\xa0])+|[>+~a-zA-Z]|[^\x00-\xa0]|\[.*\]|\{.*\})/,
// 备用添加功能(开发者自定义扩展)
Selectors = {
// as a simple example this will check
// for chars not in standard ascii table
//
// 'mySpecialSelector': {
// 'Expression': /\u0080-\uffff/,
// 'Callback': mySelectorCallback
// }
//
// 'mySelectorCallback' will be invoked
// only after passing all other standard
// checks and only if none of them worked
},
// 属性算子
Operators = {
'=': "n=='%m'",
'^=': "n.indexOf('%m')==0",
'*=': "n.indexOf('%m')>-1",
'|=': "(n+'-').indexOf('%m-')==0",
'~=': "(' '+n+' ').indexOf(' %m ')>-1",
'$=': "n.substr(n.length-'%m'.length)=='%m'"
},
TAGS = "(?:^|[>+~\\s])",
// 简单选择器
Optimize = {
ID: new RegExp("#" + encoding + "|" + brackets),
TAG: new RegExp(TAGS + encoding + "|" + brackets),
CLASS: new RegExp("\\." + encoding + "|" + brackets),
NAME: /\[\s*name\s*=\s*((["']*)([^'"()]*?)\2)?\s*\]/
},
// 预编译匹配模式 HASH 表
Patterns = {
// 属性匹配 attribute matcher
attribute: /^\[\s*([-\w]*:?(?:[-\w])+)\s*(?:([~*^$|!]?=)\s*(["']*)([^'"()]*?)\3)?\s*\](.*)/,
// 结构性 - 伪类 structural pseudo-classes
spseudos: /^\:(root|empty|nth)?-?(first|last|only)?-?(child)?-?(of-type)?(?:\(([^\x29]*)\))?(.*)/,
// 表现状态/动态/否定 - 伪类 uistates + dynamic + negation pseudo-classes
dpseudos: /^\:([\w]+|[^\x00-\xa0]+)(?:\((["']*)(.*?(\(.*\))?[^'"()]*?)\2\))?(.*)/,
// E > F
children: /^\s*\>\s*(.*)/,
// E + F
adjacent: /^\s*\+\s*(.*)/,
// E ~ F
relative: /^\s*\~\s*(.*)/,
// E F
ancestor: /^\s+(.*)/,
// *
universal: /^\*(.*)/,
// id
id: new RegExp("^#" + encoding + "(.*)"),
// tag
tagName: new RegExp("^" + encoding + "(.*)"),
// class
className: new RegExp("^\\." + encoding + "(.*)")
},
// CSS3 伪类选择器,可以对其进行扩展
// 3 = CSS3, 2 = CSS2, '?' = maybe implemented
CSS3PseudoClasses = {
Structural: {
'root': 3,
'empty': 3,
'first-child': 3,
'last-child': 3,
'only-child': 3,
'first-of-type': 3,
'last-of-type': 3,
'only-of-type': 3,
'first-child-of-type': 3,
'last-child-of-type': 3,
'only-child-of-type': 3,
'nth-child': 3,
'nth-last-child': 3,
'nth-of-type': 3,
'nth-last-of-type': 3
},
// 其他伪类 HASH 表
Others: {
// 元素状态 UIElementStates (grouped to optimize)
'checked': 3,
'disabled': 3,
'enabled': 3,
'selected': 2,
'indeterminate': '?',
// 动态伪类 Dynamic pseudo classes
'active': 3,
'focus': 3,
'hover': 3,
'link': 3,
'visited': 3,
// 目标/语言/否定 伪类 Target, Language and Negated pseudo classes
'target': 3,
'lang': 3,
'not': 3,
// 包含文本伪类 http://www.w3.org/TR/2001/CR-css3-selectors-20011113/#content-selectors
'contains': '?'
}
},
// HTML 文档 DTD 定义的默认包含 name 属性的元素
// document.getElementsByName IE8- 只能从下列元素中获取
BY_NAME = {
meta:1, a:1, button:1, embed:1, form:1, iframe:1, img:1,
input:1, map:1, object:1, select:1, textarea:1, applet:1
},
// 自带索引的元素
INDEX_NAME = { OPTION:'index', TR:'rowIndex', TH:'cellIndex', TD:'cellIndex' },
/*---------------------------------------- 常用方法 ----------------------------------------*/
// 对象原型(方法)
OP = Object.prototype,
toString = OP.toString,
hasOwnProperty = OP.hasOwnProperty,
constructor = OP.constructor,
// 判断是否为窗口对象
isWindow = function(s, S){
return ( s === '[object Object]'
? new Function('W', S + '(w==w.document&&w.document!=w));}')
: new Function('W,t', S + 't.call(w)==="' + s + '");}') )(window, toString);
}(toString.call(window), 'return function(w){return !!w&&(w===W||'),
// 获取元素所属的窗口对象
getWindow = function(e){
return isWindow(e) ? e : (e = e.ownerDocument || e).defaultView || e.parentWindow;
},
// ecma 5 判断是否为数组的方法
isArray = isNative('isArray', Array) ? Array.isArray :
(Array.isArray = function(o){
return toString.call(o) === "[object Array]";
}),
// 遍历对象,call每个成员
oEach = function(o, f, scope){
if( typeof o === 'function' ){
scope = f;
f = o;
o = this;
}
for(var k in o){
if(f.call(scope, o[k], k, o) === false) return o;
}
return o;
},
// 返回当前时间的毫秒数
now = isNative('now', Date) ? Date.now : (Date.now = function(){
return new Date().getTime();
}),
// 数字或字符串类型(typeof 判断)
NUMBER_STRING = { 'number':1, 'string':1 },
// 引用类型(typeof 判断)
REFERENCE_TYPE = { 'object':1, 'function':1 },
// 空函数
noop = function(){},
// 对象成员强制重载
override = function(t, o){
if(!o){
o = t;
t = this;
}
for(var m in o){
t[m] = o[m];
}
return t;
},
// ecma5 快速创建对象,原型继承
extendClone = isNative('create', Object) ? Object.create :
(Object.create = function(o, P){
noop.prototype = o;
var n = new noop, v;
if(P && REFERENCE_TYPE[ typeof P ]){
for(p in P){
if( hasOwnProperty.call(P, p) ){
if( (v = P[p]) && REFERENCE_TYPE[ typeof v ] && ('value' in v) ){
n[p] = v.value;
}
else{
throw 'value is not a non-null object';
}
}
}
}
return n;
}),
createObject = extendClone,
// 检测是否优先遍历自身属性(测试非IE返回false)
TRAVERSE_OWN_1ST = (function(){
var o = { a: 1 }, c = extendClone(o), k;
c.b = 1;
for(k in c){ return k === 'a' }
})(),
// 简单对象检测:{} 或 new Object() 创建
isPlainObject = function (o){
var k;
if( o && toString.call(o) === "[object Object]" && o.constructor === Object && !hasOwnProperty.call( o, "constructor" ) ){
if( TRAVERSE_OWN_1ST ){
for(k in o){
return hasOwnProperty.call(o,k);
}
return true;
}
for(k in o){}
return k === undefined || hasOwnProperty.call(o,k);
}
return false;
},
// 对象成员继承
extend = $.extend = ($.fn = $.prototype).extend = function(){
var target = arguments[0] || {},
l = arguments.length,
i = 1,
deep = false,
overrides, name, member, copy;
// 若参数0非布尔值,调整继承对象
// deep === true -> 深拷贝
if(typeof target === 'boolean'){
deep = target;
target = arguments[1] || {};
i = 2;
}
// 若为引用类型,调整继承目标
REFERENCE_TYPE[typeof target] || (target = {});
// 根据参数长度定义继承和被继承对象
if(l === i){
target = this;
--i;
}
for(--i; ++i < l;){
overrides = arguments[i];
for(name in overrides){
copy = overrides[name];
if( deep && copy && typeof copy === 'object' ){
member = target[name];
if( isArray(copy) ){
target[name] = extend( deep, member && isArray(member) ? member : [], copy );
}
else if( isPlainObject(copy) ){
target[name] = extend( deep, member && isPlainObject(member) ? member : {}, copy );
}
else{
target[name] = copy;
}
}
else{
target[name] = copy;
}
}
}
return target;
},
// 检测 slice 方法可否转换 DOM 集合为数组 i8- BUG
BUGGY_SLICE = function() {
try {
return !slice.call(DOC.childNodes);
}
catch(e) { return true; }
} (),
makeArray = extend(Array, {
// 从数组中排除指定的元素
exclude: function(t, e, f/*, thisp */){
var l = t.length >>> 0, i = - 1, a = [], L = 0, thisp = arguments[2];
while(++i < l){
if( t[i] !== e ){
f.call(thisp, a[L++] = t[i], i);
}
else{
break;
}
}
while(++i < l){
f.call(thisp, a[L++] = t[i], i);
}
return a;
},
// 数组成员扩延
expand: BUGGY_SLICE ?
function(t, a){
var L=t.length>>>0,
l=a.length>>>0,
i=-1;
while(++i < l){
t[L++] = a[i];
}
return t;
} :
function(t, a){
a.length > 0 && push.apply(t, a);
return t;
}
}).make = function(t){
return Array.expand([], t);
};
// 某些浏览器,解析UTF-8文件的BOM和html的&nbsp;转义字符时
if( rNotSpace.test('\uFEFF\xA0') ){
rTrimLeft = /^[\s\uFEFF\xA0]+/;
rTrimRight = /[\s\uFEFF\xA0]+$/;
rTrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/;
}
// 字符串原型(方法、扩展)
if( !isNative('trimLeft', SP) ){
// 清除字符串首的空白字符
// return String
SP.trimLeft = function(){
return String(this).replace(rTrimLeft, '');
};
// 清除字符串尾的空白字符
// return String
SP.trimRight = function(){
return String(this).replace(rTrimRight, '');
};
if( !isNative('trim', SP) ){
// 清除字符串首尾的空白字符
// return String
SP.trim = function(){
return String(this).replace(rTrimLeft, '').replace(rTrimRight, '');
};
}
}
override(SP, {
// 驼峰标记法
camelCase: function(){
return this.replace(rHyphen, camelCase);
},
// 反驼峰标记法
unCamelCase: function(){
return this.replace( rUpperCase, '-$1' ).toLowerCase();
},
// 首字母大写
capitalize: function(){
return this.charAt(0).toUpperCase() + this.substring(1);
}
});
// 数组原型(方法、扩展)
if( !isNative('indexOf', AP) ){
override(AP,
// javascript 1.6 数组方法,IE8-不支持
{
// 正序(向右)查找元素,返回其索引(可设置起始位置,缺省为0)
indexOf: function(o,i) {
var l=this.length;typeof i!="number"&&(i=i?Number(i)||0:0);i!=0&&(i=i<0?Math.ceil(i):Math.floor(i));for(;i<l;i++)if(i in this&&this[i]===o)return i;return -1
}
// 反序(向左)查找元素,返回其索引(可设置起始位置,缺省为length - 1)
,lastIndexOf: function(o,i) {
var l=this.length;typeof i!="number"&&isNaN(i=Number(i))&&(i=l-1);i!=l-1&&((i=i<0?Math.ceil(i):Math.floor(i))<0?i+=l:i>=l&&(i=l-1));for(;i>-1;i--)if(i in this&&this[i]===o)return i;return -1
}
// 用指定的函数正序call数组中的每个元素
,forEach: function(f,t) {
var l=this.length,i=-1;for(;++i<l;)i in this&&f.call(t, this[i], i, this)
}
// 用指定的函数正序call数组中的每个元素,直到有一次执行结果为true
,some: function(f,t) {
var l=this.length,i=-1;for(;++i<l;)if(i in this&&f.call(t, this[i], i, this))return true;return false
}
// 用指定的函数正序call数组中的每个元素,直到有一次执行结果为false
,every: function(f,t) {
var l=this.length,i=-1;for(;++i<l;)if(i in this&&!f.call(t, this[i], i, this))return false;return true
}
// 用指定的函数正序call数组中的每个元素,以执行结果创建一个新数组
,map: function(f,t) {
var l=this.length,i=-1,a=new Array(l);for(;++i<l;)i in this&&(a[i]=f.call(t, this[i], i, this));return a
}
// 用指定的函数正序call数组中的每个元素,以执行结果为true的元素创建一个新数组
,filter: function(f,t) {
var l=this.length,i=-1,a=[];for(;++i<l;)i in this&&f.call(t, this[i], i, this)&&(a[a.length]=this[i]);return a
}
});
}
override(AP,
// 自定义数组方法
{
// 用指定的函数正序call数组中的每个元素,以执行结果为false的元素创建一个新数组
not: function(f,t) {
var l=this.length,i=-1,a=[];for(;++i<l;)i in this&&!f.call(t, this[i], i, this)&&(a[a.length]=this[i]);return a
},
// 用指定的函数正序call数组中的每个元素,并返回原数组
each: function(f,t) {
var l=this.length,i=-1;for(;++i<l;)i in this&&f.call(t, this[i], i, this);return this
}
// 用指定的函数正序call数组中的每个元素,直到有一次执行结果为true,并返回其索引
,someIndexOf: function(f,t,i) {
var l=this.length;typeof i!="number"&&(i=i?Number(i)||0:0);i!=0&&(i=i<0?Math.ceil(i):Math.floor(i));for(;i<l;i++)if(i in this&&f.call(t, this[i], i, this))return i;return -1
}
// 用指定的函数反序call数组中的每个元素,直到有一次执行结果为true,并返回其索引
,lastSomeIndexOf: function(f,t,i) {
var l=this.length;typeof i!="number"&&isNaN(i=Number(i))&&(i=l-1);i!=l-1&&((i=i<0?Math.ceil(i):Math.floor(i))<0?i+=l:i>=l&&(i=l-1));for(;i>-1;i--)if(i in this&&f.call(t, this[i], i, this))return i;return -1
}
// 从数组中排除指定的元素
,exclude: function(e, f/*, thisp*/) {
var l = this.length >>> 0, i = - 1, a = [], L = 0, thisp = arguments[2];
while(++i < l){
if( this[i] !== e ){
f.call(thisp, a[L++] = this[i], i);
}
else{
break;
}
}
while(++i < l){
f.call(thisp, a[L++] = this[i], i);
}
return a;
}
// 数组成员扩延
,expand: BUGGY_SLICE ?
function(a) {
var l = this.length >>> 0, i = - 1, L = a.length >>> 0;
while(++i < L){
this[l++] = a[i];
}
return this;
} :
function(a) {
a.length > 0 && push.apply(this, a);
return this;
}
// 过滤原数组中重复元素,返回一个新的数组
// 数组元素可为混合类型
// 不改变数组元素原来的次序
,uniq: function(){
var l = this.length, i = 0, e, a = [], L = 1, j;
if( l < 1){
return a;
}
a[0] = this[0];
if( l < 2 ){
return a;
}
o:for( ; ++i < l; ){
e = this[i];
j = L;
for( ; --j > -1; ){
if( a[j] === e ){
continue o;
}
}
a[L++] = e;
}
return a;
}
});
var push = AP.push,
slice = AP.slice,
sort = AP.sort,
indexOf = AP.indexOf,
forEach = AP.forEach,
filter = AP.filter,
map = AP.map,
// 类型判断
typeOf = (function(){
var types = {};
"Arguments Array Boolean Date Error Function JSON Math Number Object RegExp String HTMLCollection NodeList".
split(' ').each(function(type){
types[ '[object ' + type + ']' ] = type;
});
'boolean number string undefined'.
split(' ').each(function(type){
types[ type ] = type.capitalize();
});
return function(o){
return o === null ? 'Null' :
types[ typeof o ] || types[ o = toString.call(o) ] || o.slice(8, -1);
};
})(),
/*---------------------------------------- 功能测试(返回布尔值) ----------------------------------------*/
// 空对象检测
isEmptyObject = function( o ) {
for ( var name in o ) return false;
return true;
},
// 空data存储对象检测
isEmptyDataObject = function( o ) {
var name;
for ( name in o ) {
// 如果公开的和私有data成员对象都为空对象
if ( name === "data" && jQuery.isEmptyObject( o[name] ) ) {
continue;
}
if ( name !== "toJSON" ) {
return false;
}
}
return true;
},
// 检测是否支持DOM原生事件
eventSupport = function(type, tagName){
if( !tagName || typeof tagName === 'string' ){
tagName = DOC.createElement(tagName || 'div');
}
if( tagName[type = 'on' + type] === undefined ){
tagName.setAttribute(type, 'return;');
return tagName = typeof tagName[type] === 'function';
}
return tagName = true;
},
// 检测是否支持DOM原生属性
attrSupport = function(attr, tagName){
typeof( tagName || (tagName = 'div') ) === 'string' &&
( tagName = DOC.createElement(tagName) );
return tagName = tagName[ attr ] !== undefined;
},
// 检测文档 Quirks/Strict 模式的方法
isQuirks = function(doc) {
return typeof doc.compatMode == 'string' ?
doc.compatMode.indexOf('CSS') < 0 :
!!(doc = doc.createElement('div').style) && (doc.width = '1', doc = doc.width != '1px');
},
// 检测当前文档 Quirks/Strict 模式
isQuirksMode = isQuirks(DOC),
_isQuirksMode = isQuirksMode,
// 检测是否为 XML 文档的方法
isXML = function(doc) {
return doc === DOC ? isXMLDoc : doc.body === undefined;
},
// 检测当前是否为 XML 文档
isXMLDoc = isXML(DOC),
_isXMLDoc = isXMLDoc,
// 检测 DOM 原生方法
NATIVE_FOCUS = isNative('hasFocus', DOC),
NATIVE_QSAPI = isNative('querySelector', DOC),
NATIVE_GEBID = isNative('getElementById', DOC),
NATIVE_GEBEN = isNative('getElementsByName', DOC),
NATIVE_GEBTN = isNative('getElementsByTagName', ROOT),
NATIVE_GEBCN = isNative('getElementsByClassName', ROOT),
// does not work for XML namespaced attributes in IE
NATIVE_GET_ATTR = isNative('getAttribute', ROOT),
NATIVE_HAS_ATTR = isNative('hasAttribute', ROOT),
// 检测是否支持前后兄弟元素
NATIVE_ESAPI = 'nextElementSibling' in ROOT,
// 检测是否支持首尾子元素
NATIVE_ECAPI = 'firstElementChild' in ROOT,
// 检测是否支持子元素集合
NATIVE_CEAPI = 'children' in ROOT,
// 支持 DOM 元素 onreadystatechange 方法(IE)
NATIVE_ORSC = eventSupport('readystatechange'),
// 支持本地 JSON 对象(若存在返回本地对象)
NATIVE_JSON = toString.call(window.JSON) == '[object JSON]',
// 支持 W3C 标准事件注册
NATIVE_AEL = isNative('addEventListener'),
// 支持元素获取相对于窗口坐标值
NATIVE_GBCR = isNative('getBoundingClientRect', ROOT),
// 检测是否支持创建事件(DOM 2)
NATIVE_CREATE_EVENT = isNative('createEvent', DOC),
// 支持文档默认显示窗口
DEFAULT_VIEW = DOC.defaultView === window,
// 支持 w3c 标准方法获取元素最终显示样式
NATIVE_GCS = DEFAULT_VIEW && isNative('getComputedStyle', window),
// IE 为当前应用程序或整个系统捕获所有鼠标事件
NATIVE_SET_CAPTURE = isNative('setCapture', ROOT),
// 支持LINK元素的可被触发的原生onload事件属性(IE && opara)
LINK_ON_LOAD = (function(){
var link = DOC.createElement('link');
if('onload' in link){
for(var p in link){
if(p == 'onload') return link = true;
}
}
return link = false;
})(),
PARENT_ELEMENT = 'parentElement' in ROOT,
// 支持 innerHTML
INNER_HTML,
// 支持 textContent
TEXT_CONTENT,
// 存在第一个节点为空白字符(文本节点)
HAS_1ST_WSTN,
// 表格自动创建 tbody 元素
AUTO_TBODY,
// 支持 cssText
CSS_TEXT,
// 支持 CSS 透明属性
CSS_OPACITY,
// 支持 cssFloat, 否则 styleFloat (IE8-)
CSS_FLOAT,
// 支持元素最终显示样式 currentStyle (IE8-)
CURRENT_STYLE,
// 应用 getAttribute 方法取'class'值时,转换为 className
ATTR_CLASS_GET,
// 应用 getAttribute 方法取'for'值时,转换为 htmlFor
ATTR_FOR_GET,
// HTML 点操作符映射
HTML_PROPS_MAP = {
"for": "htmlFor",
"class": "className",
readonly: "readOnly",
maxlength: "maxLength",
cellspacing: "cellSpacing",
rowspan: "rowSpan",
colspan: "colSpan",
tabindex: "tabIndex",
usemap: "useMap",
frameborder: "frameBorder"
},
// HTML 属性映射
HTML_ATTRS_MAP = {
//'for': 'htmlFor', //w3c
//'htmlFor': 'for', //IE8-
//'class': 'className', //w3c
//'className': 'class', //IE8-
},
// CSS 属性映射
CSS_ATTRS = {
//styleFloat: 'cssFloat', //w3c
//cssFloat: 'styleFloat' //IE
},
// 检测 IE8- innerHTML 以<link>、<style>、<script>元素开始 BUG
BUGGY_LINK,
// 是否可对DOM节点的属性做删除操作
DELETE_EXPANDO = false,
// ie6 在移动(单/复)选框节点时,会重置选中状态
BUGGY_MOVE_CHECKED = false,
// checkbox 缺省值是否为 "on"
NATIVE_CHECK_ON = (function(){
var div = DOC.createElement('div'), a, label, checkbox, checked;
try{
delete div.test;
DELETE_EXPANDO = true;
}catch(e){}
div.innerHTML = ' <link/><table></table><a href="/a" class="t" style="float:left;opacity:.55;">t</a><label for="t"></label><input type="checkbox"/>';
TEXT_CONTENT = !!div.textContent;
if(INNER_HTML = !!div.firstChild){
BUGGY_LINK = !!div.getElementsByTagName('link')[0];
HAS_1ST_WSTN = div.firstChild.nodeType === 3;
AUTO_TBODY = !!div.getElementsByTagName('tbody')[0];
CSS_TEXT = /left/.test((a = div.getElementsByTagName('a')[0]).style.cssText);
CURRENT_STYLE = a.currentStyle && typeof a.currentStyle == 'object';
CSS_OPACITY = a.style && typeof a.style == 'object' && /^0\.55$/.test(a.style.opacity);
CSS_ATTRS['float'] = (CSS_FLOAT = 'cssFloat' in a.style) ? (CSS_ATTRS['styleFloat'] = 'cssFloat') : (CSS_ATTRS['cssFloat'] = 'styleFloat');
(ATTR_CLASS_GET = !!a.getAttribute('class')) ? (HTML_ATTRS_MAP['className'] = 'class') : (HTML_ATTRS_MAP['class'] = 'className');
(ATTR_FOR_GET = !!(label = div.getElementsByTagName('label')[0]).getAttribute('for')) ? (HTML_ATTRS_MAP['htmlFor'] = 'for') : (HTML_ATTRS_MAP['for'] = 'htmlFor');
checked = (checkbox = div.getElementsByTagName("input")[0]).checked;
checkbox.click();
BUGGY_MOVE_CHECKED = label.appendChild(checkbox).checked === checked;
return div = label = checkbox = checkbox.value == "on";
}
div = null;
})(),
// 是否支持创建文本节点插入脚本块并执行的标准方法,反之用"text"属性赋值
SCRIPT_EVAL = (function(){
var script = DOC.createElement('script');
script.type = 'text/javascript';
try{
script.appendChild( DOC.createTextNode('Array.$=1') );
}catch(e){}
HEAD.removeChild( HEAD.insertBefore(script, HEAD.firstChild) );
script = null;
if(Array.$){
delete Array.$;
return true;
}
return false;
})(),
// 创建全局执行的脚本
globalEval = new Function('r,D,H', 'return function(s){if(r.test(s)){var S=D.createElement("script");S.type="text/javascript";S.' +
(SCRIPT_EVAL ? 'appendChild(D.createTextNode(s))': 'text=s') + ';H.removeChild(H.insertBefore(S,H.firstChild));S=null}}')(rNotSpace, DOC, HEAD),
/*---------------------------------------- BUG 测试 ----------------------------------------*/
// lt safari6 typeof nodeList bug, return 'function'
BUGGY_TYPEOF_NODELIST = typeof DOC.childNodes !== 'object',
// 检测 IE8- getElementsByTagName/children 包含注释节点 BUG
BUGGY_GEBTN = NATIVE_GEBTN ? (function() {
var b, div = DOC.createElement('div');
div.appendChild(DOC.createComment(''));
b = !!div.getElementsByTagName('*')[0];
div.removeChild(div.firstChild);
return div = b;
})() : true,
// 检测 IE8- GEBEN 不针对所有元素 BUG
BUGGY_GEBEN = NATIVE_GEBEN ? (function() {
var b, B, name = ROOT.getAttribute('name');
name || ROOT.setAttribute('name', (B = true) && (name = 'HTMLHtmlElement'));
b = DOC.getElementsByName(name)[0] !== ROOT;
B && ROOT.removeAttribute('name');
return b;
})() : true,
// 检测 IE8- 非标准的布尔属性 BUG
BUGGY_HATTR = NATIVE_HAS_ATTR ? (function() {
var option = DOC.createElement('option');
option.setAttribute('selected', 'selected');
return option = !option.hasAttribute('selected');
})() : true,
// 检测 Safari select元素默认选中项 BUG
BUGGY_SELECTED = DOC.createElement('select').appendChild(DOC.createElement('option')).selected,
// 检测 NATIVE_QSAPI
RE_BUGGY_QSAPI = NATIVE_QSAPI ? (function() {
var pattern = [],
div = DOC.createElement('div'),
input;
// :enabled :disabled 伪类在 firefox3.5 存在 BUG,IE8 下则会输出错误
// http://www.w3.org/TR/html5/interactive-elements.html#selector-enabled
(input = DOC.createElement('input')).setAttribute('type', 'hidden');
div.appendChild(input);
try {
div.querySelectorAll(':enabled').length > 0 && pattern.push(':enabled', ':disabled');
} catch(e) {}
div.removeChild(div.firstChild);
input = null;
// :link 伪类在 Firefox/Safari 下存在BUG
div.appendChild(DOC.createElement('a')).setAttribute('href', '#');
div.querySelectorAll(':link').length < 1 && pattern.push(':link');
div.removeChild(div.firstChild);
// 新增伪类选择器
pattern.push(':target', ':selected', ':contains');
// IE8- 排除以下选择器
if (BUGGY_HATTR) {
pattern.push(
// 属性为空值时,首/尾 匹配选择符不能选取
'\\[\\s*.*\\^\\=', '\\[\\s*.*\\$\\=',
// input/textarea 元素不能读取原始值
'\\[\\s*value',
// 不能读取原始布尔值
'\\[\\s*ismap', '\\[\\s*checked', '\\[\\s*disabled', '\\[\\s*multiple', '\\[\\s*readonly', '\\[\\s*selected');
}
div = null;
return pattern.length ? new RegExp(pattern.join('|')) : {
'test': function() { return false }
};
})() : true,
/*---------------------------------------- 对象字典 ----------------------------------------*/
// 链接元素标签名
LINK_NODES = {
'a': 1, 'A': 1,
'area': 1, 'AREA': 1,
'link': 1, 'LINK': 1
},
// BUGGY_LINK 的元素标签名
LINK_TAG = {
link: 1, LINK: 1,
style: 1, STYLE: 1,
script: 1, SCRIPT: 1
},
// 由于原生 QSAPI 和新建选择器 API 的差异,只针对文档元素或文档碎片
QSA_NODE_TYPES = { '9': 1, '11': 1 },
// IE8- 获取属性为引用 URI 时,需要做特殊处理
ATTR_URI = {
'action': 2,
'cite': 2,
'codebase': 2,
'data': 2,
'href': 2,
'longdesc': 2,
'lowsrc': 2,
'src': 2,
'usemap': 2
},
// 布尔属性返回属性名,等同于 true/false
ATTR_BOOLEAN = {
checked: 1,
disabled: 1,
ismap: 1,
multiple: 1,
readonly: 1,
selected: 1
},
// 若文档在 quirks mode 下,以下属性必须忽略大小写
HTML_ATTRS = {
'class': 0,
'accept': 1,
'accept-charset': 1,
'align': 1,
'alink': 1,
'axis': 1,
'bgcolor': 1,
'charset': 1,
'checked': 1,
'clear': 1,
'codetype': 1,
'color': 1,
'compact': 1,
'declare': 1,
'defer': 1,
'dir': 1,
'direction': 1,
'disabled': 1,
'enctype': 1,
'face': 1,
'frame': 1,
'hreflang': 1,
'http-equiv': 1,
'lang': 1,
'language': 1,
'link': 1,
'media': 1,
'method': 1,
'multiple': 1,
'nohref': 1,
'noresize': 1,
'noshade': 1,
'nowrap': 1,
'readonly': 1,
'rel': 1,
'rev': 1,
'rules': 1,
'scope': 1,
'scrolling': 1,
'selected': 1,
'shape': 1,
'target': 1,
'text': 1,
'type': 1,
'valign': 1,
'valuetype': 1,
'vlink': 1
},
// 若文档在 XHTML standard mode 下,以下属性必须忽略大小写
XHTML_ATTRS = {
'accept': 1,
'accept-charset': 1,
'alink': 1,
'axis': 1,
'bgcolor': 1,
'charset': 1,
'codetype': 1,
'color': 1,
'enctype': 1,
'face': 1,
'hreflang': 1,
'http-equiv': 1,
'lang': 1,
'language': 1,
'link': 1,
'media': 1,
'rel': 1,
'rev': 1,
'target': 1,
'text': 1,
'type': 1,
'vlink': 1
},
// 支持 pageXOffset 属性 (非IE)
PAGE_OFFSET = 'pageXOffset' in window,
// 窗口级元素的 scroll 属性名映射
WINDOW_SCROLL = PAGE_OFFSET && {
scrollLeft: 'pageXOffset',
scrollTop: 'pageYOffset'
},
/*---------------------------------------- DOM 获取元素方法 ----------------------------------------*/
// 数组(或集合)concat 另一个集合
// @a node array|collection
// @els node array|collection
concatNodes = BUGGY_SLICE ?
function(a, els) {
var l = els.length, i = - 1, L = a.length;
while(++i < l){
a[L++] = els[i];
}
a.length = L;
return a;
} :
function(a, els) {
els.length > 0 && push.apply(a, slice.call(els));
return a;
},
// callback 每个元素
nodesCall = function(els, callback){
var l = els.length, i = -1;
while(++i < l){
callback(els[i], i, els);
}
return els;
},
// 数组(或集合)concat 另一个集合,并 callback 后者的每个元素
concatNodesCall = function(a, els, callback) {
var l = els.length, i = -1, L = a.length;
while(++i < l){
callback(a[L++] = els[i], i, els);
}
a.length = L;
return a;
},
// 根据 id 从元素集中获取一个元素
someById = function(id, els, isXml) {
var i = -1, el;
if (isXml){
while (el = els[++i]) {
if (el.getAttribute('id') === id) return el;
}
}
else{
while (el = els[++i]) {
if (el.id === id) return el;
}
}
return null;
},
// 根据 id 获取一个元素
// @i id
// @f find root
// @t tagName
byId = new Function('x,X,g,d',
'return function(i,f,t){var e;if(f?f===d?X:(e=f.nodeType!=9)||x(f):(f=d)&&X){return g(i,f.getElementsByTagName(t||"*"),!e||x(f.ownerDocument))}' +
'return (e=f.getElementById(i))&&' + (BUGGY_GEBTN ? '(e.id===i||((e=f.all[i])?(e.id===i||(e=g(i,e))):null))&&': '') +
'(!t||t==="*"||e.nodeName===t.toUpperCase()?e:null)}')(isXML, isXMLDoc, someById, DOC),
// 根据 tagName 获取元素,返回数组
byTag = BUGGY_GEBTN ?
function(tagName, from) {
var els = (from || DOC).getElementsByTagName(tagName || (tagName = '*')),
l = els.length, i = -1, a = [], el, j = -1;
if(tagName != '*'){
while(++i < l) a[i] = els[i];
return a;
}
while(++i < l){
(el = els[i]).nodeType == 1 && (a[++j] = el);
}
return a;
}:
function(tagName, from) {
return from.nodeType == 11 ? _byTag(tagName, from) :
slice.call((from || DOC).getElementsByTagName(tagName || '*'));
},
_byTag =
function(tag, from) {
var any = tag == '*', el = from, els = [ ], l = 0, next = el.firstChild;
any || (tag = tag.toUpperCase());
while ((el = next)) {
if (el.tagName > '@' && (any || el.tagName.toUpperCase() == tag)) {
els[l++] = el;
}
if ((next = el.firstChild || el.nextSibling)) continue;
while (!next && (el = el.parentNode) && el !== from) {
next = el.nextSibling;
}
}
return els;
},
// 根据 tagName 从元素集中筛选元素
filterByTag = function(tagName, els, isXml) {
isXml || (tagName = tagName.toUpperCase());
var i = -1, el, a = [], j = -1;
while (el = els[++i]) {
el.nodeName == tagName && (a[++j] = el);
}
return a;
},
// 根据 name 值,从元素集中筛选元素,并定义是否用"."操作符获取
filterByName = function(name, els, noDot) {
var i = -1, el, a = [], j = -1;
if (noDot){
while (el = els[++i]) {
el.getAttribute('name') == name && (a[++j] = el);
}
}
else{
while (el = els[++i]) {
el.name == name && (a[++j] = el);
}
}
return a;
},
// 根据 name 获取元素,返回数组
byName = BUGGY_GEBEN ?
function(name, from, tagName) {
var isDoc = true, isXml = isXMLDoc;
from ? from.nodeType == 9 ? from === DOC || (isXml = isXML(from)) :
(isDoc = false) || (isXml = (isXml = from.ownerDocument) === DOC ? isXMLDoc : isXML(isXml)) :
(from = DOC);
return BY_NAME[tagName || (tagName = '*')] && isDoc && !isXml ?
concatNodes([], from.getElementsByName(name)) :
filterByName(name, from.getElementsByTagName(tagName), isXml);
}:
function(name, from, tagName) {
var isDoc = true, isXml = isXMLDoc;
from ? from.nodeType == 9 ? from === DOC || (isXml = isXML(from)) :
(isDoc = false) || (isXml = (isXml = from.ownerDocument) === DOC ? isXMLDoc : isXML(isXml)) :
(from = DOC);
tagName || (tagName = '*');
return isDoc ? tagName == '*' ?
slice.call(from.getElementsByName(name)) :
filterByTag(tagName, from.getElementsByName(name), isXml) :
filterByName(name, from.getElementsByTagName(tagName), isXml);
},
// 根据 className 获取元素,返回数组
byClass = NATIVE_GEBCN && !BUGGY_SLICE ?
new Function('d,s,g,q,n,r', 'return function(c,f,t){t||(t="*");f||(f=d);' +
(NATIVE_QSAPI ? 'if(t!="*"&&q[f.nodeType]){return n([],f.querySelectorAll(t+(" "+c).replace(r,".")))}': '') +
'var e=f.getElementsByClassName(c);return t=="*"?s.call(e):g(t,e)}')(DOC, slice, filterByTag, QSA_NODE_TYPES, concatNodes, rSpacesG) :
function(className, from, tagName) {
var doc;
from || (from = DOC);
// IE8 支持原生选择器
if ( NATIVE_QSAPI && QSA_NODE_TYPES[from.nodeType] &&
(from.nodeType == 9 ? from === DOC || isXML(from) :
(doc = from.ownerDocument) === DOC ? isXMLDoc : isXML(doc)) ){
return concatNodes([], from.querySelectorAll((!tagName || tagName == '*' ? '' : tagName) + '.' + className.replace(rSpacesG, '.')));
}
var els = (from).getElementsByTagName(tagName || '*'), el, elClass, i = -1, a = [], j = -1;
// 单样式类
if (className.indexOf(' ') < 0) {
className = ' ' + className + ' ';
while (el = els[++i]){
(elClass = el.className) && (elClass = elClass.replace(rTrim, '')) &&
(' ' + elClass + ' ').indexOf(className) > -1 && (a[++j] = el);
}
return a;
}
// 多样式类
className = (' ' + className.replace(rSpacesG, ' , ') + ' ').split(',');
var l = className.length, k = -1;
outer: while (el = els[++i])
if ((elClass = el.className) && (elClass = elClass.replace(rTrim, '')) && elClass.indexOf(' ') > -1) {
elClass = ' ' + elClass + ' ';
j = -1;
while (++j < l) {
if (elClass.indexOf(className[j]) < 0) continue outer;
}
a[++k] = el;
}
return a;
},
// 是否原生支持文档元素的位置比较
NATIVE_CDP = isNative('compareDocumentPosition', DOC),
// 支持元素的包含比较
NATIVE_CONTAINS = isNative('contains', ROOT),
// 支持创建选区
NATIVE_CREATE_RANGE = isNative('createRange', DOC),
// 支持元素在文档中的索引
SOURCE_INDEX = 'sourceIndex' in ROOT,
// 元素排序的比较函数
sortNodes = NATIVE_CDP ?
function(a, b) {
return a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
}:
SOURCE_INDEX ? function(a, b) {
return a.sourceIndex - b.sourceIndex;
}:
NATIVE_CREATE_RANGE ? function(a, b) {
var aRange = a.ownerDocument.createRange(),
bRange = b.ownerDocument.createRange();
aRange.setStart(a, 0);
aRange.setEnd(a, 0);
bRange.setStart(b, 0);
bRange.setEnd(b, 0);
return aRange.compareBoundaryPoints(window.Range.START_TO_END, bRange);
}: noop,
// 检测一个元素是否包含另一个元素
// @container DOM element
// @el DOM element
// @incSelf boolean 表示是否包含自身
contains = NATIVE_CDP ?
function(container, el, incSelf) {
return container === el ? !!incSelf :
( container.compareDocumentPosition(el) & 16 );
}:
new Function('c,e,i', 'if(c===e)return !!i;' +
(NATIVE_CONTAINS ? 'if(c.contains)return c.contains(e);' : '') +
'while(e=e.parentNode)if(e===c)return true;return false'),
// 根据子节点类型确定位置 -> 返回数字
getIndexesByNodeType = function(el) {
var i = 0, indexes,
id = el[CSS_INDEX] || (el[CSS_INDEX] = ++$.CSS_ID);
if (!indexesByNodeType[id]) {
indexes = {};
el = el.firstChild;
while (el) {
if (el.nodeName > '@') {
indexes[el[CSS_INDEX] || (el[CSS_INDEX] = ++$.CSS_ID)] = ++i;
}
el = el.nextSibling;
}
indexes.length = i;
indexesByNodeType[id] = indexes;
}
return indexesByNodeType[id];
},
// 根据子节点名确定位置 -> 返回数字
getIndexesByNodeName = function(el, name) {
var i = 0,
indexes, id = el[CSS_INDEX] || (el[CSS_INDEX] = ++$.CSS_ID);
if (!indexesByNodeName[id] || !indexesByNodeName[id][name]) {
indexes = {};
el = el.firstChild;
while (el) {
if (el.nodeName.toUpperCase() == name) {
indexes[el[CSS_INDEX] || (el[CSS_INDEX] = ++$.CSS_ID)] = ++i;
}
el = el.nextSibling;
}
indexes.length = i;
indexesByNodeName[id] || (indexesByNodeName[id] = {});
indexesByNodeName[id][name] = indexes;
}
return indexesByNodeName[id];
},
// 获取属性值 -> 返回字符串
getAttribute = NATIVE_HAS_ATTR ?
function(node, attr) {
return node.getAttribute(attr) || '';
}: function(node, attr) {
attr = attr.toLowerCase();
if (node.form) {
switch (attr) {
case 'value':
if (node.defaultValue) return node.defaultValue || '';
break;
case 'checked':
return node.defaultChecked && attr;
case 'selected':
return node.defaultSelected && attr;
}
}
return (
// IE8- 获取指定的 URI 属性
ATTR_URI[attr] ? node.getAttribute(attr, 2) || '':
// 布尔属性返回属性名,等同于 true/false
ATTR_BOOLEAN[attr] ? node.getAttribute(attr) ? attr : '':
// 属性映射
HTML_ATTRS_MAP[attr] ? node.getAttribute(HTML_ATTRS_MAP[attr]) :
// 属性节点
((node = node.getAttributeNode(attr)) && node.value) || '');
},
// 判断是否已设置属性 -> 布尔值
hasAttribute = !BUGGY_HATTR ?
function(node, attr) {
return node.hasAttribute(attr);
}: NATIVE_HAS_ATTR ?
function(node, attr) {
return attr == 'selected' && node.nodeName == 'OPTION' ? !!node.getAttribute(attr) : node.hasAttribute(attr);
}: function(node, attr) {
// IE7- 首先需要获取属性节点
// 再返回 "specified" 或 "nodeValue" 属性
return !!((node = node.getAttributeNode(attr)) && (node.specified || node.nodeValue));
// HTML DTD 已定义的元素属性在 IE7- 中必须写值,如:
// 对于<p title></p>, 选择器'p[title]'无法正确匹配
// 对于<p customize></p>, 选择器'p[customize]'可以正确匹配
},
// 验证空节点 -> 布尔值
isEmpty = function(node) {
node = node.firstChild;
while (node) {
if (node.nodeType == 3 || node.nodeName > '@') return false;
node = node.nextSibling;
}
return true;
},
// 验证元素匹配 :link 伪类 -> 布尔值
isLink = function(el) {
return hasAttribute(el, 'href') && LINK_NODES[el.nodeName];
},
/*------------------------------- DEBUGGING --------------------------------*/
// 编译选择器,创建函数解析器
// @selector string
// @mode boolean
// false => select resolvers
// true => match resolvers
compile = function(selector, mode) {
return compileGroup(selector, '', mode || false);
},
// 选择器配置
configure = function(opts) {
if('VERBOSITY' in opts) VERBOSITY = !!opts['VERBOSITY'];
if('SIMPLENOT' in opts) SIMPLENOT = !!opts['SIMPLENOT'];
if('USE_QSAPI' in opts) USE_QSAPI = !!opts['USE_QSAPI'];
},
// 用户通知
emit = function(message) {
if (VERBOSITY) {
var console = window.console;
if (console && console.log) {
console.log(message);
} else {
if (/exception/i.test(message)) {
window.status = message;
window.defaultStatus = message;
} else {
window.status += message;
}
}
}
},
// 默认情况下启用嵌套的复杂选择器
// 对于 :not() 伪类,则使用反规则
SIMPLENOT = false,
// 可以显示 错误/警示 通知
VERBOSITY = false,
// 定义是否启用原生的 querySelectorAll 方法(若支持的话)
USE_QSAPI = NATIVE_QSAPI,
/*---------------------------- COMPILER METHODS ----------------------------*/
// 在多处创建编译函数
ACCEPT_NODE = 'f&&f(c[k]);r[r.length]=c[k];continue main;',
// 验证节点名是否需要大写
TO_UPPER_CASE = typeof DOC.createElementNS == 'function' ? '.toUpperCase()': '',
// 使用 textContent 或 innerText 属性验证 CSS3 :contains 选择器
CONTAINS_TEXT = TEXT_CONTENT ? 'e.textContent' : 'e.innerText',
// 编译一个逗号分隔组 CSS 选择器
// @mode boolean true for select, false for match
// 返回一个编译后的函数
compileGroup = function(selector, source, mode) {
var i = -1,
seen = {},
parts, token;
if ((parts = selector.match(rSplitGroup))) {
while ((token = parts[++i])) {
token = rTrim ? token.replace(rTrim, '') : token.trim();
// 避免相同的选择器重复解析
if (!seen[token]) {
seen[token] = true;
source += i > 0 ? (mode ? 'e=c[k];': 'e=k;') : '';
source += compileSelector(token, mode ? ACCEPT_NODE: 'f&&f(k);return true;');
}
}
}
if (mode) {
// 编译选择器函数
return new Function('c,s,r,d,h,g,f',
'var N,n,x=0,k=-1,e;main:while(e=c[++k]){' + source + '}return r;');
} else {
// 编译匹配器函数
return new Function('e,s,r,d,h,g,f',
'var N,n,x=0,k=e;' + source + 'return false;');
}
},
// 编译基于 CSS3 选择器函数体字符串
// 返回字符串,以备编译
compileSelector = function(selector, source) {
var i, a, b, n, k, expr, match, result, status, test, type, _source = source;
k = 0;
while (selector) {
// *** Universal selector
// * match all (empty block, do not remove)
if ((match = selector.match(Patterns.universal))) {
// do nothing, handled in the compiler where
// BUGGY_GEBTN return comment nodes (ex: IE)
true;
}
// *** ID selector
// #Foo Id case sensitive
else if ((match = selector.match(Patterns.id))) {
// document can contain conflicting elements (id/name)
// prototype selector unit need this method to recover bad HTML forms
source = 'if(' + (_isXMLDoc ? 's.getAttribute(e,"id")': '(e.submit?s.getAttribute(e,"id"):e.id)') + '=="' + match[1] + '"' + '){' + source + '}';
}
// *** Type selector
// Foo Tag (case insensitive)
else if ((match = selector.match(Patterns.tagName))) {
// both tagName and nodeName properties may be upper/lower case
// depending on their creation NAMESPACE in createElementNS()
source = 'if(e.nodeName' + (_isXMLDoc ? '=="' + match[1] + '"': TO_UPPER_CASE + '=="' + match[1].toUpperCase() + '"') + '){' + source + '}';
}
// *** Class selector
// .Foo Class (case sensitive)
else if ((match = selector.match(Patterns.className))) {
// W3C CSS3 specs: element whose "class" attribute has been assigned a
// list of whitespace-separated values, see section 6.4 Class selectors
// and notes at the bottom; explicitly non-normative in this specification.
source = 'if((n=' + (_isXMLDoc ? 's.getAttribute(e,"class")': 'e.className') + ')&&(" "+' + (_isQuirksMode ? 'n.toLowerCase()': 'n') + '.replace(' + rSpacesG + '," ")+" ").indexOf(" ' + (_isQuirksMode ? match[1].toLowerCase() : match[1]) + ' ")>-1' + '){' + source + '}';
}
// *** Attribute selector
// [attr] [attr=value] [attr="value"] [attr='value'] and !=, *=, ~=, |=, ^=, $=
// case sensitivity is treated differently depending on the document type (see map)
else if ((match = selector.match(Patterns.attribute))) {
// xml namespaced attribute ?
expr = match[1].split(':');
expr = expr.length == 2 ? expr[1] : expr[0] + '';
// replace Operators parameter if needed
if (match[2] && match[4] && (type = Operators[match[2]])) {
// case treatment depends on document
HTML_ATTRS['class'] = _isQuirksMode ? 1 : 0;
// replace escaped values and HTML entities
match[4] = match[4].replace(/\\([0-9a-f]{2,2})/, '\\x$1');
test = (_isXMLDoc ? XHTML_ATTRS: HTML_ATTRS)[expr.toLowerCase()];
type = type.replace(/\%m/g, test ? match[4].toLowerCase() : match[4]);
} else {
test = false;
// handle empty values
type = match[2] == '=' ? 'n==""': 'false';
}
// build expression for has/getAttribute
expr = 'n=s.' + (match[2] ? 'get': 'has') + 'Attribute(e,"' + match[1] + '")' + (test ? '.toLowerCase();': ';');
source = expr + 'if(' + (match[2] ? type: 'n') + '){' + source + '}';
}
// *** Adjacent sibling combinator
// E + F (F adiacent sibling of E)
else if ((match = selector.match(Patterns.adjacent))) {
k++;
source = NATIVE_ESAPI ? 'var N' + k + '=e;if(e&&(e=e.previousElementSibling)' + (_source == source ? '===g' : '') + '){' + source + '}e=N' + k + ';': 'var N' + k + '=e;while(e&&(e=e.previousSibling)){if(e.nodeName>"@"){' + source + 'break;}}e=N' + k + ';';
}
// *** General sibling combinator
// E ~ F (F relative sibling of E)
else if ((match = selector.match(Patterns.relative))) {
k++;
if(_source == source){
source = NATIVE_ECAPI && NATIVE_ESAPI ? ('var N' + k + '=e;if((e=e.parentNode)===g.parentNode){e=e.firstElementChild;' + 'while(e){if(e===N' + k + '){continue main;}if(e===g){' + source + '}e=e.nextElementSibling;}}e=N' + k + ';') : ('var N' + k + '=e;if((e=e.parentNode)===g.parentNode){e=e.firstChild;' + 'while(e){if(e===N' + k + '){continue main;}if(e===g&&e.nodeName>"@"){' + source + '}e=e.nextSibling;}}e=N' + k + ';');
}
else{
source = NATIVE_ECAPI && NATIVE_ESAPI ? ('var N' + k + '=e;e=e.parentNode.firstElementChild;' + 'while(e&&e!=N' + k + '){' + source + 'e=e.nextElementSibling;}e=N' + k + ';') : ('var N' + k + '=e;e=e.parentNode.firstChild;' + 'while(e&&e!=N' + k + '){if(e.nodeName>"@"){' + source + '}e=e.nextSibling;}e=N' + k + ';');
}
}
// *** Child combinator
// E > F (F children of E)
else if ((match = selector.match(Patterns.children))) {
k++;
source = 'var N' + k + '=e;if(e&&e!==h&&e!==g&&(e=e.parentNode)' + (_source == source ? '===g' : '') + '){' + source + '}e=N' + k + ';';
}
// *** Descendant combinator
// E F (E ancestor of F)
else if ((match = selector.match(Patterns.ancestor))) {
k++;
source = 'var N' + k + '=e;while(e&&e!==h&&e!==g&&(e=e.parentNode)){' + source + '}e=N' + k + ';';
}
// *** Structural pseudo-classes
// :root, :empty,
// :first-child, :last-child, :only-child,
// :first-of-type, :last-of-type, :only-of-type,
// :nth-child(), :nth-last-child(), :nth-of-type(), :nth-last-of-type()
else if ((match = selector.match(Patterns.spseudos)) && CSS3PseudoClasses.Structural[selector.match(rClassValue)[0]]) {
switch (match[1]) {
case 'root':
// element root of the document
source = 'if(e===h){' + source + '}';
break;
case 'empty':
// element that has no children
source = 'if(s.isEmpty(e)){' + source + '}';
break;
default:
if (match[1] && match[5]) {
if (match[5] == 'n') {
source = 'if(e!==h){' + source + '}';
break;
} else if (match[5] == 'even') {
a = 2;
b = 0;
} else if (match[5] == 'odd') {
a = 2;
b = 1;
} else {
// assumes correct "an+b" format, "b" before "a" to keep "n" values
b = ((n = match[5].match(/(-?\d{1,})$/)) ? parseInt(n[1], 10) : 0);
a = ((n = match[5].match(/(-?\d{0,})n/)) ? parseInt(n[1], 10) : 0);
if (n && n[1] == '-') a = -1;
}
// executed after the count is computed
type = match[4] ? 'n[N]': 'n';
expr = match[2] == 'last' && b >= 0 ? type + '.length-(' + (b - 1) + ')': b;
// shortcut check for of-type selectors
type = type + '[e.' + CSS_INDEX + ']';
// build test expression out of structural pseudo (an+b) parameters
// see here: http://www.w3.org/TR/css3-selectors/#nth-child-pseudo
test = b < 1 && a > 1 ? '(' + type + '-(' + expr + '))%' + a + '==0': a > +1 ? (match[2] == 'last') ? '(' + type + '-(' + expr + '))%' + a + '==0': type + '>=' + expr + '&&(' + type + '-(' + expr + '))%' + a + '==0': a < -1 ? (match[2] == 'last') ? '(' + type + '-(' + expr + '))%' + a + '==0': type + '<=' + expr + '&&(' + type + '-(' + expr + '))%' + a + '==0': a === 0 ? type + '==' + expr: a == -1 ? type + '<=' + expr: type + '>=' + expr;
// 4 cases: 1 (nth) x 4 (child, of-type, last-child, last-of-type)
source = (match[4] ? 'N=e.nodeName' + TO_UPPER_CASE + ';': '') + 'if(e!==h){' + 'n=s.getIndexesBy' + (match[4] ? 'NodeName': 'NodeType') + '(e.parentNode' + (match[4] ? ',N': '') + ');' + 'if(' + test + '){' + source + '}' + '}';
} else {
// 6 cases: 3 (first, last, only) x 1 (child) x 2 (-of-type)
a = match[2] == 'first' ? 'previous': 'next';
n = match[2] == 'only' ? 'previous': 'next';
b = match[2] == 'first' || match[2] == 'last';
type = match[4] ? '&&n.nodeName!=e.nodeName': '&&n.nodeName<"@"';
source = 'if(e!==h){' + ('n=e;while((n=n.' + a + 'Sibling)' + type + ');if(!n){' + (b ? source: 'n=e;while((n=n.' + n + 'Sibling)' + type + ');if(!n){' + source + '}') + '}') + '}';
}
break;
}
}
// *** negation, user action and target pseudo-classes
// *** UI element states and dynamic pseudo-classes
// CSS3 :not, :checked, :enabled, :disabled, :target
// CSS3 :active, :hover, :focus
// CSS3 :link, :visited
else if ((match = selector.match(Patterns.dpseudos)) && CSS3PseudoClasses.Others[selector.match(rClassValue)[0]]) {
switch (match[1]) {
// CSS3 negation pseudo-class
case 'not':
// compile nested selectors, DO NOT pass the callback parameter
// SIMPLENOT allow disabling complex selectors nested
// in :not() pseudo-classes, breaks some test units
expr = rTrim ? match[3].replace(rTrim, '') : match[3].trim();
if (SIMPLENOT && (expr.indexOf(':') > 0 || expr.indexOf('[') > 0)) source = '';
else {
if ('compatMode' in _DOC) {
source = 'N=' + compileGroup(expr, '', false) + '(e,s,r,d,h,g);if(!N){' + source + '}';
} else {
source = 'if(!s.match(e, "' + expr.replace(/\x22/g, '\\"') + '"),r,d,h,g){' + source + '}';
}
}
break;
// CSS3 UI element states
case 'checked':
// only radio buttons, check boxes and option elements
source = 'if(((typeof e.form!=="undefined"&&(/radio|checkbox/i).test(e.type))||/option/i.test(e.nodeName))&&(e.checked||e.selected)){' + source + '}';
break;
case 'enabled':
// does not consider hidden input fields
source = 'if(((typeof e.form!=="undefined"&&!(/hidden/i).test(e.type))||s.isLink(e))&&!e.disabled){' + source + '}';
break;
case 'disabled':
// does not consider hidden input fields
source = 'if(((typeof e.form!=="undefined"&&!(/hidden/i).test(e.type))||s.isLink(e))&&e.disabled){' + source + '}';
break;
// CSS3 lang pseudo-class
case 'lang':
test = '';
if (match[3]) test = match[3].substr(0, 2) + '-';
source = 'do{(n=e.lang||"").toLowerCase();' + 'if((n==""&&h.lang=="' + match[3].toLowerCase() + '")||' + '(n&&(n=="' + match[3].toLowerCase() + '"||n.substr(0,3)=="' + test.toLowerCase() + '")))' + '{' + source + 'break;}}while((e=e.parentNode)&&e!==g);';
break;
// CSS3 target pseudo-class
case 'target':
n = _DOC.location ? _DOC.location.hash: '';
if (n) {
source = 'if(e.id=="' + n.slice(1) + '"){' + source + '}';
}
break;
// CSS3 dynamic pseudo-classes
case 'link':
source = 'if(s.isLink(e)&&!e.visited){' + source + '}';
break;
case 'visited':
source = 'if(s.isLink(e)&&e.visited){' + source + '}';
break;
// CSS3 user action pseudo-classes IE & FF3 have native support
// these capabilities may be emulated by some event managers
case 'active':
if (_isXMLDoc) break;
source = 'if(e===d.activeElement){' + source + '}';
break;
case 'hover':
if (_isXMLDoc) break;
source = 'if(e===d.hoverElement){' + source + '}';
break;
case 'focus':
if (_isXMLDoc) break;
source = NATIVE_FOCUS ? 'if(e===d.activeElement&&d.hasFocus()&&(e.type||e.href)){' + source + '}': 'if(e===d.activeElement&&(e.type||e.href)){' + source + '}';
break;
// CSS2 :contains and :selected pseudo-classes
// not currently part of CSS3 drafts
case 'contains':
source = 'if(' + CONTAINS_TEXT + '.indexOf("' + match[3] + '")>-1){' + source + '}';
break;
case 'selected':
// fix Safari selectedIndex property bug
expr = BUGGY_SELECTED ? '||(n=e.parentNode)&&n.options[n.selectedIndex]===e': '';
source = 'if(e.nodeName=="OPTION"&&(e.selected' + expr + ')){' + source + '}';
break;
default:
break;
}
} else {
// this is where external extensions are
// invoked if expressions match selectors
expr = false;
status = true;
for (expr in Selectors) {
if ((match = selector.match(Selectors[expr].Expression))) {
result = Selectors[expr].Callback(match, source);
source = result.source;
status = result.status;
if (status) break;
}
}
// if an extension fails to parse the selector
// it must return a false boolean in "status"
if (!status) {
// log error but continue execution, don't throw real exceptions
// because blocking following processes maybe is not a good idea
emit('DOMException: unknown pseudo selector "' + selector + '"');
return '';
}
if (!expr) {
// see above, log error but continue execution
emit('DOMException: unknown token in selector "' + selector + '"');
return '';
}
}
// ensure "match" is not null or empty since
// we do not throw real DOMExceptions above
selector = match && match[match.length - 1];
}
return source;
},
/*---------------------------------------- CSS 选择器方法 ----------------------------------------*/
// 选取最后的 选择器/匹配 以供数据解析
lastSlice = '',
lastMatcher = '',
lastSelector = '',
isSingleMatch = false,
isSingleSelect = false,
// 初始化 选择器/匹配 的文档上下文
lastMatchContext = _DOC,
lastSelectContext = _DOC,
// 通过选择器匹配一个元素 -> 返回布尔值
match = function(el, selector, from, callback) {
var resolver, parts, hasChanged;
// 确保为元素节点
if (! (el && el.nodeType == 1 && el.nodeName > '@')) {
emit('DOMException: Passed element is not a DOM ELEMENT_NODE !');
return false;
}
if (from && from.nodeType){
if(!contains(from, el)) return false;
}
else{
typeof from == 'function' && (callback = from);
from = _DOC;
}
// 提取文档上下文
if (lastMatchContext !== from) {
lastMatchContext = from;
_ROOT = (_DOC = el.ownerDocument || el).documentElement;
_isQuirksMode = isQuirks(_DOC);
_isXMLDoc = isXML(_DOC);
}
// 若选择器匹配已迭代变更过
if (hasChanged = lastMatcher != selector) {
// 验证选择器合法性
if (selector && rValidator.test(selector)) {
// 保存通过验证的选择器
lastMatcher = selector;
selector = rTrim ? selector.replace(rTrim, '') : selector.trim();
isSingleMatch = (parts = selector.match(rSplitGroup)).length < 2;
} else {
emit('DOMException: "' + selector + '" is not a valid CSS selector.');
return false;
}
}
// 编译 XML 解析函数
if (_isXMLDoc && !(resolver = XMLMatchers[selector])) {
if (isSingleMatch) {
resolver = new Function('e,s,r,d,h,g,f', 'var N,n,x=0,k=e;' + compileSelector(selector, 'f&&f(k);return true;') + 'return false;');
} else {
resolver = compileGroup(selector, '', false);
}
XMLMatchers[selector] = resolver;
}
// 编译 HTML 解析函数
else if (! (resolver = HTMLMatchers[selector])) {
if (isSingleMatch) {
resolver = new Function('e,s,r,d,h,g,f', 'var N,n,x=0,k=e;' + compileSelector(selector, 'f&&f(k);return true;') + 'return false;');
} else {
resolver = compileGroup(selector, '', false);
}
HTMLMatchers[selector] = resolver;
}
// 重新初始化索引
indexesByNodeType = {};
indexesByNodeName = {};
return resolver(el, snap, [], _DOC, _ROOT, from || _DOC, callback);
},
// 采用本地获取方法的匹配
RE_NATIVE_GET = new RegExp('^(?:(\\*?|' + characters + ')(?:#' + encoding + '|((?:\\.' + characters + ')+)|\\[name=(["\']*)([^"\'()]*?)\\4\\])?)$'),
//RE_NATIVE_GET = new RegExp('^(?:\\*|[.#]?' + characters + ')$'),
// 支持原生选择器时,采用本地获取方法的匹配
RE_NATIVE_GET_SIMPLE =
new RegExp(BUGGY_GEBTN ? '^#?' + characters + '$' : ('^(?:\\*|[.#]?' + characters + ')$')),
SELECROR_NATIVE_GET = { '': 1, '*': 1 },
// 简单选择器,调用的本地 get 方法
// @from element
native_get_simple = function(selector, from, callback) {
var els;
switch (selector.charAt(0)) {
case '#':
if (els = byId(selector.slice(1), from)) {
callback && callback(els);
return [els];
}
return [];
case '.':
els = byClass(selector.slice(1), from);
break;
default:
els = byTag(selector, from);
break;
}
return els.length > 0 && callback ? nodesCall(els, callback) : els;
},
// 常用选择器,调用的本地 get 方法
// @from element
native_get = function(parts, from, callback) {
var els, el, part = parts[0],
part1 = parts[1];
if (part == part1){
els = byTag(part, from);
}
else if (parts[2]) {
(el = byId(parts[2], from, part1)) && callback && callback(el);
return el ? [el] : [];
}
else if (parts[3]){
els = byClass(parts[3].replace(reDots, ' ').slice(1), from, part1);
}
else {
els = byName(parts[5], from, part1);
}
return els.length > 0 && callback ? nodesCall(els, callback) : els;
},
// 支持本地 querySelectorAll 方法 -> 返回数组
qsa_api = function(selector, from, callback) {
if (USE_QSAPI && (!from || QSA_NODE_TYPES[from.nodeType]) && !RE_BUGGY_QSAPI.test(selector)) {
try {
var els = (from || DOC).querySelectorAll(selector);
} catch(e) {}
if (els) {
switch (els.length) {
case 0:
return [];
case 1:
callback && callback(els[0]);
return [els[0]];
default:
return callback ? concatNodesCall([], els, callback) : concatNodes([], els);
}
}
}
// 调用新构建的选择器方法
return new_api(selector, from, callback);
},
// 新构建 CSS 选择器方法 -> 返回数组
new_api = function(selector, from, callback) {
var id, i, el, els, parts, token, resolver, hasChanged, _from;
//from(){}
// 补全首字符
if( rLeftContext.test(selector) ) {
if(from ? from.nodeType == 9 : (from = _DOC = DOC)){
selector = '*' + selector;
}
else{
rLeftParentContext.test(selector) || (_from = from.parentNode);
}
}
// 补全尾字符
rRightContext.test(selector) && (selector = selector + '*');
from || (from = _DOC = DOC);
// 提取文档上下文
if (lastSelectContext != from) {
lastSelectContext = from;
_ROOT = (_DOC = from.ownerDocument || from).documentElement;
_isQuirksMode = isQuirks(_DOC);
_isXMLDoc = isXML(_DOC);
}
// 若选择器匹配已迭代变更过
if (hasChanged = lastSelector != selector) {
// 验证选择器合法性
if (rValidator.test(selector)) {
// 保存通过验证的选择器
lastSelector = selector;
selector = rTrim ? selector.replace(rTrim, '') : selector.trim();
isSingleSelect = (parts = selector.match(rSplitGroup)).length < 2;
} else {
emit('DOMException: "' + selector + '" is not a valid CSS selector.');
return [];
}
}
// 预过滤是否为较大的 DOM 树
// CSS 选择器逗号分隔处理
if (isSingleSelect) {
if (hasChanged) {
// 获取右向选择器标记分组
parts = selector.match(rSplitToken);
token = parts[parts.length - 1];
// 只在 :not 规则前截取
lastSlice = token.split(':not')[0];
}
// 编号优化,以减少元素遍历次数
if ((parts = lastSlice.match(Optimize.ID)) && (token = parts[1])) {
if ((el = byId(token, from))) {
if (match(el, selector)) {
callback && callback(el);
return [el];
}
}
return [];
}
// 选定 ID, 缩小选择范围
else if ((parts = selector.match(Optimize.ID)) && (token = parts[1])) {
if ((el = byId(token, _from || from))) {
if (rContext.test(selector)) {
_from = from = el.parentNode;
} else {
selector = selector.replace('#' + token, '*');
_from = from = el;
}
} else return [];
}
if (NATIVE_GEBCN) {
// 优化:GEBCN, CLASS优先,TAG其次
if ((parts = lastSlice.match(Optimize.CLASS)) && (token = parts[1])) {
if ((els = byClass(token, _from || from)).length === 0) {
return [];
}
} else if ((parts = lastSlice.match(Optimize.TAG)) && (token = parts[1])) {
if ((els = byTag(token, _from || from)).length === 0) {
return [];
}
}
} else {
// 优化:GEBCN, TAG优先,CLASS其次
if ((parts = lastSlice.match(Optimize.TAG)) && (token = parts[1])) {
if ((els = byTag(token, _from || from)).length === 0) {
return [];
}
} else if ((parts = lastSlice.match(Optimize.CLASS)) && (token = parts[1])) {
if ((els = byClass(token, _from || from)).length === 0) {
return [];
}
}
}
}
els || (els = byTag('*', _from || from));
// 预过滤结束
// 编译 XML 的解析函数
if (_isXMLDoc && !(resolver = XMLResolvers[selector])) {
if (isSingleSelect) {
resolver = new Function('c,s,r,d,h,g,f', 'var N,n,x=0,k=-1,e;main:while(e=c[++k]){' + compileSelector(selector, ACCEPT_NODE) + '}return r;');
} else {
resolver = compileGroup(selector, '', true);
}
XMLResolvers[selector] = resolver;
}
// 编译 HTML 的解析函数
else if (! (resolver = HTMLResolvers[selector])) {
if (isSingleSelect) {
resolver = new Function('c,s,r,d,h,g,f', 'var N,n,x=0,k=-1,e;main:while(e=c[++k]){' + compileSelector(selector, ACCEPT_NODE) + '}return r;');
} else {
resolver = compileGroup(selector, '', true);
}
HTMLResolvers[selector] = resolver;
}
// 重新初始化索引
indexesByNodeType = {};
indexesByNodeName = {};
return resolver(els, snap, [], _DOC, _ROOT, from, callback);
},
// 核心选择器方法路由
jscaler = window.jScaler =
new Function('R,r,G,g,d,q,n',
'return function(s,f,c){if(R.test(s))return G(s,f||d,c);var p;if(p=r.exec(s))return g(p,f||d,c);return ' +
(NATIVE_QSAPI ? 'q': 'n') + '(s,f,c)}')
(RE_NATIVE_GET_SIMPLE, RE_NATIVE_GET, native_get_simple, native_get, DOC, qsa_api, new_api),
/*---------------------------------------- 存储 ----------------------------------------*/
// 元素扩展属性,唯一性标记,zCool
CSS_INDEX = 'zCool' + now(),
// 全局唯一键
gukey = CSS_INDEX,
// 内部全局唯一键
_gukey = (gukey + Math.random()).replace('.', ''),
// 内部调用标识
INTERNAL_ID = (CSS_INDEX + Math.random()).replace('.', ''),
// 根据节点类型或节点名决定序号位置
indexesByNodeType = {},
indexesByNodeName = {},
// 存储对不同选择器进行编译的解析函数,以备反复调用
XMLResolvers = {},
HTMLResolvers = {},
// 存储对不同选择器匹配进行编译的解析函数,以备反复调用
XMLMatchers = {},
HTMLMatchers = {},
// 创建一个常用方法的存储器,用来编译函数时用形参传入该对象
snap = {
// element indexing methods (nodeType/nodeName)
getIndexesByNodeType: getIndexesByNodeType,
getIndexesByNodeName: getIndexesByNodeName,
// element inspection methods
getAttribute: getAttribute,
hasAttribute: hasAttribute,
// get 原生选择方法
byClass: byClass,
byName: byName,
byTag: byTag,
byId: byId,
// 验证 辅助方法
isEmpty: isEmpty,
isLink: isLink,
// 匹配选择器选择器
match: match
},
// 事件、数据缓存
Cache = {
//uniqueID or CSS_ID : {
// data: {}, // json
// element: element, // 对应元素 IE8-
// handle: fn, // 事件路由函数 IE8-
// events: { // 事件集
// 'mouseover': [fn, ……], // 事件队列
// 'click': [fn, ……],
// ……
// }
//}
},
/*---------------------------------------- DOMParser 对象 ----------------------------------------*/
// 支持本地解析xml字符串为文档
NATIVE_DOMParser = !!window.DOMParser &&
(isNative('DOMParser') || // chrome & opera & IE9
// firefox '[object DOMConstructor]'
// safari '[object DOMParserConstructor]'
toString.call(window.DOMParser).indexOf('[object DOM') === 0),
// IE 支持插件
NATIVE_AXO = isNative('ActiveXObject', window),
// 检测、模拟原生DOMParser
// 定义全局DOMParser对象
DOMParser = NATIVE_DOMParser ? window.DOMParser :
(window.DOMParser = (function(){
function f(){};
f.prototype.parseFromString = NATIVE_AXO ?
(function(){
try{
new ActiveXObject('Microsoft.XMLDOM');
return function(s){
var x = new ActiveXObject('Microsoft.XMLDOM');
x.async = false;
x.loadXML(s);
x.documentElement || x.loadXML('<parsererror></parsererror>');
return x;
}
}
catch(e){}
return function(s){ emit("DOMException: Your browser does not support this method.") };
})() :
function(s){ emit("DOMException: Your browser does not support this method.") };
return f;
})()),
// 解析xml字符串为xml文档
decodeXML = function(str){ return new DOMParser().parseFromString(str, 'text/xml') },
// 定义全局 XMLSerializer 对象
XMLSerializer = NATIVE_DOMParser ? window.XMLSerializer :
(window.XMLSerializer = (function(){
function f(){};
f.prototype.serializeToString = function(xml){ return xml.xml; };
return f;
})()),
encodeXML = NATIVE_DOMParser ?
function(xml){ return new XMLSerializer().serializeToString(xml) } :
function(xml){ return xml.xml; },
// chrome/safari 在xml文档中children获取子元素集合长度总是为0
BUGGY_XML_CHILDREN = NATIVE_CEAPI && (function(){
var children = decodeXML('<a><b /></a>').documentElement.children;
return !(children && children.length);
})(),
/*---------------------------------------- HTML DOM 方法相关 ----------------------------------------*/
// 验证像素单位尺寸值
rNumPx = /^-?[\d.]+(?:px)?$/i,
// 验证非像素单位尺寸值
rNum = /^-?\d/,
// 验证非像素单位尺寸值
rPercent = /^-?\d+(?:\.\d+)?%$/,
// 验证水平尺寸属性
rHR = /width|left|right/i,
// 验证尺寸属性
rSize = /width|height|top|right|bottom|left/i,
// 返回元素最终呈现样式
// 属性采用css原生写法,即不采用驼峰标记法,float也不转换为cssFloat
finalStyle = NATIVE_GCS ?
function(el, prop){
var curStyle = el.ownerDocument.defaultView.getComputedStyle(el, null);
if(!prop) return curStyle;
if(rPercent.test(curStyle = curStyle.getPropertyValue( prop.replace( rUpperCase, '-$1' ).toLowerCase() )) ){
return parseFloat(finalStyle(el.offsetParent, rHR.test(prop) ? 'width' : 'height')) * parseFloat(curStyle)/100 + 'px';
}
return curStyle;
} :
(function(){
var rOpacity = /^alpha\s*\(\s*opacity\s*[:=]\s*(\d+(?:\.\d+)?|\.\d+)\s*\)$/i;
return function(el, prop){
var curStyle = el.currentStyle;
if(!prop) return curStyle;
switch(prop){
case 'opacity':
return rOpacity.test( curStyle.filter ) ? parseFloat(RegExp.$1)/100 : 1;
case 'float':
return curStyle.styleFloat;
case 'z-index':
return curStyle.zIndex;
case 'zIndex':
return curStyle.zIndex;
}
// 连字符+字母 -> 驼峰标记法
prop = prop.replace( rHyphen, camelCase );
var value = curStyle[ prop ], dProp, cProp, oProp;
// 若值为长度单位值
var isAuto = value === 'auto';
if( isAuto || rNum.test(value) ){
// 若为像素单位值,直接返回结果
if(value.indexOf('px') > 0){
return value;
}
if(rHR.test(prop)){
dProp = 'left';
cProp = 'Left';
bProp = 'Right';
oProp = 'offsetWidth';
}
else{
dProp = 'top';
cProp = 'Top';
bProp = 'Bottom';
oProp = 'offsetHeight';
}
if(isAuto){
value = el[oProp] -
parseInt( finalStyle(el, 'border' + cProp + 'Width') ) -
parseInt( finalStyle(el, 'border' + bProp + 'Width') ) -
parseInt( finalStyle(el, 'padding' + cProp) ) -
parseInt( finalStyle(el, 'padding' + bProp) ) + 'px';
}
// 保存原始值
var style = el.style, dValue = style[dProp],
runStyle = el.runtimeStyle, rdValue = runStyle[dProp];
// 设置运行时的值,获取对应像素值 IE8-
runStyle[dProp] = curStyle[dProp];
style[dProp] = prop == 'fontSize' ? '1em' : (value || 0);
value = style['pixel' + cProp] + 'px';
// 重设回值
style[dProp] = dValue;
runStyle[dProp] = rdValue;
return value;
}
return value;
}
})(),
// 获取元素相对于页面的坐标
coord = function(el){
var win, doc, html, body, clientTop, clientLeft, rect, quirks, top, left, diffTop, diffLeft;
if( !(el && (doc = el.ownerDocument) ) ){
return null;
}
if(doc == DOC){
win = window;
quirks = isQuirksMode;
html = ROOT;
}
else{
win = doc.defaultView || doc.parentWindow;
quirks = isQuirks(doc);
html = doc.documentElement;
}
body = doc.body;
rect = el.getBoundingClientRect();
clientTop = html.clientTop || body.clientTop || 0;
clientLeft = html.clientLeft || body.clientLeft || 0;
diffTop = (win.pageYOffset || quirks || html.scrollTop || body.scrollTop ) - clientTop;
diffLeft = (win.pageXOffset || quirks || html.scrollLeft || body.scrollLeft) - clientLeft;
return {
left: rect.left + diffLeft,
top: rect.top + diffTop,
right: rect.right + diffLeft,
bottom: rect.bottom + diffTop,
width: rect.width || (rect.right - rect.left),
height: rect.height || (rect.bottom - rect.top),
originalCoord: rect
}
},
pageX = function(el){ return coord(el).left },
pageY = function(el){ return coord(el).top },
rClass = /\s{2,}|[\n\t]+/g,
// 调用 trim 方法 -> 字符串
sTrim = rTrim ? '.replace(t, "")' : '.trim()',
// 获取样式类名 -> 字符串
getClass = '(C=X?e.getAttribute("class"):e.className)&&(C=C' + sTrim + ')',
// 设置样式类名 -> 函数(执行返回字符串)
setClass = function(v){return 'X?e.setAttribute("class",' + v + '):(e.className=' + v + ');'};
//
(function(f){
$.extend({
// 返回前一个兄弟元素
prev: f(0),
// 返回后一个兄弟元素
next: f(1),
// 获取前面的所有兄弟元素 返回数组
prevAll: f(0, 1),
// 获取后面的所有兄弟元素 返回数组
nextAll: f(1, 1)
});
})(function(s, a){
// d.nextElementSibling | d.nextSibling
var p = (s ? 'next' : 'previous') + (NATIVE_ESAPI ? 'Element' : '') + 'Sibling',
r = 'return d;',
R = 'return null;',
d = 'return d.' + p + ';',
e = 'while(d=d.' + p + '){';
if(a){
r = 'a[++i]=d;';
R = 'return a' + (s ? ';' : '.reverse();');
}
return new Function('M',
'return function(e,m,t){' +
'var d=e' + (a ? ',a=[],i = -1;' : ';') +
'switch(typeof m){' +
'case "string":' +
't=e.parentNode;' +
e +
'if(M(d,m,t)){' +
r +
'}' +
'}' +
R +
'case "function":' +
e +
'if(' + (NATIVE_ESAPI ? '' : 'd.nodeType===1&&') + 'm.call(t,d,e)){' +
r +
'}' +
'}' +
R +
'default:' +
( NATIVE_ESAPI ?
( a ?
(e +
r +
'}' +
R) :
d ) :
(e +
'if(d.nodeType===1){' +
r +
'}' +
'}' +
R) ) +
'}' +
'}')(match);
});
// 获取所有兄弟元素 返回数组
var sibs = (function(){
var p = 'while(d=E[++i])d!==e&&',
n = '(a[++j]=d);return a;',
t = BUGGY_XML_CHILDREN || BUGGY_GEBTN ? 'd.nodeType==1&&' : '';
return new Function('M', 'return function(e,m,t){var p=e.parentNode,E=p.child' +
(BUGGY_XML_CHILDREN ? 'Nodes' : 'ren') + ',d,i=-1,a=[],j=-1;switch(typeof m){case "string":' +
p + 'M(d,m,t||p)&&' + n + 'case "function":' + p + t + 'm.call(t,d,e)&&' + n + 'default:'+ p + t + n +'}}')(match);
})(),
// 返回第一个子元素
first,
// 返回最后一个子元素
last = (function(f){
first = f('first', 'next');
return f('last', 'previous');
// 获取首、尾子元素(可匹配过滤选择器)
})(function(c, s) {
var b = NATIVE_ECAPI && NATIVE_ESAPI;
if(b){
c += 'ElementChild';
s += 'ElementSibling';
}
else{
c += 'Child';
s += 'Sibling';
}
return new Function('M', 'return function(e,m,t){var d=e.' + c +
';switch(typeof m){case "string":while(d){if(M(d,m,t||e))return d;d=d.' + s +
'}return d;case "function":while(d){if(' + (b ? '' : 'd.nodeType==1&&') +
'm.call(t,d,e))return d;d=d.' + s + '}return d;default:' + (b ? '' : 'while(d){if(d.nodeType==1)return d;d=d.' + s + '}') +
'return d;}}')(match);
}),
// 获取子元素集合(可匹配过滤选择器)
// @e element
// @m selector string
// @t
// return array
children = (function(){
var c='Nodes', d='d.nodeType==1&&', w='while(d=E[++i])' + d + '(a[++j]=d);return a';
if(!(BUGGY_XML_CHILDREN || BUGGY_SLICE || BUGGY_GEBTN)){
c = 'ren';
d = '';
w = 'return s.call(E)';
}
return new Function('M,s', 'return function(e,m,t){var E=e.child' + c + ',d,i=-1,a=[],j=-1;switch(typeof m){case "string":while(d=E[++i])M(d,m,t||e)&&(a[++j]=d);return a;case "function":while(d=E[++i])' + d + 'm.call(t,d,e)&&(a[++j]=d);return a;default:' + w + '}}')(match, slice);
})(),
offsetParent = function(el){
var o = el.offsetParent;
while( o && ONLY_ELEMENT[o.nodeName] === undefined && finalStyle(o, "position") === "static" ){
o = o.offsetParent;
}
return o || el.ownerDocument.body;
},
// 某些元素HTML标签必须插入特定的父标签内,才能产生合法元素
// 另规避:IE7-某些元素innerHTML只读
// 创建这些需要包装的标签hash
WRAP_TAGS = {
'colgroup': 'table',
'col': 'colgroup',
'thead': 'table',
'tfoot': 'table',
'tbody': 'table',
'tr': 'tbody',
'th': 'tr',
'td': 'tr',
'optgroup': 'select',
'option': 'optgroup',
'area': 'map',
'legend': 'fieldset'
},
// 匹配非自闭合标签的缩写
rSelfClosingTag = /<(?!area|base|br|col|command|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)(([\w:]+)[^>]*)\/>/gi,
// 通过html字符串创建元素、节点集合或文档碎片
// @sHtml html string
// @frag element|documentFragment or nodes array|collection
createNodes = function(sHtml, frag, tagName){
tagName = tagName ? tagName.toLowerCase() : rHtmlTag.test(sHtml) && RegExp.$1.toLowerCase()
var root = DOC.createElement('div'),
wrapName = tagName && WRAP_TAGS[tagName],
deep = 0;
sHtml = sHtml.replace(rSelfClosingTag, '<$1></$2>');
// 若匹配hash标签
if(wrapName){
// 迭代包装父标签,并保存迭代层次
do{
sHtml = '<' + wrapName + '>' + sHtml + '</' + wrapName + '>';
deep++;
}
while(wrapName = WRAP_TAGS[wrapName]);
root.innerHTML = sHtml;
// 根据迭代层次截取被包装的子元素
while(--deep > -1){
root = root.removeChild(root.firstChild);
}
}
else if(BUGGY_LINK && tagName && LINK_TAG[tagName] && /^\s*</.test(sHtml)){
root.innerHTML = '<b>!</b>' + sHtml;
root.removeChild(root.firstChild);
}
else{
root.innerHTML = sHtml;
}
if( !frag ){
try{
return root.removeChild( first(root) );
}
finally{ root = null }
}
var firstChild;
// 若为元素或文档碎片
if( frag.nodeType ){
while( firstChild = root.firstChild ){
frag.appendChild( firstChild );
}
}
// 扩展数组或集合
else{
while( firstChild = root.firstChild ){
frag[ frag.length++ ] = root.removeChild( firstChild );
}
}
return root = firstChild = frag;
},
// 通过html字符串创建元素
// @sHtml html string
createElement = function(sHtml){
return /^\w+$/.test(sHtml) ? DOC.createElement(sHtml) : createNodes(sHtml);
},
// text, comment, element and documentFragment node
FRAG_APPEND_NODE_TYPE = { "3": 1, "8": 1, "1": 1, "11": 1 },
// 创建文档碎片
// @nodes nodes array|collection or html string
createFrag = function(nodes){
var frag = DOC.createDocumentFragment(), node, nType, i = -1;
if( nodes ){
if(typeof nodes === 'string'){
return createNodes(nodes, frag);
}
else if( nType = nodes.nodeType ){
FRAG_APPEND_NODE_TYPE[ nType ] && frag.appendChild(nodes);
return frag;
}
else if( nodes.length > 0 ){
while(node = nodes[++i]){
frag.appendChild(node);
}
return frag;
}
}
return frag;
},
// 插入并返回节点
// @p DOM node 参照节点
// @e DOM node 被插入的节点
// @m string 插入方法名
_insert = function(p, e, m){
switch(m){
case 'append':
return p.appendChild(e);
case 'prepend':
return (m = p.firstChild) ? p.insertBefore(e, m) : p.appendChild(e);
case 'before':
return p.parentNode.insertBefore(e, p);
case 'after':
return (m = p.nextSibling) ? p.parentNode.insertBefore(e, m) : p.parentNode.appendChild(e);
case 'replace':
return p.parentNode.replaceChild(e, p);
default:
return e;
}
},
// ie6 fix
insert = BUGGY_MOVE_CHECKED
? function(p, e, m){
var oldCheckeds = [], inputs = e.nodeName === 'INPUT' ? [e] : $.byTag('input', e);
inputs = inputs.filter(function(input){
if( INPUT_CHOOSE_TYPE[input.type] ){
this.push(input.defaultChecked);
input.defaultChecked = input.checked;
return true;
}
}, oldCheckeds);
e = _insert(p, e, m);
inputs.forEach(function(input, i){
input.defaultChecked = this[i];
}, oldCheckeds);
return e;
}
: _insert,
// 过滤并返回不重复的DOM数组或集合
// @a node array or nodeList
// @z node array or nodeList or null
// @h object hash table
uniqNodes = function(a, z, h, callback){
var l = a.length, i = -1, e, L = (z || (z = [])).length || 0, k;
h || (h = {});
while( ++i < l ){
if( k = (e = a[i])[CSS_INDEX] ){
if(!h[k]){
h[k] = 1;
z[L++] = e;
callback && callback(e);
}
}
else{
h[e[CSS_INDEX] = ++$.CSS_ID] = 1;
z[L++] = e;
callback && callback(e);
}
}
z.length = L;
return z;
},
/*---------------------------------------- zCool DOM 加载事件 ----------------------------------------*/
// DOM 加载完毕
DOMContentLoaded = NATIVE_AEL ?
function(){
DOC.removeEventListener('DOMContentLoaded', DOMContentLoaded, false);
DOMReady();
} : function(){
if(DOC.readyState == 'complete'){
DOC.detachEvent('onreadystatechange', DOMContentLoaded);
DOMReady();
}
},
// 标记 DOM 加载是否完成
DOM_LOADED = false,
// DOM 加载完成执行的事件队列
DOM_LOADED_HANDLERS = [],
// IE8- DOM 加载完成辅助方法
doScrollCheck = function(){
// 若 DOM 加载未完成
if (!DOM_LOADED){
try {
// IE8- 定时测试 doScroll 方法执行
// http://javascript.nwbox.com/IEContentLoaded/
ROOT.doScroll('left');
} catch(e) {
return setTimeout( doScrollCheck, 1 );
}
DOMReady();
}
},
// DOM 加载完成执行事件队列
DOMReady = function(){
// 若 DOM 加载未完成
if(!DOM_LOADED){
// 若未加载完全,定时回调
if(!DOC.body) return setTimeout(DOMReady, 15);
DOM_LOADED = true;
if(DOM_LOADED_HANDLERS){
var f, i = -1;
while(f = DOM_LOADED_HANDLERS[++i]){
f.call( DOC, $ );
}
DOM_LOADED_HANDLERS = null;
}
}
},
// 记录是否已绑定 DOM 加载
DOM_READY_BOUND = false,
// 绑定 DOM 加载完成事件
bindDOMReady = function(){
if( DOM_READY_BOUND ) return;
DOM_READY_BOUND = true;
// 若文档 DOM 已加载完成
if( DOC.readyState == "complete" ) return DOMReady();
// w3c 标准事件模型
if( NATIVE_AEL ){
DOC.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
window.addEventListener( "load", DOMReady, false );
}
// IE8- 事件模型
else{
DOC.attachEvent("onreadystatechange", DOMContentLoaded);
window.attachEvent( "onload", DOMReady );
var toplevel = false;
try {
toplevel = window.frameElement == null;
} catch(e) {}
ROOT.doScroll && toplevel && doScrollCheck();
}
},
// 转换为绝对路径
// String 类静态方法
getURIAbsolutePath = String.getURIAbsolutePath = function(url){
var wl = location, href = location.href;
// 若为根绝对路径
if(url.indexOf('/') == 0){
var i = href.indexOf(wl.host);
return href.substring(0, i > 0 ?
i + href.substring(i).indexOf('/') :
href.indexOf(wl.pathname) + wl.pathname.indexOf(':/') + 1 ) + url;
}
// 若为绝对路径,直接返回
if(rURIScheme.test(url)){
return url;
}
href = rURIPath.test(href) && RegExp.$1;
// 若为异目录相对路径
while(url.indexOf('../') == 0){
url = url.substring(3);
href = href.substring(0, href.lastIndexOf('/'));
}
// 若为同目录相对路径
return href + '/' + url;
},
// 引入zCool.js文件的基础URI
BASE_URI = (function(){
var scripts = DOC.getElementsByTagName('script'),
src = scripts[scripts.length - 1].src,
href = getURIAbsolutePath(src),
path = href.slice(0, href.lastIndexOf('/') + 1);
return path;
})(),
// 已载入的外部链接文件
// $.imports 方法调用
LOADED_URIS = {},
// 可载入的外部链接文件的标签
URI_TAGS = [ 'link', 'script' ],
// 已载入的外部链接文件
TAGS_URI_ATTR = { 'LINK': 'href', 'link': 'href', 'SCRIPT': 'src', 'script': 'src' },
// 外部文件加载完成
READY_STATE_COMPLETE = { loaded: 1, complete: 1 },
// 外部文件加载 onload/onreadystatechange 事件绑定回调函数
DOMURILoaded = function(callback){
return function(e){
if(e.type == 'load' || READY_STATE_COMPLETE[this.readyState]){
var callee = arguments.callee, url = this[TAGS_URI_ATTR[this.tagName]];
removeEvent(this, e.type, callee);
if(LOADED_URIS[url] !== 1){
LOADED_URIS[url] = 1;
callee.urlsLength--;
}
if(callee.urlsLength == 0){
typeof callback == 'function' && callback($);
}
}
}
},
// (部分非IE浏览器)外部CSS文件加载若不支持 onreadystatechange/onload 事件,轮询回调
CSSLinkReady = function(el, url, onDOMURILoaded, callback){
return function(){
if(el.sheet){
if(LOADED_URIS[url] !== 1){
LOADED_URIS[url] = 1;
onDOMURILoaded.urlsLength--;
}
if(onDOMURILoaded.urlsLength == 0){
typeof callback == 'function' && callback($);
}
}
else{
setTimeout(arguments.callee, 15);
}
}
},
// 导入外部文件,参数为文件的相对或绝对路径
// 若参数包含一个回调函数,则等待导入的文件加载完成后执行
// urls为一个路径的字符串、外链标签的属性集(或是由它们组成的数组)
imports = function(urls, callback){
(typeof urls == 'string' || toString.call(urls) !== '[object Array]') && (urls = [urls]);
// 若未统计存储过页面的外部链接
if( isEmptyObject(LOADED_URIS) ){
var els, el, tagName, i = -1, j;
while(tagName = URI_TAGS[++i]){
els = DOC.getElementsByTagName(tagName);
j = -1;
while(el = els[++j]){
LOADED_URIS[ el[ TAGS_URI_ATTR[tagName] ] ] = 1;
}
}
}
// 统一生成文件加载函数
var onDOMURILoaded = DOMURILoaded(callback),
l = onDOMURILoaded.urlsLength = urls.length,
i = 0, url, sUrl, attr;
for(; i < l; i++){
url = urls[i];
if(typeof url == 'string' && rSuffix.test(url)){
switch(RegExp.$1){
case 'css':
url = { tagName:'link', rel: 'stylesheet', type: 'text/css', href: url };
break;
case 'js':
url = { tagName:'script', type: 'text/javascript', src: url };
break;
}
}
if(url && typeof(tagName = url.tagName) == 'string'){
delete url.tagName;
// 若未写入
if(!(el = LOADED_URIS[ sUrl = getURIAbsolutePath( url[ TAGS_URI_ATTR[tagName] ] ) ])){
el = DOC.createElement(tagName);
switch(tagName){
case 'script':
url.type || (url.type = 'text/javascript');
addEvent(el, NATIVE_ORSC ? 'readystatechange' : 'load', onDOMURILoaded);
break;
case 'link':
url.rel || (url.rel = 'stylesheet');
url.type || (url.type = 'text/css');
// firefox/safari 浏览器不支持css <link />元素的 onload 事件
NATIVE_ORSC || LINK_ON_LOAD ?
addEvent(el, NATIVE_AEL ? 'load' : 'readystatechange', onDOMURILoaded) :
setTimeout(CSSLinkReady(el, sUrl, onDOMURILoaded, callback), 15);
break;
default:
onDOMURILoaded.urlsLength--;
continue;
}
for(attr in url){
el.setAttribute(attr, url[attr]);
}
// 注意:最后再将元素插入文档,确保IE8-加载完成时,先执行加载内容,再执行回调函数
HEAD.appendChild(LOADED_URIS[sUrl] = el);
el = null;
}
// 若已写入
else{
// 已加载完成
if(el === 1){
if(--onDOMURILoaded.urlsLength == 0){
typeof callback == 'function' && callback($);
return;
}
continue;
}
// 未加载完成
else{
NATIVE_ORSC || LINK_ON_LOAD || tagName != 'link' ?
addEvent(el, NATIVE_AEL ? 'load' : 'readystatechange', onDOMURILoaded) :
setTimeout(CSSLinkReady(el, sUrl, onDOMURILoaded, callback), 15);
el = null;
}
}
}
else{
onDOMURILoaded.urlsLength--;
}
}
},
/*---------------------------------------- zCool 事件 ----------------------------------------*/
Event = function( src, props ){
if( !(this instanceof Event) ){
return new Event(src, props);
}
if( typeof src === 'string' ){
this.type = src;
}
else{
this.originalEvent = src;
this.type = src.type;
this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||
src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;
}
if ( props ) {
extend( this, props );
}
this.timeStamp = now();
this[ CSS_INDEX ] = true;
},
returnTrue = function(){ return true },
returnFalse = function(){ return false },
// 事件 mouseover/mouseout 在元素内部时无效,非IE
EVENT_RELATED_TYPE =
eventSupport('mouseenter') ? {} : {
mouseover: 'mouseenter'
,mouseout: 'mouseleave'
},
// 事件 focus/blur 捕获,非IE
EVENT_CAPTURE_TYPE =
eventSupport('focusin') ? {} : {
focus: 'focusin'
,blur: 'focusout'
},
// 某些事件类型映射转换的反转,非IE
EVENT_TYPES_MAP_SWAP = {},
// 某些事件类型映射转换,非IE
EVENT_TYPES_MAP = (function(){
var m = {};
if( EVENT_RELATED_TYPE.mouseover ){
m.mouseenter = 'mouseover';
m.mouseleave = 'mouseout';
}
if( EVENT_CAPTURE_TYPE.focus ){
m.focusin = 'focus';
m.focusout = 'blur';
}
if( !eventSupport('mousewheel') ){
m.mousewheel = 'DOMMouseScroll';
EVENT_TYPES_MAP_SWAP.DOMMouseScroll = 'mousewheel';
}
return m;
})(),
// 创建一个事件路由器(函数)
eventsRouter = NATIVE_AEL ?
function(e){
// 格式化事件对象
// 根据事件类型获取事件函数队列
var type = e.type, originalType, e = fixEvent(e, this, type),
id = this[CSS_INDEX], events = Cache[id].events, fns;
if( originalType = EVENT_TYPES_MAP_SWAP[type] ){
type = e.type = originalType;
}
// 若模拟 mouseenter/mouseleave 事件
else if(originalType = EVENT_RELATED_TYPE[type]){
if( (fns = events[originalType]) && !(e.relatedTarget && contains(this, e.relatedTarget, true)) ){
e.type = originalType;
callListeners(this, fns, e);
}
// 若不包含原始事件类型(mouseover/mouseout)的队列,直接返回
if( !(fns = events[e.type = type]) ){
return;
}
}
// 若模拟 focusin/focusout 事件
else if( (originalType = EVENT_CAPTURE_TYPE[type]) && e.eventPhase < 3 && (fns = events[originalType]) ){
if( e.eventPhase < 2 || !EVENT_CAPTURE_TYPE[id] ){
e.type = originalType;
callListeners(this, fns, e);
if(fns.length < 1) return;
}
// 若在捕获阶段或不包含原始事件类型(冒泡阶段focus/blur)的队列,直接返回
if( e.eventPhase < 2 || !(fns = events[e.type = type]) ){
return;
}
// 若当前标记为冒泡阶段
if( EVENT_CAPTURE_TYPE[id] ){
// 标记成下一捕获阶段
delete EVENT_CAPTURE_TYPE[id];
}
// 否则标记成下一冒泡阶段
else{
EVENT_CAPTURE_TYPE[id] = 1;
return;
}
}
callListeners(this, fns || events[type], e);
} :
function(e){
callListeners(this, Cache[this[CSS_INDEX]].events[e.type], fixEvent(e, this, e.type));
},
// 执行一个事件队列
callListeners = function(el, fns, e){
var fn, i = -1;
// 依次调用该队列
while(fn = fns[++i]){
// 事件函数call该元素,事件对象作为第一个参数传入
// 若调用返回false,中断调用后续队列
if(fn.call(el, e) === false){
return;
}
// 若此次调用操作了该队列(指在函数内部删除了队列的成员)
fn !== fns[i] && --i;
}
},
// 事件属性
EVENT_PROPS = 'altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement type view wheelDelta which'.split(' '),
// 产生 relatedTarget 的事件(IE)
RELATED_TARGET,
// 鼠标事件集(IE8-)
MOUSE_EVENT,
MOUSE_WHEEL_EVENT = { mousewheel:1, DOMMouseScroll:1 },
// 格式化事件对象的属性和方法(主要是IE8-版本),保持与DOM事件标准一致
fixEvent = function(e, el, t){
// 若已经格式化,返回
if( e[ CSS_INDEX ] ){
return e;
}
var eClone = new Event(e), i = -1, k, v;
while(k = EVENT_PROPS[++i]){
eClone[k] = e[k];
}
if( MOUSE_WHEEL_EVENT[t] ){
eClone.delta = (e.wheelDelta || -e.detail) > 0 ? -1 : 1;
}
// 若支持标准事件模型,直接返回fix事件对象
if(NATIVE_AEL){
// 触发事件的元素为文本节点时,调整为父元素(safari)
(v = e.target).nodeType == 3 && (eClone.target = v.parentNode);
// metaKey(通常为非MAC的浏览器)
!e.metaKey && (v = e.ctrlKey) && (eClone.metakey = v);
return eClone;
}
// IE8-只支持冒泡,不支持捕获(1-捕获阶段,2-在目标上,3-冒泡阶段)
eClone.eventPhase =
// 注册事件的元素
(eClone.currentTarget = el) ===
// 触发事件的元素
(eClone.target = e.srcElement || el.ownerDocument || DOC) ? 2 : 3;
// 鼠标事件中,事件的第二目标
(v = RELATED_TARGET[t]) && (eClone.relatedTarget = e[v]);
// 按键是否有字符与之相关
if(eClone.isChar = (v = e.keyCode) > 0){
// metaKey(通常为非MAC的浏览器)
eClone.metaKey = e.ctrlKey;
// 按下按键的数字代号
eClone.which = v;
}
// 鼠标事件中,按下的鼠标按钮
// 注意:某些浏览器的事件(如IE8-中click、dblclick等)中可能无法正确使用
(v = e.button) && (eClone.which = v & 1 ? 1 : (v & 2 ? 3 : (v & 4 ? 2 : 0)));
// 鼠标事件点相对于页面的x、y坐标
if(MOUSE_EVENT[t]){
var doc = el.ownerDocument || el, html, body;
if( doc === DOC ){
html = ROOT;
}
else{
html = doc.documentElement;
}
body = doc.body;
eClone.pageX = e.clientX + (html.scrollLeft || body.scrollLeft) - (html.clientLeft || body.clientLeft);
eClone.pageY = e.clientY + (html.scrollTop || body.scrollTop) - (html.clientTop || body.clientTop);
}
return eClone;
},
// 注册事件
addEvent = NATIVE_AEL ?
function(el, type, fn){
var originType, capture = false;
if( EVENT_TYPES_MAP[type] ){
type = EVENT_TYPES_MAP[originType = type];
EVENT_CAPTURE_TYPE[type] && (capture = true);
}
// 确定元素全局(存储)唯一标识
var id = el[CSS_INDEX] || (el[CSS_INDEX] = ++$.CSS_ID),
cache = Cache[id] || (Cache[id] = {}),
events = cache.events || (cache.events = {}),
fns = events[originType || type];
// 确认是否存在事件队列
if(!fns){
events[originType || type] = [fn];
el.addEventListener(type, eventsRouter, capture);
return el;
}
// 检测事件队列是否已包含要注册的函数
var f, i = -1;
while(f = fns[++i]){
if(f === fn || f.boundHandle === fn) return el;
}
// 将注册函数插入事件队列
fns.push(fn);
return el;
} :
function(el, type, fn){
// 确定元素全局(存储)唯一标识
var id = el[CSS_INDEX] || (el[CSS_INDEX] = ++$.CSS_ID),
cache = Cache[id] || (Cache[id] = {}),
events = cache.events || (cache.events = {}),
fns = events[type];
// 确认是否存在事件队列
if(!fns){
events[type] = [fn];
el.attachEvent('on' + type, cache.handle || (cache.handle = function(e){ eventsRouter.call(el, e) }));
return cache.element || (cache.element = el);
}
// 检测事件队列是否已包含要注册的函数
var f, i = -1;
while(f = fns[++i]){
if(f === fn || f.boundHandle === fn) return el;
}
// 将注册函数插入事件队列
fns.push(fn);
return el;
},
// 注销事件
removeEvent = NATIVE_AEL ?
function(el, type, fn){
var originType, capture = false;
if( EVENT_TYPES_MAP[type] ){
type = EVENT_TYPES_MAP[originType = type];
EVENT_CAPTURE_TYPE[type] && (capture = true);
}
// 确定元素全局(存储)唯一标识
var id = el[CSS_INDEX], cache, events, fns;
if(id && (cache = Cache[id]) && (events = cache.events) && (fns = events[originType || type])){
var f, i = -1;
while(f = fns[++i]){
if(f === fn || f.boundHandle === fn){
fns.splice(i, 1);
break;
}
}
if(fns.length < 1){
delete events[originType || type];
el.removeEventListener(type, eventsRouter, capture);
for(type in events) return el;
return cleanEventCache(el, cache);
}
}
return el;
} :
function(el, type, fn){
// 确定元素全局(存储)唯一标识
var id = el[CSS_INDEX], cache, events, fns;
if(id && (cache = Cache[id]) && (events = cache.events) && (fns = events[type])){
var f, i = -1;
while(f = fns[++i]){
if(f === fn || f.boundHandle === fn){
fns.splice(i, 1);
break;
}
}
if(fns.length < 1){
el.detachEvent('on' + type, cache.handle);
delete events[type];
for(type in events) return el;
return cleanEventCache(el, cache);
}
}
return el;
},
// 清理元素对应的 Event Cache
cleanEventCache = NATIVE_AEL ? function(el, cache){
delete cache.events;
return el;
} : function(el, cache){
delete cache.events;
delete cache.handle;
delete cache.element;
return el;
},
// 删除一个事件类型的队列
removeEventOne = NATIVE_AEL ?
function(el, type){
// 确定元素全局(存储)唯一标识
var id = el[CSS_INDEX], cache, events, fns, originType, capture = false;
if( EVENT_TYPES_MAP[type] ){
type = EVENT_TYPES_MAP[originType = type];
EVENT_CAPTURE_TYPE[type] && (capture = true);
}
if(id && (cache = Cache[id]) && (events = cache.events) && (fns = events[originType || type])){
fns.length = 0;
delete events[originType || type];
el.removeEventListener(type, eventsRouter, capture);
for(type in events) return el;
return cleanEventCache(el, cache);
}
return el;
} :
function(el, type){
// 确定元素全局(存储)唯一标识
var id = el[CSS_INDEX], cache, events, fns;
if(id && (cache = Cache[id]) && (events = cache.events) && (fns = events[type])){
fns.length = 0;
delete events[type];
el.detachEvent('on' + type, cache.handle);
for(type in events) return el;
return cleanEventCache(el, cache);
}
return el;
},
// 删除一个事件类型的队列
removeEventAll = NATIVE_AEL ?
function(el){
// 确定元素全局(存储)唯一标识
var id = el[CSS_INDEX], cache, events, type, originType;
if(id && (cache = Cache[id]) && (events = cache.events)){
for(type in events){
events[type].length = 0;
if( originType = EVENT_TYPES_MAP[type] ){
el.removeEventListener(originType, eventsRouter, !!EVENT_CAPTURE_TYPE[originType]);
continue;
}
el.removeEventListener(type, eventsRouter, false);
}
return cleanEventCache(el, cache);
}
return el;
} :
function(el){
// 确定元素全局(存储)唯一标识
var id = el[CSS_INDEX], cache, events, type;
if(id && (cache = Cache[id]) && (events = cache.events)){
for(type in events){
events[type].length = 0;
el.detachEvent('on' + type, cache.handle);
}
return cleanEventCache(el, cache);
}
return el;
},
// 确认一个元素是否注册了事件
hasEvent = function(el, type, fn){
var id = el[$.CSS_INDEX], cache, events, fns, l;
return !!(id && (cache = Cache[id]) && (events = cache.events)) &&
// 是否注册任何事件
( (l = arguments.length) < 2 ||
// 是否注册某个类型的事件
( !!(fns = events[type]) && ( l < 3 ||
//是否注册某个类型的事件某个事件函数
fns.indexOf(fn) > -1 ) ) );
},
// 手动触发元素的事件
triggerEvent = new Function('n',
'return function(e,t){if(n(t,e)){e[t]();return e}' +
(NATIVE_CREATE_EVENT ?
'var E=e.ownerDocument.createEvent("Events");E.initEvent(t,true,true);e.dispatchEvent(E);' :
'e.fireEvent("on"+t);') +
'return e}')(isNative),
// 全局侦听器
GLOBAL_LISTENERS = {},
// 手动触发对象的事件侦听器
trigger = function(o, type, args){
var fns, fn, i = -1;
if(o){
if(o.nodeType){
return triggerEvent(o, type);
}
switch(typeof o){
case 'object':
if(o.EVENT_LISTENERS && (fns = o.EVENT_LISTENERS[type])){
while(fn = fns[++i]){
if(fn.apply(o, args) === false) return o;
}
}
return o;
case 'string':
type = o;
args = type;
o = $;
if(fns = GLOBAL_LISTENERS[type]){
while(fn = fns[++i]){
if(fn.apply(o, args) === false) return o;
}
}
return o;
default:
return o;
}
}
return o;
},
// 配置或获取数据
data = function(el, name, value){
},
// 删除元素绑定的事件和数据
// @all 指定是否同时清除所有后代元素的Data
cleanData = function(el, all){
// 确定元素全局(存储)唯一标识
var id = el[CSS_INDEX], cache, data, events, type, originType;
if(id && (cache = Cache[id])){
if(events = cache.events){
if(NATIVE_AEL){
for(type in events){
events[type].length = 0;
if( originType = EVENT_TYPES_MAP[type] ){
el.removeEventListener(originType, eventsRouter, !!EVENT_CAPTURE_TYPE[originType]);
}
el.removeEventListener(type, eventsRouter, false)
}
}
else{
for(type in events){
events[type].length = 0;
el.detachEvent('on' + type, cache.handle);
}
}
}
delete Cache[id];
}
// 包含所有后代元素
all && $.find('*', el, cleanData);
return el;
},
// 删除元素
// @el element
// @keepData boolean 是否保留元素及后代的所有注册事件和数据
remove = function(el, keepData){
keepData || el.nodeType != 1 || cleanData(el, true);
return (keepData = el.parentNode) && keepData.removeChild(el);
},
// 替换元素
// @p element 被替换元素
// @el element 替代元素
// @keepData boolean 是否保留元素及后代的所有注册事件和数据
replace = function(p, el, keepData){
keepData || p.nodeType != 1 || cleanData(el, true);
return (keepData = p.parentNode) && keepData.replaceChild(p, el);
},
/*---------------------------------------- JSON 相关 ----------------------------------------*/
// 反序列化,将标准JSON字符串编译为对象
doDecode = function(json){
return eval('(' + json + ')');
},
// 序列化,将对象解析为标准JSON字符串
doEncode = function(o){
switch(typeof o){
case 'undefined': return 'null';
case 'number': return isFinite(o) ? String(o) : 'null';
case 'string': return encodeString(o);
case 'boolean': return o ? 'true' : 'false';
case 'object':
if(o === null) return 'null';
switch(toString.call(o)){
case '[object Array]': return encodeArray(o);
case '[object Date]': return encodeDate(o);
default:
var a = ['{'], i, v;
for (i in o) {
if(!o.hasOwnProperty || o.hasOwnProperty(i)) {
v = o[i];
switch (typeof v) {
case 'undefined':
case 'function':
case 'unknown':
break;
default:
a.push(encodeString(i), ':', doEncode(v), ',');
}
}
}
a[a.length - 1 || 1] = '}';
return a.join('');
}
}
},
// 匹配转义字符
rEsc = /[\x00-\x1f\\"]/g,
// 转义字符表
ESC = {
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
// 转义字符替换函数
escReplace = function($){
return ESC[$] || ('\\u00' +
Math.floor(($ = $.charCodeAt()) / 16).toString(16) +
($ % 16).toString(16));
},
// 将字符串编译为标准JSON字符串
encodeString = function(s){
return '"' + s.replace(rEsc, escReplace) + '"';
},
// 将数组对象编译为JSON字符串
encodeArray = function(o){
var a = ['['], l = o.length, i = 0, v;
for (; i < l; i++) {
v = o[i];
switch (typeof v) {
case 'function':
case 'unknown':
break;
default:
a.push(doEncode(v), ',');
}
}
a[a.length - 1 || 1] = ']';
return a.join('');
},
// 小于2位数转换为补前位"0"的字符串
pad2Char = Number.pad2Char = function(n){ return (n > 9 ? '' : '0') + n },
// 将日期对象编译为JSON字符串
encodeDate = function(o){
return '"' + o.getFullYear() + '-' +
pad2Char(o.getUTCMonth() + 1) + '-' +
pad2Char(o.getUTCDate()) + 'T' +
pad2Char(o.getUTCHours()) + ':' +
pad2Char(o.getUTCMinutes()) + ':' +
pad2Char(o.getUTCSeconds()) + 'Z"';
},
// 创建JSON对象
JSON = {
// 序列化,解析成字符串
stringify : NATIVE_JSON ? function(o){
return $.USE_NATIVE_JSON ? NATIVE_JSON.stringify(o) : doEncode(o);
} : doEncode,
// 反序列化,编译成对象
parse : NATIVE_JSON ? function(json){
return $.USE_NATIVE_JSON ? NATIVE_JSON.parse(json) : doDecode(json);
} : doDecode
},
/*---------------------------------------- ajax 方法 ----------------------------------------*/
error = function(msg){ throw msg },
// 原生支持异步http请求
NATIVE_XHR = isNative('XMLHttpRequest', window) ||
(function(){
var xhr = window.XMLHttpRequest;
if(!xhr) return false;
try{
return String(new xhr()) == '[object XMLHttpRequest]';
} catch(e){}
})(),
// 创建请求对象
// IE7 无法请求本地文件,当ActiveX可用时启用它
xhr = NATIVE_XHR && !(NATIVE_AXO && location.protocol === "file:") ?
function(){
return new window.XMLHttpRequest();
} :
function(){
try {
return new window.ActiveXObject("Microsoft.XMLHTTP");
} catch(e) {}
},
// 异步get方法请求
get = function( url, data, callback, type ) {
// 若 data 参数省略,则移除该参数
if ( typeof data == 'function' ) {
type = type || callback;
callback = data;
data = null;
}
return ajax({
type: "GET",
url: url,
data: data,
success: callback,
dataType: type
});
},
// 异步get方法请求脚本文件
getScript = function( url, callback ) {
return get(url, null, callback, "script");
},
// 异步get方法请求JSON数据
getJSON = function( url, data, callback ) {
return get(url, data, callback, "json");
},
//
getJsonp = function(url, data, callback, context){
var iframe = DOC.createElement('iframe');
iframe.style.display = 'none';
BODY.appendChild(iframe);
iframe.jsonpCallback = function(json){
callback.call(context || window, json);
this.src = '';
this.jsonpCallback = null;
this.parentNode.removeChild(this);
};
iframe.src = 'javascript:\'<script type="text/javascript" src="' + url +
'"><\/script><script type="text/javascript">frameElement.jsonpCallback(this.jsonp||this.json||this.xml);frameElement.jsonpCallback=null;<\/script>\';';
iframe = null;
},
// 异步post方法请求JSON数据
post = function( url, data, callback, type ) {
// 若 data 参数省略,则移除该参数
if ( typeof data == 'function' ) {
type = type || callback;
callback = data;
data = {};
}
return ajax({
type: "POST",
url: url,
data: data,
success: callback,
dataType: type
});
},
// 配置异步方法
ajaxSetup = function( settings ) {
// 若存在设置选项
if( settings ){
extend( true, ajaxSettings, settings );
}
// 否则设置为缺省参数
else{
ajaxSettings = extend(true, {}, _ajaxSettings);
}
},
// 异步缺省参数设置(内部)
_ajaxSettings = {
url: location.href,
global: true,
type: "GET",
contentType: "application/x-www-form-urlencoded",
processData: true,
async: true,
ifModified: false,
/*
timeout: 0,
data: null,
username: null,
password: null,
traditional: false,
*/
xhr: xhr,
accepts: {
xml: "application/xml, text/xml",
html: "text/html",
script: "text/javascript, application/javascript",
json: "application/json, text/javascript",
text: "text/plain",
_default: "*/*"
}
},
// 异步缺省参数设置
ajaxSettings = extend(true, {}, _ajaxSettings),
// 保存请求header的最后修改,为下一次请求做准备
Last_Modified = {},
Etag = {},
// http 发送数据动作类型
HTTP_SEND_TYPE = { POST: 1, PUT: 1, DELETE: 1 },
// URI字符转义替换
rUrlParam = /=\?(&|$)/,
rQuery = /\?/,
rTimeStamp = /(\?|&)_=.*?(&|$)/,
rUrl = /^(\w+:)?\/\/([^\/?#]+)/,
r20 = /%20/g,
JSON_INDEX = now(),
// 异步请求方法
ajax = function( origSettings ) {
var s = extend( extend(true, {}, ajaxSettings), origSettings),
jsonp, status, data, sdata = s.data, dataType = s.dataType, url = s.url,
callbackContext = origSettings && origSettings.context || s,
type = s.type.toUpperCase();
// 若需要,转换 data 为字符串
if ( sdata && s.processData && typeof sdata !== "string" ) {
sdata = s.data = encodeURIParams( sdata, s.traditional );
}
// Handle JSONP Parameter Callbacks
if ( dataType === "jsonp" ) {
if ( type === "GET" ) {
if ( !rUrlParam.test( url ) ) {
url = (s.url += (rQuery.test( url ) ? "&" : "?") + (s.jsonp || "callback") + "=?");
}
} else if ( !sdata || !rUrlParam.test(sdata) ) {
sdata = s.data = (sdata ? sdata + "&" : "") + (s.jsonp || "callback") + "=?";
}
dataType = s.dataType = "json";
}
// Build temporary JSONP function
if ( dataType === "json" && (data && rUrlParam.test(data) || rUrlParam.test(url)) ) {
jsonp = s.jsonpCallback || ("jsonp" + JSON_INDEX++);
// Replace the =? sequence both in the query string and the data
if ( sdata ) {
sdata = s.data = (sdata + "").replace(rUrlParam, "=" + jsonp + "$1");
}
url = s.url = url.replace(rJson, "=" + jsonp + "$1");
// We need to make sure
// that a JSONP style response is executed properly
dataType = s.dataType = "script";
// Handle JSONP-style loading
window[ jsonp ] = window[ jsonp ] || function( tmp ) {
data = tmp;
success();
complete();
// Garbage collect
window[ jsonp ] = undefined;
try {
delete window[ jsonp ];
} catch(e) {}
if ( head ) {
head.removeChild( script );
}
};
}
if ( dataType === "script" && s.cache === null ) {
s.cache = false;
}
if ( s.cache === false && type === "GET" ) {
var ts = now();
// try replacing _= if it is there
var ret = url.replace(rTimeStamp, "$1_=" + ts + "$2");
// if nothing was replaced, add timestamp to the end
url = s.url = ret + ((ret === url) ? (url.indexOf('?') > -1 ? "&" : "?") + "_=" + ts : "");
}
// If data is available, append data to url for get requests
if ( sdata && type === "GET" ) {
url = (s.url += (url.indexOf('?') > -1 ? "&" : "?") + sdata);
}
// Watch for a new set of requests
if ( s.global && ! AJAX_ACTIVE++ ) {
trigger( "ajaxStart" );
}
// Matches an absolute URL, and saves the domain
var parts = rUrl.exec( url ),
remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host);
// If we're requesting a remote document
// and trying to load JSON or Script with a GET
if ( dataType === "script" && type === "GET" && remote ) {
var head = HEAD || ROOT;
var script = DOC.createElement("script");
script.src = url;
if ( s.scriptCharset ) {
script.charset = s.scriptCharset;
}
// Handle Script loading
if ( !jsonp ) {
var done = false;
// Attach handlers for all browsers
script.onload = script.onreadystatechange = function() {
if ( !done && (!this.readyState ||
this.readyState === "loaded" || this.readyState === "complete") ) {
done = true;
success();
complete();
// Handle memory leak in IE
script.onload = script.onreadystatechange = null;
if ( head && script.parentNode ) {
head.removeChild( script );
}
}
};
}
// Use insertBefore instead of appendChild to circumvent an IE6 bug.
// This arises when a base node is used (#2709 and #4378).
head.insertBefore( script, head.firstChild );
// We handle everything using the script element injection
return undefined;
}
var requestDone = false;
// 创建请求对象
var xhr = s.xhr();
// 若无法创建,直接返回
if ( !xhr ) return;
// 打开异步请求连接
if ( s.username ) {
xhr.open(type, url, s.async, s.username, s.password);
} else {
xhr.open(type, url, s.async);
}
// 某些浏览器跨 domain 请求时,需要额外的 try/catch 处理异常(如 Firefox 3)
try {
// 设置正确的请求头,如果数据开始发送
if ( sdata || origSettings && origSettings.contentType ) {
xhr.setRequestHeader("Content-Type", s.contentType);
}
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
if ( s.ifModified ) {
if ( Last_Modified[url] ) {
xhr.setRequestHeader("If-Modified-Since", Last_Modified[url]);
}
if ( Etag[s.url] ) {
xhr.setRequestHeader("If-None-Match", Etag[url]);
}
}
// Set header so the called script knows that it's an XMLHttpRequest
// Only send the header if it's not a remote XHR
if ( !remote ) {
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
}
// Set the Accepts header for the server, depending on the dataType
xhr.setRequestHeader("Accept", dataType && s.accepts[ dataType ] ?
s.accepts[ dataType ] + ", */*" :
s.accepts._default );
} catch(e) {}
// Allow custom headers/mimetypes and early abort
if ( s.beforeSend && s.beforeSend.call(callbackContext, xhr, s) === false ) {
// Handle the global AJAX counter
if ( s.global && ! --AJAX_ACTIVE ) {
$.trigger( "ajaxStop" );
}
// close opended socket
xhr.abort();
return false;
}
if ( s.global ) {
trigger("ajaxSend", [xhr, s]);
}
// 等待请求回调
var onreadystatechange = xhr.onreadystatechange = function( isTimeout ) {
// 若请求被终止
if ( !xhr || xhr.readyState === 0 || isTimeout === "abort" ) {
// 某些浏览器在这之前不支持触发回调(如opera某些版本)
// 模拟回调
if ( !requestDone ) {
complete();
}
requestDone = true;
if ( xhr ) {
xhr.onreadystatechange = noop;
}
}
// 若请求传输完成,数据是否可用,或已超时
else if ( !requestDone && xhr && (xhr.readyState === 4 || isTimeout === "timeout") ) {
requestDone = true;
xhr.onreadystatechange = noop;
status = isTimeout === "timeout" ?
"timeout" :
!httpSuccess( xhr ) ?
"error" :
s.ifModified && httpNotModified( xhr, s.url ) ?
"notmodified" :
"success";
var errMsg;
if ( status === "success" ) {
// Watch for, and catch, XML document parse errors
try {
// process the data (runs the xml through httpData regardless of callback)
data = httpData( xhr, s.dataType, s );
} catch(err) {
status = "parsererror";
errMsg = err;
}
}
// Make sure that the request was successful or notmodified
if ( status === "success" || status === "notmodified" ) {
// JSONP handles its own success callback
if ( !jsonp ) {
success();
}
} else {
handleError(s, xhr, status, errMsg);
}
// Fire the complete handlers
complete();
if ( isTimeout === "timeout" ) {
xhr.abort();
}
// Stop memory leaks
if ( s.async ) {
xhr = null;
}
}
};
// 重写中止请求处理程序,IE 可能不允许,但也行
// opera 中止请求时则不能触发 onreadystatechange 事件
try {
var oldAbort = xhr.abort;
xhr.abort = function() {
if ( xhr ) {
oldAbort.call( xhr );
}
onreadystatechange( "abort" );
};
} catch(e) { }
// 超时检测
if ( s.async && s.timeout > 0 ) {
setTimeout(function() {
// 检测查看请求是否还在持续
if ( xhr && !requestDone ) {
onreadystatechange( "timeout" );
}
}, s.timeout);
}
// 发送数据
try {
xhr.send( HTTP_SEND_TYPE[type] && s.data ? s.data : null );
} catch(e) {
handleError(s, xhr, null, e);
// 执行完成函数
complete();
}
// 某些老版本浏览器(如 firefox 1.5)同步请求时不能触发状态的改变
if ( !s.async ) {
onreadystatechange();
}
// 缺省请求成功的执行函数
function success() {
// 如果指定了一个请求成功回调函数,触发该回调函数并传入数据
if ( s.success ) {
s.success.call( callbackContext, data, status, xhr );
}
// 确认触发全局的请求成功回调
if ( s.global ) {
trigger( "ajaxSuccess", [xhr, s] );
}
}
// 缺省请求完成的执行函数
function complete() {
// 如果指定了一个请求完成回调函数,触发该回调函数处理结果
if ( s.complete ) {
s.complete.call( callbackContext, xhr, status);
}
// 确认触发全局的请求完成回调
if ( s.global ) {
trigger( "ajaxComplete", [xhr, s] );
}
// 操作全局 ajax 请求计数
if ( s.global && ! --AJAX_ACTIVE ) {
$.trigger( 'ajaxStop' );
}
}
// function trigger(type, args) {
// (s.context ? $(s.context) : $).trigger(type, args);
// }
// 返回 XMLHttpRequest 对象,以便可后续(终止)操作
return xhr;
},
// AJAX激活统计
AJAX_ACTIVE = 0,
// 匹配方括号对
rPairBrackets = /\[\]$/,
// 符escape不编码字符有69个:*,+,-,.,/,@,_,0-9,a-z,A-Z
// encodeURI不编码字符有82个:!,#,$,&,',(,),*,+,,,-,.,/,:,;,=,?,@,_,~,0-9,a-z,A-Z
// encodeURIComponent不编码字符有71个:!, ',(,),*,-,.,_,~,0-9,a-z,A-Z
rPlus = /\+/g,
isUtf = (DOC.charset || DOC.characterSet).toLowerCase() === 'utf-8',
rSingleByteG = /[\x00-\xff]/,
escapeDBC = NATIVE_AXO && isNative('execScript') ?
// 如果是 ie, 使用 vbscript
function(s){
window.execScript('SetLocale "zh-cn"', 'vbscript');
window[_gukey] = '';
var i = -1, l = s.length, d = '', t;
while(++i<l){
window.execScript('window.' + _gukey + '=Hex(Asc("' + s.charAt(i) + '"))', "vbscript");
d += '%' + (t = window[_gukey]).slice(0,2) + '%' + t.slice(-2);
}
window[_gukey] = undefined;
return d;
} :
// 其它浏览器利用浏览器对请求地址自动编码的特性
function(s){
var a = DOC.createElement("a"), t = (a.href = '?' + s, a.href);
return t.slice(t.indexOf('?') + 1);
},
rG = /([^\x00-\xff]+)|([\x00-\xff]+)/g,
encodeURLParam = function( s ){
return s.replace(rG, function(m, $1, $2) {
return ($1 ? escapeDBC($1) : '') + ($2 ? encodeURIComponent($2) : '');
});
},
// 根据 键/值 构建URL的参数,
// @isPost 是否用字符串作为post请求体
buildURIParam = function(key, value){
// 若为函数,call并传入键名、该函数在原集合中的索引、原集合
value = typeof value == 'function'
? value(key)
: isUtf
? encodeURIComponent(key) + '=' + encodeURIComponent(value)
: encodeURLParam(key) + '=' + encodeURLParam(value);
return value;
},
INPUT_CHOOSE_TYPE = { checkbox: 1, radio: 1 },
// 序列化一个 form elements 或 键/值 到数组,并串行输出为URI查询字符串
encodeURIParams = function( data, traditional ){
var name, a = [];
arguments.length < 2 && (traditional = ajaxSettings.traditional);
// 从表单元素或对象成员序列化
if( data.nodeType && !data.disabled ){
switch( data.tagName ){
case 'FORM':
forEach.call(data.elements, formElementBuild, a);
break;
case 'INPUT':
if( (name = data.name) && ( !INPUT_CHOOSE_TYPE[data.type] || data.checked ) ){
return buildURIParam( name, data.value );
}
return '';
break;
case 'TEXTAREA':
if( !(name = data.name) ) return '';
return buildURIParam( name, data.value );
break;
case 'SELECT':
if( !(name = data.name) ) return '';
// 多选
if( data.multiple ){
forEach.call(data, multipleBuild, a);
}
else{
return buildURIParam( name, data.value );
}
break;
case 'OPTION':
return '';
break;
case 'BUTTON':
if( !(name = data.name) ) return '';
return buildURIParam( name, data.value );
break;
default:
forEach.call(byTag('*', data), formElementBuild, a);
}
return a.join('&').replace(r20, '+');
}
else if( typeof data.length === 'number' ){
forEach.call(data, formElementBuild, a);
}
else{
for(var key in data){
addURIParams(key, data[key]);
}
}
// 返回序列化URL参数字符串
return a.join('&').replace(r20, '+');
function formElementBuild(el){
if( !el.disabled && (name = el.name)) {
switch( el.tagName ){
case 'INPUT':
if( !INPUT_CHOOSE_TYPE[el.type] || el.checked ){
this[ this.length ] = buildURIParam( name, el.value );
}
break;
case 'TEXTAREA':
this[ this.length ] = buildURIParam( name, el.text );
break;
case 'SELECT':
el.multiple ? forEach.call(el, multipleBuild, this) :
(this[ this.length ] = buildURIParam( name, el.value ));
break;
case 'OPTION':
break;
case 'BUTTON':
this[ this.length ] = buildURIParam( name, el.value );
break;
default:
}
}
};
function multipleBuild( option ){
if( option.selected ){
this[ this.length ] = buildURIParam( name, option.value );
}
};
// 添加URL参数集
function addURIParams(key, value){
// 序列化数组项
if(toString.call(value) == '[object Array]'){
forEach.call(value, traditional || rPairBrackets.test(key) ?
// 对每个数组项的作为一个标量的数组
function(v){ a[a.length] = buildURIParam(key, v) } :
// 尾递归序列化
function(v, i){ addURIParams(key + '[' + ( typeof v === 'object' ? i : '' ) + ']', v) });
}
else if ( !traditional && value && typeof value === 'object' ) {
// 序列化对象hash
oEach.call(value, function(v, k){ addURIParams(key + '[' + k + ']', v) });
}
else{
a[a.length] = buildURIParam(key, value);
}
}
},
// 异步请求错误执行回调
handleError = function( s, xhr, status, e ) {
// 若本地回调函数已指定(写入配置),触发它
if ( s.error ) {
s.error.call( s.context || s, xhr, status, e );
}
// 触发全局回调函数
// if ( s.global ) {
// (s.context ? $(s.context) : $).trigger( "ajaxError", [xhr, s, e] );
// }
},
// 确认异步请求是否成功
httpSuccess = function( xhr ) {
try {
// IE 在状态为 204 时,有时会错误的返回 1223,所以此时将其状态视为成功
return !xhr.status && location.protocol === "file:" ||
// Opera 在状态为 304 时返回 0
( xhr.status >= 200 && xhr.status < 300 ) ||
xhr.status === 304 || xhr.status === 1223 || xhr.status === 0;
} catch(e) {}
return false;
},
// 确认异步请求返回结果未被编辑
httpNotModified = function( xhr, url ) {
var _Last_Modified = xhr.getResponseHeader("Last-Modified"),
_Etag = xhr.getResponseHeader("Etag");
if ( _Last_Modified ) {
Last_Modified[url] = _Last_Modified;
}
if ( _Etag ) {
Etag[url] = _Etag;
}
// Opera 在状态为 304 时返回 0
return xhr.status === 304 || xhr.status === 0;
},
httpData = function( xhr, type, s ) {
var ct = xhr.getResponseHeader("content-type") || "",
xml = type === "xml" || !type && ct.indexOf("xml") >= 0,
data = xml ? xhr.responseXML : xhr.responseText,
root;
if ( xml ) {
if(!( (root = data.documentElement) &&
root.nodeName !== "parsererror" &&
xhr.responseText || NATIVE_AXO)){
error( "parsererror" );
}
if(NATIVE_AXO){
data = decodeXML(xhr.responseText);
if(!(root = data.documentElement) || root.nodeName === "parsererror"){
error( "parsererror" );
}
}
}
// Allow a pre-filtering function to sanitize the response
// s is checked to keep backwards compatibility
if ( s && s.dataFilter ) {
data = s.dataFilter( data, type );
}
// The filter can actually parse the response
if ( typeof data == "string" ) {
// Get the JavaScript object, if JSON is used.
if ( type === "json" || !type && ct.indexOf("json") > -1 ) {
data = $.decode( data );
// If the type is "script", eval it in global context
} else if ( type === "script" || !type && ct.indexOf("javascript") > -1 ) {
globalEval( data );
}
}
return data;
};
// IE8-
(function(){
var b = (BODY || HEAD || ROOT).appendChild(document.createElement('button'));
b.onclick = function(e){
('relatedTarget' in (e || (e = window.event))) ||
(RELATED_TARGET = { mouseover:'fromElement', mouseout:'toElement', mouseenter:'fromElement', mouseleave:'toElement' });
('pageX' in e) ||
(MOUSE_EVENT = { mouseover:1, mouseout:1, mousedown:1, mouseup:1, mousemove:1, mouseenter:1, mouseleave:1, mousewheel:1, click:1, dblclick:1 });
}
b.click && b.click();
b.parentNode.removeChild(b);
b = null;
})();
// 标准化内建事件原型
extend( Event.prototype, {
// 阻止事件产生时浏览器默认行为
preventDefault: function() {
this.isDefaultPrevented = returnTrue;
var e = this.originalEvent;
if ( e ) {
if ( e.preventDefault ) {
e.preventDefault();
} else { // IE8-
e.returnValue = false;
}
}
},
// 取消事件冒泡
stopPropagation: function() {
this.isPropagationStopped = returnTrue;
var e = this.originalEvent;
if ( e ) {
if ( e.stopPropagation ) {
e.stopPropagation();
}
// IE8-
e.cancelBubble = true;
}
},
stopImmediatePropagation: function() {
this.isImmediatePropagationStopped = returnTrue;
this.stopPropagation();
},
stopDelegate: function(){
this.isDelegateStopped = returnTrue;
},
isDelegateStopped: returnFalse,
isDefaultPrevented: returnFalse,
isPropagationStopped: returnFalse,
isImmediatePropagationStopped: returnFalse
});
// 继承 ajax 方法
$.extend({
get: get,
getScript: getScript,
getJSON: getJSON,
post: post,
ajaxSetup: ajaxSetup,
ajaxSettings: ajaxSettings,
ajax: ajax,
Last_Modified: Last_Modified,
Etag: Etag,
buildURIParam: buildURIParam,
encodeURIParams: encodeURIParams,
encodeURLParam: encodeURLParam,
addURLParams: function(url, params){
if( params && typeof params !== 'string' ){
params = encodeURIParams( params );
}
return params ? (url + (url.indexOf('?') < 0 ? '?' : url.charAt(url.length - 1) === '&' ? '' : '&') + params) : url;
}
});
/*---------------------------------------- jScaler 核心选择器对象成员 ----------------------------------------*/
extend(jscaler, {
now: now,
emit: emit,
// DOM 判断
isQuirks: isQuirks,
isQuirksMode: isQuirksMode,
isXML: isXML,
isXMLDoc: isXMLDoc,
isNative: isNative,
isWindow: isWindow,
getWindow: getWindow,
// DOM 方法
byId: byId,
byTag: byTag,
byName: byName,
byClass: byClass,
sibs: sibs,
first: first,
last: last,
children: children,
//parent: parent,
match: match,
getAttribute: getAttribute,
hasAttribute: hasAttribute,
HTMLResolvers: HTMLResolvers,
XMLResolvers: XMLResolvers,
concatNodes: concatNodes,
concatNodesCall: concatNodesCall,
// 编译选择器,创建解析函数
compile: compile,
// 配置帮助
configure: configure,
// 添加或重载用户定义算子
registerOperator: function(symbol, resolver) {
Operators[symbol] || (Operators[symbol] = resolver);
},
// 添加用户定义的回调选择
registerSelector: function(name, rexp, func) {
Selectors[name] || (Selectors[name] = {
Expression: rexp,
Callback: func
});
}
});
/*---------------------------------------- zCool DOM 方法扩展 ----------------------------------------*/
// 从核心选择器对象继承
$.extend(jscaler);
// 继承自本地变量
$.extend({
finalStyle: finalStyle,
hover:hover,
Event: Event,
addEvent: addEvent,
removeEvent: removeEvent,
removeEventOne: removeEventOne,
removeEventAll: removeEventAll,
cleanData: cleanData,
triggerEvent: triggerEvent,
trigger: trigger,
createNodes: createNodes,
createElement: createElement,
createFrag: createFrag,
coord: coord,
pageX: pageX,
pageY: pageY,
sortNodes: sortNodes,
contains: contains,
offsetParent: offsetParent,
find: jscaler,
globalEval: globalEval,
oEach: oEach,
noop: noop,
override: override,
extendClone: extendClone,
createObject: createObject,
isArray: isArray,
isPlainObject: isPlainObject,
isEmptyObject: isEmptyObject,
typeOf: typeOf,
eventSupport: eventSupport,
attrSupport: attrSupport,
encode: JSON.stringify,
decode: JSON.parse,
decodeXML: decodeXML,
encodeXML: encodeXML,
insert: insert,
error: error,
CSS_ID: 0,
CSS_INDEX: CSS_INDEX,
EVENT_PROPS: EVENT_PROPS,
REFERENCE_TYPE: REFERENCE_TYPE,
ONLY_ELEMENT: ONLY_ELEMENT,
NATIVE_SET_CAPTURE: NATIVE_SET_CAPTURE,
INPUT_CHOOSE_TYPE: INPUT_CHOOSE_TYPE,
NATIVE_ORSC: NATIVE_ORSC
});
// 样式类的方法集
$.extend({
// 生成匹配样式类的正则表达式
// @c String ClassName
// return RegExp
regClass: function(c){
return new RegExp('(?:^|\\s)(?:' + c.replace(rSpacesG, '|') + ')(?!\\S)', 'g');
},
// 检测是否包含指定的样式类
// @e DOM Element
// @c String ClassName
// @c RegExp ClassName
// @a Boolean - 是否包含所有样式类(当验证多个样式类时)
// return Boolean
hasClass: function(e, c, a){
var n = e.className, N, i, l, C;
if(n && (n = n.trim())){
// 若没有指定样式类
if( !c ){
return true;
}
// 若测试一个正则表达式
if( c.test ){
return c.test( n );
}
if(n === c){
return true;
}
N = n.replace(rSpacesrntfG, ' ');
// 若元素为单样式类
if( N.indexOf(' ') < 0 ){
return !a && c.indexOf(' ') > -1 && (' ' + c + ' ').indexOf(' ' + N + ' ') > -1;
}
// 若元素为多样式类
N = ' ' + N + ' ';
// 若测试单样式类
if( c.indexOf(' ') < 0 ){
return N.indexOf(' ' + c + ' ') > -1;
}
// 若测试多样式类
C = (' ' + c.replace(rSpacesG, ' , ') + ' ').split(','), l = c.length, i = -1;
if(a){
while( ++i < l ){
if( N.indexOf(C[i]) < 0 ){
return false;
}
}
return true;
}
while( ++i < l ){
if( N.indexOf(C[i]) > -1 ){
return true;
}
}
}
return false;
},
// 为元素增加指定的样式类
// @e DOM Element
// @c String ClassName
// return Boolean 返回结果表明是否实际添加了样式类
addClass: function(e, c){
var n = e.className, N, i, l, C;
// 若没有指定样式类
if( !c ){
return false;
}
// 已有样式类
if( n && (n = n.trim()) ){
if( n === c ){
return false;
}
N = C = ' ' + (n = n.replace(rSpacesrntfG, ' ')) + ' ';
// 添加单样式类
if( c.indexOf(' ') < 0 ){
if( C.indexOf((c = ' ' + c) + ' ') < 0 ){
e.className = n + c;
return true;
}
return false;
}
c = c.split(rSpaces);
i = -1;
l = c.length;
while( ++i < l ){
if( C.indexOf( ' ' + (n = c[i] + ' ') ) < 0 ){
C += n;
}
}
if( N === C ){
return false;
}
e.className = C.slice(1, -1);
return true;
}
// 无样式类
e.className = c;
return true;
},
// 为元素增加指定的样式类
// @e DOM Element
// @c String ClassName
// return Boolean 返回结果表明是否实际删除了样式类
removeClass: function(e, c){
var n = e.className, N;
// 已有样式类
if( n && (n = n.trim()) ){
// 若没有指定样式类
if( !c ){
if(n){
e.className = '';
return true;
}
return false;
}
// 若测试一个正则表达式
if( c.test ){
N = n.replace(c, '');
return N !== n && (e.className = N, true);
}
if( n !== c ){
// 若为多样式类
if( rSpace.test(n) ){
N = n.replace($.regClass(c), '');
return N !== n && (e.className = N, true);
}
if( c.indexOf(' ') < 0 || (' ' + c + ' ').indexOf(' ' + n + ' ') < 0 ){
return false;
}
}
e.className = '';
return true;
}
// 无样式类
return false;
},
// 为元素替换指定的样式类
// @e DOM Element
// @r String ClassName | RegExp
// @c String ClassName
// @d 指定在无匹配时也要添加样式类
// return Boolean 返回结果表明是否实际替换了样式类
replaceClass: function(e, r, c, d){
var n = e.className, N;
if( n && (n = n.trim()) ){
if( !r.test ){
if( n === r ){
return false;
}
r = $.regClass(r);
}
N = n.replace(r, '');
if( N === n ){
if( d ){
e.className = n + ' ' + c;
return true;
}
return false;
}
e.className = N + ' ' + c;
return true;
}
if( d ){
e.className = c;
return true;
}
return false;
},
// 为元素开关指定的样式类
// @e DOM Element
// @c String ClassName
// return Boolean 返回结果表明样式类的开关状态
toggleClass: function(e, c){
var n = e.className, N;
if( n && (n = n.trim()) ){
if( n === c ){
e.className = '';
return false;
}
if( (N = n.replace($.regClass(c), '')) === n ){
e.className = n + ' ' + c;
return true;
}
e.className = N;
return false;
}
e.className = c;
return true;
},
// 为元素交换指定的样式类
// @e DOM Element
// @c String ClassName
// @d String ClassName
// return String ClassName (r|c|'') 返回实际替换的样式类
// 返回空字符串表明没有找到任何样式类的匹配,没有做任何操作
swapClass: function(e, c, d){
var n = e.className, N;
if( n && (n = n.trim()) ){
if(n === c){
return e.className = d;
}
if(n === d){
return e.className = c;
}
N = n.replace($.regClass(c), '');
if(N === n){
N = n.replace($.regClass(d), '');
if(N === n){
return '';
}
e.className = N + ' ' + c;
return c;
}
e.className = N + ' ' + d;
return d;
}
return n;
}
});
// 系统信息、浏览器及版本号
(function(){
var n = window.navigator,
u = n.userAgent.toLowerCase(),
c = function(s){ return u.indexOf(s) > -1 },
v = parseFloat(/(?:.+rv|)[\/: ]([\d.]+)/.exec(u)[1]),
opera = c('opera'),
msie = !opera && c('msie'),
firefox = c('firefox'),
webkit = c('webkit'),
chrome = c('chrome'),
safari = !chrome && c('safari'),
mozzila = !webkit && c('mozzila') && !c('compatible');
$.extend({
isUtf: isUtf,
systemLanguage: n.systemLanguage || n.language,
opera : opera,
operaVersion : opera ? v : NaN,
msie : msie,
msieVersion : msie ? parseFloat(/msie ([\d.]+)/.exec(u)[1]) : NaN,
firefox : firefox,
firfoxVersion : firefox ? parseFloat(/firefox\/([\d.]+)/.exec(u)[1]) : NaN,
webkit : webkit,
webkitVersion : webkit ? v : NaN,
chrome : chrome,
safari : safari,
safariVersion : safari ? parseFloat(/[\d.]+(?= safari)/.exec(u)) : NaN,
mozzila : mozzila,
mozzilaVersion : mozzila ? v : NaN,
gecko : !webkit && c("gecko"),
windows : c("windows") || c("win32"),
mac : c("macintosh") || c("mac os x"),
air : c("adobeair"),
linux : c("linux")
});
})();
// 其他扩展成员
$.extend({
// 确保基础命名空间不冲突
noConflict: function( deep ) {
window.$ = _$;
deep && (window.zCool = _zCool);
return $;
},
// 创建(或获取)命名空间
ns : function(NS, name, ns){
NS || (NS = window);
if(typeof NS == 'string'){
ns = name;
name = NS;
NS = window;
}
if( !name ){
return ;
}
var names = name.split('.'), i = -1, l = names.length - 1;
// 获取
if(ns === undefined){
for(; ++i < l;){
if( !(NS = NS[ names[i] ]) ){
return ;
}
}
return NS[ names[l] ];
}
else{
for(; ++i < l;){
NS = NS[ names[i] ] || (NS[ names[i] ] = {});
}
if( NS[ names[l] ] ){
return extend(true, NS[ names[l] ], ns);
}
else{
return NS[ names[l] ] = ns;
}
}
},
// 导入外部文件,参数为文件的相对或绝对路径
// 若参数包含一个回调函数,则等待导入的文件加载完成后执行
// urls为一个路径的字符串、外链标签的属性集(或是由它们组成的数组)
imports: imports,
// 继承
// @subClass function
// @superClass function
inherits : function(subClass, superClass){
if( !superClass ){
superClass = subClass;
subClass = this;
}
var spp = subClass.superclass = superClass.prototype;
(subClass.prototype = extendClone(spp)).constructor = subClass;
if(spp.constructor === constructor){
spp.constructor = superClass;
}
return subClass;
},
// 以下几个函数通常都作为独立的事件函数注册
// 阻止事件默认行为
preventDefault : function(e){
e.preventDefault();
},
// 取消事件冒泡
stopPropagation : function(e){
e.stopPropagation();
},
// 返回false,阻止事件队列的后续执行
returnFalse : function(){
return false;
},
// 事件函数绑定一个对象
bindEventHandle : function(f){
var o = this,
a = arguments.length > 1 && slice.call(arguments, 1),
F = function(e){
if(a){
return f.apply(o, [e].concat(a));
}
return f.call(o, e);
};
F.boundHandle = f;
F.boundTarget = o;
return F;
}
});
/*---------------------------------------- DOM expando 清理(IE) ----------------------------------------*/
// IE8- DOM对象对javascript对象引用,引起内存泄漏
NATIVE_AEL || window.attachEvent("onunload", function() {
var id, el;
for ( id in Cache ) {
if ( el = Cache[ id ].element ) {
// 捕获 iframes unloaded 异常
try {
cleanData( el );
} catch(e) {}
}
}
});
//---------------------------------------- zCool 对象原型扩展 ----------------------------------------//
// 将zCool原型的init方法的原型设为zCool原型
(init.prototype = $.fn).extend({
init: init,
zcool: zcool,
// 缺省长度为 0
length: 0,
// 初始为空字符选择器
selector: '',
// 查询后代元素 -> 返回集合(生成新的对象)
find: function(selector, callback){
var z = $(), h = {};
this.forEach(function(context){
uniqNodes(jscaler(selector, context), z, h, callback)
});
z.selector = this.selector + (rLeftContext.test(selector) ? '' : ' ') + selector;
z.context = this.context;
return z;
},
// transform return array
toArray: function(){
return slice.call(this);
},
// 排序 -> 返回集合(原对象)
sort: function(fn){
return sort.call(this, typeof fn == 'function' ? fn : sortNodes);
},
// slice出zCool集合
// @start number
// @end number
slice: function(start/*, end*/){
var l = arguments.length, z = $();
z.context = this.context;
z.selector = this.selector + ':slice('+ slice.call(arguments).join(',') +')';
push.apply(z, slice.apply(this, arguments));
return z;
},
// 将两个集合连接生成一个新的zCool集合
// @a number 集合
concat: function(a){
var z = $();
$.concatNodes(z, this);
$.concatNodes(z, a);
return z;
},
// 过滤数组中的元素
// @selector string 用 match 函数过滤
// @selector function 用数组原型方法 filter 过滤
filter: function(selector, scope, callback){
var z = $(), a;
z.context = this.context;
z.selector = this.selector;
if( typeof selector === 'string' ){
a = filter.call(this, function(e){ return match(e, selector, scope, callback) });
z.selector += ':match(' + selector + ')';
}
else{
a = filter.call(this, selector, scope);
}
a.length && push.apply(z, a);
return z;
},
first: function() {
return this.eq( 0 );
},
last: function() {
return this.eq( -1 );
},
eq: function( i ) {
var l = this.length, j = +i + ( i < 0 ? l : 0 );
return j >= 0 && j < l ? $( this[j] ) : $();
},
// 过滤数组中的元素
// @selector string 用 match 函数过滤
// @selector function 用数组原型方法 filter 过滤
not: function(selector, scope, callback){
var z = $(), a;
z.context = this.context;
z.selector = this.selector;
if( typeof selector === 'string' ){
a = not.call(this, function(e){ return match(e, selector, scope, callback) });
z.selector += ':not(' + selector + ')';
}
else{
a = not.call(this, selector, scope);
}
a.length && push.apply(z, a);
return z;
},
// map出zCool集合, 确保每次map call返回DOMElement
map: function(fn, scope){
var z = [], L = 0;
this.forEach(function(e, i, t){
(e = fn.call(scope, e, i, t)) && (z[L++] = e);
});
z = uniqNodes(z, $(), {});
z.selector = this.selector;
z.context = this.context;
return z;
},
// 去重复 -> 返回集合(生成新的对象)
uniq: function(){
var z = uniqNodes(this, $(), {});
z.selector = this.selector;
z.context = this.context;
return z;
},
// 去重复并排序 -> 返回集合(生成新的对象)
uniqSort: function(fn){
return sort.call(this.uniq(), typeof fn != 'function' ? sortNodes : fn);
},
params: function(){
return map.call(this, function(el){
return encodeURIParams(el);
}).join('&');
},
// 生成文档碎片
toFrag: function(){
var l = this.length, i = -1, frag = DOC.createDocumentFragment();
while(++i < l){
frag.appendChild(this[i]);
}
try{ return frag } finally{ frag = null }
},
// 文档 DOM 加载
DOMReady: function( fn ) {
// 若 DOM 已加载完成
if ( DOM_LOADED ) {
// 直接执行
fn.call( DOC, $ );
}
else if ( DOM_LOADED_HANDLERS ) {
// 加入等待触发队列
DOM_LOADED_HANDLERS.push( fn );
}
// 绑定 DOM 加载事件
bindDOMReady();
return this;
},
// 返回或写入元素属性值
attr: function(name, value, scope){
if(name && this.length){
switch(typeof name){
case 'string':
if(value !== undefined){
switch(typeof value){
case 'string':
return this.each(function(el){
el[name] !== undefined ? (el[name] = value) : el.setAttribute(name, value);
});
case 'function':
return this.each(function(el){
var v = value.apply(scope, arguments)
el[name] !== undefined ? (el[name] = v) : el.setAttribute(name, v);
});
default:
return this.each(function(el){
el[name] = value;
});
}
}
return (value = this[0][name]) !== undefined ? value : getAttribute(this[0], name);
case 'object':
return this.each(function(el){
for(var k in name){
$(el).attr(k, name[k], value);
}
});
default:
return this;
}
}
return this;
},
// @e DOM node | html string
// @m string 插入方法名
insert: function(e, m){
var l = this.length, i, frag, clone;
if(e && l && m){
frag = e.nodeType ? e : createFrag($(e));
if( l < 2 ){
insert(this[0], frag, m);
}
else{
clone = frag.cloneNode(true);
insert(this[i = 0], frag, m);
l--;
while(++i < l){
insert(this[i], clone.cloneNode(true), m);
}
insert(this[i], clone, m);
}
}
return frag = clone = this;
},
// @e DOM node 被插入的节点
// @m string 插入方法名
insertTo: function(e, m){
var l = this.length;
l && $(e).insert(l < 2 ? this[0] : this, m);
return this;
},
// 触发事件或注册事件
// @type string event type
// @fn function
// @data json object
on : function(type, fn, data){
var types = type.split( rSpaces );
types.length < 2 && (types = null);
// 注册事件
if( typeof fn == 'function' ){
return this.each( types
? function(e){
types.forEach(function(type){
addEvent(e, type, fn, data)
});
}
: function(e){ addEvent(e, type, fn, data) } );
}
// 否则手动触对象的发事件侦听器
else{
return types
? this.each(function(e){
types.forEach(function(type){
triggerEvent(e, type);
});
})
: this.triggerEvent(type);
}
},
// 删除事件
// @type string event type
// @fn function
// @data boolean|function (to remove cache data)
no : function(type, fn, data){
var l = arguments.length, types;
if( type ){
types = type.split( rSpaces );
types.length < 2 && (types = null);
return this.each( types ? fn
// 若指定了事件函数,删除该句柄
? function(e){
types.forEach(function(type){
removeEvent(e, type, fn, data);
});
}
// 否则,删除该事件队列
: function(e){
types.forEach(function(type){
removeEventOne(e, type, data);
});
}
: fn
? function(e){ removeEvent(e, type, fn, data) }
: function(e){ removeEventOne(e, type, data) } );
}
// 若无参数,删除所有事件
else{
return this.each( function(e){ removeEventAll(e, data) } );
}
},
// 手动触发DOM对象的事件
triggerEvent : function(type){
return this.each(function(el){
triggerEvent(el, type);
});
},
// 手动触发对象的事件侦听器
// @type string
// @args array
trigger : function(type, args){
return this.each(function(el){
trigger(el, type, args);
});
},
// 从DOM中删除所有匹配的元素
// @selector string | @keepData
// @keepData boolean
remove:function(selector, keepData){
return typeof selector === 'string' ?
this.find(selector).remove(keepData) :
this.each(function(e){
remove(e, selector);
});
},
// remove all child nodes
empty: function(){
return this.each(function(e){
$.find('*', e, cleanData);
while(e.firstChild){
e.removeChild(e.firstChild);
}
});
},
// @all 同时清除所有后代元素的Data
cleanData: function(all){
return this.each(function(e){
cleanData(e, all);
});
},
clone: function(deep, dataAndEvents, deepDataAndEvents){
deep == null && (deep = false);
dataAndEvents == null && (dataAndEvents = false);
deepDataAndEvents = deep && (deepDataAndEvents == null ? false : deepDataAndEvents);
return this.map( function (el) {
return el.cloneNode(deep);
//return clone( el, deep, dataAndEvents, deepDataAndEvents );
});
},
// 获取元素索引
// @selector string | element collection
index: function(selector, context){
var e = this[0], i;
return e ? selector ?
selector.indexOf ? selector.indexOf(e) :
typeof selector === 'function' ?
(selector = selector.call(context, e)) && selector.indexOf ?
selector.indexOf(e) :
$(selector).indexOf(e) :
$(selector, context).indexOf(e) :
(i = INDEX_NAME[e.tagName]) ? e[i] : children(e.parentNode).indexOf(e) : -1;
},
//
offsetParent: function() {
return this.map(offsetParent);
},
window: new Function('W,D',
'return function(){' +
'return this.map(function(e){' +
'return (e=e.ownerDocument||e)===D?W:e.' + (DEFAULT_VIEW ? 'defaultView' : 'parentWindow') +
'});' +
'}')(window, DOC),
// 返回或写入元素内联样式
css: (function(){
var s = 'var f = this[0];if(f){switch(typeof s){case "string":' +
'if(s==false){return this.each(function(e){' + (CSS_TEXT ? 'e.style.cssText=""' : 'e.setAttribute("style","")') + '})}' +
'if(s.indexOf(":")<0){s=="float"&&(s="' +
(CSS_FLOAT ? 'css' : 'style') +
'Float");if(typeof v=="string"){' +
(CSS_OPACITY ? '' : 'if(s=="opacity"){s="filter";if(v){if(v=="inherit"){v="normal"}else{var V;typeof(V=parseFloat(v))=="number"&&(v="alpha(opacity:"+V*100+")")}}}') +
'return this.each(function(e){e.style[s]=v})}' +
(CSS_OPACITY ? '' : 'if(s=="opacity"){return (v=f.style.filter)===undefined?"":R.test(v)?RegExp.$1:"inherit"}') +
'return f.style[s]}' +
(CSS_OPACITY ? '' : 's=s.replace(r,F);') +
'return this.each(function(e){' +
(CSS_TEXT ? 'e.style.cssText=s' : 'e.setAttribute("style",s)') +
'});case "object":if(s){' +
'if("float" in s){s.' + (CSS_FLOAT ? 'css' : 'style') + 'Float=s["float"];delete s["float"]}' +
(CSS_OPACITY ? '' : 'if("opacity" in s){s.filter="alpha(opacity:"+parseFloat(s.opacity)*100+")";delete s.opacity}') +
'return this.each(function(e){var c = e.style, k; for(k in s)c[k]=s[k]})}}return ' +
(CSS_TEXT ? 'f.style.cssText' : 'f.getAttribute("style",s)') +
'}return this';
return CSS_OPACITY ? new Function('s,v', s) :
new Function('r,F,R', 'return function(s,v){' + s + '}')(/opacity\s*:\s*(\d+(?:\.\d+)?|\.\d+)\s*(?=;|$)/g,
function(m, $1){ return 'filter:alpha(opacity:' + parseFloat($1)*100 + ')' },
/opacity\s*[:=]\s*(\d+(?:\.\d+)?|\.\d+)/);
})(),
// 显示/隐藏元素
toggle: function( d ){
var l = this.length, i = -1, e, s;
d || (d = { block: 'none', none: 'block' });
while( ++i < l ){
(s = (e = this[i]).style).display = d[ s.display ] || d[ $.finalStyle(e, 'display') ];
}
},
// 检测是否包含指定的样式类
// @c null||undefined||''
// @c String ClassName
// @c Function to call DOM Element return String ClassName
// @a Boolean - 是否判断所有元素
// @A Boolean - 是否判断所有样式类(当验证多个样式类时)
// return Boolean
hasClass: function(c, a, A){
var l = this.length, i = -1, e, n, N, C, r, I, L, d;
// 若未声明检测的样式类
if( !c ){
if( l < 2 ){
// 注意这里的写法:
// zCool认为空集合判断无意义,无论返回何值,通常都会违背了程序的原意图
// 所以若为空集合时,确保抛出异常中断!下同
return !!((n = this[0].className) && n.trim());
}
// 检测所有元素
if( a ){
while( ++i < l ){
if( !((n = this[i].className) && n.trim()) ){
return false;
}
}
return true;
}
// 检测有一个元素
while( ++i < l ){
if( (n = this[i].className) && n.trim() ){
return true;
}
}
return false;
}
// 检测参数类型 String|Function|RegExp
n = typeOf( c );
if( l < 2 ){
return $.hasClass(e = this[0], n !== 'Function' ? c : c.call(arguments[3], e, 0, this), A);
}
switch(n){
// 若参数为样式类
case 'String':
d = c.indexOf(' ') > -1;
C = ' ' + c + ' ';
// 检测所有元素
if( a ){
outer: while( ++i < l ){
n = (e = this[i]).className;
// 若元素已有样式类
if( n && (n = n.trim()) ){
if( n === c ){
continue;
}
n = n.replace(rSpacesrntfG, ' ');
// 若元素为单样式类
if( n.indexOf(' ') < 0 ){
if( (A ? d : !d) || C.indexOf(' ' + n + ' ') < 0 ){
return false;
}
continue;
}
// 若元素为多样式类
N = ' ' + n + ' ';
if( d ){
r || (r = (' ' + c.replace(rSpacesG, ' , ') + ' ').split(','), L = r.length);
I = -1;
// 若判断包含多样式类的全部
if( A ){
while( ++I < L ){
if( N.indexOf( r[I] ) < 0 ){
return false;
}
}
continue;
}
// 若判断包含多样式类的某一个
while( ++I < L ){
if( N.indexOf( r[I] ) > -1 ){
continue outer;
}
}
return false;
}
if( N.indexOf( C ) > -1 ){
continue;
}
}
return false;
}
return true;
}
// 检测有一个元素
outer: while( ++i < l ){
n = (e = this[i]).className;
// 若元素已有样式类
if( n && (n = n.trim()) ){
if( n === c ){
return true;
}
n = n.replace(rSpacesrntfG, ' ');
// 若元素为单样式类
if( n.indexOf(' ') < 0 ){
if( (A ? d : !d) || C.indexOf(' ' + n + ' ') < 0 ){
continue;
}
return true;
}
// 若元素为多样式类
N = ' ' + n + ' ';
if( d ){
r || (r = (' ' + c.replace(rSpacesG, ' , ') + ' ').split(','), L = r.length);
I = -1;
// 若判断包含多样式类的全部
if( A ){
while( ++I < L ){
if( N.indexOf( r[I] ) < 0 ){
continue outer;
}
}
return true;
}
// 若判断包含多样式类的某一个
while( ++I < L ){
if( N.indexOf( r[I] ) > -1 ){
return true;
}
}
continue;
}
if( N.indexOf( C ) > -1 ){
return true;
}
}
}
return false;
// 若测试一个表达式
case 'RegExp':
// 检测所有元素
if( a ){
while( ++i < l ){
n = (e = this[i]).className;
// 若元素已有样式类
if( !(n && (n = n.trim()) && c.test(n)) ){
return false;
}
}
return true;
}
// 检测有一个元素
while( ++i < l ){
n = (e = this[i]).className;
// 若元素已有样式类
if( n && (n = n.trim()) && c.test(n) ){
return true;
}
}
return false;
// 若参数为函数call
case 'Function':
n = arguments[3];
// 检测所有元素
if( a ){
while( ++i < l ){
if( !$.hasClass(e = this[i], c.call(n, e, i, this), A) ){
return false;
}
}
return true;
}
// 检测有一个元素
while( ++i < l ){
if( $.hasClass(e = this[i], c.call(n, e, i, this), A) ){
return true;
}
}
return false;
}
return false;
},
// 为元素增加指定的样式类
// @c String ClassName
// @c Function to call DOM Element return String ClassName
// return this 返回原集合
addClass: function(c){
var l = this.length, i = -1, e, n, N, C, r, I, L, d;
if( l < 1 || !c ){
return this;
}
// 检测参数为字符串(样式类或函数)
n = typeof c === 'string';
if( l < 2 ){
$.addClass(e = this[0], n ? c : c.call(arguments[1], e, 0, this));
return this;
}
// 若参数为样式类
if( n ){
if( r = c.indexOf(' ') > -1 && c.split(rSpaces) ){
L = r.length;
}
while( ++i < l ){
n = (e = this[i]).className;
// 已有样式类
if( n && (n = n.trim()) ){
if( n === c ){
continue;
}
N = C = ' ' + (n = n.replace(rSpacesrntfG, ' ')) + ' ';
// 添加多样式类
if( r ){
I = -1;
while( ++I < L ){
if( C.indexOf( ' ' + (d = c[I] + ' ') ) < 0 ){
C += d;
}
}
if( N !== C ){
e.className = C.slice(1, -1);
}
continue;
}
// 添加单样式类
if( C.indexOf((d = ' ' + c) + ' ') < 0 ){
e.className = n + d;
}
continue;
}
e.className = c;
}
return this;
}
// 若参数为函数call
n = arguments[1];
while( ++i < l ){
$.addClass(e = this[i], c.call(n, e, i, this));
}
return this;
},
// 为元素删除指定的样式类
// @c null||undefined||''
// @c String ClassName
// @c Function to call DOM Element return String ClassName
// return this
removeClass: function(c){
var l = this.length, i = -1, e, n, N, C, r;
if( l < 1 ){
return this;
}
// 若未声明检测的样式类,将元素样式清空
if( !c ){
while( ++i < l ){
(e = this[i]).className && (e.className = '');
}
return this;
}
// 检测参数类型 String|Function|RegExp
n = typeOf( c );
if( l < 2 ){
$.removeClass(e = this[0], n !== 'Function' ? c : c.call(arguments[1], e, 0, this));
return this;
}
switch(n){
// 若参数为样式类
case 'String':
C = c.indexOf(' ') > -1 && (' ' + c + ' ');
while( ++i < l ){
n = (e = this[i]).className;
// 若元素已有样式类
if( n && (n = n.trim()) ){
if( n === c ){
e.className = '';
continue;
}
// 若元素为多样式类
if( rSpace.test(n) ){
N = n.replace( r || (r = $.regClass(c)), '');
if( N !== n ){
e.className = N;
}
continue;
}
// 若元素为单样式类
if( C && C.indexOf(' ' + n + ' ') > -1 ){
e.className = '';
}
}
}
return this;
// 若测试一个表达式
case 'RegExp':
while( ++i < l ){
n = (e = this[i]).className;
// 若元素已有样式类
if( n && (n = n.trim()) ){
if( (N = n.replace(c, '')) !== n ){
e.className = N;
}
}
}
return this;
// 若参数为函数call
case 'Function':
n = arguments[1];
while( ++i < l ){
$.removeClass(e = this[i], c.call(n, e, i, this));
}
return this;
}
return this;
},
// 为元素开关指定的样式类
// @c String ClassName
// return this
toggleClass: function(c){
var l = this.length, i, e, n, N, C, r;
if( l < 1 ){
return this;
}
if( l < 2 ){
$.toggleClass( this[0], c );
return this;
}
i = -1;
C = ' ' + c;
while( ++i < l ){
(e = this[i]).className = (n = e.className) && (n = n.trim())
? n === c
? ''
: (N = n.replace(r || (r = $.regClass(c)), '')) === n
? (n + C)
: N
: c;
}
return this;
},
// 为元素替换指定的样式类
// @r String ClassName | RegExp | Function
// @c String ClassName | Function
// @d 指定在无匹配时也要添加样式类
// return this
replaceClass: function(r, c, d){
var l = this.length, i = -1, e, n, N, C, R, a;
if( l < 1 ){
return this;
}
// 检测参数类型 String|Function|RegExp
n = typeOf( r ), a = arguments[3], b = arguments[4] || a;
if( l < 2 ){
$.replaceClass( e = this[0],
n !== 'Function' ? r : r.call(a, e, 0, this),
c.call ? c.call(b, e, 0, this) : c,
d );
return this;
}
switch(n){
// 若参数为样式类
case 'String':
if( c.call ){
while( ++i < l ){
$.replaceClass(e = this[i], r, c.call(b, e, i, this), d);
}
}
else{
C = ' ' + c;
while( ++i < l ){
(n = (e = this[i]).className) && (n = n.trim())
? n === c ||
( n === r
? (e.className = c)
: (N = n.replace(R || (R = $.regClass(r)), '')) === n
? d && (e.className = n + C)
: (e.className = N + C)
)
: d && (e.className = c);
}
}
return this;
// 若测试一个表达式
case 'RegExp':
if( c.call ){
while( ++i < l ){
$.replaceClass(e = this[i], r, c.call(b, e, i, this), d);
}
}
else{
C = ' ' + c;
while( ++i < l ){
(n = (e = this[i]).className) && (n = n.trim())
? n === c ||
( (N = n.replace(r, '')) === n
? d && (e.className = n + C)
: (e.className = N + C)
)
: d && (e.className = c);
}
}
return this;
// 若参数为函数call
case 'Function':
if( c.call ){
while( ++i < l ){
$.replaceClass(e = this[i], r.call(a, e, i, this), c.call(b, e, i, this), d);
}
}
else{
while( ++i < l ){
$.replaceClass(e = this[i], r.call(a, e, i, this), c, d);
}
}
return this;
}
return this;
},
// 为元素交换指定的样式类
// @c String ClassName
// @d String ClassName
// return this
swapClass: function(c, d){
var l = this.length, i, e, n, N, C, r, R, D;
if( l < 1 ){
return this;
}
if( l < 2 ){
$.swapClass( this[0], r, c );
return this;
}
i = -1;
C = ' ' + c;
D = ' ' + d;
while( ++i < l ){
(n = (e = this[i]).className) && (n = n.trim()) &&
( n === r
? (e.className = c)
: n === c
? (e.className = r)
: (N = n.replace(r || (r = $.regClass(c)), '')) === n
? (N = n.replace(R || (R = $.regClass(d)), '')) === n
|| (e.className = n + C)
: (e.className = n + D)
);
}
return this;
},
// 模拟伪类 :hover,mouseenter & mouseleave
hover: function(c){
if( typeof c === 'function' ){
return this.
on('mouseenter', c).
on('mouseleave', arguments[1] || c);
}
c || (c = '-hover');
this.each(function(e){
var h = $.data(e, 'hoverClass');
h = h ? h + ' ' + c : c;
$.data(e, 'hoverClass', h);
});
return this.
on('mouseenter', hover).
on('mouseleave', hover);
}
});
// 模拟伪类 :hover 注册的事件函数
function hover(e){
var h = $.data(this, 'hoverClass');
h && $[ e.type === 'mouseeneter' ? 'addClass' : 'removeClass' ]( h );
};
// 获取HTML文档中的body元素
$(function(){ BODY || (BODY = ONLY_ELEMENT.body = ONLY_ELEMENT.BODY = DOC.body) });
(function(f){
$.fn.extend({
// 父元素(不包括文档和文档碎片节点,下同)
parent: f(),
// 所有直系先辈元素
ancestorAll: f(1),
// 自身和所有直系先辈元素
iancestorAll: f(1, 1),
// 直系先辈元素中,最近的一个
ancestor: f(1, 0, 1),
// 自身和直系先辈元素,最近的一个
iancestor: f(1, 1, 1)
});
})(function(A, I, C){
var p = PARENT_ELEMENT ? '.parentElement' : '.parentNode,e&&e.nodeType!==1&&(e=null)',
w = 'while(e&&e!==r)',
a =
'o:while(++i<l){' +
'e=this[i]' + (I ? '' : p) + ';' +
(A ? I ? 'do' : w : 'if(e)') + '{' +
'k=e[$.CSS_INDEX]||(e[$.CSS_INDEX]=++$.CSS_ID);' +
'if(!h[k]){' +
'h[k]=1;',
b = 'z[L++]=e;' + (C ? 'continue o;' : ''),
B = '{' + b + '}',
c = '}' + (A ? 'e=e' + p + '}' + (I ? w : '') : '}') + '}z.length=L;return z;';
return new Function('$,m', 'return function(s,t,r){' +
'var l=this.length,i=-1,e,p,z=$(),L=0,h={},k;' +
'if(l<1)return z;' +
'switch(typeof s){' +
'case "string":' +
a + 'if(m(e,s,t))' + B + c +
'case "function":r||(r=t);' +
a + 'if((p=s.call(t,e,this[i],i,this)))' + B + 'else if(p===null){continue o;}' + c +
'default:' +
a + b + c +
'}' +
'}')($, match);
});
// scrollLeft && scrollTop methods
['Top', 'Left'].each(function(p){
var m = 'scroll' + p,
w = 'e===D?W:e.' + (DEFAULT_VIEW ? 'defaultView' : 'parentWindow'),
W = 'return e.scrollTo(' + (m==="scrollTop" ? '$(e).scrollLeft(),v' : 'v,$(e).scrollTop()') + ');',
d = '&&e.documentElement.' + m + '||e.body.' + m,
s = WINDOW_SCROLL[m];
$.fn[ m ] = new Function('W,$,D,R,Q,q,undefined',
'return function(v){' +
'var e=this[0];' +
'if(e){' +
'if(v!==undefined){' +
'return this.each(function(e){' +
'switch(e.nodeType){' +
'case 1:return e.' + m + '=v;' +
'case 9:e=' + w + ';' + W +
'default:' + W +
'}' +
'})' +
'}' +
'switch(e.nodeType){' +
'case 1:return e.' + m + ';' +
'case 9:return ' + (PAGE_OFFSET ? '(' + w + ').' + s : ('e===D?!Q&&R.' + m + '||e.body.' + m + ':!q(e)' + d)) + ';' +
'default:return ' + (PAGE_OFFSET ? 'e.' + s : 'e===W?!Q&&R.' + m + '||D.body.' + m + ':!q(e=e.document)' + d) + ';' +
'}' +
'}' +
'return null;' +
'}'
)(window, $, DOC, ROOT, isQuirksMode, isQuirks);
});
// ecma5 bind
isNative('bind', FP) ||
(FP.bind = function(o/*, arg1, arg2,...*/){
var f = this, a = arguments.length > 1 && slice.call(arguments, 1);
return function(){
var A = arguments.length && arguments;
return a ? f.apply(o, A ? push.apply(a, A) : a) : A ? f.apply(o, A) : f.call(o);
}
});
/*---------------------------------------- 扩展 zCool 原型 ----------------------------------------*/
// 从数组原型继承方法
// slice map filter 需要单独处理,忽略
'push pop shift unshift reverse indexOf lastIndexOf forEach every some each someIndexOf someLastIndexOf splice'.
split(' ').each(function(name){
$.fn[name] = AP[name]
});
(function(){
var b = 'return function(M,t){' +
'var z=$(),l=0,h={};' +
'f.call(this, function(e){',
a = '});' +
'z.length=l;' +
'z.context=this.context;' +
'z.selector=this.selector+":"+n;' +
'return z;' +
'}',
i = '[$.CSS_INDEX]||(e[$.CSS_INDEX]=++$.CSS_ID)',
h = '||(h[I]=z[l++]=e);';
// 获取关联单节点 返回新集合
'prev next first last'.split(' ').each(function(name){
$.fn[name] = new Function('$,m,n,f',
b +
'if(e=m(e,M,t)){' +
'var I=e' + i + ';' +
'h[I]' + h +
'}' +
a)($, $[name], name, forEach);
});
// 获取关联多节点 返回新集合
'prevAll nextAll sibs children'.split(' ').each(function(name){
$.fn[name] = new Function('$,m,n,f',
b +
'var L,i=-1,E,I;' +
'if((L=(E=m(e,M,t)).length)>0){' +
'while(++i<L){' +
'h[I=(e=E[i])' + i + ']' + h +
'}' +
'}' +
a)($, $[name], name, forEach);
});
})();
// 节点操作
'append prepend before after replace'.split(' ').each(function(m){
var b = 'return this.insert', a = '(e,"' + m + '")';
$.fn[m] = new Function('e', b + a);
$.fn[m + 'To'] = new Function('e', b + 'To' + a);
});
// 赋值/取值/操作
'html text val'.split(' ').each(function(attr, i){
$.fn[attr] = new Function('v,s', 'return this.attr("' + this[i] + '",v,s)');
},[
'innerHTML'
,TEXT_CONTENT ? 'textContent' : 'innerText'
,'value'
]);
// 取值
'coord pageX pageY'.split(' ').each(function(name){
$.fn[name] = function(){
return $[name](this[0]);
};
});
// 常用事件操作
$.EVENT_TYPES = ('mouseenter mouseleave mouseover mouseout mousemove mousedown mouseup click dblclick ' +
'focus blur focusin focusout change select submit keydown keypress keyup ' +
'resize scroll load unload error selectstart').split(' ').each(function(t){
var s = 'return this.on("' + t + '",f,d);';
$.fn[t] = new Function('f,d', s);
$.fn['no' + t.capitalize()] = new Function('f,d', s.replace('on', 'no'));
});
/*---------------------------------------- 操作 cookie ----------------------------------------*/
// 设置/获取 cookie
// @name string
$.cookie = function(name, value, opts) {
// 若name为非字符串类型
if(typeof name !== 'string'){
var cookies = {}, a = DOC.cookie.trim().split(/;\s*/);
// 返回cookie的json对象表示
if(name){
a.each(function(n){
var i = n.indexOf('=');
i < 0 && (i = n.length);
cookies[ n.slice(0, i) ] = decodeURIComponent(n.slice(i + 1));
});
return cookies;
}
// 清空所有cookie,并返回空串
else{
a.each(function(n){
var i = n.indexOf('=');
i < 0 && (i = n.length)
$.cookie(n.slice(0, i), null);
});
return DOC.cookie;
}
}
// 若指定name,且未定义value,获取相应的cookie
if( value === undefined ) {
return new RegExp('(?:^|;\\s*)' + name + '=?([^;]*)').test( DOC.cookie ) ?
decodeURIComponent(RegExp.$1) : null;
}
// 否则,设置cookie
opts || (opts = {});
if(typeof value != 'string'){
value = '';
opts.expires = -1;
}
var expires = opts.expires || '', date;
// 若设置了cookie期限
if (expires) {
// 定义数字
if (typeof expires == 'number') {
date = new Date();
date.setTime(date.getTime() + (expires * 24 * 60 * 60 * 1000));
}
// 定义日期对象
else if(toString.call(expires) == '[object Date]'){
date = expires;
}
}
// 设置相应的cookie,并返回当前设置的详细结果
return DOC.cookie = [
name + '=' + encodeURIComponent(value)
,date ? '; expires=' + date.toUTCString() : '' // IE不支持expires的max-age属性
,opts.path ? '; path=' + opts.path : ''
,opts.domain ? '; domain=' + opts.domain : ''
,opts.secure ? '; secure' : ''
].join('');
};
/*---------------------------------------- 全局对象定义 ----------------------------------------*/
// 将核心对象设置为全局对象成员
window.$ = window.zCool = $;
// 定义全局的JSON对象
NATIVE_JSON || (window.JSON = JSON);
})(this);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment