mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-16 09:34:07 -08:00
202 lines
7.1 KiB
TypeScript
202 lines
7.1 KiB
TypeScript
/**
|
|
* Captures any pasted data and sends it to method "receivedCopyPasteData" which has to be
|
|
* defined on the component which uses this mixin
|
|
*/
|
|
import Vue from 'vue';
|
|
import { debounce } from 'lodash';
|
|
|
|
export const copyPaste = Vue.extend({
|
|
data () {
|
|
return {
|
|
copyPasteElementsGotCreated: false,
|
|
};
|
|
},
|
|
mounted () {
|
|
if (this.copyPasteElementsGotCreated === true) {
|
|
return;
|
|
}
|
|
|
|
this.copyPasteElementsGotCreated = true;
|
|
// Define the style of the html elements that get created to make
|
|
// sure that they are not visible
|
|
const style = document.createElement('style');
|
|
style.type = 'text/css';
|
|
style.innerHTML = `
|
|
.hidden-copy-paste {
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
width: 10px;
|
|
height: 10px;
|
|
display: block;
|
|
font-size: 1px;
|
|
z-index: -1;
|
|
color: transparent;
|
|
background: transparent;
|
|
overflow: hidden;
|
|
border: none;
|
|
padding: 0;
|
|
resize: none;
|
|
outline: none;
|
|
-webkit-user-select: text;
|
|
user-select: text;
|
|
}
|
|
`;
|
|
document.getElementsByTagName('head')[0].appendChild(style);
|
|
|
|
// Code is mainly from
|
|
// https://www.lucidchart.com/techblog/2014/12/02/definitive-guide-copying-pasting-javascript/
|
|
const isSafari = navigator.appVersion.search('Safari') !== -1 && navigator.appVersion.search('Chrome') === -1 && navigator.appVersion.search('CrMo') === -1 && navigator.appVersion.search('CriOS') === -1;
|
|
const isIe = (navigator.userAgent.toLowerCase().indexOf('msie') !== -1 || navigator.userAgent.toLowerCase().indexOf('trident') !== -1);
|
|
|
|
const hiddenInput = document.createElement('input');
|
|
hiddenInput.setAttribute('type', 'text');
|
|
hiddenInput.setAttribute('id', 'hidden-input-copy-paste');
|
|
hiddenInput.setAttribute('class', 'hidden-copy-paste');
|
|
|
|
document.body.append(hiddenInput);
|
|
|
|
let ieClipboardDiv: HTMLDivElement | null = null;
|
|
if (isIe) {
|
|
ieClipboardDiv = document.createElement('div');
|
|
ieClipboardDiv.setAttribute('id', 'hidden-ie-clipboard-copy-paste');
|
|
ieClipboardDiv.setAttribute('class', 'hidden-copy-paste');
|
|
ieClipboardDiv.setAttribute('contenteditable', 'true');
|
|
document.body.append(ieClipboardDiv);
|
|
|
|
document.addEventListener('beforepaste', () => {
|
|
// @ts-ignore
|
|
if (hiddenInput.is(':focus')) {
|
|
this.focusIeClipboardDiv(ieClipboardDiv as HTMLDivElement);
|
|
}
|
|
}, true);
|
|
}
|
|
|
|
let userInput = '';
|
|
const hiddenInputListener = (text: string) => { };
|
|
|
|
hiddenInput.addEventListener('input', (e) => {
|
|
const value = hiddenInput.value;
|
|
userInput += value;
|
|
hiddenInputListener(userInput);
|
|
|
|
// There is a bug (sometimes) with Safari and the input area can't be updated during
|
|
// the input event, so we update the input area after the event is done being processed
|
|
if (isSafari) {
|
|
hiddenInput.focus();
|
|
setTimeout(() => { this.focusHiddenArea(hiddenInput); }, 0);
|
|
} else {
|
|
this.focusHiddenArea(hiddenInput);
|
|
}
|
|
});
|
|
|
|
// Set clipboard event listeners on the document.
|
|
['paste'].forEach((event) => {
|
|
document.addEventListener(event, debounce((e) => {
|
|
// Check if the event got emitted from a message box or from something
|
|
// else which should ignore the copy/paste
|
|
// @ts-ignore
|
|
const path = e.path || (e.composedPath && e.composedPath());
|
|
for (let index = 0; index < path.length; index++) {
|
|
if (path[index].className && typeof path[index].className === 'string' && (
|
|
path[index].className.includes('el-message-box') || path[index].className.includes('ignore-key-press')
|
|
)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (ieClipboardDiv !== null) {
|
|
this.ieClipboardEvent(event, ieClipboardDiv);
|
|
} else {
|
|
this.standardClipboardEvent(event, e as ClipboardEvent);
|
|
// @ts-ignore
|
|
if (!document.activeElement || (document.activeElement && ['textarea', 'text', 'email', 'password'].indexOf(document.activeElement.type) === -1)) {
|
|
// That it still allows to paste into text, email, password & textarea-fiels we
|
|
// check if we can identify the active element and if so only
|
|
// run it if something else is selected.
|
|
this.focusHiddenArea(hiddenInput);
|
|
e.preventDefault();
|
|
}
|
|
}
|
|
}, 1000, { leading: true }));
|
|
});
|
|
},
|
|
methods: {
|
|
receivedCopyPasteData (plainTextData: string, event?: ClipboardEvent): void {
|
|
// THIS HAS TO BE DEFINED IN COMPONENT!
|
|
},
|
|
|
|
// For every browser except IE, we can easily get and set data on the clipboard
|
|
standardClipboardEvent (clipboardEventName: string, event: ClipboardEvent) {
|
|
const clipboardData = event.clipboardData;
|
|
if (clipboardData !== null && clipboardEventName === 'paste') {
|
|
const clipboardText = clipboardData.getData('text/plain');
|
|
this.receivedCopyPasteData(clipboardText, event);
|
|
}
|
|
},
|
|
|
|
// For IE, we can get/set Text or URL just as we normally would
|
|
ieClipboardEvent (clipboardEventName: string, ieClipboardDiv: HTMLDivElement) {
|
|
// @ts-ignore
|
|
const clipboardData = window.clipboardData;
|
|
if (clipboardEventName === 'paste') {
|
|
const clipboardText = clipboardData.getData('Text');
|
|
// @ts-ignore
|
|
ieClipboardDiv.empty();
|
|
this.receivedCopyPasteData(clipboardText);
|
|
}
|
|
},
|
|
|
|
// Focuses an element to be ready for copy/paste (used exclusively for IE)
|
|
focusIeClipboardDiv (ieClipboardDiv: HTMLDivElement) {
|
|
ieClipboardDiv.focus();
|
|
const range = document.createRange();
|
|
// @ts-ignore
|
|
range.selectNodeContents((ieClipboardDiv.get(0)));
|
|
const selection = window.getSelection();
|
|
if (selection !== null) {
|
|
selection.removeAllRanges();
|
|
selection.addRange(range);
|
|
}
|
|
},
|
|
|
|
focusHiddenArea (hiddenInput: HTMLInputElement) {
|
|
// In order to ensure that the browser will fire clipboard events, we always need to have something selected
|
|
hiddenInput.value = ' ';
|
|
hiddenInput.focus();
|
|
hiddenInput.select();
|
|
},
|
|
|
|
/**
|
|
* Copies given data to clipboard
|
|
*/
|
|
copyToClipboard (value: string): void {
|
|
// FROM: https://hackernoon.com/copying-text-to-clipboard-with-javascript-df4d4988697f
|
|
const element = document.createElement('textarea'); // Create a <textarea> element
|
|
element.value = value; // Set its value to the string that you want copied
|
|
element.setAttribute('readonly', ''); // Make it readonly to be tamper-proof
|
|
element.style.position = 'absolute';
|
|
element.style.left = '-9999px'; // Move outside the screen to make it invisible
|
|
document.body.appendChild(element); // Append the <textarea> element to the HTML document
|
|
|
|
const selection = document.getSelection();
|
|
if (selection === null) {
|
|
return;
|
|
}
|
|
|
|
const selected = selection.rangeCount > 0 // Check if there is any content selected previously
|
|
? selection.getRangeAt(0) // Store selection if found
|
|
: false; // Mark as false to know no selection existed before
|
|
element.select(); // Select the <textarea> content
|
|
document.execCommand('copy'); // Copy - only works as a result of a user action (e.g. click events)
|
|
document.body.removeChild(element); // Remove the <textarea> element
|
|
if (selected) {
|
|
// If a selection existed before copying
|
|
selection.removeAllRanges(); // Unselect everything on the HTML document
|
|
selection.addRange(selected); // Restore the original selection
|
|
}
|
|
},
|
|
|
|
},
|
|
});
|