Meaning of evt = (evt) ? evt : window.event - javascript

What does this JavaScript snippet mean? The (evt) part is so confusing; evt is not a boolean. How it works?
function checkIt(evt) {
evt = (evt) ? evt : window.event
var charCode = (evt.which) ? evt.which : evt.keyCode
}

evt = (evt) ? evt : window.event is just the inline if syntax. It's equivalent to this code:
if (evt) {
evt = evt;
} else {
evt = window.event;
}
If evt is truthy, evt will be left alone. If evt isn't truthy, it will be replaced with window.event.

It's for event listeners.
IE6-IE8 used a totally different event method than the W3C standard.
When an event fires, a W3C-standard browser will pass an event object in the callback:
function keyPressed (e) { /* do stuff with e */ }
In your case, it's keydown (or something else using keyCode).
IE didn't support this, instead it had window.event which was updated every time an event happened.
So your function is checking to see if an object was passed into it:
evt = (evt) ? evt : window.event;
// does `evt` exist, and is it anything but '', 0, false, null, undefined, NaN
// yes: evt = itself (W3C)
// no: evt = window.event (IE6-8)
Then the code asks if evt.which exists, to try to figure out where to get the keyCode from.
evt.keyCode is what you should be using for modern browsers, in the case of keydown and keyup.

Assignment expressions like that are evaluated from right to left, so this means:
if evt has a truthy value, assign this value back to evt
if not, assign the value of window.event regardless of its content to evt

It means: if the evt parameter has a value then keep the value, if it doesn't have a value then use window.event instead.
The ? and ':' symbols are part of the ternary if operator:
var w = x ? y : z;
so above you assign either y or z to w depending on whether x is considered to be a true or false value.
If the checkIt function was called without passing in an evt argument i.e. checkIt() then inside the function the evt variable will have the value of undefined which is treated as false within an if condition.

Related

Javascript answer undefined

Using the following code works in all browsers, but in Firefox it gives the error "TypeError: answer is undefined quiz.js:13"
function getAnswer() {
var answer = window.event,
btn = answer.target || answer.srcElement;
return btn.id;
}
In my full code line 13 is
btn = answer.target || answer.srcElement;
I'm using this piece of code to check which button is pressed.
Is there any way to fix this?
window.event only works in IE. For other browsers, the event is passed as the argument to the handler.
Since this is not your handler of the event, you will have to do this in the actual handler and pass that information to your getAnswer function instead of using the global window.event
function getAnswer(e) {
var btn = e.target || e.srcElement;
return btn.id;
}
document.addEventListener('click', function(e) {
e = e || window.event;
console.log(getAnswer(e));
});
Or if using the HTML attribute, you have to pass it from the HTML.
<p onclick="alert(getAnswer(event))"></p>
Yes...
Firefox does not have a window.event but rather uses an event object passed in. (To the best of my knowledge, this code should not work under Chrome either.)
function getAnswer(event) {
var answer = event || window.event,
// Added the `var` here.
var btn = answer.target || answer.srcElement;
return btn.id;
}

Why aren't my parameters getting passed through to a dispatched event?

I've set up an event listener like this...
window.addEventListener('message', parseMessage, false);
var parseMessage = function(rawMessage) {
console.log(rawMessage.cmd);
};
And then I'm triggering the event like this:
var event = new Event('message', {'cmd':"blerg!"});
window.dispatchEvent(event);
The problem is the console.log in parse message is logging out undefined when I am expecting to to log out "blerg!"
What I am I doing wrong here with the events, how to I pass the 'cmd' message through to the event?
Use CustomEvent instead of Event for creating custom events.
Specify your data in a 'details' object (see code).
I changed the event name because message is also used for the postMessage API. It didn't cause problems when running in Chrome, but I wouldn't use it.
var parseMessage = function(rawMessage) {
console.log(rawMessage);
console.log(rawMessage.detail.cmd);
};
// changed event name
window.addEventListener('myMessage', parseMessage, false);
// data should be in a 'details' object
var evt = new CustomEvent('myMessage', {
detail: {
'cmd' : "blerg!"
}
});
window.dispatchEvent(evt);
Here is an adjustment for IE >= 9 compatiblity (using document.createEvent() and CustomEvent::initCustomEvent()):
var evt = document.createEvent("CustomEvent");
evt.initCustomEvent('myMessage', false, false, {
'cmd': "blerg!"
});
For IE9/10 polyfill you can use this code provided by Mozilla:
https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
(function () {
if (
typeof window.CustomEvent === "function" ||
// In Safari, typeof CustomEvent == 'object' but it otherwise works fine
this.CustomEvent.toString().indexOf('CustomEventConstructor')>-1
) { return; }
function CustomEvent ( event, params ) {
params = params || { bubbles: false, cancelable: false, detail: undefined };
var evt = document.createEvent( 'CustomEvent' );
evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
return evt;
}
CustomEvent.prototype = window.Event.prototype;
window.CustomEvent = CustomEvent;
})();
Also described here but with wrong URL:
https://stackoverflow.com/a/22946340/1736012

