Skip to content

Commit 2fce8ae

Browse files
authored
Fix maximumSelectionLength being ignored by closeOnSelect (select2#5581)
* Rewrote maximumSelectionLength tests to use container These brings the tests in line with other tests which we have, and makes it easier to understand what is actually going on in the tests. This also removes a redundant set of tests where we were testing with => 2 options being allowed. There are no current edge cases that would have required this. * Fix maximumSelectionLength being ignored by closeOnSelect There was a bug where the `maximumSelectionLength` option would not kick in if the `closeOnSelect` option was enabled. Normally, this was enabled by someone in their global configuration, but it could also be seen when somoene selected an option while holding the meta/ctrl/alt keys. This would implicitly enable the `closeOnSelect` behaviour, even when it was not globally enabled, and cause the bug. This fixes that issue by listening to the `select` event which is triggered whenever an option is selected, and triggers the "maximum selected" message based on that event. This should now force the message to be displayed, even when the results did not have to be queried another time. Fixes select2#3514 Fixes select2#3860 Closes select2#5333
1 parent f2d527e commit 2fce8ae

2 files changed

Lines changed: 94 additions & 121 deletions

File tree

src/js/select2/data/maximumSelectionLength.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,30 @@ define([
77
decorated.call(this, $e, options);
88
}
99

10+
MaximumSelectionLength.prototype.bind =
11+
function (decorated, container, $container) {
12+
var self = this;
13+
14+
decorated.call(this, container, $container);
15+
16+
container.on('select', function () {
17+
self._checkIfMaximumSelected();
18+
});
19+
};
20+
1021
MaximumSelectionLength.prototype.query =
1122
function (decorated, params, callback) {
1223
var self = this;
1324

25+
this._checkIfMaximumSelected(function () {
26+
decorated.call(self, params, callback);
27+
});
28+
};
29+
30+
MaximumSelectionLength.prototype._checkIfMaximumSelected =
31+
function (_, successCallback) {
32+
var self = this;
33+
1434
this.current(function (currentData) {
1535
var count = currentData != null ? currentData.length : 0;
1636
if (self.maximumSelectionLength > 0 &&
@@ -23,7 +43,10 @@ define([
2343
});
2444
return;
2545
}
26-
decorated.call(self, params, callback);
46+
47+
if (successCallback) {
48+
successCallback();
49+
}
2750
});
2851
};
2952

Lines changed: 70 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,202 +1,152 @@
11
module('Data adapters - Maximum selection length');
22

3+
var SelectData = require('select2/data/select');
34
var MaximumSelectionLength = require('select2/data/maximumSelectionLength');
45

56
var $ = require('jquery');
67
var Options = require('select2/options');
78
var Utils = require('select2/utils');
89

9-
function MaximumSelectionStub () {
10-
this.called = false;
11-
this.currentData = [];
12-
}
10+
var MaximumSelectionData = Utils.Decorate(SelectData, MaximumSelectionLength);
1311

14-
MaximumSelectionStub.prototype.current = function (callback) {
15-
callback(this.currentData);
16-
};
17-
18-
MaximumSelectionStub.prototype.val = function (val) {
19-
this.currentData.push(val);
20-
};
21-
22-
MaximumSelectionStub.prototype.query = function (params, callback) {
23-
this.called = true;
24-
};
12+
test('0 never displays the notice', function (assert) {
13+
assert.expect(3);
2514

26-
var MaximumSelectionData = Utils.Decorate(
27-
MaximumSelectionStub,
28-
MaximumSelectionLength
29-
);
15+
var $select = $('#qunit-fixture .multiple');
3016

31-
test('0 never displays the notice', function (assert) {
3217
var zeroOptions = new Options({
3318
maximumSelectionLength: 0
3419
});
3520

36-
var data = new MaximumSelectionData(null, zeroOptions);
21+
var container = new MockContainer();
22+
var data = new MaximumSelectionData($select, zeroOptions);
3723

38-
data.trigger = function () {
39-
assert.ok(false, 'No events should be triggered');
40-
};
24+
data.bind(container, null);
25+
26+
data.on('results:message', function () {
27+
assert.ok(false, 'The message should not be displayed');
28+
});
4129

4230
data.query({
4331
term: ''
32+
}, function () {
33+
assert.ok(true, 'The results should be queried');
4434
});
4535

46-
assert.ok(data.called);
47-
48-
data = new MaximumSelectionData(null, zeroOptions);
49-
50-
data.trigger = function () {
51-
assert.ok(false, 'No events should be triggered');
52-
};
53-
54-
data.val('1');
36+
$select.val(['One']);
5537

5638
data.query({
5739
term: ''
40+
}, function () {
41+
assert.ok(true, 'The results should be queried');
5842
});
5943

60-
assert.ok(data.called);
61-
62-
data = new MaximumSelectionData(null, zeroOptions);
63-
64-
data.trigger = function () {
65-
assert.ok(false, 'No events should be triggered');
66-
};
67-
68-
data.val('1');
69-
data.val('2');
44+
$select.val(['One', 'Two']);
7045

7146
data.query({
7247
term: ''
48+
}, function () {
49+
assert.ok(true, 'The results should be queried');
7350
});
74-
75-
assert.ok(data.called);
7651
});
7752

7853
test('< 0 never displays the notice', function (assert) {
54+
assert.expect(3);
55+
56+
var $select = $('#qunit-fixture .multiple');
57+
7958
var negativeOptions = new Options({
8059
maximumSelectionLength: -1
8160
});
8261

83-
var data = new MaximumSelectionData(null, negativeOptions);
62+
var container = new MockContainer();
63+
var data = new MaximumSelectionData($select, negativeOptions);
64+
65+
data.bind(container, null);
8466

85-
data.trigger = function () {
86-
assert.ok(false, 'No events should be triggered');
87-
};
67+
data.on('results:message', function () {
68+
assert.ok(false, 'The message should not be displayed');
69+
});
8870

8971
data.query({
9072
term: ''
73+
}, function () {
74+
assert.ok(true, 'The results should be queried');
9175
});
9276

93-
assert.ok(data.called);
94-
95-
data = new MaximumSelectionData(null, negativeOptions);
96-
97-
data.trigger = function () {
98-
assert.ok(false, 'No events should be triggered');
99-
};
100-
101-
data.val('1');
77+
$select.val(['One']);
10278

10379
data.query({
10480
term: ''
81+
}, function () {
82+
assert.ok(true, 'The results should be queried');
10583
});
10684

107-
assert.ok(data.called);
108-
109-
data = new MaximumSelectionData(null, negativeOptions);
110-
111-
data.trigger = function () {
112-
assert.ok(false, 'No events should be triggered');
113-
};
114-
115-
data.val('1');
116-
data.val('2');
85+
$select.val(['One', 'Two']);
11786

11887
data.query({
11988
term: ''
89+
}, function () {
90+
assert.ok(true, 'The results should be queried');
12091
});
121-
122-
assert.ok(data.called);
12392
});
12493

12594
test('triggers when >= 1 selection' , function (assert) {
126-
var maxOfOneOptions = new Options({
127-
maximumSelectionLength: 1
128-
});
129-
var data = new MaximumSelectionData(null, maxOfOneOptions);
95+
assert.expect(2);
13096

131-
data.trigger = function () {
132-
assert.ok(false, 'No events should be triggered');
133-
};
97+
var $select = $('#qunit-fixture .multiple');
13498

135-
data.query({
136-
term: ''
99+
var maxOfOneOptions = new Options({
100+
maximumSelectionLength: 1
137101
});
138102

139-
assert.ok(data.called);
103+
var container = new MockContainer();
104+
var data = new MaximumSelectionData($select, maxOfOneOptions);
140105

141-
data = new MaximumSelectionData(null, maxOfOneOptions);
106+
data.bind(container, null);
142107

143-
data.trigger = function () {
144-
assert.ok(true, 'The event should be triggered.');
145-
};
108+
data.on('results:message', function () {
109+
assert.ok(true, 'The message should be displayed');
110+
});
146111

147-
data.val('1');
112+
$select.val(['One']);
148113

149114
data.query({
150115
term: ''
116+
}, function () {
117+
assert.ok(false, 'The results should not be queried');
151118
});
152119

153-
assert.ok(!data.called);
154-
155-
});
156-
157-
test('triggers when >= 2 selections' , function (assert) {
158-
var maxOfTwoOptions = new Options({
159-
maximumSelectionLength: 2
160-
});
161-
var data = new MaximumSelectionData(null, maxOfTwoOptions);
162-
163-
data.trigger = function () {
164-
assert.ok(false, 'No events should be triggered');
165-
};
120+
$select.val(['One', 'Two']);
166121

167122
data.query({
168123
term: ''
124+
}, function () {
125+
assert.ok(false, 'The results should not be queried');
169126
});
127+
});
170128

171-
assert.ok(data.called);
172-
173-
data = new MaximumSelectionData(null, maxOfTwoOptions);
174-
175-
data.trigger = function () {
176-
assert.ok(false, 'No events should be triggered');
177-
};
129+
test('triggers after selection' , function (assert) {
130+
assert.expect(1);
178131

179-
data.val('1');
132+
var $select = $('#qunit-fixture .multiple');
180133

181-
data.query({
182-
term: ''
134+
var maxOfOneOptions = new Options({
135+
maximumSelectionLength: 1
183136
});
184137

185-
assert.ok(data.called);
186-
187-
data = new MaximumSelectionData(null, maxOfTwoOptions);
188-
189-
data.trigger = function () {
190-
assert.ok(true, 'The event should be triggered.');
191-
};
138+
var container = new MockContainer();
139+
var data = new MaximumSelectionData($select, maxOfOneOptions);
192140

193-
data.val('1');
194-
data.val('2');
141+
data.bind(container, null);
195142

196-
data.query({
197-
term: ''
143+
data.on('results:message', function () {
144+
assert.ok(true, 'The message should be displayed');
198145
});
199146

200-
assert.ok(!data.called);
147+
$select.val(['One']);
201148

149+
container.trigger('select', {
150+
data: {}
151+
});
202152
});

0 commit comments

Comments
 (0)