Explorar el Código

Fix support for deep nesting

While deep nesting will not work on a standard `<select>`, we can
emulate it through data objects still, and just handle the display
of the data in the results.

This also means that the horrific deep-nested CSS is back to handle
the padding. I hope that will get fixed over time.

This also fixes one of the performance issues with adding array
data, as options are added at the very end instead of one by one.
Kevin Brown hace 10 años
padre
commit
7f17291932

+ 19 - 0
dist/css/select2.css

@@ -218,6 +218,25 @@
   color: #999; }
 .select2-container--default .select2-results__option[aria-selected=true] {
   background-color: #ddd; }
+.select2-container--default .select2-results__option .select2-results__option {
+  padding-left: 1em; }
+  .select2-container--default .select2-results__option .select2-results__option .select2-results__group {
+    padding-left: 0; }
+  .select2-container--default .select2-results__option .select2-results__option .select2-results__option {
+    margin-left: -1em;
+    padding-left: 2em; }
+    .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+      margin-left: -2em;
+      padding-left: 3em; }
+      .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+        margin-left: -3em;
+        padding-left: 4em; }
+        .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+          margin-left: -4em;
+          padding-left: 5em; }
+          .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+            margin-left: -5em;
+            padding-left: 6em; }
 .select2-container--default .select2-results__option--highlighted[aria-selected] {
   background-color: #5897fb;
   color: white; }

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
dist/css/select2.min.css


+ 26 - 9
dist/js/select2.amd.full.js

