[jquery] Catch paste input

I'm looking for a way to sanitize input that I paste into the browser, is this possible to do with jQuery?

I've managed to come up with this so far:

$(this).live(pasteEventName, function(e) {
 // this is where i would like to sanitize my input
 return false;
}

Unfortunately my development has come to a screeching hold because of this "minor" issue. I would really make me a happy camper if someone could point me to the right direction.

This question is related to jquery paste sanitize

The answer is


This method uses jqueries contents().unwrap().

  1. First, detect the paste event
  2. Add a unique class to the tags that are already in the element into which we are pasting.
  3. After a given timeout scan through all the contents unwrapping tags that don't have the class that you set earlier. Note: This method does not remove self closing tags like
    See an example below.

    //find all children .find('*') and add the class .within .addClass("within") to all tags
    $('#answer_text').find('*').each(function () {
    $(this).addClass("within");
    });
    setTimeout(function() {
    $('#answer_text').find('*').each(function () {
        //if the current child does not have the specified class unwrap its contents
        $(this).not(".within").contents().unwrap();
    });
    }, 0);
    

Listen for the paste event and set a keyup event listener. On keyup, capture the value and remove the keyup event listener.

$('.inputTextArea').bind('paste', function (e){
    $(e.target).keyup(getInput);
});
function getInput(e){
    var inputText = $(e.target).val();
    $(e.target).unbind('keyup');
}

This is getting closer to what you might want.

function sanitize(s) {
  return s.replace(/\bfoo\b/g, "~"); 
};

$(function() {
 $(":text, textarea").bind("input paste", function(e) {
   try {
     clipboardData.setData("text",
       sanitize(clipboardData.getData("text"))
     );
   } catch (e) {
     $(this).val( sanitize( $(this).val() ) );
   }
 });
});

Please note that when clipboardData object is not found (on browsers other then IE) you are currently getting the element's full value + the clipboard'ed value.

You can probably do some extra steps to dif the two values, before an input & after the input, if you really are only after what data was truly pasted into the element.


$("#textboxid").on('input propertychange', function () {
    //perform operation
        });

It will work fine.


You can actually grab the value straight from the event. Its a bit obtuse how to get to it though.

Return false if you don't want it to go through.

$(this).on('paste', function(e) {

  var pasteData = e.originalEvent.clipboardData.getData('text')

});

How about comparing the original value of the field and the changed value of the field and deducting the difference as the pasted value? This catches the pasted text correctly even if there is existing text in the field.

http://jsfiddle.net/6b7sK/

function text_diff(first, second) {
    var start = 0;
    while (start < first.length && first[start] == second[start]) {
        ++start;
    }
    var end = 0;
    while (first.length - end > start && first[first.length - end - 1] == second[second.length - end - 1]) {
        ++end;
    }
    end = second.length - end;
    return second.substr(start, end - start);
}
$('textarea').bind('paste', function () {
    var self = $(this);
    var orig = self.val();
    setTimeout(function () {
        var pasted = text_diff(orig, $(self).val());
        console.log(pasted);
    });
});

This code is working for me either paste from right click or direct copy paste

   $('.textbox').on('paste input propertychange', function (e) {
        $(this).val( $(this).val().replace(/[^0-9.]/g, '') );
    })

When i paste Section 1: Labour Cost it becomes 1 in text box.

To allow only float value i use this code

 //only decimal
    $('.textbox').keypress(function(e) {
        if(e.which == 46 && $(this).val().indexOf('.') != -1) {
            e.preventDefault();
        } 
       if (e.which == 8 || e.which == 46) {
            return true;
       } else if ( e.which < 48 || e.which > 57) {
            e.preventDefault();
      }
    });

For cross platform compatibility, it should handle oninput and onpropertychange events:

$ (something).bind ("input propertychange", function (e) {
    // check for paste as in example above and
    // do something
})

See this example: http://www.p2e.dk/diverse/detectPaste.htm

It essentialy tracks every change with oninput event and then checks if it’s a paste by string comparison. Oh, and in IE there’s an onpaste event. So:

$ (something).bind ("input paste", function (e) {
    // check for paste as in example above and
    // do something
})

This proved to be quite illusive. The value of the input is not updated prior to the execution of the code inside the paste event function. I tried calling other events from within the paste event function but the input value is still not updated with the pasted text inside the function of any events. That is all events apart from keyup. If you call keyup from within the paste event function you can sanitize the pasted text from within the keyup event function. like so...

$(':input').live
(
    'input paste',
    function(e)
    {
        $(this).keyup();
    }
);

$(':input').live
(
    'keyup',
    function(e)
    {
        // sanitize pasted text here
    }
);

There is one caveat here. In Firefox, if you reset the input text on every keyup, if the text is longer than the viewable area allowed by the input width, then resetting the value on every keyup breaks the browser functionality that auto scrolls the text to the caret position at the end of the text. Instead the text scrolls back to the beginning leaving the caret out of view.


There is one caveat here. In Firefox, if you reset the input text on every keyup, if the text is longer than the viewable area allowed by the input width, then resetting the value on every keyup breaks the browser functionality that auto scrolls the text to the caret position at the end of the text. Instead the text scrolls back to the beginning leaving the caret out of view.

function scroll(elementToBeScrolled) 
{
     //this will reset the scroll to the bottom of the viewable area. 
     elementToBeScrolled.topscroll = elementToBeScrolled.scrollheight;
}

 $('').bind('input propertychange', function() {....});                      

This will work for mouse paste event.


document.addEventListener('paste', function(e){
    if(e.clipboardData.types.indexOf('text/html') > -1){
        processDataFromClipboard(e.clipboardData.getData('text/html'));
        e.preventDefault();

        ...
    }
});

Further:


Script to remove special characters from all fields with class portlet-form-input-field:

// Remove special chars from input field on paste
jQuery('.portlet-form-input-field').bind('paste', function(e) {
    var textInput = jQuery(this);
    setTimeout(function() {
        textInput.val(replaceSingleEndOfLineCharactersInString(textInput.val()));
    }, 200);
});

function replaceSingleEndOfLineCharactersInString(value) {
    <%
        // deal with end-of-line characters (\n or \r\n) that will affect string length calculation,
        // also remove all non-printable control characters that can cause XML validation errors
    %>
    if (value != "") {
        value = value.replace(/(\x00|\x01|\x02|\x03|\x04|\x05|\x06|\x07|\x08|\x0B|\x0C|\x0E|\x0F|\x10|\x11|\x12|\x13|\x14|\x15|\x16|\x17|\x18|\x19|\x1A|\x1B|\x1C|\x1D|\x1E|\x1F|\x7F)/gm,'');
        return value = value.replace(/(\r\n|\n|\r)/gm,'##').replace(/(\#\#)/gm,"\r\n");
    }
}

Hmm... I think you can use e.clipboardData to catch the data being pasted. If it doesn't pan out, have a look here.

$(this).live("paste", function(e) {
    alert(e.clipboardData); // [object Clipboard]
});

OK, just bumped into the same issue.. I went around the long way

$('input').on('paste', function () {
  var element = this;
  setTimeout(function () {
    var text = $(element).val();
    // do something with text
  }, 100);
});

Just a small timeout till .val() func can get populated.

E.