merb 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/README +41 -2
  2. data/Rakefile +4 -2
  3. data/TODO +3 -3
  4. data/bin/merb +157 -3
  5. data/doc/rdoc/classes/Hash.html +4 -4
  6. data/doc/rdoc/classes/Merb.html +2 -12
  7. data/doc/rdoc/classes/Merb/Controller.html +347 -156
  8. data/doc/rdoc/classes/Merb/RouteMatcher.html +93 -59
  9. data/doc/rdoc/classes/MerbHandler.html +117 -107
  10. data/doc/rdoc/classes/MerbHash.html +64 -58
  11. data/doc/rdoc/classes/Noroutefound.html +16 -10
  12. data/doc/rdoc/classes/Object.html +5 -5
  13. data/doc/rdoc/classes/String.html +28 -16
  14. data/doc/rdoc/classes/Symbol.html +15 -8
  15. data/doc/rdoc/created.rid +1 -1
  16. data/doc/rdoc/files/README.html +56 -4
  17. data/doc/rdoc/files/TODO.html +4 -4
  18. data/doc/rdoc/files/lib/merb/merb_controller_rb.html +1 -1
  19. data/doc/rdoc/files/lib/merb/merb_handler_rb.html +1 -1
  20. data/doc/rdoc/files/lib/merb/merb_router_rb.html +1 -1
  21. data/doc/rdoc/files/lib/merb/merb_utils_rb.html +1 -1
  22. data/doc/rdoc/files/lib/merb_rb.html +30 -2
  23. data/doc/rdoc/files/lib/{merb_config_rb.html → merb_tasks_rb.html} +4 -4
  24. data/doc/rdoc/fr_class_index.html +0 -2
  25. data/doc/rdoc/fr_file_index.html +1 -3
  26. data/doc/rdoc/fr_method_index.html +21 -21
  27. data/examples/app_skeleton/Rakefile +81 -0
  28. data/examples/app_skeleton/dist/conf/merb_init.rb +15 -0
  29. data/examples/{skeleton → app_skeleton}/dist/conf/router.rb +5 -7
  30. data/examples/app_skeleton/scripts/merb_stop +5 -0
  31. data/examples/app_skeleton/scripts/new_migration +21 -0
  32. data/examples/{skeleton → app_skeleton}/test/test_helper.rb +0 -0
  33. data/examples/sample_app/Rakefile +81 -0
  34. data/examples/sample_app/dist/app/controllers/posts.rb +26 -10
  35. data/examples/sample_app/dist/app/models/comment.rb +3 -0
  36. data/examples/sample_app/dist/app/models/post.rb +2 -11
  37. data/examples/sample_app/dist/app/views/layout/application.rhtml +59 -4
  38. data/examples/sample_app/dist/app/views/posts/_comments.rhtml +11 -0
  39. data/examples/sample_app/dist/app/views/posts/comment.merbjs +1 -0
  40. data/examples/sample_app/dist/app/views/posts/list.rhtml +2 -4
  41. data/examples/sample_app/dist/app/views/posts/new.rhtml +2 -2
  42. data/examples/sample_app/dist/app/views/posts/show.rhtml +35 -3
  43. data/examples/sample_app/dist/conf/merb_init.rb +2 -4
  44. data/examples/sample_app/dist/conf/router.rb +3 -4
  45. data/examples/sample_app/dist/public/images/bg.jpg +0 -0
  46. data/examples/sample_app/dist/public/images/book.gif +0 -0
  47. data/examples/sample_app/dist/public/images/booksmall.gif +0 -0
  48. data/examples/sample_app/dist/public/images/greenright.jpg +0 -0
  49. data/examples/sample_app/dist/public/images/louiecon.gif +0 -0
  50. data/examples/sample_app/dist/public/images/menu.gif +0 -0
  51. data/examples/sample_app/dist/public/images/menuleft.gif +0 -0
  52. data/examples/sample_app/dist/public/images/menuright.gif +0 -0
  53. data/examples/sample_app/dist/public/images/mountain.jpg +0 -0
  54. data/examples/sample_app/dist/public/images/n3.jpg +0 -0
  55. data/examples/sample_app/dist/public/images/nautica.jpg +0 -0
  56. data/examples/sample_app/dist/public/javascripts/application.js +0 -0
  57. data/examples/sample_app/dist/public/javascripts/effects.js +975 -0
  58. data/examples/sample_app/dist/public/javascripts/prototype.js +2264 -0
  59. data/examples/sample_app/dist/public/stylesheets/merb.css +277 -0
  60. data/examples/sample_app/dist/schema/migrations/001_add_comments_to_posts.rb +22 -0
  61. data/examples/sample_app/dist/schema/schema.rb +22 -0
  62. data/examples/sample_app/log/merb.log +164394 -0
  63. data/examples/sample_app/script/merb_stop +9 -0
  64. data/examples/sample_app/script/new_migration +21 -0
  65. data/lib/merb.rb +7 -4
  66. data/lib/merb/merb_controller.rb +83 -4
  67. data/lib/merb/merb_handler.rb +20 -9
  68. data/lib/merb/merb_router.rb +18 -1
  69. data/lib/merb/merb_utils.rb +11 -1
  70. data/lib/merb_tasks.rb +7 -0
  71. data/lib/tasks/db.rake +53 -0
  72. metadata +67 -34
  73. data/doc/rdoc/classes/Merb/Config.html +0 -161
  74. data/doc/rdoc/classes/Merb/Server.html +0 -288
  75. data/doc/rdoc/files/lib/merb/merb_daemon_rb.html +0 -113
  76. data/doc/rdoc/files/lib/merb/noroutefound_rb.html +0 -101
  77. data/examples/sample_app/dist/app/views/layout/posts.rhtml +0 -6
  78. data/examples/skeleton/dist/conf/merb_init.rb +0 -21
  79. data/lib/merb/merb_daemon.rb +0 -91
  80. data/lib/merb/noroutefound.rb +0 -11
  81. data/lib/merb_config.rb +0 -21
