Merge pull request #6709 from nextcloud/show-checkbox-where-the-favourite-icon-is-now
Show checkbox where the favourite icon is now
This commit is contained in:
commit
1978867a11
14 changed files with 292 additions and 160 deletions
|
@ -230,9 +230,6 @@ table th#headerName {
|
|||
position: relative;
|
||||
height: 50px;
|
||||
}
|
||||
.has-favorites #headerName-container {
|
||||
padding-left: 50px;
|
||||
}
|
||||
|
||||
table th#headerSize, table td.filesize {
|
||||
text-align: right;
|
||||
|
@ -294,7 +291,12 @@ table td.filename a.name {
|
|||
line-height: 50px;
|
||||
padding: 0;
|
||||
}
|
||||
table td.filename label.icon-loading-small {
|
||||
table td.filename .thumbnail-wrapper {
|
||||
position: absolute;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
table td.filename .thumbnail-wrapper.icon-loading-small {
|
||||
&:after {
|
||||
z-index: 10;
|
||||
}
|
||||
|
@ -306,10 +308,10 @@ table td.filename .thumbnail {
|
|||
display: inline-block;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background-size: 32px;
|
||||
margin-left: 9px;
|
||||
margin-top: 9px;
|
||||
cursor: pointer;
|
||||
float: left;
|
||||
position: absolute;
|
||||
z-index: 4;
|
||||
}
|
||||
|
@ -319,12 +321,9 @@ table td.filename input.filename {
|
|||
margin-left: 48px;
|
||||
cursor: text;
|
||||
}
|
||||
.has-favorites table td.filename input.filename {
|
||||
margin-left: 52px;
|
||||
}
|
||||
|
||||
table td.filename a, table td.login, table td.logout, table td.download, table td.upload, table td.create, table td.delete { padding:3px 8px 8px 3px; }
|
||||
table td.filename .nametext, .uploadtext, .modified, .column-last>span:first-child { float:left; padding:15px 0; }
|
||||
table td.filename .nametext, .modified, .column-last>span:first-child { float:left; padding:15px 0; }
|
||||
|
||||
.modified, .column-last>span:first-child {
|
||||
position: relative;
|
||||
|
@ -336,22 +335,23 @@ table td.filename .nametext, .uploadtext, .modified, .column-last>span:first-chi
|
|||
/* TODO fix usability bug (accidental file/folder selection) */
|
||||
table td.filename .nametext {
|
||||
position: absolute;
|
||||
left: 55px;
|
||||
padding: 0;
|
||||
padding-left: 55px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 70%;
|
||||
max-width: 800px;
|
||||
height: 100%;
|
||||
z-index: 10;
|
||||
}
|
||||
table td.filename .uploadtext {
|
||||
position: absolute;
|
||||
left: 55px;
|
||||
}
|
||||
/* ellipsis on file names */
|
||||
table td.filename .nametext .innernametext {
|
||||
max-width: calc(100% - 100px) !important;
|
||||
}
|
||||
.has-favorites #fileList td.filename a.name {
|
||||
left: 50px;
|
||||
margin-right: 50px;
|
||||
}
|
||||
|
||||
.hide-hidden-files #fileList tr.hidden-file,
|
||||
.hide-hidden-files #fileList tr.hidden-file.dragging {
|
||||
|
@ -437,49 +437,27 @@ table td.filename .uploadtext {
|
|||
opacity: .5;
|
||||
}
|
||||
|
||||
/* File checkboxes */
|
||||
#fileList tr td.filename>.selectCheckBox + label:before {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
table td.selection {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Show checkbox when hovering, checked, or selected */
|
||||
#fileList tr:hover td.filename>.selectCheckBox + label:before,
|
||||
#fileList tr:focus td.filename>.selectCheckBox + label:before,
|
||||
#fileList tr td.filename>.selectCheckBox:checked + label:before,
|
||||
#fileList tr.selected td.filename>.selectCheckBox + label:before {
|
||||
/* File checkboxes */
|
||||
#fileList tr td.selection>.selectCheckBox + label:before {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
/* Show checkbox with full opacity when hovering, checked, or selected */
|
||||
#fileList tr:hover td.selection>.selectCheckBox + label:before,
|
||||
#fileList tr:focus td.selection>.selectCheckBox + label:before,
|
||||
#fileList tr td.selection>.selectCheckBox:checked + label:before,
|
||||
#fileList tr.selected td.selection>.selectCheckBox + label:before {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Use label to have bigger clickable size for checkbox */
|
||||
#fileList tr td.filename>.selectCheckBox + label,
|
||||
#fileList tr td.selection>.selectCheckBox + label,
|
||||
.select-all + label {
|
||||
background-position: 30px 30px;
|
||||
height: 50px;
|
||||
position: absolute;
|
||||
width: 50px;
|
||||
z-index: 5;
|
||||
}
|
||||
#fileList tr td.filename>.selectCheckBox {
|
||||
/* sometimes checkbox height is bigger (KDE/Qt), so setting to absolute
|
||||
* to prevent it to increase the height */
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
}
|
||||
.select-all + label {
|
||||
top: 0;
|
||||
}
|
||||
.select-all + label:before {
|
||||
position: absolute;
|
||||
top: 18px;
|
||||
left: 18px;
|
||||
z-index: 10;
|
||||
}
|
||||
.has-favorites .select-all {
|
||||
left: 68px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
#fileList tr td.filename {
|
||||
|
@ -500,10 +478,11 @@ table td.filename .uploadtext {
|
|||
display: inline-block;
|
||||
float: left;
|
||||
}
|
||||
#fileList tr td.filename .action-favorite {
|
||||
#fileList tr td.filename .favorite-mark {
|
||||
position: absolute;
|
||||
display: block;
|
||||
float: left;
|
||||
width: 30px;
|
||||
top: -6px;
|
||||
right: -6px;
|
||||
line-height: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
@ -615,7 +594,7 @@ a.action > img {
|
|||
padding-left: 6px;
|
||||
}
|
||||
|
||||
#fileList .action.action-favorite.permanent {
|
||||
#fileList .favorite-mark.permanent {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
@ -659,9 +638,6 @@ table tr.summary td {
|
|||
.summary .info {
|
||||
margin-left: 40px;
|
||||
}
|
||||
.has-favorites .summary .info {
|
||||
margin-left: 90px;
|
||||
}
|
||||
|
||||
table.dragshadow {
|
||||
width:auto;
|
||||
|
@ -714,12 +690,24 @@ table.dragshadow td.size {
|
|||
|
||||
#filestable .filename .action .icon,
|
||||
#filestable .selectedActions a .icon,
|
||||
#filestable .filename .favorite-mark .icon,
|
||||
#controls .actions .button .icon {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
background-size: 16px 16px;
|
||||
}
|
||||
|
||||
#filestable .filename .favorite-mark {
|
||||
// Override default icons to always hide the star icon and always show the
|
||||
// starred icon even when hovered or focused.
|
||||
& .icon-star {
|
||||
background-image: none;
|
||||
}
|
||||
& .icon-starred {
|
||||
background-image: url('../../../core/img/actions/starred.svg?v=1');
|
||||
}
|
||||
}
|
||||
|
||||
#filestable .filename .action .icon.hidden,
|
||||
#filestable .selectedActions a .icon.hidden,
|
||||
#controls .actions .button .icon.hidden {
|
||||
|
|
|
@ -24,10 +24,6 @@ table td.date {
|
|||
table td {
|
||||
padding: 0;
|
||||
}
|
||||
/* and accordingly fix left margin of file list summary on mobile */
|
||||
.summary .info {
|
||||
margin-left: 105px;
|
||||
}
|
||||
|
||||
/* remove shift for multiselect bar to account for missing navigation */
|
||||
table.multiselect thead {
|
||||
|
|
|
@ -706,7 +706,7 @@
|
|||
* @property {String} mime mime type
|
||||
* @property {int} permissions permissions
|
||||
* @property {(Function|String)} icon icon path to the icon or function that returns it (deprecated, use iconClass instead)
|
||||
* @property {(Function|String)} iconClass class name of the icon (recommended for theming)
|
||||
* @property {(String|OCA.Files.FileActions~iconClassFunction)} iconClass class name of the icon (recommended for theming)
|
||||
* @property {OCA.Files.FileActions~renderActionFunction} [render] optional rendering function
|
||||
* @property {OCA.Files.FileActions~actionHandler} actionHandler action handler function
|
||||
*/
|
||||
|
@ -745,6 +745,17 @@
|
|||
* @return {String} display name
|
||||
*/
|
||||
|
||||
/**
|
||||
* Icon class function for actions.
|
||||
* The function returns the icon class of the action using
|
||||
* the given context information.
|
||||
*
|
||||
* @callback OCA.Files.FileActions~iconClassFunction
|
||||
* @param {String} fileName name of the file on which the action must be performed
|
||||
* @param {OCA.Files.FileActionContext} context action context
|
||||
* @return {String} icon class
|
||||
*/
|
||||
|
||||
/**
|
||||
* Action handler function for file actions
|
||||
*
|
||||
|
|
|
@ -115,6 +115,11 @@
|
|||
item = _.extend({}, item);
|
||||
item.displayName = item.displayName(self._context);
|
||||
}
|
||||
if (_.isFunction(item.iconClass)) {
|
||||
var fileName = self._context.$file.attr('data-file');
|
||||
item = _.extend({}, item);
|
||||
item.iconClass = item.iconClass(fileName, self._context);
|
||||
}
|
||||
return item;
|
||||
});
|
||||
items = items.sort(function(actionA, actionB) {
|
||||
|
|
|
@ -332,7 +332,7 @@
|
|||
|
||||
this.$fileList.on('click','td.filename>a.name, td.filesize, td.date', _.bind(this._onClickFile, this));
|
||||
|
||||
this.$fileList.on('change', 'td.filename>.selectCheckBox', _.bind(this._onClickFileCheckbox, this));
|
||||
this.$fileList.on('change', 'td.selection>.selectCheckBox', _.bind(this._onClickFileCheckbox, this));
|
||||
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));
|
||||
|
@ -593,7 +593,7 @@
|
|||
* @param {bool} state true to select, false to deselect
|
||||
*/
|
||||
_selectFileEl: function($tr, state, showDetailsView) {
|
||||
var $checkbox = $tr.find('td.filename>.selectCheckBox');
|
||||
var $checkbox = $tr.find('td.selection>.selectCheckBox');
|
||||
var oldData = !!this._selectedFiles[$tr.data('id')];
|
||||
var data;
|
||||
$checkbox.prop('checked', state);
|
||||
|
@ -649,7 +649,7 @@
|
|||
else {
|
||||
this._lastChecked = $tr;
|
||||
}
|
||||
var $checkbox = $tr.find('td.filename>.selectCheckBox');
|
||||
var $checkbox = $tr.find('td.selection>.selectCheckBox');
|
||||
this._selectFileEl($tr, !$checkbox.prop('checked'));
|
||||
this.updateSelectionSummary();
|
||||
} else {
|
||||
|
@ -704,7 +704,7 @@
|
|||
*/
|
||||
_onClickSelectAll: function(e) {
|
||||
var checked = $(e.target).prop('checked');
|
||||
this.$fileList.find('td.filename>.selectCheckBox').prop('checked', checked)
|
||||
this.$fileList.find('td.selection>.selectCheckBox').prop('checked', checked)
|
||||
.closest('tr').toggleClass('selected', checked);
|
||||
this._selectedFiles = {};
|
||||
this._selectionSummary.clear();
|
||||
|
@ -1063,6 +1063,13 @@
|
|||
|
||||
this.$fileList.empty();
|
||||
|
||||
if (this._allowSelection) {
|
||||
// The results table, which has no selection column, checks
|
||||
// whether the main table has a selection column or not in order
|
||||
// to align its contents with those of the main table.
|
||||
this.$el.addClass('has-selection');
|
||||
}
|
||||
|
||||
// clear "Select all" checkbox
|
||||
this.$el.find('.select-all').prop('checked', false);
|
||||
|
||||
|
@ -1192,6 +1199,20 @@
|
|||
path = this.getCurrentDirectory();
|
||||
}
|
||||
|
||||
// selection td
|
||||
if (this._allowSelection) {
|
||||
td = $('<td class="selection"></td>');
|
||||
|
||||
td.append(
|
||||
'<input id="select-' + this.id + '-' + fileData.id +
|
||||
'" type="checkbox" class="selectCheckBox checkbox"/><label for="select-' + this.id + '-' + fileData.id + '">' +
|
||||
'<span class="hidden-visually">' + t('files', 'Select') + '</span>' +
|
||||
'</label>'
|
||||
);
|
||||
|
||||
tr.append(td);
|
||||
}
|
||||
|
||||
// filename td
|
||||
td = $('<td class="filename"></td>');
|
||||
|
||||
|
@ -1203,22 +1224,13 @@
|
|||
else {
|
||||
linkUrl = this.getDownloadUrl(name, path, type === 'dir');
|
||||
}
|
||||
if (this._allowSelection) {
|
||||
td.append(
|
||||
'<input id="select-' + this.id + '-' + fileData.id +
|
||||
'" type="checkbox" class="selectCheckBox checkbox"/><label for="select-' + this.id + '-' + fileData.id + '">' +
|
||||
'<div class="thumbnail" style="background-image:url(' + icon + '); background-size: 32px;"></div>' +
|
||||
'<span class="hidden-visually">' + t('files', 'Select') + '</span>' +
|
||||
'</label>'
|
||||
);
|
||||
} else {
|
||||
td.append('<div class="thumbnail" style="background-image:url(' + icon + '); background-size: 32px;"></div>');
|
||||
}
|
||||
var linkElem = $('<a></a>').attr({
|
||||
"class": "name",
|
||||
"href": linkUrl
|
||||
});
|
||||
|
||||
linkElem.append('<div class="thumbnail-wrapper"><div class="thumbnail" style="background-image:url(' + icon + ');"></div></div>');
|
||||
|
||||
// from here work on the display name
|
||||
name = fileData.displayName || name;
|
||||
|
||||
|
@ -2614,6 +2626,13 @@
|
|||
*/
|
||||
_createSummary: function() {
|
||||
var $tr = $('<tr class="summary"></tr>');
|
||||
|
||||
if (this._allowSelection) {
|
||||
// Dummy column for selection, as all rows must have the same
|
||||
// number of columns.
|
||||
$tr.append('<td></td>');
|
||||
}
|
||||
|
||||
this.$el.find('tfoot').append($tr);
|
||||
|
||||
return new OCA.Files.FileSummary($tr, {config: this._filesConfig});
|
||||
|
|
|
@ -17,12 +17,12 @@
|
|||
PROPERTY_FAVORITE: '{' + OC.Files.Client.NS_OWNCLOUD + '}favorite'
|
||||
});
|
||||
|
||||
var TEMPLATE_FAVORITE_ACTION =
|
||||
'<a href="#" ' +
|
||||
'class="action action-favorite {{#isFavorite}}permanent{{/isFavorite}}">' +
|
||||
var TEMPLATE_FAVORITE_MARK =
|
||||
'<div ' +
|
||||
'class="favorite-mark {{#isFavorite}}permanent{{/isFavorite}}">' +
|
||||
'<span class="icon {{iconClass}}" />' +
|
||||
'<span class="hidden-visually">{{altText}}</span>' +
|
||||
'</a>';
|
||||
'</div>';
|
||||
|
||||
/**
|
||||
* Returns the icon class for the matching state
|
||||
|
@ -42,24 +42,24 @@
|
|||
*/
|
||||
function renderStar(state) {
|
||||
if (!this._template) {
|
||||
this._template = Handlebars.compile(TEMPLATE_FAVORITE_ACTION);
|
||||
this._template = Handlebars.compile(TEMPLATE_FAVORITE_MARK);
|
||||
}
|
||||
return this._template({
|
||||
isFavorite: state,
|
||||
altText: state ? t('files', 'Favorited') : t('files', 'Favorite'),
|
||||
altText: state ? t('files', 'Favorited') : t('files', 'Not favorited'),
|
||||
iconClass: getStarIconClass(state)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle star icon on action element
|
||||
* Toggle star icon on favorite mark element
|
||||
*
|
||||
* @param {Object} action element
|
||||
* @param {Object} $favoriteMarkEl favorite mark element
|
||||
* @param {boolean} state true if starred, false otherwise
|
||||
*/
|
||||
function toggleStar($actionEl, state) {
|
||||
$actionEl.removeClass('icon-star icon-starred').addClass(getStarIconClass(state));
|
||||
$actionEl.toggleClass('permanent', state);
|
||||
function toggleStar($favoriteMarkEl, state) {
|
||||
$favoriteMarkEl.removeClass('icon-star icon-starred').addClass(getStarIconClass(state));
|
||||
$favoriteMarkEl.toggleClass('permanent', state);
|
||||
}
|
||||
|
||||
OCA.Files = OCA.Files || {};
|
||||
|
@ -67,8 +67,9 @@
|
|||
/**
|
||||
* @namespace OCA.Files.TagsPlugin
|
||||
*
|
||||
* Extends the file actions and file list to include a favorite action icon
|
||||
* and addition "data-tags" and "data-favorite" attributes.
|
||||
* Extends the file actions and file list to include a favorite mark icon
|
||||
* and a favorite action in the file actions menu; it also adds "data-tags"
|
||||
* and "data-favorite" attributes to file elements.
|
||||
*/
|
||||
OCA.Files.TagsPlugin = {
|
||||
name: 'Tags',
|
||||
|
@ -84,22 +85,38 @@
|
|||
|
||||
_extendFileActions: function(fileActions) {
|
||||
var self = this;
|
||||
// register "star" action
|
||||
|
||||
fileActions.registerAction({
|
||||
name: 'Favorite',
|
||||
displayName: t('files', 'Favorite'),
|
||||
mime: 'all',
|
||||
permissions: OC.PERMISSION_READ,
|
||||
type: OCA.Files.FileActions.TYPE_INLINE,
|
||||
render: function(actionSpec, isDefault, context) {
|
||||
displayName: function(context) {
|
||||
var $file = context.$file;
|
||||
var isFavorite = $file.data('favorite') === true;
|
||||
var $icon = $(renderStar(isFavorite));
|
||||
$file.find('td:first>.favorite').replaceWith($icon);
|
||||
return $icon;
|
||||
|
||||
if (isFavorite) {
|
||||
return t('files', 'Remove from favorites');
|
||||
}
|
||||
|
||||
// As it is currently not possible to provide a context for
|
||||
// the i18n strings "Add to favorites" was used instead of
|
||||
// "Favorite" to remove the ambiguity between verb and noun
|
||||
// when it is translated.
|
||||
return t('files', 'Add to favorites');
|
||||
},
|
||||
mime: 'all',
|
||||
order: -23,
|
||||
permissions: OC.PERMISSION_READ,
|
||||
iconClass: function(fileName, context) {
|
||||
var $file = context.$file;
|
||||
var isFavorite = $file.data('favorite') === true;
|
||||
|
||||
if (isFavorite) {
|
||||
return 'icon-starred';
|
||||
}
|
||||
|
||||
return 'icon-star';
|
||||
},
|
||||
actionHandler: function(fileName, context) {
|
||||
var $actionEl = context.$file.find('.action-favorite');
|
||||
var $favoriteMarkEl = context.$file.find('.favorite-mark');
|
||||
var $file = context.$file;
|
||||
var fileInfo = context.fileList.files[$file.index()];
|
||||
var dir = context.dir || context.fileList.getCurrentDirectory();
|
||||
|
@ -118,14 +135,14 @@
|
|||
}
|
||||
|
||||
// pre-toggle the star
|
||||
toggleStar($actionEl, !isFavorite);
|
||||
toggleStar($favoriteMarkEl, !isFavorite);
|
||||
|
||||
context.fileInfoModel.trigger('busy', context.fileInfoModel, true);
|
||||
|
||||
self.applyFileTags(
|
||||
dir + '/' + fileName,
|
||||
tags,
|
||||
$actionEl,
|
||||
$favoriteMarkEl,
|
||||
isFavorite
|
||||
).then(function(result) {
|
||||
context.fileInfoModel.trigger('busy', context.fileInfoModel, false);
|
||||
|
@ -145,17 +162,19 @@
|
|||
|
||||
_extendFileList: function(fileList) {
|
||||
// extend row prototype
|
||||
fileList.$el.addClass('has-favorites');
|
||||
var oldCreateRow = fileList._createRow;
|
||||
fileList._createRow = function(fileData) {
|
||||
var $tr = oldCreateRow.apply(this, arguments);
|
||||
var isFavorite = false;
|
||||
if (fileData.tags) {
|
||||
$tr.attr('data-tags', fileData.tags.join('|'));
|
||||
if (fileData.tags.indexOf(OC.TAG_FAVORITE) >= 0) {
|
||||
$tr.attr('data-favorite', true);
|
||||
isFavorite = true;
|
||||
}
|
||||
}
|
||||
$tr.find('td:first').prepend('<div class="favorite"></div>');
|
||||
var $icon = $(renderStar(isFavorite));
|
||||
$tr.find('td.filename .thumbnail').append($icon);
|
||||
return $tr;
|
||||
};
|
||||
var oldElementToFile = fileList.elementToFile;
|
||||
|
@ -215,10 +234,10 @@
|
|||
*
|
||||
* @param {String} fileName path to the file or folder to tag
|
||||
* @param {Array.<String>} tagNames array of tag names
|
||||
* @param {Object} $actionEl element
|
||||
* @param {Object} $favoriteMarkEl favorite mark element
|
||||
* @param {boolean} isFavorite Was the item favorited before
|
||||
*/
|
||||
applyFileTags: function(fileName, tagNames, $actionEl, isFavorite) {
|
||||
applyFileTags: function(fileName, tagNames, $favoriteMarkEl, isFavorite) {
|
||||
var encodedPath = OC.encodePath(fileName);
|
||||
while (encodedPath[0] === '/') {
|
||||
encodedPath = encodedPath.substr(1);
|
||||
|
@ -238,7 +257,7 @@
|
|||
message = ': ' + response.responseJSON.message;
|
||||
}
|
||||
OC.Notification.show(t('files', 'An error occurred while trying to update the tags' + message), {type: 'error'});
|
||||
toggleStar($actionEl, isFavorite);
|
||||
toggleStar($favoriteMarkEl, isFavorite);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -41,12 +41,14 @@
|
|||
<table id="filestable" data-allow-public-upload="<?php p($_['publicUploadEnabled'])?>" data-preview-x="32" data-preview-y="32">
|
||||
<thead>
|
||||
<tr>
|
||||
<th id="headerSelection" class="hidden column-selection">
|
||||
<input type="checkbox" id="select_all_files" class="select-all checkbox"/>
|
||||
<label for="select_all_files">
|
||||
<span class="hidden-visually"><?php p($l->t('Select all'))?></span>
|
||||
</label>
|
||||
</th>
|
||||
<th id='headerName' class="hidden column-name">
|
||||
<div id="headerName-container">
|
||||
<input type="checkbox" id="select_all_files" class="select-all checkbox"/>
|
||||
<label for="select_all_files">
|
||||
<span class="hidden-visually"><?php p($l->t('Select all'))?></span>
|
||||
</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="copy-move">
|
||||
|
|
|
@ -205,6 +205,34 @@ describe('OCA.Files.FileActionsMenu tests', function() {
|
|||
expect(displayNameStub.calledWith(menuContext)).toEqual(true);
|
||||
expect(menu.$el.find('a[data-action=Something]').text()).toEqual('Test');
|
||||
});
|
||||
it('uses plain iconClass', function() {
|
||||
fileActions.registerAction({
|
||||
name: 'Something',
|
||||
mime: 'text/plain',
|
||||
permissions: OC.PERMISSION_ALL,
|
||||
iconClass: 'test'
|
||||
});
|
||||
|
||||
menu.render();
|
||||
|
||||
expect(menu.$el.find('a[data-action=Something]').children('span.icon').hasClass('test')).toEqual(true);
|
||||
});
|
||||
it('calls iconClass function', function() {
|
||||
var iconClassStub = sinon.stub().returns('test');
|
||||
|
||||
fileActions.registerAction({
|
||||
name: 'Something',
|
||||
mime: 'text/plain',
|
||||
permissions: OC.PERMISSION_ALL,
|
||||
iconClass: iconClassStub
|
||||
});
|
||||
|
||||
menu.render();
|
||||
|
||||
expect(iconClassStub.calledOnce).toEqual(true);
|
||||
expect(iconClassStub.calledWith(menuContext.$file.attr('data-file'), menuContext)).toEqual(true);
|
||||
expect(menu.$el.find('a[data-action=Something]').children('span.icon').hasClass('test')).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('action handler', function() {
|
||||
|
|
|
@ -712,8 +712,14 @@ describe('OCA.Files.FileList tests', function() {
|
|||
fileList.add(testFiles[i], {silent: true});
|
||||
}
|
||||
|
||||
$tr = fileList.findFileEl('One.txt');
|
||||
expect($tr.find('a.name').css('display')).not.toEqual('none');
|
||||
|
||||
// trigger rename prompt
|
||||
fileList.rename('One.txt');
|
||||
|
||||
expect($tr.find('a.name').css('display')).toEqual('none');
|
||||
|
||||
$input = fileList.$fileList.find('input.filename');
|
||||
$input.val('Two.jpg');
|
||||
|
||||
|
@ -735,12 +741,12 @@ describe('OCA.Files.FileList tests', function() {
|
|||
$tr = fileList.findFileEl('One.txt');
|
||||
expect($tr.length).toEqual(1);
|
||||
expect($tr.find('a .nametext').text().trim()).toEqual('One.txt');
|
||||
expect($tr.find('a.name').is(':visible')).toEqual(true);
|
||||
expect($tr.find('a.name').css('display')).not.toEqual('none');
|
||||
|
||||
$tr = fileList.findFileEl('Two.jpg');
|
||||
expect($tr.length).toEqual(1);
|
||||
expect($tr.find('a .nametext').text().trim()).toEqual('Two.jpg');
|
||||
expect($tr.find('a.name').is(':visible')).toEqual(true);
|
||||
expect($tr.find('a.name').css('display')).not.toEqual('none');
|
||||
|
||||
// input and form are gone
|
||||
expect(fileList.$fileList.find('input.filename').length).toEqual(0);
|
||||
|
@ -750,7 +756,7 @@ describe('OCA.Files.FileList tests', function() {
|
|||
doRename();
|
||||
|
||||
expect(fileList.findFileEl('Tu_after_three.txt').find('.thumbnail').parent().attr('class'))
|
||||
.toEqual('icon-loading-small');
|
||||
.toContain('icon-loading-small');
|
||||
|
||||
deferredRename.reject(409);
|
||||
|
||||
|
@ -838,7 +844,7 @@ describe('OCA.Files.FileList tests', function() {
|
|||
fileList.move('One.txt', '/somedir');
|
||||
|
||||
expect(fileList.findFileEl('One.txt').find('.thumbnail').parent().attr('class'))
|
||||
.toEqual('icon-loading-small');
|
||||
.toContain('icon-loading-small');
|
||||
|
||||
expect(moveStub.calledOnce).toEqual(true);
|
||||
|
||||
|
@ -935,7 +941,7 @@ describe('OCA.Files.FileList tests', function() {
|
|||
fileList.copy('One.txt', '/somedir');
|
||||
|
||||
expect(fileList.findFileEl('One.txt').find('.thumbnail').parent().attr('class'))
|
||||
.toEqual('icon-loading-small');
|
||||
.toContain('icon-loading-small');
|
||||
|
||||
expect(copyStub.calledOnce).toEqual(true);
|
||||
|
||||
|
@ -1741,7 +1747,7 @@ describe('OCA.Files.FileList tests', function() {
|
|||
it('Selects a file when clicking its checkbox', function() {
|
||||
var $tr = fileList.findFileEl('One.txt');
|
||||
expect($tr.find('input:checkbox').prop('checked')).toEqual(false);
|
||||
$tr.find('td.filename input:checkbox').click();
|
||||
$tr.find('td.selection input:checkbox').click();
|
||||
|
||||
expect($tr.find('input:checkbox').prop('checked')).toEqual(true);
|
||||
});
|
||||
|
@ -1779,7 +1785,7 @@ describe('OCA.Files.FileList tests', function() {
|
|||
var $tr = fileList.findFileEl('One.txt');
|
||||
var $tr2 = fileList.findFileEl('Three.pdf');
|
||||
var e;
|
||||
$tr.find('td.filename input:checkbox').click();
|
||||
$tr.find('td.selection input:checkbox').click();
|
||||
e = new $.Event('click');
|
||||
e.shiftKey = true;
|
||||
$tr2.find('td.filename .name').trigger(e);
|
||||
|
@ -1797,7 +1803,7 @@ describe('OCA.Files.FileList tests', function() {
|
|||
var $tr = fileList.findFileEl('One.txt');
|
||||
var $tr2 = fileList.findFileEl('Three.pdf');
|
||||
var e;
|
||||
$tr2.find('td.filename input:checkbox').click();
|
||||
$tr2.find('td.selection input:checkbox').click();
|
||||
e = new $.Event('click');
|
||||
e.shiftKey = true;
|
||||
$tr.find('td.filename .name').trigger(e);
|
||||
|
@ -1813,13 +1819,13 @@ describe('OCA.Files.FileList tests', function() {
|
|||
});
|
||||
it('Selecting all files will automatically check "select all" checkbox', function() {
|
||||
expect($('.select-all').prop('checked')).toEqual(false);
|
||||
$('#fileList tr td.filename input:checkbox').click();
|
||||
$('#fileList tr td.selection input:checkbox').click();
|
||||
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);
|
||||
$('#fileList tr td.filename input:checkbox').click();
|
||||
$('#fileList tr td.selection input:checkbox').click();
|
||||
expect($('.select-all').prop('checked')).toEqual(false);
|
||||
});
|
||||
it('Selecting all files also selects hidden files when invisible', function() {
|
||||
|
@ -1831,7 +1837,7 @@ describe('OCA.Files.FileList tests', function() {
|
|||
size: 150
|
||||
}));
|
||||
$('.select-all').click();
|
||||
expect($tr.find('td.filename input:checkbox').prop('checked')).toEqual(true);
|
||||
expect($tr.find('td.selection input:checkbox').prop('checked')).toEqual(true);
|
||||
expect(_.pluck(fileList.getSelectedFiles(), 'name')).toContain('.hidden');
|
||||
});
|
||||
it('Clicking "select all" will select/deselect all files', function() {
|
||||
|
@ -3150,7 +3156,7 @@ describe('OCA.Files.FileList tests', function() {
|
|||
fileList.showFileBusyState('Two.jpg', true);
|
||||
expect($tr.hasClass('busy')).toEqual(true);
|
||||
expect($tr.find('.thumbnail').parent().attr('class'))
|
||||
.toEqual('icon-loading-small');
|
||||
.toContain('icon-loading-small');
|
||||
|
||||
|
||||
fileList.showFileBusyState('Two.jpg', false);
|
||||
|
|
|
@ -49,39 +49,39 @@ describe('OCA.Files.TagsPlugin tests', function() {
|
|||
|
||||
describe('Favorites icon', function() {
|
||||
it('renders favorite icon and extra data', function() {
|
||||
var $action, $tr;
|
||||
var $favoriteMark, $tr;
|
||||
fileList.setFiles(testFiles);
|
||||
$tr = fileList.$el.find('tbody tr:first');
|
||||
$action = $tr.find('.action-favorite');
|
||||
expect($action.length).toEqual(1);
|
||||
expect($action.hasClass('permanent')).toEqual(false);
|
||||
$favoriteMark = $tr.find('.favorite-mark');
|
||||
expect($favoriteMark.length).toEqual(1);
|
||||
expect($favoriteMark.hasClass('permanent')).toEqual(false);
|
||||
|
||||
expect($tr.attr('data-tags').split('|')).toEqual(['tag1', 'tag2']);
|
||||
expect($tr.attr('data-favorite')).not.toBeDefined();
|
||||
});
|
||||
it('renders permanent favorite icon and extra data', function() {
|
||||
var $action, $tr;
|
||||
var $favoriteMark, $tr;
|
||||
testFiles[0].tags.push(OC.TAG_FAVORITE);
|
||||
fileList.setFiles(testFiles);
|
||||
$tr = fileList.$el.find('tbody tr:first');
|
||||
$action = $tr.find('.action-favorite');
|
||||
expect($action.length).toEqual(1);
|
||||
expect($action.hasClass('permanent')).toEqual(true);
|
||||
$favoriteMark = $tr.find('.favorite-mark');
|
||||
expect($favoriteMark.length).toEqual(1);
|
||||
expect($favoriteMark.hasClass('permanent')).toEqual(true);
|
||||
|
||||
expect($tr.attr('data-tags').split('|')).toEqual(['tag1', 'tag2', OC.TAG_FAVORITE]);
|
||||
expect($tr.attr('data-favorite')).toEqual('true');
|
||||
});
|
||||
it('adds has-favorites class on table', function() {
|
||||
expect(fileList.$el.hasClass('has-favorites')).toEqual(true);
|
||||
});
|
||||
});
|
||||
describe('Applying tags', function() {
|
||||
it('sends request to server and updates icon', function() {
|
||||
it('through FileActionsMenu sends request to server and updates icon', function() {
|
||||
var request;
|
||||
fileList.setFiles(testFiles);
|
||||
var $tr = fileList.findFileEl('One.txt');
|
||||
var $action = $tr.find('.action-favorite');
|
||||
$action.click();
|
||||
var $favoriteMark = $tr.find('.favorite-mark');
|
||||
var $showMenuAction = $tr.find('.action-menu');
|
||||
$showMenuAction.click();
|
||||
var $favoriteActionInMenu = $tr.find('.fileActionsMenu .action-favorite');
|
||||
$favoriteActionInMenu.click();
|
||||
|
||||
expect(fakeServer.requests.length).toEqual(1);
|
||||
request = fakeServer.requests[0];
|
||||
|
@ -94,15 +94,21 @@ describe('OCA.Files.TagsPlugin tests', function() {
|
|||
|
||||
// re-read the element as it was re-inserted
|
||||
$tr = fileList.findFileEl('One.txt');
|
||||
$action = $tr.find('.action-favorite');
|
||||
$favoriteMark = $tr.find('.favorite-mark');
|
||||
$showMenuAction = $tr.find('.action-menu');
|
||||
|
||||
expect($tr.attr('data-favorite')).toEqual('true');
|
||||
expect($tr.attr('data-tags').split('|')).toEqual(['tag1', 'tag2', 'tag3', OC.TAG_FAVORITE]);
|
||||
expect(fileList.files[0].tags).toEqual(['tag1', 'tag2', 'tag3', OC.TAG_FAVORITE]);
|
||||
expect($action.find('.icon').hasClass('icon-star')).toEqual(false);
|
||||
expect($action.find('.icon').hasClass('icon-starred')).toEqual(true);
|
||||
expect($favoriteMark.find('.icon').hasClass('icon-star')).toEqual(false);
|
||||
expect($favoriteMark.find('.icon').hasClass('icon-starred')).toEqual(true);
|
||||
|
||||
$action.click();
|
||||
// show again the menu and get the new action, as the menu was
|
||||
// closed and removed (and with it, the previous action) when that
|
||||
// action was clicked
|
||||
$showMenuAction.click();
|
||||
$favoriteActionInMenu = $tr.find('.fileActionsMenu .action-favorite');
|
||||
$favoriteActionInMenu.click();
|
||||
|
||||
expect(fakeServer.requests.length).toEqual(2);
|
||||
request = fakeServer.requests[1];
|
||||
|
@ -115,13 +121,13 @@ describe('OCA.Files.TagsPlugin tests', function() {
|
|||
|
||||
// re-read the element as it was re-inserted
|
||||
$tr = fileList.findFileEl('One.txt');
|
||||
$action = $tr.find('.action-favorite');
|
||||
$favoriteMark = $tr.find('.favorite-mark');
|
||||
|
||||
expect($tr.attr('data-favorite')).toBeFalsy();
|
||||
expect($tr.attr('data-tags').split('|')).toEqual(['tag1', 'tag2', 'tag3']);
|
||||
expect(fileList.files[0].tags).toEqual(['tag1', 'tag2', 'tag3']);
|
||||
expect($action.find('.icon').hasClass('icon-star')).toEqual(true);
|
||||
expect($action.find('.icon').hasClass('icon-starred')).toEqual(false);
|
||||
expect($favoriteMark.find('.icon').hasClass('icon-star')).toEqual(true);
|
||||
expect($favoriteMark.find('.icon').hasClass('icon-starred')).toEqual(false);
|
||||
});
|
||||
});
|
||||
describe('elementToFile', function() {
|
||||
|
|
|
@ -21,12 +21,14 @@
|
|||
<table id="filestable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th id="headerSelection" class="hidden column-selection">
|
||||
<input type="checkbox" id="select_all_trash" class="select-all checkbox"/>
|
||||
<label for="select_all_trash">
|
||||
<span class="hidden-visually"><?php p($l->t('Select all'))?></span>
|
||||
</label>
|
||||
</th>
|
||||
<th id='headerName' class="hidden column-name">
|
||||
<div id="headerName-container">
|
||||
<input type="checkbox" id="select_all_trash" class="select-all checkbox"/>
|
||||
<label for="select_all_trash">
|
||||
<span class="hidden-visually"><?php p($l->t('Select all'))?></span>
|
||||
</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">
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
padding: 28px 0 28px 56px;
|
||||
font-size: 18px;
|
||||
}
|
||||
.has-favorites:not(.hidden) ~ #searchresults .status {
|
||||
padding-left: 102px;
|
||||
.has-selection:not(.hidden) ~ #searchresults .status {
|
||||
padding-left: 105px;
|
||||
}
|
||||
#searchresults .status.fixed {
|
||||
position: fixed;
|
||||
|
@ -54,7 +54,7 @@
|
|||
}
|
||||
|
||||
#searchresults td {
|
||||
padding: 5px 19px;
|
||||
padding: 5px 14px;
|
||||
font-style: normal;
|
||||
vertical-align: middle;
|
||||
border-bottom: none;
|
||||
|
@ -67,8 +67,8 @@
|
|||
background-position: right center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
.has-favorites:not(.hidden) ~ #searchresults td.icon {
|
||||
width: 86px;
|
||||
.has-selection:not(.hidden) ~ #searchresults td.icon {
|
||||
width: 91px;
|
||||
background-size: 32px;
|
||||
}
|
||||
|
||||
|
|
|
@ -145,6 +145,14 @@ Feature: app-files
|
|||
Given I am logged in
|
||||
And I create a new folder named "A name alphabetically lower than welcome.txt"
|
||||
And I see that "A name alphabetically lower than welcome.txt" precedes "welcome.txt" in the file list
|
||||
# To mark the file as favorite the file actions menu has to be shown but, as
|
||||
# the details view is opened automatically when the folder is created,
|
||||
# clicking on the menu trigger could fail if it is covered by the details
|
||||
# view due to its opening animation. Instead of ensuring that the animations
|
||||
# of the contents and the details view have both finished it is easier to
|
||||
# close the details view and wait until it is closed before continuing.
|
||||
And I close the details view
|
||||
And I see that the details view is closed
|
||||
When I mark "welcome.txt" as favorite
|
||||
Then I see that "welcome.txt" is marked as favorite
|
||||
And I see that "welcome.txt" precedes "A name alphabetically lower than welcome.txt" in the file list
|
||||
|
@ -153,6 +161,14 @@ Feature: app-files
|
|||
Given I am logged in
|
||||
And I create a new folder named "A name alphabetically lower than welcome.txt"
|
||||
And I see that "A name alphabetically lower than welcome.txt" precedes "welcome.txt" in the file list
|
||||
# To mark the file as favorite the file actions menu has to be shown but, as
|
||||
# the details view is opened automatically when the folder is created,
|
||||
# clicking on the menu trigger could fail if it is covered by the details
|
||||
# view due to its opening animation. Instead of ensuring that the animations
|
||||
# of the contents and the details view have both finished it is easier to
|
||||
# close the details view and wait until it is closed before continuing.
|
||||
And I close the details view
|
||||
And I see that the details view is closed
|
||||
And I mark "welcome.txt" as favorite
|
||||
And I see that "welcome.txt" is marked as favorite
|
||||
And I see that "welcome.txt" precedes "A name alphabetically lower than welcome.txt" in the file list
|
||||
|
|
|
@ -77,6 +77,15 @@ class FilesAppContext implements Context, ActorAwareInterface {
|
|||
describedAs("Current section details view in Files app");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function closeDetailsViewButton() {
|
||||
return Locator::forThe()->css(".icon-close")->
|
||||
descendantOf(self::currentSectionDetailsView())->
|
||||
describedAs("Close current section details view in Files app");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
|
@ -278,16 +287,16 @@ class FilesAppContext implements Context, ActorAwareInterface {
|
|||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function favoriteActionForFile($fileName) {
|
||||
return Locator::forThe()->css(".action-favorite")->descendantOf(self::rowForFile($fileName))->
|
||||
describedAs("Favorite action for file $fileName in Files app");
|
||||
public static function favoriteMarkForFile($fileName) {
|
||||
return Locator::forThe()->css(".favorite-mark")->descendantOf(self::rowForFile($fileName))->
|
||||
describedAs("Favorite mark for file $fileName in Files app");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function notFavoritedStateIconForFile($fileName) {
|
||||
return Locator::forThe()->css(".icon-star")->descendantOf(self::favoriteActionForFile($fileName))->
|
||||
return Locator::forThe()->css(".icon-star")->descendantOf(self::favoriteMarkForFile($fileName))->
|
||||
describedAs("Not favorited state icon for file $fileName in Files app");
|
||||
}
|
||||
|
||||
|
@ -295,7 +304,7 @@ class FilesAppContext implements Context, ActorAwareInterface {
|
|||
* @return Locator
|
||||
*/
|
||||
public static function favoritedStateIconForFile($fileName) {
|
||||
return Locator::forThe()->css(".icon-starred")->descendantOf(self::favoriteActionForFile($fileName))->
|
||||
return Locator::forThe()->css(".icon-starred")->descendantOf(self::favoriteMarkForFile($fileName))->
|
||||
describedAs("Favorited state icon for file $fileName in Files app");
|
||||
}
|
||||
|
||||
|
@ -338,6 +347,20 @@ class FilesAppContext implements Context, ActorAwareInterface {
|
|||
return self::fileActionsMenuItemFor("Details");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function addToFavoritesMenuItem() {
|
||||
return self::fileActionsMenuItemFor("Add to favorites");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function removeFromFavoritesMenuItem() {
|
||||
return self::fileActionsMenuItemFor("Remove from favorites");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
|
@ -373,6 +396,13 @@ class FilesAppContext implements Context, ActorAwareInterface {
|
|||
$this->actor->find(self::detailsMenuItem(), 2)->click();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given I close the details view
|
||||
*/
|
||||
public function iCloseTheDetailsView() {
|
||||
$this->actor->find(self::closeDetailsViewButton(), 10)->click();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given I open the input field for tags in the details view
|
||||
*/
|
||||
|
@ -393,7 +423,9 @@ class FilesAppContext implements Context, ActorAwareInterface {
|
|||
public function iMarkAsFavorite($fileName) {
|
||||
$this->iSeeThatIsNotMarkedAsFavorite($fileName);
|
||||
|
||||
$this->actor->find(self::favoriteActionForFile($fileName), 10)->click();
|
||||
$this->actor->find(self::fileActionsMenuButtonForFile($fileName), 10)->click();
|
||||
|
||||
$this->actor->find(self::addToFavoritesMenuItem(), 2)->click();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -402,7 +434,9 @@ class FilesAppContext implements Context, ActorAwareInterface {
|
|||
public function iUnmarkAsFavorite($fileName) {
|
||||
$this->iSeeThatIsMarkedAsFavorite($fileName);
|
||||
|
||||
$this->actor->find(self::favoriteActionForFile($fileName), 10)->click();
|
||||
$this->actor->find(self::fileActionsMenuButtonForFile($fileName), 10)->click();
|
||||
|
||||
$this->actor->find(self::removeFromFavoritesMenuItem(), 2)->click();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue