Merge pull request #9717 from nextcloud/feature/actions-menu
New Feature/actions file menu
This commit is contained in:
commit
0ad1f19a74
16 changed files with 337 additions and 147 deletions
|
@ -176,9 +176,11 @@ table th .columntitle {
|
|||
-moz-box-sizing: border-box;
|
||||
vertical-align: middle;
|
||||
}
|
||||
table.multiselect th .columntitle {
|
||||
display: inline-block;
|
||||
}
|
||||
table th .columntitle.name {
|
||||
padding-left: 5px;
|
||||
padding-right: 80px;
|
||||
margin-left: 50px;
|
||||
}
|
||||
|
||||
|
@ -246,7 +248,7 @@ table th.column-last, table td.column-last {
|
|||
}
|
||||
table.multiselect thead {
|
||||
position: fixed;
|
||||
top: 89px;
|
||||
top: 94px;
|
||||
z-index: 55;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
|
@ -474,19 +476,19 @@ a.action > img {
|
|||
|
||||
/* Actions for selected files */
|
||||
.selectedActions {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.selectedActions.hidden {
|
||||
display: none;
|
||||
}
|
||||
.selectedActions a {
|
||||
display: inline;
|
||||
font-size: 11px;
|
||||
line-height: 50px;
|
||||
padding: 18px 5px;
|
||||
}
|
||||
.selectedActions a.delete-selected {
|
||||
padding-right: 15px;
|
||||
padding: 16px 5px;
|
||||
}
|
||||
|
||||
.selectedActions a.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
@ -495,9 +497,9 @@ a.action > img {
|
|||
vertical-align: text-bottom;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
/* hide the delete icon in name column normal resolutions */
|
||||
table th#headerName .selectedActions .delete-selected {
|
||||
display: none;
|
||||
|
||||
.selectedActions .actions-selected .icon-more {
|
||||
margin-top: -3px;
|
||||
}
|
||||
|
||||
#fileList td a {
|
||||
|
|
|
@ -28,7 +28,7 @@ table td {
|
|||
table.multiselect thead {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
|
||||
#fileList a.action.action-menu img {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
@ -41,10 +41,6 @@ table.multiselect thead {
|
|||
display: none !important;
|
||||
}
|
||||
|
||||
/* show the delete icon in name column in lower resolutions */
|
||||
table th#headerName .selectedActions .delete-selected {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* proper notification area for multi line messages */
|
||||
#notification-container {
|
||||
|
@ -71,7 +67,10 @@ table.dragshadow {
|
|||
}
|
||||
@media only screen and (max-width: 480px) {
|
||||
/* Only show icons */
|
||||
table th .selectedActions a span:not(.icon) {
|
||||
table th .selectedActions {
|
||||
float: right;
|
||||
}
|
||||
table th .selectedActions > a span:not(.icon) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -88,6 +88,23 @@
|
|||
allowLegacyActions: true,
|
||||
scrollTo: urlParams.scrollto,
|
||||
filesClient: OC.Files.getClient(),
|
||||
multiSelectMenu: [
|
||||
{
|
||||
name: 'copyMove',
|
||||
displayName: t('files', 'Move or copy'),
|
||||
iconClass: 'icon-external',
|
||||
},
|
||||
{
|
||||
name: 'download',
|
||||
displayName: t('files', 'Download'),
|
||||
iconClass: 'icon-download',
|
||||
},
|
||||
{
|
||||
name: 'delete',
|
||||
displayName: t('files', 'Delete'),
|
||||
iconClass: 'icon-delete',
|
||||
}
|
||||
],
|
||||
sorting: {
|
||||
mode: $('#defaultFileSorting').val(),
|
||||
direction: $('#defaultFileSortingDirection').val()
|
||||
|
@ -130,7 +147,7 @@
|
|||
window.FileActions.off('registerAction.app-files', this._onActionsUpdated);
|
||||
},
|
||||
|
||||
_onActionsUpdated: function(ev, newAction) {
|
||||
_onActionsUpdated: function(ev) {
|
||||
// forward new action to the file list
|
||||
if (ev.action) {
|
||||
this.fileList.fileActions.registerAction(ev.action);
|
||||
|
|
|
@ -692,21 +692,21 @@
|
|||
OCA.Files.FileActions = FileActions;
|
||||
|
||||
/**
|
||||
* Replaces the download icon with a loading spinner and vice versa
|
||||
* Replaces the button icon with a loading spinner and vice versa
|
||||
* - also adds the class disabled to the passed in element
|
||||
*
|
||||
* @param {jQuery} $downloadButtonElement download fileaction
|
||||
* @param {jQuery} $buttonElement The button element
|
||||
* @param {boolean} showIt whether to show the spinner(true) or to hide it(false)
|
||||
*/
|
||||
OCA.Files.FileActions.updateFileActionSpinner = function($downloadButtonElement, showIt) {
|
||||
var $icon = $downloadButtonElement.find('.icon');
|
||||
OCA.Files.FileActions.updateFileActionSpinner = function($buttonElement, showIt) {
|
||||
var $icon = $buttonElement.find('.icon');
|
||||
if (showIt) {
|
||||
var $loadingIcon = $('<span class="icon icon-loading-small"></span>');
|
||||
$icon.after($loadingIcon);
|
||||
$icon.addClass('hidden');
|
||||
} else {
|
||||
$downloadButtonElement.find('.icon-loading-small').remove();
|
||||
$downloadButtonElement.find('.icon').removeClass('hidden');
|
||||
$buttonElement.find('.icon-loading-small').remove();
|
||||
$buttonElement.find('.icon').removeClass('hidden');
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -126,7 +126,11 @@
|
|||
* @type OCA.Files.FileActions
|
||||
*/
|
||||
fileActions: null,
|
||||
|
||||
/**
|
||||
* File selection menu, defaults to OCA.Files.FileSelectionMenu
|
||||
* @type OCA.Files.FileSelectionMenu
|
||||
*/
|
||||
fileMultiSelectMenu: null,
|
||||
/**
|
||||
* Whether selection is allowed, checkboxes and selection overlay will
|
||||
* be rendered
|
||||
|
@ -288,6 +292,12 @@
|
|||
|
||||
this.fileSummary = this._createSummary();
|
||||
|
||||
if (options.multiSelectMenu) {
|
||||
this.fileMultiSelectMenu = new OCA.Files.FileMultiSelectMenu(options.multiSelectMenu);
|
||||
this.fileMultiSelectMenu.render();
|
||||
this.$el.find('.selectedActions').append(this.fileMultiSelectMenu.$el);
|
||||
}
|
||||
|
||||
if (options.sorting) {
|
||||
this.setSort(options.sorting.mode, options.sorting.direction, false, false);
|
||||
} else {
|
||||
|
@ -336,11 +346,10 @@
|
|||
this.$el.on('show', _.bind(this._onShow, this));
|
||||
this.$el.on('urlChanged', _.bind(this._onUrlChanged, this));
|
||||
this.$el.find('.select-all').click(_.bind(this._onClickSelectAll, this));
|
||||
this.$el.find('.download').click(_.bind(this._onClickDownloadSelected, this));
|
||||
this.$el.find('.copy-move').click(_.bind(this._onClickCopyMoveSelected, this));
|
||||
this.$el.find('.delete-selected').click(_.bind(this._onClickDeleteSelected, this));
|
||||
|
||||
this.$el.find('.selectedActions a').tooltip({placement:'top'});
|
||||
this.$el.find('.actions-selected').click(function () {
|
||||
self.fileMultiSelectMenu.show(self);
|
||||
return false;
|
||||
});
|
||||
|
||||
this.$container.on('scroll', _.bind(this._onScroll, this));
|
||||
|
||||
|
@ -365,6 +374,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
OC.Plugins.attach('OCA.Files.FileList', this);
|
||||
},
|
||||
|
||||
|
@ -388,6 +398,22 @@
|
|||
$('#app-content').off('appresized', this._onResize);
|
||||
},
|
||||
|
||||
multiSelectMenuClick: function (ev, action) {
|
||||
switch (action) {
|
||||
case 'delete':
|
||||
this._onClickDeleteSelected(ev)
|
||||
break;
|
||||
case 'download':
|
||||
this._onClickDownloadSelected(ev);
|
||||
break;
|
||||
case 'copyMove':
|
||||
this._onClickCopyMoveSelected(ev);
|
||||
break;
|
||||
case 'restore':
|
||||
this._onClickRestoreSelected(ev);
|
||||
break;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Initializes the file actions, set up listeners.
|
||||
*
|
||||
|
@ -745,7 +771,9 @@
|
|||
*/
|
||||
_onClickDownloadSelected: function(event) {
|
||||
var files;
|
||||
var self = this;
|
||||
var dir = this.getCurrentDirectory();
|
||||
|
||||
if (this.isAllSelected() && this.getSelectedFiles().length > 1) {
|
||||
files = OC.basename(dir);
|
||||
dir = OC.dirname(dir) || '/';
|
||||
|
@ -754,19 +782,16 @@
|
|||
files = _.pluck(this.getSelectedFiles(), 'name');
|
||||
}
|
||||
|
||||
var downloadFileaction = $('#selectedActionsList').find('.download');
|
||||
|
||||
// don't allow a second click on the download action
|
||||
if(downloadFileaction.hasClass('disabled')) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
if(this.fileMultiSelectMenu.isDisabled('download')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.fileMultiSelectMenu.toggleLoading('download', true);
|
||||
var disableLoadingState = function(){
|
||||
OCA.Files.FileActions.updateFileActionSpinner(downloadFileaction, false);
|
||||
self.fileMultiSelectMenu.toggleLoading('download', false);
|
||||
};
|
||||
|
||||
OCA.Files.FileActions.updateFileActionSpinner(downloadFileaction, true);
|
||||
if(this.getSelectedFiles().length > 1) {
|
||||
OCA.Files.Files.handleDownload(this.getDownloadUrl(files, dir, true), disableLoadingState);
|
||||
}
|
||||
|
@ -774,7 +799,7 @@
|
|||
var first = this.getSelectedFiles()[0];
|
||||
OCA.Files.Files.handleDownload(this.getDownloadUrl(first.name, dir, true), disableLoadingState);
|
||||
}
|
||||
return false;
|
||||
event.preventDefault();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -786,20 +811,18 @@
|
|||
|
||||
files = _.pluck(this.getSelectedFiles(), 'name');
|
||||
|
||||
var moveFileAction = $('#selectedActionsList').find('.move');
|
||||
|
||||
// don't allow a second click on the download action
|
||||
if(moveFileAction.hasClass('disabled')) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
if(this.fileMultiSelectMenu.isDisabled('copyMove')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var disableLoadingState = function(){
|
||||
OCA.Files.FileActions.updateFileActionSpinner(moveFileAction, false);
|
||||
self.fileMultiSelectMenu.toggleLoading('copyMove', false);
|
||||
};
|
||||
|
||||
var actions = this.isSelectedMovable() ? OC.dialogs.FILEPICKER_TYPE_COPY_MOVE : OC.dialogs.FILEPICKER_TYPE_COPY;
|
||||
OC.dialogs.filepicker(t('files', 'Target folder'), function(targetPath, type) {
|
||||
self.fileMultiSelectMenu.toggleLoading('copyMove', true);
|
||||
if (type === OC.dialogs.FILEPICKER_TYPE_COPY) {
|
||||
self.copy(files, targetPath, disableLoadingState);
|
||||
}
|
||||
|
@ -807,7 +830,7 @@
|
|||
self.move(files, targetPath, disableLoadingState);
|
||||
}
|
||||
}, false, "httpd/unix-directory", true, actions);
|
||||
return false;
|
||||
event.preventDefault();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -820,7 +843,6 @@
|
|||
}
|
||||
this.do_delete(files);
|
||||
event.preventDefault();
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -2885,19 +2907,20 @@
|
|||
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('.selectedActions .download').toggleClass('hidden', !this.isSelectedDownloadable());
|
||||
this.$el.find('.delete-selected').toggleClass('hidden', !this.isSelectedDeletable());
|
||||
|
||||
var $copyMove = this.$el.find('.selectedActions .copy-move');
|
||||
if (this.isSelectedCopiable()) {
|
||||
$copyMove.toggleClass('hidden', false);
|
||||
if (this.isSelectedMovable()) {
|
||||
$copyMove.find('.label').text(t('files', 'Move or copy'));
|
||||
if (this.fileMultiSelectMenu) {
|
||||
this.fileMultiSelectMenu.toggleItemVisibility('download', this.isSelectedDownloadable());
|
||||
this.fileMultiSelectMenu.toggleItemVisibility('delete', this.isSelectedDeletable());
|
||||
this.fileMultiSelectMenu.toggleItemVisibility('copyMove', this.isSelectedCopiable());
|
||||
if (this.isSelectedCopiable()) {
|
||||
if (this.isSelectedMovable()) {
|
||||
this.fileMultiSelectMenu.updateItemText('copyMove', t('files', 'Move or copy'));
|
||||
} else {
|
||||
this.fileMultiSelectMenu.updateItemText('copyMove', t('files', 'Copy'));
|
||||
}
|
||||
} else {
|
||||
$copyMove.find('.label').text(t('files', 'Copy'));
|
||||
this.fileMultiSelectMenu.toggleItemVisibility('copyMove', false);
|
||||
}
|
||||
} else {
|
||||
$copyMove.toggleClass('hidden', true);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
112
apps/files/js/filemultiselectmenu.js
Normal file
112
apps/files/js/filemultiselectmenu.js
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright (c) 2018
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3
|
||||
* or later.
|
||||
*
|
||||
* See the COPYING-README file.
|
||||
*
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var TEMPLATE_MENU =
|
||||
'<ul>' +
|
||||
'{{#each items}}' +
|
||||
'<li class="item-{{name}}">' +
|
||||
'<a href="#" class="menuitem action {{name}} permanent" data-action="{{name}}">' +
|
||||
'{{#if iconClass}}' +
|
||||
'<span class="icon {{iconClass}}"></span>' +
|
||||
'{{else}}' +
|
||||
'<span class="no-icon"></span>' +
|
||||
'{{/if}}' +
|
||||
'<span class="label">{{displayName}}</span>' +
|
||||
'</a></li>' +
|
||||
'{{/each}}' +
|
||||
'</ul>';
|
||||
|
||||
var FileMultiSelectMenu = OC.Backbone.View.extend({
|
||||
tagName: 'div',
|
||||
className: 'filesSelectMenu popovermenu bubble menu-center',
|
||||
_scopes: null,
|
||||
initialize: function(menuItems) {
|
||||
this._scopes = menuItems;
|
||||
},
|
||||
events: {
|
||||
'click a.action': '_onClickAction'
|
||||
},
|
||||
template: Handlebars.compile(TEMPLATE_MENU),
|
||||
/**
|
||||
* Renders the menu with the currently set items
|
||||
*/
|
||||
render: function() {
|
||||
this.$el.html(this.template({
|
||||
items: this._scopes
|
||||
}));
|
||||
},
|
||||
/**
|
||||
* Displays the menu under the given element
|
||||
*
|
||||
* @param {OCA.Files.FileActionContext} context context
|
||||
* @param {Object} $trigger trigger element
|
||||
*/
|
||||
show: function(context) {
|
||||
this._context = context;
|
||||
this.$el.removeClass('hidden');
|
||||
if (window.innerWidth < 480) {
|
||||
this.$el.removeClass('menu-center').addClass('menu-right');
|
||||
} else {
|
||||
this.$el.removeClass('menu-right').addClass('menu-center');
|
||||
}
|
||||
OC.showMenu(null, this.$el);
|
||||
return false;
|
||||
},
|
||||
toggleItemVisibility: function (itemName, show) {
|
||||
if (show) {
|
||||
this.$el.find('.item-' + itemName).removeClass('hidden');
|
||||
} else {
|
||||
this.$el.find('.item-' + itemName).addClass('hidden');
|
||||
}
|
||||
},
|
||||
updateItemText: function (itemName, translation) {
|
||||
this.$el.find('.item-' + itemName).find('.label').text(translation);
|
||||
},
|
||||
toggleLoading: function (itemName, showLoading) {
|
||||
var $actionElement = this.$el.find('.item-' + itemName);
|
||||
if ($actionElement.length === 0) {
|
||||
return;
|
||||
}
|
||||
var $icon = $actionElement.find('.icon');
|
||||
if (showLoading) {
|
||||
var $loadingIcon = $('<span class="icon icon-loading-small"></span>');
|
||||
$icon.after($loadingIcon);
|
||||
$icon.addClass('hidden');
|
||||
$actionElement.addClass('disabled');
|
||||
} else {
|
||||
$actionElement.find('.icon-loading-small').remove();
|
||||
$actionElement.find('.icon').removeClass('hidden');
|
||||
$actionElement.removeClass('disabled');
|
||||
}
|
||||
},
|
||||
isDisabled: function (itemName) {
|
||||
var $actionElement = this.$el.find('.item-' + itemName);
|
||||
return $actionElement.hasClass('disabled');
|
||||
},
|
||||
/**
|
||||
* Event handler whenever an action has been clicked within the menu
|
||||
*
|
||||
* @param {Object} event event object
|
||||
*/
|
||||
_onClickAction: function (event) {
|
||||
var $target = $(event.currentTarget);
|
||||
if (!$target.hasClass('menuitem')) {
|
||||
$target = $target.closest('.menuitem');
|
||||
}
|
||||
|
||||
OC.hideMenus();
|
||||
this._context.multiSelectMenuClick(event, $target.data('action'));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
OCA.Files.FileMultiSelectMenu = FileMultiSelectMenu;
|
||||
})(OC, OCA);
|
|
@ -6,6 +6,7 @@
|
|||
"jquery-visibility.js",
|
||||
"fileinfomodel.js",
|
||||
"filesummary.js",
|
||||
"filemultiselectmenu.js",
|
||||
"breadcrumb.js",
|
||||
"filelist.js",
|
||||
"search.js",
|
||||
|
|
|
@ -49,20 +49,16 @@
|
|||
</th>
|
||||
<th id='headerName' class="hidden column-name">
|
||||
<div id="headerName-container">
|
||||
<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="copy-move">
|
||||
<span class="icon icon-external"></span>
|
||||
<span class="label"><?php p($l->t('Move or copy'))?></span>
|
||||
</a>
|
||||
<a href="" class="download">
|
||||
<span class="icon icon-download"></span>
|
||||
<span><?php p($l->t('Download'))?></span>
|
||||
</a>
|
||||
<a href="" class="delete-selected">
|
||||
<span class="icon icon-delete"></span>
|
||||
<span><?php p($l->t('Delete'))?></span>
|
||||
</a>
|
||||
<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="actions-selected">
|
||||
<span class="icon icon-more"></span>
|
||||
<span><?php p($l->t('Actions'))?></span>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</th>
|
||||
|
@ -71,10 +67,6 @@
|
|||
</th>
|
||||
<th id="headerDate" class="hidden column-mtime">
|
||||
<a id="modified" class="columntitle" data-sort="mtime"><span><?php p($l->t( 'Modified' )); ?></span><span class="sort-indicator"></span></a>
|
||||
<span class="selectedActions"><a href="" class="delete-selected">
|
||||
<span><?php p($l->t('Delete'))?></span>
|
||||
<span class="icon icon-delete"></span>
|
||||
</a></span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
|
@ -28,10 +28,12 @@
|
|||
<a id="modified" class="columntitle"
|
||||
data-sort="mtime"><span><?php p($l->t('Modified')); ?></span><span
|
||||
class="sort-indicator"></span></a>
|
||||
<span class="selectedActions"><a href="" class="delete-selected">
|
||||
<span><?php p($l->t('Delete')) ?></span>
|
||||
<span class="icon icon-delete"></span>
|
||||
</a></span>
|
||||
<span class="selectedActions">
|
||||
<a href="" class="delete-selected">
|
||||
<span class="icon icon-delete"></span>
|
||||
<span><?php p($l->t('Delete')) ?></span>
|
||||
</a>
|
||||
</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
<h2><?php p($l->t('No entries found in this folder')); ?></h2>
|
||||
<p></p>
|
||||
</div>
|
||||
|
||||
<table id="filestable">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -27,11 +26,13 @@
|
|||
</th>
|
||||
<th id="headerDate" class="hidden column-mtime">
|
||||
<a id="modified" class="columntitle" data-sort="mtime"><span><?php p($l->t( 'Modified' )); ?></span><span class="sort-indicator"></span></a>
|
||||
<span class="selectedActions"><a href="" class="delete-selected">
|
||||
<?php p($l->t('Delete'))?>
|
||||
<img class="svg" alt=""
|
||||
src="<?php print_unescaped(OCP\Template::image_path("core", "actions/delete.svg")); ?>" />
|
||||
</a></span>
|
||||
<span class="selectedActions">
|
||||
<a href="" class="delete-selected">
|
||||
<img class="svg" alt=""
|
||||
src="<?php print_unescaped(OCP\Template::image_path("core", "actions/delete.svg")); ?>" />
|
||||
<?php p($l->t('Delete'))?>
|
||||
</a>
|
||||
</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
|
@ -94,9 +94,7 @@ describe('OCA.Files.FileList tests', function() {
|
|||
'<input type="checkbox" id="select_all_files" class="select-all checkbox">' +
|
||||
'<a class="name columntitle" data-sort="name"><span>Name</span><span class="sort-indicator"></span></a>' +
|
||||
'<span id="selectedActionsList" class="selectedActions hidden">' +
|
||||
'<a href class="copy-move"><span class="label">Move or copy</span></a>' +
|
||||
'<a href class="download"><img src="actions/download.svg">Download</a>' +
|
||||
'<a href class="delete-selected">Delete</a></span>' +
|
||||
'<a href class="actions-selected"><span class="icon icon-more"></span><span>Actions</span></a>' +
|
||||
'</th>' +
|
||||
'<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>' +
|
||||
|
@ -161,7 +159,22 @@ describe('OCA.Files.FileList tests', function() {
|
|||
fileList = new OCA.Files.FileList($('#app-content-files'), {
|
||||
filesClient: filesClient,
|
||||
config: filesConfig,
|
||||
enableUpload: true
|
||||
enableUpload: true,
|
||||
multiSelectMenu: [{
|
||||
name: 'copyMove',
|
||||
displayName: t('files', 'Move or copy'),
|
||||
iconClass: 'icon-external',
|
||||
},
|
||||
{
|
||||
name: 'download',
|
||||
displayName: t('files', 'Download'),
|
||||
iconClass: 'icon-download',
|
||||
},
|
||||
{
|
||||
name: 'delete',
|
||||
displayName: t('files', 'Delete'),
|
||||
iconClass: 'icon-delete',
|
||||
}]
|
||||
});
|
||||
});
|
||||
afterEach(function() {
|
||||
|
@ -2100,41 +2113,41 @@ describe('OCA.Files.FileList tests', function() {
|
|||
fileList.setFiles(testFiles);
|
||||
$('#permissions').val(OC.PERMISSION_READ | OC.PERMISSION_UPDATE);
|
||||
$('.select-all').click();
|
||||
expect(fileList.$el.find('.selectedActions .copy-move').hasClass('hidden')).toEqual(false);
|
||||
expect(fileList.$el.find('.selectedActions .copy-move .label').text()).toEqual('Move or copy');
|
||||
expect(fileList.$el.find('.selectedActions .item-copyMove').hasClass('hidden')).toEqual(false);
|
||||
expect(fileList.$el.find('.selectedActions .item-copyMove .label').text()).toEqual('Move or copy');
|
||||
testFiles[0].permissions = OC.PERMISSION_READ;
|
||||
$('.select-all').click();
|
||||
fileList.setFiles(testFiles);
|
||||
$('.select-all').click();
|
||||
expect(fileList.$el.find('.selectedActions .copy-move').hasClass('hidden')).toEqual(false);
|
||||
expect(fileList.$el.find('.selectedActions .copy-move .label').text()).toEqual('Copy');
|
||||
expect(fileList.$el.find('.selectedActions .item-copyMove').hasClass('hidden')).toEqual(false);
|
||||
expect(fileList.$el.find('.selectedActions .item-copyMove .label').text()).toEqual('Copy');
|
||||
testFiles[0].permissions = OC.PERMISSION_NONE;
|
||||
$('.select-all').click();
|
||||
fileList.setFiles(testFiles);
|
||||
$('.select-all').click();
|
||||
expect(fileList.$el.find('.selectedActions .copy-move').hasClass('hidden')).toEqual(true);
|
||||
expect(fileList.$el.find('.selectedActions .item-copyMove').hasClass('hidden')).toEqual(true);
|
||||
});
|
||||
it('show doesnt show the download action if one or more files are not downloadable', function () {
|
||||
fileList.setFiles(testFiles);
|
||||
$('#permissions').val(OC.PERMISSION_READ | OC.PERMISSION_UPDATE);
|
||||
$('.select-all').click();
|
||||
expect(fileList.$el.find('.selectedActions .download').hasClass('hidden')).toEqual(false);
|
||||
expect(fileList.$el.find('.selectedActions .item-download').hasClass('hidden')).toEqual(false);
|
||||
testFiles[0].permissions = OC.PERMISSION_UPDATE;
|
||||
$('.select-all').click();
|
||||
fileList.setFiles(testFiles);
|
||||
$('.select-all').click();
|
||||
expect(fileList.$el.find('.selectedActions .download').hasClass('hidden')).toEqual(true);
|
||||
expect(fileList.$el.find('.selectedActions .item-download').hasClass('hidden')).toEqual(true);
|
||||
});
|
||||
it('show doesnt show the delete action if one or more files are not deletable', 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);
|
||||
expect(fileList.$el.find('.selectedActions .item-delete').hasClass('hidden')).toEqual(false);
|
||||
testFiles[0].permissions = OC.PERMISSION_READ;
|
||||
$('.select-all').click();
|
||||
fileList.setFiles(testFiles);
|
||||
$('.select-all').click();
|
||||
expect(fileList.$el.find('.delete-selected').hasClass('hidden')).toEqual(true);
|
||||
expect(fileList.$el.find('.selectedActions .item-delete').hasClass('hidden')).toEqual(true);
|
||||
});
|
||||
});
|
||||
describe('Actions', function() {
|
||||
|
@ -2219,8 +2232,12 @@ describe('OCA.Files.FileList tests', function() {
|
|||
});
|
||||
});
|
||||
describe('Download', function() {
|
||||
beforeEach(function() {
|
||||
fileList.$el.find('.actions-selected').click();
|
||||
});
|
||||
|
||||
it('Opens download URL when clicking "Download"', function() {
|
||||
$('.selectedActions .download').click();
|
||||
$('.selectedActions .filesSelectMenu .download').click();
|
||||
expect(redirectStub.calledOnce).toEqual(true);
|
||||
expect(redirectStub.getCall(0).args[0]).toContain(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=%5B%22One.txt%22%2C%22Three.pdf%22%2C%22somedir%22%5D');
|
||||
redirectStub.restore();
|
||||
|
@ -2228,28 +2245,37 @@ describe('OCA.Files.FileList tests', function() {
|
|||
it('Downloads root folder when all selected in root folder', function() {
|
||||
$('#dir').val('/');
|
||||
$('.select-all').click();
|
||||
$('.selectedActions .download').click();
|
||||
$('.selectedActions .filesSelectMenu .download').click();
|
||||
expect(redirectStub.calledOnce).toEqual(true);
|
||||
expect(redirectStub.getCall(0).args[0]).toContain(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2F&files=');
|
||||
});
|
||||
it('Downloads parent folder when all selected in subfolder', function() {
|
||||
$('.select-all').click();
|
||||
$('.selectedActions .download').click();
|
||||
$('.selectedActions .filesSelectMenu .download').click();
|
||||
expect(redirectStub.calledOnce).toEqual(true);
|
||||
expect(redirectStub.getCall(0).args[0]).toContain(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2F&files=subdir');
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
fileList.$el.find('.actions-selected').click();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Delete', function() {
|
||||
var deleteStub, deferredDelete;
|
||||
beforeEach(function() {
|
||||
deferredDelete = $.Deferred();
|
||||
deleteStub = sinon.stub(filesClient, 'remove').returns(deferredDelete.promise());
|
||||
fileList.$el.find('.actions-selected').click();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
fileList.$el.find('.actions-selected').click();
|
||||
deleteStub.restore();
|
||||
});
|
||||
|
||||
it('Deletes selected files when "Delete" clicked', function() {
|
||||
$('.selectedActions .delete-selected').click();
|
||||
$('.selectedActions .filesSelectMenu .delete').click();
|
||||
|
||||
expect(deleteStub.callCount).toEqual(3);
|
||||
expect(deleteStub.getCall(0).args[0]).toEqual('/subdir/One.txt');
|
||||
|
@ -2265,7 +2291,7 @@ describe('OCA.Files.FileList tests', function() {
|
|||
});
|
||||
it('Deletes all files when all selected when "Delete" clicked', function() {
|
||||
$('.select-all').click();
|
||||
$('.selectedActions .delete-selected').click();
|
||||
$('.selectedActions .filesSelectMenu .delete').click();
|
||||
|
||||
expect(deleteStub.callCount).toEqual(4);
|
||||
expect(deleteStub.getCall(0).args[0]).toEqual('/subdir/One.txt');
|
||||
|
|
|
@ -30,7 +30,19 @@ OCA.Trashbin.App = {
|
|||
fileActions: this._createFileActions(),
|
||||
detailsViewEnabled: false,
|
||||
scrollTo: urlParams.scrollto,
|
||||
config: OCA.Files.App.getFilesConfig()
|
||||
config: OCA.Files.App.getFilesConfig(),
|
||||
multiSelectMenu: [
|
||||
{
|
||||
name: 'restore',
|
||||
displayName: t('files', 'Restore'),
|
||||
iconClass: 'icon-history',
|
||||
},
|
||||
{
|
||||
name: 'delete',
|
||||
displayName: t('files', 'Delete'),
|
||||
iconClass: 'icon-delete',
|
||||
}
|
||||
]
|
||||
}
|
||||
);
|
||||
},
|
||||
|
|
|
@ -153,7 +153,6 @@
|
|||
}
|
||||
this.fileSummary.update();
|
||||
this.updateEmptyContent();
|
||||
this.enableActions();
|
||||
},
|
||||
|
||||
_onClickRestoreSelected: function(event) {
|
||||
|
@ -162,7 +161,7 @@
|
|||
var allFiles = this.$el.find('.select-all').is(':checked');
|
||||
var files = [];
|
||||
var params = {};
|
||||
this.disableActions();
|
||||
this.fileMultiSelectMenu.toggleLoading('restore', true);
|
||||
if (allFiles) {
|
||||
this.showMask();
|
||||
params = {
|
||||
|
@ -192,13 +191,14 @@
|
|||
self.hideMask();
|
||||
// simply remove all files
|
||||
self.setFiles([]);
|
||||
self.enableActions();
|
||||
}
|
||||
else {
|
||||
self._removeCallback(result);
|
||||
}
|
||||
self.fileMultiSelectMenu.toggleLoading('restore', false);
|
||||
}
|
||||
);
|
||||
event.preventDefault();
|
||||
},
|
||||
|
||||
_onClickDeleteSelected: function(event) {
|
||||
|
@ -221,7 +221,7 @@
|
|||
};
|
||||
}
|
||||
|
||||
this.disableActions();
|
||||
this.fileMultiSelectMenu.toggleLoading('delete', true);
|
||||
if (allFiles) {
|
||||
this.showMask();
|
||||
}
|
||||
|
@ -242,11 +242,11 @@
|
|||
self.hideMask();
|
||||
// simply remove all files
|
||||
self.setFiles([]);
|
||||
self.enableActions();
|
||||
}
|
||||
else {
|
||||
self._removeCallback(result);
|
||||
}
|
||||
self.fileMultiSelectMenu.toggleLoading('delete', false);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
@ -268,16 +268,6 @@
|
|||
return '#';
|
||||
},
|
||||
|
||||
enableActions: function() {
|
||||
this.$el.find('.action').css('display', 'inline');
|
||||
this.$el.find('input:checkbox').removeClass('u-hidden');
|
||||
},
|
||||
|
||||
disableActions: function() {
|
||||
this.$el.find('.action').css('display', 'none');
|
||||
this.$el.find('input:checkbox').addClass('u-hidden');
|
||||
},
|
||||
|
||||
updateStorageStatistics: function() {
|
||||
// no op because the trashbin doesn't have
|
||||
// storage info like free space / used space
|
||||
|
|
|
@ -31,25 +31,15 @@
|
|||
<div id="headerName-container">
|
||||
<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">
|
||||
<span class="icon icon-history"></span>
|
||||
<span><?php p($l->t('Restore'))?></span>
|
||||
</a>
|
||||
<a href="" class="delete-selected">
|
||||
<span class="icon icon-delete"></span>
|
||||
<span><?php p($l->t('Delete'))?></span>
|
||||
<a href="" class="actions-selected">
|
||||
<span class="icon icon-more"></span>
|
||||
<span><?php p($l->t('Actions'))?></span>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</th>
|
||||
<th id="headerDate" class="hidden column-mtime">
|
||||
<a id="modified" class="columntitle" data-sort="mtime"><span><?php p($l->t( 'Deleted' )); ?></span><span class="sort-indicator"></span></a>
|
||||
<span class="selectedActions">
|
||||
<a href="" class="delete-selected">
|
||||
<span><?php p($l->t('Delete'))?></span>
|
||||
<span class="icon icon-delete"></span>
|
||||
</a>
|
||||
</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
|
@ -46,8 +46,8 @@ describe('OCA.Trashbin.FileList tests', function() {
|
|||
'<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>' +
|
||||
'<a href="" class="actions-selected"><span class="icon icon-more"></span><span>Actions</span>' +
|
||||
'</span>' +
|
||||
'</th></tr></thead>' +
|
||||
'<tbody id="fileList"></tbody>' +
|
||||
'<tfoot></tfoot>' +
|
||||
|
@ -90,7 +90,18 @@ describe('OCA.Trashbin.FileList tests', function() {
|
|||
var fileActions = OCA.Trashbin.App._createFileActions(fileList);
|
||||
fileList = new OCA.Trashbin.FileList(
|
||||
$('#app-content-trashbin'), {
|
||||
fileActions: fileActions
|
||||
fileActions: fileActions,
|
||||
multiSelectMenu: [{
|
||||
name: 'restore',
|
||||
displayName: t('files', 'Restore'),
|
||||
iconClass: 'icon-history',
|
||||
},
|
||||
{
|
||||
name: 'delete',
|
||||
displayName: t('files', 'Delete'),
|
||||
iconClass: 'icon-delete',
|
||||
}
|
||||
]
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -260,33 +271,41 @@ describe('OCA.Trashbin.FileList tests', function() {
|
|||
fileList.findFileEl('One.txt.d11111').find('input:checkbox').click();
|
||||
fileList.findFileEl('Three.pdf.d33333').find('input:checkbox').click();
|
||||
fileList.findFileEl('somedir.d99999').find('input:checkbox').click();
|
||||
fileList.$el.find('.actions-selected').click();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
fileList.$el.find('.actions-selected').click();
|
||||
});
|
||||
|
||||
describe('Delete', function() {
|
||||
it('Shows trashbin actions', function() {
|
||||
// visible because a few files were selected
|
||||
expect($('.selectedActions').is(':visible')).toEqual(true);
|
||||
expect($('.selectedActions .delete-selected').is(':visible')).toEqual(true);
|
||||
expect($('.selectedActions .undelete').is(':visible')).toEqual(true);
|
||||
expect($('.selectedActions .item-delete').is(':visible')).toEqual(true);
|
||||
expect($('.selectedActions .item-restore').is(':visible')).toEqual(true);
|
||||
|
||||
// check
|
||||
fileList.$el.find('.select-all').click();
|
||||
|
||||
// stays visible
|
||||
expect($('.selectedActions').is(':visible')).toEqual(true);
|
||||
expect($('.selectedActions .delete-selected').is(':visible')).toEqual(true);
|
||||
expect($('.selectedActions .undelete').is(':visible')).toEqual(true);
|
||||
expect($('.selectedActions .item-delete').is(':visible')).toEqual(true);
|
||||
expect($('.selectedActions .item-restore').is(':visible')).toEqual(true);
|
||||
|
||||
// uncheck
|
||||
fileList.$el.find('.select-all').click();
|
||||
|
||||
// becomes hidden now
|
||||
expect($('.selectedActions').is(':visible')).toEqual(false);
|
||||
expect($('.selectedActions .delete-selected').is(':visible')).toEqual(false);
|
||||
expect($('.selectedActions .undelete').is(':visible')).toEqual(false);
|
||||
expect($('.selectedActions .item-delete').is(':visible')).toEqual(false);
|
||||
expect($('.selectedActions .item-restore').is(':visible')).toEqual(false);
|
||||
});
|
||||
it('Deletes selected files when "Delete" clicked', function() {
|
||||
var request;
|
||||
$('.selectedActions .delete-selected').click();
|
||||
var $deleteLink = $('.selectedActions .filesSelectMenu .delete');
|
||||
$deleteLink.click();
|
||||
expect($deleteLink.find('.icon-loading-small').length).toEqual(1);
|
||||
expect(fakeServer.requests.length).toEqual(1);
|
||||
request = fakeServer.requests[0];
|
||||
expect(request.url).toEqual(OC.webroot + '/index.php/apps/files_trashbin/ajax/delete.php');
|
||||
|
@ -306,6 +325,7 @@ describe('OCA.Trashbin.FileList tests', function() {
|
|||
}
|
||||
})
|
||||
);
|
||||
expect($deleteLink.find('.icon-loading-small').length).toEqual(0);
|
||||
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);
|
||||
|
@ -314,7 +334,7 @@ describe('OCA.Trashbin.FileList tests', function() {
|
|||
it('Deletes all files when all selected when "Delete" clicked', function() {
|
||||
var request;
|
||||
$('.select-all').click();
|
||||
$('.selectedActions .delete-selected').click();
|
||||
$('.selectedActions .filesSelectMenu .delete').click();
|
||||
expect(fakeServer.requests.length).toEqual(1);
|
||||
request = fakeServer.requests[0];
|
||||
expect(request.url).toEqual(OC.webroot + '/index.php/apps/files_trashbin/ajax/delete.php');
|
||||
|
@ -331,7 +351,9 @@ describe('OCA.Trashbin.FileList tests', function() {
|
|||
describe('Restore', function() {
|
||||
it('Restores selected files when "Restore" clicked', function() {
|
||||
var request;
|
||||
$('.selectedActions .undelete').click();
|
||||
var $restoreLink = $('.selectedActions .filesSelectMenu .restore');
|
||||
$restoreLink.click();
|
||||
expect($restoreLink.find('.icon-loading-small').length).toEqual(1);
|
||||
expect(fakeServer.requests.length).toEqual(1);
|
||||
request = fakeServer.requests[0];
|
||||
expect(request.url).toEqual(OC.webroot + '/index.php/apps/files_trashbin/ajax/undelete.php');
|
||||
|
@ -351,6 +373,7 @@ describe('OCA.Trashbin.FileList tests', function() {
|
|||
}
|
||||
})
|
||||
);
|
||||
expect($restoreLink.find('.icon-loading-small').length).toEqual(0);
|
||||
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);
|
||||
|
@ -359,7 +382,7 @@ describe('OCA.Trashbin.FileList tests', function() {
|
|||
it('Restores all files when all selected when "Restore" clicked', function() {
|
||||
var request;
|
||||
$('.select-all').click();
|
||||
$('.selectedActions .undelete').click();
|
||||
$('.selectedActions .filesSelectMenu .restore').click();
|
||||
expect(fakeServer.requests.length).toEqual(1);
|
||||
request = fakeServer.requests[0];
|
||||
expect(request.url).toEqual(OC.webroot + '/index.php/apps/files_trashbin/ajax/undelete.php');
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
#app-navigation-toggle {
|
||||
position: fixed;
|
||||
display: inline-block !important;
|
||||
top: 45px;
|
||||
top: 50px;
|
||||
left: 0;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
|
|
Loading…
Reference in a new issue