Web应用程序如何检测粘贴事件并检索要粘贴的数据?
我希望在将文本粘贴到富文本编辑器之前删除HTML内容。
之后粘贴后清理文本有效,但问题是所有以前的格式都丢失了。例如,我可以在编辑器中编写一个句子并将其设为粗体,但是当我粘贴新文本时,所有格式都会丢失。我想只清理粘贴的文本,并保持以前的格式不变。
理想情况下,该解决方案应适用于所有现代浏览器(例如,MSIE,Gecko,Chrome和Safari)。
请注意,MSIE有clipboardData.getData()
,但我找不到其他浏览器的类似功能。
答案 0 :(得分:282)
适用于IE6 +,FF 22 +,Chrome,Safari,Edge (仅在IE9 +中测试过,但应该适用于较低版本)
如果您需要支持粘贴HTML或Firefox< = 22,请参阅解决方案#2。
<div id='editableDiv' contenteditable='true'>Paste</div>
function handlePaste (e) {
var clipboardData, pastedData;
// Stop data actually being pasted into div
e.stopPropagation();
e.preventDefault();
// Get pasted data via clipboard API
clipboardData = e.clipboardData || window.clipboardData;
pastedData = clipboardData.getData('Text');
// Do whatever with pasteddata
alert(pastedData);
}
document.getElementById('editableDiv').addEventListener('paste', handlePaste);
JSFiddle:https://jsfiddle.net/swL8ftLs/12/
请注意,此解决方案使用getData
函数的参数“Text”,这是非标准的。但是,在撰写本文时,它适用于所有浏览器。
在IE6 +,FF 3.5 +,Chrome,Safari,Edge
中测试<div id='div' contenteditable='true'>Paste</div>
var editableDiv = document.getElementById('editableDiv');
function handlepaste (e) {
var types, pastedData, savedContent;
// Browsers that support the 'text/html' type in the Clipboard API (Chrome, Firefox 22+)
if (e && e.clipboardData && e.clipboardData.types && e.clipboardData.getData) {
// Check for 'text/html' in types list. See abligh's answer below for deatils on
// why the DOMStringList bit is needed. We cannot fall back to 'text/plain' as
// Safari/Edge don't advertise HTML data even if it is available
types = e.clipboardData.types;
if (((types instanceof DOMStringList) && types.contains("text/html")) || (types.indexOf && types.indexOf('text/html') !== -1)) {
// Extract data and pass it to callback
pastedData = e.clipboardData.getData('text/html');
processPaste(editableDiv, pastedData);
// Stop the data from actually being pasted
e.stopPropagation();
e.preventDefault();
return false;
}
}
// Everything else: Move existing element contents to a DocumentFragment for safekeeping
savedContent = document.createDocumentFragment();
while(editableDiv.childNodes.length > 0) {
savedContent.appendChild(editableDiv.childNodes[0]);
}
// Then wait for browser to paste content into it and cleanup
waitForPastedData(editableDiv, savedContent);
return true;
}
function waitForPastedData (elem, savedContent) {
// If data has been processes by browser, process it
if (elem.childNodes && elem.childNodes.length > 0) {
// Retrieve pasted content via innerHTML
// (Alternatively loop through elem.childNodes or elem.getElementsByTagName here)
var pastedData = elem.innerHTML;
// Restore saved content
elem.innerHTML = "";
elem.appendChild(savedContent);
// Call callback
processPaste(elem, pastedData);
}
// Else wait 20ms and try again
else {
setTimeout(function () {
waitForPastedData(elem, savedContent)
}, 20);
}
}
function processPaste (elem, pastedData) {
// Do whatever with gathered data;
alert(pastedData);
elem.focus();
}
// Modern browsers. Note: 3rd argument is required for Firefox <= 6
if (editableDiv.addEventListener) {
editableDiv.addEventListener('paste', handlepaste, false);
}
// IE <= 8
else {
editableDiv.attachEvent('onpaste', handlepaste);
}
JSFiddle:https://jsfiddle.net/nicoburns/wrqmuabo/23/
onpaste
的{{1}}事件附加了div
函数并传递了一个参数:粘贴事件的handlePaste
对象。我们特别感兴趣的是此事件的event
属性,可以在非浏览器中启用剪贴板访问。在IE中,等效值为clipboardData
,尽管这有一个稍微不同的API。
请参阅下面的资源部分。
window.clipboardData
功能:
这个功能有两个分支。
第一次检查是否存在handlepaste
并检查event.clipboardData
属性是否包含'text / html'(types
可能是types
,使用DOMStringList
进行检查contains
方法或使用indexOf
方法检查的字符串)。如果满足所有这些条件,那么我们按照解决方案#1继续,除了'text / html'而不是'text / plain'。目前适用于Chrome和Firefox 22 +。
如果不支持此方法(所有其他浏览器),那么我们
DocumentFragment
waitForPastedData
函数 waitforpastedata
功能:
此函数首先轮询粘贴的数据(每20ms一次),这是必要的,因为它不会立即出现。当数据出现时:
processpaste
功能:
粘贴数据是否随意。在这种情况下,我们只是提醒数据,你可以做任何你喜欢的事情。您可能希望通过某种数据清理过程运行粘贴的数据。
保存并恢复光标位置
在实际情况中,您可能希望在之前保存选择,然后将其恢复(Set cursor position on contentEditable <div>)。然后,您可以在用户启动粘贴操作时将粘贴的数据插入光标所在的位置。
感谢Tim Down建议使用DocumentFragment,并且由于使用DOMStringList而不是clipData.types的字符串而在Firefox中捕获错误
答案 1 :(得分:138)
自写这个答案后情况发生了变化:现在Firefox已经在版本22中添加了支持,现在所有主流浏览器都支持在粘贴事件中访问剪贴板数据。有关示例,请参阅Nico Burns's answer。
过去,通常不可能采用跨浏览器方式。理想情况是能够通过paste
事件which is possible in recent browsers获取粘贴的内容,但不能在某些旧版浏览器(特别是Firefox&lt; 22)中获取。
当您需要支持旧浏览器时,您可以做的事情非常复杂,并且可以在Firefox 2 +,IE 5.5+和WebKit浏览器(如Safari或Chrome)中使用。 TinyMCE和CKEditor的最新版本都使用这种技术:
designMode
并在textarea上调用focus()
,从而移动插入符并有效地重定向粘贴designMode
,恢复用户选择并粘贴文字。请注意,这仅适用于键盘粘贴事件,而不适用于上下文或编辑菜单中的粘贴。当粘贴事件触发时,将插入符重定向到textarea(至少在某些浏览器中)为时已晚。
如果您需要支持Firefox 2,请注意您需要将textarea放在父文档中,而不是将WYSIWYG编辑器iframe的文档放在该浏览器中。
答案 2 :(得分:117)
简易版:
document.querySelector('[contenteditable]').addEventListener('paste', (e) => {
e.preventDefault();
const text = (e.originalEvent || e).clipboardData.getData('text/plain');
window.document.execCommand('insertText', false, text);
});
使用 clipboardData
演示: http://jsbin.com/nozifexasu/edit?js,output
Edge,Firefox,Chrome,Safari,Opera测试。
注意:请务必检查服务器端的输入/输出(如PHP strip-tags)
答案 3 :(得分:25)
<强> Live Demo 强>
在Chrome / FF / IE11上测试
Chrome / IE存在烦恼,即这些浏览器会为每个新行添加<div>
元素。有一篇关于此here的帖子,可以通过将 contenteditable 元素设置为display:inline-block
function onPaste(e){
var content;
e.preventDefault();
if( e.clipboardData ){
content = e.clipboardData.getData('text/plain');
document.execCommand('insertText', false, content);
return false;
}
else if( window.clipboardData ){
content = window.clipboardData.getData('Text');
if (window.getSelection)
window.getSelection().getRangeAt(0).insertNode( document.createTextNode(content) );
}
}
/////// EVENT BINDING /////////
document.querySelector('[contenteditable]').addEventListener('paste', onPaste);
&#13;
[contenteditable]{
/* chroem bug: https://stackoverflow.com/a/24689420/104380 */
display:inline-block;
width: calc(100% - 40px);
min-height:120px;
margin:10px;
padding:10px;
border:1px dashed green;
}
/*
mark HTML inside the "contenteditable"
(Shouldn't be any OFC!)'
*/
[contenteditable] *{
background-color:red;
}
&#13;
<div contenteditable></div>
&#13;
答案 4 :(得分:15)
我已经为Tim Downs的提议提供了一些关于屏幕外文本的概念证明。这里是代码:
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
<script language="JavaScript">
$(document).ready(function()
{
var ctrlDown = false;
var ctrlKey = 17, vKey = 86, cKey = 67;
$(document).keydown(function(e)
{
if (e.keyCode == ctrlKey) ctrlDown = true;
}).keyup(function(e)
{
if (e.keyCode == ctrlKey) ctrlDown = false;
});
$(".capture-paste").keydown(function(e)
{
if (ctrlDown && (e.keyCode == vKey || e.keyCode == cKey)){
$("#area").css("display","block");
$("#area").focus();
}
});
$(".capture-paste").keyup(function(e)
{
if (ctrlDown && (e.keyCode == vKey || e.keyCode == cKey)){
$("#area").blur();
//do your sanitation check or whatever stuff here
$("#paste-output").text($("#area").val());
$("#area").val("");
$("#area").css("display","none");
}
});
});
</script>
</head>
<body class="capture-paste">
<div id="paste-output"></div>
<div>
<textarea id="area" style="display: none; position: absolute; left: -99em;"></textarea>
</div>
</body>
</html>
只需将整个代码复制并粘贴到一个html文件中,然后尝试从文档中的任意位置粘贴(使用ctrl-v)文本。
我在IE9以及Firefox,Chrome和Opera的新版本中测试过它。效果很好。也可以使用他喜欢的任何组合组合来实现这一功能。当然不要忘记包含jQuery源代码。
随意使用此代码,如果您有一些改进或问题,请将其发回。另请注意,我不是Javascript开发人员所以我可能错过了一些东西(=&gt;做自己的测试)。
答案 5 :(得分:10)
基于 l2aelba anwser。这是在FF,Safari,Chrome,IE(8,9,10和11)
上测试的 $("#editText").on("paste", function (e) {
e.preventDefault();
var text;
var clp = (e.originalEvent || e).clipboardData;
if (clp === undefined || clp === null) {
text = window.clipboardData.getData("text") || "";
if (text !== "") {
if (window.getSelection) {
var newNode = document.createElement("span");
newNode.innerHTML = text;
window.getSelection().getRangeAt(0).insertNode(newNode);
} else {
document.selection.createRange().pasteHTML(text);
}
}
} else {
text = clp.getData('text/plain') || "";
if (text !== "") {
document.execCommand('insertText', false, text);
}
}
});
答案 6 :(得分:9)
这个不使用任何setTimeout()。
我使用this篇文章来实现跨浏览器支持。
$(document).on("focus", "input[type=text],textarea", function (e) {
var t = e.target;
if (!$(t).data("EventListenerSet")) {
//get length of field before paste
var keyup = function () {
$(this).data("lastLength", $(this).val().length);
};
$(t).data("lastLength", $(t).val().length);
//catch paste event
var paste = function () {
$(this).data("paste", 1);//Opera 11.11+
};
//process modified data, if paste occured
var func = function () {
if ($(this).data("paste")) {
alert(this.value.substr($(this).data("lastLength")));
$(this).data("paste", 0);
this.value = this.value.substr(0, $(this).data("lastLength"));
$(t).data("lastLength", $(t).val().length);
}
};
if (window.addEventListener) {
t.addEventListener('keyup', keyup, false);
t.addEventListener('paste', paste, false);
t.addEventListener('input', func, false);
}
else {//IE
t.attachEvent('onkeyup', function () {
keyup.call(t);
});
t.attachEvent('onpaste', function () {
paste.call(t);
});
t.attachEvent('onpropertychange', function () {
func.call(t);
});
}
$(t).data("EventListenerSet", 1);
}
});
此代码在粘贴之前使用选择句柄进行了扩展: demo
答案 7 :(得分:5)
对于清除粘贴的文字和用粘贴的文字替换当前选定的文字,问题非常重要:
<div id='div' contenteditable='true' onpaste='handlepaste(this, event)'>Paste</div>
JS:
function handlepaste(el, e) {
document.execCommand('insertText', false, e.clipboardData.getData('text/plain'));
e.preventDefault();
}
答案 8 :(得分:5)
这适用于所有支持onpaste事件和变异观察者的浏览器。
此解决方案仅比获取文本更进一步,它实际上允许您在粘贴到元素之前编辑粘贴的内容。
它的工作原理是使用contenteditable,onpaste事件(所有主流浏览器支持)和变异观察者(由Chrome,Firefox和IE11 +支持)
第1步
创建一个具有contenteditable
的HTML元素<div contenteditable="true" id="target_paste_element"></div>
第2步
在您的Javascript代码中添加以下事件
document.getElementById("target_paste_element").addEventListener("paste", pasteEventVerifierEditor.bind(window, pasteCallBack), false);
我们需要绑定pasteCallBack,因为异步调用变异观察器。
第3步
将以下功能添加到您的代码中
function pasteEventVerifierEditor(callback, e)
{
//is fired on a paste event.
//pastes content into another contenteditable div, mutation observer observes this, content get pasted, dom tree is copied and can be referenced through call back.
//create temp div
//save the caret position.
savedCaret = saveSelection(document.getElementById("target_paste_element"));
var tempDiv = document.createElement("div");
tempDiv.id = "id_tempDiv_paste_editor";
//tempDiv.style.display = "none";
document.body.appendChild(tempDiv);
tempDiv.contentEditable = "true";
tempDiv.focus();
//we have to wait for the change to occur.
//attach a mutation observer
if (window['MutationObserver'])
{
//this is new functionality
//observer is present in firefox/chrome and IE11
// select the target node
// create an observer instance
tempDiv.observer = new MutationObserver(pasteMutationObserver.bind(window, callback));
// configuration of the observer:
var config = { attributes: false, childList: true, characterData: true, subtree: true };
// pass in the target node, as well as the observer options
tempDiv.observer.observe(tempDiv, config);
}
}
function pasteMutationObserver(callback)
{
document.getElementById("id_tempDiv_paste_editor").observer.disconnect();
delete document.getElementById("id_tempDiv_paste_editor").observer;
if (callback)
{
//return the copied dom tree to the supplied callback.
//copy to avoid closures.
callback.apply(document.getElementById("id_tempDiv_paste_editor").cloneNode(true));
}
document.body.removeChild(document.getElementById("id_tempDiv_paste_editor"));
}
function pasteCallBack()
{
//paste the content into the element.
restoreSelection(document.getElementById("target_paste_element"), savedCaret);
delete savedCaret;
pasteHtmlAtCaret(this.innerHTML, false, true);
}
saveSelection = function(containerEl) {
if (containerEl == document.activeElement)
{
var range = window.getSelection().getRangeAt(0);
var preSelectionRange = range.cloneRange();
preSelectionRange.selectNodeContents(containerEl);
preSelectionRange.setEnd(range.startContainer, range.startOffset);
var start = preSelectionRange.toString().length;
return {
start: start,
end: start + range.toString().length
};
}
};
restoreSelection = function(containerEl, savedSel) {
containerEl.focus();
var charIndex = 0, range = document.createRange();
range.setStart(containerEl, 0);
range.collapse(true);
var nodeStack = [containerEl], node, foundStart = false, stop = false;
while (!stop && (node = nodeStack.pop())) {
if (node.nodeType == 3) {
var nextCharIndex = charIndex + node.length;
if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {
range.setStart(node, savedSel.start - charIndex);
foundStart = true;
}
if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {
range.setEnd(node, savedSel.end - charIndex);
stop = true;
}
charIndex = nextCharIndex;
} else {
var i = node.childNodes.length;
while (i--) {
nodeStack.push(node.childNodes[i]);
}
}
}
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
function pasteHtmlAtCaret(html, returnInNode, selectPastedContent) {
//function written by Tim Down
var sel, range;
if (window.getSelection) {
// IE9 and non-IE
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
// Range.createContextualFragment() would be useful here but is
// only relatively recently standardized and is not supported in
// some browsers (IE9, for one)
var el = document.createElement("div");
el.innerHTML = html;
var frag = document.createDocumentFragment(), node, lastNode;
while ( (node = el.firstChild) ) {
lastNode = frag.appendChild(node);
}
var firstNode = frag.firstChild;
range.insertNode(frag);
// Preserve the selection
if (lastNode) {
range = range.cloneRange();
if (returnInNode)
{
range.setStart(lastNode, 0); //this part is edited, set caret inside pasted node.
}
else
{
range.setStartAfter(lastNode);
}
if (selectPastedContent) {
range.setStartBefore(firstNode);
} else {
range.collapse(true);
}
sel.removeAllRanges();
sel.addRange(range);
}
}
} else if ( (sel = document.selection) && sel.type != "Control") {
// IE < 9
var originalRange = sel.createRange();
originalRange.collapse(true);
sel.createRange().pasteHTML(html);
if (selectPastedContent) {
range = sel.createRange();
range.setEndPoint("StartToStart", originalRange);
range.select();
}
}
}
代码的作用:
非常感谢Tim Down 请看这篇文章的答案:
答案 9 :(得分:4)
对我有用的解决方案是,如果要粘贴到文本输入,则会将事件侦听器添加到粘贴事件。 由于粘贴事件发生在输入更改中的文本之前,因此在我的粘贴处理程序中,我创建了一个延迟函数,在其中我检查粘贴时发生的输入框中的更改:
onPaste: function() {
var oThis = this;
setTimeout(function() { // Defer until onPaste() is done
console.log('paste', oThis.input.value);
// Manipulate pasted input
}, 1);
}
答案 10 :(得分:4)
这对于Nico的回答来说太长了,我根本不认为这对Firefox有效(根据评论),并且在Safari上对我不起作用
首先,您现在似乎可以直接从剪贴板中读取。而不是像以下代码:
if (/text\/plain/.test(e.clipboardData.types)) {
// shouldn't this be writing to elem.value for text/plain anyway?
elem.innerHTML = e.clipboardData.getData('text/plain');
}
使用:
types = e.clipboardData.types;
if (((types instanceof DOMStringList) && types.contains("text/plain")) ||
(/text\/plain/.test(types))) {
// shouldn't this be writing to elem.value for text/plain anyway?
elem.innerHTML = e.clipboardData.getData('text/plain');
}
因为Firefox有一个types
字段DOMStringList
,但未实现test
。
除非焦点位于contenteditable=true
字段中,否则Firefox不允许粘贴。
最后,Firefox不允许可靠地粘贴 ,除非焦点位于textarea
(或者可能是输入),不仅是contenteditable=true
,还包括:
display:none
visibility:hidden
我试图隐藏文本字段,以便我可以在JS VNC模拟器上进行粘贴工作(即,它将转到远程客户端,并且实际上没有textarea
等要粘贴到其中。我发现试图隐藏上面的文本字段给出了有时工作的症状,但通常在第二次粘贴时失败(或当字段被清除以防止粘贴相同的数据两次),因为字段失去焦点并且无法正常恢复它尽管focus()
。我提出的解决方案是将其放在z-order: -1000
,使其成为display:none
,将其设为1px乘1px,并将所有颜色设置为透明。呸。
在Safari上,您应用上述第二部分,即您需要textarea
而不是display:none
。
答案 11 :(得分:3)
首先想到的是谷歌关闭lib的粘贴处理程序 http://closure-library.googlecode.com/svn/trunk/closure/goog/demos/pastehandler.html
答案 12 :(得分:2)
此解决方案是替换html标签,它简单且跨浏览器;检查这个jsfiddle:http://jsfiddle.net/tomwan/cbp1u2cx/1/,核心代码:
var $plainText = $("#plainText");
var $linkOnly = $("#linkOnly");
var $html = $("#html");
$plainText.on('paste', function (e) {
window.setTimeout(function () {
$plainText.html(removeAllTags(replaceStyleAttr($plainText.html())));
}, 0);
});
$linkOnly.on('paste', function (e) {
window.setTimeout(function () {
$linkOnly.html(removeTagsExcludeA(replaceStyleAttr($linkOnly.html())));
}, 0);
});
function replaceStyleAttr (str) {
return str.replace(/(<[\w\W]*?)(style)([\w\W]*?>)/g, function (a, b, c, d) {
return b + 'style_replace' + d;
});
}
function removeTagsExcludeA (str) {
return str.replace(/<\/?((?!a)(\w+))\s*[\w\W]*?>/g, '');
}
function removeAllTags (str) {
return str.replace(/<\/?(\w+)\s*[\w\W]*?>/g, '');
}
注意:您应该在背面做一些关于xss过滤器的工作,因为此解决方案无法过滤像&#39;&lt;&lt;&gt;&gt;&#39;
这样的字符串答案 13 :(得分:2)
这对我有用:
function onPasteMe(currentData, maxLen) {
// validate max length of pasted text
var totalCharacterCount = window.clipboardData.getData('Text').length;
}
<input type="text" onPaste="return onPasteMe(this, 50);" />
答案 14 :(得分:1)
$('#dom').on('paste',function (e){
setTimeout(function(){
console.log(e.currentTarget.value);
},0);
});
答案 15 :(得分:1)
让浏览器像往常一样在其内容可编辑div中粘贴,然后在粘贴交换后,将任何用于自定义文本样式的span元素与文本本身交换。这似乎在Internet Explorer和我尝试过的其他浏览器中都可以正常工作......
$('[contenteditable]').on('paste', function (e) {
setTimeout(function () {
$(e.target).children('span').each(function () {
$(this).replaceWith($(this).text());
});
}, 0);
});
此解决方案假设您正在运行 jQuery ,并且您不希望在任何内容可编辑div中使用文本格式。
优点是它非常简单。
答案 16 :(得分:1)
您可以这样做:
将这个jQuery插件用于pre&amp;贴后事件:
$.fn.pasteEvents = function( delay ) {
if (delay == undefined) delay = 20;
return $(this).each(function() {
var $el = $(this);
$el.on("paste", function() {
$el.trigger("prepaste");
setTimeout(function() { $el.trigger("postpaste"); }, delay);
});
});
};
现在你可以使用这个插件;
$('#txt').on("prepaste", function() {
$(this).find("*").each(function(){
var tmp=new Date.getTime();
$(this).data("uid",tmp);
});
}).pasteEvents();
$('#txt').on("postpaste", function() {
$(this).find("*").each(function(){
if(!$(this).data("uid")){
$(this).removeClass();
$(this).removeAttr("style id");
}
});
}).pasteEvents();
<强>释强>
首先将所有现有元素的uid设置为数据属性。
然后比较POST PASTE事件的所有节点。因此,通过比较,您可以识别新插入的一个,因为它们将具有uid,然后只需从新创建的元素中删除style / class / id属性,以便您可以保留旧的格式。
答案 17 :(得分:1)
function myFunct( e ){
e.preventDefault();
var pastedText = undefined;
if( window.clipboardData && window.clipboardData.getData ){
pastedText = window.clipboardData.getData('Text');
}
else if( e.clipboardData && e.clipboardData.getData ){
pastedText = e.clipboardData.getData('text/plain');
}
//work with text
}
document.onpaste = myFunct;
答案 18 :(得分:1)
简单的解决方案:
document.onpaste = function(e) {
var pasted = e.clipboardData.getData('Text');
console.log(pasted)
}
答案 19 :(得分:0)
这是上面发布的现有代码,但我已经为IE更新了它,错误是当选择现有文本并粘贴时不会删除所选内容。这已通过以下代码修复
selRange.deleteContents();
请参阅下面的完整代码
$('[contenteditable]').on('paste', function (e) {
e.preventDefault();
if (window.clipboardData) {
content = window.clipboardData.getData('Text');
if (window.getSelection) {
var selObj = window.getSelection();
var selRange = selObj.getRangeAt(0);
selRange.deleteContents();
selRange.insertNode(document.createTextNode(content));
}
} else if (e.originalEvent.clipboardData) {
content = (e.originalEvent || e).clipboardData.getData('text/plain');
document.execCommand('insertText', false, content);
}
});
答案 20 :(得分:0)
当用户通过浏览器的用户界面发起“粘贴”操作时会触发粘贴事件。
HTML
<div class="source" contenteditable="true">Try copying text from this box...</div>
<div class="target" contenteditable="true">...and pasting it into this one</div>
JavaScript
const target = document.querySelector('div.target');
target.addEventListener('paste', (event) => {
let paste = (event.clipboardData || window.clipboardData).getData('text');
paste = paste.toUpperCase();
const selection = window.getSelection();
if (!selection.rangeCount) return false;
selection.deleteFromDocument();
selection.getRangeAt(0).insertNode(document.createTextNode(paste));
event.preventDefault();
});