UNPKG

25.2 kBJavaScriptView Raw
1/*
2---
3
4name: Core
5
6description: The heart of MooTools.
7
8license: MIT-style license.
9
10copyright: Copyright (c) 2006-2015 [Valerio Proietti](http://mad4milk.net/).
11
12authors: The MooTools production team (http://mootools.net/developers/)
13
14inspiration:
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)
17
18provides: [Core, MooTools, Type, typeOf, instanceOf, Native]
19
20...
21*/
22/*! MooTools: the javascript framework. license: MIT-style license. copyright: Copyright (c) 2006-2015 [Valerio Proietti](http://mad4milk.net/).*/
23(function(){
24
25this.MooTools = {
26 version: '1.5.2',
27 build: 'ed01297a1a19de0675404640e7377cf97694e131'
28};
29
30// typeOf, instanceOf
31
32var typeOf = this.typeOf = function(item){
33 if (item == null) return 'null';
34 if (item.$family != null) return item.$family();
35
36 if (item.nodeName){
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';
42 }
43
44 return typeof item;
45};
46
47var instanceOf = this.instanceOf = function(item, object){
48 if (item == null) return false;
49 var constructor = item.$constructor || item.constructor;
50 while (constructor){
51 if (constructor === object) return true;
52 constructor = constructor.parent;
53 }
54
55 return item instanceof object;
56};
57
58var hasOwnProperty = Object.prototype.hasOwnProperty;
59
60
61
62// Function overloading
63
64var Function = this.Function;
65
66Function.prototype.overloadSetter = function(usePlural){
67 var self = this;
68 return function(a, b){
69 if (a == null) return this;
70 if (usePlural || typeof a != 'string'){
71 for (var k in a) self.call(this, k, a[k]);
72
73 } else {
74 self.call(this, a, b);
75 }
76 return this;
77 };
78};
79
80Function.prototype.overloadGetter = function(usePlural){
81 var self = this;
82 return function(a){
83 var args, result;
84 if (typeof a != 'string') args = a;
85 else if (arguments.length > 1) args = arguments;
86 else if (usePlural) args = [a];
87 if (args){
88 result = {};
89 for (var i = 0; i < args.length; i++) result[args[i]] = self.call(this, args[i]);
90 } else {
91 result = self.call(this, a);
92 }
93 return result;
94 };
95};
96
97Function.prototype.extend = function(key, value){
98 this[key] = value;
99}.overloadSetter();
100
101Function.prototype.implement = function(key, value){
102 this.prototype[key] = value;
103}.overloadSetter();
104
105// From
106
107var slice = Array.prototype.slice;
108
109Function.from = function(item){
110 return (typeOf(item) == 'function') ? item : function(){
111 return item;
112 };
113};
114
115Array.from = function(item){
116 if (item == null) return [];
117 return (Type.isEnumerable(item) && typeof item != 'string') ? (typeOf(item) == 'array') ? item : slice.call(item) : [item];
118};
119
120Number.from = function(item){
121 var number = parseFloat(item);
122 return isFinite(number) ? number : null;
123};
124
125String.from = function(item){
126 return item + '';
127};
128
129// hide, protect
130
131Function.implement({
132
133 hide: function(){
134 this.$hidden = true;
135 return this;
136 },
137
138 protect: function(){
139 this.$protected = true;
140 return this;
141 }
142
143});
144
145// Type
146
147var Type = this.Type = function(name, object){
148 if (name){
149 var lower = name.toLowerCase();
150 var typeCheck = function(item){
151 return (typeOf(item) == lower);
152 };
153
154 Type['is' + name] = typeCheck;
155 if (object != null){
156 object.prototype.$family = (function(){
157 return lower;
158 }).hide();
159
160 }
161 }
162
163 if (object == null) return null;
164
165 object.extend(this);
166 object.$constructor = Type;
167 object.prototype.$constructor = object;
168
169 return object;
170};
171
172var toString = Object.prototype.toString;
173
174Type.isEnumerable = function(item){
175 return (item != null && typeof item.length == 'number' && toString.call(item) != '[object Function]' );
176};
177
178var hooks = {};
179
180var hooksOf = function(object){
181 var type = typeOf(object.prototype);
182 return hooks[type] || (hooks[type] = []);
183};
184
185var implement = function(name, method){
186 if (method && method.$hidden) return;
187
188 var hooks = hooksOf(this);
189
190 for (var i = 0; i < hooks.length; i++){
191 var hook = hooks[i];
192 if (typeOf(hook) == 'type') implement.call(hook, name, method);
193 else hook.call(this, name, method);
194 }
195
196 var previous = this.prototype[name];
197 if (previous == null || !previous.$protected) this.prototype[name] = method;
198
199 if (this[name] == null && typeOf(method) == 'function') extend.call(this, name, function(item){
200 return method.apply(item, slice.call(arguments, 1));
201 });
202};
203
204var extend = function(name, method){
205 if (method && method.$hidden) return;
206 var previous = this[name];
207 if (previous == null || !previous.$protected) this[name] = method;
208};
209
210Type.implement({
211
212 implement: implement.overloadSetter(),
213
214 extend: extend.overloadSetter(),
215
216 alias: function(name, existing){
217 implement.call(this, name, this.prototype[existing]);
218 }.overloadSetter(),
219
220 mirror: function(hook){
221 hooksOf(this).push(hook);
222 return this;
223 }
224
225});
226
227new Type('Type', Type);
228
229// Default Types
230
231var force = function(name, object, methods){
232 var isType = (object != Object),
233 prototype = object.prototype;
234
235 if (isType) object = new Type(name, object);
236
237 for (var i = 0, l = methods.length; i < l; i++){
238 var key = methods[i],
239 generic = object[key],
240 proto = prototype[key];
241
242 if (generic) generic.protect();
243 if (isType && proto) object.implement(key, proto.protect());
244 }
245
246 if (isType){
247 var methodsEnumerable = prototype.propertyIsEnumerable(methods[0]);
248 object.forEachMethod = function(fn){
249 if (!methodsEnumerable) for (var i = 0, l = methods.length; i < l; i++){
250 fn.call(prototype, prototype[methods[i]], methods[i]);
251 }
252 for (var key in prototype) fn.call(prototype, prototype[key], key);
253 };
254 }
255
256 return force;
257};
258
259force('String', String, [
260 'charAt', 'charCodeAt', 'concat', 'contains', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search',
261 'slice', 'split', 'substr', 'substring', 'trim', 'toLowerCase', 'toUpperCase'
262])('Array', Array, [
263 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice',
264 'indexOf', 'lastIndexOf', 'filter', 'forEach', 'every', 'map', 'some', 'reduce', 'reduceRight', 'contains'
265])('Number', Number, [
266 'toExponential', 'toFixed', 'toLocaleString', 'toPrecision'
267])('Function', Function, [
268 'apply', 'call', 'bind'
269])('RegExp', RegExp, [
270 'exec', 'test'
271])('Object', Object, [
272 'create', 'defineProperty', 'defineProperties', 'keys',
273 'getPrototypeOf', 'getOwnPropertyDescriptor', 'getOwnPropertyNames',
274 'preventExtensions', 'isExtensible', 'seal', 'isSealed', 'freeze', 'isFrozen'
275])('Date', Date, ['now']);
276
277Object.extend = extend.overloadSetter();
278
279Date.extend('now', function(){
280 return +(new Date);
281});
282
283new Type('Boolean', Boolean);
284
285// fixes NaN returning as Number
286
287Number.prototype.$family = function(){
288 return isFinite(this) ? 'number' : 'null';
289}.hide();
290
291// Number.random
292
293Number.extend('random', function(min, max){
294 return Math.floor(Math.random() * (max - min + 1) + min);
295});
296
297// forEach, each, keys
298
299Array.implement({
300
301
302
303 each: function(fn, bind){
304 Array.forEach(this, fn, bind);
305 return this;
306 }
307
308});
309
310Object.extend({
311
312 keys: function(object){
313 var keys = [];
314 for (var k in object){
315 if (hasOwnProperty.call(object, k)) keys.push(k);
316 }
317
318 return keys;
319 },
320
321 forEach: function(object, fn, bind){
322 Object.keys(object).forEach(function(key){
323 fn.call(bind, object[key], key, object);
324 });
325 }
326
327});
328
329Object.each = Object.forEach;
330
331
332// Array & Object cloning, Object merging and appending
333
334var cloneOf = function(item){
335 switch (typeOf(item)){
336 case 'array': return item.clone();
337 case 'object': return Object.clone(item);
338 default: return item;
339 }
340};
341
342Array.implement('clone', function(){
343 var i = this.length, clone = new Array(i);
344 while (i--) clone[i] = cloneOf(this[i]);
345 return clone;
346});
347
348var mergeOne = function(source, key, current){
349 switch (typeOf(current)){
350 case 'object':
351 if (typeOf(source[key]) == 'object') Object.merge(source[key], current);
352 else source[key] = Object.clone(current);
353 break;
354 case 'array': source[key] = current.clone(); break;
355 default: source[key] = current;
356 }
357 return source;
358};
359
360Object.extend({
361
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]);
367 }
368 return source;
369 },
370
371 clone: function(object){
372 var clone = {};
373 for (var key in object) clone[key] = cloneOf(object[key]);
374 return clone;
375 },
376
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];
381 }
382 return original;
383 }
384
385});
386
387// Object-less types
388
389['Object', 'WhiteSpace', 'TextNode', 'Collection', 'Arguments'].each(function(name){
390 new Type(name);
391});
392
393// Unique ID
394
395var UID = Date.now();
396
397String.extend('uniqueID', function(){
398 return (UID++).toString(36);
399});
400
401
402
403})();
404
405/*
406---
407
408name: Array
409
410description: Contains Array Prototypes like each, contains, and erase.
411
412license: MIT-style license.
413
414requires: [Type]
415
416provides: Array
417
418...
419*/
420
421Array.implement({
422
423
424
425 clean: function(){
426 return this.filter(function(item){
427 return item != null;
428 });
429 },
430
431 invoke: function(methodName){
432 var args = Array.slice(arguments, 1);
433 return this.map(function(item){
434 return item[methodName].apply(item, args);
435 });
436 },
437
438 associate: function(keys){
439 var obj = {}, length = Math.min(this.length, keys.length);
440 for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
441 return obj;
442 },
443
444 link: function(object){
445 var result = {};
446 for (var i = 0, l = this.length; i < l; i++){
447 for (var key in object){
448 if (object[key](this[i])){
449 result[key] = this[i];
450 delete object[key];
451 break;
452 }
453 }
454 }
455 return result;
456 },
457
458 contains: function(item, from){
459 return this.indexOf(item, from) != -1;
460 },
461
462 append: function(array){
463 this.push.apply(this, array);
464 return this;
465 },
466
467 getLast: function(){
468 return (this.length) ? this[this.length - 1] : null;
469 },
470
471 getRandom: function(){
472 return (this.length) ? this[Number.random(0, this.length - 1)] : null;
473 },
474
475 include: function(item){
476 if (!this.contains(item)) this.push(item);
477 return this;
478 },
479
480 combine: function(array){
481 for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
482 return this;
483 },
484
485 erase: function(item){
486 for (var i = this.length; i--;){
487 if (this[i] === item) this.splice(i, 1);
488 }
489 return this;
490 },
491
492 empty: function(){
493 this.length = 0;
494 return this;
495 },
496
497 flatten: function(){
498 var array = [];
499 for (var i = 0, l = this.length; i < l; i++){
500 var type = typeOf(this[i]);
501 if (type == 'null') continue;
502 array = array.concat((type == 'array' || type == 'collection' || type == 'arguments' || instanceOf(this[i], Array)) ? Array.flatten(this[i]) : this[i]);
503 }
504 return array;
505 },
506
507 pick: function(){
508 for (var i = 0, l = this.length; i < l; i++){
509 if (this[i] != null) return this[i];
510 }
511 return null;
512 },
513
514 hexToRgb: function(array){
515 if (this.length != 3) return null;
516 var rgb = this.map(function(value){
517 if (value.length == 1) value += value;
518 return parseInt(value, 16);
519 });
520 return (array) ? rgb : 'rgb(' + rgb + ')';
521 },
522
523 rgbToHex: function(array){
524 if (this.length < 3) return null;
525 if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
526 var hex = [];
527 for (var i = 0; i < 3; i++){
528 var bit = (this[i] - 0).toString(16);
529 hex.push((bit.length == 1) ? '0' + bit : bit);
530 }
531 return (array) ? hex : '#' + hex.join('');
532 }
533
534});
535
536
537
538/*
539---
540
541name: String
542
543description: Contains String Prototypes like camelCase, capitalize, test, and toInt.
544
545license: MIT-style license.
546
547requires: [Type, Array]
548
549provides: String
550
551...
552*/
553
554String.implement({
555
556 //<!ES6>
557 contains: function(string, index){
558 return (index ? String(this).slice(index) : String(this)).indexOf(string) > -1;
559 },
560 //</!ES6>
561
562 test: function(regex, params){
563 return ((typeOf(regex) == 'regexp') ? regex : new RegExp('' + regex, params)).test(this);
564 },
565
566 trim: function(){
567 return String(this).replace(/^\s+|\s+$/g, '');
568 },
569
570 clean: function(){
571 return String(this).replace(/\s+/g, ' ').trim();
572 },
573
574 camelCase: function(){
575 return String(this).replace(/-\D/g, function(match){
576 return match.charAt(1).toUpperCase();
577 });
578 },
579
580 hyphenate: function(){
581 return String(this).replace(/[A-Z]/g, function(match){
582 return ('-' + match.charAt(0).toLowerCase());
583 });
584 },
585
586 capitalize: function(){
587 return String(this).replace(/\b[a-z]/g, function(match){
588 return match.toUpperCase();
589 });
590 },
591
592 escapeRegExp: function(){
593 return String(this).replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
594 },
595
596 toInt: function(base){
597 return parseInt(this, base || 10);
598 },
599
600 toFloat: function(){
601 return parseFloat(this);
602 },
603
604 hexToRgb: function(array){
605 var hex = String(this).match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
606 return (hex) ? hex.slice(1).hexToRgb(array) : null;
607 },
608
609 rgbToHex: function(array){
610 var rgb = String(this).match(/\d{1,3}/g);
611 return (rgb) ? rgb.rgbToHex(array) : null;
612 },
613
614 substitute: function(object, regexp){
615 return String(this).replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){
616 if (match.charAt(0) == '\\') return match.slice(1);
617 return (object[name] != null) ? object[name] : '';
618 });
619 }
620
621});
622
623
624
625/*
626---
627
628name: Number
629
630description: Contains Number Prototypes like limit, round, times, and ceil.
631
632license: MIT-style license.
633
634requires: Type
635
636provides: Number
637
638...
639*/
640
641Number.implement({
642
643 limit: function(min, max){
644 return Math.min(max, Math.max(min, this));
645 },
646
647 round: function(precision){
648 precision = Math.pow(10, precision || 0).toFixed(precision < 0 ? -precision : 0);
649 return Math.round(this * precision) / precision;
650 },
651
652 times: function(fn, bind){
653 for (var i = 0; i < this; i++) fn.call(bind, i, this);
654 },
655
656 toFloat: function(){
657 return parseFloat(this);
658 },
659
660 toInt: function(base){
661 return parseInt(this, base || 10);
662 }
663
664});
665
666Number.alias('each', 'times');
667
668(function(math){
669 var methods = {};
670 math.each(function(name){
671 if (!Number[name]) methods[name] = function(){
672 return Math[name].apply(null, [this].concat(Array.from(arguments)));
673 };
674 });
675 Number.implement(methods);
676})(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']);
677
678/*
679---
680
681name: Function
682
683description: Contains Function Prototypes like create, bind, pass, and delay.
684
685license: MIT-style license.
686
687requires: Type
688
689provides: Function
690
691...
692*/
693
694Function.extend({
695
696 attempt: function(){
697 for (var i = 0, l = arguments.length; i < l; i++){
698 try {
699 return arguments[i]();
700 } catch (e){}
701 }
702 return null;
703 }
704
705});
706
707Function.implement({
708
709 attempt: function(args, bind){
710 try {
711 return this.apply(bind, Array.from(args));
712 } catch (e){}
713
714 return null;
715 },
716
717
718
719 pass: function(args, bind){
720 var self = this;
721 if (args != null) args = Array.from(args);
722 return function(){
723 return self.apply(bind, args || arguments);
724 };
725 },
726
727 delay: function(delay, bind, args){
728 return setTimeout(this.pass((args == null ? [] : args), bind), delay);
729 },
730
731 periodical: function(periodical, bind, args){
732 return setInterval(this.pass((args == null ? [] : args), bind), periodical);
733 }
734
735});
736
737
738
739/*
740---
741
742name: Object
743
744description: Object generic methods
745
746license: MIT-style license.
747
748requires: Type
749
750provides: [Object, Hash]
751
752...
753*/
754
755(function(){
756
757var hasOwnProperty = Object.prototype.hasOwnProperty;
758
759Object.extend({
760
761 subset: function(object, keys){
762 var results = {};
763 for (var i = 0, l = keys.length; i < l; i++){
764 var k = keys[i];
765 if (k in object) results[k] = object[k];
766 }
767 return results;
768 },
769
770 map: function(object, fn, bind){
771 var results = {};
772 var keys = Object.keys(object);
773 for (var i = 0; i < keys.length; i++){
774 var key = keys[i];
775 results[key] = fn.call(bind, object[key], key, object);
776 }
777 return results;
778 },
779
780 filter: function(object, fn, bind){
781 var results = {};
782 var keys = Object.keys(object);
783 for (var i = 0; i < keys.length; i++){
784 var key = keys[i], value = object[key];
785 if (fn.call(bind, value, key, object)) results[key] = value;
786 }
787 return results;
788 },
789
790 every: function(object, fn, bind){
791 var keys = Object.keys(object);
792 for (var i = 0; i < keys.length; i++){
793 var key = keys[i];
794 if (!fn.call(bind, object[key], key)) return false;
795 }
796 return true;
797 },
798
799 some: function(object, fn, bind){
800 var keys = Object.keys(object);
801 for (var i = 0; i < keys.length; i++){
802 var key = keys[i];
803 if (fn.call(bind, object[key], key)) return true;
804 }
805 return false;
806 },
807
808 values: function(object){
809 var values = [];
810 var keys = Object.keys(object);
811 for (var i = 0; i < keys.length; i++){
812 var k = keys[i];
813 values.push(object[k]);
814 }
815 return values;
816 },
817
818 getLength: function(object){
819 return Object.keys(object).length;
820 },
821
822 keyOf: function(object, value){
823 var keys = Object.keys(object);
824 for (var i = 0; i < keys.length; i++){
825 var key = keys[i];
826 if (object[key] === value) return key;
827 }
828 return null;
829 },
830
831 contains: function(object, value){
832 return Object.keyOf(object, value) != null;
833 },
834
835 toQueryString: function(object, base){
836 var queryString = [];
837
838 Object.each(object, function(value, key){
839 if (base) key = base + '[' + key + ']';
840 var result;
841 switch (typeOf(value)){
842 case 'object': result = Object.toQueryString(value, key); break;
843 case 'array':
844 var qs = {};
845 value.each(function(val, i){
846 qs[i] = val;
847 });
848 result = Object.toQueryString(qs, key);
849 break;
850 default: result = key + '=' + encodeURIComponent(value);
851 }
852 if (value != null) queryString.push(result);
853 });
854
855 return queryString.join('&');
856 }
857
858});
859
860})();
861
862
863
864/*
865---
866
867name: Class
868
869description: Contains the Class Function for easily creating, extending, and implementing reusable Classes.
870
871license: MIT-style license.
872
873requires: [Array, String, Function, Number]
874
875provides: Class
876
877...
878*/
879
880(function(){
881
882var Class = this.Class = new Type('Class', function(params){
883 if (instanceOf(params, Function)) params = {initialize: params};
884
885 var newClass = function(){
886 reset(this);
887 if (newClass.$prototyping) return this;
888 this.$caller = null;
889 this.$family = null;
890 var value = (this.initialize) ? this.initialize.apply(this, arguments) : this;
891 this.$caller = this.caller = null;
892 return value;
893 }.extend(this).implement(params);
894
895 newClass.$constructor = Class;
896 newClass.prototype.$constructor = newClass;
897 newClass.prototype.parent = parent;
898
899 return newClass;
900});
901
902var parent = function(){
903 if (!this.$caller) throw new Error('The method "parent" cannot be called.');
904 var name = this.$caller.$name,
905 parent = this.$caller.$owner.parent,
906 previous = (parent) ? parent.prototype[name] : null;
907 if (!previous) throw new Error('The method "' + name + '" has no parent.');
908 return previous.apply(this, arguments);
909};
910
911var reset = function(object){
912 for (var key in object){
913 var value = object[key];
914 switch (typeOf(value)){
915 case 'object':
916 var F = function(){};
917 F.prototype = value;
918 object[key] = reset(new F);
919 break;
920 case 'array': object[key] = value.clone(); break;
921 }
922 }
923 return object;
924};
925
926var wrap = function(self, key, method){
927 if (method.$origin) method = method.$origin;
928 var wrapper = function(){
929 if (method.$protected && this.$caller == null) throw new Error('The method "' + key + '" cannot be called.');
930 var caller = this.caller, current = this.$caller;
931 this.caller = current; this.$caller = wrapper;
932 var result = method.apply(this, arguments);
933 this.$caller = current; this.caller = caller;
934 return result;
935 }.extend({$owner: self, $origin: method, $name: key});
936 return wrapper;
937};
938
939var implement = function(key, value, retain){
940 if (Class.Mutators.hasOwnProperty(key)){
941 value = Class.Mutators[key].call(this, value);
942 if (value == null) return this;
943 }
944
945 if (typeOf(value) == 'function'){
946 if (value.$hidden) return this;
947 this.prototype[key] = (retain) ? value : wrap(this, key, value);
948 } else {
949 Object.merge(this.prototype, key, value);
950 }
951
952 return this;
953};
954
955var getInstance = function(klass){
956 klass.$prototyping = true;
957 var proto = new klass;
958 delete klass.$prototyping;
959 return proto;
960};
961
962Class.implement('implement', implement.overloadSetter());
963
964Class.Mutators = {
965
966 Extends: function(parent){
967 this.parent = parent;
968 this.prototype = getInstance(parent);
969 },
970
971 Implements: function(items){
972 Array.from(items).each(function(item){
973 var instance = new item;
974 for (var key in instance) implement.call(this, key, instance[key], true);
975 }, this);
976 }
977};
978
979})();
980
981/*
982---
983
984name: Class.Extras
985
986description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks.
987
988license: MIT-style license.
989
990requires: Class
991
992provides: [Class.Extras, Chain, Events, Options]
993
994...
995*/
996
997(function(){
998
999this.Chain = new Class({
1000
1001 $chain: [],
1002
1003 chain: function(){
1004 this.$chain.append(Array.flatten(arguments));
1005 return this;
1006 },
1007
1008 callChain: function(){
1009 return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false;
1010 },
1011
1012 clearChain: function(){
1013 this.$chain.empty();
1014 return this;
1015 }
1016
1017});
1018
1019var removeOn = function(string){
1020 return string.replace(/^on([A-Z])/, function(full, first){
1021 return first.toLowerCase();
1022 });
1023};
1024
1025this.Events = new Class({
1026
1027 $events: {},
1028
1029 addEvent: function(type, fn, internal){
1030 type = removeOn(type);
1031
1032
1033
1034 this.$events[type] = (this.$events[type] || []).include(fn);
1035 if (internal) fn.internal = true;
1036 return this;
1037 },
1038
1039 addEvents: function(events){
1040 for (var type in events) this.addEvent(type, events[type]);
1041 return this;
1042 },
1043
1044 fireEvent: function(type, args, delay){
1045 type = removeOn(type);
1046 var events = this.$events[type];
1047 if (!events) return this;
1048 args = Array.from(args);
1049 events.each(function(fn){
1050 if (delay) fn.delay(delay, this, args);
1051 else fn.apply(this, args);
1052 }, this);
1053 return this;
1054 },
1055
1056 removeEvent: function(type, fn){
1057 type = removeOn(type);
1058 var events = this.$events[type];
1059 if (events && !fn.internal){
1060 var index = events.indexOf(fn);
1061 if (index != -1) delete events[index];
1062 }
1063 return this;
1064 },
1065
1066 removeEvents: function(events){
1067 var type;
1068 if (typeOf(events) == 'object'){
1069 for (type in events) this.removeEvent(type, events[type]);
1070 return this;
1071 }
1072 if (events) events = removeOn(events);
1073 for (type in this.$events){
1074 if (events && events != type) continue;
1075 var fns = this.$events[type];
1076 for (var i = fns.length; i--;) if (i in fns){
1077 this.removeEvent(type, fns[i]);
1078 }
1079 }
1080 return this;
1081 }
1082
1083});
1084
1085this.Options = new Class({
1086
1087 setOptions: function(){
1088 var options = this.options = Object.merge.apply(null, [{}, this.options].append(arguments));
1089 if (this.addEvent) for (var option in options){
1090 if (typeOf(options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue;
1091 this.addEvent(option, options[option]);
1092 delete options[option];
1093 }
1094 return this;
1095 }
1096
1097});
1098
1099})();
1100
1101/*
1102---
1103
1104name: JSON
1105
1106description: JSON encoder and decoder.
1107
1108license: MIT-style license.
1109
1110SeeAlso: <http://www.json.org/>
1111
1112requires: [Array, String, Number, Function]
1113
1114provides: JSON
1115
1116...
1117*/
1118
1119if (typeof JSON == 'undefined') this.JSON = {};
1120
1121
1122
1123(function(){
1124
1125var special = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'};
1126
1127var escape = function(chr){
1128 return special[chr] || '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).slice(-4);
1129};
1130
1131JSON.validate = function(string){
1132 string = string.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
1133 replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
1134 replace(/(?:^|:|,)(?:\s*\[)+/g, '');
1135
1136 return (/^[\],:{}\s]*$/).test(string);
1137};
1138
1139JSON.encode = JSON.stringify ? function(obj){
1140 return JSON.stringify(obj);
1141} : function(obj){
1142 if (obj && obj.toJSON) obj = obj.toJSON();
1143
1144 switch (typeOf(obj)){
1145 case 'string':
1146 return '"' + obj.replace(/[\x00-\x1f\\"]/g, escape) + '"';
1147 case 'array':
1148 return '[' + obj.map(JSON.encode).clean() + ']';
1149 case 'object': case 'hash':
1150 var string = [];
1151 Object.each(obj, function(value, key){
1152 var json = JSON.encode(value);
1153 if (json) string.push(JSON.encode(key) + ':' + json);
1154 });
1155 return '{' + string + '}';
1156 case 'number': case 'boolean': return '' + obj;
1157 case 'null': return 'null';
1158 }
1159
1160 return null;
1161};
1162
1163JSON.secure = true;
1164
1165
1166JSON.decode = function(string, secure){
1167 if (!string || typeOf(string) != 'string') return null;
1168
1169 if (secure == null) secure = JSON.secure;
1170 if (secure){
1171 if (JSON.parse) return JSON.parse(string);
1172 if (!JSON.validate(string)) throw new Error('JSON could not decode the input; security is enabled and the value is not secure.');
1173 }
1174
1175 return eval('(' + string + ')');
1176};
1177
1178})();