From 781ba420c95576ead4e8275b05fb72ea72b0d9c6 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Wed, 29 Jul 2015 17:36:07 +0200 Subject: [PATCH] Use own tabs impl in files sidebar Also change style. --- apps/files/css/detailsView.css | 1 + apps/files/js/detailsview.js | 64 ++++++++++++++++++++------ apps/files/js/detailtabview.js | 4 +- apps/files/tests/js/detailsviewSpec.js | 32 ++++++++----- core/css/apps.css | 48 +++++++++++++++++++ 5 files changed, 123 insertions(+), 26 deletions(-) diff --git a/apps/files/css/detailsView.css b/apps/files/css/detailsView.css index e89a6a36f4..78d3357fbd 100644 --- a/apps/files/css/detailsView.css +++ b/apps/files/css/detailsView.css @@ -41,3 +41,4 @@ right: 0; margin: 15px; } + diff --git a/apps/files/js/detailsview.js b/apps/files/js/detailsview.js index 03fe736856..7b7bd013f9 100644 --- a/apps/files/js/detailsview.js +++ b/apps/files/js/detailsview.js @@ -14,15 +14,17 @@ '
' + '
' + '
' + - '
' + - '
    ' + + '
    ' + + '
      ' + '
    ' + + '
    ' + + '
    ' + '
    ' + ' ' + '
