Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Capture Document-level Paste event without focused Input or Textarea

<!DOCTYPE html>
<html>
<head>
    <title>Clipboard Paste Text</title>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script> 
    <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js"></script> 
</head>
<body>
    <input type="text" placeholder="paste in here" />
    <script type="text/javascript">
    /* <![CDATA[ */
    $(document, 'input[type="text"]').on('paste', function(event) {
        var oEvent = event.originalEvent;
        oEvent.preventDefault();

        var clipText = '';
        if(window.clipboardData){
            clipText = window.clipboardData.getData('Text');
        }else if(typeof oEvent == 'object' && oEvent.clipboardData){
            clipText = oEvent.clipboardData.getData('text/plain');
        }

        // console.log('Pasted ' + clipText.length + ' characters.');
        alert('Pasted ' + clipText.length + ' characters.');
    });
    /* ]]> */
    </script>
</body>
</html>

^ I have this demo code. It binds the paste event on INPUT[TEXT] and DOCUMENT.

  • In Google Chrome (and Opera 15+), a Ctrl+V with no caret (outside input and textarea) is captured.
  • In IE and Firefox, a Ctrl+V outside a paste-able object (input and textarea) is not captured.
    (but binding the document paste event captures paste event for all inputs and textareas.)

Is this proper behavior? Is my JS correct?

I'd like to capture Ctrl+V without a input textbox in all three browsers. I'm using a text input now but I'd like to remove it completely and capture the event at document level, not at input box level. Can it be done?

PS: I need to paste large amounts of text that hog the browser if pasted in a textarea. I'm storing it in a hidden field by capturing the paste event in a inputbox. My current solution works properly but I'm still wondering if I'm missing something or FF and IE will only trigger paste events at input/textarea level.

PPS: I've already used the spellcheck=false and autocomplete=off trick to allow more text pasted... but it still hangs for a bit, and as I don't need it editable, this is a better solution.

PPS: My JS skills are rather rusty (they are more like a JS survival mode) and I have no worries for browser backward compatibility as those who'll use this update often and hard.

Made a jsfiddle: http://jsfiddle.net/ninty9notout/A42UN/

like image 978
CodeAngry Avatar asked Aug 25 '13 13:08

CodeAngry


1 Answers

From http://www.w3.org/TR/clipboard-apis/ 5.1.3 paste event

The paste event has no default action in a non-editable context, but the event fires regardless.

Chrome uses a lazy paste event, which means that it doesn't check to see if the focused element is an editable content area, which is why the paste event works on the document.

As for firefox and IE, it actually checks the element before letting allowing the paste event to be fired. So basically, you need an content editable element in order for the paste event to work in all browsers.

I played around with using a content editable DIV as the main div on the page and I think it seems to produce the results you are looking for. Forgive me if the answer seems somewhat "hackish".

You can place a contenteditable div as the container div to the rest of your webpage and not allow a user to type into the div by returning false when the user presses a key, unless it's a key for pasting.

Here is a fiddle if you want to see how I did it.

http://jsfiddle.net/NVqQ7/3/

html

<div id="pageDiv" contenteditable><div>other content</div></div>

css

html, body, #pageDiv {
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
}

javascript:

$(document).on('paste', function(event){
    var oEvent = event.originalEvent;
    if (event.preventDefault())
        event.preventDefault();

    var clipText = '';
    if(window.clipboardData){
        clipText = window.clipboardData.getData('Text');
    }else if(typeof oEvent == 'object' && oEvent.clipboardData){
        clipText = oEvent.clipboardData.getData('text/plain');
    }

    // console.log('Pasted ' + clipText.length + ' characters.');
    alert('Pasted ' + clipText.length + ' characters.');
});

$('#pageDiv').keydown(function(e){
    if (!event.ctrlKey)
        return false;
});

A few notes:

  1. The user still must click on the body of the page in order to activate the paste event. i.e. clicking on the browser by itself may not be enough.

  2. In firfox, you need to set the contenteditable="false" in child divs, otherwise users can add text to those elements.

  3. I had to make the div height and width 100%. If your html and body are not 100% height and width, it will not work in IE.

  4. I had to change the jquery library to a newer version for IE in order for the paste event to work on the document.

Hope this helps

like image 140
Rylonian Avatar answered Sep 30 '22 06:09

Rylonian