I'm trying to let the user check/uncheck the checkbox on hitting either spacebar or enter in keyboard, I want to achieve this functionality using JavaScript function.
This is how my code looks partially:
<span class="sample" onClick="UdateComponent" tabindex="0" role="checkbox" aria-checked="" aria-decribedby="">
Inside this span I want to include onkeypress or onkeydown for achieving the functionality that is mentioned above and the constraint is I only have to use JavaScript for this.
I would strongly recommend not doing this. Use an input type="checkbox", in combination with a label. It's what they're for. You can style them extremely thoroughly. You can even hide the input type="checkbox" if you want to and only show the label.
But you've said you can't use input. So yes, you can do this with a keypress handler. You'll presumably also want to handle clicks. See comments:
// Handle toggline the "checkbox"
// Expects the element as `this` and the event as `e`
function toggleFakeCheckbox(e) {
// States as far as I can tell from
// https://www.w3.org/TR/wai-aria/states_and_properties#aria-checked
// and
// https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_checkbox_role
this.setAttribute(
"aria-checked",
this.getAttribute("aria-checked") === "true" ? "false" : "true"
);
// Avoid the default (spacebar in particular is problematic)
e.preventDefault();
e.stopPropagation();
}
// Get the element
var sample = document.querySelector(".sample");
// Set up its handlers for click and keypress
sample.addEventListener("click", toggleFakeCheckbox);
sample.addEventListener("keypress", function(e) {
// Flag for whether to toggle
var toggle = false;
var keyCode;
if ("key" in e) {
// Modern user agent
toggle = e.key === " " || e.key === "Enter";
} else {
// Fallback for older user agents
keyCode = e.which || e.keyCode;
toggle = keyCode === 32 || keyCode === 13;
}
if (toggle) {
toggleFakeCheckbox.call(this, e);
}
});
// Give it focus for easy testing
sample.focus();
/* Let's show the state of the checkbox */
[role=checkbox][aria-checked=true]:before {
content: '[x] '
}
[role=checkbox][aria-checked=false]:before {
content: '[ ] '
}
<span class="sample" tabindex="0" role="checkbox" aria-checked="true" aria-decribedby="">Checkbox</span>
But again: Reinventing the wheel isn't a good thing, even if you try to respect all the ARIA rules when doing so...
Update: And sure enough, focussing the span in IE and hitting the space bar moves us to a different part of the page, even though we both prevented the default action (which was enough to stop that on Firefox) and stopped propagation. Why does it do that? Because we tried to reinvent the wheel. Which is a Bad Thing™.
Related
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.
Pressing the tab key which triggers a focus change is also received by the input receiving the focus as a keyup.
a: <input type='text'/><br/>
b: <input type='text' onkeyup='alert("wtf?")'/><br/>
http://jsfiddle.net/59SnP/
As my control also uses tab (not in the example), I would want the focus related keyup event being consumed (but I want to receive other non-focus-change related tab events). I tried to research the rationale behind the current behavior but found nothing. The question: Where is this current behavior specified (event not consumed by focus change), and what would be a cross-browser workaround to force consuming it. Thx.
You can try this. I changed your keyup event in your input :
<input type='text' onkeyup="if(!tabPressed){ alert('This is it !'); }"/>
And I added a little event handler which will raise a flag when the tab button is pressed :
var tabPressed = false;
document.addEventListener('keydown', function (e) {
if(e.keyCode == 9) {
tabPressed = true;
} else {
tabPressed = false;
}
}, false);
Based on Nathan's insight, here is a fully working example:
// First part of Nathan's HACK (set a sentinel when a focus changing tab has happened)
var tabPressed = false;
// remove this listener to break the functionality
$(document).on("keydown", function (e) {
if(e.keyCode == 9) {
tabPressed = true;
} else {
tabPressed = false;
}
});
// The listener on the client input that would kill the keyup tab event upon focus change
$("#magic").on("keyup", function(e) {
if (tabPressed && e.keyCode==9) {
tabPressed = false; // reset the sentinel
e.stopImmediatePropagation()
e.preventDefault()
}
})
And here is the second part, which is a simple skeleton of something meaningful. We disable TAB inside the input, and log it as we do with other keyups:
$("#magic").on("keydown", function(e) {
if (e.keyCode==9) {
e.preventDefault()
e.stopPropagation()
}
})
$("#magic").on("keyup", function(e) {
$(this).val($(this).val() + " " + e.keyCode)
e.stopPropagation()
e.preventDefault()
})
The HTML backing the story is as simple as:
a: <input type='text'/><br/>
b: <input type='text'/><br/>
c: <input type='text' id='magic'/><br/>
If you want to play with it, here it is on jsfiddle
NOTE: This still is not the perfect solution, the sentinel is just reset inside the control, so if a tabpress moving the focus does not activate our input, the sentinel stucks, and the first event will be swallowed.. So here is an example of wrong behaviour:
Click on input A
Press TAB (focus moves to input B, tabPressed becomes true)
Click on input C
Press TAB (it is eaten up as sentinel is true)
Press TAB (now it goes through)
Still it is slightly better to have to press TAB twice as to have something happening automatically, wo user control...
I am trying to disable spaces in the Username text field, however my code disables using the back arrow too. Any way to allow the back arrow also?
$(function() {
var txt = $("input#UserName");
var func = function() {
txt.val(txt.val().replace(/\s/g, ''));
}
txt.keyup(func).blur(func);
});
fiddle: http://jsfiddle.net/EJFbt/
You may add keydown handler and prevent default action for space key (i.e. 32):
$("input#UserName").on({
keydown: function(e) {
if (e.which === 32)
return false;
},
change: function() {
this.value = this.value.replace(/\s/g, "");
}
});
DEMO: http://jsfiddle.net/EJFbt/1/
This seems to work for me:
<input type="text" onkeypress="return event.charCode != 32">
It doesn't "disable" the back arrow — your code keeps replacing all the text outright, whenever you press a key, and every time that happens the caret position is lost.
Simply don't do that.
Use a better mechanism for banning spaces, such as returning false from an onkeydown handler when the key pressed is space:
$(function() {
$("input#Username").on("keydown", function (e) {
return e.which !== 32;
});
});
This way, your textbox is prohibited from receiving the spaces in the first place and you don't need to replace any text. The caret will thus remain unaffected.
Update
#VisioN's adapted code will also add this space-banning support to copy-paste operations, whilst still avoiding text-replacement-on-keyup handlers that affect your textbox value whilst your caret is still active within it.
So here's the final code:
$(function() {
// "Ban" spaces in username field
$("input#Username").on({
// When a new character was typed in
keydown: function(e) {
// 32 - ASCII for Space;
// `return false` cancels the keypress
if (e.which === 32)
return false;
},
// When spaces managed to "sneak in" via copy/paste
change: function() {
// Regex-remove all spaces in the final value
this.value = this.value.replace(/\s/g, "");
}
// Notice: value replacement only in events
// that already involve the textbox losing
// losing focus, else caret position gets
// mangled.
});
});
Try checking for the proper key code in your function:
$(function(){
var txt = $("input#UserName");
var func = function(e) {
if(e.keyCode === 32){
txt.val(txt.val().replace(/\s/g, ''));
}
}
txt.keyup(func).blur(func);
});
That way only the keyCode of 32 (a space) calls the replace function. This will allow the other keypress events to get through. Depending on comparability in IE, you may need to check whether e exists, use e.which, or perhaps use the global window.event object. There are many question on here that cover such topics though.
If you're unsure about a certain keyCode try this helpful site.
One liner:
onkeypress="return event.which != 32"
I'm designing a web based accounting software. I would like to open the "new accounting document" whenever the user press N key for example. And open "settings" whenever he/she is pressing S key.
I saw some scripts based on JavaScript and jQuery. But they did not work exactly. Can anyone help me please ?
I have tried this script:
var code = (e.keyCode ? e.keyCode : e.which);
if(code == 13) { //Enter keycode
//Do something
}
$(document).bind('keyup', function(e){
if(e.which==78) {
// "n"
}
if(e.which==83) {
// "s"
}
});
To prevent if an input is focused:
$("body").on("focus",":input", function(){ $(document).unbind('keyup'); });
$("body").on("blur",":input", function(){ $(document).bind('keyup', function(e){ etc.... });
You might want to put the bind function into its own function so you don't duplicate code. e.g:
function bindKeyup(){
$(document).bind('keyup', function(e){
if(e.which==78) {
// "n"
}
if(e.which==83) {
// "s"
}
});
}
$("body").on("focus",":input", function(){ $(document).unbind('keyup'); });
$("body").on("blur",":input", function(){ bindKeyup(); });
You can detech keypresses in jQuery using either .keypress() or .keyup() methods, here is a quick example :
$(document).keyup(function(event) { // the event variable contains the key pressed
if(event.which == 78) { // N keycode
//Do something
}
});
Here is a list of keycodes : http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes
Update 1
.keyup and .keydown have different affects - as per comments from #ThomasClayson -: keyup is the best one to go for as keypress will repeat if the key is held down. it registers an event for each character inserted. It also doesn't register modifier keys such as shift (although not necessary here, it might be something to keep in mind)
Update 2
This is from the jQuery keyup doc site :
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. This
code corresponds to a key on the keyboard, including codes for special
keys such as arrows.
Affectively meaning that which.event is all you need to determine which key has been used. Thanks #nnnnnn
You need to read up on the .keyCode() attribute of the event object. You can interrogate that to discover which key was pressed and act accordingly. I'd also suggest you add modifier keys to your shortcuts, such as Shift or Alt, so that when someone is innocently typing in an input, the panel doesn't pop up. In the example below I've used Shift
$(document).keyup(function(e) {
if (e.shiftKey) {
switch(e.keyCode ? e.keyCode : e.which) {
case 78: // N pressed
myNPressedHandler();
break;
case 83: // S pressed
mySPressedHandler();
break;
}
}
}
$(document).bind('keypress', function(e) {
var keycode= (e.keyCode ? e.keyCode : e.which);
if(keyCode==78) {
// "n"
}else if(keyCode==83) {
// "s"
}
});
When using contentEditable in Firefox, is there a way to prevent the user from inserting paragraph or line breaks by pressing enter or shift+enter?
You can attach an event handler to the keydown or keypress event for the contentEditable field and cancel the event if the keycode identifies itself as enter (or shift+enter).
This will disable enter/shift+enter completely when focus is in the contentEditable field.
If using jQuery, something like:
$("#idContentEditable").keypress(function(e){ return e.which != 13; });
...which will return false and cancel the keypress event on enter.
This is possible with Vanilla JS, with the same effort:
document.getElementById('idContentEditable').addEventListener('keypress', (evt) => {
if (evt.which === 13) {
evt.preventDefault();
}
});
You should not use jQuery for the most simple things. Also, you may want to use "key" instead of "which": https://developer.mozilla.org/en-US/docs/Web/Events/keypress
Update, since keypress is deprecated:
document.getElementById('idContentEditable').addEventListener('keydown', (evt) => {
if (evt.keyCode === 13) {
evt.preventDefault();
}
});
Add the following CSS rule to hide line breaks. This is only a style setting, you should add some event handlers to prevent inserting line breaks:
.your_editable br {
display: none
}
Other than adding line breaks, the browser adds additional tags and styles (when you paste text, the browser also appends your pasted text style).
The code below covers it all.
When you press enter, no line breaks will be added.
When you paste text, all elements added by the browser are stripped from the text.
$('[contenteditable]').on('paste', function(e) {
//strips elements added to the editable tag when pasting
var $self = $(this);
setTimeout(function() {$self.html($self.text());}, 0);
}).on('keypress', function(e) {
//ignores enter key
return e.which != 13;
});
Click here for a live example
another option is to allow breaks to be entered but remove them on blur. this has the advantage of dealing with pasted content. your users will either love it or hate it (depending on your users).
function handle_blur(evt){
var elt=evt.target; elt.innerText=elt.innerText.replace(/\n/g,' ');
}
then, in html:
<span onblur="handle_blur(event)" contenteditable>editable text</span>
If you are using JQuery framework, you can set it with the on method which will let you have the desired behavior on all elements even if this one is added lately.
$(document).on('keypress', '.YourClass', function(e){
return e.which != 13;
});
Add:
display: flex;
On the contenteditable html element
$("#idContentEditable").keypress(function(e){ return e.which != 13; });
Solution proposed by Kamens doesn't work in Opera, you should attach event to document instead.
/**
* Pass false to enable
*/
var disableEnterKey = function(){
var disabled = false;
// Keypress event doesn't get fired when assigned to element in Opera
$(document).keypress(function(e){
if (disabled) return e.which != 13;
});
return function(flag){
disabled = (flag !== undefined) ? flag : true;
}
}();
If you want to target all the contentEditable fields use
$('[contenteditable]').keypress(function(e){ return e.which != 13; });
I came here searching for the same answer, and was surprised to find it's a rather simple solution, using the tried and true Event.preventDefault()
const input = document.getElementById('input');
input.addEventListener('keypress', (e) => {
if (e.which === 13) e.preventDefault();
});
<div contenteditable="true" id="input">
You can edit me, just click on me and start typing.
However, you can't add any line breaks by pressing enter.
</div>
Use CSS:
word-break: break-all;
For me, its worked!