merb 0.0.8 → 0.0.9

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