Skip to content

Commit 78111c5

Browse files
committed
get that code in there
1 parent aff979d commit 78111c5

File tree

3 files changed

+270
-1
lines changed

3 files changed

+270
-1
lines changed

README.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,28 @@
11
angular-ui-tab-scroll
22
=====================
33

4-
A scrollable tab plugin compatible with angular-ui bootstrap tabs
4+
A scrollable tab plugin compatible with angular-ui bootstrap tabs.
5+
6+
Dependencies
7+
============
8+
* Bootstrap CSS
9+
* jQuery
10+
* AngularJS
11+
* angular-ui-bootstrap
12+
13+
Usage
14+
=====
15+
16+
* Include `angular-ui-tab-scroll.js` and `angular-ui-tab-scroll.css` in your page.
17+
* Add `ui.tab.scroll` to your angular module dependencies.
18+
* Wrap your `<tabset>` inside of `<scrollable-tabset>`, like so:
19+
20+
```html
21+
<scrollable-tabset show-tooltips="true">
22+
<tabset>
23+
<tab ng-repeat="x in y">...</tab>
24+
</tabset>
25+
</scrollable-tabset>
26+
```
27+
28+
You can turn tooltips on and off with the `show-tooltips` attribute.

angular-ui-tab-scroll.css

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
.ui-tabs-scrollable {
2+
position: relative;
3+
}
4+
5+
.ui-tabs-scrollable .nav-tabs {
6+
white-space: nowrap;
7+
overflow: hidden;
8+
height: 42px!important;
9+
border-bottom: 0!important;
10+
}
11+
12+
.ui-tabs-scrollable .spacer:not(.hidden-buttons) {
13+
margin-left: 25px;
14+
margin-right: 25px;
15+
}
16+
17+
.ui-tabs-scrollable .spacer:not(.hidden-buttons) .tab-content {
18+
margin-left: -25px;
19+
margin-right: -25px;
20+
}
21+
22+
.ui-tabs-scrollable .nav > li {
23+
float: none;
24+
display: inline-block;
25+
height: 42px!important;
26+
border-bottom: 1px solid #ddd;
27+
}
28+
29+
.ui-tabs-scrollable .spacer:not(.hidden-buttons) .nav > li:first-child.active a,
30+
.ui-tabs-scrollable .spacer:not(.hidden-buttons) .nav > li:first-child a:hover {
31+
border-top-left-radius: 0!important;
32+
border-left: 1px solid transparent;
33+
}
34+
35+
.ui-tabs-scrollable .spacer:not(.hidden-buttons) .nav > li:last-child.active a,
36+
.ui-tabs-scrollable .spacer:not(.hidden-buttons) .nav > li:last-child a:hover {
37+
border-top-right-radius: 0!important;
38+
border-right: 1px solid transparent;
39+
margin-right: -1px;
40+
}
41+
42+
.ui-tabs-scrollable .nav-button {
43+
position: absolute;
44+
width: 25px;
45+
height: 42px!important;
46+
line-height: 42px;
47+
top: 0;
48+
color: #428bca;
49+
cursor: pointer;
50+
text-align: center;
51+
border: 1px solid #ddd;
52+
border-radius: 0!important;
53+
padding: 0!important;
54+
background-color: #fff;
55+
z-index: 10;
56+
}
57+
58+
.ui-tabs-scrollable .nav-button:hover {
59+
background-color: #eee;
60+
}
61+
62+
.ui-tabs-scrollable .left-nav-button {
63+
left: 0;
64+
border-top-left-radius: 4px!important;
65+
}
66+
67+
.ui-tabs-scrollable .right-nav-button {
68+
right: 0;
69+
border-top-right-radius: 4px!important;
70+
}

angular-ui-tab-scroll.js

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
angular.module('ui.tab.scroll', [])
2+
.directive('scrollableTabset', [
3+
'$window', '$interval', '$timeout',
4+
function($window, $interval, $timeout) {
5+
6+
var timeoutId = null;
7+
8+
var cancelId = function() {
9+
if(timeoutId) {
10+
$interval.cancel(timeoutId);
11+
timeoutId = null;
12+
}
13+
}
14+
15+
var unbindFunctions = function(el, cache) {
16+
if(!cache) return;
17+
el.off('mousedown', cache.mouseDown);
18+
el.off('mouseup', cache.mouseUp);
19+
};
20+
21+
var bindHoldFunctionTo = function(element, fn) {
22+
23+
var isHolding = false;
24+
25+
var mouseDown = function() {
26+
isHolding = true;
27+
28+
fn();
29+
30+
timeoutId = $interval(function() {
31+
if(isHolding) {
32+
fn();
33+
34+
if($(element).is(":disabled")) {
35+
cancelId();
36+
}
37+
}
38+
}, 100);
39+
};
40+
41+
var mouseUp = function() {
42+
isHolding = false;
43+
cancelId();
44+
};
45+
46+
element.on('mousedown', mouseDown);
47+
element.on('mouseup', mouseUp);
48+
49+
return {mouseDown: mouseDown, mouseUp: mouseUp};
50+
51+
};
52+
53+
return {
54+
restrict: 'AE',
55+
transclude: true,
56+
scope: {
57+
showTooltips: "="
58+
},
59+
template: [
60+
'<div class="ui-tabs-scrollable">',
61+
'<button ng-hide="hideButtons" ng-disabled="disableLeft()" class="btn nav-button left-nav-button" tooltip-placement="bottom" tooltip-html-unsafe="{{tooltipLeftContent()}}">',
62+
'<span class="glyphicon glyphicon-chevron-left"></span>',
63+
'</button>',
64+
'<div class="spacer" ng-class="{\'hidden-buttons\': hideButtons}" ng-transclude></div>',
65+
'<button ng-hide="hideButtons" ng-disabled="disableRight()" class="btn nav-button right-nav-button" tooltip-placement="bottom" tooltip-html-unsafe="{{tooltipRightContent()}}">',
66+
'<span class="glyphicon glyphicon-chevron-right"></span>',
67+
'</button>',
68+
'</div>'
69+
].join(''),
70+
link: function($scope, $el) {
71+
72+
$scope.currentOffset = 0;
73+
$scope.leftFunction = null;
74+
$scope.rightFunction = null;
75+
76+
$scope.toTheLeftHTML = '';
77+
$scope.toTheRightHTML = '';
78+
79+
$scope.disableLeft = function() {
80+
return !$scope.toTheLeftHTML;
81+
};
82+
83+
$scope.disableRight = function() {
84+
return !$scope.toTheRightHTML;
85+
};
86+
87+
$scope.tooltipLeftContent = function() {
88+
return $scope.showTooltips ? $scope.toTheLeftHTML : '';
89+
};
90+
91+
$scope.tooltipRightContent = function() {
92+
return $scope.showTooltips ? $scope.toTheRightHTML : '';
93+
};
94+
95+
//select the innermost child that isn't a span
96+
//this way we cover getting <tab-heading> and <tab heading=''>
97+
//but leave other markup out of it, unless it's a span (commonly an icon)
98+
var selector = '*:not(:has("*:not(span)"))';
99+
100+
$scope.toTheLeft = function() {
101+
if(!$scope.tabContainer) return;
102+
var nodes = [];
103+
$scope.tabContainer.find(selector).each(function(index, node) {
104+
var nodeObj = $(node);
105+
var nodeContainer = nodeObj.parentsUntil("ul");
106+
107+
if(nodeContainer.offset().left > 0) return;
108+
109+
nodes.push(nodeObj.html());
110+
});
111+
$scope.toTheLeftHTML = nodes.join('<br>');
112+
};
113+
114+
$scope.toTheRight = function() {
115+
if(!$scope.tabContainer) return;
116+
var nodes = [];
117+
$scope.tabContainer.find(selector).each(function(index, node) {
118+
var nodeObj = $(node);
119+
var nodeContainer = nodeObj.parentsUntil("ul");
120+
121+
var nodeWidth = nodeContainer.offset().left;
122+
123+
if(nodeWidth < $scope.tabWidth) return;
124+
125+
nodes.push(nodeObj.html());
126+
});
127+
$scope.toTheRightHTML = nodes.join('<br>');
128+
};
129+
130+
$scope.recalcSides = function() {
131+
$scope.toTheLeft();
132+
$scope.toTheRight();
133+
};
134+
135+
var generateScrollFunction = function(el, offset) {
136+
return function() {
137+
$scope.currentOffset = Math.min($scope.tabContainerWidth, Math.max(0, el.scrollLeft += offset));
138+
$scope.recalcSides();
139+
};
140+
};
141+
142+
var init = function() {
143+
var $leftNav = $el.find(".left-nav-button");
144+
var $rightNav = $el.find(".right-nav-button");
145+
var $tabs = $scope.tabContainer = $el.find(".spacer").find("ul.nav.nav-tabs");
146+
147+
var tabContainerWidth = $scope.tabContainerWidth = $tabs[0].scrollWidth;
148+
var tabWidth = $scope.tabWidth = $tabs.width();
149+
var tabScrollWidth = tabWidth / 6;
150+
var realTabs = $tabs[0];
151+
152+
$scope.hideButtons = tabContainerWidth === tabWidth;
153+
154+
$scope.leftFunction = generateScrollFunction(realTabs, -tabScrollWidth);
155+
$scope.rightfunction = generateScrollFunction(realTabs, tabScrollWidth);
156+
157+
unbindFunctions($leftNav, $scope.leftFunctionCache);
158+
unbindFunctions($rightNav, $scope.rightFunctionCache);
159+
160+
$scope.leftFunctionCache = bindHoldFunctionTo($leftNav, $scope.leftFunction);
161+
$scope.rightfunctionCache = bindHoldFunctionTo($rightNav, $scope.rightfunction);
162+
163+
$scope.recalcSides();
164+
};
165+
166+
$timeout(init, 0);
167+
168+
$(window).on('resize', function() {
169+
init();
170+
$scope.$apply();
171+
});
172+
173+
}
174+
};
175+
}]);

0 commit comments

Comments
 (0)