Project

General

Profile

« Previous | Next » 

Revision 3528

add latest stable prototype (ajax) release

View differences:

lib/style/common/prototype-1.5.1.1/prototype.js
1
/*  Prototype JavaScript framework, version 1.5.1.1
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://www.prototypejs.org/
6
 *
7
/*--------------------------------------------------------------------------*/
8

  
9
var Prototype = {
10
  Version: '1.5.1.1',
11

  
12
  Browser: {
13
    IE:     !!(window.attachEvent && !window.opera),
14
    Opera:  !!window.opera,
15
    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
16
    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1
17
  },
18

  
19
  BrowserFeatures: {
20
    XPath: !!document.evaluate,
21
    ElementExtensions: !!window.HTMLElement,
22
    SpecificElementExtensions:
23
      (document.createElement('div').__proto__ !==
24
       document.createElement('form').__proto__)
25
  },
26

  
27
  ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
28
  JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
29

  
30
  emptyFunction: function() { },
31
  K: function(x) { return x }
32
}
33

  
34
var Class = {
35
  create: function() {
36
    return function() {
37
      this.initialize.apply(this, arguments);
38
    }
39
  }
40
}
41

  
42
var Abstract = new Object();
43

  
44
Object.extend = function(destination, source) {
45
  for (var property in source) {
46
    destination[property] = source[property];
47
  }
48
  return destination;
49
}
50

  
51
Object.extend(Object, {
52
  inspect: function(object) {
53
    try {
54
      if (object === undefined) return 'undefined';
55
      if (object === null) return 'null';
56
      return object.inspect ? object.inspect() : object.toString();
57
    } catch (e) {
58
      if (e instanceof RangeError) return '...';
59
      throw e;
60
    }
61
  },
62

  
63
  toJSON: function(object) {
64
    var type = typeof object;
65
    switch(type) {
66
      case 'undefined':
67
      case 'function':
68
      case 'unknown': return;
69
      case 'boolean': return object.toString();
70
    }
71
    if (object === null) return 'null';
72
    if (object.toJSON) return object.toJSON();
73
    if (object.ownerDocument === document) return;
74
    var results = [];
75
    for (var property in object) {
76
      var value = Object.toJSON(object[property]);
77
      if (value !== undefined)
78
        results.push(property.toJSON() + ': ' + value);
79
    }
80
    return '{' + results.join(', ') + '}';
81
  },
82

  
83
  keys: function(object) {
84
    var keys = [];
85
    for (var property in object)
86
      keys.push(property);
87
    return keys;
88
  },
89

  
90
  values: function(object) {
91
    var values = [];
92
    for (var property in object)
93
      values.push(object[property]);
94
    return values;
95
  },
96

  
97
  clone: function(object) {
98
    return Object.extend({}, object);
99
  }
100
});
101

  
102
Function.prototype.bind = function() {
103
  var __method = this, args = $A(arguments), object = args.shift();
104
  return function() {
105
    return __method.apply(object, args.concat($A(arguments)));
106
  }
107
}
108

  
109
Function.prototype.bindAsEventListener = function(object) {
110
  var __method = this, args = $A(arguments), object = args.shift();
111
  return function(event) {
112
    return __method.apply(object, [event || window.event].concat(args));
113
  }
114
}
115

  
116
Object.extend(Number.prototype, {
117
  toColorPart: function() {
118
    return this.toPaddedString(2, 16);
119
  },
120

  
121
  succ: function() {
122
    return this + 1;
123
  },
124

  
125
  times: function(iterator) {
126
    $R(0, this, true).each(iterator);
127
    return this;
128
  },
129

  
130
  toPaddedString: function(length, radix) {
131
    var string = this.toString(radix || 10);
132
    return '0'.times(length - string.length) + string;
133
  },
134

  
135
  toJSON: function() {
136
    return isFinite(this) ? this.toString() : 'null';
137
  }
138
});
139

  
140
Date.prototype.toJSON = function() {
141
  return '"' + this.getFullYear() + '-' +
142
    (this.getMonth() + 1).toPaddedString(2) + '-' +
143
    this.getDate().toPaddedString(2) + 'T' +
144
    this.getHours().toPaddedString(2) + ':' +
145
    this.getMinutes().toPaddedString(2) + ':' +
146
    this.getSeconds().toPaddedString(2) + '"';
147
};
148

  
149
var Try = {
150
  these: function() {
151
    var returnValue;
152

  
153
    for (var i = 0, length = arguments.length; i < length; i++) {
154
      var lambda = arguments[i];
155
      try {
156
        returnValue = lambda();
157
        break;
158
      } catch (e) {}
159
    }
160

  
161
    return returnValue;
162
  }
163
}
164

  
165
/*--------------------------------------------------------------------------*/
166

  
167
var PeriodicalExecuter = Class.create();
168
PeriodicalExecuter.prototype = {
169
  initialize: function(callback, frequency) {
170
    this.callback = callback;
171
    this.frequency = frequency;
172
    this.currentlyExecuting = false;
173

  
174
    this.registerCallback();
175
  },
176

  
177
  registerCallback: function() {
178
    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
179
  },
180

  
181
  stop: function() {
182
    if (!this.timer) return;
183
    clearInterval(this.timer);
184
    this.timer = null;
185
  },
186

  
187
  onTimerEvent: function() {
188
    if (!this.currentlyExecuting) {
189
      try {
190
        this.currentlyExecuting = true;
191
        this.callback(this);
192
      } finally {
193
        this.currentlyExecuting = false;
194
      }
195
    }
196
  }
197
}
198
Object.extend(String, {
199
  interpret: function(value) {
200
    return value == null ? '' : String(value);
201
  },
202
  specialChar: {
203
    '\b': '\\b',
204
    '\t': '\\t',
205
    '\n': '\\n',
206
    '\f': '\\f',
207
    '\r': '\\r',
208
    '\\': '\\\\'
209
  }
210
});
211

  
212
Object.extend(String.prototype, {
213
  gsub: function(pattern, replacement) {
214
    var result = '', source = this, match;
215
    replacement = arguments.callee.prepareReplacement(replacement);
216

  
217
    while (source.length > 0) {
218
      if (match = source.match(pattern)) {
219
        result += source.slice(0, match.index);
220
        result += String.interpret(replacement(match));
221
        source  = source.slice(match.index + match[0].length);
222
      } else {
223
        result += source, source = '';
224
      }
225
    }
226
    return result;
227
  },
228

  
229
  sub: function(pattern, replacement, count) {
230
    replacement = this.gsub.prepareReplacement(replacement);
231
    count = count === undefined ? 1 : count;
232

  
233
    return this.gsub(pattern, function(match) {
234
      if (--count < 0) return match[0];
235
      return replacement(match);
236
    });
237
  },
238

  
239
  scan: function(pattern, iterator) {
240
    this.gsub(pattern, iterator);
241
    return this;
242
  },
243

  
244
  truncate: function(length, truncation) {
245
    length = length || 30;
246
    truncation = truncation === undefined ? '...' : truncation;
247
    return this.length > length ?
248
      this.slice(0, length - truncation.length) + truncation : this;
249
  },
250

  
251
  strip: function() {
252
    return this.replace(/^\s+/, '').replace(/\s+$/, '');
253
  },
254

  
255
  stripTags: function() {
256
    return this.replace(/<\/?[^>]+>/gi, '');
257
  },
258

  
259
  stripScripts: function() {
260
    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
261
  },
262

  
263
  extractScripts: function() {
264
    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
265
    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
266
    return (this.match(matchAll) || []).map(function(scriptTag) {
267
      return (scriptTag.match(matchOne) || ['', ''])[1];
268
    });
269
  },
270

  
271
  evalScripts: function() {
272
    return this.extractScripts().map(function(script) { return eval(script) });
273
  },
274

  
275
  escapeHTML: function() {
276
    var self = arguments.callee;
277
    self.text.data = this;
278
    return self.div.innerHTML;
279
  },
280

  
281
  unescapeHTML: function() {
282
    var div = document.createElement('div');
283
    div.innerHTML = this.stripTags();
284
    return div.childNodes[0] ? (div.childNodes.length > 1 ?
285
      $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
286
      div.childNodes[0].nodeValue) : '';
287
  },
288

  
289
  toQueryParams: function(separator) {
290
    var match = this.strip().match(/([^?#]*)(#.*)?$/);
291
    if (!match) return {};
292

  
293
    return match[1].split(separator || '&').inject({}, function(hash, pair) {
294
      if ((pair = pair.split('='))[0]) {
295
        var key = decodeURIComponent(pair.shift());
296
        var value = pair.length > 1 ? pair.join('=') : pair[0];
297
        if (value != undefined) value = decodeURIComponent(value);
298

  
299
        if (key in hash) {
300
          if (hash[key].constructor != Array) hash[key] = [hash[key]];
301
          hash[key].push(value);
302
        }
303
        else hash[key] = value;
304
      }
305
      return hash;
306
    });
307
  },
308

  
309
  toArray: function() {
310
    return this.split('');
311
  },
312

  
313
  succ: function() {
314
    return this.slice(0, this.length - 1) +
315
      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
316
  },
317

  
318
  times: function(count) {
319
    var result = '';
320
    for (var i = 0; i < count; i++) result += this;
321
    return result;
322
  },
323

  
324
  camelize: function() {
325
    var parts = this.split('-'), len = parts.length;
326
    if (len == 1) return parts[0];
327

  
328
    var camelized = this.charAt(0) == '-'
329
      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
330
      : parts[0];
331

  
332
    for (var i = 1; i < len; i++)
333
      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
334

  
335
    return camelized;
336
  },
337

  
338
  capitalize: function() {
339
    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
340
  },
341

  
342
  underscore: function() {
343
    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
344
  },
345

  
346
  dasherize: function() {
347
    return this.gsub(/_/,'-');
348
  },
349

  
350
  inspect: function(useDoubleQuotes) {
351
    var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
352
      var character = String.specialChar[match[0]];
353
      return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
354
    });
355
    if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
356
    return "'" + escapedString.replace(/'/g, '\\\'') + "'";
357
  },
358

  
359
  toJSON: function() {
360
    return this.inspect(true);
361
  },
362

  
363
  unfilterJSON: function(filter) {
364
    return this.sub(filter || Prototype.JSONFilter, '#{1}');
365
  },
366

  
367
  isJSON: function() {
368
    var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
369
    return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
370
  },
371

  
372
  evalJSON: function(sanitize) {
373
    var json = this.unfilterJSON();
374
    try {
375
      if (!sanitize || json.isJSON()) return eval('(' + json + ')');
376
    } catch (e) { }
377
    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
378
  },
379

  
380
  include: function(pattern) {
381
    return this.indexOf(pattern) > -1;
382
  },
383

  
384
  startsWith: function(pattern) {
385
    return this.indexOf(pattern) === 0;
386
  },
387

  
388
  endsWith: function(pattern) {
389
    var d = this.length - pattern.length;
390
    return d >= 0 && this.lastIndexOf(pattern) === d;
391
  },
392

  
393
  empty: function() {
394
    return this == '';
395
  },
396

  
397
  blank: function() {
398
    return /^\s*$/.test(this);
399
  }
400
});
401

  
402
if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
403
  escapeHTML: function() {
404
    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
405
  },
406
  unescapeHTML: function() {
407
    return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
408
  }
409
});
410

  
411
String.prototype.gsub.prepareReplacement = function(replacement) {
412
  if (typeof replacement == 'function') return replacement;
413
  var template = new Template(replacement);
414
  return function(match) { return template.evaluate(match) };
415
}
416

  
417
String.prototype.parseQuery = String.prototype.toQueryParams;
418

  
419
Object.extend(String.prototype.escapeHTML, {
420
  div:  document.createElement('div'),
421
  text: document.createTextNode('')
422
});
423

  
424
with (String.prototype.escapeHTML) div.appendChild(text);
425

  
426
var Template = Class.create();
427
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
428
Template.prototype = {
429
  initialize: function(template, pattern) {
430
    this.template = template.toString();
431
    this.pattern  = pattern || Template.Pattern;
432
  },
433

  
434
  evaluate: function(object) {
435
    return this.template.gsub(this.pattern, function(match) {
436
      var before = match[1];
437
      if (before == '\\') return match[2];
438
      return before + String.interpret(object[match[3]]);
439
    });
440
  }
441
}
442

  
443
var $break = {}, $continue = new Error('"throw $continue" is deprecated, use "return" instead');
444

  
445
var Enumerable = {
446
  each: function(iterator) {
447
    var index = 0;
448
    try {
449
      this._each(function(value) {
450
        iterator(value, index++);
451
      });
452
    } catch (e) {
453
      if (e != $break) throw e;
454
    }
455
    return this;
456
  },
457

  
458
  eachSlice: function(number, iterator) {
459
    var index = -number, slices = [], array = this.toArray();
460
    while ((index += number) < array.length)
461
      slices.push(array.slice(index, index+number));
462
    return slices.map(iterator);
463
  },
464

  
465
  all: function(iterator) {
466
    var result = true;
467
    this.each(function(value, index) {
468
      result = result && !!(iterator || Prototype.K)(value, index);
469
      if (!result) throw $break;
470
    });
471
    return result;
472
  },
473

  
474
  any: function(iterator) {
475
    var result = false;
476
    this.each(function(value, index) {
477
      if (result = !!(iterator || Prototype.K)(value, index))
478
        throw $break;
479
    });
480
    return result;
481
  },
482

  
483
  collect: function(iterator) {
484
    var results = [];
485
    this.each(function(value, index) {
486
      results.push((iterator || Prototype.K)(value, index));
487
    });
488
    return results;
489
  },
490

  
491
  detect: function(iterator) {
492
    var result;
493
    this.each(function(value, index) {
494
      if (iterator(value, index)) {
495
        result = value;
496
        throw $break;
497
      }
498
    });
499
    return result;
500
  },
501

  
502
  findAll: function(iterator) {
503
    var results = [];
504
    this.each(function(value, index) {
505
      if (iterator(value, index))
506
        results.push(value);
507
    });
508
    return results;
509
  },
510

  
511
  grep: function(pattern, iterator) {
512
    var results = [];
513
    this.each(function(value, index) {
514
      var stringValue = value.toString();
515
      if (stringValue.match(pattern))
516
        results.push((iterator || Prototype.K)(value, index));
517
    })
518
    return results;
519
  },
520

  
521
  include: function(object) {
522
    var found = false;
523
    this.each(function(value) {
524
      if (value == object) {
525
        found = true;
526
        throw $break;
527
      }
528
    });
529
    return found;
530
  },
531

  
532
  inGroupsOf: function(number, fillWith) {
533
    fillWith = fillWith === undefined ? null : fillWith;
534
    return this.eachSlice(number, function(slice) {
535
      while(slice.length < number) slice.push(fillWith);
536
      return slice;
537
    });
538
  },
539

  
540
  inject: function(memo, iterator) {
541
    this.each(function(value, index) {
542
      memo = iterator(memo, value, index);
543
    });
544
    return memo;
545
  },
546

  
547
  invoke: function(method) {
548
    var args = $A(arguments).slice(1);
549
    return this.map(function(value) {
550
      return value[method].apply(value, args);
551
    });
552
  },
553

  
554
  max: function(iterator) {
555
    var result;
556
    this.each(function(value, index) {
557
      value = (iterator || Prototype.K)(value, index);
558
      if (result == undefined || value >= result)
559
        result = value;
560
    });
561
    return result;
562
  },
563

  
564
  min: function(iterator) {
565
    var result;
566
    this.each(function(value, index) {
567
      value = (iterator || Prototype.K)(value, index);
568
      if (result == undefined || value < result)
569
        result = value;
570
    });
571
    return result;
572
  },
573

  
574
  partition: function(iterator) {
575
    var trues = [], falses = [];
576
    this.each(function(value, index) {
577
      ((iterator || Prototype.K)(value, index) ?
578
        trues : falses).push(value);
579
    });
580
    return [trues, falses];
581
  },
582

  
583
  pluck: function(property) {
584
    var results = [];
585
    this.each(function(value, index) {
586
      results.push(value[property]);
587
    });
588
    return results;
589
  },
590

  
591
  reject: function(iterator) {
592
    var results = [];
593
    this.each(function(value, index) {
594
      if (!iterator(value, index))
595
        results.push(value);
596
    });
597
    return results;
598
  },
599

  
600
  sortBy: function(iterator) {
601
    return this.map(function(value, index) {
602
      return {value: value, criteria: iterator(value, index)};
603
    }).sort(function(left, right) {
604
      var a = left.criteria, b = right.criteria;
605
      return a < b ? -1 : a > b ? 1 : 0;
606
    }).pluck('value');
607
  },
608

  
609
  toArray: function() {
610
    return this.map();
611
  },
612

  
613
  zip: function() {
614
    var iterator = Prototype.K, args = $A(arguments);
615
    if (typeof args.last() == 'function')
616
      iterator = args.pop();
617

  
618
    var collections = [this].concat(args).map($A);
619
    return this.map(function(value, index) {
620
      return iterator(collections.pluck(index));
621
    });
622
  },
623

  
624
  size: function() {
625
    return this.toArray().length;
626
  },
627

  
628
  inspect: function() {
629
    return '#<Enumerable:' + this.toArray().inspect() + '>';
630
  }
631
}
632

  
633
Object.extend(Enumerable, {
634
  map:     Enumerable.collect,
635
  find:    Enumerable.detect,
636
  select:  Enumerable.findAll,
637
  member:  Enumerable.include,
638
  entries: Enumerable.toArray
639
});
640
var $A = Array.from = function(iterable) {
641
  if (!iterable) return [];
642
  if (iterable.toArray) {
643
    return iterable.toArray();
644
  } else {
645
    var results = [];
646
    for (var i = 0, length = iterable.length; i < length; i++)
647
      results.push(iterable[i]);
648
    return results;
649
  }
650
}
651

  
652
if (Prototype.Browser.WebKit) {
653
  $A = Array.from = function(iterable) {
654
    if (!iterable) return [];
655
    if (!(typeof iterable == 'function' && iterable == '[object NodeList]') &&
656
      iterable.toArray) {
657
      return iterable.toArray();
658
    } else {
659
      var results = [];
660
      for (var i = 0, length = iterable.length; i < length; i++)
661
        results.push(iterable[i]);
662
      return results;
663
    }
664
  }
665
}
666

  
667
Object.extend(Array.prototype, Enumerable);
668

  
669
if (!Array.prototype._reverse)
670
  Array.prototype._reverse = Array.prototype.reverse;
