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