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 handler, bind it now
28 if ( !$.collapsibleTabs
.boundEvent
) {
29 $( window
).on( 'resize', $.debounce( 500, function () {
30 $.collapsibleTabs
.handleResize();
32 $.collapsibleTabs
.boundEvent
= true;
35 // call our resize handler to setup the page
36 $.collapsibleTabs
.handleResize();
40 * Returns the amount of horizontal distance between the two tabs groups
41 * (#left-navigation and #right-navigation), in pixels. If negative, this
42 * means that the tabs overlap, and the value is the width of overlapping
45 * Used in default expandCondition and collapseCondition.
47 * @return {Numeric} distance/overlap in pixels
49 function calculateTabDistance() {
50 var $leftTab
, $rightTab
, leftEnd
, rightStart
;
52 // In RTL, #right-navigation is actually on the left and vice versa.
53 // Hooray for descriptive naming.
55 $leftTab
= $( '#left-navigation' );
56 $rightTab
= $( '#right-navigation' );
58 $leftTab
= $( '#right-navigation' );
59 $rightTab
= $( '#left-navigation' );
62 leftEnd
= $leftTab
.offset().left
+ $leftTab
.width();
63 rightStart
= $rightTab
.offset().left
;
65 return rightStart
- leftEnd
;
71 expandedContainer
: '#p-views ul',
72 collapsedContainer
: '#p-cactions ul',
73 collapsible
: 'li.collapsible',
75 expandCondition: function ( eleWidth
) {
76 // If there are at least eleWidth + 1 pixels of free space, expand.
77 // We add 1 because .width() will truncate fractional values
78 // but .offset() will not.
79 return calculateTabDistance() >= (eleWidth
+ 1);
81 collapseCondition: function () {
82 // If there's an overlap, collapse.
83 return calculateTabDistance() < 0;
86 addData: function ( $collapsible
) {
87 var $settings
= $collapsible
.parent().data( 'collapsibleTabsSettings' );
89 $collapsible
.data( 'collapsibleTabsSettings', {
90 expandedContainer
: $settings
.expandedContainer
,
91 collapsedContainer
: $settings
.collapsedContainer
,
92 expandedWidth
: $collapsible
.width(),
93 prevElement
: $collapsible
.prev()
97 getSettings: function ( $collapsible
) {
98 var $settings
= $collapsible
.data( 'collapsibleTabsSettings' );
100 $.collapsibleTabs
.addData( $collapsible
);
101 $settings
= $collapsible
.data( 'collapsibleTabsSettings' );
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 outerData
, expContainerSettings
, target
,
138 outerData
= $.collapsibleTabs
.getSettings( $moving
);
142 expContainerSettings
= $.collapsibleTabs
.getSettings( $( outerData
.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
= outerData
.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 $( this ).detach().prependTo( target
).data( 'collapsibleTabsSettings', outerData
);
158 $( this ).attr( 'style', 'display: list-item;' );
159 data
= $.collapsibleTabs
.getSettings( $( ele
) );
161 expContainerSettings
= $.collapsibleTabs
.getSettings( $( data
.expandedContainer
) );
162 if ( expContainerSettings
) {
163 expContainerSettings
.shifting
= false;
164 $.collapsibleTabs
.handleResize();
169 moveToExpanded: function ( ele
) {
170 var data
, expContainerSettings
, $target
, expandedWidth
,
173 data
= $.collapsibleTabs
.getSettings( $moving
);
177 expContainerSettings
= $.collapsibleTabs
.getSettings( $( data
.expandedContainer
) );
178 if ( !expContainerSettings
) {
181 expContainerSettings
.shifting
= true;
183 // grab the next appearing placeholder so we can use it for replacing
184 $target
= $( data
.expandedContainer
).find( 'span.placeholder:first' );
185 expandedWidth
= data
.expandedWidth
;
186 $moving
.css( 'position', 'relative' ).css( ( rtl
? 'right' : 'left' ), 0 ).css( 'width', '1px' );
190 .css( 'width', '1px' )
191 .data( 'collapsibleTabsSettings', data
)
192 .animate( { width
: expandedWidth
+ 'px' }, 'normal', function () {
193 $( this ).attr( 'style', 'display: block;' );
194 var data
, expContainerSettings
;
195 data
= $.collapsibleTabs
.getSettings( $( this ) );
197 expContainerSettings
= $.collapsibleTabs
.getSettings( $( data
.expandedContainer
) );
198 if ( expContainerSettings
) {
199 expContainerSettings
.shifting
= false;
200 $.collapsibleTabs
.handleResize();