6 description: The heart of MooTools.
8 license: MIT-style license.
10 copyright: Copyright (c) 2006-2014 [Valerio Proietti](http://mad4milk.net/).
12 authors: The MooTools production team (http://mootools.net/developers/)
15 - 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)
16 - Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php)
18 provides: [Core, MooTools, Type, typeOf, instanceOf, Native]
32 var typeOf = this.typeOf = function(item){
33 if (item == null) return 'null';
34 if (item.$family != null) return item.$family();
37 if (item.nodeType == 1) return 'element';
38 if (item.nodeType == 3) return (/\S/).test(item.nodeValue) ? 'textnode' : 'whitespace';
39 } else if (typeof item.length == 'number'){
40 if ('callee' in item) return 'arguments';
41 if ('item' in item) return 'collection';
47 var instanceOf = this.instanceOf = function(item, object){
48 if (item == null) return false;
49 var constructor = item.$constructor || item.constructor;
51 if (constructor === object) return true;
52 constructor = constructor.parent;
55 if (!item.hasOwnProperty) return false;
57 return item instanceof object;
60 // Function overloading
62 var Function = this.Function;
64 var enumerables = true;
65 for (var i in {toString: 1}) enumerables = null;
66 if (enumerables) enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor'];
68 Function.prototype.overloadSetter = function(usePlural){
70 return function(a, b){
71 if (a == null) return this;
72 if (usePlural || typeof a != 'string'){
73 for (var k in a) self.call(this, k, a[k]);
74 if (enumerables) for (var i = enumerables.length; i--;){
76 if (a.hasOwnProperty(k)) self.call(this, k, a[k]);
79 self.call(this, a, b);
85 Function.prototype.overloadGetter = function(usePlural){
89 if (typeof a != 'string') args = a;
90 else if (arguments.length > 1) args = arguments;
91 else if (usePlural) args = [a];
94 for (var i = 0; i < args.length; i++) result[args[i]] = self.call(this, args[i]);
96 result = self.call(this, a);
102 Function.prototype.extend = function(key, value){
106 Function.prototype.implement = function(key, value){
107 this.prototype[key] = value;
112 var slice = Array.prototype.slice;
114 Function.from = function(item){
115 return (typeOf(item) == 'function') ? item : function(){
120 Array.from = function(item){
121 if (item == null) return [];
122 return (Type.isEnumerable(item) && typeof item != 'string') ? (typeOf(item) == 'array') ? item : slice.call(item) : [item];
125 Number.from = function(item){
126 var number = parseFloat(item);
127 return isFinite(number) ? number : null;
130 String.from = function(item){
144 this.$protected = true;
152 var Type = this.Type = function(name, object){
154 var lower = name.toLowerCase();
155 var typeCheck = function(item){
156 return (typeOf(item) == lower);
159 Type['is' + name] = typeCheck;
161 object.prototype.$family = (function(){
168 if (object == null) return null;
171 object.$constructor = Type;
172 object.prototype.$constructor = object;
177 var toString = Object.prototype.toString;
179 Type.isEnumerable = function(item){
180 return (item != null && typeof item.length == 'number' && toString.call(item) != '[object Function]' );
185 var hooksOf = function(object){
186 var type = typeOf(object.prototype);
187 return hooks[type] || (hooks[type] = []);
190 var implement = function(name, method){
191 if (method && method.$hidden) return;
193 var hooks = hooksOf(this);
195 for (var i = 0; i < hooks.length; i++){
197 if (typeOf(hook) == 'type') implement.call(hook, name, method);
198 else hook.call(this, name, method);
201 var previous = this.prototype[name];
202 if (previous == null || !previous.$protected) this.prototype[name] = method;
204 if (this[name] == null && typeOf(method) == 'function') extend.call(this, name, function(item){
205 return method.apply(item, slice.call(arguments, 1));
209 var extend = function(name, method){
210 if (method && method.$hidden) return;
211 var previous = this[name];
212 if (previous == null || !previous.$protected) this[name] = method;
217 implement: implement.overloadSetter(),
219 extend: extend.overloadSetter(),
221 alias: function(name, existing){
222 implement.call(this, name, this.prototype[existing]);
225 mirror: function(hook){
226 hooksOf(this).push(hook);
232 new Type('Type', Type);
236 var force = function(name, object, methods){
237 var isType = (object != Object),
238 prototype = object.prototype;
240 if (isType) object = new Type(name, object);
242 for (var i = 0, l = methods.length; i < l; i++){
243 var key = methods[i],
244 generic = object[key],
245 proto = prototype[key];
247 if (generic) generic.protect();
248 if (isType && proto) object.implement(key, proto.protect());
252 var methodsEnumerable = prototype.propertyIsEnumerable(methods[0]);
253 object.forEachMethod = function(fn){
254 if (!methodsEnumerable) for (var i = 0, l = methods.length; i < l; i++){
255 fn.call(prototype, prototype[methods[i]], methods[i]);
257 for (var key in prototype) fn.call(prototype, prototype[key], key);
264 force('String', String, [
265 'charAt', 'charCodeAt', 'concat', 'contains', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search',
266 'slice', 'split', 'substr', 'substring', 'trim', 'toLowerCase', 'toUpperCase'
268 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice',
269 'indexOf', 'lastIndexOf', 'filter', 'forEach', 'every', 'map', 'some', 'reduce', 'reduceRight'
270 ])('Number', Number, [
271 'toExponential', 'toFixed', 'toLocaleString', 'toPrecision'
272 ])('Function', Function, [
273 'apply', 'call', 'bind'
274 ])('RegExp', RegExp, [
276 ])('Object', Object, [
277 'create', 'defineProperty', 'defineProperties', 'keys',
278 'getPrototypeOf', 'getOwnPropertyDescriptor', 'getOwnPropertyNames',
279 'preventExtensions', 'isExtensible', 'seal', 'isSealed', 'freeze', 'isFrozen'
280 ])('Date', Date, ['now']);
282 Object.extend = extend.overloadSetter();
284 Date.extend('now', function(){
288 new Type('Boolean', Boolean);
290 // fixes NaN returning as Number
292 Number.prototype.$family = function(){
293 return isFinite(this) ? 'number' : 'null';
298 Number.extend('random', function(min, max){
299 return Math.floor(Math.random() * (max - min + 1) + min);
304 var hasOwnProperty = Object.prototype.hasOwnProperty;
305 Object.extend('forEach', function(object, fn, bind){
306 for (var key in object){
307 if (hasOwnProperty.call(object, key)) fn.call(bind, object[key], key, object);
311 Object.each = Object.forEach;
316 forEach: function(fn, bind){
317 for (var i = 0, l = this.length; i < l; i++){
318 if (i in this) fn.call(bind, this[i], i, this);
323 each: function(fn, bind){
324 Array.forEach(this, fn, bind);
330 // Array & Object cloning, Object merging and appending
332 var cloneOf = function(item){
333 switch (typeOf(item)){
334 case 'array': return item.clone();
335 case 'object': return Object.clone(item);
336 default: return item;
340 Array.implement('clone', function(){
341 var i = this.length, clone = new Array(i);
342 while (i--) clone[i] = cloneOf(this[i]);
346 var mergeOne = function(source, key, current){
347 switch (typeOf(current)){
349 if (typeOf(source[key]) == 'object') Object.merge(source[key], current);
350 else source[key] = Object.clone(current);
352 case 'array': source[key] = current.clone(); break;
353 default: source[key] = current;
360 merge: function(source, k, v){
361 if (typeOf(k) == 'string') return mergeOne(source, k, v);
362 for (var i = 1, l = arguments.length; i < l; i++){
363 var object = arguments[i];
364 for (var key in object) mergeOne(source, key, object[key]);
369 clone: function(object){
371 for (var key in object) clone[key] = cloneOf(object[key]);
375 append: function(original){
376 for (var i = 1, l = arguments.length; i < l; i++){
377 var extended = arguments[i] || {};
378 for (var key in extended) original[key] = extended[key];
387 ['Object', 'WhiteSpace', 'TextNode', 'Collection', 'Arguments'].each(function(name){
393 var UID = Date.now();
395 String.extend('uniqueID', function(){
396 return (UID++).toString(36);
408 description: Contains Array Prototypes like each, contains, and erase.
410 license: MIT-style license.
422 every: function(fn, bind){
423 for (var i = 0, l = this.length >>> 0; i < l; i++){
424 if ((i in this) && !fn.call(bind, this[i], i, this)) return false;
429 filter: function(fn, bind){
431 for (var value, i = 0, l = this.length >>> 0; i < l; i++) if (i in this){
433 if (fn.call(bind, value, i, this)) results.push(value);
438 indexOf: function(item, from){
439 var length = this.length >>> 0;
440 for (var i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++){
441 if (this[i] === item) return i;
446 map: function(fn, bind){
447 var length = this.length >>> 0, results = Array(length);
448 for (var i = 0; i < length; i++){
449 if (i in this) results[i] = fn.call(bind, this[i], i, this);
454 some: function(fn, bind){
455 for (var i = 0, l = this.length >>> 0; i < l; i++){
456 if ((i in this) && fn.call(bind, this[i], i, this)) return true;
463 return this.filter(function(item){
468 invoke: function(methodName){
469 var args = Array.slice(arguments, 1);
470 return this.map(function(item){
471 return item[methodName].apply(item, args);
475 associate: function(keys){
476 var obj = {}, length = Math.min(this.length, keys.length);
477 for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
481 link: function(object){
483 for (var i = 0, l = this.length; i < l; i++){
484 for (var key in object){
485 if (object[key](this[i])){
486 result[key] = this[i];
495 contains: function(item, from){
496 return this.indexOf(item, from) != -1;
499 append: function(array){
500 this.push.apply(this, array);
505 return (this.length) ? this[this.length - 1] : null;
508 getRandom: function(){
509 return (this.length) ? this[Number.random(0, this.length - 1)] : null;
512 include: function(item){
513 if (!this.contains(item)) this.push(item);
517 combine: function(array){
518 for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
522 erase: function(item){
523 for (var i = this.length; i--;){
524 if (this[i] === item) this.splice(i, 1);
536 for (var i = 0, l = this.length; i < l; i++){
537 var type = typeOf(this[i]);
538 if (type == 'null') continue;
539 array = array.concat((type == 'array' || type == 'collection' || type == 'arguments' || instanceOf(this[i], Array)) ? Array.flatten(this[i]) : this[i]);
545 for (var i = 0, l = this.length; i < l; i++){
546 if (this[i] != null) return this[i];
551 hexToRgb: function(array){
552 if (this.length != 3) return null;
553 var rgb = this.map(function(value){
554 if (value.length == 1) value += value;
555 return parseInt(value, 16);
557 return (array) ? rgb : 'rgb(' + rgb + ')';
560 rgbToHex: function(array){
561 if (this.length < 3) return null;
562 if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
564 for (var i = 0; i < 3; i++){
565 var bit = (this[i] - 0).toString(16);
566 hex.push((bit.length == 1) ? '0' + bit : bit);
568 return (array) ? hex : '#' + hex.join('');
580 description: Contains Function Prototypes like create, bind, pass, and delay.
582 license: MIT-style license.
594 for (var i = 0, l = arguments.length; i < l; i++){
596 return arguments[i]();
606 attempt: function(args, bind){
608 return this.apply(bind, Array.from(args));
615 bind: function(that){
617 args = arguments.length > 1 ? Array.slice(arguments, 1) : null,
620 var bound = function(){
621 var context = that, length = arguments.length;
622 if (this instanceof bound){
623 F.prototype = self.prototype;
626 var result = (!args && !length)
628 : self.apply(context, args && length ? args.concat(Array.slice(arguments)) : args || arguments);
629 return context == that ? result : context;
635 pass: function(args, bind){
637 if (args != null) args = Array.from(args);
639 return self.apply(bind, args || arguments);
643 delay: function(delay, bind, args){
644 return setTimeout(this.pass((args == null ? [] : args), bind), delay);
647 periodical: function(periodical, bind, args){
648 return setInterval(this.pass((args == null ? [] : args), bind), periodical);
660 description: Contains Number Prototypes like limit, round, times, and ceil.
662 license: MIT-style license.
673 limit: function(min, max){
674 return Math.min(max, Math.max(min, this));
677 round: function(precision){
678 precision = Math.pow(10, precision || 0).toFixed(precision < 0 ? -precision : 0);
679 return Math.round(this * precision) / precision;
682 times: function(fn, bind){
683 for (var i = 0; i < this; i++) fn.call(bind, i, this);
687 return parseFloat(this);
690 toInt: function(base){
691 return parseInt(this, base || 10);
696 Number.alias('each', 'times');
700 math.each(function(name){
701 if (!Number[name]) methods[name] = function(){
702 return Math[name].apply(null, [this].concat(Array.from(arguments)));
705 Number.implement(methods);
706 })(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']);
713 description: Contains String Prototypes like camelCase, capitalize, test, and toInt.
715 license: MIT-style license.
717 requires: [Type, Array]
727 contains: function(string, index){
728 return (index ? String(this).slice(index) : String(this)).indexOf(string) > -1;
732 test: function(regex, params){
733 return ((typeOf(regex) == 'regexp') ? regex : new RegExp('' + regex, params)).test(this);
737 return String(this).replace(/^\s+|\s+$/g, '');
741 return String(this).replace(/\s+/g, ' ').trim();
744 camelCase: function(){
745 return String(this).replace(/-\D/g, function(match){
746 return match.charAt(1).toUpperCase();
750 hyphenate: function(){
751 return String(this).replace(/[A-Z]/g, function(match){
752 return ('-' + match.charAt(0).toLowerCase());
756 capitalize: function(){
757 return String(this).replace(/\b[a-z]/g, function(match){
758 return match.toUpperCase();
762 escapeRegExp: function(){
763 return String(this).replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
766 toInt: function(base){
767 return parseInt(this, base || 10);
771 return parseFloat(this);
774 hexToRgb: function(array){
775 var hex = String(this).match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
776 return (hex) ? hex.slice(1).hexToRgb(array) : null;
779 rgbToHex: function(array){
780 var rgb = String(this).match(/\d{1,3}/g);
781 return (rgb) ? rgb.rgbToHex(array) : null;
784 substitute: function(object, regexp){
785 return String(this).replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){
786 if (match.charAt(0) == '\\') return match.slice(1);
787 return (object[name] != null) ? object[name] : '';
800 description: The Browser Object. Contains Browser initialization, Window and Document, and the Browser Hash.
802 license: MIT-style license.
804 requires: [Array, Function, Number, String]
806 provides: [Browser, Window, Document]
813 var document = this.document;
814 var window = document.window = this;
816 var parse = function(ua, platform){
817 ua = ua.toLowerCase();
818 platform = (platform ? platform.toLowerCase() : '');
820 var UA = ua.match(/(opera|ie|firefox|chrome|trident|crios|version)[\s\/:]([\w\d\.]+)?.*?(safari|(?:rv[\s\/:]|version[\s\/:])([\w\d\.]+)|$)/) || [null, 'unknown', 0];
822 if (UA[1] == 'trident'){
824 if (UA[4]) UA[2] = UA[4];
825 } else if (UA[1] == 'crios'){
829 platform = ua.match(/ip(?:ad|od|hone)/) ? 'ios' : (ua.match(/(?:webos|android)/) || platform.match(/mac|win|linux/) || ['other'])[0];
830 if (platform == 'win') platform = 'windows';
833 extend: Function.prototype.extend,
834 name: (UA[1] == 'version') ? UA[3] : UA[1],
835 version: parseFloat((UA[1] == 'opera' && UA[4]) ? UA[4] : UA[2]),
840 var Browser = this.Browser = parse(navigator.userAgent, navigator.platform);
842 if (Browser.name == 'ie'){
843 Browser.version = document.documentMode;
848 xpath: !!(document.evaluate),
849 air: !!(window.runtime),
850 query: !!(document.querySelector),
851 json: !!(window.JSON)
860 Browser.Request = (function(){
862 var XMLHTTP = function(){
863 return new XMLHttpRequest();
866 var MSXML2 = function(){
867 return new ActiveXObject('MSXML2.XMLHTTP');
870 var MSXML = function(){
871 return new ActiveXObject('Microsoft.XMLHTTP');
874 return Function.attempt(function(){
887 Browser.Features.xhr = !!(Browser.Request);
893 Browser.exec = function(text){
894 if (!text) return text;
895 if (window.execScript){
896 window.execScript(text);
898 var script = document.createElement('script');
899 script.setAttribute('type', 'text/javascript');
901 document.head.appendChild(script);
902 document.head.removeChild(script);
907 String.implement('stripScripts', function(exec){
909 var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(all, code){
910 scripts += code + '\n';
913 if (exec === true) Browser.exec(scripts);
914 else if (typeOf(exec) == 'function') exec(scripts, text);
921 Document: this.Document,
923 Element: this.Element,
927 this.Window = this.$constructor = new Type('Window', function(){});
929 this.$family = Function.from('window').hide();
931 Window.mirror(function(name, method){
932 window[name] = method;
935 this.Document = document.$constructor = new Type('Document', function(){});
937 document.$family = Function.from('document').hide();
939 Document.mirror(function(name, method){
940 document[name] = method;
943 document.html = document.documentElement;
944 if (!document.head) document.head = document.getElementsByTagName('head')[0];
946 if (document.execCommand) try {
947 document.execCommand("BackgroundImageCache", false, true);
951 if (this.attachEvent && !this.addEventListener){
952 var unloadEvent = function(){
953 this.detachEvent('onunload', unloadEvent);
954 document.head = document.html = document.window = null;
955 window = this.Window = document = null;
957 this.attachEvent('onunload', unloadEvent);
960 // IE fails on collections and <select>.options (refers to <select>)
961 var arrayFrom = Array.from;
963 arrayFrom(document.html.childNodes);
965 Array.from = function(item){
966 if (typeof item != 'string' && Type.isEnumerable(item) && typeOf(item) != 'array'){
967 var i = item.length, array = new Array(i);
968 while (i--) array[i] = item[i];
971 return arrayFrom(item);
974 var prototype = Array.prototype,
975 slice = prototype.slice;
976 ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice'].each(function(name){
977 var method = prototype[name];
978 Array[name] = function(item){
979 return method.apply(Array.from(item), slice.call(arguments, 1));
994 description: Contains the Class Function for easily creating, extending, and implementing reusable Classes.
996 license: MIT-style license.
998 requires: [Array, String, Function, Number]
1007 var Class = this.Class = new Type('Class', function(params){
1008 if (instanceOf(params, Function)) params = {initialize: params};
1010 var newClass = function(){
1012 if (newClass.$prototyping) return this;
1013 this.$caller = null;
1014 var value = (this.initialize) ? this.initialize.apply(this, arguments) : this;
1015 this.$caller = this.caller = null;
1017 }.extend(this).implement(params);
1019 newClass.$constructor = Class;
1020 newClass.prototype.$constructor = newClass;
1021 newClass.prototype.parent = parent;
1026 var parent = function(){
1027 if (!this.$caller) throw new Error('The method "parent" cannot be called.');
1028 var name = this.$caller.$name,
1029 parent = this.$caller.$owner.parent,
1030 previous = (parent) ? parent.prototype[name] : null;
1031 if (!previous) throw new Error('The method "' + name + '" has no parent.');
1032 return previous.apply(this, arguments);
1035 var reset = function(object){
1036 for (var key in object){
1037 var value = object[key];
1038 switch (typeOf(value)){
1040 var F = function(){};
1041 F.prototype = value;
1042 object[key] = reset(new F);
1044 case 'array': object[key] = value.clone(); break;
1050 var wrap = function(self, key, method){
1051 if (method.$origin) method = method.$origin;
1052 var wrapper = function(){
1053 if (method.$protected && this.$caller == null) throw new Error('The method "' + key + '" cannot be called.');
1054 var caller = this.caller, current = this.$caller;
1055 this.caller = current; this.$caller = wrapper;
1056 var result = method.apply(this, arguments);
1057 this.$caller = current; this.caller = caller;
1059 }.extend({$owner: self, $origin: method, $name: key});
1063 var implement = function(key, value, retain){
1064 if (Class.Mutators.hasOwnProperty(key)){
1065 value = Class.Mutators[key].call(this, value);
1066 if (value == null) return this;
1069 if (typeOf(value) == 'function'){
1070 if (value.$hidden) return this;
1071 this.prototype[key] = (retain) ? value : wrap(this, key, value);
1073 Object.merge(this.prototype, key, value);
1079 var getInstance = function(klass){
1080 klass.$prototyping = true;
1081 var proto = new klass;
1082 delete klass.$prototyping;
1086 Class.implement('implement', implement.overloadSetter());
1090 Extends: function(parent){
1091 this.parent = parent;
1092 this.prototype = getInstance(parent);
1095 Implements: function(items){
1096 Array.from(items).each(function(item){
1097 var instance = new item;
1098 for (var key in instance) implement.call(this, key, instance[key], true);
1110 description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks.
1112 license: MIT-style license.
1116 provides: [Class.Extras, Chain, Events, Options]
1123 this.Chain = new Class({
1128 this.$chain.append(Array.flatten(arguments));
1132 callChain: function(){
1133 return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false;
1136 clearChain: function(){
1137 this.$chain.empty();
1143 var removeOn = function(string){
1144 return string.replace(/^on([A-Z])/, function(full, first){
1145 return first.toLowerCase();
1149 this.Events = new Class({
1153 addEvent: function(type, fn, internal){
1154 type = removeOn(type);
1158 this.$events[type] = (this.$events[type] || []).include(fn);
1159 if (internal) fn.internal = true;
1163 addEvents: function(events){
1164 for (var type in events) this.addEvent(type, events[type]);
1168 fireEvent: function(type, args, delay){
1169 type = removeOn(type);
1170 var events = this.$events[type];
1171 if (!events) return this;
1172 args = Array.from(args);
1173 events.each(function(fn){
1174 if (delay) fn.delay(delay, this, args);
1175 else fn.apply(this, args);
1180 removeEvent: function(type, fn){
1181 type = removeOn(type);
1182 var events = this.$events[type];
1183 if (events && !fn.internal){
1184 var index = events.indexOf(fn);
1185 if (index != -1) delete events[index];
1190 removeEvents: function(events){
1192 if (typeOf(events) == 'object'){
1193 for (type in events) this.removeEvent(type, events[type]);
1196 if (events) events = removeOn(events);
1197 for (type in this.$events){
1198 if (events && events != type) continue;
1199 var fns = this.$events[type];
1200 for (var i = fns.length; i--;) if (i in fns){
1201 this.removeEvent(type, fns[i]);
1209 this.Options = new Class({
1211 setOptions: function(){
1212 var options = this.options = Object.merge.apply(null, [{}, this.options].append(arguments));
1213 if (this.addEvent) for (var option in options){
1214 if (typeOf(options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue;
1215 this.addEvent(option, options[option]);
1216 delete options[option];
1230 description: Object generic methods
1232 license: MIT-style license.
1236 provides: [Object, Hash]
1243 var hasOwnProperty = Object.prototype.hasOwnProperty;
1247 subset: function(object, keys){
1249 for (var i = 0, l = keys.length; i < l; i++){
1251 if (k in object) results[k] = object[k];
1256 map: function(object, fn, bind){
1258 for (var key in object){
1259 if (hasOwnProperty.call(object, key)) results[key] = fn.call(bind, object[key], key, object);
1264 filter: function(object, fn, bind){
1266 for (var key in object){
1267 var value = object[key];
1268 if (hasOwnProperty.call(object, key) && fn.call(bind, value, key, object)) results[key] = value;
1273 every: function(object, fn, bind){
1274 for (var key in object){
1275 if (hasOwnProperty.call(object, key) && !fn.call(bind, object[key], key)) return false;
1280 some: function(object, fn, bind){
1281 for (var key in object){
1282 if (hasOwnProperty.call(object, key) && fn.call(bind, object[key], key)) return true;
1287 keys: function(object){
1289 for (var key in object){
1290 if (hasOwnProperty.call(object, key)) keys.push(key);
1295 values: function(object){
1297 for (var key in object){
1298 if (hasOwnProperty.call(object, key)) values.push(object[key]);
1303 getLength: function(object){
1304 return Object.keys(object).length;
1307 keyOf: function(object, value){
1308 for (var key in object){
1309 if (hasOwnProperty.call(object, key) && object[key] === value) return key;
1314 contains: function(object, value){
1315 return Object.keyOf(object, value) != null;
1318 toQueryString: function(object, base){
1319 var queryString = [];
1321 Object.each(object, function(value, key){
1322 if (base) key = base + '[' + key + ']';
1324 switch (typeOf(value)){
1325 case 'object': result = Object.toQueryString(value, key); break;
1328 value.each(function(val, i){
1331 result = Object.toQueryString(qs, key);
1333 default: result = key + '=' + encodeURIComponent(value);
1335 if (value != null) queryString.push(result);
1338 return queryString.join('&');
1350 description: Standalone CSS3 Selector parser
1351 provides: Slick.Parser
1365 var parse = function(expression, isReversed){
1366 if (expression == null) return null;
1367 if (expression.Slick === true) return expression;
1368 expression = ('' + expression).replace(/^\s+|\s+$/g, '');
1369 reversed = !!isReversed;
1370 var currentCache = (reversed) ? reverseCache : cache;
1371 if (currentCache[expression]) return currentCache[expression];
1376 reverse: function(){
1377 return parse(this.raw, true);
1380 separatorIndex = -1;
1381 while (expression != (expression = expression.replace(regexp, parser)));
1382 parsed.length = parsed.expressions.length;
1383 return currentCache[parsed.raw] = (reversed) ? reverse(parsed) : parsed;
1386 var reverseCombinator = function(combinator){
1387 if (combinator === '!') return ' ';
1388 else if (combinator === ' ') return '!';
1389 else if ((/^!/).test(combinator)) return combinator.replace(/^!/, '');
1390 else return '!' + combinator;
1393 var reverse = function(expression){
1394 var expressions = expression.expressions;
1395 for (var i = 0; i < expressions.length; i++){
1396 var exp = expressions[i];
1397 var last = {parts: [], tag: '*', combinator: reverseCombinator(exp[0].combinator)};
1399 for (var j = 0; j < exp.length; j++){
1401 if (!cexp.reverseCombinator) cexp.reverseCombinator = ' ';
1402 cexp.combinator = cexp.reverseCombinator;
1403 delete cexp.reverseCombinator;
1406 exp.reverse().push(last);
1411 var escapeRegExp = function(string){// Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan <http://stevenlevithan.com/regex/xregexp/> MIT License
1412 return string.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, function(match){
1413 return '\\' + match;
1417 var regexp = new RegExp(
1420 puts "\t\t" + DATA.read.gsub(/\(\?x\)|\s+#.*$|\s+|\\$|\\n/,'')
1423 \\s* ( , ) \\s* # Separator \n\
1424 | \\s* ( <combinator>+ ) \\s* # Combinator \n\
1425 | ( \\s+ ) # CombinatorChildren \n\
1426 | ( <unicode>+ | \\* ) # Tag \n\
1427 | \\# ( <unicode>+ ) # ID \n\
1428 | \\. ( <unicode>+ ) # ClassName \n\
1431 \\s* (<unicode1>+) (?: \
1432 \\s* ([*^$!~|]?=) (?: \
1439 | :+ ( <unicode>+ )(?:\
1441 (?:([\"'])([^\\12]*)\\12)|((?:\\([^)]+\\)|[^()]*)+)\
1446 "^(?:\\s*(,)\\s*|\\s*(<combinator>+)\\s*|(\\s+)|(<unicode>+|\\*)|\\#(<unicode>+)|\\.(<unicode>+)|\\[\\s*(<unicode1>+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|(:+)(<unicode>+)(?:\\((?:(?:([\"'])([^\\13]*)\\13)|((?:\\([^)]+\\)|[^()]*)+))\\))?)"
1447 .replace(/<combinator>/, '[' + escapeRegExp(">+~`!@$%^&={}\\;</") + ']')
1448 .replace(/<unicode>/g, '(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
1449 .replace(/<unicode1>/g, '(?:[:\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
1471 pseudoClassQuotedValue,
1474 if (separator || separatorIndex === -1){
1475 parsed.expressions[++separatorIndex] = [];
1476 combinatorIndex = -1;
1477 if (separator) return '';
1480 if (combinator || combinatorChildren || combinatorIndex === -1){
1481 combinator = combinator || ' ';
1482 var currentSeparator = parsed.expressions[separatorIndex];
1483 if (reversed && currentSeparator[combinatorIndex])
1484 currentSeparator[combinatorIndex].reverseCombinator = reverseCombinator(combinator);
1485 currentSeparator[++combinatorIndex] = {combinator: combinator, tag: '*'};
1488 var currentParsed = parsed.expressions[separatorIndex][combinatorIndex];
1491 currentParsed.tag = tagName.replace(reUnescape, '');
1494 currentParsed.id = id.replace(reUnescape, '');
1496 } else if (className){
1497 className = className.replace(reUnescape, '');
1499 if (!currentParsed.classList) currentParsed.classList = [];
1500 if (!currentParsed.classes) currentParsed.classes = [];
1501 currentParsed.classList.push(className);
1502 currentParsed.classes.push({
1504 regexp: new RegExp('(^|\\s)' + escapeRegExp(className) + '(\\s|$)')
1507 } else if (pseudoClass){
1508 pseudoClassValue = pseudoClassValue || pseudoClassQuotedValue;
1509 pseudoClassValue = pseudoClassValue ? pseudoClassValue.replace(reUnescape, '') : null;
1511 if (!currentParsed.pseudos) currentParsed.pseudos = [];
1512 currentParsed.pseudos.push({
1513 key: pseudoClass.replace(reUnescape, ''),
1514 value: pseudoClassValue,
1515 type: pseudoMarker.length == 1 ? 'class' : 'element'
1518 } else if (attributeKey){
1519 attributeKey = attributeKey.replace(reUnescape, '');
1520 attributeValue = (attributeValue || '').replace(reUnescape, '');
1524 switch (attributeOperator){
1525 case '^=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) ); break;
1526 case '$=' : regexp = new RegExp( escapeRegExp(attributeValue) +'$' ); break;
1527 case '~=' : regexp = new RegExp( '(^|\\s)'+ escapeRegExp(attributeValue) +'(\\s|$)' ); break;
1528 case '|=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) +'(-|$)' ); break;
1529 case '=' : test = function(value){
1530 return attributeValue == value;
1532 case '*=' : test = function(value){
1533 return value && value.indexOf(attributeValue) > -1;
1535 case '!=' : test = function(value){
1536 return attributeValue != value;
1538 default : test = function(value){
1543 if (attributeValue == '' && (/^[*$^]=$/).test(attributeOperator)) test = function(){
1547 if (!test) test = function(value){
1548 return value && regexp.test(value);
1551 if (!currentParsed.attributes) currentParsed.attributes = [];
1552 currentParsed.attributes.push({
1554 operator: attributeOperator,
1555 value: attributeValue,
1566 var Slick = (this.Slick || {});
1568 Slick.parse = function(expression){
1569 return parse(expression);
1572 Slick.escapeRegExp = escapeRegExp;
1574 if (!this.Slick) this.Slick = Slick;
1576 }).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this);
1581 description: The new, superfast css selector engine.
1582 provides: Slick.Finder
1583 requires: Slick.Parser
1591 toString = Object.prototype.toString;
1593 // Feature / Bug detection
1595 local.isNativeCode = function(fn){
1596 return (/\{\s*\[native code\]\s*\}/).test('' + fn);
1599 local.isXML = function(document){
1600 return (!!document.xmlVersion) || (!!document.xml) || (toString.call(document) == '[object XMLDocument]') ||
1601 (document.nodeType == 9 && document.documentElement.nodeName != 'HTML');
1604 local.setDocument = function(document){
1606 // convert elements / window arguments to document. if document cannot be extrapolated, the function returns.
1607 var nodeType = document.nodeType;
1608 if (nodeType == 9); // document
1609 else if (nodeType) document = document.ownerDocument; // node
1610 else if (document.navigator) document = document.document; // window
1613 // check if it's the old document
1615 if (this.document === document) return;
1616 this.document = document;
1618 // check if we have done feature detection on this document before
1620 var root = document.documentElement,
1621 rootUid = this.getUIDXML(root),
1622 features = featuresCache[rootUid],
1626 for (feature in features){
1627 this[feature] = features[feature];
1632 features = featuresCache[rootUid] = {};
1634 features.root = root;
1635 features.isXMLDocument = this.isXML(document);
1637 features.brokenStarGEBTN
1638 = features.starSelectsClosedQSA
1639 = features.idGetsName
1640 = features.brokenMixedCaseQSA
1641 = features.brokenGEBCN
1642 = features.brokenCheckedQSA
1643 = features.brokenEmptyAttributeQSA
1644 = features.isHTMLDocument
1645 = features.nativeMatchesSelector
1648 var starSelectsClosed, starSelectsComments,
1649 brokenSecondClassNameGEBCN, cachedGetElementsByClassName,
1650 brokenFormAttributeGetter;
1652 var selected, id = 'slick_uniqueid';
1653 var testNode = document.createElement('div');
1655 var testRoot = document.body || document.getElementsByTagName('body')[0] || root;
1656 testRoot.appendChild(testNode);
1658 // on non-HTML documents innerHTML and getElementsById doesnt work properly
1660 testNode.innerHTML = '<a id="'+id+'"></a>';
1661 features.isHTMLDocument = !!document.getElementById(id);
1664 if (features.isHTMLDocument){
1666 testNode.style.display = 'none';
1668 // IE returns comment nodes for getElementsByTagName('*') for some documents
1669 testNode.appendChild(document.createComment(''));
1670 starSelectsComments = (testNode.getElementsByTagName('*').length > 1);
1672 // IE returns closed nodes (EG:"</foo>") for getElementsByTagName('*') for some documents
1674 testNode.innerHTML = 'foo</foo>';
1675 selected = testNode.getElementsByTagName('*');
1676 starSelectsClosed = (selected && !!selected.length && selected[0].nodeName.charAt(0) == '/');
1679 features.brokenStarGEBTN = starSelectsComments || starSelectsClosed;
1681 // IE returns elements with the name instead of just id for getElementsById for some documents
1683 testNode.innerHTML = '<a name="'+ id +'"></a><b id="'+ id +'"></b>';
1684 features.idGetsName = document.getElementById(id) === testNode.firstChild;
1687 if (testNode.getElementsByClassName){
1689 // Safari 3.2 getElementsByClassName caches results
1691 testNode.innerHTML = '<a class="f"></a><a class="b"></a>';
1692 testNode.getElementsByClassName('b').length;
1693 testNode.firstChild.className = 'b';
1694 cachedGetElementsByClassName = (testNode.getElementsByClassName('b').length != 2);
1697 // Opera 9.6 getElementsByClassName doesnt detects the class if its not the first one
1699 testNode.innerHTML = '<a class="a"></a><a class="f b a"></a>';
1700 brokenSecondClassNameGEBCN = (testNode.getElementsByClassName('a').length != 2);
1703 features.brokenGEBCN = cachedGetElementsByClassName || brokenSecondClassNameGEBCN;
1706 if (testNode.querySelectorAll){
1707 // IE 8 returns closed nodes (EG:"</foo>") for querySelectorAll('*') for some documents
1709 testNode.innerHTML = 'foo</foo>';
1710 selected = testNode.querySelectorAll('*');
1711 features.starSelectsClosedQSA = (selected && !!selected.length && selected[0].nodeName.charAt(0) == '/');
1714 // Safari 3.2 querySelectorAll doesnt work with mixedcase on quirksmode
1716 testNode.innerHTML = '<a class="MiX"></a>';
1717 features.brokenMixedCaseQSA = !testNode.querySelectorAll('.MiX').length;
1720 // Webkit and Opera dont return selected options on querySelectorAll
1722 testNode.innerHTML = '<select><option selected="selected">a</option></select>';
1723 features.brokenCheckedQSA = (testNode.querySelectorAll(':checked').length == 0);
1726 // IE returns incorrect results for attr[*^$]="" selectors on querySelectorAll
1728 testNode.innerHTML = '<a class=""></a>';
1729 features.brokenEmptyAttributeQSA = (testNode.querySelectorAll('[class*=""]').length != 0);
1734 // IE6-7, if a form has an input of id x, form.getAttribute(x) returns a reference to the input
1736 testNode.innerHTML = '<form action="s"><input id="action"/></form>';
1737 brokenFormAttributeGetter = (testNode.firstChild.getAttribute('action') != 's');
1740 // native matchesSelector function
1742 features.nativeMatchesSelector = root.matches || /*root.msMatchesSelector ||*/ root.mozMatchesSelector || root.webkitMatchesSelector;
1743 if (features.nativeMatchesSelector) try {
1744 // if matchesSelector trows errors on incorrect sintaxes we can use it
1745 features.nativeMatchesSelector.call(root, ':slick');
1746 features.nativeMatchesSelector = null;
1752 root.slick_expando = 1;
1753 delete root.slick_expando;
1754 features.getUID = this.getUIDHTML;
1756 features.getUID = this.getUIDXML;
1759 testRoot.removeChild(testNode);
1760 testNode = selected = testRoot = null;
1764 features.getAttribute = (features.isHTMLDocument && brokenFormAttributeGetter) ? function(node, name){
1765 var method = this.attributeGetters[name];
1766 if (method) return method.call(node);
1767 var attributeNode = node.getAttributeNode(name);
1768 return (attributeNode) ? attributeNode.nodeValue : null;
1769 } : function(node, name){
1770 var method = this.attributeGetters[name];
1771 return (method) ? method.call(node) : node.getAttribute(name);
1776 features.hasAttribute = (root && this.isNativeCode(root.hasAttribute)) ? function(node, attribute){
1777 return node.hasAttribute(attribute);
1778 } : function(node, attribute){
1779 node = node.getAttributeNode(attribute);
1780 return !!(node && (node.specified || node.nodeValue));
1784 // FIXME: Add specs: local.contains should be different for xml and html documents?
1785 var nativeRootContains = root && this.isNativeCode(root.contains),
1786 nativeDocumentContains = document && this.isNativeCode(document.contains);
1788 features.contains = (nativeRootContains && nativeDocumentContains) ? function(context, node){
1789 return context.contains(node);
1790 } : (nativeRootContains && !nativeDocumentContains) ? function(context, node){
1791 // IE8 does not have .contains on document.
1792 return context === node || ((context === document) ? document.documentElement : context).contains(node);
1793 } : (root && root.compareDocumentPosition) ? function(context, node){
1794 return context === node || !!(context.compareDocumentPosition(node) & 16);
1795 } : function(context, node){
1797 if (node === context) return true;
1798 } while ((node = node.parentNode));
1802 // document order sorting
1803 // credits to Sizzle (http://sizzlejs.com/)
1805 features.documentSorter = (root.compareDocumentPosition) ? function(a, b){
1806 if (!a.compareDocumentPosition || !b.compareDocumentPosition) return 0;
1807 return a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
1808 } : ('sourceIndex' in root) ? function(a, b){
1809 if (!a.sourceIndex || !b.sourceIndex) return 0;
1810 return a.sourceIndex - b.sourceIndex;
1811 } : (document.createRange) ? function(a, b){
1812 if (!a.ownerDocument || !b.ownerDocument) return 0;
1813 var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
1814 aRange.setStart(a, 0);
1815 aRange.setEnd(a, 0);
1816 bRange.setStart(b, 0);
1817 bRange.setEnd(b, 0);
1818 return aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
1823 for (feature in features){
1824 this[feature] = features[feature];
1830 var reSimpleSelector = /^([#.]?)((?:[\w-]+|\*))$/,
1831 reEmptyAttribute = /\[.+[*$^]=(?:""|'')?\]/,
1832 qsaFailExpCache = {};
1834 local.search = function(context, expression, append, first){
1836 var found = this.found = (first) ? null : (append || []);
1838 if (!context) return found;
1839 else if (context.navigator) context = context.document; // Convert the node from a window to a document
1840 else if (!context.nodeType) return found;
1845 uniques = this.uniques = {},
1846 hasOthers = !!(append && append.length),
1847 contextIsDocument = (context.nodeType == 9);
1849 if (this.document !== (contextIsDocument ? context : context.ownerDocument)) this.setDocument(context);
1851 // avoid duplicating items already in the append array
1852 if (hasOthers) for (i = found.length; i--;) uniques[this.getUID(found[i])] = true;
1854 // expression checks
1856 if (typeof expression == 'string'){ // expression is a string
1858 /*<simple-selectors-override>*/
1859 var simpleSelector = expression.match(reSimpleSelector);
1860 simpleSelectors: if (simpleSelector){
1862 var symbol = simpleSelector[1],
1863 name = simpleSelector[2],
1868 if (name == '*' && this.brokenStarGEBTN) break simpleSelectors;
1869 nodes = context.getElementsByTagName(name);
1870 if (first) return nodes[0] || null;
1871 for (i = 0; node = nodes[i++];){
1872 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
1875 } else if (symbol == '#'){
1877 if (!this.isHTMLDocument || !contextIsDocument) break simpleSelectors;
1878 node = context.getElementById(name);
1879 if (!node) return found;
1880 if (this.idGetsName && node.getAttributeNode('id').nodeValue != name) break simpleSelectors;
1881 if (first) return node || null;
1882 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
1884 } else if (symbol == '.'){
1886 if (!this.isHTMLDocument || ((!context.getElementsByClassName || this.brokenGEBCN) && context.querySelectorAll)) break simpleSelectors;
1887 if (context.getElementsByClassName && !this.brokenGEBCN){
1888 nodes = context.getElementsByClassName(name);
1889 if (first) return nodes[0] || null;
1890 for (i = 0; node = nodes[i++];){
1891 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
1894 var matchClass = new RegExp('(^|\\s)'+ Slick.escapeRegExp(name) +'(\\s|$)');
1895 nodes = context.getElementsByTagName('*');
1896 for (i = 0; node = nodes[i++];){
1897 className = node.className;
1898 if (!(className && matchClass.test(className))) continue;
1899 if (first) return node;
1900 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
1906 if (hasOthers) this.sort(found);
1907 return (first) ? null : found;
1910 /*</simple-selectors-override>*/
1912 /*<query-selector-override>*/
1913 querySelector: if (context.querySelectorAll){
1915 if (!this.isHTMLDocument
1916 || qsaFailExpCache[expression]
1917 //TODO: only skip when expression is actually mixed case
1918 || this.brokenMixedCaseQSA
1919 || (this.brokenCheckedQSA && expression.indexOf(':checked') > -1)
1920 || (this.brokenEmptyAttributeQSA && reEmptyAttribute.test(expression))
1921 || (!contextIsDocument //Abort when !contextIsDocument and...
1922 // there are multiple expressions in the selector
1923 // since we currently only fix non-document rooted QSA for single expression selectors
1924 && expression.indexOf(',') > -1
1927 ) break querySelector;
1929 var _expression = expression, _context = context;
1930 if (!contextIsDocument){
1931 // non-document rooted QSA
1932 // credits to Andrew Dupont
1933 var currentId = _context.getAttribute('id'), slickid = 'slickid__';
1934 _context.setAttribute('id', slickid);
1935 _expression = '#' + slickid + ' ' + _expression;
1936 context = _context.parentNode;
1940 if (first) return context.querySelector(_expression) || null;
1941 else nodes = context.querySelectorAll(_expression);
1943 qsaFailExpCache[expression] = 1;
1944 break querySelector;
1946 if (!contextIsDocument){
1947 if (currentId) _context.setAttribute('id', currentId);
1948 else _context.removeAttribute('id');
1953 if (this.starSelectsClosedQSA) for (i = 0; node = nodes[i++];){
1954 if (node.nodeName > '@' && !(hasOthers && uniques[this.getUID(node)])) found.push(node);
1955 } else for (i = 0; node = nodes[i++];){
1956 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
1959 if (hasOthers) this.sort(found);
1963 /*</query-selector-override>*/
1965 parsed = this.Slick.parse(expression);
1966 if (!parsed.length) return found;
1967 } else if (expression == null){ // there is no expression
1969 } else if (expression.Slick){ // expression is a parsed Slick object
1970 parsed = expression;
1971 } else if (this.contains(context.documentElement || context, expression)){ // expression is a node
1972 (found) ? found.push(expression) : found = expression;
1974 } else { // other junk
1978 /*<pseudo-selectors>*//*<nth-pseudo-selectors>*/
1980 // cache elements for the nth selectors
1983 this.posNTHLast = {};
1984 this.posNTHType = {};
1985 this.posNTHTypeLast = {};
1987 /*</nth-pseudo-selectors>*//*</pseudo-selectors>*/
1989 // if append is null and there is only a single selector with one expression use pushArray, else use pushUID
1990 this.push = (!hasOthers && (first || (parsed.length == 1 && parsed.expressions[0].length == 1))) ? this.pushArray : this.pushUID;
1992 if (found == null) found = [];
1997 var combinator, tag, id, classList, classes, attributes, pseudos;
1998 var currentItems, currentExpression, currentBit, lastBit, expressions = parsed.expressions;
2000 search: for (i = 0; (currentExpression = expressions[i]); i++) for (j = 0; (currentBit = currentExpression[j]); j++){
2002 combinator = 'combinator:' + currentBit.combinator;
2003 if (!this[combinator]) continue search;
2005 tag = (this.isXMLDocument) ? currentBit.tag : currentBit.tag.toUpperCase();
2007 classList = currentBit.classList;
2008 classes = currentBit.classes;
2009 attributes = currentBit.attributes;
2010 pseudos = currentBit.pseudos;
2011 lastBit = (j === (currentExpression.length - 1));
2013 this.bitUniques = {};
2016 this.uniques = uniques;
2024 this[combinator](context, tag, id, classes, attributes, pseudos, classList);
2025 if (first && lastBit && found.length) break search;
2027 if (first && lastBit) for (m = 0, n = currentItems.length; m < n; m++){
2028 this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList);
2029 if (found.length) break search;
2030 } else for (m = 0, n = currentItems.length; m < n; m++) this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList);
2033 currentItems = this.found;
2036 // should sort if there are nodes in append and if you pass multiple expressions.
2037 if (hasOthers || (parsed.expressions.length > 1)) this.sort(found);
2039 return (first) ? (found[0] || null) : found;
2045 local.uidk = 'slick-uniqueid';
2047 local.getUIDXML = function(node){
2048 var uid = node.getAttribute(this.uidk);
2051 node.setAttribute(this.uidk, uid);
2056 local.getUIDHTML = function(node){
2057 return node.uniqueNumber || (node.uniqueNumber = this.uidx++);
2060 // sort based on the setDocument documentSorter method.
2062 local.sort = function(results){
2063 if (!this.documentSorter) return results;
2064 results.sort(this.documentSorter);
2068 /*<pseudo-selectors>*//*<nth-pseudo-selectors>*/
2070 local.cacheNTH = {};
2072 local.matchNTH = /^([+-]?\d*)?([a-z]+)?([+-]\d+)?$/;
2074 local.parseNTHArgument = function(argument){
2075 var parsed = argument.match(this.matchNTH);
2076 if (!parsed) return false;
2077 var special = parsed[2] || false;
2078 var a = parsed[1] || 1;
2079 if (a == '-') a = -1;
2080 var b = +parsed[3] || 0;
2082 (special == 'n') ? {a: a, b: b} :
2083 (special == 'odd') ? {a: 2, b: 1} :
2084 (special == 'even') ? {a: 2, b: 0} : {a: 0, b: a};
2086 return (this.cacheNTH[argument] = parsed);
2089 local.createNTHPseudo = function(child, sibling, positions, ofType){
2090 return function(node, argument){
2091 var uid = this.getUID(node);
2092 if (!this[positions][uid]){
2093 var parent = node.parentNode;
2094 if (!parent) return false;
2095 var el = parent[child], count = 1;
2097 var nodeName = node.nodeName;
2099 if (el.nodeName != nodeName) continue;
2100 this[positions][this.getUID(el)] = count++;
2101 } while ((el = el[sibling]));
2104 if (el.nodeType != 1) continue;
2105 this[positions][this.getUID(el)] = count++;
2106 } while ((el = el[sibling]));
2109 argument = argument || 'n';
2110 var parsed = this.cacheNTH[argument] || this.parseNTHArgument(argument);
2111 if (!parsed) return false;
2112 var a = parsed.a, b = parsed.b, pos = this[positions][uid];
2113 if (a == 0) return b == pos;
2115 if (pos < b) return false;
2117 if (b < pos) return false;
2119 return ((pos - b) % a) == 0;
2123 /*</nth-pseudo-selectors>*//*</pseudo-selectors>*/
2125 local.pushArray = function(node, tag, id, classes, attributes, pseudos){
2126 if (this.matchSelector(node, tag, id, classes, attributes, pseudos)) this.found.push(node);
2129 local.pushUID = function(node, tag, id, classes, attributes, pseudos){
2130 var uid = this.getUID(node);
2131 if (!this.uniques[uid] && this.matchSelector(node, tag, id, classes, attributes, pseudos)){
2132 this.uniques[uid] = true;
2133 this.found.push(node);
2137 local.matchNode = function(node, selector){
2138 if (this.isHTMLDocument && this.nativeMatchesSelector){
2140 return this.nativeMatchesSelector.call(node, selector.replace(/\[([^=]+)=\s*([^'"\]]+?)\s*\]/g, '[$1="$2"]'));
2141 } catch(matchError){}
2144 var parsed = this.Slick.parse(selector);
2145 if (!parsed) return true;
2147 // simple (single) selectors
2148 var expressions = parsed.expressions, simpleExpCounter = 0, i, currentExpression;
2149 for (i = 0; (currentExpression = expressions[i]); i++){
2150 if (currentExpression.length == 1){
2151 var exp = currentExpression[0];
2152 if (this.matchSelector(node, (this.isXMLDocument) ? exp.tag : exp.tag.toUpperCase(), exp.id, exp.classes, exp.attributes, exp.pseudos)) return true;
2157 if (simpleExpCounter == parsed.length) return false;
2159 var nodes = this.search(this.document, parsed), item;
2160 for (i = 0; item = nodes[i++];){
2161 if (item === node) return true;
2166 local.matchPseudo = function(node, name, argument){
2167 var pseudoName = 'pseudo:' + name;
2168 if (this[pseudoName]) return this[pseudoName](node, argument);
2169 var attribute = this.getAttribute(node, name);
2170 return (argument) ? argument == attribute : !!attribute;
2173 local.matchSelector = function(node, tag, id, classes, attributes, pseudos){
2175 var nodeName = (this.isXMLDocument) ? node.nodeName : node.nodeName.toUpperCase();
2177 if (nodeName < '@') return false; // Fix for comment nodes and closed nodes
2179 if (nodeName != tag) return false;
2183 if (id && node.getAttribute('id') != id) return false;
2186 if (classes) for (i = classes.length; i--;){
2187 cls = this.getAttribute(node, 'class');
2188 if (!(cls && classes[i].regexp.test(cls))) return false;
2190 if (attributes) for (i = attributes.length; i--;){
2191 part = attributes[i];
2192 if (part.operator ? !part.test(this.getAttribute(node, part.key)) : !this.hasAttribute(node, part.key)) return false;
2194 if (pseudos) for (i = pseudos.length; i--;){
2196 if (!this.matchPseudo(node, part.key, part.value)) return false;
2203 ' ': function(node, tag, id, classes, attributes, pseudos, classList){ // all child nodes, any level
2205 var i, item, children;
2207 if (this.isHTMLDocument){
2209 item = this.document.getElementById(id);
2210 if ((!item && node.all) || (this.idGetsName && item && item.getAttributeNode('id').nodeValue != id)){
2211 // all[id] returns all the elements with that name or id inside node
2212 // if theres just one it will return the element, else it will be a collection
2213 children = node.all[id];
2214 if (!children) return;
2215 if (!children[0]) children = [children];
2216 for (i = 0; item = children[i++];){
2217 var idNode = item.getAttributeNode('id');
2218 if (idNode && idNode.nodeValue == id){
2219 this.push(item, tag, null, classes, attributes, pseudos);
2226 // if the context is in the dom we return, else we will try GEBTN, breaking the getById label
2227 if (this.contains(this.root, node)) return;
2229 } else if (this.document !== node && !this.contains(node, item)) return;
2230 this.push(item, tag, null, classes, attributes, pseudos);
2233 getByClass: if (classes && node.getElementsByClassName && !this.brokenGEBCN){
2234 children = node.getElementsByClassName(classList.join(' '));
2235 if (!(children && children.length)) break getByClass;
2236 for (i = 0; item = children[i++];) this.push(item, tag, id, null, attributes, pseudos);
2241 children = node.getElementsByTagName(tag);
2242 if (!(children && children.length)) break getByTag;
2243 if (!this.brokenStarGEBTN) tag = null;
2244 for (i = 0; item = children[i++];) this.push(item, tag, id, classes, attributes, pseudos);
2248 '>': function(node, tag, id, classes, attributes, pseudos){ // direct children
2249 if ((node = node.firstChild)) do {
2250 if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos);
2251 } while ((node = node.nextSibling));
2254 '+': function(node, tag, id, classes, attributes, pseudos){ // next sibling
2255 while ((node = node.nextSibling)) if (node.nodeType == 1){
2256 this.push(node, tag, id, classes, attributes, pseudos);
2261 '^': function(node, tag, id, classes, attributes, pseudos){ // first child
2262 node = node.firstChild;
2264 if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos);
2265 else this['combinator:+'](node, tag, id, classes, attributes, pseudos);
2269 '~': function(node, tag, id, classes, attributes, pseudos){ // next siblings
2270 while ((node = node.nextSibling)){
2271 if (node.nodeType != 1) continue;
2272 var uid = this.getUID(node);
2273 if (this.bitUniques[uid]) break;
2274 this.bitUniques[uid] = true;
2275 this.push(node, tag, id, classes, attributes, pseudos);
2279 '++': function(node, tag, id, classes, attributes, pseudos){ // next sibling and previous sibling
2280 this['combinator:+'](node, tag, id, classes, attributes, pseudos);
2281 this['combinator:!+'](node, tag, id, classes, attributes, pseudos);
2284 '~~': function(node, tag, id, classes, attributes, pseudos){ // next siblings and previous siblings
2285 this['combinator:~'](node, tag, id, classes, attributes, pseudos);
2286 this['combinator:!~'](node, tag, id, classes, attributes, pseudos);
2289 '!': function(node, tag, id, classes, attributes, pseudos){ // all parent nodes up to document
2290 while ((node = node.parentNode)) if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos);
2293 '!>': function(node, tag, id, classes, attributes, pseudos){ // direct parent (one level)
2294 node = node.parentNode;
2295 if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos);
2298 '!+': function(node, tag, id, classes, attributes, pseudos){ // previous sibling
2299 while ((node = node.previousSibling)) if (node.nodeType == 1){
2300 this.push(node, tag, id, classes, attributes, pseudos);
2305 '!^': function(node, tag, id, classes, attributes, pseudos){ // last child
2306 node = node.lastChild;
2308 if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos);
2309 else this['combinator:!+'](node, tag, id, classes, attributes, pseudos);
2313 '!~': function(node, tag, id, classes, attributes, pseudos){ // previous siblings
2314 while ((node = node.previousSibling)){
2315 if (node.nodeType != 1) continue;
2316 var uid = this.getUID(node);
2317 if (this.bitUniques[uid]) break;
2318 this.bitUniques[uid] = true;
2319 this.push(node, tag, id, classes, attributes, pseudos);
2325 for (var c in combinators) local['combinator:' + c] = combinators[c];
2329 /*<pseudo-selectors>*/
2331 'empty': function(node){
2332 var child = node.firstChild;
2333 return !(child && child.nodeType == 1) && !(node.innerText || node.textContent || '').length;
2336 'not': function(node, expression){
2337 return !this.matchNode(node, expression);
2340 'contains': function(node, text){
2341 return (node.innerText || node.textContent || '').indexOf(text) > -1;
2344 'first-child': function(node){
2345 while ((node = node.previousSibling)) if (node.nodeType == 1) return false;
2349 'last-child': function(node){
2350 while ((node = node.nextSibling)) if (node.nodeType == 1) return false;
2354 'only-child': function(node){
2356 while ((prev = prev.previousSibling)) if (prev.nodeType == 1) return false;
2358 while ((next = next.nextSibling)) if (next.nodeType == 1) return false;
2362 /*<nth-pseudo-selectors>*/
2364 'nth-child': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTH'),
2366 'nth-last-child': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHLast'),
2368 'nth-of-type': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTHType', true),
2370 'nth-last-of-type': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHTypeLast', true),
2372 'index': function(node, index){
2373 return this['pseudo:nth-child'](node, '' + (index + 1));
2376 'even': function(node){
2377 return this['pseudo:nth-child'](node, '2n');
2380 'odd': function(node){
2381 return this['pseudo:nth-child'](node, '2n+1');
2384 /*</nth-pseudo-selectors>*/
2386 /*<of-type-pseudo-selectors>*/
2388 'first-of-type': function(node){
2389 var nodeName = node.nodeName;
2390 while ((node = node.previousSibling)) if (node.nodeName == nodeName) return false;
2394 'last-of-type': function(node){
2395 var nodeName = node.nodeName;
2396 while ((node = node.nextSibling)) if (node.nodeName == nodeName) return false;
2400 'only-of-type': function(node){
2401 var prev = node, nodeName = node.nodeName;
2402 while ((prev = prev.previousSibling)) if (prev.nodeName == nodeName) return false;
2404 while ((next = next.nextSibling)) if (next.nodeName == nodeName) return false;
2408 /*</of-type-pseudo-selectors>*/
2412 'enabled': function(node){
2413 return !node.disabled;
2416 'disabled': function(node){
2417 return node.disabled;
2420 'checked': function(node){
2421 return node.checked || node.selected;
2424 'focus': function(node){
2425 return this.isHTMLDocument && this.document.activeElement === node && (node.href || node.type || this.hasAttribute(node, 'tabindex'));
2428 'root': function(node){
2429 return (node === this.root);
2432 'selected': function(node){
2433 return node.selected;
2436 /*</pseudo-selectors>*/
2439 for (var p in pseudos) local['pseudo:' + p] = pseudos[p];
2441 // attributes methods
2443 var attributeGetters = local.attributeGetters = {
2446 return ('htmlFor' in this) ? this.htmlFor : this.getAttribute('for');
2450 return ('href' in this) ? this.getAttribute('href', 2) : this.getAttribute('href');
2453 'style': function(){
2454 return (this.style) ? this.style.cssText : this.getAttribute('style');
2457 'tabindex': function(){
2458 var attributeNode = this.getAttributeNode('tabindex');
2459 return (attributeNode && attributeNode.specified) ? attributeNode.nodeValue : null;
2463 return this.getAttribute('type');
2466 'maxlength': function(){
2467 var attributeNode = this.getAttributeNode('maxLength');
2468 return (attributeNode && attributeNode.specified) ? attributeNode.nodeValue : null;
2473 attributeGetters.MAXLENGTH = attributeGetters.maxLength = attributeGetters.maxlength;
2477 var Slick = local.Slick = (this.Slick || {});
2479 Slick.version = '1.1.7';
2483 Slick.search = function(context, expression, append){
2484 return local.search(context, expression, append);
2487 Slick.find = function(context, expression){
2488 return local.search(context, expression, null, true);
2491 // Slick containment checker
2493 Slick.contains = function(container, node){
2494 local.setDocument(container);
2495 return local.contains(container, node);
2498 // Slick attribute getter
2500 Slick.getAttribute = function(node, name){
2501 local.setDocument(node);
2502 return local.getAttribute(node, name);
2505 Slick.hasAttribute = function(node, name){
2506 local.setDocument(node);
2507 return local.hasAttribute(node, name);
2512 Slick.match = function(node, selector){
2513 if (!(node && selector)) return false;
2514 if (!selector || selector === node) return true;
2515 local.setDocument(node);
2516 return local.matchNode(node, selector);
2519 // Slick attribute accessor
2521 Slick.defineAttributeGetter = function(name, fn){
2522 local.attributeGetters[name] = fn;
2526 Slick.lookupAttributeGetter = function(name){
2527 return local.attributeGetters[name];
2530 // Slick pseudo accessor
2532 Slick.definePseudo = function(name, fn){
2533 local['pseudo:' + name] = function(node, argument){
2534 return fn.call(node, argument);
2539 Slick.lookupPseudo = function(name){
2540 var pseudo = local['pseudo:' + name];
2541 if (pseudo) return function(argument){
2542 return pseudo.call(this, argument);
2547 // Slick overrides accessor
2549 Slick.override = function(regexp, fn){
2550 local.override(regexp, fn);
2554 Slick.isXML = local.isXML;
2556 Slick.uidOf = function(node){
2557 return local.getUIDHTML(node);
2560 if (!this.Slick) this.Slick = Slick;
2562 }).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this);
2569 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.
2571 license: MIT-style license.
2573 requires: [Window, Document, Array, String, Function, Object, Number, Slick.Parser, Slick.Finder]
2575 provides: [Element, Elements, $, $$, IFrame, Selectors]
2580 var Element = this.Element = function(tag, props){
2581 var konstructor = Element.Constructors[tag];
2582 if (konstructor) return konstructor(props);
2583 if (typeof tag != 'string') return document.id(tag).set(props);
2585 if (!props) props = {};
2587 if (!(/^[\w-]+$/).test(tag)){
2588 var parsed = Slick.parse(tag).expressions[0][0];
2589 tag = (parsed.tag == '*') ? 'div' : parsed.tag;
2590 if (parsed.id && props.id == null) props.id = parsed.id;
2592 var attributes = parsed.attributes;
2593 if (attributes) for (var attr, i = 0, l = attributes.length; i < l; i++){
2594 attr = attributes[i];
2595 if (props[attr.key] != null) continue;
2597 if (attr.value != null && attr.operator == '=') props[attr.key] = attr.value;
2598 else if (!attr.value && !attr.operator) props[attr.key] = true;
2601 if (parsed.classList && props['class'] == null) props['class'] = parsed.classList.join(' ');
2604 return document.newElement(tag, props);
2608 if (Browser.Element){
2609 Element.prototype = Browser.Element.prototype;
2610 // IE8 and IE9 require the wrapping.
2611 Element.prototype._fireEvent = (function(fireEvent){
2612 return function(type, event){
2613 return fireEvent.call(this, type, event);
2615 })(Element.prototype.fireEvent);
2618 new Type('Element', Element).mirror(function(name){
2619 if (Array.prototype[name]) return;
2622 obj[name] = function(){
2623 var results = [], args = arguments, elements = true;
2624 for (var i = 0, l = this.length; i < l; i++){
2625 var element = this[i], result = results[i] = element[name].apply(element, args);
2626 elements = (elements && typeOf(result) == 'element');
2628 return (elements) ? new Elements(results) : results;
2631 Elements.implement(obj);
2634 if (!Browser.Element){
2635 Element.parent = Object;
2637 Element.Prototype = {
2638 '$constructor': Element,
2639 '$family': Function.from('element').hide()
2642 Element.mirror(function(name, method){
2643 Element.Prototype[name] = method;
2647 Element.Constructors = {};
2651 var IFrame = new Type('IFrame', function(){
2652 var params = Array.link(arguments, {
2653 properties: Type.isObject,
2654 iframe: function(obj){
2655 return (obj != null);
2659 var props = params.properties || {}, iframe;
2660 if (params.iframe) iframe = document.id(params.iframe);
2661 var onload = props.onload || function(){};
2662 delete props.onload;
2663 props.id = props.name = [props.id, props.name, iframe ? (iframe.id || iframe.name) : 'IFrame_' + String.uniqueID()].pick();
2664 iframe = new Element(iframe || 'iframe', props);
2666 var onLoad = function(){
2667 onload.call(iframe.contentWindow);
2670 if (window.frames[props.id]) onLoad();
2671 else iframe.addListener('load', onLoad);
2675 var Elements = this.Elements = function(nodes){
2676 if (nodes && nodes.length){
2677 var uniques = {}, node;
2678 for (var i = 0; node = nodes[i++];){
2679 var uid = Slick.uidOf(node);
2681 uniques[uid] = true;
2688 Elements.prototype = {length: 0};
2689 Elements.parent = Array;
2691 new Type('Elements', Elements).implement({
2693 filter: function(filter, bind){
2694 if (!filter) return this;
2695 return new Elements(Array.filter(this, (typeOf(filter) == 'string') ? function(item){
2696 return item.match(filter);
2701 var length = this.length;
2702 for (var i = 0, l = arguments.length; i < l; i++){
2703 var item = document.id(arguments[i]);
2704 if (item) this[length++] = item;
2706 return (this.length = length);
2709 unshift: function(){
2711 for (var i = 0, l = arguments.length; i < l; i++){
2712 var item = document.id(arguments[i]);
2713 if (item) items.push(item);
2715 return Array.prototype.unshift.apply(this, items);
2719 var newElements = new Elements(this);
2720 for (var i = 0, l = arguments.length; i < l; i++){
2721 var item = arguments[i];
2722 if (Type.isEnumerable(item)) newElements.append(item);
2723 else newElements.push(item);
2728 append: function(collection){
2729 for (var i = 0, l = collection.length; i < l; i++) this.push(collection[i]);
2734 while (this.length) delete this[--this.length];
2745 var splice = Array.prototype.splice, object = {'0': 0, '1': 1, length: 2};
2747 splice.call(object, 1, 1);
2748 if (object[1] == 1) Elements.implement('splice', function(){
2749 var length = this.length;
2750 var result = splice.apply(this, arguments);
2751 while (length >= this.length) delete this[length--];
2755 Array.forEachMethod(function(method, name){
2756 Elements.implement(name, method);
2759 Array.mirror(Elements);
2762 var createElementAcceptsHTML;
2764 createElementAcceptsHTML = (document.createElement('<input name=x>').name == 'x');
2767 var escapeQuotes = function(html){
2768 return ('' + html).replace(/&/g, '&').replace(/"/g, '"');
2773 // #2479 - IE8 Cannot set HTML of style element
2774 var canChangeStyleHTML = (function(){
2775 var div = document.createElement('style'),
2778 div.innerHTML = '#justTesing{margin: 0px;}';
2779 flag = !!div.innerHTML;
2785 Document.implement({
2787 newElement: function(tag, props){
2789 if (props.checked != null) props.defaultChecked = props.checked;
2790 if ((props.type == 'checkbox' || props.type == 'radio') && props.value == null) props.value = 'on';
2791 /*<ltIE9>*/ // IE needs the type to be set before changing content of style element
2792 if (!canChangeStyleHTML && tag == 'style'){
2793 var styleElement = document.createElement('style');
2794 styleElement.setAttribute('type', 'text/css');
2795 if (props.type) delete props.type;
2796 return this.id(styleElement).set(props);
2799 /*<ltIE8>*/// Fix for readonly name and type properties in IE < 8
2800 if (createElementAcceptsHTML){
2802 if (props.name) tag += ' name="' + escapeQuotes(props.name) + '"';
2803 if (props.type) tag += ' type="' + escapeQuotes(props.type) + '"';
2810 return this.id(this.createElement(tag)).set(props);
2819 Slick.uidOf(window);
2820 Slick.uidOf(document);
2822 Document.implement({
2824 newTextNode: function(text){
2825 return this.createTextNode(text);
2828 getDocument: function(){
2832 getWindow: function(){
2840 string: function(id, nocash, doc){
2841 id = Slick.find(doc, '#' + id.replace(/(\W)/g, '\\$1'));
2842 return (id) ? types.element(id, nocash) : null;
2845 element: function(el, nocash){
2847 if (!nocash && !el.$family && !(/^(?:object|embed)$/i).test(el.tagName)){
2848 var fireEvent = el.fireEvent;
2849 // wrapping needed in IE7, or else crash
2850 el._fireEvent = function(type, event){
2851 return fireEvent(type, event);
2853 Object.append(el, Element.Prototype);
2858 object: function(obj, nocash, doc){
2859 if (obj.toElement) return types.element(obj.toElement(doc), nocash);
2865 types.textnode = types.whitespace = types.window = types.document = function(zero){
2869 return function(el, nocash, doc){
2870 if (el && el.$family && el.uniqueNumber) return el;
2871 var type = typeOf(el);
2872 return (types[type]) ? types[type](el, nocash, doc || document) : null;
2879 if (window.$ == null) Window.implement('$', function(el, nc){
2880 return document.id(el, nc, this.document);
2885 getDocument: function(){
2886 return this.document;
2889 getWindow: function(){
2895 [Document, Element].invoke('implement', {
2897 getElements: function(expression){
2898 return Slick.search(this, expression, new Elements);
2901 getElement: function(expression){
2902 return document.id(Slick.find(this, expression));
2907 var contains = {contains: function(element){
2908 return Slick.contains(this, element);
2911 if (!document.contains) Document.implement(contains);
2912 if (!document.createElement('div').contains) Element.implement(contains);
2918 var injectCombinator = function(expression, combinator){
2919 if (!expression) return combinator;
2921 expression = Object.clone(Slick.parse(expression));
2923 var expressions = expression.expressions;
2924 for (var i = expressions.length; i--;)
2925 expressions[i][0].combinator = combinator;
2934 }, function(combinator, method){
2935 Element.implement(method, function(expression){
2936 return this.getElement(injectCombinator(expression, combinator));
2942 getAllPrevious: '!~',
2946 }, function(combinator, method){
2947 Element.implement(method, function(expression){
2948 return this.getElements(injectCombinator(expression, combinator));
2954 getFirst: function(expression){
2955 return document.id(Slick.search(this, injectCombinator(expression, '>'))[0]);
2958 getLast: function(expression){
2959 return document.id(Slick.search(this, injectCombinator(expression, '>')).getLast());
2962 getWindow: function(){
2963 return this.ownerDocument.window;
2966 getDocument: function(){
2967 return this.ownerDocument;
2970 getElementById: function(id){
2971 return document.id(Slick.find(this, '#' + ('' + id).replace(/(\W)/g, '\\$1')));
2974 match: function(expression){
2975 return !expression || Slick.match(this, expression);
2982 if (window.$$ == null) Window.implement('$$', function(selector){
2983 if (arguments.length == 1){
2984 if (typeof selector == 'string') return Slick.search(this.document, selector, new Elements);
2985 else if (Type.isEnumerable(selector)) return new Elements(selector);
2987 return new Elements(arguments);
2994 before: function(context, element){
2995 var parent = element.parentNode;
2996 if (parent) parent.insertBefore(context, element);
2999 after: function(context, element){
3000 var parent = element.parentNode;
3001 if (parent) parent.insertBefore(context, element.nextSibling);
3004 bottom: function(context, element){
3005 element.appendChild(context);
3008 top: function(context, element){
3009 element.insertBefore(context, element.firstChild);
3014 inserters.inside = inserters.bottom;
3018 // getProperty / setProperty
3020 var propertyGetters = {}, propertySetters = {};
3024 var properties = {};
3026 'type', 'value', 'defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan',
3027 'frameBorder', 'rowSpan', 'tabIndex', 'useMap'
3028 ], function(property){
3029 properties[property.toLowerCase()] = property;
3032 properties.html = 'innerHTML';
3033 properties.text = (document.createElement('div').textContent == null) ? 'innerText': 'textContent';
3035 Object.forEach(properties, function(real, key){
3036 propertySetters[key] = function(node, value){
3039 propertyGetters[key] = function(node){
3045 propertySetters.text = (function(setter){
3046 return function(node, value){
3047 if (node.get('tag') == 'style') node.set('html', value);
3048 else node[properties.text] = value;
3050 })(propertySetters.text);
3052 propertyGetters.text = (function(getter){
3053 return function(node){
3054 return (node.get('tag') == 'style') ? node.innerHTML : getter(node);
3056 })(propertyGetters.text);
3062 'compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked',
3063 'disabled', 'readOnly', 'multiple', 'selected', 'noresize',
3064 'defer', 'defaultChecked', 'autofocus', 'controls', 'autoplay',
3069 Array.forEach(bools, function(bool){
3070 var lower = bool.toLowerCase();
3071 booleans[lower] = bool;
3072 propertySetters[lower] = function(node, value){
3073 node[bool] = !!value;
3075 propertyGetters[lower] = function(node){
3076 return !!node[bool];
3082 Object.append(propertySetters, {
3084 'class': function(node, value){
3085 ('className' in node) ? node.className = (value || '') : node.setAttribute('class', value);
3088 'for': function(node, value){
3089 ('htmlFor' in node) ? node.htmlFor = value : node.setAttribute('for', value);
3092 'style': function(node, value){
3093 (node.style) ? node.style.cssText = value : node.setAttribute('style', value);
3096 'value': function(node, value){
3097 node.value = (value != null) ? value : '';
3102 propertyGetters['class'] = function(node){
3103 return ('className' in node) ? node.className || null : node.getAttribute('class');
3107 var el = document.createElement('button');
3108 // IE sets type as readonly and throws
3109 try { el.type = 'button'; } catch(e){}
3110 if (el.type != 'button') propertySetters.type = function(node, value){
3111 node.setAttribute('type', value);
3119 // #2479 - IE8 Cannot set HTML of style element
3120 var canChangeStyleHTML = (function(){
3121 var div = document.createElement('style'),
3124 div.innerHTML = '#justTesing{margin: 0px;}';
3125 flag = !!div.innerHTML;
3131 var input = document.createElement('input'), volatileInputValue, html5InputSupport;
3135 input.type = 'submit';
3136 volatileInputValue = input.value != 't';
3138 // #2443 - IE throws "Invalid Argument" when trying to use html5 input types
3140 input.type = 'email';
3141 html5InputSupport = input.type == 'email';
3146 if (volatileInputValue || !html5InputSupport) propertySetters.type = function(node, type){
3148 var value = node.value;
3155 /* getProperty, setProperty */
3158 var pollutesGetAttribute = (function(div){
3159 div.random = 'attribute';
3160 return (div.getAttribute('random') == 'attribute');
3161 })(document.createElement('div'));
3163 var hasCloneBug = (function(test){
3164 test.innerHTML = '<object><param name="should_fix" value="the unknown" /></object>';
3165 return test.cloneNode(true).firstChild.childNodes.length != 1;
3166 })(document.createElement('div'));
3169 var hasClassList = !!document.createElement('div').classList;
3171 var classes = function(className){
3172 var classNames = (className || '').clean().split(" "), uniques = {};
3173 return classNames.filter(function(className){
3174 if (className !== "" && !uniques[className]) return uniques[className] = className;
3178 var addToClassList = function(name){
3179 this.classList.add(name);
3182 var removeFromClassList = function(name){
3183 this.classList.remove(name);
3188 setProperty: function(name, value){
3189 var setter = propertySetters[name.toLowerCase()];
3191 setter(this, value);
3194 var attributeWhiteList;
3195 if (pollutesGetAttribute) attributeWhiteList = this.retrieve('$attributeWhiteList', {});
3199 this.removeAttribute(name);
3201 if (pollutesGetAttribute) delete attributeWhiteList[name];
3204 this.setAttribute(name, '' + value);
3206 if (pollutesGetAttribute) attributeWhiteList[name] = true;
3213 setProperties: function(attributes){
3214 for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]);
3218 getProperty: function(name){
3219 var getter = propertyGetters[name.toLowerCase()];
3220 if (getter) return getter(this);
3222 if (pollutesGetAttribute){
3223 var attr = this.getAttributeNode(name), attributeWhiteList = this.retrieve('$attributeWhiteList', {});
3224 if (!attr) return null;
3225 if (attr.expando && !attributeWhiteList[name]){
3226 var outer = this.outerHTML;
3227 // segment by the opening tag and find mention of attribute name
3228 if (outer.substr(0, outer.search(/\/?['"]?>(?![^<]*<['"])/)).indexOf(name) < 0) return null;
3229 attributeWhiteList[name] = true;
3233 var result = Slick.getAttribute(this, name);
3234 return (!result && !Slick.hasAttribute(this, name)) ? null : result;
3237 getProperties: function(){
3238 var args = Array.from(arguments);
3239 return args.map(this.getProperty, this).associate(args);
3242 removeProperty: function(name){
3243 return this.setProperty(name, null);
3246 removeProperties: function(){
3247 Array.each(arguments, this.removeProperty, this);
3251 set: function(prop, value){
3252 var property = Element.Properties[prop];
3253 (property && property.set) ? property.set.call(this, value) : this.setProperty(prop, value);
3256 get: function(prop){
3257 var property = Element.Properties[prop];
3258 return (property && property.get) ? property.get.apply(this) : this.getProperty(prop);
3261 erase: function(prop){
3262 var property = Element.Properties[prop];
3263 (property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop);
3267 hasClass: hasClassList ? function(className){
3268 return this.classList.contains(className);
3269 } : function(className){
3270 return classes(this.className).contains(className);
3273 addClass: hasClassList ? function(className){
3274 classes(className).forEach(addToClassList, this);
3276 } : function(className){
3277 this.className = classes(className + ' ' + this.className).join(' ');
3281 removeClass: hasClassList ? function(className){
3282 classes(className).forEach(removeFromClassList, this);
3284 } : function(className){
3285 var classNames = classes(this.className);
3286 classes(className).forEach(classNames.erase, classNames);
3287 this.className = classNames.join(' ');
3291 toggleClass: function(className, force){
3292 if (force == null) force = !this.hasClass(className);
3293 return (force) ? this.addClass(className) : this.removeClass(className);
3297 var parent = this, fragment, elements = Array.flatten(arguments), length = elements.length;
3298 if (length > 1) parent = fragment = document.createDocumentFragment();
3300 for (var i = 0; i < length; i++){
3301 var element = document.id(elements[i], true);
3302 if (element) parent.appendChild(element);
3305 if (fragment) this.appendChild(fragment);
3310 appendText: function(text, where){
3311 return this.grab(this.getDocument().newTextNode(text), where);
3314 grab: function(el, where){
3315 inserters[where || 'bottom'](document.id(el, true), this);
3319 inject: function(el, where){
3320 inserters[where || 'bottom'](this, document.id(el, true));
3324 replaces: function(el){
3325 el = document.id(el, true);
3326 el.parentNode.replaceChild(this, el);
3330 wraps: function(el, where){
3331 el = document.id(el, true);
3332 return this.replaces(el).grab(el, where);
3335 getSelected: function(){
3336 this.selectedIndex; // Safari 3.2.1
3337 return new Elements(Array.from(this.options).filter(function(option){
3338 return option.selected;
3342 toQueryString: function(){
3343 var queryString = [];
3344 this.getElements('input, select, textarea').each(function(el){
3346 if (!el.name || el.disabled || type == 'submit' || type == 'reset' || type == 'file' || type == 'image') return;
3348 var value = (el.get('tag') == 'select') ? el.getSelected().map(function(opt){
3350 return document.id(opt).get('value');
3351 }) : ((type == 'radio' || type == 'checkbox') && !el.checked) ? null : el.get('value');
3353 Array.from(value).each(function(val){
3354 if (typeof val != 'undefined') queryString.push(encodeURIComponent(el.name) + '=' + encodeURIComponent(val));
3357 return queryString.join('&');
3365 var appendInserters = {
3366 before: 'beforeBegin',
3368 bottom: 'beforeEnd',
3373 Element.implement('appendHTML', ('insertAdjacentHTML' in document.createElement('div')) ? function(html, where){
3374 this.insertAdjacentHTML(appendInserters[where || 'bottom'], html);
3376 } : function(html, where){
3377 var temp = new Element('div', {html: html}),
3378 children = temp.childNodes,
3379 fragment = temp.firstChild;
3381 if (!fragment) return this;
3382 if (children.length > 1){
3383 fragment = document.createDocumentFragment();
3384 for (var i = 0, l = children.length; i < l; i++){
3385 fragment.appendChild(children[i]);
3389 inserters[where || 'bottom'](fragment, this);
3393 var collected = {}, storage = {};
3395 var get = function(uid){
3396 return (storage[uid] || (storage[uid] = {}));
3399 var clean = function(item){
3400 var uid = item.uniqueNumber;
3401 if (item.removeEvents) item.removeEvents();
3402 if (item.clearAttributes) item.clearAttributes();
3404 delete collected[uid];
3405 delete storage[uid];
3410 var formProps = {input: 'checked', option: 'selected', textarea: 'value'};
3414 destroy: function(){
3415 var children = clean(this).getElementsByTagName('*');
3416 Array.each(children, clean);
3417 Element.dispose(this);
3422 Array.from(this.childNodes).each(Element.dispose);
3426 dispose: function(){
3427 return (this.parentNode) ? this.parentNode.removeChild(this) : this;
3430 clone: function(contents, keepid){
3431 contents = contents !== false;
3432 var clone = this.cloneNode(contents), ce = [clone], te = [this], i;
3435 ce.append(Array.from(clone.getElementsByTagName('*')));
3436 te.append(Array.from(this.getElementsByTagName('*')));
3439 for (i = ce.length; i--;){
3440 var node = ce[i], element = te[i];
3441 if (!keepid) node.removeAttribute('id');
3443 if (node.clearAttributes){
3444 node.clearAttributes();
3445 node.mergeAttributes(element);
3446 node.removeAttribute('uniqueNumber');
3448 var no = node.options, eo = element.options;
3449 for (var j = no.length; j--;) no[j].selected = eo[j].selected;
3453 var prop = formProps[element.tagName.toLowerCase()];
3454 if (prop && element[prop]) node[prop] = element[prop];
3459 var co = clone.getElementsByTagName('object'), to = this.getElementsByTagName('object');
3460 for (i = co.length; i--;) co[i].outerHTML = to[i].outerHTML;
3463 return document.id(clone);
3468 [Element, Window, Document].invoke('implement', {
3470 addListener: function(type, fn){
3471 if (window.attachEvent && !window.addEventListener){
3472 collected[Slick.uidOf(this)] = this;
3474 if (this.addEventListener) this.addEventListener(type, fn, !!arguments[2]);
3475 else this.attachEvent('on' + type, fn);
3479 removeListener: function(type, fn){
3480 if (this.removeEventListener) this.removeEventListener(type, fn, !!arguments[2]);
3481 else this.detachEvent('on' + type, fn);
3485 retrieve: function(property, dflt){
3486 var storage = get(Slick.uidOf(this)), prop = storage[property];
3487 if (dflt != null && prop == null) prop = storage[property] = dflt;
3488 return prop != null ? prop : null;
3491 store: function(property, value){
3492 var storage = get(Slick.uidOf(this));
3493 storage[property] = value;
3497 eliminate: function(property){
3498 var storage = get(Slick.uidOf(this));
3499 delete storage[property];
3506 if (window.attachEvent && !window.addEventListener){
3507 var gc = function(){
3508 Object.each(collected, clean);
3509 if (window.CollectGarbage) CollectGarbage();
3510 window.removeListener('unload', gc);
3512 window.addListener('unload', gc);
3516 Element.Properties = {};
3520 Element.Properties.style = {
3522 set: function(style){
3523 this.style.cssText = style;
3527 return this.style.cssText;
3531 this.style.cssText = '';
3536 Element.Properties.tag = {
3539 return this.tagName.toLowerCase();
3544 Element.Properties.html = {
3546 set: function(html){
3547 if (html == null) html = '';
3548 else if (typeOf(html) == 'array') html = html.join('');
3551 if (this.styleSheet && !canChangeStyleHTML) this.styleSheet.cssText = html;
3552 else /*</ltIE9>*/this.innerHTML = html;
3555 this.set('html', '');
3560 var supportsHTML5Elements = true, supportsTableInnerHTML = true, supportsTRInnerHTML = true;
3563 // technique by jdbarlett - http://jdbartlett.com/innershiv/
3564 var div = document.createElement('div');
3565 div.innerHTML = '<nav></nav>';
3566 supportsHTML5Elements = (div.childNodes.length == 1);
3567 if (!supportsHTML5Elements){
3568 var tags = 'abbr article aside audio canvas datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video'.split(' '),
3569 fragment = document.createDocumentFragment(), l = tags.length;
3570 while (l--) fragment.createElement(tags[l]);
3576 supportsTableInnerHTML = Function.attempt(function(){
3577 var table = document.createElement('table');
3578 table.innerHTML = '<tr><td></td></tr>';
3583 var tr = document.createElement('tr'), html = '<td></td>';
3584 tr.innerHTML = html;
3585 supportsTRInnerHTML = (tr.innerHTML == html);
3589 if (!supportsTableInnerHTML || !supportsTRInnerHTML || !supportsHTML5Elements){
3591 Element.Properties.html.set = (function(set){
3593 var translations = {
3594 table: [1, '<table>', '</table>'],
3595 select: [1, '<select>', '</select>'],
3596 tbody: [2, '<table><tbody>', '</tbody></table>'],
3597 tr: [3, '<table><tbody><tr>', '</tr></tbody></table>']
3600 translations.thead = translations.tfoot = translations.tbody;
3602 return function(html){
3605 if (this.styleSheet) return set.call(this, html);
3607 var wrap = translations[this.get('tag')];
3608 if (!wrap && !supportsHTML5Elements) wrap = [0, '', ''];
3609 if (!wrap) return set.call(this, html);
3611 var level = wrap[0], wrapper = document.createElement('div'), target = wrapper;
3612 if (!supportsHTML5Elements) fragment.appendChild(wrapper);
3613 wrapper.innerHTML = [wrap[1], html, wrap[2]].flatten().join('');
3614 while (level--) target = target.firstChild;
3615 this.empty().adopt(target.childNodes);
3616 if (!supportsHTML5Elements) fragment.removeChild(wrapper);
3620 })(Element.Properties.html.set);
3625 var testForm = document.createElement('form');
3626 testForm.innerHTML = '<select><option>s</option></select>';
3628 if (testForm.firstChild.value != 's') Element.Properties.value = {
3630 set: function(value){
3631 var tag = this.get('tag');
3632 if (tag != 'select') return this.setProperty('value', value);
3633 var options = this.getElements('option');
3634 value = String(value);
3635 for (var i = 0; i < options.length; i++){
3636 var option = options[i],
3637 attr = option.getAttributeNode('value'),
3638 optionValue = (attr && attr.specified) ? option.value : option.get('text');
3639 if (optionValue === value) return option.selected = true;
3644 var option = this, tag = option.get('tag');
3646 if (tag != 'select' && tag != 'option') return this.getProperty('value');
3648 if (tag == 'select' && !(option = option.getSelected()[0])) return '';
3650 var attr = option.getAttributeNode('value');
3651 return (attr && attr.specified) ? option.value : option.get('text');
3659 if (document.createElement('div').getAttributeNode('id')) Element.Properties.id = {
3661 this.id = this.getAttributeNode('id').value = id;
3664 return this.id || null;
3667 this.id = this.getAttributeNode('id').value = '';
3679 description: Contains the Event Type, to make the event object cross-browser.
3681 license: MIT-style license.
3683 requires: [Window, Document, Array, Function, String, Object]
3693 var normalizeWheelSpeed = function(event){
3695 if (event.wheelDelta){
3696 normalized = event.wheelDelta % 120 == 0 ? event.wheelDelta / 120 : event.wheelDelta / 12;
3698 var rawAmount = event.deltaY || event.detail || 0;
3699 normalized = -(rawAmount % 3 == 0 ? rawAmount / 3 : rawAmount * 10);
3704 var DOMEvent = this.DOMEvent = new Type('DOMEvent', function(event, win){
3705 if (!win) win = window;
3706 event = event || win.event;
3707 if (event.$extended) return event;
3709 this.$extended = true;
3710 this.shift = event.shiftKey;
3711 this.control = event.ctrlKey;
3712 this.alt = event.altKey;
3713 this.meta = event.metaKey;
3714 var type = this.type = event.type;
3715 var target = event.target || event.srcElement;
3716 while (target && target.nodeType == 3) target = target.parentNode;
3717 this.target = document.id(target);
3719 if (type.indexOf('key') == 0){
3720 var code = this.code = (event.which || event.keyCode);
3721 this.key = _keys[code];
3722 if (type == 'keydown' || type == 'keyup'){
3723 if (code > 111 && code < 124) this.key = 'f' + (code - 111);
3724 else if (code > 95 && code < 106) this.key = code - 96;
3726 if (this.key == null) this.key = String.fromCharCode(code).toLowerCase();
3727 } else if (type == 'click' || type == 'dblclick' || type == 'contextmenu' || type == 'wheel' || type == 'DOMMouseScroll' || type.indexOf('mouse') == 0){
3728 var doc = win.document;
3729 doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
3731 x: (event.pageX != null) ? event.pageX : event.clientX + doc.scrollLeft,
3732 y: (event.pageY != null) ? event.pageY : event.clientY + doc.scrollTop
3735 x: (event.pageX != null) ? event.pageX - win.pageXOffset : event.clientX,
3736 y: (event.pageY != null) ? event.pageY - win.pageYOffset : event.clientY
3738 if (type == 'DOMMouseScroll' || type == 'wheel' || type == 'mousewheel') this.wheel = normalizeWheelSpeed(event);
3739 this.rightClick = (event.which == 3 || event.button == 2);
3740 if (type == 'mouseover' || type == 'mouseout'){
3741 var related = event.relatedTarget || event[(type == 'mouseover' ? 'from' : 'to') + 'Element'];
3742 while (related && related.nodeType == 3) related = related.parentNode;
3743 this.relatedTarget = document.id(related);
3745 } else if (type.indexOf('touch') == 0 || type.indexOf('gesture') == 0){
3746 this.rotation = event.rotation;
3747 this.scale = event.scale;
3748 this.targetTouches = event.targetTouches;
3749 this.changedTouches = event.changedTouches;
3750 var touches = this.touches = event.touches;
3751 if (touches && touches[0]){
3752 var touch = touches[0];
3753 this.page = {x: touch.pageX, y: touch.pageY};
3754 this.client = {x: touch.clientX, y: touch.clientY};
3758 if (!this.client) this.client = {};
3759 if (!this.page) this.page = {};
3762 DOMEvent.implement({
3765 return this.preventDefault().stopPropagation();
3768 stopPropagation: function(){
3769 if (this.event.stopPropagation) this.event.stopPropagation();
3770 else this.event.cancelBubble = true;
3774 preventDefault: function(){
3775 if (this.event.preventDefault) this.event.preventDefault();
3776 else this.event.returnValue = false;
3782 DOMEvent.defineKey = function(code, key){
3787 DOMEvent.defineKeys = DOMEvent.defineKey.overloadSetter(true);
3789 DOMEvent.defineKeys({
3790 '38': 'up', '40': 'down', '37': 'left', '39': 'right',
3791 '27': 'esc', '32': 'space', '8': 'backspace', '9': 'tab',
3792 '46': 'delete', '13': 'enter'
3806 description: Contains Element methods for dealing with events. This file also includes mouseenter and mouseleave custom Element Events, if necessary.
3808 license: MIT-style license.
3810 requires: [Element, Event]
3812 provides: Element.Event
3819 Element.Properties.events = {set: function(events){
3820 this.addEvents(events);
3823 [Element, Window, Document].invoke('implement', {
3825 addEvent: function(type, fn){
3826 var events = this.retrieve('events', {});
3827 if (!events[type]) events[type] = {keys: [], values: []};
3828 if (events[type].keys.contains(fn)) return this;
3829 events[type].keys.push(fn);
3830 var realType = type,
3831 custom = Element.Events[type],
3835 if (custom.onAdd) custom.onAdd.call(this, fn, type);
3836 if (custom.condition){
3837 condition = function(event){
3838 if (custom.condition.call(this, event, type)) return fn.call(this, event);
3842 if (custom.base) realType = Function.from(custom.base).call(this, type);
3844 var defn = function(){
3845 return fn.call(self);
3847 var nativeEvent = Element.NativeEvents[realType];
3849 if (nativeEvent == 2){
3850 defn = function(event){
3851 event = new DOMEvent(event, self.getWindow());
3852 if (condition.call(self, event) === false) event.stop();
3855 this.addListener(realType, defn, arguments[2]);
3857 events[type].values.push(defn);
3861 removeEvent: function(type, fn){
3862 var events = this.retrieve('events');
3863 if (!events || !events[type]) return this;
3864 var list = events[type];
3865 var index = list.keys.indexOf(fn);
3866 if (index == -1) return this;
3867 var value = list.values[index];
3868 delete list.keys[index];
3869 delete list.values[index];
3870 var custom = Element.Events[type];
3872 if (custom.onRemove) custom.onRemove.call(this, fn, type);
3873 if (custom.base) type = Function.from(custom.base).call(this, type);
3875 return (Element.NativeEvents[type]) ? this.removeListener(type, value, arguments[2]) : this;
3878 addEvents: function(events){
3879 for (var event in events) this.addEvent(event, events[event]);
3883 removeEvents: function(events){
3885 if (typeOf(events) == 'object'){
3886 for (type in events) this.removeEvent(type, events[type]);
3889 var attached = this.retrieve('events');
3890 if (!attached) return this;
3892 for (type in attached) this.removeEvents(type);
3893 this.eliminate('events');
3894 } else if (attached[events]){
3895 attached[events].keys.each(function(fn){
3896 this.removeEvent(events, fn);
3898 delete attached[events];
3903 fireEvent: function(type, args, delay){
3904 var events = this.retrieve('events');
3905 if (!events || !events[type]) return this;
3906 args = Array.from(args);
3908 events[type].keys.each(function(fn){
3909 if (delay) fn.delay(delay, this, args);
3910 else fn.apply(this, args);
3915 cloneEvents: function(from, type){
3916 from = document.id(from);
3917 var events = from.retrieve('events');
3918 if (!events) return this;
3920 for (var eventType in events) this.cloneEvents(from, eventType);
3921 } else if (events[type]){
3922 events[type].keys.each(function(fn){
3923 this.addEvent(type, fn);
3931 Element.NativeEvents = {
3932 click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons
3933 wheel: 2, mousewheel: 2, DOMMouseScroll: 2, //mouse wheel
3934 mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement
3935 keydown: 2, keypress: 2, keyup: 2, //keyboard
3936 orientationchange: 2, // mobile
3937 touchstart: 2, touchmove: 2, touchend: 2, touchcancel: 2, // touch
3938 gesturestart: 2, gesturechange: 2, gestureend: 2, // gesture
3939 focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, paste: 2, input: 2, //form elements
3940 load: 2, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window
3941 hashchange: 1, popstate: 2, // history
3942 error: 1, abort: 1, scroll: 1, message: 2 //misc
3947 base: 'onwheel' in document ? 'wheel' : 'onmousewheel' in document ? 'mousewheel' : 'DOMMouseScroll'
3951 var check = function(event){
3952 var related = event.relatedTarget;
3953 if (related == null) return true;
3954 if (!related) return false;
3955 return (related != this && related.prefix != 'xul' && typeOf(this) != 'document' && !this.contains(related));
3958 if ('onmouseenter' in document.documentElement){
3959 Element.NativeEvents.mouseenter = Element.NativeEvents.mouseleave = 2;
3960 Element.MouseenterCheck = check;
3962 Element.Events.mouseenter = {
3967 Element.Events.mouseleave = {
3974 if (!window.addEventListener){
3975 Element.NativeEvents.propertychange = 2;
3976 Element.Events.change = {
3978 var type = this.type;
3979 return (this.get('tag') == 'input' && (type == 'radio' || type == 'checkbox')) ? 'propertychange' : 'change';
3981 condition: function(event){
3982 return event.type != 'propertychange' || event.event.propertyName == 'checked';
3995 name: Element.Delegation
3997 description: Extends the Element native object to include the delegate method for more efficient event management.
3999 license: MIT-style license.
4001 requires: [Element.Event]
4003 provides: [Element.Delegation]
4010 var eventListenerSupport = !!window.addEventListener;
4012 Element.NativeEvents.focusin = Element.NativeEvents.focusout = 2;
4014 var bubbleUp = function(self, match, fn, event, target){
4015 while (target && target != self){
4016 if (match(target, event)) return fn.call(target, event, target);
4017 target = document.id(target.parentNode);
4024 condition: Element.MouseenterCheck
4028 condition: Element.MouseenterCheck
4031 base: 'focus' + (eventListenerSupport ? '' : 'in'),
4035 base: eventListenerSupport ? 'blur' : 'focusout',
4041 var _key = '$delegation:';
4042 var formObserver = function(type){
4048 remove: function(self, uid){
4049 var list = self.retrieve(_key + type + 'listeners', {})[uid];
4050 if (list && list.forms) for (var i = list.forms.length; i--;){
4051 list.forms[i].removeEvent(type, list.fns[i]);
4055 listen: function(self, match, fn, event, target, uid){
4056 var form = (target.get('tag') == 'form') ? target : event.target.getParent('form');
4059 var listeners = self.retrieve(_key + type + 'listeners', {}),
4060 listener = listeners[uid] || {forms: [], fns: []},
4061 forms = listener.forms, fns = listener.fns;
4063 if (forms.indexOf(form) != -1) return;
4066 var _fn = function(event){
4067 bubbleUp(self, match, fn, event, target);
4069 form.addEvent(type, _fn);
4072 listeners[uid] = listener;
4073 self.store(_key + type + 'listeners', listeners);
4078 var inputObserver = function(type){
4081 listen: function(self, match, fn, event, target){
4082 var events = {blur: function(){
4083 this.removeEvents(events);
4085 events[type] = function(event){
4086 bubbleUp(self, match, fn, event, target);
4088 event.target.addEvents(events);
4093 if (!eventListenerSupport) Object.append(map, {
4094 submit: formObserver('submit'),
4095 reset: formObserver('reset'),
4096 change: inputObserver('change'),
4097 select: inputObserver('select')
4101 var proto = Element.prototype,
4102 addEvent = proto.addEvent,
4103 removeEvent = proto.removeEvent;
4105 var relay = function(old, method){
4106 return function(type, fn, useCapture){
4107 if (type.indexOf(':relay') == -1) return old.call(this, type, fn, useCapture);
4108 var parsed = Slick.parse(type).expressions[0][0];
4109 if (parsed.pseudos[0].key != 'relay') return old.call(this, type, fn, useCapture);
4110 var newType = parsed.tag;
4111 parsed.pseudos.slice(1).each(function(pseudo){
4112 newType += ':' + pseudo.key + (pseudo.value ? '(' + pseudo.value + ')' : '');
4114 old.call(this, type, fn);
4115 return method.call(this, newType, parsed.pseudos[0].value, fn);
4121 addEvent: function(type, match, fn){
4122 var storage = this.retrieve('$delegates', {}), stored = storage[type];
4123 if (stored) for (var _uid in stored){
4124 if (stored[_uid].fn == fn && stored[_uid].match == match) return this;
4127 var _type = type, _match = match, _fn = fn, _map = map[type] || {};
4128 type = _map.base || _type;
4130 match = function(target){
4131 return Slick.match(target, _match);
4134 var elementEvent = Element.Events[_type];
4135 if (_map.condition || elementEvent && elementEvent.condition){
4136 var __match = match, condition = _map.condition || elementEvent.condition;
4137 match = function(target, event){
4138 return __match(target, event) && condition.call(target, event, type);
4142 var self = this, uid = String.uniqueID();
4143 var delegator = _map.listen ? function(event, target){
4144 if (!target && event && event.target) target = event.target;
4145 if (target) _map.listen(self, match, fn, event, target, uid);
4146 } : function(event, target){
4147 if (!target && event && event.target) target = event.target;
4148 if (target) bubbleUp(self, match, fn, event, target);
4151 if (!stored) stored = {};
4155 delegator: delegator
4157 storage[_type] = stored;
4158 return addEvent.call(this, type, delegator, _map.capture);
4161 removeEvent: function(type, match, fn, _uid){
4162 var storage = this.retrieve('$delegates', {}), stored = storage[type];
4163 if (!stored) return this;
4166 var _type = type, delegator = stored[_uid].delegator, _map = map[type] || {};
4167 type = _map.base || _type;
4168 if (_map.remove) _map.remove(this, _uid);
4169 delete stored[_uid];
4170 storage[_type] = stored;
4171 return removeEvent.call(this, type, delegator, _map.capture);
4175 if (fn) for (__uid in stored){
4177 if (s.match == match && s.fn == fn) return delegation.removeEvent.call(this, type, match, fn, __uid);
4178 } else for (__uid in stored){
4180 if (s.match == match) delegation.removeEvent.call(this, type, match, s.fn, __uid);
4187 [Element, Window, Document].invoke('implement', {
4188 addEvent: relay(addEvent, delegation.addEvent),
4189 removeEvent: relay(removeEvent, delegation.removeEvent)
4199 description: Contains methods for interacting with the styles of Elements in a fashionable way.
4201 license: MIT-style license.
4205 provides: Element.Style
4212 var html = document.html, el;
4215 // Check for oldIE, which does not remove styles when they're set to null
4216 el = document.createElement('div');
4217 el.style.color = 'red';
4218 el.style.color = null;
4219 var doesNotRemoveStyles = el.style.color == 'red';
4221 // check for oldIE, which returns border* shorthand styles in the wrong order (color-width-style instead of width-style-color)
4222 var border = '1px solid #123abc';
4223 el.style.border = border;
4224 var returnsBordersInWrongOrder = el.style.border != border;
4228 var hasGetComputedStyle = !!window.getComputedStyle,
4229 supportBorderRadius = document.createElement('div').style.borderRadius != null;
4231 Element.Properties.styles = {set: function(styles){
4232 this.setStyles(styles);
4235 var hasOpacity = (html.style.opacity != null),
4236 hasFilter = (html.style.filter != null),
4237 reAlpha = /alpha\(opacity=([\d.]+)\)/i;
4239 var setVisibility = function(element, opacity){
4240 element.store('$opacity', opacity);
4241 element.style.visibility = opacity > 0 || opacity == null ? 'visible' : 'hidden';
4245 var setFilter = function(element, regexp, value){
4246 var style = element.style,
4247 filter = style.filter || element.getComputedStyle('filter') || '';
4248 style.filter = (regexp.test(filter) ? filter.replace(regexp, value) : filter + ' ' + value).trim();
4249 if (!style.filter) style.removeAttribute('filter');
4253 var setOpacity = (hasOpacity ? function(element, opacity){
4254 element.style.opacity = opacity;
4255 } : (hasFilter ? function(element, opacity){
4256 if (!element.currentStyle || !element.currentStyle.hasLayout) element.style.zoom = 1;
4257 if (opacity == null || opacity == 1){
4258 setFilter(element, reAlpha, '');
4259 if (opacity == 1 && getOpacity(element) != 1) setFilter(element, reAlpha, 'alpha(opacity=100)');
4261 setFilter(element, reAlpha, 'alpha(opacity=' + (opacity * 100).limit(0, 100).round() + ')');
4263 } : setVisibility));
4265 var getOpacity = (hasOpacity ? function(element){
4266 var opacity = element.style.opacity || element.getComputedStyle('opacity');
4267 return (opacity == '') ? 1 : opacity.toFloat();
4268 } : (hasFilter ? function(element){
4269 var filter = (element.style.filter || element.getComputedStyle('filter')),
4271 if (filter) opacity = filter.match(reAlpha);
4272 return (opacity == null || filter == null) ? 1 : (opacity[1] / 100);
4273 } : function(element){
4274 var opacity = element.retrieve('$opacity');
4275 if (opacity == null) opacity = (element.style.visibility == 'hidden' ? 0 : 1);
4279 var floatName = (html.style.cssFloat == null) ? 'styleFloat' : 'cssFloat',
4280 namedPositions = {left: '0%', top: '0%', center: '50%', right: '100%', bottom: '100%'},
4281 hasBackgroundPositionXY = (html.style.backgroundPositionX != null);
4284 var removeStyle = function(style, property){
4285 if (property == 'backgroundPosition'){
4286 style.removeAttribute(property + 'X');
4289 style.removeAttribute(property);
4295 getComputedStyle: function(property){
4296 if (!hasGetComputedStyle && this.currentStyle) return this.currentStyle[property.camelCase()];
4297 var defaultView = Element.getDocument(this).defaultView,
4298 computed = defaultView ? defaultView.getComputedStyle(this, null) : null;
4299 return (computed) ? computed.getPropertyValue((property == floatName) ? 'float' : property.hyphenate()) : '';
4302 setStyle: function(property, value){
4303 if (property == 'opacity'){
4304 if (value != null) value = parseFloat(value);
4305 setOpacity(this, value);
4308 property = (property == 'float' ? floatName : property).camelCase();
4309 if (typeOf(value) != 'string'){
4310 var map = (Element.Styles[property] || '@').split(' ');
4311 value = Array.from(value).map(function(val, i){
4312 if (!map[i]) return '';
4313 return (typeOf(val) == 'number') ? map[i].replace('@', Math.round(val)) : val;
4315 } else if (value == String(Number(value))){
4316 value = Math.round(value);
4318 this.style[property] = value;
4320 if ((value == '' || value == null) && doesNotRemoveStyles && this.style.removeAttribute){
4321 removeStyle(this.style, property);
4327 getStyle: function(property){
4328 if (property == 'opacity') return getOpacity(this);
4329 property = (property == 'float' ? floatName : property).camelCase();
4330 if (supportBorderRadius && property.indexOf('borderRadius') != -1){
4331 return ['borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius'].map(function(corner){
4332 return this.style[corner] || '0px';
4335 var result = this.style[property];
4336 if (!result || property == 'zIndex'){
4337 if (Element.ShortStyles.hasOwnProperty(property)){
4339 for (var s in Element.ShortStyles[property]) result.push(this.getStyle(s));
4340 return result.join(' ');
4342 result = this.getComputedStyle(property);
4344 if (hasBackgroundPositionXY && /^backgroundPosition[XY]?$/.test(property)){
4345 return result.replace(/(top|right|bottom|left)/g, function(position){
4346 return namedPositions[position];
4349 if (!result && property == 'backgroundPosition') return '0px 0px';
4351 result = String(result);
4352 var color = result.match(/rgba?\([\d\s,]+\)/);
4353 if (color) result = result.replace(color[0], color[0].rgbToHex());
4355 if (!hasGetComputedStyle && !this.style[property]){
4356 if ((/^(height|width)$/).test(property) && !(/px$/.test(result))){
4357 var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0;
4358 values.each(function(value){
4359 size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt();
4361 return this['offset' + property.capitalize()] - size + 'px';
4363 if ((/^border(.+)Width|margin|padding/).test(property) && isNaN(parseFloat(result))){
4368 if (returnsBordersInWrongOrder && /^border(Top|Right|Bottom|Left)?$/.test(property) && /^#/.test(result)){
4369 return result.replace(/^(.+)\s(.+)\s(.+)$/, '$2 $3 $1');
4376 setStyles: function(styles){
4377 for (var style in styles) this.setStyle(style, styles[style]);
4381 getStyles: function(){
4383 Array.flatten(arguments).each(function(key){
4384 result[key] = this.getStyle(key);
4392 left: '@px', top: '@px', bottom: '@px', right: '@px',
4393 width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px',
4394 backgroundColor: 'rgb(@, @, @)', backgroundSize: '@px', backgroundPosition: '@px @px', color: 'rgb(@, @, @)',
4395 fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)',
4396 margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)',
4397 borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)',
4398 zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@', borderRadius: '@px @px @px @px'
4405 Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}};
4407 ['Top', 'Right', 'Bottom', 'Left'].each(function(direction){
4408 var Short = Element.ShortStyles;
4409 var All = Element.Styles;
4410 ['margin', 'padding'].each(function(style){
4411 var sd = style + direction;
4412 Short[style][sd] = All[sd] = '@px';
4414 var bd = 'border' + direction;
4415 Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)';
4416 var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color';
4418 Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px';
4419 Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@';
4420 Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)';
4423 if (hasBackgroundPositionXY) Element.ShortStyles.backgroundPosition = {backgroundPositionX: '@', backgroundPositionY: '@'};
4429 name: Element.Dimensions
4431 description: Contains methods to work with size, scroll, or positioning of Elements and the window object.
4433 license: MIT-style license.
4436 - Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html).
4437 - Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html).
4439 requires: [Element, Element.Style]
4441 provides: [Element.Dimensions]
4448 var element = document.createElement('div'),
4449 child = document.createElement('div');
4450 element.style.height = '0';
4451 element.appendChild(child);
4452 var brokenOffsetParent = (child.offsetParent === element);
4453 element = child = null;
4455 var heightComponents = ['height', 'paddingTop', 'paddingBottom', 'borderTopWidth', 'borderBottomWidth'],
4456 widthComponents = ['width', 'paddingLeft', 'paddingRight', 'borderLeftWidth', 'borderRightWidth'];
4458 var svgCalculateSize = function(el){
4460 var gCS = window.getComputedStyle(el),
4461 bounds = {x: 0, y: 0};
4463 heightComponents.each(function(css){
4464 bounds.y += parseFloat(gCS[css]);
4466 widthComponents.each(function(css){
4467 bounds.x += parseFloat(gCS[css]);
4472 var isOffset = function(el){
4473 return styleString(el, 'position') != 'static' || isBody(el);
4476 var isOffsetStatic = function(el){
4477 return isOffset(el) || (/^(?:table|td|th)$/i).test(el.tagName);
4482 scrollTo: function(x, y){
4484 this.getWindow().scrollTo(x, y);
4486 this.scrollLeft = x;
4492 getSize: function(){
4493 if (isBody(this)) return this.getWindow().getSize();
4496 // This if clause is because IE8- cannot calculate getBoundingClientRect of elements with visibility hidden.
4497 if (!window.getComputedStyle) return {x: this.offsetWidth, y: this.offsetHeight};
4500 // This svg section under, calling `svgCalculateSize()`, can be removed when FF fixed the svg size bug.
4501 // Bug info: https://bugzilla.mozilla.org/show_bug.cgi?id=530985
4502 if (this.get('tag') == 'svg') return svgCalculateSize(this);
4504 var bounds = this.getBoundingClientRect();
4505 return {x: bounds.width, y: bounds.height};
4508 getScrollSize: function(){
4509 if (isBody(this)) return this.getWindow().getScrollSize();
4510 return {x: this.scrollWidth, y: this.scrollHeight};
4513 getScroll: function(){
4514 if (isBody(this)) return this.getWindow().getScroll();
4515 return {x: this.scrollLeft, y: this.scrollTop};
4518 getScrolls: function(){
4519 var element = this.parentNode, position = {x: 0, y: 0};
4520 while (element && !isBody(element)){
4521 position.x += element.scrollLeft;
4522 position.y += element.scrollTop;
4523 element = element.parentNode;
4528 getOffsetParent: brokenOffsetParent ? function(){
4530 if (isBody(element) || styleString(element, 'position') == 'fixed') return null;
4532 var isOffsetCheck = (styleString(element, 'position') == 'static') ? isOffsetStatic : isOffset;
4533 while ((element = element.parentNode)){
4534 if (isOffsetCheck(element)) return element;
4539 if (isBody(element) || styleString(element, 'position') == 'fixed') return null;
4542 return element.offsetParent;
4547 getOffsets: function(){
4548 var hasGetBoundingClientRect = this.getBoundingClientRect;
4550 if (hasGetBoundingClientRect){
4551 var bound = this.getBoundingClientRect(),
4552 html = document.id(this.getDocument().documentElement),
4553 htmlScroll = html.getScroll(),
4554 elemScrolls = this.getScrolls(),
4555 isFixed = (styleString(this, 'position') == 'fixed');
4558 x: bound.left.toInt() + elemScrolls.x + ((isFixed) ? 0 : htmlScroll.x) - html.clientLeft,
4559 y: bound.top.toInt() + elemScrolls.y + ((isFixed) ? 0 : htmlScroll.y) - html.clientTop
4563 var element = this, position = {x: 0, y: 0};
4564 if (isBody(this)) return position;
4566 while (element && !isBody(element)){
4567 position.x += element.offsetLeft;
4568 position.y += element.offsetTop;
4570 element = element.offsetParent;
4576 getPosition: function(relative){
4577 var offset = this.getOffsets(),
4578 scroll = this.getScrolls();
4580 x: offset.x - scroll.x,
4581 y: offset.y - scroll.y
4584 if (relative && (relative = document.id(relative))){
4585 var relativePosition = relative.getPosition();
4586 return {x: position.x - relativePosition.x - leftBorder(relative), y: position.y - relativePosition.y - topBorder(relative)};
4591 getCoordinates: function(element){
4592 if (isBody(this)) return this.getWindow().getCoordinates();
4593 var position = this.getPosition(element),
4594 size = this.getSize();
4601 obj.right = obj.left + obj.width;
4602 obj.bottom = obj.top + obj.height;
4606 computePosition: function(obj){
4608 left: obj.x - styleNumber(this, 'margin-left'),
4609 top: obj.y - styleNumber(this, 'margin-top')
4613 setPosition: function(obj){
4614 return this.setStyles(this.computePosition(obj));
4620 [Document, Window].invoke('implement', {
4622 getSize: function(){
4623 var doc = getCompatElement(this);
4624 return {x: doc.clientWidth, y: doc.clientHeight};
4627 getScroll: function(){
4628 var win = this.getWindow(), doc = getCompatElement(this);
4629 return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop};
4632 getScrollSize: function(){
4633 var doc = getCompatElement(this),
4634 min = this.getSize(),
4635 body = this.getDocument().body;
4637 return {x: Math.max(doc.scrollWidth, body.scrollWidth, min.x), y: Math.max(doc.scrollHeight, body.scrollHeight, min.y)};
4640 getPosition: function(){
4641 return {x: 0, y: 0};
4644 getCoordinates: function(){
4645 var size = this.getSize();
4646 return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x};
4653 var styleString = Element.getComputedStyle;
4655 function styleNumber(element, style){
4656 return styleString(element, style).toInt() || 0;
4659 function borderBox(element){
4660 return styleString(element, '-moz-box-sizing') == 'border-box';
4663 function topBorder(element){
4664 return styleNumber(element, 'border-top-width');
4667 function leftBorder(element){
4668 return styleNumber(element, 'border-left-width');
4671 function isBody(element){
4672 return (/^(?:body|html)$/i).test(element.tagName);
4675 function getCompatElement(element){
4676 var doc = element.getDocument();
4677 return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
4683 Element.alias({position: 'setPosition'}); //compatability
4685 [Window, Document, Element].invoke('implement', {
4687 getHeight: function(){
4688 return this.getSize().y;
4691 getWidth: function(){
4692 return this.getSize().x;
4695 getScrollTop: function(){
4696 return this.getScroll().y;
4699 getScrollLeft: function(){
4700 return this.getScroll().x;
4703 getScrollHeight: function(){
4704 return this.getScrollSize().y;
4707 getScrollWidth: function(){
4708 return this.getScrollSize().x;
4712 return this.getPosition().y;
4715 getLeft: function(){
4716 return this.getPosition().x;
4726 description: Contains the basic animation logic to be extended by all other Fx Classes.
4728 license: MIT-style license.
4730 requires: [Chain, Events, Options]
4739 var Fx = this.Fx = new Class({
4741 Implements: [Chain, Events, Options],
4757 initialize: function(options){
4758 this.subject = this.subject || this;
4759 this.setOptions(options);
4762 getTransition: function(){
4764 return -(Math.cos(Math.PI * p) - 1) / 2;
4768 step: function(now){
4769 if (this.options.frameSkip){
4770 var diff = (this.time != null) ? (now - this.time) : 0, frames = diff / this.frameInterval;
4772 this.frame += frames;
4777 if (this.frame < this.frames){
4778 var delta = this.transition(this.frame / this.frames);
4779 this.set(this.compute(this.from, this.to, delta));
4781 this.frame = this.frames;
4782 this.set(this.compute(this.from, this.to, 1));
4791 compute: function(from, to, delta){
4792 return Fx.compute(from, to, delta);
4796 if (!this.isRunning()) return true;
4797 switch (this.options.link){
4798 case 'cancel': this.cancel(); return true;
4799 case 'chain': this.chain(this.caller.pass(arguments, this)); return false;
4804 start: function(from, to){
4805 if (!this.check(from, to)) return this;
4808 this.frame = (this.options.frameSkip) ? 0 : -1;
4810 this.transition = this.getTransition();
4811 var frames = this.options.frames, fps = this.options.fps, duration = this.options.duration;
4812 this.duration = Fx.Durations[duration] || duration.toInt();
4813 this.frameInterval = 1000 / fps;
4814 this.frames = frames || Math.round(this.duration / this.frameInterval);
4815 this.fireEvent('start', this.subject);
4816 pushInstance.call(this, fps);
4821 if (this.isRunning()){
4823 pullInstance.call(this, this.options.fps);
4824 if (this.frames == this.frame){
4825 this.fireEvent('complete', this.subject);
4826 if (!this.callChain()) this.fireEvent('chainComplete', this.subject);
4828 this.fireEvent('stop', this.subject);
4835 if (this.isRunning()){
4837 pullInstance.call(this, this.options.fps);
4838 this.frame = this.frames;
4839 this.fireEvent('cancel', this.subject).clearChain();
4845 if (this.isRunning()){
4847 pullInstance.call(this, this.options.fps);
4853 if (this.isPaused()) pushInstance.call(this, this.options.fps);
4857 isRunning: function(){
4858 var list = instances[this.options.fps];
4859 return list && list.contains(this);
4862 isPaused: function(){
4863 return (this.frame < this.frames) && !this.isRunning();
4868 Fx.compute = function(from, to, delta){
4869 return (to - from) * delta + from;
4872 Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000};
4876 var instances = {}, timers = {};
4878 var loop = function(){
4879 var now = Date.now();
4880 for (var i = this.length; i--;){
4881 var instance = this[i];
4882 if (instance) instance.step(now);
4886 var pushInstance = function(fps){
4887 var list = instances[fps] || (instances[fps] = []);
4889 if (!timers[fps]) timers[fps] = loop.periodical(Math.round(1000 / fps), list);
4892 var pullInstance = function(fps){
4893 var list = instances[fps];
4896 if (!list.length && timers[fps]){
4897 delete instances[fps];
4898 timers[fps] = clearInterval(timers[fps]);
4910 description: Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements.
4912 license: MIT-style license.
4914 requires: [Fx, Element.Style]
4921 Fx.CSS = new Class({
4925 //prepares the base from/to object
4927 prepare: function(element, property, values){
4928 values = Array.from(values);
4929 var from = values[0], to = values[1];
4932 from = element.getStyle(property);
4933 var unit = this.options.unit;
4934 // adapted from: https://github.com/ryanmorr/fx/blob/master/fx.js#L299
4935 if (unit && from && typeof from == 'string' && from.slice(-unit.length) != unit && parseFloat(from) != 0){
4936 element.setStyle(property, to + unit);
4937 var value = element.getComputedStyle(property);
4938 // IE and Opera support pixelLeft or pixelWidth
4939 if (!(/px$/.test(value))){
4940 value = element.style[('pixel-' + property).camelCase()];
4942 // adapted from Dean Edwards' http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
4943 var left = element.style.left;
4944 element.style.left = to + unit;
4945 value = element.style.pixelLeft;
4946 element.style.left = left;
4949 from = (to || 1) / (parseFloat(value) || 1) * (parseFloat(from) || 0);
4950 element.setStyle(property, from + unit);
4953 return {from: this.parse(from), to: this.parse(to)};
4956 //parses a value into an array
4958 parse: function(value){
4959 value = Function.from(value)();
4960 value = (typeof value == 'string') ? value.split(' ') : Array.from(value);
4961 return value.map(function(val){
4964 Object.each(Fx.CSS.Parsers, function(parser, key){
4966 var parsed = parser.parse(val);
4967 if (parsed || parsed === 0) found = {value: parsed, parser: parser};
4969 found = found || {value: val, parser: Fx.CSS.Parsers.String};
4974 //computes by a from and to prepared objects, using their parsers.
4976 compute: function(from, to, delta){
4978 (Math.min(from.length, to.length)).times(function(i){
4979 computed.push({value: from[i].parser.compute(from[i].value, to[i].value, delta), parser: from[i].parser});
4981 computed.$family = Function.from('fx:css:value');
4985 //serves the value as settable
4987 serve: function(value, unit){
4988 if (typeOf(value) != 'fx:css:value') value = this.parse(value);
4990 value.each(function(bit){
4991 returned = returned.concat(bit.parser.serve(bit.value, unit));
4996 //renders the change to an element
4998 render: function(element, property, value, unit){
4999 element.setStyle(property, this.serve(value, unit));
5002 //searches inside the page css to find the values for a selector
5004 search: function(selector){
5005 if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector];
5006 var to = {}, selectorTest = new RegExp('^' + selector.escapeRegExp() + '$');
5008 var searchStyles = function(rules){
5009 Array.each(rules, function(rule, i){
5011 searchStyles(rule.rules || rule.cssRules);
5014 if (!rule.style) return;
5015 var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){
5016 return m.toLowerCase();
5018 if (!selectorText || !selectorTest.test(selectorText)) return;
5019 Object.each(Element.Styles, function(value, style){
5020 if (!rule.style[style] || Element.ShortStyles[style]) return;
5021 value = String(rule.style[style]);
5022 to[style] = ((/^rgb/).test(value)) ? value.rgbToHex() : value;
5027 Array.each(document.styleSheets, function(sheet, j){
5028 var href = sheet.href;
5029 if (href && href.indexOf('://') > -1 && href.indexOf(document.domain) == -1) return;
5030 var rules = sheet.rules || sheet.cssRules;
5031 searchStyles(rules);
5033 return Fx.CSS.Cache[selector] = to;
5043 parse: function(value){
5044 if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true);
5045 return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false;
5047 compute: function(from, to, delta){
5048 return from.map(function(value, i){
5049 return Math.round(Fx.compute(from[i], to[i], delta));
5052 serve: function(value){
5053 return value.map(Number);
5059 compute: Fx.compute,
5060 serve: function(value, unit){
5061 return (unit) ? value + unit : value;
5066 parse: Function.from(false),
5067 compute: function(zero, one){
5070 serve: function(zero){
5084 description: Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules.
5086 license: MIT-style license.
5095 Fx.Morph = new Class({
5099 initialize: function(element, options){
5100 this.element = this.subject = document.id(element);
5101 this.parent(options);
5105 if (typeof now == 'string') now = this.search(now);
5106 for (var p in now) this.render(this.element, p, now[p], this.options.unit);
5110 compute: function(from, to, delta){
5112 for (var p in from) now[p] = this.parent(from[p], to[p], delta);
5116 start: function(properties){
5117 if (!this.check(properties)) return this;
5118 if (typeof properties == 'string') properties = this.search(properties);
5119 var from = {}, to = {};
5120 for (var p in properties){
5121 var parsed = this.prepare(this.element, p, properties[p]);
5122 from[p] = parsed.from;
5125 return this.parent(from, to);
5130 Element.Properties.morph = {
5132 set: function(options){
5133 this.get('morph').cancel().setOptions(options);
5138 var morph = this.retrieve('morph');
5140 morph = new Fx.Morph(this, {link: 'cancel'});
5141 this.store('morph', morph);
5150 morph: function(props){
5151 this.get('morph').start(props);
5160 name: Fx.Transitions
5162 description: Contains a set of advanced transitions to be used with any of the Fx Classes.
5164 license: MIT-style license.
5167 - Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>, modified and optimized to be used with MooTools.
5171 provides: Fx.Transitions
5178 getTransition: function(){
5179 var trans = this.options.transition || Fx.Transitions.Sine.easeInOut;
5180 if (typeof trans == 'string'){
5181 var data = trans.split(':');
5182 trans = Fx.Transitions;
5183 trans = trans[data[0]] || trans[data[0].capitalize()];
5184 if (data[1]) trans = trans['ease' + data[1].capitalize() + (data[2] ? data[2].capitalize() : '')];
5191 Fx.Transition = function(transition, params){
5192 params = Array.from(params);
5193 var easeIn = function(pos){
5194 return transition(pos, params);
5196 return Object.append(easeIn, {
5198 easeOut: function(pos){
5199 return 1 - transition(1 - pos, params);
5201 easeInOut: function(pos){
5202 return (pos <= 0.5 ? transition(2 * pos, params) : (2 - transition(2 * (1 - pos), params))) / 2;
5209 linear: function(zero){
5217 Fx.Transitions.extend = function(transitions){
5218 for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]);
5221 Fx.Transitions.extend({
5223 Pow: function(p, x){
5224 return Math.pow(p, x && x[0] || 6);
5228 return Math.pow(2, 8 * (p - 1));
5232 return 1 - Math.sin(Math.acos(p));
5236 return 1 - Math.cos(p * Math.PI / 2);
5239 Back: function(p, x){
5240 x = x && x[0] || 1.618;
5241 return Math.pow(p, 2) * ((x + 1) * p - x);
5244 Bounce: function(p){
5246 for (var a = 0, b = 1; 1; a += b, b /= 2){
5247 if (p >= (7 - 4 * a) / 11){
5248 value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2);
5255 Elastic: function(p, x){
5256 return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x && x[0] || 1) / 3);
5261 ['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){
5262 Fx.Transitions[transition] = new Fx.Transition(function(p){
5263 return Math.pow(p, i + 2);
5272 description: Formerly Fx.Style, effect to transition any CSS property for an element.
5274 license: MIT-style license.
5278 provides: [Fx.Tween, Element.fade, Element.highlight]
5283 Fx.Tween = new Class({
5287 initialize: function(element, options){
5288 this.element = this.subject = document.id(element);
5289 this.parent(options);
5292 set: function(property, now){
5293 if (arguments.length == 1){
5295 property = this.property || this.options.property;
5297 this.render(this.element, property, now, this.options.unit);
5301 start: function(property, from, to){
5302 if (!this.check(property, from, to)) return this;
5303 var args = Array.flatten(arguments);
5304 this.property = this.options.property || args.shift();
5305 var parsed = this.prepare(this.element, this.property, args);
5306 return this.parent(parsed.from, parsed.to);
5311 Element.Properties.tween = {
5313 set: function(options){
5314 this.get('tween').cancel().setOptions(options);
5319 var tween = this.retrieve('tween');
5321 tween = new Fx.Tween(this, {link: 'cancel'});
5322 this.store('tween', tween);
5331 tween: function(property, from, to){
5332 this.get('tween').start(property, from, to);
5336 fade: function(how){
5337 var fade = this.get('tween'), method, args = ['opacity'].append(arguments), toggle;
5338 if (args[1] == null) args[1] = 'toggle';
5340 case 'in': method = 'start'; args[1] = 1; break;
5341 case 'out': method = 'start'; args[1] = 0; break;
5342 case 'show': method = 'set'; args[1] = 1; break;
5343 case 'hide': method = 'set'; args[1] = 0; break;
5345 var flag = this.retrieve('fade:flag', this.getStyle('opacity') == 1);
5347 args[1] = flag ? 0 : 1;
5348 this.store('fade:flag', !flag);
5351 default: method = 'start';
5353 if (!toggle) this.eliminate('fade:flag');
5354 fade[method].apply(fade, args);
5355 var to = args[args.length - 1];
5356 if (method == 'set' || to != 0) this.setStyle('visibility', to == 0 ? 'hidden' : 'visible');
5357 else fade.chain(function(){
5358 this.element.setStyle('visibility', 'hidden');
5364 highlight: function(start, end){
5366 end = this.retrieve('highlight:original', this.getStyle('background-color'));
5367 end = (end == 'transparent') ? '#fff' : end;
5369 var tween = this.get('tween');
5370 tween.start('background-color', start || '#ffff88', end).chain(function(){
5371 this.setStyle('background-color', this.retrieve('highlight:original'));
5384 description: Powerful all purpose Request Class. Uses XMLHTTPRequest.
5386 license: MIT-style license.
5388 requires: [Object, Element, Chain, Events, Options, Browser]
5397 var empty = function(){},
5398 progressSupport = ('onprogress' in new Browser.Request);
5400 var Request = this.Request = new Class({
5402 Implements: [Chain, Events, Options],
5405 onRequest: function(){},
5406 onLoadstart: function(event, xhr){},
5407 onProgress: function(event, xhr){},
5408 onComplete: function(){},
5409 onCancel: function(){},
5410 onSuccess: function(responseText, responseXML){},
5411 onFailure: function(xhr){},
5412 onException: function(headerName, value){},
5413 onTimeout: function(){},
5416 withCredentials: false,*/
5420 'X-Requested-With': 'XMLHttpRequest',
5421 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
5432 evalResponse: false,
5437 initialize: function(options){
5438 this.xhr = new Browser.Request();
5439 this.setOptions(options);
5440 this.headers = this.options.headers;
5443 onStateChange: function(){
5445 if (xhr.readyState != 4 || !this.running) return;
5446 this.running = false;
5448 Function.attempt(function(){
5449 var status = xhr.status;
5450 this.status = (status == 1223) ? 204 : status;
5452 xhr.onreadystatechange = empty;
5453 if (progressSupport) xhr.onprogress = xhr.onloadstart = empty;
5455 clearTimeout(this.timer);
5459 this.response = {text: this.xhr.responseText || '', xml: this.xhr.responseXML};
5460 if (this.options.isSuccess.call(this, this.status))
5461 this.success(this.response.text, this.response.xml);
5466 isSuccess: function(){
5467 var status = this.status;
5468 return (status >= 200 && status < 300);
5471 isRunning: function(){
5472 return !!this.running;
5475 processScripts: function(text){
5476 if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return Browser.exec(text);
5477 return text.stripScripts(this.options.evalScripts);
5480 success: function(text, xml){
5481 this.onSuccess(this.processScripts(text), xml);
5484 onSuccess: function(){
5485 this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain();
5488 failure: function(){
5492 onFailure: function(){
5493 this.fireEvent('complete').fireEvent('failure', this.xhr);
5496 loadstart: function(event){
5497 this.fireEvent('loadstart', [event, this.xhr]);
5500 progress: function(event){
5501 this.fireEvent('progress', [event, this.xhr]);
5504 timeout: function(){
5505 this.fireEvent('timeout', this.xhr);
5508 setHeader: function(name, value){
5509 this.headers[name] = value;
5513 getHeader: function(name){
5514 return Function.attempt(function(){
5515 return this.xhr.getResponseHeader(name);
5520 if (!this.running) return true;
5521 switch (this.options.link){
5522 case 'cancel': this.cancel(); return true;
5523 case 'chain': this.chain(this.caller.pass(arguments, this)); return false;
5528 send: function(options){
5529 if (!this.check(options)) return this;
5531 this.options.isSuccess = this.options.isSuccess || this.isSuccess;
5532 this.running = true;
5534 var type = typeOf(options);
5535 if (type == 'string' || type == 'element') options = {data: options};
5537 var old = this.options;
5538 options = Object.append({data: old.data, url: old.url, method: old.method}, options);
5539 var data = options.data, url = String(options.url), method = options.method.toLowerCase();
5541 switch (typeOf(data)){
5542 case 'element': data = document.id(data).toQueryString(); break;
5543 case 'object': case 'hash': data = Object.toQueryString(data);
5546 if (this.options.format){
5547 var format = 'format=' + this.options.format;
5548 data = (data) ? format + '&' + data : format;
5551 if (this.options.emulation && !['get', 'post'].contains(method)){
5552 var _method = '_method=' + method;
5553 data = (data) ? _method + '&' + data : _method;
5557 if (this.options.urlEncoded && ['post', 'put'].contains(method)){
5558 var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
5559 this.headers['Content-type'] = 'application/x-www-form-urlencoded' + encoding;
5562 if (!url) url = document.location.pathname;
5564 var trimPosition = url.lastIndexOf('/');
5565 if (trimPosition > -1 && (trimPosition = url.indexOf('#')) > -1) url = url.substr(0, trimPosition);
5567 if (this.options.noCache)
5568 url += (url.indexOf('?') > -1 ? '&' : '?') + String.uniqueID();
5570 if (data && (method == 'get' || method == 'delete')){
5571 url += (url.indexOf('?') > -1 ? '&' : '?') + data;
5576 if (progressSupport){
5577 xhr.onloadstart = this.loadstart.bind(this);
5578 xhr.onprogress = this.progress.bind(this);
5581 xhr.open(method.toUpperCase(), url, this.options.async, this.options.user, this.options.password);
5582 if ((this.options.withCredentials) && 'withCredentials' in xhr) xhr.withCredentials = true;
5584 xhr.onreadystatechange = this.onStateChange.bind(this);
5586 Object.each(this.headers, function(value, key){
5588 xhr.setRequestHeader(key, value);
5590 this.fireEvent('exception', [key, value]);
5594 this.fireEvent('request');
5596 if (!this.options.async) this.onStateChange();
5597 else if (this.options.timeout) this.timer = this.timeout.delay(this.options.timeout, this);
5602 if (!this.running) return this;
5603 this.running = false;
5607 clearTimeout(this.timer);
5610 xhr.onreadystatechange = empty;
5611 if (progressSupport) xhr.onprogress = xhr.onloadstart = empty;
5612 this.xhr = new Browser.Request();
5613 this.fireEvent('cancel');
5620 ['get', 'post', 'put', 'delete', 'patch', 'head', 'GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD'].each(function(method){
5621 methods[method] = function(data){
5625 if (data != null) object.data = data;
5626 return this.send(object);
5630 Request.implement(methods);
5632 Element.Properties.send = {
5634 set: function(options){
5635 var send = this.get('send').cancel();
5636 send.setOptions(options);
5641 var send = this.retrieve('send');
5643 send = new Request({
5644 data: this, link: 'cancel', method: this.get('method') || 'post', url: this.get('action')
5646 this.store('send', send);
5655 send: function(url){
5656 var sender = this.get('send');
5657 sender.send({data: this, url: url || sender.options.url});
5670 description: Extends the basic Request Class with additional methods for interacting with HTML responses.
5672 license: MIT-style license.
5674 requires: [Element, Request]
5676 provides: Request.HTML
5681 Request.HTML = new Class({
5691 Accept: 'text/html, application/xml, text/xml, */*'
5695 success: function(text){
5696 var options = this.options, response = this.response;
5698 response.html = text.stripScripts(function(script){
5699 response.javascript = script;
5702 var match = response.html.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
5703 if (match) response.html = match[1];
5704 var temp = new Element('div').set('html', response.html);
5706 response.tree = temp.childNodes;
5707 response.elements = temp.getElements(options.filter || '*');
5709 if (options.filter) response.tree = response.elements;
5710 if (options.update){
5711 var update = document.id(options.update).empty();
5712 if (options.filter) update.adopt(response.elements);
5713 else update.set('html', response.html);
5714 } else if (options.append){
5715 var append = document.id(options.append);
5716 if (options.filter) response.elements.reverse().inject(append);
5717 else append.adopt(temp.getChildren());
5719 if (options.evalScripts) Browser.exec(response.javascript);
5721 this.onSuccess(response.tree, response.elements, response.html, response.javascript);
5726 Element.Properties.load = {
5728 set: function(options){
5729 var load = this.get('load').cancel();
5730 load.setOptions(options);
5735 var load = this.retrieve('load');
5737 load = new Request.HTML({data: this, link: 'cancel', update: this, method: 'get'});
5738 this.store('load', load);
5748 this.get('load').send(Array.link(arguments, {data: Type.isObject, url: Type.isString}));
5759 description: JSON encoder and decoder.
5761 license: MIT-style license.
5763 SeeAlso: <http://www.json.org/>
5765 requires: [Array, String, Number, Function]
5772 if (typeof JSON == 'undefined') this.JSON = {};
5778 var special = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'};
5780 var escape = function(chr){
5781 return special[chr] || '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).slice(-4);
5784 JSON.validate = function(string){
5785 string = string.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
5786 replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
5787 replace(/(?:^|:|,)(?:\s*\[)+/g, '');
5789 return (/^[\],:{}\s]*$/).test(string);
5792 JSON.encode = JSON.stringify ? function(obj){
5793 return JSON.stringify(obj);
5795 if (obj && obj.toJSON) obj = obj.toJSON();
5797 switch (typeOf(obj)){
5799 return '"' + obj.replace(/[\x00-\x1f\\"]/g, escape) + '"';
5801 return '[' + obj.map(JSON.encode).clean() + ']';
5802 case 'object': case 'hash':
5804 Object.each(obj, function(value, key){
5805 var json = JSON.encode(value);
5806 if (json) string.push(JSON.encode(key) + ':' + json);
5808 return '{' + string + '}';
5809 case 'number': case 'boolean': return '' + obj;
5810 case 'null': return 'null';
5819 JSON.decode = function(string, secure){
5820 if (!string || typeOf(string) != 'string') return null;
5822 if (secure == null) secure = JSON.secure;
5824 if (JSON.parse) return JSON.parse(string);
5825 if (!JSON.validate(string)) throw new Error('JSON could not decode the input; security is enabled and the value is not secure.');
5828 return eval('(' + string + ')');
5838 description: Extends the basic Request Class with additional methods for sending and receiving JSON data.
5840 license: MIT-style license.
5842 requires: [Request, JSON]
5844 provides: Request.JSON
5849 Request.JSON = new Class({
5854 /*onError: function(text, error){},*/
5858 initialize: function(options){
5859 this.parent(options);
5860 Object.append(this.headers, {
5861 'Accept': 'application/json',
5866 success: function(text){
5869 json = this.response.json = JSON.decode(text, this.options.secure);
5871 this.fireEvent('error', [text, error]);
5874 if (json == null) this.onFailure();
5875 else this.onSuccess(json, text);
5885 description: Class for creating, reading, and deleting browser Cookies.
5887 license: MIT-style license.
5890 - Based on the functions by Peter-Paul Koch (http://quirksmode.org).
5892 requires: [Options, Browser]
5899 var Cookie = new Class({
5901 Implements: Options,
5912 initialize: function(key, options){
5914 this.setOptions(options);
5917 write: function(value){
5918 if (this.options.encode) value = encodeURIComponent(value);
5919 if (this.options.domain) value += '; domain=' + this.options.domain;
5920 if (this.options.path) value += '; path=' + this.options.path;
5921 if (this.options.duration){
5922 var date = new Date();
5923 date.setTime(date.getTime() + this.options.duration * 24 * 60 * 60 * 1000);
5924 value += '; expires=' + date.toGMTString();
5926 if (this.options.secure) value += '; secure';
5927 this.options.document.cookie = this.key + '=' + value;
5932 var value = this.options.document.cookie.match('(?:^|;)\\s*' + this.key.escapeRegExp() + '=([^;]*)');
5933 return (value) ? decodeURIComponent(value[1]) : null;
5936 dispose: function(){
5937 new Cookie(this.key, Object.merge({}, this.options, {duration: -1})).write('');
5943 Cookie.write = function(key, value, options){
5944 return new Cookie(key, options).write(value);
5947 Cookie.read = function(key){
5948 return new Cookie(key).read();
5951 Cookie.dispose = function(key, options){
5952 return new Cookie(key, options).dispose();
5960 description: Contains the custom event domready.
5962 license: MIT-style license.
5964 requires: [Browser, Element, Element.Event]
5966 provides: [DOMReady, DomReady]
5971 (function(window, document){
5978 testElement = document.createElement('div');
5980 var domready = function(){
5981 clearTimeout(timer);
5983 Browser.loaded = ready = true;
5984 document.removeListener('DOMContentLoaded', domready).removeListener('readystatechange', check);
5985 document.fireEvent('domready');
5986 window.fireEvent('domready');
5988 // cleanup scope vars
5989 document = window = testElement = null;
5992 var check = function(){
5993 for (var i = checks.length; i--;) if (checks[i]()){
6000 var poll = function(){
6001 clearTimeout(timer);
6002 if (!check()) timer = setTimeout(poll, 10);
6005 document.addListener('DOMContentLoaded', domready);
6008 // doScroll technique by Diego Perini http://javascript.nwbox.com/IEContentLoaded/
6009 // testElement.doScroll() throws when the DOM is not ready, only in the top window
6010 var doScrollWorks = function(){
6012 testElement.doScroll();
6017 // If doScroll works already, it can't be used to determine domready
6018 // e.g. in an iframe
6019 if (testElement.doScroll && !doScrollWorks()){
6020 checks.push(doScrollWorks);
6025 if (document.readyState) checks.push(function(){
6026 var state = document.readyState;
6027 return (state == 'loaded' || state == 'complete');
6030 if ('onreadystatechange' in document) document.addListener('readystatechange', check);
6031 else shouldPoll = true;
6033 if (shouldPoll) poll();
6035 Element.Events.domready = {
6036 onAdd: function(fn){
6037 if (ready) fn.call(this);
6041 // Make sure that domready fires before load
6042 Element.Events.load = {
6044 onAdd: function(fn){
6045 if (loaded && this == window) fn.call(this);
6047 condition: function(){
6048 if (this == window){
6050 delete Element.Events.load;
6056 // This is based on the custom load event
6057 window.addEvent('load', function(){
6061 })(window, document);