Cómo agregar información adicional al texto web copiado

103

Algunos sitios web ahora usan un servicio de JavaScript de Tynt que agrega texto al contenido copiado.

Si copia texto de un sitio usando esto y luego lo pega, obtendrá un enlace al contenido original en la parte inferior del texto.

Tynt también rastrea esto a medida que sucede. Es un buen truco bien hecho.

Su secuencia de comandos para hacer esto es impresionante: en lugar de intentar manipular el portapapeles (que solo las versiones anteriores de IE les permiten hacer de forma predeterminada y que siempre deben estar apagadas), manipulan la selección real.

Por lo tanto, cuando selecciona un bloque de texto, el contenido adicional se agrega como oculto. <div> incluido en su selección. Cuando pega, el estilo adicional se ignora y aparece el enlace adicional.

En realidad, esto es bastante fácil de hacer con bloques de texto simples, pero una pesadilla cuando se consideran todas las selecciones posibles en HTML complejo en diferentes navegadores.

Estoy desarrollando una aplicación web: no quiero que nadie pueda rastrear el contenido copiado y me gustaría que la información adicional contenga algo contextual, en lugar de solo un enlace. El servicio de Tynt no es realmente apropiado en este caso.

¿Alguien sabe de una biblioteca de JavaScript de código abierto (tal vez un complemento jQuery o similar) que proporcione una funcionalidad similar pero que no exponga los datos internos de la aplicación?

Keith
fuente
1
Eche un vistazo a mi respuesta en stackoverflow.com/questions/6344588/… . Se hace de manera muy similar a como propusiste
Niklas
1
Consulte también stackoverflow.com/questions/1203082/…
Gnubie
48
Por favor, no hagas esto. POR FAVOR POR FAVOR POR FAVOR simplemente no lo hagas.
couchand
5
@couchand ¿por qué no? Entiendo lo molesto que es esto en los sitios de spam, pero esto es para una aplicación que puede usarse para citas y donde los datos internos son confidenciales. Por eso no quería usar Tynt.
Keith
4
¿Seguro que quieres hacer esto? Como usuario, lo odio y trasladaré este enojo a su producto: ¡No toque mi portapapeles!
aloisdg se muda a codidact.com

Respuestas:

138

Actualización 2020

Solución que funciona en todos los navegadores recientes .

document.addEventListener('copy', (event) => {
  const pagelink = `\n\nRead more at: ${document.location.href}`;
  event.clipboardData.setData('text', document.getSelection() + pagelink);
  event.preventDefault();
});
Lorem ipsum dolor sit amet, consectetur adipiscing elit.<br/>
<textarea name="textarea" rows="7" cols="50" placeholder="paste your copied text here"></textarea>


[Entrada anterior - antes de la actualización de 2020]

Hay dos formas principales de agregar información adicional al texto web copiado.

1. Manipulación de la selección

La idea es buscar el copy event, luego agregar un contenedor oculto con nuestra información adicional al dom, y extender la selección al mismo.
Este método está adaptado de este artículo por c.bavota . Consulte también la versión de jitbit para casos más complejos.

  • Compatibilidad del navegador : todos los navegadores principales, IE> 8.
  • Demostración : demostración de jsFiddle .
  • Código Javascript :

    function addLink() {
        //Get the selected text and append the extra info
        var selection = window.getSelection(),
            pagelink = '<br /><br /> Read more at: ' + document.location.href,
            copytext = selection + pagelink,
            newdiv = document.createElement('div');

        //hide the newly created container
        newdiv.style.position = 'absolute';
        newdiv.style.left = '-99999px';

        //insert the container, fill it with the extended text, and define the new selection
        document.body.appendChild(newdiv);
        newdiv.innerHTML = copytext;
        selection.selectAllChildren(newdiv);

        window.setTimeout(function () {
            document.body.removeChild(newdiv);
        }, 100);
    }

    document.addEventListener('copy', addLink);

2. Manipular el portapapeles

La idea es observar copy eventy modificar directamente los datos del portapapeles. Esto es posible usando la clipboardDatapropiedad. Tenga en cuenta que esta propiedad está disponible en todos los navegadores principales en read-only; el setDatamétodo solo está disponible en IE.


    function addLink(event) {
        event.preventDefault();

        var pagelink = '\n\n Read more at: ' + document.location.href,
            copytext =  window.getSelection() + pagelink;

        if (window.clipboardData) {
            window.clipboardData.setData('Text', copytext);
        }
    }

    document.addEventListener('copy', addLink);
CronosS
fuente
1
¡Salud! Desafortunadamente, necesitamos que funcione en IE, pero no es un mal comienzo.
Keith
2
Debe haber una solución para "<pre>" etiquetas, una versión más suave de este script es aquí
Alex
15
Tenga en cuenta que "Manipular el portapapeles" funciona perfectamente en FireFox, Chrome y Safari si cambia window.clipboardDataa event.clipboardData. IE (v11 también) no es compatible con event.clipboardData jsfiddle.net/m56af0je/8
mems
3
Si está utilizando Google Analytics, etc., incluso puede iniciar un evento para registrar lo que los usuarios están copiando de su sitio. Interesante
geedubb
2
La primera opción ignora los caracteres de nueva línea del texto copiado.
soham
7

Esta es una solución javascript de vainilla de una solución modificada anterior, pero es compatible con más navegadores (método de navegador cruzado)

function addLink(e) {
    e.preventDefault();
    var pagelink = '\nRead more: ' + document.location.href,
    copytext =  window.getSelection() + pagelink;
    clipdata = e.clipboardData || window.clipboardData;
    if (clipdata) {
        clipdata.setData('Text', copytext);
    }
}
document.addEventListener('copy', addLink);
GiorgosK
fuente
3

La versión más corta de jQuery que probé y está funcionando es:

jQuery(document).on('copy', function(e)
{
  var sel = window.getSelection();
  var copyFooter = 
        "<br /><br /> Source: <a href='" + document.location.href + "'>" + document.location.href + "</a><br />© YourSite";
  var copyHolder = $('<div>', {html: sel+copyFooter, style: {position: 'absolute', left: '-99999px'}});
  $('body').append(copyHolder);
  sel.selectAllChildren( copyHolder[0] );
  window.setTimeout(function() {
      copyHolder.remove();
  },0);
});
usuario2276146
fuente
¿Dónde está el código que realmente copia el resultado en el portapapeles?
vsync
@vsync Creo que esto solo agrega funcionalidad justo antes de que se realice la copia (que es realizada por el sistema cuando el usuario la inicia).
TerranRich
@vsync: como dijo TerraRich, traté de responder a la pregunta, que trataba de agregar información adicional al texto copiado, por lo que la solución cubre solo esta parte.
user2276146
3

Aquí hay un complemento en jquery para hacer eso https://github.com/niklasvh/jquery.plugin.clipboard Del proyecto readme "Este script modifica el contenido de una selección antes de que se llame a un evento de copia, lo que da como resultado la selección copiada ser diferente de lo que seleccionó el usuario.

Esto le permite agregar / anteponer contenido a la selección, como información de derechos de autor u otro contenido.

Publicado bajo licencia MIT "

sktguha
fuente
1
Eso parece muy prometedor. Utiliza estilos en línea que no permitimos con nuestro CSP, pero potencialmente podría adaptarse. ¡Salud!
Keith
3

Mejorando la respuesta, restaure la selección después de las alteraciones para evitar selecciones aleatorias después de la copia.

