Page 2 of 3 FirstFirst 123 LastLast
Results 11 to 20 of 24

Thread: [2.0.1][OPEN] modal dialog can be bypassed by tab pressing

  1. #11
    Ext User
    Join Date
    Nov 2007
    Location
    Centreville, VA
    Posts
    58

    Default Prevent TAB key from bypassing modal window

    I have been looking at this issue and come up with the following approach. Along with the code below you need to define the tabIndex configuration option for all the components you want included in the tabbing order.

    The code works in FF3 and IE7.

    Code:
    Ext.override(Ext.Window, {
       handleTabs : true,
    
       initEvents : Ext.Window.prototype.initEvents.createInterceptor(function () {
          if (this.handleTabs === true) {
             this.keys = [].concat(this.keys || [], { key : Ext.EventObject.TAB, fn : this.onTAB, scope : this });
          }
       }),
    
       onTAB : function (keyCode, e) {
          e.stopEvent();
          
          // TAB moves forward through the order. SHIFT-TAB moves backward through the order.
          var backward = e.shiftKey;
    
          // Get the set of controls that have a defined tabIndex >= 0. Sort them ascending or descending depending
          // on whether we are moving the focus forward or backward.
          var elements = Ext.query('[tabIndex][tabIndex!=-1]', this.el.dom).sort(function (a, b) {
             return backward ? b.tabIndex - a.tabIndex : a.tabIndex - b.tabIndex;
          });
          
          // We cannot determine the next element in the order if there are no elements with a defined tabIndex.
          if (elements.length === 0) {
             return;
          }
          
          // Get the tabIndex from the control that had focus when TAB/SHIFT-TAB was pressed
          var currentIndex = e.getTarget().tabIndex || 0;
    
          // Check each element to see if it is the next one in the ordering      
          for (var i=0; i<elements.length; i++) {
             var el    = elements[i];
             var index = el.tabIndex;
             
             if ((backward && index < currentIndex) || (!backward && index > currentIndex)) {
                el.focus();
                return;
             }
          }
          
          // Since no element was the next in the ordering, loop around to other end of the ordering
          elements[0].focus();
       }
    });

  2. #12
    Ext JS Premium Member dj's Avatar
    Join Date
    Mar 2007
    Location
    Germany
    Posts
    573

    Default

    One could also install a global focus/blur handler to enforce that the focus stays in the modal window.

    YUI did this:
    http://yuiblog.com/blog/2008/10/07/onfocus-onblur/
    Daniel Jagszent
    [email protected]??gsze?t.de <- convert to plain ASCII to get my email address

  3. #13
    Sencha User
    Join Date
    Sep 2007
    Posts
    46

    Default Solution

    I was running into the same problem with my application and I use this code. If the tab key is pressed and the active window is modal (if any window), it checks to see if the activeElement (the one with focus) is a child of that window. If so, we are good. If not, get the first child of the window that can receive focus and focus it:

    Code:
    Ext.onReady(function()
    {
        Ext.getBody().on('keyup', function(e, t)
        {
            if (e.TAB == e.getKey())
            {
                var top_win = Ext.WindowMgr.getActive();
                
                if (top_win && top_win.modal)
                {
                    if (!top_win.getEl().contains(document.activeElement))
                    {
                        var found = false;
                        var first_focus = top_win.findBy(function(cmp, win)
                        {
                            var ti = cmp.getEl().dom.tabIndex;
                            
                            if('hidden' != cmp.getXType() && !cmp.hidden && ti >= 0 && !found)
                            {
                                found = true;
                                return true;
                            }
                            
                            return false;
                        });
                        
                        if (first_focus.length > 0)
                        {
                            first_focus[0].focus(true);
                        }
                        else
                        {
                            top_win.focus();
                        }
                    }
                }
            }
        }, this);
    });
    My application only runs on Firefox, so the "document.activeElement" should be cross-browser tested for your application(s) if they use other browsers besides Firefox.

    Let me know if you find any bugs/efficiency upgrades
    Kavih Williams
    CEO/Founder - Push Channels & Browser Not Included
    On Twitter

  4. #14

    Default

    Can someone from Ext tell us whether this will be implemented in Ext 3.0 release. It seems unusual that we have to add these manual fixes for such a mature library now?

  5. #15
    Ext JS Premium Member
    Join Date
    Jan 2008
    Posts
    5

    Default Solution for IE7

    Quote Originally Posted by kavih7 View Post
    I was running into the same problem with my application and I use this code. If the tab key is pressed and the active window is modal (if any window), it checks to see if the activeElement (the one with focus) is a child of that window. If so, we are good. If not, get the first child of the window that can receive focus and focus it:

    Code:
    Ext.onReady(function()
    {
        Ext.getBody().on('keyup', function(e, t)
        {
            if (e.TAB == e.getKey())
            {
                var top_win = Ext.WindowMgr.getActive();
                
                if (top_win && top_win.modal)
                {
                    if (!top_win.getEl().contains(document.activeElement))
                    {
                        var found = false;
                        var first_focus = top_win.findBy(function(cmp, win)
                        {
                            var ti = cmp.getEl().dom.tabIndex;
                            
                            if('hidden' != cmp.getXType() && !cmp.hidden && ti >= 0 && !found)
                            {
                                found = true;
                                return true;
                            }
                            
                            return false;
                        });
                        
                        if (first_focus.length > 0)
                        {
                            first_focus[0].focus(true);
                        }
                        else
                        {
                            top_win.focus();
                        }
                    }
                }
            }
        }, this);
    });
    My application only runs on Firefox, so the "document.activeElement" should be cross-browser tested for your application(s) if they use other browsers besides Firefox.

    Let me know if you find any bugs/efficiency upgrades

    Thanks a lot for this solution. I had to modify it a little bit to work in IE7:

    Code:
    Ext.onReady(function()
    {
        Ext.getBody().on('keyup', function(e, t)
        {
            if (e.TAB == e.getKey())
            {
                var top_win = Ext.WindowMgr.getActive();
                
                if (top_win && top_win.modal)
                {
                    if (!top_win.getEl().contains(document.activeElement))
                    {
                        var found = false;
                        var first_focus = top_win.findBy(function(cmp, win)
                        {
                            var ti = cmp.getEl().dom.tabIndex;
                            
                            if('hidden' != cmp.getXType() && 'panel' != cmp.getXType()&& 
                               'form' != cmp.getXType()&& !cmp.hidden && ti >= 0 && !found)
                            {
                                found = true;
                                return true;
                            }
                            
                            return false;
                        });
                        
                        if (first_focus.length > 0)
                        {
                            first_focus[0].focus(true);
                        }
                        else
                        {
                            top_win.focus();
                        }
                    }
                }
            }
        }, this);
    });

  6. #16

    Default

    any word on this being an official fix? A Modal window SHOULD contain the Tab key and not let focus go outside of the window. Seems like such basic functionality that should have already been included in the library.

  7. #17
    Ext JS Premium Member prophet's Avatar
    Join Date
    Mar 2007
    Location
    Greenwich, CT
    Posts
    189

    Default

    [EXT 3] Seems like this fix breaks form field tabbing in modal windows all together...
    Any ideas?

  8. #18

    Default

    Not this again. Can someone from the Ext team not just put this on the official features list? It is quite a basic requirement and should come out of the box when windows are described as modal.

  9. #19
    Sencha User Condor's Avatar
    Join Date
    Mar 2007
    Location
    The Netherlands
    Posts
    24,246

  10. #20

    Default

    Quote Originally Posted by kavih7 View Post
    I was running into the same problem with my application and I use this code. If the tab key is pressed and the active window is modal (if any window), it checks to see if the activeElement (the one with focus) is a child of that window. If so, we are good. If not, get the first child of the window that can receive focus and focus it:

    Code:
    Ext.onReady(function()
    {
        Ext.getBody().on('keyup', function(e, t)
        {
            if (e.TAB == e.getKey())
            {
                var top_win = Ext.WindowMgr.getActive();
                
                if (top_win && top_win.modal)
                {
                    if (!top_win.getEl().contains(document.activeElement))
                    {
                        var found = false;
                        var first_focus = top_win.findBy(function(cmp, win)
                        {
                            var ti = cmp.getEl().dom.tabIndex;
                            
                            if('hidden' != cmp.getXType() && !cmp.hidden && ti >= 0 && !found)
                            {
                                found = true;
                                return true;
                            }
                            
                            return false;
                        });
                        
                        if (first_focus.length > 0)
                        {
                            first_focus[0].focus(true);
                        }
                        else
                        {
                            top_win.focus();
                        }
                    }
                }
            }
        }, this);
    });
    My application only runs on Firefox, so the "document.activeElement" should be cross-browser tested for your application(s) if they use other browsers besides Firefox.

    Let me know if you find any bugs/efficiency upgrades
    This is a good fix, but i added a defer for 1milisecond and change it to keydown. this way, you wont notice the focus rect moves to other element.

    Code:
    Ext.getBody().on('keydown', function(e, t)
    {
      if (e.TAB == e.getKey())
      {
        (function(){
          
          var top_win = Ext.WindowMgr.getActive();
          
          if (top_win)
          {
            if (!top_win.getEl().contains(document.activeElement))
            {
              var found = false;
              var first_focus = top_win.findBy(function(cmp, win)
              {
                var ti = cmp.getEl().dom.tabIndex;
                
                if('hidden' != cmp.getXType() && !cmp.hidden && ti >= 0 && !found)
                {
                  found = true;
                  return true;
                }
                
                return false;
              });
              
              if (first_focus.length > 0)
              {
                first_focus[0].focus(true);
              }
              else
              {
                top_win.focus();
              }
            }
          }
        
        }).defer(1);
      }
    }, this);

Page 2 of 3 FirstFirst 123 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •