You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

65 lines
2.3 KiB
JavaScript

export function clipboard(node, args) {
if (!window.isSecureContext) {
console.error('Clipboard action failed: app not running in secure context, see: https://developer.mozilla.org/en-US/docs/Web/API/Clipboard');
return;
}
const fireCopyCompleteEvent = () => {
node.dispatchEvent(new CustomEvent('copyComplete'));
};
const onClick = () => {
// Handle `data-clipboard` target based on object key
if (typeof args === 'object') {
// Element Inner HTML
if ('element' in args) {
const element = document.querySelector(`[data-clipboard="${args.element}"]`);
if (!element)
throw new Error(`Missing HTMLElement with an attribute of [data-clipboard="${args.element}"]`);
copyToClipboard(element.innerHTML, 'text/html').then(fireCopyCompleteEvent);
return;
}
// Form Input Value
if ('input' in args) {
const input = document.querySelector(`[data-clipboard="${args.input}"]`);
if (!input)
throw new Error(`Missing HTMLInputElement with an attribute of [data-clipboard="${args.input}"]`);
copyToClipboard(input.value).then(fireCopyCompleteEvent);
return;
}
}
// Handle everything else.
copyToClipboard(args).then(fireCopyCompleteEvent);
};
// Event Listener
node.addEventListener('click', onClick);
// Lifecycle
return {
update(newArgs) {
args = newArgs;
},
destroy() {
node.removeEventListener('click', onClick);
}
};
}
// Shared copy method
async function copyToClipboard(data, mimeType = 'text/plain') {
if (navigator.clipboard.write) {
await navigator.clipboard.write([
new ClipboardItem({
[mimeType]: new Blob([data], {
type: mimeType
}),
['text/plain']: new Blob([data], {
type: 'text/plain'
})
})
]);
}
else {
// fallback since .writeText has wider browser support
await new Promise((resolve) => {
resolve(navigator.clipboard.writeText(String(data)));
});
}
}