nitro 0.24.0 → 0.25.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 (67) hide show
  1. data/CHANGELOG +279 -0
  2. data/ProjectInfo +7 -7
  3. data/doc/AUTHORS +4 -2
  4. data/doc/RELEASES +96 -1
  5. data/lib/nitro.rb +5 -2
  6. data/lib/nitro/adapter/cgi.rb +1 -1
  7. data/lib/nitro/adapter/webrick.rb +7 -5
  8. data/lib/nitro/caching/output.rb +3 -2
  9. data/lib/nitro/cgi/utils.rb +8 -4
  10. data/lib/nitro/compiler.rb +9 -5
  11. data/lib/nitro/compiler/include.rb +42 -0
  12. data/lib/nitro/compiler/markup.rb +1 -1
  13. data/lib/nitro/compiler/morphing.rb +120 -50
  14. data/lib/nitro/compiler/squeeze.rb +2 -2
  15. data/lib/nitro/context.rb +9 -0
  16. data/lib/nitro/controller.rb +8 -4
  17. data/lib/nitro/dispatcher.rb +5 -5
  18. data/lib/nitro/dispatcher/nice.rb +16 -5
  19. data/lib/nitro/element.rb +30 -8
  20. data/lib/nitro/helper.rb +56 -0
  21. data/lib/nitro/{mixin → helper}/benchmark.rb +1 -1
  22. data/lib/nitro/{mixin → helper}/buffer.rb +1 -2
  23. data/lib/nitro/{mixin → helper}/debug.rb +1 -1
  24. data/lib/nitro/{mixin/helper.rb → helper/default.rb} +4 -4
  25. data/lib/nitro/{mixin → helper}/form.rb +3 -3
  26. data/lib/nitro/{mixin → helper}/javascript.rb +17 -1
  27. data/lib/nitro/{mixin → helper}/pager.rb +1 -1
  28. data/lib/nitro/{mixin → helper}/rss.rb +3 -3
  29. data/lib/nitro/{mixin → helper}/table.rb +1 -1
  30. data/lib/nitro/{mixin → helper}/xhtml.rb +2 -2
  31. data/lib/nitro/{mixin → helper}/xml.rb +1 -1
  32. data/lib/nitro/render.rb +16 -8
  33. data/lib/nitro/scaffold.rb +6 -6
  34. data/lib/nitro/server/runner.rb +12 -0
  35. data/lib/nitro/session/drbserver.rb +16 -1
  36. data/proto/public/js/builder.js +97 -0
  37. data/proto/public/js/controls.js +18 -5
  38. data/proto/public/js/dragdrop.js +8 -5
  39. data/proto/public/js/effects.js +185 -4
  40. data/proto/public/js/prototype.js +432 -178
  41. data/proto/public/js/scriptaculous.js +6 -2
  42. data/proto/public/js/slider.js +226 -0
  43. data/proto/public/js/unittest.js +363 -0
  44. data/proto/public/media/nitro.png +0 -0
  45. data/{script → proto/script}/scgi_ctl +0 -0
  46. data/{script → proto/script}/scgi_service +16 -8
  47. data/proto/src/skin.rb +24 -0
  48. data/{lib → src}/part/admin.rb +0 -0
  49. data/src/part/admin/controller.rb +47 -0
  50. data/{lib → src}/part/admin/skin.rb +0 -0
  51. data/src/part/admin/template/denied.xhtml +1 -0
  52. data/{lib → src}/part/admin/template/index.xhtml +0 -0
  53. data/test/nitro/{mixin → helper}/tc_pager.rb +2 -2
  54. data/test/nitro/{mixin → helper}/tc_rss.rb +3 -3
  55. data/test/nitro/{mixin → helper}/tc_table.rb +3 -3
  56. data/test/nitro/{mixin → helper}/tc_xhtml.rb +3 -3
  57. data/test/nitro/tc_caching.rb +4 -1
  58. data/test/nitro/tc_controller.rb +2 -2
  59. data/test/nitro/tc_element.rb +30 -0
  60. data/test/nitro/tc_helper.rb +36 -0
  61. data/test/nitro/tc_render.rb +1 -1
  62. metadata +70 -38
  63. data/lib/nitro/mixin/markup.rb +0 -122
  64. data/lib/part/admin/controller.rb +0 -28
  65. data/proto/README +0 -11
  66. data/proto/doc/README +0 -1
  67. data/proto/scgi.rb +0 -333
@@ -1,8 +1,8 @@
1
- /* Prototype JavaScript framework, version 1.4.0_pre11
1
+ /* Prototype JavaScript framework, version 1.4.0_rc2
2
2
  * (c) 2005 Sam Stephenson <sam@conio.net>
3
3
  *
4
4
  * THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff
5
- * against the source tree, available from the Prototype darcs repository.
5
+ * against the source tree, available from the Prototype darcs repository.
6
6
  *
7
7
  * Prototype is freely distributable under the terms of an MIT-style license.
8
8
  *
@@ -11,15 +11,15 @@
11
11
  /*--------------------------------------------------------------------------*/
12
12
 
13
13
  var Prototype = {
14
- Version: '1.4.0_pre11',
15
-
14
+ Version: '1.4.0_rc2',
15
+
16
16
  emptyFunction: function() {},
17
17
  K: function(x) {return x}
18
18
  }
19
19
 