671

  
672
Object.extend(Array.prototype, {
673
  _each: function(iterator) {
674
    for (var i = 0, length = this.length; i < length; i++)
675
      iterator(this[i]);
676
  },
677

  
678
  clear: function() {
679
    this.length = 0;
680
    return this;
681
  },
682

  
683
  first: function() {
684
    return this[0];
685
  },
686

  
687
  last: function() {
688
    return this[this.length - 1];
689
  },
690

  
691
  compact: function() {
692
    return this.select(function(value) {
693
      return value != null;
694
    });
695
  },
696

  
697
  flatten: function() {
698
    return this.inject([], function(array, value) {
699
      return array.concat(value && value.constructor == Array ?
700
        value.flatten() : [value]);
701
    });
702
  },
703

  
704
  without: function() {
705
    var values = $A(arguments);
706
    return this.select(function(value) {
707
      return !values.include(value);
708
    });
709
  },
710

  
711
  indexOf: function(object) {
712
    for (var i = 0, length = this.length; i < length; i++)
713
      if (this[i] == object) return i;
714
    return -1;
715
  },
716

  
717
  reverse: function(inline) {
718
    return (inline !== false ? this : this.toArray())._reverse();
719
  },
720

  
721
  reduce: function() {
722
    return this.length > 1 ? this : this[0];
723
  },
724

  
725
  uniq: function(sorted) {
726
    return this.inject([], function(array, value, index) {
727
      if (0 == index || (sorted ? array.last() != value : !array.include(value)))
728
        array.push(value);
729
      return array;
730
    });
731
  },
732

  
733
  clone: function() {
734
    return [].concat(this);
735
  },
736

  
737
  size: function() {
738
    return this.length;
739
  },
740

  
741
  inspect: function() {
742
    return '[' + this.map(Object.inspect).join(', ') + ']';
743
  },
744

  
745
  toJSON: function() {
746
    var results = [];
747
    this.each(function(object) {
748
      var value = Object.toJSON(object);
749
      if (value !== undefined) results.push(value);
750
    });
751
    return '[' + results.join(', ') + ']';
752
  }
753
});
754

  
755
Array.prototype.toArray = Array.prototype.clone;
756

  
757
function $w(string) {
758
  string = string.strip();
759
  return string ? string.split(/\s+/) : [];
760
}
761

  
762
if (Prototype.Browser.Opera){
763
  Array.prototype.concat = function() {
764
    var array = [];
765
    for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
766
    for (var i = 0, length = arguments.length; i < length; i++) {
767
      if (arguments[i].constructor == Array) {
768
        for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
769
          array.push(arguments[i][j]);
770
      } else {
771
        array.push(arguments[i]);
772
      }
773
    }
774
    return array;
775
  }
776
}
777
var Hash = function(object) {
778
  if (object instanceof Hash) this.merge(object);
779
  else Object.extend(this, object || {});
780
};
781

  
782
Object.extend(Hash, {
783
  toQueryString: function(obj) {
784
    var parts = [];
785
    parts.add = arguments.callee.addPair;
786

  
787
    this.prototype._each.call(obj, function(pair) {
788
      if (!pair.key) return;
789
      var value = pair.value;
790

  
791
      if (value && typeof value == 'object') {
792
        if (value.constructor == Array) value.each(function(value) {
793
          parts.add(pair.key, value);
794
        });
795
        return;
796
      }
797
      parts.add(pair.key, value);
798
    });
799

  
800
    return parts.join('&');
801
  },
802

  
803
  toJSON: function(object) {
804
    var results = [];
805
    this.prototype._each.call(object, function(pair) {
806
      var value = Object.toJSON(pair.value);
807
      if (value !== undefined) results.push(pair.key.toJSON() + ': ' + value);
808
    });
809
    return '{' + results.join(', ') + '}';
810
  }
811
});
812

  
813
Hash.toQueryString.addPair = function(key, value, prefix) {
814
  key = encodeURIComponent(key);
815
  if (value === undefined) this.push(key);
816
  else this.push(key + '=' + (value == null ? '' : encodeURIComponent(value)));
817
}
818

  
819
Object.extend(Hash.prototype, Enumerable);
820
Object.extend(Hash.prototype, {
821
  _each: function(iterator) {
822
    for (var key in this) {
823
      var value = this[key];
824
      if (value && value == Hash.prototype[key]) continue;
825

  
826
      var pair = [key, value];
827
      pair.key = key;
828
      pair.value = value;
829
      iterator(pair);
830
    }
831
  },
832

  
833
  keys: function() {
834
    return this.pluck('key');
835
  },
836

  
837
  values: function() {
838
    return this.pluck('value');
839
  },
840

  
841
  merge: function(hash) {
842
    return $H(hash).inject(this, function(mergedHash, pair) {
843
      mergedHash[pair.key] = pair.value;
844
      return mergedHash;
845
    });
846
  },
847

  
848
  remove: function() {
849
    var result;
850
    for(var i = 0, length = arguments.length; i < length; i++) {
851
      var value = this[arguments[i]];
852
      if (value !== undefined){
853
        if (result === undefined) result = value;
854
        else {
855
          if (result.constructor != Array) result = [result];
856
          result.push(value)
857
        }
858
      }
859
      delete this[arguments[i]];
860
    }
861
    return result;
862
  },
863

  
864
  toQueryString: function() {
865
    return Hash.toQueryString(this);
866
  },
867

  
868
  inspect: function() {
869
    return '#<Hash:{' + this.map(function(pair) {
870
      return pair.map(Object.inspect).join(': ');
871
    }).join(', ') + '}>';
872
  },
873

  
874
  toJSON: function() {
875
    return Hash.toJSON(this);
876
  }
877
});
878

  
879
function $H(object) {
880
  if (object instanceof Hash) return object;
881
  return new Hash(object);
882
};
883

  
884
// Safari iterates over shadowed properties
885
if (function() {
886
  var i = 0, Test = function(value) { this.key = value };
887
  Test.prototype.key = 'foo';
888
  for (var property in new Test('bar')) i++;
889
  return i > 1;
890
}()) Hash.prototype._each = function(iterator) {
891
  var cache = [];
892
  for (var key in this) {
893
    var value = this[key];
894
    if ((value && value == Hash.prototype[key]) || cache.include(key)) continue;
895
    cache.push(key);
896
    var pair = [key, value];
897
    pair.key = key;
898
    pair.value = value;
899
    iterator(pair);
900
  }
901
};
902
ObjectRange = Class.create();
903
Object.extend(ObjectRange.prototype, Enumerable);
904
Object.extend(ObjectRange.prototype, {
905
  initialize: function(start, end, exclusive) {
906
    this.start = start;
907
    this.end = end;
908
    this.exclusive = exclusive;
909
  },
910

  
911
  _each: function(iterator) {
912
    var value = this.start;
913
    while (this.include(value)) {
914
      iterator(value);
915
      value = value.succ();
916
    }
917
  },
918

  
919
  include: function(value) {
920
    if (value < this.start)
921
      return false;
922
    if (this.exclusive)
923
      return value < this.end;
924
    return value <= this.end;
925
  }
926
});
927

  
928
var $R = function(start, end, exclusive) {
929
  return new ObjectRange(start, end, exclusive);
930
}
931

  
932
var Ajax = {
933
  getTransport: function() {
934
    return Try.these(
935
      function() {return new XMLHttpRequest()},
936
      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
937
      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
938
    ) || false;
939
  },
940

  
941
  activeRequestCount: 0
942
}
943

  
944
Ajax.Responders = {
945
  responders: [],
946

  
947
  _each: function(iterator) {
948
    this.responders._each(iterator);
949
  },
950

  
951
  register: function(responder) {
952
    if (!this.include(responder))
953
      this.responders.push(responder);
954
  },
955

  
956
  unregister: function(responder) {
957
    this.responders = this.responders.without(responder);
958
  },
959

  
960
  dispatch: function(callback, request, transport, json) {
961
    this.each(function(responder) {
962
      if (typeof responder[callback] == 'function') {
963
        try {
964
          responder[callback].apply(responder, [request, transport, json]);
965
        } catch (e) {}
966
      }
967
    });
968
  }
969
};
970

  
971
Object.extend(Ajax.Responders, Enumerable);
972

  
973
Ajax.Responders.register({
974
  onCreate: function() {
975
    Ajax.activeRequestCount++;
976
  },
977
  onComplete: function() {
978
    Ajax.activeRequestCount--;
979
  }
980
});
981

  
982
Ajax.Base = function() {};
983
Ajax.Base.prototype = {
984
  setOptions: function(options) {
985
    this.options = {
986
      method:       'post',
987
      asynchronous: true,
988
      contentType:  'application/x-www-form-urlencoded',
989
      encoding:     'UTF-8',
990
      parameters:   ''
991
    }
992
    Object.extend(this.options, options || {});
993

  
994
    this.options.method = this.options.method.toLowerCase();
995
    if (typeof this.options.parameters == 'string')
996
      this.options.parameters = this.options.parameters.toQueryParams();
997
  }
998
}
999

  
1000
Ajax.Request = Class.create();
1001
Ajax.Request.Events =
1002
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
1003

  
1004
Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
1005
  _complete: false,
1006

  
1007
  initialize: function(url, options) {
1008
    this.transport = Ajax.getTransport();
1009
    this.setOptions(options);
1010
    this.request(url);
1011
  },
1012

  
1013
  request: function(url) {
1014
    this.url = url;
1015
    this.method = this.options.method;
1016
    var params = Object.clone(this.options.parameters);
1017

  
1018
    if (!['get', 'post'].include(this.method)) {
1019
      // simulate other verbs over post
1020
      params['_method'] = this.method;
1021
      this.method = 'post';
1022
    }
1023

  
1024
    this.parameters = params;
1025

  
1026
    if (params = Hash.toQueryString(params)) {
1027
      // when GET, append parameters to URL
1028
      if (this.method == 'get')
1029
        this.url += (this.url.include('?') ? '&' : '?') + params;
1030
      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
1031
        params += '&_=';
1032
    }
1033

  
1034
    try {
1035
      if (this.options.onCreate) this.options.onCreate(this.transport);
1036
      Ajax.Responders.dispatch('onCreate', this, this.transport);
1037

  
1038
      this.transport.open(this.method.toUpperCase(), this.url,
1039
        this.options.asynchronous);
1040

  
1041
      if (this.options.asynchronous)
1042
        setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
1043

  
1044
      this.transport.onreadystatechange = this.onStateChange.bind(this);
1045
      this.setRequestHeaders();
1046

  
1047
      this.body = this.method == 'post' ? (this.options.postBody || params) : null;
1048
      this.transport.send(this.body);
1049

  
1050
      /* Force Firefox to handle ready state 4 for synchronous requests */
1051
      if (!this.options.asynchronous && this.transport.overrideMimeType)
1052
        this.onStateChange();
1053

  
1054
    }
1055
    catch (e) {
1056
      this.dispatchException(e);
1057
    }
1058
  },
1059

  
1060
  onStateChange: function() {
1061
    var readyState = this.transport.readyState;
1062
    if (readyState > 1 && !((readyState == 4) && this._complete))
1063
      this.respondToReadyState(this.transport.readyState);
1064
  },
1065

  
1066
  setRequestHeaders: function() {
1067
    var headers = {
1068
      'X-Requested-With': 'XMLHttpRequest',
1069
      'X-Prototype-Version': Prototype.Version,
1070
      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
1071
    };
1072

  
1073
    if (this.method == 'post') {
1074
      headers['Content-type'] = this.options.contentType +
1075
        (this.options.encoding ? '; charset=' + this.options.encoding : '');
1076

  
1077
      /* Force "Connection: close" for older Mozilla browsers to work
1078
       * around a bug where XMLHttpRequest sends an incorrect
1079
       * Content-length header. See Mozilla Bugzilla #246651.
1080
       */
1081
      if (this.transport.overrideMimeType &&
1082
          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
1083
            headers['Connection'] = 'close';
1084
    }
1085

  
1086
    // user-defined headers
1087
    if (typeof this.options.requestHeaders == 'object') {
1088
      var extras = this.options.requestHeaders;
1089

  
1090
      if (typeof extras.push == 'function')
1091
        for (var i = 0, length = extras.length; i < length; i += 2)
1092
          headers[extras[i]] = extras[i+1];
1093
      else
1094
        $H(extras).each(function(pair) { headers[pair.key] = pair.value });
1095
    }
1096

  
1097
    for (var name in headers)
1098
      this.transport.setRequestHeader(name, headers[name]);
1099
  },
1100

  
1101
  success: function() {
1102
    return !this.transport.status
1103
        || (this.transport.status >= 200 && this.transport.status < 300);
1104
  },
1105

  
1106
  respondToReadyState: function(readyState) {
1107
    var state = Ajax.Request.Events[readyState];
1108
    var transport = this.transport, json = this.evalJSON();
1109

  
1110
    if (state == 'Complete') {
1111
      try {
1112
        this._complete = true;
1113
        (this.options['on' + this.transport.status]
1114
         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
1115
         || Prototype.emptyFunction)(transport, json);
1116
      } catch (e) {
1117
        this.dispatchException(e);
1118
      }
1119

  
1120
      var contentType = this.getHeader('Content-type');
1121
      if (contentType && contentType.strip().
1122
        match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
1123
          this.evalResponse();
1124
    }
1125

  
1126
    try {
1127
      (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
1128
      Ajax.Responders.dispatch('on' + state, this, transport, json);
1129
    } catch (e) {
1130
      this.dispatchException(e);
1131
    }
1132

  
1133
    if (state == 'Complete') {
1134
      // avoid memory leak in MSIE: clean up
1135
      this.transport.onreadystatechange = Prototype.emptyFunction;
1136
    }
1137
  },
1138

  
1139
  getHeader: function(name) {
1140
    try {
1141
      return this.transport.getResponseHeader(name);
1142
    } catch (e) { return null }
1143
  },
1144

  
1145
  evalJSON: function() {
1146
    try {
1147
      var json = this.getHeader('X-JSON');
1148
      return json ? json.evalJSON() : null;
1149
    } catch (e) { return null }
1150
  },
1151

  
1152
  evalResponse: function() {
1153
    try {
1154
      return eval((this.transport.responseText || '').unfilterJSON());
1155
    } catch (e) {
1156
      this.dispatchException(e);
1157
    }
1158
  },
1159

  
1160
  dispatchException: function(exception) {
1161
    (this.options.onException || Prototype.emptyFunction)(this, exception);
1162
    Ajax.Responders.dispatch('onException', this, exception);
1163
  }
1164
});
1165

  
1166
Ajax.Updater = Class.create();
1167

  
1168
Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
1169
  initialize: function(container, url, options) {
1170
    this.container = {
1171
      success: (container.success || container),
1172
      failure: (container.failure || (container.success ? null : container))
1173
    }
1174

  
1175
    this.transport = Ajax.getTransport();
1176
    this.setOptions(options);
1177

  
1178
    var onComplete = this.options.onComplete || Prototype.emptyFunction;
1179
    this.options.onComplete = (function(transport, param) {
1180
      this.updateContent();
1181
      onComplete(transport, param);
1182
    }).bind(this);
1183

  
1184
    this.request(url);
1185
  },
1186

  
1187
  updateContent: function() {
1188
    var receiver = this.container[this.success() ? 'success' : 'failure'];
1189
    var response = this.transport.responseText;
1190

  
1191
    if (!this.options.evalScripts) response = response.stripScripts();
1192

  
1193
    if (receiver = $(receiver)) {
1194
      if (this.options.insertion)
1195
        new this.options.insertion(receiver, response);
1196
      else
1197
        receiver.update(response);
1198
    }
1199

  
1200
    if (this.success()) {
1201
      if (this.onComplete)
1202
        setTimeout(this.onComplete.bind(this), 10);
1203
    }
1204
  }
1205
});
1206

  
1207
Ajax.PeriodicalUpdater = Class.create();
1208
Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
1209
  initialize: function(container, url, options) {
1210
    this.setOptions(options);
1211
    this.onComplete = this.options.onComplete;
1212

  
1213
    this.frequency = (this.options.frequency || 2);
1214
    this.decay = (this.options.decay || 1);
1215

  
1216
    this.updater = {};
1217
    this.container = container;
1218
    this.url = url;
1219

  
1220
    this.start();
1221
  },
