Jelajahi Sumber

Add a module for attaching the dropdown to the body

In Select2 3.x, the dropdown is attached to the body element and
it is floated above all other elements.

In Select2 4.x, the dropdown is attached directly to the Select2
container, which allows us to skip any special placing logic. This
happens to be how Chosen currently does it, and it prevents us
from having the dropdown display up, as well as a few other strange
issues that can't be prevented.

This new module will most likely become the default, as it matches
the functionality of Select2 3.x and has quite a few advantages.
The other positioning code will need to be broken out into a
separate module in the future.
Kevin Brown 11 tahun lalu
induk
melakukan
6a0c002f94

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

@@ -230,8 +230,8 @@ define('select2/results',[
     this.$results.append($options);
   };
 
-  Results.prototype.position = function ($results, $container) {
-    var $resultsContainer = $container.find('.select2-results');
+  Results.prototype.position = function ($results, $dropdown) {
+    var $resultsContainer = $dropdown.find('.select2-results');
     $resultsContainer.append($results);
   };
 
@@ -2812,6 +2812,79 @@ define('select2/dropdown/infiniteScroll',[
   return InfiniteScroll;
 });
 
+define('select2/dropdown/attachBody',[
+
+], function () {
+  function AttachBody (decorated, $element, options) {
+    decorated.call(this, $element, options);
+  }
+
+  AttachBody.prototype.bind = function (decorated, container, $container) {
+    var self = this;
+
+    decorated.call(this, container, $container);
+
+    container.on('open', function () {
+      self._showDropdown();
+    });
+
+    container.on('close', function () {
+      self._hideDropdown();
+    });
+
+    this.$dropdownContainer.on('mousedown', function (evt) {
+      evt.stopPropagation();
+    });
+  };
+
+  AttachBody.prototype.position = function (decorated, $dropdown, $container) {
+    // Clone all of the container classes
+    $dropdown.attr('class', $container.attr('class'));
+
+    $dropdown.removeClass('select2');
+    $dropdown.addClass('select2-container--open');
+
+    $dropdown.css({
+      position: 'absolute'
+    });
+
+    $dropdown.width($container.outerWidth(false));
+
+    this.$container = $container;
+  };
+
+  AttachBody.prototype.render = function (decorated) {
+    var $container = $('<span></span>');
+
+    var $dropdown = decorated.call(this);
+    $container.append($dropdown);
+
+    this.$dropdownContainer = $container;
+
+    return $container;
+  };
+
+  AttachBody.prototype._hideDropdown = function (decorated) {
+    this.$dropdownContainer.detach();
+  };
+
+  AttachBody.prototype._positionDropdown = function () {
+    var css = this.$container.offset();
+
+    css.top += this.$container.outerHeight(true);
+
+    this.$dropdownContainer.css(css);
+  };
+
+  AttachBody.prototype._showDropdown = function (decorated) {
+    this.$dropdownContainer.appendTo(document.body);
+
+    this._positionDropdown();
+  };
+
+  return AttachBody;
+});
+
 define('select2/i18n/en',[],function () {
   return {
     errorLoading: function () {
@@ -2884,6 +2957,7 @@ define('select2/defaults',[
   './dropdown/search',
   './dropdown/hidePlaceholder',
   './dropdown/infiniteScroll',
+  './dropdown/attachBody',
 
   './i18n/en'
 ], function ($, ResultsList,
@@ -2892,6 +2966,7 @@ define('select2/defaults',[
              Utils, Translation, DIACRITICS,
              SelectData, ArrayData, AjaxData, Tags, MinimumInputLength,
              Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll,
+             AttachBody,
              EnglishTranslation) {
   function Defaults () {
     this.reset();
@@ -2948,6 +3023,11 @@ define('select2/defaults',[
 
         options.dropdownAdapter = SearchableDropdown;
       }
+
+      options.dropdownAdapter = Utils.Decorate(
+        options.dropdownAdapter,
+        AttachBody
+      );
     }
 
     if (options.selectionAdapter == null) {
@@ -3162,10 +3242,9 @@ define('select2/core',[
 
     var ResultsAdapter = this.options.get('resultsAdapter');
     this.results = new ResultsAdapter($element, this.options, this.data);
-
     this.$results = this.results.render();
 
-    this.results.position(this.$results, $container);
+    this.results.position(this.$results, this.$dropdown);
 
     // Bind events
 

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

@@ -230,8 +230,8 @@ define('select2/results',[
     this.$results.append($options);
   };
 
-  Results.prototype.position = function ($results, $container) {
-    var $resultsContainer = $container.find('.select2-results');
+  Results.prototype.position = function ($results, $dropdown) {
+    var $resultsContainer = $dropdown.find('.select2-results');
     $resultsContainer.append($results);
   };
 
@@ -2812,6 +2812,79 @@ define('select2/dropdown/infiniteScroll',[
   return InfiniteScroll;
 });
 
+define('select2/dropdown/attachBody',[
+
+], function () {
+  function AttachBody (decorated, $element, options) {
+    decorated.call(this, $element, options);
+  }
+
+  AttachBody.prototype.bind = function (decorated, container, $container) {
+    var self = this;
+
+    decorated.call(this, container, $container);
+
+    container.on('open', function () {
+      self._showDropdown();
+    });
+
+    container.on('close', function () {
+      self._hideDropdown();
+    });
+
+    this.$dropdownContainer.on('mousedown', function (evt) {
+      evt.stopPropagation();
+    });
+  };
+
+  AttachBody.prototype.position = function (decorated, $dropdown, $container) {
+    // Clone all of the container classes
+    $dropdown.attr('class', $container.attr('class'));
+
+    $dropdown.removeClass('select2');
+    $dropdown.addClass('select2-container--open');
+
+    $dropdown.css({
+      position: 'absolute'
+    });
+
+    $dropdown.width($container.outerWidth(false));
+
+    this.$container = $container;
+  };
+
+  AttachBody.prototype.render = function (decorated) {
+    var $container = $('<span></span>');
+
+    var $dropdown = decorated.call(this);
+    $container.append($dropdown);
+
+    this.$dropdownContainer = $container;
+
+    return $container;
+  };
+
+  AttachBody.prototype._hideDropdown = function (decorated) {
+    this.$dropdownContainer.detach();
+  };
+
+  AttachBody.prototype._positionDropdown = function () {
+    var css = this.$container.offset();
+
+    css.top += this.$container.outerHeight(true);
+
+    this.$dropdownContainer.css(css);
+  };
+
+  AttachBody.prototype._showDropdown = function (decorated) {
+    this.$dropdownContainer.appendTo(document.body);
+
+    this._positionDropdown();
+  };
+
+  return AttachBody;
+});
+
 define('select2/i18n/en',[],function () {
   return {
     errorLoading: function () {
@@ -2884,6 +2957,7 @@ define('select2/defaults',[
   './dropdown/search',
   './dropdown/hidePlaceholder',
   './dropdown/infiniteScroll',
+  './dropdown/attachBody',
 
   './i18n/en'
 ], function ($, ResultsList,
@@ -2892,6 +2966,7 @@ define('select2/defaults',[
              Utils, Translation, DIACRITICS,
              SelectData, ArrayData, AjaxData, Tags, MinimumInputLength,
              Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll,
+             AttachBody,
              EnglishTranslation) {
   function Defaults () {
     this.reset();
@@ -2948,6 +3023,11 @@ define('select2/defaults',[
 
         options.dropdownAdapter = SearchableDropdown;
       }
+
+      options.dropdownAdapter = Utils.Decorate(
+        options.dropdownAdapter,
+        AttachBody
+      );
     }
 
     if (options.selectionAdapter == null) {
@@ -3162,10 +3242,9 @@ define('select2/core',[
 
     var ResultsAdapter = this.options.get('resultsAdapter');
     this.results = new ResultsAdapter($element, this.options, this.data);
-
     this.$results = this.results.render();
 
-    this.results.position(this.$results, $container);
+    this.results.position(this.$results, this.$dropdown);
 
     // Bind events
 

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

@@ -9765,8 +9765,8 @@ define('select2/results',[
     this.$results.append($options);
   };
 
-  Results.prototype.position = function ($results, $container) {
-    var $resultsContainer = $container.find('.select2-results');
+  Results.prototype.position = function ($results, $dropdown) {
+    var $resultsContainer = $dropdown.find('.select2-results');
     $resultsContainer.append($results);
   };
 
@@ -12347,6 +12347,79 @@ define('select2/dropdown/infiniteScroll',[
   return InfiniteScroll;
 });
 
+define('select2/dropdown/attachBody',[
+
+], function () {
+  function AttachBody (decorated, $element, options) {
+    decorated.call(this, $element, options);
+  }
+
+  AttachBody.prototype.bind = function (decorated, container, $container) {
+    var self = this;
+
+    decorated.call(this, container, $container);
+
+    container.on('open', function () {
+      self._showDropdown();
+    });
+
+    container.on('close', function () {
+      self._hideDropdown();
+    });
+
+    this.$dropdownContainer.on('mousedown', function (evt) {
+      evt.stopPropagation();
+    });
+  };
+
+  AttachBody.prototype.position = function (decorated, $dropdown, $container) {
+    // Clone all of the container classes
+    $dropdown.attr('class', $container.attr('class'));
+
+    $dropdown.removeClass('select2');
+    $dropdown.addClass('select2-container--open');
+
+    $dropdown.css({
+      position: 'absolute'
+    });
+
+    $dropdown.width($container.outerWidth(false));
+
+    this.$container = $container;
+  };
+
+  AttachBody.prototype.render = function (decorated) {
+    var $container = $('<span></span>');
+
+    var $dropdown = decorated.call(this);
+    $container.append($dropdown);
+
+    this.$dropdownContainer = $container;
+
+    return $container;
+  };
+
+  AttachBody.prototype._hideDropdown = function (decorated) {
+    this.$dropdownContainer.detach();
+  };
+
+  AttachBody.prototype._positionDropdown = function () {
+    var css = this.$container.offset();
+
+    css.top += this.$container.outerHeight(true);
+
+    this.$dropdownContainer.css(css);
+  };
+
+  AttachBody.prototype._showDropdown = function (decorated) {
+    this.$dropdownContainer.appendTo(document.body);
+
+    this._positionDropdown();
+  };
+
+  return AttachBody;
+});
+
 define('select2/i18n/en',[],function () {
   return {
     errorLoading: function () {
@@ -12419,6 +12492,7 @@ define('select2/defaults',[
   './dropdown/search',
   './dropdown/hidePlaceholder',
   './dropdown/infiniteScroll',
+  './dropdown/attachBody',
 
   './i18n/en'
 ], function ($, ResultsList,
@@ -12427,6 +12501,7 @@ define('select2/defaults',[
              Utils, Translation, DIACRITICS,
              SelectData, ArrayData, AjaxData, Tags, MinimumInputLength,
              Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll,
+             AttachBody,
              EnglishTranslation) {
   function Defaults () {
     this.reset();
@@ -12483,6 +12558,11 @@ define('select2/defaults',[
 
         options.dropdownAdapter = SearchableDropdown;
       }
+
+      options.dropdownAdapter = Utils.Decorate(
+        options.dropdownAdapter,
+        AttachBody
+      );
     }
 
     if (options.selectionAdapter == null) {
@@ -12697,10 +12777,9 @@ define('select2/core',[
 
     var ResultsAdapter = this.options.get('resultsAdapter');
     this.results = new ResultsAdapter($element, this.options, this.data);
-
     this.$results = this.results.render();
 
-    this.results.position(this.$results, $container);
+    this.results.position(this.$results, this.$dropdown);
 
     // Bind events
 

File diff ditekan karena terlalu besar
+ 0 - 0
dist/js/select2.full.min.js


+ 83 - 4
dist/js/select2.js

@@ -658,8 +658,8 @@ define('select2/results',[
     this.$results.append($options);
   };
 
-  Results.prototype.position = function ($results, $container) {
-    var $resultsContainer = $container.find('.select2-results');
+  Results.prototype.position = function ($results, $dropdown) {
+    var $resultsContainer = $dropdown.find('.select2-results');
     $resultsContainer.append($results);
   };
 
@@ -3240,6 +3240,79 @@ define('select2/dropdown/infiniteScroll',[
   return InfiniteScroll;
 });
 
+define('select2/dropdown/attachBody',[
+
+], function () {
+  function AttachBody (decorated, $element, options) {
+    decorated.call(this, $element, options);
+  }
+
+  AttachBody.prototype.bind = function (decorated, container, $container) {
+    var self = this;
+
+    decorated.call(this, container, $container);
+
+    container.on('open', function () {
+      self._showDropdown();
+    });
+
+    container.on('close', function () {
+      self._hideDropdown();
+    });
+
+    this.$dropdownContainer.on('mousedown', function (evt) {
+      evt.stopPropagation();
+    });
+  };
+
+  AttachBody.prototype.position = function (decorated, $dropdown, $container) {
+    // Clone all of the container classes
+    $dropdown.attr('class', $container.attr('class'));
+
+    $dropdown.removeClass('select2');
+    $dropdown.addClass('select2-container--open');
+
+    $dropdown.css({
+      position: 'absolute'
+    });
+
+    $dropdown.width($container.outerWidth(false));
+
+    this.$container = $container;
+  };
+
+  AttachBody.prototype.render = function (decorated) {
+    var $container = $('<span></span>');
+
+    var $dropdown = decorated.call(this);
+    $container.append($dropdown);
+
+    this.$dropdownContainer = $container;
+
+    return $container;
+  };
+
+  AttachBody.prototype._hideDropdown = function (decorated) {
+    this.$dropdownContainer.detach();
+  };
+
+  AttachBody.prototype._positionDropdown = function () {
+    var css = this.$container.offset();
+
+    css.top += this.$container.outerHeight(true);
+
+    this.$dropdownContainer.css(css);
+  };
+
+  AttachBody.prototype._showDropdown = function (decorated) {
+    this.$dropdownContainer.appendTo(document.body);
+
+    this._positionDropdown();
+  };
+
+  return AttachBody;
+});
+
 define('select2/i18n/en',[],function () {
   return {
     errorLoading: function () {
@@ -3312,6 +3385,7 @@ define('select2/defaults',[
   './dropdown/search',
   './dropdown/hidePlaceholder',
   './dropdown/infiniteScroll',
+  './dropdown/attachBody',
 
   './i18n/en'
 ], function ($, ResultsList,
@@ -3320,6 +3394,7 @@ define('select2/defaults',[
              Utils, Translation, DIACRITICS,
              SelectData, ArrayData, AjaxData, Tags, MinimumInputLength,
              Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll,
+             AttachBody,
              EnglishTranslation) {
   function Defaults () {
     this.reset();
@@ -3376,6 +3451,11 @@ define('select2/defaults',[
 
         options.dropdownAdapter = SearchableDropdown;
       }
+
+      options.dropdownAdapter = Utils.Decorate(
+        options.dropdownAdapter,
+        AttachBody
+      );
     }
 
     if (options.selectionAdapter == null) {
@@ -3590,10 +3670,9 @@ define('select2/core',[
 
     var ResultsAdapter = this.options.get('resultsAdapter');
     this.results = new ResultsAdapter($element, this.options, this.data);
-
     this.$results = this.results.render();
 
-    this.results.position(this.$results, $container);
+    this.results.position(this.$results, this.$dropdown);
 
     // Bind events
 

File diff ditekan karena terlalu besar
+ 0 - 0
dist/js/select2.min.js


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

@@ -44,7 +44,7 @@ define([
     this.results = new ResultsAdapter($element, this.options, this.data);
     this.$results = this.results.render();
 
-    this.results.position(this.$results, $container);
+    this.results.position(this.$results, this.$dropdown);
 
     // Bind events
 

+ 7 - 0
src/js/select2/defaults.js

@@ -22,6 +22,7 @@ define([
   './dropdown/search',
   './dropdown/hidePlaceholder',
   './dropdown/infiniteScroll',
+  './dropdown/attachBody',
 
   './i18n/en'
 ], function ($, ResultsList,
@@ -30,6 +31,7 @@ define([
              Utils, Translation, DIACRITICS,
              SelectData, ArrayData, AjaxData, Tags, MinimumInputLength,
              Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll,
+             AttachBody,
              EnglishTranslation) {
   function Defaults () {
     this.reset();
@@ -86,6 +88,11 @@ define([
 
         options.dropdownAdapter = SearchableDropdown;
       }
+
+      options.dropdownAdapter = Utils.Decorate(
+        options.dropdownAdapter,
+        AttachBody
+      );
     }
 
     if (options.selectionAdapter == null) {

+ 72 - 0
src/js/select2/dropdown/attachBody.js

@@ -0,0 +1,72 @@
+define([
+
+], function () {
+  function AttachBody (decorated, $element, options) {
+    decorated.call(this, $element, options);
+  }
+
+  AttachBody.prototype.bind = function (decorated, container, $container) {
+    var self = this;
+
+    decorated.call(this, container, $container);
+
+    container.on('open', function () {
+      self._showDropdown();
+    });
+
+    container.on('close', function () {
+      self._hideDropdown();
+    });
+
+    this.$dropdownContainer.on('mousedown', function (evt) {
+      evt.stopPropagation();
+    });
+  };
+
+  AttachBody.prototype.position = function (decorated, $dropdown, $container) {
+    // Clone all of the container classes
+    $dropdown.attr('class', $container.attr('class'));
+
+    $dropdown.removeClass('select2');
+    $dropdown.addClass('select2-container--open');
+
+    $dropdown.css({
+      position: 'absolute'
+    });
+
+    $dropdown.width($container.outerWidth(false));
+
+    this.$container = $container;
+  };
+
+  AttachBody.prototype.render = function (decorated) {
+    var $container = $('<span></span>');
+
+    var $dropdown = decorated.call(this);
+    $container.append($dropdown);
+
+    this.$dropdownContainer = $container;
+
+    return $container;
+  };
+
+  AttachBody.prototype._hideDropdown = function (decorated) {
+    this.$dropdownContainer.detach();
+  };
+
+  AttachBody.prototype._positionDropdown = function () {
+    var css = this.$container.offset();
+
+    css.top += this.$container.outerHeight(true);
+
+    this.$dropdownContainer.css(css);
+  };
+
+  AttachBody.prototype._showDropdown = function (decorated) {
+    this.$dropdownContainer.appendTo(document.body);
+
+    this._positionDropdown();
+  };
+
+  return AttachBody;
+});

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

@@ -72,8 +72,8 @@ define([
     this.$results.append($options);
   };
 
-  Results.prototype.position = function ($results, $container) {
-    var $resultsContainer = $container.find('.select2-results');
+  Results.prototype.position = function ($results, $dropdown) {
+    var $resultsContainer = $dropdown.find('.select2-results');
     $resultsContainer.append($results);
   };
 

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini