import deselectCurrent from './toggle-selection'; interface Options { debug?: boolean; message?: string; format?: string; // MIME type onCopy?: (clipboardData: object) => void; } const clipboardToIE11Formatting = { 'text/plain': 'Text', 'text/html': 'Url', default: 'Text', }; const defaultMessage = 'Copy to clipboard: #{key}, Enter'; function format(message: string) { const copyKey = (/mac os x/i.test(navigator.userAgent) ? '⌘' : 'Ctrl') + '+C'; return message.replace(/#{\s*key\s*}/g, copyKey); } function copy(text: string, options?: Options): boolean { let message, reselectPrevious, range, selection, mark, success = false; if (!options) { options = {}; } const debug = options.debug || false; try { reselectPrevious = deselectCurrent(); range = document.createRange(); selection = document.getSelection(); mark = document.createElement('span'); mark.textContent = text; // reset user styles for span element mark.style.all = 'unset'; // prevents scrolling to the end of the page mark.style.position = 'fixed'; mark.style.top = 0; mark.style.clip = 'rect(0, 0, 0, 0)'; // used to preserve spaces and line breaks mark.style.whiteSpace = 'pre'; // do not inherit user-select (it may be `none`) mark.style.webkitUserSelect = 'text'; mark.style.MozUserSelect = 'text'; mark.style.msUserSelect = 'text'; mark.style.userSelect = 'text'; mark.addEventListener('copy', function (e) { e.stopPropagation(); if (options.format) { e.preventDefault(); if (typeof e.clipboardData === 'undefined') { // IE 11 debug && console.warn('unable to use e.clipboardData'); debug && console.warn('trying IE specific stuff'); (window as any).clipboardData.clearData(); const format = clipboardToIE11Formatting[options.format] || clipboardToIE11Formatting['default']; (window as any).clipboardData.setData(format, text); } else { // all other browsers e.clipboardData.clearData(); e.clipboardData.setData(options.format, text); } } if (options.onCopy) { e.preventDefault(); options.onCopy(e.clipboardData); } }); document.body.appendChild(mark); range.selectNodeContents(mark); selection.addRange(range); const successful = document.execCommand('copy'); if (!successful) { throw new Error('copy command was unsuccessful'); } success = true; } catch (err) { debug && console.error('unable to copy using execCommand: ', err); debug && console.warn('trying IE specific stuff'); try { (window as any).clipboardData.setData(options.format || 'text', text); options.onCopy && options.onCopy((window as any).clipboardData); success = true; } catch (err) { debug && console.error('unable to copy using clipboardData: ', err); debug && console.error('falling back to prompt'); message = format('message' in options ? options.message : defaultMessage); window.prompt(message, text); } } finally { if (selection) { if (typeof selection.removeRange == 'function') { selection.removeRange(range); } else { selection.removeAllRanges(); } } if (mark) { document.body.removeChild(mark); } reselectPrevious(); } return success; } export default copy;