复制插入版权信息功能的实现

著作权归罪歌moecopilot本人所有。商业转载请联系作者 QQ 1993713026 获得授权,非商业转载请注明出处。
Moecopilot is the original author. Please give credit to the original author when you use it elsewhere.

在知乎或者简书复制的文本为什么会自带一些版权声明,这个功能是如何实现的?

我很好奇

著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
作者:
链接:
来源:知乎

作者:
链接:
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

说实话我觉得知乎和简书他俩的名字还挺押韵……
查了查,大致明白了这个玩意的原理
原文这里https://segmentfault.com/q/1010000003986612

大体思路:
答案区域监听copy事件,并阻止这个事件的默认行为。
获取选中的内容(<font color = red >window.getSelection()</font>)加上版权信息,
然后设置到剪切板(<font color = red >clipboardData.setData()</font>)。

下面的代码实现了一个简单的DEMO

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test</title>
</head>
<body>
    <div id="answer">测试数据<b>test</b></div>
    <script>
        function setClipboardText(event){ 
            event.preventDefault();
            var node = document.createElement('div');
            //对documentfragment不熟,不知道怎么获取里面的内容,用了一个比较笨的方式
            node.appendChild(window.getSelection().getRangeAt(0).cloneContents());
            var htmlData = '<div>著作权归作者所有。<br />' 
                            + '商业转载请联系作者获得授权,非商业转载请注明出处。<br />'
                            + '作者:tiantian<br />链接:http://segmentfault.com/u/tiantian_<br />'
                            + '来源:segmentfault<br /><br />' 
                            + node.innerHTML 
                            + '</div>';
            var textData = '著作权归作者所有。\n' 
                            + '商业转载请联系作者获得授权,非商业转载请注明出处。\n'
                            + '作者:tiantian\n链接:http://segmentfault.com/u/tiantian_\n'
                            + '来源:segmentfault\n\n' 
                            + window.getSelection().getRangeAt(0);
            if(event.clipboardData){  
                event.clipboardData.setData("text/html", htmlData); 
                event.clipboardData.setData("text/plain",textData);
            }
            else if(window.clipboardData){  
                return window.clipboardData.setData("text", textData);  
            }  
        };  
        var answer = document.getElementById("answer");
        answer.addEventListener('copy',function(e){
            setClipboardText(e);
        });
    </script>
</body>
</html>

转自tiantian

我设了一个测试网站,嵌入(iframe)在这里了qwq

超好玩哈哈哈哈或或或或

而在这里https://www.zhihu.com/question/38140568

http://static.zhihu.com/static/revved/-/js/closure/common.d3bfcd50.js


 var Qy = function(a, b, c) {
  function d(a, b) {
     return ["著作权归作者所有。",
       "商业转载请联系作者获得授权,非商业转载请注明出处。",
       "作者:" + b, "链接:" + a, "来源:知乎",
       "", ""
     ]
   }

   function f(a, b, c) {
     return " div\x3e" + d(b, c).join(
         " br /\x3e") + a +
       " /div\x3e"
   }

   function g(a) {
     var g = z.Kq(),
       m = g && (0,
         z.x)(g.Fd());
     if (m && !(42 > m.length)) {
       if ("object" === typeof a.originalEvent
         .clipboardData && (a.originalEvent
           .clipboardData.setData(
             "text/html", f(g.Mf(), b,
               c)),
           a.originalEvent.clipboardData
           .setData("text/plain", d(b,
             c).join("\n") + m),
           0 < a.originalEvent.clipboardData
           .getData("text/plain").length
         )) {
         a.preventDefault();
         return
       }
       if (window.getSelection) {
         a = g.Mf();
         var n = (0,
           window.$)(f(a, b, c)).css({
           position: "fixed",
           left: "-9999px"
         }).appendTo("body");
         window.getSelection().selectAllChildren(
           n.get(0));
         (0,
           window.setTimeout)(function() {
           g.select();
           n.remove()
         }, 200)
       }
     }
   }
   a && b && c && (z.Da(b, "http") ||
     (b = window.location.protocol +
       "//" + window.location.host +
      b),
    a.on("copy", g))
};

转自鲁小夫

如果答案设置了不能复制,则阻止copy事件,并显示提示信息,如果复制的文本长度小于42的话,不会加上版权信息。

关于copy事件:
https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement/oncopy
http://codebits.glennjones.net/editing/setclipboarddata.htm

概述

oncopy属性用来获取或设置当前元素的copy事件的事件处理函数.

语法

element.oncopy = functionRef;

functionRef 是一个函数名或者函数表达式.

