summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/files/js/app.js8
-rw-r--r--apps/files/js/fileactions.js15
-rw-r--r--apps/files/js/filelist.js19
-rw-r--r--apps/files/tests/js/fileactionsSpec.js29
-rw-r--r--apps/files/tests/js/filelistSpec.js2
-rw-r--r--apps/files_sharing/js/app.js29
-rw-r--r--apps/files_sharing/js/public.js5
-rw-r--r--apps/files_sharing/js/share.js9
-rw-r--r--apps/files_sharing/js/sharedfilelist.js56
-rw-r--r--apps/files_sharing/templates/list.php4
-rw-r--r--apps/files_sharing/tests/js/appSpec.js140
-rw-r--r--apps/files_sharing/tests/js/sharedfilelistSpec.js417
-rw-r--r--core/js/share.js45
-rw-r--r--tests/karma.config.js43
14 files changed, 751 insertions, 70 deletions
diff --git a/apps/files/js/app.js b/apps/files/js/app.js
index 6ccf5135000..71802948a5c 100644
--- a/apps/files/js/app.js
+++ b/apps/files/js/app.js
@@ -73,6 +73,14 @@
},
/**
+ * 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() {
diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js
index 8cee037e294..3df62f37518 100644
--- a/apps/files/js/fileactions.js
+++ b/apps/files/js/fileactions.js
@@ -232,7 +232,7 @@
}
if (triggerEvent){
- fileList.$fileList.trigger(jQuery.Event("fileActionsReady"));
+ fileList.$fileList.trigger(jQuery.Event("fileActionsReady", {fileList: fileList}));
}
},
getCurrentFile: function () {
@@ -252,8 +252,6 @@
* Register the actions that are used by default for the files app.
*/
registerDefaultActions: function() {
- // TODO: try to find a way to not make it depend on fileList,
- // maybe get a handler or listener to trigger events on
this.register('all', 'Delete', OC.PERMISSION_DELETE, function () {
return OC.imagePath('core', 'actions/delete');
}, function (filename, context) {
@@ -287,7 +285,8 @@
this.register(downloadScope, 'Download', OC.PERMISSION_READ, function () {
return OC.imagePath('core', 'actions/download');
}, function (filename, context) {
- var url = context.fileList.getDownloadUrl(filename, context.fileList.getCurrentDirectory());
+ var dir = context.dir || context.fileList.getCurrentDirectory();
+ var url = context.fileList.getDownloadUrl(filename, dir);
if (url) {
OC.redirect(url);
}
@@ -309,11 +308,13 @@
// 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');
- OCA.Files.FileActions.prototype.register.call(window.FileActions, 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');
+ 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 52d4c8ba3fe..68b22207144 100644
--- a/apps/files/js/filelist.js
+++ b/apps/files/js/filelist.js
@@ -508,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);
@@ -530,7 +530,7 @@
type = fileData.type || 'file',
mtime = parseInt(fileData.mtime, 10) || new Date().getTime(),
mime = fileData.mimetype,
- path = fileData.path || this.getCurrentDirectory(),
+ path = fileData.path,
linkUrl;
options = options || {};
@@ -550,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');
@@ -1224,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/fileactionsSpec.js b/apps/files/tests/js/fileactionsSpec.js
index fa634da08a2..490594a1773 100644
--- a/apps/files/tests/js/fileactionsSpec.js
+++ b/apps/files/tests/js/fileactionsSpec.js
@@ -104,7 +104,34 @@ describe('OCA.Files.FileActions tests', function() {
$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=%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=%2Fanotherpath%2Fthere&files=testName.txt'
+ );
redirectStub.restore();
});
it('deletes file when clicking delete', function() {
diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js
index a197fd5722c..3e9950dfe19 100644
--- a/apps/files/tests/js/filelistSpec.js
+++ b/apps/files/tests/js/filelistSpec.js
@@ -483,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
diff --git a/apps/files_sharing/js/app.js b/apps/files_sharing/js/app.js
index 7a71684f1a1..3764328a5d0 100644
--- a/apps/files_sharing/js/app.js
+++ b/apps/files_sharing/js/app.js
@@ -16,7 +16,7 @@ OCA.Sharing.App = {
initSharingIn: function($el) {
if (this._inFileList) {
- return;
+ return this._inFileList;
}
this._inFileList = new OCA.Sharing.FileList(
@@ -31,11 +31,12 @@ OCA.Sharing.App = {
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;
+ return this._outFileList;
}
this._outFileList = new OCA.Sharing.FileList(
$el,
@@ -49,6 +50,19 @@ OCA.Sharing.App = {
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() {
@@ -56,6 +70,7 @@ OCA.Sharing.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
@@ -75,11 +90,17 @@ OCA.Sharing.App = {
};
$(document).ready(function() {
- $('#app-content-sharingin').one('show', function(e) {
+ $('#app-content-sharingin').on('show', function(e) {
OCA.Sharing.App.initSharingIn($(e.target));
});
- $('#app-content-sharingout').one('show', function(e) {
+ $('#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 446f3f2442b..27e8d361ff9 100644
--- a/apps/files_sharing/js/public.js
+++ b/apps/files_sharing/js/public.js
@@ -166,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 1fcb1f088bf..5a42604c866 100644
--- a/apps/files_sharing/js/share.js
+++ b/apps/files_sharing/js/share.js
@@ -28,10 +28,11 @@ $(document).ready(function() {
}
// use delegate to catch the case with multiple file lists
- $('#content').delegate('#fileList', 'fileActionsReady',function(){
+ $('#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);
@@ -59,16 +60,16 @@ $(document).ready(function() {
return $result;
});
}
- })
+ });
if (!OCA.Sharing.sharesLoaded){
- OC.Share.loadIcons('file', $fileList);
+ OC.Share.loadIcons('file', fileList);
// assume that we got all shares, so switching directories
// will not invalidate that list
OCA.Sharing.sharesLoaded = true;
}
else{
- OC.Share.updateIcons('file', $fileList);
+ OC.Share.updateIcons('file', fileList);
}
});
diff --git a/apps/files_sharing/js/sharedfilelist.js b/apps/files_sharing/js/sharedfilelist.js
index 4508de47dcc..b941722d0cf 100644
--- a/apps/files_sharing/js/sharedfilelist.js
+++ b/apps/files_sharing/js/sharedfilelist.js
@@ -43,10 +43,9 @@
var $tr = OCA.Files.FileList.prototype._createRow.apply(this, arguments);
$tr.find('.filesize').remove();
var $sharedWith = $('<td class="sharedWith"></td>')
- .text(fileData.shareColumnInfo);
+ .text(fileData.counterParts.join(', '));
$tr.find('td.date').before($sharedWith);
$tr.find('td.filename input:checkbox').remove();
- $tr.attr('data-path', fileData.path);
$tr.attr('data-share-id', _.pluck(fileData.shares, 'id').join(','));
return $tr;
},
@@ -74,7 +73,12 @@
},
getDirectoryPermissions: function() {
- return OC.PERMISSION_READ;
+ 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() {
@@ -128,16 +132,16 @@
var self = this;
// OCS API uses non-camelcased names
var files = _.chain(data)
- // cOnvert share data to file data
+ // convert share data to file data
.map(function(share) {
/* jshint camelcase: false */
var file = {
id: share.file_source,
- mtime: share.stime * 1000,
mimetype: share.mimetype
};
if (share.item_type === 'folder') {
file.type = 'dir';
+ file.mimetype = 'httpd/unix-directory';
}
else {
file.type = 'file';
@@ -150,7 +154,8 @@
file.share = {
id: share.id,
type: share.share_type,
- target: share.share_with
+ target: share.share_with,
+ stime: share.stime * 1000,
};
if (self._sharedWithUser) {
file.share.ownerDisplayName = share.displayname_owner;
@@ -173,28 +178,49 @@
// 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);
}
- // format the share column info output string
- if (!data.shareColumnInfo) {
- data.shareColumnInfo = '';
- }
- else {
- data.shareColumnInfo += ', ';
+
+ 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++;
}
- // TODO. more accurate detection of name based on type
- // TODO: maybe better formatting, like "link + 3 users" when more than 1 user
- data.shareColumnInfo += (file.share.ownerDisplayName || file.share.targetDisplayName || 'link');
+
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
diff --git a/apps/files_sharing/templates/list.php b/apps/files_sharing/templates/list.php
index c688dcf8764..b07222cfe28 100644
--- a/apps/files_sharing/templates/list.php
+++ b/apps/files_sharing/templates/list.php
@@ -16,11 +16,11 @@
<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="headerSharedWith" class="hidden column-mtime">
+ <th id="headerSharedWith" class="hidden column-counterpart">
<a id="sharedwith" class="columntitle" data-sort="shareWith"><span><?php p($l->t( 'Shared with' )); ?></span><span class="sort-indicator"></span></a>
</th>
<th id="headerDate" class="hidden column-mtime">
- <a id="modified" class="columntitle" data-sort="mtime"><span><?php p($l->t( 'Shared since' )); ?></span><span class="sort-indicator"></span></a>
+ <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>
diff --git a/apps/files_sharing/tests/js/appSpec.js b/apps/files_sharing/tests/js/appSpec.js
new file mode 100644
index 00000000000..09c48a6305c
--- /dev/null
+++ b/apps/files_sharing/tests/js/appSpec.js
@@ -0,0 +1,140 @@
+/**
+* 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']
+ }]);
+
+ 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..ddcd746afe0
--- /dev/null
+++ b/apps/files_sharing/tests/js/sharedfilelistSpec.js
@@ -0,0 +1,417 @@
+/*
+ * 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-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('td.sharedWith').text()).toEqual('User Two');
+
+ 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-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('td.sharedWith').text()).toEqual('User Two');
+
+ 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-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('td.sharedWith').text()).toEqual('User Two');
+
+ 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-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('td.sharedWith').text()).toEqual('User Two');
+
+ 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-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('td.sharedWith').text()).toEqual('link');
+
+ 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-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('td.sharedWith').text()).toEqual('link, User Three, User Two');
+
+ expect($tr.find('.nametext').text().trim()).toEqual('local name.txt');
+ });
+ });
+});
diff --git a/core/js/share.js b/core/js/share.js
index 279b1d11663..894f0d488f4 100644
--- a/core/js/share.js
+++ b/core/js/share.js
@@ -32,27 +32,26 @@ OC.Share={
* (not reloaded from server)
*
* @param itemType item type
- * @param fileList file list instance or file list jQuery element,
+ * @param fileList file list instance
* defaults to OCA.Files.App.fileList
*/
updateIcons:function(itemType, fileList){
var item;
- var $fileList = (fileList || OCA.Files.App.fileList);
- // in case the jQuery element was passed instead
- if ($fileList.$fileList) {
- $fileList = $fileList.$fileList;
- }
+ fileList = fileList || OCA.Files.App.fileList;
+ var $fileList = fileList.$fileList;
+ var currentDir = fileList.getCurrentDirectory();
for (item in OC.Share.statuses){
+ var image;
var data = OC.Share.statuses[item];
- var hasLink = data['link'];
+ var hasLink = data.link;
// Links override shared in terms of icon display
if (hasLink) {
- var image = OC.imagePath('core', 'actions/public');
+ image = OC.imagePath('core', 'actions/public');
} else {
- var image = OC.imagePath('core', 'actions/shared');
+ image = OC.imagePath('core', 'actions/shared');
}
- if (itemType != 'file' && itemType != 'folder') {
+ if (itemType !== 'file' && itemType !== 'folder') {
$fileList.find('a.share[data-item="'+item+'"]').css('background', 'url('+image+') no-repeat center');
} else {
var file = $fileList.find('tr[data-id="'+item+'"]');
@@ -62,17 +61,17 @@ OC.Share={
action.addClass('permanent');
action.html(' <span>'+t('core', 'Shared')+'</span>').prepend(img);
} else {
- var dir = $('#dir').val();
+ var dir = currentDir;
if (dir.length > 1) {
var last = '';
var path = dir;
// Search for possible parent folders that are shared
while (path != last) {
- if (path == data['path'] && !data['link']) {
+ if (path === data.path && !data.link) {
var actions = $fileList.find('.fileactions .action[data-action="Share"]');
$.each(actions, function(index, action) {
var img = $(action).find('img');
- if (img.attr('src') != OC.imagePath('core', 'actions/public')) {
+ if (img.attr('src') !== OC.imagePath('core', 'actions/public')) {
img.attr('src', image);
$(action).addClass('permanent');
$(action).html(' <span>'+t('core', 'Shared')+'</span>').prepend(img);
@@ -112,14 +111,18 @@ OC.Share={
var file = $('tr').filterAttr('data-id', String(itemSource));
if (file.length > 0) {
var action = $(file).find('.fileactions .action').filterAttr('data-action', 'Share');
- 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);
- }
+ // 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) {
diff --git a/tests/karma.config.js b/tests/karma.config.js
index 08b49d854e0..846e8f7be91 100644
--- a/tests/karma.config.js
+++ b/tests/karma.config.js
@@ -43,7 +43,19 @@ module.exports = function(config) {
return apps;
*/
// other apps tests don't run yet... needs further research / clean up
- return ['files', 'files_trashbin'];
+ return [
+ 'files',
+ 'files_trashbin',
+ {
+ name: 'files_sharing',
+ srcFiles: [
+ // only test these files, others are not ready and mess
+ // up with the global namespace/classes/state
+ 'apps/files_sharing/js/app.js',
+ 'apps/files_sharing/js/sharedfilelist.js'
+ ],
+ testFiles: ['apps/files_sharing/tests/js/*.js']
+ }];
}
// respect NOCOVERAGE env variable
@@ -110,15 +122,30 @@ module.exports = function(config) {
files.push(corePath + 'tests/specs/*.js');
}
- for ( var i = 0; i < appsToTest.length; i++ ) {
- // add app JS
- var srcFile = 'apps/' + appsToTest[i] + '/js/*.js';
- files.push(srcFile);
+ function addApp(app) {
+ // if only a string was specified, expand to structure
+ if (typeof(app) === 'string') {
+ app = {
+ srcFiles: 'apps/' + app + '/js/*.js',
+ testFiles: 'apps/' + app + '/tests/js/*.js'
+ };
+ }
+
+ // add source files/patterns
+ files = files.concat(app.srcFiles || []);
+ // add test files/patterns
+ files = files.concat(app.testFiles || []);
if (enableCoverage) {
- preprocessors[srcFile] = 'coverage';
+ // add coverage entry for each file/pattern
+ for (var i = 0; i < app.srcFiles.length; i++) {
+ preprocessors[app.srcFiles[i]] = 'coverage';
+ }
}
- // add test specs
- files.push('apps/' + appsToTest[i] + '/tests/js/*.js');
+ }
+
+ // add source files for apps to test
+ for ( var i = 0; i < appsToTest.length; i++ ) {
+ addApp(appsToTest[i]);
}
// serve images to avoid warnings