diff --git a/changelog/unreleased/bugfix-webkit-copy-quicklinks b/changelog/unreleased/bugfix-webkit-copy-quicklinks new file mode 100644 index 00000000000..c2cb66b1d26 --- /dev/null +++ b/changelog/unreleased/bugfix-webkit-copy-quicklinks @@ -0,0 +1,6 @@ +Bugfix: Copy quicklinks for webkit navigator + +Copying quicklinks didn't work on safari or other webkit based browsers and is fixed now. + +https://github.com/owncloud/web/pull/9832 +https://github.com/owncloud/web/issues/9166 diff --git a/packages/web-pkg/src/composables/actions/files/useFileActionsCreateQuicklink.ts b/packages/web-pkg/src/composables/actions/files/useFileActionsCreateQuicklink.ts index f1c69f879ff..794f9dc89b0 100644 --- a/packages/web-pkg/src/composables/actions/files/useFileActionsCreateQuicklink.ts +++ b/packages/web-pkg/src/composables/actions/files/useFileActionsCreateQuicklink.ts @@ -1,5 +1,5 @@ import quickActions, { canShare } from '../../../quickActions' -import { createQuicklink } from '../../../helpers/share' +import { copyQuicklink } from '../../../helpers/share' import { ShareStatus } from '@ownclouders/web-client/src/helpers/share' import { isLocationSharesActive } from '../../../router' @@ -22,7 +22,7 @@ export const useFileActionsCreateQuickLink = ({ store }: { store?: Store } const handler = async ({ space, resources }: FileActionOptions) => { const [resource] = resources - await createQuicklink({ + await copyQuicklink({ clientService, resource, storageId: space?.id || resource?.fileId || resource?.id, diff --git a/packages/web-pkg/src/helpers/share/link.ts b/packages/web-pkg/src/helpers/share/link.ts index 2b2df16e40e..b4cdc0cfae5 100644 --- a/packages/web-pkg/src/helpers/share/link.ts +++ b/packages/web-pkg/src/helpers/share/link.ts @@ -22,6 +22,49 @@ export interface CreateQuicklink { ability: Ability } +export const copyQuicklink = async (args: CreateQuicklink) => { + const { store, language } = args + const { $gettext } = language + + // doCopy creates the requested link and copies the url to the clipboard, + // the copy action uses the clipboard // clipboardItem api to work around the webkit limitations. + // + // https://developer.apple.com/forums/thread/691873 + // + // if those apis not available (or like in firefox behind dom.events.asyncClipboard.clipboardItem) + // it has a fallback to the vue-use implementation. + // + // https://webkit.org/blog/10855/ + const doCopy = async () => { + if (typeof ClipboardItem && navigator?.clipboard?.write) { + await navigator.clipboard.write([ + new ClipboardItem({ + 'text/plain': createQuicklink(args).then( + (link) => new Blob([link.url], { type: 'text/plain' }) + ) + }) + ]) + } else { + const link = await createQuicklink(args) + const { copy } = useClipboard({ legacy: true }) + await copy(link.url) + } + } + + try { + await doCopy() + await store.dispatch('showMessage', { + title: $gettext('The link has been copied to your clipboard.') + }) + } catch (e) { + console.error(e) + await store.dispatch('showErrorMessage', { + title: $gettext('Copy link failed'), + error: e + }) + } +} + export const createQuicklink = async (args: CreateQuicklink): Promise => { const { clientService, resource, store, password, language, ability } = args const { $gettext } = language @@ -68,26 +111,10 @@ export const createQuicklink = async (args: CreateQuicklink): Promise => params.spaceRef = resource.fileId || resource.id - try { - const link = await store.dispatch('Files/addLink', { - path: resource.path, - client: clientService.owncloudSdk, - params, - storageId: resource.fileId || resource.id - }) - const { copy } = useClipboard({ legacy: true }) - copy(link.url) - - await store.dispatch('showMessage', { - title: $gettext('The link has been copied to your clipboard.') - }) - - return link - } catch (e) { - console.error(e) - await store.dispatch('showErrorMessage', { - title: $gettext('Copy link failed'), - error: e - }) - } + return store.dispatch('Files/addLink', { + path: resource.path, + client: clientService.owncloudSdk, + params, + storageId: resource.fileId || resource.id + }) } diff --git a/packages/web-pkg/src/quickActions.ts b/packages/web-pkg/src/quickActions.ts index 0f380f08f79..57955a5fad2 100644 --- a/packages/web-pkg/src/quickActions.ts +++ b/packages/web-pkg/src/quickActions.ts @@ -1,4 +1,4 @@ -import { createQuicklink } from './helpers/share' +import { copyQuicklink } from './helpers/share' import { eventBus } from './services/eventBus' import { SideBarEventTopics } from './composables/sideBar/eventTopics' import { Resource } from '@ownclouders/web-client' @@ -82,7 +82,7 @@ export default { return showQuickLinkPasswordModal( { store, $gettext: language.$gettext, passwordPolicyService }, async (password) => { - await createQuicklink({ + await copyQuicklink({ ability, clientService, language, @@ -94,7 +94,7 @@ export default { ) } - await createQuicklink({ + await copyQuicklink({ ability, clientService, language, diff --git a/packages/web-pkg/tests/unit/helpers/share/link.spec.ts b/packages/web-pkg/tests/unit/helpers/share/link.spec.ts index e4fde637098..38cfc5f97d2 100644 --- a/packages/web-pkg/tests/unit/helpers/share/link.spec.ts +++ b/packages/web-pkg/tests/unit/helpers/share/link.spec.ts @@ -1,4 +1,4 @@ -import { createQuicklink, CreateQuicklink } from '../../../../src/helpers/share' +import { copyQuicklink, createQuicklink, CreateQuicklink } from '../../../../src/helpers/share' import { DateTime } from 'luxon' import { Store } from 'vuex' import { ClientService } from '../../../../src/services' @@ -65,6 +65,7 @@ describe('createQuicklink', () => { expect(link).toBeDefined() expect(link.url).toBeDefined() + await copyQuicklink(args) expect(useClipboard).toHaveBeenCalled() expect(mockStore.dispatch).toHaveBeenCalledWith('Files/addLink', { @@ -106,6 +107,7 @@ describe('createQuicklink', () => { expect(link).toBeDefined() expect(link.url).toBeDefined() + await copyQuicklink(args) expect(useClipboard).toHaveBeenCalled() expect(mockStore.dispatch).toHaveBeenCalledWith('Files/addLink', { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 38927a429f8..64ebb337c7f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,9 +1,5 @@ lockfileVersion: '6.0' -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - overrides: '@uppy/companion-client': https://github.com/owncloud/uppy/releases/download/v3.12.13-owncloud/uppy-companion-client.tgz '@uppy/core': https://github.com/owncloud/uppy/releases/download/v3.12.13-owncloud/uppy-core.tgz @@ -22750,3 +22746,7 @@ packages: lodash: 4.17.21 vue: 3.3.4 dev: true + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false