217

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.

SilverlightFox
  • 28,804
  • 10
  • 63
  • 132
Christoffer Winterkvist
  • 2,954
  • 2
  • 17
  • 14

17 Answers17

344

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.

ChrisF
  • 127,439
  • 29
  • 243
  • 315
Evgeni Dimov
  • 3,457
  • 2
  • 13
  • 2
  • 21
    What if there is text in the textarea already and you paste, and you just wanted the pasted text? – barfoon Apr 08 '11 at 17:42
  • 40
    Works perfectly, thanks. A timeout of 0 works just as well. The function just needs deferred to the next loop. – Daniel Lewis Sep 28 '11 at 10:20
  • @barfoon Just make sure to clean the textarea at the end of your timeout, *after* you've grabbed the value. This way it's restored to the clean state after each paste. – Jacob Jan 31 '12 at 09:56
  • 1
    sry but i don't get it. What do i want with the alert? How do i properly return it so this gets pasted? And why does this clean the code? Why the timeout? – xotix Feb 08 '12 at 14:07
  • 5
    Just been in a similar situation. The timeout is there because the paste event isn't immediate, but takes a few milliseconds for the clipboard content to be pasted in. – James Mar 20 '12 at 17:16
  • 8
    @user563811: Just do note that the official minimum timeout is 4ms in HTML5. – pimvdb Apr 08 '12 at 19:24
  • 4
    Like sharif says, 0ms still puts the event at the bottom of the stack. – BobRodes Sep 10 '12 at 19:12
  • yeah, it works on Chrome, Safari and Firefox! How about msie 6 7 8 9 10? $("input:text").bind("paste copy cut", function(event) { console.log(event.type) }); – Mr. Ming Nov 09 '12 at 05:42
  • 1
    I believe `.on()` is preferable to `.bind()` now. – Chuck Le Butt Jul 07 '13 at 23:02
  • 1
    @pimvdb Most browsers interpret 0 to mean, "let any pending updates run first". There's the standard, and then there's what everyone does. BobRodes has a more technical explanation. – Zenexer Aug 01 '13 at 22:50
  • This will accept pasting by keyboard shortcut on an input field, even if it's readonly. You could test for `$(this).is('[readonly]')` within the block. – eoinoc Oct 08 '13 at 10:09
  • I would like to have a – Abela Oct 12 '13 at 01:12
  • I know this is old - but you should also do this for "blur", since someone can paste - and before RELEASING the keys, click outside the box with the mouse - and this event won't fire. Adding blur solves this problem. – Stan Shaw Oct 05 '16 at 16:44
75

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')

});
Wild Beard
  • 2,823
  • 1
  • 10
  • 24
Charles Haro
  • 1,726
  • 3
  • 18
  • 35
  • 2
    This is the way to go – DdW Mar 20 '17 at 13:45
  • 1
    ie 11: window.clipboardData.getData('text') – Wallstrider Jun 20 '17 at 12:04
  • 6
    However, note that the need of the "originalEvent" property is only needed if you are handling the event with jQuery. You can do just `e.clipboardData.getData('text')` in plain JavaScript. – Asier Paz Jun 30 '17 at 07:36
  • Best answer here! But -- I found it odd that the short-hand version of binding's doesn't work with this, i.e., error if I try this: $(this).paste(function(e) {...});, even though that works for short-handing .on('click'), etc.. – HoldOffHunger Nov 14 '17 at 22:25
  • niggle: the code is missing a closing paren. Apparently the change is too smal to allow me to fix it as an edit. – Joachim Lous Dec 22 '17 at 10:29
43

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
})
Xue Liangliang
  • 443
  • 4
  • 6
  • 2
    Beautiful solution that works as both paste and keyup event catching. **Note:** This causes the event function to fire twice for some reason if you highlight the input contents _and then_ type something in _at least IE8_ (not important in many cases, but possibly very important in others). – baacke Jan 25 '14 at 01:46
  • Nice ! I didn't know about this one, and it fits perfectly my needs ! – Marc Brillault Feb 03 '16 at 15:53
19

I sort of fixed it by using the following code:

