5 See <http://mochikit.com/> for documentation, downloads, license, etc.
7 (c) 2005 Bob Ippolito and others. All rights Reserved.
11 if (typeof(dojo
) != 'undefined') {
12 dojo
.provide('MochiKit.Visual');
13 dojo
.require('MochiKit.Base');
14 dojo
.require('MochiKit.DOM');
15 dojo
.require('MochiKit.Style');
16 dojo
.require('MochiKit.Color');
17 dojo
.require('MochiKit.Position');
20 if (typeof(JSAN
) != 'undefined') {
21 JSAN
.use("MochiKit.Base", []);
22 JSAN
.use("MochiKit.DOM", []);
23 JSAN
.use("MochiKit.Style", []);
24 JSAN
.use("MochiKit.Color", []);
25 JSAN
.use("MochiKit.Position", []);
29 if (typeof(MochiKit
.Base
) === 'undefined' ||
30 typeof(MochiKit
.DOM
) === 'undefined' ||
31 typeof(MochiKit
.Style
) === 'undefined' ||
32 typeof(MochiKit
.Position
) === 'undefined' ||
33 typeof(MochiKit
.Color
) === 'undefined') {
37 throw "MochiKit.Visual depends on MochiKit.Base, MochiKit.DOM, MochiKit.Style, MochiKit.Position and MochiKit.Color!";
40 if (typeof(MochiKit
.Visual
) == "undefined") {
44 MochiKit
.Visual
.NAME
= "MochiKit.Visual";
45 MochiKit
.Visual
.VERSION
= "1.4";
47 MochiKit
.Visual
.__repr__
= function () {
48 return "[" + this.NAME
+ " " + this.VERSION
+ "]";
51 MochiKit
.Visual
.toString
= function () {
52 return this.__repr__();
55 MochiKit
.Visual
._RoundCorners
= function (e
, options
) {
56 e
= MochiKit
.DOM
.getElement(e
);
57 this._setOptions(options
);
58 if (this.options
.__unstable__wrapElement
) {
62 var color
= this.options
.color
;
63 var C
= MochiKit
.Color
.Color
;
64 if (this.options
.color
=== "fromElement") {
65 color
= C
.fromBackground(e
);
66 } else if (!(color
instanceof C
)) {
67 color
= C
.fromString(color
);
69 this.isTransparent
= (color
.asRGB().a
<= 0);
71 var bgColor
= this.options
.bgColor
;
72 if (this.options
.bgColor
=== "fromParent") {
73 bgColor
= C
.fromBackground(e
.offsetParent
);
74 } else if (!(bgColor
instanceof C
)) {
75 bgColor
= C
.fromString(bgColor
);
78 this._roundCornersImpl(e
, color
, bgColor
);
81 MochiKit
.Visual
._RoundCorners
.prototype = {
82 _doWrap
: function (e
) {
83 var parent
= e
.parentNode
;
84 var doc
= MochiKit
.DOM
.currentDocument();
85 if (typeof(doc
.defaultView
) === "undefined"
86 || doc
.defaultView
=== null) {
89 var style
= doc
.defaultView
.getComputedStyle(e
, null);
90 if (typeof(style
) === "undefined" || style
=== null) {
93 var wrapper
= MochiKit
.DOM
.DIV({"style": {
95 // convert padding to margin
96 marginTop
: style
.getPropertyValue("padding-top"),
97 marginRight
: style
.getPropertyValue("padding-right"),
98 marginBottom
: style
.getPropertyValue("padding-bottom"),
99 marginLeft
: style
.getPropertyValue("padding-left"),
100 // remove padding so the rounding looks right
107 wrapper
.innerHTML
= e
.innerHTML
;
109 e
.appendChild(wrapper
);
113 _roundCornersImpl
: function (e
, color
, bgColor
) {
114 if (this.options
.border
) {
115 this._renderBorder(e
, bgColor
);
117 if (this._isTopRounded()) {
118 this._roundTopCorners(e
, color
, bgColor
);
120 if (this._isBottomRounded()) {
121 this._roundBottomCorners(e
, color
, bgColor
);
125 _renderBorder
: function (el
, bgColor
) {
126 var borderValue
= "1px solid " + this._borderColor(bgColor
);
127 var borderL
= "border-left: " + borderValue
;
128 var borderR
= "border-right: " + borderValue
;
129 var style
= "style='" + borderL
+ ";" + borderR
+ "'";
130 el
.innerHTML
= "<div " + style
+ ">" + el
.innerHTML
+ "</div>";
133 _roundTopCorners
: function (el
, color
, bgColor
) {
134 var corner
= this._createCorner(bgColor
);
135 for (var i
= 0; i
< this.options
.numSlices
; i
++) {
137 this._createCornerSlice(color
, bgColor
, i
, "top")
140 el
.style
.paddingTop
= 0;
141 el
.insertBefore(corner
, el
.firstChild
);
144 _roundBottomCorners
: function (el
, color
, bgColor
) {
145 var corner
= this._createCorner(bgColor
);
146 for (var i
= (this.options
.numSlices
- 1); i
>= 0; i
--) {
148 this._createCornerSlice(color
, bgColor
, i
, "bottom")
151 el
.style
.paddingBottom
= 0;
152 el
.appendChild(corner
);
155 _createCorner
: function (bgColor
) {
156 var dom
= MochiKit
.DOM
;
157 return dom
.DIV({style
: {backgroundColor
: bgColor
.toString()}});
160 _createCornerSlice
: function (color
, bgColor
, n
, position
) {
161 var slice
= MochiKit
.DOM
.SPAN();
163 var inStyle
= slice
.style
;
164 inStyle
.backgroundColor
= color
.toString();
165 inStyle
.display
= "block";
166 inStyle
.height
= "1px";
167 inStyle
.overflow
= "hidden";
168 inStyle
.fontSize
= "1px";
170 var borderColor
= this._borderColor(color
, bgColor
);
171 if (this.options
.border
&& n
=== 0) {
172 inStyle
.borderTopStyle
= "solid";
173 inStyle
.borderTopWidth
= "1px";
174 inStyle
.borderLeftWidth
= "0px";
175 inStyle
.borderRightWidth
= "0px";
176 inStyle
.borderBottomWidth
= "0px";
177 // assumes css compliant box model
178 inStyle
.height
= "0px";
179 inStyle
.borderColor
= borderColor
.toString();
180 } else if (borderColor
) {
181 inStyle
.borderColor
= borderColor
.toString();
182 inStyle
.borderStyle
= "solid";
183 inStyle
.borderWidth
= "0px 1px";
186 if (!this.options
.compact
&& (n
== (this.options
.numSlices
- 1))) {
187 inStyle
.height
= "2px";
190 this._setMargin(slice
, n
, position
);
191 this._setBorder(slice
, n
, position
);
196 _setOptions
: function (options
) {
199 color
: "fromElement",
200 bgColor
: "fromParent",
204 __unstable__wrapElement
: false
206 MochiKit
.Base
.update(this.options
, options
);
208 this.options
.numSlices
= (this.options
.compact
? 2 : 4);
211 _whichSideTop
: function () {
212 var corners
= this.options
.corners
;
213 if (this._hasString(corners
, "all", "top")) {
217 var has_tl
= (corners
.indexOf("tl") != -1);
218 var has_tr
= (corners
.indexOf("tr") != -1);
219 if (has_tl
&& has_tr
) {
231 _whichSideBottom
: function () {
232 var corners
= this.options
.corners
;
233 if (this._hasString(corners
, "all", "bottom")) {
237 var has_bl
= (corners
.indexOf('bl') != -1);
238 var has_br
= (corners
.indexOf('br') != -1);
239 if (has_bl
&& has_br
) {
251 _borderColor
: function (color
, bgColor
) {
252 if (color
== "transparent") {
254 } else if (this.options
.border
) {
255 return this.options
.border
;
256 } else if (this.options
.blend
) {
257 return bgColor
.blendedColor(color
);
263 _setMargin
: function (el
, n
, corners
) {
264 var marginSize
= this._marginSize(n
) + "px";
266 corners
== "top" ? this._whichSideTop() : this._whichSideBottom()
268 var style
= el
.style
;
270 if (whichSide
== "left") {
271 style
.marginLeft
= marginSize
;
272 style
.marginRight
= "0px";
273 } else if (whichSide
== "right") {
274 style
.marginRight
= marginSize
;
275 style
.marginLeft
= "0px";
277 style
.marginLeft
= marginSize
;
278 style
.marginRight
= marginSize
;
282 _setBorder
: function (el
, n
, corners
) {
283 var borderSize
= this._borderSize(n
) + "px";
285 corners
== "top" ? this._whichSideTop() : this._whichSideBottom()
288 var style
= el
.style
;
289 if (whichSide
== "left") {
290 style
.borderLeftWidth
= borderSize
;
291 style
.borderRightWidth
= "0px";
292 } else if (whichSide
== "right") {
293 style
.borderRightWidth
= borderSize
;
294 style
.borderLeftWidth
= "0px";
296 style
.borderLeftWidth
= borderSize
;
297 style
.borderRightWidth
= borderSize
;
301 _marginSize
: function (n
) {
302 if (this.isTransparent
) {
306 var o
= this.options
;
307 if (o
.compact
&& o
.blend
) {
308 var smBlendedMarginSizes
= [1, 0];
309 return smBlendedMarginSizes
[n
];
310 } else if (o
.compact
) {
311 var compactMarginSizes
= [2, 1];
312 return compactMarginSizes
[n
];
313 } else if (o
.blend
) {
314 var blendedMarginSizes
= [3, 2, 1, 0];
315 return blendedMarginSizes
[n
];
317 var marginSizes
= [5, 3, 2, 1];
318 return marginSizes
[n
];
322 _borderSize
: function (n
) {
323 var o
= this.options
;
325 if (o
.compact
&& (o
.blend
|| this.isTransparent
)) {
327 } else if (o
.compact
) {
328 borderSizes
= [1, 0];
329 } else if (o
.blend
) {
330 borderSizes
= [2, 1, 1, 1];
331 } else if (o
.border
) {
332 borderSizes
= [0, 2, 0, 0];
333 } else if (this.isTransparent
) {
334 borderSizes
= [5, 3, 2, 1];
338 return borderSizes
[n
];
341 _hasString
: function (str
) {
342 for (var i
= 1; i
< arguments
.length
; i
++) {
343 if (str
.indexOf(arguments
[i
]) != -1) {
350 _isTopRounded
: function () {
351 return this._hasString(this.options
.corners
,
352 "all", "top", "tl", "tr"
356 _isBottomRounded
: function () {
357 return this._hasString(this.options
.corners
,
358 "all", "bottom", "bl", "br"
362 _hasSingleTextChild
: function (el
) {
363 return (el
.childNodes
.length
== 1 && el
.childNodes
[0].nodeType
== 3);
367 /** @id MochiKit.Visual.roundElement */
368 MochiKit
.Visual
.roundElement
= function (e
, options
) {
369 new MochiKit
.Visual
._RoundCorners(e
, options
);
372 /** @id MochiKit.Visual.roundClass */
373 MochiKit
.Visual
.roundClass
= function (tagName
, className
, options
) {
374 var elements
= MochiKit
.DOM
.getElementsByTagAndClassName(
377 for (var i
= 0; i
< elements
.length
; i
++) {
378 MochiKit
.Visual
.roundElement(elements
[i
], options
);
382 /** @id MochiKit.Visual.tagifyText */
383 MochiKit
.Visual
.tagifyText
= function (element
, /* optional */tagifyStyle
) {
386 Change a node text to character in tags.
388 @param tagifyStyle: the style to apply to character nodes, default to
389 'position: relative'.
392 tagifyStyle
= tagifyStyle
|| 'position:relative';
393 if (/MSIE/.test(navigator
.userAgent
)) {
394 tagifyStyle
+= ';zoom:1';
396 element
= MochiKit
.DOM
.getElement(element
);
397 var ma
= MochiKit
.Base
.map
;
398 ma(function (child
) {
399 if (child
.nodeType
== 3) {
400 ma(function (character
) {
401 element
.insertBefore(
402 MochiKit
.DOM
.SPAN({style
: tagifyStyle
},
403 character
== ' ' ? String
.fromCharCode(160) : character
), child
);
404 }, child
.nodeValue
.split(''));
405 MochiKit
.DOM
.removeElement(child
);
407 }, element
.childNodes
);
410 /** @id MochiKit.Visual.forceRerendering */
411 MochiKit
.Visual
.forceRerendering
= function (element
) {
413 element
= MochiKit
.DOM
.getElement(element
);
414 var n
= document
.createTextNode(' ');
415 element
.appendChild(n
);
416 element
.removeChild(n
);
421 /** @id MochiKit.Visual.multiple */
422 MochiKit
.Visual
.multiple
= function (elements
, effect
, /* optional */options
) {
425 Launch the same effect subsequently on given elements.
428 options
= MochiKit
.Base
.update({
429 speed
: 0.1, delay
: 0.0
431 var masterDelay
= options
.delay
;
433 MochiKit
.Base
.map(function (innerelement
) {
434 options
.delay
= index
* options
.speed
+ masterDelay
;
435 new effect(innerelement
, options
);
440 MochiKit
.Visual
.PAIRS
= {
441 'slide': ['slideDown', 'slideUp'],
442 'blind': ['blindDown', 'blindUp'],
443 'appear': ['appear', 'fade'],
444 'size': ['grow', 'shrink']
447 /** @id MochiKit.Visual.toggle */
448 MochiKit
.Visual
.toggle
= function (element
, /* optional */effect
, /* optional */options
) {
451 Toggle an item between two state depending of its visibility, making
452 a effect between these states. Default effect is 'appear', can be
456 element
= MochiKit
.DOM
.getElement(element
);
457 effect
= (effect
|| 'appear').toLowerCase();
458 options
= MochiKit
.Base
.update({
459 queue
: {position
: 'end', scope
: (element
.id
|| 'global'), limit
: 1}
461 var v
= MochiKit
.Visual
;
462 v
[element
.style
.display
!= 'none' ?
463 v
.PAIRS
[effect
][1] : v
.PAIRS
[effect
][0]](element
, options
);
468 Transitions: define functions calculating variations depending of a position.
472 MochiKit
.Visual
.Transitions
= {};
474 /** @id MochiKit.Visual.Transitions.linear */
475 MochiKit
.Visual
.Transitions
.linear
= function (pos
) {
479 /** @id MochiKit.Visual.Transitions.sinoidal */
480 MochiKit
.Visual
.Transitions
.sinoidal
= function (pos
) {
481 return (-Math
.cos(pos
*Math
.PI
)/2) + 0.5;
484 /** @id MochiKit.Visual.Transitions.reverse */
485 MochiKit
.Visual
.Transitions
.reverse
= function (pos
) {
489 /** @id MochiKit.Visual.Transitions.flicker */
490 MochiKit
.Visual
.Transitions
.flicker
= function (pos
) {
491 return ((-Math
.cos(pos
*Math
.PI
)/4) + 0.75) + Math.random()/4;
494 /** @id MochiKit.Visual.Transitions.wobble */
495 MochiKit
.Visual
.Transitions
.wobble
= function (pos
) {
496 return (-Math
.cos(pos
*Math
.PI
*(9*pos
))/2) + 0.5;
499 /** @id MochiKit.Visual.Transitions.pulse */
500 MochiKit
.Visual
.Transitions
.pulse
= function (pos
, pulses
) {
502 return (Math
.floor(pos
*10) % 2 === 0 ?
503 (pos
*10 - Math
.floor(pos
*10)) : 1 - (pos
*10 - Math
.floor(pos
*10)));
505 return (Math
.round((pos
% (1/pulses
)) * pulses
) == 0 ?
506 ((pos
* pulses
* 2) - Math
.floor(pos
* pulses
* 2)) :
507 1 - ((pos
* pulses
* 2) - Math
.floor(pos
* pulses
* 2)));
510 /** @id MochiKit.Visual.Transitions.none */
511 MochiKit
.Visual
.Transitions
.none
= function (pos
) {
515 /** @id MochiKit.Visual.Transitions.full */
516 MochiKit
.Visual
.Transitions
.full
= function (pos
) {
526 MochiKit
.Visual
.ScopedQueue
= function () {
527 var cls
= arguments
.callee
;
528 if (!(this instanceof cls
)) {
534 MochiKit
.Base
.update(MochiKit
.Visual
.ScopedQueue
.prototype, {
535 __init__
: function () {
537 this.interval
= null;
540 /** @id MochiKit.Visual.ScopedQueue.prototype.add */
541 add
: function (effect
) {
542 var timestamp
= new Date().getTime();
544 var position
= (typeof(effect
.options
.queue
) == 'string') ?
545 effect
.options
.queue
: effect
.options
.queue
.position
;
547 var ma
= MochiKit
.Base
.map
;
550 // move unstarted effects after this effect
552 if (e
.state
== 'idle') {
553 e
.startOn
+= effect
.finishOn
;
554 e
.finishOn
+= effect
.finishOn
;
560 // start effect after last queued effect has finished
563 if (i
>= (finish
|| i
)) {
567 timestamp
= finish
|| timestamp
;
576 effect
.startOn
+= timestamp
;
577 effect
.finishOn
+= timestamp
;
578 if (!effect
.options
.queue
.limit
||
579 this.effects
.length
< effect
.options
.queue
.limit
) {
580 this.effects
.push(effect
);
583 if (!this.interval
) {
584 this.interval
= this.startLoop(MochiKit
.Base
.bind(this.loop
, this),
589 /** @id MochiKit.Visual.ScopedQueue.prototype.startLoop */
590 startLoop
: function (func
, interval
) {
591 return setInterval(func
, interval
);
594 /** @id MochiKit.Visual.ScopedQueue.prototype.remove */
595 remove
: function (effect
) {
596 this.effects
= MochiKit
.Base
.filter(function (e
) {
599 if (!this.effects
.length
) {
600 this.stopLoop(this.interval
);
601 this.interval
= null;
605 /** @id MochiKit.Visual.ScopedQueue.prototype.stopLoop */
606 stopLoop
: function (interval
) {
607 clearInterval(interval
);
610 /** @id MochiKit.Visual.ScopedQueue.prototype.loop */
612 var timePos
= new Date().getTime();
613 MochiKit
.Base
.map(function (effect
) {
614 effect
.loop(timePos
);
619 MochiKit
.Visual
.Queues
= {
622 get
: function (queueName
) {
623 if (typeof(queueName
) != 'string') {
627 if (!this.instances
[queueName
]) {
628 this.instances
[queueName
] = new MochiKit
.Visual
.ScopedQueue();
630 return this.instances
[queueName
];
634 MochiKit
.Visual
.Queue
= MochiKit
.Visual
.Queues
.get('global');
636 MochiKit
.Visual
.DefaultOptions
= {
637 transition
: MochiKit
.Visual
.Transitions
.sinoidal
,
638 duration
: 1.0, // seconds
639 fps
: 25.0, // max. 25fps due to MochiKit.Visual.Queue implementation
640 sync
: false, // true for combining
647 MochiKit
.Visual
.Base
= function () {};
649 MochiKit
.Visual
.Base
.prototype = {
652 Basic class for all Effects. Define a looping mechanism called for each step
653 of an effect. Don't instantiate it, only subclass it.
657 __class__
: MochiKit
.Visual
.Base
,
659 /** @id MochiKit.Visual.Base.prototype.start */
660 start
: function (options
) {
661 var v
= MochiKit
.Visual
;
662 this.options
= MochiKit
.Base
.setdefault(options
|| {},
664 this.currentFrame
= 0;
666 this.startOn
= this.options
.delay
*1000;
667 this.finishOn
= this.startOn
+ (this.options
.duration
*1000);
668 this.event('beforeStart');
669 if (!this.options
.sync
) {
670 v
.Queues
.get(typeof(this.options
.queue
) == 'string' ?
671 'global' : this.options
.queue
.scope
).add(this);
675 /** @id MochiKit.Visual.Base.prototype.loop */
676 loop
: function (timePos
) {
677 if (timePos
>= this.startOn
) {
678 if (timePos
>= this.finishOn
) {
679 return this.finalize();
681 var pos
= (timePos
- this.startOn
) / (this.finishOn
- this.startOn
);
683 Math
.round(pos
* this.options
.fps
* this.options
.duration
);
684 if (frame
> this.currentFrame
) {
686 this.currentFrame
= frame
;
691 /** @id MochiKit.Visual.Base.prototype.render */
692 render
: function (pos
) {
693 if (this.state
== 'idle') {
694 this.state
= 'running';
695 this.event('beforeSetup');
697 this.event('afterSetup');
699 if (this.state
== 'running') {
700 if (this.options
.transition
) {
701 pos
= this.options
.transition(pos
);
703 pos
*= (this.options
.to
- this.options
.from
);
704 pos
+= this.options
.from
;
705 this.event('beforeUpdate');
707 this.event('afterUpdate');
711 /** @id MochiKit.Visual.Base.prototype.cancel */
712 cancel
: function () {
713 if (!this.options
.sync
) {
714 MochiKit
.Visual
.Queues
.get(typeof(this.options
.queue
) == 'string' ?
715 'global' : this.options
.queue
.scope
).remove(this);
717 this.state
= 'finished';
720 /** @id MochiKit.Visual.Base.prototype.finalize */
721 finalize
: function () {
724 this.event('beforeFinish');
726 this.event('afterFinish');
732 finish
: function () {
735 update
: function (position
) {
738 /** @id MochiKit.Visual.Base.prototype.event */
739 event
: function (eventName
) {
740 if (this.options
[eventName
+ 'Internal']) {
741 this.options
[eventName
+ 'Internal'](this);
743 if (this.options
[eventName
]) {
744 this.options
[eventName
](this);
748 /** @id MochiKit.Visual.Base.prototype.repr */
750 return '[' + this.__class__
.NAME
+ ', options:' +
751 MochiKit
.Base
.repr(this.options
) + ']';
755 /** @id MochiKit.Visual.Parallel */
756 MochiKit
.Visual
.Parallel
= function (effects
, options
) {
757 var cls
= arguments
.callee
;
758 if (!(this instanceof cls
)) {
759 return new cls(effects
, options
);
762 this.__init__(effects
, options
);
765 MochiKit
.Visual
.Parallel
.prototype = new MochiKit
.Visual
.Base();
767 MochiKit
.Base
.update(MochiKit
.Visual
.Parallel
.prototype, {
770 Run multiple effects at the same time.
774 __class__
: MochiKit
.Visual
.Parallel
,
776 __init__
: function (effects
, options
) {
777 this.effects
= effects
|| [];
781 /** @id MochiKit.Visual.Parallel.prototype.update */
782 update
: function (position
) {
783 MochiKit
.Base
.map(function (effect
) {
784 effect
.render(position
);
788 /** @id MochiKit.Visual.Parallel.prototype.finish */
789 finish
: function () {
790 MochiKit
.Base
.map(function (effect
) {
796 /** @id MochiKit.Visual.Opacity */
797 MochiKit
.Visual
.Opacity
= function (element
, options
) {
798 var cls
= arguments
.callee
;
799 if (!(this instanceof cls
)) {
800 return new cls(element
, options
);
802 this.__init__(element
, options
);
805 MochiKit
.Visual
.Opacity
.prototype = new MochiKit
.Visual
.Base();
807 MochiKit
.Base
.update(MochiKit
.Visual
.Opacity
.prototype, {
810 Change the opacity of an element.
812 @param options: 'from' and 'to' change the starting and ending opacities.
813 Must be between 0.0 and 1.0. Default to current opacity and 1.0.
817 __class__
: MochiKit
.Visual
.Opacity
,
819 __init__
: function (element
, /* optional */options
) {
820 var b
= MochiKit
.Base
;
821 var s
= MochiKit
.Style
;
822 this.element
= MochiKit
.DOM
.getElement(element
);
823 // make this work on IE on elements without 'layout'
824 if (this.element
.currentStyle
&&
825 (!this.element
.currentStyle
.hasLayout
)) {
826 s
.setStyle(this.element
, {zoom
: 1});
829 from
: s
.getStyle(this.element
, 'opacity') || 0.0,
835 /** @id MochiKit.Visual.Opacity.prototype.update */
836 update
: function (position
) {
837 MochiKit
.Style
.setStyle(this.element
, {'opacity': position
});
841 /** @id MochiKit.Visual.Move.prototype */
842 MochiKit
.Visual
.Move
= function (element
, options
) {
843 var cls
= arguments
.callee
;
844 if (!(this instanceof cls
)) {
845 return new cls(element
, options
);
847 this.__init__(element
, options
);
850 MochiKit
.Visual
.Move
.prototype = new MochiKit
.Visual
.Base();
852 MochiKit
.Base
.update(MochiKit
.Visual
.Move
.prototype, {
855 Move an element between its current position to a defined position
857 @param options: 'x' and 'y' for final positions, default to 0, 0.
861 __class__
: MochiKit
.Visual
.Move
,
863 __init__
: function (element
, /* optional */options
) {
864 this.element
= MochiKit
.DOM
.getElement(element
);
865 options
= MochiKit
.Base
.update({
873 /** @id MochiKit.Visual.Move.prototype.setup */
875 // Bug in Opera: Opera returns the 'real' position of a static element
876 // or relative element that does not have top/left explicitly set
.
877 // ==> Always set top and left for position relative elements in your
878 // stylesheets (to 0 if you do not need them)
879 MochiKit
.DOM
.makePositioned(this.element
);
881 var s
= this.element
.style
;
882 var originalVisibility
= s
.visibility
;
883 var originalDisplay
= s
.display
;
884 if (originalDisplay
== 'none') {
885 s
.visibility
= 'hidden';
889 this.originalLeft
= parseFloat(MochiKit
.Style
.getStyle(this.element
, 'left') || '0');
890 this.originalTop
= parseFloat(MochiKit
.Style
.getStyle(this.element
, 'top') || '0');
892 if (this.options
.mode
== 'absolute') {
893 // absolute movement, so we need to calc deltaX and deltaY
894 this.options
.x
-= this.originalLeft
;
895 this.options
.y
-= this.originalTop
;
897 if (originalDisplay
== 'none') {
898 s
.visibility
= originalVisibility
;
899 s
.display
= originalDisplay
;
903 /** @id MochiKit.Visual.Move.prototype.update */
904 update
: function (position
) {
905 MochiKit
.Style
.setStyle(this.element
, {
906 left
: Math
.round(this.options
.x
* position
+ this.originalLeft
) + 'px',
907 top
: Math
.round(this.options
.y
* position
+ this.originalTop
) + 'px'
912 /** @id MochiKit.Visual.Scale */
913 MochiKit
.Visual
.Scale
= function (element
, percent
, options
) {
914 var cls
= arguments
.callee
;
915 if (!(this instanceof cls
)) {
916 return new cls(element
, percent
, options
);
918 this.__init__(element
, percent
, options
);
921 MochiKit
.Visual
.Scale
.prototype = new MochiKit
.Visual
.Base();
923 MochiKit
.Base
.update(MochiKit
.Visual
.Scale
.prototype, {
926 Change the size of an element.
928 @param percent: final_size = percent*original_size
930 @param options: several options changing scale behaviour
934 __class__
: MochiKit
.Visual
.Scale
,
936 __init__
: function (element
, percent
, /* optional */options
) {
937 this.element
= MochiKit
.DOM
.getElement(element
);
938 options
= MochiKit
.Base
.update({
942 scaleFromCenter
: false,
943 scaleMode
: 'box', // 'box' or 'contents' or {} with provided values
950 /** @id MochiKit.Visual.Scale.prototype.setup */
952 this.restoreAfterFinish
= this.options
.restoreAfterFinish
|| false;
953 this.elementPositioning
= MochiKit
.Style
.getStyle(this.element
,
956 var ma
= MochiKit
.Base
.map
;
957 var b
= MochiKit
.Base
.bind
;
958 this.originalStyle
= {};
960 this.originalStyle
[k
] = this.element
.style
[k
];
961 }, this), ['top', 'left', 'width', 'height', 'fontSize']);
963 this.originalTop
= this.element
.offsetTop
;
964 this.originalLeft
= this.element
.offsetLeft
;
966 var fontSize
= MochiKit
.Style
.getStyle(this.element
,
967 'font-size') || '100%';
968 ma(b(function (fontSizeType
) {
969 if (fontSize
.indexOf(fontSizeType
) > 0) {
970 this.fontSize
= parseFloat(fontSize
);
971 this.fontSizeType
= fontSizeType
;
973 }, this), ['em', 'px', '%']);
975 this.factor
= (this.options
.scaleTo
- this.options
.scaleFrom
)/100;
977 if (/^content/.test(this.options
.scaleMode
)) {
978 this.dims
= [this.element
.scrollHeight
, this.element
.scrollWidth
];
979 } else if (this.options
.scaleMode
== 'box') {
980 this.dims
= [this.element
.offsetHeight
, this.element
.offsetWidth
];
982 this.dims
= [this.options
.scaleMode
.originalHeight
,
983 this.options
.scaleMode
.originalWidth
];
987 /** @id MochiKit.Visual.Scale.prototype.update */
988 update
: function (position
) {
989 var currentScale
= (this.options
.scaleFrom
/100.0) +
990 (this.factor
* position
);
991 if (this.options
.scaleContent
&& this.fontSize
) {
992 MochiKit
.Style
.setStyle(this.element
, {
993 fontSize
: this.fontSize
* currentScale
+ this.fontSizeType
996 this.setDimensions(this.dims
[0] * currentScale
,
997 this.dims
[1] * currentScale
);
1000 /** @id MochiKit.Visual.Scale.prototype.finish */
1001 finish
: function () {
1002 if (this.restoreAfterFinish
) {
1003 MochiKit
.Style
.setStyle(this.element
, this.originalStyle
);
1007 /** @id MochiKit.Visual.Scale.prototype.setDimensions */
1008 setDimensions
: function (height
, width
) {
1011 if (/MSIE/.test(navigator
.userAgent
)) {
1014 if (this.options
.scaleX
) {
1015 d
.width
= r(width
) + 'px';
1017 if (this.options
.scaleY
) {
1018 d
.height
= r(height
) + 'px';
1020 if (this.options
.scaleFromCenter
) {
1021 var topd
= (height
- this.dims
[0])/2;
1022 var leftd
= (width
- this.dims
[1])/2;
1023 if (this.elementPositioning
== 'absolute') {
1024 if (this.options
.scaleY
) {
1025 d
.top
= this.originalTop
- topd
+ 'px';
1027 if (this.options
.scaleX
) {
1028 d
.left
= this.originalLeft
- leftd
+ 'px';
1031 if (this.options
.scaleY
) {
1032 d
.top
= -topd
+ 'px';
1034 if (this.options
.scaleX
) {
1035 d
.left
= -leftd
+ 'px';
1039 MochiKit
.Style
.setStyle(this.element
, d
);
1043 /** @id MochiKit.Visual.Highlight */
1044 MochiKit
.Visual
.Highlight
= function (element
, options
) {
1045 var cls
= arguments
.callee
;
1046 if (!(this instanceof cls
)) {
1047 return new cls(element
, options
);
1049 this.__init__(element
, options
);
1052 MochiKit
.Visual
.Highlight
.prototype = new MochiKit
.Visual
.Base();
1054 MochiKit
.Base
.update(MochiKit
.Visual
.Highlight
.prototype, {
1057 Highlight an item of the page.
1059 @param options: 'startcolor' for choosing highlighting color, default
1064 __class__
: MochiKit
.Visual
.Highlight
,
1066 __init__
: function (element
, /* optional */options
) {
1067 this.element
= MochiKit
.DOM
.getElement(element
);
1068 options
= MochiKit
.Base
.update({
1069 startcolor
: '#ffff99'
1071 this.start(options
);
1074 /** @id MochiKit.Visual.Highlight.prototype.setup */
1075 setup
: function () {
1076 var b
= MochiKit
.Base
;
1077 var s
= MochiKit
.Style
;
1078 // Prevent executing on elements not in the layout flow
1079 if (s
.getStyle(this.element
, 'display') == 'none') {
1083 // Disable background image during the effect
1085 backgroundImage
: s
.getStyle(this.element
, 'background-image')
1087 s
.setStyle(this.element
, {
1088 backgroundImage
: 'none'
1091 if (!this.options
.endcolor
) {
1092 this.options
.endcolor
=
1093 MochiKit
.Color
.Color
.fromBackground(this.element
).toHexString();
1095 if (b
.isUndefinedOrNull(this.options
.restorecolor
)) {
1096 this.options
.restorecolor
= s
.getStyle(this.element
,
1097 'background-color');
1099 // init color calculations
1100 this._base
= b
.map(b
.bind(function (i
) {
1102 this.options
.startcolor
.slice(i
*2 + 1, i
*2 + 3), 16);
1103 }, this), [0, 1, 2]);
1104 this._delta
= b
.map(b
.bind(function (i
) {
1105 return parseInt(this.options
.endcolor
.slice(i
*2 + 1, i
*2 + 3), 16)
1107 }, this), [0, 1, 2]);
1110 /** @id MochiKit.Visual.Highlight.prototype.update */
1111 update
: function (position
) {
1113 MochiKit
.Base
.map(MochiKit
.Base
.bind(function (i
) {
1114 m
+= MochiKit
.Color
.toColorPart(Math
.round(this._base
[i
] +
1115 this._delta
[i
]*position
));
1116 }, this), [0, 1, 2]);
1117 MochiKit
.Style
.setStyle(this.element
, {
1122 /** @id MochiKit.Visual.Highlight.prototype.finish */
1123 finish
: function () {
1124 MochiKit
.Style
.setStyle(this.element
,
1125 MochiKit
.Base
.update(this.oldStyle
, {
1126 backgroundColor
: this.options
.restorecolor
1131 /** @id MochiKit.Visual.ScrollTo */
1132 MochiKit
.Visual
.ScrollTo
= function (element
, options
) {
1133 var cls
= arguments
.callee
;
1134 if (!(this instanceof cls
)) {
1135 return new cls(element
, options
);
1137 this.__init__(element
, options
);
1140 MochiKit
.Visual
.ScrollTo
.prototype = new MochiKit
.Visual
.Base();
1142 MochiKit
.Base
.update(MochiKit
.Visual
.ScrollTo
.prototype, {
1145 Scroll to an element in the page.
1149 __class__
: MochiKit
.Visual
.ScrollTo
,
1151 __init__
: function (element
, /* optional */options
) {
1152 this.element
= MochiKit
.DOM
.getElement(element
);
1153 this.start(options
|| {});
1156 /** @id MochiKit.Visual.ScrollTo.prototype.setup */
1157 setup
: function () {
1158 var p
= MochiKit
.Position
;
1160 var offsets
= p
.cumulativeOffset(this.element
);
1161 if (this.options
.offset
) {
1162 offsets
.y
+= this.options
.offset
;
1165 if (window
.innerHeight
) {
1166 max
= window
.innerHeight
- window
.height
;
1167 } else if (document
.documentElement
&&
1168 document
.documentElement
.clientHeight
) {
1169 max
= document
.documentElement
.clientHeight
-
1170 document
.body
.scrollHeight
;
1171 } else if (document
.body
) {
1172 max
= document
.body
.clientHeight
- document
.body
.scrollHeight
;
1174 this.scrollStart
= p
.windowOffset
.y
;
1175 this.delta
= (offsets
.y
> max
? max
: offsets
.y
) - this.scrollStart
;
1178 /** @id MochiKit.Visual.ScrollTo.prototype.update */
1179 update
: function (position
) {
1180 var p
= MochiKit
.Position
;
1182 window
.scrollTo(p
.windowOffset
.x
, this.scrollStart
+ (position
* this.delta
));
1186 MochiKit
.Visual
.CSS_LENGTH
= /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
1188 MochiKit
.Visual
.Morph
= function (element
, options
) {
1189 var cls
= arguments
.callee
;
1190 if (!(this instanceof cls
)) {
1191 return new cls(element
, options
);
1193 this.__init__(element
, options
);
1196 MochiKit
.Visual
.Morph
.prototype = new MochiKit
.Visual
.Base();
1198 MochiKit
.Base
.update(MochiKit
.Visual
.Morph
.prototype, {
1201 Morph effect: make a transformation from current style to the given style,
1202 automatically making a transition between the two.
1206 __class__
: MochiKit
.Visual
.Morph
,
1208 __init__
: function (element
, /* optional */options
) {
1209 this.element
= MochiKit
.DOM
.getElement(element
);
1210 this.start(options
|| {});
1213 /** @id MochiKit.Visual.Morph.prototype.setup */
1214 setup
: function () {
1215 var b
= MochiKit
.Base
;
1216 var style
= this.options
.style
;
1217 this.styleStart
= {};
1221 for (var s
in style
) {
1224 if (MochiKit
.Visual
.CSS_LENGTH
.test(value
)) {
1225 var components
= value
.match(/^([\+\-]?[0-9\.]+)(.*)$/);
1226 value
= parseFloat(components
[1]);
1227 unit
= (components
.length
== 3) ? components
[2] : null;
1228 this.styleEnd
[s
] = value
;
1229 this.units
[s
] = unit
;
1230 value
= MochiKit
.Style
.getStyle(this.element
, s
);
1231 components
= value
.match(/^([\+\-]?[0-9\.]+)(.*)$/);
1232 value
= parseFloat(components
[1]);
1233 this.styleStart
[s
] = value
;
1235 var c
= MochiKit
.Color
.Color
;
1236 value
= c
.fromString(value
);
1238 this.units
[s
] = "color";
1239 this.styleEnd
[s
] = value
.toHexString();
1240 value
= MochiKit
.Style
.getStyle(this.element
, s
);
1241 this.styleStart
[s
] = c
.fromString(value
).toHexString();
1243 this.styleStart
[s
] = b
.map(b
.bind(function (i
) {
1245 this.styleStart
[s
].slice(i
*2 + 1, i
*2 + 3), 16);
1246 }, this), [0, 1, 2]);
1247 this.styleEnd
[s
] = b
.map(b
.bind(function (i
) {
1249 this.styleEnd
[s
].slice(i
*2 + 1, i
*2 + 3), 16);
1250 }, this), [0, 1, 2]);
1256 /** @id MochiKit.Visual.Morph.prototype.update */
1257 update
: function (position
) {
1259 for (var s
in this.styleStart
) {
1260 if (this.units
[s
] == "color") {
1262 var start
= this.styleStart
[s
];
1263 var end
= this.styleEnd
[s
];
1264 MochiKit
.Base
.map(MochiKit
.Base
.bind(function (i
) {
1265 m
+= MochiKit
.Color
.toColorPart(Math
.round(start
[i
] +
1266 (end
[i
] - start
[i
])*position
));
1267 }, this), [0, 1, 2]);
1268 this.element
.style
[s
] = m
;
1270 value
= this.styleStart
[s
] + Math
.round((this.styleEnd
[s
] - this.styleStart
[s
]) * position
* 1000) / 1000 + this.units
[s
];
1271 this.element
.style
[s
] = value
;
1279 Combination effects.
1283 /** @id MochiKit.Visual.fade */
1284 MochiKit
.Visual
.fade
= function (element
, /* optional */ options
) {
1287 Fade a given element: change its opacity and hide it in the end.
1289 @param options: 'to' and 'from' to change opacity.
1292 var s
= MochiKit
.Style
;
1293 var oldOpacity
= s
.getStyle(element
, 'opacity');
1294 options
= MochiKit
.Base
.update({
1295 from
: s
.getStyle(element
, 'opacity') || 1.0,
1297 afterFinishInternal
: function (effect
) {
1298 if (effect
.options
.to
!== 0) {
1301 s
.hideElement(effect
.element
);
1302 s
.setStyle(effect
.element
, {'opacity': oldOpacity
});
1305 return new MochiKit
.Visual
.Opacity(element
, options
);
1308 /** @id MochiKit.Visual.appear */
1309 MochiKit
.Visual
.appear
= function (element
, /* optional */ options
) {
1312 Make an element appear.
1314 @param options: 'to' and 'from' to change opacity.
1317 var s
= MochiKit
.Style
;
1318 var v
= MochiKit
.Visual
;
1319 options
= MochiKit
.Base
.update({
1320 from
: (s
.getStyle(element
, 'display') == 'none' ? 0.0 :
1321 s
.getStyle(element
, 'opacity') || 0.0),
1323 // force Safari to render floated elements properly
1324 afterFinishInternal
: function (effect
) {
1325 v
.forceRerendering(effect
.element
);
1327 beforeSetupInternal
: function (effect
) {
1328 s
.setStyle(effect
.element
, {'opacity': effect
.options
.from
});
1329 s
.showElement(effect
.element
);
1332 return new v
.Opacity(element
, options
);
1335 /** @id MochiKit.Visual.puff */
1336 MochiKit
.Visual
.puff
= function (element
, /* optional */ options
) {
1339 'Puff' an element: grow it to double size, fading it and make it hidden.
1342 var s
= MochiKit
.Style
;
1343 var v
= MochiKit
.Visual
;
1344 element
= MochiKit
.DOM
.getElement(element
);
1346 position
: s
.getStyle(element
, 'position'),
1347 top
: element
.style
.top
,
1348 left
: element
.style
.left
,
1349 width
: element
.style
.width
,
1350 height
: element
.style
.height
,
1351 opacity
: s
.getStyle(element
, 'opacity')
1353 options
= MochiKit
.Base
.update({
1354 beforeSetupInternal
: function (effect
) {
1355 MochiKit
.Position
.absolutize(effect
.effects
[0].element
);
1357 afterFinishInternal
: function (effect
) {
1358 s
.hideElement(effect
.effects
[0].element
);
1359 s
.setStyle(effect
.effects
[0].element
, oldStyle
);
1362 scaleFromCenter
: true
1364 return new v
.Parallel(
1365 [new v
.Scale(element
, 200,
1366 {sync
: true, scaleFromCenter
: options
.scaleFromCenter
,
1367 scaleContent
: options
.scaleContent
, restoreAfterFinish
: true}),
1368 new v
.Opacity(element
, {sync
: true, to
: 0.0 })],
1372 /** @id MochiKit.Visual.blindUp */
1373 MochiKit
.Visual
.blindUp
= function (element
, /* optional */ options
) {
1376 Blind an element up: change its vertical size to 0.
1379 var d
= MochiKit
.DOM
;
1380 element
= d
.getElement(element
);
1381 var elemClip
= d
.makeClipping(element
);
1382 options
= MochiKit
.Base
.update({
1383 scaleContent
: false,
1385 restoreAfterFinish
: true,
1386 afterFinishInternal
: function (effect
) {
1387 MochiKit
.Style
.hideElement(effect
.element
);
1388 d
.undoClipping(effect
.element
, elemClip
);
1392 return new MochiKit
.Visual
.Scale(element
, 0, options
);
1395 /** @id MochiKit.Visual.blindDown */
1396 MochiKit
.Visual
.blindDown
= function (element
, /* optional */ options
) {
1399 Blind an element down: restore its vertical size.
1402 var d
= MochiKit
.DOM
;
1403 var s
= MochiKit
.Style
;
1404 element
= d
.getElement(element
);
1405 var elementDimensions
= s
.getElementDimensions(element
);
1407 options
= MochiKit
.Base
.update({
1408 scaleContent
: false,
1411 scaleMode
: {originalHeight
: elementDimensions
.h
,
1412 originalWidth
: elementDimensions
.w
},
1413 restoreAfterFinish
: true,
1414 afterSetupInternal
: function (effect
) {
1415 elemClip
= d
.makeClipping(effect
.element
);
1416 s
.setStyle(effect
.element
, {height
: '0px'});
1417 s
.showElement(effect
.element
);
1419 afterFinishInternal
: function (effect
) {
1420 d
.undoClipping(effect
.element
, elemClip
);
1423 return new MochiKit
.Visual
.Scale(element
, 100, options
);
1426 /** @id MochiKit.Visual.switchOff */
1427 MochiKit
.Visual
.switchOff
= function (element
, /* optional */ options
) {
1430 Apply a switch-off-like effect.
1433 var d
= MochiKit
.DOM
;
1434 element
= d
.getElement(element
);
1435 var oldOpacity
= MochiKit
.Style
.getStyle(element
, 'opacity');
1437 options
= MochiKit
.Base
.update({
1439 scaleFromCenter
: true,
1441 scaleContent
: false,
1442 restoreAfterFinish
: true,
1443 beforeSetupInternal
: function (effect
) {
1444 d
.makePositioned(effect
.element
);
1445 elemClip
= d
.makeClipping(effect
.element
);
1447 afterFinishInternal
: function (effect
) {
1448 MochiKit
.Style
.hideElement(effect
.element
);
1449 d
.undoClipping(effect
.element
, elemClip
);
1450 d
.undoPositioned(effect
.element
);
1451 MochiKit
.Style
.setStyle(effect
.element
, {'opacity': oldOpacity
});
1454 var v
= MochiKit
.Visual
;
1455 return new v
.appear(element
, {
1458 transition
: v
.Transitions
.flicker
,
1459 afterFinishInternal
: function (effect
) {
1460 new v
.Scale(effect
.element
, 1, options
);
1465 /** @id MochiKit.Visual.dropOut */
1466 MochiKit
.Visual
.dropOut
= function (element
, /* optional */ options
) {
1469 Make an element fall and disappear.
1472 var d
= MochiKit
.DOM
;
1473 var s
= MochiKit
.Style
;
1474 element
= d
.getElement(element
);
1476 top
: s
.getStyle(element
, 'top'),
1477 left
: s
.getStyle(element
, 'left'),
1478 opacity
: s
.getStyle(element
, 'opacity')
1481 options
= MochiKit
.Base
.update({
1484 beforeSetupInternal
: function (effect
) {
1485 d
.makePositioned(effect
.effects
[0].element
);
1487 afterFinishInternal
: function (effect
) {
1488 s
.hideElement(effect
.effects
[0].element
);
1489 d
.undoPositioned(effect
.effects
[0].element
);
1490 s
.setStyle(effect
.effects
[0].element
, oldStyle
);
1493 var v
= MochiKit
.Visual
;
1494 return new v
.Parallel(
1495 [new v
.Move(element
, {x
: 0, y
: options
.distance
, sync
: true}),
1496 new v
.Opacity(element
, {sync
: true, to
: 0.0})],
1500 /** @id MochiKit.Visual.shake */
1501 MochiKit
.Visual
.shake
= function (element
, /* optional */ options
) {
1504 Move an element from left to right several times.
1507 var d
= MochiKit
.DOM
;
1508 var v
= MochiKit
.Visual
;
1509 var s
= MochiKit
.Style
;
1510 element
= d
.getElement(element
);
1511 options
= MochiKit
.Base
.update({
1515 afterFinishInternal
: function (effect
) {
1516 d
.undoPositioned(effect
.element
);
1517 s
.setStyle(effect
.element
, oldStyle
);
1521 top
: s
.getStyle(element
, 'top'),
1522 left
: s
.getStyle(element
, 'left') };
1523 return new v
.Move(element
,
1524 {x
: 20, y
: 0, duration
: 0.05, afterFinishInternal
: function (effect
) {
1525 new v
.Move(effect
.element
,
1526 {x
: -40, y
: 0, duration
: 0.1, afterFinishInternal
: function (effect
) {
1527 new v
.Move(effect
.element
,
1528 {x
: 40, y
: 0, duration
: 0.1, afterFinishInternal
: function (effect
) {
1529 new v
.Move(effect
.element
,
1530 {x
: -40, y
: 0, duration
: 0.1, afterFinishInternal
: function (effect
) {
1531 new v
.Move(effect
.element
,
1532 {x
: 40, y
: 0, duration
: 0.1, afterFinishInternal
: function (effect
) {
1533 new v
.Move(effect
.element
, options
1534 ) }}) }}) }}) }}) }});
1537 /** @id MochiKit.Visual.slideDown */
1538 MochiKit
.Visual
.slideDown
= function (element
, /* optional */ options
) {
1541 Slide an element down.
1542 It needs to have the content of the element wrapped in a container
1543 element with fixed height.
1546 var d
= MochiKit
.DOM
;
1547 var b
= MochiKit
.Base
;
1548 var s
= MochiKit
.Style
;
1549 element
= d
.getElement(element
);
1550 if (!element
.firstChild
) {
1551 throw "MochiKit.Visual.slideDown must be used on a element with a child";
1553 d
.removeEmptyTextNodes(element
);
1554 var oldInnerBottom
= s
.getStyle(element
.firstChild
, 'bottom') || 0;
1555 var elementDimensions
= s
.getElementDimensions(element
);
1557 options
= b
.update({
1558 scaleContent
: false,
1561 scaleMode
: {originalHeight
: elementDimensions
.h
,
1562 originalWidth
: elementDimensions
.w
},
1563 restoreAfterFinish
: true,
1564 afterSetupInternal
: function (effect
) {
1565 d
.makePositioned(effect
.element
);
1566 d
.makePositioned(effect
.element
.firstChild
);
1567 if (/Opera/.test(navigator
.userAgent
)) {
1568 s
.setStyle(effect
.element
, {top
: ''});
1570 elemClip
= d
.makeClipping(effect
.element
);
1571 s
.setStyle(effect
.element
, {height
: '0px'});
1572 s
.showElement(effect
.element
);
1574 afterUpdateInternal
: function (effect
) {
1575 s
.setStyle(effect
.element
.firstChild
,
1576 {bottom
: (effect
.dims
[0] - effect
.element
.clientHeight
) + 'px'});
1578 afterFinishInternal
: function (effect
) {
1579 d
.undoClipping(effect
.element
, elemClip
);
1580 // IE will crash if child is undoPositioned first
1581 if (/MSIE/.test(navigator
.userAgent
)) {
1582 d
.undoPositioned(effect
.element
);
1583 d
.undoPositioned(effect
.element
.firstChild
);
1585 d
.undoPositioned(effect
.element
.firstChild
);
1586 d
.undoPositioned(effect
.element
);
1588 s
.setStyle(effect
.element
.firstChild
,
1589 {bottom
: oldInnerBottom
});
1593 return new MochiKit
.Visual
.Scale(element
, 100, options
);
1596 /** @id MochiKit.Visual.slideUp */
1597 MochiKit
.Visual
.slideUp
= function (element
, /* optional */ options
) {
1600 Slide an element up.
1601 It needs to have the content of the element wrapped in a container
1602 element with fixed height.
1605 var d
= MochiKit
.DOM
;
1606 var b
= MochiKit
.Base
;
1607 var s
= MochiKit
.Style
;
1608 element
= d
.getElement(element
);
1609 if (!element
.firstChild
) {
1610 throw "MochiKit.Visual.slideUp must be used on a element with a child";
1612 d
.removeEmptyTextNodes(element
);
1613 var oldInnerBottom
= s
.getStyle(element
.firstChild
, 'bottom');
1615 options
= b
.update({
1616 scaleContent
: false,
1620 restoreAfterFinish
: true,
1621 beforeStartInternal
: function (effect
) {
1622 d
.makePositioned(effect
.element
);
1623 d
.makePositioned(effect
.element
.firstChild
);
1624 if (/Opera/.test(navigator
.userAgent
)) {
1625 s
.setStyle(effect
.element
, {top
: ''});
1627 elemClip
= d
.makeClipping(effect
.element
);
1628 s
.showElement(effect
.element
);
1630 afterUpdateInternal
: function (effect
) {
1631 s
.setStyle(effect
.element
.firstChild
,
1632 {bottom
: (effect
.dims
[0] - effect
.element
.clientHeight
) + 'px'});
1634 afterFinishInternal
: function (effect
) {
1635 s
.hideElement(effect
.element
);
1636 d
.undoClipping(effect
.element
, elemClip
);
1637 d
.undoPositioned(effect
.element
.firstChild
);
1638 d
.undoPositioned(effect
.element
);
1639 s
.setStyle(effect
.element
.firstChild
, {bottom
: oldInnerBottom
});
1642 return new MochiKit
.Visual
.Scale(element
, 0, options
);
1645 // Bug in opera makes the TD containing this element expand for a instance
1647 /** @id MochiKit.Visual.squish */
1648 MochiKit
.Visual
.squish
= function (element
, /* optional */ options
) {
1651 Reduce an element and make it disappear.
1654 var d
= MochiKit
.DOM
;
1655 var b
= MochiKit
.Base
;
1657 options
= b
.update({
1658 restoreAfterFinish
: true,
1659 beforeSetupInternal
: function (effect
) {
1660 elemClip
= d
.makeClipping(effect
.element
);
1662 afterFinishInternal
: function (effect
) {
1663 MochiKit
.Style
.hideElement(effect
.element
);
1664 d
.undoClipping(effect
.element
, elemClip
);
1668 return new MochiKit
.Visual
.Scale(element
, /Opera/.test(navigator
.userAgent
) ? 1 : 0, options
);
1671 /** @id MochiKit.Visual.grow */
1672 MochiKit
.Visual
.grow
= function (element
, /* optional */ options
) {
1675 Grow an element to its original size. Make it zero-sized before
1679 var d
= MochiKit
.DOM
;
1680 var v
= MochiKit
.Visual
;
1681 var s
= MochiKit
.Style
;
1682 element
= d
.getElement(element
);
1683 options
= MochiKit
.Base
.update({
1684 direction
: 'center',
1685 moveTransition
: v
.Transitions
.sinoidal
,
1686 scaleTransition
: v
.Transitions
.sinoidal
,
1687 opacityTransition
: v
.Transitions
.full
,
1689 scaleFromCenter
: false
1692 top
: element
.style
.top
,
1693 left
: element
.style
.left
,
1694 height
: element
.style
.height
,
1695 width
: element
.style
.width
,
1696 opacity
: s
.getStyle(element
, 'opacity')
1699 var dims
= s
.getElementDimensions(element
);
1700 var initialMoveX
, initialMoveY
;
1703 switch (options
.direction
) {
1705 initialMoveX
= initialMoveY
= moveX
= moveY
= 0;
1708 initialMoveX
= dims
.w
;
1709 initialMoveY
= moveY
= 0;
1713 initialMoveX
= moveX
= 0;
1714 initialMoveY
= dims
.h
;
1717 case 'bottom-right':
1718 initialMoveX
= dims
.w
;
1719 initialMoveY
= dims
.h
;
1724 initialMoveX
= dims
.w
/ 2;
1725 initialMoveY
= dims
.h
/ 2;
1726 moveX
= -dims
.w
/ 2;
1727 moveY
= -dims
.h
/ 2;
1731 var optionsParallel
= MochiKit
.Base
.update({
1732 beforeSetupInternal
: function (effect
) {
1733 s
.setStyle(effect
.effects
[0].element
, {height
: '0px'});
1734 s
.showElement(effect
.effects
[0].element
);
1736 afterFinishInternal
: function (effect
) {
1737 d
.undoClipping(effect
.effects
[0].element
);
1738 d
.undoPositioned(effect
.effects
[0].element
);
1739 s
.setStyle(effect
.effects
[0].element
, oldStyle
);
1743 return new v
.Move(element
, {
1747 beforeSetupInternal
: function (effect
) {
1748 s
.hideElement(effect
.element
);
1749 d
.makeClipping(effect
.element
);
1750 d
.makePositioned(effect
.element
);
1752 afterFinishInternal
: function (effect
) {
1754 [new v
.Opacity(effect
.element
, {
1755 sync
: true, to
: 1.0, from
: 0.0,
1756 transition
: options
.opacityTransition
1758 new v
.Move(effect
.element
, {
1759 x
: moveX
, y
: moveY
, sync
: true,
1760 transition
: options
.moveTransition
1762 new v
.Scale(effect
.element
, 100, {
1763 scaleMode
: {originalHeight
: dims
.h
,
1764 originalWidth
: dims
.w
},
1766 scaleFrom
: /Opera/.test(navigator
.userAgent
) ? 1 : 0,
1767 transition
: options
.scaleTransition
,
1768 scaleContent
: options
.scaleContent
,
1769 scaleFromCenter
: options
.scaleFromCenter
,
1770 restoreAfterFinish
: true
1778 /** @id MochiKit.Visual.shrink */
1779 MochiKit
.Visual
.shrink
= function (element
, /* optional */ options
) {
1782 Shrink an element and make it disappear.
1785 var d
= MochiKit
.DOM
;
1786 var v
= MochiKit
.Visual
;
1787 var s
= MochiKit
.Style
;
1788 element
= d
.getElement(element
);
1789 options
= MochiKit
.Base
.update({
1790 direction
: 'center',
1791 moveTransition
: v
.Transitions
.sinoidal
,
1792 scaleTransition
: v
.Transitions
.sinoidal
,
1793 opacityTransition
: v
.Transitions
.none
,
1795 scaleFromCenter
: false
1798 top
: element
.style
.top
,
1799 left
: element
.style
.left
,
1800 height
: element
.style
.height
,
1801 width
: element
.style
.width
,
1802 opacity
: s
.getStyle(element
, 'opacity')
1805 var dims
= s
.getElementDimensions(element
);
1808 switch (options
.direction
) {
1820 case 'bottom-right':
1831 var optionsParallel
= MochiKit
.Base
.update({
1832 beforeStartInternal
: function (effect
) {
1833 elemClip
= d
.makePositioned(effect
.effects
[0].element
);
1834 d
.makeClipping(effect
.effects
[0].element
);
1836 afterFinishInternal
: function (effect
) {
1837 s
.hideElement(effect
.effects
[0].element
);
1838 d
.undoClipping(effect
.effects
[0].element
, elemClip
);
1839 d
.undoPositioned(effect
.effects
[0].element
);
1840 s
.setStyle(effect
.effects
[0].element
, oldStyle
);
1844 return new v
.Parallel(
1845 [new v
.Opacity(element
, {
1846 sync
: true, to
: 0.0, from
: 1.0,
1847 transition
: options
.opacityTransition
1849 new v
.Scale(element
, /Opera/.test(navigator
.userAgent
) ? 1 : 0, {
1850 sync
: true, transition
: options
.scaleTransition
,
1851 scaleContent
: options
.scaleContent
,
1852 scaleFromCenter
: options
.scaleFromCenter
,
1853 restoreAfterFinish
: true
1855 new v
.Move(element
, {
1856 x
: moveX
, y
: moveY
, sync
: true, transition
: options
.moveTransition
1862 /** @id MochiKit.Visual.pulsate */
1863 MochiKit
.Visual
.pulsate
= function (element
, /* optional */ options
) {
1866 Pulse an element between appear/fade.
1869 var d
= MochiKit
.DOM
;
1870 var v
= MochiKit
.Visual
;
1871 var b
= MochiKit
.Base
;
1872 var oldOpacity
= MochiKit
.Style
.getStyle(element
, 'opacity');
1873 options
= b
.update({
1876 afterFinishInternal
: function (effect
) {
1877 MochiKit
.Style
.setStyle(effect
.element
, {'opacity': oldOpacity
});
1880 var transition
= options
.transition
|| v
.Transitions
.sinoidal
;
1881 var reverser
= b
.bind(function (pos
) {
1882 return transition(1 - v
.Transitions
.pulse(pos
, options
.pulses
));
1884 b
.bind(reverser
, transition
);
1885 return new v
.Opacity(element
, b
.update({
1886 transition
: reverser
}, options
));
1889 /** @id MochiKit.Visual.fold */
1890 MochiKit
.Visual
.fold
= function (element
, /* optional */ options
) {
1893 Fold an element, first vertically, then horizontally.
1896 var d
= MochiKit
.DOM
;
1897 var v
= MochiKit
.Visual
;
1898 var s
= MochiKit
.Style
;
1899 element
= d
.getElement(element
);
1901 top
: element
.style
.top
,
1902 left
: element
.style
.left
,
1903 width
: element
.style
.width
,
1904 height
: element
.style
.height
1906 var elemClip
= d
.makeClipping(element
);
1907 options
= MochiKit
.Base
.update({
1908 scaleContent
: false,
1910 afterFinishInternal
: function (effect
) {
1911 new v
.Scale(element
, 1, {
1912 scaleContent
: false,
1914 afterFinishInternal
: function (effect
) {
1915 s
.hideElement(effect
.element
);
1916 d
.undoClipping(effect
.element
, elemClip
);
1917 s
.setStyle(effect
.element
, oldStyle
);
1922 return new v
.Scale(element
, 5, options
);
1926 // Compatibility with MochiKit 1.0
1927 MochiKit
.Visual
.Color
= MochiKit
.Color
.Color
;
1928 MochiKit
.Visual
.getElementsComputedStyle
= MochiKit
.DOM
.computedStyle
;
1930 /* end of Rico adaptation */
1932 MochiKit
.Visual
.__new__
= function () {
1933 var m
= MochiKit
.Base
;
1935 m
.nameFunctions(this);
1937 this.EXPORT_TAGS
= {
1938 ":common": this.EXPORT
,
1939 ":all": m
.concat(this.EXPORT
, this.EXPORT_OK
)
1944 MochiKit
.Visual
.EXPORT
= [
1974 MochiKit
.Visual
.EXPORT_OK
= [
1979 MochiKit
.Visual
.__new__();
1981 MochiKit
.Base
._exportSymbols(this, MochiKit
.Visual
);