You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2008/02/11 20:46:23 UTC

svn commit: r620593 - /tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/scriptaculous_1_8/prototype.js

Author: hlship
Date: Mon Feb 11 11:46:21 2008
New Revision: 620593

URL: http://svn.apache.org/viewvc?rev=620593&view=rev
Log:
TAPESTRY-2144: Upgrade to Prototype 1.6.0.2

Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/scriptaculous_1_8/prototype.js

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/scriptaculous_1_8/prototype.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/scriptaculous_1_8/prototype.js?rev=620593&r1=620592&r2=620593&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/scriptaculous_1_8/prototype.js (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/scriptaculous_1_8/prototype.js Mon Feb 11 11:46:21 2008
@@ -1,5 +1,5 @@
-/*  Prototype JavaScript framework, version 1.6.0
- *  (c) 2005-2007 Sam Stephenson
+/*  Prototype JavaScript framework, version 1.6.0.2
+ *  (c) 2005-2008 Sam Stephenson
  *
  *  Prototype is freely distributable under the terms of an MIT-style license.
  *  For details, see the Prototype web site: http://www.prototypejs.org/
@@ -7,7 +7,7 @@
  *--------------------------------------------------------------------------*/
 
 var Prototype = {
-    Version: '1.6.0',
+    Version: '1.6.0.2',
 
     Browser: {
         IE:     !!(window.attachEvent && !window.opera),
@@ -41,8 +41,6 @@
 if (Prototype.Browser.MobileSafari)
     Prototype.BrowserFeatures.SpecificElementExtensions = false;
 
-if (Prototype.Browser.WebKit)
-    Prototype.BrowserFeatures.XPath = false;
 
 /* Based on Alex Arnell's inheritance implementation. */
 var Class = {
@@ -136,9 +134,9 @@
     {
         try
         {
-            if (object === undefined) return 'undefined';
+            if (Object.isUndefined(object)) return 'undefined';
             if (object === null) return 'null';
-            return object.inspect ? object.inspect() : object.toString();
+            return object.inspect ? object.inspect() : String(object);
         }
         catch (e)
         {
@@ -166,7 +164,7 @@
         for (var property in object)
         {
             var value = Object.toJSON(object[property]);
-            if (value !== undefined)
+            if (!Object.isUndefined(value))
                 results.push(property.toJSON() + ': ' + value);
         }
 
@@ -211,7 +209,8 @@
 
     isArray: function(object)
     {
-        return object && object.constructor === Array;
+        return object != null && typeof object == "object" &&
+               'splice' in object && 'join' in object;
     },
 
     isHash: function(object)
@@ -249,7 +248,7 @@
 
     bind: function()
     {
-        if (arguments.length < 2 && arguments[0] === undefined) return this;
+        if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
         var __method = this, args = $A(arguments), object = args.shift();
         return function()
         {
@@ -431,7 +430,7 @@
     sub: function(pattern, replacement, count)
     {
         replacement = this.gsub.prepareReplacement(replacement);
-        count = count === undefined ? 1 : count;
+        count = Object.isUndefined(count) ? 1 : count;
 
         return this.gsub(pattern, function(match)
         {
@@ -449,7 +448,7 @@
     truncate: function(length, truncation)
     {
         length = length || 30;
-        truncation = truncation === undefined ? '...' : truncation;
+        truncation = Object.isUndefined(truncation) ? '...' : truncation;
         return this.length > length ?
                this.slice(0, length - truncation.length) + truncation : String(this);
     },
@@ -599,7 +598,9 @@
 
     isJSON: function()
     {
-        var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
+        var str = this;
+        if (str.blank()) return false;
+        str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
         return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
     },
 
@@ -698,7 +699,8 @@
             if (before == '\\') return match[2];
 
             var ctx = object, expr = match[3];
-            var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/, match = pattern.exec(expr);
+            var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
+            match = pattern.exec(expr);
             if (match == null) return before;
 
             while (match != null)
@@ -711,7 +713,7 @@
             }
 
             return before + String.interpret(ctx);
-        }.bind(this));
+        });
     }
 });
 Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
@@ -843,7 +845,7 @@
 
     inGroupsOf: function(number, fillWith)
     {
-        fillWith = fillWith === undefined ? null : fillWith;
+        fillWith = Object.isUndefined(fillWith) ? null : fillWith;
         return this.eachSlice(number, function(slice)
         {
             while (slice.length < number) slice.push(fillWith);
@@ -877,7 +879,7 @@
         this.each(function(value, index)
         {
             value = iterator(value, index);
-            if (result == undefined || value >= result)
+            if (result == null || value >= result)
                 result = value;
         });
         return result;
@@ -890,7 +892,7 @@
         this.each(function(value, index)
         {
             value = iterator(value, index);
-            if (result == undefined || value < result)
+            if (result == null || value < result)
                 result = value;
         });
         return result;
@@ -986,22 +988,22 @@
 {
     if (!iterable) return [];
     if (iterable.toArray) return iterable.toArray();
-    var length = iterable.length, results = new Array(length);
+    var length = iterable.length || 0, results = new Array(length);
     while (length--) results[length] = iterable[length];
     return results;
 }
 
 if (Prototype.Browser.WebKit)
 {
-    function $A(iterable)
+    $A = function(iterable)
     {
         if (!iterable) return [];
         if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
             iterable.toArray) return iterable.toArray();
-        var length = iterable.length, results = new Array(length);
+        var length = iterable.length || 0, results = new Array(length);
         while (length--) results[length] = iterable[length];
         return results;
-    }
+    };
 }
 
 Array.from = $A;
@@ -1111,7 +1113,7 @@
         this.each(function(object)
         {
             var value = Object.toJSON(object);
-            if (value !== undefined) results.push(value);
+            if (!Object.isUndefined(value)) results.push(value);
         });
         return '[' + results.join(', ') + ']';
     }
@@ -1209,45 +1211,6 @@
 
 var Hash = Class.create(Enumerable, (function()
 {
-    if (function()
-    {
-        var i = 0, Test = function(value)
-        {
-            this.key = value
-        };
-        Test.prototype.key = 'foo';
-        for (var property in new Test('bar')) i++;
-        return i > 1;
-    }())
-    {
-        function each(iterator)
-        {
-            var cache = [];
-            for (var key in this._object)
-            {
-                var value = this._object[key];
-                if (cache.include(key)) continue;
-                cache.push(key);
-                var pair = [key, value];
-                pair.key = key;
-                pair.value = value;
-                iterator(pair);
-            }
-        }
-    }
-    else
-    {
-        function each(iterator)
-        {
-            for (var key in this._object)
-            {
-                var value = this._object[key], pair = [key, value];
-                pair.key = key;
-                pair.value = value;
-                iterator(pair);
-            }
-        }
-    }
 
     function toQueryPair(key, value)
     {
@@ -1261,7 +1224,16 @@
             this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
         },
 
-        _each: each,
+        _each: function(iterator)
+        {
+            for (var key in this._object)
+            {
+                var value = this._object[key], pair = [key, value];
+                pair.key = key;
+                pair.value = value;
+                iterator(pair);
+            }
+        },
 
         set: function(key, value)
         {
@@ -1475,8 +1447,11 @@
         Object.extend(this.options, options || { });
 
         this.options.method = this.options.method.toLowerCase();
+
         if (Object.isString(this.options.parameters))
             this.options.parameters = this.options.parameters.toQueryParams();
+        else if (Object.isHash(this.options.parameters))
+            this.options.parameters = this.options.parameters.toObject();
     }
 });
 
@@ -1628,7 +1603,7 @@
 
             var contentType = response.getHeader('Content-type');
             if (this.options.evalJS == 'force'
-                    || (this.options.evalJS && contentType
+                    || (this.options.evalJS && this.isSameOrigin() && contentType
                     && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
                 this.evalResponse();
         }
@@ -1650,11 +1625,21 @@
         }
     },
 
+    isSameOrigin: function()
+    {
+        var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
+        return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
+            protocol: location.protocol,
+            domain: document.domain,
+            port: location.port ? ':' + location.port : ''
+        }));
+    },
+
     getHeader: function(name)
     {
         try
         {
-            return this.transport.getResponseHeader(name);
+            return this.transport.getResponseHeader(name) || null;
         }
         catch (e)
         {
@@ -1702,7 +1687,7 @@
         if (readyState == 4)
         {
             var xml = transport.responseXML;
-            this.responseXML = xml === undefined ? null : xml;
+            this.responseXML = Object.isUndefined(xml) ? null : xml;
             this.responseJSON = this._getResponseJSON();
         }
     },
@@ -1755,7 +1740,8 @@
         json = decodeURIComponent(escape(json));
         try
         {
-            return json.evalJSON(this.request.options.sanitizeJSON);
+            return json.evalJSON(this.request.options.sanitizeJSON ||
+                                 !this.request.isSameOrigin());
         }
         catch (e)
         {
@@ -1767,11 +1753,13 @@
     {
         var options = this.request.options;
         if (!options.evalJSON || (options.evalJSON != 'force' &&
-                                  !(this.getHeader('Content-type') || '').include('application/json')))
+                                  !(this.getHeader('Content-type') || '').include('application/json')) ||
+            this.responseText.blank())
             return null;
         try
         {
-            return this.transport.responseText.evalJSON(options.sanitizeJSON);
+            return this.responseText.evalJSON(options.sanitizeJSON ||
+                                              !this.request.isSameOrigin());
         }
         catch (e)
         {
@@ -1788,12 +1776,12 @@
             failure: (container.failure || (container.success ? null : container))
         };
 
-        options = options || { };
+        options = Object.clone(options);
         var onComplete = options.onComplete;
-        options.onComplete = (function(response, param)
+        options.onComplete = (function(response, json)
         {
             this.updateContent(response.responseText);
-            if (Object.isFunction(onComplete)) onComplete(response, param);
+            if (Object.isFunction(onComplete)) onComplete(response, json);
         }).bind(this);
 
         $super(url, options);
@@ -1820,11 +1808,6 @@
             }
             else receiver.update(responseText);
         }
-
-        if (this.success())
-        {
-            if (this.onComplete) this.onComplete.bind(this).defer();
-        }
     }
 });
 
