Support wrapping selection index with keyboard
diff --git a/bundles/org.eclipse.rap.addons.dropdown/js/rwt/dropdown/DropDown.js b/bundles/org.eclipse.rap.addons.dropdown/js/rwt/dropdown/DropDown.js
index 8dd8b89..1c5cc54 100644
--- a/bundles/org.eclipse.rap.addons.dropdown/js/rwt/dropdown/DropDown.js
+++ b/bundles/org.eclipse.rap.addons.dropdown/js/rwt/dropdown/DropDown.js
@@ -107,12 +107,19 @@
       if( index < -1 || index >= this.getItemCount() || isNaN( index ) ) {
         throw new Error( "Can not select item: Index " + index + " not valid" );
       }
+      // This is more than optimization, it prevents too early rendering that can crash the client:
+      this._.viewer._inServerResponse = rwt.util.Functions.returnTrue;
       this._.viewer.deselectAll();
       if( index > -1 ) {
         var item = this._.viewer.getRootItem().getChild( index );
         this._.viewer.selectItem( item );
         this._.viewer.setFocusItem( item );
+        this._.viewer._scrollIntoView( index, item );
+      } else {
+        this._.viewer.setFocusItem( null );
+        this._.viewer.setTopItemIndex( 0 );
       }
+      delete this._.viewer._inServerResponse;
       this._.viewer._sendSelectionChange(); // Not called for selection changes by API/Server
     },
 
@@ -305,12 +312,14 @@
   var renderGridItems = function() {
     var rootItem = this._.viewer.getRootItem();
     var items = this._.items;
+    this._.viewer._inServerResponse = rwt.util.Functions.returnTrue;
     rootItem.setItemCount( 0 );
     rootItem.setItemCount( items.length );
     for( var i = 0; i < items.length; i++ ) {
       var gridItem = new rwt.widgets.GridItem( rootItem, i, false );
       gridItem.setTexts( [ items[ i ] ] );
     }
+    delete this._.viewer._inServerResponse;
   };
 
   var onTextAppear = function() {
@@ -325,6 +334,12 @@
       event.preventDefault();
       if( key === "Down" && this.getSelectionIndex() === -1 && this.getItemCount() > 0 ) {
         this.setSelectionIndex( 0 );
+      } else if( key === "Up" && this.getSelectionIndex() === 0 ) {
+        this.setSelectionIndex( -1 );
+      } else if( key === "Down" && this.getSelectionIndex() === this.getItemCount() - 1 ) {
+        this.setSelectionIndex( -1 );
+      } else if( key === "Up" && this.getSelectionIndex() === -1 && this.getItemCount() > 0 ) {
+        this.setSelectionIndex( this.getItemCount() - 1 );
       } else {
         this._.viewer.dispatchEvent( event );
       }
diff --git a/tests/org.eclipse.rap.addons.dropdown.test/js/rwt/dropdown/DropDown_Test.js b/tests/org.eclipse.rap.addons.dropdown.test/js/rwt/dropdown/DropDown_Test.js
index 17411ff..a579054 100644
--- a/tests/org.eclipse.rap.addons.dropdown.test/js/rwt/dropdown/DropDown_Test.js
+++ b/tests/org.eclipse.rap.addons.dropdown.test/js/rwt/dropdown/DropDown_Test.js
@@ -676,6 +676,27 @@
       assertEquals( 1, dropdown.getSelectionIndex() );
     },
 
+    testSetSelectionIndex_ScrollToSelection : function() {
+      dropdown.setVisibleItemCount( 3 );
+      showDropDown();
+      dropdown.setItems( [ "a", "b", "c", "d", "e", "f" ] );
+
+      dropdown.setSelectionIndex( 5 );
+
+      assertEquals( 3, viewer.getTopItemIndex() );
+    },
+
+    testResetSelectionIndex_ResetScrollPosition : function() {
+      dropdown.setVisibleItemCount( 3 );
+      showDropDown();
+      dropdown.setItems( [ "a", "b", "c", "d", "e", "f" ] );
+      dropdown.setSelectionIndex( 5 );
+
+      dropdown.setSelectionIndex( -1 );
+
+      assertEquals( 0, viewer.getTopItemIndex() );
+    },
+
     testSetSelectionIndex_RemoteSet : function() {
       dropdown.setItems( [ "a", "b", "c" ] );
 
@@ -754,6 +775,8 @@
     },
 
     testKeyEventForwarding_Down : function() {
+      dropdown.setItems( [ "a", "b", "c" ] );
+      dropdown.setSelectionIndex( 1 );
       showDropDown();
       var logger = TestUtil.getLogger();
 
@@ -766,6 +789,8 @@
     },
 
     testKeyEventForwarding_PageUp : function() {
+      dropdown.setItems( [ "a", "b", "c" ] );
+      dropdown.setSelectionIndex( 1 );
       showDropDown();
       var logger = TestUtil.getLogger();
 
@@ -778,6 +803,8 @@
     },
 
     testKeyEventForwarding_PageDown : function() {
+      dropdown.setItems( [ "a", "b", "c" ] );
+      dropdown.setSelectionIndex( 1 );
       showDropDown();
       var logger = TestUtil.getLogger();
 
@@ -815,6 +842,54 @@
       assertTrue( viewer.isFocusItem( viewer.getRootItem().getChild( 0 ) ) );
     },
 
+    testPressUpAfterSelectionResetsSelectsLastItem : function() {
+      dropdown.setItems( [ "a", "b", "c" ] );
+      showDropDown();
+      dropdown.setSelectionIndex( -1 );
+      TestUtil.flush();
+
+      widget.focus();
+      TestUtil.pressOnce( widget, "Up" );
+
+      assertEquals( 2, dropdown.getSelectionIndex() );
+    },
+
+    testPressUpAfterSelectionFirstItemResetsFocus : function() {
+      dropdown.setItems( [ "a", "b", "c" ] );
+      showDropDown();
+      TestUtil.flush();
+
+      widget.focus();
+      TestUtil.pressOnce( widget, "Down" );
+      TestUtil.pressOnce( widget, "Up" );
+
+      assertFalse( viewer.isFocusItem( viewer.getRootItem().getChild( 0 ) ) );
+    },
+
+    testPressUpOnFirstItemResetsSelection : function() {
+      dropdown.setItems( [ "a", "b", "c" ] );
+      dropdown.setSelectionIndex( 0 );
+      showDropDown();
+      TestUtil.flush();
+
+      widget.focus();
+      TestUtil.pressOnce( widget, "Up" );
+
+      assertEquals( -1, dropdown.getSelectionIndex() );
+    },
+
+    testPressDownOnLastItemResetsSelection : function() {
+      dropdown.setItems( [ "a", "b", "c" ] );
+      dropdown.setSelectionIndex( 2 );
+      showDropDown();
+      TestUtil.flush();
+
+      widget.focus();
+      TestUtil.pressOnce( widget, "Down" );
+
+      assertEquals( -1, dropdown.getSelectionIndex() );
+    },
+
     testSelectionResetResetsLeadItem : function() {
       dropdown.setItems( [ "a", "b", "c" ] );
       showDropDown();