diff options
Diffstat (limited to 'actionpack')
-rw-r--r-- | actionpack/CHANGELOG | 2 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/javascripts/prototype.js | 418 |
2 files changed, 241 insertions, 179 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; } |