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.collectTextNodesIgnoreClass = function(element, ignoreclass) {
28 var children = $(element).childNodes;
30 var classtest = new RegExp("^([^ ]+ )*" + ignoreclass+ "( [^ ]+)*$","i");
32 for (var i = 0; i < children.length; i++) {
33 if(children[i].nodeType==3) {
34 text+=children[i].nodeValue;
36 if((!children[i].className.match(classtest)) && children[i].hasChildNodes())
37 text += Element.collectTextNodesIgnoreClass(children[i], ignoreclass);
44 Element.setContentZoom = function(element, percent) {
46 element.style.fontSize = (percent/100) + "em";
47 if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
50 Element.getOpacity = function(element){
52 if (opacity = Element.getStyle(element, "opacity"))
53 return parseFloat(opacity);
54 if (opacity = (Element.getStyle(element, "filter") || '').match(/alpha\(opacity=(.*)\)/))
55 if(opacity[1]) return parseFloat(opacity[1]) / 100;
59 Element.setOpacity = function(element, value){
61 var els = element.style;
63 els.opacity = '0.999999';
64 if(/MSIE/.test(navigator.userAgent))
65 els.filter = Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'');
67 if(value < 0.00001) value = 0;
69 if(/MSIE/.test(navigator.userAgent))
70 els.filter = Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') +
71 "alpha(opacity="+value*100+")";
75 Element.getInlineOpacity = function(element){
78 op = element.style.opacity;
79 if (typeof op != "undefined" && op != "") return op;
83 Element.setInlineOpacity = function(element, value){
85 var els = element.style;
89 /*--------------------------------------------------------------------------*/
92 // Element.toggleClass(element, className) toggles the class being on/off
93 // Element.toggleClass(element, className1, className2) toggles between both classes,
94 // defaulting to className1 if neither exist
95 toggle: function(element, className) {
96 if(Element.Class.has(element, className)) {
97 Element.Class.remove(element, className);
98 if(arguments.length == 3) Element.Class.add(element, arguments[2]);
100 Element.Class.add(element, className);
101 if(arguments.length == 3) Element.Class.remove(element, arguments[2]);
105 // gets space-delimited classnames of an element as an array
106 get: function(element) {
107 return $(element).className.split(' ');
110 // functions adapted from original functions by Gavin Kistner
111 remove: function(element) {
112 element = $(element);
113 var removeClasses = arguments;
114 $R(1,arguments.length-1).each( function(index) {
116 element.className.split(' ').reject(
117 function(klass) { return (klass == removeClasses[index]) } ).join(' ');
121 add: function(element) {
122 element = $(element);
123 for(var i = 1; i < arguments.length; i++) {
124 Element.Class.remove(element, arguments[i]);
125 element.className += (element.className.length > 0 ? ' ' : '') + arguments[i];
129 // returns true if all given classes exist in said element
130 has: function(element) {
131 element = $(element);
132 if(!element || !element.className) return false;
134 for(var i = 1; i < arguments.length; i++) {
135 if((typeof arguments[i] == 'object') &&
136 (arguments[i].constructor == Array)) {
137 for(var j = 0; j < arguments[i].length; j++) {
138 regEx = new RegExp("(^|\\s)" + arguments[i][j] + "(\\s|$)");
139 if(!regEx.test(element.className)) return false;
142 regEx = new RegExp("(^|\\s)" + arguments[i] + "(\\s|$)");
143 if(!regEx.test(element.className)) return false;
149 // expects arrays of strings and/or strings as optional paramters
150 // Element.Class.has_any(element, ['classA','classB','classC'], 'classD')
151 has_any: function(element) {
152 element = $(element);
153 if(!element || !element.className) return false;
155 for(var i = 1; i < arguments.length; i++) {
156 if((typeof arguments[i] == 'object') &&
157 (arguments[i].constructor == Array)) {
158 for(var j = 0; j < arguments[i].length; j++) {
159 regEx = new RegExp("(^|\\s)" + arguments[i][j] + "(\\s|$)");
160 if(regEx.test(element.className)) return true;
163 regEx = new RegExp("(^|\\s)" + arguments[i] + "(\\s|$)");
164 if(regEx.test(element.className)) return true;
170 childrenWith: function(element, className) {
171 var children = $(element).getElementsByTagName('*');
172 var elements = new Array();
174 for (var i = 0; i < children.length; i++)
175 if (Element.Class.has(children[i], className))
176 elements.push(children[i]);
182 /*--------------------------------------------------------------------------*/
185 tagifyText: function(element) {
186 var tagifyStyle = "position:relative";
187 if(/MSIE/.test(navigator.userAgent)) tagifyStyle += ";zoom:1";
188 element = $(element);
189 $A(element.childNodes).each( function(child) {
190 if(child.nodeType==3) {
191 child.nodeValue.toArray().each( function(character) {
192 element.insertBefore(
193 Builder.node('span',{style: tagifyStyle},
194 character == " " ? String.fromCharCode(160) : character),
197 Element.remove(child);
201 multiple: function(element, effect) {
203 if(((typeof element == 'object') ||
204 (typeof element == 'function')) &&
208 elements = $(element).childNodes;
210 var options = Object.extend({
213 }, arguments[2] || {});
214 var speed = options.speed;
215 var delay = options.delay;
217 $A(elements).each( function(element, index) {
218 new effect(element, Object.extend(options, { delay: delay + index * speed }));
223 var Effect2 = Effect; // deprecated
225 /* ------------- transitions ------------- */
227 Effect.Transitions = {}
229 Effect.Transitions.linear = function(pos) {
232 Effect.Transitions.sinoidal = function(pos) {
233 return (-Math.cos(pos*Math.PI)/2) + 0.5;
235 Effect.Transitions.reverse = function(pos) {
238 Effect.Transitions.flicker = function(pos) {
239 return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
241 Effect.Transitions.wobble = function(pos) {
242 return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
244 Effect.Transitions.pulse = function(pos) {
245 return (Math.floor(pos*10) % 2 == 0 ?
246 (pos*10-Math.floor(pos*10)) : 1-(pos*10-Math.floor(pos*10)));
248 Effect.Transitions.none = function(pos) {
251 Effect.Transitions.full = function(pos) {
255 /* ------------- core effects ------------- */
259 _each: function(iterator) {
260 this.effects._each(iterator);
263 add: function(effect) {
264 var timestamp = new Date().getTime();
266 switch(effect.options.queue) {
268 // move unstarted effects after this effect
269 this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
270 e.startOn += effect.finishOn;
271 e.finishOn += effect.finishOn;
275 // start effect after last queued effect has finished
276 timestamp = this.effects.pluck('finishOn').max() || timestamp;
280 effect.startOn += timestamp;
281 effect.finishOn += timestamp;
282 this.effects.push(effect);
284 this.interval = setInterval(this.loop.bind(this), 40);
286 remove: function(effect) {
287 this.effects = this.effects.reject(function(e) { return e==effect });
288 if(this.effects.length == 0) {
289 clearInterval(this.interval);
290 this.interval = null;
294 var timePos = new Date().getTime();
295 this.effects.invoke('loop', timePos);
298 Object.extend(Effect.Queue, Enumerable);
300 Effect.Base = function() {};
301 Effect.Base.prototype = {
303 setOptions: function(options) {
304 this.options = Object.extend({
305 transition: Effect.Transitions.sinoidal,
306 duration: 1.0, // seconds
307 fps: 25.0, // max. 25fps due to Effect.Queue implementation
308 sync: false, // true for combining
315 start: function(options) {
316 this.setOptions(options || {});
317 this.currentFrame = 0;
319 this.startOn = this.options.delay*1000;
320 this.finishOn = this.startOn + (this.options.duration*1000);
321 this.event('beforeStart');
322 if(!this.options.sync) Effect.Queue.add(this);
324 loop: function(timePos) {
325 if(timePos >= this.startOn) {
326 if(timePos >= this.finishOn) {
329 this.event('beforeFinish');
330 if(this.finish) this.finish();
331 this.event('afterFinish');
334 var pos = (timePos - this.startOn) / (this.finishOn - this.startOn);
335 var frame = Math.round(pos * this.options.fps * this.options.duration);
336 if(frame > this.currentFrame) {
338 this.currentFrame = frame;
342 render: function(pos) {
343 if(this.state == 'idle') {
344 this.state = 'running';
345 this.event('beforeSetup');
346 if(this.setup) this.setup();
347 this.event('afterSetup');
349 if(this.options.transition) pos = this.options.transition(pos);
350 pos *= (this.options.to-this.options.from);
351 pos += this.options.from;
353 this.event('beforeUpdate');
354 if(this.update) this.update(pos);
355 this.event('afterUpdate');
358 if(!this.options.sync) Effect.Queue.remove(this);
359 this.state = 'finished';
361 event: function(eventName) {
362 if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
363 if(this.options[eventName]) this.options[eventName](this);
367 Effect.Parallel = Class.create();
368 Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
369 initialize: function(effects) {
370 this.effects = effects || [];
371 this.start(arguments[1]);
373 update: function(position) {
374 this.effects.invoke('render', position);
376 finish: function(position) {
377 this.effects.each( function(effect) {
380 effect.event('beforeFinish');
381 if(effect.finish) effect.finish(position);
382 effect.event('afterFinish');
387 Effect.Opacity = Class.create();
388 Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
389 initialize: function(element) {
390 this.element = $(element);
391 // make this work on IE on elements without 'layout'
392 if(/MSIE/.test(navigator.userAgent) && (!this.element.hasLayout))
393 this.element.style.zoom = 1;
394 var options = Object.extend({
395 from: Element.getOpacity(this.element) || 0.0,
397 }, arguments[1] || {});
400 update: function(position) {
401 Element.setOpacity(this.element, position);
405 Effect.MoveBy = Class.create();
406 Object.extend(Object.extend(Effect.MoveBy.prototype, Effect.Base.prototype), {
407 initialize: function(element, toTop, toLeft) {
408 this.element = $(element);
410 this.toLeft = toLeft;
411 this.start(arguments[3]);
414 // Bug in Opera: Opera returns the "real" position of a static element or
415 // relative element that does not have top/left explicitly set.
416 // ==> Always set top and left for position relative elements in your stylesheets
417 // (to 0 if you do not need them)
419 Element.makePositioned(this.element);
420 this.originalTop = parseFloat(Element.getStyle(this.element,'top') || '0');
421 this.originalLeft = parseFloat(Element.getStyle(this.element,'left') || '0');
423 update: function(position) {
424 var topd = this.toTop * position + this.originalTop;
425 var leftd = this.toLeft * position + this.originalLeft;
426 this.setPosition(topd, leftd);
428 setPosition: function(topd, leftd) {
429 this.element.style.top = topd + "px";
430 this.element.style.left = leftd + "px";
434 Effect.Scale = Class.create();
435 Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
436 initialize: function(element, percent) {
437 this.element = $(element)
438 var options = Object.extend({
442 scaleFromCenter: false,
443 scaleMode: 'box', // 'box' or 'contents' or {} with provided values
446 }, arguments[2] || {});
452 this.restoreAfterFinish = this.options.restoreAfterFinish || false;
453 this.elementPositioning = Element.getStyle(this.element,'position');
455 effect.originalStyle = {};
456 ['top','left','width','height','fontSize'].each( function(k) {
457 effect.originalStyle[k] = effect.element.style[k];
460 this.originalTop = this.element.offsetTop;
461 this.originalLeft = this.element.offsetLeft;
463 var fontSize = Element.getStyle(this.element,'font-size') || "100%";
464 ['em','px','%'].each( function(fontSizeType) {
465 if(fontSize.indexOf(fontSizeType)>0) {
466 effect.fontSize = parseFloat(fontSize);
467 effect.fontSizeType = fontSizeType;
471 this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
474 if(this.options.scaleMode=='box')
475 this.dims = [this.element.clientHeight, this.element.clientWidth];
476 if(this.options.scaleMode=='content')
477 this.dims = [this.element.scrollHeight, this.element.scrollWidth];
479 this.dims = [this.options.scaleMode.originalHeight,
480 this.options.scaleMode.originalWidth];
482 update: function(position) {
483 var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
484 if(this.options.scaleContent && this.fontSize)
485 this.element.style.fontSize = this.fontSize*currentScale + this.fontSizeType;
486 this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
488 finish: function(position) {
489 if (this.restoreAfterFinish) {
491 ['top','left','width','height','fontSize'].each( function(k) {
492 effect.element.style[k] = effect.originalStyle[k];
496 setDimensions: function(height, width) {
497 var els = this.element.style;
498 if(this.options.scaleX) els.width = width + 'px';
499 if(this.options.scaleY) els.height = height + 'px';
500 if(this.options.scaleFromCenter) {
501 var topd = (height - this.dims[0])/2;
502 var leftd = (width - this.dims[1])/2;
503 if(this.elementPositioning == 'absolute') {
504 if(this.options.scaleY) els.top = this.originalTop-topd + "px";
505 if(this.options.scaleX) els.left = this.originalLeft-leftd + "px";
507 if(this.options.scaleY) els.top = -topd + "px";
508 if(this.options.scaleX) els.left = -leftd + "px";
514 Effect.Highlight = Class.create();
515 Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
516 initialize: function(element) {
517 this.element = $(element);
518 var options = Object.extend({
519 startcolor: "#ffff99"
520 }, arguments[1] || {});
524 // Prevent executing on elements not in the layout flow
525 if(this.element.style.display=='none') { this.cancel(); return; }
526 // Disable background image during the effect
527 this.oldBgImage = this.element.style.backgroundImage;
528 this.element.style.backgroundImage = "none";
529 if(!this.options.endcolor)
530 this.options.endcolor = Element.getStyle(this.element, 'background-color').parseColor('#ffffff');
531 if (typeof this.options.restorecolor == "undefined")
532 this.options.restorecolor = this.element.style.backgroundColor;
533 // init color calculations
535 parseInt(this.options.startcolor.slice(1,3),16),
536 parseInt(this.options.startcolor.slice(3,5),16),
537 parseInt(this.options.startcolor.slice(5),16) ];
538 this.colors_delta = [
539 parseInt(this.options.endcolor.slice(1,3),16)-this.colors_base[0],
540 parseInt(this.options.endcolor.slice(3,5),16)-this.colors_base[1],
541 parseInt(this.options.endcolor.slice(5),16)-this.colors_base[2]];
543 update: function(position) {
544 var effect = this; var colors = $R(0,2).map( function(i){
545 return Math.round(effect.colors_base[i]+(effect.colors_delta[i]*position))
547 this.element.style.backgroundColor = "#" +
548 colors[0].toColorPart() + colors[1].toColorPart() + colors[2].toColorPart();
551 this.element.style.backgroundColor = this.options.restorecolor;
552 this.element.style.backgroundImage = this.oldBgImage;
556 Effect.ScrollTo = Class.create();
557 Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
558 initialize: function(element) {
559 this.element = $(element);
560 this.start(arguments[1] || {});
564 var offsets = Position.cumulativeOffset(this.element);
565 var max = window.innerHeight ?
566 window.height - window.innerHeight :
567 document.body.scrollHeight -
568 (document.documentElement.clientHeight ?
569 document.documentElement.clientHeight : document.body.clientHeight);
570 this.scrollStart = Position.deltaY;
571 this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
573 update: function(position) {
575 window.scrollTo(Position.deltaX,
576 this.scrollStart + (position*this.delta));
580 /* ------------- combination effects ------------- */
582 Effect.Fade = function(element) {
583 var oldOpacity = Element.getInlineOpacity(element);
584 var options = Object.extend({
585 from: Element.getOpacity(element) || 1.0,
587 afterFinishInternal: function(effect)
588 { if (effect.options.to == 0) {
589 Element.hide(effect.element);
590 Element.setInlineOpacity(effect.element, oldOpacity);
593 }, arguments[1] || {});
594 return new Effect.Opacity(element,options);
597 Effect.Appear = function(element) {
598 var options = Object.extend({
599 from: (Element.getStyle(element, "display") == "none" ? 0.0 : Element.getOpacity(element) || 0.0),
601 beforeSetup: function(effect)
602 { Element.setOpacity(effect.element, effect.options.from);
603 Element.show(effect.element); }
604 }, arguments[1] || {});
605 return new Effect.Opacity(element,options);
608 Effect.Puff = function(element) {
609 element = $(element);
610 var oldOpacity = Element.getInlineOpacity(element);
611 var oldPosition = element.style.position;
612 return new Effect.Parallel(
613 [ new Effect.Scale(element, 200,
614 { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
615 new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
616 Object.extend({ duration: 1.0,
617 beforeSetupInternal: function(effect)
618 { effect.effects[0].element.style.position = 'absolute'; },
619 afterFinishInternal: function(effect)
620 { Element.hide(effect.effects[0].element);
621 effect.effects[0].element.style.position = oldPosition;
622 Element.setInlineOpacity(effect.effects[0].element, oldOpacity); }
623 }, arguments[1] || {})
627 Effect.BlindUp = function(element) {
628 element = $(element);
629 Element.makeClipping(element);
630 return new Effect.Scale(element, 0,
631 Object.extend({ scaleContent: false,
633 restoreAfterFinish: true,
634 afterFinishInternal: function(effect)
636 Element.hide(effect.element);
637 Element.undoClipping(effect.element);
639 }, arguments[1] || {})
643 Effect.BlindDown = function(element) {
644 element = $(element);
645 var oldHeight = element.style.height;
646 var elementDimensions = Element.getDimensions(element);
647 return new Effect.Scale(element, 100,
648 Object.extend({ scaleContent: false,
651 scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
652 restoreAfterFinish: true,
653 afterSetup: function(effect) {
654 Element.makeClipping(effect.element);
655 effect.element.style.height = "0px";
656 Element.show(effect.element);
658 afterFinishInternal: function(effect) {
659 Element.undoClipping(effect.element);
660 effect.element.style.height = oldHeight;
662 }, arguments[1] || {})
666 Effect.SwitchOff = function(element) {
667 element = $(element);
668 var oldOpacity = Element.getInlineOpacity(element);
669 return new Effect.Appear(element, {
672 transition: Effect.Transitions.flicker,
673 afterFinishInternal: function(effect) {
674 new Effect.Scale(effect.element, 1, {
675 duration: 0.3, scaleFromCenter: true,
676 scaleX: false, scaleContent: false, restoreAfterFinish: true,
677 beforeSetup: function(effect) {
678 Element.makePositioned(effect.element);
679 Element.makeClipping(effect.element);
681 afterFinishInternal: function(effect) {
682 Element.hide(effect.element);
683 Element.undoClipping(effect.element);
684 Element.undoPositioned(effect.element);
685 Element.setInlineOpacity(effect.element, oldOpacity);
692 Effect.DropOut = function(element) {
693 element = $(element);
694 var oldTop = element.style.top;
695 var oldLeft = element.style.left;
696 var oldOpacity = Element.getInlineOpacity(element);
697 return new Effect.Parallel(
698 [ new Effect.MoveBy(element, 100, 0, { sync: true }),
699 new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
702 beforeSetup: function(effect) {
703 Element.makePositioned(effect.effects[0].element); },
704 afterFinishInternal: function(effect) {
705 Element.hide(effect.effects[0].element);
706 Element.undoPositioned(effect.effects[0].element);
707 effect.effects[0].element.style.left = oldLeft;
708 effect.effects[0].element.style.top = oldTop;
709 Element.setInlineOpacity(effect.effects[0].element, oldOpacity); }
710 }, arguments[1] || {}));
713 Effect.Shake = function(element) {
714 element = $(element);
715 var oldTop = element.style.top;
716 var oldLeft = element.style.left;
717 return new Effect.MoveBy(element, 0, 20,
718 { duration: 0.05, afterFinishInternal: function(effect) {
719 new Effect.MoveBy(effect.element, 0, -40,
720 { duration: 0.1, afterFinishInternal: function(effect) {
721 new Effect.MoveBy(effect.element, 0, 40,
722 { duration: 0.1, afterFinishInternal: function(effect) {
723 new Effect.MoveBy(effect.element, 0, -40,
724 { duration: 0.1, afterFinishInternal: function(effect) {
725 new Effect.MoveBy(effect.element, 0, 40,
726 { duration: 0.1, afterFinishInternal: function(effect) {
727 new Effect.MoveBy(effect.element, 0, -20,
728 { duration: 0.05, afterFinishInternal: function(effect) {
729 Element.undoPositioned(effect.element);
730 effect.element.style.left = oldLeft;
731 effect.element.style.top = oldTop;
732 }}) }}) }}) }}) }}) }});
735 Effect.SlideDown = function(element) {
736 element = $(element);
737 Element.cleanWhitespace(element);
738 // SlideDown need to have the content of the element wrapped in a container element with fixed height!
739 var oldInnerBottom = element.firstChild.style.bottom;
740 var elementDimensions = Element.getDimensions(element);
741 return new Effect.Scale(element, 100,
742 Object.extend({ scaleContent: false,
745 scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
746 restoreAfterFinish: true,
747 afterSetup: function(effect) {
748 Element.makePositioned(effect.element.firstChild);
749 if (window.opera) effect.element.firstChild.style.top = "";
750 Element.makeClipping(effect.element);
751 element.style.height = '0';
752 Element.show(element);
754 afterUpdateInternal: function(effect) {
755 effect.element.firstChild.style.bottom =
756 (effect.dims[0] - effect.element.clientHeight) + 'px'; },
757 afterFinishInternal: function(effect) {
758 Element.undoClipping(effect.element);
759 Element.undoPositioned(effect.element.firstChild);
760 effect.element.firstChild.style.bottom = oldInnerBottom; }
761 }, arguments[1] || {})
765 Effect.SlideUp = function(element) {
766 element = $(element);
767 Element.cleanWhitespace(element);
768 var oldInnerBottom = element.firstChild.style.bottom;
769 return new Effect.Scale(element, 0,
770 Object.extend({ scaleContent: false,
774 restoreAfterFinish: true,
775 beforeStartInternal: function(effect) {
776 Element.makePositioned(effect.element.firstChild);
777 if (window.opera) effect.element.firstChild.style.top = "";
778 Element.makeClipping(effect.element);
779 Element.show(element);
781 afterUpdateInternal: function(effect) {
782 effect.element.firstChild.style.bottom =
783 (effect.dims[0] - effect.element.clientHeight) + 'px'; },
784 afterFinishInternal: function(effect) {
785 Element.hide(effect.element);
786 Element.undoClipping(effect.element);
787 Element.undoPositioned(effect.element.firstChild);
788 effect.element.firstChild.style.bottom = oldInnerBottom; }
789 }, arguments[1] || {})
793 Effect.Squish = function(element) {
794 // Bug in opera makes the TD containing this element expand for a instance after finish
795 return new Effect.Scale(element, window.opera ? 1 : 0,
796 { restoreAfterFinish: true,
797 beforeSetup: function(effect) {
798 Element.makeClipping(effect.element); },
799 afterFinishInternal: function(effect) {
800 Element.hide(effect.element);
801 Element.undoClipping(effect.element); }
805 Effect.Grow = function(element) {
806 element = $(element);
807 var options = arguments[1] || {};
809 var elementDimensions = Element.getDimensions(element);
810 var originalWidth = elementDimensions.width;
811 var originalHeight = elementDimensions.height;
812 var oldTop = element.style.top;
813 var oldLeft = element.style.left;
814 var oldHeight = element.style.height;
815 var oldWidth = element.style.width;
816 var oldOpacity = Element.getInlineOpacity(element);
818 var direction = options.direction || 'center';
819 var moveTransition = options.moveTransition || Effect.Transitions.sinoidal;
820 var scaleTransition = options.scaleTransition || Effect.Transitions.sinoidal;
821 var opacityTransition = options.opacityTransition || Effect.Transitions.full;
823 var initialMoveX, initialMoveY;
828 initialMoveX = initialMoveY = moveX = moveY = 0;
831 initialMoveX = originalWidth;
832 initialMoveY = moveY = 0;
833 moveX = -originalWidth;
836 initialMoveX = moveX = 0;
837 initialMoveY = originalHeight;
838 moveY = -originalHeight;
841 initialMoveX = originalWidth;
842 initialMoveY = originalHeight;
843 moveX = -originalWidth;
844 moveY = -originalHeight;
847 initialMoveX = originalWidth / 2;
848 initialMoveY = originalHeight / 2;
849 moveX = -originalWidth / 2;
850 moveY = -originalHeight / 2;
854 return new Effect.MoveBy(element, initialMoveY, initialMoveX, {
856 beforeSetup: function(effect) {
857 Element.hide(effect.element);
858 Element.makeClipping(effect.element);
859 Element.makePositioned(effect.element);
861 afterFinishInternal: function(effect) {
863 [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: opacityTransition }),
864 new Effect.MoveBy(effect.element, moveY, moveX, { sync: true, transition: moveTransition }),
865 new Effect.Scale(effect.element, 100, {
866 scaleMode: { originalHeight: originalHeight, originalWidth: originalWidth },
867 sync: true, scaleFrom: window.opera ? 1 : 0, transition: scaleTransition, restoreAfterFinish: true})
869 beforeSetup: function(effect) {
870 effect.effects[0].element.style.height = 0;
871 Element.show(effect.effects[0].element);
873 afterFinishInternal: function(effect) {
874 var el = effect.effects[0].element;
876 Element.undoClipping(el);
877 Element.undoPositioned(el);
880 els.height = oldHeight;
881 els.width = originalWidth + 'px';
882 Element.setInlineOpacity(el, oldOpacity);
890 Effect.Shrink = function(element) {
891 element = $(element);
892 var options = arguments[1] || {};
894 var originalWidth = element.clientWidth;
895 var originalHeight = element.clientHeight;
896 var oldTop = element.style.top;
897 var oldLeft = element.style.left;
898 var oldHeight = element.style.height;
899 var oldWidth = element.style.width;
900 var oldOpacity = Element.getInlineOpacity(element);
902 var direction = options.direction || 'center';
903 var moveTransition = options.moveTransition || Effect.Transitions.sinoidal;
904 var scaleTransition = options.scaleTransition || Effect.Transitions.sinoidal;
905 var opacityTransition = options.opacityTransition || Effect.Transitions.none;
914 moveX = originalWidth;
919 moveY = originalHeight;
922 moveX = originalWidth;
923 moveY = originalHeight;
926 moveX = originalWidth / 2;
927 moveY = originalHeight / 2;
931 return new Effect.Parallel(
932 [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: opacityTransition }),
933 new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: scaleTransition, restoreAfterFinish: true}),
934 new Effect.MoveBy(element, moveY, moveX, { sync: true, transition: moveTransition })
936 beforeStartInternal: function(effect) {
937 Element.makePositioned(effect.effects[0].element);
938 Element.makeClipping(effect.effects[0].element);
940 afterFinishInternal: function(effect) {
941 var el = effect.effects[0].element;
944 Element.undoClipping(el);
945 Element.undoPositioned(el);
948 els.height = oldHeight;
949 els.width = oldWidth;
950 Element.setInlineOpacity(el, oldOpacity);
956 Effect.Pulsate = function(element) {
957 element = $(element);
958 var options = arguments[1] || {};
959 var oldOpacity = Element.getInlineOpacity(element);
960 var transition = options.transition || Effect.Transitions.sinoidal;
961 var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) };
962 reverser.bind(transition);
963 return new Effect.Opacity(element,
964 Object.extend(Object.extend({ duration: 3.0, from: 0,
965 afterFinishInternal: function(effect) { Element.setInlineOpacity(effect.element, oldOpacity); }
966 }, options), {transition: reverser}));
969 Effect.Fold = function(element) {
970 element = $(element);
971 var originalTop = element.style.top;
972 var originalLeft = element.style.left;
973 var originalWidth = element.style.width;
974 var originalHeight = element.style.height;
975 Element.makeClipping(element);
976 return new Effect.Scale(element, 5, Object.extend({
979 afterFinishInternal: function(effect) {
980 new Effect.Scale(element, 1, {
983 afterFinishInternal: function(effect) {
984 Element.hide(effect.element);
985 Element.undoClipping(effect.element);
986 effect.element.style.top = originalTop;
987 effect.element.style.left = originalLeft;
988 effect.element.style.width = originalWidth;
989 effect.element.style.height = originalHeight;
991 }}, arguments[1] || {}));