nitro 0.24.0 → 0.25.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }