Browse Source

Added compatibility with `<input />` tags

This adds backwards compatibility back into Select2 for `<input />`
tags.  The compatibility modules are only available in the full
version and will trigger a warning if a hidden input is being used.

With the new decorator, Select2 should support the basic operations
that it previously did, with the exception of completely overriding
the internal objects. As we no longer expose `data` as a writable
method, it is no longer possible to completely override the selected
data. The state is still managed internally, but in order to prevent
data corruption issues in the past, it is not exposed to the public.

Some small changes needed to be made to how Select2 was dynamically
generating new `<option>` tags, so now a method is called that can
be overridden. In the case of the new decorator, this method is
intercepted and handled without having to actually place the
`<option>` tags into the DOM.

The decorator is applied after all of the other defaults, as the
defaults are not given the current element.

There has only been limited testing with this decorator, primarily
using the `data` and `placeholder` options.

This closes https://github.com/select2/select2/issues/3022.
Kevin Brown 10 năm trước cách đây
mục cha
commit
956ac46dab

+ 1 - 0
Gruntfile.js

@@ -14,6 +14,7 @@ module.exports = function (grunt) {
 
     'select2/compat/matcher',
     'select2/compat/initSelection',
+    'select2/compat/inputData',
     'select2/compat/query',
 
     'select2/dropdown/attachContainer',

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

@@ -2406,7 +2406,6 @@ define('select2/data/select',[
       var val = data.id;
 
       this.$element.val(val);
-
       this.$element.trigger('change');
     }
   };
@@ -2492,6 +2491,10 @@ define('select2/data/select',[
     });
   };
 