@@ -0,0 +1,2264 @@
1
+ /* Prototype JavaScript framework, version 1.5.0_rc1
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.5.0_rc1',
11
+ BrowserFeatures: {
12
+ XPath: !!document.evaluate
13
+ },
14
+
15
+ ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
16
+ emptyFunction: function() {},
17
+ K: function(x) { return x }
18
+ }
19
+
20
+ var Class = {
21
+ create: function() {
22
+ return function() {
23
+ this.initialize.apply(this, arguments);
24
+ }
25
+ }
26
+ }
27
+
28
+ var Abstract = new Object();
29
+
30
+ Object.extend = function(destination, source) {
31
+ for (var property in source) {
32
+ destination[property] = source[property];
33
+ }
34
+ return destination;
35
+ }
36
+
37
+ Object.extend(Object, {
38
+ inspect: function(object) {
39
+ try {
40
+ if (object == undefined) return 'undefined';
41
+ if (object == null) return 'null';
42
+ return object.inspect ? object.inspect() : object.toString();
43
+ } catch (e) {
44
+ if (e instanceof RangeError) return '...';
45
+ throw e;
46
+ }
47
+ },
48
+
49
+ keys: function(object) {
50
+ var keys = [];
51
+ for (var property in object)
52
+ keys.push(property);
53
+ return keys;
54
+ },
55
+
56
+ values: function(object) {
57
+ var values = [];
58
+ for (var property in object)
59
+ values.push(object[property]);
60
+ return values;
61
+ },
62
+
63
+ clone: function(object) {
64
+ return Object.extend({}, object);
65
+ }
66
+ });
67
+
68
+ Function.prototype.bind = function() {
69
+ var __method = this, args = $A(arguments), object = args.shift();
70
+ return function() {
71
+ return __method.apply(object, args.concat($A(arguments)));
72
+ }
73
+ }
74
+
75
+ Function.prototype.bindAsEventListener = function(object) {
76
+ var __method = this, args = $A(arguments), object = args.shift();
77
+ return function(event) {
78
+ return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));
79
+ }
80
+ }
81
+
82
+ Object.extend(Number.prototype, {
83
+ toColorPart: function() {
84
+ var digits = this.toString(16);
85
+ if (this < 16) return '0' + digits;
86
+ return digits;
87
+ },
88
+
89
+ succ: function() {
90
+ return this + 1;
91
+ },
92
+
93
+ times: function(iterator) {
94
+ $R(0, this, true).each(iterator);
95
+ return this;
96
+ }
97
+ });
98
+
99
+ var Try = {
100
+ these: function() {
101
+ var returnValue;
102
+
103
+ for (var i = 0; i < arguments.length; i++) {
104
+ var lambda = arguments[i];
105
+ try {
106
+ returnValue = lambda();
107
+ break;
108
+ } catch (e) {}
109
+ }
110
+
111
+ return returnValue;
112
+ }
113
+ }
114
+
115
+ /*--------------------------------------------------------------------------*/
116
+
117
+ var PeriodicalExecuter = Class.create();
118
+ PeriodicalExecuter.prototype = {
119
+ initialize: function(callback, frequency) {
120
+ this.callback = callback;
121
+ this.frequency = frequency;
122
+ this.currentlyExecuting = false;
123
+
124
+ this.registerCallback();
125
+ },
126
+
127
+ registerCallback: function() {
128
+ this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
129
+ },
130
+
131
+ stop: function() {
132
+ if (!this.timer) return;
133
+ clearInterval(this.timer);
134
+ this.timer = null;
135
+ },
136
+
137
+ onTimerEvent: function() {
138
+ if (!this.currentlyExecuting) {
139
+ try {
140
+ this.currentlyExecuting = true;
141
+ this.callback(this);
142
+ } finally {
143
+ this.currentlyExecuting = false;
144
+ }
145
+ }
146
+ }
147
+ }
148
+ Object.extend(String.prototype, {
149
+ gsub: function(pattern, replacement) {
150
+ var result = '', source = this, match;
151
+ replacement = arguments.callee.prepareReplacement(replacement);
152
+
153
+ while (source.length > 0) {
154
+ if (match = source.match(pattern)) {
155
+ result += source.slice(0, match.index);
156
+ result += (replacement(match) || '').toString();
157
+ source = source.slice(match.index + match[0].length);
158
+ } else {
159
+ result += source, source = '';
160
+ }
161
+ }
162
+ return result;
163
+ },
164
+
165
+ sub: function(pattern, replacement, count) {
166
+ replacement = this.gsub.prepareReplacement(replacement);
167
+ count = count === undefined ? 1 : count;
168
+
169
+ return this.gsub(pattern, function(match) {
170
+ if (--count < 0) return match[0];
171
+ return replacement(match);
172
+ });
173
+ },
174
+
175
+ scan: function(pattern, iterator) {
176
+ this.gsub(pattern, iterator);
177
+ return this;
178
+ },
179
+
180
+ truncate: function(length, truncation) {
181
+ length = length || 30;
182
+ truncation = truncation === undefined ? '...' : truncation;
183
+ return this.length > length ?
184
+ this.slice(0, length - truncation.length) + truncation : this;
185
+ },
186
+
187
+ strip: function() {
188
+ return this.replace(/^\s+/, '').replace(/\s+$/, '');
189
+ },
190
+
191
+ stripTags: function() {
192
+ return this.replace(/<\/?[^>]+>/gi, '');
193
+ },
194
+
195
+ stripScripts: function() {
196
+ return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
197
+ },
198
+
199
+ extractScripts: function() {
200
+ var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
201
+ var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
202
+ return (this.match(matchAll) || []).map(function(scriptTag) {
203
+ return (scriptTag.match(matchOne) || ['', ''])[1];
204
+ });
205
+ },
206
+
207
+ evalScripts: function() {
208
+ return this.extractScripts().map(function(script) { return eval(script) });
209
+ },
210
+
211
+ escapeHTML: function() {
212
+ var div = document.createElement('div');
213
+ var text = document.createTextNode(this);
214
+ div.appendChild(text);
215
+ return div.innerHTML;
216
+ },
217
+
218
+ unescapeHTML: function() {
219
+ var div = document.createElement('div');
220
+ div.innerHTML = this.stripTags();
221
+ return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
222
+ },
223
+
224
+ toQueryParams: function() {
225
+ var pairs = this.match(/^\??(.*)$/)[1].split('&');
226
+ return pairs.inject({}, function(params, pairString) {
227
+ var pair = pairString.split('=');
228
+ var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
229
+ params[decodeURIComponent(pair[0])] = value;
230
+ return params;
231
+ });
232
+ },
233
+
234
+ toArray: function() {
235
+ return this.split('');
236
+ },
237
+
238
+ camelize: function() {
239
+ var oStringList = this.split('-');
240
+ if (oStringList.length == 1) return oStringList[0];
241
+
242
+ var camelizedString = this.indexOf('-') == 0
243
+ ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
244
+ : oStringList[0];
245
+
246
+ for (var i = 1, len = oStringList.length; i < len; i++) {
247
+ var s = oStringList[i];
248
+ camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
249
+ }
250
+
251
+ return camelizedString;
252
+ },
253
+
254
+ inspect: function(useDoubleQuotes) {
255
+ var escapedString = this.replace(/\\/g, '\\\\');
256
+ if (useDoubleQuotes)
257
+ return '"' + escapedString.replace(/"/g, '\\"') + '"';
258
+ else
259
+ return "'" + escapedString.replace(/'/g, '\\\'') + "'";
260
+ }
261
+ });
262
+
263
+ String.prototype.gsub.prepareReplacement = function(replacement) {
264
+ if (typeof replacement == 'function') return replacement;
265
+ var template = new Template(replacement);
266
+ return function(match) { return template.evaluate(match) };
267
+ }
268
+
269
+ String.prototype.parseQuery = String.prototype.toQueryParams;
270
+
271
+ var Template = Class.create();
272
+ Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
273
+ Template.prototype = {
274
+ initialize: function(template, pattern) {
275
+ this.template = template.toString();
276
+ this.pattern = pattern || Template.Pattern;
277
+ },
278
+
279
+ evaluate: function(object) {
280
+ return this.template.gsub(this.pattern, function(match) {
281
+ var before = match[1];
282
+ if (before == '\\') return match[2];
283
+ return before + (object[match[3]] || '').toString();
284
+ });
285
+ }
286
+ }
287
+
288
+ var $break = new Object();
289
+ var $continue = new Object();
290
+
291
+ var Enumerable = {
292
+ each: function(iterator) {
293
+ var index = 0;
294
+ try {
295
+ this._each(function(value) {
296
+ try {
297
+ iterator(value, index++);
298
+ } catch (e) {
299
+ if (e != $continue) throw e;
300
+ }
301
+ });
302
+ } catch (e) {
303
+ if (e != $break) throw e;
304
+ }
305
+ },
306
+
307
+ all: function(iterator) {
308
+ var result = true;
309
+ this.each(function(value, index) {
310
+ result = result && !!(iterator || Prototype.K)(value, index);
311
+ if (!result) throw $break;
312
+ });
313
+ return result;
314
+ },
315
+
316
+ any: function(iterator) {
317
+ var result = false;
318
+ this.each(function(value, index) {
319
+ if (result = !!(iterator || Prototype.K)(value, index))
320
+ throw $break;
321
+ });
322
+ return result;
323
+ },
324
+
325
+ collect: function(iterator) {
326
+ var results = [];
327
+ this.each(function(value, index) {
328
+ results.push(iterator(value, index));
329
+ });
330
+ return results;
331
+ },
332
+
333
+ detect: function (iterator) {
334
+ var result;
335
+ this.each(function(value, index) {
336
+ if (iterator(value, index)) {
337
+ result = value;
338
+ throw $break;
339
+ }
340
+ });
341
+ return result;
342
+ },
343
+
344
+ findAll: function(iterator) {
345
+ var results = [];
346
+ this.each(function(value, index) {
347
+ if (iterator(value, index))
348
+ results.push(value);
349
+ });
350
+ return results;
351
+ },
352
+
353
+ grep: function(pattern, iterator) {
354
+ var results = [];
355
+ this.each(function(value, index) {
356
+ var stringValue = value.toString();
357
+ if (stringValue.match(pattern))
358
+ results.push((iterator || Prototype.K)(value, index));
359
+ })
360
+ return results;
361
+ },
362
+
363
+ include: function(object) {
364
+ var found = false;
365
+ this.each(function(value) {
366
+ if (value == object) {
367
+ found = true;
368
+ throw $break;
369
+ }
370
+ });
371
+ return found;
372
+ },
373
+
374
+ inject: function(memo, iterator) {
375
+ this.each(function(value, index) {
376
+ memo = iterator(memo, value, index);
377
+ });
378
+ return memo;
379
+ },
380
+
381
+ invoke: function(method) {
382
+ var args = $A(arguments).slice(1);
383
+ return this.collect(function(value) {
384
+ return value[method].apply(value, args);
385
+ });
386
+ },
387
+
388
+ max: function(iterator) {
389
+ var result;
390
+ this.each(function(value, index) {
391
+ value = (iterator || Prototype.K)(value, index);
392
+ if (result == undefined || value >= result)
393
+ result = value;
394
+ });
395
+ return result;
396
+ },
397
+
398
+ min: function(iterator) {
399
+ var result;
400
+ this.each(function(value, index) {
401
+ value = (iterator || Prototype.K)(value, index);
402
+ if (result == undefined || value < result)
403
+ result = value;
404
+ });
405
+ return result;
406
+ },
407
+
408
+ partition: function(iterator) {
409
+ var trues = [], falses = [];
410
+ this.each(function(value, index) {
411
+ ((iterator || Prototype.K)(value, index) ?
412
+ trues : falses).push(value);
413
+ });
414
+ return [trues, falses];
415
+ },
416
+
417
+ pluck: function(property) {
418
+ var results = [];
419
+ this.each(function(value, index) {
420
+ results.push(value[property]);
421
+ });
422
+ return results;
423
+ },
424
+
425
+ reject: function(iterator) {
426
+ var results = [];
427
+ this.each(function(value, index) {
428
+ if (!iterator(value, index))
429
+ results.push(value);
430
+ });
431
+ return results;
432
+ },
433
+
434
+ sortBy: function(iterator) {
435
+ return this.collect(function(value, index) {
436
+ return {value: value, criteria: iterator(value, index)};
437
+ }).sort(function(left, right) {
438
+ var a = left.criteria, b = right.criteria;
439
+ return a < b ? -1 : a > b ? 1 : 0;
440
+ }).pluck('value');
441
+ },
442
+
443
+ toArray: function() {
444
+ return this.collect(Prototype.K);
445
+ },
446
+
447
+ zip: function() {
448
+ var iterator = Prototype.K, args = $A(arguments);
449
+ if (typeof args.last() == 'function')
450
+ iterator = args.pop();
451
+
452
+ var collections = [this].concat(args).map($A);
453
+ return this.map(function(value, index) {
454
+ return iterator(collections.pluck(index));
455
+ });
456
+ },
457
+
458
+ inspect: function() {
459
+ return '#<Enumerable:' + this.toArray().inspect() + '>';
460
+ }
461
+ }
462
+
463
+ Object.extend(Enumerable, {
464
+ map: Enumerable.collect,
465
+ find: Enumerable.detect,
466
+ select: Enumerable.findAll,
467
+ member: Enumerable.include,
468
+ entries: Enumerable.toArray
469
+ });
470
+ var $A = Array.from = function(iterable) {
471
+ if (!iterable) return [];
472
+ if (iterable.toArray) {
473
+ return iterable.toArray();
474
+ } else {
475
+ var results = [];
476
+ for (var i = 0; i < iterable.length; i++)
477
+ results.push(iterable[i]);
478
+ return results;
479
+ }
480
+ }
481
+
482
+ Object.extend(Array.prototype, Enumerable);
483
+
484
+ if (!Array.prototype._reverse)
485
+ Array.prototype._reverse = Array.prototype.reverse;
486
+
487
+ Object.extend(Array.prototype, {
488
+ _each: function(iterator) {
489
+ for (var i = 0; i < this.length; i++)
490
+ iterator(this[i]);
491
+ },
492
+
493
+ clear: function() {
494
+ this.length = 0;
495
+ return this;
496
+ },
497
+
498
+ first: function() {
499
+ return this[0];
500
+ },
501
+
502
+ last: function() {
503
+ return this[this.length - 1];
504
+ },
505
+
506
+ compact: function() {
507
+ return this.select(function(value) {
508
+ return value != undefined || value != null;
509
+ });
510
+ },
511
+
512
+ flatten: function() {
513
+ return this.inject([], function(array, value) {
514
+ return array.concat(value && value.constructor == Array ?
515
+ value.flatten() : [value]);
516
+ });
517
+ },
518
+
519
+ without: function() {
520
+ var values = $A(arguments);
521
+ return this.select(function(value) {
522
+ return !values.include(value);
523
+ });
524
+ },
525
+
526
+ indexOf: function(object) {
527
+ for (var i = 0; i < this.length; i++)
528
+ if (this[i] == object) return i;
529
+ return -1;
530
+ },
531
+
532
+ reverse: function(inline) {
533
+ return (inline !== false ? this : this.toArray())._reverse();
534
+ },
535
+
536
+ reduce: function() {
537
+ return this.length > 1 ? this : this[0];
538
+ },
539
+
540
+ uniq: function() {
541
+ return this.inject([], function(array, value) {
542
+ return array.include(value) ? array : array.concat([value]);
543
+ });
544
+ },
545
+
546
+ inspect: function() {
547
+ return '[' + this.map(Object.inspect).join(', ') + ']';
548
+ }
549
+ });
550
+ var Hash = {
551
+ _each: function(iterator) {
552
+ for (var key in this) {
553
+ var value = this[key];
554
+ if (typeof value == 'function') continue;
555
+
556
+ var pair = [key, value];
557
+ pair.key = key;
558
+ pair.value = value;
559
+ iterator(pair);
560
+ }
561
+ },
562
+
563
+ keys: function() {
564
+ return this.pluck('key');
565
+ },
566
+
567
+ values: function() {
568
+ return this.pluck('value');
569
+ },
570
+
571
+ merge: function(hash) {
572
+ return $H(hash).inject($H(this), function(mergedHash, pair) {
573
+ mergedHash[pair.key] = pair.value;
574
+ return mergedHash;
575
+ });
576
+ },
577
+
578
+ toQueryString: function() {
579
+ return this.map(function(pair) {
580
+ return pair.map(encodeURIComponent).join('=');
581
+ }).join('&');
582
+ },
583
+
584
+ inspect: function() {
585
+ return '#<Hash:{' + this.map(function(pair) {
586
+ return pair.map(Object.inspect).join(': ');
587
+ }).join(', ') + '}>';
588
+ }
589
+ }
590
+
591
+ function $H(object) {
592
+ var hash = Object.extend({}, object || {});
593
+ Object.extend(hash, Enumerable);
594
+ Object.extend(hash, Hash);
595
+ return hash;
596
+ }
597
+ ObjectRange = Class.create();
598
+ Object.extend(ObjectRange.prototype, Enumerable);
599
+ Object.extend(ObjectRange.prototype, {
600
+ initialize: function(start, end, exclusive) {
601
+ this.start = start;
602
+ this.end = end;
603
+ this.exclusive = exclusive;
604
+ },
605
+
606
+ _each: function(iterator) {
607
+ var value = this.start;
608
+ while (this.include(value)) {
609
+ iterator(value);
610
+ value = value.succ();
611
+ }
612
+ },
613
+
614
+ include: function(value) {
615
+ if (value < this.start)
616
+ return false;
617
+ if (this.exclusive)
618
+ return value < this.end;
619
+ return value <= this.end;
620
+ }
621
+ });
622
+
623
+ var $R = function(start, end, exclusive) {
624
+ return new ObjectRange(start, end, exclusive);
625
+ }
626
+
627
+ var Ajax = {
628
+ getTransport: function() {
629
+ return Try.these(
630
+ function() {return new XMLHttpRequest()},
631
+ function() {return new ActiveXObject('Msxml2.XMLHTTP')},
632
+ function() {return new ActiveXObject('Microsoft.XMLHTTP')}
633
+ ) || false;
634
+ },
635
+
636
+ activeRequestCount: 0
637
+ }
638
+
639
+ Ajax.Responders = {
640
+ responders: [],
641
+
642
+ _each: function(iterator) {
643
+ this.responders._each(iterator);
644
+ },
645
+
646
+ register: function(responderToAdd) {
647
+ if (!this.include(responderToAdd))
648
+ this.responders.push(responderToAdd);
649
+ },
650
+
651
+ unregister: function(responderToRemove) {
652
+ this.responders = this.responders.without(responderToRemove);
653
+ },
654
+
655
+ dispatch: function(callback, request, transport, json) {
656
+ this.each(function(responder) {
657
+ if (responder[callback] && typeof responder[callback] == 'function') {
658
+ try {
659
+ responder[callback].apply(responder, [request, transport, json]);
660
+ } catch (e) {}
661
+ }
662
+ });
663
+ }
664
+ };
665
+
666
+ Object.extend(Ajax.Responders, Enumerable);
667
+
668
+ Ajax.Responders.register({
669
+ onCreate: function() {
670
+ Ajax.activeRequestCount++;
671
+ },
672
+
673
+ onComplete: function() {
674
+ Ajax.activeRequestCount--;
675
+ }
676
+ });
677
+
678
+ Ajax.Base = function() {};
679
+ Ajax.Base.prototype = {
680
+ setOptions: function(options) {
681
+ this.options = {
682
+ method: 'post',
683
+ asynchronous: true,
684
+ contentType: 'application/x-www-form-urlencoded',
685
+ parameters: ''
686
+ }
687
+ Object.extend(this.options, options || {});
688
+ },
689
+
690
+ responseIsSuccess: function() {
691
+ return this.transport.status == undefined
692
+ || this.transport.status == 0
693
+ || (this.transport.status >= 200 && this.transport.status < 300);
694
+ },
695
+
696
+ responseIsFailure: function() {
697
+ return !this.responseIsSuccess();
698
+ }
699
+ }
700
+
701
+ Ajax.Request = Class.create();
702
+ Ajax.Request.Events =
703
+ ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
704
+
705
+ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
706
+ initialize: function(url, options) {
707
+ this.transport = Ajax.getTransport();
708
+ this.setOptions(options);
709
+ this.request(url);
710
+ },
711
+
712
+ request: function(url) {
713
+ var parameters = this.options.parameters || '';
714
+ if (parameters.length > 0) parameters += '&_=';
715
+
716
+ /* Simulate other verbs over post */
717
+ if (this.options.method != 'get' && this.options.method != 'post') {
718
+ parameters += (parameters.length > 0 ? '&' : '') + '_method=' + this.options.method;
719
+ this.options.method = 'post';
720
+ }
721
+
722
+ try {
723
+ this.url = url;
724
+ if (this.options.method == 'get' && parameters.length > 0)
725
+ this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
726
+
727
+ Ajax.Responders.dispatch('onCreate', this, this.transport);
728
+
729
+ this.transport.open(this.options.method, this.url,
730
+ this.options.asynchronous);
731
+
732
+ if (this.options.asynchronous)
733
+ setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
734
+
735
+ this.transport.onreadystatechange = this.onStateChange.bind(this);
736
+ this.setRequestHeaders();
737
+
738
+ var body = this.options.postBody ? this.options.postBody : parameters;
739
+ this.transport.send(this.options.method == 'post' ? body : null);
740
+
741
+ /* Force Firefox to handle ready state 4 for synchronous requests */
742
+ if (!this.options.asynchronous && this.transport.overrideMimeType)
743
+ this.onStateChange();
744
+
745
+ } catch (e) {
746
+ this.dispatchException(e);
747
+ }
748
+ },
749
+
750
+ setRequestHeaders: function() {
751
+ var requestHeaders =
752
+ ['X-Requested-With', 'XMLHttpRequest',
753
+ 'X-Prototype-Version', Prototype.Version,
754
+ 'Accept', 'text/javascript, text/html, application/xml, text/xml, */*'];
755
+
756
+ if (this.options.method == 'post') {
757
+ requestHeaders.push('Content-type', this.options.contentType);
758
+
759
+ /* Force "Connection: close" for Mozilla browsers to work around
760
+ * a bug where XMLHttpReqeuest sends an incorrect Content-length
761
+ * header. See Mozilla Bugzilla #246651.
762
+ */
763
+ if (this.transport.overrideMimeType)
764
+ requestHeaders.push('Connection', 'close');
765
+ }
766
+
767
+ if (this.options.requestHeaders)
768
+ requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
769
+
770
+ for (var i = 0; i < requestHeaders.length; i += 2)
771
+ this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
772
+ },
773
+
774
+ onStateChange: function() {
775
+ var readyState = this.transport.readyState;
776
+ if (readyState != 1)
777
+ this.respondToReadyState(this.transport.readyState);
778
+ },
779
+
780
+ header: function(name) {
781
+ try {
782
+ return this.transport.getResponseHeader(name);
783
+ } catch (e) {}
784
+ },
785
+
786
+ evalJSON: function() {
787
+ try {
788
+ return eval('(' + this.header('X-JSON') + ')');
789
+ } catch (e) {}
790
+ },
791
+
792
+ evalResponse: function() {
793
+ try {
794
+ return eval(this.transport.responseText);
795
+ } catch (e) {
796
+ this.dispatchException(e);
797
+ }
798
+ },
799
+
800
+ respondToReadyState: function(readyState) {
801
+ var event = Ajax.Request.Events[readyState];
802
+ var transport = this.transport, json = this.evalJSON();
803
+
804
+ if (event == 'Complete') {
805
+ try {
806
+ (this.options['on' + this.transport.status]
807
+ || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
808
+ || Prototype.emptyFunction)(transport, json);
809
+ } catch (e) {
810
+ this.dispatchException(e);
811
+ }
812
+
813
+ if ((this.header('Content-type') || '').match(/^text\/javascript/i))
814
+ this.evalResponse();
815
+ }
816
+
817
+ try {
818
+ (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
819
+ Ajax.Responders.dispatch('on' + event, this, transport, json);
820
+ } catch (e) {
821
+ this.dispatchException(e);
822
+ }
823
+
824
+ /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
825
+ if (event == 'Complete')
826
+ this.transport.onreadystatechange = Prototype.emptyFunction;
827
+ },
828
+
829
+ dispatchException: function(exception) {
830
+ (this.options.onException || Prototype.emptyFunction)(this, exception);
831
+ Ajax.Responders.dispatch('onException', this, exception);
832
+ }
833
+ });
834
+
835
+ Ajax.Updater = Class.create();
836
+
837
+ Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
838
+ initialize: function(container, url, options) {
839
+ this.containers = {
840
+ success: container.success ? $(container.success) : $(container),
841
+ failure: container.failure ? $(container.failure) :
842
+ (container.success ? null : $(container))
843
+ }
844
+
845
+ this.transport = Ajax.getTransport();
846
+ this.setOptions(options);
847
+
848
+ var onComplete = this.options.onComplete || Prototype.emptyFunction;
849
+ this.options.onComplete = (function(transport, object) {
850
+ this.updateContent();
851
+ onComplete(transport, object);
852
+ }).bind(this);
853
+
854
+ this.request(url);
855
+ },
856
+
857
+ updateContent: function() {
858
+ var receiver = this.responseIsSuccess() ?
859
+ this.containers.success : this.containers.failure;
860
+ var response = this.transport.responseText;
861
+
862
+ if (!this.options.evalScripts)
863
+ response = response.stripScripts();
864
+
865
+ if (receiver) {
866
+ if (this.options.insertion) {
867
+ new this.options.insertion(receiver, response);
868
+ } else {
869
+ Element.update(receiver, response);
870
+ }
871
+ }
872
+
873
+ if (this.responseIsSuccess()) {
874
+ if (this.onComplete)
875
+ setTimeout(this.onComplete.bind(this), 10);
876
+ }
877
+ }
878
+ });
879
+
880
+ Ajax.PeriodicalUpdater = Class.create();
881
+ Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
882
+ initialize: function(container, url, options) {
883
+ this.setOptions(options);
884
+ this.onComplete = this.options.onComplete;
885
+
886
+ this.frequency = (this.options.frequency || 2);
887
+ this.decay = (this.options.decay || 1);
888
+
889
+ this.updater = {};
890
+ this.container = container;
891
+ this.url = url;
892
+
893
+ this.start();
894
+ },
895
+
896
+ start: function() {
897
+ this.options.onComplete = this.updateComplete.bind(this);
898
+ this.onTimerEvent();
899
+ },
900
+
901
+ stop: function() {
902
+ this.updater.options.onComplete = undefined;
903
+ clearTimeout(this.timer);
904
+ (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
905
+ },
906
+
907
+ updateComplete: function(request) {
908
+ if (this.options.decay) {
909
+ this.decay = (request.responseText == this.lastText ?
910
+ this.decay * this.options.decay : 1);
911
+
912
+ this.lastText = request.responseText;
913
+ }
914
+ this.timer = setTimeout(this.onTimerEvent.bind(this),
915
+ this.decay * this.frequency * 1000);
916
+ },
917
+
918
+ onTimerEvent: function() {
919
+ this.updater = new Ajax.Updater(this.container, this.url, this.options);
920
+ }
921
+ });
922
+ function $() {
923
+ var results = [], element;
924
+ for (var i = 0; i < arguments.length; i++) {
925
+ element = arguments[i];
926
+ if (typeof element == 'string')
927
+ element = document.getElementById(element);
928
+ results.push(Element.extend(element));
929
+ }
930
+ return results.reduce();
931
+ }
932
+
933
+ if (Prototype.BrowserFeatures.XPath) {
934
+ document._getElementsByXPath = function(expression, parentElement) {
935
+ var results = [];
936
+ var query = document.evaluate(expression, $(parentElement) || document,
937
+ null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
938
+ for (var i = 0, len = query.snapshotLength; i < len; i++)
939
+ results.push(query.snapshotItem(i));
940
+ return results;
941
+ }
942
+ }
943
+
944
+ document.getElementsByClassName = function(className, parentElement) {
945
+ if (Prototype.BrowserFeatures.XPath) {
946
+ var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
947
+ return document._getElementsByXPath(q, parentElement);
948
+ } else {
949
+ var children = ($(parentElement) || document.body).getElementsByTagName('*');
950
+ var elements = [], child;
951
+ for (var i = 0, len = children.length; i < len; i++) {
952
+ child = children[i];
953
+ if (child.className.length == 0) continue;
954
+ if (child.className == className ||
955
+ child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
956
+ elements.push(Element.extend(child));
957
+ }
958
+ return elements;
959
+ }
960
+ }
961
+
962
+ /*--------------------------------------------------------------------------*/
963
+
964
+ if (!window.Element)
965
+ var Element = new Object();
966
+
967
+ Element.extend = function(element) {
968
+ if (!element) return;
969
+ if (_nativeExtensions || element.nodeType == 3) return element;
970
+
971
+ if (!element._extended && element.tagName && element != window) {
972
+ var methods = Object.clone(Element.Methods), cache = Element.extend.cache;
973
+
974
+ if (element.tagName == 'FORM')
975
+ Object.extend(methods, Form.Methods);
976
+ if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
977
+ Object.extend(methods, Form.Element.Methods);
978
+
979
+ for (var property in methods) {
980
+ var value = methods[property];
981
+ if (typeof value == 'function')
982
+ element[property] = cache.findOrStore(value);
983
+ }
984
+ }
985
+
986
+ element._extended = true;
987
+ return element;
988
+ }
989
+
990
+ Element.extend.cache = {
991
+ findOrStore: function(value) {
992
+ return this[value] = this[value] || function() {
993
+ return value.apply(null, [this].concat($A(arguments)));
994
+ }
995
+ }
996
+ }
997
+
998
+ Element.Methods = {
999
+ visible: function(element) {
1000
+ return $(element).style.display != 'none';
1001
+ },
1002
+
1003
+ toggle: function(element) {
1004
+ element = $(element);
1005
+ Element[Element.visible(element) ? 'hide' : 'show'](element);
1006
+ return element;
1007
+ },
1008
+
1009
+ hide: function(element) {
1010
+ $(element).style.display = 'none';
1011
+ return element;
1012
+ },
1013
+
1014
+ show: function(element) {
1015
+ $(element).style.display = '';
1016
+ return element;
1017
+ },
1018
+
1019
+ remove: function(element) {
1020
+ element = $(element);
1021
+ element.parentNode.removeChild(element);
1022
+ return element;
1023
+ },
1024
+
1025
+ update: function(element, html) {
1026
+ $(element).innerHTML = html.stripScripts();
1027
+ setTimeout(function() {html.evalScripts()}, 10);
1028
+ return element;
1029
+ },
1030
+
1031
+ replace: function(element, html) {
1032
+ element = $(element);
1033
+ if (element.outerHTML) {
1034
+ element.outerHTML = html.stripScripts();
1035
+ } else {
1036
+ var range = element.ownerDocument.createRange();
1037
+ range.selectNodeContents(element);
1038
+ element.parentNode.replaceChild(
1039
+ range.createContextualFragment(html.stripScripts()), element);
1040
+ }
1041
+ setTimeout(function() {html.evalScripts()}, 10);
1042
+ return element;
1043
+ },
1044
+
1045
+ inspect: function(element) {
1046
+ element = $(element);
1047
+ var result = '<' + element.tagName.toLowerCase();
1048
+ $H({'id': 'id', 'className': 'class'}).each(function(pair) {
1049
+ var property = pair.first(), attribute = pair.last();
1050
+ var value = (element[property] || '').toString();
1051
+ if (value) result += ' ' + attribute + '=' + value.inspect(true);
1052
+ });
1053
+ return result + '>';
1054
+ },
1055
+
1056
+ recursivelyCollect: function(element, property) {
1057
+ element = $(element);
1058
+ var elements = [];
1059
+ while (element = element[property])
1060
+ if (element.nodeType == 1)
1061
+ elements.push(Element.extend(element));
1062
+ return elements;
1063
+ },
1064
+
1065
+ ancestors: function(element) {
1066
+ return $(element).recursivelyCollect('parentNode');
1067
+ },
1068
+
1069
+ descendants: function(element) {
1070
+ element = $(element);
1071
+ return $A(element.getElementsByTagName('*'));
1072
+ },
1073
+
1074
+ previousSiblings: function(element) {
1075
+ return $(element).recursivelyCollect('previousSibling');
1076
+ },
1077
+
1078
+ nextSiblings: function(element) {
1079
+ return $(element).recursivelyCollect('nextSibling');
1080
+ },
1081
+
1082
+ siblings: function(element) {
1083
+ element = $(element);
1084
+ return element.previousSiblings().reverse().concat(element.nextSiblings());
1085
+ },
1086
+
1087
+ match: function(element, selector) {
1088
+ element = $(element);
1089
+ if (typeof selector == 'string')
1090
+ selector = new Selector(selector);
1091
+ return selector.match(element);
1092
+ },
1093
+
1094
+ up: function(element, expression, index) {
1095
+ return Selector.findElement($(element).ancestors(), expression, index);
1096
+ },
1097
+
1098
+ down: function(element, expression, index) {
1099
+ return Selector.findElement($(element).descendants(), expression, index);
1100
+ },
1101
+
1102
+ previous: function(element, expression, index) {
1103
+ return Selector.findElement($(element).previousSiblings(), expression, index);
1104
+ },
1105
+
1106
+ next: function(element, expression, index) {
1107
+ return Selector.findElement($(element).nextSiblings(), expression, index);
1108
+ },
1109
+
1110
+ getElementsBySelector: function() {
1111
+ var args = $A(arguments), element = $(args.shift());
1112
+ return Selector.findChildElements(element, args);
1113
+ },
1114
+
1115
+ getElementsByClassName: function(element, className) {
1116
+ element = $(element);
1117
+ return document.getElementsByClassName(className, element);
1118
+ },
1119
+
1120
+ getHeight: function(element) {
1121
+ element = $(element);
1122
+ return element.offsetHeight;
1123
+ },
1124
+
1125
+ classNames: function(element) {
1126
+ return new Element.ClassNames(element);
1127
+ },
1128
+
1129
+ hasClassName: function(element, className) {
1130
+ if (!(element = $(element))) return;
1131
+ return Element.classNames(element).include(className);
1132
+ },
1133
+
1134
+ addClassName: function(element, className) {
1135
+ if (!(element = $(element))) return;
1136
+ Element.classNames(element).add(className);
1137
+ return element;
1138
+ },
1139
+
1140
+ removeClassName: function(element, className) {
1141
+ if (!(element = $(element))) return;
1142
+ Element.classNames(element).remove(className);
1143
+ return element;
1144
+ },
1145
+
1146
+ observe: function() {
1147
+ Event.observe.apply(Event, arguments);
1148
+ return $A(arguments).first();
1149
+ },
1150
+
1151
+ stopObserving: function() {
1152
+ Event.stopObserving.apply(Event, arguments);
1153
+ return $A(arguments).first();
1154
+ },
1155
+
1156
+ // removes whitespace-only text node children
1157
+ cleanWhitespace: function(element) {
1158
+ element = $(element);
1159
+ var node = element.firstChild;
1160
+ while (node) {
1161
+ var nextNode = node.nextSibling;
1162
+ if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
1163
+ element.removeChild(node);
1164
+ node = nextNode;
1165
+ }
1166
+ return element;
1167
+ },
1168
+
1169
+ empty: function(element) {
1170
+ return $(element).innerHTML.match(/^\s*$/);
1171
+ },
1172
+
1173
+ childOf: function(element, ancestor) {
1174
+ element = $(element), ancestor = $(ancestor);
1175
+ while (element = element.parentNode)
1176
+ if (element == ancestor) return true;
1177
+ return false;
1178
+ },
1179
+
1180
+ scrollTo: function(element) {
1181
+ element = $(element);
1182
+ var x = element.x ? element.x : element.offsetLeft,
1183
+ y = element.y ? element.y : element.offsetTop;
1184
+ window.scrollTo(x, y);
1185
+ return element;
1186
+ },
1187
+
1188
+ getStyle: function(element, style) {
1189
+ element = $(element);
1190
+ var value = element.style[style.camelize()];
1191
+ if (!value) {
1192
+ if (document.defaultView && document.defaultView.getComputedStyle) {
1193
+ var css = document.defaultView.getComputedStyle(element, null);
1194
+ value = css ? css.getPropertyValue(style) : null;
1195
+ } else if (element.currentStyle) {
1196
+ value = element.currentStyle[style.camelize()];
1197
+ }
1198
+ }
1199
+
1200
+ if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
1201
+ if (Element.getStyle(element, 'position') == 'static') value = 'auto';
1202
+
1203
+ return value == 'auto' ? null : value;
1204
+ },
1205
+
1206
+ setStyle: function(element, style) {
1207
+ element = $(element);
1208
+ for (var name in style)
1209
+ element.style[name.camelize()] = style[name];
1210
+ return element;
1211
+ },
1212
+
1213
+ getDimensions: function(element) {
1214
+ element = $(element);
1215
+ if (Element.getStyle(element, 'display') != 'none')
1216
+ return {width: element.offsetWidth, height: element.offsetHeight};
1217
+
1218
+ // All *Width and *Height properties give 0 on elements with display none,
1219
+ // so enable the element temporarily
1220
+ var els = element.style;
1221
+ var originalVisibility = els.visibility;
1222
+ var originalPosition = els.position;
1223
+ els.visibility = 'hidden';
1224
+ els.position = 'absolute';
1225
+ els.display = '';
1226
+ var originalWidth = element.clientWidth;
1227
+ var originalHeight = element.clientHeight;
1228
+ els.display = 'none';
1229
+ els.position = originalPosition;
1230
+ els.visibility = originalVisibility;
1231
+ return {width: originalWidth, height: originalHeight};
1232
+ },
1233
+
1234
+ makePositioned: function(element) {
1235
+ element = $(element);
1236
+ var pos = Element.getStyle(element, 'position');
1237
+ if (pos == 'static' || !pos) {
1238
+ element._madePositioned = true;
1239
+ element.style.position = 'relative';
1240
+ // Opera returns the offset relative to the positioning context, when an
1241
+ // element is position relative but top and left have not been defined
1242
+ if (window.opera) {
1243
+ element.style.top = 0;
1244
+ element.style.left = 0;
1245
+ }
1246
+ }
1247
+ return element;
1248
+ },
1249
+
1250
+ undoPositioned: function(element) {
1251
+ element = $(element);
1252
+ if (element._madePositioned) {
1253
+ element._madePositioned = undefined;
1254
+ element.style.position =
1255
+ element.style.top =
1256
+ element.style.left =
1257
+ element.style.bottom =
1258
+ element.style.right = '';
1259
+ }
1260
+ return element;
1261
+ },
1262
+
1263
+ makeClipping: function(element) {
1264
+ element = $(element);
1265
+ if (element._overflow) return;
1266
+ element._overflow = element.style.overflow || 'auto';
1267
+ if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
1268
+ element.style.overflow = 'hidden';
1269
+ return element;
1270
+ },
1271
+
1272
+ undoClipping: function(element) {
1273
+ element = $(element);
1274
+ if (!element._overflow) return;
1275
+ element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
1276
+ element._overflow = null;
1277
+ return element;
1278
+ }
1279
+ }
1280
+
1281
+ // IE is missing .innerHTML support for TABLE-related elements
1282
+ if(document.all){
1283
+ Element.Methods.update = function(element, html) {
1284
+ element = $(element);
1285
+ var tagName = element.tagName.toUpperCase();
1286
+ if (['THEAD','TBODY','TR','TD'].indexOf(tagName) > -1) {
1287
+ var div = document.createElement('div');
1288
+ switch (tagName) {
1289
+ case 'THEAD':
1290
+ case 'TBODY':
1291
+ div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>';
1292
+ depth = 2;
1293
+ break;
1294
+ case 'TR':
1295
+ div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>';
1296
+ depth = 3;
1297
+ break;
1298
+ case 'TD':
1299
+ div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>';
1300
+ depth = 4;
1301
+ }
1302
+ $A(element.childNodes).each(function(node){
1303
+ element.removeChild(node)
1304
+ });
1305
+ depth.times(function(){ div = div.firstChild });
1306
+
1307
+ $A(div.childNodes).each(
1308
+ function(node){ element.appendChild(node) });
1309
+ } else {
1310
+ element.innerHTML = html.stripScripts();
1311
+ }
1312
+ setTimeout(function() {html.evalScripts()}, 10);
1313
+ return element;
1314
+ }
1315
+ }
1316
+
1317
+ Object.extend(Element, Element.Methods);
1318
+
1319
+ var _nativeExtensions = false;
1320
+
1321
+ if (!window.HTMLElement && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
1322
+ /* Emulate HTMLElement, HTMLFormElement, HTMLInputElement, HTMLTextAreaElement,
1323
+ and HTMLSelectElement in Safari */
1324
+ ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) {
1325
+ var klass = window['HTML' + tag + 'Element'] = {};
1326
+ klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__;
1327
+ });
1328
+ }
1329
+
1330
+ Element.addMethods = function(methods) {
1331
+ Object.extend(Element.Methods, methods || {});
1332
+
1333
+ function copy(methods, destination) {
1334
+ var cache = Element.extend.cache;
1335
+ for (var property in methods) {
1336
+ var value = methods[property];
1337
+ destination[property] = cache.findOrStore(value);
1338
+ }
1339
+ }
1340
+
1341
+ if (typeof HTMLElement != 'undefined') {
1342
+ copy(Element.Methods, HTMLElement.prototype);
1343
+ copy(Form.Methods, HTMLFormElement.prototype);
1344
+ [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
1345
+ copy(Form.Element.Methods, klass.prototype);
1346
+ });
1347
+ _nativeExtensions = true;
1348
+ }
1349
+ }
1350
+
1351
+ var Toggle = new Object();
1352
+ Toggle.display = Element.toggle;
1353
+
1354
+ /*--------------------------------------------------------------------------*/
1355
+
1356
+ Abstract.Insertion = function(adjacency) {
1357
+ this.adjacency = adjacency;
1358
+ }
1359
+
1360
+ Abstract.Insertion.prototype = {
1361
+ initialize: function(element, content) {
1362
+ this.element = $(element);
1363
+ this.content = content.stripScripts();
1364
+
1365
+ if (this.adjacency && this.element.insertAdjacentHTML) {
1366
+ try {
1367
+ this.element.insertAdjacentHTML(this.adjacency, this.content);
1368
+ } catch (e) {
1369
+ var tagName = this.element.tagName.toLowerCase();
1370
+ if (tagName == 'tbody' || tagName == 'tr') {
1371
+ this.insertContent(this.contentFromAnonymousTable());
1372
+ } else {
1373
+ throw e;
1374
+ }
1375
+ }
1376
+ } else {
1377
+ this.range = this.element.ownerDocument.createRange();
1378
+ if (this.initializeRange) this.initializeRange();
1379
+ this.insertContent([this.range.createContextualFragment(this.content)]);
1380
+ }
1381
+
1382
+ setTimeout(function() {content.evalScripts()}, 10);
1383
+ },
1384
+
1385
+ contentFromAnonymousTable: function() {
1386
+ var div = document.createElement('div');
1387
+ div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
1388
+ return $A(div.childNodes[0].childNodes[0].childNodes);
1389
+ }
1390
+ }
1391
+
1392
+ var Insertion = new Object();
1393
+
1394
+ Insertion.Before = Class.create();
1395
+ Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
1396
+ initializeRange: function() {
1397
+ this.range.setStartBefore(this.element);
1398
+ },
1399
+
1400
+ insertContent: function(fragments) {
1401
+ fragments.each((function(fragment) {
1402
+ this.element.parentNode.insertBefore(fragment, this.element);
1403
+ }).bind(this));
1404
+ }
1405
+ });
1406
+
1407
+ Insertion.Top = Class.create();
1408
+ Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
1409
+ initializeRange: function() {
1410
+ this.range.selectNodeContents(this.element);
1411
+ this.range.collapse(true);
1412
+ },
1413
+
1414
+ insertContent: function(fragments) {
1415
+ fragments.reverse(false).each((function(fragment) {
1416
+ this.element.insertBefore(fragment, this.element.firstChild);
1417
+ }).bind(this));
1418
+ }
1419
+ });
1420
+
1421
+ Insertion.Bottom = Class.create();
1422
+ Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
1423
+ initializeRange: function() {
1424
+ this.range.selectNodeContents(this.element);
1425
+ this.range.collapse(this.element);
1426
+ },
1427
+
1428
+ insertContent: function(fragments) {
1429
+ fragments.each((function(fragment) {
1430
+ this.element.appendChild(fragment);
1431
+ }).bind(this));
1432
+ }
1433
+ });
1434
+
1435
+ Insertion.After = Class.create();
1436
+ Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
1437
+ initializeRange: function() {
1438
+ this.range.setStartAfter(this.element);
1439
+ },
1440
+
1441
+ insertContent: function(fragments) {
1442
+ fragments.each((function(fragment) {
1443
+ this.element.parentNode.insertBefore(fragment,
1444
+ this.element.nextSibling);
1445
+ }).bind(this));
1446
+ }
1447
+ });
1448
+
1449
+ /*--------------------------------------------------------------------------*/
1450
+
1451
+ Element.ClassNames = Class.create();
1452
+ Element.ClassNames.prototype = {
1453
+ initialize: function(element) {
1454
+ this.element = $(element);
1455
+ },
1456
+
1457
+ _each: function(iterator) {
1458
+ this.element.className.split(/\s+/).select(function(name) {
1459
+ return name.length > 0;
1460
+ })._each(iterator);
1461
+ },
1462
+
1463
+ set: function(className) {
1464
+ this.element.className = className;
1465
+ },
1466
+
1467
+ add: function(classNameToAdd) {
1468
+ if (this.include(classNameToAdd)) return;
1469
+ this.set(this.toArray().concat(classNameToAdd).join(' '));
1470
+ },
1471
+
1472
+ remove: function(classNameToRemove) {
1473
+ if (!this.include(classNameToRemove)) return;
1474
+ this.set(this.select(function(className) {
1475
+ return className != classNameToRemove;
1476
+ }).join(' '));
1477
+ },
1478
+
1479
+ toString: function() {
1480
+ return this.toArray().join(' ');
1481
+ }
1482
+ }
1483
+
1484
+ Object.extend(Element.ClassNames.prototype, Enumerable);
1485
+ var Selector = Class.create();
1486
+ Selector.prototype = {
1487
+ initialize: function(expression) {
1488
+ this.params = {classNames: []};
1489
+ this.expression = expression.toString().strip();
1490
+ this.parseExpression();
1491
+ this.compileMatcher();
1492
+ },
1493
+
1494
+ parseExpression: function() {
1495
+ function abort(message) { throw 'Parse error in selector: ' + message; }
1496
+
1497
+ if (this.expression == '') abort('empty expression');
1498
+
1499
+ var params = this.params, expr = this.expression, match, modifier, clause, rest;
1500
+ while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
1501
+ params.attributes = params.attributes || [];
1502
+ params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
1503
+ expr = match[1];
1504
+ }
1505
+
1506
+ if (expr == '*') return this.params.wildcard = true;
1507
+
1508
+ while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
1509
+ modifier = match[1], clause = match[2], rest = match[3];
1510
+ switch (modifier) {
1511
+ case '#': params.id = clause; break;
1512
+ case '.': params.classNames.push(clause); break;
1513
+ case '':
1514
+ case undefined: params.tagName = clause.toUpperCase(); break;
1515
+ default: abort(expr.inspect());
1516
+ }
1517
+ expr = rest;
1518
+ }
1519
+
1520
+ if (expr.length > 0) abort(expr.inspect());
1521
+ },
1522
+
1523
+ buildMatchExpression: function() {
1524
+ var params = this.params, conditions = [], clause;
1525
+
1526
+ if (params.wildcard)
1527
+ conditions.push('true');
1528
+ if (clause = params.id)
1529
+ conditions.push('element.id == ' + clause.inspect());
1530
+ if (clause = params.tagName)
1531
+ conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
1532
+ if ((clause = params.classNames).length > 0)
1533
+ for (var i = 0; i < clause.length; i++)
1534
+ conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')');
1535
+ if (clause = params.attributes) {
1536
+ clause.each(function(attribute) {
1537
+ var value = 'element.getAttribute(' + attribute.name.inspect() + ')';
1538
+ var splitValueBy = function(delimiter) {
1539
+ return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
1540
+ }
1541
+
1542
+ switch (attribute.operator) {
1543
+ case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break;
1544
+ case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
1545
+ case '|=': conditions.push(
1546
+ splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
1547
+ ); break;
1548
+ case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break;
1549
+ case '':
1550
+ case undefined: conditions.push(value + ' != null'); break;
1551
+ default: throw 'Unknown operator ' + attribute.operator + ' in selector';
1552
+ }
1553
+ });
1554
+ }
1555
+
1556
+ return conditions.join(' && ');
1557
+ },
1558
+
1559
+ compileMatcher: function() {
1560
+ this.match = new Function('element', 'if (!element.tagName) return false; \
1561
+ return ' + this.buildMatchExpression());
1562
+ },
1563
+
1564
+ findElements: function(scope) {
1565
+ var element;
1566
+
1567
+ if (element = $(this.params.id))
1568
+ if (this.match(element))
1569
+ if (!scope || Element.childOf(element, scope))
1570
+ return [element];
1571
+
1572
+ scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
1573
+
1574
+ var results = [];
1575
+ for (var i = 0; i < scope.length; i++)
1576
+ if (this.match(element = scope[i]))
1577
+ results.push(Element.extend(element));
1578
+
1579
+ return results;
1580
+ },
1581
+
1582
+ toString: function() {
1583
+ return this.expression;
1584
+ }
1585
+ }
1586
+
1587
+ Object.extend(Selector, {
1588
+ matchElements: function(elements, expression) {
1589
+ var selector = new Selector(expression);
1590
+ return elements.select(selector.match.bind(selector));
1591
+ },
1592
+
1593
+ findElement: function(elements, expression, index) {
1594
+ if (typeof expression == 'number') index = expression, expression = false;
1595
+ return Selector.matchElements(elements, expression || '*')[index || 0];
1596
+ },
1597
+
1598
+ findChildElements: function(element, expressions) {
1599
+ return expressions.map(function(expression) {
1600
+ return expression.strip().split(/\s+/).inject([null], function(results, expr) {
1601
+ var selector = new Selector(expr);
1602
+ return results.inject([], function(elements, result) {
1603
+ return elements.concat(selector.findElements(result || element));
1604
+ });
1605
+ });
1606
+ }).flatten();
1607
+ }
1608
+ });
1609
+
1610
+ function $$() {
1611
+ return Selector.findChildElements(document, $A(arguments));
1612
+ }
1613
+ var Form = {
1614
+ reset: function(form) {
1615
+ $(form).reset();
1616
+ return form;
1617
+ }
1618
+ };
1619
+
1620
+ Form.Methods = {
1621
+ serialize: function(form) {
1622
+ return this.serializeElements(Form.getElements($(form)));
1623
+ },
1624
+
1625
+ serializeElements: function(elements) {
1626
+ var queryComponents = new Array();
1627
+
1628
+ for (var i = 0; i < elements.length; i++) {
1629
+ var queryComponent = Form.Element.serialize(elements[i]);
1630
+ if (queryComponent)
1631
+ queryComponents.push(queryComponent);
1632
+ }
1633
+
1634
+ return queryComponents.join('&');
1635
+ },
1636
+
1637
+ getElements: function(form) {
1638
+ return $A($(form).getElementsByTagName('*')).inject([], function(elements, child) {
1639
+ if (Form.Element.Serializers[child.tagName.toLowerCase()])
1640
+ elements.push(Element.extend(child));
1641
+ return elements;
1642
+ });
1643
+ },
1644
+
1645
+ getInputs: function(form, typeName, name) {
1646
+ form = $(form);
1647
+ var inputs = form.getElementsByTagName('input');
1648
+
1649
+ if (!typeName && !name)
1650
+ return inputs;
1651
+
1652
+ var matchingInputs = new Array();
1653
+ for (var i = 0; i < inputs.length; i++) {
1654
+ var input = inputs[i];
1655
+ if ((typeName && input.type != typeName) ||
1656
+ (name && input.name != name))
1657
+ continue;
1658
+ matchingInputs.push(input);
1659
+ }
1660
+
1661
+ return matchingInputs;
1662
+ },
1663
+
1664
+ disable: function(form) {
1665
+ form = $(form);
1666
+ var elements = Form.getElements(form);
1667
+ for (var i = 0; i < elements.length; i++) {
1668
+ var element = elements[i];
1669
+ element.blur();
1670
+ element.disabled = 'true';
1671
+ }
1672
+ return form;
1673
+ },
1674
+
1675
+ enable: function(form) {
1676
+ form = $(form);
1677
+ var elements = Form.getElements(form);
1678
+ for (var i = 0; i < elements.length; i++) {
1679
+ var element = elements[i];
1680
+ element.disabled = '';
1681
+ }
1682
+ return form;
1683
+ },
1684
+
1685
+ findFirstElement: function(form) {
1686
+ return Form.getElements(form).find(function(element) {
1687
+ return element.type != 'hidden' && !element.disabled &&
1688
+ ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
1689
+ });
1690
+ },
1691
+
1692
+ focusFirstElement: function(form) {
1693
+ form = $(form);
1694
+ Field.activate(Form.findFirstElement(form));
1695
+ return form;
1696
+ }
1697
+ }
1698
+
1699
+ Object.extend(Form, Form.Methods);
1700
+
1701
+ /*--------------------------------------------------------------------------*/
1702
+
1703
+ Form.Element = {
1704
+ focus: function(element) {
1705
+ $(element).focus();
1706
+ return element;
1707
+ },
1708
+
1709
+ select: function(element) {
1710
+ $(element).select();
1711
+ return element;
1712
+ }
1713
+ }
1714
+
1715
+ Form.Element.Methods = {
1716
+ serialize: function(element) {
1717
+ element = $(element);
1718
+ var method = element.tagName.toLowerCase();
1719
+ var parameter = Form.Element.Serializers[method](element);
1720
+
1721
+ if (parameter) {
1722
+ var key = encodeURIComponent(parameter[0]);
1723
+ if (key.length == 0) return;
1724
+
1725
+ if (parameter[1].constructor != Array)
1726
+ parameter[1] = [parameter[1]];
1727
+
1728
+ return parameter[1].map(function(value) {
1729
+ return key + '=' + encodeURIComponent(value);
1730
+ }).join('&');
1731
+ }
1732
+ },
1733
+
1734
+ getValue: function(element) {
1735
+ element = $(element);
1736
+ var method = element.tagName.toLowerCase();
1737
+ var parameter = Form.Element.Serializers[method](element);
1738
+
1739
+ if (parameter)
1740
+ return parameter[1];
1741
+ },
1742
+
1743
+ clear: function(element) {
1744
+ $(element).value = '';
1745
+ return element;
1746
+ },
1747
+
1748
+ present: function(element) {
1749
+ return $(element).value != '';
1750
+ },
1751
+
1752
+ activate: function(element) {
1753
+ element = $(element);
1754
+ element.focus();
1755
+ if (element.select)
1756
+ element.select();
1757
+ return element;
1758
+ },
1759
+
1760
+ disable: function(element) {
1761
+ element = $(element);
1762
+ element.disabled = true;
1763
+ return element;
1764
+ },
1765
+
1766
+ enable: function(element) {
1767
+ element = $(element);
1768
+ element.blur();
1769
+ element.disabled = false;
1770
+ return element;
1771
+ }
1772
+ }
1773
+
1774
+ Object.extend(Form.Element, Form.Element.Methods);
1775
+ var Field = Form.Element;
1776
+
1777
+ /*--------------------------------------------------------------------------*/
1778
+
1779
+ Form.Element.Serializers = {
1780
+ input: function(element) {
1781
+ switch (element.type.toLowerCase()) {
1782
+ case 'checkbox':
1783
+ case 'radio':
1784
+ return Form.Element.Serializers.inputSelector(element);
1785
+ default:
1786
+ return Form.Element.Serializers.textarea(element);
1787
+ }
1788
+ return false;
1789
+ },
1790
+
1791
+ inputSelector: function(element) {
1792
+ if (element.checked)
1793
+ return [element.name, element.value];
1794
+ },
1795
+
1796
+ textarea: function(element) {
1797
+ return [element.name, element.value];
1798
+ },
1799
+
1800
+ select: function(element) {
1801
+ return Form.Element.Serializers[element.type == 'select-one' ?
1802
+ 'selectOne' : 'selectMany'](element);
1803
+ },
1804
+
1805
+ selectOne: function(element) {
1806
+ var value = '', opt, index = element.selectedIndex;
1807
+ if (index >= 0) {
1808
+ opt = element.options[index];
1809
+ value = opt.value || opt.text;
1810
+ }
1811
+ return [element.name, value];
1812
+ },
1813
+
1814
+ selectMany: function(element) {
1815
+ var value = [];
1816
+ for (var i = 0; i < element.length; i++) {
1817
+ var opt = element.options[i];
1818
+ if (opt.selected)
1819
+ value.push(opt.value || opt.text);
1820
+ }
1821
+ return [element.name, value];
1822
+ }
1823
+ }
1824
+
1825
+ /*--------------------------------------------------------------------------*/
1826
+
1827
+ var $F = Form.Element.getValue;
1828
+
1829
+ /*--------------------------------------------------------------------------*/
1830
+
1831
+ Abstract.TimedObserver = function() {}
1832
+ Abstract.TimedObserver.prototype = {
1833
+ initialize: function(element, frequency, callback) {
1834
+ this.frequency = frequency;
1835
+ this.element = $(element);
1836
+ this.callback = callback;
1837
+
1838
+ this.lastValue = this.getValue();
1839
+ this.registerCallback();
1840
+ },
1841
+
1842
+ registerCallback: function() {
1843
+ setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
1844
+ },
1845
+
1846
+ onTimerEvent: function() {
1847
+ var value = this.getValue();
1848
+ if (this.lastValue != value) {
1849
+ this.callback(this.element, value);
1850
+ this.lastValue = value;
1851
+ }
1852
+ }
1853
+ }
1854
+
1855
+ Form.Element.Observer = Class.create();
1856
+ Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
1857
+ getValue: function() {
1858
+ return Form.Element.getValue(this.element);
1859
+ }
1860
+ });
1861
+
1862
+ Form.Observer = Class.create();
1863
+ Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
1864
+ getValue: function() {
1865
+ return Form.serialize(this.element);
1866
+ }
1867
+ });
1868
+
1869
+ /*--------------------------------------------------------------------------*/
1870
+
1871
+ Abstract.EventObserver = function() {}
1872
+ Abstract.EventObserver.prototype = {
1873
+ initialize: function(element, callback) {
1874
+ this.element = $(element);
1875
+ this.callback = callback;
1876
+
1877
+ this.lastValue = this.getValue();
1878
+ if (this.element.tagName.toLowerCase() == 'form')
1879
+ this.registerFormCallbacks();
1880
+ else
1881
+ this.registerCallback(this.element);
1882
+ },
1883
+
1884
+ onElementEvent: function() {
1885
+ var value = this.getValue();
1886
+ if (this.lastValue != value) {
1887
+ this.callback(this.element, value);
1888
+ this.lastValue = value;
1889
+ }
1890
+ },
1891
+
1892
+ registerFormCallbacks: function() {
1893
+ var elements = Form.getElements(this.element);
1894
+ for (var i = 0; i < elements.length; i++)
1895
+ this.registerCallback(elements[i]);
1896
+ },
1897
+
1898
+ registerCallback: function(element) {
1899
+ if (element.type) {
1900
+ switch (element.type.toLowerCase()) {
1901
+ case 'checkbox':
1902
+ case 'radio':
1903
+ Event.observe(element, 'click', this.onElementEvent.bind(this));
1904
+ break;
1905
+ default:
1906
+ Event.observe(element, 'change', this.onElementEvent.bind(this));
1907
+ break;
1908
+ }
1909
+ }
1910
+ }
1911
+ }
1912
+
1913
+ Form.Element.EventObserver = Class.create();
1914
+ Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
1915
+ getValue: function() {
1916
+ return Form.Element.getValue(this.element);
1917
+ }
1918
+ });
1919
+
1920
+ Form.EventObserver = Class.create();
1921
+ Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
1922
+ getValue: function() {
1923
+ return Form.serialize(this.element);
1924
+ }
1925
+ });
1926
+ if (!window.Event) {
1927
+ var Event = new Object();
1928
+ }
1929
+
1930
+ Object.extend(Event, {
1931
+ KEY_BACKSPACE: 8,
1932
+ KEY_TAB: 9,
1933
+ KEY_RETURN: 13,
1934
+ KEY_ESC: 27,
1935
+ KEY_LEFT: 37,
1936
+ KEY_UP: 38,
1937
+ KEY_RIGHT: 39,
1938
+ KEY_DOWN: 40,
1939
+ KEY_DELETE: 46,
1940
+ KEY_HOME: 36,
1941
+ KEY_END: 35,
1942
+ KEY_PAGEUP: 33,
1943
+ KEY_PAGEDOWN: 34,
1944
+
1945
+ element: function(event) {
1946
+ return event.target || event.srcElement;
1947
+ },
1948
+
1949
+ isLeftClick: function(event) {
1950
+ return (((event.which) && (event.which == 1)) ||
1951
+ ((event.button) && (event.button == 1)));
1952
+ },
1953
+
1954
+ pointerX: function(event) {
1955
+ return event.pageX || (event.clientX +
1956
+ (document.documentElement.scrollLeft || document.body.scrollLeft));
1957
+ },
1958
+
1959
+ pointerY: function(event) {
1960
+ return event.pageY || (event.clientY +
1961
+ (document.documentElement.scrollTop || document.body.scrollTop));
1962
+ },
1963
+
1964
+ stop: function(event) {
1965
+ if (event.preventDefault) {
1966
+ event.preventDefault();
1967
+ event.stopPropagation();
1968
+ } else {
1969
+ event.returnValue = false;
1970
+ event.cancelBubble = true;
1971
+ }
1972
+ },
1973
+
1974
+ // find the first node with the given tagName, starting from the
1975
+ // node the event was triggered on; traverses the DOM upwards
1976
+ findElement: function(event, tagName) {
1977
+ var element = Event.element(event);
1978
+ while (element.parentNode && (!element.tagName ||
1979
+ (element.tagName.toUpperCase() != tagName.toUpperCase())))
1980
+ element = element.parentNode;
1981
+ return element;
1982
+ },
1983
+
1984
+ observers: false,
1985
+
1986
+ _observeAndCache: function(element, name, observer, useCapture) {
1987
+ if (!this.observers) this.observers = [];
1988
+ if (element.addEventListener) {
1989
+ this.observers.push([element, name, observer, useCapture]);
1990
+ element.addEventListener(name, observer, useCapture);
1991
+ } else if (element.attachEvent) {
1992
+ this.observers.push([element, name, observer, useCapture]);
1993
+ element.attachEvent('on' + name, observer);
1994
+ }
1995
+ },
1996
+
1997
+ unloadCache: function() {
1998
+ if (!Event.observers) return;
1999
+ for (var i = 0; i < Event.observers.length; i++) {
2000
+ Event.stopObserving.apply(this, Event.observers[i]);
2001
+ Event.observers[i][0] = null;
2002
+ }
2003
+ Event.observers = false;
2004
+ },
2005
+
2006
+ observe: function(element, name, observer, useCapture) {
2007
+ element = $(element);
2008
+ useCapture = useCapture || false;
2009
+
2010
+ if (name == 'keypress' &&
2011
+ (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
2012
+ || element.attachEvent))
2013
+ name = 'keydown';
2014
+
2015
+ Event._observeAndCache(element, name, observer, useCapture);
2016
+ },
2017
+
2018
+ stopObserving: function(element, name, observer, useCapture) {
2019
+ element = $(element);
2020
+ useCapture = useCapture || false;
2021
+
2022
+ if (name == 'keypress' &&
2023
+ (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
2024
+ || element.detachEvent))
2025
+ name = 'keydown';
2026
+
2027
+ if (element.removeEventListener) {
2028
+ element.removeEventListener(name, observer, useCapture);
2029
+ } else if (element.detachEvent) {
2030
+ try {
2031
+ element.detachEvent('on' + name, observer);
2032
+ } catch (e) {}
2033
+ }
2034
+ }
2035
+ });
2036
+
2037
+ /* prevent memory leaks in IE */
2038
+ if (navigator.appVersion.match(/\bMSIE\b/))
2039
+ Event.observe(window, 'unload', Event.unloadCache, false);
2040
+ var Position = {
2041
+ // set to true if needed, warning: firefox performance problems
2042
+ // NOT neeeded for page scrolling, only if draggable contained in
2043
+ // scrollable elements
2044
+ includeScrollOffsets: false,
2045
+
2046
+ // must be called before calling withinIncludingScrolloffset, every time the
2047
+ // page is scrolled
2048
+ prepare: function() {
2049
+ this.deltaX = window.pageXOffset
2050
+ || document.documentElement.scrollLeft
2051
+ || document.body.scrollLeft
2052
+ || 0;
2053
+ this.deltaY = window.pageYOffset
2054
+ || document.documentElement.scrollTop
2055
+ || document.body.scrollTop
2056
+ || 0;
2057
+ },
2058
+
2059
+ realOffset: function(element) {
2060
+ var valueT = 0, valueL = 0;
2061
+ do {
2062
+ valueT += element.scrollTop || 0;
2063
+ valueL += element.scrollLeft || 0;
2064
+ element = element.parentNode;
2065
+ } while (element);
2066
+ return [valueL, valueT];
2067
+ },
2068
+
2069
+ cumulativeOffset: function(element) {
2070
+ var valueT = 0, valueL = 0;
2071
+ do {
2072
+ valueT += element.offsetTop || 0;
2073
+ valueL += element.offsetLeft || 0;
2074
+ element = element.offsetParent;
2075
+ } while (element);
2076
+ return [valueL, valueT];
2077
+ },
2078
+
2079
+ positionedOffset: function(element) {
2080
+ var valueT = 0, valueL = 0;
2081
+ do {
2082
+ valueT += element.offsetTop || 0;
2083
+ valueL += element.offsetLeft || 0;
2084
+ element = element.offsetParent;
2085
+ if (element) {
2086
+ if(element.tagName=='BODY') break;
2087
+ var p = Element.getStyle(element, 'position');
2088
+ if (p == 'relative' || p == 'absolute') break;
2089
+ }
2090
+ } while (element);
2091
+ return [valueL, valueT];
2092
+ },
2093
+
2094
+ offsetParent: function(element) {
2095
+ if (element.offsetParent) return element.offsetParent;
2096
+ if (element == document.body) return element;
2097
+
2098
+ while ((element = element.parentNode) && element != document.body)
2099
+ if (Element.getStyle(element, 'position') != 'static')
2100
+ return element;
2101
+
2102
+ return document.body;
2103
+ },
2104
+
2105
+ // caches x/y coordinate pair to use with overlap
2106
+ within: function(element, x, y) {
2107
+ if (this.includeScrollOffsets)
2108
+ return this.withinIncludingScrolloffsets(element, x, y);
2109
+ this.xcomp = x;
2110
+ this.ycomp = y;
2111
+ this.offset = this.cumulativeOffset(element);
2112
+
2113
+ return (y >= this.offset[1] &&
2114
+ y < this.offset[1] + element.offsetHeight &&
2115
+ x >= this.offset[0] &&
2116
+ x < this.offset[0] + element.offsetWidth);
2117
+ },
2118
+
2119
+ withinIncludingScrolloffsets: function(element, x, y) {
2120
+ var offsetcache = this.realOffset(element);
2121
+
2122
+ this.xcomp = x + offsetcache[0] - this.deltaX;
2123
+ this.ycomp = y + offsetcache[1] - this.deltaY;
2124
+ this.offset = this.cumulativeOffset(element);
2125
+
2126
+ return (this.ycomp >= this.offset[1] &&
2127
+ this.ycomp < this.offset[1] + element.offsetHeight &&
2128
+ this.xcomp >= this.offset[0] &&
2129
+ this.xcomp < this.offset[0] + element.offsetWidth);
2130
+ },
2131
+
2132
+ // within must be called directly before
2133
+ overlap: function(mode, element) {
2134
+ if (!mode) return 0;
2135
+ if (mode == 'vertical')
2136
+ return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
2137
+ element.offsetHeight;
2138
+ if (mode == 'horizontal')
2139
+ return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
2140
+ element.offsetWidth;
2141
+ },
2142
+
2143
+ page: function(forElement) {
2144
+ var valueT = 0, valueL = 0;
2145
+
2146
+ var element = forElement;
2147
+ do {
2148
+ valueT += element.offsetTop || 0;
2149
+ valueL += element.offsetLeft || 0;
2150
+
2151
+ // Safari fix
2152
+ if (element.offsetParent==document.body)
2153
+ if (Element.getStyle(element,'position')=='absolute') break;
2154
+
2155
+ } while (element = element.offsetParent);
2156
+
2157
+ element = forElement;
2158
+ do {
2159
+ if (!window.opera || element.tagName=='BODY') {
2160
+ valueT -= element.scrollTop || 0;
2161
+ valueL -= element.scrollLeft || 0;
2162
+ }
2163
+ } while (element = element.parentNode);
2164
+
2165
+ return [valueL, valueT];
2166
+ },
2167
+
2168
+ clone: function(source, target) {
2169
+ var options = Object.extend({
2170
+ setLeft: true,
2171
+ setTop: true,
2172
+ setWidth: true,
2173
+ setHeight: true,
2174
+ offsetTop: 0,
2175
+ offsetLeft: 0
2176
+ }, arguments[2] || {})
2177
+
2178
+ // find page position of source
2179
+ source = $(source);
2180
+ var p = Position.page(source);
2181
+
2182
+ // find coordinate system to use
2183
+ target = $(target);
2184
+ var delta = [0, 0];
2185
+ var parent = null;
2186
+ // delta [0,0] will do fine with position: fixed elements,
2187
+ // position:absolute needs offsetParent deltas
2188
+ if (Element.getStyle(target,'position') == 'absolute') {
2189
+ parent = Position.offsetParent(target);
2190
+ delta = Position.page(parent);
2191
+ }
2192
+
2193
+ // correct by body offsets (fixes Safari)
2194
+ if (parent == document.body) {
2195
+ delta[0] -= document.body.offsetLeft;
2196
+ delta[1] -= document.body.offsetTop;
2197
+ }
2198
+
2199
+ // set position
2200
+ if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
2201
+ if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
2202
+ if(options.setWidth) target.style.width = source.offsetWidth + 'px';
2203
+ if(options.setHeight) target.style.height = source.offsetHeight + 'px';
2204
+ },
2205
+
2206
+ absolutize: function(element) {
2207
+ element = $(element);
2208
+ if (element.style.position == 'absolute') return;
2209
+ Position.prepare();
2210
+
2211
+ var offsets = Position.positionedOffset(element);
2212
+ var top = offsets[1];
2213
+ var left = offsets[0];
2214
+ var width = element.clientWidth;
2215
+ var height = element.clientHeight;
2216
+
2217
+ element._originalLeft = left - parseFloat(element.style.left || 0);
2218
+ element._originalTop = top - parseFloat(element.style.top || 0);
2219
+ element._originalWidth = element.style.width;
2220
+ element._originalHeight = element.style.height;
2221
+
2222
+ element.style.position = 'absolute';
2223
+ element.style.top = top + 'px';;
2224
+ element.style.left = left + 'px';;
2225
+ element.style.width = width + 'px';;
2226
+ element.style.height = height + 'px';;
2227
+ },
2228
+
2229
+ relativize: function(element) {
2230
+ element = $(element);
2231
+ if (element.style.position == 'relative') return;
2232
+ Position.prepare();
2233
+
2234
+ element.style.position = 'relative';
2235
+ var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
2236
+ var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
2237
+
2238
+ element.style.top = top + 'px';
2239
+ element.style.left = left + 'px';
2240
+ element.style.height = element._originalHeight;
2241
+ element.style.width = element._originalWidth;
2242
+ }
2243
+ }
2244
+
2245
+ // Safari returns margins on body which is incorrect if the child is absolutely
2246
+ // positioned. For performance reasons, redefine Position.cumulativeOffset for
2247
+ // KHTML/WebKit only.
2248
+ if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
2249
+ Position.cumulativeOffset = function(element) {
2250
+ var valueT = 0, valueL = 0;
2251
+ do {
2252
+ valueT += element.offsetTop || 0;
2253
+ valueL += element.offsetLeft || 0;
2254
+ if (element.offsetParent == document.body)
2255
+ if (Element.getStyle(element, 'position') == 'absolute') break;
2256
+
2257
+ element = element.offsetParent;
2258
+ } while (element);
2259
+
2260
+ return [valueL, valueT];
2261
+ }
2262
+ }
2263
+
2264
+ Element.addMethods();