例子

<html>
<head>
<title>oncopy示例演示</title>

<script>
  function log(txt)
  {
    document.getElementById("log").appendChild(document.createTextNode(txt + "\n"));
  }
</script>
</head>

<body>
<div oncopy="log('复制被阻止!'); return false;">试着复制这句话!</div>

<h3>Log</h3>
<textarea rows="15" cols="80" id="log" readonly="true"></textarea>
</body>
</html>

备注

上例演示了如何禁止复制浏览器中的一段话.

规范

当用户尝试复制选中元素或文本时会触发copy事件.

glennjones给出了更加复杂的js,包括OnCopy日志的提取

  • Some of the current browsers support a clipboardData property as part of a copy event. This should allow you to set the clipboard data or append custom data as a user copies an object. The support is patchy and mostly incomplete. The IE interface is older than the rest, but has had support for a while where as Chrome and Safari support has only recently been added. With IE you can only set two fixed data types Text or URL.

  • When parts of this paragraph of text are copied an event should fire that alters the copied test. When pasted into the box below you should see a custom message. It will currently only work with IE Chrome and Safari. Try it out by copying and pasting this paragraph into the input box below.

    The code

window.addEventListener('load', function (e) {

    var node = document.getElementById('edit-box');
    var copyNode = document.getElementById('custom-copy');

    copyNode.oncopy =function (e) {
        log('copy');
        if (e.clipboardData) {
            e.preventDefault();
            e.clipboardData.setData(
                'text/xcustom', 'Added this custom data at copy');

            var setStatus = e.clipboardData.setData(
                'text/plain', 'This is not the text you copied, it ' +
                'was changed by the copy event handler');
            log('setData: ' + setStatus);
        }
        if (window.clipboardData) {
            e.returnValue = false;
            var setStatus = window.clipboardData.setData(
                'Text', 'This is not the text you copied, it ' +
                'was changed by the copy event handler');
            log('setData: ' + setStatus);
        }
    };

    node.onpaste = function (e) {
        log('paste');
        if (e.clipboardData) {
            log('event.clipboardData');
            if (e.clipboardData.types) {
                log('event.clipboardData.types');

                // Look for a types property that is undefined
                if (!isArray(e.clipboardData.types)) {
                    log('event.clipboardData.types is undefined');
                }

                // Loop the data store by type and display it
                var i = 0;
                while (i < e.clipboardData.types.length) {
                    var key = e.clipboardData.types[i];
                    var val = e.clipboardData.getData(key);
                    log((i + 1) + ': ' + key + ' - ' + val);
                    i++;
                }

            } else {
                // Look for access to data if types array is missing
                var text = e.clipboardData.getData('text/plain');
                var url = e.clipboardData.getData('text/uri-list');
                var html = e.clipboardData.getData('text/html');
                var custom = e.clipboardData.getData('text/xcustom');
                log('text/plain - ' + text);
                if (url !== undefined) {
                    log('text/uri-list - ' + url);
                }
                if (html !== undefined) {
                    log('text/html - ' + html);
                }
                if (custom !== undefined) {
                    log('text/xcustom - ' + custom);
                }
            }
        }

        // IE event is attached to the window object
        if (window.clipboardData) {
            log('window.clipboardData');
            // The schema is fixed
            var text = window.clipboardData.getData('Text');
            var url = window.clipboardData.getData('URL');
            log('Text - ' + text);
            if (url !== null) {
                log('URL - ' + url);
            }
        }
        // Needs a few msec to excute paste
        window.setTimeout(logContents, 50, true);
    };

    // Button events
    var btn = document.getElementById('clear-logs');
    btn.onclick = function (e) {
        clearLog();
    };
});

function logContents() {
    var node = document.getElementById('edit-box');
    log('Current contents - ' + node.innerHTML);
}

function log(str) {
    var node = document.getElementById('log-box');
    var li = document.createElement('li')
    li.appendChild(document.createTextNode(str));
    node.appendChild(li);
}

function clearLog() {
    var node = document.getElementById('log-box');
    while (node.firstChild) {
        node.removeChild(node.firstChild);
    }
}

function isArray(obj) {
    return obj && !(obj.propertyIsEnumerable('length')) && 
        typeof obj === 'object' && typeof obj.length === 'number';
};

我写了一个这样的页面(有些浏览器不管用QAQ):



那下一步就是要在整个博客中应用版权代码了。。

由于我是用hexo搭建的这个blog,理论上来说需要在主题中更改模板。

于是这篇就先到这里,下一篇我们来研究如何更改hexo的主题文件~