share.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. * Copyright (c) 2014
  3. *
  4. * This file is licensed under the Affero General Public License version 3
  5. * or later.
  6. *
  7. * See the COPYING-README file.
  8. *
  9. */
  10. (function() {
  11. if (!OCA.Sharing) {
  12. OCA.Sharing = {};
  13. }
  14. /**
  15. * @namespace
  16. */
  17. OCA.Sharing.Util = {
  18. /**
  19. * Initialize the sharing plugin.
  20. *
  21. * Registers the "Share" file action and adds additional
  22. * DOM attributes for the sharing file info.
  23. *
  24. * @param {OCA.Files.FileList} fileList file list to be extended
  25. */
  26. attach: function(fileList) {
  27. if (fileList.id === 'trashbin' || fileList.id === 'files.public') {
  28. return;
  29. }
  30. var fileActions = fileList.fileActions;
  31. var oldCreateRow = fileList._createRow;
  32. fileList._createRow = function(fileData) {
  33. var tr = oldCreateRow.apply(this, arguments);
  34. var sharePermissions = fileData.permissions;
  35. if (fileData.mountType && fileData.mountType === "external-root"){
  36. // for external storages we cant use the permissions of the mountpoint
  37. // instead we show all permissions and only use the share permissions from the mountpoint to handle resharing
  38. sharePermissions = sharePermissions | (OC.PERMISSION_ALL & ~OC.PERMISSION_SHARE);
  39. }
  40. if (fileData.type === 'file') {
  41. // files can't be shared with delete permissions
  42. sharePermissions = sharePermissions & ~OC.PERMISSION_DELETE;
  43. }
  44. tr.attr('data-share-permissions', sharePermissions);
  45. if (fileData.shareOwner) {
  46. tr.attr('data-share-owner', fileData.shareOwner);
  47. // user should always be able to rename a mount point
  48. if (fileData.isShareMountPoint) {
  49. tr.attr('data-permissions', fileData.permissions | OC.PERMISSION_UPDATE);
  50. }
  51. }
  52. if (fileData.recipientsDisplayName) {
  53. tr.attr('data-share-recipients', fileData.recipientsDisplayName);
  54. }
  55. return tr;
  56. };
  57. // use delegate to catch the case with multiple file lists
  58. fileList.$el.on('fileActionsReady', function(ev){
  59. var fileList = ev.fileList;
  60. var $files = ev.$files;
  61. function updateIcons($files) {
  62. if (!$files) {
  63. // if none specified, update all
  64. $files = fileList.$fileList.find('tr');
  65. }
  66. _.each($files, function(file) {
  67. OCA.Sharing.Util.updateFileActionIcon($(file));
  68. });
  69. }
  70. if (!OCA.Sharing.sharesLoaded){
  71. OC.Share.loadIcons('file', fileList, function() {
  72. // since we don't know which files are affected, just refresh them all
  73. updateIcons();
  74. });
  75. // assume that we got all shares, so switching directories
  76. // will not invalidate that list
  77. OCA.Sharing.sharesLoaded = true;
  78. }
  79. else{
  80. updateIcons($files);
  81. }
  82. });
  83. fileActions.register(
  84. 'all',
  85. 'Share',
  86. OC.PERMISSION_SHARE,
  87. OC.imagePath('core', 'actions/share'),
  88. function(filename, context) {
  89. var $tr = context.$file;
  90. var itemType = 'file';
  91. if ($tr.data('type') === 'dir') {
  92. itemType = 'folder';
  93. }
  94. var possiblePermissions = $tr.data('share-permissions');
  95. if (_.isUndefined(possiblePermissions)) {
  96. possiblePermissions = $tr.data('permissions');
  97. }
  98. var appendTo = $tr.find('td.filename');
  99. // Check if drop down is already visible for a different file
  100. if (OC.Share.droppedDown) {
  101. if ($tr.attr('data-id') !== $('#dropdown').attr('data-item-source')) {
  102. OC.Share.hideDropDown(function () {
  103. $tr.addClass('mouseOver');
  104. OC.Share.showDropDown(itemType, $tr.data('id'), appendTo, true, possiblePermissions, filename);
  105. });
  106. } else {
  107. OC.Share.hideDropDown();
  108. }
  109. } else {
  110. $tr.addClass('mouseOver');
  111. OC.Share.showDropDown(itemType, $tr.data('id'), appendTo, true, possiblePermissions, filename);
  112. }
  113. $('#dropdown').on('sharesChanged', function(ev) {
  114. // files app current cannot show recipients on load, so we don't update the
  115. // icon when changed for consistency
  116. if (context.fileList.$el.closest('#app-content-files').length) {
  117. return;
  118. }
  119. var recipients = _.pluck(ev.shares[OC.Share.SHARE_TYPE_USER], 'share_with_displayname');
  120. var groupRecipients = _.pluck(ev.shares[OC.Share.SHARE_TYPE_GROUP], 'share_with_displayname');
  121. recipients = recipients.concat(groupRecipients);
  122. // note: we only update the data attribute because updateIcon()
  123. // is called automatically after this event
  124. if (recipients.length) {
  125. $tr.attr('data-share-recipients', OCA.Sharing.Util.formatRecipients(recipients));
  126. }
  127. else {
  128. $tr.removeAttr('data-share-recipients');
  129. }
  130. });
  131. }, t('files_sharing', 'Share'));
  132. },
  133. /**
  134. * Update the file action share icon for the given file
  135. *
  136. * @param $tr file element of the file to update
  137. */
  138. updateFileActionIcon: function($tr) {
  139. // if the statuses are loaded already, use them for the icon
  140. // (needed when scrolling to the next page)
  141. var shareStatus = OC.Share.statuses[$tr.data('id')];
  142. if (shareStatus || $tr.attr('data-share-recipients') || $tr.attr('data-share-owner')) {
  143. var permissions = $tr.data('permissions');
  144. var hasLink = !!(shareStatus && shareStatus.link);
  145. OC.Share.markFileAsShared($tr, true, hasLink);
  146. if ((permissions & OC.PERMISSION_SHARE) === 0) {
  147. // if no share action exists because the admin disabled sharing for this user
  148. // we create a share notification action to inform the user about files
  149. // shared with him otherwise we just update the existing share action.
  150. // TODO: make this work like/with OC.Share.markFileAsShared()
  151. $tr.find('.fileactions .action-share-notification').remove();
  152. var shareNotification = '<a class="action action-share-notification permanent"' +
  153. ' data-action="Share-Notification" href="#" original-title="">' +
  154. ' <img class="svg" src="' + OC.imagePath('core', 'actions/share') + '"></img>';
  155. $tr.find('.fileactions').append(function() {
  156. var shareBy = escapeHTML($tr.attr('data-share-owner'));
  157. var $result = $(shareNotification + '<span> ' + shareBy + '</span></span>');
  158. $result.on('click', function() {
  159. return false;
  160. });
  161. return $result;
  162. });
  163. }
  164. }
  165. },
  166. /**
  167. * Formats a recipients array to be displayed.
  168. * The first four recipients will be shown and the
  169. * other ones will be shown as "+x" where "x" is the number of
  170. * remaining recipients.
  171. *
  172. * @param {Array.<String>} recipients recipients array
  173. * @param {int} count optional total recipients count (in case the array was shortened)
  174. * @return {String} formatted recipients display text
  175. */
  176. formatRecipients: function(recipients, count) {
  177. var maxRecipients = 4;
  178. var text;
  179. if (!_.isNumber(count)) {
  180. count = recipients.length;
  181. }
  182. // TODO: use natural sort
  183. recipients = _.first(recipients, maxRecipients).sort();
  184. text = recipients.join(', ');
  185. if (count > maxRecipients) {
  186. text += ', +' + (count - maxRecipients);
  187. }
  188. return text;
  189. }
  190. };
  191. })();
  192. OC.Plugins.register('OCA.Files.FileList', OCA.Sharing.Util);