Ignoring/canceling browser drag for JavaScript drag & drop - javascript

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.

Related

Javascript events in Chrome and Firefox

I noticed that these function doesn't work good in Firefox, but does in Chrome.
I use these function in a game in Js to shoot bullet (left mouse click) and to create a fireball all around the player with the right click that burns everyone in a small radius.
document.onclick = function(event) {
if(!player){ //to avoid onclick to be used before calling Player();
return;
}
if(player.canAttack && player.distance >= 80) { //not for sword attack
performAttack(player);
player.canAttack = false;
}
if(player.distance < 80)
performAttack(player);
//event.preventDefault();
}
document.oncontextmenu = function(event) {
//hide default behaviour of right click -> no context menu popup
event.preventDefault();
if(player.obtainedGadjet > 0) {
player.pressingMouseRight = true;
performSpecialAttack(player);
}
}
In the performAttack function I set player.isStopped = true, so my updatePlayer() doesn't change player.x and player.y while he's attacking. The same for the fireball attack. I want my player stays there.
It works in chrome, my player stops, attacks,and then can moves again, but in Firefox if I right click it somethimes acts instead as I have left clicked, so shoot the magic ball, and maybe then the fireball too. Furthermore, my player ignore isStopped = true, it seems like in Firefox oncontextmenu has "lower priority" than other events.
Any idea?
Thanks
Please note that a click event contains information about which button was pressed. You can try yourself with something like:
document.addEventListener('click', function(ev){
console.log(ev.button);
});
And, yes, click events are fired when you right-click, even if you're doing something on related contextmenu events.
So your code should look a bit more like
document.addEventListener('click', function(ev){
if (ev.button === 0) {
// Perform primary action
} else if (ev.button === 2) {
// Perform secondary action
}
});
document.addEventListener('contextmenu', function(ev){
ev.preventDefault();
});
Using the same click event is advisable as said by Ivan. You may also want to read this other discussion here on SO about best practices and why it's not always good to disable default right click behaviour (i.e.: it's not always guaranteed to work).

Javascript drag and drop - delay for allowdrop

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.

Virtual Keyboard with Jquery

I have a div that operates as a button. Once the button is clicked, I want it to simulate the pressing of a key. Elsewhere on Stackoverflow, people have suggested using jQuery.Event("keydown"); but the suggestions all use a .trigger() bound to the button as opposed to .click. So, my example code looks like this:
var press = jQuery.Event("keydown");
press.which = 69; // # The 'e' key code value
press.keyCode = 69;
$('#btn').click( function() {
$('#testInput').focus();
$(this).trigger(press);
console.info(press);
});
I've set up a dummy example at JSFiddle:
http://jsfiddle.net/ruzel/WsAbS/
Eventually, rather than have the keypress fill in a form element, I just want to register the event as a keypress to the document so that a MelonJS game can have it.
UPDATE: It looks like triggering a keypress with anything other than the keyboard is likely to be ignored by the browser for security reasons. For updating a text input, this very nice Jquery plugin will do the trick: http://bililite.com/blog/2011/01/23/improved-sendkeys/
As for anyone who comes here looking for the solution in the MelonJS case, it's best to use MelonJS's me.input object, like so:
$('#btn').mousedown(function() {
me.input.triggerKeyEvent(me.input.KEY.E, true);
});
$('#btn').mouseup(function() {
me.input.triggerKeyEvent(me.input.KEY.E, false);
});
I'm not sure why, but even though this is triggering the event correctly, it doesn't fill the input with the character.
I've modified the code to show that the document is indeed receiving keypress events when we say $(document).trigger(p)
Try it out:
http://jsfiddle.net/WsAbS/3/
var press = jQuery.Event("keydown");
press.which = 69; // # Some key code value
press.keyCode = 69;
press.target = $('#testInput');
$(document).on('keydown', function(event) {
alert(event.keyCode);
});
$('#btn').click( function() {
$(document).trigger(press);
});
I believe this should be good enough for your end goal of a MelonJS game picking up keypresses.
If you want a virtual keyboard (As the title suggests) you can use this one.

Disable dragging of a file system image into a browser.

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

Looking for a better workaround to Chrome select on focus bug

