2 * Collapsible tabs jQuery Plugin
5 var rtl = $( 'html' ).attr( 'dir' ) === 'rtl';
6 $.fn.collapsibleTabs = function ( options ) {
7 // return if the function is called on an empty jquery object
11 // Merge options into the defaults
12 var $settings = $.extend( {}, $.collapsibleTabs.defaults, options );
14 this.each( function () {
16 // add the element to our array of collapsible managers
17 $.collapsibleTabs.instances = ( $.collapsibleTabs.instances.length === 0 ?
18 $el : $.collapsibleTabs.instances.add( $el ) );
19 // attach the settings to the elements
20 $el.data( 'collapsibleTabsSettings', $settings );
21 // attach data to our collapsible elements
22 $el.children( $settings.collapsible ).each( function () {
23 $.collapsibleTabs.addData( $( this ) );
27 // if we haven't already bound our resize hanlder, bind it now
28 if ( !$.collapsibleTabs.boundEvent ) {
30 .delayedBind( '500', 'resize', function ( ) {
31 $.collapsibleTabs.handleResize();
34 // call our resize handler to setup the page
35 $.collapsibleTabs.handleResize();
39 * Returns the amount of horizontal distance between the two tabs groups
40 * (#left-navigation and #right-navigation), in pixels. If negative, this
41 * means that the tabs overlap, and the value is the width of overlapping
44 * Used in default expandCondition and collapseCondition.
46 * @return {Numeric} distance/overlap in pixels
48 function calculateTabDistance() {
49 var $leftTab, $rightTab, leftEnd, rightStart;
51 // In RTL, #right-navigation is actually on the left and vice versa.
52 // Hooray for descriptive naming.
54 $leftTab = $( '#left-navigation' );
55 $rightTab = $( '#right-navigation' );
57 $leftTab = $( '#right-navigation' );
58 $rightTab = $( '#left-navigation' );
61 leftEnd = $leftTab.offset().left + $leftTab.width();
62 rightStart = $rightTab.offset().left;
64 return rightStart - leftEnd;
70 expandedContainer: '#p-views ul',
71 collapsedContainer: '#p-cactions ul',
72 collapsible: 'li.collapsible',
74 expandCondition: function ( eleWidth ) {
75 // If there's at least eleWidth pixels free space, expand.
76 return calculateTabDistance() >= eleWidth;
78 collapseCondition: function () {
79 // If there's an overlap, collapse.
80 return calculateTabDistance() < 0;
83 addData: function ( $collapsible ) {
84 var $settings = $collapsible.parent().data( 'collapsibleTabsSettings' );
85 if ( $settings !== null ) {
86 $collapsible.data( 'collapsibleTabsSettings', {
87 expandedContainer: $settings.expandedContainer,
88 collapsedContainer: $settings.collapsedContainer,
89 expandedWidth: $collapsible.width(),
90 prevElement: $collapsible.prev()
94 getSettings: function ( $collapsible ) {
95 var $settings = $collapsible.data( 'collapsibleTabsSettings' );
96 if ( $settings === undefined ) {
97 $.collapsibleTabs.addData( $collapsible );
98 $settings = $collapsible.data( 'collapsibleTabsSettings' );
103 * @param {jQuery.Event} e
105 handleResize: function () {
106 $.collapsibleTabs.instances.each( function () {
108 data = $.collapsibleTabs.getSettings( $el );
110 if ( data.shifting ) {
114 // if the two navigations are colliding
115 if ( $el.children( data.collapsible ).length > 0 && data.collapseCondition() ) {
117 $el.trigger( 'beforeTabCollapse' );
118 // move the element to the dropdown menu
119 $.collapsibleTabs.moveToCollapsed( $el.children( data.collapsible + ':last' ) );
122 // if there are still moveable items in the dropdown menu,
123 // and there is sufficient space to place them in the tab container
124 if ( $( data.collapsedContainer + ' ' + data.collapsible ).length > 0 &&
125 data.expandCondition( $.collapsibleTabs.getSettings( $( data.collapsedContainer ).children(
126 data.collapsible + ':first' ) ).expandedWidth ) ) {
127 //move the element from the dropdown to the tab
128 $el.trigger( 'beforeTabExpand' );
130 .moveToExpanded( data.collapsedContainer + ' ' + data.collapsible + ':first' );
134 moveToCollapsed: function ( ele ) {
135 var data, expContainerSettings, target,
138 data = $.collapsibleTabs.getSettings( $moving );
142 expContainerSettings = $.collapsibleTabs.getSettings( $( data.expandedContainer ) );
143 if ( !expContainerSettings ) {
146 expContainerSettings.shifting = true;
148 // Remove the element from where it's at and put it in the dropdown menu
149 target = data.collapsedContainer;
150 $moving.css( 'position', 'relative' )
151 .css( ( rtl ? 'left' : 'right' ), 0 )
152 .animate( { width: '1px' }, 'normal', function () {
153 var data, expContainerSettings;
155 // add the placeholder
156 $( '<span class="placeholder" style="display: none;"></span>' ).insertAfter( this );
157 // XXX: 'data' is undefined here, should the 'data' from the outer scope have
159 $( this ).detach().prependTo( target ).data( 'collapsibleTabsSettings', data );
160 $( this ).attr( 'style', 'display: list-item;' );
161 data = $.collapsibleTabs.getSettings( $( ele ) );
163 expContainerSettings = $.collapsibleTabs.getSettings( $( data.expandedContainer ) );
164 if ( expContainerSettings ) {
165 expContainerSettings.shifting = false;
166 $.collapsibleTabs.handleResize();
171 moveToExpanded: function ( ele ) {
172 var data, expContainerSettings, $target, expandedWidth,
175 data = $.collapsibleTabs.getSettings( $moving );
179 expContainerSettings = $.collapsibleTabs.getSettings( $( data.expandedContainer ) );
180 if ( !expContainerSettings ) {
183 expContainerSettings.shifting = true;
185 // grab the next appearing placeholder so we can use it for replacing
186 $target = $( data.expandedContainer ).find( 'span.placeholder:first' );
187 expandedWidth = data.expandedWidth;
188 $moving.css( 'position', 'relative' ).css( ( rtl ? 'right' : 'left' ), 0 ).css( 'width', '1px' );
192 .css( 'width', '1px' )
193 .data( 'collapsibleTabsSettings', data )
194 .animate( { width: expandedWidth + 'px' }, 'normal', function () {
195 $( this ).attr( 'style', 'display: block;' );
196 var data, expContainerSettings;
197 data = $.collapsibleTabs.getSettings( $( this ) );
199 expContainerSettings = $.collapsibleTabs.getSettings( $( data.expandedContainer ) );
200 if ( expContainerSettings ) {
201 expContainerSettings.shifting = false;
202 $.collapsibleTabs.handleResize();