//設定當前document和document對應的變數和方法
setDocument = Sizzle.setDocument = function( node ) {var hasCompare,//node為Element時返回node所屬document//node為Document時返回node//node為空白時返回window.documentdoc = node ? node.ownerDocument || node : preferredDoc,//document所屬windowparent = doc.defaultView;// If no document and documentElement is available, returnif ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {return document;}// Set our document//設定全域的document為當前docdocument = doc;docElem = doc.documentElement;// Support testsdocumentIsHTML = !isXML( doc );// Support: IE>8// If iframe document is assigned to "document" variable and if iframe has been reloaded,// IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936// IE6-8 do not support the defaultView property so parent will be undefined/* * 如果 iframe文檔已經指定了document並且如果iframe重載 * 當訪問document變數時,IE將拋出"permission denied"錯誤 * IE6-8不支援defaultView所以parent變數為undefined *///所以要在unload的時候重新setDocument()//這個判斷說明當前代碼在frame中 if ( parent && parent !== parent.top ) {// IE11 does not have attachEvent, so all must suffer//frame卸載時重新設定documentif ( parent.addEventListener ) {parent.addEventListener( "unload", function() {//未傳入參數document=window.documentsetDocument();}, false );} else if ( parent.attachEvent ) {parent.attachEvent( "onunload", function() {setDocument();});}}//一些能力檢查,添加到support中/* Attributes---------------------------------------------------------------------- */// Support: IE<8// Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)// IE8以下div.getAttribute("className")會得到classsupport.attributes = assert(function( div ) {div.className = "i";return !div.getAttribute("className");});/* getElement(s)By*---------------------------------------------------------------------- */// Check if getElementsByTagName("*") returns only elements//檢查getElementsByTagName是否只返回Element元素support.getElementsByTagName = assert(function( div ) {div.appendChild( doc.createComment("") );return !div.getElementsByTagName("*").length;});// Check if getElementsByClassName can be trusted//檢查getElementsByClassName是否能正確處理多class的情況support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {div.innerHTML = "";// Support: Safari<4// Catch class over-cachingdiv.firstChild.className = "i";// Support: Opera<10// Catch gEBCN failure to find non-leading classesreturn div.getElementsByClassName("i").length === 2;});// Support: IE<10// Check if getElementById returns elements by name// The broken getElementById methods don't pick up programatically-set names,// so use a roundabout getElementsByName test//檢查是否getElementById會根據name返回元素support.getById = assert(function( div ) {docElem.appendChild( div ).id = expando;return !doc.getElementsByName || !doc.getElementsByName( expando ).length;});// ID find and filterif ( support.getById ) {Expr.find["ID"] = function( id, context ) {if ( typeof context.getElementById !== strundefined && documentIsHTML ) {var m = context.getElementById( id );// Check parentNode to catch when Blackberry 4.6 returns// nodes that are no longer in the document #6963return m && m.parentNode ? [m] : [];}};Expr.filter["ID"] = function( id ) {//將逸出字元轉回字串var attrId = id.replace( runescape, funescape );return function( elem ) {return elem.getAttribute("id") === attrId;};};} else {// Support: IE6/7// getElementById is not reliable as a find shortcut//IE6,7的getElementById因為會根據name返回元素//所以是不能用原生getElementById方法擷取元素的//所以刪除delete Expr.find["ID"];Expr.filter["ID"] = function( id ) {var attrId = id.replace( runescape, funescape );return function( elem ) {var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");return node && node.value === attrId;};};}// Tag//getElementsByTagName是否只返回Element元素Expr.find["TAG"] = support.getElementsByTagName ?function( tag, context ) {if ( typeof context.getElementsByTagName !== strundefined ) {return context.getElementsByTagName( tag );}} :function( tag, context ) {var elem,tmp = [],i = 0,results = context.getElementsByTagName( tag );// Filter out possible commentsif ( tag === "*" ) {while ( (elem = results[i++]) ) {if ( elem.nodeType === 1 ) {tmp.push( elem );}}return tmp;}return results;};// ClassExpr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {return context.getElementsByClassName( className );}};/* QSA/matchesSelector---------------------------------------------------------------------- */// QSA and matchesSelector support// matchesSelector(:active) reports false when true (IE9/Opera 11.5)rbuggyMatches = [];// qSa(:focus) reports false when true (Chrome 21)// We allow this because of a bug in IE8/9 that throws an error// whenever `document.activeElement` is accessed on an iframe// So, we allow :focus to pass through QSA all the time to avoid the IE error// See http://bugs.jquery.com/ticket/13378rbuggyQSA = [];if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {// Build QSA regex// Regex strategy adopted from Diego Periniassert(function( div ) {// Select is set to empty string on purpose// This is to test IE's treatment of not explicitly// setting a boolean content attribute,// since its presence should be enough// http://bugs.jquery.com/ticket/12359div.innerHTML = "";// Support: IE8, Opera 10-12// Nothing should be selected when empty strings follow ^= or $= or *=if ( div.querySelectorAll("[t^='']").length ) {rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );}// Support: IE8// Boolean attributes and "value" are not treated correctlyif ( !div.querySelectorAll("[selected]").length ) {rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );}// Webkit/Opera - :checked should return selected option elements// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked// IE8 throws error here and will not see later testsif ( !div.querySelectorAll(":checked").length ) {rbuggyQSA.push(":checked");}});assert(function( div ) {// Support: Windows 8 Native Apps// The type and name attributes are restricted during .innerHTML assignmentvar input = doc.createElement("input");input.setAttribute( "type", "hidden" );div.appendChild( input ).setAttribute( "name", "D" );// Support: IE8// Enforce case-sensitivity of name attributeif ( div.querySelectorAll("[name=d]").length ) {rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );}// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)// IE8 throws error here and will not see later testsif ( !div.querySelectorAll(":enabled").length ) {rbuggyQSA.push( ":enabled", ":disabled" );}// Opera 10-11 does not throw on post-comma invalid pseudosdiv.querySelectorAll("*,:x");rbuggyQSA.push(",.*:");});}if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector ||docElem.mozMatchesSelector ||docElem.oMatchesSelector ||docElem.msMatchesSelector) )) ) {assert(function( div ) {// Check to see if it's possible to do matchesSelector// on a disconnected node (IE 9)support.disconnectedMatch = matches.call( div, "div" );// This should fail with an exception// Gecko does not error, returns false insteadmatches.call( div, "[s!='']:x" );rbuggyMatches.push( "!=", pseudos );});}rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );/* Contains---------------------------------------------------------------------- */hasCompare = rnative.test( docElem.compareDocumentPosition );// Element contains another// Purposefully does not implement inclusive descendent// As in, an element does not contain itself// 當節點contains自己時,返回truecontains = hasCompare || rnative.test( docElem.contains ) ?function( a, b ) {//a是Document,adown為HtmlElement其他為avar adown = a.nodeType === 9 ? a.documentElement : a,//bup是b節點的父節點bup = b && b.parentNode;//(1)如果a是b的父節點,快速返回true//(2)如果b有父節點並且父節點是Element// a包含b的父節點返回truereturn a === bup || !!( bup && bup.nodeType === 1 && (adown.contains ?//contains的是bup而是b是為了避免contains自己時返回trueadown.contains( bup ) ://為什麼要&16,請看compareDocumentPosition的傳回值/* 000000 0 元素一致000001 1 節點在不同的文檔(或者一個在文檔之外)000010 2 節點 B 在節點 A 之前000100 4 節點 A 在節點 B 之前001000 8 節點 B 包含節點 A010000 16 節點 A 包含節點 B100000 32 瀏覽器的私人使用 */a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16));} ://沒有原生方法時迭代判斷function( a, b ) {if ( b ) {//b的某個祖先節點===a說明a包含bwhile ( (b = b.parentNode) ) {if ( b === a ) {return true;}}}return false;};/* Sorting---------------------------------------------------------------------- */// Document order sortingsortOrder = hasCompare ?function( a, b ) {// Flag for duplicate removalif ( a === b ) {hasDuplicate = true;return 0;}// Sort on method existence if only one input has compareDocumentPosition// 如果只有一個元素擁有排序方法.// a節點有排序方法返回-1,b節點有排序方法返回1var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;if ( compare ) {return compare;}// Calculate position if both inputs belong to the same document// 如果兩個元素屬於一個文檔計算位置compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?a.compareDocumentPosition( b ) :// Otherwise we know they are disconnected1;// Disconnected nodes// 如果節點不再同一文檔 或者 不支援分離排序並且a,b不再同一文檔if ( compare & 1 ||(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {// Choose the first element that is related to our preferred document// a節點包含在當前document返回-1if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {return -1;}// b節點包含在當前doucment返回1if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {return 1;}// Maintain original order// 保持原有順序return sortInput ?( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :0;}//compare //a在b之前返回-1,否則返回1return compare & 4 ? -1 : 1;} :function( a, b ) {// Exit early if the nodes are identicalif ( a === b ) {hasDuplicate = true;return 0;}var cur,i = 0,aup = a.parentNode,bup = b.parentNode,ap = [ a ],bp = [ b ];// Parentless nodes are either documents or disconnected//沒有父親節點說明可能是document或者以不再DOM樹中的節點if ( !aup || !bup ) {//如果a是document說明a在前返回-1//如果b是document說明b在前返回1//否則如果a有父節點說明b是disconnected返回-1//否則b有父節點a是disconnected返回1//如果a、b都是disconnected,使用indexOf方法return a === doc ? -1 :b === doc ? 1 :aup ? -1 :bup ? 1 :sortInput ?( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :0;// If the nodes are siblings, we can do a quick check// 父親是一個,使用siblingCheck(a,b)方法快速檢查} else if ( aup === bup ) {return siblingCheck( a, b );}// Otherwise we need full lists of their ancestors for comparison// 否則需要遍曆整個祖先cur = a;while ( (cur = cur.parentNode) ) {//將a的所有的祖先入棧ap.unshift( cur );}cur = b;while ( (cur = cur.parentNode) ) {//將b的所有的祖先入棧bp.unshift( cur );}// Walk down the tree looking for a discrepancy// 如果同層的祖先是一個while ( ap[i] === bp[i] ) {i++;}return i ?// Do a sibling check if the nodes have a common ancestor// 比較a,b的同級一個祖先之下的兩個兄弟節點的位置siblingCheck( ap[i], bp[i] ) :// Otherwise nodes in our document sort firstap[i] === preferredDoc ? -1 :bp[i] === preferredDoc ? 1 :0;};//返回documentreturn doc;};