summaryrefslogtreecommitdiff
path: root/frontend/beta/js/MochiKit/Visual.js
Unidiff
Diffstat (limited to 'frontend/beta/js/MochiKit/Visual.js') (more/less context) (show whitespace changes)
-rw-r--r--frontend/beta/js/MochiKit/Visual.js1976
1 files changed, 1976 insertions, 0 deletions
diff --git a/frontend/beta/js/MochiKit/Visual.js b/frontend/beta/js/MochiKit/Visual.js
new file mode 100644
index 0000000..914b3b4
--- a/dev/null
+++ b/frontend/beta/js/MochiKit/Visual.js
@@ -0,0 +1,1976 @@
1/***
2
3MochiKit.Visual 1.4
4
5See <http://mochikit.com/> for documentation, downloads, license, etc.
6
7(c) 2005 Bob Ippolito and others. All rights Reserved.
8
9***/
10
11if (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');
18}
19
20if (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", []);
26}
27
28try {
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') {
34 throw "";
35 }
36} catch (e) {
37 throw "MochiKit.Visual depends on MochiKit.Base, MochiKit.DOM, MochiKit.Style, MochiKit.Position and MochiKit.Color!";
38}
39
40if (typeof(MochiKit.Visual) == "undefined") {
41 MochiKit.Visual = {};
42}
43
44MochiKit.Visual.NAME = "MochiKit.Visual";
45MochiKit.Visual.VERSION = "1.4";
46
47MochiKit.Visual.__repr__ = function () {
48 return "[" + this.NAME + " " + this.VERSION + "]";
49};
50
51MochiKit.Visual.toString = function () {
52 return this.__repr__();
53};
54
55MochiKit.Visual._RoundCorners = function (e, options) {
56 e = MochiKit.DOM.getElement(e);
57 this._setOptions(options);
58 if (this.options.__unstable__wrapElement) {
59 e = this._doWrap(e);
60 }
61
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);
68 }
69 this.isTransparent = (color.asRGB().a <= 0);
70
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);
76 }
77
78 this._roundCornersImpl(e, color, bgColor);
79};
80
81MochiKit.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) {
87 return e;
88 }
89 var style = doc.defaultView.getComputedStyle(e, null);
90 if (typeof(style) === "undefined" || style === null) {
91 return e;
92 }
93 var wrapper = MochiKit.DOM.DIV({"style": {
94 display: "block",
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
101 padding: "0px"
102 /*
103 paddingRight: "0px",
104 paddingLeft: "0px"
105 */
106 }});
107 wrapper.innerHTML = e.innerHTML;
108 e.innerHTML = "";
109 e.appendChild(wrapper);
110 return e;
111 },
112
113 _roundCornersImpl: function (e, color, bgColor) {
114 if (this.options.border) {
115 this._renderBorder(e, bgColor);
116 }
117 if (this._isTopRounded()) {
118 this._roundTopCorners(e, color, bgColor);
119 }
120 if (this._isBottomRounded()) {
121 this._roundBottomCorners(e, color, bgColor);
122 }
123 },
124
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>";
131 },
132
133 _roundTopCorners: function (el, color, bgColor) {
134 var corner = this._createCorner(bgColor);
135 for (var i = 0; i < this.options.numSlices; i++) {
136 corner.appendChild(
137 this._createCornerSlice(color, bgColor, i, "top")
138 );
139 }
140 el.style.paddingTop = 0;
141 el.insertBefore(corner, el.firstChild);
142 },
143
144 _roundBottomCorners: function (el, color, bgColor) {
145 var corner = this._createCorner(bgColor);
146 for (var i = (this.options.numSlices - 1); i >= 0; i--) {
147 corner.appendChild(
148 this._createCornerSlice(color, bgColor, i, "bottom")
149 );
150 }
151 el.style.paddingBottom = 0;
152 el.appendChild(corner);
153 },
154
155 _createCorner: function (bgColor) {
156 var dom = MochiKit.DOM;
157 return dom.DIV({style: {backgroundColor: bgColor.toString()}});
158 },
159
160 _createCornerSlice: function (color, bgColor, n, position) {
161 var slice = MochiKit.DOM.SPAN();
162
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";
169
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";
184 }
185
186 if (!this.options.compact && (n == (this.options.numSlices - 1))) {
187 inStyle.height = "2px";
188 }
189
190 this._setMargin(slice, n, position);
191 this._setBorder(slice, n, position);
192
193 return slice;
194 },
195
196 _setOptions: function (options) {
197 this.options = {
198 corners: "all",
199 color: "fromElement",
200 bgColor: "fromParent",
201 blend: true,
202 border: false,
203 compact: false,
204 __unstable__wrapElement: false
205 };
206 MochiKit.Base.update(this.options, options);
207
208 this.options.numSlices = (this.options.compact ? 2 : 4);
209 },
210
211 _whichSideTop: function () {
212 var corners = this.options.corners;
213 if (this._hasString(corners, "all", "top")) {
214 return "";
215 }
216
217 var has_tl = (corners.indexOf("tl") != -1);
218 var has_tr = (corners.indexOf("tr") != -1);
219 if (has_tl && has_tr) {
220 return "";
221 }
222 if (has_tl) {
223 return "left";
224 }
225 if (has_tr) {
226 return "right";
227 }
228 return "";
229 },
230
231 _whichSideBottom: function () {
232 var corners = this.options.corners;
233 if (this._hasString(corners, "all", "bottom")) {
234 return "";
235 }
236
237 var has_bl = (corners.indexOf('bl') != -1);
238 var has_br = (corners.indexOf('br') != -1);
239 if (has_bl && has_br) {
240 return "";
241 }
242 if (has_bl) {
243 return "left";
244 }
245 if (has_br) {
246 return "right";
247 }
248 return "";
249 },
250
251 _borderColor: function (color, bgColor) {
252 if (color == "transparent") {
253 return bgColor;
254 } else if (this.options.border) {
255 return this.options.border;
256 } else if (this.options.blend) {
257 return bgColor.blendedColor(color);
258 }
259 return "";
260 },
261
262
263 _setMargin: function (el, n, corners) {
264 var marginSize = this._marginSize(n) + "px";
265 var whichSide = (
266 corners == "top" ? this._whichSideTop() : this._whichSideBottom()
267 );
268 var style = el.style;
269
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";
276 } else {
277 style.marginLeft = marginSize;
278 style.marginRight = marginSize;
279 }
280 },
281
282 _setBorder: function (el, n, corners) {
283 var borderSize = this._borderSize(n) + "px";
284 var whichSide = (
285 corners == "top" ? this._whichSideTop() : this._whichSideBottom()
286 );
287
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";
295 } else {
296 style.borderLeftWidth = borderSize;
297 style.borderRightWidth = borderSize;
298 }
299 },
300
301 _marginSize: function (n) {
302 if (this.isTransparent) {
303 return 0;
304 }
305
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];
316 } else {
317 var marginSizes = [5, 3, 2, 1];
318 return marginSizes[n];
319 }
320 },
321
322 _borderSize: function (n) {
323 var o = this.options;
324 var borderSizes;
325 if (o.compact && (o.blend || this.isTransparent)) {
326 return 1;
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];
335 } else {
336 return 0;
337 }
338 return borderSizes[n];
339 },
340
341 _hasString: function (str) {
342 for (var i = 1; i< arguments.length; i++) {
343 if (str.indexOf(arguments[i]) != -1) {
344 return true;
345 }
346 }
347 return false;
348 },
349
350 _isTopRounded: function () {
351 return this._hasString(this.options.corners,
352 "all", "top", "tl", "tr"
353 );
354 },
355
356 _isBottomRounded: function () {
357 return this._hasString(this.options.corners,
358 "all", "bottom", "bl", "br"
359 );
360 },
361
362 _hasSingleTextChild: function (el) {
363 return (el.childNodes.length == 1 && el.childNodes[0].nodeType == 3);
364 }
365};
366
367/** @id MochiKit.Visual.roundElement */
368MochiKit.Visual.roundElement = function (e, options) {
369 new MochiKit.Visual._RoundCorners(e, options);
370};
371
372/** @id MochiKit.Visual.roundClass */
373MochiKit.Visual.roundClass = function (tagName, className, options) {
374 var elements = MochiKit.DOM.getElementsByTagAndClassName(
375 tagName, className
376 );
377 for (var i = 0; i < elements.length; i++) {
378 MochiKit.Visual.roundElement(elements[i], options);
379 }
380};
381
382/** @id MochiKit.Visual.tagifyText */
383MochiKit.Visual.tagifyText = function (element, /* optional */tagifyStyle) {
384 /***
385
386 Change a node text to character in tags.
387
388 @param tagifyStyle: the style to apply to character nodes, default to
389 'position: relative'.
390
391 ***/
392 tagifyStyle = tagifyStyle || 'position:relative';
393 if (/MSIE/.test(navigator.userAgent)) {
394 tagifyStyle += ';zoom:1';
395 }
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);
406 }
407 }, element.childNodes);
408};
409
410/** @id MochiKit.Visual.forceRerendering */
411MochiKit.Visual.forceRerendering = function (element) {
412 try {
413 element = MochiKit.DOM.getElement(element);
414 var n = document.createTextNode(' ');
415 element.appendChild(n);
416 element.removeChild(n);
417 } catch(e) {
418 }
419};
420
421/** @id MochiKit.Visual.multiple */
422MochiKit.Visual.multiple = function (elements, effect, /* optional */options) {
423 /***
424
425 Launch the same effect subsequently on given elements.
426
427 ***/
428 options = MochiKit.Base.update({
429 speed: 0.1, delay: 0.0
430 }, options || {});
431 var masterDelay = options.delay;
432 var index = 0;
433 MochiKit.Base.map(function (innerelement) {
434 options.delay = index * options.speed + masterDelay;
435 new effect(innerelement, options);
436 index += 1;
437 }, elements);
438};
439
440MochiKit.Visual.PAIRS = {
441 'slide': ['slideDown', 'slideUp'],
442 'blind': ['blindDown', 'blindUp'],
443 'appear': ['appear', 'fade'],
444 'size': ['grow', 'shrink']
445};
446
447/** @id MochiKit.Visual.toggle */
448MochiKit.Visual.toggle = function (element, /* optional */effect, /* optional */options) {
449 /***
450
451 Toggle an item between two state depending of its visibility, making
452 a effect between these states. Default effect is 'appear', can be
453 'slide' or 'blind'.
454
455 ***/
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}
460 }, options || {});
461 var v = MochiKit.Visual;
462 v[element.style.display != 'none' ?
463 v.PAIRS[effect][1] : v.PAIRS[effect][0]](element, options);
464};
465
466/***
467
468Transitions: define functions calculating variations depending of a position.
469
470***/
471
472MochiKit.Visual.Transitions = {};
473
474/** @id MochiKit.Visual.Transitions.linear */
475MochiKit.Visual.Transitions.linear = function (pos) {
476 return pos;
477};
478
479/** @id MochiKit.Visual.Transitions.sinoidal */
480MochiKit.Visual.Transitions.sinoidal = function (pos) {
481 return (-Math.cos(pos*Math.PI)/2) + 0.5;
482};
483
484/** @id MochiKit.Visual.Transitions.reverse */
485MochiKit.Visual.Transitions.reverse = function (pos) {
486 return 1 - pos;
487};
488
489/** @id MochiKit.Visual.Transitions.flicker */
490MochiKit.Visual.Transitions.flicker = function (pos) {
491 return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
492};
493
494/** @id MochiKit.Visual.Transitions.wobble */
495MochiKit.Visual.Transitions.wobble = function (pos) {
496 return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
497};
498
499/** @id MochiKit.Visual.Transitions.pulse */
500MochiKit.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)));
503};
504
505/** @id MochiKit.Visual.Transitions.none */
506MochiKit.Visual.Transitions.none = function (pos) {
507 return 0;
508};
509
510/** @id MochiKit.Visual.Transitions.full */
511MochiKit.Visual.Transitions.full = function (pos) {
512 return 1;
513};
514
515/***
516
517Core effects
518
519***/
520
521MochiKit.Visual.ScopedQueue = function () {
522 var cls = arguments.callee;
523 if (!(this instanceof cls)) {
524 return new cls();
525 }
526 this.__init__();
527};
528
529MochiKit.Base.update(MochiKit.Visual.ScopedQueue.prototype, {
530 __init__: function () {
531 this.effects = [];
532 this.interval = null;
533 },
534
535 /** @id MochiKit.Visual.ScopedQueue.prototype.add */
536 add: function (effect) {
537 var timestamp = new Date().getTime();
538
539 var position = (typeof(effect.options.queue) == 'string') ?
540 effect.options.queue : effect.options.queue.position;
541
542 var ma = MochiKit.Base.map;
543 switch (position) {
544 case 'front':
545 // move unstarted effects after this effect
546 ma(function (e) {
547 if (e.state == 'idle') {
548 e.startOn += effect.finishOn;
549 e.finishOn += effect.finishOn;
550 }
551 }, this.effects);
552 break;
553 case 'end':
554 var finish;
555 // start effect after last queued effect has finished
556 ma(function (e) {
557 var i = e.finishOn;
558 if (i >= (finish || i)) {
559 finish = i;
560 }
561 }, this.effects);
562 timestamp = finish || timestamp;
563 break;
564 case 'break':
565 ma(function (e) {
566 e.finalize();
567 }, this.effects);
568 break;
569 }
570
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);
576 }
577
578 if (!this.interval) {
579 this.interval = this.startLoop(MochiKit.Base.bind(this.loop, this),
580 40);
581 }
582 },
583
584 /** @id MochiKit.Visual.ScopedQueue.prototype.startLoop */
585 startLoop: function (func, interval) {
586 return setInterval(func, interval);
587 },
588
589 /** @id MochiKit.Visual.ScopedQueue.prototype.remove */
590 remove: function (effect) {
591 this.effects = MochiKit.Base.filter(function (e) {
592 return e != effect;
593 }, this.effects);
594 if (!this.effects.length) {
595 this.stopLoop(this.interval);
596 this.interval = null;
597 }
598 },
599
600 /** @id MochiKit.Visual.ScopedQueue.prototype.stopLoop */
601 stopLoop: function (interval) {
602 clearInterval(interval);
603 },
604
605 /** @id MochiKit.Visual.ScopedQueue.prototype.loop */
606 loop: function () {
607 var timePos = new Date().getTime();
608 MochiKit.Base.map(function (effect) {
609 effect.loop(timePos);
610 }, this.effects);
611 }
612});
613
614MochiKit.Visual.Queues = {
615 instances: {},
616
617 get: function (queueName) {
618 if (typeof(queueName) != 'string') {
619 return queueName;
620 }
621
622 if (!this.instances[queueName]) {
623 this.instances[queueName] = new MochiKit.Visual.ScopedQueue();
624 }
625 return this.instances[queueName];
626 }
627};
628
629MochiKit.Visual.Queue = MochiKit.Visual.Queues.get('global');
630
631MochiKit.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
636 from: 0.0,
637 to: 1.0,
638 delay: 0.0,
639 queue: 'parallel'
640};
641
642MochiKit.Visual.Base = function () {};
643
644MochiKit.Visual.Base.prototype = {
645 /***
646
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.
649
650 ***/
651
652 __class__ : MochiKit.Visual.Base,
653
654 /** @id MochiKit.Visual.Base.prototype.start */
655 start: function (options) {
656 var v = MochiKit.Visual;
657 this.options = MochiKit.Base.setdefault(options || {},
658 v.DefaultOptions);
659 this.currentFrame = 0;
660 this.state = 'idle';
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);
667 }
668 },
669
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();
675 }
676 var pos = (timePos - this.startOn) / (this.finishOn - this.startOn);
677 var frame =
678 Math.round(pos * this.options.fps * this.options.duration);
679 if (frame > this.currentFrame) {
680 this.render(pos);
681 this.currentFrame = frame;
682 }
683 }
684 },
685
686 /** @id MochiKit.Visual.Base.prototype.render */
687 render: function (pos) {
688 if (this.state == 'idle') {
689 this.state = 'running';
690 this.event('beforeSetup');
691 this.setup();
692 this.event('afterSetup');
693 }
694 if (this.state == 'running') {
695 if (this.options.transition) {
696 pos = this.options.transition(pos);
697 }
698 pos *= (this.options.to - this.options.from);
699 pos += this.options.from;
700 this.event('beforeUpdate');
701 this.update(pos);
702 this.event('afterUpdate');
703 }
704 },
705
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);
711 }
712 this.state = 'finished';
713 },
714
715 /** @id MochiKit.Visual.Base.prototype.finalize */
716 finalize: function () {
717 this.render(1.0);
718 this.cancel();
719 this.event('beforeFinish');
720 this.finish();
721 this.event('afterFinish');
722 },
723
724 setup: function () {
725 },
726
727 finish: function () {
728 },
729
730 update: function (position) {
731 },
732
733 /** @id MochiKit.Visual.Base.prototype.event */
734 event: function (eventName) {
735 if (this.options[eventName + 'Internal']) {
736 this.options[eventName + 'Internal'](this);
737 }
738 if (this.options[eventName]) {
739 this.options[eventName](this);
740 }
741 },
742
743 /** @id MochiKit.Visual.Base.prototype.repr */
744 repr: function () {
745 return '[' + this.__class__.NAME + ', options:' +
746 MochiKit.Base.repr(this.options) + ']';
747 }
748};
749
750 /** @id MochiKit.Visual.Parallel */
751MochiKit.Visual.Parallel = function (effects, options) {
752 var cls = arguments.callee;
753 if (!(this instanceof cls)) {
754 return new cls(effects, options);
755 }
756
757 this.__init__(effects, options);
758};
759
760MochiKit.Visual.Parallel.prototype = new MochiKit.Visual.Base();
761
762MochiKit.Base.update(MochiKit.Visual.Parallel.prototype, {
763 /***
764
765 Run multiple effects at the same time.
766
767 ***/
768
769 __class__ : MochiKit.Visual.Parallel,
770
771 __init__: function (effects, options) {
772 this.effects = effects || [];
773 this.start(options);
774 },
775
776 /** @id MochiKit.Visual.Parallel.prototype.update */
777 update: function (position) {
778 MochiKit.Base.map(function (effect) {
779 effect.render(position);
780 }, this.effects);
781 },
782
783 /** @id MochiKit.Visual.Parallel.prototype.finish */
784 finish: function () {
785 MochiKit.Base.map(function (effect) {
786 effect.finalize();
787 }, this.effects);
788 }
789});
790
791/** @id MochiKit.Visual.Opacity */
792MochiKit.Visual.Opacity = function (element, options) {
793 var cls = arguments.callee;
794 if (!(this instanceof cls)) {
795 return new cls(element, options);
796 }
797 this.__init__(element, options);
798};
799
800MochiKit.Visual.Opacity.prototype = new MochiKit.Visual.Base();
801
802MochiKit.Base.update(MochiKit.Visual.Opacity.prototype, {
803 /***
804
805 Change the opacity of an element.
806
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.
809
810 ***/
811
812 __class__ : MochiKit.Visual.Opacity,
813
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});
822 }
823 options = b.update({
824 from: s.getStyle(this.element, 'opacity') || 0.0,
825 to: 1.0
826 }, options || {});
827 this.start(options);
828 },
829
830 /** @id MochiKit.Visual.Opacity.prototype.update */
831 update: function (position) {
832 MochiKit.Style.setStyle(this.element, {'opacity': position});
833 }
834});
835
836/** @id MochiKit.Visual.Move.prototype */
837MochiKit.Visual.Move = function (element, options) {
838 var cls = arguments.callee;
839 if (!(this instanceof cls)) {
840 return new cls(element, options);
841 }
842 this.__init__(element, options);
843};
844
845MochiKit.Visual.Move.prototype = new MochiKit.Visual.Base();
846
847MochiKit.Base.update(MochiKit.Visual.Move.prototype, {
848 /***
849
850 Move an element between its current position to a defined position
851
852 @param options: 'x' and 'y' for final positions, default to 0, 0.
853
854 ***/
855
856 __class__ : MochiKit.Visual.Move,
857
858 __init__: function (element, /* optional */options) {
859 this.element = MochiKit.DOM.getElement(element);
860 options = MochiKit.Base.update({
861 x: 0,
862 y: 0,
863 mode: 'relative'
864 }, options || {});
865 this.start(options);
866 },
867
868 /** @id MochiKit.Visual.Move.prototype.setup */
869 setup: function () {
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);
875
876 var s = this.element.style;
877 var originalVisibility = s.visibility;
878 var originalDisplay = s.display;
879 if (originalDisplay == 'none') {
880 s.visibility = 'hidden';
881 s.display = '';
882 }
883
884 this.originalLeft = parseFloat(MochiKit.Style.getStyle(this.element, 'left') || '0');
885 this.originalTop = parseFloat(MochiKit.Style.getStyle(this.element, 'top') || '0');
886
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;
891 }
892 if (originalDisplay == 'none') {
893 s.visibility = originalVisibility;
894 s.display = originalDisplay;
895 }
896 },
897
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'
903 });
904 }
905});
906
907/** @id MochiKit.Visual.Scale */
908MochiKit.Visual.Scale = function (element, percent, options) {
909 var cls = arguments.callee;
910 if (!(this instanceof cls)) {
911 return new cls(element, percent, options);
912 }
913 this.__init__(element, percent, options);
914};
915
916MochiKit.Visual.Scale.prototype = new MochiKit.Visual.Base();
917
918MochiKit.Base.update(MochiKit.Visual.Scale.prototype, {
919 /***
920
921 Change the size of an element.
922
923 @param percent: final_size = percent*original_size
924
925 @param options: several options changing scale behaviour
926
927 ***/
928
929 __class__ : MochiKit.Visual.Scale,
930
931 __init__: function (element, percent, /* optional */options) {
932 this.element = MochiKit.DOM.getElement(element);
933 options = MochiKit.Base.update({
934 scaleX: true,
935 scaleY: true,
936 scaleContent: true,
937 scaleFromCenter: false,
938 scaleMode: 'box', // 'box' or 'contents' or {} with provided values
939 scaleFrom: 100.0,
940 scaleTo: percent
941 }, options || {});
942 this.start(options);
943 },
944
945 /** @id MochiKit.Visual.Scale.prototype.setup */
946 setup: function () {
947 this.restoreAfterFinish = this.options.restoreAfterFinish || false;
948 this.elementPositioning = MochiKit.Style.getStyle(this.element,
949 'position');
950
951 var ma = MochiKit.Base.map;
952 var b = MochiKit.Base.bind;
953 this.originalStyle = {};
954 ma(b(function (k) {
955 this.originalStyle[k] = this.element.style[k];
956 }, this), ['top', 'left', 'width', 'height', 'fontSize']);
957
958 this.originalTop = this.element.offsetTop;
959 this.originalLeft = this.element.offsetLeft;
960
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;
967 }
968 }, this), ['em', 'px', '%']);
969
970 this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
971
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];
976 } else {
977 this.dims = [this.options.scaleMode.originalHeight,
978 this.options.scaleMode.originalWidth];
979 }
980 },
981
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
989 });
990 }
991 this.setDimensions(this.dims[0] * currentScale,
992 this.dims[1] * currentScale);
993 },
994
995 /** @id MochiKit.Visual.Scale.prototype.finish */
996 finish: function () {
997 if (this.restoreAfterFinish) {
998 MochiKit.Style.setStyle(this.element, this.originalStyle);
999 }
1000 },
1001
1002 /** @id MochiKit.Visual.Scale.prototype.setDimensions */
1003 setDimensions: function (height, width) {
1004 var d = {};
1005 var r = Math.round;
1006 if (/MSIE/.test(navigator.userAgent)) {
1007 r = Math.ceil;
1008 }
1009 if (this.options.scaleX) {
1010 d.width = r(width) + 'px';
1011 }
1012 if (this.options.scaleY) {
1013 d.height = r(height) + 'px';
1014 }
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';
1021 }
1022 if (this.options.scaleX) {
1023 d.left = this.originalLeft - leftd + 'px';
1024 }
1025 } else {
1026 if (this.options.scaleY) {
1027 d.top = -topd + 'px';
1028 }
1029 if (this.options.scaleX) {
1030 d.left = -leftd + 'px';
1031 }
1032 }
1033 }
1034 MochiKit.Style.setStyle(this.element, d);
1035 }
1036});
1037
1038/** @id MochiKit.Visual.Highlight */
1039MochiKit.Visual.Highlight = function (element, options) {
1040 var cls = arguments.callee;
1041 if (!(this instanceof cls)) {
1042 return new cls(element, options);
1043 }
1044 this.__init__(element, options);
1045};
1046
1047MochiKit.Visual.Highlight.prototype = new MochiKit.Visual.Base();
1048
1049MochiKit.Base.update(MochiKit.Visual.Highlight.prototype, {
1050 /***
1051
1052 Highlight an item of the page.
1053
1054 @param options: 'startcolor' for choosing highlighting color, default
1055 to '#ffff99'.
1056
1057 ***/
1058
1059 __class__ : MochiKit.Visual.Highlight,
1060
1061 __init__: function (element, /* optional */options) {
1062 this.element = MochiKit.DOM.getElement(element);
1063 options = MochiKit.Base.update({
1064 startcolor: '#ffff99'
1065 }, options || {});
1066 this.start(options);
1067 },
1068
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') {
1075 this.cancel();
1076 return;
1077 }
1078 // Disable background image during the effect
1079 this.oldStyle = {
1080 backgroundImage: s.getStyle(this.element, 'background-image')
1081 };
1082 s.setStyle(this.element, {
1083 backgroundImage: 'none'
1084 });
1085
1086 if (!this.options.endcolor) {
1087 this.options.endcolor =
1088 MochiKit.Color.Color.fromBackground(this.element).toHexString();
1089 }
1090 if (b.isUndefinedOrNull(this.options.restorecolor)) {
1091 this.options.restorecolor = s.getStyle(this.element,
1092 'background-color');
1093 }
1094 // init color calculations
1095 this._base = b.map(b.bind(function (i) {
1096 return parseInt(
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)
1101 - this._base[i];
1102 }, this), [0, 1, 2]);
1103 },
1104
1105 /** @id MochiKit.Visual.Highlight.prototype.update */
1106 update: function (position) {
1107 var m = '#';
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, {
1113 backgroundColor: m
1114 });
1115 },
1116
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
1122 }));
1123 }
1124});
1125
1126/** @id MochiKit.Visual.ScrollTo */
1127MochiKit.Visual.ScrollTo = function (element, options) {
1128 var cls = arguments.callee;
1129 if (!(this instanceof cls)) {
1130 return new cls(element, options);
1131 }
1132 this.__init__(element, options);
1133};
1134
1135MochiKit.Visual.ScrollTo.prototype = new MochiKit.Visual.Base();
1136
1137MochiKit.Base.update(MochiKit.Visual.ScrollTo.prototype, {
1138 /***
1139
1140 Scroll to an element in the page.
1141
1142 ***/
1143
1144 __class__ : MochiKit.Visual.ScrollTo,
1145
1146 __init__: function (element, /* optional */options) {
1147 this.element = MochiKit.DOM.getElement(element);
1148 this.start(options || {});
1149 },
1150
1151 /** @id MochiKit.Visual.ScrollTo.prototype.setup */
1152 setup: function () {
1153 var p = MochiKit.Position;
1154 p.prepare();
1155 var offsets = p.cumulativeOffset(this.element);
1156 if (this.options.offset) {
1157 offsets.y += this.options.offset;
1158 }
1159 var max;
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;
1168 }
1169 this.scrollStart = p.windowOffset.y;
1170 this.delta = (offsets.y > max ? max : offsets.y) - this.scrollStart;
1171 },
1172
1173 /** @id MochiKit.Visual.ScrollTo.prototype.update */
1174 update: function (position) {
1175 var p = MochiKit.Position;
1176 p.prepare();
1177 window.scrollTo(p.windowOffset.x, this.scrollStart + (position * this.delta));
1178 }
1179});
1180
1181MochiKit.Visual.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
1182
1183MochiKit.Visual.Morph = function (element, options) {
1184 var cls = arguments.callee;
1185 if (!(this instanceof cls)) {
1186 return new cls(element, options);
1187 }
1188 this.__init__(element, options);
1189};
1190
1191MochiKit.Visual.Morph.prototype = new MochiKit.Visual.Base();
1192
1193MochiKit.Base.update(MochiKit.Visual.Morph.prototype, {
1194 /***
1195
1196 Morph effect: make a transformation from current style to the given style,
1197 automatically making a transition between the two.
1198
1199 ***/
1200
1201 __class__ : MochiKit.Visual.Morph,
1202
1203 __init__: function (element, /* optional */options) {
1204 this.element = MochiKit.DOM.getElement(element);
1205 this.start(options || {});
1206 },
1207
1208 /** @id MochiKit.Visual.Morph.prototype.setup */
1209 setup: function () {
1210 var b = MochiKit.Base;
1211 var style = this.options.style;
1212 this.styleStart = {};
1213 this.styleEnd = {};
1214 this.units = {};
1215 var value, unit;
1216 for (var s in style) {
1217 value = style[s];
1218 s = b.camelize(s);
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;
1229 } else {
1230 var c = MochiKit.Color.Color;
1231 value = c.fromString(value);
1232 if (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();
1237
1238 this.styleStart[s] = b.map(b.bind(function (i) {
1239 return parseInt(
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) {
1243 return parseInt(
1244 this.styleEnd[s].slice(i*2 + 1, i*2 + 3), 16);
1245 }, this), [0, 1, 2]);
1246 }
1247 }
1248 }
1249 },
1250
1251 /** @id MochiKit.Visual.Morph.prototype.update */
1252 update: function (position) {
1253 var value;
1254 for (var s in this.styleStart) {
1255 if (this.units[s] == "color") {
1256 var m = '#';
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;
1264 } else {
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;
1267 }
1268 }
1269 }
1270});
1271
1272/***
1273
1274Combination effects.
1275
1276***/
1277
1278/** @id MochiKit.Visual.fade */
1279MochiKit.Visual.fade = function (element, /* optional */ options) {
1280 /***
1281
1282 Fade a given element: change its opacity and hide it in the end.
1283
1284 @param options: 'to' and 'from' to change opacity.
1285
1286 ***/
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,
1291 to: 0.0,
1292 afterFinishInternal: function (effect) {
1293 if (effect.options.to !== 0) {
1294 return;
1295 }
1296 s.hideElement(effect.element);
1297 s.setStyle(effect.element, {'opacity': oldOpacity});
1298 }
1299 }, options || {});
1300 return new MochiKit.Visual.Opacity(element, options);
1301};
1302
1303/** @id MochiKit.Visual.appear */
1304MochiKit.Visual.appear = function (element, /* optional */ options) {
1305 /***
1306
1307 Make an element appear.
1308
1309 @param options: 'to' and 'from' to change opacity.
1310
1311 ***/
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),
1317 to: 1.0,
1318 // force Safari to render floated elements properly
1319 afterFinishInternal: function (effect) {
1320 v.forceRerendering(effect.element);
1321 },
1322 beforeSetupInternal: function (effect) {
1323 s.setStyle(effect.element, {'opacity': effect.options.from});
1324 s.showElement(effect.element);
1325 }
1326 }, options || {});
1327 return new v.Opacity(element, options);
1328};
1329
1330/** @id MochiKit.Visual.puff */
1331MochiKit.Visual.puff = function (element, /* optional */ options) {
1332 /***
1333
1334 'Puff' an element: grow it to double size, fading it and make it hidden.
1335
1336 ***/
1337 var s = MochiKit.Style;
1338 var v = MochiKit.Visual;
1339 element = MochiKit.DOM.getElement(element);
1340 var oldStyle = {
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')
1347 };
1348 options = MochiKit.Base.update({
1349 beforeSetupInternal: function (effect) {
1350 MochiKit.Position.absolutize(effect.effects[0].element);
1351 },
1352 afterFinishInternal: function (effect) {
1353 s.hideElement(effect.effects[0].element);
1354 s.setStyle(effect.effects[0].element, oldStyle);
1355 },
1356 scaleContent: true,
1357 scaleFromCenter: true
1358 }, options || {});
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 })],
1364 options);
1365};
1366
1367/** @id MochiKit.Visual.blindUp */
1368MochiKit.Visual.blindUp = function (element, /* optional */ options) {
1369 /***
1370
1371 Blind an element up: change its vertical size to 0.
1372
1373 ***/
1374 var d = MochiKit.DOM;
1375 element = d.getElement(element);
1376 var elemClip = d.makeClipping(element);
1377 options = MochiKit.Base.update({
1378 scaleContent: false,
1379 scaleX: false,
1380 restoreAfterFinish: true,
1381 afterFinishInternal: function (effect) {
1382 MochiKit.Style.hideElement(effect.element);
1383 d.undoClipping(effect.element, elemClip);
1384 }
1385 }, options || {});
1386
1387 return new MochiKit.Visual.Scale(element, 0, options);
1388};
1389
1390/** @id MochiKit.Visual.blindDown */
1391MochiKit.Visual.blindDown = function (element, /* optional */ options) {
1392 /***
1393
1394 Blind an element down: restore its vertical size.
1395
1396 ***/
1397 var d = MochiKit.DOM;
1398 var s = MochiKit.Style;
1399 element = d.getElement(element);
1400 var elementDimensions = s.getElementDimensions(element);
1401 var elemClip;
1402 options = MochiKit.Base.update({
1403 scaleContent: false,
1404 scaleX: false,
1405 scaleFrom: 0,
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);
1413 },
1414 afterFinishInternal: function (effect) {
1415 d.undoClipping(effect.element, elemClip);
1416 }
1417 }, options || {});
1418 return new MochiKit.Visual.Scale(element, 100, options);
1419};
1420
1421/** @id MochiKit.Visual.switchOff */
1422MochiKit.Visual.switchOff = function (element, /* optional */ options) {
1423 /***
1424
1425 Apply a switch-off-like effect.
1426
1427 ***/
1428 var d = MochiKit.DOM;
1429 element = d.getElement(element);
1430 var oldOpacity = MochiKit.Style.getStyle(element, 'opacity');
1431 var elemClip;
1432 options = MochiKit.Base.update({
1433 duration: 0.3,
1434 scaleFromCenter: true,
1435 scaleX: false,
1436 scaleContent: false,
1437 restoreAfterFinish: true,
1438 beforeSetupInternal: function (effect) {
1439 d.makePositioned(effect.element);
1440 elemClip = d.makeClipping(effect.element);
1441 },
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});
1447 }
1448 }, options || {});
1449 var v = MochiKit.Visual;
1450 return new v.appear(element, {
1451 duration: 0.4,
1452 from: 0,
1453 transition: v.Transitions.flicker,
1454 afterFinishInternal: function (effect) {
1455 new v.Scale(effect.element, 1, options);
1456 }
1457 });
1458};
1459
1460/** @id MochiKit.Visual.dropOut */
1461MochiKit.Visual.dropOut = function (element, /* optional */ options) {
1462 /***
1463
1464 Make an element fall and disappear.
1465
1466 ***/
1467 var d = MochiKit.DOM;
1468 var s = MochiKit.Style;
1469 element = d.getElement(element);
1470 var oldStyle = {
1471 top: s.getStyle(element, 'top'),
1472 left: s.getStyle(element, 'left'),
1473 opacity: s.getStyle(element, 'opacity')
1474 };
1475
1476 options = MochiKit.Base.update({
1477 duration: 0.5,
1478 distance: 100,
1479 beforeSetupInternal: function (effect) {
1480 d.makePositioned(effect.effects[0].element);
1481 },
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);
1486 }
1487 }, options || {});
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})],
1492 options);
1493};
1494
1495/** @id MochiKit.Visual.shake */
1496MochiKit.Visual.shake = function (element, /* optional */ options) {
1497 /***
1498
1499 Move an element from left to right several times.
1500
1501 ***/
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({
1507 x: -20,
1508 y: 0,
1509 duration: 0.05,
1510 afterFinishInternal: function (effect) {
1511 d.undoPositioned(effect.element);
1512 s.setStyle(effect.element, oldStyle);
1513 }
1514 }, options || {});
1515 var 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 ) }}) }}) }}) }}) }});
1530};
1531
1532/** @id MochiKit.Visual.slideDown */
1533MochiKit.Visual.slideDown = function (element, /* optional */ options) {
1534 /***
1535
1536 Slide an element down.
1537 It needs to have the content of the element wrapped in a container
1538 element with fixed height.
1539
1540 ***/
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";
1547 }
1548 d.removeEmptyTextNodes(element);
1549 var oldInnerBottom = s.getStyle(element.firstChild, 'bottom') || 0;
1550 var elementDimensions = s.getElementDimensions(element);
1551 var elemClip;
1552 options = b.update({
1553 scaleContent: false,
1554 scaleX: false,
1555 scaleFrom: 0,
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: ''});
1564 }
1565 elemClip = d.makeClipping(effect.element);
1566 s.setStyle(effect.element, {height: '0px'});
1567 s.showElement(effect.element);
1568 },
1569 afterUpdateInternal: function (effect) {
1570 s.setStyle(effect.element.firstChild,
1571 {bottom: (effect.dims[0] - effect.element.clientHeight) + 'px'});
1572 },
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);
1579 } else {
1580 d.undoPositioned(effect.element.firstChild);
1581 d.undoPositioned(effect.element);
1582 }
1583 s.setStyle(effect.element.firstChild,
1584 {bottom: oldInnerBottom});
1585 }
1586 }, options || {});
1587
1588 return new MochiKit.Visual.Scale(element, 100, options);
1589};
1590
1591/** @id MochiKit.Visual.slideUp */
1592MochiKit.Visual.slideUp = function (element, /* optional */ options) {
1593 /***
1594
1595 Slide an element up.
1596 It needs to have the content of the element wrapped in a container
1597 element with fixed height.
1598
1599 ***/
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";
1606 }
1607 d.removeEmptyTextNodes(element);
1608 var oldInnerBottom = s.getStyle(element.firstChild, 'bottom');
1609 var elemClip;
1610 options = b.update({
1611 scaleContent: false,
1612 scaleX: false,
1613 scaleMode: 'box',
1614 scaleFrom: 100,
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: ''});
1621 }
1622 elemClip = d.makeClipping(effect.element);
1623 s.showElement(effect.element);
1624 },
1625 afterUpdateInternal: function (effect) {
1626 s.setStyle(effect.element.firstChild,
1627 {bottom: (effect.dims[0] - effect.element.clientHeight) + 'px'});
1628 },
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});
1635 }
1636 }, options || {});
1637 return new MochiKit.Visual.Scale(element, 0, options);
1638};
1639
1640// Bug in opera makes the TD containing this element expand for a instance
1641// after finish
1642/** @id MochiKit.Visual.squish */
1643MochiKit.Visual.squish = function (element, /* optional */ options) {
1644 /***
1645
1646 Reduce an element and make it disappear.
1647
1648 ***/
1649 var d = MochiKit.DOM;
1650 var b = MochiKit.Base;
1651 var elemClip;
1652 options = b.update({
1653 restoreAfterFinish: true,
1654 beforeSetupInternal: function (effect) {
1655 elemClip = d.makeClipping(effect.element);
1656 },
1657 afterFinishInternal: function (effect) {
1658 MochiKit.Style.hideElement(effect.element);
1659 d.undoClipping(effect.element, elemClip);
1660 }
1661 }, options || {});
1662
1663 return new MochiKit.Visual.Scale(element, /Opera/.test(navigator.userAgent) ? 1 : 0, options);
1664};
1665
1666/** @id MochiKit.Visual.grow */
1667MochiKit.Visual.grow = function (element, /* optional */ options) {
1668 /***
1669
1670 Grow an element to its original size. Make it zero-sized before
1671 if necessary.
1672
1673 ***/
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,
1683 scaleContent: true,
1684 scaleFromCenter: false
1685 }, options || {});
1686 var oldStyle = {
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')
1692 };
1693
1694 var dims = s.getElementDimensions(element);
1695 var initialMoveX, initialMoveY;
1696 var moveX, moveY;
1697
1698 switch (options.direction) {
1699 case 'top-left':
1700 initialMoveX = initialMoveY = moveX = moveY = 0;
1701 break;
1702 case 'top-right':
1703 initialMoveX = dims.w;
1704 initialMoveY = moveY = 0;
1705 moveX = -dims.w;
1706 break;
1707 case 'bottom-left':
1708 initialMoveX = moveX = 0;
1709 initialMoveY = dims.h;
1710 moveY = -dims.h;
1711 break;
1712 case 'bottom-right':
1713 initialMoveX = dims.w;
1714 initialMoveY = dims.h;
1715 moveX = -dims.w;
1716 moveY = -dims.h;
1717 break;
1718 case 'center':
1719 initialMoveX = dims.w / 2;
1720 initialMoveY = dims.h / 2;
1721 moveX = -dims.w / 2;
1722 moveY = -dims.h / 2;
1723 break;
1724 }
1725
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);
1730 },
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);
1735 }
1736 }, options || {});
1737
1738 return new v.Move(element, {
1739 x: initialMoveX,
1740 y: initialMoveY,
1741 duration: 0.01,
1742 beforeSetupInternal: function (effect) {
1743 s.hideElement(effect.element);
1744 d.makeClipping(effect.element);
1745 d.makePositioned(effect.element);
1746 },
1747 afterFinishInternal: function (effect) {
1748 new v.Parallel(
1749 [new v.Opacity(effect.element, {
1750 sync: true, to: 1.0, from: 0.0,
1751 transition: options.opacityTransition
1752 }),
1753 new v.Move(effect.element, {
1754 x: moveX, y: moveY, sync: true,
1755 transition: options.moveTransition
1756 }),
1757 new v.Scale(effect.element, 100, {
1758 scaleMode: {originalHeight: dims.h,
1759 originalWidth: dims.w},
1760 sync: true,
1761 scaleFrom: /Opera/.test(navigator.userAgent) ? 1 : 0,
1762 transition: options.scaleTransition,
1763 scaleContent: options.scaleContent,
1764 scaleFromCenter: options.scaleFromCenter,
1765 restoreAfterFinish: true
1766 })
1767 ], optionsParallel
1768 );
1769 }
1770 });
1771};
1772
1773/** @id MochiKit.Visual.shrink */
1774MochiKit.Visual.shrink = function (element, /* optional */ options) {
1775 /***
1776
1777 Shrink an element and make it disappear.
1778
1779 ***/
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,
1789 scaleContent: true,
1790 scaleFromCenter: false
1791 }, options || {});
1792 var oldStyle = {
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')
1798 };
1799
1800 var dims = s.getElementDimensions(element);
1801 var moveX, moveY;
1802
1803 switch (options.direction) {
1804 case 'top-left':
1805 moveX = moveY = 0;
1806 break;
1807 case 'top-right':
1808 moveX = dims.w;
1809 moveY = 0;
1810 break;
1811 case 'bottom-left':
1812 moveX = 0;
1813 moveY = dims.h;
1814 break;
1815 case 'bottom-right':
1816 moveX = dims.w;
1817 moveY = dims.h;
1818 break;
1819 case 'center':
1820 moveX = dims.w / 2;
1821 moveY = dims.h / 2;
1822 break;
1823 }
1824 var elemClip;
1825
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);
1830 },
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);
1836 }
1837 }, options || {});
1838
1839 return new v.Parallel(
1840 [new v.Opacity(element, {
1841 sync: true, to: 0.0, from: 1.0,
1842 transition: options.opacityTransition
1843 }),
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
1849 }),
1850 new v.Move(element, {
1851 x: moveX, y: moveY, sync: true, transition: options.moveTransition
1852 })
1853 ], optionsParallel
1854 );
1855};
1856
1857/** @id MochiKit.Visual.pulsate */
1858MochiKit.Visual.pulsate = function (element, /* optional */ options) {
1859 /***
1860
1861 Pulse an element between appear/fade.
1862
1863 ***/
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({
1869 duration: 3.0,
1870 from: 0,
1871 afterFinishInternal: function (effect) {
1872 MochiKit.Style.setStyle(effect.element, {'opacity': oldOpacity});
1873 }
1874 }, options || {});
1875 var transition = options.transition || v.Transitions.sinoidal;
1876 var reverser = b.bind(function (pos) {
1877 return transition(1 - v.Transitions.pulse(pos));
1878 }, transition);
1879 b.bind(reverser, transition);
1880 return new v.Opacity(element, b.update({
1881 transition: reverser}, options));
1882};
1883
1884/** @id MochiKit.Visual.fold */
1885MochiKit.Visual.fold = function (element, /* optional */ options) {
1886 /***
1887
1888 Fold an element, first vertically, then horizontally.
1889
1890 ***/
1891 var d = MochiKit.DOM;
1892 var v = MochiKit.Visual;
1893 var s = MochiKit.Style;
1894 element = d.getElement(element);
1895 var oldStyle = {
1896 top: element.style.top,
1897 left: element.style.left,
1898 width: element.style.width,
1899 height: element.style.height
1900 };
1901 var elemClip = d.makeClipping(element);
1902 options = MochiKit.Base.update({
1903 scaleContent: false,
1904 scaleX: false,
1905 afterFinishInternal: function (effect) {
1906 new v.Scale(element, 1, {
1907 scaleContent: false,
1908 scaleY: false,
1909 afterFinishInternal: function (effect) {
1910 s.hideElement(effect.element);
1911 d.undoClipping(effect.element, elemClip);
1912 s.setStyle(effect.element, oldStyle);
1913 }
1914 });
1915 }
1916 }, options || {});
1917 return new v.Scale(element, 5, options);
1918};
1919
1920
1921// Compatibility with MochiKit 1.0
1922MochiKit.Visual.Color = MochiKit.Color.Color;
1923MochiKit.Visual.getElementsComputedStyle = MochiKit.DOM.computedStyle;
1924
1925/* end of Rico adaptation */
1926
1927MochiKit.Visual.__new__ = function () {
1928 var m = MochiKit.Base;
1929
1930 m.nameFunctions(this);
1931
1932 this.EXPORT_TAGS = {
1933 ":common": this.EXPORT,
1934 ":all": m.concat(this.EXPORT, this.EXPORT_OK)
1935 };
1936
1937};
1938
1939MochiKit.Visual.EXPORT = [
1940 "roundElement",
1941 "roundClass",
1942 "tagifyText",
1943 "multiple",
1944 "toggle",
1945 "Parallel",
1946 "Opacity",
1947 "Move",
1948 "Scale",
1949 "Highlight",
1950 "ScrollTo",
1951 "Morph",
1952 "fade",
1953 "appear",
1954 "puff",
1955 "blindUp",
1956 "blindDown",
1957 "switchOff",
1958 "dropOut",
1959 "shake",
1960 "slideDown",
1961 "slideUp",
1962 "squish",
1963 "grow",
1964 "shrink",
1965 "pulsate",
1966 "fold"
1967];
1968
1969MochiKit.Visual.EXPORT_OK = [
1970 "Base",
1971 "PAIRS"
1972];
1973
1974MochiKit.Visual.__new__();
1975
1976MochiKit.Base._exportSymbols(this, MochiKit.Visual);