Skip to content
This repository
Browse code

Update MooTools to version 1.3.2.

  • Loading branch information...
commit 2bf2ba5c7cbba19fae78b06da4fe8ddc8bce4063 1 parent f5c536e
Rouven Weßling authored June 13, 2011
1,220  media/system/js/mootools-core-uncompressed.js
@@ -33,8 +33,8 @@ provides: [Core, MooTools, Type, typeOf, instanceOf, Native]
33 33
 (function(){
34 34
 
35 35
 this.MooTools = {
36  
-	version: '1.3',
37  
-	build: 'a3eed692dd85050d80168ec2c708efe901bb7db3'
  36
+	version: '1.3.2',
  37
+	build: 'c9f1ff10e9e7facb65e9481049ed1b450959d587'
38 38
 };
39 39
 
40 40
 // typeOf, instanceOf
@@ -196,7 +196,7 @@ var hooksOf = function(object){
196 196
 };
197 197
 
198 198
 var implement = function(name, method){
199  
-	if (method && method.$hidden) return this;
  199
+	if (method && method.$hidden) return;
200 200
 
201 201
 	var hooks = hooksOf(this);
202 202
 
@@ -205,22 +205,19 @@ var implement = function(name, method){
205 205
 		if (typeOf(hook) == 'type') implement.call(hook, name, method);
206 206
 		else hook.call(this, name, method);
207 207
 	}
208  
-
  208
+	
209 209
 	var previous = this.prototype[name];
210 210
 	if (previous == null || !previous.$protected) this.prototype[name] = method;
211 211
 
212 212
 	if (this[name] == null && typeOf(method) == 'function') extend.call(this, name, function(item){
213 213
 		return method.apply(item, slice.call(arguments, 1));
214 214
 	});
215  
-
216  
-	return this;
217 215
 };
218 216
 
219 217
 var extend = function(name, method){
220  
-	if (method && method.$hidden) return this;
  218
+	if (method && method.$hidden) return;
221 219
 	var previous = this[name];
222 220
 	if (previous == null || !previous.$protected) this[name] = method;
223  
-	return this;
224 221
 };
225 222
 
226 223
 Type.implement({
@@ -308,9 +305,10 @@ Number.extend('random', function(min, max){
308 305
 
309 306
 // forEach, each
310 307
 
  308
+var hasOwnProperty = Object.prototype.hasOwnProperty;
311 309
 Object.extend('forEach', function(object, fn, bind){
312 310
 	for (var key in object){
313  
-		if (object.hasOwnProperty(key)) fn.call(bind, object[key], key, object);
  311
+		if (hasOwnProperty.call(object, key)) fn.call(bind, object[key], key, object);
314 312
 	}
315 313
 });
316 314
 
@@ -541,13 +539,7 @@ provides: Array
541 539
 
542 540
 Array.implement({
543 541
 
544  
-	invoke: function(methodName){
545  
-		var args = Array.slice(arguments, 1);
546  
-		return this.map(function(item){
547  
-			return item[methodName].apply(item, args);
548  
-		});
549  
-	},
550  
-
  542
+	/*<!ES5>*/
551 543
 	every: function(fn, bind){
552 544
 		for (var i = 0, l = this.length; i < l; i++){
553 545
 			if ((i in this) && !fn.call(bind, this[i], i, this)) return false;
@@ -563,12 +555,6 @@ Array.implement({
563 555
 		return results;
564 556
 	},
565 557
 
566  
-	clean: function(){
567  
-		return this.filter(function(item){
568  
-			return item != null;
569  
-		});
570  
-	},
571  
-
572 558
 	indexOf: function(item, from){
573 559
 		var len = this.length;
574 560
 		for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){
@@ -591,6 +577,20 @@ Array.implement({
591 577
 		}
592 578
 		return false;
593 579
 	},
  580
+	/*</!ES5>*/
  581
+
  582
+	clean: function(){
  583
+		return this.filter(function(item){
  584
+			return item != null;
  585
+		});
  586
+	},
  587
+
  588
+	invoke: function(methodName){
  589
+		var args = Array.slice(arguments, 1);
  590
+		return this.map(function(item){
  591
+			return item[methodName].apply(item, args);
  592
+		});
  593
+	},
594 594
 
595 595
 	associate: function(keys){
596 596
 		var obj = {}, length = Math.min(this.length, keys.length);
@@ -874,20 +874,22 @@ Function.implement({
874 874
 		try {
875 875
 			return this.apply(bind, Array.from(args));
876 876
 		} catch (e){}
877  
-
  877
+		
878 878
 		return null;
879 879
 	},
880 880
 
  881
+	/*<!ES5>*/
881 882
 	bind: function(bind){
882 883
 		var self = this,
883 884
 			args = (arguments.length > 1) ? Array.slice(arguments, 1) : null;
884  
-
  885
+		
885 886
 		return function(){
886 887
 			if (!args && !arguments.length) return self.call(bind);
887 888
 			if (args && arguments.length) return self.apply(bind, args.concat(Array.from(arguments)));
888 889
 			return self.apply(bind, args || arguments);
889 890
 		};
890 891
 	},
  892
+	/*</!ES5>*/
891 893
 
892 894
 	pass: function(args, bind){
893 895
 		var self = this;
@@ -898,11 +900,11 @@ Function.implement({
898 900
 	},
899 901
 
900 902
 	delay: function(delay, bind, args){
901  
-		return setTimeout(this.pass(args, bind), delay);
  903
+		return setTimeout(this.pass((args == null ? [] : args), bind), delay);
902 904
 	},
903 905
 
904 906
 	periodical: function(periodical, bind, args){
905  
-		return setInterval(this.pass(args, bind), periodical);
  907
+		return setInterval(this.pass((args == null ? [] : args), bind), periodical);
906 908
 	}
907 909
 
908 910
 });
@@ -973,6 +975,9 @@ provides: [Object, Hash]
973 975
 ...
974 976
 */
975 977
 
  978
+(function(){
  979
+
  980
+var hasOwnProperty = Object.prototype.hasOwnProperty;
976 981
 
977 982
 Object.extend({
978 983
 
@@ -980,7 +985,7 @@ Object.extend({
980 985
 		var results = {};
981 986
 		for (var i = 0, l = keys.length; i < l; i++){
982 987
 			var k = keys[i];
983  
-			results[k] = object[k];
  988
+			if (k in object) results[k] = object[k];
984 989
 		}
985 990
 		return results;
986 991
 	},
@@ -988,29 +993,30 @@ Object.extend({
988 993
 	map: function(object, fn, bind){
989 994
 		var results = {};
990 995
 		for (var key in object){
991  
-			if (object.hasOwnProperty(key)) results[key] = fn.call(bind, object[key], key, object);
  996
+			if (hasOwnProperty.call(object, key)) results[key] = fn.call(bind, object[key], key, object);
992 997
 		}
993 998
 		return results;
994 999
 	},
995 1000
 
996 1001
 	filter: function(object, fn, bind){
997 1002
 		var results = {};
998  
-		Object.each(object, function(value, key){
999  
-			if (fn.call(bind, value, key, object)) results[key] = value;
1000  
-		});
  1003
+		for (var key in object){
  1004
+			var value = object[key];
  1005
+			if (hasOwnProperty.call(object, key) && fn.call(bind, value, key, object)) results[key] = value;
  1006
+		}
1001 1007
 		return results;
1002 1008
 	},
1003 1009
 
1004 1010
 	every: function(object, fn, bind){
1005 1011
 		for (var key in object){
1006  
-			if (object.hasOwnProperty(key) && !fn.call(bind, object[key], key)) return false;
  1012
+			if (hasOwnProperty.call(object, key) && !fn.call(bind, object[key], key)) return false;
1007 1013
 		}
1008 1014
 		return true;
1009 1015
 	},
1010 1016
 
1011 1017
 	some: function(object, fn, bind){
1012 1018
 		for (var key in object){
1013  
-			if (object.hasOwnProperty(key) && fn.call(bind, object[key], key)) return true;
  1019
+			if (hasOwnProperty.call(object, key) && fn.call(bind, object[key], key)) return true;
1014 1020
 		}
1015 1021
 		return false;
1016 1022
 	},
@@ -1018,7 +1024,7 @@ Object.extend({
1018 1024
 	keys: function(object){
1019 1025
 		var keys = [];
1020 1026
 		for (var key in object){
1021  
-			if (object.hasOwnProperty(key)) keys.push(key);
  1027
+			if (hasOwnProperty.call(object, key)) keys.push(key);
1022 1028
 		}
1023 1029
 		return keys;
1024 1030
 	},
@@ -1026,7 +1032,7 @@ Object.extend({
1026 1032
 	values: function(object){
1027 1033
 		var values = [];
1028 1034
 		for (var key in object){
1029  
-			if (object.hasOwnProperty(key)) values.push(object[key]);
  1035
+			if (hasOwnProperty.call(object, key)) values.push(object[key]);
1030 1036
 		}
1031 1037
 		return values;
1032 1038
 	},
@@ -1037,7 +1043,7 @@ Object.extend({
1037 1043
 
1038 1044
 	keyOf: function(object, value){
1039 1045
 		for (var key in object){
1040  
-			if (object.hasOwnProperty(key) && object[key] === value) return key;
  1046
+			if (hasOwnProperty.call(object, key) && object[key] === value) return key;
1041 1047
 		}
1042 1048
 		return null;
1043 1049
 	},
@@ -1071,6 +1077,7 @@ Object.extend({
1071 1077
 
1072 1078
 });
1073 1079
 
  1080
+})();
1074 1081
 
1075 1082
 //<1.2compat>
1076 1083
 
@@ -1324,12 +1331,13 @@ Document.mirror(function(name, method){
1324 1331
 });
1325 1332
 
1326 1333
 document.html = document.documentElement;
1327  
-document.head = document.getElementsByTagName('head')[0];
  1334
+if (!document.head) document.head = document.getElementsByTagName('head')[0];
1328 1335
 
1329 1336
 if (document.execCommand) try {
1330 1337
 	document.execCommand("BackgroundImageCache", false, true);
1331 1338
 } catch (e){}
1332 1339
 
  1340
+/*<ltIE9>*/
1333 1341
 if (this.attachEvent && !this.addEventListener){
1334 1342
 	var unloadEvent = function(){
1335 1343
 		this.detachEvent('onunload', unloadEvent);
@@ -1361,6 +1369,7 @@ try {
1361 1369
 		};
1362 1370
 	});
1363 1371
 }
  1372
+/*</ltIE9>*/
1364 1373
 
1365 1374
 //<1.2compat>
1366 1375
 
@@ -1452,18 +1461,20 @@ var Event = new Type('Event', function(event, win){
1452 1461
 	var type = event.type,
1453 1462
 		target = event.target || event.srcElement,
1454 1463
 		page = {},
1455  
-		client = {};
  1464
+		client = {},
  1465
+		related = null,
  1466
+		rightClick, wheel, code, key;
1456 1467
 	while (target && target.nodeType == 3) target = target.parentNode;
1457 1468
 
1458 1469
 	if (type.indexOf('key') != -1){
1459  
-		var code = event.which || event.keyCode;
1460  
-		var key = Object.keyOf(Event.Keys, code);
  1470
+		code = event.which || event.keyCode;
  1471
+		key = Object.keyOf(Event.Keys, code);
1461 1472
 		if (type == 'keydown'){
1462 1473
 			var fKey = code - 111;
1463 1474
 			if (fKey > 0 && fKey < 13) key = 'f' + fKey;
1464 1475
 		}
1465 1476
 		if (!key) key = String.fromCharCode(code).toLowerCase();
1466  
-	} else if (type.test(/click|mouse|menu/i)){
  1477
+	} else if ((/click|mouse|menu/i).test(type)){
1467 1478
 		doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
1468 1479
 		page = {
1469 1480
 			x: (event.pageX != null) ? event.pageX : event.clientX + doc.scrollLeft,
@@ -1473,12 +1484,11 @@ var Event = new Type('Event', function(event, win){
1473 1484
 			x: (event.pageX != null) ? event.pageX - win.pageXOffset : event.clientX,
1474 1485
 			y: (event.pageY != null) ? event.pageY - win.pageYOffset : event.clientY
1475 1486
 		};
1476  
-		if (type.test(/DOMMouseScroll|mousewheel/)){
1477  
-			var wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
  1487
+		if ((/DOMMouseScroll|mousewheel/).test(type)){
  1488
+			wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
1478 1489
 		}
1479  
-		var rightClick = (event.which == 3) || (event.button == 2),
1480  
-			related = null;
1481  
-		if (type.test(/over|out/)){
  1490
+		rightClick = (event.which == 3) || (event.button == 2);
  1491
+		if ((/over|out/).test(type)){
1482 1492
 			related = event.relatedTarget || event[(type == 'mouseover' ? 'from' : 'to') + 'Element'];
1483 1493
 			var testRelated = function(){
1484 1494
 				while (related && related.nodeType == 3) related = related.parentNode;
@@ -1487,7 +1497,7 @@ var Event = new Type('Event', function(event, win){
1487 1497
 			var hasRelated = (Browser.firefox2) ? testRelated.attempt() : testRelated();
1488 1498
 			related = (hasRelated) ? related : null;
1489 1499
 		}
1490  
-	} else if (type.test(/gesture|touch/i)){
  1500
+	} else if ((/gesture|touch/i).test(type)){
1491 1501
 		this.rotation = event.rotation;
1492 1502
 		this.scale = event.scale;
1493 1503
 		this.targetTouches = event.targetTouches;
@@ -1756,7 +1766,7 @@ this.Events = new Class({
1756 1766
 		}, this);
1757 1767
 		return this;
1758 1768
 	},
1759  
-
  1769
+	
1760 1770
 	removeEvent: function(type, fn){
1761 1771
 		type = removeOn(type);
1762 1772
 		var events = this.$events[type];
@@ -1777,7 +1787,9 @@ this.Events = new Class({
1777 1787
 		for (type in this.$events){
1778 1788
 			if (events && events != type) continue;
1779 1789
 			var fns = this.$events[type];
1780  
-			for (var i = fns.length; i--;) this.removeEvent(type, fns[i]);
  1790
+			for (var i = fns.length; i--;) if (i in fns){
  1791
+				this.removeEvent(type, fns[i]);
  1792
+			}
1781 1793
 		}
1782 1794
 		return this;
1783 1795
 	}
@@ -1788,8 +1800,7 @@ this.Options = new Class({
1788 1800
 
1789 1801
 	setOptions: function(){
1790 1802
 		var options = this.options = Object.merge.apply(null, [{}, this.options].append(arguments));
1791  
-		if (!this.addEvent) return this;
1792  
-		for (var option in options){
  1803
+		if (this.addEvent) for (var option in options){
1793 1804
 			if (typeOf(options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue;
1794 1805
 			this.addEvent(option, options[option]);
1795 1806
 			delete options[option];
@@ -1810,7 +1821,7 @@ provides: Slick.Parser
1810 1821
 ...
1811 1822
 */
1812 1823
 
1813  
-(function(){
  1824
+;(function(){
1814 1825
 
1815 1826
 var parsed,
1816 1827
 	separatorIndex,
@@ -1827,13 +1838,18 @@ var parse = function(expression, isReversed){
1827 1838
 	reversed = !!isReversed;
1828 1839
 	var currentCache = (reversed) ? reverseCache : cache;
1829 1840
 	if (currentCache[expression]) return currentCache[expression];
1830  
-	parsed = {Slick: true, expressions: [], raw: expression, reverse: function(){
1831  
-		return parse(this.raw, true);
1832  
-	}};
  1841
+	parsed = {
  1842
+		Slick: true,
  1843
+		expressions: [],
  1844
+		raw: expression,
  1845
+		reverse: function(){
  1846
+			return parse(this.raw, true);
  1847
+		}
  1848
+	};
1833 1849
 	separatorIndex = -1;
1834 1850
 	while (expression != (expression = expression.replace(regexp, parser)));
1835 1851
 	parsed.length = parsed.expressions.length;
1836  
-	return currentCache[expression] = (reversed) ? reverse(parsed) : parsed;
  1852
+	return currentCache[parsed.raw] = (reversed) ? reverse(parsed) : parsed;
1837 1853
 };
1838 1854
 
1839 1855
 var reverseCombinator = function(combinator){
@@ -1862,7 +1878,9 @@ var reverse = function(expression){
1862 1878
 };
1863 1879
 
1864 1880
 var escapeRegExp = function(string){// Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan <http://stevenlevithan.com/regex/xregexp/> MIT License
1865  
-	return string.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, "\\$&");
  1881
+	return string.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, function(match){
  1882
+		return '\\' + match;
  1883
+	});
1866 1884
 };
1867 1885
 
1868 1886
 var regexp = new RegExp(
@@ -1894,7 +1912,7 @@ __END__
1894 1912
 	)?\
1895 1913
 	)"
1896 1914
 */
1897  
-	"^(?:\\s*(,)\\s*|\\s*(<combinator>+)\\s*|(\\s+)|(<unicode>+|\\*)|\\#(<unicode>+)|\\.(<unicode>+)|\\[\\s*(<unicode1>+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|:+(<unicode>+)(?:\\((?:(?:([\"'])([^\\12]*)\\12)|((?:\\([^)]+\\)|[^()]*)+))\\))?)"
  1915
+	"^(?:\\s*(,)\\s*|\\s*(<combinator>+)\\s*|(\\s+)|(<unicode>+|\\*)|\\#(<unicode>+)|\\.(<unicode>+)|\\[\\s*(<unicode1>+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|(:+)(<unicode>+)(?:\\((?:(?:([\"'])([^\\13]*)\\13)|((?:\\([^)]+\\)|[^()]*)+))\\))?)"
1898 1916
 	.replace(/<combinator>/, '[' + escapeRegExp(">+~`!@$%^&={}\\;</") + ']')
1899 1917
 	.replace(/<unicode>/g, '(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
1900 1918
 	.replace(/<unicode1>/g, '(?:[:\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
@@ -1916,6 +1934,7 @@ function parser(
1916 1934
 	attributeQuote,
1917 1935
 	attributeValue,
1918 1936
 
  1937
+	pseudoMarker,
1919 1938
 	pseudoClass,
1920 1939
 	pseudoQuote,
1921 1940
 	pseudoClassQuotedValue,
@@ -1961,7 +1980,8 @@ function parser(
1961 1980
 		if (!currentParsed.pseudos) currentParsed.pseudos = [];
1962 1981
 		currentParsed.pseudos.push({
1963 1982
 			key: pseudoClass.replace(reUnescape, ''),
1964  
-			value: pseudoClassValue
  1983
+			value: pseudoClassValue,
  1984
+			type: pseudoMarker.length == 1 ? 'class' : 'element'
1965 1985
 		});
1966 1986
 
1967 1987
 	} else if (attributeKey){
@@ -2034,9 +2054,11 @@ requires: Slick.Parser
2034 2054
 ...
2035 2055
 */
2036 2056
 
2037  
-(function(){
  2057
+;(function(){
2038 2058
 
2039  
-var local = {};
  2059
+var local = {},
  2060
+	featuresCache = {},
  2061
+	toString = Object.prototype.toString;
2040 2062
 
2041 2063
 // Feature / Bug detection
2042 2064
 
@@ -2045,16 +2067,16 @@ local.isNativeCode = function(fn){
2045 2067
 };
2046 2068
 
2047 2069
 local.isXML = function(document){
2048  
-	return (!!document.xmlVersion) || (!!document.xml) || (Object.prototype.toString.call(document) === '[object XMLDocument]') ||
2049  
-	(document.nodeType === 9 && document.documentElement.nodeName !== 'HTML');
  2070
+	return (!!document.xmlVersion) || (!!document.xml) || (toString.call(document) == '[object XMLDocument]') ||
  2071
+	(document.nodeType == 9 && document.documentElement.nodeName != 'HTML');
2050 2072
 };
2051 2073
 
2052 2074
 local.setDocument = function(document){
2053 2075
 
2054 2076
 	// convert elements / window arguments to document. if document cannot be extrapolated, the function returns.
2055  
-
2056  
-	if (document.nodeType === 9); // document
2057  
-	else if (document.ownerDocument) document = document.ownerDocument; // node
  2077
+	var nodeType = document.nodeType;
  2078
+	if (nodeType == 9); // document
  2079
+	else if (nodeType) document = document.ownerDocument; // node
2058 2080
 	else if (document.navigator) document = document.document; // window
2059 2081
 	else return;
2060 2082
 
@@ -2062,106 +2084,166 @@ local.setDocument = function(document){
2062 2084
 
2063 2085
 	if (this.document === document) return;
2064 2086
 	this.document = document;
2065  
-	var root = this.root = document.documentElement;
2066  
-
2067  
-	this.isXMLDocument = this.isXML(document);
2068  
-
2069  
-	this.brokenStarGEBTN
2070  
-	= this.starSelectsClosedQSA
2071  
-	= this.idGetsName
2072  
-	= this.brokenMixedCaseQSA
2073  
-	= this.brokenGEBCN
2074  
-	= this.brokenCheckedQSA
2075  
-	= this.brokenEmptyAttributeQSA
2076  
-	= this.isHTMLDocument
  2087
+
  2088
+	// check if we have done feature detection on this document before
  2089
+
  2090
+	var root = document.documentElement,
  2091
+		rootUid = this.getUIDXML(root),
  2092
+		features = featuresCache[rootUid],
  2093
+		feature;
  2094
+
  2095
+	if (features){
  2096
+		for (feature in features){
  2097
+			this[feature] = features[feature];
  2098
+		}
  2099
+		return;
  2100
+	}
  2101
+
  2102
+	features = featuresCache[rootUid] = {};
  2103
+
  2104
+	features.root = root;
  2105
+	features.isXMLDocument = this.isXML(document);
  2106
+
  2107
+	features.brokenStarGEBTN
  2108
+	= features.starSelectsClosedQSA
  2109
+	= features.idGetsName
  2110
+	= features.brokenMixedCaseQSA
  2111
+	= features.brokenGEBCN
  2112
+	= features.brokenCheckedQSA
  2113
+	= features.brokenEmptyAttributeQSA
  2114
+	= features.isHTMLDocument
  2115
+	= features.nativeMatchesSelector
2077 2116
 	= false;
2078 2117
 
2079 2118
 	var starSelectsClosed, starSelectsComments,
2080  
-		brokenSecondClassNameGEBCN, cachedGetElementsByClassName;
  2119
+		brokenSecondClassNameGEBCN, cachedGetElementsByClassName,
  2120
+		brokenFormAttributeGetter;
2081 2121
 
2082  
-	var selected, id;
  2122
+	var selected, id = 'slick_uniqueid';
2083 2123
 	var testNode = document.createElement('div');
2084  
-	root.appendChild(testNode);
  2124
+	
  2125
+	var testRoot = document.body || document.getElementsByTagName('body')[0] || root;
  2126
+	testRoot.appendChild(testNode);
2085 2127
 
2086 2128
 	// on non-HTML documents innerHTML and getElementsById doesnt work properly
2087 2129
 	try {
2088  
-		id = 'slick_getbyid_test';
2089 2130
 		testNode.innerHTML = '<a id="'+id+'"></a>';
2090  
-		this.isHTMLDocument = !!document.getElementById(id);
  2131
+		features.isHTMLDocument = !!document.getElementById(id);
2091 2132
 	} catch(e){};
2092 2133
 
2093  
-	if (this.isHTMLDocument){
  2134
+	if (features.isHTMLDocument){
2094 2135
 
2095 2136
 		testNode.style.display = 'none';
2096 2137
 
2097 2138
 		// IE returns comment nodes for getElementsByTagName('*') for some documents
2098 2139
 		testNode.appendChild(document.createComment(''));
2099  
-		starSelectsComments = (testNode.getElementsByTagName('*').length > 0);
  2140
+		starSelectsComments = (testNode.getElementsByTagName('*').length > 1);
2100 2141
 
2101 2142
 		// IE returns closed nodes (EG:"</foo>") for getElementsByTagName('*') for some documents
2102 2143
 		try {
2103 2144
 			testNode.innerHTML = 'foo</foo>';
2104 2145
 			selected = testNode.getElementsByTagName('*');
2105  
-			starSelectsClosed = (selected && selected.length && selected[0].nodeName.charAt(0) == '/');
  2146
+			starSelectsClosed = (selected && !!selected.length && selected[0].nodeName.charAt(0) == '/');
2106 2147
 		} catch(e){};
2107 2148
 
2108  
-		this.brokenStarGEBTN = starSelectsComments || starSelectsClosed;
2109  
-
2110  
-		// IE 8 returns closed nodes (EG:"</foo>") for querySelectorAll('*') for some documents
2111  
-		if (testNode.querySelectorAll) try {
2112  
-			testNode.innerHTML = 'foo</foo>';
2113  
-			selected = testNode.querySelectorAll('*');
2114  
-			this.starSelectsClosedQSA = (selected && selected.length && selected[0].nodeName.charAt(0) == '/');
2115  
-		} catch(e){};
  2149
+		features.brokenStarGEBTN = starSelectsComments || starSelectsClosed;
2116 2150
 
2117 2151
 		// IE returns elements with the name instead of just id for getElementsById for some documents
2118 2152
 		try {
2119  
-			id = 'slick_id_gets_name';
2120  
-			testNode.innerHTML = '<a name="'+id+'"></a><b id="'+id+'"></b>';
2121  
-			this.idGetsName = document.getElementById(id) === testNode.firstChild;
  2153
+			testNode.innerHTML = '<a name="'+ id +'"></a><b id="'+ id +'"></b>';
  2154
+			features.idGetsName = document.getElementById(id) === testNode.firstChild;
2122 2155
 		} catch(e){};
2123 2156
 
2124  
-		// Safari 3.2 querySelectorAll doesnt work with mixedcase on quirksmode
2125  
-		try {
2126  
-			testNode.innerHTML = '<a class="MiXedCaSe"></a>';
2127  
-			this.brokenMixedCaseQSA = !testNode.querySelectorAll('.MiXedCaSe').length;
2128  
-		} catch(e){};
  2157
+		if (testNode.getElementsByClassName){
2129 2158
 
2130  
-		try {
2131  
-			testNode.innerHTML = '<a class="f"></a><a class="b"></a>';
2132  
-			testNode.getElementsByClassName('b').length;
2133  
-			testNode.firstChild.className = 'b';
2134  
-			cachedGetElementsByClassName = (testNode.getElementsByClassName('b').length != 2);
2135  
-		} catch(e){};
  2159
+			// Safari 3.2 getElementsByClassName caches results
  2160
+			try {
  2161
+				testNode.innerHTML = '<a class="f"></a><a class="b"></a>';
  2162
+				testNode.getElementsByClassName('b').length;
  2163
+				testNode.firstChild.className = 'b';
  2164
+				cachedGetElementsByClassName = (testNode.getElementsByClassName('b').length != 2);
  2165
+			} catch(e){};
2136 2166
 
2137  
-		// Opera 9.6 getElementsByClassName doesnt detects the class if its not the first one
2138  
-		try {
2139  
-			testNode.innerHTML = '<a class="a"></a><a class="f b a"></a>';
2140  
-			brokenSecondClassNameGEBCN = (testNode.getElementsByClassName('a').length != 2);
2141  
-		} catch(e){};
  2167
+			// Opera 9.6 getElementsByClassName doesnt detects the class if its not the first one
  2168
+			try {
  2169
+				testNode.innerHTML = '<a class="a"></a><a class="f b a"></a>';
  2170
+				brokenSecondClassNameGEBCN = (testNode.getElementsByClassName('a').length != 2);
  2171
+			} catch(e){};
  2172
+
  2173
+			features.brokenGEBCN = cachedGetElementsByClassName || brokenSecondClassNameGEBCN;
  2174
+		}
  2175
+		
  2176
+		if (testNode.querySelectorAll){
  2177
+			// IE 8 returns closed nodes (EG:"</foo>") for querySelectorAll('*') for some documents
  2178
+			try {
  2179
+				testNode.innerHTML = 'foo</foo>';
  2180
+				selected = testNode.querySelectorAll('*');
  2181
+				features.starSelectsClosedQSA = (selected && !!selected.length && selected[0].nodeName.charAt(0) == '/');
  2182
+			} catch(e){};
  2183
+
  2184
+			// Safari 3.2 querySelectorAll doesnt work with mixedcase on quirksmode
  2185
+			try {
  2186
+				testNode.innerHTML = '<a class="MiX"></a>';
  2187
+				features.brokenMixedCaseQSA = !testNode.querySelectorAll('.MiX').length;
  2188
+			} catch(e){};
  2189
+
  2190
+			// Webkit and Opera dont return selected options on querySelectorAll
  2191
+			try {
  2192
+				testNode.innerHTML = '<select><option selected="selected">a</option></select>';
  2193
+				features.brokenCheckedQSA = (testNode.querySelectorAll(':checked').length == 0);
  2194
+			} catch(e){};
2142 2195
 
2143  
-		this.brokenGEBCN = cachedGetElementsByClassName || brokenSecondClassNameGEBCN;
  2196
+			// IE returns incorrect results for attr[*^$]="" selectors on querySelectorAll
  2197
+			try {
  2198
+				testNode.innerHTML = '<a class=""></a>';
  2199
+				features.brokenEmptyAttributeQSA = (testNode.querySelectorAll('[class*=""]').length != 0);
  2200
+			} catch(e){};
2144 2201
 
2145  
-		// Webkit dont return selected options on querySelectorAll
  2202
+		}
  2203
+
  2204
+		// IE6-7, if a form has an input of id x, form.getAttribute(x) returns a reference to the input
2146 2205
 		try {
2147  
-			testNode.innerHTML = '<select><option selected="selected">a</option></select>';
2148  
-			this.brokenCheckedQSA = (testNode.querySelectorAll(':checked').length == 0);
  2206
+			testNode.innerHTML = '<form action="s"><input id="action"/></form>';
  2207
+			brokenFormAttributeGetter = (testNode.firstChild.getAttribute('action') != 's');
2149 2208
 		} catch(e){};
2150 2209
 
2151  
-		// IE returns incorrect results for attr[*^$]="" selectors on querySelectorAll
2152  
-		try {
2153  
-			testNode.innerHTML = '<a class=""></a>';
2154  
-			this.brokenEmptyAttributeQSA = (testNode.querySelectorAll('[class*=""]').length != 0);
  2210
+		// native matchesSelector function
  2211
+
  2212
+		features.nativeMatchesSelector = root.matchesSelector || /*root.msMatchesSelector ||*/ root.mozMatchesSelector || root.webkitMatchesSelector;
  2213
+		if (features.nativeMatchesSelector) try {
  2214
+			// if matchesSelector trows errors on incorrect sintaxes we can use it
  2215
+			features.nativeMatchesSelector.call(root, ':slick');
  2216
+			features.nativeMatchesSelector = null;
2155 2217
 		} catch(e){};
2156 2218
 
2157 2219
 	}
2158 2220
 
2159  
-	root.removeChild(testNode);
2160  
-	testNode = null;
  2221
+	try {
  2222
+		root.slick_expando = 1;
  2223
+		delete root.slick_expando;
  2224
+		features.getUID = this.getUIDHTML;
  2225
+	} catch(e) {
  2226
+		features.getUID = this.getUIDXML;
  2227
+	}
  2228
+
  2229
+	testRoot.removeChild(testNode);
  2230
+	testNode = selected = testRoot = null;
  2231
+
  2232
+	// getAttribute
  2233
+
  2234
+	features.getAttribute = (features.isHTMLDocument && brokenFormAttributeGetter) ? function(node, name){
  2235
+		var method = this.attributeGetters[name];
  2236
+		if (method) return method.call(node);
  2237
+		var attributeNode = node.getAttributeNode(name);
  2238
+		return (attributeNode) ? attributeNode.nodeValue : null;
  2239
+	} : function(node, name){
  2240
+		var method = this.attributeGetters[name];
  2241
+		return (method) ? method.call(node) : node.getAttribute(name);
  2242
+	};
2161 2243
 
2162 2244
 	// hasAttribute
2163 2245
 
2164  
-	this.hasAttribute = (root && this.isNativeCode(root.hasAttribute)) ? function(node, attribute) {
  2246
+	features.hasAttribute = (root && this.isNativeCode(root.hasAttribute)) ? function(node, attribute) {
2165 2247
 		return node.hasAttribute(attribute);
2166 2248
 	} : function(node, attribute) {
2167 2249
 		node = node.getAttributeNode(attribute);
@@ -2170,7 +2252,7 @@ local.setDocument = function(document){
2170 2252
 
2171 2253
 	// contains
2172 2254
 	// FIXME: Add specs: local.contains should be different for xml and html documents?
2173  
-	this.contains = (root && this.isNativeCode(root.contains)) ? function(context, node){
  2255
+	features.contains = (root && this.isNativeCode(root.contains)) ? function(context, node){
2174 2256
 		return context.contains(node);
2175 2257
 	} : (root && root.compareDocumentPosition) ? function(context, node){
2176 2258
 		return context === node || !!(context.compareDocumentPosition(node) & 16);
@@ -2184,7 +2266,7 @@ local.setDocument = function(document){
2184 2266
 	// document order sorting
2185 2267
 	// credits to Sizzle (http://sizzlejs.com/)
2186 2268
 
2187  
-	this.documentSorter = (root.compareDocumentPosition) ? function(a, b){
  2269
+	features.documentSorter = (root.compareDocumentPosition) ? function(a, b){
2188 2270
 		if (!a.compareDocumentPosition || !b.compareDocumentPosition) return 0;
2189 2271
 		return a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
2190 2272
 	} : ('sourceIndex' in root) ? function(a, b){
@@ -2200,52 +2282,149 @@ local.setDocument = function(document){
2200 2282
 		return aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
2201 2283
 	} : null ;
2202 2284
 
2203  
-	this.getUID = (this.isHTMLDocument) ? this.getUIDHTML : this.getUIDXML;
  2285
+	root = null;
2204 2286
 
  2287
+	for (feature in features){
  2288
+		this[feature] = features[feature];
  2289
+	}
2205 2290
 };
2206 2291
 
2207 2292
 // Main Method
2208 2293
 
  2294
+var reSimpleSelector = /^([#.]?)((?:[\w-]+|\*))$/,
  2295
+	reEmptyAttribute = /\[.+[*$^]=(?:""|'')?\]/,
  2296
+	qsaFailExpCache = {};
  2297
+
2209 2298
 local.search = function(context, expression, append, first){
2210 2299
 
2211 2300
 	var found = this.found = (first) ? null : (append || []);
2212  
-
2213  
-	// context checks
2214  
-
2215  
-	if (!context) return found; // No context
2216  
-	if (context.navigator) context = context.document; // Convert the node from a window to a document
2217  
-	else if (!context.nodeType) return found; // Reject misc junk input
  2301
+	
  2302
+	if (!context) return found;
  2303
+	else if (context.navigator) context = context.document; // Convert the node from a window to a document
  2304
+	else if (!context.nodeType) return found;
2218 2305
 
2219 2306
 	// setup
2220 2307
 
2221  
-	var parsed, i;
  2308
+	var parsed, i,
  2309
+		uniques = this.uniques = {},
  2310
+		hasOthers = !!(append && append.length),
  2311
+		contextIsDocument = (context.nodeType == 9);
2222 2312
 
2223  
-	var uniques = this.uniques = {};
2224  
-
2225  
-	if (this.document !== (context.ownerDocument || context)) this.setDocument(context);
2226  
-
2227  
-	// should sort if there are nodes in append and if you pass multiple expressions.
2228  
-	// should remove duplicates if append already has items
2229  
-	var shouldUniques = !!(append && append.length);
  2313
+	if (this.document !== (contextIsDocument ? context : context.ownerDocument)) this.setDocument(context);
2230 2314
 
2231 2315
 	// avoid duplicating items already in the append array
2232  
-	if (shouldUniques) for (i = found.length; i--;) this.uniques[this.getUID(found[i])] = true;
  2316
+	if (hasOthers) for (i = found.length; i--;) uniques[this.getUID(found[i])] = true;
2233 2317
 
2234 2318
 	// expression checks
2235 2319
 
2236 2320
 	if (typeof expression == 'string'){ // expression is a string
2237 2321
 
2238  
-		// Overrides
  2322
+		/*<simple-selectors-override>*/
  2323
+		var simpleSelector = expression.match(reSimpleSelector);
  2324
+		simpleSelectors: if (simpleSelector) {
  2325
+
  2326
+			var symbol = simpleSelector[1],
  2327
+				name = simpleSelector[2],
  2328
+				node, nodes;
  2329
+
  2330
+			if (!symbol){
  2331
+
  2332
+				if (name == '*' && this.brokenStarGEBTN) break simpleSelectors;
  2333
+				nodes = context.getElementsByTagName(name);
  2334
+				if (first) return nodes[0] || null;
  2335
+				for (i = 0; node = nodes[i++];){
  2336
+					if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
  2337
+				}
  2338
+
  2339
+			} else if (symbol == '#'){
  2340
+
  2341
+				if (!this.isHTMLDocument || !contextIsDocument) break simpleSelectors;
  2342
+				node = context.getElementById(name);
  2343
+				if (!node) return found;
  2344
+				if (this.idGetsName && node.getAttributeNode('id').nodeValue != name) break simpleSelectors;
  2345
+				if (first) return node || null;
  2346
+				if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
  2347
+
  2348
+			} else if (symbol == '.'){
  2349
+
  2350
+				if (!this.isHTMLDocument || ((!context.getElementsByClassName || this.brokenGEBCN) && context.querySelectorAll)) break simpleSelectors;
  2351
+				if (context.getElementsByClassName && !this.brokenGEBCN){
  2352
+					nodes = context.getElementsByClassName(name);
  2353
+					if (first) return nodes[0] || null;
  2354
+					for (i = 0; node = nodes[i++];){
  2355
+						if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
  2356
+					}
  2357
+				} else {
  2358
+					var matchClass = new RegExp('(^|\\s)'+ Slick.escapeRegExp(name) +'(\\s|$)');
  2359
+					nodes = context.getElementsByTagName('*');
  2360
+					for (i = 0; node = nodes[i++];){
  2361
+						className = node.className;
  2362
+						if (!(className && matchClass.test(className))) continue;
  2363
+						if (first) return node;
  2364
+						if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
  2365
+					}
  2366
+				}
2239 2367
 
2240  
-		for (i = this.overrides.length; i--;){
2241  
-			var override = this.overrides[i];
2242  
-			if (override.regexp.test(expression)){
2243  
-				var result = override.method.call(context, expression, found, first);
2244  
-				if (result === false) continue;
2245  
-				if (result === true) return found;
2246  
-				return result;
2247 2368
 			}
  2369
+
  2370
+			if (hasOthers) this.sort(found);
  2371
+			return (first) ? null : found;
  2372
+
  2373
+		}
  2374
+		/*</simple-selectors-override>*/
  2375
+
  2376
+		/*<query-selector-override>*/
  2377
+		querySelector: if (context.querySelectorAll) {
  2378
+
  2379
+			if (!this.isHTMLDocument
  2380
+				|| qsaFailExpCache[expression]
  2381
+				//TODO: only skip when expression is actually mixed case
  2382
+				|| this.brokenMixedCaseQSA
  2383
+				|| (this.brokenCheckedQSA && expression.indexOf(':checked') > -1)
  2384
+				|| (this.brokenEmptyAttributeQSA && reEmptyAttribute.test(expression))
  2385
+				|| (!contextIsDocument //Abort when !contextIsDocument and...
  2386
+					//  there are multiple expressions in the selector
  2387
+					//  since we currently only fix non-document rooted QSA for single expression selectors
  2388
+					&& expression.indexOf(',') > -1
  2389
+				)
  2390
+				|| Slick.disableQSA
  2391
+			) break querySelector;
  2392
+
  2393
+			var _expression = expression, _context = context;
  2394
+			if (!contextIsDocument){
  2395
+				// non-document rooted QSA
  2396
+				// credits to Andrew Dupont
  2397
+				var currentId = _context.getAttribute('id'), slickid = 'slickid__';
  2398
+				_context.setAttribute('id', slickid);
  2399
+				_expression = '#' + slickid + ' ' + _expression;
  2400
+				context = _context.parentNode;
  2401
+			}
  2402
+
  2403
+			try {
  2404
+				if (first) return context.querySelector(_expression) || null;
  2405
+				else nodes = context.querySelectorAll(_expression);
  2406
+			} catch(e) {
  2407
+				qsaFailExpCache[expression] = 1;
  2408
+				break querySelector;
  2409
+			} finally {
  2410
+				if (!contextIsDocument){
  2411
+					if (currentId) _context.setAttribute('id', currentId);
  2412
+					else _context.removeAttribute('id');
  2413
+					context = _context;
  2414
+				}
  2415
+			}
  2416
+
  2417
+			if (this.starSelectsClosedQSA) for (i = 0; node = nodes[i++];){
  2418
+				if (node.nodeName > '@' && !(hasOthers && uniques[this.getUID(node)])) found.push(node);
  2419
+			} else for (i = 0; node = nodes[i++];){
  2420
+				if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
  2421
+			}
  2422
+
  2423
+			if (hasOthers) this.sort(found);
  2424
+			return found;
  2425
+
2248 2426
 		}
  2427
+		/*</query-selector-override>*/
2249 2428
 
2250 2429
 		parsed = this.Slick.parse(expression);
2251 2430
 		if (!parsed.length) return found;
@@ -2260,10 +2439,10 @@ local.search = function(context, expression, append, first){
2260 2439
 		return found;
2261 2440
 	}
2262 2441
 
2263  
-	// cache elements for the nth selectors
2264  
-
2265 2442
 	/*<pseudo-selectors>*//*<nth-pseudo-selectors>*/
2266 2443
 
  2444
+	// cache elements for the nth selectors
  2445
+
2267 2446
 	this.posNTH = {};
2268 2447
 	this.posNTHLast = {};
2269 2448
 	this.posNTHType = {};
@@ -2272,7 +2451,7 @@ local.search = function(context, expression, append, first){
2272 2451
 	/*</nth-pseudo-selectors>*//*</pseudo-selectors>*/
2273 2452
 
2274 2453
 	// if append is null and there is only a single selector with one expression use pushArray, else use pushUID
2275  
-	this.push = (!shouldUniques && (first || (parsed.length == 1 && parsed.expressions[0].length == 1))) ? this.pushArray : this.pushUID;
  2454
+	this.push = (!hasOthers && (first || (parsed.length == 1 && parsed.expressions[0].length == 1))) ? this.pushArray : this.pushUID;
2276 2455
 
2277 2456
 	if (found == null) found = [];
2278 2457
 
@@ -2318,7 +2497,8 @@ local.search = function(context, expression, append, first){
2318 2497
 		currentItems = this.found;
2319 2498
 	}
2320 2499
 
2321  
-	if (shouldUniques || (parsed.expressions.length > 1)) this.sort(found);
  2500
+	// should sort if there are nodes in append and if you pass multiple expressions.
  2501
+	if (hasOthers || (parsed.expressions.length > 1)) this.sort(found);
2322 2502
 
2323 2503
 	return (first) ? (found[0] || null) : found;
2324 2504
 };
@@ -2326,7 +2506,7 @@ local.search = function(context, expression, append, first){
2326 2506
 // Utils
2327 2507
 
2328 2508
 local.uidx = 1;
2329  
-local.uidk = 'slick:uniqueid';
  2509
+local.uidk = 'slick-uniqueid';
2330 2510
 
2331 2511
 local.getUIDXML = function(node){
2332 2512
 	var uid = node.getAttribute(this.uidk);
@@ -2380,12 +2560,12 @@ local.createNTHPseudo = function(child, sibling, positions, ofType){
2380 2560
 			if (ofType){
2381 2561
 				var nodeName = node.nodeName;
2382 2562
 				do {
2383  
-					if (el.nodeName !== nodeName) continue;
  2563
+					if (el.nodeName != nodeName) continue;
2384 2564
 					this[positions][this.getUID(el)] = count++;
2385 2565
 				} while ((el = el[sibling]));
2386 2566
 			} else {
2387 2567
 				do {
2388  
-					if (el.nodeType !== 1) continue;
  2568
+					if (el.nodeType != 1) continue;
2389 2569
 					this[positions][this.getUID(el)] = count++;
2390 2570
 				} while ((el = el[sibling]));
2391 2571
 			}
@@ -2419,17 +2599,29 @@ local.pushUID = function(node, tag, id, classes, attributes, pseudos){
2419 2599
 };
2420 2600
 
2421 2601
 local.matchNode = function(node, selector){
  2602
+	if (this.isHTMLDocument && this.nativeMatchesSelector){
  2603
+		try {
  2604
+			return this.nativeMatchesSelector.call(node, selector.replace(/\[([^=]+)=\s*([^'"\]]+?)\s*\]/g, '[$1="$2"]'));
  2605
+		} catch(matchError) {}
  2606
+	}
  2607
+	
2422 2608
 	var parsed = this.Slick.parse(selector);
2423 2609
 	if (!parsed) return true;
2424 2610
 
2425 2611
 	// simple (single) selectors
2426  
-	if(parsed.length == 1 && parsed.expressions[0].length == 1){
2427  
-		var exp = parsed.expressions[0][0];
2428  
-		return this.matchSelector(node, (this.isXMLDocument) ? exp.tag : exp.tag.toUpperCase(), exp.id, exp.classes, exp.attributes, exp.pseudos);
  2612
+	var expressions = parsed.expressions, reversedExpressions, simpleExpCounter = 0, i;
  2613
+	for (i = 0; (currentExpression = expressions[i]); i++){
  2614
+		if (currentExpression.length == 1){
  2615
+			var exp = currentExpression[0];
  2616
+			if (this.matchSelector(node, (this.isXMLDocument) ? exp.tag : exp.tag.toUpperCase(), exp.id, exp.classes, exp.attributes, exp.pseudos)) return true;
  2617
+			simpleExpCounter++;
  2618
+		}
2429 2619
 	}
2430 2620
 
2431  
-	var nodes = this.search(this.document, parsed);
2432  
-	for (var i = 0, item; item = nodes[i++];){
  2621
+	if (simpleExpCounter == parsed.length) return false;
  2622
+
  2623
+	var nodes = this.search(this.document, parsed), item;
  2624
+	for (i = 0; item = nodes[i++];){
2433 2625
 		if (item === node) return true;
2434 2626
 	}
2435 2627
 	return false;
@@ -2444,10 +2636,11 @@ local.matchPseudo = function(node, name, argument){
2444 2636
 
2445 2637
 local.matchSelector = function(node, tag, id, classes, attributes, pseudos){
2446 2638
 	if (tag){
  2639
+		var nodeName = (this.isXMLDocument) ? node.nodeName : node.nodeName.toUpperCase();
2447 2640
 		if (tag == '*'){
2448  
-			if (node.nodeName < '@') return false; // Fix for comment nodes and closed nodes
  2641
+			if (nodeName < '@') return false; // Fix for comment nodes and closed nodes
2449 2642
 		} else {
2450  
-			if (node.nodeName != tag) return false;
  2643
+			if (nodeName != tag) return false;
2451 2644
 		}
2452 2645
 	}
2453 2646
 
@@ -2455,7 +2648,7 @@ local.matchSelector = function(node, tag, id, classes, attributes, pseudos){
2455 2648
 
2456 2649
 	var i, part, cls;
2457 2650
 	if (classes) for (i = classes.length; i--;){
2458  
-		cls = ('className' in node) ? node.className : node.getAttribute('class');
  2651
+		cls = node.getAttribute('class') || node.className;
2459 2652
 		if (!(cls && classes[i].regexp.test(cls))) return false;
2460 2653
 	}
2461 2654
 	if (attributes) for (i = attributes.length; i--;){
@@ -2484,15 +2677,18 @@ var combinators = {
2484 2677
 					children = node.all[id];
2485 2678
 					if (!children) return;
2486 2679
 					if (!children[0]) children = [children];
2487  
-					for (i = 0; item = children[i++];) if (item.getAttributeNode('id').nodeValue == id){
2488  
-						this.push(item, tag, null, classes, attributes, pseudos);
2489  
-						break;
2490  
-					}
  2680
+					for (i = 0; item = children[i++];){
  2681
+						var idNode = item.getAttributeNode('id');
  2682
+						if (idNode && idNode.nodeValue == id){
  2683
+							this.push(item, tag, null, classes, attributes, pseudos);
  2684
+							break;
  2685
+						}
  2686
+					} 
2491 2687
 					return;
2492 2688
 				}
2493 2689
 				if (!item){
2494 2690
 					// if the context is in the dom we return, else we will try GEBTN, breaking the getById label
2495  
-					if (this.contains(this.document.documentElement, node)) return;
  2691
+					if (this.contains(this.root, node)) return;
2496 2692
 					else break getById;
2497 2693
 				} else if (this.document !== node && !this.contains(node, item)) return;
2498 2694
 				this.push(item, tag, null, classes, attributes, pseudos);
@@ -2515,12 +2711,12 @@ var combinators = {
2515 2711
 
2516 2712
 	'>': function(node, tag, id, classes, attributes, pseudos){ // direct children
2517 2713
 		if ((node = node.firstChild)) do {
2518  
-			if (node.nodeType === 1) this.push(node, tag, id, classes, attributes, pseudos);
  2714
+			if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos);
2519 2715
 		} while ((node = node.nextSibling));
2520 2716
 	},
2521 2717
 
2522 2718
 	'+': function(node, tag, id, classes, attributes, pseudos){ // next sibling
2523  
-		while ((node = node.nextSibling)) if (node.nodeType === 1){
  2719
+		while ((node = node.nextSibling)) if (node.nodeType == 1){
2524 2720
 			this.push(node, tag, id, classes, attributes, pseudos);
2525 2721
 			break;
2526 2722
 		}
@@ -2529,14 +2725,14 @@ var combinators = {
2529 2725
 	'^': function(node, tag, id, classes, attributes, pseudos){ // first child
2530 2726
 		node = node.firstChild;
2531