PageRenderTime 113ms CodeModel.GetById 15ms app.highlight 83ms RepoModel.GetById 1ms app.codeStats 1ms

/dozer/media/javascript/prototype.js

https://bitbucket.org/bbangert/dozer/
JavaScript | 2337 lines | 2088 code | 219 blank | 30 comment | 269 complexity | ed2d6608b0832c5e990e10729157b485 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   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
   9var 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
  20var Class = {
  21  create: function() {
  22    return function() {
  23      this.initialize.apply(this, arguments);
  24    }
  25  }
  26}
  27
  28var Abstract = new Object();
  29
  30Object.extend = function(destination, source) {
  31  for (var property in source) {
  32    destination[property] = source[property];
  33  }
  34  return destination;
  35}
  36
  37Object.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
  68Function.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
  75Function.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
  82Object.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
  99var 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
 117var PeriodicalExecuter = Class.create();
 118PeriodicalExecuter.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}
 148String.interpret = function(value){
 149  return value == null ? '' : String(value);
 150}
 151
 152Object.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
 294String.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
 300String.prototype.parseQuery = String.prototype.toQueryParams;
 301
 302var Template = Class.create();
 303Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
 304Template.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
 319var $break    = new Object();
 320var $continue = new Object();
 321
 322var 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
 514Object.extend(Enumerable, {
 515  map:     Enumerable.collect,
 516  find:    Enumerable.detect,
 517  select:  Enumerable.findAll,
 518  member:  Enumerable.include,
 519  entries: Enumerable.toArray
 520});
 521var $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
 533Object.extend(Array.prototype, Enumerable);
 534
 535if (!Array.prototype._reverse)
 536  Array.prototype._reverse = Array.prototype.reverse;
 537
 538Object.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
 610Array.prototype.toArray = Array.prototype.clone;
 611
 612function $w(string){
 613  string = string.strip();
 614  return string ? string.split(/\s+/) : [];
 615}
 616
 617if(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}
 632var Hash = function(obj) {
 633  Object.extend(this, obj || {});
 634};
 635
 636Object.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
 663Object.extend(Hash.prototype, Enumerable);
 664Object.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
 719function $H(object) {
 720  if (object && object.constructor == Hash) return object;
 721  return new Hash(object);
 722};
 723ObjectRange = Class.create();
 724Object.extend(ObjectRange.prototype, Enumerable);
 725Object.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
 749var $R = function(start, end, exclusive) {
 750  return new ObjectRange(start, end, exclusive);
 751}
 752
 753var 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
 765Ajax.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
 792Object.extend(Ajax.Responders, Enumerable);
 793
 794Ajax.Responders.register({
 795  onCreate: function() {
 796    Ajax.activeRequestCount++;
 797  },
 798  onComplete: function() {
 799    Ajax.activeRequestCount--;
 800  }
 801});
 802
 803Ajax.Base = function() {};
 804Ajax.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
 821Ajax.Request = Class.create();
 822Ajax.Request.Events =
 823  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
 824
 825Ajax.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
 983Ajax.Updater = Class.create();
 984
 985Object.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
1024Ajax.PeriodicalUpdater = Class.create();
1025Ajax.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});
1066function $(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
1077if (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
1088document.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
1106if (!window.Element)
1107  var Element = new Object();
1108
1109Element.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
1133Element.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
1141Element.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
1486Object.extend(Element.Methods, {childOf: Element.Methods.descendantOf});
1487
1488Element._attributeTranslations = {};
1489
1490Element._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
1503Element._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
1522Object.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
1531Element.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
1540if (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
1576Object.extend(Element, Element.Methods);
1577
1578var _nativeExtensions = false;
1579
1580if(/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
1588Element.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
1612var Toggle = new Object();
1613Toggle.display = Element.toggle;
1614
1615/*--------------------------------------------------------------------------*/
1616
1617Abstract.Insertion = function(adjacency) {
1618  this.adjacency = adjacency;
1619}
1620
1621Abstract.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
1653var Insertion = new Object();
1654
1655Insertion.Before = Class.create();
1656Insertion.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
1668Insertion.Top = Class.create();
1669Insertion.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
1682Insertion.Bottom = Class.create();
1683Insertion.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
1696Insertion.After = Class.create();
1697Insertion.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
1712Element.ClassNames = Class.create();
1713Element.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
1743Object.extend(Element.ClassNames.prototype, Enumerable);
1744var Selector = Class.create();
1745Selector.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.inspe

Large files files are truncated, but you can click here to view the full file