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
) {
501 return (Math
.floor(pos
*10) % 2 === 0 ?
502 (pos
*10 - Math
.floor(pos
*10)) : 1 - (pos
*10 - Math
.floor(pos
*10)));
505 /** @id MochiKit.Visual.Transitions.none */
506 MochiKit
.Visual
.Transitions
.none = function (pos
) {
510 /** @id MochiKit.Visual.Transitions.full */
511 MochiKit
.Visual
.Transitions
.full = function (pos
) {
521 MochiKit
.Visual
.ScopedQueue = function () {
522 var cls
= arguments
.callee
;
523 if (!(this instanceof cls
)) {
529 MochiKit
.Base
.update(MochiKit
.Visual
.ScopedQueue
.prototype, {
530 __init__: function () {
532 this.interval
= null;
535 /** @id MochiKit.Visual.ScopedQueue.prototype.add */
536 add: function (effect
) {
537 var timestamp
= new Date().getTime();
539 var position
= (typeof(effect
.options
.queue
) == 'string') ?
540 effect
.options
.queue
: effect
.options
.queue
.position
;
542 var ma
= MochiKit
.Base
.map
;
545 // move unstarted effects after this effect
547 if (e
.state
== 'idle') {
548 e
.startOn
+= effect
.finishOn
;
549 e
.finishOn
+= effect
.finishOn
;
555 // start effect after last queued effect has finished
558 if (i
>= (finish
|| i
)) {
562 timestamp
= finish
|| timestamp
;
571 effect
.startOn
+= timestamp
;
572 effect
.finishOn
+= timestamp
;
573 if (!effect
.options
.queue
.limit
||
574 this.effects
.length
< effect
.options
.queue
.limit
) {
575 this.effects
.push(effect
);
578 if (!this.interval
) {
579 this.interval
= this.startLoop(MochiKit
.Base
.bind(this.loop
, this),
584 /** @id MochiKit.Visual.ScopedQueue.prototype.startLoop */
585 startLoop: function (func
, interval
) {
586 return setInterval(func
, interval
);
589 /** @id MochiKit.Visual.ScopedQueue.prototype.remove */
590 remove: function (effect
) {
591 this.effects
= MochiKit
.Base
.filter(function (e
) {
594 if (!this.effects
.length
) {
595 this.stopLoop(this.interval
);
596 this.interval
= null;
600 /** @id MochiKit.Visual.ScopedQueue.prototype.stopLoop */
601 stopLoop: function (interval
) {
602 clearInterval(interval
);
605 /** @id MochiKit.Visual.ScopedQueue.prototype.loop */
607 var timePos
= new Date().getTime();
608 MochiKit
.Base
.map(function (effect
) {
609 effect
.loop(timePos
);
614 MochiKit
.Visual
.Queues
= {
617 get: function (queueName
) {
618 if (typeof(queueName
) != 'string') {
622 if (!this.instances
[queueName
]) {
623 this.instances
[queueName
] = new MochiKit
.Visual
.ScopedQueue();
625 return this.instances
[queueName
];
629 MochiKit
.Visual
.Queue
= MochiKit
.Visual
.Queues
.get('global');
631 MochiKit
.Visual
.DefaultOptions
= {
632 transition
: MochiKit
.Visual
.Transitions
.sinoidal
,
633 duration
: 1.0, // seconds
634 fps
: 25.0, // max. 25fps due to MochiKit.Visual.Queue implementation
635 sync
: false, // true for combining
642 MochiKit
.Visual
.Base = function () {};
644 MochiKit
.Visual
.Base
.prototype = {
647 Basic class for all Effects. Define a looping mechanism called for each step
648 of an effect. Don't instantiate it, only subclass it.
652 __class__
: MochiKit
.Visual
.Base
,
654 /** @id MochiKit.Visual.Base.prototype.start */
655 start: function (options
) {
656 var v
= MochiKit
.Visual
;
657 this.options
= MochiKit
.Base
.setdefault(options
|| {},
659 this.currentFrame
= 0;
661 this.startOn
= this.options
.delay
*1000;
662 this.finishOn
= this.startOn
+ (this.options
.duration
*1000);
663 this.event('beforeStart');
664 if (!this.options
.sync
) {
665 v
.Queues
.get(typeof(this.options
.queue
) == 'string' ?
666 'global' : this.options
.queue
.scope
).add(this);
670 /** @id MochiKit.Visual.Base.prototype.loop */
671 loop: function (timePos
) {
672 if (timePos
>= this.startOn
) {
673 if (timePos
>= this.finishOn
) {
674 return this.finalize();
676 var pos
= (timePos
- this.startOn
) / (this.finishOn
- this.startOn
);
678 Math
.round(pos
* this.options
.fps
* this.options
.duration
);
679 if (frame
> this.currentFrame
) {
681 this.currentFrame
= frame
;
686 /** @id MochiKit.Visual.Base.prototype.render */
687 render: function (pos
) {
688 if (this.state
== 'idle') {
689 this.state
= 'running';
690 this.event('beforeSetup');
692 this.event('afterSetup');
694 if (this.state
== 'running') {
695 if (this.options
.transition
) {
696 pos
= this.options
.transition(pos
);
698 pos
*= (this.options
.to
- this.options
.from);
699 pos
+= this.options
.from;
700 this.event('beforeUpdate');
702 this.event('afterUpdate');
706 /** @id MochiKit.Visual.Base.prototype.cancel */
707 cancel: function () {
708 if (!this.options
.sync
) {
709 MochiKit
.Visual
.Queues
.get(typeof(this.options
.queue
) == 'string' ?
710 'global' : this.options
.queue
.scope
).remove(this);
712 this.state
= 'finished';
715 /** @id MochiKit.Visual.Base.prototype.finalize */
716 finalize: function () {
719 this.event('beforeFinish');
721 this.event('afterFinish');
727 finish: function () {
730 update: function (position
) {
733 /** @id MochiKit.Visual.Base.prototype.event */
734 event: function (eventName
) {
735 if (this.options
[eventName
+ 'Internal']) {
736 this.options
[eventName
+ 'Internal'](this);
738 if (this.options
[eventName
]) {
739 this.options
[eventName
](this);
743 /** @id MochiKit.Visual.Base.prototype.repr */
745 return '[' + this.__class__
.NAME
+ ', options:' +
746 MochiKit
.Base
.repr(this.options
) + ']';
750 /** @id MochiKit.Visual.Parallel */
751 MochiKit
.Visual
.Parallel = function (effects
, options
) {
752 var cls
= arguments
.callee
;
753 if (!(this instanceof cls
)) {
754 return new cls(effects
, options
);
757 this.__init__(effects
, options
);
760 MochiKit
.Visual
.Parallel
.prototype = new MochiKit
.Visual
.Base();
762 MochiKit
.Base
.update(MochiKit
.Visual
.Parallel
.prototype, {
765 Run multiple effects at the same time.
769 __class__
: MochiKit
.Visual
.Parallel
,
771 __init__: function (effects
, options
) {
772 this.effects
= effects
|| [];
776 /** @id MochiKit.Visual.Parallel.prototype.update */
777 update: function (position
) {
778 MochiKit
.Base
.map(function (effect
) {
779 effect
.render(position
);
783 /** @id MochiKit.Visual.Parallel.prototype.finish */
784 finish: function () {
785 MochiKit
.Base
.map(function (effect
) {
791 /** @id MochiKit.Visual.Opacity */
792 MochiKit
.Visual
.Opacity = function (element
, options
) {
793 var cls
= arguments
.callee
;
794 if (!(this instanceof cls
)) {
795 return new cls(element
, options
);
797 this.__init__(element
, options
);
800 MochiKit
.Visual
.Opacity
.prototype = new MochiKit
.Visual
.Base();
802 MochiKit
.Base
.update(MochiKit
.Visual
.Opacity
.prototype, {
805 Change the opacity of an element.
807 @param options: 'from' and 'to' change the starting and ending opacities.
808 Must be between 0.0 and 1.0. Default to current opacity and 1.0.
812 __class__
: MochiKit
.Visual
.Opacity
,
814 __init__: function (element
, /* optional */options
) {
815 var b
= MochiKit
.Base
;
816 var s
= MochiKit
.Style
;
817 this.element
= MochiKit
.DOM
.getElement(element
);
818 // make this work on IE on elements without 'layout'
819 if (this.element
.currentStyle
&&
820 (!this.element
.currentStyle
.hasLayout
)) {
821 s
.setStyle(this.element
, {zoom
: 1});
824 from: s
.getStyle(this.element
, 'opacity') || 0.0,
830 /** @id MochiKit.Visual.Opacity.prototype.update */
831 update: function (position
) {
832 MochiKit
.Style
.setStyle(this.element
, {'opacity': position
});
836 /** @id MochiKit.Visual.Move.prototype */
837 MochiKit
.Visual
.Move = function (element
, options
) {
838 var cls
= arguments
.callee
;
839 if (!(this instanceof cls
)) {
840 return new cls(element
, options
);
842 this.__init__(element
, options
);
845 MochiKit
.Visual
.Move
.prototype = new MochiKit
.Visual
.Base();
847 MochiKit
.Base
.update(MochiKit
.Visual
.Move
.prototype, {
850 Move an element between its current position to a defined position
852 @param options: 'x' and 'y' for final positions, default to 0, 0.
856 __class__
: MochiKit
.Visual
.Move
,
858 __init__: function (element
, /* optional */options
) {
859 this.element
= MochiKit
.DOM
.getElement(element
);
860 options
= MochiKit
.Base
.update({
868 /** @id MochiKit.Visual.Move.prototype.setup */
870 // Bug in Opera: Opera returns the 'real' position of a static element
871 // or relative element that does not have top/left explicitly set.
872 // ==> Always set top and left for position relative elements in your
873 // stylesheets (to 0 if you do not need them)
874 MochiKit
.DOM
.makePositioned(this.element
);
876 var s
= this.element
.style
;
877 var originalVisibility
= s
.visibility
;
878 var originalDisplay
= s
.display
;
879 if (originalDisplay
== 'none') {
880 s
.visibility
= 'hidden';
884 this.originalLeft
= parseFloat(MochiKit
.Style
.getStyle(this.element
, 'left') || '0');
885 this.originalTop
= parseFloat(MochiKit
.Style
.getStyle(this.element
, 'top') || '0');
887 if (this.options
.mode
== 'absolute') {
888 // absolute movement, so we need to calc deltaX and deltaY
889 this.options
.x
-= this.originalLeft
;
890 this.options
.y
-= this.originalTop
;
892 if (originalDisplay
== 'none') {
893 s
.visibility
= originalVisibility
;
894 s
.display
= originalDisplay
;
898 /** @id MochiKit.Visual.Move.prototype.update */
899 update: function (position
) {
900 MochiKit
.Style
.setStyle(this.element
, {
901 left
: Math
.round(this.options
.x
* position
+ this.originalLeft
) + 'px',
902 top
: Math
.round(this.options
.y
* position
+ this.originalTop
) + 'px'
907 /** @id MochiKit.Visual.Scale */
908 MochiKit
.Visual
.Scale = function (element
, percent
, options
) {
909 var cls
= arguments
.callee
;
910 if (!(this instanceof cls
)) {
911 return new cls(element
, percent
, options
);
913 this.__init__(element
, percent
, options
);
916 MochiKit
.Visual
.Scale
.prototype = new MochiKit
.Visual
.Base();
918 MochiKit
.Base
.update(MochiKit
.Visual
.Scale
.prototype, {
921 Change the size of an element.
923 @param percent: final_size = percent*original_size
925 @param options: several options changing scale behaviour
929 __class__
: MochiKit
.Visual
.Scale
,
931 __init__: function (element
, percent
, /* optional */options
) {
932 this.element
= MochiKit
.DOM
.getElement(element
);
933 options
= MochiKit
.Base
.update({
937 scaleFromCenter
: false,
938 scaleMode
: 'box', // 'box' or 'contents' or {} with provided values
945 /** @id MochiKit.Visual.Scale.prototype.setup */
947 this.restoreAfterFinish
= this.options
.restoreAfterFinish
|| false;
948 this.elementPositioning
= MochiKit
.Style
.getStyle(this.element
,
951 var ma
= MochiKit
.Base
.map
;
952 var b
= MochiKit
.Base
.bind
;
953 this.originalStyle
= {};
955 this.originalStyle
[k
] = this.element
.style
[k
];
956 }, this), ['top', 'left', 'width', 'height', 'fontSize']);
958 this.originalTop
= this.element
.offsetTop
;
959 this.originalLeft
= this.element
.offsetLeft
;
961 var fontSize
= MochiKit
.Style
.getStyle(this.element
,
962 'font-size') || '100%';
963 ma(b(function (fontSizeType
) {
964 if (fontSize
.indexOf(fontSizeType
) > 0) {
965 this.fontSize
= parseFloat(fontSize
);
966 this.fontSizeType
= fontSizeType
;
968 }, this), ['em', 'px', '%']);
970 this.factor
= (this.options
.scaleTo
- this.options
.scaleFrom
)/100;
972 if (/^content/.test(this.options
.scaleMode
)) {
973 this.dims
= [this.element
.scrollHeight
, this.element
.scrollWidth
];
974 } else if (this.options
.scaleMode
== 'box') {
975 this.dims
= [this.element
.offsetHeight
, this.element
.offsetWidth
];
977 this.dims
= [this.options
.scaleMode
.originalHeight
,
978 this.options
.scaleMode
.originalWidth
];
982 /** @id MochiKit.Visual.Scale.prototype.update */
983 update: function (position
) {
984 var currentScale
= (this.options
.scaleFrom
/100.0) +
985 (this.factor
* position
);
986 if (this.options
.scaleContent
&& this.fontSize
) {
987 MochiKit
.Style
.setStyle(this.element
, {
988 fontSize
: this.fontSize
* currentScale
+ this.fontSizeType
991 this.setDimensions(this.dims
[0] * currentScale
,
992 this.dims
[1] * currentScale
);
995 /** @id MochiKit.Visual.Scale.prototype.finish */
996 finish: function () {
997 if (this.restoreAfterFinish
) {
998 MochiKit
.Style
.setStyle(this.element
, this.originalStyle
);
1002 /** @id MochiKit.Visual.Scale.prototype.setDimensions */
1003 setDimensions: function (height
, width
) {
1006 if (/MSIE/.test(navigator
.userAgent
)) {
1009 if (this.options
.scaleX
) {
1010 d
.width
= r(width
) + 'px';
1012 if (this.options
.scaleY
) {
1013 d
.height
= r(height
) + 'px';
1015 if (this.options
.scaleFromCenter
) {
1016 var topd
= (height
- this.dims
[0])/2;
1017 var leftd
= (width
- this.dims
[1])/2;
1018 if (this.elementPositioning
== 'absolute') {
1019 if (this.options
.scaleY
) {
1020 d
.top
= this.originalTop
- topd
+ 'px';
1022 if (this.options
.scaleX
) {
1023 d
.left
= this.originalLeft
- leftd
+ 'px';
1026 if (this.options
.scaleY
) {
1027 d
.top
= -topd
+ 'px';
1029 if (this.options
.scaleX
) {
1030 d
.left
= -leftd
+ 'px';
1034 MochiKit
.Style
.setStyle(this.element
, d
);
1038 /** @id MochiKit.Visual.Highlight */
1039 MochiKit
.Visual
.Highlight = function (element
, options
) {
1040 var cls
= arguments
.callee
;
1041 if (!(this instanceof cls
)) {
1042 return new cls(element
, options
);
1044 this.__init__(element
, options
);
1047 MochiKit
.Visual
.Highlight
.prototype = new MochiKit
.Visual
.Base();
1049 MochiKit
.Base
.update(MochiKit
.Visual
.Highlight
.prototype, {
1052 Highlight an item of the page.
1054 @param options: 'startcolor' for choosing highlighting color, default
1059 __class__
: MochiKit
.Visual
.Highlight
,
1061 __init__: function (element
, /* optional */options
) {
1062 this.element
= MochiKit
.DOM
.getElement(element
);
1063 options
= MochiKit
.Base
.update({
1064 startcolor
: '#ffff99'
1066 this.start(options
);
1069 /** @id MochiKit.Visual.Highlight.prototype.setup */
1070 setup: function () {
1071 var b
= MochiKit
.Base
;
1072 var s
= MochiKit
.Style
;
1073 // Prevent executing on elements not in the layout flow
1074 if (s
.getStyle(this.element
, 'display') == 'none') {
1078 // Disable background image during the effect
1080 backgroundImage
: s
.getStyle(this.element
, 'background-image')
1082 s
.setStyle(this.element
, {
1083 backgroundImage
: 'none'
1086 if (!this.options
.endcolor
) {
1087 this.options
.endcolor
=
1088 MochiKit
.Color
.Color
.fromBackground(this.element
).toHexString();
1090 if (b
.isUndefinedOrNull(this.options
.restorecolor
)) {
1091 this.options
.restorecolor
= s
.getStyle(this.element
,
1092 'background-color');
1094 // init color calculations
1095 this._base
= b
.map(b
.bind(function (i
) {
1097 this.options
.startcolor
.slice(i
*2 + 1, i
*2 + 3), 16);
1098 }, this), [0, 1, 2]);
1099 this._delta
= b
.map(b
.bind(function (i
) {
1100 return parseInt(this.options
.endcolor
.slice(i
*2 + 1, i
*2 + 3), 16)
1102 }, this), [0, 1, 2]);
1105 /** @id MochiKit.Visual.Highlight.prototype.update */
1106 update: function (position
) {
1108 MochiKit
.Base
.map(MochiKit
.Base
.bind(function (i
) {
1109 m
+= MochiKit
.Color
.toColorPart(Math
.round(this._base
[i
] +
1110 this._delta
[i
]*position
));
1111 }, this), [0, 1, 2]);
1112 MochiKit
.Style
.setStyle(this.element
, {
1117 /** @id MochiKit.Visual.Highlight.prototype.finish */
1118 finish: function () {
1119 MochiKit
.Style
.setStyle(this.element
,
1120 MochiKit
.Base
.update(this.oldStyle
, {
1121 backgroundColor
: this.options
.restorecolor
1126 /** @id MochiKit.Visual.ScrollTo */
1127 MochiKit
.Visual
.ScrollTo = function (element
, options
) {
1128 var cls
= arguments
.callee
;
1129 if (!(this instanceof cls
)) {
1130 return new cls(element
, options
);
1132 this.__init__(element
, options
);
1135 MochiKit
.Visual
.ScrollTo
.prototype = new MochiKit
.Visual
.Base();
1137 MochiKit
.Base
.update(MochiKit
.Visual
.ScrollTo
.prototype, {
1140 Scroll to an element in the page.
1144 __class__
: MochiKit
.Visual
.ScrollTo
,
1146 __init__: function (element
, /* optional */options
) {
1147 this.element
= MochiKit
.DOM
.getElement(element
);
1148 this.start(options
|| {});
1151 /** @id MochiKit.Visual.ScrollTo.prototype.setup */
1152 setup: function () {
1153 var p
= MochiKit
.Position
;
1155 var offsets
= p
.cumulativeOffset(this.element
);
1156 if (this.options
.offset
) {
1157 offsets
.y
+= this.options
.offset
;
1160 if (window
.innerHeight
) {
1161 max
= window
.innerHeight
- window
.height
;
1162 } else if (document
.documentElement
&&
1163 document
.documentElement
.clientHeight
) {
1164 max
= document
.documentElement
.clientHeight
-
1165 document
.body
.scrollHeight
;
1166 } else if (document
.body
) {
1167 max
= document
.body
.clientHeight
- document
.body
.scrollHeight
;
1169 this.scrollStart
= p
.windowOffset
.y
;
1170 this.delta
= (offsets
.y
> max
? max
: offsets
.y
) - this.scrollStart
;
1173 /** @id MochiKit.Visual.ScrollTo.prototype.update */
1174 update: function (position
) {
1175 var p
= MochiKit
.Position
;
1177 window
.scrollTo(p
.windowOffset
.x
, this.scrollStart
+ (position
* this.delta
));
1181 MochiKit
.Visual
.CSS_LENGTH
= /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
1183 MochiKit
.Visual
.Morph = function (element
, options
) {
1184 var cls
= arguments
.callee
;
1185 if (!(this instanceof cls
)) {
1186 return new cls(element
, options
);
1188 this.__init__(element
, options
);
1191 MochiKit
.Visual
.Morph
.prototype = new MochiKit
.Visual
.Base();
1193 MochiKit
.Base
.update(MochiKit
.Visual
.Morph
.prototype, {
1196 Morph effect: make a transformation from current style to the given style,
1197 automatically making a transition between the two.
1201 __class__
: MochiKit
.Visual
.Morph
,
1203 __init__: function (element
, /* optional */options
) {
1204 this.element
= MochiKit
.DOM
.getElement(element
);
1205 this.start(options
|| {});
1208 /** @id MochiKit.Visual.Morph.prototype.setup */
1209 setup: function () {
1210 var b
= MochiKit
.Base
;
1211 var style
= this.options
.style
;
1212 this.styleStart
= {};
1216 for (var s
in style
) {
1219 if (MochiKit
.Visual
.CSS_LENGTH
.test(value
)) {
1220 var components
= value
.match(/^([\+\-]?[0-9\.]+)(.*)$/);
1221 value
= parseFloat(components
[1]);
1222 unit
= (components
.length
== 3) ? components
[2] : null;
1223 this.styleEnd
[s
] = value
;
1224 this.units
[s
] = unit
;
1225 value
= MochiKit
.Style
.getStyle(this.element
, s
);
1226 components
= value
.match(/^([\+\-]?[0-9\.]+)(.*)$/);
1227 value
= parseFloat(components
[1]);
1228 this.styleStart
[s
] = value
;
1230 var c
= MochiKit
.Color
.Color
;
1231 value
= c
.fromString(value
);
1233 this.units
[s
] = "color";
1234 this.styleEnd
[s
] = value
.toHexString();
1235 value
= MochiKit
.Style
.getStyle(this.element
, s
);
1236 this.styleStart
[s
] = c
.fromString(value
).toHexString();
1238 this.styleStart
[s
] = b
.map(b
.bind(function (i
) {
1240 this.styleStart
[s
].slice(i
*2 + 1, i
*2 + 3), 16);
1241 }, this), [0, 1, 2]);
1242 this.styleEnd
[s
] = b
.map(b
.bind(function (i
) {
1244 this.styleEnd
[s
].slice(i
*2 + 1, i
*2 + 3), 16);
1245 }, this), [0, 1, 2]);
1251 /** @id MochiKit.Visual.Morph.prototype.update */
1252 update: function (position
) {
1254 for (var s
in this.styleStart
) {
1255 if (this.units
[s
] == "color") {
1257 var start
= this.styleStart
[s
];
1258 var end
= this.styleEnd
[s
];
1259 MochiKit
.Base
.map(MochiKit
.Base
.bind(function (i
) {
1260 m
+= MochiKit
.Color
.toColorPart(Math
.round(start
[i
] +
1261 (end
[i
] - start
[i
])*position
));
1262 }, this), [0, 1, 2]);
1263 this.element
.style
[s
] = m
;
1265 value
= this.styleStart
[s
] + Math
.round((this.styleEnd
[s
] - this.styleStart
[s
]) * position
* 1000) / 1000 + this.units
[s
];
1266 this.element
.style
[s
] = value
;
1274 Combination effects.
1278 /** @id MochiKit.Visual.fade */
1279 MochiKit
.Visual
.fade = function (element
, /* optional */ options
) {
1282 Fade a given element: change its opacity and hide it in the end.
1284 @param options: 'to' and 'from' to change opacity.
1287 var s
= MochiKit
.Style
;
1288 var oldOpacity
= s
.getStyle(element
, 'opacity');
1289 options
= MochiKit
.Base
.update({
1290 from: s
.getStyle(element
, 'opacity') || 1.0,
1292 afterFinishInternal: function (effect
) {
1293 if (effect
.options
.to
!== 0) {
1296 s
.hideElement(effect
.element
);
1297 s
.setStyle(effect
.element
, {'opacity': oldOpacity
});
1300 return new MochiKit
.Visual
.Opacity(element
, options
);
1303 /** @id MochiKit.Visual.appear */
1304 MochiKit
.Visual
.appear = function (element
, /* optional */ options
) {
1307 Make an element appear.
1309 @param options: 'to' and 'from' to change opacity.
1312 var s
= MochiKit
.Style
;
1313 var v
= MochiKit
.Visual
;
1314 options
= MochiKit
.Base
.update({
1315 from: (s
.getStyle(element
, 'display') == 'none' ? 0.0 :
1316 s
.getStyle(element
, 'opacity') || 0.0),
1318 // force Safari to render floated elements properly
1319 afterFinishInternal: function (effect
) {
1320 v
.forceRerendering(effect
.element
);
1322 beforeSetupInternal: function (effect
) {
1323 s
.setStyle(effect
.element
, {'opacity': effect
.options
.from});
1324 s
.showElement(effect
.element
);
1327 return new v
.Opacity(element
, options
);
1330 /** @id MochiKit.Visual.puff */
1331 MochiKit
.Visual
.puff = function (element
, /* optional */ options
) {
1334 'Puff' an element: grow it to double size, fading it and make it hidden.
1337 var s
= MochiKit
.Style
;
1338 var v
= MochiKit
.Visual
;
1339 element
= MochiKit
.DOM
.getElement(element
);
1341 position
: s
.getStyle(element
, 'position'),
1342 top
: element
.style
.top
,
1343 left
: element
.style
.left
,
1344 width
: element
.style
.width
,
1345 height
: element
.style
.height
,
1346 opacity
: s
.getStyle(element
, 'opacity')
1348 options
= MochiKit
.Base
.update({
1349 beforeSetupInternal: function (effect
) {
1350 MochiKit
.Position
.absolutize(effect
.effects
[0].element
);
1352 afterFinishInternal: function (effect
) {
1353 s
.hideElement(effect
.effects
[0].element
);
1354 s
.setStyle(effect
.effects
[0].element
, oldStyle
);
1357 scaleFromCenter
: true
1359 return new v
.Parallel(
1360 [new v
.Scale(element
, 200,
1361 {sync
: true, scaleFromCenter
: options
.scaleFromCenter
,
1362 scaleContent
: options
.scaleContent
, restoreAfterFinish
: true}),
1363 new v
.Opacity(element
, {sync
: true, to
: 0.0 })],
1367 /** @id MochiKit.Visual.blindUp */
1368 MochiKit
.Visual
.blindUp = function (element
, /* optional */ options
) {
1371 Blind an element up: change its vertical size to 0.
1374 var d
= MochiKit
.DOM
;
1375 element
= d
.getElement(element
);
1376 var elemClip
= d
.makeClipping(element
);
1377 options
= MochiKit
.Base
.update({
1378 scaleContent
: false,
1380 restoreAfterFinish
: true,
1381 afterFinishInternal: function (effect
) {
1382 MochiKit
.Style
.hideElement(effect
.element
);
1383 d
.undoClipping(effect
.element
, elemClip
);
1387 return new MochiKit
.Visual
.Scale(element
, 0, options
);
1390 /** @id MochiKit.Visual.blindDown */
1391 MochiKit
.Visual
.blindDown = function (element
, /* optional */ options
) {
1394 Blind an element down: restore its vertical size.
1397 var d
= MochiKit
.DOM
;
1398 var s
= MochiKit
.Style
;
1399 element
= d
.getElement(element
);
1400 var elementDimensions
= s
.getElementDimensions(element
);
1402 options
= MochiKit
.Base
.update({
1403 scaleContent
: false,
1406 scaleMode
: {originalHeight
: elementDimensions
.h
,
1407 originalWidth
: elementDimensions
.w
},
1408 restoreAfterFinish
: true,
1409 afterSetupInternal: function (effect
) {
1410 elemClip
= d
.makeClipping(effect
.element
);
1411 s
.setStyle(effect
.element
, {height
: '0px'});
1412 s
.showElement(effect
.element
);
1414 afterFinishInternal: function (effect
) {
1415 d
.undoClipping(effect
.element
, elemClip
);
1418 return new MochiKit
.Visual
.Scale(element
, 100, options
);
1421 /** @id MochiKit.Visual.switchOff */
1422 MochiKit
.Visual
.switchOff = function (element
, /* optional */ options
) {
1425 Apply a switch-off-like effect.
1428 var d
= MochiKit
.DOM
;
1429 element
= d
.getElement(element
);
1430 var oldOpacity
= MochiKit
.Style
.getStyle(element
, 'opacity');
1432 options
= MochiKit
.Base
.update({
1434 scaleFromCenter
: true,
1436 scaleContent
: false,
1437 restoreAfterFinish
: true,
1438 beforeSetupInternal: function (effect
) {
1439 d
.makePositioned(effect
.element
);
1440 elemClip
= d
.makeClipping(effect
.element
);
1442 afterFinishInternal: function (effect
) {
1443 MochiKit
.Style
.hideElement(effect
.element
);
1444 d
.undoClipping(effect
.element
, elemClip
);
1445 d
.undoPositioned(effect
.element
);
1446 MochiKit
.Style
.setStyle(effect
.element
, {'opacity': oldOpacity
});
1449 var v
= MochiKit
.Visual
;
1450 return new v
.appear(element
, {
1453 transition
: v
.Transitions
.flicker
,
1454 afterFinishInternal: function (effect
) {
1455 new v
.Scale(effect
.element
, 1, options
);
1460 /** @id MochiKit.Visual.dropOut */
1461 MochiKit
.Visual
.dropOut = function (element
, /* optional */ options
) {
1464 Make an element fall and disappear.
1467 var d
= MochiKit
.DOM
;
1468 var s
= MochiKit
.Style
;
1469 element
= d
.getElement(element
);
1471 top
: s
.getStyle(element
, 'top'),
1472 left
: s
.getStyle(element
, 'left'),
1473 opacity
: s
.getStyle(element
, 'opacity')
1476 options
= MochiKit
.Base
.update({
1479 beforeSetupInternal: function (effect
) {
1480 d
.makePositioned(effect
.effects
[0].element
);
1482 afterFinishInternal: function (effect
) {
1483 s
.hideElement(effect
.effects
[0].element
);
1484 d
.undoPositioned(effect
.effects
[0].element
);
1485 s
.setStyle(effect
.effects
[0].element
, oldStyle
);
1488 var v
= MochiKit
.Visual
;
1489 return new v
.Parallel(
1490 [new v
.Move(element
, {x
: 0, y
: options
.distance
, sync
: true}),
1491 new v
.Opacity(element
, {sync
: true, to
: 0.0})],
1495 /** @id MochiKit.Visual.shake */
1496 MochiKit
.Visual
.shake = function (element
, /* optional */ options
) {
1499 Move an element from left to right several times.
1502 var d
= MochiKit
.DOM
;
1503 var v
= MochiKit
.Visual
;
1504 var s
= MochiKit
.Style
;
1505 element
= d
.getElement(element
);
1506 options
= MochiKit
.Base
.update({
1510 afterFinishInternal: function (effect
) {
1511 d
.undoPositioned(effect
.element
);
1512 s
.setStyle(effect
.element
, oldStyle
);
1516 top
: s
.getStyle(element
, 'top'),
1517 left
: s
.getStyle(element
, 'left') };
1518 return new v
.Move(element
,
1519 {x
: 20, y
: 0, duration
: 0.05, afterFinishInternal: function (effect
) {
1520 new v
.Move(effect
.element
,
1521 {x
: -40, y
: 0, duration
: 0.1, afterFinishInternal: function (effect
) {
1522 new v
.Move(effect
.element
,
1523 {x
: 40, y
: 0, duration
: 0.1, afterFinishInternal: function (effect
) {
1524 new v
.Move(effect
.element
,
1525 {x
: -40, y
: 0, duration
: 0.1, afterFinishInternal: function (effect
) {
1526 new v
.Move(effect
.element
,
1527 {x
: 40, y
: 0, duration
: 0.1, afterFinishInternal: function (effect
) {
1528 new v
.Move(effect
.element
, options
1529 ) }}) }}) }}) }}) }});
1532 /** @id MochiKit.Visual.slideDown */
1533 MochiKit
.Visual
.slideDown = function (element
, /* optional */ options
) {
1536 Slide an element down.
1537 It needs to have the content of the element wrapped in a container
1538 element with fixed height.
1541 var d
= MochiKit
.DOM
;
1542 var b
= MochiKit
.Base
;
1543 var s
= MochiKit
.Style
;
1544 element
= d
.getElement(element
);
1545 if (!element
.firstChild
) {
1546 throw "MochiKit.Visual.slideDown must be used on a element with a child";
1548 d
.removeEmptyTextNodes(element
);
1549 var oldInnerBottom
= s
.getStyle(element
.firstChild
, 'bottom') || 0;
1550 var elementDimensions
= s
.getElementDimensions(element
);
1552 options
= b
.update({
1553 scaleContent
: false,
1556 scaleMode
: {originalHeight
: elementDimensions
.h
,
1557 originalWidth
: elementDimensions
.w
},
1558 restoreAfterFinish
: true,
1559 afterSetupInternal: function (effect
) {
1560 d
.makePositioned(effect
.element
);
1561 d
.makePositioned(effect
.element
.firstChild
);
1562 if (/Opera/.test(navigator
.userAgent
)) {
1563 s
.setStyle(effect
.element
, {top
: ''});
1565 elemClip
= d
.makeClipping(effect
.element
);
1566 s
.setStyle(effect
.element
, {height
: '0px'});
1567 s
.showElement(effect
.element
);
1569 afterUpdateInternal: function (effect
) {
1570 s
.setStyle(effect
.element
.firstChild
,
1571 {bottom
: (effect
.dims
[0] - effect
.element
.clientHeight
) + 'px'});
1573 afterFinishInternal: function (effect
) {
1574 d
.undoClipping(effect
.element
, elemClip
);
1575 // IE will crash if child is undoPositioned first
1576 if (/MSIE/.test(navigator
.userAgent
)) {
1577 d
.undoPositioned(effect
.element
);
1578 d
.undoPositioned(effect
.element
.firstChild
);
1580 d
.undoPositioned(effect
.element
.firstChild
);
1581 d
.undoPositioned(effect
.element
);
1583 s
.setStyle(effect
.element
.firstChild
,
1584 {bottom
: oldInnerBottom
});
1588 return new MochiKit
.Visual
.Scale(element
, 100, options
);
1591 /** @id MochiKit.Visual.slideUp */
1592 MochiKit
.Visual
.slideUp = function (element
, /* optional */ options
) {
1595 Slide an element up.
1596 It needs to have the content of the element wrapped in a container
1597 element with fixed height.
1600 var d
= MochiKit
.DOM
;
1601 var b
= MochiKit
.Base
;
1602 var s
= MochiKit
.Style
;
1603 element
= d
.getElement(element
);
1604 if (!element
.firstChild
) {
1605 throw "MochiKit.Visual.slideUp must be used on a element with a child";
1607 d
.removeEmptyTextNodes(element
);
1608 var oldInnerBottom
= s
.getStyle(element
.firstChild
, 'bottom');
1610 options
= b
.update({
1611 scaleContent
: false,
1615 restoreAfterFinish
: true,
1616 beforeStartInternal: function (effect
) {
1617 d
.makePositioned(effect
.element
);
1618 d
.makePositioned(effect
.element
.firstChild
);
1619 if (/Opera/.test(navigator
.userAgent
)) {
1620 s
.setStyle(effect
.element
, {top
: ''});
1622 elemClip
= d
.makeClipping(effect
.element
);
1623 s
.showElement(effect
.element
);
1625 afterUpdateInternal: function (effect
) {
1626 s
.setStyle(effect
.element
.firstChild
,
1627 {bottom
: (effect
.dims
[0] - effect
.element
.clientHeight
) + 'px'});
1629 afterFinishInternal: function (effect
) {
1630 s
.hideElement(effect
.element
);
1631 d
.undoClipping(effect
.element
, elemClip
);
1632 d
.undoPositioned(effect
.element
.firstChild
);
1633 d
.undoPositioned(effect
.element
);
1634 s
.setStyle(effect
.element
.firstChild
, {bottom
: oldInnerBottom
});
1637 return new MochiKit
.Visual
.Scale(element
, 0, options
);
1640 // Bug in opera makes the TD containing this element expand for a instance
1642 /** @id MochiKit.Visual.squish */
1643 MochiKit
.Visual
.squish = function (element
, /* optional */ options
) {
1646 Reduce an element and make it disappear.
1649 var d
= MochiKit
.DOM
;
1650 var b
= MochiKit
.Base
;
1652 options
= b
.update({
1653 restoreAfterFinish
: true,
1654 beforeSetupInternal: function (effect
) {
1655 elemClip
= d
.makeClipping(effect
.element
);
1657 afterFinishInternal: function (effect
) {
1658 MochiKit
.Style
.hideElement(effect
.element
);
1659 d
.undoClipping(effect
.element
, elemClip
);
1663 return new MochiKit
.Visual
.Scale(element
, /Opera/.test(navigator
.userAgent
) ? 1 : 0, options
);
1666 /** @id MochiKit.Visual.grow */
1667 MochiKit
.Visual
.grow = function (element
, /* optional */ options
) {
1670 Grow an element to its original size. Make it zero-sized before
1674 var d
= MochiKit
.DOM
;
1675 var v
= MochiKit
.Visual
;
1676 var s
= MochiKit
.Style
;
1677 element
= d
.getElement(element
);
1678 options
= MochiKit
.Base
.update({
1679 direction
: 'center',
1680 moveTransition
: v
.Transitions
.sinoidal
,
1681 scaleTransition
: v
.Transitions
.sinoidal
,
1682 opacityTransition
: v
.Transitions
.full
,
1684 scaleFromCenter
: false
1687 top
: element
.style
.top
,
1688 left
: element
.style
.left
,
1689 height
: element
.style
.height
,
1690 width
: element
.style
.width
,
1691 opacity
: s
.getStyle(element
, 'opacity')
1694 var dims
= s
.getElementDimensions(element
);
1695 var initialMoveX
, initialMoveY
;
1698 switch (options
.direction
) {
1700 initialMoveX
= initialMoveY
= moveX
= moveY
= 0;
1703 initialMoveX
= dims
.w
;
1704 initialMoveY
= moveY
= 0;
1708 initialMoveX
= moveX
= 0;
1709 initialMoveY
= dims
.h
;
1712 case 'bottom-right':
1713 initialMoveX
= dims
.w
;
1714 initialMoveY
= dims
.h
;
1719 initialMoveX
= dims
.w
/ 2;
1720 initialMoveY
= dims
.h
/ 2;
1721 moveX
= -dims
.w
/ 2;
1722 moveY
= -dims
.h
/ 2;
1726 var optionsParallel
= MochiKit
.Base
.update({
1727 beforeSetupInternal: function (effect
) {
1728 s
.setStyle(effect
.effects
[0].element
, {height
: '0px'});
1729 s
.showElement(effect
.effects
[0].element
);
1731 afterFinishInternal: function (effect
) {
1732 d
.undoClipping(effect
.effects
[0].element
);
1733 d
.undoPositioned(effect
.effects
[0].element
);
1734 s
.setStyle(effect
.effects
[0].element
, oldStyle
);
1738 return new v
.Move(element
, {
1742 beforeSetupInternal: function (effect
) {
1743 s
.hideElement(effect
.element
);
1744 d
.makeClipping(effect
.element
);
1745 d
.makePositioned(effect
.element
);
1747 afterFinishInternal: function (effect
) {
1749 [new v
.Opacity(effect
.element
, {
1750 sync
: true, to
: 1.0, from: 0.0,
1751 transition
: options
.opacityTransition
1753 new v
.Move(effect
.element
, {
1754 x
: moveX
, y
: moveY
, sync
: true,
1755 transition
: options
.moveTransition
1757 new v
.Scale(effect
.element
, 100, {
1758 scaleMode
: {originalHeight
: dims
.h
,
1759 originalWidth
: dims
.w
},
1761 scaleFrom
: /Opera/.test(navigator
.userAgent
) ? 1 : 0,
1762 transition
: options
.scaleTransition
,
1763 scaleContent
: options
.scaleContent
,
1764 scaleFromCenter
: options
.scaleFromCenter
,
1765 restoreAfterFinish
: true
1773 /** @id MochiKit.Visual.shrink */
1774 MochiKit
.Visual
.shrink = function (element
, /* optional */ options
) {
1777 Shrink an element and make it disappear.
1780 var d
= MochiKit
.DOM
;
1781 var v
= MochiKit
.Visual
;
1782 var s
= MochiKit
.Style
;
1783 element
= d
.getElement(element
);
1784 options
= MochiKit
.Base
.update({
1785 direction
: 'center',
1786 moveTransition
: v
.Transitions
.sinoidal
,
1787 scaleTransition
: v
.Transitions
.sinoidal
,
1788 opacityTransition
: v
.Transitions
.none
,
1790 scaleFromCenter
: false
1793 top
: element
.style
.top
,
1794 left
: element
.style
.left
,
1795 height
: element
.style
.height
,
1796 width
: element
.style
.width
,
1797 opacity
: s
.getStyle(element
, 'opacity')
1800 var dims
= s
.getElementDimensions(element
);
1803 switch (options
.direction
) {
1815 case 'bottom-right':
1826 var optionsParallel
= MochiKit
.Base
.update({
1827 beforeStartInternal: function (effect
) {
1828 elemClip
= d
.makePositioned(effect
.effects
[0].element
);
1829 d
.makeClipping(effect
.effects
[0].element
);
1831 afterFinishInternal: function (effect
) {
1832 s
.hideElement(effect
.effects
[0].element
);
1833 d
.undoClipping(effect
.effects
[0].element
, elemClip
);
1834 d
.undoPositioned(effect
.effects
[0].element
);
1835 s
.setStyle(effect
.effects
[0].element
, oldStyle
);
1839 return new v
.Parallel(
1840 [new v
.Opacity(element
, {
1841 sync
: true, to
: 0.0, from: 1.0,
1842 transition
: options
.opacityTransition
1844 new v
.Scale(element
, /Opera/.test(navigator
.userAgent
) ? 1 : 0, {
1845 sync
: true, transition
: options
.scaleTransition
,
1846 scaleContent
: options
.scaleContent
,
1847 scaleFromCenter
: options
.scaleFromCenter
,
1848 restoreAfterFinish
: true
1850 new v
.Move(element
, {
1851 x
: moveX
, y
: moveY
, sync
: true, transition
: options
.moveTransition
1857 /** @id MochiKit.Visual.pulsate */
1858 MochiKit
.Visual
.pulsate = function (element
, /* optional */ options
) {
1861 Pulse an element between appear/fade.
1864 var d
= MochiKit
.DOM
;
1865 var v
= MochiKit
.Visual
;
1866 var b
= MochiKit
.Base
;
1867 var oldOpacity
= MochiKit
.Style
.getStyle(element
, 'opacity');
1868 options
= b
.update({
1871 afterFinishInternal: function (effect
) {
1872 MochiKit
.Style
.setStyle(effect
.element
, {'opacity': oldOpacity
});
1875 var transition
= options
.transition
|| v
.Transitions
.sinoidal
;
1876 var reverser
= b
.bind(function (pos
) {
1877 return transition(1 - v
.Transitions
.pulse(pos
));
1879 b
.bind(reverser
, transition
);
1880 return new v
.Opacity(element
, b
.update({
1881 transition
: reverser
}, options
));
1884 /** @id MochiKit.Visual.fold */
1885 MochiKit
.Visual
.fold = function (element
, /* optional */ options
) {
1888 Fold an element, first vertically, then horizontally.
1891 var d
= MochiKit
.DOM
;
1892 var v
= MochiKit
.Visual
;
1893 var s
= MochiKit
.Style
;
1894 element
= d
.getElement(element
);
1896 top
: element
.style
.top
,
1897 left
: element
.style
.left
,
1898 width
: element
.style
.width
,
1899 height
: element
.style
.height
1901 var elemClip
= d
.makeClipping(element
);
1902 options
= MochiKit
.Base
.update({
1903 scaleContent
: false,
1905 afterFinishInternal: function (effect
) {
1906 new v
.Scale(element
, 1, {
1907 scaleContent
: false,
1909 afterFinishInternal: function (effect
) {
1910 s
.hideElement(effect
.element
);
1911 d
.undoClipping(effect
.element
, elemClip
);
1912 s
.setStyle(effect
.element
, oldStyle
);
1917 return new v
.Scale(element
, 5, options
);
1921 // Compatibility with MochiKit 1.0
1922 MochiKit
.Visual
.Color
= MochiKit
.Color
.Color
;
1923 MochiKit
.Visual
.getElementsComputedStyle
= MochiKit
.DOM
.computedStyle
;
1925 /* end of Rico adaptation */
1927 MochiKit
.Visual
.__new__ = function () {
1928 var m
= MochiKit
.Base
;
1930 m
.nameFunctions(this);
1932 this.EXPORT_TAGS
= {
1933 ":common": this.EXPORT
,
1934 ":all": m
.concat(this.EXPORT
, this.EXPORT_OK
)
1939 MochiKit
.Visual
.EXPORT
= [
1969 MochiKit
.Visual
.EXPORT_OK
= [
1974 MochiKit
.Visual
.__new__();
1976 MochiKit
.Base
._exportSymbols(this, MochiKit
.Visual
);