Merge pull request #9341 from owncloud/sharing-fileactions-fix
Fix fileActionsReady event after deferred file actions update
This commit is contained in:
commit
59629e688c
|
@ -181,11 +181,12 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.currentFile = parent;
|
this.currentFile = parent;
|
||||||
|
var $tr = parent.closest('tr');
|
||||||
var self = this;
|
var self = this;
|
||||||
var actions = this.getActions(this.getCurrentMimeType(), this.getCurrentType(), this.getCurrentPermissions());
|
var actions = this.getActions(this.getCurrentMimeType(), this.getCurrentType(), this.getCurrentPermissions());
|
||||||
var file = this.getCurrentFile();
|
var file = this.getCurrentFile();
|
||||||
var nameLinks;
|
var nameLinks;
|
||||||
if (parent.closest('tr').data('renaming')) {
|
if ($tr.data('renaming')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,7 +279,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
if (triggerEvent){
|
if (triggerEvent){
|
||||||
fileList.$fileList.trigger(jQuery.Event("fileActionsReady", {fileList: fileList}));
|
fileList.$fileList.trigger(jQuery.Event("fileActionsReady", {fileList: fileList, $files: $tr}));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getCurrentFile: function () {
|
getCurrentFile: function () {
|
||||||
|
|
|
@ -473,6 +473,7 @@
|
||||||
/**
|
/**
|
||||||
* Appends the next page of files into the table
|
* Appends the next page of files into the table
|
||||||
* @param animate true to animate the new elements
|
* @param animate true to animate the new elements
|
||||||
|
* @return array of DOM elements of the newly added files
|
||||||
*/
|
*/
|
||||||
_nextPage: function(animate) {
|
_nextPage: function(animate) {
|
||||||
var index = this.$fileList.children().length,
|
var index = this.$fileList.children().length,
|
||||||
|
@ -483,7 +484,7 @@
|
||||||
isAllSelected = this.isAllSelected();
|
isAllSelected = this.isAllSelected();
|
||||||
|
|
||||||
if (index >= this.files.length) {
|
if (index >= this.files.length) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (count > 0 && index < this.files.length) {
|
while (count > 0 && index < this.files.length) {
|
||||||
|
@ -496,12 +497,17 @@
|
||||||
}
|
}
|
||||||
if (animate) {
|
if (animate) {
|
||||||
tr.addClass('appear transparent');
|
tr.addClass('appear transparent');
|
||||||
newTrs.push(tr);
|
|
||||||
}
|
}
|
||||||
|
newTrs.push(tr);
|
||||||
index++;
|
index++;
|
||||||
count--;
|
count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// trigger event for newly added rows
|
||||||
|
if (newTrs.length > 0) {
|
||||||
|
this.$fileList.trigger($.Event('fileActionsReady', {fileList: this, $files: newTrs}));
|
||||||
|
}
|
||||||
|
|
||||||
if (animate) {
|
if (animate) {
|
||||||
// defer, for animation
|
// defer, for animation
|
||||||
window.setTimeout(function() {
|
window.setTimeout(function() {
|
||||||
|
@ -510,6 +516,7 @@
|
||||||
}
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
return newTrs;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -518,9 +525,16 @@
|
||||||
*/
|
*/
|
||||||
_onFileActionsUpdated: function() {
|
_onFileActionsUpdated: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.$fileList.find('tr td.filename').each(function() {
|
var $files = this.$fileList.find('tr');
|
||||||
self.fileActions.display($(this), true, self);
|
if (!$files.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$files.each(function() {
|
||||||
|
self.fileActions.display($(this).find('td.filename'), false, self);
|
||||||
});
|
});
|
||||||
|
this.$fileList.trigger($.Event('fileActionsReady', {fileList: this, $files: $files}));
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -532,7 +546,6 @@
|
||||||
// detach to make adding multiple rows faster
|
// detach to make adding multiple rows faster
|
||||||
this.files = filesArray;
|
this.files = filesArray;
|
||||||
|
|
||||||
this.$fileList.detach();
|
|
||||||
this.$fileList.empty();
|
this.$fileList.empty();
|
||||||
|
|
||||||
// clear "Select all" checkbox
|
// clear "Select all" checkbox
|
||||||
|
@ -541,10 +554,7 @@
|
||||||
this.isEmpty = this.files.length === 0;
|
this.isEmpty = this.files.length === 0;
|
||||||
this._nextPage();
|
this._nextPage();
|
||||||
|
|
||||||
this.$el.find('thead').after(this.$fileList);
|
|
||||||
|
|
||||||
this.updateEmptyContent();
|
this.updateEmptyContent();
|
||||||
this.$fileList.trigger($.Event('fileActionsReady', {fileList: this}));
|
|
||||||
|
|
||||||
this.fileSummary.calculate(filesArray);
|
this.fileSummary.calculate(filesArray);
|
||||||
|
|
||||||
|
@ -1282,16 +1292,16 @@
|
||||||
// reinsert row
|
// reinsert row
|
||||||
self.files.splice(tr.index(), 1);
|
self.files.splice(tr.index(), 1);
|
||||||
tr.remove();
|
tr.remove();
|
||||||
self.add(fileInfo, {updateSummary: false, silent: true});
|
tr = self.add(fileInfo, {updateSummary: false, silent: true});
|
||||||
self.$fileList.trigger($.Event('fileActionsReady', {fileList: self}));
|
self.$fileList.trigger($.Event('fileActionsReady', {fileList: self, $files: $(tr)}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// add back the old file info when cancelled
|
// add back the old file info when cancelled
|
||||||
self.files.splice(tr.index(), 1);
|
self.files.splice(tr.index(), 1);
|
||||||
tr.remove();
|
tr.remove();
|
||||||
self.add(oldFileInfo, {updateSummary: false, silent: true});
|
tr = self.add(oldFileInfo, {updateSummary: false, silent: true});
|
||||||
self.$fileList.trigger($.Event('fileActionsReady', {fileList: self}));
|
self.$fileList.trigger($.Event('fileActionsReady', {fileList: self, $files: $(tr)}));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
input.attr('title', error);
|
input.attr('title', error);
|
||||||
|
|
|
@ -797,13 +797,24 @@ describe('OCA.Files.FileList tests', function() {
|
||||||
fileList.$fileList.on('fileActionsReady', handler);
|
fileList.$fileList.on('fileActionsReady', handler);
|
||||||
fileList.setFiles(testFiles);
|
fileList.setFiles(testFiles);
|
||||||
expect(handler.calledOnce).toEqual(true);
|
expect(handler.calledOnce).toEqual(true);
|
||||||
|
expect(handler.getCall(0).args[0].$files.length).toEqual(testFiles.length);
|
||||||
});
|
});
|
||||||
it('triggers "fileActionsReady" event after single add', function() {
|
it('triggers "fileActionsReady" event after single add', function() {
|
||||||
var handler = sinon.stub();
|
var handler = sinon.stub();
|
||||||
|
var $tr;
|
||||||
fileList.setFiles(testFiles);
|
fileList.setFiles(testFiles);
|
||||||
fileList.$fileList.on('fileActionsReady', handler);
|
fileList.$fileList.on('fileActionsReady', handler);
|
||||||
fileList.add({name: 'test.txt'});
|
$tr = fileList.add({name: 'test.txt'});
|
||||||
expect(handler.calledOnce).toEqual(true);
|
expect(handler.calledOnce).toEqual(true);
|
||||||
|
expect(handler.getCall(0).args[0].$files.is($tr)).toEqual(true);
|
||||||
|
});
|
||||||
|
it('triggers "fileActionsReady" event after next page load with the newly appended files', function() {
|
||||||
|
var handler = sinon.stub();
|
||||||
|
fileList.setFiles(generateFiles(0, 64));
|
||||||
|
fileList.$fileList.on('fileActionsReady', handler);
|
||||||
|
fileList._nextPage();
|
||||||
|
expect(handler.calledOnce).toEqual(true);
|
||||||
|
expect(handler.getCall(0).args[0].$files.length).toEqual(fileList.pageSize);
|
||||||
});
|
});
|
||||||
it('does not trigger "fileActionsReady" event after single add with silent argument', function() {
|
it('does not trigger "fileActionsReady" event after single add with silent argument', function() {
|
||||||
var handler = sinon.stub();
|
var handler = sinon.stub();
|
||||||
|
@ -1630,6 +1641,7 @@ describe('OCA.Files.FileList tests', function() {
|
||||||
});
|
});
|
||||||
it('redisplays actions when new actions have been registered', function() {
|
it('redisplays actions when new actions have been registered', function() {
|
||||||
var actionStub = sinon.stub();
|
var actionStub = sinon.stub();
|
||||||
|
var readyHandler = sinon.stub();
|
||||||
var clock = sinon.useFakeTimers();
|
var clock = sinon.useFakeTimers();
|
||||||
var debounceStub = sinon.stub(_, 'debounce', function(callback) {
|
var debounceStub = sinon.stub(_, 'debounce', function(callback) {
|
||||||
return function() {
|
return function() {
|
||||||
|
@ -1637,11 +1649,15 @@ describe('OCA.Files.FileList tests', function() {
|
||||||
_.defer(callback);
|
_.defer(callback);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// need to reinit the list to make the debounce call
|
// need to reinit the list to make the debounce call
|
||||||
fileList.destroy();
|
fileList.destroy();
|
||||||
fileList = new OCA.Files.FileList($('#app-content-files'));
|
fileList = new OCA.Files.FileList($('#app-content-files'));
|
||||||
|
|
||||||
fileList.setFiles(testFiles);
|
fileList.setFiles(testFiles);
|
||||||
|
|
||||||
|
fileList.$fileList.on('fileActionsReady', readyHandler);
|
||||||
|
|
||||||
fileList.fileActions.register(
|
fileList.fileActions.register(
|
||||||
'text/plain',
|
'text/plain',
|
||||||
'Test',
|
'Test',
|
||||||
|
@ -1654,9 +1670,13 @@ describe('OCA.Files.FileList tests', function() {
|
||||||
);
|
);
|
||||||
var $tr = fileList.findFileEl('One.txt');
|
var $tr = fileList.findFileEl('One.txt');
|
||||||
expect($tr.find('.action-test').length).toEqual(0);
|
expect($tr.find('.action-test').length).toEqual(0);
|
||||||
|
expect(readyHandler.notCalled).toEqual(true);
|
||||||
|
|
||||||
// update is delayed
|
// update is delayed
|
||||||
clock.tick(100);
|
clock.tick(100);
|
||||||
expect($tr.find('.action-test').length).toEqual(1);
|
expect($tr.find('.action-test').length).toEqual(1);
|
||||||
|
expect(readyHandler.calledOnce).toEqual(true);
|
||||||
|
|
||||||
clock.restore();
|
clock.restore();
|
||||||
debounceStub.restore();
|
debounceStub.restore();
|
||||||
});
|
});
|
||||||
|
|
|
@ -36,54 +36,34 @@
|
||||||
}
|
}
|
||||||
return tr;
|
return tr;
|
||||||
};
|
};
|
||||||
|
|
||||||
var oldRenderRow = OCA.Files.FileList.prototype._renderRow;
|
|
||||||
OCA.Files.FileList.prototype._renderRow = function(fileData) {
|
|
||||||
var $tr = oldRenderRow.apply(this, arguments);
|
|
||||||
// if the statuses are loaded already, use them for the icon
|
|
||||||
// (needed when scrolling to the next page)
|
|
||||||
var shareStatus = OC.Share.statuses[fileData.id];
|
|
||||||
if (fileData.shareOwner || fileData.recipientsDisplayName || shareStatus) {
|
|
||||||
var permissions = $tr.data('permissions');
|
|
||||||
var hasLink = !!(shareStatus && shareStatus.link);
|
|
||||||
if (permissions & OC.PERMISSION_SHARE) {
|
|
||||||
OC.Share.markFileAsShared($tr, true, hasLink);
|
|
||||||
} else {
|
|
||||||
// if no share action exists because the admin disabled sharing for this user
|
|
||||||
// we create a share notification action to inform the user about files
|
|
||||||
// shared with him otherwise we just update the existing share action.
|
|
||||||
// TODO: make this work like/with OC.Share.markFileAsShared()
|
|
||||||
var shareNotification = '<a class="action action-share-notification permanent"' +
|
|
||||||
' data-action="Share-Notification" href="#" original-title="">' +
|
|
||||||
' <img class="svg" src="' + OC.imagePath('core', 'actions/share') + '"></img>';
|
|
||||||
$tr.find('.fileactions').append(function() {
|
|
||||||
var shareBy = t('files_sharing', 'Shared by {owner}', {owner: escapeHTML(fileData.shareOwner)});
|
|
||||||
var $result = $(shareNotification + '<span> ' + shareBy + '</span></span>');
|
|
||||||
$result.on('click', function() {
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
return $result;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $tr;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// use delegate to catch the case with multiple file lists
|
// use delegate to catch the case with multiple file lists
|
||||||
$('#content').delegate('#fileList', 'fileActionsReady',function(ev){
|
$('#content').delegate('#fileList', 'fileActionsReady', function(ev){
|
||||||
var fileList = ev.fileList;
|
var fileList = ev.fileList;
|
||||||
|
var $files = ev.$files;
|
||||||
|
|
||||||
|
function updateIcons($files) {
|
||||||
|
if (!$files) {
|
||||||
|
// if none specified, update all
|
||||||
|
$files = fileList.$fileList.find('tr');
|
||||||
|
}
|
||||||
|
_.each($files, function(file) {
|
||||||
|
OCA.Sharing.Util.updateFileActionIcon($(file));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!OCA.Sharing.sharesLoaded){
|
if (!OCA.Sharing.sharesLoaded){
|
||||||
OC.Share.loadIcons('file', fileList);
|
OC.Share.loadIcons('file', fileList, function() {
|
||||||
|
// since we don't know which files are affected, just refresh them all
|
||||||
|
updateIcons();
|
||||||
|
});
|
||||||
// assume that we got all shares, so switching directories
|
// assume that we got all shares, so switching directories
|
||||||
// will not invalidate that list
|
// will not invalidate that list
|
||||||
OCA.Sharing.sharesLoaded = true;
|
OCA.Sharing.sharesLoaded = true;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
// this will update the icons for all the currently visible elements
|
updateIcons($files);
|
||||||
// additionally added elements when scrolling down will be
|
|
||||||
// updated in the _renderRow override
|
|
||||||
OC.Share.updateIcons('file', fileList);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -140,6 +120,40 @@
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the file action share icon for the given file
|
||||||
|
*
|
||||||
|
* @param $tr file element of the file to update
|
||||||
|
*/
|
||||||
|
updateFileActionIcon: function($tr) {
|
||||||
|
// if the statuses are loaded already, use them for the icon
|
||||||
|
// (needed when scrolling to the next page)
|
||||||
|
var shareStatus = OC.Share.statuses[$tr.data('id')];
|
||||||
|
if (shareStatus || $tr.attr('data-share-recipients') || $tr.attr('data-share-owner')) {
|
||||||
|
var permissions = $tr.data('permissions');
|
||||||
|
var hasLink = !!(shareStatus && shareStatus.link);
|
||||||
|
OC.Share.markFileAsShared($tr, true, hasLink);
|
||||||
|
if ((permissions & OC.PERMISSION_SHARE) === 0) {
|
||||||
|
// if no share action exists because the admin disabled sharing for this user
|
||||||
|
// we create a share notification action to inform the user about files
|
||||||
|
// shared with him otherwise we just update the existing share action.
|
||||||
|
// TODO: make this work like/with OC.Share.markFileAsShared()
|
||||||
|
$tr.find('.fileactions .action-share-notification').remove();
|
||||||
|
var shareNotification = '<a class="action action-share-notification permanent"' +
|
||||||
|
' data-action="Share-Notification" href="#" original-title="">' +
|
||||||
|
' <img class="svg" src="' + OC.imagePath('core', 'actions/share') + '"></img>';
|
||||||
|
$tr.find('.fileactions').append(function() {
|
||||||
|
var shareBy = t('files_sharing', 'Shared by {owner}', {owner: escapeHTML($tr.attr('data-share-owner'))});
|
||||||
|
var $result = $(shareNotification + '<span> ' + shareBy + '</span></span>');
|
||||||
|
$result.on('click', function() {
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
return $result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats a recipients array to be displayed.
|
* Formats a recipients array to be displayed.
|
||||||
* The first four recipients will be shown and the
|
* The first four recipients will be shown and the
|
||||||
|
|
|
@ -80,6 +80,14 @@ describe('OCA.Sharing.Util tests', function() {
|
||||||
// TODO: test data-permissions, data-share-owner, etc
|
// TODO: test data-permissions, data-share-owner, etc
|
||||||
});
|
});
|
||||||
describe('Share action icon', function() {
|
describe('Share action icon', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
OC.Share.statuses = {1: {link: false, path: '/subdir'}};
|
||||||
|
OCA.Sharing.sharesLoaded = true;
|
||||||
|
});
|
||||||
|
afterEach(function() {
|
||||||
|
OC.Share.statuses = {};
|
||||||
|
OCA.Sharing.sharesLoaded = false;
|
||||||
|
});
|
||||||
it('do not shows share text when not shared', function() {
|
it('do not shows share text when not shared', function() {
|
||||||
var $action, $tr;
|
var $action, $tr;
|
||||||
OC.Share.statuses = {};
|
OC.Share.statuses = {};
|
||||||
|
|
|
@ -29,10 +29,13 @@ OC.Share={
|
||||||
* files "Share" icon to "Shared" according to their share status and
|
* files "Share" icon to "Shared" according to their share status and
|
||||||
* share type.
|
* share type.
|
||||||
*
|
*
|
||||||
|
* If a callback is specified, the update step is skipped.
|
||||||
|
*
|
||||||
* @param itemType item type
|
* @param itemType item type
|
||||||
* @param fileList file list instance, defaults to OCA.Files.App.fileList
|
* @param fileList file list instance, defaults to OCA.Files.App.fileList
|
||||||
|
* @param callback function to call after the shares were loaded
|
||||||
*/
|
*/
|
||||||
loadIcons:function(itemType, fileList) {
|
loadIcons:function(itemType, fileList, callback) {
|
||||||
// Load all share icons
|
// Load all share icons
|
||||||
$.get(
|
$.get(
|
||||||
OC.filePath('core', 'ajax', 'share.php'),
|
OC.filePath('core', 'ajax', 'share.php'),
|
||||||
|
@ -45,9 +48,13 @@ OC.Share={
|
||||||
$.each(result.data, function(item, data) {
|
$.each(result.data, function(item, data) {
|
||||||
OC.Share.statuses[item] = data;
|
OC.Share.statuses[item] = data;
|
||||||
});
|
});
|
||||||
|
if (_.isFunction(callback)) {
|
||||||
|
callback(OC.Share.statuses);
|
||||||
|
} else {
|
||||||
OC.Share.updateIcons(itemType, fileList);
|
OC.Share.updateIcons(itemType, fileList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue