feat: add support for the Web Share Target API (#1100)
Co-authored-by: userquin <userquin@gmail.com>
This commit is contained in:
parent
a6a825e553
commit
bede92404b
11 changed files with 221 additions and 7 deletions
64
service-worker/share-target.ts
Normal file
64
service-worker/share-target.ts
Normal file
|
@ -0,0 +1,64 @@
|
|||
/// <reference lib="WebWorker" />
|
||||
declare const self: ServiceWorkerGlobalScope
|
||||
|
||||
const clientResolves: { [key: string]: Function } = {}
|
||||
|
||||
self.addEventListener('message', (event) => {
|
||||
if (event.data.action !== 'ready-to-receive')
|
||||
return
|
||||
|
||||
const id: string | undefined = (event.source as any)?.id ?? undefined
|
||||
|
||||
if (id && clientResolves[id] !== undefined)
|
||||
clientResolves[id]()
|
||||
})
|
||||
|
||||
export const onShareTarget = (event: FetchEvent) => {
|
||||
if (!event.request.url.endsWith('/web-share-target') || event.request.method !== 'POST')
|
||||
return
|
||||
|
||||
event.waitUntil(handleSharedTarget(event))
|
||||
}
|
||||
|
||||
async function handleSharedTarget(event: FetchEvent) {
|
||||
event.respondWith(Response.redirect('/home?share-target=true'))
|
||||
await waitForClientToGetReady(event.resultingClientId)
|
||||
|
||||
const [client, formData] = await getClientAndFormData(event)
|
||||
if (client === undefined)
|
||||
return
|
||||
|
||||
await sendShareTargetMessage(client, formData)
|
||||
}
|
||||
|
||||
async function sendShareTargetMessage(client: Client, data: FormData) {
|
||||
const sharedData: { text?: string; files?: File[] } = {}
|
||||
|
||||
const text = data.get('text')
|
||||
if (text !== null)
|
||||
sharedData.text = text.toString()
|
||||
|
||||
const files: File[] = []
|
||||
for (const [name, file] of data.entries()) {
|
||||
if (name === 'files' && file instanceof File)
|
||||
files.push(file)
|
||||
}
|
||||
|
||||
if (files.length !== 0)
|
||||
sharedData.files = files
|
||||
|
||||
client.postMessage({ data: sharedData, action: 'compose-with-shared-data' })
|
||||
}
|
||||
|
||||
function waitForClientToGetReady(clientId: string) {
|
||||
return new Promise<void>((resolve) => {
|
||||
clientResolves[clientId] = resolve
|
||||
})
|
||||
}
|
||||
|
||||
function getClientAndFormData(event: FetchEvent): Promise<[client: Client | undefined, formData: FormData]> {
|
||||
return Promise.all([
|
||||
self.clients.get(event.resultingClientId),
|
||||
event.request.formData(),
|
||||
])
|
||||
}
|
|
@ -7,6 +7,7 @@ import { StaleWhileRevalidate } from 'workbox-strategies'
|
|||
import { ExpirationPlugin } from 'workbox-expiration'
|
||||
|
||||
import { onNotificationClick, onPush } from './web-push-notifications'
|
||||
import { onShareTarget } from './share-target'
|
||||
|
||||
declare const self: ServiceWorkerGlobalScope
|
||||
|
||||
|
@ -32,7 +33,7 @@ if (import.meta.env.DEV)
|
|||
// deny api and server page calls
|
||||
let denylist: undefined | RegExp[]
|
||||
if (import.meta.env.PROD)
|
||||
denylist = [/^\/api\//, /^\/login\//, /^\/oauth\//, /^\/signin\//]
|
||||
denylist = [/^\/api\//, /^\/login\//, /^\/oauth\//, /^\/signin\//, /^\/web-share-target\//]
|
||||
|
||||
// only cache pages and external assets on local build + start or in production
|
||||
if (import.meta.env.PROD) {
|
||||
|
@ -90,3 +91,4 @@ registerRoute(new NavigationRoute(
|
|||
|
||||
self.addEventListener('push', onPush)
|
||||
self.addEventListener('notificationclick', onNotificationClick)
|
||||
self.addEventListener('fetch', onShareTarget)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue