Skip to content

Commit f7cbd2c

Browse files
authored
Remove support for legacy IE (select2#5834)
* Replace usage of $.trim with String.prototype.trim This officially drops support for Internet Explorer 8, since this method is not provided by that browser. This is one more step closer to removing the dependency on jQuery itself. * Replace $.isArray with Array.isArray Now that we no longer support IE8, we can rely on this method actually existing now. * Remove old getAttribute workaround for IE7 This has long been unsupported, and now that we don't care about IE8 with quirks mode, we can go back to expecting that `getAttribute` actually returns the string like it is supposed to. * Remove jQuery from Utils.copyNonInternalCssClasses This also simplifies the logic used to use more modern array methods to calculate the list of classes which need to be copied over to the destination object. * Remove unused imports * Remove use of jQuery.fn.is() * Replace $.inArray with Array.prototype.indexOf * Replace addClass, hasClass, removeClass with classList calls This replaces calls to the jQuery `getClass`, `hasClass`, and `removeClass` methods with the corresponding calls to `classList` methods on the elements that are referenced. There is one exception to this, specifically where results remove a class from any elements which may contain it, since that cannot be easily translated to use the `classList` syntax. * Remove legacy DOM modification tracking This removes the legacy tracking for `onpropertychange`, which was used by IE 8, to synchronize attribute changes from the `<select>` element back to Select2. This removes the legacy tracking of `DOMNodeInserted`, `DOMNodeRemoved`, and `DOMAttrModified` which was used by IE 9 and IE 10 for tracking when `<option>` elements were added and removed, as well as when attributes on the `<select>` element were synchronized. Now only the `MutationObserver` is in use for synchronizing changes to the `<select>` as well as changes to the `<option>` elements that it contains. * Replace $.map with Array.prototype.map
1 parent f999ed8 commit f7cbd2c

20 files changed

Lines changed: 118 additions & 174 deletions

src/js/jquery.select2.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ define([
3939
});
4040

4141
// Check if we should be returning `this`
42-
if ($.inArray(options, thisMethods) > -1) {
42+
if (thisMethods.indexOf(options) > -1) {
4343
return this;
4444
}
4545

src/js/select2/core.js

Lines changed: 37 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ define([
7777
});
7878

7979
// Hide the original select
80-
$element.addClass('select2-hidden-accessible');
80+
$element[0].classList.add('select2-hidden-accessible');
8181
$element.attr('aria-hidden', 'true');
8282

8383
// Synchronize any monitored attributes
@@ -197,42 +197,15 @@ define([
197197
this._syncA = Utils.bind(this._syncAttributes, this);
198198
this._syncS = Utils.bind(this._syncSubtree, this);
199199

200-
if (this.$element[0].attachEvent) {
201-
this.$element[0].attachEvent('onpropertychange', this._syncA);
202-
}
203-
204-
var observer = window.MutationObserver ||
205-
window.WebKitMutationObserver ||
206-
window.MozMutationObserver
207-
;
208-
209-
if (observer != null) {
210-
this._observer = new observer(function (mutations) {
211-
self._syncA();
212-
self._syncS(null, mutations);
213-
});
214-
this._observer.observe(this.$element[0], {
215-
attributes: true,
216-
childList: true,
217-
subtree: false
218-
});
219-
} else if (this.$element[0].addEventListener) {
220-
this.$element[0].addEventListener(
221-
'DOMAttrModified',
222-
self._syncA,
223-
false
224-
);
225-
this.$element[0].addEventListener(
226-
'DOMNodeInserted',
227-
self._syncS,
228-
false
229-
);
230-
this.$element[0].addEventListener(
231-
'DOMNodeRemoved',
232-
self._syncS,
233-
false
234-
);
235-
}
200+
this._observer = new window.MutationObserver(function (mutations) {
201+
self._syncA();
202+
self._syncS(mutations);
203+
});
204+
this._observer.observe(this.$element[0], {
205+
attributes: true,
206+
childList: true,
207+
subtree: false
208+
});
236209
};
237210

238211
Select2.prototype._registerDataEvents = function () {
@@ -256,7 +229,7 @@ define([
256229
});
257230

258231
this.selection.on('*', function (name, params) {
259-
if ($.inArray(name, nonRelayEvents) !== -1) {
232+
if (nonRelayEvents.indexOf(name) !== -1) {
260233
return;
261234
}
262235

@@ -284,23 +257,23 @@ define([
284257
var self = this;
285258

286259
this.on('open', function () {
287-
self.$container.addClass('select2-container--open');
260+
self.$container[0].classList.add('select2-container--open');
288261
});
289262

290263
this.on('close', function () {
291-
self.$container.removeClass('select2-container--open');
264+
self.$container[0].classList.remove('select2-container--open');
292265
});
293266

294267
this.on('enable', function () {
295-
self.$container.removeClass('select2-container--disabled');
268+
self.$container[0].classList.remove('select2-container--disabled');
296269
});
297270

298271
this.on('disable', function () {
299-
self.$container.addClass('select2-container--disabled');
272+
self.$container[0].classList.add('select2-container--disabled');
300273
});
301274

302275
this.on('blur', function () {
303-
self.$container.removeClass('select2-container--focus');
276+
self.$container[0].classList.remove('select2-container--focus');
304277
});
305278

306279
this.on('query', function (params) {
@@ -376,49 +349,30 @@ define([
376349
}
377350
};
378351

379-
Select2.prototype._isChangeMutation = function (evt, mutations) {
380-
var changed = false;
352+
Select2.prototype._isChangeMutation = function (mutations) {
381353
var self = this;
382354

383-
// Ignore any mutation events raised for elements that aren't options or
384-
// optgroups. This handles the case when the select element is destroyed
385-
if (
386-
evt && evt.target && (
387-
evt.target.nodeName !== 'OPTION' && evt.target.nodeName !== 'OPTGROUP'
388-
)
389-
) {
390-
return;
391-
}
392-
393-
if (!mutations) {
394-
// If mutation events aren't supported, then we can only assume that the
395-
// change affected the selections
396-
changed = true;
397-
} else if (mutations.addedNodes && mutations.addedNodes.length > 0) {
355+
if (mutations.addedNodes && mutations.addedNodes.length > 0) {
398356
for (var n = 0; n < mutations.addedNodes.length; n++) {
399357
var node = mutations.addedNodes[n];
400358

401359
if (node.selected) {
402-
changed = true;
360+
return true;
403361
}
404362
}
405363
} else if (mutations.removedNodes && mutations.removedNodes.length > 0) {
406-
changed = true;
407-
} else if ($.isArray(mutations)) {
408-
$.each(mutations, function(evt, mutation) {
409-
if (self._isChangeMutation(evt, mutation)) {
410-
// We've found a change mutation.
411-
// Let's escape from the loop and continue
412-
changed = true;
413-
return false;
414-
}
364+
return true;
365+
} else if (Array.isArray(mutations)) {
366+
return mutations.some(function (mutation) {
367+
return self._isChangeMutation(mutation);
415368
});
416369
}
417-
return changed;
370+
371+
return false;
418372
};
419373

420-
Select2.prototype._syncSubtree = function (evt, mutations) {
421-
var changed = this._isChangeMutation(evt, mutations);
374+
Select2.prototype._syncSubtree = function (mutations) {
375+
var changed = this._isChangeMutation(mutations);
422376
var self = this;
423377

424378
// Only re-pull the data if we think there is a change
@@ -523,11 +477,11 @@ define([
523477
};
524478

525479
Select2.prototype.isOpen = function () {
526-
return this.$container.hasClass('select2-container--open');
480+
return this.$container[0].classList.contains('select2-container--open');
527481
};
528482

529483
Select2.prototype.hasFocus = function () {
530-
return this.$container.hasClass('select2-container--focus');
484+
return this.$container[0].classList.contains('select2-container--focus');
531485
};
532486

533487
Select2.prototype.focus = function (data) {
@@ -536,7 +490,7 @@ define([
536490
return;
537491
}
538492

539-
this.$container.addClass('select2-container--focus');
493+
this.$container[0].classList.add('select2-container--focus');
540494
this.trigger('focus', {});
541495
};
542496

@@ -590,8 +544,8 @@ define([
590544

591545
var newVal = args[0];
592546

593-
if ($.isArray(newVal)) {
594-
newVal = $.map(newVal, function (obj) {
547+
if (Array.isArray(newVal)) {
548+
newVal = newVal.map(function (obj) {
595549
return obj.toString();
596550
});
597551
}
@@ -602,21 +556,8 @@ define([
602556
Select2.prototype.destroy = function () {
603557
this.$container.remove();
604558

605-
if (this.$element[0].detachEvent) {
606-
this.$element[0].detachEvent('onpropertychange', this._syncA);
607-
}
608-
609-
if (this._observer != null) {
610-
this._observer.disconnect();
611-
this._observer = null;
612-
} else if (this.$element[0].removeEventListener) {
613-
this.$element[0]
614-
.removeEventListener('DOMAttrModified', this._syncA, false);
615-
this.$element[0]
616-
.removeEventListener('DOMNodeInserted', this._syncS, false);
617-
this.$element[0]
618-
.removeEventListener('DOMNodeRemoved', this._syncS, false);
619-
}
559+
this._observer.disconnect();
560+
this._observer = null;
620561

621562
this._syncA = null;
622563
this._syncS = null;
@@ -625,7 +566,7 @@ define([
625566
this.$element.attr('tabindex',
626567
Utils.GetData(this.$element[0], 'old-tabindex'));
627568

628-
this.$element.removeClass('select2-hidden-accessible');
569+
this.$element[0].classList.remove('select2-hidden-accessible');
629570
this.$element.attr('aria-hidden', 'false');
630571
Utils.RemoveData(this.$element[0]);
631572
this.$element.removeData('select2');
@@ -653,7 +594,8 @@ define([
653594

654595
this.$container = $container;
655596

656-
this.$container.addClass('select2-container--' + this.options.get('theme'));
597+
this.$container[0].classList
598+
.add('select2-container--' + this.options.get('theme'));
657599

658600
Utils.StoreData($container[0], 'element', this.$element);
659601

src/js/select2/data/ajax.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ define([
7070

7171
if (self.options.get('debug') && window.console && console.error) {
7272
// Check to make sure that the response included a `results` key.
73-
if (!results || !results.results || !$.isArray(results.results)) {
73+
if (!results || !results.results || !Array.isArray(results.results)) {
7474
console.error(
7575
'Select2: The AJAX results did not return an array in the ' +
7676
'`results` key of the response.'

src/js/select2/data/array.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ define([
5252
var item = this._normalizeItem(data[d]);
5353

5454
// Skip items which were pre-loaded, only merge the data
55-
if ($.inArray(item.id, existingIds) >= 0) {
55+
if (existingIds.indexOf(item.id) >= 0) {
5656
var $existingOption = $existing.filter(onlyItem(item));
5757

5858
var existingData = this.item($existingOption);

src/js/select2/data/select.js

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ define([
3333
data.selected = true;
3434

3535
// If data.element is a DOM node, use it instead
36-
if ($(data.element).is('option')) {
36+
if (
37+
data.element != null && data.element.tagName.toLowerCase() === 'option'
38+
) {
3739
data.element.selected = true;
3840

3941
this.$element.trigger('input').trigger('change');
@@ -51,7 +53,7 @@ define([
5153
for (var d = 0; d < data.length; d++) {
5254
var id = data[d].id;
5355

54-
if ($.inArray(id, val) === -1) {
56+
if (val.indexOf(id) === -1) {
5557
val.push(id);
5658
}
5759
}
@@ -76,7 +78,10 @@ define([
7678

7779
data.selected = false;
7880

79-
if ($(data.element).is('option')) {
81+
if (
82+
data.element != null &&
83+
data.element.tagName.toLowerCase() === 'option'
84+
) {
8085
data.element.selected = false;
8186

8287
this.$element.trigger('input').trigger('change');
@@ -90,7 +95,7 @@ define([
9095
for (var d = 0; d < currentData.length; d++) {
9196
var id = currentData[d].id;
9297

93-
if (id !== data.id && $.inArray(id, val) === -1) {
98+
if (id !== data.id && val.indexOf(id) === -1) {
9499
val.push(id);
95100
}
96101
}
@@ -130,12 +135,15 @@ define([
130135
var $options = this.$element.children();
131136

132137
$options.each(function () {
133-
var $option = $(this);
134-
135-
if (!$option.is('option') && !$option.is('optgroup')) {
138+
if (
139+
this.tagName.toLowerCase() !== 'option' &&
140+
this.tagName.toLowerCase() !== 'optgroup'
141+
) {
136142
return;
137143
}
138144

145+
var $option = $(this);
146+
139147
var option = self.item($option);
140148

141149
var matches = self.matches(params, option);
@@ -186,15 +194,13 @@ define([
186194
option.title = data.title;
187195
}
188196

189-
var $option = $(option);
190-
191197
var normalizedData = this._normalizeItem(data);
192198
normalizedData.element = option;
193199

194200
// Override the option's data with the combined data
195201
Utils.StoreData(option, 'data', normalizedData);
196202

197-
return $option;
203+
return $(option);
198204
};
199205

200206
SelectAdapter.prototype.item = function ($option) {
@@ -206,15 +212,17 @@ define([
206212
return data;
207213
}
208214

209-
if ($option.is('option')) {
215+
var option = $option[0];
216+
217+
if (option.tagName.toLowerCase() === 'option') {
210218
data = {
211219
id: $option.val(),
212220
text: $option.text(),
213221
disabled: $option.prop('disabled'),
214222
selected: $option.prop('selected'),
215223
title: $option.prop('title')
216224
};
217-
} else if ($option.is('optgroup')) {
225+
} else if (option.tagName.toLowerCase() === 'optgroup') {
218226
data = {
219227
text: $option.prop('label'),
220228
children: [],

src/js/select2/data/tags.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ define([
1818

1919
decorated.call(this, $element, options);
2020

21-
if ($.isArray(tags)) {
21+
if (Array.isArray(tags)) {
2222
for (var t = 0; t < tags.length; t++) {
2323
var tag = tags[t];
2424
var item = this._normalizeItem(tag);
@@ -94,7 +94,11 @@ define([
9494
};
9595

9696
Tags.prototype.createTag = function (decorated, params) {
97-
var term = $.trim(params.term);
97+
if (params.term == null) {
98+
return null;
99+
}
100+
101+
var term = params.term.trim();
98102

99103
if (term === '') {
100104
return null;

src/js/select2/data/tokenizer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ define([
8282
while (i < term.length) {
8383
var termChar = term[i];
8484

85-
if ($.inArray(termChar, separators) === -1) {
85+
if (separators.indexOf(termChar) === -1) {
8686
i++;
8787

8888
continue;

0 commit comments

Comments
 (0)