6 description: The heart of MooTools.
8 license: MIT-style license.
10 copyright: Copyright (c) 2006-2012 [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]
27 build: '0f7b690afee9349b15909f33016a25d2e4d9f4e3'
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(){
165 object.type = typeCheck;
170 if (object == null) return null;
173 object.$constructor = Type;
174 object.prototype.$constructor = object;
179 var toString = Object.prototype.toString;
181 Type.isEnumerable = function(item){
182 return (item != null && typeof item.length == 'number' && toString.call(item) != '[object Function]' );
187 var hooksOf = function(object){
188 var type = typeOf(object.prototype);
189 return hooks[type] || (hooks[type] = []);
192 var implement = function(name, method){
193 if (method && method.$hidden) return;
195 var hooks = hooksOf(this);
197 for (var i = 0; i < hooks.length; i++){
199 if (typeOf(hook) == 'type') implement.call(hook, name, method);
200 else hook.call(this, name, method);
203 var previous = this.prototype[name];
204 if (previous == null || !previous.$protected) this.prototype[name] = method;
206 if (this[name] == null && typeOf(method) == 'function') extend.call(this, name, function(item){
207 return method.apply(item, slice.call(arguments, 1));
211 var extend = function(name, method){
212 if (method && method.$hidden) return;
213 var previous = this[name];
214 if (previous == null || !previous.$protected) this[name] = method;
219 implement: implement.overloadSetter(),
221 extend: extend.overloadSetter(),
223 alias: function(name, existing){
224 implement.call(this, name, this.prototype[existing]);
227 mirror: function(hook){
228 hooksOf(this).push(hook);
234 new Type('Type', Type);
238 var force = function(name, object, methods){
239 var isType = (object != Object),
240 prototype = object.prototype;
242 if (isType) object = new Type(name, object);
244 for (var i = 0, l = methods.length; i < l; i++){
245 var key = methods[i],
246 generic = object[key],
247 proto = prototype[key];
249 if (generic) generic.protect();
250 if (isType && proto) object.implement(key, proto.protect());
254 var methodsEnumerable = prototype.propertyIsEnumerable(methods[0]);
255 object.forEachMethod = function(fn){
256 if (!methodsEnumerable) for (var i = 0, l = methods.length; i < l; i++){
257 fn.call(prototype, prototype[methods[i]], methods[i]);
259 for (var key in prototype) fn.call(prototype, prototype[key], key);
266 force('String', String, [
267 'charAt', 'charCodeAt', 'concat', 'contains', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search',
268 'slice', 'split', 'substr', 'substring', 'trim', 'toLowerCase', 'toUpperCase'
270 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice',
271 'indexOf', 'lastIndexOf', 'filter', 'forEach', 'every', 'map', 'some', 'reduce', 'reduceRight'
272 ])('Number', Number, [
273 'toExponential', 'toFixed', 'toLocaleString', 'toPrecision'
274 ])('Function', Function, [
275 'apply', 'call', 'bind'
276 ])('RegExp', RegExp, [
278 ])('Object', Object, [
279 'create', 'defineProperty', 'defineProperties', 'keys',
280 'getPrototypeOf', 'getOwnPropertyDescriptor', 'getOwnPropertyNames',
281 'preventExtensions', 'isExtensible', 'seal', 'isSealed', 'freeze', 'isFrozen'
282 ])('Date', Date, ['now']);
284 Object.extend = extend.overloadSetter();
286 Date.extend('now', function(){
290 new Type('Boolean', Boolean);
292 // fixes NaN returning as Number
294 Number.prototype.$family = function(){
295 return isFinite(this) ? 'number' : 'null';
300 Number.extend('random', function(min, max){
301 return Math.floor(Math.random() * (max - min + 1) + min);
306 var hasOwnProperty = Object.prototype.hasOwnProperty;
307 Object.extend('forEach', function(object, fn, bind){
308 for (var key in object){
309 if (hasOwnProperty.call(object, key)) fn.call(bind, object[key], key, object);
313 Object.each = Object.forEach;
318 forEach: function(fn, bind){
319 for (var i = 0, l = this.length; i < l; i++){
320 if (i in this) fn.call(bind, this[i], i, this);
325 each: function(fn, bind){
326 Array.forEach(this, fn, bind);
332 // Array & Object cloning, Object merging and appending
334 var cloneOf = function(item){
335 switch (typeOf(item)){
336 case 'array': return item.clone();
337 case 'object': return Object.clone(item);
338 default: return item;
342 Array.implement('clone', function(){
343 var i = this.length, clone = new Array(i);
344 while (i--) clone[i] = cloneOf(this[i]);
348 var mergeOne = function(source, key, current){
349 switch (typeOf(current)){
351 if (typeOf(source[key]) == 'object') Object.merge(source[key], current);
352 else source[key] = Object.clone(current);
354 case 'array': source[key] = current.clone(); break;
355 default: source[key] = current;
362 merge: function(source, k, v){
363 if (typeOf(k) == 'string') return mergeOne(source, k, v);
364 for (var i = 1, l = arguments.length; i < l; i++){
365 var object = arguments[i];
366 for (var key in object) mergeOne(source, key, object[key]);
371 clone: function(object){
373 for (var key in object) clone[key] = cloneOf(object[key]);
377 append: function(original){
378 for (var i = 1, l = arguments.length; i < l; i++){
379 var extended = arguments[i] || {};
380 for (var key in extended) original[key] = extended[key];
389 ['Object', 'WhiteSpace', 'TextNode', 'Collection', 'Arguments'].each(function(name){
395 var UID = Date.now();
397 String.extend('uniqueID', function(){
398 return (UID++).toString(36);
403 var Hash = this.Hash = new Type('Hash', function(object){
404 if (typeOf(object) == 'hash') object = Object.clone(object.getClean());
405 for (var key in object) this[key] = object[key];
411 forEach: function(fn, bind){
412 Object.forEach(this, fn, bind);
415 getClean: function(){
417 for (var key in this){
418 if (this.hasOwnProperty(key)) clean[key] = this[key];
423 getLength: function(){
425 for (var key in this){
426 if (this.hasOwnProperty(key)) length++;
433 Hash.alias('each', 'forEach');
435 Object.type = Type.isObject;
437 var Native = this.Native = function(properties){
438 return new Type(properties.name, properties.initialize);
441 Native.type = Type.type;
443 Native.implement = function(objects, methods){
444 for (var i = 0; i < objects.length; i++) objects[i].implement(methods);
448 var arrayType = Array.type;
449 Array.type = function(item){
450 return instanceOf(item, Array) || arrayType(item);
453 this.$A = function(item){
454 return Array.from(item).slice();
457 this.$arguments = function(i){
463 this.$chk = function(obj){
464 return !!(obj || obj === 0);
467 this.$clear = function(timer){
469 clearInterval(timer);
473 this.$defined = function(obj){
474 return (obj != null);
477 this.$each = function(iterable, fn, bind){
478 var type = typeOf(iterable);
479 ((type == 'arguments' || type == 'collection' || type == 'array' || type == 'elements') ? Array : Object).each(iterable, fn, bind);
482 this.$empty = function(){};
484 this.$extend = function(original, extended){
485 return Object.append(original, extended);
488 this.$H = function(object){
489 return new Hash(object);
492 this.$merge = function(){
493 var args = Array.slice(arguments);
495 return Object.merge.apply(null, args);
498 this.$lambda = Function.from;
499 this.$mixin = Object.merge;
500 this.$random = Number.random;
501 this.$splat = Array.from;
502 this.$time = Date.now;
504 this.$type = function(object){
505 var type = typeOf(object);
506 if (type == 'elements') return 'array';
507 return (type == 'null') ? false : type;
510 this.$unlink = function(object){
511 switch (typeOf(object)){
512 case 'object': return Object.clone(object);
513 case 'array': return Array.clone(object);
514 case 'hash': return new Hash(object);
515 default: return object;
528 description: Contains Array Prototypes like each, contains, and erase.
530 license: MIT-style license.
542 every: function(fn, bind){
543 for (var i = 0, l = this.length >>> 0; i < l; i++){
544 if ((i in this) && !fn.call(bind, this[i], i, this)) return false;
549 filter: function(fn, bind){
551 for (var value, i = 0, l = this.length >>> 0; i < l; i++) if (i in this){
553 if (fn.call(bind, value, i, this)) results.push(value);
558 indexOf: function(item, from){
559 var length = this.length >>> 0;
560 for (var i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++){
561 if (this[i] === item) return i;
566 map: function(fn, bind){
567 var length = this.length >>> 0, results = Array(length);
568 for (var i = 0; i < length; i++){
569 if (i in this) results[i] = fn.call(bind, this[i], i, this);
574 some: function(fn, bind){
575 for (var i = 0, l = this.length >>> 0; i < l; i++){
576 if ((i in this) && fn.call(bind, this[i], i, this)) return true;
583 return this.filter(function(item){
588 invoke: function(methodName){
589 var args = Array.slice(arguments, 1);
590 return this.map(function(item){
591 return item[methodName].apply(item, args);
595 associate: function(keys){
596 var obj = {}, length = Math.min(this.length, keys.length);
597 for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
601 link: function(object){
603 for (var i = 0, l = this.length; i < l; i++){
604 for (var key in object){
605 if (object[key](this[i])){
606 result[key] = this[i];
615 contains: function(item, from){
616 return this.indexOf(item, from) != -1;
619 append: function(array){
620 this.push.apply(this, array);
625 return (this.length) ? this[this.length - 1] : null;
628 getRandom: function(){
629 return (this.length) ? this[Number.random(0, this.length - 1)] : null;
632 include: function(item){
633 if (!this.contains(item)) this.push(item);
637 combine: function(array){
638 for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
642 erase: function(item){
643 for (var i = this.length; i--;){
644 if (this[i] === item) this.splice(i, 1);
656 for (var i = 0, l = this.length; i < l; i++){
657 var type = typeOf(this[i]);
658 if (type == 'null') continue;
659 array = array.concat((type == 'array' || type == 'collection' || type == 'arguments' || instanceOf(this[i], Array)) ? Array.flatten(this[i]) : this[i]);
665 for (var i = 0, l = this.length; i < l; i++){
666 if (this[i] != null) return this[i];
671 hexToRgb: function(array){
672 if (this.length != 3) return null;
673 var rgb = this.map(function(value){
674 if (value.length == 1) value += value;
675 return parseInt(value, 16);
677 return (array) ? rgb : 'rgb(' + rgb + ')';
680 rgbToHex: function(array){
681 if (this.length < 3) return null;
682 if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
684 for (var i = 0; i < 3; i++){
685 var bit = (this[i] - 0).toString(16);
686 hex.push((bit.length == 1) ? '0' + bit : bit);
688 return (array) ? hex : '#' + hex.join('');
695 Array.alias('extend', 'append');
697 var $pick = function(){
698 return Array.from(arguments).pick();
708 description: Contains String Prototypes like camelCase, capitalize, test, and toInt.
710 license: MIT-style license.
712 requires: [Type, Array]
722 contains: function(string, index){
723 return (index ? String(this).slice(index) : String(this)).indexOf(string) > -1;
727 test: function(regex, params){
728 return ((typeOf(regex) == 'regexp') ? regex : new RegExp('' + regex, params)).test(this);
732 return String(this).replace(/^\s+|\s+$/g, '');
736 return String(this).replace(/\s+/g, ' ').trim();
739 camelCase: function(){
740 return String(this).replace(/-\D/g, function(match){
741 return match.charAt(1).toUpperCase();
745 hyphenate: function(){
746 return String(this).replace(/[A-Z]/g, function(match){
747 return ('-' + match.charAt(0).toLowerCase());
751 capitalize: function(){
752 return String(this).replace(/\b[a-z]/g, function(match){
753 return match.toUpperCase();
757 escapeRegExp: function(){
758 return String(this).replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
761 toInt: function(base){
762 return parseInt(this, base || 10);
766 return parseFloat(this);
769 hexToRgb: function(array){
770 var hex = String(this).match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
771 return (hex) ? hex.slice(1).hexToRgb(array) : null;
774 rgbToHex: function(array){
775 var rgb = String(this).match(/\d{1,3}/g);
776 return (rgb) ? rgb.rgbToHex(array) : null;
779 substitute: function(object, regexp){
780 return String(this).replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){
781 if (match.charAt(0) == '\\') return match.slice(1);
782 return (object[name] != null) ? object[name] : '';
789 String.prototype.contains = function(string, separator){
790 return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : String(this).indexOf(string) > -1;
799 description: Contains Number Prototypes like limit, round, times, and ceil.
801 license: MIT-style license.
812 limit: function(min, max){
813 return Math.min(max, Math.max(min, this));
816 round: function(precision){
817 precision = Math.pow(10, precision || 0).toFixed(precision < 0 ? -precision : 0);
818 return Math.round(this * precision) / precision;
821 times: function(fn, bind){
822 for (var i = 0; i < this; i++) fn.call(bind, i, this);
826 return parseFloat(this);
829 toInt: function(base){
830 return parseInt(this, base || 10);
835 Number.alias('each', 'times');
839 math.each(function(name){
840 if (!Number[name]) methods[name] = function(){
841 return Math[name].apply(null, [this].concat(Array.from(arguments)));
844 Number.implement(methods);
845 })(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']);
852 description: Contains Function Prototypes like create, bind, pass, and delay.
854 license: MIT-style license.
866 for (var i = 0, l = arguments.length; i < l; i++){
868 return arguments[i]();
878 attempt: function(args, bind){
880 return this.apply(bind, Array.from(args));
887 bind: function(that){
889 args = arguments.length > 1 ? Array.slice(arguments, 1) : null,
892 var bound = function(){
893 var context = that, length = arguments.length;
894 if (this instanceof bound){
895 F.prototype = self.prototype;
898 var result = (!args && !length)
900 : self.apply(context, args && length ? args.concat(Array.slice(arguments)) : args || arguments);
901 return context == that ? result : context;
907 pass: function(args, bind){
909 if (args != null) args = Array.from(args);
911 return self.apply(bind, args || arguments);
915 delay: function(delay, bind, args){
916 return setTimeout(this.pass((args == null ? [] : args), bind), delay);
919 periodical: function(periodical, bind, args){
920 return setInterval(this.pass((args == null ? [] : args), bind), periodical);
927 delete Function.prototype.bind;
931 create: function(options){
933 options = options || {};
934 return function(event){
935 var args = options.arguments;
936 args = (args != null) ? Array.from(args) : Array.slice(arguments, (options.event) ? 1 : 0);
937 if (options.event) args = [event || window.event].extend(args);
938 var returns = function(){
939 return self.apply(options.bind || null, args);
941 if (options.delay) return setTimeout(returns, options.delay);
942 if (options.periodical) return setInterval(returns, options.periodical);
943 if (options.attempt) return Function.attempt(returns);
948 bind: function(bind, args){
950 if (args != null) args = Array.from(args);
952 return self.apply(bind, args || arguments);
956 bindWithEvent: function(bind, args){
958 if (args != null) args = Array.from(args);
959 return function(event){
960 return self.apply(bind, (args == null) ? arguments : [event].concat(args));
964 run: function(args, bind){
965 return this.apply(bind, Array.from(args));
970 if (Object.create == Function.prototype.create) Object.create = null;
972 var $try = Function.attempt;
981 description: Object generic methods
983 license: MIT-style license.
987 provides: [Object, Hash]
994 var hasOwnProperty = Object.prototype.hasOwnProperty;
998 subset: function(object, keys){
1000 for (var i = 0, l = keys.length; i < l; i++){
1002 if (k in object) results[k] = object[k];
1007 map: function(object, fn, bind){
1009 for (var key in object){
1010 if (hasOwnProperty.call(object, key)) results[key] = fn.call(bind, object[key], key, object);
1015 filter: function(object, fn, bind){
1017 for (var key in object){
1018 var value = object[key];
1019 if (hasOwnProperty.call(object, key) && fn.call(bind, value, key, object)) results[key] = value;
1024 every: function(object, fn, bind){
1025 for (var key in object){
1026 if (hasOwnProperty.call(object, key) && !fn.call(bind, object[key], key)) return false;
1031 some: function(object, fn, bind){
1032 for (var key in object){
1033 if (hasOwnProperty.call(object, key) && fn.call(bind, object[key], key)) return true;
1038 keys: function(object){
1040 for (var key in object){
1041 if (hasOwnProperty.call(object, key)) keys.push(key);
1046 values: function(object){
1048 for (var key in object){
1049 if (hasOwnProperty.call(object, key)) values.push(object[key]);
1054 getLength: function(object){
1055 return Object.keys(object).length;
1058 keyOf: function(object, value){
1059 for (var key in object){
1060 if (hasOwnProperty.call(object, key) && object[key] === value) return key;
1065 contains: function(object, value){
1066 return Object.keyOf(object, value) != null;
1069 toQueryString: function(object, base){
1070 var queryString = [];
1072 Object.each(object, function(value, key){
1073 if (base) key = base + '[' + key + ']';
1075 switch (typeOf(value)){
1076 case 'object': result = Object.toQueryString(value, key); break;
1079 value.each(function(val, i){
1082 result = Object.toQueryString(qs, key);
1084 default: result = key + '=' + encodeURIComponent(value);
1086 if (value != null) queryString.push(result);
1089 return queryString.join('&');
1100 has: Object.prototype.hasOwnProperty,
1102 keyOf: function(value){
1103 return Object.keyOf(this, value);
1106 hasValue: function(value){
1107 return Object.contains(this, value);
1110 extend: function(properties){
1111 Hash.each(properties || {}, function(value, key){
1112 Hash.set(this, key, value);
1117 combine: function(properties){
1118 Hash.each(properties || {}, function(value, key){
1119 Hash.include(this, key, value);
1124 erase: function(key){
1125 if (this.hasOwnProperty(key)) delete this[key];
1130 return (this.hasOwnProperty(key)) ? this[key] : null;
1133 set: function(key, value){
1134 if (!this[key] || this.hasOwnProperty(key)) this[key] = value;
1139 Hash.each(this, function(value, key){
1145 include: function(key, value){
1146 if (this[key] == null) this[key] = value;
1150 map: function(fn, bind){
1151 return new Hash(Object.map(this, fn, bind));
1154 filter: function(fn, bind){
1155 return new Hash(Object.filter(this, fn, bind));
1158 every: function(fn, bind){
1159 return Object.every(this, fn, bind);
1162 some: function(fn, bind){
1163 return Object.some(this, fn, bind);
1166 getKeys: function(){
1167 return Object.keys(this);
1170 getValues: function(){
1171 return Object.values(this);
1174 toQueryString: function(base){
1175 return Object.toQueryString(this, base);
1180 Hash.extend = Object.append;
1182 Hash.alias({indexOf: 'keyOf', contains: 'hasValue'});
1191 description: The Browser Object. Contains Browser initialization, Window and Document, and the Browser Hash.
1193 license: MIT-style license.
1195 requires: [Array, Function, Number, String]
1197 provides: [Browser, Window, Document]
1204 var document = this.document;
1205 var window = document.window = this;
1207 var parse = function(ua, platform){
1208 ua = ua.toLowerCase();
1209 platform = (platform ? platform.toLowerCase() : '');
1211 var UA = ua.match(/(opera|ie|firefox|chrome|trident|crios|version)[\s\/:]([\w\d\.]+)?.*?(safari|(?:rv[\s\/:]|version[\s\/:])([\w\d\.]+)|$)/) || [null, 'unknown', 0];
1213 if (UA[1] == 'trident'){
1215 if (UA[4]) UA[2] = UA[4];
1216 } else if (UA[1] == 'crios') {
1220 var platform = ua.match(/ip(?:ad|od|hone)/) ? 'ios' : (ua.match(/(?:webos|android)/) || platform.match(/mac|win|linux/) || ['other'])[0];
1221 if (platform == 'win') platform = 'windows';
1224 extend: Function.prototype.extend,
1225 name: (UA[1] == 'version') ? UA[3] : UA[1],
1226 version: parseFloat((UA[1] == 'opera' && UA[4]) ? UA[4] : UA[2]),
1231 var Browser = this.Browser = parse(navigator.userAgent, navigator.platform);
1234 Browser.version = document.documentMode;
1239 xpath: !!(document.evaluate),
1240 air: !!(window.runtime),
1241 query: !!(document.querySelector),
1242 json: !!(window.JSON)
1248 Browser[Browser.name] = true;
1249 Browser[Browser.name + parseInt(Browser.version, 10)] = true;
1251 if (Browser.name == 'ie' && Browser.version >= '11') {
1255 var platform = Browser.platform;
1256 if (platform == 'windows'){
1259 Browser.Platform = {
1262 Browser.Platform[platform] = true;
1267 Browser.Request = (function(){
1269 var XMLHTTP = function(){
1270 return new XMLHttpRequest();
1273 var MSXML2 = function(){
1274 return new ActiveXObject('MSXML2.XMLHTTP');
1277 var MSXML = function(){
1278 return new ActiveXObject('Microsoft.XMLHTTP');
1281 return Function.attempt(function(){
1294 Browser.Features.xhr = !!(Browser.Request);
1300 var version = (Function.attempt(function(){
1301 return navigator.plugins['Shockwave Flash'].description;
1303 return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
1304 }) || '0 r0').match(/\d+/g);
1308 version: Number(version[0] || '0.' + version[1]) || 0,
1309 build: Number(version[2]) || 0
1317 Browser.exec = function(text){
1318 if (!text) return text;
1319 if (window.execScript){
1320 window.execScript(text);
1322 var script = document.createElement('script');
1323 script.setAttribute('type', 'text/javascript');
1325 document.head.appendChild(script);
1326 document.head.removeChild(script);
1331 String.implement('stripScripts', function(exec){
1333 var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(all, code){
1334 scripts += code + '\n';
1337 if (exec === true) Browser.exec(scripts);
1338 else if (typeOf(exec) == 'function') exec(scripts, text);
1345 Document: this.Document,
1346 Window: this.Window,
1347 Element: this.Element,
1351 this.Window = this.$constructor = new Type('Window', function(){});
1353 this.$family = Function.from('window').hide();
1355 Window.mirror(function(name, method){
1356 window[name] = method;
1359 this.Document = document.$constructor = new Type('Document', function(){});
1361 document.$family = Function.from('document').hide();
1363 Document.mirror(function(name, method){
1364 document[name] = method;
1367 document.html = document.documentElement;
1368 if (!document.head) document.head = document.getElementsByTagName('head')[0];
1370 if (document.execCommand) try {
1371 document.execCommand("BackgroundImageCache", false, true);
1375 if (this.attachEvent && !this.addEventListener){
1376 var unloadEvent = function(){
1377 this.detachEvent('onunload', unloadEvent);
1378 document.head = document.html = document.window = null;
1380 this.attachEvent('onunload', unloadEvent);
1383 // IE fails on collections and <select>.options (refers to <select>)
1384 var arrayFrom = Array.from;
1386 arrayFrom(document.html.childNodes);
1388 Array.from = function(item){
1389 if (typeof item != 'string' && Type.isEnumerable(item) && typeOf(item) != 'array'){
1390 var i = item.length, array = new Array(i);
1391 while (i--) array[i] = item[i];
1394 return arrayFrom(item);
1397 var prototype = Array.prototype,
1398 slice = prototype.slice;
1399 ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice'].each(function(name){
1400 var method = prototype[name];
1401 Array[name] = function(item){
1402 return method.apply(Array.from(item), slice.call(arguments, 1));
1410 if (Browser.Platform.ios) Browser.Platform.ipod = true;
1412 Browser.Engine = {};
1414 var setEngine = function(name, version){
1415 Browser.Engine.name = name;
1416 Browser.Engine[name + version] = true;
1417 Browser.Engine.version = version;
1421 Browser.Engine.trident = true;
1423 switch (Browser.version){
1424 case 6: setEngine('trident', 4); break;
1425 case 7: setEngine('trident', 5); break;
1426 case 8: setEngine('trident', 6);
1430 if (Browser.firefox){
1431 Browser.Engine.gecko = true;
1433 if (Browser.version >= 3) setEngine('gecko', 19);
1434 else setEngine('gecko', 18);
1437 if (Browser.safari || Browser.chrome){
1438 Browser.Engine.webkit = true;
1440 switch (Browser.version){
1441 case 2: setEngine('webkit', 419); break;
1442 case 3: setEngine('webkit', 420); break;
1443 case 4: setEngine('webkit', 525);
1448 Browser.Engine.presto = true;
1450 if (Browser.version >= 9.6) setEngine('presto', 960);
1451 else if (Browser.version >= 9.5) setEngine('presto', 950);
1452 else setEngine('presto', 925);
1455 if (Browser.name == 'unknown'){
1456 switch ((navigator.userAgent.toLowerCase().match(/(?:webkit|khtml|gecko)/) || [])[0]){
1459 Browser.Engine.webkit = true;
1462 Browser.Engine.gecko = true;
1466 this.$exec = Browser.exec;
1477 description: Contains the Event Type, to make the event object cross-browser.
1479 license: MIT-style license.
1481 requires: [Window, Document, Array, Function, String, Object]
1492 var DOMEvent = this.DOMEvent = new Type('DOMEvent', function(event, win){
1493 if (!win) win = window;
1494 event = event || win.event;
1495 if (event.$extended) return event;
1497 this.$extended = true;
1498 this.shift = event.shiftKey;
1499 this.control = event.ctrlKey;
1500 this.alt = event.altKey;
1501 this.meta = event.metaKey;
1502 var type = this.type = event.type;
1503 var target = event.target || event.srcElement;
1504 while (target && target.nodeType == 3) target = target.parentNode;
1505 this.target = document.id(target);
1507 if (type.indexOf('key') == 0){
1508 var code = this.code = (event.which || event.keyCode);
1509 this.key = _keys[code]/*<1.3compat>*/ || Object.keyOf(Event.Keys, code)/*</1.3compat>*/;
1510 if (type == 'keydown' || type == 'keyup'){
1511 if (code > 111 && code < 124) this.key = 'f' + (code - 111);
1512 else if (code > 95 && code < 106) this.key = code - 96;
1514 if (this.key == null) this.key = String.fromCharCode(code).toLowerCase();
1515 } else if (type == 'click' || type == 'dblclick' || type == 'contextmenu' || type == 'DOMMouseScroll' || type.indexOf('mouse') == 0){
1516 var doc = win.document;
1517 doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
1519 x: (event.pageX != null) ? event.pageX : event.clientX + doc.scrollLeft,
1520 y: (event.pageY != null) ? event.pageY : event.clientY + doc.scrollTop
1523 x: (event.pageX != null) ? event.pageX - win.pageXOffset : event.clientX,
1524 y: (event.pageY != null) ? event.pageY - win.pageYOffset : event.clientY
1526 if (type == 'DOMMouseScroll' || type == 'mousewheel')
1527 this.wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
1529 this.rightClick = (event.which == 3 || event.button == 2);
1530 if (type == 'mouseover' || type == 'mouseout'){
1531 var related = event.relatedTarget || event[(type == 'mouseover' ? 'from' : 'to') + 'Element'];
1532 while (related && related.nodeType == 3) related = related.parentNode;
1533 this.relatedTarget = document.id(related);
1535 } else if (type.indexOf('touch') == 0 || type.indexOf('gesture') == 0){
1536 this.rotation = event.rotation;
1537 this.scale = event.scale;
1538 this.targetTouches = event.targetTouches;
1539 this.changedTouches = event.changedTouches;
1540 var touches = this.touches = event.touches;
1541 if (touches && touches[0]){
1542 var touch = touches[0];
1543 this.page = {x: touch.pageX, y: touch.pageY};
1544 this.client = {x: touch.clientX, y: touch.clientY};
1548 if (!this.client) this.client = {};
1549 if (!this.page) this.page = {};
1552 DOMEvent.implement({
1555 return this.preventDefault().stopPropagation();
1558 stopPropagation: function(){
1559 if (this.event.stopPropagation) this.event.stopPropagation();
1560 else this.event.cancelBubble = true;
1564 preventDefault: function(){
1565 if (this.event.preventDefault) this.event.preventDefault();
1566 else this.event.returnValue = false;
1572 DOMEvent.defineKey = function(code, key){
1577 DOMEvent.defineKeys = DOMEvent.defineKey.overloadSetter(true);
1579 DOMEvent.defineKeys({
1580 '38': 'up', '40': 'down', '37': 'left', '39': 'right',
1581 '27': 'esc', '32': 'space', '8': 'backspace', '9': 'tab',
1582 '46': 'delete', '13': 'enter'
1588 var Event = DOMEvent;
1594 Event.Keys = new Hash(Event.Keys);
1603 description: Contains the Class Function for easily creating, extending, and implementing reusable Classes.
1605 license: MIT-style license.
1607 requires: [Array, String, Function, Number]
1616 var Class = this.Class = new Type('Class', function(params){
1617 if (instanceOf(params, Function)) params = {initialize: params};
1619 var newClass = function(){
1621 if (newClass.$prototyping) return this;
1622 this.$caller = null;
1623 var value = (this.initialize) ? this.initialize.apply(this, arguments) : this;
1624 this.$caller = this.caller = null;
1626 }.extend(this).implement(params);
1628 newClass.$constructor = Class;
1629 newClass.prototype.$constructor = newClass;
1630 newClass.prototype.parent = parent;
1635 var parent = function(){
1636 if (!this.$caller) throw new Error('The method "parent" cannot be called.');
1637 var name = this.$caller.$name,
1638 parent = this.$caller.$owner.parent,
1639 previous = (parent) ? parent.prototype[name] : null;
1640 if (!previous) throw new Error('The method "' + name + '" has no parent.');
1641 return previous.apply(this, arguments);
1644 var reset = function(object){
1645 for (var key in object){
1646 var value = object[key];
1647 switch (typeOf(value)){
1649 var F = function(){};
1650 F.prototype = value;
1651 object[key] = reset(new F);
1653 case 'array': object[key] = value.clone(); break;
1659 var wrap = function(self, key, method){
1660 if (method.$origin) method = method.$origin;
1661 var wrapper = function(){
1662 if (method.$protected && this.$caller == null) throw new Error('The method "' + key + '" cannot be called.');
1663 var caller = this.caller, current = this.$caller;
1664 this.caller = current; this.$caller = wrapper;
1665 var result = method.apply(this, arguments);
1666 this.$caller = current; this.caller = caller;
1668 }.extend({$owner: self, $origin: method, $name: key});
1672 var implement = function(key, value, retain){
1673 if (Class.Mutators.hasOwnProperty(key)){
1674 value = Class.Mutators[key].call(this, value);
1675 if (value == null) return this;
1678 if (typeOf(value) == 'function'){
1679 if (value.$hidden) return this;
1680 this.prototype[key] = (retain) ? value : wrap(this, key, value);
1682 Object.merge(this.prototype, key, value);
1688 var getInstance = function(klass){
1689 klass.$prototyping = true;
1690 var proto = new klass;
1691 delete klass.$prototyping;
1695 Class.implement('implement', implement.overloadSetter());
1699 Extends: function(parent){
1700 this.parent = parent;
1701 this.prototype = getInstance(parent);
1704 Implements: function(items){
1705 Array.from(items).each(function(item){
1706 var instance = new item;
1707 for (var key in instance) implement.call(this, key, instance[key], true);
1719 description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks.
1721 license: MIT-style license.
1725 provides: [Class.Extras, Chain, Events, Options]
1732 this.Chain = new Class({
1737 this.$chain.append(Array.flatten(arguments));
1741 callChain: function(){
1742 return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false;
1745 clearChain: function(){
1746 this.$chain.empty();
1752 var removeOn = function(string){
1753 return string.replace(/^on([A-Z])/, function(full, first){
1754 return first.toLowerCase();
1758 this.Events = new Class({
1762 addEvent: function(type, fn, internal){
1763 type = removeOn(type);
1766 if (fn == $empty) return this;
1769 this.$events[type] = (this.$events[type] || []).include(fn);
1770 if (internal) fn.internal = true;
1774 addEvents: function(events){
1775 for (var type in events) this.addEvent(type, events[type]);
1779 fireEvent: function(type, args, delay){
1780 type = removeOn(type);
1781 var events = this.$events[type];
1782 if (!events) return this;
1783 args = Array.from(args);
1784 events.each(function(fn){
1785 if (delay) fn.delay(delay, this, args);
1786 else fn.apply(this, args);
1791 removeEvent: function(type, fn){
1792 type = removeOn(type);
1793 var events = this.$events[type];
1794 if (events && !fn.internal){
1795 var index = events.indexOf(fn);
1796 if (index != -1) delete events[index];
1801 removeEvents: function(events){
1803 if (typeOf(events) == 'object'){
1804 for (type in events) this.removeEvent(type, events[type]);
1807 if (events) events = removeOn(events);
1808 for (type in this.$events){
1809 if (events && events != type) continue;
1810 var fns = this.$events[type];
1811 for (var i = fns.length; i--;) if (i in fns){
1812 this.removeEvent(type, fns[i]);
1820 this.Options = new Class({
1822 setOptions: function(){
1823 var options = this.options = Object.merge.apply(null, [{}, this.options].append(arguments));
1824 if (this.addEvent) for (var option in options){
1825 if (typeOf(options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue;
1826 this.addEvent(option, options[option]);
1827 delete options[option];
1839 description: Standalone CSS3 Selector parser
1840 provides: Slick.Parser
1854 var parse = function(expression, isReversed){
1855 if (expression == null) return null;
1856 if (expression.Slick === true) return expression;
1857 expression = ('' + expression).replace(/^\s+|\s+$/g, '');
1858 reversed = !!isReversed;
1859 var currentCache = (reversed) ? reverseCache : cache;
1860 if (currentCache[expression]) return currentCache[expression];
1865 reverse: function(){
1866 return parse(this.raw, true);
1869 separatorIndex = -1;
1870 while (expression != (expression = expression.replace(regexp, parser)));
1871 parsed.length = parsed.expressions.length;
1872 return currentCache[parsed.raw] = (reversed) ? reverse(parsed) : parsed;
1875 var reverseCombinator = function(combinator){
1876 if (combinator === '!') return ' ';
1877 else if (combinator === ' ') return '!';
1878 else if ((/^!/).test(combinator)) return combinator.replace(/^!/, '');
1879 else return '!' + combinator;
1882 var reverse = function(expression){
1883 var expressions = expression.expressions;
1884 for (var i = 0; i < expressions.length; i++){
1885 var exp = expressions[i];
1886 var last = {parts: [], tag: '*', combinator: reverseCombinator(exp[0].combinator)};
1888 for (var j = 0; j < exp.length; j++){
1890 if (!cexp.reverseCombinator) cexp.reverseCombinator = ' ';
1891 cexp.combinator = cexp.reverseCombinator;
1892 delete cexp.reverseCombinator;
1895 exp.reverse().push(last);
1900 var escapeRegExp = function(string){// Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan <http://stevenlevithan.com/regex/xregexp/> MIT License
1901 return string.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, function(match){
1902 return '\\' + match;
1906 var regexp = new RegExp(
1909 puts "\t\t" + DATA.read.gsub(/\(\?x\)|\s+#.*$|\s+|\\$|\\n/,'')
1912 \\s* ( , ) \\s* # Separator \n\
1913 | \\s* ( <combinator>+ ) \\s* # Combinator \n\
1914 | ( \\s+ ) # CombinatorChildren \n\
1915 | ( <unicode>+ | \\* ) # Tag \n\
1916 | \\# ( <unicode>+ ) # ID \n\
1917 | \\. ( <unicode>+ ) # ClassName \n\
1920 \\s* (<unicode1>+) (?: \
1921 \\s* ([*^$!~|]?=) (?: \
1928 | :+ ( <unicode>+ )(?:\
1930 (?:([\"'])([^\\12]*)\\12)|((?:\\([^)]+\\)|[^()]*)+)\
1935 "^(?:\\s*(,)\\s*|\\s*(<combinator>+)\\s*|(\\s+)|(<unicode>+|\\*)|\\#(<unicode>+)|\\.(<unicode>+)|\\[\\s*(<unicode1>+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|(:+)(<unicode>+)(?:\\((?:(?:([\"'])([^\\13]*)\\13)|((?:\\([^)]+\\)|[^()]*)+))\\))?)"
1936 .replace(/<combinator>/, '[' + escapeRegExp(">+~`!@$%^&={}\\;</") + ']')
1937 .replace(/<unicode>/g, '(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
1938 .replace(/<unicode1>/g, '(?:[:\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
1960 pseudoClassQuotedValue,
1963 if (separator || separatorIndex === -1){
1964 parsed.expressions[++separatorIndex] = [];
1965 combinatorIndex = -1;
1966 if (separator) return '';
1969 if (combinator || combinatorChildren || combinatorIndex === -1){
1970 combinator = combinator || ' ';
1971 var currentSeparator = parsed.expressions[separatorIndex];
1972 if (reversed && currentSeparator[combinatorIndex])
1973 currentSeparator[combinatorIndex].reverseCombinator = reverseCombinator(combinator);
1974 currentSeparator[++combinatorIndex] = {combinator: combinator, tag: '*'};
1977 var currentParsed = parsed.expressions[separatorIndex][combinatorIndex];
1980 currentParsed.tag = tagName.replace(reUnescape, '');
1983 currentParsed.id = id.replace(reUnescape, '');
1985 } else if (className){
1986 className = className.replace(reUnescape, '');
1988 if (!currentParsed.classList) currentParsed.classList = [];
1989 if (!currentParsed.classes) currentParsed.classes = [];
1990 currentParsed.classList.push(className);
1991 currentParsed.classes.push({
1993 regexp: new RegExp('(^|\\s)' + escapeRegExp(className) + '(\\s|$)')
1996 } else if (pseudoClass){
1997 pseudoClassValue = pseudoClassValue || pseudoClassQuotedValue;
1998 pseudoClassValue = pseudoClassValue ? pseudoClassValue.replace(reUnescape, '') : null;
2000 if (!currentParsed.pseudos) currentParsed.pseudos = [];
2001 currentParsed.pseudos.push({
2002 key: pseudoClass.replace(reUnescape, ''),
2003 value: pseudoClassValue,
2004 type: pseudoMarker.length == 1 ? 'class' : 'element'
2007 } else if (attributeKey){
2008 attributeKey = attributeKey.replace(reUnescape, '');
2009 attributeValue = (attributeValue || '').replace(reUnescape, '');
2013 switch (attributeOperator){
2014 case '^=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) ); break;
2015 case '$=' : regexp = new RegExp( escapeRegExp(attributeValue) +'$' ); break;
2016 case '~=' : regexp = new RegExp( '(^|\\s)'+ escapeRegExp(attributeValue) +'(\\s|$)' ); break;
2017 case '|=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) +'(-|$)' ); break;
2018 case '=' : test = function(value){
2019 return attributeValue == value;
2021 case '*=' : test = function(value){
2022 return value && value.indexOf(attributeValue) > -1;
2024 case '!=' : test = function(value){
2025 return attributeValue != value;
2027 default : test = function(value){
2032 if (attributeValue == '' && (/^[*$^]=$/).test(attributeOperator)) test = function(){
2036 if (!test) test = function(value){
2037 return value && regexp.test(value);
2040 if (!currentParsed.attributes) currentParsed.attributes = [];
2041 currentParsed.attributes.push({
2043 operator: attributeOperator,
2044 value: attributeValue,
2055 var Slick = (this.Slick || {});
2057 Slick.parse = function(expression){
2058 return parse(expression);
2061 Slick.escapeRegExp = escapeRegExp;
2063 if (!this.Slick) this.Slick = Slick;
2065 }).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this);
2070 description: The new, superfast css selector engine.
2071 provides: Slick.Finder
2072 requires: Slick.Parser
2080 toString = Object.prototype.toString;
2082 // Feature / Bug detection
2084 local.isNativeCode = function(fn){
2085 return (/\{\s*\[native code\]\s*\}/).test('' + fn);
2088 local.isXML = function(document){
2089 return (!!document.xmlVersion) || (!!document.xml) || (toString.call(document) == '[object XMLDocument]') ||
2090 (document.nodeType == 9 && document.documentElement.nodeName != 'HTML');
2093 local.setDocument = function(document){
2095 // convert elements / window arguments to document. if document cannot be extrapolated, the function returns.
2096 var nodeType = document.nodeType;
2097 if (nodeType == 9); // document
2098 else if (nodeType) document = document.ownerDocument; // node
2099 else if (document.navigator) document = document.document; // window
2102 // check if it's the old document
2104 if (this.document === document) return;
2105 this.document = document;
2107 // check if we have done feature detection on this document before
2109 var root = document.documentElement,
2110 rootUid = this.getUIDXML(root),
2111 features = featuresCache[rootUid],
2115 for (feature in features){
2116 this[feature] = features[feature];
2121 features = featuresCache[rootUid] = {};
2123 features.root = root;
2124 features.isXMLDocument = this.isXML(document);
2126 features.brokenStarGEBTN
2127 = features.starSelectsClosedQSA
2128 = features.idGetsName
2129 = features.brokenMixedCaseQSA
2130 = features.brokenGEBCN
2131 = features.brokenCheckedQSA
2132 = features.brokenEmptyAttributeQSA
2133 = features.isHTMLDocument
2134 = features.nativeMatchesSelector
2137 var starSelectsClosed, starSelectsComments,
2138 brokenSecondClassNameGEBCN, cachedGetElementsByClassName,
2139 brokenFormAttributeGetter;
2141 var selected, id = 'slick_uniqueid';
2142 var testNode = document.createElement('div');
2144 var testRoot = document.body || document.getElementsByTagName('body')[0] || root;
2145 testRoot.appendChild(testNode);
2147 // on non-HTML documents innerHTML and getElementsById doesnt work properly
2149 testNode.innerHTML = '<a id="'+id+'"></a>';
2150 features.isHTMLDocument = !!document.getElementById(id);
2153 if (features.isHTMLDocument){
2155 testNode.style.display = 'none';
2157 // IE returns comment nodes for getElementsByTagName('*') for some documents
2158 testNode.appendChild(document.createComment(''));
2159 starSelectsComments = (testNode.getElementsByTagName('*').length > 1);
2161 // IE returns closed nodes (EG:"</foo>") for getElementsByTagName('*') for some documents
2163 testNode.innerHTML = 'foo</foo>';
2164 selected = testNode.getElementsByTagName('*');
2165 starSelectsClosed = (selected && !!selected.length && selected[0].nodeName.charAt(0) == '/');
2168 features.brokenStarGEBTN = starSelectsComments || starSelectsClosed;
2170 // IE returns elements with the name instead of just id for getElementsById for some documents
2172 testNode.innerHTML = '<a name="'+ id +'"></a><b id="'+ id +'"></b>';
2173 features.idGetsName = document.getElementById(id) === testNode.firstChild;
2176 if (testNode.getElementsByClassName){
2178 // Safari 3.2 getElementsByClassName caches results
2180 testNode.innerHTML = '<a class="f"></a><a class="b"></a>';
2181 testNode.getElementsByClassName('b').length;
2182 testNode.firstChild.className = 'b';
2183 cachedGetElementsByClassName = (testNode.getElementsByClassName('b').length != 2);
2186 // Opera 9.6 getElementsByClassName doesnt detects the class if its not the first one
2188 testNode.innerHTML = '<a class="a"></a><a class="f b a"></a>';
2189 brokenSecondClassNameGEBCN = (testNode.getElementsByClassName('a').length != 2);
2192 features.brokenGEBCN = cachedGetElementsByClassName || brokenSecondClassNameGEBCN;
2195 if (testNode.querySelectorAll){
2196 // IE 8 returns closed nodes (EG:"</foo>") for querySelectorAll('*') for some documents
2198 testNode.innerHTML = 'foo</foo>';
2199 selected = testNode.querySelectorAll('*');
2200 features.starSelectsClosedQSA = (selected && !!selected.length && selected[0].nodeName.charAt(0) == '/');
2203 // Safari 3.2 querySelectorAll doesnt work with mixedcase on quirksmode
2205 testNode.innerHTML = '<a class="MiX"></a>';
2206 features.brokenMixedCaseQSA = !testNode.querySelectorAll('.MiX').length;
2209 // Webkit and Opera dont return selected options on querySelectorAll
2211 testNode.innerHTML = '<select><option selected="selected">a</option></select>';
2212 features.brokenCheckedQSA = (testNode.querySelectorAll(':checked').length == 0);
2215 // IE returns incorrect results for attr[*^$]="" selectors on querySelectorAll
2217 testNode.innerHTML = '<a class=""></a>';
2218 features.brokenEmptyAttributeQSA = (testNode.querySelectorAll('[class*=""]').length != 0);
2223 // IE6-7, if a form has an input of id x, form.getAttribute(x) returns a reference to the input
2225 testNode.innerHTML = '<form action="s"><input id="action"/></form>';
2226 brokenFormAttributeGetter = (testNode.firstChild.getAttribute('action') != 's');
2229 // native matchesSelector function
2231 features.nativeMatchesSelector = root.matches || /*root.msMatchesSelector ||*/ root.mozMatchesSelector || root.webkitMatchesSelector;
2232 if (features.nativeMatchesSelector) try {
2233 // if matchesSelector trows errors on incorrect sintaxes we can use it
2234 features.nativeMatchesSelector.call(root, ':slick');
2235 features.nativeMatchesSelector = null;
2241 root.slick_expando = 1;
2242 delete root.slick_expando;
2243 features.getUID = this.getUIDHTML;
2245 features.getUID = this.getUIDXML;
2248 testRoot.removeChild(testNode);
2249 testNode = selected = testRoot = null;
2253 features.getAttribute = (features.isHTMLDocument && brokenFormAttributeGetter) ? function(node, name){
2254 var method = this.attributeGetters[name];
2255 if (method) return method.call(node);
2256 var attributeNode = node.getAttributeNode(name);
2257 return (attributeNode) ? attributeNode.nodeValue : null;
2258 } : function(node, name){
2259 var method = this.attributeGetters[name];
2260 return (method) ? method.call(node) : node.getAttribute(name);
2265 features.hasAttribute = (root && this.isNativeCode(root.hasAttribute)) ? function(node, attribute) {
2266 return node.hasAttribute(attribute);
2267 } : function(node, attribute) {
2268 node = node.getAttributeNode(attribute);
2269 return !!(node && (node.specified || node.nodeValue));
2273 // FIXME: Add specs: local.contains should be different for xml and html documents?
2274 var nativeRootContains = root && this.isNativeCode(root.contains),
2275 nativeDocumentContains = document && this.isNativeCode(document.contains);
2277 features.contains = (nativeRootContains && nativeDocumentContains) ? function(context, node){
2278 return context.contains(node);
2279 } : (nativeRootContains && !nativeDocumentContains) ? function(context, node){
2280 // IE8 does not have .contains on document.
2281 return context === node || ((context === document) ? document.documentElement : context).contains(node);
2282 } : (root && root.compareDocumentPosition) ? function(context, node){
2283 return context === node || !!(context.compareDocumentPosition(node) & 16);
2284 } : function(context, node){
2286 if (node === context) return true;
2287 } while ((node = node.parentNode));
2291 // document order sorting
2292 // credits to Sizzle (http://sizzlejs.com/)
2294 features.documentSorter = (root.compareDocumentPosition) ? function(a, b){
2295 if (!a.compareDocumentPosition || !b.compareDocumentPosition) return 0;
2296 return a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
2297 } : ('sourceIndex' in root) ? function(a, b){
2298 if (!a.sourceIndex || !b.sourceIndex) return 0;
2299 return a.sourceIndex - b.sourceIndex;
2300 } : (document.createRange) ? function(a, b){
2301 if (!a.ownerDocument || !b.ownerDocument) return 0;
2302 var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
2303 aRange.setStart(a, 0);
2304 aRange.setEnd(a, 0);
2305 bRange.setStart(b, 0);
2306 bRange.setEnd(b, 0);
2307 return aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
2312 for (feature in features){
2313 this[feature] = features[feature];
2319 var reSimpleSelector = /^([#.]?)((?:[\w-]+|\*))$/,
2320 reEmptyAttribute = /\[.+[*$^]=(?:""|'')?\]/,
2321 qsaFailExpCache = {};
2323 local.search = function(context, expression, append, first){
2325 var found = this.found = (first) ? null : (append || []);
2327 if (!context) return found;
2328 else if (context.navigator) context = context.document; // Convert the node from a window to a document
2329 else if (!context.nodeType) return found;
2334 uniques = this.uniques = {},
2335 hasOthers = !!(append && append.length),
2336 contextIsDocument = (context.nodeType == 9);
2338 if (this.document !== (contextIsDocument ? context : context.ownerDocument)) this.setDocument(context);
2340 // avoid duplicating items already in the append array
2341 if (hasOthers) for (i = found.length; i--;) uniques[this.getUID(found[i])] = true;
2343 // expression checks
2345 if (typeof expression == 'string'){ // expression is a string
2347 /*<simple-selectors-override>*/
2348 var simpleSelector = expression.match(reSimpleSelector);
2349 simpleSelectors: if (simpleSelector) {
2351 var symbol = simpleSelector[1],
2352 name = simpleSelector[2],
2357 if (name == '*' && this.brokenStarGEBTN) break simpleSelectors;
2358 nodes = context.getElementsByTagName(name);
2359 if (first) return nodes[0] || null;
2360 for (i = 0; node = nodes[i++];){
2361 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
2364 } else if (symbol == '#'){
2366 if (!this.isHTMLDocument || !contextIsDocument) break simpleSelectors;
2367 node = context.getElementById(name);
2368 if (!node) return found;
2369 if (this.idGetsName && node.getAttributeNode('id').nodeValue != name) break simpleSelectors;
2370 if (first) return node || null;
2371 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
2373 } else if (symbol == '.'){
2375 if (!this.isHTMLDocument || ((!context.getElementsByClassName || this.brokenGEBCN) && context.querySelectorAll)) break simpleSelectors;
2376 if (context.getElementsByClassName && !this.brokenGEBCN){
2377 nodes = context.getElementsByClassName(name);
2378 if (first) return nodes[0] || null;
2379 for (i = 0; node = nodes[i++];){
2380 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
2383 var matchClass = new RegExp('(^|\\s)'+ Slick.escapeRegExp(name) +'(\\s|$)');
2384 nodes = context.getElementsByTagName('*');
2385 for (i = 0; node = nodes[i++];){
2386 className = node.className;
2387 if (!(className && matchClass.test(className))) continue;
2388 if (first) return node;
2389 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
2395 if (hasOthers) this.sort(found);
2396 return (first) ? null : found;
2399 /*</simple-selectors-override>*/
2401 /*<query-selector-override>*/
2402 querySelector: if (context.querySelectorAll) {
2404 if (!this.isHTMLDocument
2405 || qsaFailExpCache[expression]
2406 //TODO: only skip when expression is actually mixed case
2407 || this.brokenMixedCaseQSA
2408 || (this.brokenCheckedQSA && expression.indexOf(':checked') > -1)
2409 || (this.brokenEmptyAttributeQSA && reEmptyAttribute.test(expression))
2410 || (!contextIsDocument //Abort when !contextIsDocument and...
2411 // there are multiple expressions in the selector
2412 // since we currently only fix non-document rooted QSA for single expression selectors
2413 && expression.indexOf(',') > -1
2416 ) break querySelector;
2418 var _expression = expression, _context = context;
2419 if (!contextIsDocument){
2420 // non-document rooted QSA
2421 // credits to Andrew Dupont
2422 var currentId = _context.getAttribute('id'), slickid = 'slickid__';
2423 _context.setAttribute('id', slickid);
2424 _expression = '#' + slickid + ' ' + _expression;
2425 context = _context.parentNode;
2429 if (first) return context.querySelector(_expression) || null;
2430 else nodes = context.querySelectorAll(_expression);
2432 qsaFailExpCache[expression] = 1;
2433 break querySelector;
2435 if (!contextIsDocument){
2436 if (currentId) _context.setAttribute('id', currentId);
2437 else _context.removeAttribute('id');
2442 if (this.starSelectsClosedQSA) for (i = 0; node = nodes[i++];){
2443 if (node.nodeName > '@' && !(hasOthers && uniques[this.getUID(node)])) found.push(node);
2444 } else for (i = 0; node = nodes[i++];){
2445 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
2448 if (hasOthers) this.sort(found);
2452 /*</query-selector-override>*/
2454 parsed = this.Slick.parse(expression);
2455 if (!parsed.length) return found;
2456 } else if (expression == null){ // there is no expression
2458 } else if (expression.Slick){ // expression is a parsed Slick object
2459 parsed = expression;
2460 } else if (this.contains(context.documentElement || context, expression)){ // expression is a node
2461 (found) ? found.push(expression) : found = expression;
2463 } else { // other junk
2467 /*<pseudo-selectors>*//*<nth-pseudo-selectors>*/
2469 // cache elements for the nth selectors
2472 this.posNTHLast = {};
2473 this.posNTHType = {};
2474 this.posNTHTypeLast = {};
2476 /*</nth-pseudo-selectors>*//*</pseudo-selectors>*/
2478 // if append is null and there is only a single selector with one expression use pushArray, else use pushUID
2479 this.push = (!hasOthers && (first || (parsed.length == 1 && parsed.expressions[0].length == 1))) ? this.pushArray : this.pushUID;
2481 if (found == null) found = [];
2486 var combinator, tag, id, classList, classes, attributes, pseudos;
2487 var currentItems, currentExpression, currentBit, lastBit, expressions = parsed.expressions;
2489 search: for (i = 0; (currentExpression = expressions[i]); i++) for (j = 0; (currentBit = currentExpression[j]); j++){
2491 combinator = 'combinator:' + currentBit.combinator;
2492 if (!this[combinator]) continue search;
2494 tag = (this.isXMLDocument) ? currentBit.tag : currentBit.tag.toUpperCase();
2496 classList = currentBit.classList;
2497 classes = currentBit.classes;
2498 attributes = currentBit.attributes;
2499 pseudos = currentBit.pseudos;
2500 lastBit = (j === (currentExpression.length - 1));
2502 this.bitUniques = {};
2505 this.uniques = uniques;
2513 this[combinator](context, tag, id, classes, attributes, pseudos, classList);
2514 if (first && lastBit && found.length) break search;
2516 if (first && lastBit) for (m = 0, n = currentItems.length; m < n; m++){
2517 this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList);
2518 if (found.length) break search;
2519 } else for (m = 0, n = currentItems.length; m < n; m++) this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList);
2522 currentItems = this.found;
2525 // should sort if there are nodes in append and if you pass multiple expressions.
2526 if (hasOthers || (parsed.expressions.length > 1)) this.sort(found);
2528 return (first) ? (found[0] || null) : found;
2534 local.uidk = 'slick-uniqueid';
2536 local.getUIDXML = function(node){
2537 var uid = node.getAttribute(this.uidk);
2540 node.setAttribute(this.uidk, uid);
2545 local.getUIDHTML = function(node){
2546 return node.uniqueNumber || (node.uniqueNumber = this.uidx++);
2549 // sort based on the setDocument documentSorter method.
2551 local.sort = function(results){
2552 if (!this.documentSorter) return results;
2553 results.sort(this.documentSorter);
2557 /*<pseudo-selectors>*//*<nth-pseudo-selectors>*/
2559 local.cacheNTH = {};
2561 local.matchNTH = /^([+-]?\d*)?([a-z]+)?([+-]\d+)?$/;
2563 local.parseNTHArgument = function(argument){
2564 var parsed = argument.match(this.matchNTH);
2565 if (!parsed) return false;
2566 var special = parsed[2] || false;
2567 var a = parsed[1] || 1;
2568 if (a == '-') a = -1;
2569 var b = +parsed[3] || 0;
2571 (special == 'n') ? {a: a, b: b} :
2572 (special == 'odd') ? {a: 2, b: 1} :
2573 (special == 'even') ? {a: 2, b: 0} : {a: 0, b: a};
2575 return (this.cacheNTH[argument] = parsed);
2578 local.createNTHPseudo = function(child, sibling, positions, ofType){
2579 return function(node, argument){
2580 var uid = this.getUID(node);
2581 if (!this[positions][uid]){
2582 var parent = node.parentNode;
2583 if (!parent) return false;
2584 var el = parent[child], count = 1;
2586 var nodeName = node.nodeName;
2588 if (el.nodeName != nodeName) continue;
2589 this[positions][this.getUID(el)] = count++;
2590 } while ((el = el[sibling]));
2593 if (el.nodeType != 1) continue;
2594 this[positions][this.getUID(el)] = count++;
2595 } while ((el = el[sibling]));
2598 argument = argument || 'n';
2599 var parsed = this.cacheNTH[argument] || this.parseNTHArgument(argument);
2600 if (!parsed) return false;
2601 var a = parsed.a, b = parsed.b, pos = this[positions][uid];
2602 if (a == 0) return b == pos;
2604 if (pos < b) return false;
2606 if (b < pos) return false;
2608 return ((pos - b) % a) == 0;
2612 /*</nth-pseudo-selectors>*//*</pseudo-selectors>*/
2614 local.pushArray = function(node, tag, id, classes, attributes, pseudos){
2615 if (this.matchSelector(node, tag, id, classes, attributes, pseudos)) this.found.push(node);
2618 local.pushUID = function(node, tag, id, classes, attributes, pseudos){
2619 var uid = this.getUID(node);
2620 if (!this.uniques[uid] && this.matchSelector(node, tag, id, classes, attributes, pseudos)){
2621 this.uniques[uid] = true;
2622 this.found.push(node);
2626 local.matchNode = function(node, selector){
2627 if (this.isHTMLDocument && this.nativeMatchesSelector){
2629 return this.nativeMatchesSelector.call(node, selector.replace(/\[([^=]+)=\s*([^'"\]]+?)\s*\]/g, '[$1="$2"]'));
2630 } catch(matchError) {}
2633 var parsed = this.Slick.parse(selector);
2634 if (!parsed) return true;
2636 // simple (single) selectors
2637 var expressions = parsed.expressions, simpleExpCounter = 0, i;
2638 for (i = 0; (currentExpression = expressions[i]); i++){
2639 if (currentExpression.length == 1){
2640 var exp = currentExpression[0];
2641 if (this.matchSelector(node, (this.isXMLDocument) ? exp.tag : exp.tag.toUpperCase(), exp.id, exp.classes, exp.attributes, exp.pseudos)) return true;
2646 if (simpleExpCounter == parsed.length) return false;
2648 var nodes = this.search(this.document, parsed), item;
2649 for (i = 0; item = nodes[i++];){
2650 if (item === node) return true;
2655 local.matchPseudo = function(node, name, argument){
2656 var pseudoName = 'pseudo:' + name;
2657 if (this[pseudoName]) return this[pseudoName](node, argument);
2658 var attribute = this.getAttribute(node, name);
2659 return (argument) ? argument == attribute : !!attribute;
2662 local.matchSelector = function(node, tag, id, classes, attributes, pseudos){
2664 var nodeName = (this.isXMLDocument) ? node.nodeName : node.nodeName.toUpperCase();
2666 if (nodeName < '@') return false; // Fix for comment nodes and closed nodes
2668 if (nodeName != tag) return false;
2672 if (id && node.getAttribute('id') != id) return false;
2675 if (classes) for (i = classes.length; i--;){
2676 cls = this.getAttribute(node, 'class');
2677 if (!(cls && classes[i].regexp.test(cls))) return false;
2679 if (attributes) for (i = attributes.length; i--;){
2680 part = attributes[i];
2681 if (part.operator ? !part.test(this.getAttribute(node, part.key)) : !this.hasAttribute(node, part.key)) return false;
2683 if (pseudos) for (i = pseudos.length; i--;){
2685 if (!this.matchPseudo(node, part.key, part.value)) return false;
2692 ' ': function(node, tag, id, classes, attributes, pseudos, classList){ // all child nodes, any level
2694 var i, item, children;
2696 if (this.isHTMLDocument){
2698 item = this.document.getElementById(id);
2699 if ((!item && node.all) || (this.idGetsName && item && item.getAttributeNode('id').nodeValue != id)){
2700 // all[id] returns all the elements with that name or id inside node
2701 // if theres just one it will return the element, else it will be a collection
2702 children = node.all[id];
2703 if (!children) return;
2704 if (!children[0]) children = [children];
2705 for (i = 0; item = children[i++];){
2706 var idNode = item.getAttributeNode('id');
2707 if (idNode && idNode.nodeValue == id){
2708 this.push(item, tag, null, classes, attributes, pseudos);
2715 // if the context is in the dom we return, else we will try GEBTN, breaking the getById label
2716 if (this.contains(this.root, node)) return;
2718 } else if (this.document !== node && !this.contains(node, item)) return;
2719 this.push(item, tag, null, classes, attributes, pseudos);
2722 getByClass: if (classes && node.getElementsByClassName && !this.brokenGEBCN){
2723 children = node.getElementsByClassName(classList.join(' '));
2724 if (!(children && children.length)) break getByClass;
2725 for (i = 0; item = children[i++];) this.push(item, tag, id, null, attributes, pseudos);
2730 children = node.getElementsByTagName(tag);
2731 if (!(children && children.length)) break getByTag;
2732 if (!this.brokenStarGEBTN) tag = null;
2733 for (i = 0; item = children[i++];) this.push(item, tag, id, classes, attributes, pseudos);
2737 '>': function(node, tag, id, classes, attributes, pseudos){ // direct children
2738 if ((node = node.firstChild)) do {
2739 if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos);
2740 } while ((node = node.nextSibling));
2743 '+': function(node, tag, id, classes, attributes, pseudos){ // next sibling
2744 while ((node = node.nextSibling)) if (node.nodeType == 1){
2745 this.push(node, tag, id, classes, attributes, pseudos);
2750 '^': function(node, tag, id, classes, attributes, pseudos){ // first child
2751 node = node.firstChild;
2753 if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos);
2754 else this['combinator:+'](node, tag, id, classes, attributes, pseudos);
2758 '~': function(node, tag, id, classes, attributes, pseudos){ // next siblings
2759 while ((node = node.nextSibling)){
2760 if (node.nodeType != 1) continue;
2761 var uid = this.getUID(node);
2762 if (this.bitUniques[uid]) break;
2763 this.bitUniques[uid] = true;
2764 this.push(node, tag, id, classes, attributes, pseudos);
2768 '++': function(node, tag, id, classes, attributes, pseudos){ // next sibling and previous sibling
2769 this['combinator:+'](node, tag, id, classes, attributes, pseudos);
2770 this['combinator:!+'](node, tag, id, classes, attributes, pseudos);
2773 '~~': function(node, tag, id, classes, attributes, pseudos){ // next siblings and previous siblings
2774 this['combinator:~'](node, tag, id, classes, attributes, pseudos);
2775 this['combinator:!~'](node, tag, id, classes, attributes, pseudos);
2778 '!': function(node, tag, id, classes, attributes, pseudos){ // all parent nodes up to document
2779 while ((node = node.parentNode)) if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos);
2782 '!>': function(node, tag, id, classes, attributes, pseudos){ // direct parent (one level)
2783 node = node.parentNode;
2784 if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos);
2787 '!+': function(node, tag, id, classes, attributes, pseudos){ // previous sibling
2788 while ((node = node.previousSibling)) if (node.nodeType == 1){
2789 this.push(node, tag, id, classes, attributes, pseudos);
2794 '!^': function(node, tag, id, classes, attributes, pseudos){ // last child
2795 node = node.lastChild;
2797 if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos);
2798 else this['combinator:!+'](node, tag, id, classes, attributes, pseudos);
2802 '!~': function(node, tag, id, classes, attributes, pseudos){ // previous siblings
2803 while ((node = node.previousSibling)){
2804 if (node.nodeType != 1) continue;
2805 var uid = this.getUID(node);
2806 if (this.bitUniques[uid]) break;
2807 this.bitUniques[uid] = true;
2808 this.push(node, tag, id, classes, attributes, pseudos);
2814 for (var c in combinators) local['combinator:' + c] = combinators[c];
2818 /*<pseudo-selectors>*/
2820 'empty': function(node){
2821 var child = node.firstChild;
2822 return !(child && child.nodeType == 1) && !(node.innerText || node.textContent || '').length;
2825 'not': function(node, expression){
2826 return !this.matchNode(node, expression);
2829 'contains': function(node, text){
2830 return (node.innerText || node.textContent || '').indexOf(text) > -1;
2833 'first-child': function(node){
2834 while ((node = node.previousSibling)) if (node.nodeType == 1) return false;
2838 'last-child': function(node){
2839 while ((node = node.nextSibling)) if (node.nodeType == 1) return false;
2843 'only-child': function(node){
2845 while ((prev = prev.previousSibling)) if (prev.nodeType == 1) return false;
2847 while ((next = next.nextSibling)) if (next.nodeType == 1) return false;
2851 /*<nth-pseudo-selectors>*/
2853 'nth-child': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTH'),
2855 'nth-last-child': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHLast'),
2857 'nth-of-type': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTHType', true),
2859 'nth-last-of-type': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHTypeLast', true),
2861 'index': function(node, index){
2862 return this['pseudo:nth-child'](node, '' + (index + 1));
2865 'even': function(node){
2866 return this['pseudo:nth-child'](node, '2n');
2869 'odd': function(node){
2870 return this['pseudo:nth-child'](node, '2n+1');
2873 /*</nth-pseudo-selectors>*/
2875 /*<of-type-pseudo-selectors>*/
2877 'first-of-type': function(node){
2878 var nodeName = node.nodeName;
2879 while ((node = node.previousSibling)) if (node.nodeName == nodeName) return false;
2883 'last-of-type': function(node){
2884 var nodeName = node.nodeName;
2885 while ((node = node.nextSibling)) if (node.nodeName == nodeName) return false;
2889 'only-of-type': function(node){
2890 var prev = node, nodeName = node.nodeName;
2891 while ((prev = prev.previousSibling)) if (prev.nodeName == nodeName) return false;
2893 while ((next = next.nextSibling)) if (next.nodeName == nodeName) return false;
2897 /*</of-type-pseudo-selectors>*/
2901 'enabled': function(node){
2902 return !node.disabled;
2905 'disabled': function(node){
2906 return node.disabled;
2909 'checked': function(node){
2910 return node.checked || node.selected;
2913 'focus': function(node){
2914 return this.isHTMLDocument && this.document.activeElement === node && (node.href || node.type || this.hasAttribute(node, 'tabindex'));
2917 'root': function(node){
2918 return (node === this.root);
2921 'selected': function(node){
2922 return node.selected;
2925 /*</pseudo-selectors>*/
2928 for (var p in pseudos) local['pseudo:' + p] = pseudos[p];
2930 // attributes methods
2932 var attributeGetters = local.attributeGetters = {
2935 return ('htmlFor' in this) ? this.htmlFor : this.getAttribute('for');
2939 return ('href' in this) ? this.getAttribute('href', 2) : this.getAttribute('href');
2942 'style': function(){
2943 return (this.style) ? this.style.cssText : this.getAttribute('style');
2946 'tabindex': function(){
2947 var attributeNode = this.getAttributeNode('tabindex');
2948 return (attributeNode && attributeNode.specified) ? attributeNode.nodeValue : null;
2952 return this.getAttribute('type');
2955 'maxlength': function(){
2956 var attributeNode = this.getAttributeNode('maxLength');
2957 return (attributeNode && attributeNode.specified) ? attributeNode.nodeValue : null;
2962 attributeGetters.MAXLENGTH = attributeGetters.maxLength = attributeGetters.maxlength;
2966 var Slick = local.Slick = (this.Slick || {});
2968 Slick.version = '1.1.7';
2972 Slick.search = function(context, expression, append){
2973 return local.search(context, expression, append);
2976 Slick.find = function(context, expression){
2977 return local.search(context, expression, null, true);
2980 // Slick containment checker
2982 Slick.contains = function(container, node){
2983 local.setDocument(container);
2984 return local.contains(container, node);
2987 // Slick attribute getter
2989 Slick.getAttribute = function(node, name){
2990 local.setDocument(node);
2991 return local.getAttribute(node, name);
2994 Slick.hasAttribute = function(node, name){
2995 local.setDocument(node);
2996 return local.hasAttribute(node, name);
3001 Slick.match = function(node, selector){
3002 if (!(node && selector)) return false;
3003 if (!selector || selector === node) return true;
3004 local.setDocument(node);
3005 return local.matchNode(node, selector);
3008 // Slick attribute accessor
3010 Slick.defineAttributeGetter = function(name, fn){
3011 local.attributeGetters[name] = fn;
3015 Slick.lookupAttributeGetter = function(name){
3016 return local.attributeGetters[name];
3019 // Slick pseudo accessor
3021 Slick.definePseudo = function(name, fn){
3022 local['pseudo:' + name] = function(node, argument){
3023 return fn.call(node, argument);
3028 Slick.lookupPseudo = function(name){
3029 var pseudo = local['pseudo:' + name];
3030 if (pseudo) return function(argument){
3031 return pseudo.call(this, argument);
3036 // Slick overrides accessor
3038 Slick.override = function(regexp, fn){
3039 local.override(regexp, fn);
3043 Slick.isXML = local.isXML;
3045 Slick.uidOf = function(node){
3046 return local.getUIDHTML(node);
3049 if (!this.Slick) this.Slick = Slick;
3051 }).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this);
3058 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.
3060 license: MIT-style license.
3062 requires: [Window, Document, Array, String, Function, Object, Number, Slick.Parser, Slick.Finder]
3064 provides: [Element, Elements, $, $$, IFrame, Selectors]
3069 var Element = this.Element = function(tag, props){
3070 var konstructor = Element.Constructors[tag];
3071 if (konstructor) return konstructor(props);
3072 if (typeof tag != 'string') return document.id(tag).set(props);
3074 if (!props) props = {};
3076 if (!(/^[\w-]+$/).test(tag)){
3077 var parsed = Slick.parse(tag).expressions[0][0];
3078 tag = (parsed.tag == '*') ? 'div' : parsed.tag;
3079 if (parsed.id && props.id == null) props.id = parsed.id;
3081 var attributes = parsed.attributes;
3082 if (attributes) for (var attr, i = 0, l = attributes.length; i < l; i++){
3083 attr = attributes[i];
3084 if (props[attr.key] != null) continue;
3086 if (attr.value != null && attr.operator == '=') props[attr.key] = attr.value;
3087 else if (!attr.value && !attr.operator) props[attr.key] = true;
3090 if (parsed.classList && props['class'] == null) props['class'] = parsed.classList.join(' ');
3093 return document.newElement(tag, props);
3097 if (Browser.Element){
3098 Element.prototype = Browser.Element.prototype;
3099 // IE8 and IE9 require the wrapping.
3100 Element.prototype._fireEvent = (function(fireEvent){
3101 return function(type, event){
3102 return fireEvent.call(this, type, event);
3104 })(Element.prototype.fireEvent);
3107 new Type('Element', Element).mirror(function(name){
3108 if (Array.prototype[name]) return;
3111 obj[name] = function(){
3112 var results = [], args = arguments, elements = true;
3113 for (var i = 0, l = this.length; i < l; i++){
3114 var element = this[i], result = results[i] = element[name].apply(element, args);
3115 elements = (elements && typeOf(result) == 'element');
3117 return (elements) ? new Elements(results) : results;
3120 Elements.implement(obj);
3123 if (!Browser.Element){
3124 Element.parent = Object;
3126 Element.Prototype = {
3127 '$constructor': Element,
3128 '$family': Function.from('element').hide()
3131 Element.mirror(function(name, method){
3132 Element.Prototype[name] = method;
3136 Element.Constructors = {};
3140 Element.Constructors = new Hash;
3144 var IFrame = new Type('IFrame', function(){
3145 var params = Array.link(arguments, {
3146 properties: Type.isObject,
3147 iframe: function(obj){
3148 return (obj != null);
3152 var props = params.properties || {}, iframe;
3153 if (params.iframe) iframe = document.id(params.iframe);
3154 var onload = props.onload || function(){};
3155 delete props.onload;
3156 props.id = props.name = [props.id, props.name, iframe ? (iframe.id || iframe.name) : 'IFrame_' + String.uniqueID()].pick();
3157 iframe = new Element(iframe || 'iframe', props);
3159 var onLoad = function(){
3160 onload.call(iframe.contentWindow);
3163 if (window.frames[props.id]) onLoad();
3164 else iframe.addListener('load', onLoad);
3168 var Elements = this.Elements = function(nodes){
3169 if (nodes && nodes.length){
3170 var uniques = {}, node;
3171 for (var i = 0; node = nodes[i++];){
3172 var uid = Slick.uidOf(node);
3174 uniques[uid] = true;
3181 Elements.prototype = {length: 0};
3182 Elements.parent = Array;
3184 new Type('Elements', Elements).implement({
3186 filter: function(filter, bind){
3187 if (!filter) return this;
3188 return new Elements(Array.filter(this, (typeOf(filter) == 'string') ? function(item){
3189 return item.match(filter);
3194 var length = this.length;
3195 for (var i = 0, l = arguments.length; i < l; i++){
3196 var item = document.id(arguments[i]);
3197 if (item) this[length++] = item;
3199 return (this.length = length);
3202 unshift: function(){
3204 for (var i = 0, l = arguments.length; i < l; i++){
3205 var item = document.id(arguments[i]);
3206 if (item) items.push(item);
3208 return Array.prototype.unshift.apply(this, items);
3212 var newElements = new Elements(this);
3213 for (var i = 0, l = arguments.length; i < l; i++){
3214 var item = arguments[i];
3215 if (Type.isEnumerable(item)) newElements.append(item);
3216 else newElements.push(item);
3221 append: function(collection){
3222 for (var i = 0, l = collection.length; i < l; i++) this.push(collection[i]);
3227 while (this.length) delete this[--this.length];
3235 Elements.alias('extend', 'append');
3242 var splice = Array.prototype.splice, object = {'0': 0, '1': 1, length: 2};
3244 splice.call(object, 1, 1);
3245 if (object[1] == 1) Elements.implement('splice', function(){
3246 var length = this.length;
3247 var result = splice.apply(this, arguments);
3248 while (length >= this.length) delete this[length--];
3252 Array.forEachMethod(function(method, name){
3253 Elements.implement(name, method);
3256 Array.mirror(Elements);
3259 var createElementAcceptsHTML;
3261 createElementAcceptsHTML = (document.createElement('<input name=x>').name == 'x');
3264 var escapeQuotes = function(html){
3265 return ('' + html).replace(/&/g, '&').replace(/"/g, '"');
3269 Document.implement({
3271 newElement: function(tag, props){
3272 if (props && props.checked != null) props.defaultChecked = props.checked;
3273 /*<ltIE8>*/// Fix for readonly name and type properties in IE < 8
3274 if (createElementAcceptsHTML && props){
3276 if (props.name) tag += ' name="' + escapeQuotes(props.name) + '"';
3277 if (props.type) tag += ' type="' + escapeQuotes(props.type) + '"';
3283 return this.id(this.createElement(tag)).set(props);
3292 Slick.uidOf(window);
3293 Slick.uidOf(document);
3295 Document.implement({
3297 newTextNode: function(text){
3298 return this.createTextNode(text);
3301 getDocument: function(){
3305 getWindow: function(){
3313 string: function(id, nocash, doc){
3314 id = Slick.find(doc, '#' + id.replace(/(\W)/g, '\\$1'));
3315 return (id) ? types.element(id, nocash) : null;
3318 element: function(el, nocash){
3320 if (!nocash && !el.$family && !(/^(?:object|embed)$/i).test(el.tagName)){
3321 var fireEvent = el.fireEvent;
3322 // wrapping needed in IE7, or else crash
3323 el._fireEvent = function(type, event){
3324 return fireEvent(type, event);
3326 Object.append(el, Element.Prototype);
3331 object: function(obj, nocash, doc){
3332 if (obj.toElement) return types.element(obj.toElement(doc), nocash);
3338 types.textnode = types.whitespace = types.window = types.document = function(zero){
3342 return function(el, nocash, doc){
3343 if (el && el.$family && el.uniqueNumber) return el;
3344 var type = typeOf(el);
3345 return (types[type]) ? types[type](el, nocash, doc || document) : null;
3352 if (window.$ == null) Window.implement('$', function(el, nc){
3353 return document.id(el, nc, this.document);
3358 getDocument: function(){
3359 return this.document;
3362 getWindow: function(){
3368 [Document, Element].invoke('implement', {
3370 getElements: function(expression){
3371 return Slick.search(this, expression, new Elements);
3374 getElement: function(expression){
3375 return document.id(Slick.find(this, expression));
3380 var contains = {contains: function(element){
3381 return Slick.contains(this, element);
3384 if (!document.contains) Document.implement(contains);
3385 if (!document.createElement('div').contains) Element.implement(contains);
3389 Element.implement('hasChild', function(element){
3390 return this !== element && this.contains(element);
3393 (function(search, find, match){
3395 this.Selectors = {};
3396 var pseudos = this.Selectors.Pseudo = new Hash();
3398 var addSlickPseudos = function(){
3399 for (var name in pseudos) if (pseudos.hasOwnProperty(name)){
3400 Slick.definePseudo(name, pseudos[name]);
3401 delete pseudos[name];
3405 Slick.search = function(context, expression, append){
3407 return search.call(this, context, expression, append);
3410 Slick.find = function(context, expression){
3412 return find.call(this, context, expression);
3415 Slick.match = function(node, selector){
3417 return match.call(this, node, selector);
3420 })(Slick.search, Slick.find, Slick.match);
3426 var injectCombinator = function(expression, combinator){
3427 if (!expression) return combinator;
3429 expression = Object.clone(Slick.parse(expression));
3431 var expressions = expression.expressions;
3432 for (var i = expressions.length; i--;)
3433 expressions[i][0].combinator = combinator;
3442 }, function(combinator, method){
3443 Element.implement(method, function(expression){
3444 return this.getElement(injectCombinator(expression, combinator));
3450 getAllPrevious: '!~',
3454 }, function(combinator, method){
3455 Element.implement(method, function(expression){
3456 return this.getElements(injectCombinator(expression, combinator));
3462 getFirst: function(expression){
3463 return document.id(Slick.search(this, injectCombinator(expression, '>'))[0]);
3466 getLast: function(expression){
3467 return document.id(Slick.search(this, injectCombinator(expression, '>')).getLast());
3470 getWindow: function(){
3471 return this.ownerDocument.window;
3474 getDocument: function(){
3475 return this.ownerDocument;
3478 getElementById: function(id){
3479 return document.id(Slick.find(this, '#' + ('' + id).replace(/(\W)/g, '\\$1')));
3482 match: function(expression){
3483 return !expression || Slick.match(this, expression);
3490 if (window.$$ == null) Window.implement('$$', function(selector){
3491 var elements = new Elements;
3492 if (arguments.length == 1 && typeof selector == 'string') return Slick.search(this.document, selector, elements);
3493 var args = Array.flatten(arguments);
3494 for (var i = 0, l = args.length; i < l; i++){
3496 switch (typeOf(item)){
3497 case 'element': elements.push(item); break;
3498 case 'string': Slick.search(this.document, item, elements);
3506 if (window.$$ == null) Window.implement('$$', function(selector){
3507 if (arguments.length == 1){
3508 if (typeof selector == 'string') return Slick.search(this.document, selector, new Elements);
3509 else if (Type.isEnumerable(selector)) return new Elements(selector);
3511 return new Elements(arguments);
3518 before: function(context, element){
3519 var parent = element.parentNode;
3520 if (parent) parent.insertBefore(context, element);
3523 after: function(context, element){
3524 var parent = element.parentNode;
3525 if (parent) parent.insertBefore(context, element.nextSibling);
3528 bottom: function(context, element){
3529 element.appendChild(context);
3532 top: function(context, element){
3533 element.insertBefore(context, element.firstChild);
3538 inserters.inside = inserters.bottom;
3542 Object.each(inserters, function(inserter, where){
3544 where = where.capitalize();
3548 methods['inject' + where] = function(el){
3549 inserter(this, document.id(el, true));
3553 methods['grab' + where] = function(el){
3554 inserter(document.id(el, true), this);
3558 Element.implement(methods);
3564 // getProperty / setProperty
3566 var propertyGetters = {}, propertySetters = {};
3570 var properties = {};
3572 'type', 'value', 'defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan',
3573 'frameBorder', 'rowSpan', 'tabIndex', 'useMap'
3574 ], function(property){
3575 properties[property.toLowerCase()] = property;
3578 properties.html = 'innerHTML';
3579 properties.text = (document.createElement('div').textContent == null) ? 'innerText': 'textContent';
3581 Object.forEach(properties, function(real, key){
3582 propertySetters[key] = function(node, value){
3585 propertyGetters[key] = function(node){
3593 'compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked',
3594 'disabled', 'readOnly', 'multiple', 'selected', 'noresize',
3595 'defer', 'defaultChecked', 'autofocus', 'controls', 'autoplay',
3600 Array.forEach(bools, function(bool){
3601 var lower = bool.toLowerCase();
3602 booleans[lower] = bool;
3603 propertySetters[lower] = function(node, value){
3604 node[bool] = !!value;
3606 propertyGetters[lower] = function(node){
3607 return !!node[bool];
3613 Object.append(propertySetters, {
3615 'class': function(node, value){
3616 ('className' in node) ? node.className = (value || '') : node.setAttribute('class', value);
3619 'for': function(node, value){
3620 ('htmlFor' in node) ? node.htmlFor = value : node.setAttribute('for', value);
3623 'style': function(node, value){
3624 (node.style) ? node.style.cssText = value : node.setAttribute('style', value);
3627 'value': function(node, value){
3628 node.value = (value != null) ? value : '';
3633 propertyGetters['class'] = function(node){
3634 return ('className' in node) ? node.className || null : node.getAttribute('class');
3638 var el = document.createElement('button');
3639 // IE sets type as readonly and throws
3640 try { el.type = 'button'; } catch(e){}
3641 if (el.type != 'button') propertySetters.type = function(node, value){
3642 node.setAttribute('type', value);
3648 var input = document.createElement('input');
3650 input.type = 'submit';
3651 if (input.value != 't') propertySetters.type = function(node, type){
3652 var value = node.value;
3659 /* getProperty, setProperty */
3662 var pollutesGetAttribute = (function(div){
3663 div.random = 'attribute';
3664 return (div.getAttribute('random') == 'attribute');
3665 })(document.createElement('div'));
3667 var hasCloneBug = (function(test){
3668 test.innerHTML = '<object><param name="should_fix" value="the unknown"></object>';
3669 return test.cloneNode(true).firstChild.childNodes.length != 1;
3670 })(document.createElement('div'));
3673 var hasClassList = !!document.createElement('div').classList;
3675 var classes = function(className){
3676 var classNames = (className || '').clean().split(" "), uniques = {};
3677 return classNames.filter(function(className){
3678 if (className !== "" && !uniques[className]) return uniques[className] = className;
3682 var addToClassList = function(name){
3683 this.classList.add(name);
3686 var removeFromClassList = function(name){
3687 this.classList.remove(name);
3692 setProperty: function(name, value){
3693 var setter = propertySetters[name.toLowerCase()];
3695 setter(this, value);
3698 var attributeWhiteList;
3699 if (pollutesGetAttribute) attributeWhiteList = this.retrieve('$attributeWhiteList', {});
3703 this.removeAttribute(name);
3705 if (pollutesGetAttribute) delete attributeWhiteList[name];
3708 this.setAttribute(name, '' + value);
3710 if (pollutesGetAttribute) attributeWhiteList[name] = true;
3717 setProperties: function(attributes){
3718 for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]);
3722 getProperty: function(name){
3723 var getter = propertyGetters[name.toLowerCase()];
3724 if (getter) return getter(this);
3726 if (pollutesGetAttribute){
3727 var attr = this.getAttributeNode(name), attributeWhiteList = this.retrieve('$attributeWhiteList', {});
3728 if (!attr) return null;
3729 if (attr.expando && !attributeWhiteList[name]){
3730 var outer = this.outerHTML;
3731 // segment by the opening tag and find mention of attribute name
3732 if (outer.substr(0, outer.search(/\/?['"]?>(?![^<]*<['"])/)).indexOf(name) < 0) return null;
3733 attributeWhiteList[name] = true;
3737 var result = Slick.getAttribute(this, name);
3738 return (!result && !Slick.hasAttribute(this, name)) ? null : result;
3741 getProperties: function(){
3742 var args = Array.from(arguments);
3743 return args.map(this.getProperty, this).associate(args);
3746 removeProperty: function(name){
3747 return this.setProperty(name, null);
3750 removeProperties: function(){
3751 Array.each(arguments, this.removeProperty, this);
3755 set: function(prop, value){
3756 var property = Element.Properties[prop];
3757 (property && property.set) ? property.set.call(this, value) : this.setProperty(prop, value);
3760 get: function(prop){
3761 var property = Element.Properties[prop];
3762 return (property && property.get) ? property.get.apply(this) : this.getProperty(prop);
3765 erase: function(prop){
3766 var property = Element.Properties[prop];
3767 (property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop);
3771 hasClass: hasClassList ? function(className){
3772 return this.classList.contains(className);
3773 } : function(className){
3774 return this.className.clean().contains(className, ' ');
3777 addClass: hasClassList ? function(className){
3778 classes(className).forEach(addToClassList, this);
3780 } : function(className){
3781 this.className = classes(className + ' ' + this.className).join(' ');
3785 removeClass: hasClassList ? function(className){
3786 classes(className).forEach(removeFromClassList, this);
3788 } : function(className){
3789 var classNames = classes(this.className);
3790 classes(className).forEach(classNames.erase, classNames);
3791 this.className = classNames.join(' ');
3795 toggleClass: function(className, force){
3796 if (force == null) force = !this.hasClass(className);
3797 return (force) ? this.addClass(className) : this.removeClass(className);
3801 var parent = this, fragment, elements = Array.flatten(arguments), length = elements.length;
3802 if (length > 1) parent = fragment = document.createDocumentFragment();
3804 for (var i = 0; i < length; i++){
3805 var element = document.id(elements[i], true);
3806 if (element) parent.appendChild(element);
3809 if (fragment) this.appendChild(fragment);
3814 appendText: function(text, where){
3815 return this.grab(this.getDocument().newTextNode(text), where);
3818 grab: function(el, where){
3819 inserters[where || 'bottom'](document.id(el, true), this);
3823 inject: function(el, where){
3824 inserters[where || 'bottom'](this, document.id(el, true));
3828 replaces: function(el){
3829 el = document.id(el, true);
3830 el.parentNode.replaceChild(this, el);
3834 wraps: function(el, where){
3835 el = document.id(el, true);
3836 return this.replaces(el).grab(el, where);
3839 getSelected: function(){
3840 this.selectedIndex; // Safari 3.2.1
3841 return new Elements(Array.from(this.options).filter(function(option){
3842 return option.selected;
3846 toQueryString: function(){
3847 var queryString = [];
3848 this.getElements('input, select, textarea').each(function(el){
3850 if (!el.name || el.disabled || type == 'submit' || type == 'reset' || type == 'file' || type == 'image') return;
3852 var value = (el.get('tag') == 'select') ? el.getSelected().map(function(opt){
3854 return document.id(opt).get('value');
3855 }) : ((type == 'radio' || type == 'checkbox') && !el.checked) ? null : el.get('value');
3857 Array.from(value).each(function(val){
3858 if (typeof val != 'undefined') queryString.push(encodeURIComponent(el.name) + '=' + encodeURIComponent(val));
3861 return queryString.join('&');
3869 var appendInserters = {
3870 before: 'beforeBegin',
3872 bottom: 'beforeEnd',
3877 Element.implement('appendHTML', ('insertAdjacentHTML' in document.createElement('div')) ? function(html, where){
3878 this.insertAdjacentHTML(appendInserters[where || 'bottom'], html);
3880 } : function(html, where){
3881 var temp = new Element('div', {html: html}),
3882 children = temp.childNodes,
3883 fragment = temp.firstChild;
3885 if (!fragment) return this;
3886 if (children.length > 1){
3887 fragment = document.createDocumentFragment();
3888 for (var i = 0, l = children.length; i < l; i++){
3889 fragment.appendChild(children[i]);
3893 inserters[where || 'bottom'](fragment, this);
3897 var collected = {}, storage = {};
3899 var get = function(uid){
3900 return (storage[uid] || (storage[uid] = {}));
3903 var clean = function(item){
3904 var uid = item.uniqueNumber;
3905 if (item.removeEvents) item.removeEvents();
3906 if (item.clearAttributes) item.clearAttributes();
3908 delete collected[uid];
3909 delete storage[uid];
3914 var formProps = {input: 'checked', option: 'selected', textarea: 'value'};
3918 destroy: function(){
3919 var children = clean(this).getElementsByTagName('*');
3920 Array.each(children, clean);
3921 Element.dispose(this);
3926 Array.from(this.childNodes).each(Element.dispose);
3930 dispose: function(){
3931 return (this.parentNode) ? this.parentNode.removeChild(this) : this;
3934 clone: function(contents, keepid){
3935 contents = contents !== false;
3936 var clone = this.cloneNode(contents), ce = [clone], te = [this], i;
3939 ce.append(Array.from(clone.getElementsByTagName('*')));
3940 te.append(Array.from(this.getElementsByTagName('*')));
3943 for (i = ce.length; i--;){
3944 var node = ce[i], element = te[i];
3945 if (!keepid) node.removeAttribute('id');
3947 if (node.clearAttributes){
3948 node.clearAttributes();
3949 node.mergeAttributes(element);
3950 node.removeAttribute('uniqueNumber');
3952 var no = node.options, eo = element.options;
3953 for (var j = no.length; j--;) no[j].selected = eo[j].selected;
3957 var prop = formProps[element.tagName.toLowerCase()];
3958 if (prop && element[prop]) node[prop] = element[prop];
3963 var co = clone.getElementsByTagName('object'), to = this.getElementsByTagName('object');
3964 for (i = co.length; i--;) co[i].outerHTML = to[i].outerHTML;
3967 return document.id(clone);
3972 [Element, Window, Document].invoke('implement', {
3974 addListener: function(type, fn){
3975 if (window.attachEvent && !window.addEventListener){
3976 collected[Slick.uidOf(this)] = this;
3978 if (this.addEventListener) this.addEventListener(type, fn, !!arguments[2]);
3979 else this.attachEvent('on' + type, fn);
3983 removeListener: function(type, fn){
3984 if (this.removeEventListener) this.removeEventListener(type, fn, !!arguments[2]);
3985 else this.detachEvent('on' + type, fn);
3989 retrieve: function(property, dflt){
3990 var storage = get(Slick.uidOf(this)), prop = storage[property];
3991 if (dflt != null && prop == null) prop = storage[property] = dflt;
3992 return prop != null ? prop : null;
3995 store: function(property, value){
3996 var storage = get(Slick.uidOf(this));
3997 storage[property] = value;
4001 eliminate: function(property){
4002 var storage = get(Slick.uidOf(this));
4003 delete storage[property];
4010 if (window.attachEvent && !window.addEventListener){
4011 var gc = function(){
4012 Object.each(collected, clean);
4013 if (window.CollectGarbage) CollectGarbage();
4014 window.removeListener('unload', gc);
4016 window.addListener('unload', gc);
4020 Element.Properties = {};
4024 Element.Properties = new Hash;
4028 Element.Properties.style = {
4030 set: function(style){
4031 this.style.cssText = style;
4035 return this.style.cssText;
4039 this.style.cssText = '';
4044 Element.Properties.tag = {
4047 return this.tagName.toLowerCase();
4052 Element.Properties.html = {
4054 set: function(html){
4055 if (html == null) html = '';
4056 else if (typeOf(html) == 'array') html = html.join('');
4057 this.innerHTML = html;
4061 this.innerHTML = '';
4066 var supportsHTML5Elements = true, supportsTableInnerHTML = true, supportsTRInnerHTML = true;
4069 // technique by jdbarlett - http://jdbartlett.com/innershiv/
4070 var div = document.createElement('div');
4071 div.innerHTML = '<nav></nav>';
4072 supportsHTML5Elements = (div.childNodes.length == 1);
4073 if (!supportsHTML5Elements){
4074 var tags = 'abbr article aside audio canvas datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video'.split(' '),
4075 fragment = document.createDocumentFragment(), l = tags.length;
4076 while (l--) fragment.createElement(tags[l]);
4082 supportsTableInnerHTML = Function.attempt(function(){
4083 var table = document.createElement('table');
4084 table.innerHTML = '<tr><td></td></tr>';
4089 var tr = document.createElement('tr'), html = '<td></td>';
4090 tr.innerHTML = html;
4091 supportsTRInnerHTML = (tr.innerHTML == html);
4095 if (!supportsTableInnerHTML || !supportsTRInnerHTML || !supportsHTML5Elements){
4097 Element.Properties.html.set = (function(set){
4099 var translations = {
4100 table: [1, '<table>', '</table>'],
4101 select: [1, '<select>', '</select>'],
4102 tbody: [2, '<table><tbody>', '</tbody></table>'],
4103 tr: [3, '<table><tbody><tr>', '</tr></tbody></table>']
4106 translations.thead = translations.tfoot = translations.tbody;
4108 return function(html){
4109 var wrap = translations[this.get('tag')];
4110 if (!wrap && !supportsHTML5Elements) wrap = [0, '', ''];
4111 if (!wrap) return set.call(this, html);
4113 var level = wrap[0], wrapper = document.createElement('div'), target = wrapper;
4114 if (!supportsHTML5Elements) fragment.appendChild(wrapper);
4115 wrapper.innerHTML = [wrap[1], html, wrap[2]].flatten().join('');
4116 while (level--) target = target.firstChild;
4117 this.empty().adopt(target.childNodes);
4118 if (!supportsHTML5Elements) fragment.removeChild(wrapper);
4122 })(Element.Properties.html.set);
4127 var testForm = document.createElement('form');
4128 testForm.innerHTML = '<select><option>s</option></select>';
4130 if (testForm.firstChild.value != 's') Element.Properties.value = {
4132 set: function(value){
4133 var tag = this.get('tag');
4134 if (tag != 'select') return this.setProperty('value', value);
4135 var options = this.getElements('option');
4136 value = String(value);
4137 for (var i = 0; i < options.length; i++){
4138 var option = options[i],
4139 attr = option.getAttributeNode('value'),
4140 optionValue = (attr && attr.specified) ? option.value : option.get('text');
4141 if (optionValue === value) return option.selected = true;
4146 var option = this, tag = option.get('tag');
4148 if (tag != 'select' && tag != 'option') return this.getProperty('value');
4150 if (tag == 'select' && !(option = option.getSelected()[0])) return '';
4152 var attr = option.getAttributeNode('value');
4153 return (attr && attr.specified) ? option.value : option.get('text');
4161 if (document.createElement('div').getAttributeNode('id')) Element.Properties.id = {
4163 this.id = this.getAttributeNode('id').value = id;
4166 return this.id || null;
4169 this.id = this.getAttributeNode('id').value = '';
4181 description: Contains methods for interacting with the styles of Elements in a fashionable way.
4183 license: MIT-style license.
4187 provides: Element.Style
4194 var html = document.html, el;
4197 // Check for oldIE, which does not remove styles when they're set to null
4198 el = document.createElement('div');
4199 el.style.color = 'red';
4200 el.style.color = null;
4201 var doesNotRemoveStyles = el.style.color == 'red';
4203 // check for oldIE, which returns border* shorthand styles in the wrong order (color-width-style instead of width-style-color)
4204 var border = '1px solid #123abc';
4205 el.style.border = border;
4206 var returnsBordersInWrongOrder = el.style.border != border;
4210 var hasGetComputedStyle = !!window.getComputedStyle;
4212 Element.Properties.styles = {set: function(styles){
4213 this.setStyles(styles);
4216 var hasOpacity = (html.style.opacity != null),
4217 hasFilter = (html.style.filter != null),
4218 reAlpha = /alpha\(opacity=([\d.]+)\)/i;
4220 var setVisibility = function(element, opacity){
4221 element.store('$opacity', opacity);
4222 element.style.visibility = opacity > 0 || opacity == null ? 'visible' : 'hidden';
4226 var setFilter = function(element, regexp, value){
4227 var style = element.style,
4228 filter = style.filter || element.getComputedStyle('filter') || '';
4229 style.filter = (regexp.test(filter) ? filter.replace(regexp, value) : filter + ' ' + value).trim();
4230 if (!style.filter) style.removeAttribute('filter');
4234 var setOpacity = (hasOpacity ? function(element, opacity){
4235 element.style.opacity = opacity;
4236 } : (hasFilter ? function(element, opacity){
4237 if (!element.currentStyle || !element.currentStyle.hasLayout) element.style.zoom = 1;
4238 if (opacity == null || opacity == 1){
4239 setFilter(element, reAlpha, '');
4240 if (opacity == 1 && getOpacity(element) != 1) setFilter(element, reAlpha, 'alpha(opacity=100)');
4242 setFilter(element, reAlpha, 'alpha(opacity=' + (opacity * 100).limit(0, 100).round() + ')');
4244 } : setVisibility));
4246 var getOpacity = (hasOpacity ? function(element){
4247 var opacity = element.style.opacity || element.getComputedStyle('opacity');
4248 return (opacity == '') ? 1 : opacity.toFloat();
4249 } : (hasFilter ? function(element){
4250 var filter = (element.style.filter || element.getComputedStyle('filter')),
4252 if (filter) opacity = filter.match(reAlpha);
4253 return (opacity == null || filter == null) ? 1 : (opacity[1] / 100);
4254 } : function(element){
4255 var opacity = element.retrieve('$opacity');
4256 if (opacity == null) opacity = (element.style.visibility == 'hidden' ? 0 : 1);
4260 var floatName = (html.style.cssFloat == null) ? 'styleFloat' : 'cssFloat',
4261 namedPositions = {left: '0%', top: '0%', center: '50%', right: '100%', bottom: '100%'},
4262 hasBackgroundPositionXY = (html.style.backgroundPositionX != null);
4265 var removeStyle = function(style, property){
4266 if (property == 'backgroundPosition'){
4267 style.removeAttribute(property + 'X');
4270 style.removeAttribute(property);
4276 getComputedStyle: function(property){
4277 if (!hasGetComputedStyle && this.currentStyle) return this.currentStyle[property.camelCase()];
4278 var defaultView = Element.getDocument(this).defaultView,
4279 computed = defaultView ? defaultView.getComputedStyle(this, null) : null;
4280 return (computed) ? computed.getPropertyValue((property == floatName) ? 'float' : property.hyphenate()) : '';
4283 setStyle: function(property, value){
4284 if (property == 'opacity'){
4285 if (value != null) value = parseFloat(value);
4286 setOpacity(this, value);
4289 property = (property == 'float' ? floatName : property).camelCase();
4290 if (typeOf(value) != 'string'){
4291 var map = (Element.Styles[property] || '@').split(' ');
4292 value = Array.from(value).map(function(val, i){
4293 if (!map[i]) return '';
4294 return (typeOf(val) == 'number') ? map[i].replace('@', Math.round(val)) : val;
4296 } else if (value == String(Number(value))){
4297 value = Math.round(value);
4299 this.style[property] = value;
4301 if ((value == '' || value == null) && doesNotRemoveStyles && this.style.removeAttribute){
4302 removeStyle(this.style, property);
4308 getStyle: function(property){
4309 if (property == 'opacity') return getOpacity(this);
4310 property = (property == 'float' ? floatName : property).camelCase();
4311 var result = this.style[property];
4312 if (!result || property == 'zIndex'){
4313 if (Element.ShortStyles.hasOwnProperty(property)){
4315 for (var s in Element.ShortStyles[property]) result.push(this.getStyle(s));
4316 return result.join(' ');
4318 result = this.getComputedStyle(property);
4320 if (hasBackgroundPositionXY && /^backgroundPosition[XY]?$/.test(property)){
4321 return result.replace(/(top|right|bottom|left)/g, function(position){
4322 return namedPositions[position];
4325 if (!result && property == 'backgroundPosition') return '0px 0px';
4327 result = String(result);
4328 var color = result.match(/rgba?\([\d\s,]+\)/);
4329 if (color) result = result.replace(color[0], color[0].rgbToHex());
4331 if (!hasGetComputedStyle && !this.style[property]){
4332 if ((/^(height|width)$/).test(property) && !(/px$/.test(result))){
4333 var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0;
4334 values.each(function(value){
4335 size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt();
4337 return this['offset' + property.capitalize()] - size + 'px';
4339 if ((/^border(.+)Width|margin|padding/).test(property) && isNaN(parseFloat(result))){
4344 if (returnsBordersInWrongOrder && /^border(Top|Right|Bottom|Left)?$/.test(property) && /^#/.test(result)){
4345 return result.replace(/^(.+)\s(.+)\s(.+)$/, '$2 $3 $1');
4351 setStyles: function(styles){
4352 for (var style in styles) this.setStyle(style, styles[style]);
4356 getStyles: function(){
4358 Array.flatten(arguments).each(function(key){
4359 result[key] = this.getStyle(key);
4367 left: '@px', top: '@px', bottom: '@px', right: '@px',
4368 width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px',
4369 backgroundColor: 'rgb(@, @, @)', backgroundSize: '@px', backgroundPosition: '@px @px', color: 'rgb(@, @, @)',
4370 fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)',
4371 margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)',
4372 borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)',
4373 zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@'
4380 setOpacity: function(value){
4381 setOpacity(this, value);
4385 getOpacity: function(){
4386 return getOpacity(this);
4391 Element.Properties.opacity = {
4393 set: function(opacity){
4394 setOpacity(this, opacity);
4395 setVisibility(this, opacity);
4399 return getOpacity(this);
4408 Element.Styles = new Hash(Element.Styles);
4412 Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}};
4414 ['Top', 'Right', 'Bottom', 'Left'].each(function(direction){
4415 var Short = Element.ShortStyles;
4416 var All = Element.Styles;
4417 ['margin', 'padding'].each(function(style){
4418 var sd = style + direction;
4419 Short[style][sd] = All[sd] = '@px';
4421 var bd = 'border' + direction;
4422 Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)';
4423 var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color';
4425 Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px';
4426 Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@';
4427 Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)';
4430 if (hasBackgroundPositionXY) Element.ShortStyles.backgroundPosition = {backgroundPositionX: '@', backgroundPositionY: '@'};
4438 description: Contains Element methods for dealing with events. This file also includes mouseenter and mouseleave custom Element Events, if necessary.
4440 license: MIT-style license.
4442 requires: [Element, Event]
4444 provides: Element.Event
4451 Element.Properties.events = {set: function(events){
4452 this.addEvents(events);
4455 [Element, Window, Document].invoke('implement', {
4457 addEvent: function(type, fn){
4458 var events = this.retrieve('events', {});
4459 if (!events[type]) events[type] = {keys: [], values: []};
4460 if (events[type].keys.contains(fn)) return this;
4461 events[type].keys.push(fn);
4462 var realType = type,
4463 custom = Element.Events[type],
4467 if (custom.onAdd) custom.onAdd.call(this, fn, type);
4468 if (custom.condition){
4469 condition = function(event){
4470 if (custom.condition.call(this, event, type)) return fn.call(this, event);
4474 if (custom.base) realType = Function.from(custom.base).call(this, type);
4476 var defn = function(){
4477 return fn.call(self);
4479 var nativeEvent = Element.NativeEvents[realType];
4481 if (nativeEvent == 2){
4482 defn = function(event){
4483 event = new DOMEvent(event, self.getWindow());
4484 if (condition.call(self, event) === false) event.stop();
4487 this.addListener(realType, defn, arguments[2]);
4489 events[type].values.push(defn);
4493 removeEvent: function(type, fn){
4494 var events = this.retrieve('events');
4495 if (!events || !events[type]) return this;
4496 var list = events[type];
4497 var index = list.keys.indexOf(fn);
4498 if (index == -1) return this;
4499 var value = list.values[index];
4500 delete list.keys[index];
4501 delete list.values[index];
4502 var custom = Element.Events[type];
4504 if (custom.onRemove) custom.onRemove.call(this, fn, type);
4505 if (custom.base) type = Function.from(custom.base).call(this, type);
4507 return (Element.NativeEvents[type]) ? this.removeListener(type, value, arguments[2]) : this;
4510 addEvents: function(events){
4511 for (var event in events) this.addEvent(event, events[event]);
4515 removeEvents: function(events){
4517 if (typeOf(events) == 'object'){
4518 for (type in events) this.removeEvent(type, events[type]);
4521 var attached = this.retrieve('events');
4522 if (!attached) return this;
4524 for (type in attached) this.removeEvents(type);
4525 this.eliminate('events');
4526 } else if (attached[events]){
4527 attached[events].keys.each(function(fn){
4528 this.removeEvent(events, fn);
4530 delete attached[events];
4535 fireEvent: function(type, args, delay){
4536 var events = this.retrieve('events');
4537 if (!events || !events[type]) return this;
4538 args = Array.from(args);
4540 events[type].keys.each(function(fn){
4541 if (delay) fn.delay(delay, this, args);
4542 else fn.apply(this, args);
4547 cloneEvents: function(from, type){
4548 from = document.id(from);
4549 var events = from.retrieve('events');
4550 if (!events) return this;
4552 for (var eventType in events) this.cloneEvents(from, eventType);
4553 } else if (events[type]){
4554 events[type].keys.each(function(fn){
4555 this.addEvent(type, fn);
4563 Element.NativeEvents = {
4564 click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons
4565 mousewheel: 2, DOMMouseScroll: 2, //mouse wheel
4566 mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement
4567 keydown: 2, keypress: 2, keyup: 2, //keyboard
4568 orientationchange: 2, // mobile
4569 touchstart: 2, touchmove: 2, touchend: 2, touchcancel: 2, // touch
4570 gesturestart: 2, gesturechange: 2, gestureend: 2, // gesture
4571 focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, paste: 2, input: 2, //form elements
4572 load: 2, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window
4573 hashchange: 1, popstate: 2, // history
4574 error: 1, abort: 1, scroll: 1 //misc
4579 base: 'onwheel' in document ? 'wheel' : 'onmousewheel' in document ? 'mousewheel' : 'DOMMouseScroll'
4583 var check = function(event){
4584 var related = event.relatedTarget;
4585 if (related == null) return true;
4586 if (!related) return false;
4587 return (related != this && related.prefix != 'xul' && typeOf(this) != 'document' && !this.contains(related));
4590 if ('onmouseenter' in document.documentElement){
4591 Element.NativeEvents.mouseenter = Element.NativeEvents.mouseleave = 2;
4592 Element.MouseenterCheck = check;
4594 Element.Events.mouseenter = {
4599 Element.Events.mouseleave = {
4606 if (!window.addEventListener){
4607 Element.NativeEvents.propertychange = 2;
4608 Element.Events.change = {
4610 var type = this.type;
4611 return (this.get('tag') == 'input' && (type == 'radio' || type == 'checkbox')) ? 'propertychange' : 'change';
4613 condition: function(event){
4614 return event.type != 'propertychange' || event.event.propertyName == 'checked';
4622 Element.Events = new Hash(Element.Events);
4631 name: Element.Delegation
4633 description: Extends the Element native object to include the delegate method for more efficient event management.
4635 license: MIT-style license.
4637 requires: [Element.Event]
4639 provides: [Element.Delegation]
4646 var eventListenerSupport = !!window.addEventListener;
4648 Element.NativeEvents.focusin = Element.NativeEvents.focusout = 2;
4650 var bubbleUp = function(self, match, fn, event, target){
4651 while (target && target != self){
4652 if (match(target, event)) return fn.call(target, event, target);
4653 target = document.id(target.parentNode);
4660 condition: Element.MouseenterCheck
4664 condition: Element.MouseenterCheck
4667 base: 'focus' + (eventListenerSupport ? '' : 'in'),
4671 base: eventListenerSupport ? 'blur' : 'focusout',
4677 var _key = '$delegation:';
4678 var formObserver = function(type){
4684 remove: function(self, uid){
4685 var list = self.retrieve(_key + type + 'listeners', {})[uid];
4686 if (list && list.forms) for (var i = list.forms.length; i--;){
4687 list.forms[i].removeEvent(type, list.fns[i]);
4691 listen: function(self, match, fn, event, target, uid){
4692 var form = (target.get('tag') == 'form') ? target : event.target.getParent('form');
4695 var listeners = self.retrieve(_key + type + 'listeners', {}),
4696 listener = listeners[uid] || {forms: [], fns: []},
4697 forms = listener.forms, fns = listener.fns;
4699 if (forms.indexOf(form) != -1) return;
4702 var _fn = function(event){
4703 bubbleUp(self, match, fn, event, target);
4705 form.addEvent(type, _fn);
4708 listeners[uid] = listener;
4709 self.store(_key + type + 'listeners', listeners);
4714 var inputObserver = function(type){
4717 listen: function(self, match, fn, event, target){
4718 var events = {blur: function(){
4719 this.removeEvents(events);
4721 events[type] = function(event){
4722 bubbleUp(self, match, fn, event, target);
4724 event.target.addEvents(events);
4729 if (!eventListenerSupport) Object.append(map, {
4730 submit: formObserver('submit'),
4731 reset: formObserver('reset'),
4732 change: inputObserver('change'),
4733 select: inputObserver('select')
4737 var proto = Element.prototype,
4738 addEvent = proto.addEvent,
4739 removeEvent = proto.removeEvent;
4741 var relay = function(old, method){
4742 return function(type, fn, useCapture){
4743 if (type.indexOf(':relay') == -1) return old.call(this, type, fn, useCapture);
4744 var parsed = Slick.parse(type).expressions[0][0];
4745 if (parsed.pseudos[0].key != 'relay') return old.call(this, type, fn, useCapture);
4746 var newType = parsed.tag;
4747 parsed.pseudos.slice(1).each(function(pseudo){
4748 newType += ':' + pseudo.key + (pseudo.value ? '(' + pseudo.value + ')' : '');
4750 old.call(this, type, fn);
4751 return method.call(this, newType, parsed.pseudos[0].value, fn);
4757 addEvent: function(type, match, fn){
4758 var storage = this.retrieve('$delegates', {}), stored = storage[type];
4759 if (stored) for (var _uid in stored){
4760 if (stored[_uid].fn == fn && stored[_uid].match == match) return this;
4763 var _type = type, _match = match, _fn = fn, _map = map[type] || {};
4764 type = _map.base || _type;
4766 match = function(target){
4767 return Slick.match(target, _match);
4770 var elementEvent = Element.Events[_type];
4771 if (_map.condition || elementEvent && elementEvent.condition){
4772 var __match = match, condition = _map.condition || elementEvent.condition;
4773 match = function(target, event){
4774 return __match(target, event) && condition.call(target, event, type);
4778 var self = this, uid = String.uniqueID();
4779 var delegator = _map.listen ? function(event, target){
4780 if (!target && event && event.target) target = event.target;
4781 if (target) _map.listen(self, match, fn, event, target, uid);
4782 } : function(event, target){
4783 if (!target && event && event.target) target = event.target;
4784 if (target) bubbleUp(self, match, fn, event, target);
4787 if (!stored) stored = {};
4791 delegator: delegator
4793 storage[_type] = stored;
4794 return addEvent.call(this, type, delegator, _map.capture);
4797 removeEvent: function(type, match, fn, _uid){
4798 var storage = this.retrieve('$delegates', {}), stored = storage[type];
4799 if (!stored) return this;
4802 var _type = type, delegator = stored[_uid].delegator, _map = map[type] || {};
4803 type = _map.base || _type;
4804 if (_map.remove) _map.remove(this, _uid);
4805 delete stored[_uid];
4806 storage[_type] = stored;
4807 return removeEvent.call(this, type, delegator, _map.capture);
4811 if (fn) for (__uid in stored){
4813 if (s.match == match && s.fn == fn) return delegation.removeEvent.call(this, type, match, fn, __uid);
4814 } else for (__uid in stored){
4816 if (s.match == match) delegation.removeEvent.call(this, type, match, s.fn, __uid);
4823 [Element, Window, Document].invoke('implement', {
4824 addEvent: relay(addEvent, delegation.addEvent),
4825 removeEvent: relay(removeEvent, delegation.removeEvent)
4833 name: Element.Dimensions
4835 description: Contains methods to work with size, scroll, or positioning of Elements and the window object.
4837 license: MIT-style license.
4840 - Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html).
4841 - Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html).
4843 requires: [Element, Element.Style]
4845 provides: [Element.Dimensions]
4852 var element = document.createElement('div'),
4853 child = document.createElement('div');
4854 element.style.height = '0';
4855 element.appendChild(child);
4856 var brokenOffsetParent = (child.offsetParent === element);
4857 element = child = null;
4859 var isOffset = function(el){
4860 return styleString(el, 'position') != 'static' || isBody(el);
4863 var isOffsetStatic = function(el){
4864 return isOffset(el) || (/^(?:table|td|th)$/i).test(el.tagName);
4869 scrollTo: function(x, y){
4871 this.getWindow().scrollTo(x, y);
4873 this.scrollLeft = x;
4879 getSize: function(){
4880 if (isBody(this)) return this.getWindow().getSize();
4881 return {x: this.offsetWidth, y: this.offsetHeight};
4884 getScrollSize: function(){
4885 if (isBody(this)) return this.getWindow().getScrollSize();
4886 return {x: this.scrollWidth, y: this.scrollHeight};
4889 getScroll: function(){
4890 if (isBody(this)) return this.getWindow().getScroll();
4891 return {x: this.scrollLeft, y: this.scrollTop};
4894 getScrolls: function(){
4895 var element = this.parentNode, position = {x: 0, y: 0};
4896 while (element && !isBody(element)){
4897 position.x += element.scrollLeft;
4898 position.y += element.scrollTop;
4899 element = element.parentNode;
4904 getOffsetParent: brokenOffsetParent ? function(){
4906 if (isBody(element) || styleString(element, 'position') == 'fixed') return null;
4908 var isOffsetCheck = (styleString(element, 'position') == 'static') ? isOffsetStatic : isOffset;
4909 while ((element = element.parentNode)){
4910 if (isOffsetCheck(element)) return element;
4915 if (isBody(element) || styleString(element, 'position') == 'fixed') return null;
4918 return element.offsetParent;
4923 getOffsets: function(){
4924 var hasGetBoundingClientRect = this.getBoundingClientRect;
4926 hasGetBoundingClientRect = hasGetBoundingClientRect && !Browser.Platform.ios
4928 if (hasGetBoundingClientRect){
4929 var bound = this.getBoundingClientRect(),
4930 html = document.id(this.getDocument().documentElement),
4931 htmlScroll = html.getScroll(),
4932 elemScrolls = this.getScrolls(),
4933 isFixed = (styleString(this, 'position') == 'fixed');
4936 x: bound.left.toInt() + elemScrolls.x + ((isFixed) ? 0 : htmlScroll.x) - html.clientLeft,
4937 y: bound.top.toInt() + elemScrolls.y + ((isFixed) ? 0 : htmlScroll.y) - html.clientTop
4941 var element = this, position = {x: 0, y: 0};
4942 if (isBody(this)) return position;
4944 while (element && !isBody(element)){
4945 position.x += element.offsetLeft;
4946 position.y += element.offsetTop;
4948 if (Browser.firefox){
4949 if (!borderBox(element)){
4950 position.x += leftBorder(element);
4951 position.y += topBorder(element);
4953 var parent = element.parentNode;
4954 if (parent && styleString(parent, 'overflow') != 'visible'){
4955 position.x += leftBorder(parent);
4956 position.y += topBorder(parent);
4958 } else if (element != this && Browser.safari){
4959 position.x += leftBorder(element);
4960 position.y += topBorder(element);
4963 element = element.offsetParent;
4966 if (Browser.firefox && !borderBox(this)){
4967 position.x -= leftBorder(this);
4968 position.y -= topBorder(this);
4974 getPosition: function(relative){
4975 var offset = this.getOffsets(),
4976 scroll = this.getScrolls();
4978 x: offset.x - scroll.x,
4979 y: offset.y - scroll.y
4982 if (relative && (relative = document.id(relative))){
4983 var relativePosition = relative.getPosition();
4984 return {x: position.x - relativePosition.x - leftBorder(relative), y: position.y - relativePosition.y - topBorder(relative)};
4989 getCoordinates: function(element){
4990 if (isBody(this)) return this.getWindow().getCoordinates();
4991 var position = this.getPosition(element),
4992 size = this.getSize();
4999 obj.right = obj.left + obj.width;
5000 obj.bottom = obj.top + obj.height;
5004 computePosition: function(obj){
5006 left: obj.x - styleNumber(this, 'margin-left'),
5007 top: obj.y - styleNumber(this, 'margin-top')
5011 setPosition: function(obj){
5012 return this.setStyles(this.computePosition(obj));
5018 [Document, Window].invoke('implement', {
5020 getSize: function(){
5021 var doc = getCompatElement(this);
5022 return {x: doc.clientWidth, y: doc.clientHeight};
5025 getScroll: function(){
5026 var win = this.getWindow(), doc = getCompatElement(this);
5027 return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop};
5030 getScrollSize: function(){
5031 var doc = getCompatElement(this),
5032 min = this.getSize(),
5033 body = this.getDocument().body;
5035 return {x: Math.max(doc.scrollWidth, body.scrollWidth, min.x), y: Math.max(doc.scrollHeight, body.scrollHeight, min.y)};
5038 getPosition: function(){
5039 return {x: 0, y: 0};
5042 getCoordinates: function(){
5043 var size = this.getSize();
5044 return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x};
5051 var styleString = Element.getComputedStyle;
5053 function styleNumber(element, style){
5054 return styleString(element, style).toInt() || 0;
5057 function borderBox(element){
5058 return styleString(element, '-moz-box-sizing') == 'border-box';
5061 function topBorder(element){
5062 return styleNumber(element, 'border-top-width');
5065 function leftBorder(element){
5066 return styleNumber(element, 'border-left-width');
5069 function isBody(element){
5070 return (/^(?:body|html)$/i).test(element.tagName);
5073 function getCompatElement(element){
5074 var doc = element.getDocument();
5075 return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
5081 Element.alias({position: 'setPosition'}); //compatability
5083 [Window, Document, Element].invoke('implement', {
5085 getHeight: function(){
5086 return this.getSize().y;
5089 getWidth: function(){
5090 return this.getSize().x;
5093 getScrollTop: function(){
5094 return this.getScroll().y;
5097 getScrollLeft: function(){
5098 return this.getScroll().x;
5101 getScrollHeight: function(){
5102 return this.getScrollSize().y;
5105 getScrollWidth: function(){
5106 return this.getScrollSize().x;
5110 return this.getPosition().y;
5113 getLeft: function(){
5114 return this.getPosition().x;
5124 description: Contains the basic animation logic to be extended by all other Fx Classes.
5126 license: MIT-style license.
5128 requires: [Chain, Events, Options]
5137 var Fx = this.Fx = new Class({
5139 Implements: [Chain, Events, Options],
5155 initialize: function(options){
5156 this.subject = this.subject || this;
5157 this.setOptions(options);
5160 getTransition: function(){
5162 return -(Math.cos(Math.PI * p) - 1) / 2;
5166 step: function(now){
5167 if (this.options.frameSkip){
5168 var diff = (this.time != null) ? (now - this.time) : 0, frames = diff / this.frameInterval;
5170 this.frame += frames;
5175 if (this.frame < this.frames){
5176 var delta = this.transition(this.frame / this.frames);
5177 this.set(this.compute(this.from, this.to, delta));
5179 this.frame = this.frames;
5180 this.set(this.compute(this.from, this.to, 1));
5189 compute: function(from, to, delta){
5190 return Fx.compute(from, to, delta);
5194 if (!this.isRunning()) return true;
5195 switch (this.options.link){
5196 case 'cancel': this.cancel(); return true;
5197 case 'chain': this.chain(this.caller.pass(arguments, this)); return false;
5202 start: function(from, to){
5203 if (!this.check(from, to)) return this;
5206 this.frame = (this.options.frameSkip) ? 0 : -1;
5208 this.transition = this.getTransition();
5209 var frames = this.options.frames, fps = this.options.fps, duration = this.options.duration;
5210 this.duration = Fx.Durations[duration] || duration.toInt();
5211 this.frameInterval = 1000 / fps;
5212 this.frames = frames || Math.round(this.duration / this.frameInterval);
5213 this.fireEvent('start', this.subject);
5214 pushInstance.call(this, fps);
5219 if (this.isRunning()){
5221 pullInstance.call(this, this.options.fps);
5222 if (this.frames == this.frame){
5223 this.fireEvent('complete', this.subject);
5224 if (!this.callChain()) this.fireEvent('chainComplete', this.subject);
5226 this.fireEvent('stop', this.subject);
5233 if (this.isRunning()){
5235 pullInstance.call(this, this.options.fps);
5236 this.frame = this.frames;
5237 this.fireEvent('cancel', this.subject).clearChain();
5243 if (this.isRunning()){
5245 pullInstance.call(this, this.options.fps);
5251 if (this.isPaused()) pushInstance.call(this, this.options.fps);
5255 isRunning: function(){
5256 var list = instances[this.options.fps];
5257 return list && list.contains(this);
5260 isPaused: function(){
5261 return (this.frame < this.frames) && !this.isRunning();
5266 Fx.compute = function(from, to, delta){
5267 return (to - from) * delta + from;
5270 Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000};
5274 var instances = {}, timers = {};
5276 var loop = function(){
5277 var now = Date.now();
5278 for (var i = this.length; i--;){
5279 var instance = this[i];
5280 if (instance) instance.step(now);
5284 var pushInstance = function(fps){
5285 var list = instances[fps] || (instances[fps] = []);
5287 if (!timers[fps]) timers[fps] = loop.periodical(Math.round(1000 / fps), list);
5290 var pullInstance = function(fps){
5291 var list = instances[fps];
5294 if (!list.length && timers[fps]){
5295 delete instances[fps];
5296 timers[fps] = clearInterval(timers[fps]);
5308 description: Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements.
5310 license: MIT-style license.
5312 requires: [Fx, Element.Style]
5319 Fx.CSS = new Class({
5323 //prepares the base from/to object
5325 prepare: function(element, property, values){
5326 values = Array.from(values);
5327 var from = values[0], to = values[1];
5330 from = element.getStyle(property);
5331 var unit = this.options.unit;
5332 // adapted from: https://github.com/ryanmorr/fx/blob/master/fx.js#L299
5333 if (unit && from && typeof from == 'string' && from.slice(-unit.length) != unit && parseFloat(from) != 0){
5334 element.setStyle(property, to + unit);
5335 var value = element.getComputedStyle(property);
5336 // IE and Opera support pixelLeft or pixelWidth
5337 if (!(/px$/.test(value))){
5338 value = element.style[('pixel-' + property).camelCase()];
5340 // adapted from Dean Edwards' http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
5341 var left = element.style.left;
5342 element.style.left = to + unit;
5343 value = element.style.pixelLeft;
5344 element.style.left = left;
5347 from = (to || 1) / (parseFloat(value) || 1) * (parseFloat(from) || 0);
5348 element.setStyle(property, from + unit);
5351 return {from: this.parse(from), to: this.parse(to)};
5354 //parses a value into an array
5356 parse: function(value){
5357 value = Function.from(value)();
5358 value = (typeof value == 'string') ? value.split(' ') : Array.from(value);
5359 return value.map(function(val){
5362 Object.each(Fx.CSS.Parsers, function(parser, key){
5364 var parsed = parser.parse(val);
5365 if (parsed || parsed === 0) found = {value: parsed, parser: parser};
5367 found = found || {value: val, parser: Fx.CSS.Parsers.String};
5372 //computes by a from and to prepared objects, using their parsers.
5374 compute: function(from, to, delta){
5376 (Math.min(from.length, to.length)).times(function(i){
5377 computed.push({value: from[i].parser.compute(from[i].value, to[i].value, delta), parser: from[i].parser});
5379 computed.$family = Function.from('fx:css:value');
5383 //serves the value as settable
5385 serve: function(value, unit){
5386 if (typeOf(value) != 'fx:css:value') value = this.parse(value);
5388 value.each(function(bit){
5389 returned = returned.concat(bit.parser.serve(bit.value, unit));
5394 //renders the change to an element
5396 render: function(element, property, value, unit){
5397 element.setStyle(property, this.serve(value, unit));
5400 //searches inside the page css to find the values for a selector
5402 search: function(selector){
5403 if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector];
5404 var to = {}, selectorTest = new RegExp('^' + selector.escapeRegExp() + '$');
5406 var searchStyles = function(rules){
5407 Array.each(rules, function(rule, i){
5409 searchStyles(rule.rules || rule.cssRules);
5412 if (!rule.style) return;
5413 var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){
5414 return m.toLowerCase();
5416 if (!selectorText || !selectorTest.test(selectorText)) return;
5417 Object.each(Element.Styles, function(value, style){
5418 if (!rule.style[style] || Element.ShortStyles[style]) return;
5419 value = String(rule.style[style]);
5420 to[style] = ((/^rgb/).test(value)) ? value.rgbToHex() : value;
5425 Array.each(document.styleSheets, function(sheet, j){
5426 var href = sheet.href;
5427 if (href && href.indexOf('://') > -1 && href.indexOf(document.domain) == -1) return;
5428 var rules = sheet.rules || sheet.cssRules;
5429 searchStyles(rules);
5431 return Fx.CSS.Cache[selector] = to;
5441 parse: function(value){
5442 if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true);
5443 return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false;
5445 compute: function(from, to, delta){
5446 return from.map(function(value, i){
5447 return Math.round(Fx.compute(from[i], to[i], delta));
5450 serve: function(value){
5451 return value.map(Number);
5457 compute: Fx.compute,
5458 serve: function(value, unit){
5459 return (unit) ? value + unit : value;
5464 parse: Function.from(false),
5465 compute: function(zero, one){
5468 serve: function(zero){
5477 Fx.CSS.Parsers = new Hash(Fx.CSS.Parsers);
5486 description: Formerly Fx.Style, effect to transition any CSS property for an element.
5488 license: MIT-style license.
5492 provides: [Fx.Tween, Element.fade, Element.highlight]
5497 Fx.Tween = new Class({
5501 initialize: function(element, options){
5502 this.element = this.subject = document.id(element);
5503 this.parent(options);
5506 set: function(property, now){
5507 if (arguments.length == 1){
5509 property = this.property || this.options.property;
5511 this.render(this.element, property, now, this.options.unit);
5515 start: function(property, from, to){
5516 if (!this.check(property, from, to)) return this;
5517 var args = Array.flatten(arguments);
5518 this.property = this.options.property || args.shift();
5519 var parsed = this.prepare(this.element, this.property, args);
5520 return this.parent(parsed.from, parsed.to);
5525 Element.Properties.tween = {
5527 set: function(options){
5528 this.get('tween').cancel().setOptions(options);
5533 var tween = this.retrieve('tween');
5535 tween = new Fx.Tween(this, {link: 'cancel'});
5536 this.store('tween', tween);
5545 tween: function(property, from, to){
5546 this.get('tween').start(property, from, to);
5550 fade: function(how){
5551 var fade = this.get('tween'), method, args = ['opacity'].append(arguments), toggle;
5552 if (args[1] == null) args[1] = 'toggle';
5554 case 'in': method = 'start'; args[1] = 1; break;
5555 case 'out': method = 'start'; args[1] = 0; break;
5556 case 'show': method = 'set'; args[1] = 1; break;
5557 case 'hide': method = 'set'; args[1] = 0; break;
5559 var flag = this.retrieve('fade:flag', this.getStyle('opacity') == 1);
5561 args[1] = flag ? 0 : 1;
5562 this.store('fade:flag', !flag);
5565 default: method = 'start';
5567 if (!toggle) this.eliminate('fade:flag');
5568 fade[method].apply(fade, args);
5569 var to = args[args.length - 1];
5570 if (method == 'set' || to != 0) this.setStyle('visibility', to == 0 ? 'hidden' : 'visible');
5571 else fade.chain(function(){
5572 this.element.setStyle('visibility', 'hidden');
5578 highlight: function(start, end){
5580 end = this.retrieve('highlight:original', this.getStyle('background-color'));
5581 end = (end == 'transparent') ? '#fff' : end;
5583 var tween = this.get('tween');
5584 tween.start('background-color', start || '#ffff88', end).chain(function(){
5585 this.setStyle('background-color', this.retrieve('highlight:original'));
5598 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.
5600 license: MIT-style license.
5609 Fx.Morph = new Class({
5613 initialize: function(element, options){
5614 this.element = this.subject = document.id(element);
5615 this.parent(options);
5619 if (typeof now == 'string') now = this.search(now);
5620 for (var p in now) this.render(this.element, p, now[p], this.options.unit);
5624 compute: function(from, to, delta){
5626 for (var p in from) now[p] = this.parent(from[p], to[p], delta);
5630 start: function(properties){
5631 if (!this.check(properties)) return this;
5632 if (typeof properties == 'string') properties = this.search(properties);
5633 var from = {}, to = {};
5634 for (var p in properties){
5635 var parsed = this.prepare(this.element, p, properties[p]);
5636 from[p] = parsed.from;
5639 return this.parent(from, to);
5644 Element.Properties.morph = {
5646 set: function(options){
5647 this.get('morph').cancel().setOptions(options);
5652 var morph = this.retrieve('morph');
5654 morph = new Fx.Morph(this, {link: 'cancel'});
5655 this.store('morph', morph);
5664 morph: function(props){
5665 this.get('morph').start(props);
5674 name: Fx.Transitions
5676 description: Contains a set of advanced transitions to be used with any of the Fx Classes.
5678 license: MIT-style license.
5681 - Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>, modified and optimized to be used with MooTools.
5685 provides: Fx.Transitions
5692 getTransition: function(){
5693 var trans = this.options.transition || Fx.Transitions.Sine.easeInOut;
5694 if (typeof trans == 'string'){
5695 var data = trans.split(':');
5696 trans = Fx.Transitions;
5697 trans = trans[data[0]] || trans[data[0].capitalize()];
5698 if (data[1]) trans = trans['ease' + data[1].capitalize() + (data[2] ? data[2].capitalize() : '')];
5705 Fx.Transition = function(transition, params){
5706 params = Array.from(params);
5707 var easeIn = function(pos){
5708 return transition(pos, params);
5710 return Object.append(easeIn, {
5712 easeOut: function(pos){
5713 return 1 - transition(1 - pos, params);
5715 easeInOut: function(pos){
5716 return (pos <= 0.5 ? transition(2 * pos, params) : (2 - transition(2 * (1 - pos), params))) / 2;
5723 linear: function(zero){
5731 Fx.Transitions = new Hash(Fx.Transitions);
5735 Fx.Transitions.extend = function(transitions){
5736 for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]);
5739 Fx.Transitions.extend({
5741 Pow: function(p, x){
5742 return Math.pow(p, x && x[0] || 6);
5746 return Math.pow(2, 8 * (p - 1));
5750 return 1 - Math.sin(Math.acos(p));
5754 return 1 - Math.cos(p * Math.PI / 2);
5757 Back: function(p, x){
5758 x = x && x[0] || 1.618;
5759 return Math.pow(p, 2) * ((x + 1) * p - x);
5762 Bounce: function(p){
5764 for (var a = 0, b = 1; 1; a += b, b /= 2){
5765 if (p >= (7 - 4 * a) / 11){
5766 value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2);
5773 Elastic: function(p, x){
5774 return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x && x[0] || 1) / 3);
5779 ['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){
5780 Fx.Transitions[transition] = new Fx.Transition(function(p){
5781 return Math.pow(p, i + 2);
5790 description: Powerful all purpose Request Class. Uses XMLHTTPRequest.
5792 license: MIT-style license.
5794 requires: [Object, Element, Chain, Events, Options, Browser]
5803 var empty = function(){},
5804 progressSupport = ('onprogress' in new Browser.Request);
5806 var Request = this.Request = new Class({
5808 Implements: [Chain, Events, Options],
5811 onRequest: function(){},
5812 onLoadstart: function(event, xhr){},
5813 onProgress: function(event, xhr){},
5814 onComplete: function(){},
5815 onCancel: function(){},
5816 onSuccess: function(responseText, responseXML){},
5817 onFailure: function(xhr){},
5818 onException: function(headerName, value){},
5819 onTimeout: function(){},
5825 'X-Requested-With': 'XMLHttpRequest',
5826 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
5837 evalResponse: false,
5842 initialize: function(options){
5843 this.xhr = new Browser.Request();
5844 this.setOptions(options);
5845 this.headers = this.options.headers;
5848 onStateChange: function(){
5850 if (xhr.readyState != 4 || !this.running) return;
5851 this.running = false;
5853 Function.attempt(function(){
5854 var status = xhr.status;
5855 this.status = (status == 1223) ? 204 : status;
5857 xhr.onreadystatechange = empty;
5858 if (progressSupport) xhr.onprogress = xhr.onloadstart = empty;
5859 clearTimeout(this.timer);
5861 this.response = {text: this.xhr.responseText || '', xml: this.xhr.responseXML};
5862 if (this.options.isSuccess.call(this, this.status))
5863 this.success(this.response.text, this.response.xml);
5868 isSuccess: function(){
5869 var status = this.status;
5870 return (status >= 200 && status < 300);
5873 isRunning: function(){
5874 return !!this.running;
5877 processScripts: function(text){
5878 if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return Browser.exec(text);
5879 return text.stripScripts(this.options.evalScripts);
5882 success: function(text, xml){
5883 this.onSuccess(this.processScripts(text), xml);
5886 onSuccess: function(){
5887 this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain();
5890 failure: function(){
5894 onFailure: function(){
5895 this.fireEvent('complete').fireEvent('failure', this.xhr);
5898 loadstart: function(event){
5899 this.fireEvent('loadstart', [event, this.xhr]);
5902 progress: function(event){
5903 this.fireEvent('progress', [event, this.xhr]);
5906 timeout: function(){
5907 this.fireEvent('timeout', this.xhr);
5910 setHeader: function(name, value){
5911 this.headers[name] = value;
5915 getHeader: function(name){
5916 return Function.attempt(function(){
5917 return this.xhr.getResponseHeader(name);
5922 if (!this.running) return true;
5923 switch (this.options.link){
5924 case 'cancel': this.cancel(); return true;
5925 case 'chain': this.chain(this.caller.pass(arguments, this)); return false;
5930 send: function(options){
5931 if (!this.check(options)) return this;
5933 this.options.isSuccess = this.options.isSuccess || this.isSuccess;
5934 this.running = true;
5936 var type = typeOf(options);
5937 if (type == 'string' || type == 'element') options = {data: options};
5939 var old = this.options;
5940 options = Object.append({data: old.data, url: old.url, method: old.method}, options);
5941 var data = options.data, url = String(options.url), method = options.method.toLowerCase();
5943 switch (typeOf(data)){
5944 case 'element': data = document.id(data).toQueryString(); break;
5945 case 'object': case 'hash': data = Object.toQueryString(data);
5948 if (this.options.format){
5949 var format = 'format=' + this.options.format;
5950 data = (data) ? format + '&' + data : format;
5953 if (this.options.emulation && !['get', 'post'].contains(method)){
5954 var _method = '_method=' + method;
5955 data = (data) ? _method + '&' + data : _method;
5959 if (this.options.urlEncoded && ['post', 'put'].contains(method)){
5960 var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
5961 this.headers['Content-type'] = 'application/x-www-form-urlencoded' + encoding;
5964 if (!url) url = document.location.pathname;
5966 var trimPosition = url.lastIndexOf('/');
5967 if (trimPosition > -1 && (trimPosition = url.indexOf('#')) > -1) url = url.substr(0, trimPosition);
5969 if (this.options.noCache)
5970 url += (url.indexOf('?') > -1 ? '&' : '?') + String.uniqueID();
5972 if (data && (method == 'get' || method == 'delete')){
5973 url += (url.indexOf('?') > -1 ? '&' : '?') + data;
5978 if (progressSupport){
5979 xhr.onloadstart = this.loadstart.bind(this);
5980 xhr.onprogress = this.progress.bind(this);
5983 xhr.open(method.toUpperCase(), url, this.options.async, this.options.user, this.options.password);
5984 if (this.options.user && 'withCredentials' in xhr) xhr.withCredentials = true;
5986 xhr.onreadystatechange = this.onStateChange.bind(this);
5988 Object.each(this.headers, function(value, key){
5990 xhr.setRequestHeader(key, value);
5992 this.fireEvent('exception', [key, value]);
5996 this.fireEvent('request');
5998 if (!this.options.async) this.onStateChange();
5999 else if (this.options.timeout) this.timer = this.timeout.delay(this.options.timeout, this);
6004 if (!this.running) return this;
6005 this.running = false;
6008 clearTimeout(this.timer);
6009 xhr.onreadystatechange = empty;
6010 if (progressSupport) xhr.onprogress = xhr.onloadstart = empty;
6011 this.xhr = new Browser.Request();
6012 this.fireEvent('cancel');
6019 ['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){
6020 methods[method] = function(data){
6024 if (data != null) object.data = data;
6025 return this.send(object);
6029 Request.implement(methods);
6031 Element.Properties.send = {
6033 set: function(options){
6034 var send = this.get('send').cancel();
6035 send.setOptions(options);
6040 var send = this.retrieve('send');
6042 send = new Request({
6043 data: this, link: 'cancel', method: this.get('method') || 'post', url: this.get('action')
6045 this.store('send', send);
6054 send: function(url){
6055 var sender = this.get('send');
6056 sender.send({data: this, url: url || sender.options.url});
6069 description: Extends the basic Request Class with additional methods for interacting with HTML responses.
6071 license: MIT-style license.
6073 requires: [Element, Request]
6075 provides: Request.HTML
6080 Request.HTML = new Class({
6090 Accept: 'text/html, application/xml, text/xml, */*'
6094 success: function(text){
6095 var options = this.options, response = this.response;
6097 response.html = text.stripScripts(function(script){
6098 response.javascript = script;
6101 var match = response.html.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
6102 if (match) response.html = match[1];
6103 var temp = new Element('div').set('html', response.html);
6105 response.tree = temp.childNodes;
6106 response.elements = temp.getElements(options.filter || '*');
6108 if (options.filter) response.tree = response.elements;
6109 if (options.update){
6110 var update = document.id(options.update).empty();
6111 if (options.filter) update.adopt(response.elements);
6112 else update.set('html', response.html);
6113 } else if (options.append){
6114 var append = document.id(options.append);
6115 if (options.filter) response.elements.reverse().inject(append);
6116 else append.adopt(temp.getChildren());
6118 if (options.evalScripts) Browser.exec(response.javascript);
6120 this.onSuccess(response.tree, response.elements, response.html, response.javascript);
6125 Element.Properties.load = {
6127 set: function(options){
6128 var load = this.get('load').cancel();
6129 load.setOptions(options);
6134 var load = this.retrieve('load');
6136 load = new Request.HTML({data: this, link: 'cancel', update: this, method: 'get'});
6137 this.store('load', load);
6147 this.get('load').send(Array.link(arguments, {data: Type.isObject, url: Type.isString}));
6158 description: JSON encoder and decoder.
6160 license: MIT-style license.
6162 SeeAlso: <http://www.json.org/>
6164 requires: [Array, String, Number, Function]
6171 if (typeof JSON == 'undefined') this.JSON = {};
6176 stringify: JSON.stringify,
6184 var special = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'};
6186 var escape = function(chr){
6187 return special[chr] || '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).slice(-4);
6190 JSON.validate = function(string){
6191 string = string.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
6192 replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
6193 replace(/(?:^|:|,)(?:\s*\[)+/g, '');
6195 return (/^[\],:{}\s]*$/).test(string);
6198 JSON.encode = JSON.stringify ? function(obj){
6199 return JSON.stringify(obj);
6201 if (obj && obj.toJSON) obj = obj.toJSON();
6203 switch (typeOf(obj)){
6205 return '"' + obj.replace(/[\x00-\x1f\\"]/g, escape) + '"';
6207 return '[' + obj.map(JSON.encode).clean() + ']';
6208 case 'object': case 'hash':
6210 Object.each(obj, function(value, key){
6211 var json = JSON.encode(value);
6212 if (json) string.push(JSON.encode(key) + ':' + json);
6214 return '{' + string + '}';
6215 case 'number': case 'boolean': return '' + obj;
6216 case 'null': return 'null';
6224 JSON.secure = false;
6227 JSON.decode = function(string, secure){
6228 if (!string || typeOf(string) != 'string') return null;
6230 if (secure == null) secure = JSON.secure;
6232 if (JSON.parse) return JSON.parse(string);
6233 if (!JSON.validate(string)) throw new Error('JSON could not decode the input; security is enabled and the value is not secure.');
6236 return eval('(' + string + ')');
6246 description: Extends the basic Request Class with additional methods for sending and receiving JSON data.
6248 license: MIT-style license.
6250 requires: [Request, JSON]
6252 provides: Request.JSON
6257 Request.JSON = new Class({
6262 /*onError: function(text, error){},*/
6266 initialize: function(options){
6267 this.parent(options);
6268 Object.append(this.headers, {
6269 'Accept': 'application/json',
6274 success: function(text){
6277 json = this.response.json = JSON.decode(text, this.options.secure);
6279 this.fireEvent('error', [text, error]);
6282 if (json == null) this.onFailure();
6283 else this.onSuccess(json, text);
6293 description: Class for creating, reading, and deleting browser Cookies.
6295 license: MIT-style license.
6298 - Based on the functions by Peter-Paul Koch (http://quirksmode.org).
6300 requires: [Options, Browser]
6307 var Cookie = new Class({
6309 Implements: Options,
6320 initialize: function(key, options){
6322 this.setOptions(options);
6325 write: function(value){
6326 if (this.options.encode) value = encodeURIComponent(value);
6327 if (this.options.domain) value += '; domain=' + this.options.domain;
6328 if (this.options.path) value += '; path=' + this.options.path;
6329 if (this.options.duration){
6330 var date = new Date();
6331 date.setTime(date.getTime() + this.options.duration * 24 * 60 * 60 * 1000);
6332 value += '; expires=' + date.toGMTString();
6334 if (this.options.secure) value += '; secure';
6335 this.options.document.cookie = this.key + '=' + value;
6340 var value = this.options.document.cookie.match('(?:^|;)\\s*' + this.key.escapeRegExp() + '=([^;]*)');
6341 return (value) ? decodeURIComponent(value[1]) : null;
6344 dispose: function(){
6345 new Cookie(this.key, Object.merge({}, this.options, {duration: -1})).write('');
6351 Cookie.write = function(key, value, options){
6352 return new Cookie(key, options).write(value);
6355 Cookie.read = function(key){
6356 return new Cookie(key).read();
6359 Cookie.dispose = function(key, options){
6360 return new Cookie(key, options).dispose();
6368 description: Contains the custom event domready.
6370 license: MIT-style license.
6372 requires: [Browser, Element, Element.Event]
6374 provides: [DOMReady, DomReady]
6379 (function(window, document){
6386 testElement = document.createElement('div');
6388 var domready = function(){
6389 clearTimeout(timer);
6391 Browser.loaded = ready = true;
6392 document.removeListener('DOMContentLoaded', domready).removeListener('readystatechange', check);
6394 document.fireEvent('domready');
6395 window.fireEvent('domready');
6398 var check = function(){
6399 for (var i = checks.length; i--;) if (checks[i]()){
6406 var poll = function(){
6407 clearTimeout(timer);
6408 if (!check()) timer = setTimeout(poll, 10);
6411 document.addListener('DOMContentLoaded', domready);
6414 // doScroll technique by Diego Perini http://javascript.nwbox.com/IEContentLoaded/
6415 // testElement.doScroll() throws when the DOM is not ready, only in the top window
6416 var doScrollWorks = function(){
6418 testElement.doScroll();
6423 // If doScroll works already, it can't be used to determine domready
6424 // e.g. in an iframe
6425 if (testElement.doScroll && !doScrollWorks()){
6426 checks.push(doScrollWorks);
6431 if (document.readyState) checks.push(function(){
6432 var state = document.readyState;
6433 return (state == 'loaded' || state == 'complete');
6436 if ('onreadystatechange' in document) document.addListener('readystatechange', check);
6437 else shouldPoll = true;
6439 if (shouldPoll) poll();
6441 Element.Events.domready = {
6442 onAdd: function(fn){
6443 if (ready) fn.call(this);
6447 // Make sure that domready fires before load
6448 Element.Events.load = {
6450 onAdd: function(fn){
6451 if (loaded && this == window) fn.call(this);
6453 condition: function(){
6454 if (this == window){
6456 delete Element.Events.load;
6462 // This is based on the custom load event
6463 window.addEvent('load', function(){
6467 })(window, document);