Catch coller l'entrée

210

Je cherche un moyen de filtrer les entrées que je colle dans le navigateur, est-ce possible avec jQuery?

J'ai réussi à trouver cela jusqu'à présent:

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

Malheureusement, mon développement est arrivé à un point d'arrêt à cause de ce problème "mineur". Je ferais vraiment de moi un campeur heureux si quelqu'un pouvait m'orienter dans la bonne direction.

Christoffer Winterkvist
la source
6
Veuillez marquer stackoverflow.com/a/1503425/749232 comme réponse à l'usage d'autres personnes rencontrant le même problème. Cela m'a résolu.
saji89
2
.live () est obsolète à partir de jquery 1.9, ils recommandent plutôt .on ()
Sameer Alibhai

Réponses:

337

OK, je suis juste tombé sur le même problème .. J'ai parcouru le long chemin

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

Juste un petit timeout jusqu'à ce que func .val () puisse être rempli.

E.

Evgeni Dimov
la source
20
Que faire s'il y a déjà du texte dans la zone de texte et que vous collez, et que vous vouliez simplement le texte collé?
barfoon le
39
Fonctionne parfaitement, merci. Un timeout de 0 fonctionne aussi bien. Il suffit de reporter la fonction à la boucle suivante.
Daniel Lewis
4
Je viens d'être dans une situation similaire. Le délai est là car l'événement de collage n'est pas immédiat, mais il faut quelques millisecondes pour que le contenu du presse-papiers soit collé.
James
8
@ user563811: Notez simplement que le délai minimum officiel est de 4 ms en HTML5.
pimvdb le
4
Comme le dit Sharif, 0 ms place toujours l'événement au bas de la pile.
BobRodes
67

Vous pouvez réellement saisir la valeur directement de l' événement . C'est un peu obtus comment y arriver.

Retournez false si vous ne voulez pas que cela passe.

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

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

});
Charles Haro
la source
2
C'est la voie à suivre
DdW
1
ie 11: window.clipboardData.getData ('text')
Wallstrider
4
Cependant, notez que le besoin de la propriété "originalEvent" n'est nécessaire que si vous gérez l'événement avec jQuery. Vous pouvez le faire simplement e.clipboardData.getData('text')en JavaScript.
Asier Paz
Meilleure réponse ici! Mais - j'ai trouvé étrange que la version abrégée de la liaison ne fonctionne pas avec cela, c'est-à-dire une erreur si j'essaye ceci: $ (this) .paste (function (e) {...}) ;, even bien que cela fonctionne pour le short-handing .on ('click'), etc.
HoldOffHunger
niggle: il manque un paren de fermeture au code. Apparemment, le changement est trop petit pour me permettre de le corriger en tant que montage.
Joachim Lous
42

Pour la compatibilité multiplateforme, il doit gérer les événements oninput et onpropertychange:

$ (something).bind ("input propertychange", function (e) {
    // check for paste as in example above and
    // do something
})
Xue Liangliang
la source
2
Belle solution qui fonctionne à la fois pour la capture d'événements de collage et de saisie. Remarque: Cela provoque le déclenchement de la fonction d'événement deux fois pour une raison quelconque si vous mettez en surbrillance le contenu d'entrée , puis tapez quelque chose dans au moins IE8 (pas important dans de nombreux cas, mais peut-être très important dans d'autres).
baacke
Agréable ! Je ne connaissais pas celui-ci, et il correspond parfaitement à mes besoins!
Marc Brillault
18

Je l'ai en quelque sorte corrigé en utilisant le code suivant:

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

Maintenant, j'ai juste besoin de stocker l'emplacement du curseur et de l'ajouter à cette position, alors je suis prêt ...

