Skip to content
Browse files

Add support for dispose() method, which detaches all attached event h…

…andlers.

(cherry picked from commit ed82439)
  • Loading branch information...
1 parent 15bdaad commit 451147092adc3998ca9f569f587678bfe458d0c1 @kir kir committed with Simon East
Showing with 134 additions and 29 deletions.
  1. +68 −29 client/fileuploader.js
  2. +66 −0 tests/test-detach-handlers.htm
View
97 client/fileuploader.js
@@ -50,12 +50,16 @@ qq.getUniqueId = (function(){
//
// Events
+/** Returns the function which detaches attached event */
qq.attach = function(element, type, fn){
if (element.addEventListener){
element.addEventListener(type, fn, false);
} else if (element.attachEvent){
element.attachEvent('on' + type, fn);
}
+ return function() {
+ qq.detach(element, type, fn)
+ }
};
qq.detach = function(element, type, fn){
if (element.removeEventListener){
@@ -281,10 +285,11 @@ qq.FileUploaderBasic = function(o){
}
};
qq.extend(this._options, o);
-
+ qq.extend(this, qq.DisposeSupport);
+
// number of files being uploaded
this._filesInProgress = 0;
- this._handler = this._createUploadHandler();
+ this._handler = this._createUploadHandler();
if (this._options.button){
this._button = this._createUploadButton(this._options.button);
@@ -303,13 +308,16 @@ qq.FileUploaderBasic.prototype = {
_createUploadButton: function(element){
var self = this;
- return new qq.UploadButton({
+ var button = new qq.UploadButton({
element: element,
multiple: this._options.multiple && qq.UploadHandlerXhr.isSupported(),
onChange: function(input){
self._onInputChange(input);
}
- });
+ });
+
+ this.addDisposer(function() { button.dispose(); });
+ return button;
},
_createUploadHandler: function(){
var self = this,
@@ -345,7 +353,7 @@ qq.FileUploaderBasic.prototype = {
_preventLeaveInProgress: function(){
var self = this;
- qq.attach(window, 'beforeunload', function(e){
+ this._attach(window, 'beforeunload', function(e){
if (!self._filesInProgress){return;}
var e = e || window.event;
@@ -354,7 +362,8 @@ qq.FileUploaderBasic.prototype = {
// for webkit
return self._options.messages.onLeave;
});
- },
+ },
+
_onSubmit: function(id, fileName){
this._filesInProgress++;
},
@@ -572,16 +581,18 @@ qq.extend(qq.FileUploader.prototype, {
self._uploadFileList(e.dataTransfer.files);
}
});
-
- dropArea.style.display = 'none';
- qq.attach(document, 'dragenter', function(e){
+ this.addDisposer(function() { dz.dispose(); });
+
+ dropArea.style.display = 'none';
+
+ this._attach(document, 'dragenter', function(e){
if (!dz._isValidFileDrag(e)) return;
if (qq.hasClass(dropArea, self._classes.dropDisabled)) return;
dropArea.style.display = 'block';
});
- qq.attach(document, 'dragleave', function(e){
+ this._attach(document, 'dragleave', function(e){
if (!dz._isValidFileDrag(e)) return;
var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);
@@ -652,7 +663,7 @@ qq.extend(qq.FileUploader.prototype, {
var self = this,
list = this._listElement;
- qq.attach(list, 'click', function(e){
+ this._attach(list, 'click', function(e){
e = e || window.event;
var target = e.target || e.srcElement;
@@ -676,8 +687,9 @@ qq.UploadDropZone = function(o){
onLeaveNotDescendants: function(e){},
onDrop: function(e){}
};
- qq.extend(this._options, o);
-
+ qq.extend(this._options, o);
+ qq.extend(this, qq.DisposeSupport);
+
this._element = this._options.element;
this._disableDropOutside();
@@ -702,7 +714,7 @@ qq.UploadDropZone.prototype = {
_attachEvents: function(){
var self = this;
- qq.attach(self._element, 'dragover', function(e){
+ self._attach(self._element, 'dragover', function(e){
if (!self._isValidFileDrag(e)) return;
var effect = e.dataTransfer.effectAllowed;
@@ -715,14 +727,14 @@ qq.UploadDropZone.prototype = {
e.stopPropagation();
e.preventDefault();
});
-
- qq.attach(self._element, 'dragenter', function(e){
+
+ self._attach(self._element, 'dragenter', function(e){
if (!self._isValidFileDrag(e)) return;
self._options.onEnter(e);
});
-
- qq.attach(self._element, 'dragleave', function(e){
+
+ self._attach(self._element, 'dragleave', function(e){
if (!self._isValidFileDrag(e)) return;
self._options.onLeave(e);
@@ -733,8 +745,8 @@ qq.UploadDropZone.prototype = {
self._options.onLeaveNotDescendants(e);
});
-
- qq.attach(self._element, 'drop', function(e){
+
+ self._attach(self._element, 'drop', function(e){
if (!self._isValidFileDrag(e)) return;
e.preventDefault();
@@ -767,7 +779,8 @@ qq.UploadButton = function(o){
};
qq.extend(this._options, o);
-
+ qq.extend(this, qq.DisposeSupport);
+
this._element = this._options.element;
// make button suitable container for input
@@ -825,20 +838,20 @@ qq.UploadButton.prototype = {
this._element.appendChild(input);
var self = this;
- qq.attach(input, 'change', function(){
+ this._attach(input, 'change', function(){
self._options.onChange(input);
});
-
- qq.attach(input, 'mouseover', function(){
+
+ this._attach(input, 'mouseover', function(){
qq.addClass(self._element, self._options.hoverClass);
});
- qq.attach(input, 'mouseout', function(){
+ this._attach(input, 'mouseout', function(){
qq.removeClass(self._element, self._options.hoverClass);
});
- qq.attach(input, 'focus', function(){
+ this._attach(input, 'focus', function(){
qq.addClass(self._element, self._options.focusClass);
});
- qq.attach(input, 'blur', function(){
+ this._attach(input, 'blur', function(){
qq.removeClass(self._element, self._options.focusClass);
});
@@ -1021,6 +1034,7 @@ qq.extend(qq.UploadHandlerForm.prototype, {
delete self._inputs[id];
// timeout added to fix busy state in FF3.6
setTimeout(function(){
+ self._detach_event();
qq.remove(iframe);
}, 1);
});
@@ -1031,7 +1045,7 @@ qq.extend(qq.UploadHandlerForm.prototype, {
return id;
},
_attachLoadEvent: function(iframe, callback){
- qq.attach(iframe, 'load', function(){
+ this._detach_event = qq.attach(iframe, 'load', function(){
// when we remove iframe from dom
// the request stops, but in IE load
// event fires
@@ -1251,4 +1265,29 @@ qq.extend(qq.UploadHandlerXhr.prototype, {
this._xhrs[id] = null;
}
}
-});
+});
+
+/**
+ * A generic module which supports object disposing in dispose() method.
+ * */
+qq.DisposeSupport = {
+ _disposers: [],
+
+ /** Run all registered disposers */
+ dispose: function() {
+ var disposer;
+ while (disposer = this._disposers.shift()) {
+ disposer();
+ }
+ },
+
+ /** Add disposer to the collection */
+ addDisposer: function(disposeFunction) {
+ this._disposers.push(disposeFunction);
+ },
+
+ /** Attach event handler and register de-attacher as a disposer */
+ _attach: function() {
+ this.addDisposer(qq.attach.apply(this, arguments));
+ }
+};
View
66 tests/test-detach-handlers.htm
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <script src="jquery-1.4.2.min.js" type="text/javascript"></script>
+
+ <link href="qunit/qunit/qunit.css" rel="stylesheet" type="text/css" media="screen" />
+ <script src="qunit/qunit/qunit.js" type="text/javascript"></script>
+
+ <script src="../client/fileuploader.js" type="text/javascript" ></script>
+ <script>
+ var run_tests = function() {
+
+ test("detach call", function(){
+
+ var stopper = qq.attach($("#placeholder")[0], "click", function() {});
+
+ var log = "";
+ qq.detach = function(what, event, handler) {
+ log += what.id + "_" + event;
+ };
+
+ stopper();
+ equal(log, "placeholder_click", "Should call detach");
+ });
+
+ test("dispose generic", function(){
+
+ var attach_count = 0;
+ var detach_count = 0;
+
+ var attach = qq.attach;
+ var detach = qq.detach;
+ qq.attach = function() {
+ attach_count++;
+ return attach.apply(this, arguments);
+ };
+ qq.detach = function() {
+ detach_count++;
+ return detach.apply(this, arguments);
+ };
+
+ var uploader = new qq.FileUploader({
+ // pass the dom node (ex. $(selector)[0] for jQuery users)
+ element: $("#placeholder")[0]
+ });
+
+ uploader.dispose();
+
+ equal(detach_count, attach_count - 1, "Should remove all events, excluding event which disables drop outside");
+
+ });
+
+ }
+ </script>
+</head>
+<body onload="run_tests();">
+<h1 id="qunit-header">File uploader tests</h1>
+<h2 id="qunit-banner"></h2>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+
+<div id="placeholder"></div>
+</body>
+</html>
+
+

0 comments on commit 4511470

Please sign in to comment.
Something went wrong with that request. Please try again.