stefangabos / Zebra_Dialog

A small, compact, and highly configurable jQuery plugin for creating beautiful modal dialog boxes

Home Page:https://stefangabos.github.io/Zebra_Dialog/flat.html

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Lose of Focus

weisborg opened this issue · comments

I started using this dialog to replace Bootstrap/BootBox since modal on modal doesn't work well, and this allowed layers.

I discovered a weird issue though when jQuery Validation sets focus to an input in error while this dialog is shown. Part of it happens in Zebra and Bootbox- If something happens on focus of the input like a datepicker or browser autocomplete/autofill then they will appear and often on top of the dialog since some z-order we have no control over. The other half only happens in Zebra- Pressing tab will cycle through tab order, typing types text, and Enter will click buttons instead of closing the Zebra dialog. When in Edge the cursor will also blink through the dialog.

The Bootstrap/Bootbox way must monitor blur/hasFocus and steal focus back, but I'm not finding it in the source there yet. They don't keep track of avtiveElement to restore it either since nothing has focus when the dialog is closed.

I'm not sure how to resolve it other than monitoring with a timer or something then check if there is focus and either blur the activeElement or set focus to the dialog. It would be a plus to restore focus to what it was or what it became while the dialog was running too.

I could use a jsfiddle for this as it would be almost impossible to re-create the exact same scenario you are having

You should be able to see it on any page with inputs you can focus on. It isn't keeping the focus in the dialog.

I have a wrapper method I've been testing with below. I have an invalidHandler in jQuery Validation that if > 0 errors I shows an alert telling them to fix the errors on the page by passing the message text to the wrapper below and a -1 for the timeout which makes it stay open with an OK button. jQuery Validation puts focus in the input with the error, but I can also click in the dialog to put focus back there and tab around behind the dialog. The code with $element at the bottom is some code I found in Bootstrap after posting the issue yesterday. It seemed to be keeping focus in the dialog. The last 2 lines in the .on starting with blur were just setting focus to $element in Bootstrap. That overflows the stack when used though. Then I tried to just blur whatever was trying to steal focus which worked, but the dialog no longer responded to Enter since nothing had focus. The 2nd line is like my tenth attempt at setting focus to the dialog and various parts of it. No matter what I set focus to something else further up the DOM gets a focusin and this loops until it blows up the stack, so no clue how Bootstrap is using it.

function ShowStatus(isSuccess, message, msTimeout, optionsObj) {
    var timeout = (isSuccess ? 2000 : 4000);
    if (msTimeout)
        timeout = msTimeout;
    var isFixedWidth = false;
    if (optionsObj) { // Other options were here I used on bootbox and haven't put here yet.
        if (optionsObj.isFixedWidth)
            isFixedWidth = true;
    }

    new $.Zebra_Dialog({
        source: {
            inline: '<p' + (isFixedWidth ? 're class="' : ' class="text-center ') + 'largeIcon"><i class="fa ' + (isSuccess ? (isSuccess !== 2 ? 'greenText fa-check-circle' : 'amberText fa-exclamation-triangle') : 'redText fa-times-circle') + '" /> ' + (message ? message : '') + '</p' + (isFixedWidth ? 're' : '') + '>'
        },
        title: " ",
        type: false,
        position: ['center', 'top + 50'],
        width: 600,
        modal: (timeout > 0 ? false : true),
        auto_close: (timeout > 0 ? timeout : false),
        buttons: (timeout > 0 ? false : ["OK"])
    });

    var $element = $("div.ZebraDialog").first(); // May need tweaked if we do layered dialogs
    if ($element.length === 1) {
        $element.prop('tabIndex', -1);
        $(document)
        .off('focusin.ZebraDialog_') // guard against infinite focus loop
        .on('focusin.ZebraDialog_', function (e) {
            if (document !== e.target &&
                $element[0] !== e.target &&
                !$element.has(e.target).length) {
                console.log(e.target);
                $(e.target).trigger('blur');
                $("div.ZebraDialog_Buttons").first().find(".ZebraDialog_Button_0").focus();
            }
        });
    }
}

Just to let you know what I did to work around the problem in my case:

I call the method below to prevent anything from getting focus just before the dialog call, and then Call it again in onClose restoring focus back.

function ToggleFocusable(canFocus) {
	var x = document.querySelectorAll("input, select, textarea, button, object, a, [tabindex]");
	for (let i = 0; i < x.length; i++) {
		switch (x[i].nodeName) {
			case "INPUT": case "SELECT": case "TEXTAREA": case "BUTTON": case "OBJECT":
				if (canFocus) {
					if (x[i].wasDisabled) delete x[i].wasDisabled; else x[i].disabled = false;
				}
				else {
					if (x[i].disabled) x[i].wasDisabled = true; else x[i].disabled = true;
				}
				break;
			default:
				if (canFocus) {
					x[i].classList.remove("ClassThatSetsHiddenVisibility");
				}
				else {
					x[i].classList.add("ClassThatSetsHiddenVisibility");
				}
				break;
		}
	}
}