mousemove and cross-browser e.which - javascript

I need to know which mouse key is pressed on every mousemove event, and I try to use this:
getMouseCode: function(e) {
e = e || window.event;
if (!e.which && e.button) {
if (e.button & 1) e.which = 1;
else if (e.button & 4) e.which = 2;
else if (e.button & 2) e.which = 3;
};
return e.which;
},
But this is works only in chrome and IE7-8. IE9 debugger always says e.button == 0 and e.which == 1. After some debugging I figured out that window.event for IE9 contains right value of which, so I swapped
e = window.event || e;
This also does the trick for Safari & Air, but Firefox has window.event undefined, and Opera has the same wrong values in both callback argument and window.event objects.

I was looking at this question when investigating a related issue. It turned out that my issue was that I needed to use separate functions to handle onclick and onmouseover events.
I have found that when using Opera, Safari and FireFox, the "which" property of the mousemove event object is set to 1 when no mouse button has been clicked.

Though this answer may be kind of late, I am sure it will help those in the future. I stumbled upon this question while searching for this cross browser feature and originally disregarded it. I am back to provide my answer for those that follow in my footsteps.
First, some knowledge. I found this site very helpful, as all the cross browser issues (well most) are worked out, and laid out for your amusement (I laugh when us developers need to create charts and diagrams to how browsers work..)
http://unixpapa.com/js/mouse.html
On this page, near the bottom, you will find a blue link that says "Click here with various mouse buttons to test", above this you will see a code snippet. This goes into your mousedown or mouseup. If you right click and view the source at this location, you will find a script tag that holds 2 functions, the one above this link, and a 'dont' function that prevents the events from doing their default, or falling through, though not needed in all cases, is useful to know about.
The second piece of knowledge comes from another website, and provides us some insight into how to capture the mouse wheel up and down events.
http://www.javascriptkit.com/javatutors/onmousewheel.shtml
To put this all together in 1 place, we basically have the following..
function GetMouseButton(e) {
// Normalize event variable
var e = window.event || e;
// Set button to initially not recognized (or false if you need to to be)
var button = 'Not Recognized';
// Check if this is a button push event
if(e.type == 'mousedown' || e.type == 'mouseup') {
if (e.which == null) {
// Check if IE, if so, what e.button was pressed
button = (e.button < 2) ? "Left" :
((e.button == 4) ? "Middle" : "Right");
} else {
// All other browsers, what e.which was pressed
button = (e.which < 2) ? "Left" :
((e.which == 2) ? "Middle" : "Right");
}
} else {
// If this is not a button push event, then we get the direction
var direction = e.detail ? e.detail * (-120) : e.wheelDelta;
// And name the direction as a 'button'
switch(direction) {
case 120: // Browsers use different variants of these
case 240:
case 360:
button = "Middle Scroll Up";
break;
case -120:
case -240:
case -360:
button = "Middle Scroll Down";
break;
}
}
alert(button);
}
/* Simple Bind function (like jQuery's for example) */
function Bind(elem, type, eventHandle) {
if (elem == null || elem == undefined) return;
if ( elem.addEventListener ) {
elem.addEventListener( type, eventHandle, false );
} else if ( elem.attachEvent ) {
elem.attachEvent( "on" + type, eventHandle );
} else {
elem["on"+type]=eventHandle;
}
}
/* Bind your mousedown / mouseup to the window, as well as the mousewheel */
Bind(window, 'mousedown', GetMouseButton);
Bind(window, 'mouseup', GetMouseButton);
/* One of FireFox's browser versions doesn't recognize mousewheel,
* we account for that in this line
*/
var MouseWheelEvent =
(/Firefox/i.test(navigator.userAgent))? "DOMMouseScroll" : "mousewheel";
Bind(window, MouseWheelEvent, GetMouseButton);
To save you some time [and knowledge, if you don't care to look at these links], you can view a working example at the following jsfiddle:
http://jsfiddle.net/BNefn/
EDIT
I should have also said, that since you need to know this on every mousemove event, you can simply store the resulting button 'name' and event type (down or up), and then recall that variables information during your mousemove event. If you have a variable for each of these "buttons" you can then see which button is pressed and which isn't, and clear the variables that are pressed on mouseup.

Related

jquery mobile - keyup keydown on mobile devices

I have a need for an input (type='text') to go send results to the my server to check availability of something typed by the user.
I use the delegate to add the event handlers to the elements:
$(document).delegate('#signup', 'pageshow', function() {
var keydown = function(e) {
e = e || window.event;
var char = e.which || e.keyCode;
if (char == 8) {
$(".pagemessage").text("Pressed: '<BACKSPACE>'");
appcheckDomainOnKeyDown();
}
return true;
};
var keyup = function(e) {
e = e || window.event;
var char = e.which || e.keyCode;
if (char == 8) {
appcheckDomainOnKeyUp();
}
return true;
};
var keypress = function(e) {
e = e || window.event;
var char = e.which || e.keyCode;
var str = String.fromCharCode(char);
$(".pagemessage").text("Pressed: '" + str +"'");
if (/[a-zA-Z0-9-\._]/.test(str) || char == 8 || char == 9) {
appcheckDomainOnKeyDown();
appcheckDomainOnKeyUp();
return true;
}
return false;
};
The key handers work perfectly on my desktop but not on a mobile device. Hopefully you can see that I'm trying to allow certain characters into the box (and a backspace to delete the characters.
From the fact I cannot see the pagemessage element update, 'keypress' does not seem to be trapped. I tried handling this in the keyup/keydown, but I'm not sure how to apply the shiftKey bits to get an actual character pressed - for example pressing + 5 would give '%' however in the keydown it returns shiftKey and 5.
I read the documentation and the closest I could find to 'keypress' was a 'tap' event, but that didn't work either.
I have tried trapping the 'keypress' event as suggested in one post here, and on a desktop this does not trap the backspace, and does nothing at all on a mobile device.
I then tried this as suggested in another post:
var inputEV = 'oninput' in window ? 'input' : 'keyup';
$("#new_domain").off(inputEV);
$("#new_domain").on(inputEV, function (e) {
keydown(e);
keyup(e);
});
and it does not work in either desktop browser or mobile device.
I then tried changing the input type to 'search', and I get a pretty enhancement, that a keypress does add a clear button... but does nothing on the mobile device regarding my own functionality.
I think I have run out of things to try, the only thing left is to add a button to go check - and no one wants that :)
Anyone know how I can do what I need?
In case it's relevant, I'm using chrome on my desktop and android device (HTC one, and Nexus 5)
Keyup should work. It works in this example: http://jsbin.com/aNEBIKA/2/. That tested find on my Galaxy S3. Each keypress updates the footer h3 element with the text entered.
Could it be that you are binding your listeners at the wrong time? The documentation does suggest binding like this:
$(document).bind('pageinit')
http://demos.jquerymobile.com/1.2.0/docs/api/events.html

How to keep the OS "Save As" dialog from poppng up when Ctrl S is entered

I have some JavaScript that gets triggered by Ctrl + S and saves a local structure, call "group" below. But despite the last three lines of the code, the OS (Windows 7) "Save As" dialog pops up. Is there any way to keep the OS from popping up its Save As dialog?
Thanks
$(document).on('keydown',function(e) {
if ( e.ctrlKey && e.keyCode == 83 ) { // CTRL+S - save group
var raw_groupName = prompt("Group Name: ", g.last_groupName);
var groupName = raw_groupName.replace(/ /g,"_");
saveGroup(groupName);
e.stopPropagation();
e.preventDefault();
return (false);
};
}
I listened for the keydown event and attached the listener to the window object.
window.addEventListener('keydown', function (evt) {
if (evt.ctrlKey && evt.keyCode === 83) {
evt.preventDefault();
}
}, false);
Above code works for me: http://jsfiddle.net/s66JK/
You are probably listening to the onkeypress event which will always give you an e.keyCode equal to 0. Have you tried putting a breakpoint inside your if ? It's most likely always false. onkeypress uses e.charCode.
I tried your code and it works with the onkeydown event.

how to add dbclick() on right click in jquery

Hi I want to have a dblclick() on the right click as the google maps have to zoom in and zoom out. Is there any way to do that. I have written the dblclick but now its working with only left click. Any pointers on how to do this. Here is my code
$("div#demo1").dblclick(function(e) {
//alert(e.getElementById());
if( (!$.browser.msie && e.button == 0) || ($.browser.msie && e.button == 1) ) {
alert("Left Mouse Button was clicked on demo1 div!");
$("div.window").animate({
'height':'+=20', 'width':'+=20'
},0,function(){
jsPlumb.repaintEverything();
jsPlumb.repaintEverything();
});
// Left mouse button was clicked (all browsers)
}
else if( (!$.browser.msie && e.button == 2) || ($.browser.msie && e.button == 3) ) {
alert("right click double");
}
});
There is another way you could detect a double right-click that does not involve fiddling with timers or keeping track of click counts manually. Using the .detail property of the event object in a mouseup or mousedown event. .detail holds the click count which will tell you how many clicks have happened recently. If .detail === 2 it was a double-click.
// suppress the right-click menu
$('#target').on('contextmenu', function (evt) {
evt.preventDefault();
});
$('#target').mouseup(function (evt) {
if (evt.which === 3) { // right-click
/* if you wanted to be less strict about what
counts as a double click you could use
evt.originalEvent.detail > 1 instead */
if (evt.originalEvent.detail === 2) {
$(this).text('Double right-click');
} else if (evt.originalEvent.detail === 1) {
$(this).text('Single right-click');
}
}
});
You might notice that I am using evt.originalEvent.detail to access the property instead of just .detail. This is because jQuery provides it's own version of the event object which does not include .detail, but you can access the original event object that the browser returned via .originalEvent. If you were using pure JavaScript instead of jQuery you would just use evt.detail.
Here's a working example.
There is no real way to do it, you can emulate it by taking the default timer for double clicks which IIRC is 300ms:
function makeDoubleRightClickHandler( handler ) {
var timeout = 0, clicked = false;
return function(e) {
e.preventDefault();
if( clicked ) {
clearTimeout(timeout);
clicked = false;
return handler.apply( this, arguments );
}
else {
clicked = true;
timeout = setTimeout( function() {
clicked = false;
}, 300 );
}
};
}
$(document).contextmenu( makeDoubleRightClickHandler( function(e) {
console.log("double right click" );
}));
http://jsfiddle.net/5kvFG/2/
Because the right-click has meaning to the user agent that is outside the purview of javascript (the context menu), you're going to have to do some dancing around.
First, you should disable the context menu on the target element:
document.getElementById('demo1').oncontextmenu = function() {
return false;
};
Now, when we right click, there won't be the context menu messing up the second click.
Next, understand that "double-click right" does not, generally speaking, exist. Even though you can bind the dblclick event, that isn't a generic event. "Double-click" is, by definition, double-clicking with the left mouse button.
So, we'll have to use the mousedown event, check to see how many times the right has been clicked, and react after two. I created a small helper function that keeps track of the click count and resets the state after a short time-frame.
var RightClick = {
'sensitivity':350,
'count':0,
'timer':false,
'active':function () {
this.count++;
this.timer = setTimeout(
this.endCountdown.bind(this),
this.sensitivity
);
},
'endCountdown': function () {
this.count = 0;
this.timer = false;
}
};
$("div#demo1").mousedown(function(e) {
if(e.which == 3) {
RightClick.active();
if (RightClick.count == 2)
alert("right click double");
}
});
Try it here: http://jsfiddle.net/94L7z/
You can adjust the sensitivity rate, allowing for shorter or longer double-clicks, depending on your preference.
Documentation
element.onContextMenu on MDN - https://developer.mozilla.org/en-US/docs/DOM/window.oncontextmenu
element.onMouseDown on MDN - https://developer.mozilla.org/en-US/docs/DOM/element.onmousedown
window.setTimeout on MDN - https://developer.mozilla.org/en-US/docs/DOM/window.setTimeout
jQuery event.which - http://api.jquery.com/event.which/
"Javascript Madness: Mouse Events" on UnixPapa.com, an article showing some tests related to mouse events and the left/right buttons - http://unixpapa.com/js/mouse.html
The problem is the concept of double clicking is only relevant to the left mouse button as far as JS is concerned. So no matter how many time, and how fast you click the right mouse button, it just registers as a bunch of single clicks. So what to do?
Create a global variable to track click count
detect a single right-click, you already know how to do this it seems
set the global variable that the right-click was fired once
set a timeout, so if another right click doesn't come through in a
reasonable time to be considered a dblclick the global variable
resets to 0. I recommend 300 ms, it seems to be the most natural
each time a right-click registers check that variable, if it's more
than one, fire your double-right-click handler.
you may want to make that global variable an object so you can track which element
registered the right click and expire specific element right clicks
accordingly. This will allow you to ignore if they double click
while moving the mouse over various objects. I consider this
optional as the chain of events are unlikely for a user to follow,
but depending on your app may result in unexpected functionality.
It might be better to define a jQuery function with this (try it):
var precision = 400;
var lastClickTime = 0;
$(document).ready(function()
{
var div = $('#div');
$(div).bind("contextmenu", function(e)
{
return false;
});
$(div).mousedown(function(event)
{
if (event.which == 3)
{
var time = new Date().getTime();
if(time - lastClickTime <= precision)
{
// DOUBLE RIGHT CLICK
alert('double click');
}
lastClickTime = time;
}
});
});

Remove Any Spaces While Typing into a Textbox on a Web Page Part II

This involves HTML + JS and/or JQuery:
I would have commented on the previous post, but I don't have comment reputation or cannot comment for some reason.
Josh Stodola's great code from Part I is as follows:
$(function() {
var txt = $("#myTextbox");
var func = function() {
txt.val(txt.val().replace(/\s/g, ''));
}
txt.keyup(func).blur(func);
});
This works great except .replace puts the cursor at the end of the string on every keyup (at least in IE8 and Chrome).
As a result, it renders the left & right cursor keys useless, which is needed inside the input box.
Is there any way to enhance the above code so that the cursor keys do not activate it, but so that the text still gets updated on the fly?
The best solution is to avoid using key events to capture text input. They're not the best tool for the job. Instead, you should use the HTML5 oninput event (supported in the latest and recent versions of every current major browser) and fall back to onpropertychange for older versions of Internet Explorer:
var alreadyHandled;
txt.bind("input propertychange", function (evt) {
// return if the value hasn't changed or we've already handled oninput
if (evt.type == "propertychange" && (window.event.propertyName != "value"
|| alreadyHandled)) {
alreadyHandled = false;
return;
}
alreadyHandled = true;
// Your code here
});
These events don't fire for keys that don't result in text entry — don't you just hate it when you shift-tab back to a form element and the resulting keyup event causes the page's script to move focus forward again?
Additional benefits over key events:
They fire immediately when the key is pressed and not when the key is lifted, as in keyup. This means you don't get a visual delay before any adjustments to the text are made.
They capture other forms of text input like dragging & droppping, spell checker corrections and cut/pasting.
Further reading at Effectively detecting user input in JavaScript.
Update the function:
var func = function(e) {
if(e.keyCode !== 37 && e.keyCode !== 38 && e.keyCode !== 39 && e.keyCode !== 40){
txt.val(txt.val().replace(/\s/g, ''));
}
}
try:
$(function() {
var txt = $("#myTextbox");
var func = function(e) {
if(e.keyCode != "37" && e.keyCode != "38" && e.keyCode != "39" && e.keyCode != "40"){
txt.val(txt.val().replace(/\s/g, ''));
}
}
txt.keyup(func).blur(func);
});
$(function() {
var txt = $("#myTextbox");
var func = function() {
txt.val(txt.val().replace(/\s/g, ''));
}
txt.keyup(function(evt){
if(evt.keyCode < 37 || evt.keyCode > 40) {
func;
}
}).blur(func);
});
Something like that should do it. It will run the function if the keycode isn't 37,38,39 or 40 (the four arrow key keycodes). Note that it won't actually stop the cursor position moving to the end when any other key is pressed. For that, you'd need to keep track of the current cursor position. Take a look at this link for jCaret plugin, which can do this

How can I disabling backspace key press on all browsers?

I'm trying to disable the backspace button on an order page in all cases except when a textarea or text input is an active element to prevent users from accidentally backing out of an order. I have it working fine in most browsers, but in IE (testing in IE9, both regular and compatibility mode) it still allows the user to hit the backspace and go to the previous page.
Here's the code:
$(document).keypress(function(e){
var activeNodeName=document.activeElement.nodeName;
var activeElType=document.activeElement.type;
if (e.keyCode==8 && activeNodeName != 'INPUT' && activeNodeName != 'TEXTAREA'){
return false;
} else {
if (e.keyCode==8 && activeNodeName=='INPUT' && activeElType != 'TEXT' && activeElType != 'text'){
return false;
}
}
});
Any advice on what I'm doing wrong here?
Thanks!
I think you're overcomplicating that. Rather than checking for an active element, find the event target instead. This should give you the information you need. It's also better to use keydown rather than keypress when there is no visible character. Finally, it's better to use e.preventDefault() for better granularity.
$(document).keydown(function(e) {
var nodeName = e.target.nodeName.toLowerCase();
if (e.which === 8) {
if ((nodeName === 'input' && e.target.type === 'text') ||
nodeName === 'textarea') {
// do nothing
} else {
e.preventDefault();
}
}
});
NB I could have done this the other way round, rather than an empty if block and all the code going in the else block, but I think this is more readable.
Instead of keypress, try the keydown function, it will fire before the actual browser based hook. Also, putting in a preventDefault() function will assist in this. IE :
$(document).keydown(function(e){
e.preventDefault();
alert(e.keyCode);
});
Hope this helps.
The most Simple thing you can do is add the following one line in the very first script of you page at very first line
window.history.forward(1);
Most examples seem to be for the JQuery framework - Here an example for ExtJS
(I've been getting a lot of downvotes for this recently as the question now has JQuery tag on it, which it didn't previously. I can remove the answer if you like as isn't for JQuery but it's proven to help others not using that framework).
To use this add this code block to your code base, I recommend adding it inside the applications init function().
/**
* This disables the backspace key in all browsers by listening for it on the keydown press and completely
* preventing any actions if it is not which the event fired from is one of the extjs nodes that it should affect
*/
Ext.EventManager.on(window, 'keydown', function(e, t) {
var nodeName = e.target.nodeName.toLowerCase();
if (e.getKey() == e.BACKSPACE) {
if ((nodeName === 'input' && e.target.type === 'text') ||
nodeName === 'textarea') {
// do nothing
} else {
e.preventDefault();
}
}
});
Use e.which instead of e.keyCode; jQuery normalizes this value across browsers.
http://api.jquery.com/keydown/
To determine which key was pressed,
examine the event object that is
passed to the handler function. While
browsers use differing properties to
store this information, jQuery
normalizes the .which property so you
can reliably use it to retrieve the
key code.
Then, use e.preventDefault(); to prevent the default behaviour of moving to the previous page.
<html>
<head>
<script type="text/javascript">
function stopKey(evt) {
var evt = (evt) ? evt : ((event) ? event : null);
var node = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
if ((evt.keyCode == 8) && (node.type!="text")) {return false;}
}
document.onkeypress = stopKey;
</script>
</head>
<body onkeydown="return stopKey()">
<form>
<input type="TEXTAREA" name="var1" >
<input type="TEXT" name="var2" >
</form>
</body>
</html
I had to add the onDownKey attribute to the body in order to get editing keys to go to the functions.
$(document).keydown(function(e) {
var elid = $(document.activeElement).is('input');
if (e.keyCode === 8 && !elid) {
return false;
}
});
Hope this might help you
Seems like the "backspace" will also act as "navigation back" if you have selected radio buttons, check-boxes and body of document as well. Really annoying for forms - especially when using post. All the form could be lost with one slip of the "backspace" key -_- ...
Honestly... who's idea was it to allow the "backspace as a navigational "back" button!!! really bad idea in my opinion.
I disable the "backspace" default on anything that is not a text area or text field - like this:
$(document).keydown(function(e){
console.log(e.keyCode+"\n");
var typeName = e.target.type;//typeName should end up being things like 'text', 'textarea', 'radio', 'undefined' etc.
console.log(typeName+"\n");
// Prevent Backspace as navigation backbutton
if(e.keyCode == 8 && typeName != "text" && typeName != "textarea"){
console.log("Prevent Backbutton as Navigation Back"+typeName+"\n");
e.preventDefault();
}
//
})
Not sure where else one would want the normal behavior of a back-button other than in these two areas.
document.onkeydown = KeyPress;
function KeyPress(e) {
if (!e.metaKey){
e.preventDefault();
}
}

Categories