this.zoomOutBtn = null;
this.zoomResetBtn = null;
+ // Use an AbortController for robust event listener cleanup.
+ this.abortController = new AbortController();
+
// Bind event handlers for proper addition and removal
this.boundMouseMoveHandler = this.handleMouseMove.bind(this);
this.boundMouseUpHandler = this.handleMouseUp.bind(this);
}
setupEventListeners() {
- this.toggleInteractionBtn.addEventListener('click', this.boundToggleInteraction);
- this.copyCodeBtn.addEventListener('click', this.boundCopyCode);
- this.zoomInBtn.addEventListener('click', this.boundZoomIn);
- this.zoomOutBtn.addEventListener('click', this.boundZoomOut);
- this.zoomResetBtn.addEventListener('click', this.boundResetZoom);
+ const { signal } = this.abortController;
+
+ this.toggleInteractionBtn.addEventListener('click', this.boundToggleInteraction, { signal });
+ this.copyCodeBtn.addEventListener('click', this.boundCopyCode, { signal });
+ this.zoomInBtn.addEventListener('click', this.boundZoomIn, { signal });
+ this.zoomOutBtn.addEventListener('click', this.boundZoomOut, { signal });
+ this.zoomResetBtn.addEventListener('click', this.boundResetZoom, { signal });
- this.viewport.addEventListener('wheel', this.boundHandleWheel, { passive: false });
- this.viewport.addEventListener('mousedown', this.boundHandleMouseDown);
+ this.viewport.addEventListener('wheel', this.boundHandleWheel, { passive: false, signal });
+ this.viewport.addEventListener('mousedown', this.boundHandleMouseDown, { signal });
// Listen on document for mousemove to handle dragging outside viewport
- document.addEventListener('mousemove', this.boundMouseMoveHandler);
+ document.addEventListener('mousemove', this.boundMouseMoveHandler, { signal });
// Listen on window for mouseup to ensure drag ends even if mouse is released outside
- window.addEventListener('mouseup', this.boundMouseUpHandler, true); // Use capture phase
+ window.addEventListener('mouseup', this.boundMouseUpHandler, { signal, capture: true });
- this.viewport.addEventListener('contextmenu', this.boundPreventDefault);
- this.viewport.addEventListener('selectstart', this.boundPreventSelect);
+ this.viewport.addEventListener('contextmenu', this.boundPreventDefault, { signal });
+ this.viewport.addEventListener('selectstart', this.boundPreventSelect, { signal });
}
toggleInteraction() {
}
destroy() {
- // Remove event listeners specific to this instance
- this.toggleInteractionBtn.removeEventListener('click', this.boundToggleInteraction);
- this.copyCodeBtn.removeEventListener('click', this.boundCopyCode);
- this.zoomInBtn.removeEventListener('click', this.boundZoomIn);
- this.zoomOutBtn.removeEventListener('click', this.boundZoomOut);
- this.zoomResetBtn.removeEventListener('click', this.boundResetZoom);
-
- this.viewport.removeEventListener('wheel', this.boundHandleWheel, { passive: false });
- this.viewport.removeEventListener('mousedown', this.boundHandleMouseDown);
- this.viewport.removeEventListener('contextmenu', this.boundPreventDefault);
- this.viewport.removeEventListener('selectstart', this.boundPreventSelect);
-
- document.removeEventListener('mousemove', this.boundMouseMoveHandler);
- window.removeEventListener('mouseup', this.boundMouseUpHandler, true);
-
+ // Abort all listeners attached with this controller's signal.
+ this.abortController.abort();
this.container.innerHTML = ''; // Clear the container's content
}
}