Changeset 16233

Show
Ignore:
Timestamp:
01/06/09 04:40:56 (14 months ago)
Author:
bill
Message:

Defer focusing on a static Menu/MenuBar until user clicks it, or tabs into it. Once user clicks on a Menu/MenuBar, it focuses on it, and then (as before) any mouse movement or keyboard movement (via arrow keys) will change focus. Also (as before), focus is shifted to a context menu immediately when it's displayed.

Separated out CSS classes for indicating that a MenuItem? is mouse hovered (dijitMenuItemHover), and to indicate which MenuItem? is selected/active (dijitMenuItemSelected). Currently they look exactly the same, although that could be changed (including removing the hover effect altogether).

"Selected/active" is in the sense of the selected tab, and is controlled by the mouse or keyboard. Implementation-wise, it means that either the MenuItem? has focus, or focus is on a submenu of that MenuItem?.

Also added dijitMenuPassive/dijitMenuActive class to the Menu/MenuBar domNode so that CSS rules for hover can be customized based on whether or not the menu has focus. Once the menu gets focus the dijitMenuHover effect is disabled in favor of the dijitMenuSelected effect, so that the dijitMenuHover effect won't linger on "File" if user moved the mouse over "File" but then used the keyboard arrows to move to the "Edit" MenuBarItem?. (This is a setting in tundra/nihilo/soria and can be changed if desired.)

Open issue with re-focus on click-execute of a leaf menu item... after executing a menu choice focus ends up nowhere (or maybe on the page itself). Probably should be going to the menubar?

Refs #4634 !strict

Location:
dijit/trunk
Files:
7 modified

Legend:

