web-dev-qa-db-fra.com

javascript couper/copier/coller dans le presse-papier: comment Google l'a-t-il résolu?

Oui, cette question a été posée encore et encore: comment copier et coller du presse-papiers dans le système avec javascript? Je n'ai trouvé que des solutions partielles et des bidouilles jusqu'ici ... La raison pour laquelle on l'a demandé si souvent dans le passé est qu'il n'y a toujours pas de solution efficace. Cependant, j’ai vu que Google Docs dispose actuellement d’une solution efficace pour les événements clavier ainsi que pour les boutons. Alors, c'est possible, mais comment font-ils? L'article de Software Salad, Accéder au Presse-papiers système avec JavaScript - Un Saint Graal? , Donne un bon aperçu du problème (mais il date de quelques années).

En bref:

  • vous pouvez utiliser les événements de clavier ctrl + x, ctrl + c, ctrl + v pour copier du texte à partir d'une zone de texte masquée avec des données préparées, ou pour intercepter du texte collé dans un champ masqué, puis y remédier

  • vous pouvez utiliser du piratage via Flash ou peut-être une applet Java pour copier quelque chose dans le presse-papiers du système sans nécessiter l'approbation de l'utilisateur.

  • vous pouvez utiliser une "vraie" solution avec clipboardData.setData pour IE et execCommand pour d'autres navigateurs, ce qui dépend de l'approbation de l'utilisateur.

Avez-vous une idée de la façon dont Google a résolu le problème du presse-papiers?

22
Jos de Jong

[Note: Cette réponse était exacte au moment de sa rédaction et a répondu correctement à la question du PO. Cependant, la technologie a évolué depuis lors; si vous souhaitez prendre en charge le copier-coller dans votre application Web, veuillez consulter les autres réponses plus récentes sur cette page. —Ruakh]


Cependant, j’ai vu que Google Docs dispose actuellement d’une solution efficace pour les événements clavier ainsi que pour les boutons.

Non, ça ne va pas. Pas vraiment. Pour les événements de clavier, Google Documents ne fait rien. cela ne fonctionne tout simplement pas bloque la fonctionnalité copier-coller par défaut du navigateur; ainsi, les utilisateurs peuvent copier et coller librement sans que Google Docs ne soit gênant. Pour les boutons, Google Docs ne prend pas en charge le presse-papiers système, mais son propre "Presse-papiers Web", entièrement intégré à Google Docs. Vous ne pouvez pas utiliser les boutons de la barre d'outils pour copier du texte à coller dans un autre programme de votre ordinateur ni pour coller du texte copié à partir d'un autre programme de votre ordinateur.

Pour plus d'informations à ce sujet, voir "Copier et coller dans Google Documents" . (C'est orienté utilisateur plutôt que développeur, mais il fait un travail décent en précisant ce qui est et ce qui n'est pas supporté.)

10
ruakh

Je sais que cette question a été postée il y a longtemps, mais je devais vérifier comment Google le fait, alors peut-être que quelqu'un trouvera cela utile.

En fait, Google utilise également le presse-papiers du système, mais c’est un peu délicat. Si vous utilisez un raccourci clavier, vous pouvez capturer un événement copier/coller/couper, par exemple. la fenêtre:

window.addEventListener('copy', function (ev) {
    console.log('copy event');
    // you can set clipboard data here, e.g.
    ev.clipboardData.setData('text/plain', 'some text pushed to clipboard');
    // you need to prevent default behaviour here, otherwise browser will overwrite your content with currently selected 
    ev.preventDefault();
});

exemple live de raccourci clavier: http://jsfiddle.net/tyk9U/

