// copyright (c) 2005 thomas fuchs (http://script.aculo.us, http://mir.aculo.us) // contributors: // justin palmer (http://encytemedia.com/) // mark pilgrim (http://diveintomark.org/) // martin bialasinki // // see scriptaculous.js for full license. /* ------------- element ext -------------- */ // converts rgb() and #xxx to #xxxxxx format, // returns self (or first argument) if not convertable string.prototype.parsecolor = function() { var color = '#'; if(this.slice(0,4) == 'rgb(') { var cols = this.slice(4,this.length-1).split(','); var i=0; do { color += parseint(cols[i]).tocolorpart() } while (++i<3); } else { if(this.slice(0,1) == '#') { if(this.length==4) for(var i=1;i<4;i++) color += (this.charat(i) + this.charat(i)).tolowercase(); if(this.length==7) color = this.tolowercase(); } } return(color.length==7 ? color : (arguments[0] || this)); } element.collecttextnodes = function(element) { return $a($(element).childnodes).collect( function(node) { return (node.nodetype==3 ? node.nodevalue : (node.haschildnodes() ? element.collecttextnodes(node) : '')); }).flatten().join(''); } element.collecttextnodesignoreclass = function(element, classname) { return $a($(element).childnodes).collect( function(node) { return (node.nodetype==3 ? node.nodevalue : ((node.haschildnodes() && !element.hasclassname(node,classname)) ? element.collecttextnodes(node) : '')); }).flatten().join(''); } element.setstyle = function(element, style) { element = $(element); for(k in style) element.style[k.camelize()] = style[k]; } element.setcontentzoom = function(element, percent) { element.setstyle(element, {fontsize: (percent/100) + 'em'}); if(navigator.appversion.indexof('applewebkit')>0) window.scrollby(0,0); } element.getopacity = function(element){ 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){ element= $(element); if (value == 1){ element.setstyle(element, { opacity: (/gecko/.test(navigator.useragent) && !/konqueror|safari|khtml/.test(navigator.useragent)) ? 0.999999 : null }); if(/msie/.test(navigator.useragent)) element.setstyle(element, {filter: element.getstyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')}); } else { if(value < 0.00001) value = 0; element.setstyle(element, {opacity: value}); if(/msie/.test(navigator.useragent)) element.setstyle(element, { filter: element.getstyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') + 'alpha(opacity='+value*100+')' }); } } element.getinlineopacity = function(element){ return $(element).style.opacity || ''; } element.childrenwithclassname = function(element, classname) { return $a($(element).getelementsbytagname('*')).select( function(c) { return element.hasclassname(c, classname) }); } array.prototype.call = function() { var args = arguments; this.each(function(f){ f.apply(this, args) }); } /*--------------------------------------------------------------------------*/ var effect = { tagifytext: function(element) { var tagifystyle = 'position:relative'; if(/msie/.test(navigator.useragent)) tagifystyle += ';zoom:1'; element = $(element); $a(element.childnodes).each( function(child) { if(child.nodetype==3) { child.nodevalue.toarray().each( function(character) { element.insertbefore( builder.node('span',{style: tagifystyle}, character == ' ' ? string.fromcharcode(160) : character), child); }); element.remove(child); } }); }, multiple: function(element, effect) { var elements; if(((typeof element == 'object') || (typeof element == 'function')) && (element.length)) elements = element; else elements = $(element).childnodes; var options = object.extend({ speed: 0.1, delay: 0.0 }, arguments[2] || {}); var masterdelay = options.delay; $a(elements).each( function(element, index) { new effect(element, object.extend(options, { delay: index * options.speed + masterdelay })); }); }, pairs: { 'slide': ['slidedown','slideup'], 'blind': ['blinddown','blindup'], 'appear': ['appear','fade'] }, toggle: function(element, effect) { element = $(element); effect = (effect || 'appear').tolowercase(); var options = object.extend({ queue: { position:'end', scope:(element.id || 'global') } }, arguments[2] || {}); effect[element.visible(element) ? effect.pairs[effect][1] : effect.pairs[effect][0]](element, options); } }; var 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()/4; } 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.scopedqueue = class.create(); object.extend(object.extend(effect.scopedqueue.prototype, enumerable), { initialize: function() { this.effects = []; this.interval = null; }, _each: function(iterator) { this.effects._each(iterator); }, add: function(effect) { var timestamp = new date().gettime(); var position = (typeof effect.options.queue == 'string') ? effect.options.queue : effect.options.queue.position; switch(position) { case 'front': // move unstarted effects after this effect this.effects.findall(function(e){ return e.state=='idle' }).each( function(e) { e.starton += effect.finishon; e.finishon += effect.finishon; }); break; case 'end': // start effect after last queued effect has finished timestamp = this.effects.pluck('finishon').max() || timestamp; break; } effect.starton += timestamp; effect.finishon += timestamp; this.effects.push(effect); if(!this.interval) this.interval = setinterval(this.loop.bind(this), 40); }, remove: function(effect) { this.effects = this.effects.reject(function(e) { return e==effect }); if(this.effects.length == 0) { clearinterval(this.interval); this.interval = null; } }, loop: function() { var timepos = new date().gettime(); this.effects.invoke('loop', timepos); } }); effect.queues = { instances: $h(), get: function(queuename) { if(typeof queuename != 'string') return queuename; if(!this.instances[queuename]) this.instances[queuename] = new effect.scopedqueue(); return this.instances[queuename]; } } effect.queue = effect.queues.get('global'); effect.defaultoptions = { transition: effect.transitions.sinoidal, duration: 1.0, // seconds fps: 25.0, // max. 25fps due to effect.queue implementation sync: false, // true for combining from: 0.0, to: 1.0, delay: 0.0, queue: 'parallel' } effect.base = function() {}; effect.base.prototype = { position: null, start: function(options) { this.options = object.extend(object.extend({},effect.defaultoptions), options || {}); this.currentframe = 0; this.state = 'idle'; this.starton = this.options.delay*1000; this.finishon = this.starton + (this.options.duration*1000); this.event('beforestart'); if(!this.options.sync) effect.queues.get(typeof this.options.queue == 'string' ? 'global' : this.options.queue.scope).add(this); }, loop: function(timepos) { if(timepos >= this.starton) { if(timepos >= this.finishon) { this.render(1.0); this.cancel(); this.event('beforefinish'); if(this.finish) this.finish(); this.event('afterfinish'); return; } var pos = (timepos - this.starton) / (this.finishon - this.starton); var frame = math.round(pos * this.options.fps * this.options.duration); if(frame > this.currentframe) { this.render(pos); this.currentframe = frame; } } }, render: function(pos) { if(this.state == 'idle') { this.state = 'running'; this.event('beforesetup'); if(this.setup) this.setup(); this.event('aftersetup'); } if(this.state == 'running') { 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'); } }, cancel: function() { if(!this.options.sync) effect.queues.get(typeof this.options.queue == 'string' ? 'global' : this.options.queue.scope).remove(this); this.state = 'finished'; }, event: function(eventname) { if(this.options[eventname + 'internal']) this.options[eventname + 'internal'](this); if(this.options[eventname]) this.options[eventname](this); }, inspect: function() { return '#'; } } effect.parallel = class.create(); object.extend(object.extend(effect.parallel.prototype, effect.base.prototype), { initialize: function(effects) { this.effects = effects || []; this.start(arguments[1]); }, update: function(position) { this.effects.invoke('render', position); }, finish: function(position) { this.effects.each( function(effect) { effect.render(1.0); effect.cancel(); effect.event('beforefinish'); if(effect.finish) effect.finish(position); effect.event('afterfinish'); }); } }); 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)) element.setstyle(this.element, {zoom: 1}); var options = object.extend({ from: element.getopacity(this.element) || 0.0, to: 1.0 }, arguments[1] || {}); this.start(options); }, update: function(position) { element.setopacity(this.element, position); } }); effect.move = class.create(); object.extend(object.extend(effect.move.prototype, effect.base.prototype), { initialize: function(element) { this.element = $(element); var options = object.extend({ x: 0, y: 0, mode: 'relative' }, arguments[1] || {}); this.start(options); }, setup: function() { // bug in opera: opera returns the "real" position of a static element or // relative element that does not have top/left explicitly set. // ==> always set top and left for position relative elements in your stylesheets // (to 0 if you do not need them) element.makepositioned(this.element); this.originalleft = parsefloat(element.getstyle(this.element,'left') || '0'); this.originaltop = parsefloat(element.getstyle(this.element,'top') || '0'); if(this.options.mode == 'absolute') { // absolute movement, so we need to calc deltax and deltay this.options.x = this.options.x - this.originalleft; this.options.y = this.options.y - this.originaltop; } }, update: function(position) { element.setstyle(this.element, { left: this.options.x * position + this.originalleft + 'px', top: this.options.y * position + this.originaltop + 'px' }); } }); // for backwards compatibility effect.moveby = function(element, totop, toleft) { return new effect.move(element, object.extend({ x: toleft, y: totop }, arguments[3] || {})); }; effect.scale = class.create(); object.extend(object.extend(effect.scale.prototype, effect.base.prototype), { initialize: function(element, percent) { this.element = $(element) var options = object.extend({ scalex: true, scaley: true, scalecontent: true, scalefromcenter: false, scalemode: 'box', // 'box' or 'contents' or {} with provided values scalefrom: 100.0, scaleto: percent }, arguments[2] || {}); this.start(options); }, setup: function() { this.restoreafterfinish = this.options.restoreafterfinish || false; this.elementpositioning = element.getstyle(this.element,'position'); this.originalstyle = {}; ['top','left','width','height','fontsize'].each( function(k) { this.originalstyle[k] = this.element.style[k]; }.bind(this)); this.originaltop = this.element.offsettop; this.originalleft = this.element.offsetleft; var fontsize = element.getstyle(this.element,'font-size') || '100%'; ['em','px','%'].each( function(fontsizetype) { if(fontsize.indexof(fontsizetype)>0) { this.fontsize = parsefloat(fontsize); this.fontsizetype = fontsizetype; } }.bind(this)); this.factor = (this.options.scaleto - this.options.scalefrom)/100; this.dims = null; if(this.options.scalemode=='box') this.dims = [this.element.offsetheight, this.element.offsetwidth]; if(/^content/.test(this.options.scalemode)) 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) element.setstyle(this.element, {fontsize: this.fontsize * currentscale + this.fontsizetype }); this.setdimensions(this.dims[0] * currentscale, this.dims[1] * currentscale); }, finish: function(position) { if (this.restoreafterfinish) element.setstyle(this.element, this.originalstyle); }, setdimensions: function(height, width) { var d = {}; if(this.options.scalex) d.width = width + 'px'; if(this.options.scaley) d.height = height + 'px'; if(this.options.scalefromcenter) { var topd = (height - this.dims[0])/2; var leftd = (width - this.dims[1])/2; if(this.elementpositioning == 'absolute') { if(this.options.scaley) d.top = this.originaltop-topd + 'px'; if(this.options.scalex) d.left = this.originalleft-leftd + 'px'; } else { if(this.options.scaley) d.top = -topd + 'px'; if(this.options.scalex) d.left = -leftd + 'px'; } } element.setstyle(this.element, d); } }); effect.highlight = class.create(); object.extend(object.extend(effect.highlight.prototype, effect.base.prototype), { initialize: function(element) { this.element = $(element); var options = object.extend({ startcolor: '#ffff99' }, arguments[1] || {}); this.start(options); }, setup: function() { // prevent executing on elements not in the layout flow if(element.getstyle(this.element, 'display')=='none') { this.cancel(); return; } // disable background image during the effect this.oldstyle = { backgroundimage: element.getstyle(this.element, 'background-image') }; element.setstyle(this.element, {backgroundimage: 'none'}); if(!this.options.endcolor) this.options.endcolor = element.getstyle(this.element, 'background-color').parsecolor('#ffffff'); if(!this.options.restorecolor) this.options.restorecolor = element.getstyle(this.element, 'background-color'); // init color calculations this._base = $r(0,2).map(function(i){ return parseint(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); this._delta = $r(0,2).map(function(i){ return parseint(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this)); }, update: function(position) { element.setstyle(this.element,{backgroundcolor: $r(0,2).inject('#',function(m,v,i){ return m+(math.round(this._base[i]+(this._delta[i]*position)).tocolorpart()); }.bind(this)) }); }, finish: function() { element.setstyle(this.element, object.extend(this.oldstyle, { backgroundcolor: this.options.restorecolor })); } }); effect.scrollto = class.create(); object.extend(object.extend(effect.scrollto.prototype, effect.base.prototype), { initialize: function(element) { this.element = $(element); this.start(arguments[1] || {}); }, setup: function() { position.prepare(); var offsets = position.cumulativeoffset(this.element); if(this.options.offset) offsets[1] += this.options.offset; var max = window.innerheight ? window.height - window.innerheight : document.body.scrollheight - (document.documentelement.clientheight ? document.documentelement.clientheight : document.body.clientheight); this.scrollstart = position.deltay; this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollstart; }, update: function(position) { position.prepare(); window.scrollto(position.deltax, this.scrollstart + (position*this.delta)); } }); /* ------------- combination effects ------------- */ effect.fade = function(element) { var oldopacity = element.getinlineopacity(element); var options = object.extend({ from: element.getopacity(element) || 1.0, to: 0.0, afterfinishinternal: function(effect) { with(element) { if(effect.options.to!=0) return; hide(effect.element); setstyle(effect.element, {opacity: oldopacity}); }} }, arguments[1] || {}); return new effect.opacity(element,options); } effect.appear = function(element) { var options = object.extend({ from: (element.getstyle(element, 'display') == 'none' ? 0.0 : element.getopacity(element) || 0.0), to: 1.0, beforesetup: function(effect) { with(element) { setopacity(effect.element, effect.options.from); show(effect.element); }} }, arguments[1] || {}); return new effect.opacity(element,options); } effect.puff = function(element) { element = $(element); var oldstyle = { opacity: element.getinlineopacity(element), position: element.getstyle(element, 'position') }; return new effect.parallel( [ new effect.scale(element, 200, { sync: true, scalefromcenter: true, scalecontent: true, restoreafterfinish: true }), new effect.opacity(element, { sync: true, to: 0.0 } ) ], object.extend({ duration: 1.0, beforesetupinternal: function(effect) { with(element) { setstyle(effect.effects[0].element, {position: 'absolute'}); }}, afterfinishinternal: function(effect) { with(element) { hide(effect.effects[0].element); setstyle(effect.effects[0].element, oldstyle); }} }, arguments[1] || {}) ); } effect.blindup = function(element) { element = $(element); element.makeclipping(element); return new effect.scale(element, 0, object.extend({ scalecontent: false, scalex: false, restoreafterfinish: true, afterfinishinternal: function(effect) { with(element) { [hide, undoclipping].call(effect.element); }} }, arguments[1] || {}) ); } effect.blinddown = function(element) { element = $(element); var oldheight = element.getstyle(element, 'height'); var elementdimensions = element.getdimensions(element); return new effect.scale(element, 100, object.extend({ scalecontent: false, scalex: false, scalefrom: 0, scalemode: {originalheight: elementdimensions.height, originalwidth: elementdimensions.width}, restoreafterfinish: true, aftersetup: function(effect) { with(element) { makeclipping(effect.element); setstyle(effect.element, {height: '0px'}); show(effect.element); }}, afterfinishinternal: function(effect) { with(element) { undoclipping(effect.element); setstyle(effect.element, {height: oldheight}); }} }, arguments[1] || {}) ); } effect.switchoff = function(element) { element = $(element); var oldopacity = element.getinlineopacity(element); return new effect.appear(element, { duration: 0.4, from: 0, transition: effect.transitions.flicker, afterfinishinternal: function(effect) { new effect.scale(effect.element, 1, { duration: 0.3, scalefromcenter: true, scalex: false, scalecontent: false, restoreafterfinish: true, beforesetup: function(effect) { with(element) { [makepositioned,makeclipping].call(effect.element); }}, afterfinishinternal: function(effect) { with(element) { [hide,undoclipping,undopositioned].call(effect.element); setstyle(effect.element, {opacity: oldopacity}); }} }) } }); } effect.dropout = function(element) { element = $(element); var oldstyle = { top: element.getstyle(element, 'top'), left: element.getstyle(element, 'left'), opacity: element.getinlineopacity(element) }; return new effect.parallel( [ new effect.move(element, {x: 0, y: 100, sync: true }), new effect.opacity(element, { sync: true, to: 0.0 }) ], object.extend( { duration: 0.5, beforesetup: function(effect) { with(element) { makepositioned(effect.effects[0].element); }}, afterfinishinternal: function(effect) { with(element) { [hide, undopositioned].call(effect.effects[0].element); setstyle(effect.effects[0].element, oldstyle); }} }, arguments[1] || {})); } effect.shake = function(element) { element = $(element); var oldstyle = { top: element.getstyle(element, 'top'), left: element.getstyle(element, 'left') }; return new effect.move(element, { x: 20, y: 0, duration: 0.05, afterfinishinternal: function(effect) { new effect.move(effect.element, { x: -40, y: 0, duration: 0.1, afterfinishinternal: function(effect) { new effect.move(effect.element, { x: 40, y: 0, duration: 0.1, afterfinishinternal: function(effect) { new effect.move(effect.element, { x: -40, y: 0, duration: 0.1, afterfinishinternal: function(effect) { new effect.move(effect.element, { x: 40, y: 0, duration: 0.1, afterfinishinternal: function(effect) { new effect.move(effect.element, { x: -20, y: 0, duration: 0.05, afterfinishinternal: function(effect) { with(element) { undopositioned(effect.element); setstyle(effect.element, oldstyle); }}}) }}) }}) }}) }}) }}); } effect.slidedown = function(element) { element = $(element); element.cleanwhitespace(element); // slidedown need to have the content of the element wrapped in a container element with fixed height! var oldinnerbottom = element.getstyle(element.firstchild, 'bottom'); var elementdimensions = element.getdimensions(element); return new effect.scale(element, 100, object.extend({ scalecontent: false, scalex: false, scalefrom: 0, scalemode: {originalheight: elementdimensions.height, originalwidth: elementdimensions.width}, restoreafterfinish: true, aftersetup: function(effect) { with(element) { makepositioned(effect.element); makepositioned(effect.element.firstchild); if(window.opera) setstyle(effect.element, {top: ''}); makeclipping(effect.element); setstyle(effect.element, {height: '0px'}); show(element); }}, afterupdateinternal: function(effect) { with(element) { setstyle(effect.element.firstchild, {bottom: (effect.dims[0] - effect.element.clientheight) + 'px' }); }}, afterfinishinternal: function(effect) { with(element) { undoclipping(effect.element); undopositioned(effect.element.firstchild); undopositioned(effect.element); setstyle(effect.element.firstchild, {bottom: oldinnerbottom}); }} }, arguments[1] || {}) ); } effect.slideup = function(element) { element = $(element); element.cleanwhitespace(element); var oldinnerbottom = element.getstyle(element.firstchild, 'bottom'); return new effect.scale(element, 0, object.extend({ scalecontent: false, scalex: false, scalemode: 'box', scalefrom: 100, restoreafterfinish: true, beforestartinternal: function(effect) { with(element) { makepositioned(effect.element); makepositioned(effect.element.firstchild); if(window.opera) setstyle(effect.element, {top: ''}); makeclipping(effect.element); show(element); }}, afterupdateinternal: function(effect) { with(element) { setstyle(effect.element.firstchild, {bottom: (effect.dims[0] - effect.element.clientheight) + 'px' }); }}, afterfinishinternal: function(effect) { with(element) { [hide, undoclipping].call(effect.element); undopositioned(effect.element.firstchild); undopositioned(effect.element); setstyle(effect.element.firstchild, {bottom: oldinnerbottom}); }} }, arguments[1] || {}) ); } // bug in opera makes the td containing this element expand for a instance after finish effect.squish = function(element) { return new effect.scale(element, window.opera ? 1 : 0, { restoreafterfinish: true, beforesetup: function(effect) { with(element) { makeclipping(effect.element); }}, afterfinishinternal: function(effect) { with(element) { hide(effect.element); undoclipping(effect.element); }} }); } effect.grow = function(element) { element = $(element); var options = object.extend({ direction: 'center', movetransistion: effect.transitions.sinoidal, scaletransition: effect.transitions.sinoidal, opacitytransition: effect.transitions.full }, arguments[1] || {}); var oldstyle = { top: element.style.top, left: element.style.left, height: element.style.height, width: element.style.width, opacity: element.getinlineopacity(element) }; var dims = element.getdimensions(element); var initialmovex, initialmovey; var movex, movey; switch (options.direction) { case 'top-left': initialmovex = initialmovey = movex = movey = 0; break; case 'top-right': initialmovex = dims.width; initialmovey = movey = 0; movex = -dims.width; break; case 'bottom-left': initialmovex = movex = 0; initialmovey = dims.height; movey = -dims.height; break; case 'bottom-right': initialmovex = dims.width; initialmovey = dims.height; movex = -dims.width; movey = -dims.height; break; case 'center': initialmovex = dims.width / 2; initialmovey = dims.height / 2; movex = -dims.width / 2; movey = -dims.height / 2; break; } return new effect.move(element, { x: initialmovex, y: initialmovey, duration: 0.01, beforesetup: function(effect) { with(element) { hide(effect.element); makeclipping(effect.element); makepositioned(effect.element); }}, afterfinishinternal: function(effect) { new effect.parallel( [ new effect.opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacitytransition }), new effect.move(effect.element, { x: movex, y: movey, sync: true, transition: options.movetransition }), new effect.scale(effect.element, 100, { scalemode: { originalheight: dims.height, originalwidth: dims.width }, sync: true, scalefrom: window.opera ? 1 : 0, transition: options.scaletransition, restoreafterfinish: true}) ], object.extend({ beforesetup: function(effect) { with(element) { setstyle(effect.effects[0].element, {height: '0px'}); show(effect.effects[0].element); }}, afterfinishinternal: function(effect) { with(element) { [undoclipping, undopositioned].call(effect.effects[0].element); setstyle(effect.effects[0].element, oldstyle); }} }, options) ) } }); } effect.shrink = function(element) { element = $(element); var options = object.extend({ direction: 'center', movetransistion: effect.transitions.sinoidal, scaletransition: effect.transitions.sinoidal, opacitytransition: effect.transitions.none }, arguments[1] || {}); var oldstyle = { top: element.style.top, left: element.style.left, height: element.style.height, width: element.style.width, opacity: element.getinlineopacity(element) }; var dims = element.getdimensions(element); var movex, movey; switch (options.direction) { case 'top-left': movex = movey = 0; break; case 'top-right': movex = dims.width; movey = 0; break; case 'bottom-left': movex = 0; movey = dims.height; break; case 'bottom-right': movex = dims.width; movey = dims.height; break; case 'center': movex = dims.width / 2; movey = dims.height / 2; break; } return new effect.parallel( [ new effect.opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacitytransition }), new effect.scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaletransition, restoreafterfinish: true}), new effect.move(element, { x: movex, y: movey, sync: true, transition: options.movetransition }) ], object.extend({ beforestartinternal: function(effect) { with(element) { [makepositioned, makeclipping].call(effect.effects[0].element) }}, afterfinishinternal: function(effect) { with(element) { [hide, undoclipping, undopositioned].call(effect.effects[0].element); setstyle(effect.effects[0].element, oldstyle); }} }, options) ); } effect.pulsate = function(element) { element = $(element); var options = arguments[1] || {}; var oldopacity = element.getinlineopacity(element); var transition = options.transition || effect.transitions.sinoidal; var reverser = function(pos){ return transition(1-effect.transitions.pulse(pos)) }; reverser.bind(transition); return new effect.opacity(element, object.extend(object.extend({ duration: 3.0, from: 0, afterfinishinternal: function(effect) { element.setstyle(effect.element, {opacity: oldopacity}); } }, options), {transition: reverser})); } effect.fold = function(element) { element = $(element); var oldstyle = { top: element.style.top, left: element.style.left, width: element.style.width, height: element.style.height }; element.makeclipping(element); return new effect.scale(element, 5, object.extend({ scalecontent: false, scalex: false, afterfinishinternal: function(effect) { new effect.scale(element, 1, { scalecontent: false, scaley: false, afterfinishinternal: function(effect) { with(element) { [hide, undoclipping].call(effect.element); setstyle(effect.element, oldstyle); }} }); }}, arguments[1] || {})); }