1
0
mirror of synced 2024-11-25 06:16:08 +03:00

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.
This commit is contained in:
Kevin Brown 2015-02-17 14:29:26 -05:00
parent a954bae228
commit 956ac46dab
12 changed files with 403 additions and 24 deletions

View File

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

View File

@ -2406,7 +2406,6 @@ define('select2/data/select',[
var val = data.id; var val = data.id;
this.$element.val(val); this.$element.val(val);
this.$element.trigger('change'); 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) { SelectAdapter.prototype.option = function (data) {
var option; var option;
@ -2632,7 +2635,7 @@ define('select2/data/array',[
ArrayAdapter.__super__.constructor.call(this, $element, options); ArrayAdapter.__super__.constructor.call(this, $element, options);
$element.append(this.convertToOptions(data)); this.addOptions(this.convertToOptions(data));
} }
Utils.Extend(ArrayAdapter, SelectAdapter); Utils.Extend(ArrayAdapter, SelectAdapter);
@ -2643,7 +2646,7 @@ define('select2/data/array',[
if ($option.length === 0) { if ($option.length === 0) {
$option = this.option(data); $option = this.option(data);
this.$element.append($option); this.addOptions([$option]);
} }
ArrayAdapter.__super__.select.call(this, data); ArrayAdapter.__super__.select.call(this, data);
@ -2871,7 +2874,7 @@ define('select2/data/tags',[
var $option = self.option(tag); var $option = self.option(tag);
$option.attr('data-select2-tag', true); $option.attr('data-select2-tag', true);
self.$element.append($option); self.addOptions([$option]);
self.insertTag(data, tag); self.insertTag(data, tag);
} }
@ -4057,6 +4060,15 @@ define('select2/options',[
} }
this.options = Defaults.apply(this.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) { Options.prototype.fromElement = function ($e) {
@ -4974,6 +4986,112 @@ define('select2/compat/initSelection',[
return 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',[ define('select2/compat/query',[
], function () { ], function () {

View File

@ -2406,7 +2406,6 @@ define('select2/data/select',[
var val = data.id; var val = data.id;
this.$element.val(val); this.$element.val(val);
this.$element.trigger('change'); 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) { SelectAdapter.prototype.option = function (data) {
var option; var option;
@ -2632,7 +2635,7 @@ define('select2/data/array',[
ArrayAdapter.__super__.constructor.call(this, $element, options); ArrayAdapter.__super__.constructor.call(this, $element, options);
$element.append(this.convertToOptions(data)); this.addOptions(this.convertToOptions(data));
} }
Utils.Extend(ArrayAdapter, SelectAdapter); Utils.Extend(ArrayAdapter, SelectAdapter);
@ -2643,7 +2646,7 @@ define('select2/data/array',[
if ($option.length === 0) { if ($option.length === 0) {
$option = this.option(data); $option = this.option(data);
this.$element.append($option); this.addOptions([$option]);
} }
ArrayAdapter.__super__.select.call(this, data); ArrayAdapter.__super__.select.call(this, data);
@ -2871,7 +2874,7 @@ define('select2/data/tags',[
var $option = self.option(tag); var $option = self.option(tag);
$option.attr('data-select2-tag', true); $option.attr('data-select2-tag', true);
self.$element.append($option); self.addOptions([$option]);
self.insertTag(data, tag); self.insertTag(data, tag);
} }
@ -4057,6 +4060,15 @@ define('select2/options',[
} }
this.options = Defaults.apply(this.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) { Options.prototype.fromElement = function ($e) {

View File

@ -2845,7 +2845,6 @@ define('select2/data/select',[
var val = data.id; var val = data.id;
this.$element.val(val); this.$element.val(val);
this.$element.trigger('change'); 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) { SelectAdapter.prototype.option = function (data) {
var option; var option;
@ -3071,7 +3074,7 @@ define('select2/data/array',[
ArrayAdapter.__super__.constructor.call(this, $element, options); ArrayAdapter.__super__.constructor.call(this, $element, options);
$element.append(this.convertToOptions(data)); this.addOptions(this.convertToOptions(data));
} }
Utils.Extend(ArrayAdapter, SelectAdapter); Utils.Extend(ArrayAdapter, SelectAdapter);
@ -3082,7 +3085,7 @@ define('select2/data/array',[
if ($option.length === 0) { if ($option.length === 0) {
$option = this.option(data); $option = this.option(data);
this.$element.append($option); this.addOptions([$option]);
} }
ArrayAdapter.__super__.select.call(this, data); ArrayAdapter.__super__.select.call(this, data);
@ -3310,7 +3313,7 @@ define('select2/data/tags',[
var $option = self.option(tag); var $option = self.option(tag);
$option.attr('data-select2-tag', true); $option.attr('data-select2-tag', true);
self.$element.append($option); self.addOptions([$option]);
self.insertTag(data, tag); self.insertTag(data, tag);
} }
@ -4496,6 +4499,15 @@ define('select2/options',[
} }
this.options = Defaults.apply(this.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) { Options.prototype.fromElement = function ($e) {
@ -5413,6 +5425,112 @@ define('select2/compat/initSelection',[
return 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',[ define('select2/compat/query',[
], function () { ], function () {

File diff suppressed because one or more lines are too long

20
dist/js/select2.js vendored
View File

@ -2845,7 +2845,6 @@ define('select2/data/select',[
var val = data.id; var val = data.id;
this.$element.val(val); this.$element.val(val);
this.$element.trigger('change'); 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) { SelectAdapter.prototype.option = function (data) {
var option; var option;
@ -3071,7 +3074,7 @@ define('select2/data/array',[
ArrayAdapter.__super__.constructor.call(this, $element, options); ArrayAdapter.__super__.constructor.call(this, $element, options);
$element.append(this.convertToOptions(data)); this.addOptions(this.convertToOptions(data));
} }
Utils.Extend(ArrayAdapter, SelectAdapter); Utils.Extend(ArrayAdapter, SelectAdapter);
@ -3082,7 +3085,7 @@ define('select2/data/array',[
if ($option.length === 0) { if ($option.length === 0) {
$option = this.option(data); $option = this.option(data);
this.$element.append($option); this.addOptions([$option]);
} }
ArrayAdapter.__super__.select.call(this, data); ArrayAdapter.__super__.select.call(this, data);
@ -3310,7 +3313,7 @@ define('select2/data/tags',[
var $option = self.option(tag); var $option = self.option(tag);
$option.attr('data-select2-tag', true); $option.attr('data-select2-tag', true);
self.$element.append($option); self.addOptions([$option]);
self.insertTag(data, tag); self.insertTag(data, tag);
} }
@ -4496,6 +4499,15 @@ define('select2/options',[
} }
this.options = Defaults.apply(this.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) { Options.prototype.fromElement = function ($e) {

File diff suppressed because one or more lines are too long

105
src/js/select2/compat/inputData.js vendored Normal file
View File

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

View File

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

View File

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

View File

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

View File

@ -11,6 +11,15 @@ define([
} }
this.options = Defaults.apply(this.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) { Options.prototype.fromElement = function ($e) {