'; var TEMPLATE_TAB_HEADER = - '
  • {{label}}
  • '; + '
  • {{label}}
  • '; /** * @class OCA.Files.DetailsView @@ -69,11 +71,17 @@ */ _detailFileInfoViews: [], + /** + * Id of the currently selected tab + * + * @type string + */ + _currentTabId: null, + /** * Initialize the details view */ initialize: function() { - var self = this; this.$el = $('
    '); this.fileInfo = null; this._tabViews = []; @@ -84,8 +92,10 @@ event.preventDefault(); }); + this.$el.on('click', '.tabHeaders .tabHeader', _.bind(this._onClickTab, this)); + // uncomment to add some dummy tabs for testing - // this._addTestTabs(); + //this._addTestTabs(); }, /** @@ -97,6 +107,27 @@ } }, + _onClickTab: function(e) { + var $target = $(e.target); + if (!$target.hasClass('tabHeader')) { + $target = $target.closest('.tabHeader'); + } + var tabIndex = $target.attr('data-tabindex'); + var targetTab; + if (_.isUndefined(tabIndex)) { + return; + } + + this.$el.find('.tabsContainer .tab').addClass('hidden'); + targetTab = this._tabViews[tabIndex]; + targetTab.$el.removeClass('hidden'); + + this.$el.find('.tabHeaders li').removeClass('selected'); + $target.addClass('selected'); + + e.preventDefault(); + }, + _addTestTabs: function() { for (var j = 0; j < 2; j++) { var testView = new OCA.Files.DetailTabView('testtab' + j); @@ -131,7 +162,7 @@ closeLabel: t('files', 'Close') })); var $tabsContainer = $el.find('.tabsContainer'); - var $tabHeadsContainer = $el.find('.tabHeadsContainer'); + var $tabHeadsContainer = $el.find('.tabHeaders'); var $detailsContainer = $el.find('.detailFileInfoContainer'); // render details @@ -140,14 +171,25 @@ }); if (this._tabViews.length > 0) { + if (!this._currentTab) { + this._currentTab = this._tabViews[0].getId(); + } + // render tabs - _.each(this._tabViews, function(tabView) { + _.each(this._tabViews, function(tabView, i) { // hidden by default - $tabsContainer.append(tabView.get$()); + var $el = tabView.get$(); + var isCurrent = (tabView.getId() === self._currentTab); + if (!isCurrent) { + $el.addClass('hidden'); + } + $tabsContainer.append($el); $tabHeadsContainer.append(self._templateTabHeader({ tabId: tabView.getId(), - label: tabView.getLabel() + tabIndex: i, + label: tabView.getLabel(), + selected: isCurrent })); }); } @@ -155,10 +197,6 @@ // TODO: select current tab this.$el.append($el); - - if (this._tabViews.length > 0) { - $tabsContainer.tabs({}); - } }, /** diff --git a/apps/files/js/detailtabview.js b/apps/files/js/detailtabview.js index 7e0f9eff16..b9b1dda2cc 100644 --- a/apps/files/js/detailtabview.js +++ b/apps/files/js/detailtabview.js @@ -59,8 +59,8 @@ throw 'Argument "id" is required'; } this._id = id; - this.$el = $('
    '); - this.$el.attr('id', id); + this.$el = $('
    '); + this.$el.attr('data-tabid', id); }, /** diff --git a/apps/files/tests/js/detailsviewSpec.js b/apps/files/tests/js/detailsviewSpec.js index b00c15032b..db1e24fd68 100644 --- a/apps/files/tests/js/detailsviewSpec.js +++ b/apps/files/tests/js/detailsviewSpec.js @@ -64,23 +64,20 @@ describe('OCA.Files.DetailsView tests', function() { }); }); describe('tabs', function() { - it('renders registered tabs', function() { - var testView = new OCA.Files.DetailTabView('test1'); - var testView2 = new OCA.Files.DetailTabView('test2'); + var testView, testView2; + + beforeEach(function() { + testView = new OCA.Files.DetailTabView('test1'); + testView2 = new OCA.Files.DetailTabView('test2'); detailsView.addTabView(testView); detailsView.addTabView(testView2); detailsView.render(); - - expect(detailsView.$el.find('.tabsContainer .detailTabView').length).toEqual(2); + }); + it('renders registered tabs', function() { + expect(detailsView.$el.find('.tab').length).toEqual(2); }); it('updates registered tabs when fileinfo is updated', function() { var tabRenderStub = sinon.stub(OCA.Files.DetailTabView.prototype, 'render'); - var testView = new OCA.Files.DetailTabView('test1'); - var testView2 = new OCA.Files.DetailTabView('test2'); - detailsView.addTabView(testView); - detailsView.addTabView(testView2); - detailsView.render(); - var fileInfo = {id: 5, name: 'test.txt'}; tabRenderStub.reset(); detailsView.setFileInfo(fileInfo); @@ -91,5 +88,18 @@ describe('OCA.Files.DetailsView tests', function() { expect(tabRenderStub.callCount).toEqual(2); tabRenderStub.restore(); }); + it('selects the first tab by default', function() { + expect(detailsView.$el.find('.tabHeader').eq(0).hasClass('selected')).toEqual(true); + expect(detailsView.$el.find('.tabHeader').eq(1).hasClass('selected')).toEqual(false); + expect(detailsView.$el.find('.tab').eq(0).hasClass('hidden')).toEqual(false); + expect(detailsView.$el.find('.tab').eq(1).hasClass('hidden')).toEqual(true); + }); + it('switches the current tab when clicking on tab header', function() { + detailsView.$el.find('.tabHeader').eq(1).click(); + expect(detailsView.$el.find('.tabHeader').eq(0).hasClass('selected')).toEqual(false); + expect(detailsView.$el.find('.tabHeader').eq(1).hasClass('selected')).toEqual(true); + expect(detailsView.$el.find('.tab').eq(0).hasClass('hidden')).toEqual(true); + expect(detailsView.$el.find('.tab').eq(1).hasClass('hidden')).toEqual(false); + }); }); }); diff --git a/core/css/apps.css b/core/css/apps.css index d3b9c0e709..bbeb444499 100644 --- a/core/css/apps.css +++ b/core/css/apps.css @@ -592,3 +592,51 @@ em { padding:16px; } +/* generic tab styles */ +.tabHeaders { + margin: 15px; + background-color: #1D2D44; +} + +.tabHeaders .tabHeader { + float: left; + border: 1px solid #ddd; + padding: 5px; + cursor: pointer; + background-color: #f8f8f8; + font-weight: bold; +} +.tabHeaders .tabHeader, .tabHeaders .tabHeader a { + color: #888; +} + +.tabHeaders .tabHeader:first-child { + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; +} + +.tabHeaders .tabHeader:last-child { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; +} + +.tabHeaders .tabHeader.selected, +.tabHeaders .tabHeader:hover { + background-color: #e8e8e8; +} + +.tabHeaders .tabHeader.selected, +.tabHeaders .tabHeader.selected a, +.tabHeaders .tabHeader:hover, +.tabHeaders .tabHeader:hover a { + color: #000; +} + +.tabsContainer { + clear: left; +} + +.tabsContainer .tab { + padding: 15px; +} +