Christoffer Winterkvist
la source
1
Comment avez-vous enregistré l'emplacement du curseur?
Petah
@Petah Vous pouvez vérifier quel élément a le focus .find(':focus')et savoir que cet élément détermine l'emplacement du curseur pour lui. Regardez ça .
Jacob
Rappelez-vous que "live" est déconseillé au profit de "on"
NBPalomino
inputfait la différence :) Je les ai normalement dans mes événements de zone de texte, keyup keydown paste inputmais cela dépend évidemment de vos motivations
Pierre
10

Hmm ... Je pense que vous pouvez utiliser e.clipboardDatapour attraper les données collées. Si cela ne fonctionne pas, jetez un œil ici .

$(this).live("paste", function(e) {
    alert(e.clipboardData); // [object Clipboard]
});
moff
la source
2
Lorsque je lance ceci dans Safari, je reçois 'undefined' :(
Christoffer Winterkvist
1
clipboardData est mis en sandbox sur la plupart des navigateurs (trou de sécurité évident.)
podperson
2
Internet Explorer uniquement!
Lodewijk
9

Écoutez l'événement coller et définissez un écouteur d'événement keyup. À la clé, capturez la valeur et supprimez l'écouteur d'événement de clé.

$('.inputTextArea').bind('paste', function (e){
    $(e.target).keyup(getInput);
});
function getInput(e){
    var inputText = $(e.target).val();
    $(e.target).unbind('keyup');
}
Eric
la source
6
C'est très bien, mais cela ne fonctionne pas pour le collage par clic droit.
Joseph Ravenwolfe
cela ne fonctionne pas non plus pour le collage par clic moyen (X11), cela ne fonctionne que s'ils ont utilisé le clavier pour coller.
Jasen
7
$("#textboxid").on('input propertychange', function () {
    //perform operation
        });

Cela fonctionnera bien.

Rajat Jain
la source
6

Cela se rapproche de ce que vous pourriez souhaiter.

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() ) );
   }
 });
});

Veuillez noter que lorsque l'objet clipboardData n'est pas trouvé (sur les navigateurs autres qu'IE), vous obtenez actuellement la valeur complète de l'élément + la valeur du presse-papiers.

Vous pouvez probablement faire quelques étapes supplémentaires pour dif les deux valeurs, avant une entrée et après l'entrée, si vous êtes vraiment seulement après quelles données ont vraiment été collées dans l'élément.

Monsieur chanceux
la source
6
 $('').bind('input propertychange', function() {....});                      

Cela fonctionnera pour l'événement de collage de souris.

Abhiram
la source
2
C'est le meilleur usage de tous.
Sinan Eldem
5

Que diriez-vous de comparer la valeur d'origine du champ et la valeur modifiée du champ et de déduire la différence comme valeur collée? Cela capture le texte collé correctement même s'il existe du texte dans le champ.

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
la source
5

Ce code fonctionne pour moi, soit coller à partir du clic droit, soit copier coller directement

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

Quand je le colle, Section 1: Labour Costil devient 1dans la zone de texte.

Pour autoriser uniquement la valeur flottante, j'utilise ce 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
la source
4
document.addEventListener('paste', function(e){
    if(e.clipboardData.types.indexOf('text/html') > -1){
        processDataFromClipboard(e.clipboardData.getData('text/html'));
        e.preventDefault();

        ...
    }
});

Plus loin:

davidcondrey
la source
text / html n'est pas valide, seulement l'url et le texte.
Mike
@Mike J'ai copié l'extrait directement de la documentation référencée.
davidcondrey
J'ai essayé ça pendant environ une journée. text / html ne fonctionnerait jamais. J'ai fini par ajouter un délai d'expiration de 0 et j'ai pu récupérer le code HTML de la div où ils collaient. Si quelqu'un avait un violon fonctionnel, cela aiderait. Peut-être que je le fais mal ...
Mike
3

Voir cet exemple: http://www.p2e.dk/diverse/detectPaste.htm

Il suit essentiellement chaque changement avec un événement oninput, puis vérifie s'il s'agit d'une comparaison de collage par chaîne. Oh, et dans IE, il y a un événement onpaste. Alors:

$ (something).bind ("input paste", function (e) {
    // check for paste as in example above and
    // do something
})
Ilya Birman
la source
Il est donc impossible d'obtenir simplement le texte de collage lorsque l'événement se produit?
Christoffer Winterkvist
Eh bien, je suppose que vous devrez y faire face vous-même, comme comparer l'avant et l'après. Cela doit être assez facile. Mais pourquoi ne revalidez-vous pas simplement l'entrée entière? Lent?
Ilya Birman
Je pensais juste que ce serait possible mais je suppose que non. En ce moment, j'essaie une autre méthode en la collant dans une zone de texte puis en la transférant vers sa destination finale. J'espère que cela fonctionnera.
Christoffer Winterkvist
Il vous suffit de trouver le fragment de correspondance maximum au début de deux chaînes (avant et après). Tout à partir de là et jusqu'à la différence de longueur est le texte collé.
Ilya Birman
@IlyaBirman non, ce n'est pas le cas: par exemple, le texte collé peut remplacer une partie (ou la totalité) de l'original
Jasen
1

Cette méthode utilise jqueries contents (). Unwrap ().

  1. Tout d'abord, détectez l'événement coller
  2. Ajoutez une classe unique aux balises qui sont déjà dans l'élément dans lequel nous collons.
  3. Après un délai donné, parcourez toutes les balises de déballage du contenu qui n'ont pas la classe que vous avez définie plus tôt. Remarque: Cette méthode ne supprime pas les balises à fermeture automatique comme
    voir un exemple ci-dessous.

    //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
la source
Certainement la meilleure réponse, la plus courte et la plus parlante jamais vue !!! Merci beaucoup, vous avez fait ma journée;)
webprogrammer
0

Cela s'est révélé assez illusoire. La valeur de l'entrée n'est pas mise à jour avant l'exécution du code à l'intérieur de la fonction d'événement coller. J'ai essayé d'appeler d'autres événements à partir de la fonction d'événement de collage, mais la valeur d'entrée n'est toujours pas mise à jour avec le texte collé dans la fonction des événements. C'est tous les événements à l'exception de keyup. Si vous appelez keyup depuis la fonction d'événement coller, vous pouvez nettoyer le texte collé depuis la fonction d'événement keyup. ainsi...

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

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

Il y a une mise en garde ici. Dans Firefox, si vous réinitialisez le texte d'entrée à chaque saisie, si le texte est plus long que la zone visible autorisée par la largeur d'entrée, la réinitialisation de la valeur à chaque saisie interrompt la fonctionnalité du navigateur qui fait défiler automatiquement le texte jusqu'à la position du curseur au fin du texte. Au lieu de cela, le texte revient au début, laissant le curseur hors de vue.


la source
onpaste est appelé avant que le contenu ne soit collé. Vous avez besoin d'un délai temporisé d'au moins 4 ms pour créer votre propre fonction de post-collage, pour laver les résultats de la pâte.
DragonLord
-1

Script pour supprimer les caractères spéciaux de tous les champs avec la classe 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");
    }
}
Alex le cuisinier
la source
2
Pourriez-vous s'il vous plaît ajouter une description de la désinfection pertinente et pourquoi cela peut aider à résoudre le problème de l'affiche? Le simple fait de fournir un bloc de code n'aide pas vraiment l'OP (ou les futurs chercheurs) à comprendre comment résoudre le problème - il encourage simplement à copier / coller du code mal compris.
Troy Alford
-2

Il y a une mise en garde ici. Dans Firefox, si vous réinitialisez le texte d'entrée à chaque saisie, si le texte est plus long que la zone visible autorisée par la largeur d'entrée, la réinitialisation de la valeur à chaque saisie interrompt la fonctionnalité du navigateur qui fait défiler automatiquement le texte jusqu'à la position du curseur au fin du texte. Au lieu de cela, le texte revient au début, laissant le curseur hors de vue.

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