aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorJan-Christoph Borchardt <hey@jancborchardt.net>2014-06-27 13:51:18 +0200
committerJan-Christoph Borchardt <hey@jancborchardt.net>2014-06-27 13:51:18 +0200
commitb975f0e7184f769d9bc857c1e6db90006b45e2c8 (patch)
treea041f595dd56094160cf3aeb79f55b542a25db44 /apps
parent4d6019b73fd8b1a1d8e8fecbeb129bea12feb89d (diff)
parentec4cf96f0d4f170b21d77378e4f11b88b01aaebc (diff)
downloadnextcloud-server-b975f0e7184f769d9bc857c1e6db90006b45e2c8.tar.gz
nextcloud-server-b975f0e7184f769d9bc857c1e6db90006b45e2c8.zip
Merge pull request #9174 from owncloud/breadcrumbfix
Breadcrumb width calculation fix
Diffstat (limited to 'apps')
-rw-r--r--apps/files/js/breadcrumb.js144
-rw-r--r--apps/files/js/file-upload.js27
-rw-r--r--apps/files/js/filelist.js28
-rw-r--r--apps/files/tests/js/breadcrumbSpec.js79
-rw-r--r--apps/files/tests/js/filelistSpec.js5
5 files changed, 155 insertions, 128 deletions
diff --git a/apps/files/js/breadcrumb.js b/apps/files/js/breadcrumb.js
index c017d710d6d..7381fa8e432 100644
--- a/apps/files/js/breadcrumb.js
+++ b/apps/files/js/breadcrumb.js
@@ -41,8 +41,9 @@
$el: null,
dir: null,
- lastWidth: 0,
- hiddenBreadcrumbs: 0,
+ /**
+ * Total width of all breadcrumbs
+ */
totalWidth: 0,
breadcrumbs: [],
onClick: null,
@@ -116,7 +117,6 @@
}
this._updateTotalWidth();
- this.resize($(window).width(), true);
},
/**
@@ -150,93 +150,93 @@
return crumbs;
},
+ /**
+ * Calculate the total breadcrumb width when
+ * all crumbs are expanded
+ */
_updateTotalWidth: function () {
- var self = this;
-
- this.lastWidth = 0;
-
- // initialize with some extra space
- this.totalWidth = 64;
- // FIXME: this class should not know about global elements
- if ( $('#navigation').length ) {
- this.totalWidth += $('#navigation').outerWidth();
+ 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();
+ },
- if ( $('#app-navigation').length && !$('#app-navigation').hasClass('hidden')) {
- this.totalWidth += $('#app-navigation').outerWidth();
+ /**
+ * Show/hide breadcrumbs to fit the given width
+ */
+ setMaxWidth: function (availableWidth) {
+ if (this.availableWidth !== availableWidth) {
+ this.availableWidth = availableWidth;
+ this._resize();
}
- this.hiddenBreadcrumbs = 0;
+ },
- for (var i = 0; i < this.breadcrumbs.length; i++ ) {
- this.totalWidth += $(this.breadcrumbs[i]).get(0).offsetWidth;
+ _resize: function() {
+ var i, $crumb, $ellipsisCrumb;
+
+ if (!this.availableWidth) {
+ this.availableWidth = this.$el.width();
}
- $.each($('#controls .actions'), function(index, action) {
- self.totalWidth += $(action).outerWidth();
- });
+ if (this.breadcrumbs.length <= 1) {
+ return;
+ }
- },
+ // reset crumbs
+ this.$el.find('.crumb.ellipsized').remove();
- /**
- * Show/hide breadcrumbs to fit the given width
- */
- resize: function (width, firstRun) {
- var i, $crumb;
+ // unhide all
+ this.$el.find('.crumb.hidden').removeClass('hidden');
- if (width === this.lastWidth) {
+ if (this.totalWidth <= this.availableWidth) {
+ // no need to compute breadcrumbs, there is enough space
return;
}
- // window was shrinked since last time or first run ?
- if ((width < this.lastWidth || firstRun) && width < this.totalWidth) {
- if (this.hiddenBreadcrumbs === 0 && this.breadcrumbs.length > 1) {
- // start by hiding the first breadcrumb after home,
- // that one will have extra three dots displayed
- $crumb = this.breadcrumbs[1];
- this.totalWidth -= $crumb.get(0).offsetWidth;
- $crumb.find('a').addClass('hidden');
- $crumb.append('<span class="ellipsis">...</span>');
- this.totalWidth += $crumb.get(0).offsetWidth;
- this.hiddenBreadcrumbs = 2;
- }
- i = this.hiddenBreadcrumbs;
- // hide subsequent breadcrumbs if the space is still not enough
- while (width < this.totalWidth && i > 1 && i < this.breadcrumbs.length - 1) {
- $crumb = this.breadcrumbs[i];
- this.totalWidth -= $crumb.get(0).offsetWidth;
+ // 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');
- this.hiddenBreadcrumbs = i;
- i++;
- }
- // window is bigger than last time
- } else if (width > this.lastWidth && this.hiddenBreadcrumbs > 0) {
- i = this.hiddenBreadcrumbs;
- while (width > this.totalWidth && i > 0) {
- if (this.hiddenBreadcrumbs === 1) {
- // special handling for last one as it has the three dots
- $crumb = this.breadcrumbs[1];
- if ($crumb) {
- this.totalWidth -= $crumb.get(0).offsetWidth;
- $crumb.find('.ellipsis').remove();
- $crumb.find('a').removeClass('hidden');
- this.totalWidth += $crumb.get(0).offsetWidth;
- }
- } else {
- $crumb = this.breadcrumbs[i];
- $crumb.removeClass('hidden');
- this.totalWidth += $crumb.get(0).offsetWidth;
- if (this.totalWidth > width) {
- this.totalWidth -= $crumb.get(0).offsetWidth;
- $crumb.addClass('hidden');
- break;
- }
+ if (firstHidden) {
+ // set the path of this one as title for the ellipsis
+ this.$el.find('.crumb.ellipsized')
+ .attr('title', $crumb.attr('data-dir'))
+ .tipsy();
}
- i--;
- this.hiddenBreadcrumbs = i;
+ // and all the previous ones (going backwards)
+ firstHidden = false;
+ } else {
+ // add to total width
+ currentTotalWidth += $crumb.data('real-width');
}
+ i--;
}
- this.lastWidth = width;
+ if (!OC.Util.hasSVGSupport()) {
+ OC.Util.replaceSVG(this.$el);
+ }
}
};
diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js
index da58e1c31b8..2637d13f9ba 100644
--- a/apps/files/js/file-upload.js
+++ b/apps/files/js/file-upload.js
@@ -179,9 +179,20 @@ OC.Upload = {
callbacks.onNoConflicts(selection);
},
+ _hideProgressBar: function() {
+ $('#uploadprogresswrapper input.stop').fadeOut();
+ $('#uploadprogressbar').fadeOut(function() {
+ $('#file_upload_start').trigger(new $.Event('resized'));
+ });
+ },
+
+ _showProgressBar: function() {
+ $('#uploadprogressbar').fadeIn();
+ $('#file_upload_start').trigger(new $.Event('resized'));
+ },
+
init: function() {
if ( $('#file_upload_start').exists() ) {
-
var file_upload_param = {
dropZone: $('#content'), // restrict dropZone to content div
autoUpload: false,
@@ -444,7 +455,7 @@ OC.Upload = {
OC.Upload.log('progress handle fileuploadstart', e, data);
$('#uploadprogresswrapper input.stop').show();
$('#uploadprogressbar').progressbar({value: 0});
- $('#uploadprogressbar').fadeIn();
+ OC.Upload._showProgressBar();
});
fileupload.on('fileuploadprogress', function(e, data) {
OC.Upload.log('progress handle fileuploadprogress', e, data);
@@ -458,15 +469,13 @@ OC.Upload = {
fileupload.on('fileuploadstop', function(e, data) {
OC.Upload.log('progress handle fileuploadstop', e, data);
- $('#uploadprogresswrapper input.stop').fadeOut();
- $('#uploadprogressbar').fadeOut();
+ OC.Upload._hideProgressBar();
});
fileupload.on('fileuploadfail', function(e, data) {
OC.Upload.log('progress handle fileuploadfail', e, data);
//if user pressed cancel hide upload progress bar and cancel button
if (data.errorThrown === 'abort') {
- $('#uploadprogresswrapper input.stop').fadeOut();
- $('#uploadprogressbar').fadeOut();
+ OC.Upload._hideProgressBar();
}
});
@@ -649,7 +658,7 @@ OC.Upload = {
//IE < 10 does not fire the necessary events for the progress bar.
if ($('html.lte9').length === 0) {
$('#uploadprogressbar').progressbar({value: 0});
- $('#uploadprogressbar').fadeIn();
+ OC.Upload._showProgressBar();
}
var eventSource = new OC.EventSource(
@@ -668,12 +677,12 @@ OC.Upload = {
});
eventSource.listen('success', function(data) {
var file = data;
- $('#uploadprogressbar').fadeOut();
+ OC.Upload._hideProgressBar();
FileList.add(file, {hidden: hidden, animate: true});
});
eventSource.listen('error', function(error) {
- $('#uploadprogressbar').fadeOut();
+ OC.Upload._hideProgressBar();
var message = (error && error.message) || t('core', 'Error fetching URL');
OC.Notification.show(message);
//hide notification after 10 sec
diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js
index 55afedb2065..31c4c111832 100644
--- a/apps/files/js/filelist.js
+++ b/apps/files/js/filelist.js
@@ -150,11 +150,10 @@
this.$el.find('thead th .columntitle').click(_.bind(this._onClickHeader, this));
- $(window).resize(function() {
- // TODO: debounce this ?
- var width = $(this).width();
- self.breadcrumb.resize(width, false);
- });
+ this._onResize = _.debounce(_.bind(this._onResize, this), 100);
+ $(window).resize(this._onResize);
+
+ this.$el.on('show', this._onResize);
this.$fileList.on('click','td.filename>a.name', _.bind(this._onClickFile, this));
this.$fileList.on('change', 'td.filename>input:checkbox', _.bind(this._onClickFileCheckbox, this));
@@ -177,6 +176,22 @@
},
/**
+ * Event handler for when the window size changed
+ */
+ _onResize: function() {
+ var containerWidth = this.$el.width();
+ var actionsWidth = 0;
+ $.each(this.$el.find('#controls .actions'), function(index, action) {
+ actionsWidth += $(action).outerWidth();
+ });
+
+ // substract app navigation toggle when visible
+ containerWidth -= $('#app-navigation-toggle').width();
+
+ this.breadcrumb.setMaxWidth(containerWidth - actionsWidth - 10);
+ },
+
+ /**
* Event handler for when the URL changed
*/
_onUrlChanged: function(e) {
@@ -1538,6 +1553,9 @@
// handle upload events
var fileUploadStart = this.$el.find('#file_upload_start');
+ // detect the progress bar resize
+ fileUploadStart.on('resized', this._onResize);
+
fileUploadStart.on('fileuploaddrop', function(e, data) {
OC.Upload.log('filelist handle fileuploaddrop', e, data);
diff --git a/apps/files/tests/js/breadcrumbSpec.js b/apps/files/tests/js/breadcrumbSpec.js
index e3d9c757a7c..30784fd70ad 100644
--- a/apps/files/tests/js/breadcrumbSpec.js
+++ b/apps/files/tests/js/breadcrumbSpec.js
@@ -19,7 +19,6 @@
*
*/
-/* global BreadCrumb */
describe('OCA.Files.BreadCrumb tests', function() {
var BreadCrumb = OCA.Files.BreadCrumb;
@@ -131,48 +130,42 @@ describe('OCA.Files.BreadCrumb tests', function() {
});
});
describe('Resizing', function() {
- var bc, widthStub, dummyDir,
- oldUpdateTotalWidth;
+ var bc, dummyDir, widths, oldUpdateTotalWidth;
beforeEach(function() {
- dummyDir = '/short name/longer name/looooooooooooonger/even longer long long long longer long/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/last one';
+ dummyDir = '/short name/longer name/looooooooooooonger/' +
+ 'even longer long long long longer long/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/last one';
+
+ // using hard-coded widths (pre-measured) to avoid getting different
+ // results on different browsers due to font engine differences
+ widths = [41, 106, 112, 160, 257, 251, 91];
oldUpdateTotalWidth = BreadCrumb.prototype._updateTotalWidth;
BreadCrumb.prototype._updateTotalWidth = function() {
- // need to set display:block for correct offsetWidth (no CSS loaded here)
- $('div.crumb').css({
- 'display': 'block',
- 'float': 'left'
+ // pre-set a width to simulate consistent measurement
+ $('div.crumb').each(function(index){
+ $(this).css('width', widths[index]);
});
return oldUpdateTotalWidth.apply(this, arguments);
};
bc = new BreadCrumb();
- widthStub = sinon.stub($.fn, 'width');
// append dummy navigation and controls
// as they are currently used for measurements
$('#testArea').append(
- '<div id="navigation" style="width: 80px"></div>',
'<div id="controls"></div>'
);
-
- // make sure we know the test screen width
- $('#testArea').css('width', 1280);
-
- // use test area as we need it for measurements
$('#controls').append(bc.$el);
- $('#controls').append('<div class="actions"><div>Dummy action with a given width</div></div>');
});
afterEach(function() {
BreadCrumb.prototype._updateTotalWidth = oldUpdateTotalWidth;
- widthStub.restore();
bc = null;
});
- it('Hides breadcrumbs to fit window', function() {
+ it('Hides breadcrumbs to fit max allowed width', function() {
var $crumbs;
- widthStub.returns(500);
+ bc.setMaxWidth(500);
// triggers resize implicitly
bc.setDirectory(dummyDir);
$crumbs = bc.$el.find('.crumb');
@@ -190,19 +183,23 @@ describe('OCA.Files.BreadCrumb tests', function() {
expect($crumbs.eq(4).hasClass('hidden')).toEqual(true);
expect($crumbs.eq(5).hasClass('hidden')).toEqual(true);
expect($crumbs.eq(6).hasClass('hidden')).toEqual(false);
+ expect($crumbs.eq(7).hasClass('hidden')).toEqual(false);
});
- it('Updates ellipsis on window size increase', function() {
+ it('Updates the breadcrumbs when reducing max allowed width', function() {
var $crumbs;
- widthStub.returns(500);
+ // enough space
+ bc.setMaxWidth(1800);
+
+ expect(bc.$el.find('.ellipsis').length).toEqual(0);
+
// triggers resize implicitly
bc.setDirectory(dummyDir);
- $crumbs = bc.$el.find('.crumb');
// simulate increase
- $('#testArea').css('width', 1800);
- bc.resize(1800);
+ bc.setMaxWidth(950);
+ $crumbs = bc.$el.find('.crumb');
// first one is always visible
expect($crumbs.eq(0).hasClass('hidden')).toEqual(false);
// second one has ellipsis
@@ -213,37 +210,35 @@ describe('OCA.Files.BreadCrumb tests', function() {
// subsequent elements are hidden
expect($crumbs.eq(2).hasClass('hidden')).toEqual(true);
expect($crumbs.eq(3).hasClass('hidden')).toEqual(true);
- expect($crumbs.eq(4).hasClass('hidden')).toEqual(true);
// the rest is visible
+ expect($crumbs.eq(4).hasClass('hidden')).toEqual(false);
expect($crumbs.eq(5).hasClass('hidden')).toEqual(false);
expect($crumbs.eq(6).hasClass('hidden')).toEqual(false);
});
- it('Updates ellipsis on window size decrease', function() {
+ it('Removes the ellipsis when there is enough space', function() {
var $crumbs;
- $('#testArea').css('width', 2000);
- widthStub.returns(2000);
+ bc.setMaxWidth(500);
// triggers resize implicitly
bc.setDirectory(dummyDir);
$crumbs = bc.$el.find('.crumb');
- // simulate decrease
- bc.resize(500);
- $('#testArea').css('width', 500);
+ // ellipsis
+ expect(bc.$el.find('.ellipsis').length).toEqual(1);
- // first one is always visible
+ // simulate increase
+ bc.setMaxWidth(1800);
+
+ // no ellipsis
+ expect(bc.$el.find('.ellipsis').length).toEqual(0);
+
+ // all are visible
expect($crumbs.eq(0).hasClass('hidden')).toEqual(false);
- // second one has ellipsis
expect($crumbs.eq(1).hasClass('hidden')).toEqual(false);
- expect($crumbs.eq(1).find('.ellipsis').length).toEqual(1);
- // there is only one ellipsis in total
- expect($crumbs.find('.ellipsis').length).toEqual(1);
- // subsequent elements are hidden
- expect($crumbs.eq(2).hasClass('hidden')).toEqual(true);
- expect($crumbs.eq(3).hasClass('hidden')).toEqual(true);
- expect($crumbs.eq(4).hasClass('hidden')).toEqual(true);
- // the rest is visible
- expect($crumbs.eq(5).hasClass('hidden')).toEqual(true);
+ expect($crumbs.eq(2).hasClass('hidden')).toEqual(false);
+ expect($crumbs.eq(3).hasClass('hidden')).toEqual(false);
+ expect($crumbs.eq(4).hasClass('hidden')).toEqual(false);
+ expect($crumbs.eq(5).hasClass('hidden')).toEqual(false);
expect($crumbs.eq(6).hasClass('hidden')).toEqual(false);
});
});
diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js
index dea7c48e05e..318f66825a6 100644
--- a/apps/files/tests/js/filelistSpec.js
+++ b/apps/files/tests/js/filelistSpec.js
@@ -21,6 +21,7 @@
describe('OCA.Files.FileList tests', function() {
var testFiles, alertStub, notificationStub, fileList;
+ var bcResizeStub;
/**
* Generate test file data
@@ -52,6 +53,9 @@ describe('OCA.Files.FileList tests', function() {
beforeEach(function() {
alertStub = sinon.stub(OC.dialogs, 'alert');
notificationStub = sinon.stub(OC.Notification, 'show');
+ // prevent resize algo to mess up breadcrumb order while
+ // testing
+ bcResizeStub = sinon.stub(OCA.Files.BreadCrumb.prototype, '_resize');
// init parameters and test table elements
$('#testArea').append(
@@ -125,6 +129,7 @@ describe('OCA.Files.FileList tests', function() {
notificationStub.restore();
alertStub.restore();
+ bcResizeStub.restore();
});
describe('Getters', function() {
it('Returns the current directory', function() {