aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Stephenson <sam@37signals.com>2006-11-12 03:44:35 +0000
committerSam Stephenson <sam@37signals.com>2006-11-12 03:44:35 +0000
commitc192bdfc74777f3a86f2f9b54459259330424cf5 (patch)
tree8482e517cd3506bff8ed83460051d8c58ec7e651
parent79c309e43ba8832a8665fdec26e32062e5b2b830 (diff)
downloadrails-c192bdfc74777f3a86f2f9b54459259330424cf5.tar.gz
rails-c192bdfc74777f3a86f2f9b54459259330424cf5.tar.bz2
rails-c192bdfc74777f3a86f2f9b54459259330424cf5.zip
Update to Prototype 1.5.0_rc2
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@5497 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
-rw-r--r--actionpack/CHANGELOG2
-rw-r--r--actionpack/lib/action_view/helpers/javascripts/prototype.js418
-rw-r--r--railties/CHANGELOG2
-rw-r--r--railties/html/javascripts/prototype.js418
4 files changed, 482 insertions, 358 deletions
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index e1dae7e939..54335ee107 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,7 @@
*SVN*
+* Update to Prototype 1.5.0_rc2. [Sam Stephenson]
+
* Remove JavaScriptLiteral in favor of ActiveSupport::JSON::Variable. [Sam Stephenson]
* Sync ActionController::StatusCodes::STATUS_CODES with http://www.iana.org/assignments/http-status-codes. #6586 [dkubb]
diff --git a/actionpack/lib/action_view/helpers/javascripts/prototype.js b/actionpack/lib/action_view/helpers/javascripts/prototype.js
index 8ceb046995..ce1e5a028b 100644
--- a/actionpack/lib/action_view/helpers/javascripts/prototype.js
+++ b/actionpack/lib/action_view/helpers/javascripts/prototype.js
@@ -1,5 +1,5 @@
-/* Prototype JavaScript framework, version 1.5.0_rc1
- * (c) 2005 Sam Stephenson <sam@conio.net>
+/* Prototype JavaScript framework, version 1.5.0_rc2
+ * (c) 2005, 2006 Sam Stephenson <sam@conio.net>
*
* Prototype is freely distributable under the terms of an MIT-style license.
* For details, see the Prototype web site: http://prototype.conio.net/
@@ -7,7 +7,7 @@
/*--------------------------------------------------------------------------*/
var Prototype = {
- Version: '1.5.0_rc1',
+ Version: '1.5.0_rc2',
BrowserFeatures: {
XPath: !!document.evaluate
},
@@ -37,8 +37,8 @@ Object.extend = function(destination, source) {
Object.extend(Object, {
inspect: function(object) {
try {
- if (object == undefined) return 'undefined';
- if (object == null) return 'null';
+ if (object === undefined) return 'undefined';
+ if (object === null) return 'null';
return object.inspect ? object.inspect() : object.toString();
} catch (e) {
if (e instanceof RangeError) return '...';
@@ -100,7 +100,7 @@ var Try = {
these: function() {
var returnValue;
- for (var i = 0; i < arguments.length; i++) {
+ for (var i = 0, length = arguments.length; i < length; i++) {
var lambda = arguments[i];
try {
returnValue = lambda();
@@ -221,13 +221,23 @@ Object.extend(String.prototype, {
return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
},
- toQueryParams: function() {
- var pairs = this.match(/^\??(.*)$/)[1].split('&');
- return pairs.inject({}, function(params, pairString) {
- var pair = pairString.split('=');
- var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
- params[decodeURIComponent(pair[0])] = value;
- return params;
+ toQueryParams: function(separator) {
+ var match = this.strip().match(/([^?#]*)(#.*)?$/);
+ if (!match) return {};
+
+ return match[1].split(separator || '&').inject({}, function(hash, pair) {
+ if ((pair = pair.split('='))[0]) {
+ var name = decodeURIComponent(pair[0]);
+ var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
+
+ if (hash[name] !== undefined) {
+ if (hash[name].constructor != Array)
+ hash[name] = [hash[name]];
+ if (value) hash[name].push(value);
+ }
+ else hash[name] = value;
+ }
+ return hash;
});
},
@@ -243,7 +253,7 @@ Object.extend(String.prototype, {
? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
: oStringList[0];
- for (var i = 1, len = oStringList.length; i < len; i++) {
+ for (var i = 1, length = oStringList.length; i < length; i++) {
var s = oStringList[i];
camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
}
@@ -338,7 +348,7 @@ var Enumerable = {
return results;
},
- detect: function (iterator) {
+ detect: function(iterator) {
var result;
this.each(function(value, index) {
if (iterator(value, index)) {
@@ -490,7 +500,7 @@ var $A = Array.from = function(iterable) {
return iterable.toArray();
} else {
var results = [];
- for (var i = 0; i < iterable.length; i++)
+ for (var i = 0, length = iterable.length; i < length; i++)
results.push(iterable[i]);
return results;
}
@@ -503,7 +513,7 @@ if (!Array.prototype._reverse)
Object.extend(Array.prototype, {
_each: function(iterator) {
- for (var i = 0; i < this.length; i++)
+ for (var i = 0, length = this.length; i < length; i++)
iterator(this[i]);
},
@@ -541,7 +551,7 @@ Object.extend(Array.prototype, {
},
indexOf: function(object) {
- for (var i = 0; i < this.length; i++)
+ for (var i = 0, length = this.length; i < length; i++)
if (this[i] == object) return i;
return -1;
},
@@ -568,6 +578,8 @@ Object.extend(Array.prototype, {
return '[' + this.map(Object.inspect).join(', ') + ']';
}
});
+
+Array.prototype.toArray = Array.prototype.clone;
var Hash = {
_each: function(iterator) {
for (var key in this) {
@@ -590,7 +602,7 @@ var Hash = {
},
merge: function(hash) {
- return $H(hash).inject($H(this), function(mergedHash, pair) {
+ return $H(hash).inject(this, function(mergedHash, pair) {
mergedHash[pair.key] = pair.value;
return mergedHash;
});
@@ -598,6 +610,22 @@ var Hash = {
toQueryString: function() {
return this.map(function(pair) {
+ if (!pair.key) return null;
+
+ if (pair.value && pair.value.constructor == Array) {
+ pair.value = pair.value.compact();
+
+ if (pair.value.length < 2) {
+ pair.value = pair.value.reduce();
+ } else {
+ var key = encodeURIComponent(pair.key);
+ return pair.value.map(function(value) {
+ return key + '=' + encodeURIComponent(value);
+ }).join('&');
+ }
+ }
+
+ if (pair.value == undefined) pair[1] = '';
return pair.map(encodeURIComponent).join('=');
}).join('&');
},
@@ -664,18 +692,18 @@ Ajax.Responders = {
this.responders._each(iterator);
},
- register: function(responderToAdd) {
- if (!this.include(responderToAdd))
- this.responders.push(responderToAdd);
+ register: function(responder) {
+ if (!this.include(responder))
+ this.responders.push(responder);
},
- unregister: function(responderToRemove) {
- this.responders = this.responders.without(responderToRemove);
+ unregister: function(responder) {
+ this.responders = this.responders.without(responder);
},
dispatch: function(callback, request, transport, json) {
this.each(function(responder) {
- if (responder[callback] && typeof responder[callback] == 'function') {
+ if (typeof responder[callback] == 'function') {
try {
responder[callback].apply(responder, [request, transport, json]);
} catch (e) {}
@@ -690,7 +718,6 @@ Ajax.Responders.register({
onCreate: function() {
Ajax.activeRequestCount++;
},
-
onComplete: function() {
Ajax.activeRequestCount--;
}
@@ -703,19 +730,14 @@ Ajax.Base.prototype = {
method: 'post',
asynchronous: true,
contentType: 'application/x-www-form-urlencoded',
+ encoding: 'UTF-8',
parameters: ''
}
Object.extend(this.options, options || {});
- },
- responseIsSuccess: function() {
- return this.transport.status == undefined
- || this.transport.status == 0
- || (this.transport.status >= 200 && this.transport.status < 300);
- },
-
- responseIsFailure: function() {
- return !this.responseIsSuccess();
+ this.options.method = this.options.method.toLowerCase();
+ this.options.parameters = $H(typeof this.options.parameters == 'string' ?
+ this.options.parameters.toQueryParams() : this.options.parameters);
}
}
@@ -731,24 +753,28 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
},
request: function(url) {
- var parameters = this.options.parameters || '';
- if (parameters.length > 0) parameters += '&_=';
+ var params = this.options.parameters;
+ if (params.any()) params['_'] = '';
- /* Simulate other verbs over post */
- if (this.options.method != 'get' && this.options.method != 'post') {
- parameters += (parameters.length > 0 ? '&' : '') + '_method=' + this.options.method;
+ if (!['get', 'post'].include(this.options.method)) {
+ // simulate other verbs over post
+ params['_method'] = this.options.method;
this.options.method = 'post';
}
- try {
- this.url = url;
- if (this.options.method == 'get' && parameters.length > 0)
- this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
+ this.url = url;
+
+ // when GET, append parameters to URL
+ if (this.options.method == 'get' && params.any())
+ this.url += (this.url.indexOf('?') >= 0 ? '&' : '?') +
+ params.toQueryString();
+ try {
Ajax.Responders.dispatch('onCreate', this, this.transport);
- this.transport.open(this.options.method, this.url,
- this.options.asynchronous);
+ this.transport.open(this.options.method.toUpperCase(), this.url,
+ this.options.asynchronous, this.options.username,
+ this.options.password);
if (this.options.asynchronous)
setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
@@ -756,95 +782,116 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
this.transport.onreadystatechange = this.onStateChange.bind(this);
this.setRequestHeaders();
- var body = this.options.postBody ? this.options.postBody : parameters;
- this.transport.send(this.options.method == 'post' ? body : null);
+ var body = this.options.method == 'post' ?
+ (this.options.postBody || params.toQueryString()) : null;
+
+ this.transport.send(body);
/* Force Firefox to handle ready state 4 for synchronous requests */
if (!this.options.asynchronous && this.transport.overrideMimeType)
this.onStateChange();
-
- } catch (e) {
+ }
+ catch (e) {
this.dispatchException(e);
}
},
+ onStateChange: function() {
+ var readyState = this.transport.readyState;
+ if (readyState > 1)
+ this.respondToReadyState(this.transport.readyState);
+ },
+
setRequestHeaders: function() {
- var requestHeaders =
- ['X-Requested-With', 'XMLHttpRequest',
- 'X-Prototype-Version', Prototype.Version,
- 'Accept', 'text/javascript, text/html, application/xml, text/xml, */*'];
+ var headers = {
+ 'X-Requested-With': 'XMLHttpRequest',
+ 'X-Prototype-Version': Prototype.Version,
+ 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
+ };
if (this.options.method == 'post') {
- requestHeaders.push('Content-type', this.options.contentType);
+ headers['Content-type'] = this.options.contentType +
+ (this.options.encoding ? '; charset=' + this.options.encoding : '');
- /* Force "Connection: close" for Mozilla browsers to work around
- * a bug where XMLHttpReqeuest sends an incorrect Content-length
- * header. See Mozilla Bugzilla #246651.
+ /* Force "Connection: close" for older Mozilla browsers to work
+ * around a bug where XMLHttpRequest sends an incorrect
+ * Content-length header. See Mozilla Bugzilla #246651.
*/
- if (this.transport.overrideMimeType)
- requestHeaders.push('Connection', 'close');
+ if (this.transport.overrideMimeType &&
+ (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
+ headers['Connection'] = 'close';
}
- if (this.options.requestHeaders)
- requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
-
- for (var i = 0; i < requestHeaders.length; i += 2)
- this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
- },
-
- onStateChange: function() {
- var readyState = this.transport.readyState;
- if (readyState != 1)
- this.respondToReadyState(this.transport.readyState);
- },
+ // user-defined headers
+ if (typeof this.options.requestHeaders == 'object') {
+ var extras = this.options.requestHeaders;
- header: function(name) {
- try {
- return this.transport.getResponseHeader(name);
- } catch (e) {}
- },
+ if (typeof extras.push == 'function')
+ for (var i = 0, length = extras.length; i < length; i += 2)
+ headers[extras[i]] = extras[i+1];
+ else
+ $H(extras).each(function(pair) { headers[pair.key] = pair.value });
+ }
- evalJSON: function() {
- try {
- return eval('(' + this.header('X-JSON') + ')');
- } catch (e) {}
+ for (var name in headers)
+ this.transport.setRequestHeader(name, headers[name]);
},
- evalResponse: function() {
- try {
- return eval(this.transport.responseText);
- } catch (e) {
- this.dispatchException(e);
- }
+ success: function() {
+ return !this.transport.status
+ || (this.transport.status >= 200 && this.transport.status < 300);
},
respondToReadyState: function(readyState) {
- var event = Ajax.Request.Events[readyState];
+ var state = Ajax.Request.Events[readyState];
var transport = this.transport, json = this.evalJSON();
- if (event == 'Complete') {
+ if (state == 'Complete') {
try {
(this.options['on' + this.transport.status]
- || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
+ || this.options['on' + (this.success() ? 'Success' : 'Failure')]
|| Prototype.emptyFunction)(transport, json);
} catch (e) {
this.dispatchException(e);
}
-
- if ((this.header('Content-type') || '').match(/^text\/javascript/i))
- this.evalResponse();
}
try {
- (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
- Ajax.Responders.dispatch('on' + event, this, transport, json);
+ (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
+ Ajax.Responders.dispatch('on' + state, this, transport, json);
} catch (e) {
this.dispatchException(e);
}
- /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
- if (event == 'Complete')
+ if (state == 'Complete') {
+ if ((this.getHeader('Content-type') || '').strip().
+ match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
+ this.evalResponse();
+
+ // avoid memory leak in MSIE: clean up
this.transport.onreadystatechange = Prototype.emptyFunction;
+ }
+ },
+
+ getHeader: function(name) {
+ try {
+ return this.transport.getResponseHeader(name);
+ } catch (e) { return null }
+ },
+
+ evalJSON: function() {
+ try {
+ var json = this.getHeader('X-JSON');
+ return json ? eval('(' + json + ')') : null;
+ } catch (e) { return null }
+ },
+
+ evalResponse: function() {
+ try {
+ return eval(this.transport.responseText);
+ } catch (e) {
+ this.dispatchException(e);
+ }
},
dispatchException: function(exception) {
@@ -857,41 +904,37 @@ Ajax.Updater = Class.create();
Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
initialize: function(container, url, options) {
- this.containers = {
- success: container.success ? $(container.success) : $(container),
- failure: container.failure ? $(container.failure) :
- (container.success ? null : $(container))
+ this.container = {
+ success: (container.success || container),
+ failure: (container.failure || (container.success ? null : container))
}
this.transport = Ajax.getTransport();
this.setOptions(options);
var onComplete = this.options.onComplete || Prototype.emptyFunction;
- this.options.onComplete = (function(transport, object) {
+ this.options.onComplete = (function(transport, param) {
this.updateContent();
- onComplete(transport, object);
+ onComplete(transport, param);
}).bind(this);
this.request(url);
},
updateContent: function() {
- var receiver = this.responseIsSuccess() ?
- this.containers.success : this.containers.failure;
+ var receiver = this.container[this.success() ? 'success' : 'failure'];
var response = this.transport.responseText;
- if (!this.options.evalScripts)
- response = response.stripScripts();
+ if (!this.options.evalScripts) response = response.stripScripts();
- if (receiver) {
- if (this.options.insertion) {
+ if (receiver = $(receiver)) {
+ if (this.options.insertion)
new this.options.insertion(receiver, response);
- } else {
- Element.update(receiver, response);
- }
+ else
+ receiver.update(response);
}
- if (this.responseIsSuccess()) {
+ if (this.success()) {
if (this.onComplete)
setTimeout(this.onComplete.bind(this), 10);
}
@@ -940,15 +983,15 @@ Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
this.updater = new Ajax.Updater(this.container, this.url, this.options);
}
});
-function $() {
- var results = [], element;
- for (var i = 0; i < arguments.length; i++) {
- element = arguments[i];
- if (typeof element == 'string')
- element = document.getElementById(element);
- results.push(Element.extend(element));
+function $(element) {
+ if (arguments.length > 1) {
+ for (var i = 0, elements = [], length = arguments.length; i < length; i++)
+ elements.push($(arguments[i]));
+ return elements;
}
- return results.reduce();
+ if (typeof element == 'string')
+ element = document.getElementById(element);
+ return Element.extend(element);
}
if (Prototype.BrowserFeatures.XPath) {
@@ -956,7 +999,7 @@ if (Prototype.BrowserFeatures.XPath) {
var results = [];
var query = document.evaluate(expression, $(parentElement) || document,
null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
- for (var i = 0, len = query.snapshotLength; i < len; i++)
+ for (var i = 0, length = query.snapshotLength; i < length; i++)
results.push(query.snapshotItem(i));
return results;
}
@@ -969,11 +1012,9 @@ document.getElementsByClassName = function(className, parentElement) {
} else {
var children = ($(parentElement) || document.body).getElementsByTagName('*');
var elements = [], child;
- for (var i = 0, len = children.length; i < len; i++) {
+ for (var i = 0, length = children.length; i < length; i++) {
child = children[i];
- if (child.className.length == 0) continue;
- if (child.className == className ||
- child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
+ if (Element.hasClassName(child, className))
elements.push(Element.extend(child));
}
return elements;
@@ -997,9 +1038,11 @@ Element.extend = function(element) {
if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
Object.extend(methods, Form.Element.Methods);
+ Object.extend(methods, Element.Methods.Simulated);
+
for (var property in methods) {
var value = methods[property];
- if (typeof value == 'function')
+ if (typeof value == 'function' && !(property in element))
element[property] = cache.findOrStore(value);
}
}
@@ -1093,6 +1136,13 @@ Element.Methods = {
return $A(element.getElementsByTagName('*'));
},
+ immediateDescendants: function(element) {
+ if (!(element = $(element).firstChild)) return [];
+ while (element && element.nodeType != 1) element = element.nextSibling;
+ if (element) return [element].concat($(element).nextSiblings());
+ return [];
+ },
+
previousSiblings: function(element) {
return $(element).recursivelyCollect('previousSibling');
},
@@ -1139,6 +1189,10 @@ Element.Methods = {
return document.getElementsByClassName(className, element);
},
+ readAttribute: function(element, name) {
+ return $(element).getAttribute(name);
+ },
+
getHeight: function(element) {
element = $(element);
return element.offsetHeight;
@@ -1150,7 +1204,12 @@ Element.Methods = {
hasClassName: function(element, className) {
if (!(element = $(element))) return;
- return Element.classNames(element).include(className);
+ var elementClassName = element.className;
+ if (elementClassName.length == 0) return false;
+ if (elementClassName == className ||
+ elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
+ return true;
+ return false;
},
addClassName: function(element, className) {
@@ -1300,13 +1359,19 @@ Element.Methods = {
}
}
+Element.Methods.Simulated = {
+ hasAttribute: function(element, attribute) {
+ return $(element).getAttributeNode(attribute).specified;
+ }
+}
+
// IE is missing .innerHTML support for TABLE-related elements
if(document.all){
Element.Methods.update = function(element, html) {
element = $(element);
html = typeof html == 'undefined' ? '' : html.toString();
var tagName = element.tagName.toUpperCase();
- if (['THEAD','TBODY','TR','TD'].indexOf(tagName) > -1) {
+ if (['THEAD','TBODY','TR','TD'].include(tagName)) {
var div = document.createElement('div');
switch (tagName) {
case 'THEAD':
@@ -1352,16 +1417,19 @@ if(/Konqueror|Safari|KHTML/.test(navigator.userAgent))
Element.addMethods = function(methods) {
Object.extend(Element.Methods, methods || {});
- function copy(methods, destination) {
+ function copy(methods, destination, onlyIfAbsent) {
+ onlyIfAbsent = onlyIfAbsent || false;
var cache = Element.extend.cache;
for (var property in methods) {
var value = methods[property];
- destination[property] = cache.findOrStore(value);
+ if (!onlyIfAbsent || !(property in destination))
+ destination[property] = cache.findOrStore(value);
}
}
if (typeof HTMLElement != 'undefined') {
copy(Element.Methods, HTMLElement.prototype);
+ copy(Element.Methods.Simulated, HTMLElement.prototype, true);
copy(Form.Methods, HTMLFormElement.prototype);
[HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
copy(Form.Element.Methods, klass.prototype);
@@ -1388,8 +1456,8 @@ Abstract.Insertion.prototype = {
try {
this.element.insertAdjacentHTML(this.adjacency, this.content);
} catch (e) {
- var tagName = this.element.tagName.toLowerCase();
- if (tagName == 'tbody' || tagName == 'tr') {
+ var tagName = this.element.tagName.toUpperCase();
+ if (['TBODY', 'TR'].include(tagName)) {
this.insertContent(this.contentFromAnonymousTable());
} else {
throw e;
@@ -1488,18 +1556,16 @@ Element.ClassNames.prototype = {
add: function(classNameToAdd) {
if (this.include(classNameToAdd)) return;
- this.set(this.toArray().concat(classNameToAdd).join(' '));
+ this.set($A(this).concat(classNameToAdd).join(' '));
},
remove: function(classNameToRemove) {
if (!this.include(classNameToRemove)) return;
- this.set(this.select(function(className) {
- return className != classNameToRemove;
- }).join(' '));
+ this.set($A(this).without(classNameToRemove).join(' '));
},
toString: function() {
- return this.toArray().join(' ');
+ return $A(this).join(' ');
}
}
@@ -1552,7 +1618,7 @@ Selector.prototype = {
if (clause = params.tagName)
conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
if ((clause = params.classNames).length > 0)
- for (var i = 0; i < clause.length; i++)
+ for (var i = 0, length = clause.length; i < length; i++)
conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')');
if (clause = params.attributes) {
clause.each(function(attribute) {
@@ -1594,7 +1660,7 @@ Selector.prototype = {
scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
var results = [];
- for (var i = 0; i < scope.length; i++)
+ for (var i = 0, length = scope.length; i < length; i++)
if (this.match(element = scope[i]))
results.push(Element.extend(element));
@@ -1636,32 +1702,30 @@ var Form = {
reset: function(form) {
$(form).reset();
return form;
+ },
+
+ serializeElements: function(elements) {
+ return elements.inject([], function(queryComponents, element) {
+ var queryComponent = Form.Element.serialize(element);
+ if (queryComponent) queryComponents.push(queryComponent);
+ return queryComponents;
+ }).join('&');
}
};
Form.Methods = {
serialize: function(form) {
- return this.serializeElements(Form.getElements($(form)));
- },
-
- serializeElements: function(elements) {
- var queryComponents = new Array();
-
- for (var i = 0; i < elements.length; i++) {
- var queryComponent = Form.Element.serialize(elements[i]);
- if (queryComponent)
- queryComponents.push(queryComponent);
- }
-
- return queryComponents.join('&');
+ return Form.serializeElements($(form).getElements());
},
getElements: function(form) {
- return $A($(form).getElementsByTagName('*')).inject([], function(elements, child) {
- if (Form.Element.Serializers[child.tagName.toLowerCase()])
- elements.push(Element.extend(child));
- return elements;
- });
+ return $A($(form).getElementsByTagName('*')).inject([],
+ function(elements, child) {
+ if (Form.Element.Serializers[child.tagName.toLowerCase()])
+ elements.push(Element.extend(child));
+ return elements;
+ }
+ );
},
getInputs: function(form, typeName, name) {
@@ -1672,12 +1736,12 @@ Form.Methods = {
return inputs;
var matchingInputs = new Array();
- for (var i = 0; i < inputs.length; i++) {
+ for (var i = 0, length = inputs.length; i < length; i++) {
var input = inputs[i];
if ((typeName && input.type != typeName) ||
(name && input.name != name))
continue;
- matchingInputs.push(input);
+ matchingInputs.push(Element.extend(input));
}
return matchingInputs;
@@ -1685,27 +1749,23 @@ Form.Methods = {
disable: function(form) {
form = $(form);
- var elements = Form.getElements(form);
- for (var i = 0; i < elements.length; i++) {
- var element = elements[i];
+ form.getElements().each(function(element) {
element.blur();
element.disabled = 'true';
- }
+ });
return form;
},
enable: function(form) {
form = $(form);
- var elements = Form.getElements(form);
- for (var i = 0; i < elements.length; i++) {
- var element = elements[i];
+ form.getElements().each(function(element) {
element.disabled = '';
- }
+ });
return form;
},
findFirstElement: function(form) {
- return Form.getElements(form).find(function(element) {
+ return $(form).getElements().find(function(element) {
return element.type != 'hidden' && !element.disabled &&
['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
});
@@ -1713,7 +1773,7 @@ Form.Methods = {
focusFirstElement: function(form) {
form = $(form);
- Field.activate(Form.findFirstElement(form));
+ form.findFirstElement().activate();
return form;
}
}
@@ -1828,18 +1888,20 @@ Form.Element.Serializers = {
selectOne: function(element) {
var value = '', opt, index = element.selectedIndex;
if (index >= 0) {
- opt = element.options[index];
- value = opt.value || opt.text;
+ opt = Element.extend(element.options[index]);
+ // Uses the new potential extension if hasAttribute isn't native.
+ value = opt.hasAttribute('value') ? opt.value : opt.text;
}
return [element.name, value];
},
selectMany: function(element) {
var value = [];
- for (var i = 0; i < element.length; i++) {
- var opt = element.options[i];
+ for (var i = 0, length = element.length; i < length; i++) {
+ var opt = Element.extend(element.options[i]);
if (opt.selected)
- value.push(opt.value || opt.text);
+ // Uses the new potential extension if hasAttribute isn't native.
+ value.push(opt.hasAttribute('value') ? opt.value : opt.text);
}
return [element.name, value];
}
@@ -1913,9 +1975,7 @@ Abstract.EventObserver.prototype = {
},
registerFormCallbacks: function() {
- var elements = Form.getElements(this.element);
- for (var i = 0; i < elements.length; i++)
- this.registerCallback(elements[i]);
+ Form.getElements(this.element).each(this.registerCallback.bind(this));
},
registerCallback: function(element) {
@@ -2019,7 +2079,7 @@ Object.extend(Event, {
unloadCache: function() {
if (!Event.observers) return;
- for (var i = 0; i < Event.observers.length; i++) {
+ for (var i = 0, length = Event.observers.length; i < length; i++) {
Event.stopObserving.apply(this, Event.observers[i]);
Event.observers[i][0] = null;
}
diff --git a/railties/CHANGELOG b/railties/CHANGELOG
index e2659c9051..496654ddb5 100644
--- a/railties/CHANGELOG
+++ b/railties/CHANGELOG
@@ -1,5 +1,7 @@
*SVN*
+* Update to Prototype 1.5.0_rc2. [Sam Stephenson]
+
* Add grep-based fallback to reaper, to work in pidless setups [Jamis Buck]
* Only wrap request processing with our USR1 signal handler so FastCGI can trap it and raise an exception while waiting for connections. Idle processes exit immediately rather than waiting for another request; active processes gracefully exit when the request is finished. [Jeremy Kemper]
diff --git a/railties/html/javascripts/prototype.js b/railties/html/javascripts/prototype.js
index 8ceb046995..ce1e5a028b 100644
--- a/railties/html/javascripts/prototype.js
+++ b/railties/html/javascripts/prototype.js
@@ -1,5 +1,5 @@
-/* Prototype JavaScript framework, version 1.5.0_rc1
- * (c) 2005 Sam Stephenson <sam@conio.net>
+/* Prototype JavaScript framework, version 1.5.0_rc2
+ * (c) 2005, 2006 Sam Stephenson <sam@conio.net>
*
* Prototype is freely distributable under the terms of an MIT-style license.
* For details, see the Prototype web site: http://prototype.conio.net/
@@ -7,7 +7,7 @@
/*--------------------------------------------------------------------------*/
var Prototype = {
- Version: '1.5.0_rc1',
+ Version: '1.5.0_rc2',
BrowserFeatures: {
XPath: !!document.evaluate
},
@@ -37,8 +37,8 @@ Object.extend = function(destination, source) {
Object.extend(Object, {
inspect: function(object) {
try {
- if (object == undefined) return 'undefined';
- if (object == null) return 'null';
+ if (object === undefined) return 'undefined';
+ if (object === null) return 'null';
return object.inspect ? object.inspect() : object.toString();
} catch (e) {
if (e instanceof RangeError) return '...';
@@ -100,7 +100,7 @@ var Try = {
these: function() {
var returnValue;
- for (var i = 0; i < arguments.length; i++) {
+ for (var i = 0, length = arguments.length; i < length; i++) {
var lambda = arguments[i];
try {
returnValue = lambda();
@@ -221,13 +221,23 @@ Object.extend(String.prototype, {
return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
},
- toQueryParams: function() {
- var pairs = this.match(/^\??(.*)$/)[1].split('&');
- return pairs.inject({}, function(params, pairString) {
- var pair = pairString.split('=');
- var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
- params[decodeURIComponent(pair[0])] = value;
- return params;
+ toQueryParams: function(separator) {
+ var match = this.strip().match(/([^?#]*)(#.*)?$/);
+ if (!match) return {};
+
+ return match[1].split(separator || '&').inject({}, function(hash, pair) {
+ if ((pair = pair.split('='))[0]) {
+ var name = decodeURIComponent(pair[0]);
+ var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
+
+ if (hash[name] !== undefined) {
+ if (hash[name].constructor != Array)
+ hash[name] = [hash[name]];
+ if (value) hash[name].push(value);
+ }
+ else hash[name] = value;
+ }
+ return hash;
});
},
@@ -243,7 +253,7 @@ Object.extend(String.prototype, {
? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
: oStringList[0];
- for (var i = 1, len = oStringList.length; i < len; i++) {
+ for (var i = 1, length = oStringList.length; i < length; i++) {
var s = oStringList[i];
camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
}
@@ -338,7 +348,7 @@ var Enumerable = {
return results;
},
- detect: function (iterator) {
+ detect: function(iterator) {
var result;
this.each(function(value, index) {
if (iterator(value, index)) {
@@ -490,7 +500,7 @@ var $A = Array.from = function(iterable) {
return iterable.toArray();
} else {
var results = [];
- for (var i = 0; i < iterable.length; i++)
+ for (var i = 0, length = iterable.length; i < length; i++)
results.push(iterable[i]);
return results;
}
@@ -503,7 +513,7 @@ if (!Array.prototype._reverse)
Object.extend(Array.prototype, {
_each: function(iterator) {
- for (var i = 0; i < this.length; i++)
+ for (var i = 0, length = this.length; i < length; i++)
iterator(this[i]);
},
@@ -541,7 +551,7 @@ Object.extend(Array.prototype, {
},
indexOf: function(object) {
- for (var i = 0; i < this.length; i++)
+ for (var i = 0, length = this.length; i < length; i++)
if (this[i] == object) return i;
return -1;
},
@@ -568,6 +578,8 @@ Object.extend(Array.prototype, {
return '[' + this.map(Object.inspect).join(', ') + ']';
}
});
+
+Array.prototype.toArray = Array.prototype.clone;
var Hash = {
_each: function(iterator) {
for (var key in this) {
@@ -590,7 +602,7 @@ var Hash = {
},
merge: function(hash) {
- return $H(hash).inject($H(this), function(mergedHash, pair) {
+ return $H(hash).inject(this, function(mergedHash, pair) {
mergedHash[pair.key] = pair.value;
return mergedHash;
});
@@ -598,6 +610,22 @@ var Hash = {
toQueryString: function() {
return this.map(function(pair) {
+ if (!pair.key) return null;
+
+ if (pair.value && pair.value.constructor == Array) {
+ pair.value = pair.value.compact();
+
+ if (pair.value.length < 2) {
+ pair.value = pair.value.reduce();
+ } else {
+ var key = encodeURIComponent(pair.key);
+ return pair.value.map(function(value) {
+ return key + '=' + encodeURIComponent(value);
+ }).join('&');
+ }
+ }
+
+ if (pair.value == undefined) pair[1] = '';
return pair.map(encodeURIComponent).join('=');
}).join('&');
},
@@ -664,18 +692,18 @@ Ajax.Responders = {
this.responders._each(iterator);
},
- register: function(responderToAdd) {
- if (!this.include(responderToAdd))
- this.responders.push(responderToAdd);
+ register: function(responder) {
+ if (!this.include(responder))
+ this.responders.push(responder);
},
- unregister: function(responderToRemove) {
- this.responders = this.responders.without(responderToRemove);
+ unregister: function(responder) {
+ this.responders = this.responders.without(responder);
},
dispatch: function(callback, request, transport, json) {
this.each(function(responder) {
- if (responder[callback] && typeof responder[callback] == 'function') {
+ if (typeof responder[callback] == 'function') {
try {
responder[callback].apply(responder, [request, transport, json]);
} catch (e) {}
@@ -690,7 +718,6 @@ Ajax.Responders.register({
onCreate: function() {
Ajax.activeRequestCount++;
},
-
onComplete: function() {
Ajax.activeRequestCount--;
}
@@ -703,19 +730,14 @@ Ajax.Base.prototype = {
method: 'post',
asynchronous: true,
contentType: 'application/x-www-form-urlencoded',
+ encoding: 'UTF-8',
parameters: ''
}
Object.extend(this.options, options || {});
- },
- responseIsSuccess: function() {
- return this.transport.status == undefined
- || this.transport.status == 0
- || (this.transport.status >= 200 && this.transport.status < 300);
- },
-
- responseIsFailure: function() {
- return !this.responseIsSuccess();
+ this.options.method = this.options.method.toLowerCase();
+ this.options.parameters = $H(typeof this.options.parameters == 'string' ?
+ this.options.parameters.toQueryParams() : this.options.parameters);
}
}
@@ -731,24 +753,28 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
},
request: function(url) {
- var parameters = this.options.parameters || '';
- if (parameters.length > 0) parameters += '&_=';
+ var params = this.options.parameters;
+ if (params.any()) params['_'] = '';
- /* Simulate other verbs over post */
- if (this.options.method != 'get' && this.options.method != 'post') {
- parameters += (parameters.length > 0 ? '&' : '') + '_method=' + this.options.method;
+ if (!['get', 'post'].include(this.options.method)) {
+ // simulate other verbs over post
+ params['_method'] = this.options.method;
this.options.method = 'post';
}
- try {
- this.url = url;
- if (this.options.method == 'get' && parameters.length > 0)
- this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
+ this.url = url;
+
+ // when GET, append parameters to URL
+ if (this.options.method == 'get' && params.any())
+ this.url += (this.url.indexOf('?') >= 0 ? '&' : '?') +
+ params.toQueryString();
+ try {
Ajax.Responders.dispatch('onCreate', this, this.transport);
- this.transport.open(this.options.method, this.url,
- this.options.asynchronous);
+ this.transport.open(this.options.method.toUpperCase(), this.url,
+ this.options.asynchronous, this.options.username,
+ this.options.password);
if (this.options.asynchronous)
setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
@@ -756,95 +782,116 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
this.transport.onreadystatechange = this.onStateChange.bind(this);
this.setRequestHeaders();
- var body = this.options.postBody ? this.options.postBody : parameters;
- this.transport.send(this.options.method == 'post' ? body : null);
+ var body = this.options.method == 'post' ?
+ (this.options.postBody || params.toQueryString()) : null;
+
+ this.transport.send(body);
/* Force Firefox to handle ready state 4 for synchronous requests */
if (!this.options.asynchronous && this.transport.overrideMimeType)
this.onStateChange();
-
- } catch (e) {
+ }
+ catch (e) {
this.dispatchException(e);
}
},
+ onStateChange: function() {
+ var readyState = this.transport.readyState;
+ if (readyState > 1)
+ this.respondToReadyState(this.transport.readyState);
+ },
+
setRequestHeaders: function() {
- var requestHeaders =
- ['X-Requested-With', 'XMLHttpRequest',
- 'X-Prototype-Version', Prototype.Version,
- 'Accept', 'text/javascript, text/html, application/xml, text/xml, */*'];
+ var headers = {
+ 'X-Requested-With': 'XMLHttpRequest',
+ 'X-Prototype-Version': Prototype.Version,
+ 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
+ };
if (this.options.method == 'post') {
- requestHeaders.push('Content-type', this.options.contentType);
+ headers['Content-type'] = this.options.contentType +
+ (this.options.encoding ? '; charset=' + this.options.encoding : '');
- /* Force "Connection: close" for Mozilla browsers to work around
- * a bug where XMLHttpReqeuest sends an incorrect Content-length
- * header. See Mozilla Bugzilla #246651.
+ /* Force "Connection: close" for older Mozilla browsers to work
+ * around a bug where XMLHttpRequest sends an incorrect
+ * Content-length header. See Mozilla Bugzilla #246651.
*/
- if (this.transport.overrideMimeType)
- requestHeaders.push('Connection', 'close');
+ if (this.transport.overrideMimeType &&
+ (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
+ headers['Connection'] = 'close';
}
- if (this.options.requestHeaders)
- requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
-
- for (var i = 0; i < requestHeaders.length; i += 2)
- this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
- },
-
- onStateChange: function() {
- var readyState = this.transport.readyState;
- if (readyState != 1)
- this.respondToReadyState(this.transport.readyState);
- },
+ // user-defined headers
+ if (typeof this.options.requestHeaders == 'object') {
+ var extras = this.options.requestHeaders;
- header: function(name) {
- try {
- return this.transport.getResponseHeader(name);
- } catch (e) {}
- },
+ if (typeof extras.push == 'function')
+ for (var i = 0, length = extras.length; i < length; i += 2)
+ headers[extras[i]] = extras[i+1];
+ else
+ $H(extras).each(function(pair) { headers[pair.key] = pair.value });
+ }
- evalJSON: function() {
- try {
- return eval('(' + this.header('X-JSON') + ')');
- } catch (e) {}
+ for (var name in headers)
+ this.transport.setRequestHeader(name, headers[name]);
},
- evalResponse: function() {
- try {
- return eval(this.transport.responseText);
- } catch (e) {
- this.dispatchException(e);
- }
+ success: function() {
+ return !this.transport.status
+ || (this.transport.status >= 200 && this.transport.status < 300);
},
respondToReadyState: function(readyState) {
- var event = Ajax.Request.Events[readyState];
+ var state = Ajax.Request.Events[readyState];
var transport = this.transport, json = this.evalJSON();
- if (event == 'Complete') {
+ if (state == 'Complete') {
try {
(this.options['on' + this.transport.status]
- || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
+ || this.options['on' + (this.success() ? 'Success' : 'Failure')]
|| Prototype.emptyFunction)(transport, json);
} catch (e) {
this.dispatchException(e);
}
-
- if ((this.header('Content-type') || '').match(/^text\/javascript/i))
- this.evalResponse();
}
try {
- (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
- Ajax.Responders.dispatch('on' + event, this, transport, json);
+ (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
+ Ajax.Responders.dispatch('on' + state, this, transport, json);
} catch (e) {
this.dispatchException(e);
}
- /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
- if (event == 'Complete')
+ if (state == 'Complete') {
+ if ((this.getHeader('Content-type') || '').strip().
+ match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
+ this.evalResponse();
+
+ // avoid memory leak in MSIE: clean up
this.transport.onreadystatechange = Prototype.emptyFunction;
+ }
+ },
+
+ getHeader: function(name) {
+ try {
+ return this.transport.getResponseHeader(name);
+ } catch (e) { return null }
+ },
+
+ evalJSON: function() {
+ try {
+ var json = this.getHeader('X-JSON');
+ return json ? eval('(' + json + ')') : null;
+ } catch (e) { return null }
+ },
+
+ evalResponse: function() {
+ try {
+ return eval(this.transport.responseText);
+ } catch (e) {
+ this.dispatchException(e);
+ }
},
dispatchException: function(exception) {
@@ -857,41 +904,37 @@ Ajax.Updater = Class.create();
Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
initialize: function(container, url, options) {
- this.containers = {
- success: container.success ? $(container.success) : $(container),
- failure: container.failure ? $(container.failure) :
- (container.success ? null : $(container))
+ this.container = {
+ success: (container.success || container),
+ failure: (container.failure || (container.success ? null : container))
}
this.transport = Ajax.getTransport();
this.setOptions(options);
var onComplete = this.options.onComplete || Prototype.emptyFunction;
- this.options.onComplete = (function(transport, object) {
+ this.options.onComplete = (function(transport, param) {
this.updateContent();
- onComplete(transport, object);
+ onComplete(transport, param);
}).bind(this);
this.request(url);
},
updateContent: function() {
- var receiver = this.responseIsSuccess() ?
- this.containers.success : this.containers.failure;
+ var receiver = this.container[this.success() ? 'success' : 'failure'];
var response = this.transport.responseText;
- if (!this.options.evalScripts)
- response = response.stripScripts();
+ if (!this.options.evalScripts) response = response.stripScripts();
- if (receiver) {
- if (this.options.insertion) {
+ if (receiver = $(receiver)) {
+ if (this.options.insertion)
new this.options.insertion(receiver, response);
- } else {
- Element.update(receiver, response);
- }
+ else
+ receiver.update(response);
}
- if (this.responseIsSuccess()) {
+ if (this.success()) {
if (this.onComplete)
setTimeout(this.onComplete.bind(this), 10);
}
@@ -940,15 +983,15 @@ Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
this.updater = new Ajax.Updater(this.container, this.url, this.options);
}
});
-function $() {
- var results = [], element;
- for (var i = 0; i < arguments.length; i++) {
- element = arguments[i];
- if (typeof element == 'string')
- element = document.getElementById(element);
- results.push(Element.extend(element));
+function $(element) {
+ if (arguments.length > 1) {
+ for (var i = 0, elements = [], length = arguments.length; i < length; i++)
+ elements.push($(arguments[i]));
+ return elements;
}
- return results.reduce();
+ if (typeof element == 'string')
+ element = document.getElementById(element);
+ return Element.extend(element);
}
if (Prototype.BrowserFeatures.XPath) {
@@ -956,7 +999,7 @@ if (Prototype.BrowserFeatures.XPath) {
var results = [];
var query = document.evaluate(expression, $(parentElement) || document,
null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
- for (var i = 0, len = query.snapshotLength; i < len; i++)
+ for (var i = 0, length = query.snapshotLength; i < length; i++)
results.push(query.snapshotItem(i));
return results;
}
@@ -969,11 +1012,9 @@ document.getElementsByClassName = function(className, parentElement) {
} else {
var children = ($(parentElement) || document.body).getElementsByTagName('*');
var elements = [], child;
- for (var i = 0, len = children.length; i < len; i++) {
+ for (var i = 0, length = children.length; i < length; i++) {
child = children[i];
- if (child.className.length == 0) continue;
- if (child.className == className ||
- child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
+ if (Element.hasClassName(child, className))
elements.push(Element.extend(child));
}
return elements;
@@ -997,9 +1038,11 @@ Element.extend = function(element) {
if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
Object.extend(methods, Form.Element.Methods);
+ Object.extend(methods, Element.Methods.Simulated);
+
for (var property in methods) {
var value = methods[property];
- if (typeof value == 'function')
+ if (typeof value == 'function' && !(property in element))
element[property] = cache.findOrStore(value);
}
}
@@ -1093,6 +1136,13 @@ Element.Methods = {
return $A(element.getElementsByTagName('*'));
},
+ immediateDescendants: function(element) {
+ if (!(element = $(element).firstChild)) return [];
+ while (element && element.nodeType != 1) element = element.nextSibling;
+ if (element) return [element].concat($(element).nextSiblings());
+ return [];
+ },
+
previousSiblings: function(element) {
return $(element).recursivelyCollect('previousSibling');
},
@@ -1139,6 +1189,10 @@ Element.Methods = {
return document.getElementsByClassName(className, element);
},
+ readAttribute: function(element, name) {
+ return $(element).getAttribute(name);
+ },
+
getHeight: function(element) {
element = $(element);
return element.offsetHeight;
@@ -1150,7 +1204,12 @@ Element.Methods = {
hasClassName: function(element, className) {
if (!(element = $(element))) return;
- return Element.classNames(element).include(className);
+ var elementClassName = element.className;
+ if (elementClassName.length == 0) return false;
+ if (elementClassName == className ||
+ elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
+ return true;
+ return false;
},
addClassName: function(element, className) {
@@ -1300,13 +1359,19 @@ Element.Methods = {
}
}
+Element.Methods.Simulated = {
+ hasAttribute: function(element, attribute) {
+ return $(element).getAttributeNode(attribute).specified;
+ }
+}
+
// IE is missing .innerHTML support for TABLE-related elements
if(document.all){
Element.Methods.update = function(element, html) {
element = $(element);
html = typeof html == 'undefined' ? '' : html.toString();
var tagName = element.tagName.toUpperCase();
- if (['THEAD','TBODY','TR','TD'].indexOf(tagName) > -1) {
+ if (['THEAD','TBODY','TR','TD'].include(tagName)) {
var div = document.createElement('div');
switch (tagName) {
case 'THEAD':
@@ -1352,16 +1417,19 @@ if(/Konqueror|Safari|KHTML/.test(navigator.userAgent))
Element.addMethods = function(methods) {
Object.extend(Element.Methods, methods || {});
- function copy(methods, destination) {
+ function copy(methods, destination, onlyIfAbsent) {
+ onlyIfAbsent = onlyIfAbsent || false;
var cache = Element.extend.cache;
for (var property in methods) {
var value = methods[property];
- destination[property] = cache.findOrStore(value);
+ if (!onlyIfAbsent || !(property in destination))
+ destination[property] = cache.findOrStore(value);
}
}
if (typeof HTMLElement != 'undefined') {
copy(Element.Methods, HTMLElement.prototype);
+ copy(Element.Methods.Simulated, HTMLElement.prototype, true);
copy(Form.Methods, HTMLFormElement.prototype);
[HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
copy(Form.Element.Methods, klass.prototype);
@@ -1388,8 +1456,8 @@ Abstract.Insertion.prototype = {
try {
this.element.insertAdjacentHTML(this.adjacency, this.content);
} catch (e) {
- var tagName = this.element.tagName.toLowerCase();
- if (tagName == 'tbody' || tagName == 'tr') {
+ var tagName = this.element.tagName.toUpperCase();
+ if (['TBODY', 'TR'].include(tagName)) {
this.insertContent(this.contentFromAnonymousTable());
} else {
throw e;
@@ -1488,18 +1556,16 @@ Element.ClassNames.prototype = {
add: function(classNameToAdd) {
if (this.include(classNameToAdd)) return;
- this.set(this.toArray().concat(classNameToAdd).join(' '));
+ this.set($A(this).concat(classNameToAdd).join(' '));
},
remove: function(classNameToRemove) {
if (!this.include(classNameToRemove)) return;
- this.set(this.select(function(className) {
- return className != classNameToRemove;
- }).join(' '));
+ this.set($A(this).without(classNameToRemove).join(' '));
},
toString: function() {
- return this.toArray().join(' ');
+ return $A(this).join(' ');
}
}
@@ -1552,7 +1618,7 @@ Selector.prototype = {
if (clause = params.tagName)
conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
if ((clause = params.classNames).length > 0)
- for (var i = 0; i < clause.length; i++)
+ for (var i = 0, length = clause.length; i < length; i++)
conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')');
if (clause = params.attributes) {
clause.each(function(attribute) {
@@ -1594,7 +1660,7 @@ Selector.prototype = {
scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
var results = [];
- for (var i = 0; i < scope.length; i++)
+ for (var i = 0, length = scope.length; i < length; i++)
if (this.match(element = scope[i]))
results.push(Element.extend(element));
@@ -1636,32 +1702,30 @@ var Form = {
reset: function(form) {
$(form).reset();
return form;
+ },
+
+ serializeElements: function(elements) {
+ return elements.inject([], function(queryComponents, element) {
+ var queryComponent = Form.Element.serialize(element);
+ if (queryComponent) queryComponents.push(queryComponent);
+ return queryComponents;
+ }).join('&');
}
};
Form.Methods = {
serialize: function(form) {
- return this.serializeElements(Form.getElements($(form)));
- },
-
- serializeElements: function(elements) {
- var queryComponents = new Array();
-
- for (var i = 0; i < elements.length; i++) {
- var queryComponent = Form.Element.serialize(elements[i]);
- if (queryComponent)
- queryComponents.push(queryComponent);
- }
-
- return queryComponents.join('&');
+ return Form.serializeElements($(form).getElements());
},
getElements: function(form) {
- return $A($(form).getElementsByTagName('*')).inject([], function(elements, child) {
- if (Form.Element.Serializers[child.tagName.toLowerCase()])
- elements.push(Element.extend(child));
- return elements;
- });
+ return $A($(form).getElementsByTagName('*')).inject([],
+ function(elements, child) {
+ if (Form.Element.Serializers[child.tagName.toLowerCase()])
+ elements.push(Element.extend(child));
+ return elements;
+ }
+ );
},
getInputs: function(form, typeName, name) {
@@ -1672,12 +1736,12 @@ Form.Methods = {
return inputs;
var matchingInputs = new Array();
- for (var i = 0; i < inputs.length; i++) {
+ for (var i = 0, length = inputs.length; i < length; i++) {
var input = inputs[i];
if ((typeName && input.type != typeName) ||
(name && input.name != name))
continue;
- matchingInputs.push(input);
+ matchingInputs.push(Element.extend(input));
}
return matchingInputs;
@@ -1685,27 +1749,23 @@ Form.Methods = {
disable: function(form) {
form = $(form);
- var elements = Form.getElements(form);
- for (var i = 0; i < elements.length; i++) {
- var element = elements[i];
+ form.getElements().each(function(element) {
element.blur();
element.disabled = 'true';
- }
+ });
return form;
},
enable: function(form) {
form = $(form);
- var elements = Form.getElements(form);
- for (var i = 0; i < elements.length; i++) {
- var element = elements[i];
+ form.getElements().each(function(element) {
element.disabled = '';
- }
+ });
return form;
},
findFirstElement: function(form) {
- return Form.getElements(form).find(function(element) {
+ return $(form).getElements().find(function(element) {
return element.type != 'hidden' && !element.disabled &&
['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
});
@@ -1713,7 +1773,7 @@ Form.Methods = {
focusFirstElement: function(form) {
form = $(form);
- Field.activate(Form.findFirstElement(form));
+ form.findFirstElement().activate();
return form;
}
}
@@ -1828,18 +1888,20 @@ Form.Element.Serializers = {
selectOne: function(element) {
var value = '', opt, index = element.selectedIndex;
if (index >= 0) {
- opt = element.options[index];
- value = opt.value || opt.text;
+ opt = Element.extend(element.options[index]);
+ // Uses the new potential extension if hasAttribute isn't native.
+ value = opt.hasAttribute('value') ? opt.value : opt.text;
}
return [element.name, value];
},
selectMany: function(element) {
var value = [];
- for (var i = 0; i < element.length; i++) {
- var opt = element.options[i];
+ for (var i = 0, length = element.length; i < length; i++) {
+ var opt = Element.extend(element.options[i]);
if (opt.selected)
- value.push(opt.value || opt.text);
+ // Uses the new potential extension if hasAttribute isn't native.
+ value.push(opt.hasAttribute('value') ? opt.value : opt.text);
}
return [element.name, value];
}
@@ -1913,9 +1975,7 @@ Abstract.EventObserver.prototype = {
},
registerFormCallbacks: function() {
- var elements = Form.getElements(this.element);
- for (var i = 0; i < elements.length; i++)
- this.registerCallback(elements[i]);
+ Form.getElements(this.element).each(this.registerCallback.bind(this));
},
registerCallback: function(element) {
@@ -2019,7 +2079,7 @@ Object.extend(Event, {
unloadCache: function() {
if (!Event.observers) return;
- for (var i = 0; i < Event.observers.length; i++) {
+ for (var i = 0, length = Event.observers.length; i < length; i++) {
Event.stopObserving.apply(this, Event.observers[i]);
Event.observers[i][0] = null;
}