diff options
author | William Bargent <personal@williambargent.co.uk> | 2016-07-25 15:25:02 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-07-25 15:25:02 +0100 |
commit | 352e24e703aae74c9486810e8c3550ae581c93cb (patch) | |
tree | 144f60ca01ed26ef1ea52cb66637b1220bfbe003 /apps/files | |
parent | e51afa1684a0d555082e3115a75dc357a14a9cca (diff) | |
parent | f18338d93284f475d7f78dc2762ff0fdc8137dea (diff) | |
download | nextcloud-server-352e24e703aae74c9486810e8c3550ae581c93cb.tar.gz nextcloud-server-352e24e703aae74c9486810e8c3550ae581c93cb.zip |
Merge pull request #292 from nextcloud/recent-files
Add "Recent" file listing
Diffstat (limited to 'apps/files')
-rw-r--r-- | apps/files/appinfo/app.php | 14 | ||||
-rw-r--r-- | apps/files/appinfo/routes.php | 5 | ||||
-rw-r--r-- | apps/files/js/filelist.js | 7 | ||||
-rw-r--r-- | apps/files/js/recentfilelist.js | 106 | ||||
-rw-r--r-- | apps/files/js/recentplugin.js | 117 | ||||
-rw-r--r-- | apps/files/lib/AppInfo/Application.php | 3 | ||||
-rw-r--r-- | apps/files/lib/Controller/ApiController.php | 65 | ||||
-rw-r--r-- | apps/files/lib/Controller/ViewController.php | 2 | ||||
-rw-r--r-- | apps/files/recentlist.php | 7 | ||||
-rw-r--r-- | apps/files/templates/recentlist.php | 42 | ||||
-rw-r--r-- | apps/files/tests/Controller/ApiControllerTest.php | 8 | ||||
-rw-r--r-- | apps/files/tests/Controller/ViewControllerTest.php | 25 |
12 files changed, 373 insertions, 28 deletions
diff --git a/apps/files/appinfo/app.php b/apps/files/appinfo/app.php index cc86e9bf270..850c335c27d 100644 --- a/apps/files/appinfo/app.php +++ b/apps/files/appinfo/app.php @@ -28,6 +28,7 @@ */ \OCP\App::registerAdmin('files', 'admin'); +$l = \OC::$server->getL10N('files'); \OC::$server->getNavigationManager()->add(function () { $urlGenerator = \OC::$server->getURLGenerator(); @@ -49,8 +50,7 @@ $templateManager->registerTemplate('application/vnd.oasis.opendocument.presentat $templateManager->registerTemplate('application/vnd.oasis.opendocument.text', 'core/templates/filetemplates/template.odt'); $templateManager->registerTemplate('application/vnd.oasis.opendocument.spreadsheet', 'core/templates/filetemplates/template.ods'); -\OCA\Files\App::getNavigationManager()->add(function () { - $l = \OC::$server->getL10N('files'); +\OCA\Files\App::getNavigationManager()->add(function () use ($l) { return [ 'id' => 'files', 'appname' => 'files', @@ -60,6 +60,16 @@ $templateManager->registerTemplate('application/vnd.oasis.opendocument.spreadshe ]; }); +\OCA\Files\App::getNavigationManager()->add(function () use ($l) { + return [ + 'id' => 'recent', + 'appname' => 'files', + 'script' => 'recentlist.php', + 'order' => 2, + 'name' => $l->t('Recent'), + ]; +}); + \OC::$server->getActivityManager()->registerExtension(function() { return new \OCA\Files\Activity( \OC::$server->query('L10NFactory'), diff --git a/apps/files/appinfo/routes.php b/apps/files/appinfo/routes.php index 34bb1011773..7b5ac63a160 100644 --- a/apps/files/appinfo/routes.php +++ b/apps/files/appinfo/routes.php @@ -51,6 +51,11 @@ $application->registerRoutes( 'requirements' => array('tagName' => '.+'), ), array( + 'name' => 'API#getRecentFiles', + 'url' => '/api/v1/recent/', + 'verb' => 'GET' + ), + array( 'name' => 'API#updateFileSorting', 'url' => '/api/v1/sorting', 'verb' => 'POST' diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index f0b16a57886..24cccb3a5c8 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -175,6 +175,11 @@ _clientSideSort: true, /** + * Whether or not users can change the sort attribute or direction + */ + _allowSorting: true, + + /** * Current directory * @type String */ @@ -718,7 +723,7 @@ $target = $target.closest('a'); } sort = $target.attr('data-sort'); - if (sort) { + if (sort && this._allowSorting) { if (this._sort === sort) { this.setSort(sort, (this._sortDirection === 'desc')?'asc':'desc', true, true); } diff --git a/apps/files/js/recentfilelist.js b/apps/files/js/recentfilelist.js new file mode 100644 index 00000000000..e8c61cbfe2d --- /dev/null +++ b/apps/files/js/recentfilelist.js @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com> + * + * This file is licensed under the Affero General Public License version 3 + * or later. + * + * See the COPYING-README file. + * + */ + +// HACK: this piece needs to be loaded AFTER the files app (for unit tests) +$(document).ready(function () { + (function (OCA) { + /** + * @class OCA.Files.RecentFileList + * @augments OCA.Files.RecentFileList + * + * @classdesc Recent file list. + * Displays the list of recently modified files + * + * @param $el container element with existing markup for the #controls + * and a table + * @param [options] map of options, see other parameters + */ + var RecentFileList = function ($el, options) { + options.sorting = { + mode: 'mtime', + direction: 'desc' + }; + this.initialize($el, options); + this._allowSorting = false; + }; + RecentFileList.prototype = _.extend({}, OCA.Files.FileList.prototype, + /** @lends OCA.Files.RecentFileList.prototype */ { + id: 'recent', + appName: t('files', 'Recent'), + + _clientSideSort: true, + _allowSelection: false, + + /** + * @private + */ + initialize: function () { + OCA.Files.FileList.prototype.initialize.apply(this, arguments); + if (this.initialized) { + return; + } + OC.Plugins.attach('OCA.Files.RecentFileList', 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 () { + this.showMask(); + if (this._reloadCall) { + this._reloadCall.abort(); + } + + // there is only root + this._setCurrentDir('/', false); + + this._reloadCall = $.ajax({ + url: OC.generateUrl('/apps/files/api/v1/recent'), + 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)); + return true; + } + return false; + } + }); + + OCA.Files.RecentFileList = RecentFileList; + })(OCA); +}); + diff --git a/apps/files/js/recentplugin.js b/apps/files/js/recentplugin.js new file mode 100644 index 00000000000..fcd427b18a2 --- /dev/null +++ b/apps/files/js/recentplugin.js @@ -0,0 +1,117 @@ +/* + * 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.RecentPlugin + * + * Registers the recent file list from the files app sidebar. + */ + OCA.Files.RecentPlugin = { + name: 'Recent', + + /** + * @type OCA.Files.RecentFileList + */ + recentFileList: null, + + attach: function () { + var self = this; + $('#app-content-recent').on('show.plugin-recent', function (e) { + self.showFileList($(e.target)); + }); + $('#app-content-recent').on('hide.plugin-recent', function () { + self.hideFileList(); + }); + }, + + detach: function () { + if (this.recentFileList) { + this.recentFileList.destroy(); + OCA.Files.fileActions.off('setDefault.plugin-recent', this._onActionsUpdated); + OCA.Files.fileActions.off('registerAction.plugin-recent', this._onActionsUpdated); + $('#app-content-recent').off('.plugin-recent'); + this.recentFileList = null; + } + }, + + showFileList: function ($el) { + if (!this.recentFileList) { + this.recentFileList = this._createRecentFileList($el); + } + return this.recentFileList; + }, + + hideFileList: function () { + if (this.recentFileList) { + this.recentFileList.$fileList.empty(); + } + }, + + /** + * Creates the recent file list. + * + * @param $el container for the file list + * @return {OCA.Files.RecentFileList} file list + */ + _createRecentFileList: function ($el) { + var fileActions = this._createFileActions(); + // register recent list for sidebar section + return new OCA.Files.RecentFileList( + $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-recent', this._onActionsUpdated); + OCA.Files.fileActions.on('registerAction.plugin-recent', 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}); + var path = OC.joinPaths(context.$file.attr('data-path'), filename); + OCA.Files.App.fileList.changeDirectory(path, true, true); + }); + fileActions.setDefault('dir', 'Open'); + return fileActions; + }, + + _onActionsUpdated: function (ev) { + if (ev.action) { + this.recentFileList.fileActions.registerAction(ev.action); + } else if (ev.defaultAction) { + this.recentFileList.fileActions.setDefault( + ev.defaultAction.mime, + ev.defaultAction.name + ); + } + } + }; + +})(OCA); + +OC.Plugins.register('OCA.Files.App', OCA.Files.RecentPlugin); + diff --git a/apps/files/lib/AppInfo/Application.php b/apps/files/lib/AppInfo/Application.php index fac8e3a3a4b..fc91e05ba7e 100644 --- a/apps/files/lib/AppInfo/Application.php +++ b/apps/files/lib/AppInfo/Application.php @@ -47,7 +47,8 @@ class Application extends App { $c->query('TagService'), $server->getPreviewManager(), $server->getShareManager(), - $server->getConfig() + $server->getConfig(), + $server->getUserFolder() ); }); diff --git a/apps/files/lib/Controller/ApiController.php b/apps/files/lib/Controller/ApiController.php index 57eb43bbe9c..7ce83bfca15 100644 --- a/apps/files/lib/Controller/ApiController.php +++ b/apps/files/lib/Controller/ApiController.php @@ -31,6 +31,7 @@ namespace OCA\Files\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Controller; +use OCP\Files\Folder; use OCP\IConfig; use OCP\IRequest; use OCP\AppFramework\Http\DataResponse; @@ -39,7 +40,7 @@ use OCP\AppFramework\Http\Response; use OCA\Files\Service\TagService; use OCP\IPreview; use OCP\Share\IManager; -use OCP\Files\Node; +use OC\Files\Node\Node; use OCP\IUserSession; /** @@ -58,12 +59,18 @@ class ApiController extends Controller { private $userSession; /** IConfig */ private $config; + /** @var Folder */ + private $userFolder; /** * @param string $appName * @param IRequest $request + * @param IUserSession $userSession * @param TagService $tagService * @param IPreview $previewManager + * @param IManager $shareManager + * @param IConfig $config + * @param Folder $userFolder */ public function __construct($appName, IRequest $request, @@ -71,13 +78,15 @@ class ApiController extends Controller { TagService $tagService, IPreview $previewManager, IManager $shareManager, - IConfig $config) { + IConfig $config, + Folder $userFolder) { parent::__construct($appName, $request); $this->userSession = $userSession; $this->tagService = $tagService; $this->previewManager = $previewManager; $this->shareManager = $shareManager; $this->config = $config; + $this->userFolder = $userFolder; } /** @@ -143,6 +152,28 @@ class ApiController extends Controller { } /** + * @param \OCP\Files\Node[] $nodes + * @return array + */ + private function formatNodes(array $nodes) { + return array_values(array_map(function (Node $node) { + /** @var \OC\Files\Node\Node $shareTypes */ + $shareTypes = $this->getShareTypes($node); + $file = \OCA\Files\Helper::formatFileInfo($node->getFileInfo()); + $parts = explode('/', dirname($node->getPath()), 4); + if (isset($parts[3])) { + $file['path'] = '/' . $parts[3]; + } else { + $file['path'] = '/'; + } + if (!empty($shareTypes)) { + $file['shareTypes'] = $shareTypes; + } + return $file; + }, $nodes)); + } + + /** * Returns a list of all files tagged with the given tag. * * @NoAdminRequired @@ -151,28 +182,28 @@ class ApiController extends Controller { * @return DataResponse */ public function getFilesByTag($tagName) { - $files = array(); $nodes = $this->tagService->getFilesByTag($tagName); - foreach ($nodes as &$node) { - $shareTypes = $this->getShareTypes($node); - $fileInfo = $node->getFileInfo(); - $file = \OCA\Files\Helper::formatFileInfo($fileInfo); - $parts = explode('/', dirname($fileInfo->getPath()), 4); - if(isset($parts[3])) { - $file['path'] = '/' . $parts[3]; - } else { - $file['path'] = '/'; - } + $files = $this->formatNodes($nodes); + foreach ($files as &$file) { $file['tags'] = [$tagName]; - if (!empty($shareTypes)) { - $file['shareTypes'] = $shareTypes; - } - $files[] = $file; } return new DataResponse(['files' => $files]); } /** + * Returns a list of recently modifed files. + * + * @NoAdminRequired + * + * @return DataResponse + */ + public function getRecentFiles() { + $nodes = $this->userFolder->getRecent(100); + $files = $this->formatNodes($nodes); + return new DataResponse(['files' => $files]); + } + + /** * Return a list of share types for outgoing shares * * @param Node $node file node diff --git a/apps/files/lib/Controller/ViewController.php b/apps/files/lib/Controller/ViewController.php index 5e342e6589b..9dbe06ff789 100644 --- a/apps/files/lib/Controller/ViewController.php +++ b/apps/files/lib/Controller/ViewController.php @@ -173,9 +173,11 @@ class ViewController extends Controller { \OCP\Util::addscript('files', 'search'); \OCP\Util::addScript('files', 'favoritesfilelist'); + \OCP\Util::addScript('files', 'recentfilelist'); \OCP\Util::addScript('files', 'tagsplugin'); \OCP\Util::addScript('files', 'gotoplugin'); \OCP\Util::addScript('files', 'favoritesplugin'); + \OCP\Util::addScript('files', 'recentplugin'); \OCP\Util::addScript('files', 'detailfileinfoview'); \OCP\Util::addScript('files', 'sidebarpreviewmanager'); diff --git a/apps/files/recentlist.php b/apps/files/recentlist.php new file mode 100644 index 00000000000..1976be4894a --- /dev/null +++ b/apps/files/recentlist.php @@ -0,0 +1,7 @@ +<?php +// Check if we are a user +OCP\User::checkLoggedIn(); + +$tmpl = new OCP\Template('files', 'recentlist', ''); + +$tmpl->printPage(); diff --git a/apps/files/templates/recentlist.php b/apps/files/templates/recentlist.php new file mode 100644 index 00000000000..1667eb4cc8d --- /dev/null +++ b/apps/files/templates/recentlist.php @@ -0,0 +1,42 @@ +<?php /** @var $l OC_L10N */ ?> +<div id='notification'></div> + +<div id="emptycontent" class="hidden"></div> + +<input type="hidden" name="dir" value="" id="dir"> + +<div class="nofilterresults hidden"> + <div class="icon-search"></div> + <h2><?php p($l->t('No entries found in this folder')); ?></h2> + <p></p> +</div> + +<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></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></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"> + <span><?php p($l->t('Delete')) ?></span> + <span class="icon icon-delete"></span> + </a></span> + </th> + </tr> + </thead> + <tbody id="fileList"> + </tbody> + <tfoot> + </tfoot> +</table> diff --git a/apps/files/tests/Controller/ApiControllerTest.php b/apps/files/tests/Controller/ApiControllerTest.php index 1d39c88021b..348150e0e08 100644 --- a/apps/files/tests/Controller/ApiControllerTest.php +++ b/apps/files/tests/Controller/ApiControllerTest.php @@ -59,6 +59,8 @@ class ApiControllerTest extends TestCase { private $shareManager; /** @var \OCP\IConfig */ private $config; + /** @var \OC\Files\Node\Folder */ + private $userFolder; public function setUp() { $this->request = $this->getMockBuilder('\OCP\IRequest') @@ -82,6 +84,9 @@ class ApiControllerTest extends TestCase { ->disableOriginalConstructor() ->getMock(); $this->config = $this->getMock('\OCP\IConfig'); + $this->userFolder = $this->getMockBuilder('\OC\Files\Node\Folder') + ->disableOriginalConstructor() + ->getMock(); $this->apiController = new ApiController( $this->appName, @@ -90,7 +95,8 @@ class ApiControllerTest extends TestCase { $this->tagService, $this->preview, $this->shareManager, - $this->config + $this->config, + $this->userFolder ); } diff --git a/apps/files/tests/Controller/ViewControllerTest.php b/apps/files/tests/Controller/ViewControllerTest.php index ceb48a2241f..373f8c25152 100644 --- a/apps/files/tests/Controller/ViewControllerTest.php +++ b/apps/files/tests/Controller/ViewControllerTest.php @@ -191,7 +191,16 @@ class ViewControllerTest extends TestCase { 'appname' => 'files', 'script' => 'list.php', 'order' => 0, - 'name' => new \OC_L10N_String(new \OC_L10N('files'), 'All files', []), + 'name' => (string)new \OC_L10N_String(new \OC_L10N('files'), 'All files', []), + 'active' => false, + 'icon' => '', + ], + [ + 'id' => 'recent', + 'appname' => 'files', + 'script' => 'recentlist.php', + 'order' => 2, + 'name' => (string)new \OC_L10N_String(new \OC_L10N('files'), 'Recent', []), 'active' => false, 'icon' => '', ], @@ -209,7 +218,7 @@ class ViewControllerTest extends TestCase { 'appname' => 'files_sharing', 'script' => 'list.php', 'order' => 10, - 'name' => new \OC_L10N_String(new \OC_L10N('files_sharing'), 'Shared with you', []), + 'name' => (string)new \OC_L10N_String(new \OC_L10N('files_sharing'), 'Shared with you', []), 'active' => false, 'icon' => '', ], @@ -218,7 +227,7 @@ class ViewControllerTest extends TestCase { 'appname' => 'files_sharing', 'script' => 'list.php', 'order' => 15, - 'name' => new \OC_L10N_String(new \OC_L10N('files_sharing'), 'Shared with others', []), + 'name' => (string)new \OC_L10N_String(new \OC_L10N('files_sharing'), 'Shared with others', []), 'active' => false, 'icon' => '', ], @@ -227,7 +236,7 @@ class ViewControllerTest extends TestCase { 'appname' => 'files_sharing', 'script' => 'list.php', 'order' => 20, - 'name' => new \OC_L10N_String(new \OC_L10N('files_sharing'), 'Shared by link', []), + 'name' => (string)new \OC_L10N_String(new \OC_L10N('files_sharing'), 'Shared by link', []), 'active' => false, 'icon' => '', ], @@ -236,7 +245,7 @@ class ViewControllerTest extends TestCase { 'appname' => 'systemtags', 'script' => 'list.php', 'order' => 25, - 'name' => new \OC_L10N_String(new \OC_L10N('systemtags'), 'Tags', []), + 'name' => (string)new \OC_L10N_String(new \OC_L10N('systemtags'), 'Tags', []), 'active' => false, 'icon' => '', ], @@ -245,7 +254,7 @@ class ViewControllerTest extends TestCase { 'appname' => 'files_trashbin', 'script' => 'list.php', 'order' => 50, - 'name' => new \OC_L10N_String(new \OC_L10N('files_trashbin'), 'Deleted files', []), + 'name' => (string)new \OC_L10N_String(new \OC_L10N('files_trashbin'), 'Deleted files', []), 'active' => false, 'icon' => '', ], @@ -273,6 +282,10 @@ class ViewControllerTest extends TestCase { 'content' => null, ], [ + 'id' => 'recent', + 'content' => null, + ], + [ 'id' => 'favorites', 'content' => null, ], |