From c28e411249faaa99212b6d022fa0119a56a23d5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Tue, 11 Jul 2023 12:27:36 +0200 Subject: [PATCH 1/3] fix: Expose slides and previews where suitable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Service/FileTargetService.php | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/lib/Service/FileTargetService.php b/lib/Service/FileTargetService.php index 0fbda328e9..14a9b4fb3b 100644 --- a/lib/Service/FileTargetService.php +++ b/lib/Service/FileTargetService.php @@ -6,6 +6,7 @@ use OCP\Files\IRootFolder; use OCP\ICacheFactory; use OCP\IL10N; +use OCP\IURLGenerator; use Psr\Log\LoggerInterface; class FileTargetService { @@ -16,6 +17,7 @@ public function __construct( private IRootFolder $rootFolder, private LoggerInterface $logger, private IL10N $l10n, + private IURLGenerator $urlGenerator, private ?string $userId, ) { } @@ -64,6 +66,13 @@ public function getFileTargets(File $file): array { ]; } + if (isset($targets['Slide'])) { + $categories['slides'] = [ + 'label' => $this->l10n->t('Slides'), + 'entries' => $this->mapTargets($filePath, $targets['Slide'], true) + ]; + } + $cache->set($cacheKey, $categories); return $categories; @@ -73,19 +82,23 @@ public function getTargetPreview($file, $target) { return $this->remoteService->fetchTargetThumbnail($file, $target); } - private function mapTargets(string $filePath, array $targets): array { + private function mapTargets(string $filePath, array $targets, bool $showPreview = false): array { $result = []; foreach ($targets as $name => $identifier) { - $result[] = [ + $targetData = [ 'id' => $identifier, 'name' => $name, - // Disable previews for now as they may cause endless requests against Collabora - // 'preview' => $this->urlGenerator->linkToOCSRouteAbsolute('richdocuments.Target.getPreview', [ - // 'path' => $filePath, - // 'target' => $identifier, - // ]), ]; + if ($showPreview) { + $targetData['preview'] = $this->urlGenerator->linkToOCSRouteAbsolute('richdocuments.Target.getPreview', [ + 'path' => $filePath, + 'target' => $identifier, + ]); + } + + $result[] = $targetData; + } return $result; } From b60f6309cc96d87b6d6cdd74d6cece7b2edfd1ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Tue, 11 Jul 2023 12:28:11 +0200 Subject: [PATCH 2/3] fix: Move link picker and metadata extraction to viewer to act in the user session aware iframe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- src/document.js | 63 ++----------------------------- src/view/DocumentTargetPicker.vue | 5 +++ src/view/Office.vue | 60 +++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 60 deletions(-) diff --git a/src/document.js b/src/document.js index c95a829220..e3f261e631 100644 --- a/src/document.js +++ b/src/document.js @@ -2,8 +2,6 @@ import { emit } from '@nextcloud/event-bus' import { generateOcsUrl, getRootUrl, imagePath } from '@nextcloud/router' import { getRequestToken } from '@nextcloud/auth' import { loadState } from '@nextcloud/initial-state' -import { showError } from '@nextcloud/dialogs' -import { getLinkWithPicker } from '@nextcloud/vue/dist/Components/NcRichText.js' import Config from './services/config.tsx' import { setGuestName, shouldAskForGuestName } from './helpers/guestName.js' import { getUIDefaults, generateCSSVarTokens, getCollaboraTheme } from './helpers/coolParameters.js' @@ -368,6 +366,9 @@ const documentsMain = { 'Action_FollowUser', 'Host_VersionRestore', 'Action_RemoveView', + 'Action_InsertLink', + 'Action_Paste', + 'Action_GetLinkPreview_Resp', ] PostMessages.registerPostMessageHandler(({ parsed, data }) => { console.debug('[document] Received post message ', parsed) @@ -497,12 +498,6 @@ const documentsMain = { case 'UI_Mention': documentsMain.sendUserList(parsed.args.text) break - case 'UI_PickLink': - documentsMain.openLinkPicker() - break - case 'Action_GetLinkPreview': - documentsMain.resolveLink(args.url) - break default: console.debug('[document] Unhandled post message', parsed) } @@ -659,58 +654,6 @@ const documentsMain = { PostMessages.sendWOPIPostMessage('loolframe', 'Action_Mention', { list }) }, - async openLinkPicker() { - try { - const link = await getLinkWithPicker(null, true) - try { - const url = new URL(link) - if (url.protocol === 'http:' || url.protocol === 'https:') { - PostMessages.sendWOPIPostMessage('loolframe', 'Action_InsertLink', { url: link }) - return - } - } catch (e) { - console.debug('error when parsing the link picker result') - } - PostMessages.sendWOPIPostMessage('loolframe', 'Action_Paste', { Mimetype: 'text/plain', Data: link }) - } catch (e) { - showError(t('richdocuments', 'Failed to get a link with the picker')) - console.error('Link picker promise rejected :', e) - } - }, - - async resolveLink(url) { - try { - const result = await axios.get(generateOcsUrl('references/resolve', 2), { - params: { - reference: url, - }, - }) - const resolvedLink = result.data.ocs.data.references[url] - const title = resolvedLink?.openGraphObject?.name - const thumbnailUrl = resolvedLink?.openGraphObject?.thumb - if (thumbnailUrl) { - try { - const imageResponse = await axios.get(thumbnailUrl, { responseType: 'blob' }) - if (imageResponse?.status === 200 && imageResponse?.data) { - const reader = new FileReader() - reader.addEventListener('loadend', (e) => { - const b64Image = e.target.result - PostMessages.sendWOPIPostMessage('loolframe', 'Action_GetLinkPreview_Resp', { url, title, image: b64Image }) - }) - reader.readAsDataURL(imageResponse.data) - } - } catch (e) { - console.error('Error loading the reference image', e) - } - } else { - PostMessages.sendWOPIPostMessage('loolframe', 'Action_GetLinkPreview_Resp', { url, title, image: null }) - } - } catch (e) { - showError(t('richdocuments', 'Failed to get the link preview')) - console.error('Error resolving a reference', e) - } - }, - onStartup() { // Does anything indicate that we need to autostart a session? const fileId = (getSearchParam('fileId') || '').replace(/^\W*/, '') diff --git a/src/view/DocumentTargetPicker.vue b/src/view/DocumentTargetPicker.vue index 83b2fd8a7b..d16c0ca69e 100644 --- a/src/view/DocumentTargetPicker.vue +++ b/src/view/DocumentTargetPicker.vue @@ -201,4 +201,9 @@ h3 { box-shadow: none !important; flex-shrink: 0; } + +img { + max-width: 100px; + margin-left: 20px; +} diff --git a/src/view/Office.vue b/src/view/Office.vue index 638573ffff..06ad0c4932 100644 --- a/src/view/Office.vue +++ b/src/view/Office.vue @@ -85,6 +85,10 @@ import PostMessageService from '../services/postMessage.tsx' import FilesAppIntegration from './FilesAppIntegration.js' import { LOADING_ERROR, checkCollaboraConfiguration, checkProxyStatus } from '../services/collabora.js' import { enableScrollLock, disableScrollLock } from '../helpers/safariFixer.js' +import { getLinkWithPicker } from '@nextcloud/vue/dist/Components/NcRichText.js' +import { showError } from '@nextcloud/dialogs' +import axios from '@nextcloud/axios' +import { generateOcsUrl } from '@nextcloud/router' const FRAME_DOCUMENT = 'FRAME_DOCUMENT' const PostMessages = new PostMessageService({ @@ -221,6 +225,56 @@ export default { async share() { FilesAppIntegration.share() }, + async pickLink() { + try { + const link = await getLinkWithPicker(null, true) + try { + const url = new URL(link) + if (url.protocol === 'http:' || url.protocol === 'https:') { + PostMessages.sendWOPIPostMessage(FRAME_DOCUMENT, 'Action_InsertLink', { url: link }) + return + } + } catch (e) { + console.debug('error when parsing the link picker result') + } + PostMessages.sendWOPIPostMessage(FRAME_DOCUMENT, 'Action_Paste', { Mimetype: 'text/plain', Data: link }) + } catch (e) { + showError(t('richdocuments', 'Failed to get a link with the picker')) + console.error('Link picker promise rejected :', e) + } + }, + async resolveLink(url) { + try { + const result = await axios.get(generateOcsUrl('references/resolve', 2), { + params: { + reference: url, + }, + }) + const resolvedLink = result.data.ocs.data.references[url] + const title = resolvedLink?.openGraphObject?.name + const thumbnailUrl = resolvedLink?.openGraphObject?.thumb + if (thumbnailUrl) { + try { + const imageResponse = await axios.get(thumbnailUrl, { responseType: 'blob' }) + if (imageResponse?.status === 200 && imageResponse?.data) { + const reader = new FileReader() + reader.addEventListener('loadend', (e) => { + const b64Image = e.target.result + PostMessages.sendWOPIPostMessage(FRAME_DOCUMENT, 'Action_GetLinkPreview_Resp', { url, title, image: b64Image }) + }) + reader.readAsDataURL(imageResponse.data) + } + } catch (e) { + console.error('Error loading the reference image', e) + } + } else { + PostMessages.sendWOPIPostMessage(FRAME_DOCUMENT, 'Action_GetLinkPreview_Resp', { url, title, image: null }) + } + } catch (e) { + showError(t('richdocuments', 'Failed to get the link preview')) + console.error('Error resolving a reference', e) + } + }, close() { FilesAppIntegration.close() disableScrollLock() @@ -306,6 +360,12 @@ export default { case 'UI_ZoteroKeyMissing': this.showZotero = true break + case 'UI_PickLink': + this.pickLink() + break + case 'Action_GetLinkPreview': + this.resolveLink(args.url) + break } }, }, From 057aebbe33b147968178619193b53af3058e224f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Wed, 12 Jul 2023 16:23:11 +0200 Subject: [PATCH 3/3] fix: Avoid opening the link picker twice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- src/view/Office.vue | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/view/Office.vue b/src/view/Office.vue index 06ad0c4932..3659d84abc 100644 --- a/src/view/Office.vue +++ b/src/view/Office.vue @@ -86,7 +86,6 @@ import FilesAppIntegration from './FilesAppIntegration.js' import { LOADING_ERROR, checkCollaboraConfiguration, checkProxyStatus } from '../services/collabora.js' import { enableScrollLock, disableScrollLock } from '../helpers/safariFixer.js' import { getLinkWithPicker } from '@nextcloud/vue/dist/Components/NcRichText.js' -import { showError } from '@nextcloud/dialogs' import axios from '@nextcloud/axios' import { generateOcsUrl } from '@nextcloud/router' @@ -136,7 +135,9 @@ export default { loadingTimeout: null, error: null, views: [], + showZotero: false, + showLinkPicker: false, } }, computed: { @@ -227,6 +228,10 @@ export default { }, async pickLink() { try { + if (this.showLinkPicker) { + return + } + this.showLinkPicker = true const link = await getLinkWithPicker(null, true) try { const url = new URL(link) @@ -239,8 +244,9 @@ export default { } PostMessages.sendWOPIPostMessage(FRAME_DOCUMENT, 'Action_Paste', { Mimetype: 'text/plain', Data: link }) } catch (e) { - showError(t('richdocuments', 'Failed to get a link with the picker')) console.error('Link picker promise rejected :', e) + } finally { + this.showLinkPicker = false } }, async resolveLink(url) { @@ -271,7 +277,6 @@ export default { PostMessages.sendWOPIPostMessage(FRAME_DOCUMENT, 'Action_GetLinkPreview_Resp', { url, title, image: null }) } } catch (e) { - showError(t('richdocuments', 'Failed to get the link preview')) console.error('Error resolving a reference', e) } },