WordPress.org

Make WordPress Core

Changeset 12557


Ignore:
Timestamp:
12/27/2009 10:30:58 PM (10 years ago)
Author:
azaozz
Message:

Update Prototype.js to 1.6.1 and remove the second copy of it from wp-includes/js/scriptaculous, update Scriptaculous.js to 1.8.3, props Simek, fixes #11041

Location:
trunk/wp-includes
Files:
1 deleted
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/wp-includes/js/prototype.js

    r6512 r12557  
    1 /*  Prototype JavaScript framework, version 1.6.0
    2  *  (c) 2005-2007 Sam Stephenson
     1/*  Prototype JavaScript framework, version 1.6.1
     2 *  (c) 2005-2009 Sam Stephenson
    33 *
    44 *  Prototype is freely distributable under the terms of an MIT-style license.
     
    88
    99var Prototype = {
    10   Version: '1.6.0',
    11 
    12   Browser: {
    13     IE:     !!(window.attachEvent && !window.opera),
    14     Opera:  !!window.opera,
    15     WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
    16     Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
    17     MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
    18   },
     10  Version: '1.6.1',
     11
     12  Browser: (function(){
     13    var ua = navigator.userAgent;
     14    var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
     15    return {
     16      IE:             !!window.attachEvent && !isOpera,
     17      Opera:          isOpera,
     18      WebKit:         ua.indexOf('AppleWebKit/') > -1,
     19      Gecko:          ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
     20      MobileSafari:   /Apple.*Mobile.*Safari/.test(ua)
     21    }
     22  })(),
    1923
    2024  BrowserFeatures: {
    2125    XPath: !!document.evaluate,
    22     ElementExtensions: !!window.HTMLElement,
    23     SpecificElementExtensions:
    24       document.createElement('div').__proto__ &&
    25       document.createElement('div').__proto__ !==
    26         document.createElement('form').__proto__
     26    SelectorsAPI: !!document.querySelector,
     27    ElementExtensions: (function() {
     28      var constructor = window.Element || window.HTMLElement;
     29      return !!(constructor && constructor.prototype);
     30    })(),
     31    SpecificElementExtensions: (function() {
     32      if (typeof window.HTMLDivElement !== 'undefined')
     33        return true;
     34
     35      var div = document.createElement('div');
     36      var form = document.createElement('form');
     37      var isSupported = false;
     38
     39      if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) {
     40        isSupported = true;
     41      }
     42
     43      div = form = null;
     44
     45      return isSupported;
     46    })()
    2747  },
    2848
     
    3757  Prototype.BrowserFeatures.SpecificElementExtensions = false;
    3858
    39 if (Prototype.Browser.WebKit)
    40   Prototype.BrowserFeatures.XPath = false;
     59
     60var Abstract = { };
     61
     62
     63var Try = {
     64  these: function() {
     65    var returnValue;
     66
     67    for (var i = 0, length = arguments.length; i < length; i++) {
     68      var lambda = arguments[i];
     69      try {
     70        returnValue = lambda();
     71        break;
     72      } catch (e) { }
     73    }
     74
     75    return returnValue;
     76  }
     77};
    4178
    4279/* Based on Alex Arnell's inheritance implementation. */
    43 var Class = {
    44   create: function() {
     80
     81var Class = (function() {
     82  function subclass() {};
     83  function create() {
    4584    var parent = null, properties = $A(arguments);
    4685    if (Object.isFunction(properties[0]))
     
    5695
    5796    if (parent) {
    58       var subclass = function() { };
    5997      subclass.prototype = parent.prototype;
    6098      klass.prototype = new subclass;
     
    69107
    70108    klass.prototype.constructor = klass;
    71 
    72109    return klass;
    73110  }
    74 };
    75 
    76 Class.Methods = {
    77   addMethods: function(source) {
     111
     112  function addMethods(source) {
    78113    var ancestor   = this.superclass && this.superclass.prototype;
    79114    var properties = Object.keys(source);
    80115
    81     if (!Object.keys({ toString: true }).length)
    82       properties.push("toString", "valueOf");
     116    if (!Object.keys({ toString: true }).length) {
     117      if (source.toString != Object.prototype.toString)
     118        properties.push("toString");
     119      if (source.valueOf != Object.prototype.valueOf)
     120        properties.push("valueOf");
     121    }
    83122
    84123    for (var i = 0, length = properties.length; i < length; i++) {
     
    86125      if (ancestor && Object.isFunction(value) &&
    87126          value.argumentNames().first() == "$super") {
    88         var method = value, value = Object.extend((function(m) {
    89           return function() { return ancestor[m].apply(this, arguments) };
    90         })(property).wrap(method), {
    91           valueOf:  function() { return method },
    92           toString: function() { return method.toString() }
    93         });
     127        var method = value;
     128        value = (function(m) {
     129          return function() { return ancestor[m].apply(this, arguments); };
     130        })(property).wrap(method);
     131
     132        value.valueOf = method.valueOf.bind(method);
     133        value.toString = method.toString.bind(method);
    94134      }
    95135      this.prototype[property] = value;
     
    98138    return this;
    99139  }
    100 };
    101 
    102 var Abstract = { };
    103 
    104 Object.extend = function(destination, source) {
    105   for (var property in source)
    106     destination[property] = source[property];
    107   return destination;
    108 };
    109 
    110 Object.extend(Object, {
    111   inspect: function(object) {
     140
     141  return {
     142    create: create,
     143    Methods: {
     144      addMethods: addMethods
     145    }
     146  };
     147})();
     148(function() {
     149
     150  var _toString = Object.prototype.toString;
     151
     152  function extend(destination, source) {
     153    for (var property in source)
     154      destination[property] = source[property];
     155    return destination;
     156  }
     157
     158  function inspect(object) {
    112159    try {
    113       if (object === undefined) return 'undefined';
     160      if (isUndefined(object)) return 'undefined';
    114161      if (object === null) return 'null';
    115       return object.inspect ? object.inspect() : object.toString();
     162      return object.inspect ? object.inspect() : String(object);
    116163    } catch (e) {
    117164      if (e instanceof RangeError) return '...';
    118165      throw e;
    119166    }
    120   },
    121 
    122   toJSON: function(object) {
     167  }
     168
     169  function toJSON(object) {
    123170    var type = typeof object;
    124171    switch (type) {
     
    131178    if (object === null) return 'null';
    132179    if (object.toJSON) return object.toJSON();
    133     if (Object.isElement(object)) return;
     180    if (isElement(object)) return;
    134181
    135182    var results = [];
    136183    for (var property in object) {
    137       var value = Object.toJSON(object[property]);
    138       if (value !== undefined)
     184      var value = toJSON(object[property]);
     185      if (!isUndefined(value))
    139186        results.push(property.toJSON() + ': ' + value);
    140187    }
    141188
    142189    return '{' + results.join(', ') + '}';
    143   },
    144 
    145   toQueryString: function(object) {
     190  }
     191
     192  function toQueryString(object) {
    146193    return $H(object).toQueryString();
    147   },
    148 
    149   toHTML: function(object) {
     194  }
     195
     196  function toHTML(object) {
    150197    return object && object.toHTML ? object.toHTML() : String.interpret(object);
    151   },
    152 
    153   keys: function(object) {
    154     var keys = [];
     198  }
     199
     200  function keys(object) {
     201    var results = [];
    155202    for (var property in object)
    156       keys.push(property);
    157     return keys;
    158   },
    159 
    160   values: function(object) {
    161     var values = [];
     203      results.push(property);
     204    return results;
     205  }
     206
     207  function values(object) {
     208    var results = [];
    162209    for (var property in object)
    163       values.push(object[property]);
    164     return values;
    165   },
    166 
    167   clone: function(object) {
    168     return Object.extend({ }, object);
    169   },
    170 
    171   isElement: function(object) {
    172     return object && object.nodeType == 1;
    173   },
    174 
    175   isArray: function(object) {
    176     return object && object.constructor === Array;
    177   },
    178 
    179   isHash: function(object) {
     210      results.push(object[property]);
     211    return results;
     212  }
     213
     214  function clone(object) {
     215    return extend({ }, object);
     216  }
     217
     218  function isElement(object) {
     219    return !!(object && object.nodeType == 1);
     220  }
     221
     222  function isArray(object) {
     223    return _toString.call(object) == "[object Array]";
     224  }
     225
     226
     227  function isHash(object) {
    180228    return object instanceof Hash;
    181   },
    182 
    183   isFunction: function(object) {
    184     return typeof object == "function";
    185   },
    186 
    187   isString: function(object) {
    188     return typeof object == "string";
    189   },
    190 
    191   isNumber: function(object) {
    192     return typeof object == "number";
    193   },
    194 
    195   isUndefined: function(object) {
    196     return typeof object == "undefined";
    197   }
    198 });
    199 
    200 Object.extend(Function.prototype, {
    201   argumentNames: function() {
    202     var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip");
     229  }
     230
     231  function isFunction(object) {
     232    return typeof object === "function";
     233  }
     234
     235  function isString(object) {
     236    return _toString.call(object) == "[object String]";
     237  }
     238
     239  function isNumber(object) {
     240    return _toString.call(object) == "[object Number]";
     241  }
     242
     243  function isUndefined(object) {
     244    return typeof object === "undefined";
     245  }
     246
     247  extend(Object, {
     248    extend:        extend,
     249    inspect:       inspect,
     250    toJSON:        toJSON,
     251    toQueryString: toQueryString,
     252    toHTML:        toHTML,
     253    keys:          keys,
     254    values:        values,
     255    clone:         clone,
     256    isElement:     isElement,
     257    isArray:       isArray,
     258    isHash:        isHash,
     259    isFunction:    isFunction,
     260    isString:      isString,
     261    isNumber:      isNumber,
     262    isUndefined:   isUndefined
     263  });
     264})();
     265Object.extend(Function.prototype, (function() {
     266  var slice = Array.prototype.slice;
     267
     268  function update(array, args) {
     269    var arrayLength = array.length, length = args.length;
     270    while (length--) array[arrayLength + length] = args[length];
     271    return array;
     272  }
     273
     274  function merge(array, args) {
     275    array = slice.call(array, 0);
     276    return update(array, args);
     277  }
     278
     279  function argumentNames() {
     280    var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
     281      .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
     282      .replace(/\s+/g, '').split(',');
    203283    return names.length == 1 && !names[0] ? [] : names;
    204   },
    205 
    206   bind: function() {
    207     if (arguments.length < 2 && arguments[0] === undefined) return this;
    208     var __method = this, args = $A(arguments), object = args.shift();
     284  }
     285
     286  function bind(context) {
     287    if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
     288    var __method = this, args = slice.call(arguments, 1);
    209289    return function() {
    210       return __method.apply(object, args.concat($A(arguments)));
    211     }
    212   },
    213 
    214   bindAsEventListener: function() {
    215     var __method = this, args = $A(arguments), object = args.shift();
     290      var a = merge(args, arguments);
     291      return __method.apply(context, a);
     292    }
     293  }
     294
     295  function bindAsEventListener(context) {
     296    var __method = this, args = slice.call(arguments, 1);
    216297    return function(event) {
    217       return __method.apply(object, [event || window.event].concat(args));
    218     }
    219   },
    220 
    221   curry: function() {
     298      var a = update([event || window.event], args);
     299      return __method.apply(context, a);
     300    }
     301  }
     302
     303  function curry() {
    222304    if (!arguments.length) return this;
    223     var __method = this, args = $A(arguments);
     305    var __method = this, args = slice.call(arguments, 0);
    224306    return function() {
    225       return __method.apply(this, args.concat($A(arguments)));
    226     }
    227   },
    228 
    229   delay: function() {
    230     var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
     307      var a = merge(args, arguments);
     308      return __method.apply(this, a);
     309    }
     310  }
     311
     312  function delay(timeout) {
     313    var __method = this, args = slice.call(arguments, 1);
     314    timeout = timeout * 1000
    231315    return window.setTimeout(function() {
    232316      return __method.apply(__method, args);
    233317    }, timeout);
    234   },
    235 
    236   wrap: function(wrapper) {
     318  }
     319
     320  function defer() {
     321    var args = update([0.01], arguments);
     322    return this.delay.apply(this, args);
     323  }
     324
     325  function wrap(wrapper) {
    237326    var __method = this;
    238327    return function() {
    239       return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
    240     }
    241   },
    242 
    243   methodize: function() {
     328      var a = update([__method.bind(this)], arguments);
     329      return wrapper.apply(this, a);
     330    }
     331  }
     332
     333  function methodize() {
    244334    if (this._methodized) return this._methodized;
    245335    var __method = this;
    246336    return this._methodized = function() {
    247       return __method.apply(null, [this].concat($A(arguments)));
     337      var a = update([this], arguments);
     338      return __method.apply(null, a);
    248339    };
    249340  }
    250 });
    251 
    252 Function.prototype.defer = Function.prototype.delay.curry(0.01);
     341
     342  return {
     343    argumentNames:       argumentNames,
     344    bind:                bind,
     345    bindAsEventListener: bindAsEventListener,
     346    curry:               curry,
     347    delay:               delay,
     348    defer:               defer,
     349    wrap:                wrap,
     350    methodize:           methodize
     351  }
     352})());
     353
    253354
    254355Date.prototype.toJSON = function() {
     
    261362};
    262363
    263 var Try = {
    264   these: function() {
    265     var returnValue;
    266 
    267     for (var i = 0, length = arguments.length; i < length; i++) {
    268       var lambda = arguments[i];
    269       try {
    270         returnValue = lambda();
    271         break;
    272       } catch (e) { }
    273     }
    274 
    275     return returnValue;
    276   }
    277 };
    278364
    279365RegExp.prototype.match = RegExp.prototype.test;
     
    282368  return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
    283369};
    284 
    285 /*--------------------------------------------------------------------------*/
    286 
    287370var PeriodicalExecuter = Class.create({
    288371  initialize: function(callback, frequency) {
     
    313396        this.currentlyExecuting = true;
    314397        this.execute();
    315       } finally {
    316398        this.currentlyExecuting = false;
     399      } catch(e) {
     400        this.currentlyExecuting = false;
     401        throw e;
    317402      }
    318403    }
     
    333418});
    334419
    335 Object.extend(String.prototype, {
    336   gsub: function(pattern, replacement) {
     420Object.extend(String.prototype, (function() {
     421
     422  function prepareReplacement(replacement) {
     423    if (Object.isFunction(replacement)) return replacement;
     424    var template = new Template(replacement);
     425    return function(match) { return template.evaluate(match) };
     426  }
     427
     428  function gsub(pattern, replacement) {
    337429    var result = '', source = this, match;
    338     replacement = arguments.callee.prepareReplacement(replacement);
     430    replacement = prepareReplacement(replacement);
     431
     432    if (Object.isString(pattern))
     433      pattern = RegExp.escape(pattern);
     434
     435    if (!(pattern.length || pattern.source)) {
     436      replacement = replacement('');
     437      return replacement + source.split('').join(replacement) + replacement;
     438    }
    339439
    340440    while (source.length > 0) {
     
    348448    }
    349449    return result;
    350   },
    351 
    352   sub: function(pattern, replacement, count) {
    353     replacement = this.gsub.prepareReplacement(replacement);
    354     count = count === undefined ? 1 : count;
     450  }
     451
     452  function sub(pattern, replacement, count) {
     453    replacement = prepareReplacement(replacement);
     454    count = Object.isUndefined(count) ? 1 : count;
    355455
    356456    return this.gsub(pattern, function(match) {
     
    358458      return replacement(match);
    359459    });
    360   },
    361 
    362   scan: function(pattern, iterator) {
     460  }
     461
     462  function scan(pattern, iterator) {
    363463    this.gsub(pattern, iterator);
    364464    return String(this);
    365   },
    366 
    367   truncate: function(length, truncation) {
     465  }
     466
     467  function truncate(length, truncation) {
    368468    length = length || 30;
    369     truncation = truncation === undefined ? '...' : truncation;
     469    truncation = Object.isUndefined(truncation) ? '...' : truncation;
    370470    return this.length > length ?
    371471      this.slice(0, length - truncation.length) + truncation : String(this);
    372   },
    373 
    374   strip: function() {
     472  }
     473
     474  function strip() {
    375475    return this.replace(/^\s+/, '').replace(/\s+$/, '');
    376   },
    377 
    378   stripTags: function() {
    379     return this.replace(/<\/?[^>]+>/gi, '');
    380   },
    381 
    382   stripScripts: function() {
     476  }
     477
     478  function stripTags() {
     479    return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, '');
     480  }
     481
     482  function stripScripts() {
    383483    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
    384   },
    385 
    386   extractScripts: function() {
     484  }
     485
     486  function extractScripts() {
    387487    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
    388488    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
     
    390490      return (scriptTag.match(matchOne) || ['', ''])[1];
    391491    });
    392   },
    393 
    394   evalScripts: function() {
     492  }
     493
     494  function evalScripts() {
    395495    return this.extractScripts().map(function(script) { return eval(script) });
    396   },
    397 
    398   escapeHTML: function() {
    399     var self = arguments.callee;
    400     self.text.data = this;
    401     return self.div.innerHTML;
    402   },
    403 
    404   unescapeHTML: function() {
    405     var div = new Element('div');
    406     div.innerHTML = this.stripTags();
    407     return div.childNodes[0] ? (div.childNodes.length > 1 ?
    408       $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
    409       div.childNodes[0].nodeValue) : '';
    410   },
    411 
    412   toQueryParams: function(separator) {
     496  }
     497
     498  function escapeHTML() {
     499    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
     500  }
     501
     502  function unescapeHTML() {
     503    return this.stripTags().replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&amp;/g,'&');
     504  }
     505
     506
     507  function toQueryParams(separator) {
    413508    var match = this.strip().match(/([^?#]*)(#.*)?$/);
    414509    if (!match) return { };
     
    428523      return hash;
    429524    });
    430   },
    431 
    432   toArray: function() {
     525  }
     526
     527  function toArray() {
    433528    return this.split('');
    434   },
    435 
    436   succ: function() {
     529  }
     530
     531  function succ() {
    437532    return this.slice(0, this.length - 1) +
    438533      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
    439   },
    440 
    441   times: function(count) {
     534  }
     535
     536  function times(count) {
    442537    return count < 1 ? '' : new Array(count + 1).join(this);
    443   },
    444 
    445   camelize: function() {
     538  }
     539
     540  function camelize() {
    446541    var parts = this.split('-'), len = parts.length;
    447542    if (len == 1) return parts[0];
     
    455550
    456551    return camelized;
    457   },
    458 
    459   capitalize: function() {
     552  }
     553
     554  function capitalize() {
    460555    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
    461   },
    462 
    463   underscore: function() {
    464     return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
    465   },
    466 
    467   dasherize: function() {
    468     return this.gsub(/_/,'-');
    469   },
    470 
    471   inspect: function(useDoubleQuotes) {
    472     var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
    473       var character = String.specialChar[match[0]];
    474       return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
     556  }
     557
     558  function underscore() {
     559    return this.replace(/::/g, '/')
     560               .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
     561               .replace(/([a-z\d])([A-Z])/g, '$1_$2')
     562               .replace(/-/g, '_')
     563               .toLowerCase();
     564  }
     565
     566  function dasherize() {
     567    return this.replace(/_/g, '-');
     568  }
     569
     570  function inspect(useDoubleQuotes) {
     571    var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) {
     572      if (character in String.specialChar) {
     573        return String.specialChar[character];
     574      }
     575      return '\\u00' + character.charCodeAt().toPaddedString(2, 16);
    475576    });
    476577    if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
    477578    return "'" + escapedString.replace(/'/g, '\\\'') + "'";
    478   },
    479 
    480   toJSON: function() {
     579  }
     580
     581  function toJSON() {
    481582    return this.inspect(true);
    482   },
    483 
    484   unfilterJSON: function(filter) {
    485     return this.sub(filter || Prototype.JSONFilter, '#{1}');
    486   },
    487 
    488   isJSON: function() {
    489     var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
     583  }
     584
     585  function unfilterJSON(filter) {
     586    return this.replace(filter || Prototype.JSONFilter, '$1');
     587  }
     588
     589  function isJSON() {
     590    var str = this;
     591    if (str.blank()) return false;
     592    str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
    490593    return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
    491   },
    492 
    493   evalJSON: function(sanitize) {
     594  }
     595
     596  function evalJSON(sanitize) {
    494597    var json = this.unfilterJSON();
    495598    try {
     
    497600    } catch (e) { }
    498601    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
    499   },
    500 
    501   include: function(pattern) {
     602  }
     603
     604  function include(pattern) {
    502605    return this.indexOf(pattern) > -1;
    503   },
    504 
    505   startsWith: function(pattern) {
     606  }
     607
     608  function startsWith(pattern) {
    506609    return this.indexOf(pattern) === 0;
    507   },
    508 
    509   endsWith: function(pattern) {
     610  }
     611
     612  function endsWith(pattern) {
    510613    var d = this.length - pattern.length;
    511614    return d >= 0 && this.lastIndexOf(pattern) === d;
    512   },
    513 
    514   empty: function() {
     615  }
     616
     617  function empty() {
    515618    return this == '';
    516   },
    517 
    518   blank: function() {
     619  }
     620
     621  function blank() {
    519622    return /^\s*$/.test(this);
    520   },
    521 
    522   interpolate: function(object, pattern) {
     623  }
     624
     625  function interpolate(object, pattern) {
    523626    return new Template(this, pattern).evaluate(object);
    524627  }
    525 });
    526 
    527 if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
    528   escapeHTML: function() {
    529     return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
    530   },
    531   unescapeHTML: function() {
    532     return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
    533   }
    534 });
    535 
    536 String.prototype.gsub.prepareReplacement = function(replacement) {
    537   if (Object.isFunction(replacement)) return replacement;
    538   var template = new Template(replacement);
    539   return function(match) { return template.evaluate(match) };
    540 };
    541 
    542 String.prototype.parseQuery = String.prototype.toQueryParams;
    543 
    544 Object.extend(String.prototype.escapeHTML, {
    545   div:  document.createElement('div'),
    546   text: document.createTextNode('')
    547 });
    548 
    549 with (String.prototype.escapeHTML) div.appendChild(text);
     628
     629  return {
     630    gsub:           gsub,
     631    sub:            sub,
     632    scan:           scan,
     633    truncate:       truncate,
     634    strip:          String.prototype.trim ? String.prototype.trim : strip,
     635    stripTags:      stripTags,
     636    stripScripts:   stripScripts,
     637    extractScripts: extractScripts,
     638    evalScripts:    evalScripts,
     639    escapeHTML:     escapeHTML,
     640    unescapeHTML:   unescapeHTML,
     641    toQueryParams:  toQueryParams,
     642    parseQuery:     toQueryParams,
     643    toArray:        toArray,
     644    succ:           succ,
     645    times:          times,
     646    camelize:       camelize,
     647    capitalize:     capitalize,
     648    underscore:     underscore,
     649    dasherize:      dasherize,
     650    inspect:        inspect,
     651    toJSON:         toJSON,
     652    unfilterJSON:   unfilterJSON,
     653    isJSON:         isJSON,
     654    evalJSON:       evalJSON,
     655    include:        include,
     656    startsWith:     startsWith,
     657    endsWith:       endsWith,
     658    empty:          empty,
     659    blank:          blank,
     660    interpolate:    interpolate
     661  };
     662})());
    550663
    551664var Template = Class.create({
     
    556669
    557670  evaluate: function(object) {
    558     if (Object.isFunction(object.toTemplateReplacements))
     671    if (object && Object.isFunction(object.toTemplateReplacements))
    559672      object = object.toTemplateReplacements();
    560673
    561674    return this.template.gsub(this.pattern, function(match) {
    562       if (object == null) return '';
     675      if (object == null) return (match[1] + '');
    563676
    564677      var before = match[1] || '';
     
    566679
    567680      var ctx = object, expr = match[3];
    568       var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/, match = pattern.exec(expr);
     681      var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
     682      match = pattern.exec(expr);
    569683      if (match == null) return before;
    570684
    571685      while (match != null) {
    572         var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
     686        var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1];
    573687        ctx = ctx[comp];
    574688        if (null == ctx || '' == match[3]) break;
     
    578692
    579693      return before + String.interpret(ctx);
    580     }.bind(this));
     694    });
    581695  }
    582696});
     
    585699var $break = { };
    586700
    587 var Enumerable = {
    588   each: function(iterator, context) {
     701var Enumerable = (function() {
     702  function each(iterator, context) {
    589703    var index = 0;
    590     iterator = iterator.bind(context);
    591704    try {
    592705      this._each(function(value) {
    593         iterator(value, index++);
     706        iterator.call(context, value, index++);
    594707      });
    595708    } catch (e) {
     
    597710    }
    598711    return this;
    599   },
    600 
    601   eachSlice: function(number, iterator, context) {
    602     iterator = iterator ? iterator.bind(context) : Prototype.K;
     712  }
     713
     714  function eachSlice(number, iterator, context) {
    603715    var index = -number, slices = [], array = this.toArray();
     716    if (number < 1) return array;
    604717    while ((index += number) < array.length)
    605718      slices.push(array.slice(index, index+number));
    606719    return slices.collect(iterator, context);
    607   },
    608 
    609   all: function(iterator, context) {
    610     iterator = iterator ? iterator.bind(context) : Prototype.K;
     720  }
     721
     722  function all(iterator, context) {
     723    iterator = iterator || Prototype.K;
    611724    var result = true;
    612725    this.each(function(value, index) {
    613       result = result && !!iterator(value, index);
     726      result = result && !!iterator.call(context, value, index);
    614727      if (!result) throw $break;
    615728    });
    616729    return result;
    617   },
    618 
    619   any: function(iterator, context) {
    620     iterator = iterator ? iterator.bind(context) : Prototype.K;
     730  }
     731
     732  function any(iterator, context) {
     733    iterator = iterator || Prototype.K;
    621734    var result = false;
    622735    this.each(function(value, index) {
    623       if (result = !!iterator(value, index))
     736      if (result = !!iterator.call(context, value, index))
    624737        throw $break;
    625738    });
    626739    return result;
    627   },
    628 
    629   collect: function(iterator, context) {
    630     iterator = iterator ? iterator.bind(context) : Prototype.K;
     740  }
     741
     742  function collect(iterator, context) {
     743    iterator = iterator || Prototype.K;
    631744    var results = [];
    632745    this.each(function(value, index) {
    633       results.push(iterator(value, index));
     746      results.push(iterator.call(context, value, index));
    634747    });
    635748    return results;
    636   },
    637 
    638   detect: function(iterator, context) {
    639     iterator = iterator.bind(context);
     749  }
     750
     751  function detect(iterator, context) {
    640752    var result;
    641753    this.each(function(value, index) {
    642       if (iterator(value, index)) {
     754      if (iterator.call(context, value, index)) {
    643755        result = value;
    644756        throw $break;
     
    646758    });
    647759    return result;
    648   },
    649 
    650   findAll: function(iterator, context) {
    651     iterator = iterator.bind(context);
     760  }
     761
     762  function findAll(iterator, context) {
    652763    var results = [];
    653764    this.each(function(value, index) {
    654       if (iterator(value, index))
     765      if (iterator.call(context, value, index))
    655766        results.push(value);
    656767    });
    657768    return results;
    658   },
    659 
    660   grep: function(filter, iterator, context) {
    661     iterator = iterator ? iterator.bind(context) : Prototype.K;
     769  }
     770
     771  function grep(filter, iterator, context) {
     772    iterator = iterator || Prototype.K;
    662773    var results = [];
    663774
    664775    if (Object.isString(filter))
    665       filter = new RegExp(filter);
     776      filter = new RegExp(RegExp.escape(filter));
    666777
    667778    this.each(function(value, index) {
    668779      if (filter.match(value))
    669         results.push(iterator(value, index));
     780        results.push(iterator.call(context, value, index));
    670781    });
    671782    return results;
    672   },
    673 
    674   include: function(object) {
     783  }
     784
     785  function include(object) {
    675786    if (Object.isFunction(this.indexOf))
    676787      if (this.indexOf(object) != -1) return true;
     
    684795    });
    685796    return found;
    686   },
    687 
    688   inGroupsOf: function(number, fillWith) {
    689     fillWith = fillWith === undefined ? null : fillWith;
     797  }
     798
     799  function inGroupsOf(number, fillWith) {
     800    fillWith = Object.isUndefined(fillWith) ? null : fillWith;
    690801    return this.eachSlice(number, function(slice) {
    691802      while(slice.length < number) slice.push(fillWith);
    692803      return slice;
    693804    });
    694   },
    695 
    696   inject: function(memo, iterator, context) {
    697     iterator = iterator.bind(context);
     805  }
     806
     807  function inject(memo, iterator, context) {
    698808    this.each(function(value, index) {
    699       memo = iterator(memo, value, index);
     809      memo = iterator.call(context, memo, value, index);
    700810    });
    701811    return memo;
    702   },
    703 
    704   invoke: function(method) {
     812  }
     813
     814  function invoke(method) {
    705815    var args = $A(arguments).slice(1);
    706816    return this.map(function(value) {
    707817      return value[method].apply(value, args);
    708818    });
    709   },
    710 
    711   max: function(iterator, context) {
    712     iterator = iterator ? iterator.bind(context) : Prototype.K;
     819  }
     820
     821  function max(iterator, context) {
     822    iterator = iterator || Prototype.K;
    713823    var result;
    714824    this.each(function(value, index) {
    715       value = iterator(value, index);
    716       if (result == undefined || value >= result)
     825      value = iterator.call(context, value, index);
     826      if (result == null || value >= result)
    717827        result = value;
    718828    });
    719829    return result;
    720   },
    721 
    722   min: function(iterator, context) {
    723     iterator = iterator ? iterator.bind(context) : Prototype.K;
     830  }
     831
     832  function min(iterator, context) {
     833    iterator = iterator || Prototype.K;
    724834    var result;
    725835    this.each(function(value, index) {
    726       value = iterator(value, index);
    727       if (result == undefined || value < result)
     836      value = iterator.call(context, value, index);
     837      if (result == null || value < result)
    728838        result = value;
    729839    });
    730840    return result;
    731   },
    732 
    733   partition: function(iterator, context) {
    734     iterator = iterator ? iterator.bind(context) : Prototype.K;
     841  }
     842
     843  function partition(iterator, context) {
     844    iterator = iterator || Prototype.K;
    735845    var trues = [], falses = [];
    736846    this.each(function(value, index) {
    737       (iterator(value, index) ?
     847      (iterator.call(context, value, index) ?
    738848        trues : falses).push(value);
    739849    });
    740850    return [trues, falses];
    741   },
    742 
    743   pluck: function(property) {
     851  }
     852
     853  function pluck(property) {
    744854    var results = [];
    745855    this.each(function(value) {
     
    747857    });
    748858    return results;
    749   },
    750 
    751   reject: function(iterator, context) {
    752     iterator = iterator.bind(context);
     859  }
     860
     861  function reject(iterator, context) {
    753862    var results = [];
    754863    this.each(function(value, index) {
    755       if (!iterator(value, index))
     864      if (!iterator.call(context, value, index))
    756865        results.push(value);
    757866    });
    758867    return results;
    759   },
    760 
    761   sortBy: function(iterator, context) {
    762     iterator = iterator.bind(context);
     868  }
     869
     870  function sortBy(iterator, context) {
    763871    return this.map(function(value, index) {
    764       return {value: value, criteria: iterator(value, index)};
     872      return {
     873        value: value,
     874        criteria: iterator.call(context, value, index)
     875      };
    765876    }).sort(function(left, right) {
    766877      var a = left.criteria, b = right.criteria;
    767878      return a < b ? -1 : a > b ? 1 : 0;
    768879    }).pluck('value');
    769   },
    770 
    771   toArray: function() {
     880  }
     881
     882  function toArray() {
    772883    return this.map();
    773   },
    774 
    775   zip: function() {
     884  }
     885
     886  function zip() {
    776887    var iterator = Prototype.K, args = $A(arguments);
    777888    if (Object.isFunction(args.last()))
     
    782893      return iterator(collections.pluck(index));
    783894    });
    784   },
    785 
    786   size: function() {
     895  }
     896
     897  function size() {
    787898    return this.toArray().length;
    788   },
    789 
    790   inspect: function() {
     899  }
     900
     901  function inspect() {
    791902    return '#<Enumerable:' + this.toArray().inspect() + '>';
    792903  }
    793 };
    794 
    795 Object.extend(Enumerable, {
    796   map:     Enumerable.collect,
    797   find:    Enumerable.detect,
    798   select:  Enumerable.findAll,
    799   filter:  Enumerable.findAll,
    800   member:  Enumerable.include,
    801   entries: Enumerable.toArray,
    802   every:   Enumerable.all,
    803   some:    Enumerable.any
    804 });
     904
     905
     906
     907
     908
     909
     910
     911
     912
     913  return {
     914    each:       each,
     915    eachSlice:  eachSlice,
     916    all:        all,
     917    every:      all,
     918    any:        any,
     919    some:       any,
     920    collect:    collect,
     921    map:        collect,
     922    detect:     detect,
     923    findAll:    findAll,
     924    select:     findAll,
     925    filter:     findAll,
     926    grep:       grep,
     927    include:    include,
     928    member:     include,
     929    inGroupsOf: inGroupsOf,
     930    inject:     inject,
     931    invoke:     invoke,
     932    max:        max,
     933    min:        min,
     934    partition:  partition,
     935    pluck:      pluck,
     936    reject:     reject,
     937    sortBy:     sortBy,
     938    toArray:    toArray,
     939    entries:    toArray,
     940    zip:        zip,
     941    size:       size,
     942    inspect:    inspect,
     943    find:       detect
     944  };
     945})();
    805946function $A(iterable) {
    806947  if (!iterable) return [];
    807   if (iterable.toArray) return iterable.toArray();
    808   var length = iterable.length, results = new Array(length);
     948  if ('toArray' in Object(iterable)) return iterable.toArray();
     949  var length = iterable.length || 0, results = new Array(length);
    809950  while (length--) results[length] = iterable[length];
    810951  return results;
    811952}
    812953
    813 if (Prototype.Browser.WebKit) {
    814   function $A(iterable) {
    815     if (!iterable) return [];
    816     if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
    817         iterable.toArray) return iterable.toArray();
    818     var length = iterable.length, results = new Array(length);
    819     while (length--) results[length] = iterable[length];
    820     return results;
    821   }
     954function $w(string) {
     955  if (!Object.isString(string)) return [];
     956  string = string.strip();
     957  return string ? string.split(/\s+/) : [];
    822958}
    823959
    824960Array.from = $A;
    825961
    826 Object.extend(Array.prototype, Enumerable);
    827 
    828 if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;
    829 
    830 Object.extend(Array.prototype, {
    831   _each: function(iterator) {
     962
     963(function() {
     964  var arrayProto = Array.prototype,
     965      slice = arrayProto.slice,
     966      _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available
     967
     968  function each(iterator) {
    832969    for (var i = 0, length = this.length; i < length; i++)
    833970      iterator(this[i]);
    834   },
    835 
    836   clear: function() {
     971  }
     972  if (!_each) _each = each;
     973
     974  function clear() {
    837975    this.length = 0;
    838976    return this;
    839   },
    840 
    841   first: function() {
     977  }
     978
     979  function first() {
    842980    return this[0];
    843   },
    844 
    845   last: function() {
     981  }
     982
     983  function last() {
    846984    return this[this.length - 1];
    847   },
    848 
    849   compact: function() {
     985  }
     986
     987  function compact() {
    850988    return this.select(function(value) {
    851989      return value != null;
    852990    });
    853   },
    854 
    855   flatten: function() {
     991  }
     992
     993  function flatten() {
    856994    return this.inject([], function(array, value) {
    857       return array.concat(Object.isArray(value) ?
    858         value.flatten() : [value]);
     995      if (Object.isArray(value))
     996        return array.concat(value.flatten());
     997      array.push(value);
     998      return array;
    859999    });
    860   },
    861 
    862   without: function() {
    863     var values = $A(arguments);
     1000  }
     1001
     1002  function without() {
     1003    var values = slice.call(arguments, 0);
    8641004    return this.select(function(value) {
    8651005      return !values.include(value);
    8661006    });
    867   },
    868 
    869   reverse: function(inline) {
     1007  }
     1008
     1009  function reverse(inline) {
    8701010    return (inline !== false ? this : this.toArray())._reverse();
    871   },
    872 
    873   reduce: function() {
    874     return this.length > 1 ? this : this[0];
    875   },
    876 
    877   uniq: function(sorted) {
     1011  }
     1012
     1013  function uniq(sorted) {
    8781014    return this.inject([], function(array, value, index) {
    8791015      if (0 == index || (sorted ? array.last() != value : !array.include(value)))
     
    8811017      return array;
    8821018    });
    883   },
    884 
    885   intersect: function(array) {
     1019  }
     1020
     1021  function intersect(array) {
    8861022    return this.uniq().findAll(function(item) {
    8871023      return array.detect(function(value) { return item === value });
    8881024    });
    889   },
    890 
    891   clone: function() {
    892     return [].concat(this);
    893   },
    894 
    895   size: function() {
     1025  }
     1026
     1027
     1028  function clone() {
     1029    return slice.call(this, 0);
     1030  }
     1031
     1032  function size() {
    8961033    return this.length;
    897   },
    898 
    899   inspect: function() {
     1034  }
     1035
     1036  function inspect() {
    9001037    return '[' + this.map(Object.inspect).join(', ') + ']';
    901   },
    902 
    903   toJSON: function() {
     1038  }
     1039
     1040  function toJSON() {
    9041041    var results = [];
    9051042    this.each(function(object) {
    9061043      var value = Object.toJSON(object);
    907       if (value !== undefined) results.push(value);
     1044      if (!Object.isUndefined(value)) results.push(value);
    9081045    });
    9091046    return '[' + results.join(', ') + ']';
    9101047  }
    911 });
    912 
    913 // use native browser JS 1.6 implementation if available
    914 if (Object.isFunction(Array.prototype.forEach))
    915   Array.prototype._each = Array.prototype.forEach;
    916 
    917 if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {
    918   i || (i = 0);
    919   var length = this.length;
    920   if (i < 0) i = length + i;
    921   for (; i < length; i++)
    922     if (this[i] === item) return i;
    923   return -1;
    924 };
    925 
    926 if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {
    927   i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
    928   var n = this.slice(0, i).reverse().indexOf(item);
    929   return (n < 0) ? n : i - n - 1;
    930 };
    931 
    932 Array.prototype.toArray = Array.prototype.clone;
    933 
    934 function $w(string) {
    935   if (!Object.isString(string)) return [];
    936   string = string.strip();
    937   return string ? string.split(/\s+/) : [];
    938 }
    939 
    940 if (Prototype.Browser.Opera){
    941   Array.prototype.concat = function() {
    942     var array = [];
    943     for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
     1048
     1049  function indexOf(item, i) {
     1050    i || (i = 0);
     1051    var length = this.length;
     1052    if (i < 0) i = length + i;
     1053    for (; i < length; i++)
     1054      if (this[i] === item) return i;
     1055    return -1;
     1056  }
     1057
     1058  function lastIndexOf(item, i) {
     1059    i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
     1060    var n = this.slice(0, i).reverse().indexOf(item);
     1061    return (n < 0) ? n : i - n - 1;
     1062  }
     1063
     1064  function concat() {
     1065    var array = slice.call(this, 0), item;
    9441066    for (var i = 0, length = arguments.length; i < length; i++) {
    945       if (Object.isArray(arguments[i])) {
    946         for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
    947           array.push(arguments[i][j]);
     1067      item = arguments[i];
     1068      if (Object.isArray(item) && !('callee' in item)) {
     1069        for (var j = 0, arrayLength = item.length; j < arrayLength; j++)
     1070          array.push(item[j]);
    9481071      } else {
    949         array.push(arguments[i]);
     1072        array.push(item);
    9501073      }
    9511074    }
    9521075    return array;
    953   };
    954 }
    955 Object.extend(Number.prototype, {
    956   toColorPart: function() {
    957     return this.toPaddedString(2, 16);
    958   },
    959 
    960   succ: function() {
    961     return this + 1;
    962   },
    963 
    964   times: function(iterator) {
    965     $R(0, this, true).each(iterator);
    966     return this;
    967   },
    968 
    969   toPaddedString: function(length, radix) {
    970     var string = this.toString(radix || 10);
    971     return '0'.times(length - string.length) + string;
    972   },
    973 
    974   toJSON: function() {
    975     return isFinite(this) ? this.toString() : 'null';
    976   }
    977 });
    978 
    979 $w('abs round ceil floor').each(function(method){
    980   Number.prototype[method] = Math[method].methodize();
    981 });
     1076  }
     1077
     1078  Object.extend(arrayProto, Enumerable);
     1079
     1080  if (!arrayProto._reverse)
     1081    arrayProto._reverse = arrayProto.reverse;
     1082
     1083  Object.extend(arrayProto, {
     1084    _each:     _each,
     1085    clear:     clear,
     1086    first:     first,
     1087    last:      last,
     1088    compact:   compact,
     1089    flatten:   flatten,
     1090    without:   without,
     1091    reverse:   reverse,
     1092    uniq:      uniq,
     1093    intersect: intersect,
     1094    clone:     clone,
     1095    toArray:   clone,
     1096    size:      size,
     1097    inspect:   inspect,
     1098    toJSON:    toJSON
     1099  });
     1100
     1101  var CONCAT_ARGUMENTS_BUGGY = (function() {
     1102    return [].concat(arguments)[0][0] !== 1;
     1103  })(1,2)
     1104
     1105  if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat;
     1106
     1107  if (!arrayProto.indexOf) arrayProto.indexOf = indexOf;
     1108  if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf;
     1109})();
    9821110function $H(object) {
    9831111  return new Hash(object);
     
    9851113
    9861114var Hash = Class.create(Enumerable, (function() {
    987   if (function() {
    988     var i = 0, Test = function(value) { this.key = value };
    989     Test.prototype.key = 'foo';
    990     for (var property in new Test('bar')) i++;
    991     return i > 1;
    992   }()) {
    993     function each(iterator) {
    994       var cache = [];
    995       for (var key in this._object) {
    996         var value = this._object[key];
    997         if (cache.include(key)) continue;
    998         cache.push(key);
    999         var pair = [key, value];
    1000         pair.key = key;
    1001         pair.value = value;
    1002         iterator(pair);
    1003       }
    1004     }
    1005   } else {
    1006     function each(iterator) {
    1007       for (var key in this._object) {
    1008         var value = this._object[key], pair = [key, value];
    1009         pair.key = key;
    1010         pair.value = value;
    1011         iterator(pair);
    1012       }
    1013     }
     1115  function initialize(object) {
     1116    this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
     1117  }
     1118
     1119  function _each(iterator) {
     1120    for (var key in this._object) {
     1121      var value = this._object[key], pair = [key, value];
     1122      pair.key = key;
     1123      pair.value = value;
     1124      iterator(pair);
     1125    }
     1126  }
     1127
     1128  function set(key, value) {
     1129    return this._object[key] = value;
     1130  }
     1131
     1132  function get(key) {
     1133    if (this._object[key] !== Object.prototype[key])
     1134      return this._object[key];
     1135  }
     1136
     1137  function unset(key) {
     1138    var value = this._object[key];
     1139    delete this._object[key];
     1140    return value;
     1141  }
     1142
     1143  function toObject() {
     1144    return Object.clone(this._object);
     1145  }
     1146
     1147  function keys() {
     1148    return this.pluck('key');
     1149  }
     1150
     1151  function values() {
     1152    return this.pluck('value');
     1153  }
     1154
     1155  function index(value) {
     1156    var match = this.detect(function(pair) {
     1157      return pair.value === value;
     1158    });
     1159    return match && match.key;
     1160  }
     1161
     1162  function merge(object) {
     1163    return this.clone().update(object);
     1164  }
     1165
     1166  function update(object) {
     1167    return new Hash(object).inject(this, function(result, pair) {
     1168      result.set(pair.key, pair.value);
     1169      return result;
     1170    });
    10141171  }
    10151172
     
    10191176  }
    10201177
     1178  function toQueryString() {
     1179    return this.inject([], function(results, pair) {
     1180      var key = encodeURIComponent(pair.key), values = pair.value;
     1181
     1182      if (values && typeof values == 'object') {
     1183        if (Object.isArray(values))
     1184          return results.concat(values.map(toQueryPair.curry(key)));
     1185      } else results.push(toQueryPair(key, values));
     1186      return results;
     1187    }).join('&');
     1188  }
     1189
     1190  function inspect() {
     1191    return '#<Hash:{' + this.map(function(pair) {
     1192      return pair.map(Object.inspect).join(': ');
     1193    }).join(', ') + '}>';
     1194  }
     1195
     1196  function toJSON() {
     1197    return Object.toJSON(this.toObject());
     1198  }
     1199
     1200  function clone() {
     1201    return new Hash(this);
     1202  }
     1203
    10211204  return {
    1022     initialize: function(object) {
    1023       this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
    1024     },
    1025 
    1026     _each: each,
    1027 
    1028     set: function(key, value) {
    1029       return this._object[key] = value;
    1030     },
    1031 
    1032     get: function(key) {
    1033       return this._object[key];
    1034     },
    1035 
    1036     unset: function(key) {
    1037       var value = this._object[key];
    1038       delete this._object[key];
    1039       return value;
    1040     },
    1041 
    1042     toObject: function() {
    1043       return Object.clone(this._object);
    1044     },
    1045 
    1046     keys: function() {
    1047       return this.pluck('key');
    1048     },
    1049 
    1050     values: function() {
    1051       return this.pluck('value');
    1052     },
    1053 
    1054     index: function(value) {
    1055       var match = this.detect(function(pair) {
    1056         return pair.value === value;
    1057       });
    1058       return match && match.key;
    1059     },
    1060 
    1061     merge: function(object) {
    1062       return this.clone().update(object);
    1063     },
    1064 
    1065     update: function(object) {
    1066       return new Hash(object).inject(this, function(result, pair) {
    1067         result.set(pair.key, pair.value);
    1068         return result;
    1069       });
    1070     },
    1071 
    1072     toQueryString: function() {
    1073       return this.map(function(pair) {
    1074         var key = encodeURIComponent(pair.key), values = pair.value;
    1075 
    1076         if (values && typeof values == 'object') {
    1077           if (Object.isArray(values))
    1078             return values.map(toQueryPair.curry(key)).join('&');
    1079         }
    1080         return toQueryPair(key, values);
    1081       }).join('&');
    1082     },
    1083 
    1084     inspect: function() {
    1085       return '#<Hash:{' + this.map(function(pair) {
    1086         return pair.map(Object.inspect).join(': ');
    1087       }).join(', ') + '}>';
    1088     },
    1089 
    1090     toJSON: function() {
    1091       return Object.toJSON(this.toObject());
    1092     },
    1093 
    1094     clone: function() {
    1095       return new Hash(this);
    1096     }
    1097   }
     1205    initialize:             initialize,
     1206    _each:                  _each,
     1207    set:                    set,
     1208    get:                    get,
     1209    unset:                  unset,
     1210    toObject:               toObject,
     1211    toTemplateReplacements: toObject,
     1212    keys:                   keys,
     1213    values:                 values,
     1214    index:                  index,
     1215    merge:                  merge,
     1216    update:                 update,
     1217    toQueryString:          toQueryString,
     1218    inspect:                inspect,
     1219    toJSON:                 toJSON,
     1220    clone:                  clone
     1221  };
    10981222})());
    10991223
    1100 Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;
    11011224Hash.from = $H;
    1102 var ObjectRange = Class.create(Enumerable, {
    1103   initialize: function(start, end, exclusive) {
     1225Object.extend(Number.prototype, (function() {
     1226  function toColorPart() {
     1227    return this.toPaddedString(2, 16);
     1228  }
     1229
     1230  function succ() {
     1231    return this + 1;
     1232  }
     1233
     1234  function times(iterator, context) {
     1235    $R(0, this, true).each(iterator, context);
     1236    return this;
     1237  }
     1238
     1239  function toPaddedString(length, radix) {
     1240    var string = this.toString(radix || 10);
     1241    return '0'.times(length - string.length) + string;
     1242  }
     1243
     1244  function toJSON() {
     1245    return isFinite(this) ? this.toString() : 'null';
     1246  }
     1247
     1248  function abs() {
     1249    return Math.abs(this);
     1250  }
     1251
     1252  function round() {
     1253    return Math.round(this);
     1254  }
     1255
     1256  function ceil() {
     1257    return Math.ceil(this);
     1258  }
     1259
     1260  function floor() {
     1261    return Math.floor(this);
     1262  }
     1263
     1264  return {
     1265    toColorPart:    toColorPart,
     1266    succ:           succ,
     1267    times:          times,
     1268    toPaddedString: toPaddedString,
     1269    toJSON:         toJSON,
     1270    abs:            abs,
     1271    round:          round,
     1272    ceil:           ceil,
     1273    floor:          floor
     1274  };
     1275})());
     1276
     1277function $R(start, end, exclusive) {
     1278  return new ObjectRange(start, end, exclusive);
     1279}
     1280
     1281var ObjectRange = Class.create(Enumerable, (function() {
     1282  function initialize(start, end, exclusive) {
    11041283    this.start = start;
    11051284    this.end = end;
    11061285    this.exclusive = exclusive;
    1107   },
    1108 
    1109   _each: function(iterator) {
     1286  }
     1287
     1288  function _each(iterator) {
    11101289    var value = this.start;
    11111290    while (this.include(value)) {
     
    11131292      value = value.succ();
    11141293    }
    1115   },
    1116 
    1117   include: function(value) {
     1294  }
     1295
     1296  function include(value) {
    11181297    if (value < this.start)
    11191298      return false;
     
    11221301    return value <= this.end;
    11231302  }
    1124 });
    1125 
    1126 var $R = function(start, end, exclusive) {
    1127   return new ObjectRange(start, end, exclusive);
    1128 };
     1303
     1304  return {
     1305    initialize: initialize,
     1306    _each:      _each,
     1307    include:    include
     1308  };
     1309})());
     1310
     1311
    11291312
    11301313var Ajax = {
     
    11731356  onComplete: function() { Ajax.activeRequestCount-- }
    11741357});
    1175 
    11761358Ajax.Base = Class.create({
    11771359  initialize: function(options) {
     
    11881370
    11891371    this.options.method = this.options.method.toLowerCase();
     1372
    11901373    if (Object.isString(this.options.parameters))
    11911374      this.options.parameters = this.options.parameters.toQueryParams();
     1375    else if (Object.isHash(this.options.parameters))
     1376      this.options.parameters = this.options.parameters.toObject();
    11921377  }
    11931378});
    1194 
    11951379Ajax.Request = Class.create(Ajax.Base, {
    11961380  _complete: false,
     
    12081392
    12091393    if (!['get', 'post'].include(this.method)) {
    1210       // simulate other verbs over post
    12111394      params['_method'] = this.method;
    12121395      this.method = 'post';
     
    12161399
    12171400    if (params = Object.toQueryString(params)) {
    1218       // when GET, append parameters to URL
    12191401      if (this.method == 'get')
    12201402        this.url += (this.url.include('?') ? '&' : '?') + params;
     
    12751457    }
    12761458
    1277     // user-defined headers
    12781459    if (typeof this.options.requestHeaders == 'object') {
    12791460      var extras = this.options.requestHeaders;
     
    13161497      var contentType = response.getHeader('Content-type');
    13171498      if (this.options.evalJS == 'force'
    1318           || (this.options.evalJS && contentType
     1499          || (this.options.evalJS && this.isSameOrigin() && contentType
    13191500          && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
    13201501        this.evalResponse();
     
    13291510
    13301511    if (state == 'Complete') {
    1331       // avoid memory leak in MSIE: clean up
    13321512      this.transport.onreadystatechange = Prototype.emptyFunction;
    13331513    }
     1514  },
     1515
     1516  isSameOrigin: function() {
     1517    var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
     1518    return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
     1519      protocol: location.protocol,
     1520      domain: document.domain,
     1521      port: location.port ? ':' + location.port : ''
     1522    }));
    13341523  },
    13351524
    13361525  getHeader: function(name) {
    13371526    try {
    1338       return this.transport.getResponseHeader(name);
    1339     } catch (e) { return null }
     1527      return this.transport.getResponseHeader(name) || null;
     1528    } catch (e) { return null; }
    13401529  },
    13411530
     
    13571546  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
    13581547
     1548
     1549
     1550
     1551
     1552
     1553
     1554
    13591555Ajax.Response = Class.create({
    13601556  initialize: function(request){
     
    13721568    if(readyState == 4) {
    13731569      var xml = transport.responseXML;
    1374       this.responseXML  = xml === undefined ? null : xml;
     1570      this.responseXML  = Object.isUndefined(xml) ? null : xml;
    13751571      this.responseJSON = this._getResponseJSON();
    13761572    }
     
    13781574
    13791575  status:      0,
     1576
    13801577  statusText: '',
    13811578
     
    14091606    json = decodeURIComponent(escape(json));
    14101607    try {
    1411       return json.evalJSON(this.request.options.sanitizeJSON);
     1608      return json.evalJSON(this.request.options.sanitizeJSON ||
     1609        !this.request.isSameOrigin());
    14121610    } catch (e) {
    14131611      this.request.dispatchException(e);
     
    14181616    var options = this.request.options;
    14191617    if (!options.evalJSON || (options.evalJSON != 'force' &&
    1420       !(this.getHeader('Content-type') || '').include('application/json')))
    1421         return null;
     1618      !(this.getHeader('Content-type') || '').include('application/json')) ||
     1619        this.responseText.blank())
     1620          return null;
    14221621    try {
    1423       return this.transport.responseText.evalJSON(options.sanitizeJSON);
     1622      return this.responseText.evalJSON(options.sanitizeJSON ||
     1623        !this.request.isSameOrigin());
    14241624    } catch (e) {
    14251625      this.request.dispatchException(e);
     
    14351635    };
    14361636
    1437     options = options || { };
     1637    options = Object.clone(options);
    14381638    var onComplete = options.onComplete;
    1439     options.onComplete = (function(response, param) {
     1639    options.onComplete = (function(response, json) {
    14401640      this.updateContent(response.responseText);
    1441       if (Object.isFunction(onComplete)) onComplete(response, param);
     1641      if (Object.isFunction(onComplete)) onComplete(response, json);
    14421642    }).bind(this);
    14431643
     
    14611661      else receiver.update(responseText);
    14621662    }
    1463 
    1464     if (this.success()) {
    1465       if (this.onComplete) this.onComplete.bind(this).defer();
    1466     }
    14671663  }
    14681664});
     
    15081704  }
    15091705});
     1706
     1707
     1708
    15101709function $(element) {
    15111710  if (arguments.length > 1) {
     
    15351734
    15361735if (!Node.ELEMENT_NODE) {
    1537   // DOM level 2 ECMAScript Language Binding
    15381736  Object.extend(Node, {
    15391737    ELEMENT_NODE: 1,
     
    15521750}
    15531751
    1554 (function() {
    1555   var element = this.Element;
    1556   this.Element = function(tagName, attributes) {
     1752
     1753(function(global) {
     1754
     1755  var SETATTRIBUTE_IGNORES_NAME = (function(){
     1756    var elForm = document.createElement("form");
     1757    var elInput = document.createElement("input");
     1758    var root = document.documentElement;
     1759    elInput.setAttribute("name", "test");
     1760    elForm.appendChild(elInput);
     1761    root.appendChild(elForm);
     1762    var isBuggy = elForm.elements
     1763      ? (typeof elForm.elements.test == "undefined")
     1764      : null;
     1765    root.removeChild(elForm);
     1766    elForm = elInput = null;
     1767    return isBuggy;
     1768  })();
     1769
     1770  var element = global.Element;
     1771  global.Element = function(tagName, attributes) {
    15571772    attributes = attributes || { };
    15581773    tagName = tagName.toLowerCase();
    15591774    var cache = Element.cache;
    1560     if (Prototype.Browser.IE && attributes.name) {
     1775    if (SETATTRIBUTE_IGNORES_NAME && attributes.name) {
    15611776      tagName = '<' + tagName + ' name="' + attributes.name + '">';
    15621777      delete attributes.name;
     
    15661781    return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
    15671782  };
    1568   Object.extend(this.Element, element || { });
    1569 }).call(window);
     1783  Object.extend(global.Element, element || { });
     1784  if (element) global.Element.prototype = element.prototype;
     1785})(this);
    15701786
    15711787Element.cache = { };
     1788Element.idCounter = 1;
    15721789
    15731790Element.Methods = {
     
    15821799  },
    15831800
     1801
    15841802  hide: function(element) {
    1585     $(element).style.display = 'none';
     1803    element = $(element);
     1804    element.style.display = 'none';
    15861805    return element;
    15871806  },
    15881807
    15891808  show: function(element) {
    1590     $(element).style.display = '';
     1809    element = $(element);
     1810    element.style.display = '';
    15911811    return element;
    15921812  },
     
    15981818  },
    15991819
    1600   update: function(element, content) {
    1601     element = $(element);
    1602     if (content && content.toElement) content = content.toElement();
    1603     if (Object.isElement(content)) return element.update().insert(content);
    1604     content = Object.toHTML(content);
    1605     element.innerHTML = content.stripScripts();
    1606     content.evalScripts.bind(content).defer();
    1607     return element;
    1608   },
     1820  update: (function(){
     1821
     1822    var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){
     1823      var el = document.createElement("select"),
     1824          isBuggy = true;
     1825      el.innerHTML = "<option value=\"test\">test</option>";
     1826      if (el.options && el.options[0]) {
     1827        isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION";
     1828      }
     1829      el = null;
     1830      return isBuggy;
     1831    })();
     1832
     1833    var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){
     1834      try {
     1835        var el = document.createElement("table");
     1836        if (el && el.tBodies) {
     1837          el.innerHTML = "<tbody><tr><td>test</td></tr></tbody>";
     1838          var isBuggy = typeof el.tBodies[0] == "undefined";
     1839          el = null;
     1840          return isBuggy;
     1841        }
     1842      } catch (e) {
     1843        return true;
     1844      }
     1845    })();
     1846
     1847    var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () {
     1848      var s = document.createElement("script"),
     1849          isBuggy = false;
     1850      try {
     1851        s.appendChild(document.createTextNode(""));
     1852        isBuggy = !s.firstChild ||
     1853          s.firstChild && s.firstChild.nodeType !== 3;
     1854      } catch (e) {
     1855        isBuggy = true;
     1856      }
     1857      s = null;
     1858      return isBuggy;
     1859    })();
     1860
     1861    function update(element, content) {
     1862      element = $(element);
     1863
     1864      if (content && content.toElement)
     1865        content = content.toElement();
     1866
     1867      if (Object.isElement(content))
     1868        return element.update().insert(content);
     1869
     1870      content = Object.toHTML(content);
     1871
     1872      var tagName = element.tagName.toUpperCase();
     1873
     1874      if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) {
     1875        element.text = content;
     1876        return element;
     1877      }
     1878
     1879      if (SELECT_ELEMENT_INNERHTML_BUGGY || TABLE_ELEMENT_INNERHTML_BUGGY) {
     1880        if (tagName in Element._insertionTranslations.tags) {
     1881          while (element.firstChild) {
     1882            element.removeChild(element.firstChild);
     1883          }
     1884          Element._getContentFromAnonymousElement(tagName, content.stripScripts())
     1885            .each(function(node) {
     1886              element.appendChild(node)
     1887            });
     1888        }
     1889        else {
     1890          element.innerHTML = content.stripScripts();
     1891        }
     1892      }
     1893      else {
     1894        element.innerHTML = content.stripScripts();
     1895      }
     1896
     1897      content.evalScripts.bind(content).defer();
     1898      return element;
     1899    }
     1900
     1901    return update;
     1902  })(),
    16091903
    16101904  replace: function(element, content) {
     
    16291923          insertions = {bottom:insertions};
    16301924
    1631     var content, t, range;
    1632 
    1633     for (position in insertions) {
     1925    var content, insert, tagName, childNodes;
     1926
     1927    for (var position in insertions) {
    16341928      content  = insertions[position];
    16351929      position = position.toLowerCase();
    1636       t = Element._insertionTranslations[position];
     1930      insert = Element._insertionTranslations[position];
    16371931
    16381932      if (content && content.toElement) content = content.toElement();
    16391933      if (Object.isElement(content)) {
    1640         t.insert(element, content);
     1934        insert(element, content);
    16411935        continue;
    16421936      }
     
    16441938      content = Object.toHTML(content);
    16451939
    1646       range = element.ownerDocument.createRange();
    1647       t.initializeRange(element, range);
    1648       t.insert(element, range.createContextualFragment(content.stripScripts()));
     1940      tagName = ((position == 'before' || position == 'after')
     1941        ? element.parentNode : element).tagName.toUpperCase();
     1942
     1943      childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
     1944
     1945      if (position == 'top' || position == 'after') childNodes.reverse();
     1946      childNodes.each(insert.curry(element));
    16491947
    16501948      content.evalScripts.bind(content).defer();
     
    16871985
    16881986  ancestors: function(element) {
    1689     return $(element).recursivelyCollect('parentNode');
     1987    return Element.recursivelyCollect(element, 'parentNode');
    16901988  },
    16911989
    16921990  descendants: function(element) {
    1693     return $A($(element).getElementsByTagName('*')).each(Element.extend);
     1991    return Element.select(element, "*");
    16941992  },
    16951993
     
    17082006
    17092007  previousSiblings: function(element) {
    1710     return $(element).recursivelyCollect('previousSibling');
     2008    return Element.recursivelyCollect(element, 'previousSibling');
    17112009  },
    17122010
    17132011  nextSiblings: function(element) {
    1714     return $(element).recursivelyCollect('nextSibling');
     2012    return Element.recursivelyCollect(element, 'nextSibling');
    17152013  },
    17162014
    17172015  siblings: function(element) {
    17182016    element = $(element);
    1719     return element.previousSiblings().reverse().concat(element.nextSiblings());
     2017    return Element.previousSiblings(element).reverse()
     2018      .concat(Element.nextSiblings(element));
    17202019  },
    17212020
     
    17292028    element = $(element);
    17302029    if (arguments.length == 1) return $(element.parentNode);
    1731     var ancestors = element.ancestors();
    1732     return expression ? Selector.findElement(ancestors, expression, index) :
    1733       ancestors[index || 0];
     2030    var ancestors = Element.ancestors(element);
     2031    return Object.isNumber(expression) ? ancestors[expression] :
     2032      Selector.findElement(ancestors, expression, index);
    17342033  },
    17352034
    17362035  down: function(element, expression, index) {
    17372036    element = $(element);
    1738     if (arguments.length == 1) return element.firstDescendant();
    1739     var descendants = element.descendants();
    1740     return expression ? Selector.findElement(descendants, expression, index) :
    1741       descendants[index || 0];
     2037    if (arguments.length == 1) return Element.firstDescendant(element);
     2038    return Object.isNumber(expression) ? Element.descendants(element)[expression] :
     2039      Element.select(element, expression)[index || 0];
    17422040  },
    17432041
     
    17452043    element = $(element);
    17462044    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
    1747     var previousSiblings = element.previousSiblings();
    1748     return expression ? Selector.findElement(previousSiblings, expression, index) :
    1749       previousSiblings[index || 0];
     2045    var previousSiblings = Element.previousSiblings(element);
     2046    return Object.isNumber(expression) ? previousSiblings[expression] :
     2047      Selector.findElement(previousSiblings, expression, index);
    17502048  },
    17512049
     
    17532051    element = $(element);
    17542052    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
    1755     var nextSiblings = element.nextSiblings();
    1756     return expression ? Selector.findElement(nextSiblings, expression, index) :
    1757       nextSiblings[index || 0];
    1758   },
    1759 
    1760   select: function() {
    1761     var args = $A(arguments), element = $(args.shift());
     2053    var nextSiblings = Element.nextSiblings(element);
     2054    return Object.isNumber(expression) ? nextSiblings[expression] :
     2055      Selector.findElement(nextSiblings, expression, index);
     2056  },
     2057
     2058
     2059  select: function(element) {
     2060    var args = Array.prototype.slice.call(arguments, 1);
    17622061    return Selector.findChildElements(element, args);
    17632062  },
    17642063
    1765   adjacent: function() {
    1766     var args = $A(arguments), element = $(args.shift());
     2064  adjacent: function(element) {
     2065    var args = Array.prototype.slice.call(arguments, 1);
    17672066    return Selector.findChildElements(element.parentNode, args).without(element);
    17682067  },
     
    17702069  identify: function(element) {
    17712070    element = $(element);
    1772     var id = element.readAttribute('id'), self = arguments.callee;
     2071    var id = Element.readAttribute(element, 'id');
    17732072    if (id) return id;
    1774     do { id = 'anonymous_element_' + self.counter++ } while ($(id));
    1775     element.writeAttribute('id', id);
     2073    do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id));
     2074    Element.writeAttribute(element, 'id', id);
    17762075    return id;
    17772076  },
     
    17962095
    17972096    if (typeof name == 'object') attributes = name;
    1798     else attributes[name] = value === undefined ? true : value;
     2097    else attributes[name] = Object.isUndefined(value) ? true : value;
    17992098
    18002099    for (var attr in attributes) {
    1801       var name = t.names[attr] || attr, value = attributes[attr];
     2100      name = t.names[attr] || attr;
     2101      value = attributes[attr];
    18022102      if (t.values[attr]) name = t.values[attr](element, value);
    18032103      if (value === false || value === null)
     
    18112111
    18122112  getHeight: function(element) {
    1813     return $(element).getDimensions().height;
     2113    return Element.getDimensions(element).height;
    18142114  },
    18152115
    18162116  getWidth: function(element) {
    1817     return $(element).getDimensions().width;
     2117    return Element.getDimensions(element).width;
    18182118  },
    18192119
     
    18312131  addClassName: function(element, className) {
    18322132    if (!(element = $(element))) return;
    1833     if (!element.hasClassName(className))
     2133    if (!Element.hasClassName(element, className))
    18342134      element.className += (element.className ? ' ' : '') + className;
    18352135    return element;
     
    18452145  toggleClassName: function(element, className) {
    18462146    if (!(element = $(element))) return;
    1847     return element[element.hasClassName(className) ?
    1848       'removeClassName' : 'addClassName'](className);
    1849   },
    1850 
    1851   // removes whitespace-only text node children
     2147    return Element[Element.hasClassName(element, className) ?
     2148      'removeClassName' : 'addClassName'](element, className);
     2149  },
     2150
    18522151  cleanWhitespace: function(element) {
    18532152    element = $(element);
     
    18722171      return (element.compareDocumentPosition(ancestor) & 8) === 8;
    18732172
    1874     if (element.sourceIndex && !Prototype.Browser.Opera) {
    1875       var e = element.sourceIndex, a = ancestor.sourceIndex,
    1876        nextAncestor = ancestor.nextSibling;
    1877       if (!nextAncestor) {
    1878         do { ancestor = ancestor.parentNode; }
    1879         while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);
    1880       }
    1881       if (nextAncestor) return (e > a && e < nextAncestor.sourceIndex);
    1882     }
     2173    if (ancestor.contains)
     2174      return ancestor.contains(element) && ancestor !== element;
    18832175
    18842176    while (element = element.parentNode)
    18852177      if (element == ancestor) return true;
     2178
    18862179    return false;
    18872180  },
     
    18892182  scrollTo: function(element) {
    18902183    element = $(element);
    1891     var pos = element.cumulativeOffset();
     2184    var pos = Element.cumulativeOffset(element);
    18922185    window.scrollTo(pos[0], pos[1]);
    18932186    return element;
     
    18982191    style = style == 'float' ? 'cssFloat' : style.camelize();
    18992192    var value = element.style[style];
    1900     if (!value) {
     2193    if (!value || value == 'auto') {
    19012194      var css = document.defaultView.getComputedStyle(element, null);
    19022195      value = css ? css[style] : null;
     
    19222215      else
    19232216        elementStyle[(property == 'float' || property == 'cssFloat') ?
    1924           (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
     2217          (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
    19252218            property] = styles[property];
    19262219
     
    19372230  getDimensions: function(element) {
    19382231    element = $(element);
    1939     var display = $(element).getStyle('display');
     2232    var display = Element.getStyle(element, 'display');
    19402233    if (display != 'none' && display != null) // Safari bug
    19412234      return {width: element.offsetWidth, height: element.offsetHeight};
    19422235
    1943     // All *Width and *Height properties give 0 on elements with display none,
    1944     // so enable the element temporarily
    19452236    var els = element.style;
    19462237    var originalVisibility = els.visibility;
     
    19482239    var originalDisplay = els.display;
    19492240    els.visibility = 'hidden';
    1950     els.position = 'absolute';
     2241    if (originalPosition != 'fixed') // Switching fixed to absolute causes issues in Safari
     2242      els.position = 'absolute';
    19512243    els.display = 'block';
    19522244    var originalWidth = element.clientWidth;
     
    19642256      element._madePositioned = true;
    19652257      element.style.position = 'relative';
    1966       // Opera returns the offset relative to the positioning context, when an
    1967       // element is position relative but top and left have not been defined
    1968       if (window.opera) {
     2258      if (Prototype.Browser.Opera) {
    19692259        element.style.top = 0;
    19702260        element.style.left = 0;
     
    20212311      element = element.offsetParent;
    20222312      if (element) {
    2023         if (element.tagName == 'BODY') break;
     2313        if (element.tagName.toUpperCase() == 'BODY') break;
    20242314        var p = Element.getStyle(element, 'position');
    2025         if (p == 'relative' || p == 'absolute') break;
     2315        if (p !== 'static') break;
    20262316      }
    20272317    } while (element);
     
    20312321  absolutize: function(element) {
    20322322    element = $(element);
    2033     if (element.getStyle('position') == 'absolute') return;
    2034     // Position.prepare(); // To be done manually by Scripty when it needs it.
    2035 
    2036     var offsets = element.positionedOffset();
     2323    if (Element.getStyle(element, 'position') == 'absolute') return element;
     2324
     2325    var offsets = Element.positionedOffset(element);
    20372326    var top     = offsets[1];
    20382327    var left    = offsets[0];
     
    20552344  relativize: function(element) {
    20562345    element = $(element);
    2057     if (element.getStyle('position') == 'relative') return;
    2058     // Position.prepare(); // To be done manually by Scripty when it needs it.
     2346    if (Element.getStyle(element, 'position') == 'relative') return element;
    20592347
    20602348    element.style.position = 'relative';
     
    20982386      valueL += element.offsetLeft || 0;
    20992387
    2100       // Safari fix
    21012388      if (element.offsetParent == document.body &&
    21022389        Element.getStyle(element, 'position') == 'absolute') break;
     
    21062393    element = forElement;
    21072394    do {
    2108       if (!Prototype.Browser.Opera || element.tagName == 'BODY') {
     2395      if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) {
    21092396        valueT -= element.scrollTop  || 0;
    21102397        valueL -= element.scrollLeft || 0;
     
    21252412    }, arguments[2] || { });
    21262413
    2127     // find page position of source
    21282414    source = $(source);
    2129     var p = source.viewportOffset();
    2130 
    2131     // find coordinate system to use
     2415    var p = Element.viewportOffset(source);
     2416
    21322417    element = $(element);
    21332418    var delta = [0, 0];
    21342419    var parent = null;
    2135     // delta [0,0] will do fine with position: fixed elements,
    2136     // position:absolute needs offsetParent deltas
    21372420    if (Element.getStyle(element, 'position') == 'absolute') {
    2138       parent = element.getOffsetParent();
    2139       delta = parent.viewportOffset();
    2140     }
    2141 
    2142     // correct by body offsets (fixes Safari)
     2421      parent = Element.getOffsetParent(element);
     2422      delta = Element.viewportOffset(parent);
     2423    }
     2424
    21432425    if (parent == document.body) {
    21442426      delta[0] -= document.body.offsetLeft;
     
    21462428    }
    21472429
    2148     // set position
    21492430    if (options.setLeft)   element.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
    21502431    if (options.setTop)    element.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
     
    21552436};
    21562437
    2157 Element.Methods.identify.counter = 1;
    2158 
    21592438Object.extend(Element.Methods, {
    21602439  getElementsBySelector: Element.Methods.select,
     2440
    21612441  childElements: Element.Methods.immediateDescendants
    21622442});
     
    21722452};
    21732453
    2174 
    2175 if (!document.createRange || Prototype.Browser.Opera) {
    2176   Element.Methods.insert = function(element, insertions) {
    2177     element = $(element);
    2178 
    2179     if (Object.isString(insertions) || Object.isNumber(insertions) ||
    2180         Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
    2181           insertions = { bottom: insertions };
    2182 
    2183     var t = Element._insertionTranslations, content, position, pos, tagName;
    2184 
    2185     for (position in insertions) {
    2186       content  = insertions[position];
    2187       position = position.toLowerCase();
    2188       pos      = t[position];
    2189 
    2190       if (content && content.toElement) content = content.toElement();
    2191       if (Object.isElement(content)) {
    2192         pos.insert(element, content);
    2193         continue;
    2194       }
    2195 
    2196       content = Object.toHTML(content);
    2197       tagName = ((position == 'before' || position == 'after')
    2198         ? element.parentNode : element).tagName.toUpperCase();
    2199 
    2200       if (t.tags[tagName]) {
    2201         var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
    2202         if (position == 'top' || position == 'after') fragments.reverse();
    2203         fragments.each(pos.insert.curry(element));
    2204       }
    2205       else element.insertAdjacentHTML(pos.adjacency, content.stripScripts());
    2206 
    2207       content.evalScripts.bind(content).defer();
    2208     }
    2209 
    2210     return element;
    2211   };
     2454if (Prototype.Browser.Opera) {
     2455  Element.Methods.getStyle = Element.Methods.getStyle.wrap(
     2456    function(proceed, element, style) {
     2457      switch (style) {
     2458        case 'left': case 'top': case 'right': case 'bottom':
     2459          if (proceed(element, 'position') === 'static') return null;
     2460        case 'height': case 'width':
     2461          if (!Element.visible(element)) return null;
     2462
     2463          var dim = parseInt(proceed(element, style), 10);
     2464
     2465          if (dim !== element['offset' + style.capitalize()])
     2466            return dim + 'px';
     2467
     2468          var properties;
     2469          if (style === 'height') {
     2470            properties = ['border-top-width', 'padding-top',
     2471             'padding-bottom', 'border-bottom-width'];
     2472          }
     2473          else {
     2474            properties = ['border-left-width', 'padding-left',
     2475             'padding-right', 'border-right-width'];
     2476          }
     2477          return properties.inject(dim, function(memo, property) {
     2478            var val = proceed(element, property);
     2479            return val === null ? memo : memo - parseInt(val, 10);
     2480          }) + 'px';
     2481        default: return proceed(element, style);
     2482      }
     2483    }
     2484  );
     2485
     2486  Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
     2487    function(proceed, element, attribute) {
     2488      if (attribute === 'title') return element.title;
     2489      return proceed(element, attribute);
     2490    }
     2491  );
    22122492}
    22132493
    2214 if (Prototype.Browser.Opera) {
    2215   Element.Methods._getStyle = Element.Methods.getStyle;
    2216   Element.Methods.getStyle = function(element, style) {
    2217     switch(style) {
    2218       case 'left':
    2219       case 'top':
    2220       case 'right':
    2221       case 'bottom':
    2222         if (Element._getStyle(element, 'position') == 'static') return null;
    2223       default: return Element._getStyle(element, style);
    2224     }
    2225   };
    2226   Element.Methods._readAttribute = Element.Methods.readAttribute;
    2227   Element.Methods.readAttribute = function(element, attribute) {
    2228     if (attribute == 'title') return element.title;
    2229     return Element._readAttribute(element, attribute);
    2230   };
    2231 }
    2232 
    22332494else if (Prototype.Browser.IE) {
    2234   $w('positionedOffset getOffsetParent viewportOffset').each(function(method) {
     2495  Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
     2496    function(proceed, element) {
     2497      element = $(element);
     2498      try { element.offsetParent }
     2499      catch(e) { return $(document.body) }
     2500      var position = element.getStyle('position');
     2501      if (position !== 'static') return proceed(element);
     2502      element.setStyle({ position: 'relative' });
     2503      var value = proceed(element);
     2504      element.setStyle({ position: position });
     2505      return value;
     2506    }
     2507  );
     2508
     2509  $w('positionedOffset viewportOffset').each(function(method) {
    22352510    Element.Methods[method] = Element.Methods[method].wrap(
    22362511      function(proceed, element) {
    22372512        element = $(element);
     2513        try { element.offsetParent }
     2514        catch(e) { return Element._returnOffset(0,0) }
    22382515        var position = element.getStyle('position');
    2239         if (position != 'static') return proceed(element);
     2516        if (position !== 'static') return proceed(element);
     2517        var offsetParent = element.getOffsetParent();
     2518        if (offsetParent && offsetParent.getStyle('position') === 'fixed')
     2519          offsetParent.setStyle({ zoom: 1 });
    22402520        element.setStyle({ position: 'relative' });
    22412521        var value = proceed(element);
     
    22452525    );
    22462526  });
     2527
     2528  Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap(
     2529    function(proceed, element) {
     2530      try { element.offsetParent }
     2531      catch(e) { return Element._returnOffset(0,0) }
     2532      return proceed(element);
     2533    }
     2534  );
    22472535
    22482536  Element.Methods.getStyle = function(element, style) {
     
    22872575  };
    22882576
    2289   Element._attributeTranslations = {
    2290     read: {
    2291       names: {
    2292         'class': 'className',
    2293         'for':   'htmlFor'
    2294       },
    2295       values: {
    2296         _getAttr: function(element, attribute) {
    2297           return element.getAttribute(attribute, 2);
     2577  Element._attributeTranslations = (function(){
     2578
     2579    var classProp = 'className';
     2580    var forProp = 'for';
     2581
     2582    var el = document.createElement('div');
     2583
     2584    el.setAttribute(classProp, 'x');
     2585
     2586    if (el.className !== 'x') {
     2587      el.setAttribute('class', 'x');
     2588      if (el.className === 'x') {
     2589        classProp = 'class';
     2590      }
     2591    }
     2592    el = null;
     2593
     2594    el = document.createElement('label');
     2595    el.setAttribute(forProp, 'x');
     2596    if (el.htmlFor !== 'x') {
     2597      el.setAttribute('htmlFor', 'x');
     2598      if (el.htmlFor === 'x') {
     2599        forProp = 'htmlFor';
     2600      }
     2601    }
     2602    el = null;
     2603
     2604    return {
     2605      read: {
     2606        names: {
     2607          'class':      classProp,
     2608          'className':  classProp,
     2609          'for':        forProp,
     2610          'htmlFor':    forProp
    22982611        },
    2299         _getAttrNode: function(element, attribute) {
    2300           var node = element.getAttributeNode(attribute);
    2301           return node ? node.value : "";
    2302         },
    2303         _getEv: function(element, attribute) {
    2304           var attribute = element.getAttribute(attribute);
    2305           return attribute ? attribute.toString().slice(23, -2) : null;
    2306         },
    2307         _flag: function(element, attribute) {
    2308           return $(element).hasAttribute(attribute) ? attribute : null;
    2309         },
    2310         style: function(element) {
    2311           return element.style.cssText.toLowerCase();
    2312         },
    2313         title: function(element) {
    2314           return element.title;
     2612        values: {
     2613          _getAttr: function(element, attribute) {
     2614            return element.getAttribute(attribute);
     2615          },
     2616          _getAttr2: function(element, attribute) {
     2617            return element.getAttribute(attribute, 2);
     2618          },
     2619          _getAttrNode: function(element, attribute) {
     2620            var node = element.getAttributeNode(attribute);
     2621            return node ? node.value : "";
     2622          },
     2623          _getEv: (function(){
     2624
     2625            var el = document.createElement('div');
     2626            el.onclick = Prototype.emptyFunction;
     2627            var value = el.getAttribute('onclick');
     2628            var f;
     2629
     2630            if (String(value).indexOf('{') > -1) {
     2631              f = function(element, attribute) {
     2632                attribute = element.getAttribute(attribute);
     2633                if (!attribute) return null;
     2634                attribute = attribute.toString();
     2635                attribute = attribute.split('{')[1];
     2636                attribute = attribute.split('}')[0];
     2637                return attribute.strip();
     2638              };
     2639            }
     2640            else if (value === '') {
     2641              f = function(element, attribute) {
     2642                attribute = element.getAttribute(attribute);
     2643                if (!attribute) return null;
     2644                return attribute.strip();
     2645              };
     2646            }
     2647            el = null;
     2648            return f;
     2649          })(),
     2650          _flag: function(element, attribute) {
     2651            return $(element).hasAttribute(attribute) ? attribute : null;
     2652          },
     2653          style: function(element) {
     2654            return element.style.cssText.toLowerCase();
     2655          },
     2656          title: function(element) {
     2657            return element.title;
     2658          }
    23152659        }
    23162660      }
    23172661    }
    2318   };
     2662  })();
    23192663
    23202664  Element._attributeTranslations.write = {
    2321     names: Object.clone(Element._attributeTranslations.read.names),
     2665    names: Object.extend({
     2666      cellpadding: 'cellPadding',
     2667      cellspacing: 'cellSpacing'
     2668    }, Element._attributeTranslations.read.names),
    23222669    values: {
    23232670      checked: function(element, value) {
     
    23342681
    23352682  $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
    2336       'encType maxLength readOnly longDesc').each(function(attr) {
     2683      'encType maxLength readOnly longDesc frameBorder').each(function(attr) {
    23372684    Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
    23382685    Element._attributeTranslations.has[attr.toLowerCase()] = attr;
     
    23412688  (function(v) {
    23422689    Object.extend(v, {
    2343       href:        v._getAttr,
    2344       src:         v._getAttr,
     2690      href:        v._getAttr2,
     2691      src:         v._getAttr2,
    23452692      type:        v._getAttr,
    23462693      action:      v._getAttrNode,
     
    23692716    });
    23702717  })(Element._attributeTranslations.read.values);
     2718
     2719  if (Prototype.BrowserFeatures.ElementExtensions) {
     2720    (function() {
     2721      function _descendants(element) {
     2722        var nodes = element.getElementsByTagName('*'), results = [];
     2723        for (var i = 0, node; node = nodes[i]; i++)
     2724          if (node.tagName !== "!") // Filter out comment nodes.
     2725            results.push(node);
     2726        return results;
     2727      }
     2728
     2729      Element.Methods.down = function(element, expression, index) {
     2730        element = $(element);
     2731        if (arguments.length == 1) return element.firstDescendant();
     2732        return Object.isNumber(expression) ? _descendants(element)[expression] :
     2733          Element.select(element, expression)[index || 0];
     2734      }
     2735    })();
     2736  }
     2737
    23712738}
    23722739
     
    23872754
    23882755    if (value == 1)
    2389       if(element.tagName == 'IMG' && element.width) {
     2756      if(element.tagName.toUpperCase() == 'IMG' && element.width) {
    23902757        element.width++; element.width--;
    23912758      } else try {
     
    23982765  };
    23992766
    2400   // Safari returns margins on body which is incorrect if the child is absolutely
    2401   // positioned.  For performance reasons, redefine Position.cumulativeOffset for
    2402   // KHTML/WebKit only.
    24032767  Element.Methods.cumulativeOffset = function(element) {
    24042768    var valueT = 0, valueL = 0;
     
    24162780}
    24172781
    2418 if (Prototype.Browser.IE || Prototype.Browser.Opera) {
    2419   // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements
    2420   Element.Methods.update = function(element, content) {
    2421     element = $(element);
    2422 
    2423     if (content && content.toElement) content = content.toElement();
    2424     if (Object.isElement(content)) return element.update().insert(content);
    2425 
    2426     content = Object.toHTML(content);
    2427     var tagName = element.tagName.toUpperCase();
    2428 
    2429     if (tagName in Element._insertionTranslations.tags) {
    2430       $A(element.childNodes).each(function(node) { element.removeChild(node) });
    2431       Element._getContentFromAnonymousElement(tagName, content.stripScripts())
    2432         .each(function(node) { element.appendChild(node) });
    2433     }
    2434     else element.innerHTML = content.stripScripts();
    2435 
    2436     content.evalScripts.bind(content).defer();
    2437     return element;
    2438   };
    2439 }
    2440 
    2441 if (document.createElement('div').outerHTML) {
     2782if ('outerHTML' in document.documentElement) {
    24422783  Element.Methods.replace = function(element, content) {
    24432784    element = $(element);
     
    24772818Element._getContentFromAnonymousElement = function(tagName, html) {
    24782819  var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
    2479   div.innerHTML = t[0] + html + t[1];
    2480   t[2].times(function() { div = div.firstChild });
     2820  if (t) {
     2821    div.innerHTML = t[0] + html + t[1];
     2822    t[2].times(function() { div = div.firstChild });
     2823  } else div.innerHTML = html;
    24812824  return $A(div.childNodes);
    24822825};
    24832826
    24842827Element._insertionTranslations = {
    2485   before: {
    2486     adjacency: 'beforeBegin',
    2487     insert: function(element, node) {
    2488       element.parentNode.insertBefore(node, element);
    2489     },
    2490     initializeRange: function(element, range) {
    2491       range.setStartBefore(element);
    2492     }
    2493   },
    2494   top: {
    2495     adjacency: 'afterBegin',
    2496     insert: function(element, node) {
    2497       element.insertBefore(node, element.firstChild);
    2498     },
    2499     initializeRange: function(element, range) {
    2500       range.selectNodeContents(element);
    2501       range.collapse(true);
    2502     }
    2503   },
    2504   bottom: {
    2505     adjacency: 'beforeEnd',
    2506     insert: function(element, node) {
    2507       element.appendChild(node);
    2508     }
    2509   },
    2510   after: {
    2511     adjacency: 'afterEnd',
    2512     insert: function(element, node) {
    2513       element.parentNode.insertBefore(node, element.nextSibling);
    2514     },
    2515     initializeRange: function(element, range) {
    2516       range.setStartAfter(element);
    2517     }
     2828  before: function(element, node) {
     2829    element.parentNode.insertBefore(node, element);
     2830  },
     2831  top: function(element, node) {
     2832    element.insertBefore(node, element.firstChild);
     2833  },
     2834  bottom: function(element, node) {
     2835    element.appendChild(node);
     2836  },
     2837  after: function(element, node) {
     2838    element.parentNode.insertBefore(node, element.nextSibling);
    25182839  },
    25192840  tags: {
     
    25272848
    25282849(function() {
    2529   this.bottom.initializeRange = this.top.initializeRange;
    2530   Object.extend(this.tags, {
    2531     THEAD: this.tags.TBODY,
    2532     TFOOT: this.tags.TBODY,
    2533     TH:    this.tags.TD
     2850  var tags = Element._insertionTranslations.tags;
     2851  Object.extend(tags, {
     2852    THEAD: tags.TBODY,
     2853    TFOOT: tags.TBODY,
     2854    TH:    tags.TD
    25342855  });
    2535 }).call(Element._insertionTranslations);
     2856})();
    25362857
    25372858Element.Methods.Simulated = {
     
    25392860    attribute = Element._attributeTranslations.has[attribute] || attribute;
    25402861    var node = $(element).getAttributeNode(attribute);
    2541     return node && node.specified;
     2862    return !!(node && node.specified);
    25422863  }
    25432864};
     
    25472868Object.extend(Element, Element.Methods);
    25482869
    2549 if (!Prototype.BrowserFeatures.ElementExtensions &&
    2550     document.createElement('div').__proto__) {
    2551   window.HTMLElement = { };
    2552   window.HTMLElement.prototype = document.createElement('div').__proto__;
    2553   Prototype.BrowserFeatures.ElementExtensions = true;
    2554 }
     2870(function(div) {
     2871
     2872  if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) {
     2873    window.HTMLElement = { };
     2874    window.HTMLElement.prototype = div['__proto__'];
     2875    Prototype.BrowserFeatures.ElementExtensions = true;
     2876  }
     2877
     2878  div = null;
     2879
     2880})(document.createElement('div'))
    25552881
    25562882Element.extend = (function() {
    2557   if (Prototype.BrowserFeatures.SpecificElementExtensions)
    2558     return Prototype.K;
    2559 
    2560   var Methods = { }, ByTag = Element.Methods.ByTag;
    2561 
    2562   var extend = Object.extend(function(element) {
    2563     if (!element || element._extendedByPrototype ||
    2564         element.nodeType != 1 || element == window) return element;
    2565 
    2566     var methods = Object.clone(Methods),
    2567       tagName = element.tagName, property, value;
    2568 
    2569     // extend methods for specific tags
    2570     if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
    2571 
    2572     for (property in methods) {
    2573       value = methods[property];
     2883
     2884  function checkDeficiency(tagName) {
     2885    if (typeof window.Element != 'undefined') {
     2886      var proto = window.Element.prototype;
     2887      if (proto) {
     2888        var id = '_' + (Math.random()+'').slice(2);
     2889        var el = document.createElement(tagName);
     2890        proto[id] = 'x';
     2891        var isBuggy = (el[id] !== 'x');
     2892        delete proto[id];
     2893        el = null;
     2894        return isBuggy;
     2895      }
     2896    }
     2897    return false;
     2898  }
     2899
     2900  function extendElementWith(element, methods) {
     2901    for (var property in methods) {
     2902      var value = methods[property];
    25742903      if (Object.isFunction(value) && !(property in element))
    25752904        element[property] = value.methodize();
    25762905    }
     2906  }
     2907
     2908  var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object');
     2909
     2910  if (Prototype.BrowserFeatures.SpecificElementExtensions) {
     2911    if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) {
     2912      return function(element) {
     2913        if (element && typeof element._extendedByPrototype == 'undefined') {
     2914          var t = element.tagName;
     2915          if (t && (/^(?:object|applet|embed)$/i.test(t))) {
     2916            extendElementWith(element, Element.Methods);
     2917            extendElementWith(element, Element.Methods.Simulated);
     2918            extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]);
     2919          }
     2920        }
     2921        return element;
     2922      }
     2923    }
     2924    return Prototype.K;
     2925  }
     2926
     2927  var Methods = { }, ByTag = Element.Methods.ByTag;
     2928
     2929  var extend = Object.extend(function(element) {
     2930    if (!element || typeof element._extendedByPrototype != 'undefined' ||
     2931        element.nodeType != 1 || element == window) return element;
     2932
     2933    var methods = Object.clone(Methods),
     2934        tagName = element.tagName.toUpperCase();
     2935
     2936    if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
     2937
     2938    extendElementWith(element, methods);
    25772939
    25782940    element._extendedByPrototype = Prototype.emptyFunction;
     
    25812943  }, {
    25822944    refresh: function() {
    2583       // extend methods for all tags (Safari doesn't need this)
    25842945      if (!Prototype.BrowserFeatures.ElementExtensions) {
    25852946        Object.extend(Methods, Element.Methods);
     
    26603021    if (window[klass]) return window[klass];
    26613022
    2662     window[klass] = { };
    2663     window[klass].prototype = document.createElement(tagName).__proto__;
    2664     return window[klass];
    2665   }
     3023    var element = document.createElement(tagName);
     3024    var proto = element['__proto__'] || element.constructor.prototype;
     3025    element = null;
     3026    return proto;
     3027  }
     3028
     3029  var elementPrototype = window.HTMLElement ? HTMLElement.prototype :
     3030   Element.prototype;
    26663031
    26673032  if (F.ElementExtensions) {
    2668     copy(Element.Methods, HTMLElement.prototype);
    2669     copy(Element.Methods.Simulated, HTMLElement.prototype, true);
     3033    copy(Element.Methods, elementPrototype);
     3034    copy(Element.Methods.Simulated, elementPrototype, true);
    26703035  }
    26713036
     
    26853050};
    26863051
     3052
    26873053document.viewport = {
     3054
    26883055  getDimensions: function() {
    2689     var dimensions = { };
    2690     $w('width height').each(function(d) {
    2691       var D = d.capitalize();
    2692       dimensions[d] = self['inner' + D] ||
    2693        (document.documentElement['client' + D] || document.body['client' + D]);
    2694     });
    2695     return dimensions;
    2696   },
    2697 
    2698   getWidth: function() {
    2699     return this.getDimensions().width;
    2700   },
    2701 
    2702   getHeight: function() {
    2703     return this.getDimensions().height;
     3056    return { width: this.getWidth(), height: this.getHeight() };
    27043057  },
    27053058
     
    27073060    return Element._returnOffset(
    27083061      window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
    2709       window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
     3062      window.pageYOffset || document.documentElement.scrollTop  || document.body.scrollTop);
    27103063  }
    27113064};
    2712 /* Portions of the Selector class are derived from Jack Slocum’s DomQuery,
     3065
     3066(function(viewport) {
     3067  var B = Prototype.Browser, doc = document, element, property = {};
     3068
     3069  function getRootElement() {
     3070    if (B.WebKit && !doc.evaluate)
     3071      return document;
     3072
     3073    if (B.Opera && window.parseFloat(window.opera.version()) < 9.5)
     3074      return document.body;
     3075
     3076    return document.documentElement;
     3077  }
     3078
     3079  function define(D) {
     3080    if (!element) element = getRootElement();
     3081
     3082    property[D] = 'client' + D;
     3083
     3084    viewport['get' + D] = function() { return element[property[D]] };
     3085    return viewport['get' + D]();
     3086  }
     3087
     3088  viewport.getWidth  = define.curry('Width');
     3089
     3090  viewport.getHeight = define.curry('Height');
     3091})(document.viewport);
     3092
     3093
     3094Element.Storage = {
     3095  UID: 1
     3096};
     3097
     3098Element.addMethods({
     3099  getStorage: function(element) {
     3100    if (!(element = $(element))) return;
     3101
     3102    var uid;
     3103    if (element === window) {
     3104      uid = 0;
     3105    } else {
     3106      if (typeof element._prototypeUID === "undefined")
     3107        element._prototypeUID = [Element.Storage.UID++];
     3108      uid = element._prototypeUID[0];
     3109    }
     3110
     3111    if (!Element.Storage[uid])
     3112      Element.Storage[uid] = $H();
     3113
     3114    return Element.Storage[uid];
     3115  },
     3116
     3117  store: function(element, key, value) {
     3118    if (!(element = $(element))) return;
     3119
     3120    if (arguments.length === 2) {
     3121      Element.getStorage(element).update(key);
     3122    } else {
     3123      Element.getStorage(element).set(key, value);
     3124    }
     3125
     3126    return element;
     3127  },
     3128
     3129  retrieve: function(element, key, defaultValue) {
     3130    if (!(element = $(element))) return;
     3131    var hash = Element.getStorage(element), value = hash.get(key);
     3132
     3133    if (Object.isUndefined(value)) {
     3134      hash.set(key, defaultValue);
     3135      value = defaultValue;
     3136    }
     3137
     3138    return value;
     3139  },
     3140
     3141  clone: function(element, deep) {
     3142    if (!(element = $(element))) return;
     3143    var clone = element.cloneNode(deep);
     3144    clone._prototypeUID = void 0;
     3145    if (deep) {
     3146      var descendants = Element.select(clone, '*'),
     3147          i = descendants.length;
     3148      while (i--) {
     3149        descendants[i]._prototypeUID = void 0;
     3150      }
     3151    }
     3152    return Element.extend(clone);
     3153  }
     3154});
     3155/* Portions of the Selector class are derived from Jack Slocum's DomQuery,
    27133156 * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
    27143157 * license.  Please see http://www.yui-ext.com/ for more information. */
     
    27173160  initialize: function(expression) {
    27183161    this.expression = expression.strip();
    2719     this.compileMatcher();
     3162
     3163    if (this.shouldUseSelectorsAPI()) {
     3164      this.mode = 'selectorsAPI';
     3165    } else if (this.shouldUseXPath()) {
     3166      this.mode = 'xpath';
     3167      this.compileXPathMatcher();
     3168    } else {
     3169      this.mode = "normal";
     3170      this.compileMatcher();
     3171    }
     3172
     3173  },
     3174
     3175  shouldUseXPath: (function() {
     3176
     3177    var IS_DESCENDANT_SELECTOR_BUGGY = (function(){
     3178      var isBuggy = false;
     3179      if (document.evaluate && window.XPathResult) {
     3180        var el = document.createElement('div');
     3181        el.innerHTML = '<ul><li></li></ul><div><ul><li></li></ul></div>';
     3182
     3183        var xpath = ".//*[local-name()='ul' or local-name()='UL']" +
     3184          "//*[local-name()='li' or local-name()='LI']";
     3185
     3186        var result = document.evaluate(xpath, el, null,
     3187          XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
     3188
     3189        isBuggy = (result.snapshotLength !== 2);
     3190        el = null;
     3191      }
     3192      return isBuggy;
     3193    })();
     3194
     3195    return function() {
     3196      if (!Prototype.BrowserFeatures.XPath) return false;
     3197
     3198      var e = this.expression;
     3199
     3200      if (Prototype.Browser.WebKit &&
     3201       (e.include("-of-type") || e.include(":empty")))
     3202        return false;
     3203
     3204      if ((/(\[[\w-]*?:|:checked)/).test(e))
     3205        return false;
     3206
     3207      if (IS_DESCENDANT_SELECTOR_BUGGY) return false;
     3208
     3209      return true;
     3210    }
     3211
     3212  })(),
     3213
     3214  shouldUseSelectorsAPI: function() {
     3215    if (!Prototype.BrowserFeatures.SelectorsAPI) return false;
     3216
     3217    if (Selector.CASE_INSENSITIVE_CLASS_NAMES) return false;
     3218
     3219    if (!Selector._div) Selector._div = new Element('div');
     3220
     3221    try {
     3222      Selector._div.querySelector(this.expression);
     3223    } catch(e) {
     3224      return false;
     3225    }
     3226
     3227    return true;
    27203228  },
    27213229
    27223230  compileMatcher: function() {
    2723     // Selectors with namespaced attributes can't use the XPath version
    2724     if (Prototype.BrowserFeatures.XPath && !(/(\[[\w-]*?:|:checked)/).test(this.expression))
    2725       return this.compileXPathMatcher();
    2726 
    27273231    var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
    2728         c = Selector.criteria, le, p, m;
     3232        c = Selector.criteria, le, p, m, len = ps.length, name;
    27293233
    27303234    if (Selector._cache[e]) {
     
    27383242    while (e && le != e && (/\S/).test(e)) {
    27393243      le = e;
    2740       for (var i in ps) {
    2741         p = ps[i];
     3244      for (var i = 0; i<len; i++) {
     3245        p = ps[i].re;
     3246        name = ps[i].name;
    27423247        if (m = e.match(p)) {
    2743           this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
    2744               new Template(c[i]).evaluate(m));
     3248          this.matcher.push(Object.isFunction(c[name]) ? c[name](m) :
     3249            new Template(c[name]).evaluate(m));
    27453250          e = e.replace(m[0], '');
    27463251          break;
     
    27563261  compileXPathMatcher: function() {
    27573262    var e = this.expression, ps = Selector.patterns,
    2758         x = Selector.xpath, le, m;
     3263        x = Selector.xpath, le, m, len = ps.length, name;
    27593264
    27603265    if (Selector._cache[e]) {
     
    27653270    while (e && le != e && (/\S/).test(e)) {
    27663271      le = e;
    2767       for (var i in ps) {
    2768         if (m = e.match(ps[i])) {
    2769           this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :
    2770             new Template(x[i]).evaluate(m));
     3272      for (var i = 0; i<len; i++) {
     3273        name = ps[i].name;
     3274        if (m = e.match(ps[i].re)) {
     3275          this.matcher.push(Object.isFunction(x[name]) ? x[name](m) :
     3276            new Template(x[name]).evaluate(m));
    27713277          e = e.replace(m[0], '');
    27723278          break;
     
    27813287  findElements: function(root) {
    27823288    root = root || document;
    2783     if (this.xpath) return document._getElementsByXPath(this.xpath, root);
    2784     return this.matcher(root);
     3289    var e = this.expression, results;
     3290
     3291    switch (this.mode) {
     3292      case 'selectorsAPI':
     3293        if (root !== document) {
     3294          var oldId = root.id, id = $(root).identify();
     3295          id = id.replace(/([\.:])/g, "\\$1");
     3296          e = "#" + id + " " + e;
     3297        }
     3298
     3299        results = $A(root.querySelectorAll(e)).map(Element.extend);
     3300        root.id = oldId;
     3301
     3302        return results;
     3303      case 'xpath':
     3304        return document._getElementsByXPath(this.xpath, root);
     3305      default:
     3306       return this.matcher(root);
     3307    }
    27853308  },
    27863309
     
    27893312
    27903313    var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
    2791     var le, p, m;
     3314    var le, p, m, len = ps.length, name;
    27923315
    27933316    while (e && le !== e && (/\S/).test(e)) {
    27943317      le = e;
    2795       for (var i in ps) {
    2796         p = ps[i];
     3318      for (var i = 0; i<len; i++) {
     3319        p = ps[i].re;
     3320        name = ps[i].name;
    27973321        if (m = e.match(p)) {
    2798           // use the Selector.assertions methods unless the selector
    2799           // is too complex.
    2800           if (as[i]) {
    2801             this.tokens.push([i, Object.clone(m)]);
     3322          if (as[name]) {
     3323            this.tokens.push([name, Object.clone(m)]);
    28023324            e = e.replace(m[0], '');
    28033325          } else {
    2804             // reluctantly do a document-wide search
    2805             // and look for a match in the array
    28063326            return this.findElements(document).include(element);
    28073327          }
     
    28293349  }
    28303350});
     3351
     3352if (Prototype.BrowserFeatures.SelectorsAPI &&
     3353 document.compatMode === 'BackCompat') {
     3354  Selector.CASE_INSENSITIVE_CLASS_NAMES = (function(){
     3355    var div = document.createElement('div'),
     3356     span = document.createElement('span');
     3357
     3358    div.id = "prototype_test_id";
     3359    span.className = 'Test';
     3360    div.appendChild(span);
     3361    var isIgnored = (div.querySelector('#prototype_test_id .test') !== null);
     3362    div = span = null;
     3363    return isIgnored;
     3364  })();
     3365}
    28313366
    28323367Object.extend(Selector, {
     
    28453380    className:    "[contains(concat(' ', @class, ' '), ' #{1} ')]",
    28463381    id:           "[@id='#{1}']",
    2847     attrPresence: "[@#{1}]",
     3382    attrPresence: function(m) {
     3383      m[1] = m[1].toLowerCase();
     3384      return new Template("[@#{1}]").evaluate(m);
     3385    },
    28483386    attr: function(m) {
     3387      m[1] = m[1].toLowerCase();
    28493388      m[3] = m[5] || m[6];
    28503389      return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
     
    28693408      'last-child':  '[not(following-sibling::*)]',
    28703409      'only-child':  '[not(preceding-sibling::* or following-sibling::*)]',
    2871       'empty':       "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
     3410      'empty':       "[count(*) = 0 and (count(text()) = 0)]",
    28723411      'checked':     "[@checked]",
    2873       'disabled':    "[@disabled]",
    2874       'enabled':     "[not(@disabled)]",
     3412      'disabled':    "[(@disabled) and (@type!='hidden')]",
     3413      'enabled':     "[not(@disabled) and (@type!='hidden')]",
    28753414      'not': function(m) {
    28763415        var e = m[6], p = Selector.patterns,
    2877             x = Selector.xpath, le, m, v;
     3416            x = Selector.xpath, le, v, len = p.length, name;
    28783417
    28793418        var exclusion = [];
    28803419        while (e && le != e && (/\S/).test(e)) {
    28813420          le = e;
    2882           for (var i in p) {
    2883             if (m = e.match(p[i])) {
    2884               v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);
     3421          for (var i = 0; i<len; i++) {
     3422            name = p[i].name
     3423            if (m = e.match(p[i].re)) {
     3424              v = Object.isFunction(x[name]) ? x[name](m) : new Template(x[name]).evaluate(m);
    28853425              exclusion.push("(" + v.substring(1, v.length - 1) + ")");
    28863426              e = e.replace(m[0], '');
     
    29323472
    29333473  criteria: {
    2934     tagName:      'n = h.tagName(n, r, "#{1}", c);   c = false;',
    2935     className:    'n = h.className(n, r, "#{1}", c); c = false;',
    2936     id:           'n = h.id(n, r, "#{1}", c);        c = false;',
    2937     attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
     3474    tagName:      'n = h.tagName(n, r, "#{1}", c);      c = false;',
     3475    className:    'n = h.className(n, r, "#{1}", c);    c = false;',
     3476    id:           'n = h.id(n, r, "#{1}", c);           c = false;',
     3477    attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;',
    29383478    attr: function(m) {
    29393479      m[3] = (m[5] || m[6]);
    2940       return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
     3480      return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);
    29413481    },
    29423482    pseudo: function(m) {
     
    29503490  },
    29513491
    2952   patterns: {
    2953     // combinators must be listed first
    2954     // (and descendant needs to be last combinator)
    2955     laterSibling: /^\s*~\s*/,
    2956     child:        /^\s*>\s*/,
    2957     adjacent:     /^\s*\+\s*/,
    2958     descendant:   /^\s/,
    2959 
    2960     // selectors follow
    2961     tagName:      /^\s*(\*|[\w\-]+)(\b|$)?/,
    2962     id:           /^#([\w\-\*]+)(\b|$)/,
    2963     className:    /^\.([\w\-\*]+)(\b|$)/,
    2964     pseudo:       /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s)|(?=:))/,
    2965     attrPresence: /^\[([\w]+)\]/,
    2966     attr:         /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
    2967   },
    2968 
    2969   // for Selector.match and Element#match
     3492  patterns: [
     3493    { name: 'laterSibling', re: /^\s*~\s*/ },
     3494    { name: 'child',        re: /^\s*>\s*/ },
     3495    { name: 'adjacent',     re: /^\s*\+\s*/ },
     3496    { name: 'descendant',   re: /^\s/ },
     3497
     3498    { name: 'tagName',      re: /^\s*(\*|[\w\-]+)(\b|$)?/ },
     3499    { name: 'id',           re: /^#([\w\-\*]+)(\b|$)/ },
     3500    { name: 'className',    re: /^\.([\w\-\*]+)(\b|$)/ },
     3501    { name: 'pseudo',       re: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/ },
     3502    { name: 'attrPresence', re: /^\[((?:[\w-]+:)?[\w-]+)\]/ },
     3503    { name: 'attr',         re: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ }
     3504  ],
     3505
    29703506  assertions: {
    29713507    tagName: function(element, matches) {
     
    29873523    attr: function(element, matches) {
    29883524      var nodeValue = Element.readAttribute(element, matches[1]);
    2989       return Selector.operators[matches[2]](nodeValue, matches[3]);
     3525      return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);
    29903526    }
    29913527  },
    29923528
    29933529  handlers: {
    2994     // UTILITY FUNCTIONS
    2995     // joins two collections
    29963530    concat: function(a, b) {
    29973531      for (var i = 0, node; node = b[i]; i++)
     
    30003534    },
    30013535
    3002     // marks an array of nodes for counting
    30033536    mark: function(nodes) {
     3537      var _true = Prototype.emptyFunction;
    30043538      for (var i = 0, node; node = nodes[i]; i++)
    3005         node._counted = true;
     3539        node._countedByPrototype = _true;
    30063540      return nodes;
    30073541    },
    30083542
    3009     unmark: function(nodes) {
    3010       for (var i = 0, node; node = nodes[i]; i++)
    3011         node._counted = undefined;
    3012       return nodes;
    3013     },
    3014 
    3015     // mark each child node with its position (for nth calls)
    3016     // "ofType" flag indicates whether we're indexing for nth-of-type
    3017     // rather than nth-child
     3543    unmark: (function(){
     3544
     3545      var PROPERTIES_ATTRIBUTES_MAP = (function(){
     3546        var el = document.createElement('div'),
     3547            isBuggy = false,
     3548            propName = '_countedByPrototype',
     3549            value = 'x'
     3550        el[propName] = value;
     3551        isBuggy = (el.getAttribute(propName) === value);
     3552        el = null;
     3553        return isBuggy;
     3554      })();
     3555
     3556      return PROPERTIES_ATTRIBUTES_MAP ?
     3557        function(nodes) {
     3558          for (var i = 0, node; node = nodes[i]; i++)
     3559            node.removeAttribute('_countedByPrototype');
     3560          return nodes;
     3561        } :
     3562        function(nodes) {
     3563          for (var i = 0, node; node = nodes[i]; i++)
     3564            node._countedByPrototype = void 0;
     3565          return nodes;
     3566        }
     3567    })(),
     3568
    30183569    index: function(parentNode, reverse, ofType) {
    3019       parentNode._counted = true;
     3570      parentNode._countedByPrototype = Prototype.emptyFunction;
    30203571      if (reverse) {
    30213572        for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
    30223573          var node = nodes[i];
    3023           if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
     3574          if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
    30243575        }
    30253576      } else {
    30263577        for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
    3027           if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
     3578          if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
    30283579      }
    30293580    },
    30303581
    3031     // filters out duplicates and extends all nodes
    30323582    unique: function(nodes) {
    30333583      if (nodes.length == 0) return nodes;
    30343584      var results = [], n;
    30353585      for (var i = 0, l = nodes.length; i < l; i++)
    3036         if (!(n = nodes[i])._counted) {
    3037           n._counted = true;
     3586        if (typeof (n = nodes[i])._countedByPrototype == 'undefined') {
     3587          n._countedByPrototype = Prototype.emptyFunction;
    30383588          results.push(Element.extend(n));
    30393589        }
     
    30413591    },
    30423592
    3043     // COMBINATOR FUNCTIONS
    30443593    descendant: function(nodes) {
    30453594      var h = Selector.handlers;
     
    30523601      var h = Selector.handlers;
    30533602      for (var i = 0, results = [], node; node = nodes[i]; i++) {
    3054         for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
     3603        for (var j = 0, child; child = node.childNodes[j]; j++)
    30553604          if (child.nodeType == 1 && child.tagName != '!') results.push(child);
    30563605      }
     
    30753624    nextElementSibling: function(node) {
    30763625      while (node = node.nextSibling)
    3077           if (node.nodeType == 1) return node;
     3626        if (node.nodeType == 1) return node;
    30783627      return null;
    30793628    },
     
    30853634    },
    30863635
    3087     // TOKEN FUNCTIONS
    30883636    tagName: function(nodes, root, tagName, combinator) {
    3089       tagName = tagName.toUpperCase();
     3637      var uTagName = tagName.toUpperCase();
    30903638      var results = [], h = Selector.handlers;
    30913639      if (nodes) {
    30923640        if (combinator) {
    3093           // fastlane for ordinary descendant combinators
    30943641          if (combinator == "descendant") {
    30953642            for (var i = 0, node; node = nodes[i]; i++)
     
    31003647        }
    31013648        for (var i = 0, node; node = nodes[i]; i++)
    3102           if (node.tagName.toUpperCase() == tagName) results.push(node);
     3649          if (node.tagName.toUpperCase() === uTagName) results.push(node);
    31033650        return results;
    31043651      } else return root.getElementsByTagName(tagName);
     
    31073654    id: function(nodes, root, id, combinator) {
    31083655      var targetNode = $(id), h = Selector.handlers;
    3109       if (!targetNode) return [];
    3110       if (!nodes && root == document) return [targetNode];
     3656
     3657      if (root == document) {
     3658        if (!targetNode) return [];
     3659        if (!nodes) return [targetNode];
     3660      } else {
     3661        if (!root.sourceIndex || root.sourceIndex < 1) {
     3662          var nodes = root.getElementsByTagName('*');
     3663          for (var j = 0, node; node = nodes[j]; j++) {
     3664            if (node.id === id) return [node];
     3665          }
     3666        }
     3667      }
     3668
    31113669      if (nodes) {
    31123670        if (combinator) {
     
    31473705    },
    31483706
    3149     attrPresence: function(nodes, root, attr) {
     3707    attrPresence: function(nodes, root, attr, combinator) {
    31503708      if (!nodes) nodes = root.getElementsByTagName("*");
     3709      if (nodes && combinator) nodes = this[combinator](nodes);
    31513710      var results = [];
    31523711      for (var i = 0, node; node = nodes[i]; i++)
     
    31553714    },
    31563715
    3157     attr: function(nodes, root, attr, value, operator) {
     3716    attr: function(nodes, root, attr, value, operator, combinator) {
    31583717      if (!nodes) nodes = root.getElementsByTagName("*");
     3718      if (nodes && combinator) nodes = this[combinator](nodes);
    31593719      var handler = Selector.operators[operator], results = [];
    31603720      for (var i = 0, node; node = nodes[i]; i++) {
     
    32183778    },
    32193779
    3220     // handles the an+b logic
    32213780    getIndices: function(a, b, total) {
    32223781      if (a == 0) return b > 0 ? [b] : [];
     
    32273786    },
    32283787
    3229     // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
    32303788    nth: function(nodes, formula, root, reverse, ofType) {
    32313789      if (nodes.length == 0) return [];
     
    32353793      h.mark(nodes);
    32363794      for (var i = 0, node; node = nodes[i]; i++) {
    3237         if (!node.parentNode._counted) {
     3795        if (!node.parentNode._countedByPrototype) {
    32383796          h.index(node.parentNode, reverse, ofType);
    32393797          indexed.push(node.parentNode);
     
    32613819    'empty': function(nodes, value, root) {
    32623820      for (var i = 0, results = [], node; node = nodes[i]; i++) {
    3263         // IE treats comments as element nodes
    3264         if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
     3821        if (node.tagName == '!' || node.firstChild) continue;
    32653822        results.push(node);
    32663823      }
     
    32733830      h.mark(exclusions);
    32743831      for (var i = 0, results = [], node; node = nodes[i]; i++)
    3275         if (!node._counted) results.push(node);
     3832        if (!node._countedByPrototype) results.push(node);
    32763833      h.unmark(exclusions);
    32773834      return results;
     
    32803837    'enabled': function(nodes, value, root) {
    32813838      for (var i = 0, results = [], node; node = nodes[i]; i++)
    3282         if (!node.disabled) results.push(node);
     3839        if (!node.disabled && (!node.type || node.type !== 'hidden'))
     3840          results.push(node);
    32833841      return results;
    32843842    },
     
    33003858    '=':  function(nv, v) { return nv == v; },
    33013859    '!=': function(nv, v) { return nv != v; },
    3302     '^=': function(nv, v) { return nv.startsWith(v); },
    3303     '$=': function(nv, v) { return nv.endsWith(v); },
    3304     '*=': function(nv, v) { return nv.include(v); },
     3860    '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); },
     3861    '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); },
     3862    '*=': function(nv, v) { return nv == v || nv && nv.include(v); },
    33053863    '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
    3306     '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
     3864    '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() +
     3865     '-').include('-' + (v || "").toUpperCase() + '-'); }
     3866  },
     3867
     3868  split: function(expression) {
     3869    var expressions = [];
     3870    expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
     3871      expressions.push(m[1].strip());
     3872    });
     3873    return expressions;
    33073874  },
    33083875
    33093876  matchElements: function(elements, expression) {
    3310     var matches = new Selector(expression).findElements(), h = Selector.handlers;
     3877    var matches = $$(expression), h = Selector.handlers;
    33113878    h.mark(matches);
    33123879    for (var i = 0, results = [], element; element = elements[i]; i++)
    3313       if (element._counted) results.push(element);
     3880      if (element._countedByPrototype) results.push(element);
    33143881    h.unmark(matches);
    33153882    return results;
     
    33243891
    33253892  findChildElements: function(element, expressions) {
    3326     var exprs = expressions.join(','), expressions = [];
    3327     exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
    3328       expressions.push(m[1].strip());
    3329     });
     3893    expressions = Selector.split(expressions.join(','));
    33303894    var results = [], h = Selector.handlers;
    33313895    for (var i = 0, l = expressions.length, selector; i < l; i++) {
     
    33373901});
    33383902
     3903if (Prototype.Browser.IE) {
     3904  Object.extend(Selector.handlers, {
     3905    concat: function(a, b) {
     3906      for (var i = 0, node; node = b[i]; i++)
     3907        if (node.tagName !== "!") a.push(node);
     3908      return a;
     3909    }
     3910  });
     3911}
     3912
    33393913function $$() {
    33403914  return Selector.findChildElements(document, $A(arguments));
    33413915}
     3916
    33423917var Form = {
    33433918  reset: function(form) {
    3344     $(form).reset();
     3919    form = $(form);
     3920    form.reset();
    33453921    return form;
    33463922  },
     
    33483924  serializeElements: function(elements, options) {
    33493925    if (typeof options != 'object') options = { hash: !!options };
    3350     else if (options.hash === undefined) options.hash = true;
     3926    else if (Object.isUndefined(options.hash)) options.hash = true;
    33513927    var key, value, submitted = false, submit = options.submit;
    33523928
     
    33543930      if (!element.disabled && element.name) {
    33553931        key = element.name; value = $(element).getValue();
    3356         if (value != null && (element.type != 'submit' || (!submitted &&
     3932        if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
    33573933            submit !== false && (!submit || key == submit) && (submitted = true)))) {
    33583934          if (key in result) {
    3359             // a key is already present; construct an array of values
    33603935            if (!Object.isArray(result[key])) result[key] = [result[key]];
    33613936            result[key].push(value);
     
    33773952
    33783953  getElements: function(form) {
    3379     return $A($(form).getElementsByTagName('*')).inject([],
    3380       function(elements, child) {
    3381         if (Form.Element.Serializers[child.tagName.toLowerCase()])
    3382           elements.push(Element.extend(child));
    3383         return elements;
    3384       }
    3385     );
     3954    var elements = $(form).getElementsByTagName('*'),
     3955        element,
     3956        arr = [ ],
     3957        serializers = Form.Element.Serializers;
     3958    for (var i = 0; element = elements[i]; i++) {
     3959      arr.push(element);
     3960    }
     3961    return arr.inject([], function(elements, child) {
     3962      if (serializers[child.tagName.toLowerCase()])
     3963        elements.push(Element.extend(child));
     3964      return elements;
     3965    })
    33863966  },
    33873967
     
    34234003
    34244004    return firstByIndex ? firstByIndex : elements.find(function(element) {
    3425       return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
     4005      return /^(?:input|select|textarea)$/i.test(element.tagName);
    34264006    });
    34274007  },
     
    34544034/*--------------------------------------------------------------------------*/
    34554035
     4036
    34564037Form.Element = {
    34574038  focus: function(element) {
     
    34674048
    34684049Form.Element.Methods = {
     4050
    34694051  serialize: function(element) {
    34704052    element = $(element);
     
    35074089      element.focus();
    35084090      if (element.select && (element.tagName.toLowerCase() != 'input' ||
    3509           !['button', 'reset', 'submit'].include(element.type)))
     4091          !(/^(?:button|reset|submit)$/i.test(element.type))))
    35104092        element.select();
    35114093    } catch (e) { }
     
    35154097  disable: function(element) {
    35164098    element = $(element);
    3517     element.blur();
    35184099    element.disabled = true;
    35194100    return element;
     
    35304111
    35314112var Field = Form.Element;
     4113
    35324114var $F = Form.Element.Methods.getValue;
    35334115
     
    35464128
    35474129  inputSelector: function(element, value) {
    3548     if (value === undefined) return element.checked ? element.value : null;
     4130    if (Object.isUndefined(value)) return element.checked ? element.value : null;
    35494131    else element.checked = !!value;
    35504132  },
    35514133
    35524134  textarea: function(element, value) {
    3553     if (value === undefined) return element.value;
     4135    if (Object.isUndefined(value)) return element.value;
    35544136    else element.value = value;
    35554137  },
    35564138
    3557   select: function(element, index) {
    3558     if (index === undefined)
     4139  select: function(element, value) {
     4140    if (Object.isUndefined(value))
    35594141      return this[element.type == 'select-one' ?
    35604142        'selectOne' : 'selectMany'](element);
    35614143    else {
    3562       var opt, value, single = !Object.isArray(index);
     4144      var opt, currentValue, single = !Object.isArray(value);
    35634145      for (var i = 0, length = element.length; i < length; i++) {
    35644146        opt = element.options[i];
    3565         value = this.optionValue(opt);
     4147        currentValue = this.optionValue(opt);
    35664148        if (single) {
    3567           if (value == index) {
     4149          if (currentValue == value) {
    35684150            opt.selected = true;
    35694151            return;
    35704152          }
    35714153        }
    3572         else opt.selected = index.include(value);
     4154        else opt.selected = value.include(currentValue);
    35734155      }
    35744156    }
     
    35924174
    35934175  optionValue: function(opt) {
    3594     // extend element because hasAttribute may not be native
    35954176    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
    35964177  }
     
    35984179
    35994180/*--------------------------------------------------------------------------*/
     4181
    36004182
    36014183Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
     
    36804262  }
    36814263});
    3682 if (!window.Event) var Event = { };
    3683 
    3684 Object.extend(Event, {
    3685   KEY_BACKSPACE: 8,
    3686   KEY_TAB:       9,
    3687   KEY_RETURN:   13,
    3688   KEY_ESC:      27,
    3689   KEY_LEFT:     37,
    3690   KEY_UP:       38,
    3691   KEY_RIGHT:    39,
    3692   KEY_DOWN:     40,
    3693   KEY_DELETE:   46,
    3694   KEY_HOME:     36,
    3695   KEY_END:      35,
    3696   KEY_PAGEUP:   33,
    3697   KEY_PAGEDOWN: 34,
    3698   KEY_INSERT:   45,
    3699 
    3700   cache: { },
    3701 
    3702   relatedTarget: function(event) {
    3703     var element;
    3704     switch(event.type) {
    3705       case 'mouseover': element = event.fromElement; break;
    3706       case 'mouseout':  element = event.toElement;   break;
    3707       default: return null;
    3708     }
    3709     return Element.extend(element);
    3710   }
    3711 });
    3712 
    3713 Event.Methods = (function() {
    3714   var isButton;
    3715 
     4264(function() {
     4265
     4266  var Event = {
     4267    KEY_BACKSPACE: 8,
     4268    KEY_TAB:       9,
     4269    KEY_RETURN:   13,
     4270    KEY_ESC:      27,
     4271    KEY_LEFT:     37,
     4272    KEY_UP:       38,
     4273    KEY_RIGHT:    39,
     4274    KEY_DOWN:     40,
     4275    KEY_DELETE:   46,
     4276    KEY_HOME:     36,
     4277    KEY_END:      35,
     4278    KEY_PAGEUP:   33,
     4279    KEY_PAGEDOWN: 34,
     4280    KEY_INSERT:   45,
     4281
     4282    cache: {}
     4283  };
     4284
     4285  var docEl = document.documentElement;
     4286  var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
     4287    && 'onmouseleave' in docEl;
     4288
     4289  var _isButton;
    37164290  if (Prototype.Browser.IE) {
    37174291    var buttonMap = { 0: 1, 1: 4, 2: 2 };
    3718     isButton = function(event, code) {
    3719       return event.button == buttonMap[code];
     4292    _isButton = function(event, code) {
     4293      return event.button === buttonMap[code];
    37204294    };
    3721 
    37224295  } else if (Prototype.Browser.WebKit) {
    3723     isButton = function(event, code) {
     4296    _isButton = function(event, code) {
    37244297      switch (code) {
    37254298        case 0: return event.which == 1 && !event.metaKey;
     
    37284301      }
    37294302    };
    3730 
    37314303  } else {
    3732     isButton = function(event, code) {
     4304    _isButton = function(event, code) {
    37334305      return event.which ? (event.which === code + 1) : (event.button === code);
    37344306    };
    37354307  }
    37364308
    3737   return {
    3738     isLeftClick:   function(event) { return isButton(event, 0) },
    3739     isMiddleClick: function(event) { return isButton(event, 1) },
    3740     isRightClick:  function(event) { return isButton(event, 2) },
    3741 
    3742     element: function(event) {
    3743       var node = Event.extend(event).target;
    3744       return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node);
    3745     },
    3746 
    3747     findElement: function(event, expression) {
    3748       var element = Event.element(event);
    3749       return element.match(expression) ? element : element.up(expression);
    3750     },
    3751 
    3752     pointer: function(event) {
    3753       return {
    3754         x: event.pageX || (event.clientX +
    3755           (document.documentElement.scrollLeft || document.body.scrollLeft)),
    3756         y: event.pageY || (event.clientY +
    3757           (document.documentElement.scrollTop || document.body.scrollTop))
    3758       };
    3759     },
    3760 
    3761     pointerX: function(event) { return Event.pointer(event).x },
    3762     pointerY: function(event) { return Event.pointer(event).y },
    3763 
    3764     stop: function(event) {
    3765       Event.extend(event);
    3766       event.preventDefault();
    3767       event.stopPropagation();
    3768       event.stopped = true;
    3769     }
     4309  function isLeftClick(event)   { return _isButton(event, 0) }
     4310
     4311  function isMiddleClick(event) { return _isButton(event, 1) }
     4312
     4313  function isRightClick(event)  { return _isButton(event, 2) }
     4314
     4315  function element(event) {
     4316    event = Event.extend(event);
     4317
     4318    var node = event.target, type = event.type,
     4319     currentTarget = event.currentTarget;
     4320
     4321    if (currentTarget && currentTarget.tagName) {
     4322      if (type === 'load' || type === 'error' ||
     4323        (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
     4324          && currentTarget.type === 'radio'))
     4325            node = currentTarget;
     4326    }
     4327
     4328    if (node.nodeType == Node.TEXT_NODE)
     4329      node = node.parentNode;
     4330
     4331    return Element.extend(node);
     4332  }
     4333
     4334  function findElement(event, expression) {
     4335    var element = Event.element(event);
     4336    if (!expression) return element;
     4337    var elements = [element].concat(element.ancestors());
     4338    return Selector.findElement(elements, expression, 0);
     4339  }
     4340
     4341  function pointer(event) {
     4342    return { x: pointerX(event), y: pointerY(event) };
     4343  }
     4344
     4345  function pointerX(event) {
     4346    var docElement = document.documentElement,
     4347     body = document.body || { scrollLeft: 0 };
     4348
     4349    return event.pageX || (event.clientX +
     4350      (docElement.scrollLeft || body.scrollLeft) -
     4351      (docElement.clientLeft || 0));
     4352  }
     4353
     4354  function pointerY(event) {
     4355    var docElement = document.documentElement,
     4356     body = document.body || { scrollTop: 0 };
     4357
     4358    return  event.pageY || (event.clientY +
     4359       (docElement.scrollTop || body.scrollTop) -
     4360       (docElement.clientTop || 0));
     4361  }
     4362
     4363
     4364  function stop(event) {
     4365    Event.extend(event);
     4366    event.preventDefault();
     4367    event.stopPropagation();
     4368
     4369    event.stopped = true;
     4370  }
     4371
     4372  Event.Methods = {
     4373    isLeftClick: isLeftClick,
     4374    isMiddleClick: isMiddleClick,
     4375    isRightClick: isRightClick,
     4376
     4377    element: element,
     4378    findElement: findElement,
     4379
     4380    pointer: pointer,
     4381    pointerX: pointerX,
     4382    pointerY: pointerY,
     4383
     4384    stop: stop
    37704385  };
    3771 })();
    3772 
    3773 Event.extend = (function() {
     4386
     4387
    37744388  var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
    37754389    m[name] = Event.Methods[name].methodize();
     
    37784392
    37794393  if (Prototype.Browser.IE) {
     4394    function _relatedTarget(event) {
     4395      var element;
     4396      switch (event.type) {
     4397        case 'mouseover': element = event.fromElement; break;
     4398        case 'mouseout':  element = event.toElement;   break;
     4399        default: return null;
     4400      }
     4401      return Element.extend(element);
     4402    }
     4403
    37804404    Object.extend(methods, {
    37814405      stopPropagation: function() { this.cancelBubble = true },
    37824406      preventDefault:  function() { this.returnValue = false },
    3783       inspect: function() { return "[object Event]" }
     4407      inspect: function() { return '[object Event]' }
    37844408    });
    37854409
    3786     return function(event) {
     4410    Event.extend = function(event, element) {
    37874411      if (!event) return false;
    37884412      if (event._extendedByPrototype) return event;
     
    37904414      event._extendedByPrototype = Prototype.emptyFunction;
    37914415      var pointer = Event.pointer(event);
     4416
    37924417      Object.extend(event, {
    3793         target: event.srcElement,
    3794         relatedTarget: Event.relatedTarget(event),
     4418        target: event.srcElement || element,
     4419        relatedTarget: _relatedTarget(event),
    37954420        pageX:  pointer.x,
    37964421        pageY:  pointer.y
    37974422      });
     4423
    37984424      return Object.extend(event, methods);
    37994425    };
    3800 
    38014426  } else {
    3802     Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__;
     4427    Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__;
    38034428    Object.extend(Event.prototype, methods);
    3804     return Prototype.K;
    3805   }
     4429    Event.extend = Prototype.K;
     4430  }
     4431
     4432  function _createResponder(element, eventName, handler) {
     4433    var registry = Element.retrieve(element, 'prototype_event_registry');
     4434
     4435    if (Object.isUndefined(registry)) {
     4436      CACHE.push(element);
     4437      registry = Element.retrieve(element, 'prototype_event_registry', $H());
     4438    }
     4439
     4440    var respondersForEvent = registry.get(eventName);
     4441    if (Object.isUndefined(respondersForEvent)) {
     4442      respondersForEvent = [];
     4443      registry.set(eventName, respondersForEvent);
     4444    }
     4445
     4446    if (respondersForEvent.pluck('handler').include(handler)) return false;
     4447
     4448    var responder;
     4449    if (eventName.include(":")) {
     4450      responder = function(event) {
     4451        if (Object.isUndefined(event.eventName))
     4452          return false;
     4453
     4454        if (event.eventName !== eventName)
     4455          return false;
     4456
     4457        Event.extend(event, element);
     4458        handler.call(element, event);
     4459      };
     4460    } else {
     4461      if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED &&
     4462       (eventName === "mouseenter" || eventName === "mouseleave")) {
     4463        if (eventName === "mouseenter" || eventName === "mouseleave") {
     4464          responder = function(event) {
     4465            Event.extend(event, element);
     4466
     4467            var parent = event.relatedTarget;
     4468            while (parent && parent !== element) {
     4469              try { parent = parent.parentNode; }
     4470              catch(e) { parent = element; }
     4471            }
     4472
     4473            if (parent === element) return;
     4474
     4475            handler.call(element, event);
     4476          };
     4477        }
     4478      } else {
     4479        responder = function(event) {
     4480          Event.extend(event, element);
     4481          handler.call(element, event);
     4482        };
     4483      }
     4484    }
     4485
     4486    responder.handler = handler;
     4487    respondersForEvent.push(responder);
     4488    return responder;
     4489  }
     4490
     4491  function _destroyCache() {
     4492    for (var i = 0, length = CACHE.length; i < length; i++) {
     4493      Event.stopObserving(CACHE[i]);
     4494      CACHE[i] = null;
     4495    }
     4496  }
     4497
     4498  var CACHE = [];
     4499
     4500  if (Prototype.Browser.IE)
     4501    window.attachEvent('onunload', _destroyCache);
     4502
     4503  if (Prototype.Browser.WebKit)
     4504    window.addEventListener('unload', Prototype.emptyFunction, false);
     4505
     4506
     4507  var _getDOMEventName = Prototype.K;
     4508
     4509  if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) {
     4510    _getDOMEventName = function(eventName) {
     4511      var translations = { mouseenter: "mouseover", mouseleave: "mouseout" };
     4512      return eventName in translations ? translations[eventName] : eventName;
     4513    };
     4514  }
     4515
     4516  function observe(element, eventName, handler) {
     4517    element = $(element);
     4518
     4519    var responder = _createResponder(element, eventName, handler);
     4520
     4521    if (!responder) return element;
     4522
     4523    if (eventName.include(':')) {
     4524      if (element.addEventListener)
     4525        element.addEventListener("dataavailable", responder, false);
     4526      else {
     4527        element.attachEvent("ondataavailable", responder);
     4528        element.attachEvent("onfilterchange", responder);
     4529      }
     4530    } else {
     4531      var actualEventName = _getDOMEventName(eventName);
     4532
     4533      if (element.addEventListener)
     4534        element.addEventListener(actualEventName, responder, false);
     4535      else
     4536        element.attachEvent("on" + actualEventName, responder);
     4537    }
     4538
     4539    return element;
     4540  }
     4541
     4542  function stopObserving(element, eventName, handler) {
     4543    element = $(element);
     4544
     4545    var registry = Element.retrieve(element, 'prototype_event_registry');
     4546
     4547    if (Object.isUndefined(registry)) return element;
     4548
     4549    if (eventName && !handler) {
     4550      var responders = registry.get(eventName);
     4551
     4552      if (Object.isUndefined(responders)) return element;
     4553
     4554      responders.each( function(r) {
     4555        Element.stopObserving(element, eventName, r.handler);
     4556      });
     4557      return element;
     4558    } else if (!eventName) {
     4559      registry.each( function(pair) {
     4560        var eventName = pair.key, responders = pair.value;
     4561
     4562        responders.each( function(r) {
     4563          Element.stopObserving(element, eventName, r.handler);
     4564        });
     4565      });
     4566      return element;
     4567    }
     4568
     4569    var responders = registry.get(eventName);
     4570
     4571    if (!responders) return;
     4572
     4573    var responder = responders.find( function(r) { return r.handler === handler; });
     4574    if (!responder) return element;
     4575
     4576    var actualEventName = _getDOMEventName(eventName);
     4577
     4578    if (eventName.include(':')) {
     4579      if (element.removeEventListener)
     4580        element.removeEventListener("dataavailable", responder, false);
     4581      else {
     4582        element.detachEvent("ondataavailable", responder);
     4583        element.detachEvent("onfilterchange",  responder);
     4584      }
     4585    } else {
     4586      if (element.removeEventListener)
     4587        element.removeEventListener(actualEventName, responder, false);
     4588      else
     4589        element.detachEvent('on' + actualEventName, responder);
     4590    }
     4591
     4592    registry.set(eventName, responders.without(responder));
     4593
     4594    return element;
     4595  }
     4596
     4597  function fire(element, eventName, memo, bubble) {
     4598    element = $(element);
     4599
     4600    if (Object.isUndefined(bubble))
     4601      bubble = true;
     4602
     4603    if (element == document && document.createEvent && !element.dispatchEvent)
     4604      element = document.documentElement;
     4605
     4606    var event;
     4607    if (document.createEvent) {
     4608      event = document.createEvent('HTMLEvents');
     4609      event.initEvent('dataavailable', true, true);
     4610    } else {
     4611      event = document.createEventObject();
     4612      event.eventType = bubble ? 'ondataavailable' : 'onfilterchange';
     4613    }
     4614
     4615    event.eventName = eventName;
     4616    event.memo = memo || { };
     4617
     4618    if (document.createEvent)
     4619      element.dispatchEvent(event);
     4620    else
     4621      element.fireEvent(event.eventType, event);
     4622
     4623    return Event.extend(event);
     4624  }
     4625
     4626
     4627  Object.extend(Event, Event.Methods);
     4628
     4629  Object.extend(Event, {
     4630    fire:          fire,
     4631    observe:       observe,
     4632    stopObserving: stopObserving
     4633  });
     4634
     4635  Element.addMethods({
     4636    fire:          fire,
     4637
     4638    observe:       observe,
     4639
     4640    stopObserving: stopObserving
     4641  });
     4642
     4643  Object.extend(document, {
     4644    fire:          fire.methodize(),
     4645
     4646    observe:       observe.methodize(),
     4647
     4648    stopObserving: stopObserving.methodize(),
     4649
     4650    loaded:        false
     4651  });
     4652
     4653  if (window.Event) Object.extend(window.Event, Event);
     4654  else window.Event = Event;
    38064655})();
    3807 
    3808 Object.extend(Event, (function() {
    3809   var cache = Event.cache;
    3810 
    3811   function getEventID(element) {
    3812     if (element._eventID) return element._eventID;
    3813     arguments.callee.id = arguments.callee.id || 1;
    3814     return element._eventID = ++arguments.callee.id;
    3815   }
    3816 
    3817   function getDOMEventName(eventName) {
    3818     if (eventName && eventName.include(':')) return "dataavailable";
    3819     return eventName;
    3820   }
    3821 
    3822   function getCacheForID(id) {
    3823     return cache[id] = cache[id] || { };
    3824   }
    3825 
    3826   function getWrappersForEventName(id, eventName) {
    3827     var c = getCacheForID(id);
    3828     return c[eventName] = c[eventName] || [];
    3829   }
    3830 
    3831   function createWrapper(element, eventName, handler) {
    3832     var id = getEventID(element);
    3833     var c = getWrappersForEventName(id, eventName);
    3834     if (c.pluck("handler").include(handler)) return false;
    3835 
    3836     var wrapper = function(event) {
    3837       if (!Event || !Event.extend ||
    3838         (event.eventName && event.eventName != eventName))
    3839           return false;
    3840 
    3841       Event.extend(event);
    3842       handler.call(element, event)
    3843     };
    3844 
    3845     wrapper.handler = handler;
    3846     c.push(wrapper);
    3847     return wrapper;
    3848   }
    3849 
    3850   function findWrapper(id, eventName, handler) {
    3851     var c = getWrappersForEventName(id, eventName);
    3852     return c.find(function(wrapper) { return wrapper.handler == handler });
    3853   }
    3854 
    3855   function destroyWrapper(id, eventName, handler) {
    3856     var c = getCacheForID(id);
    3857     if (!c[eventName]) return false;
    3858     c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
    3859   }
    3860 
    3861   function destroyCache() {
    3862     for (var id in cache)
    3863       for (var eventName in cache[id])
    3864         cache[id][eventName] = null;
    3865   }
    3866 
    3867   if (window.attachEvent) {
    3868     window.attachEvent("onunload", destroyCache);
    3869   }
    3870 
    3871   return {
    3872     observe: function(element, eventName, handler) {
    3873       element = $(element);
    3874       var name = getDOMEventName(eventName);
    3875 
    3876       var wrapper = createWrapper(element, eventName, handler);
    3877       if (!wrapper) return element;
    3878 
    3879       if (element.addEventListener) {
    3880         element.addEventListener(name, wrapper, false);
    3881       } else {
    3882         element.attachEvent("on" + name, wrapper);
    3883       }
    3884 
    3885       return element;
    3886     },
    3887 
    3888     stopObserving: function(element, eventName, handler) {
    3889       element = $(element);
    3890       var id = getEventID(element), name = getDOMEventName(eventName);
    3891 
    3892       if (!handler && eventName) {
    3893         getWrappersForEventName(id, eventName).each(function(wrapper) {
    3894           element.stopObserving(eventName, wrapper.handler);
    3895         });
    3896         return element;
    3897 
    3898       } else if (!eventName) {
    3899         Object.keys(getCacheForID(id)).each(function(eventName) {
    3900           element.stopObserving(eventName);
    3901         });
    3902         return element;
    3903       }
    3904 
    3905       var wrapper = findWrapper(id, eventName, handler);
    3906       if (!wrapper) return element;
    3907 
    3908       if (element.removeEventListener) {
    3909         element.removeEventListener(name, wrapper, false);
    3910       } else {
    3911         element.detachEvent("on" + name, wrapper);
    3912       }
    3913 
    3914       destroyWrapper(id, eventName, handler);
    3915 
    3916       return element;
    3917     },
    3918 
    3919     fire: function(element, eventName, memo) {
    3920       element = $(element);
    3921       if (element == document && document.createEvent && !element.dispatchEvent)
    3922         element = document.documentElement;
    3923 
    3924       if (document.createEvent) {
    3925         var event = document.createEvent("HTMLEvents");
    3926         event.initEvent("dataavailable", true, true);
    3927       } else {
    3928         var event = document.createEventObject();
    3929         event.eventType = "ondataavailable";
    3930       }
    3931 
    3932       event.eventName = eventName;
    3933       event.memo = memo || { };
    3934 
    3935       if (document.createEvent) {
    3936         element.dispatchEvent(event);
    3937       } else {
    3938         element.fireEvent(event.eventType, event);
    3939       }
    3940 
    3941       return event;
    3942     }
    3943   };
    3944 })());
    3945 
    3946 Object.extend(Event, Event.Methods);
    3947 
    3948 Element.addMethods({
    3949   fire:          Event.fire,
    3950   observe:       Event.observe,
    3951   stopObserving: Event.stopObserving
    3952 });
    3953 
    3954 Object.extend(document, {
    3955   fire:          Element.Methods.fire.methodize(),
    3956   observe:       Element.Methods.observe.methodize(),
    3957   stopObserving: Element.Methods.stopObserving.methodize()
    3958 });
    39594656
    39604657(function() {
    39614658  /* Support for the DOMContentLoaded event is based on work by Dan Webb,
    3962      Matthias Miller, Dean Edwards and John Resig. */
    3963 
    3964   var timer, fired = false;
     4659     Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */
     4660
     4661  var timer;
    39654662
    39664663  function fireContentLoadedEvent() {
    3967     if (fired) return;
    3968     if (timer) window.clearInterval(timer);
    3969     document.fire("dom:loaded");
    3970     fired = true;
     4664    if (document.loaded) return;
     4665    if (timer) window.clearTimeout(timer);
     4666    document.loaded = true;
     4667    document.fire('dom:loaded');
     4668  }
     4669
     4670  function checkReadyState() {
     4671    if (document.readyState === 'complete') {
     4672      document.stopObserving('readystatechange', checkReadyState);
     4673      fireContentLoadedEvent();
     4674    }
     4675  }
     4676
     4677  function pollDoScroll() {
     4678    try { document.documentElement.doScroll('left'); }
     4679    catch(e) {
     4680      timer = pollDoScroll.defer();
     4681      return;
     4682    }
     4683    fireContentLoadedEvent();
    39714684  }
    39724685
    39734686  if (document.addEventListener) {
    3974     if (Prototype.Browser.WebKit) {
    3975       timer = window.setInterval(function() {
    3976         if (/loaded|complete/.test(document.readyState))
    3977           fireContentLoadedEvent();
    3978       }, 0);
    3979 
    3980       Event.observe(window, "load", fireContentLoadedEvent);
    3981 
    3982     } else {
    3983       document.addEventListener("DOMContentLoaded",
    3984         fireContentLoadedEvent, false);
    3985     }
    3986 
     4687    document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
    39874688  } else {
    3988     document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>");
    3989     $("__onDOMContentLoaded").onreadystatechange = function() {
    3990       if (this.readyState == "complete") {
    3991         this.onreadystatechange = null;
    3992         fireContentLoadedEvent();
    3993       }
    3994     };
    3995   }
     4689    document.observe('readystatechange', checkReadyState);
     4690    if (window == top)
     4691      timer = pollDoScroll.defer();
     4692  }
     4693
     4694  Event.observe(window, 'load', fireContentLoadedEvent);
    39964695})();
     4696
     4697Element.addMethods();
     4698
    39974699/*------------------------------- DEPRECATED -------------------------------*/
    39984700
     
    40234725var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
    40244726
    4025 // This should be moved to script.aculo.us; notice the deprecated methods
    4026 // further below, that map to the newer Element methods.
    40274727var Position = {
    4028   // set to true if needed, warning: firefox performance problems
    4029   // NOT neeeded for page scrolling, only if draggable contained in
    4030   // scrollable elements
    40314728  includeScrollOffsets: false,
    40324729
    4033   // must be called before calling withinIncludingScrolloffset, every time the
    4034   // page is scrolled
    40354730  prepare: function() {
    40364731    this.deltaX =  window.pageXOffset
     
    40444739  },
    40454740
    4046   // caches x/y coordinate pair to use with overlap
    40474741  within: function(element, x, y) {
    40484742    if (this.includeScrollOffsets)
     
    40714765  },
    40724766
    4073   // within must be called directly before
    40744767  overlap: function(mode, element) {
    40754768    if (!mode) return 0;
     
    40824775  },
    40834776
    4084   // Deprecation layer -- use newer Element methods now (1.5.2).
    40854777
    40864778  cumulativeOffset: Element.Methods.cumulativeOffset,
     
    41814873
    41824874/*--------------------------------------------------------------------------*/
    4183 
    4184 Element.addMethods();
  • trunk/wp-includes/js/scriptaculous/MIT-LICENSE

    r7131 r12557  
    1 Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
     1Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
    22
    33Permission is hereby granted, free of charge, to any person obtaining
  • trunk/wp-includes/js/scriptaculous/builder.js

    r7131 r12557  
    1 // script.aculo.us builder.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007
     1// script.aculo.us builder.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
    22
    3 // Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
     3// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
    44//
    55// script.aculo.us is freely distributable under the terms of an MIT-style license.
     
    2727  node: function(elementName) {
    2828    elementName = elementName.toUpperCase();
    29    
     29
    3030    // try innerHTML approach
    3131    var parentTag = this.NODEMAP[elementName] || 'div';
     
    3535    } catch(e) {}
    3636    var element = parentElement.firstChild || null;
    37      
     37
    3838    // see if browser added wrapping tags
    3939    if(element && (element.tagName.toUpperCase() != elementName))
    4040      element = element.getElementsByTagName(elementName)[0];
    41    
     41
    4242    // fallback to createElement approach
    4343    if(!element) element = document.createElement(elementName);
    44    
     44
    4545    // abort if nothing could be created
    4646    if(!element) return;
     
    6363            if(!element) {
    6464              element = document.createElement(elementName);
    65               for(attr in arguments[1]) 
     65              for(attr in arguments[1])
    6666                element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
    6767            }
     
    6969              element = parentElement.getElementsByTagName(elementName)[0];
    7070          }
    71         } 
     71        }
    7272
    7373    // text, or array of children
     
    7575      this._children(element, arguments[2]);
    7676
    77      return element;
     77     return $(element);
    7878  },
    7979  _text: function(text) {
     
    101101      children.flatten().each( function(e) {
    102102        if(typeof e=='object')
    103           element.appendChild(e)
     103          element.appendChild(e);
    104104        else
    105105          if(Builder._isStringOrNumber(e))
     
    118118    return element.down();
    119119  },
    120   dump: function(scope) { 
    121     if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope 
    122  
     120  dump: function(scope) {
     121    if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope
     122
    123123    var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
    124124      "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
     
    127127      "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
    128128      "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
    129  
    130     tags.each( function(tag){ 
    131       scope[tag] = function() { 
    132         return Builder.node.apply(Builder, [tag].concat($A(arguments))); 
    133       } 
     129
     130    tags.each( function(tag){
     131      scope[tag] = function() {
     132        return Builder.node.apply(Builder, [tag].concat($A(arguments)));
     133      };
    134134    });
    135135  }
    136 }
     136};
  • trunk/wp-includes/js/scriptaculous/controls.js

    r7131 r12557  
    1 // script.aculo.us controls.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007
    2 
    3 // Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
    4 //           (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
    5 //           (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
     1// script.aculo.us controls.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
     2
     3// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
     4//           (c) 2005-2009 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
     5//           (c) 2005-2009 Jon Tirsen (http://www.tirsen.com)
    66// Contributors:
    77//  Richard Livsey
    88//  Rahul Bhargava
    99//  Rob Wills
    10 // 
     10//
    1111// script.aculo.us is freely distributable under the terms of an MIT-style license.
    1212// For details, see the script.aculo.us web site: http://script.aculo.us/
    1313
    14 // Autocompleter.Base handles all the autocompletion functionality 
     14// Autocompleter.Base handles all the autocompletion functionality
    1515// that's independent of the data source for autocompletion. This
    1616// includes drawing the autocompletion menu, observing keyboard
    1717// and mouse events, and similar.
    1818//
    19 // Specific autocompleters need to provide, at the very least, 
     19// Specific autocompleters need to provide, at the very least,
    2020// a getUpdatedChoices function that will be invoked every time
    21 // the text inside the monitored textbox changes. This method 
     21// the text inside the monitored textbox changes. This method
    2222// should get the text for which to provide autocompletion by
    2323// invoking this.getToken(), NOT by directly accessing
     
    3333// Additionally, ',' in the above example can be replaced with
    3434// a token array, e.g. { tokens: [',', '\n'] } which
    35 // enables autocompletion on multiple tokens. This is most 
    36 // useful when one of the tokens is \n (a newline), as it 
     35// enables autocompletion on multiple tokens. This is most
     36// useful when one of the tokens is \n (a newline), as it
    3737// allows smart autocompletion after linebreaks.
    3838
     
    4040  throw("controls.js requires including script.aculo.us' effects.js library");
    4141
    42 var Autocompleter = { }
     42var Autocompleter = { };
    4343Autocompleter.Base = Class.create({
    4444  baseInitialize: function(element, update, options) {
    45     element          = $(element)
    46     this.element     = element; 
    47     this.update      = $(update); 
    48     this.hasFocus    = false; 
    49     this.changed     = false; 
    50     this.active      = false; 
    51     this.index       = 0;     
     45    element          = $(element);
     46    this.element     = element;
     47    this.update      = $(update);
     48    this.hasFocus    = false;
     49    this.changed     = false;
     50    this.active      = false;
     51    this.index       = 0;
    5252    this.entryCount  = 0;
    5353    this.oldElementValue = this.element.value;
     
    6262    this.options.frequency    = this.options.frequency || 0.4;
    6363    this.options.minChars     = this.options.minChars || 1;
    64     this.options.onShow       = this.options.onShow || 
    65       function(element, update){ 
     64    this.options.onShow       = this.options.onShow ||
     65      function(element, update){
    6666        if(!update.style.position || update.style.position=='absolute') {
    6767          update.style.position = 'absolute';
    6868          Position.clone(element, update, {
    69             setHeight: false, 
     69            setHeight: false,
    7070            offsetTop: element.offsetHeight
    7171          });
     
    7373        Effect.Appear(update,{duration:0.15});
    7474      };
    75     this.options.onHide = this.options.onHide || 
     75    this.options.onHide = this.options.onHide ||
    7676      function(element, update){ new Effect.Fade(update,{duration:0.15}) };
    7777
    78     if(typeof(this.options.tokens) == 'string') 
     78    if(typeof(this.options.tokens) == 'string')
    7979      this.options.tokens = new Array(this.options.tokens);
    8080    // Force carriage returns as token delimiters anyway
     
    8383
    8484    this.observer = null;
    85    
     85
    8686    this.element.setAttribute('autocomplete','off');
    8787
     
    8989
    9090    Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
    91     Event.observe(this.element, 'keypress', this.onKeyPress.bindAsEventListener(this));
     91    Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));
    9292  },
    9393
    9494  show: function() {
    9595    if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
    96     if(!this.iefix && 
     96    if(!this.iefix &&
    9797      (Prototype.Browser.IE) &&
    9898      (Element.getStyle(this.update, 'position')=='absolute')) {
    99       new Insertion.After(this.update, 
     99      new Insertion.After(this.update,
    100100       '<iframe id="' + this.update.id + '_iefix" '+
    101101       'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
     
    105105    if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
    106106  },
    107  
     107
    108108  fixIEOverlapping: function() {
    109109    Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
     
    145145         this.markPrevious();
    146146         this.render();
    147          if(Prototype.Browser.WebKit) Event.stop(event);
     147         Event.stop(event);
    148148         return;
    149149       case Event.KEY_DOWN:
    150150         this.markNext();
    151151         this.render();
    152          if(Prototype.Browser.WebKit) Event.stop(event);
     152         Event.stop(event);
    153153         return;
    154154      }
    155      else 
    156        if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || 
     155     else
     156       if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
    157157         (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;
    158158
     
    161161
    162162    if(this.observer) clearTimeout(this.observer);
    163       this.observer = 
     163      this.observer =
    164164        setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
    165165  },
     
    173173  onHover: function(event) {
    174174    var element = Event.findElement(event, 'LI');
    175     if(this.index != element.autocompleteIndex) 
     175    if(this.index != element.autocompleteIndex)
    176176    {
    177177        this.index = element.autocompleteIndex;
     
    180180    Event.stop(event);
    181181  },
    182  
     182
    183183  onClick: function(event) {
    184184    var element = Event.findElement(event, 'LI');
     
    187187    this.hide();
    188188  },
    189  
     189
    190190  onBlur: function(event) {
    191191    // needed to make click events working
    192192    setTimeout(this.hide.bind(this), 250);
    193193    this.hasFocus = false;
    194     this.active = false;     
    195   }, 
    196  
     194    this.active = false;
     195  },
     196
    197197  render: function() {
    198198    if(this.entryCount > 0) {
    199199      for (var i = 0; i < this.entryCount; i++)
    200         this.index==i ? 
    201           Element.addClassName(this.getEntry(i),"selected") : 
     200        this.index==i ?
     201          Element.addClassName(this.getEntry(i),"selected") :
    202202          Element.removeClassName(this.getEntry(i),"selected");
    203       if(this.hasFocus) { 
     203      if(this.hasFocus) {
    204204        this.show();
    205205        this.active = true;
     
    210210    }
    211211  },
    212  
     212
    213213  markPrevious: function() {
    214     if(this.index > 0) this.index--
     214    if(this.index > 0) this.index--;
    215215      else this.index = this.entryCount-1;
    216216    this.getEntry(this.index).scrollIntoView(true);
    217217  },
    218  
     218
    219219  markNext: function() {
    220     if(this.index < this.entryCount-1) this.index++
     220    if(this.index < this.entryCount-1) this.index++;
    221221      else this.index = 0;
    222222    this.getEntry(this.index).scrollIntoView(false);
    223223  },
    224  
     224
    225225  getEntry: function(index) {
    226226    return this.update.firstChild.childNodes[index];
    227227  },
    228  
     228
    229229  getCurrentEntry: function() {
    230230    return this.getEntry(this.index);
    231231  },
    232  
     232
    233233  selectEntry: function() {
    234234    this.active = false;
     
    247247    } else
    248248      value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
    249    
     249
    250250    var bounds = this.getTokenBounds();
    251251    if (bounds[0] != -1) {
     
    260260    this.oldElementValue = this.element.value;
    261261    this.element.focus();
    262    
     262
    263263    if (this.options.afterUpdateElement)
    264264      this.options.afterUpdateElement(this.element, selectedElement);
     
    272272
    273273      if(this.update.firstChild && this.update.down().childNodes) {
    274         this.entryCount = 
     274        this.entryCount =
    275275          this.update.down().childNodes.length;
    276276        for (var i = 0; i < this.entryCount; i++) {
     
    279279          this.addObservers(entry);
    280280        }
    281       } else { 
     281      } else {
    282282        this.entryCount = 0;
    283283      }
     
    285285      this.stopIndicator();
    286286      this.index = 0;
    287      
     287
    288288      if(this.entryCount==1 && this.options.autoSelect) {
    289289        this.selectEntry();
     
    301301
    302302  onObserverEvent: function() {
    303     this.changed = false;   
     303    this.changed = false;
    304304    this.tokenBounds = null;
    305305    if(this.getToken().length>=this.options.minChars) {
     
    354354  getUpdatedChoices: function() {
    355355    this.startIndicator();
    356    
    357     var entry = encodeURIComponent(this.options.paramName) + '=' + 
     356
     357    var entry = encodeURIComponent(this.options.paramName) + '=' +
    358358      encodeURIComponent(this.getToken());
    359359
     
    361361      this.options.callback(this.element, entry) : entry;
    362362
    363     if(this.options.defaultParams) 
     363    if(this.options.defaultParams)
    364364      this.options.parameters += '&' + this.options.defaultParams;
    365    
     365
    366366    new Ajax.Request(this.url, this.options);
    367367  },
     
    385385//
    386386// - partialSearch - If false, the autocompleter will match entered
    387 //                    text only at the beginning of strings in the 
     387//                    text only at the beginning of strings in the
    388388//                    autocomplete array. Defaults to true, which will
    389389//                    match text at the beginning of any *word* in the
     
    402402//                 Defaults to true.
    403403//
    404 // It's possible to pass in a custom function as the 'selector' 
     404// It's possible to pass in a custom function as the 'selector'
    405405// option, if you prefer to write your own autocompletion logic.
    406406// In that case, the other options above will not apply unless
     
    430430        var count     = 0;
    431431
    432         for (var i = 0; i < instance.options.array.length && 
    433           ret.length < instance.options.choices ; i++) { 
     432        for (var i = 0; i < instance.options.array.length &&
     433          ret.length < instance.options.choices ; i++) {
    434434
    435435          var elem = instance.options.array[i];
    436           var foundPos = instance.options.ignoreCase ? 
    437             elem.toLowerCase().indexOf(entry.toLowerCase()) : 
     436          var foundPos = instance.options.ignoreCase ?
     437            elem.toLowerCase().indexOf(entry.toLowerCase()) :
    438438            elem.indexOf(entry);
    439439
    440440          while (foundPos != -1) {
    441             if (foundPos == 0 && elem.length != entry.length) { 
    442               ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" + 
     441            if (foundPos == 0 && elem.length != entry.length) {
     442              ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
    443443                elem.substr(entry.length) + "</li>");
    444444              break;
    445             } else if (entry.length >= instance.options.partialChars && 
     445            } else if (entry.length >= instance.options.partialChars &&
    446446              instance.options.partialSearch && foundPos != -1) {
    447447              if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
     
    453453            }
    454454
    455             foundPos = instance.options.ignoreCase ? 
    456               elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : 
     455            foundPos = instance.options.ignoreCase ?
     456              elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
    457457              elem.indexOf(entry, foundPos + 1);
    458458
     
    460460        }
    461461        if (partial.length)
    462           ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
     462          ret = ret.concat(partial.slice(0, instance.options.choices - ret.length));
    463463        return "<ul>" + ret.join('') + "</ul>";
    464464      }
     
    477477    Field.activate(field);
    478478  }, 1);
    479 }
     479};
    480480
    481481Ajax.InPlaceEditor = Class.create({
     
    607607  },
    608608  getText: function() {
    609     return this.element.innerHTML;
     609    return this.element.innerHTML.unescapeHTML();
    610610  },
    611611  handleAJAXFailure: function(transport) {
     
    783783        var js = transport.responseText.strip();
    784784        if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
    785           throw 'Server returned an invalid collection representation.';
     785          throw('Server returned an invalid collection representation.');
    786786        this._collection = eval(js);
    787787        this.checkForExternalText();
     
    940940};
    941941
    942 // Delayed observer, like Form.Element.Observer, 
     942// Delayed observer, like Form.Element.Observer,
    943943// but waits for delay after last key input
    944944// Ideal for live-search fields
     
    950950    this.callback  = callback;
    951951    this.timer     = null;
    952     this.lastValue = $F(this.element); 
     952    this.lastValue = $F(this.element);
    953953    Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
    954954  },
  • trunk/wp-includes/js/scriptaculous/dragdrop.js

    r7131 r12557  
    1 // script.aculo.us dragdrop.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007
    2 
    3 // Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
    4 //           (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
    5 //
     1// script.aculo.us dragdrop.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
     2
     3// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
     4//
    65// script.aculo.us is freely distributable under the terms of an MIT-style license.
    76// For details, see the script.aculo.us web site: http://script.aculo.us/
     
    3534      }
    3635    }
    37    
     36
    3837    if(options.accept) options.accept = [options.accept].flatten();
    3938
     
    4342    this.drops.push(options);
    4443  },
    45  
     44
    4645  findDeepestChild: function(drops) {
    4746    deepest = drops[0];
    48      
     47
    4948    for (i = 1; i < drops.length; ++i)
    5049      if (Element.isParent(drops[i].element, deepest.element))
    5150        deepest = drops[i];
    52    
     51
    5352    return deepest;
    5453  },
     
    5756    var containmentNode;
    5857    if(drop.tree) {
    59       containmentNode = element.treeNode; 
     58      containmentNode = element.treeNode;
    6059    } else {
    6160      containmentNode = element.parentNode;
     
    6362    return drop._containers.detect(function(c) { return containmentNode == c });
    6463  },
    65  
     64
    6665  isAffected: function(point, element, drop) {
    6766    return (
     
    7069        this.isContained(element, drop)) &&
    7170      ((!drop.accept) ||
    72         (Element.classNames(element).detect( 
     71        (Element.classNames(element).detect(
    7372          function(v) { return drop.accept.include(v) } ) )) &&
    7473      Position.within(drop.element, point[0], point[1]) );
     
    9089    if(!this.drops.length) return;
    9190    var drop, affected = [];
    92    
     91
    9392    this.drops.each( function(drop) {
    9493      if(Droppables.isAffected(point, element, drop))
    9594        affected.push(drop);
    9695    });
    97        
     96
    9897    if(affected.length>0)
    9998      drop = Droppables.findDeepestChild(affected);
     
    104103      if(drop.onHover)
    105104        drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
    106      
     105
    107106      if (drop != this.last_active) Droppables.activate(drop);
    108107    }
     
    115114    if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
    116115      if (this.last_active.onDrop) {
    117         this.last_active.onDrop(element, this.last_active.element, event); 
    118         return true; 
     116        this.last_active.onDrop(element, this.last_active.element, event);
     117        return true;
    119118      }
    120119  },
     
    124123      this.deactivate(this.last_active);
    125124  }
    126 }
     125};
    127126
    128127var Draggables = {
    129128  drags: [],
    130129  observers: [],
    131  
     130
    132131  register: function(draggable) {
    133132    if(this.drags.length == 0) {
     
    135134      this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
    136135      this.eventKeypress  = this.keyPress.bindAsEventListener(this);
    137      
     136
    138137      Event.observe(document, "mouseup", this.eventMouseUp);
    139138      Event.observe(document, "mousemove", this.eventMouseMove);
     
    142141    this.drags.push(draggable);
    143142  },
    144  
     143
    145144  unregister: function(draggable) {
    146145    this.drags = this.drags.reject(function(d) { return d==draggable });
     
    151150    }
    152151  },
    153  
     152
    154153  activate: function(draggable) {
    155     if(draggable.options.delay) { 
    156       this._timeout = setTimeout(function() { 
    157         Draggables._timeout = null; 
    158         window.focus(); 
    159         Draggables.activeDraggable = draggable; 
    160       }.bind(this), draggable.options.delay); 
     154    if(draggable.options.delay) {
     155      this._timeout = setTimeout(function() {
     156        Draggables._timeout = null;
     157        window.focus();
     158        Draggables.activeDraggable = draggable;
     159      }.bind(this), draggable.options.delay);
    161160    } else {
    162161      window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
     
    164163    }
    165164  },
    166  
     165
    167166  deactivate: function() {
    168167    this.activeDraggable = null;
    169168  },
    170  
     169
    171170  updateDrag: function(event) {
    172171    if(!this.activeDraggable) return;
     
    176175    if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
    177176    this._lastPointer = pointer;
    178    
     177
    179178    this.activeDraggable.updateDrag(event, pointer);
    180179  },
    181  
     180
    182181  endDrag: function(event) {
    183     if(this._timeout) { 
    184       clearTimeout(this._timeout); 
    185       this._timeout = null; 
     182    if(this._timeout) {
     183      clearTimeout(this._timeout);
     184      this._timeout = null;
    186185    }
    187186    if(!this.activeDraggable) return;
     
    190189    this.activeDraggable = null;
    191190  },
    192  
     191
    193192  keyPress: function(event) {
    194193    if(this.activeDraggable)
    195194      this.activeDraggable.keyPress(event);
    196195  },
    197  
     196
    198197  addObserver: function(observer) {
    199198    this.observers.push(observer);
    200199    this._cacheObserverCallbacks();
    201200  },
    202  
     201
    203202  removeObserver: function(element) {  // element instead of observer fixes mem leaks
    204203    this.observers = this.observers.reject( function(o) { return o.element==element });
    205204    this._cacheObserverCallbacks();
    206205  },
    207  
     206
    208207  notify: function(eventName, draggable, event) {  // 'onStart', 'onEnd', 'onDrag'
    209208    if(this[eventName+'Count'] > 0)
     
    213212    if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
    214213  },
    215  
     214
    216215  _cacheObserverCallbacks: function() {
    217216    ['onStart','onEnd','onDrag'].each( function(eventName) {
     
    221220    });
    222221  }
    223 }
     222};
    224223
    225224/*--------------------------------------------------------------------------*/
     
    237236      endeffect: function(element) {
    238237        var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0;
    239         new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity, 
     238        new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
    240239          queue: {scope:'_draggable', position:'end'},
    241           afterFinish: function(){ 
    242             Draggable._dragging[element] = false 
     240          afterFinish: function(){
     241            Draggable._dragging[element] = false
    243242          }
    244         }); 
     243        });
    245244      },
    246245      zindex: 1000,
     
    253252      delay: 0
    254253    };
    255    
     254
    256255    if(!arguments[1] || Object.isUndefined(arguments[1].endeffect))
    257256      Object.extend(defaults, {
     
    259258          element._opacity = Element.getOpacity(element);
    260259          Draggable._dragging[element] = true;
    261           new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); 
     260          new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
    262261        }
    263262      });
    264    
     263
    265264    var options = Object.extend(defaults, arguments[1] || { });
    266265
    267266    this.element = $(element);
    268    
     267
    269268    if(options.handle && Object.isString(options.handle))
    270269      this.handle = this.element.down('.'+options.handle, 0);
    271    
     270
    272271    if(!this.handle) this.handle = $(options.handle);
    273272    if(!this.handle) this.handle = this.element;
    274    
     273
    275274    if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
    276275      options.scroll = $(options.scroll);
     
    278277    }
    279278
    280     Element.makePositioned(this.element); // fix IE   
     279    Element.makePositioned(this.element); // fix IE
    281280
    282281    this.options  = options;
    283     this.dragging = false;   
     282    this.dragging = false;
    284283
    285284    this.eventMouseDown = this.initDrag.bindAsEventListener(this);
    286285    Event.observe(this.handle, "mousedown", this.eventMouseDown);
    287    
     286
    288287    Draggables.register(this);
    289288  },
    290  
     289
    291290  destroy: function() {
    292291    Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
    293292    Draggables.unregister(this);
    294293  },
    295  
     294
    296295  currentDelta: function() {
    297296    return([
     
    299298      parseInt(Element.getStyle(this.element,'top') || '0')]);
    300299  },
    301  
     300
    302301  initDrag: function(event) {
    303302    if(!Object.isUndefined(Draggable._dragging[this.element]) &&
    304303      Draggable._dragging[this.element]) return;
    305     if(Event.isLeftClick(event)) {   
     304    if(Event.isLeftClick(event)) {
    306305      // abort on form elements, fixes a Firefox issue
    307306      var src = Event.element(event);
     
    312311        tag_name=='BUTTON' ||
    313312        tag_name=='TEXTAREA')) return;
    314        
     313
    315314      var pointer = [Event.pointerX(event), Event.pointerY(event)];
    316       var pos     = Position.cumulativeOffset(this.element);
     315      var pos     = this.element.cumulativeOffset();
    317316      this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
    318      
     317
    319318      Draggables.activate(this);
    320319      Event.stop(event);
    321320    }
    322321  },
    323  
     322
    324323  startDrag: function(event) {
    325324    this.dragging = true;
    326325    if(!this.delta)
    327326      this.delta = this.currentDelta();
    328    
     327
    329328    if(this.options.zindex) {
    330329      this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
    331330      this.element.style.zIndex = this.options.zindex;
    332331    }
    333    
     332
    334333    if(this.options.ghosting) {
    335334      this._clone = this.element.cloneNode(true);
    336       this.element._originallyAbsolute = (this.element.getStyle('position') == 'absolute');
    337       if (!this.element._originallyAbsolute)
     335      this._originallyAbsolute = (this.element.getStyle('position') == 'absolute');
     336      if (!this._originallyAbsolute)
    338337        Position.absolutize(this.element);
    339338      this.element.parentNode.insertBefore(this._clone, this.element);
    340339    }
    341    
     340
    342341    if(this.options.scroll) {
    343342      if (this.options.scroll == window) {
     
    350349      }
    351350    }
    352    
     351
    353352    Draggables.notify('onStart', this, event);
    354        
     353
    355354    if(this.options.starteffect) this.options.starteffect(this.element);
    356355  },
    357  
     356
    358357  updateDrag: function(event, pointer) {
    359358    if(!this.dragging) this.startDrag(event);
    360    
     359
    361360    if(!this.options.quiet){
    362361      Position.prepare();
    363362      Droppables.show(pointer, this.element);
    364363    }
    365    
     364
    366365    Draggables.notify('onDrag', this, event);
    367    
     366
    368367    this.draw(pointer);
    369368    if(this.options.change) this.options.change(this);
    370    
     369
    371370    if(this.options.scroll) {
    372371      this.stopScrolling();
    373      
     372
    374373      var p;
    375374      if (this.options.scroll == window) {
     
    389388      this.startScrolling(speed);
    390389    }
    391    
     390
    392391    // fix AppleWebKit rendering
    393392    if(Prototype.Browser.WebKit) window.scrollBy(0,0);
    394    
     393
    395394    Event.stop(event);
    396395  },
    397  
     396
    398397  finishDrag: function(event, success) {
    399398    this.dragging = false;
    400    
     399
    401400    if(this.options.quiet){
    402401      Position.prepare();
     
    406405
    407406    if(this.options.ghosting) {
    408       if (!this.element._originallyAbsolute)
     407      if (!this._originallyAbsolute)
    409408        Position.relativize(this.element);
    410       delete this.element._originallyAbsolute;
     409      delete this._originallyAbsolute;
    411410      Element.remove(this._clone);
    412411      this._clone = null;
    413412    }
    414413
    415     var dropped = false; 
    416     if(success) { 
    417       dropped = Droppables.fire(event, this.element); 
    418       if (!dropped) dropped = false; 
     414    var dropped = false;
     415    if(success) {
     416      dropped = Droppables.fire(event, this.element);
     417      if (!dropped) dropped = false;
    419418    }
    420419    if(dropped && this.options.onDropped) this.options.onDropped(this.element);
     
    423422    var revert = this.options.revert;
    424423    if(revert && Object.isFunction(revert)) revert = revert(this.element);
    425    
     424
    426425    var d = this.currentDelta();
    427426    if(revert && this.options.reverteffect) {
     
    436435      this.element.style.zIndex = this.originalZ;
    437436
    438     if(this.options.endeffect) 
     437    if(this.options.endeffect)
    439438      this.options.endeffect(this.element);
    440      
     439
    441440    Draggables.deactivate(this);
    442441    Droppables.reset();
    443442  },
    444  
     443
    445444  keyPress: function(event) {
    446445    if(event.keyCode!=Event.KEY_ESC) return;
     
    448447    Event.stop(event);
    449448  },
    450  
     449
    451450  endDrag: function(event) {
    452451    if(!this.dragging) return;
     
    455454    Event.stop(event);
    456455  },
    457  
     456
    458457  draw: function(point) {
    459     var pos = Position.cumulativeOffset(this.element);
     458    var pos = this.element.cumulativeOffset();
    460459    if(this.options.ghosting) {
    461460      var r   = Position.realOffset(this.element);
    462461      pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
    463462    }
    464    
     463
    465464    var d = this.currentDelta();
    466465    pos[0] -= d[0]; pos[1] -= d[1];
    467    
     466
    468467    if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
    469468      pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
    470469      pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
    471470    }
    472    
    473     var p = [0,1].map(function(i){ 
    474       return (point[i]-pos[i]-this.offset[i]) 
     471
     472    var p = [0,1].map(function(i){
     473      return (point[i]-pos[i]-this.offset[i])
    475474    }.bind(this));
    476    
     475
    477476    if(this.options.snap) {
    478477      if(Object.isFunction(this.options.snap)) {
     
    481480      if(Object.isArray(this.options.snap)) {
    482481        p = p.map( function(v, i) {
    483           return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this))
     482          return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this));
    484483      } else {
    485484        p = p.map( function(v) {
    486           return (v/this.options.snap).round()*this.options.snap }.bind(this))
     485          return (v/this.options.snap).round()*this.options.snap }.bind(this));
    487486      }
    488487    }}
    489    
     488
    490489    var style = this.element.style;
    491490    if((!this.options.constraint) || (this.options.constraint=='horizontal'))
     
    493492    if((!this.options.constraint) || (this.options.constraint=='vertical'))
    494493      style.top  = p[1] + "px";
    495    
     494
    496495    if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
    497496  },
    498  
     497
    499498  stopScrolling: function() {
    500499    if(this.scrollInterval) {
     
    504503    }
    505504  },
    506  
     505
    507506  startScrolling: function(speed) {
    508507    if(!(speed[0] || speed[1])) return;
     
    511510    this.scrollInterval = setInterval(this.scroll.bind(this), 10);
    512511  },
    513  
     512
    514513  scroll: function() {
    515514    var current = new Date();
     
    527526      this.options.scroll.scrollTop  += this.scrollSpeed[1] * delta / 1000;
    528527    }
    529    
     528
    530529    Position.prepare();
    531530    Droppables.show(Draggables._lastPointer, this.element);
     
    541540      this.draw(Draggables._lastScrollPointer);
    542541    }
    543    
     542
    544543    if(this.options.change) this.options.change(this);
    545544  },
    546  
     545
    547546  _getWindowScroll: function(w) {
    548547    var T, L, W, H;
     
    563562      } else {
    564563        W = body.offsetWidth;
    565         H = body.offsetHeight
     564        H = body.offsetHeight;
    566565      }
    567566    }
     
    580579    this.lastValue = Sortable.serialize(this.element);
    581580  },
    582  
     581
    583582  onStart: function() {
    584583    this.lastValue = Sortable.serialize(this.element);
    585584  },
    586  
     585
    587586  onEnd: function() {
    588587    Sortable.unmark();
     
    594593var Sortable = {
    595594  SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
    596  
     595
    597596  sortables: { },
    598  
     597
    599598  _findRootElement: function(element) {
    600     while (element.tagName.toUpperCase() != "BODY") { 
     599    while (element.tagName.toUpperCase() != "BODY") {
    601600      if(element.id && Sortable.sortables[element.id]) return element;
    602601      element = element.parentNode;
     
    609608    return Sortable.sortables[element.id];
    610609  },
    611  
     610
    612611  destroy: function(element){
    613     var s = Sortable.options(element);
    614    
     612    element = $(element);
     613    var s = Sortable.sortables[element.id];
     614
    615615    if(s) {
    616616      Draggables.removeObserver(s.element);
    617617      s.droppables.each(function(d){ Droppables.remove(d) });
    618618      s.draggables.invoke('destroy');
    619      
     619
    620620      delete Sortable.sortables[s.element.id];
    621621    }
     
    624624  create: function(element) {
    625625    element = $(element);
    626     var options = Object.extend({ 
     626    var options = Object.extend({
    627627      element:     element,
    628628      tag:         'li',       // assumes li children, override with tag: 'tagname'
     
    638638      hoverclass:  null,
    639639      ghosting:    false,
    640       quiet:       false, 
     640      quiet:       false,
    641641      scroll:      false,
    642642      scrollSensitivity: 20,
    643643      scrollSpeed: 15,
    644644      format:      this.SERIALIZE_RULE,
    645      
    646       // these take arrays of elements or ids and can be 
     645
     646      // these take arrays of elements or ids and can be
    647647      // used for better initialization performance
    648648      elements:    false,
    649649      handles:     false,
    650      
     650
    651651      onChange:    Prototype.emptyFunction,
    652652      onUpdate:    Prototype.emptyFunction
     
    685685      options_for_draggable.zindex = options.zindex;
    686686
    687     // build options for the droppables 
     687    // build options for the droppables
    688688    var options_for_droppable = {
    689689      overlap:     options.overlap,
     
    692692      hoverclass:  options.hoverclass,
    693693      onHover:     Sortable.onHover
    694     }
    695    
     694    };
     695
    696696    var options_for_tree = {
    697697      onHover:      Sortable.onEmptyHover,
     
    699699      containment:  options.containment,
    700700      hoverclass:   options.hoverclass
    701     }
     701    };
    702702
    703703    // fix for gecko engine
    704     Element.cleanWhitespace(element); 
     704    Element.cleanWhitespace(element);
    705705
    706706    options.draggables = [];
     
    715715    (options.elements || this.findElements(element, options