On the front page of a site I am building, several <div>s use the CSS :hover pseudo-class to add a border when the mouse is over them. One of the <div>s contains a <form> which, using jQuery, will keep the border if an input within it has focus. This works perfectly except that IE6 does not support :hover on any elements other than <a>s. So, for this browser only we are using jQuery to mimic CSS :hover using the $(#element).hover() method. The only problem is, now that jQuery handles both the form focus() and hover(), when an input has focus then the user moves the mouse in and out, the border goes away.
I was thinking we could use some kind of conditional to stop this behavior. For instance, if we tested on mouse out if any of the inputs had focus, we could stop the border from going away. AFAIK, there is no :focus selector in jQuery, so I'm not sure how to make this happen. Any ideas?
jQuery 1.6+
jQuery added a :focus selector so we no longer need to add it ourselves. Just use $("..").is(":focus")
jQuery 1.5 and below
Edit: As times change, we find better methods for testing focus, the new favorite is this gist from Ben Alman:
jQuery.expr[':'].focus = function( elem ) {
return elem === document.activeElement && ( elem.type || elem.href );
};
Quoted from Mathias Bynens here:
Note that the (elem.type || elem.href) test was added to filter out false positives like body. This way, we make sure to filter out all elements except form controls and hyperlinks.
You're defining a new selector. See Plugins/Authoring. Then you can do:
if ($("...").is(":focus")) {
...
}
or:
$("input:focus").doStuff();
Any jQuery
If you just want to figure out which element has focus, you can use
$(document.activeElement)
If you aren't sure if the version will be 1.6 or lower, you can add the :focus selector if it is missing:
(function ( $ ) {
var filters = $.expr[":"];
if ( !filters.focus ) {
filters.focus = function( elem ) {
return elem === document.activeElement && ( elem.type || elem.href );
};
}
})( jQuery );
CSS:
.focus {
border-color:red;
}
JQuery:
$(document).ready(function() {
$('input').blur(function() {
$('input').removeClass("focus");
})
.focus(function() {
$(this).addClass("focus")
});
});
Here’s a more robust answer than the currently accepted one:
jQuery.expr[':'].focus = function(elem) {
return elem === document.activeElement && (elem.type || elem.href);
};
Note that the (elem.type || elem.href) test was added to filter out false positives like body. This way, we make sure to filter out all elements except form controls and hyperlinks.
(Taken from this gist by Ben Alman.)
April 2015 Update
Since this question has been around a while, and some new conventions have come into play, I feel that I should mention the .live method has been depreciated.
In its place, the .on method has now been introduced.
Their documentation is quite useful in explaining how it works;
The .on() method attaches event handlers to the currently selected set
of elements in the jQuery object. As of jQuery 1.7, the .on() method
provides all functionality required for attaching event handlers. For
help in converting from older jQuery event methods, see .bind(),
.delegate(), and .live().
So, in order for you to target the 'input focused' event, you can use this in a script. Something like:
$('input').on("focus", function(){
//do some stuff
});
This is quite robust and even allows you to use the TAB key as well.
I'm not entirely sure what you're after but this sounds like it can be achieved by storing the state of the input elements (or the div?) as a variable:
$('div').each(function(){
var childInputHasFocus = false;
$(this).hover(function(){
if (childInputHasFocus) {
// do something
} else { }
}, function() {
if (childInputHasFocus) {
// do something
} else { }
});
$('input', this)
.focus(function(){
childInputHasFocus = true;
})
.blur(function(){
childInputHasFocus = false;
});
});
An alternative to using classes to mark the state of an element is the internal data store functionality.
P.S.: You are able to store booleans and whatever you desire using the data() function. It's not just about strings :)
$("...").mouseover(function ()
{
// store state on element
}).mouseout(function ()
{
// remove stored state on element
});
And then it's just a matter of accessing the state of elements.
if anyone cares there is a much better way to capture focus now, $(foo).focus(...)
http://api.jquery.com/focus/
Have you thought about using mouseOver and mouseOut to simulate this. Also look into mouseEnter and mouseLeave
Keep track of both states (hovered, focused) as true/false flags, and whenever one changes, run a function that removes border if both are false, otherwise shows border.
So: onfocus sets focused = true, onblur sets focused = false. onmouseover sets hovered = true, onmouseout sets hovered = false. After each of these events run a function that adds/removes border.
As far as I know, you can't ask the browser if any input on the screen has focus, you have to set up some sort of focus tracking.
I usually have a variable called "noFocus" and set it to true. Then I add a focus event to all inputs that makes noFocus false. Then I add a blur event to all inputs that set noFocus back to true.
I have a MooTools class that handles this quite easily, I'm sure you could create a jquery plugin to do the same.
Once that's created, you could do check noFocus before doing any border swapping.
There is no :focus, but there is :selected
http://docs.jquery.com/Selectors/selected
but if you want to change how things look based on what is selected you should probably be working with the blur events.
http://docs.jquery.com/Events/blur
There is a plugin to check if an element is focused: http://plugins.jquery.com/project/focused
$('input').each(function(){
if ($(this) == $.focused()) {
$(this).addClass('focused');
}
})
I had a .live("focus") event set to select() (highlight) the contents of a text input so that the user wouldn't have to select it before typing a new value.
$(formObj).select();
Because of quirks between different browsers, the select would sometimes be superseded by the click that caused it, and it would deselect the contents right after in favor of placing the cursor within the text field (worked mostly ok in FF but failed in IE)
I thought I could solve this by putting a slight delay on the select...
setTimeout(function(){$(formObj).select();},200);
This worked fine and the select would persist, but a funny problem arose.. If you tabbed from one field to the next, the focus would switch to the next field before the select took place. Since select steals focus, the focus would then go back and trigger a new "focus" event. This ended up in a cascade of input selects dancing all over the screen.
A workable solution would be to check that the field still has focus before executing the select(), but as mentioned, there's no simple way to check... I ended up just dispensing with the whole auto highlight, rather than turning what should be a single jQuery select() call into a huge function laden with subroutines...
What I wound up doing is creating an arbitrary class called .elementhasfocus which is added and removed within the jQuery focus() function. When the hover() function runs on mouse out, it checks for .elementhasfocus:
if(!$("#quotebox").is(".boxhasfocus")) $(this).removeClass("box_border");
So if it doesn't have that class (read: no elements within the div have focus) the border is removed. Otherwise, nothing happens.
Simple
<input type="text" />
<script>
$("input").focusin(function() {
alert("I am in Focus");
});
</script>
Related
assuming I have a (very large) div tag and inside the div tag I have a (normal size) button, now I want to be able to create a shortcut that if a user is hovering over the div tag, they can press return key to click the button.
$(window).keypress(function(e){
if (e.keyCode == xxx) {
$('div').hover(function(){
$('this button').click();
});
}
});
This is how I imagine it might look like in jQuery (didn't work obviously). I am open to suggestions. jQuery solutions are fine, plain javascript solutions are even better.
It's actually pretty easy.
$(window).keypress(function(e){
if (e.keyCode == xxx) {
$('div:hover button').click();
}
});
Don't use .hover() or .on('hover') because they are simply not selectors.
You can use .is(":hover") within your keypress handler to determine if the proper div is being hovered:
$(window).keypress(function(){
if($("#target").is(":hover")){
alert("pressed!");
}
});
http://jsfiddle.net/y7joukzw/2/
(NOTE: Make sure you click within the "result" frame to ensure it is the active frame when testing the jsfiddle)
Rather than checking for hover on every keypress, you're better off reversing the order of event checking so that you only incur the keypress overhead while the user is hovering. Something like:
function checkKeypress(e) {
// Check keypress and perhaps do something
}
$('div').hover(
function(){
$(window).keypress(checkKeypress);
},
function() {
$(window).off('keypress', checkKeypress);
}
);
I'm doing a simple show/hide on a search form that uses jQuery's toggleClass() and CSS to show and hide the form. That's easy enough, something like:
$('#site-search-toggle').click(function(e){
$('#site-search').toggleClass('search-open');
e.preventDefault()
});
What I'd like to do but am having a hard time figuring out is to put focus on the search input when the form is shown and remove the focus from the search input when the form is hidden.
It's easy to add focus:
$('#site-search-toggle').click(function(e){
$('#site-search').toggleClass('search-open');
$('#site-search input[type="search"]').focus();
e.preventDefault()
});
But I'm stuck at how to remove it when $('#site-search-toggle') is clicked again to hide the form.
Just found this thread as I've been banging my head against this problem for a while now.
I've found a very simple way to do this, and essentially all you need to do is provide a click handler. When the element is clicked, you toggle the class which controls the 'focused' state, but you also programatically focus the element:
document.getElementById('myelement').addEventListener('click', function() {
this.classList.toggle('focus'); // or whatever...
this.focus();
});
You will need to give the element some sort of 'tabindex' value, probably 0 or -1.
And then, you provide a 'blur' handler, which just removes the 'focus' class whenver the user navigates away from the element.
document.getElementById('myelement').addEventListener('blur', function() {
this.classList.remove('focus');
return false;
});
Works like a dream!
I'm sorry that this is not a jQuery answer, but it should be easy enough to adapt - I just don't use it...
Danny
OK I figured this one out, or at least I found a way to do what I need to do. I added a second class, search-closed, toggled both classes, then used each class to focus or blur the field, something like this:
$('#site-search').addClass('search-closed');
$('.site-search__toggle').click(function(e){
// toggle both classes
$('#site-search').toggleClass('search-open search-closed');
// set focus when form is visible, .search-open
// use setTimeout to make sure the cursor actually gets in there
// don't know why, but it works
setTimeout (function(){
$('#site-search.search-open .site-search__input').focus();
}, 20);
// blur when the form is not visible, .search-closed
$('#site-search.search-closed .site-search__input').blur();
});
Try this:
$('#site-search-toggle').click(function(e){
$('#site-search').toggleClass('search-open');
if ($('#site-search').hasClass('search-open')) {
$('#site-search input[type="search"]').focus();
} else {
$('#site-search input[type="search"]').blur();
}
e.preventDefault();
});
I'm not looking for an action to call when hovering, but instead a way to tell if an element is being hovered over currently. For instance:
$('#elem').mouseIsOver(); // returns true or false
Is there a jQuery method that accomplishes this?
Original (And Correct) Answer:
You can use is() and check for the selector :hover.
var isHovered = $('#elem').is(":hover"); // returns true or false
Example: http://jsfiddle.net/Meligy/2kyaJ/3/
(This only works when the selector matches ONE element max. See Edit 3 for more)
.
Edit 1 (June 29, 2013): (Applicable to jQuery 1.9.x only, as it works with 1.10+, see next Edit 2)
This answer was the best solution at the time the question was answered. This ':hover' selector was removed with the .hover() method removal in jQuery 1.9.x.
Interestingly a recent answer by "allicarn" shows it's possible to use :hover as CSS selector (vs. Sizzle) when you prefix it with a selector $($(this).selector + ":hover").length > 0, and it seems to work!
Also, hoverIntent plugin mentioned in a another answer looks very nice as well.
Edit 2 (September 21, 2013): .is(":hover") works
Based on another comment I have noticed that the original way I posted, .is(":hover"), actually still works in jQuery, so.
It worked in jQuery 1.7.x.
It stopped working in 1.9.1, when someone reported it to me, and we all thought it was related to jQuery removing the hover alias for event handling in that version.
It worked again in jQuery 1.10.1 and 2.0.2 (maybe 2.0.x), which suggests that the failure in 1.9.x was a bug or so not an intentional behaviour as we thought in the previous point.
If you want to test this in a particular jQuery version, just open the JSFidlle example at the beginning of this answer, change to the desired jQuery version and click "Run". If the colour changes on hover, it works.
.
Edit 3 (March 9, 2014): It only works when the jQuery sequence contains a single element
As shown by #Wilmer in the comments, he has a fiddle which doesn't even work against jQuery versions I and others here tested it against. When I tried to find what's special about his case I noticed that he was trying to check multiple elements at a time. This was throwing Uncaught Error: Syntax error, unrecognized expression: unsupported pseudo: hover.
So, working with his fiddle, this does NOT work:
var isHovered = !!$('#up, #down').filter(":hover").length;
While this DOES work:
var isHovered = !!$('#up,#down').
filter(function() { return $(this).is(":hover"); }).length;
It also works with jQuery sequences that contain a single element, like if the original selector matched only one element, or if you called .first() on the results, etc.
This is also referenced at my JavaScript + Web Dev Tips & Resources Newsletter.
Use:
var hovered = $("#parent").find("#element:hover").length;
jQuery 1.9+
It does not work in jQuery 1.9. Made this plugin based on user2444818's answer.
jQuery.fn.mouseIsOver = function () {
return $(this).parent().find($(this).selector + ":hover").length > 0;
};
http://jsfiddle.net/Wp2v4/1/
The accepted answer didn't work for me on JQuery 2.x
.is(":hover") returns false on every call.
I ended up with a pretty simple solution that works:
function isHovered(selector) {
return $(selector+":hover").length > 0
}
Set a flag on hover:
var over = false;
$('#elem').hover(function() {
over = true;
},
function () {
over = false;
});
Then just check your flag.
Couple updates to add after working on this subject for a while:
all solutions with .is(":hover") break on jQuery 1.9.1
The most likely reason to check if the mouse is still over an element is to attempt to prevent events firing over each other. For example, we were having issues with our mouseleave being triggered and completed before our mouseenter event even completed. Of course this was because of a quick mouse movement.
We used hoverIntent https://github.com/briancherne/jquery-hoverIntent to solve the issue for us. Essentially it triggers if the mouse movement is more deliberate. (one thing to note is that it will trigger on both mouse entering an element and leaving - if you only want to use one pass the constructor an empty function )
You can filter your elment from all hovered elements.
Problematic code:
element.filter(':hover')
Save code:
jQuery(':hover').filter(element)
To return boolean:
jQuery(':hover').filter(element).length===0
Expanding on #Mohamed's answer. You could use a little encapsulation
Like this:
jQuery.fn.mouseIsOver = function () {
if($(this[0]).is(":hover"))
{
return true;
}
return false;
};
Use it like:
$("#elem").mouseIsOver();//returns true or false
Forked the fiddle:
http://jsfiddle.net/cgWdF/1/
I like the first response, but for me it's weird. When attempting to check just after page load for the mouse, I have to put in at least a 500 millisecond delay for it to work:
$(window).on('load', function() {
setTimeout(function() {
$('img:hover').fadeOut().fadeIn();
}, 500);
});
http://codepen.io/molokoloco/pen/Grvkx/
https://api.jquery.com/hover/
Asynchronous function in line 38:
$( ".class#id" ).hover(function() {
Your javascript
});
Setting a flag per kinakuta's answer seems reasonable, you can put a listener on the body so you can check if any element is being hovered over at a particular instant.
However, how do you want to deal with child nodes? You should perhaps check if the element is an ancestor of the currently hovered element.
<script>
var isOver = (function() {
var overElement;
return {
// Set the "over" element
set: function(e) {
overElement = e.target || e.srcElement;
},
// Return the current "over" element
get: function() {
return overElement;
},
// Check if element is the current "over" element
check: function(element) {
return element == overElement;
},
// Check if element is, or an ancestor of, the
// current "over" element
checkAll: function(element) {
while (overElement.parentNode) {
if (element == overElement) return true;
overElement = overElement.parentNode;
}
return false;
}
};
}());
// Check every second if p0 is being hovered over
window.setInterval( function() {
var el = document.getElementById('p0');
document.getElementById('msg').innerHTML = isOver.checkAll(el);
}, 1000);
</script>
<body onmouseover="isOver.set(event);">
<div>Here is a div
<p id="p0">Here is a p in the div<span> here is a span in the p</span> foo bar </p>
</div>
<div id="msg"></div>
</body>
Is there a way to disable (with CSS, JS or jQuery) double-click for a given element?
The problem with Opera is that it displays a menu when I click on an element too fast. Note that I know how to disable this for me. I'd like to be able to disable this for all user that use the script.
The buttons in question are "next"/"previous" buttons and I use input type image for them, but the same happens with "a".
It turended out I need this:
/**
Disable text selection by Chris Barr, of chris-barr.com
*/
$.fn.disableTextSelect = function() {
return this.each(function(){
if($.browser.mozilla){//Firefox
$(this).css('MozUserSelect','none');
}else if($.browser.msie){//IE
$(this).bind('selectstart',function(){return false;});
}else{//Opera, etc.
$(this).mousedown(function(){return false;});
}
});
}
And then I could disable text selection on my button elements like this:
$(function(){ $('input[type=image]').disableTextSelect(); });
And now I can click buttons fast as hell and all works fine :-).
You cannot have a click and dblclick event handler attached on the same element because when you dblclick both the events are going to be triggered. In order to make it work there are few work arounds.
This might help you
Need to cancel click/mouseup events when double-click event detected
Looking at your problem there is a simple solution. In the click event handler once it is clicked set a disabled attribute or some class name(disabled). In the handler before exectuing your code checck for this attribute or class name. If it exists then dont do anything. After sometime remove this attribtue or class name. Try this
$("selector").click(function(){
var $this = $(this);
if(!$this.hasClass("disabled")){
//Do you stuff here
$this.addClass("disabled");
setTimeout(function(){
$this.removeClass("disabled");
}, 200);
}
});
JavaScript would do that for you.
DOMElement.ondblclick = (function () {return false;})();
I've got two input boxes in a div, I want to hide that div on the focusOut of the inputs, but only if both of them do not have focus.
This is a common Firefox problem (some call it adhering to standard), but the document body steals focus between.
HTML
<div id="baz">
<input type="text" id="foo" name="foo" />
<input type="text" id="bar" name="bar" />
</div>
jQuery
// jQuery Example
jQuery(":input").focusout(function(){
// Don't do anything if one of the input boxes has focus
if( jQuery(":input").is( jQuery(document.activeElement) ){ return; }
// Hide the container if one of the inputs loose focus
jQuery(this).parents("div").css("display","none");
}
Though this is a common bug, I forget how I solved it in the past. I think it had something to do with setting a timeout, or doing a screen refresh, before checking for the activeElement.
jsFiddle Example
jsFiddle Updated (FF4 Same Problem)
Demo
jQuery(":input").focusout(function(){
var elem = jQuery(this).parent("div");
window.setTimeout(function(){
// Don't do anything if one of the input boxes has focus
if( jQuery(":input").is( jQuery(document.activeElement) )){ return; }
// Hide the container if one of the inputs loose focus
elem.hide();
}, 0);
})
Demo
jQuery(document).ready(function () {
var timeoutID;
jQuery(":input").focus(function () {
window.clearTimeout(timeoutID);
}).focusout(function () {
timeoutID = window.setTimeout(function () {
jQuery("#baz").hide();
}, 0);
});
});
I think amit_g's solution was almost there. I vaguely remember that I've went about this in two ways:
compare the inputs to the activeElement (the method showed above)
setting/clearing a "focus" class on the element for the respective events
I think both methods required using setTimeout, since Firefox has a delayed trigger, which we need to force. While I've heard FF is adhering to standards here, I personally think that standard needs to be amended.
So in addition to adding the timed function call, it also needed to be cleared if the other "acceptable" element gained focus. The following is not production code but it does show it does serve as an example:
Example Solution
Example Solution (Even Better) - set $debug to false
Example Solution (Localized Blocks) - removed debugging clutter