UNPKG

@jupyterlab/apputils

Version:
254 lines 8.42 kB
// Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. import { MimeData } from '@lumino/coreutils'; /** * The clipboard interface. */ export var Clipboard; (function (Clipboard) { /** * Get the application clipboard instance. * * @deprecated To use `SystemClipboard.getInstance` for copy/cut/paste cells. */ function getInstance() { return Private.instance; } Clipboard.getInstance = getInstance; /** * Set the application clipboard instance. * * @deprecated will be removed in a future release. Use `SystemClipboard.getInstance`. */ function setInstance(value) { Private.instance = value; } Clipboard.setInstance = setInstance; /** * Copy text to the system clipboard. * * #### Notes * This can only be called in response to a user input event. */ function copyToSystem(clipboardData) { const node = document.body; const handler = (event) => { const data = event.clipboardData || window.clipboardData; if (typeof clipboardData === 'string') { data.setData('text', clipboardData); } else { clipboardData.types().map((mimeType) => { data.setData(mimeType, clipboardData.getData(mimeType)); }); } event.preventDefault(); node.removeEventListener('copy', handler); }; node.addEventListener('copy', handler); generateEvent(node); } Clipboard.copyToSystem = copyToSystem; /** * Generate a clipboard event on a node. * * @param node - The element on which to generate the event. * * @param type - The type of event to generate. * `'paste'` events cannot be programmatically generated. * * #### Notes * This can only be called in response to a user input event. */ function generateEvent(node, type = 'copy') { // http://stackoverflow.com/a/5210367 // Identify selected text. let sel = window.getSelection(); // Save the current selection. const savedRanges = []; for (let i = 0, len = (sel === null || sel === void 0 ? void 0 : sel.rangeCount) || 0; i < len; ++i) { savedRanges[i] = sel.getRangeAt(i).cloneRange(); } // Select the node content. const range = document.createRange(); range.selectNodeContents(node); if (sel) { sel.removeAllRanges(); sel.addRange(range); } // Execute the command. document.execCommand(type); // Restore the previous selection. sel = window.getSelection(); if (sel) { sel.removeAllRanges(); for (let i = 0, len = savedRanges.length; i < len; ++i) { sel.addRange(savedRanges[i]); } } } Clipboard.generateEvent = generateEvent; })(Clipboard || (Clipboard = {})); /** * The clipboard interface supporting the native clipboard API. */ export var SystemClipboard; (function (SystemClipboard) { /** * Get the system clipboard instance. */ function getInstance() { return Private.systemInstance; } SystemClipboard.getInstance = getInstance; })(SystemClipboard || (SystemClipboard = {})); /** * The namespace for module private data. */ var Private; (function (Private) { /** * The mimetype used for Jupyter cell data. */ const JUPYTER_CELL_MIME = 'application/vnd.jupyter.cells'; /** * An implementation of the clipboard interface. * This uses the native clipboard API when available, with a fallback to * a MimeData instance otherwise - The native clipboard API only works in * secure contexts (pages served over HTTPS or localhost). */ class ClipboardImpl { /** * Create a new clipboard instance. */ constructor(fallback) { this.fallback = fallback || new MimeData(); const { systemClipboard } = this; if (!systemClipboard) { console.warn('Clipboard API not available'); } } /** * Clear the clipboard. * This is a no-op for the native clipboard API. * The fallback clipboard is cleared by setting the data to an empty */ clear() { this.fallback.clear(); } /** * Whether the clipboard has data for a given mime type. * Returns `false` if the data does not exist. * * @param mime - The mime type to check. */ async hasData(mime) { const { systemClipboard } = this; if (!systemClipboard) { return this.fallback.hasData(mime); } let text; try { text = await systemClipboard.readText(); } catch (reason) { console.warn('Failed to read data from clipboard:', reason); if (reason.name === 'NotAllowedError') { // If the clipboard API is not allowed, fall back to the // internal clipboard. return this.fallback.hasData(mime); } return false; } try { this.convertStringToData(mime, text); return true; } catch (reason) { return false; } } /** * Retrieve the data for a given mime type. * * @param mime - The mime type to retrieve. * @returns A promise that resolves with the data for the given mime type. */ async getData(mime) { const { systemClipboard } = this; if (!systemClipboard) { return this.fallback.getData(mime); } try { const text = await systemClipboard.readText(); return this.convertStringToData(mime, text); } catch (reason) { console.warn('Failed to read data from clipboard:', reason); if (reason.name === 'NotAllowedError') { // If the clipboard API is not allowed, fall back to the // internal clipboard. return this.fallback.getData(mime); } return null; } } /** * Set the data for a given mime type. * * @param mime - The mime type to set. * @param data - The data to set. */ async setData(mime, data) { const { systemClipboard } = this; if (!systemClipboard) { this.fallback.clear(); this.fallback.setData(mime, data); return; } try { await systemClipboard.writeText(this.convertDataToString(mime, data)); } catch (reason) { console.warn('Failed to write data to clipboard:', reason); // If the clipboard API is not allowed, fall back to the // internal clipboard. this.fallback.clear(); this.fallback.setData(mime, data); } } /** * Convert the data to a string for the given mime type. */ convertDataToString(mime, data) { if (mime === JUPYTER_CELL_MIME) { return JSON.stringify(data); } return (data || '').toString(); } /** * Convert the string to data for the given mime type. */ convertStringToData(mime, text) { if (mime === JUPYTER_CELL_MIME) { return JSON.parse(text); } return text; } /** * Get the system clipboard instance. */ get systemClipboard() { return navigator.clipboard; } } /** * The application clipboard instance. */ Private.instance = new MimeData(); /** * The system clipboard instance. */ Private.systemInstance = new ClipboardImpl(); })(Private || (Private = {})); //# sourceMappingURL=clipboard.js.map