Get "event" object within the immediately executed function?

I use event delegation in such way:
elWraper.onclick = (function(){
//how to get here "event" object
e = e || window.event;
var t = e.target || e.srcElement;
//event handler
return function(){
//manipulations with "t" variable
}
})();
how to get "event" object within the immediately executed function?
elWraper.onclick = (function(){
// misc stuff here
//event handler
return function(e){
e = e || window.event;
var t = e.target || e.srcElement;
//manipulations with "t" variable
}
})();
In standards compliant browsers the event object is the first parameter passed into the callback function. In IE it is a global variable (which is what e = e || window.event is trying to determine). Therefore, the function that you return by the immediately executed function should accept the event object declared as its first (and usually only) argument.
Clarification
Since people are wondering (and probably they are wondering why the OP accepted this answer) there are uses for this that is not clear from the OP's question. One is to create a closure to a variable to track something:
/* Count number of clicks,
* WITHOUT USING GLOBAL VARS!
*/
el.onclick = (function(){
var counter = 0;
return function(e){
e = e || window.event;
var t = e.target || e.srcElement;
counter ++;
alert('detected '+counter+' clicks!');
// do stuff with t or e ...
}
})();
also, this is the classic way of assigning event handlers in loops:
/* Use double closure to break closure in loop!
*/
for (var i=0; i<stuff.length; i++) {
var el = stuff[i];
el.onclick = (function(x){
return function(e){
e = e || window.event;
var t = e.target || e.srcElement;
alert(x);
// do stuff with t or e ...
}
})(i);
}
Or maybe the OP just thought that he could 'cache' the event object and mistakenly believed he could use this to do it. In which case, reading my explanation (instead of just the code) should enlighten the reader as to why that would be a bad idea.
elWraper.onclick = function (e) {
//how to get here "event" object
e = e || window.event;
var t = e.target || e.srcElement;
//manipulations with "t" variable
};
I think slebetman's answer is correct according to your question. However, I don't see the point of what you are doing. If you are trying to abstract the browser's event differences, you can use something like this.
function createHandler( context, handler ) {
return function (e) {
e = e || window.event;
var t = e.target || e.srcElement;
handler.call (context || window, e, t);
}
}
Then you can use it like
div.onclick = createHandler(div, function(e, t){
alert ("actual clicked target is " + t.id);
alert ("handler was set on node " + this.id);
});
Note that you can pass anything as the context (the 'this' keyword in the handler)
It's good to know this stuff, but jquery or many other libs already do this for you and it's a lot more tested than your code will ever be and it takes care of many more browser differences than this small function. But if this all you need, this does keep code bloat down.

How can I add a keyboard shortcut to an existing JavaScript Function?

Here is my code:
function pauseSound() {
var pauseSound = document.getElementById("backgroundMusic");
pauseSound.pause();
}
I would like to add a keyboard shortcut to this code, how can I do this so that the function can also be executed when a button is clicked too?
Tried to add an else if statement but it doesn't work, any ideas?
function doc_keyUp(e) {
if (e.ctrlKey && e.keyCode == 88) {
pauseSound();
}
else if (e.ctrlKey && e.keyCode == 84) {
playSound();
}
}
An event handler for the document's keyup event seems like an appropriate solution.
Note: KeyboardEvent.keyCode was deprecated in favor of KeyboardEvent.key.
// define a handler
function doc_keyUp(e) {
// this would test for whichever key is 40 (down arrow) and the ctrl key at the same time
if (e.ctrlKey && e.key === 'ArrowDown') {
// call your function to do the thing
pauseSound();
}
}
// register the handler
document.addEventListener('keyup', doc_keyUp, false);
If you want to trigger an event after pressing a key, try:
In this example press ALT+a:
document.onkeyup = function () {
var e = e || window.event; // for IE to cover IEs window event-object
if(e.altKey && e.which == 65) {
alert('Keyboard shortcut working!');
return false;
}
}
Here is a fiddle: https://jsfiddle.net/dmtf6n27/38/
Please also note there is a difference for the keycode numbers, whether you are using onkeypress or onkeyup. W3 Schools' "KeyboardEvent keyCode" Property has more information.
//For single key: Short cut key for 'Z'
document.onkeypress = function (e) {
var evt = window.event || e;
switch (evt.keyCode) {
case 90:
// Call your method Here
break;
}
}
//For combine keys like Alt+P
document.onkeyup = function (e) {
var evt = window.event || e;
if (evt.keyCode == 80 && evt.altKey) {
// Call Your method here
}
}
}
//ensure if short cut keys are case sensitive.
// If its not case sensitive then
//check with the evt.keyCode values for both upper case and lower case. ......
Here's my solution:
HTMLElement.prototype.onshortcut = function(shortcut, handler) {
var currentKeys = []
function reset() {
currentKeys = []
}
function shortcutMatches() {
currentKeys.sort()
shortcut.sort()
return (
JSON.stringify(currentKeys) ==
JSON.stringify(shortcut)
)
}
this.onkeydown = function(ev) {
currentKeys.push(ev.key)
if (shortcutMatches()) {
ev.preventDefault()
reset()
handler(this)
}
}
this.onkeyup = reset
}
document.body.onshortcut(["Control", "Shift", "P"], el => {
alert("Hello!")
})
When you call my function, it will create an array called currentKeys; these are the keys that will are being held down at that moment.
Every time a key is pressed, sensed because of onkeydown, it is added to the currentKeys array.
When the keys are released, sensed because of onkeyup, the array is reset meaning that no keys are being pressed at that moment.
Each time it will check if the shortcut matches. If it does it will call the handler.
This worked for me
document.onkeyup=function(e){
var e = e || window.event;
if(e.which == 37) {
$("#prev").click()
}else if(e.which == 39){
$("#next").click()
}
}
Catch the key code and then call your function. This example catches the ESC key and calls your function:
function getKey(key) {
if ( key == null ) {
keycode = event.keyCode;
// To Mozilla
} else {
keycode = key.keyCode;
}
// Return the key in lower case form
if (keycode ==27){
//alert(keycode);
pauseSound();
return false;
}
//return String.fromCharCode(keycode).toLowerCase();
}
$(document).ready( function (){
$(document).keydown(function (eventObj){
//alert("Keydown: The key is: "+getKey(eventObj));
getKey(eventObj);
});
});
You'll need JQUERY for this example.
These appear to all be using the deprecated keyCode and which properties. Here is a non-deprecated version using jQuery to wire up the event:
$("body").on("keyup", function (e) {
if(e.ctrlKey && e.key == 'x')
pauseSound();
else if(e.ctrlKey && e.key == 't')
playSound();
})
Note: Ctrl+t may already be assigned to opening a new browser tab.
Here's some stuff to use if you want. You can register a bunch of keys and handler with it.
Comments are in the code, but in short it sets up a listener on the document and manages a hash with the key combinations for which you want to listen.
When you register a key (combination) to listen for, you submit the keycode (preferrably as a constant taken from the exported "key" property, to which you can add more constants for yourself), a handler function and possibly an options hash where you say if the Ctrl and/or Alt key are involved in your plans for this key.
When you de-register a key (combination) you just submit the key and the optional hash for Ctrl/Alt-ness.
window.npup = (function keypressListener() {
// Object to hold keyCode/handler mappings
var mappings = {};
// Default options for additional meta keys
var defaultOptions = {ctrl:false, alt:false};
// Flag for if we're running checks or not
var active = false;
// The function that gets called on keyup.
// Tries to find a handler to execute
function driver(event) {
var keyCode = event.keyCode, ctrl = !!event.ctrlKey, alt = !!event.altKey;
var key = buildKey(keyCode, ctrl, alt);
var handler = mappings[key];
if (handler) {handler(event);}
}
// Take the three props and make a string to use as key in the hash
function buildKey(keyCode, ctrl, alt) {return (keyCode+'_'+ctrl+'_'+alt);}
function listen(keyCode, handler, options) {
// Build default options if there are none submitted
options = options || defaultOptions;
if (typeof handler!=='function') {throw new Error('Submit a handler for keyCode #'+keyCode+'(ctrl:'+!!options.ctrl+', alt:'+options.alt+')');}
// Build a key and map handler for the key combination
var key = buildKey(keyCode, !!options.ctrl, !!options.alt);
mappings[key] = handler;
}
function unListen(keyCode, options) {
// Build default options if there are none submitted
options = options || defaultOptions;
// Build a key and map handler for the key combination
var key = buildKey(keyCode, !!options.ctrl, !!options.alt);
// Delete what was found
delete mappings[key];
}
// Rudimentary attempt att cross-browser-ness
var xb = {
addEventListener: function (element, eventName, handler) {
if (element.attachEvent) {element.attachEvent('on'+eventName, handler);}
else {element.addEventListener(eventName, handler, false);}
}
, removeEventListener: function (element, eventName, handler) {
if (element.attachEvent) {element.detachEvent('on'+eventName, handler);}
else {element.removeEventListener(eventName, handler, false);}
}
};
function setActive(activate) {
activate = (typeof activate==='undefined' || !!activate); // true is default
if (activate===active) {return;} // already in the desired state, do nothing
var addOrRemove = activate ? 'addEventListener' : 'removeEventListener';
xb[addOrRemove](document, 'keyup', driver);
active = activate;
}
// Activate on load
setActive();
// export API
return {
// Add/replace handler for a keycode.
// Submit keycode, handler function and an optional hash with booleans for properties 'ctrl' and 'alt'
listen: listen
// Remove handler for a keycode
// Submit keycode and an optional hash with booleans for properties 'ctrl' and 'alt'
, unListen: unListen
// Turn on or off the whole thing.
// Submit a boolean. No arg means true
, setActive: setActive
// Keycode constants, fill in your own here
, key : {
VK_F1 : 112
, VK_F2: 113
, VK_A: 65
, VK_B: 66
, VK_C: 67
}
};
})();
// Small demo of listen and unListen
// Usage:
// listen(key, handler [,options])
// unListen(key, [,options])
npup.listen(npup.key.VK_F1, function (event) {
console.log('F1, adding listener on \'B\'');
npup.listen(npup.key.VK_B, function (event) {
console.log('B');
});
});
npup.listen(npup.key.VK_F2, function (event) {
console.log('F2, removing listener on \'B\'');
npup.unListen(npup.key.VK_B);
});
npup.listen(npup.key.VK_A, function (event) {
console.log('ctrl-A');
}, {ctrl: true});
npup.listen(npup.key.VK_A, function (event) {
console.log('ctrl-alt-A');
}, {ctrl: true, alt: true});
npup.listen(npup.key.VK_C, function (event) {
console.log('ctrl-alt-C => It all ends!');
npup.setActive(false);
}, {ctrl: true, alt: true});
It is not terribly tested, but seemed to work OK.
Look at Javascript Char Codes (Key Codes) to find a lot of keyCodes to use,
Solution:
var activeKeys = [];
//determine operating system
var os = false;
window.addEventListener('load', function() {
var userAgent = navigator.appVersion;
if (userAgent.indexOf("Win") != -1) os = "windows";
if (userAgent.indexOf("Mac") != -1) os = "osx";
if (userAgent.indexOf("X11") != -1) os = "unix";
if (userAgent.indexOf("Linux") != -1) os = "linux";
});
window.addEventListener('keydown', function(e) {
if (activeKeys.indexOf(e.which) == -1) {
activeKeys.push(e.which);
}
if (os == 'osx') {
} else {
//use indexOf function to check for keys being pressed IE
if (activeKeys.indexOf(17) != -1 && activeKeys.indexOf(86) != -1) {
console.log('you are trying to paste with control+v keys');
}
/*
the control and v keys (for paste)
if(activeKeys.indexOf(17) != -1 && activeKeys.indexOf(86) != -1){
command and v keys are being pressed
}
*/
}
});
window.addEventListener('keyup', function(e) {
var result = activeKeys.indexOf(e.which);
if (result != -1) {
activeKeys.splice(result, 1);
}
});
Explanation:
I ran into this same problem and came up with my own solution. e.metaKey didn't seem to work with the keyup event in Chrome and Safari. However, I'm not sure if it was specific to my application since I had other algorithms blocking some key events and I may have mistakenly blocked the meta key.
This algorithm monitors for keys going down and then adds them to a list of keys that are currently being pressed. When released, the key is removed from the list. Check for simultaneous keys in the list by using indexOf to find key codes in the array.
Saving with ctrl+s in React
useEffect(() => {
document.onkeydown = function (e) {
if (e.ctrlKey == true && e.key == 's') {
e.preventDefault() // to override browser's default save page feature
alert('ctrl+s is working for save!') // invoke your API to save
}
}
}, [])
Many of these answers suggest forcibly overriding document.onkeypress. This is not a good practice because it only allows for a single event handler to be assigned. If any other handlers were previously set up by another script they will be replaced by your function. If you assign another handler later, it will replace the one you assigned here.
A much better approach is to use addEventListener to attach your keyboard shortcut. This allows you to attach as many handlers as necessary and will not interfere with any external libraries that may have attached their own.
Additionally, the UIEvent.which property was never standardized and should not be used. The same goes for KeyboardEvent.keyCode. The current standards compliant property you should use to check which key was pressed is KeyboardEvent.key. Find the key you want in the full list of available values.
For best performance, return early if your desired modifier key is not pressed. As well, rather than having multiple keypress event listeners, use a single one with a swtich/case statement to react appropriately to each key that you want to handle.
Also, do not forget to cancel the default behavior of the key with Event.preventDefault if necessary. Though, there are some shortcuts that you cannot override like ctrl+w.
document.addEventListener('keypress', event => {
if (!event.ctrlKey) { return; }
event.preventDefault();
switch (event.key) {
case 'x' : doSomething(); break
case 'z' : doSomethingElse(); break;
default : console.log('unhandled key was pressed');
}
});

