博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

jquery core 源码分析

Posted on 2008-12-04 11:20  linFen  阅读(2633)  评论(0编辑  收藏  举报
  1. **  
  2.  * author:prk  
  3.  * date:2008-08-05  
  4.  * comment:analeyse the core of jquery1.2.6  
  5.  *     
  6.  */  
  7.   
  8. /*  
  9.  * jQuery  
  10.  *   
  11.  * @VERSION - New Wave Javascript  
  12.  *   
  13.  * Copyright (c) 2008 John Resig (jquery.com) Dual licensed under the MIT  
  14.  * (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.  
  15.  *   
  16.  * $Date: 2008-07-24 01:00:32 +0800 (Thu, 24 Jul 2008) $ $Rev: 5793 $  
  17.  */  
  18.   
  19. // Map over jQuery in case of overwrite   
  20. var _jQuery = window.jQuery,   
  21. // Map over the $ in case of overwriteff   
  22. _$ = window.$;   
  23.   
  24. var jQuery = window.jQuery = window.$ = function(selector, context) {   
  25.     // The jQuery object is actually just the init constructor 'enhanced'   
  26.     return new jQuery.fn.init(selector, context);   
  27. };   
  28.   
  29. // A simple way to check for HTML strings or ID strings   
  30. // (both of which we optimize for)   
  31. var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,   
  32.   
  33. // Is it a simple selector   
  34. isSimple = /^.[^:#\[\.]*$/,   
  35.   
  36. // Will speed up references to undefined, and allows munging its name.   
  37. undefined;   
  38.   
  39. jQuery.fn = jQuery.prototype = {   
  40.     init : function(selector, context) {   
  41.         selector = selector || document;// 确定selector存在   
  42.   
  43.         // 第一种情况 Handle $(DOMElement)单个Dom 元素,忽略上下文   
  44.         if (selector.nodeType) {   
  45.             this[0] = selector;   
  46.             this.length = 1;   
  47.             return this;   
  48.         }          
  49.         if (typeof selector == "string") {//selector为string   
  50.             // Are we dealing with HTML string or an ID?   
  51.             var match = quickExpr.exec(selector);   
  52.             // Verify a match, and that no context was specified for #id   
  53.             if (match && (match[1] || !context)) {   
  54.                 if (match[1])// 第二种情况处理$(html) -> $(array)   
  55.                     selector = jQuery.clean([match[1]], context);   
  56.                 else {// 第三种情况:HANDLE: $("#id")//处理$("#id")   
  57.                     var elem = document.getElementById(match[3]);   
  58.   
  59.                     // Make sure an element was located   
  60.                     if (elem) {   
  61.                         // Handle the case where IE and Opera return items   
  62.                         // by name instead of ID   
  63.                         if (elem.id != match[3])   
  64.                             return jQuery().find(selector);// 默认是document.find()   
  65.   
  66.                         // Otherwise, we inject the element directly into the   
  67.                         // jQuery object   
  68.                         return jQuery(elem);   
  69.                     }   
  70.                     selector = [];   
  71.                 }   
  72.             } else  
  73.                 // 第四种情况:处理$(expr, [context])==$(content).find(expr)   
  74.                 return jQuery(context).find(selector);   
  75.         } else if (jQuery.isFunction(selector))   
  76.             // 第五种情况:处理$(function)七Shortcut for document ready   
  77.             return jQuery(document)[jQuery.fn.ready ? "ready" : "load"](selector);   
  78.   
  79.         // 第六种情况:处理$(elements)   
  80.         return this.setArray(jQuery.makeArray(selector));   
  81.     },   
  82.   
  83.     // 当前的版本号   
  84.     jquery : "@VERSION",   
  85.   
  86.     // jquery对象中的元素的个数。jquery像数组。能通过$('p')[0]去取得Dom对象。   
  87.     size : function() {   
  88.         return this.length;   
  89.     },   
  90.     // jquery对象的元素的个数   
  91.     length : 0,   
  92.   
  93.     // 取到本jquery对象的第几个Dom元素,无参数,代表全部的Dom元素   
  94.     get : function(num) {   
  95.         return num == undefined ? jQuery.makeArray(this) : this[num];   
  96.     },   
  97.   
  98.     // 采用jQuery构建新对象,同时引用老对象。   
  99.     pushStack : function(elems) {   
  100.         var ret = jQuery(elems);// 构建新的jquery对象   
  101.         ret.prevObject = this;// 保存老的对象的引用   
  102.         return ret;   
  103.     },   
  104.   
  105.     // 把array-like对象的元素全部push当前jquery对象。   
  106.     setArray : function(elems) {   
  107.         this.length = 0;   
  108.         Array.prototype.push.apply(this, elems);   
  109.         return this;   
  110.     },   
  111.   
  112.     // 当前jquery对象中每个元素都执行callback(index,elem)函数   
  113.     each : function(callback, args) {// 返回this   
  114.         // 其调用了jQuery的静态方法。prototype中的mothodize是解决这类问题的好方法   
  115.         return jQuery.each(this, callback, args);   
  116.     },   
  117.   
  118.     // 找到elem在本jquery对象的位置(index)   
  119.     index : function(elem) {   
  120.         var ret = -1;   
  121.         return jQuery.inArray( // 如是jQuery对象就取第一个元素   
  122.                 elem && elem.jquery ? elem[0] : elem, this);   
  123.     },   
  124.   
  125.     // attr(properties)   
  126.     // 将“名/值”形式的对象设置为所有匹配元素的属性。   
  127.     // attr(name)   
  128.     // 取得第一个匹配元素的属性值。通过这个方法可以方便地从第一个匹配元素中获取一个属性的值。如果元素没有相应属性,则返回 undefined 。   
  129.     // attr(key,value)   
  130.     // 为所有匹配的元素设置一个属性值。$("img").attr("src","test.jpg");   
  131.     // attr(key,fn)   
  132.     // 为所有匹配的元素设置一个由这个函数计算的值做属性值。   
  133.     attr : function(name, value, type) {   
  134.         var options = name;// 支持"名/值"形式的对象和string   
  135.         if (name.constructor == String)   
  136.             if (value === undefined)   
  137.                 // 调用curCss,attr静态方法返回本对象第一个元素的name的属性值   
  138.                 return this[0] && jQuery[type || "attr"](this[0], name);   
  139.             else {// 设定属性值,把name String 转换成"名/值"对象,便于统一的处理   
  140.                 options = {};   
  141.                 options[name] = value;   
  142.             }   
  143.         return this.each(function(i) {// 为每个元素的指定的name属性设值   
  144.                     for (name in options)   
  145.                         // value=options[name],可以是Fn(index),this-->each elem   
  146.                         jQuery.attr(type ? this.style : this, name, jQuery   
  147.                                 .prop(this, options[name], type, i, name));   
  148.                 });   
  149.     },   
  150.   
  151.     // css(name)   
  152.     // 访问第一个匹配元素的样式属性。   
  153.     // css(name,value)   
  154.     // 在所有匹配的元素中,设置一个样式属性的值。数字将自动转化为像素值   
  155.     // css(properties)   
  156.     // 把一个“名/值对”对象设置为所有匹配元素的样式属性。这是一种在所有匹配的元素上设置大量样式属性的最佳方式。   
  157.     css : function(key, value) {   
  158.   
  159.         if ((key == 'width' || key == 'height') && parseFloat(value) < 0)   
  160.             value = undefined;// 忽略负数   
  161.         return this.attr(key, value, "curCSS");// 调用了curCSS方法   
  162.     },   
  163.   
  164.     // text()   
  165.     // 取得所有匹配元素的内容。结果是由所有匹配元素包含的文本内容组合起来的文本。这个方法对HTML和XML文档都有效。   
  166.     // text(val)   
  167.     // 设置所有匹配元素的文本内容.与 html() 类似, 但将编码 HTML (将 "<" 和 ">" 替换成相应的HTML实体).   
  168.     text : function(text) {   
  169.         if (typeof text != "object" && text != null)   
  170.             return this.empty()// 除去所有的子元素,加上创建的文本节点   
  171.                     .append((this[0] && this[0].ownerDocument || document)   
  172.                             .createTextNode(text));   
  173.   
  174.         var ret = "";   
  175.         jQuery.each(text || this, function() {// 所有匹配元素包含的文本内容组合起来   
  176.                     jQuery.each(this.childNodes, function() {   
  177.                         if (this.nodeType != 8)// 8:注释   
  178.                                 ret += (this.nodeType != 1// 元素的话,递归子元素   
  179.                                         ? this.nodeValue   
  180.                                         : jQuery.fn.text([this]));   
  181.                         });   
  182.                 });   
  183.   
  184.         return ret;   
  185.     },   
  186.   
  187.     // *****************************************************************************   
  188.     // 一组用于元素标签包裹操作的函数   
  189.   
  190.     // 将所有匹配的元素用单个元素包裹起来   
  191.     // 这个函数的原理是检查提供的第一个元素并在它的代码结构中找到最上层的祖先元素--这个祖先元素就是包装元素。   
  192.     // 这于 '.wrap()' 是不同的,'.wrap()'为每一个匹配的元素都包裹一次。   
  193.     wrapAll : function(html) {   
  194.         if (this[0])   
  195.             /*  
  196.              * <p>Hello</p><p>cruel</p><p>World</p>。-->  
  197.              * $("p").wrapAll("<div></div>");-->调用wrapAll的jQuery对象,称:A。有三个元素。  
  198.              * 第一步:复制生成一个jQuery对象,称:B。得到:<div></div>的元素。  
  199.              * 第二步:把B所有的元素都插在A[0]元素之前,得到<div></div><p>Hello</p><p>cruel</p><p>World</p>  
  200.              * 第三步:找到B对象中所有元素的最内面的节点,如<div> </div>。称:inner Node;  
  201.              * 第四步:向所有innerNode内部插入A对象的所有元素,得到<div><p>Hello</p><p>cruel</p><p>World</p></div>  
  202.              */  
  203.             jQuery(html, this[0].ownerDocument).clone().insertBefore(this[0])   
  204.                     .map(function() {// 找到当前元素的最下层的子节点   
  205.                         var elem = this;   
  206.                         while (elem.firstChild)   
  207.                             elem = elem.firstChild;   
  208.                         return elem;   
  209.                     }).append(this);// this指是调用wrapAll的jQuery对象。   
  210.   
  211.         return this;   
  212.     },   
  213.   
  214.     // 将每一个匹配的元素的子内容(包括文本节点)用一个HTML结构包裹起来   
  215.     wrapInner : function(html) {   
  216.         return this.each(function() {// 这里包裹的对象是每个元素的对象的contents()   
  217.                     jQuery(this).contents().wrapAll(html);   
  218.                 });   
  219.     },   
  220.   
  221.     // 对于当前的jquery对象的每个元素都执行wrapAll(html)   
  222.     wrap : function(html) {   
  223.         return this.each(function() {// 这里包裹的对象是每个元素的对象   
  224.                     jQuery(this).wrapAll(html);   
  225.                 });   
  226.     },   
  227.   
  228.     // ************************************************************************   
  229.   
  230.     // ******************************************************************   
  231.     // 该组方法主要是完成把元素插到什么地方,与Ext的DomHelp的功能相似。   
  232.     // 在一个元素之前,之后,元素的开始,结束位置   
  233.   
  234.     // 向每个匹配的元素内部追加内容。   
  235.     // 这个操作与对指定的元素执行appendChild方法,将它们添加到文档中的情况类似   
  236.     append : function() {   
  237.         return this.domManip(arguments, truefalse, function(elem) {   
  238.             if (this.nodeType == 1)   
  239.                 this.appendChild(elem);   
  240.         });   
  241.     },   
  242.     // 向每个匹配的元素内部前置内容。   
  243.     // 这是向所有匹配元素内部的开始处插入内容的最佳方式。   
  244.     prepend : function() {// elem =arguments的转化集合中的dom元素   
  245.         return this.domManip(arguments, truetrue, function(elem) {   
  246.             if (this.nodeType == 1)// this=jQuery对象的每个元素(对于tr之类会修正)   
  247.                     this.insertBefore(elem, this.firstChild);   
  248.             });   
  249.     },   
  250.   
  251.     // 在每个匹配的元素之前插入内容。   
  252.     before : function() {   
  253.         return this.domManip(arguments, falsefalse, function(elem) {   
  254.             this.parentNode.insertBefore(elem, this);// this=jQuery对象的每个元素   
  255.             });   
  256.     },   
  257.   
  258.     // 在每个匹配的元素之后插入内容   
  259.     after : function() {   
  260.         return this.domManip(arguments, falsetrue, function(elem) {   
  261.             this.parentNode.insertBefore(elem, this.nextSibling);   
  262.         });   
  263.     },   
  264.   
  265.     // ******************************************************************   
  266.   
  267.     // 回到最近的一个"破坏性"操作之前。即,将匹配的元素列表变为前一次的状态。   
  268.     end : function() {   
  269.         return this.prevObject || jQuery([]);   
  270.     },   
  271.   
  272.     // 搜索所有与指定表达式匹配的元素。这个函数是找出正在处理的元素的后代元素的好方法。   
  273.     // 所有搜索都依靠jQuery表达式来完成。这个表达式可以使用CSS1-3的选择器语法来写。   
  274.     find : function(selector) {   
  275.         var elems = jQuery.map(this, function(elem) {// 找到每个元素的满足的   
  276.                     return jQuery.find(selector, elem);   
  277.                 });   
  278.   
  279.         return this.pushStack(/[^+>] [^+>]/.test(selector) ? jQuery   
  280.                 .unique(elems) : elems);// 是不是返回不重复的元素?   
  281.     },   
  282.   
  283.     // clone当前对象,events表明是否clone事件   
  284.     clone : function(events) {   
  285.         // 对每个元素都进行加工(copy)后的集合重新构建jQuery对象   
  286.         var ret = this.map(function() {   
  287.             if (jQuery.browser.msie && !jQuery.isXMLDoc(this)) {   
  288.                 // IE 中cloneNode不能copy 通过attachEvent增加的事件   
  289.                 // 而innserHTML不能copy一些修改过的属性(仅作为属性储存)如input 的name   
  290.                 var clone = this.cloneNode(true), container = document   
  291.                         .createElement("div");   
  292.                 container.appendChild(clone);   
  293.                 return jQuery.clean([container.innerHTML])[0];   
  294.             } else  
  295.                 return this.cloneNode(true);   
  296.         });   
  297.   
  298.         // Need to set the expando to null on the cloned set if it exists   
  299.         // removeData doesn't work here, IE removes it from the original as well   
  300.         // this is primarily for IE but the data expando shouldn't be copied   
  301.         // over in any browser   
  302.         var clone = ret.find("*").andSelf().each(function() {   
  303.             if (this[expando] != undefined)   
  304.                 this[expando] = null;   
  305.         });   
  306.   
  307.         if (events === true)// clone所有事件   
  308.             this.find("*").andSelf().each(function(i) {   
  309.                 if (this.nodeType == 3)   
  310.                     return;   
  311.                 var events = jQuery.data(this"events");   
  312.   
  313.                 for (var type in events)   
  314.                     for (var handler in events[type])   
  315.                         jQuery.event.add(clone[i], type, events[type][handler],   
  316.                                 events[type][handler].data);   
  317.             });   
  318.   
  319.         return ret;   
  320.     },   
  321.   
  322.     // 筛选出与指定表达式匹配的元素集合。可以通过函数来筛选当前jQuery对象的   
  323.     // 元素,还有通过用逗号分隔多个表达式来筛选   
  324.     filter : function(selector) {// grep,multiFilter的综合   
  325.         return this.pushStack(jQuery.isFunction(selector)   
  326.                 && jQuery.grep(this, function(elem, i) {   
  327.                     return selector.call(elem, i);   
  328.                 }) || jQuery.multiFilter(selector, this));   
  329.     },   
  330.   
  331.     // 删除与指定表达式匹配的元素   
  332.     not : function(selector) {   
  333.         if (selector.constructor == String)// 采用jQuery表达式   
  334.             if (isSimple.test(selector))   
  335.                 return this.pushStack(jQuery.multiFilter(selector, thistrue));   
  336.             else  
  337.                 // 多表达式要过滤   
  338.                 selector = jQuery.multiFilter(selector, this);   
  339.   
  340.         var isArrayLike = selector.length// array-like的集合?   
  341.                 && selector[selector.length - 1] !== undefined   
  342.                 && !selector.nodeType;   
  343.         return this.filter(function() {// 过滤掉return false的元素   
  344.                     return isArrayLike ? jQuery.inArray(this, selector) < 0// this在selector中?   
  345.                             : this != selector;   
  346.                 });   
  347.     },   
  348.   
  349.     // 把与表达式匹配的元素添加到jQuery对象中。array(-like)的集合也可以追加进来   
  350.     add : function(selector) {   
  351.         return this.pushStack(jQuery.unique(jQuery.merge(this.get(),   
  352.                 typeof selector == 'string' ? jQuery(selector) : jQuery   
  353.                         .makeArray(selector))));   
  354.     },   
  355.   
  356.     // 用一个表达式来检查当前选择的元素集合,如果其中至少有一个元素符合这个给定的表达式就返回true。   
  357.     is : function(selector) {   
  358.         return !!selector && jQuery.multiFilter(selector, this).length > 0;   
  359.     },   
  360.   
  361.     // 检查当前的元素是否含有某个特定的类,如果有,则返回true   
  362.     hasClass : function(selector) {   
  363.         return this.is("." + selector);   
  364.     },   
  365.   
  366.     // 获得第一个匹配元素的当前值。   
  367.     // 在 jQuery 1.2 中,可以返回任意元素的值了。包括select。如果多选,将返回一个数组,其包含所选的值。   
  368.     // 设置每一个匹配元素的值。在 jQuery 1.2, 这也可以为select元件赋值   
  369.     val : function(value) {   
  370.         if (value == undefined) {   
  371.   
  372.             if (this.length) {   
  373.                 var elem = this[0];   
  374.   
  375.                 if (jQuery.nodeName(elem, 'option'))   
  376.                     return (elem.attributes.value || {}).specified   
  377.                             ? elem.value   
  378.                             : elem.text;   
  379.   
  380.                 // We need to handle select boxes special   
  381.                 if (jQuery.nodeName(elem, "select")) {   
  382.                     var index = elem.selectedIndex, values = [], options = elem.options, one = elem.type == "select-one";   
  383.   
  384.                     // Nothing was selected   
  385.                     if (index < 0)   
  386.                         return null;   
  387.   
  388.                     // Loop through all the selected options   
  389.                     for (var i = one ? index : 0, max = one   
  390.                             ? index + 1  
  391.                             : options.length;i < max; i++) {   
  392.                         var option = options[i];   
  393.   
  394.                         if (option.selected) {   
  395.                             // Get the specifc value for the option   
  396.                             value = jQuery(option).val();   
  397.   
  398.                             // We don't need an array for one selects   
  399.                             if (one)   
  400.                                 return value;   
  401.   
  402.                             // Multi-Selects return an array   
  403.                             values.push(value);   
  404.                         }   
  405.                     }   
  406.   
  407.                     return values;   
  408.   
  409.                     // Everything else, we just grab the value   
  410.                 } else  
  411.                     return (this[0].value || "").replace(/\r/g, "");   
  412.   
  413.             }   
  414.   
  415.             return undefined;   
  416.         }   
  417.   
  418.         if (value.constructor == Number)   
  419.             value += '';   
  420.   
  421.         return this  
  422.                 .each(function() {   
  423.                     if (this.nodeType != 1)   
  424.                         return;   
  425.   
  426.                     if (value.constructor == Array   
  427.                             && /radio|checkbox/.test(this.type))   
  428.                         this.checked = (jQuery.inArray(this.value, value) >= 0 || jQuery   
  429.                                 .inArray(this.name, value) >= 0);   
  430.   
  431.                     else if (jQuery.nodeName(this"select")) {   
  432.                         var values = jQuery.makeArray(value);   
  433.   
  434.                         jQuery("option"this)   
  435.                                 .each(function() {   
  436.                                     this.selected = (jQuery.inArray(this.value,   
  437.                                             values) >= 0 || jQuery.inArray(   
  438.                                             this.text, values) >= 0);   
  439.                                 });   
  440.   
  441.                         if (!values.length)   
  442.                             this.selectedIndex = -1;   
  443.   
  444.                     } else  
  445.                         this.value = value;   
  446.                 });   
  447.     },   
  448.   
  449.     // 设置每一个匹配元素的html内容。这个函数不能用于XML文档。但可以用于XHTML文档。   
  450.     // 取得第一个匹配的元素的html内容   
  451.     html : function(value) {   
  452.         return value == undefined ? (this[0] ? this[0].innerHTML : null) : this  
  453.                 .empty().append(value);// 去掉子节点,追加value   
  454.     },   
  455.   
  456.     // 将所有匹配的元素替换成指定的HTML或DOM元素。   
  457.     replaceWith : function(value) {   
  458.         return this.after(value).remove();// this.after(value),this没有变   
  459.     },   
  460.     // 获取第N个元素 。这个元素的位置是从0算起。   
  461.     eq : function(i) {   
  462.         return this.slice(i, +i + 1);   
  463.     },   
  464.   
  465.     // 代理数组的slice,同样的操作。   
  466.     slice : function() {   
  467.         return this.pushStack(Array.prototype.slice.apply(this, arguments));   
  468.     },   
  469.   
  470.     // 对于当前jquery对象中每个元素都进行callback(i,elem)的操作   
  471.     // 返回新生成的jquery对象。   
  472.     map : function(callback) {   
  473.         return this.pushStack(jQuery.map(this, function(elem, i) {   
  474.             return callback.call(elem, i, elem);   
  475.         }));   
  476.     },   
  477.   
  478.     // 把先前jQuery对象的所有元素加到当前的jQuery对象之中   
  479.     andSelf : function() {   
  480.         return this.add(this.prevObject);   
  481.     },   
  482.   
  483.     // data(name,value)   
  484.     // 在元素上存放数据,同时也返回value。   
  485.     // 如果jQuery集合指向多个元素,那将在所有元素上设置对应数据。   
  486.     // 这个函数不用建立一个新的expando,就能在一个元素上存放任何格式的数据,而不仅仅是字符串。   
  487.   
  488.     // data(name)   
  489.     // 返回元素上储存的相应名字的数据,可以用data(name, value)来设定。   
  490.     // 如果jQuery集合指向多个元素,那将只返回第一个元素的对应数据   
  491.     data : function(key, value) {   
  492.         var parts = key.split(".");   
  493.         parts[1] = parts[1] ? "." + parts[1] : "";   
  494.   
  495.         if (value === undefined) {// 取值   
  496.             // 这个特别的方法将会触发指定的事件类型上所有绑定的处理函数。但不会执行浏览器默认动作   
  497.             var data = this.triggerHandler("getData" + parts[1] + "!",   
  498.                     [parts[0]]);   
  499.   
  500.             if (data === undefined && this.length)   
  501.                 data = jQuery.data(this[0], key);   
  502.   
  503.             return data === undefined && parts[1] ? this.data(parts[0]) : data;   
  504.         } else { // 设值   
  505.             return this.trigger("setData" + parts[1] + "!", [parts[0], value])   
  506.                     .each(function() {   
  507.                         jQuery.data(this, key, value);   
  508.                     });   
  509.         }   
  510.     },   
  511.   
  512.     // 在元素上移除存放的数据   
  513.     // 与$(...).data(name, value)函数作用相反   
  514.     removeData : function(key) {   
  515.         return this.each(function() {   
  516.             jQuery.removeData(this, key);   
  517.         });   
  518.     },   
  519.   
  520.     // Dom manipulate操作的函数,对于每个jQuery对象中元素都运行   
  521.     // 由callback操作args转化成的Dom 元素集合的函数。   
  522.     domManip : function(args, table, reverse, callback) {   
  523.         var clone = this.length > 1, elems;   
  524.   
  525.         // 对当前的jquery对象中每个元素都进行操作   
  526.         return this.each(function() {   
  527.             if (!elems) {// 把args 转化为dom元素数组,追加的内容   
  528.                     elems = jQuery.clean(args, this.ownerDocument);   
  529.                     if (reverse)// 倒序   
  530.                         elems.reverse();   
  531.                 }   
  532.   
  533.                 var obj = this;   
  534.   
  535.                 // Ie Table不兼容,要进行特殊处理   
  536.                 if (table && jQuery.nodeName(this"table")// 当前元素是table?   
  537.                         && jQuery.nodeName(elems[0], "tr"))// 要追加是tr?   
  538.                     obj = this.getElementsByTagName("tbody")[0]// 没有tbody,创建追加   
  539.                             || this.appendChild(this.ownerDocument   
  540.                                     .createElement("tbody"));   
  541.   
  542.                 var scripts = jQuery([]);   
  543.   
  544.                 jQuery.each(elems, function() {   
  545.                     // 长度大于1,就采用clone。取第一个元素,否则就是本元素   
  546.                         var elem = clone ? jQuery(this).clone(true)[0] : this;   
  547.   
  548.                         // 执行所有 scripts 在所有的元素注入之后   
  549.                         if (jQuery.nodeName(elem, "script"))   
  550.                             scripts = scripts.add(elem);   
  551.                         else {   
  552.                             // 除去内部 scripts,同时保存起来, 为了之后的计算   
  553.                             if (elem.nodeType == 1)   
  554.                                 scripts = scripts.add(jQuery("script", elem)   
  555.                                         .remove());   
  556.   
  557.                             // 注册元素到document之中   
  558.                             callback.call(obj, elem);   
  559.                         }   
  560.                     });   
  561.   
  562.                 scripts.each(evalScript);   
  563.             });   
  564.     }   
  565. };   
  566.   
  567. // Give the init function the jQuery prototype for later instantiation   
  568. jQuery.fn.init.prototype = jQuery.fn;   
  569.   
  570. function evalScript(i, elem) {   
  571.     if (elem.src) {// <script src.. 通过ajax调用了   
  572.         jQuery.ajax( {   
  573.             url : elem.src,   
  574.             async : false,   
  575.             dataType : "script"  
  576.         });   
  577.     } else {// 对于本地的,通过globalEval运行   
  578.         jQuery   
  579.                 .globalEval(elem.text || elem.textContent || elem.innerHTML   
  580.                         || "");   
  581.     }   
  582.     if (elem.parentNode)// 除去   
  583.         elem.parentNode.removeChild(elem);   
  584. }   
  585.   
  586. function now() {   
  587.     return +new Date;   
  588. }   
  589.   
  590. jQuery.extend = jQuery.fn.extend = function() {   
  591.   
  592.     var target = arguments[0] || {}, // 第一个参数是目标   
  593.     i = 1, length = arguments.length, deep = false, options;   
  594.   
  595.     if (target.constructor == Boolean) {// 第一个参数是bool型的   
  596.         deep = target;// 深度copy   
  597.         target = arguments[1] || {};// target指向第二个参数   
  598.         i = 2;   
  599.     }   
  600.   
  601.     // target 是string 型的或?   
  602.     if (typeof target != "object" && typeof target != "function")   
  603.         target = {};   
  604.   
  605.     if (length == i) {// 只有一个参数?或deep copy 时,两个参数   
  606.         target = this;// 目标为this   
  607.         --i;   
  608.     }   
  609.   
  610.     for (;i < length; i++)   
  611.         if ((options = arguments[i]) != null)   
  612.   
  613.             for (var name in options) {   
  614.                 var src = target[name], copy = options[name];   
  615.                 if (target === copy)// 防止死循环   
  616.                     continue;   
  617.                 // 深度copy处理,最深为元素   
  618.                 if (deep && copy && typeof copy == "object" && !copy.nodeType)   
  619.                     target[name] = jQuery.extend(deep, src   
  620.                             || (copy.length != null ? [] : {}), copy);   
  621.                 else if (copy !== undefined)// 直接copy   
  622.                     target[name] = copy;   
  623.   
  624.             }   
  625.   
  626.     return target;   
  627. };   
  628.   
  629. var expando = "jQuery" + now(), uuid = 0, windowData = {},   
  630. // exclude the following css properties to add px   
  631. exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,   
  632. // cache defaultView   
  633. // defaultViewis generally a reference to the window object for the document   
  634. defaultView = document.defaultView || {};   
  635.   
  636. jQuery.extend( {   
  637.     noConflict : function(deep) {   
  638.         window.$ = _$;   
  639.   
  640.         if (deep)   
  641.             window.jQuery = _jQuery;   
  642.   
  643.         return jQuery;   
  644.     },   
  645.   
  646.     // See test/unit/core.js for details concerning this function.   
  647.         // Since 1.3 DOM methods and function like alert   
  648.         // aren't supported. They return false on IE (#2968).   
  649.         isFunction : function(fn) {   
  650.             return fn instanceof Function;   
  651.         },   
  652.   
  653.         // 判断是不是XMLDoc   
  654.         isXMLDoc : function(elem) {   
  655.             return elem.documentElement && !elem.body || elem.tagName   
  656.                     && elem.ownerDocument && !elem.ownerDocument.body;   
  657.         },   
  658.   
  659.         // Evalulates a script in a global context   
  660.         // 在全局的范围eval 代码,也就是在<head></head>中   
  661.         globalEval : function(data) {   
  662.             data = jQuery.trim(data);   
  663.   
  664.             if (data) {   
  665.                 // Inspired by code by Andrea Giammarchi   
  666.                 // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html   
  667.                 var head = document.getElementsByTagName("head")[0]   
  668.                         || document.documentElement, script = document   
  669.                         .createElement("script");   
  670.   
  671.                 script.type = "text/javascript";   
  672.                 if (jQuery.browser.msie)   
  673.                     script.text = data;   
  674.                 else  
  675.                     script.appendChild(document.createTextNode(data));   
  676.   
  677.                 // Use insertBefore instead of appendChild to circumvent an IE6   
  678.                 // bug. This arises when a base node is used (#2709).   
  679.                 head.insertBefore(script, head.firstChild);   
  680.                 head.removeChild(script);   
  681.             }   
  682.         },   
  683.   
  684.         // 判断elem的nodeName是否存在   
  685.         nodeName : function(elem, name) {   
  686.             return elem.nodeName   
  687.                     && elem.nodeName.toUpperCase() == name.toUpperCase();   
  688.         },   
  689.   
  690.         cache : {},   
  691.   
  692.         data : function(elem, name, data) {   
  693.             elem = elem == window ? windowData : elem;   
  694.   
  695.             var id = elem[expando];   
  696.   
  697.             // Compute a unique ID for the element   
  698.             if (!id)   
  699.                 id = elem[expando] = ++uuid;   
  700.   
  701.             // Only generate the data cache if we're   
  702.             // trying to access or manipulate it   
  703.             if (name && !jQuery.cache[id])   
  704.                 jQuery.cache[id] = {};   
  705.   
  706.             // Prevent overriding the named cache with undefined values   
  707.             if (data !== undefined)   
  708.                 jQuery.cache[id][name] = data;   
  709.   
  710.             // Return the named cache data, or the ID for the element   
  711.             return name ? jQuery.cache[id][name] : id;   
  712.         },   
  713.   
  714.         removeData : function(elem, name) {   
  715.             elem = elem == window ? windowData : elem;   
  716.   
  717.             var id = elem[expando];   
  718.   
  719.             // If we want to remove a specific section of the element's data   
  720.             if (name) {   
  721.                 if (jQuery.cache[id]) {   
  722.                     // Remove the section of cache data   
  723.                     delete jQuery.cache[id][name];   
  724.   
  725.                     // If we've removed all the data, remove the element's cache   
  726.                     name = "";   
  727.   
  728.                     for (name in jQuery.cache[id])   
  729.                         break;   
  730.   
  731.                     if (!name)   
  732.                         jQuery.removeData(elem);   
  733.                 }   
  734.   
  735.                 // Otherwise, we want to remove all of the element's data   
  736.             } else {   
  737.                 // Clean up the element expando   
  738.                 try {   
  739.                     delete elem[expando];   
  740.                 } catch (e) {   
  741.                     // IE has trouble directly removing the expando   
  742.                     // but it's ok with using removeAttribute   
  743.                     if (elem.removeAttribute)   
  744.                         elem.removeAttribute(expando);   
  745.                 }   
  746.   
  747.                 // Completely remove the data cache   
  748.                 delete jQuery.cache[id];   
  749.             }   
  750.         },   
  751.   
  752.         // 对object中的每个对象都执行callback函数进行处理。args仅仅内部用   
  753.         each : function(object, callback, args) {   
  754.             var name, i = 0, length = object.length;   
  755.             // 和else的处理差不多,args的传参代替object的属性值   
  756.             if (args) {   
  757.                 if (length == undefined) {   
  758.                     for (name in object)   
  759.                         if (callback.apply(object[name], args) === false)   
  760.                             break;   
  761.                 } else  
  762.                     for (;i < length;)   
  763.                         if (callback.apply(object[i++], args) === false)   
  764.                             break;   
  765.   
  766.                 // A special, fast, case for the most common use of each   
  767.             } else {   
  768.                 // 不是array-like的object,对每个属性进行callback函数的调用   
  769.                 if (length == undefined) {   
  770.                     for (name in object)   
  771.                         if (callback.call(object[name], name, object[name]) === false)   
  772.                             break;   
  773.                 } else  
  774.                     // array-like object,采用数组的形式来处理   
  775.                     for (var value = object[0];i < length   
  776.                             && callback.call(value, i, value) !== false; value = object[++i]) {   
  777.                     }   
  778.             }   
  779.   
  780.             return object;   
  781.         },   
  782.   
  783.         // 根据指定元素(elem)的指定的name来修正value值,如加px,exec Fn.   
  784.         prop : function(elem, value, type, i, name) {   
  785.             if (jQuery.isFunction(value))// value=Fn   
  786.                 value = value.call(elem, i);// 得到Fn的返回value   
  787.             // 对于element的style中CSS属性,对需要加上单位的加上px单位   
  788.             return value && value.constructor == Number && type == "curCSS"  
  789.                     && !exclude.test(name) ? value + "px" : value;   
  790.         },   
  791.   
  792.         // 一组内部使用的Class操作函数   
  793.         className : {   
  794.             // 为元素增加classNameS   
  795.             add : function(elem, classNames) {// 多个className,空格分开   
  796.                 jQuery.each((classNames || "").split(/\s+/),   
  797.                         function(i, className) {   
  798.                             if (elem.nodeType == 1  
  799.                                     && !jQuery.className.has(elem.className,   
  800.                                             className))   
  801.                                 elem.className += (elem.className ? " " : "")   
  802.                                         + className;   
  803.                         });   
  804.             },   
  805.   
  806.             // 为元素除去classNames   
  807.             remove : function(elem, classNames) {   
  808.                 if (elem.nodeType == 1)// 元素   
  809.                     elem.className = classNames != undefined ? jQuery.grep(   
  810.                             elem.className.split(/\s+/), function(className) {// 过滤   
  811.                                 return !jQuery.className.has(classNames,   
  812.                                         className);   
  813.                             }).join(" ") : "";   
  814.             },   
  815.   
  816.             // 元素有没有className?   
  817.             has : function(elem, className) {   
  818.                 return jQuery.inArray(className, (elem.className || elem)   
  819.                         .toString().split(/\s+/)) > -1;   
  820.             }   
  821.         },   
  822.   
  823.         // 间隔改变elem的样式   
  824.         swap : function(elem, options, callback) {   
  825.             var old = {};   
  826.             for (var name in options) {// 替换elem.style中的属性   
  827.                 old[name] = elem.style[name];   
  828.                 elem.style[name] = options[name];   
  829.             }   
  830.             // 执行回调   
  831.             callback.call(elem);   
  832.   
  833.             // 重新换回原来的属性   
  834.             for (var name in options)   
  835.                 elem.style[name] = old[name];   
  836.         },   
  837.   
  838.         // 取得elem的name的属性值   
  839.         css : function(elem, name, force) {   
  840.             // 对元素的宽度高度修正   
  841.             if (name == "width" || name == "height") {   
  842.                 var val, props = {   
  843.                     position : "absolute",   
  844.                     visibility : "hidden",   
  845.                     display : "block"  
  846.                 }, which = (name == "width" ? ["Left""Right"] : ["Top",   
  847.                         "Bottom"]);   
  848.   
  849.                 function getWH() {// 求元素的实现高度,宽度   
  850.                     val = name == "width"  
  851.                             ? elem.offsetWidth   
  852.                             : elem.offsetHeight;   
  853.                     var padding = 0, border = 0;   
  854.                     jQuery.each(which, function() {   
  855.                         // paddinLeft,paddingRight   
  856.                             padding += parseFloat(jQuery.curCSS(elem, "padding"  
  857.                                     + thistrue))   
  858.                                     || 0;   
  859.                             // borderTopWidth,borderBottomWith   
  860.                             border += parseFloat(jQuery.curCSS(elem, "border"  
  861.                                     + this + "Width"true))   
  862.                                     || 0;   
  863.                         });   
  864.                     val -= Math.round(padding + border);   
  865.                 }   
  866.   
  867.                 if (jQuery(elem).is(":visible"))   
  868.                     getWH();   
  869.                 else  
  870.                     // 元素看不到的情况下,绝对定位,取高度或宽度   
  871.                     jQuery.swap(elem, props, getWH);   
  872.   
  873.                 return Math.max(0, val);   
  874.             }   
  875.   
  876.             return jQuery.curCSS(elem, name, force);   
  877.         },   
  878.   
  879.         curCSS : function(elem, name, force) {   
  880.             var ret, style = elem.style;   
  881.   
  882.             // elem的属性值被破坏   
  883.             function color(elem) {   
  884.                 if (!jQuery.browser.safari)   
  885.                     return false;   
  886.   
  887.                 // 从defaultView 取   
  888.                 var ret = defaultView.getComputedStyle(elem, null);   
  889.                 return !ret || ret.getPropertyValue("color") == "";   
  890.             }   
  891.   
  892.             // IE 中opacity 不兼容   
  893.             if (name == "opacity" && jQuery.browser.msie) {   
  894.                 ret = jQuery.attr(style, "opacity");   
  895.                 return ret == "" ? "1" : ret;// 1是100%的显示   
  896.             }   
  897.   
  898.             // Opera的display bug修正, 见 #2037   
  899.             if (jQuery.browser.opera && name == "display") {   
  900.                 var save = style.outline;   
  901.                 style.outline = "0 solid black";   
  902.                 style.outline = save;   
  903.             }   
  904.   
  905.             if (name.match(/float/i))// float是通过styleFloat取值的   
  906.                 name = styleFloat;   
  907.   
  908.             if (!force && style && style[name])   
  909.                 ret = style[name];// 取值   
  910.             else if (defaultView.getComputedStyle) {// 看看defaultView的CSS   
  911.   
  912.                 if (name.match(/float/i))   
  913.                     name = "float";   
  914.                 // 转换成lamb,如addMethod变成add-method   
  915.                 name = name.replace(/([A-Z])/g, "-$1").toLowerCase();   
  916.   
  917.                 var computedStyle = defaultView.getComputedStyle(elem, null);   
  918.   
  919.                 if (computedStyle && !color(elem))   
  920.                     ret = computedStyle.getPropertyValue(name);   
  921.                 else {// Safari没有正确地报道属性值,会提示none elements are involved   
  922.                     var swap = [], stack = [], a = elem, i = 0;   
  923.   
  924.                     // Locate all of the parent display: none elements   
  925.                     for (;a && color(a); a = a.parentNode)   
  926.                         stack.unshift(a);   
  927.   
  928.                     // Go through and make them visible, but in reverse   
  929.                     // (It would be better if we knew the exact display type   
  930.                     // that they had)   
  931.                     for (;i < stack.length; i++)   
  932.                         if (color(stack[i])) {   
  933.                             swap[i] = stack[i].style.display;   
  934.                             stack[i].style.display = "block";   
  935.                         }   
  936.   
  937.                     // Since we flip the display style, we have to handle that   
  938.                     // one special, otherwise get the value   
  939.                     ret = name == "display" && swap[stack.length - 1] != null  
  940.                             ? "none"  
  941.                             : (computedStyle && computedStyle   
  942.                                     .getPropertyValue(name))   
  943.                                     || "";   
  944.   
  945.                     // Finally, revert the display styles back   
  946.                     for (i = 0;i < swap.length; i++)   
  947.                         if (swap[i] != null)   
  948.                             stack[i].style.display = swap[i];   
  949.                 }   
  950.   
  951.                 // We should always get a number back from opacity   
  952.                 if (name == "opacity" && ret == "")   
  953.                     ret = "1";   
  954.   
  955.             } else if (elem.currentStyle) {// 元素的currentStyle   
  956.                 var camelCase = name.replace(/\-(\w)/g, function(all, letter) {   
  957.                     return letter.toUpperCase();   
  958.                 });   
  959.   
  960.                 ret = elem.currentStyle[name] || elem.currentStyle[camelCase];   
  961.   
  962.                 // From the awesome hack by Dean Edwards   
  963.                 // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291   
  964.   
  965.                 // If we're not dealing with a regular pixel number   
  966.                 // but a number that has a weird ending, we need to convert it   
  967.                 // to pixels   
  968.                 if (!/^\d+(px)?$/i.test(ret) && /^\d/.test(ret)) {   
  969.                     // Remember the original values   
  970.                     var left = style.left, rsLeft = elem.runtimeStyle.left;   
  971.   
  972.                     // Put in the new values to get a computed value out   
  973.                     elem.runtimeStyle.left = elem.currentStyle.left;   
  974.                     style.left = ret || 0;   
  975.                     ret = style.pixelLeft + "px";   
  976.   
  977.                     // Revert the changed values   
  978.                     style.left = left;   
  979.                     elem.runtimeStyle.left = rsLeft;   
  980.                 }   
  981.             }   
  982.   
  983.             return ret;   
  984.         },   
  985.   
  986.         // 把html转换成Dom元素,elems多个html string 的数组   
  987.         clean : function(elems, context) {   
  988.             var ret = [];   
  989.             context = context || document;   
  990.             // !context.createElement fails in IE with an error but returns   
  991.             // typeof 'object'   
  992.             if (typeof context.createElement == 'undefined')   
  993.                 // 处理context是jquery对象或数组的兼容。context可以是元素,或元素的集合,或空   
  994.                 context = context.ownerDocument || context[0]   
  995.                         && context[0].ownerDocument || document;   
  996.   
  997.             jQuery   
  998.                     .each(elems, function(i, elem) {   
  999.                         if (typeof elem == 'number')   
  1000.                             elem += '';// 把int 转换成string的最高效的方法   
  1001.   
  1002.                         if (!elem)   
  1003.                             return;// 为'',undefined,false等时返回   
  1004.   
  1005.                         // 转换html为Dom元素   
  1006.                         if (typeof elem == "string") {   
  1007.                             // Fix "XHTML"-style tags in all browsers   
  1008.                             // 对于其它的标签,修改成xml的格式   
  1009.                             elem = elem   
  1010.                                     .replace(   
  1011.                                             /(<(\w+)[^>]*?)\/>/g,// front=(<(\w+)[^>]*?)   
  1012.                                             function(all, front, tag) {   
  1013.                                                 return tag   
  1014.                                                         .match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)   
  1015.                                                         ? all   
  1016.                                                         : front + "></" + tag   
  1017.                                                                 + ">";   
  1018.                                             });   
  1019.   
  1020.                             // 去空格,否则indexof可能会出不能正常工作   
  1021.                             var tags = jQuery.trim(elem).toLowerCase(), div = context   
  1022.                                     .createElement("div");   
  1023.                             // 有些标签必须是有一些约束的,比如<option>必须在<select></select>中间   
  1024.                             // 下面的代码在大部分是对<table>中子元素进行修正。数组中第一个元素为深度   
  1025.                             var wrap = !tags.indexOf("<opt")   
  1026.                                     && [1"<select multiple='multiple'>",   
  1027.                                             "</select>"]   
  1028.                                     || !tags.indexOf("<leg")   
  1029.                                     && [1"<fieldset>""</fieldset>"]   
  1030.                                     || tags   
  1031.                                             .match(/^<(thead|tbody|tfoot|colg|cap)/)   
  1032.                                     && [1"<table>""</table>"]   
  1033.                                     || !tags.indexOf("<tr")   
  1034.                                     && [2"<table><tbody>""</tbody></table>"]   
  1035.                                     || (!tags.indexOf("<td") || !tags   
  1036.                                             .indexOf("<th"))   
  1037.                                     && [3"<table><tbody><tr>",   
  1038.                                             "</tr></tbody></table>"]   
  1039.                                     || !tags.indexOf("<col")   
  1040.                                     && [2"<table><tbody></tbody><colgroup>",   
  1041.                                             "</colgroup></table>"]   
  1042.                                     ||   
  1043.   
  1044.                                     // IE can't serialize <link> and <script>   
  1045.                                     // tags normally   
  1046.                                     jQuery.browser.msie   
  1047.                                     && [1"div<div>""</div>"] ||   
  1048.   
  1049.                                     [0""""];   
  1050.   
  1051.                             // 包裹html之后,采用innerHTML转换成Dom   
  1052.                             div.innerHTML = wrap[1] + elem + wrap[2];   
  1053.   
  1054.                             while (wrap[0]--)   
  1055.                                 // 转到正确的深度,对于[1, "<table>",   
  1056.                                 // "</table>"],div=<table>   
  1057.                                 div = div.lastChild;   
  1058.   
  1059.                             // fragments去掉IE对<table>自动插入的<tbody>   
  1060.                             if (jQuery.browser.msie) {   
  1061.   
  1062.                                 // Tag字符是<table>, *may*有伪造的 <tbody>   
  1063.                                 var tbody = !tags.indexOf("<table")// <table开头   
  1064.                                         && tags.indexOf("<tbody") < 0// 但没有<tbody   
  1065.                                 ? div.firstChild// 生成的元素中可能会自动加的<tbody>   
  1066.                                         && div.firstChild.childNodes :   
  1067.   
  1068.                                 // String was a bare <thead> or <tfoot>   
  1069.                                         wrap[1] == "<table>"  
  1070.                                                 && tags.indexOf("<tbody") < 0// 没有出现<tbody   
  1071.                                         ? div.childNodes// 没有加<tbody>   
  1072.                                                 : [];   
  1073.                                 // 除去<tbody>   
  1074.                                 for (var j = tbody.length - 1;j >= 0; --j)   
  1075.                                     if (jQuery.nodeName(tbody[j], "tbody")   
  1076.                                             && !tbody[j].childNodes.length)   
  1077.                                         tbody[j].parentNode   
  1078.                                                 .removeChild(tbody[j]);   
  1079.   
  1080.                                 // IE completely kills leading whitespace when   
  1081.                                 // innerHTML is used   
  1082.                                 if (/^\s/.test(elem))   
  1083.                                     div.insertBefore(   
  1084.                                             context.createTextNode(elem   
  1085.                                                     .match(/^\s*/)[0]),   
  1086.                                             div.firstChild);   
  1087.   
  1088.                             }   
  1089.   
  1090.                             elem = jQuery.makeArray(div.childNodes);   
  1091.                         }   
  1092.   
  1093.                         if (elem.length === 0  
  1094.                                 && (!jQuery.nodeName(elem, "form") && !jQuery   
  1095.                                         .nodeName(elem, "select")))   
  1096.                             return;   
  1097.   
  1098.                         if (elem[0] == undefined   
  1099.                                 || jQuery.nodeName(elem, "form")   
  1100.                                 || elem.options)   
  1101.                             ret.push(elem);   
  1102.   
  1103.                         else  
  1104.                             // 对于elems是array-like的集合   
  1105.                             ret = jQuery.merge(ret, elem);   
  1106.   
  1107.                     });   
  1108.   
  1109.             return ret;   
  1110.         },   
  1111.   
  1112.         // 为给定的elem的name属性设定value值   
  1113.         // 或取elem的name属性值   
  1114.         attr : function(elem, name, value) {   
  1115.             // 文本,注释节点不处理   
  1116.             if (!elem || elem.nodeType == 3 || elem.nodeType == 8)   
  1117.                 return undefined;   
  1118.   
  1119.             var notxml = !jQuery.isXMLDoc(elem),   
  1120.             // 取值还是设值?   
  1121.             set = value !== undefined, msie = jQuery.browser.msie;   
  1122.   
  1123.             // 兼容的处理   
  1124.             name = notxml && jQuery.props[name] || name;   
  1125.   
  1126.             // Only do all the following if this is a node (faster for style)   
  1127.             // IE elem.getAttribute passes even for style   
  1128.             if (elem.tagName) {   
  1129.                 var special = /href|src|style/.test(name);// 要特殊处理   
  1130.   
  1131.                 // 对于safari的特殊处理   
  1132.                 if (name == "selected" && jQuery.browser.safari)   
  1133.                     elem.parentNode.selectedIndex;   
  1134.   
  1135.                 if (name in elem && notxml && !special) {// 通过DOM 0方式进入属性   
  1136.                     if (set) {// 改变属性   
  1137.                         // IE报错,type不能改变   
  1138.                         if (name == "type" && jQuery.nodeName(elem, "input")   
  1139.                                 && elem.parentNode)   
  1140.                             throw "type property can't be changed";   
  1141.   
  1142.                         elem[name] = value;   
  1143.                     }   
  1144.   
  1145.                     // 对于attr(form,name)取是form[name].value   
  1146.                     if (jQuery.nodeName(elem, "form")   
  1147.                             && elem.getAttributeNode(name))   
  1148.                         return elem.getAttributeNode(name).nodeValue;   
  1149.                     // 返回元素的属性值   
  1150.                     return elem[name];   
  1151.                 }   
  1152.                 // 对style进行属性的操作   
  1153.                 if (msie && notxml && name == "style")   
  1154.                     return jQuery.attr(elem.style, "cssText", value);   
  1155.   
  1156.                 if (set)   
  1157.                     // IE会报错 see #1070   
  1158.                     elem.setAttribute(name, "" + value);   
  1159.   
  1160.                 var attr = msie && notxml && special   
  1161.                 // Some attributes require a special call on IE   
  1162.                         ? elem.getAttribute(name, 2)   
  1163.                         : elem.getAttribute(name);   
  1164.                 // 不存在的属性返回null,改成undefined   
  1165.                 return attr === null ? undefined : attr;   
  1166.             }   
  1167.   
  1168.             // 当elem参数是elem.style时。。。   
  1169.   
  1170.             // IE 使用 filters for opacity   
  1171.             if (msie && name == "opacity") {   
  1172.                 if (set) {   
  1173.                     // IE opacity 要层的支持   
  1174.                     elem.zoom = 1;   
  1175.   
  1176.                     // 设 alpha filter 来设定 opacity   
  1177.                     elem.filter = (elem.filter || "").replace(/alpha\([^)]*\)/,   
  1178.                             "")   
  1179.                             + ((parseInt(value) + '' == "NaN"  
  1180.                                     ? ""  
  1181.                                     : "alpha(opacity=" + value * 100 + ")"));   
  1182.                 }   
  1183.   
  1184.                 return elem.filter && elem.filter.indexOf("opacity=") >= 0  
  1185.                         ? (parseFloat(elem.filter.match(/opacity=([^)]*)/)[1]) / 100)   
  1186.                                 + ''  
  1187.                         : "";   
  1188.             }   
  1189.             // lamb字的支持   
  1190.             name = name.replace(/-([a-z])/ig, function(all, letter) {   
  1191.                 return letter.toUpperCase();   
  1192.             });   
  1193.   
  1194.             if (set)   
  1195.                 elem[name] = value;   
  1196.   
  1197.             return elem[name];   
  1198.         },   
  1199.   
  1200.         // trim(text)   
  1201.         trim : function(text) {   
  1202.             return (text || "").replace(/^\s+|\s+$/g, "");   
  1203.         },   
  1204.   
  1205.         // 把参数array转换成数组。有可能是dom collection,arguments,jquery对象   
  1206.         makeArray : function(array) {   
  1207.             var ret = [];   
  1208.   
  1209.             if (array != null) {   
  1210.                 var i = array.length;   
  1211.                 // the window, strings and functions also have 'length'   
  1212.                 if (i == null || array.split || array.setInterval || array.call)   
  1213.                     ret[0] = array;   
  1214.                 else  
  1215.                     while (i)   
  1216.                         ret[--i] = array[i];   
  1217.             }   
  1218.   
  1219.             return ret;   
  1220.         },   
  1221.   
  1222.         // 判断elem元素在array中的位置(index)   
  1223.         inArray : function(elem, array) {   
  1224.             for (var i = 0, length = array.length;i < length; i++)   
  1225.                 // Use === because on IE, window == document   
  1226.                 if (array[i] === elem)   
  1227.                     return i;   
  1228.             return -1;   
  1229.         },   
  1230.   
  1231.         // 把second 元素追加到first的数组中。   
  1232.         merge : function(first, second) {   
  1233.             // We have to loop this way because IE & Opera overwrite the length   
  1234.             // expando of getElementsByTagName   
  1235.             var i = 0, elem, pos = first.length;   
  1236.             // Also, we need to make sure that the correct elements are being   
  1237.             // returned   
  1238.             // (IE returns comment nodes in a '*' query)   
  1239.             if (jQuery.browser.msie) {   
  1240.                 while (elem = second[i++])   
  1241.                     if (elem.nodeType != 8)   
  1242.                         first[pos++] = elem;   
  1243.   
  1244.             } else  
  1245.                 while (elem = second[i++])   
  1246.                     first[pos++] = elem;   
  1247.   
  1248.             return first;   
  1249.         },   
  1250.   
  1251.         // 判断数组中的元素是否有重复的元素,返回不重复的所有元素。如Ext.DomQuery中的nodup一样处理   
  1252.         unique : function(array) {   
  1253.             var ret = [], done = {};   
  1254.   
  1255.             try {   
  1256.   
  1257.                 for (var i = 0, length = array.length;i < length; i++) {   
  1258.                     var id = jQuery.data(array[i]);   
  1259.   
  1260.                     if (!done[id]) {   
  1261.                         done[id] = true;   
  1262.                         ret.push(array[i]);   
  1263.                     }   
  1264.                 }   
  1265.   
  1266.             } catch (e) {   
  1267.                 ret = array;   
  1268.             }   
  1269.   
  1270.             return ret;   
  1271.         },   
  1272.   
  1273.         // 过滤elems中满足callback处理的所有元素   
  1274.         grep : function(elems, callback, inv) {   
  1275.             var ret = [];   
  1276.   
  1277.             // Go through the array, only saving the items   
  1278.             // that pass the validator function   
  1279.             for (var i = 0, length = elems.length;i < length; i++)   
  1280.                 if (!inv != !callback(elems[i], i))   
  1281.                     ret.push(elems[i]);   
  1282.   
  1283.             return ret;   
  1284.         },   
  1285.   
  1286.         // 返回对elems每个元素都进行操作的callback函数的返回值的集合。   
  1287.         map : function(elems, callback) {   
  1288.             var ret = [];   
  1289.   
  1290.             // Go through the array, translating each of the items to their   
  1291.             // new value (or values).   
  1292.             for (var i = 0, length = elems.length;i < length; i++) {   
  1293.                 var value = callback(elems[i], i);   
  1294.   
  1295.                 if (value != null)   
  1296.                     ret[ret.length] = value;   
  1297.             }   
  1298.   
  1299.             return ret.concat.apply([], ret);   
  1300.         }   
  1301.     });   
  1302.   
  1303. var userAgent = navigator.userAgent.toLowerCase();   
  1304.   
  1305. // 计算出浏览器的相关信息   
  1306. jQuery.browser = {   
  1307.     version : (userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [0'0'])[1],   
  1308.     safari : /webkit/.test(userAgent),   
  1309.     opera : /opera/.test(userAgent),   
  1310.     msie : /msie/.test(userAgent) && !/opera/.test(userAgent),   
  1311.     mozilla : /mozilla/.test(userAgent)   
  1312.             && !/(compatible|webkit)/.test(userAgent)   
  1313. };   
  1314.   
  1315. var styleFloat = jQuery.browser.msie ? "styleFloat" : "cssFloat";   
  1316.   
  1317. jQuery.extend( {   
  1318.   
  1319.     // 支持不支持boxModel?IE不支持   
  1320.         boxModel : !jQuery.browser.msie || document.compatMode == "CSS1Compat",   
  1321.   
  1322.         props : {   
  1323.             "for" : "htmlFor",   
  1324.             "class" : "className",   
  1325.             "float" : styleFloat,   
  1326.             cssFloat : styleFloat,   
  1327.             styleFloat : styleFloat,   
  1328.             readonly : "readOnly",   
  1329.             maxlength : "maxLength",   
  1330.             cellspacing : "cellSpacing",   
  1331.             rowspan : "rowSpan"  
  1332.         }   
  1333.     });   
  1334.   
  1335. // 一组对元素的相关节点的操作,如父,子,兄节点等   
  1336. jQuery.each( {   
  1337.     parent : function(elem) {// 父亲节点   
  1338.             return elem.parentNode;   
  1339.         },   
  1340.         parents : function(elem) {// elem的所有parentNode   
  1341.             return jQuery.dir(elem, "parentNode");   
  1342.         },   
  1343.         next : function(elem) {// 元素的下一个兄弟   
  1344.             return jQuery.nth(elem, 2"nextSibling");   
  1345.         },   
  1346.         prev : function(elem) {// 前一个兄弟   
  1347.             return jQuery.nth(elem, 2"previousSibling");   
  1348.         },   
  1349.         nextAll : function(elem) {// 所有后继兄弟   
  1350.             return jQuery.dir(elem, "nextSibling");   
  1351.         },   
  1352.         prevAll : function(elem) {// 所有前继兄弟   
  1353.             return jQuery.dir(elem, "previousSibling");   
  1354.         },   
  1355.         siblings : function(elem) {// 所有兄弟   
  1356.             return jQuery.sibling(elem.parentNode.firstChild, elem);   
  1357.         },   
  1358.         children : function(elem) {// 所有孩子   
  1359.             return jQuery.sibling(elem.firstChild);   
  1360.         },   
  1361.         contents : function(elem) {// iframe?就是文档,或者所有子节点   
  1362.             return jQuery.nodeName(elem, "iframe") ? elem.contentDocument   
  1363.                     || elem.contentWindow.document : jQuery   
  1364.                     .makeArray(elem.childNodes);   
  1365.         }   
  1366.     }, function(name, fn) {// 注册到jQuery对象中去,可以调用同名方法   
  1367.             jQuery.fn[name] = function(selector) {   
  1368.                 var ret = jQuery.map(this, fn);// 每个元素都执行同名方法   
  1369.                 if (selector && typeof selector == "string")   
  1370.                     ret = jQuery.multiFilter(selector, ret);// 过滤元素集   
  1371.                 return this.pushStack(jQuery.unique(ret));// 构建jQuery对象   
  1372.             };   
  1373.         });   
  1374.   
  1375. // 为jQuery对象生成appendTo~replaceAll五个代理函数   
  1376. // 其功能是把当前的jquery对象的每个元素都插入到每个传入的参数(元素)的一个位置:   
  1377. // 之前,之后,开始,结束,overwrite   
  1378.   
  1379. jQuery.each( {   
  1380.     appendTo : "append",   
  1381.     prependTo : "prepend",   
  1382.     insertBefore : "before",   
  1383.     insertAfter : "after",   
  1384.     replaceAll : "replaceWith"  
  1385. }, function(name, original) {   
  1386.     jQuery.fn[name] = function() {   
  1387.         var args = arguments;// 每个参数和每个元素是对应起来的   
  1388.         // 对当前jQuery中每个元素都进行的操作   
  1389.         return this.each(function() {   
  1390.             for (var i = 0, length = args.length;i < length; i++)   
  1391.                 jQuery(args[i])[original](this);// 调用original代理工作   
  1392.             });   
  1393.     };   
  1394. });   
  1395.   
  1396. // 一组对元素attr,class等进行操作的函数   
  1397. jQuery.each( {   
  1398.     removeAttr : function(name) {// 除去元素的一个属性   
  1399.             jQuery.attr(this, name, "");   
  1400.             if (this.nodeType == 1)   
  1401.                 this.removeAttribute(name);   
  1402.         },   
  1403.   
  1404.         addClass : function(classNames) {// 为元素增加一些classNames   
  1405.             jQuery.className.add(this, classNames);   
  1406.         },   
  1407.   
  1408.         removeClass : function(classNames) {// 除去元素的一些classNames   
  1409.             jQuery.className.remove(this, classNames);   
  1410.         },   
  1411.   
  1412.         toggleClass : function(classNames) {// 开关该class,   
  1413.             jQuery.className[jQuery.className.has(this, classNames)   
  1414.                     ? "remove"  
  1415.                     : "add"](this, classNames);   
  1416.         },   
  1417.   
  1418.         remove : function(selector) {// 根据selector除去元素,防内存泄露   
  1419.             if (!selector || jQuery.filter(selector, [this]).r.length) {   
  1420.                 // Prevent memory leaks   
  1421.                 jQuery("*"this).add([this]).each(function() {   
  1422.                     jQuery.event.remove(this);   
  1423.                     jQuery.removeData(this);   
  1424.                 });   
  1425.                 if (this.parentNode)   
  1426.                     this.parentNode.removeChild(this);   
  1427.             }   
  1428.         },   
  1429.         empty : function() {// 清除元素的所有子节点   
  1430.             // 删除当前对象的每个元素的的所有子节点,防止内存泄漏   
  1431.             jQuery(">*"this).remove();   
  1432.             while (this.firstChild)   
  1433.                 // 删除余留的子节点   
  1434.                 this.removeChild(this.firstChild);   
  1435.         }   
  1436.     }, function(name, fn) {   
  1437.         jQuery.fn[name] = function() {   
  1438.             return this.each(fn, arguments);   
  1439.         };   
  1440.     });   
  1441.   
  1442. // 为jQuery对象注册height,width方法   
  1443. jQuery   
  1444.         .each(   
  1445.                 ["Height""Width"],   
  1446.                 function(i, name) {   
  1447.                     var type = name.toLowerCase();   
  1448.   
  1449.                     jQuery.fn[type] = function(size) {   
  1450.                         // window的宽度和高度   
  1451.                         return this[0] == window ? (// window的宽度和高度   
  1452.                                 jQuery.browser.opera   
  1453.                                         && document.body["client" + name]   
  1454.                                         || jQuery.browser.safari   
  1455.                                         && window["inner" + name]   
  1456.                                         || document.compatMode == "CSS1Compat"  
  1457.                                         && document.documentElement["client"  
  1458.                                                 + name] || document.body["client"  
  1459.                                         + name])   
  1460.                                 : this[0] == document ? (// document的宽度和高度   
  1461.                                         Math   
  1462.                                                 .max(   
  1463.                                                         Math   
  1464.                                                                 .max(   
  1465.                                                                         document.body["scroll"  
  1466.                                                                                 + name],   
  1467.                                                                         document.documentElement["scroll"  
  1468.                                                                                 + name]),   
  1469.                                                         Math   
  1470.                                                                 .max(   
  1471.                                                                         document.body["offset"  
  1472.                                                                                 + name],   
  1473.                                                                         document.documentElement["offset"  
  1474.                                                                                 + name])))   
  1475.                                         : (size == undefined ? (// 第一个元素的的宽度和高度   
  1476.                                                 this.length ? jQuery.css(   
  1477.                                                         this[0], type) : null)   
  1478.                                                 : (// 设定当前对象所有元素宽度和高度   
  1479.                                                 this  
  1480.                                                         .css(   
  1481.                                                                 type,   
  1482.                                                                 size.constructor == String   
  1483.                                                                         ? size   
  1484.                                                                         : size   
  1485.                                                                                 + "px")));   
  1486.                     };   
  1487.                 });   
  1488.   
  1489. // Helper function used by the dimensions and offset modules   
  1490. function num(elem, prop) {   
  1491.     return elem[0] && parseInt(jQuery.curCSS(elem[0], prop, true), 10) || 0;   
  1492. }