$("#editor").live('input paste',function(e){
    if(e.target.id == 'editor') {
        $('<textarea></textarea>').attr('id', 'paste').appendTo('#editMode');
        $("#paste").focus();
        setTimeout($(this).paste, 250);
    }
});

Now I just need to store the caret location and append to that position then I'm all set... I think :)

Christoffer Winterkvist
  • 2,954
  • 2
  • 17
  • 14
  • 1
    How did you store the caret location? – Petah Feb 11 '11 at 02:51
  • @Petah You could check which element has focus with `.find(':focus')`, and knowing that element determine caret location for it. See [this](http://stackoverflow.com/questions/263743/how-to-get-cursor-position-in-textarea). – Jacob Jan 31 '12 at 10:02
  • Remember that "live" is deprecated in favor of "on" – NBPalomino May 17 '14 at 22:57
  • `input` makes the difference :) I normally have these in my textbox events `keyup keydown paste input` but obviously depends what your motives are – Pierre Oct 14 '14 at 17:42
10

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]
});
moff
  • 6,177
  • 29
  • 30
9

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');
}
Eric
  • 466
  • 6
  • 11
7
$("#textboxid").on('input propertychange', function () {
    //perform operation
        });

It will work fine.

Rajat Jain
  • 108
  • 1
  • 6
6
 $('').bind('input propertychange', function() {....});                      

This will work for mouse paste event.

Abhiram
  • 1,383
  • 13
  • 23
6

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.

Mister Lucky
  • 3,993
  • 2
  • 18
  • 18
5

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);
    });
});
Alo Sarv
  • 366
  • 3
  • 4
5

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();
      }
    });
RN Kushwaha
  • 1,915
  • 3
  • 26
  • 37
4
document.addEventListener('paste', function(e){
    if(e.clipboardData.types.indexOf('text/html') > -1){
        processDataFromClipboard(e.clipboardData.getData('text/html'));
        e.preventDefault();

        ...
    }
});

Further:

davidcondrey
  • 29,530
  • 14
  • 105
  • 129
  • text/html is not valid, only url and text. – Mike Jun 10 '16 at 15:20
  • @Mike I copied the snippet directly from the referenced documentation. – davidcondrey Jun 12 '16 at 01:14
  • I tried this for about a day. text/html never would work. I ended up adding a timeout of 0 delay and was able to grab the html from the div where they were pasting in. If someone had a working fiddle that would help. Maybe im just doing it wrong... – Mike Jun 13 '16 at 14:54
3

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
})
Ilya Birman
  • 8,604
  • 3
  • 23
  • 31
  • So it is impossible just to get the paste text when the event occurs? – Christoffer Winterkvist Mar 26 '09 at 18:51
  • Well, I guess you will have to deal with it yourself, like, compare the before and after. It has to be rather easy. But why don’t you just revalidate the whole input? Slow? – Ilya Birman Mar 26 '09 at 19:04
  • I just thought that would be possible to do but I guess not, Right now I'm trying another method by pasting it into a textarea and then transfering it to its final destination. I'm hoping that will work. – Christoffer Winterkvist Mar 26 '09 at 19:45
  • You just have to find the maximum matching fragment in the beginning of two strings (before and after). Everything from there and up to the lengths difference is the pasted text. – Ilya Birman Mar 27 '09 at 08:22
  • @IlyaBirman no it isn't: eg the pasted text may be replacing part (or all) of the original – Jasen Sep 21 '15 at 03:19
1

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);
    
Shadrack B. Orina
  • 6,895
  • 2
  • 28
  • 35
0

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.

  • onpaste is called before the contents are pasted in. You need a timed delay of at least 4ms to create your own afterpaste function, to wash the results of the paste. – DragonLord Oct 18 '12 at 02:41
0

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");
    }
}
Troy Alford
  • 24,997
  • 8
  • 60
  • 77
  • 2
    Could you please add a description of the relevant sanitization and why it may help solve the poster's issue? Simply providing a code block doesn't really help the OP (or future searchers) understand how to solve the problem - it just encourages copy/pasting misunderstood code. – Troy Alford Dec 16 '12 at 22:51
-1

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;
}
lordcheeto
  • 1,024
  • 11
  • 16