deselecting or disabling grabbing of images and links - javascript

I built an application from HTML5, CSS, and Javascript. The issue is I want to stop the mouse from grabbing images and links on the page.
For example, if I hover the mouse over an image in my application and hold down the mouse, then move the mouse while holding down, a copy or translucent view of the image comes with the pointer. Until I let go of the mousedown. I would like to disable this if I can. The same goes for any anchor tags on my page (links).
Hope that makes somewhat sense. I have been searching and tried multiple solutions like:
Making the element: draggable=false
Using:
window.onload = function() {
document.onmousemove = function() {
return false;
};
};
not sure if this is written correctly...
Body: oncontextmenu="return false;">
Sorry, cannot seem to get code block to function correctly for the above???
Anyone know if this can be done?

In jQuery:
$(document).on('mouseover mousedown', 'a, img', function() {
return false;
});
jsFiddle example
Please note that this will not stop people copying your images/links - they can still view the page source. It will only prevent the default browser behaviour.

I think you can try:
$("img").draggable("option", "draggable", false);
And it should keep your image tags from being draggable.
[New update]
It probably might not work for your 'a' anchors though, that might have something to do with the browser.

Here is my solution to
prevent highlighting text ✓
prevent copying text ✓
prevent dragging objects like images ✓
disable right click completely ✓
JavaScript with jQuery reference:
$(document).ready(function() {
// disabling text highlight on all browser
$('body').each(function(){
$(this).css({
'-webkit-touch-callout': 'none',
'-webkit-user-select': 'none',
'-khtml-user-select': 'none',
'-moz-user-select': 'none',
'-ms-user-select': 'none',
'user-select': 'none'
});
});
// disabling cut, copy, paste of DOM elements
$(document).bind('cut copy paste', function(event) {
event.preventDefault();
});
// disabling image dragging
$('img').bind('mousedown selectstart', function(event) {
event.preventDefault();
});
});
// disabling right click completelly
function mischandler(){
return false;
}
function mousehandler(e){
var myevent = (isNS) ? e : event;
var eventbutton = (isNS) ? myevent.which : myevent.button;
if((eventbutton==2)||(eventbutton==3)) return false;
}
var isNS = (navigator.appName == "Netscape") ? 1 : 0;
if(navigator.appName == "Netscape") {
document.captureEvents(Event.MOUSEDOWN||Event.MOUSEUP);
}
document.oncontextmenu = mischandler;
document.onmousedown = mousehandler;
document.onmouseup = mousehandler;
CSS code
body * {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
jsFiddle sandbox

In regards to newer iPads or iPhones with forcetouch or 3D touch:
All link and image tags are draggable within safari by default, none of the CSS tricks for user-select or touch-callout fix it. Neither do the event blockers for ("mousedown" or "selectstart") fix it.
Simply add draggable=false directly into the tags
Visit W3Schools.com!
<img src="smiley.gif" draggable="false" alt="Smiley face" height="42" width="42">

Related

Prevent user from copying text on mobile 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:
Disable right click (didn't work on mobile browsers)
Show an alert using the onmousedown event in all the page (it didn't work either)
Using any libraries is OK.
You can simply make the text into an image.
<style type="text/css">
div.image {
width: 100px;
height: 100px;
background-image: url-to-your-image;
}
</style>
To generate the images you can use a server side script as in the aswers of this question
or something like this:
<?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);
?>
Test here
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.
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. Learn more about incognito browsing</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
Try putting a transparent div over the text.
I have used jQuery here.
That should work.
var position = $('#textInHere').position();
$('#noClickThroughThis').css({
height: ($('#textInHere').height()),
width: ($('#textInHere').width()),
position: 'absolute',
top: position.top,
left: position.left,
'z-index': 100
});
Here is a fiddle
http://jsfiddle.net/lacrioque/tc4bwejn/
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;
});
A good way to work out if a user is cheating is to compare the current input length to the last input length. You can use a data attribute to store the previous value (or length):
<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
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
You can try using :after tag and styling it with content: "Text"; in css, AFAIK you cannot select :before and :after's content.
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
Prevent pasting (optional)
Clearing clipboard (looks like it doesn't work well)
Absorbs all touch events
Disable right click
Disable user selections
Disable pointer events
Add a mask with a z-index inside any selected DOM
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;'> </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
A simpler solution than the accepted one would be to simply use a canvas element with filltext
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.fillText("Can't copy this", 5, 30);
<canvas id="myCanvas"></canvas>
JSFiddle example
You can return false on jQuery's cut copy paste events.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(document).on("cut copy paste", function(event){
return false;
});
</script>
<textarea>Try to copy my text</textarea>

