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');
19 if (typeof(JSAN
) != 'undefined') {
20 JSAN
.use("MochiKit.Base", []);
21 JSAN
.use("MochiKit.DOM", []);
22 JSAN
.use("MochiKit.Style", []);
23 JSAN
.use("MochiKit.Color", []);
27 if (typeof(MochiKit
.Base
) === 'undefined' ||
28 typeof(MochiKit
.DOM
) === 'undefined' ||
29 typeof(MochiKit
.Style
) === 'undefined' ||
30 typeof(MochiKit
.Color
) === 'undefined') {
34 throw "MochiKit.Visual depends on MochiKit.Base, MochiKit.DOM, MochiKit.Style and MochiKit.Color!";
37 if (typeof(MochiKit
.Visual
) == "undefined") {
41 MochiKit
.Visual
.NAME
= "MochiKit.Visual";
42 MochiKit
.Visual
.VERSION
= "1.4";
44 MochiKit
.Visual
.__repr__ = function () {
45 return "[" + this.NAME
+ " " + this.VERSION
+ "]";
48 MochiKit
.Visual
.toString = function () {
49 return this.__repr__();
52 MochiKit
.Visual
._RoundCorners = function (e
, options
) {
53 e
= MochiKit
.DOM
.getElement(e
);
54 this._setOptions(options
);
55 if (this.options
.__unstable__wrapElement
) {
59 var color
= this.options
.color
;
60 var C
= MochiKit
.Color
.Color
;
61 if (this.options
.color
=== "fromElement") {
62 color
= C
.fromBackground(e
);
63 } else if (!(color
instanceof C
)) {
64 color
= C
.fromString(color
);
66 this.isTransparent
= (color
.asRGB().a
<= 0);
68 var bgColor
= this.options
.bgColor
;
69 if (this.options
.bgColor
=== "fromParent") {
70 bgColor
= C
.fromBackground(e
.offsetParent
);
71 } else if (!(bgColor
instanceof C
)) {
72 bgColor
= C
.fromString(bgColor
);
75 this._roundCornersImpl(e
, color
, bgColor
);
78 MochiKit
.Visual
._RoundCorners
.prototype = {
79 _doWrap: function (e
) {
80 var parent
= e
.parentNode
;
81 var doc
= MochiKit
.DOM
.currentDocument();
82 if (typeof(doc
.defaultView
) === "undefined"
83 || doc
.defaultView
=== null) {
86 var style
= doc
.defaultView
.getComputedStyle(e
, null);
87 if (typeof(style
) === "undefined" || style
=== null) {
90 var wrapper
= MochiKit
.DOM
.DIV({"style": {
92 // convert padding to margin
93 marginTop
: style
.getPropertyValue("padding-top"),
94 marginRight
: style
.getPropertyValue("padding-right"),
95 marginBottom
: style
.getPropertyValue("padding-bottom"),
96 marginLeft
: style
.getPropertyValue("padding-left"),
97 // remove padding so the rounding looks right
104 wrapper
.innerHTML
= e
.innerHTML
;
106 e
.appendChild(wrapper
);
110 _roundCornersImpl: function (e
, color
, bgColor
) {
111 if (this.options
.border
) {
112 this._renderBorder(e
, bgColor
);
114 if (this._isTopRounded()) {
115 this._roundTopCorners(e
, color
, bgColor
);
117 if (this._isBottomRounded()) {
118 this._roundBottomCorners(e
, color
, bgColor
);
122 _renderBorder: function (el
, bgColor
) {
123 var borderValue
= "1px solid " + this._borderColor(bgColor
);
124 var borderL
= "border-left: " + borderValue
;
125 var borderR
= "border-right: " + borderValue
;
126 var style
= "style='" + borderL
+ ";" + borderR
+ "'";
127 el
.innerHTML
= "<div " + style
+ ">" + el
.innerHTML
+ "</div>";
130 _roundTopCorners: function (el
, color
, bgColor
) {
131 var corner
= this._createCorner(bgColor
);
132 for (var i
= 0; i
< this.options
.numSlices
; i
++) {
134 this._createCornerSlice(color
, bgColor
, i
, "top")
137 el
.style
.paddingTop
= 0;
138 el
.insertBefore(corner
, el
.firstChild
);
141 _roundBottomCorners: function (el
, color
, bgColor
) {
142 var corner
= this._createCorner(bgColor
);
143 for (var i
= (this.options
.numSlices
- 1); i
>= 0; i
--) {
145 this._createCornerSlice(color
, bgColor
, i
, "bottom")
148 el
.style
.paddingBottom
= 0;
149 el
.appendChild(corner
);
152 _createCorner: function (bgColor
) {
153 var dom
= MochiKit
.DOM
;
154 return dom
.DIV({style
: {backgroundColor
: bgColor
.toString()}});
157 _createCornerSlice: function (color
, bgColor
, n
, position
) {
158 var slice
= MochiKit
.DOM
.SPAN();
160 var inStyle
= slice
.style
;
161 inStyle
.backgroundColor
= color
.toString();
162 inStyle
.display
= "block";
163 inStyle
.height
= "1px";
164 inStyle
.overflow
= "hidden";
165 inStyle
.fontSize
= "1px";
167 var borderColor
= this._borderColor(color
, bgColor
);
168 if (this.options
.border
&& n
=== 0) {
169 inStyle
.borderTopStyle
= "solid";
170 inStyle
.borderTopWidth
= "1px";
171 inStyle
.borderLeftWidth
= "0px";
172 inStyle
.borderRightWidth
= "0px";
173 inStyle
.borderBottomWidth
= "0px";
174 // assumes css compliant box model
175 inStyle
.height
= "0px";
176 inStyle
.borderColor
= borderColor
.toString();
177 } else if (borderColor
) {
178 inStyle
.borderColor
= borderColor
.toString();
179 inStyle
.borderStyle
= "solid";
180 inStyle
.borderWidth
= "0px 1px";
183 if (!this.options
.compact
&& (n
== (this.options
.numSlices
- 1))) {
184 inStyle
.height
= "2px";
187 this._setMargin(slice
, n
, position
);
188 this._setBorder(slice
, n
, position
);
193 _setOptions: function (options
) {
196 color
: "fromElement",
197 bgColor
: "fromParent",
201 __unstable__wrapElement
: false
203 MochiKit
.Base
.update(this.options
, options
);
205 this.options
.numSlices
= (this.options
.compact
? 2 : 4);
208 _whichSideTop: function () {
209 var corners
= this.options
.corners
;
210 if (this._hasString(corners
, "all", "top")) {
214 var has_tl
= (corners
.indexOf("tl") != -1);
215 var has_tr
= (corners
.indexOf("tr") != -1);
216 if (has_tl
&& has_tr
) {
228 _whichSideBottom: function () {
229 var corners
= this.options
.corners
;
230 if (this._hasString(corners
, "all", "bottom")) {
234 var has_bl
= (corners
.indexOf('bl') != -1);
235 var has_br
= (corners
.indexOf('br') != -1);
236 if (has_bl
&& has_br
) {
248 _borderColor: function (color
, bgColor
) {
249 if (color
== "transparent") {
251 } else if (this.options
.border
) {
252 return this.options
.border
;
253 } else if (this.options
.blend
) {
254 return bgColor
.blendedColor(color
);
260 _setMargin: function (el
, n
, corners
) {
261 var marginSize
= this._marginSize(n
) + "px";
263 corners
== "top" ? this._whichSideTop() : this._whichSideBottom()
265 var style
= el
.style
;
267 if (whichSide
== "left") {
268 style
.marginLeft
= marginSize
;
269 style
.marginRight
= "0px";
270 } else if (whichSide
== "right") {
271 style
.marginRight
= marginSize
;
272 style
.marginLeft
= "0px";
274 style
.marginLeft
= marginSize
;
275 style
.marginRight
= marginSize
;
279 _setBorder: function (el
, n
, corners
) {
280 var borderSize
= this._borderSize(n
) + "px";
282 corners
== "top" ? this._whichSideTop() : this._whichSideBottom()
285 var style
= el
.style
;
286 if (whichSide
== "left") {
287 style
.borderLeftWidth
= borderSize
;
288 style
.borderRightWidth
= "0px";
289 } else if (whichSide
== "right") {
290 style
.borderRightWidth
= borderSize
;
291 style
.borderLeftWidth
= "0px";
293 style
.borderLeftWidth
= borderSize
;
294 style
.borderRightWidth
= borderSize
;
298 _marginSize: function (n
) {
299 if (this.isTransparent
) {
303 var o
= this.options
;
304 if (o
.compact
&& o
.blend
) {
305 var smBlendedMarginSizes
= [1, 0];
306 return smBlendedMarginSizes
[n
];
307 } else if (o
.compact
) {
308 var compactMarginSizes
= [2, 1];
309 return compactMarginSizes
[n
];
310 } else if (o
.blend
) {
311 var blendedMarginSizes
= [3, 2, 1, 0];
312 return blendedMarginSizes
[n
];
314 var marginSizes
= [5, 3, 2, 1];
315 return marginSizes
[n
];
319 _borderSize: function (n
) {
320 var o
= this.options
;
322 if (o
.compact
&& (o
.blend
|| this.isTransparent
)) {
324 } else if (o
.compact
) {
325 borderSizes
= [1, 0];
326 } else if (o
.blend
) {
327 borderSizes
= [2, 1, 1, 1];
328 } else if (o
.border
) {
329 borderSizes
= [0, 2, 0, 0];
330 } else if (this.isTransparent
) {
331 borderSizes
= [5, 3, 2, 1];
335 return borderSizes
[n
];
338 _hasString: function (str
) {
339 for (var i
= 1; i
< arguments
.length
; i
++) {
340 if (str
.indexOf(arguments
[i
]) != -1) {
347 _isTopRounded: function () {
348 return this._hasString(this.options
.corners
,
349 "all", "top", "tl", "tr"
353 _isBottomRounded: function () {
354 return this._hasString(this.options
.corners
,
355 "all", "bottom", "bl", "br"
359 _hasSingleTextChild: function (el
) {
360 return (el
.childNodes
.length
== 1 && el
.childNodes
[0].nodeType
== 3);
364 /** @id MochiKit.Visual.roundElement */
365 MochiKit
.Visual
.roundElement = function (e
, options
) {
366 new MochiKit
.Visual
._RoundCorners(e
, options
);
369 /** @id MochiKit.Visual.roundClass */
370 MochiKit
.Visual
.roundClass = function (tagName
, className
, options
) {
371 var elements
= MochiKit
.DOM
.getElementsByTagAndClassName(
374 for (var i
= 0; i
< elements
.length
; i
++) {
375 MochiKit
.Visual
.roundElement(elements
[i
], options
);
379 /** @id MochiKit.Visual.tagifyText */
380 MochiKit
.Visual
.tagifyText = function (element
, /* optional */tagifyStyle
) {
383 Change a node text to character in tags.
385 @param tagifyStyle: the style to apply to character nodes, default to
386 'position: relative'.
389 var tagifyStyle
= tagifyStyle
|| 'position:relative';
390 if (/MSIE/.test(navigator
.userAgent
)) {
391 tagifyStyle
+= ';zoom:1';
393 element
= MochiKit
.DOM
.getElement(element
);
394 var ma
= MochiKit
.Base
.map
;
395 ma(function (child
) {
396 if (child
.nodeType
== 3) {
397 ma(function (character
) {
398 element
.insertBefore(
399 MochiKit
.DOM
.SPAN({style
: tagifyStyle
},
400 character
== ' ' ? String
.fromCharCode(160) : character
), child
);
401 }, child
.nodeValue
.split(''));
402 MochiKit
.DOM
.removeElement(child
);
404 }, element
.childNodes
);
407 /** @id MochiKit.Visual.forceRerendering */
408 MochiKit
.Visual
.forceRerendering = function (element
) {
410 element
= MochiKit
.DOM
.getElement(element
);
411 var n
= document
.createTextNode(' ');
412 element
.appendChild(n
);
413 element
.removeChild(n
);
418 /** @id MochiKit.Visual.multiple */
419 MochiKit
.Visual
.multiple = function (elements
, effect
, /* optional */options
) {
422 Launch the same effect subsequently on given elements.
425 options
= MochiKit
.Base
.update({
426 speed
: 0.1, delay
: 0.0
428 var masterDelay
= options
.delay
;
430 MochiKit
.Base
.map(function (innerelement
) {
431 options
.delay
= index
* options
.speed
+ masterDelay
;
432 new effect(innerelement
, options
);
437 MochiKit
.Visual
.PAIRS
= {
438 'slide': ['slideDown', 'slideUp'],
439 'blind': ['blindDown', 'blindUp'],
440 'appear': ['appear', 'fade'],
441 'size': ['grow', 'shrink']
444 /** @id MochiKit.Visual.toggle */
445 MochiKit
.Visual
.toggle = function (element
, /* optional */effect
, /* optional */options
) {
448 Toggle an item between two state depending of its visibility, making
449 a effect between these states. Default effect is 'appear', can be
453 element
= MochiKit
.DOM
.getElement(element
);
454 effect
= (effect
|| 'appear').toLowerCase();
455 options
= MochiKit
.Base
.update({
456 queue
: {position
: 'end', scope
: (element
.id
|| 'global'), limit
: 1}
458 var v
= MochiKit
.Visual
;
459 v
[element
.style
.display
!= 'none' ?
460 v
.PAIRS
[effect
][1] : v
.PAIRS
[effect
][0]](element
, options
);
465 Transitions: define functions calculating variations depending of a position.
469 MochiKit
.Visual
.Transitions
= {}
471 /** @id MochiKit.Visual.Transitions.linear */
472 MochiKit
.Visual
.Transitions
.linear = function (pos
) {
476 /** @id MochiKit.Visual.Transitions.sinoidal */
477 MochiKit
.Visual
.Transitions
.sinoidal = function (pos
) {
478 return (-Math
.cos(pos
*Math
.PI
)/2) + 0.5;
481 /** @id MochiKit.Visual.Transitions.reverse */
482 MochiKit
.Visual
.Transitions
.reverse = function (pos
) {
486 /** @id MochiKit.Visual.Transitions.flicker */
487 MochiKit
.Visual
.Transitions
.flicker = function (pos
) {
488 return ((-Math
.cos(pos
*Math
.PI
)/4) + 0.75) + Math.random()/4;
491 /** @id MochiKit.Visual.Transitions.wobble */
492 MochiKit
.Visual
.Transitions
.wobble = function (pos
) {
493 return (-Math
.cos(pos
*Math
.PI
*(9*pos
))/2) + 0.5;
496 /** @id MochiKit.Visual.Transitions.pulse */
497 MochiKit
.Visual
.Transitions
.pulse = function (pos
) {
498 return (Math
.floor(pos
*10) % 2 == 0 ?
499 (pos
*10 - Math
.floor(pos
*10)) : 1 - (pos
*10 - Math
.floor(pos
*10)));
502 /** @id MochiKit.Visual.Transitions.none */
503 MochiKit
.Visual
.Transitions
.none = function (pos
) {
507 /** @id MochiKit.Visual.Transitions.full */
508 MochiKit
.Visual
.Transitions
.full = function (pos
) {
518 MochiKit
.Visual
.ScopedQueue = function () {
522 MochiKit
.Base
.update(MochiKit
.Visual
.ScopedQueue
.prototype, {
523 __init__: function () {
525 this.interval
= null;
528 /** @id MochiKit.Visual.ScopedQueue.prototype.add */
529 add: function (effect
) {
530 var timestamp
= new Date().getTime();
532 var position
= (typeof(effect
.options
.queue
) == 'string') ?
533 effect
.options
.queue
: effect
.options
.queue
.position
;
535 var ma
= MochiKit
.Base
.map
;
538 // move unstarted effects after this effect
540 if (e
.state
== 'idle') {
541 e
.startOn
+= effect
.finishOn
;
542 e
.finishOn
+= effect
.finishOn
;
548 // start effect after last queued effect has finished
551 if (i
>= (finish
|| i
)) {
555 timestamp
= finish
|| timestamp
;
564 effect
.startOn
+= timestamp
;
565 effect
.finishOn
+= timestamp
;
566 if (!effect
.options
.queue
.limit
||
567 this.effects
.length
< effect
.options
.queue
.limit
) {
568 this.effects
.push(effect
);
571 if (!this.interval
) {
572 this.interval
= this.startLoop(MochiKit
.Base
.bind(this.loop
, this),
577 /** @id MochiKit.Visual.ScopedQueue.prototype.startLoop */
578 startLoop: function (func
, interval
) {
579 return setInterval(func
, interval
)
582 /** @id MochiKit.Visual.ScopedQueue.prototype.remove */
583 remove: function (effect
) {
584 this.effects
= MochiKit
.Base
.filter(function (e
) {
587 if (this.effects
.length
== 0) {
588 this.stopLoop(this.interval
);
589 this.interval
= null;
593 /** @id MochiKit.Visual.ScopedQueue.prototype.stopLoop */
594 stopLoop: function (interval
) {
595 clearInterval(interval
)
598 /** @id MochiKit.Visual.ScopedQueue.prototype.loop */
600 var timePos
= new Date().getTime();
601 MochiKit
.Base
.map(function (effect
) {
602 effect
.loop(timePos
);
607 MochiKit
.Visual
.Queues
= {
610 get: function (queueName
) {
611 if (typeof(queueName
) != 'string') {
615 if (!this.instances
[queueName
]) {
616 this.instances
[queueName
] = new MochiKit
.Visual
.ScopedQueue();
618 return this.instances
[queueName
];
622 MochiKit
.Visual
.Queue
= MochiKit
.Visual
.Queues
.get('global');
624 MochiKit
.Visual
.DefaultOptions
= {
625 transition
: MochiKit
.Visual
.Transitions
.sinoidal
,
626 duration
: 1.0, // seconds
627 fps
: 25.0, // max. 25fps due to MochiKit.Visual.Queue implementation
628 sync
: false, // true for combining
635 MochiKit
.Visual
.Base = function () {};
637 MochiKit
.Visual
.Base
.prototype = {
640 Basic class for all Effects. Define a looping mechanism called for each step
641 of an effect. Don't instantiate it, only subclass it.
645 __class__
: MochiKit
.Visual
.Base
,
647 /** @id MochiKit.Visual.Base.prototype.start */
648 start: function (options
) {
649 var v
= MochiKit
.Visual
;
650 this.options
= MochiKit
.Base
.setdefault(options
|| {},
652 this.currentFrame
= 0;
654 this.startOn
= this.options
.delay
*1000;
655 this.finishOn
= this.startOn
+ (this.options
.duration
*1000);
656 this.event('beforeStart');
657 if (!this.options
.sync
) {
658 v
.Queues
.get(typeof(this.options
.queue
) == 'string' ?
659 'global' : this.options
.queue
.scope
).add(this);
663 /** @id MochiKit.Visual.Base.prototype.loop */
664 loop: function (timePos
) {
665 if (timePos
>= this.startOn
) {
666 if (timePos
>= this.finishOn
) {
667 return this.finalize();
669 var pos
= (timePos
- this.startOn
) / (this.finishOn
- this.startOn
);
671 Math
.round(pos
* this.options
.fps
* this.options
.duration
);
672 if (frame
> this.currentFrame
) {
674 this.currentFrame
= frame
;
679 /** @id MochiKit.Visual.Base.prototype.render */
680 render: function (pos
) {
681 if (this.state
== 'idle') {
682 this.state
= 'running';
683 this.event('beforeSetup');
685 this.event('afterSetup');
687 if (this.state
== 'running') {
688 if (this.options
.transition
) {
689 pos
= this.options
.transition(pos
);
691 pos
*= (this.options
.to
- this.options
.from);
692 pos
+= this.options
.from;
693 this.event('beforeUpdate');
695 this.event('afterUpdate');
699 /** @id MochiKit.Visual.Base.prototype.cancel */
700 cancel: function () {
701 if (!this.options
.sync
) {
702 MochiKit
.Visual
.Queues
.get(typeof(this.options
.queue
) == 'string' ?
703 'global' : this.options
.queue
.scope
).remove(this);
705 this.state
= 'finished';
708 /** @id MochiKit.Visual.Base.prototype.finalize */
709 finalize: function () {
712 this.event('beforeFinish');
714 this.event('afterFinish');
720 finish: function () {
723 update: function (position
) {
726 /** @id MochiKit.Visual.Base.prototype.event */
727 event: function (eventName
) {
728 if (this.options
[eventName
+ 'Internal']) {
729 this.options
[eventName
+ 'Internal'](this);
731 if (this.options
[eventName
]) {
732 this.options
[eventName
](this);
736 /** @id MochiKit.Visual.Base.prototype.repr */
738 return '[' + this.__class__
.NAME
+ ', options:' +
739 MochiKit
.Base
.repr(this.options
) + ']';
743 /** @id MochiKit.Visual.Parallel */
744 MochiKit
.Visual
.Parallel = function (effects
, options
) {
745 this.__init__(effects
, options
);
748 MochiKit
.Visual
.Parallel
.prototype = new MochiKit
.Visual
.Base();
750 MochiKit
.Base
.update(MochiKit
.Visual
.Parallel
.prototype, {
753 Run multiple effects at the same time.
756 __init__: function (effects
, options
) {
757 this.effects
= effects
|| [];
761 /** @id MochiKit.Visual.Parallel.prototype.update */
762 update: function (position
) {
763 MochiKit
.Base
.map(function (effect
) {
764 effect
.render(position
);
768 /** @id MochiKit.Visual.Parallel.prototype.finish */
769 finish: function () {
770 MochiKit
.Base
.map(function (effect
) {
776 /** @id MochiKit.Visual.Opacity */
777 MochiKit
.Visual
.Opacity = function (element
, options
) {
778 this.__init__(element
, options
);
781 MochiKit
.Visual
.Opacity
.prototype = new MochiKit
.Visual
.Base();
783 MochiKit
.Base
.update(MochiKit
.Visual
.Opacity
.prototype, {
786 Change the opacity of an element.
788 @param options: 'from' and 'to' change the starting and ending opacities.
789 Must be between 0.0 and 1.0. Default to current opacity and 1.0.
792 __init__: function (element
, /* optional */options
) {
793 var b
= MochiKit
.Base
;
794 var s
= MochiKit
.Style
;
795 this.element
= MochiKit
.DOM
.getElement(element
);
796 // make this work on IE on elements without 'layout'
797 if (this.element
.currentStyle
&&
798 (!this.element
.currentStyle
.hasLayout
)) {
799 s
.setStyle(this.element
, {zoom
: 1});
802 from: s
.getOpacity(this.element
) || 0.0,
808 /** @id MochiKit.Visual.Opacity.prototype.update */
809 update: function (position
) {
810 MochiKit
.Style
.setOpacity(this.element
, position
);
814 /** @id MochiKit.Visual.Opacity.prototype.Move */
815 MochiKit
.Visual
.Move = function (element
, options
) {
816 this.__init__(element
, options
);
819 MochiKit
.Visual
.Move
.prototype = new MochiKit
.Visual
.Base();
821 MochiKit
.Base
.update(MochiKit
.Visual
.Move
.prototype, {
824 Move an element between its current position to a defined position
826 @param options: 'x' and 'y' for final positions, default to 0, 0.
829 __init__: function (element
, /* optional */options
) {
830 this.element
= MochiKit
.DOM
.getElement(element
);
831 options
= MochiKit
.Base
.update({
839 /** @id MochiKit.Visual.Move.prototype.setup */
841 // Bug in Opera: Opera returns the 'real' position of a static element
842 // or relative element that does not have top/left explicitly set.
843 // ==> Always set top and left for position relative elements in your
844 // stylesheets (to 0 if you do not need them)
845 MochiKit
.DOM
.makePositioned(this.element
);
847 var s
= this.element
.style
;
848 var originalVisibility
= s
.visibility
;
849 var originalDisplay
= s
.display
;
850 if (originalDisplay
== 'none') {
851 s
.visibility
= 'hidden';
855 this.originalLeft
= parseFloat(MochiKit
.Style
.getStyle(this.element
, 'left') || '0');
856 this.originalTop
= parseFloat(MochiKit
.Style
.getStyle(this.element
, 'top') || '0');
858 if (this.options
.mode
== 'absolute') {
859 // absolute movement, so we need to calc deltaX and deltaY
860 this.options
.x
-= this.originalLeft
;
861 this.options
.y
-= this.originalTop
;
863 if (originalDisplay
== 'none') {
864 s
.visibility
= originalVisibility
;
865 s
.display
= originalDisplay
;
869 /** @id MochiKit.Visual.Move.prototype.update */
870 update: function (position
) {
871 MochiKit
.Style
.setStyle(this.element
, {
872 left
: Math
.round(this.options
.x
* position
+ this.originalLeft
) + 'px',
873 top
: Math
.round(this.options
.y
* position
+ this.originalTop
) + 'px'
878 /** @id MochiKit.Visual.Scale */
879 MochiKit
.Visual
.Scale = function (element
, percent
, options
) {
880 this.__init__(element
, percent
, options
);
883 MochiKit
.Visual
.Scale
.prototype = new MochiKit
.Visual
.Base();
885 MochiKit
.Base
.update(MochiKit
.Visual
.Scale
.prototype, {
888 Change the size of an element.
890 @param percent: final_size = percent*original_size
892 @param options: several options changing scale behaviour
895 __init__: function (element
, percent
, /* optional */options
) {
896 this.element
= MochiKit
.DOM
.getElement(element
)
897 options
= MochiKit
.Base
.update({
901 scaleFromCenter
: false,
902 scaleMode
: 'box', // 'box' or 'contents' or {} with provided values
909 /** @id MochiKit.Visual.Scale.prototype.setup */
911 this.restoreAfterFinish
= this.options
.restoreAfterFinish
|| false;
912 this.elementPositioning
= MochiKit
.Style
.getStyle(this.element
,
915 var ma
= MochiKit
.Base
.map
;
916 var b
= MochiKit
.Base
.bind
;
917 this.originalStyle
= {};
919 this.originalStyle
[k
] = this.element
.style
[k
];
920 }, this), ['top', 'left', 'width', 'height', 'fontSize']);
922 this.originalTop
= this.element
.offsetTop
;
923 this.originalLeft
= this.element
.offsetLeft
;
925 var fontSize
= MochiKit
.Style
.getStyle(this.element
,
926 'font-size') || '100%';
927 ma(b(function (fontSizeType
) {
928 if (fontSize
.indexOf(fontSizeType
) > 0) {
929 this.fontSize
= parseFloat(fontSize
);
930 this.fontSizeType
= fontSizeType
;
932 }, this), ['em', 'px', '%']);
934 this.factor
= (this.options
.scaleTo
- this.options
.scaleFrom
)/100;
936 if (/^content/.test(this.options
.scaleMode
)) {
937 this.dims
= [this.element
.scrollHeight
, this.element
.scrollWidth
];
938 } else if (this.options
.scaleMode
== 'box') {
939 this.dims
= [this.element
.offsetHeight
, this.element
.offsetWidth
];
941 this.dims
= [this.options
.scaleMode
.originalHeight
,
942 this.options
.scaleMode
.originalWidth
];
946 /** @id MochiKit.Visual.Scale.prototype.update */
947 update: function (position
) {
948 var currentScale
= (this.options
.scaleFrom
/100.0) +
949 (this.factor
* position
);
950 if (this.options
.scaleContent
&& this.fontSize
) {
951 MochiKit
.Style
.setStyle(this.element
, {
952 fontSize
: this.fontSize
* currentScale
+ this.fontSizeType
955 this.setDimensions(this.dims
[0] * currentScale
,
956 this.dims
[1] * currentScale
);
959 /** @id MochiKit.Visual.Scale.prototype.finish */
960 finish: function () {
961 if (this.restoreAfterFinish
) {
962 MochiKit
.Style
.setStyle(this.element
, this.originalStyle
);
966 /** @id MochiKit.Visual.Scale.prototype.setDimensions */
967 setDimensions: function (height
, width
) {
970 if (/MSIE/.test(navigator
.userAgent
)) {
973 if (this.options
.scaleX
) {
974 d
.width
= r(width
) + 'px';
976 if (this.options
.scaleY
) {
977 d
.height
= r(height
) + 'px';
979 if (this.options
.scaleFromCenter
) {
980 var topd
= (height
- this.dims
[0])/2;
981 var leftd
= (width
- this.dims
[1])/2;
982 if (this.elementPositioning
== 'absolute') {
983 if (this.options
.scaleY
) {
984 d
.top
= this.originalTop
- topd
+ 'px';
986 if (this.options
.scaleX
) {
987 d
.left
= this.originalLeft
- leftd
+ 'px';
990 if (this.options
.scaleY
) {
991 d
.top
= -topd
+ 'px';
993 if (this.options
.scaleX
) {
994 d
.left
= -leftd
+ 'px';
998 MochiKit
.Style
.setStyle(this.element
, d
);
1002 /** @id MochiKit.Visual.Highlight */
1003 MochiKit
.Visual
.Highlight = function (element
, options
) {
1004 this.__init__(element
, options
);
1007 MochiKit
.Visual
.Highlight
.prototype = new MochiKit
.Visual
.Base();
1009 MochiKit
.Base
.update(MochiKit
.Visual
.Highlight
.prototype, {
1012 Highlight an item of the page.
1014 @param options: 'startcolor' for choosing highlighting color, default
1018 __init__: function (element
, /* optional */options
) {
1019 this.element
= MochiKit
.DOM
.getElement(element
);
1020 options
= MochiKit
.Base
.update({
1021 startcolor
: '#ffff99'
1023 this.start(options
);
1026 /** @id MochiKit.Visual.Highlight.prototype.setup */
1027 setup: function () {
1028 var b
= MochiKit
.Base
;
1029 var s
= MochiKit
.Style
;
1030 // Prevent executing on elements not in the layout flow
1031 if (s
.getStyle(this.element
, 'display') == 'none') {
1035 // Disable background image during the effect
1037 backgroundImage
: s
.getStyle(this.element
, 'background-image')
1039 s
.setStyle(this.element
, {
1040 backgroundImage
: 'none'
1043 if (!this.options
.endcolor
) {
1044 this.options
.endcolor
=
1045 MochiKit
.Color
.Color
.fromBackground(this.element
).toHexString();
1047 if (b
.isUndefinedOrNull(this.options
.restorecolor
)) {
1048 this.options
.restorecolor
= s
.getStyle(this.element
,
1049 'background-color');
1051 // init color calculations
1052 this._base
= b
.map(b
.bind(function (i
) {
1054 this.options
.startcolor
.slice(i
*2 + 1, i
*2 + 3), 16);
1055 }, this), [0, 1, 2]);
1056 this._delta
= b
.map(b
.bind(function (i
) {
1057 return parseInt(this.options
.endcolor
.slice(i
*2 + 1, i
*2 + 3), 16)
1059 }, this), [0, 1, 2]);
1062 /** @id MochiKit.Visual.Highlight.prototype.update */
1063 update: function (position
) {
1065 MochiKit
.Base
.map(MochiKit
.Base
.bind(function (i
) {
1066 m
+= MochiKit
.Color
.toColorPart(Math
.round(this._base
[i
] +
1067 this._delta
[i
]*position
));
1068 }, this), [0, 1, 2]);
1069 MochiKit
.Style
.setStyle(this.element
, {
1074 /** @id MochiKit.Visual.Highlight.prototype.finish */
1075 finish: function () {
1076 MochiKit
.Style
.setStyle(this.element
,
1077 MochiKit
.Base
.update(this.oldStyle
, {
1078 backgroundColor
: this.options
.restorecolor
1083 /** @id MochiKit.Visual.ScrollTo */
1084 MochiKit
.Visual
.ScrollTo = function (element
, options
) {
1085 this.__init__(element
, options
);
1088 MochiKit
.Visual
.ScrollTo
.prototype = new MochiKit
.Visual
.Base();
1090 MochiKit
.Base
.update(MochiKit
.Visual
.ScrollTo
.prototype, {
1093 Scroll to an element in the page.
1096 __init__: function (element
, /* optional */options
) {
1097 this.element
= MochiKit
.DOM
.getElement(element
);
1098 this.start(options
|| {});
1101 /** @id MochiKit.Visual.ScrollTo.prototype.setup */
1102 setup: function () {
1103 var p
= MochiKit
.Position
;
1105 var offsets
= p
.cumulativeOffset(this.element
);
1106 if (this.options
.offset
) {
1107 offsets
.y
+= this.options
.offset
;
1110 if (window
.innerHeight
) {
1111 max
= window
.innerHeight
- window
.height
;
1112 } else if (document
.documentElement
&&
1113 document
.documentElement
.clientHeight
) {
1114 max
= document
.documentElement
.clientHeight
-
1115 document
.body
.scrollHeight
;
1116 } else if (document
.body
) {
1117 max
= document
.body
.clientHeight
- document
.body
.scrollHeight
;
1119 this.scrollStart
= p
.windowOffset
.y
;
1120 this.delta
= (offsets
.y
> max
? max
: offsets
.y
) - this.scrollStart
;
1123 /** @id MochiKit.Visual.ScrollTo.prototype.update */
1124 update: function (position
) {
1125 var p
= MochiKit
.Position
;
1127 window
.scrollTo(p
.windowOffset
.x
, this.scrollStart
+ (position
* this.delta
));
1133 Combination effects.
1137 /** @id MochiKit.Visual.fade */
1138 MochiKit
.Visual
.fade = function (element
, /* optional */ options
) {
1141 Fade a given element: change its opacity and hide it in the end.
1143 @param options: 'to' and 'from' to change opacity.
1146 var s
= MochiKit
.Style
;
1147 var oldOpacity
= MochiKit
.DOM
.getElement(element
).style
.opacity
|| '';
1148 options
= MochiKit
.Base
.update({
1149 from: s
.getOpacity(element
) || 1.0,
1151 afterFinishInternal: function (effect
) {
1152 if (effect
.options
.to
!== 0) {
1155 s
.hideElement(effect
.element
);
1156 s
.setStyle(effect
.element
, {opacity
: oldOpacity
});
1159 return new MochiKit
.Visual
.Opacity(element
, options
);
1162 /** @id MochiKit.Visual.appear */
1163 MochiKit
.Visual
.appear = function (element
, /* optional */ options
) {
1166 Make an element appear.
1168 @param options: 'to' and 'from' to change opacity.
1171 var s
= MochiKit
.Style
;
1172 var v
= MochiKit
.Visual
;
1173 options
= MochiKit
.Base
.update({
1174 from: (s
.getStyle(element
, 'display') == 'none' ? 0.0 :
1175 s
.getOpacity(element
) || 0.0),
1177 // force Safari to render floated elements properly
1178 afterFinishInternal: function (effect
) {
1179 v
.forceRerendering(effect
.element
);
1181 beforeSetupInternal: function (effect
) {
1182 s
.setOpacity(effect
.element
, effect
.options
.from);
1183 s
.showElement(effect
.element
);
1186 return new v
.Opacity(element
, options
);
1189 /** @id MochiKit.Visual.puff */
1190 MochiKit
.Visual
.puff = function (element
, /* optional */ options
) {
1193 'Puff' an element: grow it to double size, fading it and make it hidden.
1196 var s
= MochiKit
.Style
;
1197 var v
= MochiKit
.Visual
;
1198 element
= MochiKit
.DOM
.getElement(element
);
1200 opacity
: element
.style
.opacity
|| '',
1201 position
: s
.getStyle(element
, 'position'),
1202 top
: element
.style
.top
,
1203 left
: element
.style
.left
,
1204 width
: element
.style
.width
,
1205 height
: element
.style
.height
1207 options
= MochiKit
.Base
.update({
1208 beforeSetupInternal: function (effect
) {
1209 MochiKit
.Position
.absolutize(effect
.effects
[0].element
)
1211 afterFinishInternal: function (effect
) {
1212 s
.hideElement(effect
.effects
[0].element
);
1213 s
.setStyle(effect
.effects
[0].element
, oldStyle
);
1216 return new v
.Parallel(
1217 [new v
.Scale(element
, 200,
1218 {sync
: true, scaleFromCenter
: true,
1219 scaleContent
: true, restoreAfterFinish
: true}),
1220 new v
.Opacity(element
, {sync
: true, to
: 0.0 })],
1224 /** @id MochiKit.Visual.blindUp */
1225 MochiKit
.Visual
.blindUp = function (element
, /* optional */ options
) {
1228 Blind an element up: change its vertical size to 0.
1231 var d
= MochiKit
.DOM
;
1232 element
= d
.getElement(element
);
1233 var elemClip
= d
.makeClipping(element
);
1234 options
= MochiKit
.Base
.update({
1235 scaleContent
: false,
1237 restoreAfterFinish
: true,
1238 afterFinishInternal: function (effect
) {
1239 MochiKit
.Style
.hideElement(effect
.element
);
1240 d
.undoClipping(effect
.element
, elemClip
);
1244 return new MochiKit
.Visual
.Scale(element
, 0, options
);
1247 /** @id MochiKit.Visual.blindDown */
1248 MochiKit
.Visual
.blindDown = function (element
, /* optional */ options
) {
1251 Blind an element down: restore its vertical size.
1254 var d
= MochiKit
.DOM
;
1255 var s
= MochiKit
.Style
;
1256 element
= d
.getElement(element
);
1257 var elementDimensions
= s
.getElementDimensions(element
);
1259 options
= MochiKit
.Base
.update({
1260 scaleContent
: false,
1263 scaleMode
: {originalHeight
: elementDimensions
.h
,
1264 originalWidth
: elementDimensions
.w
},
1265 restoreAfterFinish
: true,
1266 afterSetupInternal: function (effect
) {
1267 elemClip
= d
.makeClipping(effect
.element
);
1268 s
.setStyle(effect
.element
, {height
: '0px'});
1269 s
.showElement(effect
.element
);
1271 afterFinishInternal: function (effect
) {
1272 d
.undoClipping(effect
.element
, elemClip
);
1275 return new MochiKit
.Visual
.Scale(element
, 100, options
);
1278 /** @id MochiKit.Visual.switchOff */
1279 MochiKit
.Visual
.switchOff = function (element
, /* optional */ options
) {
1282 Apply a switch-off-like effect.
1285 var d
= MochiKit
.DOM
;
1286 element
= d
.getElement(element
);
1287 var oldOpacity
= element
.style
.opacity
|| '';
1289 var options
= MochiKit
.Base
.update({
1291 scaleFromCenter
: true,
1293 scaleContent
: false,
1294 restoreAfterFinish
: true,
1295 beforeSetupInternal: function (effect
) {
1296 d
.makePositioned(effect
.element
);
1297 elemClip
= d
.makeClipping(effect
.element
);
1299 afterFinishInternal: function (effect
) {
1300 MochiKit
.Style
.hideElement(effect
.element
);
1301 d
.undoClipping(effect
.element
, elemClip
);
1302 d
.undoPositioned(effect
.element
);
1303 MochiKit
.Style
.setStyle(effect
.element
, {opacity
: oldOpacity
});
1306 var v
= MochiKit
.Visual
;
1307 return new v
.appear(element
, {
1310 transition
: v
.Transitions
.flicker
,
1311 afterFinishInternal: function (effect
) {
1312 new v
.Scale(effect
.element
, 1, options
)
1317 /** @id MochiKit.Visual.dropOut */
1318 MochiKit
.Visual
.dropOut = function (element
, /* optional */ options
) {
1321 Make an element fall and disappear.
1324 var d
= MochiKit
.DOM
;
1325 var s
= MochiKit
.Style
;
1326 element
= d
.getElement(element
);
1328 top
: s
.getStyle(element
, 'top'),
1329 left
: s
.getStyle(element
, 'left'),
1330 opacity
: element
.style
.opacity
|| ''
1333 options
= MochiKit
.Base
.update({
1335 beforeSetupInternal: function (effect
) {
1336 d
.makePositioned(effect
.effects
[0].element
);
1338 afterFinishInternal: function (effect
) {
1339 s
.hideElement(effect
.effects
[0].element
);
1340 d
.undoPositioned(effect
.effects
[0].element
);
1341 s
.setStyle(effect
.effects
[0].element
, oldStyle
);
1344 var v
= MochiKit
.Visual
;
1345 return new v
.Parallel(
1346 [new v
.Move(element
, {x
: 0, y
: 100, sync
: true}),
1347 new v
.Opacity(element
, {sync
: true, to
: 0.0})],
1351 /** @id MochiKit.Visual.shake */
1352 MochiKit
.Visual
.shake = function (element
, /* optional */ options
) {
1355 Move an element from left to right several times.
1358 var d
= MochiKit
.DOM
;
1359 var v
= MochiKit
.Visual
;
1360 var s
= MochiKit
.Style
;
1361 element
= d
.getElement(element
);
1362 options
= MochiKit
.Base
.update({
1366 afterFinishInternal: function (effect
) {
1367 d
.undoPositioned(effect
.element
);
1368 s
.setStyle(effect
.element
, oldStyle
);
1372 top
: s
.getStyle(element
, 'top'),
1373 left
: s
.getStyle(element
, 'left') };
1374 return new v
.Move(element
,
1375 {x
: 20, y
: 0, duration
: 0.05, afterFinishInternal: function (effect
) {
1376 new v
.Move(effect
.element
,
1377 {x
: -40, y
: 0, duration
: 0.1, afterFinishInternal: function (effect
) {
1378 new v
.Move(effect
.element
,
1379 {x
: 40, y
: 0, duration
: 0.1, afterFinishInternal: function (effect
) {
1380 new v
.Move(effect
.element
,
1381 {x
: -40, y
: 0, duration
: 0.1, afterFinishInternal: function (effect
) {
1382 new v
.Move(effect
.element
,
1383 {x
: 40, y
: 0, duration
: 0.1, afterFinishInternal: function (effect
) {
1384 new v
.Move(effect
.element
, options
1385 ) }}) }}) }}) }}) }});
1388 /** @id MochiKit.Visual.slideDown */
1389 MochiKit
.Visual
.slideDown = function (element
, /* optional */ options
) {
1392 Slide an element down.
1393 It needs to have the content of the element wrapped in a container
1394 element with fixed height.
1397 var d
= MochiKit
.DOM
;
1398 var b
= MochiKit
.Base
;
1399 var s
= MochiKit
.Style
;
1400 element
= d
.getElement(element
);
1401 if (!element
.firstChild
) {
1402 throw "MochiKit.Visual.slideDown must be used on a element with a child";
1404 d
.removeEmptyTextNodes(element
);
1405 var oldInnerBottom
= s
.getStyle(element
.firstChild
, 'bottom') || 0;
1406 var elementDimensions
= s
.getElementDimensions(element
);
1408 options
= b
.update({
1409 scaleContent
: false,
1412 scaleMode
: {originalHeight
: elementDimensions
.h
,
1413 originalWidth
: elementDimensions
.w
},
1414 restoreAfterFinish
: true,
1415 afterSetupInternal: function (effect
) {
1416 d
.makePositioned(effect
.element
);
1417 d
.makePositioned(effect
.element
.firstChild
);
1418 if (/Opera/.test(navigator
.userAgent
)) {
1419 s
.setStyle(effect
.element
, {top
: ''});
1421 elemClip
= d
.makeClipping(effect
.element
);
1422 s
.setStyle(effect
.element
, {height
: '0px'});
1423 s
.showElement(effect
.element
);
1425 afterUpdateInternal: function (effect
) {
1426 s
.setStyle(effect
.element
.firstChild
,
1427 {bottom
: (effect
.dims
[0] - effect
.element
.clientHeight
) + 'px'})
1429 afterFinishInternal: function (effect
) {
1430 d
.undoClipping(effect
.element
, elemClip
);
1431 // IE will crash if child is undoPositioned first
1432 if (/MSIE/.test(navigator
.userAgent
)) {
1433 d
.undoPositioned(effect
.element
);
1434 d
.undoPositioned(effect
.element
.firstChild
);
1436 d
.undoPositioned(effect
.element
.firstChild
);
1437 d
.undoPositioned(effect
.element
);
1439 s
.setStyle(effect
.element
.firstChild
,
1440 {bottom
: oldInnerBottom
});
1444 return new MochiKit
.Visual
.Scale(element
, 100, options
);
1447 /** @id MochiKit.Visual.slideUp */
1448 MochiKit
.Visual
.slideUp = function (element
, /* optional */ options
) {
1451 Slide an element up.
1452 It needs to have the content of the element wrapped in a container
1453 element with fixed height.
1456 var d
= MochiKit
.DOM
;
1457 var b
= MochiKit
.Base
;
1458 var s
= MochiKit
.Style
;
1459 element
= d
.getElement(element
);
1460 if (!element
.firstChild
) {
1461 throw "MochiKit.Visual.slideUp must be used on a element with a child";
1463 d
.removeEmptyTextNodes(element
);
1464 var oldInnerBottom
= s
.getStyle(element
.firstChild
, 'bottom');
1466 options
= b
.update({
1467 scaleContent
: false,
1471 restoreAfterFinish
: true,
1472 beforeStartInternal: function (effect
) {
1473 d
.makePositioned(effect
.element
);
1474 d
.makePositioned(effect
.element
.firstChild
);
1475 if (/Opera/.test(navigator
.userAgent
)) {
1476 s
.setStyle(effect
.element
, {top
: ''});
1478 elemClip
= d
.makeClipping(effect
.element
);
1479 s
.showElement(effect
.element
);
1481 afterUpdateInternal: function (effect
) {
1482 s
.setStyle(effect
.element
.firstChild
,
1483 {bottom
: (effect
.dims
[0] - effect
.element
.clientHeight
) + 'px'});
1485 afterFinishInternal: function (effect
) {
1486 s
.hideElement(effect
.element
);
1487 d
.undoClipping(effect
.element
, elemClip
);
1488 d
.undoPositioned(effect
.element
.firstChild
);
1489 d
.undoPositioned(effect
.element
);
1490 s
.setStyle(effect
.element
.firstChild
, {bottom
: oldInnerBottom
});
1493 return new MochiKit
.Visual
.Scale(element
, 0, options
);
1496 // Bug in opera makes the TD containing this element expand for a instance
1498 /** @id MochiKit.Visual.squish */
1499 MochiKit
.Visual
.squish = function (element
, /* optional */ options
) {
1502 Reduce an element and make it disappear.
1505 var d
= MochiKit
.DOM
;
1506 var b
= MochiKit
.Base
;
1508 options
= b
.update({
1509 restoreAfterFinish
: true,
1510 beforeSetupInternal: function (effect
) {
1511 elemClip
= d
.makeClipping(effect
.element
);
1513 afterFinishInternal: function (effect
) {
1514 MochiKit
.Style
.hideElement(effect
.element
);
1515 d
.undoClipping(effect
.element
, elemClip
);
1519 return new MochiKit
.Visual
.Scale(element
, /Opera/.test(navigator
.userAgent
) ? 1 : 0, options
);
1522 /** @id MochiKit.Visual.grow */
1523 MochiKit
.Visual
.grow = function (element
, /* optional */ options
) {
1526 Grow an element to its original size. Make it zero-sized before
1530 var d
= MochiKit
.DOM
;
1531 var v
= MochiKit
.Visual
;
1532 var s
= MochiKit
.Style
;
1533 element
= d
.getElement(element
);
1534 options
= MochiKit
.Base
.update({
1535 direction
: 'center',
1536 moveTransition
: v
.Transitions
.sinoidal
,
1537 scaleTransition
: v
.Transitions
.sinoidal
,
1538 opacityTransition
: v
.Transitions
.full
1541 top
: element
.style
.top
,
1542 left
: element
.style
.left
,
1543 height
: element
.style
.height
,
1544 width
: element
.style
.width
,
1545 opacity
: element
.style
.opacity
|| ''
1548 var dims
= s
.getElementDimensions(element
);
1549 var initialMoveX
, initialMoveY
;
1552 switch (options
.direction
) {
1554 initialMoveX
= initialMoveY
= moveX
= moveY
= 0;
1557 initialMoveX
= dims
.w
;
1558 initialMoveY
= moveY
= 0;
1562 initialMoveX
= moveX
= 0;
1563 initialMoveY
= dims
.h
;
1566 case 'bottom-right':
1567 initialMoveX
= dims
.w
;
1568 initialMoveY
= dims
.h
;
1573 initialMoveX
= dims
.w
/ 2;
1574 initialMoveY
= dims
.h
/ 2;
1575 moveX
= -dims
.w
/ 2;
1576 moveY
= -dims
.h
/ 2;
1580 var optionsParallel
= MochiKit
.Base
.update({
1581 beforeSetupInternal: function (effect
) {
1582 s
.setStyle(effect
.effects
[0].element
, {height
: '0px'});
1583 s
.showElement(effect
.effects
[0].element
);
1585 afterFinishInternal: function (effect
) {
1586 d
.undoClipping(effect
.effects
[0].element
);
1587 d
.undoPositioned(effect
.effects
[0].element
);
1588 s
.setStyle(effect
.effects
[0].element
, oldStyle
);
1592 return new v
.Move(element
, {
1596 beforeSetupInternal: function (effect
) {
1597 s
.hideElement(effect
.element
);
1598 d
.makeClipping(effect
.element
);
1599 d
.makePositioned(effect
.element
);
1601 afterFinishInternal: function (effect
) {
1603 [new v
.Opacity(effect
.element
, {
1604 sync
: true, to
: 1.0, from: 0.0,
1605 transition
: options
.opacityTransition
1607 new v
.Move(effect
.element
, {
1608 x
: moveX
, y
: moveY
, sync
: true,
1609 transition
: options
.moveTransition
1611 new v
.Scale(effect
.element
, 100, {
1612 scaleMode
: {originalHeight
: dims
.h
,
1613 originalWidth
: dims
.w
},
1615 scaleFrom
: /Opera/.test(navigator
.userAgent
) ? 1 : 0,
1616 transition
: options
.scaleTransition
,
1617 restoreAfterFinish
: true
1625 /** @id MochiKit.Visual.shrink */
1626 MochiKit
.Visual
.shrink = function (element
, /* optional */ options
) {
1629 Shrink an element and make it disappear.
1632 var d
= MochiKit
.DOM
;
1633 var v
= MochiKit
.Visual
;
1634 var s
= MochiKit
.Style
;
1635 element
= d
.getElement(element
);
1636 options
= MochiKit
.Base
.update({
1637 direction
: 'center',
1638 moveTransition
: v
.Transitions
.sinoidal
,
1639 scaleTransition
: v
.Transitions
.sinoidal
,
1640 opacityTransition
: v
.Transitions
.none
1643 top
: element
.style
.top
,
1644 left
: element
.style
.left
,
1645 height
: element
.style
.height
,
1646 width
: element
.style
.width
,
1647 opacity
: element
.style
.opacity
|| ''
1650 var dims
= s
.getElementDimensions(element
);
1653 switch (options
.direction
) {
1665 case 'bottom-right':
1676 var optionsParallel
= MochiKit
.Base
.update({
1677 beforeStartInternal: function (effect
) {
1678 elemClip
= d
.makePositioned(effect
.effects
[0].element
);
1679 d
.makeClipping(effect
.effects
[0].element
);
1681 afterFinishInternal: function (effect
) {
1682 s
.hideElement(effect
.effects
[0].element
);
1683 d
.undoClipping(effect
.effects
[0].element
, elemClip
);
1684 d
.undoPositioned(effect
.effects
[0].element
);
1685 s
.setStyle(effect
.effects
[0].element
, oldStyle
);
1689 return new v
.Parallel(
1690 [new v
.Opacity(element
, {
1691 sync
: true, to
: 0.0, from: 1.0,
1692 transition
: options
.opacityTransition
1694 new v
.Scale(element
, /Opera/.test(navigator
.userAgent
) ? 1 : 0, {
1695 sync
: true, transition
: options
.scaleTransition
,
1696 restoreAfterFinish
: true
1698 new v
.Move(element
, {
1699 x
: moveX
, y
: moveY
, sync
: true, transition
: options
.moveTransition
1705 /** @id MochiKit.Visual.pulsate */
1706 MochiKit
.Visual
.pulsate = function (element
, /* optional */ options
) {
1709 Pulse an element between appear/fade.
1712 var d
= MochiKit
.DOM
;
1713 var v
= MochiKit
.Visual
;
1714 var b
= MochiKit
.Base
;
1715 var oldOpacity
= d
.getElement(element
).style
.opacity
|| '';
1716 options
= b
.update({
1719 afterFinishInternal: function (effect
) {
1720 MochiKit
.Style
.setStyle(effect
.element
, {opacity
: oldOpacity
});
1723 var transition
= options
.transition
|| v
.Transitions
.sinoidal
;
1724 var reverser
= b
.bind(function (pos
) {
1725 return transition(1 - v
.Transitions
.pulse(pos
));
1727 b
.bind(reverser
, transition
);
1728 return new v
.Opacity(element
, b
.update({
1729 transition
: reverser
}, options
));
1732 /** @id MochiKit.Visual.fold */
1733 MochiKit
.Visual
.fold = function (element
, /* optional */ options
) {
1736 Fold an element, first vertically, then horizontally.
1739 var d
= MochiKit
.DOM
;
1740 var v
= MochiKit
.Visual
;
1741 var s
= MochiKit
.Style
;
1742 element
= d
.getElement(element
);
1744 top
: element
.style
.top
,
1745 left
: element
.style
.left
,
1746 width
: element
.style
.width
,
1747 height
: element
.style
.height
1749 var elemClip
= d
.makeClipping(element
);
1750 options
= MochiKit
.Base
.update({
1751 scaleContent
: false,
1753 afterFinishInternal: function (effect
) {
1754 new v
.Scale(element
, 1, {
1755 scaleContent
: false,
1757 afterFinishInternal: function (effect
) {
1758 s
.hideElement(effect
.element
);
1759 d
.undoClipping(effect
.element
, elemClip
);
1760 s
.setStyle(effect
.element
, oldStyle
);
1765 return new v
.Scale(element
, 5, options
);
1769 // Compatibility with MochiKit 1.0
1770 MochiKit
.Visual
.Color
= MochiKit
.Color
.Color
;
1771 MochiKit
.Visual
.getElementsComputedStyle
= MochiKit
.DOM
.computedStyle
;
1773 /* end of Rico adaptation */
1775 MochiKit
.Visual
.__new__ = function () {
1776 var m
= MochiKit
.Base
;
1778 m
.nameFunctions(this);
1780 this.EXPORT_TAGS
= {
1781 ":common": this.EXPORT
,
1782 ":all": m
.concat(this.EXPORT
, this.EXPORT_OK
)
1787 MochiKit
.Visual
.EXPORT
= [
1817 MochiKit
.Visual
.EXPORT_OK
= [
1821 MochiKit
.Visual
.__new__();
1823 MochiKit
.Base
._exportSymbols(this, MochiKit
.Visual
);