I am asking after reading and following these answers.
jQuery prevent multiple clicks until animation is done
how to prevent click queue build up, using toggle in jquery? tried using bind/unbind('click')
Despite having e.stopPropagation(); and if ($element.is(':animated')){return false;} in place fast clicks bubble.
Here is my fiddle. Slow clicks work fine, fast clicks make it fail. What am I doing wrong please? How can I discard all fast clicks while the menu items are animated?
Your code was solid, however, you were adding the class BEFORE checking for animation.
I simply moved your animation check up, and prevented the click from even changing the class.
// jQuery 1.11.0 on DOM ready
var $hamburgerMenuButton = $('#burgerButton');
var $navTitle = $('.navigation-item');
var $score = $('.score');
$hamburgerMenuButton.click(function(e) {
e.stopPropagation();
if ( !$hamburgerMenuButton.hasClass('open')) {
console.log('hamburgerMenuButton does NOT have class open');
if ( $navTitle.is(':animated') ) {
$score.append('<br>animating ');
return false;
}
$hamburgerMenuButton.addClass('open');
console.log('class open ADDED to hamburgerMenuButton');
$score.append('<br>class open ADDED ');
var delay = 0;
$navTitle.each(function(){
$(this).delay(delay).animate({
'margin-left':'0px'
},500,'easeOutQuint');
delay += 33;
}); // animation end
$score.append('<br>clicked ');
} // if end
else {
console.log('hamburgerMenuButton does HAVE class open');
if ( $navTitle.is(':animated') ) {
$score.append('<br>animating ');
return false;
}
$hamburgerMenuButton.removeClass('open');
console.log('class open REMOVED from hamburgerMenuButton');
$score.append('<br>class open REMOVED ');
var delay = 0;
$navTitle.each(function(){
$(this).delay(delay).animate({
'margin-left':'10em'
},500,'easeOutQuint');
delay += 33;
}); // animation end
$score.append('<br>clicked again');
} // else end
}); // $hamburgerMenuButton click end
https://jsfiddle.net/gregborbonus/b2tw65hf/3/
Related
I know there are many similar posts, but still I haven't get to the code I need.
Basically, I want to make a presentation the first time the user scrolls down. For that, I want to prevent the default action of scroll and (if it's scrolling down) make an animation to the next div.
window.scrolledToRed = false
window.scrolledToGreen = false
window.scrollTo = (to, guard ) =>
$('html, body').animate({
scrollTop: $(to).offset().top
}, 1000, =>
window[guard] = true
)
window.addEventListener 'wheel', (e) ->
if (e.wheelDelta < 0)
if (!window.scrolledToRed)
scrollTo('.red', 'scrolledToRed')
else if (!window.scrolledToYellow)
scrollTo('.green', 'scrolledToGreen')
I've created a Fiddle that represents the problem:
https://jsfiddle.net/pn6zqgwu/2/
When the user scrolls down the first time I want to take him to the red div and the next time to the green one.
None of the solutions I've tried really worked, since it was both "jumping" and scrolling where I want.
Any idea of how to solve the problem?
Thanks in advanced
Maybe you need to call e.preventDefault() to prevent browser default scroll behavior
I have made a fiddle for you, you can make more checks and add animations
var redTouched = false;
var greenTouched = false;
function scrollCb() {
event.preventDefault();
console.log(event.wheelDelta)
if (event.wheelDelta < 0) {
if (!redTouched) {
$(window).scrollTop($('.red').position().top);
redTouched = true;
} else if (redTouched && !greenTouched) {
$(window).scrollTop($('.green').position().top);
greenTouched = true;
} else if (redTouched && greenTouched) {
window.removeEventListener('mousewheel', scrollCb)
}
} else {
window.removeEventListener('mousewheel', scrollCb)
}
window.addEventListener('mousewheel', scrollCb);
https://jsfiddle.net/jacobjuul/b0k03wtr/
I am creating a Memory Game for a class at school, and I am using Bootstrap and jQuery. See Github. For testing use this jsfiddle, as the github code will change, I've included it if you would like to fork it for your own purposes.
I've constructed the code on the following logic:
Pick with how many cards you want to play.
Cards get loaded and randomized. Each pair have the same class(card* and glyphicon*).
You click on one card, then on another, and if they match they get discarded, else you pick again.
The problem that I'm currently having is with the third step, namely when you click on the third card it shows the previous two, meaning I need to include something to escape the first click events. At least that was my first suggestion for the problem. If you have other suggestions to completely restructure the third step, please don't shy to elaborate why.
// check if picked cards' classes match
jQuery("[class^=card]").click(function() { //picking the first card
jQuery(this).css('color', '#000');
var firstCard = $(this);
var firstCardClass = $(this).find('[class*=glyphicon]').attr('class').split(' ')[1];
jQuery("[class^=card]").click(function() { //picking the second card
var secondCard = $(this);
var secondCardClass = $(this).find('[class*=glyphicon]').attr('class').split(' ')[1];
console.log(firstCardClass);
console.log(secondCardClass);
if (firstCardClass == secondCardClass) {
console.log("yes")
$(firstCard).css('color', '#005d00'); //make them green
$(secondCard).css('color', '#005d00');
setTimeout(function() {
$(firstCard).css('display', 'none'); //discard
$(secondCard).css('display', 'none');
}, 1000);
}
else {
console.log("no");
$(firstCard).css('color', '#cc0000'); //make them red
$(secondCard).css('color', '#cc0000');
setTimeout(function() {
$(firstCard).css('color', '#fff'); //hide again
$(secondCard).css('color', '#fff');
}, 1000);
}
});
});
Note that the icons should be white as the cards, made them grey to see witch ones match without the need of firebug. If you click on more then two cards you will see what the problem is (if I failed to explain it well). I tried with including click unbind events in the end of each statement, but couldn't make it work.
Try your best! Thanks!
EDITED:
Seems I misunderstood the question so here's how I would go about having such game.
First I'll have my cards to have a structure like this:
<span class="card" data-card-type="one">One</span>
I'll use data-card-type to compare whether two cards are of the same type
I'll have a global variable firstCard which is originally null, if null I assign the clicked card to it and if not I compare the clicked card with it and then whether it's a match or not, I assign null to it meaning another pairing has begun.
I'll do all the logic in one onclick, looks weird to have a click listener inside another makes it to somehow look over-complicated.
var firstCard = null;
$('.card').on('click', function() {
$(this).addClass('selected');
if(!firstCard)
firstCard = $(this);
else if(firstCard[0] != $(this)[0]) {
if(firstCard.data('card-type') == $(this).data('card-type')) {
firstCard.remove();
$(this).remove();
firstCard = null;
//$('.card.selected').removeClass('selected');
}
else {
firstCard = null;
$('.card.selected').removeClass('selected');
}
}
});
jsfiddle DEMO
when a card is clicked, you can add a class to that particular card (e.g. classname clickedcard). Whenever you click another card you can test if there are 2 cards having this clickedcard class. If so, you can take action, for example remove all the clickedcard classes and add one again to the newly clicked one.
In pseudo code I would do it something like this:
jQuery("[class^=card]").click(function() {
if (jQuery('.clickedcard').length == 2) {
// two cards where clicked already...
// take the actions you want to do for 2 clicked cards
// you can use jQuery('.clickedcard')[0] and jQuery('.clickedcard')[1]
// to address both clicked cards
jQuery('.clickedcard').removeClass('clickedcard');
} else {
// no card or only one card is clicked
// do actions on the clicked card and add classname
jQuery(this).addClass('clickedcard');
}
});
You could use `one' (to bind an event once):
$("[class^=card]").one(`click', firstCard);
function firstCard() { //picking the first card
$(this).css('color', '#000');
var firstCard = $(this);
var firstCardClass = $(this).find('[class*=glyphicon]').attr('class').split(' ')[1];
$("[class^=card]").one('click', secondCard);
function secondCard() { //picking the second card
var secondCard = $(this);
var secondCardClass = $(this).find('[class*=glyphicon]').attr('class').split(' ')[1];
console.log(firstCardClass);
console.log(secondCardClass);
if (firstCardClass == secondCardClass) {
console.log("yes")
$(firstCard).css('color', '#005d00'); //make them green
$(secondCard).css('color', '#005d00');
setTimeout(function() {
$(firstCard).css('display', 'none'); //discard
$(secondCard).css('display', 'none');
}, 1000);
}
else {
console.log("no");
$(firstCard).css('color', '#cc0000'); //make them red
$(secondCard).css('color', '#cc0000');
setTimeout(function() {
$(firstCard).css('color', '#fff'); //hide again
$(secondCard).css('color', '#fff');
}, 1000);
}
$("[class^=card]").one(`click', firstCard);
}
}
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/
I need to change the back button functionality of my phonegap project, which I've succeeded in doing without any problem. The only issue now, is that I need to further change the functionality based on if the user has a certain field selected.
Basically, if the user has clicked in a field with the id of "date-selector1", I need to completely disable the back button.
I was attempting to use document.activeElement, but it only returns the type of the element (input in this case), but I still want the functionality to work when they are in a general input, but not when they are in an input of a specific id.
EDIT
I tried all of the suggestions below, and have ended up with the following code, but still no success.
function pluginDeviceReady() {
document.addEventListener("backbutton", onBackKeyDown, false);
}
function onBackKeyDown() {
var sElement = document.activeElement;
var isBadElement = false;
var eList = ['procedure-date', 'immunization-date', 'lab-test-done', 'condition-onset', 'condition-resolution', 'medication-start-date', 'medication-stop-date', 'reaction-date'];
console.log("[[ACTIVE ELEMENT: --> " + document.activeElement + "]]");
for (var i = 0;i < eList.length - 1;i++) {
if (sElement == $(eList[i])[0]) {
isBadElement = true;
}
}
if (isBadElement) {
console.log('Back button not allowed here');
} else if ($.mobile.activePage.is('#main') || $.mobile.activePage.is('#family') || $.mobile.activePage.is('#login')) {
navigator.app.exitApp();
} else {
navigator.app.backHistory();
}
}
if you're listening for the back button you can add this if statement:
if (document.activeElement == $("#date-selector1")[0]) {
/*disable button here, return false etc...*/
}
or even better (Thanks to Jonathan Sampson)
if (document.activeElement.id === "date-selector1") {
/*disable button here, return false etc...*/
}
You can have a flag set when a user clicks on a field or you can have a click event (or any other type of event) when a user clicks on the field that should disable the back button.
From the documentation it looks like for the specific page that the backbuton is conditional on you can drop back-btn=true removing that back button.
http://jquerymobile.com/test/docs/toolbars/docs-headers.html
If you need complex conditional functionality you can just create your own button in the header or footer, style it using jquery-mobile widgets and implement your own click functionality.
http://jsfiddle.net/SXrAb/
Following the jsfiddle link there is a simplified sample of what I need. Currently it shows the calendar on button click, and hides it on input blur.
What I cannot implement additionally is hiding calendar on button click.
So - calendar should:
open on button click if hidden (done)
hide on blur (done)
hide on button click if opened (this is what I'm in stuck with, because blur is triggered before button click event so I have no chance to handle it properly)
UPD:
the solution is expected to work correctly in all cases, like "mousedown on button, drag below, mouseup" (otherwise I wouldn't ask it ;-)
Try this:
var $calendar = $('#calendar');
var mousedown = false;
$('#calendar-input').blur(function() {
if (!mousedown)
$calendar.hide();
});
$('#calendar-button').mousedown(function() {
mousedown = true;
});
$('#calendar-button').mouseup(function() {
mousedown = false;
});
$('#calendar-button').click(function() {
if ($calendar.is(':visible')) {
$calendar.hide();
}
else {
$calendar.show();
$('#calendar-input').focus();
}
});
Demo here: http://jsfiddle.net/Tz73k/
UPDATE: OK, I moved the mouseup event to the document level. I don't think the mouse state can be tricked now by dragging the mouse before releasing it:
var $calendar = $('#calendar');
var mousedown = false;
$('#calendar-input').blur(function() {
if (!mousedown)
$calendar.hide();
});
$('#calendar-button').mousedown(function() {
mousedown = true;
});
$(document).mouseup(function() {
mousedown = false;
});
$('#calendar-button').click(function() {
if ($calendar.is(':visible')) {
$calendar.hide();
}
else {
$calendar.show();
$('#calendar-input').focus();
}
});
Updated fiddle: http://jsfiddle.net/yQ5CT/
It's helpful to think of the calendar and the button as a set, where you only hide the calendar when everything in the set has blurred. To do this you need a system where focus can be "handed off" between the calendar and button without triggering your hide function. To do this you'll need a focus and blur handler on both your calendar and your button, as well as a state variable for isFocused.
var isFocused;
jQuery('#calendar,#calendar-button,#calendar-input').blur(function(){
isFocused = false;
setTimeout(function() {
if (!isFocused) { hide(); }
}, 0);
});
jQuery('#calendar,#calendar-button,#calendar-input').focus(function(){
isFocused = true;
});
The setTimeout is because, when you click the button, focus is lost on calendar before it's gained on the button, so there's momentarily nothing in focus.
Edit
I guess there's actually three elements in the set, the button, the textbox, and the calendar. I updated the example. This also fixes the issue that, in your example, you can't click between the calendar and the textbox without the calendar hiding. Presumably the real calendar can be manipulated by clicking it.
Edit 2
For this to work you'll need to make your calendar focusable by giving it a tabindex.
<span id="calendar" tabindex="-1">I'm a calendar ;-)</span>
Hiya Demo here http://jsfiddle.net/SXrAb/50/ -- (non alert version) http://jsfiddle.net/SXrAb/51/
Thanks zerkms!
JQuery Code
var $calendar = $('#calendar');
$calendar.hide();
var isBlurEventInvoked = true;
var calendarShow = false;
$('#calendar-input').blur(function() {
alert(isBlurEventInvoked + " ==== " + calendarShow);
if (isBlurEventInvoked && calendarShow){
$calendar.hide();
isBlurEventInvoked = true;
}
});
$('#calendar-button').click(function() {
if (!$calendar.is(':visible') && isBlurEventInvoked){
$calendar.show();
$('#calendar-input').focus();
calendarShow = true;
isBlurEventInvoked = true;
}else if ($calendar.is(':visible')) {
$calendar.hide();
isBlurEventInvoked = false;
calendarShow = false;
}
});