r2780 - updated and abstracted out focus and selection methods, which also fixes keyboard events ...

r2780 - updated and abstracted out focus and selection methods, which also fixes keyboard events ...


Author: scottjehl
Date: Tue Jun 16 10:20:41 2009
New Revision: 2780
Modified:
branches/labs/selectmenu/ui.selectmenu.js
Log:
updated and abstracted out focus and selection methods, which also fixes
keyboard events within optgroups
Modified: branches/labs/selectmenu/ui.selectmenu.js
==============================================================================
--- branches/labs/selectmenu/ui.selectmenu.js    (original)
+++ branches/labs/selectmenu/ui.selectmenu.js    Tue Jun 16 10:20:41 2009
@@ -44,60 +44,61 @@
        //click toggle for menu visibility
        this.newelement
-        .bind('mousedown', function(){
-            self._toggle();
-            //make sure a click won't open/close instantly
-            if(o.style == "popup"){
-                self._safemouseup = false;
-                setTimeout(function(){self._safemouseup = true;}, 500);
-            }    
-            return false;
-        })
-        .bind('click',function(){
-            return false;
-        })
-        .keydown(function(event){
-            var ret = true;
-            switch (event.keyCode) {
-                case $.ui.keyCode.ENTER:
-                case $.ui.keyCode.SPACE:
-                    ret = false;
-                    self._toggle();    
-                    break;
-                case $.ui.keyCode.UP:
-                case $.ui.keyCode.LEFT:
-                    ret = false;
-                    
self.list.find('li.ui-selectmenu-item-selected').prev().trigger('mouseup');    
-                    break;
-                case $.ui.keyCode.DOWN:
-                case $.ui.keyCode.RIGHT:
-                    ret = false;
-                    
self.list.find('li.ui-selectmenu-item-selected').next().trigger('mouseup');    
-                    break;    
-                case $.ui.keyCode.TAB:
-                    ret = true;
-                    break;    
-                default:
-                    ret = false;
-                    self._typeAhead(event.keyCode, 'mouseup');
-                    break;    
-            }
-            return ret;
-        })
-        .bind('mouseover focus', function(){
$(this).addClass('ui-selectmenu-focus ui-state-hover'); })
-        .bind('mouseout blur', function(){
-            $(this).removeClass('ui-selectmenu-focus ui-state-hover');
-        });
+            .bind('mousedown', function(){
+                self._toggle();
+                //make sure a click won't open/close instantly
+                if(o.style == "popup"){
+                    self._safemouseup = false;
+                    setTimeout(function(){self._safemouseup = true;}, 500);
+                }    
+                return false;
+            })
+            .bind('click',function(){
+                return false;
+            })
+            .keydown(function(event){
+                var ret = true;
+                switch (event.keyCode) {
+                    case $.ui.keyCode.ENTER:
+                    case $.ui.keyCode.SPACE:
+                        ret = false;
+                        self._toggle();    
+                        break;
+                    case $.ui.keyCode.UP:
+                    case $.ui.keyCode.LEFT:
+                        ret = false;
+                        self._moveSelection(-1);
+                        break;
+                    case $.ui.keyCode.DOWN:
+                    case $.ui.keyCode.RIGHT:
+                        ret = false;
+                        self._moveSelection(1);
+                        break;    
+                    case $.ui.keyCode.TAB:
+                        ret = true;
+                        break;    
+                    default:
+                        ret = false;
+                        self._typeAhead(event.keyCode, 'mouseup');
+                        break;    
+                }
+                return ret;
+            })
+            .bind('mouseover focus', function(){
$(this).addClass('ui-selectmenu-focus ui-state-hover'); })
+            .bind('mouseout blur', function(){
+                $(this).removeClass('ui-selectmenu-focus ui-state-hover');
+            });
        
        //document click closes menu
-        $(document).mousedown(function(){
-            self.close();
-        });
+        $(document)
+            .mousedown(function(){
+                self.close();
+            });
        //change event on original selectmenu
-            this.element
-                .click(function(){ this._refreshValue(); })
-                .focus(function(){ this.newelement.focus(); });
+        this.element
+            .click(function(){ this._refreshValue(); })
+            .focus(function(){ this.newelement.focus(); });
        
        
        //create menu portion, append to body
@@ -202,6 +203,9 @@
        if(o.maxHeight && o.maxHeight < this.list.height()){
            this.list.height(o.maxHeight);
        }    
+        
+        //save reference to actionable li's (not group label li's)
+        this._optionLis = this.list.find('li:not(.ui-selectmenu-group)');
                
        //transfer menu click to menu button
        this.list
@@ -212,33 +216,28 @@
                case $.ui.keyCode.UP:
                case $.ui.keyCode.LEFT:
                    ret = false;
-                    if($(event.target).parents('li:eq(0)').prev().size()>0){
-                        
$(event.target).blur().parents('li:eq(0)').prev().find('a:eq(0)').focus();
-                    }    
+                    self._moveFocus(-1);
                    break;
                case $.ui.keyCode.DOWN:
                case $.ui.keyCode.RIGHT:
                    ret = false;
-                    if($(event.target).parents('li:eq(0)').next().size()>0){
-                        
$(event.target).blur().parents('li:eq(0)').next().find('a:eq(0)').focus();
-                    }    
+                    self._moveFocus(1);
                    break;    
                case $.ui.keyCode.HOME:
-                    $(event.target).blur();
-                    self.list.find('a:first').focus();
+                    ret = false;
+                    self._moveFocus(':first');
                    break;    
                case $.ui.keyCode.PAGE_UP:
                    ret = false;
-                    self._scrollPage(event.target, 'up');
+                    self._scrollPage('up');
                    break;    
                case $.ui.keyCode.PAGE_DOWN:
                    ret = false;
-                    self._scrollPage(event.target, 'down');
+                    self._scrollPage('down');
                    break;
                case $.ui.keyCode.END:
                    ret = false;
-                    $(event.target).blur();
-                    self.list.find('a:last').focus();
+                    self._moveFocus(':last');
                    break;            
                case $.ui.keyCode.ENTER:
                case $.ui.keyCode.SPACE:
@@ -379,24 +378,10 @@
        return newText;
    },
    
-    _scrollPage: function(curTarget,direction){
-        var numPerPage = Math.floor(this.list.outerHeight() /
this.list.find('li:first').outerHeight());
-        var currentIndex = parseInt(
$(curTarget).parents('li:eq(0)').data('index') );
-        var nextIndex = (direction == 'up') ? currentIndex - numPerPage :
currentIndex + numPerPage;
-        nextIndex = ':eq('+nextIndex+')';
-        if(this.list.find('li' + nextIndex).size() < 1){
-            nextIndex = (direction == 'up') ? ':first' : ':last';
-        }
-        this.list.find('li' + nextIndex + ' a').focus();
-    },
-    
-    _selectedIndex: function(){
-        return this.element[0].selectedIndex;
-    },
-    
    _selectOptions: function(){
        var opts = [];
        var self = this;
+        //this should use map
        this.element.find('option').each(function(i){
            opts.push({
                value: jQuery(this).attr('value'),
@@ -407,6 +392,45 @@
            });
        });
        return opts;
+    },
+        
+    _selectedIndex: function(){
+        return this.element[0].selectedIndex;
+    },
+    
+    _selectedOptionLi: function(){
+        return this._optionLis.eq(this._selectedIndex());
+    },
+    
+    _focusedOptionLi: function(){
+        return this.list.find('.ui-selectmenu-item-focus');
+    },
+    
+    _moveSelection: function(amt){
+        var currIndex = parseInt(this._selectedOptionLi().data('index'), 10);
+        var newIndex = currIndex + amt;
+        return this._optionLis.eq(newIndex).trigger('mouseup');
+    },
+    
+    _moveFocus: function(amt){
+        if(!isNaN(amt)){
+            var currIndex = parseInt(this._focusedOptionLi().data('index'), 10);
+            var newIndex = currIndex + amt;
+        }
+        else { var newIndex =
parseInt(this._optionLis.filter(amt).data('index'), 10); }
+        
+        if(newIndex < 0){ newIndex = 0; }
+        if(newIndex > this._optionLis.size()-1){
+            newIndex = this._optionLis.size()-1;
+        }
+        this._focusedOptionLi().find('a:eq(0)').blur();
+        this._optionLis.eq(newIndex).find('a:eq(0)').focus();
+    },
+    
+    _scrollPage: function(direction){
+        var numPerPage = Math.floor(this.list.outerHeight() /
this.list.find('li:first').outerHeight());
+        numPerPage = (direction == 'up') ? -numPerPage : numPerPage;
+        this._moveFocus(numPerPage);
    },
    
    _change: function(event, index) {