如何向复制的网页文本添加额外信息

发布于 2024-08-17 08:03:12 字数 609 浏览 2 评论 0原文

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

如果您使用此功能从网站复制文本,然后粘贴,您将在文本底部获得原始内容的链接。

Tynt 也会在事件发生时对其进行跟踪。这是一个巧妙的技巧,做得很好。

他们执行此操作的脚本令人印象深刻 - 而不是尝试操作剪贴板(默认情况下只有旧版本的 IE 允许他们执行此操作,并且应始终将其关闭),而是操作实际的选择。

因此,当您选择文本块时,额外的内容将作为隐藏的

添加到您的选择中。当您粘贴时,额外的样式将被忽略并显示额外的链接。

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

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

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

Some websites now use a JavaScript service from Tynt that appends text to copied content.

If you copy text from a site using this and then paste you get a link to the original content at the bottom of the text.

Tynt also tracks this as it happens. It's a neat trick well done.

Their script for doing this is impressive - rather than try to manipulate the clipboard (which only older versions of IE lets them do by default and which should always be turned off) they manipulate the actual selection.

So when you select a block of text the extra content is added as a hidden <div> included in your selection. When you paste the extra style is ignored and the extra link appears.

This is actually fairly easy to do with simple blocks of text, but a nightmare when you consider all the selections possible across complex HTML in different browsers.

I'm developing a web application - I don't want anyone to be able to track the content copied and I would like the extra info to contain something contextual, rather than just a link. Tynt's service isn't really appropriate in this case.

Does anyone know of an open source JavaScript library (maybe a jQuery plug in or similar) that provides similar functionality but that doesn't expose internal application data?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

近箐 2024-08-24 08:03:12

2022 更新

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

const copyListener = (event) => {
  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. 操作选择的

想法是监视复制事件,然后将带有额外信息的隐藏容器附加到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);
  1. 操作剪贴板

这个想法是观察复制事件并直接修改剪贴板数据。这可以使用clipboardData 属性来实现。请注意,此属性在所有主要浏览器中均以只读 方式提供; 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);

2022 Update

More complex solution that handles rich text formatting. The 2020 solution is still relevant if you only deal with plain text.

const copyListener = (event) => {
  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 Update

Solution that works on all recent browsers.

Note that this solution will strip rich text formatting (such as bold and italic), even when pasting into a rich text editor.

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>


[Older post - before the 2020 update]

There are two main ways to add extra info to copied web text.

  1. Manipulating the selection

The idea is to watch for the copy event, then append a hidden container with our extra info to the dom, and extend the selection to it.
This method is adapted from this article by c.bavota. Check also jitbit's version for more complex case.

  • Browser compatibility: All major browsers, IE > 8.
  • Demo: jsFiddle demo.
  • Javascript code:

    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. Manipulating the clipboard

The idea is to watch the copy event and directly modify the clipboard data. This is possible using the clipboardData property. Note that this property is available in all major browsers in read-only; the setData method is only available on IE.

  • Browser compatibility: IE > 4.
  • Demo: jsFiddle demo.
  • Javascript code:

    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);
自演自醉 2024-08-24 08:03:12

这是上面修改后的普通 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);

This is a vanilla javascript solution from a modified solution above but supports more browsers (cross browser method)

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);
世界和平 2024-08-24 08:03:12

我测试过并且正在运行的 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);
});

The shortest version for jQuery that I tested and is working is:

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);
});
泅人 2024-08-24 08:03:12

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

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

根据 MIT 许可发布”

Here is a plugin in jquery to do that
https://github.com/niklasvh/jquery.plugin.clipboard
From the project readme
"This script modifies the contents of a selection prior to a copy event being called, resulting in the copied selection being different from what the user selected.

This allows you to append/prepend content to the selection, such as copyright information or other content.

Released under MIT License"

东风软 2024-08-24 08:03:12

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

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

Improving on the answer, restore selection after the alterations to prevent random selections after copy.

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);
忆伤 2024-08-24 08:03:12

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>

Improvement for 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>

寂寞美少年 2024-08-24 08:03:12

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

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

Also a little shorter solution:

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;
} );
半衬遮猫 2024-08-24 08:03:12

它是上述 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);

It's a compilation of 2 answers above + compatibility with Microsoft Edge.

I've also added a restore of the original selection at the end, as it is expected by default in any browser.

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文