summaryrefslogtreecommitdiff
path: root/frontend/gamma/js/MochiKit/Visual.js
Unidiff
Diffstat (limited to 'frontend/gamma/js/MochiKit/Visual.js') (more/less context) (show whitespace changes)
-rw-r--r--frontend/gamma/js/MochiKit/Visual.js1975
1 files changed, 1975 insertions, 0 deletions
diff --git a/frontend/gamma/js/MochiKit/Visual.js b/frontend/gamma/js/MochiKit/Visual.js
new file mode 100644
index 0000000..648d82a
--- a/dev/null
+++ b/frontend/gamma/js/MochiKit/Visual.js
@@ -0,0 +1,1975 @@
1/***
2
3MochiKit.Visual 1.5
4
5See <http://mochikit.com/> for documentation, downloads, license, etc.
6
7(c) 2005 Bob Ippolito and others. All rights Reserved.
8
9***/
10
11MochiKit.Base._module('Visual', '1.5', ['Base', 'DOM', 'Style', 'Color', 'Position']);
12
13MochiKit.Visual._RoundCorners = function (e, options) {
14 e = MochiKit.DOM.getElement(e);
15 this._setOptions(options);
16 if (this.options.__unstable__wrapElement) {
17 e = this._doWrap(e);
18 }
19
20 var color = this.options.color;
21 var C = MochiKit.Color.Color;
22 if (this.options.color === "fromElement") {
23 color = C.fromBackground(e);
24 } else if (!(color instanceof C)) {
25 color = C.fromString(color);
26 }
27 this.isTransparent = (color.asRGB().a <= 0);
28
29 var bgColor = this.options.bgColor;
30 if (this.options.bgColor === "fromParent") {
31 bgColor = C.fromBackground(e.offsetParent);
32 } else if (!(bgColor instanceof C)) {
33 bgColor = C.fromString(bgColor);
34 }
35
36 this._roundCornersImpl(e, color, bgColor);
37};
38
39MochiKit.Visual._RoundCorners.prototype = {
40 _doWrap: function (e) {
41 var parent = e.parentNode;
42 var doc = MochiKit.DOM.currentDocument();
43 if (typeof(doc.defaultView) === "undefined"
44 || doc.defaultView === null) {
45 return e;
46 }
47 var style = doc.defaultView.getComputedStyle(e, null);
48 if (typeof(style) === "undefined" || style === null) {
49 return e;
50 }
51 var wrapper = MochiKit.DOM.DIV({"style": {
52 display: "block",
53 // convert padding to margin
54 marginTop: style.getPropertyValue("padding-top"),
55 marginRight: style.getPropertyValue("padding-right"),
56 marginBottom: style.getPropertyValue("padding-bottom"),
57 marginLeft: style.getPropertyValue("padding-left"),
58 // remove padding so the rounding looks right
59 padding: "0px"
60 /*
61 paddingRight: "0px",
62 paddingLeft: "0px"
63 */
64 }});
65 wrapper.innerHTML = e.innerHTML;
66 e.innerHTML = "";
67 e.appendChild(wrapper);
68 return e;
69 },
70
71 _roundCornersImpl: function (e, color, bgColor) {
72 if (this.options.border) {
73 this._renderBorder(e, bgColor);
74 }
75 if (this._isTopRounded()) {
76 this._roundTopCorners(e, color, bgColor);
77 }
78 if (this._isBottomRounded()) {
79 this._roundBottomCorners(e, color, bgColor);
80 }
81 },
82
83 _renderBorder: function (el, bgColor) {
84 var borderValue = "1px solid " + this._borderColor(bgColor);
85 var borderL = "border-left: " + borderValue;
86 var borderR = "border-right: " + borderValue;
87 var style = "style='" + borderL + ";" + borderR + "'";
88 el.innerHTML = "<div " + style + ">" + el.innerHTML + "</div>";
89 },
90
91 _roundTopCorners: function (el, color, bgColor) {
92 var corner = this._createCorner(bgColor);
93 for (var i = 0; i < this.options.numSlices; i++) {
94 corner.appendChild(
95 this._createCornerSlice(color, bgColor, i, "top")
96 );
97 }
98 el.style.paddingTop = 0;
99 el.insertBefore(corner, el.firstChild);
100 },
101
102 _roundBottomCorners: function (el, color, bgColor) {
103 var corner = this._createCorner(bgColor);
104 for (var i = (this.options.numSlices - 1); i >= 0; i--) {
105 corner.appendChild(
106 this._createCornerSlice(color, bgColor, i, "bottom")
107 );
108 }
109 el.style.paddingBottom = 0;
110 el.appendChild(corner);
111 },
112
113 _createCorner: function (bgColor) {
114 var dom = MochiKit.DOM;
115 return dom.DIV({style: {backgroundColor: bgColor.toString()}});
116 },
117
118 _createCornerSlice: function (color, bgColor, n, position) {
119 var slice = MochiKit.DOM.SPAN();
120
121 var inStyle = slice.style;
122 inStyle.backgroundColor = color.toString();
123 inStyle.display = "block";
124 inStyle.height = "1px";
125 inStyle.overflow = "hidden";
126 inStyle.fontSize = "1px";
127
128 var borderColor = this._borderColor(color, bgColor);
129 if (this.options.border && n === 0) {
130 inStyle.borderTopStyle = "solid";
131 inStyle.borderTopWidth = "1px";
132 inStyle.borderLeftWidth = "0px";
133 inStyle.borderRightWidth = "0px";
134 inStyle.borderBottomWidth = "0px";
135 // assumes css compliant box model
136 inStyle.height = "0px";
137 inStyle.borderColor = borderColor.toString();
138 } else if (borderColor) {
139 inStyle.borderColor = borderColor.toString();
140 inStyle.borderStyle = "solid";
141 inStyle.borderWidth = "0px 1px";
142 }
143
144 if (!this.options.compact && (n == (this.options.numSlices - 1))) {
145 inStyle.height = "2px";
146 }
147
148 this._setMargin(slice, n, position);
149 this._setBorder(slice, n, position);
150
151 return slice;
152 },
153
154 _setOptions: function (options) {
155 this.options = {
156 corners: "all",
157 color: "fromElement",
158 bgColor: "fromParent",
159 blend: true,
160 border: false,
161 compact: false,
162 __unstable__wrapElement: false
163 };
164 MochiKit.Base.update(this.options, options);
165
166 this.options.numSlices = (this.options.compact ? 2 : 4);
167 },
168
169 _whichSideTop: function () {
170 var corners = this.options.corners;
171 if (this._hasString(corners, "all", "top")) {
172 return "";
173 }
174
175 var has_tl = (corners.indexOf("tl") != -1);
176 var has_tr = (corners.indexOf("tr") != -1);
177 if (has_tl && has_tr) {
178 return "";
179 }
180 if (has_tl) {
181 return "left";
182 }
183 if (has_tr) {
184 return "right";
185 }
186 return "";
187 },
188
189 _whichSideBottom: function () {
190 var corners = this.options.corners;
191 if (this._hasString(corners, "all", "bottom")) {
192 return "";
193 }
194
195 var has_bl = (corners.indexOf('bl') != -1);
196 var has_br = (corners.indexOf('br') != -1);
197 if (has_bl && has_br) {
198 return "";
199 }
200 if (has_bl) {
201 return "left";
202 }
203 if (has_br) {
204 return "right";
205 }
206 return "";
207 },
208
209 _borderColor: function (color, bgColor) {
210 if (color == "transparent") {
211 return bgColor;
212 } else if (this.options.border) {
213 return this.options.border;
214 } else if (this.options.blend) {
215 return bgColor.blendedColor(color);
216 }
217 return "";
218 },
219
220
221 _setMargin: function (el, n, corners) {
222 var marginSize = this._marginSize(n) + "px";
223 var whichSide = (
224 corners == "top" ? this._whichSideTop() : this._whichSideBottom()
225 );
226 var style = el.style;
227
228 if (whichSide == "left") {
229 style.marginLeft = marginSize;
230 style.marginRight = "0px";
231 } else if (whichSide == "right") {
232 style.marginRight = marginSize;
233 style.marginLeft = "0px";
234 } else {
235 style.marginLeft = marginSize;
236 style.marginRight = marginSize;
237 }
238 },
239
240 _setBorder: function (el, n, corners) {
241 var borderSize = this._borderSize(n) + "px";
242 var whichSide = (
243 corners == "top" ? this._whichSideTop() : this._whichSideBottom()
244 );
245
246 var style = el.style;
247 if (whichSide == "left") {
248 style.borderLeftWidth = borderSize;
249 style.borderRightWidth = "0px";
250 } else if (whichSide == "right") {
251 style.borderRightWidth = borderSize;
252 style.borderLeftWidth = "0px";
253 } else {
254 style.borderLeftWidth = borderSize;
255 style.borderRightWidth = borderSize;
256 }
257 },
258
259 _marginSize: function (n) {
260 if (this.isTransparent) {
261 return 0;
262 }
263
264 var o = this.options;
265 if (o.compact && o.blend) {
266 var smBlendedMarginSizes = [1, 0];
267 return smBlendedMarginSizes[n];
268 } else if (o.compact) {
269 var compactMarginSizes = [2, 1];
270 return compactMarginSizes[n];
271 } else if (o.blend) {
272 var blendedMarginSizes = [3, 2, 1, 0];
273 return blendedMarginSizes[n];
274 } else {
275 var marginSizes = [5, 3, 2, 1];
276 return marginSizes[n];
277 }
278 },
279
280 _borderSize: function (n) {
281 var o = this.options;
282 var borderSizes;
283 if (o.compact && (o.blend || this.isTransparent)) {
284 return 1;
285 } else if (o.compact) {
286 borderSizes = [1, 0];
287 } else if (o.blend) {
288 borderSizes = [2, 1, 1, 1];
289 } else if (o.border) {
290 borderSizes = [0, 2, 0, 0];
291 } else if (this.isTransparent) {
292 borderSizes = [5, 3, 2, 1];
293 } else {
294 return 0;
295 }
296 return borderSizes[n];
297 },
298
299 _hasString: function (str) {
300 for (var i = 1; i< arguments.length; i++) {
301 if (str.indexOf(arguments[i]) != -1) {
302 return true;
303 }
304 }
305 return false;
306 },
307
308 _isTopRounded: function () {
309 return this._hasString(this.options.corners,
310 "all", "top", "tl", "tr"
311 );
312 },
313
314 _isBottomRounded: function () {
315 return this._hasString(this.options.corners,
316 "all", "bottom", "bl", "br"
317 );
318 },
319
320 _hasSingleTextChild: function (el) {
321 return (el.childNodes.length == 1 && el.childNodes[0].nodeType == 3);
322 }
323};
324
325/** @id MochiKit.Visual.roundElement */
326MochiKit.Visual.roundElement = function (e, options) {
327 new MochiKit.Visual._RoundCorners(e, options);
328};
329
330/** @id MochiKit.Visual.roundClass */
331MochiKit.Visual.roundClass = function (tagName, className, options) {
332 var elements = MochiKit.DOM.getElementsByTagAndClassName(
333 tagName, className
334 );
335 for (var i = 0; i < elements.length; i++) {
336 MochiKit.Visual.roundElement(elements[i], options);
337 }
338};
339
340/** @id MochiKit.Visual.tagifyText */
341MochiKit.Visual.tagifyText = function (element, /* optional */tagifyStyle) {
342 /***
343
344 Change a node text to character in tags.
345
346 @param tagifyStyle: the style to apply to character nodes, default to
347 'position: relative'.
348
349 ***/
350 tagifyStyle = tagifyStyle || 'position:relative';
351 if (/MSIE/.test(navigator.userAgent)) {
352 tagifyStyle += ';zoom:1';
353 }
354 element = MochiKit.DOM.getElement(element);
355 var ma = MochiKit.Base.map;
356 ma(function (child) {
357 if (child.nodeType == 3) {
358 ma(function (character) {
359 element.insertBefore(
360 MochiKit.DOM.SPAN({style: tagifyStyle},
361 character == ' ' ? String.fromCharCode(160) : character), child);
362 }, child.nodeValue.split(''));
363 MochiKit.DOM.removeElement(child);
364 }
365 }, element.childNodes);
366};
367
368MochiKit.Visual._forceRerendering = function (element) {
369 try {
370 element = MochiKit.DOM.getElement(element);
371 var n = document.createTextNode(' ');
372 element.appendChild(n);
373 element.removeChild(n);
374 } catch(e) {
375 }
376};
377
378/** @id MochiKit.Visual.multiple */
379MochiKit.Visual.multiple = function (elements, effect, /* optional */options) {
380 /***
381
382 Launch the same effect subsequently on given elements.
383
384 ***/
385 options = MochiKit.Base.update({
386 speed: 0.1, delay: 0.0
387 }, options);
388 var masterDelay = options.delay;
389 var index = 0;
390 MochiKit.Base.map(function (innerelement) {
391 options.delay = index * options.speed + masterDelay;
392 new effect(innerelement, options);
393 index += 1;
394 }, elements);
395};
396
397MochiKit.Visual.PAIRS = {
398 'slide': ['slideDown', 'slideUp'],
399 'blind': ['blindDown', 'blindUp'],
400 'appear': ['appear', 'fade'],
401 'size': ['grow', 'shrink']
402};
403
404/** @id MochiKit.Visual.toggle */
405MochiKit.Visual.toggle = function (element, /* optional */effect, /* optional */options) {
406 /***
407
408 Toggle an item between two state depending of its visibility, making
409 a effect between these states. Default effect is 'appear', can be
410 'slide' or 'blind'.
411
412 ***/
413 element = MochiKit.DOM.getElement(element);
414 effect = (effect || 'appear').toLowerCase();
415 options = MochiKit.Base.update({
416 queue: {position: 'end', scope: (element.id || 'global'), limit: 1}
417 }, options);
418 var v = MochiKit.Visual;
419 v[MochiKit.Style.getStyle(element, 'display') != 'none' ?
420 v.PAIRS[effect][1] : v.PAIRS[effect][0]](element, options);
421};
422
423/***
424
425Transitions: define functions calculating variations depending of a position.
426
427***/
428
429MochiKit.Visual.Transitions = { __export__: false };
430
431/** @id MochiKit.Visual.Transitions.linear */
432MochiKit.Visual.Transitions.linear = function (pos) {
433 return pos;
434};
435
436/** @id MochiKit.Visual.Transitions.sinoidal */
437MochiKit.Visual.Transitions.sinoidal = function (pos) {
438 return 0.5 - Math.cos(pos*Math.PI)/2;
439};
440
441/** @id MochiKit.Visual.Transitions.reverse */
442MochiKit.Visual.Transitions.reverse = function (pos) {
443 return 1 - pos;
444};
445
446/** @id MochiKit.Visual.Transitions.flicker */
447MochiKit.Visual.Transitions.flicker = function (pos) {
448 return 0.25 - Math.cos(pos*Math.PI)/4 + Math.random()/2;
449};
450
451/** @id MochiKit.Visual.Transitions.wobble */
452MochiKit.Visual.Transitions.wobble = function (pos) {
453 return 0.5 - Math.cos(9*pos*Math.PI)/2;
454};
455
456/** @id MochiKit.Visual.Transitions.pulse */
457MochiKit.Visual.Transitions.pulse = function (pos, pulses) {
458 if (pulses) {
459 pos *= 2 * pulses;
460 } else {
461 pos *= 10;
462 }
463 var decimals = pos - Math.floor(pos);
464 return (Math.floor(pos) % 2 == 0) ? decimals : 1 - decimals;
465};
466
467/** @id MochiKit.Visual.Transitions.parabolic */
468MochiKit.Visual.Transitions.parabolic = function (pos) {
469 return pos * pos;
470};
471
472/** @id MochiKit.Visual.Transitions.none */
473MochiKit.Visual.Transitions.none = function (pos) {
474 return 0;
475};
476
477/** @id MochiKit.Visual.Transitions.full */
478MochiKit.Visual.Transitions.full = function (pos) {
479 return 1;
480};
481
482/***
483
484Core effects
485
486***/
487
488MochiKit.Visual.ScopedQueue = function () {
489 var cls = arguments.callee;
490 if (!(this instanceof cls)) {
491 return new cls();
492 }
493 this.__init__();
494};
495MochiKit.Visual.ScopedQueue.__export__ = false;
496
497MochiKit.Base.update(MochiKit.Visual.ScopedQueue.prototype, {
498 __init__: function () {
499 this.effects = [];
500 this.interval = null;
501 },
502
503 /** @id MochiKit.Visual.ScopedQueue.prototype.add */
504 add: function (effect) {
505 var timestamp = new Date().getTime();
506
507 var position = (typeof(effect.options.queue) == 'string') ?
508 effect.options.queue : effect.options.queue.position;
509
510 var ma = MochiKit.Base.map;
511 switch (position) {
512 case 'front':
513 // move unstarted effects after this effect
514 ma(function (e) {
515 if (e.state == 'idle') {
516 e.startOn += effect.finishOn;
517 e.finishOn += effect.finishOn;
518 }
519 }, this.effects);
520 break;
521 case 'end':
522 var finish;
523 // start effect after last queued effect has finished
524 ma(function (e) {
525 var i = e.finishOn;
526 if (i >= (finish || i)) {
527 finish = i;
528 }
529 }, this.effects);
530 timestamp = finish || timestamp;
531 break;
532 case 'break':
533 ma(function (e) {
534 e.finalize();
535 }, this.effects);
536 break;
537 }
538
539 effect.startOn += timestamp;
540 effect.finishOn += timestamp;
541 if (!effect.options.queue.limit ||
542 this.effects.length < effect.options.queue.limit) {
543 this.effects.push(effect);
544 }
545
546 if (!this.interval) {
547 this.interval = this.startLoop(MochiKit.Base.bind(this.loop, this),
548 40);
549 }
550 },
551
552 /** @id MochiKit.Visual.ScopedQueue.prototype.startLoop */
553 startLoop: function (func, interval) {
554 return setInterval(func, interval);
555 },
556
557 /** @id MochiKit.Visual.ScopedQueue.prototype.remove */
558 remove: function (effect) {
559 this.effects = MochiKit.Base.filter(function (e) {
560 return e != effect;
561 }, this.effects);
562 if (!this.effects.length) {
563 this.stopLoop(this.interval);
564 this.interval = null;
565 }
566 },
567
568 /** @id MochiKit.Visual.ScopedQueue.prototype.stopLoop */
569 stopLoop: function (interval) {
570 clearInterval(interval);
571 },
572
573 /** @id MochiKit.Visual.ScopedQueue.prototype.loop */
574 loop: function () {
575 var timePos = new Date().getTime();
576 MochiKit.Base.map(function (effect) {
577 effect.loop(timePos);
578 }, this.effects);
579 }
580});
581
582MochiKit.Visual.Queues = {
583 __export__: false,
584 instances: {},
585 get: function (queueName) {
586 if (typeof(queueName) != 'string') {
587 return queueName;
588 }
589
590 if (!this.instances[queueName]) {
591 this.instances[queueName] = new MochiKit.Visual.ScopedQueue();
592 }
593 return this.instances[queueName];
594 }
595};
596
597MochiKit.Visual.Queue = MochiKit.Visual.Queues.get('global');
598MochiKit.Visual.Queue.__export__ = false;
599
600MochiKit.Visual.DefaultOptions = {
601 __export__: false,
602 transition: MochiKit.Visual.Transitions.sinoidal,
603 duration: 1.0, // seconds
604 fps: 25.0, // max. 25fps due to MochiKit.Visual.Queue implementation
605 sync: false, // true for combining
606 from: 0.0,
607 to: 1.0,
608 delay: 0.0,
609 queue: 'parallel'
610};
611
612MochiKit.Visual.Base = function () {};
613
614MochiKit.Visual.Base.prototype = {
615 /***
616
617 Basic class for all Effects. Define a looping mechanism called for each step
618 of an effect. Don't instantiate it, only subclass it.
619
620 ***/
621
622 __class__ : MochiKit.Visual.Base,
623
624 /** @id MochiKit.Visual.Base.prototype.start */
625 start: function (options) {
626 var v = MochiKit.Visual;
627 this.options = MochiKit.Base.setdefault(options,
628 v.DefaultOptions);
629 this.currentFrame = 0;
630 this.state = 'idle';
631 this.startOn = this.options.delay*1000;
632 this.finishOn = this.startOn + (this.options.duration*1000);
633 this.event('beforeStart');
634 if (!this.options.sync) {
635 v.Queues.get(typeof(this.options.queue) == 'string' ?
636 'global' : this.options.queue.scope).add(this);
637 }
638 },
639
640 /** @id MochiKit.Visual.Base.prototype.loop */
641 loop: function (timePos) {
642 if (timePos >= this.startOn) {
643 if (timePos >= this.finishOn) {
644 return this.finalize();
645 }
646 var pos = (timePos - this.startOn) / (this.finishOn - this.startOn);
647 var frame =
648 Math.round(pos * this.options.fps * this.options.duration);
649 if (frame > this.currentFrame) {
650 this.render(pos);
651 this.currentFrame = frame;
652 }
653 }
654 },
655
656 /** @id MochiKit.Visual.Base.prototype.render */
657 render: function (pos) {
658 if (this.state == 'idle') {
659 this.state = 'running';
660 this.event('beforeSetup');
661 this.setup();
662 this.event('afterSetup');
663 }
664 if (this.state == 'running') {
665 if (this.options.transition) {
666 pos = this.options.transition(pos);
667 }
668 pos *= (this.options.to - this.options.from);
669 pos += this.options.from;
670 this.event('beforeUpdate');
671 this.update(pos);
672 this.event('afterUpdate');
673 }
674 },
675
676 /** @id MochiKit.Visual.Base.prototype.cancel */
677 cancel: function () {
678 if (!this.options.sync) {
679 MochiKit.Visual.Queues.get(typeof(this.options.queue) == 'string' ?
680 'global' : this.options.queue.scope).remove(this);
681 }
682 this.state = 'finished';
683 },
684
685 /** @id MochiKit.Visual.Base.prototype.finalize */
686 finalize: function () {
687 this.render(1.0);
688 this.cancel();
689 this.event('beforeFinish');
690 this.finish();
691 this.event('afterFinish');
692 },
693
694 setup: function () {
695 },
696
697 finish: function () {
698 },
699
700 update: function (position) {
701 },
702
703 /** @id MochiKit.Visual.Base.prototype.event */
704 event: function (eventName) {
705 if (this.options[eventName + 'Internal']) {
706 this.options[eventName + 'Internal'](this);
707 }
708 if (this.options[eventName]) {
709 this.options[eventName](this);
710 }
711 },
712
713 /** @id MochiKit.Visual.Base.prototype.repr */
714 repr: function () {
715 return '[' + this.__class__.NAME + ', options:' +
716 MochiKit.Base.repr(this.options) + ']';
717 }
718};
719
720/** @id MochiKit.Visual.Parallel */
721MochiKit.Visual.Parallel = function (effects, options) {
722 var cls = arguments.callee;
723 if (!(this instanceof cls)) {
724 return new cls(effects, options);
725 }
726
727 this.__init__(effects, options);
728};
729
730MochiKit.Visual.Parallel.prototype = new MochiKit.Visual.Base();
731
732MochiKit.Base.update(MochiKit.Visual.Parallel.prototype, {
733 /***
734
735 Run multiple effects at the same time.
736
737 ***/
738
739 __class__ : MochiKit.Visual.Parallel,
740
741 __init__: function (effects, options) {
742 this.effects = effects || [];
743 this.start(options);
744 },
745
746 /** @id MochiKit.Visual.Parallel.prototype.update */
747 update: function (position) {
748 MochiKit.Base.map(function (effect) {
749 effect.render(position);
750 }, this.effects);
751 },
752
753 /** @id MochiKit.Visual.Parallel.prototype.finish */
754 finish: function () {
755 MochiKit.Base.map(function (effect) {
756 effect.finalize();
757 }, this.effects);
758 }
759});
760
761/** @id MochiKit.Visual.Sequence */
762MochiKit.Visual.Sequence = function (effects, options) {
763 var cls = arguments.callee;
764 if (!(this instanceof cls)) {
765 return new cls(effects, options);
766 }
767 this.__init__(effects, options);
768};
769
770MochiKit.Visual.Sequence.prototype = new MochiKit.Visual.Base();
771
772MochiKit.Base.update(MochiKit.Visual.Sequence.prototype, {
773
774 __class__ : MochiKit.Visual.Sequence,
775
776 __init__: function (effects, options) {
777 var defs = { transition: MochiKit.Visual.Transitions.linear,
778 duration: 0 };
779 this.effects = effects || [];
780 MochiKit.Base.map(function (effect) {
781 defs.duration += effect.options.duration;
782 }, this.effects);
783 MochiKit.Base.setdefault(options, defs);
784 this.start(options);
785 },
786
787 /** @id MochiKit.Visual.Sequence.prototype.update */
788 update: function (position) {
789 var time = position * this.options.duration;
790 for (var i = 0; i < this.effects.length; i++) {
791 var effect = this.effects[i];
792 if (time <= effect.options.duration) {
793 effect.render(time / effect.options.duration);
794 break;
795 } else {
796 time -= effect.options.duration;
797 }
798 }
799 },
800
801 /** @id MochiKit.Visual.Sequence.prototype.finish */
802 finish: function () {
803 MochiKit.Base.map(function (effect) {
804 effect.finalize();
805 }, this.effects);
806 }
807});
808
809/** @id MochiKit.Visual.Opacity */
810MochiKit.Visual.Opacity = function (element, options) {
811 var cls = arguments.callee;
812 if (!(this instanceof cls)) {
813 return new cls(element, options);
814 }
815 this.__init__(element, options);
816};
817
818MochiKit.Visual.Opacity.prototype = new MochiKit.Visual.Base();
819
820MochiKit.Base.update(MochiKit.Visual.Opacity.prototype, {
821 /***
822
823 Change the opacity of an element.
824
825 @param options: 'from' and 'to' change the starting and ending opacities.
826 Must be between 0.0 and 1.0. Default to current opacity and 1.0.
827
828 ***/
829
830 __class__ : MochiKit.Visual.Opacity,
831
832 __init__: function (element, /* optional */options) {
833 var b = MochiKit.Base;
834 var s = MochiKit.Style;
835 this.element = MochiKit.DOM.getElement(element);
836 // make this work on IE on elements without 'layout'
837 if (this.element.currentStyle &&
838 (!this.element.currentStyle.hasLayout)) {
839 s.setStyle(this.element, {zoom: 1});
840 }
841 options = b.update({
842 from: s.getStyle(this.element, 'opacity') || 0.0,
843 to: 1.0
844 }, options);
845 this.start(options);
846 },
847
848 /** @id MochiKit.Visual.Opacity.prototype.update */
849 update: function (position) {
850 MochiKit.Style.setStyle(this.element, {'opacity': position});
851 }
852});
853
854/** @id MochiKit.Visual.Move.prototype */
855MochiKit.Visual.Move = function (element, options) {
856 var cls = arguments.callee;
857 if (!(this instanceof cls)) {
858 return new cls(element, options);
859 }
860 this.__init__(element, options);
861};
862
863MochiKit.Visual.Move.prototype = new MochiKit.Visual.Base();
864
865MochiKit.Base.update(MochiKit.Visual.Move.prototype, {
866 /***
867
868 Move an element between its current position to a defined position
869
870 @param options: 'x' and 'y' for final positions, default to 0, 0.
871
872 ***/
873
874 __class__ : MochiKit.Visual.Move,
875
876 __init__: function (element, /* optional */options) {
877 this.element = MochiKit.DOM.getElement(element);
878 options = MochiKit.Base.update({
879 x: 0,
880 y: 0,
881 mode: 'relative'
882 }, options);
883 this.start(options);
884 },
885
886 /** @id MochiKit.Visual.Move.prototype.setup */
887 setup: function () {
888 // Bug in Opera: Opera returns the 'real' position of a static element
889 // or relative element that does not have top/left explicitly set.
890 // ==> Always set top and left for position relative elements in your
891 // stylesheets (to 0 if you do not need them)
892 MochiKit.Style.makePositioned(this.element);
893
894 var s = this.element.style;
895 var originalVisibility = s.visibility;
896 var originalDisplay = s.display;
897 if (originalDisplay == 'none') {
898 s.visibility = 'hidden';
899 s.display = '';
900 }
901
902 this.originalLeft = parseFloat(MochiKit.Style.getStyle(this.element, 'left') || '0');
903 this.originalTop = parseFloat(MochiKit.Style.getStyle(this.element, 'top') || '0');
904
905 if (this.options.mode == 'absolute') {
906 // absolute movement, so we need to calc deltaX and deltaY
907 this.options.x -= this.originalLeft;
908 this.options.y -= this.originalTop;
909 }
910 if (originalDisplay == 'none') {
911 s.visibility = originalVisibility;
912 s.display = originalDisplay;
913 }
914 },
915
916 /** @id MochiKit.Visual.Move.prototype.update */
917 update: function (position) {
918 MochiKit.Style.setStyle(this.element, {
919 left: Math.round(this.options.x * position + this.originalLeft) + 'px',
920 top: Math.round(this.options.y * position + this.originalTop) + 'px'
921 });
922 }
923});
924
925/** @id MochiKit.Visual.Scale */
926MochiKit.Visual.Scale = function (element, percent, options) {
927 var cls = arguments.callee;
928 if (!(this instanceof cls)) {
929 return new cls(element, percent, options);
930 }
931 this.__init__(element, percent, options);
932};
933
934MochiKit.Visual.Scale.prototype = new MochiKit.Visual.Base();
935
936MochiKit.Base.update(MochiKit.Visual.Scale.prototype, {
937 /***
938
939 Change the size of an element.
940
941 @param percent: final_size = percent*original_size
942
943 @param options: several options changing scale behaviour
944
945 ***/
946
947 __class__ : MochiKit.Visual.Scale,
948
949 __init__: function (element, percent, /* optional */options) {
950 this.element = MochiKit.DOM.getElement(element);
951 options = MochiKit.Base.update({
952 scaleX: true,
953 scaleY: true,
954 scaleContent: true,
955 scaleFromCenter: false,
956 scaleMode: 'box', // 'box' or 'contents' or {} with provided values
957 scaleFrom: 100.0,
958 scaleTo: percent
959 }, options);
960 this.start(options);
961 },
962
963 /** @id MochiKit.Visual.Scale.prototype.setup */
964 setup: function () {
965 this.restoreAfterFinish = this.options.restoreAfterFinish || false;
966 this.elementPositioning = MochiKit.Style.getStyle(this.element,
967 'position');
968
969 var ma = MochiKit.Base.map;
970 var b = MochiKit.Base.bind;
971 this.originalStyle = {};
972 ma(b(function (k) {
973 this.originalStyle[k] = this.element.style[k];
974 }, this), ['top', 'left', 'width', 'height', 'fontSize']);
975
976 this.originalTop = this.element.offsetTop;
977 this.originalLeft = this.element.offsetLeft;
978
979 var fontSize = MochiKit.Style.getStyle(this.element,
980 'font-size') || '100%';
981 ma(b(function (fontSizeType) {
982 if (fontSize.indexOf(fontSizeType) > 0) {
983 this.fontSize = parseFloat(fontSize);
984 this.fontSizeType = fontSizeType;
985 }
986 }, this), ['em', 'px', '%']);
987
988 this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
989
990 if (/^content/.test(this.options.scaleMode)) {
991 this.dims = [this.element.scrollHeight, this.element.scrollWidth];
992 } else if (this.options.scaleMode == 'box') {
993 this.dims = [this.element.offsetHeight, this.element.offsetWidth];
994 } else {
995 this.dims = [this.options.scaleMode.originalHeight,
996 this.options.scaleMode.originalWidth];
997 }
998 },
999
1000 /** @id MochiKit.Visual.Scale.prototype.update */
1001 update: function (position) {
1002 var currentScale = (this.options.scaleFrom/100.0) +
1003 (this.factor * position);
1004 if (this.options.scaleContent && this.fontSize) {
1005 MochiKit.Style.setStyle(this.element, {
1006 fontSize: this.fontSize * currentScale + this.fontSizeType
1007 });
1008 }
1009 this.setDimensions(this.dims[0] * currentScale,
1010 this.dims[1] * currentScale);
1011 },
1012
1013 /** @id MochiKit.Visual.Scale.prototype.finish */
1014 finish: function () {
1015 if (this.restoreAfterFinish) {
1016 MochiKit.Style.setStyle(this.element, this.originalStyle);
1017 }
1018 },
1019
1020 /** @id MochiKit.Visual.Scale.prototype.setDimensions */
1021 setDimensions: function (height, width) {
1022 var d = {};
1023 var r = Math.round;
1024 if (/MSIE/.test(navigator.userAgent)) {
1025 r = Math.ceil;
1026 }
1027 if (this.options.scaleX) {
1028 d.width = r(width) + 'px';
1029 }
1030 if (this.options.scaleY) {
1031 d.height = r(height) + 'px';
1032 }
1033 if (this.options.scaleFromCenter) {
1034 var topd = (height - this.dims[0])/2;
1035 var leftd = (width - this.dims[1])/2;
1036 if (this.elementPositioning == 'absolute') {
1037 if (this.options.scaleY) {
1038 d.top = this.originalTop - topd + 'px';
1039 }
1040 if (this.options.scaleX) {
1041 d.left = this.originalLeft - leftd + 'px';
1042 }
1043 } else {
1044 if (this.options.scaleY) {
1045 d.top = -topd + 'px';
1046 }
1047 if (this.options.scaleX) {
1048 d.left = -leftd + 'px';
1049 }
1050 }
1051 }
1052 MochiKit.Style.setStyle(this.element, d);
1053 }
1054});
1055
1056/** @id MochiKit.Visual.Highlight */
1057MochiKit.Visual.Highlight = function (element, options) {
1058 var cls = arguments.callee;
1059 if (!(this instanceof cls)) {
1060 return new cls(element, options);
1061 }
1062 this.__init__(element, options);
1063};
1064
1065MochiKit.Visual.Highlight.prototype = new MochiKit.Visual.Base();
1066
1067MochiKit.Base.update(MochiKit.Visual.Highlight.prototype, {
1068 /***
1069
1070 Highlight an item of the page.
1071
1072 @param options: 'startcolor' for choosing highlighting color, default
1073 to '#ffff99'.
1074
1075 ***/
1076
1077 __class__ : MochiKit.Visual.Highlight,
1078
1079 __init__: function (element, /* optional */options) {
1080 this.element = MochiKit.DOM.getElement(element);
1081 options = MochiKit.Base.update({
1082 startcolor: '#ffff99'
1083 }, options);
1084 this.start(options);
1085 },
1086
1087 /** @id MochiKit.Visual.Highlight.prototype.setup */
1088 setup: function () {
1089 var b = MochiKit.Base;
1090 var s = MochiKit.Style;
1091 // Prevent executing on elements not in the layout flow
1092 if (s.getStyle(this.element, 'display') == 'none') {
1093 this.cancel();
1094 return;
1095 }
1096 // Disable background image during the effect
1097 this.oldStyle = {
1098 backgroundImage: s.getStyle(this.element, 'background-image')
1099 };
1100 s.setStyle(this.element, {
1101 backgroundImage: 'none'
1102 });
1103
1104 if (!this.options.endcolor) {
1105 this.options.endcolor =
1106 MochiKit.Color.Color.fromBackground(this.element).toHexString();
1107 }
1108 if (b.isUndefinedOrNull(this.options.restorecolor)) {
1109 this.options.restorecolor = s.getStyle(this.element,
1110 'background-color');
1111 }
1112 // init color calculations
1113 this._base = b.map(b.bind(function (i) {
1114 return parseInt(
1115 this.options.startcolor.slice(i*2 + 1, i*2 + 3), 16);
1116 }, this), [0, 1, 2]);
1117 this._delta = b.map(b.bind(function (i) {
1118 return parseInt(this.options.endcolor.slice(i*2 + 1, i*2 + 3), 16)
1119 - this._base[i];
1120 }, this), [0, 1, 2]);
1121 },
1122
1123 /** @id MochiKit.Visual.Highlight.prototype.update */
1124 update: function (position) {
1125 var m = '#';
1126 MochiKit.Base.map(MochiKit.Base.bind(function (i) {
1127 m += MochiKit.Color.toColorPart(Math.round(this._base[i] +
1128 this._delta[i]*position));
1129 }, this), [0, 1, 2]);
1130 MochiKit.Style.setStyle(this.element, {
1131 backgroundColor: m
1132 });
1133 },
1134
1135 /** @id MochiKit.Visual.Highlight.prototype.finish */
1136 finish: function () {
1137 MochiKit.Style.setStyle(this.element,
1138 MochiKit.Base.update(this.oldStyle, {
1139 backgroundColor: this.options.restorecolor
1140 }));
1141 }
1142});
1143
1144/** @id MochiKit.Visual.ScrollTo */
1145MochiKit.Visual.ScrollTo = function (element, options) {
1146 var cls = arguments.callee;
1147 if (!(this instanceof cls)) {
1148 return new cls(element, options);
1149 }
1150 this.__init__(element, options);
1151};
1152
1153MochiKit.Visual.ScrollTo.prototype = new MochiKit.Visual.Base();
1154
1155MochiKit.Base.update(MochiKit.Visual.ScrollTo.prototype, {
1156 /***
1157
1158 Scroll to an element in the page.
1159
1160 ***/
1161
1162 __class__ : MochiKit.Visual.ScrollTo,
1163
1164 __init__: function (element, /* optional */options) {
1165 this.element = MochiKit.DOM.getElement(element);
1166 this.start(options);
1167 },
1168
1169 /** @id MochiKit.Visual.ScrollTo.prototype.setup */
1170 setup: function () {
1171 var p = MochiKit.Position;
1172 p.prepare();
1173 var offsets = p.cumulativeOffset(this.element);
1174 if (this.options.offset) {
1175 offsets.y += this.options.offset;
1176 }
1177 var max;
1178 if (window.innerHeight) {
1179 max = window.innerHeight - window.height;
1180 } else if (document.documentElement &&
1181 document.documentElement.clientHeight) {
1182 max = document.documentElement.clientHeight -
1183 document.body.scrollHeight;
1184 } else if (document.body) {
1185 max = document.body.clientHeight - document.body.scrollHeight;
1186 }
1187 this.scrollStart = p.windowOffset.y;
1188 this.delta = (offsets.y > max ? max : offsets.y) - this.scrollStart;
1189 },
1190
1191 /** @id MochiKit.Visual.ScrollTo.prototype.update */
1192 update: function (position) {
1193 var p = MochiKit.Position;
1194 p.prepare();
1195 window.scrollTo(p.windowOffset.x, this.scrollStart + (position * this.delta));
1196 }
1197});
1198
1199MochiKit.Visual._CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
1200
1201MochiKit.Visual.Morph = function (element, options) {
1202 var cls = arguments.callee;
1203 if (!(this instanceof cls)) {
1204 return new cls(element, options);
1205 }
1206 this.__init__(element, options);
1207};
1208
1209MochiKit.Visual.Morph.prototype = new MochiKit.Visual.Base();
1210
1211MochiKit.Base.update(MochiKit.Visual.Morph.prototype, {
1212 /***
1213
1214 Morph effect: make a transformation from current style to the given style,
1215 automatically making a transition between the two.
1216
1217 ***/
1218
1219 __class__ : MochiKit.Visual.Morph,
1220
1221 __init__: function (element, /* optional */options) {
1222 this.element = MochiKit.DOM.getElement(element);
1223 this.start(options);
1224 },
1225
1226 /** @id MochiKit.Visual.Morph.prototype.setup */
1227 setup: function () {
1228 var b = MochiKit.Base;
1229 var style = this.options.style;
1230 this.styleStart = {};
1231 this.styleEnd = {};
1232 this.units = {};
1233 var value, unit;
1234 for (var s in style) {
1235 value = style[s];
1236 s = b.camelize(s);
1237 if (MochiKit.Visual._CSS_LENGTH.test(value)) {
1238 var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
1239 value = parseFloat(components[1]);
1240 unit = (components.length == 3) ? components[2] : null;
1241 this.styleEnd[s] = value;
1242 this.units[s] = unit;
1243 value = MochiKit.Style.getStyle(this.element, s);
1244 components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
1245 value = parseFloat(components[1]);
1246 this.styleStart[s] = value;
1247 } else if (/[Cc]olor$/.test(s)) {
1248 var c = MochiKit.Color.Color;
1249 value = c.fromString(value);
1250 if (value) {
1251 this.units[s] = "color";
1252 this.styleEnd[s] = value.toHexString();
1253 value = MochiKit.Style.getStyle(this.element, s);
1254 this.styleStart[s] = c.fromString(value).toHexString();
1255
1256 this.styleStart[s] = b.map(b.bind(function (i) {
1257 return parseInt(
1258 this.styleStart[s].slice(i*2 + 1, i*2 + 3), 16);
1259 }, this), [0, 1, 2]);
1260 this.styleEnd[s] = b.map(b.bind(function (i) {
1261 return parseInt(
1262 this.styleEnd[s].slice(i*2 + 1, i*2 + 3), 16);
1263 }, this), [0, 1, 2]);
1264 }
1265 } else {
1266 // For non-length & non-color properties, we just set the value
1267 this.element.style[s] = value;
1268 }
1269 }
1270 },
1271
1272 /** @id MochiKit.Visual.Morph.prototype.update */
1273 update: function (position) {
1274 var value;
1275 for (var s in this.styleStart) {
1276 if (this.units[s] == "color") {
1277 var m = '#';
1278 var start = this.styleStart[s];
1279 var end = this.styleEnd[s];
1280 MochiKit.Base.map(MochiKit.Base.bind(function (i) {
1281 m += MochiKit.Color.toColorPart(Math.round(start[i] +
1282 (end[i] - start[i])*position));
1283 }, this), [0, 1, 2]);
1284 this.element.style[s] = m;
1285 } else {
1286 value = this.styleStart[s] + Math.round((this.styleEnd[s] - this.styleStart[s]) * position * 1000) / 1000 + this.units[s];
1287 this.element.style[s] = value;
1288 }
1289 }
1290 }
1291});
1292
1293/***
1294
1295Combination effects.
1296
1297***/
1298
1299/** @id MochiKit.Visual.fade */
1300MochiKit.Visual.fade = function (element, /* optional */ options) {
1301 /***
1302
1303 Fade a given element: change its opacity and hide it in the end.
1304
1305 @param options: 'to' and 'from' to change opacity.
1306
1307 ***/
1308 var s = MochiKit.Style;
1309 var oldOpacity = s.getStyle(element, 'opacity');
1310 options = MochiKit.Base.update({
1311 from: s.getStyle(element, 'opacity') || 1.0,
1312 to: 0.0,
1313 afterFinishInternal: function (effect) {
1314 if (effect.options.to !== 0) {
1315 return;
1316 }
1317 s.hideElement(effect.element);
1318 s.setStyle(effect.element, {'opacity': oldOpacity});
1319 }
1320 }, options);
1321 return new MochiKit.Visual.Opacity(element, options);
1322};
1323
1324/** @id MochiKit.Visual.appear */
1325MochiKit.Visual.appear = function (element, /* optional */ options) {
1326 /***
1327
1328 Make an element appear.
1329
1330 @param options: 'to' and 'from' to change opacity.
1331
1332 ***/
1333 var s = MochiKit.Style;
1334 var v = MochiKit.Visual;
1335 options = MochiKit.Base.update({
1336 from: (s.getStyle(element, 'display') == 'none' ? 0.0 :
1337 s.getStyle(element, 'opacity') || 0.0),
1338 to: 1.0,
1339 // force Safari to render floated elements properly
1340 afterFinishInternal: function (effect) {
1341 v._forceRerendering(effect.element);
1342 },
1343 beforeSetupInternal: function (effect) {
1344 s.setStyle(effect.element, {'opacity': effect.options.from});
1345 s.showElement(effect.element);
1346 }
1347 }, options);
1348 return new v.Opacity(element, options);
1349};
1350
1351/** @id MochiKit.Visual.puff */
1352MochiKit.Visual.puff = function (element, /* optional */ options) {
1353 /***
1354
1355 'Puff' an element: grow it to double size, fading it and make it hidden.
1356
1357 ***/
1358 var s = MochiKit.Style;
1359 var v = MochiKit.Visual;
1360 element = MochiKit.DOM.getElement(element);
1361 var elementDimensions = MochiKit.Style.getElementDimensions(element, true);
1362 var oldStyle = {
1363 position: s.getStyle(element, 'position'),
1364 top: element.style.top,
1365 left: element.style.left,
1366 width: element.style.width,
1367 height: element.style.height,
1368 opacity: s.getStyle(element, 'opacity')
1369 };
1370 options = MochiKit.Base.update({
1371 beforeSetupInternal: function (effect) {
1372 MochiKit.Position.absolutize(effect.effects[0].element);
1373 },
1374 afterFinishInternal: function (effect) {
1375 s.hideElement(effect.effects[0].element);
1376 s.setStyle(effect.effects[0].element, oldStyle);
1377 },
1378 scaleContent: true,
1379 scaleFromCenter: true
1380 }, options);
1381 return new v.Parallel(
1382 [new v.Scale(element, 200,
1383 {sync: true, scaleFromCenter: options.scaleFromCenter,
1384 scaleMode: {originalHeight: elementDimensions.h,
1385 originalWidth: elementDimensions.w},
1386 scaleContent: options.scaleContent, restoreAfterFinish: true}),
1387 new v.Opacity(element, {sync: true, to: 0.0 })],
1388 options);
1389};
1390
1391/** @id MochiKit.Visual.blindUp */
1392MochiKit.Visual.blindUp = function (element, /* optional */ options) {
1393 /***
1394
1395 Blind an element up: change its vertical size to 0.
1396
1397 ***/
1398 var d = MochiKit.DOM;
1399 var s = MochiKit.Style;
1400 element = d.getElement(element);
1401 var elementDimensions = s.getElementDimensions(element, true);
1402 var elemClip = s.makeClipping(element);
1403 options = MochiKit.Base.update({
1404 scaleContent: false,
1405 scaleX: false,
1406 scaleMode: {originalHeight: elementDimensions.h,
1407 originalWidth: elementDimensions.w},
1408 restoreAfterFinish: true,
1409 afterFinishInternal: function (effect) {
1410 s.hideElement(effect.element);
1411 s.undoClipping(effect.element, elemClip);
1412 }
1413 }, options);
1414 return new MochiKit.Visual.Scale(element, 0, options);
1415};
1416
1417/** @id MochiKit.Visual.blindDown */
1418MochiKit.Visual.blindDown = function (element, /* optional */ options) {
1419 /***
1420
1421 Blind an element down: restore its vertical size.
1422
1423 ***/
1424 var d = MochiKit.DOM;
1425 var s = MochiKit.Style;
1426 element = d.getElement(element);
1427 var elementDimensions = s.getElementDimensions(element, true);
1428 var elemClip;
1429 options = MochiKit.Base.update({
1430 scaleContent: false,
1431 scaleX: false,
1432 scaleFrom: 0,
1433 scaleMode: {originalHeight: elementDimensions.h,
1434 originalWidth: elementDimensions.w},
1435 restoreAfterFinish: true,
1436 afterSetupInternal: function (effect) {
1437 elemClip = s.makeClipping(effect.element);
1438 s.setStyle(effect.element, {height: '0px'});
1439 s.showElement(effect.element);
1440 },
1441 afterFinishInternal: function (effect) {
1442 s.undoClipping(effect.element, elemClip);
1443 }
1444 }, options);
1445 return new MochiKit.Visual.Scale(element, 100, options);
1446};
1447
1448/** @id MochiKit.Visual.switchOff */
1449MochiKit.Visual.switchOff = function (element, /* optional */ options) {
1450 /***
1451
1452 Apply a switch-off-like effect.
1453
1454 ***/
1455 var d = MochiKit.DOM;
1456 var s = MochiKit.Style;
1457 element = d.getElement(element);
1458 var elementDimensions = s.getElementDimensions(element, true);
1459 var oldOpacity = s.getStyle(element, 'opacity');
1460 var elemClip;
1461 options = MochiKit.Base.update({
1462 duration: 0.7,
1463 restoreAfterFinish: true,
1464 beforeSetupInternal: function (effect) {
1465 s.makePositioned(element);
1466 elemClip = s.makeClipping(element);
1467 },
1468 afterFinishInternal: function (effect) {
1469 s.hideElement(element);
1470 s.undoClipping(element, elemClip);
1471 s.undoPositioned(element);
1472 s.setStyle(element, {'opacity': oldOpacity});
1473 }
1474 }, options);
1475 var v = MochiKit.Visual;
1476 return new v.Sequence(
1477 [new v.appear(element,
1478 { sync: true, duration: 0.57 * options.duration,
1479 from: 0, transition: v.Transitions.flicker }),
1480 new v.Scale(element, 1,
1481 { sync: true, duration: 0.43 * options.duration,
1482 scaleFromCenter: true, scaleX: false,
1483 scaleMode: {originalHeight: elementDimensions.h,
1484 originalWidth: elementDimensions.w},
1485 scaleContent: false, restoreAfterFinish: true })],
1486 options);
1487};
1488
1489/** @id MochiKit.Visual.dropOut */
1490MochiKit.Visual.dropOut = function (element, /* optional */ options) {
1491 /***
1492
1493 Make an element fall and disappear.
1494
1495 ***/
1496 var d = MochiKit.DOM;
1497 var s = MochiKit.Style;
1498 element = d.getElement(element);
1499 var oldStyle = {
1500 top: s.getStyle(element, 'top'),
1501 left: s.getStyle(element, 'left'),
1502 opacity: s.getStyle(element, 'opacity')
1503 };
1504
1505 options = MochiKit.Base.update({
1506 duration: 0.5,
1507 distance: 100,
1508 beforeSetupInternal: function (effect) {
1509 s.makePositioned(effect.effects[0].element);
1510 },
1511 afterFinishInternal: function (effect) {
1512 s.hideElement(effect.effects[0].element);
1513 s.undoPositioned(effect.effects[0].element);
1514 s.setStyle(effect.effects[0].element, oldStyle);
1515 }
1516 }, options);
1517 var v = MochiKit.Visual;
1518 return new v.Parallel(
1519 [new v.Move(element, {x: 0, y: options.distance, sync: true}),
1520 new v.Opacity(element, {sync: true, to: 0.0})],
1521 options);
1522};
1523
1524/** @id MochiKit.Visual.shake */
1525MochiKit.Visual.shake = function (element, /* optional */ options) {
1526 /***
1527
1528 Move an element from left to right several times.
1529
1530 ***/
1531 var d = MochiKit.DOM;
1532 var v = MochiKit.Visual;
1533 var s = MochiKit.Style;
1534 element = d.getElement(element);
1535 var oldStyle = {
1536 top: s.getStyle(element, 'top'),
1537 left: s.getStyle(element, 'left')
1538 };
1539 options = MochiKit.Base.update({
1540 duration: 0.5,
1541 afterFinishInternal: function (effect) {
1542 s.undoPositioned(element);
1543 s.setStyle(element, oldStyle);
1544 }
1545 }, options);
1546 return new v.Sequence(
1547 [new v.Move(element, { sync: true, duration: 0.1 * options.duration,
1548 x: 20, y: 0 }),
1549 new v.Move(element, { sync: true, duration: 0.2 * options.duration,
1550 x: -40, y: 0 }),
1551 new v.Move(element, { sync: true, duration: 0.2 * options.duration,
1552 x: 40, y: 0 }),
1553 new v.Move(element, { sync: true, duration: 0.2 * options.duration,
1554 x: -40, y: 0 }),
1555 new v.Move(element, { sync: true, duration: 0.2 * options.duration,
1556 x: 40, y: 0 }),
1557 new v.Move(element, { sync: true, duration: 0.1 * options.duration,
1558 x: -20, y: 0 })],
1559 options);
1560};
1561
1562/** @id MochiKit.Visual.slideDown */
1563MochiKit.Visual.slideDown = function (element, /* optional */ options) {
1564 /***
1565
1566 Slide an element down.
1567 It needs to have the content of the element wrapped in a container
1568 element with fixed height.
1569
1570 ***/
1571 var d = MochiKit.DOM;
1572 var b = MochiKit.Base;
1573 var s = MochiKit.Style;
1574 element = d.getElement(element);
1575 if (!element.firstChild) {
1576 throw new Error("MochiKit.Visual.slideDown must be used on a element with a child");
1577 }
1578 d.removeEmptyTextNodes(element);
1579 var oldInnerBottom = s.getStyle(element.firstChild, 'bottom') || 0;
1580 var elementDimensions = s.getElementDimensions(element, true);
1581 var elemClip;
1582 options = b.update({
1583 scaleContent: false,
1584 scaleX: false,
1585 scaleFrom: 0,
1586 scaleMode: {originalHeight: elementDimensions.h,
1587 originalWidth: elementDimensions.w},
1588 restoreAfterFinish: true,
1589 afterSetupInternal: function (effect) {
1590 s.makePositioned(effect.element);
1591 s.makePositioned(effect.element.firstChild);
1592 if (/Opera/.test(navigator.userAgent)) {
1593 s.setStyle(effect.element, {top: ''});
1594 }
1595 elemClip = s.makeClipping(effect.element);
1596 s.setStyle(effect.element, {height: '0px'});
1597 s.showElement(effect.element);
1598 },
1599 afterUpdateInternal: function (effect) {
1600 var elementDimensions = s.getElementDimensions(effect.element, true);
1601 s.setStyle(effect.element.firstChild,
1602 {bottom: (effect.dims[0] - elementDimensions.h) + 'px'});
1603 },
1604 afterFinishInternal: function (effect) {
1605 s.undoClipping(effect.element, elemClip);
1606 // IE will crash if child is undoPositioned first
1607 if (/MSIE/.test(navigator.userAgent)) {
1608 s.undoPositioned(effect.element);
1609 s.undoPositioned(effect.element.firstChild);
1610 } else {
1611 s.undoPositioned(effect.element.firstChild);
1612 s.undoPositioned(effect.element);
1613 }
1614 s.setStyle(effect.element.firstChild, {bottom: oldInnerBottom});
1615 }
1616 }, options);
1617
1618 return new MochiKit.Visual.Scale(element, 100, options);
1619};
1620
1621/** @id MochiKit.Visual.slideUp */
1622MochiKit.Visual.slideUp = function (element, /* optional */ options) {
1623 /***
1624
1625 Slide an element up.
1626 It needs to have the content of the element wrapped in a container
1627 element with fixed height.
1628
1629 ***/
1630 var d = MochiKit.DOM;
1631 var b = MochiKit.Base;
1632 var s = MochiKit.Style;
1633 element = d.getElement(element);
1634 if (!element.firstChild) {
1635 throw new Error("MochiKit.Visual.slideUp must be used on a element with a child");
1636 }
1637 d.removeEmptyTextNodes(element);
1638 var oldInnerBottom = s.getStyle(element.firstChild, 'bottom');
1639 var elementDimensions = s.getElementDimensions(element, true);
1640 var elemClip;
1641 options = b.update({
1642 scaleContent: false,
1643 scaleX: false,
1644 scaleMode: {originalHeight: elementDimensions.h,
1645 originalWidth: elementDimensions.w},
1646 scaleFrom: 100,
1647 restoreAfterFinish: true,
1648 beforeStartInternal: function (effect) {
1649 s.makePositioned(effect.element);
1650 s.makePositioned(effect.element.firstChild);
1651 if (/Opera/.test(navigator.userAgent)) {
1652 s.setStyle(effect.element, {top: ''});
1653 }
1654 elemClip = s.makeClipping(effect.element);
1655 s.showElement(effect.element);
1656 },
1657 afterUpdateInternal: function (effect) {
1658 var elementDimensions = s.getElementDimensions(effect.element, true);
1659 s.setStyle(effect.element.firstChild,
1660 {bottom: (effect.dims[0] - elementDimensions.h) + 'px'});
1661 },
1662 afterFinishInternal: function (effect) {
1663 s.hideElement(effect.element);
1664 s.undoClipping(effect.element, elemClip);
1665 s.undoPositioned(effect.element.firstChild);
1666 s.undoPositioned(effect.element);
1667 s.setStyle(effect.element.firstChild, {bottom: oldInnerBottom});
1668 }
1669 }, options);
1670 return new MochiKit.Visual.Scale(element, 0, options);
1671};
1672
1673// Bug in opera makes the TD containing this element expand for a instance
1674// after finish
1675/** @id MochiKit.Visual.squish */
1676MochiKit.Visual.squish = function (element, /* optional */ options) {
1677 /***
1678
1679 Reduce an element and make it disappear.
1680
1681 ***/
1682 var d = MochiKit.DOM;
1683 var b = MochiKit.Base;
1684 var s = MochiKit.Style;
1685 var elementDimensions = s.getElementDimensions(element, true);
1686 var elemClip;
1687 options = b.update({
1688 restoreAfterFinish: true,
1689 scaleMode: {originalHeight: elementDimensions.w,
1690 originalWidth: elementDimensions.h},
1691 beforeSetupInternal: function (effect) {
1692 elemClip = s.makeClipping(effect.element);
1693 },
1694 afterFinishInternal: function (effect) {
1695 s.hideElement(effect.element);
1696 s.undoClipping(effect.element, elemClip);
1697 }
1698 }, options);
1699
1700 return new MochiKit.Visual.Scale(element, /Opera/.test(navigator.userAgent) ? 1 : 0, options);
1701};
1702
1703/** @id MochiKit.Visual.grow */
1704MochiKit.Visual.grow = function (element, /* optional */ options) {
1705 /***
1706
1707 Grow an element to its original size. Make it zero-sized before
1708 if necessary.
1709
1710 ***/
1711 var d = MochiKit.DOM;
1712 var v = MochiKit.Visual;
1713 var s = MochiKit.Style;
1714 element = d.getElement(element);
1715 options = MochiKit.Base.update({
1716 direction: 'center',
1717 moveTransition: v.Transitions.sinoidal,
1718 scaleTransition: v.Transitions.sinoidal,
1719 opacityTransition: v.Transitions.full,
1720 scaleContent: true,
1721 scaleFromCenter: false
1722 }, options);
1723 var oldStyle = {
1724 top: element.style.top,
1725 left: element.style.left,
1726 height: element.style.height,
1727 width: element.style.width,
1728 opacity: s.getStyle(element, 'opacity')
1729 };
1730 var dims = s.getElementDimensions(element, true);
1731 var initialMoveX, initialMoveY;
1732 var moveX, moveY;
1733
1734 switch (options.direction) {
1735 case 'top-left':
1736 initialMoveX = initialMoveY = moveX = moveY = 0;
1737 break;
1738 case 'top-right':
1739 initialMoveX = dims.w;
1740 initialMoveY = moveY = 0;
1741 moveX = -dims.w;
1742 break;
1743 case 'bottom-left':
1744 initialMoveX = moveX = 0;
1745 initialMoveY = dims.h;
1746 moveY = -dims.h;
1747 break;
1748 case 'bottom-right':
1749 initialMoveX = dims.w;
1750 initialMoveY = dims.h;
1751 moveX = -dims.w;
1752 moveY = -dims.h;
1753 break;
1754 case 'center':
1755 initialMoveX = dims.w / 2;
1756 initialMoveY = dims.h / 2;
1757 moveX = -dims.w / 2;
1758 moveY = -dims.h / 2;
1759 break;
1760 }
1761
1762 var optionsParallel = MochiKit.Base.update({
1763 beforeSetupInternal: function (effect) {
1764 s.setStyle(effect.effects[0].element, {height: '0px'});
1765 s.showElement(effect.effects[0].element);
1766 },
1767 afterFinishInternal: function (effect) {
1768 s.undoClipping(effect.effects[0].element);
1769 s.undoPositioned(effect.effects[0].element);
1770 s.setStyle(effect.effects[0].element, oldStyle);
1771 }
1772 }, options);
1773
1774 return new v.Move(element, {
1775 x: initialMoveX,
1776 y: initialMoveY,
1777 duration: 0.01,
1778 beforeSetupInternal: function (effect) {
1779 s.hideElement(effect.element);
1780 s.makeClipping(effect.element);
1781 s.makePositioned(effect.element);
1782 },
1783 afterFinishInternal: function (effect) {
1784 new v.Parallel(
1785 [new v.Opacity(effect.element, {
1786 sync: true, to: 1.0, from: 0.0,
1787 transition: options.opacityTransition
1788 }),
1789 new v.Move(effect.element, {
1790 x: moveX, y: moveY, sync: true,
1791 transition: options.moveTransition
1792 }),
1793 new v.Scale(effect.element, 100, {
1794 scaleMode: {originalHeight: dims.h,
1795 originalWidth: dims.w},
1796 sync: true,
1797 scaleFrom: /Opera/.test(navigator.userAgent) ? 1 : 0,
1798 transition: options.scaleTransition,
1799 scaleContent: options.scaleContent,
1800 scaleFromCenter: options.scaleFromCenter,
1801 restoreAfterFinish: true
1802 })
1803 ], optionsParallel
1804 );
1805 }
1806 });
1807};
1808
1809/** @id MochiKit.Visual.shrink */
1810MochiKit.Visual.shrink = function (element, /* optional */ options) {
1811 /***
1812
1813 Shrink an element and make it disappear.
1814
1815 ***/
1816 var d = MochiKit.DOM;
1817 var v = MochiKit.Visual;
1818 var s = MochiKit.Style;
1819 element = d.getElement(element);
1820 options = MochiKit.Base.update({
1821 direction: 'center',
1822 moveTransition: v.Transitions.sinoidal,
1823 scaleTransition: v.Transitions.sinoidal,
1824 opacityTransition: v.Transitions.none,
1825 scaleContent: true,
1826 scaleFromCenter: false
1827 }, options);
1828 var oldStyle = {
1829 top: element.style.top,
1830 left: element.style.left,
1831 height: element.style.height,
1832 width: element.style.width,
1833 opacity: s.getStyle(element, 'opacity')
1834 };
1835
1836 var dims = s.getElementDimensions(element, true);
1837 var moveX, moveY;
1838
1839 switch (options.direction) {
1840 case 'top-left':
1841 moveX = moveY = 0;
1842 break;
1843 case 'top-right':
1844 moveX = dims.w;
1845 moveY = 0;
1846 break;
1847 case 'bottom-left':
1848 moveX = 0;
1849 moveY = dims.h;
1850 break;
1851 case 'bottom-right':
1852 moveX = dims.w;
1853 moveY = dims.h;
1854 break;
1855 case 'center':
1856 moveX = dims.w / 2;
1857 moveY = dims.h / 2;
1858 break;
1859 }
1860 var elemClip;
1861
1862 var optionsParallel = MochiKit.Base.update({
1863 beforeStartInternal: function (effect) {
1864 s.makePositioned(effect.effects[0].element);
1865 elemClip = s.makeClipping(effect.effects[0].element);
1866 },
1867 afterFinishInternal: function (effect) {
1868 s.hideElement(effect.effects[0].element);
1869 s.undoClipping(effect.effects[0].element, elemClip);
1870 s.undoPositioned(effect.effects[0].element);
1871 s.setStyle(effect.effects[0].element, oldStyle);
1872 }
1873 }, options);
1874
1875 return new v.Parallel(
1876 [new v.Opacity(element, {
1877 sync: true, to: 0.0, from: 1.0,
1878 transition: options.opacityTransition
1879 }),
1880 new v.Scale(element, /Opera/.test(navigator.userAgent) ? 1 : 0, {
1881 scaleMode: {originalHeight: dims.h, originalWidth: dims.w},
1882 sync: true, transition: options.scaleTransition,
1883 scaleContent: options.scaleContent,
1884 scaleFromCenter: options.scaleFromCenter,
1885 restoreAfterFinish: true
1886 }),
1887 new v.Move(element, {
1888 x: moveX, y: moveY, sync: true, transition: options.moveTransition
1889 })
1890 ], optionsParallel
1891 );
1892};
1893
1894/** @id MochiKit.Visual.pulsate */
1895MochiKit.Visual.pulsate = function (element, /* optional */ options) {
1896 /***
1897
1898 Pulse an element between appear/fade.
1899
1900 ***/
1901 var d = MochiKit.DOM;
1902 var v = MochiKit.Visual;
1903 var b = MochiKit.Base;
1904 var oldOpacity = MochiKit.Style.getStyle(element, 'opacity');
1905 options = b.update({
1906 duration: 3.0,
1907 from: 0,
1908 afterFinishInternal: function (effect) {
1909 MochiKit.Style.setStyle(effect.element, {'opacity': oldOpacity});
1910 }
1911 }, options);
1912 var transition = options.transition || v.Transitions.sinoidal;
1913 options.transition = function (pos) {
1914 return transition(1 - v.Transitions.pulse(pos, options.pulses));
1915 };
1916 return new v.Opacity(element, options);
1917};
1918
1919/** @id MochiKit.Visual.fold */
1920MochiKit.Visual.fold = function (element, /* optional */ options) {
1921 /***
1922
1923 Fold an element, first vertically, then horizontally.
1924
1925 ***/
1926 var d = MochiKit.DOM;
1927 var v = MochiKit.Visual;
1928 var s = MochiKit.Style;
1929 element = d.getElement(element);
1930 var elementDimensions = s.getElementDimensions(element, true);
1931 var oldStyle = {
1932 top: element.style.top,
1933 left: element.style.left,
1934 width: element.style.width,
1935 height: element.style.height
1936 };
1937 var elemClip = s.makeClipping(element);
1938 options = MochiKit.Base.update({
1939 scaleContent: false,
1940 scaleX: false,
1941 scaleMode: {originalHeight: elementDimensions.h,
1942 originalWidth: elementDimensions.w},
1943 afterFinishInternal: function (effect) {
1944 new v.Scale(element, 1, {
1945 scaleContent: false,
1946 scaleY: false,
1947 scaleMode: {originalHeight: elementDimensions.h,
1948 originalWidth: elementDimensions.w},
1949 afterFinishInternal: function (effect) {
1950 s.hideElement(effect.element);
1951 s.undoClipping(effect.element, elemClip);
1952 s.setStyle(effect.element, oldStyle);
1953 }
1954 });
1955 }
1956 }, options);
1957 return new v.Scale(element, 5, options);
1958};
1959
1960
1961/* end of Rico adaptation */
1962
1963MochiKit.Visual.__new__ = function () {
1964 var m = MochiKit.Base;
1965
1966 // Backwards compatibility aliases
1967 m._deprecated(this, 'Color', 'MochiKit.Color.Color', '1.1');
1968 m._deprecated(this, 'getElementsComputedStyle', 'MochiKit.Style.getStyle', '1.1');
1969
1970 m.nameFunctions(this);
1971};
1972
1973MochiKit.Visual.__new__();
1974
1975MochiKit.Base._exportSymbols(this, MochiKit.Visual);