web/wp-includes/js/scriptaculous/effects.js
changeset 194 32102edaa81b
parent 136 bde1974c263b
equal deleted inserted replaced
193:2f6f6f7551ca 194:32102edaa81b
     1 // script.aculo.us effects.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007
     1 // script.aculo.us effects.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
     2 
     2 
     3 // Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
     3 // Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
     4 // Contributors:
     4 // Contributors:
     5 //  Justin Palmer (http://encytemedia.com/)
     5 //  Justin Palmer (http://encytemedia.com/)
     6 //  Mark Pilgrim (http://diveintomark.org/)
     6 //  Mark Pilgrim (http://diveintomark.org/)
     7 //  Martin Bialasinki
     7 //  Martin Bialasinki
     8 // 
     8 //
     9 // script.aculo.us is freely distributable under the terms of an MIT-style license.
     9 // script.aculo.us is freely distributable under the terms of an MIT-style license.
    10 // For details, see the script.aculo.us web site: http://script.aculo.us/ 
    10 // For details, see the script.aculo.us web site: http://script.aculo.us/
    11 
    11 
    12 // converts rgb() and #xxx to #xxxxxx format,  
    12 // converts rgb() and #xxx to #xxxxxx format,
    13 // returns self (or first argument) if not convertable  
    13 // returns self (or first argument) if not convertable
    14 String.prototype.parseColor = function() {  
    14 String.prototype.parseColor = function() {
    15   var color = '#';
    15   var color = '#';
    16   if (this.slice(0,4) == 'rgb(') {  
    16   if (this.slice(0,4) == 'rgb(') {
    17     var cols = this.slice(4,this.length-1).split(',');  
    17     var cols = this.slice(4,this.length-1).split(',');
    18     var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);  
    18     var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
    19   } else {  
    19   } else {
    20     if (this.slice(0,1) == '#') {  
    20     if (this.slice(0,1) == '#') {
    21       if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();  
    21       if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
    22       if (this.length==7) color = this.toLowerCase();  
    22       if (this.length==7) color = this.toLowerCase();
    23     }  
    23     }
    24   }  
    24   }
    25   return (color.length==7 ? color : (arguments[0] || this));  
    25   return (color.length==7 ? color : (arguments[0] || this));
    26 };
    26 };
    27 
    27 
    28 /*--------------------------------------------------------------------------*/
    28 /*--------------------------------------------------------------------------*/
    29 
    29 
    30 Element.collectTextNodes = function(element) {  
    30 Element.collectTextNodes = function(element) {
    31   return $A($(element).childNodes).collect( function(node) {
    31   return $A($(element).childNodes).collect( function(node) {
    32     return (node.nodeType==3 ? node.nodeValue : 
    32     return (node.nodeType==3 ? node.nodeValue :
    33       (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
    33       (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
    34   }).flatten().join('');
    34   }).flatten().join('');
    35 };
    35 };
    36 
    36 
    37 Element.collectTextNodesIgnoreClass = function(element, className) {  
    37 Element.collectTextNodesIgnoreClass = function(element, className) {
    38   return $A($(element).childNodes).collect( function(node) {
    38   return $A($(element).childNodes).collect( function(node) {
    39     return (node.nodeType==3 ? node.nodeValue : 
    39     return (node.nodeType==3 ? node.nodeValue :
    40       ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? 
    40       ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
    41         Element.collectTextNodesIgnoreClass(node, className) : ''));
    41         Element.collectTextNodesIgnoreClass(node, className) : ''));
    42   }).flatten().join('');
    42   }).flatten().join('');
    43 };
    43 };
    44 
    44 
    45 Element.setContentZoom = function(element, percent) {
    45 Element.setContentZoom = function(element, percent) {
    46   element = $(element);  
    46   element = $(element);
    47   element.setStyle({fontSize: (percent/100) + 'em'});   
    47   element.setStyle({fontSize: (percent/100) + 'em'});
    48   if (Prototype.Browser.WebKit) window.scrollBy(0,0);
    48   if (Prototype.Browser.WebKit) window.scrollBy(0,0);
    49   return element;
    49   return element;
    50 };
    50 };
    51 
    51 
    52 Element.getInlineOpacity = function(element){
    52 Element.getInlineOpacity = function(element){
    70     message: 'The specified DOM element does not exist, but is required for this effect to operate'
    70     message: 'The specified DOM element does not exist, but is required for this effect to operate'
    71   },
    71   },
    72   Transitions: {
    72   Transitions: {
    73     linear: Prototype.K,
    73     linear: Prototype.K,
    74     sinoidal: function(pos) {
    74     sinoidal: function(pos) {
    75       return (-Math.cos(pos*Math.PI)/2) + 0.5;
    75       return (-Math.cos(pos*Math.PI)/2) + .5;
    76     },
    76     },
    77     reverse: function(pos) {
    77     reverse: function(pos) {
    78       return 1-pos;
    78       return 1-pos;
    79     },
    79     },
    80     flicker: function(pos) {
    80     flicker: function(pos) {
    81       var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
    81       var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4;
    82       return pos > 1 ? 1 : pos;
    82       return pos > 1 ? 1 : pos;
    83     },
    83     },
    84     wobble: function(pos) {
    84     wobble: function(pos) {
    85       return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
    85       return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5;
    86     },
    86     },
    87     pulse: function(pos, pulses) { 
    87     pulse: function(pos, pulses) {
    88       pulses = pulses || 5; 
    88       return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5;
    89       return (
    89     },
    90         ((pos % (1/pulses)) * pulses).round() == 0 ? 
    90     spring: function(pos) {
    91               ((pos * pulses * 2) - (pos * pulses * 2).floor()) : 
    91       return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
    92           1 - ((pos * pulses * 2) - (pos * pulses * 2).floor())
       
    93         );
       
    94     },
       
    95     spring: function(pos) { 
       
    96       return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6)); 
       
    97     },
    92     },
    98     none: function(pos) {
    93     none: function(pos) {
    99       return 0;
    94       return 0;
   100     },
    95     },
   101     full: function(pos) {
    96     full: function(pos) {
   112     queue:      'parallel'
   107     queue:      'parallel'
   113   },
   108   },
   114   tagifyText: function(element) {
   109   tagifyText: function(element) {
   115     var tagifyStyle = 'position:relative';
   110     var tagifyStyle = 'position:relative';
   116     if (Prototype.Browser.IE) tagifyStyle += ';zoom:1';
   111     if (Prototype.Browser.IE) tagifyStyle += ';zoom:1';
   117     
   112 
   118     element = $(element);
   113     element = $(element);
   119     $A(element.childNodes).each( function(child) {
   114     $A(element.childNodes).each( function(child) {
   120       if (child.nodeType==3) {
   115       if (child.nodeType==3) {
   121         child.nodeValue.toArray().each( function(character) {
   116         child.nodeValue.toArray().each( function(character) {
   122           element.insertBefore(
   117           element.insertBefore(
   123             new Element('span', {style: tagifyStyle}).update(
   118             new Element('span', {style: tagifyStyle}).update(
   124               character == ' ' ? String.fromCharCode(160) : character), 
   119               character == ' ' ? String.fromCharCode(160) : character),
   125               child);
   120               child);
   126         });
   121         });
   127         Element.remove(child);
   122         Element.remove(child);
   128       }
   123       }
   129     });
   124     });
   130   },
   125   },
   131   multiple: function(element, effect) {
   126   multiple: function(element, effect) {
   132     var elements;
   127     var elements;
   133     if (((typeof element == 'object') || 
   128     if (((typeof element == 'object') ||
   134         Object.isFunction(element)) && 
   129         Object.isFunction(element)) &&
   135        (element.length))
   130        (element.length))
   136       elements = element;
   131       elements = element;
   137     else
   132     else
   138       elements = $(element).childNodes;
   133       elements = $(element).childNodes;
   139       
   134 
   140     var options = Object.extend({
   135     var options = Object.extend({
   141       speed: 0.1,
   136       speed: 0.1,
   142       delay: 0.0
   137       delay: 0.0
   143     }, arguments[2] || { });
   138     }, arguments[2] || { });
   144     var masterDelay = options.delay;
   139     var masterDelay = options.delay;
   150   PAIRS: {
   145   PAIRS: {
   151     'slide':  ['SlideDown','SlideUp'],
   146     'slide':  ['SlideDown','SlideUp'],
   152     'blind':  ['BlindDown','BlindUp'],
   147     'blind':  ['BlindDown','BlindUp'],
   153     'appear': ['Appear','Fade']
   148     'appear': ['Appear','Fade']
   154   },
   149   },
   155   toggle: function(element, effect) {
   150   toggle: function(element, effect, options) {
   156     element = $(element);
   151     element = $(element);
   157     effect = (effect || 'appear').toLowerCase();
   152     effect  = (effect || 'appear').toLowerCase();
   158     var options = Object.extend({
   153     
       
   154     return Effect[ Effect.PAIRS[ effect ][ element.visible() ? 1 : 0 ] ](element, Object.extend({
   159       queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
   155       queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
   160     }, arguments[2] || { });
   156     }, options || {}));
   161     Effect[element.visible() ? 
       
   162       Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
       
   163   }
   157   }
   164 };
   158 };
   165 
   159 
   166 Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;
   160 Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;
   167 
   161 
   168 /* ------------- core effects ------------- */
   162 /* ------------- core effects ------------- */
   169 
   163 
   170 Effect.ScopedQueue = Class.create(Enumerable, {
   164 Effect.ScopedQueue = Class.create(Enumerable, {
   171   initialize: function() {
   165   initialize: function() {
   172     this.effects  = [];
   166     this.effects  = [];
   173     this.interval = null;    
   167     this.interval = null;
   174   },
   168   },
   175   _each: function(iterator) {
   169   _each: function(iterator) {
   176     this.effects._each(iterator);
   170     this.effects._each(iterator);
   177   },
   171   },
   178   add: function(effect) {
   172   add: function(effect) {
   179     var timestamp = new Date().getTime();
   173     var timestamp = new Date().getTime();
   180     
   174 
   181     var position = Object.isString(effect.options.queue) ? 
   175     var position = Object.isString(effect.options.queue) ?
   182       effect.options.queue : effect.options.queue.position;
   176       effect.options.queue : effect.options.queue.position;
   183     
   177 
   184     switch(position) {
   178     switch(position) {
   185       case 'front':
   179       case 'front':
   186         // move unstarted effects after this effect  
   180         // move unstarted effects after this effect
   187         this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
   181         this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
   188             e.startOn  += effect.finishOn;
   182             e.startOn  += effect.finishOn;
   189             e.finishOn += effect.finishOn;
   183             e.finishOn += effect.finishOn;
   190           });
   184           });
   191         break;
   185         break;
   195       case 'end':
   189       case 'end':
   196         // start effect after last queued effect has finished
   190         // start effect after last queued effect has finished
   197         timestamp = this.effects.pluck('finishOn').max() || timestamp;
   191         timestamp = this.effects.pluck('finishOn').max() || timestamp;
   198         break;
   192         break;
   199     }
   193     }
   200     
   194 
   201     effect.startOn  += timestamp;
   195     effect.startOn  += timestamp;
   202     effect.finishOn += timestamp;
   196     effect.finishOn += timestamp;
   203 
   197 
   204     if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
   198     if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
   205       this.effects.push(effect);
   199       this.effects.push(effect);
   206     
   200 
   207     if (!this.interval)
   201     if (!this.interval)
   208       this.interval = setInterval(this.loop.bind(this), 15);
   202       this.interval = setInterval(this.loop.bind(this), 15);
   209   },
   203   },
   210   remove: function(effect) {
   204   remove: function(effect) {
   211     this.effects = this.effects.reject(function(e) { return e==effect });
   205     this.effects = this.effects.reject(function(e) { return e==effect });
   214       this.interval = null;
   208       this.interval = null;
   215     }
   209     }
   216   },
   210   },
   217   loop: function() {
   211   loop: function() {
   218     var timePos = new Date().getTime();
   212     var timePos = new Date().getTime();
   219     for(var i=0, len=this.effects.length;i<len;i++) 
   213     for(var i=0, len=this.effects.length;i<len;i++)
   220       this.effects[i] && this.effects[i].loop(timePos);
   214       this.effects[i] && this.effects[i].loop(timePos);
   221   }
   215   }
   222 });
   216 });
   223 
   217 
   224 Effect.Queues = {
   218 Effect.Queues = {
   225   instances: $H(),
   219   instances: $H(),
   226   get: function(queueName) {
   220   get: function(queueName) {
   227     if (!Object.isString(queueName)) return queueName;
   221     if (!Object.isString(queueName)) return queueName;
   228     
   222 
   229     return this.instances.get(queueName) ||
   223     return this.instances.get(queueName) ||
   230       this.instances.set(queueName, new Effect.ScopedQueue());
   224       this.instances.set(queueName, new Effect.ScopedQueue());
   231   }
   225   }
   232 };
   226 };
   233 Effect.Queue = Effect.Queues.get('global');
   227 Effect.Queue = Effect.Queues.get('global');
   234 
   228 
   235 Effect.Base = Class.create({
   229 Effect.Base = Class.create({
   236   position: null,
   230   position: null,
   237   start: function(options) {
   231   start: function(options) {
   238     function codeForEvent(options,eventName){
       
   239       return (
       
   240         (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
       
   241         (options[eventName] ? 'this.options.'+eventName+'(this);' : '')
       
   242       );
       
   243     }
       
   244     if (options && options.transition === false) options.transition = Effect.Transitions.linear;
   232     if (options && options.transition === false) options.transition = Effect.Transitions.linear;
   245     this.options      = Object.extend(Object.extend({ },Effect.DefaultOptions), options || { });
   233     this.options      = Object.extend(Object.extend({ },Effect.DefaultOptions), options || { });
   246     this.currentFrame = 0;
   234     this.currentFrame = 0;
   247     this.state        = 'idle';
   235     this.state        = 'idle';
   248     this.startOn      = this.options.delay*1000;
   236     this.startOn      = this.options.delay*1000;
   249     this.finishOn     = this.startOn+(this.options.duration*1000);
   237     this.finishOn     = this.startOn+(this.options.duration*1000);
   250     this.fromToDelta  = this.options.to-this.options.from;
   238     this.fromToDelta  = this.options.to-this.options.from;
   251     this.totalTime    = this.finishOn-this.startOn;
   239     this.totalTime    = this.finishOn-this.startOn;
   252     this.totalFrames  = this.options.fps*this.options.duration;
   240     this.totalFrames  = this.options.fps*this.options.duration;
   253     
   241 
   254     eval('this.render = function(pos){ '+
   242     this.render = (function() {
   255       'if (this.state=="idle"){this.state="running";'+
   243       function dispatch(effect, eventName) {
   256       codeForEvent(this.options,'beforeSetup')+
   244         if (effect.options[eventName + 'Internal'])
   257       (this.setup ? 'this.setup();':'')+ 
   245           effect.options[eventName + 'Internal'](effect);
   258       codeForEvent(this.options,'afterSetup')+
   246         if (effect.options[eventName])
   259       '};if (this.state=="running"){'+
   247           effect.options[eventName](effect);
   260       'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';'+
   248       }
   261       'this.position=pos;'+
   249 
   262       codeForEvent(this.options,'beforeUpdate')+
   250       return function(pos) {
   263       (this.update ? 'this.update(pos);':'')+
   251         if (this.state === "idle") {
   264       codeForEvent(this.options,'afterUpdate')+
   252           this.state = "running";
   265       '}}');
   253           dispatch(this, 'beforeSetup');
   266     
   254           if (this.setup) this.setup();
       
   255           dispatch(this, 'afterSetup');
       
   256         }
       
   257         if (this.state === "running") {
       
   258           pos = (this.options.transition(pos) * this.fromToDelta) + this.options.from;
       
   259           this.position = pos;
       
   260           dispatch(this, 'beforeUpdate');
       
   261           if (this.update) this.update(pos);
       
   262           dispatch(this, 'afterUpdate');
       
   263         }
       
   264       };
       
   265     })();
       
   266 
   267     this.event('beforeStart');
   267     this.event('beforeStart');
   268     if (!this.options.sync)
   268     if (!this.options.sync)
   269       Effect.Queues.get(Object.isString(this.options.queue) ? 
   269       Effect.Queues.get(Object.isString(this.options.queue) ?
   270         'global' : this.options.queue.scope).add(this);
   270         'global' : this.options.queue.scope).add(this);
   271   },
   271   },
   272   loop: function(timePos) {
   272   loop: function(timePos) {
   273     if (timePos >= this.startOn) {
   273     if (timePos >= this.startOn) {
   274       if (timePos >= this.finishOn) {
   274       if (timePos >= this.finishOn) {
   275         this.render(1.0);
   275         this.render(1.0);
   276         this.cancel();
   276         this.cancel();
   277         this.event('beforeFinish');
   277         this.event('beforeFinish');
   278         if (this.finish) this.finish(); 
   278         if (this.finish) this.finish();
   279         this.event('afterFinish');
   279         this.event('afterFinish');
   280         return;  
   280         return;
   281       }
   281       }
   282       var pos   = (timePos - this.startOn) / this.totalTime,
   282       var pos   = (timePos - this.startOn) / this.totalTime,
   283           frame = (pos * this.totalFrames).round();
   283           frame = (pos * this.totalFrames).round();
   284       if (frame > this.currentFrame) {
   284       if (frame > this.currentFrame) {
   285         this.render(pos);
   285         this.render(pos);
   287       }
   287       }
   288     }
   288     }
   289   },
   289   },
   290   cancel: function() {
   290   cancel: function() {
   291     if (!this.options.sync)
   291     if (!this.options.sync)
   292       Effect.Queues.get(Object.isString(this.options.queue) ? 
   292       Effect.Queues.get(Object.isString(this.options.queue) ?
   293         'global' : this.options.queue.scope).remove(this);
   293         'global' : this.options.queue.scope).remove(this);
   294     this.state = 'finished';
   294     this.state = 'finished';
   295   },
   295   },
   296   event: function(eventName) {
   296   event: function(eventName) {
   297     if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
   297     if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
   325 });
   325 });
   326 
   326 
   327 Effect.Tween = Class.create(Effect.Base, {
   327 Effect.Tween = Class.create(Effect.Base, {
   328   initialize: function(object, from, to) {
   328   initialize: function(object, from, to) {
   329     object = Object.isString(object) ? $(object) : object;
   329     object = Object.isString(object) ? $(object) : object;
   330     var args = $A(arguments), method = args.last(), 
   330     var args = $A(arguments), method = args.last(),
   331       options = args.length == 5 ? args[3] : null;
   331       options = args.length == 5 ? args[3] : null;
   332     this.method = Object.isFunction(method) ? method.bind(object) :
   332     this.method = Object.isFunction(method) ? method.bind(object) :
   333       Object.isFunction(object[method]) ? object[method].bind(object) : 
   333       Object.isFunction(object[method]) ? object[method].bind(object) :
   334       function(value) { object[method] = value };
   334       function(value) { object[method] = value };
   335     this.start(Object.extend({ from: from, to: to }, options || { }));
   335     this.start(Object.extend({ from: from, to: to }, options || { }));
   336   },
   336   },
   337   update: function(position) {
   337   update: function(position) {
   338     this.method(position);
   338     this.method(position);
   392   }
   392   }
   393 });
   393 });
   394 
   394 
   395 // for backwards compatibility
   395 // for backwards compatibility
   396 Effect.MoveBy = function(element, toTop, toLeft) {
   396 Effect.MoveBy = function(element, toTop, toLeft) {
   397   return new Effect.Move(element, 
   397   return new Effect.Move(element,
   398     Object.extend({ x: toLeft, y: toTop }, arguments[3] || { }));
   398     Object.extend({ x: toLeft, y: toTop }, arguments[3] || { }));
   399 };
   399 };
   400 
   400 
   401 Effect.Scale = Class.create(Effect.Base, {
   401 Effect.Scale = Class.create(Effect.Base, {
   402   initialize: function(element, percent) {
   402   initialize: function(element, percent) {
   414     this.start(options);
   414     this.start(options);
   415   },
   415   },
   416   setup: function() {
   416   setup: function() {
   417     this.restoreAfterFinish = this.options.restoreAfterFinish || false;
   417     this.restoreAfterFinish = this.options.restoreAfterFinish || false;
   418     this.elementPositioning = this.element.getStyle('position');
   418     this.elementPositioning = this.element.getStyle('position');
   419     
   419 
   420     this.originalStyle = { };
   420     this.originalStyle = { };
   421     ['top','left','width','height','fontSize'].each( function(k) {
   421     ['top','left','width','height','fontSize'].each( function(k) {
   422       this.originalStyle[k] = this.element.style[k];
   422       this.originalStyle[k] = this.element.style[k];
   423     }.bind(this));
   423     }.bind(this));
   424       
   424 
   425     this.originalTop  = this.element.offsetTop;
   425     this.originalTop  = this.element.offsetTop;
   426     this.originalLeft = this.element.offsetLeft;
   426     this.originalLeft = this.element.offsetLeft;
   427     
   427 
   428     var fontSize = this.element.getStyle('font-size') || '100%';
   428     var fontSize = this.element.getStyle('font-size') || '100%';
   429     ['em','px','%','pt'].each( function(fontSizeType) {
   429     ['em','px','%','pt'].each( function(fontSizeType) {
   430       if (fontSize.indexOf(fontSizeType)>0) {
   430       if (fontSize.indexOf(fontSizeType)>0) {
   431         this.fontSize     = parseFloat(fontSize);
   431         this.fontSize     = parseFloat(fontSize);
   432         this.fontSizeType = fontSizeType;
   432         this.fontSizeType = fontSizeType;
   433       }
   433       }
   434     }.bind(this));
   434     }.bind(this));
   435     
   435 
   436     this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
   436     this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
   437     
   437 
   438     this.dims = null;
   438     this.dims = null;
   439     if (this.options.scaleMode=='box')
   439     if (this.options.scaleMode=='box')
   440       this.dims = [this.element.offsetHeight, this.element.offsetWidth];
   440       this.dims = [this.element.offsetHeight, this.element.offsetWidth];
   441     if (/^content/.test(this.options.scaleMode))
   441     if (/^content/.test(this.options.scaleMode))
   442       this.dims = [this.element.scrollHeight, this.element.scrollWidth];
   442       this.dims = [this.element.scrollHeight, this.element.scrollWidth];
   507   }
   507   }
   508 });
   508 });
   509 
   509 
   510 Effect.ScrollTo = function(element) {
   510 Effect.ScrollTo = function(element) {
   511   var options = arguments[1] || { },
   511   var options = arguments[1] || { },
   512     scrollOffsets = document.viewport.getScrollOffsets(),
   512   scrollOffsets = document.viewport.getScrollOffsets(),
   513     elementOffsets = $(element).cumulativeOffset(),
   513   elementOffsets = $(element).cumulativeOffset();
   514     max = (window.height || document.body.scrollHeight) - document.viewport.getHeight();  
       
   515 
   514 
   516   if (options.offset) elementOffsets[1] += options.offset;
   515   if (options.offset) elementOffsets[1] += options.offset;
   517 
   516 
   518   return new Effect.Tween(null,
   517   return new Effect.Tween(null,
   519     scrollOffsets.top,
   518     scrollOffsets.top,
   520     elementOffsets[1] > max ? max : elementOffsets[1],
   519     elementOffsets[1],
   521     options,
   520     options,
   522     function(p){ scrollTo(scrollOffsets.left, p.round()) }
   521     function(p){ scrollTo(scrollOffsets.left, p.round()); }
   523   );
   522   );
   524 };
   523 };
   525 
   524 
   526 /* ------------- combination effects ------------- */
   525 /* ------------- combination effects ------------- */
   527 
   526 
   529   element = $(element);
   528   element = $(element);
   530   var oldOpacity = element.getInlineOpacity();
   529   var oldOpacity = element.getInlineOpacity();
   531   var options = Object.extend({
   530   var options = Object.extend({
   532     from: element.getOpacity() || 1.0,
   531     from: element.getOpacity() || 1.0,
   533     to:   0.0,
   532     to:   0.0,
   534     afterFinishInternal: function(effect) { 
   533     afterFinishInternal: function(effect) {
   535       if (effect.options.to!=0) return;
   534       if (effect.options.to!=0) return;
   536       effect.element.hide().setStyle({opacity: oldOpacity}); 
   535       effect.element.hide().setStyle({opacity: oldOpacity});
   537     }
   536     }
   538   }, arguments[1] || { });
   537   }, arguments[1] || { });
   539   return new Effect.Opacity(element,options);
   538   return new Effect.Opacity(element,options);
   540 };
   539 };
   541 
   540 
   547   // force Safari to render floated elements properly
   546   // force Safari to render floated elements properly
   548   afterFinishInternal: function(effect) {
   547   afterFinishInternal: function(effect) {
   549     effect.element.forceRerendering();
   548     effect.element.forceRerendering();
   550   },
   549   },
   551   beforeSetup: function(effect) {
   550   beforeSetup: function(effect) {
   552     effect.element.setOpacity(effect.options.from).show(); 
   551     effect.element.setOpacity(effect.options.from).show();
   553   }}, arguments[1] || { });
   552   }}, arguments[1] || { });
   554   return new Effect.Opacity(element,options);
   553   return new Effect.Opacity(element,options);
   555 };
   554 };
   556 
   555 
   557 Effect.Puff = function(element) {
   556 Effect.Puff = function(element) {
   558   element = $(element);
   557   element = $(element);
   559   var oldStyle = { 
   558   var oldStyle = {
   560     opacity: element.getInlineOpacity(), 
   559     opacity: element.getInlineOpacity(),
   561     position: element.getStyle('position'),
   560     position: element.getStyle('position'),
   562     top:  element.style.top,
   561     top:  element.style.top,
   563     left: element.style.left,
   562     left: element.style.left,
   564     width: element.style.width,
   563     width: element.style.width,
   565     height: element.style.height
   564     height: element.style.height
   566   };
   565   };
   567   return new Effect.Parallel(
   566   return new Effect.Parallel(
   568    [ new Effect.Scale(element, 200, 
   567    [ new Effect.Scale(element, 200,
   569       { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), 
   568       { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
   570      new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], 
   569      new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
   571      Object.extend({ duration: 1.0, 
   570      Object.extend({ duration: 1.0,
   572       beforeSetupInternal: function(effect) {
   571       beforeSetupInternal: function(effect) {
   573         Position.absolutize(effect.effects[0].element)
   572         Position.absolutize(effect.effects[0].element);
   574       },
   573       },
   575       afterFinishInternal: function(effect) {
   574       afterFinishInternal: function(effect) {
   576          effect.effects[0].element.hide().setStyle(oldStyle); }
   575          effect.effects[0].element.hide().setStyle(oldStyle); }
   577      }, arguments[1] || { })
   576      }, arguments[1] || { })
   578    );
   577    );
   580 
   579 
   581 Effect.BlindUp = function(element) {
   580 Effect.BlindUp = function(element) {
   582   element = $(element);
   581   element = $(element);
   583   element.makeClipping();
   582   element.makeClipping();
   584   return new Effect.Scale(element, 0,
   583   return new Effect.Scale(element, 0,
   585     Object.extend({ scaleContent: false, 
   584     Object.extend({ scaleContent: false,
   586       scaleX: false, 
   585       scaleX: false,
   587       restoreAfterFinish: true,
   586       restoreAfterFinish: true,
   588       afterFinishInternal: function(effect) {
   587       afterFinishInternal: function(effect) {
   589         effect.element.hide().undoClipping();
   588         effect.element.hide().undoClipping();
   590       } 
   589       }
   591     }, arguments[1] || { })
   590     }, arguments[1] || { })
   592   );
   591   );
   593 };
   592 };
   594 
   593 
   595 Effect.BlindDown = function(element) {
   594 Effect.BlindDown = function(element) {
   596   element = $(element);
   595   element = $(element);
   597   var elementDimensions = element.getDimensions();
   596   var elementDimensions = element.getDimensions();
   598   return new Effect.Scale(element, 100, Object.extend({ 
   597   return new Effect.Scale(element, 100, Object.extend({
   599     scaleContent: false, 
   598     scaleContent: false,
   600     scaleX: false,
   599     scaleX: false,
   601     scaleFrom: 0,
   600     scaleFrom: 0,
   602     scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
   601     scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
   603     restoreAfterFinish: true,
   602     restoreAfterFinish: true,
   604     afterSetup: function(effect) {
   603     afterSetup: function(effect) {
   605       effect.element.makeClipping().setStyle({height: '0px'}).show(); 
   604       effect.element.makeClipping().setStyle({height: '0px'}).show();
   606     },  
   605     },
   607     afterFinishInternal: function(effect) {
   606     afterFinishInternal: function(effect) {
   608       effect.element.undoClipping();
   607       effect.element.undoClipping();
   609     }
   608     }
   610   }, arguments[1] || { }));
   609   }, arguments[1] || { }));
   611 };
   610 };
   616   return new Effect.Appear(element, Object.extend({
   615   return new Effect.Appear(element, Object.extend({
   617     duration: 0.4,
   616     duration: 0.4,
   618     from: 0,
   617     from: 0,
   619     transition: Effect.Transitions.flicker,
   618     transition: Effect.Transitions.flicker,
   620     afterFinishInternal: function(effect) {
   619     afterFinishInternal: function(effect) {
   621       new Effect.Scale(effect.element, 1, { 
   620       new Effect.Scale(effect.element, 1, {
   622         duration: 0.3, scaleFromCenter: true,
   621         duration: 0.3, scaleFromCenter: true,
   623         scaleX: false, scaleContent: false, restoreAfterFinish: true,
   622         scaleX: false, scaleContent: false, restoreAfterFinish: true,
   624         beforeSetup: function(effect) { 
   623         beforeSetup: function(effect) {
   625           effect.element.makePositioned().makeClipping();
   624           effect.element.makePositioned().makeClipping();
   626         },
   625         },
   627         afterFinishInternal: function(effect) {
   626         afterFinishInternal: function(effect) {
   628           effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
   627           effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
   629         }
   628         }
   630       })
   629       });
   631     }
   630     }
   632   }, arguments[1] || { }));
   631   }, arguments[1] || { }));
   633 };
   632 };
   634 
   633 
   635 Effect.DropOut = function(element) {
   634 Effect.DropOut = function(element) {
   637   var oldStyle = {
   636   var oldStyle = {
   638     top: element.getStyle('top'),
   637     top: element.getStyle('top'),
   639     left: element.getStyle('left'),
   638     left: element.getStyle('left'),
   640     opacity: element.getInlineOpacity() };
   639     opacity: element.getInlineOpacity() };
   641   return new Effect.Parallel(
   640   return new Effect.Parallel(
   642     [ new Effect.Move(element, {x: 0, y: 100, sync: true }), 
   641     [ new Effect.Move(element, {x: 0, y: 100, sync: true }),
   643       new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
   642       new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
   644     Object.extend(
   643     Object.extend(
   645       { duration: 0.5,
   644       { duration: 0.5,
   646         beforeSetup: function(effect) {
   645         beforeSetup: function(effect) {
   647           effect.effects[0].element.makePositioned(); 
   646           effect.effects[0].element.makePositioned();
   648         },
   647         },
   649         afterFinishInternal: function(effect) {
   648         afterFinishInternal: function(effect) {
   650           effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
   649           effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
   651         } 
   650         }
   652       }, arguments[1] || { }));
   651       }, arguments[1] || { }));
   653 };
   652 };
   654 
   653 
   655 Effect.Shake = function(element) {
   654 Effect.Shake = function(element) {
   656   element = $(element);
   655   element = $(element);
   674     new Effect.Move(effect.element,
   673     new Effect.Move(effect.element,
   675       { x:  distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
   674       { x:  distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
   676     new Effect.Move(effect.element,
   675     new Effect.Move(effect.element,
   677       { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {
   676       { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {
   678         effect.element.undoPositioned().setStyle(oldStyle);
   677         effect.element.undoPositioned().setStyle(oldStyle);
   679   }}) }}) }}) }}) }}) }});
   678   }}); }}); }}); }}); }}); }});
   680 };
   679 };
   681 
   680 
   682 Effect.SlideDown = function(element) {
   681 Effect.SlideDown = function(element) {
   683   element = $(element).cleanWhitespace();
   682   element = $(element).cleanWhitespace();
   684   // SlideDown need to have the content of the element wrapped in a container element with fixed height!
   683   // SlideDown need to have the content of the element wrapped in a container element with fixed height!
   685   var oldInnerBottom = element.down().getStyle('bottom');
   684   var oldInnerBottom = element.down().getStyle('bottom');
   686   var elementDimensions = element.getDimensions();
   685   var elementDimensions = element.getDimensions();
   687   return new Effect.Scale(element, 100, Object.extend({ 
   686   return new Effect.Scale(element, 100, Object.extend({
   688     scaleContent: false, 
   687     scaleContent: false,
   689     scaleX: false, 
   688     scaleX: false,
   690     scaleFrom: window.opera ? 0 : 1,
   689     scaleFrom: window.opera ? 0 : 1,
   691     scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
   690     scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
   692     restoreAfterFinish: true,
   691     restoreAfterFinish: true,
   693     afterSetup: function(effect) {
   692     afterSetup: function(effect) {
   694       effect.element.makePositioned();
   693       effect.element.makePositioned();
   695       effect.element.down().makePositioned();
   694       effect.element.down().makePositioned();
   696       if (window.opera) effect.element.setStyle({top: ''});
   695       if (window.opera) effect.element.setStyle({top: ''});
   697       effect.element.makeClipping().setStyle({height: '0px'}).show(); 
   696       effect.element.makeClipping().setStyle({height: '0px'}).show();
   698     },
   697     },
   699     afterUpdateInternal: function(effect) {
   698     afterUpdateInternal: function(effect) {
   700       effect.element.down().setStyle({bottom:
   699       effect.element.down().setStyle({bottom:
   701         (effect.dims[0] - effect.element.clientHeight) + 'px' }); 
   700         (effect.dims[0] - effect.element.clientHeight) + 'px' });
   702     },
   701     },
   703     afterFinishInternal: function(effect) {
   702     afterFinishInternal: function(effect) {
   704       effect.element.undoClipping().undoPositioned();
   703       effect.element.undoClipping().undoPositioned();
   705       effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
   704       effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
   706     }, arguments[1] || { })
   705     }, arguments[1] || { })
   710 Effect.SlideUp = function(element) {
   709 Effect.SlideUp = function(element) {
   711   element = $(element).cleanWhitespace();
   710   element = $(element).cleanWhitespace();
   712   var oldInnerBottom = element.down().getStyle('bottom');
   711   var oldInnerBottom = element.down().getStyle('bottom');
   713   var elementDimensions = element.getDimensions();
   712   var elementDimensions = element.getDimensions();
   714   return new Effect.Scale(element, window.opera ? 0 : 1,
   713   return new Effect.Scale(element, window.opera ? 0 : 1,
   715    Object.extend({ scaleContent: false, 
   714    Object.extend({ scaleContent: false,
   716     scaleX: false, 
   715     scaleX: false,
   717     scaleMode: 'box',
   716     scaleMode: 'box',
   718     scaleFrom: 100,
   717     scaleFrom: 100,
   719     scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
   718     scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
   720     restoreAfterFinish: true,
   719     restoreAfterFinish: true,
   721     afterSetup: function(effect) {
   720     afterSetup: function(effect) {
   722       effect.element.makePositioned();
   721       effect.element.makePositioned();
   723       effect.element.down().makePositioned();
   722       effect.element.down().makePositioned();
   724       if (window.opera) effect.element.setStyle({top: ''});
   723       if (window.opera) effect.element.setStyle({top: ''});
   725       effect.element.makeClipping().show();
   724       effect.element.makeClipping().show();
   726     },  
   725     },
   727     afterUpdateInternal: function(effect) {
   726     afterUpdateInternal: function(effect) {
   728       effect.element.down().setStyle({bottom:
   727       effect.element.down().setStyle({bottom:
   729         (effect.dims[0] - effect.element.clientHeight) + 'px' });
   728         (effect.dims[0] - effect.element.clientHeight) + 'px' });
   730     },
   729     },
   731     afterFinishInternal: function(effect) {
   730     afterFinishInternal: function(effect) {
   734     }
   733     }
   735    }, arguments[1] || { })
   734    }, arguments[1] || { })
   736   );
   735   );
   737 };
   736 };
   738 
   737 
   739 // Bug in opera makes the TD containing this element expand for a instance after finish 
   738 // Bug in opera makes the TD containing this element expand for a instance after finish
   740 Effect.Squish = function(element) {
   739 Effect.Squish = function(element) {
   741   return new Effect.Scale(element, window.opera ? 1 : 0, { 
   740   return new Effect.Scale(element, window.opera ? 1 : 0, {
   742     restoreAfterFinish: true,
   741     restoreAfterFinish: true,
   743     beforeSetup: function(effect) {
   742     beforeSetup: function(effect) {
   744       effect.element.makeClipping(); 
   743       effect.element.makeClipping();
   745     },  
   744     },
   746     afterFinishInternal: function(effect) {
   745     afterFinishInternal: function(effect) {
   747       effect.element.hide().undoClipping(); 
   746       effect.element.hide().undoClipping();
   748     }
   747     }
   749   });
   748   });
   750 };
   749 };
   751 
   750 
   752 Effect.Grow = function(element) {
   751 Effect.Grow = function(element) {
   762     left: element.style.left,
   761     left: element.style.left,
   763     height: element.style.height,
   762     height: element.style.height,
   764     width: element.style.width,
   763     width: element.style.width,
   765     opacity: element.getInlineOpacity() };
   764     opacity: element.getInlineOpacity() };
   766 
   765 
   767   var dims = element.getDimensions();    
   766   var dims = element.getDimensions();
   768   var initialMoveX, initialMoveY;
   767   var initialMoveX, initialMoveY;
   769   var moveX, moveY;
   768   var moveX, moveY;
   770   
   769 
   771   switch (options.direction) {
   770   switch (options.direction) {
   772     case 'top-left':
   771     case 'top-left':
   773       initialMoveX = initialMoveY = moveX = moveY = 0; 
   772       initialMoveX = initialMoveY = moveX = moveY = 0;
   774       break;
   773       break;
   775     case 'top-right':
   774     case 'top-right':
   776       initialMoveX = dims.width;
   775       initialMoveX = dims.width;
   777       initialMoveY = moveY = 0;
   776       initialMoveY = moveY = 0;
   778       moveX = -dims.width;
   777       moveX = -dims.width;
   793       initialMoveY = dims.height / 2;
   792       initialMoveY = dims.height / 2;
   794       moveX = -dims.width / 2;
   793       moveX = -dims.width / 2;
   795       moveY = -dims.height / 2;
   794       moveY = -dims.height / 2;
   796       break;
   795       break;
   797   }
   796   }
   798   
   797 
   799   return new Effect.Move(element, {
   798   return new Effect.Move(element, {
   800     x: initialMoveX,
   799     x: initialMoveX,
   801     y: initialMoveY,
   800     y: initialMoveY,
   802     duration: 0.01, 
   801     duration: 0.01,
   803     beforeSetup: function(effect) {
   802     beforeSetup: function(effect) {
   804       effect.element.hide().makeClipping().makePositioned();
   803       effect.element.hide().makeClipping().makePositioned();
   805     },
   804     },
   806     afterFinishInternal: function(effect) {
   805     afterFinishInternal: function(effect) {
   807       new Effect.Parallel(
   806       new Effect.Parallel(
   808         [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
   807         [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
   809           new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
   808           new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
   810           new Effect.Scale(effect.element, 100, {
   809           new Effect.Scale(effect.element, 100, {
   811             scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, 
   810             scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
   812             sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
   811             sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
   813         ], Object.extend({
   812         ], Object.extend({
   814              beforeSetup: function(effect) {
   813              beforeSetup: function(effect) {
   815                effect.effects[0].element.setStyle({height: '0px'}).show(); 
   814                effect.effects[0].element.setStyle({height: '0px'}).show();
   816              },
   815              },
   817              afterFinishInternal: function(effect) {
   816              afterFinishInternal: function(effect) {
   818                effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); 
   817                effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
   819              }
   818              }
   820            }, options)
   819            }, options)
   821       )
   820       );
   822     }
   821     }
   823   });
   822   });
   824 };
   823 };
   825 
   824 
   826 Effect.Shrink = function(element) {
   825 Effect.Shrink = function(element) {
   838     width: element.style.width,
   837     width: element.style.width,
   839     opacity: element.getInlineOpacity() };
   838     opacity: element.getInlineOpacity() };
   840 
   839 
   841   var dims = element.getDimensions();
   840   var dims = element.getDimensions();
   842   var moveX, moveY;
   841   var moveX, moveY;
   843   
   842 
   844   switch (options.direction) {
   843   switch (options.direction) {
   845     case 'top-left':
   844     case 'top-left':
   846       moveX = moveY = 0;
   845       moveX = moveY = 0;
   847       break;
   846       break;
   848     case 'top-right':
   847     case 'top-right':
   855       break;
   854       break;
   856     case 'bottom-right':
   855     case 'bottom-right':
   857       moveX = dims.width;
   856       moveX = dims.width;
   858       moveY = dims.height;
   857       moveY = dims.height;
   859       break;
   858       break;
   860     case 'center':  
   859     case 'center':
   861       moveX = dims.width / 2;
   860       moveX = dims.width / 2;
   862       moveY = dims.height / 2;
   861       moveY = dims.height / 2;
   863       break;
   862       break;
   864   }
   863   }
   865   
   864 
   866   return new Effect.Parallel(
   865   return new Effect.Parallel(
   867     [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
   866     [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
   868       new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
   867       new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
   869       new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
   868       new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
   870     ], Object.extend({            
   869     ], Object.extend({
   871          beforeStartInternal: function(effect) {
   870          beforeStartInternal: function(effect) {
   872            effect.effects[0].element.makePositioned().makeClipping(); 
   871            effect.effects[0].element.makePositioned().makeClipping();
   873          },
   872          },
   874          afterFinishInternal: function(effect) {
   873          afterFinishInternal: function(effect) {
   875            effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
   874            effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
   876        }, options)
   875        }, options)
   877   );
   876   );
   878 };
   877 };
   879 
   878 
   880 Effect.Pulsate = function(element) {
   879 Effect.Pulsate = function(element) {
   881   element = $(element);
   880   element = $(element);
   882   var options    = arguments[1] || { };
   881   var options    = arguments[1] || { },
   883   var oldOpacity = element.getInlineOpacity();
   882     oldOpacity = element.getInlineOpacity(),
   884   var transition = options.transition || Effect.Transitions.sinoidal;
   883     transition = options.transition || Effect.Transitions.linear,
   885   var reverser   = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
   884     reverser   = function(pos){
   886   reverser.bind(transition);
   885       return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5);
   887   return new Effect.Opacity(element, 
   886     };
       
   887 
       
   888   return new Effect.Opacity(element,
   888     Object.extend(Object.extend({  duration: 2.0, from: 0,
   889     Object.extend(Object.extend({  duration: 2.0, from: 0,
   889       afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
   890       afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
   890     }, options), {transition: reverser}));
   891     }, options), {transition: reverser}));
   891 };
   892 };
   892 
   893 
   896     top: element.style.top,
   897     top: element.style.top,
   897     left: element.style.left,
   898     left: element.style.left,
   898     width: element.style.width,
   899     width: element.style.width,
   899     height: element.style.height };
   900     height: element.style.height };
   900   element.makeClipping();
   901   element.makeClipping();
   901   return new Effect.Scale(element, 5, Object.extend({   
   902   return new Effect.Scale(element, 5, Object.extend({
   902     scaleContent: false,
   903     scaleContent: false,
   903     scaleX: false,
   904     scaleX: false,
   904     afterFinishInternal: function(effect) {
   905     afterFinishInternal: function(effect) {
   905     new Effect.Scale(element, 1, { 
   906     new Effect.Scale(element, 1, {
   906       scaleContent: false, 
   907       scaleContent: false,
   907       scaleY: false,
   908       scaleY: false,
   908       afterFinishInternal: function(effect) {
   909       afterFinishInternal: function(effect) {
   909         effect.element.hide().undoClipping().setStyle(oldStyle);
   910         effect.element.hide().undoClipping().setStyle(oldStyle);
   910       } });
   911       } });
   911   }}, arguments[1] || { }));
   912   }}, arguments[1] || { }));
   916     this.element = $(element);
   917     this.element = $(element);
   917     if (!this.element) throw(Effect._elementDoesNotExistError);
   918     if (!this.element) throw(Effect._elementDoesNotExistError);
   918     var options = Object.extend({
   919     var options = Object.extend({
   919       style: { }
   920       style: { }
   920     }, arguments[1] || { });
   921     }, arguments[1] || { });
   921     
   922 
   922     if (!Object.isString(options.style)) this.style = $H(options.style);
   923     if (!Object.isString(options.style)) this.style = $H(options.style);
   923     else {
   924     else {
   924       if (options.style.include(':'))
   925       if (options.style.include(':'))
   925         this.style = options.style.parseStyle();
   926         this.style = options.style.parseStyle();
   926       else {
   927       else {
   934         options.afterFinishInternal = function(effect) {
   935         options.afterFinishInternal = function(effect) {
   935           effect.element.addClassName(effect.options.style);
   936           effect.element.addClassName(effect.options.style);
   936           effect.transforms.each(function(transform) {
   937           effect.transforms.each(function(transform) {
   937             effect.element.style[transform.style] = '';
   938             effect.element.style[transform.style] = '';
   938           });
   939           });
   939         }
   940         };
   940       }
   941       }
   941     }
   942     }
   942     this.start(options);
   943     this.start(options);
   943   },
   944   },
   944   
   945 
   945   setup: function(){
   946   setup: function(){
   946     function parseColor(color){
   947     function parseColor(color){
   947       if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
   948       if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
   948       color = color.parseColor();
   949       color = color.parseColor();
   949       return $R(0,2).map(function(i){
   950       return $R(0,2).map(function(i){
   950         return parseInt( color.slice(i*2+1,i*2+3), 16 ) 
   951         return parseInt( color.slice(i*2+1,i*2+3), 16 );
   951       });
   952       });
   952     }
   953     }
   953     this.transforms = this.style.map(function(pair){
   954     this.transforms = this.style.map(function(pair){
   954       var property = pair[0], value = pair[1], unit = null;
   955       var property = pair[0], value = pair[1], unit = null;
   955 
   956 
   965           value = parseFloat(components[1]);
   966           value = parseFloat(components[1]);
   966           unit = (components.length == 3) ? components[2] : null;
   967           unit = (components.length == 3) ? components[2] : null;
   967       }
   968       }
   968 
   969 
   969       var originalValue = this.element.getStyle(property);
   970       var originalValue = this.element.getStyle(property);
   970       return { 
   971       return {
   971         style: property.camelize(), 
   972         style: property.camelize(),
   972         originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), 
   973         originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
   973         targetValue: unit=='color' ? parseColor(value) : value,
   974         targetValue: unit=='color' ? parseColor(value) : value,
   974         unit: unit
   975         unit: unit
   975       };
   976       };
   976     }.bind(this)).reject(function(transform){
   977     }.bind(this)).reject(function(transform){
   977       return (
   978       return (
   978         (transform.originalValue == transform.targetValue) ||
   979         (transform.originalValue == transform.targetValue) ||
   979         (
   980         (
   980           transform.unit != 'color' &&
   981           transform.unit != 'color' &&
   981           (isNaN(transform.originalValue) || isNaN(transform.targetValue))
   982           (isNaN(transform.originalValue) || isNaN(transform.targetValue))
   982         )
   983         )
   983       )
   984       );
   984     });
   985     });
   985   },
   986   },
   986   update: function(position) {
   987   update: function(position) {
   987     var style = { }, transform, i = this.transforms.length;
   988     var style = { }, transform, i = this.transforms.length;
   988     while(i--)
   989     while(i--)
   989       style[(transform = this.transforms[i]).style] = 
   990       style[(transform = this.transforms[i]).style] =
   990         transform.unit=='color' ? '#'+
   991         transform.unit=='color' ? '#'+
   991           (Math.round(transform.originalValue[0]+
   992           (Math.round(transform.originalValue[0]+
   992             (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
   993             (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
   993           (Math.round(transform.originalValue[1]+
   994           (Math.round(transform.originalValue[1]+
   994             (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
   995             (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
   995           (Math.round(transform.originalValue[2]+
   996           (Math.round(transform.originalValue[2]+
   996             (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
   997             (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
   997         (transform.originalValue +
   998         (transform.originalValue +
   998           (transform.targetValue - transform.originalValue) * position).toFixed(3) + 
   999           (transform.targetValue - transform.originalValue) * position).toFixed(3) +
   999             (transform.unit === null ? '' : transform.unit);
  1000             (transform.unit === null ? '' : transform.unit);
  1000     this.element.setStyle(style, true);
  1001     this.element.setStyle(style, true);
  1001   }
  1002   }
  1002 });
  1003 });
  1003 
  1004 
  1030     );
  1031     );
  1031   }
  1032   }
  1032 });
  1033 });
  1033 
  1034 
  1034 Element.CSS_PROPERTIES = $w(
  1035 Element.CSS_PROPERTIES = $w(
  1035   'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + 
  1036   'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +
  1036   'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
  1037   'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
  1037   'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
  1038   'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
  1038   'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
  1039   'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
  1039   'fontSize fontWeight height left letterSpacing lineHeight ' +
  1040   'fontSize fontWeight height left letterSpacing lineHeight ' +
  1040   'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
  1041   'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
  1041   'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
  1042   'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
  1042   'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
  1043   'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
  1043   'right textIndent top width wordSpacing zIndex');
  1044   'right textIndent top width wordSpacing zIndex');
  1044   
  1045 
  1045 Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
  1046 Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
  1046 
  1047 
  1047 String.__parseStyleElement = document.createElement('div');
  1048 String.__parseStyleElement = document.createElement('div');
  1048 String.prototype.parseStyle = function(){
  1049 String.prototype.parseStyle = function(){
  1049   var style, styleRules = $H();
  1050   var style, styleRules = $H();
  1051     style = new Element('div',{style:this}).style;
  1052     style = new Element('div',{style:this}).style;
  1052   else {
  1053   else {
  1053     String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>';
  1054     String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>';
  1054     style = String.__parseStyleElement.childNodes[0].style;
  1055     style = String.__parseStyleElement.childNodes[0].style;
  1055   }
  1056   }
  1056   
  1057 
  1057   Element.CSS_PROPERTIES.each(function(property){
  1058   Element.CSS_PROPERTIES.each(function(property){
  1058     if (style[property]) styleRules.set(property, style[property]); 
  1059     if (style[property]) styleRules.set(property, style[property]);
  1059   });
  1060   });
  1060   
  1061 
  1061   if (Prototype.Browser.IE && this.include('opacity'))
  1062   if (Prototype.Browser.IE && this.include('opacity'))
  1062     styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]);
  1063     styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]);
  1063 
  1064 
  1064   return styleRules;
  1065   return styleRules;
  1065 };
  1066 };
  1074   };
  1075   };
  1075 } else {
  1076 } else {
  1076   Element.getStyles = function(element) {
  1077   Element.getStyles = function(element) {
  1077     element = $(element);
  1078     element = $(element);
  1078     var css = element.currentStyle, styles;
  1079     var css = element.currentStyle, styles;
  1079     styles = Element.CSS_PROPERTIES.inject({ }, function(hash, property) {
  1080     styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) {
  1080       hash.set(property, css[property]);
  1081       results[property] = css[property];
  1081       return hash;
  1082       return results;
  1082     });
  1083     });
  1083     if (!styles.opacity) styles.set('opacity', element.getOpacity());
  1084     if (!styles.opacity) styles.opacity = element.getOpacity();
  1084     return styles;
  1085     return styles;
  1085   };
  1086   };
  1086 };
  1087 }
  1087 
  1088 
  1088 Effect.Methods = {
  1089 Effect.Methods = {
  1089   morph: function(element, style) {
  1090   morph: function(element, style) {
  1090     element = $(element);
  1091     element = $(element);
  1091     new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { }));
  1092     new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { }));
  1092     return element;
  1093     return element;
  1093   },
  1094   },
  1094   visualEffect: function(element, effect, options) {
  1095   visualEffect: function(element, effect, options) {
  1095     element = $(element)
  1096     element = $(element);
  1096     var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);
  1097     var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);
  1097     new Effect[klass](element, options);
  1098     new Effect[klass](element, options);
  1098     return element;
  1099     return element;
  1099   },
  1100   },
  1100   highlight: function(element, options) {
  1101   highlight: function(element, options) {
  1104   }
  1105   }
  1105 };
  1106 };
  1106 
  1107 
  1107 $w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+
  1108 $w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+
  1108   'pulsate shake puff squish switchOff dropOut').each(
  1109   'pulsate shake puff squish switchOff dropOut').each(
  1109   function(effect) { 
  1110   function(effect) {
  1110     Effect.Methods[effect] = function(element, options){
  1111     Effect.Methods[effect] = function(element, options){
  1111       element = $(element);
  1112       element = $(element);
  1112       Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);
  1113       Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);
  1113       return element;
  1114       return element;
  1114     }
  1115     };
  1115   }
  1116   }
  1116 );
  1117 );
  1117 
  1118 
  1118 $w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each( 
  1119 $w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(
  1119   function(f) { Effect.Methods[f] = Element[f]; }
  1120   function(f) { Effect.Methods[f] = Element[f]; }
  1120 );
  1121 );
  1121 
  1122 
  1122 Element.addMethods(Effect.Methods);
  1123 Element.addMethods(Effect.Methods);