From 7da736f929e88f4730f160d28afc90667c26b966 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 26 Jun 2005 12:03:43 +0000 Subject: Added script.aculo.us Javascripts (controls.js, dragdrop.js, effects.js) (NEEDS MORE DESCRIPTION) #1509 [Thomas Fuchs] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1522 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- .../lib/action_view/helpers/javascripts/effects.js | 557 +++++++++++++++++++++ 1 file changed, 557 insertions(+) create mode 100644 actionpack/lib/action_view/helpers/javascripts/effects.js (limited to 'actionpack/lib/action_view/helpers/javascripts/effects.js') 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 -- cgit v1.2.3