diff --git a/src/eventhandler.js b/src/eventhandler.js index e265fbf7..8e608806 100644 --- a/src/eventhandler.js +++ b/src/eventhandler.js @@ -91,15 +91,21 @@ $.EventHandler.prototype = { /** - * Remove all event handler for a given event type. + * Remove all event handlers for a given event type. If no type is given all + * event handlers for every event type are removed. * @function * @param {String} eventName - Name of event for which all handlers are to be removed. */ - removeAllHandlers: function( eventName ){ - this.events[ eventName ] = []; + removeAllHandlers: function( eventName ) { + if (eventName){ + this.events[ eventName ] = []; + } else{ + for (var eventType in this.events) { + this.events[eventType] = []; + } + } }, - /** * Retrive the list of all handlers registered for a given event. * @function diff --git a/src/mousetracker.js b/src/mousetracker.js index 1dbe7f1b..f2dd53f8 100644 --- a/src/mousetracker.js +++ b/src/mousetracker.js @@ -171,6 +171,15 @@ $.MouseTracker.prototype = { + /** + * Clean up any events or objects created by the mouse tracker. + * @function + */ + destroy: function() { + stopTracking( this ); + this.element = null; + }, + /** * Are we currently tracking events on this element. * @deprecated Just use this.tracking diff --git a/src/overlay.js b/src/overlay.js index 8635499f..a0e40490 100644 --- a/src/overlay.js +++ b/src/overlay.js @@ -157,6 +157,9 @@ } } + // clear the onDraw callback + this.onDraw = null; + style.top = ""; style.left = ""; style.position = ""; diff --git a/src/viewer.js b/src/viewer.js index 0c6f5969..d9b02708 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -499,7 +499,9 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype, this.viewport = this.preserveViewport ? this.viewport : null; //this.profiler = null; - this.canvas.innerHTML = ""; + if (this.canvas){ + this.canvas.innerHTML = ""; + } VIEWERS[ this.hash ] = null; delete VIEWERS[ this.hash ]; @@ -509,6 +511,47 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype, return this; }, + + /** + * Function to destroy the viewer and clean up everything created by + * OpenSeadragon. + * @function + * @name OpenSeadragon.Viewer.prototype.destroy + */ + destroy: function( ) { + this.close(); + + this.removeAllHandlers(); + + // Go through top element (passed to us) and remove all children + // Use removeChild to make sure it handles SVG or any non-html + // also it performs better - http://jsperf.com/innerhtml-vs-removechild/15 + if (this.element){ + while (this.element.firstChild) { + this.element.removeChild(this.element.firstChild); + } + } + + // destroy the mouse trackers + if (this.keyboardCommandArea){ + this.keyboardCommandArea.innerTracker.destroy(); + } + if (this.innerTracker){ + this.innerTracker.destroy(); + } + if (this.outerTracker){ + this.outerTracker.destroy(); + } + + // clear all our references to dom objects + this.canvas = null; + this.keyboardCommandArea = null; + this.container = null; + + // clear our reference to the main element - they will need to pass it in again, creating a new viewer + this.element = null; + }, + /** * @function diff --git a/test/basic.js b/test/basic.js index 61f36673..7e0492c0 100644 --- a/test/basic.js +++ b/test/basic.js @@ -208,4 +208,31 @@ viewer.open('/test/data/testpattern.dzi'); }); + // ---------- + asyncTest('Destroy', function() { + viewer.addHandler("open", function () { + // Check that the DOM has been modified + notEqual(0, $('#example').children().length); + + var closeCalled = false; + var closeHandler = function() { + viewer.removeHandler('close', closeHandler); + closeCalled = true; + }; + + viewer.addHandler('close', closeHandler); + viewer.destroy(); + + // Check that the DOM has been cleaned up + equal(0, $('#example').children().length); + equal(null, viewer.canvas); + equal(null, viewer.keyboardCommandArea); + equal(null, viewer.container); + equal(null, viewer.element); + equal(true, closeCalled); + start(); + }); + viewer.open('/test/data/testpattern.dzi'); + }); + })();