My goal: Press and HOLD space key while an effect occurs (to simulate a fingerprint scan). If user releases key before effect finishes, I want to display a confirm message. The keydown part works fine and proceeds to function "process", but no error message is displayed on keyup if it is released before the effect finishes. This is what I have...
var active = false;
$(document).one("keydown", function(e) {
if ((e.keyCode == 32) && (active == false)) {
active = true;
$(".panel_1").slideDown(5000, function() {
active = false;
$(".panel_1").slideUp(2000, function() {process(); })
});
}
});
$(document).one("keyup",function(e) {
if ((e.keyCode == 32) && (active == true)) {
var r=confirm("Oops! You must HOLD down the space key until scan is complete. Press OK to try again, or Cancel to return to homepage.");
if (r==true) {
reset();
}
else {
window.location.replace("home.html");
}
}
});
Verify that you are releasing the key during the first slideDown animation. According to your code, once it starts to slide up your active gets set to false and then makes it so the keyup event will not trigger.
Also as a side note I'd recommend using triple = in JavaScript.
Your code seems to work here: http://jsfiddle.net/D52eq/ but note that the confirmation message occurs only if the space bar is released during the .slideDown() phase of the effect - you're setting active = false; before the .slideUp() call.
If you want the confirmation if the space bar is released before completion of the entire animation and process() call then try this:
$(document).one("keydown", function(e) {
if ((e.keyCode == 32) && (!active)) {
active = true;
$(".panel_1").slideDown(5000).slideUp(2000, function() {
process();
active = false;
})
}
});
Note that then you can just chain the .slideDown() and .slideUp(), you don't need to supply a callback function to .slideDown(). Also I've replaced active == false with !active.
Demo: http://jsfiddle.net/D52eq/1/
Related
This is a complete revision of my initial question, all unnecessary resources and references were deleted
I am tying the same event listener to 2 different elements: a button and Enter key, and it looks like the following:
var funcelement = function(){
//function code
};
$('#buttonID').click(funcelement);
$('#inputID').keyup(function () {
if (event.which == 13) {
$('#buttonID').trigger('click');
}
})
What I am trying to do is to prevent propagation of the enter key press if focus is on the submit button(#buttonID) by using preventDefault().
So I tried various combinations to make it work. The following is the latest result on my attempts
$('#inputID').keyup(function () {
var hasfocus = $('#buttonID').is(':focus') || false;
if (event.which == 13) {
if (!hasfocus) {
event.preventDefault();
$('#buttonID').trigger('click');
//hasfocus = true;
}
else {
//event.preventDefault();
//$('#buttonID').trigger('click');
}
}
})
After I enter a text into an input box and press Enter key, a confirmation window with yes/cancel buttons pops up with focus on yes button. Once I press Enter again, another window confirming that changes were made pops up with Ok button focused on it. Once I press Enter again, everything I need is being made.
However, there is one problem: after the last step is done, I am going back to the if (!hasfocus) line.
How do I prevent that from happening? Once the stuff I need is done - I don't want to go into that line again.
You can pass a parameter to into the function and stop the propagation there like so:
var funcelement = function(event, wasTriggeredByEnterKey){
if (wasTriggeredByEnterKey && $('#buttonID').is(':focus')) {
event.stopPropagation;
}
//function code
};
$('#buttonID').click(funcelement);
$('#inputID').keyup(function () {
if (event.which == 13) {
$('#buttonID').trigger('click', [true]);
}
}
)
UPDATE
In order to answer your revised issue, you should use the "keydown" event rather than "keyup" when working with alerts. This is because alerts close with the "keydown" event but then you are still triggering the "keyup" event when you release the enter key. Simply change the one word like this:
$('#inputID').keydown(function () {
var hasfocus = $('#buttonID').is(':focus') || false;
if (event.which == 13) {
if (!hasfocus) {
event.preventDefault();
$('#buttonID').trigger('click');
//hasfocus = true;
}
else {
//event.preventDefault();
//$('#buttonID').trigger('click');
}
}
})
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 have a text input, that presently goes transparent when a user presses shift (keydown) and binds a listener for the shift key going up
ie.
$('#foo').keydown(function(){
if(event.which==16){
//make #foo transparent
$(this).keyup(function(){
if(event.which==16){
//return #foo to its former glory
$(this).unbind('keyup');
}
});
};
})
This works fine when no characters are pressed in the interim between depressing and releasing the shift key. The problem is that when shift is down and another character is pressed, the shift key seems to have been completely forgotten about. When the shift key is released, no keyup fires.
I tried triggering a 'fake' keydown with the .which property set to 16, to nudge it in the right direction after other characters are pressed, but to no avail.
Any suggestions would be greatly appreciated!
While pressing shift, it will continuously trigger keydown events until you release it, so your example will bind as many keyup handlers as there are keydown events triggered. This will most likely cause all kind of weird problems.
Instead, bind both keydown and keyup to the same handler and do your magic in there:
$("#foo").on("keydown keyup", function (e) {
if (e.which === 16) {
if (e.type === "keydown") {
// make #foo transparent
} else {
// return #foo to its former glory
}
}
});
See test case on jsFiddle.
However, if you lose focus of the input while pressing shift and then release, it will not work as expected. One way to solve it is to bind to window instead:
var $foo = $("#foo");
var shiftPressed = false;
$(window).on("keydown keyup", function (e) {
if (e.which === 16) {
shiftPressed = e.type === "keydown";
if (shiftPressed && e.target === $foo[0]) {
$foo.addClass("transparent");
} else {
$foo.removeClass("transparent");
}
}
});
$foo.on("focus blur", function (e) {
if (e.type === "focus" && shiftPressed) {
$foo.addClass("transparent");
} else {
$foo.removeClass("transparent");
}
});
See test case on jsFiddle.
I'm building something mainly for use on tablets, where the user can tap an item on the screen and a class is applied to it. This is what I have so far:
The problems:
I want to use touch events to remove the class and add the class on touch end (to make it faster).
I don't want it to do anything if the user swipes (touchmoves).
I've tried a number of things, none of which have worked. The simplest I've tried (unsuccessfully) is this:
var dragging = false;
$(".items").on("touchmove", function(){
dragging = true;
});
$('.items').on("click touchend", function(event){
if (dragging = true){
}
else{
$('.items').removeClass('selected');
$(this).addClass('selected');
}
});
I would argue this is a more safe way of doing it
Setting variable to false
var dragging = false;
Setting var to true ontouchmove (allows you to reuse this code everywhere in your app)
$("body").on("touchmove", function(){
dragging = true;
});
Your button
$("#button").on("touchend", function(){
if (dragging)
return;
// your button action code
});
Resetting variable (important)
$("body").on("touchstart", function(){
dragging = false;
});
You want to use either of the following:
if(dragging == true)
Or, simply:
if(dragging)
You should only use a single = sign when you are setting a value, whereas two == signs should be used when checking a value. Therefore, your code should look like:
$('.items').on("click touchend", function(event){
if(!dragging)
{
$('.items').removeClass('selected');
$(this).addClass('selected');
}
});
Notice how you do not need to check if dragging == true because you are not running any code in this case. Instead you can simply check if dragging == false or, !dragging
You can just check if event is cancelable. It's false after touchmove
$('.items').on("click touchend", function(event){
if (event.cancelable){
$('.items').removeClass('selected');
$(this).addClass('selected');
}
});
where you have dragging check put
if (dragging == true){
dragging = false;
}
else{
$('.items').removeClass('selected');
$(this).addClass('selected');
}
it will reset it on release
also watch out for double calls on events as they sometimes trigger twice on some platforms best to check platform with first the following will help with checks
var clickEventType=((document.ontouchstart!==null)?'click':'touchend');
or
var clickEventType = 'touchend';
if(document.ontouchstart!==null)
{
clickEventType = '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();
});