summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/UploadWizard/resources/jquery/jquery.morphCrossfade.js
blob: be7ccf175f10282af71b48b61783d0670addcc55 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/**
 * jQuery Morphing Crossfade plugin
 * Copyright Neil Kandalgaonkar, 2010
 *
 * This work is licensed under the terms of the GNU General Public License,
 * version 2 or later.
 * (see http://www.fsf.org/licensing/licenses/gpl.html).
 * Derivative works and later versions of the code must be free software
 * licensed under the same or a compatible license.
 *
 * There are a lot of cross-fading plugins out there, but most assume that all
 * elements are the same, fixed width. This will also grow or shrink the container
 * vertically while crossfading. This can be useful when (for instance) you have a
 * control panel and you want to switch from a simpler interface to a more advanced
 * version. Or, perhaps you like the way the Mac OS X Preferences panel works, where
 * you click on an icon and get a crossfade effect to another dialog, even if it's one
 * with different dimensions.
 *
 * How to use it:
 * Create some DOM structure where all the panels you want to crossfade are contained in
 * one parent, e.g.
 *
 *  <div id="container">
 *    <div id="panel1"/>
 *    <div id="panel2"/>
 *    <div id="panel3"/>
 *  </div>
 *
 * Initialize the crossfader:
 *
 *   $( '#container' ).morphCrossfader();
 *
 * By default, this will hide all elements except the first child (in this case #panel1).
 *
 * Then, whenever you want to crossfade, do something like this. The currently selected panel
 * will fade away, and your selection will fade in.
 *
 *   $( '#container' ).morphCrossfade( '#panel2' );
 *
 */

( function ( $ ) {
	/**
	 * Initialize crossfading of the children of an element
	 *
	 * @return {jQuery}
	 * @chainable
	 */
	$.fn.morphCrossfader = function () {
		// the elements that are immediate children are the crossfadables
		// they must all be "on top" of each other, so position them relative
		this.css( {
			position: 'relative'
		} );
		this.children().css( {
			position: 'absolute',
			top: 0,
			left: 0,
			opacity: 0,
			visibility: 'hidden'
		} );

		// should achieve the same result as crossfade( this.children().first() ) but without
		// animation etc.
		$.each( this, function ( i, container ) {
			var $container = $( container );
			$container.morphCrossfade( $container.children().first(), 0 );
		} );

		return this;
	};

	/**
	 * Initialize crossfading of the children of an element
	 *
	 * @param {string} newPanelSelector Selector of new thing to show; should be an immediate child of the crossfader element
	 * @param {number} [speed] How fast to crossfade, in milliseconds
	 * @return {jQuery}
	 * @chainable
	 */
	$.fn.morphCrossfade = function ( newPanelSelector, speed ) {
		if ( typeof speed === 'undefined' ) {
			speed = 400;
		}

		$.each( this, function ( i, container ) {
			var $container = $( container ),
				$oldPanel = $( $container.data( 'crossfadeDisplay' ) ),
				$newPanel = ( typeof newPanelSelector === 'string' ) ?
					$container.find( newPanelSelector ) : $( newPanelSelector );

			if ( $oldPanel.get( 0 ) !== $newPanel.get( 0 ) ) {
				if ( $oldPanel.length ) {
					// remove auto setting of height from container, and
					// make doubly sure that the container height is equal to oldPanel,
					// and prevent now-oversized panels from sticking out
					$container.css( { height: $oldPanel.outerHeight() } );
					// take it out of the flow
					$oldPanel.css( { position: 'absolute' } );
					// fade WITHOUT hiding when opacity = 0
					$oldPanel.stop().animate( { opacity: 0 }, speed, 'linear', function () {
						$oldPanel.css( { visibility: 'hidden' } );
					} );
				}
				$container.data( 'crossfadeDisplay', $newPanel );

				$newPanel.css( { visibility: 'visible' } );
				$container.stop().animate( { height: $newPanel.outerHeight() }, speed, 'linear', function () {
					// we place it back into the flow, in case its size changes.
					$newPanel.css( { position: 'relative' } );
					// and allow the container to grow with it.
					$container.css( { height: 'auto' } );
				} );
				$newPanel.stop().animate( { opacity: 1 }, speed );
			}
		} );

		return this;
	};

}( jQuery ) );