Detect when mouse actually moves, not just when the page moves - javascript

I'm having a pretty big problem trying to create navigation on my page. If the mouse enters an element then it selects it, then if you use arrow keys it will select the elements relative to the selected one. However this is an issue when the arrow keys cause the page to scroll, because (depending on the position of the mouse) it will select the appropriate element then instantly select the item the mouse is now over after the page moved (even if you didn't move the mouse).
Does anyone know how to fix this problem? I tried tinkering with it but none of my solutions seemed to work. Any help is appreciated, thank you.

It sounds like you should bind the "select when mouse enters" event on mousemove and unbind said event on mousestop. mousestop does not exist on its own, so you will have to create it somehow or use a plugin (there are at least a few out there such as https://github.com/richardscarrott/jquery-mousestop-event/ ). I think this would be the simplest solution, but your UI seems a little bizarre (you want the arrow key to scroll the page normally and "select" an element that's possibly larger than the scroll size?)

Not sure I completely understand, but you should be able to use a combination of the mousemove and keypress events:
$("#element").mousemove(function(e){
alert("mouse moved");
});
$("#element").keypress(function(e){
if (e.keyCode == 38 || e.keyCode == 40){ //up & down arrow keys
e.preventDefault();
}
});

Try returning false from the keyboard event handler where you check for arrow keys:
element.onkeypress = function(ev) {
// ...
return false;
}
This will prevent the "default behavior" that the browser has for the event, which is to scroll. This works also for links, for example: if you return false from a click event handler for a link, clicking the link will not automatically follow it.

Related

Making the scrolling keys scroll the proper page element

I have a DIV in my page that is scrollable, while no other elements on the page are. (The page layout is fixed with controls above and below the DIV itself.) I would like the arrow keys and page up/page down to scroll the DIV under all circumstances, but I cannot seem to do so unless the DIV actually has the focus. There are other input fields in other DIVs which often have focus. I have tried capturing the arrow keys and page/up down 'keydown' event at the document level and simulating the same event directly (using answers from this question) to the DIV that needs to scroll, but no scrolling occurs. I know the event is being dispatched because if I attach an event handler I see it, but for some reason it doesn't cause any scrolling. I have also tried setting the "tabIndex" attribute of the DIV with no difference.
How can I designate a specific element to receive specific keys like this? It is extremely user unfriendly to require a specific element to be focused for certain keys to work, when those keys only make sense for a single element on the page. Having to constantly switch focus from another element to the scrollable area to scroll and back to enter data just isn't acceptable.
I have seen suggestions that scrolling can be simulated by other means, but I want to avoid that route because this doesn't always produce identical results, and I also want to generalize it to other kinds of key events and action besides scrolling.
You can scroll any element by adjusting its scrollTop DOM property.
If you capture all the keydown events on the document and then decide on what action you want to take depending on the key pressed (use the which property of the event object) and maybe some other circumstances (inputs focused, controls checked etc.) you can easily scroll your div. Check out this fiddle for a simple demo.
you can you keypress or keyDown events on the document and trigger actions on your DIV.
$(document).ready(function(){
$(document).on("keydown", handleKeyDown);
function handleKeyDown(evt) {
var code = parseInt(evt.keyCode); // the key Code of the key which was pressed during the event /and parses it and returns a 'integer'.
if(code == 38){ // 38 is the keycode for UP key on the keyboard
alert("up");
} else if(code == 40) // 40 is the keycode for down key on the keyboard.
alert("down");
}
}
});
and as explained in breif by Tadeáš Peták you can use the scrollTop DOM property to scroll any element, enjoy.

Prevent right/left arrow navigation in select

I have 3 selects that I am enabling keyboard navigation(right and left arrow keys) to move between them. The default behavior when pressing the right or left arrow key is to move up/down the list.
My solution works moving between the selects, but every time you move to a new select, the selected value in the select that you just moved from gets moved up or down depending on which arrow you pressed.
Is there a way to prevent the default right and left arrow keys for the selects? I have tried e.preventPropagation and e.preventDefault but that doesn't seem to work.
JSFIDDLE
I just figured it out. I was binding to keypress event, when I needed to bind to the keydown event. When binding to keydown then you can use e.preventDefault().
JSFIDDLE SOLUTION
Since OP's solution does not work in Firefox, I created a workaround for the known bug in Firefox.
Basically event.preventDefault doesn't prevent ← and → on <select> nodes in Firefox.
So here's the workaround in action.
For more information on this, see my detailed answer on similar question
No way to get it work in Firefox preventing event default.... And Ruud solution is too complicated. So I've implemented that simple and clean solution, based on the same idea:
$('select').on('keydown', function( e ){
switch(e.keyCode) {
// User pressed "left" or "right" arrow
case 37:
case 39:
var val = $(this).val();
var $slt = $(this).one('change', function(){
$slt.val( val ).change();
});
break;
}
});
The only inconvenient is that "change" event is triggered twice, so you're app may take care about that.

Mouse cursor disaappears on keypress event in Jquery

I am using arrow keys to move an object in my code. Everything works fine except that the mouse cursor disappears when I press any of the arrow keys. How can I make the cursor stay visible? I am using this code check for arrow keys pressed.
$(document).ready(function() {
$(document).keydown(function(event) {
checkKeys(event);
}).keyup(function(event) {
keyUp(event);
});
});
That's browser behavior (maybe even OS behavior!), you probably won't find a way to stop it with javascript.
It's intended to hide the cursor so you can see what you're typing. Try it on any website, keystrokes always make the mouse cursor go away.

jQuery find(':focus') not acting as expected

I'm making a widget that slides in and out of view on hover with showTracker and hideTracker functions. I want to prevent it from sliding out of view if it contains a focussed form element though, so I've got this going:
function hideTracker(){
if($('#tracker').find(':focus').length == 0){
$('#tracker').stop().hide();
}
}
Cool. Now it doesn't hide if the mouse happens to move out if there's a field in focus. Unfortunately, that also means that when the field does lose focus (and it's time for the widget to hide again) it just stays there. The unHover event has been and gone.
So I added this:
$('#tracker *').blur(function(){
hideTracker();
});
And that works too - with one little bug that I need help with!
If the focus moves from one element within the tracker to another which is also within #tracker, the tracker hides. I figured that if($('#tracker').find(':focus').length == 0) would return false, given that the next form element has focus, but I guess it doesn't.
Is it the case that .blur() fires before the next element attains focus?
How can I get around this?
How about something like this?
$('body *').focus(function(){
if(!$(this).is('#tracker *') && $('#tracker:visible').length != 0) hideTracker();
});
Yikes. Tricky. Yes, what's happening is:
mousedown: old form element gets the blur event. $(':focus').length == 0.
mouseup: new form element gets the focus event. $newFormElement.is(':focus') == true.
This is an improvement:
$('#tracker').focusout(function() //basically like $('#tracker, #tracker *').blur(), but "this" is always '#tracker'
{
if(!$(this).is('#tracker:hover')) //for some reason plain old :hover doesn't work, at least on the latest OS X Chrome
hideTracker();
});
But it's not perfect. It only really works if you use the mouse. If you use tab to move between fields (or some other possible mechanism) while your mouse is not hovering over #tracker, it won't work.
Here's another attempt. It's a bit...hackier. The gist is that, instead of handling the blur event, you handle the focus event of the second thing that's focused. But! What if you click something that can't be focused? Blank space on your page? Then no focus event is fired.
Okay. So the trick is: put a tabindex="0" in your root <html> tag. This means that there is always something that can be focused. So there's no way to focus on nothing (at least, I don't think so).
Then you can do this:
$('*').live('focus', function(e)
{
if(!$.contains($('#tracker')[0], this)) //if the new thing you focused on is not a descendant of #tracker
hideTracker();
e.stopPropagation();
});
Eh? So yeah, that's a certified hack. But it's a tough problem, and that's the best I can come up with at this hour.
Thank you all for your answers. Utilising the .focus() event rather than .blur() was a clever way to look at it. Unfortunately, it does raise a couple of browser problems, and I couldn't get any of the above working very robustly.
In the end I decided to use setTimeout(hideTracker, 100); to allow the focus() event to take place before the count of focussed elements within tracker was evaluated. Not ideal, but it's working well and the delay is fairly imperceptible.
Thanks again.

How to disable page scrolling in FF with arrow keys

I'm building a menu with topics and items. Each topic can be expanded and collapsed by clicking on it. My task is to make it possible to move through menu topics and items with the up and down arrow keys. I've done this already, but the problem is that when the page is bigger than the window, the page is scrolling when pressing the arrow keys. I've tried using:
document.body.style.overflow = "hidden";
to stop the page from scrolling. Thus when I click on 'Topic2' for example I can continue using the arrow keys to go to next topic/item. After that if I click anywhere else on the screen I set the overflow back to auto and the page can be scrolled again.
This works in IE, but not in FF. In FF the scrollbars are being removed and the mousewheel doesn't scroll the page, but the arrow keys still DO. So my question is how to fix that,
or better, how not to scroll the page when the focus is on any menu element? Thus I won't use the overflow property.
You have to bind a keydown event to the document, and if the event keycode matches any of the arrow keys (37 through 40), return false. That way the arrow press won't go any further.
document.onkeydown = function(e) {
var k = e.keyCode;
if(k >= 37 && k <= 40) {
return false;
}
}
You can easily expand on that to work only when your menu is active, but without seeing some of it's code, it's impossible to give you an example.
below code has fixed the problem
$(window).scroll(function () {
window.scrollTo(0,0);
});
The only way I can see is intercepting the keydown event and doing the blurring/focusing yourself.
There seem to be some gotchas with catching those keys, see this question for a number of (JQuery based) examples that look quite promising.

Categories