Update share action text to display owner/recipients

- when a share was changed, update the share action text
- added file data attribute "data-share-recipients"
This commit is contained in:
Vincent Petry 2014-05-28 18:39:29 +02:00
parent f931df2dac
commit 7961d4a87e
4 changed files with 226 additions and 131 deletions

View File

@ -8,7 +8,9 @@
* *
*/ */
OCA.Sharing = {}; if (!OCA.Sharing) {
OCA.Sharing = {};
}
OCA.Sharing.App = { OCA.Sharing.App = {
_inFileList: null, _inFileList: null,

View File

@ -8,103 +8,154 @@
* *
*/ */
$(document).ready(function() { (function() {
if (!_.isUndefined(OC.Share) && !_.isUndefined(OCA.Files)) { if (!OCA.Sharing) {
// TODO: make a separate class for this or a hook or jQuery event ? OCA.Sharing = {};
if (OCA.Files.FileList) { }
var oldCreateRow = OCA.Files.FileList.prototype._createRow; OCA.Sharing.Util = {
OCA.Files.FileList.prototype._createRow = function(fileData) { initialize: function() {
var tr = oldCreateRow.apply(this, arguments); if (!_.isUndefined(OC.Share) && !_.isUndefined(OCA.Files)) {
if (fileData.shareOwner) { // TODO: make a separate class for this or a hook or jQuery event ?
tr.attr('data-share-owner', fileData.shareOwner); if (OCA.Files.FileList) {
// user should always be able to rename a mount point var oldCreateRow = OCA.Files.FileList.prototype._createRow;
if (fileData.isShareMountPoint) { OCA.Files.FileList.prototype._createRow = function(fileData) {
tr.attr('data-permissions', fileData.permissions | OC.PERMISSION_UPDATE); var tr = oldCreateRow.apply(this, arguments);
tr.attr('data-reshare-permissions', fileData.permissions); if (fileData.shareOwner) {
} tr.attr('data-share-owner', fileData.shareOwner);
// user should always be able to rename a mount point
if (fileData.isShareMountPoint) {
tr.attr('data-permissions', fileData.permissions | OC.PERMISSION_UPDATE);
tr.attr('data-reshare-permissions', fileData.permissions);
}
}
return tr;
};
} }
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){
// if no share action exists because the admin disabled sharing for this user // 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 // we create a share notification action to inform the user about files
// shared with him otherwise we just update the existing share action. // shared with him otherwise we just update the existing share action.
var fileList = ev.fileList; var fileList = ev.fileList;
var $fileList = $(this); var $fileList = $(this);
$fileList.find('[data-share-owner]').each(function() { $fileList.find('[data-share-owner]').each(function() {
var $tr = $(this); var $tr = $(this);
var $action; var permissions = $tr.data('permissions');
var owner; if(permissions & OC.PERMISSION_SHARE) {
var message; OC.Share.markFileAsShared($tr, true);
var permissions = $tr.data('permissions'); } else {
if(permissions & OC.PERMISSION_SHARE) { // TODO: make this work like/with OC.Share.markFileAsShared()
$action = $tr.find('[data-Action="Share"]'); var shareNotification = '<a class="action action-share-notification permanent"' +
$action.addClass('permanent'); ' data-action="Share-Notification" href="#" original-title="">' +
owner = $tr.closest('tr').attr('data-share-owner'); ' <img class="svg" src="' + OC.imagePath('core', 'actions/share') + '"></img>';
message = ' ' + t('files_sharing', 'Shared by {owner}', {owner: owner}); $tr.find('.fileactions').append(function() {
$action.find('span').text(message); var owner = $(this).closest('tr').attr('data-share-owner');
} else { var shareBy = t('files_sharing', 'Shared by {owner}', {owner: owner});
var shareNotification = '<a class="action action-share-notification permanent"' + var $result = $(shareNotification + '<span> ' + shareBy + '</span></span>');
' data-action="Share-Notification" href="#" original-title="">' + $result.on('click', function() {
' <img class="svg" src="' + OC.imagePath('core', 'actions/share') + '"></img>'; return false;
$tr.find('.fileactions').append(function() { });
var owner = $(this).closest('tr').attr('data-share-owner'); return $result;
var shareBy = t('files_sharing', 'Shared by {owner}', {owner: owner}); });
var $result = $(shareNotification + '<span> ' + shareBy + '</span></span>'); }
$result.on('click', function() {
return false;
});
return $result;
}); });
}
});
if (!OCA.Sharing.sharesLoaded){ if (!OCA.Sharing.sharesLoaded){
OC.Share.loadIcons('file', fileList); OC.Share.loadIcons('file', fileList);
// 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{
OC.Share.updateIcons('file', fileList); OC.Share.updateIcons('file', fileList);
} }
}); });
OCA.Files.fileActions.register( OCA.Files.fileActions.register(
'all', 'all',
'Share', 'Share',
OC.PERMISSION_SHARE, OC.PERMISSION_SHARE,
OC.imagePath('core', 'actions/share'), OC.imagePath('core', 'actions/share'),
function(filename, context) { function(filename, context) {
var $tr = context.$file; var $tr = context.$file;
var itemType = 'file'; var itemType = 'file';
if ($tr.data('type') === 'dir') { if ($tr.data('type') === 'dir') {
itemType = 'folder'; itemType = 'folder';
} }
var possiblePermissions = $tr.data('reshare-permissions'); var possiblePermissions = $tr.data('reshare-permissions');
if (_.isUndefined(possiblePermissions)) { if (_.isUndefined(possiblePermissions)) {
possiblePermissions = $tr.data('permissions'); possiblePermissions = $tr.data('permissions');
} }
var appendTo = $tr.find('td.filename'); var appendTo = $tr.find('td.filename');
// Check if drop down is already visible for a different file // Check if drop down is already visible for a different file
if (OC.Share.droppedDown) { if (OC.Share.droppedDown) {
if ($tr.data('id') !== $('#dropdown').attr('data-item-source')) { if ($tr.data('id') !== $('#dropdown').attr('data-item-source')) {
OC.Share.hideDropDown(function () { OC.Share.hideDropDown(function () {
$tr.addClass('mouseOver');
OC.Share.showDropDown(itemType, $tr.data('id'), appendTo, true, possiblePermissions, filename);
});
} else {
OC.Share.hideDropDown();
}
} else {
$tr.addClass('mouseOver'); $tr.addClass('mouseOver');
OC.Share.showDropDown(itemType, $tr.data('id'), appendTo, true, possiblePermissions, filename); OC.Share.showDropDown(itemType, $tr.data('id'), appendTo, true, possiblePermissions, filename);
}
$('#dropdown').on('sharesChanged', function(ev) {
// note: we only update the data attribute because updateIcon()
// is called automatically after this event
var userShares = ev.itemShares[OC.Share.SHARE_TYPE_USER] || [];
var groupShares = ev.itemShares[OC.Share.SHARE_TYPE_GROUP] || [];
var linkShares = ev.itemShares[OC.Share.SHARE_TYPE_LINK] || [];
var recipients = _.union(userShares, groupShares);
if (linkShares.length > 0) {
recipients.unshift(t('files_sharing', 'Public'));
}
// only update the recipients if they existed before
// (some file lists don't have them)
if (!_.isUndefined($tr.attr('data-share-recipients'))) {
// FIXME: use display names from users, we currently only got user ids
if (recipients.length) {
$tr.attr('data-share-recipients', OCA.Sharing.Util.formatRecipients(recipients));
}
else {
$tr.attr('data-share-recipients', '');
}
}
}); });
} else { });
OC.Share.hideDropDown();
}
} else {
$tr.addClass('mouseOver');
OC.Share.showDropDown(itemType, $tr.data('id'), appendTo, true, possiblePermissions, filename);
} }
}); },
}
/**
* Formats a recipient array to be displayed.
* The first four recipients will be shown and the
* other ones will be shown as "+x" where "x" is the number of
* remaining recipients.
*
* @param recipients recipients array
* @param count optional total recipients count (in case the array was shortened)
* @return formatted recipients display text
*/
formatRecipients: function(recipients, count) {
var maxRecipients = 4;
var text;
if (!_.isNumber(count)) {
count = recipients.length;
}
text = _.first(recipients, maxRecipients).join(', ');
if (count > maxRecipients) {
text += ', +' + (count - maxRecipients);
}
return text;
}
};
})();
$(document).ready(function() {
OCA.Sharing.Util.initialize();
}); });

