How to check fromElement/toElement in mouse event? - javascript

I'm trying to make a tooltip using JavaScript. Part of my script has function for debugging purposes:
function fnTooltip(e) {
if (e.type === "mouseout") {
console.log(...);
if ((e.fromElement === "td") && (e.toElement !== "td")) {
debugger;
console.log(...);
}
}
}
When i move mouse out from td cell, nothing happens. If i write to console "e.fromElement" and "e.toElement", they both are equal "[object HTMLTableCellElement]". In another part of my script using almost the same function but with event type "mouseover", everything works fine. So what am i doing wrong? How do i check e.fromElelement and e.toElement.
I also tried relatedTarget, target, srcTarget with same result.

Related

How to check if right mouse button pressed button?

I've been working all day on this with no progress. Anyways, I've got to build a SIMPLE JavaScript program, since we are only in the beginning phase, basically there should be a button and if I press it with the LEFT mouse button, it should alert("LEFT"), this part is easy because I can use onClick, but I should also check if I pressed the button with the RIGHT mouse button, in that case it should alert("RIGHT"). My struggle comes from the fact that it's easy to check the left button, but how do you actually do it with the right button? It might be a simple problem, but I don't seem to find a correct answer. Thank you in advance.
Simply check the event.button code
0 === left
2 === right
document.querySelector(buttonSelector).addEventListener('mousedown', (e) => {
if(e.button === 0){
alert('Left')
}else if(e.button === 2){
alert('Right')
}
});
I would add in this 'contextmenu' piece if you don't already have it to prevent the right click context menu from popping up.
document.getElementById('buttonID').addEventListener('mousedown', (e) => {
if (e.button === 0) {
console.log('Left')
} else if (e.button === 2) {
console.log('Right')
}
});
document.getElementById('buttonID').addEventListener("contextmenu", (e) => {
e.preventDefault();
return false;
});

How to identify a real click [duplicate]

I need to find a way to determine if a link has been activated via a mouse click or a keypress.
Save
The idea is that if they are using a mouse to hit the link then they can keep using the mouse to choose what they do next. But if they tabbing around the page and they tab to the Save link, then I'll open then next line for editing (the page is like a spreadsheet with each line becoming editable using ajax).
I thought the event parameter could be queried for which mouse button is pressed, but when no button is pressed the answer is 0 and that's the same as the left mouse button. They I thought I could get the keyCode from the event but that is coming back as undefined so I'm assuming a mouse event doesn't include that info.
function submitData(event, id)
{
alert("key = "+event.keyCode + " mouse button = "+event.button);
}
always returns "key = undefined mouse button = 0"
Can you help?
Could check if event.screenX and event.screenY are zero.
$('a#foo').click(function(evt) {
if (evt.screenX == 0 && evt.screenY == 0) {
window.alert('Keyboard click.');
} else {
window.alert('Mouse click.');
}
});
Demo on CodePen
I couldn't find a guarantee that it works in all browsers and all cases, but it has the benefit of not trying to detect a "click" done via the keyboard. So this solution detects "click" more reliably at the cost of detecting if it's from keyboard or mouse somewhat less reliably. If you prefer the reverse, look as the answer from #Gonzalo.
Note: One place I found using this method is Chromium
You can use event.detail
if(event.detail === 0) {
// keypress
} else {
// mouse event
}
You can create a condition with event.type
function submitData(event, id)
{
if(event.type == 'mousedown')
{
// do something
return;
}
if(event.type == 'keypress')
{
// do something else
return;
}
}
Note: You'll need to attach an event which supports both event types. With JQuery it would look something like $('a.save').bind('mousedown keypress', submitData(event, this));
The inline onClick="" will not help you as it will always pass that click event since that's how it's trapped.
EDIT: Here's a working demo to prove my case with native JavaScript: http://jsfiddle.net/AlienWebguy/HPEjt/
I used a button so it'd be easier to see the node highlighted during a tab focus, but it will work the same with any node.
You can differentiate between a click and a keyboard hit capturing and discarding the keydown event originated at the moment of the key press:
jQuery(function($) {
$("a#foo").keydown(function() {
alert("keyboard");
return false;
}).click(function() {
alert("mouse");
return false;
})
})
http://jsfiddle.net/NuP2g/
I know this is an old question but given how much time I lost looking for a working, no jquery and IE-compatible solution, I think it won't be a bad idea to put it here (where I came first).
I tested this and found it working fine :
let mouseDown = false;
element.addEventListener('mousedown', () => {
mouseDown = true;
});
element.addEventListener('mouseup', () => {
mouseDown = false;
});
element.addEventListener('focus', (event) => {
if (mouseDown) {
// keyboard
} else {
// mouse
}
});
Source link : https://www.darrenlester.com/blog/focus-only-on-tab
Wasn't able to come up with solution relying entirely on the events but you can position an anchor tag over a button and give it a tabindex of -1. This gives you a button that can be focused and engaged with keyboard enter/spacebar, as well as giving you a clickable surface that gives you an option to differentiate the two codepaths.
.button {
position: relative;
}
.anchor {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
<button id="button" class="button">
button
<a class="anchor" href="#example" tabindex="-1"></a>
</button>
I use the following
const isKeyboardClick = nativeEvent.detail === 0 && !nativeEvent.pointerType;
Works in evergreen browsers via detail and IE11 via pointerType. Does not work for the case where e.g. radio button <input> is wrapped by a <label> element.
Nowadays, you can make use of instanceof which even has full browser support.
function onMouseOrKeyboardSubmit(event, id) {
if (event instanceof KeyboardEvent) {
alert("Submitted via keyboard");
} else if (event instanceof MouseEvent) {
alert("Submitted via mouse");
} else {
alert("Unexpected submit event");
}
}
Handle the mouseup event.
If you get a click right afterwards, it was probably done with the mouse.

on down arrow KeyPress, click event is getting fired

on down arrow keypress , click event is getting fired, event.keycode is undefined
$(".dropdown:not(.li-search) a.dropdown-toggle", ".navbar-collapse").on("click", function(event) {
var target = $(this).attr("target");
if (event.keyCode !== '40'){
if (!$(".li-menu").is(":visible") && target === undefined) {
location.href=this.href;
} else {
window.open(this.href, '_blank');
}
}
});
in this code i am trying to open main menu in new tab , but external link is getting open on down arrow keypress
call preventDefault() function.
$(".dropdown:not(.li-search) a.dropdown-toggle", ".navbar-collapse").on("click", function(event) {
event.preventDefault();
var target = $(this).attr("target");
if(event.keyCode!=='40'){
if (!$(".li-menu").is(":visible") && target===undefined) {
location.href=this.href;
}
else {
window.open(this.href,'_blank');
}
}
});
See the keycode for the reference https://css-tricks.com/snippets/javascript/javascript-keycodes/
in order to configure your app for particular key event
Looking at the classes dropdown-toggle, navbar-collapse, I'm guessing that you are using Bootstrap library.
If that is the case, the behaviour you are seeing is reasonable. Let's break down the issues:
on down arrow keypress , click event is getting fired
Q: You have only bind the handler on click event so why are it is being triggered on keypress?
A: Because this is a feature of bootstrap dropdown. To have better accessibilty, bootstrap triggers click event on the keydown of up, down, esc and space keys.
event.keycode is undefined
Since it is a click event handler and not some keyboard event handler like keydown or keypress, event.keyCode should be undefined
Note: You are using a strict equality in the following condition
if (event.keyCode !== '40')
This will check both the type and value of the operands. Now, event.keyCode always return a Number while '40' is a string, hence the above condtion will yield false even if keyCode is 40. You should correct it to:
if (event.keyCode !== 40)
Now, if you want to stop the redirect on down key, you should check whether the event triggered is an original event or was triggered by some js logic. For this, you may choose jQuery's event.isTrigger or event.originalEvent
Here's a code snippet:
$(".dropdown:not(.li-search) a.dropdown-toggle", ".navbar-collapse").on("click", function(event) {
var target = $(this).attr("target");
// Check if NOT an triggered event
if (!event.isTrigger) {
if (!$(".li-menu").is(":visible") && target === undefined) {
location.href = this.href;
} else {
window.open(this.href, '_blank');
}
}
});
<a> tags will fire the click event when you press enter on them. However you will not have a keyCode on the event because it is not a Key* event. If you want to know the keyCode add a keyDown or keyUp handler as well. You could also handle both by doing something like the following:
$(".dropdown:not(.li-search) a.dropdown-toggle", ".navbar-collapse").on("click keydown", function(event) {
var target = $(this).attr("target");
if(event.type === 'keydown' && event.keyCode!=='40'){
if (!$(".li-menu").is(":visible") && target===undefined) {
location.href=this.href;
}
else {
window.open(this.href,'_blank');
}
}
});
You'll probably also want to add an event.preventDefault(); in there if you wish to prevent default browser behaviour from taking place.

JS Busy loading indicator ignore middle click

My busy loading indicator basically works by detecting clicks. However, I just noted that when I middle click an item, it opens a link in a new tab and then the loading indicator shows up forever. How can I tell JS to ignore the middle mouse button?
window.onload = setupFunc;
function setupFunc() {
document.getElementsByTagName('body')[0].onclick = clickFunc;
hideBusysign();
Wicket.Ajax.registerPreCallHandler(showBusysign);
Wicket.Ajax.registerPostCallHandler(hideBusysign);
Wicket.Ajax.registerFailureHandler(hideBusysign);
}
function hideBusysign() {
document.getElementById('busy').style.display ='none';
}
function showBusysign() {
document.getElementById('busy').style.display ='inline';
}
function clickFunc(eventData) {
var clickedElement = (window.event) ? event.srcElement : eventData.target;
if (clickedElement.tagName.toUpperCase() == 'BUTTON' || clickedElement.tagName.toUpperCase() == 'A' || clickedElement.parentNode.tagName.toUpperCase() == 'A'
|| (clickedElement.tagName.toUpperCase() == 'INPUT' && (clickedElement.type.toUpperCase() == 'BUTTON' || clickedElement.type.toUpperCase() == 'SUBMIT'))) {
showBusysign();
}
}
You can try to, but it won't work very well with all browsers.
This page describes what browsers support disabling the middle mouse button via JS. Firefox is not one of them...
Another option is to scope the click events to only work on AJAX links/buttons.
For instance (rewriting with jQuery only b/c I'm hopeless without it):
// On load
$(function() {
Wicket.Ajax.registerPreCallHandler(showBusysign);
Wicket.Ajax.registerPostCallHandler(hideBusysign);
Wicket.Ajax.registerFailureHandler(hideBusysign);
});
// Assuming you add an "ajax" class to all appropriate markup (in Wicket)
// .live would be appropriate, too
$('body').delegate('a.ajax, input:button.ajax, input:submit.ajax', 'click', function(){
showBusysign();
});

Problem with Google Chrome and Javascript. Guru needed!

i have a strange problem only in Chrome using an iframe but working in all others common browser.
the problem: If i type in the IFRAME and then press the button to send, it work fine, the focus back to the IFRAME and the cursor BLINK.
But if i type and then press ENTER to invoke the event handler function, the focus back but the cursor disappear. And then if you go in another window and then back the cursor appear. This happen only in Chrome. I did the example page to show the problem in action. Click the link below to see.
UPDATE: I added the code also here below
var editorFrame = 'myEditor'
function addFrame() {
var newFrame = new Element('iframe', {
width: '520',
height: '100',
id: editorFrame,
name: editorFrame,
src: 'blank.asp',
class: 'myClass'
});
$('myArea').appendChild(newFrame);
window.iframeLoaded = function() {
// this is call-back from the iframe to be sure that is loaded, so can safety attach the event handler
var iframeDoc, UNDEF = "undefined";
if (typeof newFrame.contentDocument != UNDEF) {
iframeDoc = newFrame.contentDocument;
} else if (typeof newFrame.contentWindow != UNDEF) {
iframeDoc = newFrame.contentWindow.document;
}
if (typeof iframeDoc.addEventListener != UNDEF) {
iframeDoc.addEventListener('keydown', keyHandler, false);
} else if (typeof iframeDoc.attachEvent != UNDEF) {
iframeDoc.attachEvent('onkeydown', keyHandler);
}
};
}
function resetContent()
{
var myIFrame = $(editorFrame);
if (myIFrame) myIFrame.contentWindow.document.body.innerHTML='';
}
function setEditFocus()
{
var iFrame = document.frames ? document.frames[editorFrame] : $(editorFrame);
var ifWin = iFrame .contentWindow || iFrame;
ifWin.focus();
}
function send()
{
resetContent();
setEditFocus();
}
function keyHandler (evt) {
var myKey=(evt.which || evt.charCode || evt.keyCode)
if (myKey==13) {
if (!evt) var evt = window.event;
evt.returnValue = false;
if (Prototype.Browser.IE) evt.keyCode = 0;
evt.cancelBubble = true;
if (evt.stopPropagation) evt.stopPropagation();
if (evt.preventDefault) evt.preventDefault();
send();
}
}
In the HTML page
<body onload="addFrame()">
<div id="myArea"></div>
<input id="myButton" type="button" value="click me to send [case 1]" onclick="send()">
To make more easy to understand the problem i've create a specific page to reproduce the problem with full example and source included.
You can view here by using Google Chrome:
example of the problem
I really need your help because i tried to solve this problem for many days with no luck. And all the suggestions, tips and workaround are well accepted.
Thanks in advance.
I'm not really sure what the cause of the issue is, as there are times where Chrome will give focus to the element correctly, though most of the time it does not. You shouldn't need to request focus at all, since the focus is not lost when you press the key. If you omit the setEditFocus() call, you should notice that it still works correctly in everything but Chrome, which apparently gets offended that you've removed all of the content in the body.
When you set contenteditable, every browser sets the innerHTML of the iframe document's body element to be something different:
Browser | innerHTML
-----------------------------
Internet Explorer | ''
Opera | '<br>\n'
Firefox | '<br>'
Chrome/Safari | '\n'
If you're not expecting to see that extra stuff when you parse the content later, you might want to remove it upfront in addFrame().
I was able to "fix" the problem by doing the following:
First, update the event handler so we can return false in it and prevent Opera from generating HTML for fun when we call getSelection() later...
function addFrame() {
...
window.iframeloaded = function() {
...
if (typeof iframeDoc.addEventListener != UNDEF) {
iframeDoc.addEventListener('keypress', keyHandler, false);
} else if (typeof iframeDoc.attachEvent != UNDEF) {
iframeDoc.attachEvent('onkeypress', keyHandler);
}
}
}
Edit: Removed original function in favour of the new one included below
Finally, return false from the key press handler to fix the Opera issue mentioned above.
function keyHandler (evt) {
var myKey=(evt.which || evt.charCode || evt.keyCode)
if (myKey==13) {
...
return false;
}
}
I had originally done what syockit suggested, but I found it was doing weird things with the caret size in Chrome, which this method seems to avoid (although Firefox is still a bit off...). If you don't care about that, setting the innerHTML to be non-blank is likely an easier solution.
Also note that you should be using className instead of class in the object you pass to new Element(), since IE seems to consider it a reserved word and says that it's a syntax error.
Edit: After playing around with it, the following function seems to work reliably in IE8/Firefox/Chrome/Safari/Opera for your more advanced test case. Unfortunately, I did have to include Prototype's browser detection to account for Opera, since while everything looks the same as far as the JavaScript is concerned, the actual behaviour requires different code that conflicts with the other browsers, and I wasn't able to find a better way to differentiate between them.
Here's the new function, which focuses on the editable content of the iframe, and makes sure that if there is already content in there, that the caret is moved to the end of that content:
function focusEditableFrame(frame) {
if (!frame)
return;
if (frame.contentWindow)
frame = frame.contentWindow;
if (!Prototype.Browser.Opera) {
frame.focus();
if (frame.getSelection) {
if (frame.document.body.innerHTML == '')
frame.getSelection().extend(frame.document.body, 0);
else
frame.getSelection().collapseToEnd();
} else if (frame.document.body.createTextRange) {
var range = frame.document.body.createTextRange();
range.moveEnd('character', frame.document.body.innerHTML.length);
range.collapse(false);
range.select();
}
} else {
frame.document.body.blur();
frame.document.body.focus();
}
}
Updated setEditFocus() (Not really necessary now, but since you already have it):
function setEditFocus()
{
focusEditableFrame($(editorFrame));
}
You know how I solved this one? In resetContent(), replace '' with ' ':
if (myIFrame) myIFrame.contentWindow.document.body.innerHTML=' ';
If it works, good. Don't ask why though, it might be one of those Webkit glitches with Range object, file a bug if you will.
Just quickly, can you try adding semicolons to the end of the lines inside your send() function? And see if that works.
function send() {
resetContent();
setEditFocus();
}

Categories

Resources