web-dev-qa-db-fra.com

Javascript - Copier la chaîne dans le presse-papiers en tant que texte / html

Existe-t-il un moyen en javascript pour copier une chaîne html (ie <b>xx<b>) dans le presse-papiers en tant que texte/html, de sorte qu'il puisse ensuite être collé dans, par exemple, un message gmail avec la mise en forme (par exemple, xx en gras)

Il existe des solutions pour copier dans le presse-papiers sous forme de texte (text/plain) par exemple https://stackoverflow.com/a/30810322/460084 mais pas sous forme de texte/html

J'ai besoin d'une solution non flash et non jquery qui fonctionnera au moins sur IE11 FF42 et Chrome.

Idéalement, je voudrais stocker les versions texte et html de la chaîne dans le presse-papiers afin que la bonne puisse être collée selon que la cible prend en charge html ou non.

22
kofifus

J'ai apporté quelques modifications à la réponse de Loilo ci-dessus:

  • la définition (et la restauration ultérieure) du focus sur la div cachée empêche FF d'entrer dans une récursivité sans fin lors de la copie à partir d'une zone de texte

  • définir la plage aux enfants intérieurs du div empêche chrome d'insérer un <br> supplémentaire au début

  • removeAllRanges sur getSelection () empêche l'ajout à la sélection existante (éventuellement non nécessaire)

  • essayer/rattraper execCommand

  • mieux cacher la copie div

Sous OSX, cela ne fonctionnera pas. Safari ne prend pas en charge execCommand et chrome OSX a un bogue connu https://bugs.chromium.org/p/chromium/issues/detail?id=552975

code:

clipboardDiv = document.createElement('div');
clipboardDiv.style.fontSize = '12pt'; // Prevent zooming on iOS
// Reset box model
clipboardDiv.style.border = '0';
clipboardDiv.style.padding = '0';
clipboardDiv.style.margin = '0';
// Move element out of screen 
clipboardDiv.style.position = 'fixed';
clipboardDiv.style['right'] = '-9999px';
clipboardDiv.style.top = (window.pageYOffset || document.documentElement.scrollTop) + 'px';
// more hiding
clipboardDiv.setAttribute('readonly', '');
clipboardDiv.style.opacity = 0;
clipboardDiv.style.pointerEvents = 'none';
clipboardDiv.style.zIndex = -1;
clipboardDiv.setAttribute('tabindex', '0'); // so it can be focused
clipboardDiv.innerHTML = '';
document.body.appendChild(clipboardDiv);

function copyHtmlToClipboard(html) {
  clipboardDiv.innerHTML=html;

  var focused=document.activeElement;
  clipboardDiv.focus();

  window.getSelection().removeAllRanges();  
  var range = document.createRange(); 
  range.setStartBefore(clipboardDiv.firstChild);
  range.setEndAfter(clipboardDiv.lastChild);
  window.getSelection().addRange(range);  

  var ok=false;
  try {
     if (document.execCommand('copy')) ok=true; else utils.log('execCommand returned false !');
  } catch (err) {
     utils.log('execCommand failed ! exception '+err);
  }

  focused.focus();
}

voir jsfiddle où vous pouvez entrer un segment html dans la zone de texte et copier dans le presse-papiers avec ctrl + c.

4
kofifus

Depuis que cette réponse a attiré l'attention, j'ai complètement réécrit l'original en désordre pour être plus facile à saisir. Si vous voulez regarder la version pré-révisée, vous pouvez la trouver ici .


La question résumée:

Puis-je utiliser JavaScript pour copier la sortie formatée d'un code HTML dans le presse-papiers des utilisateurs?


Réponse:

Oui, avec certaines limitations, vous le pouvez.


Solution:

Voici une fonction qui fera exactement cela. Je l'ai testé avec vos navigateurs requis, cela fonctionne dans chacun d'eux. Cependant, IE 11 demandera une confirmation sur cette action.

