diff --git a/web/static/script/jquery-1.7.2.js b/web/static/script/jquery-1.7.2.js index 64b566a..0bb8b16 100644 --- a/web/static/script/jquery-1.7.2.js +++ b/web/static/script/jquery-1.7.2.js @@ -7840,8 +7840,8 @@ * - finds the right dataType (mediates between content-type and expected dataType) * - returns the corresponding response */ - function ajaxHandleResponses( s, jqXHR, responses ) { - + // 函数用于处理 AJAX 请求的响应 + function ajaxHandleResponses(s, jqXHR, responses) { var contents = s.contents, dataTypes = s.dataTypes, responseFields = s.responseFields, @@ -7850,66 +7850,64 @@ finalDataType, firstDataType; - // Fill responseXXX fields - for ( type in responseFields ) { - if ( type in responses ) { - jqXHR[ responseFields[type] ] = responses[ type ]; + // 遍历 responseFields 并将响应数据存储到 jqXHR 的相应属性中 + for (type in responseFields) { + if (type in responses) { + jqXHR[responseFields[type]] = responses[type]; } } - // Remove auto dataType and get content-type in the process - while( dataTypes[ 0 ] === "*" ) { + // 移除自动数据类型,并在过程中获取内容类型 + while (dataTypes[0] === "*") { dataTypes.shift(); - if ( ct === undefined ) { - ct = s.mimeType || jqXHR.getResponseHeader( "content-type" ); + if (ct === undefined) { + ct = s.mimeType || jqXHR.getResponseHeader("content-type"); } } - // Check if we're dealing with a known content-type - if ( ct ) { - for ( type in contents ) { - if ( contents[ type ] && contents[ type ].test( ct ) ) { - dataTypes.unshift( type ); + // 检查是否是已知的内容类型 + if (ct) { + for (type in contents) { + if (contents[type] && contents[type].test(ct)) { + dataTypes.unshift(type); break; } } } - // Check to see if we have a response for the expected dataType - if ( dataTypes[ 0 ] in responses ) { - finalDataType = dataTypes[ 0 ]; + // 检查是否有期望数据类型的响应 + if (dataTypes[0] in responses) { + finalDataType = dataTypes[0]; } else { - // Try convertible dataTypes - for ( type in responses ) { - if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) { + // 尝试可转换的数据类型 + for (type in responses) { + if (!dataTypes[0] || s.converters[type + " " + dataTypes[0]]) { finalDataType = type; break; } - if ( !firstDataType ) { + if (!firstDataType) { firstDataType = type; } } - // Or just use first one + // 或者仅使用第一个数据类型 finalDataType = finalDataType || firstDataType; } - // If we found a dataType - // We add the dataType to the list if needed - // and return the corresponding response - if ( finalDataType ) { - if ( finalDataType !== dataTypes[ 0 ] ) { - dataTypes.unshift( finalDataType ); + // 如果找到了数据类型 + // 如果需要,将数据类型添加到列表中并返回相应的响应 + if (finalDataType) { + if (finalDataType!== dataTypes[0]) { + dataTypes.unshift(finalDataType); } - return responses[ finalDataType ]; + return responses[finalDataType]; } } -// Chain conversions given the request and the original response - function ajaxConvert( s, response ) { - - // Apply the dataFilter if provided - if ( s.dataFilter ) { - response = s.dataFilter( response, s.dataType ); +// 根据请求和原始响应进行链式转换 + function ajaxConvert(s, response) { + // 如果提供了数据过滤器,则应用数据过滤器 + if (s.dataFilter) { + response = s.dataFilter(response, s.dataType); } var dataTypes = s.dataTypes, @@ -7918,56 +7916,53 @@ key, length = dataTypes.length, tmp, - // Current and previous dataTypes - current = dataTypes[ 0 ], + // 当前和之前的数据类型 + current = dataTypes[0], prev, - // Conversion expression + // 转换表达式 conversion, - // Conversion function + // 转换函数 conv, - // Conversion functions (transitive conversion) + // 转换函数(传递转换) conv1, conv2; - // For each dataType in the chain - for ( i = 1; i < length; i++ ) { - - // Create converters map - // with lowercased keys - if ( i === 1 ) { - for ( key in s.converters ) { - if ( typeof key === "string" ) { - converters[ key.toLowerCase() ] = s.converters[ key ]; + // 对于链中的每个数据类型 + for (i = 1; i < length; i++) { + // 创建转换器映射,使用小写键 + if (i === 1) { + for (key in s.converters) { + if (typeof key === "string") { + converters[key.toLowerCase()] = s.converters[key]; } } } - // Get the dataTypes + // 获取数据类型 prev = current; - current = dataTypes[ i ]; + current = dataTypes[i]; - // If current is auto dataType, update it to prev - if ( current === "*" ) { + // 如果当前是自动数据类型,将其更新为 prev + if (current === "*") { current = prev; - // If no auto and dataTypes are actually different - } else if ( prev !== "*" && prev !== current ) { - - // Get the converter + // 如果不是自动数据类型且数据类型不同 + } else if (prev!== "*" && prev!== current) { + // 获取转换器 conversion = prev + " " + current; - conv = converters[ conversion ] || converters[ "* " + current ]; + conv = converters[conversion] || converters["* " + current]; - // If there is no direct converter, search transitively - if ( !conv ) { + // 如果没有直接的转换器,进行传递搜索 + if (!conv) { conv2 = undefined; - for ( conv1 in converters ) { - tmp = conv1.split( " " ); - if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) { - conv2 = converters[ tmp[1] + " " + current ]; - if ( conv2 ) { - conv1 = converters[ conv1 ]; - if ( conv1 === true ) { + for (conv1 in converters) { + tmp = conv1.split(" "); + if (tmp[0] === prev || tmp[0] === "*") { + conv2 = converters[tmp[1] + " " + current]; + if (conv2) { + conv1 = converters[conv1]; + if (conv1 === true) { conv = conv2; - } else if ( conv2 === true ) { + } else if (conv2 === true) { conv = conv1; } break; @@ -7975,14 +7970,14 @@ } } } - // If we found no converter, dispatch an error - if ( !( conv || conv2 ) ) { - jQuery.error( "No conversion from " + conversion.replace(" "," to ") ); + // 如果没有找到转换器,发出错误 + if (!(conv || conv2)) { + jQuery.error("No conversion from " + conversion.replace(" ", " to ")); } - // If found converter is not an equivalence - if ( conv !== true ) { - // Convert with 1 or 2 converters accordingly - response = conv ? conv( response ) : conv2( conv1(response) ); + // 如果找到的转换器不是等价的 + if (conv!== true) { + // 相应地使用 1 或 2 个转换器进行转换 + response = conv? conv(response) : conv2(conv1(response)); } } } @@ -7996,39 +7991,48 @@ jsre = /(\=)\?(&|$)|\?\?/i; // Default jsonp settings + // 使用 jQuery.ajaxSetup 配置全局的 AJAX 设置 jQuery.ajaxSetup({ + // 定义 jsonp 的参数名 jsonp: "callback", - jsonpCallback: function() { - return jQuery.expando + "_" + ( jsc++ ); + // 定义 jsonpCallback 函数,生成一个唯一的回调函数名 + jsonpCallback: function () { + return jQuery.expando + "_" + (jsc++); } }); // Detect, normalize options and install callbacks for jsonp requests - jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { - - var inspectData = ( typeof s.data === "string" ) && /^application\/x\-www\-form\-urlencoded/.test( s.contentType ); +// 使用 jQuery.ajaxPrefilter 对 json 和 jsonp 类型的请求进行预处理 + jQuery.ajaxPrefilter("json jsonp", function (s, originalSettings, jqXHR) { + // 检查 s.data 是否为字符串且内容类型是否为 application/x-www-form-urlencoded + var inspectData = (typeof s.data === "string") && /^application\/x-www-form-urlencoded/.test(s.contentType); - if ( s.dataTypes[ 0 ] === "jsonp" || - s.jsonp !== false && ( jsre.test( s.url ) || - inspectData && jsre.test( s.data ) ) ) { + // 如果数据类型为 jsonp 或 jsonp 不为 false 且 url 或 data 中包含 jsonp 回调参数 + if (s.dataTypes[0] === "jsonp" || + s.jsonp!== false && (jsre.test(s.url) || + inspectData && jsre.test(s.data))) { var responseContainer, + // 获取或生成 jsonpCallback 函数 jsonpCallback = s.jsonpCallback = - jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback, - previous = window[ jsonpCallback ], + jQuery.isFunction(s.jsonpCallback)? s.jsonpCallback() : s.jsonpCallback, + // 存储之前的 jsonpCallback 函数 + previous = window[jsonpCallback], url = s.url, data = s.data, replace = "$1" + jsonpCallback + "$2"; - if ( s.jsonp !== false ) { - url = url.replace( jsre, replace ); - if ( s.url === url ) { - if ( inspectData ) { - data = data.replace( jsre, replace ); + if (s.jsonp!== false) { + // 替换 url 中的 jsonp 回调参数 + url = url.replace(jsre, replace); + if (s.url === url) { + if (inspectData) { + // 替换 data 中的 jsonp 回调参数 + data = data.replace(jsre, replace); } - if ( s.data === data ) { - // Add callback manually - url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback; + if (s.data === data) { + // 手动添加 jsonp 回调参数到 url 中 + url += (/\?/.test(url)? "&" : "?") + s.jsonp + "=" + jsonpCallback; } } } @@ -8036,120 +8040,121 @@ s.url = url; s.data = data; - // Install callback - window[ jsonpCallback ] = function( response ) { - responseContainer = [ response ]; + // 安装回调函数 + window[jsonpCallback] = function (response) { + responseContainer = [response]; }; - // Clean-up function - jqXHR.always(function() { - // Set callback back to previous value - window[ jsonpCallback ] = previous; - // Call if it was a function and we have a response - if ( responseContainer && jQuery.isFunction( previous ) ) { - window[ jsonpCallback ]( responseContainer[ 0 ] ); + // 清理函数 + jqXHR.always(function () { + // 将回调函数恢复为之前的值 + window[jsonpCallback] = previous; + // 如果 responseContainer 存在且 previous 是函数,则调用回调函数 + if (responseContainer && jQuery.isFunction(previous)) { + window[jsonpCallback](responseContainer[0]); } }); - // Use data converter to retrieve json after script execution - s.converters["script json"] = function() { - if ( !responseContainer ) { - jQuery.error( jsonpCallback + " was not called" ); + // 使用数据转换器在脚本执行后获取 json 数据 + s.converters["script json"] = function () { + if (!responseContainer) { + jQuery.error(jsonpCallback + " was not called"); } - return responseContainer[ 0 ]; + return responseContainer[0]; }; - // force json dataType - s.dataTypes[ 0 ] = "json"; + // 强制使用 json 数据类型 + s.dataTypes[0] = "json"; - // Delegate to script + // 委托给 script 类型处理 return "script"; } }); - - // Install script dataType +// 使用 jQuery.ajaxSetup 配置 script 数据类型的相关设置 jQuery.ajaxSetup({ accepts: { + // 定义 script 类型可接受的内容类型 script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" }, contents: { + // 定义 script 类型的内容匹配正则表达式 script: /javascript|ecmascript/ }, converters: { - "text script": function( text ) { - jQuery.globalEval( text ); + // 定义 text 到 script 的数据转换器,执行全局的脚本评估 + "text script": function (text) { + jQuery.globalEval(text); return text; } } }); // Handle cache's special case and global - jQuery.ajaxPrefilter( "script", function( s ) { - if ( s.cache === undefined ) { + // 使用 jQuery.ajaxPrefilter 为 "script" 类型的请求添加预处理 + jQuery.ajaxPrefilter("script", function (s) { + // 如果未定义 s.cache,则将其设置为 false + if (s.cache === undefined) { s.cache = false; } - if ( s.crossDomain ) { + // 如果是跨域请求 + if (s.crossDomain) { + // 将请求类型设置为 GET s.type = "GET"; + // 将全局标志设置为 false s.global = false; } }); -// Bind script tag hack transport - jQuery.ajaxTransport( "script", function(s) { - - // This transport only deals with cross domain requests - if ( s.crossDomain ) { - +// 绑定 script 标签的 hack 传输方式 + jQuery.ajaxTransport("script", function (s) { + // 这个传输方式仅处理跨域请求 + if (s.crossDomain) { var script, - head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement; + // 获取文档的 head 元素 + head = document.head || document.getElementsByTagName("head")[0] || document.documentElement; return { - - send: function( _, callback ) { - - script = document.createElement( "script" ); - + send: function (_, callback) { + // 创建 script 元素 + script = document.createElement("script"); + // 设置 script 元素为异步加载 script.async = "async"; - - if ( s.scriptCharset ) { + // 如果设置了脚本字符集,将其设置到 script 元素上 + if (s.scriptCharset) { script.charset = s.scriptCharset; } - + // 设置 script 的 src 属性为请求的 url script.src = s.url; - // Attach handlers for all browsers - script.onload = script.onreadystatechange = function( _, isAbort ) { - - if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { - - // Handle memory leak in IE + // 为 script 元素添加 onload 和 onreadystatechange 事件处理函数 + script.onload = script.onreadystatechange = function (_, isAbort) { + // 如果是中止或者 script 的 readyState 不存在或为 loaded 或 complete 状态 + if (isAbort ||!script.readyState || /loaded|complete/.test(script.readyState)) { + // 处理 IE 的内存泄漏问题 script.onload = script.onreadystatechange = null; - - // Remove the script - if ( head && script.parentNode ) { - head.removeChild( script ); + // 移除 script 元素 + if (head && script.parentNode) { + head.removeChild(script); } - - // Dereference the script + // 解除对 script 的引用 script = undefined; - - // Callback if not abort - if ( !isAbort ) { - callback( 200, "success" ); + // 如果不是中止,调用回调函数 + if (!isAbort) { + callback(200, "success"); } } }; - // 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 ); + // 使用 insertBefore 代替 appendChild 以避免 IE6 的一个 bug + // 当使用 base 节点时会出现此问题 (#2709 和 #4378) + head.insertBefore(script, head.firstChild); }, - - abort: function() { - if ( script ) { - script.onload( 0, 1 ); + // abort 函数,用于中止请求 + abort: function () { + if (script) { + script.onload(0, 1); } } }; @@ -8159,295 +8164,306 @@ - var // #5280: Internet Explorer will keep connections alive if we don't abort on unload - xhrOnUnloadAbort = window.ActiveXObject ? function() { - // Abort all pending requests - for ( var key in xhrCallbacks ) { - xhrCallbacks[ key ]( 0, 1 ); + // #5280: Internet Explorer will keep connections alive if we don't abort on unload +// 定义 xhrOnUnloadAbort 函数,用于在页面卸载时中止所有挂起的请求(针对 IE) + var xhrOnUnloadAbort = window.ActiveXObject? function() { + // 中止所有挂起的请求 + for (var key in xhrCallbacks) { + xhrCallbacks[key](0, 1); } } : false, + // 存储 xhr 的唯一标识符 xhrId = 0, + // 存储 xhr 的回调函数 xhrCallbacks; // Functions to create xhrs +// 创建标准的 XHR 对象 function createStandardXHR() { try { return new window.XMLHttpRequest(); - } catch( e ) {} + } catch (e) {} } +// 创建 ActiveXHR 对象(用于 IE) function createActiveXHR() { try { - return new window.ActiveXObject( "Microsoft.XMLHTTP" ); - } catch( e ) {} + return new window.ActiveXObject("Microsoft.XMLHTTP"); + } catch (e) {} } // Create the request object // (This is still attached to ajaxSettings for backward compatibility) - jQuery.ajaxSettings.xhr = window.ActiveXObject ? - /* Microsoft failed to properly - * implement the XMLHttpRequest in IE7 (can't request local files), - * so we use the ActiveXObject when it is available - * Additionally XMLHttpRequest can be disabled in IE7/IE8 so - * we need a fallback. - */ +// 根据浏览器环境选择创建 XHR 对象的函数,并将其赋值给 jQuery.ajaxSettings.xhr + jQuery.ajaxSettings.xhr = window.ActiveXObject? + // Microsoft failed to properly implement the XMLHttpRequest in IE7 (can't request local files), + // so we use the ActiveXObject when it is available + // Additionally XMLHttpRequest can be disabled in IE7/IE8 so we need a fallback. function() { - return !this.isLocal && createStandardXHR() || createActiveXHR(); + return!this.isLocal && createStandardXHR() || createActiveXHR(); } : // For all other browsers, use the standard XMLHttpRequest object createStandardXHR; // Determine support properties - (function( xhr ) { - jQuery.extend( jQuery.support, { - ajax: !!xhr, - cors: !!xhr && ( "withCredentials" in xhr ) +// 扩展 jQuery.support 对象,判断浏览器对 ajax 和 cors 的支持情况 + (function (xhr) { + jQuery.extend(jQuery.support, { + ajax:!!xhr, + cors:!!xhr && ("withCredentials" in xhr) }); - })( jQuery.ajaxSettings.xhr() ); + })(jQuery.ajaxSettings.xhr()); // Create transport if the browser can provide an xhr - if ( jQuery.support.ajax ) { - - jQuery.ajaxTransport(function( s ) { +// 如果浏览器支持 xhr,则创建传输对象 + if (jQuery.support.ajax) { + jQuery.ajaxTransport(function (s) { // Cross domain only allowed if supported through XMLHttpRequest - if ( !s.crossDomain || jQuery.support.cors ) { - + // 仅当通过 XMLHttpRequest 支持跨域时才允许跨域请求 + if (!s.crossDomain || jQuery.support.cors) { var callback; return { - send: function( headers, complete ) { - - // Get a new xhr + send: function (headers, complete) { + // 获取一个新的 xhr 对象 var xhr = s.xhr(), handle, i; - // Open the socket - // Passing null username, generates a login popup on Opera (#2865) - if ( s.username ) { - xhr.open( s.type, s.url, s.async, s.username, s.password ); + // 打开请求连接 + // 传递空用户名会在 Opera 上触发登录弹窗 (#2865) + if (s.username) { + xhr.open(s.type, s.url, s.async, s.username, s.password); } else { - xhr.open( s.type, s.url, s.async ); + xhr.open(s.type, s.url, s.async); } - // Apply custom fields if provided - if ( s.xhrFields ) { - for ( i in s.xhrFields ) { - xhr[ i ] = s.xhrFields[ i ]; + // 应用自定义字段(如果提供) + if (s.xhrFields) { + for (i in s.xhrFields) { + xhr[i] = s.xhrFields[i]; } } - // Override mime type if needed - if ( s.mimeType && xhr.overrideMimeType ) { - xhr.overrideMimeType( s.mimeType ); + // 覆盖 MIME 类型(如果需要) + if (s.mimeType && xhr.overrideMimeType) { + xhr.overrideMimeType(s.mimeType); } // X-Requested-With header - // For cross-domain requests, seeing as conditions for a preflight are - // akin to a jigsaw puzzle, we simply never set it to be sure. - // (it can always be set on a per-request basis or even using ajaxSetup) - // For same-domain requests, won't change header if already provided. - if ( !s.crossDomain && !headers["X-Requested-With"] ) { - headers[ "X-Requested-With" ] = "XMLHttpRequest"; + // 对于跨域请求,由于预检条件比较复杂,我们通常不设置该头 + // 对于同域请求,如果未提供该头则设置 + if (!s.crossDomain &&!headers["X-Requested-With"]) { + headers["X-Requested-With"] = "XMLHttpRequest"; } // Need an extra try/catch for cross domain requests in Firefox 3 + // 在 Firefox 3 中进行跨域请求时需要额外的 try/catch try { - for ( i in headers ) { - xhr.setRequestHeader( i, headers[ i ] ); + // 遍历 headers 对象,为 xhr 设置请求头 + for (i in headers) { + xhr.setRequestHeader(i, headers[i]); } - } catch( _ ) {} + } catch (_) {} - // Do send the request - // This may raise an exception which is actually - // handled in jQuery.ajax (so no try/catch here) - xhr.send( ( s.hasContent && s.data ) || null ); - - // Listener - callback = function( _, isAbort ) { +// 发送请求 +// 这里可能会引发异常,实际上会在 jQuery.ajax 中处理,所以这里没有 try/catch + xhr.send((s.hasContent && s.data) || null); +// 监听器函数 + callback = function (_, isAbort) { var status, statusText, responseHeaders, responses, xml; - // Firefox throws exceptions when accessing properties - // of an xhr when a network error occured + // Firefox 在网络错误时访问 xhr 的属性会抛出异常 // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE) try { + // 如果 callback 存在且 (是中止状态或者 xhr 的 readyState 为 4) + if (callback && (isAbort || xhr.readyState === 4)) { - // Was never called and is aborted or complete - if ( callback && ( isAbort || xhr.readyState === 4 ) ) { - - // Only called once + // 只调用一次 callback = undefined; - // Do not keep as active anymore - if ( handle ) { + // 不再保持活跃状态 + if (handle) { xhr.onreadystatechange = jQuery.noop; - if ( xhrOnUnloadAbort ) { - delete xhrCallbacks[ handle ]; + if (xhrOnUnloadAbort) { + delete xhrCallbacks[handle]; } } - // If it's an abort - if ( isAbort ) { - // Abort it manually if needed - if ( xhr.readyState !== 4 ) { + // 如果是中止操作 + if (isAbort) { + // 如果需要,手动中止请求 + if (xhr.readyState!== 4) { xhr.abort(); } } else { + // 获取响应状态码 status = xhr.status; + // 获取所有响应头 responseHeaders = xhr.getAllResponseHeaders(); responses = {}; + // 获取响应的 XML 数据 xml = xhr.responseXML; - // Construct response list - if ( xml && xml.documentElement /* #4958 */ ) { + // 构建响应列表 + if (xml && xml.documentElement /* #4958 */) { responses.xml = xml; } - // When requesting binary data, IE6-9 will throw an exception - // on any attempt to access responseText (#11426) + // 当请求二进制数据时,IE6-9 尝试访问 responseText 会抛出异常 (#11426) try { responses.text = xhr.responseText; - } catch( _ ) { - } + } catch (_) {} - // Firefox throws an exception when accessing - // statusText for faulty cross-domain requests + // Firefox 访问跨域请求的 statusText 时会抛出异常 try { statusText = xhr.statusText; - } catch( e ) { - // We normalize with Webkit giving an empty statusText + } catch (e) { + // 标准化处理,Webkit 会给出空的 statusText statusText = ""; } - // Filter status for non standard behaviors + // 对非标准行为过滤状态 - // If the request is local and we have data: assume a success - // (success with no data won't get notified, that's the best we - // can do given current implementations) - if ( !status && s.isLocal && !s.crossDomain ) { - status = responses.text ? 200 : 404; - // IE - #1450: sometimes returns 1223 when it should be 204 - } else if ( status === 1223 ) { + // 如果请求是本地的且有数据:假设请求成功 + // (无数据的成功请求不会被通知,这是在当前实现下能做到的最好处理) + if (!status && s.isLocal &&!s.crossDomain) { + status = responses.text? 200 : 404; + // IE - #1450: 有时应返回 204 却返回 1223 + } else if (status === 1223) { status = 204; } } } - } catch( firefoxAccessException ) { - if ( !isAbort ) { - complete( -1, firefoxAccessException ); + } catch (firefoxAccessException) { + // 如果不是中止操作 + if (!isAbort) { + complete(-1, firefoxAccessException); } } - // Call complete if needed - if ( responses ) { - complete( status, statusText, responses, responseHeaders ); + // 如果需要,调用 complete 函数 + if (responses) { + complete(status, statusText, responses, responseHeaders); } }; - // if we're in sync mode or it's in cache - // and has been retrieved directly (IE6 & IE7) - // we need to manually fire the callback - if ( !s.async || xhr.readyState === 4 ) { +// 如果是同步模式或者在缓存中且直接获取到(IE6 和 IE7) +// 我们需要手动触发回调 + if (!s.async || xhr.readyState === 4) { callback(); } else { handle = ++xhrId; - if ( xhrOnUnloadAbort ) { - // Create the active xhrs callbacks list if needed - // and attach the unload handler - if ( !xhrCallbacks ) { + if (xhrOnUnloadAbort) { + // 如果需要,创建活跃的 xhrs 回调列表并添加 unload 处理器 + if (!xhrCallbacks) { xhrCallbacks = {}; - jQuery( window ).unload( xhrOnUnloadAbort ); + jQuery(window).unload(xhrOnUnloadAbort); } - // Add to list of active xhrs callbacks - xhrCallbacks[ handle ] = callback; + // 添加到活跃的 xhrs 回调列表 + xhrCallbacks[handle] = callback; } + // 设置 xhr 的 onreadystatechange 事件处理函数为 callback xhr.onreadystatechange = callback; } }, - abort: function() { - if ( callback ) { - callback(0,1); +// abort 函数,用于中止请求 + abort: function () { + if (callback) { + callback(0, 1); } - } - }; - } - }); - } + }; + // 存储元素的默认显示属性 var elemdisplay = {}, + // 存储 iframe 元素 iframe, iframeDoc, + // 用于匹配 toggle、show 或 hide 的正则表达式 rfxtypes = /^(?:toggle|show|hide)$/, + // 用于匹配数字和单位的正则表达式 rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i, + // 存储定时器 ID timerId, + // 存储不同类型动画涉及的属性数组 fxAttrs = [ - // height animations - [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ], - // width animations - [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ], - // opacity animations - [ "opacity" ] + // 高度相关动画涉及的属性 + ["height", "marginTop", "marginBottom", "paddingTop", "paddingBottom"], + // 宽度相关动画涉及的属性 + ["width", "marginLeft", "marginRight", "paddingLeft", "paddingRight"], + // 透明度相关动画涉及的属性 + ["opacity"] ], + // 存储当前动画的时间 fxNow; +// 扩展 jQuery.fn 对象 jQuery.fn.extend({ - show: function( speed, easing, callback ) { + show: function (speed, easing, callback) { var elem, display; - if ( speed || speed === 0 ) { - return this.animate( genFx("show", 3), speed, easing, callback ); + // 如果指定了速度(包括速度为 0) + if (speed || speed === 0) { + // 使用 animate 函数,根据 genFx 生成的显示属性进行动画显示操作,并指定速度、缓动和回调 + return this.animate(genFx("show", 3), speed, easing, callback); } else { - for ( var i = 0, j = this.length; i < j; i++ ) { - elem = this[ i ]; + // 遍历元素集合 + for (var i = 0, j = this.length; i < j; i++) { + elem = this[i]; - if ( elem.style ) { + if (elem.style) { + // 获取元素的显示样式 display = elem.style.display; - // Reset the inline display of this element to learn if it is - // being hidden by cascaded rules or not - if ( !jQuery._data(elem, "olddisplay") && display === "none" ) { + // 如果元素没有存储 "olddisplay" 数据且显示样式为 "none" + if (!jQuery._data(elem, "olddisplay") && display === "none") { + // 重置元素的显示样式为空字符串 display = elem.style.display = ""; } - // Set elements which have been overridden with display: none - // in a stylesheet to whatever the default browser style is - // for such an element - if ( (display === "" && jQuery.css(elem, "display") === "none") || - !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) { - jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) ); + // 如果元素的显示样式为空且 jQuery.css 显示为 "none" 或元素不在文档元素中 + if ((display === "" && jQuery.css(elem, "display") === "none") || + !jQuery.contains(elem.ownerDocument.documentElement, elem)) { + // 存储元素的默认显示样式 + jQuery._data(elem, "olddisplay", defaultDisplay(elem.nodeName)); } } } - // Set the display of most of the elements in a second loop - // to avoid the constant reflow - for ( i = 0; i < j; i++ ) { - elem = this[ i ]; + // 第二个循环设置元素的显示样式,避免频繁重排 + for (i = 0; i < j; i++) { + elem = this[i]; - if ( elem.style ) { + if (elem.style) { display = elem.style.display; - if ( display === "" || display === "none" ) { - elem.style.display = jQuery._data( elem, "olddisplay" ) || ""; + // 如果元素的显示样式为空或为 "none" + if (display === "" || display === "none") { + // 将元素的显示样式设置为存储的 "olddisplay" 数据或空字符串 + elem.style.display = jQuery._data(elem, "olddisplay") || ""; } } } + // 返回 jQuery 对象本身 return this; } - }, + } + }); hide: function( speed, easing, callback ) { + // 如果指定了速度(包括速度为 0) if ( speed || speed === 0 ) { + // 使用 animate 函数,根据 genFx 生成的隐藏属性进行动画隐藏操作,并指定速度、缓动和回调 return this.animate( genFx("hide", 3), speed, easing, callback); } else { @@ -8455,70 +8471,84 @@ i = 0, j = this.length; + // 遍历元素集合 for ( ; i < j; i++ ) { elem = this[i]; if ( elem.style ) { + // 获取元素的显示样式 display = jQuery.css( elem, "display" ); - if ( display !== "none" && !jQuery._data( elem, "olddisplay" ) ) { + // 如果元素当前显示样式不为 "none" 且元素没有存储 "olddisplay" 数据 + if ( display!== "none" &&!jQuery._data( elem, "olddisplay" ) ) { + // 存储元素的当前显示样式 jQuery._data( elem, "olddisplay", display ); } } } - // Set the display of the elements in a second loop - // to avoid the constant reflow + // 第二个循环设置元素的显示样式为 "none" + // 避免频繁的重排 for ( i = 0; i < j; i++ ) { if ( this[i].style ) { this[i].style.display = "none"; } } + // 返回 jQuery 对象本身 return this; } }, - // Save the old toggle function +// 保存旧的 toggle 函数 _toggle: jQuery.fn.toggle, toggle: function( fn, fn2, callback ) { var bool = typeof fn === "boolean"; + // 如果 fn 和 fn2 都是函数 if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) { + // 应用旧的 toggle 函数 this._toggle.apply( this, arguments ); } else if ( fn == null || bool ) { + // 遍历元素集合 this.each(function() { - var state = bool ? fn : jQuery(this).is(":hidden"); - jQuery(this)[ state ? "show" : "hide" ](); + var state = bool? fn : jQuery(this).is(":hidden"); + // 根据元素状态进行显示或隐藏操作 + jQuery(this)[ state? "show" : "hide" ](); }); } else { + // 使用 animate 函数,根据 genFx 生成的切换属性进行动画切换操作,并指定速度、缓动和回调 this.animate(genFx("toggle", 3), fn, fn2, callback); } + // 返回 jQuery 对象本身 return this; - }, + } fadeTo: function( speed, to, easing, callback ) { + // 过滤出隐藏的元素,将其不透明度设置为 0,显示它们,回到之前的状态,并执行动画 return this.filter(":hidden").css("opacity", 0).show().end() .animate({opacity: to}, speed, easing, callback); }, animate: function( prop, speed, easing, callback ) { + // 使用 jQuery.speed 函数生成动画的速度、缓动和回调等配置信息 var optall = jQuery.speed( speed, easing, callback ); + // 如果传入的 prop 是空对象,对每个元素调用 optall.complete 函数并传入 false 作为参数 if ( jQuery.isEmptyObject( prop ) ) { return this.each( optall.complete, [ false ] ); } - // Do not change referenced properties as per-property easing will be lost + // 扩展一个新的对象存储 prop,避免修改原有的引用,防止丢失每个属性的缓动设置 prop = jQuery.extend( {}, prop ); function doAnimation() { - // XXX 'this' does not always have a nodeName when running the - // test suite + // 在测试套件中,'this' 可能并不总是有 nodeName 属性 + // 如果 optall.queue 为 false,标记元素 if ( optall.queue === false ) { jQuery._mark( this ); } @@ -8530,30 +8560,33 @@ parts, start, end, unit, method; - // will store per property easing and be used to determine when an animation is complete + // 存储每个属性的缓动信息,并用于判断动画是否完成 opt.animatedProperties = {}; - // first pass over propertys to expand / normalize + // 第一次遍历属性,进行扩展和规范化处理 for ( p in prop ) { name = jQuery.camelCase( p ); - if ( p !== name ) { + if ( p!== name ) { + // 将转换后的属性名作为键,存储原属性值,并删除原属性键 prop[ name ] = prop[ p ]; delete prop[ p ]; } if ( ( hooks = jQuery.cssHooks[ name ] ) && "expand" in hooks ) { + // 使用 cssHooks 的 expand 方法扩展属性值 replace = hooks.expand( prop[ name ] ); delete prop[ name ]; - // not quite $.extend, this wont overwrite keys already present. - // also - reusing 'p' from above because we have the correct "name" + // 并非完全的 jQuery.extend,不会覆盖已有的键 + // 这里复用上面的 'p',因为我们有正确的 "name" for ( p in replace ) { - if ( ! ( p in prop ) ) { + if (! ( p in prop ) ) { prop[ p ] = replace[ p ]; } } } } + } for ( name in prop ) { val = prop[ name ];