View File

@ -48,6 +48,9 @@
if (this._sharedWithUser) { if (this._sharedWithUser) {
$tr.attr('data-share-owner', fileData.shares[0].ownerDisplayName); $tr.attr('data-share-owner', fileData.shares[0].ownerDisplayName);
} }
if (fileData.recipientsDisplayName) {
$tr.attr('data-share-recipients', fileData.recipientsDisplayName);
}
return $tr; return $tr;
}, },
@ -179,15 +182,15 @@
// inside the same file object (by file id). // inside the same file object (by file id).
.reduce(function(memo, file) { .reduce(function(memo, file) {
var data = memo[file.id]; var data = memo[file.id];
var counterPart = file.share.ownerDisplayName || file.share.targetDisplayName; var recipient = file.share.targetDisplayName;
if (!data) { if (!data) {
data = memo[file.id] = file; data = memo[file.id] = file;
data.shares = [file.share]; data.shares = [file.share];
// using a hash to make them unique, // using a hash to make them unique,
// this is only a list to be displayed // this is only a list to be displayed
data.counterParts = {}; data.recipients = {};
// counter is cheaper than calling _.keys().length // counter is cheaper than calling _.keys().length
data.counterPartsCount = 0; data.recipientsCount = 0;
data.mtime = file.share.stime; data.mtime = file.share.stime;
} }
else { else {
@ -200,10 +203,14 @@
if (file.share.type === OC.Share.SHARE_TYPE_LINK) { if (file.share.type === OC.Share.SHARE_TYPE_LINK) {
data.hasLinkShare = true; data.hasLinkShare = true;
} else if (counterPart && data.counterPartsCount < 10) { } else if (recipient) {
// limit counterparts for output // limit counterparts for output
data.counterParts[counterPart] = true; if (data.recipientsCount < 3) {
data.counterPartsCount++; // only store the first ones, they will be the only ones
// displayed
data.recipients[recipient] = true;
}
data.recipientsCount++;
} }
delete file.share; delete file.share;
@ -213,14 +220,18 @@
.values() .values()
// Clean up // Clean up
.each(function(data) { .each(function(data) {
// convert the counterParts map to a flat // convert the recipients map to a flat
// array of sorted names // array of sorted names
data.counterParts = _.chain(data.counterParts).keys().sort().value(); data.recipients = _.chain(data.recipients).keys().sort().value();
if (data.hasLinkShare) { if (data.hasLinkShare) {
data.counterParts.unshift(t('files_sharing', 'link')); data.recipients.unshift(t('files_sharing', 'Public'));
delete data.hasLinkShare; delete data.hasLinkShare;
} }
delete data.counterPartsCount; data.recipientsDisplayName = OCA.Sharing.Util.formatRecipients(
data.recipients,
data.recipientsCount
);
delete data.recipientsCount;
}) })
// Sort by expected sort comparator // Sort by expected sort comparator
.sortBy(this._sortComparator) .sortBy(this._sortComparator)

View File

@ -56,20 +56,14 @@ OC.Share={
image = OC.imagePath('core', 'actions/public'); image = OC.imagePath('core', 'actions/public');
} }
if (itemType !== 'file' && itemType !== 'folder') { if (itemType !== 'file' && itemType !== 'folder') {
$fileList.find('a.share[data-item="'+item+'"]').css('background', 'url('+image+') no-repeat center'); $('a.share[data-item="'+item+'"]').css('background', 'url('+image+') no-repeat center');
} else { } else {
// TODO: ultimately this part should be moved to files_sharing app
var file = $fileList.find('tr[data-id="'+item+'"]'); var file = $fileList.find('tr[data-id="'+item+'"]');
var shareFolder = OC.imagePath('core', 'filetypes/folder-shared'); var shareFolder = OC.imagePath('core', 'filetypes/folder-shared');
var img; var img;
if (file.length > 0) { if (file.length > 0) {
var type = file.data('type'); this.markFileAsShared(file, true, image);
if (type === 'dir') {
file.children('.filename').css('background-image', 'url('+shareFolder+')');
}
var action = $(file).find('.fileactions .action[data-action="Share"]');
img = action.find('img').attr('src', image);
action.addClass('permanent');
action.html(' <span>'+t('core', 'Shared')+'</span>').prepend(img);
} else { } else {
var dir = currentDir; var dir = currentDir;
if (dir.length > 1) { if (dir.length > 1) {
@ -82,6 +76,7 @@ OC.Share={
var files = $fileList.find('.filename'); var files = $fileList.find('.filename');
var i; var i;
for (i = 0; i < actions.length; i++) { for (i = 0; i < actions.length; i++) {
// TODO: use this.markFileAsShared()
img = $(actions[i]).find('img'); img = $(actions[i]).find('img');
if (img.attr('src') !== OC.imagePath('core', 'actions/public')) { if (img.attr('src') !== OC.imagePath('core', 'actions/public')) {
img.attr('src', image); img.attr('src', image);
@ -125,29 +120,9 @@ OC.Share={
if (itemType != 'file' && itemType != 'folder') { if (itemType != 'file' && itemType != 'folder') {
$('a.share[data-item="'+itemSource+'"]').css('background', 'url('+image+') no-repeat center'); $('a.share[data-item="'+itemSource+'"]').css('background', 'url('+image+') no-repeat center');
} else { } else {
var file = $('tr').filterAttr('data-id', String(itemSource)); var $tr = $('tr').filterAttr('data-id', String(itemSource));
if (file.length > 0) { if ($tr.length > 0) {
var type = file.data('type'); this.markFileAsShared($tr, shares, image);
var shareFolder = OC.imagePath('core', 'filetypes/folder');
if (type === 'dir' && shares) {
shareFolder = OC.imagePath('core', 'filetypes/folder-shared');
file.children('.filename').css('background-image', 'url('+shareFolder+')');
} else if (type === 'dir') {
file.children('.filename').css('background-image', 'url('+shareFolder+')');
}
var action = $(file).find('.fileactions .action').filterAttr('data-action', 'Share');
// in case of multiple lists/rows, there might be more than one visible
action.each(function() {
var action = $(this);
var img = action.find('img').attr('src', image);
if (shares) {
action.addClass('permanent');
action.html(' <span>'+ escapeHTML(t('core', 'Shared'))+'</span>').prepend(img);
} else {
action.removeClass('permanent');
action.html(' <span>'+ escapeHTML(t('core', 'Share'))+'</span>').prepend(img);
}
});
} }
} }
if (shares) { if (shares) {
@ -157,6 +132,59 @@ OC.Share={
delete OC.Share.statuses[itemSource]; delete OC.Share.statuses[itemSource];
} }
}, },
/**
* Marks/unmarks a given file as shared
*
* @param $tr file element to mark as shared
* @param state true to mark as shared, false to unmark
* @param image image to use for the icon
*/
markFileAsShared: function($tr, state, image) {
var action = $tr.find('.fileactions .action[data-action="Share"]');
var type = $tr.data('type');
var img = action.find('img');
var message;
var recipients;
var owner;
var shareFolderIcon;
if (type === 'dir' && state) {
shareFolderIcon = OC.imagePath('core', 'filetypes/folder-shared');
$tr.children('.filename').css('background-image', 'url(' + shareFolderIcon + ')');
} else if (type === 'dir') {
shareFolderIcon = OC.imagePath('core', 'filetypes/folder');
$tr.children('.filename').css('background-image', 'url(' + shareFolderIcon + ')');
}
if (state) {
recipients = $tr.attr('data-share-recipients');
owner = $tr.attr('data-share-owner');
action.addClass('permanent');
message = t('core', 'Shared');
if (owner && !recipients) {
message = t('files_sharing', 'Shared by {owner}', {owner: owner});
image = image || OC.imagePath('core', 'actions/share');
}
if (recipients) {
image = image || OC.imagePath('core', 'actions/shared');
if (owner) {
message = ' ' + t(
'files_sharing',
'Shared by {owner} with You, {recipients}',
{owner: owner, recipients: recipients}
);
}
else {
message = t('core', 'Shared with {recipients}', {recipients: recipients});
}
}
action.html(' <span>'+ message + '</span>').prepend(img);
}
else {
action.removeClass('permanent');
action.html(' <span>'+ escapeHTML(t('core', 'Share'))+'</span>').prepend(img);
}
img.attr('src', image);
},
loadItem:function(itemType, itemSource) { loadItem:function(itemType, itemSource) {
var data = ''; var data = '';
var checkReshare = true; var checkReshare = true;
@ -384,6 +412,7 @@ OC.Share={
OC.Share.share(itemType, itemSource, shareType, shareWith, permissions, itemSourceName, expirationDate, function() { OC.Share.share(itemType, itemSource, shareType, shareWith, permissions, itemSourceName, expirationDate, function() {
OC.Share.addShareWith(shareType, shareWith, selected.item.label, permissions, possiblePermissions); OC.Share.addShareWith(shareType, shareWith, selected.item.label, permissions, possiblePermissions);
$('#shareWith').val(''); $('#shareWith').val('');
$('#dropdown').trigger(new $.Event('sharesChanged', {itemShares: OC.Share.itemShares}));
OC.Share.updateIcon(itemType, itemSource); OC.Share.updateIcon(itemType, itemSource);
}); });
return false; return false;
@ -665,6 +694,7 @@ $(document).ready(function() {
$li.remove(); $li.remove();
var index = OC.Share.itemShares[shareType].indexOf(shareWith); var index = OC.Share.itemShares[shareType].indexOf(shareWith);
OC.Share.itemShares[shareType].splice(index, 1); OC.Share.itemShares[shareType].splice(index, 1);
$('#dropdown').trigger(new $.Event('sharesChanged', {itemShares: OC.Share.itemShares}));
OC.Share.updateIcon(itemType, itemSource); OC.Share.updateIcon(itemType, itemSource);
if (typeof OC.Share.statuses[itemSource] === 'undefined') { if (typeof OC.Share.statuses[itemSource] === 'undefined') {
$('#expiration').hide('blind'); $('#expiration').hide('blind');
@ -723,6 +753,7 @@ $(document).ready(function() {
if (oc_appconfig.core.enforcePasswordForPublicLink === false) { if (oc_appconfig.core.enforcePasswordForPublicLink === false) {
OC.Share.share(itemType, itemSource, OC.Share.SHARE_TYPE_LINK, '', OC.PERMISSION_READ, itemSourceName, expirationDate, function(data) { OC.Share.share(itemType, itemSource, OC.Share.SHARE_TYPE_LINK, '', OC.PERMISSION_READ, itemSourceName, expirationDate, function(data) {
OC.Share.showLink(data.token, null, itemSource); OC.Share.showLink(data.token, null, itemSource);
$('#dropdown').trigger(new $.Event('sharesChanged', {itemShares: OC.Share.itemShares}));
OC.Share.updateIcon(itemType, itemSource); OC.Share.updateIcon(itemType, itemSource);
}); });
} else { } else {