Enable double tap event while allowing scrolling using Jquery - javascript

I have been developing mobile apps using Cordova/Phonegap and this time I had to enable a double tap on rows of one specific table. I don't want to use a plugin or another library for it as it is only for one part of the app. How do I check double tap on Javascript?

So I searched "How do I check for double tap in javascript?", and voila! using #mfirdaus answer in this question I solved it. But I came to another issue, I cant scroll. So I searched "How do I enable scrolling while checking for double tap?" and found the answer here very useful.
I compiled both answers to create a function that attaches a double tap event on a given element:
var tapped = false;
var isDragging = false;
function attachDoubleTap(elem, callbacks) {
callbacks = callbacks || {};
callbacks.onSingleTap = callbacks.onSingleTap || function() {}
callbacks.onDoubleTap = callbacks.onDoubleTap || function() {}
$(document)
.on('touchstart', elem, function(e) {
$(window).bind('touchmove', function() {
isDragging = true;
$(window).unbind('touchmove');
});
})
.on('touchend', elem, function(e) {
var wasDragging = isDragging;
isDragging = false;
$(window).unbind("touchmove");
if (!wasDragging) { //was clicking
//detect single or double tap
var _this = $(this);
if(!tapped){ //if tap is not set, set up single tap
tapped=setTimeout(function(){
tapped=null
//insert things you want to do when single tapped
callbacks.onSingleTap(_this);
},200); //wait 300ms then run single click code
} else { //tapped within 300ms of last tap. double tap
clearTimeout(tapped); //stop single tap callback
tapped=null
//insert things you want to do when double tapped
callbacks.onDoubleTap(_this);
}
}
})
}
$(document).ready(function() {
attachDoubleTap('#canvas', {
onSingleTap: function() {
$('.msg').text('single tap');
},
onDoubleTap: function() {
$('.msg').text('double tap');
},
onMove: function() {
$('.msg').text('moved');
}
});
});
var tapped = false;
var isDragging = false;
function attachDoubleTap(elem, callbacks) {
callbacks = callbacks || {};
callbacks.onSingleTap = callbacks.onSingleTap || function() {}
callbacks.onDoubleTap = callbacks.onDoubleTap || function() {}
callbacks.onMove = callbacks.onMove || function() {}
$(document)
.on('touchstart', elem, function(e) {
$(window).bind('touchmove', function() {
isDragging = true;
callbacks.onMove();
$(window).unbind('touchmove');
});
})
.on('touchend', elem, function(e) {
var wasDragging = isDragging;
isDragging = false;
$(window).unbind("touchmove");
if (!wasDragging) { //was clicking
//detect single or double tap
var _this = $(this);
if (!tapped) { //if tap is not set, set up single tap
tapped = setTimeout(function() {
tapped = null
//insert things you want to do when single tapped
callbacks.onSingleTap(_this);
}, 200); //wait 300ms then run single click code
} else { //tapped within 300ms of last tap. double tap
clearTimeout(tapped); //stop single tap callback
tapped = null
//insert things you want to do when double tapped
callbacks.onDoubleTap(_this);
}
}
})
}
body {
font-family: arial;
}
#canvas {
width: 500px;
height: 450px;
background-color: #b0dddf;
border: 1px solid #ccc;
}
.msg {
border: 1px solid #ccc;
margin: 0 auto;
width: 300px;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="canvas">
<ul>
<li>Try to tap once</li>
<li>Try to tap twice</li>
<li>Try to tap and drag</li>
</ul>
<div class='msg'></div>
</div>
I hope this helps someone in the future. (I only included the Move() callback on the snippet to show it is working, it is up to you to add it to the function)

Related

Prevent click event if dragged

I asked a related question here
I'm trying to stop click events if dragged.
I think the simplest version of this is dragging yourself. Basically IF the user presses down, then moves, then releases I don't want a click event.
Note, the code below is not trying to allow click, it's trying only to prevent it. I thought calling preventDefault in mouseup would tell the browser, don't do the default thing, that being sending a click event because the user let up on the mouse.
let dragTarget;
let dragMouseStartX;
let dragMouseStartY;
let dragTargetStartX;
let dragTargetStartY;
const px = v => `${v}px`;
function dragStart(e) {
e.preventDefault();
e.stopPropagation();
dragTarget = this;
const rect = this.getBoundingClientRect();
dragMouseStartX = e.pageX;
dragMouseStartY = e.pageY;
dragTargetStartX = (window.scrollX + rect.left) | 0;
dragTargetStartY = (window.scrollY + rect.top) | 0;
window.addEventListener('mousemove', dragMove, {passive: false});
window.addEventListener('mouseup', dragStop, {passive: false});
}
function dragMove(e) {
if (dragTarget) {
e.preventDefault();
e.stopPropagation();
const x = dragTargetStartX + (e.pageX - dragMouseStartX);
const y = dragTargetStartY + (e.pageY - dragMouseStartY);
dragTarget.style.left = px(x);
dragTarget.style.top = px(y);
}
}
function dragStop(e) {
e.preventDefault();
e.stopPropagation();
dragTarget = undefined;
window.removeEventListener('mousemove', dragMove);
window.removeEventListener('mouseup', dragStop);
}
document.querySelector('.drag').addEventListener('mousedown', dragStart);
document.querySelector('.drag').addEventListener('click', () => {
console.log('clicked', new Date());
});
body { height: 100vh; }
.drag {
background: red;
color: white;
padding: 1em;
position: absolute;
user-select: none;
cursor: pointer;
}
<div class="drag">drag and release me</div>
One solution is to remove the click event and just do it myself in mouseup. If there was no movement call whatever I was going to call for click
But, in my actual use case dragging is on the parent like this (you can drag red or blue)
let dragTarget;
let dragMouseStartX;
let dragMouseStartY;
let dragTargetStartX;
let dragTargetStartY;
const px = v => `${v}px`;
function dragStart(e) {
e.preventDefault();
e.stopPropagation();
dragTarget = this;
const rect = this.getBoundingClientRect();
dragMouseStartX = e.pageX;
dragMouseStartY = e.pageY;
dragTargetStartX = (window.scrollX + rect.left) | 0;
dragTargetStartY = (window.scrollY + rect.top) | 0;
window.addEventListener('mousemove', dragMove, {passive: false});
window.addEventListener('mouseup', dragStop, {passive: false});
}
function dragMove(e) {
if (dragTarget) {
e.preventDefault();
e.stopPropagation();
const x = dragTargetStartX + (e.pageX - dragMouseStartX);
const y = dragTargetStartY + (e.pageY - dragMouseStartY);
dragTarget.style.left = px(x);
dragTarget.style.top = px(y);
}
}
function dragStop(e) {
e.preventDefault();
e.stopPropagation();
dragTarget = undefined;
window.removeEventListener('mousemove', dragMove);
window.removeEventListener('mouseup', dragStop);
}
document.querySelector('.drag').addEventListener('mousedown', dragStart);
document.querySelector('.click').addEventListener('click', () => {
console.log('clicked', new Date());
});
body { height: 100vh; }
.drag {
background: blue;
color: white;
padding: 2em;
position: absolute;
user-select: none;
cursor: pointer;
}
.click {
padding: 1em;
background: red;
}
<div class="drag"><div class="click">drag and release me</div></div>
So now the 2 elements are not related directly but, if the user drags on red I don't want the inner element to get a click event. Also note in my real code there are lots of child elements that I don't want to receieve click events in the same way (parent is the drag target). Note: again, in the example above I'm just trying to stop all click events (calling preventDefault) and failing.
I can think of lots of hacky solutions, for example 2 are.
In the first mousemove event, search all children for click event listeners, remove all of them, on mouseup restore them (possibly after a timeout)
In mouseup, set a flag to ignore clicks and set a timeout to clear the flag, have all click listeners no-op if the flag is set.
Both of those require a bunch of coordination.
In the first, I'd need to write some kind of system to keep track of click handlers and the elements they are on so I can save and restore them so instead of elem.addEventListener('click', someHandler) it would have to be more like registerClickListener(elem, someHandler). Not hard but if I forget then it fails.
In the second I'd have to remember to always check some global variable in every listener implemention.
elem.addEventListener('click', () => {
if (ignoreClicks) return;
...
})
Again if I forget then it fails. By forget I mean much much deeper in the DOM in unrelated code.
Both seem semi error prone so wondering if there is some other solution I'm overlooking that works like I thought preventDefault would work.
I could wrap addEventListener so for click handlers it adds a wrapper to filter out unwanted clicks. That's less error prone but it seems overkill.
Am I missing a simpler solution?
I think how it works is that click fires after a mouseup and mousedown occur on the same element and doesn't wait to see what they do (e.g. trying to stop the click from happening).
The easiest way I've seen to stop this from happening is by disabling pointer events for that element while dragging. It changes the cursor to default while dragging which isn't optimal but that might be avoidable and this is still my fav solution. For example:
let dragTarget;
let dragMouseStartX;
let dragMouseStartY;
let dragTargetStartX;
let dragTargetStartY;
const px = v => `${v}px`;
function dragStart(e) {
dragTarget = this;
dragTarget.classList.add("dragging");
const rect = this.getBoundingClientRect();
dragMouseStartX = e.pageX;
dragMouseStartY = e.pageY;
dragTargetStartX = (window.scrollX + rect.left) | 0;
dragTargetStartY = (window.scrollY + rect.top) | 0;
window.addEventListener('mousemove', dragMove, {passive: false});
window.addEventListener('mouseup', dragStop, {passive: false});
return false;
}
function dragMove(e) {
if (dragTarget) {
e.preventDefault();
e.stopPropagation();
const x = dragTargetStartX + (e.pageX - dragMouseStartX);
const y = dragTargetStartY + (e.pageY - dragMouseStartY);
dragTarget.style.left = px(x);
dragTarget.style.top = px(y);
}
}
function dragStop(e) {
dragTarget.classList.remove("dragging");
dragTarget = undefined;
window.removeEventListener('mousemove', dragMove);
window.removeEventListener('mouseup', dragStop);
}
document.querySelector('.drag').addEventListener('mousedown', dragStart);
document.querySelector('.click').addEventListener('click', () => {
console.log('clicked', new Date());
});
body { height: 100vh; }
.drag {
background: blue;
color: white;
padding: 2em;
position: absolute;
user-select: none;
cursor: pointer;
}
.click {
padding: 1em;
background: red;
}
.dragging {
pointer-events: none;
}
<div class="drag"><div class="click">drag and release me</div></div>
Some of the other options you were thinking of going down are certainly possible but this is the simplest in my opinion that should work for a lot of use cases.
I got the idea for this solution from this answer here:
https://stackoverflow.com/a/24273710/12259250
I believe some of the other answers to that question mimicked some of your alternatives so you can check those out too.
There is an optional third argument for addEventListener called capture which indicates that your function is called before the event function of any other element. By setting it to true and apply on your root element (window) you can simply shut off all click events by setting a flag.
let ignoreClicks = true; // switch me to turn on click events
document.getElementById ('d1').addEventListener ('click', function() { console.log ('d1'); });
document.getElementById ('d2').addEventListener ('click', function() { console.log ('d2'); });
window.addEventListener ('click', function (event) {
if (ignoreClicks) event.stopPropagation();
}, true );
<div id="d1" style="background-color:red;width:200px;height:100px;"></div>
<div id="d2" style="background-color:green;width:200px;height:100px;"></div>

How would I prevent redirecting of a href during touchmove and mousemove?

I've got an issue while I'm trying to combine touchstart and mousedown in 1 function. I've used an a tag as the target element of the function for going to the link directly when I touched or clicked the tag.
The issue is when I touch the middle of a tag, link doesn't respond. it only works when I click the element or touch the edge of the a tag, and the output fires mousedown.
In the mobile mode, try to click the edge of a tag as much as you would possible like a grey dot in the picture above. I've created an CodePen example for looking, testing and understanding better.
How would I fix this issue?
class Slider {
constructor($el, paragraph) {
this.$el = $el;
this.paragraph = paragraph;
}
start(e) {
e.preventDefault();
var type = e.type;
if (type === 'touchstart' || type === 'mousedown') this.paragraph.text(this.paragraph.text() + ' ' + type);
return false;
}
apply() {
this.$el.bind('touchstart mousedown', (e) => this.start(e));
}
}
const setSlider = new Slider($('#anchor'), $('.textbox'), {passive: false});
setSlider.apply();
a {
display: block;
width: 100px;
height: 100px;
background-color: orange;
}
<a id="anchor" href="https://google.co.uk">Tap or Click Me</a>
<p class="textbox"></p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
========= Progress Update ==========
I've just added move & end function then I have to click twice for moving on to the linked website. It keeps getting worse and have no idea how to solve this issue.
class Slider {
constructor($el, paragraph) {
this.$el = $el;
this.paragraph = paragraph;
}
start(e) {
e.preventDefault();
var type = e.type;
if (type === 'touchstart' || type === 'mousedown') this.paragraph.text(this.paragraph.text() + ' ' + type);
this.$el.bind('touchmove mousemove', (e) => this.move(e));
this.$el.bind('touchend mouseup', (e) => this.end(e));
return false;
}
move(e) {
var type = e.type;
if (type === 'touchstart' || type === 'mousedown') this.paragraph.text(this.paragraph.text() + ' ' + type);
return false;
}
end(e) {
console.log('test');
this.$el.on('click');
this.$el.off('touchstart touchend');
return false;
}
apply() {
this.$el.bind('touchstart || mousedown', (e) => this.start(e));
}
}
const setSlider = new Slider($('#anchor'), $('.textbox'));
setSlider.apply();
======== Progress Updated After Bounty (Latest) ========
After dozens of tried, I've finally figured out and solve the previous problem but I've faced up a new issue that can't draggable and redirecting instantly.
When I use the preventDefault in the start function, all of the events work fine. The only issue of this case is dragging doesn't prevent redirecting link from the a tag. It always send me to the website no matter which ways to call the functions, clicked or dragged.
when I don't use the preventDefault, dragging doesn't work. it only works clicking the elements.
My final goal is to prevent redirecting link of the a tag from the both events, touchmove and mousemove. I've been searched about on google so many times but haven't got any of the clues.
I've written an example in Codepen and this is what I've done so far:
class Slider {
constructor($el, paragraph) {
this.$el = $el;
this.paragraph = paragraph;
}
start(e) {
var type = e.type;
if (type === 'touchstart') {
this.paragraph.text(this.paragraph.text() + ' ' + type);
} else if (type === 'mousedown') {
this.paragraph.text(this.paragraph.text() + ' ' + type);
}
}
move(e) {
var type = e.type;
}
end(e) {
var type = e.type;
if (type === 'touchend') {
console.log('touchstart enabled');
} else if (type === 'mouseup') {
console.log('mousedown enabled');
}
}
apply() {
this.$el.bind({
touchstart: (e) => this.start(e),
touchmove: (e) => this.move(e),
touchend: (e) => this.end(e),
mousedown:(e) => this.start(e),
onmousemove: (e) => this.move(e),
mouseup: (e) => this.end(e)
});
}
}
const setSlider = new Slider($('#anchor'), $('.textbox'));
setSlider.apply();
a {
display: block;
width: 100px;
height: 100px;
background-color: orange;
}
<a id="anchor" href="https://google.co.uk">Tap or Click Me</a>
<p class="textbox"></p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I think I found the solution about this. I add this code for some people in the future who are trying hard to search the same problem such as me.
function start(event, etype, condition) {
console.log(etype); // track the type of event
if (!condition) event.preventDefault(); // compare etype(eventType). Set preventDefault if condition is falsy.
items.off('click');
items.on({
['touchmove mousemove']: (event) => move(event, etype, condition),
['touchend mouseup']: end
});
}
function move(event, etype, cnd) {
if (cnd) event.preventDefault();
console.log(cnd); // track the type of event from the condition
items.on('click', function(event) {event.preventDefault();});
}
function end(event) {
items.off('touchmove mousemove touchend mouseup');
}
var items = $('.item a');
items.on('touchstart mousedown', function() {
var eventType = event.type;
var condition = (eventType === 'touchstart' || eventType === 'mousedown');
start(event, eventType, condition);
});
#anchor {
display: block;
width: 100px;
height: 100px;
background-color: orange;
}
.item {
background-color: gray;
}
.item + .item {
margin-top: 10px;
}
.item a {
cursor: pointer;
display: inline-block;
background-color: blue;
color: white;
padding: 9px;
width: 100%;
height: 100%;
}
<div id="items" class="items">
<div class="item">
<a target="_blank" href="https://google.com">Anchor</a>
</div>
<div class="item">
<a target="_blank" href="https://google.com">Anchor</a>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
i think i figured out little solution for you. enable the preventDefault and afterwards enable the draggable for the a tag. Let me know if this works for you.
start(e) {
e.preventDefault();
...//rest of the code
apply() {
$el.draggable("enable");
...//rest of the code

jQuery: Prevent multiple clicks?

I'm trying to prevent mutiple clicks on a link and I need to wait until the function's complete before allowing another click on the same link.
However, everything I do, the multiple clicks is always allowed.
This is my code:
var active = false;
$('#rotRight').live('click', function(){
if (active) {
return;
}
$(this).attr('id', 'rotRight1');
var curAngle = parseInt($(".selected").getRotateAngle()) || 0;
if($(".selected").rotate({
angle: curAngle,
animateTo: curAngle - 90
})){
active = true;
}
$(this).attr('id', 'rotRight');
active = false;
});
I know I'm in the right path. I just need someone to let me know what i'm missing or if I'm doing something wrong please.
Any help would be appreciated.
Thanks
The rotate plugin has a callback where you can reset the active flag value
var active = false;
$('#rotRight').live('click', function() {
if (active) {
return;
}
var curAngle = parseInt($(".selected").getRotateAngle()) || 0;
active = true;
$(".selected").rotate({
angle: curAngle,
animateTo: curAngle - 90,
callback: function() {
active = false;
}
})
});
Try preventing default behaviour first before returning
var active = false;
$('#rotRight').live('click', function(e){
if (active) {
e.preventDefault(); // prevent default behaviour before returning
return;
}
...
});
You could always create an overlay (loading screen), stopping the user doing anything till the process is completed via a full screen div with the following css:
#overlay {
background-color: rgba(0, 0, 0, 0.3);
z-index: 999;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
display: none;
}​
This will do the following: https://gyazo.com/aa833914eda1c39d3b8198db2b32dc41
Makes all content un-clickable until after the loading screen has finished.
You can try to use the Data attribute on your link. Like that, you can set the "active" property on the link itself and act in consequence. Jquery handle that system with $().data(string) method. I think it's cleaner than using a global "active" var.
$('#rotRight').live('click', function() {
if ($(this).data("active") != undefined && $(this).data("active") == true) {
return;
}
var curAngle = parseInt($(".selected").getRotateAngle()) || 0;
$(this).data("active") = true;
var self = $(this);
$(".selected").rotate({
angle: curAngle,
animateTo: curAngle - 90,
callback: function() {
self.data("active") = false;
}
})
});
$('#rotRight').live('click', function(e) {
if (e.handled!=true) {
e.preventDefault(); // prevent default behaviour before returning
return;
}
e.handled=true;
});

how to implement mousemove while mouseDown pressed js

I have to implement mouse move event only when mouse down is pressed.
I need to execute "OK Moved" only when mouse down and mouse move.
I used this code
$(".floor").mousedown(function() {
$(".floor").bind('mouseover',function(){
alert("OK Moved!");
});
})
.mouseup(function() {
$(".floor").unbind('mouseover');
});
Use the mousemove event.
From mousemove and mouseover jquery docs:
The mousemove event is sent to an element when the mouse pointer moves inside the element.
The mouseover event is sent to an element when the mouse pointer enters the element.
Example: (check console output)
$(".floor").mousedown(function () {
$(this).mousemove(function () {
console.log("OK Moved!");
});
}).mouseup(function () {
$(this).unbind('mousemove');
}).mouseout(function () {
$(this).unbind('mousemove');
});
https://jsfiddle.net/n4820hsh/
In pure javascript, you can achieve this with
function mouseMoveWhilstDown(target, whileMove) {
var endMove = function () {
window.removeEventListener('mousemove', whileMove);
window.removeEventListener('mouseup', endMove);
};
target.addEventListener('mousedown', function (event) {
event.stopPropagation(); // remove if you do want it to propagate ..
window.addEventListener('mousemove', whileMove);
window.addEventListener('mouseup', endMove);
});
}
Then using the function along the lines of
mouseMoveWhilstDown(
document.getElementById('move'),
function (event) { console.log(event); }
);
(nb: in the above example, you don't need the function - you could call it as mouseMoveWhilstDown(document.getElementById('move'), console.log), but you might want to do something with it other than output it to the console!)
I know that this issue was submitted and resolved approximately seven years ago, but there is a simpler solution now:
element.addEventListener('mousemove', function(event) {
if(event.buttons == 1) {
event.preventDefault();
// Your code here!
}
});
or for touch compatible devices:
element.addEventListener('touchmove', function(event) {
if(event.touches.length == 1) {
event.preventDefault();
// Your code here!
}
}
For more information on MouseEvent.buttons, click here to visit MDN Web Docs. Touch compatible devices, however, tend to listen to TouchEvents instead of MouseEvents. TouchEvent.touches.length achieves a similar effect to MouseEvent.buttons.
To provide an example, I used the following code to move an element I created. For moving an element, I used the 'mousemove' event's MouseEvent.movementX and MouseEvent.movementY to simplify the code. The 'touchmove' event does not have these so I stored the previous touch coordinates and cleared them on 'touchstart'. You can do something similar for the 'mousemove' event if desired, as the movementX and movementY values may vary across browsers.
document.addEventListener('DOMContentLoaded', () => {
var element = document.getElementById('box');
element.style.position = 'fixed';
// MouseEvent solution.
element.addEventListener('mousemove', function(event) {
if(event.buttons == 1) {
event.preventDefault();
this.style.left = (this.offsetLeft+event.movementX)+'px';
this.style.top = (this.offsetTop+event.movementY)+'px';
}
});
// TouchEvent solution.
element.addEventListener('touchstart', function(event) {
/* Elements do not have a 'previousTouch' property. I create
this property during the touchmove event to store and
access the previous touchmove event's touch coordinates. */
delete this.previousTouch;
});
element.addEventListener('touchmove', function(event) {
if(event.touches.length == 1) {
event.preventDefault();
if(typeof this.previousTouch == 'object') {
this.style.left = (this.offsetLeft+event.touches[0].pageX-this.previousTouch.x)+'px';
this.style.top = (this.offsetTop+event.touches[0].pageY-this.previousTouch.y)+'px';
}
this.previousTouch = {
x: event.touches[0].pageX,
y: event.touches[0].pageY
};
}
});
});
#box {
width: 100px;
height: 100px;
padding: 1ch;
box-sizing: border-box;
background-color: red;
border-radius: 5px;
color: white;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="box">Drag Me!</div>
</body>
</html>
Hopefully this solution is helpful to you!
The default behaviour will stop mouseMove and mouseUp from running, you can solve this by basically adding event.preventDefault() to the mousedown function
please ensure that you use the same parameter name passed in the mousedown function to trigger the preventDefault() if not it will not work , in the example below i passed event as the parameter to the mousedown function and then triggered preventDefault() by typing event.preventDefault()
let sliderImages = Array.from(document.getElementsByClassName('slidess'));
const sliderPos = sliderImages.forEach( function (slide, index) {
let mousePosStart, isDown = false;
slide.addEventListener('mousedown', mousedown)
slide.addEventListener('mousemove', mousemove)
slide.addEventListener('mouseup', mouseup)
function mousedown(event) {
if (isDown == false) {
mousePosStart = event.pageX - this.offsetLeft;
isDown = true;
event.preventDefault();
}
}
function mousemove(event) {
if (isDown == true) {
let mousePosMove = event.pageX - this.offsetLeft;
}
}
function mouseup(event) {
if (isDown === true) {
isDown = false;
let mousePosEnd = event.pageX - this.offsetLeft;
}
}
});

Stop a textarea acting as a drag target for images

I have various elements on the page that can be dragged onto various drop zones. However for the textarea I can't find a way to show to the user that a draggable image suitable for a different zone, may not be dropped in the textarea.
I tried all kinds of combinations handling the ondragenter and ondragover events but it has been impossible to show the "no drop" icon when the image is dragged over the textarea.
There are lots of tutorials and tips on how to made a drop zone accept everything. I want to know how to make a dropzone and a textarea in particular reject a drag item. Turning of drag behavior for the item is not an option because there are other zones that should accept that image.
This JS fiddle shows that by default an image can be dragged into a textarea resulting in the URL being shown. I would love some help showing me how to stop that.
function dragstart(event) {//stuff}
function dragenter(event) {event.preventDefault();}
function dragover(event) {event.preventDefault();}
function dragdrop(event) {event.preventDefault();}
http://jsfiddle.net/mWKd3/16/
You aren't binding/attaching your events, for the attributes ondragstart, ondragenter, ondragover, and ondragdrop are not defined.
Here is a new fiddle that displays it http://jsfiddle.net/mWKd3/18/
In-Short - the Javascript (I'm using jQuery to attach the events)
$("img").bind("dragstart",function(e){
});
$("textarea").bind("dragenter",function(e){
e.preventDefault();
});
$("textarea").bind("dragover",function(e){
e.preventDefault();
});
$("textarea").bind("dragdrop",function(e){
e.preventDefault();
});
The following was an alternative method of doing drag-n-drop.
Referencing http://css-tricks.com/snippets/jquery/draggable-without-jquery-ui/ and extending your jsfiddle
HTML*
<div style='height:2em;display:block;'></div>
<img id='imgarea' src="http://www.planetinaction.com/images/gexplorer_logo48.png" draggable="true">
<textarea id='tarea' class="textzone"></textarea>
<div id='debugger' style='top:0em;left:5em;right:0em;height:2em;width:auto;position:absolute;display:block;'>Debug Window</div>
CSS*
.targetzone {
width: 200px;
height: 200px;
background-color: yellow;
}
.textzone {
width: 200px;
height: 200px;
background-color: white;
}
Javascript*
(function($) {
$.fn.dragstart = function(opt) {
opt = $.extend({handle:"",cursor:"move"}, opt);
if(opt.handle === "") {
var $el = this;
} else {
var $el = this.find(opt.handle);
}
return $el.css('cursor', opt.cursor).on("mousedown", function(e) {
if(opt.handle === "") {
var $drag = $(this).addClass('draggable');
} else {
var $drag = $(this).addClass('active-handle').parent().addClass('draggable');
}
var z_idx = $drag.css('z-index'),
drg_h = $drag.outerHeight(),
drg_w = $drag.outerWidth(),
pos_y = $drag.offset().top + drg_h - e.pageY,
pos_x = $drag.offset().left + drg_w - e.pageX;
$(this).data("start_pos_x",$drag.offset().left);
$(this).data("start_pos_y",$drag.offset().top);
$(this).data("start_z_idx",z_idx);
$drag.css('z-index', 1000).parents().on("mousemove", function(e) {
$('.draggable').offset({
top:e.pageY + pos_y - drg_h,
left:e.pageX + pos_x - drg_w
});
}).on("mouseup", function(e) {
$(this).removeClass('draggable').css('z-index', z_idx);
$("#debugger").append(document.elementFromPoint(e.pageX,e.pageY).id + " was selected!");
})
e.preventDefault(); // disable selection
}).on("mouseup", function() {
if(opt.handle === "") {
$(this).removeClass('draggable');
} else {
$(this).removeClass('active-handle').parent().removeClass('draggable');
}
$(this).offset({
top: $(this).data("start_pos_y"),
left: $(this).data("start_pos_x")
});
});
}
})(jQuery);
$("img").dragstart();

Categories

Resources