monorail 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ # $Id: version.rb 2404 2006-04-28 16:32:58Z francis $
2
+ #
3
+ #
4
+
5
+ Version = "0.0.3"
@@ -0,0 +1,11 @@
1
+ # $Id$
2
+ #
3
+ #
4
+
5
+ module Controller_sample
6
+
7
+ def index
8
+ render "sample_page"
9
+ end
10
+
11
+ end
@@ -0,0 +1 @@
1
+ Sample page <%= Time.now %>
@@ -0,0 +1,8 @@
1
+ <html>
2
+ <head>
3
+ <title>Monorail</title>
4
+ </head>
5
+ <body>
6
+ <h1>Monorail</h1>
7
+ </body>
8
+ </html>
@@ -0,0 +1,1781 @@
1
+ /* Prototype JavaScript framework, version 1.4.0
2
+ * (c) 2005 Sam Stephenson <sam@conio.net>
3
+ *
4
+ * Prototype is freely distributable under the terms of an MIT-style license.
5
+ * For details, see the Prototype web site: http://prototype.conio.net/
6
+ *
7
+ /*--------------------------------------------------------------------------*/
8
+
9
+ var Prototype = {
10
+ Version: '1.4.0',
11
+ ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
12
+
13
+ emptyFunction: function() {},
14
+ K: function(x) {return x}
15
+ }
16
+
17
+ var Class = {
18
+ create: function() {
19
+ return function() {
20
+ this.initialize.apply(this, arguments);
21
+ }
22
+ }
23
+ }
24
+
25
+ var Abstract = new Object();
26
+
27
+ Object.extend = function(destination, source) {
28
+ for (property in source) {
29
+ destination[property] = source[property];
30
+ }
31
+ return destination;
32
+ }
33
+
34
+ Object.inspect = function(object) {
35
+ try {
36
+ if (object == undefined) return 'undefined';
37
+ if (object == null) return 'null';
38
+ return object.inspect ? object.inspect() : object.toString();
39
+ } catch (e) {
40
+ if (e instanceof RangeError) return '...';
41
+ throw e;
42
+ }
43
+ }
44
+
45
+ Function.prototype.bind = function() {
46
+ var __method = this, args = $A(arguments), object = args.shift();
47
+ return function() {
48
+ return __method.apply(object, args.concat($A(arguments)));
49
+ }
50
+ }
51
+
52
+ Function.prototype.bindAsEventListener = function(object) {
53
+ var __method = this;
54
+ return function(event) {
55
+ return __method.call(object, event || window.event);
56
+ }
57
+ }
58
+
59
+ Object.extend(Number.prototype, {
60
+ toColorPart: function() {
61
+ var digits = this.toString(16);
62
+ if (this < 16) return '0' + digits;
63
+ return digits;
64
+ },
65
+
66
+ succ: function() {
67
+ return this + 1;
68
+ },
69
+
70
+ times: function(iterator) {
71
+ $R(0, this, true).each(iterator);
72
+ return this;
73
+ }
74
+ });
75
+
76
+ var Try = {
77
+ these: function() {
78
+ var returnValue;
79
+
80
+ for (var i = 0; i < arguments.length; i++) {
81
+ var lambda = arguments[i];
82
+ try {
83
+ returnValue = lambda();
84
+ break;
85
+ } catch (e) {}
86
+ }
87
+
88
+ return returnValue;
89
+ }
90
+ }
91
+
92
+ /*--------------------------------------------------------------------------*/
93
+
94
+ var PeriodicalExecuter = Class.create();
95
+ PeriodicalExecuter.prototype = {
96
+ initialize: function(callback, frequency) {
97
+ this.callback = callback;
98
+ this.frequency = frequency;
99
+ this.currentlyExecuting = false;
100
+
101
+ this.registerCallback();
102
+ },
103
+
104
+ registerCallback: function() {
105
+ setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
106
+ },
107
+
108
+ onTimerEvent: function() {
109
+ if (!this.currentlyExecuting) {
110
+ try {
111
+ this.currentlyExecuting = true;
112
+ this.callback();
113
+ } finally {
114
+ this.currentlyExecuting = false;
115
+ }
116
+ }
117
+ }
118
+ }
119
+
120
+ /*--------------------------------------------------------------------------*/
121
+
122
+ function $() {
123
+ var elements = new Array();
124
+
125
+ for (var i = 0; i < arguments.length; i++) {
126
+ var element = arguments[i];
127
+ if (typeof element == 'string')
128
+ element = document.getElementById(element);
129
+
130
+ if (arguments.length == 1)
131
+ return element;
132
+
133
+ elements.push(element);
134
+ }
135
+
136
+ return elements;
137
+ }
138
+ Object.extend(String.prototype, {
139
+ stripTags: function() {
140
+ return this.replace(/<\/?[^>]+>/gi, '');
141
+ },
142
+
143
+ stripScripts: function() {
144
+ return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
145
+ },
146
+
147
+ extractScripts: function() {
148
+ var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
149
+ var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
150
+ return (this.match(matchAll) || []).map(function(scriptTag) {
151
+ return (scriptTag.match(matchOne) || ['', ''])[1];
152
+ });
153
+ },
154
+
155
+ evalScripts: function() {
156
+ return this.extractScripts().map(eval);
157
+ },
158
+
159
+ escapeHTML: function() {
160
+ var div = document.createElement('div');
161
+ var text = document.createTextNode(this);
162
+ div.appendChild(text);
163
+ return div.innerHTML;
164
+ },
165
+
166
+ unescapeHTML: function() {
167
+ var div = document.createElement('div');
168
+ div.innerHTML = this.stripTags();
169
+ return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
170
+ },
171
+
172
+ toQueryParams: function() {
173
+ var pairs = this.match(/^\??(.*)$/)[1].split('&');
174
+ return pairs.inject({}, function(params, pairString) {
175
+ var pair = pairString.split('=');
176
+ params[pair[0]] = pair[1];
177
+ return params;
178
+ });
179
+ },
180
+
181
+ toArray: function() {
182
+ return this.split('');
183
+ },
184
+
185
+ camelize: function() {
186
+ var oStringList = this.split('-');
187
+ if (oStringList.length == 1) return oStringList[0];
188
+
189
+ var camelizedString = this.indexOf('-') == 0
190
+ ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
191
+ : oStringList[0];
192
+
193
+ for (var i = 1, len = oStringList.length; i < len; i++) {
194
+ var s = oStringList[i];
195
+ camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
196
+ }
197
+
198
+ return camelizedString;
199
+ },
200
+
201
+ inspect: function() {
202
+ return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'";
203
+ }
204
+ });
205
+
206
+ String.prototype.parseQuery = String.prototype.toQueryParams;
207
+
208
+ var $break = new Object();
209
+ var $continue = new Object();
210
+
211
+ var Enumerable = {
212
+ each: function(iterator) {
213
+ var index = 0;
214
+ try {
215
+ this._each(function(value) {
216
+ try {
217
+ iterator(value, index++);
218
+ } catch (e) {
219
+ if (e != $continue) throw e;
220
+ }
221
+ });
222
+ } catch (e) {
223
+ if (e != $break) throw e;
224
+ }
225
+ },
226
+
227
+ all: function(iterator) {
228
+ var result = true;
229
+ this.each(function(value, index) {
230
+ result = result && !!(iterator || Prototype.K)(value, index);
231
+ if (!result) throw $break;
232
+ });
233
+ return result;
234
+ },
235
+
236
+ any: function(iterator) {
237
+ var result = true;
238
+ this.each(function(value, index) {
239
+ if (result = !!(iterator || Prototype.K)(value, index))
240
+ throw $break;
241
+ });
242
+ return result;
243
+ },
244
+
245
+ collect: function(iterator) {
246
+ var results = [];
247
+ this.each(function(value, index) {
248
+ results.push(iterator(value, index));
249
+ });
250
+ return results;
251
+ },
252
+
253
+ detect: function (iterator) {
254
+ var result;
255
+ this.each(function(value, index) {
256
+ if (iterator(value, index)) {
257
+ result = value;
258
+ throw $break;
259
+ }
260
+ });
261
+ return result;
262
+ },
263
+
264
+ findAll: function(iterator) {
265
+ var results = [];
266
+ this.each(function(value, index) {
267
+ if (iterator(value, index))
268
+ results.push(value);
269
+ });
270
+ return results;
271
+ },
272
+
273
+ grep: function(pattern, iterator) {
274
+ var results = [];
275
+ this.each(function(value, index) {
276
+ var stringValue = value.toString();
277
+ if (stringValue.match(pattern))
278
+ results.push((iterator || Prototype.K)(value, index));
279
+ })
280
+ return results;
281
+ },
282
+
283
+ include: function(object) {
284
+ var found = false;
285
+ this.each(function(value) {
286
+ if (value == object) {
287
+ found = true;
288
+ throw $break;
289
+ }
290
+ });
291
+ return found;
292
+ },
293
+
294
+ inject: function(memo, iterator) {
295
+ this.each(function(value, index) {
296
+ memo = iterator(memo, value, index);
297
+ });
298
+ return memo;
299
+ },
300
+
301
+ invoke: function(method) {
302
+ var args = $A(arguments).slice(1);
303
+ return this.collect(function(value) {
304
+ return value[method].apply(value, args);
305
+ });
306
+ },
307
+
308
+ max: function(iterator) {
309
+ var result;
310
+ this.each(function(value, index) {
311
+ value = (iterator || Prototype.K)(value, index);
312
+ if (value >= (result || value))
313
+ result = value;
314
+ });
315
+ return result;
316
+ },
317
+
318
+ min: function(iterator) {
319
+ var result;
320
+ this.each(function(value, index) {
321
+ value = (iterator || Prototype.K)(value, index);
322
+ if (value <= (result || value))
323
+ result = value;
324
+ });
325
+ return result;
326
+ },
327
+
328
+ partition: function(iterator) {
329
+ var trues = [], falses = [];
330
+ this.each(function(value, index) {
331
+ ((iterator || Prototype.K)(value, index) ?
332
+ trues : falses).push(value);
333
+ });
334
+ return [trues, falses];
335
+ },
336
+
337
+ pluck: function(property) {
338
+ var results = [];
339
+ this.each(function(value, index) {
340
+ results.push(value[property]);
341
+ });
342
+ return results;
343
+ },
344
+
345
+ reject: function(iterator) {
346
+ var results = [];
347
+ this.each(function(value, index) {
348
+ if (!iterator(value, index))
349
+ results.push(value);
350
+ });
351
+ return results;
352
+ },
353
+
354
+ sortBy: function(iterator) {
355
+ return this.collect(function(value, index) {
356
+ return {value: value, criteria: iterator(value, index)};
357
+ }).sort(function(left, right) {
358
+ var a = left.criteria, b = right.criteria;
359
+ return a < b ? -1 : a > b ? 1 : 0;
360
+ }).pluck('value');
361
+ },
362
+
363
+ toArray: function() {
364
+ return this.collect(Prototype.K);
365
+ },
366
+
367
+ zip: function() {
368
+ var iterator = Prototype.K, args = $A(arguments);
369
+ if (typeof args.last() == 'function')
370
+ iterator = args.pop();
371
+
372
+ var collections = [this].concat(args).map($A);
373
+ return this.map(function(value, index) {
374
+ iterator(value = collections.pluck(index));
375
+ return value;
376
+ });
377
+ },
378
+
379
+ inspect: function() {
380
+ return '#<Enumerable:' + this.toArray().inspect() + '>';
381
+ }
382
+ }
383
+
384
+ Object.extend(Enumerable, {
385
+ map: Enumerable.collect,
386
+ find: Enumerable.detect,
387
+ select: Enumerable.findAll,
388
+ member: Enumerable.include,
389
+ entries: Enumerable.toArray
390
+ });
391
+ var $A = Array.from = function(iterable) {
392
+ if (!iterable) return [];
393
+ if (iterable.toArray) {
394
+ return iterable.toArray();
395
+ } else {
396
+ var results = [];
397
+ for (var i = 0; i < iterable.length; i++)
398
+ results.push(iterable[i]);
399
+ return results;
400
+ }
401
+ }
402
+
403
+ Object.extend(Array.prototype, Enumerable);
404
+
405
+ Array.prototype._reverse = Array.prototype.reverse;
406
+
407
+ Object.extend(Array.prototype, {
408
+ _each: function(iterator) {
409
+ for (var i = 0; i < this.length; i++)
410
+ iterator(this[i]);
411
+ },
412
+
413
+ clear: function() {
414
+ this.length = 0;
415
+ return this;
416
+ },
417
+
418
+ first: function() {
419
+ return this[0];
420
+ },
421
+
422
+ last: function() {
423
+ return this[this.length - 1];
424
+ },
425
+
426
+ compact: function() {
427
+ return this.select(function(value) {
428
+ return value != undefined || value != null;
429
+ });
430
+ },
431
+
432
+ flatten: function() {
433
+ return this.inject([], function(array, value) {
434
+ return array.concat(value.constructor == Array ?
435
+ value.flatten() : [value]);
436
+ });
437
+ },
438
+
439
+ without: function() {
440
+ var values = $A(arguments);
441
+ return this.select(function(value) {
442
+ return !values.include(value);
443
+ });
444
+ },
445
+
446
+ indexOf: function(object) {
447
+ for (var i = 0; i < this.length; i++)
448
+ if (this[i] == object) return i;
449
+ return -1;
450
+ },
451
+
452
+ reverse: function(inline) {
453
+ return (inline !== false ? this : this.toArray())._reverse();
454
+ },
455
+
456
+ shift: function() {
457
+ var result = this[0];
458
+ for (var i = 0; i < this.length - 1; i++)
459
+ this[i] = this[i + 1];
460
+ this.length--;
461
+ return result;
462
+ },
463
+
464
+ inspect: function() {
465
+ return '[' + this.map(Object.inspect).join(', ') + ']';
466
+ }
467
+ });
468
+ var Hash = {
469
+ _each: function(iterator) {
470
+ for (key in this) {
471
+ var value = this[key];
472
+ if (typeof value == 'function') continue;
473
+
474
+ var pair = [key, value];
475
+ pair.key = key;
476
+ pair.value = value;
477
+ iterator(pair);
478
+ }
479
+ },
480
+
481
+ keys: function() {
482
+ return this.pluck('key');
483
+ },
484
+
485
+ values: function() {
486
+ return this.pluck('value');
487
+ },
488
+
489
+ merge: function(hash) {
490
+ return $H(hash).inject($H(this), function(mergedHash, pair) {
491
+ mergedHash[pair.key] = pair.value;
492
+ return mergedHash;
493
+ });
494
+ },
495
+
496
+ toQueryString: function() {
497
+ return this.map(function(pair) {
498
+ return pair.map(encodeURIComponent).join('=');
499
+ }).join('&');
500
+ },
501
+
502
+ inspect: function() {
503
+ return '#<Hash:{' + this.map(function(pair) {
504
+ return pair.map(Object.inspect).join(': ');
505
+ }).join(', ') + '}>';
506
+ }
507
+ }
508
+
509
+ function $H(object) {
510
+ var hash = Object.extend({}, object || {});
511
+ Object.extend(hash, Enumerable);
512
+ Object.extend(hash, Hash);
513
+ return hash;
514
+ }
515
+ ObjectRange = Class.create();
516
+ Object.extend(ObjectRange.prototype, Enumerable);
517
+ Object.extend(ObjectRange.prototype, {
518
+ initialize: function(start, end, exclusive) {
519
+ this.start = start;
520
+ this.end = end;
521
+ this.exclusive = exclusive;
522
+ },
523
+
524
+ _each: function(iterator) {
525
+ var value = this.start;
526
+ do {
527
+ iterator(value);
528
+ value = value.succ();
529
+ } while (this.include(value));
530
+ },
531
+
532
+ include: function(value) {
533
+ if (value < this.start)
534
+ return false;
535
+ if (this.exclusive)
536
+ return value < this.end;
537
+ return value <= this.end;
538
+ }
539
+ });
540
+
541
+ var $R = function(start, end, exclusive) {
542
+ return new ObjectRange(start, end, exclusive);
543
+ }
544
+
545
+ var Ajax = {
546
+ getTransport: function() {
547
+ return Try.these(
548
+ function() {return new ActiveXObject('Msxml2.XMLHTTP')},
549
+ function() {return new ActiveXObject('Microsoft.XMLHTTP')},
550
+ function() {return new XMLHttpRequest()}
551
+ ) || false;
552
+ },
553
+
554
+ activeRequestCount: 0
555
+ }
556
+
557
+ Ajax.Responders = {
558
+ responders: [],
559
+
560
+ _each: function(iterator) {
561
+ this.responders._each(iterator);
562
+ },
563
+
564
+ register: function(responderToAdd) {
565
+ if (!this.include(responderToAdd))
566
+ this.responders.push(responderToAdd);
567
+ },
568
+
569
+ unregister: function(responderToRemove) {
570
+ this.responders = this.responders.without(responderToRemove);
571
+ },
572
+
573
+ dispatch: function(callback, request, transport, json) {
574
+ this.each(function(responder) {
575
+ if (responder[callback] && typeof responder[callback] == 'function') {
576
+ try {
577
+ responder[callback].apply(responder, [request, transport, json]);
578
+ } catch (e) {}
579
+ }
580
+ });
581
+ }
582
+ };
583
+
584
+ Object.extend(Ajax.Responders, Enumerable);
585
+
586
+ Ajax.Responders.register({
587
+ onCreate: function() {
588
+ Ajax.activeRequestCount++;
589
+ },
590
+
591
+ onComplete: function() {
592
+ Ajax.activeRequestCount--;
593
+ }
594
+ });
595
+
596
+ Ajax.Base = function() {};
597
+ Ajax.Base.prototype = {
598
+ setOptions: function(options) {
599
+ this.options = {
600
+ method: 'post',
601
+ asynchronous: true,
602
+ parameters: ''
603
+ }
604
+ Object.extend(this.options, options || {});
605
+ },
606
+
607
+ responseIsSuccess: function() {
608
+ return this.transport.status == undefined
609
+ || this.transport.status == 0
610
+ || (this.transport.status >= 200 && this.transport.status < 300);
611
+ },
612
+
613
+ responseIsFailure: function() {
614
+ return !this.responseIsSuccess();
615
+ }
616
+ }
617
+
618
+ Ajax.Request = Class.create();
619
+ Ajax.Request.Events =
620
+ ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
621
+
622
+ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
623
+ initialize: function(url, options) {
624
+ this.transport = Ajax.getTransport();
625
+ this.setOptions(options);
626
+ this.request(url);
627
+ },
628
+
629
+ request: function(url) {
630
+ var parameters = this.options.parameters || '';
631
+ if (parameters.length > 0) parameters += '&_=';
632
+
633
+ try {
634
+ this.url = url;
635
+ if (this.options.method == 'get' && parameters.length > 0)
636
+ this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
637
+
638
+ Ajax.Responders.dispatch('onCreate', this, this.transport);
639
+
640
+ this.transport.open(this.options.method, this.url,
641
+ this.options.asynchronous);
642
+
643
+ if (this.options.asynchronous) {
644
+ this.transport.onreadystatechange = this.onStateChange.bind(this);
645
+ setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
646
+ }
647
+
648
+ this.setRequestHeaders();
649
+
650
+ var body = this.options.postBody ? this.options.postBody : parameters;
651
+ this.transport.send(this.options.method == 'post' ? body : null);
652
+
653
+ } catch (e) {
654
+ this.dispatchException(e);
655
+ }
656
+ },
657
+
658
+ setRequestHeaders: function() {
659
+ var requestHeaders =
660
+ ['X-Requested-With', 'XMLHttpRequest',
661
+ 'X-Prototype-Version', Prototype.Version];
662
+
663
+ if (this.options.method == 'post') {
664
+ requestHeaders.push('Content-type',
665
+ 'application/x-www-form-urlencoded');
666
+
667
+ /* Force "Connection: close" for Mozilla browsers to work around
668
+ * a bug where XMLHttpReqeuest sends an incorrect Content-length
669
+ * header. See Mozilla Bugzilla #246651.
670
+ */
671
+ if (this.transport.overrideMimeType)
672
+ requestHeaders.push('Connection', 'close');
673
+ }
674
+
675
+ if (this.options.requestHeaders)
676
+ requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
677
+
678
+ for (var i = 0; i < requestHeaders.length; i += 2)
679
+ this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
680
+ },
681
+
682
+ onStateChange: function() {
683
+ var readyState = this.transport.readyState;
684
+ if (readyState != 1)
685
+ this.respondToReadyState(this.transport.readyState);
686
+ },
687
+
688
+ header: function(name) {
689
+ try {
690
+ return this.transport.getResponseHeader(name);
691
+ } catch (e) {}
692
+ },
693
+
694
+ evalJSON: function() {
695
+ try {
696
+ return eval(this.header('X-JSON'));
697
+ } catch (e) {}
698
+ },
699
+
700
+ evalResponse: function() {
701
+ try {
702
+ return eval(this.transport.responseText);
703
+ } catch (e) {
704
+ this.dispatchException(e);
705
+ }
706
+ },
707
+
708
+ respondToReadyState: function(readyState) {
709
+ var event = Ajax.Request.Events[readyState];
710
+ var transport = this.transport, json = this.evalJSON();
711
+
712
+ if (event == 'Complete') {
713
+ try {
714
+ (this.options['on' + this.transport.status]
715
+ || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
716
+ || Prototype.emptyFunction)(transport, json);
717
+ } catch (e) {
718
+ this.dispatchException(e);
719
+ }
720
+
721
+ if ((this.header('Content-type') || '').match(/^text\/javascript/i))
722
+ this.evalResponse();
723
+ }
724
+
725
+ try {
726
+ (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
727
+ Ajax.Responders.dispatch('on' + event, this, transport, json);
728
+ } catch (e) {
729
+ this.dispatchException(e);
730
+ }
731
+
732
+ /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
733
+ if (event == 'Complete')
734
+ this.transport.onreadystatechange = Prototype.emptyFunction;
735
+ },
736
+
737
+ dispatchException: function(exception) {
738
+ (this.options.onException || Prototype.emptyFunction)(this, exception);
739
+ Ajax.Responders.dispatch('onException', this, exception);
740
+ }
741
+ });
742
+
743
+ Ajax.Updater = Class.create();
744
+
745
+ Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
746
+ initialize: function(container, url, options) {
747
+ this.containers = {
748
+ success: container.success ? $(container.success) : $(container),
749
+ failure: container.failure ? $(container.failure) :
750
+ (container.success ? null : $(container))
751
+ }
752
+
753
+ this.transport = Ajax.getTransport();
754
+ this.setOptions(options);
755
+
756
+ var onComplete = this.options.onComplete || Prototype.emptyFunction;
757
+ this.options.onComplete = (function(transport, object) {
758
+ this.updateContent();
759
+ onComplete(transport, object);
760
+ }).bind(this);
761
+
762
+ this.request(url);
763
+ },
764
+
765
+ updateContent: function() {
766
+ var receiver = this.responseIsSuccess() ?
767
+ this.containers.success : this.containers.failure;
768
+ var response = this.transport.responseText;
769
+
770
+ if (!this.options.evalScripts)
771
+ response = response.stripScripts();
772
+
773
+ if (receiver) {
774
+ if (this.options.insertion) {
775
+ new this.options.insertion(receiver, response);
776
+ } else {
777
+ Element.update(receiver, response);
778
+ }
779
+ }
780
+
781
+ if (this.responseIsSuccess()) {
782
+ if (this.onComplete)
783
+ setTimeout(this.onComplete.bind(this), 10);
784
+ }
785
+ }
786
+ });
787
+
788
+ Ajax.PeriodicalUpdater = Class.create();
789
+ Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
790
+ initialize: function(container, url, options) {
791
+ this.setOptions(options);
792
+ this.onComplete = this.options.onComplete;
793
+
794
+ this.frequency = (this.options.frequency || 2);
795
+ this.decay = (this.options.decay || 1);
796
+
797
+ this.updater = {};
798
+ this.container = container;
799
+ this.url = url;
800
+
801
+ this.start();
802
+ },
803
+
804
+ start: function() {
805
+ this.options.onComplete = this.updateComplete.bind(this);
806
+ this.onTimerEvent();
807
+ },
808
+
809
+ stop: function() {
810
+ this.updater.onComplete = undefined;
811
+ clearTimeout(this.timer);
812
+ (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
813
+ },
814
+
815
+ updateComplete: function(request) {
816
+ if (this.options.decay) {
817
+ this.decay = (request.responseText == this.lastText ?
818
+ this.decay * this.options.decay : 1);
819
+
820
+ this.lastText = request.responseText;
821
+ }
822
+ this.timer = setTimeout(this.onTimerEvent.bind(this),
823
+ this.decay * this.frequency * 1000);
824
+ },
825
+
826
+ onTimerEvent: function() {
827
+ this.updater = new Ajax.Updater(this.container, this.url, this.options);
828
+ }
829
+ });
830
+ document.getElementsByClassName = function(className, parentElement) {
831
+ var children = ($(parentElement) || document.body).getElementsByTagName('*');
832
+ return $A(children).inject([], function(elements, child) {
833
+ if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
834
+ elements.push(child);
835
+ return elements;
836
+ });
837
+ }
838
+
839
+ /*--------------------------------------------------------------------------*/
840
+
841
+ if (!window.Element) {
842
+ var Element = new Object();
843
+ }
844
+
845
+ Object.extend(Element, {
846
+ visible: function(element) {
847
+ return $(element).style.display != 'none';
848
+ },
849
+
850
+ toggle: function() {
851
+ for (var i = 0; i < arguments.length; i++) {
852
+ var element = $(arguments[i]);
853
+ Element[Element.visible(element) ? 'hide' : 'show'](element);
854
+ }
855
+ },
856
+
857
+ hide: function() {
858
+ for (var i = 0; i < arguments.length; i++) {
859
+ var element = $(arguments[i]);
860
+ element.style.display = 'none';
861
+ }
862
+ },
863
+
864
+ show: function() {
865
+ for (var i = 0; i < arguments.length; i++) {
866
+ var element = $(arguments[i]);
867
+ element.style.display = '';
868
+ }
869
+ },
870
+
871
+ remove: function(element) {
872
+ element = $(element);
873
+ element.parentNode.removeChild(element);
874
+ },
875
+
876
+ update: function(element, html) {
877
+ $(element).innerHTML = html.stripScripts();
878
+ setTimeout(function() {html.evalScripts()}, 10);
879
+ },
880
+
881
+ getHeight: function(element) {
882
+ element = $(element);
883
+ return element.offsetHeight;
884
+ },
885
+
886
+ classNames: function(element) {
887
+ return new Element.ClassNames(element);
888
+ },
889
+
890
+ hasClassName: function(element, className) {
891
+ if (!(element = $(element))) return;
892
+ return Element.classNames(element).include(className);
893
+ },
894
+
895
+ addClassName: function(element, className) {
896
+ if (!(element = $(element))) return;
897
+ return Element.classNames(element).add(className);
898
+ },
899
+
900
+ removeClassName: function(element, className) {
901
+ if (!(element = $(element))) return;
902
+ return Element.classNames(element).remove(className);
903
+ },
904
+
905
+ // removes whitespace-only text node children
906
+ cleanWhitespace: function(element) {
907
+ element = $(element);
908
+ for (var i = 0; i < element.childNodes.length; i++) {
909
+ var node = element.childNodes[i];
910
+ if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
911
+ Element.remove(node);
912
+ }
913
+ },
914
+
915
+ empty: function(element) {
916
+ return $(element).innerHTML.match(/^\s*$/);
917
+ },
918
+
919
+ scrollTo: function(element) {
920
+ element = $(element);
921
+ var x = element.x ? element.x : element.offsetLeft,
922
+ y = element.y ? element.y : element.offsetTop;
923
+ window.scrollTo(x, y);
924
+ },
925
+
926
+ getStyle: function(element, style) {
927
+ element = $(element);
928
+ var value = element.style[style.camelize()];
929
+ if (!value) {
930
+ if (document.defaultView && document.defaultView.getComputedStyle) {
931
+ var css = document.defaultView.getComputedStyle(element, null);
932
+ value = css ? css.getPropertyValue(style) : null;
933
+ } else if (element.currentStyle) {
934
+ value = element.currentStyle[style.camelize()];
935
+ }
936
+ }
937
+
938
+ if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
939
+ if (Element.getStyle(element, 'position') == 'static') value = 'auto';
940
+
941
+ return value == 'auto' ? null : value;
942
+ },
943
+
944
+ setStyle: function(element, style) {
945
+ element = $(element);
946
+ for (name in style)
947
+ element.style[name.camelize()] = style[name];
948
+ },
949
+
950
+ getDimensions: function(element) {
951
+ element = $(element);
952
+ if (Element.getStyle(element, 'display') != 'none')
953
+ return {width: element.offsetWidth, height: element.offsetHeight};
954
+
955
+ // All *Width and *Height properties give 0 on elements with display none,
956
+ // so enable the element temporarily
957
+ var els = element.style;
958
+ var originalVisibility = els.visibility;
959
+ var originalPosition = els.position;
960
+ els.visibility = 'hidden';
961
+ els.position = 'absolute';
962
+ els.display = '';
963
+ var originalWidth = element.clientWidth;
964
+ var originalHeight = element.clientHeight;
965
+ els.display = 'none';
966
+ els.position = originalPosition;
967
+ els.visibility = originalVisibility;
968
+ return {width: originalWidth, height: originalHeight};
969
+ },
970
+
971
+ makePositioned: function(element) {
972
+ element = $(element);
973
+ var pos = Element.getStyle(element, 'position');
974
+ if (pos == 'static' || !pos) {
975
+ element._madePositioned = true;
976
+ element.style.position = 'relative';
977
+ // Opera returns the offset relative to the positioning context, when an
978
+ // element is position relative but top and left have not been defined
979
+ if (window.opera) {
980
+ element.style.top = 0;
981
+ element.style.left = 0;
982
+ }
983
+ }
984
+ },
985
+
986
+ undoPositioned: function(element) {
987
+ element = $(element);
988
+ if (element._madePositioned) {
989
+ element._madePositioned = undefined;
990
+ element.style.position =
991
+ element.style.top =
992
+ element.style.left =
993
+ element.style.bottom =
994
+ element.style.right = '';
995
+ }
996
+ },
997
+
998
+ makeClipping: function(element) {
999
+ element = $(element);
1000
+ if (element._overflow) return;
1001
+ element._overflow = element.style.overflow;
1002
+ if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
1003
+ element.style.overflow = 'hidden';
1004
+ },
1005
+
1006
+ undoClipping: function(element) {
1007
+ element = $(element);
1008
+ if (element._overflow) return;
1009
+ element.style.overflow = element._overflow;
1010
+ element._overflow = undefined;
1011
+ }
1012
+ });
1013
+
1014
+ var Toggle = new Object();
1015
+ Toggle.display = Element.toggle;
1016
+
1017
+ /*--------------------------------------------------------------------------*/
1018
+
1019
+ Abstract.Insertion = function(adjacency) {
1020
+ this.adjacency = adjacency;
1021
+ }
1022
+
1023
+ Abstract.Insertion.prototype = {
1024
+ initialize: function(element, content) {
1025
+ this.element = $(element);
1026
+ this.content = content.stripScripts();
1027
+
1028
+ if (this.adjacency && this.element.insertAdjacentHTML) {
1029
+ try {
1030
+ this.element.insertAdjacentHTML(this.adjacency, this.content);
1031
+ } catch (e) {
1032
+ if (this.element.tagName.toLowerCase() == 'tbody') {
1033
+ this.insertContent(this.contentFromAnonymousTable());
1034
+ } else {
1035
+ throw e;
1036
+ }
1037
+ }
1038
+ } else {
1039
+ this.range = this.element.ownerDocument.createRange();
1040
+ if (this.initializeRange) this.initializeRange();
1041
+ this.insertContent([this.range.createContextualFragment(this.content)]);
1042
+ }
1043
+
1044
+ setTimeout(function() {content.evalScripts()}, 10);
1045
+ },
1046
+
1047
+ contentFromAnonymousTable: function() {
1048
+ var div = document.createElement('div');
1049
+ div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
1050
+ return $A(div.childNodes[0].childNodes[0].childNodes);
1051
+ }
1052
+ }
1053
+
1054
+ var Insertion = new Object();
1055
+
1056
+ Insertion.Before = Class.create();
1057
+ Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
1058
+ initializeRange: function() {
1059
+ this.range.setStartBefore(this.element);
1060
+ },
1061
+
1062
+ insertContent: function(fragments) {
1063
+ fragments.each((function(fragment) {
1064
+ this.element.parentNode.insertBefore(fragment, this.element);
1065
+ }).bind(this));
1066
+ }
1067
+ });
1068
+
1069
+ Insertion.Top = Class.create();
1070
+ Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
1071
+ initializeRange: function() {
1072
+ this.range.selectNodeContents(this.element);
1073
+ this.range.collapse(true);
1074
+ },
1075
+
1076
+ insertContent: function(fragments) {
1077
+ fragments.reverse(false).each((function(fragment) {
1078
+ this.element.insertBefore(fragment, this.element.firstChild);
1079
+ }).bind(this));
1080
+ }
1081
+ });
1082
+
1083
+ Insertion.Bottom = Class.create();
1084
+ Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
1085
+ initializeRange: function() {
1086
+ this.range.selectNodeContents(this.element);
1087
+ this.range.collapse(this.element);
1088
+ },
1089
+
1090
+ insertContent: function(fragments) {
1091
+ fragments.each((function(fragment) {
1092
+ this.element.appendChild(fragment);
1093
+ }).bind(this));
1094
+ }
1095
+ });
1096
+
1097
+ Insertion.After = Class.create();
1098
+ Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
1099
+ initializeRange: function() {
1100
+ this.range.setStartAfter(this.element);
1101
+ },
1102
+
1103
+ insertContent: function(fragments) {
1104
+ fragments.each((function(fragment) {
1105
+ this.element.parentNode.insertBefore(fragment,
1106
+ this.element.nextSibling);
1107
+ }).bind(this));
1108
+ }
1109
+ });
1110
+
1111
+ /*--------------------------------------------------------------------------*/
1112
+
1113
+ Element.ClassNames = Class.create();
1114
+ Element.ClassNames.prototype = {
1115
+ initialize: function(element) {
1116
+ this.element = $(element);
1117
+ },
1118
+
1119
+ _each: function(iterator) {
1120
+ this.element.className.split(/\s+/).select(function(name) {
1121
+ return name.length > 0;
1122
+ })._each(iterator);
1123
+ },
1124
+
1125
+ set: function(className) {
1126
+ this.element.className = className;
1127
+ },
1128
+
1129
+ add: function(classNameToAdd) {
1130
+ if (this.include(classNameToAdd)) return;
1131
+ this.set(this.toArray().concat(classNameToAdd).join(' '));
1132
+ },
1133
+
1134
+ remove: function(classNameToRemove) {
1135
+ if (!this.include(classNameToRemove)) return;
1136
+ this.set(this.select(function(className) {
1137
+ return className != classNameToRemove;
1138
+ }).join(' '));
1139
+ },
1140
+
1141
+ toString: function() {
1142
+ return this.toArray().join(' ');
1143
+ }
1144
+ }
1145
+
1146
+ Object.extend(Element.ClassNames.prototype, Enumerable);
1147
+ var Field = {
1148
+ clear: function() {
1149
+ for (var i = 0; i < arguments.length; i++)
1150
+ $(arguments[i]).value = '';
1151
+ },
1152
+
1153
+ focus: function(element) {
1154
+ $(element).focus();
1155
+ },
1156
+
1157
+ present: function() {
1158
+ for (var i = 0; i < arguments.length; i++)
1159
+ if ($(arguments[i]).value == '') return false;
1160
+ return true;
1161
+ },
1162
+
1163
+ select: function(element) {
1164
+ $(element).select();
1165
+ },
1166
+
1167
+ activate: function(element) {
1168
+ element = $(element);
1169
+ element.focus();
1170
+ if (element.select)
1171
+ element.select();
1172
+ }
1173
+ }
1174
+
1175
+ /*--------------------------------------------------------------------------*/
1176
+
1177
+ var Form = {
1178
+ serialize: function(form) {
1179
+ var elements = Form.getElements($(form));
1180
+ var queryComponents = new Array();
1181
+
1182
+ for (var i = 0; i < elements.length; i++) {
1183
+ var queryComponent = Form.Element.serialize(elements[i]);
1184
+ if (queryComponent)
1185
+ queryComponents.push(queryComponent);
1186
+ }
1187
+
1188
+ return queryComponents.join('&');
1189
+ },
1190
+
1191
+ getElements: function(form) {
1192
+ form = $(form);
1193
+ var elements = new Array();
1194
+
1195
+ for (tagName in Form.Element.Serializers) {
1196
+ var tagElements = form.getElementsByTagName(tagName);
1197
+ for (var j = 0; j < tagElements.length; j++)
1198
+ elements.push(tagElements[j]);
1199
+ }
1200
+ return elements;
1201
+ },
1202
+
1203
+ getInputs: function(form, typeName, name) {
1204
+ form = $(form);
1205
+ var inputs = form.getElementsByTagName('input');
1206
+
1207
+ if (!typeName && !name)
1208
+ return inputs;
1209
+
1210
+ var matchingInputs = new Array();
1211
+ for (var i = 0; i < inputs.length; i++) {
1212
+ var input = inputs[i];
1213
+ if ((typeName && input.type != typeName) ||
1214
+ (name && input.name != name))
1215
+ continue;
1216
+ matchingInputs.push(input);
1217
+ }
1218
+
1219
+ return matchingInputs;
1220
+ },
1221
+
1222
+ disable: function(form) {
1223
+ var elements = Form.getElements(form);
1224
+ for (var i = 0; i < elements.length; i++) {
1225
+ var element = elements[i];
1226
+ element.blur();
1227
+ element.disabled = 'true';
1228
+ }
1229
+ },
1230
+
1231
+ enable: function(form) {
1232
+ var elements = Form.getElements(form);
1233
+ for (var i = 0; i < elements.length; i++) {
1234
+ var element = elements[i];
1235
+ element.disabled = '';
1236
+ }
1237
+ },
1238
+
1239
+ findFirstElement: function(form) {
1240
+ return Form.getElements(form).find(function(element) {
1241
+ return element.type != 'hidden' && !element.disabled &&
1242
+ ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
1243
+ });
1244
+ },
1245
+
1246
+ focusFirstElement: function(form) {
1247
+ Field.activate(Form.findFirstElement(form));
1248
+ },
1249
+
1250
+ reset: function(form) {
1251
+ $(form).reset();
1252
+ }
1253
+ }
1254
+
1255
+ Form.Element = {
1256
+ serialize: function(element) {
1257
+ element = $(element);
1258
+ var method = element.tagName.toLowerCase();
1259
+ var parameter = Form.Element.Serializers[method](element);
1260
+
1261
+ if (parameter) {
1262
+ var key = encodeURIComponent(parameter[0]);
1263
+ if (key.length == 0) return;
1264
+
1265
+ if (parameter[1].constructor != Array)
1266
+ parameter[1] = [parameter[1]];
1267
+
1268
+ return parameter[1].map(function(value) {
1269
+ return key + '=' + encodeURIComponent(value);
1270
+ }).join('&');
1271
+ }
1272
+ },
1273
+
1274
+ getValue: function(element) {
1275
+ element = $(element);
1276
+ var method = element.tagName.toLowerCase();
1277
+ var parameter = Form.Element.Serializers[method](element);
1278
+
1279
+ if (parameter)
1280
+ return parameter[1];
1281
+ }
1282
+ }
1283
+
1284
+ Form.Element.Serializers = {
1285
+ input: function(element) {
1286
+ switch (element.type.toLowerCase()) {
1287
+ case 'submit':
1288
+ case 'hidden':
1289
+ case 'password':
1290
+ case 'text':
1291
+ return Form.Element.Serializers.textarea(element);
1292
+ case 'checkbox':
1293
+ case 'radio':
1294
+ return Form.Element.Serializers.inputSelector(element);
1295
+ }
1296
+ return false;
1297
+ },
1298
+
1299
+ inputSelector: function(element) {
1300
+ if (element.checked)
1301
+ return [element.name, element.value];
1302
+ },
1303
+
1304
+ textarea: function(element) {
1305
+ return [element.name, element.value];
1306
+ },
1307
+
1308
+ select: function(element) {
1309
+ return Form.Element.Serializers[element.type == 'select-one' ?
1310
+ 'selectOne' : 'selectMany'](element);
1311
+ },
1312
+
1313
+ selectOne: function(element) {
1314
+ var value = '', opt, index = element.selectedIndex;
1315
+ if (index >= 0) {
1316
+ opt = element.options[index];
1317
+ value = opt.value;
1318
+ if (!value && !('value' in opt))
1319
+ value = opt.text;
1320
+ }
1321
+ return [element.name, value];
1322
+ },
1323
+
1324
+ selectMany: function(element) {
1325
+ var value = new Array();
1326
+ for (var i = 0; i < element.length; i++) {
1327
+ var opt = element.options[i];
1328
+ if (opt.selected) {
1329
+ var optValue = opt.value;
1330
+ if (!optValue && !('value' in opt))
1331
+ optValue = opt.text;
1332
+ value.push(optValue);
1333
+ }
1334
+ }
1335
+ return [element.name, value];
1336
+ }
1337
+ }
1338
+
1339
+ /*--------------------------------------------------------------------------*/
1340
+
1341
+ var $F = Form.Element.getValue;
1342
+
1343
+ /*--------------------------------------------------------------------------*/
1344
+
1345
+ Abstract.TimedObserver = function() {}
1346
+ Abstract.TimedObserver.prototype = {
1347
+ initialize: function(element, frequency, callback) {
1348
+ this.frequency = frequency;
1349
+ this.element = $(element);
1350
+ this.callback = callback;
1351
+
1352
+ this.lastValue = this.getValue();
1353
+ this.registerCallback();
1354
+ },
1355
+
1356
+ registerCallback: function() {
1357
+ setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
1358
+ },
1359
+
1360
+ onTimerEvent: function() {
1361
+ var value = this.getValue();
1362
+ if (this.lastValue != value) {
1363
+ this.callback(this.element, value);
1364
+ this.lastValue = value;
1365
+ }
1366
+ }
1367
+ }
1368
+
1369
+ Form.Element.Observer = Class.create();
1370
+ Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
1371
+ getValue: function() {
1372
+ return Form.Element.getValue(this.element);
1373
+ }
1374
+ });
1375
+
1376
+ Form.Observer = Class.create();
1377
+ Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
1378
+ getValue: function() {
1379
+ return Form.serialize(this.element);
1380
+ }
1381
+ });
1382
+
1383
+ /*--------------------------------------------------------------------------*/
1384
+
1385
+ Abstract.EventObserver = function() {}
1386
+ Abstract.EventObserver.prototype = {
1387
+ initialize: function(element, callback) {
1388
+ this.element = $(element);
1389
+ this.callback = callback;
1390
+
1391
+ this.lastValue = this.getValue();
1392
+ if (this.element.tagName.toLowerCase() == 'form')
1393
+ this.registerFormCallbacks();
1394
+ else
1395
+ this.registerCallback(this.element);
1396
+ },
1397
+
1398
+ onElementEvent: function() {
1399
+ var value = this.getValue();
1400
+ if (this.lastValue != value) {
1401
+ this.callback(this.element, value);
1402
+ this.lastValue = value;
1403
+ }
1404
+ },
1405
+
1406
+ registerFormCallbacks: function() {
1407
+ var elements = Form.getElements(this.element);
1408
+ for (var i = 0; i < elements.length; i++)
1409
+ this.registerCallback(elements[i]);
1410
+ },
1411
+
1412
+ registerCallback: function(element) {
1413
+ if (element.type) {
1414
+ switch (element.type.toLowerCase()) {
1415
+ case 'checkbox':
1416
+ case 'radio':
1417
+ Event.observe(element, 'click', this.onElementEvent.bind(this));
1418
+ break;
1419
+ case 'password':
1420
+ case 'text':
1421
+ case 'textarea':
1422
+ case 'select-one':
1423
+ case 'select-multiple':
1424
+ Event.observe(element, 'change', this.onElementEvent.bind(this));
1425
+ break;
1426
+ }
1427
+ }
1428
+ }
1429
+ }
1430
+
1431
+ Form.Element.EventObserver = Class.create();
1432
+ Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
1433
+ getValue: function() {
1434
+ return Form.Element.getValue(this.element);
1435
+ }
1436
+ });
1437
+
1438
+ Form.EventObserver = Class.create();
1439
+ Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
1440
+ getValue: function() {
1441
+ return Form.serialize(this.element);
1442
+ }
1443
+ });
1444
+ if (!window.Event) {
1445
+ var Event = new Object();
1446
+ }
1447
+
1448
+ Object.extend(Event, {
1449
+ KEY_BACKSPACE: 8,
1450
+ KEY_TAB: 9,
1451
+ KEY_RETURN: 13,
1452
+ KEY_ESC: 27,
1453
+ KEY_LEFT: 37,
1454
+ KEY_UP: 38,
1455
+ KEY_RIGHT: 39,
1456
+ KEY_DOWN: 40,
1457
+ KEY_DELETE: 46,
1458
+
1459
+ element: function(event) {
1460
+ return event.target || event.srcElement;
1461
+ },
1462
+
1463
+ isLeftClick: function(event) {
1464
+ return (((event.which) && (event.which == 1)) ||
1465
+ ((event.button) && (event.button == 1)));
1466
+ },
1467
+
1468
+ pointerX: function(event) {
1469
+ return event.pageX || (event.clientX +
1470
+ (document.documentElement.scrollLeft || document.body.scrollLeft));
1471
+ },
1472
+
1473
+ pointerY: function(event) {
1474
+ return event.pageY || (event.clientY +
1475
+ (document.documentElement.scrollTop || document.body.scrollTop));
1476
+ },
1477
+
1478
+ stop: function(event) {
1479
+ if (event.preventDefault) {
1480
+ event.preventDefault();
1481
+ event.stopPropagation();
1482
+ } else {
1483
+ event.returnValue = false;
1484
+ event.cancelBubble = true;
1485
+ }
1486
+ },
1487
+
1488
+ // find the first node with the given tagName, starting from the
1489
+ // node the event was triggered on; traverses the DOM upwards
1490
+ findElement: function(event, tagName) {
1491
+ var element = Event.element(event);
1492
+ while (element.parentNode && (!element.tagName ||
1493
+ (element.tagName.toUpperCase() != tagName.toUpperCase())))
1494
+ element = element.parentNode;
1495
+ return element;
1496
+ },
1497
+
1498
+ observers: false,
1499
+
1500
+ _observeAndCache: function(element, name, observer, useCapture) {
1501
+ if (!this.observers) this.observers = [];
1502
+ if (element.addEventListener) {
1503
+ this.observers.push([element, name, observer, useCapture]);
1504
+ element.addEventListener(name, observer, useCapture);
1505
+ } else if (element.attachEvent) {
1506
+ this.observers.push([element, name, observer, useCapture]);
1507
+ element.attachEvent('on' + name, observer);
1508
+ }
1509
+ },
1510
+
1511
+ unloadCache: function() {
1512
+ if (!Event.observers) return;
1513
+ for (var i = 0; i < Event.observers.length; i++) {
1514
+ Event.stopObserving.apply(this, Event.observers[i]);
1515
+ Event.observers[i][0] = null;
1516
+ }
1517
+ Event.observers = false;
1518
+ },
1519
+
1520
+ observe: function(element, name, observer, useCapture) {
1521
+ var element = $(element);
1522
+ useCapture = useCapture || false;
1523
+
1524
+ if (name == 'keypress' &&
1525
+ (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
1526
+ || element.attachEvent))
1527
+ name = 'keydown';
1528
+
1529
+ this._observeAndCache(element, name, observer, useCapture);
1530
+ },
1531
+
1532
+ stopObserving: function(element, name, observer, useCapture) {
1533
+ var element = $(element);
1534
+ useCapture = useCapture || false;
1535
+
1536
+ if (name == 'keypress' &&
1537
+ (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
1538
+ || element.detachEvent))
1539
+ name = 'keydown';
1540
+
1541
+ if (element.removeEventListener) {
1542
+ element.removeEventListener(name, observer, useCapture);
1543
+ } else if (element.detachEvent) {
1544
+ element.detachEvent('on' + name, observer);
1545
+ }
1546
+ }
1547
+ });
1548
+
1549
+ /* prevent memory leaks in IE */
1550
+ Event.observe(window, 'unload', Event.unloadCache, false);
1551
+ var Position = {
1552
+ // set to true if needed, warning: firefox performance problems
1553
+ // NOT neeeded for page scrolling, only if draggable contained in
1554
+ // scrollable elements
1555
+ includeScrollOffsets: false,
1556
+
1557
+ // must be called before calling withinIncludingScrolloffset, every time the
1558
+ // page is scrolled
1559
+ prepare: function() {
1560
+ this.deltaX = window.pageXOffset
1561
+ || document.documentElement.scrollLeft
1562
+ || document.body.scrollLeft
1563
+ || 0;
1564
+ this.deltaY = window.pageYOffset
1565
+ || document.documentElement.scrollTop
1566
+ || document.body.scrollTop
1567
+ || 0;
1568
+ },
1569
+
1570
+ realOffset: function(element) {
1571
+ var valueT = 0, valueL = 0;
1572
+ do {
1573
+ valueT += element.scrollTop || 0;
1574
+ valueL += element.scrollLeft || 0;
1575
+ element = element.parentNode;
1576
+ } while (element);
1577
+ return [valueL, valueT];
1578
+ },
1579
+
1580
+ cumulativeOffset: function(element) {
1581
+ var valueT = 0, valueL = 0;
1582
+ do {
1583
+ valueT += element.offsetTop || 0;
1584
+ valueL += element.offsetLeft || 0;
1585
+ element = element.offsetParent;
1586
+ } while (element);
1587
+ return [valueL, valueT];
1588
+ },
1589
+
1590
+ positionedOffset: function(element) {
1591
+ var valueT = 0, valueL = 0;
1592
+ do {
1593
+ valueT += element.offsetTop || 0;
1594
+ valueL += element.offsetLeft || 0;
1595
+ element = element.offsetParent;
1596
+ if (element) {
1597
+ p = Element.getStyle(element, 'position');
1598
+ if (p == 'relative' || p == 'absolute') break;
1599
+ }
1600
+ } while (element);
1601
+ return [valueL, valueT];
1602
+ },
1603
+
1604
+ offsetParent: function(element) {
1605
+ if (element.offsetParent) return element.offsetParent;
1606
+ if (element == document.body) return element;
1607
+
1608
+ while ((element = element.parentNode) && element != document.body)
1609
+ if (Element.getStyle(element, 'position') != 'static')
1610
+ return element;
1611
+
1612
+ return document.body;
1613
+ },
1614
+
1615
+ // caches x/y coordinate pair to use with overlap
1616
+ within: function(element, x, y) {
1617
+ if (this.includeScrollOffsets)
1618
+ return this.withinIncludingScrolloffsets(element, x, y);
1619
+ this.xcomp = x;
1620
+ this.ycomp = y;
1621
+ this.offset = this.cumulativeOffset(element);
1622
+
1623
+ return (y >= this.offset[1] &&
1624
+ y < this.offset[1] + element.offsetHeight &&
1625
+ x >= this.offset[0] &&
1626
+ x < this.offset[0] + element.offsetWidth);
1627
+ },
1628
+
1629
+ withinIncludingScrolloffsets: function(element, x, y) {
1630
+ var offsetcache = this.realOffset(element);
1631
+
1632
+ this.xcomp = x + offsetcache[0] - this.deltaX;
1633
+ this.ycomp = y + offsetcache[1] - this.deltaY;
1634
+ this.offset = this.cumulativeOffset(element);
1635
+
1636
+ return (this.ycomp >= this.offset[1] &&
1637
+ this.ycomp < this.offset[1] + element.offsetHeight &&
1638
+ this.xcomp >= this.offset[0] &&
1639
+ this.xcomp < this.offset[0] + element.offsetWidth);
1640
+ },
1641
+
1642
+ // within must be called directly before
1643
+ overlap: function(mode, element) {
1644
+ if (!mode) return 0;
1645
+ if (mode == 'vertical')
1646
+ return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
1647
+ element.offsetHeight;
1648
+ if (mode == 'horizontal')
1649
+ return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
1650
+ element.offsetWidth;
1651
+ },
1652
+
1653
+ clone: function(source, target) {
1654
+ source = $(source);
1655
+ target = $(target);
1656
+ target.style.position = 'absolute';
1657
+ var offsets = this.cumulativeOffset(source);
1658
+ target.style.top = offsets[1] + 'px';
1659
+ target.style.left = offsets[0] + 'px';
1660
+ target.style.width = source.offsetWidth + 'px';
1661
+ target.style.height = source.offsetHeight + 'px';
1662
+ },
1663
+
1664
+ page: function(forElement) {
1665
+ var valueT = 0, valueL = 0;
1666
+
1667
+ var element = forElement;
1668
+ do {
1669
+ valueT += element.offsetTop || 0;
1670
+ valueL += element.offsetLeft || 0;
1671
+
1672
+ // Safari fix
1673
+ if (element.offsetParent==document.body)
1674
+ if (Element.getStyle(element,'position')=='absolute') break;
1675
+
1676
+ } while (element = element.offsetParent);
1677
+
1678
+ element = forElement;
1679
+ do {
1680
+ valueT -= element.scrollTop || 0;
1681
+ valueL -= element.scrollLeft || 0;
1682
+ } while (element = element.parentNode);
1683
+
1684
+ return [valueL, valueT];
1685
+ },
1686
+
1687
+ clone: function(source, target) {
1688
+ var options = Object.extend({
1689
+ setLeft: true,
1690
+ setTop: true,
1691
+ setWidth: true,
1692
+ setHeight: true,
1693
+ offsetTop: 0,
1694
+ offsetLeft: 0
1695
+ }, arguments[2] || {})
1696
+
1697
+ // find page position of source
1698
+ source = $(source);
1699
+ var p = Position.page(source);
1700
+
1701
+ // find coordinate system to use
1702
+ target = $(target);
1703
+ var delta = [0, 0];
1704
+ var parent = null;
1705
+ // delta [0,0] will do fine with position: fixed elements,
1706
+ // position:absolute needs offsetParent deltas
1707
+ if (Element.getStyle(target,'position') == 'absolute') {
1708
+ parent = Position.offsetParent(target);
1709
+ delta = Position.page(parent);
1710
+ }
1711
+
1712
+ // correct by body offsets (fixes Safari)
1713
+ if (parent == document.body) {
1714
+ delta[0] -= document.body.offsetLeft;
1715
+ delta[1] -= document.body.offsetTop;
1716
+ }
1717
+
1718
+ // set position
1719
+ if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
1720
+ if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
1721
+ if(options.setWidth) target.style.width = source.offsetWidth + 'px';
1722
+ if(options.setHeight) target.style.height = source.offsetHeight + 'px';
1723
+ },
1724
+
1725
+ absolutize: function(element) {
1726
+ element = $(element);
1727
+ if (element.style.position == 'absolute') return;
1728
+ Position.prepare();
1729
+
1730
+ var offsets = Position.positionedOffset(element);
1731
+ var top = offsets[1];
1732
+ var left = offsets[0];
1733
+ var width = element.clientWidth;
1734
+ var height = element.clientHeight;
1735
+
1736
+ element._originalLeft = left - parseFloat(element.style.left || 0);
1737
+ element._originalTop = top - parseFloat(element.style.top || 0);
1738
+ element._originalWidth = element.style.width;
1739
+ element._originalHeight = element.style.height;
1740
+
1741
+ element.style.position = 'absolute';
1742
+ element.style.top = top + 'px';;
1743
+ element.style.left = left + 'px';;
1744
+ element.style.width = width + 'px';;
1745
+ element.style.height = height + 'px';;
1746
+ },
1747
+
1748
+ relativize: function(element) {
1749
+ element = $(element);
1750
+ if (element.style.position == 'relative') return;
1751
+ Position.prepare();
1752
+
1753
+ element.style.position = 'relative';
1754
+ var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
1755
+ var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
1756
+
1757
+ element.style.top = top + 'px';
1758
+ element.style.left = left + 'px';
1759
+ element.style.height = element._originalHeight;
1760
+ element.style.width = element._originalWidth;
1761
+ }
1762
+ }
1763
+
1764
+ // Safari returns margins on body which is incorrect if the child is absolutely
1765
+ // positioned. For performance reasons, redefine Position.cumulativeOffset for
1766
+ // KHTML/WebKit only.
1767
+ if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
1768
+ Position.cumulativeOffset = function(element) {
1769
+ var valueT = 0, valueL = 0;
1770
+ do {
1771
+ valueT += element.offsetTop || 0;
1772
+ valueL += element.offsetLeft || 0;
1773
+ if (element.offsetParent == document.body)
1774
+ if (Element.getStyle(element, 'position') == 'absolute') break;
1775
+
1776
+ element = element.offsetParent;
1777
+ } while (element);
1778
+
1779
+ return [valueL, valueT];
1780
+ }
1781
+ }