1222

  
1223
  start: function() {
1224
    this.options.onComplete = this.updateComplete.bind(this);
1225
    this.onTimerEvent();
1226
  },
1227

  
1228
  stop: function() {
1229
    this.updater.options.onComplete = undefined;
1230
    clearTimeout(this.timer);
1231
    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
1232
  },
1233

  
1234
  updateComplete: function(request) {
1235
    if (this.options.decay) {
1236
      this.decay = (request.responseText == this.lastText ?
1237
        this.decay * this.options.decay : 1);
1238

  
1239
      this.lastText = request.responseText;
1240
    }
1241
    this.timer = setTimeout(this.onTimerEvent.bind(this),
1242
      this.decay * this.frequency * 1000);
1243
  },
1244

  
1245
  onTimerEvent: function() {
1246
    this.updater = new Ajax.Updater(this.container, this.url, this.options);
1247
  }
1248
});
1249
function $(element) {
1250
  if (arguments.length > 1) {
1251
    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
1252
      elements.push($(arguments[i]));
1253
    return elements;
1254
  }
1255
  if (typeof element == 'string')
1256
    element = document.getElementById(element);
1257
  return Element.extend(element);
1258
}
1259

  
1260
if (Prototype.BrowserFeatures.XPath) {
1261
  document._getElementsByXPath = function(expression, parentElement) {
1262
    var results = [];
1263
    var query = document.evaluate(expression, $(parentElement) || document,
1264
      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
1265
    for (var i = 0, length = query.snapshotLength; i < length; i++)
1266
      results.push(query.snapshotItem(i));
1267
    return results;
1268
  };
1269

  
1270
  document.getElementsByClassName = function(className, parentElement) {
1271
    var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
1272
    return document._getElementsByXPath(q, parentElement);
1273
  }
1274

  
1275
} else document.getElementsByClassName = function(className, parentElement) {
1276
  var children = ($(parentElement) || document.body).getElementsByTagName('*');
1277
  var elements = [], child, pattern = new RegExp("(^|\\s)" + className + "(\\s|$)");
1278
  for (var i = 0, length = children.length; i < length; i++) {
1279
    child = children[i];
1280
    var elementClassName = child.className;
1281
    if (elementClassName.length == 0) continue;
1282
    if (elementClassName == className || elementClassName.match(pattern))
1283
      elements.push(Element.extend(child));
1284
  }
1285
  return elements;
1286
};
1287

  
1288
/*--------------------------------------------------------------------------*/
1289

  
1290
if (!window.Element) var Element = {};
1291

  
1292
Element.extend = function(element) {
1293
  var F = Prototype.BrowserFeatures;
1294
  if (!element || !element.tagName || element.nodeType == 3 ||
1295
   element._extended || F.SpecificElementExtensions || element == window)
1296
    return element;
1297

  
1298
  var methods = {}, tagName = element.tagName, cache = Element.extend.cache,
1299
   T = Element.Methods.ByTag;
1300

  
1301
  // extend methods for all tags (Safari doesn't need this)
1302
  if (!F.ElementExtensions) {
1303
    Object.extend(methods, Element.Methods),
1304
    Object.extend(methods, Element.Methods.Simulated);
1305
  }
1306

  
1307
  // extend methods for specific tags
1308
  if (T[tagName]) Object.extend(methods, T[tagName]);
1309

  
1310
  for (var property in methods) {
1311
    var value = methods[property];
1312
    if (typeof value == 'function' && !(property in element))
1313
      element[property] = cache.findOrStore(value);
1314
  }
1315

  
1316
  element._extended = Prototype.emptyFunction;
1317
  return element;
1318
};
1319

  
1320
Element.extend.cache = {
1321
  findOrStore: function(value) {
1322
    return this[value] = this[value] || function() {
1323
      return value.apply(null, [this].concat($A(arguments)));
1324
    }
1325
  }
1326
};
1327

  
1328
Element.Methods = {
1329
  visible: function(element) {
1330
    return $(element).style.display != 'none';
1331
  },
1332

  
1333
  toggle: function(element) {
1334
    element = $(element);
1335
    Element[Element.visible(element) ? 'hide' : 'show'](element);
1336
    return element;
1337
  },
1338

  
1339
  hide: function(element) {
1340
    $(element).style.display = 'none';
1341
    return element;
1342
  },
1343

  
1344
  show: function(element) {
1345
    $(element).style.display = '';
1346
    return element;
1347
  },
1348

  
1349
  remove: function(element) {
1350
    element = $(element);
1351
    element.parentNode.removeChild(element);
1352
    return element;
1353
  },
1354

  
1355
  update: function(element, html) {
1356
    html = typeof html == 'undefined' ? '' : html.toString();
1357
    $(element).innerHTML = html.stripScripts();
1358
    setTimeout(function() {html.evalScripts()}, 10);
1359
    return element;
1360
  },
1361

  
1362
  replace: function(element, html) {
1363
    element = $(element);
1364
    html = typeof html == 'undefined' ? '' : html.toString();
1365
    if (element.outerHTML) {
1366
      element.outerHTML = html.stripScripts();
1367
    } else {
1368
      var range = element.ownerDocument.createRange();
1369
      range.selectNodeContents(element);
1370
      element.parentNode.replaceChild(
1371
        range.createContextualFragment(html.stripScripts()), element);
1372
    }
1373
    setTimeout(function() {html.evalScripts()}, 10);
1374
    return element;
1375
  },
1376

  
1377
  inspect: function(element) {
1378
    element = $(element);
1379
    var result = '<' + element.tagName.toLowerCase();
1380
    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
1381
      var property = pair.first(), attribute = pair.last();
1382
      var value = (element[property] || '').toString();
1383
      if (value) result += ' ' + attribute + '=' + value.inspect(true);
1384
    });
1385
    return result + '>';
1386
  },
