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 are at least eleWidth + 1 pixels of free space, expand.
76 // We add 1 because .width() will truncate fractional values
77 // but .offset() will not.
78 return calculateTabDistance() >= (eleWidth
+ 1);
80 collapseCondition: function () {
81 // If there's an overlap, collapse.
82 return calculateTabDistance() < 0;
85 addData: function ( $collapsible
) {
86 var $settings
= $collapsible
.parent().data( 'collapsibleTabsSettings' );
88 $collapsible
.data( 'collapsibleTabsSettings', {
89 expandedContainer
: $settings
.expandedContainer
,
90 collapsedContainer
: $settings
.collapsedContainer
,
91 expandedWidth
: $collapsible
.width(),
92 prevElement
: $collapsible
.prev()
96 getSettings: function ( $collapsible
) {
97 var $settings
= $collapsible
.data( 'collapsibleTabsSettings' );
99 $.collapsibleTabs
.addData( $collapsible
);
100 $settings
= $collapsible
.data( 'collapsibleTabsSettings' );
105 * @param {jQuery.Event} e
107 handleResize: function () {
108 $.collapsibleTabs
.instances
.each( function () {
110 data
= $.collapsibleTabs
.getSettings( $el
);
112 if ( data
.shifting
) {
116 // if the two navigations are colliding
117 if ( $el
.children( data
.collapsible
).length
> 0 && data
.collapseCondition() ) {
119 $el
.trigger( 'beforeTabCollapse' );
120 // move the element to the dropdown menu
121 $.collapsibleTabs
.moveToCollapsed( $el
.children( data
.collapsible
+ ':last' ) );
124 // if there are still moveable items in the dropdown menu,
125 // and there is sufficient space to place them in the tab container
126 if ( $( data
.collapsedContainer
+ ' ' + data
.collapsible
).length
> 0 &&
127 data
.expandCondition( $.collapsibleTabs
.getSettings( $( data
.collapsedContainer
).children(
128 data
.collapsible
+ ':first' ) ).expandedWidth
) ) {
129 //move the element from the dropdown to the tab
130 $el
.trigger( 'beforeTabExpand' );
132 .moveToExpanded( data
.collapsedContainer
+ ' ' + data
.collapsible
+ ':first' );
136 moveToCollapsed: function ( ele
) {
137 var outerData
, expContainerSettings
, target
,
140 outerData
= $.collapsibleTabs
.getSettings( $moving
);
144 expContainerSettings
= $.collapsibleTabs
.getSettings( $( outerData
.expandedContainer
) );
145 if ( !expContainerSettings
) {
148 expContainerSettings
.shifting
= true;
150 // Remove the element from where it's at and put it in the dropdown menu
151 target
= outerData
.collapsedContainer
;
152 $moving
.css( 'position', 'relative' )
153 .css( ( rtl
? 'left' : 'right' ), 0 )
154 .animate( { width
: '1px' }, 'normal', function () {
155 var data
, expContainerSettings
;
157 // add the placeholder
158 $( '<span class="placeholder" style="display: none;"></span>' ).insertAfter( this );
159 $( this ).detach().prependTo( target
).data( 'collapsibleTabsSettings', outerData
);
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();