effects.js
上传用户:jisenq
上传日期:2014-06-29
资源大小:7216k
文件大小:32k
源码类别:

数据库编程

开发平台:

ASP/ASPX

  1. // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
  2. // Contributors:
  3. //  Justin Palmer (http://encytemedia.com/)
  4. //  Mark Pilgrim (http://diveintomark.org/)
  5. //  Martin Bialasinki
  6. // 
  7. // See scriptaculous.js for full license.  
  8. /* ------------- element ext -------------- */  
  9.  
  10. // converts rgb() and #xxx to #xxxxxx format,  
  11. // returns self (or first argument) if not convertable  
  12. String.prototype.parseColor = function() {  
  13.   var color = '#';  
  14.   if(this.slice(0,4) == 'rgb(') {  
  15.     var cols = this.slice(4,this.length-1).split(',');  
  16.     var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);  
  17.   } else {  
  18.     if(this.slice(0,1) == '#') {  
  19.       if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();  
  20.       if(this.length==7) color = this.toLowerCase();  
  21.     }  
  22.   }  
  23.   return(color.length==7 ? color : (arguments[0] || this));  
  24. }
  25. Element.collectTextNodes = function(element) {  
  26.   return $A($(element).childNodes).collect( function(node) {
  27.     return (node.nodeType==3 ? node.nodeValue : 
  28.       (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
  29.   }).flatten().join('');
  30. }
  31. Element.collectTextNodesIgnoreClass = function(element, className) {  
  32.   return $A($(element).childNodes).collect( function(node) {
  33.     return (node.nodeType==3 ? node.nodeValue : 
  34.       ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? 
  35.         Element.collectTextNodes(node) : ''));
  36.   }).flatten().join('');
  37. }
  38. Element.setStyle = function(element, style) {
  39.   element = $(element);
  40.   for(k in style) element.style[k.camelize()] = style[k];
  41. }
  42. Element.setContentZoom = function(element, percent) {  
  43.   Element.setStyle(element, {fontSize: (percent/100) + 'em'});   
  44.   if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);  
  45. }
  46. Element.getOpacity = function(element){  
  47.   var opacity;
  48.   if (opacity = Element.getStyle(element, 'opacity'))  
  49.     return parseFloat(opacity);  
  50.   if (opacity = (Element.getStyle(element, 'filter') || '').match(/alpha(opacity=(.*))/))  
  51.     if(opacity[1]) return parseFloat(opacity[1]) / 100;  
  52.   return 1.0;  
  53. }
  54. Element.setOpacity = function(element, value){  
  55.   element= $(element);  
  56.   if (value == 1){
  57.     Element.setStyle(element, { opacity: 
  58.       (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 
  59.       0.999999 : null });
  60.     if(/MSIE/.test(navigator.userAgent))  
  61.       Element.setStyle(element, {filter: Element.getStyle(element,'filter').replace(/alpha([^)]*)/gi,'')});  
  62.   } else {  
  63.     if(value < 0.00001) value = 0;  
  64.     Element.setStyle(element, {opacity: value});
  65.     if(/MSIE/.test(navigator.userAgent))  
  66.      Element.setStyle(element, 
  67.        { filter: Element.getStyle(element,'filter').replace(/alpha([^)]*)/gi,'') +
  68.                  'alpha(opacity='+value*100+')' });  
  69.   }   
  70. }  
  71.  
  72. Element.getInlineOpacity = function(element){  
  73.   return $(element).style.opacity || '';
  74. }  
  75. Element.childrenWithClassName = function(element, className) {  
  76.   return $A($(element).getElementsByTagName('*')).select(
  77.     function(c) { return Element.hasClassName(c, className) });
  78. }
  79. Array.prototype.call = function() {
  80.   var args = arguments;
  81.   this.each(function(f){ f.apply(this, args) });
  82. }
  83. /*--------------------------------------------------------------------------*/
  84. var Effect = {
  85.   tagifyText: function(element) {
  86.     var tagifyStyle = 'position:relative';
  87.     if(/MSIE/.test(navigator.userAgent)) tagifyStyle += ';zoom:1';
  88.     element = $(element);
  89.     $A(element.childNodes).each( function(child) {
  90.       if(child.nodeType==3) {
  91.         child.nodeValue.toArray().each( function(character) {
  92.           element.insertBefore(
  93.             Builder.node('span',{style: tagifyStyle},
  94.               character == ' ' ? String.fromCharCode(160) : character), 
  95.               child);
  96.         });
  97.         Element.remove(child);
  98.       }
  99.     });
  100.   },
  101.   multiple: function(element, effect) {
  102.     var elements;
  103.     if(((typeof element == 'object') || 
  104.         (typeof element == 'function')) && 
  105.        (element.length))
  106.       elements = element;
  107.     else
  108.       elements = $(element).childNodes;
  109.       
  110.     var options = Object.extend({
  111.       speed: 0.1,
  112.       delay: 0.0
  113.     }, arguments[2] || {});
  114.     var masterDelay = options.delay;
  115.     $A(elements).each( function(element, index) {
  116.       new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
  117.     });
  118.   },
  119.   PAIRS: {
  120.     'slide':  ['SlideDown','SlideUp'],
  121.     'blind':  ['BlindDown','BlindUp'],
  122.     'appear': ['Appear','Fade']
  123.   },
  124.   toggle: function(element, effect) {
  125.     element = $(element);
  126.     effect = (effect || 'appear').toLowerCase();
  127.     var options = Object.extend({
  128.       queue: { position:'end', scope:(element.id || 'global') }
  129.     }, arguments[2] || {});
  130.     Effect[Element.visible(element) ? 
  131.       Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
  132.   }
  133. };
  134. var Effect2 = Effect; // deprecated
  135. /* ------------- transitions ------------- */
  136. Effect.Transitions = {}
  137. Effect.Transitions.linear = function(pos) {
  138.   return pos;
  139. }
  140. Effect.Transitions.sinoidal = function(pos) {
  141.   return (-Math.cos(pos*Math.PI)/2) + 0.5;
  142. }
  143. Effect.Transitions.reverse  = function(pos) {
  144.   return 1-pos;
  145. }
  146. Effect.Transitions.flicker = function(pos) {
  147.   return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
  148. }
  149. Effect.Transitions.wobble = function(pos) {
  150.   return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
  151. }
  152. Effect.Transitions.pulse = function(pos) {
  153.   return (Math.floor(pos*10) % 2 == 0 ? 
  154.     (pos*10-Math.floor(pos*10)) : 1-(pos*10-Math.floor(pos*10)));
  155. }
  156. Effect.Transitions.none = function(pos) {
  157.   return 0;
  158. }
  159. Effect.Transitions.full = function(pos) {
  160.   return 1;
  161. }
  162. /* ------------- core effects ------------- */
  163. Effect.ScopedQueue = Class.create();
  164. Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
  165.   initialize: function() {
  166.     this.effects  = [];
  167.     this.interval = null;
  168.   },
  169.   _each: function(iterator) {
  170.     this.effects._each(iterator);
  171.   },
  172.   add: function(effect) {
  173.     var timestamp = new Date().getTime();
  174.     
  175.     var position = (typeof effect.options.queue == 'string') ? 
  176.       effect.options.queue : effect.options.queue.position;
  177.     
  178.     switch(position) {
  179.       case 'front':
  180.         // move unstarted effects after this effect  
  181.         this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
  182.             e.startOn  += effect.finishOn;
  183.             e.finishOn += effect.finishOn;
  184.           });
  185.         break;
  186.       case 'end':
  187.         // start effect after last queued effect has finished
  188.         timestamp = this.effects.pluck('finishOn').max() || timestamp;
  189.         break;
  190.     }
  191.     
  192.     effect.startOn  += timestamp;
  193.     effect.finishOn += timestamp;
  194.     this.effects.push(effect);
  195.     if(!this.interval) 
  196.       this.interval = setInterval(this.loop.bind(this), 40);
  197.   },
  198.   remove: function(effect) {
  199.     this.effects = this.effects.reject(function(e) { return e==effect });
  200.     if(this.effects.length == 0) {
  201.       clearInterval(this.interval);
  202.       this.interval = null;
  203.     }
  204.   },
  205.   loop: function() {
  206.     var timePos = new Date().getTime();
  207.     this.effects.invoke('loop', timePos);
  208.   }
  209. });
  210. Effect.Queues = {
  211.   instances: $H(),
  212.   get: function(queueName) {
  213.     if(typeof queueName != 'string') return queueName;
  214.     
  215.     if(!this.instances[queueName])
  216.       this.instances[queueName] = new Effect.ScopedQueue();
  217.       
  218.     return this.instances[queueName];
  219.   }
  220. }
  221. Effect.Queue = Effect.Queues.get('global');
  222. Effect.DefaultOptions = {
  223.   transition: Effect.Transitions.sinoidal,
  224.   duration:   1.0,   // seconds
  225.   fps:        25.0,  // max. 25fps due to Effect.Queue implementation
  226.   sync:       false, // true for combining
  227.   from:       0.0,
  228.   to:         1.0,
  229.   delay:      0.0,
  230.   queue:      'parallel'
  231. }
  232. Effect.Base = function() {};
  233. Effect.Base.prototype = {
  234.   position: null,
  235.   start: function(options) {
  236.     this.options      = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
  237.     this.currentFrame = 0;
  238.     this.state        = 'idle';
  239.     this.startOn      = this.options.delay*1000;
  240.     this.finishOn     = this.startOn + (this.options.duration*1000);
  241.     this.event('beforeStart');
  242.     if(!this.options.sync)
  243.       Effect.Queues.get(typeof this.options.queue == 'string' ? 
  244.         'global' : this.options.queue.scope).add(this);
  245.   },
  246.   loop: function(timePos) {
  247.     if(timePos >= this.startOn) {
  248.       if(timePos >= this.finishOn) {
  249.         this.render(1.0);
  250.         this.cancel();
  251.         this.event('beforeFinish');
  252.         if(this.finish) this.finish(); 
  253.         this.event('afterFinish');
  254.         return;  
  255.       }
  256.       var pos   = (timePos - this.startOn) / (this.finishOn - this.startOn);
  257.       var frame = Math.round(pos * this.options.fps * this.options.duration);
  258.       if(frame > this.currentFrame) {
  259.         this.render(pos);
  260.         this.currentFrame = frame;
  261.       }
  262.     }
  263.   },
  264.   render: function(pos) {
  265.     if(this.state == 'idle') {
  266.       this.state = 'running';
  267.       this.event('beforeSetup');
  268.       if(this.setup) this.setup();
  269.       this.event('afterSetup');
  270.     }
  271.     if(this.state == 'running') {
  272.       if(this.options.transition) pos = this.options.transition(pos);
  273.       pos *= (this.options.to-this.options.from);
  274.       pos += this.options.from;
  275.       this.position = pos;
  276.       this.event('beforeUpdate');
  277.       if(this.update) this.update(pos);
  278.       this.event('afterUpdate');
  279.     }
  280.   },
  281.   cancel: function() {
  282.     if(!this.options.sync)
  283.       Effect.Queues.get(typeof this.options.queue == 'string' ? 
  284.         'global' : this.options.queue.scope).remove(this);
  285.     this.state = 'finished';
  286.   },
  287.   event: function(eventName) {
  288.     if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
  289.     if(this.options[eventName]) this.options[eventName](this);
  290.   },
  291.   inspect: function() {
  292.     return '#<Effect:' + $H(this).inspect() + ',options:' + $H(this.options).inspect() + '>';
  293.   }
  294. }
  295. Effect.Parallel = Class.create();
  296. Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
  297.   initialize: function(effects) {
  298.     this.effects = effects || [];
  299.     this.start(arguments[1]);
  300.   },
  301.   update: function(position) {
  302.     this.effects.invoke('render', position);
  303.   },
  304.   finish: function(position) {
  305.     this.effects.each( function(effect) {
  306.       effect.render(1.0);
  307.       effect.cancel();
  308.       effect.event('beforeFinish');
  309.       if(effect.finish) effect.finish(position);
  310.       effect.event('afterFinish');
  311.     });
  312.   }
  313. });
  314. Effect.Opacity = Class.create();
  315. Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
  316.   initialize: function(element) {
  317.     this.element = $(element);
  318.     // make this work on IE on elements without 'layout'
  319.     if(/MSIE/.test(navigator.userAgent) && (!this.element.hasLayout))
  320.       Element.setStyle(this.element, {zoom: 1});
  321.     var options = Object.extend({
  322.       from: Element.getOpacity(this.element) || 0.0,
  323.       to:   1.0
  324.     }, arguments[1] || {});
  325.     this.start(options);
  326.   },
  327.   update: function(position) {
  328.     Element.setOpacity(this.element, position);
  329.   }
  330. });
  331. Effect.Move = Class.create();
  332. Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
  333.   initialize: function(element) {
  334.     this.element = $(element);
  335.     var options = Object.extend({
  336.       x:    0,
  337.       y:    0,
  338.       mode: 'relative'
  339.     }, arguments[1] || {});
  340.     this.start(options);
  341.   },
  342.   setup: function() {
  343.     // Bug in Opera: Opera returns the "real" position of a static element or
  344.     // relative element that does not have top/left explicitly set.
  345.     // ==> Always set top and left for position relative elements in your stylesheets 
  346.     // (to 0 if you do not need them) 
  347.     Element.makePositioned(this.element);
  348.     this.originalLeft = parseFloat(Element.getStyle(this.element,'left') || '0');
  349.     this.originalTop  = parseFloat(Element.getStyle(this.element,'top')  || '0');
  350.     if(this.options.mode == 'absolute') {
  351.       // absolute movement, so we need to calc deltaX and deltaY
  352.       this.options.x = this.options.x - this.originalLeft;
  353.       this.options.y = this.options.y - this.originalTop;
  354.     }
  355.   },
  356.   update: function(position) {
  357.     Element.setStyle(this.element, {
  358.       left: this.options.x  * position + this.originalLeft + 'px',
  359.       top:  this.options.y  * position + this.originalTop  + 'px'
  360.     });
  361.   }
  362. });
  363. // for backwards compatibility
  364. Effect.MoveBy = function(element, toTop, toLeft) {
  365.   return new Effect.Move(element, 
  366.     Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
  367. };
  368. Effect.Scale = Class.create();
  369. Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
  370.   initialize: function(element, percent) {
  371.     this.element = $(element)
  372.     var options = Object.extend({
  373.       scaleX: true,
  374.       scaleY: true,
  375.       scaleContent: true,
  376.       scaleFromCenter: false,
  377.       scaleMode: 'box',        // 'box' or 'contents' or {} with provided values
  378.       scaleFrom: 100.0,
  379.       scaleTo:   percent
  380.     }, arguments[2] || {});
  381.     this.start(options);
  382.   },
  383.   setup: function() {
  384.     this.restoreAfterFinish = this.options.restoreAfterFinish || false;
  385.     this.elementPositioning = Element.getStyle(this.element,'position');
  386.     
  387.     this.originalStyle = {};
  388.     ['top','left','width','height','fontSize'].each( function(k) {
  389.       this.originalStyle[k] = this.element.style[k];
  390.     }.bind(this));
  391.       
  392.     this.originalTop  = this.element.offsetTop;
  393.     this.originalLeft = this.element.offsetLeft;
  394.     
  395.     var fontSize = Element.getStyle(this.element,'font-size') || '100%';
  396.     ['em','px','%'].each( function(fontSizeType) {
  397.       if(fontSize.indexOf(fontSizeType)>0) {
  398.         this.fontSize     = parseFloat(fontSize);
  399.         this.fontSizeType = fontSizeType;
  400.       }
  401.     }.bind(this));
  402.     
  403.     this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
  404.     
  405.     this.dims = null;
  406.     if(this.options.scaleMode=='box')
  407.       this.dims = [this.element.offsetHeight, this.element.offsetWidth];
  408.     if(/^content/.test(this.options.scaleMode))
  409.       this.dims = [this.element.scrollHeight, this.element.scrollWidth];
  410.     if(!this.dims)
  411.       this.dims = [this.options.scaleMode.originalHeight,
  412.                    this.options.scaleMode.originalWidth];
  413.   },
  414.   update: function(position) {
  415.     var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
  416.     if(this.options.scaleContent && this.fontSize)
  417.       Element.setStyle(this.element, {fontSize: this.fontSize * currentScale + this.fontSizeType });
  418.     this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
  419.   },
  420.   finish: function(position) {
  421.     if (this.restoreAfterFinish) Element.setStyle(this.element, this.originalStyle);
  422.   },
  423.   setDimensions: function(height, width) {
  424.     var d = {};
  425.     if(this.options.scaleX) d.width = width + 'px';
  426.     if(this.options.scaleY) d.height = height + 'px';
  427.     if(this.options.scaleFromCenter) {
  428.       var topd  = (height - this.dims[0])/2;
  429.       var leftd = (width  - this.dims[1])/2;
  430.       if(this.elementPositioning == 'absolute') {
  431.         if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
  432.         if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
  433.       } else {
  434.         if(this.options.scaleY) d.top = -topd + 'px';
  435.         if(this.options.scaleX) d.left = -leftd + 'px';
  436.       }
  437.     }
  438.     Element.setStyle(this.element, d);
  439.   }
  440. });
  441. Effect.Highlight = Class.create();
  442. Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
  443.   initialize: function(element) {
  444.     this.element = $(element);
  445.     var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
  446.     this.start(options);
  447.   },
  448.   setup: function() {
  449.     // Prevent executing on elements not in the layout flow
  450.     if(Element.getStyle(this.element, 'display')=='none') { this.cancel(); return; }
  451.     // Disable background image during the effect
  452.     this.oldStyle = {
  453.       backgroundImage: Element.getStyle(this.element, 'background-image') };
  454.     Element.setStyle(this.element, {backgroundImage: 'none'});
  455.     if(!this.options.endcolor)
  456.       this.options.endcolor = Element.getStyle(this.element, 'background-color').parseColor('#ffffff');
  457.     if(!this.options.restorecolor)
  458.       this.options.restorecolor = Element.getStyle(this.element, 'background-color');
  459.     // init color calculations
  460.     this._base  = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
  461.     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));
  462.   },
  463.   update: function(position) {
  464.     Element.setStyle(this.element,{backgroundColor: $R(0,2).inject('#',function(m,v,i){
  465.       return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
  466.   },
  467.   finish: function() {
  468.     Element.setStyle(this.element, Object.extend(this.oldStyle, {
  469.       backgroundColor: this.options.restorecolor
  470.     }));
  471.   }
  472. });
  473. Effect.ScrollTo = Class.create();
  474. Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
  475.   initialize: function(element) {
  476.     this.element = $(element);
  477.     this.start(arguments[1] || {});
  478.   },
  479.   setup: function() {
  480.     Position.prepare();
  481.     var offsets = Position.cumulativeOffset(this.element);
  482.     if(this.options.offset) offsets[1] += this.options.offset;
  483.     var max = window.innerHeight ? 
  484.       window.height - window.innerHeight :
  485.       document.body.scrollHeight - 
  486.         (document.documentElement.clientHeight ? 
  487.           document.documentElement.clientHeight : document.body.clientHeight);
  488.     this.scrollStart = Position.deltaY;
  489.     this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
  490.   },
  491.   update: function(position) {
  492.     Position.prepare();
  493.     window.scrollTo(Position.deltaX, 
  494.       this.scrollStart + (position*this.delta));
  495.   }
  496. });
  497. /* ------------- combination effects ------------- */
  498. Effect.Fade = function(element) {
  499.   var oldOpacity = Element.getInlineOpacity(element);
  500.   var options = Object.extend({
  501.   from: Element.getOpacity(element) || 1.0,
  502.   to:   0.0,
  503.   afterFinishInternal: function(effect) { with(Element) { 
  504.     if(effect.options.to!=0) return;
  505.     hide(effect.element);
  506.     setStyle(effect.element, {opacity: oldOpacity}); }}
  507.   }, arguments[1] || {});
  508.   return new Effect.Opacity(element,options);
  509. }
  510. Effect.Appear = function(element) {
  511.   var options = Object.extend({
  512.   from: (Element.getStyle(element, 'display') == 'none' ? 0.0 : Element.getOpacity(element) || 0.0),
  513.   to:   1.0,
  514.   beforeSetup: function(effect) { with(Element) {
  515.     setOpacity(effect.element, effect.options.from);
  516.     show(effect.element); }}
  517.   }, arguments[1] || {});
  518.   return new Effect.Opacity(element,options);
  519. }
  520. Effect.Puff = function(element) {
  521.   element = $(element);
  522.   var oldStyle = { opacity: Element.getInlineOpacity(element), position: Element.getStyle(element, 'position') };
  523.   return new Effect.Parallel(
  524.    [ new Effect.Scale(element, 200, 
  525.       { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), 
  526.      new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], 
  527.      Object.extend({ duration: 1.0, 
  528.       beforeSetupInternal: function(effect) { with(Element) {
  529.         setStyle(effect.effects[0].element, {position: 'absolute'}); }},
  530.       afterFinishInternal: function(effect) { with(Element) {
  531.          hide(effect.effects[0].element);
  532.          setStyle(effect.effects[0].element, oldStyle); }}
  533.      }, arguments[1] || {})
  534.    );
  535. }
  536. Effect.BlindUp = function(element) {
  537.   element = $(element);
  538.   Element.makeClipping(element);
  539.   return new Effect.Scale(element, 0, 
  540.     Object.extend({ scaleContent: false, 
  541.       scaleX: false, 
  542.       restoreAfterFinish: true,
  543.       afterFinishInternal: function(effect) { with(Element) {
  544.         [hide, undoClipping].call(effect.element); }} 
  545.     }, arguments[1] || {})
  546.   );
  547. }
  548. Effect.BlindDown = function(element) {
  549.   element = $(element);
  550.   var oldHeight = Element.getStyle(element, 'height');
  551.   var elementDimensions = Element.getDimensions(element);
  552.   return new Effect.Scale(element, 100, 
  553.     Object.extend({ scaleContent: false, 
  554.       scaleX: false,
  555.       scaleFrom: 0,
  556.       scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
  557.       restoreAfterFinish: true,
  558.       afterSetup: function(effect) { with(Element) {
  559.         makeClipping(effect.element);
  560.         setStyle(effect.element, {height: '0px'});
  561.         show(effect.element); 
  562.       }},  
  563.       afterFinishInternal: function(effect) { with(Element) {
  564.         undoClipping(effect.element);
  565.         setStyle(effect.element, {height: oldHeight});
  566.       }}
  567.     }, arguments[1] || {})
  568.   );
  569. }
  570. Effect.SwitchOff = function(element) {
  571.   element = $(element);
  572.   var oldOpacity = Element.getInlineOpacity(element);
  573.   return new Effect.Appear(element, { 
  574.     duration: 0.4,
  575.     from: 0,
  576.     transition: Effect.Transitions.flicker,
  577.     afterFinishInternal: function(effect) {
  578.       new Effect.Scale(effect.element, 1, { 
  579.         duration: 0.3, scaleFromCenter: true,
  580.         scaleX: false, scaleContent: false, restoreAfterFinish: true,
  581.         beforeSetup: function(effect) { with(Element) {
  582.           [makePositioned,makeClipping].call(effect.element);
  583.         }},
  584.         afterFinishInternal: function(effect) { with(Element) {
  585.           [hide,undoClipping,undoPositioned].call(effect.element);
  586.           setStyle(effect.element, {opacity: oldOpacity});
  587.         }}
  588.       })
  589.     }
  590.   });
  591. }
  592. Effect.DropOut = function(element) {
  593.   element = $(element);
  594.   var oldStyle = {
  595.     top: Element.getStyle(element, 'top'),
  596.     left: Element.getStyle(element, 'left'),
  597.     opacity: Element.getInlineOpacity(element) };
  598.   return new Effect.Parallel(
  599.     [ new Effect.Move(element, {x: 0, y: 100, sync: true }), 
  600.       new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
  601.     Object.extend(
  602.       { duration: 0.5,
  603.         beforeSetup: function(effect) { with(Element) {
  604.           makePositioned(effect.effects[0].element); }},
  605.         afterFinishInternal: function(effect) { with(Element) {
  606.           [hide, undoPositioned].call(effect.effects[0].element);
  607.           setStyle(effect.effects[0].element, oldStyle); }} 
  608.       }, arguments[1] || {}));
  609. }
  610. Effect.Shake = function(element) {
  611.   element = $(element);
  612.   var oldStyle = {
  613.     top: Element.getStyle(element, 'top'),
  614.     left: Element.getStyle(element, 'left') };
  615.   return new Effect.Move(element, 
  616.     { x:  20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
  617.   new Effect.Move(effect.element,
  618.     { x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
  619.   new Effect.Move(effect.element,
  620.     { x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
  621.   new Effect.Move(effect.element,
  622.     { x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
  623.   new Effect.Move(effect.element,
  624.     { x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
  625.   new Effect.Move(effect.element,
  626.     { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { with(Element) {
  627.         undoPositioned(effect.element);
  628.         setStyle(effect.element, oldStyle);
  629.   }}}) }}) }}) }}) }}) }});
  630. }
  631. Effect.SlideDown = function(element) {
  632.   element = $(element);
  633.   Element.cleanWhitespace(element);
  634.   // SlideDown need to have the content of the element wrapped in a container element with fixed height!
  635.   var oldInnerBottom = Element.getStyle(element.firstChild, 'bottom');
  636.   var elementDimensions = Element.getDimensions(element);
  637.   return new Effect.Scale(element, 100, Object.extend({ 
  638.     scaleContent: false, 
  639.     scaleX: false, 
  640.     scaleFrom: 0,
  641.     scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
  642.     restoreAfterFinish: true,
  643.     afterSetup: function(effect) { with(Element) {
  644.       makePositioned(effect.element);
  645.       makePositioned(effect.element.firstChild);
  646.       if(window.opera) setStyle(effect.element, {top: ''});
  647.       makeClipping(effect.element);
  648.       setStyle(effect.element, {height: '0px'});
  649.       show(element); }},
  650.     afterUpdateInternal: function(effect) { with(Element) {
  651.       setStyle(effect.element.firstChild, {bottom:
  652.         (effect.dims[0] - effect.element.clientHeight) + 'px' }); }},
  653.     afterFinishInternal: function(effect) { with(Element) {
  654.       undoClipping(effect.element); 
  655.       undoPositioned(effect.element.firstChild);
  656.       undoPositioned(effect.element);
  657.       setStyle(effect.element.firstChild, {bottom: oldInnerBottom}); }}
  658.     }, arguments[1] || {})
  659.   );
  660. }
  661.   
  662. Effect.SlideUp = function(element) {
  663.   element = $(element);
  664.   Element.cleanWhitespace(element);
  665.   var oldInnerBottom = Element.getStyle(element.firstChild, 'bottom');
  666.   return new Effect.Scale(element, 0, 
  667.    Object.extend({ scaleContent: false, 
  668.     scaleX: false, 
  669.     scaleMode: 'box',
  670.     scaleFrom: 100,
  671.     restoreAfterFinish: true,
  672.     beforeStartInternal: function(effect) { with(Element) {
  673.       makePositioned(effect.element);
  674.       makePositioned(effect.element.firstChild);
  675.       if(window.opera) setStyle(effect.element, {top: ''});
  676.       makeClipping(effect.element);
  677.       show(element); }},  
  678.     afterUpdateInternal: function(effect) { with(Element) {
  679.       setStyle(effect.element.firstChild, {bottom:
  680.         (effect.dims[0] - effect.element.clientHeight) + 'px' }); }},
  681.     afterFinishInternal: function(effect) { with(Element) {
  682.         [hide, undoClipping].call(effect.element); 
  683.         undoPositioned(effect.element.firstChild);
  684.         undoPositioned(effect.element);
  685.         setStyle(effect.element.firstChild, {bottom: oldInnerBottom}); }}
  686.    }, arguments[1] || {})
  687.   );
  688. }
  689. // Bug in opera makes the TD containing this element expand for a instance after finish 
  690. Effect.Squish = function(element) {
  691.   return new Effect.Scale(element, window.opera ? 1 : 0, 
  692.     { restoreAfterFinish: true,
  693.       beforeSetup: function(effect) { with(Element) {
  694.         makeClipping(effect.element); }},  
  695.       afterFinishInternal: function(effect) { with(Element) {
  696.         hide(effect.element); 
  697.         undoClipping(effect.element); }}
  698.   });
  699. }
  700. Effect.Grow = function(element) {
  701.   element = $(element);
  702.   var options = Object.extend({
  703.     direction: 'center',
  704.     moveTransistion: Effect.Transitions.sinoidal,
  705.     scaleTransition: Effect.Transitions.sinoidal,
  706.     opacityTransition: Effect.Transitions.full
  707.   }, arguments[1] || {});
  708.   var oldStyle = {
  709.     top: element.style.top,
  710.     left: element.style.left,
  711.     height: element.style.height,
  712.     width: element.style.width,
  713.     opacity: Element.getInlineOpacity(element) };
  714.   var dims = Element.getDimensions(element);    
  715.   var initialMoveX, initialMoveY;
  716.   var moveX, moveY;
  717.   
  718.   switch (options.direction) {
  719.     case 'top-left':
  720.       initialMoveX = initialMoveY = moveX = moveY = 0; 
  721.       break;
  722.     case 'top-right':
  723.       initialMoveX = dims.width;
  724.       initialMoveY = moveY = 0;
  725.       moveX = -dims.width;
  726.       break;
  727.     case 'bottom-left':
  728.       initialMoveX = moveX = 0;
  729.       initialMoveY = dims.height;
  730.       moveY = -dims.height;
  731.       break;
  732.     case 'bottom-right':
  733.       initialMoveX = dims.width;
  734.       initialMoveY = dims.height;
  735.       moveX = -dims.width;
  736.       moveY = -dims.height;
  737.       break;
  738.     case 'center':
  739.       initialMoveX = dims.width / 2;
  740.       initialMoveY = dims.height / 2;
  741.       moveX = -dims.width / 2;
  742.       moveY = -dims.height / 2;
  743.       break;
  744.   }
  745.   
  746.   return new Effect.Move(element, {
  747.     x: initialMoveX,
  748.     y: initialMoveY,
  749.     duration: 0.01, 
  750.     beforeSetup: function(effect) { with(Element) {
  751.       hide(effect.element);
  752.       makeClipping(effect.element);
  753.       makePositioned(effect.element);
  754.     }},
  755.     afterFinishInternal: function(effect) {
  756.       new Effect.Parallel(
  757.         [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
  758.           new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
  759.           new Effect.Scale(effect.element, 100, {
  760.             scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, 
  761.             sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
  762.         ], Object.extend({
  763.              beforeSetup: function(effect) { with(Element) {
  764.                setStyle(effect.effects[0].element, {height: '0px'});
  765.                show(effect.effects[0].element); }},
  766.              afterFinishInternal: function(effect) { with(Element) {
  767.                [undoClipping, undoPositioned].call(effect.effects[0].element); 
  768.                setStyle(effect.effects[0].element, oldStyle); }}
  769.            }, options)
  770.       )
  771.     }
  772.   });
  773. }
  774. Effect.Shrink = function(element) {
  775.   element = $(element);
  776.   var options = Object.extend({
  777.     direction: 'center',
  778.     moveTransistion: Effect.Transitions.sinoidal,
  779.     scaleTransition: Effect.Transitions.sinoidal,
  780.     opacityTransition: Effect.Transitions.none
  781.   }, arguments[1] || {});
  782.   var oldStyle = {
  783.     top: element.style.top,
  784.     left: element.style.left,
  785.     height: element.style.height,
  786.     width: element.style.width,
  787.     opacity: Element.getInlineOpacity(element) };
  788.   var dims = Element.getDimensions(element);
  789.   var moveX, moveY;
  790.   
  791.   switch (options.direction) {
  792.     case 'top-left':
  793.       moveX = moveY = 0;
  794.       break;
  795.     case 'top-right':
  796.       moveX = dims.width;
  797.       moveY = 0;
  798.       break;
  799.     case 'bottom-left':
  800.       moveX = 0;
  801.       moveY = dims.height;
  802.       break;
  803.     case 'bottom-right':
  804.       moveX = dims.width;
  805.       moveY = dims.height;
  806.       break;
  807.     case 'center':  
  808.       moveX = dims.width / 2;
  809.       moveY = dims.height / 2;
  810.       break;
  811.   }
  812.   
  813.   return new Effect.Parallel(
  814.     [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
  815.       new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
  816.       new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
  817.     ], Object.extend({            
  818.          beforeStartInternal: function(effect) { with(Element) {
  819.            [makePositioned, makeClipping].call(effect.effects[0].element) }},
  820.          afterFinishInternal: function(effect) { with(Element) {
  821.            [hide, undoClipping, undoPositioned].call(effect.effects[0].element);
  822.            setStyle(effect.effects[0].element, oldStyle); }}
  823.        }, options)
  824.   );
  825. }
  826. Effect.Pulsate = function(element) {
  827.   element = $(element);
  828.   var options    = arguments[1] || {};
  829.   var oldOpacity = Element.getInlineOpacity(element);
  830.   var transition = options.transition || Effect.Transitions.sinoidal;
  831.   var reverser   = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) };
  832.   reverser.bind(transition);
  833.   return new Effect.Opacity(element, 
  834.     Object.extend(Object.extend({  duration: 3.0, from: 0,
  835.       afterFinishInternal: function(effect) { Element.setStyle(effect.element, {opacity: oldOpacity}); }
  836.     }, options), {transition: reverser}));
  837. }
  838. Effect.Fold = function(element) {
  839.   element = $(element);
  840.   var oldStyle = {
  841.     top: element.style.top,
  842.     left: element.style.left,
  843.     width: element.style.width,
  844.     height: element.style.height };
  845.   Element.makeClipping(element);
  846.   return new Effect.Scale(element, 5, Object.extend({   
  847.     scaleContent: false,
  848.     scaleX: false,
  849.     afterFinishInternal: function(effect) {
  850.     new Effect.Scale(element, 1, { 
  851.       scaleContent: false, 
  852.       scaleY: false,
  853.       afterFinishInternal: function(effect) { with(Element) {
  854.         [hide, undoClipping].call(effect.element); 
  855.         setStyle(effect.element, oldStyle);
  856.       }} });
  857.   }}, arguments[1] || {}));
  858. }