Changeset 618 for trunk/packages


Ignore:
Timestamp:
Jun 21, 2008, 6:43:15 PM (16 years ago)
Author:
geofft
Message:

Apply a background color to every other VM, and move the power button to the left,
closer to the VM name.

Upgraded prototype.js to 1.6.

Location:
trunk/packages/sipb-xen-www/code
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/packages/sipb-xen-www/code/static/prototype.js

    r205 r618  
    1 /*  Prototype JavaScript framework, version 1.5.1.1
    2  *  (c) 2005-2007 Sam Stephenson
     1/*  Prototype JavaScript framework, version 1.6.0.2
     2 *  (c) 2005-2008 Sam Stephenson
    33 *
    44 *  Prototype is freely distributable under the terms of an MIT-style license.
    55 *  For details, see the Prototype web site: http://www.prototypejs.org/
    66 *
    7 /*--------------------------------------------------------------------------*/
     7 *--------------------------------------------------------------------------*/
    88
    99var Prototype = {
    10   Version: '1.5.1.1',
     10  Version: '1.6.0.2',
    1111
    1212  Browser: {
     
    1414    Opera:  !!window.opera,
    1515    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
    16     Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1
     16    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
     17    MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
    1718  },
    1819
     
    2122    ElementExtensions: !!window.HTMLElement,
    2223    SpecificElementExtensions:
    23       (document.createElement('div').__proto__ !==
    24        document.createElement('form').__proto__)
     24      document.createElement('div').__proto__ &&
     25      document.createElement('div').__proto__ !==
     26        document.createElement('form').__proto__
    2527  },
    2628
     
    3032  emptyFunction: function() { },
    3133  K: function(x) { return x }
    32 }
    33 
     34};
     35
     36if (Prototype.Browser.MobileSafari)
     37  Prototype.BrowserFeatures.SpecificElementExtensions = false;
     38
     39
     40/* Based on Alex Arnell's inheritance implementation. */
    3441var Class = {
    3542  create: function() {
    36     return function() {
     43    var parent = null, properties = $A(arguments);
     44    if (Object.isFunction(properties[0]))
     45      parent = properties.shift();
     46
     47    function klass() {
    3748      this.initialize.apply(this, arguments);
    3849    }
    39   }
    40 }
    41 
    42 var Abstract = new Object();
     50
     51    Object.extend(klass, Class.Methods);
     52    klass.superclass = parent;
     53    klass.subclasses = [];
     54
     55    if (parent) {
     56      var subclass = function() { };
     57      subclass.prototype = parent.prototype;
     58      klass.prototype = new subclass;
     59      parent.subclasses.push(klass);
     60    }
     61
     62    for (var i = 0; i < properties.length; i++)
     63      klass.addMethods(properties[i]);
     64
     65    if (!klass.prototype.initialize)
     66      klass.prototype.initialize = Prototype.emptyFunction;
     67
     68    klass.prototype.constructor = klass;
     69
     70    return klass;
     71  }
     72};
     73
     74Class.Methods = {
     75  addMethods: function(source) {
     76    var ancestor   = this.superclass && this.superclass.prototype;
     77    var properties = Object.keys(source);
     78
     79    if (!Object.keys({ toString: true }).length)
     80      properties.push("toString", "valueOf");
     81
     82    for (var i = 0, length = properties.length; i < length; i++) {
     83      var property = properties[i], value = source[property];
     84      if (ancestor && Object.isFunction(value) &&
     85          value.argumentNames().first() == "$super") {
     86        var method = value, value = Object.extend((function(m) {
     87          return function() { return ancestor[m].apply(this, arguments) };
     88        })(property).wrap(method), {
     89          valueOf:  function() { return method },
     90          toString: function() { return method.toString() }
     91        });
     92      }
     93      this.prototype[property] = value;
     94    }
     95
     96    return this;
     97  }
     98};
     99
     100var Abstract = { };
    43101
    44102Object.extend = function(destination, source) {
    45   for (var property in source) {
     103  for (var property in source)
    46104    destination[property] = source[property];
    47   }
    48105  return destination;
    49 }
     106};
    50107
    51108Object.extend(Object, {
    52109  inspect: function(object) {
    53110    try {
    54       if (object === undefined) return 'undefined';
     111      if (Object.isUndefined(object)) return 'undefined';
    55112      if (object === null) return 'null';
    56       return object.inspect ? object.inspect() : object.toString();
     113      return object.inspect ? object.inspect() : String(object);
    57114    } catch (e) {
    58115      if (e instanceof RangeError) return '...';
     
    63120  toJSON: function(object) {
    64121    var type = typeof object;
    65     switch(type) {
     122    switch (type) {
    66123      case 'undefined':
    67124      case 'function':
     
    69126      case 'boolean': return object.toString();
    70127    }
     128
    71129    if (object === null) return 'null';
    72130    if (object.toJSON) return object.toJSON();
    73     if (object.ownerDocument === document) return;
     131    if (Object.isElement(object)) return;
     132
    74133    var results = [];
    75134    for (var property in object) {
    76135      var value = Object.toJSON(object[property]);
    77       if (value !== undefined)
     136      if (!Object.isUndefined(value))
    78137        results.push(property.toJSON() + ': ' + value);
    79138    }
     139
    80140    return '{' + results.join(', ') + '}';
     141  },
     142
     143  toQueryString: function(object) {
     144    return $H(object).toQueryString();
     145  },
     146
     147  toHTML: function(object) {
     148    return object && object.toHTML ? object.toHTML() : String.interpret(object);
    81149  },
    82150
     
    96164
    97165  clone: function(object) {
    98     return Object.extend({}, object);
     166    return Object.extend({ }, object);
     167  },
     168
     169  isElement: function(object) {
     170    return object && object.nodeType == 1;
     171  },
     172
     173  isArray: function(object) {
     174    return object != null && typeof object == "object" &&
     175      'splice' in object && 'join' in object;
     176  },
     177
     178  isHash: function(object) {
     179    return object instanceof Hash;
     180  },
     181
     182  isFunction: function(object) {
     183    return typeof object == "function";
     184  },
     185
     186  isString: function(object) {
     187    return typeof object == "string";
     188  },
     189
     190  isNumber: function(object) {
     191    return typeof object == "number";
     192  },
     193
     194  isUndefined: function(object) {
     195    return typeof object == "undefined";
    99196  }
    100197});
    101198
    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';
     199Object.extend(Function.prototype, {
     200  argumentNames: function() {
     201    var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip");
     202    return names.length == 1 && !names[0] ? [] : names;
     203  },
     204
     205  bind: function() {
     206    if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
     207    var __method = this, args = $A(arguments), object = args.shift();
     208    return function() {
     209      return __method.apply(object, args.concat($A(arguments)));
     210    }
     211  },
     212
     213  bindAsEventListener: function() {
     214    var __method = this, args = $A(arguments), object = args.shift();
     215    return function(event) {
     216      return __method.apply(object, [event || window.event].concat(args));
     217    }
     218  },
     219
     220  curry: function() {
     221    if (!arguments.length) return this;
     222    var __method = this, args = $A(arguments);
     223    return function() {
     224      return __method.apply(this, args.concat($A(arguments)));
     225    }
     226  },
     227
     228  delay: function() {
     229    var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
     230    return window.setTimeout(function() {
     231      return __method.apply(__method, args);
     232    }, timeout);
     233  },
     234
     235  wrap: function(wrapper) {
     236    var __method = this;
     237    return function() {
     238      return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
     239    }
     240  },
     241
     242  methodize: function() {
     243    if (this._methodized) return this._methodized;
     244    var __method = this;
     245    return this._methodized = function() {
     246      return __method.apply(null, [this].concat($A(arguments)));
     247    };
    137248  }
    138249});
    139250
     251Function.prototype.defer = Function.prototype.delay.curry(0.01);
     252
    140253Date.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) + '"';
     254  return '"' + this.getUTCFullYear() + '-' +
     255    (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
     256    this.getUTCDate().toPaddedString(2) + 'T' +
     257    this.getUTCHours().toPaddedString(2) + ':' +
     258    this.getUTCMinutes().toPaddedString(2) + ':' +
     259    this.getUTCSeconds().toPaddedString(2) + 'Z"';
    147260};
    148261
     
    156269        returnValue = lambda();
    157270        break;
    158       } catch (e) {}
     271      } catch (e) { }
    159272    }
    160273
    161274    return returnValue;
    162275  }
    163 }
     276};
     277
     278RegExp.prototype.match = RegExp.prototype.test;
     279
     280RegExp.escape = function(str) {
     281  return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
     282};
    164283
    165284/*--------------------------------------------------------------------------*/
    166285
    167 var PeriodicalExecuter = Class.create();
    168 PeriodicalExecuter.prototype = {
     286var PeriodicalExecuter = Class.create({
    169287  initialize: function(callback, frequency) {
    170288    this.callback = callback;
     
    179297  },
    180298
     299  execute: function() {
     300    this.callback(this);
     301  },
     302
    181303  stop: function() {
    182304    if (!this.timer) return;
     
    189311      try {
    190312        this.currentlyExecuting = true;
    191         this.callback(this);
     313        this.execute();
    192314      } finally {
    193315        this.currentlyExecuting = false;
     
    195317    }
    196318  }
    197 }
     319});
    198320Object.extend(String, {
    199321  interpret: function(value) {
     
    229351  sub: function(pattern, replacement, count) {
    230352    replacement = this.gsub.prepareReplacement(replacement);
    231     count = count === undefined ? 1 : count;
     353    count = Object.isUndefined(count) ? 1 : count;
    232354
    233355    return this.gsub(pattern, function(match) {
     
    239361  scan: function(pattern, iterator) {
    240362    this.gsub(pattern, iterator);
    241     return this;
     363    return String(this);
    242364  },
    243365
    244366  truncate: function(length, truncation) {
    245367    length = length || 30;
    246     truncation = truncation === undefined ? '...' : truncation;
     368    truncation = Object.isUndefined(truncation) ? '...' : truncation;
    247369    return this.length > length ?
    248       this.slice(0, length - truncation.length) + truncation : this;
     370      this.slice(0, length - truncation.length) + truncation : String(this);
    249371  },
    250372
     
    280402
    281403  unescapeHTML: function() {
    282     var div = document.createElement('div');
     404    var div = new Element('div');
    283405    div.innerHTML = this.stripTags();
    284406    return div.childNodes[0] ? (div.childNodes.length > 1 ?
     
    289411  toQueryParams: function(separator) {
    290412    var match = this.strip().match(/([^?#]*)(#.*)?$/);
    291     if (!match) return {};
    292 
    293     return match[1].split(separator || '&').inject({}, function(hash, pair) {
     413    if (!match) return { };
     414
     415    return match[1].split(separator || '&').inject({ }, function(hash, pair) {
    294416      if ((pair = pair.split('='))[0]) {
    295417        var key = decodeURIComponent(pair.shift());
     
    298420
    299421        if (key in hash) {
    300           if (hash[key].constructor != Array) hash[key] = [hash[key]];
     422          if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
    301423          hash[key].push(value);
    302424        }
     
    317439
    318440  times: function(count) {
    319     var result = '';
    320     for (var i = 0; i < count; i++) result += this;
    321     return result;
     441    return count < 1 ? '' : new Array(count + 1).join(this);
    322442  },
    323443
     
    366486
    367487  isJSON: function() {
    368     var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
     488    var str = this;
     489    if (str.blank()) return false;
     490    str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
    369491    return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
    370492  },
     
    397519  blank: function() {
    398520    return /^\s*$/.test(this);
     521  },
     522
     523  interpolate: function(object, pattern) {
     524    return new Template(this, pattern).evaluate(object);
    399525  }
    400526});
     
    410536
    411537String.prototype.gsub.prepareReplacement = function(replacement) {
    412   if (typeof replacement == 'function') return replacement;
     538  if (Object.isFunction(replacement)) return replacement;
    413539  var template = new Template(replacement);
    414540  return function(match) { return template.evaluate(match) };
    415 }
     541};
    416542
    417543String.prototype.parseQuery = String.prototype.toQueryParams;
     
    424550with (String.prototype.escapeHTML) div.appendChild(text);
    425551
    426 var Template = Class.create();
    427 Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
    428 Template.prototype = {
     552var Template = Class.create({
    429553  initialize: function(template, pattern) {
    430554    this.template = template.toString();
    431     this.pattern  = pattern || Template.Pattern;
     555    this.pattern = pattern || Template.Pattern;
    432556  },
    433557
    434558  evaluate: function(object) {
     559    if (Object.isFunction(object.toTemplateReplacements))
     560      object = object.toTemplateReplacements();
     561
    435562    return this.template.gsub(this.pattern, function(match) {
    436       var before = match[1];
     563      if (object == null) return '';
     564
     565      var before = match[1] || '';
    437566      if (before == '\\') return match[2];
    438       return before + String.interpret(object[match[3]]);
     567
     568      var ctx = object, expr = match[3];
     569      var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
     570      match = pattern.exec(expr);
     571      if (match == null) return before;
     572
     573      while (match != null) {
     574        var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
     575        ctx = ctx[comp];
     576        if (null == ctx || '' == match[3]) break;
     577        expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
     578        match = pattern.exec(expr);
     579      }
     580
     581      return before + String.interpret(ctx);
    439582    });
    440583  }
    441 }
    442 
    443 var $break = {}, $continue = new Error('"throw $continue" is deprecated, use "return" instead');
     584});
     585Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
     586
     587var $break = { };
    444588
    445589var Enumerable = {
    446   each: function(iterator) {
     590  each: function(iterator, context) {
    447591    var index = 0;
     592    iterator = iterator.bind(context);
    448593    try {
    449594      this._each(function(value) {
     
    456601  },
    457602
    458   eachSlice: function(number, iterator) {
     603  eachSlice: function(number, iterator, context) {
     604    iterator = iterator ? iterator.bind(context) : Prototype.K;
    459605    var index = -number, slices = [], array = this.toArray();
    460606    while ((index += number) < array.length)
    461607      slices.push(array.slice(index, index+number));
    462     return slices.map(iterator);
    463   },
    464 
    465   all: function(iterator) {
     608    return slices.collect(iterator, context);
     609  },
     610
     611  all: function(iterator, context) {
     612    iterator = iterator ? iterator.bind(context) : Prototype.K;
    466613    var result = true;
    467614    this.each(function(value, index) {
    468       result = result && !!(iterator || Prototype.K)(value, index);
     615      result = result && !!iterator(value, index);
    469616      if (!result) throw $break;
    470617    });
     
    472619  },
    473620
    474   any: function(iterator) {
     621  any: function(iterator, context) {
     622    iterator = iterator ? iterator.bind(context) : Prototype.K;
    475623    var result = false;
    476624    this.each(function(value, index) {
    477       if (result = !!(iterator || Prototype.K)(value, index))
     625      if (result = !!iterator(value, index))
    478626        throw $break;
    479627    });
     
    481629  },
    482630
    483   collect: function(iterator) {
     631  collect: function(iterator, context) {
     632    iterator = iterator ? iterator.bind(context) : Prototype.K;
    484633    var results = [];
    485634    this.each(function(value, index) {
    486       results.push((iterator || Prototype.K)(value, index));
     635      results.push(iterator(value, index));
    487636    });
    488637    return results;
    489638  },
    490639
    491   detect: function(iterator) {
     640  detect: function(iterator, context) {
     641    iterator = iterator.bind(context);
    492642    var result;
    493643    this.each(function(value, index) {
     
    500650  },
    501651
    502   findAll: function(iterator) {
     652  findAll: function(iterator, context) {
     653    iterator = iterator.bind(context);
    503654    var results = [];
    504655    this.each(function(value, index) {
     
    509660  },
    510661
    511   grep: function(pattern, iterator) {
     662  grep: function(filter, iterator, context) {
     663    iterator = iterator ? iterator.bind(context) : Prototype.K;
    512664    var results = [];
     665
     666    if (Object.isString(filter))
     667      filter = new RegExp(filter);
     668
    513669    this.each(function(value, index) {
    514       var stringValue = value.toString();
    515       if (stringValue.match(pattern))
    516         results.push((iterator || Prototype.K)(value, index));
    517     })
     670      if (filter.match(value))
     671        results.push(iterator(value, index));
     672    });
    518673    return results;
    519674  },
    520675
    521676  include: function(object) {
     677    if (Object.isFunction(this.indexOf))
     678      if (this.indexOf(object) != -1) return true;
     679
    522680    var found = false;
    523681    this.each(function(value) {
     
    531689
    532690  inGroupsOf: function(number, fillWith) {
    533     fillWith = fillWith === undefined ? null : fillWith;
     691    fillWith = Object.isUndefined(fillWith) ? null : fillWith;
    534692    return this.eachSlice(number, function(slice) {
    535693      while(slice.length < number) slice.push(fillWith);
     
    538696  },
    539697
    540   inject: function(memo, iterator) {
     698  inject: function(memo, iterator, context) {
     699    iterator = iterator.bind(context);
    541700    this.each(function(value, index) {
    542701      memo = iterator(memo, value, index);
     
    552711  },
    553712
    554   max: function(iterator) {
     713  max: function(iterator, context) {
     714    iterator = iterator ? iterator.bind(context) : Prototype.K;
    555715    var result;
    556716    this.each(function(value, index) {
    557       value = (iterator || Prototype.K)(value, index);
    558       if (result == undefined || value >= result)
     717      value = iterator(value, index);
     718      if (result == null || value >= result)
    559719        result = value;
    560720    });
     
    562722  },
    563723
    564   min: function(iterator) {
     724  min: function(iterator, context) {
     725    iterator = iterator ? iterator.bind(context) : Prototype.K;
    565726    var result;
    566727    this.each(function(value, index) {
    567       value = (iterator || Prototype.K)(value, index);
    568       if (result == undefined || value < result)
     728      value = iterator(value, index);
     729      if (result == null || value < result)
    569730        result = value;
    570731    });
     
    572733  },
    573734
    574   partition: function(iterator) {
     735  partition: function(iterator, context) {
     736    iterator = iterator ? iterator.bind(context) : Prototype.K;
    575737    var trues = [], falses = [];
    576738    this.each(function(value, index) {
    577       ((iterator || Prototype.K)(value, index) ?
     739      (iterator(value, index) ?
    578740        trues : falses).push(value);
    579741    });
     
    583745  pluck: function(property) {
    584746    var results = [];
    585     this.each(function(value, index) {
     747    this.each(function(value) {
    586748      results.push(value[property]);
    587749    });
     
    589751  },
    590752
    591   reject: function(iterator) {
     753  reject: function(iterator, context) {
     754    iterator = iterator.bind(context);
    592755    var results = [];
    593756    this.each(function(value, index) {
     
    598761  },
    599762
    600   sortBy: function(iterator) {
     763  sortBy: function(iterator, context) {
     764    iterator = iterator.bind(context);
    601765    return this.map(function(value, index) {
    602766      return {value: value, criteria: iterator(value, index)};
     
    613777  zip: function() {
    614778    var iterator = Prototype.K, args = $A(arguments);
    615     if (typeof args.last() == 'function')
     779    if (Object.isFunction(args.last()))
    616780      iterator = args.pop();
    617781
     
    629793    return '#<Enumerable:' + this.toArray().inspect() + '>';
    630794  }
    631 }
     795};
    632796
    633797Object.extend(Enumerable, {
     
    635799  find:    Enumerable.detect,
    636800  select:  Enumerable.findAll,
     801  filter:  Enumerable.findAll,
    637802  member:  Enumerable.include,
    638   entries: Enumerable.toArray
     803  entries: Enumerable.toArray,
     804  every:   Enumerable.all,
     805  some:    Enumerable.any
    639806});
    640 var $A = Array.from = function(iterable) {
     807function $A(iterable) {
    641808  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]);
     809  if (iterable.toArray) return iterable.toArray();
     810  var length = iterable.length || 0, results = new Array(length);
     811  while (length--) results[length] = iterable[length];
     812  return results;
     813}
     814
     815if (Prototype.Browser.WebKit) {
     816  $A = function(iterable) {
     817    if (!iterable) return [];
     818    if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
     819        iterable.toArray) return iterable.toArray();
     820    var length = iterable.length || 0, results = new Array(length);
     821    while (length--) results[length] = iterable[length];
    648822    return results;
    649   }
     823  };
    650824}
    651825
    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 }
     826Array.from = $A;
    666827
    667828Object.extend(Array.prototype, Enumerable);
    668829
    669 if (!Array.prototype._reverse)
    670   Array.prototype._reverse = Array.prototype.reverse;
     830if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;
    671831
    672832Object.extend(Array.prototype, {
     
    697857  flatten: function() {
    698858    return this.inject([], function(array, value) {
    699       return array.concat(value && value.constructor == Array ?
     859      return array.concat(Object.isArray(value) ?
    700860        value.flatten() : [value]);
    701861    });
     
    707867      return !values.include(value);
    708868    });
    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;
    715869  },
    716870
     
    731885  },
    732886
     887  intersect: function(array) {
     888    return this.uniq().findAll(function(item) {
     889      return array.detect(function(value) { return item === value });
     890    });
     891  },
     892
    733893  clone: function() {
    734894    return [].concat(this);
     
    747907    this.each(function(object) {
    748908      var value = Object.toJSON(object);
    749       if (value !== undefined) results.push(value);
     909      if (!Object.isUndefined(value)) results.push(value);
    750910    });
    751911    return '[' + results.join(', ') + ']';
     
    753913});
    754914
     915// use native browser JS 1.6 implementation if available
     916if (Object.isFunction(Array.prototype.forEach))
     917  Array.prototype._each = Array.prototype.forEach;
     918
     919if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {
     920  i || (i = 0);
     921  var length = this.length;
     922  if (i < 0) i = length + i;
     923  for (; i < length; i++)
     924    if (this[i] === item) return i;
     925  return -1;
     926};
     927
     928if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {
     929  i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
     930  var n = this.slice(0, i).reverse().indexOf(item);
     931  return (n < 0) ? n : i - n - 1;
     932};
     933
    755934Array.prototype.toArray = Array.prototype.clone;
    756935
    757936function $w(string) {
     937  if (!Object.isString(string)) return [];
    758938  string = string.strip();
    759939  return string ? string.split(/\s+/) : [];
     
    765945    for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
    766946    for (var i = 0, length = arguments.length; i < length; i++) {
    767       if (arguments[i].constructor == Array) {
     947      if (Object.isArray(arguments[i])) {
    768948        for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
    769949          array.push(arguments[i][j]);
     
    773953    }
    774954    return array;
    775   }
     955  };
    776956}
    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(', ') + '}';
     957Object.extend(Number.prototype, {
     958  toColorPart: function() {
     959    return this.toPaddedString(2, 16);
     960  },
     961
     962  succ: function() {
     963    return this + 1;
     964  },
     965
     966  times: function(iterator) {
     967    $R(0, this, true).each(iterator);
     968    return this;
     969  },
     970
     971  toPaddedString: function(length, radix) {
     972    var string = this.toString(radix || 10);
     973    return '0'.times(length - string.length) + string;
     974  },
     975
     976  toJSON: function() {
     977    return isFinite(this) ? this.toString() : 'null';
    810978  }
    811979});
    812980
    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   }
     981$w('abs round ceil floor').each(function(method){
     982  Number.prototype[method] = Math[method].methodize();
    877983});
    878 
    879984function $H(object) {
    880   if (object instanceof Hash) return object;
    881985  return new Hash(object);
    882986};
    883987
    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, {
     988var Hash = Class.create(Enumerable, (function() {
     989
     990  function toQueryPair(key, value) {
     991    if (Object.isUndefined(value)) return key;
     992    return key + '=' + encodeURIComponent(String.interpret(value));
     993  }
     994
     995  return {
     996    initialize: function(object) {
     997      this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
     998    },
     999
     1000    _each: function(iterator) {
     1001      for (var key in this._object) {
     1002        var value = this._object[key], pair = [key, value];
     1003        pair.key = key;
     1004        pair.value = value;
     1005        iterator(pair);
     1006      }
     1007    },
     1008
     1009    set: function(key, value) {
     1010      return this._object[key] = value;
     1011    },
     1012
     1013    get: function(key) {
     1014      return this._object[key];
     1015    },
     1016
     1017    unset: function(key) {
     1018      var value = this._object[key];
     1019      delete this._object[key];
     1020      return value;
     1021    },
     1022
     1023    toObject: function() {
     1024      return Object.clone(this._object);
     1025    },
     1026
     1027    keys: function() {
     1028      return this.pluck('key');
     1029    },
     1030
     1031    values: function() {
     1032      return this.pluck('value');
     1033    },
     1034
     1035    index: function(value) {
     1036      var match = this.detect(function(pair) {
     1037        return pair.value === value;
     1038      });
     1039      return match && match.key;
     1040    },
     1041
     1042    merge: function(object) {
     1043      return this.clone().update(object);
     1044    },
     1045
     1046    update: function(object) {
     1047      return new Hash(object).inject(this, function(result, pair) {
     1048        result.set(pair.key, pair.value);
     1049        return result;
     1050      });
     1051    },
     1052
     1053    toQueryString: function() {
     1054      return this.map(function(pair) {
     1055        var key = encodeURIComponent(pair.key), values = pair.value;
     1056
     1057        if (values && typeof values == 'object') {
     1058          if (Object.isArray(values))
     1059            return values.map(toQueryPair.curry(key)).join('&');
     1060        }
     1061        return toQueryPair(key, values);
     1062      }).join('&');
     1063    },
     1064
     1065    inspect: function() {
     1066      return '#<Hash:{' + this.map(function(pair) {
     1067        return pair.map(Object.inspect).join(': ');
     1068      }).join(', ') + '}>';
     1069    },
     1070
     1071    toJSON: function() {
     1072      return Object.toJSON(this.toObject());
     1073    },
     1074
     1075    clone: function() {
     1076      return new Hash(this);
     1077    }
     1078  }
     1079})());
     1080
     1081Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;
     1082Hash.from = $H;
     1083var ObjectRange = Class.create(Enumerable, {
    9051084  initialize: function(start, end, exclusive) {
    9061085    this.start = start;
     
    9281107var $R = function(start, end, exclusive) {
    9291108  return new ObjectRange(start, end, exclusive);
    930 }
     1109};
    9311110
    9321111var Ajax = {
     
    9401119
    9411120  activeRequestCount: 0
    942 }
     1121};
    9431122
    9441123Ajax.Responders = {
     
    9601139  dispatch: function(callback, request, transport, json) {
    9611140    this.each(function(responder) {
    962       if (typeof responder[callback] == 'function') {
     1141      if (Object.isFunction(responder[callback])) {
    9631142        try {
    9641143          responder[callback].apply(responder, [request, transport, json]);
    965         } catch (e) {}
     1144        } catch (e) { }
    9661145      }
    9671146    });
     
    9721151
    9731152Ajax.Responders.register({
    974   onCreate: function() {
    975     Ajax.activeRequestCount++;
    976   },
    977   onComplete: function() {
    978     Ajax.activeRequestCount--;
    979   }
     1153  onCreate:   function() { Ajax.activeRequestCount++ },
     1154  onComplete: function() { Ajax.activeRequestCount-- }
    9801155});
    9811156
    982 Ajax.Base = function() {};
    983 Ajax.Base.prototype = {
    984   setOptions: function(options) {
     1157Ajax.Base = Class.create({
     1158  initialize: function(options) {
    9851159    this.options = {
    9861160      method:       'post',
     
    9881162      contentType:  'application/x-www-form-urlencoded',
    9891163      encoding:     'UTF-8',
    990       parameters:   ''
    991     }
    992     Object.extend(this.options, options || {});
     1164      parameters:   '',
     1165      evalJSON:     true,
     1166      evalJS:       true
     1167    };
     1168    Object.extend(this.options, options || { });
    9931169
    9941170    this.options.method = this.options.method.toLowerCase();
    995     if (typeof this.options.parameters == 'string')
     1171
     1172    if (Object.isString(this.options.parameters))
    9961173      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(), {
     1174    else if (Object.isHash(this.options.parameters))
     1175      this.options.parameters = this.options.parameters.toObject();
     1176  }
     1177});
     1178
     1179Ajax.Request = Class.create(Ajax.Base, {
    10051180  _complete: false,
    10061181
    1007   initialize: function(url, options) {
     1182  initialize: function($super, url, options) {
     1183    $super(options);
    10081184    this.transport = Ajax.getTransport();
    1009     this.setOptions(options);
    10101185    this.request(url);
    10111186  },
     
    10241199    this.parameters = params;
    10251200
    1026     if (params = Hash.toQueryString(params)) {
     1201    if (params = Object.toQueryString(params)) {
    10271202      // when GET, append parameters to URL
    10281203      if (this.method == 'get')
     
    10331208
    10341209    try {
    1035       if (this.options.onCreate) this.options.onCreate(this.transport);
    1036       Ajax.Responders.dispatch('onCreate', this, this.transport);
     1210      var response = new Ajax.Response(this);
     1211      if (this.options.onCreate) this.options.onCreate(response);
     1212      Ajax.Responders.dispatch('onCreate', this, response);
    10371213
    10381214      this.transport.open(this.method.toUpperCase(), this.url,
    10391215        this.options.asynchronous);
    10401216
    1041       if (this.options.asynchronous)
    1042         setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
     1217      if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
    10431218
    10441219      this.transport.onreadystatechange = this.onStateChange.bind(this);
     
    10881263      var extras = this.options.requestHeaders;
    10891264
    1090       if (typeof extras.push == 'function')
     1265      if (Object.isFunction(extras.push))
    10911266        for (var i = 0, length = extras.length; i < length; i += 2)
    10921267          headers[extras[i]] = extras[i+1];
     
    11001275
    11011276  success: function() {
    1102     return !this.transport.status
    1103         || (this.transport.status >= 200 && this.transport.status < 300);
     1277    var status = this.getStatus();
     1278    return !status || (status >= 200 && status < 300);
     1279  },
     1280
     1281  getStatus: function() {
     1282    try {
     1283      return this.transport.status || 0;
     1284    } catch (e) { return 0 }
    11041285  },
    11051286
    11061287  respondToReadyState: function(readyState) {
    1107     var state = Ajax.Request.Events[readyState];
    1108     var transport = this.transport, json = this.evalJSON();
     1288    var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
    11091289
    11101290    if (state == 'Complete') {
    11111291      try {
    11121292        this._complete = true;
    1113         (this.options['on' + this.transport.status]
     1293        (this.options['on' + response.status]
    11141294         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
    1115          || Prototype.emptyFunction)(transport, json);
     1295         || Prototype.emptyFunction)(response, response.headerJSON);
    11161296      } catch (e) {
    11171297        this.dispatchException(e);
    11181298      }
    11191299
    1120       var contentType = this.getHeader('Content-type');
    1121       if (contentType && contentType.strip().
    1122         match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
    1123           this.evalResponse();
     1300      var contentType = response.getHeader('Content-type');
     1301      if (this.options.evalJS == 'force'
     1302          || (this.options.evalJS && this.isSameOrigin() && contentType
     1303          && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
     1304        this.evalResponse();
    11241305    }
    11251306
    11261307    try {
    1127       (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
    1128       Ajax.Responders.dispatch('on' + state, this, transport, json);
     1308      (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
     1309      Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
    11291310    } catch (e) {
    11301311      this.dispatchException(e);
     
    11371318  },
    11381319
     1320  isSameOrigin: function() {
     1321    var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
     1322    return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
     1323      protocol: location.protocol,
     1324      domain: document.domain,
     1325      port: location.port ? ':' + location.port : ''
     1326    }));
     1327  },
     1328
    11391329  getHeader: function(name) {
    11401330    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;
     1331      return this.transport.getResponseHeader(name) || null;
    11491332    } catch (e) { return null }
    11501333  },
     
    11641347});
    11651348
    1166 Ajax.Updater = Class.create();
    1167 
    1168 Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
    1169   initialize: function(container, url, options) {
     1349Ajax.Request.Events =
     1350  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
     1351
     1352Ajax.Response = Class.create({
     1353  initialize: function(request){
     1354    this.request = request;
     1355    var transport  = this.transport  = request.transport,
     1356        readyState = this.readyState = transport.readyState;
     1357
     1358    if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
     1359      this.status       = this.getStatus();
     1360      this.statusText   = this.getStatusText();
     1361      this.responseText = String.interpret(transport.responseText);
     1362      this.headerJSON   = this._getHeaderJSON();
     1363    }
     1364
     1365    if(readyState == 4) {
     1366      var xml = transport.responseXML;
     1367      this.responseXML  = Object.isUndefined(xml) ? null : xml;
     1368      this.responseJSON = this._getResponseJSON();
     1369    }
     1370  },
     1371
     1372  status:      0,
     1373  statusText: '',
     1374
     1375  getStatus: Ajax.Request.prototype.getStatus,
     1376
     1377  getStatusText: function() {
     1378    try {
     1379      return this.transport.statusText || '';
     1380    } catch (e) { return '' }
     1381  },
     1382
     1383  getHeader: Ajax.Request.prototype.getHeader,
     1384
     1385  getAllHeaders: function() {
     1386    try {
     1387      return this.getAllResponseHeaders();
     1388    } catch (e) { return null }
     1389  },
     1390
     1391  getResponseHeader: function(name) {
     1392    return this.transport.getResponseHeader(name);
     1393  },
     1394
     1395  getAllResponseHeaders: function() {
     1396    return this.transport.getAllResponseHeaders();
     1397  },
     1398
     1399  _getHeaderJSON: function() {
     1400    var json = this.getHeader('X-JSON');
     1401    if (!json) return null;
     1402    json = decodeURIComponent(escape(json));
     1403    try {
     1404      return json.evalJSON(this.request.options.sanitizeJSON ||
     1405        !this.request.isSameOrigin());
     1406    } catch (e) {
     1407      this.request.dispatchException(e);
     1408    }
     1409  },
     1410
     1411  _getResponseJSON: function() {
     1412    var options = this.request.options;
     1413    if (!options.evalJSON || (options.evalJSON != 'force' &&
     1414      !(this.getHeader('Content-type') || '').include('application/json')) ||
     1415        this.responseText.blank())
     1416          return null;
     1417    try {
     1418      return this.responseText.evalJSON(options.sanitizeJSON ||
     1419        !this.request.isSameOrigin());
     1420    } catch (e) {
     1421      this.request.dispatchException(e);
     1422    }
     1423  }
     1424});
     1425
     1426Ajax.Updater = Class.create(Ajax.Request, {
     1427  initialize: function($super, container, url, options) {
    11701428    this.container = {
    11711429      success: (container.success || container),
    11721430      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);
     1431    };
     1432
     1433    options = Object.clone(options);
     1434    var onComplete = options.onComplete;
     1435    options.onComplete = (function(response, json) {
     1436      this.updateContent(response.responseText);
     1437      if (Object.isFunction(onComplete)) onComplete(response, json);
    11821438    }).bind(this);
    11831439
    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();
     1440    $super(url, options);
     1441  },
     1442
     1443  updateContent: function(responseText) {
     1444    var receiver = this.container[this.success() ? 'success' : 'failure'],
     1445        options = this.options;
     1446
     1447    if (!options.evalScripts) responseText = responseText.stripScripts();
    11921448
    11931449    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);
     1450      if (options.insertion) {
     1451        if (Object.isString(options.insertion)) {
     1452          var insertion = { }; insertion[options.insertion] = responseText;
     1453          receiver.insert(insertion);
     1454        }
     1455        else options.insertion(receiver, responseText);
     1456      }
     1457      else receiver.update(responseText);
    12031458    }
    12041459  }
    12051460});
    12061461
    1207 Ajax.PeriodicalUpdater = Class.create();
    1208 Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
    1209   initialize: function(container, url, options) {
    1210     this.setOptions(options);
     1462Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
     1463  initialize: function($super, container, url, options) {
     1464    $super(options);
    12111465    this.onComplete = this.options.onComplete;
    12121466
     
    12141468    this.decay = (this.options.decay || 1);
    12151469
    1216     this.updater = {};
     1470    this.updater = { };
    12171471    this.container = container;
    12181472    this.url = url;
     
    12321486  },
    12331487
    1234   updateComplete: function(request) {
     1488  updateComplete: function(response) {
    12351489    if (this.options.decay) {
    1236       this.decay = (request.responseText == this.lastText ?
     1490      this.decay = (response.responseText == this.lastText ?
    12371491        this.decay * this.options.decay : 1);
    12381492
    1239       this.lastText = request.responseText;
    1240     }
    1241     this.timer = setTimeout(this.onTimerEvent.bind(this),
    1242       this.decay * this.frequency * 1000);
     1493      this.lastText = response.responseText;
     1494    }
     1495    this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
    12431496  },
    12441497
     
    12531506    return elements;
    12541507  }
    1255   if (typeof element == 'string')
     1508  if (Object.isString(element))
    12561509    element = document.getElementById(element);
    12571510  return Element.extend(element);
     
    12641517      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    12651518    for (var i = 0, length = query.snapshotLength; i < length; i++)
    1266       results.push(query.snapshotItem(i));
     1519      results.push(Element.extend(query.snapshotItem(i)));
    12671520    return results;
    12681521  };
    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 };
     1522}
    12871523
    12881524/*--------------------------------------------------------------------------*/
    12891525
    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 };
     1526if (!window.Node) var Node = { };
     1527
     1528if (!Node.ELEMENT_NODE) {
     1529  // DOM level 2 ECMAScript Language Binding
     1530  Object.extend(Node, {
     1531    ELEMENT_NODE: 1,
     1532    ATTRIBUTE_NODE: 2,
     1533    TEXT_NODE: 3,
     1534    CDATA_SECTION_NODE: 4,
     1535    ENTITY_REFERENCE_NODE: 5,
     1536    ENTITY_NODE: 6,
     1537    PROCESSING_INSTRUCTION_NODE: 7,
     1538    COMMENT_NODE: 8,
     1539    DOCUMENT_NODE: 9,
     1540    DOCUMENT_TYPE_NODE: 10,
     1541    DOCUMENT_FRAGMENT_NODE: 11,
     1542    NOTATION_NODE: 12
     1543  });
     1544}
     1545
     1546(function() {
     1547  var element = this.Element;
     1548  this.Element = function(tagName, attributes) {
     1549    attributes = attributes || { };
     1550    tagName = tagName.toLowerCase();
     1551    var cache = Element.cache;
     1552    if (Prototype.Browser.IE && attributes.name) {
     1553      tagName = '<' + tagName + ' name="' + attributes.name + '">';
     1554      delete attributes.name;
     1555      return Element.writeAttribute(document.createElement(tagName), attributes);
     1556    }
     1557    if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
     1558    return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
     1559  };
     1560  Object.extend(this.Element, element || { });
     1561}).call(window);
     1562
     1563Element.cache = { };
    13271564
    13281565Element.Methods = {
     
    13531590  },
    13541591
    1355   update: function(element, html) {
    1356     html = typeof html == 'undefined' ? '' : html.toString();
    1357     $(element).innerHTML = html.stripScripts();
    1358     setTimeout(function() {html.evalScripts()}, 10);
     1592  update: function(element, content) {
     1593    element = $(element);
     1594    if (content && content.toElement) content = content.toElement();
     1595    if (Object.isElement(content)) return element.update().insert(content);
     1596    content = Object.toHTML(content);
     1597    element.innerHTML = content.stripScripts();
     1598    content.evalScripts.bind(content).defer();
    13591599    return element;
    13601600  },
    13611601
    1362   replace: function(element, html) {
     1602  replace: function(element, content) {
    13631603    element = $(element);
    1364     html = typeof html == 'undefined' ? '' : html.toString();
    1365     if (element.outerHTML) {
    1366       element.outerHTML = html.stripScripts();
    1367     } else {
     1604    if (content && content.toElement) content = content.toElement();
     1605    else if (!Object.isElement(content)) {
     1606      content = Object.toHTML(content);
    13681607      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);
     1608      range.selectNode(element);
     1609      content.evalScripts.bind(content).defer();
     1610      content = range.createContextualFragment(content.stripScripts());
     1611    }
     1612    element.parentNode.replaceChild(content, element);
    13741613    return element;
     1614  },
     1615
     1616  insert: function(element, insertions) {
     1617    element = $(element);
     1618
     1619    if (Object.isString(insertions) || Object.isNumber(insertions) ||
     1620        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
     1621          insertions = {bottom:insertions};
     1622
     1623    var content, insert, tagName, childNodes;
     1624
     1625    for (var position in insertions) {
     1626      content  = insertions[position];
     1627      position = position.toLowerCase();
     1628      insert = Element._insertionTranslations[position];
     1629
     1630      if (content && content.toElement) content = content.toElement();
     1631      if (Object.isElement(content)) {
     1632        insert(element, content);
     1633        continue;
     1634      }
     1635
     1636      content = Object.toHTML(content);
     1637
     1638      tagName = ((position == 'before' || position == 'after')
     1639        ? element.parentNode : element).tagName.toUpperCase();
     1640
     1641      childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
     1642
     1643      if (position == 'top' || position == 'after') childNodes.reverse();
     1644      childNodes.each(insert.curry(element));
     1645
     1646      content.evalScripts.bind(content).defer();
     1647    }
     1648
     1649    return element;
     1650  },
     1651
     1652  wrap: function(element, wrapper, attributes) {
     1653    element = $(element);
     1654    if (Object.isElement(wrapper))
     1655      $(wrapper).writeAttribute(attributes || { });
     1656    else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
     1657    else wrapper = new Element('div', wrapper);
     1658    if (element.parentNode)
     1659      element.parentNode.replaceChild(wrapper, element);
     1660    wrapper.appendChild(element);
     1661    return wrapper;
    13751662  },
    13761663
     
    14001687
    14011688  descendants: function(element) {
    1402     return $A($(element).getElementsByTagName('*')).each(Element.extend);
     1689    return $(element).select("*");
    14031690  },
    14041691
     
    14301717
    14311718  match: function(element, selector) {
    1432     if (typeof selector == 'string')
     1719    if (Object.isString(selector))
    14331720      selector = new Selector(selector);
    14341721    return selector.match($(element));
     
    14391726    if (arguments.length == 1) return $(element.parentNode);
    14401727    var ancestors = element.ancestors();
    1441     return expression ? Selector.findElement(ancestors, expression, index) :
    1442       ancestors[index || 0];
     1728    return Object.isNumber(expression) ? ancestors[expression] :
     1729      Selector.findElement(ancestors, expression, index);
    14431730  },
    14441731
     
    14461733    element = $(element);
    14471734    if (arguments.length == 1) return element.firstDescendant();
    1448     var descendants = element.descendants();
    1449     return expression ? Selector.findElement(descendants, expression, index) :
    1450       descendants[index || 0];
     1735    return Object.isNumber(expression) ? element.descendants()[expression] :
     1736      element.select(expression)[index || 0];
    14511737  },
    14521738
     
    14551741    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
    14561742    var previousSiblings = element.previousSiblings();
    1457     return expression ? Selector.findElement(previousSiblings, expression, index) :
    1458       previousSiblings[index || 0];
     1743    return Object.isNumber(expression) ? previousSiblings[expression] :
     1744      Selector.findElement(previousSiblings, expression, index);
    14591745  },
    14601746
     
    14631749    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
    14641750    var nextSiblings = element.nextSiblings();
    1465     return expression ? Selector.findElement(nextSiblings, expression, index) :
    1466       nextSiblings[index || 0];
    1467   },
    1468 
    1469   getElementsBySelector: function() {
     1751    return Object.isNumber(expression) ? nextSiblings[expression] :
     1752      Selector.findElement(nextSiblings, expression, index);
     1753  },
     1754
     1755  select: function() {
    14701756    var args = $A(arguments), element = $(args.shift());
    14711757    return Selector.findChildElements(element, args);
    14721758  },
    14731759
    1474   getElementsByClassName: function(element, className) {
    1475     return document.getElementsByClassName(className, element);
     1760  adjacent: function() {
     1761    var args = $A(arguments), element = $(args.shift());
     1762    return Selector.findChildElements(element.parentNode, args).without(element);
     1763  },
     1764
     1765  identify: function(element) {
     1766    element = $(element);
     1767    var id = element.readAttribute('id'), self = arguments.callee;
     1768    if (id) return id;
     1769    do { id = 'anonymous_element_' + self.counter++ } while ($(id));
     1770    element.writeAttribute('id', id);
     1771    return id;
    14761772  },
    14771773
     
    14791775    element = $(element);
    14801776    if (Prototype.Browser.IE) {
    1481       if (!element.attributes) return null;
    1482       var t = Element._attributeTranslations;
     1777      var t = Element._attributeTranslations.read;
    14831778      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;
     1779      if (t.names[name]) name = t.names[name];
     1780      if (name.include(':')) {
     1781        return (!element.attributes || !element.attributes[name]) ? null :
     1782         element.attributes[name].value;
     1783      }
    14871784    }
    14881785    return element.getAttribute(name);
     1786  },
     1787
     1788  writeAttribute: function(element, name, value) {
     1789    element = $(element);
     1790    var attributes = { }, t = Element._attributeTranslations.write;
     1791
     1792    if (typeof name == 'object') attributes = name;
     1793    else attributes[name] = Object.isUndefined(value) ? true : value;
     1794
     1795    for (var attr in attributes) {
     1796      name = t.names[attr] || attr;
     1797      value = attributes[attr];
     1798      if (t.values[attr]) name = t.values[attr](element, value);
     1799      if (value === false || value === null)
     1800        element.removeAttribute(name);
     1801      else if (value === true)
     1802        element.setAttribute(name, name);
     1803      else element.setAttribute(name, value);
     1804    }
     1805    return element;
    14891806  },
    14901807
     
    15041821    if (!(element = $(element))) return;
    15051822    var elementClassName = element.className;
    1506     if (elementClassName.length == 0) return false;
    1507     if (elementClassName == className ||
    1508         elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
    1509       return true;
    1510     return false;
     1823    return (elementClassName.length > 0 && (elementClassName == className ||
     1824      new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
    15111825  },
    15121826
    15131827  addClassName: function(element, className) {
    15141828    if (!(element = $(element))) return;
    1515     Element.classNames(element).add(className);
     1829    if (!element.hasClassName(className))
     1830      element.className += (element.className ? ' ' : '') + className;
    15161831    return element;
    15171832  },
     
    15191834  removeClassName: function(element, className) {
    15201835    if (!(element = $(element))) return;
    1521     Element.classNames(element).remove(className);
     1836    element.className = element.className.replace(
     1837      new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
    15221838    return element;
    15231839  },
     
    15251841  toggleClassName: function(element, className) {
    15261842    if (!(element = $(element))) return;
    1527     Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
    1528     return element;
    1529   },
    1530 
    1531   observe: function() {
    1532     Event.observe.apply(Event, arguments);
    1533     return $A(arguments).first();
    1534   },
    1535 
    1536   stopObserving: function() {
    1537     Event.stopObserving.apply(Event, arguments);
    1538     return $A(arguments).first();
     1843    return element[element.hasClassName(className) ?
     1844      'removeClassName' : 'addClassName'](className);
    15391845  },
    15401846
     
    15581864  descendantOf: function(element, ancestor) {
    15591865    element = $(element), ancestor = $(ancestor);
     1866    var originalAncestor = ancestor;
     1867
     1868    if (element.compareDocumentPosition)
     1869      return (element.compareDocumentPosition(ancestor) & 8) === 8;
     1870
     1871    if (element.sourceIndex && !Prototype.Browser.Opera) {
     1872      var e = element.sourceIndex, a = ancestor.sourceIndex,
     1873       nextAncestor = ancestor.nextSibling;
     1874      if (!nextAncestor) {
     1875        do { ancestor = ancestor.parentNode; }
     1876        while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);
     1877      }
     1878      if (nextAncestor && nextAncestor.sourceIndex)
     1879       return (e > a && e < nextAncestor.sourceIndex);
     1880    }
     1881
    15601882    while (element = element.parentNode)
    1561       if (element == ancestor) return true;
     1883      if (element == originalAncestor) return true;
    15621884    return false;
    15631885  },
     
    15651887  scrollTo: function(element) {
    15661888    element = $(element);
    1567     var pos = Position.cumulativeOffset(element);
     1889    var pos = element.cumulativeOffset();
    15681890    window.scrollTo(pos[0], pos[1]);
    15691891    return element;
     
    15861908  },
    15871909
    1588   setStyle: function(element, styles, camelized) {
     1910  setStyle: function(element, styles) {
    15891911    element = $(element);
    1590     var elementStyle = element.style;
    1591 
     1912    var elementStyle = element.style, match;
     1913    if (Object.isString(styles)) {
     1914      element.style.cssText += ';' + styles;
     1915      return styles.include('opacity') ?
     1916        element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
     1917    }
    15921918    for (var property in styles)
    1593       if (property == 'opacity') element.setOpacity(styles[property])
     1919      if (property == 'opacity') element.setOpacity(styles[property]);
    15941920      else
    15951921        elementStyle[(property == 'float' || property == 'cssFloat') ?
    1596           (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
    1597           (camelized ? property : property.camelize())] = styles[property];
     1922          (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
     1923            property] = styles[property];
    15981924
    15991925    return element;
     
    16621988    element = $(element);
    16631989    if (element._overflow) return element;
    1664     element._overflow = element.style.overflow || 'auto';
    1665     if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
     1990    element._overflow = Element.getStyle(element, 'overflow') || 'auto';
     1991    if (element._overflow !== 'hidden')
    16661992      element.style.overflow = 'hidden';
    16671993    return element;
     
    16742000    element._overflow = null;
    16752001    return element;
     2002  },
     2003
     2004  cumulativeOffset: function(element) {
     2005    var valueT = 0, valueL = 0;
     2006    do {
     2007      valueT += element.offsetTop  || 0;
     2008      valueL += element.offsetLeft || 0;
     2009      element = element.offsetParent;
     2010    } while (element);
     2011    return Element._returnOffset(valueL, valueT);
     2012  },
     2013
     2014  positionedOffset: function(element) {
     2015    var valueT = 0, valueL = 0;
     2016    do {
     2017      valueT += element.offsetTop  || 0;
     2018      valueL += element.offsetLeft || 0;
     2019      element = element.offsetParent;
     2020      if (element) {
     2021        if (element.tagName == 'BODY') break;
     2022        var p = Element.getStyle(element, 'position');
     2023        if (p !== 'static') break;
     2024      }
     2025    } while (element);
     2026    return Element._returnOffset(valueL, valueT);
     2027  },
     2028
     2029  absolutize: function(element) {
     2030    element = $(element);
     2031    if (element.getStyle('position') == 'absolute') return;
     2032    // Position.prepare(); // To be done manually by Scripty when it needs it.
     2033
     2034    var offsets = element.positionedOffset();
     2035    var top     = offsets[1];
     2036    var left    = offsets[0];
     2037    var width   = element.clientWidth;
     2038    var height  = element.clientHeight;
     2039
     2040    element._originalLeft   = left - parseFloat(element.style.left  || 0);
     2041    element._originalTop    = top  - parseFloat(element.style.top || 0);
     2042    element._originalWidth  = element.style.width;
     2043    element._originalHeight = element.style.height;
     2044
     2045    element.style.position = 'absolute';
     2046    element.style.top    = top + 'px';
     2047    element.style.left   = left + 'px';
     2048    element.style.width  = width + 'px';
     2049    element.style.height = height + 'px';
     2050    return element;
     2051  },
     2052
     2053  relativize: function(element) {
     2054    element = $(element);
     2055    if (element.getStyle('position') == 'relative') return;
     2056    // Position.prepare(); // To be done manually by Scripty when it needs it.
     2057
     2058    element.style.position = 'relative';
     2059    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
     2060    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
     2061
     2062    element.style.top    = top + 'px';
     2063    element.style.left   = left + 'px';
     2064    element.style.height = element._originalHeight;
     2065    element.style.width  = element._originalWidth;
     2066    return element;
     2067  },
     2068
     2069  cumulativeScrollOffset: function(element) {
     2070    var valueT = 0, valueL = 0;
     2071    do {
     2072      valueT += element.scrollTop  || 0;
     2073      valueL += element.scrollLeft || 0;
     2074      element = element.parentNode;
     2075    } while (element);
     2076    return Element._returnOffset(valueL, valueT);
     2077  },
     2078
     2079  getOffsetParent: function(element) {
     2080    if (element.offsetParent) return $(element.offsetParent);
     2081    if (element == document.body) return $(element);
     2082
     2083    while ((element = element.parentNode) && element != document.body)
     2084      if (Element.getStyle(element, 'position') != 'static')
     2085        return $(element);
     2086
     2087    return $(document.body);
     2088  },
     2089
     2090  viewportOffset: function(forElement) {
     2091    var valueT = 0, valueL = 0;
     2092
     2093    var element = forElement;
     2094    do {
     2095      valueT += element.offsetTop  || 0;
     2096      valueL += element.offsetLeft || 0;
     2097
     2098      // Safari fix
     2099      if (element.offsetParent == document.body &&
     2100        Element.getStyle(element, 'position') == 'absolute') break;
     2101
     2102    } while (element = element.offsetParent);
     2103
     2104    element = forElement;
     2105    do {
     2106      if (!Prototype.Browser.Opera || element.tagName == 'BODY') {
     2107        valueT -= element.scrollTop  || 0;
     2108        valueL -= element.scrollLeft || 0;
     2109      }
     2110    } while (element = element.parentNode);
     2111
     2112    return Element._returnOffset(valueL, valueT);
     2113  },
     2114
     2115  clonePosition: function(element, source) {
     2116    var options = Object.extend({
     2117      setLeft:    true,
     2118      setTop:     true,
     2119      setWidth:   true,
     2120      setHeight:  true,
     2121      offsetTop:  0,
     2122      offsetLeft: 0
     2123    }, arguments[2] || { });
     2124
     2125    // find page position of source
     2126    source = $(source);
     2127    var p = source.viewportOffset();
     2128
     2129    // find coordinate system to use
     2130    element = $(element);
     2131    var delta = [0, 0];
     2132    var parent = null;
     2133    // delta [0,0] will do fine with position: fixed elements,
     2134    // position:absolute needs offsetParent deltas
     2135    if (Element.getStyle(element, 'position') == 'absolute') {
     2136      parent = element.getOffsetParent();
     2137      delta = parent.viewportOffset();
     2138    }
     2139
     2140    // correct by body offsets (fixes Safari)
     2141    if (parent == document.body) {
     2142      delta[0] -= document.body.offsetLeft;
     2143      delta[1] -= document.body.offsetTop;
     2144    }
     2145
     2146    // set position
     2147    if (options.setLeft)   element.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
     2148    if (options.setTop)    element.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
     2149    if (options.setWidth)  element.style.width = source.offsetWidth + 'px';
     2150    if (options.setHeight) element.style.height = source.offsetHeight + 'px';
     2151    return element;
    16762152  }
    16772153};
    16782154
     2155Element.Methods.identify.counter = 1;
     2156
    16792157Object.extend(Element.Methods, {
    1680   childOf: Element.Methods.descendantOf,
     2158  getElementsBySelector: Element.Methods.select,
    16812159  childElements: Element.Methods.immediateDescendants
    16822160});
    16832161
     2162Element._attributeTranslations = {
     2163  write: {
     2164    names: {
     2165      className: 'class',
     2166      htmlFor:   'for'
     2167    },
     2168    values: { }
     2169  }
     2170};
     2171
    16842172if (Prototype.Browser.Opera) {
    1685   Element.Methods._getStyle = Element.Methods.getStyle;
    1686   Element.Methods.getStyle = function(element, style) {
    1687     switch(style) {
    1688       case 'left':
    1689       case 'top':
    1690       case 'right':
    1691       case 'bottom':
    1692         if (Element._getStyle(element, 'position') == 'static') return null;
    1693       default: return Element._getStyle(element, style);
    1694     }
    1695   };
     2173  Element.Methods.getStyle = Element.Methods.getStyle.wrap(
     2174    function(proceed, element, style) {
     2175      switch (style) {
     2176        case 'left': case 'top': case 'right': case 'bottom':
     2177          if (proceed(element, 'position') === 'static') return null;
     2178        case 'height': case 'width':
     2179          // returns '0px' for hidden elements; we want it to return null
     2180          if (!Element.visible(element)) return null;
     2181
     2182          // returns the border-box dimensions rather than the content-box
     2183          // dimensions, so we subtract padding and borders from the value
     2184          var dim = parseInt(proceed(element, style), 10);
     2185
     2186          if (dim !== element['offset' + style.capitalize()])
     2187            return dim + 'px';
     2188
     2189          var properties;
     2190          if (style === 'height') {
     2191            properties = ['border-top-width', 'padding-top',
     2192             'padding-bottom', 'border-bottom-width'];
     2193          }
     2194          else {
     2195            properties = ['border-left-width', 'padding-left',
     2196             'padding-right', 'border-right-width'];
     2197          }
     2198          return properties.inject(dim, function(memo, property) {
     2199            var val = proceed(element, property);
     2200            return val === null ? memo : memo - parseInt(val, 10);
     2201          }) + 'px';
     2202        default: return proceed(element, style);
     2203      }
     2204    }
     2205  );
     2206
     2207  Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
     2208    function(proceed, element, attribute) {
     2209      if (attribute === 'title') return element.title;
     2210      return proceed(element, attribute);
     2211    }
     2212  );
    16962213}
     2214
    16972215else if (Prototype.Browser.IE) {
     2216  // IE doesn't report offsets correctly for static elements, so we change them
     2217  // to "relative" to get the values, then change them back.
     2218  Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
     2219    function(proceed, element) {
     2220      element = $(element);
     2221      var position = element.getStyle('position');
     2222      if (position !== 'static') return proceed(element);
     2223      element.setStyle({ position: 'relative' });
     2224      var value = proceed(element);
     2225      element.setStyle({ position: position });
     2226      return value;
     2227    }
     2228  );
     2229
     2230  $w('positionedOffset viewportOffset').each(function(method) {
     2231    Element.Methods[method] = Element.Methods[method].wrap(
     2232      function(proceed, element) {
     2233        element = $(element);
     2234        var position = element.getStyle('position');
     2235        if (position !== 'static') return proceed(element);
     2236        // Trigger hasLayout on the offset parent so that IE6 reports
     2237        // accurate offsetTop and offsetLeft values for position: fixed.
     2238        var offsetParent = element.getOffsetParent();
     2239        if (offsetParent && offsetParent.getStyle('position') === 'fixed')
     2240          offsetParent.setStyle({ zoom: 1 });
     2241        element.setStyle({ position: 'relative' });
     2242        var value = proceed(element);
     2243        element.setStyle({ position: position });
     2244        return value;
     2245      }
     2246    );
     2247  });
     2248
    16982249  Element.Methods.getStyle = function(element, style) {
    16992250    element = $(element);
     
    17102261    if (value == 'auto') {
    17112262      if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
    1712         return element['offset'+style.capitalize()] + 'px';
     2263        return element['offset' + style.capitalize()] + 'px';
    17132264      return null;
    17142265    }
     
    17172268
    17182269  Element.Methods.setOpacity = function(element, value) {
     2270    function stripAlpha(filter){
     2271      return filter.replace(/alpha\([^\)]*\)/gi,'');
     2272    }
    17192273    element = $(element);
     2274    var currentStyle = element.currentStyle;
     2275    if ((currentStyle && !currentStyle.hasLayout) ||
     2276      (!currentStyle && element.style.zoom == 'normal'))
     2277        element.style.zoom = 1;
     2278
    17202279    var filter = element.getStyle('filter'), style = element.style;
    17212280    if (value == 1 || value === '') {
    1722       style.filter = filter.replace(/alpha\([^\)]*\)/gi,'');
     2281      (filter = stripAlpha(filter)) ?
     2282        style.filter = filter : style.removeAttribute('filter');
    17232283      return element;
    17242284    } else if (value < 0.00001) value = 0;
    1725     style.filter = filter.replace(/alpha\([^\)]*\)/gi, '') +
     2285    style.filter = stripAlpha(filter) +
    17262286      'alpha(opacity=' + (value * 100) + ')';
    17272287    return element;
    17282288  };
    17292289
    1730   // IE is missing .innerHTML support for TABLE-related elements
    1731   Element.Methods.update = function(element, html) {
    1732     element = $(element);
    1733     html = typeof html == 'undefined' ? '' : html.toString();
    1734     var tagName = element.tagName.toUpperCase();
    1735     if (['THEAD','TBODY','TR','TD'].include(tagName)) {
    1736       var div = document.createElement('div');
    1737       switch (tagName) {
    1738         case 'THEAD':
    1739         case 'TBODY':
    1740           div.innerHTML = '<table><tbody>' +  html.stripScripts() + '</tbody></table>';
    1741           depth = 2;
    1742           break;
    1743         case 'TR':
    1744           div.innerHTML = '<table><tbody><tr>' +  html.stripScripts() + '</tr></tbody></table>';
    1745           depth = 3;
    1746           break;
    1747         case 'TD':
    1748           div.innerHTML = '<table><tbody><tr><td>' +  html.stripScripts() + '</td></tr></tbody></table>';
    1749           depth = 4;
    1750       }
    1751       $A(element.childNodes).each(function(node) { element.removeChild(node) });
    1752       depth.times(function() { div = div.firstChild });
    1753       $A(div.childNodes).each(function(node) { element.appendChild(node) });
    1754     } else {
    1755       element.innerHTML = html.stripScripts();
    1756     }
    1757     setTimeout(function() { html.evalScripts() }, 10);
    1758     return element;
    1759   }
     2290  Element._attributeTranslations = {
     2291    read: {
     2292      names: {
     2293        'class': 'className',
     2294        'for':   'htmlFor'
     2295      },
     2296      values: {
     2297        _getAttr: function(element, attribute) {
     2298          return element.getAttribute(attribute, 2);
     2299        },
     2300        _getAttrNode: function(element, attribute) {
     2301          var node = element.getAttributeNode(attribute);
     2302          return node ? node.value : "";
     2303        },
     2304        _getEv: function(element, attribute) {
     2305          attribute = element.getAttribute(attribute);
     2306          return attribute ? attribute.toString().slice(23, -2) : null;
     2307        },
     2308        _flag: function(element, attribute) {
     2309          return $(element).hasAttribute(attribute) ? attribute : null;
     2310        },
     2311        style: function(element) {
     2312          return element.style.cssText.toLowerCase();
     2313        },
     2314        title: function(element) {
     2315          return element.title;
     2316        }
     2317      }
     2318    }
     2319  };
     2320
     2321  Element._attributeTranslations.write = {
     2322    names: Object.extend({
     2323      cellpadding: 'cellPadding',
     2324      cellspacing: 'cellSpacing'
     2325    }, Element._attributeTranslations.read.names),
     2326    values: {
     2327      checked: function(element, value) {
     2328        element.checked = !!value;
     2329      },
     2330
     2331      style: function(element, value) {
     2332        element.style.cssText = value ? value : '';
     2333      }
     2334    }
     2335  };
     2336
     2337  Element._attributeTranslations.has = {};
     2338
     2339  $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
     2340      'encType maxLength readOnly longDesc').each(function(attr) {
     2341    Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
     2342    Element._attributeTranslations.has[attr.toLowerCase()] = attr;
     2343  });
     2344
     2345  (function(v) {
     2346    Object.extend(v, {
     2347      href:        v._getAttr,
     2348      src:         v._getAttr,
     2349      type:        v._getAttr,
     2350      action:      v._getAttrNode,
     2351      disabled:    v._flag,
     2352      checked:     v._flag,
     2353      readonly:    v._flag,
     2354      multiple:    v._flag,
     2355      onload:      v._getEv,
     2356      onunload:    v._getEv,
     2357      onclick:     v._getEv,
     2358      ondblclick:  v._getEv,
     2359      onmousedown: v._getEv,
     2360      onmouseup:   v._getEv,
     2361      onmouseover: v._getEv,
     2362      onmousemove: v._getEv,
     2363      onmouseout:  v._getEv,
     2364      onfocus:     v._getEv,
     2365      onblur:      v._getEv,
     2366      onkeypress:  v._getEv,
     2367      onkeydown:   v._getEv,
     2368      onkeyup:     v._getEv,
     2369      onsubmit:    v._getEv,
     2370      onreset:     v._getEv,
     2371      onselect:    v._getEv,
     2372      onchange:    v._getEv
     2373    });
     2374  })(Element._attributeTranslations.read.values);
    17602375}
    1761 else if (Prototype.Browser.Gecko) {
     2376
     2377else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
    17622378  Element.Methods.setOpacity = function(element, value) {
    17632379    element = $(element);
     
    17682384}
    17692385
    1770 Element._attributeTranslations = {
    1771   names: {
    1772     colspan:   "colSpan",
    1773     rowspan:   "rowSpan",
    1774     valign:    "vAlign",
    1775     datetime:  "dateTime",
    1776     accesskey: "accessKey",
    1777     tabindex:  "tabIndex",
    1778     enctype:   "encType",
    1779     maxlength: "maxLength",
    1780     readonly:  "readOnly",
    1781     longdesc:  "longDesc"
    1782   },
    1783   values: {
    1784     _getAttr: function(element, attribute) {
    1785       return element.getAttribute(attribute, 2);
    1786     },
    1787     _flag: function(element, attribute) {
    1788       return $(element).hasAttribute(attribute) ? attribute : null;
    1789     },
    1790     style: function(element) {
    1791       return element.style.cssText.toLowerCase();
    1792     },
    1793     title: function(element) {
    1794       var node = element.getAttributeNode('title');
    1795       return node.specified ? node.nodeValue : null;
    1796     }
    1797   }
     2386else if (Prototype.Browser.WebKit) {
     2387  Element.Methods.setOpacity = function(element, value) {
     2388    element = $(element);
     2389    element.style.opacity = (value == 1 || value === '') ? '' :
     2390      (value < 0.00001) ? 0 : value;
     2391
     2392    if (value == 1)
     2393      if(element.tagName == 'IMG' && element.width) {
     2394        element.width++; element.width--;
     2395      } else try {
     2396        var n = document.createTextNode(' ');
     2397        element.appendChild(n);
     2398        element.removeChild(n);
     2399      } catch (e) { }
     2400
     2401    return element;
     2402  };
     2403
     2404  // Safari returns margins on body which is incorrect if the child is absolutely
     2405  // positioned.  For performance reasons, redefine Element#cumulativeOffset for
     2406  // KHTML/WebKit only.
     2407  Element.Methods.cumulativeOffset = function(element) {
     2408    var valueT = 0, valueL = 0;
     2409    do {
     2410      valueT += element.offsetTop  || 0;
     2411      valueL += element.offsetLeft || 0;
     2412      if (element.offsetParent == document.body)
     2413        if (Element.getStyle(element, 'position') == 'absolute') break;
     2414
     2415      element = element.offsetParent;
     2416    } while (element);
     2417
     2418    return Element._returnOffset(valueL, valueT);
     2419  };
     2420}
     2421
     2422if (Prototype.Browser.IE || Prototype.Browser.Opera) {
     2423  // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements
     2424  Element.Methods.update = function(element, content) {
     2425    element = $(element);
     2426
     2427    if (content && content.toElement) content = content.toElement();
     2428    if (Object.isElement(content)) return element.update().insert(content);
     2429
     2430    content = Object.toHTML(content);
     2431    var tagName = element.tagName.toUpperCase();
     2432
     2433    if (tagName in Element._insertionTranslations.tags) {
     2434      $A(element.childNodes).each(function(node) { element.removeChild(node) });
     2435      Element._getContentFromAnonymousElement(tagName, content.stripScripts())
     2436        .each(function(node) { element.appendChild(node) });
     2437    }
     2438    else element.innerHTML = content.stripScripts();
     2439
     2440    content.evalScripts.bind(content).defer();
     2441    return element;
     2442  };
     2443}
     2444
     2445if ('outerHTML' in document.createElement('div')) {
     2446  Element.Methods.replace = function(element, content) {
     2447    element = $(element);
     2448
     2449    if (content && content.toElement) content = content.toElement();
     2450    if (Object.isElement(content)) {
     2451      element.parentNode.replaceChild(content, element);
     2452      return element;
     2453    }
     2454
     2455    content = Object.toHTML(content);
     2456    var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
     2457
     2458    if (Element._insertionTranslations.tags[tagName]) {
     2459      var nextSibling = element.next();
     2460      var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
     2461      parent.removeChild(element);
     2462      if (nextSibling)
     2463        fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
     2464      else
     2465        fragments.each(function(node) { parent.appendChild(node) });
     2466    }
     2467    else element.outerHTML = content.stripScripts();
     2468
     2469    content.evalScripts.bind(content).defer();
     2470    return element;
     2471  };
     2472}
     2473
     2474Element._returnOffset = function(l, t) {
     2475  var result = [l, t];
     2476  result.left = l;
     2477  result.top = t;
     2478  return result;
    17982479};
    17992480
     2481Element._getContentFromAnonymousElement = function(tagName, html) {
     2482  var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
     2483  if (t) {
     2484    div.innerHTML = t[0] + html + t[1];
     2485    t[2].times(function() { div = div.firstChild });
     2486  } else div.innerHTML = html;
     2487  return $A(div.childNodes);
     2488};
     2489
     2490Element._insertionTranslations = {
     2491  before: function(element, node) {
     2492    element.parentNode.insertBefore(node, element);
     2493  },
     2494  top: function(element, node) {
     2495    element.insertBefore(node, element.firstChild);
     2496  },
     2497  bottom: function(element, node) {
     2498    element.appendChild(node);
     2499  },
     2500  after: function(element, node) {
     2501    element.parentNode.insertBefore(node, element.nextSibling);
     2502  },
     2503  tags: {
     2504    TABLE:  ['<table>',                '</table>',                   1],
     2505    TBODY:  ['<table><tbody>',         '</tbody></table>',           2],
     2506    TR:     ['<table><tbody><tr>',     '</tr></tbody></table>',      3],
     2507    TD:     ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
     2508    SELECT: ['<select>',               '</select>',                  1]
     2509  }
     2510};
     2511
    18002512(function() {
    1801   Object.extend(this, {
    1802     href: this._getAttr,
    1803     src:  this._getAttr,
    1804     type: this._getAttr,
    1805     disabled: this._flag,
    1806     checked:  this._flag,
    1807     readonly: this._flag,
    1808     multiple: this._flag
     2513  Object.extend(this.tags, {
     2514    THEAD: this.tags.TBODY,
     2515    TFOOT: this.tags.TBODY,
     2516    TH:    this.tags.TD
    18092517  });
    1810 }).call(Element._attributeTranslations.values);
     2518}).call(Element._insertionTranslations);
    18112519
    18122520Element.Methods.Simulated = {
    18132521  hasAttribute: function(element, attribute) {
    1814     var t = Element._attributeTranslations, node;
    1815     attribute = t.names[attribute] || attribute;
    1816     node = $(element).getAttributeNode(attribute);
     2522    attribute = Element._attributeTranslations.has[attribute] || attribute;
     2523    var node = $(element).getAttributeNode(attribute);
    18172524    return node && node.specified;
    18182525  }
    18192526};
    18202527
    1821 Element.Methods.ByTag = {};
     2528Element.Methods.ByTag = { };
    18222529
    18232530Object.extend(Element, Element.Methods);
    18242531
    18252532if (!Prototype.BrowserFeatures.ElementExtensions &&
    1826  document.createElement('div').__proto__) {
    1827   window.HTMLElement = {};
     2533    document.createElement('div').__proto__) {
     2534  window.HTMLElement = { };
    18282535  window.HTMLElement.prototype = document.createElement('div').__proto__;
    18292536  Prototype.BrowserFeatures.ElementExtensions = true;
    18302537}
     2538
     2539Element.extend = (function() {
     2540  if (Prototype.BrowserFeatures.SpecificElementExtensions)
     2541    return Prototype.K;
     2542
     2543  var Methods = { }, ByTag = Element.Methods.ByTag;
     2544
     2545  var extend = Object.extend(function(element) {
     2546    if (!element || element._extendedByPrototype ||
     2547        element.nodeType != 1 || element == window) return element;
     2548
     2549    var methods = Object.clone(Methods),
     2550      tagName = element.tagName, property, value;
     2551
     2552    // extend methods for specific tags
     2553    if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
     2554
     2555    for (property in methods) {
     2556      value = methods[property];
     2557      if (Object.isFunction(value) && !(property in element))
     2558        element[property] = value.methodize();
     2559    }
     2560
     2561    element._extendedByPrototype = Prototype.emptyFunction;
     2562    return element;
     2563
     2564  }, {
     2565    refresh: function() {
     2566      // extend methods for all tags (Safari doesn't need this)
     2567      if (!Prototype.BrowserFeatures.ElementExtensions) {
     2568        Object.extend(Methods, Element.Methods);
     2569        Object.extend(Methods, Element.Methods.Simulated);
     2570      }
     2571    }
     2572  });
     2573
     2574  extend.refresh();
     2575  return extend;
     2576})();
    18312577
    18322578Element.hasAttribute = function(element, attribute) {
     
    18542600  }
    18552601
    1856   if (!tagName) Object.extend(Element.Methods, methods || {});
     2602  if (!tagName) Object.extend(Element.Methods, methods || { });
    18572603  else {
    1858     if (tagName.constructor == Array) tagName.each(extend);
     2604    if (Object.isArray(tagName)) tagName.each(extend);
    18592605    else extend(tagName);
    18602606  }
     
    18632609    tagName = tagName.toUpperCase();
    18642610    if (!Element.Methods.ByTag[tagName])
    1865       Element.Methods.ByTag[tagName] = {};
     2611      Element.Methods.ByTag[tagName] = { };
    18662612    Object.extend(Element.Methods.ByTag[tagName], methods);
    18672613  }
     
    18692615  function copy(methods, destination, onlyIfAbsent) {
    18702616    onlyIfAbsent = onlyIfAbsent || false;
    1871     var cache = Element.extend.cache;
    18722617    for (var property in methods) {
    18732618      var value = methods[property];
     2619      if (!Object.isFunction(value)) continue;
    18742620      if (!onlyIfAbsent || !(property in destination))
    1875         destination[property] = cache.findOrStore(value);
     2621        destination[property] = value.methodize();
    18762622    }
    18772623  }
     
    18972643    if (window[klass]) return window[klass];
    18982644
    1899     window[klass] = {};
     2645    window[klass] = { };
    19002646    window[klass].prototype = document.createElement(tagName).__proto__;
    19012647    return window[klass];
     
    19102656    for (var tag in Element.Methods.ByTag) {
    19112657      var klass = findDOMClass(tag);
    1912       if (typeof klass == "undefined") continue;
     2658      if (Object.isUndefined(klass)) continue;
    19132659      copy(T[tag], klass.prototype);
    19142660    }
     
    19172663  Object.extend(Element, Element.Methods);
    19182664  delete Element.ByTag;
     2665
     2666  if (Element.extend.refresh) Element.extend.refresh();
     2667  Element.cache = { };
    19192668};
    19202669
    1921 var Toggle = { display: Element.toggle };
    1922 
    1923 /*--------------------------------------------------------------------------*/
    1924 
    1925 Abstract.Insertion = function(adjacency) {
    1926   this.adjacency = adjacency;
    1927 }
    1928 
    1929 Abstract.Insertion.prototype = {
    1930   initialize: function(element, content) {
    1931     this.element = $(element);
    1932     this.content = content.stripScripts();
    1933 
    1934     if (this.adjacency && this.element.insertAdjacentHTML) {
    1935       try {
    1936         this.element.insertAdjacentHTML(this.adjacency, this.content);
    1937       } catch (e) {
    1938         var tagName = this.element.tagName.toUpperCase();
    1939         if (['TBODY', 'TR'].include(tagName)) {
    1940           this.insertContent(this.contentFromAnonymousTable());
    1941         } else {
    1942           throw e;
    1943         }
    1944       }
    1945     } else {
    1946       this.range = this.element.ownerDocument.createRange();
    1947       if (this.initializeRange) this.initializeRange();
    1948       this.insertContent([this.range.createContextualFragment(this.content)]);
    1949     }
    1950 
    1951     setTimeout(function() {content.evalScripts()}, 10);
    1952   },
    1953 
    1954   contentFromAnonymousTable: function() {
    1955     var div = document.createElement('div');
    1956     div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
    1957     return $A(div.childNodes[0].childNodes[0].childNodes);
    1958   }
    1959 }
    1960 
    1961 var Insertion = new Object();
    1962 
    1963 Insertion.Before = Class.create();
    1964 Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
    1965   initializeRange: function() {
    1966     this.range.setStartBefore(this.element);
    1967   },
    1968 
    1969   insertContent: function(fragments) {
    1970     fragments.each((function(fragment) {
    1971       this.element.parentNode.insertBefore(fragment, this.element);
    1972     }).bind(this));
    1973   }
    1974 });
    1975 
    1976 Insertion.Top = Class.create();
    1977 Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
    1978   initializeRange: function() {
    1979     this.range.selectNodeContents(this.element);
    1980     this.range.collapse(true);
    1981   },
    1982 
    1983   insertContent: function(fragments) {
    1984     fragments.reverse(false).each((function(fragment) {
    1985       this.element.insertBefore(fragment, this.element.firstChild);
    1986     }).bind(this));
    1987   }
    1988 });
    1989 
    1990 Insertion.Bottom = Class.create();
    1991 Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
    1992   initializeRange: function() {
    1993     this.range.selectNodeContents(this.element);
    1994     this.range.collapse(this.element);
    1995   },
    1996 
    1997   insertContent: function(fragments) {
    1998     fragments.each((function(fragment) {
    1999       this.element.appendChild(fragment);
    2000     }).bind(this));
    2001   }
    2002 });
    2003 
    2004 Insertion.After = Class.create();
    2005 Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
    2006   initializeRange: function() {
    2007     this.range.setStartAfter(this.element);
    2008   },
    2009 
    2010   insertContent: function(fragments) {
    2011     fragments.each((function(fragment) {
    2012       this.element.parentNode.insertBefore(fragment,
    2013         this.element.nextSibling);
    2014     }).bind(this));
    2015   }
    2016 });
    2017 
    2018 /*--------------------------------------------------------------------------*/
    2019 
    2020 Element.ClassNames = Class.create();
    2021 Element.ClassNames.prototype = {
    2022   initialize: function(element) {
    2023     this.element = $(element);
    2024   },
    2025 
    2026   _each: function(iterator) {
    2027     this.element.className.split(/\s+/).select(function(name) {
    2028       return name.length > 0;
    2029     })._each(iterator);
    2030   },
    2031 
    2032   set: function(className) {
    2033     this.element.className = className;
    2034   },
    2035 
    2036   add: function(classNameToAdd) {
    2037     if (this.include(classNameToAdd)) return;
    2038     this.set($A(this).concat(classNameToAdd).join(' '));
    2039   },
    2040 
    2041   remove: function(classNameToRemove) {
    2042     if (!this.include(classNameToRemove)) return;
    2043     this.set($A(this).without(classNameToRemove).join(' '));
    2044   },
    2045 
    2046   toString: function() {
    2047     return $A(this).join(' ');
     2670document.viewport = {
     2671  getDimensions: function() {
     2672    var dimensions = { };
     2673    var B = Prototype.Browser;
     2674    $w('width height').each(function(d) {
     2675      var D = d.capitalize();
     2676      dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] :
     2677        (B.Opera) ? document.body['client' + D] : document.documentElement['client' + D];
     2678    });
     2679    return dimensions;
     2680  },
     2681
     2682  getWidth: function() {
     2683    return this.getDimensions().width;
     2684  },
     2685
     2686  getHeight: function() {
     2687    return this.getDimensions().height;
     2688  },
     2689
     2690  getScrollOffsets: function() {
     2691    return Element._returnOffset(
     2692      window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
     2693      window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
    20482694  }
    20492695};
    2050 
    2051 Object.extend(Element.ClassNames.prototype, Enumerable);
    20522696/* Portions of the Selector class are derived from Jack Slocum’s DomQuery,
    20532697 * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
    20542698 * license.  Please see http://www.yui-ext.com/ for more information. */
    20552699
    2056 var Selector = Class.create();
    2057 
    2058 Selector.prototype = {
     2700var Selector = Class.create({
    20592701  initialize: function(expression) {
    20602702    this.expression = expression.strip();
     
    20622704  },
    20632705
     2706  shouldUseXPath: function() {
     2707    if (!Prototype.BrowserFeatures.XPath) return false;
     2708
     2709    var e = this.expression;
     2710
     2711    // Safari 3 chokes on :*-of-type and :empty
     2712    if (Prototype.Browser.WebKit &&
     2713     (e.include("-of-type") || e.include(":empty")))
     2714      return false;
     2715
     2716    // XPath can't do namespaced attributes, nor can it read
     2717    // the "checked" property from DOM nodes
     2718    if ((/(\[[\w-]*?:|:checked)/).test(this.expression))
     2719      return false;
     2720
     2721    return true;
     2722  },
     2723
    20642724  compileMatcher: function() {
    2065     // Selectors with namespaced attributes can't use the XPath version
    2066     if (Prototype.BrowserFeatures.XPath && !(/\[[\w-]*?:/).test(this.expression))
     2725    if (this.shouldUseXPath())
    20672726      return this.compileXPathMatcher();
    20682727
     
    20712730
    20722731    if (Selector._cache[e]) {
    2073       this.matcher = Selector._cache[e]; return;
    2074     }
     2732      this.matcher = Selector._cache[e];
     2733      return;
     2734    }
     2735
    20752736    this.matcher = ["this.matcher = function(root) {",
    20762737                    "var r = root, h = Selector.handlers, c = false, n;"];
     
    20812742        p = ps[i];
    20822743        if (m = e.match(p)) {
    2083           this.matcher.push(typeof c[i] == 'function' ? c[i](m) :
     2744          this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
    20842745              new Template(c[i]).evaluate(m));
    20852746          e = e.replace(m[0], '');
     
    20962757  compileXPathMatcher: function() {
    20972758    var e = this.expression, ps = Selector.patterns,
    2098         x = Selector.xpath, le,  m;
     2759        x = Selector.xpath, le, m;
    20992760
    21002761    if (Selector._cache[e]) {
     
    21072768      for (var i in ps) {
    21082769        if (m = e.match(ps[i])) {
    2109           this.matcher.push(typeof x[i] == 'function' ? x[i](m) :
     2770          this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :
    21102771            new Template(x[i]).evaluate(m));
    21112772          e = e.replace(m[0], '');
     
    21262787
    21272788  match: function(element) {
    2128     return this.findElements(document).include(element);
     2789    this.tokens = [];
     2790
     2791    var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
     2792    var le, p, m;
     2793
     2794    while (e && le !== e && (/\S/).test(e)) {
     2795      le = e;
     2796      for (var i in ps) {
     2797        p = ps[i];
     2798        if (m = e.match(p)) {
     2799          // use the Selector.assertions methods unless the selector
     2800          // is too complex.
     2801          if (as[i]) {
     2802            this.tokens.push([i, Object.clone(m)]);
     2803            e = e.replace(m[0], '');
     2804          } else {
     2805            // reluctantly do a document-wide search
     2806            // and look for a match in the array
     2807            return this.findElements(document).include(element);
     2808          }
     2809        }
     2810      }
     2811    }
     2812
     2813    var match = true, name, matches;
     2814    for (var i = 0, token; token = this.tokens[i]; i++) {
     2815      name = token[0], matches = token[1];
     2816      if (!Selector.assertions[name](element, matches)) {
     2817        match = false; break;
     2818      }
     2819    }
     2820
     2821    return match;
    21292822  },
    21302823
     
    21362829    return "#<Selector:" + this.expression.inspect() + ">";
    21372830  }
    2138 };
     2831});
    21392832
    21402833Object.extend(Selector, {
    2141   _cache: {},
     2834  _cache: { },
    21422835
    21432836  xpath: {
     
    21532846    className:    "[contains(concat(' ', @class, ' '), ' #{1} ')]",
    21542847    id:           "[@id='#{1}']",
    2155     attrPresence: "[@#{1}]",
     2848    attrPresence: function(m) {
     2849      m[1] = m[1].toLowerCase();
     2850      return new Template("[@#{1}]").evaluate(m);
     2851    },
    21562852    attr: function(m) {
     2853      m[1] = m[1].toLowerCase();
    21572854      m[3] = m[5] || m[6];
    21582855      return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
     
    21612858      var h = Selector.xpath.pseudos[m[1]];
    21622859      if (!h) return '';
    2163       if (typeof h === 'function') return h(m);
     2860      if (Object.isFunction(h)) return h(m);
    21642861      return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
    21652862    },
     
    21832880      'not': function(m) {
    21842881        var e = m[6], p = Selector.patterns,
    2185             x = Selector.xpath, le, m, v;
     2882            x = Selector.xpath, le, v;
    21862883
    21872884        var exclusion = [];
     
    21902887          for (var i in p) {
    21912888            if (m = e.match(p[i])) {
    2192               v = typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m);
     2889              v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);
    21932890              exclusion.push("(" + v.substring(1, v.length - 1) + ")");
    21942891              e = e.replace(m[0], '');
     
    22402937
    22412938  criteria: {
    2242     tagName:      'n = h.tagName(n, r, "#{1}", c);   c = false;',
    2243     className:    'n = h.className(n, r, "#{1}", c); c = false;',
    2244     id:           'n = h.id(n, r, "#{1}", c);        c = false;',
    2245     attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
     2939    tagName:      'n = h.tagName(n, r, "#{1}", c);      c = false;',
     2940    className:    'n = h.className(n, r, "#{1}", c);    c = false;',
     2941    id:           'n = h.id(n, r, "#{1}", c);           c = false;',
     2942    attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;',
    22462943    attr: function(m) {
    22472944      m[3] = (m[5] || m[6]);
    2248       return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
    2249     },
    2250     pseudo:       function(m) {
     2945      return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);
     2946    },
     2947    pseudo: function(m) {
    22512948      if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
    22522949      return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
     
    22702967    id:           /^#([\w\-\*]+)(\b|$)/,
    22712968    className:    /^\.([\w\-\*]+)(\b|$)/,
    2272     pseudo:       /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s|(?=:))/,
     2969    pseudo:
     2970/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,
    22732971    attrPresence: /^\[([\w]+)\]/,
    2274     attr:         /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/
     2972    attr:         /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
     2973  },
     2974
     2975  // for Selector.match and Element#match
     2976  assertions: {
     2977    tagName: function(element, matches) {
     2978      return matches[1].toUpperCase() == element.tagName.toUpperCase();
     2979    },
     2980
     2981    className: function(element, matches) {
     2982      return Element.hasClassName(element, matches[1]);
     2983    },
     2984
     2985    id: function(element, matches) {
     2986      return element.id === matches[1];
     2987    },
     2988
     2989    attrPresence: function(element, matches) {
     2990      return Element.hasAttribute(element, matches[1]);
     2991    },
     2992
     2993    attr: function(element, matches) {
     2994      var nodeValue = Element.readAttribute(element, matches[1]);
     2995      return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);
     2996    }
    22752997  },
    22762998
     
    22863008    // marks an array of nodes for counting
    22873009    mark: function(nodes) {
     3010      var _true = Prototype.emptyFunction;
    22883011      for (var i = 0, node; node = nodes[i]; i++)
    2289         node._counted = true;
     3012        node._countedByPrototype = _true;
    22903013      return nodes;
    22913014    },
     
    22933016    unmark: function(nodes) {
    22943017      for (var i = 0, node; node = nodes[i]; i++)
    2295         node._counted = undefined;
     3018        node._countedByPrototype = undefined;
    22963019      return nodes;
    22973020    },
     
    23013024    // rather than nth-child
    23023025    index: function(parentNode, reverse, ofType) {
    2303       parentNode._counted = true;
     3026      parentNode._countedByPrototype = Prototype.emptyFunction;
    23043027      if (reverse) {
    23053028        for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
    2306           node = nodes[i];
    2307           if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
     3029          var node = nodes[i];
     3030          if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
    23083031        }
    23093032      } else {
    23103033        for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
    2311           if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
     3034          if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
    23123035      }
    23133036    },
     
    23183041      var results = [], n;
    23193042      for (var i = 0, l = nodes.length; i < l; i++)
    2320         if (!(n = nodes[i])._counted) {
    2321           n._counted = true;
     3043        if (!(n = nodes[i])._countedByPrototype) {
     3044          n._countedByPrototype = Prototype.emptyFunction;
    23223045          results.push(Element.extend(n));
    23233046        }
     
    23363059      var h = Selector.handlers;
    23373060      for (var i = 0, results = [], node; node = nodes[i]; i++) {
    2338         for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
     3061        for (var j = 0, child; child = node.childNodes[j]; j++)
    23393062          if (child.nodeType == 1 && child.tagName != '!') results.push(child);
    23403063      }
     
    23713094    // TOKEN FUNCTIONS
    23723095    tagName: function(nodes, root, tagName, combinator) {
    2373       tagName = tagName.toUpperCase();
     3096      var uTagName = tagName.toUpperCase();
    23743097      var results = [], h = Selector.handlers;
    23753098      if (nodes) {
     
    23843107        }
    23853108        for (var i = 0, node; node = nodes[i]; i++)
    2386           if (node.tagName.toUpperCase() == tagName) results.push(node);
     3109          if (node.tagName.toUpperCase() === uTagName) results.push(node);
    23873110        return results;
    23883111      } else return root.getElementsByTagName(tagName);
     
    23913114    id: function(nodes, root, id, combinator) {
    23923115      var targetNode = $(id), h = Selector.handlers;
    2393       if (!nodes && root == document) return targetNode ? [targetNode] : [];
     3116      if (!targetNode) return [];
     3117      if (!nodes && root == document) return [targetNode];
    23943118      if (nodes) {
    23953119        if (combinator) {
     
    24303154    },
    24313155
    2432     attrPresence: function(nodes, root, attr) {
     3156    attrPresence: function(nodes, root, attr, combinator) {
     3157      if (!nodes) nodes = root.getElementsByTagName("*");
     3158      if (nodes && combinator) nodes = this[combinator](nodes);
    24333159      var results = [];
    24343160      for (var i = 0, node; node = nodes[i]; i++)
     
    24373163    },
    24383164
    2439     attr: function(nodes, root, attr, value, operator) {
     3165    attr: function(nodes, root, attr, value, operator, combinator) {
    24403166      if (!nodes) nodes = root.getElementsByTagName("*");
     3167      if (nodes && combinator) nodes = this[combinator](nodes);
    24413168      var handler = Selector.operators[operator], results = [];
    24423169      for (var i = 0, node; node = nodes[i]; i++) {
     
    25173244      h.mark(nodes);
    25183245      for (var i = 0, node; node = nodes[i]; i++) {
    2519         if (!node.parentNode._counted) {
     3246        if (!node.parentNode._countedByPrototype) {
    25203247          h.index(node.parentNode, reverse, ofType);
    25213248          indexed.push(node.parentNode);
     
    25553282      h.mark(exclusions);
    25563283      for (var i = 0, results = [], node; node = nodes[i]; i++)
    2557         if (!node._counted) results.push(node);
     3284        if (!node._countedByPrototype) results.push(node);
    25583285      h.unmark(exclusions);
    25593286      return results;
     
    25893316  },
    25903317
     3318  split: function(expression) {
     3319    var expressions = [];
     3320    expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
     3321      expressions.push(m[1].strip());
     3322    });
     3323    return expressions;
     3324  },
     3325
    25913326  matchElements: function(elements, expression) {
    2592     var matches = new Selector(expression).findElements(), h = Selector.handlers;
     3327    var matches = $$(expression), h = Selector.handlers;
    25933328    h.mark(matches);
    25943329    for (var i = 0, results = [], element; element = elements[i]; i++)
    2595       if (element._counted) results.push(element);
     3330      if (element._countedByPrototype) results.push(element);
    25963331    h.unmark(matches);
    25973332    return results;
     
    25993334
    26003335  findElement: function(elements, expression, index) {
    2601     if (typeof expression == 'number') {
     3336    if (Object.isNumber(expression)) {
    26023337      index = expression; expression = false;
    26033338    }
     
    26063341
    26073342  findChildElements: function(element, expressions) {
    2608     var exprs = expressions.join(','), expressions = [];
    2609     exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
    2610       expressions.push(m[1].strip());
    2611     });
     3343    expressions = Selector.split(expressions.join(','));
    26123344    var results = [], h = Selector.handlers;
    26133345    for (var i = 0, l = expressions.length, selector; i < l; i++) {
     
    26183350  }
    26193351});
     3352
     3353if (Prototype.Browser.IE) {
     3354  Object.extend(Selector.handlers, {
     3355    // IE returns comment nodes on getElementsByTagName("*").
     3356    // Filter them out.
     3357    concat: function(a, b) {
     3358      for (var i = 0, node; node = b[i]; i++)
     3359        if (node.tagName !== "!") a.push(node);
     3360      return a;
     3361    },
     3362
     3363    // IE improperly serializes _countedByPrototype in (inner|outer)HTML.
     3364    unmark: function(nodes) {
     3365      for (var i = 0, node; node = nodes[i]; i++)
     3366        node.removeAttribute('_countedByPrototype');
     3367      return nodes;
     3368    }
     3369  });
     3370}
    26203371
    26213372function $$() {
     
    26283379  },
    26293380
    2630   serializeElements: function(elements, getHash) {
    2631     var data = elements.inject({}, function(result, element) {
     3381  serializeElements: function(elements, options) {
     3382    if (typeof options != 'object') options = { hash: !!options };
     3383    else if (Object.isUndefined(options.hash)) options.hash = true;
     3384    var key, value, submitted = false, submit = options.submit;
     3385
     3386    var data = elements.inject({ }, function(result, element) {
    26323387      if (!element.disabled && element.name) {
    2633         var key = element.name, value = $(element).getValue();
    2634         if (value != null) {
    2635                 if (key in result) {
    2636             if (result[key].constructor != Array) result[key] = [result[key]];
     3388        key = element.name; value = $(element).getValue();
     3389        if (value != null && (element.type != 'submit' || (!submitted &&
     3390            submit !== false && (!submit || key == submit) && (submitted = true)))) {
     3391          if (key in result) {
     3392            // a key is already present; construct an array of values
     3393            if (!Object.isArray(result[key])) result[key] = [result[key]];
    26373394            result[key].push(value);
    26383395          }
     
    26433400    });
    26443401
    2645     return getHash ? data : Hash.toQueryString(data);
     3402    return options.hash ? data : Object.toQueryString(data);
    26463403  }
    26473404};
    26483405
    26493406Form.Methods = {
    2650   serialize: function(form, getHash) {
    2651     return Form.serializeElements(Form.getElements(form), getHash);
     3407  serialize: function(form, options) {
     3408    return Form.serializeElements(Form.getElements(form), options);
    26523409  },
    26533410
     
    26913448
    26923449  findFirstElement: function(form) {
    2693     return $(form).getElements().find(function(element) {
    2694       return element.type != 'hidden' && !element.disabled &&
    2695         ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
     3450    var elements = $(form).getElements().findAll(function(element) {
     3451      return 'hidden' != element.type && !element.disabled;
     3452    });
     3453    var firstByIndex = elements.findAll(function(element) {
     3454      return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
     3455    }).sortBy(function(element) { return element.tabIndex }).first();
     3456
     3457    return firstByIndex ? firstByIndex : elements.find(function(element) {
     3458      return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
    26963459    });
    26973460  },
     
    27043467
    27053468  request: function(form, options) {
    2706     form = $(form), options = Object.clone(options || {});
    2707 
    2708     var params = options.parameters;
     3469    form = $(form), options = Object.clone(options || { });
     3470
     3471    var params = options.parameters, action = form.readAttribute('action') || '';
     3472    if (action.blank()) action = window.location.href;
    27093473    options.parameters = form.serialize(true);
    27103474
    27113475    if (params) {
    2712       if (typeof params == 'string') params = params.toQueryParams();
     3476      if (Object.isString(params)) params = params.toQueryParams();
    27133477      Object.extend(options.parameters, params);
    27143478    }
     
    27173481      options.method = form.method;
    27183482
    2719     return new Ajax.Request(form.readAttribute('action'), options);
    2720   }
    2721 }
     3483    return new Ajax.Request(action, options);
     3484  }
     3485};
    27223486
    27233487/*--------------------------------------------------------------------------*/
     
    27333497    return element;
    27343498  }
    2735 }
     3499};
    27363500
    27373501Form.Element.Methods = {
     
    27413505      var value = element.getValue();
    27423506      if (value != undefined) {
    2743         var pair = {};
     3507        var pair = { };
    27443508        pair[element.name] = value;
    2745         return Hash.toQueryString(pair);
     3509        return Object.toQueryString(pair);
    27463510      }
    27473511    }
     
    27533517    var method = element.tagName.toLowerCase();
    27543518    return Form.Element.Serializers[method](element);
     3519  },
     3520
     3521  setValue: function(element, value) {
     3522    element = $(element);
     3523    var method = element.tagName.toLowerCase();
     3524    Form.Element.Serializers[method](element, value);
     3525    return element;
    27553526  },
    27563527
     
    27693540      element.focus();
    27703541      if (element.select && (element.tagName.toLowerCase() != 'input' ||
    2771         !['button', 'reset', 'submit'].include(element.type)))
     3542          !['button', 'reset', 'submit'].include(element.type)))
    27723543        element.select();
    2773     } catch (e) {}
     3544    } catch (e) { }
    27743545    return element;
    27753546  },
     
    27873558    return element;
    27883559  }
    2789 }
     3560};
    27903561
    27913562/*--------------------------------------------------------------------------*/
     
    27973568
    27983569Form.Element.Serializers = {
    2799   input: function(element) {
     3570  input: function(element, value) {
    28003571    switch (element.type.toLowerCase()) {
    28013572      case 'checkbox':
    28023573      case 'radio':
    2803         return Form.Element.Serializers.inputSelector(element);
     3574        return Form.Element.Serializers.inputSelector(element, value);
    28043575      default:
    2805         return Form.Element.Serializers.textarea(element);
    2806     }
    2807   },
    2808 
    2809   inputSelector: function(element) {
    2810     return element.checked ? element.value : null;
    2811   },
    2812 
    2813   textarea: function(element) {
    2814     return element.value;
    2815   },
    2816 
    2817   select: function(element) {
    2818     return this[element.type == 'select-one' ?
    2819       'selectOne' : 'selectMany'](element);
     3576        return Form.Element.Serializers.textarea(element, value);
     3577    }
     3578  },
     3579
     3580  inputSelector: function(element, value) {
     3581    if (Object.isUndefined(value)) return element.checked ? element.value : null;
     3582    else element.checked = !!value;
     3583  },
     3584
     3585  textarea: function(element, value) {
     3586    if (Object.isUndefined(value)) return element.value;
     3587    else element.value = value;
     3588  },
     3589
     3590  select: function(element, index) {
     3591    if (Object.isUndefined(index))
     3592      return this[element.type == 'select-one' ?
     3593        'selectOne' : 'selectMany'](element);
     3594    else {
     3595      var opt, value, single = !Object.isArray(index);
     3596      for (var i = 0, length = element.length; i < length; i++) {
     3597        opt = element.options[i];
     3598        value = this.optionValue(opt);
     3599        if (single) {
     3600          if (value == index) {
     3601            opt.selected = true;
     3602            return;
     3603          }
     3604        }
     3605        else opt.selected = index.include(value);
     3606      }
     3607    }
    28203608  },
    28213609
     
    28403628    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
    28413629  }
    2842 }
     3630};
    28433631
    28443632/*--------------------------------------------------------------------------*/
    28453633
    2846 Abstract.TimedObserver = function() {}
    2847 Abstract.TimedObserver.prototype = {
    2848   initialize: function(element, frequency, callback) {
    2849     this.frequency = frequency;
     3634Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
     3635  initialize: function($super, element, frequency, callback) {
     3636    $super(callback, frequency);
    28503637    this.element   = $(element);
    2851     this.callback  = callback;
    2852 
    28533638    this.lastValue = this.getValue();
    2854     this.registerCallback();
    2855   },
    2856 
    2857   registerCallback: function() {
    2858     setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
    2859   },
    2860 
    2861   onTimerEvent: function() {
     3639  },
     3640
     3641  execute: function() {
    28623642    var value = this.getValue();
    2863     var changed = ('string' == typeof this.lastValue && 'string' == typeof value
    2864       ? this.lastValue != value : String(this.lastValue) != String(value));
    2865     if (changed) {
     3643    if (Object.isString(this.lastValue) && Object.isString(value) ?
     3644        this.lastValue != value : String(this.lastValue) != String(value)) {
    28663645      this.callback(this.element, value);
    28673646      this.lastValue = value;
    28683647    }
    28693648  }
    2870 }
    2871 
    2872 Form.Element.Observer = Class.create();
    2873 Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
     3649});
     3650
     3651Form.Element.Observer = Class.create(Abstract.TimedObserver, {
    28743652  getValue: function() {
    28753653    return Form.Element.getValue(this.element);
     
    28773655});
    28783656
    2879 Form.Observer = Class.create();
    2880 Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
     3657Form.Observer = Class.create(Abstract.TimedObserver, {
    28813658  getValue: function() {
    28823659    return Form.serialize(this.element);
     
    28863663/*--------------------------------------------------------------------------*/
    28873664
    2888 Abstract.EventObserver = function() {}
    2889 Abstract.EventObserver.prototype = {
     3665Abstract.EventObserver = Class.create({
    28903666  initialize: function(element, callback) {
    28913667    this.element  = $(element);
     
    29083684
    29093685  registerFormCallbacks: function() {
    2910     Form.getElements(this.element).each(this.registerCallback.bind(this));
     3686    Form.getElements(this.element).each(this.registerCallback, this);
    29113687  },
    29123688
     
    29243700    }
    29253701  }
    2926 }
    2927 
    2928 Form.Element.EventObserver = Class.create();
    2929 Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
     3702});
     3703
     3704Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
    29303705  getValue: function() {
    29313706    return Form.Element.getValue(this.element);
     
    29333708});
    29343709
    2935 Form.EventObserver = Class.create();
    2936 Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
     3710Form.EventObserver = Class.create(Abstract.EventObserver, {
    29373711  getValue: function() {
    29383712    return Form.serialize(this.element);
    29393713  }
    29403714});
    2941 if (!window.Event) {
    2942   var Event = new Object();
    2943 }
     3715if (!window.Event) var Event = { };
    29443716
    29453717Object.extend(Event, {
     
    29573729  KEY_PAGEUP:   33,
    29583730  KEY_PAGEDOWN: 34,
    2959 
    2960   element: function(event) {
    2961     return $(event.target || event.srcElement);
    2962   },
    2963 
    2964   isLeftClick: function(event) {
    2965     return (((event.which) && (event.which == 1)) ||
    2966             ((event.button) && (event.button == 1)));
    2967   },
    2968 
    2969   pointerX: function(event) {
    2970     return event.pageX || (event.clientX +
    2971       (document.documentElement.scrollLeft || document.body.scrollLeft));
    2972   },
    2973 
    2974   pointerY: function(event) {
    2975     return event.pageY || (event.clientY +
    2976       (document.documentElement.scrollTop || document.body.scrollTop));
    2977   },
    2978 
    2979   stop: function(event) {
    2980     if (event.preventDefault) {
     3731  KEY_INSERT:   45,
     3732
     3733  cache: { },
     3734
     3735  relatedTarget: function(event) {
     3736    var element;
     3737    switch(event.type) {
     3738      case 'mouseover': element = event.fromElement; break;
     3739      case 'mouseout':  element = event.toElement;   break;
     3740      default: return null;
     3741    }
     3742    return Element.extend(element);
     3743  }
     3744});
     3745
     3746Event.Methods = (function() {
     3747  var isButton;
     3748
     3749  if (Prototype.Browser.IE) {
     3750    var buttonMap = { 0: 1, 1: 4, 2: 2 };
     3751    isButton = function(event, code) {
     3752      return event.button == buttonMap[code];
     3753    };
     3754
     3755  } else if (Prototype.Browser.WebKit) {
     3756    isButton = function(event, code) {
     3757      switch (code) {
     3758        case 0: return event.which == 1 && !event.metaKey;
     3759        case 1: return event.which == 1 && event.metaKey;
     3760        default: return false;
     3761      }
     3762    };
     3763
     3764  } else {
     3765    isButton = function(event, code) {
     3766      return event.which ? (event.which === code + 1) : (event.button === code);
     3767    };
     3768  }
     3769
     3770  return {
     3771    isLeftClick:   function(event) { return isButton(event, 0) },
     3772    isMiddleClick: function(event) { return isButton(event, 1) },
     3773    isRightClick:  function(event) { return isButton(event, 2) },
     3774
     3775    element: function(event) {
     3776      var node = Event.extend(event).target;
     3777      return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node);
     3778    },
     3779
     3780    findElement: function(event, expression) {
     3781      var element = Event.element(event);
     3782      if (!expression) return element;
     3783      var elements = [element].concat(element.ancestors());
     3784      return Selector.findElement(elements, expression, 0);
     3785    },
     3786
     3787    pointer: function(event) {
     3788      return {
     3789        x: event.pageX || (event.clientX +
     3790          (document.documentElement.scrollLeft || document.body.scrollLeft)),
     3791        y: event.pageY || (event.clientY +
     3792          (document.documentElement.scrollTop || document.body.scrollTop))
     3793      };
     3794    },
     3795
     3796    pointerX: function(event) { return Event.pointer(event).x },
     3797    pointerY: function(event) { return Event.pointer(event).y },
     3798
     3799    stop: function(event) {
     3800      Event.extend(event);
    29813801      event.preventDefault();
    29823802      event.stopPropagation();
     3803      event.stopped = true;
     3804    }
     3805  };
     3806})();
     3807
     3808Event.extend = (function() {
     3809  var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
     3810    m[name] = Event.Methods[name].methodize();
     3811    return m;
     3812  });
     3813
     3814  if (Prototype.Browser.IE) {
     3815    Object.extend(methods, {
     3816      stopPropagation: function() { this.cancelBubble = true },
     3817      preventDefault:  function() { this.returnValue = false },
     3818      inspect: function() { return "[object Event]" }
     3819    });
     3820
     3821    return function(event) {
     3822      if (!event) return false;
     3823      if (event._extendedByPrototype) return event;
     3824
     3825      event._extendedByPrototype = Prototype.emptyFunction;
     3826      var pointer = Event.pointer(event);
     3827      Object.extend(event, {
     3828        target: event.srcElement,
     3829        relatedTarget: Event.relatedTarget(event),
     3830        pageX:  pointer.x,
     3831        pageY:  pointer.y
     3832      });
     3833      return Object.extend(event, methods);
     3834    };
     3835
     3836  } else {
     3837    Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__;
     3838    Object.extend(Event.prototype, methods);
     3839    return Prototype.K;
     3840  }
     3841})();
     3842
     3843Object.extend(Event, (function() {
     3844  var cache = Event.cache;
     3845
     3846  function getEventID(element) {
     3847    if (element._prototypeEventID) return element._prototypeEventID[0];
     3848    arguments.callee.id = arguments.callee.id || 1;
     3849    return element._prototypeEventID = [++arguments.callee.id];
     3850  }
     3851
     3852  function getDOMEventName(eventName) {
     3853    if (eventName && eventName.include(':')) return "dataavailable";
     3854    return eventName;
     3855  }
     3856
     3857  function getCacheForID(id) {
     3858    return cache[id] = cache[id] || { };
     3859  }
     3860
     3861  function getWrappersForEventName(id, eventName) {
     3862    var c = getCacheForID(id);
     3863    return c[eventName] = c[eventName] || [];
     3864  }
     3865
     3866  function createWrapper(element, eventName, handler) {
     3867    var id = getEventID(element);
     3868    var c = getWrappersForEventName(id, eventName);
     3869    if (c.pluck("handler").include(handler)) return false;
     3870
     3871    var wrapper = function(event) {
     3872      if (!Event || !Event.extend ||
     3873        (event.eventName && event.eventName != eventName))
     3874          return false;
     3875
     3876      Event.extend(event);
     3877      handler.call(element, event);
     3878    };
     3879
     3880    wrapper.handler = handler;
     3881    c.push(wrapper);
     3882    return wrapper;
     3883  }
     3884
     3885  function findWrapper(id, eventName, handler) {
     3886    var c = getWrappersForEventName(id, eventName);
     3887    return c.find(function(wrapper) { return wrapper.handler == handler });
     3888  }
     3889
     3890  function destroyWrapper(id, eventName, handler) {
     3891    var c = getCacheForID(id);
     3892    if (!c[eventName]) return false;
     3893    c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
     3894  }
     3895
     3896  function destroyCache() {
     3897    for (var id in cache)
     3898      for (var eventName in cache[id])
     3899        cache[id][eventName] = null;
     3900  }
     3901
     3902  if (window.attachEvent) {
     3903    window.attachEvent("onunload", destroyCache);
     3904  }
     3905
     3906  return {
     3907    observe: function(element, eventName, handler) {
     3908      element = $(element);
     3909      var name = getDOMEventName(eventName);
     3910
     3911      var wrapper = createWrapper(element, eventName, handler);
     3912      if (!wrapper) return element;
     3913
     3914      if (element.addEventListener) {
     3915        element.addEventListener(name, wrapper, false);
     3916      } else {
     3917        element.attachEvent("on" + name, wrapper);
     3918      }
     3919
     3920      return element;
     3921    },
     3922
     3923    stopObserving: function(element, eventName, handler) {
     3924      element = $(element);
     3925      var id = getEventID(element), name = getDOMEventName(eventName);
     3926
     3927      if (!handler && eventName) {
     3928        getWrappersForEventName(id, eventName).each(function(wrapper) {
     3929          element.stopObserving(eventName, wrapper.handler);
     3930        });
     3931        return element;
     3932
     3933      } else if (!eventName) {
     3934        Object.keys(getCacheForID(id)).each(function(eventName) {
     3935          element.stopObserving(eventName);
     3936        });
     3937        return element;
     3938      }
     3939
     3940      var wrapper = findWrapper(id, eventName, handler);
     3941      if (!wrapper) return element;
     3942
     3943      if (element.removeEventListener) {
     3944        element.removeEventListener(name, wrapper, false);
     3945      } else {
     3946        element.detachEvent("on" + name, wrapper);
     3947      }
     3948
     3949      destroyWrapper(id, eventName, handler);
     3950
     3951      return element;
     3952    },
     3953
     3954    fire: function(element, eventName, memo) {
     3955      element = $(element);
     3956      if (element == document && document.createEvent && !element.dispatchEvent)
     3957        element = document.documentElement;
     3958
     3959      var event;
     3960      if (document.createEvent) {
     3961        event = document.createEvent("HTMLEvents");
     3962        event.initEvent("dataavailable", true, true);
     3963      } else {
     3964        event = document.createEventObject();
     3965        event.eventType = "ondataavailable";
     3966      }
     3967
     3968      event.eventName = eventName;
     3969      event.memo = memo || { };
     3970
     3971      if (document.createEvent) {
     3972        element.dispatchEvent(event);
     3973      } else {
     3974        element.fireEvent(event.eventType, event);
     3975      }
     3976
     3977      return Event.extend(event);
     3978    }
     3979  };
     3980})());
     3981
     3982Object.extend(Event, Event.Methods);
     3983
     3984Element.addMethods({
     3985  fire:          Event.fire,
     3986  observe:       Event.observe,
     3987  stopObserving: Event.stopObserving
     3988});
     3989
     3990Object.extend(document, {
     3991  fire:          Element.Methods.fire.methodize(),
     3992  observe:       Element.Methods.observe.methodize(),
     3993  stopObserving: Element.Methods.stopObserving.methodize(),
     3994  loaded:        false
     3995});
     3996
     3997(function() {
     3998  /* Support for the DOMContentLoaded event is based on work by Dan Webb,
     3999     Matthias Miller, Dean Edwards and John Resig. */
     4000
     4001  var timer;
     4002
     4003  function fireContentLoadedEvent() {
     4004    if (document.loaded) return;
     4005    if (timer) window.clearInterval(timer);
     4006    document.fire("dom:loaded");
     4007    document.loaded = true;
     4008  }
     4009
     4010  if (document.addEventListener) {
     4011    if (Prototype.Browser.WebKit) {
     4012      timer = window.setInterval(function() {
     4013        if (/loaded|complete/.test(document.readyState))
     4014          fireContentLoadedEvent();
     4015      }, 0);
     4016
     4017      Event.observe(window, "load", fireContentLoadedEvent);
     4018
    29834019    } else {
    2984       event.returnValue = false;
    2985       event.cancelBubble = true;
    2986     }
    2987   },
    2988 
    2989   // find the first node with the given tagName, starting from the
    2990   // node the event was triggered on; traverses the DOM upwards
    2991   findElement: function(event, tagName) {
    2992     var element = Event.element(event);
    2993     while (element.parentNode && (!element.tagName ||
    2994         (element.tagName.toUpperCase() != tagName.toUpperCase())))
    2995       element = element.parentNode;
    2996     return element;
    2997   },
    2998 
    2999   observers: false,
    3000 
    3001   _observeAndCache: function(element, name, observer, useCapture) {
    3002     if (!this.observers) this.observers = [];
    3003     if (element.addEventListener) {
    3004       this.observers.push([element, name, observer, useCapture]);
    3005       element.addEventListener(name, observer, useCapture);
    3006     } else if (element.attachEvent) {
    3007       this.observers.push([element, name, observer, useCapture]);
    3008       element.attachEvent('on' + name, observer);
    3009     }
    3010   },
    3011 
    3012   unloadCache: function() {
    3013     if (!Event.observers) return;
    3014     for (var i = 0, length = Event.observers.length; i < length; i++) {
    3015       Event.stopObserving.apply(this, Event.observers[i]);
    3016       Event.observers[i][0] = null;
    3017     }
    3018     Event.observers = false;
    3019   },
    3020 
    3021   observe: function(element, name, observer, useCapture) {
    3022     element = $(element);
    3023     useCapture = useCapture || false;
    3024 
    3025     if (name == 'keypress' &&
    3026       (Prototype.Browser.WebKit || element.attachEvent))
    3027       name = 'keydown';
    3028 
    3029     Event._observeAndCache(element, name, observer, useCapture);
    3030   },
    3031 
    3032   stopObserving: function(element, name, observer, useCapture) {
    3033     element = $(element);
    3034     useCapture = useCapture || false;
    3035 
    3036     if (name == 'keypress' &&
    3037         (Prototype.Browser.WebKit || element.attachEvent))
    3038       name = 'keydown';
    3039 
    3040     if (element.removeEventListener) {
    3041       element.removeEventListener(name, observer, useCapture);
    3042     } else if (element.detachEvent) {
    3043       try {
    3044         element.detachEvent('on' + name, observer);
    3045       } catch (e) {}
    3046     }
    3047   }
    3048 });
    3049 
    3050 /* prevent memory leaks in IE */
    3051 if (Prototype.Browser.IE)
    3052   Event.observe(window, 'unload', Event.unloadCache, false);
     4020      document.addEventListener("DOMContentLoaded",
     4021        fireContentLoadedEvent, false);
     4022    }
     4023
     4024  } else {
     4025    document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>");
     4026    $("__onDOMContentLoaded").onreadystatechange = function() {
     4027      if (this.readyState == "complete") {
     4028        this.onreadystatechange = null;
     4029        fireContentLoadedEvent();
     4030      }
     4031    };
     4032  }
     4033})();
     4034/*------------------------------- DEPRECATED -------------------------------*/
     4035
     4036Hash.toQueryString = Object.toQueryString;
     4037
     4038var Toggle = { display: Element.toggle };
     4039
     4040Element.Methods.childOf = Element.Methods.descendantOf;
     4041
     4042var Insertion = {
     4043  Before: function(element, content) {
     4044    return Element.insert(element, {before:content});
     4045  },
     4046
     4047  Top: function(element, content) {
     4048    return Element.insert(element, {top:content});
     4049  },
     4050
     4051  Bottom: function(element, content) {
     4052    return Element.insert(element, {bottom:content});
     4053  },
     4054
     4055  After: function(element, content) {
     4056    return Element.insert(element, {after:content});
     4057  }
     4058};
     4059
     4060var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
     4061
     4062// This should be moved to script.aculo.us; notice the deprecated methods
     4063// further below, that map to the newer Element methods.
    30534064var Position = {
    30544065  // set to true if needed, warning: firefox performance problems
     
    30704081  },
    30714082
    3072   realOffset: function(element) {
    3073     var valueT = 0, valueL = 0;
    3074     do {
    3075       valueT += element.scrollTop  || 0;
    3076       valueL += element.scrollLeft || 0;
    3077       element = element.parentNode;
    3078     } while (element);
    3079     return [valueL, valueT];
    3080   },
    3081 
    3082   cumulativeOffset: function(element) {
    3083     var valueT = 0, valueL = 0;
    3084     do {
    3085       valueT += element.offsetTop  || 0;
    3086       valueL += element.offsetLeft || 0;
    3087       element = element.offsetParent;
    3088     } while (element);
    3089     return [valueL, valueT];
    3090   },
    3091 
    3092   positionedOffset: function(element) {
    3093     var valueT = 0, valueL = 0;
    3094     do {
    3095       valueT += element.offsetTop  || 0;
    3096       valueL += element.offsetLeft || 0;
    3097       element = element.offsetParent;
    3098       if (element) {
    3099         if(element.tagName=='BODY') break;
    3100         var p = Element.getStyle(element, 'position');
    3101         if (p == 'relative' || p == 'absolute') break;
    3102       }
    3103     } while (element);
    3104     return [valueL, valueT];
    3105   },
    3106 
    3107   offsetParent: function(element) {
    3108     if (element.offsetParent) return element.offsetParent;
    3109     if (element == document.body) return element;
    3110 
    3111     while ((element = element.parentNode) && element != document.body)
    3112       if (Element.getStyle(element, 'position') != 'static')
    3113         return element;
    3114 
    3115     return document.body;
    3116   },
    3117 
    31184083  // caches x/y coordinate pair to use with overlap
    31194084  within: function(element, x, y) {
     
    31224087    this.xcomp = x;
    31234088    this.ycomp = y;
    3124     this.offset = this.cumulativeOffset(element);
     4089    this.offset = Element.cumulativeOffset(element);
    31254090
    31264091    return (y >= this.offset[1] &&
     
    31314096
    31324097  withinIncludingScrolloffsets: function(element, x, y) {
    3133     var offsetcache = this.realOffset(element);
     4098    var offsetcache = Element.cumulativeScrollOffset(element);
    31344099
    31354100    this.xcomp = x + offsetcache[0] - this.deltaX;
    31364101    this.ycomp = y + offsetcache[1] - this.deltaY;
    3137     this.offset = this.cumulativeOffset(element);
     4102    this.offset = Element.cumulativeOffset(element);
    31384103
    31394104    return (this.ycomp >= this.offset[1] &&
     
    31544119  },
    31554120
    3156   page: function(forElement) {
    3157     var valueT = 0, valueL = 0;
    3158 
    3159     var element = forElement;
    3160     do {
    3161       valueT += element.offsetTop  || 0;
    3162       valueL += element.offsetLeft || 0;
    3163 
    3164       // Safari fix
    3165       if (element.offsetParent == document.body)
    3166         if (Element.getStyle(element,'position')=='absolute') break;
    3167 
    3168     } while (element = element.offsetParent);
    3169 
    3170     element = forElement;
    3171     do {
    3172       if (!window.opera || element.tagName=='BODY') {
    3173         valueT -= element.scrollTop  || 0;
    3174         valueL -= element.scrollLeft || 0;
    3175       }
    3176     } while (element = element.parentNode);
    3177 
    3178     return [valueL, valueT];
    3179   },
    3180 
    3181   clone: function(source, target) {
    3182     var options = Object.extend({
    3183       setLeft:    true,
    3184       setTop:     true,
    3185       setWidth:   true,
    3186       setHeight:  true,
    3187       offsetTop:  0,
    3188       offsetLeft: 0
    3189     }, arguments[2] || {})
    3190 
    3191     // find page position of source
    3192     source = $(source);
    3193     var p = Position.page(source);
    3194 
    3195     // find coordinate system to use
    3196     target = $(target);
    3197     var delta = [0, 0];
    3198     var parent = null;
    3199     // delta [0,0] will do fine with position: fixed elements,
    3200     // position:absolute needs offsetParent deltas
    3201     if (Element.getStyle(target,'position') == 'absolute') {
    3202       parent = Position.offsetParent(target);
    3203       delta = Position.page(parent);
    3204     }
    3205 
    3206     // correct by body offsets (fixes Safari)
    3207     if (parent == document.body) {
    3208       delta[0] -= document.body.offsetLeft;
    3209       delta[1] -= document.body.offsetTop;
    3210     }
    3211 
    3212     // set position
    3213     if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
    3214     if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
    3215     if(options.setWidth)  target.style.width = source.offsetWidth + 'px';
    3216     if(options.setHeight) target.style.height = source.offsetHeight + 'px';
    3217   },
     4121  // Deprecation layer -- use newer Element methods now (1.5.2).
     4122
     4123  cumulativeOffset: Element.Methods.cumulativeOffset,
     4124
     4125  positionedOffset: Element.Methods.positionedOffset,
    32184126
    32194127  absolutize: function(element) {
    3220     element = $(element);
    3221     if (element.style.position == 'absolute') return;
    32224128    Position.prepare();
    3223 
    3224     var offsets = Position.positionedOffset(element);
    3225     var top     = offsets[1];
    3226     var left    = offsets[0];
    3227     var width   = element.clientWidth;
    3228     var height  = element.clientHeight;
    3229 
    3230     element._originalLeft   = left - parseFloat(element.style.left  || 0);
    3231     element._originalTop    = top  - parseFloat(element.style.top || 0);
    3232     element._originalWidth  = element.style.width;
    3233     element._originalHeight = element.style.height;
    3234 
    3235     element.style.position = 'absolute';
    3236     element.style.top    = top + 'px';
    3237     element.style.left   = left + 'px';
    3238     element.style.width  = width + 'px';
    3239     element.style.height = height + 'px';
     4129    return Element.absolutize(element);
    32404130  },
    32414131
    32424132  relativize: function(element) {
    3243     element = $(element);
    3244     if (element.style.position == 'relative') return;
    32454133    Position.prepare();
    3246 
    3247     element.style.position = 'relative';
    3248     var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
    3249     var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
    3250 
    3251     element.style.top    = top + 'px';
    3252     element.style.left   = left + 'px';
    3253     element.style.height = element._originalHeight;
    3254     element.style.width  = element._originalWidth;
    3255   }
    3256 }
    3257 
    3258 // Safari returns margins on body which is incorrect if the child is absolutely
    3259 // positioned.  For performance reasons, redefine Position.cumulativeOffset for
    3260 // KHTML/WebKit only.
    3261 if (Prototype.Browser.WebKit) {
    3262   Position.cumulativeOffset = function(element) {
    3263     var valueT = 0, valueL = 0;
    3264     do {
    3265       valueT += element.offsetTop  || 0;
    3266       valueL += element.offsetLeft || 0;
    3267       if (element.offsetParent == document.body)
    3268         if (Element.getStyle(element, 'position') == 'absolute') break;
    3269 
    3270       element = element.offsetParent;
    3271     } while (element);
    3272 
    3273     return [valueL, valueT];
    3274   }
    3275 }
     4134    return Element.relativize(element);
     4135  },
     4136
     4137  realOffset: Element.Methods.cumulativeScrollOffset,
     4138
     4139  offsetParent: Element.Methods.getOffsetParent,
     4140
     4141  page: Element.Methods.viewportOffset,
     4142
     4143  clone: function(source, target, options) {
     4144    options = options || { };
     4145    return Element.clonePosition(target, source, options);
     4146  }
     4147};
     4148
     4149/*--------------------------------------------------------------------------*/
     4150
     4151if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
     4152  function iter(name) {
     4153    return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
     4154  }
     4155
     4156  instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
     4157  function(element, className) {
     4158    className = className.toString().strip();
     4159    var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
     4160    return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
     4161  } : function(element, className) {
     4162    className = className.toString().strip();
     4163    var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
     4164    if (!classNames && !className) return elements;
     4165
     4166    var nodes = $(element).getElementsByTagName('*');
     4167    className = ' ' + className + ' ';
     4168
     4169    for (var i = 0, child, cn; child = nodes[i]; i++) {
     4170      if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
     4171          (classNames && classNames.all(function(name) {
     4172            return !name.toString().blank() && cn.include(' ' + name + ' ');
     4173          }))))
     4174        elements.push(Element.extend(child));
     4175    }
     4176    return elements;
     4177  };
     4178
     4179  return function(className, parentElement) {
     4180    return $(parentElement || document.body).getElementsByClassName(className);
     4181  };
     4182}(Element.Methods);
     4183
     4184/*--------------------------------------------------------------------------*/
     4185
     4186Element.ClassNames = Class.create();
     4187Element.ClassNames.prototype = {
     4188  initialize: function(element) {
     4189    this.element = $(element);
     4190  },
     4191
     4192  _each: function(iterator) {
     4193    this.element.className.split(/\s+/).select(function(name) {
     4194      return name.length > 0;
     4195    })._each(iterator);
     4196  },
     4197
     4198  set: function(className) {
     4199    this.element.className = className;
     4200  },
     4201
     4202  add: function(classNameToAdd) {
     4203    if (this.include(classNameToAdd)) return;
     4204    this.set($A(this).concat(classNameToAdd).join(' '));
     4205  },
     4206
     4207  remove: function(classNameToRemove) {
     4208    if (!this.include(classNameToRemove)) return;
     4209    this.set($A(this).without(classNameToRemove).join(' '));
     4210  },
     4211
     4212  toString: function() {
     4213    return $A(this).join(' ');
     4214  }
     4215};
     4216
     4217Object.extend(Element.ClassNames.prototype, Enumerable);
     4218
     4219/*--------------------------------------------------------------------------*/
    32764220
    32774221Element.addMethods();
  • trunk/packages/sipb-xen-www/code/static/style.css

    r435 r618  
    7474  font-weight: bold;
    7575}
     76
     77/* Striping applied (by JavaScript) to every other row in /list. */
     78tr.stripedrow {
     79  background-color: #DDF;
     80}
  • trunk/packages/sipb-xen-www/code/templates/list.tmpl

    r609 r618  
    119119#def machineRow($machine)
    120120      <tr>
    121         <td><a href="info?machine_id=$machine.machine_id">$machine.name</a></td>
    122         <td>${machine.memory}M</td>
    123         <td>$machine.owner</td>
    124         <td>$machine.administrator</td>
    125 #if $machine.nics
    126 #set $nic = $machine.nics[0]
    127         <td>$nic.ip</td>
    128 #else
    129         <td></td>
    130 #end if
    131 <td>#slurp
    132 #if $machine.uptime
    133 ${datetime.timedelta(seconds=int(machine.uptime))}#slurp
    134 #end if
    135 </td>
    136         <td>#slurp
    137 #if $has_vnc[$machine] == True
    138 <a href="vnc?machine_id=$machine.machine_id">Console</a>#slurp
    139 #else if $has_vnc[$machine] != 'Off'
    140 #filter None
    141 $has_vnc[$machine]
    142 #end filter
    143 #end if
    144 </td>
    145121        <td rowspan="2">
    146122          <form action="command" method="post">
     
    153129          </form>
    154130        </td>
     131        <td><a href="info?machine_id=$machine.machine_id">$machine.name</a></td>
     132        <td>${machine.memory}M</td>
     133        <td>$machine.owner</td>
     134        <td>$machine.administrator</td>
     135#if $machine.nics
     136#set $nic = $machine.nics[0]
     137        <td>$nic.ip</td>
     138#else
     139        <td></td>
     140#end if
     141<td>#slurp
     142#if $machine.uptime
     143${datetime.timedelta(seconds=int(machine.uptime))}#slurp
     144#end if
     145</td>
     146        <td>#slurp
     147#if $has_vnc[$machine] == True
     148<a href="vnc?machine_id=$machine.machine_id">Console</a>#slurp
     149#else if $has_vnc[$machine] != 'Off'
     150#filter None
     151$has_vnc[$machine]
     152#end filter
     153#end if
     154</td>
    155155      </tr>
    156156      <tr>
     
    160160
    161161#def machineList($machines)
    162     <table>
     162    <table cellspacing="0" cellpadding="2">
    163163      <tr>
     164        <th></th>
    164165        <th>Name</th>
    165166        <th>Memory</th>
     
    177178        <th>Uptime</th>
    178179        <th>VNC</th>
    179         <th></th>
    180180      </tr>
    181181      #for $machine in $machines:
     
    185185      #end for
    186186    </table>
     187    <script type="text/javascript" src="/static/stripe.js"></script>
     188    <script type="text/javascript">
     189        document.observe("dom:loaded", function() {
     190            stripe(\$('machinelist').getElementsByTagName('table')[0],
     191                   'stripedrow');
     192        });
     193    </script>
    187194#end def
    188195
  • trunk/packages/sipb-xen-www/code/templates/skeleton.tmpl

    r543 r618  
    5757<li><a href="vnc?machine_id=$machine.machine_id">Console</a></li>
    5858#end if
    59 <li><a href="help">Help</a></ul></li>
     59<li><a href="help">Help</a></li>
    6060</ul>
    6161#end if
Note: See TracChangeset for help on using the changeset viewer.