diff options
author | Julius Härtl <jus@bitgrid.net> | 2022-09-01 20:09:33 +0200 |
---|---|---|
committer | Julius Härtl <jus@bitgrid.net> | 2023-03-02 21:01:44 +0100 |
commit | 6130f1a78ea4f7fba3e3690528f2b53a0d9f5b82 (patch) | |
tree | 404bcf6ad7790b7ecda2eed0efb3a9d4618fddbb /apps | |
parent | b6d8fc97afe28bc1b017026447264ba37ed37caa (diff) | |
download | nextcloud-server-6130f1a78ea4f7fba3e3690528f2b53a0d9f5b82.tar.gz nextcloud-server-6130f1a78ea4f7fba3e3690528f2b53a0d9f5b82.zip |
Implement file reference wiget
Signed-off-by: Julius Härtl <jus@bitgrid.net>
Diffstat (limited to 'apps')
-rw-r--r-- | apps/files/composer/composer/autoload_classmap.php | 1 | ||||
-rw-r--r-- | apps/files/composer/composer/autoload_static.php | 1 | ||||
-rw-r--r-- | apps/files/lib/AppInfo/Application.php | 3 | ||||
-rw-r--r-- | apps/files/lib/Listener/RenderReferenceEventListener.php | 39 | ||||
-rw-r--r-- | apps/files/src/reference-files.js | 58 | ||||
-rw-r--r-- | apps/files/src/views/FileReferencePickerElement.vue | 113 | ||||
-rw-r--r-- | apps/files/src/views/ReferenceFileWidget.vue | 182 |
7 files changed, 397 insertions, 0 deletions
diff --git a/apps/files/composer/composer/autoload_classmap.php b/apps/files/composer/composer/autoload_classmap.php index ef3480081e0..29ad9921eae 100644 --- a/apps/files/composer/composer/autoload_classmap.php +++ b/apps/files/composer/composer/autoload_classmap.php @@ -50,6 +50,7 @@ return array( 'OCA\\Files\\Helper' => $baseDir . '/../lib/Helper.php', 'OCA\\Files\\Listener\\LegacyLoadAdditionalScriptsAdapter' => $baseDir . '/../lib/Listener/LegacyLoadAdditionalScriptsAdapter.php', 'OCA\\Files\\Listener\\LoadSidebarListener' => $baseDir . '/../lib/Listener/LoadSidebarListener.php', + 'OCA\\Files\\Listener\\RenderReferenceEventListener' => $baseDir . '/../lib/Listener/RenderReferenceEventListener.php', 'OCA\\Files\\Migration\\Version11301Date20191205150729' => $baseDir . '/../lib/Migration/Version11301Date20191205150729.php', 'OCA\\Files\\Migration\\Version12101Date20221011153334' => $baseDir . '/../lib/Migration/Version12101Date20221011153334.php', 'OCA\\Files\\Notification\\Notifier' => $baseDir . '/../lib/Notification/Notifier.php', diff --git a/apps/files/composer/composer/autoload_static.php b/apps/files/composer/composer/autoload_static.php index 4f7872e39df..5ed4124cbde 100644 --- a/apps/files/composer/composer/autoload_static.php +++ b/apps/files/composer/composer/autoload_static.php @@ -65,6 +65,7 @@ class ComposerStaticInitFiles 'OCA\\Files\\Helper' => __DIR__ . '/..' . '/../lib/Helper.php', 'OCA\\Files\\Listener\\LegacyLoadAdditionalScriptsAdapter' => __DIR__ . '/..' . '/../lib/Listener/LegacyLoadAdditionalScriptsAdapter.php', 'OCA\\Files\\Listener\\LoadSidebarListener' => __DIR__ . '/..' . '/../lib/Listener/LoadSidebarListener.php', + 'OCA\\Files\\Listener\\RenderReferenceEventListener' => __DIR__ . '/..' . '/../lib/Listener/RenderReferenceEventListener.php', 'OCA\\Files\\Migration\\Version11301Date20191205150729' => __DIR__ . '/..' . '/../lib/Migration/Version11301Date20191205150729.php', 'OCA\\Files\\Migration\\Version12101Date20221011153334' => __DIR__ . '/..' . '/../lib/Migration/Version12101Date20221011153334.php', 'OCA\\Files\\Notification\\Notifier' => __DIR__ . '/..' . '/../lib/Notification/Notifier.php', diff --git a/apps/files/lib/AppInfo/Application.php b/apps/files/lib/AppInfo/Application.php index 01fe46bb877..e3152c77abc 100644 --- a/apps/files/lib/AppInfo/Application.php +++ b/apps/files/lib/AppInfo/Application.php @@ -44,6 +44,7 @@ use OCA\Files\Event\LoadAdditionalScriptsEvent; use OCA\Files\Event\LoadSidebar; use OCA\Files\Listener\LegacyLoadAdditionalScriptsAdapter; use OCA\Files\Listener\LoadSidebarListener; +use OCA\Files\Listener\RenderReferenceEventListener; use OCA\Files\Notification\Notifier; use OCA\Files\Search\FilesSearchProvider; use OCA\Files\Service\TagService; @@ -53,6 +54,7 @@ use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; +use OCP\Collaboration\Reference\RenderReferenceEvent; use OCP\Collaboration\Resources\IProviderManager; use OCP\IConfig; use OCP\IL10N; @@ -118,6 +120,7 @@ class Application extends App implements IBootstrap { $context->registerEventListener(LoadAdditionalScriptsEvent::class, LegacyLoadAdditionalScriptsAdapter::class); $context->registerEventListener(LoadSidebar::class, LoadSidebarListener::class); + $context->registerEventListener(RenderReferenceEvent::class, RenderReferenceEventListener::class); $context->registerSearchProvider(FilesSearchProvider::class); diff --git a/apps/files/lib/Listener/RenderReferenceEventListener.php b/apps/files/lib/Listener/RenderReferenceEventListener.php new file mode 100644 index 00000000000..121ff745065 --- /dev/null +++ b/apps/files/lib/Listener/RenderReferenceEventListener.php @@ -0,0 +1,39 @@ +<?php + +declare(strict_types=1); +/** + * @copyright Copyright (c) 2022 Julius Härtl <jus@bitgrid.net> + * + * @author Julius Härtl <jus@bitgrid.net> + * + * @license GNU AGPL version 3 or any later version + * + * 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/>. + */ + +namespace OCA\Files\Listener; + +use OCP\Collaboration\Reference\RenderReferenceEvent; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; + +class RenderReferenceEventListener implements IEventListener { + public function handle(Event $event): void { + if (!$event instanceof RenderReferenceEvent) { + return; + } + + \OCP\Util::addScript('files', 'reference-files'); + } +} diff --git a/apps/files/src/reference-files.js b/apps/files/src/reference-files.js new file mode 100644 index 00000000000..db563200cd0 --- /dev/null +++ b/apps/files/src/reference-files.js @@ -0,0 +1,58 @@ +/** + * @copyright Copyright (c) 2022 Julius Härtl <jus@bitgrid.net> + * + * @author Julius Härtl <jus@bitgrid.net> + * + * @license GNU AGPL version 3 or any later version + * + * 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 Vue from 'vue' +import { translate as t } from '@nextcloud/l10n' + +import { registerWidget, registerCustomPickerElement, NcCustomPickerRenderResult } from '@nextcloud/vue/dist/Components/NcRichText.js' + +import FileWidget from './views/ReferenceFileWidget.vue' +import FileReferencePickerElement from './views/FileReferencePickerElement.vue' + +Vue.mixin({ + methods: { + t, + }, +}) + +registerWidget('file', (el, { richObjectType, richObject, accessible }) => { + const Widget = Vue.extend(FileWidget) + new Widget({ + propsData: { + richObjectType, + richObject, + accessible, + }, + }).$mount(el) +}) + +registerCustomPickerElement('files', (el, { providerId, accessible }) => { + const Element = Vue.extend(FileReferencePickerElement) + const vueElement = new Element({ + propsData: { + providerId, + accessible, + }, + }).$mount(el) + return new NcCustomPickerRenderResult(vueElement.$el, vueElement) +}, (el, renderResult) => { + renderResult.object.$destroy() +}) diff --git a/apps/files/src/views/FileReferencePickerElement.vue b/apps/files/src/views/FileReferencePickerElement.vue new file mode 100644 index 00000000000..543dba3350d --- /dev/null +++ b/apps/files/src/views/FileReferencePickerElement.vue @@ -0,0 +1,113 @@ +<!-- + - @copyright Copyright (c) 2023 Julius Härtl <jus@bitgrid.net> + - + - @author Julius Härtl <jus@bitgrid.net> + - + - @license GNU AGPL version 3 or any later version + - + - 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/>. + --> + +<template> + <div ref="picker" class="reference-file-picker" /> +</template> + +<script> +import { FilePickerType } from '@nextcloud/dialogs' +import { generateUrl } from '@nextcloud/router' +export default { + name: 'FileReferencePickerElement', + components: { + }, + props: { + providerId: { + type: String, + required: true, + }, + accessible: { + type: Boolean, + default: false, + }, + }, + mounted() { + this.openFilePicker() + window.addEventListener('click', this.onWindowClick) + }, + beforeDestroy() { + window.removeEventListener('click', this.onWindowClick) + }, + methods: { + onWindowClick(e) { + if (e.target.tagName === 'A' && e.target.classList.contains('oc-dialog-close')) { + this.$emit('cancel') + } + }, + async openFilePicker() { + OC.dialogs.filepicker( + t('files', 'Select file or folder to link to'), + (file) => { + const client = OC.Files.getClient() + client.getFileInfo(file).then((_status, fileInfo) => { + this.submit(fileInfo.id) + }) + }, + false, // multiselect + [], // mime filter + false, // modal + FilePickerType.Choose, // type + '', + { + target: this.$refs.picker, + }, + ) + }, + submit(fileId) { + const fileLink = window.location.protocol + '//' + window.location.host + + generateUrl('/f/{fileId}', { fileId }) + this.$emit('submit', fileLink) + }, + }, +} +</script> + +<style scoped lang="scss"> +.reference-file-picker { + flex-grow: 1; + margin-top: 44px; + + &:deep(.oc-dialog) { + transform: none !important; + box-shadow: none !important; + flex-grow: 1 !important; + position: static !important; + width: 100% !important; + height: auto !important; + padding: 0 !important; + max-width: initial; + + .oc-dialog-close { + display: none; + } + + .oc-dialog-buttonrow.onebutton.aside { + position: absolute; + padding: 12px 32px; + } + + .oc-dialog-content { + max-width: 100% !important; + } + } +} +</style> diff --git a/apps/files/src/views/ReferenceFileWidget.vue b/apps/files/src/views/ReferenceFileWidget.vue new file mode 100644 index 00000000000..f0ac7007312 --- /dev/null +++ b/apps/files/src/views/ReferenceFileWidget.vue @@ -0,0 +1,182 @@ +<!-- + - @copyright Copyright (c) 2022 Julius Härtl <jus@bitgrid.net> + - + - @author Julius Härtl <jus@bitgrid.net> + - + - @license GNU AGPL version 3 or any later version + - + - 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/>. + --> + +<template> + <div v-if="!accessible" class="widget-file widget-file--no-access"> + <div class="widget-file--image widget-file--image--icon icon-folder" /> + <div class="widget-file--details"> + <p class="widget-file--title"> + {{ t('files', 'File cannot be accessed') }} + </p> + <p class="widget-file--description"> + {{ t('files', 'You might not have have permissions to view it, ask the sender to share it') }} + </p> + </div> + </div> + <a v-else + class="widget-file" + :href="richObject.link" + @click.prevent="navigate"> + <div class="widget-file--image" :class="filePreviewClass" :style="filePreview" /> + <div class="widget-file--details"> + <p class="widget-file--title">{{ richObject.name }}</p> + <p class="widget-file--description">{{ fileSize }}<br>{{ fileMtime }}</p> + <p class="widget-file--link">{{ filePath }}</p> + </div> + </a> +</template> +<script> +import { generateUrl } from '@nextcloud/router' +import path from 'path' + +export default { + name: 'ReferenceFileWidget', + props: { + richObject: { + type: Object, + required: true, + }, + accessible: { + type: Boolean, + default: true, + }, + }, + data() { + return { + previewUrl: window.OC.MimeType.getIconUrl(this.richObject.mimetype), + } + }, + computed: { + fileSize() { + return window.OC.Util.humanFileSize(this.richObject.size) + }, + fileMtime() { + return window.OC.Util.relativeModifiedDate(this.richObject.mtime * 1000) + }, + filePath() { + return path.dirname(this.richObject.path) + }, + filePreview() { + if (this.previewUrl) { + return { + backgroundImage: 'url(' + this.previewUrl + ')', + } + } + + return { + backgroundImage: 'url(' + window.OC.MimeType.getIconUrl(this.richObject.mimetype) + ')', + } + + }, + filePreviewClass() { + if (this.previewUrl) { + return 'widget-file--image--preview' + } + return 'widget-file--image--icon' + + }, + }, + mounted() { + if (this.richObject['preview-available']) { + const previewUrl = generateUrl('/core/preview?fileId={fileId}&x=250&y=250', { + fileId: this.richObject.id, + }) + const img = new Image() + img.onload = () => { + this.previewUrl = previewUrl + } + img.onerror = err => { + console.error('could not load recommendation preview', err) + } + img.src = previewUrl + } + }, + methods: { + navigate() { + if (OCA.Viewer && OCA.Viewer.mimetypes.indexOf(this.richObject.mimetype) !== -1) { + OCA.Viewer.open({ path: this.richObject.path }) + return + } + window.location = generateUrl('/f/' + this.id) + }, + }, +} +</script> +<style lang="scss" scoped> +.widget-file { + display: flex; + flex-grow: 1; + color: var(--color-main-text) !important; + text-decoration: none !important; + + &--image { + min-width: 40%; + background-position: center; + background-size: cover; + background-repeat: no-repeat; + + &.widget-file--image--icon { + min-width: 88px; + background-size: 44px; + } + } + + &--title { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-weight: bold; + } + + &--details { + padding: 12px; + flex-grow: 1; + display: flex; + flex-direction: column; + + p { + margin: 0; + padding: 0; + } + } + + &--description { + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 3; + line-clamp: 3; + -webkit-box-orient: vertical; + } + + &--link { + color: var(--color-text-maxcontrast); + } + + &.widget-file--no-access { + padding: 12px; + + .widget-file--details { + padding: 0; + } + } +} +</style> |