~edubuntu-dev/+junk/ubiquity-slideshow

« back to all changes in this revision

Viewing changes to slides/link-core/prototype.js

  • Committer: Jonathan Carter
  • Date: 2010-09-06 22:16:58 UTC
  • Revision ID: jcarter@revolutionlinux.com-20100906221658-kquwnpweqg5rl2pz
Initial bzrification

Show diffs side-by-side

added added

removed removed

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