Prevent user from copying text on mobile browsers

前端 未结 11 2084
陌清茗
陌清茗 2021-02-20 01:57

I\'m trying to develop a typing speed competition using JavaScript. People should write all the words they see from a div to a textarea.

To prevent cheating (like copyin

相关标签:
11条回答
  • 2021-02-20 01:57

    You can prevent the user from actually selecting the text so it can not be copied - however I'd still combine this with paste detection as others recommended

    .noselect {
        -moz-user-select: none;
        -webkit-user-select: none;
        -ms-user-select: none;
        user-select: none;
    }
    <p>this can be selected</p>
    <p class="noselect">this can NOT be selected</p>

    But the user can still open the page source and copy it from there.

    0 讨论(0)
  • 2021-02-20 01:58

    It's easy to disable the paste feature by using jQuery. For example, if you have an edit field like this one:

    <p id='someInput' contenteditable='true'>Here is the text</p>
    

    Then, this piece of jQuery code will disable the pasting feature on it:

    $('#someInput').on('paste', function(e) {
      return false;
    });
    
    0 讨论(0)
  • 2021-02-20 01:58

    pointer-events: none

    CSS pointer-events allows you to control the interaction between an element and the mouse. When set to none, the element is never the target of mouse events.

    MDN definition page

    0 讨论(0)
  • 2021-02-20 01:58

    Thanks for your amazing solutions. I tested all of them, and in short some of them worked only on a PC, some only on Chrome and Firefox and some only on Safari, but unfortunately none of them worked 100%.

    Although @Max answer might be safest, I didn't tag with PHP in the question because if I use this solution dealing with answers, it will be hard because I don't have access to words on the client side!

    So the ultimate solution I came with was combining all of the provided answers plus some new methods (like clearing the clipboard every second) into a jQuery plugin. Now it works on multiple elements too and worked 100% on PC browsers, Firefox, Chrome, and Safari.


    What this plugin does

    1. Prevent pasting (optional)
    2. Clearing clipboard (looks like it doesn't work well)
    3. Absorbs all touch events
    4. Disable right click
    5. Disable user selections
    6. Disable pointer events
    7. Add a mask with a z-index inside any selected DOM
    8. Add a transparent div on any selected DOM

    A jsFiddle:

    (function($) {
    
        $.fn.blockCopy = function(options) {
    
            var settings = $.extend({
                blockPasteClass    : null
            }, options);
    
            if(settings.blockPasteClass){
                $("." + settings.blockPasteClass ).bind('copy paste cut drag drop', function (e) {
                    e.preventDefault();
                    return false;
                });
            }
    
            function style_appender(rule){
                $('html > head').append($('<style>'+rule+'</style>'));
            }
    
            function html_appender(html){
                $("body").append(html);
            }
    
            function clearClipboard() {
                var $temp = $("#bypasser");
                $temp.val("You can't cheat !").select();
                document.execCommand("copy");
            }
    
            function add_absolute_div(id) {
                html_appender("<div id='noClick"+id+"' onclick='return false;' oncontextmenu='return false;'>&nbsp;</div>");
            }
    
            function absorbEvent_(event) {
                var e = event || window.event;
                e.preventDefault && e.preventDefault();
                e.stopPropagation && e.stopPropagation();
                e.cancelBubble = true;
                e.returnValue = false;
                return false;
            }
    
            function preventLongPressMenu(node) {
                node.ontouchstart = absorbEvent_;
                node.ontouchmove = absorbEvent_;
                node.ontouchend = absorbEvent_;
                node.ontouchcancel = absorbEvent_;
            }
    
            function set_absolute_div(element,id){
                var position = element.position();
                var noclick = "#noClick" + id;
    
                $(noclick).css({
                    height: (element.height()),
                    width:    (element.width()),
                    position: 'absolute',
                    top: position.top,
                    left: position.left,
                    'z-index': 100
                })
            }
    
    
            $("body").bind("contextmenu", function(e) {
                e.preventDefault();
            });
    
            //Append needed rules to CSS
            style_appender(
                "* {-moz-user-select: none !important; -khtml-user-select: none !important;   -webkit-user-select: none !important; -ms-user-select: none !important;   user-select: none !important; }"+
                ".content {position: relative !important; }" +
                ".content .mask {position: absolute !important ; z-index: 1 !important; width: 100% !important; height: 100%!important;}" +
                ".content a {position: relative !important; z-index: 3 !important;}"+
                ".content, .content .mask{ pointer-events: none;}"
            );
    
    
            //Append an input to clear the clipboard
            html_appender("<input id='bypasser' value='nothing' type='hidden'>");
    
            //Clearing clipboard Intervali
            setInterval(clearClipboard,1000);
    
            var id = 1;
    
            return this.each( function() {
    
                //Preventing using touch events
                preventLongPressMenu($(this));
    
                //Add CSS preventer rules to selected DOM & append mask to class
                $(this).addClass("content").append("<div class='mask'></div>");
    
                //Append an absolute div to body
                add_absolute_div(id);
    
                //Set position of the div to selected DOM
                set_absolute_div($(this),id);
    
                id++;
            });
        }
    }(jQuery));
    

    Usage

    $(document).ready(function(){
    
        $(".words").blockCopy({
            blockPasteClass : "noPasting"
        });
    
    });
    

    HTML for demo:

    <div class="words">Test1: Can you copy me or not?</div><br>
    <div class="words">Test2: Can you <br> copy me or not?</div><br>
    <textarea class="words">Test3: Can you <br>copy me or not?</textarea><br>
    
    
    <textarea  class="noPasting"   placeholder="Test1: Paste content if you can"   ></textarea><br>
    
    <textarea  class="noPasting"   placeholder="Test2: Paste content if you can"   ></textarea>
    

    Let me know your opinions. Thanks.

    Sources

    • Answers to this question

    • Copy text to clipboard

    • Add CSS rule using jQuery

    0 讨论(0)
  • 2021-02-20 02:09

    One crazy way of doing this is, laying out another absolutely positioned element on top of this. But this will disallow clicking of links too! May be you can do it with position: relative and a higher z-index.

    .content {position: relative;}
    .content .mask {position: absolute; z-index: 1; width: 100%; height: 100%;}
    .content a {position: relative; z-index: 3;}
    <div class="content">
      <div class="mask"></div>
      <p>Pages that you view in incognito tabs won’t stick around in your browser’s history, cookie store or search history after you’ve closed <strong>all</strong> of your incognito tabs. Any files that you download or bookmarks that you create will be kept. <a href="https://support.google.com/chrome/?p=incognito">Learn more about incognito browsing</a></p>
    </div>

    Try using the touch or longpress events.

    <!DOCTYPE html>
    <html>
    <head>
      <script>
        function absorbEvent_(event) {
          var e = event || window.event;
          e.preventDefault && e.preventDefault();
          e.stopPropagation && e.stopPropagation();
          e.cancelBubble = true;
          e.returnValue = false;
          return false;
        }
    
        function preventLongPressMenu(node) {
          node.ontouchstart = absorbEvent_;
          node.ontouchmove = absorbEvent_;
          node.ontouchend = absorbEvent_;
          node.ontouchcancel = absorbEvent_;
        }
    
        function init() {
          preventLongPressMenu(document.getElementById('theimage'));
        }
      </script>
    </head>
    <body onload="init()">
      <img id="theimage" src="http://www.google.com/logos/arthurboyd2010-hp.jpg" width="400">
    </body>
    </html>
    

    Source

    0 讨论(0)
  • 2021-02-20 02:10

    You can try using :after tag and styling it with content: "Text"; in css, AFAIK you cannot select :before and :after's content.

    0 讨论(0)
提交回复
热议问题