nitro 0.23.0 → 0.24.0

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 (76) hide show
  1. data/CHANGELOG +350 -0
  2. data/INSTALL +2 -2
  3. data/ProjectInfo +61 -0
  4. data/README +5 -4
  5. data/Rakefile +5 -4
  6. data/bin/nitrogen +3 -1
  7. data/doc/AUTHORS +27 -3
  8. data/doc/RELEASES +193 -0
  9. data/doc/lhttpd.txt +4 -0
  10. data/lib/nitro.rb +1 -1
  11. data/lib/nitro/adapter/cgi.rb +6 -321
  12. data/lib/nitro/adapter/fastcgi.rb +2 -14
  13. data/lib/nitro/adapter/scgi.rb +237 -71
  14. data/lib/nitro/adapter/webrick.rb +25 -7
  15. data/lib/nitro/caching.rb +1 -0
  16. data/lib/nitro/cgi.rb +296 -0
  17. data/lib/nitro/{cookie.rb → cgi/cookie.rb} +0 -0
  18. data/lib/nitro/cgi/http.rb +62 -0
  19. data/lib/nitro/{request.rb → cgi/request.rb} +4 -1
  20. data/lib/nitro/{response.rb → cgi/response.rb} +0 -0
  21. data/lib/nitro/cgi/stream.rb +43 -0
  22. data/lib/nitro/cgi/utils.rb +38 -0
  23. data/lib/nitro/compiler.rb +23 -11
  24. data/lib/nitro/compiler/css.rb +8 -0
  25. data/lib/nitro/compiler/morphing.rb +66 -0
  26. data/lib/nitro/context.rb +21 -30
  27. data/lib/nitro/controller.rb +23 -100
  28. data/lib/nitro/dispatcher.rb +18 -8
  29. data/lib/nitro/element.rb +6 -2
  30. data/lib/nitro/flash.rb +2 -2
  31. data/lib/nitro/mixin/buffer.rb +2 -2
  32. data/lib/nitro/mixin/form.rb +204 -93
  33. data/lib/nitro/mixin/javascript.rb +170 -11
  34. data/lib/nitro/mixin/markup.rb +1 -0
  35. data/lib/nitro/mixin/pager.rb +7 -4
  36. data/lib/nitro/mixin/rss.rb +2 -0
  37. data/lib/nitro/mixin/table.rb +23 -6
  38. data/lib/nitro/mixin/xhtml.rb +2 -2
  39. data/lib/nitro/render.rb +19 -5
  40. data/lib/nitro/scaffold.rb +12 -6
  41. data/lib/nitro/server.rb +4 -6
  42. data/lib/nitro/server/runner.rb +2 -2
  43. data/lib/nitro/session.rb +8 -1
  44. data/lib/nitro/session/file.rb +40 -0
  45. data/lib/part/admin.rb +2 -0
  46. data/lib/part/admin/controller.rb +7 -3
  47. data/lib/part/admin/skin.rb +8 -1
  48. data/lib/part/admin/template/index.xhtml +39 -1
  49. data/proto/public/error.xhtml +5 -3
  50. data/proto/public/js/behaviour.js +254 -254
  51. data/proto/public/js/controls.js +427 -165
  52. data/proto/public/js/dragdrop.js +255 -276
  53. data/proto/public/js/effects.js +476 -277
  54. data/proto/public/js/prototype.js +561 -127
  55. data/proto/public/js/scaffold.js +74 -0
  56. data/proto/public/js/scriptaculous.js +44 -0
  57. data/proto/public/js/util.js +548 -0
  58. data/proto/public/scaffold/list.xhtml +4 -1
  59. data/proto/scgi.rb +333 -0
  60. data/script/scgi_ctl +221 -0
  61. data/script/scgi_service +120 -0
  62. data/test/nitro/adapter/raw_post1.bin +0 -0
  63. data/test/nitro/{tc_cookie.rb → cgi/tc_cookie.rb} +1 -1
  64. data/test/nitro/{tc_request.rb → cgi/tc_request.rb} +1 -1
  65. data/test/nitro/mixin/tc_xhtml.rb +1 -1
  66. data/test/nitro/{adapter/tc_cgi.rb → tc_cgi.rb} +12 -12
  67. data/test/nitro/tc_controller.rb +9 -5
  68. metadata +159 -169
  69. data/benchmark/bench.rb +0 -5
  70. data/benchmark/simple-webrick-n-200.txt +0 -44
  71. data/benchmark/static-webrick-n-200.txt +0 -43
  72. data/benchmark/tiny-lhttpd-n-200-c-5.txt +0 -43
  73. data/benchmark/tiny-webrick-n-200-c-5.txt +0 -44
  74. data/benchmark/tiny-webrick-n-200.txt +0 -44
  75. data/benchmark/tiny2-webrick-n-200.txt +0 -44
  76. data/examples/README +0 -7
