Project

General

Profile

1
/*  Prototype JavaScript framework, version 1.4.0
2
 *  (c) 2005 Sam Stephenson <sam@conio.net>
3
 *
4
 *  Prototype is freely distributable under the terms of an MIT-style license.
5
 *  For details, see the Prototype web site: http://prototype.conio.net/
6
 *
7
/*--------------------------------------------------------------------------*/
8

    
9
var Prototype = {
10
  Version: '1.4.0',
11
  ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
12

    
13
  emptyFunction: function() {},
14
  K: function(x) {return x}
15
}
16

    
17
var Class = {
18
  create: function() {
19
    return function() {
20
      this.initialize.apply(this, arguments);
21
    }
22
  }
23
}
24

    
25
var Abstract = new Object();
26

    
27
Object.extend = function(destination, source) {
28
  for (property in source) {
29
    destination[property] = source[property];
30
  }
31
  return destination;
32
}
33

    
34
Object.inspect = function(object) {
35
  try {
36
    if (object == undefined) return 'undefined';
37
    if (object == null) return 'null';
38
    return object.inspect ? object.inspect() : object.toString();
39
  } catch (e) {
40
    if (e instanceof RangeError) return '...';
41
    throw e;
42
  }
43
}
44

    
45
Function.prototype.bind = function() {
46
  var __method = this, args = $A(arguments), object = args.shift();
47
  return function() {
48
    return __method.apply(object, args.concat($A(arguments)));
49
  }
50
}
51

    
52
Function.prototype.bindAsEventListener = function(object) {
53
  var __method = this;
54
  return function(event) {
55
    return __method.call(object, event || window.event);
56
  }
57
}
58

    
59
Object.extend(Number.prototype, {
60
  toColorPart: function() {
61
    var digits = this.toString(16);
62
    if (this < 16) return '0' + digits;
63
    return digits;
64
  },
65

    
66
  succ: function() {
67
    return this + 1;
68
  },
69

    
70
  times: function(iterator) {
71
    $R(0, this, true).each(iterator);
72
    return this;
73
  }
74
});
75

    
76
var Try = {
77
  these: function() {
78
    var returnValue;
79

    
80
    for (var i = 0; i < arguments.length; i++) {
81
      var lambda = arguments[i];
82
      try {
83
        returnValue = lambda();
84
        break;
85
      } catch (e) {}
86
    }
87

    
88
    return returnValue;
89
  }
90
}
91

    
92
/*--------------------------------------------------------------------------*/
93

    
94
var PeriodicalExecuter = Class.create();
95
PeriodicalExecuter.prototype = {
96
  initialize: function(callback, frequency) {
97
    this.callback = callback;
98
    this.frequency = frequency;
99
    this.currentlyExecuting = false;
100

    
101
    this.registerCallback();
102
  },
103

    
104
  registerCallback: function() {
105
    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
106
  },
107

    
108
  onTimerEvent: function() {
109
    if (!this.currentlyExecuting) {
110
      try {
111
        this.currentlyExecuting = true;
112
        this.callback();
113
      } finally {
114
        this.currentlyExecuting = false;
115
      }
116
    }
117
  }
118
}
119

    
120
/*--------------------------------------------------------------------------*/
121

    
122
function $() {
123
  var elements = new Array();
124

    
125
  for (var i = 0; i < arguments.length; i++) {
126
    var element = arguments[i];
127
    if (typeof element == 'string')
128
      element = document.getElementById(element);
129

    
130
    if (arguments.length == 1)
131
      return element;
132

    
133
    elements.push(element);
134
  }
135

    
136
  return elements;
137
}
138
Object.extend(String.prototype, {
139
  stripTags: function() {
140
    return this.replace(/<\/?[^>]+>/gi, '');
141
  },
142

    
143
  stripScripts: function() {
144
    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
145
  },
146

    
147
  extractScripts: function() {
148
    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
149
    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
150
    return (this.match(matchAll) || []).map(function(scriptTag) {
151
      return (scriptTag.match(matchOne) || ['', ''])[1];
152
    });
153
  },
154

    
155
  evalScripts: function() {
156
    return this.extractScripts().map(eval);
157
  },
158

    
159
  escapeHTML: function() {
160
    var div = document.createElement('div');
161
    var text = document.createTextNode(this);
162
    div.appendChild(text);
163
    return div.innerHTML;
164
  },
165

    
166
  unescapeHTML: function() {
167
    var div = document.createElement('div');
168
    div.innerHTML = this.stripTags();
169
    return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
170
  },
171

    
172
  toQueryParams: function() {
173
    var pairs = this.match(/^\??(.*)$/)[1].split('&');
174
    return pairs.inject({}, function(params, pairString) {
175
      var pair = pairString.split('=');
176
      params[pair[0]] = pair[1];
177
      return params;
178
    });
179
  },
180

    
181
  toArray: function() {
182
    return this.split('');
183
  },
184

    
185
  camelize: function() {
186
    var oStringList = this.split('-');
187
    if (oStringList.length == 1) return oStringList[0];
188

    
189
    var camelizedString = this.indexOf('-') == 0
190
      ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
191
      : oStringList[0];
192

    
193
    for (var i = 1, len = oStringList.length; i < len; i++) {
194
      var s = oStringList[i];
195
      camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
196
    }
197

    
198
    return camelizedString;
199
  },
200

    
201
  inspect: function() {
202
    return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'";
203
  }
204
});
205

    
206
String.prototype.parseQuery = String.prototype.toQueryParams;
207

    
208
var $break    = new Object();
209
var $continue = new Object();
210

    
211
var Enumerable = {
212
  each: function(iterator) {
213
    var index = 0;
214
    try {
215
      this._each(function(value) {
216
        try {
217
          iterator(value, index++);
218
        } catch (e) {
219
          if (e != $continue) throw e;
220
        }
221
      });
222
    } catch (e) {
223
      if (e != $break) throw e;
224
    }
225
  },
226

    
227
  all: function(iterator) {
228
    var result = true;
229
    this.each(function(value, index) {
230
      result = result && !!(iterator || Prototype.K)(value, index);
231
      if (!result) throw $break;
232
    });
233
    return result;
234
  },
235

    
236
  any: function(iterator) {
237
    var result = true;
238
    this.each(function(value, index) {
239
      if (result = !!(iterator || Prototype.K)(value, index))
240
        throw $break;
241
    });
242
    return result;
243
  },
244

    
245
  collect: function(iterator) {
246
    var results = [];
247
    this.each(function(value, index) {
248
      results.push(iterator(value, index));
249
    });
250
    return results;
251
  },
252

    
253
  detect: function (iterator) {
254
    var result;
255
    this.each(function(value, index) {
256
      if (iterator(value, index)) {
257
        result = value;
258
        throw $break;
259
      }
260
    });
261
    return result;
262
  },
263

    
264
  findAll: function(iterator) {
265
    var results = [];
266
    this.each(function(value, index) {
267
      if (iterator(value, index))
268
        results.push(value);
269
    });
270
    return results;
271
  },
272

    
273
  grep: function(pattern, iterator) {
274
    var results = [];
275
    this.each(function(value, index) {
276
      var stringValue = value.toString();
277
      if (stringValue.match(pattern))
278
        results.push((iterator || Prototype.K)(value, index));
279
    })
280
    return results;
281
  },
282

    
283
  include: function(object) {
284
    var found = false;
285
    this.each(function(value) {
286
      if (value == object) {
287
        found = true;
288
        throw $break;
289
      }
290
    });
291
    return found;
292
  },
293

    
294
  inject: function(memo, iterator) {
295
    this.each(function(value, index) {
296
      memo = iterator(memo, value, index);
297
    });
298
    return memo;
299
  },
300

    
301
  invoke: function(method) {
302
    var args = $A(arguments).slice(1);
303
    return this.collect(function(value) {
304
      return value[method].apply(value, args);
305
    });
306
  },
307

    
308
  max: function(iterator) {
309
    var result;
310
    this.each(function(value, index) {
311
      value = (iterator || Prototype.K)(value, index);
312
      if (value >= (result || value))
313
        result = value;
314
    });
315
    return result;
316
  },
317

    
318
  min: function(iterator) {
319
    var result;
320
    this.each(function(value, index) {
321
      value = (iterator || Prototype.K)(value, index);
322
      if (value <= (result || value))
323
        result = value;
324
    });
325
    return result;
326
  },
327

    
328
  partition: function(iterator) {
329
    var trues = [], falses = [];
330
    this.each(function(value, index) {
331
      ((iterator || Prototype.K)(value, index) ?
332
        trues : falses).push(value);
333
    });
334
    return [trues, falses];
335
  },
336

    
337
  pluck: function(property) {
338
    var results = [];
339
    this.each(function(value, index) {
340
      results.push(value[property]);
341
    });
342
    return results;
343
  },
344

    
345
  reject: function(iterator) {
346
    var results = [];
347
    this.each(function(value, index) {
348
      if (!iterator(value, index))
349
        results.push(value);
350
    });
351
    return results;
352
  },
353

    
354
  sortBy: function(iterator) {
355
    return this.collect(function(value, index) {
356
      return {value: value, criteria: iterator(value, index)};
357
    }).sort(function(left, right) {
358
      var a = left.criteria, b = right.criteria;
359
      return a < b ? -1 : a > b ? 1 : 0;
360
    }).pluck('value');
361
  },
362

    
363
  toArray: function() {
364
    return this.collect(Prototype.K);
365
  },
366

    
367
  zip: function() {
368
    var iterator = Prototype.K, args = $A(arguments);
369
    if (typeof args.last() == 'function')
370
      iterator = args.pop();
371

    
372
    var collections = [this].concat(args).map($A);
373
    return this.map(function(value, index) {
374
      iterator(value = collections.pluck(index));
375
      return value;
376
    });
377
  },
378

    
379
  inspect: function() {
380
    return '#<Enumerable:' + this.toArray().inspect() + '>';
381
  }
382
}
383

    
384
Object.extend(Enumerable, {
385
  map:     Enumerable.collect,
386
  find:    Enumerable.detect,
387
  select:  Enumerable.findAll,
388
  member:  Enumerable.include,
389
  entries: Enumerable.toArray
390
});
391
var $A = Array.from = function(iterable) {
392
  if (!iterable) return [];
393
  if (iterable.toArray) {
394
    return iterable.toArray();
395
  } else {
396
    var results = [];
397
    for (var i = 0; i < iterable.length; i++)
398
      results.push(iterable[i]);
399
    return results;
400
  }
401
}
402

    
403
Object.extend(Array.prototype, Enumerable);
404

    
405
Array.prototype._reverse = Array.prototype.reverse;
406

    
407
Object.extend(Array.prototype, {
408
  _each: function(iterator) {
409
    for (var i = 0; i < this.length; i++)
410
      iterator(this[i]);
411
  },
412

    
413
  clear: function() {
414
    this.length = 0;
415
    return this;
416
  },
417

    
418
  first: function() {
419
    return this[0];
420
  },
421

    
422
  last: function() {
423
    return this[this.length - 1];
424
  },
425

    
426
  compact: function() {
427
    return this.select(function(value) {
428
      return value != undefined || value != null;
429
    });
430
  },
431

    
432
  flatten: function() {
433
    return this.inject([], function(array, value) {
434
      return array.concat(value.constructor == Array ?
435
        value.flatten() : [value]);
436
    });
437
  },
438

    
439
  without: function() {
440
    var values = $A(arguments);
441
    return this.select(function(value) {
442
      return !values.include(value);
443
    });
444
  },
445

    
446
  indexOf: function(object) {
447
    for (var i = 0; i < this.length; i++)
448
      if (this[i] == object) return i;
449
    return -1;
450
  },
451

    
452
  reverse: function(inline) {
453
    return (inline !== false ? this : this.toArray())._reverse();
454
  },
455

    
456
  shift: function() {
457
    var result = this[0];
458
    for (var i = 0; i < this.length - 1; i++)
459
      this[i] = this[i + 1];
460
    this.length--;
461
    return result;
462
  },
463

    
464
  inspect: function() {
465
    return '[' + this.map(Object.inspect).join(', ') + ']';
466
  }
467
});
468
var Hash = {
469
  _each: function(iterator) {
470
    for (key in this) {
471
      var value = this[key];
472
      if (typeof value == 'function') continue;
473

    
474
      var pair = [key, value];
475
      pair.key = key;
476
      pair.value = value;
477
      iterator(pair);
478
    }
479
  },
480

    
481
  keys: function() {
482
    return this.pluck('key');
483
  },
484

    
485
  values: function() {
486
    return this.pluck('value');
487
  },
488

    
489
  merge: function(hash) {
490
    return $H(hash).inject($H(this), function(mergedHash, pair) {
491
      mergedHash[pair.key] = pair.value;
492
      return mergedHash;
493
    });
494
  },
495

    
496
  toQueryString: function() {
497
    return this.map(function(pair) {
498
      return pair.map(encodeURIComponent).join('=');
499
    }).join('&');
500
  },
501

    
502
  inspect: function() {
503
    return '#<Hash:{' + this.map(function(pair) {
504
      return pair.map(Object.inspect).join(': ');
505
    }).join(', ') + '}>';
506
  }
507
}
508

    
509
function $H(object) {
510
  var hash = Object.extend({}, object || {});
511
  Object.extend(hash, Enumerable);
512
  Object.extend(hash, Hash);
513
  return hash;
514
}
515
ObjectRange = Class.create();
516
Object.extend(ObjectRange.prototype, Enumerable);
517
Object.extend(ObjectRange.prototype, {
518
  initialize: function(start, end, exclusive) {
519
    this.start = start;
520
    this.end = end;
521
    this.exclusive = exclusive;
522
  },
523

    
524
  _each: function(iterator) {
525
    var value = this.start;
526
    do {
527
      iterator(value);
528
      value = value.succ();
529
    } while (this.include(value));
530
  },
531

    
532
  include: function(value) {
533
    if (value < this.start)
534
      return false;
535
    if (this.exclusive)
536
      return value < this.end;
537
    return value <= this.end;
538
  }
539
});
540

    
541
var $R = function(start, end, exclusive) {
542
  return new ObjectRange(start, end, exclusive);
543
}
544

    
545
var Ajax = {
546
  getTransport: function() {
547
    return Try.these(
548
      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
549
      function() {return new ActiveXObject('Microsoft.XMLHTTP')},
550
      function() {return new XMLHttpRequest()}
551
    ) || false;
552
  },
553

    
554
  activeRequestCount: 0
555
}
556

    
557
Ajax.Responders = {
558
  responders: [],
559

    
560
  _each: function(iterator) {
561
    this.responders._each(iterator);
562
  },
563

    
564
  register: function(responderToAdd) {
565
    if (!this.include(responderToAdd))
566
      this.responders.push(responderToAdd);
567
  },
568

    
569
  unregister: function(responderToRemove) {
570
    this.responders = this.responders.without(responderToRemove);
571
  },
572

    
573
  dispatch: function(callback, request, transport, json) {
574
    this.each(function(responder) {
575
      if (responder[callback] && typeof responder[callback] == 'function') {
576
        try {
577
          responder[callback].apply(responder, [request, transport, json]);
578
        } catch (e) {}
579
      }
580
    });
581
  }
582
};
583

    
584
Object.extend(Ajax.Responders, Enumerable);
585

    
586
Ajax.Responders.register({
587
  onCreate: function() {
588
    Ajax.activeRequestCount++;
589
  },
590

    
591
  onComplete: function() {
592
    Ajax.activeRequestCount--;
593
  }
594
});
595

    
596
Ajax.Base = function() {};
597
Ajax.Base.prototype = {
598
  setOptions: function(options) {
599
    this.options = {
600
      method:       'post',
601
      asynchronous: true,
602
      parameters:   ''
603
    }
604
    Object.extend(this.options, options || {});
605
  },
606

    
607
  responseIsSuccess: function() {
608
    return this.transport.status == undefined
609
        || this.transport.status == 0
610
        || (this.transport.status >= 200 && this.transport.status < 300);
611
  },
612

    
613
  responseIsFailure: function() {
614
    return !this.responseIsSuccess();
615
  }
616
}
617

    
618
Ajax.Request = Class.create();
619
Ajax.Request.Events =
620
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
621

    
622
Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
623
  initialize: function(url, options) {
624
    this.transport = Ajax.getTransport();
625
    this.setOptions(options);
626
    this.request(url);
627
  },
