Как добавить дополнительную информацию к скопированному веб-тексту

103

Некоторые веб-сайты теперь используют службу JavaScript от Tynt, которая добавляет текст к скопированному содержимому.

Если вы скопируете текст с сайта, используя это, а затем вставите, вы получите ссылку на исходный контент внизу текста.

Тынт также отслеживает, как это происходит. Это отличный трюк.

Их сценарий для этого впечатляет - вместо того, чтобы пытаться манипулировать буфером обмена (что позволяет им делать только старые версии IE по умолчанию и который всегда следует выключать), они манипулируют фактическим выделением.

Поэтому, когда вы выбираете блок текста, дополнительный контент добавляется как скрытый, <div>включенный в ваш выбор. При вставке лишний стиль игнорируется и появляется дополнительная ссылка.

На самом деле это довольно легко сделать с простыми блоками текста, но это кошмар, если учесть все возможные варианты выбора в сложном HTML в разных браузерах.

Я разрабатываю веб-приложение - я не хочу, чтобы кто-либо мог отслеживать скопированный контент, и я хотел бы, чтобы дополнительная информация содержала что-то контекстное, а не просто ссылку. В этом случае услуга Tynt не совсем подходит.

Кто-нибудь знает библиотеку JavaScript с открытым исходным кодом (возможно, плагин jQuery или аналогичный), которая предоставляет аналогичные функции, но не раскрывает внутренние данные приложения?

Кит
источник
1
Посмотрите мой ответ на stackoverflow.com/questions/6344588/… . Это сделано очень похоже на то, что вы предложили
Никлас
1
См. Также stackoverflow.com/questions/1203082/…
Gnubie
48
Пожалуйста, не делай этого. ПОЖАЛУЙСТА, ПОЖАЛУЙСТА, ПОЖАЛУЙСТА, просто не делайте этого.
couchand
5
@coucha, а почему бы и нет? Я понимаю, насколько это раздражает на сайтах со спамом, но это для приложения, которое можно использовать для цитирования и где внутренние данные конфиденциальны. Вот почему я не хотел использовать Tynt.
Кейт
4
Вы уверены, что хотите это сделать? Как пользователь, я ненавижу это, и я перенесу этот гнев в ваш продукт: не трогайте мой буфер обмена!
aloisdg переходит на codidact.com

Ответы:

138

Обновление 2020

Решение, которое работает во всех последних браузерах.

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>


[Предыдущее сообщение - до обновления 2020]

Есть два основных способа добавить дополнительную информацию к скопированному веб-тексту.

1. Манипулирование выделением

Идея состоит в том, чтобы следить за copy eventобъектом, затем добавить в него скрытый контейнер с нашей дополнительной информацией domи расширить выбор до него.
Этот метод адаптирован из этой статьи по c.bavota . Также проверьте версию jitbit для более сложного случая.

  • Совместимость с браузером: все основные браузеры, IE> 8.
  • Демо : jsFiddle demo .
  • Код 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. Работа с буфером обмена

Идея состоит в том, чтобы наблюдать copy eventи напрямую изменять данные буфера обмена. Это возможно с помощью clipboardDataсобственности. Обратите внимание, что это свойство доступно во всех основных браузерах в read-only; setDataметод доступен только в IE.

  • Совместимость с браузером : IE> 4.
  • Демо : jsFiddle demo .
  • Код Javascript :

    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
источник
1
Ура! К сожалению, нам нужно, чтобы это работало в IE, но это неплохое начало.
Кейт
2
Должен быть обходной путь для тегов «<pre>», более плавная версия этого скрипта находится здесь
Alex
15
Обратите внимание, что «Управление буфером обмена» лучше всего работает в FireFox, Chrome и Safari, если вы измените window.clipboardDataна event.clipboardData. IE (тоже v11) не поддерживает event.clipboardData jsfiddle.net/m56af0je/8
mems
3
Если вы используете Google Analytics и т. Д., Вы даже можете запустить событие, чтобы регистрировать, что пользователи копируют с вашего сайта. Интересно
geedubb 05
2
Первый вариант игнорирует символы новой строки скопированного текста.
Soham
7

Это ванильное решение javascript из модифицированного решения выше, но поддерживает больше браузеров (кроссбраузерный метод)

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
источник
3

Самая короткая версия jQuery, которую я тестировал и сейчас работает:

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
источник
где код, который фактически копирует результат в буфер обмена?
vsync
@vsync Я считаю, что это просто добавляет функциональность непосредственно перед копированием (что выполняется системой, когда пользователь инициирует его).
TerranRich
@vsync - как сказал TerraRich, я попытался ответить на вопрос, который касался добавления дополнительной информации в скопированный текст, поэтому решение охватывает только эту часть.
user2276146
3

Вот плагин в jquery для этого https://github.com/niklasvh/jquery.plugin.clipboard Из файла readme проекта "Этот скрипт изменяет содержимое выделенного фрагмента до вызова события копирования, что приводит к скопированному выделению. отличается от того, что выбрал пользователь.

Это позволяет вам добавлять / добавлять контент к выбору, например информацию об авторских правах или другой контент.

Выпущено по лицензии MIT "

Sktguha
источник
1
Это выглядит очень многообещающе. Он использует встроенные стили, которые мы не допускаем в нашем CSP, но потенциально может быть адаптирован. Ура!
Кит
3

Улучшая ответ, восстановите выбор после изменений, чтобы предотвратить случайный выбор после копирования.

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
источник
@TsukimotoMitsumasa Должно бытьvar range = selection.getRangeAt(0);
Vokiel
Восстановление выделения текста - хорошая идея, в противном случае это нарушит поведение браузера по умолчанию.
Сергей
2

Улучшение на 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
источник
1
При копировании-вставке теряется форматирование ( <a> , <img> , <b> и другие теги). Лучше получить HTML-код выделенного текста. Используйте функцию getSelectionHtml () из этого ответа: [ stackoverflow.com/a/4177234/4177020] И теперь вы можете заменить эту строку var selection = window.getSelection();на эту:var selection = getSelectionHtml();
Дмитрий Кулахин 02
0

Также немного более короткое решение:

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;
} );
почти
источник
0

Это сборник из 2 ответов выше + совместимость с Microsoft Edge.

Я также добавил восстановление исходного выделения в конце, как это ожидается по умолчанию в любом браузере.

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);
Сергей
источник