Javascript cross browser scripting

I have a tiny function I use to only allow numeric input. It works great in IE, but I cannot get it to work in FireFox or Chrome. I have this js file loaded in my script tag of my HTML page.
var numberOnly = function(evt) {
var theEvent = evt || window.event;
var key = theEvent.keyCode || theEvent.which;
key = String.fromCharCode( key );
var regex = /[0-9]|\./;
if( !regex.test(key) ) {
theEvent.returnValue = false;
}
};
var wireElemToEvent = function(elemId, event, func){
var elem = document.getElementById(elemId);
if (typeof window.event !== 'undefined') {
elem.attachEvent("on" + event, func);
} else {
elem.addEventListener(event, func, true);
}
};
var wireEvents = function(){
wireElemToEvent("tbxQuantity", "keypress", numberOnly);
wireElemToEvent("tbxPhone", "keypress", numberOnly);
wireElemToEvent("tbxZip", "keypress", numberOnly);
};
window.onload = wireEvents;
Chrome tells me
file:///C:/Documents%20and%20Settings/xxx/Desktop/numbersonly/res/js/numbersonly.js:17Uncaught TypeError: Object #<an HTMLInputElement> has no method 'attachEvent'
Any idea what I am doing wrong?
In wireElemToEvent You may want to check that elem is not null after you initialize it. Also, it would be better to check the existence of elem.attachEvent and elem.addEventListener rather than whether window.event is defined.
Here is the function I use to attach events cross browser:
function eventListen( t, fn, o ) {
o = o || window;
var e = t+fn;
if ( o.attachEvent ) {
o['e'+e] = fn;
o[e] = function(){
o['e'+e]( window.event );
};
o.attachEvent( 'on'+t, o[e] );
}else{
o.addEventListener( t, fn, false );
}
}
And to use it:
eventListen('message', function(e){
var msg = JSON.parse(e.data);
...
});
I've had the same problem and, because I am a novice, was looking around for a day for a solution.
Apparently (typeof window.event !== 'undefined') doesn't stop Safari/Chrome from getting in that if statement. So it actually initializes the attachEvent and doesn't know what to do with it.
Solution:
var wireElemToEvent = function(elemId, event, func){
var elem = document.getElementById(elemId);
if (elem.attachEvent) {
elem.attachEvent("on" + event, func);
}
else { // if (elem.addEventListener) interchangeably
elem.addEventListener(event, func, true);
}
};
One good way to make cross-browser scripting easier is to use jQuery. Plus, there's no reason to reinvent the wheel. Why not try this jQuery plugin: jQuery ยป numeric

Categories