parlement 0.1

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