20
20
  var Class = {
21
21
  create: function() {
22
- return function() {
22
+ return function() {
23
23
  this.initialize.apply(this, arguments);
24
24
  }
25
25
  }
@@ -69,7 +69,7 @@ Object.extend(Number.prototype, {
69
69
  succ: function() {
70
70
  return this + 1;
71
71
  },
72
-
72
+
73
73
  times: function(iterator) {
74
74
  $R(0, this, true).each(iterator);
75
75
  return this;
@@ -110,10 +110,10 @@ PeriodicalExecuter.prototype = {
110
110
 
111
111
  onTimerEvent: function() {
112
112
  if (!this.currentlyExecuting) {
113
- try {
113
+ try {
114
114
  this.currentlyExecuting = true;
115
- this.callback();
116
- } finally {
115
+ this.callback();
116
+ } finally {
117
117
  this.currentlyExecuting = false;
118
118
  }
119
119
  }
@@ -130,7 +130,7 @@ function $() {
130
130
  if (typeof element == 'string')
131
131
  element = document.getElementById(element);
132
132
 
133
- if (arguments.length == 1)
133
+ if (arguments.length == 1)
134
134
  return element;
135
135
 
136
136
  elements.push(element);
@@ -138,7 +138,6 @@ function $() {
138
138
 
139
139
  return elements;
140
140
  }
141
-
142
141
  Object.extend(String.prototype, {
143
142
  stripTags: function() {
144
143
  return this.replace(/<\/?[^>]+>/gi, '');
@@ -156,7 +155,7 @@ Object.extend(String.prototype, {
156
155
  div.innerHTML = this.stripTags();
157
156
  return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
158
157
  },
159
-
158
+
160
159
  toQueryParams: function() {
161
160
  var pairs = this.match(/^\??(.*)$/)[1].split('&');
162
161
  return pairs.inject({}, function(params, pairString) {
@@ -165,7 +164,27 @@ Object.extend(String.prototype, {
165
164
  return params;
166
165
  });
167
166
  },
168
-
167
+
168
+ toArray: function() {
169
+ return this.split('');
170
+ },
171
+
172
+ camelize: function() {
173
+ var oStringList = this.split('-');
174
+ if (oStringList.length == 1) return oStringList[0];
175
+
176
+ var camelizedString = this.indexOf('-') == 0
177
+ ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
178
+ : oStringList[0];
179
+
180
+ for (var i = 1, len = oStringList.length; i < len; i++) {
181
+ var s = oStringList[i];
182
+ camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
183
+ }
184
+
185
+ return camelizedString;
186
+ },
187
+
169
188
  inspect: function() {
170
189
  return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'";
171
190
  }
@@ -173,7 +192,6 @@ Object.extend(String.prototype, {
173
192
 
174
193
  String.prototype.parseQuery = String.prototype.toQueryParams;
175
194
 
176
-
177
195
  var $break = new Object();
178
196
  var $continue = new Object();
179
197
 
@@ -192,25 +210,25 @@ var Enumerable = {
192
210
  if (e != $break) throw e;
193
211
  }
194
212
  },
195
-
213
+
196
214
  all: function(iterator) {
197
215
  var result = true;
198
216
  this.each(function(value, index) {
199
- if (!(result &= (iterator || Prototype.K)(value, index)))
217
+ if (!(result &= (iterator || Prototype.K)(value, index)))
200
218
  throw $break;
201
219
  });
202
220
  return result;
203
221
  },
204
-
222
+
205
223
  any: function(iterator) {
206
224
  var result = true;
207
225
  this.each(function(value, index) {
208
- if (result &= (iterator || Prototype.K)(value, index))
226
+ if (result &= (iterator || Prototype.K)(value, index))
209
227
  throw $break;
210
228
  });
211
229
  return result;
212
230
  },
213
-
231
+
214
232
  collect: function(iterator) {
215
233
  var results = [];
216
234
  this.each(function(value, index) {
@@ -218,7 +236,7 @@ var Enumerable = {
218
236
  });
219
237
  return results;
220
238
  },
221
-
239
+
222
240
  detect: function (iterator) {
223
241
  var result;
224
242
  this.each(function(value, index) {
@@ -229,7 +247,7 @@ var Enumerable = {
229
247
  });
230
248
  return result;
231
249
  },
232
-
250
+
233
251
  findAll: function(iterator) {
234
252
  var results = [];
235
253
  this.each(function(value, index) {
@@ -238,7 +256,7 @@ var Enumerable = {
238
256
  });
239
257
  return results;
240
258
  },
241
-
259
+
242
260
  grep: function(pattern, iterator) {
243
261
  var results = [];
244
262
  this.each(function(value, index) {
@@ -248,7 +266,7 @@ var Enumerable = {
248
266
  })
249
267
  return results;
250
268
  },
251
-
269
+
252
270
  include: function(object) {
253
271
  var found = false;
254
272
  this.each(function(value) {
@@ -259,21 +277,21 @@ var Enumerable = {
259
277
  });
260
278
  return found;
261
279
  },
262
-
280
+
263
281
  inject: function(memo, iterator) {
264
282
  this.each(function(value, index) {
265
283
  memo = iterator(memo, value, index);
266
284
  });
267
285
  return memo;
268
286
  },
269
-
287
+
270
288
  invoke: function(method) {
271
289
  var args = $A(arguments).slice(1);
272
290
  return this.collect(function(value) {
273
291
  return value[method].apply(value, args);
274
292
  });
275
293
  },
276
-
294
+
277
295
  max: function(iterator) {
278
296
  var result;
279
297
  this.each(function(value, index) {
@@ -283,7 +301,7 @@ var Enumerable = {
283
301
  });
284
302
  return result;
285
303
  },
286
-
304
+
287
305
  min: function(iterator) {
288
306
  var result;
289
307
  this.each(function(value, index) {
@@ -293,16 +311,16 @@ var Enumerable = {
293
311
  });
294
312
  return result;
295
313
  },
296
-
314
+
297
315
  partition: function(iterator) {
298
316
  var trues = [], falses = [];
299
317
  this.each(function(value, index) {
300
- ((iterator || Prototype.K)(value, index) ?
318
+ ((iterator || Prototype.K)(value, index) ?
301
319
  trues : falses).push(value);
302
320
  });
303
321
  return [trues, falses];
304
322
  },
305
-
323
+
306
324
  pluck: function(property) {
307
325
  var results = [];
308
326
  this.each(function(value, index) {
@@ -310,7 +328,7 @@ var Enumerable = {
310
328
  });
311
329
  return results;
312
330
  },
313
-
331
+
314
332
  reject: function(iterator) {
315
333
  var results = [];
316
334
  this.each(function(value, index) {
@@ -319,7 +337,7 @@ var Enumerable = {
319
337
  });
320
338
  return results;
321
339
  },
322
-
340
+
323
341
  sortBy: function(iterator) {
324
342
  return this.collect(function(value, index) {
325
343
  return {value: value, criteria: iterator(value, index)};
@@ -328,11 +346,11 @@ var Enumerable = {
328
346
  return a < b ? -1 : a > b ? 1 : 0;
329
347
  }).pluck('value');
330
348
  },
331
-
349
+
332
350
  toArray: function() {
333
351
  return this.collect(Prototype.K);
334
352
  },
335
-
353
+
336
354
  zip: function() {
337
355
  var iterator = Prototype.K, args = $A(arguments);
338
356
  if (typeof args.last() == 'function')
@@ -344,7 +362,7 @@ var Enumerable = {
344
362
  return value;
345
363
  });
346
364
  },
347
-
365
+
348
366
  inspect: function() {
349
367
  return '#<Enumerable:' + this.toArray().inspect() + '>';
350
368
  }
@@ -357,7 +375,6 @@ Object.extend(Enumerable, {
357
375
  member: Enumerable.include,
358
376
  entries: Enumerable.toArray
359
377
  });
360
-
361
378
  var $A = Array.from = function(iterable) {
362
379
  if (iterable.toArray) {
363
380
  return iterable.toArray();
@@ -376,74 +393,86 @@ Object.extend(Array.prototype, {
376
393
  for (var i = 0; i < this.length; i++)
377
394
  iterator(this[i]);
378
395
  },
379
-
396
+
380
397
  first: function() {
381
398
  return this[0];
382
399
  },
383
-
400
+
384
401
  last: function() {
385
402
  return this[this.length - 1];
386
403
  },
387
-
404
+
388
405
  compact: function() {
389
406
  return this.select(function(value) {
390
407
  return value != undefined || value != null;
391
408
  });
392
409
  },
393
-
410
+
394
411
  flatten: function() {
395
412
  return this.inject([], function(array, value) {
396
413
  return array.concat(value.constructor == Array ?
397
414
  value.flatten() : [value]);
398
415
  });
399
416
  },
400
-
417
+
401
418
  without: function() {
402
419
  var values = $A(arguments);
403
420
  return this.select(function(value) {
404
421
  return !values.include(value);
405
422
  });
406
423
  },
407
-
424
+
425
+ indexOf: function(object) {
426
+ for (var i = 0; i < this.length; i++)
427
+ if (this[i] == object) return i;
428
+ return false;
429
+ },
430
+
431
+ reverse: function() {
432
+ var result = [];
433
+ for (var i = this.length; i > 0; i--)
434
+ result.push(this[i-1]);
435
+ return result;
436
+ },
437
+
408
438
  inspect: function() {
409
439
  return '[' + this.map(Object.inspect).join(', ') + ']';
410
440
  }
411
441
  });
412
-
413
442
  var Hash = {
414
443
  _each: function(iterator) {
415
444
  for (key in this) {
416
445
  var value = this[key];
417
446
  if (typeof value == 'function') continue;
418
-
447
+
419
448
  var pair = [key, value];
420
449
  pair.key = key;
421
450
  pair.value = value;
422
451
  iterator(pair);
423
452
  }
424
453
  },
425
-
454
+
426
455
  keys: function() {
427
456
  return this.pluck('key');
428
457
  },
429
-
458
+
430
459
  values: function() {
431
460
  return this.pluck('value');
432
461
  },
433
-
462
+
434
463
  merge: function(hash) {
435
464
  return $H(hash).inject($H(this), function(mergedHash, pair) {
436
465
  mergedHash[pair.key] = pair.value;
437
466
  return mergedHash;
438
467
  });
439
468
  },
440
-
469
+
441
470
  toQueryString: function() {
442
471
  return this.map(function(pair) {
443
472
  return pair.map(encodeURIComponent).join('=');
444
473
  }).join('&');
445
474
  },
446
-
475
+
447
476
  inspect: function() {
448
477
  return '#<Hash:{' + this.map(function(pair) {
449
478
  return pair.map(Object.inspect).join(': ');
@@ -457,7 +486,6 @@ function $H(object) {
457
486
  Object.extend(hash, Hash);
458
487
  return hash;
459
488
  }
460
-
461
489
  var Range = Class.create();
462
490
  Object.extend(Range.prototype, Enumerable);
463
491
  Object.extend(Range.prototype, {
@@ -466,7 +494,7 @@ Object.extend(Range.prototype, {
466
494
  this.end = end;
467
495
  this.exclusive = exclusive;
468
496
  },
469
-
497
+
470
498
  _each: function(iterator) {
471
499
  var value = this.start;
472
500
  do {
@@ -474,9 +502,9 @@ Object.extend(Range.prototype, {
474
502
  value = value.succ();
475
503
  } while (this.include(value));
476
504
  },
477
-
505
+
478
506
  include: function(value) {
479
- if (value < this.start)
507
+ if (value < this.start)
480
508
  return false;
481
509
  if (this.exclusive)
482
510
  return value < this.end;
@@ -496,13 +524,13 @@ var Ajax = {
496
524
  function() {return new XMLHttpRequest()}
497
525
  ) || false;
498
526
  },
499
-
527
+
500
528
  activeRequestCount: 0
501
529
  }
502
530
 
503
531
  Ajax.Responders = {
504
532
  responders: [],
505
-
533
+
506
534
  _each: function(iterator) {
507
535
  this.responders._each(iterator);
508
536
  },
@@ -511,11 +539,11 @@ Ajax.Responders = {
511
539
  if (!this.include(responderToAdd))
512
540
  this.responders.push(responderToAdd);
513
541
  },
514
-
542
+
515
543
  unregister: function(responderToRemove) {
516
544
  this.responders = this.responders.without(responderToRemove);
517
545
  },
518
-
546
+
519
547
  dispatch: function(callback, request, transport, json) {
520
548
  this.each(function(responder) {
521
549
  if (responder[callback] && typeof responder[callback] == 'function') {
@@ -534,7 +562,7 @@ Ajax.Responders.register({
534
562
  onCreate: function() {
535
563
  Ajax.activeRequestCount++;
536
564
  },
537
-
565
+
538
566
  onComplete: function() {
539
567
  Ajax.activeRequestCount--;
540
568
  }
@@ -553,7 +581,7 @@ Ajax.Base.prototype = {
553
581
 
554
582
  responseIsSuccess: function() {
555
583
  return this.transport.status == undefined
556
- || this.transport.status == 0
584
+ || this.transport.status == 0
557
585
  || (this.transport.status >= 200 && this.transport.status < 300);
558
586
  },
559
587
 
@@ -563,7 +591,7 @@ Ajax.Base.prototype = {
563
591
  }
564
592
 
565
593
  Ajax.Request = Class.create();
566
- Ajax.Request.Events =
594
+ Ajax.Request.Events =
567
595
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
568
596
 
569
597
  Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
@@ -579,12 +607,12 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
579
607
 
580
608
  try {
581
609
  this.url = url;
582
- if (this.options.method == 'get')
583
- this.url += '?' + parameters;
584
-
610
+ if (this.options.method == 'get' && parameters.length > 0)
611
+ this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
612
+
585
613
  Ajax.Responders.dispatch('onCreate', this, this.transport);
586
-
587
- this.transport.open(this.options.method, this.url,
614
+
615
+ this.transport.open(this.options.method, this.url,
588
616
  this.options.asynchronous);
589
617
 
590
618
  if (this.options.asynchronous) {
@@ -598,21 +626,23 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
598
626
  this.transport.send(this.options.method == 'post' ? body : null);
599
627
 
600
628
  } catch (e) {
629
+ (this.options.onException || Prototype.emptyFunction)(this, e);
630
+ Ajax.Responders.dispatch('onException', this, e);
601
631
  }
602
632
  },
603
633
 
604
634
  setRequestHeaders: function() {
605
- var requestHeaders =
635
+ var requestHeaders =
606
636
  ['X-Requested-With', 'XMLHttpRequest',
607
637
  'X-Prototype-Version', Prototype.Version];
608
638
 
609
639
  if (this.options.method == 'post') {
610
- requestHeaders.push('Content-type',
640
+ requestHeaders.push('Content-type',
611
641
  'application/x-www-form-urlencoded');
612
642
 
613
643
  /* Force "Connection: close" for Mozilla browsers to work around
614
644
  * a bug where XMLHttpReqeuest sends an incorrect Content-length
615
- * header. See Mozilla Bugzilla #246651.
645
+ * header. See Mozilla Bugzilla #246651.
616
646
  */
617
647
  if (this.transport.overrideMimeType)
618
648
  requestHeaders.push('Connection', 'close');
@@ -630,7 +660,7 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
630
660
  if (readyState != 1)
631
661
  this.respondToReadyState(this.transport.readyState);
632
662
  },
633
-
663
+
634
664
  evalJSON: function() {
635
665
  try {
636
666
  var json = this.transport.getResponseHeader('X-JSON'), object;
@@ -719,7 +749,7 @@ Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
719
749
  this.onComplete = this.options.onComplete;
720
750
 
721
751
  this.frequency = (this.options.frequency || 2);
722
- this.decay = 1;
752
+ this.decay = (this.options.decay || 1);
723
753
 
724
754
  this.updater = {};
725
755
  this.container = container;
@@ -736,17 +766,17 @@ Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
736
766
  stop: function() {
737
767
  this.updater.onComplete = undefined;
738
768
  clearTimeout(this.timer);
739
- (this.onComplete || Ajax.emptyFunction).apply(this, arguments);
769
+ (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
740
770
  },
741
771
 
742
772
  updateComplete: function(request) {
743
773
  if (this.options.decay) {
744
- this.decay = (request.responseText == this.lastText ?
774
+ this.decay = (request.responseText == this.lastText ?
745
775
  this.decay * this.options.decay : 1);
746
776
 
747
777
  this.lastText = request.responseText;
748
778
  }
749
- this.timer = setTimeout(this.onTimerEvent.bind(this),
779
+ this.timer = setTimeout(this.onTimerEvent.bind(this),
750
780
  this.decay * this.frequency * 1000);
751
781
  },
752
782
 
@@ -754,11 +784,10 @@ Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
754
784
  this.updater = new Ajax.Updater(this.container, this.url, this.options);
755
785
  }
756
786
  });
757
-
758
787
  document.getElementsByClassName = function(className, parentElement) {
759
- var children = (document.body || $(parentElement)).getElementsByTagName('*');
788
+ var children = ($(parentElement) || document.body).getElementsByTagName('*');
760
789
  return $A(children).inject([], function(elements, child) {
761
- if (Element.hasClassName(child, className))
790
+ if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
762
791
  elements.push(child);
763
792
  return elements;
764
793
  });
@@ -774,11 +803,11 @@ Object.extend(Element, {
774
803
  visible: function(element) {
775
804
  return $(element).style.display != 'none';
776
805
  },
777
-
806
+
778
807
  toggle: function() {
779
808
  for (var i = 0; i < arguments.length; i++) {
780
809
  var element = $(arguments[i]);
781
- Element[Element.visible(element) ? 'show' : 'hide'](element);
810
+ Element[Element.visible(element) ? 'hide' : 'show'](element);
782
811
  }
783
812
  },
784
813
 
@@ -788,7 +817,7 @@ Object.extend(Element, {
788
817
  element.style.display = 'none';
789
818
  }
790
819
  },
791
-
820
+
792
821
  show: function() {
793
822
  for (var i = 0; i < arguments.length; i++) {
794
823
  var element = $(arguments[i]);
@@ -800,12 +829,12 @@ Object.extend(Element, {
800
829
  element = $(element);
801
830
  element.parentNode.removeChild(element);
802
831
  },
803
-
832
+
804
833
  getHeight: function(element) {
805
834
  element = $(element);
806
- return element.offsetHeight;
835
+ return element.offsetHeight;
807
836
  },
808
-
837
+
809
838
  classNames: function(element) {
810
839
  return new Element.ClassNames(element);
811
840
  },
@@ -824,26 +853,107 @@ Object.extend(Element, {
824
853
  if (!(element = $(element))) return;
825
854
  return Element.classNames(element).remove(className);
826
855
  },
827
-
856
+
828
857
  // removes whitespace-only text node children
829
858
  cleanWhitespace: function(element) {
830
859
  element = $(element);
831
860
  for (var i = 0; i < element.childNodes.length; i++) {
832
861
  var node = element.childNodes[i];
833
- if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
862
+ if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
834
863
  Element.remove(node);
835
864
  }
836
865
  },
837
-
866
+
838
867
  empty: function(element) {
839
868
  return $(element).innerHTML.match(/^\s*$/);
840
869
  },
841
-
870
+
842
871
  scrollTo: function(element) {
843
872
  element = $(element);
844
873
  var x = element.x ? element.x : element.offsetLeft,
845
874
  y = element.y ? element.y : element.offsetTop;
846
875
  window.scrollTo(x, y);
876
+ },
877
+
878
+ getStyle: function(element, style) {
879
+ element = $(element);
880
+ var value = element.style[style.camelize()];
881
+ if (!value) {
882
+ if (document.defaultView && document.defaultView.getComputedStyle) {
883
+ var css = document.defaultView.getComputedStyle(element, null);
884
+ value = css ? css.getPropertyValue(style) : null;
885
+ } else if (element.currentStyle) {
886
+ value = element.currentStyle[style.camelize()];
887
+ }
888
+ }
889
+
890
+ if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
891
+ if (Element.getStyle(element, 'position') == 'static') value = 'auto';
892
+
893
+ return value == 'auto' ? null : value;
894
+ },
895
+
896
+ getDimensions: function(element) {
897
+ element = $(element);
898
+ if (Element.getStyle(element, 'display') != 'none')
899
+ return {width: element.offsetWidth, height: element.offsetHeight};
900
+
901
+ // All *Width and *Height properties give 0 on elements with display none,
902
+ // so enable the element temporarily
903
+ var els = element.style;
904
+ var originalVisibility = els.visibility;
905
+ var originalPosition = els.position;
906
+ els.visibility = 'hidden';
907
+ els.position = 'absolute';
908
+ els.display = '';
909
+ var originalWidth = element.clientWidth;
910
+ var originalHeight = element.clientHeight;
911
+ els.display = 'none';
912
+ els.position = originalPosition;
913
+ els.visibility = originalVisibility;
914
+ return {width: originalWidth, height: originalHeight};
915
+ },
916
+
917
+ makePositioned: function(element) {
918
+ element = $(element);
919
+ var pos = Element.getStyle(element, 'position');
920
+ if (pos == 'static' || !pos) {
921
+ element._madePositioned = true;
922
+ element.style.position = 'relative';
923
+ // Opera returns the offset relative to the positioning context, when an
924
+ // element is position relative but top and left have not been defined
925
+ if (window.opera) {
926
+ element.style.top = 0;
927
+ element.style.left = 0;
928
+ }
929
+ }
930
+ },
931
+
932
+ undoPositioned: function(element) {
933
+ element = $(element);
934
+ if (element._madePositioned) {
935
+ element._madePositioned = undefined;
936
+ element.style.position =
937
+ element.style.top =
938
+ element.style.left =
939
+ element.style.bottom =
940
+ element.style.right = '';
941
+ }
942
+ },
943
+
944
+ makeClipping: function(element) {
945
+ element = $(element);
946
+ if (element._overflow) return;
947
+ element._overflow = element.style.overflow;
948
+ if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
949
+ element.style.overflow = 'hidden';
950
+ },
951
+
952
+ undoClipping: function(element) {
953
+ element = $(element);
954
+ if (element._overflow) return;
955
+ element.style.overflow = element._overflow;
956
+ element._overflow = undefined;
847
957
  }
848
958
  });
849
959
 
@@ -860,14 +970,13 @@ Abstract.Insertion.prototype = {
860
970
  initialize: function(element, content) {
861
971
  this.element = $(element);
862
972
  this.content = content;
863
-
973
+
864
974
  if (this.adjacency && this.element.insertAdjacentHTML) {
865
975
  try {
866
976
  this.element.insertAdjacentHTML(this.adjacency, this.content);
867
977
  } catch (e) {
868
978
  if (this.element.tagName.toLowerCase() == 'tbody') {
869
- this.fragment = this.contentFromAnonymousTable();
870
- this.insertContent();
979
+ this.insertContent(this.contentFromAnonymousTable());
871
980
  } else {
872
981
  throw e;
873
982
  }
@@ -875,15 +984,14 @@ Abstract.Insertion.prototype = {
875
984
  } else {
876
985
  this.range = this.element.ownerDocument.createRange();
877
986
  if (this.initializeRange) this.initializeRange();
878
- this.fragment = this.range.createContextualFragment(this.content);
879
- this.insertContent();
987
+ this.insertContent([this.range.createContextualFragment(this.content)]);
880
988
  }
881
989
  },
882
-
990
+
883
991
  contentFromAnonymousTable: function() {
884
992
  var div = document.createElement('div');
885
993
  div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
886
- return div.childNodes[0].childNodes[0].childNodes[0];
994
+ return $A(div.childNodes[0].childNodes[0].childNodes);
887
995
  }
888
996
  }
889
997
 
@@ -894,9 +1002,11 @@ Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin')
894
1002
  initializeRange: function() {
895
1003
  this.range.setStartBefore(this.element);
896
1004
  },
897
-
898
- insertContent: function() {
899
- this.element.parentNode.insertBefore(this.fragment, this.element);
1005
+
1006
+ insertContent: function(fragments) {
1007
+ fragments.each((function(fragment) {
1008
+ this.element.parentNode.insertBefore(fragment, this.element);
1009
+ }).bind(this));
900
1010
  }
901
1011
  });
902
1012
 
@@ -906,9 +1016,11 @@ Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
906
1016
  this.range.selectNodeContents(this.element);
907
1017
  this.range.collapse(true);
908
1018
  },
909
-
910
- insertContent: function() {
911
- this.element.insertBefore(this.fragment, this.element.firstChild);
1019
+
1020
+ insertContent: function(fragments) {
1021
+ fragments.reverse().each((function(fragment) {
1022
+ this.element.insertBefore(fragment, this.element.firstChild);
1023
+ }).bind(this));
912
1024
  }
913
1025
  });
914
1026
 
@@ -918,9 +1030,11 @@ Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'),
918
1030
  this.range.selectNodeContents(this.element);
919
1031
  this.range.collapse(this.element);
920
1032
  },
921
-
922
- insertContent: function() {
923
- this.element.appendChild(this.fragment);
1033
+
1034
+ insertContent: function(fragments) {
1035
+ fragments.each((function(fragment) {
1036
+ this.element.appendChild(fragment);
1037
+ }).bind(this));
924
1038
  }
925
1039
  });
926
1040
 
@@ -929,10 +1043,12 @@ Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
929
1043
  initializeRange: function() {
930
1044
  this.range.setStartAfter(this.element);
931
1045
  },
932
-
933
- insertContent: function() {
934
- this.element.parentNode.insertBefore(this.fragment,
935
- this.element.nextSibling);
1046
+
1047
+ insertContent: function(fragments) {
1048
+ fragments.each((function(fragment) {
1049
+ this.element.parentNode.insertBefore(fragment,
1050
+ this.element.nextSibling);
1051
+ }).bind(this));
936
1052
  }
937
1053
  });
938
1054
 
@@ -949,30 +1065,29 @@ Element.ClassNames.prototype = {
949
1065
  return name.length > 0;
950
1066
  })._each(iterator);
951
1067
  },
952
-
1068
+
953
1069
  set: function(className) {
954
1070
  this.element.className = className;
955
1071
  },
956
-
1072
+
957
1073
  add: function(classNameToAdd) {
958
1074
  if (this.include(classNameToAdd)) return;
959
1075
  this.set(this.toArray().concat(classNameToAdd).join(' '));
960
1076
  },
961
-
1077
+
962
1078
  remove: function(classNameToRemove) {
963
1079
  if (!this.include(classNameToRemove)) return;
964
1080
  this.set(this.select(function(className) {
965
1081
  return className != classNameToRemove;
966
1082
  }));
967
1083
  },
968
-
1084
+
969
1085
  toString: function() {
970
1086
  return this.toArray().join(' ');
971
1087
  }
972
1088
  }
973
1089
 
974
1090
  Object.extend(Element.ClassNames.prototype, Enumerable);
975
-
976
1091
  var Field = {
977
1092
  clear: function() {
978
1093
  for (var i = 0; i < arguments.length; i++)
@@ -982,17 +1097,17 @@ var Field = {
982
1097
  focus: function(element) {
983
1098
  $(element).focus();
984
1099
  },
985
-
1100
+
986
1101
  present: function() {
987
1102
  for (var i = 0; i < arguments.length; i++)
988
1103
  if ($(arguments[i]).value == '') return false;
989
1104
  return true;
990
1105
  },
991
-
1106
+
992
1107
  select: function(element) {
993
1108
  $(element).select();
994
1109
  },
995
-
1110
+
996
1111
  activate: function(element) {
997
1112
  $(element).focus();
998
1113
  $(element).select();
@@ -1005,18 +1120,18 @@ var Form = {
1005
1120
  serialize: function(form) {
1006
1121
  var elements = Form.getElements($(form));
1007
1122
  var queryComponents = new Array();
1008
-
1123
+
1009
1124
  for (var i = 0; i < elements.length; i++) {
1010
1125
  var queryComponent = Form.Element.serialize(elements[i]);
1011
1126
  if (queryComponent)
1012
1127
  queryComponents.push(queryComponent);
1013
1128
  }
1014
-
1129
+
1015
1130
  return queryComponents.join('&');
1016
1131
  },
1017
-
1132
+
1018
1133
  getElements: function(form) {
1019
- var form = $(form);
1134
+ form = $(form);
1020
1135
  var elements = new Array();
1021
1136
 
1022
1137
  for (tagName in Form.Element.Serializers) {
@@ -1026,19 +1141,19 @@ var Form = {
1026
1141
  }
1027
1142
  return elements;
1028
1143
  },
1029
-
1144
+
1030
1145
  getInputs: function(form, typeName, name) {
1031
- var form = $(form);
1146
+ form = $(form);
1032
1147
  var inputs = form.getElementsByTagName('input');
1033
-
1148
+
1034
1149
  if (!typeName && !name)
1035
1150
  return inputs;
1036
-
1151
+
1037
1152
  var matchingInputs = new Array();
1038
1153
  for (var i = 0; i < inputs.length; i++) {
1039
1154
  var input = inputs[i];
1040
1155
  if ((typeName && input.type != typeName) ||
1041
- (name && input.name != name))
1156
+ (name && input.name != name))
1042
1157
  continue;
1043
1158
  matchingInputs.push(input);
1044
1159
  }
@@ -1064,7 +1179,7 @@ var Form = {
1064
1179
  },
1065
1180
 
1066
1181
  focusFirstElement: function(form) {
1067
- var form = $(form);
1182
+ form = $(form);
1068
1183
  var elements = Form.getElements(form);
1069
1184
  for (var i = 0; i < elements.length; i++) {
1070
1185
  var element = elements[i];
@@ -1082,21 +1197,21 @@ var Form = {
1082
1197
 
1083
1198
  Form.Element = {
1084
1199
  serialize: function(element) {
1085
- var element = $(element);
1200
+ element = $(element);
1086
1201
  var method = element.tagName.toLowerCase();
1087
1202
  var parameter = Form.Element.Serializers[method](element);
1088
-
1203
+
1089
1204
  if (parameter)
1090
- return encodeURIComponent(parameter[0]) + '=' +
1091
- encodeURIComponent(parameter[1]);
1205
+ return encodeURIComponent(parameter[0]) + '=' +
1206
+ encodeURIComponent(parameter[1]);
1092
1207
  },
1093
-
1208
+
1094
1209
  getValue: function(element) {
1095
- var element = $(element);
1210
+ element = $(element);
1096
1211
  var method = element.tagName.toLowerCase();
1097
1212
  var parameter = Form.Element.Serializers[method](element);
1098
-
1099
- if (parameter)
1213
+
1214
+ if (parameter)
1100
1215
  return parameter[1];
1101
1216
  }
1102
1217
  }
@@ -1109,7 +1224,7 @@ Form.Element.Serializers = {
1109
1224
  case 'password':
1110
1225
  case 'text':
1111
1226
  return Form.Element.Serializers.textarea(element);
1112
- case 'checkbox':
1227
+ case 'checkbox':
1113
1228
  case 'radio':
1114
1229
  return Form.Element.Serializers.inputSelector(element);
1115
1230
  }
@@ -1124,12 +1239,12 @@ Form.Element.Serializers = {
1124
1239
  textarea: function(element) {
1125
1240
  return [element.name, element.value];
1126
1241
  },
1127
-
1242
+
1128
1243
  select: function(element) {
1129
- return Form.Element.Serializers[element.type == 'select-one' ?
1244
+ return Form.Element.Serializers[element.type == 'select-one' ?
1130
1245
  'selectOne' : 'selectMany'](element);
1131
1246
  },
1132
-
1247
+
1133
1248
  selectOne: function(element) {
1134
1249
  var value = '', opt, index = element.selectedIndex;
1135
1250
  if (index >= 0) {
@@ -1140,7 +1255,7 @@ Form.Element.Serializers = {
1140
1255
  }
1141
1256
  return [element.name, value];
1142
1257
  },
1143
-
1258
+
1144
1259
  selectMany: function(element) {
1145
1260
  var value = new Array();
1146
1261
  for (var i = 0; i < element.length; i++) {
@@ -1168,15 +1283,15 @@ Abstract.TimedObserver.prototype = {
1168
1283
  this.frequency = frequency;
1169
1284
  this.element = $(element);
1170
1285
  this.callback = callback;
1171
-
1286
+
1172
1287
  this.lastValue = this.getValue();
1173
1288
  this.registerCallback();
1174
1289
  },
1175
-
1290
+
1176
1291
  registerCallback: function() {
1177
1292
  setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
1178
1293
  },
1179
-
1294
+
1180
1295
  onTimerEvent: function() {
1181
1296
  var value = this.getValue();
1182
1297
  if (this.lastValue != value) {
@@ -1207,14 +1322,14 @@ Abstract.EventObserver.prototype = {
1207
1322
  initialize: function(element, callback) {
1208
1323
  this.element = $(element);
1209
1324
  this.callback = callback;
1210
-
1325
+
1211
1326
  this.lastValue = this.getValue();
1212
1327
  if (this.element.tagName.toLowerCase() == 'form')
1213
1328
  this.registerFormCallbacks();
1214
1329
  else
1215
1330
  this.registerCallback(this.element);
1216
1331
  },
1217
-
1332
+
1218
1333
  onElementEvent: function() {
1219
1334
  var value = this.getValue();
1220
1335
  if (this.lastValue != value) {
@@ -1222,22 +1337,22 @@ Abstract.EventObserver.prototype = {
1222
1337
  this.lastValue = value;
1223
1338
  }
1224
1339
  },
1225
-
1340
+
1226
1341
  registerFormCallbacks: function() {
1227
1342
  var elements = Form.getElements(this.element);
1228
1343
  for (var i = 0; i < elements.length; i++)
1229
1344
  this.registerCallback(elements[i]);
1230
1345
  },
1231
-
1346
+
1232
1347
  registerCallback: function(element) {
1233
1348
  if (element.type) {
1234
1349
  switch (element.type.toLowerCase()) {
1235
- case 'checkbox':
1350
+ case 'checkbox':
1236
1351
  case 'radio':
1237
1352
  element.target = this;
1238
1353
  element.prev_onclick = element.onclick || Prototype.emptyFunction;
1239
1354
  element.onclick = function() {
1240
- this.prev_onclick();
1355
+ this.prev_onclick();
1241
1356
  this.target.onElementEvent();
1242
1357
  }
1243
1358
  break;
@@ -1249,12 +1364,12 @@ Abstract.EventObserver.prototype = {
1249
1364
  element.target = this;
1250
1365
  element.prev_onchange = element.onchange || Prototype.emptyFunction;
1251
1366
  element.onchange = function() {
1252
- this.prev_onchange();
1367
+ this.prev_onchange();
1253
1368
  this.target.onElementEvent();
1254
1369
  }
1255
1370
  break;
1256
1371
  }
1257
- }
1372
+ }
1258
1373
  }
1259
1374
  }
1260
1375
 
@@ -1271,8 +1386,6 @@ Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
1271
1386
  return Form.serialize(this.element);
1272
1387
  }
1273
1388
  });
1274
-
1275
-
1276
1389
  if (!window.Event) {
1277
1390
  var Event = new Object();
1278
1391
  }
@@ -1298,19 +1411,19 @@ Object.extend(Event, {
1298
1411
  },
1299
1412
 
1300
1413
  pointerX: function(event) {
1301
- return event.pageX || (event.clientX +
1414
+ return event.pageX || (event.clientX +
1302
1415
  (document.documentElement.scrollLeft || document.body.scrollLeft));
1303
1416
  },
1304
1417
 
1305
1418
  pointerY: function(event) {
1306
- return event.pageY || (event.clientY +
1419
+ return event.pageY || (event.clientY +
1307
1420
  (document.documentElement.scrollTop || document.body.scrollTop));
1308
1421
  },
1309
1422
 
1310
1423
  stop: function(event) {
1311
- if (event.preventDefault) {
1312
- event.preventDefault();
1313
- event.stopPropagation();
1424
+ if (event.preventDefault) {
1425
+ event.preventDefault();
1426
+ event.stopPropagation();
1314
1427
  } else {
1315
1428
  event.returnValue = false;
1316
1429
  event.cancelBubble = true;
@@ -1328,7 +1441,7 @@ Object.extend(Event, {
1328
1441
  },
1329
1442
 
1330
1443
  observers: false,
1331
-
1444
+
1332
1445
  _observeAndCache: function(element, name, observer, useCapture) {
1333
1446
  if (!this.observers) this.observers = [];
1334
1447
  if (element.addEventListener) {
@@ -1339,7 +1452,7 @@ Object.extend(Event, {
1339
1452
  element.attachEvent('on' + name, observer);
1340
1453
  }
1341
1454
  },
1342
-
1455
+
1343
1456
  unloadCache: function() {
1344
1457
  if (!Event.observers) return;
1345
1458
  for (var i = 0; i < Event.observers.length; i++) {
@@ -1352,24 +1465,24 @@ Object.extend(Event, {
1352
1465
  observe: function(element, name, observer, useCapture) {
1353
1466
  var element = $(element);
1354
1467
  useCapture = useCapture || false;
1355
-
1468
+
1356
1469
  if (name == 'keypress' &&
1357
1470
  (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
1358
1471
  || element.attachEvent))
1359
1472
  name = 'keydown';
1360
-
1473
+
1361
1474
  this._observeAndCache(element, name, observer, useCapture);
1362
1475
  },
1363
1476
 
1364
1477
  stopObserving: function(element, name, observer, useCapture) {
1365
1478
  var element = $(element);
1366
1479
  useCapture = useCapture || false;
1367
-
1480
+
1368
1481
  if (name == 'keypress' &&
1369
1482
  (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
1370
1483
  || element.detachEvent))
1371
1484
  name = 'keydown';
1372
-
1485
+
1373
1486
  if (element.removeEventListener) {
1374
1487
  element.removeEventListener(name, observer, useCapture);
1375
1488
  } else if (element.detachEvent) {
@@ -1380,24 +1493,22 @@ Object.extend(Event, {
1380
1493
 
1381
1494
  /* prevent memory leaks in IE */
1382
1495
  Event.observe(window, 'unload', Event.unloadCache, false);
1383
-
1384
1496
  var Position = {
1385
-
1386
1497
  // set to true if needed, warning: firefox performance problems
1387
1498
  // NOT neeeded for page scrolling, only if draggable contained in
1388
1499
  // scrollable elements
1389
- includeScrollOffsets: false,
1500
+ includeScrollOffsets: false,
1390
1501
 
1391
1502
  // must be called before calling withinIncludingScrolloffset, every time the
1392
1503
  // page is scrolled
1393
1504
  prepare: function() {
1394
- this.deltaX = window.pageXOffset
1395
- || document.documentElement.scrollLeft
1396
- || document.body.scrollLeft
1505
+ this.deltaX = window.pageXOffset
1506
+ || document.documentElement.scrollLeft
1507
+ || document.body.scrollLeft
1397
1508
  || 0;
1398
- this.deltaY = window.pageYOffset
1399
- || document.documentElement.scrollTop
1400
- || document.body.scrollTop
1509
+ this.deltaY = window.pageYOffset
1510
+ || document.documentElement.scrollTop
1511
+ || document.body.scrollTop
1401
1512
  || 0;
1402
1513
  },
1403
1514
 
@@ -1405,7 +1516,7 @@ var Position = {
1405
1516
  var valueT = 0, valueL = 0;
1406
1517
  do {
1407
1518
  valueT += element.scrollTop || 0;
1408
- valueL += element.scrollLeft || 0;
1519
+ valueL += element.scrollLeft || 0;
1409
1520
  element = element.parentNode;
1410
1521
  } while (element);
1411
1522
  return [valueL, valueT];
@@ -1421,6 +1532,31 @@ var Position = {
1421
1532
  return [valueL, valueT];
1422
1533
  },
1423
1534
 
1535
+ positionedOffset: function(element) {
1536
+ var valueT = 0, valueL = 0;
1537
+ do {
1538
+ valueT += element.offsetTop || 0;
1539
+ valueL += element.offsetLeft || 0;
1540
+ element = element.offsetParent;
1541
+ if (element) {
1542
+ p = Element.getStyle(element, 'position');
1543
+ if (p == 'relative' || p == 'absolute') break;
1544
+ }
1545
+ } while (element);
1546
+ return [valueL, valueT];
1547
+ },
1548
+
1549
+ offsetParent: function(element) {
1550
+ if (element.offsetParent) return element.offsetParent;
1551
+ if (element == document.body) return element;
1552
+
1553
+ while ((element = element.parentNode) && element != document.body)
1554
+ if (Element.getStyle(element, 'position') != 'static')
1555
+ return element;
1556
+
1557
+ return document.body;
1558
+ },
1559
+
1424
1560
  // caches x/y coordinate pair to use with overlap
1425
1561
  within: function(element, x, y) {
1426
1562
  if (this.includeScrollOffsets)
@@ -1431,7 +1567,7 @@ var Position = {
1431
1567
 
1432
1568
  return (y >= this.offset[1] &&
1433
1569
  y < this.offset[1] + element.offsetHeight &&
1434
- x >= this.offset[0] &&
1570
+ x >= this.offset[0] &&
1435
1571
  x < this.offset[0] + element.offsetWidth);
1436
1572
  },
1437
1573
 
@@ -1444,18 +1580,18 @@ var Position = {
1444
1580
 
1445
1581
  return (this.ycomp >= this.offset[1] &&
1446
1582
  this.ycomp < this.offset[1] + element.offsetHeight &&
1447
- this.xcomp >= this.offset[0] &&
1583
+ this.xcomp >= this.offset[0] &&
1448
1584
  this.xcomp < this.offset[0] + element.offsetWidth);
1449
1585
  },
1450
1586
 
1451
1587
  // within must be called directly before
1452
- overlap: function(mode, element) {
1453
- if (!mode) return 0;
1454
- if (mode == 'vertical')
1455
- return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
1588
+ overlap: function(mode, element) {
1589
+ if (!mode) return 0;
1590
+ if (mode == 'vertical')
1591
+ return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
1456
1592
  element.offsetHeight;
1457
1593
  if (mode == 'horizontal')
1458
- return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
1594
+ return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
1459
1595
  element.offsetWidth;
1460
1596
  },
1461
1597
 
@@ -1468,5 +1604,123 @@ var Position = {
1468
1604
  target.style.left = offsets[0] + 'px';
1469
1605
  target.style.width = source.offsetWidth + 'px';
1470
1606
  target.style.height = source.offsetHeight + 'px';
1607
+ },
1608
+
1609
+ page: function(forElement) {
1610
+ var valueT = 0, valueL = 0;
1611
+
1612
+ var element = forElement;
1613
+ do {
1614
+ valueT += element.offsetTop || 0;
1615
+ valueL += element.offsetLeft || 0;
1616
+
1617
+ // Safari fix
1618
+ if (element.offsetParent==document.body)
1619
+ if (Element.getStyle(element,'position')=='absolute') break;
1620
+
1621
+ } while (element = element.offsetParent);
1622
+
1623
+ element = forElement;
1624
+ do {
1625
+ valueT -= element.scrollTop || 0;
1626
+ valueL -= element.scrollLeft || 0;
1627
+ } while (element = element.parentNode);
1628
+
1629
+ return [valueL, valueT];
1630
+ },
1631
+
1632
+ clone: function(source, target) {
1633
+ var options = Object.extend({
1634
+ setLeft: true,
1635
+ setTop: true,
1636
+ setWidth: true,
1637
+ setHeight: true,
1638
+ offsetTop: 0,
1639
+ offsetLeft: 0
1640
+ }, arguments[2] || {})
1641
+
1642
+ // find page position of source
1643
+ source = $(source);
1644
+ var p = Position.page(source);
1645
+
1646
+ // find coordinate system to use
1647
+ target = $(target);
1648
+ var delta = [0, 0];
1649
+ var parent = null;
1650
+ // delta [0,0] will do fine with position: fixed elements,
1651
+ // position:absolute needs offsetParent deltas
1652
+ if (Element.getStyle(target,'position') == 'absolute') {
1653
+ parent = Position.offsetParent(target);
1654
+ delta = Position.page(parent);
1655
+ }
1656
+
1657
+ // correct by body offsets (fixes Safari)
1658
+ if (parent == document.body) {
1659
+ delta[0] -= document.body.offsetLeft;
1660
+ delta[1] -= document.body.offsetTop;
1661
+ }
1662
+
1663
+ // set position
1664
+ if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
1665
+ if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
1666
+ if(options.setWidth) target.style.width = source.offsetWidth + 'px';
1667
+ if(options.setHeight) target.style.height = source.offsetHeight + 'px';
1668
+ },
1669
+
1670
+ absolutize: function(element) {
1671
+ element = $(element);
1672
+ if (element.style.position == 'absolute') return;
1673
+ Position.prepare();
1674
+
1675
+ var offsets = Position.positionedOffset(element);
1676
+ var top = offsets[1];
1677
+ var left = offsets[0];
1678
+ var width = element.clientWidth;
1679
+ var height = element.clientHeight;
1680
+
1681
+ element._originalLeft = left - parseFloat(element.style.left || 0);
1682
+ element._originalTop = top - parseFloat(element.style.top || 0);
1683
+ element._originalWidth = element.style.width;
1684
+ element._originalHeight = element.style.height;
1685
+
1686
+ element.style.position = 'absolute';
1687
+ element.style.top = top + 'px';;
1688
+ element.style.left = left + 'px';;
1689
+ element.style.width = width + 'px';;
1690
+ element.style.height = height + 'px';;
1691
+ },
1692
+
1693
+ relativize: function(element) {
1694
+ element = $(element);
1695
+ if (element.style.position == 'relative') return;
1696
+ Position.prepare();
1697
+
1698
+ element.style.position = 'relative';
1699
+ var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
1700
+ var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
1701
+
1702
+ element.style.top = top + 'px';
1703
+ element.style.left = left + 'px';
1704
+ element.style.height = element._originalHeight;
1705
+ element.style.width = element._originalWidth;
1471
1706
  }
1472
1707
  }
1708
+
1709
+ // Safari returns margins on body which is incorrect if the child is absolutely
1710
+ // positioned. For performance reasons, redefine Position.cumulativeOffset for
1711
+ // KHTML/WebKit only.
1712
+ if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
1713
+ Position.cumulativeOffset = function(element) {
1714
+ var valueT = 0, valueL = 0;
1715
+ do {
1716
+ valueT += element.offsetTop || 0;
1717
+ valueL += element.offsetLeft || 0;
1718
+ if (element.offsetParent == document.body)
1719
+ if (Element.getStyle(element, 'position') == 'absolute') break;
1720
+
1721
+ element = element.offsetParent;
1722
+ } while (element);
1723
+
1724
+ return [valueL, valueT];
1725
+ }
1726
+ }