Como adicionar informações extras ao texto da web copiado

103

Alguns sites agora usam um serviço JavaScript da Tynt que anexa texto ao conteúdo copiado.

Se você copiar o texto de um site usando isso e depois colar, obterá um link para o conteúdo original na parte inferior do texto.

Tynt também rastreia isso conforme acontece. É um truque legal bem executado.

Seu script para fazer isso é impressionante - em vez de tentar manipular a área de transferência (o que apenas as versões mais antigas do IE permitem fazer por padrão e que deve estar sempre desligada), eles manipulam a seleção real.

Portanto, quando você seleciona um bloco de texto, o conteúdo extra é adicionado como oculto <div>incluído em sua seleção. Quando você cola, o estilo extra é ignorado e o link extra aparece.

Na verdade, isso é bastante fácil de fazer com blocos de texto simples, mas um pesadelo quando você considera todas as seleções possíveis em HTML complexo em navegadores diferentes.

Estou desenvolvendo um aplicativo da web - não quero que ninguém rastreie o conteúdo copiado e gostaria que as informações extras contivessem algo contextual, em vez de apenas um link. O serviço de Tynt não é realmente apropriado neste caso.

Alguém conhece uma biblioteca JavaScript de código aberto (talvez um plug-in jQuery ou semelhante) que fornece funcionalidade semelhante, mas que não expõe dados internos do aplicativo?

Keith
fonte
1
Dê uma olhada na minha resposta em stackoverflow.com/questions/6344588/… . É feito de forma muito semelhante à que você propôs
Niklas
48
Por favor, não faça isso. POR FAVOR, apenas não faça isso.
couchand
5
@couchand porque não? Eu entendo como isso é irritante em sites de spam, mas isso é para um aplicativo que pode ser usado para citações e onde os dados internos são confidenciais. É por isso que não queria usar Tynt.
Keith
4
Você tem certeza de que quer fazer isso? Como usuário, odeio isso e vou transportar essa raiva para o seu produto: Não toque na minha prancheta!
aloisdg mudando para codidact.com

Respostas:

138

Atualização de 2020

Solução que funciona em todos os navegadores recentes .

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>


[Postagem mais antiga - antes da atualização de 2020]

Existem duas maneiras principais de adicionar informações extras ao texto da web copiado.

1. Manipulando a seleção

A ideia é observar o e copy event, em seguida, anexar um contêiner oculto com nossas informações extras ao dome estender a seleção a ele.
Este método foi adaptado deste artigo por c.bavota . Verifique também a versão de jitbit para casos mais complexos.

  • Compatibilidade do navegador : todos os principais navegadores, IE> 8.
  • Demonstração : demonstração do 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. Manipulando a área de transferência

A ideia é observar copy evente modificar diretamente os dados da área de transferência. Isso é possível usando a clipboardDatapropriedade. Observe que esta propriedade está disponível em todos os principais navegadores em read-only; o setDatamétodo está disponível apenas no 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
fonte
1
Felicidades! Infelizmente, precisamos que ele funcione no IE, mas isso não é um mau começo.
Keith de
2
Deve haver uma solução alternativa para as tags "<pre>", uma versão mais suave deste script está aqui
Alex
15
Observe que "Manipulando a área de transferência" funciona perfeitamente no FireFox, Chrome e Safari se você mudar window.clipboardDatapara event.clipboardData. IE (v11 também) não é compatível com event.clipboardData jsfiddle.net/m56af0je/8
mems
3
Se você estiver usando o Google Analytics etc, você pode até disparar um evento para registrar o que os usuários estão copiando do seu site. Interessante
geedubb
2
A primeira opção ignora os novos caracteres de linha do texto copiado.
soham
7

Esta é uma solução javascript vanilla de uma solução modificada acima, mas oferece suporte a mais 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
fonte
3

A versão mais curta do jQuery que testei e está funcionando é:

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);
});
user2276146
fonte
onde está o código que realmente copia o resultado para a área de transferência?
vsync
@vsync Eu acredito que isso apenas adiciona funcionalidade antes de a cópia ocorrer (o que é feito pelo sistema quando o usuário o inicia).
TerranRich
@vsync - como o TerraRich disse, tentei responder à pergunta, que era sobre adicionar informações extras ao texto copiado, então a solução cobre apenas esta parte.
user2276146
3

Aqui está um plugin em jquery para fazer isso https://github.com/niklasvh/jquery.plugin.clipboard Do leia-me do projeto "Este script modifica o conteúdo de uma seleção antes de um evento de cópia ser chamado, resultando na seleção copiada ser diferente do que o usuário selecionou.

Isso permite que você anexe / prefixe conteúdo à seleção, como informações de direitos autorais ou outro conteúdo.

Lançado sob licença MIT "

sktguha
fonte
1
Isso parece muito promissor. Ele usa estilos embutidos que não permitimos com nosso CSP, mas poderia ser adaptado. Felicidades!
Keith,
3

Melhorando a resposta, restaure a seleção após as alterações para evitar seleções aleatórias após a cópia.

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
fonte
@TsukimotoMitsumasa Deveria havervar range = selection.getRangeAt(0);
Vokiel de
Restaurar a seleção de texto é uma boa ideia, caso contrário, isso quebra o comportamento padrão do navegador.
Sergey
2

Melhoria 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
fonte
1
Ao copiar e colar, você perde a formatação ( <a> , <img> , <b> e outras tags). É melhor obter o código HTML do texto selecionado. Use a função getSelectionHtml () a partir desta resposta: [ stackoverflow.com/a/4177234/4177020] E agora você pode substituir esta string var selection = window.getSelection();por esta:var selection = getSelectionHtml();
Dmitry Kulahin
0

Também uma solução um pouco mais curta:

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
fonte
0

É uma compilação de 2 respostas acima + compatibilidade com Microsoft Edge.

Também adicionei uma restauração da seleção original no final, como é esperado por padrão em qualquer 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
fonte