`;
// Removed symbol info from popup
// content += `
${symbolDesc}
`;
if (comment) {
content += `
${comment}
`;
}
if (data.timestamp) {
const timestamp = parseTimestamp(data.timestamp);
const date = new Date(timestamp);
if (!isNaN(date.getTime())) {
content += `
${date.toISOString()}
`;
}
}
content += "
";
return content;
},
destroyed() {
const self = this as unknown as LiveViewHookContext;
// Mark as destroyed immediately
self.isDestroyed = true;
// Disable pushEvent to prevent any events from being sent during cleanup
const originalPushEvent = self.pushEvent;
self.pushEvent = () => {}; // No-op function
// Clear interval timer
if (self.cleanupInterval !== undefined) {
clearInterval(self.cleanupInterval);
self.cleanupInterval = undefined;
}
// Clear programmatic move timeout
if (self.programmaticMoveTimeout !== undefined) {
clearTimeout(self.programmaticMoveTimeout);
self.programmaticMoveTimeout = undefined;
}
// Remove popup navigation event listener
if (self.popupNavigationHandler) {
document.removeEventListener('click', self.popupNavigationHandler);
self.popupNavigationHandler = undefined;
}
// Close any open popups before cleanup
if (self.map !== undefined) {
try {
self.map.closePopup();
} catch (e) {
console.debug("Error closing popup during cleanup:", e);
}
}
if (self.boundsTimer !== undefined) {
clearTimeout(self.boundsTimer);
}
if (self.resizeHandler !== undefined) {
window.removeEventListener("resize", self.resizeHandler);
self.resizeHandler = undefined;
}
// Remove map event handlers
if (self.map !== undefined && self.mapEventHandlers !== undefined) {
self.mapEventHandlers.forEach((handler, event) => {
try {
self.map.off(event, handler);
} catch (e) {
console.debug(`Error removing ${event} handler:`, e);
}
});
self.mapEventHandlers.clear();
}
// Remove all event listeners from markers before clearing layers
if (self.markers !== undefined) {
self.markers.forEach((marker: any) => {
try {
marker.off(); // Remove all event listeners
if (marker.getPopup()) {
marker.unbindPopup(); // Unbind popup to prevent events
}
} catch (e) {
console.debug(`Error cleaning up marker:`, e);
}
});
}
if (self.markerLayer !== undefined) {
self.markerLayer!.clearLayers();
}
if (self.markers !== undefined) {
self.markers!.clear();
}
if (self.markerStates !== undefined) {
self.markerStates!.clear();
}
if (self.map !== undefined) {
self.map!.remove();
self.map = undefined;
}
// Restore original pushEvent (though it won't be used since we're destroyed)
self.pushEvent = originalPushEvent;
},
};
// Helper to validate and fallback symbol code per aprs.fi logic
function getValidSymbolCode(
symbolCode: string | undefined,
symbolTableId: string | undefined,
): string {
if (!symbolCode || symbolCode.length !== 1) {
return symbolTableId === "\\" ? "O" : ">";
}
const code = symbolCode.charCodeAt(0);
if (code < 33 || code > 126) {
return symbolTableId === "\\" ? "O" : ">";
}
return symbolCode;
}
export default MapAPRSMap;