From 6c5696d3a84ff71fc5ddb53b490bbc77f5c119f5 Mon Sep 17 00:00:00 2001 From: Christoph Wurst Date: Tue, 12 Apr 2016 17:10:09 +0200 Subject: [PATCH] filter hidden files on the web interface add checkbox to toggle show/hide hidden files persist show hidden setting fix settings menu layout test ApiController::showHiddenFiles don't show hidden files by default Store config in Backbone model and inject it into FileList Filter files only temporarily when rending the file list Fix file rename validation --- apps/files/appinfo/routes.php | 5 ++ apps/files/controller/apicontroller.php | 12 +++++ apps/files/controller/viewcontroller.php | 3 ++ apps/files/css/files.css | 5 ++ apps/files/js/app.js | 51 ++++++++++++++++++- apps/files/js/filelist.js | 46 ++++++++++++++++- apps/files/templates/appnavigation.php | 10 ++-- apps/files/templates/index.php | 1 + .../tests/controller/ViewControllerTest.php | 6 ++- .../tests/controller/apicontrollertest.php | 14 +++++ apps/files_sharing/js/app.js | 9 ++-- apps/files_trashbin/js/app.js | 3 +- apps/systemtags/js/app.js | 3 +- 13 files changed, 155 insertions(+), 13 deletions(-) diff --git a/apps/files/appinfo/routes.php b/apps/files/appinfo/routes.php index 6ad938101a..2291b48e3c 100644 --- a/apps/files/appinfo/routes.php +++ b/apps/files/appinfo/routes.php @@ -54,6 +54,11 @@ $application->registerRoutes( 'url' => '/api/v1/sorting', 'verb' => 'POST' ), + array( + 'name' => 'API#showHiddenFiles', + 'url' => '/api/v1/showhidden', + 'verb' => 'POST' + ), [ 'name' => 'view#index', 'url' => '/', diff --git a/apps/files/controller/apicontroller.php b/apps/files/controller/apicontroller.php index 43d426476f..072498c7b5 100644 --- a/apps/files/controller/apicontroller.php +++ b/apps/files/controller/apicontroller.php @@ -224,4 +224,16 @@ class ApiController extends Controller { return new Response(); } + /** + * Toggle default for showing/hiding hidden files + * + * @NoAdminRequired + * + * @param bool $show + */ + public function showHiddenFiles($show) { + $this->config->setUserValue($this->userSession->getUser()->getUID(), 'files', 'show_hidden', (int) $show); + return new Response(); + } + } diff --git a/apps/files/controller/viewcontroller.php b/apps/files/controller/viewcontroller.php index 6c5f4c6d2a..9fe3452133 100644 --- a/apps/files/controller/viewcontroller.php +++ b/apps/files/controller/viewcontroller.php @@ -67,6 +67,7 @@ class ViewController extends Controller { * @param IL10N $l10n * @param IConfig $config * @param EventDispatcherInterface $eventDispatcherInterface + * @param IUserSession $userSession */ public function __construct($appName, IRequest $request, @@ -222,6 +223,8 @@ class ViewController extends Controller { $user = $this->userSession->getUser()->getUID(); $params['defaultFileSorting'] = $this->config->getUserValue($user, 'files', 'file_sorting', 'name'); $params['defaultFileSortingDirection'] = $this->config->getUserValue($user, 'files', 'file_sorting_direction', 'asc'); + $showHidden = (bool) $this->config->getUserValue($this->userSession->getUser()->getUID(), 'files', 'show_hidden', false); + $params['showHiddenFiles'] = $showHidden ? 1 : 0; $params['appNavigation'] = $nav; $params['appContents'] = $contentItems; $this->navigationManager->setActiveEntry('files_index'); diff --git a/apps/files/css/files.css b/apps/files/css/files.css index d20ab102ba..373739071e 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -2,6 +2,11 @@ This file is licensed under the Affero General Public License version 3 or later. See the COPYING-README file. */ +/* SETTINGS */ +#files-setting-showhidden { + padding-bottom: 8px; +} + /* FILE MENU */ .actions { padding:5px; height:32px; display: inline-block; float: left; } .actions input, .actions button, .actions .button { margin:0; float:left; } diff --git a/apps/files/js/app.js b/apps/files/js/app.js index 4ed805d268..eac080a009 100644 --- a/apps/files/js/app.js +++ b/apps/files/js/app.js @@ -11,7 +11,7 @@ * */ -/* global dragOptions, folderDropOptions */ +/* global dragOptions, folderDropOptions, OC */ (function() { if (!OCA.Files) { @@ -40,11 +40,23 @@ */ fileList: null, + /** + * Backbone model for storing files preferences + */ + _filesConfig: null, + /** * Initializes the files app */ initialize: function() { this.navigation = new OCA.Files.Navigation($('#app-navigation')); + this.$showHiddenFiles = $('input#showhiddenfilesToggle'); + var showHidden = $('#showHiddenFiles').val() === "1"; + this.$showHiddenFiles.prop('checked', showHidden); + + this._filesConfig = new OC.Backbone.Model({ + showhidden: showHidden + }); var urlParams = OC.Util.History.parseUrlQuery(); var fileActions = new OCA.Files.FileActions(); @@ -76,7 +88,8 @@ sorting: { mode: $('#defaultFileSorting').val(), direction: $('#defaultFileSortingDirection').val() - } + }, + config: this._filesConfig, } ); this.files.initialize(); @@ -90,6 +103,8 @@ this._setupEvents(); // trigger URL change event handlers this._onPopState(urlParams); + + this._debouncedPersistShowHiddenFilesState = _.debounce(this._persistShowHiddenFilesState, 1200); }, /** @@ -143,6 +158,14 @@ return this.navigation.getActiveItem(); }, + /** + * + * @returns {Backbone.Model} + */ + getFilesConfig: function() { + return this._filesConfig; + }, + /** * Setup events based on URL changes */ @@ -154,6 +177,30 @@ $('#app-content').delegate('>div', 'changeViewerMode', _.bind(this._onChangeViewerMode, this)); $('#app-navigation').on('itemChanged', _.bind(this._onNavigationChanged, this)); + this.$showHiddenFiles.on('change', _.bind(this._onShowHiddenFilesChange, this)); + }, + + /** + * Toggle showing hidden files according to the settings checkbox + * + * @returns {undefined} + */ + _onShowHiddenFilesChange: function() { + var show = this.$showHiddenFiles.is(':checked'); + this._filesConfig.set('showhidden', show); + this._debouncedPersistShowHiddenFilesState(); + }, + + /** + * Persist show hidden preference on ther server + * + * @returns {undefined} + */ + _persistShowHiddenFilesState: function() { + var show = this._filesConfig.get('showhidden'); + $.post(OC.generateUrl('/apps/files/api/v1/showhidden'), { + show: show + }); }, /** diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 7de64f8ade..79dc42da8f 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -144,6 +144,11 @@ */ _filter: '', + /** + * @type Backbone.Model + */ + _filesConfig: null, + /** * Sort attribute * @type String @@ -198,6 +203,15 @@ return; } + if (options.config) { + this._filesConfig = options.config; + } else { + this._filesConfig = OCA.Files.App.getFilesConfig(); + } + this._filesConfig.on('change:showhidden', function() { + self.setFiles(self.files); + }); + if (options.dragOptions) { this._dragOptions = options.dragOptions; } @@ -847,6 +861,10 @@ * @return array of DOM elements of the newly added files */ _nextPage: function(animate) { + // Save full files list while rendering + var allFiles = this.files; + this.files = this._filterHiddenFiles(this.files); + var index = this.$fileList.children().length, count = this.pageSize(), hidden, @@ -893,6 +911,10 @@ } }, 0); } + + // Restore full files list after rendering + this.files = allFiles; + return newTrs; }, @@ -930,24 +952,46 @@ // clear "Select all" checkbox this.$el.find('.select-all').prop('checked', false); + // Save full files list while rendering + var allFiles = this.files; + this.files = this._filterHiddenFiles(this.files); + this.isEmpty = this.files.length === 0; this._nextPage(); this.updateEmptyContent(); - this.fileSummary.calculate(filesArray); + this.fileSummary.calculate(this.files); this._selectedFiles = {}; this._selectionSummary.clear(); this.updateSelectionSummary(); $(window).scrollTop(0); + // Restore full files list after rendering + this.files = allFiles; + this.$fileList.trigger(jQuery.Event('updated')); _.defer(function() { self.$el.closest('#app-content').trigger(jQuery.Event('apprendered')); }); }, + /** + * Filter hidden files of the given filesArray (dot-files) + * + * @param filesArray files to be filtered + * @returns {array} + */ + _filterHiddenFiles: function(files) { + if (this._filesConfig.get('showhidden')) { + return files; + } + return _.filter(files, function(file) { + return file.name.indexOf('.') !== 0; + }); + }, + /** * Returns the icon URL matching the given file info * diff --git a/apps/files/templates/appnavigation.php b/apps/files/templates/appnavigation.php index 39a5875f3d..9c79f80671 100644 --- a/apps/files/templates/appnavigation.php +++ b/apps/files/templates/appnavigation.php @@ -16,9 +16,13 @@
- - - t('Use this address to access your Files via WebDAV', array(link_to_docs('user-webdav'))));?> +
+ + +
+ + + t('Use this address to access your Files via WebDAV', array(link_to_docs('user-webdav'))));?>
diff --git a/apps/files/templates/index.php b/apps/files/templates/index.php index db464ad2ec..7281edd3ae 100644 --- a/apps/files/templates/index.php +++ b/apps/files/templates/index.php @@ -20,4 +20,5 @@ + 'MyName', 'ownerDisplayName' => 'MyDisplayName', ])); - $this->config->expects($this->exactly(2)) + $this->config->expects($this->exactly(3)) ->method('getUserValue') ->will($this->returnValueMap([ [$this->user->getUID(), 'files', 'file_sorting', 'name', 'name'], - [$this->user->getUID(), 'files', 'file_sorting_direction', 'asc', 'asc'] + [$this->user->getUID(), 'files', 'file_sorting_direction', 'asc', 'asc'], + [$this->user->getUID(), 'files', 'show_hidden', false, false], ])); $this->config @@ -244,6 +245,7 @@ class ViewControllerTest extends TestCase { 'isPublic' => false, 'defaultFileSorting' => 'name', 'defaultFileSortingDirection' => 'asc', + 'showHiddenFiles' => false, 'mailNotificationEnabled' => 'no', 'mailPublicNotificationEnabled' => 'no', 'allowShareWithLink' => 'yes', diff --git a/apps/files/tests/controller/apicontrollertest.php b/apps/files/tests/controller/apicontrollertest.php index 59f53e8ee8..2eba7d62fe 100644 --- a/apps/files/tests/controller/apicontrollertest.php +++ b/apps/files/tests/controller/apicontrollertest.php @@ -1,4 +1,5 @@ * @author Lukas Reschke @@ -382,4 +383,17 @@ class ApiControllerTest extends TestCase { $this->assertEquals($expected, $result); } + public function testShowHiddenFiles() { + $show = false; + + $this->config->expects($this->once()) + ->method('setUserValue') + ->with($this->user->getUID(), 'files', 'show_hidden', $show); + + $expected = new Http\Response(); + $actual = $this->apiController->showHiddenFiles($show); + + $this->assertEquals($expected, $actual); + } + } diff --git a/apps/files_sharing/js/app.js b/apps/files_sharing/js/app.js index af198208de..6f12b3d445 100644 --- a/apps/files_sharing/js/app.js +++ b/apps/files_sharing/js/app.js @@ -33,7 +33,8 @@ OCA.Sharing.App = { id: 'shares.self', scrollContainer: $('#app-content'), sharedWithUser: true, - fileActions: this._createFileActions() + fileActions: this._createFileActions(), + config: OCA.Files.App.getFilesConfig() } ); @@ -55,7 +56,8 @@ OCA.Sharing.App = { id: 'shares.others', scrollContainer: $('#app-content'), sharedWithUser: false, - fileActions: this._createFileActions() + fileActions: this._createFileActions(), + config: OCA.Files.App.getFilesConfig() } ); @@ -77,7 +79,8 @@ OCA.Sharing.App = { id: 'shares.link', scrollContainer: $('#app-content'), linksOnly: true, - fileActions: this._createFileActions() + fileActions: this._createFileActions(), + config: OCA.Files.App.getFilesConfig() } ); diff --git a/apps/files_trashbin/js/app.js b/apps/files_trashbin/js/app.js index 771ea90bc1..fd3d5db32f 100644 --- a/apps/files_trashbin/js/app.js +++ b/apps/files_trashbin/js/app.js @@ -29,7 +29,8 @@ OCA.Trashbin.App = { scrollContainer: $('#app-content'), fileActions: this._createFileActions(), detailsViewEnabled: false, - scrollTo: urlParams.scrollto + scrollTo: urlParams.scrollto, + config: OCA.Files.App.getFilesConfig() } ); }, diff --git a/apps/systemtags/js/app.js b/apps/systemtags/js/app.js index d28514358c..e027c0be12 100644 --- a/apps/systemtags/js/app.js +++ b/apps/systemtags/js/app.js @@ -28,7 +28,8 @@ { id: 'systemtags', scrollContainer: $('#app-content'), - fileActions: this._createFileActions() + fileActions: this._createFileActions(), + config: OCA.Files.App.getFilesConfig() } );