clipboard-polyfill
Version:
A polyfill for the asynchronous clipboard API
417 lines (403 loc) • 12.8 kB
JavaScript
// src/clipboard-polyfill/ClipboardItem/data-types.ts
var TEXT_PLAIN = "text/plain";
var TEXT_HTML = "text/html";
// src/clipboard-polyfill/debug.ts
var debugLogImpl = (s) => {
};
function debugLog(s) {
debugLogImpl(s);
}
function setDebugLog(logFn) {
debugLogImpl = logFn;
}
var showWarnings = true;
function suppressWarnings() {
showWarnings = false;
}
function shouldShowWarnings() {
return showWarnings;
}
function warnOrLog() {
(console.warn || console.log).apply(console, arguments);
}
var warn = warnOrLog.bind("[clipboard-polyfill]");
// src/clipboard-polyfill/builtins/window-globalThis.ts
var originalWindow = typeof window === "undefined" ? void 0 : window;
var originalGlobalThis = typeof globalThis === "undefined" ? void 0 : globalThis;
// src/clipboard-polyfill/builtins/promise-constructor.ts
var _a, _b, _c;
var promiseConstructorImpl = (_c = (_a = originalWindow) == null ? void 0 : _a.Promise) != null ? _c : (_b = originalGlobalThis) == null ? void 0 : _b.Promise;
function getPromiseConstructor() {
if (!promiseConstructorImpl) {
throw new Error(
"No `Promise` implementation available for `clipboard-polyfill`. Consider using: https://github.com/lgarron/clipboard-polyfill#flat-file-version-with-promise-included"
);
}
return promiseConstructorImpl;
}
// src/clipboard-polyfill/builtins/builtin-globals.ts
var originalNavigator = typeof navigator === "undefined" ? void 0 : navigator;
var originalNavigatorClipboard = originalNavigator == null ? void 0 : originalNavigator.clipboard;
var _a2;
var originalNavigatorClipboardRead = (_a2 = originalNavigatorClipboard == null ? void 0 : originalNavigatorClipboard.read) == null ? void 0 : _a2.bind(
originalNavigatorClipboard
);
var _a3;
var originalNavigatorClipboardReadText = (_a3 = originalNavigatorClipboard == null ? void 0 : originalNavigatorClipboard.readText) == null ? void 0 : _a3.bind(
originalNavigatorClipboard
);
var _a4;
var originalNavigatorClipboardWrite = (_a4 = originalNavigatorClipboard == null ? void 0 : originalNavigatorClipboard.write) == null ? void 0 : _a4.bind(
originalNavigatorClipboard
);
var _a5;
var originalNavigatorClipboardWriteText = (_a5 = originalNavigatorClipboard == null ? void 0 : originalNavigatorClipboard.writeText) == null ? void 0 : _a5.bind(
originalNavigatorClipboard
);
var _a6;
var originalWindowClipboardItem = (_a6 = originalWindow) == null ? void 0 : _a6.ClipboardItem;
var promiseConstructor = getPromiseConstructor();
// src/clipboard-polyfill/strategies/internet-explorer.ts
var ieWindow = originalWindow;
function seemToBeInIE() {
return typeof ClipboardEvent === "undefined" && typeof (ieWindow == null ? void 0 : ieWindow.clipboardData) !== "undefined" && typeof (ieWindow == null ? void 0 : ieWindow.clipboardData.setData) !== "undefined";
}
function writeTextIE(text) {
if (!ieWindow.clipboardData) {
return false;
}
var success = ieWindow.clipboardData.setData("Text", text);
if (success) {
debugLog("writeTextIE worked");
}
return success;
}
function readTextIE() {
if (!ieWindow.clipboardData) {
throw new Error("Cannot read IE clipboard Data ");
}
var text = ieWindow.clipboardData.getData("Text");
if (text === "") {
throw new Error(
"Empty clipboard or could not read plain text from clipboard"
);
}
return text;
}
// src/clipboard-polyfill/strategies/dom.ts
function copyListener(tracker, data, e) {
debugLog("listener called");
tracker.success = true;
for (var type in data) {
var value = data[type];
var clipboardData = e.clipboardData;
clipboardData.setData(type, value);
if (type === TEXT_PLAIN && clipboardData.getData(type) !== value) {
debugLog("setting text/plain failed");
tracker.success = false;
}
}
e.preventDefault();
}
function execCopy(data) {
var tracker = { success: false };
var listener = copyListener.bind(this, tracker, data);
document.addEventListener("copy", listener);
try {
document.execCommand("copy");
} finally {
document.removeEventListener("copy", listener);
}
return tracker.success;
}
function copyUsingTempSelection(e, data) {
selectionSet(e);
var success = execCopy(data);
selectionClear();
return success;
}
function copyUsingTempElem(data) {
var tempElem = document.createElement("div");
tempElem.setAttribute("style", "-webkit-user-select: text !important");
tempElem.textContent = "temporary element";
document.body.appendChild(tempElem);
var success = copyUsingTempSelection(tempElem, data);
document.body.removeChild(tempElem);
return success;
}
function copyTextUsingDOM(str) {
debugLog("copyTextUsingDOM");
var tempElem = document.createElement("div");
tempElem.setAttribute("style", "-webkit-user-select: text !important");
var spanParent = tempElem;
if (tempElem.attachShadow) {
debugLog("Using shadow DOM.");
spanParent = tempElem.attachShadow({ mode: "open" });
}
var span = document.createElement("span");
span.innerText = str;
spanParent.appendChild(span);
document.body.appendChild(tempElem);
selectionSet(span);
var result = document.execCommand("copy");
selectionClear();
document.body.removeChild(tempElem);
return result;
}
function selectionSet(elem) {
var sel = document.getSelection();
if (sel) {
var range = document.createRange();
range.selectNodeContents(elem);
sel.removeAllRanges();
sel.addRange(range);
}
}
function selectionClear() {
var sel = document.getSelection();
if (sel) {
sel.removeAllRanges();
}
}
// src/clipboard-polyfill/implementations/write-fallback.ts
function writeFallback(stringItem) {
var hasTextPlain = TEXT_PLAIN in stringItem;
if (seemToBeInIE()) {
if (!hasTextPlain) {
throw new Error("No `text/plain` value was specified.");
}
if (writeTextIE(stringItem[TEXT_PLAIN])) {
return true;
} else {
throw new Error("Copying failed, possibly because the user rejected it.");
}
}
if (execCopy(stringItem)) {
debugLog("regular execCopy worked");
return true;
}
if (navigator.userAgent.indexOf("Edge") > -1) {
debugLog('UA "Edge" => assuming success');
return true;
}
if (copyUsingTempSelection(document.body, stringItem)) {
debugLog("copyUsingTempSelection worked");
return true;
}
if (copyUsingTempElem(stringItem)) {
debugLog("copyUsingTempElem worked");
return true;
}
if (copyTextUsingDOM(stringItem[TEXT_PLAIN])) {
debugLog("copyTextUsingDOM worked");
return true;
}
return false;
}
// src/clipboard-polyfill/promise/promise-compat.ts
function promiseRecordMap(keys, f) {
var promiseList = [];
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
promiseList.push(f(key));
}
return promiseConstructor.all(promiseList).then((vList) => {
var dataOut = {};
for (var i2 = 0; i2 < keys.length; i2++) {
dataOut[keys[i2]] = vList[i2];
}
return dataOut;
});
}
var voidPromise = promiseConstructor.resolve();
var truePromiseFn = () => promiseConstructor.resolve(true);
var falsePromise = promiseConstructor.resolve(false);
function rejectThrownErrors(executor) {
return new promiseConstructor((resolve, reject) => {
try {
resolve(executor());
} catch (e) {
reject(e);
}
});
}
// src/clipboard-polyfill/implementations/text.ts
function stringToStringItem(s) {
var stringItem = {};
stringItem[TEXT_PLAIN] = s;
return stringItem;
}
function writeText(s) {
if (originalNavigatorClipboardWriteText) {
debugLog("Using `navigator.clipboard.writeText()`.");
return originalNavigatorClipboardWriteText(s).catch(
() => writeTextStringFallbackPromise(s)
);
}
return writeTextStringFallbackPromise(s);
}
function writeTextStringFallbackPromise(s) {
return rejectThrownErrors(
() => promiseConstructor.resolve(writeTextStringFallback(s))
);
}
function writeTextStringFallback(s) {
if (!writeFallback(stringToStringItem(s))) {
throw new Error("writeText() failed");
}
}
function readText() {
return rejectThrownErrors(() => {
if (originalNavigatorClipboardReadText) {
debugLog("Using `navigator.clipboard.readText()`.");
return originalNavigatorClipboardReadText();
}
if (seemToBeInIE()) {
var result = readTextIE();
return promiseConstructor.resolve(result);
}
throw new Error("Read is not supported in your browser.");
});
}
// src/clipboard-polyfill/ClipboardItem/check.ts
function hasItemWithType(clipboardItems, typeName) {
for (var i = 0; i < clipboardItems.length; i++) {
var item = clipboardItems[i];
if (item.types.indexOf(typeName) !== -1) {
return true;
}
}
return false;
}
// src/clipboard-polyfill/ClipboardItem/ClipboardItemPolyfill.ts
function ClipboardItemPolyfillImpl(items, options) {
var _a7;
var types = Object.keys(items);
var _items = {};
for (var type in items) {
var item = items[type];
if (typeof item === "string") {
_items[type] = stringToBlob(type, item);
} else {
_items[type] = item;
}
}
var presentationStyle = (_a7 = options == null ? void 0 : options.presentationStyle) != null ? _a7 : "unspecified";
function getType(type2) {
return promiseConstructor.resolve(_items[type2]);
}
return {
types,
presentationStyle,
getType
};
}
var ClipboardItemPolyfill = ClipboardItemPolyfillImpl;
// src/clipboard-polyfill/ClipboardItem/convert.ts
function stringToBlob(type, str) {
return new Blob([str], {
type
});
}
function blobToString(blob) {
return new promiseConstructor((resolve, reject) => {
var fileReader = new FileReader();
fileReader.addEventListener("load", () => {
var result = fileReader.result;
if (typeof result === "string") {
resolve(result);
} else {
reject("could not convert blob to string");
}
});
fileReader.readAsText(blob);
});
}
function clipboardItemToGlobalClipboardItem(clipboardItem) {
return promiseRecordMap(clipboardItem.types, function(type) {
return clipboardItem.getType(type);
}).then((items) => {
return new promiseConstructor((resolve, reject) => {
var options = {};
if (clipboardItem.presentationStyle) {
options.presentationStyle = clipboardItem.presentationStyle;
}
if (originalWindowClipboardItem) {
resolve(new originalWindowClipboardItem(items, options));
} else {
reject("window.ClipboardItem is not defined");
}
});
});
}
function textToClipboardItem(text) {
var items = {};
items[TEXT_PLAIN] = stringToBlob(text, TEXT_PLAIN);
return new ClipboardItemPolyfill(items);
}
function getTypeAsString(clipboardItem, type) {
return clipboardItem.getType(type).then((text) => {
return blobToString(text);
});
}
function toStringItem(data) {
return promiseRecordMap(data.types, function(type) {
return getTypeAsString(data, type);
});
}
// src/clipboard-polyfill/implementations/blob.ts
function write(data) {
return rejectThrownErrors(() => {
if (originalNavigatorClipboardWrite && originalWindowClipboardItem) {
var originalNavigatorClipboardWriteCached = originalNavigatorClipboardWrite;
debugLog("Using `navigator.clipboard.write()`.");
return promiseConstructor.all(data.map(clipboardItemToGlobalClipboardItem)).then(
(globalClipboardItems) => {
return originalNavigatorClipboardWriteCached(globalClipboardItems).then(truePromiseFn).catch((e) => {
if (!hasItemWithType(data, TEXT_PLAIN) && !hasItemWithType(data, TEXT_HTML)) {
throw e;
}
return falsePromise;
});
}
);
}
return falsePromise;
}).then((success) => {
if (success) {
return voidPromise;
}
var hasTextPlain = hasItemWithType(data, TEXT_PLAIN);
if (shouldShowWarnings() && !hasTextPlain) {
debugLog(
"clipboard.write() was called without a `text/plain` data type. On some platforms, this may result in an empty clipboard. Call suppressWarnings() to suppress this warning."
);
}
return toStringItem(data[0]).then((stringItem) => {
if (!writeFallback(stringItem)) {
throw new Error("write() failed");
}
});
});
}
function read() {
return rejectThrownErrors(() => {
if (originalNavigatorClipboardRead) {
debugLog("Using `navigator.clipboard.read()`.");
return originalNavigatorClipboardRead();
}
return readText().then((text) => {
return [textToClipboardItem(text)];
});
});
}
export {
ClipboardItemPolyfill as ClipboardItem,
read,
readText,
setDebugLog,
suppressWarnings,
write,
writeText
};
//# sourceMappingURL=clipboard-polyfill.es6.js.map