]> jfr.im git - irc/quakenet/qwebirc.git/blob - static/js/mootools-1.2.5.1-more-nc.js
Merge.
[irc/quakenet/qwebirc.git] / static / js / mootools-1.2.5.1-more-nc.js
1 //MooTools More, <http://mootools.net/more>. Copyright (c) 2006-2009 Aaron Newton <http://clientcide.com/>, Valerio Proietti <http://mad4milk.net> & the MooTools team <http://mootools.net/developers>, MIT Style License.
2
3 /*
4 ---
5
6 script: More.js
7
8 name: More
9
10 description: MooTools More
11
12 license: MIT-style license
13
14 requires:
15 - Core/MooTools
16
17 provides: [MooTools.More]
18
19 ...
20 */
21
22 MooTools.More = {
23 'version': '1.2.5.1',
24 'build': '254884f2b83651bf95260eed5c6cceb838e22d8e'
25 };
26
27
28 /*
29 ---
30
31 script: Class.Binds.js
32
33 name: Class.Binds
34
35 description: Automagically binds specified methods in a class to the instance of the class.
36
37 license: MIT-style license
38
39 authors:
40 - Aaron Newton
41
42 requires:
43 - Core/Class
44 - /MooTools.More
45
46 provides: [Class.Binds]
47
48 ...
49 */
50
51 Class.Mutators.Binds = function(binds){
52 return binds;
53 };
54
55 Class.Mutators.initialize = function(initialize){
56 return function(){
57 $splat(this.Binds).each(function(name){
58 var original = this[name];
59 if (original) this[name] = original.bind(this);
60 }, this);
61 return initialize.apply(this, arguments);
62 };
63 };
64
65
66 /*
67 ---
68
69 script: Element.Measure.js
70
71 name: Element.Measure
72
73 description: Extends the Element native object to include methods useful in measuring dimensions.
74
75 credits: "Element.measure / .expose methods by Daniel Steigerwald License: MIT-style license. Copyright: Copyright (c) 2008 Daniel Steigerwald, daniel.steigerwald.cz"
76
77 license: MIT-style license
78
79 authors:
80 - Aaron Newton
81
82 requires:
83 - Core/Element.Style
84 - Core/Element.Dimensions
85 - /MooTools.More
86
87 provides: [Element.Measure]
88
89 ...
90 */
91
92 Element.implement({
93
94 measure: function(fn){
95 var vis = function(el) {
96 return !!(!el || el.offsetHeight || el.offsetWidth);
97 };
98 if (vis(this)) return fn.apply(this);
99 var parent = this.getParent(),
100 restorers = [],
101 toMeasure = [];
102 while (!vis(parent) && parent != document.body) {
103 toMeasure.push(parent.expose());
104 parent = parent.getParent();
105 }
106 var restore = this.expose();
107 var result = fn.apply(this);
108 restore();
109 toMeasure.each(function(restore){
110 restore();
111 });
112 return result;
113 },
114
115 expose: function(){
116 if (this.getStyle('display') != 'none') return $empty;
117 var before = this.style.cssText;
118 this.setStyles({
119 display: 'block',
120 position: 'absolute',
121 visibility: 'hidden'
122 });
123 return function(){
124 this.style.cssText = before;
125 }.bind(this);
126 },
127
128 getDimensions: function(options){
129 options = $merge({computeSize: false},options);
130 var dim = {};
131 var getSize = function(el, options){
132 return (options.computeSize)?el.getComputedSize(options):el.getSize();
133 };
134 var parent = this.getParent('body');
135 if (parent && this.getStyle('display') == 'none'){
136 dim = this.measure(function(){
137 return getSize(this, options);
138 });
139 } else if (parent){
140 try { //safari sometimes crashes here, so catch it
141 dim = getSize(this, options);
142 }catch(e){}
143 } else {
144 dim = {x: 0, y: 0};
145 }
146 return $chk(dim.x) ? $extend(dim, {width: dim.x, height: dim.y}) : $extend(dim, {x: dim.width, y: dim.height});
147 },
148
149 getComputedSize: function(options){
150 //legacy support for my stupid spelling error
151 if (options && options.plains) options.planes = options.plains;
152
153 options = $merge({
154 styles: ['padding','border'],
155 planes: {
156 height: ['top','bottom'],
157 width: ['left','right']
158 },
159 mode: 'both'
160 }, options);
161
162 var size = {width: 0,height: 0};
163 switch (options.mode){
164 case 'vertical':
165 delete size.width;
166 delete options.planes.width;
167 break;
168 case 'horizontal':
169 delete size.height;
170 delete options.planes.height;
171 break;
172 }
173 var getStyles = [];
174 //this function might be useful in other places; perhaps it should be outside this function?
175 $each(options.planes, function(plane, key){
176 plane.each(function(edge){
177 options.styles.each(function(style){
178 getStyles.push((style == 'border') ? style + '-' + edge + '-' + 'width' : style + '-' + edge);
179 });
180 });
181 });
182 var styles = {};
183 getStyles.each(function(style){ styles[style] = this.getComputedStyle(style); }, this);
184 var subtracted = [];
185 $each(options.planes, function(plane, key){ //keys: width, height, planes: ['left', 'right'], ['top','bottom']
186 var capitalized = key.capitalize();
187 size['total' + capitalized] = size['computed' + capitalized] = 0;
188 plane.each(function(edge){ //top, left, right, bottom
189 size['computed' + edge.capitalize()] = 0;
190 getStyles.each(function(style, i){ //padding, border, etc.
191 //'padding-left'.test('left') size['totalWidth'] = size['width'] + [padding-left]
192 if (style.test(edge)){
193 styles[style] = styles[style].toInt() || 0; //styles['padding-left'] = 5;
194 size['total' + capitalized] = size['total' + capitalized] + styles[style];
195 size['computed' + edge.capitalize()] = size['computed' + edge.capitalize()] + styles[style];
196 }
197 //if width != width (so, padding-left, for instance), then subtract that from the total
198 if (style.test(edge) && key != style &&
199 (style.test('border') || style.test('padding')) && !subtracted.contains(style)){
200 subtracted.push(style);
201 size['computed' + capitalized] = size['computed' + capitalized]-styles[style];
202 }
203 });
204 });
205 });
206
207 ['Width', 'Height'].each(function(value){
208 var lower = value.toLowerCase();
209 if(!$chk(size[lower])) return;
210
211 size[lower] = size[lower] + this['offset' + value] + size['computed' + value];
212 size['total' + value] = size[lower] + size['total' + value];
213 delete size['computed' + value];
214 }, this);
215
216 return $extend(styles, size);
217 }
218
219 });
220
221 /*
222 ---
223
224 script: Drag.js
225
226 name: Drag
227
228 description: The base Drag Class. Can be used to drag and resize Elements using mouse events.
229
230 license: MIT-style license
231
232 authors:
233 - Valerio Proietti
234 - Tom Occhinno
235 - Jan Kassens
236
237 requires:
238 - Core/Events
239 - Core/Options
240 - Core/Element.Event
241 - Core/Element.Style
242 - Core/Element.Dimensions
243 - /MooTools.More
244
245 provides: [Drag]
246 ...
247
248 */
249
250 var Drag = new Class({
251
252 Implements: [Events, Options],
253
254 options: {/*
255 onBeforeStart: $empty(thisElement),
256 onStart: $empty(thisElement, event),
257 onSnap: $empty(thisElement)
258 onDrag: $empty(thisElement, event),
259 onCancel: $empty(thisElement),
260 onComplete: $empty(thisElement, event),*/
261 snap: 6,
262 unit: 'px',
263 grid: false,
264 style: true,
265 limit: false,
266 handle: false,
267 invert: false,
268 preventDefault: false,
269 stopPropagation: false,
270 modifiers: {x: 'left', y: 'top'}
271 },
272
273 initialize: function(){
274 var params = Array.link(arguments, {'options': Object.type, 'element': $defined});
275 this.element = document.id(params.element);
276 this.document = this.element.getDocument();
277 this.setOptions(params.options || {});
278 var htype = $type(this.options.handle);
279 this.handles = ((htype == 'array' || htype == 'collection') ? $$(this.options.handle) : document.id(this.options.handle)) || this.element;
280 this.mouse = {'now': {}, 'pos': {}};
281 this.value = {'start': {}, 'now': {}};
282
283 this.selection = (Browser.Engine.trident) ? 'selectstart' : 'mousedown';
284
285 this.bound = {
286 start: this.start.bind(this),
287 check: this.check.bind(this),
288 drag: this.drag.bind(this),
289 stop: this.stop.bind(this),
290 cancel: this.cancel.bind(this),
291 eventStop: $lambda(false)
292 };
293 this.attach();
294 },
295
296 attach: function(){
297 this.handles.addEvent('mousedown', this.bound.start);
298 return this;
299 },
300
301 detach: function(){
302 this.handles.removeEvent('mousedown', this.bound.start);
303 return this;
304 },
305
306 start: function(event){
307 if (event.rightClick) return;
308 if (this.options.preventDefault) event.preventDefault();
309 if (this.options.stopPropagation) event.stopPropagation();
310 this.mouse.start = event.page;
311 this.fireEvent('beforeStart', this.element);
312 var limit = this.options.limit;
313 this.limit = {x: [], y: []};
314 var styles = this.element.getStyles('left', 'right', 'top', 'bottom');
315 this._invert = {
316 x: this.options.modifiers.x == 'left' && styles.left == 'auto' &&
317 !isNaN(styles.right.toInt()) && (this.options.modifiers.x = 'right'),
318 y: this.options.modifiers.y == 'top' && styles.top == 'auto' &&
319 !isNaN(styles.bottom.toInt()) && (this.options.modifiers.y = 'bottom')
320 };
321
322 var z, coordinates;
323 for (z in this.options.modifiers){
324 if (!this.options.modifiers[z]) continue;
325
326 var style = this.element.getStyle(this.options.modifiers[z]);
327
328 // Some browsers (IE and Opera) don't always return pixels.
329 if (style && !style.match(/px$/)){
330 if (!coordinates) coordinates = this.element.getCoordinates(this.element.getOffsetParent());
331 style = coordinates[this.options.modifiers[z]];
332 }
333
334 if (this.options.style) this.value.now[z] = (style || 0).toInt();
335 else this.value.now[z] = this.element[this.options.modifiers[z]];
336
337 if (this.options.invert) this.value.now[z] *= -1;
338 if (this._invert[z]) this.value.now[z] *= -1;
339
340 this.mouse.pos[z] = event.page[z] - this.value.now[z];
341
342 if (limit && limit[z]){
343 for (var i = 2; i--; i){
344 if ($chk(limit[z][i])) this.limit[z][i] = $lambda(limit[z][i])();
345 }
346 }
347 }
348
349 if ($type(this.options.grid) == 'number') this.options.grid = {x: this.options.grid, y: this.options.grid};
350 this.document.addEvents({mousemove: this.bound.check, mouseup: this.bound.cancel});
351 this.document.addEvent(this.selection, this.bound.eventStop);
352 },
353
354 check: function(event){
355 if (this.options.preventDefault) event.preventDefault();
356 var distance = Math.round(Math.sqrt(Math.pow(event.page.x - this.mouse.start.x, 2) + Math.pow(event.page.y - this.mouse.start.y, 2)));
357 if (distance > this.options.snap){
358 this.cancel();
359 this.document.addEvents({
360 mousemove: this.bound.drag,
361 mouseup: this.bound.stop
362 });
363 this.fireEvent('start', [this.element, event]).fireEvent('snap', this.element);
364 }
365 },
366
367 drag: function(event){
368 if (this.options.preventDefault) event.preventDefault();
369 this.mouse.now = event.page;
370 for (var z in this.options.modifiers){
371 if (!this.options.modifiers[z]) continue;
372 this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z];
373 if (this.options.invert) this.value.now[z] *= -1;
374 if (this._invert[z]) this.value.now[z] *= -1;
375 if (this.options.limit && this.limit[z]){
376 if ($chk(this.limit[z][1]) && (this.value.now[z] > this.limit[z][1])){
377 this.value.now[z] = this.limit[z][1];
378 } else if ($chk(this.limit[z][0]) && (this.value.now[z] < this.limit[z][0])){
379 this.value.now[z] = this.limit[z][0];
380 }
381 }
382 if (this.options.grid[z]) this.value.now[z] -= ((this.value.now[z] - (this.limit[z][0]||0)) % this.options.grid[z]);
383 if (this.options.style) {
384 this.element.setStyle(this.options.modifiers[z], this.value.now[z] + this.options.unit);
385 } else {
386 this.element[this.options.modifiers[z]] = this.value.now[z];
387 }
388 }
389 this.fireEvent('drag', [this.element, event]);
390 },
391
392 cancel: function(event){
393 this.document.removeEvent('mousemove', this.bound.check);
394 this.document.removeEvent('mouseup', this.bound.cancel);
395 if (event){
396 this.document.removeEvent(this.selection, this.bound.eventStop);
397 this.fireEvent('cancel', this.element);
398 }
399 },
400
401 stop: function(event){
402 this.document.removeEvent(this.selection, this.bound.eventStop);
403 this.document.removeEvent('mousemove', this.bound.drag);
404 this.document.removeEvent('mouseup', this.bound.stop);
405 if (event) this.fireEvent('complete', [this.element, event]);
406 }
407
408 });
409
410 Element.implement({
411
412 makeResizable: function(options){
413 var drag = new Drag(this, $merge({modifiers: {x: 'width', y: 'height'}}, options));
414 this.store('resizer', drag);
415 return drag.addEvent('drag', function(){
416 this.fireEvent('resize', drag);
417 }.bind(this));
418 }
419
420 });
421
422
423 /*
424 ---
425
426 script: Slider.js
427
428 name: Slider
429
430 description: Class for creating horizontal and vertical slider controls.
431
432 license: MIT-style license
433
434 authors:
435 - Valerio Proietti
436
437 requires:
438 - Core/Element.Dimensions
439 - /Class.Binds
440 - /Drag
441 - /Element.Measure
442
443 provides: [Slider]
444
445 ...
446 */
447
448 var Slider = new Class({
449
450 Implements: [Events, Options],
451
452 Binds: ['clickedElement', 'draggedKnob', 'scrolledElement'],
453
454 options: {/*
455 onTick: $empty(intPosition),
456 onChange: $empty(intStep),
457 onComplete: $empty(strStep),*/
458 onTick: function(position){
459 if (this.options.snap) position = this.toPosition(this.step);
460 this.knob.setStyle(this.property, position);
461 },
462 initialStep: 0,
463 snap: false,
464 offset: 0,
465 range: false,
466 wheel: false,
467 steps: 100,
468 mode: 'horizontal'
469 },
470
471 initialize: function(element, knob, options){
472 this.setOptions(options);
473 this.element = document.id(element);
474 this.knob = document.id(knob);
475 this.previousChange = this.previousEnd = this.step = -1;
476 var offset, limit = {}, modifiers = {'x': false, 'y': false};
477 switch (this.options.mode){
478 case 'vertical':
479 this.axis = 'y';
480 this.property = 'top';
481 offset = 'offsetHeight';
482 break;
483 case 'horizontal':
484 this.axis = 'x';
485 this.property = 'left';
486 offset = 'offsetWidth';
487 }
488
489 this.full = this.element.measure(function(){
490 this.half = this.knob[offset] / 2;
491 return this.element[offset] - this.knob[offset] + (this.options.offset * 2);
492 }.bind(this));
493
494 this.setRange(this.options.range);
495
496 this.knob.setStyle('position', 'relative').setStyle(this.property, - this.options.offset);
497 modifiers[this.axis] = this.property;
498 limit[this.axis] = [- this.options.offset, this.full - this.options.offset];
499
500 var dragOptions = {
501 snap: 0,
502 limit: limit,
503 modifiers: modifiers,
504 onDrag: this.draggedKnob,
505 onStart: this.draggedKnob,
506 onBeforeStart: (function(){
507 this.isDragging = true;
508 }).bind(this),
509 onCancel: function() {
510 this.isDragging = false;
511 }.bind(this),
512 onComplete: function(){
513 this.isDragging = false;
514 this.draggedKnob();
515 this.end();
516 }.bind(this)
517 };
518 if (this.options.snap){
519 dragOptions.grid = Math.ceil(this.stepWidth);
520 dragOptions.limit[this.axis][1] = this.full;
521 }
522
523 this.drag = new Drag(this.knob, dragOptions);
524 this.attach();
525 if (this.options.initialStep != null) this.set(this.options.initialStep)
526 },
527
528 attach: function(){
529 this.element.addEvent('mousedown', this.clickedElement);
530 if (this.options.wheel) this.element.addEvent('mousewheel', this.scrolledElement);
531 this.drag.attach();
532 return this;
533 },
534
535 detach: function(){
536 this.element.removeEvent('mousedown', this.clickedElement);
537 this.element.removeEvent('mousewheel', this.scrolledElement);
538 this.drag.detach();
539 return this;
540 },
541
542 set: function(step){
543 if (!((this.range > 0) ^ (step < this.min))) step = this.min;
544 if (!((this.range > 0) ^ (step > this.max))) step = this.max;
545
546 this.step = Math.round(step);
547 this.checkStep();
548 this.fireEvent('tick', this.toPosition(this.step));
549 this.end();
550 return this;
551 },
552
553 setRange: function(range, pos){
554 this.min = $pick(range[0], 0);
555 this.max = $pick(range[1], this.options.steps);
556 this.range = this.max - this.min;
557 this.steps = this.options.steps || this.full;
558 this.stepSize = Math.abs(this.range) / this.steps;
559 this.stepWidth = this.stepSize * this.full / Math.abs(this.range);
560 this.set($pick(pos, this.step).floor(this.min).max(this.max));
561 return this;
562 },
563
564 clickedElement: function(event){
565 if (this.isDragging || event.target == this.knob) return;
566
567 var dir = this.range < 0 ? -1 : 1;
568 var position = event.page[this.axis] - this.element.getPosition()[this.axis] - this.half;
569 position = position.limit(-this.options.offset, this.full -this.options.offset);
570
571 this.step = Math.round(this.min + dir * this.toStep(position));
572 this.checkStep();
573 this.fireEvent('tick', position);
574 this.end();
575 },
576
577 scrolledElement: function(event){
578 var mode = (this.options.mode == 'horizontal') ? (event.wheel < 0) : (event.wheel > 0);
579 this.set(mode ? this.step - this.stepSize : this.step + this.stepSize);
580 event.stop();
581 },
582
583 draggedKnob: function(){
584 var dir = this.range < 0 ? -1 : 1;
585 var position = this.drag.value.now[this.axis];
586 position = position.limit(-this.options.offset, this.full -this.options.offset);
587 this.step = Math.round(this.min + dir * this.toStep(position));
588 this.checkStep();
589 },
590
591 checkStep: function(){
592 if (this.previousChange != this.step){
593 this.previousChange = this.step;
594 this.fireEvent('change', this.step);
595 }
596 },
597
598 end: function(){
599 if (this.previousEnd !== this.step){
600 this.previousEnd = this.step;
601 this.fireEvent('complete', this.step + '');
602 }
603 },
604
605 toStep: function(position){
606 var step = (position + this.options.offset) * this.stepSize / this.full * this.steps;
607 return this.options.steps ? Math.round(step -= step % this.stepSize) : step;
608 },
609
610 toPosition: function(step){
611 return (this.full * Math.abs(this.min - step)) / (this.steps * this.stepSize) - this.options.offset;
612 }
613
614 });
615
616
617 /*
618 ---
619
620 script: Color.js
621
622 name: Color
623
624 description: Class for creating and manipulating colors in JavaScript. Supports HSB -> RGB Conversions and vice versa.
625
626 license: MIT-style license
627
628 authors:
629 - Valerio Proietti
630
631 requires:
632 - Core/Array
633 - Core/String
634 - Core/Number
635 - Core/Hash
636 - Core/Function
637 - Core/$util
638
639 provides: [Color]
640
641 ...
642 */
643
644 var Color = new Native({
645
646 initialize: function(color, type){
647 if (arguments.length >= 3){
648 type = 'rgb'; color = Array.slice(arguments, 0, 3);
649 } else if (typeof color == 'string'){
650 if (color.match(/rgb/)) color = color.rgbToHex().hexToRgb(true);
651 else if (color.match(/hsb/)) color = color.hsbToRgb();
652 else color = color.hexToRgb(true);
653 }
654 type = type || 'rgb';
655 switch (type){
656 case 'hsb':
657 var old = color;
658 color = color.hsbToRgb();
659 color.hsb = old;
660 break;
661 case 'hex': color = color.hexToRgb(true); break;
662 }
663 color.rgb = color.slice(0, 3);
664 color.hsb = color.hsb || color.rgbToHsb();
665 color.hex = color.rgbToHex();
666 return $extend(color, this);
667 }
668
669 });
670
671 Color.implement({
672
673 mix: function(){
674 var colors = Array.slice(arguments);
675 var alpha = ($type(colors.getLast()) == 'number') ? colors.pop() : 50;
676 var rgb = this.slice();
677 colors.each(function(color){
678 color = new Color(color);
679 for (var i = 0; i < 3; i++) rgb[i] = Math.round((rgb[i] / 100 * (100 - alpha)) + (color[i] / 100 * alpha));
680 });
681 return new Color(rgb, 'rgb');
682 },
683
684 invert: function(){
685 return new Color(this.map(function(value){
686 return 255 - value;
687 }));
688 },
689
690 setHue: function(value){
691 return new Color([value, this.hsb[1], this.hsb[2]], 'hsb');
692 },
693
694 setSaturation: function(percent){
695 return new Color([this.hsb[0], percent, this.hsb[2]], 'hsb');
696 },
697
698 setBrightness: function(percent){
699 return new Color([this.hsb[0], this.hsb[1], percent], 'hsb');
700 }
701
702 });
703
704 var $RGB = function(r, g, b){
705 return new Color([r, g, b], 'rgb');
706 };
707
708 var $HSB = function(h, s, b){
709 return new Color([h, s, b], 'hsb');
710 };
711
712 var $HEX = function(hex){
713 return new Color(hex, 'hex');
714 };
715
716 Array.implement({
717
718 rgbToHsb: function(){
719 var red = this[0],
720 green = this[1],
721 blue = this[2],
722 hue = 0;
723 var max = Math.max(red, green, blue),
724 min = Math.min(red, green, blue);
725 var delta = max - min;
726 var brightness = max / 255,
727 saturation = (max != 0) ? delta / max : 0;
728 if(saturation != 0) {
729 var rr = (max - red) / delta;
730 var gr = (max - green) / delta;
731 var br = (max - blue) / delta;
732 if (red == max) hue = br - gr;
733 else if (green == max) hue = 2 + rr - br;
734 else hue = 4 + gr - rr;
735 hue /= 6;
736 if (hue < 0) hue++;
737 }
738 return [Math.round(hue * 360), Math.round(saturation * 100), Math.round(brightness * 100)];
739 },
740
741 hsbToRgb: function(){
742 var br = Math.round(this[2] / 100 * 255);
743 if (this[1] == 0){
744 return [br, br, br];
745 } else {
746 var hue = this[0] % 360;
747 var f = hue % 60;
748 var p = Math.round((this[2] * (100 - this[1])) / 10000 * 255);
749 var q = Math.round((this[2] * (6000 - this[1] * f)) / 600000 * 255);
750 var t = Math.round((this[2] * (6000 - this[1] * (60 - f))) / 600000 * 255);
751 switch (Math.floor(hue / 60)){
752 case 0: return [br, t, p];
753 case 1: return [q, br, p];
754 case 2: return [p, br, t];
755 case 3: return [p, q, br];
756 case 4: return [t, p, br];
757 case 5: return [br, p, q];
758 }
759 }
760 return false;
761 }
762
763 });
764
765 String.implement({
766
767 rgbToHsb: function(){
768 var rgb = this.match(/\d{1,3}/g);
769 return (rgb) ? rgb.rgbToHsb() : null;
770 },
771
772 hsbToRgb: function(){
773 var hsb = this.match(/\d{1,3}/g);
774 return (hsb) ? hsb.hsbToRgb() : null;
775 }
776
777 });
778
779
780 /*
781 ---
782
783 script: Hash.Cookie.js
784
785 name: Hash.Cookie
786
787 description: Class for creating, reading, and deleting Cookies in JSON format.
788
789 license: MIT-style license
790
791 authors:
792 - Valerio Proietti
793 - Aaron Newton
794
795 requires:
796 - Core/Cookie
797 - Core/JSON
798 - /MooTools.More
799
800 provides: [Hash.Cookie]
801
802 ...
803 */
804
805 Hash.Cookie = new Class({
806
807 Extends: Cookie,
808
809 options: {
810 autoSave: true
811 },
812
813 initialize: function(name, options){
814 this.parent(name, options);
815 this.load();
816 },
817
818 save: function(){
819 var value = JSON.encode(this.hash);
820 if (!value || value.length > 4096) return false; //cookie would be truncated!
821 if (value == '{}') this.dispose();
822 else this.write(value);
823 return true;
824 },
825
826 load: function(){
827 this.hash = new Hash(JSON.decode(this.read(), true));
828 return this;
829 }
830
831 });
832
833 Hash.each(Hash.prototype, function(method, name){
834 if (typeof method == 'function') Hash.Cookie.implement(name, function(){
835 var value = method.apply(this.hash, arguments);
836 if (this.options.autoSave) this.save();
837 return value;
838 });
839 });