jQuery UI Tabs Overflow

Extend jQuery UI Tabs to provide a dropdown when the tabs overflow / extend / exceed the parent container.

by hrabinowitz

HTML

<link rel="stylesheet" href="http://static-stage.maklarpaket.se/admin/css/jquery-ui-custom.css">
<script src="https://raw.github.com/brandonaaron/jquery-mousewheel/master/jquery.mousewheel.js"></script>
<article>
     <h1 class="has-sub">Overflow Tabs</h1>

     <h3>Extending jQuery UI Tabs</h3>

    <br>
    <p>This plugin extends jQuery UI Tabs but if the width of the tabs exceeds the width of the container then it will group the extra tabs in a simple dropdown menu.</p>
        <p>This was developed using a combination of the following sources:</p>
        <ul>
            <li>https://github.com/jasonday/plusTabs</li>
            <li>http://jsfiddle.net/mekwall/dECtZ/</li>
            <li>http://jquery.aamirafridi.com/jst/</li>
            <li>http://jsfiddle.net/Bua2d/</li>
        </ul>
    <br>
    <div id="switcher"></div>
    <br>
    <br>
    <div id="tabs">
        <ol>
            <li><a href="#tabs-1">Nunc tincidunt</a>
            </li>
            <li><a href="#tabs-2">Proin dolor</a>
            </li>
            <li><a href="#tabs-3">Aenean lacinia</a>
            </li>
            <li><a href="#tabs-4">Nunc tincidunt</a>
            </li>
            <li><a href="#tabs-5">Proin dolor</a>
            </li>
            <li><a href="#tabs-6">Aenean lacinia</a>
            </li>
            <li><a href="#tabs-7">Nunc tincidunt</a>
            </li>
            <li><a href="#tabs-8">Proin dolor</a>
            </li>
            <li><a href="#tabs-9">Aenean lacinia</a>
            </li>
            <li><a href="#tabs-10">Nunc tincidunt</a>
            </li>
            <li><a href="#tabs-11">Proin dolor</a>
            </li>
            <li><a href="#tabs-12">Aenean lacinia</a>
            </li>
            <li><a href="#tabs-13">Aenean lacinia13</a>
            </li>
            <li><a href="#tabs-14">Aenean lacinia14</a>
            </li>
            <li><a href="#tabs-15">Aenean lacinia15</a>
            </li>
            <li><a...

CSS

@import url(http://fonts.googleapis.com/css?family=Ubuntu:300);
 body, html {
    font-family: Calibri, Verdana, Arial, sans-serif;
    border: 0;
    margin: 0;
    padding: 0;
}
h1, h2, h3 {
    font-family: Ubuntu;
    line-height: 1.5;
    margin-bottom: .5em;
}
h1 {
    font-size: 2em;
}
h1.has-sub {
    margin-bottom: 0;
}
h2 {
    font-size: 1.3em;
}
ul {
    list-style: disc;
    margin-left: 1.5em;
    margin-top: .5em;
    margin-bottom: .5em;
    line-height: 1.4;
}
p {
    line-height: 1.4;
    margin-bottom: .5em;
}
header {
    background: rgb(76, 76, 76);
    /* Old browsers */
    background: -moz-linear-gradient(top, rgba(76, 76, 76, 1) 1%, rgba(63, 63, 63, 1) 100%);
    /* FF3.6+ */
    background: -webkit-gradient(linear, left top, left bottom, color-stop(1%, rgba(76, 76, 76, 1)), color-stop(100%, rgba(63, 63, 63, 1)));
    /* Chrome,Safari4+ */
    background: -webkit-linear-gradient(top, rgba(76, 76, 76, 1) 1%, rgba(63, 63, 63, 1) 100%);
    /* Chrome10+,Safari5.1+ */
    background: -o-linear-gradient(top, rgba(76, 76, 76, 1) 1%, rgba(63, 63, 63, 1) 100%);
    /* Opera11.10+ */
    background: -ms-linear-gradient(top, rgba(76, 76, 76, 1) 1%, rgba(63, 63, 63, 1) 100%);
    /* IE10+ */
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#4c4c4c', endColorstr='#3f3f3f', GradientType=0);
    /* IE6-9 */
    background: linear-gradient(top, rgba(76, 76, 76, 1) 1%, rgba(63, 63, 63, 1) 100%);
    /* W3C */
    padding: .2em 1.2em;
    font-family: Ubuntu;
    font-size: 1.3em;
    color: #999;
    text-shadow: -1px -1px 0 #333;
    text-align: right;
    box-shadow: 0 0 50px 20px rgba(0, 0, 0, .1);
    border-bottom: 1px solid #fff;
}
header span {
    margin-left: .3em;
    font-size: .6em;
}
article {
    padding: 20px;
}
.columns {
    padding: 2em;
    -webkit-column-count: 3;
    -webkit-column-gap: 5em;
    -webkit-column-rule: 1px dashed #ccc;
    column-count: 2;
    column-rule: 1px dashed #ccc;
    border: 1px solid...

JavaScript

$.widget("ui.tabs", $.ui.tabs, {
	options: {
		overflowTabs: false,
		tabPadding: 25,
		containerPadding: 0,
		dropdownSize: 50
	},
	
	_create: function() {
		this._super("_create");
		this.tabsWidth = 0;
		this.containerWidth = 0;
		
		if (!this.options.overflowTabs)
			return;
		
		// update the tabs
		this.updateOverflowTabs();
		
		// Detect a window resize and check the tabs again
		var that = this;
		$(window).resize(function() {
			// Add a slight delay after resize, to fix Maximise issue.
			setTimeout(function() {
				that.updateOverflowTabs();
			}, 150);
		});
		
		// Detect dropdown click
		$(".overflow-selector").click(function() {
			if ($('.ui-tabs-overflow').hasClass('hide')) {
				$('.ui-tabs-overflow').removeClass('hide');
			} else {
				$('.ui-tabs-overflow').addClass('hide');
			}
		});
	},
	
	refresh: function() {
		this._super("refresh");
		this.updateOverflowTabs();
	},
	
	updateOverflowTabs: function() {
		var failsafe = 0;
		this._calculateWidths();
		console.log(this.containerWidth);
		
		// Loop until tabsWidth is less than the containerWidth
		while (this.tabsWidth > this.containerWidth && failsafe < 30)
		{
			this._hideTab();
			this._calculateWidths();
			failsafe++;
		}
	
		// Finish now if there are no tabs in the overflow list
		if ($(this.element).find('.ui-tabs-overflow li').size() == 0)
			return;
			
		// Reset
		failsafe = 0;
		
		// Get the first tab in the overflow list
		var next = this._nextTab();

		// Loop until we cannot fit any more tabs
		while (next.totalSize < this.containerWidth && $(this.element).find('.ui-tabs-overflow li').size() > 0 && failsafe < 30)
		{
			this._showTab(next.tab);
			this._calculateWidths();
			
			next = this._nextTab();

			failsafe++;
		}
	},
	
	_calculateWidths: function() {
		var width = 0;
		$(this.element).find('.ui-tabs-nav > li').each(function(){
			width += $(this).outerWidth(true);
		});
		
		this.tabsWidth = width;
		this.containerWidth = $(this.element).parent().width() -...