Render inline system tags using new DAV properties API
Signed-off-by: Lucas Azevedo <lhs_azevedo@hotmail.com>pull/40284/head
parent
c6e6ebb999
commit
146e9eeb9f
@ -1,128 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com>
|
|
||||||
*
|
|
||||||
* This file is licensed under the Affero General Public License version 3
|
|
||||||
* or later.
|
|
||||||
*
|
|
||||||
* See the COPYING-README file.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* global Handlebars */
|
|
||||||
|
|
||||||
(function (OCA) {
|
|
||||||
|
|
||||||
_.extend(OC.Files.Client, {
|
|
||||||
PROPERTY_SYSTEM_TAGS: '{' + OC.Files.Client.NS_NEXTCLOUD + '}system-tags',
|
|
||||||
});
|
|
||||||
|
|
||||||
OCA.Files = OCA.Files || {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extends the file actions and file list to add system tags inline
|
|
||||||
*
|
|
||||||
* @namespace OCA.Files.SystemTagsPlugin
|
|
||||||
*/
|
|
||||||
OCA.Files.SystemTagsPlugin = {
|
|
||||||
name: 'SystemTags',
|
|
||||||
|
|
||||||
allowedLists: [
|
|
||||||
'files',
|
|
||||||
'favorites',
|
|
||||||
'shares.self',
|
|
||||||
'shares.others',
|
|
||||||
'shares.link'
|
|
||||||
],
|
|
||||||
|
|
||||||
_buildTagSpan: function(tag, isMore = false) {
|
|
||||||
var $tag = $('<li class="system-tags__tag"></li>');
|
|
||||||
$tag.text(tag).addClass(isMore ? 'system-tags__tag--more' : '');
|
|
||||||
return $tag;
|
|
||||||
},
|
|
||||||
|
|
||||||
_buildTagsUI: function(tags) {
|
|
||||||
$systemTags = $('<ul class="system-tags"></ul>');
|
|
||||||
if (tags.length === 1) {
|
|
||||||
$systemTags.attr('aria-label', t('files', 'This file has the tag {tag}', { tag: tags[0] }));
|
|
||||||
} else if (tags.length > 1) {
|
|
||||||
var firstTags = tags.slice(0, -1).join(', ');
|
|
||||||
var lastTag = tags[tags.length - 1];
|
|
||||||
$systemTags.attr('aria-label', t('files', 'This file has the tags {firstTags} and {lastTag}', { firstTags, lastTag }));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tags.length > 0) {
|
|
||||||
$systemTags.append(this._buildTagSpan(tags[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
// More tags than the one we're showing
|
|
||||||
if (tags.length > 1) {
|
|
||||||
$moreTag = this._buildTagSpan('+' + (tags.length - 1), true)
|
|
||||||
$moreTag.attr('title', tags.slice(1).join(', '));
|
|
||||||
$systemTags.append($moreTag);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $systemTags;
|
|
||||||
},
|
|
||||||
|
|
||||||
_extendFileList: function(fileList) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
// extend row prototype
|
|
||||||
var oldCreateRow = fileList._createRow;
|
|
||||||
fileList._createRow = function(fileData) {
|
|
||||||
var $tr = oldCreateRow.apply(this, arguments);
|
|
||||||
var systemTags = fileData.systemTags || [];
|
|
||||||
|
|
||||||
// Update tr data list
|
|
||||||
$tr.attr('data-systemTags', systemTags.join('|'));
|
|
||||||
|
|
||||||
// No tags, no need to do anything
|
|
||||||
if (systemTags.length === 0) {
|
|
||||||
return $tr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build tags ui and inject
|
|
||||||
$systemTags = self._buildTagsUI.apply(self, [systemTags])
|
|
||||||
$systemTags.insertAfter($tr.find('td.filename .nametext'));
|
|
||||||
return $tr;
|
|
||||||
};
|
|
||||||
|
|
||||||
var oldElementToFile = fileList.elementToFile;
|
|
||||||
fileList.elementToFile = function ($el) {
|
|
||||||
var fileInfo = oldElementToFile.apply(this, arguments);
|
|
||||||
var systemTags = $el.attr('data-systemTags');
|
|
||||||
fileInfo.systemTags = systemTags?.split?.('|') || [];
|
|
||||||
return fileInfo;
|
|
||||||
};
|
|
||||||
|
|
||||||
var oldGetWebdavProperties = fileList._getWebdavProperties;
|
|
||||||
fileList._getWebdavProperties = function () {
|
|
||||||
var props = oldGetWebdavProperties.apply(this, arguments);
|
|
||||||
props.push(OC.Files.Client.PROPERTY_SYSTEM_TAGS);
|
|
||||||
return props;
|
|
||||||
};
|
|
||||||
|
|
||||||
fileList.filesClient.addFileInfoParser(function (response) {
|
|
||||||
var data = {};
|
|
||||||
var props = response.propStat[0].properties;
|
|
||||||
var systemTags = props[OC.Files.Client.PROPERTY_SYSTEM_TAGS] || [];
|
|
||||||
if (systemTags && systemTags.length) {
|
|
||||||
data.systemTags = systemTags
|
|
||||||
.filter(xmlvalue => xmlvalue.namespaceURI === OC.Files.Client.NS_NEXTCLOUD && xmlvalue.nodeName.split(':')[1] === 'system-tag')
|
|
||||||
.map(xmlvalue => xmlvalue.textContent || xmlvalue.text);
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
attach: function(fileList) {
|
|
||||||
if (this.allowedLists.indexOf(fileList.id) < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._extendFileList(fileList);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
})
|
|
||||||
(OCA);
|
|
||||||
|
|
||||||
OC.Plugins.register('OCA.Files.FileList', OCA.Files.SystemTagsPlugin);
|
|
||||||
@ -0,0 +1,88 @@
|
|||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2023 Lucas Azevedo <lhs_azevedo@hotmail.com>
|
||||||
|
*
|
||||||
|
* @author Lucas Azevedo <lhs_azevedo@hotmail.com>
|
||||||
|
*
|
||||||
|
* @license AGPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import { FileAction, Node, registerDavProperty, registerFileAction } from "@nextcloud/files";
|
||||||
|
import { translate as t } from '@nextcloud/l10n'
|
||||||
|
|
||||||
|
import '../css/fileEntryInlineSystemTags.scss'
|
||||||
|
|
||||||
|
const getNodeSystemTags = function (node: Node): string[] {
|
||||||
|
const tags = node.attributes?.['system-tags']?.['system-tag'] as string|string[]|undefined
|
||||||
|
|
||||||
|
if (tags === undefined) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
return [tags].flat()
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderTag = function (tag: string, isMore: boolean = false): HTMLElement {
|
||||||
|
const tagElement = document.createElement('li')
|
||||||
|
tagElement.classList.add('files-list__system-tag')
|
||||||
|
tagElement.innerText = tag
|
||||||
|
|
||||||
|
if (isMore) {
|
||||||
|
tagElement.classList.add('files-list__system-tag--more')
|
||||||
|
}
|
||||||
|
|
||||||
|
return tagElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const action = new FileAction({
|
||||||
|
id: 'system-tags',
|
||||||
|
displayName: () => '',
|
||||||
|
iconSvgInline: () => '',
|
||||||
|
exec: async () => null,
|
||||||
|
|
||||||
|
async renderInline(node: Node) {
|
||||||
|
// Ensure we have the system tags as an array
|
||||||
|
const tags = getNodeSystemTags(node)
|
||||||
|
|
||||||
|
if (tags.length === 0) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const systemTagsElement = document.createElement('ul')
|
||||||
|
systemTagsElement.classList.add('files-list__system-tags')
|
||||||
|
|
||||||
|
if (tags.length === 1) {
|
||||||
|
systemTagsElement.setAttribute('aria-label', t('files', 'This file has the tag {tag}', { tag: tags[0] }));
|
||||||
|
} else {
|
||||||
|
var firstTags = tags.slice(0, -1).join(', ');
|
||||||
|
var lastTag = tags[tags.length - 1];
|
||||||
|
systemTagsElement.setAttribute('aria-label', t('files', 'This file has the tags {firstTags} and {lastTag}', { firstTags, lastTag }));
|
||||||
|
}
|
||||||
|
|
||||||
|
systemTagsElement.append(renderTag(tags[0]))
|
||||||
|
|
||||||
|
// More tags than the one we're showing
|
||||||
|
if (tags.length > 1) {
|
||||||
|
const moreTagElement = renderTag('+' + (tags.length - 1), true)
|
||||||
|
moreTagElement.setAttribute('title', tags.slice(1).join(', '));
|
||||||
|
systemTagsElement.append(moreTagElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
return systemTagsElement
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
registerDavProperty('nc:system-tags')
|
||||||
|
registerFileAction(action)
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
.files-list__system-tags {
|
||||||
|
--min-size: 32px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-width: calc(var(--min-size) * 2);
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.files-list__system-tag {
|
||||||
|
padding: 5px 10px;
|
||||||
|
border: 1px solid;
|
||||||
|
border-radius: var(--border-radius-pill);
|
||||||
|
border-color: var(--color-border);
|
||||||
|
color: var(--color-text-maxcontrast);
|
||||||
|
height: var(--min-size);
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
line-height: 22px; // min-size - 2 * 5px padding
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&--more {
|
||||||
|
overflow: visible;
|
||||||
|
text-overflow: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proper spacing if multiple shown
|
||||||
|
& + .files-list__system-tag {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue