script/vendor/legacy/CSS_selector_engine.js
/**
 * A complex selector is a chain of one or more compound selectors separated by combinators.
 *
 * @param {!string} selector CSS3-selector
 * @param {boolean=} onlyOne only one need
 * @param {(Document|Node|Array.<Node>)=} root
 * @this {(Document|Node)}
 * @return {(Array.<Node>|NodeList)} return NodeList if onlyOne == true
 */
A complex selector is a chain of one or more compound selectors separated by combinators.
A complex selector is a chain of one or more compound selectors separated by combinators .
function queryComplexSelector(selector, onlyOne, root) {
	var hasNodesRef = !!root && this.nodeType === 9
		, result = []
		, selElements
		, root_is_iterable_object
		, nqs_node
		, i
	;
	root = hasNodesRef ? root : this;
	if(document_native_querySelectorAll) {
		try {
			if(hasNodesRef && IS_QUERY_SELECTOR_SUPPORT_REF_NODES) {
				return _NodeList_from(document_native_querySelectorAll.call(this, selector, root));
			}
			root_is_iterable_object =
				typeof root["length"] == "number" && root["nodeType"] === void 0;
			nqs_node = root_is_iterable_object ? root[0] : root;
			i = 0;
			do {
				if(onlyOne) {
					return [
						(nqs_node.nodeType === 9 ? document_native_querySelector : native_querySelector).call(nqs_node, selector)
					]
				}
				else {
					selElements =
						(nqs_node.nodeType === 9 ? document_native_querySelectorAll : native_querySelectorAll).call(nqs_node, selector);
				}
				if(selElements.length) {
					if(root_is_iterable_object) {
						result = result.concat(_Array_slice.call(selElements));
					}
					else {
						result = selElements;
					}
				}
			}
			while(root_is_iterable_object && (nqs_node = root[++i]));
			return _NodeList_from(result);
		}
		catch(__e__) {
			result = [];
		}
	}
	selector = _String_trim.call(selector.replace(RE__queryComplexSelector__doubleSpaces, "$1"));
	var
		rule
		, resultKeys
		, nextRule
		, isLastRule
		, isFirstRule = true
		, fail = false
		, need_SparseArray
		, nodeSortingNeeds
		, forseNo_need_SparseArray = !!document.querySelector["__noorder__"] || !!document.querySelectorAll["__noorder__"]
		, rules = selector
			.replace(RE__querySelector__arrtSpaceSeparated_toSafe, "@=")
			.replace(RE__queryCompoundSelector__pseudoNthChildPlus, STRING_FOR_RE__queryCompoundSelector__pseudoNthChildPlus)
			.match(RE__queryComplexSelector__selectorsMatcher)
		, parsedRule
		, haveStackedResult
		, stackedResult
		, k
		, l
	;
	selElements = root;
	while(rule = rules.shift()) {
		nextRule = rules[0];
		isLastRule = !nextRule || nextRule.charAt(0) === ',';
		if((!__GCC__ONLY_FOR_IELT8_BUILD__ && !nodeSourceIndex_support) && nextRule && nextRule.length > 1 && !resultKeys)resultKeys = {};
		if(!fail) {
			if(isFirstRule
				&& ("nodeType" in root) && root.nodeType === 9
				&& rule.toUpperCase() === "BODY") {
				selElements = [root["body"]];
				isLastRule ? (result = selElements) : result.concat(selElements);
			}
			else if(isFirstRule && rule === ":root") {
				selElements = [(root.nodeType === 9 ? root : root.ownerDocument)["documentElement"]];
				isLastRule && (result = selElements);
			}
			else if(selElements && (!(root = selElements) || selElements.length === 0)) {
				selElements = null;
				fail = true;
			}
			else {
				nodeSortingNeeds = (isLastRule && (nodeSortingNeeds || !!nextRule || root.length > 1));
				need_SparseArray = !forseNo_need_SparseArray
				   && (__GCC__ONLY_FOR_IELT8_BUILD__ || nodeSourceIndex_support)
				   && nodeSortingNeeds
				;
				parsedRule = rule.match(RE__queryCompoundSelector__selectorMatch);
				selElements =
					parsedRule ?
						queryCompoundSelector(
							parsedRule,
							root,
							isLastRule && !haveStackedResult ? result : [],
							need_SparseArray,
							null,
							onlyOne && isLastRule && !haveStackedResult,
							(!__GCC__ONLY_FOR_IELT8_BUILD__ && !nodeSourceIndex_support)
								&& (
									isLastRule && resultKeys
										|| !isFirstRule && root.length > 1 && {}
								),
							haveStackedResult,
							isFirstRule
						)
						:
						[]
				;
				if(haveStackedResult) {
					l = stackedResult.length;
					while(l-- > 0) {
						if(!selElements[l]) {
							selElements.splice(l, 1);
							stackedResult.splice(l, 1);
						}
					}
					if(isLastRule && stackedResult.length) {
						if(onlyOne)return stackedResult[0];
						result = result.concat(stackedResult);
					}
				}
				if(parsedRule && parsedRule[7] !== void 0 && selElements.length && !isLastRule) {
					if(haveStackedResult)throwSyntaxErrException();
					haveStackedResult = true;
					stackedResult = [];
					k = -1;
					l = selElements.length;
					while(++k < l) {
						stackedResult.push(selElements[k]);
					}
				}
				if(selector === "," || !parsedRule)throwSyntaxErrException();
			}
		}
		if(onlyOne && isLastRule && selElements && selElements.length) {
			return selElements[0];
		}
		if(isFirstRule = isLastRule) {
			if(!result.length && selElements) {
				nodeSortingNeeds = false;
				result = _NodeList_from(selElements);
			}
			selElements = null;
			root = this;
			fail = false;
			if(haveStackedResult) {
				stackedResult = haveStackedResult = void 0;
			}
		}
		if(!nextRule || nextRule === ",")break;
	}
	if(!__GCC__ONLY_FOR_IELT8_BUILD__ && !nodeSourceIndex_support && nodeSortingNeeds) {
		result.sort(queryComplexSelector_sort);
	}
	return nodeSortingNeeds ?
		_NodeList_from(result, true)
		:
		result
	;
}
function queryComplexSelector ( selector , onlyOne , root ) { var hasNodesRef = ! ! root && this . nodeType === 9 , result = [ ] , selElements , root_is_iterable_object , nqs_node , i ; root = hasNodesRef ? root : this ; if ( document_native_querySelectorAll ) { try { if ( hasNodesRef && IS_QUERY_SELECTOR_SUPPORT_REF_NODES ) { return _NodeList_from ( document_native_querySelectorAll . call ( this , selector , root ) ) ; } root_is_iterable_object = typeof root [ "length" ] == "number" && root [ "nodeType" ] === void 0 ; nqs_node = root_is_iterable_object ? root [ 0 ] : root ; i = 0 ; do { if ( onlyOne ) { return [ ( nqs_node . nodeType === 9 ? document_native_querySelector : native_querySelector ) . call ( nqs_node , selector ) ] } else { selElements = ( nqs_node . nodeType === 9 ? document_native_querySelectorAll : native_querySelectorAll ) . call ( nqs_node , selector ) ; } if ( selElements . length ) { if ( root_is_iterable_object ) { result = result . concat ( _Array_slice . call ( selElements ) ) ; } else { result = selElements ; } } } while ( root_is_iterable_object && ( nqs_node = root [ ++ i ] ) ) ; return _NodeList_from ( result ) ; } catch ( __e__ ) { result = [ ] ; } } selector = _String_trim . call ( selector . replace ( RE__queryComplexSelector__doubleSpaces , "$1" ) ) ; var rule , resultKeys , nextRule , isLastRule , isFirstRule = true , fail = false , need_SparseArray , nodeSortingNeeds , forseNo_need_SparseArray = ! ! document . querySelector [ "__noorder__" ] || ! ! document . querySelectorAll [ "__noorder__" ] , rules = selector . replace ( RE__querySelector__arrtSpaceSeparated_toSafe , "@=" ) . replace ( RE__queryCompoundSelector__pseudoNthChildPlus , STRING_FOR_RE__queryCompoundSelector__pseudoNthChildPlus ) . match ( RE__queryComplexSelector__selectorsMatcher ) , parsedRule , haveStackedResult , stackedResult , k , l ; selElements = root ; while ( rule = rules . shift ( ) ) { nextRule = rules [ 0 ] ; isLastRule = ! nextRule || nextRule . charAt ( 0 ) === ',' ; if ( ( ! __GCC__ONLY_FOR_IELT8_BUILD__ && ! nodeSourceIndex_support ) && nextRule && nextRule . length > 1 && ! resultKeys ) resultKeys = { } ; if ( ! fail ) { if ( isFirstRule && ( "nodeType" in root ) && root . nodeType === 9 && rule . toUpperCase ( ) === "BODY" ) { selElements = [ root [ "body" ] ] ; isLastRule ? ( result = selElements ) : result . concat ( selElements ) ; } else if ( isFirstRule && rule === ":root" ) { selElements = [ ( root . nodeType === 9 ? root : root . ownerDocument ) [ "documentElement" ] ] ; isLastRule && ( result = selElements ) ; } else if ( selElements && ( ! ( root = selElements ) || selElements . length === 0 ) ) { selElements = null ; fail = true ; } else { nodeSortingNeeds = ( isLastRule && ( nodeSortingNeeds || ! ! nextRule || root . length > 1 ) ) ; need_SparseArray = ! forseNo_need_SparseArray && ( __GCC__ONLY_FOR_IELT8_BUILD__ || nodeSourceIndex_support ) && nodeSortingNeeds ; parsedRule = rule . match ( RE__queryCompoundSelector__selectorMatch ) ; selElements = parsedRule ? queryCompoundSelector ( parsedRule , root , isLastRule && ! haveStackedResult ? result : [ ] , need_SparseArray , null , onlyOne && isLastRule && ! haveStackedResult , ( ! __GCC__ONLY_FOR_IELT8_BUILD__ && ! nodeSourceIndex_support ) && ( isLastRule && resultKeys || ! isFirstRule && root . length > 1 && { } ) , haveStackedResult , isFirstRule ) : [ ] ; if ( haveStackedResult ) { l = stackedResult . length ; while ( l -- > 0 ) { if ( ! selElements [ l ] ) { selElements . splice ( l , 1 ) ; stackedResult . splice ( l , 1 ) ; } } if ( isLastRule && stackedResult . length ) { if ( onlyOne ) return stackedResult [ 0 ] ; result = result . concat ( stackedResult ) ; } } if ( parsedRule && parsedRule [ 7 ] !== void 0 && selElements . length && ! isLastRule ) { if ( haveStackedResult ) throwSyntaxErrException ( ) ; haveStackedResult = true ; stackedResult = [ ] ; k = - 1 ; l = selElements . length ; while ( ++ k < l ) { stackedResult . push ( selElements [ k ] ) ; } } if ( selector === "," || ! parsedRule ) throwSyntaxErrException ( ) ; } } if ( onlyOne && isLastRule && selElements && selElements . length ) { return selElements [ 0 ] ; } if ( isFirstRule = isLastRule ) { if ( ! result . length && selElements ) { nodeSortingNeeds = false ; result = _NodeList_from ( selElements ) ; } selElements = null ; root = this ; fail = false ; if ( haveStackedResult ) { stackedResult = haveStackedResult = void 0 ; } } if ( ! nextRule || nextRule === "," ) break ; } if ( ! __GCC__ONLY_FOR_IELT8_BUILD__ && ! nodeSourceIndex_support && nodeSortingNeeds ) { result . sort ( queryComplexSelector_sort ) ; } return nodeSortingNeeds ? _NodeList_from ( result , true ) : result ; }
A complex selector is a chain of one or more compound selectors separated by combinators.
A complex selector is a chain of one or more compound selectors separated by combinators .
//nodesRef supporting only in document.querySelector[All] /** @type {boolean} */ /*1*/ /*2*/ //1. fast and unsafe isArray 2. Not a <form> //For CSS4 parent selector //For CSS4 parent selector //root is document //"Boris Zbarsky <bzbarsky@MIT.EDU>": Mapping selector == "body" to document.body. This isn't a valid optimization for querySelector, since there can in fact be multiple <body> tags and since furthermore document.body can be a <frameset>. A UA could try to optimize this case by keeping track of the <body> tags and such, at some cost on every DOM mutation. //No result in previous rule -> Nothing to do //CSS3 selector and part of CSS4 selector /*TODO::CSS4 Reference combinator
				 else if(parsedRule[1] == "/") {
				 if(parsedRule[4] || parsedRule[5] || parsedRule[6] || parsedRule[7] || (!nextRule && nextRule === ",")) {
				 //TODO:: _throwDOMException("SYNTAX_ERR");
				 }
				 else {
				 rules[1] = nextRule.substr(1);//TODO::
				 }
				 }*/ //tagName#id.class! <-- "!" CSS4 parent selector //Can be only one "!" parent selector in one compound selector //If last rule in this selector //For CSS4 parent selector