@@ -1,4 +1,4 @@
1
- /* Prototype JavaScript framework, version 1.3.1
1
+ /* Prototype JavaScript framework, version 1.4.0_pre11
2
2
  * (c) 2005 Sam Stephenson <sam@conio.net>
3
3
  *
4
4
  * THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff
@@ -11,8 +11,10 @@
11
11
  /*--------------------------------------------------------------------------*/
12
12
 
13
13
  var Prototype = {
14
- Version: '1.3.1',
15
- emptyFunction: function() {}
14
+ Version: '1.4.0_pre11',
15
+
16
+ emptyFunction: function() {},
17
+ K: function(x) {return x}
16
18
  }
17
19
 
18
20
  var Class = {
@@ -32,29 +34,47 @@ Object.extend = function(destination, source) {
32
34
  return destination;
33
35
  }
34
36
 
35
- Object.prototype.extend = function(object) {
36
- return Object.extend.apply(this, [this, object]);
37
+ Object.inspect = function(object) {
38
+ try {
39
+ if (object == undefined) return 'undefined';
40
+ if (object == null) return 'null';
41
+ return object.inspect ? object.inspect() : object.toString();
42
+ } catch (e) {
43
+ if (e instanceof RangeError) return '...';
44
+ throw e;
45
+ }
37
46
  }
38
47
 
39
48
  Function.prototype.bind = function(object) {
40
49
  var __method = this;
41
50
  return function() {
42
- __method.apply(object, arguments);
51
+ return __method.apply(object, arguments);
43
52
  }
44
53
  }
45
54
 
46
55
  Function.prototype.bindAsEventListener = function(object) {
47
56
  var __method = this;
48
57
  return function(event) {
49
- __method.call(object, event || window.event);
58
+ return __method.call(object, event || window.event);
50
59
  }
51
60
  }
52
61
 
53
- Number.prototype.toColorPart = function() {
54
- var digits = this.toString(16);
55
- if (this < 16) return '0' + digits;
56
- return digits;
57
- }
62
+ Object.extend(Number.prototype, {
63
+ toColorPart: function() {
64
+ var digits = this.toString(16);
65
+ if (this < 16) return '0' + digits;
66
+ return digits;
67
+ },
68
+
69
+ succ: function() {
70
+ return this + 1;
71
+ },
72
+
73
+ times: function(iterator) {
74
+ $R(0, this, true).each(iterator);
75
+ return this;
76
+ }
77
+ });
58
78
 
59
79
  var Try = {
60
80
  these: function() {
@@ -119,35 +139,7 @@ function $() {
119
139
  return elements;
120
140
  }
121
141
 
122
- if (!Array.prototype.push) {
123
- Array.prototype.push = function() {
124
- var startLength = this.length;
125
- for (var i = 0; i < arguments.length; i++)
126
- this[startLength + i] = arguments[i];
127
- return this.length;
128
- }
129
- }
130
-
131
- if (!Function.prototype.apply) {
132
- // Based on code from http://www.youngpup.net/
133
- Function.prototype.apply = function(object, parameters) {
134
- var parameterStrings = new Array();
135
- if (!object) object = window;
136
- if (!parameters) parameters = new Array();
137
-
138
- for (var i = 0; i < parameters.length; i++)
139
- parameterStrings[i] = 'parameters[' + i + ']';
140
-
141
- object.__apply__ = this;
142
- var result = eval('object.__apply__(' +
143
- parameterStrings[i].join(', ') + ')');
144
- object.__apply__ = null;
145
-
146
- return result;
147
- }
148
- }
149
-
150
- String.prototype.extend({
142
+ Object.extend(String.prototype, {
151
143
  stripTags: function() {
152
144
  return this.replace(/<\/?[^>]+>/gi, '');
153
145
  },
@@ -162,10 +154,340 @@ String.prototype.extend({
162
154
  unescapeHTML: function() {
163
155
  var div = document.createElement('div');
164
156
  div.innerHTML = this.stripTags();
165
- return div.childNodes[0].nodeValue;
157
+ return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
158
+ },
159
+
160
+ toQueryParams: function() {
161
+ var pairs = this.match(/^\??(.*)$/)[1].split('&');
162
+ return pairs.inject({}, function(params, pairString) {
163
+ var pair = pairString.split('=');
164
+ params[pair[0]] = pair[1];
165
+ return params;
166
+ });
167
+ },
168
+
169
+ inspect: function() {
170
+ return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'";
171
+ }
172
+ });
173
+
174
+ String.prototype.parseQuery = String.prototype.toQueryParams;
175
+
176
+
177
+ var $break = new Object();
178
+ var $continue = new Object();
179
+
180
+ var Enumerable = {
181
+ each: function(iterator) {
182
+ var index = 0;
183
+ try {
184
+ this._each(function(value) {
185
+ try {
186
+ iterator(value, index++);
187
+ } catch (e) {
188
+ if (e != $continue) throw e;
189
+ }
190
+ });
191
+ } catch (e) {
192
+ if (e != $break) throw e;
193
+ }
194
+ },
195
+
196
+ all: function(iterator) {
197
+ var result = true;
198
+ this.each(function(value, index) {
199
+ if (!(result &= (iterator || Prototype.K)(value, index)))
200
+ throw $break;
201
+ });
202
+ return result;
203
+ },
204
+
205
+ any: function(iterator) {
206
+ var result = true;
207
+ this.each(function(value, index) {
208
+ if (result &= (iterator || Prototype.K)(value, index))
209
+ throw $break;
210
+ });
211
+ return result;
212
+ },
213
+
214
+ collect: function(iterator) {
215
+ var results = [];
216
+ this.each(function(value, index) {
217
+ results.push(iterator(value, index));
218
+ });
219
+ return results;
220
+ },
221
+
222
+ detect: function (iterator) {
223
+ var result;
224
+ this.each(function(value, index) {
225
+ if (iterator(value, index)) {
226
+ result = value;
227
+ throw $break;
228
+ }
229
+ });
230
+ return result;
231
+ },
232
+
233
+ findAll: function(iterator) {
234
+ var results = [];
235
+ this.each(function(value, index) {
236
+ if (iterator(value, index))
237
+ results.push(value);
238
+ });
239
+ return results;
240
+ },
241
+
242
+ grep: function(pattern, iterator) {
243
+ var results = [];
244
+ this.each(function(value, index) {
245
+ var stringValue = value.toString();
246
+ if (stringValue.match(pattern))
247
+ results.push((iterator || Prototype.K)(value, index));
248
+ })
249
+ return results;
250
+ },
251
+
252
+ include: function(object) {
253
+ var found = false;
254
+ this.each(function(value) {
255
+ if (value == object) {
256
+ found = true;
257
+ throw $break;
258
+ }
259
+ });
260
+ return found;
261
+ },
262
+
263
+ inject: function(memo, iterator) {
264
+ this.each(function(value, index) {
265
+ memo = iterator(memo, value, index);
266
+ });
267
+ return memo;
268
+ },
269
+
270
+ invoke: function(method) {
271
+ var args = $A(arguments).slice(1);
272
+ return this.collect(function(value) {
273
+ return value[method].apply(value, args);
274
+ });
275
+ },
276
+
277
+ max: function(iterator) {
278
+ var result;
279
+ this.each(function(value, index) {
280
+ value = (iterator || Prototype.K)(value, index);
281
+ if (value >= (result || value))
282
+ result = value;
283
+ });
284
+ return result;
285
+ },
286
+
287
+ min: function(iterator) {
288
+ var result;
289
+ this.each(function(value, index) {
290
+ value = (iterator || Prototype.K)(value, index);
291
+ if (value <= (result || value))
292
+ result = value;
293
+ });
294
+ return result;
295
+ },
296
+
297
+ partition: function(iterator) {
298
+ var trues = [], falses = [];
299
+ this.each(function(value, index) {
300
+ ((iterator || Prototype.K)(value, index) ?
301
+ trues : falses).push(value);
302
+ });
303
+ return [trues, falses];
304
+ },
305
+
306
+ pluck: function(property) {
307
+ var results = [];
308
+ this.each(function(value, index) {
309
+ results.push(value[property]);
310
+ });
311
+ return results;
312
+ },
313
+
314
+ reject: function(iterator) {
315
+ var results = [];
316
+ this.each(function(value, index) {
317
+ if (!iterator(value, index))
318
+ results.push(value);
319
+ });
320
+ return results;
321
+ },
322
+
323
+ sortBy: function(iterator) {
324
+ return this.collect(function(value, index) {
325
+ return {value: value, criteria: iterator(value, index)};
326
+ }).sort(function(left, right) {
327
+ var a = left.criteria, b = right.criteria;
328
+ return a < b ? -1 : a > b ? 1 : 0;
329
+ }).pluck('value');
330
+ },
331
+
332
+ toArray: function() {
333
+ return this.collect(Prototype.K);
334
+ },
335
+
336
+ zip: function() {
337
+ var iterator = Prototype.K, args = $A(arguments);
338
+ if (typeof args.last() == 'function')
339
+ iterator = args.pop();
340
+
341
+ var collections = [this].concat(args).map($A);
342
+ return this.map(function(value, index) {
343
+ iterator(value = collections.pluck(index));
344
+ return value;
345
+ });
346
+ },
347
+
348
+ inspect: function() {
349
+ return '#<Enumerable:' + this.toArray().inspect() + '>';
350
+ }
351
+ }
352
+
353
+ Object.extend(Enumerable, {
354
+ map: Enumerable.collect,
355
+ find: Enumerable.detect,
356
+ select: Enumerable.findAll,
357
+ member: Enumerable.include,
358
+ entries: Enumerable.toArray
359
+ });
360
+
361
+ var $A = Array.from = function(iterable) {
362
+ if (iterable.toArray) {
363
+ return iterable.toArray();
364
+ } else {
365
+ var results = [];
366
+ for (var i = 0; i < iterable.length; i++)
367
+ results.push(iterable[i]);
368
+ return results;
369
+ }
370
+ }
371
+
372
+ Object.extend(Array.prototype, Enumerable);
373
+
374
+ Object.extend(Array.prototype, {
375
+ _each: function(iterator) {
376
+ for (var i = 0; i < this.length; i++)
377
+ iterator(this[i]);
378
+ },
379
+
380
+ first: function() {
381
+ return this[0];
382
+ },
383
+
384
+ last: function() {
385
+ return this[this.length - 1];
386
+ },
387
+
388
+ compact: function() {
389
+ return this.select(function(value) {
390
+ return value != undefined || value != null;
391
+ });
392
+ },
393
+
394
+ flatten: function() {
395
+ return this.inject([], function(array, value) {
396
+ return array.concat(value.constructor == Array ?
397
+ value.flatten() : [value]);
398
+ });
399
+ },
400
+
401
+ without: function() {
402
+ var values = $A(arguments);
403
+ return this.select(function(value) {
404
+ return !values.include(value);
405
+ });
406
+ },
407
+
408
+ inspect: function() {
409
+ return '[' + this.map(Object.inspect).join(', ') + ']';
410
+ }
411
+ });
412
+
413
+ var Hash = {
414
+ _each: function(iterator) {
415
+ for (key in this) {
416
+ var value = this[key];
417
+ if (typeof value == 'function') continue;
418
+
419
+ var pair = [key, value];
420
+ pair.key = key;
421
+ pair.value = value;
422
+ iterator(pair);
423
+ }
424
+ },
425
+
426
+ keys: function() {
427
+ return this.pluck('key');
428
+ },
429
+
430
+ values: function() {
431
+ return this.pluck('value');
432
+ },
433
+
434
+ merge: function(hash) {
435
+ return $H(hash).inject($H(this), function(mergedHash, pair) {
436
+ mergedHash[pair.key] = pair.value;
437
+ return mergedHash;
438
+ });
439
+ },
440
+
441
+ toQueryString: function() {
442
+ return this.map(function(pair) {
443
+ return pair.map(encodeURIComponent).join('=');
444
+ }).join('&');
445
+ },
446
+
447
+ inspect: function() {
448
+ return '#<Hash:{' + this.map(function(pair) {
449
+ return pair.map(Object.inspect).join(': ');
450
+ }).join(', ') + '}>';
451
+ }
452
+ }
453
+
454
+ function $H(object) {
455
+ var hash = Object.extend({}, object || {});
456
+ Object.extend(hash, Enumerable);
457
+ Object.extend(hash, Hash);
458
+ return hash;
459
+ }
460
+
461
+ var Range = Class.create();
462
+ Object.extend(Range.prototype, Enumerable);
463
+ Object.extend(Range.prototype, {
464
+ initialize: function(start, end, exclusive) {
465
+ this.start = start;
466
+ this.end = end;
467
+ this.exclusive = exclusive;
468
+ },
469
+
470
+ _each: function(iterator) {
471
+ var value = this.start;
472
+ do {
473
+ iterator(value);
474
+ value = value.succ();
475
+ } while (this.include(value));
476
+ },
477
+
478
+ include: function(value) {
479
+ if (value < this.start)
480
+ return false;
481
+ if (this.exclusive)
482
+ return value < this.end;
483
+ return value <= this.end;
166
484
  }
167
485
  });
168
486
 
487
+ var $R = function(start, end, exclusive) {
488
+ return new Range(start, end, exclusive);
489
+ }
490
+
169
491
  var Ajax = {
170
492
  getTransport: function() {
171
493
  return Try.these(
@@ -173,9 +495,51 @@ var Ajax = {
173
495
  function() {return new ActiveXObject('Microsoft.XMLHTTP')},
174
496
  function() {return new XMLHttpRequest()}
175
497
  ) || false;
176
- }
498
+ },
499
+
500
+ activeRequestCount: 0
177
501
  }
178
502
 
503
+ Ajax.Responders = {
504
+ responders: [],
505
+
506
+ _each: function(iterator) {
507
+ this.responders._each(iterator);
508
+ },
509
+
510
+ register: function(responderToAdd) {
511
+ if (!this.include(responderToAdd))
512
+ this.responders.push(responderToAdd);
513
+ },
514
+
515
+ unregister: function(responderToRemove) {
516
+ this.responders = this.responders.without(responderToRemove);
517
+ },
518
+
519
+ dispatch: function(callback, request, transport, json) {
520
+ this.each(function(responder) {
521
+ if (responder[callback] && typeof responder[callback] == 'function') {
522
+ try {
523
+ responder[callback].apply(responder, [request, transport, json]);
524
+ } catch (e) {
525
+ }
526
+ }
527
+ });
528
+ }
529
+ };
530
+
531
+ Object.extend(Ajax.Responders, Enumerable);
532
+
533
+ Ajax.Responders.register({
534
+ onCreate: function() {
535
+ Ajax.activeRequestCount++;
536
+ },
537
+
538
+ onComplete: function() {
539
+ Ajax.activeRequestCount--;
540
+ }
541
+ });
542
+
179
543
  Ajax.Base = function() {};
180
544
  Ajax.Base.prototype = {
181
545
  setOptions: function(options) {
@@ -183,7 +547,8 @@ Ajax.Base.prototype = {
183
547
  method: 'post',
184
548
  asynchronous: true,
185
549
  parameters: ''
186
- }.extend(options || {});
550
+ }
551
+ Object.extend(this.options, options || {});
187
552
  },
188
553
 
189
554
  responseIsSuccess: function() {
@@ -201,7 +566,7 @@ Ajax.Request = Class.create();
201
566
  Ajax.Request.Events =
202
567
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
203
568
 
204
- Ajax.Request.prototype = (new Ajax.Base()).extend({
569
+ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
205
570
  initialize: function(url, options) {
206
571
  this.transport = Ajax.getTransport();
207
572
  this.setOptions(options);
@@ -213,10 +578,13 @@ Ajax.Request.prototype = (new Ajax.Base()).extend({
213
578
  if (parameters.length > 0) parameters += '&_=';
214
579
 
215
580
  try {
216
- if (this.options.method == 'get')
217
- url += '?' + parameters;
218
-
219
- this.transport.open(this.options.method, url,
581
+ this.url = url;
582
+ if (this.options.method == 'get')
583
+ this.url += '?' + parameters;
584
+
585
+ Ajax.Responders.dispatch('onCreate', this, this.transport);
586
+
587
+ this.transport.open(this.options.method, this.url,
220
588
  this.options.asynchronous);
221
589
 
222
590
  if (this.options.asynchronous) {
@@ -262,16 +630,27 @@ Ajax.Request.prototype = (new Ajax.Base()).extend({
262
630
  if (readyState != 1)
263
631
  this.respondToReadyState(this.transport.readyState);
264
632
  },
633
+
634
+ evalJSON: function() {
635
+ try {
636
+ var json = this.transport.getResponseHeader('X-JSON'), object;
637
+ object = eval(json);
638
+ return object;
639
+ } catch (e) {
640
+ }
641
+ },
265
642
 
266
643
  respondToReadyState: function(readyState) {
267
644
  var event = Ajax.Request.Events[readyState];
645
+ var transport = this.transport, json = this.evalJSON();
268
646
 
269
647
  if (event == 'Complete')
270
648
  (this.options['on' + this.transport.status]
271
- || this.options['on' + this.responseIsSuccess() ? 'Success' : 'Failure']
272
- || Prototype.emptyFunction)(this.transport);
649
+ || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
650
+ || Prototype.emptyFunction)(transport, json);
273
651
 
274
- (this.options['on' + event] || Prototype.emptyFunction)(this.transport);
652
+ (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
653
+ Ajax.Responders.dispatch('on' + event, this, transport, json);
275
654
 
276
655
  /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
277
656
  if (event == 'Complete')
@@ -282,7 +661,7 @@ Ajax.Request.prototype = (new Ajax.Base()).extend({
282
661
  Ajax.Updater = Class.create();
283
662
  Ajax.Updater.ScriptFragment = '(?:<script.*?>)((\n|.)*?)(?:<\/script>)';
284
663
 
285
- Ajax.Updater.prototype.extend(Ajax.Request.prototype).extend({
664
+ Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
286
665
  initialize: function(container, url, options) {
287
666
  this.containers = {
288
667
  success: container.success ? $(container.success) : $(container),
@@ -294,9 +673,9 @@ Ajax.Updater.prototype.extend(Ajax.Request.prototype).extend({
294
673
  this.setOptions(options);
295
674
 
296
675
  var onComplete = this.options.onComplete || Prototype.emptyFunction;
297
- this.options.onComplete = (function() {
676
+ this.options.onComplete = (function(transport, object) {
298
677
  this.updateContent();
299
- onComplete(this.transport);
678
+ onComplete(transport, object);
300
679
  }).bind(this);
301
680
 
302
681
  this.request(url);
@@ -320,8 +699,7 @@ Ajax.Updater.prototype.extend(Ajax.Request.prototype).extend({
320
699
 
321
700
  if (this.responseIsSuccess()) {
322
701
  if (this.onComplete)
323
- setTimeout((function() {this.onComplete(
324
- this.transport)}).bind(this), 10);
702
+ setTimeout(this.onComplete.bind(this), 10);
325
703
  }
326
704
 
327
705
  if (this.options.evalScripts && scripts) {
@@ -335,7 +713,7 @@ Ajax.Updater.prototype.extend(Ajax.Request.prototype).extend({
335
713
  });
336
714
 
337
715
  Ajax.PeriodicalUpdater = Class.create();
338
- Ajax.PeriodicalUpdater.prototype = (new Ajax.Base()).extend({
716
+ Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
339
717
  initialize: function(container, url, options) {
340
718
  this.setOptions(options);
341
719
  this.onComplete = this.options.onComplete;
@@ -377,22 +755,13 @@ Ajax.PeriodicalUpdater.prototype = (new Ajax.Base()).extend({
377
755
  }
378
756
  });
379
757
 
380
- document.getElementsByClassName = function(className) {
381
- var children = document.getElementsByTagName('*') || document.all;
382
- var elements = new Array();
383
-
384
- for (var i = 0; i < children.length; i++) {
385
- var child = children[i];
386
- var classNames = child.className.split(' ');
387
- for (var j = 0; j < classNames.length; j++) {
388
- if (classNames[j] == className) {
389
- elements.push(child);
390
- break;
391
- }
392
- }
393
- }
394
-
395
- return elements;
758
+ document.getElementsByClassName = function(className, parentElement) {
759
+ var children = (document.body || $(parentElement)).getElementsByTagName('*');
760
+ return $A(children).inject([], function(elements, child) {
761
+ if (Element.hasClassName(child, className))
762
+ elements.push(child);
763
+ return elements;
764
+ });
396
765
  }
397
766
 
398
767
  /*--------------------------------------------------------------------------*/
@@ -402,11 +771,14 @@ if (!window.Element) {
402
771
  }
403
772
 
404
773
  Object.extend(Element, {
774
+ visible: function(element) {
775
+ return $(element).style.display != 'none';
776
+ },
777
+
405
778
  toggle: function() {
406
779
  for (var i = 0; i < arguments.length; i++) {
407
780
  var element = $(arguments[i]);
408
- element.style.display =
409
- (element.style.display == 'none' ? '' : 'none');
781
+ Element[Element.visible(element) ? 'show' : 'hide'](element);
410
782
  }
411
783
  },
412
784
 
@@ -416,7 +788,7 @@ Object.extend(Element, {
416
788
  element.style.display = 'none';
417
789
  }
418
790
  },
419
-
791
+
420
792
  show: function() {
421
793
  for (var i = 0; i < arguments.length; i++) {
422
794
  var element = $(arguments[i]);
@@ -428,54 +800,50 @@ Object.extend(Element, {
428
800
  element = $(element);
429
801
  element.parentNode.removeChild(element);
430
802
  },
431
-
803
+
432
804
  getHeight: function(element) {
433
805
  element = $(element);
434
806
  return element.offsetHeight;
435
807
  },
808
+
809
+ classNames: function(element) {
810
+ return new Element.ClassNames(element);
811
+ },
436
812
 
437
813
  hasClassName: function(element, className) {
438
- element = $(element);
439
- if (!element)
440
- return;
441
- var a = element.className.split(' ');
442
- for (var i = 0; i < a.length; i++) {
443
- if (a[i] == className)
444
- return true;
445
- }
446
- return false;
814
+ if (!(element = $(element))) return;
815
+ return Element.classNames(element).include(className);
447
816
  },
448
817
 
449
818
  addClassName: function(element, className) {
450
- element = $(element);
451
- Element.removeClassName(element, className);
452
- element.className += ' ' + className;
819
+ if (!(element = $(element))) return;
820
+ return Element.classNames(element).add(className);
453
821
  },
454
822
 
455
823
  removeClassName: function(element, className) {
456
- element = $(element);
457
- if (!element)
458
- return;
459
- var newClassName = '';
460
- var a = element.className.split(' ');
461
- for (var i = 0; i < a.length; i++) {
462
- if (a[i] != className) {
463
- if (i > 0)
464
- newClassName += ' ';
465
- newClassName += a[i];
466
- }
467
- }
468
- element.className = newClassName;
824
+ if (!(element = $(element))) return;
825
+ return Element.classNames(element).remove(className);
469
826
  },
470
827
 
471
828
  // removes whitespace-only text node children
472
829
  cleanWhitespace: function(element) {
473
- var element = $(element);
830
+ element = $(element);
474
831
  for (var i = 0; i < element.childNodes.length; i++) {
475
832
  var node = element.childNodes[i];
476
833
  if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
477
834
  Element.remove(node);
478
835
  }
836
+ },
837
+
838
+ empty: function(element) {
839
+ return $(element).innerHTML.match(/^\s*$/);
840
+ },
841
+
842
+ scrollTo: function(element) {
843
+ element = $(element);
844
+ var x = element.x ? element.x : element.offsetLeft,
845
+ y = element.y ? element.y : element.offsetTop;
846
+ window.scrollTo(x, y);
479
847
  }
480
848
  });
481
849
 
@@ -494,20 +862,35 @@ Abstract.Insertion.prototype = {
494
862
  this.content = content;
495
863
 
496
864
  if (this.adjacency && this.element.insertAdjacentHTML) {
497
- this.element.insertAdjacentHTML(this.adjacency, this.content);
865
+ try {
866
+ this.element.insertAdjacentHTML(this.adjacency, this.content);
867
+ } catch (e) {
868
+ if (this.element.tagName.toLowerCase() == 'tbody') {
869
+ this.fragment = this.contentFromAnonymousTable();
870
+ this.insertContent();
871
+ } else {
872
+ throw e;
873
+ }
874
+ }
498
875
  } else {
499
876
  this.range = this.element.ownerDocument.createRange();
500
877
  if (this.initializeRange) this.initializeRange();
501
878
  this.fragment = this.range.createContextualFragment(this.content);
502
879
  this.insertContent();
503
880
  }
881
+ },
882
+
883
+ contentFromAnonymousTable: function() {
884
+ var div = document.createElement('div');
885
+ div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
886
+ return div.childNodes[0].childNodes[0].childNodes[0];
504
887
  }
505
888
  }
506
889
 
507
890
  var Insertion = new Object();
508
891
 
509
892
  Insertion.Before = Class.create();
510
- Insertion.Before.prototype = (new Abstract.Insertion('beforeBegin')).extend({
893
+ Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
511
894
  initializeRange: function() {
512
895
  this.range.setStartBefore(this.element);
513
896
  },
@@ -518,7 +901,7 @@ Insertion.Before.prototype = (new Abstract.Insertion('beforeBegin')).extend({
518
901
  });
519
902
 
520
903
  Insertion.Top = Class.create();
521
- Insertion.Top.prototype = (new Abstract.Insertion('afterBegin')).extend({
904
+ Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
522
905
  initializeRange: function() {
523
906
  this.range.selectNodeContents(this.element);
524
907
  this.range.collapse(true);
@@ -530,7 +913,7 @@ Insertion.Top.prototype = (new Abstract.Insertion('afterBegin')).extend({
530
913
  });
531
914
 
532
915
  Insertion.Bottom = Class.create();
533
- Insertion.Bottom.prototype = (new Abstract.Insertion('beforeEnd')).extend({
916
+ Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
534
917
  initializeRange: function() {
535
918
  this.range.selectNodeContents(this.element);
536
919
  this.range.collapse(this.element);
@@ -542,7 +925,7 @@ Insertion.Bottom.prototype = (new Abstract.Insertion('beforeEnd')).extend({
542
925
  });
543
926
 
544
927
  Insertion.After = Class.create();
545
- Insertion.After.prototype = (new Abstract.Insertion('afterEnd')).extend({
928
+ Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
546
929
  initializeRange: function() {
547
930
  this.range.setStartAfter(this.element);
548
931
  },
@@ -553,6 +936,43 @@ Insertion.After.prototype = (new Abstract.Insertion('afterEnd')).extend({
553
936
  }
554
937
  });
555
938
 
939
+ /*--------------------------------------------------------------------------*/
940
+
941
+ Element.ClassNames = Class.create();
942
+ Element.ClassNames.prototype = {
943
+ initialize: function(element) {
944
+ this.element = $(element);
945
+ },
946
+
947
+ _each: function(iterator) {
948
+ this.element.className.split(/\s+/).select(function(name) {
949
+ return name.length > 0;
950
+ })._each(iterator);
951
+ },
952
+
953
+ set: function(className) {
954
+ this.element.className = className;
955
+ },
956
+
957
+ add: function(classNameToAdd) {
958
+ if (this.include(classNameToAdd)) return;
959
+ this.set(this.toArray().concat(classNameToAdd).join(' '));
960
+ },
961
+
962
+ remove: function(classNameToRemove) {
963
+ if (!this.include(classNameToRemove)) return;
964
+ this.set(this.select(function(className) {
965
+ return className != classNameToRemove;
966
+ }));
967
+ },
968
+
969
+ toString: function() {
970
+ return this.toArray().join(' ');
971
+ }
972
+ }
973
+
974
+ Object.extend(Element.ClassNames.prototype, Enumerable);
975
+
556
976
  var Field = {
557
977
  clear: function() {
558
978
  for (var i = 0; i < arguments.length; i++)
@@ -704,19 +1124,32 @@ Form.Element.Serializers = {
704
1124
  textarea: function(element) {
705
1125
  return [element.name, element.value];
706
1126
  },
707
-
1127
+
708
1128
  select: function(element) {
709
- var value = '';
710
- if (element.type == 'select-one') {
711
- var index = element.selectedIndex;
712
- if (index >= 0)
713
- value = element.options[index].value || element.options[index].text;
714
- } else {
715
- value = new Array();
716
- for (var i = 0; i < element.length; i++) {
717
- var opt = element.options[i];
718
- if (opt.selected)
719
- value.push(opt.value || opt.text);
1129
+ return Form.Element.Serializers[element.type == 'select-one' ?
1130
+ 'selectOne' : 'selectMany'](element);
1131
+ },
1132
+
1133
+ selectOne: function(element) {
1134
+ var value = '', opt, index = element.selectedIndex;
1135
+ if (index >= 0) {
1136
+ opt = element.options[index];
1137
+ value = opt.value;
1138
+ if (!value && !('value' in opt))
1139
+ value = opt.text;
1140
+ }
1141
+ return [element.name, value];
1142
+ },
1143
+
1144
+ selectMany: function(element) {
1145
+ var value = new Array();
1146
+ for (var i = 0; i < element.length; i++) {
1147
+ var opt = element.options[i];
1148
+ if (opt.selected) {
1149
+ var optValue = opt.value;
1150
+ if (!optValue && !('value' in opt))
1151
+ optValue = opt.text;
1152
+ value.push(optValue);
720
1153
  }
721
1154
  }
722
1155
  return [element.name, value];
@@ -754,14 +1187,14 @@ Abstract.TimedObserver.prototype = {
754
1187
  }
755
1188
 
756
1189
  Form.Element.Observer = Class.create();
757
- Form.Element.Observer.prototype = (new Abstract.TimedObserver()).extend({
1190
+ Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
758
1191
  getValue: function() {
759
1192
  return Form.Element.getValue(this.element);
760
1193
  }
761
1194
  });
762
1195
 
763
1196
  Form.Observer = Class.create();
764
- Form.Observer.prototype = (new Abstract.TimedObserver()).extend({
1197
+ Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
765
1198
  getValue: function() {
766
1199
  return Form.serialize(this.element);
767
1200
  }
@@ -826,14 +1259,14 @@ Abstract.EventObserver.prototype = {
826
1259
  }
827
1260
 
828
1261
  Form.Element.EventObserver = Class.create();
829
- Form.Element.EventObserver.prototype = (new Abstract.EventObserver()).extend({
1262
+ Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
830
1263
  getValue: function() {
831
1264
  return Form.Element.getValue(this.element);
832
1265
  }
833
1266
  });
834
1267
 
835
1268
  Form.EventObserver = Class.create();
836
- Form.EventObserver.prototype = (new Abstract.EventObserver()).extend({
1269
+ Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
837
1270
  getValue: function() {
838
1271
  return Form.serialize(this.element);
839
1272
  }
@@ -880,6 +1313,7 @@ Object.extend(Event, {
880
1313
  event.stopPropagation();
881
1314
  } else {
882
1315
  event.returnValue = false;
1316
+ event.cancelBubble = true;
883
1317
  }
884
1318
  },
885
1319
 
@@ -920,7 +1354,7 @@ Object.extend(Event, {
920
1354
  useCapture = useCapture || false;
921
1355
 
922
1356
  if (name == 'keypress' &&
923
- ((navigator.appVersion.indexOf('AppleWebKit') > 0)
1357
+ (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
924
1358
  || element.attachEvent))
925
1359
  name = 'keydown';
926
1360
 
@@ -932,7 +1366,7 @@ Object.extend(Event, {
932
1366
  useCapture = useCapture || false;
933
1367
 
934
1368
  if (name == 'keypress' &&
935
- ((navigator.appVersion.indexOf('AppleWebKit') > 0)
1369
+ (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
936
1370
  || element.detachEvent))
937
1371
  name = 'keydown';
938
1372