From 259809e5457945193aa57b1cf72b8990b6dd004e Mon Sep 17 00:00:00 2001 From: Szymon Porwolik Date: Mon, 24 Nov 2025 20:07:10 +0100 Subject: [PATCH] Ensure DX Waterfall object is destroyed when turned off Ultimate fix for DX Waterfall not closed properly --- assets/js/dxwaterfall.js | 97 +++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 45 deletions(-) diff --git a/assets/js/dxwaterfall.js b/assets/js/dxwaterfall.js index f63b977bb..21a0dae5c 100644 --- a/assets/js/dxwaterfall.js +++ b/assets/js/dxwaterfall.js @@ -1,7 +1,7 @@ // @ts-nocheck /** * @fileoverview DX WATERFALL for WaveLog - * @version 0.9.5 // also change line 32 + * @version 0.9.6 // also change line 32 * @author Wavelog Team * * @description @@ -29,7 +29,7 @@ var DX_WATERFALL_CONSTANTS = { // Version - VERSION: '0.9.5', // DX Waterfall version (keep in sync with @version in file header) + VERSION: '0.9.6', // DX Waterfall version (keep in sync with @version in file header) // Debug and logging DEBUG_MODE: false, // Set to true for verbose logging, false for production @@ -1595,8 +1595,10 @@ var dxWaterfall = { var checkFrequency = function(attemptsLeft) { // Check if already completed (state changed from INITIALIZING) var state = DXWaterfallStateMachine.getState(); - if (state === DX_WATERFALL_CONSTANTS.STATES.READY || state === DX_WATERFALL_CONSTANTS.STATES.ERROR) { - // Already initialized or error occurred - stop checking + if (state === DX_WATERFALL_CONSTANTS.STATES.READY || + state === DX_WATERFALL_CONSTANTS.STATES.ERROR || + state === DX_WATERFALL_CONSTANTS.STATES.DISABLED) { + // Already initialized, error occurred, or waterfall was disabled - stop checking if (frequencyCheckTimer) { clearTimeout(frequencyCheckTimer); frequencyCheckTimer = null; @@ -5870,6 +5872,15 @@ var dxWaterfall = { if (this.$freqCalculated) { this.$freqCalculated.off('focus blur input keydown'); } + if (this.$frequency) { + this.$frequency.off('change'); + } + if (this.$bandSelect) { + this.$bandSelect.off('change'); + } + if (this.$modeSelect) { + this.$modeSelect.off('change'); + } if (this.canvas) { // Unbind jQuery events on canvas (click is handled globally, not here) $(this.canvas).off('wheel'); @@ -6772,6 +6783,7 @@ function setFrequency(frequencyInKHz, fromWaterfall) { // Debounce variables for power toggle var lastToggleTime = 0; var TOGGLE_DEBOUNCE_MS = 5000; // 5 second cooldown + var initializationDelayTimer = null; // Track the 3-second initialization delay timer // Shared debounce check function var checkToggleDebounce = function() { @@ -6810,6 +6822,9 @@ function setFrequency(frequencyInKHz, fromWaterfall) { waterfallActive = true; + // Log user action + DX_WATERFALL_UTILS.log.debug('[Power Control] User turned ON waterfall'); + // Update UI - hide header, show content area, show power-off icon, update container styling $('#dxWaterfallSpot').addClass('active'); $('#dxWaterfallSpotHeader').addClass('hidden'); @@ -6821,57 +6836,39 @@ function setFrequency(frequencyInKHz, fromWaterfall) { $('#dxWaterfallCanvasContainer').show(); $('#dxWaterfallMenuContainer').show(); - // Initialize waterfall - destroy first if already exists to ensure clean state + // Completely destroy and reinitialize waterfall for clean state if (typeof dxWaterfall !== 'undefined') { - // Check current state - only destroy if in a state that needs cleanup var currentState = DXWaterfallStateMachine.getState(); - // Don't destroy if: - // - Already disabled (nothing to destroy) - // - In INITIALIZING state (let it finish initializing) - var shouldDestroy = currentState !== DX_WATERFALL_CONSTANTS.STATES.DISABLED && - currentState !== DX_WATERFALL_CONSTANTS.STATES.INITIALIZING && - dxWaterfall.canvas; - - if (shouldDestroy) { + // Destroy if not already disabled (clears event handlers and state) + if (currentState !== DX_WATERFALL_CONSTANTS.STATES.DISABLED && dxWaterfall.canvas) { dxWaterfall.destroy(); } - // Only proceed if currently disabled - if (currentState === DX_WATERFALL_CONSTANTS.STATES.DISABLED) { - // Transition to INITIALIZING state immediately - DXWaterfallStateMachine.setState(DX_WATERFALL_CONSTANTS.STATES.INITIALIZING); + // Transition to INITIALIZING state + DXWaterfallStateMachine.setState(DX_WATERFALL_CONSTANTS.STATES.INITIALIZING); - // Initialize canvas immediately so we can show waiting message - dxWaterfall._initializeCanvas(); + // Initialize canvas immediately so we can show waiting message + dxWaterfall._initializeCanvas(); - // Show waiting message using the helper function (cleaner and consistent) - dxWaterfall.displayWaitingMessage(lang_dxwaterfall_please_wait); + // Show waiting message + dxWaterfall.displayWaitingMessage(lang_dxwaterfall_please_wait); - // Set up periodic refresh interval - waterfallRefreshInterval = setInterval(function() { - if (dxWaterfall.canvas) { - var currentState = DXWaterfallStateMachine.getState(); - if (currentState === DX_WATERFALL_CONSTANTS.STATES.TUNING) { - // Fast refresh during CAT operations for spinner animation - dxWaterfall.refresh(); - } else { - // Normal refresh when idle - dxWaterfall.refresh(); - } - } - }, DX_WATERFALL_CONSTANTS.VISUAL.STATIC_NOISE_REFRESH_MS); + // Set up periodic refresh interval + waterfallRefreshInterval = setInterval(function() { + if (dxWaterfall.canvas) { + dxWaterfall.refresh(); + } + }, DX_WATERFALL_CONSTANTS.VISUAL.STATIC_NOISE_REFRESH_MS); - // Add 3 second delay before actually initializing and fetching data - // This allows page to fully load and stabilize - setTimeout(function() { - // Only proceed if still in INITIALIZING state (not manually changed) - if (DXWaterfallStateMachine.getState() === DX_WATERFALL_CONSTANTS.STATES.INITIALIZING) { - // Continue initialization - check for valid frequency and start data fetch - dxWaterfall._continueInitialization(); - } - }, 3000); // 3 second delay before data fetch - } + // Add 3 second delay before initializing (allows page to stabilize) + initializationDelayTimer = setTimeout(function() { + if (DXWaterfallStateMachine.getState() === DX_WATERFALL_CONSTANTS.STATES.INITIALIZING) { + // Complete initialization - this re-attaches event handlers and starts fetching + dxWaterfall._completeInitialization(); + } + initializationDelayTimer = null; + }, 3000); } }; @@ -6898,6 +6895,16 @@ function setFrequency(frequencyInKHz, fromWaterfall) { waterfallActive = false; + // Log user action + DX_WATERFALL_UTILS.log.debug('[Power Control] User turned OFF waterfall'); + + // Clear the initialization delay timer if still pending + if (initializationDelayTimer) { + clearTimeout(initializationDelayTimer); + initializationDelayTimer = null; + DX_WATERFALL_UTILS.log.debug('[Power Control] Cleared pending initialization timer'); + } + // Stop the refresh interval (managed outside dxWaterfall object) if (waterfallRefreshInterval) { clearInterval(waterfallRefreshInterval);