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 @@