@@ -2324,9 +2324,19 @@ define('select2/data/select',[
   };
 
   SelectAdapter.prototype.option = function (data) {
-    var option = document.createElement('option');
+    var option;
 
-    option.value = data.id;
+    if (data.children) {
+      option = document.createElement('optgroup');
+      option.label = data.text;
+    } else {
+      option = document.createElement('option');
+      option.innerText = data.text;
+    }
+
+    if (data.id) {
+      option.value = data.id;
+    }
 
     if (data.disabled) {
       option.disabled = true;
@@ -2336,8 +2346,6 @@ define('select2/data/select',[
       option.selected = true;
     }
 
-    option.innerText = data.text;
-
     var $option = $(option);
 
     var normalizedData = this._normalizeItem(data);
@@ -2367,7 +2375,7 @@ define('select2/data/select',[
       };
     } else if ($option.is('optgroup')) {
       data = {
-        text: $option.attr('label'),
+        text: $option.prop('label'),
         children: []
       };
 
@@ -2444,7 +2452,7 @@ define('select2/data/array',[
 
     ArrayAdapter.__super__.constructor.call(this, $element, options);
 
-    this.convertToOptions(data);
+    $element.append(this.convertToOptions(data));
   }
 
   Utils.Extend(ArrayAdapter, SelectAdapter);
@@ -2469,6 +2477,8 @@ define('select2/data/array',[
       return self.item($(this)).id;
     }).get();
 
+    var $options = [];
+
     // Filter out all items except for the one passed in the argument
     function onlyItem (item) {
       return function () {
@@ -2477,8 +2487,7 @@ define('select2/data/array',[
     }
 
     for (var d = 0; d < data.length; d++) {
-      var item = data[d];
-      item.id = item.id.toString();
+      var item = this._normalizeItem(data[d]);
 
       // Skip items which were pre-loaded, only merge the data
       if (existingIds.indexOf(item.id) >= 0) {
@@ -2496,8 +2505,16 @@ define('select2/data/array',[
 
       var $option = this.option(item);
 
-      this.$element.append($option);
+      if (item.children) {
+        var $children = this.convertToOptions(item.children);
+
+        $option.append($children);
+      }
+
+      $options.push($option);
     }
+
+    return $options;
   };
 
   return ArrayAdapter;

+ 26 - 9
dist/js/select2.amd.js

@@ -2324,9 +2324,19 @@ define('select2/data/select',[
   };
 
   SelectAdapter.prototype.option = function (data) {
-    var option = document.createElement('option');
+    var option;
 
-    option.value = data.id;
+    if (data.children) {
+      option = document.createElement('optgroup');
+      option.label = data.text;
+    } else {
+      option = document.createElement('option');
+      option.innerText = data.text;
+    }
+
+    if (data.id) {
+      option.value = data.id;
+    }
 
     if (data.disabled) {
       option.disabled = true;
@@ -2336,8 +2346,6 @@ define('select2/data/select',[
       option.selected = true;
     }
 
-    option.innerText = data.text;
-
     var $option = $(option);
 
     var normalizedData = this._normalizeItem(data);
@@ -2367,7 +2375,7 @@ define('select2/data/select',[
       };
     } else if ($option.is('optgroup')) {
       data = {
-        text: $option.attr('label'),
+        text: $option.prop('label'),
         children: []
       };
 
@@ -2444,7 +2452,7 @@ define('select2/data/array',[
 
     ArrayAdapter.__super__.constructor.call(this, $element, options);
 
-    this.convertToOptions(data);
+    $element.append(this.convertToOptions(data));
   }
 
   Utils.Extend(ArrayAdapter, SelectAdapter);
@@ -2469,6 +2477,8 @@ define('select2/data/array',[
       return self.item($(this)).id;
     }).get();
 
+    var $options = [];
+
     // Filter out all items except for the one passed in the argument
     function onlyItem (item) {
       return function () {
@@ -2477,8 +2487,7 @@ define('select2/data/array',[
     }
 
     for (var d = 0; d < data.length; d++) {
-      var item = data[d];
-      item.id = item.id.toString();
+      var item = this._normalizeItem(data[d]);
 
       // Skip items which were pre-loaded, only merge the data
       if (existingIds.indexOf(item.id) >= 0) {
@@ -2496,8 +2505,16 @@ define('select2/data/array',[
 
       var $option = this.option(item);
 
-      this.$element.append($option);
+      if (item.children) {
+        var $children = this.convertToOptions(item.children);
+
+        $option.append($children);
+      }
+
+      $options.push($option);
     }
+
+    return $options;
   };
 
   return ArrayAdapter;

+ 26 - 9
dist/js/select2.full.js

@@ -11859,9 +11859,19 @@ define('select2/data/select',[
   };
 
   SelectAdapter.prototype.option = function (data) {
-    var option = document.createElement('option');
+    var option;
 
-    option.value = data.id;
+    if (data.children) {
+      option = document.createElement('optgroup');
+      option.label = data.text;
+    } else {
+      option = document.createElement('option');
+      option.innerText = data.text;
+    }
+
+    if (data.id) {
+      option.value = data.id;
+    }
 
     if (data.disabled) {
       option.disabled = true;
@@ -11871,8 +11881,6 @@ define('select2/data/select',[
       option.selected = true;
     }
 
-    option.innerText = data.text;
-
     var $option = $(option);
 
     var normalizedData = this._normalizeItem(data);
@@ -11902,7 +11910,7 @@ define('select2/data/select',[
       };
     } else if ($option.is('optgroup')) {
       data = {
-        text: $option.attr('label'),
+        text: $option.prop('label'),
         children: []
       };
 
@@ -11979,7 +11987,7 @@ define('select2/data/array',[
 
     ArrayAdapter.__super__.constructor.call(this, $element, options);
 
-    this.convertToOptions(data);
+    $element.append(this.convertToOptions(data));
   }
 
   Utils.Extend(ArrayAdapter, SelectAdapter);
@@ -12004,6 +12012,8 @@ define('select2/data/array',[
       return self.item($(this)).id;
     }).get();
 
+    var $options = [];
+
     // Filter out all items except for the one passed in the argument
     function onlyItem (item) {
       return function () {
@@ -12012,8 +12022,7 @@ define('select2/data/array',[
     }
 
     for (var d = 0; d < data.length; d++) {
-      var item = data[d];
-      item.id = item.id.toString();
+      var item = this._normalizeItem(data[d]);
 
       // Skip items which were pre-loaded, only merge the data
       if (existingIds.indexOf(item.id) >= 0) {
@@ -12031,8 +12040,16 @@ define('select2/data/array',[
 
       var $option = this.option(item);
 
-      this.$element.append($option);
+      if (item.children) {
+        var $children = this.convertToOptions(item.children);
+
+        $option.append($children);
+      }
+
+      $options.push($option);
     }
+
+    return $options;
   };
 
   return ArrayAdapter;

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
dist/js/select2.full.min.js


+ 26 - 9
dist/js/select2.js

@@ -2752,9 +2752,19 @@ define('select2/data/select',[
   };
 
   SelectAdapter.prototype.option = function (data) {
-    var option = document.createElement('option');
+    var option;
 
-    option.value = data.id;
+    if (data.children) {
+      option = document.createElement('optgroup');
+      option.label = data.text;
+    } else {
+      option = document.createElement('option');
+      option.innerText = data.text;
+    }
+
+    if (data.id) {
+      option.value = data.id;
+    }
 
     if (data.disabled) {
       option.disabled = true;
@@ -2764,8 +2774,6 @@ define('select2/data/select',[
       option.selected = true;
     }
 
-    option.innerText = data.text;
-
     var $option = $(option);
 
     var normalizedData = this._normalizeItem(data);
@@ -2795,7 +2803,7 @@ define('select2/data/select',[
       };
     } else if ($option.is('optgroup')) {
       data = {
-        text: $option.attr('label'),
+        text: $option.prop('label'),
         children: []
       };
 
@@ -2872,7 +2880,7 @@ define('select2/data/array',[
 
     ArrayAdapter.__super__.constructor.call(this, $element, options);
 
-    this.convertToOptions(data);
+    $element.append(this.convertToOptions(data));
   }
 
   Utils.Extend(ArrayAdapter, SelectAdapter);
@@ -2897,6 +2905,8 @@ define('select2/data/array',[
       return self.item($(this)).id;
     }).get();
 
+    var $options = [];
+
     // Filter out all items except for the one passed in the argument
     function onlyItem (item) {
       return function () {
@@ -2905,8 +2915,7 @@ define('select2/data/array',[
     }
 
     for (var d = 0; d < data.length; d++) {
-      var item = data[d];
-      item.id = item.id.toString();
+      var item = this._normalizeItem(data[d]);
 
       // Skip items which were pre-loaded, only merge the data
       if (existingIds.indexOf(item.id) >= 0) {
@@ -2924,8 +2933,16 @@ define('select2/data/array',[
 
       var $option = this.option(item);
 
-      this.$element.append($option);
+      if (item.children) {
+        var $children = this.convertToOptions(item.children);
+
+        $option.append($children);
+      }
+
+      $options.push($option);
     }
+
+    return $options;
   };
 
   return ArrayAdapter;

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
dist/js/select2.min.js


+ 13 - 4
src/js/select2/data/array.js

@@ -8,7 +8,7 @@ define([
 
     ArrayAdapter.__super__.constructor.call(this, $element, options);
 
-    this.convertToOptions(data);
+    $element.append(this.convertToOptions(data));
   }
 
   Utils.Extend(ArrayAdapter, SelectAdapter);
@@ -33,6 +33,8 @@ define([
       return self.item($(this)).id;
     }).get();
 
+    var $options = [];
+
     // Filter out all items except for the one passed in the argument
     function onlyItem (item) {
       return function () {
@@ -41,8 +43,7 @@ define([
     }
 
     for (var d = 0; d < data.length; d++) {
-      var item = data[d];
-      item.id = item.id.toString();
+      var item = this._normalizeItem(data[d]);
 
       // Skip items which were pre-loaded, only merge the data
       if (existingIds.indexOf(item.id) >= 0) {
@@ -60,8 +61,16 @@ define([
 
       var $option = this.option(item);
 
-      this.$element.append($option);
+      if (item.children) {
+        var $children = this.convertToOptions(item.children);
+
+        $option.append($children);
+      }
+
+      $options.push($option);
     }
+
+    return $options;
   };
 
   return ArrayAdapter;

+ 13 - 5
src/js/select2/data/select.js

@@ -148,9 +148,19 @@ define([
   };
 
   SelectAdapter.prototype.option = function (data) {
-    var option = document.createElement('option');
+    var option;
 
-    option.value = data.id;
+    if (data.children) {
+      option = document.createElement('optgroup');
+      option.label = data.text;
+    } else {
+      option = document.createElement('option');
+      option.innerText = data.text;
+    }
+
+    if (data.id) {
+      option.value = data.id;
+    }
 
     if (data.disabled) {
       option.disabled = true;
@@ -160,8 +170,6 @@ define([
       option.selected = true;
     }
 
-    option.innerText = data.text;
-
     var $option = $(option);
 
     var normalizedData = this._normalizeItem(data);
@@ -191,7 +199,7 @@ define([
       };
     } else if ($option.is('optgroup')) {
       data = {
-        text: $option.attr('label'),
+        text: $option.prop('label'),
         children: []
       };
 

+ 33 - 0
src/scss/theme/default/layout.scss

@@ -47,6 +47,39 @@
     &[aria-selected=true] {
       background-color: #ddd;
     }
+
+    .select2-results__option {
+      padding-left: 1em;
+
+      .select2-results__group {
+        padding-left: 0;
+      }
+
+      .select2-results__option {
+        margin-left: -1em;
+        padding-left: 2em;
+
+        .select2-results__option {
+          margin-left: -2em;
+          padding-left: 3em;
+
+          .select2-results__option {
+            margin-left: -3em;
+            padding-left: 4em;
+
+            .select2-results__option {
+              margin-left: -4em;
+              padding-left: 5em;
+
+              .select2-results__option {
+                margin-left: -5em;
+                padding-left: 6em;
+              }
+            }
+          }
+        }
+      }
+    }
   }
 
   .select2-results__option--highlighted[aria-selected] {

+ 57 - 0
tests/data/array-tests.js

@@ -21,6 +21,25 @@ var options = new Options({
   ]
 });
 
+var nestedOptions = new Options({
+  data: [
+    {
+      text: 'Default',
+      children: [
+        {
+          text: 'Next',
+          children: [
+            {
+              id: 'a',
+              text: 'Option'
+            }
+          ]
+        }
+      ]
+    }
+  ]
+});
+
 test('current gets default for single', function (assert) {
   var $select = $('#qunit-fixture .single');
 
@@ -186,3 +205,41 @@ test('option tags are automatically generated', function (assert) {
     'An <option> element should be created for each object'
   );
 });
+
+test('optgroup tags can also be generated', function (assert) {
+  var $select = $('#qunit-fixture .single');
+
+  var data = new ArrayData($select, nestedOptions);
+
+  assert.equal(
+    $select.find('option').length,
+    1,
+    'An <option> element should be created for the one selectable object'
+  );
+
+  assert.equal(
+    $select.find('optgroup').length,
+    2,
+    'An <optgroup> element should be created for the two with children'
+  );
+});
+
+test('optgroup tags have the right properties', function (assert) {
+  var $select = $('#qunit-fixture .single');
+
+  var data = new ArrayData($select, nestedOptions);
+
+  var $group = $select.children('optgroup');
+
+  assert.equal(
+    $group.prop('label'),
+    'Default',
+    'An `<optgroup>` label should match the text property'
+  );
+
+  assert.equal(
+    $group.children().length,
+    1,
+    'The <optgroup> should have one child under it'
+  );
+});

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio