【问题标题】:How to add extra info to copied web text如何向复制的网络文本添加额外信息
【发布时间】:2011-01-02 20:05:16
【问题描述】:

一些网站现在使用来自Tynt 的 JavaScript 服务,该服务将文本附加到复制的内容。

如果您使用它从网站复制文本然后粘贴,您会在文本底部获得指向原始内容的链接。

Tynt 也会在它发生时跟踪它。这是一个巧妙的技巧。

他们这样做的脚本令人印象深刻——而不是试图操纵剪贴板(只有旧版本的 IE 默认允许他们这样做,并且应该始终关闭),而是操纵实际的选择。

因此,当您选择文本块时,额外内容将作为隐藏的<div> 添加到您的选择中。当您粘贴时,多余的样式会被忽略并出现额外的链接。

这实际上对简单的文本块很容易做到,但是当您考虑到在不同浏览器中跨复杂 HTML 的所有可能选择时,这是一场噩梦。

我正在开发一个 Web 应用程序 - 我不希望任何人能够跟踪复制的内容,我希望额外的信息包含上下文相关的内容,而不仅仅是一个链接。 Tynt 的服务在这种情况下并不合适。

有谁知道提供类似功能但不公开内部应用程序数据的开源 JavaScript 库(可能是 jQuery 插件或类似的)?

【问题讨论】:

  • 请不要这样做。求求求你不要。
  • @couchand 为什么不呢?我知道这在垃圾邮件网站上有多烦人,但这是针对可用于引用且内部数据敏感的应用程序。这就是我不想使用 Tynt 的原因。
  • 您确定要这样做吗?作为用户,我讨厌它,我会将这种愤怒转移到您的产品中:Don't touch my clipboard!
  • @aloisdgmovingtocodidact.com 这是十年前的事了,但这是一项要求——他们从中复制的文件是合法的,这对他们自动将引用链接包含回源代码有很大帮助.这不是我在一般网站上会做的事情 - 用户明白复制的报价必须准确引用它的来源。

标签: javascript clipboard


【解决方案1】:

2022 年更新

处理富文本格式的更复杂的解决方案。如果您只处理纯文本,2020 年的解决方案仍然适用。

const copyListener = (e) => {
  const range = window.getSelection().getRangeAt(0),
    rangeContents = range.cloneContents(),
    pageLink = `Read more at: ${document.location.href}`,
    helper = document.createElement("div");

  helper.appendChild(rangeContents);

  event.clipboardData.setData("text/plain", `${helper.innerText}\n${pageLink}`);
  event.clipboardData.setData("text/html", `${helper.innerHTML}<br>${pageLink}`);
  event.preventDefault();
};
document.addEventListener("copy", copyListener);
#richText {
  width: 415px;
  height: 70px;
  border: 1px solid #777;
  overflow: scroll;
}

#richText:empty:before {
  content: "Paste your copied text here";
  color: #888;
}
<h4>Rich text:</h4>
<p>Lorem <u>ipsum</u> dolor sit <b>amet</b>, consectetur <i>adipiscing</i> elit.</p>
<h4>Plain text editor:</h4>
<textarea name="textarea" rows="5" cols="50" placeholder="Paste your copied text here"></textarea>
<h4>Rich text editor:</h4>
<div id="richText" contenteditable="true"></div>

2020 年更新

适用于所有近期浏览器的解决方案。

请注意,即使粘贴到富文本编辑器中,此解决方案也会去除富文本格式(例如粗体和斜体)。

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

[较早的帖子 - 2020 年更新之前]

向复制的网络文本添加额外信息的主要方法有两种。

  1. 操作选择

我们的想法是监视copy event,然后将带有我们额外信息的隐藏容器附加到dom,并将选择扩展到它。
此方法改编自 c.bavotathis article。更复杂的情况也请查看jitbit's version

  • 浏览器兼容性:所有主流浏览器,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);
  1. 操作剪贴板

思路是看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);

【讨论】:

  • 干杯!不幸的是,我们需要它在 IE 中工作,但这并不是一个糟糕的开始。
  • 应该有“
    ”标签的变通方法,这个脚本更流畅的版本是here
  • 请注意,如果您将window.clipboardData 更改为event.clipboardData,则“操作剪贴板”在 FireFox、Chrome 和 Safari 中运行良好。 IE(也是v11)不支持event.clipboardDatajsfiddle.net/m56af0je/8
  • 如果您使用 Google Analytics 等,您甚至可以触发一个事件来记录用户从您的站点复制的内容。有趣
  • 第一个选项忽略复制文本的换行符。
【解决方案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 /><a href="' + document.location.href + '">Source</a>');
    e.preventDefault();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<p>Example text with <b>bold</b> and <i>italic</i>. Try copying and pasting me into a rich text editor.</p>

【讨论】:

  • 复制粘贴时会丢失格式( 和其他标签)。最好获取所选文本的 HTML 代码。使用此答案中的 getSelectionHtml() 函数:[stackoverflow.com/a/4177234/4177020] 现在您可以用这个字符串替换此字符串 var selection = window.getSelection();var selection = getSelectionHtml();
  • 如果你粘贴到富文本编辑器中,你会得到一个带有标题“Source”的漂亮链接,这很好。但是,它不保留原始文本的富文本格式。另外,我不确定为什么需要$('&lt;div/&gt;').html(selection + "").text()selection.toString() 是以纯文本开头的。
  • 另外,这部分应该正确转义:&lt;a href="' + document.location.href + '"&gt;,现在不是。
【解决方案3】:

这是一个来自上述修改解决方案的 vanilla 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);

【讨论】:

  • 请注意,此解决方案将去除富文本格式(例如粗体和斜体)。
【解决方案4】:

这是上面 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);

【讨论】:

    【解决方案5】:

    改进答案,修改后恢复选择,防止复制后随机选择。

    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);
    

    【讨论】:

    • @TsukimotoMitsumasa 应该有var range = selection.getRangeAt(0);
    • 恢复文本选择是个好主意,否则会破坏默认浏览器行为。
    • “改进答案”...改进哪个答案?
    【解决方案6】:

    这是 jquery 中的一个插件来做到这一点 https://github.com/niklasvh/jquery.plugin.clipboard 来自项目自述文件 "此脚本在调用复制事件之前修改选择的内容,导致复制的选择与用户选择的不同。

    这允许您在选择中附加/预先添加内容,例如版权信息或其他内容。

    根据 MIT 许可发布”

    【讨论】:

    • 这看起来很有希望。它使用我们的 CSP 不允许的内联样式,但它可能会被修改。干杯!
    【解决方案7】:

    我测试过的 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);
    });
    

    【讨论】:

    • 实际将结果复制到剪贴板的代码在哪里?
    • @vsync 我相信这只是在复制发生之前添加了功能(这是由系统在用户启动它时完成的)。
    • @vsync - 正如 TerraRich 所说,我试图回答这个问题,即在复制的文本中添加额外信息,因此解决方案仅涵盖这部分。
    【解决方案8】:

    还有一个更短的解决方案:

    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;
    } );
    

    【讨论】:

      猜你喜欢
      • 2021-04-29
      • 1970-01-01
      • 1970-01-01
      • 2017-05-26
      • 2019-11-10
      • 2023-03-08
      • 1970-01-01
      • 2022-06-22
      • 1970-01-01
      相关资源
      最近更新 更多