// GridTracker Copyright © 2023 GridTracker.org // All rights reserved. // See LICENSE for more information. const pjson = require("./package.json"); var gtVersionStr = pjson.version var gtVersion = parseInt(gtVersionStr.replace(/\./g, "")); var gtBeta = pjson.betaVersion; GT.startingUp = true; // var GT is in screen.js GT.startVersion = 0; if (typeof localStorage.currentVersion != "undefined") { GT.startVersion = parseInt(localStorage.currentVersion); } GT.firstRun = false; if (typeof localStorage.currentVersion == "undefined" || localStorage.currentVersion != String(gtVersion)) { if (typeof localStorage.currentVersion == "undefined") { GT.firstRun = true; } localStorage.currentVersion = String(gtVersion); } const vers = String(gtVersion); const gtShortVersion = "v" + vers.substr(0, 1) + "." + vers.substr(1, 2) + "." + vers.substr(3, 4) + (gtBeta.length > 0 ? (" " + gtBeta) : ""); const gtVersionString = "GridTracker " + gtShortVersion; const gtUserAgent = "GridTracker/" + vers.substr(0, 1) + "." + vers.substr(1, 2) + "." + vers.substr(3, 4); const os = require("os"); const fs = require("fs"); const process = require("process"); const path = require("path"); GT.dirSeperator = path.sep; GT.platform = os.platform(); if (GT.platform.indexOf("win") == 0 || GT.platform.indexOf("Win") == 0) { GT.platform = "windows"; } if (GT.platform.indexOf("inux") > -1) { GT.platform = "linux"; } if (GT.platform.indexOf("darwin") > -1) { GT.platform = "mac"; } const gui = require("nw.gui"); const win = gui.Window.get(); if (GT.firstRun) { win.moveTo(2, 2); } GT.developerMode = process.versions["nw-flavor"] == "sdk"; GT.popupWindowHandle = null; GT.callRosterWindowHandle = null; GT.conditionsWindowHandle = null; GT.conditionsWindowInitialized = false; GT.chatWindowHandle = null; GT.chatWindowInitialized = false; GT.statsWindowHandle = null; GT.statsWindowInitialized = false; GT.lookupWindowHandle = null; GT.lookupWindowInitialized = false; GT.baWindowHandle = null; GT.baWindowInitialized = false; GT.alertWindowHandle = null; GT.alertWindowInitialized = false; GT.myDXGrid = ""; GT.appSettings = {}; GT.mapSettings = {}; GT.legendColors = {}; GT.adifLogSettings = {}; GT.msgSettings = {}; GT.receptionSettings = {}; GT.receptionReports = { lastDownloadTimeSec: 0, lastSequenceNumber: "0", spots: {} }; GT.N1MMSettings = {}; GT.log4OMSettings = {}; GT.dxkLogSettings = {}; GT.HRDLogbookLogSettings = {}; GT.acLogSettings = {}; GT.trustedQslSettings = {}; GT.callsignLookups = {}; GT.startupLogs = []; GT.mapMemory = []; GT.callsignDatabaseDXCC = { 291: true, 1: true, 6: true, 110: true, 202: true }; GT.callsignDatabaseUS = { 291: true, 6: true, 110: true }; GT.callsignDatabaseUSplus = { 291: true, 6: true, 110: true, 202: true }; GT.acknowledgedCalls = {}; function loadAllSettings() { for (let x in localStorage) { if (!validSettings.includes(x) && typeof localStorage[x] == "string") { delete localStorage[x]; } } GT.appSettings = loadDefaultsAndMerge("appSettings", def_appSettings); GT.mapSettings = loadDefaultsAndMerge("mapSettings", def_mapSettings); GT.legendColors = loadDefaultsAndMerge("legendColors", def_legendColors); GT.adifLogSettings = loadDefaultsAndMerge( "adifLogSettings", def_adifLogSettings ); GT.msgSettings = loadDefaultsAndMerge("msgSettings", def_msgSettings); GT.receptionSettings = loadDefaultsAndMerge( "receptionSettings", def_receptionSettings ); GT.N1MMSettings = loadDefaultsAndMerge("N1MMSettings", def_N1MMSettings); GT.log4OMSettings = loadDefaultsAndMerge("log4OMSettings", def_log4OMSettings); GT.dxkLogSettings = loadDefaultsAndMerge("dxkLogSettings", def_dxkLogSettings); GT.HRDLogbookLogSettings = loadDefaultsAndMerge( "HRDLogbookLogSettings", def_HRDLogbookLogSettings ); GT.pstrotatorSettings = loadDefaultsAndMerge( "pstrotatorSettings", def_pstrotatorSettings ); GT.acLogSettings = loadDefaultsAndMerge("acLogSettings", def_acLogSettings); GT.trustedQslSettings = loadDefaultsAndMerge( "trustedQslSettings", def_trustedQslSettings ); GT.callsignLookups = loadDefaultsAndMerge( "callsignLookups", def_callsignLookups ); GT.bandActivity = loadDefaultsAndMerge("bandActivity", def_bandActivity); GT.startupLogs = loadArrayIfExists("startupLogs"); GT.mapMemory = loadArrayIfExists("mapMemory"); if (GT.mapMemory.length != 7) { GT.mapMemory = []; for (let x = 0; x < 7; x++) { GT.mapMemory[x] = {}; GT.mapMemory[x].zoom = -1; GT.mapMemory[x].LoLa = [0, 0]; } GT.appSettings.mapMemory = JSON.stringify(GT.mapMemory); } } loadAllSettings(); const k_frequencyBucket = 10000; GT.flightDuration = 30; GT.crScript = GT.appSettings.crScript; GT.spotView = GT.appSettings.spotView; GT.myLat = GT.mapSettings.latitude; GT.myLon = GT.mapSettings.longitude; function loadDefaultsAndMerge(key, def) { var settings = {}; if (key in localStorage) { settings = JSON.parse(localStorage[key]); } var merged = deepmerge(def, settings); for (var x in merged) { if (!(x in def)) { delete merged[x]; } } localStorage[key] = JSON.stringify(merged); return merged; } function loadArrayIfExists(key) { var data = []; if (key in localStorage) { data = JSON.parse(localStorage[key]); } return data; } function loadObjectIfExists(key) { var data = {}; if (key in localStorage) { data = JSON.parse(localStorage[key]); } return data; } function saveAppSettings() { localStorage.appSettings = JSON.stringify(GT.appSettings); } function saveMapSettings() { localStorage.mapSettings = JSON.stringify(GT.mapSettings); } function saveLegendColors() { localStorage.legendColors = JSON.stringify(GT.legendColors); } function saveAdifSettings() { localStorage.adifLogSettings = JSON.stringify(GT.adifLogSettings); } function saveStartupLogs() { localStorage.startupLogs = JSON.stringify(GT.startupLogs); } function saveLogSettings() { localStorage.adifLogSettings = JSON.stringify(GT.adifLogSettings); localStorage.N1MMSettings = JSON.stringify(GT.N1MMSettings); localStorage.log4OMSettings = JSON.stringify(GT.log4OMSettings); localStorage.dxkLogSettings = JSON.stringify(GT.dxkLogSettings); localStorage.HRDLogbookLogSettings = JSON.stringify(GT.HRDLogbookLogSettings); localStorage.pstrotatorSettings = JSON.stringify(GT.pstrotatorSettings); localStorage.acLogSettings = JSON.stringify(GT.acLogSettings); localStorage.trustedQslSettings = JSON.stringify(GT.trustedQslSettings); } function saveAndCloseApp() { GT.closing = true; saveReceptionReports(); try { var data = {}; data.version = gtVersion; data.tracker = GT.tracker; for (var key in GT.QSOhash) GT.QSOhash[key].rect = null; data.g_QSOhash = GT.QSOhash; fs.writeFileSync(GT.NWappData + "internal_qso.json", JSON.stringify(data)); saveScreenSettings(); GT.conditionsWindowHandle.window.saveScreenSettings(); GT.callRosterWindowHandle.window.saveScreenSettings(); GT.statsWindowHandle.window.saveScreenSettings(); GT.baWindowHandle.window.saveScreenSettings(); GT.alertWindowHandle.window.saveScreenSettings(); GT.lookupWindowHandle.window.saveScreenSettings(); GT.chatWindowHandle.window.saveScreenSettings(); } catch (e) { console.error(e); } if (GT.map) { mapMemory(6, true, true); GT.mapSettings.zoom = GT.map.getView().getZoom(); saveMapSettings(); } if (GT.wsjtUdpServer != null) { try { if (multicastEnable.checked == true && GT.appSettings.wsjtIP != "") { GT.wsjtUdpServer.dropMembership(GT.appSettings.wsjtIP); } GT.wsjtUdpServer.close(); } catch (e) { console.error(e); } } if (GT.forwardUdpServer != null) { GT.forwardUdpServer.close(); } saveAppSettings(); saveAdifSettings(); saveMapSettings(); saveLegendColors(); try { if (GT.rosterInitialized) { GT.callRosterWindowHandle.window.writeRosterSettings(); } if (GT.popupWindowHandle != null) GT.popupWindowHandle.window.close(true); GT.conditionsWindowHandle.window.close(true); GT.chatWindowHandle.window.close(true); GT.statsWindowHandle.window.close(true); GT.lookupWindowHandle.window.close(true); GT.baWindowHandle.window.close(true); GT.alertWindowHandle.window.isShowing = false; GT.alertWindowHandle.window.saveScreenSettings(); GT.alertWindowHandle.window.close(true); GT.callRosterWindowHandle.window.close(true); } catch (e) { console.error(e); } nw.App.quit(); } function clearAndReload() { GT.closing = true; if (GT.wsjtUdpServer != null) { GT.wsjtUdpServer.close(); GT.wsjtUdpServer = null; } localStorage.clear(); chrome.runtime.reload(); } win.hide(); win.on("close", function () { saveAndCloseApp(); }); win.show(); win.setMinimumSize(200, 600); GT.wsjtxProcessRunning = false; GT.jtdxProcessRunning = false; GT.wsjtxIni = Array(); GT.jtdxIni = Array(); GT.setNewUdpPortTimeoutHandle = null; GT.map = null; GT.menuShowing = true; GT.closing = false; GT.liveGrids = {}; GT.qsoGrids = {}; GT.liveCallsigns = {}; GT.flightPaths = Array(); GT.flightPathOffset = 0; GT.flightPathLineDash = [9, 3, 3]; GT.flightPathTotal = (9 + 3 + 3) * 2; GT.lastMessages = Array(); GT.lastTraffic = Array(); GT.showAllGrids = false; GT.maps = Array(); GT.modes = {}; GT.modes_phone = {}; GT.colorBands = [ "OOB", "4000m", "2200m", "630m", "160m", "80m", "60m", "40m", "30m", "20m", "17m", "15m", "12m", "11m", "10m", "8m", "6m", "4m", "2m", "1.25m", "70cm", "33cm", "23cm", "13cm", "9cm", "5cm", "3cm", "1.2cm", "6mm", "4mm", "2.5mm", "2mm", "1mm" ]; GT.pathIgnore = {}; GT.pathIgnore.RU = true; GT.pathIgnore.FTRU = true; GT.pathIgnore.FD = true; GT.pathIgnore.TEST = true; GT.pathIgnore.DX = true; GT.pathIgnore.CQ = true; GT.replaceCQ = {}; GT.replaceCQ.ASIA = "AS"; GT.myDXCC = -1; GT.QSOhash = {}; GT.QSLcount = 0; GT.QSOcount = 0; GT.ignoreMessages = 0; GT.lastTimeSinceMessageInSeconds = timeNowSec(); GT.loadQSOs = false; GT.mainBorderColor = "#222222FF"; GT.pushPinMode = false; GT.pskBandActivityTimerHandle = null; GT.workingIniPath = ""; GT.dxccInfo = {}; GT.prefixToMap = {}; GT.directCallToDXCC = {}; GT.directCallToCQzone = {}; GT.directCallToITUzone = {}; GT.prefixToCQzone = {}; GT.prefixToITUzone = {}; GT.dxccToAltName = {}; GT.dxccToCountryCode = {}; GT.altNameToDXCC = {}; GT.dxccToADIFName = {}; GT.gridToDXCC = {}; GT.gridToState = {}; GT.StateData = {}; GT.cqZones = {}; GT.wacZones = {}; GT.wasZones = {}; GT.ituZones = {}; GT.dxccCount = {}; GT.unconfirmedCalls = new Map(); GT.tracker = {}; GT.lastTrasmissionTimeSec = timeNowSec(); GT.getPostBuffer = getPostBuffer; const PSKREPORTER_INTERVAL_IN_SECONDS = 5 * 60; initQSOdata(); function initQSOdata() { GT.tracker.worked = {}; GT.tracker.confirmed = {}; GT.tracker.worked.call = {}; GT.tracker.worked.grid = {}; GT.tracker.worked.dxcc = {}; GT.tracker.worked.cqz = {}; GT.tracker.worked.ituz = {}; GT.tracker.worked.state = {}; GT.tracker.worked.px = {}; GT.tracker.worked.cnty = {}; GT.tracker.worked.cont = {}; GT.tracker.worked.pota = {}; GT.tracker.confirmed.call = {}; GT.tracker.confirmed.grid = {}; GT.tracker.confirmed.dxcc = {}; GT.tracker.confirmed.cqz = {}; GT.tracker.confirmed.ituz = {}; GT.tracker.confirmed.state = {}; GT.tracker.confirmed.px = {}; GT.tracker.confirmed.cnty = {}; GT.tracker.confirmed.cont = {}; GT.tracker.confirmed.pota = {}; } GT.offlineLayer = null; GT.mapsLayer = Array(); GT.tileLayer = null; GT.mapView = null; GT.layerSources = {}; GT.layerVectors = {}; GT.scaleLine = null; GT.scaleUnits = {}; GT.scaleUnits.MI = "us"; GT.scaleUnits.KM = "metric"; GT.scaleUnits.NM = "nautical"; GT.scaleUnits.DG = "degrees"; GT.passingToolTipTableString = ""; GT.mouseX = 0; GT.mouseY = 0; GT.appData = ""; GT.jsonDir = ""; GT.NWappData = ""; GT.screenshotDir = ""; GT.scriptDir = ""; GT.qsoLogFile = ""; GT.LoTWLogFile = ""; GT.userMediaDir = ""; GT.gtMediaDir = path.resolve("./media"); GT.localeString = navigator.language; GT.shapeFile = "./data/shapes.json"; GT.mapsFile = "./data/maps.json"; GT.voices = null; GT.shapeData = {}; GT.countyData = {}; GT.zipToCounty = {}; GT.stateToCounty = {}; GT.cntyToCounty = {}; GT.us48Data = {}; GT.pskColors = {}; GT.pskColors.OOB = "888888"; GT.pskColors["4000m"] = "45E0FF"; GT.pskColors["2200m"] = "FF4500"; GT.pskColors["630m"] = "1E90FF"; GT.pskColors["160m"] = "7CFC00"; GT.pskColors["80m"] = "E550E5"; GT.pskColors["60m"] = "99CCFF"; GT.pskColors["40m"] = "00FFFF"; GT.pskColors["30m"] = "62FF62"; GT.pskColors["20m"] = "FFC40C"; GT.pskColors["17m"] = "F2F261"; GT.pskColors["15m"] = "CCA166"; GT.pskColors["12m"] = "CB3D3D"; GT.pskColors["11m"] = "00FF00"; GT.pskColors["10m"] = "FF69B4"; GT.pskColors["8m"] = "8b00fb"; GT.pskColors["6m"] = "ff4d4d"; GT.pskColors["4m"] = "df0040"; GT.pskColors["2m"] = "FF1493"; GT.pskColors["1.25m"] = "beff00"; GT.pskColors["70cm"] = "999900"; GT.pskColors["33cm"] = "ff8c90"; GT.pskColors["23cm"] = "5AB8C7"; GT.pskColors["13cm"] = "ff7540"; GT.pskColors["9cm"] = "b77ac7"; GT.pskColors["5cm"] = "b77ac7"; GT.pskColors["3cm"] = "696969"; GT.pskColors["1.2cm"] = "b77ac7"; GT.pskColors["6mm"] = "b77ac7"; GT.pskColors["4mm"] = "b77ac7"; GT.pskColors["2.5mm"] = "b77ac7"; GT.pskColors["2mm"] = "b77ac7"; GT.pskColors["1mm"] = "b77ac7"; GT.bandToColor = {}; GT.colorLeafletPins = {}; GT.colorLeafletQPins = {}; GT.UTCoptions = { year: "numeric", month: "numeric", day: "numeric", hour: "2-digit", minute: "2-digit", second: "2-digit", timeZone: "UTC", timeZoneName: "short" }; GT.LocalOptions = { year: "numeric", month: "numeric", day: "numeric", hour: "2-digit", minute: "2-digit", second: "2-digit", timeZoneName: "short" }; GT.earthShadowImageArray = Array(); GT.earthShadowImageArray[0] = "./img/shadow_on_32.png"; GT.earthShadowImageArray[1] = "./img/shadow_off_32.png"; GT.gtFlagImageArray = Array(); GT.gtFlagImageArray[1] = "./img/flag_on.png"; GT.gtFlagImageArray[0] = "./img/flag_off.png"; GT.gtShareFlagImageArray = Array(); GT.gtShareFlagImageArray[1] = "./img/share-on.png"; GT.gtShareFlagImageArray[0] = "./img/share-off.png"; GT.mapImageArray = Array(); GT.mapImageArray[1] = "./img/online_map.png"; GT.mapImageArray[0] = "./img/offline_map.png"; GT.pinImageArray = Array(); GT.pinImageArray[1] = "./img/red_pin_32.png"; GT.pinImageArray[0] = "./img/gt_grid.png"; GT.qsoLockImageArray = Array(); GT.qsoLockImageArray[0] = "./img/qso_unlocked_32.png"; GT.qsoLockImageArray[1] = "./img/qso_locked_32.png"; GT.qslLockImageArray = Array(); GT.qslLockImageArray[0] = "./img/qsl_unlocked_32.png"; GT.qslLockImageArray[1] = "./img/qsl_locked_32.png"; GT.alertImageArray = Array(); GT.alertImageArray[0] = "./img/unmuted-button.png"; GT.alertImageArray[1] = "./img/muted-button.png"; GT.spotImageArray = Array(); GT.spotImageArray[0] = "./img/spots.png"; GT.spotImageArray[1] = "./img/spots.png"; GT.spotImageArray[2] = "./img/heat.png"; GT.maidenheadModeImageArray = Array(); GT.maidenheadModeImageArray[0] = "./img/mh4_32.png"; GT.maidenheadModeImageArray[1] = "./img/mh6_32.png"; GT.gridViewArray = Array(); GT.gridViewArray[1] = "Live"; GT.gridViewArray[2] = "Logbook"; GT.gridViewArray[3] = "Logbook & Live"; GT.trophyImageArray = Array(); GT.trophyImageArray[0] = "./img/blank_trophy.png"; GT.trophyImageArray[1] = "./img/cq_trophy.png"; GT.trophyImageArray[2] = "./img/itu_trophy.png"; GT.trophyImageArray[3] = "./img/wac_trophy.png"; GT.trophyImageArray[4] = "./img/was_trophy.png"; GT.trophyImageArray[5] = "./img/dxcc_trophy.png"; GT.trophyImageArray[6] = "./img/usc_trophy.png"; GT.trophyImageArray[7] = "./img/us48_trophy.png"; GT.viewInfo = {}; GT.viewInfo[0] = ["qsoGrids", "Grids", 0, 0, 0]; GT.viewInfo[1] = ["cqZones", "CQ Zones", 0, 0, 40]; GT.viewInfo[2] = ["ituZones", "ITU Zones", 0, 0, 90]; GT.viewInfo[3] = ["wacZones", "Continents", 0, 0, 7]; GT.viewInfo[4] = ["wasZones", "US States", 0, 0, 50]; GT.viewInfo[5] = ["dxccInfo", "DXCCs", 0, 0, 340]; GT.viewInfo[6] = ["countyData", "US Counties", 0, 0, 3220]; GT.viewInfo[7] = ["us48Data", "US Continental Grids", 0, 0, 488]; GT.soundCard = GT.appSettings.soundCard; GT.gridAlpha = "88"; if (typeof GT.mapMemory[6] == "undefined") GT.mapMemory[6] = GT.mapMemory[0]; class UnconfirmedCallsKey { constructor(dxcc, band) { this._DXCC = dxcc; this._BAND = band; } get dxcc() { return parseInt(this._DXCC); } set dxcc(dxcc) { this._DXCC = dxcc; } get band() { return this._BAND; } set band(band) { this._BAND = band; } get key() { return Symbol.for(`UnconfirmedCallsKey[${this.dxcc}:${this.band}]`); } } GT.unconfirmedCallsSentinel = new UnconfirmedCallsKey(0, ""); function qsoBackupFileInit() { var adifHeader = "GridTracker v" + gtVersion + " \r\n"; if (!fs.existsSync(GT.qsoLogFile)) { fs.writeFileSync(GT.qsoLogFile, adifHeader); } } function gtBandFilterChanged(selector) { GT.appSettings.gtBandFilter = selector.value; removePaths(); redrawGrids(); redrawPins(); redrawSpots(); redrawParks(); } function gtModeFilterChanged(selector) { GT.appSettings.gtModeFilter = selector.value; redrawGrids(); redrawPins(); redrawSpots(); redrawParks(); } function gtPropFilterChanged(selector) { GT.appSettings.gtPropFilter = selector.value; redrawGrids(); redrawSpots(); } function setBandAndModeToAuto() { GT.appSettings.gtModeFilter = GT.appSettings.gtBandFilter = gtBandFilter.value = gtModeFilter.value = "auto"; redrawGrids(); redrawPins(); redrawSpots(); redrawParks(); } function hideLiveGrid(i) { if (GT.layerSources.live.hasFeature(GT.liveGrids[i].rectangle)) { GT.layerSources.live.removeFeature(GT.liveGrids[i].rectangle); } } function liveTriangleGrid(i) { if (GT.liveGrids[i].isTriangle == false) { if (GT.layerSources.live.hasFeature(GT.liveGrids[i].rectangle)) { GT.layerSources.live.removeFeature(GT.liveGrids[i].rectangle); } gridToTriangle(i, GT.liveGrids[i].rectangle, false); GT.liveGrids[i].isTriangle = true; GT.layerSources.live.addFeature(GT.liveGrids[i].rectangle); } } function qsoTriangleGrid(i) { if (GT.qsoGrids[i].isTriangle == false) { if (GT.layerSources.qso.hasFeature(GT.qsoGrids[i].rectangle)) { GT.layerSources.qso.removeFeature(GT.qsoGrids[i].rectangle); } gridToTriangle(i, GT.qsoGrids[i].rectangle, true); GT.qsoGrids[i].isTriangle = true; GT.layerSources.qso.addFeature(GT.qsoGrids[i].rectangle); } } function setGridViewMode(mode) { GT.appSettings.gridViewMode = Number(mode); gridViewButton.innerHTML = GT.gridViewArray[GT.appSettings.gridViewMode]; redrawGrids(); goProcessRoster(); } function cycleGridView() { var mode = GT.appSettings.gridViewMode; mode++; if (mode > 3) mode = 1; if (mode < 1) mode = 1; GT.appSettings.gridViewMode = mode; gridViewButton.innerHTML = GT.gridViewArray[GT.appSettings.gridViewMode]; redrawGrids(); saveAppSettings(); } function toggleEarth() { GT.appSettings.earthImgSrc ^= 1; earthImg.src = GT.earthShadowImageArray[GT.appSettings.earthImgSrc]; if (GT.appSettings.earthImgSrc == 1) { dayNight.hide(); GT.nightTime = dayNight.refresh(); } else { GT.nightTime = dayNight.refresh(); dayNight.show(); } changeMapLayer(); } function toggleOffline() { if (GT.map == null) return; if (GT.mapSettings.offlineMode == true) { GT.mapSettings.offlineMode = false; offlineImg.src = GT.mapImageArray[1]; conditionsButton.style.display = "inline-block"; gtFlagButton.style.display = "inline-block"; gtShareButton.style.display = "inline-block"; buttonSpotsBoxDiv.style.display = "inline-block"; donateButton.style.display = "inline-block"; potaButton.style.display = (GT.appSettings.potaEnabled == 1 && GT.appSettings.potaShowMenu) ? "inline-block" : "none"; if (GT.appSettings.gtShareEnable == true) { gtFlagButton.style.display = "inline-block"; if (GT.appSettings.gtMsgEnable == true) { msgButton.style.display = "inline-block"; } else msgButton.style.display = "none"; } else { msgButton.style.display = "none"; gtFlagButton.style.display = "none"; } for (var key in GT.adifLogSettings.menu) { var value = GT.adifLogSettings.menu[key]; var where = key + "Div"; document.getElementById(key).checked = value; if (value == true) { document.getElementById(where).style.display = "inline-block"; } else { document.getElementById(where).style.display = "none"; } } bandActivityDiv.style.display = "block"; } else { GT.mapSettings.offlineMode = true; offlineImg.src = GT.mapImageArray[0]; conditionsButton.style.display = "none"; buttonPsk24CheckBoxDiv.style.display = "none"; buttonQRZCheckBoxDiv.style.display = "none"; buttonLOTWCheckBoxDiv.style.display = "none"; buttonClubCheckBoxDiv.style.display = "none"; gtFlagButton.style.display = "none"; bandActivityDiv.style.display = "none"; gtShareButton.style.display = "none"; msgButton.style.display = "none"; donateButton.style.display = "none"; potaButton.style.display = "none"; buttonSpotsBoxDiv.style.display = "none"; setGtShareButtons(); } loadMapSettings(); changeMapValues(); } // from GridTracker.html function ignoreMessagesToggle() { GT.ignoreMessages ^= 1; if (GT.ignoreMessages == 0) { txrxdec.style.backgroundColor = "Green"; txrxdec.style.borderColor = "GreenYellow"; txrxdec.innerHTML = "RECEIVE"; txrxdec.title = "Click to ignore incoming messages"; } else { txrxdec.style.backgroundColor = "DimGray"; txrxdec.style.borderColor = "DarkGray"; txrxdec.innerHTML = "IGNORE"; txrxdec.title = "Click to resume reading messages"; } } // from GridTracker.html function toggleTime() { GT.appSettings.useLocalTime ^= 1; displayTime(); } function dateToString(dateTime) { if (GT.appSettings.useLocalTime == 1) { return dateTime.toLocaleString().replace(/,/g, ""); } else return dateTime.toUTCString().replace(/GMT/g, "UTC").replace(/,/g, ""); } function userDayString(Msec) { var dateTime; if (Msec != null) dateTime = new Date(Msec); else dateTime = new Date(); var ds = dateTime.toUTCString().replace(/GMT/g, "UTC").replace(/,/g, ""); var dra = ds.split(" "); dra.shift(); dra.pop(); dra.pop(); return dra.join(" "); } function userTimeString(Msec) { var dateTime; if (Msec != null) dateTime = new Date(Msec); else dateTime = new Date(); return dateToString(dateTime); } function getWpx(callsign) { var prefix = null; if (callsign.includes("/")) // Handle in the future? { return null; } if (!/\d/.test(callsign)) // Insert 0, never seen this { return null; } var end = callsign.length; var foundPrefix = false; var prefixEnd = 1; while (prefixEnd != end) { if (/\d/.test(callsign.charAt(prefixEnd))) { while (prefixEnd + 1 != end && /\d/.test(callsign.charAt(prefixEnd + 1))) { prefixEnd++; } foundPrefix = true; break; } prefixEnd++; } if (foundPrefix) prefix = callsign.substr(0, prefixEnd + 1); return String(prefix); } GT.qsoRefreshTimer = null; function refreshQSOs() { if (GT.qsoRefreshTimer != null) { nodeTimers.clearTimeout(GT.qsoRefreshTimer); } GT.qsoRefreshTimer = nodeTimers.setTimeout(processQSOs, 500); } function processQSOs() { GT.qsoRefreshTimer = null; initQSOdata(); var currentYear = new Date().getFullYear(); for (let hash in GT.QSOhash) { let details = GT.QSOhash[hash]; let qsoDate = new Date(1970, 0, 1); qsoDate.setSeconds(details.time); let isCurrentYear = (qsoDate.getFullYear() == currentYear); let dayAsString = String(parseInt(details.time / 86400)); let fourGrid = details.grid.substr(0, 4); let isDigi = details.digital; let isPhone = details.phone; GT.tracker.worked.call[details.DXcall + details.band + details.mode] = true; GT.tracker.worked.call[details.DXcall] = true; GT.tracker.worked.call[details.DXcall + details.mode] = true; GT.tracker.worked.call[details.DXcall + details.band] = true; if (isDigi == true) { GT.tracker.worked.call[details.DXcall + "dg"] = true; GT.tracker.worked.call[details.DXcall + details.band + "dg"] = true; } if (fourGrid != "") { GT.tracker.worked.grid[fourGrid] = true; GT.tracker.worked.grid[fourGrid + details.mode] = true; GT.tracker.worked.grid[fourGrid + details.band] = true; GT.tracker.worked.grid[fourGrid + details.band + details.mode] = true if (isDigi == true) { GT.tracker.worked.grid[fourGrid + "dg"] = true; GT.tracker.worked.grid[fourGrid + details.band + "dg"] = true; } } if (details.ituz) { GT.tracker.worked.ituz[details.ituz + "|" + details.band + details.mode] = true; GT.tracker.worked.ituz[details.ituz + "|"] = true; GT.tracker.worked.ituz[details.ituz + "|" + details.mode] = true; GT.tracker.worked.ituz[details.ituz + "|" + details.band] = true; if (isDigi == true) { GT.tracker.worked.ituz[details.ituz + "|dg"] = true; GT.tracker.worked.ituz[details.ituz + "|" + details.band + "dg"] = true; } } if (details.cqz) { GT.tracker.worked.cqz[details.cqz + "|" + details.band + details.mode] = true; GT.tracker.worked.cqz[details.cqz + "|"] = true; GT.tracker.worked.cqz[details.cqz + "|" + details.mode] = true; GT.tracker.worked.cqz[details.cqz + "|" + details.band] = true; if (isDigi == true) { GT.tracker.worked.cqz[details.cqz + "|dg"] = true; GT.tracker.worked.cqz[details.cqz + "|" + details.band + "dg"] = true; } if (isCurrentYear) { GT.tracker.worked.cqz[`${details.cqz}-${currentYear}`] = true; } } if (details.dxcc > 0) { var sDXCC = String(details.dxcc); GT.tracker.worked.dxcc[sDXCC + "|" + details.band + details.mode] = true; GT.tracker.worked.dxcc[sDXCC + "|"] = true; GT.tracker.worked.dxcc[sDXCC + "|" + details.mode] = true; GT.tracker.worked.dxcc[sDXCC + "|" + details.band] = true; if (isDigi == true) { GT.tracker.worked.dxcc[sDXCC + "|dg"] = true; GT.tracker.worked.dxcc[sDXCC + "|" + details.band + "dg"] = true; } if (isCurrentYear) { GT.tracker.worked.dxcc[`${sDXCC}-${currentYear}`] = true; } } if (details.px) { GT.tracker.worked.px[details.px + details.band + details.mode] = true; // store the last one GT.tracker.worked.px[details.px] = hash; GT.tracker.worked.px[details.px + details.mode] = true; GT.tracker.worked.px[details.px + details.band] = true; if (isDigi == true) { GT.tracker.worked.px[details.px + "dg"] = true; GT.tracker.worked.px[details.px + details.band + "dg"] = true; } if (isPhone == true) { GT.tracker.worked.px[details.px + "ph"] = true; GT.tracker.worked.px[details.px + details.band + "ph"] = true; } } if (details.cont) { GT.tracker.worked.cont[details.cont + details.band + details.mode] = true; // store the last one GT.tracker.worked.cont[details.cont] = hash; GT.tracker.worked.cont[details.cont + details.mode] = true; GT.tracker.worked.cont[details.cont + details.band] = true; if (isDigi == true) { GT.tracker.worked.cont[details.cont + "dg"] = true; GT.tracker.worked.cont[details.cont + details.band + "dg"] = true; } } if (details.state) { GT.tracker.worked.state[details.state] = true; GT.tracker.worked.state[details.state + details.mode] = true; GT.tracker.worked.state[details.state + details.band] = true; GT.tracker.worked.state[details.state + details.band + details.mode] = true; if (isDigi) { GT.tracker.worked.state[details.state + "dg"] = GT.tracker.worked.state[details.state + details.band + "dg"] = true; } } if (details.cnty) { GT.tracker.worked.cnty[details.cnty] = true; GT.tracker.worked.cnty[details.cnty + details.mode] = true; GT.tracker.worked.cnty[details.cnty + details.band] = true; GT.tracker.worked.cnty[details.cnty + details.band + details.mode] = true; if (isDigi) { GT.tracker.worked.cnty[details.cnty + "dg"] = true; GT.tracker.worked.cnty[details.cnty + details.band + "dg"] = true; } } if (details.pota) { GT.tracker.worked.pota[dayAsString + details.DXcall + details.pota] = true; GT.tracker.worked.pota[dayAsString + details.DXcall + details.pota + details.mode] = true; GT.tracker.worked.pota[dayAsString + details.DXcall + details.pota + details.band] = true; GT.tracker.worked.pota[dayAsString + details.DXcall + details.pota + details.band + details.mode] = true; if (isDigi == true) { GT.tracker.worked.pota[dayAsString + details.DXcall + details.pota + "dg"] = true; GT.tracker.worked.pota[dayAsString + details.DXcall + details.pota + details.band + "dg"] = true; } } if (details.confirmed == true) { GT.tracker.confirmed.call[details.DXcall + details.band + details.mode] = true; GT.tracker.confirmed.call[details.DXcall] = true; GT.tracker.confirmed.call[details.DXcall + details.mode] = true; GT.tracker.confirmed.call[details.DXcall + details.band] = true; if (isDigi == true) { GT.tracker.confirmed.call[details.DXcall + "dg"] = true; GT.tracker.confirmed.call[details.DXcall + details.band + "dg"] = true; } if (fourGrid != "") { GT.tracker.confirmed.grid[fourGrid + details.band + details.mode] = true; GT.tracker.confirmed.grid[fourGrid] = true; GT.tracker.confirmed.grid[fourGrid + details.mode] = true; GT.tracker.confirmed.grid[fourGrid + details.band] = true; if (isDigi == true) { GT.tracker.confirmed.grid[fourGrid + "dg"] = true; GT.tracker.confirmed.grid[fourGrid + details.band + "dg"] = true; } } if (details.ituz && details.ituz.length > 0) { GT.tracker.confirmed.ituz[details.ituz + "|" + details.band + details.mode] = true; GT.tracker.confirmed.ituz[details.ituz + "|"] = true; GT.tracker.confirmed.ituz[details.ituz + "|" + details.mode] = true; GT.tracker.confirmed.ituz[details.ituz + "|" + details.band] = true; if (isDigi == true) { GT.tracker.confirmed.ituz[details.ituz + "|dg"] = true; GT.tracker.confirmed.ituz[details.ituz + "|" + details.band + "dg"] = true; } } if (details.cqz && details.cqz.length > 0) { GT.tracker.confirmed.cqz[details.cqz + "|" + details.band + details.mode] = true; GT.tracker.confirmed.cqz[details.cqz + "|"] = true; GT.tracker.confirmed.cqz[details.cqz + "|" + details.mode] = true; GT.tracker.confirmed.cqz[details.cqz + "|" + details.band] = true; if (isDigi == true) { GT.tracker.confirmed.cqz[details.cqz + "|dg"] = true; GT.tracker.confirmed.cqz[details.cqz + "|" + details.band + "dg"] = true; } } if (details.dxcc > 0) { var sDXCC = String(details.dxcc); GT.tracker.confirmed.dxcc[sDXCC + "|" + details.band + details.mode] = true; GT.tracker.confirmed.dxcc[sDXCC + "|"] = true; GT.tracker.confirmed.dxcc[sDXCC + "|" + details.mode] = true; GT.tracker.confirmed.dxcc[sDXCC + "|" + details.band] = true; if (isDigi == true) { GT.tracker.confirmed.dxcc[sDXCC + "|dg"] = true; GT.tracker.confirmed.dxcc[sDXCC + "|" + details.band + "dg"] = true; } } if (details.state) { GT.tracker.confirmed.state[details.state] = true; GT.tracker.confirmed.state[details.state + details.mode] = true; GT.tracker.confirmed.state[details.state + details.band] = true; GT.tracker.confirmed.state[details.state + details.band + details.mode] = true; if (isDigi) { GT.tracker.confirmed.state[details.state + "dg"] = true; GT.tracker.confirmed.state[details.state + details.band + "dg"] = true; } } if (details.cnty) { GT.tracker.confirmed.cnty[details.cnty] = true; GT.tracker.confirmed.cnty[details.cnty + details.mode] = true; GT.tracker.confirmed.cnty[details.cnty + details.band] = true; GT.tracker.confirmed.cnty[details.cnty + details.band + details.mode] = true; if (isDigi) { GT.tracker.confirmed.cnty[details.cnty + "dg"] = true; GT.tracker.confirmed.cnty[details.cnty + details.band + "dg"] = true; } } if (details.px) { GT.tracker.confirmed.px[details.px + details.band + details.mode] = true; // store the last one GT.tracker.confirmed.px[details.px] = hash; GT.tracker.confirmed.px[details.px + details.mode] = true; GT.tracker.confirmed.px[details.px + details.band] = true; if (isDigi == true) { GT.tracker.confirmed.px[details.px + "dg"] = true; GT.tracker.confirmed.px[details.px + details.band + "dg"] = true; } if (isPhone == true) { GT.tracker.confirmed.px[details.px + "ph"] = true; GT.tracker.confirmed.px[details.px + details.band + "ph"] = true; } } if (details.cont) { GT.tracker.confirmed.cont[details.cont + details.band + details.mode] = true; // store the last one GT.tracker.confirmed.cont[details.cont] = hash; GT.tracker.confirmed.cont[details.cont + details.mode] = true; GT.tracker.confirmed.cont[details.cont + details.band] = true; if (isDigi == true) { GT.tracker.confirmed.cont[details.cont + "dg"] = true; GT.tracker.confirmed.cont[details.cont + details.band + "dg"] = true; } } } } updateRosterWorked(); goProcessRoster(); redrawGrids(); } function isKnownCallsignDXCC(dxcc) { if (dxcc in GT.callsignDatabaseDXCC) return true; return false; } function isKnownCallsignUS(dxcc) { if (dxcc in GT.callsignDatabaseUS) return true; return false; } function isKnownCallsignUSplus(dxcc) { if (dxcc in GT.callsignDatabaseUSplus) return true; return false; } function addQSO( finalGrid, finalDXcall, finalDEcall, finalRSTsent, finalTime, ifinalMsg, mode, band, confirmed, finalRSTrecv, finalDxcc, finalState, finalCont, finalCnty, finalCqZone, finalItuZone, finalVucc = [], finalPropMode = "", finalDigital = false, finalPhone = false, finalIOTA = "", finalSatName = "", finalPOTA = null ) { let hash = ""; let finalMsg = ifinalMsg.trim(); if (finalMsg.length > 40) finalMsg = finalMsg.substring(0, 40) + "..."; let details = null; let timeMod = finalTime - (finalTime % 360) + 180; hash = unique(mode + band + finalDXcall + timeMod); let lookupCall = false; if (hash in GT.QSOhash) { details = GT.QSOhash[hash]; if (finalGrid.length > 0 && finalGrid != details.grid) { // only touch the grid if it's larger than the last grid && the 4wide is the same if (details.grid.length < 6 && (details.grid.substr(0, 4) == finalGrid.substr(0, 4) || details.grid.length == 0)) { details.grid = finalGrid; } else if (details.grid.length != 0 && confirmed == true) { details.grid = finalGrid; } } if (finalRSTsent.length > 0) details.RSTsent = finalRSTsent; if (finalRSTrecv.length > 0) details.RSTrecv = finalRSTrecv; if (finalCqZone.length > 0) details.cqz = finalCqZone; if (finalItuZone.length > 0) details.ituz = finalItuZone; if (details.state != null && finalState != null && details.state != finalState && confirmed == true) { details.state = finalState; } else if (details.state == null && finalState != null) details.state = finalState; if (finalDxcc < 1 && details.dxcc > 0) finalDxcc = details.dxcc; if (finalCont == null && details.cont) finalCont = details.cont; if (details.cnty != null && finalCnty != null && details.cnty != finalCnty && confirmed == true) { details.qual = true; details.cnty = finalCnty; } else if (details.cnty == null && details.cnty != null) details.cnty = finalCnty; if (finalPropMode.length > 0) details.propMode = finalPropMode; if (finalVucc.length > 0) details.vucc_grids = finalVucc; if (finalIOTA.length > 0) details.IOTA = finalIOTA; if (finalSatName.length > 0) details.satName = finalSatName; if (finalPOTA) details.pota = finalPOTA; details.confirmed |= confirmed; } else { details = {}; details.grid = finalGrid; details.RSTsent = finalRSTsent; details.RSTrecv = finalRSTrecv; details.msg = "-"; details.band = band; details.mode = mode; details.DEcall = finalDXcall; details.DXcall = finalDEcall; details.cqz = finalCqZone; details.ituz = finalItuZone; details.delta = -1; details.time = finalTime; details.state = finalState; details.zipcode = null; details.qso = true; details.px = null; details.zone = null; details.cont = null; details.cnty = finalCnty; details.vucc_grids = finalVucc; details.propMode = finalPropMode; details.digital = finalDigital; details.phone = finalPhone; details.IOTA = finalIOTA; details.satName = finalSatName; details.pota = finalPOTA; details.worked = true; details.confirmed = confirmed; } if (finalDxcc < 1) finalDxcc = callsignToDxcc(finalDXcall); details.dxcc = finalDxcc; if (details.dxcc > 0 && details.px == null) { details.px = getWpx(finalDXcall); if (details.px) { details.zone = Number(details.px.charAt(details.px.length - 1)); } } var fourGrid = details.grid.substr(0, 4); details.cont = finalCont; if (finalDxcc > 0) { details.cont = GT.dxccInfo[finalDxcc].continent; if (details.dxcc == 390 && details.zone == 1) details.cont = "EU"; } if (details.cnty && confirmed == true) { details.qual = true; } if (isKnownCallsignUSplus(finalDxcc)) { if (details.state == null && fourGrid.length > 0) { if (fourGrid in GT.gridToState && GT.gridToState[fourGrid].length == 1) { details.state = GT.gridToState[fourGrid][0]; } if (details.state == null) { lookupCall = true; } } if (details.cnty == null) { lookupCall = true; } else { if (!(details.cnty in GT.cntyToCounty)) { lookupCall = true; } } } if (!details.cqz || details.cqz.length == 0) { details.cqz = cqZoneFromCallsign(finalDXcall, details.dxcc); } if (!details.ituz || details.ituz.length == 0) { details.ituz = ituZoneFromCallsign(finalDXcall, details.dxcc); } if (finalMsg.length > 0) details.msg = finalMsg; GT.QSOhash[hash] = details; if (lookupCall) { if (GT.callsignLookups.ulsUseEnable) { lookupUsCallsign(details, true); } } } function addLiveCallsign( finalGrid, finalDXcall, finalDEcall, finalRSTsent, finalTime, ifinalMsg, mode, band, confirmed, isQSO, finalRSTrecv, finalDxcc, finalState, finalCont, finalCnty, finalCqZone, finalItuZone, finalVucc = [], finalPropMode = "", finalDigital = false, finalPhone = false, finalIOTA = "", finalSatName = "", finalPOTA = null ) { var callsign = null; var rect = null; var wspr = mode == "WSPR" ? parseInt(band) * 2 : null; var hash = ""; var finalMsg = ifinalMsg.trim(); if (finalMsg.length > 40) finalMsg = finalMsg.substring(0, 40) + "..."; if (finalDxcc < 1) finalDxcc = callsignToDxcc(finalDXcall); hash = finalDXcall + band + mode; if (hash in GT.liveCallsigns) callsign = GT.liveCallsigns[hash]; if (finalDxcc in GT.dxccCount) GT.dxccCount[finalDxcc]++; else GT.dxccCount[finalDxcc] = 1; if (wspr != null && validateMapBandAndMode(band, mode)) { rect = qthToBox( finalGrid, finalDXcall, false, false, finalDEcall, band, wspr, hash ); } if (callsign == null) { var newCallsign = {}; newCallsign.DEcall = finalDXcall; newCallsign.grid = finalGrid; newCallsign.mode = mode; newCallsign.band = band; newCallsign.msg = finalMsg; newCallsign.dxcc = finalDxcc; newCallsign.worked = false; newCallsign.confirmed = false; newCallsign.RSTsent = "-"; newCallsign.RSTrecv = "-"; newCallsign.dt = 0.0; newCallsign.qso = false; newCallsign.distance = 0; newCallsign.px = null; newCallsign.zone = null; newCallsign.pota = null; newCallsign.cnty = finalCnty; newCallsign.cont = finalCont; if (finalDxcc > -1) { newCallsign.px = getWpx(finalDXcall); if (newCallsign.px) { newCallsign.zone = Number( newCallsign.px.charAt(newCallsign.px.length - 1) ); } if (newCallsign.cont == null) { newCallsign.cont = GT.dxccInfo[finalDxcc].continent; if (newCallsign.dxcc == 390 && newCallsign.zone == 1) { newCallsign.cont = "EU"; } } } if (finalRSTsent != null) { newCallsign.RSTsent = finalRSTsent; } if (finalRSTrecv != null) { newCallsign.RSTrecv = finalRSTrecv; } newCallsign.time = finalTime; newCallsign.age = finalTime; newCallsign.delta = -1; newCallsign.DXcall = finalDEcall; newCallsign.rect = rect; newCallsign.wspr = wspr; newCallsign.state = finalState; newCallsign.alerted = false; newCallsign.instance = null; newCallsign.shouldAlert = false; newCallsign.zipcode = null; newCallsign.qrz = false; newCallsign.vucc_grids = []; newCallsign.propMode = ""; newCallsign.digital = finalDigital; newCallsign.phone = finalPhone; newCallsign.IOTA = finalIOTA; newCallsign.satName = finalSatName; newCallsign.hash = hash; if (newCallsign.state == null && isKnownCallsignDXCC(finalDxcc) && finalGrid.length > 0) { if (GT.callsignLookups.ulsUseEnable) { lookupUsCallsign(newCallsign, false); } if (newCallsign.state == null && isKnownCallsignUSplus(finalDxcc)) { var fourGrid = finalGrid.substr(0, 4); if (fourGrid in GT.gridToState && GT.gridToState[finalGrid.substr(0, 4)].length == 1) { newCallsign.state = GT.gridToState[finalGrid.substr(0, 4)][0]; } } } GT.liveCallsigns[hash] = newCallsign; } else { if (callsign.DXcall != "Self" && finalTime > callsign.time) { callsign.time = finalTime; callsign.age = finalTime; callsign.mode = mode; callsign.band = band; callsign.delta = -1; callsign.DXcall = finalDEcall; callsign.msg = finalMsg; callsign.rect = rect; callsign.dxcc = finalDxcc; callsign.wspr = wspr; if (finalGrid.length > callsign.grid.length) callsign.grid = finalGrid; if (finalGrid.length == callsign.grid.length && finalGrid != callsign.grid) callsign.grid = finalGrid; if (finalRSTsent != null) callsign.RSTsent = finalRSTsent; if (finalRSTrecv != null) callsign.RSTrecv = finalRSTrecv; callsign.vucc_grids = []; callsign.propMode = ""; callsign.digital = finalDigital; callsign.phone = finalPhone; callsign.IOTA = finalIOTA; callsign.satName = finalSatName; } } } function timeoutSetUdpPort() { GT.appSettings.wsjtUdpPort = udpPortInput.value; lastMsgTimeDiv.innerHTML = $.i18n("gt.timeoutSetUdpPort"); GT.setNewUdpPortTimeoutHandle = null; } function setUdpPort() { if (GT.setNewUdpPortTimeoutHandle != null) { nodeTimers.clearTimeout(GT.setNewUdpPortTimeoutHandle); } lastMsgTimeDiv.innerHTML = $.i18n("gt.setUdpPort"); GT.setNewUdpPortTimeoutHandle = nodeTimers.setTimeout(timeoutSetUdpPort, 1000); } function changeGridDecay() { GT.appSettings.gridsquareDecayTime = parseInt(gridDecay.value); decayRateTd.innerHTML = Number(GT.appSettings.gridsquareDecayTime) == 0 ? "No Decay" : toDHMS(Number(GT.appSettings.gridsquareDecayTime)); } function changeMouseOverValue() { GT.mapSettings.mouseOver = mouseOverValue.checked; saveMapSettings(); } function changeMergeOverlayValue() { GT.mapSettings.mergeOverlay = mergeOverlayValue.checked; saveMapSettings(); setTrophyOverlay(GT.currentOverlay); } function getPathColor() { if (GT.mapSettings.nightMapEnable && GT.nightTime) { if (GT.mapSettings.nightPathColor == 0) return "#000"; if (GT.mapSettings.nightPathColor == 361) return "#FFF"; return "hsl(" + GT.mapSettings.nightPathColor + ", 100%, 50%)"; } else { if (GT.mapSettings.pathColor == 0) return "#000"; if (GT.mapSettings.pathColor == 361) return "#FFF"; return "hsl(" + GT.mapSettings.pathColor + ", 100%, 50%)"; } } function getQrzPathColor() { if (GT.mapSettings.nightMapEnable && GT.nightTime) { if (GT.mapSettings.nightQrzPathColor == 0) return "#000"; if (GT.mapSettings.nightQrzPathColor == 361) return "#FFF"; return "hsl(" + GT.mapSettings.nightQrzPathColor + ", 100%, 50%)"; } else { if (GT.mapSettings.qrzPathColor == 0) return "#000"; if (GT.mapSettings.qrzPathColor == 361) return "#FFF"; return "hsl(" + GT.mapSettings.qrzPathColor + ", 100%, 50%)"; } } function changeShadow() { GT.mapSettings.shadow = shadowValue.value; showDarknessTd.innerHTML = parseInt(shadowValue.value * 100) + "%"; saveMapSettings(); GT.nightTime = dayNight.refresh(); } function changePathWidth() { GT.appSettings.pathWidthWeight = pathWidthValue.value; GT.appSettings.qrzPathWidthWeight = qrzPathWidthValue.value; pathWidthTd.innerHTML = pathWidthValue.value; qrzPathWidthTd.innerHTML = qrzPathWidthValue.value; for (var i = GT.flightPaths.length - 1; i >= 0; i--) { var featureStyle = GT.flightPaths[i].getStyle(); var featureStroke = featureStyle.getStroke(); var color = GT.flightPaths[i].isQRZ ? getQrzPathColor() : getPathColor(); var width = GT.flightPaths[i].isQRZ ? qrzPathWidthValue.value : pathWidthValue.value; if (width == 0) { if ("Arrow" in GT.flightPaths[i]) { GT.layerSources.flight.removeFeature(GT.flightPaths[i].Arrow); } GT.layerSources.flight.removeFeature(GT.flightPaths[i]); delete GT.flightPaths[i]; GT.flightPaths[i] = null; GT.flightPaths.splice(i, 1); continue; } featureStroke.setWidth(width); if (GT.flightPaths[i].isShapeFlight == 0) featureStroke.setColor(color); featureStyle.setStroke(featureStroke); GT.flightPaths[i].setStyle(featureStyle); if ("Arrow" in GT.flightPaths[i]) { var stroke = new ol.style.Stroke({ color: color, width: width }); var thisStle = new ol.style.Style({ image: new ol.style.Circle({ stroke: stroke, radius: 3 }) }); GT.flightPaths[i].Arrow.setStyle(thisStle); } } if (GT.transmitFlightPath != null) { var featureStyle = GT.transmitFlightPath.getStyle(); var featureStroke = featureStyle.getStroke(); if (qrzPathWidthValue.value == 0) { GT.layerSources.transmit.clear(); GT.transmitFlightPath = null; } else { featureStroke.setWidth(qrzPathWidthValue.value); featureStroke.setColor(getQrzPathColor()); featureStyle.setStroke(featureStroke); GT.transmitFlightPath.setStyle(featureStyle); if ("Arrow" in GT.transmitFlightPath) { var stroke = new ol.style.Stroke({ color: getQrzPathColor(), width: qrzPathWidthValue.value }); var thisStle = new ol.style.Style({ image: new ol.style.Circle({ stroke: stroke, radius: 3 }) }); GT.transmitFlightPath.Arrow.setStyle(thisStle); } } } } function compareCallsignTime(a, b) { if (a.time < b.time) return -1; if (a.time > b.time) return 1; return 0; } function remove_duplicates(arr) { var obj = {}; var ret_arr = []; for (var i = 0; i < arr.length; i++) { obj[arr[i]] = true; } for (var key in obj) { ret_arr.push(key); } return ret_arr; } function splitNoParen(s) { var results = []; var next; var str = ""; var left = 0, right = 0; function keepResult() { results.push(str.trim()); str = ""; } for (var i = 0; i < s.length; i++) { switch (s[i]) { case ",": if (left == right) { keepResult(); left = right = 0; } else { str += s[i]; } break; case "(": left++; str += s[i]; break; case ")": right++; str += s[i]; break; default: str += s[i]; } } keepResult(); return results; } function createSpotTipTable(toolElement) { try { var now = timeNowSec(); var worker = ""; if (toolElement.spot in GT.receptionReports.spots) { GT.layerSources["psk-hop"].clear(); var report = GT.receptionReports.spots[toolElement.spot]; var LL = squareToCenter(GT.appSettings.myRawGrid); var fromPoint = ol.proj.fromLonLat([LL.o, LL.a]); worker = ""; worker += ""; worker += ""; worker += ""; if (report.dxcc > 0) { worker += ""; } worker += ""; worker += ""; worker += ""; LL = squareToCenter(report.grid); report.bearing = parseInt(MyCircle.bearing(GT.myLat, GT.myLon, LL.a, LL.o)); worker += ""; worker += ""; worker += ""; if ("source" in report) { let color = (report.source == "O" ? "cyan;font-size: larger" : "orange"); let fullSource = (report.source == "O" ? "OAMS Realtime Network" : "PSK-Reporter"); worker += ""; } worker += "
Rx Spot
Age" + toDHMS(Number(now - report.when)) + "
dB" + formatSignalReport(Number(report.snr)) + "
Call" + formatCallsign(report.call) + "
DXCC" + GT.dxccToAltName[report.dxcc] + " (" + GT.dxccInfo[report.dxcc].pp + ")
Grid" + report.grid + "
Freq" + formatMhz(report.freq) + " (" + report.band + ")
Mode" + report.mode + "
Dist" + parseInt(MyCircle.distance(GT.myLat, GT.myLon, LL.a, LL.o, distanceUnit.value) * MyCircle.validateRadius(distanceUnit.value)) + distanceUnit.value.toLowerCase() + "
Azim" + report.bearing + "°
Time" + userTimeString(report.when * 1000) + "
Source" + fullSource + "
"; var strokeWeight = pathWidthValue.value; var toPoint = ol.proj.fromLonLat([LL.o, LL.a]); flightFeature( [fromPoint, toPoint], { weight: strokeWeight, color: getQrzPathColor(), steps: 75 }, "psk-hop", false ); } myTooltip.innerHTML = worker; GT.passingToolTipTableString = worker; return 10; } catch (err) { console.error("Unexpected error at createSpotTipTable", toolElement, err) } } function createTooltTipTable(toolElement) { if (typeof toolElement.spot != "undefined") { return createSpotTipTable(toolElement); } var colspan = 10; if (GT.callsignLookups.lotwUseEnable == true) colspan++; if (GT.callsignLookups.eqslUseEnable == true) colspan++; if (GT.callsignLookups.oqrsUseEnable == true) colspan++; if (toolElement.qso == true) colspan += 2; var worker = ""; if (toolElement.qth in GT.gridToDXCC) { worker += ""; } var newCallList = Array(); if (toolElement.qso == true) { if (Object.keys(toolElement.hashes).length > 0) { worker += "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; if (GT.callsignLookups.lotwUseEnable == true) worker += ""; if (GT.callsignLookups.eqslUseEnable == true) worker += ""; if (GT.callsignLookups.oqrsUseEnable == true) worker += ""; worker += ""; } for (var KeyIsHash in toolElement.hashes) { if (KeyIsHash in GT.QSOhash) { newCallList.push(GT.QSOhash[KeyIsHash]); } } if ( toolElement.qth in GT.liveGrids && GT.liveGrids[toolElement.qth].rectangle != null && GT.liveGrids[toolElement.qth].isTriangle == false ) { for (var KeyIsCall in GT.liveGrids[toolElement.qth].rectangle.liveHash) { if (KeyIsCall in GT.liveCallsigns && GT.appSettings.gridViewMode == 3) { newCallList.push(GT.liveCallsigns[KeyIsCall]); } } } } else { if (toolElement.liveHash != null && Object.keys(toolElement.liveHash).length > 0) { worker += "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; if (GT.callsignLookups.lotwUseEnable == true) worker += ""; if (GT.callsignLookups.eqslUseEnable == true) worker += ""; if (GT.callsignLookups.oqrsUseEnable == true) worker += ""; worker += ""; } for (var KeyIsCall in toolElement.liveHash) { if (KeyIsCall in GT.liveCallsigns) { newCallList.push(GT.liveCallsigns[KeyIsCall]); } } } newCallList.sort(compareCallsignTime).reverse(); for (var x = 0; x < newCallList.length; x++) { var callsign = newCallList[x]; var bgDX = " style='font-weight:bold;color:cyan;' "; var bgDE = " style='font-weight:bold;color:yellow;' "; if (callsign.DXcall == GT.appSettings.myCall) { bgDX = " style='background-color:cyan;color:#000;font-weight:bold' "; } if (callsign.DEcall == GT.appSettings.myCall) { bgDE = " style='background-color:#FFFF00;color:#000;font-weight:bold' "; } if (typeof callsign.msg == "undefined" || callsign.msg == "") { callsign.msg = "-"; } var ageString = ""; if (timeNowSec() - callsign.time < 3601) { ageString = toDHMS(timeNowSec() - callsign.time); } else { ageString = userTimeString(callsign.time * 1000); } worker += ""; worker += "
" + formatCallsign(callsign.DEcall) + "
"; worker += ""; worker += "
"; worker += ""; worker += "" + ""; if (callsign.DXcall.indexOf("CQ") == 0 || callsign.DXcall == "-") { worker += formatCallsign(callsign.DXcall); } else { worker += "
" + formatCallsign(callsign.DXcall) + "
"; } worker += "" + "
" + ""; if (toolElement.qso == true) { worker += ""; } worker += "" + ""; if (GT.callsignLookups.lotwUseEnable == true) { worker += ""; } if (GT.callsignLookups.eqslUseEnable == true) { worker += ""; } if (GT.callsignLookups.oqrsUseEnable == true) { worker += ""; } worker += ""; } worker += "
" + toolElement.qth + " (" + $.i18n((toolElement.qso ? "gt.gridView.logbook" : "gt.gridView.live")) + ")
"; for (var x = 0; x < GT.gridToDXCC[toolElement.qth].length; x++) { worker += GT.dxccToAltName[GT.gridToDXCC[toolElement.qth][x]]; if (toolElement.qth in GT.gridToState) { worker += " ("; var added = false; for (var y = 0; y < GT.gridToState[toolElement.qth].length; y++) { if ( GT.gridToDXCC[toolElement.qth][x] == GT.StateData[GT.gridToState[toolElement.qth][y]].dxcc ) { worker += GT.StateData[GT.gridToState[toolElement.qth][y]].name + " / "; added = true; } } if (added == true) { worker = worker.substr(0, worker.length - " / ".length); } worker += ")"; } if (x + 1 < GT.gridToDXCC[toolElement.qth].length) worker += ", "; } worker += "
" + $.i18n("gt.newCallList.Call") + "" + $.i18n("gt.newCallList.Freq") + "" + $.i18n("gt.newCallList.Sent") + "" + $.i18n("gt.newCallList.Rcvd") + "" + $.i18n("gt.newCallList.Station") + "" + $.i18n("gt.newCallList.Mode") + "" + $.i18n("gt.newCallList.Band") + "" + $.i18n("gt.newCallList.QSL") + "" + $.i18n("gt.newCallList.LastMsg") + "" + $.i18n("gt.newCallList.DXCC") + "" + $.i18n("gt.newCallList.Time") + "" + $.i18n("gt.qsoPage.LoTW") + "" + $.i18n("gt.qsoPage.eQSL") + "" + $.i18n("gt.qsoPage.OQRS") + "
" + $.i18n("gt.newCallList.Call") + "" + $.i18n("gt.newCallList.Freq") + "" + $.i18n("gt.newCallList.Sent") + "" + $.i18n("gt.newCallList.Rcvd") + "" + $.i18n("gt.newCallList.Station") + "" + $.i18n("gt.newCallList.Mode") + "" + $.i18n("gt.newCallList.Band") + "" + $.i18n("gt.newCallList.LastMsg") + "" + $.i18n("gt.newCallList.DXCC") + "" + $.i18n("gt.newCallList.Time") + "" + $.i18n("gt.newCallList.LoTW") + "" + $.i18n("gt.newCallList.eQSL") + "" + $.i18n("gt.newCallList.OQRS") + "
" + (callsign.delta > -1 ? callsign.delta : "-") + "" + callsign.RSTsent + "" + callsign.RSTrecv + "" + callsign.mode + "" + callsign.band + "" + (callsign.confirmed ? "✔" : "") + "" + callsign.msg + "" + GT.dxccToAltName[callsign.dxcc] + " (" + GT.dxccInfo[callsign.dxcc].pp + ")" + ageString + "" + (callsign.DEcall in GT.lotwCallsigns ? "✋" : "") + "" + (callsign.DEcall in GT.eqslCallsigns ? "✋" : "") + "" + (callsign.DEcall in GT.oqrsCallsigns ? "✋" : "") + "
"; myTooltip.innerHTML = worker; GT.passingToolTipTableString = worker; return newCallList.length; } // creates table for filling the pop-up window with log entries of unconfirmed qsos. function createTooltTipTableLogbook(toolElement) { var colspan = 10; if (toolElement.qso == true) { colspan += 2; } if (GT.callsignLookups.lotwUseEnable == true) colspan++; if (GT.callsignLookups.eqslUseEnable == true) colspan++; if (GT.callsignLookups.oqrsUseEnable == true) colspan++; var worker = ""; worker += "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; if (GT.callsignLookups.lotwUseEnable == true) worker += ""; if (GT.callsignLookups.eqslUseEnable == true) worker += ""; if (GT.callsignLookups.oqrsUseEnable == true) worker += ""; worker += ""; var newCallList = Array(); toolElement.forEach(function (value, key, set) { newCallList.push(value); }); newCallList.sort(compareCallsignTime).reverse(); for (var x = 0; x < newCallList.length; x++) { var callsign = newCallList[x]; var bgDX = " style='font-weight:bold;color:cyan;' "; var bgDE = " style='font-weight:bold;color:yellow;' "; if (callsign.DXcall == GT.appSettings.myCall) { bgDX = " style='background-color:cyan;color:#000;font-weight:bold' "; } if (callsign.DEcall == GT.appSettings.myCall) { bgDE = " style='background-color:#FFFF00;color:#000;font-weight:bold' "; } var ageString = ""; if (timeNowSec() - callsign.time < 3601) { ageString = toDHMS(timeNowSec() - callsign.time); } else { ageString = userTimeString(callsign.time * 1000); } worker += ""; worker += "
" + formatCallsign(callsign.DEcall) + "
"; worker += ""; worker += "
"; worker += ""; worker += "" + ""; if (callsign.DXcall.indexOf("CQ") == 0 || callsign.DXcall == "-") { worker += formatCallsign(callsign.DXcall); } else { worker += "
" + formatCallsign(callsign.DXcall) + "
"; } worker += "" + "
" + ""; worker += "" + ""; if (GT.callsignLookups.lotwUseEnable == true) { worker += ""; } if (GT.callsignLookups.eqslUseEnable == true) { worker += ""; } if (GT.callsignLookups.oqrsUseEnable == true) { if (callsign.DEcall in GT.oqrsCallsigns) { worker += ""; } else { worker += ""; } } worker += ""; } worker += "
" + "Logbook entries" + "
" + $.i18n("gt.newCallList.Call") + "" + $.i18n("gt.newCallList.Freq") + "" + $.i18n("gt.newCallList.Sent") + "" + $.i18n("gt.newCallList.Rcvd") + "" + $.i18n("gt.newCallList.Station") + "" + $.i18n("gt.newCallList.Mode") + "" + $.i18n("gt.newCallList.Band") + "" + $.i18n("gt.newCallList.DXCC") + "" + $.i18n("gt.newCallList.Time") + "" + $.i18n("gt.newCallList.LoTW") + "" + $.i18n("gt.newCallList.eQSL") + "" + $.i18n("gt.newCallList.OQRS") + "
" + (callsign.delta > -1 ? callsign.delta : "-") + "" + callsign.RSTsent + "" + callsign.RSTrecv + "" + callsign.mode + "" + callsign.band + "" + GT.dxccToAltName[callsign.dxcc] + " (" + GT.dxccInfo[callsign.dxcc].pp + ")" + ageString + "" + (callsign.DEcall in GT.lotwCallsigns ? "✋" : "") + "" + (callsign.DEcall in GT.eqslCallsigns ? "✋" : "") + "" + "✋ 📬
"; myTooltip.innerHTML = worker; GT.passingToolTipTableString = worker; return newCallList.length; } function renderTooltipWindow(feature) { if (GT.popupWindowHandle != null) { try { createTooltTipTable(feature); var adif = GT.popupWindowHandle.window.document.getElementById( "adifTable" ); adif.innerHTML = GT.passingToolTipTableString; var positionInfo = myTooltip.getBoundingClientRect(); GT.popupWindowHandle.show(); GT.popupWindowHandle.focus(); GT.popupWindowHandle.width = parseInt(positionInfo.width) + 20; GT.popupWindowHandle.height = parseInt(positionInfo.height) + 50; } catch (e) { console.error(e); } } } // renders the pop-window for logbook entries of unconfirmed qsos. function renderTooltipWindowLogbook(logbookEntries) { if (GT.popupWindowHandle != null) { try { createTooltTipTableLogbook(logbookEntries); var adif = GT.popupWindowHandle.window.document.getElementById( "adifTable" ); adif.innerHTML = GT.passingToolTipTableString; var positionInfo = myTooltip.getBoundingClientRect(); GT.popupWindowHandle.show(); GT.popupWindowHandle.focus(); GT.popupWindowHandle.width = parseInt(positionInfo.width) + 20; GT.popupWindowHandle.height = parseInt(positionInfo.height) + 50; } catch (e) { console.error(e); } } } function leftClickGtFlag(feature) { var e = window.event; if ((e.which && e.which == 1) || (e.button && e.button == 1)) { startLookup(GT.gtFlagPins[feature.key].call, GT.gtFlagPins[feature.key].grid); } return false; } function openConditionsWindow() { if (GT.conditionsWindowHandle == null) { popupNewWindows(); var gui = require("nw.gui"); gui.Window.open( "gt_conditions.html", { show: false, id: "GT-Conditions" }, function (new_win) { GT.conditionsWindowHandle = new_win; new_win.on("loaded", function () { GT.conditionsWindowHandle.setMinimumSize(490, 280); if (GT.firstRun) { GT.conditionsWindowHandle.resizeTo(490, 280); GT.conditionsWindowHandle.moveTo(100, 100); } }); new_win.on("close", function () { GT.conditionsWindowHandle.window.isShowing = false; GT.conditionsWindowHandle.window.saveScreenSettings(); GT.conditionsWindowHandle.hide(); }); } ); lockNewWindows(); } else { try { if (GT.conditionsWindowHandle.window.isShowing == false) { GT.conditionsWindowHandle.window.isShowing = true; GT.conditionsWindowHandle.window.saveScreenSettings(); GT.conditionsWindowHandle.show(); GT.conditionsWindowHandle.focus(); } else { GT.conditionsWindowHandle.window.isShowing = false; GT.conditionsWindowHandle.window.saveScreenSettings(); GT.conditionsWindowHandle.hide(); } } catch (e) { console.error(e); } } } GT.rosterInitialized = false; GT.callRoster = {}; GT.rosterUpdateTimer = null; function insertMessageInRoster(newMessage, msgDEcallsign, msgDXcallsign, callObj, hash) { if (GT.rosterUpdateTimer != null) { nodeTimers.clearTimeout(GT.rosterUpdateTimer); GT.rosterUpdateTimer = null; } var now = timeNowSec(); if (!(hash in GT.callRoster)) { GT.callRoster[hash] = {}; callObj.life = now; callObj.reset = false; } if (callObj.reset) { callObj.life = now; callObj.reset = false; } if (typeof callObj.life == "undefined") { callObj.life = now; callObj.reset = false; } GT.callRoster[hash].message = newMessage; GT.callRoster[hash].callObj = callObj; GT.callRoster[hash].DXcall = msgDXcallsign; GT.callRoster[hash].DEcall = msgDEcallsign; GT.rosterUpdateTimer = nodeTimers.setTimeout(delayedRosterUpdate, 150); } function delayedRosterUpdate() { GT.rosterUpdateTimer = null; goProcessRoster(); } function openCallRosterWindow(show = true) { if (GT.callRosterWindowHandle == null) { popupNewWindows(); var gui = require("nw.gui"); gui.Window.open( "gt_roster.html", { show: false, id: "GT-roster", icon: "img/roster-icon.png" }, function (new_win) { GT.callRosterWindowHandle = new_win; new_win.on("loaded", function () { GT.callRosterWindowHandle.setMinimumSize(390, 250); GT.callRosterWindowHandle.setResizable(true); if (GT.firstRun) { GT.callRosterWindowHandle.resizeTo(1000, 500); GT.callRosterWindowHandle.moveTo(15, 15); } }); new_win.on("close", function () { GT.callRosterWindowHandle.window.isShowing = false; GT.callRosterWindowHandle.window.saveScreenSettings(); GT.callRosterWindowHandle.hide(); }); } ); lockNewWindows(); } else { try { if (GT.rosterInitialized) { if (GT.callRosterWindowHandle.window.isShowing == false) { GT.callRosterWindowHandle.show(); GT.callRosterWindowHandle.window.isShowing = true; GT.callRosterWindowHandle.window.saveScreenSettings(); GT.callRosterWindowHandle.focus(); goProcessRoster(); } else { GT.callRosterWindowHandle.window.isShowing = false; GT.callRosterWindowHandle.window.saveScreenSettings(); GT.callRosterWindowHandle.hide(); } } } catch (e) { console.error(e); } } } function updateRosterWorked() { if (GT.rosterInitialized) { try { GT.callRosterWindowHandle.window.updateWorked(); } catch (e) { console.error(e); } } } function updateRosterInstances() { if (GT.rosterInitialized) { try { GT.callRosterWindowHandle.window.updateInstances(); } catch (e) { console.error(e); } } } // Called from GridTracher.html function changeLogbookPage() { qsoItemsPerPageTd.innerHTML = GT.appSettings.qsoItemsPerPage = parseInt(qsoItemsPerPageValue.value); } function updateLogbook() { showWorkedBox(0, 0, true); } function openStatsWindow(show = true) { if (GT.statsWindowHandle == null) { popupNewWindows(); var gui = require("nw.gui"); gui.Window.open( "gt_stats.html", { show: false, id: "GT-stats" }, function (new_win) { GT.statsWindowHandle = new_win; new_win.on("loaded", function () { GT.statsWindowHandle.setMinimumSize(620, 200); GT.statsWindowHandle.setResizable(true); if (GT.firstRun) { GT.statsWindowHandle.resizeTo(640, 480); GT.statsWindowHandle.moveTo(50, 50); } }); new_win.on("close", function () { GT.statsWindowHandle.window.isShowing = false; GT.statsWindowHandle.window.saveScreenSettings(); GT.statsWindowHandle.hide(); }); } ); lockNewWindows(); } else { try { if (GT.statsWindowHandle.window.isShowing == false) { GT.statsWindowHandle.show(); GT.statsWindowHandle.window.isShowing = true; GT.statsWindowHandle.window.saveScreenSettings(); GT.statsWindowHandle.focus(); } else { GT.statsWindowHandle.window.isShowing = false; GT.statsWindowHandle.window.saveScreenSettings(); GT.statsWindowHandle.hide(); } } catch (e) { console.error(e); } } } function showMessaging(show = true, cid) { if (GT.chatWindowHandle == null) { popupNewWindows(); var gui = require("nw.gui"); gui.Window.open( "gt_chat.html", { show: false, id: "GT-chat" }, function (new_win) { GT.chatWindowHandle = new_win; GT.chatWindowHandle.on("loaded", function () { GT.chatWindowHandle.setMinimumSize(450, 140); GT.chatWindowHandle.setResizable(true); if (GT.firstRun) { GT.chatWindowHandle.resizeTo(640, 300); GT.chatWindowHandle.moveTo(50, 50); } }); GT.chatWindowHandle.on("close", function () { GT.chatWindowHandle.window.closeMessageArea(); GT.chatWindowHandle.window.isShowing = false; GT.chatWindowHandle.window.saveScreenSettings(); GT.chatWindowHandle.hide(); }); } ); lockNewWindows(); } else { try { GT.chatWindowHandle.window.isShowing = true; GT.chatWindowHandle.window.saveScreenSettings(); GT.chatWindowHandle.show(); GT.chatWindowHandle.focus(); if (typeof cid != "undefined") GT.chatWindowHandle.window.openId(cid); } catch (e) { console.error(e); } } } function onRightClickGridSquare(feature) { var e = window.event; if ( (e.which && e.button == 2 && event.shiftKey) || (e.button && e.button == 2 && event.shiftKey) ) { createTooltTipTable(feature); selectElementContents(myTooltip); } else if (e.button == 0 && GT.mapSettings.mouseOver == false) { mouseOverDataItem(feature, false); } else if ((e.which && e.which == 3) || (e.button && e.button == 2)) { if (GT.popupWindowHandle == null) { popupNewWindows(); var gui = require("nw.gui"); gui.Window.open( "gt_popup.html", { show: false, id: "GT-popup" }, function (new_win) { GT.popupWindowHandle = new_win; new_win.on("loaded", function () { GT.popupWindowHandle.show(); GT.popupWindowHandle.focus(); renderTooltipWindow(feature); }); new_win.on("close", function () { GT.popupWindowHandle.hide(); }); } ); lockNewWindows(); } else { try { renderTooltipWindow(feature); } catch (e) { console.error(e); } } mouseOutOfDataItem(); } else if ((e.which && e.which == 1) || (e.button && e.button == 0)) { if ("spot" in feature) { spotLookupAndSetCall(feature.spot); } } return false; } function onMouseUpdate(e) { GT.mouseX = e.pageX; GT.mouseY = e.pageY; mouseMoveGrid(); } function getMouseX() { return GT.mouseX; } function getMouseY() { return GT.mouseY; } GT.tempGridBox = null; function tempGridToBox(iQTH, oldGrid, borderColor, boxColor, layer) { var borderWeight = 2; var newGridBox = null; var LL = squareToLatLong(iQTH.substr(0, 4)); if (oldGrid) { if (GT.layerSources.temp.hasFeature(oldGrid)) { GT.layerSources.temp.removeFeature(oldGrid); } } var bounds = [ [LL.lo1, LL.la1], [LL.lo2, LL.la2] ]; newGridBox = rectangle(bounds); newGridBox.setId(iQTH); const featureStyle = new ol.style.Style({ fill: new ol.style.Fill({ color: boxColor }), stroke: new ol.style.Stroke({ color: borderColor, width: borderWeight, lineJoin: "round" }), zIndex: 60 }); newGridBox.setStyle(featureStyle); newGridBox.grid = iQTH; newGridBox.size = 0; GT.layerSources.temp.addFeature(newGridBox); return newGridBox; } GT.tempGrids = Array(); function onMyKeyDown(event) { if (event.keyCode == 27) { rootSettingsDiv.style.display = "none"; helpDiv.style.display = "none"; GT.helpShow = false; } if (rootSettingsDiv.style.display == "none") { if (event.code in GT.hotKeys) { if (typeof GT.hotKeys[event.code].param1 != "undefined") { var param2 = null; if (typeof GT.hotKeys[event.code].param2 != "undefined") { if (typeof event[GT.hotKeys[event.code].param2] != "undefined") { param2 = event[GT.hotKeys[event.code].param2]; } } GT.hotKeys[event.code].func(GT.hotKeys[event.code].param1, param2); } else { if (event.ctrlKey == false) GT.hotKeys[event.code].func(); } } else if (event.key in GT.hotKeys) { if (typeof GT.hotKeys[event.key].param1 != "undefined") { var param2 = null; if (typeof GT.hotKeys[event.key].param2 != "undefined") { if (typeof event[GT.hotKeys[event.key].param2] != "undefined") { param2 = event[GT.hotKeys[event.key].param2]; } } GT.hotKeys[event.key].func(GT.hotKeys[event.key].param1, param2); } else { if (event.ctrlKey == false) GT.hotKeys[event.key].func(); } } } } function clearTempGrids() { GT.layerSources.temp.clear(); GT.tempGrids = Array(); } GT.currentShapes = {}; function clearCurrentShapes() { GT.layerSources.award.clear(); GT.currentShapes = {}; } function mapMemory(x, save, exit = false) { if (save == true) { GT.mapMemory[x].LoLa = GT.mapView.getCenter(); GT.mapMemory[x].zoom = GT.mapView.getZoom(); localStorage.mapMemory = JSON.stringify(GT.mapMemory); if (exit == false) { playAlertMediaFile("Clicky-3.mp3"); } } else { if (GT.mapMemory[x].zoom != -1) { GT.mapView.setCenter(GT.mapMemory[x].LoLa); GT.mapView.setZoom(GT.mapMemory[x].zoom); } } } GT.hotKeys = {}; function registerHotKey(key, func, param1, param2) { GT.hotKeys[key] = {}; GT.hotKeys[key].func = func; GT.hotKeys[key].param1 = param1; GT.hotKeys[key].param2 = param2; } function registerHotKeys() { registerHotKey("1", setTrophyOverlay, 0); registerHotKey("2", setTrophyOverlay, 1); registerHotKey("3", setTrophyOverlay, 2); registerHotKey("4", setTrophyOverlay, 3); registerHotKey("5", setTrophyOverlay, 4); registerHotKey("6", setTrophyOverlay, 5); registerHotKey("7", setTrophyOverlay, 6); registerHotKey("8", setTrophyOverlay, 7); registerHotKey("9", toggleTimezones); registerHotKey("0", toggleNexrad); registerHotKey("KeyA", toggleAnimate); registerHotKey("KeyB", toggleAllGrids); registerHotKey("KeyC", showConditionsBox); registerHotKey("KeyD", toggleMoon); registerHotKey("KeyE", toggleMoonTrack); registerHotKey("KeyF", toggleSpotPaths); registerHotKey("KeyG", toggleGtMap); registerHotKey("KeyI", showRootInfoBox); registerHotKey("KeyK", makeScreenshots); registerHotKey("KeyL", adifLoadDialog); registerHotKey("KeyM", toggleAlertMute); registerHotKey("KeyN", toggleEarth); registerHotKey("KeyO", cycleSpotsView); registerHotKey("KeyP", togglePushPinMode); registerHotKey("KeyQ", cycleGridView); registerHotKey("KeyR", openCallRosterWindow); registerHotKey("KeyS", showSettingsBox); registerHotKey("KeyT", toggleSpotOverGrids); registerHotKey("KeyU", toggleMergeOverlay); registerHotKey("KeyW", toggleGridMode); registerHotKey("KeyX", toggleMouseTrack); registerHotKey("KeyZ", setCenterQTH); registerHotKey("Minus", toggleCRScript); registerHotKey("F5", mapMemory, 0, "shiftKey"); registerHotKey("F6", mapMemory, 1, "shiftKey"); registerHotKey("F7", mapMemory, 2, "shiftKey"); registerHotKey("F8", mapMemory, 3, "shiftKey"); registerHotKey("F9", mapMemory, 4, "shiftKey"); registerHotKey("F10", mapMemory, 5, "shiftKey"); registerHotKey("F11", toggleFullscreen); registerHotKey("F12", toggleMenu); registerHotKey("F1", toggleHelp); registerHotKey("?", toggleHelp); registerHotKey("Equal", cycleTrophyOverlay); } function toggleMoon() { GT.appSettings.moonTrack ^= 1; if (GT.appSettings.moonTrack == 1) { moonLayer.show(); } else { moonLayer.hide(); } } function toggleMoonTrack() { GT.appSettings.moonPath ^= 1; moonLayer.refresh(); } function toggleFullscreen() { if (document.fullscreenElement == null) { mainBody.requestFullscreen(); } else { document.exitFullscreen(); } } function toggleMenu() { if (GT.menuShowing == false) collapseMenu(false); else collapseMenu(true); } GT.helpShow = false; function toggleHelp() { GT.helpShow = !GT.helpShow; if (GT.helpShow == true) { helpDiv.style.display = "block"; } else helpDiv.style.display = "none"; } function onMyKeyUp(event) { } GT.currentOverlay = 0; function cycleTrophyOverlay() { GT.currentOverlay++; GT.currentOverlay %= 8; setTrophyOverlay(GT.currentOverlay); } function didWork(testObj) { return testObj.worked; } function didConfirm(testObj) { return testObj.confirmed; } function makeTitleInfo(mapWindow) { var band = GT.appSettings.gtBandFilter.length == 0 ? "Mixed" : GT.appSettings.gtBandFilter == "auto" ? GT.appSettings.myBand : GT.appSettings.gtBandFilter; var mode = GT.appSettings.gtModeFilter.length == 0 ? "Mixed" : GT.appSettings.gtModeFilter == "auto" ? GT.appSettings.myMode : GT.appSettings.gtModeFilter; var news = `GridTracker ${gtVersionStr} [Band: ${band} Mode: ${mode}`; var end = "]"; if (mapWindow) { news += ` Layer: ${GT.viewInfo[GT.currentOverlay][1]}`; } if (GT.currentOverlay == 0 && GT.appSettings.gridViewMode == 1) { return news + end; } var workline = ` - Worked ${GT.viewInfo[GT.currentOverlay][2]} Confirmed ${GT.viewInfo[GT.currentOverlay][3]}` if ( GT.viewInfo[GT.currentOverlay][2] <= GT.viewInfo[GT.currentOverlay][4] && GT.viewInfo[GT.currentOverlay][4] > 0 ) { end = ` Needed ${(GT.viewInfo[GT.currentOverlay][4] - GT.viewInfo[GT.currentOverlay][2])}]`; } return news + workline + end; } function setTrophyOverlay(which) { GT.currentOverlay = which; window.document.title = makeTitleInfo(true); trophyImg.src = GT.trophyImageArray[which]; myTrophyTooltip.style.zIndex = -1; clearCurrentShapes(); // set the scope of key var key = 0; if (which == 0) { for (key in GT.layerVectors) { GT.layerVectors[key].setVisible(true); } if ( GT.appSettings.gtFlagImgSrc > 0 && GT.appSettings.gtShareEnable == true && GT.mapSettings.offlineMode == false ) { GT.layerVectors.gtflags.setVisible(true); } else { GT.layerVectors.gtflags.setVisible(false); } GT.layerVectors.award.setVisible(false); if (GT.showAllGrids == false) { GT.layerVectors["line-grids"].setVisible(false); GT.layerVectors["big-grids"].setVisible(false); GT.layerVectors["long-grids"].setVisible(false); } if (GT.timezoneLayer) { if (GT.timezonesEnable == 1) { GT.timezoneLayer.setVisible(true); } else { GT.timezoneLayer.setVisible(false); } } } else { if (GT.mapSettings.mergeOverlay == false) { for (key in GT.layerVectors) { GT.layerVectors[key].setVisible(false); } } else { for (key in GT.layerVectors) { GT.layerVectors[key].setVisible(true); } if ( GT.appSettings.gtFlagImgSrc > 0 && GT.appSettings.gtShareEnable == true && GT.mapSettings.offlineMode == false ) { GT.layerVectors.gtflags.setVisible(true); } else { GT.layerVectors.gtflags.setVisible(false); } if (GT.showAllGrids == false) { GT.layerVectors["line-grids"].setVisible(false); GT.layerVectors["big-grids"].setVisible(false); GT.layerVectors["long-grids"].setVisible(false); } } GT.layerVectors.award.setVisible(true); if (GT.timezoneLayer) { GT.timezoneLayer.setVisible(false); } mapLoseFocus(); } if (which == 1) { for (key in GT.cqZones) { var boxColor = "#FF000015"; var borderColor = "#005500FF"; var borderWeight = 1; if (didConfirm(GT.cqZones[key])) { boxColor = "#00FF0066"; } else if (didWork(GT.cqZones[key])) { boxColor = "#FFFF0066"; } GT.currentShapes[key] = shapeFeature( key, GT.cqZones[key].geo, "cqzone", boxColor, borderColor, borderWeight ); GT.layerSources.award.addFeature(GT.currentShapes[key]); } } if (which == 2) { for (key in GT.ituZones) { var boxColor = "#FF000015"; var borderColor = "#800080FF"; var borderWeight = 1; if (didConfirm(GT.ituZones[key])) { boxColor = "#00FF0066"; borderWeight = 1; } else if (didWork(GT.ituZones[key])) { boxColor = "#FFFF0066"; borderWeight = 1; } GT.currentShapes[key] = shapeFeature( key, GT.ituZones[key].geo, "ituzone", boxColor, borderColor, borderWeight ); GT.layerSources.award.addFeature(GT.currentShapes[key]); } } if (which == 3) { for (key in GT.wacZones) { var boxColor = "#FF000015"; var borderColor = "#006666FF"; var borderWeight = 1; var originalKey = key; if (didConfirm(GT.wacZones[key])) { boxColor = "#00FF0066"; } else if (didWork(GT.wacZones[key])) { boxColor = "#FFFF0066"; } GT.currentShapes[originalKey] = shapeFeature( originalKey, GT.wacZones[originalKey].geo, "wac", boxColor, borderColor, borderWeight ); GT.layerSources.award.addFeature(GT.currentShapes[originalKey]); } } if (which == 4) { for (key in GT.wasZones) { var boxColor = "#FF000020"; var borderColor = "#0000FFFF"; var borderWeight = 1; if (didConfirm(GT.wasZones[key])) { boxColor = "#00FF0066"; } else if (didWork(GT.wasZones[key])) { boxColor = "#FFFF0066"; } GT.currentShapes[key] = shapeFeature( key, GT.wasZones[key].geo, "was", boxColor, borderColor, borderWeight ); GT.layerSources.award.addFeature(GT.currentShapes[key]); } } if (which == 5) { for (key in GT.dxccInfo) { var boxColor = "#FF000015"; var borderColor = "#0000FFFF"; var borderWeight = 1; if (didConfirm(GT.dxccInfo[key])) { boxColor = "#00FF0066"; } else if (didWork(GT.dxccInfo[key])) { boxColor = "#FFFF0066"; } if (GT.dxccInfo[key].geo != "deleted") { GT.currentShapes[key] = shapeFeature( key, GT.dxccInfo[key].geo, "dxcc", boxColor, borderColor, borderWeight ); GT.layerSources.award.addFeature(GT.currentShapes[key]); } } } if (which == 6) { for (key in GT.countyData) { var boxColor = "#00000000"; var borderColor = "#0000FFFF"; var borderWeight = 0.1; if (didConfirm(GT.countyData[key])) { boxColor = "#00FF0066"; borderWeight = 1; } else if (didWork(GT.countyData[key])) { boxColor = "#FFFF0066"; borderWeight = 1; } GT.currentShapes[key] = shapeFeature( key, GT.countyData[key].geo, "usc", boxColor, borderColor, borderWeight ); GT.layerSources.award.addFeature(GT.currentShapes[key]); } } if (which == 7) { for (key in GT.us48Data) { var LL = squareToLatLong(key); var bounds = [ [LL.lo1, LL.la1], [LL.lo2, LL.la2] ]; var boxColor = "#FF000015"; var borderColor = "#0000FFFF"; var borderWeight = 0.1; if (GT.us48Data[key].confirmed) { boxColor = "#00FF0066"; borderWeight = 0.2; } else if (GT.us48Data[key].worked) { boxColor = "#FFFF0066"; borderWeight = 0.2; } GT.currentShapes[key] = gridFeature( key, rectangle(bounds), "us48", boxColor, borderColor, borderWeight ); GT.layerSources.award.addFeature(GT.currentShapes[key]); } } updateSpotView(true); } function gridFeature( key, objectData, propname, fillColor, borderColor, borderWidth ) { var style = new ol.style.Style({ stroke: new ol.style.Stroke({ color: borderColor, width: borderWidth }), fill: new ol.style.Fill({ color: fillColor }) }); objectData.setStyle(style); objectData.set("prop", propname); objectData.set("grid", key); objectData.size = 2; return objectData; } function moonOver(feature) { if (GT.currentOverlay != 0) return false; var data = subLunar(timeNowSec()); var object = doRAconvert(GT.myLon, GT.myLat, data.RA, data.Dec); var elevation = object.elevation.toFixed(1); var elColor = "yellow"; if (elevation <= 0) elColor = "red"; if (elevation > 10.0) elColor = "lightgreen"; var worker = ""; worker += ""; worker += ""; worker += ""; worker += "
Moon
Azimuth" + object.azimuth.toFixed(1) + "°
Elevation" + elevation + "
"; myMoonTooltip.innerHTML = worker; moonMove(); myMoonTooltip.style.zIndex = 499; myMoonTooltip.style.display = "block"; return true; } function moonMove(feature) { var positionInfo = myMoonTooltip.getBoundingClientRect(); myMoonTooltip.style.left = getMouseX() - positionInfo.width / 2 + "px"; myMoonTooltip.style.top = getMouseY() - positionInfo.height - 22 + "px"; } function moonOut(feature) { myMoonTooltip.style.zIndex = -1; } function trophyOver(feature) { var name = feature.getGeometryName(); var infoObject = {}; var trophy = ""; var zone = null; var key = feature.get("prop"); if (key == "cqzone") { trophy = "CQ Zone"; infoObject = GT.cqZones[name]; zone = name; name = GT.cqZones[name].name; } if (key == "ituzone") { trophy = "ITU Zone"; infoObject = GT.ituZones[name]; } if (key == "wac" && name in GT.wacZones) { trophy = "Continent"; infoObject = GT.wacZones[name]; } if (key == "was" && name in GT.wasZones) { trophy = "US State"; infoObject = GT.wasZones[name]; } if (key == "dxcc" && name in GT.dxccInfo) { trophy = "DXCC"; var ref = name; infoObject = GT.dxccInfo[ref]; name = GT.dxccInfo[ref].name + " (" + GT.dxccInfo[ref].pp + ")"; } if (key == "usc") { trophy = "US County"; infoObject = GT.countyData[name]; name = infoObject.geo.properties.n + ", " + infoObject.geo.properties.st; } if (key == "us48") { trophy = "US Continental Grids"; infoObject = GT.us48Data[feature.get("grid")]; name = feature.get("grid"); if (name in GT.gridToState) { zone = ""; for (var x = 0; x < GT.gridToDXCC[name].length; x++) { if (name in GT.gridToState) { for (var y = 0; y < GT.gridToState[name].length; y++) { if (GT.gridToDXCC[name][x] == GT.StateData[GT.gridToState[name][y]].dxcc && GT.gridToDXCC[name][x] == 291) { zone += GT.StateData[GT.gridToState[name][y]].name + ", "; } } } } zone = zone.substr(0, zone.length - 2); } } var worker = ""; worker += ""; worker += ""; if (zone) { worker += " "; } var wc1Table = ""; if (infoObject.worked) { wc1Table = ""; } var wcTable = ""; if (infoObject.confirmed) { wcTable = ""; } if (!infoObject.worked && !infoObject.confirmed) { worker += ""; } else { worker += "" + wc1Table + wcTable + ""; } worker += "
" + trophy + "
" + name + "
" + zone + "
"; wc1Table += ""; wc1Table += ""; wc1Table += ""; wc1Table += ""; wc1Table += ""; wc1Table += ""; wc1Table += ""; wc1Table += ""; wc1Table += "
" + $.i18n("gt.wcTable.Worked") + "
Band"; var keys = Object.keys(infoObject.worked_bands).sort(); for (key in keys) { wc1Table += ""; } wc1Table += "
" + keys[key] + " (" + infoObject.worked_bands[keys[key]] + ")
" + $.i18n("gt.wcTable.Mode") + ""; keys = Object.keys(infoObject.worked_modes).sort(); for (key in keys) { wc1Table += ""; } wc1Table += "
" + keys[key] + " (" + infoObject.worked_modes[keys[key]] + ")
"; wcTable += ""; wcTable += ""; wcTable += ""; wcTable += ""; wcTable += ""; wcTable += ""; wcTable += ""; wcTable += ""; wcTable += "
" + $.i18n("gt.wcTable.Confirmed") + "
" + $.i18n("gt.wcTable.Band") + ""; var keys = Object.keys(infoObject.confirmed_bands).sort(); for (key in keys) { wcTable += ""; } wcTable += "
" + keys[key] + " (" + infoObject.confirmed_bands[keys[key]] + ")
" + $.i18n("gt.wcTable.Mode") + ""; keys = Object.keys(infoObject.confirmed_modes).sort(); for (key in keys) { wcTable += ""; } wcTable += "
" + keys[key] + " (" + infoObject.confirmed_modes[keys[key]] + ")
" + $.i18n("gt.wcTable.Needed") + "
"; myTrophyTooltip.innerHTML = "
" + worker + "
"; trophyMove(feature); myTrophyTooltip.style.zIndex = 499; myTrophyTooltip.style.display = "block"; return true; } function trophyMove(feature) { var positionInfo = myTrophyTooltip.getBoundingClientRect(); myTrophyTooltip.style.left = getMouseX() - positionInfo.width / 2 + "px"; myTrophyTooltip.style.top = getMouseY() - positionInfo.height - 22 + "px"; } function trophyOut(feature) { myTrophyTooltip.style.zIndex = -1; } GT.MyCurrentGrid = ""; GT.MyGridIsUp = false; function mouseDownGrid(longlat) { var grid = latLonToGridSquare(longlat[1], longlat[0]); GT.MyCurrentGrid = grid.substr(0, 4); var worker = ""; worker += ""; var bearing = parseInt( MyCircle.bearing(GT.myLat, GT.myLon, longlat[1], longlat[0]) ); worker += ""; worker += ""; worker += ""; worker += "
Dist" + parseInt( MyCircle.distance( GT.myLat, GT.myLon, longlat[1], longlat[0], distanceUnit.value ) * MyCircle.validateRadius(distanceUnit.value) ) + distanceUnit.value.toLowerCase() + "
Azim" + bearing + "°
Lat" + longlat[1].toFixed(3) + "
Long" + longlat[0].toFixed(3) + "
"; if (grid in GT.gridToDXCC) { worker += ""; worker += ""; for (var x = 0; x < GT.gridToDXCC[grid].length; x++) { worker += ""; } if (grid in GT.gridToState) { worker += ""; for (var x = 0; x < GT.gridToDXCC[grid].length; x++) { worker += ""; } } worker += "
" + GT.dxccToAltName[GT.gridToDXCC[grid][x]] + " (" + GT.dxccInfo[GT.gridToDXCC[grid][x]].pp + ")
"; if (grid in GT.gridToState) { for (var y = 0; y < GT.gridToState[grid].length; y++) { if ( GT.gridToDXCC[grid][x] == GT.StateData[GT.gridToState[grid][y]].dxcc ) { worker += GT.StateData[GT.gridToState[grid][y]].name + "
"; } } } worker += "
"; } GT.tempGridBox = tempGridToBox(grid, GT.tempGridBox, "#000000FF", "#00000000"); myGridTooltip.innerHTML = "
" + grid + "
" + worker; GT.MyGridIsUp = true; mouseMoveGrid(); myGridTooltip.style.zIndex = 499; myGridTooltip.style.display = "block"; } function mouseMoveGrid() { if (GT.MyGridIsUp == true) { var positionInfo = myGridTooltip.getBoundingClientRect(); myGridTooltip.style.left = getMouseX() - positionInfo.width / 2 + "px"; myGridTooltip.style.top = getMouseY() - positionInfo.height - 22 + "px"; } } function mouseUpGrid() { GT.MyGridIsUp = false; myGridTooltip.style.zIndex = -1; if (GT.tempGridBox) { if (GT.layerSources.temp.hasFeature(GT.tempGridBox)) { GT.layerSources.temp.removeFeature(GT.tempGridBox); } GT.tempGridBox = null; } } function createFlagTipTable(feature) { var worker = ""; var key = feature.key; var dxcc = callsignToDxcc(GT.gtFlagPins[key].call); var dxccName = GT.dxccToAltName[dxcc]; var workColor = "cyan"; if (GT.gtFlagPins[key].call + GT.appSettings.myBand + GT.appSettings.myMode in GT.tracker.worked.call) { workColor = "yellow"; } if (GT.gtFlagPins[key].call + GT.appSettings.myBand + GT.appSettings.myMode in GT.tracker.confirmed.call) { workColor = "#00FF00"; } worker += "
" + formatCallsign(GT.gtFlagPins[key].call) + "
"; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; var LL = squareToCenter(GT.gtFlagPins[key].grid); var bearing = parseInt(MyCircle.bearing(GT.myLat, GT.myLon, LL.a, LL.o)); worker += ""; worker += ""; worker += "
DXCC" + dxccName + " (" + GT.dxccInfo[dxcc].pp + ")
Grid" + GT.gtFlagPins[key].grid + "
Freq" + formatMhz(Number(GT.gtFlagPins[key].freq / 1000), 3, 3) + " (" + formatBand(Number(GT.gtFlagPins[key].freq / 1000000)) + ")
Mode" + GT.gtFlagPins[key].mode + "
Dist" + parseInt(MyCircle.distance(GT.myLat, GT.myLon, LL.a, LL.o, distanceUnit.value) * MyCircle.validateRadius(distanceUnit.value)) + distanceUnit.value.toLowerCase() + "
Azim" + bearing + "°
"; myFlagtip.innerHTML = worker; } function mouseOverGtFlag(feature) { if (GT.currentOverlay != 0) return false; createFlagTipTable(feature); mouseGtFlagMove(feature); myFlagtip.style.zIndex = 499; myFlagtip.style.display = "block"; return true; } function mouseGtFlagMove(feature) { var positionInfo = myFlagtip.getBoundingClientRect(); myFlagtip.style.left = getMouseX() - positionInfo.width / 2 + "px"; myFlagtip.style.top = getMouseY() - positionInfo.height - 22 + "px"; } function mouseOutGtFlag(feature) { myFlagtip.style.zIndex = -1; } function mouseOverTimezone(feature) { var style = new ol.style.Style({ fill: new ol.style.Fill({ color: "#FFFF0088" }) }); feature.setStyle(style); createTimezoneTipTable(feature); TimezoneMove(); myTimezoneTip.style.zIndex = 499; myTimezoneTip.style.display = "block"; return true; } function createTimezoneTipTable(feature) { var props = feature.getProperties(); moment.locale(navigator.languages[0]); var m = moment().tz(props.tzid); var abbr = m.format("zz"); var zone = m.format("Z"); if (zone.indexOf(abbr) > -1) abbr = ""; else abbr = " (" + abbr + ")"; worker = "
" + props.tzid + "
"; worker += ""; worker += ""; worker += ""; worker += "
" + m.format("LLLL") + "
" + zone + abbr + "
"; myTimezoneTip.innerHTML = worker; } function TimezoneMove() { var positionInfo = myTimezoneTip.getBoundingClientRect(); myTimezoneTip.style.left = getMouseX() - positionInfo.width / 2 + "px"; myTimezoneTip.style.top = getMouseY() - positionInfo.height - 22 + "px"; } function mouseOutZimezone(feature) { myTimezoneTip.style.zIndex = -1; feature.setStyle(null); } function mouseOverDataItem(feature, fromHover) { if (GT.currentOverlay != 0) return false; if (GT.MyGridIsUp) return false; if (GT.mapSettings.mouseOver == true && fromHover == false) return false; if (GT.mapSettings.mouseOver == false && fromHover == true) return false; createTooltTipTable(feature); mouseMoveDataItem(feature); myTooltip.style.zIndex = 500; myTooltip.style.display = "block"; return true; } function mouseMoveDataItem(feature) { var positionInfo = myTooltip.getBoundingClientRect(); var windowWidth = window.innerWidth; var windowHeight = window.innerHeight; var top = 0; var left = 0; var noRoomLeft = false; var noRoomRight = false; top = getMouseY() - (positionInfo.height / 2); // Favor the left side over the right side (avoid covering the work panel if possible) if (getMouseX() - positionInfo.width < 0) { noRoomLeft = true; left = getMouseX() + 10; } else { left = getMouseX() - (10 + positionInfo.width); } if (windowWidth - getMouseX() < positionInfo.width) { noRoomRight = true; } if (noRoomLeft == true && noRoomRight == true) { if (positionInfo.width >= windowWidth) { left = 0; } else { left = getMouseX() - (positionInfo.width / 2); if (left + positionInfo.width > windowWidth) { left = windowWidth - positionInfo.width; } } top = getMouseY() + 10; if (positionInfo.height < getMouseY() - 10) { top = (getMouseY() - positionInfo.height) - 10; } } else { if (top + positionInfo.height > windowHeight) { top = windowHeight - positionInfo.height; } } if (top < 0) { top = 0; } if (left < 0) { left = 0; } myTooltip.style.top = parseInt(top) + "px"; myTooltip.style.left = parseInt(left) + "px"; } function mouseOutOfDataItem(feature) { myTooltip.style.zIndex = -1; if (GT.spotView == 1) GT.layerSources["psk-hop"].clear(); } function reloadInfo(bandOrMode) { if (GT.statsWindowInitialized == true) { try { GT.statsWindowHandle.window.reloadInfo(); } catch (e) { console.error(e); } } } function twoWideToLatLong(qth) { qth = qth.toUpperCase(); var a = qth.charCodeAt(0) - 65; var b = qth.charCodeAt(1) - 65; var la1 = b * 10; var lo1 = a * 20; var la2 = la1 + 10; var lo2 = lo1 + 20; var LatLong = []; la1 -= 90; lo1 -= 180; la2 -= 90; lo2 -= 180; LatLong.la1 = la1; LatLong.lo1 = lo1; LatLong.la2 = la2; LatLong.lo2 = lo2; return LatLong; } function squareToCenter(qth) { var LL = squareToLatLongAll(qth); var obj = {}; obj.a = LL.la2 - (LL.la2 - LL.la1) / 2; obj.o = LL.lo2 - (LL.lo2 - LL.lo1) / 2; return obj; } function squareToLatLongAll(qth) { qth = qth.toUpperCase(); var a = qth.charCodeAt(0) - 65; var b = qth.charCodeAt(1) - 65; var c = qth.charCodeAt(2) - 48; var d = qth.charCodeAt(3) - 48; var la1 = b * 10 + d; var lo1 = a * 20 + c * 2; var la2; var lo2; var LatLong = []; if (qth.length == 4) { la2 = la1 + 1; lo2 = lo1 + 2; LatLong.size = 4; } else { var lo3; var la3; var e = qth.charCodeAt(4) - 65; var f = qth.charCodeAt(5) - 65; var R = 5 / 60; var T = 2.5 / 60; lo3 = (e * 5) / 60; la3 = (f * 2.5) / 60; la1 += la3; lo1 += lo3; la2 = la1 + T; lo2 = lo1 + R; LatLong.size = 6; } la1 -= 90; lo1 -= 180; la2 -= 90; lo2 -= 180; LatLong.la1 = la1; LatLong.lo1 = lo1; LatLong.la2 = la2; LatLong.lo2 = lo2; return LatLong; } function squareToLatLong(qth) { qth = qth.toUpperCase(); var a = qth.charCodeAt(0) - 65; var b = qth.charCodeAt(1) - 65; var c = qth.charCodeAt(2) - 48; var d = qth.charCodeAt(3) - 48; var la1 = b * 10 + d; var lo1 = a * 20 + c * 2; var la2; var lo2; var LatLong = []; if (qth.length == 4 || GT.appSettings.sixWideMode == 0) { la2 = la1 + 1; lo2 = lo1 + 2; LatLong.size = 4; } else { var lo3; var la3; var e = qth.charCodeAt(4) - 65; var f = qth.charCodeAt(5) - 65; var R = 5 / 60; var T = 2.5 / 60; lo3 = (e * 5) / 60; la3 = (f * 2.5) / 60; la1 += la3; lo1 += lo3; la2 = la1 + T; lo2 = lo1 + R; LatLong.size = 6; } la1 -= 90; lo1 -= 180; la2 -= 90; lo2 -= 180; LatLong.la1 = la1; LatLong.lo1 = lo1; LatLong.la2 = la2; LatLong.lo2 = lo2; return LatLong; } function iconFeature(center, iconObj, zIndex, propName) { var feature = new ol.Feature({ geometry: new ol.geom.Point(center), prop: propName }); var iconStyle = new ol.style.Style({ zIndex: zIndex, image: iconObj }); feature.setStyle(iconStyle); return feature; } function qthToQsoBox(iQTH, iHash, locked, DE, worked, confirmed, band, wspr) { if (GT.appSettings.gridViewMode == 1) return null; var borderColor = GT.mainBorderColor; var boxColor = GT.legendColors.QSX + GT.gridAlpha; var borderWeight = 0.5; var myDEbox = false; if (worked) { boxColor = GT.legendColors.QSO + GT.gridAlpha; } if (confirmed) { boxColor = GT.legendColors.QSL + GT.gridAlpha; } if (wspr != null) { boxColor = "hsl(" + wspr + ",100%,50%)"; borderColor = "gray"; } var zIndex = 2; var entityVisibility = GT.appSettings.gridViewMode > 1; var returnRectangle = null; if (GT.appSettings.sixWideMode == 0) iQTH = iQTH.substr(0, 4); else iQTH = iQTH.substr(0, 6); var rect = null; if (iQTH == "") { for (var key in GT.qsoGrids) { if (iHash in GT.qsoGrids[key].rectangle.hashes) { rect = GT.qsoGrids[key]; break; } } } else { if (iQTH in GT.qsoGrids) { rect = GT.qsoGrids[iQTH]; } } if (rect == null) { if (iQTH != "") { // Valid QTH var triangleView = false; if (GT.appSettings.gridViewMode == 3 && iQTH in GT.liveGrids && entityVisibility == true && GT.pushPinMode == false) { if (confirmed) { hideLiveGrid(iQTH); } else { liveTriangleGrid(iQTH); triangleView = true; } } LL = squareToLatLong(iQTH); if (LL.size == 6) { borderColor = "#000000FF"; zIndex = 50; } newRect = {}; newRect.shouldDim = false; newRect.qth = iQTH; var bounds = [ [LL.lo1, LL.la1], [LL.lo2, LL.la2] ]; if (triangleView == true) newRect.rectangle = triangle(bounds, true); else newRect.rectangle = rectangle(bounds); newRect.isTriangle = triangleView; const featureHoverStyle = new ol.style.Style({ fill: new ol.style.Fill({ color: boxColor }), stroke: new ol.style.Stroke({ color: borderColor, width: borderWeight, lineJoin: "round" }), zIndex: zIndex }); newRect.rectangle.setStyle(featureHoverStyle); newRect.rectangle.qth = iQTH; if (GT.pushPinMode == false && entityVisibility == true) { GT.layerSources.qso.addFeature(newRect.rectangle); } var newPin = GT.colorLeafletQPins.worked[band]; if (confirmed) newPin = GT.colorLeafletQPins.confirmed[band]; newRect.rectangle.pin = iconFeature( ol.extent.getCenter(newRect.rectangle.getGeometry().getExtent()), GT.appSettings.sixWideMode == 1 ? newPin : GT.pushPinIconOff, zIndex, "pin" ); newRect.rectangle.pin.qth = iQTH; newRect.rectangle.pin.hashes = {}; newRect.rectangle.pin.hashes[iHash] = 1; newRect.rectangle.pin.size = LL.size; if (GT.pushPinMode && entityVisibility == true) { GT.layerSources["qso-pins"].addFeature(newRect.rectangle.pin); } newRect.rectangle.locked = locked; newRect.rectangle.worked = worked; newRect.rectangle.confirmed = confirmed; newRect.rectangle.size = LL.size; newRect.rectangle.hashes = {}; newRect.rectangle.hashes[iHash] = 1; newRect.rectangle.qso = true; newRect.rectangle.pin.qso = true; GT.qsoGrids[iQTH] = newRect; returnRectangle = newRect.rectangle; } } else { if (!(iHash in rect.rectangle.hashes)) { rect.rectangle.hashes[iHash] = 1; rect.rectangle.pin.hashes[iHash] = 1; } if (!confirmed && rect.rectangle.confirmed) { return rect.rectangle; } if (worked && !rect.rectangle.worked) rect.rectangle.worked = worked; if (confirmed && !rect.rectangle.confirmed) { rect.rectangle.confirmed = confirmed; } borderColor = GT.mainBorderColor; if (myDEbox) borderWeight = 1; zIndex = 2; if (rect.rectangle.size == 6) { borderColor = "#000000FF"; zIndex = 50; } rect.shouldDim = false; const featureHoverStyle = new ol.style.Style({ fill: new ol.style.Fill({ color: boxColor }), stroke: new ol.style.Stroke({ color: borderColor, width: borderWeight, lineJoin: "round" }), zIndex: zIndex }); rect.rectangle.setStyle(featureHoverStyle); returnRectangle = rect.rectangle; } return returnRectangle; } function qthToBox(iQTH, iDEcallsign, iCQ, locked, DE, band, wspr, hash) { if (GT.appSettings.gridViewMode == 2) return null; var borderColor = GT.mainBorderColor; var boxColor = GT.legendColors.QSX + GT.gridAlpha; var borderWeight = 0.5; var myDEzOffset = 0; var myDEbox = false; if (DE == "CQ" || iCQ) { boxColor = GT.legendColors.CQ + GT.gridAlpha; } if (DE == GT.appSettings.myCall) { borderColor = "#FF0000FF"; boxColor = GT.legendColors.QRZ + GT.gridAlpha; borderWeight = 1.0; myDEzOffset = 20; myDEbox = true; } if (DE.indexOf("CQ DX") > -1) { boxColor = GT.legendColors.CQDX + GT.gridAlpha; } if (locked) { boxColor = GT.legendColors.QTH + GT.gridAlpha; borderColor = "#000000FF"; borderOpacity = 1; } if (wspr != null) { boxColor = "hsl(" + wspr + ",100%,50%)"; borderColor = "gray"; } var zIndex = 2; var returnRectangle = null; if (GT.appSettings.sixWideMode == 0) iQTH = iQTH.substr(0, 4); else iQTH = iQTH.substr(0, 6); var rect = null; if (iQTH == "") { for (var key in GT.liveGrids) { if (hash in GT.liveGrids[key].rectangle.liveHash) { rect = GT.liveGrids[key]; break; } } } else { if (iQTH in GT.liveGrids) { rect = GT.liveGrids[iQTH]; } } if (rect == null) { if (iQTH != "") { // Valid QTH var entityVisibility = true; var triangleView = false; if ( Number(GT.appSettings.gridViewMode) == 3 && iQTH in GT.qsoGrids && GT.pushPinMode == false ) { if ( GT.mapSettings.splitQSL || GT.qsoGrids[iQTH].rectangle.confirmed == false ) { qsoTriangleGrid(iQTH); triangleView = true; entityVisibility = true; } else entityVisibility = false; } LL = squareToLatLong(iQTH); if (LL.size == 6) { borderColor = "#000000FF"; // borderWeight = 1.0; zIndex = 50; } newRect = {}; newRect.age = GT.timeNow; newRect.shouldDim = false; newRect.qth = iQTH; var bounds = [ [LL.lo1, LL.la1], [LL.lo2, LL.la2] ]; if (triangleView == true) newRect.rectangle = triangle(bounds, false); else newRect.rectangle = rectangle(bounds); newRect.isTriangle = triangleView; newRect.rectangle.setId(iQTH); const featureHoverStyle = new ol.style.Style({ fill: new ol.style.Fill({ color: boxColor }), stroke: new ol.style.Stroke({ color: borderColor, width: borderWeight, lineJoin: "round" }), zIndex: zIndex }); newRect.rectangle.setStyle(featureHoverStyle); newRect.rectangle.qth = iQTH; if (GT.pushPinMode == false && entityVisibility) { GT.layerSources.live.addFeature(newRect.rectangle); } newRect.rectangle.pin = iconFeature( ol.extent.getCenter(newRect.rectangle.getGeometry().getExtent()), GT.colorLeafletPins[band], zIndex, "pin" ); newRect.rectangle.pin.qth = iQTH; newRect.rectangle.pin.liveHash = {}; newRect.rectangle.pin.liveHash[hash] = 1; newRect.rectangle.pin.size = LL.size; if (GT.pushPinMode && entityVisibility == true) { GT.layerSources["live-pins"].addFeature(newRect.rectangle.pin); } newRect.rectangle.locked = locked; newRect.rectangle.size = LL.size; newRect.rectangle.liveHash = {}; newRect.rectangle.liveHash[hash] = 1; newRect.rectangle.qso = false; newRect.rectangle.pin.qso = false; GT.liveGrids[iQTH] = newRect; returnRectangle = newRect.rectangle; } } else { if (!(hash in rect.rectangle.liveHash)) { rect.rectangle.liveHash[hash] = 1; rect.rectangle.pin.liveHash[hash] = 1; } if (locked && !rect.rectangle.locked) rect.rectangle.locked = locked; if (rect.rectangle.locked) { borderColor = "#000000FF"; } if (myDEbox) borderWeight = 1; if (rect.rectangle.size == 6) { borderColor = "#000000FF"; // borderWeight = 1.0; zIndex = 50; } newRect.age = GT.timeNow; newRect.shouldDim = false; const featureHoverStyle = new ol.style.Style({ fill: new ol.style.Fill({ color: boxColor }), stroke: new ol.style.Stroke({ color: borderColor, width: borderWeight, lineJoin: "round" }), zIndex: zIndex }); rect.rectangle.setStyle(featureHoverStyle); returnRectangle = rect.rectangle; } return returnRectangle; } function alphaFrom(rgba) { var alphaInt = hexToA(rgba); var alphaFloat = alphaInt / 255.0; return alphaFloat; } function alphaTo(rgba, alphaFloat) { var alphaInt = parseInt(alphaFloat * 255); var alphaHex = alphaInt.toString(16); if (alphaHex.length == 1) { alphaHex = "0" + alphaHex; } return rgba.slice(0, -2) + alphaHex; } function intAlphaToRGB(rgb, alphaInt) { var alphaHex = alphaInt.toString(16); if (alphaHex.length == 1) { alphaHex = "0" + alphaHex; } return rgb + alphaHex; } function dimFunction(qthObj) { if (qthObj.rectangle.locked == false) { var featureStyle = qthObj.rectangle.getStyle(); var featureFill = featureStyle.getFill(); var fillColor = featureFill.getColor(); var featureStroke = featureStyle.getStroke(); var strokeColor = featureStroke.getColor(); var percent = 1.0 - (GT.timeNow - qthObj.age) / gridDecay.value; var alpha = Math.max(0.06, (GT.mapSettings.gridAlpha / 255) * percent); fillColor = alphaTo(fillColor, alpha); featureFill.setColor(fillColor); featureStyle.setFill(featureFill); strokeColor = alphaTo(strokeColor, alpha); featureStroke.setColor(strokeColor); featureStyle.setStroke(featureStroke); qthObj.rectangle.setStyle(featureStyle); } } function toggleTrafficDecode() { trafficDecode.checked = trafficDecode.checked != true; changeTrafficDecode(); } function changeTrafficDecode() { GT.mapSettings.trafficDecode = trafficDecode.checked; trafficDecodeView(); saveMapSettings(); } function trafficDecodeView() { if (GT.mapSettings.trafficDecode == false) { trafficDiv.innerHTML = ""; GT.lastTraffic = Array(); } } function changeFitQRZvalue() { GT.mapSettings.fitQRZ = fitQRZvalue.checked; saveMapSettings(); } function changeQrzDxccFallbackValue() { GT.mapSettings.qrzDxccFallback = qrzDxccFallbackValue.checked; saveMapSettings(); } function changeCqHiliteValue(check) { GT.mapSettings.CQhilite = check.checked; saveMapSettings(); if (check.checked == false) removePaths(); } function changeFocusRigValue(check) { GT.mapSettings.focusRig = check.checked; saveMapSettings(); } function changeHaltOntTxValue(check) { GT.mapSettings.haltAllOnTx = check.checked; saveMapSettings(); } function changeSplitQSL() { GT.mapSettings.splitQSL = splitQSLValue.checked; saveMapSettings(); redrawGrids(); } function setAnimateView() { if (animateValue.checked) { animationSpeedTd.style.display = "inline-table"; } else { animationSpeedTd.style.display = "none"; } } function toggleAnimate() { animateValue.checked = animateValue.checked != true; changeAnimate(); } function toggleAllGrids() { GT.showAllGrids = !GT.showAllGrids; setTrophyOverlay(GT.currentOverlay); gridOverlayImg.style.filter = GT.showAllGrids ? "" : "grayscale(1)"; } function changeAnimate() { GT.mapSettings.animate = animateValue.checked; saveMapSettings(); var dash = []; var dashOff = 0; if (GT.mapSettings.animate == true) { dash = GT.flightPathLineDash; dashOff = GT.flightPathTotal - GT.flightPathOffset; } for (var i = GT.flightPaths.length - 1; i >= 0; i--) { if (GT.flightPaths[i].isShapeFlight == 0) { var featureStyle = GT.flightPaths[i].getStyle(); var featureStroke = featureStyle.getStroke(); featureStroke.setLineDash(dash); featureStroke.setLineDashOffset(dashOff); featureStyle.setStroke(featureStroke); GT.flightPaths[i].setStyle(featureStyle); } } if (GT.transmitFlightPath != null) { var featureStyle = GT.transmitFlightPath.getStyle(); var featureStroke = featureStyle.getStroke(); featureStroke.setLineDash(dash); featureStroke.setLineDashOffset(dashOff); featureStyle.setStroke(featureStroke); GT.transmitFlightPath.setStyle(featureStyle); } setAnimateView(); } function changeAnimateSpeedValue() { GT.mapSettings.animateSpeed = 21 - animateSpeedValue.value; saveMapSettings(); } GT.animateFrame = 0; GT.nextDimTime = 0; GT.last = 0; function removeFlightPathsAndDimSquares() { for (var i = GT.flightPaths.length - 1; i >= 0; i--) { if (GT.flightPaths[i].age < GT.timeNow) { if (typeof GT.flightPaths[i].Arrow != "undefined") { GT.layerSources.flight.removeFeature(GT.flightPaths[i].Arrow); } GT.layerSources.flight.removeFeature(GT.flightPaths[i]); delete GT.flightPaths[i]; GT.flightPaths[i] = null; GT.flightPaths.splice(i, 1); } } if (GT.timeNow > GT.nextDimTime) { dimGridsquare(); } } function animatePaths() { requestAnimationFrame(animatePaths); GT.last ^= GT.last; if (GT.last == 1) return; GT.animateFrame++; GT.animateFrame %= GT.mapSettings.animateSpeed; if (GT.animateFrame > 0) return; if (GT.mapSettings.animate == false) return; GT.flightPathOffset += 1; GT.flightPathOffset %= GT.flightPathTotal; var targetOffset = GT.flightPathTotal - GT.flightPathOffset; var featureStyle = null; var featureStroke = null; for (var i = 0; i < GT.flightPaths.length; i++) { if (GT.flightPaths[i].isShapeFlight == 0) { featureStyle = GT.flightPaths[i].getStyle(); featureStroke = featureStyle.getStroke(); featureStroke.setLineDashOffset(targetOffset); GT.flightPaths[i].setStyle(featureStyle); } } if (GT.transmitFlightPath != null) { var featureStyle = GT.transmitFlightPath.getStyle(); var featureStroke = featureStyle.getStroke(); featureStroke.setLineDashOffset(targetOffset); featureStyle.setStroke(featureStroke); GT.transmitFlightPath.setStyle(featureStyle); } } function removePaths() { GT.layerSources.flight.clear(); GT.flightPaths = Array(); } function fadePaths() { if (pathWidthValue.value == 0) { removePaths(); } } function dimGridsquare() { if (gridDecay.value == 0) return; for (var i in GT.liveGrids) { dimFunction(GT.liveGrids[i]); if ( GT.timeNow - GT.liveGrids[i].age >= gridDecay.value && GT.liveGrids[i].rectangle.locked == false ) { // Walk the rectangles DEcall's and remove them from GT.liveCallsigns for (var CallIsKey in GT.liveGrids[i].rectangle.liveHash) { if (CallIsKey in GT.liveCallsigns) { GT.liveCallsigns[CallIsKey].rect = null; delete GT.liveCallsigns[CallIsKey]; } } if (GT.liveGrids[i].rectangle.pin != null) { if ( GT.layerSources["live-pins"].hasFeature(GT.liveGrids[i].rectangle.pin) ) { GT.layerSources["live-pins"].removeFeature( GT.liveGrids[i].rectangle.pin ); } } if (GT.layerSources.live.hasFeature(GT.liveGrids[i].rectangle)) { GT.layerSources.live.removeFeature(GT.liveGrids[i].rectangle); if (GT.appSettings.gridViewMode == 3 && i in GT.qsoGrids) { if (GT.qsoGrids[i].isTriangle) { triangleToGrid(i, GT.qsoGrids[i].rectangle); GT.qsoGrids[i].isTriangle = false; } } } GT.liveGrids[i] = null; delete GT.liveGrids[i]; } } GT.nextDimTime = GT.timeNow + 7; } function updateCountStats() { var count = Object.keys(GT.liveCallsigns).length; if (GT.appSettings.myCall in GT.liveCallsigns) count--; callsignCount.innerHTML = count; qsoCount.innerHTML = GT.QSOcount; qslCount.innerHTML = GT.QSLcount; countryCount.innerHTML = Object.keys(GT.dxccCount).length; if (Object.keys(GT.QSOhash).length > 0) { clearOrLoadButton.innerHTML = $.i18n("quickLoad.clearLog.label"); GT.loadQSOs = false; } else { clearOrLoadButton.innerHTML = $.i18n("quickLoad.loadLog.label"); GT.loadQSOs = true; } } function clearGrids() { GT.layerSources.live.clear(); GT.layerSources["live-pins"].clear(); for (var i in GT.liveGrids) { // Walk the rectangles DEcall's and remove the rect from the GT.liveCallsigns for (var CallIsKey in GT.liveGrids[i].rectangle.liveHash) { if (CallIsKey in GT.liveCallsigns) GT.liveCallsigns[CallIsKey].rect = null; } } GT.liveGrids = {}; } function clearQsoGrids() { GT.layerSources.qso.clear(); GT.layerSources["qso-pins"].clear(); GT.qsoGrids = {}; for (var key in GT.dxccInfo) { GT.dxccInfo[key].worked = false; GT.dxccInfo[key].confirmed = false; GT.dxccInfo[key].worked_bands = {}; GT.dxccInfo[key].confirmed_bands = {}; GT.dxccInfo[key].worked_modes = {}; GT.dxccInfo[key].confirmed_modes = {}; } for (var key in GT.cqZones) { GT.cqZones[key].worked = false; GT.cqZones[key].confirmed = false; GT.cqZones[key].worked_bands = {}; GT.cqZones[key].confirmed_bands = {}; GT.cqZones[key].worked_modes = {}; GT.cqZones[key].confirmed_modes = {}; } for (var key in GT.ituZones) { GT.ituZones[key].worked = false; GT.ituZones[key].confirmed = false; GT.ituZones[key].worked_bands = {}; GT.ituZones[key].confirmed_bands = {}; GT.ituZones[key].worked_modes = {}; GT.ituZones[key].confirmed_modes = {}; } for (var key in GT.wasZones) { GT.wasZones[key].worked = false; GT.wasZones[key].confirmed = false; GT.wasZones[key].worked_bands = {}; GT.wasZones[key].confirmed_bands = {}; GT.wasZones[key].worked_modes = {}; GT.wasZones[key].confirmed_modes = {}; } for (var key in GT.wacZones) { GT.wacZones[key].worked = false; GT.wacZones[key].confirmed = false; GT.wacZones[key].worked_bands = {}; GT.wacZones[key].confirmed_bands = {}; GT.wacZones[key].worked_modes = {}; GT.wacZones[key].confirmed_modes = {}; } for (var key in GT.countyData) { GT.countyData[key].worked = false; GT.countyData[key].confirmed = false; GT.countyData[key].worked_bands = {}; GT.countyData[key].confirmed_bands = {}; GT.countyData[key].worked_modes = {}; GT.countyData[key].confirmed_modes = {}; } for (var key in GT.us48Data) { GT.us48Data[key].worked = false; GT.us48Data[key].confirmed = false; GT.us48Data[key].worked_bands = {}; GT.us48Data[key].confirmed_bands = {}; GT.us48Data[key].worked_modes = {}; GT.us48Data[key].confirmed_modes = {}; } } function clearCalls() { removePaths(); for (var i in GT.liveCallsigns) { if ( typeof GT.liveCallsigns[i].rect != "undefined" && GT.liveCallsigns[i].rect != null ) { if (i in GT.liveCallsigns[i].rect.liveHash) { delete GT.liveCallsigns[i].rect.liveHash[i]; } } } GT.liveCallsigns = {}; GT.dxccCount = {}; redrawGrids(); } function clearLive() { GT.Decodes = 0; GT.lastMessages = Array(); GT.lastTraffic = Array(); GT.callRoster = {}; GT.dxccCount = {}; removePaths(); removePaths(); clearGrids(); clearCalls(); clearTempGrids(); setHomeGridsquare(); redrawGrids(); updateRosterWorked(); goProcessRoster(); } function clearAll() { clearTempGrids(); clearCalls(); clearQSOs(); GT.lastMessages = Array(); GT.lastTraffic = Array(); GT.dxccCount = {}; redrawGrids(); GT.callRoster = {}; updateRosterWorked(); goProcessRoster(); } function clearOrLoadQSOs() { if (GT.loadQSOs == true) { startupAdifLoadCheck(); } else { clearQSOs(); } } function clearAndLoadQSOs() { clearQSOs(); startupAdifLoadCheck(); } function clearQSOs() { initQSOdata(); GT.QSOhash = {}; GT.QSLcount = 0; GT.QSOcount = 0; setTrophyOverlay(GT.currentOverlay); redrawGrids(); updateLogbook(); updateRosterWorked(); goProcessRoster(); clearLogFilesAndCounts(); } function clearLogFilesAndCounts() { tryToDeleteLog("LogbookOfTheWorld.adif"); tryToDeleteLog("qrz.adif"); tryToDeleteLog("clublog.adif"); GT.adifLogSettings.downloads = {}; GT.adifLogSettings.lastFetch.lotw_qso = "1970-01-01"; GT.adifLogSettings.lastFetch.lotw_qsl = "1970-01-01"; saveAdifSettings(); } function getCurrentBandModeHTML() { var band = GT.appSettings.gtBandFilter == "auto" ? GT.appSettings.myBand + " (Auto)" : GT.appSettings.gtBandFilter.length == 0 ? "Mixed Bands" : GT.appSettings.gtBandFilter; var mode = GT.appSettings.gtModeFilter == "auto" ? GT.appSettings.myMode + " (Auto)" : GT.appSettings.gtModeFilter.length == 0 ? "Mixed Modes" : GT.appSettings.gtModeFilter; return ( "
" + $.i18n("stats.viewing") + ": " + band + " / " + mode + "

" ); } GT.currentDay = 0; GT.nightTime = false; GT.currentNightState = false; GT.timeNow = timeNowSec(); function displayTime() { GT.timeNow = timeNowSec(); if (menuDiv.className == "menuDivStart" && GT.menuShowing == true) { menuDiv.className = "menuDivEnd"; mapDiv.className = "mapDivEnd"; LegendDiv.className = "legendDivEnd"; GT.map.updateSize(); } currentTime.innerHTML = "" + userTimeString(null) + ""; if (GT.lastTimeSinceMessageInSeconds > 0) { var since = GT.timeNow - GT.lastTimeSinceMessageInSeconds; secondsAgoMsg.innerHTML = toDHMS(since); if (since > 17 && since < 122) { secondsAgoMsg.style.backgroundColor = "yellow"; secondsAgoMsg.style.color = "#000"; } else if (since > 121) { secondsAgoMsg.style.backgroundColor = "red"; secondsAgoMsg.style.color = "#000"; } else { secondsAgoMsg.style.backgroundColor = "blue"; secondsAgoMsg.style.color = "#FF0"; } } else secondsAgoMsg.innerHTML = "Never"; checkWsjtxListener(); if (GT.timeNow % 22 == 0) { GT.nightTime = dayNight.refresh(); moonLayer.refresh(); } pskSpotCheck(GT.timeNow); if (GT.currentNightState != GT.nightTime) { changeMapLayer(); GT.currentNightState = GT.nightTime; } } function timeNowSec() { return parseInt(Date.now() / 1000); } function createGlobalHeatmapLayer(name, radius, blur) { GT.layerSources[name] = new ol.source.Vector({}); GT.layerVectors[name] = new ol.layer.Heatmap({ source: GT.layerSources[name], blur: 20, radius: 15, zIndex: Object.keys(GT.layerVectors).length + 1 }); GT.layerVectors[name].set("name", name); } function createGlobalMapLayer(name, maxResolution, minResolution) { GT.layerSources[name] = new ol.source.Vector({}); if ( typeof maxResolution == "undefined" && typeof minResolution == "undefined" ) { var zIndex = Object.keys(GT.layerVectors).length + 1; GT.layerVectors[name] = new ol.layer.Vector({ source: GT.layerSources[name], zIndex: zIndex }); } else if (typeof minResolution == "undefined") { GT.layerVectors[name] = new ol.layer.Vector({ source: GT.layerSources[name], maxResolution: maxResolution, zIndex: Object.keys(GT.layerVectors).length + 1 }); } else { GT.layerVectors[name] = new ol.layer.Vector({ source: GT.layerSources[name], maxResolution: maxResolution, minResolution: minResolution, zIndex: Object.keys(GT.layerVectors).length + 1 }); } GT.layerVectors[name].set("name", name); } function createGeoJsonLayer(name, url, color, stroke) { var style = new ol.style.Style({ stroke: new ol.style.Stroke({ color: color, width: stroke }), fill: new ol.style.Fill({ color: "#00000000" }) }); var layerSource = new ol.source.Vector({ url: url, format: new ol.format.GeoJSON({ geometryName: name }), overlaps: false }); var layerVector = new ol.layer.Vector({ source: layerSource, style: style, visible: true, zIndex: 1 }); layerVector.set("name", name); return layerVector; } GT.gtFlagIcon = new ol.style.Icon({ src: "./img/flag_gt_user.png", anchorYUnits: "pixels", anchorXUnits: "pixels", anchor: [12, 17] }); GT.pushPinIconOff = new ol.style.Icon({ src: "./img/red-circle.png", anchorYUnits: "pixels", anchorXUnits: "pixels", anchor: [5, 18] }); function panTo(location) { var duration = 1000; GT.mapView.animate({ center: location, duration: duration }); } function toggleMouseTrack() { GT.appSettings.mouseTrack ^= 1; if (GT.appSettings.mouseTrack == 0) mouseTrackDiv.style.display = "none"; } function myGmapNameCompare(a, b) { return GT.maps[a].name.localeCompare(GT.maps[b].name); } GT.Nexrad = null; GT.hoverFunctors = Object(); GT.lastHover = { feature: null, functor: null }; function initHoverFunctors() { // { hover: , move: , out: }; GT.hoverFunctors.tz = { hover: mouseOverTimezone, move: TimezoneMove, out: mouseOutZimezone }; GT.hoverFunctors.grid = { hover: mouseOverDataItem, move: mouseMoveDataItem, out: mouseOutOfDataItem }; GT.hoverFunctors.pin = { hover: mouseOverDataItem, move: mouseMoveDataItem, out: mouseOutOfDataItem }; GT.hoverFunctors.moon = { hover: moonOver, move: moonMove, out: moonOut }; GT.hoverFunctors.dxcc = { hover: trophyOver, move: trophyMove, out: trophyOut }; GT.hoverFunctors.cqzone = { hover: trophyOver, move: trophyMove, out: trophyOut }; GT.hoverFunctors.ituzone = { hover: trophyOver, move: trophyMove, out: trophyOut }; GT.hoverFunctors.wac = { hover: trophyOver, move: trophyMove, out: trophyOut }; GT.hoverFunctors.was = { hover: trophyOver, move: trophyMove, out: trophyOut }; GT.hoverFunctors.usc = { hover: trophyOver, move: trophyMove, out: trophyOut }; GT.hoverFunctors.us48 = { hover: trophyOver, move: trophyMove, out: trophyOut }; GT.hoverFunctors.parkFlag = { hover: mouseOverPark, move: mouseParkMove, out: mouseOutPark }; GT.hoverFunctors.gtFlag = { hover: mouseOverGtFlag, move: mouseGtFlagMove, out: mouseOutGtFlag }; GT.hoverFunctors.spot = { hover: mouseOverDataItem, move: mouseMoveDataItem, out: mouseOutOfDataItem }; } function initMap() { initHoverFunctors(); document.getElementById("mapDiv").innerHTML = ""; GT.maps = JSON.parse(fs.readFileSync(GT.mapsFile)); if (GT.maps) { var saveSettings = false; GT.maps = Object.keys(GT.maps).sort().reduce((obj, key) => { obj[key] = GT.maps[key]; return obj; }, {}); if (!(GT.mapSettings.mapIndex in GT.maps)) { GT.mapSettings.mapIndex = def_mapSettings.mapIndex; saveSettings = true; } if (!(GT.mapSettings.nightMapIndex in GT.maps)) { GT.mapSettings.nightMapIndex = def_mapSettings.nightMapIndex; saveSettings = true; } if (saveSettings) { saveMapSettings(); } for (const key in GT.maps) { GT.mapsLayer[key] = new ol.source.XYZ(GT.maps[key]); var option = document.createElement("option"); option.value = key; option.text = key; mapSelect.appendChild(option); option = document.createElement("option"); option.value = key; option.text = key; mapNightSelect.appendChild(option); } mapSelect.value = GT.mapSettings.mapIndex; mapNightSelect.value = GT.mapSettings.nightMapIndex; } else GT.mapsLayer[0] = new ol.source.OSM(); GT.offlineLayer = new ol.source.XYZ({ url: "/map/sat/{z}/{x}/{y}.png" }); if (GT.mapSettings.offlineMode) { GT.tileLayer = new ol.layer.Tile({ source: GT.offlineLayer, loadTilesWhileInteracting: true, loadTilesWhileAnimating: true }); } else { GT.tileLayer = new ol.layer.Tile({ source: GT.mapsLayer[mapSelect.value], loadTilesWhileInteracting: true, loadTilesWhileAnimating: true }); } GT.scaleLine = new ol.control.ScaleLine({ units: GT.scaleUnits[GT.appSettings.distanceUnit] }); GT.mapControl = [ GT.scaleLine, new ol.control.Zoom(), new ol.control.FullScreen({ source: "mainBody" }) ]; createGlobalMapLayer("award"); createGlobalHeatmapLayer("psk-heat", 10, 5); createGlobalMapLayer("qso"); createGlobalMapLayer("qso-pins"); createGlobalMapLayer("live"); createGlobalMapLayer("live-pins"); createGlobalMapLayer("line-grids"); createGlobalMapLayer("long-grids", 4500); createGlobalMapLayer("big-grids", 50000, 4501); createGlobalMapLayer("psk-flights"); createGlobalMapLayer("psk-spots"); createGlobalMapLayer("psk-hop"); createGlobalMapLayer("pota"); createGlobalMapLayer("flight"); createGlobalMapLayer("transmit"); createGlobalMapLayer("gtflags"); createGlobalMapLayer("temp"); createGlobalMapLayer("tz"); createGlobalMapLayer("radar"); GT.mapView = new ol.View({ center: [GT.myLon, GT.myLat], zoomFactor: 1.25, zoom: GT.mapSettings.zoom, showFullExtent: true }); GT.map = new ol.Map({ target: "mapDiv", layers: [ GT.tileLayer, GT.layerVectors.award, GT.layerVectors["psk-heat"], GT.layerVectors.qso, GT.layerVectors["qso-pins"], GT.layerVectors.live, GT.layerVectors["live-pins"], GT.layerVectors["line-grids"], GT.layerVectors["long-grids"], GT.layerVectors["big-grids"], GT.layerVectors["psk-flights"], GT.layerVectors["psk-spots"], GT.layerVectors["psk-hop"], GT.layerVectors.pota, GT.layerVectors.flight, GT.layerVectors.transmit, GT.layerVectors.gtflags, GT.layerVectors.temp, GT.layerVectors.tz, GT.layerVectors.radar ], interactions: ol.interaction.defaults({ dragPan: false, mouseWheelZoom: false }).extend([ new ol.interaction.DragPan({ kinetic: false }), new ol.interaction.MouseWheelZoom({ duration: 0 }) ]), controls: GT.mapControl, loadTilesWhileInteracting: false, loadTilesWhileAnimating: false, view: GT.mapView }); mapDiv.addEventListener("pointermove", function (event) { onMouseUpdate(event); var mousePosition = GT.map.getEventPixel(event); if (GT.appSettings.mouseTrack == 1) { var mouseLngLat = GT.map.getEventCoordinate(event); if (mouseLngLat) { var LL = ol.proj.toLonLat(mouseLngLat); var dist = parseInt(MyCircle.distance(GT.myLat, GT.myLon, LL[1], LL[0], distanceUnit.value) * MyCircle.validateRadius(distanceUnit.value)) + distanceUnit.value.toLowerCase(); var azim = parseInt(MyCircle.bearing(GT.myLat, GT.myLon, LL[1], LL[0])) + "°"; var gg = latLonToGridSquare(LL[1], LL[0], (GT.appSettings.sixWideMode == 1 ? 6 : 4)); mouseTrackDiv.innerHTML = LL[1].toFixed(3) + ", " + LL[0].toFixed(3) + " " + dist + " " + azim + " " + gg; mouseTrackDiv.style.display = "block"; } } let noFeature = true; if (GT.map.hasFeatureAtPixel(mousePosition)) { let features = GT.map.getFeaturesAtPixel(mousePosition); if (features != null) { for (let index in features) { if (!(features[index].A.prop in GT.hoverFunctors)) continue; if (GT.lastHover.feature) { if (features[index] != GT.lastHover.feature) { GT.lastHover.functor.out(GT.lastHover.feature); GT.lastHover.feature = null; } else { // feature is still up. GT.hoverFunctors[features[index].A.prop].move(features[index]); noFeature = false; break; } } if (GT.lastHover.feature == null) { if (GT.hoverFunctors[features[index].A.prop].hover(features[index], true)) { // feature was displayed. GT.lastHover.feature = features[index]; GT.lastHover.functor = GT.hoverFunctors[features[index].A.prop]; noFeature = false; break; } } } } } if (noFeature && GT.lastHover.feature) { GT.lastHover.functor.out(GT.lastHover.feature); GT.lastHover.feature = null; } }); mapDiv.addEventListener("mouseleave", mapLoseFocus, false); mapDiv.addEventListener("contextmenu", function (event) { event.preventDefault(); }); GT.map.on("pointerdown", function (event) { var shouldReturn = false; var features = GT.map.getFeaturesAtPixel(event.pixel); if (features != null) { features = features.reverse(); var finalGridFeature = null; for (var index in features) { if (!(features[index].A.prop in GT.hoverFunctors)) continue; if (features[index].size == 6) { noFeature = false; finalGridFeature = features[index]; } if (features[index].size == 4 && finalGridFeature == null) { noFeature = false; finalGridFeature = features[index]; } if (features[index].size == 1) { leftClickGtFlag(features[index]); shouldReturn = true; } if (features[index].size == 22) { leftClickPota(features[index].key); shouldReturn = true; } } if (finalGridFeature) { onRightClickGridSquare(finalGridFeature); shouldReturn = true; } } if (event.activePointers[0].buttons == 1 && event.activePointers[0].ctrlKey == true) { var LL = ol.proj.toLonLat(event.coordinate); var info = {}; info.callObj = {}; info.callObj.distance = 1; // We just need the heading, but distance makes it valid info.callObj.heading = parseInt(MyCircle.bearing(GT.myLat, GT.myLon, LL[1], LL[0])); aimRotator(info); } if (shouldReturn) return true; if (event.activePointers[0].buttons == 2 && GT.currentOverlay == 0) { mouseDownGrid(ol.proj.toLonLat(event.coordinate)); return true; } }); GT.map.on("pointerup", function (event) { mouseUpGrid(); if (GT.mapSettings.mouseOver == false) { mouseOutOfDataItem(); } }); document.getElementById("menuDiv").style.display = "block"; dayNight.init(GT.map); if (GT.appSettings.earthImgSrc == 1) { dayNight.hide(); } else { GT.nightTime = dayNight.show(); } moonLayer.init(GT.map); if (GT.appSettings.moonTrack == 1) { moonLayer.show(); } else { moonLayer.hide(); } GT.tileLayer.setOpacity(Number(GT.mapSettings.loudness)); requestAnimationFrame(animatePaths); nightMapEnable.checked = GT.mapSettings.nightMapEnable; changeNightMapEnable(nightMapEnable); } function changeNightMapEnable(check) { if (check.checked) { nightMapTd.style.display = "inline-table"; spotNightPathColorDiv.style.display = "inline-block"; GT.mapSettings.nightMapEnable = true; GT.nightTime = dayNight.refresh(); } else { nightMapTd.style.display = "none"; spotNightPathColorDiv.style.display = "none"; GT.mapSettings.nightMapEnable = false; } changeMapLayer(); redrawSpots(); saveMapSettings(); } GT.lasttimezone = null; GT.nexradInterval = null; GT.nexradEnable = 0; function createNexRad() { var layerSource = new ol.source.TileWMS({ url: "http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0q.cgi", params: { LAYERS: "nexrad-n0q" } }); var layerVector = new ol.layer.Tile({ source: layerSource, visible: true, zIndex: 900 }); layerVector.set("name", "radar"); return layerVector; } function toggleNexrad() { GT.nexradEnable ^= 1; if (GT.nexradEnable == 1) { if (GT.Nexrad != null) { GT.map.removeLayer(GT.Nexrad); } GT.Nexrad = createNexRad(); GT.map.addLayer(GT.Nexrad); if (GT.nexradInterval == null) { GT.nexradInterval = nodeTimers.setInterval(nexradRefresh, 600000); } } else { if (GT.nexradInterval != null) { nodeTimers.clearInterval(GT.nexradInterval); GT.nexradInterval = null; } if (GT.Nexrad) { GT.map.removeLayer(GT.Nexrad); GT.Nexrad = null; } } GT.mapSettings.usNexrad = GT.nexradEnable == 1; radarImg.style.filter = GT.mapSettings.usNexrad ? "" : "grayscale(1)"; saveMapSettings(); } function nexradRefresh() { if (GT.Nexrad != null) { GT.Nexrad.getSource().updateParams({ ol3_salt: Math.random() }); GT.Nexrad.getSource().refresh(); } } function collapseMenu(shouldCollapse) { if (shouldCollapse == true) { GT.menuShowing = false; mapDiv.className = "mapDivStart"; menuDiv.className = "menuDivStart"; LegendDiv.className = "legendDivStart"; chevronDiv.className = "chevronDivEnd"; } else { GT.menuShowing = true; chevronDiv.className = "chevronDivStart"; displayTime(); } GT.map.updateSize(); } function mapLoseFocus() { if (GT.lastHover.feature) { GT.lastHover.functor.out(GT.lastHover.feature); GT.lastHover.feature = null; } } function lineString(points) { var thing = new ol.geom.LineString(points); var rect = new ol.Feature({ geometry: thing, prop: "lineString" }); return rect; } function rectangle(bounds, options) { var thing = new ol.geom.Polygon([ [ ol.proj.fromLonLat([bounds[0][0], bounds[0][1]]), ol.proj.fromLonLat([bounds[0][0], bounds[1][1]]), ol.proj.fromLonLat([bounds[1][0], bounds[1][1]]), ol.proj.fromLonLat([bounds[1][0], bounds[0][1]]) ] ]); var rect = new ol.Feature({ prop: "grid", geometry: thing }); return rect; } function triangle(bounds, topLeft) { var thing = null; if (topLeft) { thing = new ol.geom.Polygon([ [ ol.proj.fromLonLat([bounds[0][0], bounds[0][1]]), ol.proj.fromLonLat([bounds[0][0], bounds[1][1]]), ol.proj.fromLonLat([bounds[1][0], bounds[1][1]]), ol.proj.fromLonLat([bounds[0][0], bounds[0][1]]) ] ]); } else { thing = new ol.geom.Polygon([ [ ol.proj.fromLonLat([bounds[0][0], bounds[0][1]]), ol.proj.fromLonLat([bounds[1][0], bounds[1][1]]), ol.proj.fromLonLat([bounds[1][0], bounds[0][1]]), ol.proj.fromLonLat([bounds[0][0], bounds[0][1]]) ] ]); } var rect = new ol.Feature({ prop: "grid", geometry: thing }); return rect; } function triangleToGrid(iQTH, feature) { var LL = squareToLatLong(iQTH); var bounds = [ [LL.lo1, LL.la1], [LL.lo2, LL.la2] ]; var thing = new ol.geom.Polygon([ [ ol.proj.fromLonLat([bounds[0][0], bounds[0][1]]), ol.proj.fromLonLat([bounds[0][0], bounds[1][1]]), ol.proj.fromLonLat([bounds[1][0], bounds[1][1]]), ol.proj.fromLonLat([bounds[1][0], bounds[0][1]]), ol.proj.fromLonLat([bounds[0][0], bounds[0][1]]) ] ]); feature.setGeometry(thing); } function gridToTriangle(iQTH, feature, topLeft) { var LL = squareToLatLong(iQTH); var bounds = [ [LL.lo1, LL.la1], [LL.lo2, LL.la2] ]; var thing = null; if (topLeft) { thing = new ol.geom.Polygon([ [ ol.proj.fromLonLat([bounds[0][0], bounds[0][1]]), ol.proj.fromLonLat([bounds[0][0], bounds[1][1]]), ol.proj.fromLonLat([bounds[1][0], bounds[1][1]]), ol.proj.fromLonLat([bounds[0][0], bounds[0][1]]) ] ]); } else { thing = new ol.geom.Polygon([ [ ol.proj.fromLonLat([bounds[0][0], bounds[0][1]]), ol.proj.fromLonLat([bounds[1][0], bounds[1][1]]), ol.proj.fromLonLat([bounds[1][0], bounds[0][1]]), ol.proj.fromLonLat([bounds[0][0], bounds[0][1]]) ] ]); } feature.setGeometry(thing); } function liveHash(call, band, mode) { return call + band + mode; } function setHomeGridsquare() { GT.appSettings.centerGridsquare = GT.appSettings.myGrid; if (GT.appSettings.centerGridsquare.length > 0) { homeQTHInput.value = GT.appSettings.centerGridsquare; } var hash = GT.appSettings.myCall; var rect = qthToBox( GT.appSettings.myGrid, GT.appSettings.myCall, false, true, "", GT.appSettings.myBand, null, hash ); if (typeof rect != "undefined" && rect != null) { var push = false; if (!(hash in GT.liveCallsigns)) { newCallsign = {}; push = true; } else newCallsign = GT.liveCallsigns[hash]; newCallsign.DEcall = GT.appSettings.myCall; newCallsign.grid = GT.appSettings.myGrid; newCallsign.wspr = null; newCallsign.msg = GT.appSettings.myGrid; newCallsign.RSTsent = "-"; newCallsign.RSTrecv = "-"; newCallsign.time = timeNowSec(); newCallsign.delta = -1; newCallsign.DXcall = "Self"; newCallsign.rect = rect; newCallsign.mode = GT.appSettings.myMode; newCallsign.band = GT.appSettings.myBand; newCallsign.worked = false; newCallsign.confirmed = false; newCallsign.state = null; newCallsign.zipcode = null; newCallsign.cnty = null; newCallsign.qual = false; newCallsign.instance = null; newCallsign.alerted = false; newCallsign.shouldAlert = false; GT.myDXCC = newCallsign.dxcc = callsignToDxcc(GT.appSettings.myCall); newCallsign.locked = true; if (push) GT.liveCallsigns[hash] = newCallsign; } } GT.transmitFlightPath = null; function haltAllTx(allTx = false) { for (var instance in GT.instances) { if (instance != GT.activeInstance || allTx == true) { var responseArray = Buffer.alloc(1024); var length = 0; var port = GT.instances[instance].remote.port; var address = GT.instances[instance].remote.address; length = encodeQUINT32(responseArray, length, 0xadbccbda); length = encodeQUINT32(responseArray, length, 2); length = encodeQUINT32(responseArray, length, 8); length = encodeQUTF8(responseArray, length, instance); length = encodeQBOOL(responseArray, length, 0); responseArray = responseArray.slice(0, length); wsjtUdpMessage(responseArray, responseArray.length, port, address); } } } function initiateQso(thisCall) { if (thisCall in GT.callRoster && GT.callRoster[thisCall].message.instance in GT.instances) { if (GT.mapSettings.focusRig && GT.activeInstance != GT.callRoster[thisCall].message.instance) { activeRig(GT.callRoster[thisCall].message.instance); } if (GT.mapSettings.haltAllOnTx) { haltAllTx(); } var newMessage = GT.callRoster[thisCall].message; var responseArray = Buffer.alloc(1024); var length = 0; var instance = GT.callRoster[thisCall].message.instance; var port = GT.instances[instance].remote.port; var address = GT.instances[instance].remote.address; length = encodeQUINT32(responseArray, length, newMessage.magic_key); length = encodeQUINT32(responseArray, length, newMessage.schema_number); length = encodeQUINT32(responseArray, length, 4); length = encodeQUTF8(responseArray, length, newMessage.Id); length = encodeQUINT32(responseArray, length, newMessage.TM); length = encodeQINT32(responseArray, length, newMessage.SR); length = encodeQDOUBLE(responseArray, length, newMessage.DT); length = encodeQUINT32(responseArray, length, newMessage.DF); length = encodeQUTF8(responseArray, length, newMessage.MO); length = encodeQUTF8(responseArray, length, newMessage.Msg); length = encodeQBOOL(responseArray, length, newMessage.LC); length = encodeQBOOL(responseArray, length, 0); responseArray = responseArray.slice(0, length); wsjtUdpMessage(responseArray, responseArray.length, port, address); } } function spotLookupAndSetCall(spot) { var call = GT.receptionReports.spots[spot].call; var grid = GT.receptionReports.spots[spot].grid; var band = GT.receptionReports.spots[spot].band; var mode = GT.receptionReports.spots[spot].mode; for (var instance in GT.instances) { if (GT.instances[instance].valid && GT.instances[instance].status.Band == band && GT.instances[instance].status.MO == mode) { setCallAndGrid(call, grid, instance); return; } } setCallAndGrid(call, grid, null); } function setCallAndGrid(callsign, grid, instance = null, genMessages = true) { var thisInstance = null; var port; var address; if (instance != null) { if (instance in GT.instances) { thisInstance = GT.instances[instance].status; port = GT.instances[instance].remote.port; address = GT.instances[instance].remote.address; } } else { if (GT.instances[GT.activeInstance].valid) { thisInstance = GT.instances[GT.activeInstance].status; port = GT.instances[GT.activeInstance].remote.port; address = GT.instances[GT.activeInstance].remote.address; } } if (thisInstance && (thisInstance.TxEnabled == 0 || genMessages == false)) { var responseArray = Buffer.alloc(1024); var length = 0; length = encodeQUINT32(responseArray, length, thisInstance.magic_key); length = encodeQUINT32(responseArray, length, thisInstance.schema_number); length = encodeQUINT32(responseArray, length, 15); length = encodeQUTF8(responseArray, length, thisInstance.Id); length = encodeQUTF8(responseArray, length, thisInstance.MO); length = encodeQUINT32(responseArray, length, thisInstance.FreqTol); length = encodeQUTF8(responseArray, length, thisInstance.Submode); length = encodeQBOOL(responseArray, length, thisInstance.Fastmode); length = encodeQUINT32(responseArray, length, thisInstance.TRP); length = encodeQUINT32(responseArray, length, thisInstance.RxDF); if (genMessages == true) { length = encodeQUTF8(responseArray, length, callsign); var hash = liveHash(callsign, thisInstance.Band, thisInstance.MO); if (hash in GT.liveCallsigns && GT.liveCallsigns[hash].grid.length > 1) { grid = GT.liveCallsigns[hash].grid; } if (grid.length == 0) grid = " "; length = encodeQUTF8(responseArray, length, grid); length = encodeQBOOL(responseArray, length, 1); responseArray = responseArray.slice(0, length); wsjtUdpMessage(responseArray, responseArray.length, port, address); addLastTraffic("Generated Msgs"); } else { // Callsign length = encodeQUTF8(responseArray, length, " "); // Grid length = encodeQUTF8(responseArray, length, " "); length = encodeQBOOL(responseArray, length, 1); responseArray = responseArray.slice(0, length); wsjtUdpMessage(responseArray, responseArray.length, port, address); responseArray = Buffer.alloc(1024); length = 0; length = encodeQUINT32(responseArray, length, thisInstance.magic_key); length = encodeQUINT32(responseArray, length, thisInstance.schema_number); length = encodeQUINT32(responseArray, length, 9); length = encodeQUTF8(responseArray, length, thisInstance.Id); length = encodeQUTF8(responseArray, length, ""); length = encodeQBOOL(responseArray, length, 0); responseArray = responseArray.slice(0, length); wsjtUdpMessage(responseArray, responseArray.length, port, address); } } if (thisInstance && thisInstance.TxEnabled == 1 && genMessages == true) { addLastTraffic("Transmit Enabled!
Generate Msgs Aborted"); } } GT.wsjtHandlers = { 0: handleWsjtxNotSupported, 1: handleWsjtxStatus, 2: handleWsjtxDecode, 3: handleWsjtxClear, 4: handleWsjtxNotSupported, 5: handleWsjtxQSO, 6: handleWsjtxClose, 7: handleWsjtxNotSupported, 8: handleWsjtxNotSupported, 9: handleWsjtxNotSupported, 10: handleWsjtxWSPR, 11: handleWsjtxNotSupported, 12: handleWsjtxADIF }; GT.oldQSOTimer = null; function handleWsjtxADIF(newMessage) { if (GT.oldQSOTimer) { nodeTimers.clearTimeout(GT.oldQSOTimer); GT.oldQSOTimer = null; } sendToLogger(newMessage.ADIF); } function handleWsjtxQSO(newMessage) { if (GT.oldQSOTimer) { nodeTimers.clearTimeout(GT.oldQSOTimer); GT.oldQSOTimer = null; } GT.oldStyleLogMessage = Object.assign({}, newMessage); GT.oldQSOTimer = nodeTimers.setTimeout(oldSendToLogger, 3000); } function handleWsjtxNotSupported(newMessage) { } GT.lastBand = ""; GT.lastMode = ""; GT.lastRawGrid = "AA00AA"; GT.weAreDecoding = false; GT.localDXcall = ""; GT.countIndex = 0; GT.lastCountIndex = 0; function rigChange(up) { if (GT.activeInstance == "") return; var targetInstance = 0; if (up) { targetInstance = GT.instances[GT.activeInstance].intId + 1; } else { targetInstance = GT.instances[GT.activeInstance].intId - 1; if (targetInstance < 0) targetInstance = GT.instancesIndex.length - 1; } targetInstance %= GT.instancesIndex.length; setRig(targetInstance); } function setRig(instanceId) { if (GT.instances[GT.instancesIndex[instanceId]].valid) { if (GT.lastMapView != null) { GT.mapView.animate({ zoom: GT.lastMapView.zoom, duration: 100 }); GT.mapView.animate({ center: GT.lastMapView.LoLa, duration: 100 }); GT.lastMapView = null; } GT.activeInstance = GT.instancesIndex[instanceId]; handleWsjtxStatus(GT.instances[GT.activeInstance].status); handleClosed(GT.instances[GT.activeInstance].status); } } function activeRig(instance) { if (GT.instances[instance].valid) { if (GT.lastMapView != null) { GT.mapView.animate({ zoom: GT.lastMapView.zoom, duration: 100 }); GT.mapView.animate({ center: GT.lastMapView.LoLa, duration: 100 }); GT.lastMapView = null; } GT.activeInstance = instance; handleWsjtxStatus(GT.instances[GT.activeInstance].status); handleClosed(GT.instances[GT.activeInstance].status); } } GT.lastTransmitCallsign = {}; GT.lastStatusCallsign = {}; GT.lastTxMessage = null; function handleWsjtxStatus(newMessage) { if (GT.ignoreMessages == 1) return; if (GT.rosterInitialized) { try { GT.callRosterWindowHandle.window.processStatus(newMessage); } catch (e) { console.error(e); } } if (GT.activeInstance == "") { GT.activeInstance = newMessage.instance; } if (Object.keys(GT.instances).length > 1) { rigWrap.style.display = "block"; } else { rigWrap.style.display = "none"; } var DXcall = newMessage.DXcall.trim(); if (DXcall.length > 1) { if (!(newMessage.instance in GT.lastTransmitCallsign)) { GT.lastTransmitCallsign[newMessage.instance] = ""; } if (!(newMessage.instance in GT.lastStatusCallsign)) { GT.lastStatusCallsign[newMessage.instance] = ""; } if (lookupOnTx.checked == true && newMessage.Transmitting == 1 && GT.lastTransmitCallsign[newMessage.instance] != DXcall) { openLookupWindow(true); GT.lastTransmitCallsign[newMessage.instance] = DXcall; } if (GT.lastStatusCallsign[newMessage.instance] != DXcall) { GT.lastStatusCallsign[newMessage.instance] = DXcall; lookupCallsign(DXcall, newMessage.DXgrid.trim()); } } if (GT.rosterInitialized && GT.callRosterWindowHandle.window.CR.rosterSettings.clearRosterOnBandChange && GT.instances[newMessage.instance].oldStatus) { if (GT.instances[newMessage.instance].oldStatus.Band != newMessage.Band || GT.instances[newMessage.instance].oldStatus.MO != newMessage.MO) { for (const call in GT.callRoster) { if (GT.callRoster[call].callObj.instance == newMessage.instance) { delete GT.callRoster[call]; } } if (GT.activeInstance == newMessage.instance) { goProcessRoster(); } } } if (GT.activeInstance == newMessage.instance) { var sp = newMessage.Id.split(" - "); rigDiv.innerHTML = sp[sp.length - 1].substring(0, 18); var bandChange = false; var modeChange = false; wsjtxMode.innerHTML = "" + newMessage.MO + ""; GT.appSettings.myMode = newMessage.MO; GT.appSettings.myBand = newMessage.Band; if (GT.lastBand != GT.appSettings.myBand) { GT.lastBand = GT.appSettings.myBand; bandChange = true; if (GT.pskBandActivityTimerHandle != null) { nodeTimers.clearInterval(GT.pskBandActivityTimerHandle); GT.pskBandActivityTimerHandle = null; } } if (GT.lastMode != GT.appSettings.myMode) { GT.lastMode = GT.appSettings.myMode; modeChange = true; if (GT.pskBandActivityTimerHandle != null) { nodeTimers.clearInterval(GT.pskBandActivityTimerHandle); GT.pskBandActivityTimerHandle = null; } } if (GT.pskBandActivityTimerHandle == null) pskGetBandActivity(); if (bandChange || modeChange || GT.startingUp) { removePaths(); goProcessRoster(); redrawGrids(); redrawSpots(); redrawParks(); redrawPins(); var msg = "" + GT.appSettings.myBand + " / " + GT.appSettings.myMode + ""; addLastTraffic(msg); ackAlerts(); updateChatWindow(); oamsBandActivityCheck(); GT.gtLiveStatusUpdate = true; GT.startingUp = false; } GT.appSettings.myRawFreq = newMessage.Frequency; frequency.innerHTML = "" + formatMhz(Number(newMessage.Frequency / 1000), 3, 3) + " Hz (" + GT.appSettings.myBand + ")"; GT.appSettings.myRawCall = newMessage.DEcall.trim(); GT.appSettings.myRawGrid = newMessage.DEgrid.trim().substr(0, 6); var LL = squareToCenter(GT.appSettings.myRawGrid); GT.mapSettings.latitude = GT.myLat = LL.a; GT.mapSettings.longitude = GT.myLon = LL.o; if (GT.appSettings.myRawGrid != GT.lastRawGrid) { GT.lastRawGrid = GT.appSettings.myRawGrid; } dxCallBoxDiv.className = "DXCallBox"; var hash = DXcall + GT.appSettings.myBand + GT.appSettings.myMode; if (hash in GT.tracker.worked.call) { dxCallBoxDiv.className = "DXCallBoxWorked"; } if (hash in GT.tracker.confirmed.call) { dxCallBoxDiv.className = "DXCallBoxConfirmed"; } if (GT.appSettings.clearOnCQ && newMessage.Transmitting == 1 && newMessage.TxMessage && GT.lastTxMessage != newMessage.TxMessage) { GT.lastTxMessage = newMessage.TxMessage; if (newMessage.TxMessage.substring(0, 2) == "CQ" && DXcall.length > 0) { setCallAndGrid("", "", newMessage.instance, false); DXcall = ""; newMessage.DXgrid = ""; } } GT.localDXcall = DXcall; localDXcall.innerHTML = formatCallsign(DXcall); if (localDXcall.innerHTML.length == 0) { localDXcall.innerHTML = "-"; GT.localDXcall = ""; } localDXGrid.innerHTML = GT.myDXGrid = newMessage.DXgrid.trim(); if (GT.myDXGrid.length == 0 && hash in GT.liveCallsigns) { localDXGrid.innerHTML = GT.myDXGrid = GT.liveCallsigns[hash].grid.substr(0, 4); } if (localDXGrid.innerHTML.length == 0) { localDXGrid.innerHTML = "-"; localDXDistance.innerHTML = " "; localDXAzimuth.innerHTML = " "; } else { var LL = squareToCenter(GT.myDXGrid); localDXDistance.innerHTML = parseInt(MyCircle.distance(GT.myLat, GT.myLon, LL.a, LL.o, distanceUnit.value) * MyCircle.validateRadius(distanceUnit.value)) + distanceUnit.value.toLowerCase(); localDXAzimuth.innerHTML = parseInt(MyCircle.bearing(GT.myLat, GT.myLon, LL.a, LL.o)) + "°"; } if (localDXcall.innerHTML != "-") { localDXReport.innerHTML = formatSignalReport(Number(newMessage.Report.trim())); if (DXcall.length > 0) { localDXCountry.innerHTML = GT.dxccToAltName[callsignToDxcc(DXcall)]; } else { localDXCountry.innerHTML = " "; } } else { localDXReport.innerHTML = localDXCountry.innerHTML = ""; } GT.appSettings.myCall = newMessage.DEcall; GT.appSettings.myGrid = newMessage.DEgrid.trim().substr(0, 6); if (GT.appSettings.myGrid.length > 0) setHomeGridsquare(); if (GT.appSettings.myGrid.length > 0) GT.appSettings.centerGridsquare = GT.appSettings.myGrid; if (newMessage.Decoding == 1) { // Decoding dimGridsquare(); fadePaths(); txrxdec.style.backgroundColor = "Blue"; txrxdec.style.borderColor = "Cyan"; txrxdec.innerHTML = "DECODE"; GT.countIndex++; GT.weAreDecoding = true; } else { GT.weAreDecoding = false; if (GT.countIndex != GT.lastCountIndex) { GT.lastCountIndex = GT.countIndex; updateCountStats(); if (bandChange || modeChange) reloadInfo(bandChange || modeChange); var worker = ""; worker += "
"; worker += ""; worker += ""; worker += ""; worker += GT.lastMessages.join(""); worker += "
Last " + GT.lastMessages.length + " Decoded Messages
TimedBDTFreqModeMessageDXCC
"; setStatsDiv("decodeLastListDiv", worker); setStatsDivHeight("decodeLastListDiv", getStatsWindowHeight() + 26 + "px"); if (GT.appSettings.gtShareEnable == true && Object.keys(GT.spotCollector).length > 0) { gtChatSendSpots(GT.spotCollector, GT.spotDetailsCollector); GT.spotCollector = {}; GT.spotDetailsCollector = {}; } } txrxdec.style.backgroundColor = "Green"; txrxdec.style.borderColor = "GreenYellow"; txrxdec.innerHTML = "RECEIVE"; } if (newMessage.TxEnabled) { if (GT.mapSettings.fitQRZ && (GT.spotView == 0 || GT.receptionSettings.mergeSpots)) { if (GT.lastMapView == null) { GT.lastMapView = {}; GT.lastMapView.LoLa = GT.mapView.getCenter(); GT.lastMapView.zoom = GT.mapView.getZoom(); } if (GT.myDXGrid.length > 0) { fitViewBetweenPoints([getPoint(GT.appSettings.myRawGrid), getPoint(GT.myDXGrid)]); } else if (GT.mapSettings.qrzDxccFallback && DXcall.length > 0 && callsignToDxcc(DXcall) > 0) { var dxcc = callsignToDxcc(DXcall); var Lat = GT.dxccInfo[dxcc].lat; var Lon = GT.dxccInfo[dxcc].lon; fitViewBetweenPoints([getPoint(GT.appSettings.myRawGrid), ol.proj.fromLonLat([Lon, Lat])], 15); } } } else { if (GT.lastMapView != null) { GT.mapView.animate({ zoom: GT.lastMapView.zoom, duration: 1200 }); GT.mapView.animate({ center: GT.lastMapView.LoLa, duration: 1200 }); GT.lastMapView = null; } } if (newMessage.Transmitting == 0) { // Not Transmitting GT.lastTxMessage = null; GT.layerSources.transmit.clear(); GT.transmitFlightPath = null; } else { GT.lastTrasmissionTimeSec = GT.timeNow; txrxdec.style.backgroundColor = "Red"; txrxdec.style.borderColor = "Orange"; txrxdec.innerHTML = "TRANSMIT"; GT.layerSources.transmit.clear(); GT.transmitFlightPath = null; if (qrzPathWidthValue.value != 0 && GT.appSettings.gridViewMode != 2 && validateGridFromString(GT.appSettings.myRawGrid)) { var strokeColor = getQrzPathColor(); var strokeWeight = qrzPathWidthValue.value; var LL = squareToCenter(GT.appSettings.myRawGrid); var fromPoint = ol.proj.fromLonLat([LL.o, LL.a]); var toPoint = null; if (validateGridFromString(GT.myDXGrid)) { LL = squareToCenter(GT.myDXGrid); toPoint = ol.proj.fromLonLat([LL.o, LL.a]); } else if (GT.mapSettings.qrzDxccFallback && DXcall.length > 0 && callsignToDxcc(DXcall) > 0) { var dxcc = callsignToDxcc(DXcall); toPoint = ol.proj.fromLonLat([GT.dxccInfo[dxcc].lon, GT.dxccInfo[dxcc].lat]); var locality = GT.dxccInfo[dxcc].geo; if (locality == "deleted") locality = null; if (locality != null) { var feature = shapeFeature("qrz", locality, "qrz", "#FFFF0010", "#FF0000FF", 1.0); GT.layerSources.transmit.addFeature(feature); } } if (toPoint) { try { GT.transmitFlightPath = flightFeature( [fromPoint, toPoint], { weight: strokeWeight, color: strokeColor, steps: 75, zIndex: 90 }, "transmit", true ); } catch (err) { console.error("Unexpected error inside handleWsjtxStatus", err) } } } GT.weAreDecoding = false; } } if (newMessage.Decoding == 0) { goProcessRoster(); processClassicAlerts(); } } function reportDecodes() { if (Object.keys(GT.decodeCollector).length > 0) { gtChatSendDecodes(GT.decodeCollector); GT.decodeCollector = {}; } } GT.lastMapView = null; function drawTraffic() { while (GT.lastTraffic.length > 60) GT.lastTraffic.pop(); var worker = GT.lastTraffic.join("
"); worker = worker.split("80%'>
").join("80%'>"); if (GT.localDXcall.length > 1) { worker = worker .split(GT.localDXcall) .join("" + GT.localDXcall + ""); } if (GT.appSettings.myRawCall.length > 1) { worker = worker .split(GT.appSettings.myRawCall) .join("" + GT.appSettings.myRawCall + ""); } trafficDiv.innerHTML = worker; } function getPoint(grid) { var LL = squareToCenter(grid); return ol.proj.fromLonLat([LL.o, LL.a]); } function fitViewBetweenPoints(points, maxZoom = 20) { var start = ol.proj.toLonLat(points[0]); var end = ol.proj.toLonLat(points[1]); if (Math.abs(start[0] - end[0]) > 180) { // Wrapped if (end[0] < start[0]) { start[0] -= 360; } else { end[0] -= 360; } } start = ol.proj.fromLonLat(start); end = ol.proj.fromLonLat(end); var line = new ol.geom.LineString([start, end]); var feature = new ol.Feature({ geometry: line }); var extent = feature.getGeometry().getExtent(); GT.mapView.fit(extent, { duration: 500, maxZoom: maxZoom, padding: [75, 75, 75, 75] }); } GT.spotCollector = {}; GT.spotDetailsCollector = {}; GT.decodeCollector = {}; function handleWsjtxDecode(newMessage) { // eg: "YK7DAQ RR73; 3O5GAS +14" if (newMessage.Msg.indexOf(" RR73; ") > -1) { let parts = newMessage.Msg.split("RR73; "); // parts[0] is "YK7DAQ " includes space // parts[1] is "3O5GAS +14" no leading space, a useable message let caller = parts[1].split(" ")[1]; // caller is "" let first = parts[0] + caller + " RR73"; // first is "YK7DAQ RR73" finalWsjtxDecode(newMessage, true, parts[1]); // Send the RR73 last as it's more important to us finalWsjtxDecode(newMessage, true, first); } else { // A classic mode 0 decoded messages finalWsjtxDecode(newMessage); } } function finalWsjtxDecode(newMessage, isFox = false, foxMessage) { var didAlert = false; var didCustomAlert = false; var validQTH = false; var CQ = false; var RR73 = false; var msgDEcallsign = ""; var msgDXcallsign = ""; var theirQTH = ""; var countryName = ""; var newF; if (newMessage.OF > 0) { newF = formatMhz(Number((newMessage.OF + newMessage.DF) / 1000), 3, 3); } else { newF = newMessage.DF; } var theTimeStamp = timeNowSec() - (timeNowSec() % 86400) + parseInt(newMessage.TM / 1000); var theMessage = (isFox == true ? foxMessage : newMessage.Msg); // Break up the decoded message var decodeWords = theMessage.split(" ").slice(0, 5); while (decodeWords[decodeWords.length - 1] == "") decodeWords.pop(); if (decodeWords.length > 1) { if (theMessage.indexOf("<") != -1) { for (const i in decodeWords) { decodeWords[i] = decodeWords[i].replace("<", "").replace(">", ""); if (decodeWords[i].indexOf("...") != -1) { if (i != 0) { // simply ignore <...> , we don't know who they are and we aint talking to them. return; } else { decodeWords[0] = "UNKNOWN"; } } } } var rect = null; // Grab the last word in the decoded message var qth = decodeWords[decodeWords.length - 1].trim(); if (qth.length == 4) { var LETTERS = qth.substr(0, 2); var NUMBERS = qth.substr(2, 2); if (/^[A-R]+$/.test(LETTERS) && /^[0-9]+$/.test(NUMBERS)) { theirQTH = LETTERS + NUMBERS; if (theirQTH != "RR73") { validQTH = true; } else { theirQTH = ""; validQTH = false; } } } if (validQTH) msgDEcallsign = decodeWords[decodeWords.length - 2].trim(); if (validQTH == false && decodeWords.length == 3) { msgDEcallsign = decodeWords[decodeWords.length - 2].trim(); } if (validQTH == false && decodeWords.length == 2) { msgDEcallsign = decodeWords[decodeWords.length - 1].trim(); } if (decodeWords[0] == "CQ") { CQ = true; msgDXcallsign = "CQ"; } if (decodeWords.length == 4 && CQ == true) { msgDXcallsign += " " + decodeWords[1]; } if (decodeWords.length == 3 && CQ == true && validQTH == false) { msgDXcallsign += " " + decodeWords[1]; } if (decodeWords.length < 4 && CQ == false) { msgDXcallsign = decodeWords[0]; } if (decodeWords.length >= 3 && CQ == true && validQTH == false) { if (validateNumAndLetter(decodeWords[decodeWords.length - 1].trim())) { msgDEcallsign = decodeWords[decodeWords.length - 1].trim(); } else msgDEcallsign = decodeWords[decodeWords.length - 2].trim(); } if (decodeWords.length >= 4 && CQ == false) { msgDXcallsign = decodeWords[0]; msgDEcallsign = decodeWords[1]; } if (decodeWords[2] == "RR73") { RR73 = true; } var callsign = null; var hash = msgDEcallsign + newMessage.OB + newMessage.OM; if (hash in GT.liveCallsigns) callsign = GT.liveCallsigns[hash]; var canPath = false; if ( (GT.appSettings.gtBandFilter.length == 0 || (GT.appSettings.gtBandFilter == "auto" && newMessage.OB == GT.appSettings.myBand) || newMessage.OB == GT.appSettings.gtBandFilter) && (GT.appSettings.gtModeFilter.length == 0 || (GT.appSettings.gtModeFilter == "auto" && newMessage.OM == GT.appSettings.myMode) || newMessage.OM == GT.appSettings.gtModeFilter || GT.appSettings.gtModeFilter == "Digital") ) { rect = qthToBox(theirQTH, msgDEcallsign, CQ, false, msgDXcallsign, newMessage.OB, null, hash); canPath = true; } if (rect != null && theirQTH == "") { theirQTH = rect.qth; } if (rect) { GT.liveGrids[theirQTH].age = GT.timeNow; } if (callsign == null) { let newCallsign = {}; newCallsign.DEcall = msgDEcallsign; newCallsign.grid = theirQTH; newCallsign.wspr = null; newCallsign.msg = newMessage.Msg; newCallsign.RSTsent = newMessage.SR; newCallsign.RSTrecv = "-"; newCallsign.time = theTimeStamp; newCallsign.life = newCallsign.age = timeNowSec(); newCallsign.delta = newMessage.DF; newCallsign.dt = newMessage.DT.toFixed(2); newCallsign.DXcall = msgDXcallsign.trim(); newCallsign.rect = rect; newCallsign.state = null; newCallsign.zipcode = null; newCallsign.worked = false; newCallsign.confirmed = false; newCallsign.qso = false; newCallsign.dxcc = callsignToDxcc(newCallsign.DEcall); newCallsign.px = null; newCallsign.pota = null; newCallsign.zone = null; newCallsign.vucc_grids = []; newCallsign.propMode = ""; newCallsign.digital = true; newCallsign.phone = false; newCallsign.IOTA = ""; newCallsign.satName = ""; newCallsign.hash = hash; if (newCallsign.dxcc != -1) { newCallsign.px = getWpx(newCallsign.DEcall); if (newCallsign.px) { newCallsign.zone = Number( newCallsign.px.charAt(newCallsign.px.length - 1) ); } newCallsign.cont = GT.dxccInfo[newCallsign.dxcc].continent; if (newCallsign.dxcc == 390 && newCallsign.zone == 1) { newCallsign.cont = "EU"; } } newCallsign.ituz = ituZoneFromCallsign(newCallsign.DEcall, newCallsign.dxcc); newCallsign.cqz = cqZoneFromCallsign(newCallsign.DEcall, newCallsign.dxcc); newCallsign.distance = 0; newCallsign.heading = 0; newCallsign.cnty = null; newCallsign.qual = false; getLookupCachedObject(msgDEcallsign, null, null, null, newCallsign); if (GT.callsignLookups.ulsUseEnable == true && isKnownCallsignDXCC(newCallsign.dxcc)) { lookupUsCallsign(newCallsign, false); } if (newCallsign.dxcc in GT.dxccCount) GT.dxccCount[newCallsign.dxcc]++; else GT.dxccCount[newCallsign.dxcc] = 1; newCallsign.alerted = false; newCallsign.shouldAlert = false; GT.liveCallsigns[hash] = newCallsign; callsign = newCallsign; } else { if (validQTH) { callsign.grid = theirQTH; if (rect != null && callsign.grid != rect.qth) { if ( (GT.appSettings.gtBandFilter.length == 0 || (GT.appSettings.gtBandFilter == "auto" && newMessage.OB == GT.appSettings.myBand) || newMessage.OB == GT.appSettings.gtBandFilter) && (GT.appSettings.gtModeFilter.length == 0 || (GT.appSettings.gtModeFilter == "auto" && newMessage.OM == GT.appSettings.myMode) || newMessage.OM == GT.appSettings.gtModeFilter || GT.appSettings.gtModeFilter == "Digital") ) { rect = qthToBox( theirQTH, msgDEcallsign, CQ, false, msgDXcallsign, newMessage.OB, null, hash ); canPath = true; } } } callsign.time = theTimeStamp; callsign.age = timeNowSec(); callsign.RSTsent = newMessage.SR; callsign.delta = newMessage.DF; callsign.DXcall = msgDXcallsign.trim(); callsign.msg = newMessage.Msg; callsign.rect = rect; callsign.dt = newMessage.DT.toFixed(2); } callsign.mode = newMessage.OM; callsign.band = newMessage.OB; callsign.instance = newMessage.instance; callsign.grid = callsign.grid.substr(0, 4); callsign.CQ = CQ; callsign.RR73 = RR73; callsign.UTC = toColonHMS(parseInt(newMessage.TM / 1000)); callsign.qrz = (msgDXcallsign == GT.appSettings.myCall); if (callsign.grid.length > 0 && callsign.distance == 0) { var LL = squareToCenter(callsign.grid); callsign.distance = MyCircle.distance(GT.myLat, GT.myLon, LL.a, LL.o, distanceUnit.value); callsign.heading = MyCircle.bearing(GT.myLat, GT.myLon, LL.a, LL.o); } if (GT.appSettings.potaEnabled == 1) { callsign.pota = null; if (callsign.DEcall in GT.pota.callSpots || callsign.DEcall in GT.pota.callSchedule) { var now = Date.now(); if (callsign.DEcall in GT.pota.callSpots) { if (GT.pota.callSpots[callsign.DEcall] in GT.pota.parkSpots && GT.pota.parkSpots[GT.pota.callSpots[callsign.DEcall]][callsign.DEcall].expire > now) { callsign.pota = GT.pota.callSpots[callsign.DEcall]; } } else if (callsign.DEcall in GT.pota.callSchedule) { for (var i in GT.pota.callSchedule[callsign.DEcall]) { if (now < GT.pota.callSchedule[callsign.DEcall][i].end && now >= GT.pota.callSchedule[callsign.DEcall][i].start) { callsign.pota = GT.pota.callSchedule[callsign.DEcall][i].id; break; } } } if (callsign.pota) { potaSpotFromDecode(callsign); } else if (CQ == true && msgDXcallsign == "CQ POTA") { callsign.pota = "?-????"; } } else if (CQ == true && msgDXcallsign == "CQ POTA") { callsign.pota = "?-????"; } } if (newMessage.NW) { didCustomAlert = processAlertMessage(decodeWords, theMessage.substr(0, 30).trim(), callsign.band, callsign.mode); didAlert = checkClassicAlerts(CQ, callsign, newMessage, msgDXcallsign); insertMessageInRoster(newMessage, msgDEcallsign, msgDXcallsign, callsign, hash); if (GT.mapSettings.trafficDecode && (didAlert == true || didCustomAlert == true)) { var traffic = htmlEntities(theMessage); if (didAlert == true) { traffic = "⚠️ " + traffic; } if (didCustomAlert == true) { traffic = traffic + " 🚩"; } GT.lastTraffic.unshift(traffic); GT.lastTraffic.unshift(userTimeString(null)); GT.lastTraffic.unshift("
"); drawTraffic(); lastMessageWasInfo = true; } if (GT.appSettings.gtSpotEnable == true && newMessage.OF > 0) { let freq = callsign.delta + newMessage.OF; if (callsign.DEcall in GT.gtCallsigns) { for (const cid in GT.gtCallsigns[callsign.DEcall]) { if (cid in GT.gtFlagPins && GT.gtFlagPins[cid].o == 1) { GT.spotCollector[cid] = callsign.RSTsent; GT.spotDetailsCollector[cid] = [freq, callsign.mode]; } } } freq = freq - (freq % k_frequencyBucket); GT.decodeCollector[freq] ??= 0; GT.decodeCollector[freq]++; } } if (callsign.dxcc != -1) countryName = GT.dxccToAltName[callsign.dxcc]; if (canPath == true) { if (callsign.DXcall.indexOf("CQ") < 0 && GT.appSettings.gridViewMode != 2) { // Nothing special, we know the callers grid if (callsign.grid != "") { // Our msgDEcallsign is not sending a CQ. // Let's see if we can locate who he's talking to in our known list var DEcallsign = null; if (callsign.DXcall + newMessage.OB + newMessage.OM in GT.liveCallsigns) { DEcallsign = GT.liveCallsigns[callsign.DXcall + newMessage.OB + newMessage.OM]; } else if (callsign.DXcall in GT.liveCallsigns) { DEcallsign = GT.liveCallsigns[callsign.DXcall]; } if (DEcallsign != null && DEcallsign.grid != "") { var strokeColor = getPathColor(); var strokeWeight = pathWidthValue.value; var flightPath = null; var isQRZ = false; if (msgDXcallsign == GT.appSettings.myCall) { strokeColor = getQrzPathColor(); strokeWeight = qrzPathWidthValue.value; isQRZ = true; } if (strokeWeight != 0) { var fromPoint = getPoint(callsign.grid); var toPoint = getPoint(DEcallsign.grid); try { flightPath = flightFeature( [fromPoint, toPoint], { weight: strokeWeight, color: strokeColor, steps: 75, zIndex: 90 }, "flight", true ); flightPath.age = GT.timeNow + GT.flightDuration; flightPath.isShapeFlight = 0; flightPath.isQRZ = isQRZ; GT.flightPaths.push(flightPath); } catch (err) { console.error("Unexpected error inside handleWsjtxDecode 1", err) } } } } else if (GT.mapSettings.qrzDxccFallback && msgDXcallsign == GT.appSettings.myCall && callsign.dxcc > 0) { // the caller is calling us, but they don't have a grid, so lookup the DXCC and show it var strokeColor = getQrzPathColor(); var strokeWeight = qrzPathWidthValue.value; var flightPath = null; var isQRZ = true; var DEcallsign = GT.liveCallsigns[GT.appSettings.myCall]; if (strokeWeight != 0) { var toPoint = getPoint(DEcallsign.grid); var Lat = GT.dxccInfo[callsign.dxcc].lat; var Lon = GT.dxccInfo[callsign.dxcc].lon; var fromPoint = ol.proj.fromLonLat([Lon, Lat]); try { flightPath = flightFeature( [fromPoint, toPoint], { weight: strokeWeight, color: strokeColor, steps: 75, zIndex: 90 }, "flight", true ); flightPath.age = GT.timeNow + GT.flightDuration; flightPath.isShapeFlight = 0; flightPath.isQRZ = isQRZ; GT.flightPaths.push(flightPath); } catch (err) { console.error("Unexpected error inside handleWsjtxDecode 2", err) } var feature = shapeFeature( "qrz", GT.dxccInfo[callsign.dxcc].geo, "qrz", "#FFFF0010", "#FF0000FF", 1.0 ); feature.age = GT.timeNow + GT.flightDuration; feature.isShapeFlight = 1; feature.isQRZ = isQRZ; GT.layerSources.flight.addFeature(feature); GT.flightPaths.push(feature); } } } else if (GT.mapSettings.CQhilite && msgDXcallsign.indexOf("CQ ") == 0 && callsign.grid != "" && GT.appSettings.gridViewMode != 2 && pathWidthValue.value != 0) { var CCd = msgDXcallsign.replace("CQ ", "").split(" ")[0]; if (CCd.length < 5 && !(CCd in GT.pathIgnore)) { var locality = null; // Direct lookup US states, Continents, possibly if (CCd in GT.replaceCQ) CCd = GT.replaceCQ[CCd]; if (CCd.length == 2 && CCd in GT.shapeData) { locality = GT.shapeData[CCd]; } else if (CCd.length == 3) { // maybe it's DEL, or WYO. check the first two letters if (CCd.substr(0, 2) in GT.shapeData) { locality = GT.shapeData[CCd.substr(0, 2)]; } } if (locality == null) { // Check the prefix for dxcc direct if (CCd in GT.prefixToMap) { locality = GT.dxccInfo[GT.prefixToMap[CCd]].geo; if (locality == "deleted") { locality = null; } } } if (locality != null) { var strokeColor = getPathColor(); var strokeWeight = pathWidthValue.value; var flightPath = null; var feature = shapeFeature( CCd, locality, CCd, "#00000000", "#FF0000C0", strokeWeight ); feature.age = GT.timeNow + GT.flightDuration; feature.isShapeFlight = 1; feature.isQRZ = false; GT.layerSources.flight.addFeature(feature); GT.flightPaths.push(feature); var fromPoint = getPoint(callsign.grid); var toPoint = ol.proj.fromLonLat(locality.properties.center); try { flightPath = flightFeature( [fromPoint, toPoint], { weight: strokeWeight, color: strokeColor, steps: 75, zIndex: 90 }, "flight", true ); flightPath.age = GT.timeNow + GT.flightDuration; flightPath.isShapeFlight = 0; flightPath.isQRZ = false; GT.flightPaths.push(flightPath); } catch (err) { console.error("Unexpected error inside handleWsjtxDecode 3", err) } } } } } } var bgColor = "black"; if (newMessage.LC > 0) bgColor = "#880000"; GT.lastMessages.unshift( "" + userTimeString(theTimeStamp * 1000) + "" + newMessage.SR + "" + newMessage.DT.toFixed(1) + "" + newF + "" + newMessage.MO + "" + htmlEntities(theMessage) + "" + countryName + "" ); while (GT.lastMessages.length > 100) GT.lastMessages.pop(); } function addLastTraffic(traffic) { GT.lastTraffic.unshift(traffic); GT.lastTraffic.unshift( "
" ); drawTraffic(); } function htmlEntities(str) { return String(str) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """); } function shapeFeature( key, geoJsonData, propname, fillColor, borderColor, borderWidth ) { var feature = new ol.format.GeoJSON({ geometryName: key }).readFeature(geoJsonData, { featureProjection: "EPSG:3857" }); var style = new ol.style.Style({ stroke: new ol.style.Stroke({ color: borderColor, width: borderWidth }), fill: new ol.style.Fill({ color: fillColor }) }); feature.setStyle(style); feature.set("prop", propname); feature.size = 2; return feature; } function handleWsjtxClear(newMessage) { for (var hash in GT.liveCallsigns) { if (GT.liveCallsigns[hash].instance == newMessage.instance || GT.liveCallsigns[hash].mode == GT.instances[newMessage.instance].status.MO) { delete GT.liveCallsigns[hash]; } } for (var call in GT.callRoster) { if (GT.callRoster[call].callObj.instance == newMessage.instance) { delete GT.callRoster[call]; } } redrawGrids(); redrawPins(); updateCountStats(); goProcessRoster(); } function goProcessRoster() { var now = timeNowSec(); for (const call in GT.callRoster) { if (now - GT.callRoster[call].callObj.age > 300) { GT.callRoster[call].callObj.alerted = false; GT.callRoster[call].callObj.shouldAlert = false; delete GT.callRoster[call]; continue; } } if (GT.rosterInitialized) { try { GT.callRosterWindowHandle.window.processRoster(GT.callRoster); } catch (e) { console.log("Call Roster exception"); console.log(e.message); } } } function handleClosed(newMessage) { if (GT.activeInstance == newMessage.Id && GT.instances[newMessage.Id].open == false) { txrxdec.style.backgroundColor = "Purple"; txrxdec.style.borderColor = "Purple"; var name = newMessage.Id.toUpperCase().split(" - "); var txt = name[name.length - 1]; txrxdec.innerHTML = txt + " Closed"; } } function handleWsjtxClose(newMessage) { updateCountStats(); GT.instances[newMessage.Id].open = false; handleClosed(newMessage); updateRosterInstances(); } function handleWsjtxWSPR(newMessage) { if (GT.ignoreMessages == 1) return; let callsign = newMessage.Callsign.replace("<", "").replace(">", "").trim(); addLiveCallsign( newMessage.Grid, callsign, "-", Number(newMessage.SR), timeNowSec(), "Pwr:" + newMessage.Power + " Freq:" + formatMhz(Number(newMessage.Frequency / 1000), 3, 3) + " Delta:" + Number(newMessage.DT).toFixed(2) + " Drift:" + newMessage.Drift, "WSPR", formatBand(Number(newMessage.Frequency / 1000000)), false, false, null, callsignToDxcc(callsign), null, null, null, "", "" ); processAlertMessage(callsign + " " + newMessage.Grid); updateCountStats(); } function centerOn(grid) { if (grid.length >= 4) { var LL = squareToLatLong(grid); GT.map .getView() .setCenter( ol.proj.fromLonLat([ LL.lo2 - (LL.lo2 - LL.lo1) / 2, LL.la2 - (LL.la2 - LL.la1) / 2 ]) ); } } function setCenterQTH() { if (homeQTHInput.value.length >= 4) { GT.appSettings.centerGridsquare = homeQTHInput.value; // Grab home QTH Gridsquare from Center QTH var LL = squareToLatLong(homeQTHInput.value); GT.map .getView() .setCenter( ol.proj.fromLonLat([ LL.lo2 - (LL.lo2 - LL.lo1) / 2, LL.la2 - (LL.la2 - LL.la1) / 2 ]) ); } else { homeQTHInput.value = ""; } } function setCenterGridsquare() { if (GT.mapMemory[6].zoom != -1) { mapMemory(6, false); return; } setCenterQTH(); } function changeLookupMerge() { GT.appSettings.lookupMerge = lookupMerge.checked; GT.appSettings.lookupMissingGrid = lookupMissingGrid.checked; if (GT.appSettings.lookupMerge == true) { lookupMissingGridDiv.style.display = "inline-block"; } else { lookupMissingGridDiv.style.display = "none"; } } function changelookupOnTx() { GT.appSettings.lookupOnTx = lookupOnTx.checked; GT.appSettings.lookupCloseLog = lookupCloseLog.checked; } function exportSettings() { var filename = GT.appData + GT.dirSeperator + "gt_settings.json"; var toWrite = JSON.stringify(localStorage); fs.writeFileSync(filename, toWrite); checkForSettings(); } function checkForSettings() { var filename = GT.appData + GT.dirSeperator + "gt_settings.json"; if (fs.existsSync(filename)) { importSettingsButton.style.display = "inline-block"; importSettingsFile.style.display = "inline-block"; importSettingsFile.innerHTML = filename; } else { importSettingsButton.style.display = "none"; importSettingsFile.style.display = "none"; } } function importSettings() { checkForSettings(); var filename = GT.appData + GT.dirSeperator + "gt_settings.json"; if (fs.existsSync(filename)) { var data = fs.readFileSync(filename); data = JSON.parse(data); if ( typeof data.appSettings != "undefined" && data.currentVersion == localStorage.currentVersion ) { localStorage.clear(); for (var key in data) { localStorage[key] = data[key]; } fs.unlinkSync(filename); chrome.runtime.reload(); } else { if (typeof data.appSettings == "undefined") { importSettingsFile.innerHTML = "Settings File Corrupt!"; } else if (data.currentVersion != localStorage.currentVersion) { importSettingsFile.innerHTML = "Settings Version Mismatch!"; } } } } function showCallsignBox(redraw) { var worker = "
" + $.i18n("gt.callsignBox.title") + "

"; GT.newCallsignCount = Object.keys(GT.liveCallsigns).length; if (GT.newCallsignCount > 0) { var newCallList = Array(); worker += "
" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; // "; if (GT.callsignLookups.lotwUseEnable == true) worker += ""; if (GT.callsignLookups.eqslUseEnable == true) worker += ""; if (GT.callsignLookups.oqrsUseEnable == true) worker += ""; for (var x in GT.liveCallsigns) { if (GT.liveCallsigns[x].dxcc != -1) { newCallList.push(GT.liveCallsigns[x]); } } newCallList.sort(compareCallsignTime).reverse(); for (var x in newCallList) { if (newCallList[x].DEcall == GT.appSettings.myRawCall) continue; var grid = newCallList[x].rect ? newCallList[x].rect.qth : "-"; var cqzone = newCallList[x].cqz ? newCallList[x].cqz : "-"; var ituzone = newCallList[x].ituz ? newCallList[x].ituz : "-"; var geo = GT.dxccInfo[newCallList[x].dxcc]; var thisCall = formatCallsign(newCallList[x].DEcall); worker += ""; worker += ""; worker += ""; worker += ""; var ageString = ""; if (timeNowSec() - newCallList[x].time < 3601) { ageString = toDHMS(timeNowSec() - newCallList[x].time); } else { ageString = userTimeString(newCallList[x].time * 1000); } worker += ""; if (GT.callsignLookups.lotwUseEnable == true) { worker += ""; } if (GT.callsignLookups.eqslUseEnable == true) { worker += ""; } if (GT.callsignLookups.oqrsUseEnable == true) { worker += ""; } worker += ""; } worker += "
" + $.i18n("gt.callsignBox.callsign") + "" + $.i18n("gt.callsignBox.Grid") + "" + $.i18n("gt.callsignBox.DXCC") + "" + $.i18n("gt.callsignBox.CQ") + "" + $.i18n("gt.callsignBox.ITU") + "" + $.i18n("gt.callsignBox.Flag") + "" + $.i18n("gt.callsignBox.QSO") + "" + $.i18n("gt.callsignBox.Grid") + "" + $.i18n("gt.callsignBox.When") + "ITUzCQzISO" + $.i18n("gt.callsignBox.LoTW") + "" + $.i18n("gt.callsignBox.eQSL") + "" + $.i18n("gt.callsignBox.OQRS") + "
" + thisCall + "" + grid + "" + geo.name + " (" + geo.pp + ")" + cqzone + "" + ituzone + "" + (thisCall in GT.tracker.worked.call ? "✔" : "") + "" + (thisCall in GT.tracker.confirmed.call ? "✔" : "") + "" + ageString + "" + (thisCall in GT.lotwCallsigns ? "✋" : "") + "" + (thisCall in GT.eqslCallsigns ? "✋" : "") + "" + (thisCall in GT.oqrsCallsigns ? "✋" : "") + "
"; } var heard = 0; var List = {}; if (Object.keys(GT.dxccCount).length > 0) { for (var key in GT.dxccCount) { if (key != -1) { var item = {}; item.total = GT.dxccCount[key]; item.confirmed = GT.dxccInfo[key].confirmed; item.worked = GT.dxccInfo[key].worked; item.dxcc = key; item.flag = GT.dxccInfo[key].flag; List[GT.dxccToAltName[key]] = item; heard++; } } worker += "
" + "" + "" + "" + "" + "" + "" + ""; Object.keys(List) .sort() .forEach(function (key, i) { worker += ""; worker += ""; worker += ""; worker += ""; }); worker += "
DXCC (" + heard + ")
" + $.i18n("gt.callsignBox.Name") + "" + $.i18n("gt.callsignBox.Flag") + "" + $.i18n("gt.callsignBox.Calls") + "
" + key + "" + List[key].total + "
"; } worker += ""; setStatsDiv("callsignListDiv", worker); } function setStatsDiv(div, worker) { if ( GT.statsWindowHandle != null && typeof GT.statsWindowHandle.window[div] !== "undefined" ) { GT.statsWindowHandle.window[div].innerHTML = worker; } } function setStatsDivHeight(div, heightWithPx) { if ( GT.statsWindowHandle != null && typeof GT.statsWindowHandle.window[div] !== "undefined" ) { GT.statsWindowHandle.window[div].style.height = heightWithPx; } } function getStatsWindowHeight() { if ( GT.statsWindowHandle != null && typeof GT.statsWindowHandle.window.window !== "undefined" ) { return GT.statsWindowHandle.window.window.innerHeight - 63; } return 300; } function setLookupDiv(div, worker) { if ( GT.lookupWindowHandle && GT.lookupWindowInitialized && typeof GT.lookupWindowHandle.window[div].innerHTML !== "undefined" ) { GT.lookupWindowHandle.window[div].innerHTML = worker; } } function setLookupDivHeight(div, heightWithPx) { if ( GT.lookupWindowHandle && GT.lookupWindowInitialized && typeof GT.lookupWindowHandle.window[div].style !== "undefined" ) { GT.lookupWindowHandle.window[div].style.height = heightWithPx; } } function getLookupWindowHeight() { if ( GT.lookupWindowHandle && GT.lookupWindowInitialized && typeof GT.lookupWindowHandle.window.window !== "undefined" ) { return GT.lookupWindowHandle.window.window.innerHeight; } return 300; } function showConditionsBox() { if (GT.mapSettings.offlineMode == false) { openConditionsWindow(); } } function myCallCompare(a, b) { return a.DEcall.localeCompare(b.DEcall); } function myGridCompare(a, b) { return a.grid.localeCompare(b.grid); } function myModeCompare(a, b) { return a.mode.localeCompare(b.mode); } function myDxccCompare(a, b) { return GT.dxccToAltName[a.dxcc].localeCompare(GT.dxccToAltName[b.dxcc]); } function myDxccIntCompare(a, b) { if (!(a in GT.dxccToAltName)) return 0; if (!(b in GT.dxccToAltName)) { return GT.dxccToAltName[a].localeCompare(GT.dxccToAltName[b]); } } function myTimeCompare(a, b) { if (a.time > b.time) return 1; if (a.time < b.time) return -1; return 0; } function myBandCompare(a, b) { return a.band.localeCompare(b.band); } function myConfirmedCompare(a, b) { if (a.confirmed && !b.confirmed) return 1; if (!a.confirmed && b.confirmed) return -1; return 0; } GT.sortFunction = [ myCallCompare, myGridCompare, myModeCompare, myDxccCompare, myTimeCompare, myBandCompare, myConfirmedCompare ]; GT.lastSortIndex = 4; GT.qsoPages = 1; GT.qsoPage = 0; GT.lastSortType = 0; GT.searchWB = ""; GT.gridSearch = ""; GT.filterBand = "Mixed"; GT.filterMode = "Mixed"; GT.filterDxcc = 0; GT.filterQSL = "All"; GT.lastSearchSelection = null; function resetSearch() { GT.lastSortIndex = 4; GT.qsoPages = 1; GT.qsoPage = 0; GT.lastSortType = 2; GT.searchWB = ""; GT.gridSearch = ""; GT.filterBand = "Mixed"; GT.filterMode = "Mixed"; GT.filterDxcc = 0; GT.filterQSL = "All"; GT.lastSearchSelection = null; } function showWorkedByCall(callsign, event) { event.preventDefault(); resetSearch(); GT.searchWB = callsign; if (event.shiftKey == true) GT.filterQSL = "true"; openInfoTab("qsobox", "workedBoxDiv", showWorkedBox); } function showWorkedSearchChanged(object, index) { ValidateCallsign(object, null); GT.searchWB = object.value.toUpperCase(); GT.lastSearchSelection = object.id; showWorkedBox(index, 0); } function showWorkedSearchGrid(object, index) { ValidateCallsign(object, null); GT.gridSearch = object.value.toUpperCase(); GT.lastSearchSelection = object.id; showWorkedBox(index, 0); } function filterBandFunction(event, index) { GT.filterBand = this.value; GT.lastSearchSelection = this.id; showWorkedBox(index, 0); } function filterModeFunction(event, index) { GT.filterMode = this.value; GT.lastSearchSelection = this.id; showWorkedBox(index, 0); } function filterDxccFunction(event, index) { GT.filterDxcc = this.value; GT.lastSearchSelection = this.id; showWorkedBox(index, 0); } function filterQSLFunction(event, index) { GT.filterQSL = this.value; GT.lastSearchSelection = this.id; showWorkedBox(index, 0); } function showWorkedBox(sortIndex, nextPage, redraw) { try { var myObjects = null; var mySort = sortIndex; var bandOptions; var modeOptions; var dxccOptions; var bands = {}; var modes = {}; var dxccs = {}; var ObjectCount = 0; myObjects = GT.QSOhash; if (sortIndex == null || typeof sortIndex == "undefined") { mySort = 4; GT.lastSortIndex = 4; GT.lastSortType = 2; } var list = Object.values(myObjects); if (GT.searchWB.length > 0) { let regExTest = new RegExp(GT.searchWB, "gi") list = list.filter(function (value) { return value.DEcall.match(regExTest); }); } if (GT.gridSearch.length > 0) { list = list.filter(function (value) { var x = value.grid.indexOf(GT.gridSearch); var y = value.vucc_grids.indexOf(GT.gridSearch); return x == 0 || y == 0; }); } for (var key in list) { bands[list[key].band] = list[key].band; modes[list[key].mode] = list[key].mode; var unconfirmedCallsKey = new UnconfirmedCallsKey(list[key].dxcc, list[key].band); if (GT.unconfirmedCalls.has(unconfirmedCallsKey.key) && list[key].confirmed) { GT.unconfirmedCalls.set(unconfirmedCallsKey.key, GT.unconfirmedCallsSentinel); } else if ( !list[key].confirmed && // check for sentinel object -- confirmed country. key needs to be kept in here so that // an recent unconfirmed qso doesn't mark the key as unconfirmed GT.unconfirmedCalls.get(unconfirmedCallsKey.key) != GT.unconfirmedCallsSentinel ) { var logs = GT.unconfirmedCalls.get(unconfirmedCallsKey.key); if (logs == undefined) { logs = new Set(); logs.add(list[key]); GT.unconfirmedCalls.set(unconfirmedCallsKey.key, logs); } else if (!logs.has(list[key])) { logs.add(list[key]); } } var pp = list[key].dxcc in GT.dxccInfo ? GT.dxccInfo[list[key].dxcc].pp : "?"; dxccs[GT.dxccToAltName[list[key].dxcc] + " (" + pp + ")"] = list[key].dxcc; } if (GT.filterBand != "Mixed") { list = list.filter(function (value) { return value.band == GT.filterBand; }); } if (GT.filterMode != "Mixed") { list = list.filter(function (value) { if ( GT.filterMode == "Phone" && value.mode in GT.modes_phone && GT.modes_phone[value.mode] ) { return true; } if ( GT.filterMode == "Digital" && value.mode in GT.modes && GT.modes[value.mode] ) { return true; } return value.mode == GT.filterMode; }); } if (GT.filterDxcc != 0) { list = list.filter(function (value) { return value.dxcc == GT.filterDxcc; }); } if (GT.filterQSL != "All") { list = list.filter(function (value) { return value.confirmed == (GT.filterQSL == "true"); }); } if (typeof redraw == "undefined") { if (typeof nextPage == "undefined") { nextPage = 0; if (GT.lastSortIndex != mySort) { list = list.sort(GT.sortFunction[mySort]); GT.lastSortIndex = mySort; GT.lastSortType = 1; GT.qsoPage = 0; } else { list = list.sort(GT.sortFunction[mySort]).reverse(); GT.lastSortIndex = -1; GT.lastSortType = 2; GT.qsoPage = 0; } } else { if (GT.lastSortType == 1) { list = list.sort(GT.sortFunction[mySort]); } else { list = list.sort(GT.sortFunction[mySort]).reverse(); } } } else { mySort = GT.lastSortIndex; if (mySort == -1) mySort = 4; if (GT.lastSortType == 1) { list = list.sort(GT.sortFunction[mySort]); } else { list = list.sort(GT.sortFunction[mySort]).reverse(); } } ObjectCount = list.length; GT.qsoPages = parseInt(ObjectCount / GT.appSettings.qsoItemsPerPage) + 1; GT.qsoPage += nextPage; GT.qsoPage %= GT.qsoPages; if (GT.qsoPage < 0) GT.qsoPage = GT.qsoPages - 1; var startIndex = GT.qsoPage * GT.appSettings.qsoItemsPerPage; var endIndex = startIndex + GT.appSettings.qsoItemsPerPage; if (endIndex > ObjectCount) endIndex = ObjectCount; var workHead = " Entries (" + ObjectCount + ")"; if (GT.qsoPages > 1) { workHead += "
⇦ "; workHead += " Page " + (GT.qsoPage + 1) + " of " + GT.qsoPages + " (" + (endIndex - startIndex) + ") "; workHead += " ⇨"; } setStatsDiv("workedHeadDiv", workHead); if (myObjects != null) { var worker = ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; if (GT.filterDxcc != 0) { worker += ""; worker += ""; } else { worker += " "; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; if (GT.callsignLookups.lotwUseEnable == true) worker += ""; if (GT.callsignLookups.eqslUseEnable == true) worker += ""; if (GT.callsignLookups.oqrsUseEnable == true) worker += ""; worker += ""; var key = null; for (var i = startIndex; i < endIndex; i++) { key = list[i]; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; if (GT.callsignLookups.lotwUseEnable == true) { worker += ""; } if (GT.callsignLookups.eqslUseEnable == true) { worker += ""; } if (GT.callsignLookups.oqrsUseEnable == true) { worker += ""; } worker += ""; } worker += "
"; if (GT.searchWB.length > 0) { worker += ""; } worker += ""; if (GT.gridSearch.length > 0) { worker += ""; } worker += "
"; } worker += "
" + $.i18n("gt.qsoPage.Station") + "" + $.i18n("gt.qsoPage.Grid") + "" + $.i18n("gt.qsoPage.Band") + "" + $.i18n("gt.qsoPage.Mode") + "" + $.i18n("gt.qsoPage.QSL") + "" + $.i18n("gt.qsoPage.Sent") + "" + $.i18n("gt.qsoPage.Rcvd") + "" + $.i18n("gt.qsoPage.DXCC") + "" + $.i18n("gt.qsoPage.Flag") + "" + $.i18n("roster.secondary.wanted.state") + "" + $.i18n("gt.qsoPage.When") + "" + $.i18n("gt.qsoPage.LoTW") + "" + $.i18n("gt.qsoPage.eQSL") + "" + $.i18n("gt.qsoPage.OQRS") + "
" + formatCallsign(key.DEcall) + "" + key.grid + (key.vucc_grids.length ? ", " + key.vucc_grids.join(", ") : "") + "" + key.band + "" + key.mode + "" + (key.confirmed ? "✔" : "") + "" + key.RSTsent + "" + key.RSTrecv + "" + GT.dxccToAltName[key.dxcc] + " (" + (key.dxcc in GT.dxccInfo ? GT.dxccInfo[key.dxcc].pp : "?") + ")" + (key.state ? key.state : " ") + "" + userTimeString(key.time * 1000) + "" + (key.DEcall in GT.lotwCallsigns ? "✋" : "") + "" + (key.DEcall in GT.eqslCallsigns ? "✋" : "") + "" + (key.DEcall in GT.oqrsCallsigns ? "✋" : "") + "
"; setStatsDiv("workedListDiv", worker); statsValidateCallByElement("searchWB"); statsValidateCallByElement("searchGrid"); var newSelect = document.createElement("select"); newSelect.id = "bandFilter"; newSelect.title = "Band Filter"; var option = document.createElement("option"); option.value = "Mixed"; option.text = "Mixed"; newSelect.appendChild(option); Object.keys(bands) .sort(function (a, b) { return parseInt(a) - parseInt(b); }) .forEach(function (key) { var option = document.createElement("option"); option.value = key; option.text = key; newSelect.appendChild(option); }); statsAppendChild( "bandFilterDiv", newSelect, "filterBandFunction", GT.filterBand, true ); newSelect = document.createElement("select"); newSelect.id = "modeFilter"; newSelect.title = "Mode Filter"; option = document.createElement("option"); option.value = "Mixed"; option.text = "Mixed"; newSelect.appendChild(option); option = document.createElement("option"); option.value = "Phone"; option.text = "Phone"; newSelect.appendChild(option); option = document.createElement("option"); option.value = "Digital"; option.text = "Digital"; newSelect.appendChild(option); Object.keys(modes) .sort() .forEach(function (key) { var option = document.createElement("option"); option.value = key; option.text = key; newSelect.appendChild(option); }); statsAppendChild( "modeFilterDiv", newSelect, "filterModeFunction", GT.filterMode, true ); newSelect = document.createElement("select"); newSelect.id = "dxccFilter"; newSelect.title = "DXCC Filter"; option = document.createElement("option"); option.value = 0; option.text = "All"; newSelect.appendChild(option); Object.keys(dxccs) .sort() .forEach(function (key) { var option = document.createElement("option"); option.value = dxccs[key]; option.text = key; newSelect.appendChild(option); }); statsAppendChild( "dxccFilterDiv", newSelect, "filterDxccFunction", GT.filterDxcc, true ); newSelect = document.createElement("select"); newSelect.id = "qslFilter"; newSelect.title = "QSL Filter"; option = document.createElement("option"); option.value = "All"; option.text = "All"; newSelect.appendChild(option); option = document.createElement("option"); option.value = true; option.text = "Yes"; newSelect.appendChild(option); option = document.createElement("option"); option.value = false; option.text = "No"; newSelect.appendChild(option); statsAppendChild( "qslFilterDiv", newSelect, "filterQSLFunction", GT.filterQSL, true ); statsFocus(GT.lastSearchSelection); setStatsDivHeight("workedListDiv", getStatsWindowHeight() - 6 + "px"); } else setStatsDiv("workedListDiv", "None"); myObjects = null; } catch (e) { console.error(e); } } function statsValidateCallByElement(elementString) { if (GT.statsWindowHandle != null && typeof GT.statsWindowHandle.window.validateCallByElement !== "undefined") { GT.statsWindowHandle.window.validateCallByElement(elementString); } } function statsFocus(selection) { if (GT.statsWindowHandle != null && typeof GT.statsWindowHandle.window.statsFocus !== "undefined") { GT.statsWindowHandle.window.statsFocus(selection); } } function lookupValidateCallByElement(elementString) { if (GT.lookupWindowHandle != null && GT.lookupWindowInitialized && typeof GT.lookupWindowHandle.window.validateCallByElement !== "undefined") { GT.lookupWindowHandle.window.validateCallByElement(elementString); } } function lookupFocus(selection) { if (GT.lookupWindowHandle != null && GT.lookupWindowInitialized && typeof GT.lookupWindowHandle.window.statsFocus !== "undefined") { GT.lookupWindowHandle.window.statsFocus(selection); } } function statsAppendChild(elementString, object, onInputString, defaultValue) { if (GT.statsWindowHandle != null && typeof GT.statsWindowHandle.window.appendToChild !== "undefined") { GT.statsWindowHandle.window.appendToChild( elementString, object, onInputString, defaultValue ); } } function showDXCCsBox() { var worker = getCurrentBandModeHTML(); var confirmed = 0; var worked = 0; var needed = 0; var List = {}; var ListConfirmed = {}; var ListNotWorked = {}; for (var key in GT.dxccInfo) { if (key != -1 && Number(GT.dxccInfo[key].dxcc) > 0) { if (GT.dxccInfo[key].worked == true) { var item = {}; item.dxcc = GT.dxccInfo[key].dxcc; item.flag = GT.dxccInfo[key].flag; item.confirmed = GT.dxccInfo[key].confirmed; List[GT.dxccInfo[key].name] = item; worked++; } if (GT.dxccInfo[key].confirmed == true) { var item = {}; item.dxcc = GT.dxccInfo[key].dxcc; item.flag = GT.dxccInfo[key].flag; item.confirmed = GT.dxccInfo[key].confirmed; ListConfirmed[GT.dxccInfo[key].name] = item; confirmed++; } if ( GT.dxccInfo[key].worked == false && GT.dxccInfo[key].confirmed == false && GT.dxccInfo[key].pp != "" && GT.dxccInfo[key].geo != "deleted" ) { var item = {}; item.dxcc = GT.dxccInfo[key].dxcc; item.flag = GT.dxccInfo[key].flag; item.confirmed = GT.dxccInfo[key].confirmed; ListNotWorked[GT.dxccInfo[key].name] = item; needed++; } } } if (worked > 0) { worker += "
" + "" + "" + "" + ""; Object.keys(List) .sort() .forEach(function (key, i) { var rowStyle = List[key].confirmed ? "" : "background-clip:content-box;box-shadow: 0 0 8px 3px inset "; var rowAttributes = List[key].confirmed ? "" : "id='unconfirmed" + List[key].dxcc + "Id'"; worker += ""; worker += ""; worker += ""; }); worker += "
" + "" + $.i18n("gt.dxccBox.Worked") + " (" + worked + ")
" + $.i18n("gt.dxccBox.Name") + "" + $.i18n("gt.dxccBox.Flag") + "" + $.i18n("gt.dxccBox.DXCC") + "
" + key + "" + List[key].dxcc + "
"; } if (confirmed > 0) { worker += "
" + "" + "" + "" + ""; Object.keys(ListConfirmed) .sort() .forEach(function (key, i) { worker += ""; worker += ""; worker += ""; }); worker += "
" + $.i18n("gt.dxccBox.Confirmed") + " (" + confirmed + ")
" + $.i18n("gt.dxccBox.Name") + "" + $.i18n("gt.dxccBox.Flag") + "" + $.i18n("gt.dxccBox.DXCC") + "
" + key + "" + ListConfirmed[key].dxcc + "
"; } if (needed > 0) { worker += "
" + "" + "" + "" + ""; Object.keys(ListNotWorked) .sort() .forEach(function (key, i) { worker += ""; worker += ""; worker += ""; }); worker += "
" + $.i18n("gt.dxccBox.Needed") + " (" + needed + ")
" + $.i18n("gt.dxccBox.Name") + "" + $.i18n("gt.dxccBox.Flag") + "" + $.i18n("gt.dxccBox.DXCC") + "
" + key + "" + ListNotWorked[key].dxcc + "
"; } setStatsDiv("dxccListDiv", worker); Object.keys(List).forEach(function (key, i) { var band = GT.appSettings.gtBandFilter == "auto" ? GT.appSettings.myBand : GT.appSettings.gtBandFilter.length == 0 ? "" : GT.appSettings.gtBandFilter; var unconfirmedCallsKey = new UnconfirmedCallsKey(List[key].dxcc, band); if (GT.unconfirmedCalls.has(unconfirmedCallsKey.key) && GT.unconfirmedCalls.get(unconfirmedCallsKey.key) != GT.unconfirmedCallsSentinel) { var onMousedown = function (e) { if (e.which == 1) { if (GT.popupWindowHandle == null) { popupNewWindows(); var gui = require("nw.gui"); gui.Window.open( "gt_popup.html", { show: false, id: "GT-popup" }, function (new_win) { GT.popupWindowHandle = new_win; new_win.on("loaded", function () { GT.popupWindowHandle.show(); GT.popupWindowHandle.focus(); renderTooltipWindowLogbook(GT.unconfirmedCalls.get(unconfirmedCallsKey.key)); }); new_win.on("close", function () { GT.popupWindowHandle.hide(); }); } ); lockNewWindows(); } else { renderTooltipWindowLogbook(GT.unconfirmedCalls.get(unconfirmedCallsKey.key)); } } }; var unconfirmedTd = GT.statsWindowHandle.window.document.getElementById("unconfirmed" + List[key].dxcc + "Id"); if (unconfirmedTd != null) { unconfirmedTd.addEventListener("mousedown", onMousedown); } } }); } function showCQzoneBox() { var worker = getCurrentBandModeHTML(); worker += "
" + "" + $.i18n("gt.CQZoneBox.Worked") + "
"; worker += displayItemList(GT.cqZones, "#FFFFFF"); worker += "
"; setStatsDiv("cqzoneListDiv", worker); } function showITUzoneBox() { var worker = getCurrentBandModeHTML(); worker += "
" + "" + $.i18n("gt.ITUZoneBox.Worked") + "
"; worker += displayItemList(GT.ituZones, "#FFFFFF"); worker += "
"; setStatsDiv("ituzoneListDiv", worker); } function showWASWACzoneBox() { var worker = getCurrentBandModeHTML(); worker += "
" + "" + $.i18n("gt.WASWACBox.WAC") + "
"; worker += displayItemList(GT.wacZones, "#90EE90"); worker += "
"; worker += "
" + "" + $.i18n("gt.WASWACBox.WAS") + "
"; worker += displayItemList(GT.wasZones, "#00DDDD"); worker += "
"; setStatsDiv("waswacListDiv", worker); } function displayItemList(table, color) { var worked = 0; var needed = 0; var confirmed = 0; for (var key in table) { if (table[key].worked == true) { worked++; } if (table[key].confirmed == true) { confirmed++; } if (table[key].confirmed == false && table[key].worked == false) { needed++; } } var worker = "
"; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; var inversionAlpha = "DD"; var confirmed = ""; var bold = "text-shadow: 0px 0px 1px black;"; var unconf = "background-clip:content-box;box-shadow: 0 0 8px 3px inset "; Object.keys(table) .sort() .forEach(function (key, i) { var style; var name = typeof table[key].name !== "undefined" ? key + " / " + table[key].name : key; if (table[key].confirmed == true) { style = "color:" + color + ";" + confirmed; } else if (table[key].worked == true) { style = "color:" + color + ";" + unconf; } else { // needed style = "color:#000000;background-color:" + color + ";" + bold; } worker += ""; }); worker += "
" + $.i18n("gt.displayItemsList.Worked") + " (" + worked + ")
" + $.i18n("gt.displayItemsList.Confirmed") + " (" + confirmed + ")
" + $.i18n("gt.displayItemsList.Needed") + " (" + needed + ")
Name
" + name + "
"; return worker; } function showWPXBox() { var worker = getCurrentBandModeHTML(); var band = GT.appSettings.gtBandFilter == "auto" ? GT.appSettings.myBand : GT.appSettings.gtBandFilter.length == 0 ? "" : GT.appSettings.gtBandFilter; var mode = GT.appSettings.gtModeFilter == "auto" ? GT.appSettings.myMode : GT.appSettings.gtModeFilter.length == 0 ? "" : GT.appSettings.gtModeFilter; if (mode == "Digital") { mode = "dg"; } if (mode == "Phone") { mode = "ph"; } var modifier = String(band) + String(mode); var worked = 0; var confirmed = 0; var List = {}; var ListConfirmed = {}; for (var key in GT.tracker.worked.px) { if (typeof GT.tracker.worked.px[key] == "string" && key + modifier in GT.tracker.worked.px) { List[key] = key; } } for (var key in GT.tracker.confirmed.px) { if (typeof GT.tracker.confirmed.px[key] == "string" && key + modifier in GT.tracker.confirmed.px) { ListConfirmed[key] = key; } } worked = Object.keys(List).length; confirmed = Object.keys(ListConfirmed).length; if (worked > 0) { worker += "
" + "" + $.i18n("gt.WPXBox.worked") + " (" + worked + ")
"; worker += "
"; Object.keys(List) .sort() .forEach(function (key, i) { worker += ""; }); worker += "
" + formatCallsign(key) + "" + formatCallsign(GT.QSOhash[GT.tracker.worked.px[key]].DEcall) + "
"; worker += "
"; } if (confirmed > 0) { worker += "
" + "" + $.i18n("gt.WPXBox.confirmed") + " (" + confirmed + ")
"; worker += "
"; Object.keys(ListConfirmed) .sort() .forEach(function (key, i) { worker += ""; }); worker += "
" + formatCallsign(key) + "" + formatCallsign(GT.QSOhash[GT.tracker.confirmed.px[key]].DEcall) + "
"; worker += "
"; } setStatsDiv("wpxListDiv", worker); } function showRootInfoBox() { openStatsWindow(); } function showSettingsBox() { if (rootSettingsDiv.style.display == "inline-block") { updateRunningProcesses(); rootSettingsDiv.style.display = "none"; } else { updateRunningProcesses(); helpDiv.style.display = "none"; GT.helpShow = false; rootSettingsDiv.style.display = "inline-block"; } } function toggleBaWindow(event) { event.preventDefault(); if (GT.baWindowHandle == null) { openBaWindow(true); } else { if (GT.baWindowHandle.window.isShowing == true) { openBaWindow(false); } else { openBaWindow(true); } } } function openBaWindow(show = true) { if (GT.baWindowHandle == null) { popupNewWindows(); var gui = require("nw.gui"); gui.Window.open( "gt_bandactivity.html", { show: false, id: "GT-baac", frame: false, resizable: true, always_on_top: true }, function (new_win) { GT.baWindowHandle = new_win; new_win.on("loaded", function () { GT.baWindowHandle.setMinimumSize(198, 52); if (GT.firstRun) { GT.baWindowHandle.resizeTo(198, 52); GT.baWindowHandle.moveTo(250, 250); } }); new_win.on("close", function () { GT.baWindowHandle.window.isShowing = false; GT.baWindowHandle.window.saveScreenSettings(); GT.baWindowHandle.hide(); }); } ); lockNewWindows(); } else { try { if (show == true) { GT.baWindowHandle.show(); GT.baWindowHandle.window.isShowing = true; GT.baWindowHandle.window.saveScreenSettings(); } else { GT.baWindowHandle.window.isShowing = false; GT.baWindowHandle.window.saveScreenSettings(); GT.baWindowHandle.hide(); } } catch (e) { console.error(e); } } } function openAlertWindow(show = true) { if (GT.alertWindowHandle == null) { popupNewWindows(); var gui = require("nw.gui"); gui.Window.open( "gt_alert.html", { show: false, id: "GT-alert", always_on_top: true }, function (new_win) { GT.alertWindowHandle = new_win; new_win.on("loaded", function () { GT.alertWindowHandle.window.isShowing = false; GT.alertWindowHandle.window.saveScreenSettings(); GT.alertWindowHandle.hide(); }); new_win.on("close", function () { ackAlerts(); GT.alertWindowHandle.window.isShowing = false; GT.alertWindowHandle.window.saveScreenSettings(); GT.alertWindowHandle.hide(); }); } ); lockNewWindows(); } else { try { if (show == true) { GT.alertWindowHandle.show(); GT.alertWindowHandle.window.isShowing = true; GT.alertWindowHandle.window.saveScreenSettings(); } else { GT.alertWindowHandle.window.isShowing = false; GT.alertWindowHandle.window.saveScreenSettings(); GT.alertWindowHandle.hide(); } } catch (e) { console.error(e); } } } function openLookupWindow(show = false) { if (GT.lookupWindowHandle == null) { popupNewWindows(); var gui = require("nw.gui"); gui.Window.open( "gt_lookup.html", { show: false, id: "GT-lookups", icon: "img/lookup-icon.png" }, function (new_win) { GT.lookupWindowHandle = new_win; new_win.on("loaded", function () { GT.lookupWindowHandle.setMinimumSize(680, 200); GT.lookupWindowHandle.setResizable(true); if (GT.firstRun) { GT.lookupWindowHandle.resizeTo(680, 200); GT.lookupWindowHandle.moveTo(75, 75); } }); new_win.on("close", function () { GT.lookupWindowHandle.window.isShowing = false; GT.lookupWindowHandle.window.saveScreenSettings(); GT.lookupWindowHandle.hide(); }); } ); lockNewWindows(); } else { try { if (show) { GT.lookupWindowHandle.show(); GT.lookupWindowHandle.window.isShowing = true; GT.lookupWindowHandle.window.saveScreenSettings(); } else { GT.lookupWindowHandle.hide(); GT.lookupWindowHandle.window.isShowing = false; GT.lookupWindowHandle.window.saveScreenSettings(); } } catch (e) { console.error(e); } } } function openInfoTab(evt, tabName, callFunc, callObj) { openStatsWindow(); if (GT.statsWindowHandle != null) { // Declare all variables var i, infoTabcontent, infoTablinks; // Get all elements with class="infoTabcontent" and hide them infoTabcontent = GT.statsWindowHandle.window.document.getElementsByClassName( "infoTabcontent" ); for (i = 0; i < infoTabcontent.length; i++) { infoTabcontent[i].style.display = "none"; } // Get all elements with class="infoTablinks" and remove the class "active" infoTablinks = GT.statsWindowHandle.window.document.getElementsByClassName( "infoTablinks" ); for (i = 0; i < infoTablinks.length; i++) { infoTablinks[i].className = infoTablinks[i].className.replace( " active", "" ); } // Show the current tab, and add an "active" class to the button that opened the tab GT.statsWindowHandle.window.document.getElementById(tabName).style.display = "block"; if (evt) { evt = GT.statsWindowHandle.window.document.getElementById(evt); } if (evt) { if (typeof evt.currentTarget != "undefined") { evt.currentTarget.className += " active"; } else evt.className += " active"; } if (callFunc) { if (callObj) callFunc(callObj); else callFunc(); } } } function openSettingsTab(evt, tabName) { // Declare all variables var i, settingsTabcontent, settingsTablinks; // Get all elements with class="settingsTabcontent" and hide them settingsTabcontent = document.getElementsByClassName("settingsTabcontent"); for (i = 0; i < settingsTabcontent.length; i++) { settingsTabcontent[i].style.display = "none"; } // Get all elements with class="settingsTablinks" and remove the class "active" settingsTablinks = document.getElementsByClassName("settingsTablinks"); for (i = 0; i < settingsTablinks.length; i++) { settingsTablinks[i].className = settingsTablinks[i].className.replace( " active", "" ); } displayAlerts(); // Show the current tab, and add an "active" class to the button that opened the tab document.getElementById(tabName).style.display = "block"; if (typeof evt.currentTarget != "undefined") { evt.currentTarget.className += " active"; } else evt.className += " active"; } function setGridMode(mode) { GT.appSettings.sixWideMode = mode; modeImg.src = GT.maidenheadModeImageArray[GT.appSettings.sixWideMode]; clearTempGrids(); redrawGrids(); } function toggleGridMode() { GT.appSettings.sixWideMode ^= 1; modeImg.src = GT.maidenheadModeImageArray[GT.appSettings.sixWideMode]; clearTempGrids(); redrawGrids(); } function newStatObject() { var statObject = {}; statObject.worked = 0; statObject.confirmed = 0; statObject.worked_bands = {}; statObject.confirmed_bands = {}; statObject.worked_modes = {}; statObject.confirmed_modes = {}; statObject.worked_types = {}; statObject.confirmed_types = {}; return statObject; } function newStatCountObject() { var statCountObject = {}; statCountObject.worked = 0; statCountObject.confirmed = 0; statCountObject.worked_bands = {}; statCountObject.confirmed_bands = {}; statCountObject.worked_modes = {}; statCountObject.confirmed_modes = {}; statCountObject.worked_types = {}; statCountObject.confirmed_types = {}; statCountObject.worked_high = 0; statCountObject.confirmed_high = 0; statCountObject.worked_high_key = null; statCountObject.confirmed_high_key = null; return statCountObject; } function newDistanceObject(start = 0) { var distance = {}; distance.worked_unit = start; distance.worked_hash = ""; distance.confirmed_unit = start; distance.confirmed_hash = null; return distance; } function newModeType() { var modeType = {}; modeType.worked = 0; modeType.confirmed = 0; return modeType; } GT.statBoxTimer = null; function showStatBox(resize) { var count = Object.keys(GT.QSOhash).length; if (typeof resize != "undefined" && resize) { setStatsDivHeight("statViewDiv", getStatsWindowHeight() + 29 + "px"); return; } if (GT.statBoxTimer) nodeTimers.clearTimeout(GT.statBoxTimer); if (count > 0) { setStatsDiv( "statViewDiv", " 
" + $.i18n("gt.statBox.NoEntries") + "
 " ); setStatsDivHeight("statViewDiv", "auto"); GT.statBoxTimer = nodeTimers.setTimeout(renderStatsBox, 250); } else { setStatsDiv( "statViewDiv", " 
" + $.i18n("gt.statBox.NoEntries") + "
 " ); setStatsDivHeight("statViewDiv", "auto"); } } function getTypeFromMode(mode) { if (mode in GT.modes) { if (GT.modes[mode] == true) return "Digital"; else if (GT.modes_phone[mode] == true) return "Phone"; else if (mode == "CW") return "CW"; } return "Other"; } function workObject(obj, count, band, mode, type, didConfirm) { obj.worked++; obj.worked_bands[band] = ~~obj.worked_bands[band] + 1; obj.worked_modes[mode] = ~~obj.worked_modes[mode] + 1; if (!count) { obj.worked_types.Mixed = ~~obj.worked_modes.Mixed + 1; if (type) obj.worked_types[type] = ~~obj.worked_modes[type] + 1; } if (didConfirm) { obj.confirmed++; obj.confirmed_bands[band] = ~~obj.confirmed_bands[band] + 1; obj.confirmed_modes[mode] = ~~obj.confirmed_modes[mode] + 1; if (!count) { obj.confirmed_types.Mixed = ~~obj.confirmed_types.Mixed + 1; if (type) obj.confirmed_types[type] = ~~obj.confirmed_types[type] + 1; } } return obj; } function renderStatsBox() { var worker = ""; var scoreSection = "Initial"; try { var dxccInfo = {}; var cqZones = {}; var ituZones = {}; var wasZones = {}; var wacZones = {}; var countyData = {}; var gridData = {}; var wpxData = {}; var callData = {}; var long_distance = newDistanceObject(); var short_distance = newDistanceObject(100000); long_distance.band = {}; long_distance.mode = {}; long_distance.type = {}; short_distance.band = {}; short_distance.mode = {}; short_distance.type = {}; var modet = {}; modet.Mixed = newStatCountObject(); modet.Digital = newStatCountObject(); modet.Phone = newStatCountObject(); modet.CW = newStatCountObject(); modet.Other = newStatCountObject(); var details = {}; details.callsigns = {}; details.oldest = timeNowSec() + 86400; details.newest = 0; scoreSection = "QSO"; for (var i in GT.QSOhash) { var finalGrid = GT.QSOhash[i].grid; var didConfirm = GT.QSOhash[i].confirmed; var band = GT.QSOhash[i].band; var mode = GT.QSOhash[i].mode; var state = GT.QSOhash[i].state; var cont = GT.QSOhash[i].cont; var finalDxcc = GT.QSOhash[i].dxcc; var cnty = GT.QSOhash[i].cnty; var ituz = GT.QSOhash[i].ituz; var cqz = GT.QSOhash[i].cqz; var wpx = GT.QSOhash[i].px; var call = GT.QSOhash[i].DXcall; var who = GT.QSOhash[i].DEcall; var type = getTypeFromMode(mode); if (!(who in callData)) callData[who] = newStatObject(); workObject(callData[who], false, band, mode, type, didConfirm); details.callsigns[call] = ~~details.callsigns[call] + 1; if (GT.QSOhash[i].time < details.oldest) { details.oldest = GT.QSOhash[i].time; } if (GT.QSOhash[i].time > details.newest) { details.newest = GT.QSOhash[i].time; } workObject(modet.Mixed, true, band, mode, type, didConfirm); if (mode in GT.modes) { if (GT.modes[mode] == true) { workObject(modet.Digital, true, band, mode, type, didConfirm); } else if (GT.modes_phone[mode] == true) { workObject(modet.Phone, true, band, mode, type, didConfirm); } else if (mode == "CW") { workObject(modet.CW, true, band, mode, type, didConfirm); } else workObject(modet.Other, true, band, mode, type, didConfirm); } else workObject(modet.Other, true, band, mode, type, didConfirm); if (state != null && isKnownCallsignUS(finalDxcc)) { if (state.substr(0, 2) != "US") state = "US-" + state; if (state in GT.StateData) { var name = GT.StateData[state].name; if (name in GT.wasZones) { if (!(name in wasZones)) wasZones[name] = newStatObject(); workObject(wasZones[name], false, band, mode, type, didConfirm); } } } if (wpx != null) { if (!(wpx in wpxData)) wpxData[wpx] = newStatObject(); workObject(wpxData[wpx], false, band, mode, type, didConfirm); } if (cnty != null) { if (cnty in GT.cntyToCounty) { if (!(cnty in countyData)) countyData[cnty] = newStatObject(); workObject(countyData[cnty], false, band, mode, type, didConfirm); } } if (cont != null) { if (cont in GT.shapeData) { var name = GT.shapeData[cont].properties.name; if (name in GT.wacZones) { if (!(name in wacZones)) wacZones[name] = newStatObject(); workObject(wacZones[name], false, band, mode, type, didConfirm); } } } if (finalGrid.length > 0) { LL = squareToCenter(finalGrid); unit = parseInt(MyCircle.distance(GT.myLat, GT.myLon, LL.a, LL.o, distanceUnit.value) * MyCircle.validateRadius(distanceUnit.value)); if (unit > long_distance.worked_unit) { long_distance.worked_unit = unit; long_distance.worked_hash = i; } if (!(band in long_distance.band)) { long_distance.band[band] = newDistanceObject(); } if (!(mode in long_distance.mode)) { long_distance.mode[mode] = newDistanceObject(); } if (!(type in long_distance.type)) { long_distance.type[type] = newDistanceObject(); } if (unit > long_distance.mode[mode].worked_unit) { long_distance.mode[mode].worked_unit = unit; long_distance.mode[mode].worked_hash = i; } if (unit > long_distance.band[band].worked_unit) { long_distance.band[band].worked_unit = unit; long_distance.band[band].worked_hash = i; } if (unit > long_distance.type[type].worked_unit) { long_distance.type[type].worked_unit = unit; long_distance.type[type].worked_hash = i; } if (didConfirm) { if (unit > long_distance.confirmed_unit) { long_distance.confirmed_unit = unit; long_distance.confirmed_hash = i; } if (unit > long_distance.mode[mode].confirmed_unit) { long_distance.mode[mode].confirmed_unit = unit; long_distance.mode[mode].confirmed_hash = i; } if (unit > long_distance.band[band].confirmed_unit) { long_distance.band[band].confirmed_unit = unit; long_distance.band[band].confirmed_hash = i; } if (unit > long_distance.type[type].confirmed_unit) { long_distance.type[type].confirmed_unit = unit; long_distance.type[type].confirmed_hash = i; } } if (unit > 0) { if (unit < short_distance.worked_unit) { short_distance.worked_unit = unit; short_distance.worked_hash = i; } if (!(band in short_distance.band)) { short_distance.band[band] = newDistanceObject(100000); } if (!(mode in short_distance.mode)) { short_distance.mode[mode] = newDistanceObject(100000); } if (!(type in short_distance.type)) { short_distance.type[type] = newDistanceObject(100000); } if (unit < short_distance.mode[mode].worked_unit) { short_distance.mode[mode].worked_unit = unit; short_distance.mode[mode].worked_hash = i; } if (unit < short_distance.band[band].worked_unit) { short_distance.band[band].worked_unit = unit; short_distance.band[band].worked_hash = i; } if (unit < short_distance.type[type].worked_unit) { short_distance.type[type].worked_unit = unit; short_distance.type[type].worked_hash = i; } if (didConfirm) { if (unit < short_distance.confirmed_unit) { short_distance.confirmed_unit = unit; short_distance.confirmed_hash = i; } if (unit < short_distance.mode[mode].confirmed_unit) { short_distance.mode[mode].confirmed_unit = unit; short_distance.mode[mode].confirmed_hash = i; } if (unit < short_distance.band[band].confirmed_unit) { short_distance.band[band].confirmed_unit = unit; short_distance.band[band].confirmed_hash = i; } if (unit < short_distance.type[type].confirmed_unit) { short_distance.type[type].confirmed_unit = unit; short_distance.type[type].confirmed_hash = i; } } } } if (finalDxcc > 0) { if (!(GT.dxccToAltName[finalDxcc] in dxccInfo)) { dxccInfo[GT.dxccToAltName[finalDxcc]] = newStatObject(); } workObject( dxccInfo[GT.dxccToAltName[finalDxcc]], false, band, mode, type, didConfirm ); } if (cqz && cqz.length > 0) { var name = GT.cqZones[cqz].name; if (!(name in cqZones)) cqZones[name] = newStatObject(); workObject(cqZones[name], false, band, mode, type, didConfirm); } if (ituz && ituz.length > 0) { if (!(ituz in ituZones)) ituZones[ituz] = newStatObject(); workObject(ituZones[ituz], false, band, mode, type, didConfirm); } if (finalGrid.length > 0) { var gridCheck = finalGrid.substr(0, 4); if (!(gridCheck in gridData)) gridData[gridCheck] = newStatObject(); workObject(gridData[gridCheck], false, band, mode, type, didConfirm); } } scoreSection = "Stats"; var stats = {}; var output = {}; dxccInfo.order = 1; stats.DXCC = dxccInfo; stats.GRID = gridData; stats.CQ = cqZones; stats.ITU = ituZones; stats.WAC = wacZones; stats.WAS = wasZones; stats.USC = countyData; stats.WPX = wpxData; stats.WRFA = callData; for (i in stats) { output[i] = newStatCountObject(); for (var key in stats[i]) { if (stats[i][key].worked) { output[i].worked++; if (stats[i][key].worked > output[i].worked_high) { output[i].worked_high = stats[i][key].worked; output[i].worked_high_key = key; } } if (stats[i][key].confirmed) { output[i].confirmed++; if (stats[i][key].confirmed > output[i].confirmed_high) { output[i].confirmed_high = stats[i][key].confirmed; output[i].confirmed_high_key = key; } } for (var band in stats[i][key].worked_bands) { output[i].worked_bands[band] = ~~output[i].worked_bands[band] + 1; } for (var band in stats[i][key].confirmed_bands) { output[i].confirmed_bands[band] = ~~output[i].confirmed_bands[band] + 1; } for (var mode in stats[i][key].worked_modes) { output[i].worked_modes[mode] = ~~output[i].worked_modes[mode] + 1; } for (var mode in stats[i][key].confirmed_modes) { output[i].confirmed_modes[mode] = ~~output[i].confirmed_modes[mode] + 1; } for (var type in stats[i][key].worked_types) { output[i].worked_types[type] = ~~output[i].worked_types[type] + 1; } for (var type in stats[i][key].confirmed_types) { output[i].confirmed_types[type] = ~~output[i].confirmed_types[type] + 1; } } stats[i] = null; } scoreSection = "Modes"; output.MIXED = modet.Mixed; output.DIGITAL = modet.Digital; output.PHONE = modet.Phone; output.CW = modet.CW; output.Other = modet.Other; for (var i in output) { output[i].worked_band_count = Object.keys(output[i].worked_bands).length; output[i].confirmed_band_count = Object.keys( output[i].confirmed_bands ).length; output[i].worked_mode_count = Object.keys(output[i].worked_modes).length; output[i].confirmed_mode_count = Object.keys( output[i].confirmed_modes ).length; output[i].worked_type_count = Object.keys(output[i].worked_types).length; output[i].confirmed_type_count = Object.keys( output[i].confirmed_types ).length; } var TypeNames = { 0: ["MIXED", $.i18n("gt.typeNames.Mixed"), ""], 1: ["DIGITAL", $.i18n("gt.typeNames.Digital"), ""], 2: ["PHONE", $.i18n("gt.typeNames.Phone"), ""], 3: ["CW", $.i18n("gt.typeNames.CW"), ""], 4: ["Other", $.i18n("gt.typeNames.Other"), ""] }; var AwardNames = { 0: ["WRFA", $.i18n("gt.awardNames.WRFA"), "WRFA", "yellow"], 1: ["GRID", $.i18n("gt.awardNames.Grid"), "GSA", "cyan"], 2: ["DXCC", $.i18n("gt.awardNames.DXCC"), "DXWA", "orange"], 3: ["CQ", $.i18n("gt.awardNames.CQ"), "WAZ", "lightgreen"], 4: ["ITU", $.i18n("gt.awardNames.ITU"), "ITUz", "#DD44DD"], 5: ["WAC", $.i18n("gt.awardNames.WAC"), "WAC", "cyan"], 6: ["WAS", $.i18n("gt.awardNames.WAS"), "WAS", "lightblue"], 7: ["USC", $.i18n("gt.awardNames.USC"), "USA-CA", "orange"], 8: ["WPX", $.i18n("gt.awardNames.WPX"), "WPX", "yellow"] }; worker = ""; worker += "

" + $.i18n("gt.logbook.title") + "

"; worker += ""; var ws = ""; if (Object.keys(details.callsigns).length > 1) ws = "s"; worker += ""; worker += ""; worker += ""; worker += "
Callsign" + ws + "" + Object.keys(details.callsigns).sort().join(", ") + "
" + $.i18n("gt.logbook.firstContact") + "" + userTimeString(details.oldest * 1000) + "
" + $.i18n("gt.logbook.lastContact") + "" + userTimeString(details.newest * 1000) + "
"; worker += "
"; worker += "

" + $.i18n("gt.logbook.scoreCard") + "

"; worker += ""; worker += "" + "" + ""; for (var key in AwardNames) { scoreSection = "Award " + AwardNames[key][1]; var infoObject = output[AwardNames[key][0]]; worker += ""; worker += ""; if (infoObject.confirmed_high_key) { worker += ""; } else worker += ""; worker += ""; } scoreSection = "Long Distance"; worker += ""; worker += ""; if (long_distance.confirmed_hash && long_distance.confirmed_unit > 0) { worker += ""; } else worker += ""; scoreSection = "Short Distance"; worker += ""; worker += ""; if (short_distance.confirmed_hash && short_distance.confirmed_unit > 0) { worker += ""; } else worker += ""; worker += ""; worker += "
" + $.i18n("gt.logbook.topScore") + "" + $.i18n("gt.logbook.worked") + "" + $.i18n("gt.logbook.confirmed") + "
" + AwardNames[key][1] + "" + infoObject.worked_high_key + " (" + infoObject.worked_high + ")" + infoObject.confirmed_high_key + " (" + infoObject.confirmed_high + ")
" + $.i18n("gt.score.LongDist") + "" + long_distance.worked_unit + " " + distanceUnit.value.toLowerCase(); worker += " " + GT.QSOhash[long_distance.worked_hash].DEcall + ""; worker += " " + GT.QSOhash[long_distance.worked_hash].grid + "" + long_distance.confirmed_unit + " " + distanceUnit.value.toLowerCase(); worker += " " + GT.QSOhash[long_distance.confirmed_hash].DEcall + ""; worker += " " + GT.QSOhash[long_distance.confirmed_hash].grid + "
" + $.i18n("gt.score.ShortDist") + "" + short_distance.worked_unit + " " + distanceUnit.value.toLowerCase(); worker += " " + GT.QSOhash[short_distance.worked_hash].DEcall + ""; worker += " " + GT.QSOhash[short_distance.worked_hash].grid + "" + short_distance.confirmed_unit + " " + distanceUnit.value.toLowerCase(); worker += " " + GT.QSOhash[short_distance.confirmed_hash].DEcall + ""; worker += " " + GT.QSOhash[short_distance.confirmed_hash].grid + "
"; worker += "
"; worker += "

" + $.i18n("gt.AwardTypes") + "

"; scoreSection = "Award Types"; for (var key in AwardNames) { worker += createStatTable( AwardNames[key][1], output[AwardNames[key][0]], AwardNames[key][2] ); } worker += "
"; scoreSection = "Mode Types"; worker += "

" + $.i18n("gt.ModeTypes") + "

"; for (var key in TypeNames) { worker += createStatTable( TypeNames[key][1], output[TypeNames[key][0]], TypeNames[key][2] ); } worker += "
"; worker += "

" + $.i18n("gt.Distances") + "

"; scoreSection = "Distances"; worker += createDistanceTable(long_distance, $.i18n("gt.LongestDist")); worker += createDistanceTable(short_distance, $.i18n("gt.ShortestDist")); worker += "
"; } catch (e) { worker += "
In Section: " + scoreSection + "
" + $.i18n("gt.scorecardError"); } setStatsDiv("statViewDiv", worker); setStatsDivHeight("statViewDiv", getStatsWindowHeight() + 29 + "px"); } function hashNameSort(a, b) { if (GT.QSOhash[a].DEcall > GT.QSOhash[b].DEcall) return 1; if (GT.QSOhash[b].DEcall > GT.QSOhash[a].DEcall) return -1; return 0; } function createDistanceTable(obj, name) { var worker = ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += "
" + name + "
" + $.i18n("gt.distanceTable.Worked") + "" + $.i18n("gt.distanceTable.Confirmed") + "
" + $.i18n("gt.distanceTable.Bands") + ""; var keys = Object.keys(obj.band).sort(numberSort); for (var key in keys) { var grid = GT.QSOhash[obj.band[keys[key]].worked_hash].grid; var call = GT.QSOhash[obj.band[keys[key]].worked_hash].DEcall; worker += ""; worker += ""; worker += ""; worker += ""; } worker += "
" + keys[key] + "(" + obj.band[keys[key]].worked_unit + " " + distanceUnit.value.toLowerCase() + ")" + call + "" + grid + "
"; for (var key in keys) { if (keys[key] in obj.band && obj.band[keys[key]].confirmed_hash) { var grid = GT.QSOhash[obj.band[keys[key]].confirmed_hash].grid; var call = GT.QSOhash[obj.band[keys[key]].confirmed_hash].DEcall; worker += ""; worker += ""; worker += ""; worker += ""; } else worker += ""; } worker += "
" + keys[key] + "(" + obj.band[keys[key]].confirmed_unit + " " + distanceUnit.value.toLowerCase() + ")" + call + "" + grid + "
 
" + $.i18n("gt.distanceTable.Modes") + ""; keys = Object.keys(obj.mode).sort(); for (var key in keys) { var grid = GT.QSOhash[obj.mode[keys[key]].worked_hash].grid; var call = GT.QSOhash[obj.mode[keys[key]].worked_hash].DEcall; worker += ""; worker += ""; worker += ""; worker += ""; } worker += "
" + keys[key] + "(" + obj.mode[keys[key]].worked_unit + " " + distanceUnit.value.toLowerCase() + ")" + call + "" + grid + "
"; for (var key in keys) { if (keys[key] in obj.mode && obj.mode[keys[key]].confirmed_hash) { var grid = GT.QSOhash[obj.mode[keys[key]].confirmed_hash].grid; var call = GT.QSOhash[obj.mode[keys[key]].confirmed_hash].DEcall; worker += ""; worker += ""; worker += ""; worker += ""; } else worker += ""; } worker += "
" + keys[key] + "(" + obj.mode[keys[key]].confirmed_unit + " " + distanceUnit.value.toLowerCase() + ")" + call + "" + grid + "
 
" + $.i18n("gt.distanceTable.Types") + ""; keys = Object.keys(obj.type).sort(); for (var key in keys) { var grid = GT.QSOhash[obj.type[keys[key]].worked_hash].grid; var call = GT.QSOhash[obj.type[keys[key]].worked_hash].DEcall; worker += ""; worker += ""; worker += ""; worker += ""; } worker += "
" + keys[key] + "(" + obj.type[keys[key]].worked_unit + " " + distanceUnit.value.toLowerCase() + ")" + call + "" + grid + "
"; for (var key in keys) { if (keys[key] in obj.type && obj.type[keys[key]].confirmed_hash) { var grid = GT.QSOhash[obj.type[keys[key]].confirmed_hash].grid; var call = GT.QSOhash[obj.type[keys[key]].confirmed_hash].DEcall; worker += ""; worker += ""; worker += ""; worker += ""; } else worker += ""; } worker += "
" + keys[key] + "(" + obj.type[keys[key]].confirmed_unit + " " + distanceUnit.value.toLowerCase() + ")" + call + "" + grid + "
 
"; return worker; } function numberSort(a, b) { // cut off 'm' from 80m or 70cm var metersA = a.slice(0, -1); var metersB = b.slice(0, -1); // if last letter is c we have a centimeter band, multiply value with 0.01 if (metersA.slice(-1) == "c") { metersA = 0.01 * parseInt(metersA); } else { metersA = parseInt(metersA); } if (metersB.slice(-1) == "c") { metersB = 0.01 * parseInt(metersB); } else { metersA = parseInt(metersA); } if (metersA > metersB) return 1; if (metersB > metersA) return -1; return 0; } function createStatTable(title, infoObject, awardName) { var wc1Table = ""; if (infoObject.worked) { wc1Table = ""; wc1Table += ""; var award = ""; wc1Table += "" + award + ""; wc1Table += ""; wc1Table += ""; wc1Table += ""; wc1Table += ""; wc1Table += ""; wc1Table += ""; wc1Table += ""; wc1Table += ""; wc1Table += ""; if (infoObject.worked_type_count > 0) { wc1Table += ""; wc1Table += ""; wc1Table += ""; wc1Table += ""; wc1Table += ""; } wc1Table += "
" + title + "
" + $.i18n("gt.statTable.Worked") + " (" + infoObject.worked + ")" + $.i18n("gt.statTable.Confirmed") + " (" + infoObject.confirmed + ")
" + $.i18n("gt.statTable.Bands") + ""; var keys = Object.keys(infoObject.worked_bands).sort(numberSort); for (var key in keys) { wc1Table += ""; } wc1Table += "
" + keys[key] + " (" + infoObject.worked_bands[keys[key]] + ")
"; for (var key in keys) { if (keys[key] in infoObject.confirmed_bands) { wc1Table += ""; } else wc1Table += ""; } wc1Table += "
" + keys[key] + " (" + infoObject.confirmed_bands[keys[key]] + ")
 
" + $.i18n("gt.statTable.Modes") + ""; keys = Object.keys(infoObject.worked_modes).sort(); for (var key in keys) { wc1Table += ""; } wc1Table += "
" + keys[key] + " (" + infoObject.worked_modes[keys[key]] + ")
"; for (var key in keys) { if (keys[key] in infoObject.confirmed_modes) { wc1Table += ""; } else wc1Table += ""; } wc1Table += "
" + keys[key] + " (" + infoObject.confirmed_modes[keys[key]] + ")
 
" + $.i18n("gt.statTable.Types") + ""; var keys = Object.keys(infoObject.worked_types).sort(); for (var key in keys) { wc1Table += ""; } wc1Table += "
" + keys[key] + " (" + infoObject.worked_types[keys[key]] + ") " + "
"; for (var key in keys) { if (keys[key] in infoObject.confirmed_types) { wc1Table += ""; } else wc1Table += ""; } wc1Table += "
" + keys[key] + " (" + infoObject.confirmed_types[keys[key]] + ") " + "
 
"; } return wc1Table; } function validatePropMode(propMode) { if (GT.appSettings.gtPropFilter == "mixed") return true; return GT.appSettings.gtPropFilter == propMode; } function validateMapBandAndMode(band, mode) { if ((GT.appSettings.gtBandFilter.length == 0 || (GT.appSettings.gtBandFilter == "auto" ? GT.appSettings.myBand == band : GT.appSettings.gtBandFilter == band))) { if (GT.appSettings.gtModeFilter.length == 0) return true; if (GT.appSettings.gtModeFilter == "auto") return GT.appSettings.myMode == mode; if (GT.appSettings.gtModeFilter == "Digital") { if (mode in GT.modes && GT.modes[mode]) return true; return false; } if (GT.appSettings.gtModeFilter == "Phone") { if (mode in GT.modes_phone && GT.modes_phone[mode]) return true; return false; } if (GT.appSettings.gtModeFilter == "CW" && mode == "CW") return true; return GT.appSettings.gtModeFilter == mode; } else { return false; } } function redrawGrids() { if (GT.appSettings.gridViewMode == 2) removePaths(); clearGrids(); clearQsoGrids(); GT.QSLcount = 0; GT.QSOcount = 0; for (var i in GT.QSOhash) { var finalGrid = GT.QSOhash[i].grid; var worked = GT.QSOhash[i].worked; var didConfirm = GT.QSOhash[i].confirmed; var band = GT.QSOhash[i].band; var mode = GT.QSOhash[i].mode; GT.QSOcount++; if (didConfirm) GT.QSLcount++; if (validateMapBandAndMode(GT.QSOhash[i].band, GT.QSOhash[i].mode) && validatePropMode(GT.QSOhash[i].propMode)) { if (GT.appSettings.gridViewMode > 1) { GT.QSOhash[i].rect = qthToQsoBox( GT.QSOhash[i].grid, i, false, GT.QSOhash[i].DXcall, GT.QSOhash[i].worked, GT.QSOhash[i].confirmed, GT.QSOhash[i].band, GT.QSOhash[i].wspr ); for (var vucc in GT.QSOhash[i].vucc_grids) { qthToQsoBox( GT.QSOhash[i].vucc_grids[vucc], i, false, GT.QSOhash[i].DXcall, GT.QSOhash[i].worked, GT.QSOhash[i].confirmed, GT.QSOhash[i].band, GT.QSOhash[i].wspr ); } } var state = GT.QSOhash[i].state; var cont = GT.QSOhash[i].cont; var finalDxcc = GT.QSOhash[i].dxcc; var cnty = GT.QSOhash[i].cnty; var ituz = GT.QSOhash[i].ituz; var cqz = GT.QSOhash[i].cqz; if (state != null && isKnownCallsignUS(finalDxcc)) { if (state.substr(0, 2) != "US") state = "US-" + state; if (state in GT.StateData) { var name = GT.StateData[state].name; if (name in GT.wasZones) { GT.wasZones[name].worked |= worked; if (worked) { GT.wasZones[name].worked_bands[band] = ~~GT.wasZones[name].worked_bands[band] + 1; GT.wasZones[name].worked_modes[mode] = ~~GT.wasZones[name].worked_modes[mode] + 1; } GT.wasZones[name].confirmed |= didConfirm; if (didConfirm) { GT.wasZones[name].confirmed_bands[band] = ~~GT.wasZones[name].confirmed_bands[band] + 1; GT.wasZones[name].confirmed_modes[mode] = ~~GT.wasZones[name].confirmed_modes[mode] + 1; } } } } if (cnty != null) { if (cnty in GT.cntyToCounty) { GT.countyData[cnty].worked |= worked; if (worked) { GT.countyData[cnty].worked_bands[band] = ~~GT.countyData[cnty].worked_bands[band] + 1; GT.countyData[cnty].worked_modes[mode] = ~~GT.countyData[cnty].worked_modes[mode] + 1; } GT.countyData[cnty].confirmed |= didConfirm; if (didConfirm) { GT.countyData[cnty].confirmed_bands[band] = ~~GT.countyData[cnty].confirmed_bands[band] + 1; GT.countyData[cnty].confirmed_modes[mode] = ~~GT.countyData[cnty].confirmed_modes[mode] + 1; } } } if (cont != null) { if (cont in GT.shapeData) { var name = GT.shapeData[cont].properties.name; if (name in GT.wacZones) { GT.wacZones[name].worked |= worked; if (worked) { GT.wacZones[name].worked_bands[band] = ~~GT.wacZones[name].worked_bands[band] + 1; GT.wacZones[name].worked_modes[mode] = ~~GT.wacZones[name].worked_modes[mode] + 1; } GT.wacZones[name].confirmed |= didConfirm; if (didConfirm) { GT.wacZones[name].confirmed_bands[band] = ~~GT.wacZones[name].confirmed_bands[band] + 1; GT.wacZones[name].confirmed_modes[mode] = ~~GT.wacZones[name].confirmed_modes[mode] + 1; } } } } GT.dxccInfo[finalDxcc].worked |= worked; if (worked) { GT.dxccInfo[finalDxcc].worked_bands[band] = ~~GT.dxccInfo[finalDxcc].worked_bands[band] + 1; GT.dxccInfo[finalDxcc].worked_modes[mode] = ~~GT.dxccInfo[finalDxcc].worked_modes[mode] + 1; } GT.dxccInfo[finalDxcc].confirmed |= didConfirm; if (didConfirm) { GT.dxccInfo[finalDxcc].confirmed_bands[band] = ~~GT.dxccInfo[finalDxcc].confirmed_bands[band] + 1; GT.dxccInfo[finalDxcc].confirmed_modes[mode] = ~~GT.dxccInfo[finalDxcc].confirmed_modes[mode] + 1; } if (cqz && cqz.length > 0) { GT.cqZones[cqz].worked |= worked; if (worked) { GT.cqZones[cqz].worked_bands[band] = ~~GT.cqZones[cqz].worked_bands[band] + 1; GT.cqZones[cqz].worked_modes[mode] = ~~GT.cqZones[cqz].worked_modes[mode] + 1; } GT.cqZones[cqz].confirmed |= didConfirm; if (didConfirm) { GT.cqZones[cqz].confirmed_bands[band] = ~~GT.cqZones[cqz].confirmed_bands[band] + 1; GT.cqZones[cqz].confirmed_modes[mode] = ~~GT.cqZones[cqz].confirmed_modes[mode] + 1; } } if (ituz && ituz.length > 0) { GT.ituZones[ituz].worked |= worked; if (worked) { GT.ituZones[ituz].worked_bands[band] = ~~GT.ituZones[ituz].worked_bands[band] + 1; GT.ituZones[ituz].worked_modes[mode] = ~~GT.ituZones[ituz].worked_modes[mode] + 1; } GT.ituZones[ituz].confirmed |= didConfirm; if (didConfirm) { GT.ituZones[ituz].confirmed_bands[band] = ~~GT.ituZones[ituz].confirmed_bands[band] + 1; GT.ituZones[ituz].confirmed_modes[mode] = ~~GT.ituZones[ituz].confirmed_modes[mode] + 1; } } if (finalGrid.length > 0) { var gridCheck = finalGrid.substr(0, 4); if (gridCheck in GT.us48Data) { GT.us48Data[gridCheck].worked |= worked; if (worked) { GT.us48Data[gridCheck].worked_bands[band] = ~~GT.us48Data[gridCheck].worked_bands[band] + 1; GT.us48Data[gridCheck].worked_modes[mode] = ~~GT.us48Data[gridCheck].worked_modes[mode] + 1; } GT.us48Data[gridCheck].confirmed |= didConfirm; if (didConfirm) { GT.us48Data[gridCheck].confirmed_bands[band] = ~~GT.us48Data[gridCheck].confirmed_bands[band] + 1; GT.us48Data[gridCheck].confirmed_modes[mode] = ~~GT.us48Data[gridCheck].confirmed_modes[mode] + 1; } } } for (var key in GT.QSOhash[i].vucc_grids) { var grid = GT.QSOhash[i].vucc_grids[key].substr(0, 4); if (grid in GT.us48Data) { GT.us48Data[grid].worked |= worked; if (worked) { GT.us48Data[grid].worked_bands[band] = ~~GT.us48Data[grid].worked_bands[band] + 1; GT.us48Data[grid].worked_modes[mode] = ~~GT.us48Data[grid].worked_modes[mode] + 1; } GT.us48Data[grid].confirmed |= didConfirm; if (didConfirm) { GT.us48Data[grid].confirmed_bands[band] = ~~GT.us48Data[grid].confirmed_bands[band] + 1; GT.us48Data[grid].confirmed_modes[mode] = ~~GT.us48Data[grid].confirmed_modes[mode] + 1; } } } } } for (var layer in GT.viewInfo) { var search = GT[GT.viewInfo[layer][0]]; var worked = (confirmed = 0); if (layer == 0) { for (var key in search) { if (search[key].rectangle.worked) worked++; if (search[key].rectangle.confirmed) confirmed++; } GT.viewInfo[layer][2] = worked; GT.viewInfo[layer][3] = confirmed; } else if (layer == 5) { for (var key in search) { if (search[key].geo != "deleted") { if (search[key].worked) worked++; if (search[key].confirmed) confirmed++; } } GT.viewInfo[layer][2] = worked; GT.viewInfo[layer][3] = confirmed; } else { for (var key in search) { if (search[key].worked) worked++; if (search[key].confirmed) confirmed++; } GT.viewInfo[layer][2] = worked; GT.viewInfo[layer][3] = confirmed; } } for (var i in GT.liveCallsigns) { if (GT.appSettings.gridViewMode != 2 && validateMapBandAndMode(GT.liveCallsigns[i].band, GT.liveCallsigns[i].mode)) { if (GT.appSettings.gridViewMode == 1 || GT.appSettings.gridViewMode == 3) { GT.liveCallsigns[i].rect = qthToBox( GT.liveCallsigns[i].grid, GT.liveCallsigns[i].DEcall, false, false, GT.liveCallsigns[i].DXcall, GT.liveCallsigns[i].band, GT.liveCallsigns[i].wspr, i ); } } } reloadInfo(false); setHomeGridsquare(); setTrophyOverlay(GT.currentOverlay); updateCountStats(); } function toggleAlertMute() { GT.appSettings.alertMute ^= 1; alertMuteImg.src = GT.alertImageArray[GT.appSettings.alertMute]; if (GT.appSettings.alertMute == 1) { chrome.tts.stop(); } } function togglePushPinMode() { GT.pushPinMode = !GT.pushPinMode; GT.appSettings.pushPinMode = GT.pushPinMode; pinImg.src = GT.pinImageArray[GT.pushPinMode == false ? 0 : 1]; clearTempGrids(); redrawGrids(); } function stopAsking(checkbox) { GT.appSettings.stopAskingVersion = checkbox.checked; } function toggleGtShareEnable() { if (GT.appSettings.gtShareEnable == true) { GT.appSettings.gtShareEnable = false; } else GT.appSettings.gtShareEnable = true; setGtShareButtons(); goProcessRoster(); } function setGtShareButtons() { if (GT.appSettings.gtShareEnable == true && GT.mapSettings.offlineMode == false) { if (GT.appSettings.gtMsgEnable == true) { msgButton.style.display = "inline-block"; } else msgButton.style.display = "none"; gtFlagButton.style.display = "inline-block"; if (GT.appSettings.gtFlagImgSrc > 0) { GT.layerVectors.gtflags.setVisible(true); } else { GT.layerVectors.gtflags.setVisible(false); } } else { GT.oamsBandActivityData = null; renderBandActivity(); msgButton.style.display = "none"; gtFlagButton.style.display = "none"; GT.layerVectors.gtflags.setVisible(false); clearGtFlags(); // Clear list GT.gtFlagPins = Object() GT.gtMessages = Object(); GT.gtUnread = Object(); GT.gtCallsigns = Object(); GT.gtSentAwayToCid = Object(); if (GT.chatWindowHandle != null) { try { GT.chatWindowHandle.hide(); GT.chatWindowHandle.window.allCallDiv.innerHTML = ""; GT.chatWindowHandle.window.updateCount(); } catch (e) { console.error(e); } } goProcessRoster(); } gtShareFlagImg.src = GT.gtShareFlagImageArray[GT.appSettings.gtShareEnable == false ? 0 : 1]; } function setMulticastIp() { GT.appSettings.wsjtIP = multicastIpInput.value; } function setMulticastEnable(checkbox) { if (checkbox.checked == true) { multicastTD.style.display = "block"; if (ValidateMulticast(multicastIpInput)) { GT.appSettings.wsjtIP = multicastIpInput.value; } else { GT.appSettings.wsjtIP = ""; } } else { multicastTD.style.display = "none"; GT.appSettings.wsjtIP = ""; } GT.appSettings.multicast = checkbox.checked; } function setUdpForwardEnable(checkbox) { if (checkbox.checked) { if ( ValidatePort( udpForwardPortInput, null, CheckForwardPortIsNotReceivePort ) && ValidateIPaddress(udpForwardIpInput, null) ) { GT.appSettings.wsjtForwardUdpEnable = checkbox.checked; return; } } checkbox.checked = false; GT.appSettings.wsjtForwardUdpEnable = checkbox.checked; } function setGTspotEnable(checkbox) { GT.appSettings.gtSpotEnable = checkbox.checked; if (GT.appSettings.gtSpotEnable == false) { GT.spotCollector = {}; GT.spotDetailsCollector = {}; GT.decodeCollector = {}; } GT.gtLiveStatusUpdate = true; } function setOamsBandActivity(checkbox) { GT.appSettings.oamsBandActivity = checkbox.checked; if (GT.appSettings.oamsBandActivity == false) { bandActivityNeighborDiv.style.display = "none"; GT.oamsBandActivityData = null; } else { bandActivityNeighborDiv.style.display = ""; oamsBandActivityCheck(); } renderBandActivity(); } function setOamsBandActivityNeighbors(checkbox) { GT.appSettings.oamsBandActivityNeighbors = checkbox.checked; oamsBandActivityCheck(); } function setOamsSimplepush(checkbox) { GT.msgSettings.msgSimplepush = checkbox.checked; simplePushDiv.style.display = (GT.msgSettings.msgSimplepush == true ? "inline-block" : "none"); localStorage.msgSettings = JSON.stringify(GT.msgSettings); } function setOamsSimplepushChat(checkbox) { GT.msgSettings.msgSimplepushChat = checkbox.checked; // One must be checked, otherwise why is the service enabled? if (GT.msgSettings.msgSimplepushChat == false && GT.msgSettings.msgSimplepushRoster == false) { GT.msgSettings.msgSimplepushRoster = msgSimplepushRoster.checked = true; } localStorage.msgSettings = JSON.stringify(GT.msgSettings); } function setOamsSimplepushRoster(checkbox) { GT.msgSettings.msgSimplepushRoster = checkbox.checked; // One must be checked, otherwise why is the service enabled? if (GT.msgSettings.msgSimplepushRoster == false && GT.msgSettings.msgSimplepushChat == false) { GT.msgSettings.msgSimplepushChat = msgSimplepushChat.checked = true; } localStorage.msgSettings = JSON.stringify(GT.msgSettings); } function setOamsPushover(checkbox) { GT.msgSettings.msgPushover = checkbox.checked; pushOverDiv.style.display = (GT.msgSettings.msgPushover == true ? "inline-block" : "none"); localStorage.msgSettings = JSON.stringify(GT.msgSettings); } function setOamsPushoverChat(checkbox) { GT.msgSettings.msgPushoverChat = checkbox.checked; // One must be checked, otherwise why is the service enabled? if (GT.msgSettings.msgPushoverChat == false && GT.msgSettings.msgPushoverRoster == false) { GT.msgSettings.msgPushoverRoster = msgPushoverRoster.checked = true; } localStorage.msgSettings = JSON.stringify(GT.msgSettings); } function setOamsPushoverRoster(checkbox) { GT.msgSettings.msgPushoverRoster = checkbox.checked; // One must be checked, otherwise why is the service enabled? if (GT.msgSettings.msgPushoverRoster == false && GT.msgSettings.msgPushoverChat == false) { GT.msgSettings.msgPushoverChat = msgPushoverChat.checked = true; } localStorage.msgSettings = JSON.stringify(GT.msgSettings); } function setMsgEnable(checkbox) { GT.appSettings.gtMsgEnable = checkbox.checked; if (GT.appSettings.gtShareEnable == true) { if (GT.appSettings.gtMsgEnable == true) { msgButton.style.display = "inline-block"; } else { msgButton.style.display = "none"; if (GT.chatWindowHandle != null) { GT.chatWindowHandle.hide(); } } } goProcessRoster(); GT.gtLiveStatusUpdate = true; setMsgSettingsView(); } function newMessageSetting(whichSetting) { if (whichSetting.id in GT.msgSettings) { GT.msgSettings[whichSetting.id] = whichSetting.value; localStorage.msgSettings = JSON.stringify(GT.msgSettings); setMsgSettingsView(); } } function checkForNewVersion(showUptoDate = false) { if (typeof nw != "undefined") { getBuffer( "https://storage.googleapis.com/gt_app/version.txt", versionCheck, showUptoDate, "http", 80 ); } } function downloadAcknowledgements() { if (GT.mapSettings.offlineMode == false) { getBuffer( "https://storage.googleapis.com/gt_app/acknowledgements.json", updateAcks, null, "http", 80 ); nodeTimers.setTimeout(downloadAcknowledgements, 86400000); } } GT.non_us_bands = [ "630m", "160m", "80m", "60m", "40m", "30m", "20m", "17m", "15m", "12m", "10m", "6m", "4m", "2m" ]; GT.us_bands = [ "630m", "160m", "80m", "60m", "40m", "30m", "20m", "17m", "15m", "12m", "10m", "6m", "2m" ]; function renderBandActivity() { var buffer = ""; if (typeof GT.bandActivity.lines[GT.appSettings.myMode] != "undefined" || GT.oamsBandActivityData != null) { var lines = (GT.appSettings.myMode in GT.bandActivity.lines) ? GT.bandActivity.lines[GT.appSettings.myMode] : []; var bands = (GT.myDXCC in GT.callsignDatabaseUSplus) ? GT.us_bands : GT.non_us_bands; var bandData = {}; var maxValue = 0; for (var i = 0; i < bands.length; i++) { bandData[bands[i]] = { pskScore: 0, pskSpots: 0, pskTx: 0, pskRx: 0, oamsRxSpots: 0, oamsTxSpots: 0, oamsTx: 0, oamsRx: 0, oamsDecodes: 0, oamsScore: 0 }; } for (var x = 0; x < lines.length; x++) { var firstChar = lines[x].charCodeAt(0); if (firstChar != 35 && lines[x].length > 1) { // doesn't begins with # and has something var values = lines[x].trim().split(" "); var band = formatBand(Number(Number(values[0]) / 1000000)); if (band in bandData) { var place = bandData[band]; place.pskScore += Number(values[1]); place.pskSpots += Number(values[2]); place.pskTx += Number(values[3]); place.pskRx += Number(values[4]); if (maxValue < place.pskScore) maxValue = place.pskScore; if (maxValue < place.pskSpots) maxValue = place.pskSpots; } } } if (GT.appSettings.gtShareEnable == true && GT.appSettings.oamsBandActivity == true && GT.oamsBandActivityData) { for (const grid in GT.oamsBandActivityData) { for (const band in GT.oamsBandActivityData[grid]) { if (band in bandData) { var place = bandData[band]; var data = GT.oamsBandActivityData[grid][band]; place.oamsScore ??= 0; place.oamsDecodes += data.d; place.oamsRxSpots += data.rS; place.oamsTxSpots += data.tS; place.oamsTx += data.t; place.oamsRx += data.r; if (data.r > 0) { place.oamsScore += parseInt((data.d > data.rS) ? (data.d / data.r) + (data.t > 0 ? data.tS / data.t : 0) : (data.rS / data.r) + (data.t > 0 ? data.tS / data.t : 0)); } else { place.oamsScore += parseInt(data.t > 0 ? data.tS / data.t : 0); } if (maxValue < place.oamsScore) maxValue = place.oamsScore; } } } } let scaleFactor = 1.0; if (maxValue > 26) { scaleFactor = 26 / maxValue; } for (const band in bandData) { let blockMyBand = (band == GT.appSettings.myBand) ? " class='myBand' " : ""; let title; let blueBarValue; if (GT.appSettings.gtShareEnable == true && GT.appSettings.oamsBandActivity == true) { title = "OAMS\n"; title += "\tScore: " + bandData[band].oamsScore + "\n\tDecodes: " + bandData[band].oamsDecodes + "\n\tTX-Spots: " + bandData[band].oamsTxSpots + "\n\tRX-Spots: " + bandData[band].oamsRxSpots + "\n\tTx: " + bandData[band].oamsTx + "\tRx: " + bandData[band].oamsRx; title += "\nPSK-Reporter\n"; title += "\tScore: " + bandData[band].pskScore + "\n\tSpots: " + bandData[band].pskSpots + "\n\tTx: " + bandData[band].pskTx + "\tRx: " + bandData[band].pskRx; blueBarValue = (bandData[band].oamsScore * scaleFactor + 1); } else { title = "Score: " + bandData[band].pskScore + "\nSpots: " + bandData[band].pskSpots + "\nTx: " + bandData[band].pskTx + "\tRx: " + bandData[band].pskRx; blueBarValue = (bandData[band].pskSpots * scaleFactor + 1); } buffer += "
"; buffer += "
"; buffer += "
"; buffer += "
" + parseInt(band) + "
"; buffer += "
"; } } else { buffer = "..no data yet.."; } graphDiv.innerHTML = buffer; if (GT.baWindowInitialized == true) { GT.baWindowHandle.window.graphDiv.innerHTML = buffer; } } function pskBandActivityCallback(buffer, flag) { var result = String(buffer); if (result.indexOf("frequency score") > -1) { // looks good so far GT.bandActivity.lines[GT.appSettings.myMode] = result.split("\n"); GT.bandActivity.lastUpdate[GT.appSettings.myMode] = GT.timeNow + 600; localStorage.bandActivity = JSON.stringify(GT.bandActivity); } renderBandActivity(); } /* FIXME ****************************************************************************** Should we somewhere in settings, have a checkbox to enable / disable PSK spots specifically? We can disable the overall spots, both PSK and OAMS, and OAMS has a checkbox in the OAMS tab. I'm thinking for the situation where I only want to pull in OAMS spots and not PSK reporter's spots. Answer: this the Band Activity, not PSK Spots, different API. But we can revisit as we now have OAMS Band Activity - Tag ************************************************************************************ */ function pskGetBandActivity() { if (GT.mapSettings.offlineMode == true) return; if (typeof GT.bandActivity.lastUpdate[GT.appSettings.myMode] == "undefined") { GT.bandActivity.lastUpdate[GT.appSettings.myMode] = 0; } if (GT.appSettings.myMode.length > 0 && GT.appSettings.myGrid.length > 0 && GT.timeNow > GT.bandActivity.lastUpdate[GT.appSettings.myMode]) { getBuffer( "https://pskreporter.info/cgi-bin/psk-freq.pl?mode=" + GT.appSettings.myMode + "&grid=" + GT.appSettings.myGrid.substr(0, 4) + "&cb=" + timeNowSec(), pskBandActivityCallback, null, "https", 443 ); } renderBandActivity(); if (GT.pskBandActivityTimerHandle != null) { nodeTimers.clearInterval(GT.pskBandActivityTimerHandle); } GT.pskBandActivityTimerHandle = nodeTimers.setInterval(pskGetBandActivity, 601000); // every 20 minutes, 1 second } function getIniFromApp(appName) { var result = Array(); result.port = -1; result.ip = ""; result.MyCall = "NOCALL"; result.MyGrid = ""; result.MyBand = ""; result.MyMode = ""; result.IniPath = ""; result.N1MMServer = ""; result.N1MMServerPort = 0; result.BroadcastToN1MM = false; result.appName = appName; var wsjtxCfgPath = ""; var data = String(nw.App.dataPath); var end = 0; if (GT.platform == "windows") { end = data.indexOf("GridTracker\\User Data\\Default"); if (end > -1) { wsjtxCfgPath = data.substr(0, end) + appName + "\\" + appName + ".ini"; } } else if (GT.platform == "mac") { wsjtxCfgPath = process.env.HOME + "/Library/Preferences/WSJT-X.ini"; } else { wsjtxCfgPath = process.env.HOME + "/.config/" + appName + ".ini"; } if (fs.existsSync(wsjtxCfgPath)) { var fileBuf = fs.readFileSync(wsjtxCfgPath, "ascii"); var fileArray = fileBuf.split("\n"); for (var key in fileArray) fileArray[key] = fileArray[key].trim(); result.IniPath = data.substr(0, end) + appName + "\\"; for (var x = 0; x < fileArray.length; x++) { var indexOfPort = fileArray[x].indexOf("UDPServerPort="); if (indexOfPort == 0) { var portSplit = fileArray[x].split("="); result.port = portSplit[1]; } indexOfPort = fileArray[x].indexOf("UDPServer="); if (indexOfPort == 0) { var portSplit = fileArray[x].split("="); result.ip = portSplit[1]; } indexOfPort = fileArray[x].indexOf("MyCall="); if (indexOfPort == 0) { var portSplit = fileArray[x].split("="); result.MyCall = portSplit[1]; } indexOfPort = fileArray[x].indexOf("MyGrid="); if (indexOfPort == 0) { var portSplit = fileArray[x].split("="); result.MyGrid = portSplit[1].substr(0, 6); } indexOfPort = fileArray[x].indexOf("Mode="); if (indexOfPort == 0) { var portSplit = fileArray[x].split("="); result.MyMode = portSplit[1]; } indexOfPort = fileArray[x].indexOf("DialFreq="); if (indexOfPort == 0) { var portSplit = fileArray[x].split("="); result.MyBand = formatBand(Number(portSplit[1] / 1000000)); } indexOfPort = fileArray[x].indexOf("N1MMServerPort="); if (indexOfPort == 0) { var portSplit = fileArray[x].split("="); result.N1MMServerPort = portSplit[1]; } indexOfPort = fileArray[x].indexOf("N1MMServer="); if (indexOfPort == 0) { var portSplit = fileArray[x].split("="); result.N1MMServer = portSplit[1]; } indexOfPort = fileArray[x].indexOf("BroadcastToN1MM="); if (indexOfPort == 0) { var portSplit = fileArray[x].split("="); result.BroadcastToN1MM = portSplit[1] == "true"; } } } return result; } function checkRunningProcesses() { var child_process = require("child_process"); var list = GT.platform == "windows" ? child_process.execFileSync("tasklist.exe") : child_process.execFileSync("ps", ["-aef"]); GT.wsjtxProcessRunning = list.indexOf("wsjtx") > -1; GT.jtdxProcessRunning = list.indexOf("jtdx") > -1; } function updateRunningProcesses() { try { checkRunningProcesses(); } catch (e) { GT.wsjtxProcessRunning = false; GT.jtdxProcessRunning = false; } runningAppsDiv.innerHTML = "WSJT-X "; if (GT.wsjtxProcessRunning == true) runningAppsDiv.innerHTML += " - up - "; else runningAppsDiv.innerHTML += " - ? - "; GT.wsjtxIni = getIniFromApp("WSJT-X"); if (GT.wsjtxIni.port > -1) { runningAppsDiv.innerHTML += "(" + GT.wsjtxIni.ip + " / " + GT.wsjtxIni.port + ") "; } else runningAppsDiv.innerHTML += "(?) "; if (GT.platform != "mac") { runningAppsDiv.innerHTML += " / JTDX "; if (GT.jtdxProcessRunning == true) runningAppsDiv.innerHTML += " - up - "; else runningAppsDiv.innerHTML += " - ? - "; GT.jtdxIni = getIniFromApp("JTDX"); if (GT.jtdxIni.port > -1) { runningAppsDiv.innerHTML += "(" + GT.jtdxIni.ip + " / " + GT.jtdxIni.port + ") "; } else runningAppsDiv.innerHTML += "(?) "; } } function updateBasedOnIni() { var which = null; var count = 0; if (GT.wsjtxProcessRunning) { count++; } if (GT.jtdxProcessRunning) { count++; } // UdpPortNotSet if (GT.appSettings.wsjtUdpPort == 0 && count < 2) { if (GT.wsjtxProcessRunning || count == 0) { which = GT.wsjtxIni; } else if (GT.jtdxProcessRunning) { which = GT.jtdxIni; } if (which != null && which.port > -1) { GT.appSettings.wsjtUdpPort = which.port; GT.appSettings.wsjtIP = which.ip; } if (which == null) { GT.appSettings.wsjtUdpPort = 2237; GT.appSettings.wsjtIP = ""; } if (ipToInt(GT.appSettings.wsjtIP) >= ipToInt("224.0.0.0") && ipToInt(GT.appSettings.wsjtIP) < ipToInt("240.0.0.0")) { GT.appSettings.multicast = true; } else { GT.appSettings.multicast = false; } } // Which INI do we load? if (GT.appSettings.wsjtUdpPort) { which = null; if (GT.wsjtxIni.port == GT.appSettings.wsjtUdpPort) { which = GT.wsjtxIni; } else if (GT.jtdxIni.port == GT.appSettings.wsjtUdpPort) { which = GT.jtdxIni; } if (which != null) { GT.appSettings.myCall = which.MyCall; GT.appSettings.myGrid = which.MyGrid; GT.lastBand = GT.appSettings.myBand; GT.lastMode = GT.appSettings.myMode; GT.workingIniPath = which.IniPath; } if (which != null && which.BroadcastToN1MM == true && GT.N1MMSettings.enable == true) { if (which.N1MMServer == GT.N1MMSettings.ip && which.N1MMServerPort == GT.N1MMSettings.port) { buttonN1MMCheckBox.checked = GT.N1MMSettings.enable = false; localStorage.N1MMSettings = JSON.stringify(GT.N1MMSettings); alert(which.appName + " N1MM Logger+ is enabled with same settings, disabled GridTracker N1MM logger"); } } if (which != null) { if (GT.appSettings.wsjtIP == "") { GT.appSettings.wsjtIP = which.ip; } } } if (GT.appSettings.myGrid.length > 0) { setHomeGridsquare(); } } function CheckReceivePortIsNotForwardPort(value) { if (udpForwardIpInput.value == "127.0.0.1" && udpForwardPortInput.value == value && GT.appSettings.wsjtIP == "" && udpForwardEnable.checked) { return false; } return true; } function CheckForwardPortIsNotReceivePort(value) { if (udpForwardIpInput.value == "127.0.0.1" && udpPortInput.value == value && GT.appSettings.wsjtIP == "") { return false; } return true; } function setForwardIp() { GT.appSettings.wsjtForwardUdpIp = udpForwardIpInput.value; if (ValidatePort(udpPortInput, null, CheckReceivePortIsNotForwardPort)) { setUdpPort(); } ValidatePort(udpForwardPortInput, null, CheckForwardPortIsNotReceivePort); } function setForwardPort() { GT.appSettings.wsjtForwardUdpPort = udpForwardPortInput.value; ValidateIPaddress(udpForwardIpInput, null); if (ValidatePort(udpPortInput, null, CheckReceivePortIsNotForwardPort)) { setUdpPort(); } } function validIpKeys(value) { if (value == 46) return true; return value >= 48 && value <= 57; } function validNumberKeys(value) { return value >= 48 && value <= 57; } function validateNumAndLetter(input) { if (/\d/.test(input) && /[A-Z]/.test(input)) return true; else return false; } function validCallsignsKeys(value) { if (value == 44) return true; if (value >= 47 && value <= 57) return true; if (value >= 65 && value <= 90) return true; return value >= 97 && value <= 122; } function ValidateCallsigns(inputText, validDiv) { inputText.value = inputText.value.toUpperCase(); var callsigns = inputText.value.split(","); var passed = false; for (var call in callsigns) { if (callsigns[call].length > 0) { if (/\d/.test(callsigns[call]) && /[A-Z]/.test(callsigns[call])) { passed = true; } else { passed = false; break; } } else { passed = false; break; } } if (passed) { inputText.style.color = "#FF0"; inputText.style.backgroundColor = "green"; } else { inputText.style.color = "#000"; inputText.style.backgroundColor = "yellow"; } return passed; } function ValidateCallsign(inputText, validDiv) { addError.innerHTML = ""; if (inputText.value.length > 0) { var passed = false; inputText.value = inputText.value.toUpperCase(); if (/\d/.test(inputText.value) || /[A-Z]/.test(inputText.value)) { passed = true; } if (passed) { inputText.style.color = "#FF0"; inputText.style.backgroundColor = "green"; if (validDiv) validDiv.innerHTML = "Valid!"; return true; } else { inputText.style.color = "#000"; inputText.style.backgroundColor = "yellow"; if (validDiv) validDiv.innerHTML = "Invalid!"; return false; } } else { inputText.style.color = "#000"; inputText.style.backgroundColor = "yellow"; if (validDiv) validDiv.innerHTML = "Invalid!"; return false; } } function ValidateGridsquareOnly4(inputText, validDiv) { addError.innerHTML = ""; if (inputText.value.length == 4) { var gridSquare = ""; var LETTERS = inputText.value.substr(0, 2).toUpperCase(); var NUMBERS = inputText.value.substr(2, 2).toUpperCase(); if (/^[A-R]+$/.test(LETTERS) && /^[0-9]+$/.test(NUMBERS)) { gridSquare = LETTERS + NUMBERS; } if (gridSquare != "") { inputText.style.color = "#FF0"; inputText.style.backgroundColor = "green"; inputText.value = gridSquare; if (validDiv) validDiv.innerHTML = "Valid!"; return true; } else { inputText.style.color = "#FFF"; inputText.style.backgroundColor = "red"; if (validDiv) validDiv.innerHTML = "Invalid!"; return false; } } else { inputText.style.color = "#000"; inputText.style.backgroundColor = "yellow"; if (validDiv) validDiv.innerHTML = "Valid!"; return true; } } function validateGridFromString(inputText) { var validGrid = false; if (inputText.length == 4 || inputText.length == 6) { var LETTERS = inputText.substr(0, 2); var NUMBERS = inputText.substr(2, 2); if (/^[A-R]+$/.test(LETTERS) && /^[0-9]+$/.test(NUMBERS)) { validGrid = true; } if (validGrid && inputText.length == 6) { var LETTERS_SUB = inputText.substr(4, 2); if (!(/^[A-Xa-x]+$/.test(LETTERS_SUB))) { validGrid = false; } } } return validGrid; } function ValidateGridsquare(inputText, validDiv) { if (inputText.value.length == 4 || inputText.value.length == 6) { var gridSquare = ""; var LETTERS = inputText.value.substr(0, 2).toUpperCase(); var NUMBERS = inputText.value.substr(2, 2).toUpperCase(); if (/^[A-R]+$/.test(LETTERS) && /^[0-9]+$/.test(NUMBERS)) { gridSquare = LETTERS + NUMBERS; } if (inputText.value.length > 4) { var LETTERS_SUB = inputText.value.substr(4, 2); gridSquare = ""; if ( /^[A-R]+$/.test(LETTERS) && /^[0-9]+$/.test(NUMBERS) && /^[A-Xa-x]+$/.test(LETTERS_SUB) ) { gridSquare = LETTERS + NUMBERS + LETTERS_SUB; } } if (gridSquare != "") { inputText.style.color = "#FF0"; inputText.style.backgroundColor = "green"; inputText.value = gridSquare; if (validDiv) validDiv.innerHTML = "Valid!"; return true; } else { inputText.style.color = "#FFF"; inputText.style.backgroundColor = "red"; if (validDiv) validDiv.innerHTML = "Invalid!"; return false; } } else { inputText.style.color = "#FFF"; inputText.style.backgroundColor = "red"; if (validDiv) validDiv.innerHTML = "Invalid!"; return false; } } function ipToInt(ip) { return ip .split(".") .map((octet, index, array) => { return parseInt(octet) * Math.pow(256, array.length - index - 1); }) .reduce((prev, curr) => { return prev + curr; }); } function ValidateMulticast(inputText) { var ipformat = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; if (inputText.value.match(ipformat)) { if (inputText.value != "0.0.0.0" && inputText.value != "255.255.255.255") { var ipInt = ipToInt(inputText.value); if (ipInt >= ipToInt("224.0.0.0") && ipInt < ipToInt("240.0.0.0")) { if (ipInt > ipToInt("224.0.0.255")) { inputText.style.color = "black"; inputText.style.backgroundColor = "yellow"; } else { inputText.style.color = "#FF0"; inputText.style.backgroundColor = "green"; } return true; } else { inputText.style.color = "#FFF"; inputText.style.backgroundColor = "red"; return false; } } else { inputText.style.color = "#FFF"; inputText.style.backgroundColor = "red"; return false; } } else { inputText.style.color = "#FFF"; inputText.style.backgroundColor = "red"; return false; } } function ValidateIPaddress(inputText, checkBox) { var ipformat = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; if (inputText.value.match(ipformat)) { if (inputText.value != "0.0.0.0" && inputText.value != "255.255.255.255") { inputText.style.color = "#FF0"; inputText.style.backgroundColor = "green"; return true; } else { inputText.style.color = "#FFF"; inputText.style.backgroundColor = "red"; if (checkBox) checkBox.checked = false; return false; } } else { inputText.style.color = "#FFF"; inputText.style.backgroundColor = "red"; if (checkBox) checkBox.checked = false; return false; } } function ValidatePort(inputText, checkBox, callBackCheck) { var value = Number(inputText.value); if (value > 1023 && value < 65536) { if (callBackCheck && !callBackCheck(value)) { inputText.style.color = "#FFF"; inputText.style.backgroundColor = "red"; if (checkBox) checkBox.checked = false; return false; } else { inputText.style.color = "#FF0"; inputText.style.backgroundColor = "green"; return true; } } else { inputText.style.color = "#FFF"; inputText.style.backgroundColor = "red"; if (checkBox) checkBox.checked = false; return false; } } function workingCallsignEnableChanged(ele) { GT.appSettings.workingCallsignEnable = ele.checked; applyCallsignsAndDateDiv.style.display = ""; } function workingDateEnableChanged(ele) { GT.appSettings.workingDateEnable = ele.checked; applyCallsignsAndDateDiv.style.display = ""; } function workingDateChanged() { if (workingTimeValue.value.length == 0) { workingTimeValue.value = "00:00"; } if (workingDateValue.value.length == 0) { workingDateValue.value = "1970-01-01"; } var fields = workingDateValue.value.split("-"); var time = workingTimeValue.value.split(":"); GT.appSettings.workingDate = Date.UTC( parseInt(fields[0]), parseInt(fields[1]) - 1, parseInt(fields[2]), parseInt(time[0]), parseInt(time[1]), 0 ) / 1000; displayWorkingDate(); if (GT.appSettings.workingDateEnable) { applyCallsignsAndDateDiv.style.display = ""; } } function displayWorkingDate() { var date = new Date(GT.appSettings.workingDate * 1000); workingDateString.innerHTML = dateToString(date); } GT.tempWorkingCallsigns = {}; function workingCallsignsChanged(ele) { GT.tempWorkingCallsigns = {}; var callsigns = ele.value.split(","); for (var call in callsigns) { GT.tempWorkingCallsigns[callsigns[call]] = true; } if (callsigns.length > 0) { GT.appSettings.workingCallsigns = Object.assign({}, GT.tempWorkingCallsigns); if (GT.appSettings.workingCallsignEnable) { applyCallsignsAndDateDiv.style.display = ""; } } else applyCallsignsAndDateDiv.style.display = "none"; } function applyCallsignsAndDates() { clearAndLoadQSOs(); applyCallsignsAndDateDiv.style.display = "none"; } function selectElementContents(el) { if (document.createRange && window.getSelection) { var range = document.createRange(); var sel = window.getSelection(); sel.removeAllRanges(); range.selectNodeContents(el); sel.addRange(range); var text = sel.toString(); text = text.replace(/\t/g, ","); sel.removeAllRanges(); selectNodeDiv.innerText = text; range.selectNodeContents(selectNodeDiv); sel.addRange(range); document.execCommand("copy"); sel.removeAllRanges(); selectNodeDiv.innerText = ""; } } function popupNewWindows() { if (typeof nw != "undefined") { win.on("new-win-policy", function (frame, url, policy) { policy.forceNewPopup(); }); } } function lockNewWindows() { if (typeof nw != "undefined") { win.on("new-win-policy", newFrame); } } GT.lastUrl = ""; function newFrame(frame, url, policy) { if (url != GT.lastUrl) { nw.Shell.openExternal(url); GT.lastUrl = url; nodeTimers.setTimeout(clearLastUrlTimeOut, 5000); } policy.ignore(); } function clearLastUrlTimeOut() { GT.lastUrl = ""; } function byName(a, b) { if (GT.enums[a] < GT.enums[b]) return -1; if (GT.enums[a] > GT.enums[b]) return 1; return 0; } GT.ancPrefixes = ["P", "M", "MM", "AM", "A", "NWS"]; function callsignToDxcc(insign) { var callsign = insign; if (!/\d/.test(callsign) || !/[a-zA-Z]/.test(callsign)) { return -1; } if (callsign in GT.directCallToDXCC) { return Number(GT.directCallToDXCC[callsign]); } if (callsign.includes("/")) { var parts = callsign.split("/"); var end = parts.length - 1; if (GT.ancPrefixes.includes(parts[end])) { if (parts[end].toUpperCase() == "MM") { return 0; } parts.pop(); end = parts.length - 1; } if (end) { if (isNaN(parts[end])) { if (parts[1].length > parts[0].length) { callsign = parts[0]; } else { if (callsignToDxcc(parts[1]) != -1) callsign = parts[1]; else callsign = parts[0]; } } else callsign = parts[0]; } else callsign = parts[0]; if (callsign in GT.directCallToDXCC) { return Number(GT.directCallToDXCC[callsign]); } } for (var x = callsign.length; x > 0; x--) { if (callsign.substr(0, x) in GT.prefixToMap) { return Number(GT.dxccInfo[GT.prefixToMap[callsign.substr(0, x)]].dxcc); } } return -1; } function cqZoneFromCallsign(insign, dxcc) { var callsign = insign; if (!/\d/.test(callsign) || !/[a-zA-Z]/.test(callsign)) { return null; } if (callsign in GT.directCallToCQzone) { return GT.directCallToCQzone[callsign]; } for (var x = callsign.length; x > 0; x--) { if (callsign.substr(0, x) in GT.prefixToCQzone) { return GT.prefixToCQzone[callsign.substr(0, x)]; } } if (dxcc > 0) { return GT.dxccInfo[dxcc].cqzone; } return null; } function ituZoneFromCallsign(insign, dxcc) { var callsign = insign; if (!/\d/.test(callsign) || !/[a-zA-Z]/.test(callsign)) { return null; } if (callsign in GT.directCallToITUzone) { return GT.directCallToITUzone[callsign]; } for (var x = callsign.length; x > 0; x--) { if (callsign.substr(0, x) in GT.prefixToITUzone) { return GT.prefixToITUzone[callsign.substr(0, x)]; } } if (dxcc > 0) { return GT.dxccInfo[dxcc].ituzone; } return null; } function loadMaidenHeadData() { var file = "./data/mh-root-prefixed.json"; if (fs.existsSync(file)) { var fileBuf = fs.readFileSync(file, "UTF-8"); GT.dxccInfo = JSON.parse(fileBuf); for (var key in GT.dxccInfo) { GT.dxccToAltName[GT.dxccInfo[key].dxcc] = GT.dxccInfo[key].name; GT.dxccToADIFName[GT.dxccInfo[key].dxcc] = GT.dxccInfo[key].aname; GT.altNameToDXCC[GT.dxccInfo[key].name] = GT.dxccInfo[key].dxcc; GT.dxccToCountryCode[GT.dxccInfo[key].dxcc] = GT.dxccInfo[key].cc; for (var x = 0; x < GT.dxccInfo[key].prefix.length; x++) { GT.prefixToMap[GT.dxccInfo[key].prefix[x]] = key; } delete GT.dxccInfo[key].prefix; for (var x = 0; x < GT.dxccInfo[key].direct.length; x++) { GT.directCallToDXCC[GT.dxccInfo[key].direct[x]] = GT.dxccInfo[key].dxcc; } delete GT.dxccInfo[key].direct; for (var val in GT.dxccInfo[key].prefixCQ) { GT.prefixToCQzone[val] = GT.dxccInfo[key].prefixCQ[val]; } delete GT.dxccInfo[key].prefixCQ; for (var val in GT.dxccInfo[key].prefixITU) { GT.prefixToITUzone[val] = GT.dxccInfo[key].prefixITU[val]; } delete GT.dxccInfo[key].prefixITU; for (var val in GT.dxccInfo[key].directCQ) { GT.directCallToCQzone[val] = GT.dxccInfo[key].directCQ[val]; } delete GT.dxccInfo[key].directCQ; for (var val in GT.dxccInfo[key].directITU) { GT.directCallToITUzone[val] = GT.dxccInfo[key].directITU[val]; } delete GT.dxccInfo[key].directITU; for (var x = 0; x < GT.dxccInfo[key].mh.length; x++) { if (!(GT.dxccInfo[key].mh[x] in GT.gridToDXCC)) { GT.gridToDXCC[GT.dxccInfo[key].mh[x]] = Array(); } GT.gridToDXCC[GT.dxccInfo[key].mh[x]].push(GT.dxccInfo[key].dxcc); } if (GT.dxccInfo[key].dxcc != 291) { delete GT.dxccInfo[key].mh; } } file = "./data/dxcc.json"; var files = fs.readFileSync(file); var dxccGeo = JSON.parse(files); for (var key in dxccGeo.features) { var dxcc = dxccGeo.features[key].properties.dxcc_entity_code; GT.dxccInfo[dxcc].geo = dxccGeo.features[key]; } file = "./data/counties.json"; files = fs.readFileSync(file); var countyData = JSON.parse(files); for (var id in countyData) { if (!(countyData[id].properties.st in GT.stateToCounty)) { GT.stateToCounty[countyData[id].properties.st] = Array(); } GT.stateToCounty[countyData[id].properties.st].push(id); var cnty = countyData[id].properties.st + "," + replaceAll(countyData[id].properties.n, " ", "").toUpperCase(); if (!(cnty in GT.cntyToCounty)) { GT.cntyToCounty[cnty] = toProperCase(countyData[id].properties.n); } GT.countyData[cnty] = {}; GT.countyData[cnty].geo = countyData[id]; GT.countyData[cnty].worked = false; GT.countyData[cnty].confirmed = false; GT.countyData[cnty].worked_bands = {}; GT.countyData[cnty].confirmed_bands = {}; GT.countyData[cnty].worked_modes = {}; GT.countyData[cnty].confirmed_modes = {}; for (var x in countyData[id].properties.z) { var zipS = String(countyData[id].properties.z[x]); if (!(zipS in GT.zipToCounty)) { GT.zipToCounty[zipS] = Array(); } GT.zipToCounty[zipS].push(cnty); } } files = null; countyData = null; GT.shapeData = JSON.parse(fs.readFileSync(GT.shapeFile)); GT.StateData = JSON.parse(fs.readFileSync("./data/state.json")); for (var key in GT.StateData) { for (var x = 0; x < GT.StateData[key].mh.length; x++) { if (!(GT.StateData[key].mh[x] in GT.gridToState)) { GT.gridToState[GT.StateData[key].mh[x]] = Array(); } GT.gridToState[GT.StateData[key].mh[x]].push(GT.StateData[key].postal); } } file = "./data/phone.json"; fileBuf = fs.readFileSync(file, "UTF-8"); GT.phonetics = JSON.parse(fileBuf); file = "./data/enums.json"; fileBuf = fs.readFileSync(file, "UTF-8"); GT.enums = JSON.parse(fileBuf); for (var key in GT.dxccInfo) { if (GT.dxccInfo[key].pp != "" && GT.dxccInfo[key].geo != "deleted") { GT.enums[GT.dxccInfo[key].dxcc] = GT.dxccInfo[key].name; } if (key == 291) { // US Mainland for (var mh in GT.dxccInfo[key].mh) { var sqr = GT.dxccInfo[key].mh[mh]; GT.us48Data[sqr] = {}; GT.us48Data[sqr].name = sqr; GT.us48Data[sqr].worked = false; GT.us48Data[sqr].confirmed = false; GT.us48Data[sqr].worked_bands = {}; GT.us48Data[sqr].confirmed_bands = {}; GT.us48Data[sqr].worked_modes = {}; GT.us48Data[sqr].confirmed_modes = {}; } delete GT.dxccInfo[key].mh; } } fileBuf = fs.readFileSync("./data/cqzone.json"); GT.cqZones = JSON.parse(fileBuf); fileBuf = fs.readFileSync("./data/ituzone.json"); GT.ituZones = JSON.parse(fileBuf); for (var key in GT.StateData) { if (key.substr(0, 3) == "US-") { var shapeKey = key.substr(3, 2); var name = GT.StateData[key].name; if (shapeKey in GT.shapeData) { GT.wasZones[name] = {}; GT.wasZones[name].geo = GT.shapeData[shapeKey]; GT.wasZones[name].worked = false; GT.wasZones[name].confirmed = false; GT.wasZones[name].worked_bands = {}; GT.wasZones[name].confirmed_bands = {}; GT.wasZones[name].worked_modes = {}; GT.wasZones[name].confirmed_modes = {}; } } } for (var key in GT.shapeData) { if (GT.shapeData[key].properties.type == "Continent") { var name = GT.shapeData[key].properties.name; GT.wacZones[name] = {}; GT.wacZones[name].geo = GT.shapeData[key]; GT.wacZones[name].worked = false; GT.wacZones[name].confirmed = false; GT.wacZones[name].worked_bands = {}; GT.wacZones[name].confirmed_bands = {}; GT.wacZones[name].worked_modes = {}; GT.wacZones[name].confirmed_modes = {}; } } } var localeDxcc = "./i18n/" + GT.appSettings.locale + "-dxcc.json"; if (fs.existsSync(localeDxcc)) { var fileBuf = fs.readFileSync(localeDxcc, "UTF-8"); var langDxcc = JSON.parse(fileBuf); if (langDxcc) { for (const dxcc in langDxcc) { if (dxcc in GT.dxccInfo) { GT.dxccInfo[dxcc].name = langDxcc[dxcc]; GT.dxccToAltName[dxcc] = langDxcc[dxcc]; } } } } var localeState = "./i18n/" + GT.appSettings.locale + "-state.json"; if (fs.existsSync(localeState)) { var fileBuf = fs.readFileSync(localeState, "UTF-8"); var langState = JSON.parse(fileBuf); if (langState) { for (const state in langState) { if (state in GT.StateData) { GT.StateData[state].name = langState[state]; } } } } } GT.timezonesEnable = 0; GT.timezoneLayer = null; function createZoneLayer() { GT.timezoneLayer = createGeoJsonLayer( "tz", "./data/combined-with-oceans.json", "#000088FF", 0.5 ); GT.map.addLayer(GT.timezoneLayer); GT.timezoneLayer.setVisible(false); } function toggleTimezones() { if (GT.currentOverlay != 0) return; GT.timezonesEnable ^= 1; if (GT.timezonesEnable == 1) { if (GT.timezoneLayer == null) { createZoneLayer(); } GT.timezoneLayer.setVisible(true); } else { if (GT.timezoneLayer != null) { GT.map.removeLayer(GT.timezoneLayer); GT.timezoneLayer = null; } } timezoneImg.style.filter = GT.timezonesEnable == 1 ? "" : "grayscale(1)"; } function drawAllGrids() { var borderColor = "#000"; var borderWeight = 0.5; for (var x = -178; x < 181; x += 2) { var fromPoint = ol.proj.fromLonLat([x, -90]); var toPoint = ol.proj.fromLonLat([x, 90]); var points = [fromPoint, toPoint]; if (x % 20 == 0) borderWeight = 0.75; else borderWeight = 0.25; var newGridBox = lineString(points); var featureStyle = new ol.style.Style({ stroke: new ol.style.Stroke({ color: borderColor, width: borderWeight }) }); newGridBox.setStyle(featureStyle); GT.layerSources["line-grids"].addFeature(newGridBox); } for (var x = -90; x < 91; x++) { var fromPoint = ol.proj.fromLonLat([-180, x]); var toPoint = ol.proj.fromLonLat([180, x]); var points = [fromPoint, toPoint]; if (x % 10 == 0) borderWeight = 0.75; else borderWeight = 0.25; var newGridBox = lineString(points); var featureStyle = new ol.style.Style({ stroke: new ol.style.Stroke({ color: borderColor, width: borderWeight }) }); newGridBox.setStyle(featureStyle); GT.layerSources["line-grids"].addFeature(newGridBox); } for (var x = 65; x < 83; x++) { for (var y = 65; y < 83; y++) { for (var a = 0; a < 10; a++) { for (var b = 0; b < 10; b++) { var LL = squareToLatLong( String.fromCharCode(x) + String.fromCharCode(y) + String(a) + String(b) ); var Lat = LL.la2 - (LL.la2 - LL.la1) / 2; var Lon = LL.lo2 - (LL.lo2 - LL.lo1) / 2; var point = ol.proj.fromLonLat([Lon, Lat]); var feature = new ol.Feature({ geometry: new ol.geom.Point(point), prop: String(a) + String(b) }); var featureStyle = new ol.style.Style({ text: new ol.style.Text({ fill: new ol.style.Fill({ color: "#000" }), font: "normal 16px sans-serif", stroke: new ol.style.Stroke({ color: "#88888888", width: 1 }), text: String.fromCharCode(x) + String.fromCharCode(y) + String(a) + String(b), offsetY: 1 }) }); feature.setStyle(featureStyle); GT.layerSources["long-grids"].addFeature(feature); } } var LL = twoWideToLatLong(String.fromCharCode(x) + String.fromCharCode(y)); var Lat = LL.la2 - (LL.la2 - LL.la1) / 2; var Lon = LL.lo2 - (LL.lo2 - LL.lo1) / 2; var point = ol.proj.fromLonLat([Lon, Lat]); feature = new ol.Feature(new ol.geom.Point(point)); featureStyle = new ol.style.Style({ text: new ol.style.Text({ fill: new ol.style.Fill({ color: "#000" }), font: "normal 24px sans-serif", stroke: new ol.style.Stroke({ color: "#88888888", width: 2 }), text: String.fromCharCode(x) + String.fromCharCode(y) }) }); feature.setStyle(featureStyle); GT.layerSources["big-grids"].addFeature(feature); } } } function versionCheck(buffer, flag) { var version = String(buffer); if (version.indexOf("gridtracker") == 0) { // good, we're looking at our version string var versionArray = version.split(":"); if (versionArray.length == 3) { // Good, there are 3 parts var stableVersion = Number(versionArray[1]); var betaVersion = Number(versionArray[2]); if (gtVersion < stableVersion) { var verString = String(stableVersion); main.style.display = "none"; newVersionMustDownloadDiv.innerHTML = "New Version v" + verString.substr(0, 1) + "." + verString.substr(1, 2) + "." + verString.substr(3) + " available for download.
Go there now?

"; versionDiv.style.display = "block"; } else { if (flag) { if (gtVersion < betaVersion) { var verString = String(betaVersion); main.style.display = "none"; newVersionMustDownloadDiv.innerHTML = "New Beta Version v" + verString.substr(0, 1) + "." + verString.substr(1, 2) + "." + verString.substr(3) + " available for download.
Go there now?

"; versionDiv.style.display = "block"; } else { main.style.display = "none"; upToDateDiv.style.display = "block"; } } } } } } function updateAcks(buffer) { try { GT.acknowledgedCalls = JSON.parse(buffer); } catch (e) { // can't write, somethings broke } } function readAcksFromDisk() { try { var fileBuf = fs.readFileSync(GT.NWappData + "acknowledgements.json"); var loadedData = JSON.parse(fileBuf); // some validation here? GT.acknowledgedCalls = loadedData; } catch (e) { // file failed to load, probably not downloaded console.error(e); } } function onExitAppToGoWebsite() { require("nw.gui").Shell.openExternal("https://gridtracker.org/"); saveAndCloseApp(); } function mailThem(address) { require("nw.gui").Shell.openExternal("mailto:" + address); } function openSite(address) { require("nw.gui").Shell.openExternal(address); } function closeUpdateToDateDiv() { upToDateDiv.style.display = "none"; main.style.display = "block"; } function cancelVersion() { main.style.display = "block"; versionDiv.style.display = "none"; } function getBuffer(file_url, callback, flag, mode, port, cache = null) { var url = require("url"); var http = require(mode); var fileBuffer = null; var options = null; options = { host: url.parse(file_url).host, // eslint-disable-line node/no-deprecated-api port: port, followAllRedirects: true, path: url.parse(file_url).path, // eslint-disable-line node/no-deprecated-api headers: { "User-Agent": gtUserAgent, "x-user-agent": gtUserAgent } }; http.get(options, function (res) { // var fsize = res.headers["content-length"]; var cookies = null; if (typeof res.headers["set-cookie"] != "undefined") { cookies = res.headers["set-cookie"]; } res .on("data", function (data) { if (fileBuffer == null) fileBuffer = data; else fileBuffer += data; }) .on("end", function () { if (typeof callback == "function") { // Call it, since we have confirmed it is callable callback(fileBuffer, flag, cache); } }) .on("error", function (e) { console.error("getBuffer " + file_url + " error: " + e.message); }); }); } function getPostBuffer( file_url, callback, flag, mode, port, theData, timeoutMs, timeoutCallback, who ) { var querystring = require("querystring"); var postData = querystring.stringify(theData); var url = require("url"); var http = require(mode); var fileBuffer = null; var options = { host: url.parse(file_url).host, // eslint-disable-line node/no-deprecated-api port: port, path: url.parse(file_url).path, // eslint-disable-line node/no-deprecated-api method: "post", headers: { "Content-Type": "application/x-www-form-urlencoded", "Content-Length": postData.length, "User-Agent": gtUserAgent, "x-user-agent": gtUserAgent } }; var req = http.request(options, function (res) { // var fsize = res.headers["content-length"]; var cookies = null; if (typeof res.headers["set-cookie"] != "undefined") { cookies = res.headers["set-cookie"]; } res .on("data", function (data) { if (fileBuffer == null) fileBuffer = data; else fileBuffer += data; }) .on("end", function () { if (typeof callback == "function") { // Call it, since we have confirmed it is callable callback(fileBuffer, flag, cookies); } }) .on("error", function () { if (typeof errorCallback == "function") { errorCallback(); } }); }); if (typeof timeoutMs == "number" && timeoutMs > 0) { req.on("socket", function (socket) { socket.setTimeout(timeoutMs); socket.on("timeout", function () { req.abort(); }); }); req.on("error", function (err) // eslint-disable-line node/handle-callback-err { if (typeof timeoutCallback == "function") { timeoutCallback( file_url, callback, flag, mode, port, theData, timeoutMs, timeoutCallback, who ); } }); } req.write(postData); req.end(); } function colorToHex(color) { if (color.substr(0, 1) == "#") { return color; } var digits = /(.*?)rgb\((\d+), (\d+), (\d+)\)/.exec(color); var red = parseInt(digits[2]); var green = parseInt(digits[3]); var blue = parseInt(digits[4]); var rgb = ("00" + (+red).toString(16)).substr(-2); rgb += ("00" + (+green).toString(16)).substr(-2); rgb += ("00" + (+blue).toString(16)).substr(-2); return "#" + rgb; } function setHueColor() { GT.mapHue = colorToHex(hueDiv.style.backgroundColor); if (GT.mapHue == "#000000") GT.mapHue = 0; } function loadMapSettings() { shadowValue.value = GT.mapSettings.shadow; showDarknessTd.innerHTML = parseInt(shadowValue.value * 100) + "%"; pathWidthTd.innerHTML = pathWidthValue.value = GT.appSettings.pathWidthWeight; qrzPathWidthTd.innerHTML = qrzPathWidthValue.value = GT.appSettings.qrzPathWidthWeight; gridDecay.value = GT.appSettings.gridsquareDecayTime; changeGridDecay(); pathColorValue.value = GT.mapSettings.pathColor; qrzPathColorValue.value = GT.mapSettings.qrzPathColor; brightnessValue.value = GT.mapSettings.loudness; nightBrightnessValue.value = GT.mapSettings.nightLoudness; nightPathColorValue.value = GT.mapSettings.nightPathColor; nightQrzPathColorValue.value = GT.mapSettings.nightQrzPathColor; mouseOverValue.checked = GT.mapSettings.mouseOver; mergeOverlayValue.checked = GT.mapSettings.mergeOverlay; offlineImg.src = GT.mapImageArray[GT.mapSettings.offlineMode ? 0 : 1]; mapSelect.value = GT.mapSettings.mapIndex; mapNightSelect.value = GT.mapSettings.nightMapIndex; animateValue.checked = GT.mapSettings.animate; animateSpeedValue.value = 21 - GT.mapSettings.animateSpeed; setAnimateView(); splitQSLValue.checked = GT.mapSettings.splitQSL; fitQRZvalue.checked = GT.mapSettings.fitQRZ; qrzDxccFallbackValue.checked = GT.mapSettings.qrzDxccFallback; CqHiliteValue.checked = GT.mapSettings.CQhilite; focusRigValue.checked = GT.mapSettings.focusRig; haltAllOnTxValue.checked = GT.mapSettings.haltAllOnTx; trafficDecode.checked = GT.mapSettings.trafficDecode; setSpotImage(); timezoneImg.style.filter = GT.timezonesEnable == 1 ? "" : "grayscale(1)"; radarImg.style.filter = GT.mapSettings.usNexrad ? "" : "grayscale(1)"; gridOverlayImg.style.filter = GT.showAllGrids ? "" : "grayscale(1)"; GT.bandToColor = JSON.parse(JSON.stringify(GT.pskColors)); setGridOpacity(); var pathColor = pathColorValue.value == 0 ? "#000" : pathColorValue.value == 361 ? "#FFF" : "hsl(" + pathColorValue.value + ", 100%, 50%)"; if (pathColorValue.value != 0) { pathColorDiv.style.color = "#000"; pathColorDiv.style.backgroundColor = pathColor; } else { pathColorDiv.style.color = "#FFF"; pathColorDiv.style.backgroundColor = pathColor; } pathColor = qrzPathColorValue.value == 0 ? "#000" : qrzPathColorValue.value == 361 ? "#FFF" : "hsl(" + qrzPathColorValue.value + ", 100%, 50%)"; if (qrzPathColorValue.value != 0) { qrzPathColorDiv.style.color = "#000"; qrzPathColorDiv.style.backgroundColor = pathColor; } else { qrzPathColorDiv.style.color = "#FFF"; qrzPathColorDiv.style.backgroundColor = pathColor; } setNightHtml(); displayLegend(); } function changeDistanceUnit() { GT.appSettings.distanceUnit = distanceUnit.value; GT.scaleLine.setUnits(GT.scaleUnits[GT.appSettings.distanceUnit]); goProcessRoster(); } function changeMapNightValues() { GT.mapSettings.nightPathColor = nightPathColorValue.value; GT.mapSettings.nightQrzPathColor = nightQrzPathColorValue.value; GT.mapSettings.nightMapIndex = mapNightSelect.value; GT.mapSettings.nightLoudness = nightBrightnessValue.value; saveMapSettings(); setNightHtml(); changeMapLayer(); } function setNightHtml() { var pathColor = GT.mapSettings.nightPathColor == 0 ? "#000" : GT.mapSettings.nightPathColor == 361 ? "#FFF" : "hsl(" + GT.mapSettings.nightPathColor + ", 100%, 50%)"; if (GT.mapSettings.nightPathColor != 0) { pathNightColorDiv.style.color = "#000"; pathNightColorDiv.style.backgroundColor = pathColor; } else { pathNightColorDiv.style.color = "#FFF"; pathNightColorDiv.style.backgroundColor = pathColor; } pathColor = GT.mapSettings.nightQrzPathColor == 0 ? "#000" : GT.mapSettings.nightQrzPathColor == 361 ? "#FFF" : "hsl(" + GT.mapSettings.nightQrzPathColor + ", 100%, 50%)"; if (GT.mapSettings.nightQrzPathColor != 0) { pathNightQrzColorDiv.style.color = "#000"; pathNightQrzColorDiv.style.backgroundColor = pathColor; } else { pathNightQrzColorDiv.style.color = "#FFF"; pathNightQrzColorDiv.style.backgroundColor = pathColor; } } function changeMapValues() { GT.mapSettings.pathColor = pathColorValue.value; GT.mapSettings.qrzPathColor = qrzPathColorValue.value; GT.mapSettings.loudness = brightnessValue.value; GT.mapSettings.mapIndex = mapSelect.value; if (GT.appSettings.gtFlagImgSrc > 0 && GT.mapSettings.offlineMode == false && GT.appSettings.gtShareEnable == true) { GT.layerVectors.gtflags.setVisible(true); } else { GT.layerVectors.gtflags.setVisible(false); } saveMapSettings(); saveAlertSettings(); var pathColor = GT.mapSettings.pathColor == 0 ? "#000" : GT.mapSettings.pathColor == 361 ? "#FFF" : "hsl(" + GT.mapSettings.pathColor + ", 100%, 50%)"; if (GT.mapSettings.pathColor != 0) { pathColorDiv.style.color = "#000"; pathColorDiv.style.backgroundColor = pathColor; } else { pathColorDiv.style.color = "#FFF"; pathColorDiv.style.backgroundColor = pathColor; } pathColor = GT.mapSettings.qrzPathColor == 0 ? "#000" : GT.mapSettings.qrzPathColor == 361 ? "#FFF" : "hsl(" + GT.mapSettings.qrzPathColor + ", 100%, 50%)"; if (GT.mapSettings.qrzPathColor != 0) { qrzPathColorDiv.style.color = "#000"; qrzPathColorDiv.style.backgroundColor = pathColor; } else { qrzPathColorDiv.style.color = "#FFF"; qrzPathColorDiv.style.backgroundColor = pathColor; } changeMapLayer(); displayLegend(); } function setLegendColor(name, newColor) { var legendBox = document.getElementById("LegendDiv" + name); legendBox.style.backgroundColor = newColor; legendBox.style.color = pickTextColorBasedOnBgColorAdvanced(newColor, "#EEEEEE", "#222222"); } function setLegendGrid(name, newColor) { document.getElementById(name + "gridValue").value = newColor; } function setLegendAndGridSettings() { for (var key in GT.legendColors) { setLegendColor(key, GT.legendColors[key]); setLegendGrid(key, GT.legendColors[key]); } } function resetLegendColors() { for (var key in def_legendColors) { GT.legendColors[key] = def_legendColors[key]; } setLegendAndGridSettings(); saveLegendColors(); redrawGrids(); } GT.redrawFromLegendTimeoutHandle = null; function changeLegendColor(source) { var newColor = source.value; var name = source.id.replace("gridValue", ""); setLegendColor(name, newColor); GT.legendColors[name] = newColor; if (GT.redrawFromLegendTimeoutHandle != null) { nodeTimers.clearTimeout(GT.redrawFromLegendTimeoutHandle); } GT.redrawFromLegendTimeoutHandle = nodeTimers.setTimeout(redrawGrids, 500); } function toggleLegend() { if (GT.mapSettings.legend == true) GT.mapSettings.legend = false; else GT.mapSettings.legend = true; saveMapSettings(); displayLegend(); } function hideLegend() { LegendDiv.style.display = "none"; } function displayLegend() { if (GT.mapSettings.legend == true) { LegendDiv.style.display = "block"; legendImg.style.webkitFilter = ""; } else { LegendDiv.style.display = "none"; legendImg.style.webkitFilter = "grayscale(1) brightness(50%)"; } } function rgbToHex(R, G, B) { return toHex(R) + toHex(G) + toHex(B); } function toHex(n) { n = parseInt(n, 10); if (isNaN(n)) return "00"; n = Math.max(0, Math.min(n, 255)); return ( "0123456789ABCDEF".charAt((n - (n % 16)) / 16) + "0123456789ABCDEF".charAt(n % 16) ); } function hexToR(h) { return parseInt(cutHex(h).substring(0, 2), 16); } function hexToG(h) { return parseInt(cutHex(h).substring(2, 4), 16); } function hexToB(h) { return parseInt(cutHex(h).substring(4, 6), 16); } function hexToA(h) { return parseInt(cutHex(h).substring(6, 8), 16); } function cutHex(h) { return h.charAt(0) == "#" ? h.substring(1, 9) : h; } function changeMapLayer() { if (GT.mapSettings.offlineMode) { GT.tileLayer.setSource(GT.offlineLayer); GT.tileLayer.setOpacity(Number(GT.mapSettings.loudness)); } else { if (GT.mapSettings.nightMapEnable && GT.nightTime) { GT.tileLayer.setSource(GT.mapsLayer[GT.mapSettings.nightMapIndex]); GT.tileLayer.setOpacity(Number(GT.mapSettings.nightLoudness)); } else { GT.tileLayer.setSource(GT.mapsLayer[GT.mapSettings.mapIndex]); GT.tileLayer.setOpacity(Number(GT.mapSettings.loudness)); } } changePathWidth(); redrawSpots(); redrawParks(); } function voiceChangedValue() { GT.speechSettings.voice = Number(alertVoiceInput.value) + 1; changeSpeechValues(); } function timedGetVoices() { GT.voices = window.speechSynthesis.getVoices(); if (GT.voices.length > 0) { var newSelect = document.createElement("select"); newSelect.id = "alertVoiceInput"; newSelect.title = "Select Voice"; for (var i = 0; i < GT.voices.length; i++) { var option = document.createElement("option"); option.value = i; newstring = GT.voices[i].name.replace(/ /g, ""); option.text = newstring; if (GT.voices[i].default) { option.selected = true; } newSelect.appendChild(option); } newSelect.oninput = voiceChangedValue; voicesDiv.appendChild(newSelect); } GT.speechAvailable = true; loadAlerts(); } function initSpeech() { window.speechSynthesis.onvoiceschanged = function () { nodeTimers.setTimeout(timedGetVoices, 3000); }; var msg = new SpeechSynthesisUtterance("\n"); msg.lang = GT.localeString; window.speechSynthesis.speak(msg); } function initSoundCards() { navigator.mediaDevices .enumerateDevices() .then(gotAudioDevices) .catch(errorCallback); } function errorCallback(e) { } function gotAudioDevices(deviceInfos) { soundCardDiv.innerHTML = ""; var newSelect = document.createElement("select"); newSelect.id = "soundCardInput"; newSelect.title = "Select Sound Card"; for (var i = 0; i !== deviceInfos.length; ++i) { var deviceInfo = deviceInfos[i]; if (deviceInfo.kind == "audiooutput") { var option = document.createElement("option"); option.value = deviceInfo.deviceId; option.text = deviceInfo.label || "Speaker " + (newSelect.length + 1); newSelect.appendChild(option); } } newSelect.oninput = soundCardChangedValue; soundCardDiv.appendChild(newSelect); soundCardInput.value = GT.soundCard; } function soundCardChangedValue() { GT.appSettings.soundCard = GT.soundCard = soundCardInput.value; playTestFile(); } function setPins() { GT.colorLeafletPins = {}; GT.colorLeafleteQPins = {}; GT.colorLeafletQPins.worked = {}; GT.colorLeafletQPins.confirmed = {}; for (var i = 0; i < GT.colorBands.length; i++) { var pin = new ol.style.Icon({ src: "./img/pin/" + GT.colorBands[i] + ".png", anchorYUnits: "pixels", anchorXUnits: "pixels", anchor: [5, 18] }); GT.colorLeafletPins[GT.colorBands[i]] = pin; pin = new ol.style.Icon({ src: "./img/pin/" + GT.colorBands[i] + "w.png", anchorYUnits: "pixels", anchorXUnits: "pixels", anchor: [5, 18] }); GT.colorLeafletQPins.worked[GT.colorBands[i]] = pin; pin = new ol.style.Icon({ src: "./img/pin/" + GT.colorBands[i] + "q.png", anchorYUnits: "pixels", anchorXUnits: "pixels", anchor: [5, 18] }); GT.colorLeafletQPins.confirmed[GT.colorBands[i]] = pin; } } function changeClearOnCQ() { GT.appSettings.clearOnCQ = clearOnCQ.checked; saveAppSettings(); } function loadViewSettings() { gtBandFilter.value = GT.appSettings.gtBandFilter; gtModeFilter.value = GT.appSettings.gtModeFilter; gtPropFilter.value = GT.appSettings.gtPropFilter; distanceUnit.value = GT.appSettings.distanceUnit; languageLocale.value = GT.appSettings.locale; N1MMIpInput.value = GT.N1MMSettings.ip; N1MMPortInput.value = GT.N1MMSettings.port; buttonN1MMCheckBox.checked = GT.N1MMSettings.enable; ValidatePort(N1MMPortInput, buttonN1MMCheckBox, null); ValidateIPaddress(N1MMIpInput, buttonN1MMCheckBox, null); log4OMIpInput.value = GT.log4OMSettings.ip; log4OMPortInput.value = GT.log4OMSettings.port; buttonLog4OMCheckBox.checked = GT.log4OMSettings.enable; ValidatePort(log4OMPortInput, buttonLog4OMCheckBox, null); ValidateIPaddress(log4OMIpInput, buttonLog4OMCheckBox, null); acLogIpInput.value = GT.acLogSettings.ip; acLogPortInput.value = GT.acLogSettings.port; buttonacLogCheckBox.checked = GT.acLogSettings.enable; ValidatePort(acLogPortInput, buttonacLogCheckBox, null); ValidateIPaddress(acLogIpInput, buttonacLogCheckBox, null); dxkLogIpInput.value = GT.dxkLogSettings.ip; dxkLogPortInput.value = GT.dxkLogSettings.port; buttondxkLogCheckBox.checked = GT.dxkLogSettings.enable; ValidatePort(dxkLogPortInput, buttondxkLogCheckBox, null); ValidateIPaddress(dxkLogIpInput, buttondxkLogCheckBox, null); hrdLogbookIpInput.value = GT.HRDLogbookLogSettings.ip; hrdLogbookPortInput.value = GT.HRDLogbookLogSettings.port; buttonHrdLogbookCheckBox.checked = GT.HRDLogbookLogSettings.enable; ValidatePort(hrdLogbookPortInput, buttonHrdLogbookCheckBox, null); ValidateIPaddress(hrdLogbookIpInput, buttonHrdLogbookCheckBox, null); pstrotatorIpInput.value = GT.pstrotatorSettings.ip; pstrotatorPortInput.value = GT.pstrotatorSettings.port; pstrotatorCheckBox.checked = GT.pstrotatorSettings.enable; ValidatePort(pstrotatorPortInput, pstrotatorCheckBox, null); ValidateIPaddress(pstrotatorIpInput, pstrotatorCheckBox, null); spotHistoryTimeValue.value = parseInt( GT.receptionSettings.viewHistoryTimeSec / 60 ); spotHistoryTimeTd.innerHTML = "Max Age: " + toDHM(Number(GT.receptionSettings.viewHistoryTimeSec)); spotPathsValue.checked = GT.receptionSettings.viewPaths; spotPathColorValue.value = GT.receptionSettings.pathColor; spotNightPathColorValue.value = GT.receptionSettings.pathNightColor; spotWidthTd.innerHTML = spotWidthValue.value = GT.receptionSettings.spotWidth; spotMergeValue.checked = GT.receptionSettings.mergeSpots; lookupOnTx.checked = GT.appSettings.lookupOnTx; lookupCallookPreferred.checked = GT.appSettings.lookupCallookPreferred; lookupCloseLog.checked = GT.appSettings.lookupCloseLog; lookupMerge.checked = GT.appSettings.lookupMerge; lookupMissingGrid.checked = GT.appSettings.lookupMissingGrid; clearOnCQ.checked = GT.appSettings.clearOnCQ; if (GT.appSettings.lookupMerge == true) { lookupMissingGridDiv.style.display = "inline-block"; } else { lookupMissingGridDiv.style.display = "none"; } if (GT.receptionSettings.viewPaths) { spotPathWidthDiv.style.display = "inline-block"; } else { spotPathWidthDiv.style.display = "none"; } spotPathChange(); setLegendAndGridSettings(); } function loadMsgSettings() { msgEnable.checked = GT.appSettings.gtMsgEnable; GTspotEnable.checked = GT.appSettings.gtSpotEnable; oamsBandActivity.checked = GT.appSettings.oamsBandActivity; oamsBandActivityNeighbors.checked = GT.appSettings.oamsBandActivityNeighbors; setOamsBandActivity(oamsBandActivity); setSpotImage(); for (var key in GT.msgSettings) { document.getElementById(key).value = GT.msgSettings[key]; } msgSimplepush.checked = GT.msgSettings.msgSimplepush; msgSimplepushChat.checked = GT.msgSettings.msgSimplepushChat; msgSimplepushRoster.checked = GT.msgSettings.msgSimplepushRoster; msgPushover.checked = GT.msgSettings.msgPushover; msgPushoverChat.checked = GT.msgSettings.msgPushoverChat; msgPushoverRoster.checked = GT.msgSettings.msgPushoverRoster; ValidateText(msgAwayText); setMsgSettingsView(); } function setMsgSettingsView() { if (msgEnable.checked) msgSettingsDiv.style.display = "inline-block"; else msgSettingsDiv.style.display = "none"; if (GT.msgSettings.msgAlertSelect > 0) { msgFrequencySelectDiv.style.display = "inline-block"; if (GT.msgSettings.msgAlertSelect == 1) { msgAlertWord.style.display = "inline-block"; msgAlertMedia.style.display = "none"; ValidateText(msgAlertWord); } if (GT.msgSettings.msgAlertSelect == 2) { msgAlertWord.style.display = "none"; msgAlertMedia.style.display = "inline-block"; } } else { msgFrequencySelectDiv.style.display = "none"; msgAlertWord.style.display = "none"; msgAlertMedia.style.display = "none"; } if (GT.msgSettings.msgAwaySelect > 0) { msgAwayTextDiv.style.display = "inline-block"; } else msgAwayTextDiv.style.display = "none"; simplePushDiv.style.display = (GT.msgSettings.msgSimplepush == true ? "inline-block" : "none"); pushOverDiv.style.display = (GT.msgSettings.msgPushover == true ? "inline-block" : "none"); ValidateText(msgSimplepushApiKey); ValidateText(msgPushoverUserKey); ValidateText(msgPushoverToken); } function loadAdifSettings() { qsoItemsPerPageTd.innerHTML = qsoItemsPerPageValue.value = GT.appSettings.qsoItemsPerPage; workingCallsignEnable.checked = GT.appSettings.workingCallsignEnable; workingCallsignsValue.value = Object.keys( GT.appSettings.workingCallsigns ).join(","); ValidateCallsigns(workingCallsignsValue); workingDateEnable.checked = GT.appSettings.workingDateEnable; displayWorkingDate(); if (GT.platform == "mac") { selectTQSLButton.style.display = "none"; } for (var key in GT.adifLogSettings.menu) { var value = GT.adifLogSettings.menu[key]; var where = key + "Div"; if (document.getElementById(key) != null) { document.getElementById(key).checked = value; if (value == true) { document.getElementById(where).style.display = "inline-block"; } else { document.getElementById(where).style.display = "none"; } } } for (var key in GT.adifLogSettings.startup) { if (document.getElementById(key) != null) { document.getElementById(key).checked = GT.adifLogSettings.startup[key]; } } for (var key in GT.adifLogSettings.nickname) { if (document.getElementById(key) != null) { document.getElementById(key).checked = GT.adifLogSettings.nickname[key]; if (key == "nicknameeQSLCheckBox") { if (document.getElementById(key).checked == true) { eQSLNickname.style.display = "inline-block"; } else { eQSLNickname.style.display = "none"; } } } } for (var key in GT.adifLogSettings.text) { if (document.getElementById(key) != null) { document.getElementById(key).value = GT.adifLogSettings.text[key]; ValidateText(document.getElementById(key)); } } for (var key in GT.adifLogSettings.qsolog) { if (document.getElementById(key) != null) { document.getElementById(key).checked = GT.adifLogSettings.qsolog[key]; if (key == "logLOTWqsoCheckBox") { if (document.getElementById(key).checked == true) { lotwUpload.style.display = "inline-block"; trustedTestButton.style.display = "inline-block"; } else { lotwUpload.style.display = "none"; trustedTestButton.style.display = "none"; } } } } if (clubCall.value == "" && GT.appSettings.myRawCall != "NOCALL") { clubCall.value = GT.appSettings.myRawCall; ValidateText(clubCall); localStorage.adifLogSettings = JSON.stringify(GT.adifLogSettings); } try { findTrustedQSLPaths(); } catch (e) { if (logLOTWqsoCheckBox.checked == true) { alert("Unable to access LoTW TrustedQSL (TQSL) due to OS permissions\nLogging to LoTW disabled for this session\nRun as administrator or allow file access to GridTracker if problem persists"); logLOTWqsoCheckBox.checked = false; } } setAdifStartup(loadAdifCheckBox); ValidateQrzApi(qrzApiKey); } function startupVersionInit() { if (!GT.developerMode) { document.body.addEventListener("contextmenu", function (ev) { ev.preventDefault(); }); } imSureCheck.checked = false; stopAskingCheckbox.checked = GT.appSettings.stopAskingVersion; if (stopAskingCheckbox.checked == false) { checkForNewVersion(); nodeTimers.setInterval(checkForNewVersion, 86400000); } } function startupButtonsAndInputs() { try { GT.pushPinMode = !(GT.appSettings.pushPinMode == true); togglePushPinMode(); udpForwardEnable.checked = GT.appSettings.wsjtForwardUdpEnable; multicastEnable.checked = GT.appSettings.multicast; gridViewButton.innerHTML = GT.gridViewArray[GT.appSettings.gridViewMode]; earthImg.src = GT.earthShadowImageArray[GT.appSettings.earthImgSrc]; gtFlagImg.src = GT.gtFlagImageArray[GT.appSettings.gtFlagImgSrc % 2]; gtShareFlagImg.src = GT.gtShareFlagImageArray[GT.appSettings.gtShareEnable == false ? 0 : 1]; alertMuteImg.src = GT.alertImageArray[GT.appSettings.alertMute]; modeImg.src = GT.maidenheadModeImageArray[GT.appSettings.sixWideMode]; if (GT.appSettings.centerGridsquare.length > 0) { homeQTHInput.value = GT.appSettings.centerGridsquare.substr(0, 6); if (ValidateGridsquare(homeQTHInput, null)) setCenterGridsquare(); } ValidateCallsign(alertValueInput, null); if (GT.mapSettings.offlineMode == true) { conditionsButton.style.display = "none"; buttonPsk24CheckBoxDiv.style.display = "none"; buttonQRZCheckBoxDiv.style.display = "none"; buttonLOTWCheckBoxDiv.style.display = "none"; buttonClubCheckBoxDiv.style.display = "none"; gtFlagButton.style.display = "none"; gtShareButton.style.display = "none"; msgButton.style.display = "none"; donateButton.style.display = "none"; bandActivityDiv.style.display = "none"; buttonSpotsBoxDiv.style.display = "none"; potaButton.style.display = "none"; } setGtShareButtons(); } catch (e) { console.error(e); } } function startupEventsAndTimers() { document.addEventListener("keydown", onMyKeyDown, true); document.addEventListener("keyup", onMyKeyUp, false); // Clock timer update every second nodeTimers.setInterval(displayTime, 1000); nodeTimers.setInterval(reportDecodes, 60000); nodeTimers.setInterval(oamsBandActivityCheck, 300000); } GT.finishedLoading = false; function postInit() { setGridViewMode(GT.appSettings.gridViewMode); redrawSpots(); checkForSettings(); updateForwardListener(); addLastTraffic("GridTracker
" + gtShortVersion); GT.nexradEnable = GT.mapSettings.usNexrad ? 0 : 1; toggleNexrad(); if (String(gtVersion) != String(GT.startVersion)) { // generalbut.className = "settingsTablinks"; showSettingsBox(); openSettingsTab(updatebut, "updateSettingsDiv"); } GT.finishedLoading = true; // tagme var x = document.querySelectorAll("input[type='range']"); for (var i = 0; i < x.length; i++) { if (x[i].title.length > 0) x[i].title += "\n"; x[i].title += "(Use Arrow Keys For Smaller Increments)"; } openLookupWindow(false); openBaWindow(false); openAlertWindow(false); openCallRosterWindow(false); openConditionsWindow(false); showMessaging(false); if (GT.developerMode) { devPanel.style.display = "inline-block"; } nodeTimers.setInterval(removeFlightPathsAndDimSquares, 2000); } document.addEventListener("dragover", function (event) { event.preventDefault(); }); document.addEventListener("drop", function (event) { event.preventDefault(); if (GT.finishedLoading == true) dropHandler(event); }); GT.startupTable = [ [startupVersionInit, "Completed Version Check", "gt.startupTable.versionCheck"], [loadI18n, "Loading Locales", "gt.startupTable.loadi18n"], [qsoBackupFileInit, "QSO Backup Initialized", "gt.startupTable.qsoBackup"], [callsignServicesInit, "Callsign Services Initialized", "gt.startupTable.callsigns"], [loadMapSettings, "Map Settings Initialized", "gt.startupTable.mapSettings"], [initMap, "Loaded Map", "gt.startupTable.loadMap"], [setPins, "Created Pins", "gt.startupTable.setPins"], [loadViewSettings, "Loaded View Settings", "gt.startupTable.viewSettings"], [loadMsgSettings, "Loaded Messaging Settings", "gt.startupTable.msgSettings"], [setFileSelectors, "Set File Selectors", "gt.startupTable.fileSelectors"], [lockNewWindows, "Locked New Windows", "gt.startupTable.newWindows"], [loadMaidenHeadData, "Loaded Maidenhead Dataset", "gt.startupTable.maidenheadData"], [drawAllGrids, "Rendered All Maidenhead Grids", "gt.startupTable.renderGrids"], [updateRunningProcesses, "Updated Running Processes", "gt.startupTable.updateProcesses"], [updateBasedOnIni, "Updated from WSJT-X/JTDX", "gt.startupTable.updateINI"], [loadAdifSettings, "Loaded ADIF Settings", "gt.startupTable.loadADIF"], [startupButtonsAndInputs, "Buttons and Inputs Initialized", "gt.startupTable.initButtons"], [initSpeech, "Speech Initialized", "gt.startupTable.initSpeech"], [initSoundCards, "Sounds Initialized", "gt.startupTable.initSounds"], [loadPortSettings, "Loaded Network Settings", "gt.startupTable.loadPorts"], [loadLookupDetails, "Callsign Lookup Details Loaded", "gt.startupTable.loadLookup"], [renderLocale, "Rendering Locale", "gt.startupTable.renderLocale"], [startupEventsAndTimers, "Set Events and Timers", "gt.startupTable.eventTimers"], [registerHotKeys, "Registered Hotkeys", "gt.startupTable.regHotkeys"], [gtChatSystemInit, "Chat System Initialized", "gt.startupTable.initOams"], [initPota, "POTA Initialized", "gt.startupTable.loadPOTA"], [downloadAcknowledgements, "Contributor Acknowledgements Loaded", "gt.startupTable.getAcks"], [postInit, "Finalizing System", "gt.startupTable.postInit"], [undefined, "Completed", "gt.startupEngine.completed"] ]; function init() { startupVersionDiv.innerHTML = gtVersionString; aboutVersionDiv.innerHTML = gtVersionString; GT.currentDay = parseInt(timeNowSec() / 86400); if (mediaCheck() == false) { startupDiv.style.display = "none"; documentsDiv.style.display = "block"; searchedDocFolder.innerHTML = GT.appData; } else { documentsDiv.style.display = "none"; startupDiv.style.display = "block"; startupStatusDiv.innerHTML = "Starting..."; nodeTimers.setTimeout(startupEngine, 32); } } function startupEngine() { if (GT.startupTable.length > 0) { var funcInfo = GT.startupTable.shift(); funcInfo[0] && funcInfo[0](); startupStatusDiv.innerHTML = funcInfo[1]; nodeTimers.setTimeout(startupEngine, 32); } else { setTimeout(endStartup, 2000); startupAdifLoadCheck(); openStatsWindow(false); } } function refreshI18NStrings() { GT.gridViewArray = Array(); GT.gridViewArray[1] = $.i18n("mapFilter.data.Live"); GT.gridViewArray[2] = $.i18n("mapFilter.data.Logbook"); GT.gridViewArray[3] = $.i18n("mapFilter.data.LogLive"); GT.startupTable.forEach(function (item) { item[1] = $.i18n(item[2]); }) } function directoryInput(what) { GT.appSettings.savedAppData = what.files[0].path; init(); } function endStartup() { startupDiv.style.display = "none"; main.style.display = "block"; GT.map.updateSize(); } function loadPortSettings() { multicastEnable.checked = GT.appSettings.multicast; multicastIpInput.value = GT.appSettings.wsjtIP; setMulticastEnable(multicastEnable); udpPortInput.value = GT.appSettings.wsjtUdpPort; ValidatePort(udpPortInput, null, CheckReceivePortIsNotForwardPort); udpForwardPortInput.value = GT.appSettings.wsjtForwardUdpPort; ValidatePort(udpForwardPortInput, null, CheckForwardPortIsNotReceivePort); udpForwardIpInput.value = GT.appSettings.wsjtForwardUdpIp; ValidateIPaddress(udpForwardIpInput, null); udpForwardEnable.checked = GT.appSettings.wsjtForwardUdpEnable; setUdpForwardEnable(udpForwardEnable); } GT.wsjtCurrentPort = -1; GT.wsjtUdpServer = null; GT.wsjtUdpSocketReady = false; GT.wsjtUdpSocketError = false; GT.qtToSplice = 0; function decodeQUINT8(byteArray) { GT.qtToSplice = 1; return byteArray[0]; } function encodeQBOOL(byteArray, offset, value) { return byteArray.writeUInt8(value, offset); } function decodeQUINT32(byteArray) { GT.qtToSplice = 4; return byteArray.readUInt32BE(0); } function encodeQUINT32(byteArray, offset, value) { if (value == -1) value = 4294967295; return byteArray.writeUInt32BE(value, offset); } function decodeQINT32(byteArray) { GT.qtToSplice = 4; return byteArray.readInt32BE(0); } function encodeQINT32(byteArray, offset, value) { return byteArray.writeInt32BE(value, offset); } function decodeQUINT64(byteArray) { var value = 0; for (var i = 0; i < 8; i++) { value = value * 256 + byteArray[i]; } GT.qtToSplice = 8; return value; } function encodeQUINT64(byteArray, offset, value) { var breakOut = Array(); for (var i = 0; i < 8; i++) { breakOut[i] = value & 0xff; value >>= 8; } for (var i = 0; i < 8; i++) { offset = encodeQBOOL(byteArray, offset, breakOut[7 - i]); } return offset; } function decodeQUTF8(byteArray) { var utf8_len = decodeQUINT32(byteArray); var result = ""; byteArray = byteArray.slice(GT.qtToSplice); if (utf8_len == 0xffffffff) utf8_len = 0; else result = byteArray.slice(0, utf8_len); GT.qtToSplice = utf8_len + 4; return result.toString(); } function encodeQUTF8(byteArray, offset, value) { offset = encodeQUINT32(byteArray, offset, value.length); var wrote = byteArray.write(value, offset, value.length); return wrote + offset; } function decodeQDOUBLE(byteArray) { GT.qtToSplice = 8; return byteArray.readDoubleBE(0); } function encodeQDOUBLE(byteArray, offset, value) { return byteArray.writeDoubleBE(value, offset); } GT.forwardUdpServer = null; function updateForwardListener() { if (GT.forwardUdpServer != null) { GT.forwardUdpServer.close(); } if (GT.closing == true) return; var dgram = require("dgram"); GT.forwardUdpServer = dgram.createSocket({ type: "udp4", reuseAddr: true }); GT.forwardUdpServer.on("listening", function () { }); GT.forwardUdpServer.on("error", function () { GT.forwardUdpServer.close(); GT.forwardUdpServer = null; }); GT.forwardUdpServer.on("message", function (originalMessage, remote) { // Decode enough to get the rig-name, so we know who to send to var message = Object.assign({}, originalMessage); var newMessage = {}; newMessage.magic_key = decodeQUINT32(message); message = message.slice(GT.qtToSplice); if (newMessage.magic_key == 0xadbccbda) { newMessage.schema_number = decodeQUINT32(message); message = message.slice(GT.qtToSplice); newMessage.type = decodeQUINT32(message); message = message.slice(GT.qtToSplice); newMessage.Id = decodeQUTF8(message); message = message.slice(GT.qtToSplice); var instanceId = newMessage.Id; if (instanceId in GT.instances) { wsjtUdpMessage( originalMessage, originalMessage.length, GT.instances[instanceId].remote.port, GT.instances[instanceId].remote.address ); } } }); GT.forwardUdpServer.bind(0); } function sendForwardUdpMessage(msg, length, port, address) { if (GT.forwardUdpServer) { GT.forwardUdpServer.send(msg, 0, length, port, address); } } function wsjtUdpMessage(msg, length, port, address) { if (GT.wsjtUdpServer) { GT.wsjtUdpServer.send(msg, 0, length, port, address); } } function checkWsjtxListener() { if ( GT.wsjtUdpServer == null || (GT.wsjtUdpSocketReady == false && GT.wsjtUdpSocketError == true) ) { GT.wsjtCurrentPort = -1; GT.wsjtCurrentIP = "none"; } updateWsjtxListener(GT.appSettings.wsjtUdpPort); } GT.instances = {}; GT.instancesIndex = Array(); GT.activeInstance = ""; GT.activeIndex = 0; GT.currentID = null; function updateWsjtxListener(port) { if (port == GT.wsjtCurrentPort && GT.appSettings.wsjtIP == GT.wsjtCurrentIP) { return; } if (GT.wsjtUdpServer != null) { if (multicastEnable.checked == true && GT.appSettings.wsjtIP != "") { try { GT.wsjtUdpServer.dropMembership(GT.appSettings.wsjtIP); } catch (e) { console.error(e); } } GT.wsjtUdpServer.close(); GT.wsjtUdpServer = null; GT.wsjtUdpSocketReady = false; } if (GT.closing == true) return; GT.wsjtUdpSocketError = false; var dgram = require("dgram"); GT.wsjtUdpServer = dgram.createSocket({ type: "udp4", reuseAddr: true }); if (multicastEnable.checked == true && GT.appSettings.wsjtIP != "") { GT.wsjtUdpServer.on("listening", function () { var address = GT.wsjtUdpServer.address(); GT.wsjtUdpServer.setBroadcast(true); GT.wsjtUdpServer.setMulticastTTL(128); GT.wsjtUdpServer.addMembership(GT.appSettings.wsjtIP); GT.wsjtUdpSocketReady = true; }); } else { GT.appSettings.multicast = false; GT.wsjtCurrentIP = GT.appSettings.wsjtIP = ""; GT.wsjtUdpServer.on("listening", function () { GT.wsjtUdpServer.setBroadcast(true); GT.wsjtUdpSocketReady = true; }); } GT.wsjtUdpServer.on("error", function () { GT.wsjtUdpServer.close(); GT.wsjtUdpServer = null; GT.wsjtUdpSocketReady = false; GT.wsjtUdpSocketError = true; }); GT.wsjtUdpServer.on("message", function (message, remote) { // if (GT.closing == true) true; if ( typeof udpForwardEnable != "undefined" && udpForwardEnable.checked == true ) { sendForwardUdpMessage( message, message.length, udpForwardPortInput.value, udpForwardIpInput.value ); } var newMessage = {}; newMessage.magic_key = decodeQUINT32(message); message = message.slice(GT.qtToSplice); if (newMessage.magic_key == 0xadbccbda) { newMessage.schema_number = decodeQUINT32(message); message = message.slice(GT.qtToSplice); newMessage.type = decodeQUINT32(message); message = message.slice(GT.qtToSplice); newMessage.Id = decodeQUTF8(message); message = message.slice(GT.qtToSplice); var instanceId = newMessage.Id; if (!(instanceId in GT.instances)) { GT.instances[instanceId] = {}; GT.instances[instanceId].valid = false; GT.instancesIndex.push(instanceId); GT.instances[instanceId].intId = GT.instancesIndex.length - 1; GT.instances[instanceId].crEnable = true; GT.instances[instanceId].oldStatus = null; GT.instances[instanceId].status = null; if (GT.instancesIndex.length > 1) { multiRigCRDiv.style.display = "inline-block"; haltTXDiv.style.display = "inline-block"; } updateRosterInstances(); } var notify = false; if (GT.instances[instanceId].open == false) notify = true; GT.instances[instanceId].open = true; GT.instances[instanceId].remote = remote; if (notify) updateRosterInstances(); if (newMessage.type == 1) { newMessage.event = "Status"; newMessage.Frequency = decodeQUINT64(message); newMessage.Band = formatBand(Number(newMessage.Frequency / 1000000)); message = message.slice(GT.qtToSplice); newMessage.MO = decodeQUTF8(message); message = message.slice(GT.qtToSplice); newMessage.DXcall = decodeQUTF8(message); message = message.slice(GT.qtToSplice); newMessage.Report = decodeQUTF8(message); message = message.slice(GT.qtToSplice); newMessage.TxMode = decodeQUTF8(message); message = message.slice(GT.qtToSplice); newMessage.TxEnabled = decodeQUINT8(message); message = message.slice(GT.qtToSplice); newMessage.Transmitting = decodeQUINT8(message); message = message.slice(GT.qtToSplice); newMessage.Decoding = decodeQUINT8(message); message = message.slice(GT.qtToSplice); newMessage.RxDF = decodeQINT32(message); message = message.slice(GT.qtToSplice); newMessage.TxDF = decodeQINT32(message); message = message.slice(GT.qtToSplice); newMessage.DEcall = decodeQUTF8(message); message = message.slice(GT.qtToSplice); newMessage.DEgrid = decodeQUTF8(message); message = message.slice(GT.qtToSplice); newMessage.DXgrid = decodeQUTF8(message); message = message.slice(GT.qtToSplice); newMessage.TxWatchdog = decodeQUINT8(message); message = message.slice(GT.qtToSplice); newMessage.Submode = decodeQUTF8(message); message = message.slice(GT.qtToSplice); newMessage.Fastmode = decodeQUINT8(message); message = message.slice(GT.qtToSplice); if (message.length > 0) { newMessage.SopMode = decodeQUINT8(message); message = message.slice(GT.qtToSplice); } else { newMessage.SopMode = -1; } if (message.length > 0) { newMessage.FreqTol = decodeQINT32(message); message = message.slice(GT.qtToSplice); } else { newMessage.FreqTol = -1; } if (message.length > 0) { newMessage.TRP = decodeQINT32(message); message = message.slice(GT.qtToSplice); } else { newMessage.TRP = -1; } if (message.length > 0) { newMessage.ConfName = decodeQUTF8(message); message = message.slice(GT.qtToSplice); } else { newMessage.ConfName = null; } if (message.length > 0) { newMessage.TxMessage = decodeQUTF8(message); message = message.slice(GT.qtToSplice); } else { newMessage.TxMessage = null; } GT.instances[instanceId].oldStatus = GT.instances[instanceId].status; GT.instances[instanceId].status = newMessage; GT.instances[instanceId].valid = true; } if (GT.instances[instanceId].valid == true) { if (newMessage.type == 2) { newMessage.event = "Decode"; newMessage.NW = decodeQUINT8(message); message = message.slice(GT.qtToSplice); newMessage.TM = decodeQUINT32(message); message = message.slice(GT.qtToSplice); newMessage.SR = decodeQINT32(message); message = message.slice(GT.qtToSplice); newMessage.DT = decodeQDOUBLE(message); message = message.slice(GT.qtToSplice); newMessage.DF = decodeQUINT32(message); message = message.slice(GT.qtToSplice); newMessage.MO = decodeQUTF8(message); message = message.slice(GT.qtToSplice); newMessage.Msg = decodeQUTF8(message); message = message.slice(GT.qtToSplice); newMessage.LC = decodeQUINT8(message); message = message.slice(GT.qtToSplice); newMessage.OA = decodeQUINT8(message); message = message.slice(GT.qtToSplice); newMessage.OF = GT.instances[instanceId].status.Frequency; newMessage.OC = GT.instances[instanceId].status.DEcall; newMessage.OG = GT.instances[instanceId].status.DEgrid; newMessage.OM = GT.instances[instanceId].status.MO; newMessage.OB = GT.instances[instanceId].status.Band; newMessage.SP = GT.instances[instanceId].status.SopMode; } if (newMessage.type == 3) { newMessage.event = "Clear"; } if (newMessage.type == 5) { newMessage.event = "QSO Logged"; newMessage.DateOff = decodeQUINT64(message); message = message.slice(GT.qtToSplice); newMessage.TimeOff = decodeQUINT32(message); message = message.slice(GT.qtToSplice); newMessage.timespecOff = decodeQUINT8(message); message = message.slice(GT.qtToSplice); if (newMessage.timespecOff == 2) { newMessage.offsetOff = decodeQINT32(message); message = message.slice(GT.qtToSplice); } newMessage.DXCall = decodeQUTF8(message); message = message.slice(GT.qtToSplice); newMessage.DXGrid = decodeQUTF8(message); message = message.slice(GT.qtToSplice); newMessage.Frequency = decodeQUINT64(message); message = message.slice(GT.qtToSplice); newMessage.MO = decodeQUTF8(message); message = message.slice(GT.qtToSplice); newMessage.ReportSend = decodeQUTF8(message); message = message.slice(GT.qtToSplice); newMessage.ReportRecieved = decodeQUTF8(message); message = message.slice(GT.qtToSplice); newMessage.TXPower = decodeQUTF8(message); message = message.slice(GT.qtToSplice); newMessage.Comments = decodeQUTF8(message); message = message.slice(GT.qtToSplice); newMessage.Name = decodeQUTF8(message); message = message.slice(GT.qtToSplice); newMessage.DateOn = decodeQUINT64(message); message = message.slice(GT.qtToSplice); newMessage.TimeOn = decodeQUINT32(message); message = message.slice(GT.qtToSplice); newMessage.timespecOn = decodeQUINT8(message); message = message.slice(GT.qtToSplice); if (newMessage.timespecOn == 2) { newMessage.offsetOn = decodeQINT32(message); message = message.slice(GT.qtToSplice); } if (message.length > 0) { newMessage.Operatorcall = decodeQUTF8(message); message = message.slice(GT.qtToSplice); } else newMessage.Operatorcall = ""; if (message.length > 0) { newMessage.Mycall = decodeQUTF8(message); message = message.slice(GT.qtToSplice); } else newMessage.Mycall = ""; if (message.length > 0) { newMessage.Mygrid = decodeQUTF8(message); message = message.slice(GT.qtToSplice); } else newMessage.Mygrid = ""; if (message.length > 0) { newMessage.ExchangeSent = decodeQUTF8(message); message = message.slice(GT.qtToSplice); } else newMessage.ExchangeSent = ""; if (message.length > 0) { newMessage.ExchangeReceived = decodeQUTF8(message); message = message.slice(GT.qtToSplice); } else newMessage.ExchangeReceived = ""; } if (newMessage.type == 6) { newMessage.event = "Close"; } if (newMessage.type == 10) { newMessage.event = "WSPRDecode"; newMessage.NW = decodeQUINT8(message); message = message.slice(GT.qtToSplice); newMessage.TM = decodeQUINT32(message); message = message.slice(GT.qtToSplice); newMessage.SR = decodeQINT32(message); message = message.slice(GT.qtToSplice); newMessage.DT = decodeQDOUBLE(message); message = message.slice(GT.qtToSplice); newMessage.Frequency = decodeQUINT64(message); message = message.slice(GT.qtToSplice); newMessage.Drift = decodeQINT32(message); message = message.slice(GT.qtToSplice); newMessage.Callsign = decodeQUTF8(message); message = message.slice(GT.qtToSplice); newMessage.Grid = decodeQUTF8(message); message = message.slice(GT.qtToSplice); newMessage.Power = decodeQINT32(message); message = message.slice(GT.qtToSplice); newMessage.OA = decodeQUINT8(message); message = message.slice(GT.qtToSplice); newMessage.OF = GT.instances[instanceId].status.Frequency; newMessage.OC = GT.instances[instanceId].status.DEcall; newMessage.OG = GT.instances[instanceId].status.DEgrid; newMessage.OM = GT.instances[instanceId].status.MO; newMessage.OB = GT.instances[instanceId].status.Band; } if (newMessage.type == 12) { newMessage.event = "ADIF"; newMessage.ADIF = decodeQUTF8(message); message = message.slice(GT.qtToSplice); } if (newMessage.type in GT.wsjtHandlers) { newMessage.remote = remote; newMessage.instance = instanceId; lastMsgTimeDiv.innerHTML = $.i18n("gt.newMesg.Recvd") + newMessage.Id; GT.wsjtHandlers[newMessage.type](newMessage); GT.lastTimeSinceMessageInSeconds = parseInt(Date.now() / 1000); } } } }); GT.wsjtUdpServer.bind(port); GT.wsjtCurrentPort = port; GT.wsjtCurrentIP = GT.appSettings.wsjtIP; } function loadLookupDetails() { lookupService.value = GT.appSettings.lookupService; if (lookupService.value == "QRZ") { lookupLogin.value = GT.appSettings.lookupLoginQrz; lookupPassword.value = GT.appSettings.lookupPasswordQrz; } if (lookupService.value == "QRZCQ") { lookupLogin.value = GT.appSettings.lookupLoginCq; lookupPassword.value = GT.appSettings.lookupPasswordCq; } if (lookupService.value == "HAMQTH") { lookupLogin.value = GT.appSettings.lookupLoginQth; lookupPassword.value = GT.appSettings.lookupPasswordQth; } ValidateText(lookupLogin); ValidateText(lookupPassword); if (lookupService.value == "CALLOOK") { lookupCredentials.style.display = "none"; } else lookupCredentials.style.display = "block"; } function lookupValueChanged(what) { if (GT.appSettings.lookupService != lookupService.value) { GT.lastLookupCallsign = ""; if (lookupService.value == "QRZ") { lookupLogin.value = GT.appSettings.lookupLoginQrz; lookupPassword.value = GT.appSettings.lookupPasswordQrz; } if (lookupService.value == "QRZCQ") { lookupLogin.value = GT.appSettings.lookupLoginCq; lookupPassword.value = GT.appSettings.lookupPasswordCq; } if (lookupService.value == "HAMQTH") { lookupLogin.value = GT.appSettings.lookupLoginQth; lookupPassword.value = GT.appSettings.lookupPasswordQth; } } GT.appSettings.lookupService = lookupService.value; GT.appSettings.lookupCallookPreferred = lookupCallookPreferred.checked; lookupQrzTestResult.innerHTML = ""; GT.qrzLookupSessionId = null; if (lookupService.value == "CALLOOK") { lookupCredentials.style.display = "none"; } else lookupCredentials.style.display = "block"; if (ValidateText(lookupLogin) && ValidateText(lookupPassword)) { if (lookupService.value == "QRZ") { GT.appSettings.lookupLoginQrz = lookupLogin.value; GT.appSettings.lookupPasswordQrz = lookupPassword.value; } if (lookupService.value == "QRZCQ") { GT.appSettings.lookupLoginCq = lookupLogin.value; GT.appSettings.lookupPasswordCq = lookupPassword.value; } if (lookupService.value == "HAMQTH") { GT.appSettings.lookupLoginQth = lookupLogin.value; GT.appSettings.lookupPasswordQth = lookupPassword.value; } } } GT.lastLookupCallsign = ""; GT.lookupTimeout = null; function lookupCallsign(callsign, gridPass, useCache = true) { if (GT.mapSettings.offlineMode == true && useCache == false) return; GT.lastLookupCallsign = callsign; if (GT.lookupWindowHandle && GT.lookupWindowInitialized) { GT.lookupWindowHandle.window.lookupCallsignInput.value = callsign; lookupValidateCallByElement("lookupCallsignInput"); } if (GT.lookupTimeout != null) { nodeTimers.clearTimeout(GT.lookupTimeout); GT.lookupTimeout = null; } GT.lookupTimeout = nodeTimers.setTimeout(searchLogForCallsign, 500, callsign); if (useCache) { getLookupCachedObject( callsign, gridPass, cacheLookupObject, continueWithLookup ); } else continueWithLookup(callsign, gridPass); } function continueWithLookup(callsign, gridPass) { setLookupDiv( "lookupInfoDiv", "Looking up " + callsign + ", please wait..." ); if (GT.appSettings.lookupCallookPreferred) { var dxcc = callsignToDxcc(callsign); var where; var ccode = 0; if (dxcc in GT.dxccToAltName) { where = GT.dxccToAltName[dxcc]; ccode = GT.dxccInfo[dxcc].ccode; } else where = "Unknown"; if (ccode == 840) { getBuffer( "https://callook.info/" + callsign + "/json", callookResults, gridPass, "https", 443, true ); } } if (GT.appSettings.lookupService != "CALLOOK") { GT.qrzLookupCallsign = callsign; GT.qrzLookupGrid = gridPass; if ( GT.qrzLookupSessionId == null || timeNowSec() - GT.sinceLastLookup > 3600 ) { GT.qrzLookupSessionId = null; GT.sinceLastLookup = timeNowSec(); GetSessionID(null, true); } else { GT.sinceLastLookup = timeNowSec(); GetLookup(true); } } else { var dxcc = callsignToDxcc(callsign); var where; var ccode = 0; if (dxcc in GT.dxccToAltName) { where = GT.dxccToAltName[dxcc]; ccode = GT.dxccInfo[dxcc].ccode; } else where = "Unknown"; if (ccode == 840) { getBuffer( "https://callook.info/" + callsign + "/json", callookResults, gridPass, "https", 443, true ); } else { var worker = "
" + $.i18n("gt.callookDX1") + "
" + $.i18n("gt.callookDX2") + "
" + $.i18n("gt.callookDX3") + "
"; worker += "
" + $.i18n("gt.callookDX4") + " " + callsign + " " + $.i18n("gt.callookDX5") + " " + where + "
"; worker += "

" + $.i18n("gt.callookDX6") + "
"; worker += $.i18n("gt.callookDX7") + "
"; setLookupDiv("lookupInfoDiv", worker); } } } function callookResults(buffer, gridPass) { var results = JSON.parse(buffer); if (typeof results.status != "undefined") { if (results.status == "VALID") { var callObject = {}; var dxcc = callsignToDxcc(results.current.callsign); if (dxcc in GT.dxccToAltName) callObject.land = GT.dxccToAltName[dxcc]; callObject.type = results.type; callObject.call = results.current.callsign; callObject.dxcc = dxcc; callObject.email = ""; callObject.class = results.current.operClass; callObject.aliases = results.previous.callsign; callObject.trustee = results.trustee.callsign + (results.trustee.name.length > 0 ? "; " + results.trustee.name : ""); callObject.name = results.name; callObject.fname = ""; callObject.addr1 = results.address.line1; callObject.addr2 = results.address.line2; callObject.addrAttn = results.address.attn; callObject.lat = results.location.latitude; callObject.lon = results.location.longitude; callObject.grid = results.location.gridsquare; callObject.efdate = results.otherInfo.grantDate; callObject.expdate = results.otherInfo.expiryDate; callObject.frn = results.otherInfo.frn; callObject.bio = 0; callObject.image = ""; callObject.country = "United States"; if (gridPass) callObject.gtGrid = gridPass; callObject.source = "Source
C A L L O O K
"; cacheLookupObject(callObject, gridPass, true); } else if (results.status == "INVALID") { setLookupDiv("lookupInfoDiv", "Invalid Lookup"); } else { setLookupDiv("lookupInfoDiv", "Server is down for maintenance"); } } else setLookupDiv("lookupInfoDiv", "Unknown Lookup Error"); } GT.qrzLookupSessionId = null; GT.qrzLookupCallsign = ""; GT.qrzLookupGrid = ""; GT.sinceLastLookup = 0; function GetSessionID(resultTd, useCache) { if (GT.mapSettings.offlineMode == true) return; if (resultTd != null) resultTd.innerHTML = "Testing"; if (GT.appSettings.lookupService == "QRZCQ") { getBuffer( "https://ssl.qrzcq.com/xml?username=" + GT.appSettings.lookupLoginCq + "&password=" + encodeURIComponent(GT.appSettings.lookupPasswordCq) + "&agent=GridTracker1.18", qrzGetSessionCallback, resultTd, "https", 443, useCache ); } else if (GT.appSettings.lookupService == "QRZ") { getBuffer( "https://xmldata.qrz.com/xml/current/?username=" + GT.appSettings.lookupLoginQrz + ";password=" + encodeURIComponent(GT.appSettings.lookupPasswordQrz), qrzGetSessionCallback, resultTd, "https", 443, useCache ); } else { getBuffer( "https://www.hamqth.com/xml.php?u=" + GT.appSettings.lookupLoginQth + "&p=" + encodeURIComponent(GT.appSettings.lookupPasswordQth), hamQthGetSessionCallback, resultTd, "https", 443, useCache ); } } function hamQthGetSessionCallback(buffer, resultTd) { var oParser = new DOMParser(); var oDOM = oParser.parseFromString(buffer, "text/xml"); var result = ""; if (oDOM != null) { var json = XML2jsobj(oDOM.documentElement); if (json.hasOwnProperty("session")) { if (json.session.hasOwnProperty("session_id")) { result = "Valid"; GT.qrzLookupSessionId = json.session.session_id; } else { result = "" + json.session.error + ""; GT.qrzLookupSessionId = null; } } else { result = "Invalid Response"; GT.qrzLookupSessionId = null; } } else { result = "Unknown Error"; GT.qrzLookupSessionId = null; } if (resultTd == null) { // It's a true session Request SessionResponse(GT.qrzLookupSessionId, result); } else { GT.qrzLookupSessionId = null; resultTd.innerHTML = result; } } function qrzGetSessionCallback(buffer, resultTd, useCache) { var oParser = new DOMParser(); var oDOM = oParser.parseFromString(buffer, "text/xml"); var result = ""; if (oDOM != null) { var json = XML2jsobj(oDOM.documentElement); if (json.hasOwnProperty("Session")) { if (json.Session.hasOwnProperty("Key")) { result = "Valid"; GT.qrzLookupSessionId = json.Session.Key; } else { result = "" + json.Session.Error + ""; GT.qrzLookupSessionId = null; } } else { result = "Invalid Response"; GT.qrzLookupSessionId = null; } } else { result = "Unknown Error"; GT.qrzLookupSessionId = null; } if (resultTd == null) { // It's a true session Request SessionResponse(GT.qrzLookupSessionId, result, useCache); } else resultTd.innerHTML = result; } function SessionResponse(newKey, result, useCache) { // for QRZCQ.com as well if (newKey == null) { setLookupDiv("lookupInfoDiv", result, useCache); } else { GetLookup(useCache); } } function GetLookup(useCache) { if (GT.appSettings.lookupService == "QRZCQ") { getBuffer( "https://ssl.qrzcq.com/xml?s=" + GT.qrzLookupSessionId + "&callsign=" + GT.qrzLookupCallsign + "&agent=GridTracker", qrzLookupResults, GT.qrzLookupGrid, "https", 443, useCache ); } else if (GT.appSettings.lookupService == "QRZ") { getBuffer( "http://xmldata.qrz.com/xml/current/?s=" + GT.qrzLookupSessionId + ";callsign=" + GT.qrzLookupCallsign, qrzLookupResults, GT.qrzLookupGrid, "http", 80, useCache ); } else { getBuffer( "https://www.hamqth.com/xml.php?id=" + GT.qrzLookupSessionId + "&callsign=" + GT.qrzLookupCallsign + "&prg=GridTracker", qthHamLookupResults, GT.qrzLookupGrid, "https", 443, useCache ); } } function qthHamLookupResults(buffer, gridPass, useCache) { var oParser = new DOMParser(); var oDOM = oParser.parseFromString(buffer, "text/xml"); var result = ""; if (oDOM != null) { var json = XML2jsobj(oDOM.documentElement); if (json.hasOwnProperty("search")) { if (gridPass) json.search.gtGrid = gridPass; json.search.source = "Source
HamQTH
"; cacheLookupObject(json.search, gridPass, true); } else { GT.qrzLookupSessionId = null; setLookupDiv( "lookupInfoDiv", "
" + $.i18n("gt.lookup.NoResult") + "

" ); } } else { setLookupDiv("lookupInfoDiv", buffer); GT.qrzLookupSessionId = null; } } function qrzLookupResults(buffer, gridPass, useCache) { var oParser = new DOMParser(); var oDOM = oParser.parseFromString(buffer, "text/xml"); var result = ""; if (oDOM != null) { var json = XML2jsobj(oDOM.documentElement); if (json.hasOwnProperty("Callsign")) { var call = ""; if (json.Callsign.hasOwnProperty("callsign")) { json.Callsign.call = lookup.callsign; delete json.Callsign.callsign; } if (json.Callsign.hasOwnProperty("call")) call = json.Callsign.call; if (GT.appSettings.lookupService == "QRZ") { json.Callsign.source = "Source
QRZ.com
"; } else { json.Callsign.source = "Source
QRZCQ.com
"; } if (gridPass) json.Callsign.gtGrid = gridPass; cacheLookupObject(json.Callsign, gridPass, true); } else { setLookupDiv( "lookupInfoDiv", "
" + $.i18n("gt.lookup.NoResult") + "

" ); GT.qrzLookupSessionId = null; } } else { setLookupDiv("lookupInfoDiv", buffer); GT.qrzLookupSessionId = null; } } GT.lastLookupAddress = null; GT.Idb = null; GT.Irequest = null; function initialDatabases() { GT.Irequest = window.indexedDB.open("GridTracker", 1); GT.Irequest.onerror = function (event) { alert($.i18n("gt.dbInit.error1") + event.target.errorCode + $.i18n("gt.dbInit.error2")); }; GT.Irequest.onsuccess = function (event) { GT.Idb = GT.Irequest.result; if (!GT.Idb.objectStoreNames.contains("lookups")) { GT.Idb.createObjectStore("lookups", { keyPath: "call" }); } init(); }; GT.Irequest.onupgradeneeded = function (event) { GT.Idb = GT.Irequest.result; if (!GT.Idb.objectStoreNames.contains("lookups")) { GT.Idb.createObjectStore("lookups", { keyPath: "call" }); } init(); }; } function addLookupObjectToIndexedDB(lookupObject) { var request = GT.Idb .transaction(["lookups"], "readwrite") .objectStore("lookups") .put(lookupObject); request.onerror = function (event) { addLastTraffic("Lookup Write Issue"); }; } function getLookupCachedObject( call, gridPass, resultFunction = null, noResultFunction = null, callObject = null ) { var request = GT.Idb .transaction(["lookups"], "readwrite") .objectStore("lookups") .get(call); request.onsuccess = function (event) { if ( request.result && parseInt(request.result.cached) + 604800 > timeNowSec() ) { // 7 days, should an option Tag! I know right?! delete request.result; request.result = null; GT.Idb .transaction(["lookups"], "readwrite") .objectStore("lookups") .delete(call); } if (callObject != null) { if (request.result != null) { callObject.cnty = request.result.cnty; if (callObject.cnty in GT.countyData) { callObject.qual = true; } else { callObject.cnty = null; callObject.qual = false; } } return; } if (request.result != null && resultFunction) { resultFunction(request.result, gridPass, false); } else if (noResultFunction) { noResultFunction(call, gridPass); } }; request.onerror = function (event) { if (noResultFunction) { noResultFunction(call, gridPass); } }; } function cacheLookupObject(lookup, gridPass, cacheable = false) { if (!("cnty" in lookup)) { lookup.cnty = null; } if (lookup.hasOwnProperty("callsign")) { lookup.call = lookup.callsign; delete lookup.callsign; } lookup.call = lookup.call.toUpperCase(); if (lookup.hasOwnProperty("latitude")) { lookup.lat = lookup.latitude; delete lookup.latitude; } if (lookup.hasOwnProperty("longitude")) { lookup.lon = lookup.longitude; delete lookup.longitude; } if (lookup.hasOwnProperty("locator")) { lookup.grid = lookup.locator; delete lookup.locator; } if (lookup.hasOwnProperty("website")) { lookup.url = lookup.website; delete lookup.website; } if (lookup.hasOwnProperty("web")) { lookup.url = lookup.web; delete lookup.web; } if (lookup.hasOwnProperty("qslpic")) { lookup.image = lookup.qslpic; delete lookup.qslpic; } if (lookup.hasOwnProperty("picture")) { lookup.image = lookup.picture; delete lookup.picture; } if (lookup.hasOwnProperty("address")) { lookup.addr1 = lookup.address; delete lookup.address; } if (lookup.hasOwnProperty("adr_city")) { lookup.addr2 = lookup.adr_city; delete lookup.adr_city; } if (lookup.hasOwnProperty("city")) { lookup.addr2 = lookup.city; delete lookup.city; } if (lookup.hasOwnProperty("itu")) { lookup.ituzone = lookup.itu; delete lookup.itu; } if (lookup.hasOwnProperty("cq")) { lookup.cqzone = lookup.cq; delete lookup.cq; } if (lookup.hasOwnProperty("adif")) { lookup.dxcc = lookup.adif; delete lookup.adif; } if (!lookup.hasOwnProperty("dxcc")) { lookup.dxcc = callsignToDxcc(lookup.call.toUpperCase()); } if (lookup.hasOwnProperty("adr_name")) { lookup.name = lookup.adr_name; delete lookup.adr_name; } if (lookup.hasOwnProperty("adr_street1")) { lookup.addr1 = lookup.adr_street1; delete lookup.adr_street1; } if (lookup.hasOwnProperty("us_state")) { lookup.state = lookup.us_state; delete lookup.us_state; } if (lookup.hasOwnProperty("oblast")) { lookup.state = lookup.oblast; delete lookup.oblast; } if (lookup.hasOwnProperty("district")) { lookup.state = lookup.district; delete lookup.district; } if (lookup.hasOwnProperty("adr_zip")) { lookup.zip = lookup.adr_zip; delete lookup.adr_zip; } if (lookup.hasOwnProperty("adr_country")) { lookup.country = lookup.adr_country; delete lookup.adr_country; } if (lookup.hasOwnProperty("us_county")) { lookup.county = lookup.us_county; delete lookup.us_county; } if (lookup.hasOwnProperty("qsldirect")) { lookup.mqsl = lookup.qsldirect; delete lookup.qsldirect; } if (lookup.hasOwnProperty("qsl")) { lookup.bqsl = lookup.qsl; delete lookup.qsl; } if (lookup.hasOwnProperty("utc_offset")) { lookup.GMTOffset = lookup.utc_offset; delete lookup.utc_offset; } if (lookup.hasOwnProperty("land")) { lookup.country = lookup.land; delete lookup.land; } if ("grid" in lookup) { lookup.grid = lookup.grid.toUpperCase(); } if (lookup.hasOwnProperty("state") && lookup.hasOwnProperty("county")) { var foundCounty = false; if (lookup.cnty == null) { lookup.county = lookup.state + ", " + lookup.county; lookup.cnty = replaceAll(lookup.county.toUpperCase(), " ", ""); } if (lookup.cnty in GT.countyData) { for (const hash in GT.liveCallsigns) { if ( GT.liveCallsigns[hash].DEcall == lookup.call && GT.liveCallsigns[hash].state == "US-" + lookup.state ) { GT.liveCallsigns[hash].cnty = lookup.cnty; GT.liveCallsigns[hash].qual = true; GT.liveCallsigns[hash].cntys = 0; foundCounty = true; } } if (foundCounty) { goProcessRoster(); } } else { // console.log( "bad county: " + lookup.cnty); lookup.cnty = null; } } lookup.name = joinSpaceIf( getLookProp(lookup, "fname"), getLookProp(lookup, "name") ); lookup.fname = ""; if (cacheable) { lookup.cached = timeNowSec(); addLookupObjectToIndexedDB(lookup); } displayLookupObject(lookup, gridPass, cacheable); } function displayLookupObject(lookup, gridPass, fromCache = false) { var worker = ""; var thisCall = getLookProp(lookup, "call").toUpperCase(); worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; GT.lastLookupAddress = ""; if (getLookProp(lookup, "addrAttn").length > 0) { worker += ""; worker += ""; worker += ""; } worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += "
"; worker += formatCallsign(getLookProp(lookup, "call").toUpperCase()); worker += ""; if (lookup.dxcc > 0 && lookup.dxcc in GT.dxccInfo) { worker += ""; } worker += ""; var image = getLookProp(lookup, "image"); if (image.length > 0) { worker += ""; } worker += "
"; worker += getLookProp(lookup, "addrAttn"); GT.lastLookupAddress += getLookProp(lookup, "addrAttn") + "\n"; worker += "
"; worker += "" + getLookProp(lookup, "name") + ""; GT.lastLookupAddress += getLookProp(lookup, "name") + "\n"; worker += "
"; worker += getLookProp(lookup, "addr1"); GT.lastLookupAddress += getLookProp(lookup, "addr1") + "\n"; worker += "
"; worker += joinCommaIf( getLookProp(lookup, "addr2"), joinSpaceIf(getLookProp(lookup, "state"), getLookProp(lookup, "zip")) ); GT.lastLookupAddress += joinCommaIf( getLookProp(lookup, "addr2"), joinSpaceIf(getLookProp(lookup, "state"), getLookProp(lookup, "zip")) ) + "\n"; worker += "
"; var country = getLookProp(lookup, "country"); worker += country; GT.lastLookupAddress += country + "\n"; worker += "
"; var email = getLookProp(lookup, "email"); if (email.length > 0) { worker += "
" + email + "
"; GT.lastLookupAddress += email + "\n"; } worker += "
"; var card = "
" + worker + "
"; worker = ""; worker += ""; worker += ""; if (getLookProp(lookup, "url").length > 0) { worker += ""; worker += ""; worker += ""; worker += ""; } if (Number(getLookProp(lookup, "bio")) > 0) { worker += ""; worker += ""; worker += ""; worker += ""; } for (const cid in GT.gtCallsigns[thisCall]) { if (cid in GT.gtFlagPins && GT.gtFlagPins[cid].canmsg == true) { worker += ""; break; } } worker += makeRow("Type", lookup, "type"); worker += makeRow("Class", lookup, "class"); worker += makeRow("Codes", lookup, "codes"); worker += makeRow("QTH", lookup, "qth"); var dates = joinIfBothWithDash( getLookProp(lookup, "efdate"), getLookProp(lookup, "expdate") ); if (dates.length > 0) { worker += ""; } var Aliases = joinCommaIf( getLookProp(lookup, "aliases"), getLookProp(lookup, "p_call") ); if (Aliases.length > 0) { worker += ""; } worker += makeRow("Polish OT", lookup, "plot"); worker += makeRow("German DOK", lookup, "dok"); worker += makeYesNoRow("DOK is Sonder-DOK", lookup, "sondok"); // worker += makeRow("DXCC", lookup, "dxcc"); worker += ""; worker += makeRow("CQ zone", lookup, "cqzone"); worker += makeRow("ITU zone", lookup, "ituzone"); worker += makeRow("IOTA", lookup, "iota"); worker += makeRow("FIPS", lookup, "fips"); worker += makeRow("FRN", lookup, "frn"); worker += makeRow("Timezone", lookup, "TimeZone"); worker += makeRow("GMT Offset", lookup, "GMTOffset"); worker += makeRow("County", lookup, "county"); worker += makeRow("Latitude", lookup, "lat"); worker += makeRow("Longitude", lookup, "lon"); if (getLookProp(lookup, "lat").length > 0 && getLookProp(lookup, "lon").length > 0) { worker += ""; var bearing = parseInt(MyCircle.bearing(GT.myLat, GT.myLon, Number(lookup.lat), Number(lookup.lon))); worker += ""; } worker += makeRow("Grid", lookup, "grid", true); if ( getLookProp(lookup, "gtGrid").length > 0 && getLookProp(lookup, "gtGrid").toUpperCase() != getLookProp(lookup, "grid").toUpperCase() ) { worker += makeRow("GT Grid", lookup, "gtGrid"); } worker += makeRow("Born", lookup, "born"); worker += makeYesNoRow("LoTW", lookup, "lotw"); worker += makeYesNoRow("eQSL", lookup, "eqsl"); worker += makeYesNoRow("Bureau QSL", lookup, "bqsl"); worker += makeYesNoRow("Mail Direct QSL", lookup, "mqsl"); worker += makeRow("QSL Via", lookup, "qsl_via"); worker += makeRow("QRZ Admin", lookup, "user"); worker += makeRow("Prefix", lookup, "prefix"); worker += lookup.source; if (GT.callsignLookups.lotwUseEnable == true && thisCall in GT.lotwCallsigns) { lookup.ulotw = "✋ (" + userDayString(GT.lotwCallsigns[thisCall] * 86400 * 1000) + ")"; worker += makeRow("LoTW Member", lookup, "ulotw"); } if (GT.callsignLookups.eqslUseEnable == true && thisCall in GT.eqslCallsigns) { lookup.ueqsl = "✋"; worker += makeRow("eQSL Member", lookup, "ueqsl"); } if (GT.callsignLookups.oqrsUseEnable == true && thisCall in GT.oqrsCallsigns) { lookup.uoqrs = "✋"; worker += makeRow("ClubLog OQRS", lookup, "uoqrs"); } if (fromCache) { worker += ""; } worker += "
Details
Website"; worker += "
Link
"; worker += "
Biography"; worker += "
Link
"; worker += "
" + $.i18n("rosterColumns.OAMS.user") + "
Effective Dates" + dates + "
Aliases" + Aliases + "
DXCC" + getLookProp(lookup, "dxcc") + " - " + GT.dxccToAltName[getLookProp(lookup, "dxcc")] + "
Distance" + parseInt( MyCircle.distance( GT.myLat, GT.myLon, Number(lookup.lat), Number(lookup.lon), distanceUnit.value ) * MyCircle.validateRadius(distanceUnit.value) ) + distanceUnit.value.toLowerCase() + "
Azimuth" + bearing + "°
Cached Record" + userTimeString(lookup.cached * 1000) + "
"; var details = "
" + worker + "
"; var genMessage = "
Clear
Generate Messages
"; setLookupDiv( "lookupInfoDiv", "" + genMessage + "
" + card + "" + details + "
" ); setLookupDivHeight("lookupBoxDiv", getLookupWindowHeight() + "px"); } function clearLookup() { if (GT.lookupWindowHandle && GT.lookupWindowInitialized) { GT.lookupWindowHandle.window.lookupCallsignInput.value = ""; lookupValidateCallByElement("lookupCallsignInput"); setLookupDiv("lookupLocalDiv", ""); setLookupDiv("lookupInfoDiv", ""); setLookupDivHeight("lookupBoxDiv", getLookupWindowHeight() + "px"); } } function addTextToClipboard(data) { navigator.clipboard.writeText(data); } function saveToCsv(lookup) { var name = joinSpaceIf( getLookProp(lookup, "fname"), getLookProp(lookup, "name") ); var addr1 = getLookProp(lookup, "addr1"); var addr2 = "\"" + joinCommaIf( getLookProp(lookup, "addr2"), joinSpaceIf(getLookProp(lookup, "state"), getLookProp(lookup, "zip")) ) + "\""; var country = getLookProp(lookup, "country"); if ( getLookProp(lookup, "land").length > 0 && country != getLookProp(lookup, "land") ) { country = getLookProp(lookup, "land"); } if (country == "United States") country = ""; tryToWriteAdifToDocFolder( "thanks.csv", name + "," + addr1 + "," + addr2 + "," + country + "\r\n", true ); } function makeYesNoRow(first, object, key) { var value = getLookProp(object, key); if (value.length > 0) { var test = value.toUpperCase(); if (test == "Y") return "" + first + "Yes"; if (test == "N") return "" + first + "No"; if (test == "?") return ""; return ( "" + first + "" + (object[key] == 1 ? "Yes" : "No") + "" ); } return ""; } function makeRow(first, object, key, clip = false) { var value = getLookProp(object, key); if (value.length > 0) { if (clip) { return ( "" + first + "" + object[key].substr(0, 45) + "" ); } else { return ( "" + first + "" + object[key].substr(0, 45) + "" ); } } return ""; } function getLookProp(object, key) { return object.hasOwnProperty(key) ? object[key] : ""; } function joinSpaceIf(camera1, camera2) { if (camera1.length > 0 && camera2.length > 0) return camera1 + " " + camera2; if (camera1.length > 0) return camera1; if (camera2.length > 0) return camera2; return ""; } function joinCommaIf(camera1, camera2) { if (camera1.length > 0 && camera2.length > 0) { if (camera1.indexOf(",") > -1) return camera1 + " " + camera2; else return camera1 + ", " + camera2; } if (camera1.length > 0) return camera1; if (camera2.length > 0) return camera2; return ""; } function joinIfBothWithDash(camera1, camera2) { if (camera1.length > 0 && camera2.length > 0) { return camera1 + " / " + camera2; } return ""; } function startLookup(call, grid) { if (call == "-") return; if (grid == "-") grid = ""; openLookupWindow(true); lookupCallsign(call, grid); } function searchLogForCallsign(call) { setLookupDiv("lookupLocalDiv", ""); var list = Object.values(GT.QSOhash) .filter(function (value) { return value.DEcall == call; }) .sort(GT.appSettings.myBandCompare); var worker = ""; if (call in GT.acknowledgedCalls) { worker = "

" + $.i18n("gt.lookup.acks") + " " + formatCallsign(call) + " " + GT.acknowledgedCalls[call].message + "

"; } var work = {}; var conf = {}; var lastTime = 0; var lastRow = null; var dxcc = (list.length > 0 ? list[0].dxcc : callsignToDxcc(call)); for (row in list) { var what = list[row].band + "," + list[row].mode; if (list[row].time > lastTime) { lastRow = row; lastTime = list[row].time; } if (list[row].confirmed) { conf[what] = GT.pskColors[list[row].band]; if (what in work) delete work[what]; } else if (!(what in conf)) work[what] = GT.pskColors[list[row].band]; } worker += "
"; if (Object.keys(work).length > 0) { worker += ""; } if (Object.keys(conf).length > 0) { worker += ""; } if (lastRow) { worker += ""; } worker += "
Worked"; var k = Object.keys(work).sort(); for (var key in k) { worker += "" + k[key] + " "; } worker += "
Confirmed"; var k = Object.keys(conf).sort(); for (var key in k) { worker += "" + k[key] + " "; } worker += "
Last QSO"; worker += "" + list[lastRow].band + "," + list[lastRow].mode + " " + userTimeString(list[lastRow].time * 1000); worker += "
" + GT.dxccToAltName[dxcc] + " (" + GT.dxccInfo[dxcc].pp + ")"; for (var band in GT.colorBands) { if (String(dxcc) + "|" + GT.colorBands[band] in GT.tracker.worked.dxcc) { var strike = ""; if (String(dxcc) + "|" + GT.colorBands[band] in GT.tracker.confirmed.dxcc) { strike = "text-decoration: underline overline;"; } worker += "
" + GT.colorBands[band] + "
 "; } } worker += "
"; setLookupDiv("lookupLocalDiv", worker); } function startGenMessages(call, grid, instance = null) { if (call == "-") return; if (grid == "-") grid = ""; setCallAndGrid(call, grid, instance); } function is_dir(path) { try { var stat = fs.lstatSync(path); return stat.isDirectory(); } catch (e) { // lstatSync throws an error if path doesn't exist, which isn't an error so don't send it to console return false; } } // Old versions of GridTracker copied its own media files into the // user's media directory. Clean out old duplicate files from the // user directory if they have the same name and size in the // system directory. // function purgeUserFiles(userDir, systemDir) { var userFiles = fs.readdirSync(userDir); var systemFiles = fs.readdirSync(systemDir); userFiles.forEach((filename) => { if (systemFiles.includes(filename)) { var userPath = path.join(userDir, filename); var systemPath = path.join(systemDir, filename); console.log(userPath + " -- " + systemPath); if (fs.statSync(userPath).size == fs.statSync(systemPath).size) { console.log("removing duplicate user media " + filename); try { fs.unlinkSync(userPath); } catch (e) { console.error(e); } } } }); } function mediaCheck() { var homeDir = (GT.platform == "windows") ? process.env.USERPROFILE : process.env.HOME; GT.appData = path.join(homeDir, "OneDrive\\Dokumente"); if (!is_dir(GT.appData)) { GT.appData = path.join(homeDir, "OneDrive\\Documents"); if (!is_dir(GT.appData)) { GT.appData = path.join(homeDir, "Dokumente") if (!is_dir(GT.appData)) { GT.appData = path.join(homeDir, "Documents") if (!is_dir(GT.appData)) { if (GT.appSettings.savedAppData != null) { GT.appData = GT.appSettings.savedAppData; if (!is_dir(GT.appData)) return false; } else { return false; } } } } } GT.appData = path.join(GT.appData, "GridTracker"); GT.userMediaDir = path.join(GT.appData, "media"); GT.jsonDir = path.join(GT.appData, "data"); GT.screenshotDir = path.join(GT.appData, "screenshots"); GT.scriptDir = path.join(GT.appData, "scripts"); GT.NWappData = path.join(nw.App.dataPath, "Ginternal"); try { var tryDirectory = ""; var userdirs = [ GT.appData, GT.NWappData, GT.screenshotDir, GT.scriptDir, GT.userMediaDir ]; for (var dir of userdirs) { if (!fs.existsSync(dir)) { tryDirectory = dir; fs.mkdirSync(dir); } } } catch (e) { alert("Unable to create or access " + tryDirectory + " folder.\r\nPermission violation, GT cannot continue"); nw.App.quit(); } GT.jsonDir += GT.dirSeperator; GT.NWappData += GT.dirSeperator; GT.screenshotDir += GT.dirSeperator; GT.scriptDir += GT.dirSeperator; GT.qsoLogFile = path.join(GT.appData, "GridTracker_QSO.adif"); GT.LoTWLogFile = path.join(GT.appData, "LogbookOfTheWorld.adif"); logEventMedia.appendChild(newOption("none", "None")); msgAlertMedia.appendChild(newOption("none", "Select File")); alertMediaSelect.appendChild(newOption("none", "Select File")); huntCallsignNotifyMedia.appendChild(newOption("none", "Select File")); huntGridNotifyMedia.appendChild(newOption("none", "Select File")); huntDXCCNotifyMedia.appendChild(newOption("none", "Select File")); huntCQzNotifyMedia.appendChild(newOption("none", "Select File")); huntITUzNotifyMedia.appendChild(newOption("none", "Select File")); huntStatesNotifyMedia.appendChild(newOption("none", "Select File")); huntRosterNotifyMedia.appendChild(newOption("none", "Select File")); purgeUserFiles(GT.userMediaDir, GT.gtMediaDir); // add all the files in both directories to the list, user filenames // override system filenames later var mediaFiles = [].concat( fs.readdirSync(GT.userMediaDir), fs.readdirSync(GT.gtMediaDir) ); mediaFiles.forEach((filename) => { var noExt = path.parse(filename).name; logEventMedia.appendChild(newOption(filename, noExt)); alertMediaSelect.appendChild(newOption(filename, noExt)); huntCallsignNotifyMedia.appendChild(newOption(filename, noExt)); huntGridNotifyMedia.appendChild(newOption(filename, noExt)); huntDXCCNotifyMedia.appendChild(newOption(filename, noExt)); huntCQzNotifyMedia.appendChild(newOption(filename, noExt)); huntITUzNotifyMedia.appendChild(newOption(filename, noExt)); huntStatesNotifyMedia.appendChild(newOption(filename, noExt)); huntRosterNotifyMedia.appendChild(newOption(filename, noExt)); msgAlertMedia.appendChild(newOption(filename, noExt)); }); var modeData = fs.readFileSync("./data/modes.json"); GT.modes = JSON.parse(modeData); for (var key in GT.modes) { gtModeFilter.appendChild(newOption(key)); } modeData = fs.readFileSync("./data/modes-phone.json"); GT.modes_phone = JSON.parse(modeData); initQSOdata(); GT.QSOhash = {}; GT.QSLcount = 0; GT.QSOcount = 0; // Old log filenames, no longer referenced tryToDeleteLog("lotw_QSL.adif"); tryToDeleteLog("lotw_QSO.adif"); tryToDeleteLog("lotw.adif"); try { let fileExists = fs.existsSync(GT.NWappData + "internal_qso.json"); if (fileExists == true && GT.startVersion > 1231202) { var data = JSON.parse(fs.readFileSync(GT.NWappData + "internal_qso.json")); GT.tracker = data.tracker; if (typeof GT.tracker.worked.px == "undefined") { GT.tracker.worked.px = {}; GT.tracker.confirmed.px = {}; } if (typeof GT.tracker.worked.pota == "undefined") { GT.tracker.worked.pota = {}; GT.tracker.confirmed.pota = {}; } for (const i in data.g_QSOhash) { GT.QSOhash[i] = fillObjectFromTemplate(def_qso, data.g_QSOhash[i]); GT.QSOcount++; if (GT.QSOhash[i].confirmed) GT.QSLcount++; } fs.unlinkSync(GT.NWappData + "internal_qso.json"); } else if (fileExists == true) { fs.unlinkSync(GT.NWappData + "internal_qso.json"); } loadReceptionReports(); } catch (e) { } return true; } function newOption(value, text) { if (typeof text == "undefined") text = value; var option = document.createElement("option"); option.value = value; option.text = text; return option; } GT.rosterSpot = false; function setRosterSpot(enabled) { GT.rosterSpot = enabled; } function saveReceptionReports() { try { fs.writeFileSync( GT.NWappData + "spots.json", JSON.stringify(GT.receptionReports) ); } catch (e) { console.error(e); } } function loadReceptionReports() { try { var clear = true; if (fs.existsSync(GT.NWappData + "spots.json")) { GT.receptionReports = JSON.parse( fs.readFileSync(GT.NWappData + "spots.json") ); if (timeNowSec() - GT.receptionReports.lastDownloadTimeSec <= 86400) { clear = false; } } if (clear == true) { GT.receptionReports = { lastDownloadTimeSec: 0, lastSequenceNumber: "0", spots: {} }; } } catch (e) { GT.receptionReports = { lastDownloadTimeSec: 0, lastSequenceNumber: "0", spots: {} }; } } function pskSpotCheck(timeSec) { if (GT.mapSettings.offlineMode == true) return; if (GT.appSettings.myCall == null || GT.appSettings.myCall == "NOCALL" || GT.appSettings.myCall == "") return; if ( (GT.spotView > 0 || GT.rosterSpot) && (GT.receptionReports.lastDownloadTimeSec < GT.lastTrasmissionTimeSec) && ( timeSec - GT.receptionReports.lastDownloadTimeSec > PSKREPORTER_INTERVAL_IN_SECONDS || GT.receptionReports.lastDownloadTimeSec > timeSec ) ) { GT.receptionReports.lastDownloadTimeSec = timeSec; localStorage.receptionSettings = JSON.stringify(GT.receptionSettings); spotRefreshDiv.innerHTML = "…refreshing…"; getBuffer( `https://retrieve.pskreporter.info/query?rronly=1&lastseqno=${GT.receptionReports.lastSequenceNumber}` + `&senderCallsign=${encodeURIComponent(GT.appSettings.myRawCall)}` + `&appcontact=${encodeURIComponent(`GT-${pjson.version}`)}`, pskSpotResults, null, "https", 443 ); } else if (GT.spotView > 0) { if ( GT.lastTrasmissionTimeSec < GT.receptionReports.lastDownloadTimeSec && (timeSec - GT.receptionReports.lastDownloadTimeSec) > PSKREPORTER_INTERVAL_IN_SECONDS ) { spotRefreshDiv.innerHTML = "No recent TX"; } else { spotRefreshDiv.innerHTML = "Refresh: " + toDHMS(Number(PSKREPORTER_INTERVAL_IN_SECONDS - (timeSec - GT.receptionReports.lastDownloadTimeSec))); } } } function pskSpotResults(buffer, flag) { var oParser = new DOMParser(); var oDOM = oParser.parseFromString(buffer, "text/xml"); var result = ""; if (oDOM != null) { var json = XML2jsobj(oDOM.documentElement); if ("lastSequenceNumber" in json) { GT.receptionReports.lastSequenceNumber = json.lastSequenceNumber.value; if ("receptionReport" in json) { for (const key in json.receptionReport) { if (typeof json.receptionReport[key].frequency != "undefined" && typeof json.receptionReport[key].sNR != "undefined") { var report; var call = json.receptionReport[key].receiverCallsign; var mode = json.receptionReport[key].mode; var grid = json.receptionReport[key].receiverLocator.substr(0, 6); if (grid.length < 4) { continue; } var band = formatBand(Number(parseInt(json.receptionReport[key].frequency) / 1000000)); var hash = call + mode + band; if (hash in GT.receptionReports.spots) { report = GT.receptionReports.spots[hash]; if (parseInt(json.receptionReport[key].flowStartSeconds) < report.when) { continue; } } else { report = GT.receptionReports.spots[hash] = {}; report.call = call; report.band = band; report.grid = grid.toUpperCase(); report.mode = mode; } if (typeof json.receptionReport[key].receiverCallsign != "undefined") { report.dxcc = callsignToDxcc(json.receptionReport[key].receiverCallsign); } else report.dxcc = -1; report.when = parseInt(json.receptionReport[key].flowStartSeconds); report.snr = json.receptionReport[key].sNR; report.freq = parseInt(json.receptionReport[key].frequency); var SNR = parseInt((parseInt(report.snr) + 25) * 9); if (SNR > 255) SNR = 255; if (SNR < 0) SNR = 0; report.color = SNR; report.source = "P"; } } } } } GT.receptionReports.lastDownloadTimeSec = timeNowSec(); localStorage.receptionSettings = JSON.stringify(GT.receptionSettings); redrawSpots(); if (GT.rosterSpot) goProcessRoster(); } GT.oamsSpotTimeout = null; function addNewOAMSSpot(cid, db, frequency, band, mode) { if (GT.oamsSpotTimeout !== null) { nodeTimers.clearTimeout(GT.oamsSpotTimeout); GT.oamsSpotTimeout = null; } var report; var call = GT.gtFlagPins[cid].call; var grid = GT.gtFlagPins[cid].grid.substr(0, 6); var hash = call + mode + band; if (hash in GT.receptionReports.spots) { report = GT.receptionReports.spots[hash]; } else { report = GT.receptionReports.spots[hash] = {}; report.call = call; report.band = band; report.grid = grid; report.mode = mode; } report.dxcc = GT.gtFlagPins[cid].dxcc; report.when = timeNowSec(); report.snr = Number(db); report.freq = frequency; var SNR = parseInt((parseInt(report.snr) + 25) * 9); if (SNR > 255) SNR = 255; if (SNR < 0) SNR = 0; report.color = SNR; report.source = "O"; GT.oamsSpotTimeout = nodeTimers.setTimeout(redrawSpots, 250); } function spotFeature(center) { return new ol.Feature( ol.geom.Polygon.circular(center, 30000, 63).transform( "EPSG:4326", "EPSG:3857" ) ); } GT.spotTotalCount = 0; function createSpot(report, key, fromPoint, addToLayer = true) { try { var LL = squareToCenter(report.grid); if (isNaN(LL.a)) { // Bad value in grid, don't map // return; } var spot = spotFeature([LL.o, LL.a]); var colorNoAlpha = "#" + GT.bandToColor[report.band]; var colorAlpha = intAlphaToRGB(colorNoAlpha, report.color); var spotColor = colorAlpha; var workingColor = GT.mapSettings.nightMapEnable && GT.nightTime ? GT.receptionSettings.pathNightColor : GT.receptionSettings.pathColor; if (workingColor != -1) { var testColor = workingColor < 1 ? "#0000000" : workingColor == 361 ? "#FFFFFF" : "hsla(" + workingColor + ", 100%, 50%," + report.color / 255 + ")"; if (workingColor < 1 || workingColor == 361) { spotColor = intAlphaToRGB(testColor.substr(0, 7), report.color); } else { spotColor = testColor; } } featureStyle = new ol.style.Style({ fill: new ol.style.Fill({ color: spotColor }), stroke: new ol.style.Stroke({ color: "#000000FF", width: 0.25 }) }); spot.setStyle(featureStyle); spot.spot = key; spot.set("prop", "spot"); spot.size = 6; // Mouseover detection GT.layerSources["psk-spots"].addFeature(spot); var toPoint = ol.proj.fromLonLat([LL.o, LL.a]); var lonLat = new ol.geom.Point(toPoint); var pointFeature = new ol.Feature({ geometry: lonLat, weight: report.color / 255 // e.g. temperature }); GT.layerSources["psk-heat"].addFeature(pointFeature); if (GT.receptionSettings.viewPaths && GT.receptionSettings.spotWidth > 0) { var strokeWeight = GT.receptionSettings.spotWidth; var flightColor = workingColor == -1 ? colorNoAlpha + "BB" : GT.mapSettings.nightMapEnable && GT.nightTime ? GT.spotNightFlightColor : GT.spotFlightColor; flightFeature( [fromPoint, toPoint], { weight: strokeWeight, color: flightColor, steps: 75 }, "psk-flights", false ); } } catch (err) { console.error("Unexpected error inside createSpot", report, err) } } function redrawSpots() { var shouldSave = false; var now = timeNowSec(); GT.spotTotalCount = 0; GT.layerSources["psk-spots"].clear(); GT.layerSources["psk-flights"].clear(); GT.layerSources["psk-hop"].clear(); GT.layerSources["psk-heat"].clear(); var fromPoint = getPoint(GT.appSettings.myRawGrid); if (GT.receptionSettings.mergeSpots == false) { var spot = iconFeature(fromPoint, GT.gtFlagIcon, 100, "homeFlag"); GT.layerSources["psk-spots"].addFeature(spot); } for (var key in GT.receptionReports.spots) { report = GT.receptionReports.spots[key]; if ((now - report.when > 86400) || (report.grid.length < 4)) { delete GT.receptionReports.spots[key]; shouldSave = true; continue; } if (validateMapBandAndMode(report.band, report.mode)) { if (now - report.when <= GT.receptionSettings.viewHistoryTimeSec) { createSpot(report, key, fromPoint); GT.spotTotalCount++; } } } if (shouldSave) { saveReceptionReports(); } updateSpotCountDiv(); } function updateSpotCountDiv() { spotCountDiv.innerHTML = "Spots: " + GT.spotTotalCount; } GT.spotFlightColor = "#FFFFFFBB"; GT.spotNightFlightColor = "#FFFFFFBB"; function changeSpotValues() { GT.receptionSettings.viewHistoryTimeSec = parseInt(spotHistoryTimeValue.value) * 60; spotHistoryTimeTd.innerHTML = "Max Age: " + toDHM(Number(GT.receptionSettings.viewHistoryTimeSec)); GT.receptionSettings.viewPaths = spotPathsValue.checked; if (GT.receptionSettings.viewPaths) { spotPathWidthDiv.style.display = "inline-block"; } else { spotPathWidthDiv.style.display = "none"; } GT.receptionSettings.mergeSpots = spotMergeValue.checked; localStorage.receptionSettings = JSON.stringify(GT.receptionSettings); setTrophyOverlay(GT.currentOverlay); updateSpotView(); if (GT.rosterSpot) goProcessRoster(); } function mapTransChange() { GT.mapSettings.mapTrans = mapTransValue.value; mapTransTd.innerHTML = String(100 - parseInt(((GT.mapSettings.mapTrans * 255) / 255) * 100)) + "%"; mapSettingsDiv.style.backgroundColor = "rgba(0,0,0, " + GT.mapSettings.mapTrans + ")"; } function spotPathChange() { GT.receptionSettings.pathColor = spotPathColorValue.value; var pathColor = GT.receptionSettings.pathColor < 1 ? "#000" : GT.receptionSettings.pathColor == 361 ? "#FFF" : "hsl(" + GT.receptionSettings.pathColor + ", 100%, 50%)"; if (GT.receptionSettings.pathColor > 0) { spotPathColorDiv.style.color = "#000"; spotPathColorDiv.style.backgroundColor = pathColor; } else { spotPathColorDiv.style.color = "#FFF"; spotPathColorDiv.style.backgroundColor = pathColor; } if (GT.receptionSettings.pathColor == -1) { spotPathInfoTd.innerHTML = "PSK-Reporter Palette"; } else spotPathInfoTd.innerHTML = ""; GT.spotFlightColor = GT.receptionSettings.pathColor < 1 ? "#0000000BB" : GT.receptionSettings.pathColor == 361 ? "#FFFFFFBB" : "hsla(" + GT.receptionSettings.pathColor + ", 100%, 50%,0.73)"; GT.receptionSettings.pathNightColor = spotNightPathColorValue.value; var pathNightColor = GT.receptionSettings.pathNightColor < 1 ? "#000" : GT.receptionSettings.pathNightColor == 361 ? "#FFF" : "hsl(" + GT.receptionSettings.pathNightColor + ", 100%, 50%)"; if (GT.receptionSettings.pathNightColor > 0) { spotNightPathColorDiv.style.color = "#000"; spotNightPathColorDiv.style.backgroundColor = pathNightColor; } else { spotNightPathColorDiv.style.color = "#FFF"; spotNightPathColorDiv.style.backgroundColor = pathNightColor; } if (GT.receptionSettings.pathNightColor == -1) { spotNightPathInfoTd.innerHTML = "PSK-Reporter Palette"; } else spotNightPathInfoTd.innerHTML = ""; GT.spotNightFlightColor = GT.receptionSettings.pathNightColor < 1 ? "#0000000BB" : GT.receptionSettings.pathNightColor == 361 ? "#FFFFFFBB" : "hsla(" + GT.receptionSettings.pathNightColor + ", 100%, 50%,0.73)"; spotWidthTd.innerHTML = GT.receptionSettings.spotWidth = spotWidthValue.value; localStorage.receptionSettings = JSON.stringify(GT.receptionSettings); } function toggleSpotOverGrids() { spotMergeValue.checked = spotMergeValue.checked != true; changeSpotValues(); redrawSpots(); } function toggleMergeOverlay() { mergeOverlayValue.checked = mergeOverlayValue.checked != true; changeMergeOverlayValue(); } function toggleSpotPaths() { var spotPaths = spotPathsValue.checked == true ? 1 : 0; spotPaths ^= 1; spotPathsValue.checked = spotPaths == 1; GT.receptionSettings.viewPaths = spotPathsValue.checked; localStorage.receptionSettings = JSON.stringify(GT.receptionSettings); if (GT.receptionSettings.viewPaths) { spotPathWidthDiv.style.display = "inline-block"; } else { spotPathWidthDiv.style.display = "none"; } redrawSpots(); } function setSpotImage() { spotsButtonImg.src = GT.spotImageArray[GT.spotView]; spotsButtonImg.style.filter = (GT.spotView == 0) ? "grayscale(1)" : ""; } function cycleSpotsView() { GT.spotView++; GT.spotView %= 3; GT.appSettings.spotView = GT.spotView; setSpotImage(); setTrophyOverlay(GT.currentOverlay); updateSpotView(); } function toggleCRScript() { GT.crScript ^= 1; GT.appSettings.crScript = GT.crScript; if (GT.crScript == 1) { addLastTraffic( "Call Roster Script Enabled" ); } else { addLastTraffic( "Call Roster Script Disabled" ); } goProcessRoster(); } function updateSpotView(leaveCount = true) { if (GT.spotView > 0) { if (GT.receptionSettings.mergeSpots == false) { for (var key in GT.layerVectors) { GT.layerVectors[key].setVisible(false); } } if (GT.spotView == 1) { GT.layerVectors["psk-spots"].setVisible(true); GT.layerVectors["psk-flights"].setVisible(true); GT.layerVectors["psk-hop"].setVisible(true); GT.layerVectors["psk-heat"].setVisible(false); } else { GT.layerVectors["psk-spots"].setVisible(false); GT.layerVectors["psk-flights"].setVisible(false); GT.layerVectors["psk-hop"].setVisible(false); GT.layerVectors["psk-heat"].setVisible(true); } SpotsDiv.style.display = "block"; if (leaveCount == false) spotRefreshDiv.innerHTML = " "; } else { GT.layerVectors["psk-spots"].setVisible(false); GT.layerVectors["psk-flights"].setVisible(false); GT.layerVectors["psk-hop"].setVisible(false); GT.layerVectors["psk-heat"].setVisible(false); SpotsDiv.style.display = "none"; spotRefreshDiv.innerHTML = " "; } } function gotoDonate() { var gui = require("nw.gui"); gui.Shell.openExternal("https://gridtracker.org/donations/"); } function getSpotTime(hash) { if (hash in GT.receptionReports.spots) { return GT.receptionReports.spots[hash]; } else return null; } function setGridOpacity() { opacityValue.value = GT.mapSettings.gridAlpha; showOpacityTd.innerHTML = parseInt((GT.mapSettings.gridAlpha / 255) * 100) + "%"; GT.gridAlpha = parseInt(GT.mapSettings.gridAlpha).toString(16); } function changeGridOpacity() { GT.mapSettings.gridAlpha = opacityValue.value; showOpacityTd.innerHTML = parseInt((GT.mapSettings.gridAlpha / 255) * 100) + "%"; GT.gridAlpha = parseInt(GT.mapSettings.gridAlpha).toString(16); saveMapSettings(); } function currentTimeStampString() { var now = new Date(); return ( now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate() + " " + padNumber(now.getHours()) + "." + padNumber(now.getMinutes()) + "." + padNumber(now.getSeconds()) ); } function showNativeFolder(fn) { nw.Shell.showItemInFolder(decodeURI(fn)); } function makeScreenshots() { var win = gui.Window.get(); win.capturePage( function (buffer) { var clipboard = nw.Clipboard.get(); clipboard.set(buffer, "png", true); }, { format: "png", datatype: "raw" } ); win.capturePage( function (buffer) { try { var fn = GT.screenshotDir + "Screenshot " + currentTimeStampString() + ".png"; fs.writeFileSync(fn, buffer); addLastTraffic( "Saved Screenshot" ); } catch (e) { addLastTraffic( "Screenshot write failed" ); } }, { format: "png", datatype: "buffer" } ); } function refreshSpotsNoTx() { redrawSpots(); } nodeTimers.setInterval(refreshSpotsNoTx, 300000); nodeTimers.setTimeout(refreshSpotsNoTx, 300000);