628

    
629
  request: function(url) {
630
    var parameters = this.options.parameters || '';
631
    if (parameters.length > 0) parameters += '&_=';
632

    
633
    try {
634
      this.url = url;
635
      if (this.options.method == 'get' && parameters.length > 0)
636
        this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
637

    
638
      Ajax.Responders.dispatch('onCreate', this, this.transport);
639

    
640
      this.transport.open(this.options.method, this.url,
641
        this.options.asynchronous);
642

    
643
      if (this.options.asynchronous) {
644
        this.transport.onreadystatechange = this.onStateChange.bind(this);
645
        setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
646
      }
647

    
648
      this.setRequestHeaders();
649

    
650
      var body = this.options.postBody ? this.options.postBody : parameters;
651
      this.transport.send(this.options.method == 'post' ? body : null);
652

    
653
    } catch (e) {
654
      this.dispatchException(e);
655
    }
656
  },
657

    
658
  setRequestHeaders: function() {
659
    var requestHeaders =
660
      ['X-Requested-With', 'XMLHttpRequest',
661
       'X-Prototype-Version', Prototype.Version];
662

    
663
    if (this.options.method == 'post') {
664
      requestHeaders.push('Content-type',
665
        'application/x-www-form-urlencoded');
666

    
667
      /* Force "Connection: close" for Mozilla browsers to work around
668
       * a bug where XMLHttpReqeuest sends an incorrect Content-length
669
       * header. See Mozilla Bugzilla #246651.
670
       */
671
      if (this.transport.overrideMimeType)
672
        requestHeaders.push('Connection', 'close');
673
    }
674

    
675
    if (this.options.requestHeaders)
676
      requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
677

    
678
    for (var i = 0; i < requestHeaders.length; i += 2)
679
      this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
680
  },
681

    
682
  onStateChange: function() {
683
    var readyState = this.transport.readyState;
684
    if (readyState != 1)
685
      this.respondToReadyState(this.transport.readyState);
686
  },
687

    
688
  header: function(name) {
689
    try {
690
      return this.transport.getResponseHeader(name);
691
    } catch (e) {}
692
  },
693

    
694
  evalJSON: function() {
695
    try {
696
      return eval(this.header('X-JSON'));
697
    } catch (e) {}
698
  },
699

    
700
  evalResponse: function() {
701
    try {
702
      return eval(this.transport.responseText);
703
    } catch (e) {
704
      this.dispatchException(e);
705
    }
706
  },
707

    
708
  respondToReadyState: function(readyState) {
709
    var event = Ajax.Request.Events[readyState];
710
    var transport = this.transport, json = this.evalJSON();
711

    
712
    if (event == 'Complete') {
713
      try {
714
        (this.options['on' + this.transport.status]
715
         || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
716
         || Prototype.emptyFunction)(transport, json);
717
      } catch (e) {
718
        this.dispatchException(e);
719
      }
720

    
721
      if ((this.header('Content-type') || '').match(/^text\/javascript/i))
722
        this.evalResponse();
723
    }
724

    
725
    try {
726
      (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
727
      Ajax.Responders.dispatch('on' + event, this, transport, json);
728
    } catch (e) {
729
      this.dispatchException(e);
730
    }
731

    
732
    /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
733
    if (event == 'Complete')
734
      this.transport.onreadystatechange = Prototype.emptyFunction;
735
  },
736

    
737
  dispatchException: function(exception) {
738
    (this.options.onException || Prototype.emptyFunction)(this, exception);
739
    Ajax.Responders.dispatch('onException', this, exception);
740
  }
741
});
742

    
743
Ajax.Updater = Class.create();
744

    
745
Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
746
  initialize: function(container, url, options) {
747
    this.containers = {
748
      success: container.success ? $(container.success) : $(container),
749
      failure: container.failure ? $(container.failure) :
750
        (container.success ? null : $(container))
751
    }
752

    
753
    this.transport = Ajax.getTransport();
754
    this.setOptions(options);
755

    
756
    var onComplete = this.options.onComplete || Prototype.emptyFunction;
757
    this.options.onComplete = (function(transport, object) {
758
      this.updateContent();
759
      onComplete(transport, object);
760
    }).bind(this);
761

    
762
    this.request(url);
763
  },
