I am experimenting with the HTML5 file API. I notice however that browsers have a default behaviour where they display an image if you drag the image into the browser. This can however be annoying if your aim is to upload the image rather than to view it.
I am wondering if there is a way of preventing this behaviour? I have tried stopPropagation / preventDefault on an ondrop event which works somewhat, however leaves the "drop" cursor in place giving the impression that the image can be dropped anywhere on the page.
Ideally you would only see the "drop" cursor on the designated area where images are meant to be dropped.
The dataTransfer object has dropEffect and effectAllowed properties. Not exactly sure what the difference between them, but setting both to 'none' should help.
$(document).bind({
dragenter: function (e) {
e.stopPropagation();
e.preventDefault();
var dt = e.originalEvent.dataTransfer;
dt.effectAllowed = dt.dropEffect = 'none';
},
dragover: function (e) {
e.stopPropagation();
e.preventDefault();
var dt = e.originalEvent.dataTransfer;
dt.effectAllowed = dt.dropEffect = 'none';
}
});
See the http://jsfiddle.net/andreymir/H3RR7/embedded/result/ - drop allowed to rectangle only.
Perhaps this is what you are looking for? I designed this myself.
http://rightandrong.info/html5upload/Upload.html
Related
I am implementing drag'n'drop functionality on the page. The idea is that user can start dragging image from special place and drop it (release left mouse button) inside textarea, where special tag insertion will occur.
I have no issues with the dragging itself, the problem I got is that I can't determine position of the mouse inside textarea. I know x and y positions from mouseup event and I definetely know the mouse pointer is inside textarea, but can't determine at which position do I need to insert the required tag. Since the focus is not inside the textarea, selectionStart and selectionEnd properties are 0. Also, it is worth noticing that I prevent default behavior by returning false in mousemove handler - otherwise default behavior will put the image itself inside the textarea (which is extremely bad for base64 images).
Below is the code I currently have.
window.onPreviewItemMouseDown = function (e) {
var curTarget = $(e.currentTarget);
var container = curTarget.parent();
window.draggingImage = funcToGetId();
$(document).on("mousemove", window.onPreviewItemDragged);
$(document).on("mouseup", window.onPreviewItemDropped);
};
window.onPreviewItemDragged = function (e) {
return false;
};
window.onPreviewItemDropped = function (e) {
var target = $(e.target);
$(document).off("mousemove");
$(document).off("mouseup");
if (target[0].id === ID_TEXTAREA_TEXT) {
// here I need to get mouse pointer position inside the text somehow
}
return false;
};
Any help is appreciated.
In your case it would be easier to use native ondragstart event instead of a complex mousedown-move-up implementation, and manipulate the data to drop. Something like this:
document.getElementById('img').addEventListener('dragstart', function (e) {
e.dataTransfer.setData("text", '[img]' + this.id + '[/img]');
});
A live demo at jsFiddle. Or a delegated version. Notice that you can also delegate to the "special place" element, which might make the page running a little bit faster.
I'm currently stuck at the following problem:
I need to create a delay when dragover happens en then check if current dragover object is still the same. When it's the same object -> execute code.
This is my code:
var draggedId = null;
var triggered = false;
function allowDrop(ev) {
draggedId = ev.target.id;
setTimeout(function () {
if (draggedId == ev.target.id && ev.target.id != "" && !triggered) {
triggered = true;
draggedId = "";
ev.preventDefault();
}
}, 2000);
}
function drop(ev) {
ev.preventDefault();
}
function dragLeave(ev) {
draggedId == "";
triggered = false;
}
Allowdrop function is the dragover event.
ev.preventDefault() to allow the drop can't happen there because that function is assync.
Any idea's?
Thanks,
Mathias
Can you explain more about what you are trying to achieve and I can answer more fully ?
It's generally the case that you cannot always say for certain whether a drop will work, the best you can do is to setup drop zones on your page and have them cancel the dragover event based on what you can tell about the drop. If you want to make your application work with cross window dragging, then you cannot rely on a global variable to store information about what is being dragged, and you cannot actually see what is inside the drag - you can only know what kind of thing is being dragged. So if the drop might be acceptable you need to cancel the event. See this question
I think that maybe you are confused about how dragevents propagate which is the reason you think you need a timeout ? But blocking the event queue to figure out whether you accept a drop, or trying to cancel the drag event after it has already bubbled to the top and been handled in the default way by the browser (which is to not accept the drop) isn't going to work.
I want to cancel an HTML5 drag operation based on some condition. I have tried to search this but found nothing useful. It seems that there is no way to cancel an HTML5 drag and drop using JavaScript. returning false in the dragstart doesn't seem to do anything. Any ideas?
You can cancel it by calling event.preventDefault() in the event handler.
For example this should work:
<p id="p1" draggable="true" ondragstart="dragstart_handler(event);">This element is draggable.</p>
<script>
var enableDragDrop = true;
function dragstart_handler(ev) {
if (!enableDragDrop) {
ev.preventDefault();
}
console.log("dragStart");
}
</script>
I think you need to do something tricky to make it work, for I do not know how to stop a drag from js, but you can fake a drag with mousedown,mousedown,mouseup and a isDragging flag
some code look like:
var isDragging = false
var fakeDraggingElement
var currentDragging
$('#item').mousedown(function(e){
e.preventDefault()
isDragging = true
currentDragging = this
//change your cursor and make it loos like dragging
$('#parent').css({cursor: 'move'})
//fake dragging element
fakeDraggingElement = $(this).clone().css({
opacity:0.5,
position:'absolute',
top:e.pageY+offsetY, //parent offset
left:e.pageX+offsetX,//parent offset
}).appendTo(parent)
}).mousemove(function(e){
if(!isDragging){
return
}
fakeDraggingElement.css({
top:e.pageY+offsetY, //parent offset
left:e.pageX+offsetX,//parent offset
})
}).mousedown(function(e){
if(!isDragging){
return
}
cancleDrag()
//your old drop
ondrop(currentDragging,e.target)
})
function cancleDrag(){
isDragging = false
$(currentDragging).remove()
currentDragging = undefined
}
EDIT:
got it. Its a bit roundabout, but works. Take advantage of the fact that the drag event is a cancellable mouse event, and cancelling it stops all further drag actions. Create a drag event on your condition and call preventDefault(). The following cancels it after 3 seconds:
setTimeout(function(){document.getElementById("drag").ondrag = function(e){
e.preventDefault();
this.ondrag = null;
return false;
};},3000);
Note first that I clear all ondrag events after it is cancelled, which you may need to adjust if you need other ondrag events, and second that this truly cancels all parts of the drag, so you don't get an ondragend event after, as shown in this jsfiddle:
http://jsfiddle.net/MaxPRafferty/aCkbR/
Source: HTML5 Spec: http://www.w3.org/html/wg/drafts/html/master/editing.html#dndevents
I'm working on a html5 canvas game, but I don't know how to handle touch events. When a user touch the screen, and drag, then the browser will scroll the page. I would like to prevent it, and get the touch start, and touch end position. Is it possible?
Thanks in advance
You need to override the default touch behaviour to stop touchevents dragging the page. Clearly, you'll need to handle them again if your page becomes larger than the available area, but as you're making a game, going to assume you're doing 100%/100% layout.
function preventBehavior(e) {
e.preventDefault();
};
document.addEventListener("touchmove", preventBehavior, {passive: false});
Edit: here's the W3C recommendation talking about touch events, which might be handy for you.
Due to breaking changes made in recent versions of Chrome, the above answers are no longer correct. Attaching a touch event listener to the document or body elements will cause the event listener to be registered in "passive" mode, which causes calls to preventDefault to be ignored.
There are two solutions:
The preferred solution is to use the CSS style touch-action to specify that no scrolling should happen (e.g. with the value "none")
In cases where this is not appropriate (e.g. if the type of interaction should change dynamically in a way that cannot be determined before the gesture begins) then the event listener must be registered with the third parameter set to { passive: false } (you should perform browser detection to ensure that this style is supported first, though).
If you don't want to use jQuery mobile or any other library then you can try this.
var startX, startY, endX, endY;
document.addEventListener("touchstart", function(e){
startX = e.touches[0].pageX;
startY = e.touches[0].pageY;
e.preventDefault();//Stops the default behavior
}, false);
document.addEventListener("touchend", function(e){
endX = e.touches[0].pageX;
endY = e.touches[0].pageY;
e.preventDefault();//Stops the default behavior
}, false);
canvas.addEventListener('touchstart', function(e)
{
alert(e.changedTouches[0].pageX + " " + e.changedTouches[0].pageY);
}
canvas.addEventListener('touchend', function(e)
{
alert(e.changedTouches[0].pageX + " " + e.changedTouches[0].pageY);
}
Here's a good article about touching and gesturing on mobile phones:
http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/
Following solution preventing scroll when dragging AND at the same time usual scroll is working (when not dragging)
var scrollable = true;
var listener = function(e) {
if (! scrollable) {
e.preventDefault();
}
}
document.addEventListener('touchmove', listener, { passive:false });
onDragstartHandler() {
scrollable = false;
}
onDragendHandler(} {
scrollable = true;
}
Don't forget to bind onDragstartHandler and onDragendHandler to related elements
I'm implementing a drag & drop script in (plain) JavaScript. All good, except one thing. For example, in Firefox (probably not only there), if you drag an object the second time, it is getting dragged as a built-in browser feature (for easy drag & drop image saving to desktop, for example, I think). Well this kind of ruins my script.
Thing is, I know this is possible, and I've even done it before, but that was like a long time and I got it working by trial and error, just entered focus() and blur() all over the place 'till it seemed to actually loose focus.
So if someone knows how to clear this out for me, he'd be my personal hero. Blur() on the dragging object? focus() on a different one? etc.
Thanks!
//Ok, the parts of the code regarding this would be:
...
this.handle.onmousedown = function(e)
{
self.startDragging(e);
};
this.handle.onmouseup = function(e)
{
self.stopDragging(e);
};
setInterval(function(){self.animate()}, 25);
...
startDragging: function(e)
{
this.dragging = true;
},
stopDragging: function(e)
{
this.dragging = false;
},
animate: function()
{
if(this.dragging)
...
Unless I misinterpreted your question, try event.preventDefault(); in your mousedown event listener. It would help if you could provide snippets of code to show us how you are implementing drag/drop.
Edit: With your implementation, something like this should work:
this.handle.onmousedown = function(e) {
if(!e) e = window.event;
if(e.preventDefault) e.preventDefault();
else e.returnValue = false;
self.startDragging(e);
};
However, I would recommend using event listeners instead.