Black-Hole Black-Hole - 4 months ago 8
CSS Question

Prevent user from copying text on browsers

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 copying the words from div) one way is check the written words only when a keyboard key is down, but I was wondering if there is a way to prevent the user from copying the text in a browser?

What I have tried so far:


  1. Disable right click (didn't work on mobile browsers)

  2. Show an alert using the onmousedown event in all the page (it didn't work either)



Using any libraries is OK.

Answer

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