764

    
765
  updateContent: function() {
766
    var receiver = this.responseIsSuccess() ?
767
      this.containers.success : this.containers.failure;
768
    var response = this.transport.responseText;
769

    
770
    if (!this.options.evalScripts)
771
      response = response.stripScripts();
772

    
773
    if (receiver) {
774
      if (this.options.insertion) {
775
        new this.options.insertion(receiver, response);
776
      } else {
777
        Element.update(receiver, response);
778
      }
779
    }
780

    
781
    if (this.responseIsSuccess()) {
782
      if (this.onComplete)
783
        setTimeout(this.onComplete.bind(this), 10);
784
    }
785
  }
786
});
787

    
788
Ajax.PeriodicalUpdater = Class.create();
789
Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
790
  initialize: function(container, url, options) {
791
    this.setOptions(options);
792
    this.onComplete = this.options.onComplete;
793

    
794
    this.frequency = (this.options.frequency || 2);
795
    this.decay = (this.options.decay || 1);
796

    
797
    this.updater = {};
798
    this.container = container;
799
    this.url = url;
800

    
801
    this.start();
802
  },
803

    
804
  start: function() {
805
    this.options.onComplete = this.updateComplete.bind(this);
806
    this.onTimerEvent();
807
  },
808

    
809
  stop: function() {
810
    this.updater.onComplete = undefined;
811
    clearTimeout(this.timer);
812
    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
813
  },
814

    
815
  updateComplete: function(request) {
816
    if (this.options.decay) {
817
      this.decay = (request.responseText == this.lastText ?
818
        this.decay * this.options.decay : 1);
819

    
820
      this.lastText = request.responseText;
821
    }
822
    this.timer = setTimeout(this.onTimerEvent.bind(this),
823
      this.decay * this.frequency * 1000);
824
  },
825

    
826
  onTimerEvent: function() {
827
    this.updater = new Ajax.Updater(this.container, this.url, this.options);
828
  }
829
});
830
document.getElementsByClassName = function(className, parentElement) {
831
  var children = ($(parentElement) || document.body).getElementsByTagName('*');
832
  return $A(children).inject([], function(elements, child) {
833
    if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
834
      elements.push(child);
835
    return elements;
836
  });
837
}
838

    
839
/*--------------------------------------------------------------------------*/
840

    
841
if (!window.Element) {
842
  var Element = new Object();
843
}
844

    
845
Object.extend(Element, {
846
  visible: function(element) {
847
    return $(element).style.display != 'none';
848
  },
849

    
850
  toggle: function() {
851
    for (var i = 0; i < arguments.length; i++) {
852
      var element = $(arguments[i]);
853
      Element[Element.visible(element) ? 'hide' : 'show'](element);
854
    }
855
  },
856

    
857
  hide: function() {
858
    for (var i = 0; i < arguments.length; i++) {
859
      var element = $(arguments[i]);
860
      element.style.display = 'none';
861
    }
862
  },
863

    
864
  show: function() {
865
    for (var i = 0; i < arguments.length; i++) {
866
      var element = $(arguments[i]);
867
      element.style.display = '';
868
    }
869
  },
870

    
871
  remove: function(element) {
872
    element = $(element);
873
    element.parentNode.removeChild(element);
874
  },
875

    
876
  update: function(element, html) {
877
    $(element).innerHTML = html.stripScripts();
878
    setTimeout(function() {html.evalScripts()}, 10);
879
  },
880

    
881
  getHeight: function(element) {
882
    element = $(element);
883
    return element.offsetHeight;
884
  },
885

    
886
  classNames: function(element) {
887
    return new Element.ClassNames(element);
888
  },
889

    
890
  hasClassName: function(element, className) {
891
    if (!(element = $(element))) return;
892
    return Element.classNames(element).include(className);
893
  },
894

    
895
  addClassName: function(element, className) {
896
    if (!(element = $(element))) return;
897
    return Element.classNames(element).add(className);
898
  },
899

    
900
  removeClassName: function(element, className) {
901
    if (!(element = $(element))) return;
902
    return Element.classNames(element).remove(className);
903
  },
904

    
905
  // removes whitespace-only text node children
906
  cleanWhitespace: function(element) {
907
    element = $(element);
908
    for (var i = 0; i < element.childNodes.length; i++) {
909
      var node = element.childNodes[i];
910
      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
911
        Element.remove(node);
912
    }
913
  },
914

    
915
  empty: function(element) {
916
    return $(element).innerHTML.match(/^\s*$/);
917
  },
918

    
919
  scrollTo: function(element) {
920
    element = $(element);
921
    var x = element.x ? element.x : element.offsetLeft,
922
        y = element.y ? element.y : element.offsetTop;
923
    window.scrollTo(x, y);
924
  },
925

    
926
  getStyle: function(element, style) {
927
    element = $(element);
928
    var value = element.style[style.camelize()];
929
    if (!value) {
930
      if (document.defaultView && document.defaultView.getComputedStyle) {
931
        var css = document.defaultView.getComputedStyle(element, null);
932
        value = css ? css.getPropertyValue(style) : null;
933
      } else if (element.currentStyle) {
934
        value = element.currentStyle[style.camelize()];
935
      }
936
    }
937

    
938
    if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
939
      if (Element.getStyle(element, 'position') == 'static') value = 'auto';
940

    
941
    return value == 'auto' ? null : value;
942
  },
943

    
944
  setStyle: function(element, style) {
945
    element = $(element);
946
    for (name in style)
947
      element.style[name.camelize()] = style[name];
948
  },
949

    
950
  getDimensions: function(element) {
951
    element = $(element);
952
    if (Element.getStyle(element, 'display') != 'none')
953
      return {width: element.offsetWidth, height: element.offsetHeight};
954

    
955
    // All *Width and *Height properties give 0 on elements with display none,
956
    // so enable the element temporarily
957
    var els = element.style;
958
    var originalVisibility = els.visibility;
959
    var originalPosition = els.position;
960
    els.visibility = 'hidden';
961
    els.position = 'absolute';
962
    els.display = '';
963
    var originalWidth = element.clientWidth;
964
    var originalHeight = element.clientHeight;
965
    els.display = 'none';
966
    els.position = originalPosition;
967
    els.visibility = originalVisibility;
968
    return {width: originalWidth, height: originalHeight};
969
  },
970

    
971
  makePositioned: function(element) {
972
    element = $(element);
973
    var pos = Element.getStyle(element, 'position');
974
    if (pos == 'static' || !pos) {
975
      element._madePositioned = true;
976
      element.style.position = 'relative';
977
      // Opera returns the offset relative to the positioning context, when an
978
      // element is position relative but top and left have not been defined
979
      if (window.opera) {
980
        element.style.top = 0;
981
        element.style.left = 0;
982
      }
983
    }
984
  },
985

    
986
  undoPositioned: function(element) {
987
    element = $(element);
988
    if (element._madePositioned) {
989
      element._madePositioned = undefined;
990
      element.style.position =
991
        element.style.top =
992
        element.style.left =
993
        element.style.bottom =
994
        element.style.right = '';
995
    }
996
  },
997

    
998
  makeClipping: function(element) {
999
    element = $(element);
1000
    if (element._overflow) return;
1001
    element._overflow = element.style.overflow;
1002
    if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
1003
      element.style.overflow = 'hidden';
1004
  },
1005

    
1006
  undoClipping: function(element) {
1007
    element = $(element);
1008
    if (element._overflow) return;
1009
    element.style.overflow = element._overflow;
1010
    element._overflow = undefined;
1011
  }
1012
});
1013

    
1014
var Toggle = new Object();
1015
Toggle.display = Element.toggle;
1016

    
1017
/*--------------------------------------------------------------------------*/
1018

    
1019
Abstract.Insertion = function(adjacency) {
1020
  this.adjacency = adjacency;
1021
}
1022

    
1023
Abstract.Insertion.prototype = {
1024
  initialize: function(element, content) {
1025
    this.element = $(element);
1026
    this.content = content.stripScripts();
1027

    
1028
    if (this.adjacency && this.element.insertAdjacentHTML) {
1029
      try {
1030
        this.element.insertAdjacentHTML(this.adjacency, this.content);
1031
      } catch (e) {
1032
        if (this.element.tagName.toLowerCase() == 'tbody') {
1033
          this.insertContent(this.contentFromAnonymousTable());
1034
        } else {
1035
          throw e;
1036
        }
1037
      }
1038
    } else {
1039
      this.range = this.element.ownerDocument.createRange();
1040
      if (this.initializeRange) this.initializeRange();
1041
      this.insertContent([this.range.createContextualFragment(this.content)]);
1042
    }
1043

    
1044
    setTimeout(function() {content.evalScripts()}, 10);
1045
  },
1046

    
1047
  contentFromAnonymousTable: function() {
1048
    var div = document.createElement('div');
1049
    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
1050
    return $A(div.childNodes[0].childNodes[0].childNodes);
1051
  }
1052
}
1053

    
1054
var Insertion = new Object();
1055

    
1056
Insertion.Before = Class.create();
1057
Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
1058
  initializeRange: function() {
1059
    this.range.setStartBefore(this.element);
1060
  },
1061

    
1062
  insertContent: function(fragments) {
1063
    fragments.each((function(fragment) {
1064
      this.element.parentNode.insertBefore(fragment, this.element);
1065
    }).bind(this));
1066
  }
1067
});
1068

    
1069
Insertion.Top = Class.create();
1070
Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
1071
  initializeRange: function() {
1072
    this.range.selectNodeContents(this.element);
1073
    this.range.collapse(true);
1074
  },
1075

    
1076
  insertContent: function(fragments) {
1077
    fragments.reverse(false).each((function(fragment) {
1078
      this.element.insertBefore(fragment, this.element.firstChild);
1079
    }).bind(this));
1080
  }
1081
});
1082

    
1083
Insertion.Bottom = Class.create();
1084
Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
1085
  initializeRange: function() {
1086
    this.range.selectNodeContents(this.element);
1087
    this.range.collapse(this.element);
1088
  },
1089

    
1090
  insertContent: function(fragments) {
1091
    fragments.each((function(fragment) {
1092
      this.element.appendChild(fragment);
1093
    }).bind(this));
1094
  }
1095
});
1096

    
1097
Insertion.After = Class.create();
1098
Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
1099
  initializeRange: function() {
1100
    this.range.setStartAfter(this.element);
1101
  },
1102

    
1103
  insertContent: function(fragments) {
1104
    fragments.each((function(fragment) {
1105
      this.element.parentNode.insertBefore(fragment,
1106
        this.element.nextSibling);
1107
    }).bind(this));
1108
  }
