diff options
Diffstat (limited to 'apps/files/js')
-rw-r--r-- | apps/files/js/app.js | 26 | ||||
-rw-r--r-- | apps/files/js/breadcrumb.js | 10 | ||||
-rw-r--r-- | apps/files/js/file-upload.js | 3 | ||||
-rw-r--r-- | apps/files/js/fileactions.js | 2 | ||||
-rw-r--r-- | apps/files/js/filelist.js | 114 | ||||
-rw-r--r-- | apps/files/js/files.js | 72 | ||||
-rw-r--r-- | apps/files/js/keyboardshortcuts.js | 3 | ||||
-rw-r--r-- | apps/files/js/navigation.js | 21 |
8 files changed, 156 insertions, 95 deletions
diff --git a/apps/files/js/app.js b/apps/files/js/app.js index 6cdb339b22d..9155fb38cdb 100644 --- a/apps/files/js/app.js +++ b/apps/files/js/app.js @@ -11,6 +11,7 @@ * */ +/* global dragOptions, folderDropOptions */ (function() { if (!OCA.Files) { @@ -24,11 +25,16 @@ this.navigation = new OCA.Files.Navigation($('#app-navigation')); // TODO: ideally these should be in a separate class / app (the embedded "all files" app) - this.fileList = OCA.Files.FileList; this.fileActions = OCA.Files.FileActions; this.files = OCA.Files.Files; - this.fileList = new OCA.Files.FileList($('#app-content-files')); + this.fileList = new OCA.Files.FileList( + $('#app-content-files'), { + scrollContainer: $('#app-content'), + dragOptions: dragOptions, + folderDropOptions: folderDropOptions + } + ); this.files.initialize(); this.fileActions.registerDefaultActions(this.fileList); this.fileList.setFileActions(this.fileActions); @@ -58,7 +64,8 @@ OC.Util.History.addOnPopStateHandler(_.bind(this._onPopState, this)); // detect when app changed their current directory - $('#app-content>div').on('changeDirectory', _.bind(this._onDirectoryChanged, this)); + $('#app-content').delegate('>div', 'changeDirectory', _.bind(this._onDirectoryChanged, this)); + $('#app-content').delegate('>div', 'changeViewerMode', _.bind(this._onChangeViewerMode, this)); $('#app-navigation').on('itemChanged', _.bind(this._onNavigationChanged, this)); }, @@ -88,6 +95,16 @@ }, /** + * Event handler for when an app notifies that it needs space + * for viewer mode. + */ + _onChangeViewerMode: function(e) { + var state = !!e.viewerModeEnabled; + $('#app-navigation').toggleClass('hidden', state); + $('.app-files').toggleClass('viewer-mode no-sidebar', state); + }, + + /** * Event handler for when the URL changed */ _onPopState: function(params) { @@ -96,6 +113,9 @@ view: 'files' }, params); var lastId = this.navigation.getActiveItem(); + if (!this.navigation.itemExists(params.view)) { + params.view = 'files'; + } this.navigation.setActiveItem(params.view, {silent: true}); if (lastId !== this.navigation.getActiveItem()) { this.navigation.getActiveContainer().trigger(new $.Event('show')); diff --git a/apps/files/js/breadcrumb.js b/apps/files/js/breadcrumb.js index 1a77481b678..c017d710d6d 100644 --- a/apps/files/js/breadcrumb.js +++ b/apps/files/js/breadcrumb.js @@ -159,7 +159,11 @@ this.totalWidth = 64; // FIXME: this class should not know about global elements if ( $('#navigation').length ) { - this.totalWidth += $('#navigation').get(0).offsetWidth; + this.totalWidth += $('#navigation').outerWidth(); + } + + if ( $('#app-navigation').length && !$('#app-navigation').hasClass('hidden')) { + this.totalWidth += $('#app-navigation').outerWidth(); } this.hiddenBreadcrumbs = 0; @@ -167,8 +171,8 @@ this.totalWidth += $(this.breadcrumbs[i]).get(0).offsetWidth; } - $.each($('#controls .actions>div'), function(index, action) { - self.totalWidth += $(action).get(0).offsetWidth; + $.each($('#controls .actions'), function(index, action) { + self.totalWidth += $(action).outerWidth(); }); }, diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index 0ca2852f9f6..6b0ca793681 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -460,7 +460,6 @@ OC.Upload = { $('#uploadprogresswrapper input.stop').fadeOut(); $('#uploadprogressbar').fadeOut(); - Files.updateStorageStatistics(); }); fileupload.on('fileuploadfail', function(e, data) { OC.Upload.log('progress handle fileuploadfail', e, data); @@ -471,8 +470,6 @@ OC.Upload = { } }); - } else { - console.log('skipping file progress because your browser is broken'); } } diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js index 7be599871e4..b9cd9816d4c 100644 --- a/apps/files/js/fileactions.js +++ b/apps/files/js/fileactions.js @@ -209,6 +209,8 @@ * 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 this.register('all', 'Delete', OC.PERMISSION_DELETE, function () { return OC.imagePath('core', 'actions/delete'); }, function (filename) { diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index de34d932b11..38766e2b801 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -8,21 +8,20 @@ * */ -/* global Files */ -/* global dragOptions, folderDropOptions */ (function() { /** * The FileList class manages a file list view. * A file list view consists of a controls bar and * a file list table. */ - var FileList = function($el) { - this.initialize($el); + var FileList = function($el, options) { + this.initialize($el, options); }; FileList.prototype = { SORT_INDICATOR_ASC_CLASS: 'icon-triangle-s', SORT_INDICATOR_DESC_CLASS: 'icon-triangle-n', + id: 'files', appName: t('files', 'Files'), isEmpty: true, useUndo:true, @@ -95,16 +94,35 @@ */ _currentDirectory: null, + _dragOptions: null, + _folderDropOptions: null, + /** * Initialize the file list and its components + * + * @param $el container element with existing markup for the #controls + * and a table + * @param options map of options, see other parameters + * @param scrollContainer scrollable container, defaults to $(window) + * @param dragOptions drag options, disabled by default + * @param folderDropOptions folder drop options, disabled by default */ - initialize: function($el) { + initialize: function($el, options) { var self = this; + options = options || {}; if (this.initialized) { return; } + if (options.dragOptions) { + this._dragOptions = options.dragOptions; + } + if (options.folderDropOptions) { + this._folderDropOptions = options.folderDropOptions; + } + this.$el = $el; + this.$container = options.scrollContainer || $(window); this.$table = $el.find('table:first'); this.$fileList = $el.find('#fileList'); this.fileActions = OCA.Files.FileActions; @@ -116,13 +134,17 @@ this.setSort('name', 'asc'); - this.breadcrumb = new OCA.Files.BreadCrumb({ + var breadcrumbOptions = { onClick: _.bind(this._onClickBreadCrumb, this), - onDrop: _.bind(this._onDropOnBreadCrumb, this), - getCrumbUrl: function(part, index) { + getCrumbUrl: function(part) { return self.linkTo(part.dir); } - }); + }; + // if dropping on folders is allowed, then also allow on breadcrumbs + if (this._folderDropOptions) { + breadcrumbOptions.onDrop = _.bind(this._onDropOnBreadCrumb, this); + } + this.breadcrumb = new OCA.Files.BreadCrumb(breadcrumbOptions); this.$el.find('#controls').prepend(this.breadcrumb.$el); @@ -137,14 +159,13 @@ this.$fileList.on('click','td.filename>a.name', _.bind(this._onClickFile, this)); this.$fileList.on('change', 'td.filename>input:checkbox', _.bind(this._onClickFileCheckbox, this)); this.$el.on('urlChanged', _.bind(this._onUrlChanged, this)); - this.$el.find('#select_all').click(_.bind(this._onClickSelectAll, this)); + this.$el.find('.select-all').click(_.bind(this._onClickSelectAll, this)); this.$el.find('.download').click(_.bind(this._onClickDownloadSelected, this)); this.$el.find('.delete-selected').click(_.bind(this._onClickDeleteSelected, this)); this.setupUploadEvents(); - // FIXME: only do this when visible - $(window).scroll(function(e) {self._onScroll(e);}); + this.$container.on('scroll', _.bind(this._onScroll, this)); }, /** @@ -182,7 +203,7 @@ delete this._selectedFiles[$tr.data('id')]; this._selectionSummary.remove(data); } - this.$el.find('#select_all').prop('checked', this._selectionSummary.getTotal() === this.files.length); + this.$el.find('.select-all').prop('checked', this._selectionSummary.getTotal() === this.files.length); }, /** @@ -327,8 +348,12 @@ } }, + /** + * Event handler for when scrolling the list container. + * This appends/renders the next page of entries when reaching the bottom. + */ _onScroll: function(e) { - if ($(window).scrollTop() + $(window).height() > $(document).height() - 500) { + if (this.$container.scrollTop() + this.$container.height() > this.$el.height() - 100) { this._nextPage(true); } }, @@ -460,7 +485,7 @@ this.$fileList.empty(); // clear "Select all" checkbox - this.$el.find('#select_all').prop('checked', false); + this.$el.find('.select-all').prop('checked', false); this.isEmpty = this.files.length === 0; this._nextPage(); @@ -469,10 +494,6 @@ this.updateEmptyContent(); this.$fileList.trigger(jQuery.Event("fileActionsReady")); - // "Files" might not be loaded in extending apps - if (window.Files) { - Files.setupDragAndDrop(); - } this.fileSummary.calculate(filesArray); @@ -540,7 +561,8 @@ else { linkUrl = this.getDownloadUrl(name, this.getCurrentDirectory()); } - td.append('<input id="select-' + fileData.id + '" type="checkbox" /><label for="select-' + fileData.id + '"></label>'); + td.append('<input id="select-' + this.id + '-' + fileData.id + + '" type="checkbox" /><label for="select-' + this.id + '-' + fileData.id + '"></label>'); var linkElem = $('<a></a>').attr({ "class": "name", "href": linkUrl @@ -694,12 +716,12 @@ // TODO: move dragging to FileActions ? // enable drag only for deletable files - if (permissions & OC.PERMISSION_DELETE) { - filenameTd.draggable(dragOptions); + if (this._dragOptions && permissions & OC.PERMISSION_DELETE) { + filenameTd.draggable(this._dragOptions); } // allow dropping on folders - if (fileData.type === 'dir') { - filenameTd.droppable(folderDropOptions); + if (this._folderDropOptions && fileData.type === 'dir') { + filenameTd.droppable(this._folderDropOptions); } if (options.hidden) { @@ -780,8 +802,7 @@ * @param changeUrl true to also update the URL, false otherwise (default) */ _setCurrentDir: function(targetDir, changeUrl) { - var url, - previousDir = this.getCurrentDirectory(), + var previousDir = this.getCurrentDirectory(), baseDir = OC.basename(targetDir); if (baseDir !== '') { @@ -832,7 +853,7 @@ var self = this; this._selectedFiles = {}; this._selectionSummary.clear(); - this.$el.find('#select_all').prop('checked', false); + this.$el.find('.select-all').prop('checked', false); this.showMask(); if (this._reloadCall) { this._reloadCall.abort(); @@ -873,7 +894,7 @@ // TODO: should rather return upload file size through // the files list ajax call - Files.updateStorageStatistics(true); + this.updateStorageStatistics(true); if (result.data.permissions) { this.setDirectoryPermissions(result.data.permissions); @@ -882,12 +903,16 @@ this.setFiles(result.data.files); }, + updateStorageStatistics: function(force) { + OCA.Files.Files.updateStorageStatistics(this.getCurrentDirectory(), force); + }, + getAjaxUrl: function(action, params) { - return Files.getAjaxUrl(action, params); + return OCA.Files.Files.getAjaxUrl(action, params); }, getDownloadUrl: function(files, dir) { - return Files.getDownloadUrl(files, dir || this.getCurrentDirectory()); + return OCA.Files.Files.getDownloadUrl(files, dir || this.getCurrentDirectory()); }, /** @@ -994,6 +1019,7 @@ setViewerMode: function(show){ this.showActions(!show); this.$el.find('#filestable').toggleClass('hidden', show); + this.$el.trigger(new $.Event('changeViewerMode', {viewerModeEnabled: show})); }, /** * Removes a file entry from the list @@ -1014,7 +1040,7 @@ this._selectFileEl(fileEl, false); this.updateSelectionSummary(); } - if (fileEl.data('permissions') & OC.PERMISSION_DELETE) { + if (this._dragOptions && (fileEl.data('permissions') & OC.PERMISSION_DELETE)) { // file is only draggable when delete permissions are set fileEl.find('td.filename').draggable('destroy'); } @@ -1109,7 +1135,8 @@ OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error')); } $td.css('background-image', oldBackgroundImage); - }); + } + ); }); }, @@ -1144,7 +1171,7 @@ var filename = input.val(); if (filename !== oldname) { // Files.isFileNameValid(filename) throws an exception itself - Files.isFileNameValid(filename); + OCA.Files.Files.isFileNameValid(filename); if (self.inList(filename)) { throw t('files', '{new_name} already exists', {new_name: filename}); } @@ -1299,7 +1326,7 @@ self.updateEmptyContent(); self.fileSummary.update(); self.updateSelectionSummary(); - Files.updateStorageStatistics(); + self.updateStorageStatistics(); } else { if (result.status === 'error' && result.data.message) { OC.Notification.show(result.data.message); @@ -1406,6 +1433,7 @@ */ updateSelectionSummary: function() { var summary = this._selectionSummary.summary; + var canDelete; if (summary.totalFiles === 0 && summary.totalDirs === 0) { this.$el.find('#headerName a.name>span:first').text(t('files','Name')); this.$el.find('#headerSize a>span:first').text(t('files','Size')); @@ -1414,6 +1442,7 @@ this.$el.find('.selectedActions').addClass('hidden'); } else { + canDelete = (this.getDirectoryPermissions() & OC.PERMISSION_DELETE); this.$el.find('.selectedActions').removeClass('hidden'); this.$el.find('#headerSize a>span:first').text(OC.Util.humanFileSize(summary.totalSize)); var selection = ''; @@ -1429,6 +1458,7 @@ this.$el.find('#headerName a.name>span:first').text(selection); this.$el.find('#modified a>span:first').text(''); this.$el.find('table').addClass('multiselect'); + this.$el.find('.delete-selected').toggleClass('hidden', !canDelete); } }, @@ -1437,7 +1467,7 @@ * @return true if all files are selected, false otherwise */ isAllSelected: function() { - return this.$el.find('#select_all').prop('checked'); + return this.$el.find('.select-all').prop('checked'); }, /** @@ -1475,7 +1505,10 @@ } return name; }, - + + /** + * Setup file upload events related to the file-upload plugin + */ setupUploadEvents: function() { var self = this; @@ -1486,6 +1519,11 @@ OC.Upload.log('filelist handle fileuploaddrop', e, data); var dropTarget = $(e.originalEvent.target).closest('tr, .crumb'); + // check if dropped inside this list at all + if (dropTarget && !self.$el.has(dropTarget).length) { + return false; + } + if (dropTarget && (dropTarget.data('type') === 'dir' || dropTarget.hasClass('crumb'))) { // drag&drop upload to folder // remember as context @@ -1515,7 +1553,7 @@ }; } else { // cancel uploads to current dir if no permission - var isCreatable = (this.getDirectoryPermissions() & OC.PERMISSION_CREATE) !== 0; + var isCreatable = (self.getDirectoryPermissions() & OC.PERMISSION_CREATE) !== 0; if (!isCreatable) { return false; } @@ -1655,6 +1693,7 @@ uploadText.fadeOut(); uploadText.attr('currentUploads', 0); } + self.updateStorageStatistics(); }); fileUploadStart.on('fileuploadfail', function(e, data) { OC.Upload.log('filelist handle fileuploadfail', e, data); @@ -1668,6 +1707,7 @@ uploadText.fadeOut(); uploadText.attr('currentUploads', 0); } + self.updateStorageStatistics(); }); } diff --git a/apps/files/js/files.js b/apps/files/js/files.js index 9ab8d0fcb53..81588c2f961 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -15,13 +15,8 @@ (function() { var Files = { // file space size sync - _updateStorageStatistics: function() { - // FIXME - console.warn('FIXME: storage statistics!'); - return; - Files._updateStorageStatisticsTimeout = null; - var currentDir = OCA.Files.FileList.getCurrentDirectory(), - state = Files.updateStorageStatistics; + _updateStorageStatistics: function(currentDir) { + var state = Files.updateStorageStatistics; if (state.dir){ if (state.dir === currentDir) { return; @@ -36,20 +31,26 @@ Files.updateMaxUploadFilesize(response); }); }, - updateStorageStatistics: function(force) { + /** + * Update storage statistics such as free space, max upload, + * etc based on the given directory. + * + * Note this function is debounced to avoid making too + * many ajax calls in a row. + * + * @param dir directory + * @param force whether to force retrieving + */ + updateStorageStatistics: function(dir, force) { if (!OC.currentUser) { return; } - // debounce to prevent calling too often - if (Files._updateStorageStatisticsTimeout) { - clearTimeout(Files._updateStorageStatisticsTimeout); - } if (force) { - Files._updateStorageStatistics(); + Files._updateStorageStatistics(dir); } else { - Files._updateStorageStatisticsTimeout = setTimeout(Files._updateStorageStatistics, 250); + Files._updateStorageStatisticsDebounced(dir); } }, @@ -149,24 +150,6 @@ } }, - // TODO: move to FileList class - setupDragAndDrop: function() { - var $fileList = $('#fileList'); - - //drag/drop of files - $fileList.find('tr td.filename').each(function(i,e) { - if ($(e).parent().data('permissions') & OC.PERMISSION_DELETE) { - $(e).draggable(dragOptions); - } - }); - - $fileList.find('tr[data-type="dir"] td.filename').each(function(i,e) { - if ($(e).parent().data('permissions') & OC.PERMISSION_CREATE) { - $(e).droppable(folderDropOptions); - } - }); - }, - /** * Returns the download URL of the given file(s) * @param filename string or array of file names to download @@ -243,9 +226,7 @@ initialize: function() { Files.getMimeIcon.cache = {}; Files.displayEncryptionWarning(); - Files.bindKeyboardShortcuts(document, jQuery); - - Files.setupDragAndDrop(); + Files.bindKeyboardShortcuts(document, $); // TODO: move file list related code (upload) to OCA.Files.FileList $('#file_action_panel').attr('activeAction', false); @@ -259,7 +240,6 @@ // Trigger cancelling of file upload $('#uploadprogresswrapper .stop').on('click', function() { OC.Upload.cancelUploads(); - OCA.Files.FileList.updateSelectionSummary(); }); // drag&drop support using jquery.fileupload @@ -275,18 +255,19 @@ setTimeout(Files.displayStorageWarnings, 100); OC.Notification.setDefault(Files.displayStorageWarnings); - // only possible at the moment if user is logged in - if (OC.currentUser) { + // only possible at the moment if user is logged in or the files app is loaded + if (OC.currentUser && OCA.Files.App) { // start on load - we ask the server every 5 minutes var updateStorageStatisticsInterval = 5*60*1000; - var updateStorageStatisticsIntervalId = setInterval(Files.updateStorageStatistics, updateStorageStatisticsInterval); + var updateStorageStatisticsIntervalId = setInterval(OCA.Files.App.fileList.updateStorageStatistics, updateStorageStatisticsInterval); + // TODO: this should also stop when switching to another view // Use jquery-visibility to de-/re-activate file stats sync if ($.support.pageVisibility) { $(document).on({ 'show.visibility': function() { if (!updateStorageStatisticsIntervalId) { - updateStorageStatisticsIntervalId = setInterval(Files.updateStorageStatistics, updateStorageStatisticsInterval); + updateStorageStatisticsIntervalId = setInterval(OCA.Files.App.fileList.updateStorageStatistics, updateStorageStatisticsInterval); } }, 'hide.visibility': function() { @@ -314,6 +295,7 @@ } } + Files._updateStorageStatisticsDebounced = _.debounce(Files._updateStorageStatistics, 250); OCA.Files.Files = Files; })(); @@ -349,7 +331,9 @@ function scanFiles(force, dir, users) { scannerEventSource.listen('done',function(count) { scanFiles.scanning=false; console.log('done after ' + count + ' files'); - OCA.Files.Files.updateStorageStatistics(); + if (OCA.Files.App) { + OCA.Files.App.fileList.updateStorageStatistics(true); + } }); scannerEventSource.listen('user',function(user) { console.log('scanning files for ' + user); @@ -360,7 +344,7 @@ scanFiles.scanning=false; // TODO: move to FileList var createDragShadow = function(event) { //select dragged file - var FileList = OCA.Files.FileList; + var FileList = OCA.Files.App.fileList; var isDragSelected = $(event.target).parents('tr').find('td input:first').prop('checked'); if (!isDragSelected) { //select dragged file @@ -395,7 +379,7 @@ var createDragShadow = function(event) { newtr.find('td.filename').attr('style','background-image:url('+OC.imagePath('core', 'filetypes/folder.png')+')'); } else { var path = dir + '/' + elem.name; - OCA.Files.App.fileList.lazyLoadPreview(path, elem.mime, function(previewpath) { + OCA.Files.App.files.lazyLoadPreview(path, elem.mime, function(previewpath) { newtr.find('td.filename').attr('style','background-image:url('+previewpath+')'); }, null, null, elem.etag); } @@ -446,7 +430,7 @@ var folderDropOptions = { hoverClass: "canDrop", drop: function( event, ui ) { // don't allow moving a file into a selected folder - var FileList = OCA.Files.FileList; + var FileList = OCA.Files.App.fileList; if ($(event.target).parents('tr').find('td input:first').prop('checked') === true) { return false; } diff --git a/apps/files/js/keyboardshortcuts.js b/apps/files/js/keyboardshortcuts.js index 9d6c3ae8c33..b2f2cd0e582 100644 --- a/apps/files/js/keyboardshortcuts.js +++ b/apps/files/js/keyboardshortcuts.js @@ -12,7 +12,6 @@ * enter: open file/folder * delete/backspace: delete file/folder *****************************/ -var Files = Files || {}; (function(Files) { var keys = []; var keyCodes = { @@ -167,4 +166,4 @@ var Files = Files || {}; removeA(keys, event.keyCode); }); }; -})(Files); +})((OCA.Files && OCA.Files.Files) || {}); diff --git a/apps/files/js/navigation.js b/apps/files/js/navigation.js index c4a02ee7549..c58a284e83f 100644 --- a/apps/files/js/navigation.js +++ b/apps/files/js/navigation.js @@ -73,25 +73,40 @@ * @param array options "silent" to not trigger event */ setActiveItem: function(itemId, options) { + var oldItemId = this._activeItem; if (itemId === this._activeItem) { + if (!options || !options.silent) { + this.$el.trigger( + new $.Event('itemChanged', {itemId: itemId, previousItemId: oldItemId}) + ); + } return; } - this._activeItem = itemId; this.$el.find('li').removeClass('selected'); if (this.$currentContent) { this.$currentContent.addClass('hidden'); this.$currentContent.trigger(jQuery.Event('hide')); } + this._activeItem = itemId; + this.$el.find('li[data-id=' + itemId + ']').addClass('selected'); this.$currentContent = $('#app-content-' + itemId); this.$currentContent.removeClass('hidden'); - this.$el.find('li[data-id=' + itemId + ']').addClass('selected'); if (!options || !options.silent) { this.$currentContent.trigger(jQuery.Event('show')); - this.$el.trigger(new $.Event('itemChanged', {itemId: itemId})); + this.$el.trigger( + new $.Event('itemChanged', {itemId: itemId, previousItemId: oldItemId}) + ); } }, /** + * Returns whether a given item exists + */ + itemExists: function(itemId) { + return this.$el.find('li[data-id=' + itemId + ']').length; + }, + + /** * Event handler for when clicking on an item. */ _onClickItem: function(ev) { |