UNPKG

json-joy

Version:

Collection of libraries for building collaborative editing apps.

149 lines (148 loc) 4.99 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DomClipboard = void 0; const dom_1 = require("../../../../util/dom"); const toText = (buf) => new TextDecoder().decode(buf); const writeSync = (data) => { try { if (typeof document !== 'object') return false; const selection = window.getSelection(); if (!selection) return false; const queryCommandSupported = document.queryCommandSupported; const copySupported = queryCommandSupported?.('copy') ?? true; const cutSupported = queryCommandSupported?.('cut') ?? true; if (!copySupported && !cutSupported) return false; const restoreSelection = (0, dom_1.saveSelection)(); const value = data['text/plain'] ?? ''; const text = typeof value === 'string' ? value : ''; const span = document.createElement('span'); const style = span.style; style.whiteSpace = 'pre'; style.userSelect = 'all'; style.position = 'fixed'; style.top = '-9999px'; style.left = '-9999px'; const listener = (event) => { event.preventDefault(); const clipboardData = event.clipboardData; if (!clipboardData) return; for (const type in data) { const value = data[type]; switch (type) { case 'text/plain': case 'text/html': case 'image/png': { clipboardData.setData(type, value); break; } default: { clipboardData.setData('web ' + type, value); } } } }; span.addEventListener('copy', listener); span.addEventListener('cut', listener); try { document.body.appendChild(span); const select = () => { span.textContent = text; selection.removeAllRanges(); const range = document.createRange(); range.selectNode(span); selection.addRange(range); }; select(); document.execCommand('cut'); select(); return document.execCommand('copy'); } catch { return false; } finally { try { // span.removeEventListener('copy', listener); // span.removeEventListener('cut', listener); document.body.removeChild(span); restoreSelection?.(); } catch { } } } catch { return false; } }; class DomClipboard { constructor(clipboard) { this.clipboard = clipboard; } writeText(text) { const success = writeSync({ 'text/plain': text }); if (success) return; return this.clipboard.writeText(text); } write(text, binary) { const success = writeSync(text); const binaryKeysLength = binary ? Object.keys(binary).length : 0; if (success && binaryKeysLength === 0) return; const clipboardData = {}; const data = { ...binary, ...(!success ? text : {}), }; for (const type in data) { switch (type) { case 'text/plain': case 'text/html': case 'image/png': { clipboardData[type] = new Blob([data[type]], { type }); break; } default: { clipboardData['web ' + type] = new Blob([data[type]], { type }); } } } const item = new ClipboardItem(clipboardData); const items = [item]; return this.clipboard.write(items); } async read(types) { const clipboard = this.clipboard; const items = await clipboard.read(); const data = {}; const promises = []; const item = items[0]; for (const type of types) { if (item.types.includes(type)) promises.push(item .getType(type) .then((blob) => blob.arrayBuffer()) .then((value) => [type, new Uint8Array(value)])); } const results = await Promise.all(promises); for (const [type, value] of results) data[type] = value; return data; } async readData() { const data = {}; const { 'text/plain': text, 'text/html': html } = await this.read(['text/plain', 'text/html']); if (!text && !html) return data; if (text) data.text = toText(text); if (html) data.html = toText(html); return data; } } exports.DomClipboard = DomClipboard;