jQuery + CSS cursor mousedown + Chrome = not working - javascript

I decided to make/test Cursors cross-browser, so far on Firefox its working perfect, but on Chrome - somewhat..
Now, the custom cursor shows, but when you click somewhere, it doesn't change, it does trigger mousedown event, but it doesn't change the cursor. I tried just mousedown(); and it changed the cursor. I guess the the mouseup event is causing this trouble.
$("body").mousedown(function() {
$("body").addClass("clicked");
console.log("down");
});
$("body").mouseup(function() {
$("body").removeClass("clicked");
console.log("up");
});
CSS
body {
cursor: url("../img/cursor1.cur"), default;
}
.clicked {
cursor: url("../img/cursor2.cur"), default;
}

Try clicking and moving the mouse.
I think chrome only changes cursor on mousemove.
EDIT: This is a known bug, see Getting the browser cursor from "wait" to "auto" without the user moving the mouse

I just tried out the following:
$('body').mousedown(function(){
$(this).css('background-color', 'red');
});
$('body').mouseup(function(){
$(this).css('background-color', 'green');
});
The result was as expected, click down -> red BG, click up -> green BG
BUT: this only happened, when i assigned css: html, body { height:100%; min-height:100%; }
Without the CSS the events were not really working as "fluent" as they should be.
Little tip: with firebug (at least chrome dev tools) you can monitor events using the following snipped:
monitorEvents( $$('body')[0] )
Hope this helped

The problem is that you are using the global window.event object, and not jQuery's event object. window.event only works in some browsers, and it is not a W3C standard.
jQuery normalizes the event object so it's the same in all browsers. The event handler is passed that jQuery event object as a parameter. You should be using that.
$(".class_name").mousedown(function (e) {
switch (e.which) {
case 1: //leftclick
//...
break;
case 3: //rightclick
//...
break;
}
});

Related

Mouse cursor set using jQuery/CSS not changing until mouse moved

