diff --git a/web/static/script/jquery-1.7.2.js b/web/static/script/jquery-1.7.2.js index b02dff2..3f17540 100644 --- a/web/static/script/jquery-1.7.2.js +++ b/web/static/script/jquery-1.7.2.js @@ -2000,249 +2000,297 @@ + // 正则表达式,用于检测字符串是否为有效的 JSON 对象或数组 var rbrace = /^(?:\{.*\}|\[.*\])$/, - rmultiDash = /([A-Z])/g; +// 正则表达式,用于匹配大写字母 + rmultiDash = /([A-Z])/g; -jQuery.extend({ - cache: {}, - - // Please use with caution - uuid: 0, - - // Unique for each copy of jQuery on the page - // Non-digits removed to match rinlinejQuery - expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), +// 扩展 jQuery 对象,添加新属性和方法 + jQuery.extend({ + // 用于缓存元素及其相关数据的对象 + cache: {}, + + // 唯一标识符,每次调用会递增 + // 请谨慎使用 + uuid: 0, + + // 页面上每个 jQuery 实例的唯一标识符 + // 使用了随机数去除非数字字符,以匹配 rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // 以下元素如果尝试添加 expando 属性,会引发无法捕获的异常 + noData: { + // 禁止在 embed 元素上设置 expando 属性 + "embed": true, + // 除 Flash 外,禁止在所有对象上设置 expando 属性 + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + // 禁止在 applet 元素上设置 expando 属性 + "applet": true + }, - // The following elements throw uncatchable exceptions if you - // attempt to add expando properties to them. - noData: { - "embed": true, - // Ban all objects except for Flash (which handle expandos) - "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", - "applet": true - }, + // 检查指定元素是否包含数据 + hasData: function( elem ) { + // 如果 elem 是一个节点,则从缓存中获取相应的数据 + // 否则直接从 elem 的 expando 属性中获取数据 + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + // 如果 elem 存在且不是空数据对象,则返回 true + return !!elem && !isEmptyDataObject( elem ); + }, - hasData: function( elem ) { - elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; - return !!elem && !isEmptyDataObject( elem ); - }, + // 定义 data 函数,用于在元素或对象上存储或获取数据 + data: function( elem, name, data, pvt /* 内部使用 */ ) { + // 检查元素是否可以接受数据,如果不可以则返回 + if ( !jQuery.acceptData( elem ) ) { + return; + } - data: function( elem, name, data, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } + var privateCache, thisCache, ret, + internalKey = jQuery.expando, // 获取唯一标识符 + getByName = typeof name === "string", // 检查 name 是否为字符串 - var privateCache, thisCache, ret, - internalKey = jQuery.expando, - getByName = typeof name === "string", + // 处理 DOM 节点和 JS 对象的不同情况,因为 IE6-7 + // 无法在 DOM 和 JS 边界之间正确进行垃圾回收 + isNode = elem.nodeType, // 判断 elem 是否为 DOM 节点 - // We have to handle DOM nodes and JS objects differently because IE6-7 - // can't GC object references properly across the DOM-JS boundary - isNode = elem.nodeType, + // 只有 DOM 节点需要全局 jQuery 缓存;JS 对象的数据 + // 直接附加到对象上,因此可以自动进行垃圾回收 + cache = isNode ? jQuery.cache : elem, // 根据 elem 类型选择缓存 - // Only DOM nodes need the global jQuery cache; JS object data is - // attached directly to the object so GC can occur automatically - cache = isNode ? jQuery.cache : elem, + // 只有当 JS 对象的缓存已经存在时,才为其定义 ID, + // 这样可以让代码在没有缓存的 DOM 节点路径上快速处理 + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey, + isEvents = name === "events"; // 检查 name 是否等于 "events" - // Only defining an ID for JS objects if its cache already exists allows - // the code to shortcut on the same path as a DOM node with no cache - id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey, - isEvents = name === "events"; + // 在尝试获取没有数据的对象时,避免做不必要的工作 + if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) { + return; // 如果没有找到数据或条件不满足,返回 + } - // Avoid doing any more work than we need to when trying to get data on an - // object that has no data at all - if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) { - return; - } - if ( !id ) { - // Only DOM nodes need a new unique ID for each element since their data - // ends up in the global cache - if ( isNode ) { - elem[ internalKey ] = id = ++jQuery.uuid; - } else { - id = internalKey; + if ( !id ) { + // 只有 DOM 节点需要为每个元素生成一个新的唯一 ID + // 因为它们的数据最终会存储在全局缓存中 + if ( isNode ) { + elem[ internalKey ] = id = ++jQuery.uuid; // 为 DOM 节点分配唯一的 ID + } else { + id = internalKey; // 对于非 DOM 对象,使用内部键作为 ID + } } - } - if ( !cache[ id ] ) { - cache[ id ] = {}; + if ( !cache[ id ] ) { + cache[ id ] = {}; // 初始化缓存对象,如果该 ID 的缓存不存在 - // Avoids exposing jQuery metadata on plain JS objects when the object - // is serialized using JSON.stringify - if ( !isNode ) { - cache[ id ].toJSON = jQuery.noop; + // 避免在使用 JSON.stringify 序列化普通 JS 对象时暴露 jQuery 元数据 + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; // 如果不是 DOM 节点,则定义 toJSON 方法为无操作 + } } - } - // An object can be passed to jQuery.data instead of a key/value pair; this gets - // shallow copied over onto the existing cache - if ( typeof name === "object" || typeof name === "function" ) { - if ( pvt ) { - cache[ id ] = jQuery.extend( cache[ id ], name ); - } else { - cache[ id ].data = jQuery.extend( cache[ id ].data, name ); +// 可以将一个对象传递给 jQuery.data,而不是键/值对; +// 这个对象会被浅拷贝到现有的缓存中 + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + // 如果是私有数据,则直接扩展当前 ID 的缓存 + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + // 否则,将数据扩展到现有的 data 属性上 + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } } - } - privateCache = thisCache = cache[ id ]; - // jQuery data() is stored in a separate object inside the object's internal data - // cache in order to avoid key collisions between internal data and user-defined - // data. - if ( !pvt ) { - if ( !thisCache.data ) { - thisCache.data = {}; - } + privateCache = thisCache = cache[ id ]; // 初始化 privateCache 和 thisCache,指向指定 ID 的缓存对象 - thisCache = thisCache.data; - } +// jQuery 的 data() 方法存储在对象内部数据缓存中的一个单独对象中 +// 以避免内部数据和用户定义数据之间的键冲突。 + if ( !pvt ) { + // 如果不是私有数据,则为 thisCache 初始化一个 data 对象 + if ( !thisCache.data ) { + thisCache.data = {}; // 创建一个空的数据对象 + } - if ( data !== undefined ) { - thisCache[ jQuery.camelCase( name ) ] = data; - } + thisCache = thisCache.data; // 将 thisCache 指向 data 对象 + } - // Users should not attempt to inspect the internal events object using jQuery.data, - // it is undocumented and subject to change. But does anyone listen? No. - if ( isEvents && !thisCache[ name ] ) { - return privateCache.events; - } +// 如果 data 参数不为 undefined,则将其存储在 thisCache 中 + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; // 使用驼峰命名法格式化名称,并赋值 + } - // Check for both converted-to-camel and non-converted data property names - // If a data property was specified - if ( getByName ) { +// 用户不应尝试通过 jQuery.data 检查内部事件对象, +// 该对象未记录并可能会更改。但真的有人听从吗?没有。 + if ( isEvents && !thisCache[ name ] ) { + return privateCache.events; // 如果是事件并且 thisCache 中不存在该名称,则返回 privateCache 的 events + } - // First Try to find as-is property data - ret = thisCache[ name ]; +// 检查数据属性名称,既包括未转换的原始名称也包括转换为驼峰命名法的名称 +// 如果指定了数据属性 + if ( getByName ) { - // Test for null|undefined property data - if ( ret == null ) { + // 首先尝试查找原始名称对应的数据属性 + ret = thisCache[ name ]; - // Try to find the camelCased property - ret = thisCache[ jQuery.camelCase( name ) ]; + // 测试获取到的属性数据是否为 null 或 undefined + if ( ret == null ) { + // 尝试查找驼峰命名法格式化后的属性 + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + // 如果没有指定获取名称,直接返回 thisCache + ret = thisCache; } - } else { - ret = thisCache; - } - return ret; - }, +// 返回结果 + return ret; + }, - removeData: function( elem, name, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } + removeData: function( elem, name, pvt /* 仅供内部使用 */ ) { + // 检查元素是否可以接受数据 + if ( !jQuery.acceptData( elem ) ) { + return; // 如果不能接受数据,则退出 + } - var thisCache, i, l, + var thisCache, i, l, // 声明变量以用于后续操作 - // Reference to internal data cache key - internalKey = jQuery.expando, - isNode = elem.nodeType, + // 内部数据缓存的键引用 + internalKey = jQuery.expando, - // See jQuery.data for more information - cache = isNode ? jQuery.cache : elem, +// 检查元素类型,确定是否为节点 + isNode = elem.nodeType, - // See jQuery.data for more information - id = isNode ? elem[ internalKey ] : internalKey; +// 根据元素类型选择缓存对象,节点使用 jQuery.cache,其他元素直接使用 elem + cache = isNode ? jQuery.cache : elem, - // If there is already no cache entry for this object, there is no - // purpose in continuing - if ( !cache[ id ] ) { - return; - } +// 获取元素的唯一标识符,如果是节点,则从元素中获取 internalKey,否则使用 internalKey 本身 + id = isNode ? elem[ internalKey ] : internalKey; - if ( name ) { +// 如果该对象已经没有缓存条目,继续执行没有意义 + if ( !cache[ id ] ) { + return; // 退出函数 + } - thisCache = pvt ? cache[ id ] : cache[ id ].data; +// 如果指定了名称(name),则根据 pvt 选择不同的数据缓存 + if ( name ) { + // 根据是否是私有数据选择对应的缓存 + thisCache = pvt ? cache[ id ] : cache[ id ].data; - if ( thisCache ) { - // Support array or space separated string names for data keys - if ( !jQuery.isArray( name ) ) { + // 检查 thisCache 是否存在 + if ( thisCache ) { - // try the string as a key before any manipulation - if ( name in thisCache ) { - name = [ name ]; - } else { + // 支持数组或以空格分隔的字符串作为数据键名 + if ( !jQuery.isArray( name ) ) { - // split the camel cased version by spaces unless a key with the spaces exists - name = jQuery.camelCase( name ); + // 尝试将字符串作为键值直接访问,如果存在,则将其转换为数组 if ( name in thisCache ) { - name = [ name ]; + name = [ name ]; // 将单个键封装成数组 } else { - name = name.split( " " ); + // 对名称进行驼峰命名法处理,并再次检查该键是否存在于 thisCache 中 + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; // 如果存在,封装成数组 + } else { + // 如果仍然不存在,按空格分割字符串为多个键名 + name = name.split( " " ); + } } } - } - for ( i = 0, l = name.length; i < l; i++ ) { - delete thisCache[ name[i] ]; - } + // 遍历所有要删除的键名,并从 thisCache 中删除对应的条目 + for ( i = 0, l = name.length; i < l; i++ ) { + delete thisCache[ name[i] ]; + } - // If there is no data left in the cache, we want to continue - // and let the cache object itself get destroyed - if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { - return; + // 如果缓存中没有剩余的数据,我们希望继续执行并让缓存对象本身被销毁 + if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { + return; // 如果缓存不为空,则退出函数 + } } - } } - // See jQuery.data for more information - if ( !pvt ) { - delete cache[ id ].data; - - // Don't destroy the parent cache unless the internal data object - // had been the only thing left in it - if ( !isEmptyDataObject(cache[ id ]) ) { - return; + // See jQuery.data for more information +// 首先判断pvt是否为假(即不存在或值为false等情况) + if (!pvt) { + // 如果pvt不存在,从名为cache的对象中,根据id删除其data属性 + delete cache[id].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + // 以下判断表示,只有当cache[id]这个对象内部的数据对象(也就是刚删除data属性后的cache[id])已经为空(即除了刚删除的data属性外没别的内容了)时,才继续往下执行删除整个cache[id]的操作; + // 如果cache[id]还有其他属性等内容存在,就直接返回(不进行后续删除整个cache[id]的操作) + if (!isEmptyDataObject(cache[id])) { + return; + } } - } - // Browsers that fail expando deletion also refuse to delete expandos on - // the window, but it will allow it on all other JS objects; other browsers - // don't care - // Ensure that `cache` is not a window object #10080 - if ( jQuery.support.deleteExpando || !cache.setInterval ) { - delete cache[ id ]; - } else { - cache[ id ] = null; - } - - // We destroyed the cache and need to eliminate the expando on the node to avoid - // false lookups in the cache for entries that no longer exist - if ( isNode ) { - // IE does not allow us to delete expando properties from nodes, - // nor does it have a removeAttribute function on Document nodes; - // we must handle all of these cases - if ( jQuery.support.deleteExpando ) { - delete elem[ internalKey ]; - } else if ( elem.removeAttribute ) { - elem.removeAttribute( internalKey ); +// Browsers that fail expando deletion also refuse to delete expandos on +// the window, but it will allow it on all other JS objects; other browsers +// don't care +// Ensure that `cache` is not a window object #10080 +// 这里进行条件判断,目的是决定如何处理从cache对象中删除以id为键的元素 +// 如果浏览器支持删除扩展属性(jQuery.support.deleteExpando为真)或者cache对象不存在setInterval属性(意味着它不是window对象,因为window对象有setInterval方法) + if (jQuery.support.deleteExpando ||!cache.setInterval) { + // 那么直接从cache对象中删除以id为键的这个元素 + delete cache[id]; } else { - elem[ internalKey ] = null; + // 否则(也就是不满足上述条件,可能是浏览器不支持删除扩展属性且cache对象是window对象这种情况),将cache[id]赋值为null,相当于进行一种间接的“清除”处理(虽然不能直接删除window对象上的属性,但可以通过赋值为null来达到类似效果) + cache[id] = null; + } + + // We destroyed the cache and need to eliminate the expando on the node to avoid +// false lookups in the cache for entries that no longer exist +// 这段注释说明,当缓存已经被销毁时,需要移除节点上的扩展属性(expando),以避免在缓存中对已不存在的条目进行错误查找。 + if (isNode) { + // 如果当前元素是节点(isNode为真),以下代码处理不同浏览器环境下移除节点上特定扩展属性的情况。 + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + // 如果浏览器支持删除扩展属性(jQuery.support.deleteExpando为真) + if (jQuery.support.deleteExpando) { + // 直接从elem元素对象上删除名为internalKey的属性(这个internalKey应该是用于存储某种扩展数据相关的键) + delete elem[internalKey]; + } else if (elem.removeAttribute) { + // 如果不支持直接删除扩展属性,但elem元素有removeAttribute方法, + // 则使用removeAttribute方法来移除名为internalKey的属性,达到类似效果。 + elem.removeAttribute(internalKey); + } else { + // 如果前面两种情况都不满足(既不支持直接删除扩展属性,也没有removeAttribute方法可用), + // 则将elem[internalKey]赋值为null,进行一种间接的“清除”处理,尽量避免后续可能出现的问题。 + elem[internalKey] = null; + } } - } - }, + }, - // For internal use only. - _data: function( elem, name, data ) { - return jQuery.data( elem, name, data, true ); - }, +// For internal use only. +// 以下方法被标记为仅供内部使用,从函数的实现来看,它实际上是调用了jQuery.data方法,并传入了额外的参数true, +// 具体功能应该和jQuery.data相关联,可能在内部处理数据时有一些特殊逻辑。 + _data: function(elem, name, data) { + return jQuery.data(elem, name, data, true); + }, - // A method for determining if a DOM node can handle the data expando - acceptData: function( elem ) { - if ( elem.nodeName ) { - var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; +// A method for determining if a DOM node can handle the data expando +// 这个方法用于判断一个DOM节点是否能够处理数据扩展属性(data expando)。 + acceptData: function(elem) { + if (elem.nodeName) { + // 获取elem节点名称的小写形式对应的在jQuery.noData对象中的匹配项, + // jQuery.noData应该是一个存储了哪些节点名称不适合处理数据扩展属性相关信息的对象。 + var match = jQuery.noData[elem.nodeName.toLowerCase()]; - if ( match ) { - return !(match === true || elem.getAttribute("classid") !== match); + if (match) { + // 如果存在匹配项,根据匹配项的值来返回判断结果。 + // 如果match为true或者elem节点的classid属性值不等于match时,返回false,表示该节点不能处理数据扩展属性; + // 否则返回true。 + return!(match === true || elem.getAttribute("classid")!== match); + } } + + // 如果前面没有匹配到不适合处理的情况或者节点本身没有节点名称(elem.nodeName不存在),默认返回true,表示可以处理数据扩展属性。 + return true; } + }); + - return true; - } -}); jQuery.fn.extend({ data: function( key, value ) {