jquery/jquery

View on GitHub
src/selector-native.js

Summary

Maintainability
C
7 hrs
Test Coverage
define( [
    "./core",
    "./var/document",
    "./var/documentElement",
    "./var/hasOwn",
    "./var/indexOf"
], function( jQuery, document, documentElement, hasOwn, indexOf ) {

"use strict";

/*
 * Optional (non-Sizzle) selector module for custom builds.
 *
 * Note that this DOES NOT SUPPORT many documented jQuery
 * features in exchange for its smaller size:
 *
 * Attribute not equal selector
 * Positional selectors (:first; :eq(n); :odd; etc.)
 * Type selectors (:input; :checkbox; :button; etc.)
 * State-based selectors (:animated; :visible; :hidden; etc.)
 * :has(selector)
 * :not(complex selector)
 * custom selectors via Sizzle extensions
 * Leading combinators (e.g., $collection.find("> *"))
 * Reliable functionality on XML fragments
 * Requiring all parts of a selector to match elements under context
 *   (e.g., $div.find("div > *") now matches children of $div)
 * Matching against non-elements
 * Reliable sorting of disconnected nodes
 * querySelectorAll bug fixes (e.g., unreliable :focus on WebKit)
 *
 * If any of these are unacceptable tradeoffs, either use Sizzle or
 * customize this stub for the project's specific needs.
 */

var hasDuplicate, sortInput,
    sortStable = jQuery.expando.split( "" ).sort( sortOrder ).join( "" ) === jQuery.expando,
    matches = documentElement.matches ||
        documentElement.webkitMatchesSelector ||
        documentElement.mozMatchesSelector ||
        documentElement.oMatchesSelector ||
        documentElement.msMatchesSelector,

    // CSS string/identifier serialization
    // https://drafts.csswg.org/cssom/#common-serializing-idioms
    rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g,
    fcssescape = function( ch, asCodePoint ) {
        if ( asCodePoint ) {

            // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
            if ( ch === "\0" ) {
                return "\uFFFD";
            }

            // Control characters and (dependent upon position) numbers get escaped as code points
            return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
        }

        // Other potentially-special ASCII characters get backslash-escaped
        return "\\" + ch;
    };

function sortOrder( a, b ) {

    // Flag for duplicate removal
    if ( a === b ) {
        hasDuplicate = true;
        return 0;
    }

    // Sort on method existence if only one input has compareDocumentPosition
    var 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 disconnected
        1;

    // Disconnected nodes
    if ( compare & 1 ) {

        // Choose the first element that is related to our preferred document
        if ( a === document || a.ownerDocument === document &&
            jQuery.contains( document, a ) ) {
            return -1;
        }
        if ( b === document || b.ownerDocument === document &&
            jQuery.contains( document, b ) ) {
            return 1;
        }

        // Maintain original order
        return sortInput ?
            ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
            0;
    }

    return compare & 4 ? -1 : 1;
}

function uniqueSort( results ) {
    var elem,
        duplicates = [],
        j = 0,
        i = 0;

    hasDuplicate = false;
    sortInput = !sortStable && results.slice( 0 );
    results.sort( sortOrder );

    if ( hasDuplicate ) {
        while ( ( elem = results[ i++ ] ) ) {
            if ( elem === results[ i ] ) {
                j = duplicates.push( i );
            }
        }
        while ( j-- ) {
            results.splice( duplicates[ j ], 1 );
        }
    }

    // Clear input after sorting to release objects
    // See https://github.com/jquery/sizzle/pull/225
    sortInput = null;

    return results;
}

function escape( sel ) {
    return ( sel + "" ).replace( rcssescape, fcssescape );
}

jQuery.extend( {
    uniqueSort: uniqueSort,
    unique: uniqueSort,
    escapeSelector: escape,
    find: function( selector, context, results, seed ) {
        var elem, nodeType,
            i = 0;

        results = results || [];
        context = context || document;

        // Same basic safeguard as Sizzle
        if ( !selector || typeof selector !== "string" ) {
            return results;
        }

        // Early return if context is not an element or document
        if ( ( nodeType = context.nodeType ) !== 1 && nodeType !== 9 ) {
            return [];
        }

        if ( seed ) {
            while ( ( elem = seed[ i++ ] ) ) {
                if ( jQuery.find.matchesSelector( elem, selector ) ) {
                    results.push( elem );
                }
            }
        } else {
            jQuery.merge( results, context.querySelectorAll( selector ) );
        }

        return results;
    },
    text: function( elem ) {
        var node,
            ret = "",
            i = 0,
            nodeType = elem.nodeType;

        if ( !nodeType ) {

            // If no nodeType, this is expected to be an array
            while ( ( node = elem[ i++ ] ) ) {

                // Do not traverse comment nodes
                ret += jQuery.text( node );
            }
        } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {

            // Use textContent for elements
            return elem.textContent;
        } else if ( nodeType === 3 || nodeType === 4 ) {
            return elem.nodeValue;
        }

        // Do not include comment or processing instruction nodes

        return ret;
    },
    contains: function( a, b ) {
        var adown = a.nodeType === 9 ? a.documentElement : a,
            bup = b && b.parentNode;
        return a === bup || !!( bup && bup.nodeType === 1 && adown.contains( bup ) );
    },
    isXMLDoc: 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 ).documentElement;
        return documentElement ? documentElement.nodeName !== "HTML" : false;
    },
    expr: {
        attrHandle: {},
        match: {
            bool: new RegExp( "^(?:checked|selected|async|autofocus|autoplay|controls|defer" +
                "|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped)$", "i" ),
            needsContext: /^[\x20\t\r\n\f]*[>+~]/
        }
    }
} );

jQuery.extend( jQuery.find, {
    matches: function( expr, elements ) {
        return jQuery.find( expr, null, null, elements );
    },
    matchesSelector: function( elem, expr ) {
        return matches.call( elem, expr );
    },
    attr: function( elem, name ) {
        var fn = jQuery.expr.attrHandle[ name.toLowerCase() ],

            // Don't get fooled by Object.prototype properties (jQuery #13807)
            value = fn && hasOwn.call( jQuery.expr.attrHandle, name.toLowerCase() ) ?
                fn( elem, name, jQuery.isXMLDoc( elem ) ) :
                undefined;
        return value !== undefined ? value : elem.getAttribute( name );
    }
} );

} );