diff options
Diffstat (limited to 'actionpack/lib/action_view/helpers/javascripts')
4 files changed, 1416 insertions, 182 deletions
diff --git a/actionpack/lib/action_view/helpers/javascripts/controls.js b/actionpack/lib/action_view/helpers/javascripts/controls.js new file mode 100644 index 0000000000..94d438a784 --- /dev/null +++ b/actionpack/lib/action_view/helpers/javascripts/controls.js @@ -0,0 +1,218 @@ +// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Ajax.Autocompleter = Class.create(); +Ajax.Autocompleter.prototype = (new Ajax.Base()).extend({ + initialize: function(element, update, url, options) { + this.element = $(element); + this.update = $(update); + this.has_focus = false; + this.changed = false; + this.active = false; + this.index = 0; + this.entry_count = 0; + this.url = url; + + this.setOptions(options); + this.options.asynchronous = true; + this.options.onComplete = this.onComplete.bind(this) + this.options.frequency = this.options.frequency || 0.4; + this.options.min_chars = this.options.min_chars || 1; + this.options.method = 'post'; + + if(this.options.indicator) + this.indicator = $(this.options.indicator); + + this.observer = null; + + Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this)); + Event.observe(document, "click", this.onBlur.bindAsEventListener(this)); + }, + + show: function() { + Element.show(this.update); + if(!this.iefix && (navigator.appVersion.indexOf('MSIE')>0)) { + new Insertion.Before(this.update, + '<iframe id="' + this.update.id + '_iefix" style="display:none;" src="javascript:false;" frameborder="0" scrolling="no"></iframe>'); + this.iefix = $(this.update.id+'_iefix'); + this.iefix.style.position = 'absolute'; + this.iefix.style.zIndex = 1; + this.update.style.zIndex = 2; + } + if(this.iefix) { + Position.clone(this.update, this.iefix); + Element.show(this.iefix); + } + }, + + hide: function() { + if(this.iefix) Element.hide(this.iefix); + Element.hide(this.update); + }, + + startIndicator: function() { + if(this.indicator) Element.show(this.indicator); + }, + + stopIndicator: function() { + if(this.indicator) Element.hide(this.indicator); + }, + + onObserverEvent: function() { + this.changed = false; + if(this.element.value.length>=this.options.min_chars) { + this.startIndicator(); + this.options.parameters = this.options.callback ? + this.options.callback(this.element, Form.Element.getValue(this.element)) : + Form.Element.getValue(this.element); + new Ajax.Request(this.url, this.options); + } else { + this.active = false; + this.hide(); + } + }, + + onComplete: function(request) { + if(!this.changed) { + this.update.innerHTML = request.responseText; + + if(this.update.firstChild && this.update.firstChild.childNodes) { + this.entry_count = + this.update.firstChild.childNodes.length; + for (var i = 0; i < this.entry_count; i++) { + entry = this.get_entry(i); + entry.autocompleteIndex = i; + Event.observe(entry, "mouseover", this.onHover.bindAsEventListener(this)); + Event.observe(entry, "click", this.onClick.bindAsEventListener(this)); + } + } else { + this.entry_count = 0; + } + + this.stopIndicator(); + + this.index = 0; + this.render(); + } + }, + + onKeyPress: function(event) { + if(this.active) + switch(event.keyCode) { + case Event.KEY_TAB: + case Event.KEY_RETURN: + this.select_entry(); + Event.stop(event); + case Event.KEY_ESC: + this.hide(); + this.active = false; + return; + case Event.KEY_LEFT: + case Event.KEY_RIGHT: + return; + case Event.KEY_UP: + this.mark_previous(); + this.render(); + return; + case Event.KEY_DOWN: + this.mark_next(); + this.render(); + return; + } + else + if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN) + return; + + this.changed = true; + this.has_focus = true; + + if(this.observer) clearTimeout(this.observer); + this.observer = + setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000); + }, + + onHover: function(event) { + element = Event.findElement(event, 'LI'); + if(this.index != element.autocompleteIndex) + { + this.index = element.autocompleteIndex; + this.render(); + } + }, + + onClick: function(event) { + element = Event.findElement(event, 'LI'); + this.index = element.autocompleteIndex; + this.select_entry(); + }, + + onBlur: function(event) { + element = Event.element(event); + if(element==this.update) return; + while(element.parentNode) + { element = element.parentNode; if(element==this.update) return; } + this.hide(); + this.active = false; + }, + + render: function() { + if(this.entry_count > 0) { + for (var i = 0; i < this.entry_count; i++) + this.index==i ? + Element.Class.add(this.get_entry(i),"selected") : + Element.Class.remove(this.get_entry(i),"selected"); + + if(this.has_focus) { + if(this.get_current_entry().scrollIntoView) + this.get_current_entry().scrollIntoView(false); + + this.show(); + this.active = true; + } + } else this.hide(); + }, + + mark_previous: function() { + if(this.index > 0) this.index-- + else this.index = this.entry_count-1; + }, + + mark_next: function() { + if(this.index < this.entry_count-1) this.index++ + else this.index = 0; + }, + + get_entry: function(index) { + return this.update.firstChild.childNodes[index]; + }, + + get_current_entry: function() { + return this.get_entry(this.index); + }, + + select_entry: function() { + this.hide(); + this.active = false; + value = Text.decodeHTML(Element.collectTextNodesIgnoreClass(this.get_current_entry(), 'informal')); + this.element.value = value; + this.element.focus(); + } +});
\ No newline at end of file diff --git a/actionpack/lib/action_view/helpers/javascripts/dragdrop.js b/actionpack/lib/action_view/helpers/javascripts/dragdrop.js new file mode 100644 index 0000000000..f9ed0b7898 --- /dev/null +++ b/actionpack/lib/action_view/helpers/javascripts/dragdrop.js @@ -0,0 +1,385 @@ +// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// +// Element.Class part Copyright (c) 2005 by Rick Olson +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +/*--------------------------------------------------------------------------*/ + +var Droppables = { + drops: false, + include_scroll_offsets: false, + + add: function(element) { + var element = $(element); + var options = { + greedy: true, + hoverclass: null + }.extend(arguments[1] || {}); + + // cache containers + if(options.containment) { + options._containers = new Array(); + var containment = options.containment; + if((typeof containment == 'object') && + (containment.constructor == Array)) { + for(var i=0; i<containment.length; i++) + options._containers.push($(containment[i])); + } else { + options._containers.push($(containment)); + } + options._containers_length = + options._containers.length-1; + } + + if(element.style.position=='') //fix IE + element.style.position = 'relative'; + + // activate the droppable + element.droppable = options; + + if(!this.drops) this.drops = []; + this.drops.push(element); + }, + + is_contained: function(element, drop) { + var containers = drop.droppable._containers; + var parentNode = element.parentNode; + var i = drop.droppable._containers_length; + do { if(parentNode==containers[i]) return true; } while (i--); + return false; + }, + + is_affected: function(pX, pY, element, drop) { + return ( + (drop!=element) && + ((!drop.droppable._containers) || + this.is_contained(element, drop)) && + ((!drop.droppable.accept) || + (Element.Class.has_any(element, drop.droppable.accept))) && + Position.within(drop, pX, pY) ); + }, + + deactivate: function(drop) { + Element.Class.remove(drop, drop.droppable.hoverclass); + this.last_active = null; + }, + + activate: function(drop) { + if(this.last_active) this.deactivate(this.last_active); + if(drop.droppable.hoverclass) { + Element.Class.add(drop, drop.droppable.hoverclass); + this.last_active = drop; + } + }, + + show: function(event, element) { + if(!this.drops) return; + var pX = Event.pointerX(event); + var pY = Event.pointerY(event); + if(this.include_scroll_offsets) Position.prepare(); + + var i = this.drops.length-1; do { + var drop = this.drops[i]; + if(this.is_affected(pX, pY, element, drop)) { + if(drop.droppable.onHover) + drop.droppable.onHover( + element, drop, Position.overlap(drop.droppable.overlap, drop)); + if(drop.droppable.greedy) { + this.activate(drop); + return; + } + } + } while (i--); + }, + + fire: function(event, element) { + if(!this.drops) return; + var pX = Event.pointerX(event); + var pY = Event.pointerY(event); + if(this.include_scroll_offsets) Position.prepare(); + + var i = this.drops.length-1; do { + var drop = this.drops[i]; + if(this.is_affected(pX, pY, element, drop)) + if(drop.droppable.onDrop) + drop.droppable.onDrop(element); + } while (i--); + }, + + reset: function() { + if(this.last_active) + this.deactivate(this.last_active); + } +} + +Draggables = { + observers: new Array(), + addObserver: function(observer) { + this.observers.push(observer); + }, + notify: function(eventName) { // 'onStart', 'onEnd' + for(var i = 0; i < this.observers.length; i++) + this.observers[i][eventName](); + } +} + +/*--------------------------------------------------------------------------*/ + +Draggable = Class.create(); +Draggable.prototype = { + initialize: function(element) { + var options = { + handle: false, + starteffect: function(element) { + new Effect2.Opacity(element, {duration:0.2, from:1.0, to:0.7}); + }, + reverteffect: function(element, top_offset, left_offset) { + new Effect2.MoveBy(element, -top_offset, -left_offset, {duration:0.4}); + }, + endeffect: function(element) { + new Effect2.Opacity(element, {duration:0.2, from:0.7, to:1.0}); + }, + zindex: 1000 + }.extend(arguments[1] || {}); + + this.element = $(element); + this.element.drag = this; + this.handle = options.handle ? $(options.handle) : this.element; + + this.offsetX = 0; + this.offsetY = 0; + this.originalLeft = this.currentLeft(); + 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; + + this.active = false; + this.dragging = false; + + Event.observe(this.handle, "mousedown", this.startDrag.bindAsEventListener(this)); + Event.observe(document, "mouseup", this.endDrag.bindAsEventListener(this)); + Event.observe(document, "mousemove", this.update.bindAsEventListener(this)); + }, + currentLeft: function() { + return parseInt(this.element.style.left || '0'); + }, + currentTop: function() { + return parseInt(this.element.style.top || '0') + }, + startDrag: function(event) { + if(Event.isLeftClick(event)) { + this.active = true; + + var style = this.element.style; + this.originalY = this.element.offsetTop - this.currentTop(); - this.originalTop; + this.originalX = this.element.offsetLeft - this.currentLeft(); - this.originalLeft; + this.offsetY = event.clientY - this.originalY - this.originalTop; + this.offsetX = event.clientX - this.originalX - this.originalLeft; + + Event.stop(event); + } + }, + endDrag: function(event) { + if(this.active && this.dragging) { + this.active = false; + this.dragging = false; + + Droppables.fire(event, this.element); + Draggables.notify('onEnd'); + + if(this.options.revert && this.options.reverteffect) { + this.options.reverteffect(this.element, + this.currentTop()-this.originalTop, + this.currentLeft()-this.originalLeft); + } else { + this.originalLeft = this.currentLeft(); + this.originalTop = this.currentTop(); + } + this.element.style.zIndex = this.originalZ; + + if(this.options.endeffect) + this.options.endeffect(this.element); + + Droppables.reset(); + Event.stop(event); + } + this.active = false; + this.dragging = false; + }, + draw: function(event) { + var style = this.element.style; + this.originalX = this.element.offsetLeft - this.currentLeft() - this.originalLeft; + this.originalY = this.element.offsetTop - this.currentTop() - this.originalTop; + if((!this.options.constraint) || (this.options.constraint=='horizontal')) + style.left = ((event.clientX - this.originalX) - this.offsetX) + "px"; + if((!this.options.constraint) || (this.options.constraint=='vertical')) + style.top = ((event.clientY - this.originalY) - this.offsetY) + "px"; + if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering + }, + update: function(event) { + if(this.active) { + if(!this.dragging) { + var style = this.element.style; + this.dragging = true; + if(style.position=="") style.position = "relative"; + style.zIndex = this.options.zindex; + Draggables.notify('onStart'); + if(this.options.starteffect) this.options.starteffect(this.element); + } + + Droppables.show(event, this.element); + this.draw(event); + if(this.options.change) this.options.change(this); + + // fix AppleWebKit rendering + if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); + + Event.stop(event); + } + } +} + +/*--------------------------------------------------------------------------*/ + +SortableObserver = Class.create(); +SortableObserver.prototype = { + initialize: function(element, observer) { + this.element = $(element); + this.observer = observer; + this.lastValue = Sortable.serialize(this.element); + }, + onStart: function() { + this.lastValue = Sortable.serialize(this.element); + }, + onEnd: function() { + if(this.lastValue != Sortable.serialize(this.element)) + this.observer(this.element) + } +} + +Sortable = { + create: function(element) { + var element = $(element); + var options = { + tag: 'li', // assumes li children, override with tag: 'tagname' + overlap: 'vertical', // one of 'vertical', 'horizontal' + constraint: 'vertical', // one of 'vertical', 'horizontal', false + containment: element, // also takes array of elements (or id's); or false + handle: false, // or a CSS class + only: false, + hoverclass: null, + onChange: function() {}, + onUpdate: function() {} + }.extend(arguments[1] || {}); + element.sortable = options; + + // build options for the draggables + var options_for_draggable = { + revert: true, + constraint: options.constraint, + handle: handle }; + if(options.starteffect) + options_for_draggable.starteffect = options.starteffect; + if(options.reverteffect) + options_for_draggable.reverteffect = options.reverteffect; + if(options.endeffect) + options_for_draggable.endeffect = options.endeffect; + if(options.zindex) + options_for_draggable.zindex = options.zindex; + + // build options for the droppables + var options_for_droppable = { + overlap: options.overlap, + containment: options.containment, + hoverclass: options.hoverclass, + onHover: function(element, dropon, overlap) { + if(overlap>0.5) { + if(dropon.previousSibling != element) { + var oldParentNode = element.parentNode; + element.style.visibility = "hidden"; // fix gecko rendering + dropon.parentNode.insertBefore(element, dropon); + if(dropon.parentNode!=oldParentNode && oldParentNode.sortable) + oldParentNode.sortable.onChange(element); + if(dropon.parentNode.sortable) + dropon.parentNode.sortable.onChange(element); + } + } else { + var nextElement = dropon.nextSibling || null; + if(nextElement != element) { + var oldParentNode = element.parentNode; + element.style.visibility = "hidden"; // fix gecko rendering + dropon.parentNode.insertBefore(element, nextElement); + if(dropon.parentNode!=oldParentNode && oldParentNode.sortable) + oldParentNode.sortable.onChange(element); + if(dropon.parentNode.sortable) + dropon.parentNode.sortable.onChange(element); + } + } + } + } + + // fix for gecko engine + Element.cleanWhitespace(element); + + // for onupdate + Draggables.addObserver(new SortableObserver(element, options.onUpdate)); + + // make it so + var elements = element.childNodes; + for (var i = 0; i < elements.length; i++) + if(elements[i].tagName && elements[i].tagName==options.tag.toUpperCase() && + (!options.only || (Element.Class.has(elements[i], options.only)))) { + + // handles are per-draggable + var handle = options.handle ? + Element.Class.childrenWith(elements[i], options.handle)[0] : elements[i]; + + new Draggable(elements[i], options_for_draggable.extend({ handle: handle })); + Droppables.add(elements[i], options_for_droppable); + } + + }, + serialize: function(element) { + var element = $(element); + var options = { + tag: element.sortable.tag, + only: element.sortable.only, + name: element.id + }.extend(arguments[1] || {}); + + var items = $(element).childNodes; + var queryComponents = new Array(); + + for(var i=0; i<items.length; i++) + if(items[i].tagName && items[i].tagName==options.tag.toUpperCase() && + (!options.only || (Element.Class.has(items[i], options.only)))) + queryComponents.push( + encodeURIComponent(options.name) + "[]=" + + encodeURIComponent(items[i].id.split("_")[1])); + + return queryComponents.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 new file mode 100644 index 0000000000..82f1fd53ed --- /dev/null +++ b/actionpack/lib/action_view/helpers/javascripts/effects.js @@ -0,0 +1,557 @@ +// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// +// Parts (c) 2005 Justin Palmer (http://encytemedia.com/) +// Parts (c) 2005 Mark Pilgrim (http://diveintomark.org/) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +Effect = {} +Effect2 = Effect; // deprecated + +/* ------------- transitions ------------- */ + +Effect.Transitions = {} + +Effect.Transitions.linear = function(pos) { + return pos; +} +Effect.Transitions.sinoidal = function(pos) { + return (-Math.cos(pos*Math.PI)/2) + 0.5; +} +Effect.Transitions.reverse = function(pos) { + return 1-pos; +} +Effect.Transitions.flicker = function(pos) { + return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random(0.25); +} +Effect.Transitions.wobble = function(pos) { + return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5; +} +Effect.Transitions.pulse = function(pos) { + return (Math.floor(pos*10) % 2 == 0 ? + (pos*10-Math.floor(pos*10)) : 1-(pos*10-Math.floor(pos*10))); +} + +Effect.Transitions.none = function(pos) { + return 0; +} +Effect.Transitions.full = function(pos) { + return 1; +} + +/* ------------- core effects ------------- */ + +Effect.Base = function() {}; +Effect.Base.prototype = { + setOptions: function(options) { + this.options = { + transition: Effect.Transitions.sinoidal, + duration: 1.0, // seconds + fps: 25.0, // max. 100fps + sync: false, // true for combining + from: 0.0, + to: 1.0 + }.extend(options || {}); + }, + start: function(options) { + this.setOptions(options || {}); + this.currentFrame = 0; + this.startOn = new Date().getTime(); + this.finishOn = this.startOn + (this.options.duration*1000); + if(this.options.beforeStart) this.options.beforeStart(this); + if(!this.options.sync) this.loop(); + }, + loop: function() { + timePos = new Date().getTime(); + if(timePos >= this.finishOn) { + this.render(this.options.to); + if(this.finish) this.finish(); + if(this.options.afterFinish) this.options.afterFinish(this); + return; + } + pos = (timePos - this.startOn) / (this.finishOn - this.startOn); + frame = Math.round(pos * this.options.fps * this.options.duration); + if(frame > this.currentFrame) { + this.render(pos); + this.currentFrame = frame; + } + this.timeout = setTimeout(this.loop.bind(this), 10); + }, + render: function(pos) { + if(this.options.transition) pos = this.options.transition(pos); + pos = pos * (this.options.to-this.options.from); + pos += this.options.from; + if(this.options.beforeUpdate) this.options.beforeUpdate(this); + if(this.update) this.update(pos); + if(this.options.afterUpdate) this.options.afterUpdate(this); + }, + cancel: function() { + if(this.timeout) clearTimeout(this.timeout); + } +} + +Effect.Parallel = Class.create(); + Effect.Parallel.prototype = (new Effect.Base()).extend({ + initialize: function(effects) { + this.effects = effects || []; + this.start(arguments[1]); + }, + update: function(position) { + for (var i = 0; i < this.effects.length; i++) + this.effects[i].render(position); + }, + finish: function(position) { + for (var i = 0; i < this.effects.length; i++) + if(this.effects[i].finish) this.effects[i].finish(position); + } + }); + +Effect.Opacity = Class.create(); +Effect.Opacity.prototype = (new Effect.Base()).extend({ + initialize: function(element) { + this.element = $(element); + options = { + from: 0.0, + to: 1.0 + }.extend(arguments[1] || {}); + this.start(options); + }, + update: function(position) { + this.setOpacity(position); + }, + setOpacity: function(opacity) { + opacity = (opacity == 1) ? 0.99999 : opacity; + this.element.style.opacity = opacity; + this.element.style.filter = "alpha(opacity:"+opacity*100+")"; + } +}); + +Effect.MoveBy = Class.create(); + Effect.MoveBy.prototype = (new Effect.Base()).extend({ + initialize: function(element, toTop, toLeft) { + this.element = $(element); + this.originalTop = parseFloat(this.element.style.top || '0'); + this.originalLeft = parseFloat(this.element.style.left || '0'); + this.toTop = toTop; + this.toLeft = toLeft; + if(this.element.style.position == "") + this.element.style.position = "relative"; + this.start(arguments[3]); + }, + update: function(position) { + topd = this.toTop * position + this.originalTop; + leftd = this.toLeft * position + this.originalLeft; + this.setPosition(topd, leftd); + }, + setPosition: function(topd, leftd) { + this.element.style.top = topd + "px"; + this.element.style.left = leftd + "px"; + } +}); + +Effect.Scale = Class.create(); +Effect.Scale.prototype = (new Effect.Base()).extend({ + initialize: function(element, percent) { + this.element = $(element) + options = { + scaleX: true, + scaleY: true, + scaleContent: true, + scaleFromCenter: false, + scaleMode: 'box', // 'box' or 'contents' or {} with provided values + scaleFrom: 100.0 + }.extend(arguments[2] || {}); + this.originalTop = this.element.offsetTop; + this.originalLeft = this.element.offsetLeft; + if (this.element.style.fontSize=="") this.sizeEm = 1.0; + if (this.element.style.fontSize && this.element.style.fontSize.indexOf("em")>0) + this.sizeEm = parseFloat(this.element.style.fontSize); + this.factor = (percent/100.0) - (options.scaleFrom/100.0); + if(options.scaleMode=='box') { + this.originalHeight = this.element.clientHeight; + this.originalWidth = this.element.clientWidth; + } else + if(options.scaleMode=='contents') { + this.originalHeight = this.element.scrollHeight; + this.originalWidth = this.element.scrollWidth; + } else { + this.originalHeight = options.scaleMode.originalHeight; + this.originalWidth = options.scaleMode.originalWidth; + } + this.start(options); + }, + + update: function(position) { + currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); + if(this.options.scaleContent && this.sizeEm) + this.element.style.fontSize = this.sizeEm*currentScale + "em"; + this.setDimensions( + this.originalWidth * currentScale, + this.originalHeight * currentScale); + }, + + setDimensions: function(width, height) { + if(this.options.scaleX) this.element.style.width = width + 'px'; + if(this.options.scaleY) this.element.style.height = height + 'px'; + if(this.options.scaleFromCenter) { + topd = (height - this.originalHeight)/2; + leftd = (width - this.originalWidth)/2; + if(this.element.style.position=='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"; + } else { + if(this.options.scaleY) this.element.style.top = -topd + "px"; + if(this.options.scaleX) this.element.style.left = -leftd + "px"; + } + } + } +}); + +Effect.Highlight = Class.create(); +Effect.Highlight.prototype = (new Effect.Base()).extend({ + initialize: function(element) { + this.element = $(element); + + // try to parse current background color as default for endcolor + // browser stores this as: "rgb(255, 255, 255)", convert to "#ffffff" format + var endcolor = "#ffffff"; + var current = this.element.style.backgroundColor; + if(current && current.slice(0,4) == "rgb(") { + endcolor = "#"; + var cols = current.slice(4,current.length-1).split(','); + var i=0; do { endcolor += parseInt(cols[i]).toColorPart() } while (++i<3); } + + var options = { + startcolor: "#ffff99", + endcolor: endcolor + }.extend(arguments[1] || {}); + + // init color calculations + this.colors_base = [ + parseInt(options.startcolor.slice(1,3),16), + parseInt(options.startcolor.slice(3,5),16), + parseInt(options.startcolor.slice(5),16) ]; + this.colors_delta = [ + parseInt(options.endcolor.slice(1,3),16)-this.colors_base[0], + parseInt(options.endcolor.slice(3,5),16)-this.colors_base[1], + parseInt(options.endcolor.slice(5),16)-this.colors_base[2] ]; + + this.start(options); + }, + 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)) ]; + this.element.style.backgroundColor = "#" + + colors[0].toColorPart() + colors[1].toColorPart() + colors[2].toColorPart(); + } +}); + + +/* ------------- prepackaged effects ------------- */ + +Effect.Fade = function(element) { + options = { + from: 1.0, + to: 0.0, + afterFinish: function(effect) + { Element.hide(effect.element); + effect.setOpacity(1); } + }.extend(arguments[1] || {}); + new Effect.Opacity(element,options); +} + +Effect.Appear = function(element) { + options = { + from: 0.0, + to: 1.0, + beforeStart: function(effect) + { effect.setOpacity(0); + Element.show(effect.element); }, + afterUpdate: function(effect) + { Element.show(effect.element); } + }.extend(arguments[1] || {}); + new Effect.Opacity(element,options); +} + +Effect.Puff = function(element) { + new Effect.Parallel( + [ new Effect.Scale(element, 200, { sync: true, scaleFromCenter: true }), + new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0 } ) ], + { duration: 1.0, + afterUpdate: function(effect) + { effect.effects[0].element.style.position = 'absolute'; }, + afterFinish: function(effect) + { Element.hide(effect.effects[0].element); } + } + ); +} + +Effect.BlindUp = function(element) { + $(element).style.overflow = 'hidden'; + new Effect.Scale(element, 0, + { scaleContent: false, + scaleX: false, + afterFinish: function(effect) + { Element.hide(effect.element) } + }.extend(arguments[1] || {}) + ); +} + +Effect.BlindDown = function(element) { + $(element).style.height = '0px'; + $(element).style.overflow = 'hidden'; + Element.show(element); + new Effect.Scale(element, 100, + { scaleContent: false, + scaleX: false, + scaleMode: 'contents', + scaleFrom: 0 + }.extend(arguments[1] || {}) + ); +} + +Effect.SwitchOff = function(element) { + new Effect.Appear(element, + { duration: 0.4, + transition: Effect.Transitions.flicker, + afterFinish: function(effect) + { effect.element.style.overflow = 'hidden'; + new Effect.Scale(effect.element, 1, + { duration: 0.3, scaleFromCenter: true, + scaleX: false, scaleContent: false, + afterUpdate: function(effect) { + if(effect.element.style.position=="") + effect.element.style.position = 'relative'; }, + afterFinish: function(effect) { Element.hide(effect.element); } + } ) + } + } ) +} + +Effect.DropOut = function(element) { + new Effect.Parallel( + [ new Effect.MoveBy(element, 100, 0, { sync: true }), + new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0 } ) ], + { duration: 0.5, + afterFinish: function(effect) + { Element.hide(effect.effects[0].element); } + }); +} + +Effect.Shake = function(element) { + new Effect.MoveBy(element, 0, 20, + { duration: 0.05, afterFinish: function(effect) { + new Effect.MoveBy(effect.element, 0, -40, + { duration: 0.1, afterFinish: function(effect) { + new Effect.MoveBy(effect.element, 0, 40, + { duration: 0.1, afterFinish: function(effect) { + new Effect.MoveBy(effect.element, 0, -40, + { duration: 0.1, afterFinish: function(effect) { + new Effect.MoveBy(effect.element, 0, 40, + { duration: 0.1, afterFinish: function(effect) { + new Effect.MoveBy(effect.element, 0, -20, + { duration: 0.05, afterFinish: function(effect) { + }}) }}) }}) }}) }}) }}); +} + +Effect.SlideDown = function(element) { + $(element).style.height = '0px'; + $(element).style.overflow = 'hidden'; + $(element).firstChild.style.position = 'relative'; + Element.show(element); + new Effect.Scale(element, 100, + { scaleContent: false, + scaleX: false, + scaleMode: 'contents', + scaleFrom: 0, + afterUpdate: function(effect) + { effect.element.firstChild.style.bottom = + (effect.originalHeight - effect.element.clientHeight) + 'px'; } + }.extend(arguments[1] || {}) + ); +} + +Effect.SlideUp = function(element) { + $(element).style.overflow = 'hidden'; + $(element).firstChild.style.position = 'relative'; + Element.show(element); + new Effect.Scale(element, 0, + { scaleContent: false, + scaleX: false, + afterUpdate: function(effect) + { effect.element.firstChild.style.bottom = + (effect.originalHeight - effect.element.clientHeight) + 'px'; }, + afterFinish: function(effect) + { Element.hide(effect.element); } + }.extend(arguments[1] || {}) + ); +} + +Effect.Squish = function(element) { + new Effect.Scale(element, 0, + { afterFinish: function(effect) { Element.hide(effect.element); } }); +} + +Effect.Grow = function(element) { + element = $(element); + var options = arguments[1] || {}; + + var originalWidth = element.clientWidth; + var originalHeight = element.clientHeight; + element.style.overflow = 'hidden'; + Element.show(element); + + var direction = options.direction || 'center'; + var moveTransition = options.moveTransition || Effect.Transitions.sinoidal; + var scaleTransition = options.scaleTransition || Effect.Transitions.sinoidal; + var opacityTransition = options.opacityTransition || Effect.Transitions.full; + + var initialMoveX, initialMoveY; + var moveX, moveY; + + switch (direction) { + case 'top-left': + initialMoveX = initialMoveY = moveX = moveY = 0; + break; + case 'top-right': + initialMoveX = originalWidth; + initialMoveY = moveY = 0; + moveX = -originalWidth; + break; + case 'bottom-left': + initialMoveX = moveX = 0; + initialMoveY = originalHeight; + moveY = -originalHeight; + break; + case 'bottom-right': + initialMoveX = originalWidth; + initialMoveY = originalHeight; + moveX = -originalWidth; + moveY = -originalHeight; + break; + case 'center': + initialMoveX = originalWidth / 2; + initialMoveY = originalHeight / 2; + moveX = -originalWidth / 2; + moveY = -originalHeight / 2; + break; + } + + new Effect.MoveBy(element, initialMoveY, initialMoveX, { + duration: 0.01, + beforeUpdate: function(effect) { $(element).style.height = '0px'; }, + afterFinish: function(effect) { + new Effect.Parallel( + [ new Effect.Opacity(element, { sync: true, to: 1.0, from: 0.0, transition: opacityTransition }), + new Effect.MoveBy(element, moveY, moveX, { sync: true, transition: moveTransition }), + new Effect.Scale(element, 100, { + scaleMode: { originalHeight: originalHeight, originalWidth: originalWidth }, + sync: true, scaleFrom: 0, scaleTo: 100, transition: scaleTransition })], + options); } + }); +} + +Effect.Shrink = function(element) { + element = $(element); + var options = arguments[1] || {}; + + var originalWidth = element.clientWidth; + var originalHeight = element.clientHeight; + element.style.overflow = 'hidden'; + Element.show(element); + + var direction = options.direction || 'center'; + var moveTransition = options.moveTransition || Effect.Transitions.sinoidal; + var scaleTransition = options.scaleTransition || Effect.Transitions.sinoidal; + var opacityTransition = options.opacityTransition || Effect.Transitions.none; + + var moveX, moveY; + + switch (direction) { + case 'top-left': + moveX = moveY = 0; + break; + case 'top-right': + moveX = originalWidth; + moveY = 0; + break; + case 'bottom-left': + moveX = 0; + moveY = originalHeight; + break; + case 'bottom-right': + moveX = originalWidth; + moveY = originalHeight; + break; + case 'center': + moveX = originalWidth / 2; + moveY = originalHeight / 2; + break; + } + + new Effect.Parallel( + [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: opacityTransition }), + new Effect.Scale(element, 0, { sync: true, transition: moveTransition }), + new Effect.MoveBy(element, moveY, moveX, { sync: true, transition: scaleTransition }) ], + options); +} + +Effect.Pulsate = function(element) { + var options = arguments[1] || {}; + var transition = options.transition || Effect.Transitions.sinoidal; + var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) }; + reverser.bind(transition); + new Effect.Opacity(element, + { duration: 3.0, + afterFinish: function(effect) { Element.show(effect.element); } + }.extend(options).extend({transition: reverser})); +} + +Effect.Fold = function(element) { + $(element).style.overflow = 'hidden'; + new Effect2.Scale(element, 5, { + scaleContent: false, + scaleTo: 100, + scaleX: false, + afterFinish: function(effect) { + new Effect.Scale(element, 1, { + scaleContent: false, + scaleTo: 0, + scaleY: false, + afterFinish: function(effect) { Element.hide(effect.element) } }); + }}.extend(arguments[1] || {})); +} + +// old: new Effect.ContentZoom(element, percent) +// new: Element.setContentZoom(element, percent) + +Element.setContentZoom = function(element, percent) { + var element = $(element); + + var sizeEm = 1.0; + if (element.style.fontSize.indexOf("em")>0) + sizeEm = parseFloat(element.style.fontSize); + + element.style.fontSize = sizeEm*(percent/100) + "em"; + if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); +}
\ No newline at end of file diff --git a/actionpack/lib/action_view/helpers/javascripts/prototype.js b/actionpack/lib/action_view/helpers/javascripts/prototype.js index ca772aa8fa..1ebb2a46b7 100644 --- a/actionpack/lib/action_view/helpers/javascripts/prototype.js +++ b/actionpack/lib/action_view/helpers/javascripts/prototype.js @@ -559,205 +559,279 @@ Insertion.After.prototype = (new Abstract.Insertion('afterEnd')).extend({ } }); -/*--------------------------------------------------------------------------*/ - -var Effect = new Object(); -Effect.Highlight = Class.create(); -Effect.Highlight.prototype = { - initialize: function(element) { - this.element = $(element); - this.start = 153; - this.finish = 255; - this.current = this.start; - this.fade(); - }, - - fade: function() { - if (this.isFinished()) return; - if (this.timer) clearTimeout(this.timer); - this.highlight(this.element, this.current); - this.current += 17; - this.timer = setTimeout(this.fade.bind(this), 250); - }, - - isFinished: function() { - return this.current > this.finish; - }, - - highlight: function(element, current) { - element.style.backgroundColor = "#ffff" + current.toColorPart(); +// === Prototype Extension ==================================================== + +// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// +// Element.Class part Copyright (c) 2005 by Rick Olson +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +var Event = { + KEY_BACKSPACE: 8, + KEY_TAB: 9, + KEY_RETURN: 13, + KEY_ESC: 27, + KEY_LEFT: 37, + KEY_UP: 38, + KEY_RIGHT: 39, + KEY_DOWN: 40, + KEY_DELETE: 46, + + element: function(event) { + return event.srcElement || event.currentTarget; + }, + + isLeftClick: function(event) { + return (((event.which) && (event.which == 1)) || + ((event.button) && (event.button == 1))); + }, + + pointerX: function(event) { + return event.pageX || (event.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft)); + }, + + pointerY: function(event) { + return event.pageY || (event.clientY + (document.documentElement.scrollTop || document.body.scrollTop)); + }, + + stop: function(event) { + if(event.preventDefault) + { event.preventDefault(); event.stopPropagation(); } + else + event.returnValue = false; + }, + + // find the first node with the given tagName, starting from the + // node the event was triggered on, traverses the DOM upwards + findElement: function(event, tagName) { + element = Event.element(event); + while(element.tagName.toUpperCase() != tagName.toUpperCase() && element.parentNode) + element = element.parentNode; + return element; + }, + + observe: function(element, name, observer) { + if(name=='keypress') { + if(navigator.appVersion.indexOf('AppleWebKit')>0) + { $(element).addEventListener("keydown",observer,false); return; } + if($(element).addEventListener) $(element).addEventListener("keypress",observer,false) + else if($(element).attachEvent) $(element).attachEvent("onkeydown",observer); + } else { + if($(element).addEventListener) $(element).addEventListener(name,observer,false) + else if($(element).attachEvent) $(element).attachEvent("on" + name,observer); + } } } +/*--------------------------------------------------------------------------*/ -Effect.Fade = Class.create(); -Effect.Fade.prototype = { - initialize: function(element) { - this.element = $(element); - this.start = 100; - this.finish = 0; - this.current = this.start; - this.fade(); - }, - - fade: function() { - if (this.isFinished()) { this.element.style.display = 'none'; return; } - if (this.timer) clearTimeout(this.timer); - this.setOpacity(this.element, this.current); - this.current -= 10; - this.timer = setTimeout(this.fade.bind(this), 50); - }, - - isFinished: function() { - return this.current <= this.finish; - }, - - setOpacity: function(element, opacity) { - opacity = (opacity == 100) ? 99.999 : opacity; - element.style.filter = "alpha(opacity:"+opacity+")"; - element.style.opacity = opacity/100 /*//*/; +// removes whitespace-only text node children +// needed to make Gecko-based browsers happy +Element.cleanWhitespace = function(element) { + var 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); } } -Effect.Scale = Class.create(); -Effect.Scale.prototype = { - initialize: function(element, percent) { - this.element = $(element); - this.startScale = 1.0; - this.startHeight = this.element.offsetHeight; - this.startWidth = this.element.offsetWidth; - this.currentHeight = this.startHeight; - this.currentWidth = this.startWidth; - this.finishScale = (percent/100) /*//*/; - if (this.element.style.fontSize=="") this.sizeEm = 1.0; - if (this.element.style.fontSize.indexOf("em")>0) - this.sizeEm = parseFloat(this.element.style.fontSize); - if(this.element.effect_scale) { - clearTimeout(this.element.effect_scale.timer); - this.startScale = this.element.effect_scale.currentScale; - this.startHeight = this.element.effect_scale.startHeight; - this.startWidth = this.element.effect_scale.startWidth; - if(this.element.effect_scale.sizeEm) - this.sizeEm = this.element.effect_scale.sizeEm; - } - this.element.effect_scale = this; - this.currentScale = this.startScale; - this.factor = this.finishScale - this.startScale; - this.options = arguments[2] || {}; - this.scale(); - }, - - scale: function() { - if (this.isFinished()) { - this.setDimensions(this.element, this.startWidth*this.finishScale, this.startHeight*this.finishScale); - if(this.sizeEm) this.element.style.fontSize = this.sizeEm*this.finishScale + "em"; - if(this.options.complete) this.options.complete(this); - return; - } - if (this.timer) clearTimeout(this.timer); - if (this.options.step) this.options.step(this); - this.setDimensions(this.element, this.currentWidth, this.currentHeight); - if(this.sizeEm) this.element.style.fontSize = this.sizeEm*this.currentScale + "em"; - this.currentScale += (this.factor/10) /*//*/; - this.currentWidth = this.startWidth * this.currentScale; - this.currentHeight = this.startHeight * this.currentScale; - this.timer = setTimeout(this.scale.bind(this), 50); - }, - - isFinished: function() { - return (this.factor < 0) ? - this.currentScale <= this.finishScale : this.currentScale >= this.finishScale; - }, +Element.collectTextNodesIgnoreClass = function(element, ignoreclass) { + var children = $(element).childNodes; + var text = ""; + var classtest = new RegExp("^([^ ]+ )*" + ignoreclass+ "( [^ ]+)*$","i"); - setDimensions: function(element, width, height) { - element.style.width = width + 'px'; - element.style.height = height + 'px'; + for (var i = 0; i < children.length; i++) { + if(children[i].nodeType==3) { + text+=children[i].nodeValue; + } else { + if((!children[i].className.match(classtest)) && children[i].hasChildNodes()) + text += Element.collectTextNodesIgnoreClass(children[i], ignoreclass); + } } + + return text; } -Effect.Squish = Class.create(); -Effect.Squish.prototype = { - initialize: function(element) { - this.element = $(element); - new Effect.Scale(this.element, 1, { complete: this.hide.bind(this) } ); - }, - hide: function() { - this.element.style.display = 'none'; - } -} +/*--------------------------------------------------------------------------*/ -Effect.Puff = Class.create(); -Effect.Puff.prototype = { - initialize: function(element) { - this.element = $(element); - this.opacity = 100; - this.startTop = this.element.top || this.element.offsetTop; - this.startLeft = this.element.left || this.element.offsetLeft; - new Effect.Scale(this.element, 200, { step: this.fade.bind(this), complete: this.hide.bind(this) } ); - }, - fade: function(effect) { - topd = (((effect.currentScale)*effect.startHeight) - effect.startHeight)/2; - leftd = (((effect.currentScale)*effect.startWidth) - effect.startWidth)/2; - this.element.style.position='absolute'; - this.element.style.top = this.startTop-topd + "px"; - this.element.style.left = this.startLeft-leftd + "px"; - this.opacity -= 10; - this.setOpacity(this.element, this.opacity); - if(navigator.appVersion.indexOf('AppleWebKit')>0) this.element.innerHTML += ''; //force redraw on safari - }, - hide: function() { - this.element.style.display = 'none'; +Text = { + stripTags: function(htmlstr) { + return htmlstr.replace(/<\/?[^>]+>/gi,""); }, - setOpacity: function(element, opacity) { - opacity = (opacity == 100) ? 99.999 : opacity; - element.style.filter = "alpha(opacity:"+opacity+")"; - element.style.opacity = opacity/100 /*//*/; + decodeHTML: function(htmlstr) { + return htmlstr.replace(/</gi,"<").replace(/>/gi,">").replace(/"/gi,'"').replace(/'/gi,"'").replace(/&/gi,"&").replace(/[\n\r]/gi,""); } } -Effect.Appear = Class.create(); -Effect.Appear.prototype = { - initialize: function(element) { - this.element = $(element); - this.start = 0; - this.finish = 100; - this.current = this.start; - this.fade(); - }, - - fade: function() { - if (this.isFinished()) return; - if (this.timer) clearTimeout(this.timer); - this.setOpacity(this.element, this.current); - this.current += 10; - this.timer = setTimeout(this.fade.bind(this), 50); - }, - - isFinished: function() { - return this.current > this.finish; - }, - - setOpacity: function(element, opacity) { - opacity = (opacity == 100) ? 99.999 : opacity; - element.style.filter = "alpha(opacity:"+opacity+")"; - element.style.opacity = opacity/100 /*//*/; - element.style.display = ''; - } -} +/*--------------------------------------------------------------------------*/ -Effect.ContentZoom = Class.create(); -Effect.ContentZoom.prototype = { - initialize: function(element, percent) { - this.element = $(element); - if (this.element.style.fontSize=="") this.sizeEm = 1.0; - if (this.element.style.fontSize.indexOf("em")>0) - this.sizeEm = parseFloat(this.element.style.fontSize); - if(this.element.effect_contentzoom) { - this.sizeEm = this.element.effect_contentzoom.sizeEm; +Element.Class = { + // Element.toggleClass(element, className) toggles the class being on/off + // Element.toggleClass(element, className1, className2) toggles between both classes, + // defaulting to className1 if neither exist + toggle: function(element, className) { + if(Element.Class.has(element, className)) { + Element.Class.remove(element, className); + if(arguments.length == 3) Element.Class.add(element, arguments[2]); + } else { + Element.Class.add(element, className); + if(arguments.length == 3) Element.Class.remove(element, arguments[2]); + } + }, + + // gets space-delimited classnames of an element as an array + get: function(element) { + element = $(element); + 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("^" + arguments[i] + "\\b\\s*|\\s*\\b" + arguments[i] + "\\b", 'g'); + element.className = element.className.replace(regEx, '') + } + }, + + add: function(element) { + element = $(element); + for(var i = 1; i < arguments.length; i++) { + Element.Class.remove(element, arguments[i]); + element.className += (element.className.length > 0 ? ' ' : '') + arguments[i]; + } + }, + + // returns true if all given classes exist in said element + has: function(element) { + element = $(element); + if(!element || !element.className) return false; + var regEx; + for(var i = 1; i < arguments.length; i++) { + regEx = new RegExp("\\b" + arguments[i] + "\\b"); + if(!regEx.test(element.className)) return false; + } + return true; + }, + + // expects arrays of strings and/or strings as optional paramters + // Element.Class.has_any(element, ['classA','classB','classC'], 'classD') + has_any: function(element) { + element = $(element); + if(!element || !element.className) return false; + var regEx; + for(var i = 1; i < arguments.length; i++) { + if((typeof arguments[i] == 'object') && + (arguments[i].constructor == Array)) { + for(var j = 0; j < arguments[i].length; j++) { + regEx = new RegExp("\\b" + arguments[i][j] + "\\b"); + if(regEx.test(element.className)) return true; + } + } else { + regEx = new RegExp("\\b" + arguments[i] + "\\b"); + if(regEx.test(element.className)) return true; + } + } + return false; + }, + + childrenWith: function(element, className) { + var children = $(element).getElementsByTagName('*'); + var elements = new Array(); + + for (var i = 0; i < children.length; i++) { + if (Element.Class.has(children[i], className)) { + elements.push(children[i]); + break; + } + } + + return elements; } - this.element.effect_contentzoom = this; - this.element.style.fontSize = this.sizeEm*(percent/100) + "em" /*//*/; - if(navigator.appVersion.indexOf('AppleWebKit')>0) { this.element.scrollTop -= 1; }; - } } + +/*--------------------------------------------------------------------------*/ + +var Position = { + // must be called before calling within_including_scrolloffset, every time the page is scrolled + prepare: function() { + this.deltaX = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0; + this.deltaY = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; + this.include_scroll_offsets = true; + }, + + real_offset: function(element) { + var valueT = 0; var valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while(element); + return [valueL, valueT]; + }, + + // caches x/y coordinate pair to use with overlap + within: function(element, x, y) { + if(this.include_scroll_offsets) + return within_including_scrolloffsets(element, x, y); + this.xcomp = x; + this.ycomp = y; + var offsettop = element.offsetTop; + var offsetleft = element.offsetLeft; + return (y>=offsettop && + y<offsettop+element.offsetHeight && + x>=offsetleft && + x<offsetleft+element.offsetWidth); + }, + + within_including_scrolloffsets: function(element, x, y) { + var offsetcache = this.real_offset(element); + this.xcomp = x + offsetcache[0] - this.deltaX; + this.ycomp = y + offsetcache[1] - this.deltaY; + this.xcomp = x; + this.ycomp = y; + var offsettop = element.offsetTop; + var offsetleft = element.offsetLeft; + return (y>=offsettop && + y<offsettop+element.offsetHeight && + x>=offsetleft && + x<offsetleft+element.offsetWidth); + }, + + // within must be called directly before + overlap: function(mode, element) { + if(!mode) return 0; + if(mode == 'vertical') + return ((element.offsetTop+element.offsetHeight)-this.ycomp) / element.offsetHeight; + if(mode == 'horizontal') + return ((element.offsetLeft+element.offsetWidth)-this.xcomp) / element.offsetWidth; + }, + + clone: function(source, target) { + $(target).style.top = $(source).style.top; + $(target).style.left = $(source).style.left; + $(target).style.width = $(source).offsetWidth + "px"; + $(target).style.height = $(source).offsetHeight + "px"; + } +}
\ No newline at end of file |