Запретить пользователю копировать текст в браузерах

Я пытаюсь разработать конкуренцию скорости ввода с использованием JavaScript. Люди должны писать все слова, которые они видят из div, в текстовое поле.

Чтобы предотвратить обман (например, копирование слов из div), один из способов - проверить написанные слова только тогда, когда клавиатура нажата, но мне было интересно, есть ли способ предотвратить копирование текста пользователем в браузере?

То, что я пробовал до сих пор:

  • Отключить правый щелчок (не работает в мобильных браузерах)
  • Показывать оповещение, используя событие onmousedown на всей странице (это тоже не сработало)

Использование любых библиотек в порядке.

Ответ 1

Спасибо за ваши замечательные решения. Я тестировал их все, а вкратце некоторые из них работали только на ПК, некоторые только на Chrome и Firefox, а некоторые только на Safari, но, к сожалению, ни один из них не работал на 100%.

Хотя ответ @Max может быть самым безопасным, я не помещал PHP в вопрос, потому что, если я использую это решение для ответов, это будет сложно, потому что у меня нет доступа к словам на стороне клиента!

Итак, окончательное решение, с которым я пришел, состояло в объединении всех предоставленных ответов плюс некоторые новые методы (например, очистка буфера обмена каждую секунду) в плагин jQuery. Теперь он работает и с несколькими элементами и работает на ПК на 100%, Firefox, Chrome и Safari.


Что делает этот плагин

  • Предотвращение вставки (необязательно)
  • Очистка буфера обмена (похоже, что он не работает)
  • Поглощает все события касания
  • Отключить правый клик
  • Отключить выбор пользователя
  • Отключить события указателя
  • Добавьте маску с z-индексом внутри любого выбранного DOM
  • Добавить прозрачный div для любого выбранного DOM

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

Использование

$(document).ready(function(){

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

});

HTML для демонстрации:

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

Сообщите мне свое мнение. Спасибо.

Источники

Ответ 2

Вы можете просто сделать текст в изображении.

<style type="text/css">
div.image {
    width: 100px;
    height: 100px;
    background-image: url-to-your-image;
}
</style>

Чтобы сгенерировать изображения, вы можете использовать серверную часть script, как в aswers этот вопрос

или что-то вроде этого:

<?php
header("Content-type: image/png");
$im = @imagecreate(210, 30)
or die("Cannot Initialize new GD image stream");
$background_color = imagecolorallocate($im, 255, 255, 255);
$text_color = imagecolorallocate($im, 0, 0, 0);
imagestring($im, 4, 5, 5,  "This is a test", $text_color);
imagepng($im);
imagedestroy($im);
?> 

Проверить здесь

Ответ 3

Один сумасшедший способ сделать это - выложить еще один абсолютно позиционированный элемент поверх этого. Но это также запретит клики по ссылкам! Возможно, вы можете сделать это с помощью position: relative и более высокого 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>

Ответ 4

Попробуйте поставить прозрачный div над текстом. Я использовал jQuery здесь. Это должно работать.

var position = $('#textInHere').position();
$('#noClickThroughThis').css({
    height: ($('#textInHere').height()),
    width:  ($('#textInHere').width()),
    position: 'absolute',
    top: position.top,
    left: position.left,
    'z-index': 100
});

Вот скрипка http://jsfiddle.net/lacrioque/tc4bwejn/

Ответ 5

Вы можете запретить пользователю фактически выбирать текст, чтобы он не мог быть скопирован - однако я бы все же сочетал это с обнаружением пасты, как рекомендовали другие

.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>

Ответ 6

Легко отключить функцию вставки с помощью jQuery. Например, если у вас есть поле редактирования, подобное этому:

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

Затем этот кусок кода jQuery отключит функцию вставки:

$('#someInput').on('paste', function(e) {
  return false;
});

Ответ 7

Хороший способ работать, если пользователь обманывает, - сравнить текущую длину ввода с последней длиной ввода. Вы можете использовать атрибут data для хранения предыдущего значения (или длины):

<textarea class="typing-only" data-temp=""></textarea>

JQuery

$(document).on('input', '.typing-only', function(){
    if((this.value.length - 1) > $(this).data('temp').length){
        alert('Cheat!');
    }
    $(this).data('temp', this.value);
});

JSFiddle demo

Ответ 8

pointer-events: none

CSS pointer-events позволяет вам контролировать взаимодействие между элементом и мышью. Если установлено значение none, элемент никогда не является объектом событий мыши.

Страница определения MDN

Ответ 9

Вы можете попробовать использовать тег : после и стилизовать его с помощью контента: "Текст"; в css, AFAIK вы не можете выбрать: до и: после содержимого.

Ответ 10

Более простым решением, чем принятое, было бы просто использовать элемент canvas с filltext

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.fillText("Can't copy this", 5, 30);
<canvas id="myCanvas"></canvas>