@@ -2012,26 +1995,30 @@
             Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
             insertions = {bottom:insertions};
 
-        var content, t, range;
+        var content, insert, tagName, childNodes;
 
-        for (position in insertions)
+        for (var position in insertions)
         {
             content = insertions[position];
             position = position.toLowerCase();
-            t = Element._insertionTranslations[position];
+            insert = Element._insertionTranslations[position];
 
             if (content && content.toElement) content = content.toElement();
             if (Object.isElement(content))
             {
-                t.insert(element, content);
+                insert(element, content);
                 continue;
             }
 
             content = Object.toHTML(content);
 
-            range = element.ownerDocument.createRange();
-            t.initializeRange(element, range);
-            t.insert(element, range.createContextualFragment(content.stripScripts()));
+            tagName = ((position == 'before' || position == 'after')
+                    ? element.parentNode : element).tagName.toUpperCase();
+
+            childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
+
+            if (position == 'top' || position == 'after') childNodes.reverse();
+            childNodes.each(insert.curry(element));
 
             content.evalScripts.bind(content).defer();
         }
@@ -2082,7 +2069,7 @@
 
     descendants: function(element)
     {
-        return $A($(element).getElementsByTagName('*')).each(Element.extend);
+        return $(element).select("*");
     },
 
     firstDescendant: function(element)
@@ -2128,17 +2115,16 @@
         element = $(element);
         if (arguments.length == 1) return $(element.parentNode);
         var ancestors = element.ancestors();
-        return expression ? Selector.findElement(ancestors, expression, index) :
-               ancestors[index || 0];
+        return Object.isNumber(expression) ? ancestors[expression] :
+               Selector.findElement(ancestors, expression, index);
     },
 
     down: function(element, expression, index)
     {
         element = $(element);
         if (arguments.length == 1) return element.firstDescendant();
-        var descendants = element.descendants();
-        return expression ? Selector.findElement(descendants, expression, index) :
-               descendants[index || 0];
+        return Object.isNumber(expression) ? element.descendants()[expression] :
+               element.select(expression)[index || 0];
     },
 
     previous: function(element, expression, index)
@@ -2146,8 +2132,8 @@
         element = $(element);
         if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
         var previousSiblings = element.previousSiblings();
-        return expression ? Selector.findElement(previousSiblings, expression, index) :
-               previousSiblings[index || 0];
+        return Object.isNumber(expression) ? previousSiblings[expression] :
+               Selector.findElement(previousSiblings, expression, index);
     },
 
     next: function(element, expression, index)
@@ -2155,8 +2141,8 @@
         element = $(element);
         if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
         var nextSiblings = element.nextSiblings();
-        return expression ? Selector.findElement(nextSiblings, expression, index) :
-               nextSiblings[index || 0];
+        return Object.isNumber(expression) ? nextSiblings[expression] :
+               Selector.findElement(nextSiblings, expression, index);
     },
 
     select: function()
@@ -2206,11 +2192,12 @@
         var attributes = { }, t = Element._attributeTranslations.write;
 
         if (typeof name == 'object') attributes = name;
-        else attributes[name] = value === undefined ? true : value;
+        else attributes[name] = Object.isUndefined(value) ? true : value;
 
         for (var attr in attributes)
         {
-            var name = t.names[attr] || attr, value = attributes[attr];
+            name = t.names[attr] || attr;
+            value = attributes[attr];
             if (t.values[attr]) name = t.values[attr](element, value);
             if (value === false || value === null)
                 element.removeAttribute(name);
@@ -2267,7 +2254,7 @@
                        'removeClassName' : 'addClassName'](className);
     },
 
-// removes whitespace-only text node children
+    // removes whitespace-only text node children
     cleanWhitespace: function(element)
     {
         element = $(element);
@@ -2290,6 +2277,7 @@
     descendantOf: function(element, ancestor)
     {
         element = $(element),ancestor = $(ancestor);
+        var originalAncestor = ancestor;
 
         if (element.compareDocumentPosition)
             return (element.compareDocumentPosition(ancestor) & 8) === 8;
@@ -2305,11 +2293,12 @@
                 }
                 while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);
             }
-            if (nextAncestor) return (e > a && e < nextAncestor.sourceIndex);
+            if (nextAncestor && nextAncestor.sourceIndex)
+                return (e > a && e < nextAncestor.sourceIndex);
         }
 
         while (element = element.parentNode)
-            if (element == ancestor) return true;
+            if (element == originalAncestor) return true;
         return false;
     },
 
@@ -2354,7 +2343,7 @@
             if (property == 'opacity') element.setOpacity(styles[property]);
             else
                 elementStyle[(property == 'float' || property == 'cssFloat') ?
-                             (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
+                             (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
                              property] = styles[property];
 
         return element;
@@ -2467,7 +2456,7 @@
             {
                 if (element.tagName == 'BODY') break;
                 var p = Element.getStyle(element, 'position');
-                if (p == 'relative' || p == 'absolute') break;
+                if (p !== 'static') break;
             }
         } while (element);
         return Element._returnOffset(valueL, valueT);
@@ -2625,84 +2614,86 @@
     }
 };
 
-
-if (!document.createRange || Prototype.Browser.Opera)
+if (Prototype.Browser.Opera)
 {
-    Element.Methods.insert = function(element, insertions)
-    {
-        element = $(element);
-
-        if (Object.isString(insertions) || Object.isNumber(insertions) ||
-            Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
-            insertions = { bottom: insertions };
+    Element.Methods.getStyle = Element.Methods.getStyle.wrap(
+            function(proceed, element, style)
+            {
+                switch (style)
+                        {
+                    case 'left': case 'top': case 'right': case 'bottom':
+                    if (proceed(element, 'position') === 'static') return null;
+                    case 'height': case 'width':
+                // returns '0px' for hidden elements; we want it to return null
+                    if (!Element.visible(element)) return null;
+
+                // returns the border-box dimensions rather than the content-box
+                // dimensions, so we subtract padding and borders from the value
+                    var dim = parseInt(proceed(element, style), 10);
 
-        var t = Element._insertionTranslations, content, position, pos, tagName;
+                    if (dim !== element['offset' + style.capitalize()])
+                        return dim + 'px';
 
-        for (position in insertions)
-        {
-            content = insertions[position];
-            position = position.toLowerCase();
-            pos = t[position];
-
-            if (content && content.toElement) content = content.toElement();
-            if (Object.isElement(content))
-            {
-                pos.insert(element, content);
-                continue;
+                    var properties;
+                    if (style === 'height')
+                    {
+                        properties = ['border-top-width', 'padding-top',
+                            'padding-bottom', 'border-bottom-width'];
+                    }
+                    else
+                    {
+                        properties = ['border-left-width', 'padding-left',
+                            'padding-right', 'border-right-width'];
+                    }
+                    return properties.inject(dim, function(memo, property)
+                    {
+                        var val = proceed(element, property);
+                        return val === null ? memo : memo - parseInt(val, 10);
+                    }) + 'px';
+                    default: return proceed(element, style);
+                }
             }
+            );
 
-            content = Object.toHTML(content);
-            tagName = ((position == 'before' || position == 'after')
-                    ? element.parentNode : element).tagName.toUpperCase();
-
-            if (t.tags[tagName])
+    Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
+            function(proceed, element, attribute)
             {
-                var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
-                if (position == 'top' || position == 'after') fragments.reverse();
-                fragments.each(pos.insert.curry(element));
+                if (attribute === 'title') return element.title;
+                return proceed(element, attribute);
             }
-            else element.insertAdjacentHTML(pos.adjacency, content.stripScripts());
-
-            content.evalScripts.bind(content).defer();
-        }
-
-        return element;
-    };
-}
-
-if (Prototype.Browser.Opera)
-{
-    Element.Methods._getStyle = Element.Methods.getStyle;
-    Element.Methods.getStyle = function(element, style)
-    {
-        switch (style)
-                {
-            case 'left':
-            case 'top':
-            case 'right':
-            case 'bottom':
-                if (Element._getStyle(element, 'position') == 'static') return null;
-            default: return Element._getStyle(element, style);
-        }
-    };
-    Element.Methods._readAttribute = Element.Methods.readAttribute;
-    Element.Methods.readAttribute = function(element, attribute)
-    {
-        if (attribute == 'title') return element.title;
-        return Element._readAttribute(element, attribute);
-    };
+            );
 }
 
 else if (Prototype.Browser.IE)
 {
-    $w('positionedOffset getOffsetParent viewportOffset').each(function(method)
+    // IE doesn't report offsets correctly for static elements, so we change them
+    // to "relative" to get the values, then change them back.
+    Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
+            function(proceed, element)
+            {
+                element = $(element);
+                var position = element.getStyle('position');
+                if (position !== 'static') return proceed(element);
+                element.setStyle({ position: 'relative' });
+                var value = proceed(element);
+                element.setStyle({ position: position });
+                return value;
+            }
+            );
+
+    $w('positionedOffset viewportOffset').each(function(method)
     {
         Element.Methods[method] = Element.Methods[method].wrap(
                 function(proceed, element)
                 {
                     element = $(element);
                     var position = element.getStyle('position');
-                    if (position != 'static') return proceed(element);
+                    if (position !== 'static') return proceed(element);
+        // Trigger hasLayout on the offset parent so that IE6 reports
+                    // accurate offsetTop and offsetLeft values for position: fixed.
+                    var offsetParent = element.getOffsetParent();
+                    if (offsetParent && offsetParent.getStyle('position') === 'fixed')
+                        offsetParent.setStyle({ zoom: 1 });
                     element.setStyle({ position: 'relative' });
                     var value = proceed(element);
                     element.setStyle({ position: position });
@@ -2777,7 +2768,7 @@
                 },
                 _getEv: function(element, attribute)
                 {
-                    var attribute = element.getAttribute(attribute);
+                    attribute = element.getAttribute(attribute);
                     return attribute ? attribute.toString().slice(23, -2) : null;
                 },
                 _flag: function(element, attribute)
@@ -2797,7 +2788,10 @@
     };
 
     Element._attributeTranslations.write = {
-        names: Object.clone(Element._attributeTranslations.read.names),
+        names: Object.extend({
+            cellpadding: 'cellPadding',
+            cellspacing: 'cellSpacing'
+        }, Element._attributeTranslations.read.names),
         values: {
             checked: function(element, value)
             {
@@ -2892,7 +2886,7 @@
     };
 
   // Safari returns margins on body which is incorrect if the child is absolutely
-    // positioned.  For performance reasons, redefine Position.cumulativeOffset for
+    // positioned.  For performance reasons, redefine Element#cumulativeOffset for
     // KHTML/WebKit only.
     Element.Methods.cumulativeOffset = function(element)
     {
@@ -2942,7 +2936,7 @@
     };
 }
 
-if (document.createElement('div').outerHTML)
+if ('outerHTML' in document.createElement('div'))
 {
     Element.Methods.replace = function(element, content)
     {
@@ -2992,55 +2986,34 @@
 Element._getContentFromAnonymousElement = function(tagName, html)
 {
     var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
-    div.innerHTML = t[0] + html + t[1];
-    t[2].times(function()
+    if (t)
     {
-        div = div.firstChild
-    });
+        div.innerHTML = t[0] + html + t[1];
+        t[2].times(function()
+        {
+            div = div.firstChild
+        });
+    }
+    else div.innerHTML = html;
     return $A(div.childNodes);
 };
 
 Element._insertionTranslations = {
-    before: {
-        adjacency: 'beforeBegin',
-        insert: function(element, node)
-        {
-            element.parentNode.insertBefore(node, element);
-        },
-        initializeRange: function(element, range)
-        {
-            range.setStartBefore(element);
-        }
+    before: function(element, node)
+    {
+        element.parentNode.insertBefore(node, element);
     },
-    top: {
-        adjacency: 'afterBegin',
-        insert: function(element, node)
-        {
-            element.insertBefore(node, element.firstChild);
-        },
-        initializeRange: function(element, range)
-        {
-            range.selectNodeContents(element);
-            range.collapse(true);
-        }
+    top: function(element, node)
+    {
+        element.insertBefore(node, element.firstChild);
     },
-    bottom: {
-        adjacency: 'beforeEnd',
-        insert: function(element, node)
-        {
-            element.appendChild(node);
-        }
+    bottom: function(element, node)
+    {
+        element.appendChild(node);
     },
-    after: {
-        adjacency: 'afterEnd',
-        insert: function(element, node)
-        {
-            element.parentNode.insertBefore(node, element.nextSibling);
-        },
-        initializeRange: function(element, range)
-        {
-            range.setStartAfter(element);
-        }
+    after: function(element, node)
+    {
+        element.parentNode.insertBefore(node, element.nextSibling);
     },
     tags: {
         TABLE:  ['<table>',                '</table>',                   1],
@@ -3053,7 +3026,6 @@
 
 (function()
 {
-    this.bottom.initializeRange = this.top.initializeRange;
     Object.extend(this.tags, {
         THEAD: this.tags.TBODY,
         TFOOT: this.tags.TBODY,
@@ -3234,11 +3206,12 @@
     getDimensions: function()
     {
         var dimensions = { };
+        var B = Prototype.Browser;
         $w('width height').each(function(d)
         {
             var D = d.capitalize();
-            dimensions[d] = self['inner' + D] ||
-                            (document.documentElement['client' + D] || document.body['client' + D]);
+            dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] :
+                            (B.Opera) ? document.body['client' + D] : document.documentElement['client' + D];
         });
         return dimensions;
     },
@@ -3271,10 +3244,28 @@
         this.compileMatcher();
     },
 
+    shouldUseXPath: function()
+    {
+        if (!Prototype.BrowserFeatures.XPath) return false;
+
+        var e = this.expression;
+
+    // Safari 3 chokes on :*-of-type and :empty
+        if (Prototype.Browser.WebKit &&
+            (e.include("-of-type") || e.include(":empty")))
+            return false;
+
+    // XPath can't do namespaced attributes, nor can it read
+        // the "checked" property from DOM nodes
+        if ((/(\[[\w-]*?:|:checked)/).test(this.expression))
+            return false;
+
+        return true;
+    },
+
     compileMatcher: function()
     {
-        // Selectors with namespaced attributes can't use the XPath version
-        if (Prototype.BrowserFeatures.XPath && !(/(\[[\w-]*?:|:checked)/).test(this.expression))
+        if (this.shouldUseXPath())
             return this.compileXPathMatcher();
 
         var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
@@ -3287,7 +3278,7 @@
         }
 
         this.matcher = ["this.matcher = function(root) {",
-                "var r = root, h = Selector.handlers, c = false, n;"];
+            "var r = root, h = Selector.handlers, c = false, n;"];
 
         while (e && le != e && (/\S/).test(e))
         {
@@ -3421,9 +3412,14 @@
         },
         className:    "[contains(concat(' ', @class, ' '), ' #{1} ')]",
         id:           "[@id='#{1}']",
-        attrPresence: "[@#{1}]",
+        attrPresence: function(m)
+        {
+            m[1] = m[1].toLowerCase();
+            return new Template("[@#{1}]").evaluate(m);
+        },
         attr: function(m)
         {
+            m[1] = m[1].toLowerCase();
             m[3] = m[5] || m[6];
             return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
         },
@@ -3454,7 +3450,7 @@
             'not': function(m)
             {
                 var e = m[6], p = Selector.patterns,
-                        x = Selector.xpath, le, m, v;
+                        x = Selector.xpath, le, v;
 
                 var exclusion = [];
                 while (e && le != e && (/\S/).test(e))
@@ -3526,14 +3522,14 @@
     },
 
     criteria: {
-        tagName:      'n = h.tagName(n, r, "#{1}", c);   c = false;',
-        className:    'n = h.className(n, r, "#{1}", c); c = false;',
-        id:           'n = h.id(n, r, "#{1}", c);        c = false;',
-        attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
+        tagName:      'n = h.tagName(n, r, "#{1}", c);      c = false;',
+        className:    'n = h.className(n, r, "#{1}", c);    c = false;',
+        id:           'n = h.id(n, r, "#{1}", c);           c = false;',
+        attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;',
         attr: function(m)
         {
             m[3] = (m[5] || m[6]);
-            return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
+            return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);
         },
         pseudo: function(m)
         {
@@ -3547,23 +3543,24 @@
     },
 
     patterns: {
-    // combinators must be listed first
-    // (and descendant needs to be last combinator)
+        // combinators must be listed first
+        // (and descendant needs to be last combinator)
         laterSibling: /^\s*~\s*/,
         child:        /^\s*>\s*/,
         adjacent:     /^\s*\+\s*/,
         descendant:   /^\s/,
 
-    // selectors follow
+        // selectors follow
         tagName:      /^\s*(\*|[\w\-]+)(\b|$)?/,
         id:           /^#([\w\-\*]+)(\b|$)/,
         className:    /^\.([\w\-\*]+)(\b|$)/,
-        pseudo:       /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s)|(?=:))/,
+        pseudo:
+                /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,
         attrPresence: /^\[([\w]+)\]/,
         attr:         /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
     },
 
-// for Selector.match and Element#match
+    // for Selector.match and Element#match
     assertions: {
         tagName: function(element, matches)
         {
@@ -3588,13 +3585,13 @@
         attr: function(element, matches)
         {
             var nodeValue = Element.readAttribute(element, matches[1]);
-            return Selector.operators[matches[2]](nodeValue, matches[3]);
+            return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);
         }
     },
 
     handlers: {
-    // UTILITY FUNCTIONS
-    // joins two collections
+        // UTILITY FUNCTIONS
+        // joins two collections
         concat: function(a, b)
         {
             for (var i = 0, node; node = b[i]; i++)
@@ -3602,57 +3599,58 @@
             return a;
         },
 
-    // marks an array of nodes for counting
+        // marks an array of nodes for counting
         mark: function(nodes)
         {
+            var _true = Prototype.emptyFunction;
             for (var i = 0, node; node = nodes[i]; i++)
-                node._counted = true;
+                node._countedByPrototype = _true;
             return nodes;
         },
 
         unmark: function(nodes)
         {
             for (var i = 0, node; node = nodes[i]; i++)
-                node._counted = undefined;
+                node._countedByPrototype = undefined;
             return nodes;
         },
 
-    // mark each child node with its position (for nth calls)
-    // "ofType" flag indicates whether we're indexing for nth-of-type
-    // rather than nth-child
+        // mark each child node with its position (for nth calls)
+        // "ofType" flag indicates whether we're indexing for nth-of-type
+        // rather than nth-child
         index: function(parentNode, reverse, ofType)
         {
-            parentNode._counted = true;
+            parentNode._countedByPrototype = Prototype.emptyFunction;
             if (reverse)
             {
                 for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--)
                 {
                     var node = nodes[i];
-                    if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
+                    if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
                 }
             }
             else
             {
                 for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
-                    if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
+                    if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
             }
         },
 
-    // filters out duplicates and extends all nodes
+        // filters out duplicates and extends all nodes
         unique: function(nodes)
         {
             if (nodes.length == 0) return nodes;
             var results = [], n;
             for (var i = 0, l = nodes.length; i < l; i++)
-                if (!(n = nodes[i])._counted)
+                if (!(n = nodes[i])._countedByPrototype)
                 {
-                    n._counted = true;
+                    n._countedByPrototype = Prototype.emptyFunction;
                     results.push(Element.extend(n));
                 }
             return Selector.handlers.unmark(results);
         },
 
-    // COMBINATOR FUNCTIONS
+        // COMBINATOR FUNCTIONS
         descendant: function(nodes)
         {
             var h = Selector.handlers;
@@ -3666,7 +3664,7 @@
             var h = Selector.handlers;
             for (var i = 0, results = [], node; node = nodes[i]; i++)
             {
-                for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
+                for (var j = 0, child; child = node.childNodes[j]; j++)
                     if (child.nodeType == 1 && child.tagName != '!') results.push(child);
             }
             return results;
@@ -3704,10 +3702,10 @@
             return null;
         },
 
-    // TOKEN FUNCTIONS
+        // TOKEN FUNCTIONS
         tagName: function(nodes, root, tagName, combinator)
         {
-            tagName = tagName.toUpperCase();
+            var uTagName = tagName.toUpperCase();
             var results = [], h = Selector.handlers;
             if (nodes)
             {
@@ -3724,7 +3722,7 @@
                     if (tagName == "*") return nodes;
                 }
                 for (var i = 0, node; node = nodes[i]; i++)
-                    if (node.tagName.toUpperCase() == tagName) results.push(node);
+                    if (node.tagName.toUpperCase() === uTagName) results.push(node);
                 return results;
             }
             else return root.getElementsByTagName(tagName);
@@ -3784,18 +3782,20 @@
             return results;
         },
 
-        attrPresence: function(nodes, root, attr)
+        attrPresence: function(nodes, root, attr, combinator)
         {
             if (!nodes) nodes = root.getElementsByTagName("*");
+            if (nodes && combinator) nodes = this[combinator](nodes);
             var results = [];
             for (var i = 0, node; node = nodes[i]; i++)
                 if (Element.hasAttribute(node, attr)) results.push(node);
             return results;
         },
 
-        attr: function(nodes, root, attr, value, operator)
+        attr: function(nodes, root, attr, value, operator, combinator)
         {
             if (!nodes) nodes = root.getElementsByTagName("*");
+            if (nodes && combinator) nodes = this[combinator](nodes);
             var handler = Selector.operators[operator], results = [];
             for (var i = 0, node; node = nodes[i]; i++)
             {
@@ -3871,7 +3871,7 @@
             return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
         },
 
-    // handles the an+b logic
+        // handles the an+b logic
         getIndices: function(a, b, total)
         {
             if (a == 0) return b > 0 ? [b] : [];
@@ -3882,7 +3882,7 @@
             });
         },
 
-    // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
+        // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
         nth: function(nodes, formula, root, reverse, ofType)
         {
             if (nodes.length == 0) return [];
@@ -3892,7 +3892,7 @@
             h.mark(nodes);
             for (var i = 0, node; node = nodes[i]; i++)
             {
-                if (!node.parentNode._counted)
+                if (!node.parentNode._countedByPrototype)
                 {
                     h.index(node.parentNode, reverse, ofType);
                     indexed.push(node.parentNode);
@@ -3938,7 +3938,7 @@
             var exclusions = new Selector(selector).findElements(root);
             h.mark(exclusions);
             for (var i = 0, results = [], node; node = nodes[i]; i++)
-                if (!node._counted) results.push(node);
+                if (!node._countedByPrototype) results.push(node);
             h.unmark(exclusions);
             return results;
         },
@@ -3996,12 +3996,22 @@
         }
     },
 
+    split: function(expression)
+    {
+        var expressions = [];
+        expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m)
+        {
+            expressions.push(m[1].strip());
+        });
+        return expressions;
+    },
+
     matchElements: function(elements, expression)
     {
-        var matches = new Selector(expression).findElements(), h = Selector.handlers;
+        var matches = $$(expression), h = Selector.handlers;
         h.mark(matches);
         for (var i = 0, results = [], element; element = elements[i]; i++)
-            if (element._counted) results.push(element);
+            if (element._countedByPrototype) results.push(element);
         h.unmark(matches);
         return results;
     },
@@ -4018,11 +4028,7 @@
 
     findChildElements: function(element, expressions)
     {
-        var exprs = expressions.join(','), expressions = [];
-        exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m)
-        {
-            expressions.push(m[1].strip());
-        });
+        expressions = Selector.split(expressions.join(','));
         var results = [], h = Selector.handlers;
         for (var i = 0, l = expressions.length, selector; i < l; i++)
         {
@@ -4033,6 +4039,28 @@
     }
 });
 
+if (Prototype.Browser.IE)
+{
+    Object.extend(Selector.handlers, {
+        // IE returns comment nodes on getElementsByTagName("*").
+        // Filter them out.
+        concat: function(a, b)
+        {
+            for (var i = 0, node; node = b[i]; i++)
+                if (node.tagName !== "!") a.push(node);
+            return a;
+        },
+
+        // IE improperly serializes _countedByPrototype in (inner|outer)HTML.
+        unmark: function(nodes)
+        {
+            for (var i = 0, node; node = nodes[i]; i++)
+                node.removeAttribute('_countedByPrototype');
+            return nodes;
+        }
+    });
+}
+
 function $$()
 {
     return Selector.findChildElements(document, $A(arguments));
@@ -4047,7 +4075,7 @@
     serializeElements: function(elements, options)
     {
         if (typeof options != 'object') options = { hash: !!options };
-        else if (options.hash === undefined) options.hash = true;
+        else if (Object.isUndefined(options.hash)) options.hash = true;
         var key, value, submitted = false, submit = options.submit;
 
         var data = elements.inject({ }, function(result, element)
@@ -4286,19 +4314,19 @@
 
     inputSelector: function(element, value)
     {
-        if (value === undefined) return element.checked ? element.value : null;
+        if (Object.isUndefined(value)) return element.checked ? element.value : null;
         else element.checked = !!value;
     },
 
     textarea: function(element, value)
     {
-        if (value === undefined) return element.value;
+        if (Object.isUndefined(value)) return element.value;
         else element.value = value;
     },
 
     select: function(element, index)
     {
-        if (index === undefined)
+        if (Object.isUndefined(index))
             return this[element.type == 'select-one' ?
                         'selectOne' : 'selectMany'](element);
         else
@@ -4534,7 +4562,9 @@
         findElement: function(event, expression)
         {
             var element = Event.element(event);
-            return element.match(expression) ? element : element.up(expression);
+            if (!expression) return element;
+            var elements = [element].concat(element.ancestors());
+            return Selector.findElement(elements, expression, 0);
         },
 
         pointer: function(event)
@@ -4622,9 +4652,9 @@
 
     function getEventID(element)
     {
-        if (element._eventID) return element._eventID;
+        if (element._prototypeEventID) return element._prototypeEventID[0];
         arguments.callee.id = arguments.callee.id || 1;
-        return element._eventID = ++arguments.callee.id;
+        return element._prototypeEventID = [++arguments.callee.id];
     }
 
     function getDOMEventName(eventName)
@@ -4657,7 +4687,7 @@
                 return false;
 
             Event.extend(event);
-            handler.call(element, event)
+            handler.call(element, event);
         };
 
         wrapper.handler = handler;
@@ -4760,14 +4790,15 @@
             if (element == document && document.createEvent && !element.dispatchEvent)
                 element = document.documentElement;
 
+            var event;
             if (document.createEvent)
             {
-                var event = document.createEvent("HTMLEvents");
+                event = document.createEvent("HTMLEvents");
                 event.initEvent("dataavailable", true, true);
             }
             else
             {
-                var event = document.createEventObject();
+                event = document.createEventObject();
                 event.eventType = "ondataavailable";
             }
 
@@ -4783,7 +4814,7 @@
                 element.fireEvent(event.eventType, event);
             }
 
-            return event;
+            return Event.extend(event);
         }
     };
 })());
@@ -4799,7 +4830,8 @@
 Object.extend(document, {
     fire:          Element.Methods.fire.methodize(),
     observe:       Element.Methods.observe.methodize(),
-    stopObserving: Element.Methods.stopObserving.methodize()
+    stopObserving: Element.Methods.stopObserving.methodize(),
+    loaded:        false
 });
 
 (function()
@@ -4807,14 +4839,14 @@
     /* Support for the DOMContentLoaded event is based on work by Dan Webb,
 Matthias Miller, Dean Edwards and John Resig. */
 
-    var timer, fired = false;
+    var timer;
 
     function fireContentLoadedEvent()
     {
-        if (fired) return;
+        if (document.loaded) return;
         if (timer) window.clearInterval(timer);
         document.fire("dom:loaded");
-        fired = true;
+        document.loaded = true;
     }
 
     if (document.addEventListener)
@@ -4885,13 +4917,13 @@
 // This should be moved to script.aculo.us; notice the deprecated methods
 // further below, that map to the newer Element methods.
 var Position = {
-// set to true if needed, warning: firefox performance problems
-// NOT neeeded for page scrolling, only if draggable contained in
-// scrollable elements
+    // set to true if needed, warning: firefox performance problems
+    // NOT neeeded for page scrolling, only if draggable contained in
+    // scrollable elements
     includeScrollOffsets: false,
 
-// must be called before calling withinIncludingScrolloffset, every time the
-// page is scrolled
+    // must be called before calling withinIncludingScrolloffset, every time the
+    // page is scrolled
     prepare: function()
     {
         this.deltaX = window.pageXOffset
@@ -4904,7 +4936,7 @@
                 || 0;
     },
 
-// caches x/y coordinate pair to use with overlap
+    // caches x/y coordinate pair to use with overlap
     within: function(element, x, y)
     {
         if (this.includeScrollOffsets)
@@ -4933,7 +4965,7 @@
                 this.xcomp < this.offset[0] + element.offsetWidth);
     },
 
-// within must be called directly before
+    // within must be called directly before
     overlap: function(mode, element)
     {
         if (!mode) return 0;
@@ -4945,7 +4977,7 @@
                    element.offsetWidth;
     },
 
-// Deprecation layer -- use newer Element methods now (1.5.2).
+    // Deprecation layer -- use newer Element methods now (1.5.2).
 
     cumulativeOffset: Element.Methods.cumulativeOffset,