Disable web page navigation on swipe(back and forward)

On a Windows phone, in IE users can go back and forward by swiping on the screen if the swipe is coming from the edge. This OS level functionality is hampering my webpage's UX.
Is there any js or css which can disable that? Some hack would also do.
A snapshot from windowsphone's website:
Here is the link to the reference page: http://www.windowsphone.com/en-in/how-to/wp8/basics/gestures-swipe-pan-and-stretch
Please note that I still need touchaction enabled for horizontal scrolling.
You Should Try this solution in two way :
1) CSS only fix for Chrome/Firefox
html, body {
overscroll-behavior-x: none;
}
2) JavaScript fix for Safari
if (window.safari) {
history.pushState(null, null, location.href);
window.onpopstate = function(event) {
history.go(1);
};
}
Over time, Safari will implement overscroll-behavior-x and we'll be able to remove the JS hack
Possible duplicate of iOS 7 - is there a way to disable the swipe back and forward functionality in Safari?
Copy and paste this JavaScript:
var xPos = null;
var yPos = null;
window.addEventListener( "touchmove", function ( event ) {
var touch = event.originalEvent.touches[ 0 ];
oldX = xPos;
oldY = yPos;
xPos = touch.pageX;
yPos = touch.pageY;
if ( oldX == null && oldY == null ) {
return false;
}
else {
if ( Math.abs( oldX-xPos ) > Math.abs( oldY-yPos ) ) {
event.preventDefault();
return false;
}
}
} );
If you want it minified, copy and paste this:
var xPos=null;var yPos=null;window.addEventListener("touchmove",function(event){var touch=event.originalEvent.touches[0];oldX=xPos;oldY=yPos;xPos=touch.pageX;yPos=touch.pageY;if(oldX==null && oldY==null){return false;}else{if(Math.abs(oldX-xPos)>Math.abs(oldY-yPos)){event.preventDefault();return false;}}});
How about preventing the default action of the swipe event. Somewhere in your document.ready add (note I've included the document.ready in this example, only the function needs to be added):
$(document).ready(function(){
$(window).on('touchmove',function(e){e.preventDefault();});
});
In this case I believe the event is called 'touchmove'you may need to extend this to also ignore default behavior of touchstart/touchend but I'm not 100% sure.
Check out this Codepen by David Hill.
var elem = document.getElementById("container"); //area we don't want touch drag
var defaultPrevent=function(e){e.preventDefault();}
elem.addEventListener("touchstart", defaultPrevent);
elem.addEventListener("touchmove" , defaultPrevent);
I actually think this is a cool way to build objects too.
This is also a problem for Mac users who have configured swipe-left to navigate backwards. You can't disable this setting, but you can prompt the user to confirm that they intended to navigate away https://developer.mozilla.org/en-US/docs/Web/Events/beforeunload.
*{
-webkit-touch-callout: none;
}
The result is to completely deactivate any touch events

iOS: disable bounce scroll but allow normal scrolling

I don't want the content of my site sloshing around when the user hits the edge of a page. I just want it to stop.
The omni-present javascript solution I see everywhere is this:
$(document).bind(
'touchmove',
function(e) {
e.preventDefault();
}
);
But this prevents scrolling entirely. Is there way to just remove the bounce. Preferably with CSS or a meta tag as opposed JS, but anything that works will do.
I have to add another answer.
My first approach should work, but, there is an iOS bug, which still bumbs the whole page, even if e.stopPropagation.
mikeyUX find a workaround for this: https://stackoverflow.com/a/16898264/2978727
I wonder why he just get a few clicks for this great idea...
This is how I used his approach in my case:
var content = document.getElementById('scrollDiv');
content.addEventListener('touchstart', function(event) {
this.allowUp = (this.scrollTop > 0);
this.allowDown = (this.scrollTop < this.scrollHeight - this.clientHeight);
this.slideBeginY = event.pageY;
});
content.addEventListener('touchmove', function(event) {
var up = (event.pageY > this.slideBeginY);
var down = (event.pageY < this.slideBeginY);
this.slideBeginY = event.pageY;
if ((up && this.allowUp) || (down && this.allowDown)) {
event.stopPropagation();
}
else {
event.preventDefault();
}
});
Disable bouncing by prevent the default behaviour of the document:
document.addEventListener("touchmove", function(event){
event.preventDefault();
});
Allow scrolling by prevent that the touch reaches the document level (where you would prevent the scrolling):
var scrollingDiv = document.getElementById('scrollDiv');
scrollingDiv.addEventListener('touchmove', function(event){
event.stopPropagation();
});
Mind the difference between these two:
event.stopPropagation()
event.preventDefault()
StopPropagation should be your choice here !
Here is a very good explanation:
http://davidwalsh.name/javascript-events
Edit:
Same problem, same solution:
document.ontouchmove and scrolling on iOS 5
Edit2:
fixed typo in variable names
added brackets after methods
If apply to Desktop Browser, don't need any JavaScript codes, just few lines of CSS codes:
html {
height : 100%;
overflow: hidden;
}
body {
height : 100%;
overflow: auto;
}
I tried lots of different approaches I found here on stackoverflow, but iNoBounce was the thing that really worked for me:
https://github.com/lazd/iNoBounce
I just included it in my index.html:
<script src="inobounce.js"></script>
This library is solution for my scenarios. Easy way to use just include library and initialize where you want like these;
noBounce.init({
animate: true
});
If you want to prevent bouncing only on one element and not on the whole page you can do it like:
noBounce.init({
animate: true,
element: document.getElementById("content")
});
iOS 16 started support of css overscroll-behavior.
If you are targeting > iOS 16 devices (including its WKWebview), to prevent overscroll bounce, the solution is simple
add following CSS
html {
overscroll-behavior: none;
}
Tested in iOS 16 and above.
Found a code that worked to me, I believe it will work to you.
The solution is written here: http://apdevblog.com/optimizing-webkit-overflow-scrolling/
Basically, you need to have this js code:
document.addEventListener("DOMContentLoaded", ready, false);
document.addEventListener("touchmove", function (evt)
{
evt.preventDefault();
}, false);
function ready()
{
var container = document.getElementsByClassName("scrollable")[0];
var subcontainer = container.children[0];
var subsubcontainer = container.children[0].children[0];
container.addEventListener("touchmove", function (evt)
{
if (subsubcontainer.getBoundingClientRect().height > subcontainer.getBoundingClientRect().height)
{
evt.stopPropagation();
}
}, false);
}
And then, have your scrollable divs with the class="scrollable".
After trying these suggestions and reading several articles, the fix for me was to use the CSS property < overflow-x: hidden; > on the problematic element/container.

No outline on mouse focus but still have outline on keyboard focus?

When elements of a page have focus (such as a link or button), they show an outline. I would like this outline to only display when that element was given focus by the keyboard, not by the mouse.
Is it possible to determine how that element got its focus with JavaScript? If so, how do I then control the browser's own outlining feature?
Browsers use the CSS outline property to show which element has the focus, as you might already know. So, in jQuery, you might use:
$(document).ready(function() {
$("body").on("mousedown", "*", function(e) {
if (($(this).is(":focus") || $(this).is(e.target)) && $(this).css("outline-style") == "none") {
$(this).css("outline", "none").on("blur", function() {
$(this).off("blur").css("outline", "");
});
}
});
});
Explanation: This function looks for the mousedown event on any element. This event is delegated, meaning it will apply to elements currently on the page as well as any created dynamically in the future. When the mouse is clicked over the element, its CSS outline property is set to none; the outline is removed.
The targeted element gets a new handler for blur. When focus is taken from the element, the outline property is set to a blank string (this removes it from the element's style attribute), allowing the browser to control the outline again. Then, the element removes its own blur handler to free up memory. This way, an element is only outlined when focused from the keyboard.
Edit
Based on Rakesh's comments below, I made a slight change. The function can now detect if there's already an outline set, and will avoid overriding it. Demo here.
http://jsfiddle.net/np3FE/2/
$(function(){
var lastKey = new Date(),
lastClick = new Date();
$(document).on( "focusin", function(e){
$(".non-keyboard-outline").removeClass("non-keyboard-outline");
var wasByKeyboard = lastClick < lastKey
if( wasByKeyboard ) {
$( e.target ).addClass( "non-keyboard-outline");
}
});
$(document).on( "click", function(){
lastClick = new Date();
});
$(document).on( "keydown", function() {
lastKey = new Date();
});
});
CSS
*:active, *:focus {
outline: none;
}
*:active.non-keyboard-outline, *:focus.non-keyboard-outline {
outline: red auto 5px;
}
Removing outline is terrible for accessibility! Ideally, the focus ring shows up only when the user intends to use the keyboard.
2018 Answer: Use :focus-visible. It's currently a W3C proposal for styling keyboard-only focus using CSS. Until major browsers support it, you can use this robust polyfill. It doesn't require adding extra elements or altering the tabindex.
/* Remove outline for non-keyboard :focus */
*:focus:not(.focus-visible) {
outline: none;
}
/* Optional: Customize .focus-visible */
.focus-visible {
outline-color: lightgreen;
}
I also wrote a more detailed post with some demo just in case you need more info.
One easy way I can see is to use the mouse event to prevent the focus from firing.
$('#element').click(function(){
$(this).blur();
});
This brings a potencial problem that you won't be able to use the mouse to select the element at all. So you can also just add a class and adjust the focus style.
$('#element').click(function(){
$(this).addClass('fromMouse');
});
$('#element').blur(function(){
if($(this).hasClass('fromMouse'){
$(this).removeClass('fromMouse');
}
});
CSS
.fromMouse{
outline: none;
}
http://api.jquery.com/blur/
CSS
:focus{
outline: none;
}
.outline{
outline: 2px solid rgba(200,120,120, 0.8);
}
jQuery code
$(function(){
$('*').on('keydown.tab', function(e){
/*
TAB or Shift Tab, Aw.
Add some more key code if you really want
*/
if ( 9== e.which && this == e.target ){
window.setTimeout( function(){
$('.outline').removeClass('outline');
$(document.activeElement).addClass('outline');
}, 100 );
}
});
});
This works fine. You will get outline only when the element is focused using Keyboard ( I am aware of Tab and Shift Tab only, you can add more though )
See it working:
http://jsbin.com/okarez/1
Based on #theftprevention answer, a more customisable solution can be :
$(function(){
$('body')
.on('focus', '*', function() {
var e = $(this);
if (!e.is('.focus-mouse')) {
e.addClass('focus-keyboard');
}
})
.on('mousedown', '*', function() {
$(this).removeClass('focus-keyboard').addClass('focus-mouse');
})
.on('blur', '*', function() {
$(this).removeClass('focus-keyboard').removeClass('focus-mouse');
});
});
Now, you just have to cutomize using .focus-keyboard and .focus-mouse classes in CSS.
.focus-keyboard{
background:#eeeeee;
}
.focus-mouse{
outline: 0;
}
you can add class to body to know css if user is currently using mouse or keyboard
document.body.addEventListener('mousedown', function() {
document.body.classList.add('using-mouse');
});
document.body.addEventListener('keydown', function() {
document.body.classList.remove('using-mouse');
});
and in css
:focus {
outline: #08f auto 2px;
}
body.using-mouse :focus {
outline: none;
}

When I click on a canvas and drag my mouse, the cursor changes to a text-selection cursor. How can I prevent this?

Here's a fiddle: http://jsfiddle.net/MZ9Xm/
Note: The following occurs in Chrome 22.0.1221.1, but not in Firefox 14.0.1. [Ubuntu linux]
Move your mouse to the top canvas and press and hold the mouse button. Drag the mouse, and the cursor will change to a text-selection mouse cursor (I-bar). This does not happen if there are no other elements on the page.
I've messed around with setting user-selection to none, but have not had any luck.
You can bind a mousedown event in your canvas to prevent default behavior.
Something like:
// with jQuery
$( "#canvasId" ).mousedown(function(event){
event.preventDefault();
});
// without jQuery
document.getElementById( "canvasId" ).onmousedown = function(event){
event.preventDefault();
};
Here is the updated fiddle: http://jsfiddle.net/MZ9Xm/1/
You will need to test this to see if there is some side effect in what you are doing.
Have you tried using the CSS cursor property ?
canvas {
cursor: pointer;
}
It should display the default cursor.
Try this:
var canvasEls = document.getElementsByTagName('canvas'),
preventHl = function () { return false; },
i = 0;
while (i < canvasEls.length) {
canvasEls[i].onmousedown = preventHl;
i += 1;
}
Returning false will prevent default actions such as highlighting from occurring.

Categories

Resources