1387

  
1388
  recursivelyCollect: function(element, property) {
1389
    element = $(element);
1390
    var elements = [];
1391
    while (element = element[property])
1392
      if (element.nodeType == 1)
1393
        elements.push(Element.extend(element));
1394
    return elements;
1395
  },
1396

  
1397
  ancestors: function(element) {
1398
    return $(element).recursivelyCollect('parentNode');
1399
  },
1400

  
1401
  descendants: function(element) {
1402
    return $A($(element).getElementsByTagName('*')).each(Element.extend);
1403
  },
1404

  
1405
  firstDescendant: function(element) {
1406
    element = $(element).firstChild;
1407
    while (element && element.nodeType != 1) element = element.nextSibling;
1408
    return $(element);
1409
  },
1410

  
1411
  immediateDescendants: function(element) {
1412
    if (!(element = $(element).firstChild)) return [];
1413
    while (element && element.nodeType != 1) element = element.nextSibling;
1414
    if (element) return [element].concat($(element).nextSiblings());
1415
    return [];
1416
  },
1417

  
1418
  previousSiblings: function(element) {
1419
    return $(element).recursivelyCollect('previousSibling');
1420
  },
1421

  
1422
  nextSiblings: function(element) {
1423
    return $(element).recursivelyCollect('nextSibling');
1424
  },
