Browse Source

Add more keyboard support

When the main container is focused, you can now move the highlighted
result by using the up and down arrows on the keyboard.

This does not yet keep the highlighted result visible at all times,
and it only is implemented on single selects, but that will come in
the future.
Kevin Brown 10 years ago
parent
commit
8dfd6d6960

+ 57 - 0
dist/js/select2.amd.full.js

@@ -305,6 +305,10 @@ define('select2/results',[
     container.on('results:select', function () {
     container.on('results:select', function () {
       var $highlighted = self.$results.find('.highlighted');
       var $highlighted = self.$results.find('.highlighted');
 
 
+      if ($highlighted.length === 0) {
+        return;
+      }
+
       var data = $highlighted.data('data');
       var data = $highlighted.data('data');
 
 
       if ($highlighted.attr('aria-selected') == 'true') {
       if ($highlighted.attr('aria-selected') == 'true') {
@@ -318,6 +322,49 @@ define('select2/results',[
       }
       }
     });
     });
 
 
+    container.on('results:previous', function () {
+      var $highlighted = self.$results.find('.highlighted');
+
+      var $options = self.$results.find('[aria-selected]');
+
+      var currentIndex = $options.index($highlighted);
+
+      // If we are already at te top, don't move further
+      if (currentIndex === 0) {
+        return;
+      }
+
+      var nextIndex = currentIndex - 1;
+
+      // If none are highlighted, highlight the first
+      if ($highlighted.length === 0) {
+        nextIndex = 0;
+      }
+
+      var $next = $options.eq(nextIndex);
+
+      $next.trigger('mouseenter');
+    });
+
+    container.on('results:next', function () {
+      var $highlighted = self.$results.find('.highlighted');
+
+      var $options = self.$results.find('[aria-selected]');
+
+      var currentIndex = $options.index($highlighted);
+
+      var nextIndex = currentIndex + 1;
+
+      // If we are at the last option, stay there
+      if (nextIndex >= $options.length) {
+        return;
+      }
+
+      var $next = $options.eq(nextIndex);
+
+      $next.trigger('mouseenter');
+    });
+
     this.$results.on('mouseup', '.option[aria-selected]', function (evt) {
     this.$results.on('mouseup', '.option[aria-selected]', function (evt) {
       var $this = $(this);
       var $this = $(this);
 
 
@@ -477,6 +524,10 @@ define('select2/selection/single',[
       if (container.isOpen()) {
       if (container.isOpen()) {
         if (key == KEYS.ENTER) {
         if (key == KEYS.ENTER) {
           self.trigger('results:select');
           self.trigger('results:select');
+        } else if (key == KEYS.UP) {
+          self.trigger('results:previous');
+        } else if (key == KEYS.DOWN) {
+          self.trigger('results:next');
         }
         }
       } else {
       } else {
         if (key == KEYS.ENTER || key == KEYS.SPACE) {
         if (key == KEYS.ENTER || key == KEYS.SPACE) {
@@ -1239,6 +1290,12 @@ define('select2/core',[
     this.selection.on('results:select', function () {
     this.selection.on('results:select', function () {
       self.trigger('results:select');
       self.trigger('results:select');
     });
     });
+    this.selection.on('results:previous', function () {
+      self.trigger('results:previous');
+    });
+    this.selection.on('results:next', function () {
+      self.trigger('results:next');
+    });
 
 
     this.selection.on('unselected', function (params) {
     this.selection.on('unselected', function (params) {
       self.trigger('unselect', params);
       self.trigger('unselect', params);

+ 57 - 0
dist/js/select2.amd.js

@@ -305,6 +305,10 @@ define('select2/results',[
     container.on('results:select', function () {
     container.on('results:select', function () {
       var $highlighted = self.$results.find('.highlighted');
       var $highlighted = self.$results.find('.highlighted');
 
 
+      if ($highlighted.length === 0) {
+        return;
+      }
+
       var data = $highlighted.data('data');
       var data = $highlighted.data('data');
 
 
       if ($highlighted.attr('aria-selected') == 'true') {
       if ($highlighted.attr('aria-selected') == 'true') {
@@ -318,6 +322,49 @@ define('select2/results',[
       }
       }
     });
     });
 
 
+    container.on('results:previous', function () {
+      var $highlighted = self.$results.find('.highlighted');
+
+      var $options = self.$results.find('[aria-selected]');
+
+      var currentIndex = $options.index($highlighted);
+
+      // If we are already at te top, don't move further
+      if (currentIndex === 0) {
+        return;
+      }
+
+      var nextIndex = currentIndex - 1;
+
+      // If none are highlighted, highlight the first
+      if ($highlighted.length === 0) {
+        nextIndex = 0;
+      }
+
+      var $next = $options.eq(nextIndex);
+
+      $next.trigger('mouseenter');
+    });
+
+    container.on('results:next', function () {
+      var $highlighted = self.$results.find('.highlighted');
+
+      var $options = self.$results.find('[aria-selected]');
+
+      var currentIndex = $options.index($highlighted);
+
+      var nextIndex = currentIndex + 1;
+
+      // If we are at the last option, stay there
+      if (nextIndex >= $options.length) {
+        return;
+      }
+
+      var $next = $options.eq(nextIndex);
+
+      $next.trigger('mouseenter');
+    });
+
     this.$results.on('mouseup', '.option[aria-selected]', function (evt) {
     this.$results.on('mouseup', '.option[aria-selected]', function (evt) {
       var $this = $(this);
       var $this = $(this);
 
 
@@ -477,6 +524,10 @@ define('select2/selection/single',[
       if (container.isOpen()) {
       if (container.isOpen()) {
         if (key == KEYS.ENTER) {
         if (key == KEYS.ENTER) {
           self.trigger('results:select');
           self.trigger('results:select');
+        } else if (key == KEYS.UP) {
+          self.trigger('results:previous');
+        } else if (key == KEYS.DOWN) {
+          self.trigger('results:next');
         }
         }
       } else {
       } else {
         if (key == KEYS.ENTER || key == KEYS.SPACE) {
         if (key == KEYS.ENTER || key == KEYS.SPACE) {
@@ -1239,6 +1290,12 @@ define('select2/core',[
     this.selection.on('results:select', function () {
     this.selection.on('results:select', function () {
       self.trigger('results:select');
       self.trigger('results:select');
     });
     });
+    this.selection.on('results:previous', function () {
+      self.trigger('results:previous');
+    });
+    this.selection.on('results:next', function () {
+      self.trigger('results:next');
+    });
 
 
     this.selection.on('unselected', function (params) {
     this.selection.on('unselected', function (params) {
       self.trigger('unselect', params);
       self.trigger('unselect', params);

+ 57 - 0
dist/js/select2.full.js

@@ -9843,6 +9843,10 @@ define('select2/results',[
     container.on('results:select', function () {
     container.on('results:select', function () {
       var $highlighted = self.$results.find('.highlighted');
       var $highlighted = self.$results.find('.highlighted');
 
 
+      if ($highlighted.length === 0) {
+        return;
+      }
+
       var data = $highlighted.data('data');
       var data = $highlighted.data('data');
 
 
       if ($highlighted.attr('aria-selected') == 'true') {
       if ($highlighted.attr('aria-selected') == 'true') {
@@ -9856,6 +9860,49 @@ define('select2/results',[
       }
       }
     });
     });
 
 
+    container.on('results:previous', function () {
+      var $highlighted = self.$results.find('.highlighted');
+
+      var $options = self.$results.find('[aria-selected]');
+
+      var currentIndex = $options.index($highlighted);
+
+      // If we are already at te top, don't move further
+      if (currentIndex === 0) {
+        return;
+      }
+
+      var nextIndex = currentIndex - 1;
+
+      // If none are highlighted, highlight the first
+      if ($highlighted.length === 0) {
+        nextIndex = 0;
+      }
+
+      var $next = $options.eq(nextIndex);
+
+      $next.trigger('mouseenter');
+    });
+
+    container.on('results:next', function () {
+      var $highlighted = self.$results.find('.highlighted');
+
+      var $options = self.$results.find('[aria-selected]');
+
+      var currentIndex = $options.index($highlighted);
+
+      var nextIndex = currentIndex + 1;
+
+      // If we are at the last option, stay there
+      if (nextIndex >= $options.length) {
+        return;
+      }
+
+      var $next = $options.eq(nextIndex);
+
+      $next.trigger('mouseenter');
+    });
+
     this.$results.on('mouseup', '.option[aria-selected]', function (evt) {
     this.$results.on('mouseup', '.option[aria-selected]', function (evt) {
       var $this = $(this);
       var $this = $(this);
 
 
@@ -10015,6 +10062,10 @@ define('select2/selection/single',[
       if (container.isOpen()) {
       if (container.isOpen()) {
         if (key == KEYS.ENTER) {
         if (key == KEYS.ENTER) {
           self.trigger('results:select');
           self.trigger('results:select');
+        } else if (key == KEYS.UP) {
+          self.trigger('results:previous');
+        } else if (key == KEYS.DOWN) {
+          self.trigger('results:next');
         }
         }
       } else {
       } else {
         if (key == KEYS.ENTER || key == KEYS.SPACE) {
         if (key == KEYS.ENTER || key == KEYS.SPACE) {
@@ -10777,6 +10828,12 @@ define('select2/core',[
     this.selection.on('results:select', function () {
     this.selection.on('results:select', function () {
       self.trigger('results:select');
       self.trigger('results:select');
     });
     });
+    this.selection.on('results:previous', function () {
+      self.trigger('results:previous');
+    });
+    this.selection.on('results:next', function () {
+      self.trigger('results:next');
+    });
 
 
     this.selection.on('unselected', function (params) {
     this.selection.on('unselected', function (params) {
       self.trigger('unselect', params);
       self.trigger('unselect', params);

File diff suppressed because it is too large
+ 0 - 0
dist/js/select2.full.min.js


+ 57 - 0
dist/js/select2.js

@@ -734,6 +734,10 @@ define('select2/results',[
     container.on('results:select', function () {
     container.on('results:select', function () {
       var $highlighted = self.$results.find('.highlighted');
       var $highlighted = self.$results.find('.highlighted');
 
 
+      if ($highlighted.length === 0) {
+        return;
+      }
+
       var data = $highlighted.data('data');
       var data = $highlighted.data('data');
 
 
       if ($highlighted.attr('aria-selected') == 'true') {
       if ($highlighted.attr('aria-selected') == 'true') {
@@ -747,6 +751,49 @@ define('select2/results',[
       }
       }
     });
     });
 
 
+    container.on('results:previous', function () {
+      var $highlighted = self.$results.find('.highlighted');
+
+      var $options = self.$results.find('[aria-selected]');
+
+      var currentIndex = $options.index($highlighted);
+
+      // If we are already at te top, don't move further
+      if (currentIndex === 0) {
+        return;
+      }
+
+      var nextIndex = currentIndex - 1;
+
+      // If none are highlighted, highlight the first
+      if ($highlighted.length === 0) {
+        nextIndex = 0;
+      }
+
+      var $next = $options.eq(nextIndex);
+
+      $next.trigger('mouseenter');
+    });
+
+    container.on('results:next', function () {
+      var $highlighted = self.$results.find('.highlighted');
+
+      var $options = self.$results.find('[aria-selected]');
+
+      var currentIndex = $options.index($highlighted);
+
+      var nextIndex = currentIndex + 1;
+
+      // If we are at the last option, stay there
+      if (nextIndex >= $options.length) {
+        return;
+      }
+
+      var $next = $options.eq(nextIndex);
+
+      $next.trigger('mouseenter');
+    });
+
     this.$results.on('mouseup', '.option[aria-selected]', function (evt) {
     this.$results.on('mouseup', '.option[aria-selected]', function (evt) {
       var $this = $(this);
       var $this = $(this);
 
 
@@ -906,6 +953,10 @@ define('select2/selection/single',[
       if (container.isOpen()) {
       if (container.isOpen()) {
         if (key == KEYS.ENTER) {
         if (key == KEYS.ENTER) {
           self.trigger('results:select');
           self.trigger('results:select');
+        } else if (key == KEYS.UP) {
+          self.trigger('results:previous');
+        } else if (key == KEYS.DOWN) {
+          self.trigger('results:next');
         }
         }
       } else {
       } else {
         if (key == KEYS.ENTER || key == KEYS.SPACE) {
         if (key == KEYS.ENTER || key == KEYS.SPACE) {
@@ -1668,6 +1719,12 @@ define('select2/core',[
     this.selection.on('results:select', function () {
     this.selection.on('results:select', function () {
       self.trigger('results:select');
       self.trigger('results:select');
     });
     });
+    this.selection.on('results:previous', function () {
+      self.trigger('results:previous');
+    });
+    this.selection.on('results:next', function () {
+      self.trigger('results:next');
+    });
 
 
     this.selection.on('unselected', function (params) {
     this.selection.on('unselected', function (params) {
       self.trigger('unselect', params);
       self.trigger('unselect', params);

File diff suppressed because it is too large
+ 0 - 0
dist/js/select2.min.js


+ 6 - 0
src/js/select2/core.js

@@ -81,6 +81,12 @@ define([
     this.selection.on('results:select', function () {
     this.selection.on('results:select', function () {
       self.trigger('results:select');
       self.trigger('results:select');
     });
     });
+    this.selection.on('results:previous', function () {
+      self.trigger('results:previous');
+    });
+    this.selection.on('results:next', function () {
+      self.trigger('results:next');
+    });
 
 
     this.selection.on('unselected', function (params) {
     this.selection.on('unselected', function (params) {
       self.trigger('unselect', params);
       self.trigger('unselect', params);

+ 47 - 0
src/js/select2/results.js

@@ -166,6 +166,10 @@ define([
     container.on('results:select', function () {
     container.on('results:select', function () {
       var $highlighted = self.$results.find('.highlighted');
       var $highlighted = self.$results.find('.highlighted');
 
 
+      if ($highlighted.length === 0) {
+        return;
+      }
+
       var data = $highlighted.data('data');
       var data = $highlighted.data('data');
 
 
       if ($highlighted.attr('aria-selected') == 'true') {
       if ($highlighted.attr('aria-selected') == 'true') {
@@ -179,6 +183,49 @@ define([
       }
       }
     });
     });
 
 
+    container.on('results:previous', function () {
+      var $highlighted = self.$results.find('.highlighted');
+
+      var $options = self.$results.find('[aria-selected]');
+
+      var currentIndex = $options.index($highlighted);
+
+      // If we are already at te top, don't move further
+      if (currentIndex === 0) {
+        return;
+      }
+
+      var nextIndex = currentIndex - 1;
+
+      // If none are highlighted, highlight the first
+      if ($highlighted.length === 0) {
+        nextIndex = 0;
+      }
+
+      var $next = $options.eq(nextIndex);
+
+      $next.trigger('mouseenter');
+    });
+
+    container.on('results:next', function () {
+      var $highlighted = self.$results.find('.highlighted');
+
+      var $options = self.$results.find('[aria-selected]');
+
+      var currentIndex = $options.index($highlighted);
+
+      var nextIndex = currentIndex + 1;
+
+      // If we are at the last option, stay there
+      if (nextIndex >= $options.length) {
+        return;
+      }
+
+      var $next = $options.eq(nextIndex);
+
+      $next.trigger('mouseenter');
+    });
+
     this.$results.on('mouseup', '.option[aria-selected]', function (evt) {
     this.$results.on('mouseup', '.option[aria-selected]', function (evt) {
       var $this = $(this);
       var $this = $(this);
 
 

+ 4 - 0
src/js/select2/selection/single.js

@@ -53,6 +53,10 @@ define([
       if (container.isOpen()) {
       if (container.isOpen()) {
         if (key == KEYS.ENTER) {
         if (key == KEYS.ENTER) {
           self.trigger('results:select');
           self.trigger('results:select');
+        } else if (key == KEYS.UP) {
+          self.trigger('results:previous');
+        } else if (key == KEYS.DOWN) {
+          self.trigger('results:next');
         }
         }
       } else {
       } else {
         if (key == KEYS.ENTER || key == KEYS.SPACE) {
         if (key == KEYS.ENTER || key == KEYS.SPACE) {

Some files were not shown because too many files changed in this diff