Vous trouverez ci-dessous une explication sur la façon dont cela fonctionne. Vous pouvez tester interactivement la fonction dans ce jsFiddle .

// This function expects an HTML string and copies it as rich text.

function copyFormatted (html) {
  // Create container for the HTML
  // [1]
  var container = document.createElement('div')
  container.innerHTML = html

  // Hide element
  // [2]
  container.style.position = 'fixed'
  container.style.pointerEvents = 'none'
  container.style.opacity = 0

  // Detect all style sheets of the page
  var activeSheets = Array.prototype.slice.call(document.styleSheets)
    .filter(function (sheet) {
      return !sheet.disabled
    })

  // Mount the container to the DOM to make `contentWindow` available
  // [3]
  document.body.appendChild(container)

  // Copy to clipboard
  // [4]
  window.getSelection().removeAllRanges()

  var range = document.createRange()
  range.selectNode(container)
  window.getSelection().addRange(range)

  // [5.1]
  document.execCommand('copy')

  // [5.2]
  for (var i = 0; i < activeSheets.length; i++) activeSheets[i].disabled = true

  // [5.3]
  document.execCommand('copy')

  // [5.4]
  for (var i = 0; i < activeSheets.length; i++) activeSheets[i].disabled = false

  // Remove the container
  // [6]
  document.body.removeChild(container)
}

Explication:

Examinez les commentaires dans le code ci-dessus pour voir où vous en êtes actuellement dans le processus suivant:

  1. Nous créons un conteneur dans lequel mettre notre code HTML.
  2. Nous stylisons le conteneur à masquer et détectons les feuilles de style actives de la page. La raison sera expliquée sous peu.
  3. Nous mettons le conteneur dans le DOM de la page.
  4. Nous supprimons les sélections éventuellement existantes et sélectionnons le contenu de notre conteneur.
  5. Nous faisons la copie elle-même. Il s'agit en fait d'un processus en plusieurs étapes: Chrome copiera le texte tel qu'il le voit, avec les styles CSS appliqués, tandis que les autres navigateurs le copieront avec les styles par défaut du navigateur. Par conséquent, nous désactiverons tous les utilisateurs avant de copier pour obtenir le résultat le plus cohérent possible.

    1. Avant cela, nous exécutons prématurément la commande copy. Il s'agit d'un hack pour IE11: dans ce navigateur, la copie doit être confirmée manuellement une fois. Jusqu'à ce que l'utilisateur clique sur le bouton "Confirmer", IE les utilisateurs verraient la page sans aucun style. Pour éviter cela, nous copions d'abord, attendons la confirmation, puis désactivons les styles et copions à nouveau. fois, nous n'obtiendrons pas de dialogue de confirmation puisque IE se souvient de notre dernier choix.
    2. Nous désactivons en fait les styles de la page.
    3. Maintenant, nous exécutons à nouveau la commande copy.
    4. Nous réactivons les feuilles de style.
  6. Nous supprimons le conteneur du DOM de la page.

Et nous avons terminé.


Mises en garde:

  • Le contenu formaté ne sera pas parfaitement cohérent entre les navigateurs.

    Comme expliqué ci-dessus, Chrome (c'est-à-dire le moteur Blink) utilisera une stratégie différente de Firefox et IE: Chrome copiera le contenu avec son style CSS, mais en omettant tous les styles qui ne sont pas définis.

    Firefox et IE d'autre part n'appliquera pas de CSS spécifique à la page, ils appliqueront les styles par défaut du navigateur. Cela signifie également qu'ils auront des styles étranges qui leur seront appliqués, par exemple la police par défaut (qui est généralement Times New Roman ).

  • Pour des raisons de sécurité, les navigateurs autorisent uniquement l'exécution de la fonction en tant qu'effet d'une interaction utilisateur (par exemple, un clic, une pression sur une touche, etc.)

27
Loilo