Merge pull request #8417 from owncloud/share-overview
Sharing overview page
This commit is contained in:
commit
517501ffbf
27 changed files with 1496 additions and 164 deletions
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
@ -57,6 +64,22 @@
|
|||
return this.navigation.getActiveContainer();
|
||||
},
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
var file = self.getCurrentFile();
|
||||
// also set on global object for legacy apps
|
||||
window.FileActions.currentFile = self.currentFile;
|
||||
|
||||
event.data.actionFunc(file);
|
||||
var file = self.getCurrentFile();
|
||||
var $tr = $(this).closest('tr');
|
||||
|
||||
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;
|
||||
|
||||
// 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);
|
||||
};
|
||||
})();
|
||||
|
||||
// for backward compatibility
|
||||
window.FileActions = OCA.Files.FileActions;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
@ -783,13 +808,6 @@
|
|||
return OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/');
|
||||
},
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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');
|
||||
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() {
|
||||
|
@ -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');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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')
|
||||
)
|
||||
);
|
||||
|
|
3
apps/files_sharing/css/sharedfilelist.css
Normal file
3
apps/files_sharing/css/sharedfilelist.css
Normal file
|
@ -0,0 +1,3 @@
|
|||
#filestable.shareList .summary .filesize {
|
||||
display: none;
|
||||
}
|
106
apps/files_sharing/js/app.js
Normal file
106
apps/files_sharing/js/app.js
Normal file
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
235
apps/files_sharing/js/sharedfilelist.js
Normal file
235
apps/files_sharing/js/sharedfilelist.js
Normal file
|
@ -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;
|
||||
})();
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -195,6 +206,27 @@ class Api {
|
|||
return new \OC_OCS_Result($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
|
11
apps/files_sharing/list.php
Normal file
11
apps/files_sharing/list.php
Normal file
|
@ -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();
|
28
apps/files_sharing/templates/list.php
Normal file
28
apps/files_sharing/templates/list.php
Normal file
|
@ -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>
|
143
apps/files_sharing/tests/js/appSpec.js
Normal file
143
apps/files_sharing/tests/js/appSpec.js
Normal file
|
@ -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;
|
||||
});
|
||||
});
|
||||
});
|
412
apps/files_sharing/tests/js/sharedfilelistSpec.js
Normal file
412
apps/files_sharing/tests/js/sharedfilelistSpec.js
Normal file
|
@ -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');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -9,7 +9,7 @@ array(
|
|||
"id" => 'trashbin',
|
||||
"appname" => 'files_trashbin',
|
||||
"script" => 'list.php',
|
||||
"order" => 1,
|
||||
"order" => 50,
|
||||
"name" => $l->t('Deleted files')
|
||||
)
|
||||
);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -211,7 +211,16 @@ var OC={
|
|||
linkToRemote:function(service) {
|
||||
return window.location.protocol + '//' + window.location.host + OC.linkToRemoteBase(service);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Gets the base path for the given OCS API service.
|
||||
* @param {string} service name
|
||||
* @return {string} OCS API base path
|
||||
*/
|
||||
linkToOCS: function(service) {
|
||||
return window.location.protocol + '//' + window.location.host + OC.webroot + '/ocs/v1.php/' + service + '/';
|
||||
},
|
||||
|
||||
/**
|
||||
* Generates the absolute url for the given relative url, which can contain parameters.
|
||||
* @param {string} url
|
||||
|
@ -1241,7 +1250,7 @@ OC.Util = {
|
|||
* @return {string} fixed image path with png extension if SVG is not supported
|
||||
*/
|
||||
replaceSVGIcon: function(file) {
|
||||
if (!OC.Util.hasSVGSupport()) {
|
||||
if (file && !OC.Util.hasSVGSupport()) {
|
||||
var i = file.lastIndexOf('.svg');
|
||||
if (i >= 0) {
|
||||
file = file.substr(0, i) + '.png' + file.substr(i+4);
|
||||
|
|
|
@ -10,8 +10,11 @@ OC.Share={
|
|||
* Loads ALL share statuses from server, stores them in OC.Share.statuses then
|
||||
* calls OC.Share.updateIcons() to update the files "Share" icon to "Shared"
|
||||
* according to their share status and share type.
|
||||
*
|
||||
* @param itemType item type
|
||||
* @param fileList file list instance, defaults to OCA.Files.App.fileList
|
||||
*/
|
||||
loadIcons:function(itemType) {
|
||||
loadIcons:function(itemType, fileList) {
|
||||
// Load all share icons
|
||||
$.get(OC.filePath('core', 'ajax', 'share.php'), { fetch: 'getItemsSharedStatuses', itemType: itemType }, function(result) {
|
||||
if (result && result.status === 'success') {
|
||||
|
@ -19,7 +22,7 @@ OC.Share={
|
|||
$.each(result.data, function(item, data) {
|
||||
OC.Share.statuses[item] = data;
|
||||
});
|
||||
OC.Share.updateIcons(itemType);
|
||||
OC.Share.updateIcons(itemType, fileList);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -27,40 +30,55 @@ OC.Share={
|
|||
* Updates the files' "Share" icons according to the known
|
||||
* sharing states stored in OC.Share.statuses.
|
||||
* (not reloaded from server)
|
||||
*
|
||||
* @param itemType item type
|
||||
* @param fileList file list instance
|
||||
* defaults to OCA.Files.App.fileList
|
||||
*/
|
||||
updateIcons:function(itemType){
|
||||
updateIcons:function(itemType, fileList){
|
||||
var item;
|
||||
var $fileList;
|
||||
var currentDir;
|
||||
if (!fileList && OCA.Files) {
|
||||
fileList = OCA.Files.App.fileList;
|
||||
}
|
||||
// fileList is usually only defined in the files app
|
||||
if (fileList) {
|
||||
$fileList = fileList.$fileList;
|
||||
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') {
|
||||
$('a.share[data-item="'+item+'"]').css('background', 'url('+image+') no-repeat center');
|
||||
if (itemType !== 'file' && itemType !== 'folder') {
|
||||
$fileList.find('a.share[data-item="'+item+'"]').css('background', 'url('+image+') no-repeat center');
|
||||
} else {
|
||||
var file = $('tr[data-id="'+item+'"]');
|
||||
var file = $fileList.find('tr[data-id="'+item+'"]');
|
||||
if (file.length > 0) {
|
||||
var action = $(file).find('.fileactions .action[data-action="Share"]');
|
||||
var img = action.find('img').attr('src', image);
|
||||
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']) {
|
||||
var actions = $('.fileactions .action[data-action="Share"]');
|
||||
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);
|
||||
|
@ -100,14 +118,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) {
|
||||
|
|
|
@ -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);
|
||||
if (enableCoverage) {
|
||||
preprocessors[srcFile] = 'coverage';
|
||||
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 test specs
|
||||
files.push('apps/' + appsToTest[i] + '/tests/js/*.js');
|
||||
|
||||
// add source files/patterns
|
||||
files = files.concat(app.srcFiles || []);
|
||||
// add test files/patterns
|
||||
files = files.concat(app.testFiles || []);
|
||||
if (enableCoverage) {
|
||||
// add coverage entry for each file/pattern
|
||||
for (var i = 0; i < app.srcFiles.length; i++) {
|
||||
preprocessors[app.srcFiles[i]] = 'coverage';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add source files for apps to test
|
||||
for ( var i = 0; i < appsToTest.length; i++ ) {
|
||||
addApp(appsToTest[i]);
|
||||
}
|
||||
|
||||
// serve images to avoid warnings
|
||||
|
|
Loading…
Reference in a new issue