Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Breadcrumbs refactor #7051

Merged
merged 33 commits into from
Nov 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
9422e98
Breadcrumbs hiding calculation
skjnldsv Nov 3, 2017
9bb28ba
Flex to controls
skjnldsv Nov 3, 2017
c80b824
Fix style and flex width
skjnldsv Nov 4, 2017
9616074
Fix controls width
skjnldsv Nov 4, 2017
6ee75e1
Fixed computation and removed unwanted scripts
skjnldsv Nov 4, 2017
1786784
Popover init
skjnldsv Nov 4, 2017
03d074e
Popover filling system updated
skjnldsv Nov 4, 2017
33bac27
Do not hide root
skjnldsv Nov 6, 2017
9d3af82
Fixed breadcrumb action feedback and optimisation
skjnldsv Nov 7, 2017
396154d
Fixed click in menu
skjnldsv Nov 7, 2017
e4b190d
small bg colour fix
skjnldsv Nov 7, 2017
4fe7ec3
fix multiple span next to last crumb link
skjnldsv Nov 7, 2017
397e6af
Fix filepicker
skjnldsv Nov 7, 2017
77f6456
Fix click error on oc-dialog breadcrumb
skjnldsv Nov 7, 2017
b9fbb67
Design fix for icons
skjnldsv Nov 7, 2017
2348d14
Moved too wide header menu selector to #header
skjnldsv Nov 7, 2017
c6103dc
Popover icon
skjnldsv Nov 8, 2017
ce391ee
Scroll in popover: max 10 items shown and no flex shrink
skjnldsv Nov 8, 2017
176ad76
Fix to-be-shown algorithm
skjnldsv Nov 8, 2017
267b673
Updated tests according to new system
skjnldsv Nov 8, 2017
41210c8
Add droppable ability to menu and icon switch. Fix colour
skjnldsv Nov 8, 2017
694a96d
Fixed some more test and loop fix
skjnldsv Nov 8, 2017
f25cb7d
Menu hidden by default
skjnldsv Nov 8, 2017
b001060
Fixed remaining tests
skjnldsv Nov 8, 2017
5842729
Improve drag & drop and fix some background issue if d&d on narrow wi…
skjnldsv Nov 8, 2017
aea30e0
Scrutinizer fix
skjnldsv Nov 8, 2017
85355e9
Fixed tests and width calculation
skjnldsv Nov 8, 2017
521b8e8
Fixed header menus
skjnldsv Nov 9, 2017
2a1e9ad
Removed console log
skjnldsv Nov 9, 2017
ebf131b
Fixed firefox scrollbar
skjnldsv Nov 9, 2017
f40e56f
Fix menu declaration and width calculation
skjnldsv Nov 10, 2017
b4f5b38
Add menu tests
skjnldsv Nov 11, 2017
8c2dbeb
Added more tests and only test jsunit on drone (for testing only)
skjnldsv Nov 12, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 9 additions & 13 deletions apps/files/css/files.scss
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,6 @@
top: 44px;
}

/* make sure there's enough room for the file actions */
#body-user #filestable {
min-width: 688px; /* 768 (mobile break) - 80 (nav width) */
}
#body-user #controls {
min-width: 688px; /* 768 (mobile break) - 80 (nav width) */
}

#filestable tbody tr {
height: 51px;
}
Expand All @@ -74,12 +66,16 @@
background-color: rgb(179, 230, 255)!important;
}

.app-files #app-content.dir-drop, .file-drag #filestable tbody tr, .file-drag #filestable tbody tr:hover{
background-color: rgba(0, 0, 0, 0)!important;
.app-files #app-content.dir-drop {
background-color: $color-main-background !important;
}

.file-drag #filestable tbody tr, .file-drag #filestable tbody tr:hover{
background-color: transparent !important;
}

.app-files #app-content.dir-drop #filestable tbody tr.dropping-to-dir{
background-color: rgb(179, 230, 255)!important;
background-color: rgb(179, 230, 255) !important;
}

/* icons for sidebar */
Expand Down Expand Up @@ -740,9 +736,9 @@ table.dragshadow td.size {
margin-bottom: 2px;
}

.canDrop,
.breadcrumb .canDrop > a,
#filestable tbody tr.canDrop {
background-color: rgba(255, 255, 140, 1);
background-color: rgb(179, 230, 255);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should create a variable to unify our drag-and-drop colour. @jancborchardt

}


Expand Down
223 changes: 142 additions & 81 deletions apps/files/js/breadcrumb.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
*/
var BreadCrumb = function(options){
this.$el = $('<div class="breadcrumb"></div>');
this.$menu = $('<div class="popovermenu menu-center"><ul></ul></div>');

this.crumbSelector = '.crumb:not(.hidden):not(.crumbhome):not(.crumbmenu)';
options = options || {};
if (options.onClick) {
this.onClick = options.onClick;
Expand All @@ -47,6 +50,7 @@
}
this._detailViews = [];
};

