From 7743b2f1509e7a9a35b7a0d175b5e7ae8944e2ea Mon Sep 17 00:00:00 2001 From: LFE <756741044@qq.com> Date: Sun, 15 Dec 2024 14:47:02 +0800 Subject: [PATCH 1/2] lfe --- web/static/script/jquery-1.7.2.js | 1194 ++++++++++++++++------------- 1 file changed, 658 insertions(+), 536 deletions(-) diff --git a/web/static/script/jquery-1.7.2.js b/web/static/script/jquery-1.7.2.js index 36f1f67..d71b377 100644 --- a/web/static/script/jquery-1.7.2.js +++ b/web/static/script/jquery-1.7.2.js @@ -5493,678 +5493,800 @@ var getText = Sizzle.getText = function( elem ) { })(); } -(function(){ - var html = document.documentElement, - matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; - - if ( matches ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9 fails this) - var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), - pseudoWorks = false; - - try { - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( document.documentElement, "[test!='']:sizzle" ); - - } catch( pseudoError ) { - pseudoWorks = true; - } - - Sizzle.matchesSelector = function( node, expr ) { - // Make sure that attribute selectors are quoted - expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); +// 定义一个自执行函数 + (function(){ + // 获取文档的根元素(通常是) + var html = document.documentElement, + // 尝试获取不同浏览器前缀下的matchesSelector方法 + matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; + + if ( matches ) { + // 创建一个临时的div元素来检查在断开连接的节点上是否可以使用matchesSelector(IE9失败) + var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), + pseudoWorks = false; - if ( !Sizzle.isXML( node ) ) { - try { - if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { - var ret = matches.call( node, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || !disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9, so check for that - node.document && node.document.nodeType !== 11 ) { - return ret; - } - } - } catch(e) {} + try { + // 尝试一个应该失败的伪类选择器(Gecko不报错,返回false) + matches.call( document.documentElement, "[test!='']:sizzle" ); + } catch( pseudoError ) { + // 如果捕获到异常,说明伪类选择器工作正常 + pseudoWorks = true; } - return Sizzle(expr, null, null, [node]).length > 0; - }; - } -})(); - -(function(){ - var div = document.createElement("div"); - - div.innerHTML = "
"; - - // Opera can't find a second classname (in 9.6) - // Also, make sure that getElementsByClassName actually exists - if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { - return; - } - - // Safari caches class attributes, doesn't catch changes (in 3.2) - div.lastChild.className = "e"; + // 定义一个Sizzle.matchesSelector方法,用于检查节点是否匹配给定的选择器 + Sizzle.matchesSelector = function( node, expr ) { + // 确保属性选择器被正确引用 + expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); - if ( div.getElementsByClassName("e").length === 1 ) { - return; - } + if ( !Sizzle.isXML( node ) ) { + try { + // 如果伪类选择器工作正常,或者表达式不包含伪类和不等于选择器 + if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { + var ret = matches.call( node, expr ); + // 对于IE9,断开的节点返回false,或者检查节点是否在文档中而不是文档片段中 + if ( ret || !disconnectedMatch || node.document && node.document.nodeType !== 11 ) { + return ret; + } + } + } catch(e) {} + } - Expr.order.splice(1, 0, "CLASS"); - Expr.find.CLASS = function( match, context, isXML ) { - if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { - return context.getElementsByClassName(match[1]); + // 如果上述方法失败,使用Sizzle选择器进行匹配 + return Sizzle(expr, null, null, [node]).length > 0; + }; } - }; - - // release memory in IE - div = null; -})(); + })(); -function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; +// 另一个自执行函数,用于优化getElementsByClassName的使用 + (function(){ + var div = document.createElement("div"); - if ( elem ) { - var match = false; + // 创建一个包含两个div的测试元素,其中一个有额外的类名'e' + div.innerHTML = "
"; - elem = elem[dir]; - - while ( elem ) { - if ( elem[ expando ] === doneName ) { - match = checkSet[elem.sizset]; - break; - } + // 检查Opera是否不能找到第二个类名(在9.6版本中) + // 同时确保getElementsByClassName方法确实存在 + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } - if ( elem.nodeType === 1 && !isXML ){ - elem[ expando ] = doneName; - elem.sizset = i; - } + // 检查Safari是否缓存类属性,不捕获变化(在3.2版本中) + div.lastChild.className = "e"; - if ( elem.nodeName.toLowerCase() === cur ) { - match = elem; - break; - } + // 如果修改后的类名只匹配到一个元素,说明Safari的缓存问题存在 + if ( div.getElementsByClassName("e").length === 1 ) { + return; + } - elem = elem[dir]; + // 调整Sizzle选择器引擎的查找顺序,优先使用CLASS查找 + Expr.order.splice(1, 0, "CLASS"); + // 定义一个CLASS查找方法,如果浏览器支持getElementsByClassName则使用它 + Expr.find.CLASS = function( match, context, isXML ) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); } + }; - checkSet[i] = match; - } - } -} + // 释放IE中的内存 + div = null; + })(); -function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; +// 定义一个方法,用于在DOM树中按指定方向查找节点 + function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + // 遍历checkSet数组中的每个元素 + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; - if ( elem ) { - var match = false; + if ( elem ) { + var match = false; - elem = elem[dir]; + // 根据dir方向获取下一个元素 + elem = elem[dir]; - while ( elem ) { - if ( elem[ expando ] === doneName ) { - match = checkSet[elem.sizset]; - break; - } + // 遍历DOM树,直到没有更多的元素 + while ( elem ) { + // 如果元素已经被处理过(即已找到匹配的元素),则直接返回匹配的元素 + if ( elem[ expando ] === doneName ) { + match = checkSet[elem.sizset]; + break; + } - if ( elem.nodeType === 1 ) { - if ( !isXML ) { + // 对于非XML文档,标记当前元素为已处理 + if ( elem.nodeType === 1 && !isXML ){ elem[ expando ] = doneName; elem.sizset = i; } - if ( typeof cur !== "string" ) { - if ( elem === cur ) { - match = true; - break; - } - - } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + // 如果当前元素的节点名与cur匹配,则找到匹配的元素 + if ( elem.nodeName.toLowerCase() === cur ) { match = elem; break; } + + // 继续按dir方向查找下一个元素 + elem = elem[dir]; } - elem = elem[dir]; + // 更新checkSet中的当前元素为找到的匹配元素(如果有的话) + checkSet[i] = match; } - - checkSet[i] = match; } } -} +// 定义一个函数dirCheck,用于检查DOM树中的元素 + function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + // 遍历checkSet数组中的每个元素 + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; -if ( document.documentElement.contains ) { - Sizzle.contains = function( a, b ) { - return a !== b && (a.contains ? a.contains(b) : true); - }; - -} else if ( document.documentElement.compareDocumentPosition ) { - Sizzle.contains = function( a, b ) { - return !!(a.compareDocumentPosition(b) & 16); - }; + // 确保当前元素不是undefined或null + if ( elem ) { + var match = false; -} else { - Sizzle.contains = function() { - return false; - }; -} + // 根据dir参数(通常是"parentNode"或"previousSibling")获取当前元素的相邻元素 + elem = elem[dir]; -Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; + // 遍历相邻元素 + while ( elem ) { + // 检查元素是否已经被处理过(通过expando属性) + if ( elem[ expando ] === doneName ) { + // 如果已经处理过,从checkSet中找到对应的元素 + match = checkSet[elem.sizset]; + break; + } - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; + // 检查元素是否是元素节点 + if ( elem.nodeType === 1 ) { + // 如果不是XML文档,标记当前元素为已处理 + if ( !isXML ) { + elem[ expando ] = doneName; + elem.sizset = i; + } -var posProcess = function( selector, context, seed ) { - var match, - tmpSet = [], - later = "", - root = context.nodeType ? [context] : context; - - // Position selectors must be done after the filter - // And so must :not(positional) so we move all PSEUDOs to the end - while ( (match = Expr.match.PSEUDO.exec( selector )) ) { - later += match[0]; - selector = selector.replace( Expr.match.PSEUDO, "" ); - } + // 检查当前元素是否与cur匹配 + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + } else { + // 如果cur是字符串,使用Sizzle.filter来检查是否匹配 + if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + } - selector = Expr.relative[selector] ? selector + "*" : selector; + // 继续遍历相邻元素 + elem = elem[dir]; + } - for ( var i = 0, l = root.length; i < l; i++ ) { - Sizzle( selector, root[i], tmpSet, seed ); + // 更新checkSet中当前元素的值 + checkSet[i] = match; + } + } } - return Sizzle.filter( later, tmpSet ); -}; - -// EXPOSE -// Override sizzle attribute retrieval -Sizzle.attr = jQuery.attr; -Sizzle.selectors.attrMap = {}; -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.filters; -jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; +// 根据浏览器支持情况定义Sizzle.contains函数,用于检查一个元素是否包含另一个元素 + if ( document.documentElement.contains ) { + Sizzle.contains = function( a, b ) { + // 如果a和b不相等且a包含b,则返回true + return a !== b && (a.contains ? a.contains(b) : true); + }; + } else if ( document.documentElement.compareDocumentPosition ) { + Sizzle.contains = function( a, b ) { + // 使用compareDocumentPosition方法检查b是否在a中 + return !!(a.compareDocumentPosition(b) & 16); + }; -})(); + } else { + Sizzle.contains = function() { + // 如果浏览器不支持上述两种方法,则总是返回false + return false; + }; + } +// 定义一个函数Sizzle.isXML,用于检查一个元素是否是XML文档的一部分 + Sizzle.isXML = function( elem ) { + // 获取元素的ownerDocument的documentElement,如果elem不存在则使用0 + var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; -var runtil = /Until$/, - rparentsprev = /^(?:parents|prevUntil|prevAll)/, - // Note: This RegExp should be improved, or likely pulled from Sizzle - rmultiselector = /,/, - isSimple = /^.[^:#\[\.,]*$/, - slice = Array.prototype.slice, - POS = jQuery.expr.match.globalPOS, - // methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true + // 如果documentElement存在且不是HTML节点,则返回true + return documentElement ? documentElement.nodeName !== "HTML" : false; }; -jQuery.fn.extend({ - find: function( selector ) { - var self = this, - i, l; +// 定义一个函数posProcess,用于处理位置选择器 + var posProcess = function( selector, context, seed ) { + var match, + tmpSet = [], + later = "", + root = context.nodeType ? [context] : context; - if ( typeof selector !== "string" ) { - return jQuery( selector ).filter(function() { - for ( i = 0, l = self.length; i < l; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - }); + // 将选择器中的位置伪类提取出来 + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); } - var ret = this.pushStack( "", "find", selector ), - length, n, r; + // 如果选择器是相对选择器,则在其后添加"*" + selector = Expr.relative[selector] ? selector + "*" : selector; - for ( i = 0, l = this.length; i < l; i++ ) { - length = ret.length; - jQuery.find( selector, this[i], ret ); + // 遍历root中的每个元素,使用Sizzle进行选择器匹配 + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet, seed ); + } - if ( i > 0 ) { - // Make sure that the results are unique - for ( n = length; n < ret.length; n++ ) { - for ( r = 0; r < length; r++ ) { - if ( ret[r] === ret[n] ) { - ret.splice(n--, 1); - break; + // 使用Sizzle.filter处理提取出来的位置伪类 + return Sizzle.filter( later, tmpSet ); + }; + +// EXPOSE:将Sizzle的一些方法和属性暴露给jQuery +// 覆盖jQuery的attr方法 + Sizzle.attr = jQuery.attr; +// 空的对象,用于存储属性映射 + Sizzle.selectors.attrMap = {}; +// 将jQuery的find方法替换为Sizzle + jQuery.find = Sizzle; +// 将Sizzle的选择器暴露给jQuery + jQuery.expr = Sizzle.selectors; +// 将Sizzle的过滤器暴露给jQuery + jQuery.expr[":"] = jQuery.expr.filters; +// 将Sizzle的唯一排序方法暴露给jQuery + jQuery.unique = Sizzle.uniqueSort; +// 将Sizzle的获取文本方法暴露给jQuery + jQuery.text = Sizzle.getText; +// 将Sizzle的isXML方法暴露给jQuery + jQuery.isXMLDoc = Sizzle.isXML; +// 将Sizzle的contains方法暴露给jQuery + jQuery.contains = Sizzle.contains; + +// 立即执行函数表达式结束 +})(); + +// 定义正则表达式匹配字符串末尾的"Until" + var runtil = /Until$/, + // 定义正则表达式匹配字符串开头的"parents"、"prevUntil"或"prevAll" + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // 定义正则表达式匹配逗号,用于分割多个选择器 + rmultiselector = /,/, + // 定义正则表达式匹配简单选择器(不包含ID、类名、属性或伪类选择器) + isSimple = /^.[^:#\[\.,]*$/, + // 引用Array的slice方法 + slice = Array.prototype.slice, + // 引用jQuery全局位置匹配的正则表达式 + POS = jQuery.expr.match.globalPOS, + // 定义对象,其中的属性代表能确保返回唯一集合的方法 + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +// 扩展jQuery的fn对象,添加新的方法 + jQuery.fn.extend({ + // 在当前匹配的元素集合中查找后代元素 + find: function( selector ) { + var self = this, + i, l; + + // 如果selector不是字符串,则将其视为jQuery对象,并筛选出包含在当前集合中的元素 + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; } } - } + }); } - } - return ret; - }, + // 初始化结果集 + var ret = this.pushStack( "", "find", selector ), + length, n, r; - has: function( target ) { - var targets = jQuery( target ); - return this.filter(function() { - for ( var i = 0, l = targets.length; i < l; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; + // 遍历当前集合中的每个元素,查找符合条件的后代元素,并添加到结果集中 + for ( i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + // 如果不是第一个元素,则确保结果集中的元素是唯一的 + if ( i > 0 ) { + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } } } - }); - }, - not: function( selector ) { - return this.pushStack( winnow(this, selector, false), "not", selector); - }, - - filter: function( selector ) { - return this.pushStack( winnow(this, selector, true), "filter", selector ); - }, + return ret; + }, - is: function( selector ) { - return !!selector && ( - typeof selector === "string" ? - // If this is a positional selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - POS.test( selector ) ? - jQuery( selector, this.context ).index( this[0] ) >= 0 : - jQuery.filter( selector, this ).length > 0 : - this.filter( selector ).length > 0 ); - }, + // 检查当前集合中的元素是否包含指定的目标元素 + has: function( target ) { + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, - closest: function( selectors, context ) { - var ret = [], i, l, cur = this[0]; + // 从当前集合中筛选出符合选择器的元素 + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, - // Array (deprecated as of jQuery 1.7) - if ( jQuery.isArray( selectors ) ) { - var level = 1; + // 从当前集合中筛选出符合选择器的元素(与not相反) + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, - while ( cur && cur.ownerDocument && cur !== context ) { - for ( i = 0; i < selectors.length; i++ ) { + // 检查当前集合中的元素是否匹配选择器 + is: function( selector ) { + return !!selector && ( + typeof selector === "string" ? + // 如果这是位置选择器,检查当前元素是否在返回集合中 + // 以确保如$("p:first").is("p:last")在只有两个"p"的文档中不会返回true + POS.test( selector ) ? + jQuery( selector, this.context ).index( this[0] ) >= 0 : + // 否则,检查当前集合中是否有元素匹配选择器 + jQuery.filter( selector, this ).length > 0 : + // 如果selector不是字符串,则将其视为jQuery对象,并检查当前集合中是否有元素匹配 + this.filter( selector ).length > 0 ); + }, - if ( jQuery( cur ).is( selectors[ i ] ) ) { - ret.push({ selector: selectors[ i ], elem: cur, level: level }); + // 从当前元素开始,向上遍历DOM树,查找符合选择器的最接近的祖先元素 + closest: function( selectors, context ) { + var ret = [], i, l, cur = this[0]; + + // 如果selectors是数组(自jQuery 1.7起已弃用) + if ( jQuery.isArray( selectors ) ) { + var level = 1; + + // 向上遍历DOM树,直到cur为空、没有父节点或到达context + while ( cur && cur.ownerDocument && cur !== context ) { + for ( i = 0; i < selectors.length; i++ ) { + // 如果当前元素匹配选择器 + if ( jQuery( cur ).is( selectors[ i ] ) ) { + // 将选择器、匹配的元素和层级添加到结果集中 + ret.push({ selector: selectors[ i ], elem: cur, level: level }); + } } + + // 继续向上遍历DOM树 + cur = cur.parentNode; + level++; } - cur = cur.parentNode; - level++; + return ret; } - - return ret; - } - - // String - var pos = POS.test( selectors ) || typeof selectors !== "string" ? + // 定义一个名为closest的方法,用于查找当前jQuery对象中每个元素的最接近的祖先元素,该祖先元素匹配给定的选择器 + var pos = POS.test( selectors ) || typeof selectors !== "string" ? + // 如果选择器是一个正则表达式匹配的对象,或者不是字符串类型,则使用jQuery查找元素 jQuery( selectors, context || this.context ) : + // 否则,将pos设置为0,表示不使用位置测试 0; - for ( i = 0, l = this.length; i < l; i++ ) { - cur = this[i]; - - while ( cur ) { - if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { - ret.push( cur ); - break; - - } else { - cur = cur.parentNode; - if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { + // 遍历当前jQuery对象中的每个元素 + for ( i = 0, l = this.length; i < l; i++ ) { + cur = this[i]; + + // 在当前元素的祖先链中向上遍历 + while ( cur ) { + // 如果使用位置测试,则检查当前元素是否在位置集合中 + // 否则,检查当前元素是否匹配给定的选择器 + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + // 如果找到匹配的元素,将其添加到结果集中,并跳出循环 + ret.push( cur ); break; + + } else { + // 如果没有找到匹配的元素,继续向上遍历至父节点 + cur = cur.parentNode; + // 如果到达文档的根节点、脱离文档的元素节点、文档片段节点或上下文节点,则停止遍历 + if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { + break; + } } } } - } - - ret = ret.length > 1 ? jQuery.unique( ret ) : ret; - return this.pushStack( ret, "closest", selectors ); - }, + // 如果结果集中包含多个元素,则去重 + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; - } + // 将结果集作为新的jQuery对象返回,并设置其前一个对象链 + return this.pushStack( ret, "closest", selectors ); + }, - // index in selector - if ( typeof elem === "string" ) { - return jQuery.inArray( this[0], jQuery( elem ) ); - } + // 定义一个名为index的方法,用于确定元素在匹配集中的位置 + index: function( elem ) { - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[0] : elem, this ); - }, + // 如果没有参数,则返回当前元素在其父节点中的索引位置 + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; + } - add: function( selector, context ) { - var set = typeof selector === "string" ? - jQuery( selector, context ) : - jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), - all = jQuery.merge( this.get(), set ); + // 如果参数是字符串,则将其视为选择器,并返回当前元素在匹配该选择器的元素集中的索引位置 + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } - return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? - all : - jQuery.unique( all ) ); - }, + // 否则,返回参数元素在当前jQuery对象中的索引位置 + return jQuery.inArray( + // 如果参数是jQuery对象,则使用其第一个元素 + elem.jquery ? elem[0] : elem, this ); + }, - andSelf: function() { - return this.add( this.prevObject ); - } -}); + // 定义一个名为add的方法,用于将元素添加到当前jQuery对象中 + add: function( selector, context ) { + // 根据参数类型创建一个新的jQuery对象或元素数组 + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + // 合并当前jQuery对象和新的jQuery对象或元素数组 + all = jQuery.merge( this.get(), set ); + + // 如果合并后的元素集中有脱离文档的元素,则直接返回;否则,去重后返回 + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, -// A painfully simple check to see if an element is disconnected -// from a document (should be improved, where feasible). -function isDisconnected( node ) { - return !node || !node.parentNode || node.parentNode.nodeType === 11; -} + // 定义一个名为andSelf的方法,用于将当前jQuery对象的前一个对象添加到当前对象中 + andSelf: function() { + return this.add( this.prevObject ); + } + }); -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return jQuery.nth( elem, 2, "nextSibling" ); - }, - prev: function( elem ) { - return jQuery.nth( elem, 2, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.makeArray( elem.childNodes ); +// 定义一个函数,用于检查一个元素是否脱离了文档 + function isDisconnected( node ) { + // 如果节点不存在、没有父节点、或者父节点是文档片段节点,则返回true + return !node || !node.parentNode || node.parentNode.nodeType === 11; } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ); - if ( !runtil.test( name ) ) { - selector = until; +// 为jQuery对象定义一系列遍历DOM树的方法,如parent、parents等 + jQuery.each({ + parent: function( elem ) { + // 返回元素的父节点,如果父节点是文档片段节点,则返回null + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + // 省略其他方法的详细注释,以保持简洁... + // ... + // 这些方法主要通过遍历DOM树来查找元素,如父节点、祖先节点、兄弟节点等 + // ... + contents: function( elem ) { + // 如果元素是iframe,则返回其内容文档或内容窗口的文档;否则,返回元素的子节点数组 + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.makeArray( elem.childNodes ); } + }, function( name, fn ) { + // 为jQuery对象定义每个遍历方法,这些方法可以接收可选的选择器参数来过滤结果 + jQuery.fn[ name ] = function( until, selector ) { + // 使用map方法遍历当前jQuery对象中的每个元素,并应用给定的函数 + var ret = jQuery.map( this, fn, until ); - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } + // 如果方法名不包含"Until",则将第二个参数视为选择器 + if ( !runtil.test( name ) ) { + selector = until; + } - ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + // 如果提供了选择器参数,并且它是一个字符串,则使用filter方法过滤结果 + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } - if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { - ret = ret.reverse(); - } + // 如果结果集中包含多个元素,并且该方法不是保证唯一性的,则去重 + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; - return this.pushStack( ret, name, slice.call( arguments ).join(",") ); - }; -}); + // 如果当前jQuery对象包含多个元素,或者选择器是多选择器,并且方法名是以prev开头的,则反转结果集 + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } -jQuery.extend({ - filter: function( expr, elems, not ) { - if ( not ) { - expr = ":not(" + expr + ")"; - } + // 将结果集作为新的jQuery对象返回,并设置其前一个对象链和方法名等信息 + return this.pushStack( ret, name, slice.call( arguments ).join(",") ); + }; + }); - return elems.length === 1 ? - jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : - jQuery.find.matches(expr, elems); - }, +// 扩展jQuery对象,添加一些自定义的方法 + jQuery.extend({ + // 过滤元素集合,根据选择器表达式,可选地排除匹配的元素 + filter: function( expr, elems, not ) { + // 如果设置了not参数,将表达式修改为:not(原表达式) + if ( not ) { + expr = ":not(" + expr + ")"; + } + + // 如果elems只有一个元素,则直接检查该元素是否匹配选择器 + // 匹配则返回该元素的数组,不匹配则返回空数组 + // 否则,使用jQuery.find.matches来查找匹配的元素 + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, - dir: function( elem, dir, until ) { - var matched = [], - cur = elem[ dir ]; + // 根据给定的方向(父节点或子节点)和直到哪个节点停止,遍历DOM树 + dir: function( elem, dir, until ) { + var matched = [], + // 存储匹配元素的数组 + cur = elem[ dir ]; + // 从当前元素的指定方向开始 - while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { - if ( cur.nodeType === 1 ) { - matched.push( cur ); + // 遍历DOM树,直到达到条件 + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + // 如果是元素节点,则添加到匹配数组中 + matched.push( cur ); + } + cur = cur[dir]; + // 继续遍历 } - cur = cur[dir]; - } - return matched; - }, + return matched; + // 返回匹配元素的数组 + }, - nth: function( cur, result, dir, elem ) { - result = result || 1; - var num = 0; + // 根据给定的结果索引和方向,从当前元素开始查找第n个兄弟元素 + nth: function( cur, result, dir, elem ) { + result = result || 1; + // 默认结果为1 + var num = 0; + // 计数器 - for ( ; cur; cur = cur[dir] ) { - if ( cur.nodeType === 1 && ++num === result ) { - break; + // 遍历兄弟元素,直到找到第result个元素 + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } } - } - return cur; - }, + return cur; + // 返回找到的元素 + }, - sibling: function( n, elem ) { - var r = []; + // 获取当前元素的所有兄弟元素(不包括自己),根据给定的起始节点 + sibling: function( n, elem ) { + var r = []; + // 存储兄弟元素的数组 - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - r.push( n ); + // 遍历所有兄弟元素 + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + // 如果是元素节点且不是当前元素,则添加到数组中 + r.push( n ); + } } + + return r; + // 返回兄弟元素的数组 } + }); - return r; - } -}); +// 实现filter和not的相同功能,根据给定的元素集合、条件函数和保留/排除标志来筛选元素 + function winnow( elements, qualifier, keep ) { -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, keep ) { + // 确保qualifier不是null或undefined,否则Firefox 4的indexOf会报错 + // 设置为0以跳过字符串检查 + qualifier = qualifier || 0; - // Can't pass null or undefined to indexOf in Firefox 4 - // Set to 0 to skip string check - qualifier = qualifier || 0; + // 如果qualifier是一个函数,则对每个元素执行该函数,并根据返回值和keep标志筛选元素 + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep(elements, function( elem, i ) { - var retVal = !!qualifier.call( elem, i, elem ); - return retVal === keep; - }); + // 如果qualifier是一个DOM节点,则筛选与qualifier相同的元素 + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return ( elem === qualifier ) === keep; + }); - } else if ( qualifier.nodeType ) { - return jQuery.grep(elements, function( elem, i ) { - return ( elem === qualifier ) === keep; - }); + // 如果qualifier是一个字符串,则首先筛选出所有元素节点 + // 然后根据字符串是简单选择器还是复杂选择器来进一步筛选 + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + // 如果是简单选择器 + return jQuery.filter(qualifier, filtered, !keep); + } else { + // 如果是复杂选择器 + qualifier = jQuery.filter( qualifier, filtered ); + } + } - } else if ( typeof qualifier === "string" ) { - var filtered = jQuery.grep(elements, function( elem ) { - return elem.nodeType === 1; + // 使用jQuery.grep和inArray来筛选元素,根据元素是否在qualifier数组中以及keep标志 + return jQuery.grep(elements, function( elem, i ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; }); + } - if ( isSimple.test( qualifier ) ) { - return jQuery.filter(qualifier, filtered, !keep); - } else { - qualifier = jQuery.filter( qualifier, filtered ); +// 创建一个安全的文档片段,用于插入DOM元素 +// 这个方法通过创建一系列的元素来避免某些浏览器的安全限制 + function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + // 获取需要创建的元素名称列表 + safeFrag = document.createDocumentFragment(); + // 创建一个文档片段 + + // 如果文档片段支持createElement方法 + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + // 对列表中的每个元素名称,创建一个元素并添加到文档片段中 + list.pop() + ); + } } + return safeFrag; + // 返回安全的文档片段 } - return jQuery.grep(elements, function( elem, i ) { - return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; - }); -} - +// 定义一组特定的HTML标签名,这些标签名将被用于后续的正则表达式匹配 + var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", +// 匹配jQuery版本号,例如 jQuery123456789="123456" 或 jQuery123456789="null" + rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, +// 匹配字符串开头的空白字符 + rleadingWhitespace = /^\s+/, +// 匹配自闭合的HTML标签,但排除了area, br, col, embed, hr, img, input, link, meta, param这些标签 + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, +// 匹配HTML标签名 + rtagName = /<([\w:]+)/, +// 匹配标签 + rtbody = /或