1
0
mirror of synced 2024-11-21 20:46:07 +03:00

Add back *css* options through an adapter

The old functionality where classes were directly copied to the
container can be done by setting `dropdownCssClass: ':all:'` when
initializing Select2.

This closes https://github.com/select2/select2/issues/2879.
This commit is contained in:
Kevin Brown 2015-04-05 21:58:02 -04:00
parent 4fc874a3ae
commit f3f1b31958
12 changed files with 639 additions and 35 deletions

View File

@ -10,9 +10,12 @@ module.exports = function (grunt) {
fullIncludes = [
'jquery',
'select2/compat/matcher',
'select2/compat/containerCss',
'select2/compat/dropdownCss',
'select2/compat/initSelection',
'select2/compat/inputData',
'select2/compat/matcher',
'select2/compat/query',
'select2/dropdown/attachContainer',

View File

@ -4428,6 +4428,19 @@ S2.define('select2/defaults',[
);
}
if (
options.dropdownCssClass != null ||
options.dropdownCss != null ||
options.adaptDropdownCssClass != null
) {
var DropdownCSS = require(options.amdBase + 'compat/dropdownCss');
options.dropdownAdapter = Utils.Decorate(
options.dropdownAdapter,
DropdownCSS
);
}
options.dropdownAdapter = Utils.Decorate(
options.dropdownAdapter,
AttachBody
@ -4463,6 +4476,19 @@ S2.define('select2/defaults',[
);
}
if (
options.containerCssClass != null ||
options.containerCss != null ||
options.adaptContainerCssClass != null
) {
var ContainerCSS = require(options.amdBase + 'compat/containerCss');
options.selectionAdapter = Utils.Decorate(
options.selectionAdapter,
ContainerCSS
);
}
options.selectionAdapter = Utils.Decorate(
options.selectionAdapter,
EventRelay
@ -5283,47 +5309,162 @@ S2.define('select2/core',[
return Select2;
});
S2.define('select2/compat/matcher',[
S2.define('select2/compat/utils',[
'jquery'
], function ($) {
function oldMatcher (matcher) {
function wrappedMatcher (params, data) {
var match = $.extend(true, {}, data);
function syncCssClasses ($dest, $src, adapter) {
var classes, replacements = [], adapted;
if (params.term == null || $.trim(params.term) === '') {
return match;
}
classes = $.trim($dest.attr('class'));
if (data.children) {
for (var c = data.children.length - 1; c >= 0; c--) {
var child = data.children[c];
if (classes) {
classes = '' + classes; // for IE which returns object
// Check if the child object matches
// The old matcher returned a boolean true or false
var doesMatch = matcher(params.term, child.text, child);
// If the child didn't match, pop it off
if (!doesMatch) {
match.children.splice(c, 1);
}
$(classes.split(/\s+/)).each(function () {
// Save all Select2 classes
if (this.indexOf('select2-') === 0) {
replacements.push(this);
}
if (match.children.length > 0) {
return match;
}
}
if (matcher(params.term, data.text, data)) {
return match;
}
return null;
});
}
return wrappedMatcher;
classes = $.trim($src.attr('class'));
if (classes) {
classes = '' + classes; // for IE which returns object
$(classes.split(/\s+/)).each(function () {
// Only adapt non-Select2 classes
if (this.indexOf('select2-') !== 0) {
adapted = adapter(this);
if (adapted != null) {
replacements.push(adapted);
}
}
});
}
$dest.attr('class', replacements.join(' '));
}
return oldMatcher;
return {
syncCssClasses: syncCssClasses
};
});
S2.define('select2/compat/containerCss',[
'jquery',
'./utils'
], function ($, CompatUtils) {
// No-op CSS adapter that discards all classes by default
function _containerAdapter (clazz) {
return null;
}
function ContainerCSS () { }
ContainerCSS.prototype.render = function (decorated) {
var $container = decorated.call(this);
var containerCssClass = this.options.get('containerCssClass') || '';
if ($.isFunction(containerCssClass)) {
containerCssClass = containerCssClass(this.$element);
}
var containerCssAdapter = this.options.get('adaptContainerCssClass');
containerCssAdapter = containerCssAdapter || _containerAdapter;
if (containerCssClass.indexOf(':all:') !== -1) {
containerCssClass = containerCssClass.replace(':all', '');
var _cssAdapter = containerCssAdapter;
containerCssAdapter = function (clazz) {
var adapted = _cssAdapter(clazz);
if (adapted != null) {
// Append the old one along with the adapted one
return adapted + ' ' + clazz;
}
return clazz;
};
}
var containerCss = this.options.get('containerCss') || {};
if ($.isFunction(containerCss)) {
containerCss = containerCss(this.$element);
}
CompatUtils.syncCssClasses($container, this.$element, containerCssAdapter);
$container.css(containerCss);
$container.addClass(containerCssClass);
return $container;
};
return ContainerCSS;
});
S2.define('select2/compat/dropdownCss',[
'jquery',
'./utils'
], function ($, CompatUtils) {
// No-op CSS adapter that discards all classes by default
function _dropdownAdapter (clazz) {
return null;
}
function DropdownCSS () { }
DropdownCSS.prototype.render = function (decorated) {
var $dropdown = decorated.call(this);
var dropdownCssClass = this.options.get('dropdownCssClass') || '';
if ($.isFunction(dropdownCssClass)) {
dropdownCssClass = dropdownCssClass(this.$element);
}
var dropdownCssAdapter = this.options.get('adaptDropdownCssClass');
dropdownCssAdapter = dropdownCssAdapter || _dropdownAdapter;
if (dropdownCssClass.indexOf(':all:') !== -1) {
dropdownCssClass = dropdownCssClass.replace(':all', '');
var _cssAdapter = dropdownCssAdapter;
dropdownCssAdapter = function (clazz) {
var adapted = _cssAdapter(clazz);
if (adapted != null) {
// Append the old one along with the adapted one
return adapted + ' ' + clazz;
}
return clazz;
};
}
var dropdownCss = this.options.get('dropdownCss') || {};
if ($.isFunction(dropdownCss)) {
dropdownCss = dropdownCss(this.$element);
}
CompatUtils.syncCssClasses($dropdown, this.$element, dropdownCssAdapter);
$dropdown.css(dropdownCss);
$dropdown.addClass(dropdownCssClass);
return $dropdown;
};
return DropdownCSS;
});
S2.define('select2/compat/initSelection',[
@ -5497,6 +5638,49 @@ S2.define('select2/compat/inputData',[
return InputData;
});
S2.define('select2/compat/matcher',[
'jquery'
], function ($) {
function oldMatcher (matcher) {
function wrappedMatcher (params, data) {
var match = $.extend(true, {}, data);
if (params.term == null || $.trim(params.term) === '') {
return match;
}
if (data.children) {
for (var c = data.children.length - 1; c >= 0; c--) {
var child = data.children[c];
// Check if the child object matches
// The old matcher returned a boolean true or false
var doesMatch = matcher(params.term, child.text, child);
// If the child didn't match, pop it off
if (!doesMatch) {
match.children.splice(c, 1);
}
}
if (match.children.length > 0) {
return match;
}
}
if (matcher(params.term, data.text, data)) {
return match;
}
return null;
}
return wrappedMatcher;
}
return oldMatcher;
});
S2.define('select2/compat/query',[
], function () {

File diff suppressed because one or more lines are too long

26
dist/js/select2.js vendored
View File

@ -4428,6 +4428,19 @@ S2.define('select2/defaults',[
);
}
if (
options.dropdownCssClass != null ||
options.dropdownCss != null ||
options.adaptDropdownCssClass != null
) {
var DropdownCSS = require(options.amdBase + 'compat/dropdownCss');
options.dropdownAdapter = Utils.Decorate(
options.dropdownAdapter,
DropdownCSS
);
}
options.dropdownAdapter = Utils.Decorate(
options.dropdownAdapter,
AttachBody
@ -4463,6 +4476,19 @@ S2.define('select2/defaults',[
);
}
if (
options.containerCssClass != null ||
options.containerCss != null ||
options.adaptContainerCssClass != null
) {
var ContainerCSS = require(options.amdBase + 'compat/containerCss');
options.selectionAdapter = Utils.Decorate(
options.selectionAdapter,
ContainerCSS
);
}
options.selectionAdapter = Utils.Decorate(
options.selectionAdapter,
EventRelay

File diff suppressed because one or more lines are too long

56
src/js/select2/compat/containerCss.js vendored Normal file
View File

@ -0,0 +1,56 @@
define([
'jquery',
'./utils'
], function ($, CompatUtils) {
// No-op CSS adapter that discards all classes by default
function _containerAdapter (clazz) {
return null;
}
function ContainerCSS () { }
ContainerCSS.prototype.render = function (decorated) {
var $container = decorated.call(this);
var containerCssClass = this.options.get('containerCssClass') || '';
if ($.isFunction(containerCssClass)) {
containerCssClass = containerCssClass(this.$element);
}
var containerCssAdapter = this.options.get('adaptContainerCssClass');
containerCssAdapter = containerCssAdapter || _containerAdapter;
if (containerCssClass.indexOf(':all:') !== -1) {
containerCssClass = containerCssClass.replace(':all', '');
var _cssAdapter = containerCssAdapter;
containerCssAdapter = function (clazz) {
var adapted = _cssAdapter(clazz);
if (adapted != null) {
// Append the old one along with the adapted one
return adapted + ' ' + clazz;
}
return clazz;
};
}
var containerCss = this.options.get('containerCss') || {};
if ($.isFunction(containerCss)) {
containerCss = containerCss(this.$element);
}
CompatUtils.syncCssClasses($container, this.$element, containerCssAdapter);
$container.css(containerCss);
$container.addClass(containerCssClass);
return $container;
};
return ContainerCSS;
});

56
src/js/select2/compat/dropdownCss.js vendored Normal file
View File

@ -0,0 +1,56 @@
define([
'jquery',
'./utils'
], function ($, CompatUtils) {
// No-op CSS adapter that discards all classes by default
function _dropdownAdapter (clazz) {
return null;
}
function DropdownCSS () { }
DropdownCSS.prototype.render = function (decorated) {
var $dropdown = decorated.call(this);
var dropdownCssClass = this.options.get('dropdownCssClass') || '';
if ($.isFunction(dropdownCssClass)) {
dropdownCssClass = dropdownCssClass(this.$element);
}
var dropdownCssAdapter = this.options.get('adaptDropdownCssClass');
dropdownCssAdapter = dropdownCssAdapter || _dropdownAdapter;
if (dropdownCssClass.indexOf(':all:') !== -1) {
dropdownCssClass = dropdownCssClass.replace(':all', '');
var _cssAdapter = dropdownCssAdapter;
dropdownCssAdapter = function (clazz) {
var adapted = _cssAdapter(clazz);
if (adapted != null) {
// Append the old one along with the adapted one
return adapted + ' ' + clazz;
}
return clazz;
};
}
var dropdownCss = this.options.get('dropdownCss') || {};
if ($.isFunction(dropdownCss)) {
dropdownCss = dropdownCss(this.$element);
}
CompatUtils.syncCssClasses($dropdown, this.$element, dropdownCssAdapter);
$dropdown.css(dropdownCss);
$dropdown.addClass(dropdownCssClass);
return $dropdown;
};
return DropdownCSS;
});

43
src/js/select2/compat/utils.js vendored Normal file
View File

@ -0,0 +1,43 @@
define([
'jquery'
], function ($) {
function syncCssClasses ($dest, $src, adapter) {
var classes, replacements = [], adapted;
classes = $.trim($dest.attr('class'));
if (classes) {
classes = '' + classes; // for IE which returns object
$(classes.split(/\s+/)).each(function () {
// Save all Select2 classes
if (this.indexOf('select2-') === 0) {
replacements.push(this);
}
});
}
classes = $.trim($src.attr('class'));
if (classes) {
classes = '' + classes; // for IE which returns object
$(classes.split(/\s+/)).each(function () {
// Only adapt non-Select2 classes
if (this.indexOf('select2-') !== 0) {
adapted = adapter(this);
if (adapted != null) {
replacements.push(adapted);
}
}
});
}
$dest.attr('class', replacements.join(' '));
}
return {
syncCssClasses: syncCssClasses
};
});

View File

@ -165,6 +165,19 @@ define([
);
}
if (
options.dropdownCssClass != null ||
options.dropdownCss != null ||
options.adaptDropdownCssClass != null
) {
var DropdownCSS = require(options.amdBase + 'compat/dropdownCss');
options.dropdownAdapter = Utils.Decorate(
options.dropdownAdapter,
DropdownCSS
);
}
options.dropdownAdapter = Utils.Decorate(
options.dropdownAdapter,
AttachBody
@ -200,6 +213,19 @@ define([
);
}
if (
options.containerCssClass != null ||
options.containerCss != null ||
options.adaptContainerCssClass != null
) {
var ContainerCSS = require(options.amdBase + 'compat/containerCss');
options.selectionAdapter = Utils.Decorate(
options.selectionAdapter,
ContainerCSS
);
}
options.selectionAdapter = Utils.Decorate(
options.selectionAdapter,
EventRelay

View File

@ -0,0 +1,104 @@
module('Dropdown - dropdownCssClass compatibility');
var $ = require('jquery');
var Utils = require('select2/utils');
var Options = require('select2/options');
var Dropdown = require('select2/dropdown');
var DropdownCSS = Utils.Decorate(
Dropdown,
require('select2/compat/dropdownCss')
);
test('all classes will be copied if :all: is used', function (assert) {
var $element = $('<select class="test copy works"></select>');
var options = new Options({
dropdownCssClass: ':all:'
});
var select = new DropdownCSS($element, options);
var $dropdown = select.render();
assert.ok($dropdown.hasClass('test'));
assert.ok($dropdown.hasClass('copy'));
assert.ok($dropdown.hasClass('works'));
assert.ok(!$dropdown.hasClass(':all:'));
});
test(':all: can be used with other classes', function (assert) {
var $element = $('<select class="test copy works"></select>');
var options = new Options({
dropdownCssClass: ':all: other'
});
var select = new DropdownCSS($element, options);
var $dropdown = select.render();
assert.ok($dropdown.hasClass('test'));
assert.ok($dropdown.hasClass('copy'));
assert.ok($dropdown.hasClass('works'));
assert.ok($dropdown.hasClass('other'));
assert.ok(!$dropdown.hasClass(':all:'));
});
test('classes can be passed in as a string', function (assert) {
var $element = $('<select class="test copy works"></select>');
var options = new Options({
dropdownCssClass: 'other'
});
var select = new DropdownCSS($element, options);
var $dropdown = select.render();
assert.ok($dropdown.hasClass('other'));
});
test('a function can be used based on the element', function (assert){
var $element = $('<select class="test"></select>');
var options = new Options({
dropdownCssClass: function ($element) {
return 'function';
}
});
var select = new DropdownCSS($element, options);
var $dropdown = select.render();
assert.ok($dropdown.hasClass('function'));
assert.ok(!$dropdown.hasClass('test'));
});
test(':all: works around custom adapters', function (assert) {
var $element = $('<select class="test"></select>');
var options = new Options({
dropdownCssClass: ':all: something',
adaptDropdownCssClass: function (clazz) {
return clazz + '-modified';
}
});
var select = new DropdownCSS($element, options);
var $dropdown = select.render();
assert.ok($dropdown.hasClass('something'));
assert.ok($dropdown.hasClass('test'));
assert.ok($dropdown.hasClass('test-modified'));
});
module('Dropdown - adaptDropdownCss compatibility');
test('only return when adapted', function (assert) {
var $element = $('<select class="original"></select>');
var options = new Options({
adaptDropdownCssClass: function (clazz) {
return 'modified';
}
});
var select = new DropdownCSS($element, options);
var $dropdown = select.render();
assert.ok(!$dropdown.hasClass('original'));
assert.ok($dropdown.hasClass('modified'));
});

View File

@ -0,0 +1,104 @@
module('Dropdown - containerCssClass compatibility');
var $ = require('jquery');
var Utils = require('select2/utils');
var Options = require('select2/options');
var SingleSelection = require('select2/selection/single');
var ContainerCSS = Utils.Decorate(
SingleSelection,
require('select2/compat/containerCss')
);
test('all classes will be copied if :all: is used', function (assert) {
var $element = $('<select class="test copy works"></select>');
var options = new Options({
containerCssClass: ':all:'
});
var select = new ContainerCSS($element, options);
var $container = select.render();
assert.ok($container.hasClass('test'));
assert.ok($container.hasClass('copy'));
assert.ok($container.hasClass('works'));
assert.ok(!$container.hasClass(':all:'));
});
test(':all: can be used with other classes', function (assert) {
var $element = $('<select class="test copy works"></select>');
var options = new Options({
containerCssClass: ':all: other'
});
var select = new ContainerCSS($element, options);
var $container = select.render();
assert.ok($container.hasClass('test'));
assert.ok($container.hasClass('copy'));
assert.ok($container.hasClass('works'));
assert.ok($container.hasClass('other'));
assert.ok(!$container.hasClass(':all:'));
});
test('classes can be passed in as a string', function (assert) {
var $element = $('<select class="test copy works"></select>');
var options = new Options({
containerCssClass: 'other'
});
var select = new ContainerCSS($element, options);
var $container = select.render();
assert.ok($container.hasClass('other'));
});
test('a function can be used based on the element', function (assert){
var $element = $('<select class="test"></select>');
var options = new Options({
containerCssClass: function ($element) {
return 'function';
}
});
var select = new ContainerCSS($element, options);
var $container = select.render();
assert.ok($container.hasClass('function'));
assert.ok(!$container.hasClass('test'));
});
test(':all: works around custom adapters', function (assert) {
var $element = $('<select class="test"></select>');
var options = new Options({
containerCssClass: ':all: something',
adaptContainerCssClass: function (clazz) {
return clazz + '-modified';
}
});
var select = new ContainerCSS($element, options);
var $container = select.render();
assert.ok($container.hasClass('something'));
assert.ok($container.hasClass('test'));
assert.ok($container.hasClass('test-modified'));
});
module('Selection - adaptContainerCss compatibility');
test('only return when adapted', function (assert) {
var $element = $('<select class="original"></select>');
var options = new Options({
adaptContainerCssClass: function (clazz) {
return 'modified';
}
});
var select = new ContainerCSS($element, options);
var $container = select.render();
assert.ok(!$container.hasClass('original'));
assert.ok($container.hasClass('modified'));
});

View File

@ -66,6 +66,7 @@
<script src="data/maximumSelectionLength-tests.js" type="text/javascript"></script>
<script src="data/minimumInputLength-tests.js" type="text/javascript"></script>
<script src="dropdown/dropdownCss-tests.js" type="text/javascript"></script>
<script src="dropdown/selectOnClose-tests.js" type="text/javascript"></script>
<script src="dropdown/stopPropagation-tests.js" type="text/javascript"></script>
@ -75,6 +76,7 @@
<script src="options/width-tests.js" type="text/javascript"></script>
<script src="selection/allowClear-tests.js" type="text/javascript"></script>
<script src="selection/containerCss-tests.js" type="text/javascript"></script>
<script src="selection/multiple-tests.js" type="text/javascript"></script>
<script src="selection/placeholder-tests.js" type="text/javascript"></script>
<script src="selection/single-tests.js" type="text/javascript"></script>