1
0
mirror of synced 2025-02-03 21:59:24 +03:00

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.
This commit is contained in:
Kevin Brown 2014-11-25 15:39:42 -05:00
parent 31c09315c8
commit 6a0c002f94
10 changed files with 416 additions and 21 deletions

View File

@ -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

View File

@ -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

View File

@ -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 suppressed because one or more lines are too long

87
dist/js/select2.js vendored
View File

@ -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 suppressed because one or more lines are too long

View File

@ -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

View File

@ -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
src/js/select2/dropdown/attachBody.js vendored Normal file
View File

@ -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;
});

View File

@ -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);
};