Unmodified
Added
Removed
  • dijit/trunk/Menu.js

    r16207 r16233  
    1616        // popupDelay: Integer 
    1717        //      number of milliseconds before hovering (without clicking) causes the popup to automatically open. 
    18         //      set this to -1 to disable automatically opening of submenus. 
    1918        popupDelay: 500, 
    2019 
     
    5251 
    5352        onItemHover: function(/*MenuItem*/ item){ 
    54                 // summary: Called when cursor is over a MenuItem 
    55                 this.focusChild(item); 
    56  
    57                 if(this.focusedChild.popup && !this.focusedChild.disabled && !this.hover_timer && this.popupDelay>=0){ 
    58                         this.hover_timer = setTimeout(dojo.hitch(this, "_openPopup"), this.popupDelay); 
     53                // summary: 
     54                //              Called when cursor is over a MenuItem. 
     55 
     56                // Don't do anything unless user has "activated" the menu by: 
     57                //              1) clicking it 
     58                //              2) tabbing into it 
     59                //              3) opening it from a parent menu (which automatically focuses it) 
     60                if(this.isActive){ 
     61                        this.focusChild(item); 
     62         
     63                        if(this.focusedChild.popup && !this.focusedChild.disabled && !this.hover_timer){ 
     64                                this.hover_timer = setTimeout(dojo.hitch(this, "_openPopup"), this.popupDelay); 
     65                        } 
    5966                } 
    6067        }, 
    6168 
    6269        _onChildBlur: function(item){ 
    63                 // summary: Close all popups that are open and descendants of this menu 
     70                // summary: 
     71                //              Called when a child MenuItem becomes inactive because focus 
     72                //              has been removed from the MenuItem *and* it's descendant menus. 
     73 
     74                item._setSelected(false); 
     75 
     76                // Close all popups that are open and descendants of this menu 
    6477                dijit.popup.close(item.popup); 
    65                 item._blur(); 
    6678                this._stopPopupTimer(); 
    6779        }, 
     
    6981        onItemUnhover: function(/*MenuItem*/ item){ 
    7082                // summary: Callback fires when mouse exits a MenuItem 
    71                 this._stopPopupTimer(); 
     83                if(this.isActive){ 
     84                        this._stopPopupTimer(); 
     85                } 
    7286        }, 
    7387 
     
    87101                // summary: user defined function to handle clicks on an item 
    88102                if(item.disabled){ return false; } 
     103 
     104                this.focusChild(item); 
    89105 
    90106                if(item.popup){ 
     
    149165        }, 
    150166 
     167        _onFocus: function(){ 
     168                // summary: 
     169                //              Called when this Menu gets focus from: 
     170                //                      1) clicking it 
     171                //                      2) tabbing into it 
     172                //                      3) being opened by a parent menu. 
     173                //              This is not called just from mouse hover. 
     174                this.isActive = true; 
     175                dojo.addClass(this.domNode, "dijitMenuActive"); 
     176                dojo.removeClass(this.domNode, "dijitMenuPassive"); 
     177                this.inherited(arguments); 
     178        }, 
     179         
    151180        _onBlur: function(){ 
     181                // summary: 
     182                //              Called when focus is moved away from this Menu and it's submenus 
     183                this.isActive = false; 
     184                dojo.removeClass(this.domNode, "dijitMenuActive"); 
     185                dojo.addClass(this.domNode, "dijitMenuPassive"); 
     186 
    152187                // If user blurs/clicks away from a MenuBar (or always visible Menu), then close all popped up submenus etc. 
    153188                this.onClose(); 
     189 
    154190                this.inherited(arguments); 
    155191        }, 
     
    177213 
    178214        templateString: 
    179                         '<table class="dijit dijitMenu dijitReset dijitMenuTable" waiRole="menu" tabIndex="${tabIndex}" dojoAttachEvent="onkeypress:_onKeyPress">' + 
     215                        '<table class="dijit dijitMenu dijitMenuPassive dijitReset dijitMenuTable" waiRole="menu" tabIndex="${tabIndex}" dojoAttachEvent="onkeypress:_onKeyPress">' + 
    180216                                '<tbody class="dijitReset" dojoAttachPoint="containerNode"></tbody>'+ 
    181217                        '</table>', 
     
    429465        _onHover: function(){ 
    430466                // summary: callback when mouse is moved onto menu item 
     467                dojo.addClass(this.domNode, 'dijitMenuItemHover'); 
    431468                this.getParent().onItemHover(this); 
    432469        }, 
    433470 
    434471        _onUnhover: function(){ 
    435                 // summary: callback when mouse is moved off of menu item 
     472                // summary: 
     473                //              Callback when mouse is moved off of menu item, 
     474                //              possibly to a child menu, or maybe to a sibling 
     475                //              menuitem or somewhere else entirely. 
    436476 
    437477                // if we are unhovering the currently selected item 
    438478                // then unselect it 
     479                dojo.removeClass(this.domNode, 'dijitMenuItemHover'); 
    439480                this.getParent().onItemUnhover(this); 
    440481        }, 
     
    450491 
    451492        focus: function(){ 
    452                 dojo.addClass(this.domNode, 'dijitMenuItemHover'); 
     493                // summary: 
     494                //              Focus on this MenuItem 
    453495                try{ 
    454496                        dijit.focus(this.focusNode); 
     
    458500        }, 
    459501 
    460         _blur: function(){ 
    461                 dojo.removeClass(this.domNode, 'dijitMenuItemHover'); 
     502        _onFocus: function(){ 
     503                this._setSelected(true); 
     504        }, 
     505 
     506        _setSelected: function(selected){ 
     507                // summary: 
     508                //              Indicate that this node is the currently selected one 
     509 
     510                /*** 
     511                 * TODO: remove this method and calls to it, when _onBlur() is working for MenuItem. 
     512                 * Currently _onBlur() gets called when focus is moved from the MenuItem to a child menu. 
     513                 * That's not supposed to happen, but the problem is: 
     514                 * In order to allow dijit.popup's getTopPopup()  work,a sub menu's popupParent 
     515                 * points to the parent Menu, bypassing the parent MenuItem... thus the 
     516                 * MenuItem is not in the chain of active widgets and gets a premature call to 
     517                 * _onBlur() 
     518                 */ 
     519                 
     520                dojo.toggleClass(this.domNode, "dijitMenuItemSelected", selected); 
    462521        }, 
    463522 
  • dijit/trunk/MenuBar.js

    r16188 r16233  
    77        //              A menu bar, listing menu choices horizontally, like the "File" menu in most desktop applications 
    88 
    9         templateString: '<div class="dijitMenuBar" dojoAttachPoint="containerNode"  tabIndex="${tabIndex}" dojoAttachEvent="onkeypress: _onKeyPress"></div>', 
     9        templateString: '<div class="dijitMenuBar dijitMenuPassive" dojoAttachPoint="containerNode"  tabIndex="${tabIndex}" dojoAttachEvent="onkeypress: _onKeyPress"></div>', 
    1010 
    1111        _isMenuBar: true, 
  • dijit/trunk/tests/test_Menu.html

    r16168 r16233  
    9191        } 
    9292        dojo.addOnLoad(function(){ 
    93             // need to explicitly update our buttons states, otherwise the  
    94             // browser will remember the last states of them before reloading  
    95             // (so a programmatic menu is created, reload, and "the create  
    96             // programmatic menu" button is still in disabled state) 
    97             updateButtons(false); 
     93                // need to explicitly update our buttons states, otherwise the  
     94                // browser will remember the last states of them before reloading  
     95                // (so a programmatic menu is created, reload, and "the create  
     96                // programmatic menu" button is still in disabled state) 
     97                updateButtons(false); 
    9898        }); 
    9999    </script> 
     
    192192                                        <div dojoType="dijit.MenuBarItem"> 
    193193                                                <span>File</span> 
    194                                                 <div dojoType="dijit.Menu"> 
     194                                                <div dojoType="dijit.Menu" id="fileMenu"> 
    195195                                                        <div dojoType="dijit.MenuItem">New</div> 
    196196                                                        <div dojoType="dijit.MenuItem">Open</div> 
     
    202202                                        <div dojoType="dijit.MenuBarItem"> 
    203203                                                <span>Edit</span> 
    204                                                 <div dojoType="dijit.Menu"> 
     204                                                <div dojoType="dijit.Menu" id="editMenu"> 
    205205                                                        <div dojoType="dijit.MenuItem"  iconClass="dijitEditorIcon dijitEditorIconCut" 
    206206                                                                onClick="console.log('not actually cutting anything, just a test!')">Cut</div> 
     
    213213                                        <div dojoType="dijit.MenuBarItem"> 
    214214                                                <span>View</span> 
    215                                                 <div dojoType="dijit.Menu"> 
     215                                                <div dojoType="dijit.Menu" id="viewMenu"> 
    216216                                                        <div dojoType="dijit.MenuItem">Normal</div> 
    217217                                                        <div dojoType="dijit.MenuItem">Outline</div> 
    218218                                                        <div dojoType="dijit.PopupMenuItem"> 
    219219                                                                <span>Zoom</span> 
    220                                                                 <div dojoType="dijit.Menu" id="menuBarSub1"> 
     220                                                                <div dojoType="dijit.Menu" id="zoomMenu"> 
    221221                                                                        <div dojoType="dijit.MenuItem">50%</div> 
    222222                                                                        <div dojoType="dijit.MenuItem">75%</div> 
     
    230230                                        <div dojoType="dijit.MenuBarItem"> 
    231231                                                <span>Help</span> 
    232                                                 <div dojoType="dijit.Menu"> 
     232                                                <div dojoType="dijit.Menu" id="helpMenu"> 
    233233                                                        <div dojoType="dijit.MenuItem">Help Topics</div> 
    234234                                                        <div dojoType="dijit.MenuItem">About Dijit</div> 
     
    295295                                        <li>left click context menu (left click on input on far right) 
    296296                                        <li>Example of programatically created menu 
    297                                         <li>Note: while some accelerator (shortcut) keys are displayed in the context menu, they are not actually hooked up to the corresponding actions (if any), they need to be setup explicitly by the user explicitly 
     297                                        <li>Note: while some accelerator (shortcut) keys are displayed in the context menu, they are not actually hooked up to the corresponding actions (if any), they need to be setup explicitly by the user 
    298298                                </ul> 
    299299                 
  • dijit/trunk/themes/dijit.css

    r16216 r16233  
    983983} 
    984984 
    985 .dijitMenuItemHover { 
     985.dijitMenuPassive .dijitMenuItemHover, 
     986.dijitMenuItemSelected { 
     987        /* 
     988         * dijitMenuItemHover refers to actual mouse over 
     989         * dijitMenuItemSelected is used after a menu has been "activated" by 
     990         * clicking it, tabbing into it, or being opened from a parent menu, 
     991         * and denotes that the menu item has focus or that focus is on a child 
     992         * menu 
     993         */ 
    986994        background-color:black; 
    987995        color:white; 
     
    10111019} 
    10121020 
    1013 .dijit_a11y .dijitMenuItemHover .dijitMenuItemLabel { 
     1021.dijit_a11y .dijitMenuItemSelected .dijitMenuItemLabel { 
    10141022        border-width: 1px; 
    10151023        border-style: solid; 
    10161024} 
    1017 .dijit_a11y .dijitMenuItemHover { 
     1025.dijit_a11y .dijitMenuItemSelected { 
    10181026        border: 1px #fff dotted !important; 
    10191027} 
  • dijit/trunk/themes/nihilo/Menu.css

    r16141 r16233  
    2525} 
    2626 
    27 .nihilo .dijitMenuItemHover { 
     27.nihilo .dijitMenuPassive .dijitMenuItemHover, 
     28.nihilo .dijitMenuItemSelected { 
    2829        background-color: #ffe284; /* #95a0b0; #555555; #aaaaaa; #646464;  #60a1ea; #848484; */ 
    2930        color: #243C5F; 
     
    6970.nihilo .dijitCheckedMenuItemIcon { 
    7071        background-image: url('images/spriteCheckbox.gif'); 
    71         background-position: -16px; 
     72        background-position: -80px; 
    7273} 
    7374 
    7475.nihilo .dijitCheckedMenuItemIconChecked { 
    75         background-position: 0px; 
    76 } 
    77  
    78 .nihilo .dijitMenuItemHover .dijitCheckedMenuItemIcon { 
    79         background-position: -80px; 
    80 } 
    81  
    82 .nihilo .dijitMenuItemHover .dijitCheckedMenuItemIconChecked { 
    8376        background-position: -64px; 
    8477} 
  • dijit/trunk/themes/soria/Menu.css

    r16141 r16233  
    2525} 
    2626 
    27 .soria .dijitMenuItemHover { 
     27.soria .dijitMenuPassive .dijitMenuItemHover, 
     28.soria .dijitMenuItemSelected { 
    2829        background-color: #d9e6f9; /* #95a0b0; #555555; #aaaaaa; #646464;  #60a1ea; #848484; */ 
    2930        color: #243C5F; 
     
    6970.soria .dijitCheckedMenuItemIcon { 
    7071        background-image: url('images/spriteCheckbox.gif'); 
    71         background-position: -16px; 
     72        background-position: -80px; 
    7273} 
    7374 
    7475.soria .dijitCheckedMenuItemIconChecked { 
    75         background-position: 0px; 
    76 } 
    77  
    78 .soria .dijitMenuItemHover .dijitCheckedMenuItemIcon { 
    79         background-position: -80px; 
    80 } 
    81  
    82 .soria .dijitMenuItemHover .dijitCheckedMenuItemIconChecked { 
    8376        background-position: -64px; 
    8477} 
  • dijit/trunk/themes/tundra/Menu.css

    r16141 r16233  
    2424} 
    2525 
    26 .tundra .dijitMenuItemHover { 
     26.tundra .dijitMenuPassive .dijitMenuItemHover, 
     27.tundra .dijitMenuItemSelected { 
    2728        background-color: #3559ac; 
    2829        color:#fff; 
     
    6364.tundra .dijitCheckedMenuItemIcon { 
    6465        background-image: url('images/checkmark.png'); 
    65         background-position: -16px; 
     66        background-position: -80px; 
    6667} 
    6768 
     
    7475} 
    7576 
    76 .tundra .dijitMenuItemHover .dijitCheckedMenuItemIcon { 
    77         background-position: -80px; 
    78 } 
    79  
    80 .tundra .dijitMenuItemHover .dijitCheckedMenuItemIconChecked { 
     77.tundra .dijitCheckedMenuItemIconChecked { 
    8178        background-position: -64px; 
    8279}