Skip to content

Commit 9e505cd

Browse files
committed
Merge pull request select2#2313 from FallSe7en/master
Cleanup jQuery DOM elements on destroy
2 parents 7268973 + f9be3c0 commit 9e505cd

1 file changed

Lines changed: 42 additions & 32 deletions

File tree

select2.js

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -234,20 +234,6 @@ the specific language governing permissions and limitations under the Apache Lic
234234
};
235235
}
236236

237-
/**
238-
* A simple implementation of a thunk
239-
* @param formula function used to lazily initialize the thunk
240-
* @return {Function}
241-
*/
242-
function thunk(formula) {
243-
var evaluated = false,
244-
value;
245-
return function() {
246-
if (evaluated === false) { value = formula(); evaluated = true; }
247-
return value;
248-
};
249-
};
250-
251237
function installDebouncedScroll(threshold, element) {
252238
var notify = debounce(threshold, function (e) { element.trigger("scroll-debounced", e);});
253239
element.on("scroll", function (e) {
@@ -640,6 +626,15 @@ the specific language governing permissions and limitations under the Apache Lic
640626
if (original!==input) return input;
641627
}
642628

629+
function cleanupJQueryElements() {
630+
var self = this;
631+
632+
Array.prototype.forEach.call(arguments, function (element) {
633+
self[element].remove();
634+
self[element] = null;
635+
});
636+
}
637+
643638
/**
644639
* Creates a new class
645640
*
@@ -695,8 +690,7 @@ the specific language governing permissions and limitations under the Apache Lic
695690

696691
this.container.attr("title", opts.element.attr("title"));
697692

698-
// cache the body so future lookups are cheap
699-
this.body = thunk(function() { return opts.element.closest("body"); });
693+
this.body = $("body");
700694

701695
syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass);
702696

@@ -832,7 +826,10 @@ the specific language governing permissions and limitations under the Apache Lic
832826

833827
this.close();
834828

835-
if (this.propertyObserver) { delete this.propertyObserver; this.propertyObserver = null; }
829+
if (this.propertyObserver) {
830+
this.propertyObserver.disconnect();
831+
this.propertyObserver = null;
832+
}
836833

837834
if (select2 !== undefined) {
838835
select2.container.remove();
@@ -850,6 +847,14 @@ the specific language governing permissions and limitations under the Apache Lic
850847
}
851848
element.show();
852849
}
850+
851+
cleanupJQueryElements.call(this,
852+
"container",
853+
"liveRegion",
854+
"dropdown",
855+
"results",
856+
"search"
857+
);
853858
},
854859

855860
// abstract
@@ -1089,18 +1094,13 @@ the specific language governing permissions and limitations under the Apache Lic
10891094
});
10901095
}
10911096

1092-
// hold onto a reference of the callback to work around a chromium bug
1093-
if (this.mutationCallback === undefined) {
1094-
this.mutationCallback = function (mutations) {
1095-
mutations.forEach(sync);
1096-
}
1097-
}
1098-
10991097
// safari, chrome, firefox, IE11
11001098
observer = window.MutationObserver || window.WebKitMutationObserver|| window.MozMutationObserver;
11011099
if (observer !== undefined) {
11021100
if (this.propertyObserver) { delete this.propertyObserver; this.propertyObserver = null; }
1103-
this.propertyObserver = new observer(this.mutationCallback);
1101+
this.propertyObserver = new observer(function (mutations) {
1102+
mutations.forEach(sync);
1103+
});
11041104
this.propertyObserver.observe(el.get(0), { attributes:true, subtree:false });
11051105
}
11061106
},
@@ -1258,11 +1258,11 @@ the specific language governing permissions and limitations under the Apache Lic
12581258
}
12591259

12601260
//console.log("below/ droptop:", dropTop, "dropHeight", dropHeight, "sum", (dropTop+dropHeight)+" viewport bottom", viewportBottom, "enough?", enoughRoomBelow);
1261-
//console.log("above/ offset.top", offset.top, "dropHeight", dropHeight, "top", (offset.top-dropHeight), "scrollTop", this.body().scrollTop(), "enough?", enoughRoomAbove);
1261+
//console.log("above/ offset.top", offset.top, "dropHeight", dropHeight, "top", (offset.top-dropHeight), "scrollTop", this.body.scrollTop(), "enough?", enoughRoomAbove);
12621262

12631263
// fix positioning when body has an offset and is not position: static
1264-
if (this.body().css('position') !== 'static') {
1265-
bodyOffset = this.body().offset();
1264+
if (this.body.css('position') !== 'static') {
1265+
bodyOffset = this.body.offset();
12661266
dropTop -= bodyOffset.top;
12671267
dropLeft -= bodyOffset.left;
12681268
}
@@ -1344,8 +1344,8 @@ the specific language governing permissions and limitations under the Apache Lic
13441344

13451345
this.clearDropdownAlignmentPreference();
13461346

1347-
if(this.dropdown[0] !== this.body().children().last()[0]) {
1348-
this.dropdown.detach().appendTo(this.body());
1347+
if(this.dropdown[0] !== this.body.children().last()[0]) {
1348+
this.dropdown.detach().appendTo(this.body);
13491349
}
13501350

13511351
// create the dropdown mask if doesn't already exist
@@ -1354,7 +1354,7 @@ the specific language governing permissions and limitations under the Apache Lic
13541354
mask = $(document.createElement("div"));
13551355
mask.attr("id","select2-drop-mask").attr("class","select2-drop-mask");
13561356
mask.hide();
1357-
mask.appendTo(this.body());
1357+
mask.appendTo(this.body);
13581358
mask.on("mousedown touchstart click", function (e) {
13591359
// Prevent IE from generating a click event on the body
13601360
reinsertElement(mask);
@@ -2009,6 +2009,11 @@ the specific language governing permissions and limitations under the Apache Lic
20092009
$("label[for='" + this.focusser.attr('id') + "']")
20102010
.attr('for', this.opts.element.attr("id"));
20112011
this.parent.destroy.apply(this, arguments);
2012+
2013+
cleanupJQueryElements.call(this,
2014+
"selection",
2015+
"focusser"
2016+
);
20122017
},
20132018

20142019
// single
@@ -2090,7 +2095,7 @@ the specific language governing permissions and limitations under the Apache Lic
20902095
this.search.on("blur", this.bind(function(e) {
20912096
// a workaround for chrome to keep the search field focussed when the scroll bar is used to scroll the dropdown.
20922097
// without this the search field loses focus which is annoying
2093-
if (document.activeElement === this.body().get(0)) {
2098+
if (document.activeElement === this.body.get(0)) {
20942099
window.setTimeout(this.bind(function() {
20952100
if (this.opened()) {
20962101
this.search.focus();
@@ -2599,6 +2604,11 @@ the specific language governing permissions and limitations under the Apache Lic
25992604
$("label[for='" + this.search.attr('id') + "']")
26002605
.attr('for', this.opts.element.attr("id"));
26012606
this.parent.destroy.apply(this, arguments);
2607+
2608+
cleanupJQueryElements.call(this,
2609+
"searchContainer",
2610+
"selection"
2611+
);
26022612
},
26032613

26042614
// multi

0 commit comments

Comments
 (0)