Signed-off-by: Lucas Azevedo <lhs_azevedo@hotmail.com>tags/v28.0.0beta1
@@ -406,40 +406,6 @@ table { | |||
z-index: 10; | |||
padding: 0 20px 0 0; | |||
} | |||
/* System tags */ | |||
.system-tags { | |||
--min-size: 32px; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
min-width: calc(var(--min-size) * 2); | |||
max-width: 300px; | |||
.system-tags__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 | |||
& + .system-tags__tag { | |||
margin-left: 5px; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
@@ -24,6 +24,5 @@ | |||
"sidebarpreviewmanager.js", | |||
"sidebarpreviewtext.js", | |||
"tagsplugin.js", | |||
"systemtagsplugin.js", | |||
"templates.js" | |||
] |
@@ -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; | |||
} | |||
} |
@@ -5,6 +5,7 @@ import './actions/deleteAction' | |||
import './actions/downloadAction' | |||
import './actions/editLocallyAction' | |||
import './actions/favoriteAction' | |||
import './actions/inlineSystemTagsAction' | |||
import './actions/openFolderAction' | |||
import './actions/openInFilesAction.js' | |||
import './actions/renameAction' |