1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Scrollable tabs 👍

This commit is contained in:
Nick O'Leary 2016-09-26 22:56:28 +01:00
parent 1866c9c7ef
commit e4626ee52b
5 changed files with 258 additions and 130 deletions

View File

@ -17,15 +17,58 @@
RED.tabs = (function() { RED.tabs = (function() {
function createTabs(options) { function createTabs(options) {
var tabs = {}; var tabs = {};
var currentTabWidth; var currentTabWidth;
var currentActiveTabWidth = 0; var currentActiveTabWidth = 0;
var ul = $("#"+options.id); var ul = $("#"+options.id);
ul.addClass("red-ui-tabs"); var wrapper = ul.wrap( "<div>" ).parent();
var scrollContainer = ul.wrap( "<div>" ).parent();
wrapper.addClass("red-ui-tabs");
if (options.addButton && typeof options.addButton === 'function') {
wrapper.addClass("red-ui-tabs-add");
var addButton = $('<div class="red-ui-tab-button"><a href="#"><i class="fa fa-plus"></i></a></div>').appendTo(wrapper);
addButton.find('a').click(function(evt) {
evt.preventDefault();
options.addButton();
})
}
var scrollLeft;
var scrollRight;
if (options.scrollable) {
wrapper.addClass("red-ui-tabs-scrollable");
scrollContainer.addClass("red-ui-tabs-scroll-container");
scrollContainer.scroll(updateScroll);
scrollLeft = $('<div class="red-ui-tab-button red-ui-tab-scroll red-ui-tab-scroll-left"><a href="#" style="display:none;"><i class="fa fa-caret-left"></i></a></div>').appendTo(wrapper).find("a");
scrollLeft.on('mousedown',function(evt) { scrollEventHandler(evt,'-=150') });
scrollRight = $('<div class="red-ui-tab-button red-ui-tab-scroll red-ui-tab-scroll-right"><a href="#" style="display:none;"><i class="fa fa-caret-right"></i></a></div>').appendTo(wrapper).find("a");
scrollRight.on('mousedown',function(evt) { scrollEventHandler(evt,'+=150') });
}
function scrollEventHandler(evt,dir) {
evt.preventDefault();
if ($(this).hasClass('disabled')) {
return;
}
var currentScrollLeft = scrollContainer.scrollLeft();
scrollContainer.animate( { scrollLeft: dir }, 300);
var interval = setInterval(function() {
var newScrollLeft = scrollContainer.scrollLeft()
if (newScrollLeft === currentScrollLeft) {
clearInterval(interval);
return;
}
currentScrollLeft = newScrollLeft;
scrollContainer.animate( { scrollLeft: dir }, 300);
},300);
$(this).one('mouseup',function() {
clearInterval(interval);
})
}
ul.children().first().addClass("active"); ul.children().first().addClass("active");
ul.children().addClass("red-ui-tab"); ul.children().addClass("red-ui-tab");
@ -34,6 +77,23 @@ RED.tabs = (function() {
return false; return false;
} }
function updateScroll() {
if (ul.children().length !== 0) {
var sl = scrollContainer.scrollLeft();
var scWidth = scrollContainer.width();
var ulWidth = ul.width();
if (sl === 0) {
scrollLeft.hide();
} else {
scrollLeft.show();
}
if (sl === ulWidth-scWidth) {
scrollRight.hide();
} else {
scrollRight.show();
}
}
}
function onTabDblClick() { function onTabDblClick() {
if (options.ondblclick) { if (options.ondblclick) {
options.ondblclick(tabs[$(this).attr('href').slice(1)]); options.ondblclick(tabs[$(this).attr('href').slice(1)]);
@ -49,6 +109,14 @@ RED.tabs = (function() {
ul.children().removeClass("active"); ul.children().removeClass("active");
ul.children().css({"transition": "width 100ms"}); ul.children().css({"transition": "width 100ms"});
link.parent().addClass("active"); link.parent().addClass("active");
if (options.scrollable) {
var pos = link.parent().position().left;
if (pos-21 < 0) {
scrollContainer.animate( { scrollLeft: '+='+(pos-50) }, 300);
} else if (pos + 120 > scrollContainer.width()) {
scrollContainer.animate( { scrollLeft: '+='+(pos + 140-scrollContainer.width()) }, 300);
}
}
if (options.onchange) { if (options.onchange) {
options.onchange(tabs[link.attr('href').slice(1)]); options.onchange(tabs[link.attr('href').slice(1)]);
} }
@ -61,23 +129,29 @@ RED.tabs = (function() {
function updateTabWidths() { function updateTabWidths() {
var tabs = ul.find("li.red-ui-tab"); var tabs = ul.find("li.red-ui-tab");
var width = ul.width(); var width = wrapper.width();
var tabCount = tabs.size(); var tabCount = tabs.size();
var tabWidth = (width-12-(tabCount*6))/tabCount; var tabWidth = (width-12-(tabCount*6))/tabCount;
currentTabWidth = 100*tabWidth/width; currentTabWidth = (100*tabWidth/width)+"%";
currentActiveTabWidth = currentTabWidth+"%"; currentActiveTabWidth = currentTabWidth+"%";
if (options.scrollable) {
if (options.hasOwnProperty("minimumActiveTabWidth")) { tabWidth = Math.max(tabWidth,140);
currentTabWidth = tabWidth+"px";
currentActiveTabWidth = 0;
var listWidth = Math.max(wrapper.width(),12+(tabWidth+6)*tabCount);
ul.width(listWidth);
updateScroll();
} else if (options.hasOwnProperty("minimumActiveTabWidth")) {
if (tabWidth < options.minimumActiveTabWidth) { if (tabWidth < options.minimumActiveTabWidth) {
tabCount -= 1; tabCount -= 1;
tabWidth = (width-12-options.minimumActiveTabWidth-(tabCount*6))/tabCount; tabWidth = (width-12-options.minimumActiveTabWidth-(tabCount*6))/tabCount;
currentTabWidth = 100*tabWidth/width; currentTabWidth = (100*tabWidth/width)+"%";
currentActiveTabWidth = options.minimumActiveTabWidth+"px"; currentActiveTabWidth = options.minimumActiveTabWidth+"px";
} else { } else {
currentActiveTabWidth = 0; currentActiveTabWidth = 0;
} }
} }
tabs.css({width:currentTabWidth+"%"}); tabs.css({width:currentTabWidth});
if (tabWidth < 50) { if (tabWidth < 50) {
ul.find(".red-ui-tab-close").hide(); ul.find(".red-ui-tab-close").hide();
ul.find(".red-ui-tab-icon").hide(); ul.find(".red-ui-tab-icon").hide();
@ -97,7 +171,9 @@ RED.tabs = (function() {
} }
ul.find("li.red-ui-tab a").on("click",onTabClick).on("dblclick",onTabDblClick); ul.find("li.red-ui-tab a").on("click",onTabClick).on("dblclick",onTabDblClick);
updateTabWidths(); setTimeout(function() {
updateTabWidths();
},0);
function removeTab(id) { function removeTab(id) {
@ -210,8 +286,6 @@ RED.tabs = (function() {
break; break;
} }
} }
// console.log(ui.position.left,ui.offset.left);
}, },
stop: function(event,ui) { stop: function(event,ui) {
ul.children().css({position:"relative",left:"",transition:""}); ul.children().css({position:"relative",left:"",transition:""});

View File

@ -166,13 +166,16 @@ RED.workspaces = (function() {
RED.nodes.dirty(true); RED.nodes.dirty(true);
setWorkspaceOrder(newOrder); setWorkspaceOrder(newOrder);
}, },
minimumActiveTabWidth: 150 minimumActiveTabWidth: 150,
scrollable: true,
addButton: function() {
addWorkspace();
}
}); });
} }
function init() { function init() {
createWorkspaceTabs(); createWorkspaceTabs();
$('#btn-workspace-add-tab').on("click",function(e) {addWorkspace(); e.preventDefault()});
RED.events.on("sidebar:resize",workspace_tabs.resize); RED.events.on("sidebar:resize",workspace_tabs.resize);
RED.menu.setAction('menu-item-workspace-delete',function() { RED.menu.setAction('menu-item-workspace-delete',function() {

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2015 IBM Corp. * Copyright 2015, 2016 IBM Corp.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -14,47 +14,174 @@
* limitations under the License. * limitations under the License.
**/ **/
ul.red-ui-tabs { .red-ui-tabs {
list-style-type: none;
padding:0;
margin: 0;
display: block;
height: 35px;
box-sizing:border-box;
white-space: nowrap;
border-bottom: 1px solid $primary-border-color;
background: #fff;
@include disable-selection;
}
ul.red-ui-tabs li {
box-sizing: border-box;
display: inline-block;
border-left: 1px solid $primary-border-color;
border-top: 1px solid $primary-border-color;
border-right: 1px solid $primary-border-color;
border-bottom: 1px solid $primary-border-color;
background: $tab-background-inactive;
margin: 3px 3px 0 3px;
height: 32px;
line-height: 29px;
max-width: 200px;
width: 14%;
overflow: hidden;
white-space: nowrap;
}
ul.red-ui-tabs li a.red-ui-tab-label {
display: block;
font-size: 14px;
padding-left: 12px;
width: 100%;
height: 100%;
color: #666;
}
ul.red-ui-tabs li {
position: relative; position: relative;
background: #fff;
overflow: hidden;
height: 35px;
box-sizing: border-box;
.red-ui-tabs-scroll-container {
height: 60px;
overflow-x: scroll;
overflow-y: hidden;
&::-webkit-scrollbar {
display: none;
}
}
& ul {
//background: #9999ff;
list-style-type: none;
padding:0;
margin: 0;
display: block;
height: 35px;
box-sizing:border-box;
border-bottom: 1px solid $primary-border-color;
white-space: nowrap;
@include disable-selection;
li {
box-sizing: border-box;
display: inline-block;
border-left: 1px solid $primary-border-color;
border-top: 1px solid $primary-border-color;
border-right: 1px solid $primary-border-color;
border-bottom: 1px solid $primary-border-color;
background: $tab-background-inactive;
margin: 3px 3px 0 3px;
height: 32px;
line-height: 29px;
max-width: 200px;
width: 14%;
overflow: hidden;
white-space: nowrap;
position: relative;
a.red-ui-tab-label {
display: block;
font-size: 14px;
padding-left: 12px;
width: 100%;
height: 100%;
color: #666;
}
a:hover {
text-decoration: none;
}
a:focus {
text-decoration: none;
}
&:not(.active) a:hover+a.red-ui-tab-close {
background: $tab-background-hover;
}
&.active {
background: $tab-background-active;
font-weight: bold;
border-bottom: 1px solid #fff;
z-index: 2;
a {
color: #333;
}
a.red-ui-tab-close {
color: #aaa;
background: $tab-background-active;
&:hover {
background: $workspace-button-background-hover !important;
color: $workspace-button-color-hover;
}
}
.red-ui-tab-icon {
opacity: 0.2;
}
}
&:not(.active) a:hover {
color: $workspace-button-color-hover;
background: $tab-background-hover;
}
}
}
&.red-ui-tabs-scrollable {
padding-left: 21px;
padding-right: 21px;
}
&.red-ui-tabs-add {
padding-right: 35px;
}
&.red-ui-tabs-add.red-ui-tabs-scrollable {
padding-right: 59px;
}
} }
.red-ui-tab-button {
position: absolute;
box-sizing: border-box;
top: 0;
right: 0;
height: 35px;
background: #fff;
border-bottom: 1px solid $primary-border-color;
z-index: 3;
a {
@include workspace-button;
line-height: 32px;
height: 32px;
width: 32px;
margin-top: 3px;
margin-right:3px;
margin-left:3px;
border: 1px solid $primary-border-color;
z-index: 3;
}
}
.red-ui-tab-scroll {
width: 21px;
top: 0;
a {
height: 35px;
width: 21px;
display: block;
color: $link-color;
font-size: 22px;
text-align: center;
margin:0;
border-left: none;
border-right: none;
border-top: none;
}
}
.red-ui-tab-scroll-left {
left:0;
a {
border-right: 1px solid $primary-border-color;
// box-shadow: 8px 0px 5px -2px rgba(0,0,0,0.1);
}
}
.red-ui-tab-scroll-right {
right: 0px;
a {
border-left: 1px solid $primary-border-color;
// box-shadow: -8px 0px 5px -2px rgba(0,0,0,0.1);
}
}
.red-ui-tabs.red-ui-tabs-add .red-ui-tab-scroll-right {
right: 38px;
}
.red-ui-tab-icon {
margin-left: -8px;
margin-right: 3px;
margin-top: -2px;
opacity: 0.1;
width: 20px;
height: 20px;
vertical-align: middle;
}
.red-ui-tabs-badges { .red-ui-tabs-badges {
position: absolute; position: absolute;
top:2px; top:2px;
@ -96,51 +223,3 @@ ul.red-ui-tabs li {
opacity: 1; opacity: 1;
} }
} }
ul.red-ui-tabs li:not(.active) a:hover+a.red-ui-tab-close {
background: $tab-background-hover;
}
ul.red-ui-tabs li.active a.red-ui-tab-close {
color: #aaa;
background: $tab-background-active;
&:hover {
background: $workspace-button-background-hover !important;
color: $workspace-button-color-hover;
}
}
ul.red-ui-tabs li a:hover {
text-decoration: none;
}
ul.red-ui-tabs li:not(.active) a:hover {
color: $workspace-button-color-hover;
background: $tab-background-hover;
}
ul.red-ui-tabs li a:focus {
text-decoration: none;
}
ul.red-ui-tabs li.active {
background: $tab-background-active;
font-weight: bold;
border-bottom: 1px solid #fff;
z-index: 2;
}
ul.red-ui-tabs li.active a {
color: #333;
}
.red-ui-tab-icon {
margin-left: -8px;
margin-right: 3px;
margin-top: -2px;
opacity: 0.1;
width: 20px;
height: 20px;
vertical-align: middle;
}
ul.red-ui-tabs li.active .red-ui-tab-icon {
opacity: 0.2;
}

View File

@ -48,33 +48,6 @@
@include component-footer-button; @include component-footer-button;
} }
#workspace-tabs {
margin-right: 35px;
}
#workspace-add-tab {
position: absolute;
box-sizing: border-box;
top: 0;
right: 0;
height: 35px;
width: 35px;
background: #fff;
border-bottom: 1px solid $primary-border-color;
}
#btn-workspace-add-tab {
@include workspace-button;
line-height: 32px;
height: 32px;
width: 32px;
margin-top: 3px;
margin-right:3px;
border: 1px solid $primary-border-color;
}
#workspace-footer { #workspace-footer {
@include component-footer; @include component-footer;
} }

View File

@ -45,7 +45,6 @@
<div id="main-container" class="sidebar-closed hide"> <div id="main-container" class="sidebar-closed hide">
<div id="workspace"> <div id="workspace">
<ul id="workspace-tabs"></ul> <ul id="workspace-tabs"></ul>
<div id="workspace-add-tab"><a id="btn-workspace-add-tab" href="#"><i class="fa fa-plus"></i></a></div>
<div id="chart" tabindex="1"></div> <div id="chart" tabindex="1"></div>
<div id="workspace-toolbar"></div> <div id="workspace-toolbar"></div>
<div id="workspace-footer"> <div id="workspace-footer">