3 MooTools: the javascript framework
6 - http://mootools.net/core/f62dd4514b59c41f42c7579664bca750
9 - packager build Core/Core Core/Array Core/Event Core/Browser Core/Class.Extras Core/Element.Event Core/Element.Dimensions Core/Fx.Tween Core/Fx.Morph Core/Fx.Transitions Core/DOMReady
16 description: The heart of MooTools.
18 license: MIT-style license.
20 copyright: Copyright (c) 2006-2010 [Valerio Proietti](http://mad4milk.net/).
22 authors: The MooTools production team (http://mootools.net/developers/)
25 - Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)
26 - Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php)
28 provides: [Core, MooTools, Type, typeOf, instanceOf, Native]
37 build: 'a3eed692dd85050d80168ec2c708efe901bb7db3'
42 var typeOf = this.typeOf = function(item){
43 if (item == null) return 'null';
44 if (item.$family) return item.$family();
47 if (item.nodeType == 1) return 'element';
48 if (item.nodeType == 3) return (/\S/).test(item.nodeValue) ? 'textnode' : 'whitespace';
49 } else if (typeof item.length == 'number'){
50 if (item.callee) return 'arguments';
51 if ('item' in item) return 'collection';
57 var instanceOf = this.instanceOf = function(item, object){
58 if (item == null) return false;
59 var constructor = item.$constructor || item.constructor;
61 if (constructor === object) return true;
62 constructor = constructor.parent;
64 return item instanceof object;
67 // Function overloading
69 var Function = this.Function;
71 var enumerables = true;
72 for (var i in {toString: 1}) enumerables = null;
73 if (enumerables) enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor'];
75 Function.prototype.overloadSetter = function(usePlural){
77 return function(a, b){
78 if (a == null) return this;
79 if (usePlural || typeof a != 'string'){
80 for (var k in a) self.call(this, k, a[k]);
81 if (enumerables) for (var i = enumerables.length; i--;){
83 if (a.hasOwnProperty(k)) self.call(this, k, a[k]);
86 self.call(this, a, b);
92 Function.prototype.overloadGetter = function(usePlural){
96 if (usePlural || typeof a != 'string') args = a;
97 else if (arguments.length > 1) args = arguments;
100 for (var i = 0; i < args.length; i++) result[args[i]] = self.call(this, args[i]);
102 result = self.call(this, a);
108 Function.prototype.extend = function(key, value){
112 Function.prototype.implement = function(key, value){
113 this.prototype[key] = value;
118 var slice = Array.prototype.slice;
120 Function.from = function(item){
121 return (typeOf(item) == 'function') ? item : function(){
126 Array.from = function(item){
127 if (item == null) return [];
128 return (Type.isEnumerable(item) && typeof item != 'string') ? (typeOf(item) == 'array') ? item : slice.call(item) : [item];
131 Number.from = function(item){
132 var number = parseFloat(item);
133 return isFinite(number) ? number : null;
136 String.from = function(item){
150 this.$protected = true;
158 var Type = this.Type = function(name, object){
160 var lower = name.toLowerCase();
161 var typeCheck = function(item){
162 return (typeOf(item) == lower);
165 Type['is' + name] = typeCheck;
167 object.prototype.$family = (function(){
171 object.type = typeCheck;
176 if (object == null) return null;
179 object.$constructor = Type;
180 object.prototype.$constructor = object;
185 var toString = Object.prototype.toString;
187 Type.isEnumerable = function(item){
188 return (item != null && typeof item.length == 'number' && toString.call(item) != '[object Function]' );
193 var hooksOf = function(object){
194 var type = typeOf(object.prototype);
195 return hooks[type] || (hooks[type] = []);
198 var implement = function(name, method){
199 if (method && method.$hidden) return this;
201 var hooks = hooksOf(this);
203 for (var i = 0; i < hooks.length; i++){
205 if (typeOf(hook) == 'type') implement.call(hook, name, method);
206 else hook.call(this, name, method);
209 var previous = this.prototype[name];
210 if (previous == null || !previous.$protected) this.prototype[name] = method;
212 if (this[name] == null && typeOf(method) == 'function') extend.call(this, name, function(item){
213 return method.apply(item, slice.call(arguments, 1));
219 var extend = function(name, method){
220 if (method && method.$hidden) return this;
221 var previous = this[name];
222 if (previous == null || !previous.$protected) this[name] = method;
228 implement: implement.overloadSetter(),
230 extend: extend.overloadSetter(),
232 alias: function(name, existing){
233 implement.call(this, name, this.prototype[existing]);
236 mirror: function(hook){
237 hooksOf(this).push(hook);
243 new Type('Type', Type);
247 var force = function(name, object, methods){
248 var isType = (object != Object),
249 prototype = object.prototype;
251 if (isType) object = new Type(name, object);
253 for (var i = 0, l = methods.length; i < l; i++){
254 var key = methods[i],
255 generic = object[key],
256 proto = prototype[key];
258 if (generic) generic.protect();
260 if (isType && proto){
261 delete prototype[key];
262 prototype[key] = proto.protect();
266 if (isType) object.implement(prototype);
271 force('String', String, [
272 'charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search',
273 'slice', 'split', 'substr', 'substring', 'toLowerCase', 'toUpperCase'
275 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice',
276 'indexOf', 'lastIndexOf', 'filter', 'forEach', 'every', 'map', 'some', 'reduce', 'reduceRight'
277 ])('Number', Number, [
278 'toExponential', 'toFixed', 'toLocaleString', 'toPrecision'
279 ])('Function', Function, [
280 'apply', 'call', 'bind'
281 ])('RegExp', RegExp, [
283 ])('Object', Object, [
284 'create', 'defineProperty', 'defineProperties', 'keys',
285 'getPrototypeOf', 'getOwnPropertyDescriptor', 'getOwnPropertyNames',
286 'preventExtensions', 'isExtensible', 'seal', 'isSealed', 'freeze', 'isFrozen'
287 ])('Date', Date, ['now']);
289 Object.extend = extend.overloadSetter();
291 Date.extend('now', function(){
295 new Type('Boolean', Boolean);
297 // fixes NaN returning as Number
299 Number.prototype.$family = function(){
300 return isFinite(this) ? 'number' : 'null';
305 Number.extend('random', function(min, max){
306 return Math.floor(Math.random() * (max - min + 1) + min);
311 Object.extend('forEach', function(object, fn, bind){
312 for (var key in object){
313 if (object.hasOwnProperty(key)) fn.call(bind, object[key], key, object);
317 Object.each = Object.forEach;
321 forEach: function(fn, bind){
322 for (var i = 0, l = this.length; i < l; i++){
323 if (i in this) fn.call(bind, this[i], i, this);
327 each: function(fn, bind){
328 Array.forEach(this, fn, bind);
334 // Array & Object cloning, Object merging and appending
336 var cloneOf = function(item){
337 switch (typeOf(item)){
338 case 'array': return item.clone();
339 case 'object': return Object.clone(item);
340 default: return item;
344 Array.implement('clone', function(){
345 var i = this.length, clone = new Array(i);
346 while (i--) clone[i] = cloneOf(this[i]);
350 var mergeOne = function(source, key, current){
351 switch (typeOf(current)){
353 if (typeOf(source[key]) == 'object') Object.merge(source[key], current);
354 else source[key] = Object.clone(current);
356 case 'array': source[key] = current.clone(); break;
357 default: source[key] = current;
364 merge: function(source, k, v){
365 if (typeOf(k) == 'string') return mergeOne(source, k, v);
366 for (var i = 1, l = arguments.length; i < l; i++){
367 var object = arguments[i];
368 for (var key in object) mergeOne(source, key, object[key]);
373 clone: function(object){
375 for (var key in object) clone[key] = cloneOf(object[key]);
379 append: function(original){
380 for (var i = 1, l = arguments.length; i < l; i++){
381 var extended = arguments[i] || {};
382 for (var key in extended) original[key] = extended[key];
391 ['Object', 'WhiteSpace', 'TextNode', 'Collection', 'Arguments'].each(function(name){
397 var UID = Date.now();
399 String.extend('uniqueID', function(){
400 return (UID++).toString(36);
405 var Hash = this.Hash = new Type('Hash', function(object){
406 if (typeOf(object) == 'hash') object = Object.clone(object.getClean());
407 for (var key in object) this[key] = object[key];
413 forEach: function(fn, bind){
414 Object.forEach(this, fn, bind);
417 getClean: function(){
419 for (var key in this){
420 if (this.hasOwnProperty(key)) clean[key] = this[key];
425 getLength: function(){
427 for (var key in this){
428 if (this.hasOwnProperty(key)) length++;
435 Hash.alias('each', 'forEach');
437 Object.type = Type.isObject;
439 var Native = this.Native = function(properties){
440 return new Type(properties.name, properties.initialize);
443 Native.type = Type.type;
445 Native.implement = function(objects, methods){
446 for (var i = 0; i < objects.length; i++) objects[i].implement(methods);
450 var arrayType = Array.type;
451 Array.type = function(item){
452 return instanceOf(item, Array) || arrayType(item);
455 this.$A = function(item){
456 return Array.from(item).slice();
459 this.$arguments = function(i){
465 this.$chk = function(obj){
466 return !!(obj || obj === 0);
469 this.$clear = function(timer){
471 clearInterval(timer);
475 this.$defined = function(obj){
476 return (obj != null);
479 this.$each = function(iterable, fn, bind){
480 var type = typeOf(iterable);
481 ((type == 'arguments' || type == 'collection' || type == 'array' || type == 'elements') ? Array : Object).each(iterable, fn, bind);
484 this.$empty = function(){};
486 this.$extend = function(original, extended){
487 return Object.append(original, extended);
490 this.$H = function(object){
491 return new Hash(object);
494 this.$merge = function(){
495 var args = Array.slice(arguments);
497 return Object.merge.apply(null, args);
500 this.$lambda = Function.from;
501 this.$mixin = Object.merge;
502 this.$random = Number.random;
503 this.$splat = Array.from;
504 this.$time = Date.now;
506 this.$type = function(object){
507 var type = typeOf(object);
508 if (type == 'elements') return 'array';
509 return (type == 'null') ? false : type;
512 this.$unlink = function(object){
513 switch (typeOf(object)){
514 case 'object': return Object.clone(object);
515 case 'array': return Array.clone(object);
516 case 'hash': return new Hash(object);
517 default: return object;
531 description: Contains Array Prototypes like each, contains, and erase.
533 license: MIT-style license.
544 invoke: function(methodName){
545 var args = Array.slice(arguments, 1);
546 return this.map(function(item){
547 return item[methodName].apply(item, args);
551 every: function(fn, bind){
552 for (var i = 0, l = this.length; i < l; i++){
553 if ((i in this) && !fn.call(bind, this[i], i, this)) return false;
558 filter: function(fn, bind){
560 for (var i = 0, l = this.length; i < l; i++){
561 if ((i in this) && fn.call(bind, this[i], i, this)) results.push(this[i]);
567 return this.filter(function(item){
572 indexOf: function(item, from){
573 var len = this.length;
574 for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){
575 if (this[i] === item) return i;
580 map: function(fn, bind){
582 for (var i = 0, l = this.length; i < l; i++){
583 if (i in this) results[i] = fn.call(bind, this[i], i, this);
588 some: function(fn, bind){
589 for (var i = 0, l = this.length; i < l; i++){
590 if ((i in this) && fn.call(bind, this[i], i, this)) return true;
595 associate: function(keys){
596 var obj = {}, length = Math.min(this.length, keys.length);
597 for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
601 link: function(object){
603 for (var i = 0, l = this.length; i < l; i++){
604 for (var key in object){
605 if (object[key](this[i])){
606 result[key] = this[i];
615 contains: function(item, from){
616 return this.indexOf(item, from) != -1;
619 append: function(array){
620 this.push.apply(this, array);
625 return (this.length) ? this[this.length - 1] : null;
628 getRandom: function(){
629 return (this.length) ? this[Number.random(0, this.length - 1)] : null;
632 include: function(item){
633 if (!this.contains(item)) this.push(item);
637 combine: function(array){
638 for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
642 erase: function(item){
643 for (var i = this.length; i--;){
644 if (this[i] === item) this.splice(i, 1);
656 for (var i = 0, l = this.length; i < l; i++){
657 var type = typeOf(this[i]);
658 if (type == 'null') continue;
659 array = array.concat((type == 'array' || type == 'collection' || type == 'arguments' || instanceOf(this[i], Array)) ? Array.flatten(this[i]) : this[i]);
665 for (var i = 0, l = this.length; i < l; i++){
666 if (this[i] != null) return this[i];
671 hexToRgb: function(array){
672 if (this.length != 3) return null;
673 var rgb = this.map(function(value){
674 if (value.length == 1) value += value;
675 return value.toInt(16);
677 return (array) ? rgb : 'rgb(' + rgb + ')';
680 rgbToHex: function(array){
681 if (this.length < 3) return null;
682 if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
684 for (var i = 0; i < 3; i++){
685 var bit = (this[i] - 0).toString(16);
686 hex.push((bit.length == 1) ? '0' + bit : bit);
688 return (array) ? hex : '#' + hex.join('');
695 Array.alias('extend', 'append');
697 var $pick = function(){
698 return Array.from(arguments).pick();
709 description: Contains Function Prototypes like create, bind, pass, and delay.
711 license: MIT-style license.
723 for (var i = 0, l = arguments.length; i < l; i++){
725 return arguments[i]();
735 attempt: function(args, bind){
737 return this.apply(bind, Array.from(args));
743 bind: function(bind){
745 args = (arguments.length > 1) ? Array.slice(arguments, 1) : null;
748 if (!args && !arguments.length) return self.call(bind);
749 if (args && arguments.length) return self.apply(bind, args.concat(Array.from(arguments)));
750 return self.apply(bind, args || arguments);
754 pass: function(args, bind){
756 if (args != null) args = Array.from(args);
758 return self.apply(bind, args || arguments);
762 delay: function(delay, bind, args){
763 return setTimeout(this.pass(args, bind), delay);
766 periodical: function(periodical, bind, args){
767 return setInterval(this.pass(args, bind), periodical);
774 delete Function.prototype.bind;
778 create: function(options){
780 options = options || {};
781 return function(event){
782 var args = options.arguments;
783 args = (args != null) ? Array.from(args) : Array.slice(arguments, (options.event) ? 1 : 0);
784 if (options.event) args = [event || window.event].extend(args);
785 var returns = function(){
786 return self.apply(options.bind || null, args);
788 if (options.delay) return setTimeout(returns, options.delay);
789 if (options.periodical) return setInterval(returns, options.periodical);
790 if (options.attempt) return Function.attempt(returns);
795 bind: function(bind, args){
797 if (args != null) args = Array.from(args);
799 return self.apply(bind, args || arguments);
803 bindWithEvent: function(bind, args){
805 if (args != null) args = Array.from(args);
806 return function(event){
807 return self.apply(bind, (args == null) ? arguments : [event].concat(args));
811 run: function(args, bind){
812 return this.apply(bind, Array.from(args));
817 var $try = Function.attempt;
827 description: Contains Number Prototypes like limit, round, times, and ceil.
829 license: MIT-style license.
840 limit: function(min, max){
841 return Math.min(max, Math.max(min, this));
844 round: function(precision){
845 precision = Math.pow(10, precision || 0).toFixed(precision < 0 ? -precision : 0);
846 return Math.round(this * precision) / precision;
849 times: function(fn, bind){
850 for (var i = 0; i < this; i++) fn.call(bind, i, this);
854 return parseFloat(this);
857 toInt: function(base){
858 return parseInt(this, base || 10);
863 Number.alias('each', 'times');
867 math.each(function(name){
868 if (!Number[name]) methods[name] = function(){
869 return Math[name].apply(null, [this].concat(Array.from(arguments)));
872 Number.implement(methods);
873 })(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']);
881 description: Contains String Prototypes like camelCase, capitalize, test, and toInt.
883 license: MIT-style license.
894 test: function(regex, params){
895 return ((typeOf(regex) == 'regexp') ? regex : new RegExp('' + regex, params)).test(this);
898 contains: function(string, separator){
899 return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1;
903 return this.replace(/^\s+|\s+$/g, '');
907 return this.replace(/\s+/g, ' ').trim();
910 camelCase: function(){
911 return this.replace(/-\D/g, function(match){
912 return match.charAt(1).toUpperCase();
916 hyphenate: function(){
917 return this.replace(/[A-Z]/g, function(match){
918 return ('-' + match.charAt(0).toLowerCase());
922 capitalize: function(){
923 return this.replace(/\b[a-z]/g, function(match){
924 return match.toUpperCase();
928 escapeRegExp: function(){
929 return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
932 toInt: function(base){
933 return parseInt(this, base || 10);
937 return parseFloat(this);
940 hexToRgb: function(array){
941 var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
942 return (hex) ? hex.slice(1).hexToRgb(array) : null;
945 rgbToHex: function(array){
946 var rgb = this.match(/\d{1,3}/g);
947 return (rgb) ? rgb.rgbToHex(array) : null;
950 substitute: function(object, regexp){
951 return this.replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){
952 if (match.charAt(0) == '\\') return match.slice(1);
953 return (object[name] != null) ? object[name] : '';
965 description: The Browser Object. Contains Browser initialization, Window and Document, and the Browser Hash.
967 license: MIT-style license.
969 requires: [Array, Function, Number, String]
971 provides: [Browser, Window, Document]
978 var document = this.document;
979 var window = document.window = this;
983 this.$uid = (window.ActiveXObject) ? function(item){
984 return (item.uid || (item.uid = [UID++]))[0];
986 return item.uid || (item.uid = UID++);
992 var ua = navigator.userAgent.toLowerCase(),
993 platform = navigator.platform.toLowerCase(),
994 UA = ua.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/) || [null, 'unknown', 0],
995 mode = UA[1] == 'ie' && document.documentMode;
997 var Browser = this.Browser = {
999 extend: Function.prototype.extend,
1001 name: (UA[1] == 'version') ? UA[3] : UA[1],
1003 version: mode || parseFloat((UA[1] == 'opera' && UA[4]) ? UA[4] : UA[2]),
1006 name: ua.match(/ip(?:ad|od|hone)/) ? 'ios' : (ua.match(/(?:webos|android)/) || platform.match(/mac|win|linux/) || ['other'])[0]
1010 xpath: !!(document.evaluate),
1011 air: !!(window.runtime),
1012 query: !!(document.querySelector),
1013 json: !!(window.JSON)
1020 Browser[Browser.name] = true;
1021 Browser[Browser.name + parseInt(Browser.version, 10)] = true;
1022 Browser.Platform[Browser.Platform.name] = true;
1026 Browser.Request = (function(){
1028 var XMLHTTP = function(){
1029 return new XMLHttpRequest();
1032 var MSXML2 = function(){
1033 return new ActiveXObject('MSXML2.XMLHTTP');
1036 var MSXML = function(){
1037 return new ActiveXObject('Microsoft.XMLHTTP');
1040 return Function.attempt(function(){
1053 Browser.Features.xhr = !!(Browser.Request);
1057 var version = (Function.attempt(function(){
1058 return navigator.plugins['Shockwave Flash'].description;
1060 return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
1061 }) || '0 r0').match(/\d+/g);
1063 Browser.Plugins.Flash = {
1064 version: Number(version[0] || '0.' + version[1]) || 0,
1065 build: Number(version[2]) || 0
1070 Browser.exec = function(text){
1071 if (!text) return text;
1072 if (window.execScript){
1073 window.execScript(text);
1075 var script = document.createElement('script');
1076 script.setAttribute('type', 'text/javascript');
1078 document.head.appendChild(script);
1079 document.head.removeChild(script);
1084 String.implement('stripScripts', function(exec){
1086 var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(all, code){
1087 scripts += code + '\n';
1090 if (exec === true) Browser.exec(scripts);
1091 else if (typeOf(exec) == 'function') exec(scripts, text);
1098 Document: this.Document,
1099 Window: this.Window,
1100 Element: this.Element,
1104 this.Window = this.$constructor = new Type('Window', function(){});
1106 this.$family = Function.from('window').hide();
1108 Window.mirror(function(name, method){
1109 window[name] = method;
1112 this.Document = document.$constructor = new Type('Document', function(){});
1114 document.$family = Function.from('document').hide();
1116 Document.mirror(function(name, method){
1117 document[name] = method;
1120 document.html = document.documentElement;
1121 document.head = document.getElementsByTagName('head')[0];
1123 if (document.execCommand) try {
1124 document.execCommand("BackgroundImageCache", false, true);
1127 if (this.attachEvent && !this.addEventListener){
1128 var unloadEvent = function(){
1129 this.detachEvent('onunload', unloadEvent);
1130 document.head = document.html = document.window = null;
1132 this.attachEvent('onunload', unloadEvent);
1135 // IE fails on collections and <select>.options (refers to <select>)
1136 var arrayFrom = Array.from;
1138 arrayFrom(document.html.childNodes);
1140 Array.from = function(item){
1141 if (typeof item != 'string' && Type.isEnumerable(item) && typeOf(item) != 'array'){
1142 var i = item.length, array = new Array(i);
1143 while (i--) array[i] = item[i];
1146 return arrayFrom(item);
1149 var prototype = Array.prototype,
1150 slice = prototype.slice;
1151 ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice'].each(function(name){
1152 var method = prototype[name];
1153 Array[name] = function(item){
1154 return method.apply(Array.from(item), slice.call(arguments, 1));
1161 if (Browser.Platform.ios) Browser.Platform.ipod = true;
1163 Browser.Engine = {};
1165 var setEngine = function(name, version){
1166 Browser.Engine.name = name;
1167 Browser.Engine[name + version] = true;
1168 Browser.Engine.version = version;
1172 Browser.Engine.trident = true;
1174 switch (Browser.version){
1175 case 6: setEngine('trident', 4); break;
1176 case 7: setEngine('trident', 5); break;
1177 case 8: setEngine('trident', 6);
1181 if (Browser.firefox){
1182 Browser.Engine.gecko = true;
1184 if (Browser.version >= 3) setEngine('gecko', 19);
1185 else setEngine('gecko', 18);
1188 if (Browser.safari || Browser.chrome){
1189 Browser.Engine.webkit = true;
1191 switch (Browser.version){
1192 case 2: setEngine('webkit', 419); break;
1193 case 3: setEngine('webkit', 420); break;
1194 case 4: setEngine('webkit', 525);
1199 Browser.Engine.presto = true;
1201 if (Browser.version >= 9.6) setEngine('presto', 960);
1202 else if (Browser.version >= 9.5) setEngine('presto', 950);
1203 else setEngine('presto', 925);
1206 if (Browser.name == 'unknown'){
1207 switch ((ua.match(/(?:webkit|khtml|gecko)/) || [])[0]){
1210 Browser.Engine.webkit = true;
1213 Browser.Engine.gecko = true;
1217 this.$exec = Browser.exec;
1229 description: Object generic methods
1231 license: MIT-style license.
1235 provides: [Object, Hash]
1243 subset: function(object, keys){
1245 for (var i = 0, l = keys.length; i < l; i++){
1247 results[k] = object[k];
1252 map: function(object, fn, bind){
1254 for (var key in object){
1255 if (object.hasOwnProperty(key)) results[key] = fn.call(bind, object[key], key, object);
1260 filter: function(object, fn, bind){
1262 Object.each(object, function(value, key){
1263 if (fn.call(bind, value, key, object)) results[key] = value;
1268 every: function(object, fn, bind){
1269 for (var key in object){
1270 if (object.hasOwnProperty(key) && !fn.call(bind, object[key], key)) return false;
1275 some: function(object, fn, bind){
1276 for (var key in object){
1277 if (object.hasOwnProperty(key) && fn.call(bind, object[key], key)) return true;
1282 keys: function(object){
1284 for (var key in object){
1285 if (object.hasOwnProperty(key)) keys.push(key);
1290 values: function(object){
1292 for (var key in object){
1293 if (object.hasOwnProperty(key)) values.push(object[key]);
1298 getLength: function(object){
1299 return Object.keys(object).length;
1302 keyOf: function(object, value){
1303 for (var key in object){
1304 if (object.hasOwnProperty(key) && object[key] === value) return key;
1309 contains: function(object, value){
1310 return Object.keyOf(object, value) != null;
1313 toQueryString: function(object, base){
1314 var queryString = [];
1316 Object.each(object, function(value, key){
1317 if (base) key = base + '[' + key + ']';
1319 switch (typeOf(value)){
1320 case 'object': result = Object.toQueryString(value, key); break;
1323 value.each(function(val, i){
1326 result = Object.toQueryString(qs, key);
1328 default: result = key + '=' + encodeURIComponent(value);
1330 if (value != null) queryString.push(result);
1333 return queryString.join('&');
1343 has: Object.prototype.hasOwnProperty,
1345 keyOf: function(value){
1346 return Object.keyOf(this, value);
1349 hasValue: function(value){
1350 return Object.contains(this, value);
1353 extend: function(properties){
1354 Hash.each(properties || {}, function(value, key){
1355 Hash.set(this, key, value);
1360 combine: function(properties){
1361 Hash.each(properties || {}, function(value, key){
1362 Hash.include(this, key, value);
1367 erase: function(key){
1368 if (this.hasOwnProperty(key)) delete this[key];
1373 return (this.hasOwnProperty(key)) ? this[key] : null;
1376 set: function(key, value){
1377 if (!this[key] || this.hasOwnProperty(key)) this[key] = value;
1382 Hash.each(this, function(value, key){
1388 include: function(key, value){
1389 if (this[key] == null) this[key] = value;
1393 map: function(fn, bind){
1394 return new Hash(Object.map(this, fn, bind));
1397 filter: function(fn, bind){
1398 return new Hash(Object.filter(this, fn, bind));
1401 every: function(fn, bind){
1402 return Object.every(this, fn, bind);
1405 some: function(fn, bind){
1406 return Object.some(this, fn, bind);
1409 getKeys: function(){
1410 return Object.keys(this);
1413 getValues: function(){
1414 return Object.values(this);
1417 toQueryString: function(base){
1418 return Object.toQueryString(this, base);
1423 Hash.extend = Object.append;
1425 Hash.alias({indexOf: 'keyOf', contains: 'hasValue'});
1435 description: Contains the Event Class, to make the event object cross-browser.
1437 license: MIT-style license.
1439 requires: [Window, Document, Array, Function, String, Object]
1446 var Event = new Type('Event', function(event, win){
1447 if (!win) win = window;
1448 var doc = win.document;
1449 event = event || win.event;
1450 if (event.$extended) return event;
1451 this.$extended = true;
1452 var type = event.type,
1453 target = event.target || event.srcElement,
1456 while (target && target.nodeType == 3) target = target.parentNode;
1458 if (type.indexOf('key') != -1){
1459 var code = event.which || event.keyCode;
1460 var key = Object.keyOf(Event.Keys, code);
1461 if (type == 'keydown'){
1462 var fKey = code - 111;
1463 if (fKey > 0 && fKey < 13) key = 'f' + fKey;
1465 if (!key) key = String.fromCharCode(code).toLowerCase();
1466 } else if (type.test(/click|mouse|menu/i)){
1467 doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
1469 x: (event.pageX != null) ? event.pageX : event.clientX + doc.scrollLeft,
1470 y: (event.pageY != null) ? event.pageY : event.clientY + doc.scrollTop
1473 x: (event.pageX != null) ? event.pageX - win.pageXOffset : event.clientX,
1474 y: (event.pageY != null) ? event.pageY - win.pageYOffset : event.clientY
1476 if (type.test(/DOMMouseScroll|mousewheel/)){
1477 var wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
1479 var rightClick = (event.which == 3) || (event.button == 2),
1481 if (type.test(/over|out/)){
1482 related = event.relatedTarget || event[(type == 'mouseover' ? 'from' : 'to') + 'Element'];
1483 var testRelated = function(){
1484 while (related && related.nodeType == 3) related = related.parentNode;
1487 var hasRelated = (Browser.firefox2) ? testRelated.attempt() : testRelated();
1488 related = (hasRelated) ? related : null;
1490 } else if (type.test(/gesture|touch/i)){
1491 this.rotation = event.rotation;
1492 this.scale = event.scale;
1493 this.targetTouches = event.targetTouches;
1494 this.changedTouches = event.changedTouches;
1495 var touches = this.touches = event.touches;
1496 if (touches && touches[0]){
1497 var touch = touches[0];
1498 page = {x: touch.pageX, y: touch.pageY};
1499 client = {x: touch.clientX, y: touch.clientY};
1503 return Object.append(this, {
1509 rightClick: rightClick,
1513 relatedTarget: document.id(related),
1514 target: document.id(target),
1519 shift: event.shiftKey,
1520 control: event.ctrlKey,
1541 Event.Keys = new Hash(Event.Keys);
1548 return this.stopPropagation().preventDefault();
1551 stopPropagation: function(){
1552 if (this.event.stopPropagation) this.event.stopPropagation();
1553 else this.event.cancelBubble = true;
1557 preventDefault: function(){
1558 if (this.event.preventDefault) this.event.preventDefault();
1559 else this.event.returnValue = false;
1571 description: Contains the Class Function for easily creating, extending, and implementing reusable Classes.
1573 license: MIT-style license.
1575 requires: [Array, String, Function, Number]
1584 var Class = this.Class = new Type('Class', function(params){
1585 if (instanceOf(params, Function)) params = {initialize: params};
1587 var newClass = function(){
1589 if (newClass.$prototyping) return this;
1590 this.$caller = null;
1591 var value = (this.initialize) ? this.initialize.apply(this, arguments) : this;
1592 this.$caller = this.caller = null;
1594 }.extend(this).implement(params);
1596 newClass.$constructor = Class;
1597 newClass.prototype.$constructor = newClass;
1598 newClass.prototype.parent = parent;
1603 var parent = function(){
1604 if (!this.$caller) throw new Error('The method "parent" cannot be called.');
1605 var name = this.$caller.$name,
1606 parent = this.$caller.$owner.parent,
1607 previous = (parent) ? parent.prototype[name] : null;
1608 if (!previous) throw new Error('The method "' + name + '" has no parent.');
1609 return previous.apply(this, arguments);
1612 var reset = function(object){
1613 for (var key in object){
1614 var value = object[key];
1615 switch (typeOf(value)){
1617 var F = function(){};
1618 F.prototype = value;
1619 object[key] = reset(new F);
1621 case 'array': object[key] = value.clone(); break;
1627 var wrap = function(self, key, method){
1628 if (method.$origin) method = method.$origin;
1629 var wrapper = function(){
1630 if (method.$protected && this.$caller == null) throw new Error('The method "' + key + '" cannot be called.');
1631 var caller = this.caller, current = this.$caller;
1632 this.caller = current; this.$caller = wrapper;
1633 var result = method.apply(this, arguments);
1634 this.$caller = current; this.caller = caller;
1636 }.extend({$owner: self, $origin: method, $name: key});
1640 var implement = function(key, value, retain){
1641 if (Class.Mutators.hasOwnProperty(key)){
1642 value = Class.Mutators[key].call(this, value);
1643 if (value == null) return this;
1646 if (typeOf(value) == 'function'){
1647 if (value.$hidden) return this;
1648 this.prototype[key] = (retain) ? value : wrap(this, key, value);
1650 Object.merge(this.prototype, key, value);
1656 var getInstance = function(klass){
1657 klass.$prototyping = true;
1658 var proto = new klass;
1659 delete klass.$prototyping;
1663 Class.implement('implement', implement.overloadSetter());
1667 Extends: function(parent){
1668 this.parent = parent;
1669 this.prototype = getInstance(parent);
1672 Implements: function(items){
1673 Array.from(items).each(function(item){
1674 var instance = new item;
1675 for (var key in instance) implement.call(this, key, instance[key], true);
1688 description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks.
1690 license: MIT-style license.
1694 provides: [Class.Extras, Chain, Events, Options]
1701 this.Chain = new Class({
1706 this.$chain.append(Array.flatten(arguments));
1710 callChain: function(){
1711 return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false;
1714 clearChain: function(){
1715 this.$chain.empty();
1721 var removeOn = function(string){
1722 return string.replace(/^on([A-Z])/, function(full, first){
1723 return first.toLowerCase();
1727 this.Events = new Class({
1731 addEvent: function(type, fn, internal){
1732 type = removeOn(type);
1735 if (fn == $empty) return this;
1738 this.$events[type] = (this.$events[type] || []).include(fn);
1739 if (internal) fn.internal = true;
1743 addEvents: function(events){
1744 for (var type in events) this.addEvent(type, events[type]);
1748 fireEvent: function(type, args, delay){
1749 type = removeOn(type);
1750 var events = this.$events[type];
1751 if (!events) return this;
1752 args = Array.from(args);
1753 events.each(function(fn){
1754 if (delay) fn.delay(delay, this, args);
1755 else fn.apply(this, args);
1760 removeEvent: function(type, fn){
1761 type = removeOn(type);
1762 var events = this.$events[type];
1763 if (events && !fn.internal){
1764 var index = events.indexOf(fn);
1765 if (index != -1) delete events[index];
1770 removeEvents: function(events){
1772 if (typeOf(events) == 'object'){
1773 for (type in events) this.removeEvent(type, events[type]);
1776 if (events) events = removeOn(events);
1777 for (type in this.$events){
1778 if (events && events != type) continue;
1779 var fns = this.$events[type];
1780 for (var i = fns.length; i--;) this.removeEvent(type, fns[i]);
1787 this.Options = new Class({
1789 setOptions: function(){
1790 var options = this.options = Object.merge.apply(null, [{}, this.options].append(arguments));
1791 if (!this.addEvent) return this;
1792 for (var option in options){
1793 if (typeOf(options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue;
1794 this.addEvent(option, options[option]);
1795 delete options[option];
1808 description: Standalone CSS3 Selector parser
1809 provides: Slick.Parser
1823 var parse = function(expression, isReversed){
1824 if (expression == null) return null;
1825 if (expression.Slick === true) return expression;
1826 expression = ('' + expression).replace(/^\s+|\s+$/g, '');
1827 reversed = !!isReversed;
1828 var currentCache = (reversed) ? reverseCache : cache;
1829 if (currentCache[expression]) return currentCache[expression];
1830 parsed = {Slick: true, expressions: [], raw: expression, reverse: function(){
1831 return parse(this.raw, true);
1833 separatorIndex = -1;
1834 while (expression != (expression = expression.replace(regexp, parser)));
1835 parsed.length = parsed.expressions.length;
1836 return currentCache[expression] = (reversed) ? reverse(parsed) : parsed;
1839 var reverseCombinator = function(combinator){
1840 if (combinator === '!') return ' ';
1841 else if (combinator === ' ') return '!';
1842 else if ((/^!/).test(combinator)) return combinator.replace(/^!/, '');
1843 else return '!' + combinator;
1846 var reverse = function(expression){
1847 var expressions = expression.expressions;
1848 for (var i = 0; i < expressions.length; i++){
1849 var exp = expressions[i];
1850 var last = {parts: [], tag: '*', combinator: reverseCombinator(exp[0].combinator)};
1852 for (var j = 0; j < exp.length; j++){
1854 if (!cexp.reverseCombinator) cexp.reverseCombinator = ' ';
1855 cexp.combinator = cexp.reverseCombinator;
1856 delete cexp.reverseCombinator;
1859 exp.reverse().push(last);
1864 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, "\\$&");
1868 var regexp = new RegExp(
1871 puts "\t\t" + DATA.read.gsub(/\(\?x\)|\s+#.*$|\s+|\\$|\\n/,'')
1874 \\s* ( , ) \\s* # Separator \n\
1875 | \\s* ( <combinator>+ ) \\s* # Combinator \n\
1876 | ( \\s+ ) # CombinatorChildren \n\
1877 | ( <unicode>+ | \\* ) # Tag \n\
1878 | \\# ( <unicode>+ ) # ID \n\
1879 | \\. ( <unicode>+ ) # ClassName \n\
1882 \\s* (<unicode1>+) (?: \
1883 \\s* ([*^$!~|]?=) (?: \
1890 | :+ ( <unicode>+ )(?:\
1892 (?:([\"'])([^\\12]*)\\12)|((?:\\([^)]+\\)|[^()]*)+)\
1897 "^(?:\\s*(,)\\s*|\\s*(<combinator>+)\\s*|(\\s+)|(<unicode>+|\\*)|\\#(<unicode>+)|\\.(<unicode>+)|\\[\\s*(<unicode1>+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|:+(<unicode>+)(?:\\((?:(?:([\"'])([^\\12]*)\\12)|((?:\\([^)]+\\)|[^()]*)+))\\))?)"
1898 .replace(/<combinator>/, '[' + escapeRegExp(">+~`!@$%^&={}\\;</") + ']')
1899 .replace(/<unicode>/g, '(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
1900 .replace(/<unicode1>/g, '(?:[:\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
1921 pseudoClassQuotedValue,
1924 if (separator || separatorIndex === -1){
1925 parsed.expressions[++separatorIndex] = [];
1926 combinatorIndex = -1;
1927 if (separator) return '';
1930 if (combinator || combinatorChildren || combinatorIndex === -1){
1931 combinator = combinator || ' ';
1932 var currentSeparator = parsed.expressions[separatorIndex];
1933 if (reversed && currentSeparator[combinatorIndex])
1934 currentSeparator[combinatorIndex].reverseCombinator = reverseCombinator(combinator);
1935 currentSeparator[++combinatorIndex] = {combinator: combinator, tag: '*'};
1938 var currentParsed = parsed.expressions[separatorIndex][combinatorIndex];
1941 currentParsed.tag = tagName.replace(reUnescape, '');
1944 currentParsed.id = id.replace(reUnescape, '');
1946 } else if (className){
1947 className = className.replace(reUnescape, '');
1949 if (!currentParsed.classList) currentParsed.classList = [];
1950 if (!currentParsed.classes) currentParsed.classes = [];
1951 currentParsed.classList.push(className);
1952 currentParsed.classes.push({
1954 regexp: new RegExp('(^|\\s)' + escapeRegExp(className) + '(\\s|$)')
1957 } else if (pseudoClass){
1958 pseudoClassValue = pseudoClassValue || pseudoClassQuotedValue;
1959 pseudoClassValue = pseudoClassValue ? pseudoClassValue.replace(reUnescape, '') : null;
1961 if (!currentParsed.pseudos) currentParsed.pseudos = [];
1962 currentParsed.pseudos.push({
1963 key: pseudoClass.replace(reUnescape, ''),
1964 value: pseudoClassValue
1967 } else if (attributeKey){
1968 attributeKey = attributeKey.replace(reUnescape, '');
1969 attributeValue = (attributeValue || '').replace(reUnescape, '');
1973 switch (attributeOperator){
1974 case '^=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) ); break;
1975 case '$=' : regexp = new RegExp( escapeRegExp(attributeValue) +'$' ); break;
1976 case '~=' : regexp = new RegExp( '(^|\\s)'+ escapeRegExp(attributeValue) +'(\\s|$)' ); break;
1977 case '|=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) +'(-|$)' ); break;
1978 case '=' : test = function(value){
1979 return attributeValue == value;
1981 case '*=' : test = function(value){
1982 return value && value.indexOf(attributeValue) > -1;
1984 case '!=' : test = function(value){
1985 return attributeValue != value;
1987 default : test = function(value){
1992 if (attributeValue == '' && (/^[*$^]=$/).test(attributeOperator)) test = function(){
1996 if (!test) test = function(value){
1997 return value && regexp.test(value);
2000 if (!currentParsed.attributes) currentParsed.attributes = [];
2001 currentParsed.attributes.push({
2003 operator: attributeOperator,
2004 value: attributeValue,
2015 var Slick = (this.Slick || {});
2017 Slick.parse = function(expression){
2018 return parse(expression);
2021 Slick.escapeRegExp = escapeRegExp;
2023 if (!this.Slick) this.Slick = Slick;
2025 }).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this);
2031 description: The new, superfast css selector engine.
2032 provides: Slick.Finder
2033 requires: Slick.Parser
2041 // Feature / Bug detection
2043 local.isNativeCode = function(fn){
2044 return (/\{\s*\[native code\]\s*\}/).test('' + fn);
2047 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');
2052 local.setDocument = function(document){
2054 // convert elements / window arguments to document. if document cannot be extrapolated, the function returns.
2056 if (document.nodeType === 9); // document
2057 else if (document.ownerDocument) document = document.ownerDocument; // node
2058 else if (document.navigator) document = document.document; // window
2061 // check if it's the old document
2063 if (this.document === document) return;
2064 this.document = document;
2065 var root = this.root = document.documentElement;
2067 this.isXMLDocument = this.isXML(document);
2069 this.brokenStarGEBTN
2070 = this.starSelectsClosedQSA
2072 = this.brokenMixedCaseQSA
2074 = this.brokenCheckedQSA
2075 = this.brokenEmptyAttributeQSA
2076 = this.isHTMLDocument
2079 var starSelectsClosed, starSelectsComments,
2080 brokenSecondClassNameGEBCN, cachedGetElementsByClassName;
2083 var testNode = document.createElement('div');
2084 root.appendChild(testNode);
2086 // on non-HTML documents innerHTML and getElementsById doesnt work properly
2088 id = 'slick_getbyid_test';
2089 testNode.innerHTML = '<a id="'+id+'"></a>';
2090 this.isHTMLDocument = !!document.getElementById(id);
2093 if (this.isHTMLDocument){
2095 testNode.style.display = 'none';
2097 // IE returns comment nodes for getElementsByTagName('*') for some documents
2098 testNode.appendChild(document.createComment(''));
2099 starSelectsComments = (testNode.getElementsByTagName('*').length > 0);
2101 // IE returns closed nodes (EG:"</foo>") for getElementsByTagName('*') for some documents
2103 testNode.innerHTML = 'foo</foo>';
2104 selected = testNode.getElementsByTagName('*');
2105 starSelectsClosed = (selected && selected.length && selected[0].nodeName.charAt(0) == '/');
2108 this.brokenStarGEBTN = starSelectsComments || starSelectsClosed;
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) == '/');
2117 // IE returns elements with the name instead of just id for getElementsById for some documents
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;
2124 // Safari 3.2 querySelectorAll doesnt work with mixedcase on quirksmode
2126 testNode.innerHTML = '<a class="MiXedCaSe"></a>';
2127 this.brokenMixedCaseQSA = !testNode.querySelectorAll('.MiXedCaSe').length;
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);
2137 // Opera 9.6 getElementsByClassName doesnt detects the class if its not the first one
2139 testNode.innerHTML = '<a class="a"></a><a class="f b a"></a>';
2140 brokenSecondClassNameGEBCN = (testNode.getElementsByClassName('a').length != 2);
2143 this.brokenGEBCN = cachedGetElementsByClassName || brokenSecondClassNameGEBCN;
2145 // Webkit dont return selected options on querySelectorAll
2147 testNode.innerHTML = '<select><option selected="selected">a</option></select>';
2148 this.brokenCheckedQSA = (testNode.querySelectorAll(':checked').length == 0);
2151 // IE returns incorrect results for attr[*^$]="" selectors on querySelectorAll
2153 testNode.innerHTML = '<a class=""></a>';
2154 this.brokenEmptyAttributeQSA = (testNode.querySelectorAll('[class*=""]').length != 0);
2159 root.removeChild(testNode);
2164 this.hasAttribute = (root && this.isNativeCode(root.hasAttribute)) ? function(node, attribute) {
2165 return node.hasAttribute(attribute);
2166 } : function(node, attribute) {
2167 node = node.getAttributeNode(attribute);
2168 return !!(node && (node.specified || node.nodeValue));
2172 // FIXME: Add specs: local.contains should be different for xml and html documents?
2173 this.contains = (root && this.isNativeCode(root.contains)) ? function(context, node){
2174 return context.contains(node);
2175 } : (root && root.compareDocumentPosition) ? function(context, node){
2176 return context === node || !!(context.compareDocumentPosition(node) & 16);
2177 } : function(context, node){
2179 if (node === context) return true;
2180 } while ((node = node.parentNode));
2184 // document order sorting
2185 // credits to Sizzle (http://sizzlejs.com/)
2187 this.documentSorter = (root.compareDocumentPosition) ? function(a, b){
2188 if (!a.compareDocumentPosition || !b.compareDocumentPosition) return 0;
2189 return a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
2190 } : ('sourceIndex' in root) ? function(a, b){
2191 if (!a.sourceIndex || !b.sourceIndex) return 0;
2192 return a.sourceIndex - b.sourceIndex;
2193 } : (document.createRange) ? function(a, b){
2194 if (!a.ownerDocument || !b.ownerDocument) return 0;
2195 var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
2196 aRange.setStart(a, 0);
2197 aRange.setEnd(a, 0);
2198 bRange.setStart(b, 0);
2199 bRange.setEnd(b, 0);
2200 return aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
2203 this.getUID = (this.isHTMLDocument) ? this.getUIDHTML : this.getUIDXML;
2209 local.search = function(context, expression, append, first){
2211 var found = this.found = (first) ? null : (append || []);
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
2223 var uniques = this.uniques = {};
2225 if (this.document !== (context.ownerDocument || context)) this.setDocument(context);
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);
2231 // avoid duplicating items already in the append array
2232 if (shouldUniques) for (i = found.length; i--;) this.uniques[this.getUID(found[i])] = true;
2234 // expression checks
2236 if (typeof expression == 'string'){ // expression is a string
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;
2250 parsed = this.Slick.parse(expression);
2251 if (!parsed.length) return found;
2252 } else if (expression == null){ // there is no expression
2254 } else if (expression.Slick){ // expression is a parsed Slick object
2255 parsed = expression;
2256 } else if (this.contains(context.documentElement || context, expression)){ // expression is a node
2257 (found) ? found.push(expression) : found = expression;
2259 } else { // other junk
2263 // cache elements for the nth selectors
2265 /*<pseudo-selectors>*//*<nth-pseudo-selectors>*/
2268 this.posNTHLast = {};
2269 this.posNTHType = {};
2270 this.posNTHTypeLast = {};
2272 /*</nth-pseudo-selectors>*//*</pseudo-selectors>*/
2274 // 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;
2277 if (found == null) found = [];
2282 var combinator, tag, id, classList, classes, attributes, pseudos;
2283 var currentItems, currentExpression, currentBit, lastBit, expressions = parsed.expressions;
2285 search: for (i = 0; (currentExpression = expressions[i]); i++) for (j = 0; (currentBit = currentExpression[j]); j++){
2287 combinator = 'combinator:' + currentBit.combinator;
2288 if (!this[combinator]) continue search;
2290 tag = (this.isXMLDocument) ? currentBit.tag : currentBit.tag.toUpperCase();
2292 classList = currentBit.classList;
2293 classes = currentBit.classes;
2294 attributes = currentBit.attributes;
2295 pseudos = currentBit.pseudos;
2296 lastBit = (j === (currentExpression.length - 1));
2298 this.bitUniques = {};
2301 this.uniques = uniques;
2309 this[combinator](context, tag, id, classes, attributes, pseudos, classList);
2310 if (first && lastBit && found.length) break search;
2312 if (first && lastBit) for (m = 0, n = currentItems.length; m < n; m++){
2313 this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList);
2314 if (found.length) break search;
2315 } else for (m = 0, n = currentItems.length; m < n; m++) this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList);
2318 currentItems = this.found;
2321 if (shouldUniques || (parsed.expressions.length > 1)) this.sort(found);
2323 return (first) ? (found[0] || null) : found;
2329 local.uidk = 'slick:uniqueid';
2331 local.getUIDXML = function(node){
2332 var uid = node.getAttribute(this.uidk);
2335 node.setAttribute(this.uidk, uid);
2340 local.getUIDHTML = function(node){
2341 return node.uniqueNumber || (node.uniqueNumber = this.uidx++);
2344 // sort based on the setDocument documentSorter method.
2346 local.sort = function(results){
2347 if (!this.documentSorter) return results;
2348 results.sort(this.documentSorter);
2352 /*<pseudo-selectors>*//*<nth-pseudo-selectors>*/
2354 local.cacheNTH = {};
2356 local.matchNTH = /^([+-]?\d*)?([a-z]+)?([+-]\d+)?$/;
2358 local.parseNTHArgument = function(argument){
2359 var parsed = argument.match(this.matchNTH);
2360 if (!parsed) return false;
2361 var special = parsed[2] || false;
2362 var a = parsed[1] || 1;
2363 if (a == '-') a = -1;
2364 var b = +parsed[3] || 0;
2366 (special == 'n') ? {a: a, b: b} :
2367 (special == 'odd') ? {a: 2, b: 1} :
2368 (special == 'even') ? {a: 2, b: 0} : {a: 0, b: a};
2370 return (this.cacheNTH[argument] = parsed);
2373 local.createNTHPseudo = function(child, sibling, positions, ofType){
2374 return function(node, argument){
2375 var uid = this.getUID(node);
2376 if (!this[positions][uid]){
2377 var parent = node.parentNode;
2378 if (!parent) return false;
2379 var el = parent[child], count = 1;
2381 var nodeName = node.nodeName;
2383 if (el.nodeName !== nodeName) continue;
2384 this[positions][this.getUID(el)] = count++;
2385 } while ((el = el[sibling]));
2388 if (el.nodeType !== 1) continue;
2389 this[positions][this.getUID(el)] = count++;
2390 } while ((el = el[sibling]));
2393 argument = argument || 'n';
2394 var parsed = this.cacheNTH[argument] || this.parseNTHArgument(argument);
2395 if (!parsed) return false;
2396 var a = parsed.a, b = parsed.b, pos = this[positions][uid];
2397 if (a == 0) return b == pos;
2399 if (pos < b) return false;
2401 if (b < pos) return false;
2403 return ((pos - b) % a) == 0;
2407 /*</nth-pseudo-selectors>*//*</pseudo-selectors>*/
2409 local.pushArray = function(node, tag, id, classes, attributes, pseudos){
2410 if (this.matchSelector(node, tag, id, classes, attributes, pseudos)) this.found.push(node);
2413 local.pushUID = function(node, tag, id, classes, attributes, pseudos){
2414 var uid = this.getUID(node);
2415 if (!this.uniques[uid] && this.matchSelector(node, tag, id, classes, attributes, pseudos)){
2416 this.uniques[uid] = true;
2417 this.found.push(node);
2421 local.matchNode = function(node, selector){
2422 var parsed = this.Slick.parse(selector);
2423 if (!parsed) return true;
2425 // 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);
2431 var nodes = this.search(this.document, parsed);
2432 for (var i = 0, item; item = nodes[i++];){
2433 if (item === node) return true;
2438 local.matchPseudo = function(node, name, argument){
2439 var pseudoName = 'pseudo:' + name;
2440 if (this[pseudoName]) return this[pseudoName](node, argument);
2441 var attribute = this.getAttribute(node, name);
2442 return (argument) ? argument == attribute : !!attribute;
2445 local.matchSelector = function(node, tag, id, classes, attributes, pseudos){
2448 if (node.nodeName < '@') return false; // Fix for comment nodes and closed nodes
2450 if (node.nodeName != tag) return false;
2454 if (id && node.getAttribute('id') != id) return false;
2457 if (classes) for (i = classes.length; i--;){
2458 cls = ('className' in node) ? node.className : node.getAttribute('class');
2459 if (!(cls && classes[i].regexp.test(cls))) return false;
2461 if (attributes) for (i = attributes.length; i--;){
2462 part = attributes[i];
2463 if (part.operator ? !part.test(this.getAttribute(node, part.key)) : !this.hasAttribute(node, part.key)) return false;
2465 if (pseudos) for (i = pseudos.length; i--;){
2467 if (!this.matchPseudo(node, part.key, part.value)) return false;
2474 ' ': function(node, tag, id, classes, attributes, pseudos, classList){ // all child nodes, any level
2476 var i, item, children;
2478 if (this.isHTMLDocument){
2480 item = this.document.getElementById(id);
2481 if ((!item && node.all) || (this.idGetsName && item && item.getAttributeNode('id').nodeValue != id)){
2482 // all[id] returns all the elements with that name or id inside node
2483 // if theres just one it will return the element, else it will be a collection
2484 children = node.all[id];
2485 if (!children) return;
2486 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);
2494 // 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;
2497 } else if (this.document !== node && !this.contains(node, item)) return;
2498 this.push(item, tag, null, classes, attributes, pseudos);
2501 getByClass: if (classes && node.getElementsByClassName && !this.brokenGEBCN){
2502 children = node.getElementsByClassName(classList.join(' '));
2503 if (!(children && children.length)) break getByClass;
2504 for (i = 0; item = children[i++];) this.push(item, tag, id, null, attributes, pseudos);
2509 children = node.getElementsByTagName(tag);
2510 if (!(children && children.length)) break getByTag;
2511 if (!this.brokenStarGEBTN) tag = null;
2512 for (i = 0; item = children[i++];) this.push(item, tag, id, classes, attributes, pseudos);
2516 '>': function(node, tag, id, classes, attributes, pseudos){ // direct children
2517 if ((node = node.firstChild)) do {
2518 if (node.nodeType === 1) this.push(node, tag, id, classes, attributes, pseudos);
2519 } while ((node = node.nextSibling));
2522 '+': function(node, tag, id, classes, attributes, pseudos){ // next sibling
2523 while ((node = node.nextSibling)) if (node.nodeType === 1){
2524 this.push(node, tag, id, classes, attributes, pseudos);
2529 '^': function(node, tag, id, classes, attributes, pseudos){ // first child
2530 node = node.firstChild;
2532 if (node.nodeType === 1) this.push(node, tag, id, classes, attributes, pseudos);
2533 else this['combinator:+'](node, tag, id, classes, attributes, pseudos);
2537 '~': function(node, tag, id, classes, attributes, pseudos){ // next siblings
2538 while ((node = node.nextSibling)){
2539 if (node.nodeType !== 1) continue;
2540 var uid = this.getUID(node);
2541 if (this.bitUniques[uid]) break;
2542 this.bitUniques[uid] = true;
2543 this.push(node, tag, id, classes, attributes, pseudos);
2547 '++': function(node, tag, id, classes, attributes, pseudos){ // next sibling and previous sibling
2548 this['combinator:+'](node, tag, id, classes, attributes, pseudos);
2549 this['combinator:!+'](node, tag, id, classes, attributes, pseudos);
2552 '~~': function(node, tag, id, classes, attributes, pseudos){ // next siblings and previous siblings
2553 this['combinator:~'](node, tag, id, classes, attributes, pseudos);
2554 this['combinator:!~'](node, tag, id, classes, attributes, pseudos);
2557 '!': function(node, tag, id, classes, attributes, pseudos){ // all parent nodes up to document
2558 while ((node = node.parentNode)) if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos);
2561 '!>': function(node, tag, id, classes, attributes, pseudos){ // direct parent (one level)
2562 node = node.parentNode;
2563 if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos);
2566 '!+': function(node, tag, id, classes, attributes, pseudos){ // previous sibling
2567 while ((node = node.previousSibling)) if (node.nodeType === 1){
2568 this.push(node, tag, id, classes, attributes, pseudos);
2573 '!^': function(node, tag, id, classes, attributes, pseudos){ // last child
2574 node = node.lastChild;
2576 if (node.nodeType === 1) this.push(node, tag, id, classes, attributes, pseudos);
2577 else this['combinator:!+'](node, tag, id, classes, attributes, pseudos);
2581 '!~': function(node, tag, id, classes, attributes, pseudos){ // previous siblings
2582 while ((node = node.previousSibling)){
2583 if (node.nodeType !== 1) continue;
2584 var uid = this.getUID(node);
2585 if (this.bitUniques[uid]) break;
2586 this.bitUniques[uid] = true;
2587 this.push(node, tag, id, classes, attributes, pseudos);
2593 for (var c in combinators) local['combinator:' + c] = combinators[c];
2597 /*<pseudo-selectors>*/
2599 'empty': function(node){
2600 var child = node.firstChild;
2601 return !(child && child.nodeType == 1) && !(node.innerText || node.textContent || '').length;
2604 'not': function(node, expression){
2605 return !this.matchNode(node, expression);
2608 'contains': function(node, text){
2609 return (node.innerText || node.textContent || '').indexOf(text) > -1;
2612 'first-child': function(node){
2613 while ((node = node.previousSibling)) if (node.nodeType === 1) return false;
2617 'last-child': function(node){
2618 while ((node = node.nextSibling)) if (node.nodeType === 1) return false;
2622 'only-child': function(node){
2624 while ((prev = prev.previousSibling)) if (prev.nodeType === 1) return false;
2626 while ((next = next.nextSibling)) if (next.nodeType === 1) return false;
2630 /*<nth-pseudo-selectors>*/
2632 'nth-child': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTH'),
2634 'nth-last-child': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHLast'),
2636 'nth-of-type': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTHType', true),
2638 'nth-last-of-type': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHTypeLast', true),
2640 'index': function(node, index){
2641 return this['pseudo:nth-child'](node, '' + index + 1);
2644 'even': function(node, argument){
2645 return this['pseudo:nth-child'](node, '2n');
2648 'odd': function(node, argument){
2649 return this['pseudo:nth-child'](node, '2n+1');
2652 /*</nth-pseudo-selectors>*/
2654 /*<of-type-pseudo-selectors>*/
2656 'first-of-type': function(node){
2657 var nodeName = node.nodeName;
2658 while ((node = node.previousSibling)) if (node.nodeName === nodeName) return false;
2662 'last-of-type': function(node){
2663 var nodeName = node.nodeName;
2664 while ((node = node.nextSibling)) if (node.nodeName === nodeName) return false;
2668 'only-of-type': function(node){
2669 var prev = node, nodeName = node.nodeName;
2670 while ((prev = prev.previousSibling)) if (prev.nodeName === nodeName) return false;
2672 while ((next = next.nextSibling)) if (next.nodeName === nodeName) return false;
2676 /*</of-type-pseudo-selectors>*/
2680 'enabled': function(node){
2681 return (node.disabled === false);
2684 'disabled': function(node){
2685 return (node.disabled === true);
2688 'checked': function(node){
2689 return node.checked || node.selected;
2692 'focus': function(node){
2693 return this.isHTMLDocument && this.document.activeElement === node && (node.href || node.type || this.hasAttribute(node, 'tabindex'));
2696 'root': function(node){
2697 return (node === this.root);
2700 'selected': function(node){
2701 return node.selected;
2704 /*</pseudo-selectors>*/
2707 for (var p in pseudos) local['pseudo:' + p] = pseudos[p];
2709 // attributes methods
2711 local.attributeGetters = {
2713 'class': function(){
2714 return ('className' in this) ? this.className : this.getAttribute('class');
2718 return ('htmlFor' in this) ? this.htmlFor : this.getAttribute('for');
2722 return ('href' in this) ? this.getAttribute('href', 2) : this.getAttribute('href');
2725 'style': function(){
2726 return (this.style) ? this.style.cssText : this.getAttribute('style');
2731 local.getAttribute = function(node, name){
2732 // FIXME: check if getAttribute() will get input elements on a form on this browser
2733 // getAttribute is faster than getAttributeNode().nodeValue
2734 var method = this.attributeGetters[name];
2735 if (method) return method.call(node);
2736 var attributeNode = node.getAttributeNode(name);
2737 return attributeNode ? attributeNode.nodeValue : null;
2742 local.overrides = [];
2744 local.override = function(regexp, method){
2745 this.overrides.push({regexp: regexp, method: method});
2750 /*<query-selector-override>*/
2752 var reEmptyAttribute = /\[.*[*$^]=(?:["']{2})?\]/;
2754 local.override(/./, function(expression, found, first){ //querySelectorAll override
2756 if (!this.querySelectorAll || this.nodeType != 9 || !local.isHTMLDocument || local.brokenMixedCaseQSA ||
2757 (local.brokenCheckedQSA && expression.indexOf(':checked') > -1) ||
2758 (local.brokenEmptyAttributeQSA && reEmptyAttribute.test(expression)) || Slick.disableQSA) return false;
2762 if (first) return this.querySelector(expression) || null;
2763 else nodes = this.querySelectorAll(expression);
2768 var i, hasOthers = !!(found.length);
2770 if (local.starSelectsClosedQSA) for (i = 0; node = nodes[i++];){
2771 if (node.nodeName > '@' && (!hasOthers || !local.uniques[local.getUIDHTML(node)])) found.push(node);
2772 } else for (i = 0; node = nodes[i++];){
2773 if (!hasOthers || !local.uniques[local.getUIDHTML(node)]) found.push(node);
2776 if (hasOthers) local.sort(found);
2782 /*</query-selector-override>*/
2786 local.override(/^[\w-]+$|^\*$/, function(expression, found, first){ // tag override
2787 var tag = expression;
2788 if (tag == '*' && local.brokenStarGEBTN) return false;
2790 var nodes = this.getElementsByTagName(tag);
2792 if (first) return nodes[0] || null;
2793 var i, node, hasOthers = !!(found.length);
2795 for (i = 0; node = nodes[i++];){
2796 if (!hasOthers || !local.uniques[local.getUID(node)]) found.push(node);
2799 if (hasOthers) local.sort(found);
2806 /*<class-override>*/
2808 local.override(/^\.[\w-]+$/, function(expression, found, first){ // class override
2809 if (!local.isHTMLDocument || (!this.getElementsByClassName && this.querySelectorAll)) return false;
2811 var nodes, node, i, hasOthers = !!(found && found.length), className = expression.substring(1);
2812 if (this.getElementsByClassName && !local.brokenGEBCN){
2813 nodes = this.getElementsByClassName(className);
2814 if (first) return nodes[0] || null;
2815 for (i = 0; node = nodes[i++];){
2816 if (!hasOthers || !local.uniques[local.getUIDHTML(node)]) found.push(node);
2819 var matchClass = new RegExp('(^|\\s)'+ Slick.escapeRegExp(className) +'(\\s|$)');
2820 nodes = this.getElementsByTagName('*');
2821 for (i = 0; node = nodes[i++];){
2822 className = node.className;
2823 if (!className || !matchClass.test(className)) continue;
2824 if (first) return node;
2825 if (!hasOthers || !local.uniques[local.getUIDHTML(node)]) found.push(node);
2828 if (hasOthers) local.sort(found);
2829 return (first) ? null : true;
2832 /*</class-override>*/
2836 local.override(/^#[\w-]+$/, function(expression, found, first){ // ID override
2837 if (!local.isHTMLDocument || this.nodeType != 9) return false;
2839 var id = expression.substring(1), el = this.getElementById(id);
2840 if (!el) return found;
2841 if (local.idGetsName && el.getAttributeNode('id').nodeValue != id) return false;
2842 if (first) return el || null;
2843 var hasOthers = !!(found.length);
2844 if (!hasOthers || !local.uniques[local.getUIDHTML(el)]) found.push(el);
2845 if (hasOthers) local.sort(found);
2853 if (typeof document != 'undefined') local.setDocument(document);
2857 var Slick = local.Slick = (this.Slick || {});
2859 Slick.version = '0.9dev';
2863 Slick.search = function(context, expression, append){
2864 return local.search(context, expression, append);
2867 Slick.find = function(context, expression){
2868 return local.search(context, expression, null, true);
2871 // Slick containment checker
2873 Slick.contains = function(container, node){
2874 local.setDocument(container);
2875 return local.contains(container, node);
2878 // Slick attribute getter
2880 Slick.getAttribute = function(node, name){
2881 return local.getAttribute(node, name);
2886 Slick.match = function(node, selector){
2887 if (!(node && selector)) return false;
2888 if (!selector || selector === node) return true;
2889 if (typeof selector != 'string') return false;
2890 local.setDocument(node);
2891 return local.matchNode(node, selector);
2894 // Slick attribute accessor
2896 Slick.defineAttributeGetter = function(name, fn){
2897 local.attributeGetters[name] = fn;
2901 Slick.lookupAttributeGetter = function(name){
2902 return local.attributeGetters[name];
2905 // Slick pseudo accessor
2907 Slick.definePseudo = function(name, fn){
2908 local['pseudo:' + name] = function(node, argument){
2909 return fn.call(node, argument);
2914 Slick.lookupPseudo = function(name){
2915 var pseudo = local['pseudo:' + name];
2916 if (pseudo) return function(argument){
2917 return pseudo.call(this, argument);
2922 // Slick overrides accessor
2924 Slick.override = function(regexp, fn){
2925 local.override(regexp, fn);
2929 Slick.isXML = local.isXML;
2931 Slick.uidOf = function(node){
2932 return local.getUIDHTML(node);
2935 if (!this.Slick) this.Slick = Slick;
2937 }).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this);
2945 description: One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser, time-saver methods to let you easily work with HTML Elements.
2947 license: MIT-style license.
2949 requires: [Window, Document, Array, String, Function, Number, Slick.Parser, Slick.Finder]
2951 provides: [Element, Elements, $, $$, Iframe, Selectors]
2956 var Element = function(tag, props){
2957 var konstructor = Element.Constructors[tag];
2958 if (konstructor) return konstructor(props);
2959 if (typeof tag != 'string') return document.id(tag).set(props);
2961 if (!props) props = {};
2963 if (!tag.test(/^[\w-]+$/)){
2964 var parsed = Slick.parse(tag).expressions[0][0];
2965 tag = (parsed.tag == '*') ? 'div' : parsed.tag;
2966 if (parsed.id && props.id == null) props.id = parsed.id;
2968 var attributes = parsed.attributes;
2969 if (attributes) for (var i = 0, l = attributes.length; i < l; i++){
2970 var attr = attributes[i];
2971 if (attr.value != null && attr.operator == '=' && props[attr.key] == null)
2972 props[attr.key] = attr.value;
2975 if (parsed.classList && props['class'] == null) props['class'] = parsed.classList.join(' ');
2978 return document.newElement(tag, props);
2981 if (Browser.Element) Element.prototype = Browser.Element.prototype;
2983 new Type('Element', Element).mirror(function(name){
2984 if (Array.prototype[name]) return;
2987 obj[name] = function(){
2988 var results = [], args = arguments, elements = true;
2989 for (var i = 0, l = this.length; i < l; i++){
2990 var element = this[i], result = results[i] = element[name].apply(element, args);
2991 elements = (elements && typeOf(result) == 'element');
2993 return (elements) ? new Elements(results) : results;
2996 Elements.implement(obj);
2999 if (!Browser.Element){
3000 Element.parent = Object;
3002 Element.Prototype = {'$family': Function.from('element').hide()};
3004 Element.mirror(function(name, method){
3005 Element.Prototype[name] = method;
3009 Element.Constructors = {};
3013 Element.Constructors = new Hash;
3017 var IFrame = new Type('IFrame', function(){
3018 var params = Array.link(arguments, {
3019 properties: Type.isObject,
3020 iframe: function(obj){
3021 return (obj != null);
3025 var props = params.properties || {}, iframe;
3026 if (params.iframe) iframe = document.id(params.iframe);
3027 var onload = props.onload || function(){};
3028 delete props.onload;
3029 props.id = props.name = [props.id, props.name, iframe ? (iframe.id || iframe.name) : 'IFrame_' + String.uniqueID()].pick();
3030 iframe = new Element(iframe || 'iframe', props);
3032 var onLoad = function(){
3033 onload.call(iframe.contentWindow);
3036 if (window.frames[props.id]) onLoad();
3037 else iframe.addListener('load', onLoad);
3041 var Elements = this.Elements = function(nodes){
3042 if (nodes && nodes.length){
3043 var uniques = {}, node;
3044 for (var i = 0; node = nodes[i++];){
3045 var uid = Slick.uidOf(node);
3047 uniques[uid] = true;
3054 Elements.prototype = {length: 0};
3055 Elements.parent = Array;
3057 new Type('Elements', Elements).implement({
3059 filter: function(filter, bind){
3060 if (!filter) return this;
3061 return new Elements(Array.filter(this, (typeOf(filter) == 'string') ? function(item){
3062 return item.match(filter);
3067 var length = this.length;
3068 for (var i = 0, l = arguments.length; i < l; i++){
3069 var item = document.id(arguments[i]);
3070 if (item) this[length++] = item;
3072 return (this.length = length);
3076 var newElements = new Elements(this);
3077 for (var i = 0, l = arguments.length; i < l; i++){
3078 var item = arguments[i];
3079 if (Type.isEnumerable(item)) newElements.append(item);
3080 else newElements.push(item);
3085 append: function(collection){
3086 for (var i = 0, l = collection.length; i < l; i++) this.push(collection[i]);
3091 while (this.length) delete this[--this.length];
3100 var splice = Array.prototype.splice, object = {'0': 0, '1': 1, length: 2};
3102 splice.call(object, 1, 1);
3103 if (object[1] == 1) Elements.implement('splice', function(){
3104 var length = this.length;
3105 splice.apply(this, arguments);
3106 while (length >= this.length) delete this[length--];
3110 Elements.implement(Array.prototype);
3112 Array.mirror(Elements);
3115 var createElementAcceptsHTML;
3117 var x = document.createElement('<input name=x>');
3118 createElementAcceptsHTML = (x.name == 'x');
3121 var escapeQuotes = function(html){
3122 return ('' + html).replace(/&/g, '&').replace(/"/g, '"');
3126 Document.implement({
3128 newElement: function(tag, props){
3129 if (props && props.checked != null) props.defaultChecked = props.checked;
3130 /*<ltIE8>*/// Fix for readonly name and type properties in IE < 8
3131 if (createElementAcceptsHTML && props){
3133 if (props.name) tag += ' name="' + escapeQuotes(props.name) + '"';
3134 if (props.type) tag += ' type="' + escapeQuotes(props.type) + '"';
3140 return this.id(this.createElement(tag)).set(props);
3147 Document.implement({
3149 newTextNode: function(text){
3150 return this.createTextNode(text);
3153 getDocument: function(){
3157 getWindow: function(){
3165 string: function(id, nocash, doc){
3166 id = Slick.find(doc, '#' + id.replace(/(\W)/g, '\\$1'));
3167 return (id) ? types.element(id, nocash) : null;
3170 element: function(el, nocash){
3172 if (!nocash && !el.$family && !(/^object|embed$/i).test(el.tagName)){
3173 Object.append(el, Element.Prototype);
3178 object: function(obj, nocash, doc){
3179 if (obj.toElement) return types.element(obj.toElement(doc), nocash);
3185 types.textnode = types.whitespace = types.window = types.document = function(zero){
3189 return function(el, nocash, doc){
3190 if (el && el.$family && el.uid) return el;
3191 var type = typeOf(el);
3192 return (types[type]) ? types[type](el, nocash, doc || document) : null;
3199 if (window.$ == null) Window.implement('$', function(el, nc){
3200 return document.id(el, nc, this.document);
3205 getDocument: function(){
3206 return this.document;
3209 getWindow: function(){
3215 [Document, Element].invoke('implement', {
3217 getElements: function(expression){
3218 return Slick.search(this, expression, new Elements);
3221 getElement: function(expression){
3222 return document.id(Slick.find(this, expression));
3229 (function(search, find, match){
3231 this.Selectors = {};
3232 var pseudos = this.Selectors.Pseudo = new Hash();
3234 var addSlickPseudos = function(){
3235 for (var name in pseudos) if (pseudos.hasOwnProperty(name)){
3236 Slick.definePseudo(name, pseudos[name]);
3237 delete pseudos[name];
3241 Slick.search = function(context, expression, append){
3243 return search.call(this, context, expression, append);
3246 Slick.find = function(context, expression){
3248 return find.call(this, context, expression);
3251 Slick.match = function(node, selector){
3253 return match.call(this, node, selector);
3256 })(Slick.search, Slick.find, Slick.match);
3258 if (window.$$ == null) Window.implement('$$', function(selector){
3259 var elements = new Elements;
3260 if (arguments.length == 1 && typeof selector == 'string') return Slick.search(this.document, selector, elements);
3261 var args = Array.flatten(arguments);
3262 for (var i = 0, l = args.length; i < l; i++){
3264 switch (typeOf(item)){
3265 case 'element': elements.push(item); break;
3266 case 'string': Slick.search(this.document, item, elements);
3274 if (window.$$ == null) Window.implement('$$', function(selector){
3275 if (arguments.length == 1){
3276 if (typeof selector == 'string') return Slick.search(this.document, selector, new Elements);
3277 else if (Type.isEnumerable(selector)) return new Elements(selector);
3279 return new Elements(arguments);
3284 var collected = {}, storage = {};
3285 var props = {input: 'checked', option: 'selected', textarea: 'value'};
3287 var get = function(uid){
3288 return (storage[uid] || (storage[uid] = {}));
3291 var clean = function(item){
3292 if (item.removeEvents) item.removeEvents();
3293 if (item.clearAttributes) item.clearAttributes();
3296 delete collected[uid];
3297 delete storage[uid];
3302 var camels = ['defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', 'frameBorder', 'maxLength', 'readOnly',
3303 'rowSpan', 'tabIndex', 'useMap'
3305 var bools = ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readOnly', 'multiple', 'selected',
3309 'html': 'innerHTML',
3310 'class': 'className',
3312 'text': (function(){
3313 var temp = document.createElement('div');
3314 return (temp.innerText == null) ? 'textContent' : 'innerText';
3317 var readOnly = ['type'];
3318 var expandos = ['value', 'defaultValue'];
3319 var uriAttrs = /^(?:href|src|usemap)$/i;
3321 bools = bools.associate(bools);
3322 camels = camels.associate(camels.map(String.toLowerCase));
3323 readOnly = readOnly.associate(readOnly);
3325 Object.append(attributes, expandos.associate(expandos));
3329 before: function(context, element){
3330 var parent = element.parentNode;
3331 if (parent) parent.insertBefore(context, element);
3334 after: function(context, element){
3335 var parent = element.parentNode;
3336 if (parent) parent.insertBefore(context, element.nextSibling);
3339 bottom: function(context, element){
3340 element.appendChild(context);
3343 top: function(context, element){
3344 element.insertBefore(context, element.firstChild);
3349 inserters.inside = inserters.bottom;
3353 Object.each(inserters, function(inserter, where){
3355 where = where.capitalize();
3359 methods['inject' + where] = function(el){
3360 inserter(this, document.id(el, true));
3364 methods['grab' + where] = function(el){
3365 inserter(document.id(el, true), this);
3369 Element.implement(methods);
3375 var injectCombinator = function(expression, combinator){
3376 if (!expression) return combinator;
3378 expression = Slick.parse(expression);
3380 var expressions = expression.expressions;
3381 for (var i = expressions.length; i--;)
3382 expressions[i][0].combinator = combinator;
3389 set: function(prop, value){
3390 var property = Element.Properties[prop];
3391 (property && property.set) ? property.set.call(this, value) : this.setProperty(prop, value);
3394 get: function(prop){
3395 var property = Element.Properties[prop];
3396 return (property && property.get) ? property.get.apply(this) : this.getProperty(prop);
3399 erase: function(prop){
3400 var property = Element.Properties[prop];
3401 (property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop);
3405 setProperty: function(attribute, value){
3406 attribute = camels[attribute] || attribute;
3407 if (value == null) return this.removeProperty(attribute);
3408 var key = attributes[attribute];
3409 (key) ? this[key] = value :
3410 (bools[attribute]) ? this[attribute] = !!value : this.setAttribute(attribute, '' + value);
3414 setProperties: function(attributes){
3415 for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]);
3419 getProperty: function(attribute){
3420 attribute = camels[attribute] || attribute;
3421 var key = attributes[attribute] || readOnly[attribute];
3422 return (key) ? this[key] :
3423 (bools[attribute]) ? !!this[attribute] :
3424 (uriAttrs.test(attribute) ? this.getAttribute(attribute, 2) :
3425 (key = this.getAttributeNode(attribute)) ? key.nodeValue : null) || null;
3428 getProperties: function(){
3429 var args = Array.from(arguments);
3430 return args.map(this.getProperty, this).associate(args);
3433 removeProperty: function(attribute){
3434 attribute = camels[attribute] || attribute;
3435 var key = attributes[attribute];
3436 (key) ? this[key] = '' :
3437 (bools[attribute]) ? this[attribute] = false : this.removeAttribute(attribute);
3441 removeProperties: function(){
3442 Array.each(arguments, this.removeProperty, this);
3446 hasClass: function(className){
3447 return this.className.clean().contains(className, ' ');
3450 addClass: function(className){
3451 if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean();
3455 removeClass: function(className){
3456 this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1');
3460 toggleClass: function(className, force){
3461 if (force == null) force = !this.hasClass(className);
3462 return (force) ? this.addClass(className) : this.removeClass(className);
3466 var parent = this, fragment, elements = Array.flatten(arguments), length = elements.length;
3467 if (length > 1) parent = fragment = document.createDocumentFragment();
3469 for (var i = 0; i < length; i++){
3470 var element = document.id(elements[i], true);
3471 if (element) parent.appendChild(element);
3474 if (fragment) this.appendChild(fragment);
3479 appendText: function(text, where){
3480 return this.grab(this.getDocument().newTextNode(text), where);
3483 grab: function(el, where){
3484 inserters[where || 'bottom'](document.id(el, true), this);
3488 inject: function(el, where){
3489 inserters[where || 'bottom'](this, document.id(el, true));
3493 replaces: function(el){
3494 el = document.id(el, true);
3495 el.parentNode.replaceChild(this, el);
3499 wraps: function(el, where){
3500 el = document.id(el, true);
3501 return this.replaces(el).grab(el, where);
3504 getPrevious: function(expression){
3505 return document.id(Slick.find(this, injectCombinator(expression, '!~')));
3508 getAllPrevious: function(expression){
3509 return Slick.search(this, injectCombinator(expression, '!~'), new Elements);
3512 getNext: function(expression){
3513 return document.id(Slick.find(this, injectCombinator(expression, '~')));
3516 getAllNext: function(expression){
3517 return Slick.search(this, injectCombinator(expression, '~'), new Elements);
3520 getFirst: function(expression){
3521 return document.id(Slick.search(this, injectCombinator(expression, '>'))[0]);
3524 getLast: function(expression){
3525 return document.id(Slick.search(this, injectCombinator(expression, '>')).getLast());
3528 getParent: function(expression){
3529 return document.id(Slick.find(this, injectCombinator(expression, '!')));
3532 getParents: function(expression){
3533 return Slick.search(this, injectCombinator(expression, '!'), new Elements);
3536 getSiblings: function(expression){
3537 return Slick.search(this, injectCombinator(expression, '~~'), new Elements);
3540 getChildren: function(expression){
3541 return Slick.search(this, injectCombinator(expression, '>'), new Elements);
3544 getWindow: function(){
3545 return this.ownerDocument.window;
3548 getDocument: function(){
3549 return this.ownerDocument;
3552 getElementById: function(id){
3553 return document.id(Slick.find(this, '#' + ('' + id).replace(/(\W)/g, '\\$1')));
3556 getSelected: function(){
3557 this.selectedIndex; // Safari 3.2.1
3558 return new Elements(Array.from(this.options).filter(function(option){
3559 return option.selected;
3563 toQueryString: function(){
3564 var queryString = [];
3565 this.getElements('input, select, textarea').each(function(el){
3567 if (!el.name || el.disabled || type == 'submit' || type == 'reset' || type == 'file' || type == 'image') return;
3569 var value = (el.get('tag') == 'select') ? el.getSelected().map(function(opt){
3571 return document.id(opt).get('value');
3572 }) : ((type == 'radio' || type == 'checkbox') && !el.checked) ? null : el.get('value');
3574 Array.from(value).each(function(val){
3575 if (typeof val != 'undefined') queryString.push(encodeURIComponent(el.name) + '=' + encodeURIComponent(val));
3578 return queryString.join('&');
3581 clone: function(contents, keepid){
3582 contents = contents !== false;
3583 var clone = this.cloneNode(contents);
3584 var clean = function(node, element){
3585 if (!keepid) node.removeAttribute('id');
3587 node.clearAttributes();
3588 node.mergeAttributes(element);
3589 node.removeAttribute('uid');
3591 var no = node.options, eo = element.options;
3592 for (var j = no.length; j--;) no[j].selected = eo[j].selected;
3595 var prop = props[element.tagName.toLowerCase()];
3596 if (prop && element[prop]) node[prop] = element[prop];
3601 var ce = clone.getElementsByTagName('*'), te = this.getElementsByTagName('*');
3602 for (i = ce.length; i--;) clean(ce[i], te[i]);
3607 var ts = this.getElementsByTagName('object'),
3608 cs = clone.getElementsByTagName('object'),
3609 tl = ts.length, cl = cs.length;
3610 for (i = 0; i < tl && i < cl; i++)
3611 cs[i].outerHTML = ts[i].outerHTML;
3613 return document.id(clone);
3616 destroy: function(){
3617 var children = clean(this).getElementsByTagName('*');
3618 Array.each(children, clean);
3619 Element.dispose(this);
3624 Array.from(this.childNodes).each(Element.dispose);
3628 dispose: function(){
3629 return (this.parentNode) ? this.parentNode.removeChild(this) : this;
3632 match: function(expression){
3633 return !expression || Slick.match(this, expression);
3638 var contains = {contains: function(element){
3639 return Slick.contains(this, element);
3642 if (!document.contains) Document.implement(contains);
3643 if (!document.createElement('div').contains) Element.implement(contains);
3647 Element.implement('hasChild', function(element){
3648 return this !== element && this.contains(element);
3653 [Element, Window, Document].invoke('implement', {
3655 addListener: function(type, fn){
3656 if (type == 'unload'){
3657 var old = fn, self = this;
3659 self.removeListener('unload', fn);
3663 collected[this.uid] = this;
3665 if (this.addEventListener) this.addEventListener(type, fn, false);
3666 else this.attachEvent('on' + type, fn);
3670 removeListener: function(type, fn){
3671 if (this.removeEventListener) this.removeEventListener(type, fn, false);
3672 else this.detachEvent('on' + type, fn);
3676 retrieve: function(property, dflt){
3677 var storage = get(this.uid), prop = storage[property];
3678 if (dflt != null && prop == null) prop = storage[property] = dflt;
3679 return prop != null ? prop : null;
3682 store: function(property, value){
3683 var storage = get(this.uid);
3684 storage[property] = value;
3688 eliminate: function(property){
3689 var storage = get(this.uid);
3690 delete storage[property];
3697 if (window.attachEvent && !window.addEventListener) window.addListener('unload', function(){
3698 Object.each(collected, clean);
3699 if (window.CollectGarbage) CollectGarbage();
3704 Element.Properties = {};
3708 Element.Properties = new Hash;
3712 Element.Properties.style = {
3714 set: function(style){
3715 this.style.cssText = style;
3719 return this.style.cssText;
3723 this.style.cssText = '';
3728 Element.Properties.tag = {
3731 return this.tagName.toLowerCase();
3736 (function(maxLength){
3737 if (maxLength != null) Element.Properties.maxlength = Element.Properties.maxLength = {
3739 var maxlength = this.getAttribute('maxLength');
3740 return maxlength == maxLength ? null : maxlength;
3743 })(document.createElement('input').getAttribute('maxLength'));
3745 Element.Properties.html = (function(){
3747 var tableTest = Function.attempt(function(){
3748 var table = document.createElement('table');
3749 table.innerHTML = '<tr><td></td></tr>';
3752 var wrapper = document.createElement('div');
3754 var translations = {
3755 table: [1, '<table>', '</table>'],
3756 select: [1, '<select>', '</select>'],
3757 tbody: [2, '<table><tbody>', '</tbody></table>'],
3758 tr: [3, '<table><tbody><tr>', '</tr></tbody></table>']
3760 translations.thead = translations.tfoot = translations.tbody;
3764 var html = Array.flatten(arguments).join('');
3765 var wrap = (!tableTest && translations[this.get('tag')]);
3767 var first = wrapper;
3768 first.innerHTML = wrap[1] + html + wrap[2];
3769 for (var i = wrap[0]; i--;) first = first.firstChild;
3770 this.empty().adopt(first.childNodes);
3772 this.innerHTML = html;
3777 html.erase = html.set;
3788 description: Contains Element methods for dealing with events. This file also includes mouseenter and mouseleave custom Element Events.
3790 license: MIT-style license.
3792 requires: [Element, Event]
3794 provides: Element.Event
3801 Element.Properties.events = {set: function(events){
3802 this.addEvents(events);
3805 [Element, Window, Document].invoke('implement', {
3807 addEvent: function(type, fn){
3808 var events = this.retrieve('events', {});
3809 if (!events[type]) events[type] = {keys: [], values: []};
3810 if (events[type].keys.contains(fn)) return this;
3811 events[type].keys.push(fn);
3812 var realType = type,
3813 custom = Element.Events[type],
3817 if (custom.onAdd) custom.onAdd.call(this, fn);
3818 if (custom.condition){
3819 condition = function(event){
3820 if (custom.condition.call(this, event)) return fn.call(this, event);
3824 realType = custom.base || realType;
3826 var defn = function(){
3827 return fn.call(self);
3829 var nativeEvent = Element.NativeEvents[realType];
3831 if (nativeEvent == 2){
3832 defn = function(event){
3833 event = new Event(event, self.getWindow());
3834 if (condition.call(self, event) === false) event.stop();
3837 this.addListener(realType, defn);
3839 events[type].values.push(defn);
3843 removeEvent: function(type, fn){
3844 var events = this.retrieve('events');
3845 if (!events || !events[type]) return this;
3846 var list = events[type];
3847 var index = list.keys.indexOf(fn);
3848 if (index == -1) return this;
3849 var value = list.values[index];
3850 delete list.keys[index];
3851 delete list.values[index];
3852 var custom = Element.Events[type];
3854 if (custom.onRemove) custom.onRemove.call(this, fn);
3855 type = custom.base || type;
3857 return (Element.NativeEvents[type]) ? this.removeListener(type, value) : this;
3860 addEvents: function(events){
3861 for (var event in events) this.addEvent(event, events[event]);
3865 removeEvents: function(events){
3867 if (typeOf(events) == 'object'){
3868 for (type in events) this.removeEvent(type, events[type]);
3871 var attached = this.retrieve('events');
3872 if (!attached) return this;
3874 for (type in attached) this.removeEvents(type);
3875 this.eliminate('events');
3876 } else if (attached[events]){
3877 attached[events].keys.each(function(fn){
3878 this.removeEvent(events, fn);
3880 delete attached[events];
3885 fireEvent: function(type, args, delay){
3886 var events = this.retrieve('events');
3887 if (!events || !events[type]) return this;
3888 args = Array.from(args);
3890 events[type].keys.each(function(fn){
3891 if (delay) fn.delay(delay, this, args);
3892 else fn.apply(this, args);
3897 cloneEvents: function(from, type){
3898 from = document.id(from);
3899 var events = from.retrieve('events');
3900 if (!events) return this;
3902 for (var eventType in events) this.cloneEvents(from, eventType);
3903 } else if (events[type]){
3904 events[type].keys.each(function(fn){
3905 this.addEvent(type, fn);