1109
});
1110

    
1111
/*--------------------------------------------------------------------------*/
1112

    
1113
Element.ClassNames = Class.create();
1114
Element.ClassNames.prototype = {
1115
  initialize: function(element) {
1116
    this.element = $(element);
1117
  },
1118

    
1119
  _each: function(iterator) {
1120
    this.element.className.split(/\s+/).select(function(name) {
1121
      return name.length > 0;
1122
    })._each(iterator);
1123
  },
1124

    
1125
  set: function(className) {
1126
    this.element.className = className;
1127
  },
1128

    
1129
  add: function(classNameToAdd) {
1130
    if (this.include(classNameToAdd)) return;
1131
    this.set(this.toArray().concat(classNameToAdd).join(' '));
1132
  },
1133

    
1134
  remove: function(classNameToRemove) {
1135
    if (!this.include(classNameToRemove)) return;
1136
    this.set(this.select(function(className) {
1137
      return className != classNameToRemove;
1138
    }).join(' '));
1139
  },
1140

    
1141
  toString: function() {
1142
    return this.toArray().join(' ');
1143
  }
1144
}
1145

    
1146
Object.extend(Element.ClassNames.prototype, Enumerable);
1147
var Field = {
1148
  clear: function() {
1149
    for (var i = 0; i < arguments.length; i++)
1150
      $(arguments[i]).value = '';
1151
  },
1152

    
1153
  focus: function(element) {
1154
    $(element).focus();
1155
  },
1156

    
1157
  present: function() {
1158
    for (var i = 0; i < arguments.length; i++)
1159
      if ($(arguments[i]).value == '') return false;
1160
    return true;
1161
  },
1162

    
1163
  select: function(element) {
1164
    $(element).select();
1165
  },
1166

    
1167
  activate: function(element) {
1168
    element = $(element);
1169
    element.focus();
1170
    if (element.select)
1171
      element.select();
1172
  }
1173
}
1174

    
1175
/*--------------------------------------------------------------------------*/
1176

    
1177
var Form = {
1178
  serialize: function(form) {
1179
    var elements = Form.getElements($(form));
1180
    var queryComponents = new Array();
1181

    
1182
    for (var i = 0; i < elements.length; i++) {
1183
      var queryComponent = Form.Element.serialize(elements[i]);
1184
      if (queryComponent)
1185
        queryComponents.push(queryComponent);
1186
    }
1187

    
1188
    return queryComponents.join('&');
1189
  },
1190

    
1191
  getElements: function(form) {
1192
    form = $(form);
1193
    var elements = new Array();
1194

    
1195
    for (tagName in Form.Element.Serializers) {
1196
      var tagElements = form.getElementsByTagName(tagName);
1197
      for (var j = 0; j < tagElements.length; j++)
1198
        elements.push(tagElements[j]);
1199
    }
1200
    return elements;
1201
  },
1202

    
1203
  getInputs: function(form, typeName, name) {
1204
    form = $(form);
1205
    var inputs = form.getElementsByTagName('input');
1206

    
1207
    if (!typeName && !name)
1208
      return inputs;
1209

    
1210
    var matchingInputs = new Array();
1211
    for (var i = 0; i < inputs.length; i++) {
1212
      var input = inputs[i];
1213
      if ((typeName && input.type != typeName) ||
1214
          (name && input.name != name))
1215
        continue;
1216
      matchingInputs.push(input);
1217
    }
1218

    
1219
    return matchingInputs;
1220
  },
1221

    
1222
  disable: function(form) {
1223
    var elements = Form.getElements(form);
1224
    for (var i = 0; i < elements.length; i++) {
1225
      var element = elements[i];
1226
      element.blur();
1227
      element.disabled = 'true';
1228
    }
1229
  },
1230

    
1231
  enable: function(form) {
1232
    var elements = Form.getElements(form);
1233
    for (var i = 0; i < elements.length; i++) {
1234
      var element = elements[i];
1235
      element.disabled = '';
1236
    }
1237
  },
1238

    
1239
  findFirstElement: function(form) {
1240
    return Form.getElements(form).find(function(element) {
1241
      return element.type != 'hidden' && !element.disabled &&
1242
        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
1243
    });
1244
  },
1245

    
1246
  focusFirstElement: function(form) {
1247
    Field.activate(Form.findFirstElement(form));
1248
  },
1249

    
1250
  reset: function(form) {
1251
    $(form).reset();
1252
  }
1253
}
1254

    
1255
Form.Element = {
1256
  serialize: function(element) {
1257
    element = $(element);
1258
    var method = element.tagName.toLowerCase();
1259
    var parameter = Form.Element.Serializers[method](element);
1260

    
1261
    if (parameter) {
1262
      var key = encodeURIComponent(parameter[0]);
1263
      if (key.length == 0) return;
1264

    
1265
      if (parameter[1].constructor != Array)
1266
        parameter[1] = [parameter[1]];
1267

    
1268
      return parameter[1].map(function(value) {
1269
        return key + '=' + encodeURIComponent(value);
1270
      }).join('&');
1271
    }
1272
  },
1273

    
1274
  getValue: function(element) {
1275
    element = $(element);
1276
    var method = element.tagName.toLowerCase();
1277
    var parameter = Form.Element.Serializers[method](element);
1278

    
1279
    if (parameter)
1280
      return parameter[1];
1281
  }
1282
}
1283

    
1284
Form.Element.Serializers = {
1285
  input: function(element) {
1286
    switch (element.type.toLowerCase()) {
1287
      case 'submit':
1288
      case 'hidden':
1289
      case 'password':
1290
      case 'text':
1291
        return Form.Element.Serializers.textarea(element);
1292
      case 'checkbox':
1293
      case 'radio':
1294
        return Form.Element.Serializers.inputSelector(element);
1295
    }
1296
    return false;
1297
  },
1298

    
1299
  inputSelector: function(element) {
1300
    if (element.checked)
1301
      return [element.name, element.value];
1302
  },
1303

    
1304
  textarea: function(element) {
1305
    return [element.name, element.value];
1306
  },
1307

    
1308
  select: function(element) {
1309
    return Form.Element.Serializers[element.type == 'select-one' ?
1310
      'selectOne' : 'selectMany'](element);
1311
  },
1312

    
1313
  selectOne: function(element) {
1314
    var value = '', opt, index = element.selectedIndex;
1315
    if (index >= 0) {
1316
      opt = element.options[index];
1317
      value = opt.value;
1318
      if (!value && !('value' in opt))
1319
        value = opt.text;
1320
    }
1321
    return [element.name, value];
1322
  },
1323

    
1324
  selectMany: function(element) {
1325
    var value = new Array();
1326
    for (var i = 0; i < element.length; i++) {
1327
      var opt = element.options[i];
1328
      if (opt.selected) {
1329
        var optValue = opt.value;
1330
        if (!optValue && !('value' in opt))
1331
          optValue = opt.text;
1332
        value.push(optValue);
1333
      }
1334
    }
1335
    return [element.name, value];
1336
  }
1337
}
1338

    
1339
/*--------------------------------------------------------------------------*/
1340

    
1341
var $F = Form.Element.getValue;
1342

    
1343
/*--------------------------------------------------------------------------*/
1344

    
1345
Abstract.TimedObserver = function() {}
1346
Abstract.TimedObserver.prototype = {
1347
  initialize: function(element, frequency, callback) {
1348
    this.frequency = frequency;
1349
    this.element   = $(element);
1350
    this.callback  = callback;
1351

    
1352
    this.lastValue = this.getValue();
1353
    this.registerCallback();
1354
  },
1355

    
1356
  registerCallback: function() {
1357
    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
1358
  },
1359

    
1360
  onTimerEvent: function() {
1361
    var value = this.getValue();
1362
    if (this.lastValue != value) {
1363
      this.callback(this.element, value);
1364
      this.lastValue = value;
1365
    }
1366
  }
1367
}
1368

    
1369
Form.Element.Observer = Class.create();
1370
Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
1371
  getValue: function() {
1372
    return Form.Element.getValue(this.element);
1373
  }
1374
});
1375

    
1376
Form.Observer = Class.create();
1377
Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
1378
  getValue: function() {
1379
    return Form.serialize(this.element);
1380
  }