In my code I use the jQuery/CSS to set and unset the 'wait' mouse cursor with the following code:
function setWaitCursor() {
$('body').css('cursor', 'wait');
}
function setDefaultCursor() {
$('body').css('cursor', '');
}
I use this code to change the mouse cursor for a long operation:
setWaitCursor();
... do stuff that takes a few seconds ...
setDefaultCursor();
This code doesn't seem to work unless you move the mouse, however (at least for Chrome on Win 10). If the mouse is not moved after setDefaultCursor is called, the cursor displays the 'wait' cursor until the mouse is moved (or vice versa).
Example: https://jsfiddle.net/antonyakushin/0jv6rqkf/
In this fiddle, the cursor changes for 2 seconds after the link is
clicked. If you don't move the mouse when you click the link, the
cursor does not change.
What is the best way to resolve this issue, so that even if the mouse is not moved the cursor is changed?
Although this is not the answer to this specific problem, this behavior can happen:
On Chrome
With DevTools open (which is very likely, in order to debug this issue)
The solution is simply to close the Chrome DevTools.
Some elements have default cursor styles. So wile changing the cursor style we need to change that too.
$(document).ready(function() {
function setWaitCursor(elem) {
elem.css('cursor', 'wait');
$('body').css('cursor', 'wait');
}
function setDefaultCursor(elem) {
elem.css('cursor', '');
$('body').css('cursor', '');
}
$('#testLink').on('click', function() {
var x = $(this)
setWaitCursor(x);
setTimeout(function() {
setDefaultCursor(x);
}, 5000);
return false;
});
});
Demo fiddle
Just change the body to *. It will be applicable to all the elements.
Fiidle Demo
Code snippets:
$(document).ready(function() {
function setWaitCursor() {
$('*').css('cursor', 'wait');
}
function setDefaultCursor() {
$('*').css('cursor', '');
}
$('#testLink').on('click', function() {
setWaitCursor();
setTimeout(function() {
setDefaultCursor();
}, 2000);
return false;
});
});
body {
min-width: 500px;
min-height: 500px;
background-color: gray;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<div id="mouseContainer">
Test Link
</div>
I think I solved it! Just call setTimeout() after you change the cursor. For example
$('body').addClass('in-progress-cursor');
setTimeout(null, 0); //in typescript we need to provide arguments
This is well-known trick (Why is setTimeout(fn, 0) sometimes useful?) but I didn't expect this would work in this case.
This is my favorite method of telling user unobtrusively that there is something going on. For example I use it to indicate that http requests are in progress. It is such a relief that the solution is found. Why I feel stupid again...
Actually I see the timeout in John R's answer now. But it is not evident enough.
I had the same problem and I noticed on another post cursor won't change until mouse moves that they had suggested doing a blur and focus to fix this. It worked for me. So, your setWaitCursor() should look something like this. That should force it to change without the mouse move. It worked for me in Chrome, but haven't tried other browsers.
function setWaitCursor(elem) {
elem.css('cursor', 'wait');
$('body').css('cursor', 'wait');
window.blur();
window.focus();
}

Doubletap event on input text on mobile [duplicate]

I'm looking for the best solution to adding both "doubletap" and "longtap" events for use with jQuery's live(), bind() and trigger(). I rolled my own quick solution, but it's a little buggy. Does anyone have plugins they would recommend, or implentations of their own they'd like to share?
It has been reported to jQuery as a bug, but as doubletapping isn't the same as doubleclicking, it does not have a high priority. However, mastermind Raul Sanchez coded a jquery solution for doubletap which you can probably use!
Here's the link, works on mobile Safari.
It's easy to use:
$('selector').doubletap(function() {});
-edit-
And there's a longtap plugin here! You can see a demo on your iPad or iPhone here.
rsplak's answer is good. I checked out that link and it does work well.
However, it only implements a doubletap jQuery function
I needed a custom doubletap event that I could bind/delegate to. i.e.
$('.myelement').bind('doubletap', function(event){
//...
});
This is more important if you're writing a backbone.js style app, where there is a lot of event binding going on.
So I took Raul Sanchez's work, and turned it into a "jQuery special event".
Have a look here: https://gist.github.com/1652946 Might be useful to someone.
Just use a multitouch JavaScript library like Hammer.js. Then you can write code like:
canvas
.hammer({prevent_default: true})
.bind('doubletap', function(e) { // Also fires on double click
// Generate a pony
})
.bind('hold', function(e) {
// Generate a unicorn
});
It supports tap, double tap, swipe, hold, transform (i.e., pinch) and drag. The touch events also fire when equivalent mouse actions happen, so you don't need to write two sets of event handlers. Oh, and you need the jQuery plugin if you want to be able to write in the jQueryish way as I did.
I wrote a very similar answer to this question because it's also very popular but not very well answered.
You can also use jQuery Finger which also supports event delegation:
For longtap:
// direct event
$('selector').on('press', function() { /* handle event */ });
// delegated event
$('ancestor').on('press', 'selector', function() { /* handle event */ });
For double tap:
// direct event
$('selector').on('doubletap', function() { /* handle event */ });
// delegated event
$('ancestor').on('doubletap', 'selector', function() { /* handle event */ });
Here's a pretty basic outline of a function you can extend upon for the longtap:
$('#myDiv').mousedown(function() {
var d = new Date;
a = d.getTime();
});
$('#myDiv').mouseup(function() {
var d = new Date;
b = d.getTime();
if (b-a > 500) {
alert('This has been a longtouch!');
}
});
The length of time can be defined by the if block in the mouseup function. This probably could be beefed up upon a good deal. I have a jsFiddle set up for those who want to play with it.
EDIT: I just realized that this depends on mousedown and mouseup being fired with finger touches. If that isn't the case, then substitute whatever the appropriate method is... I'm not that familiar with mobile development.
based on latest jquery docs i've written doubletap event
https://gist.github.com/attenzione/7098476
function itemTapEvent(event) {
if (event.type == 'touchend') {
var lastTouch = $(this).data('lastTouch') || {lastTime: 0},
now = event.timeStamp,
delta = now - lastTouch.lastTime;
if ( delta > 20 && delta < 250 ) {
if (lastTouch.timerEv)
clearTimeout(lastTouch.timerEv);
return;
} else
$(this).data('lastTouch', {lastTime: now});
$(this).data('lastTouch')['timerEv'] = setTimeout(function() {
$(this).trigger('touchend');
}, 250);
}
}
$('selector').bind('touchend', itemTapEvent);

getting a mouseenter event from a still mouse entering an animated element

I'm writing a image carousel and due to some class adding/removing my css pointer as well as my mouseenter event don't seem to work properly.
$("img", ":not(.active)").on("click", function() {
var $this = $(this);
$("img").removeClass("active");
$this.addClass("active");
goto($this.index());
});
$("img").on("mouseenter", function() {
console.log("silence");
});
function goto(i) {
$(".images").animate({
left: 55-i*310
});
}
http://jsfiddle.net/rnfkqq6s/3/
please take a look at the fiddle and watch the console. when the mouse doesn't move while clicking, the mouseenter sometimes isn't beeing triggered. the same thing with the cursor. what am I doing wrong here?
This issue relates to a known bug:
See similar:
Getting the browser cursor from "wait" to "auto" without the user moving the mouse
The bug report:
https://code.google.com/p/chromium/issues/detail?id=26723#c87

Firefox firing dragleave when dragging over text

I'm attempting to track a dragenter/leave for the entire screen, which is so far working fine in Chrome/Safari, courtesy of the draghover plugin from https://stackoverflow.com/a/10310815/698289 as in:
$.fn.draghover = function(options) {
return this.each(function() {
var collection = $(),
self = $(this);
self.on('dragenter', function(e) {
if (collection.size() === 0) {
self.trigger('draghoverstart');
}
collection = collection.add(e.target);
});
self.on('dragleave drop', function(e) {
// timeout is needed because Firefox 3.6 fires the dragleave event on
// the previous element before firing dragenter on the next one
setTimeout( function() {
collection = collection.not(e.target);
if (collection.size() === 0) {
self.trigger('draghoverend');
}
}, 1);
});
});
};
function setText(text) {
$('p.target').text(text);
}
$(document).ready(function() {
$(window).draghover().on({
'draghoverstart': function() {
setText('enter');
},
'draghoverend': function() {
setText('leave');
}
});
});
However Firefox is still giving me problems when I drag over text items, here's a fiddle to demonstrate: http://jsfiddle.net/tusRy/6/
Is this a Firefox bug or can this be tamed with JS? Or is there a more robust method for performing all of this?
Thanks!
UPDATE: Updated fiddle to http://jsfiddle.net/tusRy/6/ to reduce clutter a bit. To explain the expected behavior of the fiddle:
Drag a file into the window and p.target should be "ENTER" colored yellow.
Drag a file out of the window and p.target should be "LEAVE" colored red.
Drop a file in the window and p.target should be "LEAVE" colored red.
In firefox, the LEAVE event is triggered when you drag the file over text.
As of version 22.0 Firefox is still doing this. When you drag over a text node it fires two kinds of dragenter and dragleave events: one where the event target and relatedTarget are BOTH the parent element of the text node, and another where the target is the parent element and the relatedTarget is the actual text node (not even a proper DOM element).
The workaround is just to check for those two kinds of events in your dragenter and dragleave handlers and ignore them:
try {
if(event.relatedTarget.nodeType == 3) return;
} catch(err) {}
if(event.target === event.relatedTarget) return;
I use a try/catch block to check the nodeType because occasionally events fire (inexplicably) from outside the document (eg. in other iframes) and trying to access their nodeType throws a permissions error.
Here's the implementation:
http://jsfiddle.net/9A7te/
1) Your dropzone should have only one child element, which might have everything else you need. Something like
<div id="#dropzone">
<div><!--Your contents here--></div>
</div>
2) Use this CSS:
#dropzone * { pointer-events: none; }
You might need to include the :before and :after since the * don't apply to them.
This should be enough to let the drop work in Firefox and Chrome. In your example, it should be enough to add:
body * { pointer-events: none; }
At the end of the CSS. I've done it here:
http://jsfiddle.net/djsbellini/eKttq/
Other examples:
http://jsfiddle.net/djsbellini/6yZV6/1/
http://jsfiddle.net/djsbellini/yR8t8/
I came up with kind of a solution, yet to test on other browsers other than Chrome and FF but working so far. This is how the setTimeout looks now:
setTimeout( function() {
var isChild = false;
// in order to get permission errors, use the try-catch
// to check if the relatedTarget is a child of the body
try {
isChild = $('body').find(e.relatedTarget).length ? true : isChild;
}
catch(err){} // do nothing
collection = collection.not(e.target);
if (collection.size() === 0 && !isChild) {
self.trigger('draghoverend');
}
}, 1);
The entire code here - http://jsfiddle.net/tusRy/13/.
The idea is to check if the related tag is a child of the body, in which case we are still in the Browsers and the draghoverend event should be not triggered. As this can throw errors when moving out of the windows, I used a try method to avoid it.
Well, perhaps somebody with more skills on JS could improve this :)
I found the answer in a non-selected answer to this SO question asking about dragleave firing on child elements. I have a <div> that has many children elements. An semi-opaque overlay <span> becomes visible over the <div> whenever there's a dragenter on the page. As you found, 'dragover' isn't like mouseover. It triggers dragleave whenever you hover over a child element.
The solution? Dragout It makes dragover work more like mouseover. Very short.

Chrome sets cursor to text while dragging, why?

My application has many drag and drop features. While dragging I want the cursor to change to some grab cursor. Internet Explorer and Firefox work fine for this, but Chrome always changes the cursor to the text cursor.
None of these solutions worked for me because it's too much code.
I use a custom jQuery implementation to do the drag, and adding this line in the mousedown handler did the trick for me in Chrome.
e.originalEvent.preventDefault();
Try turning off text selection event.
document.onselectstart = function(){ return false; }
This will disable any text selection on the page and it seems that browser starts to show custom cursors.
But remember that text selection will not work at all, so it's the best to do it only while dragging, and turn it on again just after that. Just attach function that doesn't return false:
document.onselectstart = function(){ return true; }
If you want to prevent the browser from selecting text within an element and showing the select cursor, you can do the following:
element.addEventListener("mousedown", function(e) { e.preventDefault(); }, false);
Pitfall
You cannot put the
document.onselectstart = function(){ return false; };
into your "mousedown" handler because onselectstart has already been triggered.
Solution
Thus, to have it working, you need to do it before the mousedown event. I did it in the mouseover event, since as soon as the mouse enters my element, I want it to be draggable, not selectable. Then you can put the
document.onselectstart = null;
call into the mouseout event. However, there's a catch. While dragging, the mouseover/mouseout event might be called. To counter that, in your dragging/mousedown event, set a flag_dragging to true and set it to false when dragging stops (mouseup). The mouseout function can check that flag before setting
document.onselectstart = null;
Example
I know you are not using any library, but here's a jQuery code sample that might help others.
var flag_dragging = false;//counter Chrome dragging/text selection issue
$(".dragme").mouseover(function(){
document.onselectstart = function(){ return false; };
}).mouseout(function(){
if(!flag_dragging){
document.onselectstart = null;
}
});
//make them draggable
$(".dragme").draggable({
start: function(event, ui){
flag_dragging = true;
}, stop: function(event, ui){
flag_dragging = false;
}
});
I solved a same issue by making the Elements not selectable, and adding an active pseudo class on the draged elements:
* {
-webkit-user-select: none;
}
.your-class:active {
cursor: crosshair;
}
I was facing almost same problem. I want cursor inside my DIV element and all its child to be the default, the CSS tips here helped in IE, FF and Opera, but not for Google Chrome. Here is what I have done in parent DIV:
<div ... onselectstart="return false;" ... > ... </div>
Now it is working fine. Hope this help.
I have a similar issue using jQuery UI draggable and sortable (ver. 1.8.1), and it's quite specific, so I assume that you are using same library.
Problem is caused by a bug in jQuery UI (actually a fix for other Safari bug).
I just raised the issue in jQuery UI http://dev.jqueryui.com/ticket/5678 so I guess you will need to wait till it's fixed.
I've found a workaround for this, but it's quite hard-core, so you only use it if you really know what is going on ;)
if ($.browser.safari) {
$.ui.mouse.prototype.__mouseDown = $.ui.mouse.prototype._mouseDown;
$.ui.mouse.prototype._mouseDown = function(event){
event.preventDefault();
return $.ui.mouse.prototype.__mouseDown.apply(this, arguments);
}
}
It simply switches off the fix that's in jQuery UI code, so basically it may break something.
Just use this line inside your mousedown event
arguments[0].preventDefault();
You can also disable text selection by CSS adding this class to your draggable element
.nonselectable {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}

Categories

Resources