Browse Source

Better accessibility for results

Options are correctly called out as focus moves around the results
list.
Kevin Brown 10 years ago
parent
commit
7c8601d33b

+ 1 - 1
dist/css/select2.css

@@ -117,7 +117,7 @@
     display: block;
     display: block;
     padding: 6px; }
     padding: 6px; }
 .select2-container.select2-theme-default .dropdown .results .options .option[aria-disabled=true] {
 .select2-container.select2-theme-default .dropdown .results .options .option[aria-disabled=true] {
-  color: #666; }
+  color: #999; }
 .select2-container.select2-theme-default .dropdown .results .options .option[aria-selected=true] {
 .select2-container.select2-theme-default .dropdown .results .options .option[aria-selected=true] {
   background-color: #ddd; }
   background-color: #ddd; }
 .select2-container.select2-theme-default .dropdown .results .options .option[aria-selected].highlighted {
 .select2-container.select2-theme-default .dropdown .results .options .option[aria-selected].highlighted {

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


+ 43 - 4
dist/js/select2.amd.full.js

@@ -154,6 +154,7 @@ define('select2/results',[
   function Results ($element, options, dataAdapter) {
   function Results ($element, options, dataAdapter) {
     this.$element = $element;
     this.$element = $element;
     this.data = dataAdapter;
     this.data = dataAdapter;
+    this.options = options;
 
 
     Results.__super__.constructor.call(this);
     Results.__super__.constructor.call(this);
   }
   }
@@ -165,6 +166,10 @@ define('select2/results',[
       '<ul class="options" role="listbox"></ul>'
       '<ul class="options" role="listbox"></ul>'
     );
     );
 
 
+    if (this.options.get('multiple')) {
+      $results.attr('aria-multiselectable', 'true');
+    }
+
     this.$results = $results;
     this.$results = $results;
 
 
     return $results;
     return $results;
@@ -284,6 +289,10 @@ define('select2/results',[
   Results.prototype.bind = function (container, $container) {
   Results.prototype.bind = function (container, $container) {
     var self = this;
     var self = this;
 
 
+    var id = container.id + '-results';
+
+    this.$results.attr('id', id);
+
     container.on('results:all', function (params) {
     container.on('results:all', function (params) {
       self.clear();
       self.clear();
       self.append(params.data);
       self.append(params.data);
@@ -308,6 +317,7 @@ define('select2/results',[
     container.on('open', function () {
     container.on('open', function () {
       // When the dropdown is open, aria-expended="true"
       // When the dropdown is open, aria-expended="true"
       self.$results.attr('aria-expanded', 'true');
       self.$results.attr('aria-expanded', 'true');
+      self.$results.attr('aria-hidden', 'false');
 
 
       self.setClasses();
       self.setClasses();
     });
     });
@@ -315,6 +325,8 @@ define('select2/results',[
     container.on('close', function () {
     container.on('close', function () {
       // When the dropdown is closed, aria-expended="false"
       // When the dropdown is closed, aria-expended="false"
       self.$results.attr('aria-expanded', 'false');
       self.$results.attr('aria-expanded', 'false');
+      self.$results.attr('aria-hidden', 'true');
+      self.$results.removeAttr('aria-activedescendant');
     });
     });
 
 
     container.on('results:select', function () {
     container.on('results:select', function () {
@@ -401,6 +413,10 @@ define('select2/results',[
       }
       }
     });
     });
 
 
+    container.on('results:focus', function (params) {
+      params.element.addClass('highlighted');
+    });
+
     this.$results.on('mouseup', '.option[aria-selected]', function (evt) {
     this.$results.on('mouseup', '.option[aria-selected]', function (evt) {
       var $this = $(this);
       var $this = $(this);
 
 
@@ -422,12 +438,21 @@ define('select2/results',[
     });
     });
 
 
     this.$results.on('mouseenter', '.option[aria-selected]', function (evt) {
     this.$results.on('mouseenter', '.option[aria-selected]', function (evt) {
+      var data = $(this).data('data');
+
       self.$results.find('.option.highlighted').removeClass('highlighted');
       self.$results.find('.option.highlighted').removeClass('highlighted');
-      $(this).addClass('highlighted');
+
+      self.trigger('results:focus', {
+        data: data,
+        element: $(this)
+      });
     });
     });
 
 
     this.$results.on('mouseleave', '.option', function (evt) {
     this.$results.on('mouseleave', '.option', function (evt) {
-      $(this).removeClass('highlighted');
+      if ($(this).hasClass('highlighted')) {
+        $(this).removeClass('highlighted');
+        self.$results.removeAttr('aria-activedescendant');
+      }
     });
     });
   };
   };
 
 
@@ -537,9 +562,11 @@ define('select2/selection/single',[
     SingleSelection.__super__.bind.apply(this, arguments);
     SingleSelection.__super__.bind.apply(this, arguments);
 
 
     var id = container.id + '-container';
     var id = container.id + '-container';
+    var resultsId = container.id + '-results';
 
 
     this.$selection.find('.rendered-selection').attr('id', id);
     this.$selection.find('.rendered-selection').attr('id', id);
     this.$selection.attr('aria-labelledby', id);
     this.$selection.attr('aria-labelledby', id);
+    this.$selection.attr('aria-owns', resultsId);
 
 
     this.$selection.on('mousedown', function (evt) {
     this.$selection.on('mousedown', function (evt) {
       // Only respond to left clicks
       // Only respond to left clicks
@@ -576,6 +603,8 @@ 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');
+
+          evt.preventDefault();
         } else if (key == KEYS.UP) {
         } else if (key == KEYS.UP) {
           self.trigger('results:previous');
           self.trigger('results:previous');
 
 
@@ -588,10 +617,16 @@ define('select2/selection/single',[
       } else {
       } else {
         if (key == KEYS.ENTER || key == KEYS.SPACE) {
         if (key == KEYS.ENTER || key == KEYS.SPACE) {
           self.trigger('open');
           self.trigger('open');
+
+          evt.preventDefault();
         }
         }
       }
       }
     });
     });
 
 
+    container.on('results:focus', function (params) {
+      self.$selection.attr('aria-activedescendant', params.data._resultId);
+    });
+
     container.on('selection:update', function (params) {
     container.on('selection:update', function (params) {
       self.update(params.data);
       self.update(params.data);
     });
     });
@@ -622,7 +657,7 @@ define('select2/selection/single',[
     this.$selection.find('.rendered-selection').html(formatted);
     this.$selection.find('.rendered-selection').html(formatted);
 
 
     if (data[0]._resultId != null) {
     if (data[0]._resultId != null) {
-      this.$selection.attr('aria-activedescendent', data[0]._resultId);
+      this.$selection.attr('aria-activedescendant', data[0]._resultId);
     }
     }
   };
   };
 
 
@@ -1404,6 +1439,10 @@ define('select2/core',[
       self.trigger('close');
       self.trigger('close');
     });
     });
 
 
+    this.results.on('results:focus', function (params) {
+      self.trigger('results:focus', params);
+    });
+
     this.on('open', function () {
     this.on('open', function () {
       $container.addClass('open');
       $container.addClass('open');
     });
     });
@@ -1455,7 +1494,7 @@ define('select2/core',[
     var $container = $(
     var $container = $(
       '<span class="select2 select2-container select2-theme-default">' +
       '<span class="select2 select2-container select2-theme-default">' +
         '<span class="selection"></span>' +
         '<span class="selection"></span>' +
-        '<span class="dropdown-wrapper"></span>' +
+        '<span class="dropdown-wrapper" aria-hidden="true"></span>' +
       '</span>'
       '</span>'
     );
     );
 
 

+ 43 - 4
dist/js/select2.amd.js

@@ -154,6 +154,7 @@ define('select2/results',[
   function Results ($element, options, dataAdapter) {
   function Results ($element, options, dataAdapter) {
     this.$element = $element;
     this.$element = $element;
     this.data = dataAdapter;
     this.data = dataAdapter;
+    this.options = options;
 
 
     Results.__super__.constructor.call(this);
     Results.__super__.constructor.call(this);
   }
   }
@@ -165,6 +166,10 @@ define('select2/results',[
       '<ul class="options" role="listbox"></ul>'
       '<ul class="options" role="listbox"></ul>'
     );
     );
 
 
+    if (this.options.get('multiple')) {
+      $results.attr('aria-multiselectable', 'true');
+    }
+
     this.$results = $results;
     this.$results = $results;
 
 
     return $results;
     return $results;
@@ -284,6 +289,10 @@ define('select2/results',[
   Results.prototype.bind = function (container, $container) {
   Results.prototype.bind = function (container, $container) {
     var self = this;
     var self = this;
 
 
+    var id = container.id + '-results';
+
+    this.$results.attr('id', id);
+
     container.on('results:all', function (params) {
     container.on('results:all', function (params) {
       self.clear();
       self.clear();
       self.append(params.data);
       self.append(params.data);
@@ -308,6 +317,7 @@ define('select2/results',[
     container.on('open', function () {
     container.on('open', function () {
       // When the dropdown is open, aria-expended="true"
       // When the dropdown is open, aria-expended="true"
       self.$results.attr('aria-expanded', 'true');
       self.$results.attr('aria-expanded', 'true');
+      self.$results.attr('aria-hidden', 'false');
 
 
       self.setClasses();
       self.setClasses();
     });
     });
@@ -315,6 +325,8 @@ define('select2/results',[
     container.on('close', function () {
     container.on('close', function () {
       // When the dropdown is closed, aria-expended="false"
       // When the dropdown is closed, aria-expended="false"
       self.$results.attr('aria-expanded', 'false');
       self.$results.attr('aria-expanded', 'false');
+      self.$results.attr('aria-hidden', 'true');
+      self.$results.removeAttr('aria-activedescendant');
     });
     });
 
 
     container.on('results:select', function () {
     container.on('results:select', function () {
@@ -401,6 +413,10 @@ define('select2/results',[
       }
       }
     });
     });
 
 
+    container.on('results:focus', function (params) {
+      params.element.addClass('highlighted');
+    });
+
     this.$results.on('mouseup', '.option[aria-selected]', function (evt) {
     this.$results.on('mouseup', '.option[aria-selected]', function (evt) {
       var $this = $(this);
       var $this = $(this);
 
 
@@ -422,12 +438,21 @@ define('select2/results',[
     });
     });
 
 
     this.$results.on('mouseenter', '.option[aria-selected]', function (evt) {
     this.$results.on('mouseenter', '.option[aria-selected]', function (evt) {
+      var data = $(this).data('data');
+
       self.$results.find('.option.highlighted').removeClass('highlighted');
       self.$results.find('.option.highlighted').removeClass('highlighted');
-      $(this).addClass('highlighted');
+
+      self.trigger('results:focus', {
+        data: data,
+        element: $(this)
+      });
     });
     });
 
 
     this.$results.on('mouseleave', '.option', function (evt) {
     this.$results.on('mouseleave', '.option', function (evt) {
-      $(this).removeClass('highlighted');
+      if ($(this).hasClass('highlighted')) {
+        $(this).removeClass('highlighted');
+        self.$results.removeAttr('aria-activedescendant');
+      }
     });
     });
   };
   };
 
 
@@ -537,9 +562,11 @@ define('select2/selection/single',[
     SingleSelection.__super__.bind.apply(this, arguments);
     SingleSelection.__super__.bind.apply(this, arguments);
 
 
     var id = container.id + '-container';
     var id = container.id + '-container';
+    var resultsId = container.id + '-results';
 
 
     this.$selection.find('.rendered-selection').attr('id', id);
     this.$selection.find('.rendered-selection').attr('id', id);
     this.$selection.attr('aria-labelledby', id);
     this.$selection.attr('aria-labelledby', id);
+    this.$selection.attr('aria-owns', resultsId);
 
 
     this.$selection.on('mousedown', function (evt) {
     this.$selection.on('mousedown', function (evt) {
       // Only respond to left clicks
       // Only respond to left clicks
@@ -576,6 +603,8 @@ 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');
+
+          evt.preventDefault();
         } else if (key == KEYS.UP) {
         } else if (key == KEYS.UP) {
           self.trigger('results:previous');
           self.trigger('results:previous');
 
 
@@ -588,10 +617,16 @@ define('select2/selection/single',[
       } else {
       } else {
         if (key == KEYS.ENTER || key == KEYS.SPACE) {
         if (key == KEYS.ENTER || key == KEYS.SPACE) {
           self.trigger('open');
           self.trigger('open');
+
+          evt.preventDefault();
         }
         }
       }
       }
     });
     });
 
 
+    container.on('results:focus', function (params) {
+      self.$selection.attr('aria-activedescendant', params.data._resultId);
+    });
+
     container.on('selection:update', function (params) {
     container.on('selection:update', function (params) {
       self.update(params.data);
       self.update(params.data);
     });
     });
@@ -622,7 +657,7 @@ define('select2/selection/single',[
     this.$selection.find('.rendered-selection').html(formatted);
     this.$selection.find('.rendered-selection').html(formatted);
 
 
     if (data[0]._resultId != null) {
     if (data[0]._resultId != null) {
-      this.$selection.attr('aria-activedescendent', data[0]._resultId);
+      this.$selection.attr('aria-activedescendant', data[0]._resultId);
     }
     }
   };
   };
 
 
@@ -1404,6 +1439,10 @@ define('select2/core',[
       self.trigger('close');
       self.trigger('close');
     });
     });
 
 
+    this.results.on('results:focus', function (params) {
+      self.trigger('results:focus', params);
+    });
+
     this.on('open', function () {
     this.on('open', function () {
       $container.addClass('open');
       $container.addClass('open');
     });
     });
@@ -1455,7 +1494,7 @@ define('select2/core',[
     var $container = $(
     var $container = $(
       '<span class="select2 select2-container select2-theme-default">' +
       '<span class="select2 select2-container select2-theme-default">' +
         '<span class="selection"></span>' +
         '<span class="selection"></span>' +
-        '<span class="dropdown-wrapper"></span>' +
+        '<span class="dropdown-wrapper" aria-hidden="true"></span>' +
       '</span>'
       '</span>'
     );
     );
 
 

+ 43 - 4
dist/js/select2.full.js

@@ -9692,6 +9692,7 @@ define('select2/results',[
   function Results ($element, options, dataAdapter) {
   function Results ($element, options, dataAdapter) {
     this.$element = $element;
     this.$element = $element;
     this.data = dataAdapter;
     this.data = dataAdapter;
+    this.options = options;
 
 
     Results.__super__.constructor.call(this);
     Results.__super__.constructor.call(this);
   }
   }
@@ -9703,6 +9704,10 @@ define('select2/results',[
       '<ul class="options" role="listbox"></ul>'
       '<ul class="options" role="listbox"></ul>'
     );
     );
 
 
+    if (this.options.get('multiple')) {
+      $results.attr('aria-multiselectable', 'true');
+    }
+
     this.$results = $results;
     this.$results = $results;
 
 
     return $results;
     return $results;
@@ -9822,6 +9827,10 @@ define('select2/results',[
   Results.prototype.bind = function (container, $container) {
   Results.prototype.bind = function (container, $container) {
     var self = this;
     var self = this;
 
 
+    var id = container.id + '-results';
+
+    this.$results.attr('id', id);
+
     container.on('results:all', function (params) {
     container.on('results:all', function (params) {
       self.clear();
       self.clear();
       self.append(params.data);
       self.append(params.data);
@@ -9846,6 +9855,7 @@ define('select2/results',[
     container.on('open', function () {
     container.on('open', function () {
       // When the dropdown is open, aria-expended="true"
       // When the dropdown is open, aria-expended="true"
       self.$results.attr('aria-expanded', 'true');
       self.$results.attr('aria-expanded', 'true');
+      self.$results.attr('aria-hidden', 'false');
 
 
       self.setClasses();
       self.setClasses();
     });
     });
@@ -9853,6 +9863,8 @@ define('select2/results',[
     container.on('close', function () {
     container.on('close', function () {
       // When the dropdown is closed, aria-expended="false"
       // When the dropdown is closed, aria-expended="false"
       self.$results.attr('aria-expanded', 'false');
       self.$results.attr('aria-expanded', 'false');
+      self.$results.attr('aria-hidden', 'true');
+      self.$results.removeAttr('aria-activedescendant');
     });
     });
 
 
     container.on('results:select', function () {
     container.on('results:select', function () {
@@ -9939,6 +9951,10 @@ define('select2/results',[
       }
       }
     });
     });
 
 
+    container.on('results:focus', function (params) {
+      params.element.addClass('highlighted');
+    });
+
     this.$results.on('mouseup', '.option[aria-selected]', function (evt) {
     this.$results.on('mouseup', '.option[aria-selected]', function (evt) {
       var $this = $(this);
       var $this = $(this);
 
 
@@ -9960,12 +9976,21 @@ define('select2/results',[
     });
     });
 
 
     this.$results.on('mouseenter', '.option[aria-selected]', function (evt) {
     this.$results.on('mouseenter', '.option[aria-selected]', function (evt) {
+      var data = $(this).data('data');
+
       self.$results.find('.option.highlighted').removeClass('highlighted');
       self.$results.find('.option.highlighted').removeClass('highlighted');
-      $(this).addClass('highlighted');
+
+      self.trigger('results:focus', {
+        data: data,
+        element: $(this)
+      });
     });
     });
 
 
     this.$results.on('mouseleave', '.option', function (evt) {
     this.$results.on('mouseleave', '.option', function (evt) {
-      $(this).removeClass('highlighted');
+      if ($(this).hasClass('highlighted')) {
+        $(this).removeClass('highlighted');
+        self.$results.removeAttr('aria-activedescendant');
+      }
     });
     });
   };
   };
 
 
@@ -10075,9 +10100,11 @@ define('select2/selection/single',[
     SingleSelection.__super__.bind.apply(this, arguments);
     SingleSelection.__super__.bind.apply(this, arguments);
 
 
     var id = container.id + '-container';
     var id = container.id + '-container';
+    var resultsId = container.id + '-results';
 
 
     this.$selection.find('.rendered-selection').attr('id', id);
     this.$selection.find('.rendered-selection').attr('id', id);
     this.$selection.attr('aria-labelledby', id);
     this.$selection.attr('aria-labelledby', id);
+    this.$selection.attr('aria-owns', resultsId);
 
 
     this.$selection.on('mousedown', function (evt) {
     this.$selection.on('mousedown', function (evt) {
       // Only respond to left clicks
       // Only respond to left clicks
@@ -10114,6 +10141,8 @@ 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');
+
+          evt.preventDefault();
         } else if (key == KEYS.UP) {
         } else if (key == KEYS.UP) {
           self.trigger('results:previous');
           self.trigger('results:previous');
 
 
@@ -10126,10 +10155,16 @@ define('select2/selection/single',[
       } else {
       } else {
         if (key == KEYS.ENTER || key == KEYS.SPACE) {
         if (key == KEYS.ENTER || key == KEYS.SPACE) {
           self.trigger('open');
           self.trigger('open');
+
+          evt.preventDefault();
         }
         }
       }
       }
     });
     });
 
 
+    container.on('results:focus', function (params) {
+      self.$selection.attr('aria-activedescendant', params.data._resultId);
+    });
+
     container.on('selection:update', function (params) {
     container.on('selection:update', function (params) {
       self.update(params.data);
       self.update(params.data);
     });
     });
@@ -10160,7 +10195,7 @@ define('select2/selection/single',[
     this.$selection.find('.rendered-selection').html(formatted);
     this.$selection.find('.rendered-selection').html(formatted);
 
 
     if (data[0]._resultId != null) {
     if (data[0]._resultId != null) {
-      this.$selection.attr('aria-activedescendent', data[0]._resultId);
+      this.$selection.attr('aria-activedescendant', data[0]._resultId);
     }
     }
   };
   };
 
 
@@ -10942,6 +10977,10 @@ define('select2/core',[
       self.trigger('close');
       self.trigger('close');
     });
     });
 
 
+    this.results.on('results:focus', function (params) {
+      self.trigger('results:focus', params);
+    });
+
     this.on('open', function () {
     this.on('open', function () {
       $container.addClass('open');
       $container.addClass('open');
     });
     });
@@ -10993,7 +11032,7 @@ define('select2/core',[
     var $container = $(
     var $container = $(
       '<span class="select2 select2-container select2-theme-default">' +
       '<span class="select2 select2-container select2-theme-default">' +
         '<span class="selection"></span>' +
         '<span class="selection"></span>' +
-        '<span class="dropdown-wrapper"></span>' +
+        '<span class="dropdown-wrapper" aria-hidden="true"></span>' +
       '</span>'
       '</span>'
     );
     );
 
 

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


+ 43 - 4
dist/js/select2.js

@@ -583,6 +583,7 @@ define('select2/results',[
   function Results ($element, options, dataAdapter) {
   function Results ($element, options, dataAdapter) {
     this.$element = $element;
     this.$element = $element;
     this.data = dataAdapter;
     this.data = dataAdapter;
+    this.options = options;
 
 
     Results.__super__.constructor.call(this);
     Results.__super__.constructor.call(this);
   }
   }
@@ -594,6 +595,10 @@ define('select2/results',[
       '<ul class="options" role="listbox"></ul>'
       '<ul class="options" role="listbox"></ul>'
     );
     );
 
 
+    if (this.options.get('multiple')) {
+      $results.attr('aria-multiselectable', 'true');
+    }
+
     this.$results = $results;
     this.$results = $results;
 
 
     return $results;
     return $results;
@@ -713,6 +718,10 @@ define('select2/results',[
   Results.prototype.bind = function (container, $container) {
   Results.prototype.bind = function (container, $container) {
     var self = this;
     var self = this;
 
 
+    var id = container.id + '-results';
+
+    this.$results.attr('id', id);
+
     container.on('results:all', function (params) {
     container.on('results:all', function (params) {
       self.clear();
       self.clear();
       self.append(params.data);
       self.append(params.data);
@@ -737,6 +746,7 @@ define('select2/results',[
     container.on('open', function () {
     container.on('open', function () {
       // When the dropdown is open, aria-expended="true"
       // When the dropdown is open, aria-expended="true"
       self.$results.attr('aria-expanded', 'true');
       self.$results.attr('aria-expanded', 'true');
+      self.$results.attr('aria-hidden', 'false');
 
 
       self.setClasses();
       self.setClasses();
     });
     });
@@ -744,6 +754,8 @@ define('select2/results',[
     container.on('close', function () {
     container.on('close', function () {
       // When the dropdown is closed, aria-expended="false"
       // When the dropdown is closed, aria-expended="false"
       self.$results.attr('aria-expanded', 'false');
       self.$results.attr('aria-expanded', 'false');
+      self.$results.attr('aria-hidden', 'true');
+      self.$results.removeAttr('aria-activedescendant');
     });
     });
 
 
     container.on('results:select', function () {
     container.on('results:select', function () {
@@ -830,6 +842,10 @@ define('select2/results',[
       }
       }
     });
     });
 
 
+    container.on('results:focus', function (params) {
+      params.element.addClass('highlighted');
+    });
+
     this.$results.on('mouseup', '.option[aria-selected]', function (evt) {
     this.$results.on('mouseup', '.option[aria-selected]', function (evt) {
       var $this = $(this);
       var $this = $(this);
 
 
@@ -851,12 +867,21 @@ define('select2/results',[
     });
     });
 
 
     this.$results.on('mouseenter', '.option[aria-selected]', function (evt) {
     this.$results.on('mouseenter', '.option[aria-selected]', function (evt) {
+      var data = $(this).data('data');
+
       self.$results.find('.option.highlighted').removeClass('highlighted');
       self.$results.find('.option.highlighted').removeClass('highlighted');
-      $(this).addClass('highlighted');
+
+      self.trigger('results:focus', {
+        data: data,
+        element: $(this)
+      });
     });
     });
 
 
     this.$results.on('mouseleave', '.option', function (evt) {
     this.$results.on('mouseleave', '.option', function (evt) {
-      $(this).removeClass('highlighted');
+      if ($(this).hasClass('highlighted')) {
+        $(this).removeClass('highlighted');
+        self.$results.removeAttr('aria-activedescendant');
+      }
     });
     });
   };
   };
 
 
@@ -966,9 +991,11 @@ define('select2/selection/single',[
     SingleSelection.__super__.bind.apply(this, arguments);
     SingleSelection.__super__.bind.apply(this, arguments);
 
 
     var id = container.id + '-container';
     var id = container.id + '-container';
+    var resultsId = container.id + '-results';
 
 
     this.$selection.find('.rendered-selection').attr('id', id);
     this.$selection.find('.rendered-selection').attr('id', id);
     this.$selection.attr('aria-labelledby', id);
     this.$selection.attr('aria-labelledby', id);
+    this.$selection.attr('aria-owns', resultsId);
 
 
     this.$selection.on('mousedown', function (evt) {
     this.$selection.on('mousedown', function (evt) {
       // Only respond to left clicks
       // Only respond to left clicks
@@ -1005,6 +1032,8 @@ 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');
+
+          evt.preventDefault();
         } else if (key == KEYS.UP) {
         } else if (key == KEYS.UP) {
           self.trigger('results:previous');
           self.trigger('results:previous');
 
 
@@ -1017,10 +1046,16 @@ define('select2/selection/single',[
       } else {
       } else {
         if (key == KEYS.ENTER || key == KEYS.SPACE) {
         if (key == KEYS.ENTER || key == KEYS.SPACE) {
           self.trigger('open');
           self.trigger('open');
+
+          evt.preventDefault();
         }
         }
       }
       }
     });
     });
 
 
+    container.on('results:focus', function (params) {
+      self.$selection.attr('aria-activedescendant', params.data._resultId);
+    });
+
     container.on('selection:update', function (params) {
     container.on('selection:update', function (params) {
       self.update(params.data);
       self.update(params.data);
     });
     });
@@ -1051,7 +1086,7 @@ define('select2/selection/single',[
     this.$selection.find('.rendered-selection').html(formatted);
     this.$selection.find('.rendered-selection').html(formatted);
 
 
     if (data[0]._resultId != null) {
     if (data[0]._resultId != null) {
-      this.$selection.attr('aria-activedescendent', data[0]._resultId);
+      this.$selection.attr('aria-activedescendant', data[0]._resultId);
     }
     }
   };
   };
 
 
@@ -1833,6 +1868,10 @@ define('select2/core',[
       self.trigger('close');
       self.trigger('close');
     });
     });
 
 
+    this.results.on('results:focus', function (params) {
+      self.trigger('results:focus', params);
+    });
+
     this.on('open', function () {
     this.on('open', function () {
       $container.addClass('open');
       $container.addClass('open');
     });
     });
@@ -1884,7 +1923,7 @@ define('select2/core',[
     var $container = $(
     var $container = $(
       '<span class="select2 select2-container select2-theme-default">' +
       '<span class="select2 select2-container select2-theme-default">' +
         '<span class="selection"></span>' +
         '<span class="selection"></span>' +
-        '<span class="dropdown-wrapper"></span>' +
+        '<span class="dropdown-wrapper" aria-hidden="true"></span>' +
       '</span>'
       '</span>'
     );
     );
 
 

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


+ 5 - 1
src/js/select2/core.js

@@ -116,6 +116,10 @@ define([
       self.trigger('close');
       self.trigger('close');
     });
     });
 
 
+    this.results.on('results:focus', function (params) {
+      self.trigger('results:focus', params);
+    });
+
     this.on('open', function () {
     this.on('open', function () {
       $container.addClass('open');
       $container.addClass('open');
     });
     });
@@ -167,7 +171,7 @@ define([
     var $container = $(
     var $container = $(
       '<span class="select2 select2-container select2-theme-default">' +
       '<span class="select2 select2-container select2-theme-default">' +
         '<span class="selection"></span>' +
         '<span class="selection"></span>' +
-        '<span class="dropdown-wrapper"></span>' +
+        '<span class="dropdown-wrapper" aria-hidden="true"></span>' +
       '</span>'
       '</span>'
     );
     );
 
 

+ 27 - 2
src/js/select2/results.js

@@ -4,6 +4,7 @@ define([
   function Results ($element, options, dataAdapter) {
   function Results ($element, options, dataAdapter) {
     this.$element = $element;
     this.$element = $element;
     this.data = dataAdapter;
     this.data = dataAdapter;
+    this.options = options;
 
 
     Results.__super__.constructor.call(this);
     Results.__super__.constructor.call(this);
   }
   }
@@ -15,6 +16,10 @@ define([
       '<ul class="options" role="listbox"></ul>'
       '<ul class="options" role="listbox"></ul>'
     );
     );
 
 
+    if (this.options.get('multiple')) {
+      $results.attr('aria-multiselectable', 'true');
+    }
+
     this.$results = $results;
     this.$results = $results;
 
 
     return $results;
     return $results;
@@ -134,6 +139,10 @@ define([
   Results.prototype.bind = function (container, $container) {
   Results.prototype.bind = function (container, $container) {
     var self = this;
     var self = this;
 
 
+    var id = container.id + '-results';
+
+    this.$results.attr('id', id);
+
     container.on('results:all', function (params) {
     container.on('results:all', function (params) {
       self.clear();
       self.clear();
       self.append(params.data);
       self.append(params.data);
@@ -158,6 +167,7 @@ define([
     container.on('open', function () {
     container.on('open', function () {
       // When the dropdown is open, aria-expended="true"
       // When the dropdown is open, aria-expended="true"
       self.$results.attr('aria-expanded', 'true');
       self.$results.attr('aria-expanded', 'true');
+      self.$results.attr('aria-hidden', 'false');
 
 
       self.setClasses();
       self.setClasses();
     });
     });
@@ -165,6 +175,8 @@ define([
     container.on('close', function () {
     container.on('close', function () {
       // When the dropdown is closed, aria-expended="false"
       // When the dropdown is closed, aria-expended="false"
       self.$results.attr('aria-expanded', 'false');
       self.$results.attr('aria-expanded', 'false');
+      self.$results.attr('aria-hidden', 'true');
+      self.$results.removeAttr('aria-activedescendant');
     });
     });
 
 
     container.on('results:select', function () {
     container.on('results:select', function () {
@@ -251,6 +263,10 @@ define([
       }
       }
     });
     });
 
 
+    container.on('results:focus', function (params) {
+      params.element.addClass('highlighted');
+    });
+
     this.$results.on('mouseup', '.option[aria-selected]', function (evt) {
     this.$results.on('mouseup', '.option[aria-selected]', function (evt) {
       var $this = $(this);
       var $this = $(this);
 
 
@@ -272,12 +288,21 @@ define([
     });
     });
 
 
     this.$results.on('mouseenter', '.option[aria-selected]', function (evt) {
     this.$results.on('mouseenter', '.option[aria-selected]', function (evt) {
+      var data = $(this).data('data');
+
       self.$results.find('.option.highlighted').removeClass('highlighted');
       self.$results.find('.option.highlighted').removeClass('highlighted');
-      $(this).addClass('highlighted');
+
+      self.trigger('results:focus', {
+        data: data,
+        element: $(this)
+      });
     });
     });
 
 
     this.$results.on('mouseleave', '.option', function (evt) {
     this.$results.on('mouseleave', '.option', function (evt) {
-      $(this).removeClass('highlighted');
+      if ($(this).hasClass('highlighted')) {
+        $(this).removeClass('highlighted');
+        self.$results.removeAttr('aria-activedescendant');
+      }
     });
     });
   };
   };
 
 

+ 11 - 1
src/js/select2/selection/single.js

@@ -30,9 +30,11 @@ define([
     SingleSelection.__super__.bind.apply(this, arguments);
     SingleSelection.__super__.bind.apply(this, arguments);
 
 
     var id = container.id + '-container';
     var id = container.id + '-container';
+    var resultsId = container.id + '-results';
 
 
     this.$selection.find('.rendered-selection').attr('id', id);
     this.$selection.find('.rendered-selection').attr('id', id);
     this.$selection.attr('aria-labelledby', id);
     this.$selection.attr('aria-labelledby', id);
+    this.$selection.attr('aria-owns', resultsId);
 
 
     this.$selection.on('mousedown', function (evt) {
     this.$selection.on('mousedown', function (evt) {
       // Only respond to left clicks
       // Only respond to left clicks
@@ -69,6 +71,8 @@ define([
       if (container.isOpen()) {
       if (container.isOpen()) {
         if (key == KEYS.ENTER) {
         if (key == KEYS.ENTER) {
           self.trigger('results:select');
           self.trigger('results:select');
+
+          evt.preventDefault();
         } else if (key == KEYS.UP) {
         } else if (key == KEYS.UP) {
           self.trigger('results:previous');
           self.trigger('results:previous');
 
 
@@ -81,10 +85,16 @@ define([
       } else {
       } else {
         if (key == KEYS.ENTER || key == KEYS.SPACE) {
         if (key == KEYS.ENTER || key == KEYS.SPACE) {
           self.trigger('open');
           self.trigger('open');
+
+          evt.preventDefault();
         }
         }
       }
       }
     });
     });
 
 
+    container.on('results:focus', function (params) {
+      self.$selection.attr('aria-activedescendant', params.data._resultId);
+    });
+
     container.on('selection:update', function (params) {
     container.on('selection:update', function (params) {
       self.update(params.data);
       self.update(params.data);
     });
     });
@@ -115,7 +125,7 @@ define([
     this.$selection.find('.rendered-selection').html(formatted);
     this.$selection.find('.rendered-selection').html(formatted);
 
 
     if (data[0]._resultId != null) {
     if (data[0]._resultId != null) {
-      this.$selection.attr('aria-activedescendent', data[0]._resultId);
+      this.$selection.attr('aria-activedescendant', data[0]._resultId);
     }
     }
   };
   };
 
 

+ 1 - 1
src/scss/theme/default/layout.scss

@@ -96,7 +96,7 @@
           }
           }
 
 
           &[aria-disabled=true] {
           &[aria-disabled=true] {
-            color: #666;
+            color: #999;
           }
           }
 
 
           &[aria-selected=true] {
           &[aria-selected=true] {

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