1425

  
1426
  siblings: function(element) {
1427
    element = $(element);
1428
    return element.previousSiblings().reverse().concat(element.nextSiblings());
1429
  },
1430

  
1431
  match: function(element, selector) {
1432
    if (typeof selector == 'string')
1433
      selector = new Selector(selector);
1434
    return selector.match($(element));
1435
  },
1436

  
1437
  up: function(element, expression, index) {
1438
    element = $(element);
1439
    if (arguments.length == 1) return $(element.parentNode);
1440
    var ancestors = element.ancestors();
1441
    return expression ? Selector.findElement(ancestors, expression, index) :
1442
      ancestors[index || 0];
1443
  },
1444

  
1445
  down: function(element, expression, index) {
1446
    element = $(element);
1447
    if (arguments.length == 1) return element.firstDescendant();
1448
    var descendants = element.descendants();
1449
    return expression ? Selector.findElement(descendants, expression, index) :
1450
      descendants[index || 0];
1451
  },
1452

  
1453
  previous: function(element, expression, index) {
1454
    element = $(element);
1455
    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
1456
    var previousSiblings = element.previousSiblings();
1457
    return expression ? Selector.findElement(previousSiblings, expression, index) :
1458
      previousSiblings[index || 0];
1459
  },
1460

  
1461
  next: function(element, expression, index) {
1462
    element = $(element);
1463
    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
1464
    var nextSiblings = element.nextSiblings();
1465
    return expression ? Selector.findElement(nextSiblings, expression, index) :
1466
      nextSiblings[index || 0];
1467
  },
1468

  
1469
  getElementsBySelector: function() {
1470
    var args = $A(arguments), element = $(args.shift());
1471
    return Selector.findChildElements(element, args);
1472
  },
1473

  
1474
  getElementsByClassName: function(element, className) {
1475
    return document.getElementsByClassName(className, element);
1476
  },
1477

  
1478
  readAttribute: function(element, name) {
1479
    element = $(element);
1480
    if (Prototype.Browser.IE) {
1481
      if (!element.attributes) return null;
1482
      var t = Element._attributeTranslations;
1483
      if (t.values[name]) return t.values[name](element, name);
1484
      if (t.names[name])  name = t.names[name];
1485
      var attribute = element.attributes[name];
1486
      return attribute ? attribute.nodeValue : null;
1487
    }
1488
    return element.getAttribute(name);
1489
  },
1490

  
1491
  getHeight: function(element) {
1492
    return $(element).getDimensions().height;
1493
  },
1494

  
1495
  getWidth: function(element) {
1496
    return $(element).getDimensions().width;
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff