json-joy
Version:
Collection of libraries for building collaborative editing apps.
149 lines (148 loc) • 4.99 kB
JavaScript
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;
;