+  SelectAdapter.prototype.addOptions = function ($options) {
+    this.$element.append($options);
+  };
+
   SelectAdapter.prototype.option = function (data) {
     var option;
 
@@ -2632,7 +2635,7 @@ define('select2/data/array',[
 
     ArrayAdapter.__super__.constructor.call(this, $element, options);
 
-    $element.append(this.convertToOptions(data));
+    this.addOptions(this.convertToOptions(data));
   }
 
   Utils.Extend(ArrayAdapter, SelectAdapter);
@@ -2643,7 +2646,7 @@ define('select2/data/array',[
     if ($option.length === 0) {
       $option = this.option(data);
 
-      this.$element.append($option);
+      this.addOptions([$option]);
     }
 
     ArrayAdapter.__super__.select.call(this, data);
@@ -2871,7 +2874,7 @@ define('select2/data/tags',[
         var $option = self.option(tag);
         $option.attr('data-select2-tag', true);
 
-        self.$element.append($option);
+        self.addOptions([$option]);
 
         self.insertTag(data, tag);
       }
@@ -4057,6 +4060,15 @@ define('select2/options',[
     }
 
     this.options = Defaults.apply(this.options);
+
+    if ($element && $element.is('input')) {
+      var InputCompat = require(this.get('amdBase') + 'compat/inputData');
+
+      this.options.dataAdapter = Utils.Decorate(
+        this.options.dataAdapter,
+        InputCompat
+      );
+    }
   }
 
   Options.prototype.fromElement = function ($e) {
@@ -4974,6 +4986,112 @@ define('select2/compat/initSelection',[
   return InitSelection;
 });
 
+define('select2/compat/inputData',[
+  'jquery'
+], function ($) {
+  function InputData (decorated, $element, options) {
+    this._currentData = [];
+    this._valueSeparator = options.get('valueSeparator') || ',';
+
+    decorated.call(this, $element, options);
+  }
+
+  InputData.prototype.current = function (_, callback) {
+    function getSelected (data, selectedIds) {
+      var selected = [];
+
+      if (data.selected || $.inArray(selectedIds, data.id) !== -1) {
+        selected.push(data);
+      }
+
+      if (data.children) {
+        selected.push.apply(selected, getSelected(data.children, selectedIds));
+      }
+
+      return selected;
+    }
+
+    var selected = [];
+
+    for (var d = 0; d < this._currentData.length; d++) {
+      var data = this._currentData[d];
+
+      selected.push.apply(
+        selected,
+        getSelected(
+          data,
+          this.$element.val().split(
+            this._valueSeparator
+          )
+        )
+      );
+    }
+
+    callback(selected);
+  };
+
+  InputData.prototype.select = function (_, data) {
+    if (!this.options.get('multiple')) {
+      this.current(function (allData) {
+        $.map(allData, function (data) {
+          data.selected = false;
+        });
+      });
+    }
+
+    data.selected = true;
+
+    this._syncValue();
+  };
+
+  InputData.prototype.unselect = function (_, data) {
+    data.selected = false;
+
+    this._syncValue();
+  };
+
+  InputData.prototype._syncValue = function () {
+    var self = this;
+
+    this.current(function (allData) {
+      self.$element.val(
+        allData.join(
+          self._valueSeparator
+        )
+      );
+      self.$element.trigger('change');
+    });
+  };
+
+  InputData.prototype.query = function (_, params, callback) {
+    var results = [];
+
+    for (var d = 0; d < this._currentData.length; d++) {
+      var data = this._currentData[d];
+
+      var matches = this.matches(params, data);
+
+      if (matches !== null) {
+        results.push(matches);
+      }
+    }
+
+    callback({
+      results: results
+    });
+  };
+
+  InputData.prototype.addOptions = function (_, $options) {
+    var options = $.map($options, function ($option) {
+      return $.data($option[0], 'data');
+    });
+
+    this._currentData.push.apply(this._currentData, options);
+  };
+
+  return InputData;
+});
+
 define('select2/compat/query',[
 
 ], function () {

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

@@ -2406,7 +2406,6 @@ define('select2/data/select',[
       var val = data.id;
 
       this.$element.val(val);
-
       this.$element.trigger('change');
     }
   };
@@ -2492,6 +2491,10 @@ define('select2/data/select',[
     });
   };
 
+  SelectAdapter.prototype.addOptions = function ($options) {
+    this.$element.append($options);
+  };
+
   SelectAdapter.prototype.option = function (data) {
     var option;
 
@@ -2632,7 +2635,7 @@ define('select2/data/array',[
 
     ArrayAdapter.__super__.constructor.call(this, $element, options);
 
-    $element.append(this.convertToOptions(data));
+    this.addOptions(this.convertToOptions(data));
   }
 
   Utils.Extend(ArrayAdapter, SelectAdapter);
@@ -2643,7 +2646,7 @@ define('select2/data/array',[
     if ($option.length === 0) {
       $option = this.option(data);
 
-      this.$element.append($option);
+      this.addOptions([$option]);
     }
 
     ArrayAdapter.__super__.select.call(this, data);
@@ -2871,7 +2874,7 @@ define('select2/data/tags',[
         var $option = self.option(tag);
         $option.attr('data-select2-tag', true);
 
-        self.$element.append($option);
+        self.addOptions([$option]);
 
         self.insertTag(data, tag);
       }
@@ -4057,6 +4060,15 @@ define('select2/options',[
     }
 
     this.options = Defaults.apply(this.options);
+
+    if ($element && $element.is('input')) {
+      var InputCompat = require(this.get('amdBase') + 'compat/inputData');
+
+      this.options.dataAdapter = Utils.Decorate(
+        this.options.dataAdapter,
+        InputCompat
+      );
+    }
   }
 
   Options.prototype.fromElement = function ($e) {

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

@@ -2845,7 +2845,6 @@ define('select2/data/select',[
       var val = data.id;
 
       this.$element.val(val);
-
       this.$element.trigger('change');
     }
   };
@@ -2931,6 +2930,10 @@ define('select2/data/select',[
     });
   };
 
+  SelectAdapter.prototype.addOptions = function ($options) {
+    this.$element.append($options);
+  };
+
   SelectAdapter.prototype.option = function (data) {
     var option;
 
@@ -3071,7 +3074,7 @@ define('select2/data/array',[
 
     ArrayAdapter.__super__.constructor.call(this, $element, options);
 
-    $element.append(this.convertToOptions(data));
+    this.addOptions(this.convertToOptions(data));
   }
 
   Utils.Extend(ArrayAdapter, SelectAdapter);
@@ -3082,7 +3085,7 @@ define('select2/data/array',[
     if ($option.length === 0) {
       $option = this.option(data);
 
-      this.$element.append($option);
+      this.addOptions([$option]);
     }
 
     ArrayAdapter.__super__.select.call(this, data);
@@ -3310,7 +3313,7 @@ define('select2/data/tags',[
         var $option = self.option(tag);
         $option.attr('data-select2-tag', true);
 
-        self.$element.append($option);
+        self.addOptions([$option]);
 
         self.insertTag(data, tag);
       }
@@ -4496,6 +4499,15 @@ define('select2/options',[
     }
 
     this.options = Defaults.apply(this.options);
+
+    if ($element && $element.is('input')) {
+      var InputCompat = require(this.get('amdBase') + 'compat/inputData');
+
+      this.options.dataAdapter = Utils.Decorate(
+        this.options.dataAdapter,
+        InputCompat
+      );
+    }
   }
 
   Options.prototype.fromElement = function ($e) {
@@ -5413,6 +5425,112 @@ define('select2/compat/initSelection',[
   return InitSelection;
 });
 
+define('select2/compat/inputData',[
+  'jquery'
+], function ($) {
+  function InputData (decorated, $element, options) {
+    this._currentData = [];
+    this._valueSeparator = options.get('valueSeparator') || ',';
+
+    decorated.call(this, $element, options);
+  }
+
+  InputData.prototype.current = function (_, callback) {
+    function getSelected (data, selectedIds) {
+      var selected = [];
+
+      if (data.selected || $.inArray(selectedIds, data.id) !== -1) {
+        selected.push(data);
+      }
+
+      if (data.children) {
+        selected.push.apply(selected, getSelected(data.children, selectedIds));
+      }
+
+      return selected;
+    }
+
+    var selected = [];
+
+    for (var d = 0; d < this._currentData.length; d++) {
+      var data = this._currentData[d];
+
+      selected.push.apply(
+        selected,
+        getSelected(
+          data,
+          this.$element.val().split(
+            this._valueSeparator
+          )
+        )
+      );
+    }
+
+    callback(selected);
+  };
+
+  InputData.prototype.select = function (_, data) {
+    if (!this.options.get('multiple')) {
+      this.current(function (allData) {
+        $.map(allData, function (data) {
+          data.selected = false;
+        });
+      });
+    }
+
+    data.selected = true;
+
+    this._syncValue();
+  };
+
+  InputData.prototype.unselect = function (_, data) {
+    data.selected = false;
+
+    this._syncValue();
+  };
+
+  InputData.prototype._syncValue = function () {
+    var self = this;
+
+    this.current(function (allData) {
+      self.$element.val(
+        allData.join(
+          self._valueSeparator
+        )
+      );
+      self.$element.trigger('change');
+    });
+  };
+
+  InputData.prototype.query = function (_, params, callback) {
+    var results = [];
+
+    for (var d = 0; d < this._currentData.length; d++) {
+      var data = this._currentData[d];
+
+      var matches = this.matches(params, data);
+
+      if (matches !== null) {
+        results.push(matches);
+      }
+    }
+
+    callback({
+      results: results
+    });
+  };
+
+  InputData.prototype.addOptions = function (_, $options) {
+    var options = $.map($options, function ($option) {
+      return $.data($option[0], 'data');
+    });
+
+    this._currentData.push.apply(this._currentData, options);
+  };
+
+  return InputData;
+});
+
 define('select2/compat/query',[
 
 ], function () {

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/js/select2.full.min.js


+ 16 - 4
dist/js/select2.js

@@ -2845,7 +2845,6 @@ define('select2/data/select',[
       var val = data.id;
 
       this.$element.val(val);
-
       this.$element.trigger('change');
     }
   };
@@ -2931,6 +2930,10 @@ define('select2/data/select',[
     });
   };
 
+  SelectAdapter.prototype.addOptions = function ($options) {
+    this.$element.append($options);
+  };
+
   SelectAdapter.prototype.option = function (data) {
     var option;
 
@@ -3071,7 +3074,7 @@ define('select2/data/array',[
 
     ArrayAdapter.__super__.constructor.call(this, $element, options);
 
-    $element.append(this.convertToOptions(data));
+    this.addOptions(this.convertToOptions(data));
   }
 
   Utils.Extend(ArrayAdapter, SelectAdapter);
@@ -3082,7 +3085,7 @@ define('select2/data/array',[
     if ($option.length === 0) {
       $option = this.option(data);
 
-      this.$element.append($option);
+      this.addOptions([$option]);
     }
 
     ArrayAdapter.__super__.select.call(this, data);
@@ -3310,7 +3313,7 @@ define('select2/data/tags',[
         var $option = self.option(tag);
         $option.attr('data-select2-tag', true);
 
-        self.$element.append($option);
+        self.addOptions([$option]);
 
         self.insertTag(data, tag);
       }
@@ -4496,6 +4499,15 @@ define('select2/options',[
     }
 
     this.options = Defaults.apply(this.options);
+
+    if ($element && $element.is('input')) {
+      var InputCompat = require(this.get('amdBase') + 'compat/inputData');
+
+      this.options.dataAdapter = Utils.Decorate(
+        this.options.dataAdapter,
+        InputCompat
+      );
+    }
   }
 
   Options.prototype.fromElement = function ($e) {

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/js/select2.min.js


+ 105 - 0
src/js/select2/compat/inputData.js

@@ -0,0 +1,105 @@
+define([
+  'jquery'
+], function ($) {
+  function InputData (decorated, $element, options) {
+    this._currentData = [];
+    this._valueSeparator = options.get('valueSeparator') || ',';
+
+    decorated.call(this, $element, options);
+  }
+
+  InputData.prototype.current = function (_, callback) {
+    function getSelected (data, selectedIds) {
+      var selected = [];
+
+      if (data.selected || $.inArray(selectedIds, data.id) !== -1) {
+        selected.push(data);
+      }
+
+      if (data.children) {
+        selected.push.apply(selected, getSelected(data.children, selectedIds));
+      }
+
+      return selected;
+    }
+
+    var selected = [];
+
+    for (var d = 0; d < this._currentData.length; d++) {
+      var data = this._currentData[d];
+
+      selected.push.apply(
+        selected,
+        getSelected(
+          data,
+          this.$element.val().split(
+            this._valueSeparator
+          )
+        )
+      );
+    }
+
+    callback(selected);
+  };
+
+  InputData.prototype.select = function (_, data) {
+    if (!this.options.get('multiple')) {
+      this.current(function (allData) {
+        $.map(allData, function (data) {
+          data.selected = false;
+        });
+      });
+    }
+
+    data.selected = true;
+
+    this._syncValue();
+  };
+
+  InputData.prototype.unselect = function (_, data) {
+    data.selected = false;
+
+    this._syncValue();
+  };
+
+  InputData.prototype._syncValue = function () {
+    var self = this;
+
+    this.current(function (allData) {
+      self.$element.val(
+        allData.join(
+          self._valueSeparator
+        )
+      );
+      self.$element.trigger('change');
+    });
+  };
+
+  InputData.prototype.query = function (_, params, callback) {
+    var results = [];
+
+    for (var d = 0; d < this._currentData.length; d++) {
+      var data = this._currentData[d];
+
+      var matches = this.matches(params, data);
+
+      if (matches !== null) {
+        results.push(matches);
+      }
+    }
+
+    callback({
+      results: results
+    });
+  };
+
+  InputData.prototype.addOptions = function (_, $options) {
+    var options = $.map($options, function ($option) {
+      return $.data($option[0], 'data');
+    });
+
+    this._currentData.push.apply(this._currentData, options);
+  };
+
+  return InputData;
+});

+ 2 - 2
src/js/select2/data/array.js

@@ -8,7 +8,7 @@ define([
 
     ArrayAdapter.__super__.constructor.call(this, $element, options);
 
-    $element.append(this.convertToOptions(data));
+    this.addOptions(this.convertToOptions(data));
   }
 
   Utils.Extend(ArrayAdapter, SelectAdapter);
@@ -19,7 +19,7 @@ define([
     if ($option.length === 0) {
       $option = this.option(data);
 
-      this.$element.append($option);
+      this.addOptions([$option]);
     }
 
     ArrayAdapter.__super__.select.call(this, data);

+ 4 - 1
src/js/select2/data/select.js

@@ -61,7 +61,6 @@ define([
       var val = data.id;
 
       this.$element.val(val);
-
       this.$element.trigger('change');
     }
   };
@@ -147,6 +146,10 @@ define([
     });
   };
 
+  SelectAdapter.prototype.addOptions = function ($options) {
+    this.$element.append($options);
+  };
+
   SelectAdapter.prototype.option = function (data) {
     var option;
 

+ 1 - 1
src/js/select2/data/tags.js

@@ -71,7 +71,7 @@ define([
         var $option = self.option(tag);
         $option.attr('data-select2-tag', true);
 
-        self.$element.append($option);
+        self.addOptions([$option]);
 
         self.insertTag(data, tag);
       }

+ 9 - 0
src/js/select2/options.js

@@ -11,6 +11,15 @@ define([
     }
 
     this.options = Defaults.apply(this.options);
+
+    if ($element && $element.is('input')) {
+      var InputCompat = require(this.get('amdBase') + 'compat/inputData');
+
+      this.options.dataAdapter = Utils.Decorate(
+        this.options.dataAdapter,
+        InputCompat
+      );
+    }
   }
 
   Options.prototype.fromElement = function ($e) {

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác