Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

hide sign in form after 10s if cookie not set and no inputs are selected

I'm developing a little function for my site where a sign in form is automatically shown in the navbar when the site is opened up, but only if a certain cookie has not been set. Then, after 10 seconds has passed, the form will disappear.

It is also supposed to stay open if the user has selected one of the form inputs OR if one of the inputs contain contents. (#user-pest or #pass-pest).

Most of it is working the way it is supposed to, however, even when one of the inputs is selected or contains contents, once 10 seconds has passed, the form will disappear from the page.

The following is the JavaScript (and jQuery) code that I am using (updated).

$(document).ready(function(){
    // hide sign in form

    function hideForm(){ // function for updating elements
        $("#darknet-login-nav").css("display", "none");
        $(".index-outer").css("height", "100px");
        $(".index-inner").css("width", "438px");
        $(".index-inner").css("top", "-10px");
        $("#darknet-mast").css("font-size", "97px");
    }

    function hideFormSet(){ // function used for updating elements and setting cookie
        hideForm();
        document.cookie = "signinNav=set";
    }

    var checkDisplayed = getCookie("signinNav"); // get cookie contents
    if(checkDisplayed == "set"){ 
        hideForm(); // if cookie is set, hide the form
    } else { // if it isn't
        var hideInterval = setInterval(hideFormSet, 10000); // after 10 seconds, call hideFormSet function
        if($("#user-pest").is(':focus') || $("#pass-pest").is(':focus')){
            clearInterval(hideInterval); // if one of the inputs are focused on, stop the interval
        } else {
            hideInterval; // if they aren't focused, start the interval
        }
    }
});

and this is my simplified markup.

<div class="darknet-nav-login-form" id="darknet-login-nav">
    <form action="" method="post">
        <input type="text" name="username" id="user-pest" placeholder="Username" autocomplete="off"><br>
        <input type="password" name="password" id="pass-pest" placeholder="Password" autocomplete="off"><br>
    </form>
</div>

I'm still very new to JavaScript, so any pointers and fixes will be greatly appreciated.

EDIT: please check my above updated code.

Even when on of the inputs are focused, the interval will still continue, rather than stopping.

Thanks

like image 958
GROVER. Avatar asked Jul 04 '16 07:07

GROVER.


3 Answers

If I understand your goal correctly, you also want to hide the form 10 seconds after the inputs lose focus. In that case it's easier to bind to the focusin/focusout events to restart the timeout, otherwise when leaving an input just before the interval fires it is hidden much earlier than the timeout.

var inputs = $('#user-pest, #pass-pest'),
    hideTimeout,
    checkFocus = function(){
        var hide = !inputs.is(':focus');
        if(hide===!!hideTimeout)return;
        if(hide)
            hideTimeout = setTimeout(hideFormSet, 10000);
        else
            hideTimeout = clearTimeout(hideTimeout);
        };

inputs.focusin(checkFocus).focusout(checkFocus);
checkFocus();

Sidenote, jQuery's is method checks if any of the elements in the jq array corresponds to the selector, so instead of a separate and/or, you can do: $('#user-pest, #pass-pest').is(':focus')

example Fiddle

Sidenote2, the (re)binding will occur twice because one input loses focus before the next one gains focus. This is not a problem in itself, but if the form only contains those 2 inputs, using event bubbling to check focus on the form itself might be one little step further optimized: inputs.parent().focusin(checkFocus).focusout(checkFocus);

like image 196
Me.Name Avatar answered Sep 23 '22 21:09

Me.Name


You need an && in this line.

if(!$("#user-pest").is(':focus') || !$("#pass-pest").is(':focus')){

What you had before was

if( user-pest is not focused OR pass-pest is not focused)

A user can't focus both of them at once, thus this will always evaluate to true and hide will be set to true. Use the following:

if(!$("#user-pest").is(':focus') && !$("#pass-pest").is(':focus')){

Alternatively you could also use the following

if($("#user-pest").is(':focus') || $("#pass-pest").is(':focus')){
    var hide = false;
} else {
    var hide = true;
}

As pointed out in your comment there is also another problem, which I missed the first time.

The hide variable is set on page load, which happens instantly, and you most likely won't have had the time to focus either object yet. You should move the code that checks if it's focused to inside the timeout callback.

See this jsFiddle for the full code of a working example. Basically your timeout should check if the inputs are focused when run, not on page load, as seen in the following snippet.

setTimeout(function() {
  if (!$("#user-pest").is(':focus') && !$("#pass-pest").is(':focus')) {
    $("#darknet-login-nav").css("display", "none");
    $(".index-outer").css("height", "100px");
    $(".index-inner").css("width", "438px");
    $(".index-inner").css("top", "-10px");
    $("#darknet-mast").css("font-size", "97px");
    document.cookie = "signinNav=set"; // set the cookie so the form doesn't appear when they come back later
  }
}, 2000);
like image 33
Robin Avatar answered Sep 20 '22 21:09

Robin


Here's a solution which ensures that the inputs are each empty and that they're not focused. Behaviour beyond the initial 10s timeout wasn't specified, so I've left the interval active - the hide behaviour will be invoked any time the timeout elapses and the conditions for hiding the header are met.

If you wish to make it a 'one-shot' timer, simply clearInterval in the intervalHandler function.

window.addEventListener('load', onDocLoaded, false);

var intervalHandle;

function onDocLoaded(evt)
{
	intervalHandle = setInterval(intervalHandler, 2000);
}

function hideHeader()
{
	document.getElementById('darknet-login-nav').classList.add('hidden');
}

// returns true/false
// true if the header should be hidden, false otherwise.
// Things that will prevent the header from being hidden area
// 0) content in the #user-pest input
// 1) content in the #pass-pest input
// 2) focus of either #user-pest or #pass-pest elements
function shouldHideHeader()
{
	if (document.getElementById('user-pest').value != '')
		return false;
		
	if (document.getElementById('pass-pest').value != '')
		return false;
		
	if (document.activeElement == document.getElementById('user-pest'))
		return false;
		
	if (document.activeElement == document.getElementById('pass-pest'))
		return false;
		
	return true;
}


function intervalHandler()
{
	if (shouldHideHeader())
		hideHeader();
}
.darknet-nav-login-form
{
	height: 42px;
}
.hidden
{
	height: 0px;
	overflow: hidden;
	transition: height 2s;
}
<div class="darknet-nav-login-form" id="darknet-login-nav">
		<form action="" method="post">
			<input type="text" name="username" id="user-pest" placeholder="Username" autocomplete="off"/><br>
			<input type="password" name="password" id="pass-pest" placeholder="Password" autocomplete="off"/><br>
		</form>
	</div>
like image 37
enhzflep Avatar answered Sep 23 '22 21:09

enhzflep