aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files_sharing/js
diff options
context:
space:
mode:
authorLukas Reschke <lukas@statuscode.ch>2014-05-30 13:42:24 +0200
committerLukas Reschke <lukas@statuscode.ch>2014-05-30 13:42:24 +0200
commit517501ffbf369b24191d8b9a9f2ce44a9891fb97 (patch)
treef638ba7e2f3554b7b1a31f628496c7d0740fd2ac /apps/files_sharing/js
parent929882a32a020b6c05605f416fa55024b9a60d33 (diff)
parent7fac2b62e954b0f8a693516da1151c97efa2ee99 (diff)
downloadnextcloud-server-517501ffbf369b24191d8b9a9f2ce44a9891fb97.tar.gz
nextcloud-server-517501ffbf369b24191d8b9a9f2ce44a9891fb97.zip
Merge pull request #8417 from owncloud/share-overview
Sharing overview page
Diffstat (limited to 'apps/files_sharing/js')
-rw-r--r--apps/files_sharing/js/app.js106
-rw-r--r--apps/files_sharing/js/public.js23
-rw-r--r--apps/files_sharing/js/share.js50
-rw-r--r--apps/files_sharing/js/sharedfilelist.js235
4 files changed, 384 insertions, 30 deletions
diff --git a/apps/files_sharing/js/app.js b/apps/files_sharing/js/app.js
new file mode 100644
index 00000000000..3764328a5d0
--- /dev/null
+++ b/apps/files_sharing/js/app.js
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com>
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+OCA.Sharing = {};
+OCA.Sharing.App = {
+
+ _inFileList: null,
+ _outFileList: null,
+
+ initSharingIn: function($el) {
+ if (this._inFileList) {
+ return this._inFileList;
+ }
+
+ this._inFileList = new OCA.Sharing.FileList(
+ $el,
+ {
+ scrollContainer: $('#app-content'),
+ sharedWithUser: true,
+ fileActions: this._createFileActions()
+ }
+ );
+
+ this._extendFileList(this._inFileList);
+ this._inFileList.appName = t('files_sharing', 'Shared with you');
+ this._inFileList.$el.find('#emptycontent').text(t('files_sharing', 'No files have been shared with you yet.'));
+ return this._inFileList;
+ },
+
+ initSharingOut: function($el) {
+ if (this._outFileList) {
+ return this._outFileList;
+ }
+ this._outFileList = new OCA.Sharing.FileList(
+ $el,
+ {
+ scrollContainer: $('#app-content'),
+ sharedWithUser: false,
+ fileActions: this._createFileActions()
+ }
+ );
+
+ this._extendFileList(this._outFileList);
+ this._outFileList.appName = t('files_sharing', 'Shared with others');
+ this._outFileList.$el.find('#emptycontent').text(t('files_sharing', 'You haven\'t shared any files yet.'));
+ return this._outFileList;
+ },
+
+ removeSharingIn: function() {
+ if (this._inFileList) {
+ this._inFileList.$fileList.empty();
+ }
+ },
+
+ removeSharingOut: function() {
+ if (this._outFileList) {
+ this._outFileList.$fileList.empty();
+ }
+ },
+
+ _createFileActions: function() {
+ // inherit file actions from the files app
+ var fileActions = new OCA.Files.FileActions();
+ // note: not merging the legacy actions because legacy apps are not
+ // compatible with the sharing overview and need to be adapted first
+ fileActions.registerDefaultActions();
+ fileActions.merge(OCA.Files.fileActions);
+
+ // when the user clicks on a folder, redirect to the corresponding
+ // folder in the files app instead of opening it directly
+ fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) {
+ OCA.Files.App.setActiveView('files', {silent: true});
+ OCA.Files.App.fileList.changeDirectory(context.$file.attr('data-path') + '/' + filename, true, true);
+ });
+ fileActions.setDefault('dir', 'Open');
+ return fileActions;
+ },
+
+ _extendFileList: function(fileList) {
+ // remove size column from summary
+ fileList.fileSummary.$el.find('.filesize').remove();
+ }
+};
+
+$(document).ready(function() {
+ $('#app-content-sharingin').on('show', function(e) {
+ OCA.Sharing.App.initSharingIn($(e.target));
+ });
+ $('#app-content-sharingin').on('hide', function() {
+ OCA.Sharing.App.removeSharingIn();
+ });
+ $('#app-content-sharingout').on('show', function(e) {
+ OCA.Sharing.App.initSharingOut($(e.target));
+ });
+ $('#app-content-sharingout').on('hide', function() {
+ OCA.Sharing.App.removeSharingOut();
+ });
+});
+
diff --git a/apps/files_sharing/js/public.js b/apps/files_sharing/js/public.js
index d825ee9de15..27e8d361ff9 100644
--- a/apps/files_sharing/js/public.js
+++ b/apps/files_sharing/js/public.js
@@ -19,9 +19,18 @@ OCA.Sharing.PublicApp = {
initialize: function($el) {
var self = this;
+ var fileActions;
if (this._initialized) {
return;
}
+ fileActions = new OCA.Files.FileActions();
+ // default actions
+ fileActions.registerDefaultActions();
+ // legacy actions
+ fileActions.merge(window.FileActions);
+ // regular actions
+ fileActions.merge(OCA.Files.fileActions);
+
this._initialized = true;
this.initialDir = $('#dir').val();
@@ -32,7 +41,8 @@ OCA.Sharing.PublicApp = {
{
scrollContainer: $(window),
dragOptions: dragOptions,
- folderDropOptions: folderDropOptions
+ folderDropOptions: folderDropOptions,
+ fileActions: fileActions
}
);
this.files = OCA.Files.Files;
@@ -121,10 +131,8 @@ OCA.Sharing.PublicApp = {
};
});
- this.fileActions = _.extend({}, OCA.Files.FileActions);
- this.fileActions.registerDefaultActions(this.fileList);
- delete this.fileActions.actions.all.Share;
- this.fileList.setFileActions(this.fileActions);
+ // do not allow sharing from the public page
+ delete this.fileList.fileActions.actions.all.Share;
this.fileList.changeDirectory(this.initialDir || '/', false, true);
@@ -158,7 +166,10 @@ OCA.Sharing.PublicApp = {
$(document).ready(function() {
var App = OCA.Sharing.PublicApp;
- App.initialize($('#preview'));
+ // defer app init, to give a chance to plugins to register file actions
+ _.defer(function() {
+ App.initialize($('#preview'));
+ });
if (window.Files) {
// HACK: for oc-dialogs previews that depends on Files:
diff --git a/apps/files_sharing/js/share.js b/apps/files_sharing/js/share.js
index 84c5bf57b38..5a42604c866 100644
--- a/apps/files_sharing/js/share.js
+++ b/apps/files_sharing/js/share.js
@@ -8,12 +8,8 @@
*
*/
-/* global FileList, FileActions */
$(document).ready(function() {
-
- var sharesLoaded = false;
-
- if (typeof OC.Share !== 'undefined' && typeof FileActions !== 'undefined') {
+ if (!_.isUndefined(OC.Share) && !_.isUndefined(OCA.Files)) {
// TODO: make a separate class for this or a hook or jQuery event ?
if (OCA.Files.FileList) {
var oldCreateRow = OCA.Files.FileList.prototype._createRow;
@@ -31,10 +27,12 @@ $(document).ready(function() {
};
}
- $('#fileList').on('fileActionsReady',function(){
+ // use delegate to catch the case with multiple file lists
+ $('#content').delegate('#fileList', 'fileActionsReady',function(ev){
// 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.
+ var fileList = ev.fileList;
var $fileList = $(this);
$fileList.find('[data-share-owner]').each(function() {
var $tr = $(this);
@@ -62,46 +60,50 @@ $(document).ready(function() {
return $result;
});
}
- })
+ });
- // FIXME: these calls are also working on hard-coded
- // list selectors...
- if (!sharesLoaded){
- OC.Share.loadIcons('file');
+ if (!OCA.Sharing.sharesLoaded){
+ OC.Share.loadIcons('file', fileList);
// assume that we got all shares, so switching directories
// will not invalidate that list
- sharesLoaded = true;
+ OCA.Sharing.sharesLoaded = true;
}
else{
- OC.Share.updateIcons('file');
+ OC.Share.updateIcons('file', fileList);
}
});
- FileActions.register('all', 'Share', OC.PERMISSION_SHARE, OC.imagePath('core', 'actions/share'), function(filename) {
- var tr = FileList.findFileEl(filename);
+ OCA.Files.fileActions.register(
+ 'all',
+ 'Share',
+ OC.PERMISSION_SHARE,
+ OC.imagePath('core', 'actions/share'),
+ function(filename, context) {
+
+ var $tr = context.$file;
var itemType = 'file';
- if ($(tr).data('type') == 'dir') {
+ if ($tr.data('type') === 'dir') {
itemType = 'folder';
}
- var possiblePermissions = $(tr).data('reshare-permissions');
+ var possiblePermissions = $tr.data('reshare-permissions');
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
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 () {
- $(tr).addClass('mouseOver');
- OC.Share.showDropDown(itemType, $(tr).data('id'), appendTo, true, possiblePermissions, filename);
+ $tr.addClass('mouseOver');
+ OC.Share.showDropDown(itemType, $tr.data('id'), appendTo, true, possiblePermissions, filename);
});
} else {
OC.Share.hideDropDown();
}
} else {
- $(tr).addClass('mouseOver');
- OC.Share.showDropDown(itemType, $(tr).data('id'), appendTo, true, possiblePermissions, filename);
+ $tr.addClass('mouseOver');
+ OC.Share.showDropDown(itemType, $tr.data('id'), appendTo, true, possiblePermissions, filename);
}
});
}
diff --git a/apps/files_sharing/js/sharedfilelist.js b/apps/files_sharing/js/sharedfilelist.js
new file mode 100644
index 00000000000..ef1034ecfdc
--- /dev/null
+++ b/apps/files_sharing/js/sharedfilelist.js
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com>
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+(function() {
+
+ /**
+ * Sharing file list
+ *
+ * Contains both "shared with others" and "shared with you" modes.
+ */
+ var FileList = function($el, options) {
+ this.initialize($el, options);
+ };
+
+ FileList.prototype = _.extend({}, OCA.Files.FileList.prototype, {
+ appName: 'Shares',
+
+ /**
+ * Whether the list shows the files shared with the user (true) or
+ * the files that the user shared with others (false).
+ */
+ _sharedWithUser: false,
+
+ initialize: function($el, options) {
+ OCA.Files.FileList.prototype.initialize.apply(this, arguments);
+ if (this.initialized) {
+ return;
+ }
+
+ if (options && options.sharedWithUser) {
+ this._sharedWithUser = true;
+ }
+ },
+
+ _createRow: function(fileData) {
+ // TODO: hook earlier and render the whole row here
+ var $tr = OCA.Files.FileList.prototype._createRow.apply(this, arguments);
+ $tr.find('.filesize').remove();
+ $tr.find('td.date').before($tr.children('td:first'));
+ $tr.find('td.filename input:checkbox').remove();
+ $tr.attr('data-share-id', _.pluck(fileData.shares, 'id').join(','));
+ if (this._sharedWithUser) {
+ $tr.attr('data-share-owner', fileData.shares[0].ownerDisplayName);
+ }
+ return $tr;
+ },
+
+ /**
+ * Set whether the list should contain outgoing shares
+ * or incoming shares.
+ *
+ * @param state true for incoming shares, false otherwise
+ */
+ setSharedWithUser: function(state) {
+ this._sharedWithUser = !!state;
+ },
+
+ updateEmptyContent: function() {
+ var dir = this.getCurrentDirectory();
+ if (dir === '/') {
+ // root has special permissions
+ this.$el.find('#emptycontent').toggleClass('hidden', !this.isEmpty);
+ this.$el.find('#filestable thead th').toggleClass('hidden', this.isEmpty);
+ }
+ else {
+ OCA.Files.FileList.prototype.updateEmptyContent.apply(this, arguments);
+ }
+ },
+
+ getDirectoryPermissions: function() {
+ return OC.PERMISSION_READ | OC.PERMISSION_DELETE;
+ },
+
+ updateStorageStatistics: function() {
+ // no op because it doesn't have
+ // storage info like free space / used space
+ },
+
+ reload: function() {
+ var self = this;
+ this.showMask();
+ if (this._reloadCall) {
+ this._reloadCall.abort();
+ }
+ this._reloadCall = $.ajax({
+ url: OC.linkToOCS('apps/files_sharing/api/v1') + 'shares',
+ /* jshint camelcase: false */
+ data: {
+ format: 'json',
+ shared_with_me: !!this._sharedWithUser
+ },
+ type: 'GET',
+ beforeSend: function(xhr) {
+ xhr.setRequestHeader('OCS-APIREQUEST', 'true');
+ },
+ error: function(result) {
+ self.reloadCallback(result);
+ },
+ success: function(result) {
+ self.reloadCallback(result);
+ }
+ });
+ },
+
+ reloadCallback: function(result) {
+ delete this._reloadCall;
+ this.hideMask();
+
+ this.$el.find('#headerSharedWith').text(
+ t('files_sharing', this._sharedWithUser ? 'Shared by' : 'Shared with')
+ );
+ if (result.ocs && result.ocs.data) {
+ this.setFiles(this._makeFilesFromShares(result.ocs.data));
+ }
+ else {
+ // TODO: error handling
+ }
+ },
+
+ /**
+ * Converts the OCS API share response data to a file info
+ * list
+ * @param OCS API share array
+ * @return array of file info maps
+ */
+ _makeFilesFromShares: function(data) {
+ var self = this;
+ // OCS API uses non-camelcased names
+ var files = _.chain(data)
+ // convert share data to file data
+ .map(function(share) {
+ /* jshint camelcase: false */
+ var file = {
+ id: share.file_source,
+ mimetype: share.mimetype
+ };
+ if (share.item_type === 'folder') {
+ file.type = 'dir';
+ file.mimetype = 'httpd/unix-directory';
+ }
+ else {
+ file.type = 'file';
+ // force preview retrieval as we don't have mime types,
+ // the preview endpoint will fall back to the mime type
+ // icon if no preview exists
+ file.isPreviewAvailable = true;
+ file.icon = true;
+ }
+ file.share = {
+ id: share.id,
+ type: share.share_type,
+ target: share.share_with,
+ stime: share.stime * 1000,
+ };
+ if (self._sharedWithUser) {
+ file.share.ownerDisplayName = share.displayname_owner;
+ file.name = OC.basename(share.file_target);
+ file.path = OC.dirname(share.file_target);
+ file.permissions = share.permissions;
+ }
+ else {
+ file.share.targetDisplayName = share.share_with_displayname;
+ file.name = OC.basename(share.path);
+ file.path = OC.dirname(share.path);
+ file.permissions = OC.PERMISSION_ALL;
+ }
+ return file;
+ })
+ // Group all files and have a "shares" array with
+ // the share info for each file.
+ //
+ // This uses a hash memo to cumulate share information
+ // inside the same file object (by file id).
+ .reduce(function(memo, file) {
+ var data = memo[file.id];
+ var counterPart = file.share.ownerDisplayName || file.share.targetDisplayName;
+ if (!data) {
+ data = memo[file.id] = file;
+ data.shares = [file.share];
+ // using a hash to make them unique,
+ // this is only a list to be displayed
+ data.counterParts = {};
+ // counter is cheaper than calling _.keys().length
+ data.counterPartsCount = 0;
+ data.mtime = file.share.stime;
+ }
+ else {
+ // always take the most recent stime
+ if (file.share.stime > data.mtime) {
+ data.mtime = file.share.stime;
+ }
+ data.shares.push(file.share);
+ }
+
+ if (file.share.type === OC.Share.SHARE_TYPE_LINK) {
+ data.hasLinkShare = true;
+ } else if (counterPart && data.counterPartsCount < 10) {
+ // limit counterparts for output
+ data.counterParts[counterPart] = true;
+ data.counterPartsCount++;
+ }
+
+ delete file.share;
+ return memo;
+ }, {})
+ // Retrieve only the values of the returned hash
+ .values()
+ // Clean up
+ .each(function(data) {
+ // convert the counterParts map to a flat
+ // array of sorted names
+ data.counterParts = _.chain(data.counterParts).keys().sort().value();
+ if (data.hasLinkShare) {
+ data.counterParts.unshift(t('files_sharing', 'link'));
+ delete data.hasLinkShare;
+ }
+ delete data.counterPartsCount;
+ })
+ // Sort by expected sort comparator
+ .sortBy(this._sortComparator)
+ // Finish the chain by getting the result
+ .value();
+
+ return files;
+ }
+ });
+
+ OCA.Sharing.FileList = FileList;
+})();