function addLink() {
    //Get the selected text and append the extra info
    var selection = window.getSelection(),
        pagelink = '<br /><br /> Read more at: ' + document.location.href,
        copytext = selection + pagelink,
        newdiv = document.createElement('div');
    var range = selection.getRangeAt(0); // edited according to @Vokiel's comment

    //hide the newly created container
    newdiv.style.position = 'absolute';
    newdiv.style.left = '-99999px';

    //insert the container, fill it with the extended text, and define the new selection
    document.body.appendChild(newdiv);
    newdiv.innerHTML = copytext;
    selection.selectAllChildren(newdiv);

    window.setTimeout(function () {
        document.body.removeChild(newdiv);
        selection.removeAllRanges();
        selection.addRange(range);
    }, 100);
}

document.addEventListener('copy', addLink);
digitalPBK
fuente
@TsukimotoMitsumasa Debe habervar range = selection.getRangeAt(0);
Vokiel
Restaurar la selección de texto es una buena idea; de lo contrario, rompe el comportamiento predeterminado del navegador.
Sergey
2

Mejora para 2018

document.addEventListener('copy', function (e) {
    var selection = window.getSelection();
    e.clipboardData.setData('text/plain', $('<div/>').html(selection + "").text() + "\n\n" + 'Source: ' + document.location.href);
    e.clipboardData.setData('text/html', selection + '<br /><br />Source: <a href="' + document.location.href + '">' + document.title + '</a>');
    e.preventDefault();
});
tronic
fuente
1
Cuando copia y pega pierde el formato ( <a> , <img> , <b> y otras etiquetas). Es mejor obtener el código HTML del texto seleccionado. Use la función getSelectionHtml () de esta respuesta: [ stackoverflow.com/a/4177234/4177020] Y ahora puede reemplazar esta cadena var selection = window.getSelection();por esta:var selection = getSelectionHtml();
Dmitry Kulahin
0

También una solución un poco más corta:

jQuery( document ).ready( function( $ )
    {
    function addLink()
    {
    var sel = window.getSelection();
    var pagelink = "<br /><br /> Source: <a href='" + document.location.href + "'>" + document.location.href + "</a><br />© text is here";
    var div = $( '<div>', {style: {position: 'absolute', left: '-99999px'}, html: sel + pagelink} );
    $( 'body' ).append( div );
    sel.selectAllChildren( div[0] );
    div.remove();
    }



document.oncopy = addLink;
} );
almo
fuente
0

Es una compilación de las 2 respuestas anteriores + compatibilidad con Microsoft Edge.

También agregué una restauración de la selección original al final, como se espera de forma predeterminada en cualquier navegador.

function addCopyrightInfo() {
    //Get the selected text and append the extra info
    var selection, selectedNode, html;
    if (window.getSelection) {
        var selection = window.getSelection();
        if (selection.rangeCount) {
            selectedNode = selection.getRangeAt(0).startContainer.parentNode;
            var container = document.createElement("div");
            container.appendChild(selection.getRangeAt(0).cloneContents());
            html = container.innerHTML;
        }
    }
    else {
        console.debug("The text [selection] not found.")
        return;
    }

    // Save current selection to resore it back later.
    var range = selection.getRangeAt(0);

    if (!html)
        html = '' + selection;

    html += "<br/><br/><small><span>Source: </span><a target='_blank' title='" + document.title + "' href='" + document.location.href + "'>" + document.title + "</a></small><br/>";
    var newdiv = document.createElement('div');

    //hide the newly created container
    newdiv.style.position = 'absolute';
    newdiv.style.left = '-99999px';

    // Insert the container, fill it with the extended text, and define the new selection.
    selectedNode.appendChild(newdiv); // *For the Microsoft Edge browser so that the page wouldn't scroll to the bottom.

    newdiv.innerHTML = html;
    selection.selectAllChildren(newdiv);

    window.setTimeout(function () {
        selectedNode.removeChild(newdiv);
        selection.removeAllRanges();
        selection.addRange(range); // Restore original selection.
    }, 5); // Timeout is reduced to 10 msc for Microsoft Edge's sake so that it does not blink very noticeably.  
}

document.addEventListener('copy', addCopyrightInfo);
Sergey
fuente