1 // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
3 // Justin Palmer (http://encytemedia.com/)
4 // Mark Pilgrim (http://diveintomark.org/)
7 // See scriptaculous.js for full license.
9 /* ------------- element ext -------------- */
11 // converts rgb() and #xxx to #xxxxxx format,
12 // returns self (or first argument) if not convertable
13 String
.prototype.parseColor = function() {
15 if(this.slice(0,4) == 'rgb(') {
16 var cols
= this.slice(4,this.length
-1).split(',');
17 var i
=0; do { color
+= parseInt(cols
[i
]).toColorPart() } while (++i
<3);
19 if(this.slice(0,1) == '#') {
20 if(this.length
==4) for(var i
=1;i
<4;i
++) color
+= (this.charAt(i
) + this.charAt(i
)).toLowerCase();
21 if(this.length
==7) color
= this.toLowerCase();
24 return(color
.length
==7 ? color : (arguments
[0] || this));
27 Element
.collectTextNodes = function(element
) {
28 return $A($(element
).childNodes
).collect( function(node
) {
29 return (node
.nodeType
==3 ? node
.nodeValue :
30 (node
.hasChildNodes() ? Element
.collectTextNodes(node
) : ''));
31 }).flatten().join('');
34 Element
.collectTextNodesIgnoreClass = function(element
, className
) {
35 return $A($(element
).childNodes
).collect( function(node
) {
36 return (node
.nodeType
==3 ? node
.nodeValue :
37 ((node
.hasChildNodes() && !Element
.hasClassName(node
,className
)) ?
38 Element
.collectTextNodes(node
) : ''));
39 }).flatten().join('');
42 Element
.setStyle = function(element
, style
) {
44 for(k
in style
) element
.style
[k
.camelize()] = style
[k
];
47 Element
.setContentZoom = function(element
, percent
) {
48 Element
.setStyle(element
, {fontSize: (percent
/100) + 'em'});
49 if(navigator
.appVersion
.indexOf('AppleWebKit')>0) window
.scrollBy(0,0);
52 Element
.getOpacity = function(element
){
54 if (opacity
= Element
.getStyle(element
, 'opacity'))
55 return parseFloat(opacity
);
56 if (opacity
= (Element
.getStyle(element
, 'filter') || '').match(/alpha\(opacity=(.*)\)/))
57 if(opacity
[1]) return parseFloat(opacity
[1]) / 100;
61 Element
.setOpacity = function(element
, value
){
64 Element
.setStyle(element
, { opacity:
65 (/Gecko/.test(navigator
.userAgent
) && !/Konqueror|Safari|KHTML/.test(navigator
.userAgent
)) ?
67 if(/MSIE/.test(navigator
.userAgent
))
68 Element
.setStyle(element
, {filter: Element
.getStyle(element
,'filter').replace(/alpha\([^\)]*\)/gi,'')});
70 if(value
< 0.00001) value
= 0;
71 Element
.setStyle(element
, {opacity: value
});
72 if(/MSIE/.test(navigator
.userAgent
))
73 Element
.setStyle(element
,
74 { filter: Element
.getStyle(element
,'filter').replace(/alpha\([^\)]*\)/gi,'') +
75 'alpha(opacity='+value
*100+')' });
79 Element
.getInlineOpacity = function(element
){
80 return $(element
).style
.opacity
|| '';
83 Element
.childrenWithClassName = function(element
, className
) {
84 return $A($(element
).getElementsByTagName('*')).select(
85 function(c
) { return Element
.hasClassName(c
, className
) });
88 Array
.prototype.call = function() {
90 this.each(function(f
){ f
.apply(this, args
) });
93 /*--------------------------------------------------------------------------*/
96 tagifyText: function(element
) {
97 var tagifyStyle
= 'position:relative';
98 if(/MSIE/.test(navigator
.userAgent
)) tagifyStyle
+= ';zoom:1';
100 $A(element
.childNodes
).each( function(child
) {
101 if(child
.nodeType
==3) {
102 child
.nodeValue
.toArray().each( function(character
) {
103 element
.insertBefore(
104 Builder
.node('span',{style: tagifyStyle
},
105 character
== ' ' ? String
.fromCharCode(160) : character
),
108 Element
.remove(child
);
112 multiple: function(element
, effect
) {
114 if(((typeof element
== 'object') ||
115 (typeof element
== 'function')) &&
119 elements
= $(element
).childNodes
;
121 var options
= Object
.extend({
124 }, arguments
[2] || {});
125 var masterDelay
= options
.delay
;
127 $A(elements
).each( function(element
, index
) {
128 new effect(element
, Object
.extend(options
, { delay: index
* options
.speed
+ masterDelay
}));
132 'slide': ['SlideDown','SlideUp'],
133 'blind': ['BlindDown','BlindUp'],
134 'appear': ['Appear','Fade']
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') }
141 }, arguments
[2] || {});
142 Effect
[Element
.visible(element
) ?
143 Effect
.PAIRS
[effect
][1] : Effect
.PAIRS
[effect
][0]](element
, options
);
147 var Effect2
= Effect
; // deprecated
149 /* ------------- transitions ------------- */
151 Effect
.Transitions
= {}
153 Effect
.Transitions
.linear = function(pos
) {
156 Effect
.Transitions
.sinoidal = function(pos
) {
157 return (-Math
.cos(pos
*Math
.PI
)/2) + 0.5;
159 Effect
.Transitions
.reverse = function(pos
) {
162 Effect
.Transitions
.flicker = function(pos
) {
163 return ((-Math
.cos(pos
*Math
.PI
)/4) + 0.75) + Math
.random()/4;
165 Effect
.Transitions
.wobble = function(pos
) {
166 return (-Math
.cos(pos
*Math
.PI
*(9*pos
))/2) + 0.5;
168 Effect
.Transitions
.pulse = function(pos
) {
169 return (Math
.floor(pos
*10) % 2 == 0 ?
170 (pos
*10-Math
.floor(pos
*10)) : 1-(pos
*10-Math
.floor(pos
*10)));
172 Effect
.Transitions
.none = function(pos
) {
175 Effect
.Transitions
.full = function(pos
) {
179 /* ------------- core effects ------------- */
181 Effect
.ScopedQueue
= Class
.create();
182 Object
.extend(Object
.extend(Effect
.ScopedQueue
.prototype, Enumerable
), {
183 initialize: function() {
185 this.interval
= null;
187 _each: function(iterator
) {
188 this.effects
._each(iterator
);
190 add: function(effect
) {
191 var timestamp
= new Date().getTime();
193 var position
= (typeof effect
.options
.queue
== 'string') ?
194 effect
.options
.queue : effect
.options
.queue
.position
;
198 // move unstarted effects after this effect
199 this.effects
.findAll(function(e
){ return e
.state
=='idle' }).each( function(e
) {
200 e
.startOn
+= effect
.finishOn
;
201 e
.finishOn
+= effect
.finishOn
;
205 // start effect after last queued effect has finished
206 timestamp
= this.effects
.pluck('finishOn').max() || timestamp
;
210 effect
.startOn
+= timestamp
;
211 effect
.finishOn
+= timestamp
;
212 this.effects
.push(effect
);
214 this.interval
= setInterval(this.loop
.bind(this), 40);
216 remove: function(effect
) {
217 this.effects
= this.effects
.reject(function(e
) { return e
==effect
});
218 if(this.effects
.length
== 0) {
219 clearInterval(this.interval
);
220 this.interval
= null;
224 var timePos
= new Date().getTime();
225 this.effects
.invoke('loop', timePos
);
231 get: function(queueName
) {
232 if(typeof queueName
!= 'string') return queueName
;
234 if(!this.instances
[queueName
])
235 this.instances
[queueName
] = new Effect
.ScopedQueue();
237 return this.instances
[queueName
];
240 Effect
.Queue
= Effect
.Queues
.get('global');
242 Effect
.DefaultOptions
= {
243 transition: Effect
.Transitions
.sinoidal
,
244 duration: 1.0, // seconds
245 fps: 25.0, // max. 25fps due to Effect.Queue implementation
246 sync: false, // true for combining
253 Effect
.Base = function() {};
254 Effect
.Base
.prototype = {
256 start: function(options
) {
257 this.options
= Object
.extend(Object
.extend({},Effect
.DefaultOptions
), options
|| {});
258 this.currentFrame
= 0;
260 this.startOn
= this.options
.delay
*1000;
261 this.finishOn
= this.startOn
+ (this.options
.duration
*1000);
262 this.event('beforeStart');
263 if(!this.options
.sync
)
264 Effect
.Queues
.get(typeof this.options
.queue
== 'string' ?
265 'global' : this.options
.queue
.scope
).add(this);
267 loop: function(timePos
) {
268 if(timePos
>= this.startOn
) {
269 if(timePos
>= this.finishOn
) {
272 this.event('beforeFinish');
273 if(this.finish
) this.finish();
274 this.event('afterFinish');
277 var pos
= (timePos
- this.startOn
) / (this.finishOn
- this.startOn
);
278 var frame
= Math
.round(pos
* this.options
.fps
* this.options
.duration
);
279 if(frame
> this.currentFrame
) {
281 this.currentFrame
= frame
;
285 render: function(pos
) {
286 if(this.state
== 'idle') {
287 this.state
= 'running';
288 this.event('beforeSetup');
289 if(this.setup
) this.setup();
290 this.event('afterSetup');
292 if(this.state
== 'running') {
293 if(this.options
.transition
) pos
= this.options
.transition(pos
);
294 pos
*= (this.options
.to
-this.options
.from);
295 pos
+= this.options
.from;
297 this.event('beforeUpdate');
298 if(this.update
) this.update(pos
);
299 this.event('afterUpdate');
303 if(!this.options
.sync
)
304 Effect
.Queues
.get(typeof this.options
.queue
== 'string' ?
305 'global' : this.options
.queue
.scope
).remove(this);
306 this.state
= 'finished';
308 event: function(eventName
) {
309 if(this.options
[eventName
+ 'Internal']) this.options
[eventName
+ 'Internal'](this);
310 if(this.options
[eventName
]) this.options
[eventName
](this);
312 inspect: function() {
313 return '#<Effect:' + $H(this).inspect() + ',options:' + $H(this.options
).inspect() + '>';
317 Effect
.Parallel
= Class
.create();
318 Object
.extend(Object
.extend(Effect
.Parallel
.prototype, Effect
.Base
.prototype), {
319 initialize: function(effects
) {
320 this.effects
= effects
|| [];
321 this.start(arguments
[1]);
323 update: function(position
) {
324 this.effects
.invoke('render', position
);
326 finish: function(position
) {
327 this.effects
.each( function(effect
) {
330 effect
.event('beforeFinish');
331 if(effect
.finish
) effect
.finish(position
);
332 effect
.event('afterFinish');
337 Effect
.Opacity
= Class
.create();
338 Object
.extend(Object
.extend(Effect
.Opacity
.prototype, Effect
.Base
.prototype), {
339 initialize: function(element
) {
340 this.element
= $(element
);
341 // make this work on IE on elements without 'layout'
342 if(/MSIE/.test(navigator
.userAgent
) && (!this.element
.hasLayout
))
343 Element
.setStyle(this.element
, {zoom: 1});
344 var options
= Object
.extend({
345 from: Element
.getOpacity(this.element
) || 0.0,
347 }, arguments
[1] || {});
350 update: function(position
) {
351 Element
.setOpacity(this.element
, position
);
355 Effect
.Move
= Class
.create();
356 Object
.extend(Object
.extend(Effect
.Move
.prototype, Effect
.Base
.prototype), {
357 initialize: function(element
) {
358 this.element
= $(element
);
359 var options
= Object
.extend({
363 }, arguments
[1] || {});
367 // Bug in Opera: Opera returns the "real" position of a static element or
368 // relative element that does not have top/left explicitly set.
369 // ==> Always set top and left for position relative elements in your stylesheets
370 // (to 0 if you do not need them)
371 Element
.makePositioned(this.element
);
372 this.originalLeft
= parseFloat(Element
.getStyle(this.element
,'left') || '0');
373 this.originalTop
= parseFloat(Element
.getStyle(this.element
,'top') || '0');
374 if(this.options
.mode
== 'absolute') {
375 // absolute movement, so we need to calc deltaX and deltaY
376 this.options
.x
= this.options
.x
- this.originalLeft
;
377 this.options
.y
= this.options
.y
- this.originalTop
;
380 update: function(position
) {
381 Element
.setStyle(this.element
, {
382 left: this.options
.x
* position
+ this.originalLeft
+ 'px',
383 top: this.options
.y
* position
+ this.originalTop
+ 'px'
388 // for backwards compatibility
389 Effect
.MoveBy = function(element
, toTop
, toLeft
) {
390 return new Effect
.Move(element
,
391 Object
.extend({ x: toLeft
, y: toTop
}, arguments
[3] || {}));
394 Effect
.Scale
= Class
.create();
395 Object
.extend(Object
.extend(Effect
.Scale
.prototype, Effect
.Base
.prototype), {
396 initialize: function(element
, percent
) {
397 this.element
= $(element
)
398 var options
= Object
.extend({
402 scaleFromCenter: false,
403 scaleMode: 'box', // 'box' or 'contents' or {} with provided values
406 }, arguments
[2] || {});
410 this.restoreAfterFinish
= this.options
.restoreAfterFinish
|| false;
411 this.elementPositioning
= Element
.getStyle(this.element
,'position');
413 this.originalStyle
= {};
414 ['top','left','width','height','fontSize'].each( function(k
) {
415 this.originalStyle
[k
] = this.element
.style
[k
];
418 this.originalTop
= this.element
.offsetTop
;
419 this.originalLeft
= this.element
.offsetLeft
;
421 var fontSize
= Element
.getStyle(this.element
,'font-size') || '100%';
422 ['em','px','%'].each( function(fontSizeType
) {
423 if(fontSize
.indexOf(fontSizeType
)>0) {
424 this.fontSize
= parseFloat(fontSize
);
425 this.fontSizeType
= fontSizeType
;
429 this.factor
= (this.options
.scaleTo
- this.options
.scaleFrom
)/100;
432 if(this.options
.scaleMode
=='box')
433 this.dims
= [this.element
.offsetHeight
, this.element
.offsetWidth
];
434 if(/^content/.test(this.options
.scaleMode
))
435 this.dims
= [this.element
.scrollHeight
, this.element
.scrollWidth
];
437 this.dims
= [this.options
.scaleMode
.originalHeight
,
438 this.options
.scaleMode
.originalWidth
];
440 update: function(position
) {
441 var currentScale
= (this.options
.scaleFrom
/100.0) + (this.factor
* position
);
442 if(this.options
.scaleContent
&& this.fontSize
)
443 Element
.setStyle(this.element
, {fontSize: this.fontSize
* currentScale
+ this.fontSizeType
});
444 this.setDimensions(this.dims
[0] * currentScale
, this.dims
[1] * currentScale
);
446 finish: function(position
) {
447 if (this.restoreAfterFinish
) Element
.setStyle(this.element
, this.originalStyle
);
449 setDimensions: function(height
, width
) {
451 if(this.options
.scaleX
) d
.width
= width
+ 'px';
452 if(this.options
.scaleY
) d
.height
= height
+ 'px';
453 if(this.options
.scaleFromCenter
) {
454 var topd
= (height
- this.dims
[0])/2;
455 var leftd
= (width
- this.dims
[1])/2;
456 if(this.elementPositioning
== 'absolute') {
457 if(this.options
.scaleY
) d
.top
= this.originalTop
-topd
+ 'px';
458 if(this.options
.scaleX
) d
.left
= this.originalLeft
-leftd
+ 'px';
460 if(this.options
.scaleY
) d
.top
= -topd
+ 'px';
461 if(this.options
.scaleX
) d
.left
= -leftd
+ 'px';
464 Element
.setStyle(this.element
, d
);
468 Effect
.Highlight
= Class
.create();
469 Object
.extend(Object
.extend(Effect
.Highlight
.prototype, Effect
.Base
.prototype), {
470 initialize: function(element
) {
471 this.element
= $(element
);
472 var options
= Object
.extend({ startcolor: '#ffff99' }, arguments
[1] || {});
476 // Prevent executing on elements not in the layout flow
477 if(Element
.getStyle(this.element
, 'display')=='none') { this.cancel(); return; }
478 // Disable background image during the effect
480 backgroundImage: Element
.getStyle(this.element
, 'background-image') };
481 Element
.setStyle(this.element
, {backgroundImage: 'none'});
482 if(!this.options
.endcolor
)
483 this.options
.endcolor
= Element
.getStyle(this.element
, 'background-color').parseColor('#ffffff');
484 if(!this.options
.restorecolor
)
485 this.options
.restorecolor
= Element
.getStyle(this.element
, 'background-color');
486 // init color calculations
487 this._base
= $R(0,2).map(function(i
){ return parseInt(this.options
.startcolor
.slice(i
*2+1,i
*2+3),16) }.bind(this));
488 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));
490 update: function(position
) {
491 Element
.setStyle(this.element
,{backgroundColor: $R(0,2).inject('#',function(m
,v
,i
){
492 return m
+(Math
.round(this._base
[i
]+(this._delta
[i
]*position
)).toColorPart()); }.bind(this)) });
495 Element
.setStyle(this.element
, Object
.extend(this.oldStyle
, {
496 backgroundColor: this.options
.restorecolor
501 Effect
.ScrollTo
= Class
.create();
502 Object
.extend(Object
.extend(Effect
.ScrollTo
.prototype, Effect
.Base
.prototype), {
503 initialize: function(element
) {
504 this.element
= $(element
);
505 this.start(arguments
[1] || {});
509 var offsets
= Position
.cumulativeOffset(this.element
);
510 if(this.options
.offset
) offsets
[1] += this.options
.offset
;
511 var max
= window
.innerHeight
?
512 window
.height
- window
.innerHeight :
513 document
.body
.scrollHeight
-
514 (document
.documentElement
.clientHeight
?
515 document
.documentElement
.clientHeight : document
.body
.clientHeight
);
516 this.scrollStart
= Position
.deltaY
;
517 this.delta
= (offsets
[1] > max
? max : offsets
[1]) - this.scrollStart
;
519 update: function(position
) {
521 window
.scrollTo(Position
.deltaX
,
522 this.scrollStart
+ (position
*this.delta
));
526 /* ------------- combination effects ------------- */
528 Effect
.Fade = function(element
) {
529 var oldOpacity
= Element
.getInlineOpacity(element
);
530 var options
= Object
.extend({
531 from: Element
.getOpacity(element
) || 1.0,
533 afterFinishInternal: function(effect
) { with(Element
) {
534 if(effect
.options
.to
!=0) return;
535 hide(effect
.element
);
536 setStyle(effect
.element
, {opacity: oldOpacity
}); }}
537 }, arguments
[1] || {});
538 return new Effect
.Opacity(element
,options
);
541 Effect
.Appear = function(element
) {
542 var options
= Object
.extend({
543 from: (Element
.getStyle(element
, 'display') == 'none' ? 0.0 : Element
.getOpacity(element
) || 0.0),
545 beforeSetup: function(effect
) { with(Element
) {
546 setOpacity(effect
.element
, effect
.options
.from);
547 show(effect
.element
); }}
548 }, arguments
[1] || {});
549 return new Effect
.Opacity(element
,options
);
552 Effect
.Puff = function(element
) {
553 element
= $(element
);
554 var oldStyle
= { opacity: Element
.getInlineOpacity(element
), position: Element
.getStyle(element
, 'position') };
555 return new Effect
.Parallel(
556 [ new Effect
.Scale(element
, 200,
557 { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
558 new Effect
.Opacity(element
, { sync: true, to: 0.0 } ) ],
559 Object
.extend({ duration: 1.0,
560 beforeSetupInternal: function(effect
) { with(Element
) {
561 setStyle(effect
.effects
[0].element
, {position: 'absolute'}); }},
562 afterFinishInternal: function(effect
) { with(Element
) {
563 hide(effect
.effects
[0].element
);
564 setStyle(effect
.effects
[0].element
, oldStyle
); }}
565 }, arguments
[1] || {})
569 Effect
.BlindUp = function(element
) {
570 element
= $(element
);
571 Element
.makeClipping(element
);
572 return new Effect
.Scale(element
, 0,
573 Object
.extend({ scaleContent: false,
575 restoreAfterFinish: true,
576 afterFinishInternal: function(effect
) { with(Element
) {
577 [hide
, undoClipping
].call(effect
.element
); }}
578 }, arguments
[1] || {})
582 Effect
.BlindDown = function(element
) {
583 element
= $(element
);
584 var oldHeight
= Element
.getStyle(element
, 'height');
585 var elementDimensions
= Element
.getDimensions(element
);
586 return new Effect
.Scale(element
, 100,
587 Object
.extend({ scaleContent: false,
590 scaleMode: {originalHeight: elementDimensions
.height
, originalWidth: elementDimensions
.width
},
591 restoreAfterFinish: true,
592 afterSetup: function(effect
) { with(Element
) {
593 makeClipping(effect
.element
);
594 setStyle(effect
.element
, {height: '0px'});
595 show(effect
.element
);
597 afterFinishInternal: function(effect
) { with(Element
) {
598 undoClipping(effect
.element
);
599 setStyle(effect
.element
, {height: oldHeight
});
601 }, arguments
[1] || {})
605 Effect
.SwitchOff = function(element
) {
606 element
= $(element
);
607 var oldOpacity
= Element
.getInlineOpacity(element
);
608 return new Effect
.Appear(element
, {
611 transition: Effect
.Transitions
.flicker
,
612 afterFinishInternal: function(effect
) {
613 new Effect
.Scale(effect
.element
, 1, {
614 duration: 0.3, scaleFromCenter: true,
615 scaleX: false, scaleContent: false, restoreAfterFinish: true,
616 beforeSetup: function(effect
) { with(Element
) {
617 [makePositioned
,makeClipping
].call(effect
.element
);
619 afterFinishInternal: function(effect
) { with(Element
) {
620 [hide
,undoClipping
,undoPositioned
].call(effect
.element
);
621 setStyle(effect
.element
, {opacity: oldOpacity
});
628 Effect
.DropOut = function(element
) {
629 element
= $(element
);
631 top: Element
.getStyle(element
, 'top'),
632 left: Element
.getStyle(element
, 'left'),
633 opacity: Element
.getInlineOpacity(element
) };
634 return new Effect
.Parallel(
635 [ new Effect
.Move(element
, {x: 0, y: 100, sync: true }),
636 new Effect
.Opacity(element
, { sync: true, to: 0.0 }) ],
639 beforeSetup: function(effect
) { with(Element
) {
640 makePositioned(effect
.effects
[0].element
); }},
641 afterFinishInternal: function(effect
) { with(Element
) {
642 [hide
, undoPositioned
].call(effect
.effects
[0].element
);
643 setStyle(effect
.effects
[0].element
, oldStyle
); }}
644 }, arguments
[1] || {}));
647 Effect
.Shake = function(element
) {
648 element
= $(element
);
650 top: Element
.getStyle(element
, 'top'),
651 left: Element
.getStyle(element
, 'left') };
652 return new Effect
.Move(element
,
653 { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect
) {
654 new Effect
.Move(effect
.element
,
655 { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect
) {
656 new Effect
.Move(effect
.element
,
657 { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect
) {
658 new Effect
.Move(effect
.element
,
659 { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect
) {
660 new Effect
.Move(effect
.element
,
661 { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect
) {
662 new Effect
.Move(effect
.element
,
663 { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect
) { with(Element
) {
664 undoPositioned(effect
.element
);
665 setStyle(effect
.element
, oldStyle
);
666 }}}) }}) }}) }}) }}) }});
669 Effect
.SlideDown = function(element
) {
670 element
= $(element
);
671 Element
.cleanWhitespace(element
);
672 // SlideDown need to have the content of the element wrapped in a container element with fixed height!
673 var oldInnerBottom
= Element
.getStyle(element
.firstChild
, 'bottom');
674 var elementDimensions
= Element
.getDimensions(element
);
675 return new Effect
.Scale(element
, 100, Object
.extend({
679 scaleMode: {originalHeight: elementDimensions
.height
, originalWidth: elementDimensions
.width
},
680 restoreAfterFinish: true,
681 afterSetup: function(effect
) { with(Element
) {
682 makePositioned(effect
.element
);
683 makePositioned(effect
.element
.firstChild
);
684 if(window
.opera
) setStyle(effect
.element
, {top: ''});
685 makeClipping(effect
.element
);
686 setStyle(effect
.element
, {height: '0px'});
688 afterUpdateInternal: function(effect
) { with(Element
) {
689 setStyle(effect
.element
.firstChild
, {bottom:
690 (effect
.dims
[0] - effect
.element
.clientHeight
) + 'px' }); }},
691 afterFinishInternal: function(effect
) { with(Element
) {
692 undoClipping(effect
.element
);
693 undoPositioned(effect
.element
.firstChild
);
694 undoPositioned(effect
.element
);
695 setStyle(effect
.element
.firstChild
, {bottom: oldInnerBottom
}); }}
696 }, arguments
[1] || {})
700 Effect
.SlideUp = function(element
) {
701 element
= $(element
);
702 Element
.cleanWhitespace(element
);
703 var oldInnerBottom
= Element
.getStyle(element
.firstChild
, 'bottom');
704 return new Effect
.Scale(element
, 0,
705 Object
.extend({ scaleContent: false,
709 restoreAfterFinish: true,
710 beforeStartInternal: function(effect
) { with(Element
) {
711 makePositioned(effect
.element
);
712 makePositioned(effect
.element
.firstChild
);
713 if(window
.opera
) setStyle(effect
.element
, {top: ''});
714 makeClipping(effect
.element
);
716 afterUpdateInternal: function(effect
) { with(Element
) {
717 setStyle(effect
.element
.firstChild
, {bottom:
718 (effect
.dims
[0] - effect
.element
.clientHeight
) + 'px' }); }},
719 afterFinishInternal: function(effect
) { with(Element
) {
720 [hide
, undoClipping
].call(effect
.element
);
721 undoPositioned(effect
.element
.firstChild
);
722 undoPositioned(effect
.element
);
723 setStyle(effect
.element
.firstChild
, {bottom: oldInnerBottom
}); }}
724 }, arguments
[1] || {})
728 // Bug in opera makes the TD containing this element expand for a instance after finish
729 Effect
.Squish = function(element
) {
730 return new Effect
.Scale(element
, window
.opera
? 1 : 0,
731 { restoreAfterFinish: true,
732 beforeSetup: function(effect
) { with(Element
) {
733 makeClipping(effect
.element
); }},
734 afterFinishInternal: function(effect
) { with(Element
) {
735 hide(effect
.element
);
736 undoClipping(effect
.element
); }}
740 Effect
.Grow = function(element
) {
741 element
= $(element
);
742 var options
= Object
.extend({
744 moveTransistion: Effect
.Transitions
.sinoidal
,
745 scaleTransition: Effect
.Transitions
.sinoidal
,
746 opacityTransition: Effect
.Transitions
.full
747 }, arguments
[1] || {});
749 top: element
.style
.top
,
750 left: element
.style
.left
,
751 height: element
.style
.height
,
752 width: element
.style
.width
,
753 opacity: Element
.getInlineOpacity(element
) };
755 var dims
= Element
.getDimensions(element
);
756 var initialMoveX
, initialMoveY
;
759 switch (options
.direction
) {
761 initialMoveX
= initialMoveY
= moveX
= moveY
= 0;
764 initialMoveX
= dims
.width
;
765 initialMoveY
= moveY
= 0;
769 initialMoveX
= moveX
= 0;
770 initialMoveY
= dims
.height
;
771 moveY
= -dims
.height
;
774 initialMoveX
= dims
.width
;
775 initialMoveY
= dims
.height
;
777 moveY
= -dims
.height
;
780 initialMoveX
= dims
.width
/ 2;
781 initialMoveY
= dims
.height
/ 2;
782 moveX
= -dims
.width
/ 2;
783 moveY
= -dims
.height
/ 2;
787 return new Effect
.Move(element
, {
791 beforeSetup: function(effect
) { with(Element
) {
792 hide(effect
.element
);
793 makeClipping(effect
.element
);
794 makePositioned(effect
.element
);
796 afterFinishInternal: function(effect
) {
798 [ new Effect
.Opacity(effect
.element
, { sync: true, to: 1.0, from: 0.0, transition: options
.opacityTransition
}),
799 new Effect
.Move(effect
.element
, { x: moveX
, y: moveY
, sync: true, transition: options
.moveTransition
}),
800 new Effect
.Scale(effect
.element
, 100, {
801 scaleMode: { originalHeight: dims
.height
, originalWidth: dims
.width
},
802 sync: true, scaleFrom: window
.opera
? 1 : 0, transition: options
.scaleTransition
, restoreAfterFinish: true})
804 beforeSetup: function(effect
) { with(Element
) {
805 setStyle(effect
.effects
[0].element
, {height: '0px'});
806 show(effect
.effects
[0].element
); }},
807 afterFinishInternal: function(effect
) { with(Element
) {
808 [undoClipping
, undoPositioned
].call(effect
.effects
[0].element
);
809 setStyle(effect
.effects
[0].element
, oldStyle
); }}
816 Effect
.Shrink = function(element
) {
817 element
= $(element
);
818 var options
= Object
.extend({
820 moveTransistion: Effect
.Transitions
.sinoidal
,
821 scaleTransition: Effect
.Transitions
.sinoidal
,
822 opacityTransition: Effect
.Transitions
.none
823 }, arguments
[1] || {});
825 top: element
.style
.top
,
826 left: element
.style
.left
,
827 height: element
.style
.height
,
828 width: element
.style
.width
,
829 opacity: Element
.getInlineOpacity(element
) };
831 var dims
= Element
.getDimensions(element
);
834 switch (options
.direction
) {
851 moveX
= dims
.width
/ 2;
852 moveY
= dims
.height
/ 2;
856 return new Effect
.Parallel(
857 [ new Effect
.Opacity(element
, { sync: true, to: 0.0, from: 1.0, transition: options
.opacityTransition
}),
858 new Effect
.Scale(element
, window
.opera
? 1 : 0, { sync: true, transition: options
.scaleTransition
, restoreAfterFinish: true}),
859 new Effect
.Move(element
, { x: moveX
, y: moveY
, sync: true, transition: options
.moveTransition
})
861 beforeStartInternal: function(effect
) { with(Element
) {
862 [makePositioned
, makeClipping
].call(effect
.effects
[0].element
) }},
863 afterFinishInternal: function(effect
) { with(Element
) {
864 [hide
, undoClipping
, undoPositioned
].call(effect
.effects
[0].element
);
865 setStyle(effect
.effects
[0].element
, oldStyle
); }}
870 Effect
.Pulsate = function(element
) {
871 element
= $(element
);
872 var options
= arguments
[1] || {};
873 var oldOpacity
= Element
.getInlineOpacity(element
);
874 var transition
= options
.transition
|| Effect
.Transitions
.sinoidal
;
875 var reverser = function(pos
){ return transition(1-Effect
.Transitions
.pulse(pos
)) };
876 reverser
.bind(transition
);
877 return new Effect
.Opacity(element
,
878 Object
.extend(Object
.extend({ duration: 3.0, from: 0,
879 afterFinishInternal: function(effect
) { Element
.setStyle(effect
.element
, {opacity: oldOpacity
}); }
880 }, options
), {transition: reverser
}));
883 Effect
.Fold = function(element
) {
884 element
= $(element
);
886 top: element
.style
.top
,
887 left: element
.style
.left
,
888 width: element
.style
.width
,
889 height: element
.style
.height
};
890 Element
.makeClipping(element
);
891 return new Effect
.Scale(element
, 5, Object
.extend({
894 afterFinishInternal: function(effect
) {
895 new Effect
.Scale(element
, 1, {
898 afterFinishInternal: function(effect
) { with(Element
) {
899 [hide
, undoClipping
].call(effect
.element
);
900 setStyle(effect
.element
, oldStyle
);
902 }}, arguments
[1] || {}));