diff --git a/web/static/script/jquery-1.7.2.js b/web/static/script/jquery-1.7.2.js index 714bbf4..b02dff2 100644 --- a/web/static/script/jquery-1.7.2.js +++ b/web/static/script/jquery-1.7.2.js @@ -1475,458 +1475,532 @@ - var // Static reference to slice - sliceDeferred = [].slice; - - jQuery.extend({ - - Deferred: function( func ) { - var doneList = jQuery.Callbacks( "once memory" ), - failList = jQuery.Callbacks( "once memory" ), - progressList = jQuery.Callbacks( "memory" ), - state = "pending", - lists = { - resolve: doneList, - reject: failList, - notify: progressList - }, - promise = { - done: doneList.add, - fail: failList.add, - progress: progressList.add, - - state: function() { - return state; + // 静态引用 slice 方法,用于数组切片 + var sliceDeferred = [].slice; + + jQuery.extend({ + // 定义 Deferred 函数,用于创建一个新的延迟对象 + Deferred: function( func ) { + // 创建三个回调列表:成功、失败和进度 + var doneList = jQuery.Callbacks("once memory"), // 成功回调列表,只能被调用一次,并保留内存 + failList = jQuery.Callbacks("once memory"), // 失败回调列表,同样只调用一次并保留内存 + progressList = jQuery.Callbacks("memory"), // 进度回调列表,可以多次调用并保留内存 + state = "pending", // 初始状态为“待处理” + lists = { + resolve: doneList, // 将成功列表绑定到 resolve + reject: failList, // 将失败列表绑定到 reject + notify: progressList // 将进度列表绑定到 notify }, - - // Deprecated - isResolved: doneList.fired, - isRejected: failList.fired, - - then: function( doneCallbacks, failCallbacks, progressCallbacks ) { - deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); - return this; - }, - always: function() { - deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); - return this; - }, - pipe: function( fnDone, fnFail, fnProgress ) { - return jQuery.Deferred(function( newDefer ) { - jQuery.each( { - done: [ fnDone, "resolve" ], - fail: [ fnFail, "reject" ], - progress: [ fnProgress, "notify" ] - }, function( handler, data ) { - var fn = data[ 0 ], - action = data[ 1 ], - returned; - if ( jQuery.isFunction( fn ) ) { - deferred[ handler ](function() { - returned = fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify ); - } else { - newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); - } - }); - } else { - deferred[ handler ]( newDefer[ action ] ); + promise = { // 定义 promise 对象 + done: doneList.add, // 添加成功回调的方法 + fail: failList.add, // 添加失败回调的方法 + progress: progressList.add, // 添加进度回调的方法 + + state: function () { // 返回当前状态的方法 + return state; // 返回状态 + }, + + // 已废弃的方法,检查是否已经解决 + isResolved: doneList.fired, // 检查成功回调是否已被调用 + isRejected: failList.fired, // 检查失败回调是否已被调用 + + then: function (doneCallbacks, failCallbacks, progressCallbacks) { + // 链式调用,将相应的回调添加到 deferred 对象 + deferred.done(doneCallbacks).fail(failCallbacks).progress(progressCallbacks); + return this; // 返回当前对象,以支持链式调用 + }, + always: function () { + // 无论成功或失败都执行的回调 + deferred.done.apply(deferred, arguments).fail.apply(deferred, arguments); + return this; // 返回当前对象,以支持链式调用 + }, + + pipe: function (fnDone, fnFail, fnProgress) { + // 创建一个新的延迟对象,允许链式调用 + return jQuery.Deferred(function (newDefer) { + // 遍历每个处理程序(成功、失败和进度) + jQuery.each({ + done: [fnDone, "resolve"], // 成功回调及其对应的操作 + fail: [fnFail, "reject"], // 失败回调及其对应的操作 + progress: [fnProgress, "notify"] // 进度回调及其对应的操作 + }, function (handler, data) { + var fn = data[0], // 获取回调函数 + action = data[1], // 获取对应的操作 + returned; // 用于存储返回值 + + // 检查 fn 是否为一个有效的函数 + if (jQuery.isFunction(fn)) { + // 为当前的 deferred 添加相应的回调处理 + deferred[handler](function () { + returned = fn.apply(this, arguments); // 调用该函数并获取返回值 + + // 检查返回值是否是一个具有 promise 方法的对象 + if (returned && jQuery.isFunction(returned.promise)) { + // 若是,则将新的 deferred 的 resolve/reject/notify 方法与返回的 promise 绑定 + returned.promise().then(newDefer.resolve, newDefer.reject, newDefer.notify); + } else { + // 否则,直接将返回值传递到新的 deferred + newDefer[action + "With"](this === deferred ? newDefer : this, [returned]); + } + }); + } else { + // 如果 fn 不是函数,则直接将新的 deferred 的操作与原 deferred 的操作绑定 + deferred[handler](newDefer[action]); + } + }); + }).promise(); // 返回新的 promise 对象 + }, + +// 获取当前 deferred 的 promise +// 如果提供了 obj,则将 promise 方法添加到该对象上 + promise: function (obj) { + if (obj == null) { + obj = promise; // 如果没有提供对象,则使用当前的 promise + } else { + // 将 promise 中的方法复制到提供的对象中 + for (var key in promise) { + obj[key] = promise[key]; } - }); - }).promise(); - }, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - if ( obj == null ) { - obj = promise; - } else { - for ( var key in promise ) { - obj[ key ] = promise[ key ]; } + return obj; // 返回最终的对象 } - return obj; - } - }, - deferred = promise.promise({}), - key; + }, + deferred = promise.promise({}), + key; - for ( key in lists ) { - deferred[ key ] = lists[ key ].fire; - deferred[ key + "With" ] = lists[ key ].fireWith; - } + // 遍历 lists 对象中的每个 key + for (key in lists) { + // 将 lists 中相应的 fire 方法赋值给 deferred 对象的对应属性 + deferred[key] = lists[key].fire; + // 将 lists 中的 fireWith 方法赋值给 deferred 对象的对应属性,允许带上下文和参数调用 + deferred[key + "With"] = lists[key].fireWith; + } - // Handle state - deferred.done( function() { - state = "resolved"; - }, failList.disable, progressList.lock ).fail( function() { - state = "rejected"; - }, doneList.disable, progressList.lock ); +// 处理状态变化 + deferred.done(function () { + // 当执行完所有成功回调后,将状态设置为 "resolved" + state = "resolved"; + }, failList.disable, progressList.lock).fail(function () { + // 当执行失败回调时,将状态设置为 "rejected" + state = "rejected"; + }, doneList.disable, progressList.lock); - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } +// 如果提供了 func 函数,则调用它,并将 deferred 作为上下文传入 + if (func) { + func.call(deferred, deferred); + } - // All done! - return deferred; - }, +// 返回 deferred 对象,表示所有操作已完成 + return deferred; + }, - // Deferred helper - when: function( firstParam ) { - var args = sliceDeferred.call( arguments, 0 ), - i = 0, - length = args.length, - pValues = new Array( length ), - count = length, - pCount = length, - deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? - firstParam : - jQuery.Deferred(), - promise = deferred.promise(); - function resolveFunc( i ) { - return function( value ) { - args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; - if ( !( --count ) ) { - deferred.resolveWith( deferred, args ); + // Deferred 辅助函数 + when: function( firstParam ) { + // 将传入的参数转换为数组形式,取出所有参数 + var args = sliceDeferred.call( arguments, 0 ), + i = 0, + length = args.length, // 参数长度 + pValues = new Array( length ), // 用于存储进度值的数组 + count = length, // 计数器,用于跟踪已解析的 promise 数量 + pCount = length, // 另一个计数器,可能用于未来扩展 + deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? + // 如果只有一个参数且它是一个可执行 promise 的对象,则使用这个对象;否则创建新的 Deferred 对象 + firstParam : + jQuery.Deferred(), + promise = deferred.promise(); // 获取与 deferred 相关联的 promise 对象 + + // 定义解析函数,用于处理成功回调 + function resolveFunc( i ) { + return function( value ) { + // 将对应索引的参数值设置为传入的 value,如果有多个参数则存储为数组 + args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + // 减少计数器,当所有 promise 都已解决时,调用 resolve + if ( !( --count ) ) { + deferred.resolveWith( deferred, args ); // 触发 deferred 的 resolved 状态,并传入所有结果 + } + }; + } + + // 定义进度处理函数,用于处理进度通知 + function progressFunc( i ) { + return function( value ) { + // 将进度值存储在 pValues 数组中 + pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + // 通知 promise 的进度更新 + deferred.notifyWith( promise, pValues ); // 发送当前进度值给观察者 + }; + } + + if ( length > 1 ) { // 如果参数个数大于1 + for ( ; i < length; i++ ) { // 遍历所有参数 + // 检查当前参数是否为一个有 promise 方法的对象 + if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) { + // 调用当前参数的 promise 方法,并处理成功和失败的回调 + // resolveFunc(i) 用于成功时的处理,deferred.reject 用于失败时的处理,progressFunc(i) 用于进度更新的处理 + args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) ); + } else { + // 如果当前参数不是一个有效的 promise,则计数器减一 + --count; + } } - }; - } - function progressFunc( i ) { - return function( value ) { - pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; - deferred.notifyWith( promise, pValues ); - }; - } - if ( length > 1 ) { - for ( ; i < length; i++ ) { - if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) { - args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) ); - } else { - --count; + // 如果 count 计数器为0,表示所有的 promise 都已解决 + if ( !count ) { + // 将 args 中的所有结果传递给 deferred 的 resolved 状态,完成整个过程 + deferred.resolveWith( deferred, args ); } + } else if ( deferred !== firstParam ) { // 如果只有一个参数且它不是最初传入的 firstParam + // 将 firstParam 的值作为数组传递给 deferred 的 resolved 状态 + deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); } - if ( !count ) { - deferred.resolveWith( deferred, args ); - } - } else if ( deferred !== firstParam ) { - deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); +// 最后返回与 deferred 相关联的 promise 对象 + return promise; + } - return promise; - } }); -jQuery.support = (function() { + jQuery.support = (function() { // 定义 jQuery.support 作为一个立即执行函数表达式 (IIFE) - var support, - all, - a, - select, - opt, - input, - fragment, - tds, - events, - eventName, - i, - isSupported, - div = document.createElement( "div" ), - documentElement = document.documentElement; + var support, // 用于存储支持的特性 + all, // 用于存储 div 中的所有元素 + a, // 存储第一个 元素 + select, // 将来可能用于存储 元素 + fragment, // 将来可能用于存储文档片段 + tds, // 将来可能用于存储 元素 + events, // 将来可能用于存储事件支持情况 + eventName, // 将来可能用于存储事件名称 + i, // 循环计数器 + isSupported, // 用于指示某些特性的支持状态 + div = document.createElement("div"), // 创建一个新的 div 元素 + documentElement = document.documentElement; // 获取文档根元素 - // Preliminary tests - div.setAttribute("className", "t"); - div.innerHTML = "
a"; + // 进行初步测试 + div.setAttribute("className", "t"); // 设置 div 的 className 属性(IE 特有) + // 设置 div 的 innerHTML,包括一些元素和属性 + div.innerHTML = "
a"; - all = div.getElementsByTagName( "*" ); - a = div.getElementsByTagName( "a" )[ 0 ]; + all = div.getElementsByTagName("*"); // 获取 div 中的所有元素 + a = div.getElementsByTagName("a")[0]; // 获取 div 中的第一个 元素 - // Can't get basic test support - if ( !all || !all.length || !a ) { - return {}; - } + // 如果无法获取基本的测试支持,则返回一个空对象 + if ( !all || !all.length || !a ) { + return {}; + } - // First batch of supports tests - select = document.createElement( "select" ); - opt = select.appendChild( document.createElement("option") ); - input = div.getElementsByTagName( "input" )[ 0 ]; - - support = { - // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: ( div.firstChild.nodeType === 3 ), - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - tbody: !div.getElementsByTagName("tbody").length, - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - htmlSerialize: !!div.getElementsByTagName("link").length, - - // Get the style information from getAttribute - // (IE uses .cssText instead) - style: /top/.test( a.getAttribute("style") ), - - // Make sure that URLs aren't manipulated - // (IE normalizes it by default) - hrefNormalized: ( a.getAttribute("href") === "/a" ), - - // Make sure that element opacity exists - // (IE uses filter instead) - // Use a regex to work around a WebKit issue. See #5145 - opacity: /^0.55/.test( a.style.opacity ), - - // Verify style float existence - // (IE uses styleFloat instead of cssFloat) - cssFloat: !!a.style.cssFloat, - - // Make sure that if no value is specified for a checkbox - // that it defaults to "on". - // (WebKit defaults to "" instead) - checkOn: ( input.value === "on" ), - - // Make sure that a selected-by-default option has a working selected property. - // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) - optSelected: opt.selected, - - // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) - getSetAttribute: div.className !== "t", - - // Tests for enctype support on a form(#6743) - enctype: !!document.createElement("form").enctype, - - // Makes sure cloning an html5 element does not cause problems - // Where outerHTML is undefined, this still works - html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", - - // Will be defined later - submitBubbles: true, - changeBubbles: true, - focusinBubbles: false, - deleteExpando: true, - noCloneEvent: true, - inlineBlockNeedsLayout: false, - shrinkWrapBlocks: false, - reliableMarginRight: true, - pixelMargin: true - }; - // jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead - jQuery.boxModel = support.boxModel = (document.compatMode === "CSS1Compat"); + // 第一批支持测试 + select = document.createElement("select"); // 创建一个 中添加一个 元素的 style 属性中是否包含 "top" - fragment.removeChild( div ); + // 确保 URL 不会被修改 + // (IE 默认会对其进行规范化) + hrefNormalized: (a.getAttribute("href") === "/a"), // 检查 元素的 href 是否为指定的值 - // Null elements to avoid leaks in IE - fragment = select = opt = div = input = null; + // 确保元素透明度存在 + // (IE 使用 filter 代替) + // 使用正则表达式来解决 WebKit 问题 + opacity: /^0.55/.test(a.style.opacity), // 检查 元素的 opacity 样式是否为 0.55 - // Run tests that need a body at doc ready - jQuery(function() { - var container, outer, inner, table, td, offsetSupport, - marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight, - paddingMarginBorderVisibility, paddingMarginBorder, - body = document.getElementsByTagName("body")[0]; + // 验证样式浮动的存在 + // (IE 使用 styleFloat 而不是 cssFloat) + cssFloat: !!a.style.cssFloat, // 检查 元素的 cssFloat 是否存在并转换为布尔值 - if ( !body ) { - // Return for frameset docs that don't have a body - return; + // 确保如果未指定复选框的值,则默认为 "on" + // (WebKit 默认为 "") + checkOn: (input.value === "on"), // 检查 input 元素的值是否为 "on" + + // 确保默认选中的选项具有有效的 selected 属性。 + // (WebKit 默认情况下为 false,而 IE 也是如此,如果它在 optgroup 中) + optSelected: opt.selected, // 检查选项是否被选中 + + // 测试 camelCase 类的 setAttribute 是否有效。如果有效,则在进行 get/setAttribute 时需要 attrFixes(适用于 IE6/7) + getSetAttribute: div.className !== "t", // 检查 div 的 className 是否不等于 "t" + + // 测试表单上的 enctype 支持 (#6743) + enctype: !!document.createElement("form").enctype, // 检查新的表单元素是否具有 enctype 属性并转换为布尔值 + + // 确保克隆一个 HTML5 元素不会导致问题 + // 当 outerHTML 未定义时,这仍然有效 + html5Clone: document.createElement("nav").cloneNode(true).outerHTML !== "<:nav>", // 检查克隆的