1381
});
1382

    
1383
/*--------------------------------------------------------------------------*/
1384

    
1385
Abstract.EventObserver = function() {}
1386
Abstract.EventObserver.prototype = {
1387
  initialize: function(element, callback) {
1388
    this.element  = $(element);
1389
    this.callback = callback;
1390

    
1391
    this.lastValue = this.getValue();
1392
    if (this.element.tagName.toLowerCase() == 'form')
1393
      this.registerFormCallbacks();
1394
    else
1395
      this.registerCallback(this.element);
1396
  },
1397

    
1398
  onElementEvent: function() {
1399
    var value = this.getValue();
1400
    if (this.lastValue != value) {
1401
      this.callback(this.element, value);
1402
      this.lastValue = value;
1403
    }
1404
  },
1405

    
1406
  registerFormCallbacks: function() {
1407
    var elements = Form.getElements(this.element);
1408
    for (var i = 0; i < elements.length; i++)
1409
      this.registerCallback(elements[i]);
1410
  },
1411

    
1412
  registerCallback: function(element) {
1413
    if (element.type) {
1414
      switch (element.type.toLowerCase()) {
1415
        case 'checkbox':
1416
        case 'radio':
1417
          Event.observe(element, 'click', this.onElementEvent.bind(this));
1418
          break;
1419
        case 'password':
1420
        case 'text':
1421
        case 'textarea':
1422
        case 'select-one':
1423
        case 'select-multiple':
1424
          Event.observe(element, 'change', this.onElementEvent.bind(this));
1425
          break;
1426
      }
1427
    }
1428
  }
1429
}
1430

    
1431
Form.Element.EventObserver = Class.create();
1432
Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
1433
  getValue: function() {
1434
    return Form.Element.getValue(this.element);
1435
  }
1436
});
1437

    
1438
Form.EventObserver = Class.create();
1439
Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
1440
  getValue: function() {
1441
    return Form.serialize(this.element);
1442
  }
1443
});
1444
if (!window.Event) {
1445
  var Event = new Object();
1446
}
1447

    
1448
Object.extend(Event, {
1449
  KEY_BACKSPACE: 8,
1450
  KEY_TAB:       9,
1451
  KEY_RETURN:   13,
1452
  KEY_ESC:      27,
1453
  KEY_LEFT:     37,
1454
  KEY_UP:       38,
1455
  KEY_RIGHT:    39,
1456
  KEY_DOWN:     40,
1457
  KEY_DELETE:   46,
1458

    
1459
  element: function(event) {
1460
    return event.target || event.srcElement;
1461
  },
1462

    
1463
  isLeftClick: function(event) {
1464
    return (((event.which) && (event.which == 1)) ||
1465
            ((event.button) && (event.button == 1)));
1466
  },
1467

    
1468
  pointerX: function(event) {
1469
    return event.pageX || (event.clientX +
1470
      (document.documentElement.scrollLeft || document.body.scrollLeft));
1471
  },
1472

    
1473
  pointerY: function(event) {
1474
    return event.pageY || (event.clientY +
1475
      (document.documentElement.scrollTop || document.body.scrollTop));
1476
  },
1477

    
1478
  stop: function(event) {
1479
    if (event.preventDefault) {
1480
      event.preventDefault();
1481
      event.stopPropagation();
1482
    } else {
1483
      event.returnValue = false;
1484
      event.cancelBubble = true;
1485
    }
1486
  },
1487

    
1488
  // find the first node with the given tagName, starting from the
1489
  // node the event was triggered on; traverses the DOM upwards
1490
  findElement: function(event, tagName) {
1491
    var element = Event.element(event);
1492
    while (element.parentNode && (!element.tagName ||
1493
        (element.tagName.toUpperCase() != tagName.toUpperCase())))
1494
      element = element.parentNode;
1495
    return element;
1496
  },
1497

    
1498
  observers: false,
1499

    
1500
  _observeAndCache: function(element, name, observer, useCapture) {
1501
    if (!this.observers) this.observers = [];
1502
    if (element.addEventListener) {
1503
      this.observers.push([element, name, observer, useCapture]);
1504
      element.addEventListener(name, observer, useCapture);
1505
    } else if (element.attachEvent) {
1506
      this.observers.push([element, name, observer, useCapture]);
1507
      element.attachEvent('on' + name, observer);
1508
    }
1509
  },
1510

    
1511
  unloadCache: function() {
1512
    if (!Event.observers) return;
1513
    for (var i = 0; i < Event.observers.length; i++) {
1514
      Event.stopObserving.apply(this, Event.observers[i]);
1515
      Event.observers[i][0] = null;
1516
    }
1517
    Event.observers = false;
1518
  },
1519

    
1520
  observe: function(elementParam, name, observer, useCapture) {
1521
    var element = $(elementParam);
1522
    useCapture = useCapture || false;
1523

    
1524
    if (name == 'keypress' &&
1525
        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
1526
        || element.attachEvent))
1527
      name = 'keydown';
1528

    
1529
    this._observeAndCache(element, name, observer, useCapture);
1530
  },
1531

    
1532
  stopObserving: function(elementParam, name, observer, useCapture) {
1533
    var element = $(elementParam);
1534
    useCapture = useCapture || false;
1535

    
1536
    if (name == 'keypress' &&
1537
        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
1538
        || element.detachEvent))
1539
      name = 'keydown';
1540

    
1541
    if (element.removeEventListener) {
1542
      element.removeEventListener(name, observer, useCapture);
1543
    } else if (element.detachEvent) {
1544
      element.detachEvent('on' + name, observer);
1545
    }
1546
  }