I have the same problem as the user in this question, which is due to this bug in Webkit. However, the workaround provided will not work for my app. Let me re-state the problem so that you don't have to go read another question:
I am trying to select all the text in a textarea when it gets focus. The following jQuery code works in IE/FF/Opera:
$('#out').focus(function(){
$('#out').select();
});
However, in Chrome/Safari the text is selected--very briefly--but then the mouseUp event is fired and the text is deselected. The following workaround is offered in the above links:
$('#out').mouseup(function(e){
e.preventDefault();
});
However, this workaround is no good for me. I want to select all text only when the user gives the textarea focus. He must then be able to select only part of the text if he chooses. Can anyone think of a workaround that still meets this requirement?
How about this?
$('#out').focus(function () {
$('#out').select().mouseup(function (e) {
e.preventDefault();
$(this).unbind("mouseup");
});
});
The accepted answer (and basically every other solution I found so far) does not work with keyboard focus, i. e. pressing tab, at least not in my Chromium 21. I use the following snippet instead:
$('#out').focus(function () {
$(this).select().one('mouseup', function (e) {
$(this).off('keyup');
e.preventDefault();
}).one('keyup', function () {
$(this).select().off('mouseup');
});
});
e.preventDefault() in the keyup or focus handler does not help, so the unselecting after a keyboard focus seems to not happen in their default handlers, but rather somewhere between the focus and keyup events.
As suggested by #BarelyFitz, it might be better to work with namespaced events in order to not accidentally unbind other event handlers. Replace 'keyup' with 'keyup.selectText' and 'mouseup' with 'mouseup.selectText' for that.
Why not simply:
$('#out').focus(function(){
$(this).one('mouseup', function() {
$(this).select();
});
});
Seems to work in all major browsers...
A very slightly different approach would be to separate the focus event from the mouse sequence. This works really nicely for me - no state variables, no leaked handlers, no inadvertent removal of handlers, and it works with click, tab, or programmatic focus. Code and jsFiddle below -
$('#out').focus(function() {
$(this).select();
});
$('#out').on('mousedown.selectOnFocus', function() {
if (!($(this).is(':focus'))) {
$(this).focus();
$(this).one('mouseup.selectOnFocus', function(up) {
up.preventDefault();
});
}
});
https://jsfiddle.net/tpankake/eob9eb26/27/
Make a bool. Set it to true after a focus event and reset it after a mouse up event. During the mouse up, if it's true, you know the user just selected the text field; therefore you know you must prevent the mouse up from happening. Otherwise, you must let it pass.
var textFieldGotFocus = false;
$('#out').focus(function()
{
$('#out').select();
textFieldGotFocus = true;
});
$('#out').mouseup(function(e)
{
if (textFieldGotFocus)
e.preventDefault();
});
$(document).mouseup(function() { textFieldGotFocus = false; });
It's important that you put the mouseup listener that resets the variable on document, since it's not guaranteed that the user will release the mouse button over the text field.
onclick="var self = this;setTimeout(function() {self.select();}, 0);"
Select the text before putting the focus on the input box.
$('#out').select().focus();
digitalfresh's solution is mostly there, but has a bug in that if you manually trigger .focus() using JS (so not using a click), or if you tab to the field, then you get an unwanted mouseup event bound - this causes the first click that should deselect the text to be ignored.
To solve:
var out = $('#out');
var mouseCurrentlyDown = false;
out.focus(function () {
out.select();
if (mouseCurrentlyDown) {
out.one('mouseup', function (e) {
e.preventDefault();
});
}
}).mousedown(function() {
mouseCurrentlyDown = true;
});
$('body').mouseup(function() {
mouseCurrentlyDown = false;
});
Note: The mouseup event should be on body and not the input as we want to account for the user mousedown-ing within the input, moving the mouse out of the input, and then mouseup-ing.
tpankake's answer converted to a reusable jQuery function..
(If you upvote this, please also upvote his answer)
Load the following AFTER loading the jQuery library:
$.fn.focusSelect = function () {
return this.each(function () {
var me = $(this);
me.focus(function () {
$(this).select();
});
me.on('mousedown.selectOnFocus', function () {
var me2 = $(this);
if (me2.is(':focus') === false) {
me2.focus();
me2.one('mouseup.selectOnFocus', function (up) {
up.preventDefault();
});
}
});
});
};
Use it like this:
$(document).ready(function () {
// apply to all inputs on the page:
$('input[type=text]').focusSelect();
// apply only to one input
$('#out').focusSelect();
});

Categories