bio 0.7.1 → 1.0.0

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