├── .editorconfig ├── README.md ├── bower.json ├── css └── tabdrop.css └── js └── bootstrap-tabdrop.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | indent_style = space 7 | indent_size = 2 8 | 9 | [*.js] 10 | indent_style = tab 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | bootstrap-tabdrop 2 | ================= 3 | 4 | A dropdown tab tool for @twitter bootstrap forked from Stefan Petre's (of eyecon.ro), improvements by @jschab and @josephdburdick 5 | 6 | The dropdown tab appears when your tabs do not all fit in the same row. 7 | 8 | Original site and examples: http://www.eyecon.ro/bootstrap-tabdrop/ 9 | 10 | Added functionality: Displays the text of an active tab selected from the dropdown list instead of the text option on the dropdown tab (improved). 11 | 12 | Added functionality: Allows customizable offset to determine whether tab is overflown or not. 13 | 14 | ## Requirements 15 | 16 | * [Bootstrap](http://twitter.github.com/bootstrap/) 2.0.4+ 17 | * [jQuery](http://jquery.com/) 1.7.1+ 18 | 19 | ## Example 20 | 21 | No additional HTML needed - the script adds it when the dropdown tab is needed. It also supports tabs that have `display: flex`. 22 | 23 | Direct javascript: 24 | ```javascript 25 | this.$('.nav-tabs').tabdrop(); 26 | ``` 27 | 28 | ## Use 29 | 30 | Call the tabdrop: 31 | ```javascript 32 | .tabdrop(); 33 | ``` 34 | 35 | Call the tabdrop with options: 36 | ```javascript 37 | .tabdrop(options); 38 | ``` 39 | 40 | ### Options 41 | 42 | #### text 43 | Type: string 44 | 45 | Default: icon 46 | ```html 47 | 48 | ``` 49 | To change the default value, call 50 | ```javascript 51 | .tabdrop({text: "your text here"}); 52 | ``` 53 | when initalizing the tabdrop. The displayed value will change when a tab is selected from the dropdown list. 54 | 55 | #### align 56 | Type: string 57 | 58 | Default: right 59 | ```js 60 | $('.nav-tabs').tabdrop({align: 'left'}); 61 | ``` 62 | when initalizing the tabdrop. The tab will align on the left or right. This addresses issues with tabs that have `display: flex`. 63 | 64 | #### offsetTop 65 | Type: integer 66 | 67 | Default: 0 68 | 69 | To change the default value, call 70 | ```javascript 71 | .tabdrop({offsetTop: N}); 72 | ``` 73 | when initalizing the tabdrop. This determines when tab has to be included in the dropdown. 74 | 75 | ### Methods 76 | 77 | #### layout 78 | 79 | Checks to see if the tabs all fit in one row and displays the text of an active tab in the list: 80 | ```javascript 81 | .tabdrop('layout'); 82 | ``` 83 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootstrap-tabdrop", 3 | "version": "1.0.1", 4 | "homepage": "https://github.com/jschab/bootstrap-tabdrop", 5 | "description": "dropdown tab tool for twitter bootstrap.", 6 | "main": "js/bootstrap-tabdrop.js", 7 | "repository": { 8 | "type": "git", 9 | "url": "git://github.com/jschab/bootstrap-tabdrop.git" 10 | }, 11 | "dependencies": { 12 | "jquery": ">=1.7.1", 13 | "bootstrap": ">=2.0.4" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /css/tabdrop.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Tab drop for Bootstrap 3 | * 4 | * Copyright 2012 Stefan Petre 5 | * Improvements by Jenna Schabdach 6 | * Licensed under the Apache License v2.0 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | */ 10 | .nav-tabs, 11 | .nav-pills { 12 | position: relative; 13 | } 14 | 15 | /* adjust as needed so the tab text displays */ 16 | .tabdrop{ 17 | width: 120px; 18 | } 19 | 20 | /* hide any icons found in tabs not on first line */ 21 | .nav-tabs li li i{ 22 | visibility: hidden; 23 | } 24 | -------------------------------------------------------------------------------- /js/bootstrap-tabdrop.js: -------------------------------------------------------------------------------- 1 | /* ========================================================= 2 | * bootstrap-tabdrop.js 3 | * http://www.eyecon.ro/bootstrap-tabdrop 4 | * ========================================================= 5 | * Copyright 2012 Stefan Petre 6 | * Copyright 2013 Jenna Schabdach 7 | * Copyright 2014 Jose Ant. Aranda 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * ========================================================= */ 21 | 22 | !function ($) { 23 | 24 | var WinResizer = (function () { 25 | var registered = []; 26 | var inited = false; 27 | var timer; 28 | var resize = function () { 29 | clearTimeout(timer); 30 | timer = setTimeout(notify, 100); 31 | }; 32 | var notify = function () { 33 | for (var i = 0, cnt = registered.length; i < cnt; i++) { 34 | registered[i].apply(); 35 | } 36 | }; 37 | return { 38 | register: function (fn) { 39 | registered.push(fn); 40 | if (inited === false) { 41 | $(window).on('resize', resize); 42 | inited = true; 43 | } 44 | }, 45 | unregister: function (fn) { 46 | var registeredFnIndex = registered.indexOf(fn); 47 | if (registeredFnIndex > -1) { 48 | registered.splice(registeredFnIndex, 1); 49 | } 50 | } 51 | } 52 | }()); 53 | 54 | var TabDrop = function (element, options) { 55 | this.element = $(element); 56 | this.options = options; 57 | 58 | if (options.align === "left") 59 | this.dropdown = $('
'); 60 | else 61 | this.dropdown = $(' '); 62 | 63 | this.dropdown.prependTo(this.element); 64 | if (this.element.parent().is('.tabs-below')) { 65 | this.dropdown.addClass('dropup'); 66 | } 67 | 68 | var boundLayout = $.proxy(this.layout, this); 69 | 70 | WinResizer.register(boundLayout); 71 | this.element.on('shown.bs.tab', function (e) { 72 | boundLayout(); 73 | }); 74 | 75 | this.teardown = function () { 76 | WinResizer.unregister(boundLayout); 77 | this.element.off('shown.bs.tab', function (e) { 78 | boundLayout(); 79 | }); 80 | }; 81 | 82 | this.layout(); 83 | }; 84 | 85 | TabDrop.prototype = { 86 | constructor: TabDrop, 87 | 88 | layout: function () { 89 | var self = this; 90 | var collection = []; 91 | var isUsingFlexbox = function(el){ 92 | return el.element.css('display').indexOf('flex') > -1; 93 | }; 94 | 95 | function setDropdownText(text) { 96 | self.dropdown.find('a span.display-tab').html(text); 97 | } 98 | 99 | function setDropdownDefaultText(collection) { 100 | var text; 101 | if (jQuery.isFunction(self.options.text)) { 102 | text = self.options.text(collection); 103 | } else { 104 | text = self.options.text; 105 | } 106 | setDropdownText(text); 107 | } 108 | 109 | // Flexbox support 110 | function handleFlexbox(){ 111 | if (isUsingFlexbox(self)){ 112 | if (self.element.find('li.tabdrop').hasClass('pull-right')){ 113 | self.element.find('li.tabdrop').css({position: 'absolute', right: 0}); 114 | self.element.css('padding-right', self.element.find('.tabdrop').outerWidth(true)); 115 | } 116 | } 117 | } 118 | 119 | function checkOffsetAndPush(recursion) { 120 | self.element.find('> li:not(.tabdrop)') 121 | .each(function () { 122 | if (this.offsetTop > self.options.offsetTop) { 123 | collection.push(this); 124 | } 125 | }); 126 | 127 | if (collection.length > 0) { 128 | if (!recursion) { 129 | self.dropdown.removeClass('hide'); 130 | self.dropdown.find('ul').empty(); 131 | } 132 | self.dropdown.find('ul').prepend(collection); 133 | 134 | if (self.dropdown.find('.active').length == 1) { 135 | self.dropdown.addClass('active'); 136 | setDropdownText(self.dropdown.find('.active > a').html()); 137 | } else { 138 | self.dropdown.removeClass('active'); 139 | setDropdownDefaultText(collection); 140 | } 141 | handleFlexbox(); 142 | collection = []; 143 | checkOffsetAndPush(true); 144 | } else { 145 | if (!recursion) { 146 | self.dropdown.addClass('hide'); 147 | } 148 | } 149 | } 150 | 151 | self.element.append(self.dropdown.find('li')); 152 | checkOffsetAndPush(); 153 | } 154 | }; 155 | 156 | $.fn.tabdrop = function (option) { 157 | return this.each(function () { 158 | var $this = $(this), 159 | data = $this.data('tabdrop'), 160 | options = typeof option === 'object' && option; 161 | if (!data) { 162 | options = $.extend({}, $.fn.tabdrop.defaults, options); 163 | data = new TabDrop(this, options); 164 | $this.data('tabdrop', data); 165 | } 166 | if (typeof option == 'string') { 167 | data[option](); 168 | } 169 | }) 170 | }; 171 | 172 | $.fn.tabdrop.defaults = { 173 | text: '', 174 | offsetTop: 0 175 | }; 176 | 177 | $.fn.tabdrop.Constructor = TabDrop; 178 | 179 | }(window.jQuery); 180 | --------------------------------------------------------------------------------