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