Fixed many issues, clean up
- 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)
This commit is contained in:
parent
9d38e3602b
commit
6fd084243b
|
@ -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'],
|
||||
|
|
Loading…
Reference in New Issue