parent
c6be491a89
commit
a5bb66f4a7
@ -0,0 +1,99 @@ |
||||
/* |
||||
* 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. |
||||
* |
||||
*/ |
||||
|
||||
// HACK: this piece needs to be loaded AFTER the files app (for unit tests)
|
||||
$(document).ready(function() { |
||||
(function(OCA) { |
||||
/** |
||||
* @class OCA.Files.FavoritesFileList |
||||
* @augments OCA.Files.FavoritesFileList |
||||
* |
||||
* @classdesc Favorites file list. |
||||
* Displays the list of files marked as favorites |
||||
* |
||||
* @param $el container element with existing markup for the #controls |
||||
* and a table |
||||
* @param [options] map of options, see other parameters |
||||
*/ |
||||
var FavoritesFileList = function($el, options) { |
||||
this.initialize($el, options); |
||||
}; |
||||
FavoritesFileList.prototype = _.extend({}, OCA.Files.FileList.prototype, |
||||
/** @lends OCA.Files.FavoritesFileList.prototype */ { |
||||
id: 'favorites', |
||||
appName: 'Favorites', |
||||
|
||||
_clientSideSort: true, |
||||
_allowSelection: false, |
||||
|
||||
/** |
||||
* @private |
||||
*/ |
||||
initialize: function($el, options) { |
||||
OCA.Files.FileList.prototype.initialize.apply(this, arguments); |
||||
if (this.initialized) { |
||||
return; |
||||
} |
||||
OC.Plugins.attach('OCA.Files.FavoritesFileList', this); |
||||
}, |
||||
|
||||
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 tagName = OC.TAG_FAVORITE; |
||||
this.showMask(); |
||||
if (this._reloadCall) { |
||||
this._reloadCall.abort(); |
||||
} |
||||
this._reloadCall = $.ajax({ |
||||
url: OC.generateUrl('/apps/files/api/v1/tags/{tagName}/files', {tagName: tagName}), |
||||
type: 'GET', |
||||
dataType: 'json' |
||||
}); |
||||
var callBack = this.reloadCallback.bind(this); |
||||
return this._reloadCall.then(callBack, callBack); |
||||
}, |
||||
|
||||
reloadCallback: function(result) { |
||||
delete this._reloadCall; |
||||
this.hideMask(); |
||||
|
||||
if (result.files) { |
||||
this.setFiles(result.files.sort(this._sortComparator)); |
||||
} |
||||
else { |
||||
// TODO: error handling
|
||||
} |
||||
} |
||||
}); |
||||
|
||||
OCA.Files.FavoritesFileList = FavoritesFileList; |
||||
})(OCA); |
||||
}); |
||||
|
||||
@ -0,0 +1,116 @@ |
||||
/* |
||||
* 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(OCA) { |
||||
/** |
||||
* @namespace OCA.Files.FavoritesPlugin |
||||
* |
||||
* Registers the favorites file list from the files app sidebar. |
||||
*/ |
||||
OCA.Files.FavoritesPlugin = { |
||||
name: 'Favorites', |
||||
|
||||
/** |
||||
* @type OCA.Files.FavoritesFileList |
||||
*/ |
||||
favoritesFileList: null, |
||||
|
||||
attach: function() { |
||||
var self = this; |
||||
$('#app-content-favorites').on('show.plugin-favorites', function(e) { |
||||
self.showFileList($(e.target)); |
||||
}); |
||||
$('#app-content-favorites').on('hide.plugin-favorites', function() { |
||||
self.hideFileList(); |
||||
}); |
||||
}, |
||||
|
||||
detach: function() { |
||||
if (this.favoritesFileList) { |
||||
this.favoritesFileList.destroy(); |
||||
OCA.Files.fileActions.off('setDefault.plugin-favorites', this._onActionsUpdated); |
||||
OCA.Files.fileActions.off('registerAction.plugin-favorites', this._onActionsUpdated); |
||||
$('#app-content-favorites').off('.plugin-favorites'); |
||||
this.favoritesFileList = null; |
||||
} |
||||
}, |
||||
|
||||
showFileList: function($el) { |
||||
if (!this.favoritesFileList) { |
||||
this.favoritesFileList = this._createFavoritesFileList($el); |
||||
} |
||||
return this.favoritesFileList; |
||||
}, |
||||
|
||||
hideFileList: function() { |
||||
if (this.favoritesFileList) { |
||||
this.favoritesFileList.$fileList.empty(); |
||||
} |
||||
}, |
||||
|
||||
/** |
||||
* Creates the favorites file list. |
||||
* |
||||
* @param $el container for the file list |
||||
* @return {OCA.Files.FavoritesFileList} file list |
||||
*/ |
||||
_createFavoritesFileList: function($el) { |
||||
var fileActions = this._createFileActions(); |
||||
// register favorite list for sidebar section
|
||||
return new OCA.Files.FavoritesFileList( |
||||
$el, { |
||||
fileActions: fileActions, |
||||
scrollContainer: $('#app-content') |
||||
} |
||||
); |
||||
}, |
||||
|
||||
_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); |
||||
|
||||
if (!this._globalActionsInitialized) { |
||||
// in case actions are registered later
|
||||
this._onActionsUpdated = _.bind(this._onActionsUpdated, this); |
||||
OCA.Files.fileActions.on('setDefault.plugin-favorites', this._onActionsUpdated); |
||||
OCA.Files.fileActions.on('registerAction.plugin-favorites', this._onActionsUpdated); |
||||
this._globalActionsInitialized = true; |
||||
} |
||||
|
||||
// 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; |
||||
}, |
||||
|
||||
_onActionsUpdated: function(ev) { |
||||
if (ev.action) { |
||||
this.favoritesFileList.fileActions.registerAction(ev.action); |
||||
} else if (ev.defaultAction) { |
||||
this.favoritesFileList.fileActions.setDefault( |
||||
ev.defaultAction.mime, |
||||
ev.defaultAction.name |
||||
); |
||||
} |
||||
} |
||||
}; |
||||
|
||||
})(OCA); |
||||
|
||||
OC.Plugins.register('OCA.Files.App', OCA.Files.FavoritesPlugin); |
||||
|
||||
@ -0,0 +1,135 @@ |
||||
/* |
||||
* 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(OCA) { |
||||
|
||||
OCA.Files = OCA.Files || {}; |
||||
|
||||
/** |
||||
* @namespace OCA.Files.TagsPlugin |
||||
* |
||||
* Extends the file actions and file list to include a favorite action icon |
||||
* and addition "data-tags" and "data-favorite" attributes. |
||||
*/ |
||||
OCA.Files.TagsPlugin = { |
||||
name: 'Tags', |
||||
|
||||
allowedLists: [ |
||||
'files', |
||||
'favorites' |
||||
], |
||||
|
||||
_extendFileActions: function(fileActions) { |
||||
var self = this; |
||||
// register "star" action
|
||||
fileActions.registerAction({ |
||||
name: 'favorite', |
||||
displayName: 'Favorite', |
||||
mime: 'all', |
||||
permissions: OC.PERMISSION_READ, |
||||
render: function(actionSpec, isDefault, context) { |
||||
// TODO: use proper icon
|
||||
var $file = context.$file; |
||||
var isFavorite = $file.data('favorite') === true; |
||||
var starState = isFavorite ? '★' : '☆'; |
||||
var $icon = $( |
||||
'<a href="#" class="action action-favorite ' + (isFavorite ? 'permanent' : '') + '">' + |
||||
starState + '</a>' |
||||
); |
||||
$file.find('td:first>.favorite').prepend($icon); |
||||
return $icon; |
||||
}, |
||||
actionHandler: function(fileName, context) { |
||||
var $actionEl = context.$file.find('.action-favorite'); |
||||
var $file = context.$file; |
||||
var dir = context.dir || context.fileList.getCurrentDirectory(); |
||||
var tags = $file.attr('data-tags'); |
||||
if (_.isUndefined(tags)) { |
||||
tags = ''; |
||||
} |
||||
tags = tags.split('|'); |
||||
tags = _.without(tags, ''); |
||||
var isFavorite = tags.indexOf(OC.TAG_FAVORITE) >= 0; |
||||
if (isFavorite) { |
||||
// remove tag from list
|
||||
tags = _.without(tags, OC.TAG_FAVORITE); |
||||
} else { |
||||
tags.push(OC.TAG_FAVORITE); |
||||
} |
||||
if ($actionEl.hasClass('icon-loading')) { |
||||
// do nothing
|
||||
return; |
||||
} |
||||
$actionEl.addClass('icon-loading permanent'); |
||||
self.applyFileTags( |
||||
dir + '/' + fileName, |
||||
tags |
||||
).then(function() { |
||||
// TODO: read from result
|
||||
$actionEl.removeClass('icon-loading'); |
||||
$actionEl.html(isFavorite ? '☆' : '★'); |
||||
$actionEl.toggleClass('permanent', !isFavorite); |
||||
$file.attr('data-tags', tags.join('|')); |
||||
$file.attr('data-favorite', !isFavorite); |
||||
}); |
||||
} |
||||
}); |
||||
}, |
||||
|
||||
_extendFileList: function(fileList) { |
||||
// extend row prototype
|
||||
fileList.$fileList.addClass('has-favorites'); |
||||
var oldCreateRow = fileList._createRow; |
||||
fileList._createRow = function(fileData) { |
||||
var $tr = oldCreateRow.apply(this, arguments); |
||||
if (fileData.tags) { |
||||
$tr.attr('data-tags', fileData.tags.join('|')); |
||||
if (fileData.tags.indexOf(OC.TAG_FAVORITE) >= 0) { |
||||
$tr.attr('data-favorite', true); |
||||
} |
||||
} |
||||
$tr.find('td:first').prepend('<div class="favorite"></div>'); |
||||
return $tr; |
||||
}; |
||||
}, |
||||
|
||||
attach: function(fileList) { |
||||
if (this.allowedLists.indexOf(fileList.id) < 0) { |
||||
return; |
||||
} |
||||
this._extendFileActions(fileList.fileActions); |
||||
this._extendFileList(fileList); |
||||
}, |
||||
|
||||
/** |
||||
* Replaces the given files' tags with the specified ones. |
||||
* |
||||
* @param {String} fileName path to the file or folder to tag |
||||
* @param {Array.<String>} tagNames array of tag names |
||||
*/ |
||||
applyFileTags: function(fileName, tagNames) { |
||||
var encodedPath = OC.encodePath(fileName); |
||||
while (encodedPath[0] === '/') { |
||||
encodedPath = encodedPath.substr(1); |
||||
} |
||||
return $.ajax({ |
||||
url: OC.generateUrl('/apps/files/api/v1/files/') + encodedPath, |
||||
contentType: 'application/json', |
||||
data: JSON.stringify({ |
||||
tags: tagNames || [] |
||||
}), |
||||
dataType: 'json', |
||||
type: 'POST' |
||||
}); |
||||
} |
||||
}; |
||||
})(OCA); |
||||
|
||||
OC.Plugins.register('OCA.Files.FileList', OCA.Files.TagsPlugin); |
||||
|
||||
@ -0,0 +1,94 @@ |
||||
<?php |
||||
/** |
||||
* 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. |
||||
*/ |
||||
|
||||
namespace OCA\Files\Service; |
||||
|
||||
/** |
||||
* Service class to manage tags on files. |
||||
*/ |
||||
class TagService { |
||||
|
||||
/** |
||||
* @var \OCP\IUserSession |
||||
*/ |
||||
private $userSession; |
||||
|
||||
/** |
||||
* @var \OCP\ITags |
||||
*/ |
||||
private $tagger; |
||||
|
||||
/** |
||||
* @var \OCP\Files\Folder |
||||
*/ |
||||
private $homeFolder; |
||||
|
||||
public function __construct( |
||||
\OCP\IUserSession $userSession, |
||||
\OCP\ITags $tagger, |
||||
\OCP\Files\Folder $homeFolder |
||||
) { |
||||
$this->userSession = $userSession; |
||||
$this->tagger = $tagger; |
||||
$this->homeFolder = $homeFolder; |
||||
} |
||||
|
||||
/** |
||||
* Updates the tags of the specified file path. |
||||
* The passed tags are absolute, which means they will |
||||
* replace the actual tag selection. |
||||
* |
||||
* @param string $path path |
||||
* @param array $tags array of tags |
||||
* @return array list of tags |
||||
* @throws \OCP\NotFoundException if the file does not exist |
||||
*/ |
||||
public function updateFileTags($path, $tags) { |
||||
$fileId = $this->homeFolder->get($path)->getId(); |
||||
|
||||
$currentTags = $this->tagger->getTagsForObjects(array($fileId)); |
||||
|
||||
if (!empty($currentTags)) { |
||||
$currentTags = current($currentTags); |
||||
} |
||||
|
||||
$newTags = array_diff($tags, $currentTags); |
||||
foreach ($newTags as $tag) { |
||||
$this->tagger->tagAs($fileId, $tag); |
||||
} |
||||
$deletedTags = array_diff($currentTags, $tags); |
||||
foreach ($deletedTags as $tag) { |
||||
$this->tagger->unTag($fileId, $tag); |
||||
} |
||||
|
||||
// TODO: re-read from tagger to make sure the |
||||
// list is up to date, in case of concurrent changes ? |
||||
return $tags; |
||||
} |
||||
|
||||
/** |
||||
* Updates the tags of the specified file path. |
||||
* The passed tags are absolute, which means they will |
||||
* replace the actual tag selection. |
||||
* |
||||
* @param array $tagName tag name to filter by |
||||
* @return FileInfo[] list of matching files |
||||
* @throws \Exception if the tag does not exist |
||||
*/ |
||||
public function getFilesByTag($tagName) { |
||||
$nodes = $this->homeFolder->searchByTag( |
||||
$tagName, $this->userSession->getUser()->getUId() |
||||
); |
||||
foreach ($nodes as &$node) { |
||||
$node = $node->getFileInfo(); |
||||
} |
||||
|
||||
return $nodes; |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,30 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* ownCloud - Simple files list |
||||
* |
||||
* @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/>. |
||||
* |
||||
*/ |
||||
|
||||
// Check if we are a user |
||||
OCP\User::checkLoggedIn(); |
||||
|
||||
// renders the controls and table headers template |
||||
$tmpl = new OCP\Template('files', 'simplelist', ''); |
||||
$tmpl->printPage(); |
||||
|
||||
@ -0,0 +1,36 @@ |
||||
<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="headerSize" class="hidden column-size"> |
||||
<a class="size sort columntitle" data-sort="size"><span><?php p($l->t('Size')); ?></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( 'Modified' )); ?></span><span class="sort-indicator"></span></a>
|
||||
<span class="selectedActions"><a href="" class="delete-selected"> |
||||
<?php p($l->t('Delete'))?> |
||||
<img class="svg" alt="<?php p($l->t('Delete'))?>"
|
||||
src="<?php print_unescaped(OCP\image_path("core", "actions/delete.svg")); ?>" />
|
||||
</a></span> |
||||
</th> |
||||
</tr> |
||||
</thead> |
||||
<tbody id="fileList"> |
||||
</tbody> |
||||
<tfoot> |
||||
</tfoot> |
||||
</table> |
||||
|
||||
@ -0,0 +1,109 @@ |
||||
/* |
||||
* 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.Files.FavoritesFileList tests', function() { |
||||
var fileList; |
||||
|
||||
beforeEach(function() { |
||||
// 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">' + |
||||
'<a class="name columntitle" data-sort="name"><span>Name</span><span class="sort-indicator"></span></a>' + |
||||
'</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() { |
||||
fileList.destroy(); |
||||
fileList = undefined; |
||||
}); |
||||
|
||||
describe('loading file list', function() { |
||||
var response; |
||||
|
||||
beforeEach(function() { |
||||
fileList = new OCA.Files.FavoritesFileList( |
||||
$('#app-content-container') |
||||
); |
||||
OCA.Files.FavoritesPlugin.attach(fileList); |
||||
|
||||
fileList.reload(); |
||||
|
||||
/* jshint camelcase: false */ |
||||
response = { |
||||
files: [{ |
||||
id: 7, |
||||
name: 'test.txt', |
||||
path: '/somedir', |
||||
size: 123, |
||||
mtime: 11111000, |
||||
tags: [OC.TAG_FAVORITE], |
||||
permissions: OC.PERMISSION_ALL, |
||||
mimetype: 'text/plain' |
||||
}] |
||||
}; |
||||
}); |
||||
it('render files', function() { |
||||
var request; |
||||
|
||||
expect(fakeServer.requests.length).toEqual(1); |
||||
request = fakeServer.requests[0]; |
||||
expect(request.url).toEqual( |
||||
OC.generateUrl('apps/files/api/v1/tags/{tagName}/files', {tagName: OC.TAG_FAVORITE}) |
||||
); |
||||
|
||||
fakeServer.requests[0].respond( |
||||
200, |
||||
{ 'Content-Type': 'application/json' }, |
||||
JSON.stringify(response) |
||||
); |
||||
|
||||
var $rows = fileList.$el.find('tbody tr'); |
||||
var $tr = $rows.eq(0); |
||||
expect($rows.length).toEqual(1); |
||||
expect($tr.attr('data-id')).toEqual('7'); |
||||
expect($tr.attr('data-type')).toEqual('file'); |
||||
expect($tr.attr('data-file')).toEqual('test.txt'); |
||||
expect($tr.attr('data-path')).toEqual('/somedir'); |
||||
expect($tr.attr('data-size')).toEqual('123'); |
||||
expect(parseInt($tr.attr('data-permissions'), 10)) |
||||
.toEqual(OC.PERMISSION_ALL); |
||||
expect($tr.attr('data-mime')).toEqual('text/plain'); |
||||
expect($tr.attr('data-mtime')).toEqual('11111000'); |
||||
expect($tr.find('a.name').attr('href')).toEqual( |
||||
OC.webroot + |
||||
'/index.php/apps/files/ajax/download.php' + |
||||
'?dir=%2Fsomedir&files=test.txt' |
||||
); |
||||
expect($tr.find('.nametext').text().trim()).toEqual('test.txt'); |
||||
}); |
||||
}); |
||||
}); |
||||
@ -0,0 +1,130 @@ |
||||
/* |
||||
* 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.Files.FavoritesPlugin tests', function() { |
||||
var Plugin = OCA.Files.FavoritesPlugin; |
||||
var fileList; |
||||
|
||||
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-favorites" class="hidden">' + |
||||
'</div>' + |
||||
'</div>' + |
||||
'</div>' |
||||
); |
||||
OC.Plugins.attach('OCA.Files.App', Plugin); |
||||
fileList = Plugin.showFileList($('#app-content-favorites')); |
||||
}); |
||||
afterEach(function() { |
||||
OC.Plugins.detach('OCA.Files.App', Plugin); |
||||
}); |
||||
|
||||
describe('initialization', function() { |
||||
it('inits favorites list on show', function() { |
||||
expect(fileList).toBeDefined(); |
||||
}); |
||||
}); |
||||
describe('file actions', function() { |
||||
var oldLegacyFileActions; |
||||
|
||||
beforeEach(function() { |
||||
oldLegacyFileActions = window.FileActions; |
||||
window.FileActions = new OCA.Files.FileActions(); |
||||
}); |
||||
|
||||
afterEach(function() { |
||||
window.FileActions = oldLegacyFileActions; |
||||
}); |
||||
it('provides default file actions', function() { |
||||
var fileActions = fileList.fileActions; |
||||
|
||||
expect(fileActions.actions.all).toBeDefined(); |
||||
expect(fileActions.actions.all.Delete).toBeDefined(); |
||||
expect(fileActions.actions.all.Rename).toBeDefined(); |
||||
expect(fileActions.actions.all.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 |
||||
); |
||||
|
||||
Plugin.favoritesFileList = null; |
||||
fileList = Plugin.showFileList($('#app-content-favorites')); |
||||
|
||||
expect(fileList.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 |
||||
); |
||||
|
||||
Plugin.favoritesFileList = null; |
||||
fileList = Plugin.showFileList($('#app-content-favorites')); |
||||
|
||||
expect(fileList.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-favorites').append($table); |
||||
|
||||
Plugin.favoritesFileList = null; |
||||
fileList = Plugin.showFileList($('#app-content-favorites')); |
||||
|
||||
fileList.setFiles([{ |
||||
name: 'testdir', |
||||
type: 'dir', |
||||
path: '/somewhere/inside/subdir', |
||||
counterParts: ['user2'], |
||||
shareOwner: 'user2' |
||||
}]); |
||||
|
||||
fileList.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; |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
@ -0,0 +1,84 @@ |
||||
/* |
||||
* 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.Files.TagsPlugin tests', function() { |
||||
var fileList; |
||||
var testFiles; |
||||
|
||||
beforeEach(function() { |
||||
var $content = $('<div id="content"></div>'); |
||||
$('#testArea').append($content); |
||||
// dummy file list
|
||||
var $div = $( |
||||
'<div>' + |
||||
'<table id="filestable">' + |
||||
'<thead></thead>' + |
||||
'<tbody id="fileList"></tbody>' + |
||||
'</table>' + |
||||
'</div>'); |
||||
$('#content').append($div); |
||||
|
||||
fileList = new OCA.Files.FileList($div); |
||||
OCA.Files.TagsPlugin.attach(fileList); |
||||
|
||||
testFiles = [{ |
||||
id: 1, |
||||
type: 'file', |
||||
name: 'One.txt', |
||||
path: '/subdir', |
||||
mimetype: 'text/plain', |
||||
size: 12, |
||||
permissions: OC.PERMISSION_ALL, |
||||
etag: 'abc', |
||||
shareOwner: 'User One', |
||||
isShareMountPoint: false, |
||||
tags: ['tag1', 'tag2'] |
||||
}]; |
||||
}); |
||||
afterEach(function() { |
||||
fileList.destroy(); |
||||
fileList = null; |
||||
}); |
||||
|
||||
describe('Favorites icon', function() { |
||||
it('renders favorite icon and extra data', function() { |
||||
var $action, $tr; |
||||
fileList.setFiles(testFiles); |
||||
$tr = fileList.$el.find('tbody tr:first'); |
||||
$action = $tr.find('.action-favorite'); |
||||
expect($action.length).toEqual(1); |
||||
expect($action.hasClass('permanent')).toEqual(false); |
||||
|
||||
expect($tr.attr('data-tags').split('|')).toEqual(['tag1', 'tag2']); |
||||
expect($tr.attr('data-favorite')).not.toBeDefined(); |
||||
}); |
||||
it('renders permanent favorite icon and extra data', function() { |
||||
var $action, $tr; |
||||
testFiles[0].tags.push(OC.TAG_FAVORITE); |
||||
fileList.setFiles(testFiles); |
||||
$tr = fileList.$el.find('tbody tr:first'); |
||||
$action = $tr.find('.action-favorite'); |
||||
expect($action.length).toEqual(1); |
||||
expect($action.hasClass('permanent')).toEqual(true); |
||||
|
||||
expect($tr.attr('data-tags').split('|')).toEqual(['tag1', 'tag2', OC.TAG_FAVORITE]); |
||||
expect($tr.attr('data-favorite')).toEqual('true'); |
||||
}); |
||||
}); |
||||
describe('Applying tags', function() { |
||||
it('sends request to server and updates icon', function() { |
||||
// TODO
|
||||
fileList.setFiles(testFiles); |
||||
}); |
||||
it('sends all tags to server when applyFileTags() is called ', function() { |
||||
// TODO
|
||||
}); |
||||
}); |
||||
}); |
||||
@ -0,0 +1,121 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* 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/>. |
||||
* |
||||
*/ |
||||
namespace OCA\Files; |
||||
|
||||
use \OCA\Files\Service\TagService; |
||||
|
||||
class TagServiceTest extends \Test\TestCase { |
||||
|
||||
/** |
||||
* @var string |
||||
*/ |
||||
private $user; |
||||
|
||||
/** |
||||
* @var \OCP\Files\Folder |
||||
*/ |
||||
private $root; |
||||
|
||||
/** |
||||
* @var \OCA\Files\Service\TagService |
||||
*/ |
||||
private $tagService; |
||||
|
||||
/** |
||||
* @var \OCP\ITags |
||||
*/ |
||||
private $tagger; |
||||
|
||||
protected function setUp() { |
||||
parent::setUp(); |
||||
$this->user = $this->getUniqueId('user'); |
||||
\OC_User::createUser($this->user, 'test'); |
||||
\OC_User::setUserId($this->user); |
||||
\OC_Util::setupFS($this->user); |
||||
/** |
||||
* @var \OCP\IUser |
||||
*/ |
||||
$user = new \OC\User\User($this->user, null); |
||||
/** |
||||
* @var \OCP\IUserSession |
||||
*/ |
||||
$userSession = $this->getMock('\OCP\IUserSession'); |
||||
$userSession->expects($this->any()) |
||||
->method('getUser') |
||||
->withAnyParameters() |
||||
->will($this->returnValue($user)); |
||||
|
||||
$this->root = \OC::$server->getUserFolder(); |
||||
|
||||
$this->tagger = \OC::$server->getTagManager()->load('files'); |
||||
$this->tagService = new TagService( |
||||
$userSession, |
||||
$this->tagger, |
||||
$this->root |
||||
); |
||||
} |
||||
|
||||
protected function tearDown() { |
||||
\OC_User::setUserId(''); |
||||
\OC_User::deleteUser($this->user); |
||||
} |
||||
|
||||
public function testUpdateFileTags() { |
||||
$tag1 = 'tag1'; |
||||
$tag2 = 'tag2'; |
||||
|
||||
$subdir = $this->root->newFolder('subdir'); |
||||
$testFile = $subdir->newFile('test.txt'); |
||||
$testFile->putContent('test contents'); |
||||
|
||||
$fileId = $testFile->getId(); |
||||
|
||||
// set tags |
||||
$this->tagService->updateFileTags('subdir/test.txt', array($tag1, $tag2)); |
||||
|
||||
$this->assertEquals(array($fileId), $this->tagger->getIdsForTag($tag1)); |
||||
$this->assertEquals(array($fileId), $this->tagger->getIdsForTag($tag2)); |
||||
|
||||
// remove tag |
||||
$result = $this->tagService->updateFileTags('subdir/test.txt', array($tag2)); |
||||
$this->assertEquals(array(), $this->tagger->getIdsForTag($tag1)); |
||||
$this->assertEquals(array($fileId), $this->tagger->getIdsForTag($tag2)); |
||||
|
||||
// clear tags |
||||
$result = $this->tagService->updateFileTags('subdir/test.txt', array()); |
||||
$this->assertEquals(array(), $this->tagger->getIdsForTag($tag1)); |
||||
$this->assertEquals(array(), $this->tagger->getIdsForTag($tag2)); |
||||
|
||||
// non-existing file |
||||
$caught = false; |
||||
try { |
||||
$this->tagService->updateFileTags('subdir/unexist.txt', array($tag1)); |
||||
} catch (\OCP\Files\NotFoundException $e) { |
||||
$caught = true; |
||||
} |
||||
$this->assertTrue($caught); |
||||
|
||||
$subdir->delete(); |
||||
} |
||||
} |
||||
|
||||
Loading…
Reference in new issue