diff options
author | Thomas Fuchs <thomas@fesch.at> | 2005-10-09 16:56:23 +0000 |
---|---|---|
committer | Thomas Fuchs <thomas@fesch.at> | 2005-10-09 16:56:23 +0000 |
commit | 7d101d58400acaff232091485c8e140f0a37cbaf (patch) | |
tree | 3e6ffc8d9ceb9fe44d49f9fa62ec1413c6ec36cc /actionpack/lib/action_view | |
parent | a9de9c48c22f7eab91be676fb648ca89bbfa75b0 (diff) | |
download | rails-7d101d58400acaff232091485c8e140f0a37cbaf.tar.gz rails-7d101d58400acaff232091485c8e140f0a37cbaf.tar.bz2 rails-7d101d58400acaff232091485c8e140f0a37cbaf.zip |
Update Prototype to V1.4.0_pre11, script.aculo.us to [2502] and fix the rails generator to include the new .js files [Thomas Fuchs]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@2503 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'actionpack/lib/action_view')
5 files changed, 448 insertions, 276 deletions
diff --git a/actionpack/lib/action_view/helpers/javascripts/controls.js b/actionpack/lib/action_view/helpers/javascripts/controls.js index 77046d9c35..a7436bcf17 100644 --- a/actionpack/lib/action_view/helpers/javascripts/controls.js +++ b/actionpack/lib/action_view/helpers/javascripts/controls.js @@ -60,7 +60,7 @@ Autocompleter.Base.prototype = { update.style.position = 'absolute'; Position.clone(element, update, {setHeight: false, offsetTop: element.offsetHeight}); } - new Effect.Appear(update,{duration:0.15}); + Effect.Appear(update,{duration:0.15}); }; this.options.onHide = this.options.onHide || function(element, update){ new Effect.Fade(update,{duration:0.15}) }; @@ -87,15 +87,18 @@ Autocompleter.Base.prototype = { 'src="javascript:false;" frameborder="0" scrolling="no"></iframe>'); this.iefix = $(this.update.id+'_iefix'); } - if(this.iefix) { - Position.clone(this.update, this.iefix); - this.iefix.style.zIndex = 1; - this.update.style.zIndex = 2; - Element.show(this.iefix); - } + if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50); + }, + + fixIEOverlapping: function() { + Position.clone(this.update, this.iefix); + this.iefix.style.zIndex = 1; + this.update.style.zIndex = 2; + Element.show(this.iefix); }, hide: function() { + this.stopIndicator(); if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update); if(this.iefix) Element.hide(this.iefix); }, @@ -186,7 +189,7 @@ Autocompleter.Base.prototype = { markPrevious: function() { if(this.index > 0) this.index-- - else this.index = this.entryCcount-1; + else this.index = this.entryCount-1; }, markNext: function() { @@ -420,20 +423,7 @@ Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), { // AJAX in-place editor // -// The constructor takes three parameters. The first is the element -// that should support in-place editing. The second is the url to submit -// the changed value to. The server should respond with the updated -// value (the server might have post-processed it or validation might -// have prevented it from changing). The third is a hash of options. -// -// Supported options are (all are optional and have sensible defaults): -// - okText - The text of the submit button that submits the changed value -// to the server (default: "ok") -// - cancelText - The text of the link that cancels editing (default: "cancel") -// - savingText - The text being displayed as the AJAX engine communicates -// with the server (default: "Saving...") -// - formId - The id given to the <form> element -// (default: the id of the element to edit plus '-inplaceeditor') +// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor Ajax.InPlaceEditor = Class.create(); Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99"; @@ -461,6 +451,7 @@ Ajax.InPlaceEditor.prototype = { handleLineBreaks: true, loadingText: 'Loading...', savingClassName: 'inplaceeditor-saving', + loadingClassName: 'inplaceeditor-loading', formClassName: 'inplaceeditor-form', highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor, highlightendcolor: "#FFFFFF", @@ -508,7 +499,7 @@ Ajax.InPlaceEditor.prototype = { Element.hide(this.options.externalControl); } Element.hide(this.element); - this.form = this.getForm(); + this.createForm(); this.element.parentNode.insertBefore(this.form, this.element); Field.focus(this.editField); // stop the event to avoid a page refresh in Safari @@ -516,30 +507,29 @@ Ajax.InPlaceEditor.prototype = { Event.stop(arguments[0]); } }, - getForm: function() { - form = document.createElement("form"); - form.id = this.options.formId; - Element.addClassName(form, this.options.formClassName) - form.onsubmit = this.onSubmit.bind(this); + createForm: function() { + this.form = document.createElement("form"); + this.form.id = this.options.formId; + Element.addClassName(this.form, this.options.formClassName) + this.form.onsubmit = this.onSubmit.bind(this); - this.createEditField(form); + this.createEditField(); if (this.options.textarea) { var br = document.createElement("br"); - form.appendChild(br); + this.form.appendChild(br); } okButton = document.createElement("input"); okButton.type = "submit"; okButton.value = this.options.okText; - form.appendChild(okButton); + this.form.appendChild(okButton); cancelLink = document.createElement("a"); cancelLink.href = "#"; cancelLink.appendChild(document.createTextNode(this.options.cancelText)); cancelLink.onclick = this.onclickCancel.bind(this); - form.appendChild(cancelLink); - return form; + this.form.appendChild(cancelLink); }, hasHTMLLineBreaks: function(string) { if (!this.options.handleLineBreaks) return false; @@ -548,49 +538,57 @@ Ajax.InPlaceEditor.prototype = { convertHTMLLineBreaks: function(string) { return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, ""); }, - createEditField: function(form) { - if (this.options.rows == 1 && !this.hasHTMLLineBreaks(this.getText())) { + createEditField: function() { + var text; + if(this.options.loadTextURL) { + text = this.options.loadingText; + } else { + text = this.getText(); + } + + if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) { this.options.textarea = false; var textField = document.createElement("input"); textField.type = "text"; textField.name = "value"; - textField.value = this.getText(); + textField.value = text; textField.style.backgroundColor = this.options.highlightcolor; var size = this.options.size || this.options.cols || 0; - if (size != 0) - textField.size = size; - form.appendChild(textField); + if (size != 0) textField.size = size; this.editField = textField; } else { this.options.textarea = true; var textArea = document.createElement("textarea"); textArea.name = "value"; - textArea.value = this.convertHTMLLineBreaks(this.getText()); + textArea.value = this.convertHTMLLineBreaks(text); textArea.rows = this.options.rows; textArea.cols = this.options.cols || 40; - form.appendChild(textArea); this.editField = textArea; } - }, - getText: function() { - if (this.options.loadTextURL) { + + if(this.options.loadTextURL) { this.loadExternalText(); - return this.options.loadingText; - } else { - return this.element.innerHTML; } + this.form.appendChild(this.editField); + }, + getText: function() { + return this.element.innerHTML; }, loadExternalText: function() { + Element.addClassName(this.form, this.options.loadingClassName); + this.editField.disabled = true; new Ajax.Request( this.options.loadTextURL, - { + Object.extend({ asynchronous: true, onComplete: this.onLoadedExternalText.bind(this) - } + }, this.options.ajaxOptions) ); }, onLoadedExternalText: function(transport) { - this.form.value.value = transport.responseText.stripTags(); + Element.removeClassName(this.form, this.options.loadingClassName); + this.editField.disabled = false; + this.editField.value = transport.responseText.stripTags(); }, onclickCancel: function() { this.onComplete(); @@ -606,7 +604,15 @@ Ajax.InPlaceEditor.prototype = { return false; }, onSubmit: function() { - this.saving = true; + // onLoading resets these so we need to save them away for the Ajax call + var form = this.form; + var value = this.editField.value; + + // do this first, sometimes the ajax call returns before we get a chance to switch on Saving... + // which means this will actually switch on Saving... *after* we've left edit mode causing Saving... + // to be displayed indefinitely + this.onLoading(); + new Ajax.Updater( { success: this.element, @@ -615,12 +621,11 @@ Ajax.InPlaceEditor.prototype = { }, this.url, Object.extend({ - parameters: this.options.callback(this.form, this.editField.value), + parameters: this.options.callback(form, value), onComplete: this.onComplete.bind(this), onFailure: this.onFailure.bind(this) }, this.options.ajaxOptions) ); - this.onLoading(); // stop the event to avoid a page refresh in Safari if (arguments.length > 1) { Event.stop(arguments[0]); @@ -642,7 +647,7 @@ Ajax.InPlaceEditor.prototype = { }, removeForm: function() { if(this.form) { - Element.remove(this.form); + if (this.form.parentNode) Element.remove(this.form); this.form = null; } }, diff --git a/actionpack/lib/action_view/helpers/javascripts/dragdrop.js b/actionpack/lib/action_view/helpers/javascripts/dragdrop.js index a8ed953a7f..5445d748c3 100644 --- a/actionpack/lib/action_view/helpers/javascripts/dragdrop.js +++ b/actionpack/lib/action_view/helpers/javascripts/dragdrop.js @@ -10,7 +10,7 @@ var Droppables = { drops: [], remove: function(element) { - this.drops = this.drops.reject(function(e) { return e==element }); + this.drops = this.drops.reject(function(d) { return d.element==element }); }, add: function(element) { @@ -93,7 +93,7 @@ var Droppables = { if (this.isAffected(Event.pointerX(event), Event.pointerY(event), element, this.last_active)) if (this.last_active.onDrop) - this.last_active.onDrop(element, this.last_active.element); + this.last_active.onDrop(element, this.last_active.element, event); }, reset: function() { @@ -137,7 +137,11 @@ Draggable.prototype = { }, arguments[1] || {}); this.element = $(element); - this.handle = options.handle ? $(options.handle) : this.element; + if(options.handle && (typeof options.handle == 'string')) + this.handle = Element.Class.childrenWith(this.element, options.handle)[0]; + + if(!this.handle) this.handle = $(options.handle); + if(!this.handle) this.handle = this.element; Element.makePositioned(this.element); // fix IE @@ -147,7 +151,6 @@ Draggable.prototype = { this.originalTop = this.currentTop(); this.originalX = this.element.offsetLeft; this.originalY = this.element.offsetTop; - this.originalZ = parseInt(this.element.style.zIndex || "0"); this.options = options; @@ -230,7 +233,8 @@ Draggable.prototype = { this.originalTop = this.currentTop(); } - this.element.style.zIndex = this.originalZ; + if(this.options.zindex) + this.element.style.zIndex = this.originalZ; if(this.options.endeffect) this.options.endeffect(this.element); @@ -271,8 +275,14 @@ Draggable.prototype = { if(!this.dragging) { var style = this.element.style; this.dragging = true; - if(style.position=="") style.position = "relative"; - style.zIndex = this.options.zindex; + + if(Element.getStyle(this.element,'position')=='') + style.position = "relative"; + + if(this.options.zindex) { + this.options.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0); + style.zIndex = this.options.zindex; + } if(this.options.ghosting) { this._clone = this.element.cloneNode(true); @@ -344,6 +354,7 @@ var Sortable = { only: false, hoverclass: null, ghosting: false, + format: null, onChange: function() {}, onUpdate: function() {} }, arguments[1] || {}); @@ -494,11 +505,12 @@ var Sortable = { var options = Object.extend({ tag: sortableOptions.tag, only: sortableOptions.only, - name: element.id + name: element.id, + format: sortableOptions.format || /^[^_]*_(.*)$/ }, arguments[1] || {}); - return $A(element.childNodes).collect( function(item) { + return $(this.findElements(element, options) || []).collect( function(item) { return (encodeURIComponent(options.name) + "[]=" + - encodeURIComponent(item.id.split("_")[1])); + encodeURIComponent(item.id.match(options.format) ? item.id.match(options.format)[1] : '')); }).join("&"); } }
\ No newline at end of file diff --git a/actionpack/lib/action_view/helpers/javascripts/effects.js b/actionpack/lib/action_view/helpers/javascripts/effects.js index d6fbed805e..9e8f8f4965 100644 --- a/actionpack/lib/action_view/helpers/javascripts/effects.js +++ b/actionpack/lib/action_view/helpers/javascripts/effects.js @@ -120,6 +120,7 @@ Effect.Queue = { Effect.Base = function() {}; Effect.Base.prototype = { + position: null, setOptions: function(options) { this.options = Object.extend({ transition: Effect.Transitions.sinoidal, @@ -169,6 +170,7 @@ Effect.Base.prototype = { if(this.options.transition) pos = this.options.transition(pos); pos *= (this.options.to-this.options.from); pos += this.options.from; + this.position = pos; this.event('beforeUpdate'); if(this.update) this.update(pos); this.event('afterUpdate'); @@ -207,11 +209,9 @@ Effect.Opacity = Class.create(); Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), { initialize: function(element) { this.element = $(element); - // make this work on IE on elements without 'layout' if(/MSIE/.test(navigator.userAgent) && (!this.element.hasLayout)) this.element.style.zoom = 1; - var options = Object.extend({ from: Element.getOpacity(this.element) || 0.0, to: 1.0 @@ -268,69 +268,65 @@ Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), { this.start(options); }, setup: function() { + var effect = this; + this.restoreAfterFinish = this.options.restoreAfterFinish || false; this.elementPositioning = Element.getStyle(this.element,'position'); - this.elementStyleTop = this.element.style.top; - this.elementStyleLeft = this.element.style.left; - this.elementStyleWidth = this.element.style.width; - this.elementStyleHeight = this.element.style.height; - this.elementStyleFontSize = this.element.style.fontSize; - this.originalTop = this.element.offsetTop; - this.originalLeft = this.element.offsetLeft; + + effect.originalStyle = {}; + ['top','left','width','height','fontSize'].each( function(k) { + effect.originalStyle[k] = effect.element.style[k]; + }); + + this.originalTop = this.element.offsetTop; + this.originalLeft = this.element.offsetLeft; + var fontSize = Element.getStyle(this.element,'font-size') || "100%"; - if(fontSize.indexOf("em")>0) { - this.fontSize = parseFloat(fontSize); - this.fontSizeType = "em"; - } else if(fontSize.indexOf("px")>0) { - this.fontSize = parseFloat(fontSize); - this.fontSizeType = "px"; - } else if(fontSize.indexOf("%")>0) { - this.fontSize = parseFloat(fontSize); - this.fontSizeType = "%"; - } + ['em','px','%'].each( function(fontSizeType) { + if(fontSize.indexOf(fontSizeType)>0) { + effect.fontSize = parseFloat(fontSize); + effect.fontSizeType = fontSizeType; + } + }); + this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; - if(this.options.scaleMode=='box') { - this.originalHeight = this.element.clientHeight; - this.originalWidth = this.element.clientWidth; - } else if(this.options.scaleMode=='contents') { - this.originalHeight = this.element.scrollHeight; - this.originalWidth = this.element.scrollWidth; - } else { - this.originalHeight = this.options.scaleMode.originalHeight; - this.originalWidth = this.options.scaleMode.originalWidth; - } + + this.dims = null; + if(this.options.scaleMode=='box') + this.dims = [this.element.clientHeight, this.element.clientWidth]; + if(this.options.scaleMode=='content') + this.dims = [this.element.scrollHeight, this.element.scrollWidth]; + if(!this.dims) + this.dims = [this.options.scaleMode.originalHeight, + this.options.scaleMode.originalWidth]; }, update: function(position) { var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); if(this.options.scaleContent && this.fontSize) this.element.style.fontSize = this.fontSize*currentScale + this.fontSizeType; - this.setDimensions( - this.originalWidth * currentScale, - this.originalHeight * currentScale); + this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); }, finish: function(position) { if (this.restoreAfterFinish) { - var els = this.element.style; - els.top = this.elementStyleTop; - els.left = this.elementStyleLeft; - els.width = this.elementStyleWidth; - els.height = this.elementStyleHeight; - els.height = this.elementStyleHeight; - els.fontSize = this.elementStyleFontSize; + var effect = this; + ['top','left','width','height','fontSize'].each( function(k) { + effect.element.style[k] = effect.originalStyle[k]; + }); } }, - setDimensions: function(width, height) { - if(this.options.scaleX) this.element.style.width = width + 'px'; - if(this.options.scaleY) this.element.style.height = height + 'px'; + setDimensions: function(height, width) { + var els = this.element.style; + if(this.options.scaleX) els.width = width + 'px'; + if(this.options.scaleY) els.height = height + 'px'; if(this.options.scaleFromCenter) { - var topd = (height - this.originalHeight)/2; - var leftd = (width - this.originalWidth)/2; + var topd = (height - this.dims[0])/2; + var leftd = (width - this.dims[1])/2; if(this.elementPositioning == 'absolute') { - if(this.options.scaleY) this.element.style.top = this.originalTop-topd + "px"; - if(this.options.scaleX) this.element.style.left = this.originalLeft-leftd + "px"; + if(this.options.scaleY) els.top = this.originalTop-topd + "px"; + if(this.options.scaleX) els.left = this.originalLeft-leftd + "px"; } else { - if(this.options.scaleY) this.element.style.top = -topd + "px"; - if(this.options.scaleX) this.element.style.left = -leftd + "px"; + if(this.options.scaleY) els.top = -topd + "px"; + if(this.options.scaleX) els.left = -leftd + "px"; } } } @@ -364,10 +360,9 @@ Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), parseInt(this.options.endcolor.slice(5),16)-this.colors_base[2]]; }, update: function(position) { - var colors = [ - Math.round(this.colors_base[0]+(this.colors_delta[0]*position)), - Math.round(this.colors_base[1]+(this.colors_delta[1]*position)), - Math.round(this.colors_base[2]+(this.colors_delta[2]*position)) ]; + var effect = this; var colors = $R(0,2).map( function(i){ + return Math.round(effect.colors_base[i]+(effect.colors_delta[i]*position)) + }); this.element.style.backgroundColor = "#" + colors[0].toColorPart() + colors[1].toColorPart() + colors[2].toColorPart(); }, diff --git a/actionpack/lib/action_view/helpers/javascripts/prototype.js b/actionpack/lib/action_view/helpers/javascripts/prototype.js index c0ec65450d..9f5180315d 100644 --- a/actionpack/lib/action_view/helpers/javascripts/prototype.js +++ b/actionpack/lib/action_view/helpers/javascripts/prototype.js @@ -1,4 +1,4 @@ -/* Prototype JavaScript framework, version 1.4.0_pre7 +/* Prototype JavaScript framework, version 1.4.0_pre11 * (c) 2005 Sam Stephenson <sam@conio.net> * * THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff @@ -11,7 +11,7 @@ /*--------------------------------------------------------------------------*/ var Prototype = { - Version: '1.4.0_pre7', + Version: '1.4.0_pre11', emptyFunction: function() {}, K: function(x) {return x} @@ -34,6 +34,17 @@ Object.extend = function(destination, source) { return destination; } +Object.inspect = function(object) { + try { + if (object == undefined) return 'undefined'; + if (object == null) return 'null'; + return object.inspect ? object.inspect() : object.toString(); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } +} + Function.prototype.bind = function(object) { var __method = this; return function() { @@ -128,34 +139,6 @@ function $() { return elements; } -if (!Array.prototype.push) { - Array.prototype.push = function() { - var startLength = this.length; - for (var i = 0; i < arguments.length; i++) - this[startLength + i] = arguments[i]; - return this.length; - } -} - -if (!Function.prototype.apply) { - // Based on code from http://www.youngpup.net/ - Function.prototype.apply = function(object, parameters) { - var parameterStrings = new Array(); - if (!object) object = window; - if (!parameters) parameters = new Array(); - - for (var i = 0; i < parameters.length; i++) - parameterStrings[i] = 'parameters[' + i + ']'; - - object.__apply__ = this; - var result = eval('object.__apply__(' + - parameterStrings.join(', ') + ')'); - object.__apply__ = null; - - return result; - } -} - Object.extend(String.prototype, { stripTags: function() { return this.replace(/<\/?[^>]+>/gi, ''); @@ -171,27 +154,28 @@ Object.extend(String.prototype, { unescapeHTML: function() { var div = document.createElement('div'); div.innerHTML = this.stripTags(); - return div.childNodes[0].nodeValue; + return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; }, - parseQuery: function() { - var str = this; - if (str.substring(0,1) == '?') { - str = this.substring(1); - } - var result = {}; - var pairs = str.split('&'); - for (var i = 0; i < pairs.length; i++) { - var pair = pairs[i].split('='); - result[pair[0]] = pair[1]; - } - return result; + toQueryParams: function() { + var pairs = this.match(/^\??(.*)$/)[1].split('&'); + return pairs.inject({}, function(params, pairString) { + var pair = pairString.split('='); + params[pair[0]] = pair[1]; + return params; + }); + }, + + inspect: function() { + return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'"; } }); +String.prototype.parseQuery = String.prototype.toQueryParams; -var _break = new Object(); -var _continue = new Object(); + +var $break = new Object(); +var $continue = new Object(); var Enumerable = { each: function(iterator) { @@ -201,11 +185,11 @@ var Enumerable = { try { iterator(value, index++); } catch (e) { - if (e != _continue) throw e; + if (e != $continue) throw e; } }); } catch (e) { - if (e != _break) throw e; + if (e != $break) throw e; } }, @@ -213,7 +197,7 @@ var Enumerable = { var result = true; this.each(function(value, index) { if (!(result &= (iterator || Prototype.K)(value, index))) - throw _break; + throw $break; }); return result; }, @@ -222,7 +206,7 @@ var Enumerable = { var result = true; this.each(function(value, index) { if (result &= (iterator || Prototype.K)(value, index)) - throw _break; + throw $break; }); return result; }, @@ -240,7 +224,7 @@ var Enumerable = { this.each(function(value, index) { if (iterator(value, index)) { result = value; - throw _break; + throw $break; } }); return result; @@ -270,7 +254,7 @@ var Enumerable = { this.each(function(value) { if (value == object) { found = true; - throw _break; + throw $break; } }); return found; @@ -359,6 +343,10 @@ var Enumerable = { iterator(value = collections.pluck(index)); return value; }); + }, + + inspect: function() { + return '#<Enumerable:' + this.toArray().inspect() + '>'; } } @@ -381,6 +369,8 @@ var $A = Array.from = function(iterable) { } } +Object.extend(Array.prototype, Enumerable); + Object.extend(Array.prototype, { _each: function(iterator) { for (var i = 0; i < this.length; i++) @@ -393,10 +383,80 @@ Object.extend(Array.prototype, { last: function() { return this[this.length - 1]; + }, + + compact: function() { + return this.select(function(value) { + return value != undefined || value != null; + }); + }, + + flatten: function() { + return this.inject([], function(array, value) { + return array.concat(value.constructor == Array ? + value.flatten() : [value]); + }); + }, + + without: function() { + var values = $A(arguments); + return this.select(function(value) { + return !values.include(value); + }); + }, + + inspect: function() { + return '[' + this.map(Object.inspect).join(', ') + ']'; } }); -Object.extend(Array.prototype, Enumerable); +var Hash = { + _each: function(iterator) { + for (key in this) { + var value = this[key]; + if (typeof value == 'function') continue; + + var pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + }, + + keys: function() { + return this.pluck('key'); + }, + + values: function() { + return this.pluck('value'); + }, + + merge: function(hash) { + return $H(hash).inject($H(this), function(mergedHash, pair) { + mergedHash[pair.key] = pair.value; + return mergedHash; + }); + }, + + toQueryString: function() { + return this.map(function(pair) { + return pair.map(encodeURIComponent).join('='); + }).join('&'); + }, + + inspect: function() { + return '#<Hash:{' + this.map(function(pair) { + return pair.map(Object.inspect).join(': '); + }).join(', ') + '}>'; + } +} + +function $H(object) { + var hash = Object.extend({}, object || {}); + Object.extend(hash, Enumerable); + Object.extend(hash, Hash); + return hash; +} var Range = Class.create(); Object.extend(Range.prototype, Enumerable); @@ -435,9 +495,51 @@ var Ajax = { function() {return new ActiveXObject('Microsoft.XMLHTTP')}, function() {return new XMLHttpRequest()} ) || false; - } + }, + + activeRequestCount: 0 } +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responderToAdd) { + if (!this.include(responderToAdd)) + this.responders.push(responderToAdd); + }, + + unregister: function(responderToRemove) { + this.responders = this.responders.without(responderToRemove); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (responder[callback] && typeof responder[callback] == 'function') { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) { + } + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { + Ajax.activeRequestCount++; + }, + + onComplete: function() { + Ajax.activeRequestCount--; + } +}); + Ajax.Base = function() {}; Ajax.Base.prototype = { setOptions: function(options) { @@ -476,10 +578,13 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), { if (parameters.length > 0) parameters += '&_='; try { - if (this.options.method == 'get') - url += '?' + parameters; - - this.transport.open(this.options.method, url, + this.url = url; + if (this.options.method == 'get') + this.url += '?' + parameters; + + Ajax.Responders.dispatch('onCreate', this, this.transport); + + this.transport.open(this.options.method, this.url, this.options.asynchronous); if (this.options.asynchronous) { @@ -545,6 +650,7 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), { || Prototype.emptyFunction)(transport, json); (this.options['on' + event] || Prototype.emptyFunction)(transport, json); + Ajax.Responders.dispatch('on' + event, this, transport, json); /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ if (event == 'Complete') @@ -649,22 +755,13 @@ Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { } }); -document.getElementsByClassName = function(className) { - var children = document.getElementsByTagName('*') || document.all; - var elements = new Array(); - - for (var i = 0; i < children.length; i++) { - var child = children[i]; - var classNames = child.className.split(' '); - for (var j = 0; j < classNames.length; j++) { - if (classNames[j] == className) { - elements.push(child); - break; - } - } - } - - return elements; +document.getElementsByClassName = function(className, parentElement) { + var children = (document.body || $(parentElement)).getElementsByTagName('*'); + return $A(children).inject([], function(elements, child) { + if (Element.hasClassName(child, className)) + elements.push(child); + return elements; + }); } /*--------------------------------------------------------------------------*/ @@ -674,11 +771,14 @@ if (!window.Element) { } Object.extend(Element, { + visible: function(element) { + return $(element).style.display != 'none'; + }, + toggle: function() { for (var i = 0; i < arguments.length; i++) { var element = $(arguments[i]); - element.style.display = - (element.style.display == 'none' ? '' : 'none'); + Element[Element.visible(element) ? 'show' : 'hide'](element); } }, @@ -688,7 +788,7 @@ Object.extend(Element, { element.style.display = 'none'; } }, - + show: function() { for (var i = 0; i < arguments.length; i++) { var element = $(arguments[i]); @@ -700,54 +800,50 @@ Object.extend(Element, { element = $(element); element.parentNode.removeChild(element); }, - + getHeight: function(element) { element = $(element); return element.offsetHeight; }, + + classNames: function(element) { + return new Element.ClassNames(element); + }, hasClassName: function(element, className) { - element = $(element); - if (!element) - return; - var a = element.className.split(' '); - for (var i = 0; i < a.length; i++) { - if (a[i] == className) - return true; - } - return false; + if (!(element = $(element))) return; + return Element.classNames(element).include(className); }, addClassName: function(element, className) { - element = $(element); - Element.removeClassName(element, className); - element.className += ' ' + className; + if (!(element = $(element))) return; + return Element.classNames(element).add(className); }, removeClassName: function(element, className) { - element = $(element); - if (!element) - return; - var newClassName = ''; - var a = element.className.split(' '); - for (var i = 0; i < a.length; i++) { - if (a[i] != className) { - if (i > 0) - newClassName += ' '; - newClassName += a[i]; - } - } - element.className = newClassName; + if (!(element = $(element))) return; + return Element.classNames(element).remove(className); }, // removes whitespace-only text node children cleanWhitespace: function(element) { - var element = $(element); + element = $(element); for (var i = 0; i < element.childNodes.length; i++) { var node = element.childNodes[i]; if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) Element.remove(node); } + }, + + empty: function(element) { + return $(element).innerHTML.match(/^\s*$/); + }, + + scrollTo: function(element) { + element = $(element); + var x = element.x ? element.x : element.offsetLeft, + y = element.y ? element.y : element.offsetTop; + window.scrollTo(x, y); } }); @@ -840,6 +936,43 @@ Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { } }); +/*--------------------------------------------------------------------------*/ + +Element.ClassNames = Class.create(); +Element.ClassNames.prototype = { + initialize: function(element) { + this.element = $(element); + }, + + _each: function(iterator) { + this.element.className.split(/\s+/).select(function(name) { + return name.length > 0; + })._each(iterator); + }, + + set: function(className) { + this.element.className = className; + }, + + add: function(classNameToAdd) { + if (this.include(classNameToAdd)) return; + this.set(this.toArray().concat(classNameToAdd).join(' ')); + }, + + remove: function(classNameToRemove) { + if (!this.include(classNameToRemove)) return; + this.set(this.select(function(className) { + return className != classNameToRemove; + })); + }, + + toString: function() { + return this.toArray().join(' '); + } +} + +Object.extend(Element.ClassNames.prototype, Enumerable); + var Field = { clear: function() { for (var i = 0; i < arguments.length; i++) diff --git a/actionpack/lib/action_view/helpers/javascripts/util.js b/actionpack/lib/action_view/helpers/javascripts/util.js index c83101b7d2..279bd469a6 100644 --- a/actionpack/lib/action_view/helpers/javascripts/util.js +++ b/actionpack/lib/action_view/helpers/javascripts/util.js @@ -2,7 +2,8 @@ // // See scriptaculous.js for full license. -Object.inspect = function(obj) { + +Object.debug = function(obj) { var info = []; if(typeof obj in ["string","number"]) { @@ -20,32 +21,6 @@ Object.inspect = function(obj) { ": {" + info.join(", ") + "}"); } -// borrowed from http://www.schuerig.de/michael/javascript/stdext.js -// Copyright (c) 2005, Michael Schuerig, michael@schuerig.de - -Array.flatten = function(array, excludeUndefined) { - if (excludeUndefined === undefined) { - excludeUndefined = false; - } - var result = []; - var len = array.length; - for (var i = 0; i < len; i++) { - var el = array[i]; - if (el instanceof Array) { - var flat = el.flatten(excludeUndefined); - result = result.concat(flat); - } else if (!excludeUndefined || el != undefined) { - result.push(el); - } - } - return result; -}; - -if (!Array.prototype.flatten) { - Array.prototype.flatten = function(excludeUndefined) { - return Array.flatten(this, excludeUndefined); - } -} String.prototype.toArray = function() { var results = []; @@ -57,28 +32,70 @@ String.prototype.toArray = function() { /*--------------------------------------------------------------------------*/ var Builder = { + NODEMAP: { + AREA: 'map', + CAPTION: 'table', + COL: 'table', + COLGROUP: 'table', + LEGEND: 'fieldset', + OPTGROUP: 'select', + OPTION: 'select', + PARAM: 'object', + TBODY: 'table', + TD: 'table', + TFOOT: 'table', + TH: 'table', + THEAD: 'table', + TR: 'table' + }, + // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken, + // due to a Firefox bug node: function(elementName) { - var element = document.createElement('div'); - element.innerHTML = - "<" + elementName + "></" + elementName + ">"; + elementName = elementName.toUpperCase(); + + // try innerHTML approach + var parentTag = this.NODEMAP[elementName] || 'div'; + var parentElement = document.createElement(parentTag); + parentElement.innerHTML = "<" + elementName + "></" + elementName + ">"; + var element = parentElement.firstChild || null; + + // see if browser added wrapping tags + if(element && (element.tagName != elementName)) + element = element.getElementsByTagName(elementName)[0]; + + // fallback to createElement approach + if(!element) element = document.createElement(elementName); + + // abort if nothing could be created + if(!element) return; // attributes (or text) if(arguments[1]) if(this._isStringOrNumber(arguments[1]) || (arguments[1] instanceof Array)) { - this._children(element.firstChild, arguments[1]); + this._children(element, arguments[1]); } else { var attrs = this._attributes(arguments[1]); - if(attrs.length) - element.innerHTML = "<" +elementName + " " + + if(attrs.length) { + parentElement.innerHTML = "<" +elementName + " " + attrs + "></" + elementName + ">"; + element = parentElement.firstChild || null; + // workaround firefox 1.0.X bug + if(!element) { + element = document.createElement(elementName); + for(attr in arguments[1]) + element[attr == 'class' ? 'className' : attr] = arguments[1][attr]; + } + if(element.tagName != elementName) + element = parentElement.getElementsByTagName(elementName)[0]; + } } // text, or array of children if(arguments[2]) - this._children(element.firstChild, arguments[2]); + this._children(element, arguments[2]); - return element.firstChild; + return element; }, _text: function(text) { return document.createTextNode(text); @@ -229,7 +246,12 @@ Element.setContentZoom = function(element, percent) { } Element.getOpacity = function(element){ - return parseFloat(Element.getStyle(element, "opacity") || '1'); + var opacity; + if (opacity = Element.getStyle(element, "opacity")) + return parseFloat(opacity); + if (opacity = (Element.getStyle(element, "filter") || '').match(/alpha\(opacity=(.*)\)/)) + if(opacity[1]) return parseFloat(opacity[1]) / 100; + return 1.0; } Element.setOpacity = function(element, value){ @@ -237,11 +259,14 @@ Element.setOpacity = function(element, value){ var els = element.style; if (value == 1){ els.opacity = '0.999999'; - els.filter = null; + if(/MSIE/.test(navigator.userAgent)) + els.filter = Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,''); } else { if(value < 0.00001) value = 0; els.opacity = value; - els.filter = "alpha(opacity:"+value*100+")"; + if(/MSIE/.test(navigator.userAgent)) + els.filter = Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') + + "alpha(opacity="+value*100+")"; } } @@ -261,22 +286,24 @@ Element.setInlineOpacity = function(element, value){ Element.getDimensions = function(element){ element = $(element); - // All *Width and *Height properties give 0 on elements with display "none", so enable the element temporarily - if (element.style.display == "none"){ - var originalVisibility = element.style.visibility; - var originalPosition = element.style.position; - element.style.visibility = "hidden"; - element.style.position = "absolute"; - element.style.display = ""; + // All *Width and *Height properties give 0 on elements with display "none", + // so enable the element temporarily + if (Element.getStyle(element,'display') == "none"){ + var els = element.style; + var originalVisibility = els.visibility; + var originalPosition = els.position; + els.visibility = "hidden"; + els.position = "absolute"; + els.display = ""; var originalWidth = element.clientWidth; var originalHeight = element.clientHeight; - element.style.display = "none"; - element.style.position = originalPosition; - element.style.visibility = originalVisibility; + els.display = "none"; + els.position = originalPosition; + els.visibility = originalVisibility; return {width: originalWidth, height: originalHeight}; - } else { - return {width: element.offsetWidth, height: element.offsetHeight}; } + + return {width: element.offsetWidth, height: element.offsetHeight}; } /*--------------------------------------------------------------------------*/ @@ -445,18 +472,18 @@ Element.Class = { // gets space-delimited classnames of an element as an array get: function(element) { - element = $(element); - return element.className.split(' '); + return $(element).className.split(' '); }, // functions adapted from original functions by Gavin Kistner remove: function(element) { element = $(element); - var regEx; - for(var i = 1; i < arguments.length; i++) { - regEx = new RegExp("(^|\\s)" + arguments[i] + "(\\s|$)", 'g'); - element.className = element.className.replace(regEx, '') - } + var removeClasses = arguments; + $R(1,arguments.length-1).each( function(index) { + element.className = + element.className.split(' ').reject( + function(klass) { return (klass == removeClasses[index]) } ).join(' '); + }); }, add: function(element) { |