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

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

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

Tynt также отслеживает это, когда это происходит. Это хороший трюк.

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

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

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

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

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


person Keith    schedule 08.01.2010    source источник
comment
Посмотрите мой ответ на stackoverflow.com/questions/6344588/. Делается очень похоже на то, что вы предложили   -  person Niklas    schedule 14.06.2011
comment
См. также stackoverflow.com/questions/1203082/   -  person Gnubie    schedule 14.04.2014
comment
Пожалуйста, не делайте этого. ПОЖАЛУЙСТА, ПОЖАЛУЙСТА, ПОЖАЛУЙСТА, только не надо.   -  person couchand    schedule 30.06.2015
comment
@couch, а почему бы и нет? Я понимаю, как это раздражает на спам-сайтах, но это для приложения, которое можно использовать для цитирования и где внутренние данные являются конфиденциальными. Вот почему я не хотел использовать Tynt.   -  person Keith    schedule 30.06.2015
comment
Альтернатива: github.com/tovic/sticky-attribution   -  person Taufik Nurrohman    schedule 29.05.2017
comment
Вы уверены, что хотите это сделать? Как пользователь, я ненавижу это и перенесу этот гнев в ваш продукт: Don' не трогай мой буфер обмена!   -  person aloisdg    schedule 18.02.2020
comment
@aloisdgmovingtocodidact.com это было десять лет назад, но это было требованием - документы, которые они копировали, были законными, и им очень помогло автоматическое включение ссылки на источник. Я бы не стал этого делать на обычных сайтах — пользователи понимали, что скопированная цитата должна точно указывать, откуда она взята.   -  person Keith    schedule 18.02.2020


Ответы (8)


Обновление 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.
  • Код 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.


    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);
person CronosS    schedule 24.01.2011
comment
Ваше здоровье! К сожалению, нам нужно, чтобы он работал в IE, но это неплохое начало. - person Keith; 24.01.2011
comment
@Keith Вы нашли решение как для IE, так и для обычных браузеров? Без Flash-решения. - person tunarob; 06.06.2012
comment
Должен быть обходной путь для тегов ‹pre›, более плавная версия этого скрипта здесь - person Alex from Jitbit; 24.12.2013
comment
Это не работает для меня в Йосемити. Как только я каким-либо образом связываюсь с selection в обработчике копирования, в Chrome/Firefox вообще ничего не копируется (предыдущее значение остается в буфере обмена); в Safari буфер обмена очищается, но ничего нового там не появляется. - person mgol; 11.12.2014
comment
РЕДАКТИРОВАТЬ: о, это работает, но элемент не может иметь visibility: hidden. Странный. - person mgol; 11.12.2014
comment
Обратите внимание, что Управление буфером обмена отлично работает в FireFox, Chrome и Safari, если вы измените window.clipboardData на event.clipboardData. IE (также v11) не поддерживает event.clipboardData jsfiddle.net/m56af0je/8 - person mems; 12.12.2014
comment
Если вы используете Google Analytics и т. д., вы даже можете запустить событие, чтобы регистрировать, что пользователи копируют с вашего сайта. Интересный - person geedubb; 05.01.2015
comment
Первый вариант игнорирует символы новой строки скопированного текста. - person soham; 30.01.2015
comment
Подход 1 на Edge работает, но имеет дефект графики. Когда вы копируете, строка selection.selectAllChildren(newdiv); заставляет вашу страницу прокручиваться вниз. Это происходит из-за того, что элемент newdiv добавляется снизу. Чтобы избежать нежелательной прокрутки, добавьте newdiv к элементу, вызвавшему копирование (jquery): $(e.target).after($(newdiv)) - person reallynice; 14.04.2016
comment
Немного беспокоит возможность сделать это, но не возможность сделать это с помощью более простой функции. - person Alexander; 16.05.2017
comment
@geedubb, как мы можем запустить событие, чтобы регистрировать, что пользователи копируют с сайта? - person Antonio D.; 31.03.2020

Это ванильное решение 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);
person GiorgosK    schedule 27.03.2018

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

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

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

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

person sktguha    schedule 08.09.2015
comment
Это выглядит очень многообещающе. Он использует встроенные стили, которые мы не допускаем в нашем CSP, но потенциально его можно адаптировать. Ваше здоровье! - person Keith; 08.09.2015

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

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);
person digitalPBK    schedule 23.11.2015
comment
@TsukimotoMitsumasa Должно быть var range = selection.getRangeAt(0); - person Vokiel; 21.02.2017
comment
Восстановление выделения текста — хорошая идея, иначе это нарушит поведение браузера по умолчанию. - person Sergey; 24.05.2018

Улучшение на 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();
});
person tronic    schedule 04.03.2018
comment
При копировании-вставке теряется форматирование (‹a›, ‹img›, ‹b› и другие теги). Лучше получить HTML-код выделенного текста. Используйте функцию getSelectionHtml() из этого ответа: [stackoverflow.com/a /4177234/4177020] Теперь вы можете заменить эту строку var selection = window.getSelection(); на эту: var selection = getSelectionHtml(); - person Dzmitry Kulahin; 02.10.2019

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

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;
} );
person almo    schedule 28.05.2014

Это компиляция двух ответов выше + совместимость с 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);
person Sergey    schedule 24.05.2018