1547
});
1548

    
1549
/* prevent memory leaks in IE */
1550
Event.observe(window, 'unload', Event.unloadCache, false);
1551
var Position = {
1552
  // set to true if needed, warning: firefox performance problems
1553
  // NOT neeeded for page scrolling, only if draggable contained in
1554
  // scrollable elements
1555
  includeScrollOffsets: false,
1556

    
1557
  // must be called before calling withinIncludingScrolloffset, every time the
1558
  // page is scrolled
1559
  prepare: function() {
1560
    this.deltaX =  window.pageXOffset
1561
                || document.documentElement.scrollLeft
1562
                || document.body.scrollLeft
1563
                || 0;
1564
    this.deltaY =  window.pageYOffset
1565
                || document.documentElement.scrollTop
1566
                || document.body.scrollTop
1567
                || 0;
1568
  },
1569

    
1570
  realOffset: function(element) {
1571
    var valueT = 0, valueL = 0;
1572
    do {
1573
      valueT += element.scrollTop  || 0;
1574
      valueL += element.scrollLeft || 0;
1575
      element = element.parentNode;
1576
    } while (element);
1577
    return [valueL, valueT];
1578
  },
1579

    
1580
  cumulativeOffset: function(element) {
1581
    var valueT = 0, valueL = 0;
1582
    do {
1583
      valueT += element.offsetTop  || 0;
1584
      valueL += element.offsetLeft || 0;
1585
      element = element.offsetParent;
1586
    } while (element);
1587
    return [valueL, valueT];
1588
  },
1589

    
1590
  positionedOffset: function(element) {
1591
    var valueT = 0, valueL = 0;
1592
    do {
1593
      valueT += element.offsetTop  || 0;
1594
      valueL += element.offsetLeft || 0;
1595
      element = element.offsetParent;
1596
      if (element) {
1597
        p = Element.getStyle(element, 'position');
1598
        if (p == 'relative' || p == 'absolute') break;
1599
      }
1600
    } while (element);
1601
    return [valueL, valueT];
1602
  },
1603

    
1604
  offsetParent: function(element) {
1605
    if (element.offsetParent) return element.offsetParent;
1606
    if (element == document.body) return element;
1607

    
1608
    while ((element = element.parentNode) && element != document.body)
1609
      if (Element.getStyle(element, 'position') != 'static')
1610
        return element;
1611

    
1612
    return document.body;
1613
  },
1614

    
1615
  // caches x/y coordinate pair to use with overlap
1616
  within: function(element, x, y) {
1617
    if (this.includeScrollOffsets)
1618
      return this.withinIncludingScrolloffsets(element, x, y);
1619
    this.xcomp = x;
1620
    this.ycomp = y;
1621
    this.offset = this.cumulativeOffset(element);
1622

    
1623
    return (y >= this.offset[1] &&
1624
            y <  this.offset[1] + element.offsetHeight &&
1625
            x >= this.offset[0] &&
1626
            x <  this.offset[0] + element.offsetWidth);
1627
  },
1628

    
1629
  withinIncludingScrolloffsets: function(element, x, y) {
1630
    var offsetcache = this.realOffset(element);
1631

    
1632
    this.xcomp = x + offsetcache[0] - this.deltaX;
1633
    this.ycomp = y + offsetcache[1] - this.deltaY;
1634
    this.offset = this.cumulativeOffset(element);
1635

    
1636
    return (this.ycomp >= this.offset[1] &&
1637
            this.ycomp <  this.offset[1] + element.offsetHeight &&
1638
            this.xcomp >= this.offset[0] &&
1639
            this.xcomp <  this.offset[0] + element.offsetWidth);
1640
  },
1641

    
1642
  // within must be called directly before
1643
  overlap: function(mode, element) {
1644
    if (!mode) return 0;
1645
    if (mode == 'vertical')
1646
      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
1647
        element.offsetHeight;
1648
    if (mode == 'horizontal')
1649
      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
1650
        element.offsetWidth;
1651
  },
1652

    
1653
  clone: function(source, target) {
1654
    source = $(source);
1655
    target = $(target);
1656
    target.style.position = 'absolute';
1657
    var offsets = this.cumulativeOffset(source);
1658
    target.style.top    = offsets[1] + 'px';
1659
    target.style.left   = offsets[0] + 'px';
1660
    target.style.width  = source.offsetWidth + 'px';
1661
    target.style.height = source.offsetHeight + 'px';
1662
  },
1663

    
1664
  page: function(forElement) {
1665
    var valueT = 0, valueL = 0;
1666

    
1667
    var element = forElement;
1668
    do {
1669
      valueT += element.offsetTop  || 0;
1670
      valueL += element.offsetLeft || 0;
1671

    
1672
      // Safari fix
1673
      if (element.offsetParent==document.body)
1674
        if (Element.getStyle(element,'position')=='absolute') break;
1675

    
1676
    } while (element = element.offsetParent);
1677

    
1678
    element = forElement;
1679
    do {
1680
      valueT -= element.scrollTop  || 0;
1681
      valueL -= element.scrollLeft || 0;
1682
    } while (element = element.parentNode);
1683

    
1684
    return [valueL, valueT];
1685
  },
1686

    
1687
  clone: function(source, target) {
1688
    var options = Object.extend({
1689
      setLeft:    true,
1690
      setTop:     true,
1691
      setWidth:   true,
1692
      setHeight:  true,
1693
      offsetTop:  0,
1694
      offsetLeft: 0
1695
    }, arguments[2] || {})
1696

    
1697
    // find page position of source
1698
    source = $(source);
1699
    var p = Position.page(source);
1700

    
1701
    // find coordinate system to use
1702
    target = $(target);
1703
    var delta = [0, 0];
1704
    var parent = null;
1705
    // delta [0,0] will do fine with position: fixed elements,
1706
    // position:absolute needs offsetParent deltas
1707
    if (Element.getStyle(target,'position') == 'absolute') {
1708
      parent = Position.offsetParent(target);
1709
      delta = Position.page(parent);
1710
    }
1711

    
1712
    // correct by body offsets (fixes Safari)
1713
    if (parent == document.body) {
1714
      delta[0] -= document.body.offsetLeft;
1715
      delta[1] -= document.body.offsetTop;
1716
    }
1717

    
1718
    // set position
1719
    if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
1720
    if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
1721
    if(options.setWidth)  target.style.width = source.offsetWidth + 'px';
1722
    if(options.setHeight) target.style.height = source.offsetHeight + 'px';
1723
  },
1724

    
1725
  absolutize: function(element) {
1726
    element = $(element);
1727
    if (element.style.position == 'absolute') return;
1728
    Position.prepare();
1729

    
1730
    var offsets = Position.positionedOffset(element);
1731
    var top     = offsets[1];
1732
    var left    = offsets[0];
1733
    var width   = element.clientWidth;
1734
    var height  = element.clientHeight;
1735

    
1736
    element._originalLeft   = left - parseFloat(element.style.left  || 0);
1737
    element._originalTop    = top  - parseFloat(element.style.top || 0);
1738
    element._originalWidth  = element.style.width;
1739
    element._originalHeight = element.style.height;
1740

    
1741
    element.style.position = 'absolute';
1742
    element.style.top    = top + 'px';;
1743
    element.style.left   = left + 'px';;
1744
    element.style.width  = width + 'px';;
1745
    element.style.height = height + 'px';;
1746
  },
1747

    
1748
  relativize: function(element) {
1749
    element = $(element);
1750
    if (element.style.position == 'relative') return;
1751
    Position.prepare();
1752

    
1753
    element.style.position = 'relative';
1754
    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
1755
    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
1756

    
1757
    element.style.top    = top + 'px';
1758
    element.style.left   = left + 'px';
1759
    element.style.height = element._originalHeight;
1760
    element.style.width  = element._originalWidth;
1761
  }
1762
}
1763

    
1764
// Safari returns margins on body which is incorrect if the child is absolutely
1765
// positioned.  For performance reasons, redefine Position.cumulativeOffset for
1766
// KHTML/WebKit only.
1767
if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
1768
  Position.cumulativeOffset = function(element) {
1769
    var valueT = 0, valueL = 0;
1770
    do {
1771
      valueT += element.offsetTop  || 0;
1772
      valueL += element.offsetLeft || 0;
1773
      if (element.offsetParent == document.body)
1774
        if (Element.getStyle(element, 'position') == 'absolute') break;
1775

    
1776
      element = element.offsetParent;
1777
    } while (element);
1778

    
1779
    return [valueL, valueT];
1780
  }
1781
}
(2-2/2)