/**
* @memberof OCA.Files
*/
Expand Down Expand Up @@ -110,19 +114,32 @@
* Renders the breadcrumb elements
*/
render: function() {
// Menu is destroyed on every change, we need to init it
OC.unregisterMenu($('.crumbmenu'), $('.crumbmenu > .popovermenu'));

var parts = this._makeCrumbs(this.dir || '/');
var $crumb;
var $menuItem;
this.$el.empty();
this.breadcrumbs = [];

for (var i = 0; i < parts.length; i++) {
var part = parts[i];
var $image;
var $link = $('<a></a>').attr('href', this.getCrumbUrl(part, i));
$link.text(part.name);
var $link = $('<a></a>');
$crumb = $('<div class="crumb svg"></div>');
if(part.dir) {
$link.attr('href', this.getCrumbUrl(part, i));
}
if(part.name) {
$link.text(part.name);
}
$link.addClass(part.linkclass);
$crumb.append($link);
$crumb.attr('data-dir', part.dir);
$crumb.data('dir', part.dir);
// Ignore menu button
$crumb.data('crumb-id', i - 1);
$crumb.addClass(part.class);

if (part.img) {
$image = $('<img class="svg"></img>');
Expand All @@ -132,12 +149,27 @@
}
this.breadcrumbs.push($crumb);
this.$el.append($crumb);
if (this.onClick) {
$crumb.on('click', this.onClick);
// Only add feedback if not menu
if (this.onClick && i !== 0) {
$link.on('click', this.onClick);
}
}
$crumb.addClass('last');

// Menu creation
this._createMenu();
for (var j = 0; j < parts.length; j++) {
var menuPart = parts[j];
if(menuPart.dir) {
$menuItem = $('<li class="crumblist"><a><span class="icon-folder"></span><span></span></a></li>');
$menuItem.data('dir', menuPart.dir);
$menuItem.find('a').attr('href', this.getCrumbUrl(part, j));
$menuItem.find('span:eq(1)').text(menuPart.name);
this.$menu.children('ul').append($menuItem);
if (this.onClick) {
$menuItem.on('click', this.onClick);
}
}
}
_.each(this._detailViews, function(view) {
view.render({
dirInfo: this.dirInfo
Expand All @@ -152,16 +184,20 @@

// setup drag and drop
if (this.onDrop) {
this.$el.find('.crumb:not(.last)').droppable({
this.$el.find('.crumb:not(:last-child):not(.crumbmenu), .crumblist:not(:last-child)').droppable({
drop: this.onDrop,
over: this.onOver,
out: this.onOut,
tolerance: 'pointer',
hoverClass: 'canDrop'
hoverClass: 'canDrop',
greedy: true
});
}

this._updateTotalWidth();
// Menu is destroyed on every change, we need to init it
OC.registerMenu($('.crumbmenu'), $('.crumbmenu > .popovermenu'));

this._resize();
},

/**
Expand All @@ -179,12 +215,17 @@
if (dir === '') {
parts = [];
}
// menu part
crumbs.push({
class: 'crumbmenu hidden',
linkclass: 'icon-more'
});
// root part
crumbs.push({
name: t('core', 'Home'),
dir: '/',
name: '',
alt: t('files', 'Home'),
img: OC.imagePath('core', 'places/home.svg')
class: 'crumbhome',
linkclass: 'icon-home'
});
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
Expand All @@ -197,23 +238,10 @@
return crumbs;
},

/**
* Calculate the total breadcrumb width when
* all crumbs are expanded
*/
_updateTotalWidth: function () {
this.totalWidth = 0;
for (var i = 0; i < this.breadcrumbs.length; i++ ) {
var $crumb = $(this.breadcrumbs[i]);
$crumb.data('real-width', $crumb.width());
this.totalWidth += $crumb.width();
}
this._resize();
},

/**
* Show/hide breadcrumbs to fit the given width
*
* Mostly used by tests
*
* @param {int} availableWidth available width
*/
setMaxWidth: function (availableWidth) {
Expand All @@ -223,74 +251,107 @@
}
},

_resize: function() {
var i, $crumb, $ellipsisCrumb;

if (!this.availableWidth) {
this.availableWidth = this.$el.width();
/**
* Calculate real width based on individual crumbs
* More accurate and works with tests
*
* @param {boolean} ignoreHidden ignore hidden crumbs
*/
getTotalWidth: function(ignoreHidden) {
var totalWidth = 0;
for (var i = 0; i < this.breadcrumbs.length; i++ ) {
var $crumb = $(this.breadcrumbs[i]);
if(!$crumb.hasClass('hidden') || ignoreHidden === true) {
totalWidth += $crumb.outerWidth();
}
}
return totalWidth;
},

if (this.breadcrumbs.length <= 1) {
return;
/**
* Hide the middle crumb
*/
_hideCrumb: function() {
var length = this.$el.find(this.crumbSelector).length;
// Get the middle one floored down
var elmt = Math.floor(length / 2 - 0.5);
this.$el.find(this.crumbSelector+':eq('+elmt+')').addClass('hidden');
},

/**
* Get the crumb to show
*/
_getCrumbElement: function() {
var hidden = this.$el.find('.crumb.hidden').length;
var shown = this.$el.find(this.crumbSelector).length;
// Get the outer one with priority to the highest
var elmt = (1 - shown % 2) * (hidden - 1);
return this.$el.find('.crumb.hidden:eq('+elmt+')');
},

/**
* Show the middle crumb
*/
_showCrumb: function() {
if(this.$el.find('.crumb.hidden').length === 1) {
this.$el.find('.crumb.hidden').removeClass('hidden');
}
this._getCrumbElement().removeClass('hidden');
},

/**
* Create and append the popovermenu
*/
_createMenu: function() {
this.$el.find('.crumbmenu').append(this.$menu);
this.$menu.children('ul').empty();
},

/**
* Update the popovermenu
*/
_updateMenu: function() {
var menuItems = this.$el.find('.crumb.hidden');
// Hide the crumb menu if no elements
this.$el.find('.crumbmenu').toggleClass('hidden', menuItems.length === 0);

// reset crumbs
this.$el.find('.crumb.ellipsized').remove();
this.$menu.find('li').addClass('in-breadcrumb');
for (var i = 0; i < menuItems.length; i++) {
var crumbId = $(menuItems[i]).data('crumb-id');
this.$menu.find('li:eq('+crumbId+')').removeClass('in-breadcrumb');
}
},

// unhide all
this.$el.find('.crumb.hidden').removeClass('hidden');
_resize: function() {

if (this.totalWidth <= this.availableWidth) {
// no need to compute breadcrumbs, there is enough space
if (this.breadcrumbs.length <= 2) {
// home & menu
return;
}

// running width, considering the hidden crumbs
var currentTotalWidth = $(this.breadcrumbs[0]).data('real-width');
var firstHidden = true;

// insert ellipsis after root part (root part is always visible)
$ellipsisCrumb = $('<div class="crumb ellipsized svg"><span class="ellipsis">...</span></div>');
$(this.breadcrumbs[0]).after($ellipsisCrumb);
currentTotalWidth += $ellipsisCrumb.width();

i = this.breadcrumbs.length - 1;

// find the first section that would cause the overflow
// then hide everything in front of that
//
// this ensures that the last crumb section stays visible
// for most of the cases and is always the last one to be
// hidden when the screen becomes very narrow
while (i > 0) {
$crumb = $(this.breadcrumbs[i]);
// if the current breadcrumb would cause overflow
if (!firstHidden || currentTotalWidth + $crumb.data('real-width') > this.availableWidth) {
// hide it
$crumb.addClass('hidden');
if (firstHidden) {
// set the path of this one as title for the ellipsis
this.$el.find('.crumb.ellipsized')
.attr('title', $crumb.attr('data-dir'))
.tooltip();
this.$el.find('.ellipsis')
.wrap('<a class="ellipsislink" href="' + encodeURI(OC.generateUrl('apps/files/?dir=' + $crumb.attr('data-dir'))) + '"></a>');
}
// and all the previous ones (going backwards)
firstHidden = false;
} else {
// add to total width
currentTotalWidth += $crumb.data('real-width');
}
i--;
// Used for testing since this.$el.parent fails
if (!this.availableWidth) {
this.usedWidth = this.$el.parent().width() - (this.$el.parent().find('.button').length + 1) * 44;
} else {
this.usedWidth = this.availableWidth;
}

if (!OC.Util.hasSVGSupport()) {
OC.Util.replaceSVG(this.$el);
// If container is smaller than content
// AND if there are crumbs left to hide
while (this.getTotalWidth() > this.usedWidth
&& this.$el.find(this.crumbSelector).length > 0) {
this._hideCrumb();
}
// If container is bigger than content + element to be shown
// AND if there is at least one hidden crumb
while (this.$el.find('.crumb.hidden').length > 0
&& this.getTotalWidth() + this._getCrumbElement().width() < this.usedWidth) {
this._showCrumb();
}

this._updateMenu();
}
};

OCA.Files.BreadCrumb = BreadCrumb;
})();

Loading