- fixed upload and storage statistics - fixed infinite scroll to use the correct contain for scroll detection - fixed unit test that sometimes fail for rename case - controls are now sticky again - fixed selection overlay to be aligned with the table - fixed "select all" checkbox that had id conflicts - fixed public page - fixed global actions permissions detection - fix when URL contains an invalid view id - viewer mode now hides the sidebar (ex: text editor) - added unit tests for trashbin - clean up storage info in template (most is retrieved via ajax call now)tags/v7.0.0alpha2
@@ -3,10 +3,11 @@ | |||
See the COPYING-README file. */ | |||
/* FILE MENU */ | |||
.actions { padding:5px; height:32px; width: 100%; } | |||
.actions { padding:5px; height:32px; display: inline-block; float: left; } | |||
.actions input, .actions button, .actions .button { margin:0; float:left; } | |||
.actions .button a { color: #555; } | |||
.actions .button a:hover, .actions .button a:active { color: #333; } | |||
.actions.hidden { display: none; } | |||
#new { | |||
z-index: 1010; | |||
@@ -70,10 +71,12 @@ | |||
/* FILE TABLE */ | |||
.app-files #filestable { | |||
#filestable { | |||
position: relative; | |||
top: 44px; | |||
width: 100%; | |||
} | |||
/* make sure there's enough room for the file actions */ | |||
#body-user #filestable { | |||
min-width: 688px; /* 768 (mobile break) - 80 (nav width) */ | |||
@@ -83,22 +86,33 @@ | |||
} | |||
#filestable tbody tr { background-color:#fff; height:51px; } | |||
.app-files #app-content { | |||
position: relative; | |||
} | |||
/** | |||
* Override global #controls styles | |||
* to be more flexible / relative | |||
*/ | |||
.app-files #controls { | |||
position: static; | |||
left: auto; | |||
top: auto; | |||
#body-user .app-files #controls { | |||
left: 310px; /* main nav bar + sidebar */ | |||
position: fixed; | |||
padding-left: 0px; | |||
} | |||
/* this is mostly for file viewer apps, text editor, etc */ | |||
#body-user .app-files.no-sidebar #controls { | |||
left: 0px; | |||
padding-left: 80px; /* main nav bar */ | |||
} | |||
.app-files #app-navigation { | |||
width: 150px; | |||
width: 230px; | |||
} | |||
.app-files #app-settings { | |||
width: 149px; /* DUH */ | |||
width: 229px; /* DUH */ | |||
} | |||
.app-files #app-settings input { | |||
@@ -205,9 +219,7 @@ table.multiselect thead { | |||
z-index: 10; | |||
-moz-box-sizing: border-box; | |||
box-sizing: border-box; | |||
left: 0; | |||
padding-left: 80px; | |||
width: 100%; | |||
left: 310px; /* main nav bar + sidebar */ | |||
} | |||
table.multiselect thead th { | |||
@@ -294,7 +306,7 @@ table td.filename form { font-size:14px; margin-left:48px; margin-right:48px; } | |||
/* Use label to have bigger clickable size for checkbox */ | |||
#fileList tr td.filename>input[type="checkbox"] + label, | |||
#select_all + label { | |||
.select-all + label { | |||
height: 50px; | |||
position: absolute; | |||
width: 50px; | |||
@@ -308,10 +320,10 @@ table td.filename form { font-size:14px; margin-left:48px; margin-right:48px; } | |||
#fileList tr td.filename>input[type="checkbox"] + label { | |||
left: 0; | |||
} | |||
#select_all + label { | |||
.select-all + label { | |||
top: 0; | |||
} | |||
#select_all { | |||
.select-all { | |||
position: absolute; | |||
top: 18px; | |||
left: 18px; | |||
@@ -359,6 +371,9 @@ a.action>img { max-height:16px; max-width:16px; vertical-align:text-bottom; } | |||
display: inline; | |||
padding: 17px 5px; | |||
} | |||
.selectedActions a.hidden { | |||
display: none; | |||
} | |||
.selectedActions a img { | |||
position:relative; | |||
top:5px; | |||
@@ -434,7 +449,7 @@ table.dragshadow td.size { | |||
} | |||
.mask { | |||
z-index: 50; | |||
position: fixed; | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
right: 0; |
@@ -62,6 +62,9 @@ $user = OC_User::getUser(); | |||
$config = \OC::$server->getConfig(); | |||
// mostly for the home storage's free space | |||
$dirInfo = \OC\Files\Filesystem::getFileInfo('/', false); | |||
$storageInfo=OC_Helper::getStorageInfo('/', $dirInfo); | |||
// if the encryption app is disabled, than everything is fine (INIT_SUCCESSFUL status code) | |||
$encryptionInitStatus = 2; | |||
if (OC_App::isEnabled('files_encryption')) { | |||
@@ -107,6 +110,7 @@ OCP\Util::addscript('files', 'files'); | |||
OCP\Util::addscript('files', 'navigation'); | |||
OCP\Util::addscript('files', 'keyboardshortcuts'); | |||
$tmpl = new OCP\Template('files', 'index', 'user'); | |||
$tmpl->assign('usedSpacePercent', (int)$storageInfo['relative']); | |||
$tmpl->assign('isPublic', false); | |||
$tmpl->assign("encryptedFiles", \OCP\Util::encryptedFiles()); | |||
$tmpl->assign("mailNotificationEnabled", $config->getAppValue('core', 'shareapi_allow_mail_notification', 'yes')); | |||
@@ -114,5 +118,6 @@ $tmpl->assign("allowShareWithLink", $config->getAppValue('core', 'shareapi_allow | |||
$tmpl->assign("encryptionInitStatus", $encryptionInitStatus); | |||
$tmpl->assign('appNavigation', $nav); | |||
$tmpl->assign('appContents', $contentItems); | |||
$tmpl->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true))); | |||
$tmpl->printPage(); |
@@ -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)); | |||
}, | |||
@@ -87,6 +94,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 | |||
*/ | |||
@@ -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')); |
@@ -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(); | |||
}); | |||
}, |
@@ -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'); | |||
} | |||
} | |||
@@ -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) { |
@@ -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(); | |||
}); | |||
} |
@@ -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; | |||
} |
@@ -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) || {}); |
@@ -73,24 +73,39 @@ | |||
* @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. | |||
*/ |
@@ -21,29 +21,17 @@ | |||
* | |||
*/ | |||
// Check if we are a user | |||
OCP\User::checkLoggedIn(); | |||
// dummy, will be refreshed with an ajax call | |||
$dir = '/'; | |||
// information about storage capacities | |||
// FIXME: storage info | |||
/* | |||
$storageInfo=OC_Helper::getStorageInfo($dir, $dirInfo); | |||
$config = \OC::$server->getConfig(); | |||
// TODO: move this to the generated config.js | |||
$publicUploadEnabled = $config->getAppValue('core', 'shareapi_allow_public_upload', 'yes'); | |||
$uploadLimit=OCP\Util::uploadLimit(); | |||
$maxUploadFilesize=OCP\Util::maxUploadFilesize($dir, $freeSpace); | |||
$freeSpace=$storageInfo['free']; | |||
*/ | |||
// renders the controls and table headers template | |||
$tmpl = new OCP\Template('files', 'list', ''); | |||
$tmpl->assign('usedSpacePercent', (int)$storageInfo['relative']); | |||
$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); // minimium of freeSpace and uploadLimit | |||
$tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize)); | |||
$tmpl->assign('uploadLimit', $uploadLimit); // PHP upload limit | |||
$tmpl->assign('freeSpace', $freeSpace); | |||
$tmpl->assign('publicUploadEnabled', $publicUploadEnabled); | |||
$tmpl->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true))); | |||
$tmpl->printPage(); |
@@ -10,7 +10,6 @@ | |||
<!-- config hints for javascript --> | |||
<input type="hidden" name="filesApp" id="filesApp" value="1" /> | |||
<input type="hidden" name="allowZipDownload" id="allowZipDownload" value="<?php p($_['allowZipDownload']); ?>" /> | |||
<input type="hidden" name="usedSpacePercent" id="usedSpacePercent" value="<?php p($_['usedSpacePercent']); ?>" /> | |||
<?php if (!$_['isPublic']) :?> | |||
<input type="hidden" name="encryptedFiles" id="encryptedFiles" value="<?php $_['encryptedFiles'] ? p('1') : p('0'); ?>" /> |
@@ -18,19 +18,20 @@ | |||
</ul> | |||
</div> | |||
<?php endif;?> | |||
<?php /* Note: the template attributes are here only for the public page. These are normally loaded | |||
through ajax instead (updateStorageStatistics). | |||
*/ ?> | |||
<div id="upload" class="button" | |||
title="<?php p($l->t('Upload (max. %s)', array($_['uploadMaxHumanFilesize']))) ?>"> | |||
<?php if($_['uploadMaxFilesize'] >= 0):?> | |||
<input type="hidden" id="max_upload" name="MAX_FILE_SIZE" value="<?php p($_['uploadMaxFilesize']) ?>"> | |||
<?php endif;?> | |||
<input type="hidden" id="upload_limit" value="<?php p($_['uploadLimit']) ?>"> | |||
<input type="hidden" id="free_space" value="<?php p($_['freeSpace']) ?>"> | |||
title="<?php isset($_['uploadMaxHumanFilesize']) ? p($l->t('Upload (max. %s)', array($_['uploadMaxHumanFilesize']))) : '' ?>"> | |||
<input type="hidden" id="max_upload" name="MAX_FILE_SIZE" value="<?php isset($_['uploadMaxFilesize']) ? p($_['uploadMaxFilesize']) : '' ?>"> | |||
<input type="hidden" id="upload_limit" value="<?php isset($_['uploadLimit']) ? p($_['uploadLimit']) : '' ?>"> | |||
<input type="hidden" id="free_space" value="<?php isset($_['freeSpace']) ? p($_['freeSpace']) : '' ?>"> | |||
<?php if(isset($_['dirToken'])):?> | |||
<input type="hidden" id="publicUploadRequestToken" name="requesttoken" value="<?php p($_['requesttoken']) ?>" /> | |||
<input type="hidden" id="dirToken" name="dirToken" value="<?php p($_['dirToken']) ?>" /> | |||
<?php endif;?> | |||
<input type="hidden" class="max_human_file_size" | |||
value="(max <?php p($_['uploadMaxHumanFilesize']); ?>)"> | |||
value="(max <?php isset($_['uploadMaxHumanFilesize']) ? p($_['uploadMaxHumanFilesize']) : ''; ?>)"> | |||
<input type="file" id="file_upload_start" name='files[]' | |||
data-url="<?php print_unescaped(OCP\Util::linkTo('files', 'ajax/upload.php')); ?>" /> | |||
<a href="#" class="svg icon-upload"></a> | |||
@@ -56,8 +57,8 @@ | |||
<tr> | |||
<th id='headerName' class="hidden column-name"> | |||
<div id="headerName-container"> | |||
<input type="checkbox" id="select_all" /> | |||
<label for="select_all"></label> | |||
<input type="checkbox" id="select_all_files" class="select-all"/> | |||
<label for="select_all_files"></label> | |||
<a class="name sort columntitle" data-sort="name"><span><?php p($l->t( 'Name' )); ?></span><span class="sort-indicator"></span></a> | |||
<span id="selectedActionsList" class="selectedActions"> | |||
<?php if($_['allowZipDownload']) : ?> | |||
@@ -88,6 +89,8 @@ | |||
<tfoot> | |||
</tfoot> | |||
</table> | |||
<input type="hidden" name="allowZipDownload" id="allowZipDownload" value="<?php p($_['allowZipDownload']); ?>" /> | |||
<input type="hidden" name="dir" id="dir" value="" /> | |||
<div id="editor"></div><!-- FIXME Do not use this div in your app! It is deprecated and will be removed in the future! --> | |||
<div id="uploadsize-message" title="<?php p($l->t('Upload too large'))?>"> | |||
<p> |
@@ -26,6 +26,7 @@ describe('OCA.Files.App tests', function() { | |||
beforeEach(function() { | |||
$('#testArea').append( | |||
'<div id="content" class="app-files">' + | |||
'<div id="app-navigation">' + | |||
'<ul><li data-id="files"><a>Files</a></li>' + | |||
'<li data-id="other"><a>Other</a></li>' + | |||
@@ -36,6 +37,7 @@ describe('OCA.Files.App tests', function() { | |||
'<div id="app-content-other" class="hidden">' + | |||
'</div>' + | |||
'</div>' + | |||
'</div>' + | |||
'</div>' | |||
); | |||
@@ -89,30 +91,43 @@ describe('OCA.Files.App tests', function() { | |||
expect(handler.getCall(0).args[0].dir).toEqual('/somedir'); | |||
}); | |||
it('sends "show" event to current app and sets navigation', function() { | |||
var handlerFiles = sinon.stub(); | |||
var handlerOther = sinon.stub(); | |||
$('#app-content-files').on('show', handlerFiles); | |||
$('#app-content-other').on('show', handlerOther); | |||
var showHandlerFiles = sinon.stub(); | |||
var showHandlerOther = sinon.stub(); | |||
var hideHandlerFiles = sinon.stub(); | |||
var hideHandlerOther = sinon.stub(); | |||
$('#app-content-files').on('show', showHandlerFiles); | |||
$('#app-content-files').on('hide', hideHandlerFiles); | |||
$('#app-content-other').on('show', showHandlerOther); | |||
$('#app-content-other').on('hide', hideHandlerOther); | |||
App._onPopState({view: 'other', dir: '/somedir'}); | |||
expect(handlerFiles.notCalled).toEqual(true); | |||
expect(handlerOther.calledOnce).toEqual(true); | |||
expect(showHandlerFiles.notCalled).toEqual(true); | |||
expect(hideHandlerFiles.calledOnce).toEqual(true); | |||
expect(showHandlerOther.calledOnce).toEqual(true); | |||
expect(hideHandlerOther.notCalled).toEqual(true); | |||
handlerFiles.reset(); | |||
handlerOther.reset(); | |||
showHandlerFiles.reset(); | |||
showHandlerOther.reset(); | |||
hideHandlerFiles.reset(); | |||
hideHandlerOther.reset(); | |||
App._onPopState({view: 'files', dir: '/somedir'}); | |||
expect(handlerFiles.calledOnce).toEqual(true); | |||
expect(handlerOther.notCalled).toEqual(true); | |||
expect(showHandlerFiles.calledOnce).toEqual(true); | |||
expect(hideHandlerFiles.notCalled).toEqual(true); | |||
expect(showHandlerOther.notCalled).toEqual(true); | |||
expect(hideHandlerOther.calledOnce).toEqual(true); | |||
expect(App.navigation.getActiveItem()).toEqual('files'); | |||
expect($('#app-content-files').hasClass('hidden')).toEqual(false); | |||
expect($('#app-content-other').hasClass('hidden')).toEqual(true); | |||
}); | |||
it('does not send "show" event to current app when already visible', function() { | |||
var handler = sinon.stub(); | |||
$('#app-content-files').on('show', handler); | |||
it('does not send "show" or "hide" event to current app when already visible', function() { | |||
var showHandler = sinon.stub(); | |||
var hideHandler = sinon.stub(); | |||
$('#app-content-files').on('show', showHandler); | |||
$('#app-content-files').on('hide', hideHandler); | |||
App._onPopState({view: 'files', dir: '/somedir'}); | |||
expect(handler.notCalled).toEqual(true); | |||
expect(showHandler.notCalled).toEqual(true); | |||
expect(hideHandler.notCalled).toEqual(true); | |||
}); | |||
it('state defaults to files app with root dir', function() { | |||
var handler = sinon.stub(); | |||
@@ -123,6 +138,12 @@ describe('OCA.Files.App tests', function() { | |||
expect(handler.getCall(0).args[0].view).toEqual('files'); | |||
expect(handler.getCall(0).args[0].dir).toEqual('/'); | |||
}); | |||
it('activates files app if invalid view is passed', function() { | |||
App._onPopState({view: 'invalid', dir: '/somedir'}); | |||
expect(App.navigation.getActiveItem()).toEqual('files'); | |||
expect($('#app-content-files').hasClass('hidden')).toEqual(false); | |||
}); | |||
}); | |||
describe('navigation', function() { | |||
it('switches the navigation item and panel visibility when onpopstate', function() { | |||
@@ -156,13 +177,43 @@ describe('OCA.Files.App tests', function() { | |||
expect($('li[data-id=files]').hasClass('selected')).toEqual(true); | |||
expect($('li[data-id=other]').hasClass('selected')).toEqual(false); | |||
}); | |||
it('clicking on navigation sends "urlChanged" event', function() { | |||
it('clicking on navigation sends "show" and "urlChanged" event', function() { | |||
var handler = sinon.stub(); | |||
var showHandler = sinon.stub(); | |||
$('#app-content-other').on('urlChanged', handler); | |||
$('#app-content-other').on('show', showHandler); | |||
$('li[data-id=other]>a').click(); | |||
expect(handler.calledOnce).toEqual(true); | |||
expect(handler.getCall(0).args[0].view).toEqual('other'); | |||
expect(handler.getCall(0).args[0].dir).toEqual('/'); | |||
expect(showHandler.calledOnce).toEqual(true); | |||
}); | |||
it('clicking on activate navigation only sends "urlChanged" event', function() { | |||
var handler = sinon.stub(); | |||
var showHandler = sinon.stub(); | |||
$('#app-content-files').on('urlChanged', handler); | |||
$('#app-content-files').on('show', showHandler); | |||
$('li[data-id=files]>a').click(); | |||
expect(handler.calledOnce).toEqual(true); | |||
expect(handler.getCall(0).args[0].view).toEqual('files'); | |||
expect(handler.getCall(0).args[0].dir).toEqual('/'); | |||
expect(showHandler.notCalled).toEqual(true); | |||
}); | |||
}); | |||
describe('viewer mode', function() { | |||
it('toggles the sidebar when viewer mode is enabled', function() { | |||
$('#app-content-files').trigger( | |||
new $.Event('changeViewerMode', {viewerModeEnabled: true} | |||
)); | |||
expect($('#app-navigation').hasClass('hidden')).toEqual(true); | |||
expect($('.app-files').hasClass('viewer-mode no-sidebar')).toEqual(true); | |||
$('#app-content-files').trigger( | |||
new $.Event('changeViewerMode', {viewerModeEnabled: false} | |||
)); | |||
expect($('#app-navigation').hasClass('hidden')).toEqual(false); | |||
expect($('.app-files').hasClass('viewer-mode no-sidebar')).toEqual(false); | |||
}); | |||
}); | |||
}); |
@@ -38,12 +38,19 @@ describe('OCA.Files.FileActions tests', function() { | |||
fileList = undefined; | |||
$('#dir, #permissions, #filestable').remove(); | |||
}); | |||
it('calling clear() clears file actions', function() { | |||
FileActions.clear(); | |||
expect(FileActions.actions).toEqual({}); | |||
expect(FileActions.defaults).toEqual({}); | |||
expect(FileActions.icons).toEqual({}); | |||
expect(FileActions.currentFile).toBe(null); | |||
}); | |||
it('calling display() sets file actions', function() { | |||
var fileData = { | |||
id: 18, | |||
type: 'file', | |||
name: 'testName.txt', | |||
mimetype: 'plain/text', | |||
mimetype: 'text/plain', | |||
size: '1234', | |||
etag: 'a01234c', | |||
mtime: '123456' | |||
@@ -64,7 +71,7 @@ describe('OCA.Files.FileActions tests', function() { | |||
id: 18, | |||
type: 'file', | |||
name: 'testName.txt', | |||
mimetype: 'plain/text', | |||
mimetype: 'text/plain', | |||
size: '1234', | |||
etag: 'a01234c', | |||
mtime: '123456' | |||
@@ -85,7 +92,7 @@ describe('OCA.Files.FileActions tests', function() { | |||
id: 18, | |||
type: 'file', | |||
name: 'testName.txt', | |||
mimetype: 'plain/text', | |||
mimetype: 'text/plain', | |||
size: '1234', | |||
etag: 'a01234c', | |||
mtime: '123456' | |||
@@ -105,7 +112,7 @@ describe('OCA.Files.FileActions tests', function() { | |||
id: 18, | |||
type: 'file', | |||
name: 'testName.txt', | |||
mimetype: 'plain/text', | |||
mimetype: 'text/plain', | |||
size: '1234', | |||
etag: 'a01234c', | |||
mtime: '123456' |
@@ -51,19 +51,13 @@ describe('OCA.Files.FileList tests', function() { | |||
} | |||
beforeEach(function() { | |||
// init horrible parameters | |||
var $body = $('body'); | |||
$body.append('<input type="hidden" id="dir" value="/subdir"></input>'); | |||
$body.append('<input type="hidden" id="permissions" value="31"></input>'); | |||
// dummy files table | |||
$body.append('<table id="filestable"></table>'); | |||
alertStub = sinon.stub(OC.dialogs, 'alert'); | |||
notificationStub = sinon.stub(OC.Notification, 'show'); | |||
// init parameters and test table elements | |||
$('#testArea').append( | |||
'<div id="app-content-files">' + | |||
// init horrible parameters | |||
'<input type="hidden" id="dir" value="/subdir"></input>' + | |||
'<input type="hidden" id="permissions" value="31"></input>' + | |||
// dummy controls | |||
@@ -76,7 +70,7 @@ describe('OCA.Files.FileList tests', function() { | |||
'<table id="filestable">' + | |||
'<thead><tr>' + | |||
'<th id="headerName" class="hidden column-name">' + | |||
'<input type="checkbox" id="select_all">' + | |||
'<input type="checkbox" id="select_all_files" class="select-all">' + | |||
'<a class="name columntitle" data-sort="name"><span>Name</span><span class="sort-indicator"></span></a>' + | |||
'<span class="selectedActions hidden">' + | |||
'<a href class="download">Download</a>' + | |||
@@ -85,7 +79,7 @@ describe('OCA.Files.FileList tests', function() { | |||
'<th class="hidden column-size"><a class="columntitle" data-sort="size"><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>' + | |||
'<tbody id="fileList"></tbody>' + | |||
'<tfoot></tfoot>' + | |||
'</table>' + | |||
'<div id="emptycontent">Empty content message</div>' + | |||
@@ -123,6 +117,7 @@ describe('OCA.Files.FileList tests', function() { | |||
}]; | |||
fileList = new OCA.Files.FileList($('#app-content-files')); | |||
FileActions.clear(); | |||
FileActions.registerDefaultActions(fileList); | |||
fileList.setFileActions(FileActions); | |||
}); | |||
@@ -131,7 +126,6 @@ describe('OCA.Files.FileList tests', function() { | |||
fileList = undefined; | |||
FileActions.clear(); | |||
$('#dir, #permissions, #filestable').remove(); | |||
notificationStub.restore(); | |||
alertStub.restore(); | |||
}); | |||
@@ -160,7 +154,7 @@ describe('OCA.Files.FileList tests', function() { | |||
id: 18, | |||
type: 'file', | |||
name: 'testName.txt', | |||
mimetype: 'plain/text', | |||
mimetype: 'text/plain', | |||
size: '1234', | |||
etag: 'a01234c', | |||
mtime: '123456' | |||
@@ -175,9 +169,11 @@ describe('OCA.Files.FileList tests', function() { | |||
expect($tr.attr('data-size')).toEqual('1234'); | |||
expect($tr.attr('data-etag')).toEqual('a01234c'); | |||
expect($tr.attr('data-permissions')).toEqual('31'); | |||
expect($tr.attr('data-mime')).toEqual('plain/text'); | |||
expect($tr.attr('data-mime')).toEqual('text/plain'); | |||
expect($tr.attr('data-mtime')).toEqual('123456'); | |||
expect($tr.find('a.name').attr('href')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=testName.txt'); | |||
expect($tr.find('a.name').attr('href')) | |||
.toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=testName.txt'); | |||
expect($tr.find('.nametext').text().trim()).toEqual('testName.txt'); | |||
expect($tr.find('.filesize').text()).toEqual('1 kB'); | |||
expect(fileList.findFileEl('testName.txt')[0]).toEqual($tr[0]); | |||
@@ -482,7 +478,9 @@ describe('OCA.Files.FileList tests', function() { | |||
// trigger rename prompt | |||
fileList.rename('One.txt'); | |||
$input = fileList.$fileList.find('input.filename'); | |||
$input.val('Tu_after_three.txt').blur(); | |||
$input.val('Tu_after_three.txt'); | |||
// trigger submit because triggering blur doesn't work in all browsers | |||
$input.closest('form').trigger('submit'); | |||
expect(fakeServer.requests.length).toEqual(1); | |||
request = fakeServer.requests[0]; | |||
@@ -926,6 +924,18 @@ describe('OCA.Files.FileList tests', function() { | |||
expect($('.actions').hasClass('hidden')).toEqual(true); | |||
expect($('.notCreatable').hasClass('hidden')).toEqual(false); | |||
}); | |||
it('toggling viewer mode triggers event', function() { | |||
var handler = sinon.stub(); | |||
fileList.$el.on('changeViewerMode', handler); | |||
fileList.setViewerMode(true); | |||
expect(handler.calledOnce).toEqual(true); | |||
expect(handler.getCall(0).args[0].viewerModeEnabled).toEqual(true); | |||
handler.reset(); | |||
fileList.setViewerMode(false); | |||
expect(handler.calledOnce).toEqual(true); | |||
expect(handler.getCall(0).args[0].viewerModeEnabled).toEqual(false); | |||
}); | |||
}); | |||
describe('loading file list', function() { | |||
beforeEach(function() { | |||
@@ -1198,27 +1208,27 @@ describe('OCA.Files.FileList tests', function() { | |||
expect(selection).toContain('Three.pdf'); | |||
}); | |||
it('Selecting all files will automatically check "select all" checkbox', function() { | |||
expect($('#select_all').prop('checked')).toEqual(false); | |||
expect($('.select-all').prop('checked')).toEqual(false); | |||
$('#fileList tr td.filename input:checkbox').click(); | |||
expect($('#select_all').prop('checked')).toEqual(true); | |||
expect($('.select-all').prop('checked')).toEqual(true); | |||
}); | |||
it('Selecting all files on the first visible page will not automatically check "select all" checkbox', function() { | |||
fileList.setFiles(generateFiles(0, 41)); | |||
expect($('#select_all').prop('checked')).toEqual(false); | |||
expect($('.select-all').prop('checked')).toEqual(false); | |||
$('#fileList tr td.filename input:checkbox').click(); | |||
expect($('#select_all').prop('checked')).toEqual(false); | |||
expect($('.select-all').prop('checked')).toEqual(false); | |||
}); | |||
it('Clicking "select all" will select/deselect all files', function() { | |||
fileList.setFiles(generateFiles(0, 41)); | |||
$('#select_all').click(); | |||
expect($('#select_all').prop('checked')).toEqual(true); | |||
$('.select-all').click(); | |||
expect($('.select-all').prop('checked')).toEqual(true); | |||
$('#fileList tr input:checkbox').each(function() { | |||
expect($(this).prop('checked')).toEqual(true); | |||
}); | |||
expect(_.pluck(fileList.getSelectedFiles(), 'name').length).toEqual(42); | |||
$('#select_all').click(); | |||
expect($('#select_all').prop('checked')).toEqual(false); | |||
$('.select-all').click(); | |||
expect($('.select-all').prop('checked')).toEqual(false); | |||
$('#fileList tr input:checkbox').each(function() { | |||
expect($(this).prop('checked')).toEqual(false); | |||
@@ -1226,44 +1236,44 @@ describe('OCA.Files.FileList tests', function() { | |||
expect(_.pluck(fileList.getSelectedFiles(), 'name').length).toEqual(0); | |||
}); | |||
it('Clicking "select all" then deselecting a file will uncheck "select all"', function() { | |||
$('#select_all').click(); | |||
expect($('#select_all').prop('checked')).toEqual(true); | |||
$('.select-all').click(); | |||
expect($('.select-all').prop('checked')).toEqual(true); | |||
var $tr = fileList.findFileEl('One.txt'); | |||
$tr.find('input:checkbox').click(); | |||
expect($('#select_all').prop('checked')).toEqual(false); | |||
expect($('.select-all').prop('checked')).toEqual(false); | |||
expect(_.pluck(fileList.getSelectedFiles(), 'name').length).toEqual(3); | |||
}); | |||
it('Updates the selection summary when doing a few manipulations with "Select all"', function() { | |||
$('#select_all').click(); | |||
expect($('#select_all').prop('checked')).toEqual(true); | |||
$('.select-all').click(); | |||
expect($('.select-all').prop('checked')).toEqual(true); | |||
var $tr = fileList.findFileEl('One.txt'); | |||
// unselect one | |||
$tr.find('input:checkbox').click(); | |||
expect($('#select_all').prop('checked')).toEqual(false); | |||
expect($('.select-all').prop('checked')).toEqual(false); | |||
expect(_.pluck(fileList.getSelectedFiles(), 'name').length).toEqual(3); | |||
// select all | |||
$('#select_all').click(); | |||
expect($('#select_all').prop('checked')).toEqual(true); | |||
$('.select-all').click(); | |||
expect($('.select-all').prop('checked')).toEqual(true); | |||
expect(_.pluck(fileList.getSelectedFiles(), 'name').length).toEqual(4); | |||
// unselect one | |||
$tr.find('input:checkbox').click(); | |||
expect($('#select_all').prop('checked')).toEqual(false); | |||
expect($('.select-all').prop('checked')).toEqual(false); | |||
expect(_.pluck(fileList.getSelectedFiles(), 'name').length).toEqual(3); | |||
// re-select it | |||
$tr.find('input:checkbox').click(); | |||
expect($('#select_all').prop('checked')).toEqual(true); | |||
expect($('.select-all').prop('checked')).toEqual(true); | |||
expect(_.pluck(fileList.getSelectedFiles(), 'name').length).toEqual(4); | |||
}); | |||
it('Auto-selects files on next page when "select all" is checked', function() { | |||
fileList.setFiles(generateFiles(0, 41)); | |||
$('#select_all').click(); | |||
$('.select-all').click(); | |||
expect(fileList.$fileList.find('tr input:checkbox:checked').length).toEqual(20); | |||
fileList._nextPage(true); | |||
@@ -1295,7 +1305,7 @@ describe('OCA.Files.FileList tests', function() { | |||
expect($actions.hasClass('hidden')).toEqual(true); | |||
}); | |||
it('Selection is cleared when switching dirs', function() { | |||
$('#select_all').click(); | |||
$('.select-all').click(); | |||
var data = { | |||
status: 'success', | |||
data: { | |||
@@ -1311,13 +1321,13 @@ describe('OCA.Files.FileList tests', function() { | |||
]); | |||
fileList.changeDirectory('/'); | |||
fakeServer.respond(); | |||
expect($('#select_all').prop('checked')).toEqual(false); | |||
expect($('.select-all').prop('checked')).toEqual(false); | |||
expect(_.pluck(fileList.getSelectedFiles(), 'name')).toEqual([]); | |||
}); | |||
it('getSelectedFiles returns the selected files even when they are on the next page', function() { | |||
var selectedFiles; | |||
fileList.setFiles(generateFiles(0, 41)); | |||
$('#select_all').click(); | |||
$('.select-all').click(); | |||
// unselect one to not have the "allFiles" case | |||
fileList.$fileList.find('tr input:checkbox:first').click(); | |||
@@ -1326,6 +1336,18 @@ describe('OCA.Files.FileList tests', function() { | |||
expect(selectedFiles.length).toEqual(41); | |||
}); | |||
describe('Selection overlay', function() { | |||
it('show delete action according to directory permissions', function() { | |||
fileList.setFiles(testFiles); | |||
$('#permissions').val(OC.PERMISSION_READ | OC.PERMISSION_DELETE); | |||
$('.select-all').click(); | |||
expect(fileList.$el.find('.delete-selected').hasClass('hidden')).toEqual(false); | |||
$('.select-all').click(); | |||
$('#permissions').val(OC.PERMISSION_READ); | |||
$('.select-all').click(); | |||
expect(fileList.$el.find('.delete-selected').hasClass('hidden')).toEqual(true); | |||
}); | |||
}); | |||
describe('Actions', function() { | |||
beforeEach(function() { | |||
fileList.findFileEl('One.txt').find('input:checkbox').click(); | |||
@@ -1391,7 +1413,7 @@ describe('OCA.Files.FileList tests', function() { | |||
}); | |||
it('Downloads root folder when all selected in root folder', function() { | |||
$('#dir').val('/'); | |||
$('#select_all').click(); | |||
$('.select-all').click(); | |||
var redirectStub = sinon.stub(OC, 'redirect'); | |||
$('.selectedActions .download').click(); | |||
expect(redirectStub.calledOnce).toEqual(true); | |||
@@ -1399,7 +1421,7 @@ describe('OCA.Files.FileList tests', function() { | |||
redirectStub.restore(); | |||
}); | |||
it('Downloads parent folder when all selected in subfolder', function() { | |||
$('#select_all').click(); | |||
$('.select-all').click(); | |||
var redirectStub = sinon.stub(OC, 'redirect'); | |||
$('.selectedActions .download').click(); | |||
expect(redirectStub.calledOnce).toEqual(true); | |||
@@ -1428,7 +1450,7 @@ describe('OCA.Files.FileList tests', function() { | |||
}); | |||
it('Deletes all files when all selected when "Delete" clicked', function() { | |||
var request; | |||
$('#select_all').click(); | |||
$('.select-all').click(); | |||
$('.selectedActions .delete-selected').click(); | |||
expect(fakeServer.requests.length).toEqual(1); | |||
request = fakeServer.requests[0]; | |||
@@ -1445,9 +1467,9 @@ describe('OCA.Files.FileList tests', function() { | |||
}); | |||
}); | |||
it('resets the file selection on reload', function() { | |||
fileList.$el.find('#select_all').click(); | |||
fileList.$el.find('.select-all').click(); | |||
fileList.reload(); | |||
expect(fileList.$el.find('#select_all').prop('checked')).toEqual(false); | |||
expect(fileList.$el.find('.select-all').prop('checked')).toEqual(false); | |||
expect(fileList.getSelectedFiles()).toEqual([]); | |||
}); | |||
}); |
@@ -1,11 +1,3 @@ | |||
#controls { | |||
left: 0; | |||
} | |||
#filestable { | |||
margin-top: 90px; | |||
} | |||
#preview { | |||
background: #fff; | |||
text-align: center; |
@@ -8,7 +8,8 @@ | |||
* | |||
*/ | |||
/* global OC, FileActions, FileList, Files */ | |||
/* global FileActions, Files */ | |||
/* global dragOptions, folderDropOptions */ | |||
OCA.Sharing = {}; | |||
if (!OCA.Files) { | |||
OCA.Files = {}; | |||
@@ -23,7 +24,16 @@ OCA.Sharing.PublicApp = { | |||
this._initialized = true; | |||
// file list mode ? | |||
if ($el.find('#filestable')) { | |||
this.fileList = new OCA.Files.FileList($el); | |||
this.fileList = new OCA.Files.FileList( | |||
$el, | |||
{ | |||
scrollContainer: $(window), | |||
dragOptions: dragOptions, | |||
folderDropOptions: folderDropOptions | |||
} | |||
); | |||
this.files = OCA.Files.Files; | |||
this.files.initialize(); | |||
} | |||
var mimetype = $('#mimetype').val(); | |||
@@ -145,5 +155,17 @@ OCA.Sharing.PublicApp = { | |||
$(document).ready(function() { | |||
var App = OCA.Sharing.PublicApp; | |||
App.initialize($('#preview')); | |||
// HACK: for oc-dialogs previews that depends on Files: | |||
Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) { | |||
return App.fileList.lazyLoadPreview({ | |||
path: path, | |||
mime: mime, | |||
callback: ready, | |||
width: width, | |||
height: height, | |||
etag: etag | |||
}); | |||
}; | |||
}); | |||
@@ -8,14 +8,15 @@ | |||
* | |||
*/ | |||
/* global OC, t, FileList, FileActions */ | |||
/* global FileList, FileActions */ | |||
$(document).ready(function() { | |||
var sharesLoaded = false; | |||
if (typeof OC.Share !== 'undefined' && typeof FileActions !== 'undefined') { | |||
var oldCreateRow = FileList._createRow; | |||
FileList._createRow = function(fileData) { | |||
// TODO: make a separate class for this or a hook or jQuery event ? | |||
var oldCreateRow = OCA.Files.FileList.prototype._createRow; | |||
OCA.Files.FileList.prototype._createRow = function(fileData) { | |||
var tr = oldCreateRow.apply(this, arguments); | |||
if (fileData.shareOwner) { | |||
tr.attr('data-share-owner', fileData.shareOwner); | |||
@@ -24,14 +25,16 @@ $(document).ready(function() { | |||
}; | |||
$('#fileList').on('fileActionsReady',function(){ | |||
var allShared = $('#fileList').find('[data-share-owner] [data-Action="Share"]'); | |||
var $fileList = $(this); | |||
var allShared = $fileList.find('[data-share-owner] [data-Action="Share"]'); | |||
allShared.addClass('permanent'); | |||
allShared.find('span').text(function(){ | |||
var $owner = $(this).closest('tr').attr('data-share-owner'); | |||
return ' ' + t('files_sharing', 'Shared by {owner}', {owner: $owner}); | |||
}); | |||
// FIXME: these calls are also working on hard-coded | |||
// list selectors... | |||
if (!sharesLoaded){ | |||
OC.Share.loadIcons('file'); | |||
// assume that we got all shares, so switching directories |
@@ -153,7 +153,7 @@ if (isset($path)) { | |||
$folder->assign('dir', $getPath); | |||
$folder->assign('dirToken', $linkItem['token']); | |||
$folder->assign('permissions', OCP\PERMISSION_READ); | |||
$folder->assign('isPublic',true); | |||
$folder->assign('isPublic', true); | |||
$folder->assign('publicUploadEnabled', 'no'); | |||
$folder->assign('files', $files); | |||
$folder->assign('uploadMaxFilesize', $maxUploadFilesize); |
@@ -8,7 +8,7 @@ $l = OC_L10N::get('files_trashbin'); | |||
array( | |||
"id" => 'trashbin', | |||
"appname" => 'files_trashbin', | |||
"script" => 'index.php', | |||
"script" => 'list.php', | |||
"order" => 1, | |||
"name" => $l->t('Deleted files') | |||
) |
@@ -1,4 +1,13 @@ | |||
#fileList tr[data-type="file"] td a.name, | |||
#fileList tr[data-type="file"] td a.name span { | |||
/* | |||
* Copyright (c) 2014 | |||
* | |||
* This file is licensed under the Affero General Public License version 3 | |||
* or later. | |||
* | |||
* See the COPYING-README file. | |||
* | |||
*/ | |||
#app-content-trashbin tbody tr[data-type="file"] td a.name, | |||
#app-content-trashbin tbody tr[data-type="file"] td a.name span { | |||
cursor: default; | |||
} |
@@ -17,7 +17,11 @@ OCA.Trashbin.App = { | |||
return; | |||
} | |||
this._initialized = true; | |||
this.fileList = new OCA.Trashbin.FileList($el); | |||
this.fileList = new OCA.Trashbin.FileList( | |||
$('#app-content-trashbin'), { | |||
scrollContainer: $('#app-content') | |||
} | |||
); | |||
this.registerFileActions(this.fileList); | |||
}, | |||
@@ -68,7 +72,7 @@ OCA.Trashbin.App = { | |||
}; | |||
$(document).ready(function() { | |||
$('#app-content-trashbin').on('show', function() { | |||
$('#app-content-trashbin').one('show', function() { | |||
var App = OCA.Trashbin.App; | |||
App.initialize($('#app-content-trashbin')); | |||
// force breadcrumb init |
@@ -30,6 +30,7 @@ | |||
this.initialize($el); | |||
}; | |||
FileList.prototype = _.extend({}, OCA.Files.FileList.prototype, { | |||
id: 'trashbin', | |||
appName: t('files_trashbin', 'Deleted files'), | |||
initialize: function() { | |||
@@ -37,11 +38,6 @@ | |||
this.$el.find('.undelete').click('click', _.bind(this._onClickRestoreSelected, this)); | |||
this.setSort('mtime', 'desc'); | |||
// override crumb URL maker | |||
this.breadcrumb.getCrumbUrl = function(part, index) { | |||
return OC.linkTo('files_trashbin', 'index.php')+"?view=trashbin&dir=" + encodeURIComponent(part.dir); | |||
}; | |||
/** | |||
* Override crumb making to add "Deleted Files" entry | |||
* and convert files with ".d" extensions to a more | |||
@@ -58,6 +54,13 @@ | |||
return result; | |||
}, | |||
/** | |||
* Override to only return read permissions | |||
*/ | |||
getDirectoryPermissions: function() { | |||
return OC.PERMISSION_READ | OC.PERMISSION_DELETE; | |||
}, | |||
_setCurrentDir: function(targetDir) { | |||
OCA.Files.FileList.prototype._setCurrentDir.apply(this, arguments); | |||
@@ -97,8 +100,12 @@ | |||
return OC.filePath('files_trashbin', 'ajax', action + '.php') + q; | |||
}, | |||
setupUploadEvents: function() { | |||
// override and do nothing | |||
}, | |||
linkTo: function(dir){ | |||
return OC.linkTo('files_trashbin', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/'); | |||
return OC.linkTo('files', 'index.php')+"?view=trashbin&dir="+ encodeURIComponent(dir).replace(/%2F/g, '/'); | |||
}, | |||
updateEmptyContent: function(){ | |||
@@ -126,7 +133,7 @@ | |||
_onClickRestoreSelected: function(event) { | |||
event.preventDefault(); | |||
var self = this; | |||
var allFiles = this.$el.find('#select_all').is(':checked'); | |||
var allFiles = this.$el.find('.select-all').is(':checked'); | |||
var files = []; | |||
var params = {}; | |||
this.disableActions(); | |||
@@ -171,7 +178,7 @@ | |||
_onClickDeleteSelected: function(event) { | |||
event.preventDefault(); | |||
var self = this; | |||
var allFiles = this.$el.find('#select_all').is(':checked'); | |||
var allFiles = this.$el.find('.select-all').is(':checked'); | |||
var files = []; | |||
var params = {}; | |||
if (allFiles) { | |||
@@ -230,7 +237,7 @@ | |||
return OC.generateUrl('/apps/files_trashbin/ajax/preview.php?') + $.param(urlSpec); | |||
}, | |||
getDownloadUrl: function(action, params) { | |||
getDownloadUrl: function() { | |||
// no downloads | |||
return '#'; | |||
}, | |||
@@ -243,6 +250,11 @@ | |||
disableActions: function() { | |||
this.$el.find('.action').css('display', 'none'); | |||
this.$el.find(':input:checkbox').css('display', 'none'); | |||
}, | |||
updateStorageStatistics: function() { | |||
// no op because the trashbin doesn't have | |||
// storage info like free space / used space | |||
} | |||
}); |
@@ -1,23 +0,0 @@ | |||
/* | |||
* Copyright (c) 2014 | |||
* | |||
* This file is licensed under the Affero General Public License version 3 | |||
* or later. | |||
* | |||
* See the COPYING-README file. | |||
* | |||
*/ | |||
(function() { | |||
var Files = _.extend({}, OCA.Files.Files, { | |||
updateStorageStatistics: function() { | |||
// no op because the trashbin doesn't have | |||
// storage info like free space / used space | |||
} | |||
}); | |||
OCA.Trashbin.Files = Files; | |||
})(); | |||
@@ -7,6 +7,5 @@ OCP\User::checkLoggedIn(); | |||
$tmpl = new OCP\Template('files_trashbin', 'index', ''); | |||
OCP\Util::addStyle('files_trashbin', 'trash'); | |||
OCP\Util::addScript('files_trashbin', 'app'); | |||
OCP\Util::addScript('files_trashbin', 'files'); | |||
OCP\Util::addScript('files_trashbin', 'filelist'); | |||
$tmpl->printPage(); |
@@ -13,8 +13,8 @@ | |||
<tr> | |||
<th id='headerName' class="hidden column-name"> | |||
<div id="headerName-container"> | |||
<input type="checkbox" id="select_all" /> | |||
<label for="select_all"></label> | |||
<input type="checkbox" id="select_all_trash" class="select-all"/> | |||
<label for="select_all_trash"></label> | |||
<a class="name sort columntitle" data-sort="name"><span><?php p($l->t( 'Name' )); ?></span><span class="sort-indicator"></span></a> | |||
<span id="selectedActionsList" class='selectedActions'> | |||
<a href="" class="undelete"> |
@@ -24,19 +24,16 @@ describe('OCA.Trashbin.FileList tests', function() { | |||
var FileActions = OCA.Files.FileActions; | |||
beforeEach(function() { | |||
// init horrible parameters | |||
var $body = $('body'); | |||
$body.append('<input type="hidden" id="dir" value="/"></input>'); | |||
// dummy files table | |||
$body.append('<table id="filestable"></table>'); | |||
alertStub = sinon.stub(OC.dialogs, 'alert'); | |||
notificationStub = sinon.stub(OC.Notification, 'show'); | |||
// init parameters and test table elements | |||
$('#testArea').append( | |||
'<div id="app-content-trashbin">' + | |||
// init horrible parameters | |||
'<input type="hidden" id="dir" value="/"></input>' + | |||
// set this but it shouldn't be used (could be the one from the | |||
// files app) | |||
'<input type="hidden" id="permissions" value="31"></input>' + | |||
// dummy controls | |||
'<div id="controls">' + | |||
@@ -47,13 +44,13 @@ describe('OCA.Trashbin.FileList tests', function() { | |||
// TODO: at some point this will be rendered by the fileList class itself! | |||
'<table id="filestable">' + | |||
'<thead><tr><th id="headerName" class="hidden">' + | |||
'<input type="checkbox" id="select_all">' + | |||
'<input type="checkbox" id="select_all_trash" class="select-all">' + | |||
'<span class="name">Name</span>' + | |||
'<span class="selectedActions hidden">' + | |||
'<a href class="undelete">Restore</a>' + | |||
'<a href class="delete-selected">Delete</a></span>' + | |||
'</th></tr></thead>' + | |||
'<tbody id="fileList"></tbody>' + | |||
'<tbody id="fileList"></tbody>' + | |||
'<tfoot></tfoot>' + | |||
'</table>' + | |||
'<div id="emptycontent">Empty content message</div>' + | |||
@@ -66,7 +63,6 @@ describe('OCA.Trashbin.FileList tests', function() { | |||
name: 'One.txt', | |||
mtime: 11111000, | |||
mimetype: 'text/plain', | |||
size: 12, | |||
etag: 'abc' | |||
}, { | |||
id: 2, | |||
@@ -74,7 +70,6 @@ describe('OCA.Trashbin.FileList tests', function() { | |||
name: 'Two.jpg', | |||
mtime: 22222000, | |||
mimetype: 'image/jpeg', | |||
size: 12049, | |||
etag: 'def', | |||
}, { | |||
id: 3, | |||
@@ -82,7 +77,6 @@ describe('OCA.Trashbin.FileList tests', function() { | |||
name: 'Three.pdf', | |||
mtime: 33333000, | |||
mimetype: 'application/pdf', | |||
size: 58009, | |||
etag: '123', | |||
}, { | |||
id: 4, | |||
@@ -90,7 +84,6 @@ describe('OCA.Trashbin.FileList tests', function() { | |||
mtime: 99999000, | |||
name: 'somedir', | |||
mimetype: 'httpd/unix-directory', | |||
size: 250, | |||
etag: '456' | |||
}]; | |||
@@ -106,10 +99,91 @@ describe('OCA.Trashbin.FileList tests', function() { | |||
notificationStub.restore(); | |||
alertStub.restore(); | |||
}); | |||
describe('Initialization', function() { | |||
it('Sorts by mtime by default', function() { | |||
expect(fileList._sort).toEqual('mtime'); | |||
expect(fileList._sortDirection).toEqual('desc'); | |||
}); | |||
it('Always returns read and delete permission', function() { | |||
expect(fileList.getDirectoryPermissions()).toEqual(OC.PERMISSION_READ | OC.PERMISSION_DELETE); | |||
}); | |||
}); | |||
describe('Breadcrumbs', function() { | |||
beforeEach(function() { | |||
var data = { | |||
status: 'success', | |||
data: { | |||
files: testFiles, | |||
permissions: 1 | |||
} | |||
}; | |||
fakeServer.respondWith(/\/index\.php\/apps\/files_trashbin\/ajax\/list.php\?dir=%2Fsubdir/, [ | |||
200, { | |||
"Content-Type": "application/json" | |||
}, | |||
JSON.stringify(data) | |||
]); | |||
}); | |||
it('links the breadcrumb to the trashbin view', function() { | |||
fileList.changeDirectory('/subdir', false, true); | |||
fakeServer.respond(); | |||
var $crumbs = fileList.$el.find('#controls .crumb'); | |||
expect($crumbs.length).toEqual(2); | |||
expect($crumbs.eq(0).find('a').text()).toEqual(''); | |||
expect($crumbs.eq(0).find('a').attr('href')) | |||
.toEqual(OC.webroot + '/index.php/apps/files?view=trashbin&dir=/'); | |||
expect($crumbs.eq(1).find('a').text()).toEqual('subdir'); | |||
expect($crumbs.eq(1).find('a').attr('href')) | |||
.toEqual(OC.webroot + '/index.php/apps/files?view=trashbin&dir=/subdir'); | |||
}); | |||
}); | |||
describe('Rendering rows', function() { | |||
// TODO. test that rows show the correct name but | |||
// have the real file name with the ".d" suffix | |||
// TODO: with and without dir listing | |||
it('renders rows with the correct data when in root', function() { | |||
// dir listing is false when in root | |||
$('#dir').val('/'); | |||
fileList.setFiles(testFiles); | |||
var $rows = fileList.$el.find('tbody tr'); | |||
var $tr = $rows.eq(0); | |||
expect($rows.length).toEqual(4); | |||
expect($tr.attr('data-id')).toEqual('1'); | |||
expect($tr.attr('data-type')).toEqual('file'); | |||
expect($tr.attr('data-file')).toEqual('One.txt.d11111'); | |||
expect($tr.attr('data-size')).not.toBeDefined(); | |||
expect($tr.attr('data-etag')).toEqual('abc'); | |||
expect($tr.attr('data-permissions')).toEqual('9'); // read and delete | |||
expect($tr.attr('data-mime')).toEqual('text/plain'); | |||
expect($tr.attr('data-mtime')).toEqual('11111000'); | |||
expect($tr.find('a.name').attr('href')).toEqual('#'); | |||
expect($tr.find('.nametext').text().trim()).toEqual('One.txt'); | |||
expect(fileList.findFileEl('One.txt.d11111')[0]).toEqual($tr[0]); | |||
}); | |||
it('renders rows with the correct data when in subdirectory', function() { | |||
// dir listing is true when in a subdir | |||
$('#dir').val('/subdir'); | |||
fileList.setFiles(testFiles); | |||
var $rows = fileList.$el.find('tbody tr'); | |||
var $tr = $rows.eq(0); | |||
expect($rows.length).toEqual(4); | |||
expect($tr.attr('data-id')).toEqual('1'); | |||
expect($tr.attr('data-type')).toEqual('file'); | |||
expect($tr.attr('data-file')).toEqual('One.txt'); | |||
expect($tr.attr('data-size')).not.toBeDefined(); | |||
expect($tr.attr('data-etag')).toEqual('abc'); | |||
expect($tr.attr('data-permissions')).toEqual('9'); // read and delete | |||
expect($tr.attr('data-mime')).toEqual('text/plain'); | |||
expect($tr.attr('data-mtime')).toEqual('11111000'); | |||
expect($tr.find('a.name').attr('href')).toEqual('#'); | |||
expect($tr.find('.nametext').text().trim()).toEqual('One.txt'); | |||
expect(fileList.findFileEl('One.txt')[0]).toEqual($tr[0]); | |||
}); | |||
it('does not render a size column', function() { | |||
expect(fileList.$el.find('tbody tr .filesize').length).toEqual(0); | |||
}); | |||
}); | |||
describe('File actions', function() { | |||
describe('Deleting single files', function() { | |||
@@ -142,7 +216,6 @@ describe('OCA.Trashbin.FileList tests', function() { | |||
fileList.findFileEl('somedir.d99999').find('input:checkbox').click(); | |||
}); | |||
describe('Delete', function() { | |||
// TODO: also test with "allFiles" | |||
it('Deletes selected files when "Delete" clicked', function() { | |||
var request; | |||
$('.selectedActions .delete-selected').click(); | |||
@@ -154,7 +227,16 @@ describe('OCA.Trashbin.FileList tests', function() { | |||
fakeServer.requests[0].respond( | |||
200, | |||
{ 'Content-Type': 'application/json' }, | |||
JSON.stringify({status: 'success'}) | |||
JSON.stringify({ | |||
status: 'success', | |||
data: { | |||
success: [ | |||
{filename: 'One.txt.d11111'}, | |||
{filename: 'Three.pdf.d33333'}, | |||
{filename: 'somedir.d99999'} | |||
] | |||
} | |||
}) | |||
); | |||
expect(fileList.findFileEl('One.txt.d11111').length).toEqual(0); | |||
expect(fileList.findFileEl('Three.pdf.d33333').length).toEqual(0); | |||
@@ -163,7 +245,7 @@ describe('OCA.Trashbin.FileList tests', function() { | |||
}); | |||
it('Deletes all files when all selected when "Delete" clicked', function() { | |||
var request; | |||
$('#select_all').click(); | |||
$('.select-all').click(); | |||
$('.selectedActions .delete-selected').click(); | |||
expect(fakeServer.requests.length).toEqual(1); | |||
request = fakeServer.requests[0]; | |||
@@ -179,7 +261,6 @@ describe('OCA.Trashbin.FileList tests', function() { | |||
}); | |||
}); | |||
describe('Restore', function() { | |||
// TODO: also test with "allFiles" | |||
it('Restores selected files when "Restore" clicked', function() { | |||
var request; | |||
$('.selectedActions .undelete').click(); | |||
@@ -191,16 +272,25 @@ describe('OCA.Trashbin.FileList tests', function() { | |||
fakeServer.requests[0].respond( | |||
200, | |||
{ 'Content-Type': 'application/json' }, | |||
JSON.stringify({status: 'success'}) | |||
JSON.stringify({ | |||
status: 'success', | |||
data: { | |||
success: [ | |||
{filename: 'One.txt.d11111'}, | |||
{filename: 'Three.pdf.d33333'}, | |||
{filename: 'somedir.d99999'} | |||
] | |||
} | |||
}) | |||
); | |||
expect(fileList.findFileEl('One.txt').length).toEqual(0); | |||
expect(fileList.findFileEl('Three.pdf').length).toEqual(0); | |||
expect(fileList.findFileEl('somedir').length).toEqual(0); | |||
expect(fileList.findFileEl('Two.jpg').length).toEqual(1); | |||
expect(fileList.findFileEl('One.txt.d11111').length).toEqual(0); | |||
expect(fileList.findFileEl('Three.pdf.d33333').length).toEqual(0); | |||
expect(fileList.findFileEl('somedir.d99999').length).toEqual(0); | |||
expect(fileList.findFileEl('Two.jpg.d22222').length).toEqual(1); | |||
}); | |||
it('Restores all files when all selected when "Restore" clicked', function() { | |||
var request; | |||
$('#select_all').click(); | |||
$('.select-all').click(); | |||
$('.selectedActions .undelete').click(); | |||
expect(fakeServer.requests.length).toEqual(1); | |||
request = fakeServer.requests[0]; |
@@ -302,6 +302,11 @@ input[type="submit"].enabled { | |||
border-bottom: 1px solid #e7e7e7; | |||
z-index: 50; | |||
} | |||
/* account for shift of controls bar due to app navigation */ | |||
#body-user #controls, | |||
#body-settings #controls { | |||
padding-left: 80px; | |||
} | |||
#controls .button, | |||
#controls button, | |||
#controls input[type='submit'], |