Malheureusement, ceci n’est qu’une solution pour les raccourcis clavier et il existe un problème avec le menu contextuel, car vous ne pouvez pas accéder aux données du Presse-papiers sans événement copier/couper/coller natif (de confiance). Mais Google fait un truc intéressant. Il existe une API document.execCommand() qui vous permet d'exécuter des commandes pour l'élément contenteditable et une commande 'copy' que vous pouvez déclencher via document.execCommand('copy'). Mais lorsque vous essayez ceci dans la console sous Chrome, il retourne false. J'ai passé un peu de temps à étudier cela et il s'est avéré qu'ils avaient l'extension Chrome installée, appelée "Google Drive" (allez à chrome: // apps/et vous pouvez la voir ici) qui permet l'accès au presse-papiers pour les domaines drive.google. com et docs.google.com. Ouvrez un document ou une feuille de calcul et tapez console document.execCommand('copy') - il retournera true. Lorsque vous désinstallez l'extension, vous ne pourrez plus utiliser les opérations du presse-papiers à partir du menu contextuel.

Vous pouvez créer cette application pour vous-même avec un fichier manifeste très simple (détails ici https://developer.chrome.com/apps/first_app ):

{
    "manifest_version": 2,
    "name": "App name",
    "description": "App description",
    "version": "1.0",
    "app": {
        "urls": [
            "http://your.app.url.here/"
        ],
        "launch": {
            "web_url": "http://your.app.url.here/"
        }
    },
    "icons": {
        "128": "x-128.png"
    },
    "permissions": [
        "clipboardRead",
        "clipboardWrite"
    ]
}

Le champ "permissions" permet ici les opérations dans le presse papier.

Maintenant, lorsque cette option est activée, vous pouvez utiliser document.execCommand('copy') et cela fonctionnera (vous renverrez true). Mais ce n’est pas tout - document.execCommand('copy') dans Chrome déclenche un événement de copie et vous pouvez l’attraper avec le même code que celui utilisé pour intercepter les raccourcis du presse-papiers du clavier. C'est maintenant Google le fait.

Bien entendu, cette description n’est valable que pour Chrome.

25
Mateusz W

En complément de ce que d’autres ont déjà publié dans ce fil de discussion, j’ai créé un exemple pleinement fonctionnel qui illustre l’approche des raccourcis clavier (CTRL + C ou CMD + C sous Mac OS X) ainsi que l’approche des boutons personnalisés qui déclenchent l’action de copie. 

La démo complète peut être trouvée ici: http://jsfiddle.net/rve7d/

J'ai trouvé la réponse de Mateusz W très utile lorsque j'essayais de créer cette démo, mais il n'a pas pris en compte la prise en charge de IE, qui se comporte légèrement différemment et utilise différents types de données comme premier paramètre.

if(window.clipboardData) {
    // use just 'Text' or 'Url' as a first param otherwise strange exception is thrown
    window.clipboardData.setData('Text', 'Text that will be copied to CB');        
} else if(ev.originalEvent.clipboardData) {
    ev.originalEvent.clipboardData.setData('text/plain', 'Text that will be copied to CB');      
} else {
    alert('Clipboard Data are not supported in this browser. Sorry.');
}

PS: J'avais besoin de cette fonctionnalité pour notre composant personnalisé Spreadsheet View et, en cours de route, j'ai analysé le code source de Google Spreadsheets afin que ma solution soit généralement conforme à leur solution.

4
Marek Suscak

Le google utilise une méthode très simple mais cool. En utilisant firebug, vous saurez que le code html chargé a une zone de texte dont le début commence par la taille 1. Ce que Google Doc fait, c'est que lorsque l'utilisateur sélectionne du texte et appuie sur ctrl + c, il capture l'événement le texte qui est sélectionné dans le conteneur de documents et définit la valeur de zone de texte sur ce contenu. Puis il se concentre et sélectionne la zone de texte. Maintenant, il libère l'événement ctrl + c. Mais maintenant, le texte est sélectionné dans la zone de texte. Ainsi, lorsque l'événement est publié, le navigateur copie le texte dans la zone de texte et nous obtenons ainsi le texte copié.

3
coder hacker
<p>COPY : </p>
<p>Email me at <a class="js-emaillink" href="mailto:[email protected]">[email protected]</a></p>
<p><button class="js-emailcopybtn" value="clipboard" >clipboard</button></p>
<textarea rows="10" cols = "12"></textarea>
<p>CUT: </p>
<p><textarea class="js-cuttextarea">Hello I'm some text</textarea></p>
<p><button class="js-textareacutbtn" disable>Cut Textarea</button></p>
<script>
//copy clipboard
var copyEmailBtn = document.querySelector('.js-emailcopybtn');
copyEmailBtn.addEventListener('click', function(event) {
  // Выборка ссылки с электронной почтой
  var emailLink = document.querySelector('.js-emaillink');
  var range = document.createRange();
  range.selectNode(emailLink);
  window.getSelection().addRange(range);
  try {
    // Теперь, когда мы выбрали текст ссылки, выполним команду копирования
    var successful = document.execCommand('copy');
    var msg = successful ? 'successful' : 'unsuccessful';
    console.log('Copy email command was ' + msg);
  } catch(err) {
    console.log('Oops, unable to copy');
  }
  // Снятие выделения - ВНИМАНИЕ: вы должны использовать
  // removeRange(range) когда это возможно
  window.getSelection().removeAllRanges();
});
//cut
var cutTextareaBtn = document.querySelector('.js-textareacutbtn');
cutTextareaBtn.addEventListener('click', function(event) {
  var cutTextarea = document.querySelector('.js-cuttextarea');
  cutTextarea.select();
  try {
    var successful = document.execCommand('cut');
    var msg = successful ? 'successful' : 'unsuccessful';
    console.log('Cutting text command was ' + msg);
  } catch(err) {
    console.log('Oops, unable to cut');
  }
});
</script>
0
zloctb