amrita2 2.0.1 → 2.0.2

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