浏览代码

Support duplicate options

Now that the data objects have the `element` property, we can test
to make sure it's a DOM element and then use it for selecting the
option. This allows us to select multiple options with the same id,
as well as handle cases where that is already happening.

You cannot use `$e.val()` to select two options with the same id,
as jQuery will reject it, but you can set the second option to
`.selected = true`, which is supported.
Kevin Brown 10 年之前
父节点
当前提交
0bc73941fe

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

@@ -2153,6 +2153,15 @@ define('select2/data/select',[
   SelectAdapter.prototype.select = function (data) {
     var self = this;
 
+    // If data.element is a DOM nose, use it instead
+    if ($(data.element).is('option')) {
+      data.element.selected = true;
+
+      this.$element.trigger('change');
+
+      return;
+    }
+
     if (this.$element.prop('multiple')) {
       this.current(function (currentData) {
         var val = [];
@@ -2187,6 +2196,14 @@ define('select2/data/select',[
       return;
     }
 
+    if ($(data.element).is('option')) {
+      data.element.selected = false;
+
+      this.$element.trigger('change');
+
+      return;
+    }
+
     this.current(function (currentData) {
       var val = [];
 

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

@@ -2153,6 +2153,15 @@ define('select2/data/select',[
   SelectAdapter.prototype.select = function (data) {
     var self = this;
 
+    // If data.element is a DOM nose, use it instead
+    if ($(data.element).is('option')) {
+      data.element.selected = true;
+
+      this.$element.trigger('change');
+
+      return;
+    }
+
     if (this.$element.prop('multiple')) {
       this.current(function (currentData) {
         var val = [];
@@ -2187,6 +2196,14 @@ define('select2/data/select',[
       return;
     }
 
+    if ($(data.element).is('option')) {
+      data.element.selected = false;
+
+      this.$element.trigger('change');
+
+      return;
+    }
+
     this.current(function (currentData) {
       var val = [];
 

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

@@ -11688,6 +11688,15 @@ define('select2/data/select',[
   SelectAdapter.prototype.select = function (data) {
     var self = this;
 
+    // If data.element is a DOM nose, use it instead
+    if ($(data.element).is('option')) {
+      data.element.selected = true;
+
+      this.$element.trigger('change');
+
+      return;
+    }
+
     if (this.$element.prop('multiple')) {
       this.current(function (currentData) {
         var val = [];
@@ -11722,6 +11731,14 @@ define('select2/data/select',[
       return;
     }
 
+    if ($(data.element).is('option')) {
+      data.element.selected = false;
+
+      this.$element.trigger('change');
+
+      return;
+    }
+
     this.current(function (currentData) {
       var val = [];
 

文件差异内容过多而无法显示
+ 0 - 0
dist/js/select2.full.min.js


+ 17 - 0
dist/js/select2.js

@@ -2581,6 +2581,15 @@ define('select2/data/select',[
   SelectAdapter.prototype.select = function (data) {
     var self = this;
 
+    // If data.element is a DOM nose, use it instead
+    if ($(data.element).is('option')) {
+      data.element.selected = true;
+
+      this.$element.trigger('change');
+
+      return;
+    }
+
     if (this.$element.prop('multiple')) {
       this.current(function (currentData) {
         var val = [];
@@ -2615,6 +2624,14 @@ define('select2/data/select',[
       return;
     }
 
+    if ($(data.element).is('option')) {
+      data.element.selected = false;
+
+      this.$element.trigger('change');
+
+      return;
+    }
+
     this.current(function (currentData) {
       var val = [];
 

文件差异内容过多而无法显示
+ 0 - 0
dist/js/select2.min.js


+ 17 - 0
src/js/select2/data/select.js

@@ -30,6 +30,15 @@ define([
   SelectAdapter.prototype.select = function (data) {
     var self = this;
 
+    // If data.element is a DOM nose, use it instead
+    if ($(data.element).is('option')) {
+      data.element.selected = true;
+
+      this.$element.trigger('change');
+
+      return;
+    }
+
     if (this.$element.prop('multiple')) {
       this.current(function (currentData) {
         var val = [];
@@ -64,6 +73,14 @@ define([
       return;
     }
 
+    if ($(data.element).is('option')) {
+      data.element.selected = false;
+
+      this.$element.trigger('change');
+
+      return;
+    }
+
     this.current(function (currentData) {
       var val = [];
 

+ 181 - 0
tests/data/select-tests.js

@@ -154,6 +154,158 @@ test('multiple adds to the old value', function (assert) {
   assert.deepEqual($select.val(), ['default', '2']);
 });
 
+test('duplicates - single - same id on select triggers change',
+  function (assert) {
+  var $select = $('#qunit-fixture .duplicates');
+
+  var data = new SelectData($select, data);
+  var second = $('#qunit-fixture .duplicates option')[2];
+
+  var changeTriggered = false;
+
+  assert.equal($select.val(), 'one');
+
+  $select.on('change', function () {
+    changeTriggered = true;
+  });
+
+  data.select({
+    id: 'one',
+    text: 'Uno',
+    element: second
+  });
+
+  assert.equal(
+    $select.val(),
+    'one',
+    'The value never changed'
+  );
+
+  assert.ok(
+    changeTriggered,
+    'The change event should be triggered'
+  );
+
+  assert.ok(
+    second.selected,
+    'The second duplicate is selected, not the first'
+  );
+});
+
+test('duplicates - single - different id on select triggers change',
+  function (assert) {
+  var $select = $('#qunit-fixture .duplicates');
+
+  var data = new SelectData($select, data);
+  var second = $('#qunit-fixture .duplicates option')[2];
+
+  var changeTriggered = false;
+
+  $select.val('two');
+
+  $select.on('change', function () {
+    changeTriggered = true;
+  });
+
+  data.select({
+    id: 'one',
+    text: 'Uno',
+    element: second
+  });
+
+  assert.equal(
+    $select.val(),
+    'one',
+    'The value changed to the duplicate id'
+  );
+
+  assert.ok(
+    changeTriggered,
+    'The change event should be triggered'
+  );
+
+  assert.ok(
+    second.selected,
+    'The second duplicate is selected, not the first'
+  );
+});
+
+test('duplicates - multiple - same id on select triggers change',
+function (assert) {
+  var $select = $('#qunit-fixture .duplicates-multi');
+
+  var data = new SelectData($select, data);
+  var second = $('#qunit-fixture .duplicates-multi option')[2];
+
+  var changeTriggered = false;
+
+  $select.val(['one']);
+
+  $select.on('change', function () {
+    changeTriggered = true;
+  });
+
+  data.select({
+    id: 'one',
+    text: 'Uno',
+    element: second
+  });
+
+  assert.deepEqual(
+    $select.val(),
+    ['one', 'one'],
+    'The value now has duplicates'
+  );
+
+  assert.ok(
+    changeTriggered,
+    'The change event should be triggered'
+  );
+
+  assert.ok(
+    second.selected,
+    'The second duplicate is selected, not the first'
+  );
+});
+
+test('duplicates - multiple - different id on select triggers change',
+function (assert) {
+  var $select = $('#qunit-fixture .duplicates-multi');
+
+  var data = new SelectData($select, data);
+  var second = $('#qunit-fixture .duplicates-multi option')[2];
+
+  var changeTriggered = false;
+
+  $select.val(['two']);
+
+  $select.on('change', function () {
+    changeTriggered = true;
+  });
+
+  data.select({
+    id: 'one',
+    text: 'Uno',
+    element: second
+  });
+
+  assert.deepEqual(
+    $select.val(),
+    ['two', 'one'],
+    'The value has the new id'
+  );
+
+  assert.ok(
+    changeTriggered,
+    'The change event should be triggered'
+  );
+
+  assert.ok(
+    second.selected,
+    'The second duplicate is selected, not the first'
+  );
+});
+
 module('Data adapter - Select - query');
 
 test('all options are returned with no term', function (assert) {
@@ -258,3 +410,32 @@ test('empty optgroups are still shown when queried', function (assert) {
     );
   });
 });
+
+test('multiple options with the same value are returned', function (assert) {
+  var $select = $('#qunit-fixture .duplicates');
+
+  var data = new SelectData($select, options);
+
+  data.query({}, function (data) {
+    assert.equal(
+      data.length,
+      3,
+      'The duplicate option should still be returned when queried'
+    );
+
+    var first = data[0];
+    var duplicate = data[2];
+
+    assert.equal(
+      first.id,
+      duplicate.id,
+      'The duplicates should have the same id'
+    );
+
+    assert.notEqual(
+      first.text,
+      duplicate.text,
+      'The duplicates do not have the same text'
+    );
+  });
+});

+ 12 - 0
tests/data/select.html

@@ -26,6 +26,18 @@
         </optgroup>
         <optgroup label="Empty"></optgroup>
       </select>
+
+      <select class="duplicates">
+        <option value="one">One</option>
+        <option value="two">Two</option>
+        <option value="one">Uno</option>
+      </select>
+
+      <select class="duplicates-multi" multiple="multiple">
+        <option value="one">One</option>
+        <option value="two">Two</option>
+        <option value="one">Uno</option>
+      </select>
     </div>
 
     <script src="../vendor/qunit-1.14.0.js" type="text/javascript"></script>

部分文件因为文件数量过多而无法显示