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();