summaryrefslogtreecommitdiffstats
path: root/apps
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
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')
-rw-r--r--apps/files/css/files.css8
-rw-r--r--apps/files/index.php5
-rw-r--r--apps/files/js/app.js35
-rw-r--r--apps/files/js/fileactions.js101
-rw-r--r--apps/files/js/filelist.js60
-rw-r--r--apps/files/tests/js/appSpec.js53
-rw-r--r--apps/files/tests/js/fileactionsSpec.js80
-rw-r--r--apps/files/tests/js/filelistSpec.js47
-rw-r--r--apps/files_sharing/appinfo/app.php20
-rw-r--r--apps/files_sharing/css/sharedfilelist.css3
-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
-rw-r--r--apps/files_sharing/lib/api.php38
-rw-r--r--apps/files_sharing/list.php11
-rw-r--r--apps/files_sharing/templates/list.php28
-rw-r--r--apps/files_sharing/tests/js/appSpec.js143
-rw-r--r--apps/files_sharing/tests/js/sharedfilelistSpec.js412
-rw-r--r--apps/files_trashbin/appinfo/app.php2
-rw-r--r--apps/files_trashbin/js/app.js24
-rw-r--r--apps/files_trashbin/js/filelist.js4
-rw-r--r--apps/files_trashbin/tests/js/filelistSpec.js11
-rw-r--r--apps/files_versions/js/versions.js37
24 files changed, 1405 insertions, 131 deletions
diff --git a/apps/files/css/files.css b/apps/files/css/files.css
index 731dd7a23e7..0bcea2eceaf 100644
--- a/apps/files/css/files.css
+++ b/apps/files/css/files.css
@@ -151,7 +151,13 @@ tr:hover span.extension {
}
table tr.mouseOver td { background-color:#eee; }
-table th { height:24px; padding:0 8px; color:#999; }
+table th { height:24px; padding:0 8px; }
+table th, table th a {
+ color: #999;
+}
+table.multiselect th a {
+ color: #000;
+}
table th .columntitle {
display: inline-block;
padding: 15px;
diff --git a/apps/files/index.php b/apps/files/index.php
index e24c535cb20..95ae7977ecc 100644
--- a/apps/files/index.php
+++ b/apps/files/index.php
@@ -74,7 +74,12 @@ if (OC_App::isEnabled('files_encryption')) {
$nav = new OCP\Template('files', 'appnavigation', '');
+function sortNavigationItems($item1, $item2) {
+ return $item1['order'] - $item2['order'];
+}
+
$navItems = \OCA\Files\App::getNavigationManager()->getAll();
+usort($navItems, 'sortNavigationItems');
$nav->assign('navigationItems', $navItems);
$contentItems = array();
diff --git a/apps/files/js/app.js b/apps/files/js/app.js
index 9155fb38cdb..71802948a5c 100644
--- a/apps/files/js/app.js
+++ b/apps/files/js/app.js
@@ -24,20 +24,27 @@
initialize: function() {
this.navigation = new OCA.Files.Navigation($('#app-navigation'));
- // TODO: ideally these should be in a separate class / app (the embedded "all files" app)
- this.fileActions = OCA.Files.FileActions;
+ var fileActions = new OCA.Files.FileActions();
+ // default actions
+ fileActions.registerDefaultActions();
+ // legacy actions
+ fileActions.merge(window.FileActions);
+ // regular actions
+ fileActions.merge(OCA.Files.fileActions);
+
this.files = OCA.Files.Files;
+ // TODO: ideally these should be in a separate class / app (the embedded "all files" app)
this.fileList = new OCA.Files.FileList(
$('#app-content-files'), {
scrollContainer: $('#app-content'),
dragOptions: dragOptions,
- folderDropOptions: folderDropOptions
+ folderDropOptions: folderDropOptions,
+ fileActions: fileActions,
+ allowLegacyActions: true
}
);
this.files.initialize();
- this.fileActions.registerDefaultActions(this.fileList);
- this.fileList.setFileActions(this.fileActions);
// for backward compatibility, the global FileList will
// refer to the one of the "files" view
@@ -58,6 +65,22 @@
},
/**
+ * Sets the currently active view
+ * @param viewId view id
+ */
+ setActiveView: function(viewId, options) {
+ this.navigation.setActiveItem(viewId, options);
+ },
+
+ /**
+ * Returns the view id of the currently active view
+ * @return view id
+ */
+ getActiveView: function() {
+ return this.navigation.getActiveItem();
+ },
+
+ /**
* Setup events based on URL changes
*/
_setupEvents: function() {
@@ -138,7 +161,7 @@
})();
$(document).ready(function() {
- // wait for other apps/extensions to register their event handlers
+ // wait for other apps/extensions to register their event handlers and file actions
// in the "ready" clause
_.defer(function() {
OCA.Files.App.initialize();
diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js
index 085195e961d..3df62f37518 100644
--- a/apps/files/js/fileactions.js
+++ b/apps/files/js/fileactions.js
@@ -11,11 +11,40 @@
/* global trashBinApp */
(function() {
- var FileActions = {
+ /**
+ * Construct a new FileActions instance
+ */
+ var FileActions = function() {
+ this.initialize();
+ }
+ FileActions.prototype = {
actions: {},
defaults: {},
icons: {},
currentFile: null,
+ initialize: function() {
+ this.clear();
+ },
+ /**
+ * Merges the actions from the given fileActions into
+ * this instance.
+ *
+ * @param fileActions instance of OCA.Files.FileActions
+ */
+ merge: function(fileActions) {
+ var self = this;
+ // merge first level to avoid unintended overwriting
+ _.each(fileActions.actions, function(sourceMimeData, mime) {
+ var targetMimeData = self.actions[mime];
+ if (!targetMimeData) {
+ targetMimeData = {};
+ }
+ self.actions[mime] = _.extend(targetMimeData, sourceMimeData);
+ });
+
+ this.defaults = _.extend(this.defaults, fileActions.defaults);
+ this.icons = _.extend(this.icons, fileActions.icons);
+ },
register: function (mime, name, permissions, icon, action, displayName) {
if (!this.actions[mime]) {
this.actions[mime] = {};
@@ -98,8 +127,13 @@
* @param parent "td" element of the file for which to display actions
* @param triggerEvent if true, triggers the fileActionsReady on the file
* list afterwards (false by default)
+ * @param fileList OCA.Files.FileList instance on which the action is
+ * done, defaults to OCA.Files.App.fileList
*/
- display: function (parent, triggerEvent) {
+ display: function (parent, triggerEvent, fileList) {
+ if (!fileList) {
+ console.warn('FileActions.display() MUST be called with a OCA.Files.FileList instance');
+ }
this.currentFile = parent;
var self = this;
var actions = this.getActions(this.getCurrentMimeType(), this.getCurrentType(), this.getCurrentPermissions());
@@ -120,9 +154,18 @@
event.preventDefault();
self.currentFile = event.data.elem;
+ // also set on global object for legacy apps
+ window.FileActions.currentFile = self.currentFile;
+
var file = self.getCurrentFile();
+ var $tr = $(this).closest('tr');
- event.data.actionFunc(file);
+ event.data.actionFunc(file, {
+ $file: $tr,
+ fileList: fileList || OCA.Files.App.fileList,
+ fileActions: self,
+ dir: $tr.attr('data-path') || fileList.getCurrentDirectory()
+ });
};
var addAction = function (name, action, displayName) {
@@ -189,7 +232,7 @@
}
if (triggerEvent){
- $('#fileList').trigger(jQuery.Event("fileActionsReady"));
+ fileList.$fileList.trigger(jQuery.Event("fileActionsReady", {fileList: fileList}));
}
},
getCurrentFile: function () {
@@ -208,29 +251,27 @@
/**
* Register the actions that are used by default for the files app.
*/
- registerDefaultActions: function(fileList) {
- // TODO: try to find a way to not make it depend on fileList,
- // maybe get a handler or listener to trigger events on
+ registerDefaultActions: function() {
this.register('all', 'Delete', OC.PERMISSION_DELETE, function () {
return OC.imagePath('core', 'actions/delete');
- }, function (filename) {
- fileList.do_delete(filename);
+ }, function (filename, context) {
+ context.fileList.do_delete(filename);
$('.tipsy').remove();
});
// t('files', 'Rename')
this.register('all', 'Rename', OC.PERMISSION_UPDATE, function () {
return OC.imagePath('core', 'actions/rename');
- }, function (filename) {
- fileList.rename(filename);
+ }, function (filename, context) {
+ context.fileList.rename(filename);
});
- this.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename) {
- var dir = fileList.getCurrentDirectory();
+ this.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) {
+ var dir = context.fileList.getCurrentDirectory();
if (dir !== '/') {
dir = dir + '/';
}
- fileList.changeDirectory(dir + filename);
+ context.fileList.changeDirectory(dir + filename);
});
this.setDefault('dir', 'Open');
@@ -243,20 +284,38 @@
this.register(downloadScope, 'Download', OC.PERMISSION_READ, function () {
return OC.imagePath('core', 'actions/download');
- }, function (filename) {
- var url = fileList.getDownloadUrl(filename, fileList.getCurrentDirectory());
+ }, function (filename, context) {
+ var dir = context.dir || context.fileList.getCurrentDirectory();
+ var url = context.fileList.getDownloadUrl(filename, dir);
if (url) {
OC.redirect(url);
}
});
-
- fileList.$fileList.trigger(jQuery.Event("fileActionsReady"));
}
};
OCA.Files.FileActions = FileActions;
-})();
-// for backward compatibility
-window.FileActions = OCA.Files.FileActions;
+ // global file actions to be used by all lists
+ OCA.Files.fileActions = new OCA.Files.FileActions();
+ OCA.Files.legacyFileActions = new OCA.Files.FileActions();
+
+ // for backward compatibility
+ //
+ // legacy apps are expecting a stateful global FileActions object to register
+ // their actions on. Since legacy apps are very likely to break with other
+ // FileList views than the main one ("All files"), actions registered
+ // through window.FileActions will be limited to the main file list.
+ window.FileActions = OCA.Files.legacyFileActions;
+ window.FileActions.register = function (mime, name, permissions, icon, action, displayName) {
+ console.warn('FileActions.register() is deprecated, please use OCA.Files.fileActions.register() instead', arguments);
+ OCA.Files.FileActions.prototype.register.call(
+ window.FileActions, mime, name, permissions, icon, action, displayName
+ );
+ };
+ window.FileActions.setDefault = function (mime, name) {
+ console.warn('FileActions.setDefault() is deprecated, please use OCA.Files.fileActions.setDefault() instead', mime, name);
+ OCA.Files.FileActions.prototype.setDefault.call(window.FileActions, mime, name);
+ };
+})();
diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js
index 72e1a688041..68b22207144 100644
--- a/apps/files/js/filelist.js
+++ b/apps/files/js/filelist.js
@@ -125,7 +125,7 @@
this.$container = options.scrollContainer || $(window);
this.$table = $el.find('table:first');
this.$fileList = $el.find('#fileList');
- this.fileActions = OCA.Files.FileActions;
+ this._initFileActions(options.fileActions);
this.files = [];
this._selectedFiles = {};
this._selectionSummary = new OCA.Files.FileSummary();
@@ -168,6 +168,14 @@
this.$container.on('scroll', _.bind(this._onScroll, this));
},
+ _initFileActions: function(fileActions) {
+ this.fileActions = fileActions;
+ if (!this.fileActions) {
+ this.fileActions = new OCA.Files.FileActions();
+ this.fileActions.registerDefaultActions();
+ }
+ },
+
/**
* Event handler for when the URL changed
*/
@@ -248,7 +256,14 @@
var action = this.fileActions.getDefault(mime,type, permissions);
if (action) {
event.preventDefault();
- action(filename);
+ // also set on global object for legacy apps
+ window.FileActions.currentFile = this.fileActions.currentFile;
+ action(filename, {
+ $file: $tr,
+ fileList: this,
+ fileActions: this.fileActions,
+ dir: $tr.attr('data-path') || this.getCurrentDirectory()
+ });
}
}
}
@@ -448,7 +463,7 @@
while (count > 0 && index < this.files.length) {
fileData = this.files[index];
- tr = this._renderRow(fileData, {updateSummary: false});
+ tr = this._renderRow(fileData, {updateSummary: false, silent: true});
this.$fileList.append(tr);
if (isAllSelected || this._selectedFiles[fileData.id]) {
tr.addClass('selected');
@@ -493,7 +508,7 @@
this.$el.find('thead').after(this.$fileList);
this.updateEmptyContent();
- this.$fileList.trigger(jQuery.Event("fileActionsReady"));
+ this.$fileList.trigger($.Event('fileActionsReady', {fileList: this}));
this.fileSummary.calculate(filesArray);
@@ -515,6 +530,7 @@
type = fileData.type || 'file',
mtime = parseInt(fileData.mtime, 10) || new Date().getTime(),
mime = fileData.mimetype,
+ path = fileData.path,
linkUrl;
options = options || {};
@@ -534,6 +550,13 @@
"data-permissions": fileData.permissions || this.getDirectoryPermissions()
});
+ if (!_.isUndefined(path)) {
+ tr.attr('data-path', path);
+ }
+ else {
+ path = this.getCurrentDirectory();
+ }
+
if (type === 'dir') {
// use default folder icon
icon = icon || OC.imagePath('core', 'filetypes/folder');
@@ -550,10 +573,10 @@
// linkUrl
if (type === 'dir') {
- linkUrl = this.linkTo(this.getCurrentDirectory() + '/' + name);
+ linkUrl = this.linkTo(path + '/' + name);
}
else {
- linkUrl = this.getDownloadUrl(name, this.getCurrentDirectory());
+ linkUrl = this.getDownloadUrl(name, path);
}
td.append('<input id="select-' + this.id + '-' + fileData.id +
'" type="checkbox" /><label for="select-' + this.id + '-' + fileData.id + '"></label>');
@@ -621,7 +644,8 @@
*
* @param fileData map of file attributes
* @param options map of attributes:
- * - "updateSummary" true to update the summary after adding (default), false otherwise
+ * - "updateSummary": true to update the summary after adding (default), false otherwise
+ * - "silent": true to prevent firing events like "fileActionsReady"
* @return new tr element (not appended to the table)
*/
add: function(fileData, options) {
@@ -693,6 +717,7 @@
options = options || {};
var type = fileData.type || 'file',
mime = fileData.mimetype,
+ path = fileData.path || this.getCurrentDirectory(),
permissions = parseInt(fileData.permissions, 10) || 0;
if (fileData.isShareMountPoint) {
@@ -723,13 +748,13 @@
}
// display actions
- this.fileActions.display(filenameTd, false);
+ this.fileActions.display(filenameTd, !options.silent, this);
if (fileData.isPreviewAvailable) {
// lazy load / newly inserted td ?
if (!fileData.icon) {
this.lazyLoadPreview({
- path: this.getCurrentDirectory() + '/' + fileData.name,
+ path: path + '/' + fileData.name,
mime: mime,
etag: fileData.etag,
callback: function(url) {
@@ -740,7 +765,7 @@
else {
// set the preview URL directly
var urlSpec = {
- file: this.getCurrentDirectory() + '/' + fileData.name,
+ file: path + '/' + fileData.name,
c: fileData.etag
};
var previewUrl = this.generatePreviewUrl(urlSpec);
@@ -784,13 +809,6 @@
},
/**
- * Sets the file actions handler
- */
- setFileActions: function(fileActions) {
- this.fileActions = fileActions;
- },
-
- /**
* Sets the current directory name and updates the breadcrumb.
* @param targetDir directory to display
* @param changeUrl true to also update the URL, false otherwise (default)
@@ -1213,16 +1231,16 @@
// reinsert row
self.files.splice(tr.index(), 1);
tr.remove();
- self.add(fileInfo, {updateSummary: false});
- self.$fileList.trigger($.Event('fileActionsReady'));
+ self.add(fileInfo, {updateSummary: false, silent: true});
+ self.$fileList.trigger($.Event('fileActionsReady', {fileList: self}));
}
});
} else {
// add back the old file info when cancelled
self.files.splice(tr.index(), 1);
tr.remove();
- self.add(oldFileInfo, {updateSummary: false});
- self.$fileList.trigger($.Event('fileActionsReady'));
+ self.add(oldFileInfo, {updateSummary: false, silent: true});
+ self.$fileList.trigger($.Event('fileActionsReady', {fileList: self}));
}
} catch (error) {
input.attr('title', error);
diff --git a/apps/files/tests/js/appSpec.js b/apps/files/tests/js/appSpec.js
index 0e9abad6989..a9bbab03ecb 100644
--- a/apps/files/tests/js/appSpec.js
+++ b/apps/files/tests/js/appSpec.js
@@ -41,6 +41,10 @@ describe('OCA.Files.App tests', function() {
'</div>'
);
+ window.FileActions = new OCA.Files.FileActions();
+ OCA.Files.legacyFileActions = window.FileActions;
+ OCA.Files.fileActions = new OCA.Files.FileActions();
+
pushStateStub = sinon.stub(OC.Util.History, 'pushState');
parseUrlQueryStub = sinon.stub(OC.Util.History, 'parseUrlQuery');
parseUrlQueryStub.returns({});
@@ -51,8 +55,6 @@ describe('OCA.Files.App tests', function() {
App.navigation = null;
App.fileList = null;
App.files = null;
- App.fileActions.clear();
- App.fileActions = null;
pushStateStub.restore();
parseUrlQueryStub.restore();
@@ -64,6 +66,53 @@ describe('OCA.Files.App tests', function() {
expect(App.fileList.fileActions.actions.all).toBeDefined();
expect(App.fileList.$el.is('#app-content-files')).toEqual(true);
});
+ it('merges the legacy file actions with the default ones', function() {
+ var legacyActionStub = sinon.stub();
+ var actionStub = sinon.stub();
+ // legacy action
+ window.FileActions.register(
+ 'all',
+ 'LegacyTest',
+ OC.PERMISSION_READ,
+ OC.imagePath('core', 'actions/test'),
+ legacyActionStub
+ );
+ // legacy action to be overwritten
+ window.FileActions.register(
+ 'all',
+ 'OverwriteThis',
+ OC.PERMISSION_READ,
+ OC.imagePath('core', 'actions/test'),
+ legacyActionStub
+ );
+
+ // regular file actions
+ OCA.Files.fileActions.register(
+ 'all',
+ 'RegularTest',
+ OC.PERMISSION_READ,
+ OC.imagePath('core', 'actions/test'),
+ actionStub
+ );
+
+ // overwrite
+ OCA.Files.fileActions.register(
+ 'all',
+ 'OverwriteThis',
+ OC.PERMISSION_READ,
+ OC.imagePath('core', 'actions/test'),
+ actionStub
+ );
+
+ App.initialize();
+
+ var actions = App.fileList.fileActions.actions;
+ expect(actions.all.OverwriteThis.action).toBe(actionStub);
+ expect(actions.all.LegacyTest.action).toBe(legacyActionStub);
+ expect(actions.all.RegularTest.action).toBe(actionStub);
+ // default one still there
+ expect(actions.dir.Open.action).toBeDefined();
+ });
});
describe('URL handling', function() {
diff --git a/apps/files/tests/js/fileactionsSpec.js b/apps/files/tests/js/fileactionsSpec.js
index 9152dbb58c3..490594a1773 100644
--- a/apps/files/tests/js/fileactionsSpec.js
+++ b/apps/files/tests/js/fileactionsSpec.js
@@ -21,7 +21,7 @@
describe('OCA.Files.FileActions tests', function() {
var $filesTable, fileList;
- var FileActions = OCA.Files.FileActions;
+ var FileActions;
beforeEach(function() {
// init horrible parameters
@@ -31,10 +31,11 @@ describe('OCA.Files.FileActions tests', function() {
// dummy files table
$filesTable = $body.append('<table id="filestable"></table>');
fileList = new OCA.Files.FileList($('#testArea'));
- FileActions.registerDefaultActions(fileList);
+ FileActions = new OCA.Files.FileActions();
+ FileActions.registerDefaultActions();
});
afterEach(function() {
- FileActions.clear();
+ FileActions = null;
fileList = undefined;
$('#dir, #permissions, #filestable').remove();
});
@@ -78,8 +79,8 @@ describe('OCA.Files.FileActions tests', function() {
};
var $tr = fileList.add(fileData);
- FileActions.display($tr.find('td.filename'), true);
- FileActions.display($tr.find('td.filename'), true);
+ FileActions.display($tr.find('td.filename'), true, fileList);
+ FileActions.display($tr.find('td.filename'), true, fileList);
// actions defined after cal
expect($tr.find('.action.action-download').length).toEqual(1);
@@ -98,12 +99,39 @@ describe('OCA.Files.FileActions tests', function() {
mtime: '123456'
};
var $tr = fileList.add(fileData);
- FileActions.display($tr.find('td.filename'), true);
+ FileActions.display($tr.find('td.filename'), true, fileList);
+
+ $tr.find('.action-download').click();
+
+ expect(redirectStub.calledOnce).toEqual(true);
+ expect(redirectStub.getCall(0).args[0]).toEqual(
+ OC.webroot +
+ '/index.php/apps/files/ajax/download.php' +
+ '?dir=%2Fsubdir&files=testName.txt');
+ redirectStub.restore();
+ });
+ it('takes the file\'s path into account when clicking download', function() {
+ var redirectStub = sinon.stub(OC, 'redirect');
+ var fileData = {
+ id: 18,
+ type: 'file',
+ name: 'testName.txt',
+ path: '/anotherpath/there',
+ mimetype: 'text/plain',
+ size: '1234',
+ etag: 'a01234c',
+ mtime: '123456'
+ };
+ var $tr = fileList.add(fileData);
+ FileActions.display($tr.find('td.filename'), true, fileList);
$tr.find('.action-download').click();
expect(redirectStub.calledOnce).toEqual(true);
- expect(redirectStub.getCall(0).args[0]).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=testName.txt');
+ expect(redirectStub.getCall(0).args[0]).toEqual(
+ OC.webroot + '/index.php/apps/files/ajax/download.php' +
+ '?dir=%2Fanotherpath%2Fthere&files=testName.txt'
+ );
redirectStub.restore();
});
it('deletes file when clicking delete', function() {
@@ -118,11 +146,47 @@ describe('OCA.Files.FileActions tests', function() {
mtime: '123456'
};
var $tr = fileList.add(fileData);
- FileActions.display($tr.find('td.filename'), true);
+ FileActions.display($tr.find('td.filename'), true, fileList);
$tr.find('.action.delete').click();
expect(deleteStub.calledOnce).toEqual(true);
deleteStub.restore();
});
+ it('passes context to action handler', function() {
+ var actionStub = sinon.stub();
+ var fileData = {
+ id: 18,
+ type: 'file',
+ name: 'testName.txt',
+ mimetype: 'text/plain',
+ size: '1234',
+ etag: 'a01234c',
+ mtime: '123456'
+ };
+ var $tr = fileList.add(fileData);
+ FileActions.register(
+ 'all',
+ 'Test',
+ OC.PERMISSION_READ,
+ OC.imagePath('core', 'actions/test'),
+ actionStub
+ );
+ FileActions.display($tr.find('td.filename'), true, fileList);
+ $tr.find('.action-test').click();
+ expect(actionStub.calledOnce).toEqual(true);
+ expect(actionStub.getCall(0).args[0]).toEqual('testName.txt');
+ var context = actionStub.getCall(0).args[1];
+ expect(context.$file.is($tr)).toEqual(true);
+ expect(context.fileList).toBeDefined();
+ expect(context.fileActions).toBeDefined();
+ expect(context.dir).toEqual('/subdir');
+
+ // when data-path is defined
+ actionStub.reset();
+ $tr.attr('data-path', '/somepath');
+ $tr.find('.action-test').click();
+ context = actionStub.getCall(0).args[1];
+ expect(context.dir).toEqual('/somepath');
+ });
});
diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js
index a3dc5b255a1..3e9950dfe19 100644
--- a/apps/files/tests/js/filelistSpec.js
+++ b/apps/files/tests/js/filelistSpec.js
@@ -21,7 +21,6 @@
describe('OCA.Files.FileList tests', function() {
var testFiles, alertStub, notificationStub, fileList;
- var FileActions = OCA.Files.FileActions;
/**
* Generate test file data
@@ -117,15 +116,11 @@ describe('OCA.Files.FileList tests', function() {
}];
fileList = new OCA.Files.FileList($('#app-content-files'));
- FileActions.clear();
- FileActions.registerDefaultActions(fileList);
- fileList.setFileActions(FileActions);
});
afterEach(function() {
testFiles = undefined;
fileList = undefined;
- FileActions.clear();
notificationStub.restore();
alertStub.restore();
});
@@ -488,7 +483,7 @@ describe('OCA.Files.FileList tests', function() {
var $input, request;
for (var i = 0; i < testFiles.length; i++) {
- fileList.add(testFiles[i]);
+ fileList.add(testFiles[i], {silent: true});
}
// trigger rename prompt
@@ -753,6 +748,20 @@ describe('OCA.Files.FileList tests', function() {
fileList.setFiles(testFiles);
expect(handler.calledOnce).toEqual(true);
});
+ it('triggers "fileActionsReady" event after single add', function() {
+ var handler = sinon.stub();
+ fileList.setFiles(testFiles);
+ fileList.$fileList.on('fileActionsReady', handler);
+ fileList.add({name: 'test.txt'});
+ expect(handler.calledOnce).toEqual(true);
+ });
+ it('does not trigger "fileActionsReady" event after single add with silent argument', function() {
+ var handler = sinon.stub();
+ fileList.setFiles(testFiles);
+ fileList.$fileList.on('fileActionsReady', handler);
+ fileList.add({name: 'test.txt'}, {silent: true});
+ expect(handler.notCalled).toEqual(true);
+ });
it('triggers "updated" event after update', function() {
var handler = sinon.stub();
fileList.$fileList.on('updated', handler);
@@ -1512,6 +1521,32 @@ describe('OCA.Files.FileList tests', function() {
expect(fileList.getSelectedFiles()).toEqual([]);
});
});
+ describe('File actions', function() {
+ it('Clicking on a file name will trigger default action', function() {
+ var actionStub = sinon.stub();
+ fileList.setFiles(testFiles);
+ fileList.fileActions.register(
+ 'text/plain',
+ 'Test',
+ OC.PERMISSION_ALL,
+ function() {
+ // Specify icon for hitory button
+ return OC.imagePath('core','actions/history');
+ },
+ actionStub
+ );
+ fileList.fileActions.setDefault('text/plain', 'Test');
+ var $tr = fileList.findFileEl('One.txt');
+ $tr.find('td.filename>a.name').click();
+ expect(actionStub.calledOnce).toEqual(true);
+ expect(actionStub.getCall(0).args[0]).toEqual('One.txt');
+ var context = actionStub.getCall(0).args[1];
+ expect(context.$file.is($tr)).toEqual(true);
+ expect(context.fileList).toBeDefined();
+ expect(context.fileActions).toBeDefined();
+ expect(context.dir).toEqual('/subdir');
+ });
+ });
describe('Sorting files', function() {
it('Sorts by name by default', function() {
fileList.reload();
diff --git a/apps/files_sharing/appinfo/app.php b/apps/files_sharing/appinfo/app.php
index fa43f33721c..21b2646c5ea 100644
--- a/apps/files_sharing/appinfo/app.php
+++ b/apps/files_sharing/appinfo/app.php
@@ -1,4 +1,5 @@
<?php
+$l = OC_L10N::get('files_sharing');
OC::$CLASSPATH['OC_Share_Backend_File'] = 'files_sharing/lib/share/file.php';
OC::$CLASSPATH['OC_Share_Backend_Folder'] = 'files_sharing/lib/share/folder.php';
@@ -21,3 +22,22 @@ OCP\Util::addScript('files_sharing', 'share');
\OC_Hook::connect('OC_Appconfig', 'post_set_value', '\OCA\Files\Share\Maintainer', 'configChangeHook');
OC_FileProxy::register(new OCA\Files\Share\Proxy());
+
+\OCA\Files\App::getNavigationManager()->add(
+ array(
+ "id" => 'sharingin',
+ "appname" => 'files_sharing',
+ "script" => 'list.php',
+ "order" => 10,
+ "name" => $l->t('Shared with you')
+ )
+);
+\OCA\Files\App::getNavigationManager()->add(
+ array(
+ "id" => 'sharingout',
+ "appname" => 'files_sharing',
+ "script" => 'list.php',
+ "order" => 15,
+ "name" => $l->t('Shared with others')
+ )
+);
diff --git a/apps/files_sharing/css/sharedfilelist.css b/apps/files_sharing/css/sharedfilelist.css
new file mode 100644
index 00000000000..6b0c7d2226e
--- /dev/null
+++ b/apps/files_sharing/css/sharedfilelist.css
@@ -0,0 +1,3 @@
+#filestable.shareList .summary .filesize {
+ display: none;
+}
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;
+})();
diff --git a/apps/files_sharing/lib/api.php b/apps/files_sharing/lib/api.php
index 21fd5d00a4c..dc4e5cf6c49 100644
--- a/apps/files_sharing/lib/api.php
+++ b/apps/files_sharing/lib/api.php
@@ -31,6 +31,9 @@ class Api {
* @return \OC_OCS_Result share information
*/
public static function getAllShares($params) {
+ if (isset($_GET['shared_with_me']) && $_GET['shared_with_me'] !== 'false') {
+ return self::getFilesSharedWithMe();
+ }
// if a file is specified, get the share for this file
if (isset($_GET['path'])) {
$params['itemSource'] = self::getFileId($_GET['path']);
@@ -49,12 +52,20 @@ class Api {
return self::collectShares($params);
}
- $share = \OCP\Share::getItemShared('file', null);
+ $shares = \OCP\Share::getItemShared('file', null);
- if ($share === false) {
+ if ($shares === false) {
return new \OC_OCS_Result(null, 404, 'could not get shares');
} else {
- return new \OC_OCS_Result($share);
+ foreach ($shares as &$share) {
+ // file_target might not be set if the target user hasn't mounted
+ // the filesystem yet
+ if ($share['item_type'] === 'file' && isset($share['file_target'])) {
+ $share['mimetype'] = \OC_Helper::getFileNameMimeType($share['file_target']);
+ }
+ $newShares[] = $share;
+ }
+ return new \OC_OCS_Result($shares);
}
}
@@ -196,6 +207,27 @@ class Api {
}
/**
+ * get files shared with the user
+ * @return \OC_OCS_Result
+ */
+ private static function getFilesSharedWithMe() {
+ try {
+ $shares = \OCP\Share::getItemsSharedWith('file');
+ foreach ($shares as &$share) {
+ if ($share['item_type'] === 'file') {
+ $share['mimetype'] = \OC_Helper::getFileNameMimeType($share['file_target']);
+ }
+ }
+ $result = new \OC_OCS_Result($shares);
+ } catch (\Exception $e) {
+ $result = new \OC_OCS_Result(null, 403, $e->getMessage());
+ }
+
+ return $result;
+
+ }
+
+ /**
* create a new share
* @param array $params
* @return \OC_OCS_Result
diff --git a/apps/files_sharing/list.php b/apps/files_sharing/list.php
new file mode 100644
index 00000000000..bad690ea95f
--- /dev/null
+++ b/apps/files_sharing/list.php
@@ -0,0 +1,11 @@
+<?php
+
+// Check if we are a user
+OCP\User::checkLoggedIn();
+
+$tmpl = new OCP\Template('files_sharing', 'list', '');
+
+OCP\Util::addScript('files_sharing', 'app');
+OCP\Util::addScript('files_sharing', 'sharedfilelist');
+
+$tmpl->printPage();
diff --git a/apps/files_sharing/templates/list.php b/apps/files_sharing/templates/list.php
new file mode 100644
index 00000000000..a1d95ebc1f1
--- /dev/null
+++ b/apps/files_sharing/templates/list.php
@@ -0,0 +1,28 @@
+<?php /** @var $l OC_L10N */ ?>
+<div id="controls">
+ <div id="file_action_panel"></div>
+</div>
+<div id='notification'></div>
+
+<div id="emptycontent" class="hidden"></div>
+
+<input type="hidden" name="dir" value="" id="dir">
+
+<table id="filestable">
+ <thead>
+ <tr>
+ <th id='headerName' class="hidden column-name">
+ <div id="headerName-container">
+ <a class="name sort columntitle" data-sort="name"><span><?php p($l->t( 'Name' )); ?></span><span class="sort-indicator"></span></a>
+ </div>
+ </th>
+ <th id="headerDate" class="hidden column-mtime">
+ <a id="modified" class="columntitle" data-sort="mtime"><span><?php p($l->t( 'Share time' )); ?></span><span class="sort-indicator"></span></a>
+ </th>
+ </tr>
+ </thead>
+ <tbody id="fileList">
+ </tbody>
+ <tfoot>
+ </tfoot>
+</table>
diff --git a/apps/files_sharing/tests/js/appSpec.js b/apps/files_sharing/tests/js/appSpec.js
new file mode 100644
index 00000000000..ad95ee53942
--- /dev/null
+++ b/apps/files_sharing/tests/js/appSpec.js
@@ -0,0 +1,143 @@
+/**
+* ownCloud
+*
+* @author Vincent Petry
+* @copyright 2014 Vincent Petry <pvince81@owncloud.com>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+describe('OCA.Sharing.App tests', function() {
+ var App = OCA.Sharing.App;
+ var fileListIn;
+ var fileListOut;
+
+ beforeEach(function() {
+ $('#testArea').append(
+ '<div id="app-navigation">' +
+ '<ul><li data-id="files"><a>Files</a></li>' +
+ '<li data-id="sharingin"><a></a></li>' +
+ '<li data-id="sharingout"><a></a></li>' +
+ '</ul></div>' +
+ '<div id="app-content">' +
+ '<div id="app-content-files" class="hidden">' +
+ '</div>' +
+ '<div id="app-content-sharingin" class="hidden">' +
+ '</div>' +
+ '<div id="app-content-sharingout" class="hidden">' +
+ '</div>' +
+ '</div>' +
+ '</div>'
+ );
+ fileListIn = App.initSharingIn($('#app-content-sharingin'));
+ fileListOut = App.initSharingOut($('#app-content-sharingout'));
+ });
+ afterEach(function() {
+ App._inFileList = null;
+ App._outFileList = null;
+ fileListIn = null;
+ fileListOut = null;
+ });
+
+ describe('initialization', function() {
+ it('inits sharing-in list on show', function() {
+ expect(fileListIn._sharedWithUser).toEqual(true);
+ });
+ it('inits sharing-out list on show', function() {
+ expect(fileListOut._sharedWithUser).toBeFalsy();
+ });
+ });
+ describe('file actions', function() {
+ it('provides default file actions', function() {
+ _.each([fileListIn, fileListOut], function(fileList) {
+ var fileActions = fileList.fileActions;
+
+ expect(fileActions.actions.all).toBeDefined();
+ expect(fileActions.actions.all.Delete).toBeDefined();
+ expect(fileActions.actions.all.Rename).toBeDefined();
+ expect(fileActions.actions.file.Download).toBeDefined();
+
+ expect(fileActions.defaults.dir).toEqual('Open');
+ });
+ });
+ it('provides custom file actions', function() {
+ var actionStub = sinon.stub();
+ // regular file action
+ OCA.Files.fileActions.register(
+ 'all',
+ 'RegularTest',
+ OC.PERMISSION_READ,
+ OC.imagePath('core', 'actions/shared'),
+ actionStub
+ );
+
+ App._inFileList = null;
+ fileListIn = App.initSharingIn($('#app-content-sharingin'));
+
+ expect(fileListIn.fileActions.actions.all.RegularTest).toBeDefined();
+ });
+ it('does not provide legacy file actions', function() {
+ var actionStub = sinon.stub();
+ // legacy file action
+ window.FileActions.register(
+ 'all',
+ 'LegacyTest',
+ OC.PERMISSION_READ,
+ OC.imagePath('core', 'actions/shared'),
+ actionStub
+ );
+
+ App._inFileList = null;
+ fileListIn = App.initSharingIn($('#app-content-sharingin'));
+
+ expect(fileListIn.fileActions.actions.all.LegacyTest).not.toBeDefined();
+ });
+ it('redirects to files app when opening a directory', function() {
+ var oldList = OCA.Files.App.fileList;
+ // dummy new list to make sure it exists
+ OCA.Files.App.fileList = new OCA.Files.FileList($('<table><thead></thead><tbody></tbody></table>'));
+
+ var setActiveViewStub = sinon.stub(OCA.Files.App, 'setActiveView');
+ // create dummy table so we can click the dom
+ var $table = '<table><thead></thead><tbody id="fileList"></tbody></table>';
+ $('#app-content-sharingin').append($table);
+
+ App._inFileList = null;
+ fileListIn = App.initSharingIn($('#app-content-sharingin'));
+
+ fileListIn.setFiles([{
+ name: 'testdir',
+ type: 'dir',
+ path: '/somewhere/inside/subdir',
+ counterParts: ['user2'],
+ shares: [{
+ ownerDisplayName: 'user2'
+ }]
+ }]);
+
+ fileListIn.findFileEl('testdir').find('td a.name').click();
+
+ expect(OCA.Files.App.fileList.getCurrentDirectory()).toEqual('/somewhere/inside/subdir/testdir');
+
+ expect(setActiveViewStub.calledOnce).toEqual(true);
+ expect(setActiveViewStub.calledWith('files')).toEqual(true);
+
+ setActiveViewStub.restore();
+
+ // restore old list
+ OCA.Files.App.fileList = oldList;
+ });
+ });
+});
diff --git a/apps/files_sharing/tests/js/sharedfilelistSpec.js b/apps/files_sharing/tests/js/sharedfilelistSpec.js
new file mode 100644
index 00000000000..7aec8322a44
--- /dev/null
+++ b/apps/files_sharing/tests/js/sharedfilelistSpec.js
@@ -0,0 +1,412 @@
+/*
+ * 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.
+ *
+ */
+
+describe('OCA.Sharing.FileList tests', function() {
+ var testFiles, alertStub, notificationStub, fileList;
+
+ beforeEach(function() {
+ alertStub = sinon.stub(OC.dialogs, 'alert');
+ notificationStub = sinon.stub(OC.Notification, 'show');
+
+ // init parameters and test table elements
+ $('#testArea').append(
+ '<div id="app-content-container">' +
+ // init horrible parameters
+ '<input type="hidden" id="dir" value="/"></input>' +
+ '<input type="hidden" id="permissions" value="31"></input>' +
+ // dummy controls
+ '<div id="controls">' +
+ ' <div class="actions creatable"></div>' +
+ ' <div class="notCreatable"></div>' +
+ '</div>' +
+ // dummy table
+ // TODO: at some point this will be rendered by the fileList class itself!
+ '<table id="filestable">' +
+ '<thead><tr>' +
+ '<th id="headerName" class="hidden column-name">' +
+ '<input type="checkbox" id="select_all_files" class="select-all">' +
+ '<a class="name columntitle" data-sort="name"><span>Name</span><span class="sort-indicator"></span></a>' +
+ '<span class="selectedActions hidden">' +
+ '</th>' +
+ '<th class="hidden column-mtime">' +
+ '<a class="columntitle" data-sort="mtime"><span class="sort-indicator"></span></a>' +
+ '</th>' +
+ '</tr></thead>' +
+ '<tbody id="fileList"></tbody>' +
+ '<tfoot></tfoot>' +
+ '</table>' +
+ '<div id="emptycontent">Empty content message</div>' +
+ '</div>'
+ );
+ });
+ afterEach(function() {
+ testFiles = undefined;
+ fileList = undefined;
+
+ notificationStub.restore();
+ alertStub.restore();
+ });
+
+ describe('loading file list for incoming shares', function() {
+ var ocsResponse;
+
+ beforeEach(function() {
+ fileList = new OCA.Sharing.FileList(
+ $('#app-content-container'), {
+ sharedWithUser: true
+ }
+ );
+
+ fileList.reload();
+
+ /* jshint camelcase: false */
+ ocsResponse = {
+ ocs: {
+ meta: {
+ status: 'ok',
+ statuscode: 100,
+ message: null
+ },
+ data: [{
+ id: 7,
+ item_type: 'file',
+ item_source: 49,
+ item_target: '/49',
+ file_source: 49,
+ file_target: '/local path/local name.txt',
+ path: 'files/something shared.txt',
+ permissions: 31,
+ stime: 11111,
+ share_type: OC.Share.SHARE_TYPE_USER,
+ share_with: 'user1',
+ share_with_displayname: 'User One',
+ mimetype: 'text/plain',
+ uid_owner: 'user2',
+ displayname_owner: 'User Two'
+ }]
+ }
+ };
+ });
+ it('render file shares', function() {
+ var request;
+
+ expect(fakeServer.requests.length).toEqual(1);
+ request = fakeServer.requests[0];
+ expect(request.url).toEqual(
+ OC.linkToOCS('apps/files_sharing/api/v1') +
+ 'shares?format=json&shared_with_me=true'
+ );
+
+ fakeServer.requests[0].respond(
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify(ocsResponse)
+ );
+
+ var $rows = fileList.$el.find('tbody tr');
+ var $tr = $rows.eq(0);
+ expect($rows.length).toEqual(1);
+ expect($tr.attr('data-id')).toEqual('49');
+ expect($tr.attr('data-type')).toEqual('file');
+ expect($tr.attr('data-file')).toEqual('local name.txt');
+ expect($tr.attr('data-path')).toEqual('/local path');
+ expect($tr.attr('data-size')).not.toBeDefined();
+ expect($tr.attr('data-permissions')).toEqual('31'); // read and delete
+ expect($tr.attr('data-mime')).toEqual('text/plain');
+ expect($tr.attr('data-mtime')).toEqual('11111000');
+ expect($tr.attr('data-share-owner')).toEqual('User Two');
+ expect($tr.attr('data-share-id')).toEqual('7');
+ expect($tr.find('a.name').attr('href')).toEqual(
+ OC.webroot +
+ '/index.php/apps/files/ajax/download.php' +
+ '?dir=%2Flocal%20path&files=local%20name.txt'
+ );
+ expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
+ });
+ it('render folder shares', function() {
+ /* jshint camelcase: false */
+ var request;
+ ocsResponse.ocs.data[0] = _.extend(ocsResponse.ocs.data[0], {
+ item_type: 'folder',
+ file_target: '/local path/local name',
+ path: 'files/something shared',
+ });
+
+ expect(fakeServer.requests.length).toEqual(1);
+ request = fakeServer.requests[0];
+ expect(request.url).toEqual(
+ OC.linkToOCS('apps/files_sharing/api/v1') +
+ 'shares?format=json&shared_with_me=true'
+ );
+
+ fakeServer.requests[0].respond(
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify(ocsResponse)
+ );
+
+ var $rows = fileList.$el.find('tbody tr');
+ var $tr = $rows.eq(0);
+ expect($rows.length).toEqual(1);
+ expect($tr.attr('data-id')).toEqual('49');
+ expect($tr.attr('data-type')).toEqual('dir');
+ expect($tr.attr('data-file')).toEqual('local name');
+ expect($tr.attr('data-path')).toEqual('/local path');
+ expect($tr.attr('data-size')).not.toBeDefined();
+ expect($tr.attr('data-permissions')).toEqual('31'); // read and delete
+ expect($tr.attr('data-mime')).toEqual('httpd/unix-directory');
+ expect($tr.attr('data-mtime')).toEqual('11111000');
+ expect($tr.attr('data-share-owner')).toEqual('User Two');
+ expect($tr.attr('data-share-id')).toEqual('7');
+ expect($tr.find('a.name').attr('href')).toEqual(
+ OC.webroot +
+ '/index.php/apps/files' +
+ '?dir=/local%20path/local%20name'
+ );
+ expect($tr.find('.nametext').text().trim()).toEqual('local name');
+ });
+ });
+ describe('loading file list for outgoing shares', function() {
+ var ocsResponse;
+
+ beforeEach(function() {
+ fileList = new OCA.Sharing.FileList(
+ $('#app-content-container'), {
+ sharedWithUser: false
+ }
+ );
+
+ fileList.reload();
+
+ /* jshint camelcase: false */
+ ocsResponse = {
+ ocs: {
+ meta: {
+ status: 'ok',
+ statuscode: 100,
+ message: null
+ },
+ data: [{
+ id: 7,
+ item_type: 'file',
+ item_source: 49,
+ file_source: 49,
+ path: '/local path/local name.txt',
+ permissions: 27,
+ stime: 11111,
+ share_type: OC.Share.SHARE_TYPE_USER,
+ share_with: 'user2',
+ share_with_displayname: 'User Two',
+ mimetype: 'text/plain',
+ uid_owner: 'user1',
+ displayname_owner: 'User One'
+ }]
+ }
+ };
+ });
+ it('render file shares', function() {
+ var request;
+
+ expect(fakeServer.requests.length).toEqual(1);
+ request = fakeServer.requests[0];
+ expect(request.url).toEqual(
+ OC.linkToOCS('apps/files_sharing/api/v1') +
+ 'shares?format=json&shared_with_me=false'
+ );
+
+ fakeServer.requests[0].respond(
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify(ocsResponse)
+ );
+
+ var $rows = fileList.$el.find('tbody tr');
+ var $tr = $rows.eq(0);
+ expect($rows.length).toEqual(1);
+ expect($tr.attr('data-id')).toEqual('49');
+ expect($tr.attr('data-type')).toEqual('file');
+ expect($tr.attr('data-file')).toEqual('local name.txt');
+ expect($tr.attr('data-path')).toEqual('/local path');
+ expect($tr.attr('data-size')).not.toBeDefined();
+ expect($tr.attr('data-permissions')).toEqual('31'); // read and delete
+ expect($tr.attr('data-mime')).toEqual('text/plain');
+ expect($tr.attr('data-mtime')).toEqual('11111000');
+ expect($tr.attr('data-share-owner')).not.toBeDefined();
+ expect($tr.attr('data-share-id')).toEqual('7');
+ expect($tr.find('a.name').attr('href')).toEqual(
+ OC.webroot +
+ '/index.php/apps/files/ajax/download.php' +
+ '?dir=%2Flocal%20path&files=local%20name.txt'
+ );
+ expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
+ });
+ it('render folder shares', function() {
+ var request;
+ /* jshint camelcase: false */
+ ocsResponse.ocs.data[0] = _.extend(ocsResponse.ocs.data[0], {
+ item_type: 'folder',
+ path: '/local path/local name',
+ });
+
+ expect(fakeServer.requests.length).toEqual(1);
+ request = fakeServer.requests[0];
+ expect(request.url).toEqual(
+ OC.linkToOCS('apps/files_sharing/api/v1') +
+ 'shares?format=json&shared_with_me=false'
+ );
+
+ fakeServer.requests[0].respond(
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify(ocsResponse)
+ );
+
+ var $rows = fileList.$el.find('tbody tr');
+ var $tr = $rows.eq(0);
+ expect($rows.length).toEqual(1);
+ expect($tr.attr('data-id')).toEqual('49');
+ expect($tr.attr('data-type')).toEqual('dir');
+ expect($tr.attr('data-file')).toEqual('local name');
+ expect($tr.attr('data-path')).toEqual('/local path');
+ expect($tr.attr('data-size')).not.toBeDefined();
+ expect($tr.attr('data-permissions')).toEqual('31'); // read and delete
+ expect($tr.attr('data-mime')).toEqual('httpd/unix-directory');
+ expect($tr.attr('data-mtime')).toEqual('11111000');
+ expect($tr.attr('data-share-owner')).not.toBeDefined();
+ expect($tr.attr('data-share-id')).toEqual('7');
+ expect($tr.find('a.name').attr('href')).toEqual(
+ OC.webroot +
+ '/index.php/apps/files' +
+ '?dir=/local%20path/local%20name'
+ );
+ expect($tr.find('.nametext').text().trim()).toEqual('local name');
+ });
+ it('render link shares', function() {
+ /* jshint camelcase: false */
+ var request;
+ ocsResponse.ocs.data[0] = {
+ id: 7,
+ item_type: 'file',
+ item_source: 49,
+ file_source: 49,
+ path: '/local path/local name.txt',
+ permissions: 1,
+ stime: 11111,
+ share_type: OC.Share.SHARE_TYPE_LINK,
+ share_with: null,
+ token: 'abc',
+ mimetype: 'text/plain',
+ uid_owner: 'user1',
+ displayname_owner: 'User One'
+ };
+ expect(fakeServer.requests.length).toEqual(1);
+ request = fakeServer.requests[0];
+ expect(request.url).toEqual(
+ OC.linkToOCS('apps/files_sharing/api/v1') +
+ 'shares?format=json&shared_with_me=false'
+ );
+
+ fakeServer.requests[0].respond(
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify(ocsResponse)
+ );
+
+ var $rows = fileList.$el.find('tbody tr');
+ var $tr = $rows.eq(0);
+ expect($rows.length).toEqual(1);
+ expect($tr.attr('data-id')).toEqual('49');
+ expect($tr.attr('data-type')).toEqual('file');
+ expect($tr.attr('data-file')).toEqual('local name.txt');
+ expect($tr.attr('data-path')).toEqual('/local path');
+ expect($tr.attr('data-size')).not.toBeDefined();
+ expect($tr.attr('data-permissions')).toEqual('31'); // read and delete
+ expect($tr.attr('data-mime')).toEqual('text/plain');
+ expect($tr.attr('data-mtime')).toEqual('11111000');
+ expect($tr.attr('data-share-owner')).not.toBeDefined();
+ expect($tr.attr('data-share-id')).toEqual('7');
+ expect($tr.find('a.name').attr('href')).toEqual(
+ OC.webroot +
+ '/index.php/apps/files/ajax/download.php' +
+ '?dir=%2Flocal%20path&files=local%20name.txt');
+
+ expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
+ });
+ it('groups link shares with regular shares', function() {
+ /* jshint camelcase: false */
+ var request;
+ // link share
+ ocsResponse.ocs.data.push({
+ id: 8,
+ item_type: 'file',
+ item_source: 49,
+ file_source: 49,
+ path: '/local path/local name.txt',
+ permissions: 1,
+ stime: 11111,
+ share_type: OC.Share.SHARE_TYPE_LINK,
+ share_with: null,
+ token: 'abc',
+ mimetype: 'text/plain',
+ uid_owner: 'user1',
+ displayname_owner: 'User One'
+ });
+ // another share of the same file
+ ocsResponse.ocs.data.push({
+ id: 9,
+ item_type: 'file',
+ item_source: 49,
+ file_source: 49,
+ path: '/local path/local name.txt',
+ permissions: 27,
+ stime: 22222,
+ share_type: OC.Share.SHARE_TYPE_USER,
+ share_with: 'user3',
+ share_with_displayname: 'User Three',
+ mimetype: 'text/plain',
+ uid_owner: 'user1',
+ displayname_owner: 'User One'
+ });
+ expect(fakeServer.requests.length).toEqual(1);
+ request = fakeServer.requests[0];
+ expect(request.url).toEqual(
+ OC.linkToOCS('apps/files_sharing/api/v1') +
+ 'shares?format=json&shared_with_me=false'
+ );
+
+ fakeServer.requests[0].respond(
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify(ocsResponse)
+ );
+
+ var $rows = fileList.$el.find('tbody tr');
+ var $tr = $rows.eq(0);
+ expect($rows.length).toEqual(1);
+ expect($tr.attr('data-id')).toEqual('49');
+ expect($tr.attr('data-type')).toEqual('file');
+ expect($tr.attr('data-file')).toEqual('local name.txt');
+ expect($tr.attr('data-path')).toEqual('/local path');
+ expect($tr.attr('data-size')).not.toBeDefined();
+ expect($tr.attr('data-permissions')).toEqual('31'); // read and delete
+ expect($tr.attr('data-mime')).toEqual('text/plain');
+ // always use the most recent stime
+ expect($tr.attr('data-mtime')).toEqual('22222000');
+ expect($tr.attr('data-share-owner')).not.toBeDefined();
+ expect($tr.attr('data-share-id')).toEqual('7,8,9');
+ expect($tr.find('a.name').attr('href')).toEqual(
+ OC.webroot +
+ '/index.php/apps/files/ajax/download.php' +
+ '?dir=%2Flocal%20path&files=local%20name.txt'
+ );
+ expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
+ });
+ });
+});
diff --git a/apps/files_trashbin/appinfo/app.php b/apps/files_trashbin/appinfo/app.php
index b8900ee0de3..383115b8e63 100644
--- a/apps/files_trashbin/appinfo/app.php
+++ b/apps/files_trashbin/appinfo/app.php
@@ -9,7 +9,7 @@ array(
"id" => 'trashbin',
"appname" => 'files_trashbin',
"script" => 'list.php',
- "order" => 1,
+ "order" => 50,
"name" => $l->t('Deleted files')
)
);
diff --git a/apps/files_trashbin/js/app.js b/apps/files_trashbin/js/app.js
index aa499ae1791..c59a132b8c4 100644
--- a/apps/files_trashbin/js/app.js
+++ b/apps/files_trashbin/js/app.js
@@ -19,27 +19,26 @@ OCA.Trashbin.App = {
this._initialized = true;
this.fileList = new OCA.Trashbin.FileList(
$('#app-content-trashbin'), {
- scrollContainer: $('#app-content')
+ scrollContainer: $('#app-content'),
+ fileActions: this._createFileActions()
}
);
- this.registerFileActions(this.fileList);
},
- registerFileActions: function(fileList) {
- var self = this;
- var fileActions = _.extend({}, OCA.Files.FileActions);
- fileActions.clear();
- fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename) {
- var dir = fileList.getCurrentDirectory();
+ _createFileActions: function() {
+ var fileActions = new OCA.Files.FileActions();
+ fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) {
+ var dir = context.fileList.getCurrentDirectory();
if (dir !== '/') {
dir = dir + '/';
}
- fileList.changeDirectory(dir + filename);
+ context.fileList.changeDirectory(dir + filename);
});
fileActions.setDefault('dir', 'Open');
- fileActions.register('all', 'Restore', OC.PERMISSION_READ, OC.imagePath('core', 'actions/history'), function(filename) {
+ fileActions.register('all', 'Restore', OC.PERMISSION_READ, OC.imagePath('core', 'actions/history'), function(filename, context) {
+ var fileList = context.fileList;
var tr = fileList.findFileEl(filename);
var deleteAction = tr.children("td.date").children(".action.delete");
deleteAction.removeClass('delete-icon').addClass('progress-icon');
@@ -54,7 +53,8 @@ OCA.Trashbin.App = {
fileActions.register('all', 'Delete', OC.PERMISSION_READ, function() {
return OC.imagePath('core', 'actions/delete');
- }, function(filename) {
+ }, function(filename, context) {
+ var fileList = context.fileList;
$('.tipsy').remove();
var tr = fileList.findFileEl(filename);
var deleteAction = tr.children("td.date").children(".action.delete");
@@ -67,7 +67,7 @@ OCA.Trashbin.App = {
_.bind(fileList._removeCallback, fileList)
);
});
- fileList.setFileActions(fileActions);
+ return fileActions;
}
};
diff --git a/apps/files_trashbin/js/filelist.js b/apps/files_trashbin/js/filelist.js
index 205f879f335..826c1bd64d5 100644
--- a/apps/files_trashbin/js/filelist.js
+++ b/apps/files_trashbin/js/filelist.js
@@ -26,8 +26,8 @@
return name;
}
- var FileList = function($el) {
- this.initialize($el);
+ var FileList = function($el, options) {
+ this.initialize($el, options);
};
FileList.prototype = _.extend({}, OCA.Files.FileList.prototype, {
id: 'trashbin',
diff --git a/apps/files_trashbin/tests/js/filelistSpec.js b/apps/files_trashbin/tests/js/filelistSpec.js
index d41c24c3cc9..11eeff68df8 100644
--- a/apps/files_trashbin/tests/js/filelistSpec.js
+++ b/apps/files_trashbin/tests/js/filelistSpec.js
@@ -21,7 +21,6 @@
describe('OCA.Trashbin.FileList tests', function() {
var testFiles, alertStub, notificationStub, fileList;
- var FileActions = OCA.Files.FileActions;
beforeEach(function() {
alertStub = sinon.stub(OC.dialogs, 'alert');
@@ -87,14 +86,18 @@ describe('OCA.Trashbin.FileList tests', function() {
etag: '456'
}];
- fileList = new OCA.Trashbin.FileList($('#app-content-trashbin'));
- OCA.Trashbin.App.registerFileActions(fileList);
+ // register file actions like the trashbin App does
+ var fileActions = OCA.Trashbin.App._createFileActions(fileList);
+ fileList = new OCA.Trashbin.FileList(
+ $('#app-content-trashbin'), {
+ fileActions: fileActions
+ }
+ );
});
afterEach(function() {
testFiles = undefined;
fileList = undefined;
- FileActions.clear();
$('#dir').remove();
notificationStub.restore();
alertStub.restore();
diff --git a/apps/files_versions/js/versions.js b/apps/files_versions/js/versions.js
index b452bc25b13..942a1a929f7 100644
--- a/apps/files_versions/js/versions.js
+++ b/apps/files_versions/js/versions.js
@@ -1,3 +1,14 @@
+/*
+ * Copyright (c) 2014
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+/* global scanFiles, escapeHTML, formatDate */
$(document).ready(function(){
if ($('#isPublic').val()){
@@ -7,21 +18,20 @@ $(document).ready(function(){
return;
}
- if (typeof FileActions !== 'undefined') {
+ if (OCA.Files) {
// Add versions button to 'files/index.php'
- FileActions.register(
- 'file'
- , 'Versions'
- , OC.PERMISSION_UPDATE
- , function() {
+ OCA.Files.fileActions.register(
+ 'file',
+ 'Versions',
+ OC.PERMISSION_UPDATE,
+ function() {
// Specify icon for hitory button
return OC.imagePath('core','actions/history');
- }
- ,function(filename){
+ }, function(filename, context){
// Action to perform when clicked
if (scanFiles.scanning){return;}//workaround to prevent additional http request block scanning feedback
- var file = $('#dir').val().replace(/(?!<=\/)$|\/$/, '/' + filename);
+ var file = context.dir.replace(/(?!<=\/)$|\/$/, '/' + filename);
var createDropDown = true;
// Check if drop down is already visible for a different file
if (($('#dropdown').length > 0) ) {
@@ -33,10 +43,9 @@ $(document).ready(function(){
}
if(createDropDown === true) {
- createVersionsDropdown(filename, file);
+ createVersionsDropdown(filename, file, context.fileList);
}
- }
- , t('files_versions', 'Versions')
+ }, t('files_versions', 'Versions')
);
}
@@ -75,7 +84,7 @@ function goToVersionPage(url){
window.location.assign(url);
}
-function createVersionsDropdown(filename, files) {
+function createVersionsDropdown(filename, files, fileList) {
var start = 0;
var fileEl;
@@ -88,7 +97,7 @@ function createVersionsDropdown(filename, files) {
html += '<input type="button" value="'+ t('files_versions', 'More versions...') + '" name="show-more-versions" id="show-more-versions" style="display: none;" />';
if (filename) {
- fileEl = FileList.findFileEl(filename);
+ fileEl = fileList.findFileEl(filename);
fileEl.addClass('mouseOver');
$(html).appendTo(fileEl.find('td.filename'));
} else {