3

In jQuery-UI-Dialog allows me to display a 'modal' dialog box on my web page so that the user must click an option in the dialog to proceed.

I've been writing my own dialog box code, but there is something that jQuery-UI-Dialog does that I don't know how to do yet.

I am able to display a "mask" element behind the dialog to prevent the user from clicking on elements on the page, but the user can still select elements behind the dialog using the tab key.

The jQuery-UI-Dialog seems to somehow trap the keyboard input inside the dialog box even when the tab key is pressed. This is very neat, but I will add that it could be abused.

What aspect of the DOM do I need to access to get this functionality?

Vivian River
  • 31,198
  • 62
  • 198
  • 313
  • I asked the same question earlier. Got a great answer: http://stackoverflow.com/questions/6296447/how-to-disable-outside-clicks-while-an-element-is-visible – Jonathan M Aug 12 '11 at 22:26

3 Answers3

1

In jQuery UI, they capture the tabs, while ignoring other keys, and limit the the tab sequence to only the tabbable elements on the dialog. See the snippet in the original source of code of jQuery UI v1.8.5:

        uiDialog.bind('keypress.ui-dialog', function(event) {
            if (event.keyCode !== $.ui.keyCode.TAB) {
                return;
            }

            var tabbables = $(':tabbable', this),
                first = tabbables.filter(':first'),
                last  = tabbables.filter(':last');

            if (event.target === last[0] && !event.shiftKey) {
                first.focus(1);
                return false;
            } else if (event.target === first[0] && event.shiftKey) {
                last.focus(1);
                return false;
            }
        });

keypress.ui-dialog is a namespaced event. It enables the developers to more easily identity the events, e.g. for triggering and removal. But functional wise, you can deem it as an ordinary keypress event.

William Niu
  • 15,798
  • 7
  • 53
  • 93
  • So... `keypress.ui-dialog` refer to only keypress events that happen when the focus is on the dialog? – Vivian River Aug 14 '11 at 03:25
  • It's a namespaced event. Please see updated post. To your question, this will capture all `keypress` events, as usual. – William Niu Aug 14 '11 at 09:16
  • Why did you write `.focus(1)`? I always just write `.focus()`. – Vivian River Aug 16 '11 at 21:10
  • I stated very clearly that the snippet is from the jQuery UI v1.8.5. So, I didn't write that function; jQuery UI team did. The numerical argument for `.focus(1)` is the number of ms to delay the call, a modified version of focus in jQuery UI. The reason for the 1ms delay, I think, is to override the focus function in the following code block (see you see it in the source code). – William Niu Aug 16 '11 at 22:35
0

Set body overflow to hidden

$('body').css({'overflow':'hidden'});

jQuery screen grey out box demo

Pir Abdul
  • 2,274
  • 1
  • 26
  • 35
0

I would like to accept William Niu's answer, but there is a flaw that prevents it from working in my web application. If the first or last element in the dialog is a radio button, then this code won't work in IE. The browser will tab to the radio button group one time.

If the selected radio button is one that the browser highlights when the user tabs to the radio button group, then this code will work. However, the selected radio button is not the one the browser highlights when the user tabs to the radio button group, then the focus will be lost from the dialog.

Here is some code I've written that solves this problem:

function _bindTabKeyForDialog(dialogId) {
    var tabbable = $('#' + dialogId).find(':tabbable');
    var firstElement = $(tabbable).filter(':first');
    var lastElement = $(tabbable).filter(':last');

    var firstGroup = (firstElement[0].type !== 'radio') ?
        firstElement :
        tabbable.filter("[name='" + firstElement[0].name + "']");
    var lastGroup = (lastElement[0].type !== 'radio') ?
        lastElement :
        tabbable.filter("[name='" + lastElement[0].name + "']");

    $(document).unbind('keydown.' + dialogId);
    $(document).bind('keydown.' + dialogId, function (e) {
        if (e.keyCode == 9) {
            if ($(e.target).is(lastGroup) && !e.shiftKey) {
                firstGroup.first().focus();
                e.preventDefault();
            }
            else if ($(e.target).is(firstGroup) && e.shiftKey) {
                lastGroup.first().focus();
                e.preventDefault();
            }
        }
    });
} // end _bindTabKeyForDialog

As you can see, I change William's first and last variables to groups of elements. If the first or last tabbable element in the dialog is a radio button, then it will include all radio buttons with the same name.

Otherwise, this code functions the same as William's code.

Vivian River
  • 31,198
  • 62
  • 198
  • 313
  • Just to clarify, I did not write the code. I only extracted the relevant snippet from the source code of jQuery UI, so that if can see how they did it. – William Niu Aug 16 '11 at 22:42
  • Congrats on find a solution! I wonder whether what you described in IE is an expected (buggy) behaviour (as usual). If not, it may be a bug in jQuery UI or jQuery. In that case, you should consider submitting a bug report to them. – William Niu Aug 16 '11 at 22:44