gridtracker/package.nw/lib/gt.js

16070 wiersze
416 KiB
JavaScript

// 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;
var g_startVersion = 0;
if (typeof localStorage.currentVersion != "undefined")
{
g_startVersion = localStorage.currentVersion;
}
if (typeof localStorage.currentVersion == "undefined" || localStorage.currentVersion != String(gtVersion))
{
localStorage.currentVersion = String(gtVersion);
var gui = require("nw.gui");
gui.App.clearCache();
}
var vers = String(gtVersion);
var gtShortVersion =
"v" +
vers.substr(0, 1) +
"." +
vers.substr(1, 2) +
"." +
vers.substr(3, 4) +
" " +
gtBeta;
var gtVersionString = "GridTracker " + gtShortVersion;
var g_windowName = "GT-main";
const os = require("os");
const fs = require("fs");
const process = require("process");
const path = require("path");
const g_dirSeperator = path.sep;
var g_platform = os.platform();
if (g_platform.indexOf("win") == 0 || g_platform.indexOf("Win") == 0)
{
g_platform = "windows";
}
if (g_platform.indexOf("inux") > -1)
{
g_platform = "linux";
}
if (g_platform.indexOf("darwin") > -1)
{
g_platform = "mac";
}
var gui = require("nw.gui");
var win = gui.Window.get();
var g_developerMode = process.versions["nw-flavor"] == "sdk";
var g_popupWindowHandle = null;
var g_callRosterWindowHandle = null;
var g_conditionsWindowHandle = null;
var g_chatWindowHandle = null;
var g_statsWindowHandle = null;
var g_lookupWindowHandle = null;
var g_lookupWindowInitialized = false;
var g_baWindowHandle = null;
var g_baWindowInitialized = false;
var g_appSettings = {};
var g_mapSettings = {};
var g_legendColors = {};
var g_adifLogSettings = {};
var g_msgSettings = {};
var g_receptionSettings = {};
var g_receptionReports = {
lastDownloadTimeSec: 0,
lastSequenceNumber: "0",
spots: {}
};
var g_N1MMSettings = {};
var g_log4OMSettings = {};
var g_dxkLogSettings = {};
var g_HRDLogbookLogSettings = {};
var g_acLogSettings = {};
var g_trustedQslSettings = {};
var g_callsignLookups = {};
var g_startupLogs = [];
var g_mapMemory = [];
var g_callsignDatabaseDXCC = {
291: true,
1: true,
6: true,
110: true,
202: true
};
var g_callsignDatabaseUS = {
291: true,
6: true,
110: true
};
var g_callsignDatabaseUSplus = {
291: true,
6: true,
110: true,
202: true
};
var g_acknowledgedCalls = {};
function loadAllSettings()
{
for (var x in localStorage)
{
if (!validSettings.includes(x) && typeof localStorage[x] == "string")
{
delete localStorage[x];
}
}
g_appSettings = loadDefaultsAndMerge("appSettings", def_appSettings);
g_mapSettings = loadDefaultsAndMerge("mapSettings", def_mapSettings);
g_legendColors = loadDefaultsAndMerge("legendColors", def_legendColors);
g_adifLogSettings = loadDefaultsAndMerge(
"adifLogSettings",
def_adifLogSettings
);
g_msgSettings = loadDefaultsAndMerge("msgSettings", def_msgSettings);
g_receptionSettings = loadDefaultsAndMerge(
"receptionSettings",
def_receptionSettings
);
g_N1MMSettings = loadDefaultsAndMerge("N1MMSettings", def_N1MMSettings);
g_log4OMSettings = loadDefaultsAndMerge("log4OMSettings", def_log4OMSettings);
g_dxkLogSettings = loadDefaultsAndMerge("dxkLogSettings", def_dxkLogSettings);
g_HRDLogbookLogSettings = loadDefaultsAndMerge(
"HRDLogbookLogSettings",
def_HRDLogbookLogSettings
);
g_pstrotatorSettings = loadDefaultsAndMerge(
"pstrotatorSettings",
def_pstrotatorSettings
);
g_acLogSettings = loadDefaultsAndMerge("acLogSettings", def_acLogSettings);
g_trustedQslSettings = loadDefaultsAndMerge(
"trustedQslSettings",
def_trustedQslSettings
);
g_callsignLookups = loadDefaultsAndMerge(
"callsignLookups",
def_callsignLookups
);
g_bandActivity = loadDefaultsAndMerge("bandActivity", def_bandActivity);
g_startupLogs = loadArrayIfExists("startupLogs");
g_mapMemory = loadArrayIfExists("mapMemory");
if (g_mapMemory.length != 7)
{
g_mapMemory = [];
for (var x = 0; x < 7; x++)
{
g_mapMemory[x] = {};
g_mapMemory[x].zoom = -1;
g_mapMemory[x].LoLa = [0, 0];
}
g_appSettings.mapMemory = JSON.stringify(g_mapMemory);
}
}
loadAllSettings();
const k_frequencyBucket = 10000;
var myDEcall = g_appSettings.myDEcall;
var myDEGrid = g_appSettings.myDEGrid;
var myDXGrid = "";
var myMode = g_appSettings.myMode;
var myBand = g_appSettings.myBand;
var myRawFreq = g_appSettings.myRawFreq;
var myRawCall = g_appSettings.myRawCall;
var myRawGrid = g_appSettings.myRawGrid;
var g_flightDuration = 30;
var g_crScript = g_appSettings.crScript;
var g_spotView = g_appSettings.spotView;
var g_myLat = g_mapSettings.latitude;
var g_myLon = g_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(g_appSettings);
}
function saveMapSettings()
{
localStorage.mapSettings = JSON.stringify(g_mapSettings);
}
function saveLegendColors()
{
localStorage.legendColors = JSON.stringify(g_legendColors);
}
function saveAdifSettings()
{
localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings);
}
function saveStartupLogs()
{
localStorage.startupLogs = JSON.stringify(g_startupLogs);
}
function saveLogSettings()
{
localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings);
localStorage.N1MMSettings = JSON.stringify(g_N1MMSettings);
localStorage.log4OMSettings = JSON.stringify(g_log4OMSettings);
localStorage.dxkLogSettings = JSON.stringify(g_dxkLogSettings);
localStorage.HRDLogbookLogSettings = JSON.stringify(g_HRDLogbookLogSettings);
localStorage.pstrotatorSettings = JSON.stringify(g_pstrotatorSettings);
localStorage.acLogSettings = JSON.stringify(g_acLogSettings);
localStorage.trustedQslSettings = JSON.stringify(g_trustedQslSettings);
}
function saveAndCloseApp()
{
g_closing = true;
saveReceptionReports();
try
{
var data = {};
data.version = gtVersion;
data.tracker = g_tracker;
for (var key in g_QSOhash) g_QSOhash[key].rect = null;
data.g_QSOhash = g_QSOhash;
fs.writeFileSync(g_NWappData + "internal_qso.json", JSON.stringify(data));
saveScreenSettings();
g_conditionsWindowHandle.window.saveScreenSettings();
g_callRosterWindowHandle.window.saveScreenSettings();
g_statsWindowHandle.window.saveScreenSettings();
g_baWindowHandle.window.saveScreenSettings();
g_lookupWindowHandle.window.saveScreenSettings();
g_chatWindowHandle.window.saveScreenSettings();
}
catch (e)
{
console.error(e);
}
if (g_map)
{
mapMemory(6, true, true);
g_mapSettings.zoom = g_map.getView().getZoom();
saveMapSettings();
}
if (g_wsjtUdpServer != null)
{
try
{
if (multicastEnable.checked == true && g_appSettings.wsjtIP != "")
{
g_wsjtUdpServer.dropMembership(g_appSettings.wsjtIP);
}
g_wsjtUdpServer.close();
}
catch (e)
{
console.error(e);
}
}
if (g_forwardUdpServer != null)
{
g_forwardUdpServer.close();
}
saveAppSettings();
saveAdifSettings();
saveMapSettings();
saveLegendColors();
try
{
if (g_rosterInitialized)
{
g_callRosterWindowHandle.window.writeRosterSettings();
}
if (g_popupWindowHandle != null) g_popupWindowHandle.window.close(true);
g_conditionsWindowHandle.window.close(true);
g_chatWindowHandle.window.close(true);
g_statsWindowHandle.window.close(true);
g_lookupWindowHandle.window.close(true);
g_baWindowHandle.window.close(true);
g_callRosterWindowHandle.window.close(true);
}
catch (e)
{
console.error(e);
}
nw.App.quit();
}
function clearAndReload()
{
g_closing = true;
if (g_wsjtUdpServer != null)
{
g_wsjtUdpServer.close();
g_wsjtUdpServer = null;
}
localStorage.clear();
chrome.runtime.reload();
}
win.hide();
win.on("close", function ()
{
saveAndCloseApp();
});
win.show();
win.setMinimumSize(200, 600);
var g_wsjtxProcessRunning = false;
var g_jtdxProcessRunning = false;
var g_wsjtxIni = Array();
var g_jtdxIni = Array();
var g_setNewUdpPortTimeoutHandle = null;
var g_map = null;
var g_menuShowing = true;
var g_closing = false;
var g_liveGrids = {};
var g_qsoGrids = {};
var g_liveCallsigns = {};
var g_flightPaths = Array();
var g_flightPathOffset = 0;
var g_flightPathLineDash = [9, 3, 3];
var g_flightPathTotal = (9 + 3 + 3) * 2;
var g_lastMessages = Array();
var g_lastTraffic = Array();
var g_showAllGrids = false;
var g_maps = Array();
var g_modes = {};
var g_modes_phone = {};
var g_colorBands = [
"OOB",
"4000m",
"2200m",
"630m",
"160m",
"80m",
"60m",
"40m",
"30m",
"20m",
"17m",
"15m",
"12m",
"11m",
"10m",
"8m",
"6m",
"4m",
"2m",
"1.25m",
"70cm",
"23cm",
"13cm",
"9cm",
"5cm",
"3cm",
"1.2cm",
"6mm",
"4mm",
"2.5mm",
"2mm",
"1mm"
];
var g_pathIgnore = {};
g_pathIgnore.RU = true;
g_pathIgnore.FTRU = true;
g_pathIgnore.FD = true;
g_pathIgnore.TEST = true;
g_pathIgnore.DX = true;
g_pathIgnore.CQ = true;
var g_replaceCQ = {};
g_replaceCQ.ASIA = "AS";
var g_myDXCC = -1;
var g_QSOhash = {};
var g_QSLcount = 0;
var g_QSOcount = 0;
var g_ignoreMessages = 0;
var g_lastTimeSinceMessageInSeconds = timeNowSec();
var g_loadQSOs = false;
var g_mainBorderColor = "#222222FF";
var g_pushPinMode = false;
var g_pskBandActivityTimerHandle = null;
var g_workingIniPath = "";
var g_dxccInfo = {};
var g_prefixToMap = {};
var g_directCallToDXCC = {};
var g_directCallToCQzone = {};
var g_directCallToITUzone = {};
var g_prefixToCQzone = {};
var g_prefixToITUzone = {};
var g_dxccToAltName = {};
var g_dxccToADIFName = {};
var g_gridToDXCC = {};
var g_gridToState = {};
var g_StateData = {};
var g_cqZones = {};
var g_wacZones = {};
var g_wasZones = {};
var g_ituZones = {};
var g_dxccCount = {};
var g_unconfirmedCalls = new Map();
var g_tracker = {};
var g_lastTrasmissionTimeSec = timeNowSec();
const PSKREPORTER_INTERVAL_IN_SECONDS = 5 * 60;
initQSOdata();
function initQSOdata()
{
g_tracker.worked = {};
g_tracker.confirmed = {};
g_tracker.worked.call = {};
g_tracker.worked.grid = {};
g_tracker.worked.dxcc = {};
g_tracker.worked.cqz = {};
g_tracker.worked.ituz = {};
g_tracker.worked.state = {};
g_tracker.worked.px = {};
g_tracker.worked.cnty = {};
g_tracker.worked.cont = {};
g_tracker.worked.pota = {};
g_tracker.confirmed.call = {};
g_tracker.confirmed.grid = {};
g_tracker.confirmed.dxcc = {};
g_tracker.confirmed.cqz = {};
g_tracker.confirmed.ituz = {};
g_tracker.confirmed.state = {};
g_tracker.confirmed.px = {};
g_tracker.confirmed.cnty = {};
g_tracker.confirmed.cont = {};
// Not referenced but included for consistency
g_tracker.confirmed.pota = {};
}
var g_offlineLayer = null;
var g_mapsLayer = Array();
var g_tileLayer = null;
var g_mapView = null;
var g_layerSources = {};
var g_layerVectors = {};
var g_scaleLine = null;
var g_scaleUnits = {};
g_scaleUnits.MI = "us";
g_scaleUnits.KM = "metric";
g_scaleUnits.NM = "nautical";
g_scaleUnits.DG = "degrees";
var g_passingToolTipTableString = "";
var g_mouseX = 0;
var g_mouseY = 0;
var g_appData = "";
var g_jsonDir = "";
var g_NWappData = "";
var g_screenshotDir = "";
var g_scriptDir = "";
var g_qsoLogFile = "";
var g_LoTWLogFile = "";
var g_userMediaDir = "";
var g_gtMediaDir = path.resolve("./media");
var g_localeString = navigator.language;
var g_shapeFile = "./data/shapes.json";
var g_mapsFile = "./data/maps.json";
var g_voices = null;
var g_shapeData = {};
var g_countyData = {};
var g_zipToCounty = {};
var g_stateToCounty = {};
var g_cntyToCounty = {};
var g_us48Data = {};
var g_pskColors = {};
g_pskColors.OOB = "888888";
g_pskColors["4000m"] = "45E0FF";
g_pskColors["2200m"] = "FF4500";
g_pskColors["630m"] = "1E90FF";
g_pskColors["160m"] = "7CFC00";
g_pskColors["80m"] = "E550E5";
g_pskColors["60m"] = "0000FF";
g_pskColors["40m"] = "4949FF";
g_pskColors["30m"] = "62FF62";
g_pskColors["20m"] = "FFC40C";
g_pskColors["17m"] = "F2F261";
g_pskColors["15m"] = "CCA166";
g_pskColors["12m"] = "B22222";
g_pskColors["11m"] = "00FF00";
g_pskColors["10m"] = "FF69B4";
g_pskColors["6m"] = "FF0000";
g_pskColors["4m"] = "CC0044";
g_pskColors["2m"] = "FF1493";
g_pskColors["1.25m"] = "CCFF00";
g_pskColors["70cm"] = "999900";
g_pskColors["33cm"] = "009999";
g_pskColors["23cm"] = "5AB8C7";
var g_bandToColor = {};
var g_colorLeafletPins = {};
var g_colorLeafletQPins = {};
var g_UTCoptions = {
year: "numeric",
month: "numeric",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
timeZone: "UTC",
timeZoneName: "short"
};
var g_LocalOptions = {
year: "numeric",
month: "numeric",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
timeZoneName: "short"
};
var g_earthShadowImageArray = Array();
g_earthShadowImageArray[0] = "./img/shadow_on_32.png";
g_earthShadowImageArray[1] = "./img/shadow_off_32.png";
var g_gtFlagImageArray = Array();
g_gtFlagImageArray[1] = "./img/flag_on.png";
g_gtFlagImageArray[0] = "./img/flag_off.png";
var g_gtShareFlagImageArray = Array();
g_gtShareFlagImageArray[1] = "./img/share-on.png";
g_gtShareFlagImageArray[0] = "./img/share-off.png";
var g_mapImageArray = Array();
g_mapImageArray[1] = "./img/online_map.png";
g_mapImageArray[0] = "./img/offline_map.png";
var g_pinImageArray = Array();
g_pinImageArray[1] = "./img/red_pin_32.png";
g_pinImageArray[0] = "./img/gt_grid.png";
var g_qsoLockImageArray = Array();
g_qsoLockImageArray[0] = "./img/qso_unlocked_32.png";
g_qsoLockImageArray[1] = "./img/qso_locked_32.png";
var g_qslLockImageArray = Array();
g_qslLockImageArray[0] = "./img/qsl_unlocked_32.png";
g_qslLockImageArray[1] = "./img/qsl_locked_32.png";
var g_alertImageArray = Array();
g_alertImageArray[0] = "./img/unmuted-button.png";
g_alertImageArray[1] = "./img/muted-button.png";
var g_spotImageArray = Array();
g_spotImageArray[0] = "./img/spots.png";
g_spotImageArray[1] = "./img/spots.png";
g_spotImageArray[2] = "./img/heat.png";
var g_maidenheadModeImageArray = Array();
g_maidenheadModeImageArray[0] = "./img/mh4_32.png";
g_maidenheadModeImageArray[1] = "./img/mh6_32.png";
var g_gridViewArray = Array();
g_gridViewArray[1] = "Live";
g_gridViewArray[2] = "Logbook";
g_gridViewArray[3] = "Logbook &amp; Live";
var g_trophyImageArray = Array();
g_trophyImageArray[0] = "./img/blank_trophy.png";
g_trophyImageArray[1] = "./img/cq_trophy.png";
g_trophyImageArray[2] = "./img/itu_trophy.png";
g_trophyImageArray[3] = "./img/wac_trophy.png";
g_trophyImageArray[4] = "./img/was_trophy.png";
g_trophyImageArray[5] = "./img/dxcc_trophy.png";
g_trophyImageArray[6] = "./img/usc_trophy.png";
g_trophyImageArray[7] = "./img/us48_trophy.png";
var g_viewInfo = {};
g_viewInfo[0] = ["g_qsoGrids", "Grids", 0, 0, 0];
g_viewInfo[1] = ["g_cqZones", "CQ Zones", 0, 0, 40];
g_viewInfo[2] = ["g_ituZones", "ITU Zones", 0, 0, 90];
g_viewInfo[3] = ["g_wacZones", "Continents", 0, 0, 7];
g_viewInfo[4] = ["g_wasZones", "US States", 0, 0, 50];
g_viewInfo[5] = ["g_dxccInfo", "DXCCs", 0, 0, 340];
g_viewInfo[6] = ["g_countyData", "US Counties", 0, 0, 3220];
g_viewInfo[7] = ["g_us48Data", "US Continental Grids", 0, 0, 488];
var g_soundCard = g_appSettings.soundCard;
var g_gridAlpha = "88";
if (typeof g_mapMemory[6] == "undefined") g_mapMemory[6] = g_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}]`);
}
}
var unconfirmedCallsSentinel = new UnconfirmedCallsKey(0, "");
function qsoBackupFileInit()
{
var adifHeader = "GridTracker v" + gtVersion + " <EOH>\r\n";
if (!fs.existsSync(g_qsoLogFile))
{
fs.writeFileSync(g_qsoLogFile, adifHeader);
}
}
function gtBandFilterChanged(selector)
{
g_appSettings.gtBandFilter = selector.value;
removePaths();
redrawGrids();
redrawPins();
redrawSpots();
redrawParks();
}
function gtModeFilterChanged(selector)
{
g_appSettings.gtModeFilter = selector.value;
redrawGrids();
redrawPins();
redrawSpots();
redrawParks();
}
function gtPropFilterChanged(selector)
{
g_appSettings.gtPropFilter = selector.value;
redrawGrids();
redrawSpots();
}
function setBandAndModeToAuto()
{
g_appSettings.gtModeFilter = g_appSettings.gtBandFilter = gtBandFilter.value = gtModeFilter.value =
"auto";
redrawGrids();
redrawPins();
redrawSpots();
redrawParks();
}
function hideLiveGrid(i)
{
if (g_layerSources.live.hasFeature(g_liveGrids[i].rectangle))
{
g_layerSources.live.removeFeature(g_liveGrids[i].rectangle);
}
}
function liveTriangleGrid(i)
{
if (g_liveGrids[i].isTriangle == false)
{
if (g_layerSources.live.hasFeature(g_liveGrids[i].rectangle))
{
g_layerSources.live.removeFeature(g_liveGrids[i].rectangle);
}
gridToTriangle(i, g_liveGrids[i].rectangle, false);
g_liveGrids[i].isTriangle = true;
g_layerSources.live.addFeature(g_liveGrids[i].rectangle);
}
}
function qsoTriangleGrid(i)
{
if (g_qsoGrids[i].isTriangle == false)
{
if (g_layerSources.qso.hasFeature(g_qsoGrids[i].rectangle))
{
g_layerSources.qso.removeFeature(g_qsoGrids[i].rectangle);
}
gridToTriangle(i, g_qsoGrids[i].rectangle, true);
g_qsoGrids[i].isTriangle = true;
g_layerSources.qso.addFeature(g_qsoGrids[i].rectangle);
}
}
function setGridViewMode(mode)
{
g_appSettings.gridViewMode = Number(mode);
gridViewButton.innerHTML = g_gridViewArray[g_appSettings.gridViewMode];
redrawGrids();
goProcessRoster();
}
function cycleGridView()
{
var mode = g_appSettings.gridViewMode;
mode++;
if (mode > 3) mode = 1;
if (mode < 1) mode = 1;
g_appSettings.gridViewMode = mode;
gridViewButton.innerHTML = g_gridViewArray[g_appSettings.gridViewMode];
redrawGrids();
saveAppSettings();
}
function toggleEarth()
{
g_appSettings.earthImgSrc ^= 1;
earthImg.src = g_earthShadowImageArray[g_appSettings.earthImgSrc];
if (g_appSettings.earthImgSrc == 1)
{
dayNight.hide();
g_nightTime = dayNight.refresh();
}
else
{
g_nightTime = dayNight.refresh();
dayNight.show();
}
changeMapLayer();
}
function toggleOffline()
{
if (g_map == null) return;
if (g_mapSettings.offlineMode == true)
{
g_mapSettings.offlineMode = false;
offlineImg.src = g_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 = (g_appSettings.potaEnabled == 1 && g_appSettings.potaShowMenu) ? "inline-block" : "none";
if (g_appSettings.gtShareEnable == true)
{
gtFlagButton.style.display = "inline-block";
if (g_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 g_adifLogSettings.menu)
{
var value = g_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
{
g_mapSettings.offlineMode = true;
offlineImg.src = g_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()
{
g_ignoreMessages ^= 1;
if (g_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()
{
g_appSettings.useLocalTime ^= 1;
displayTime();
}
function dateToString(dateTime)
{
if (g_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 prefix;
}
function setState(details)
{
if (details.state != null && details.state.length > 0)
{
var isDigi = details.digital;
if (details.state.substr(0, 2) != "US") { details.state = "US-" + details.state; }
g_tracker.worked.state[details.state + details.band + details.mode] = true;
g_tracker.worked.state[details.state] = true;
g_tracker.worked.state[details.state + details.mode] = true;
g_tracker.worked.state[details.state + details.band] = true;
if (isDigi)
{
g_tracker.worked.state[details.state + "dg"] = true;
g_tracker.worked.state[details.state + details.band + "dg"] = true;
}
if (details.confirmed)
{
g_tracker.confirmed.state[
details.state + details.band + details.mode
] = true;
g_tracker.confirmed.state[details.state] = true;
g_tracker.confirmed.state[details.state + details.mode] = true;
g_tracker.confirmed.state[details.state + details.band] = true;
if (isDigi)
{
g_tracker.confirmed.state[details.state + "dg"] = true;
g_tracker.confirmed.state[details.state + details.band + "dg"] = true;
}
}
}
if (details.cnty != null && details.cnty.length > 0)
{
var isDigi = details.digital;
g_tracker.worked.cnty[details.cnty + details.band + details.mode] = true;
g_tracker.worked.cnty[details.cnty] = true;
g_tracker.worked.cnty[details.cnty + details.mode] = true;
g_tracker.worked.cnty[details.cnty + details.band] = true;
if (isDigi)
{
g_tracker.worked.cnty[details.cnty + "dg"] = true;
g_tracker.worked.cnty[details.cnty + details.band + "dg"] = true;
}
if (details.confirmed)
{
g_tracker.confirmed.cnty[
details.cnty + details.band + details.mode
] = true;
g_tracker.confirmed.cnty[details.cnty] = true;
g_tracker.confirmed.cnty[details.cnty + details.mode] = true;
g_tracker.confirmed.cnty[details.cnty + details.band] = true;
if (isDigi)
{
g_tracker.confirmed.cnty[details.cnty + "dg"] = true;
g_tracker.confirmed.cnty[details.cnty + details.band + "dg"] = true;
}
}
}
}
function isKnownCallsignDXCC(dxcc)
{
if (dxcc in g_callsignDatabaseDXCC) return true;
return false;
}
function isKnownCallsignUS(dxcc)
{
if (dxcc in g_callsignDatabaseUS) return true;
return false;
}
function isKnownCallsignUSplus(dxcc)
{
if (dxcc in g_callsignDatabaseUSplus) return true;
return false;
}
function addDeDx(
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 currentYear = new Date().getFullYear();
var qsoDate = new Date(1970, 0, 1); qsoDate.setSeconds(finalTime);
var isCurrentYear = (qsoDate.getFullYear() == currentYear);
var dayAsString = String(parseInt(finalTime / 86400));
var callsign = null;
var rect = null;
var worked = false;
var didConfirm = false;
var wspr = mode == "WSPR" ? parseInt(band) * 2 : null;
var hash = "";
var locked = false;
var finalMsg = ifinalMsg.trim();
if (finalMsg.length > 40) finalMsg = finalMsg.substring(0, 40) + "...";
var details = null;
if (isQSO)
{
var timeMod = finalTime - (finalTime % 360) + 180;
hash = unique(mode + band + finalDXcall + timeMod);
var lookupCall = false;
if (hash in g_QSOhash)
{
details = g_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;
}
}
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 (finalState != null) details.state = finalState;
if (finalState == null && details.state) finalState = details.state;
if (finalDxcc < 1 && details.dxcc > 0) finalDxcc = details.dxcc;
if (finalCont == null && details.cont) finalCont = details.cont;
if (finalCnty == null && details.cnty) finalCnty = details.cnty;
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;
}
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;
}
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);
if (
details.state == null &&
isKnownCallsignUSplus(finalDxcc) &&
fourGrid.length > 0
)
{
if (fourGrid in g_gridToState && g_gridToState[fourGrid].length == 1)
{
details.state = g_gridToState[fourGrid][0];
}
lookupCall = true;
}
details.cont = finalCont;
if (finalDxcc > 0)
{
details.cont = g_dxccInfo[finalDxcc].continent;
if (details.dxcc == 390 && details.zone == 1) details.cont = "EU";
}
details.cnty = finalCnty;
if (details.cnty)
{
details.qual = true;
}
if (isKnownCallsignUSplus(finalDxcc))
{
if (details.cnty == null)
{
lookupCall = true;
}
else
{
if (!(details.cnty in g_cntyToCounty))
{
lookupCall = true;
}
}
}
var isDigi = details.digital;
var isPhone = details.phone;
details.wspr = wspr;
if (finalMsg.length > 0) details.msg = finalMsg;
g_tracker.worked.call[finalDXcall + band + mode] = true;
g_tracker.worked.call[finalDXcall] = true;
g_tracker.worked.call[finalDXcall + mode] = true;
g_tracker.worked.call[finalDXcall + band] = true;
if (isDigi == true)
{
g_tracker.worked.call[finalDXcall + "dg"] = true;
g_tracker.worked.call[finalDXcall + band + "dg"] = true;
}
if (fourGrid != "")
{
g_tracker.worked.grid[fourGrid + band + mode] = true;
g_tracker.worked.grid[fourGrid] = true;
g_tracker.worked.grid[fourGrid + mode] = true;
g_tracker.worked.grid[fourGrid + band] = true;
if (isDigi == true)
{
g_tracker.worked.grid[fourGrid + "dg"] = true;
g_tracker.worked.grid[fourGrid + band + "dg"] = true;
}
}
if (!details.ituz || details.ituz.length == 0)
{
details.ituz = ituZoneFromCallsign(finalDXcall, details.dxcc);
}
if (details.ituz)
{
g_tracker.worked.ituz[details.ituz + "|" + band + mode] = true;
g_tracker.worked.ituz[details.ituz + "|"] = true;
g_tracker.worked.ituz[details.ituz + "|" + mode] = true;
g_tracker.worked.ituz[details.ituz + "|" + band] = true;
if (isDigi == true)
{
g_tracker.worked.ituz[details.ituz + "|dg"] = true;
g_tracker.worked.ituz[details.ituz + "|" + band + "dg"] = true;
}
}
if (!details.cqz || details.cqz.length == 0)
{
details.cqz = cqZoneFromCallsign(finalDXcall, details.dxcc);
}
if (details.cqz)
{
g_tracker.worked.cqz[details.cqz + "|" + band + mode] = true;
g_tracker.worked.cqz[details.cqz + "|"] = true;
g_tracker.worked.cqz[details.cqz + "|" + mode] = true;
g_tracker.worked.cqz[details.cqz + "|" + band] = true;
if (isDigi == true)
{
g_tracker.worked.cqz[details.cqz + "|dg"] = true;
g_tracker.worked.cqz[details.cqz + "|" + band + "dg"] = true;
}
if (isCurrentYear)
{
g_tracker.worked.cqz[`${details.cqz}-${currentYear}`] = true;
}
}
if (details.dxcc > 0)
{
var sDXCC = String(details.dxcc);
g_tracker.worked.dxcc[sDXCC + "|" + band + mode] = true;
g_tracker.worked.dxcc[sDXCC + "|"] = true;
g_tracker.worked.dxcc[sDXCC + "|" + mode] = true;
g_tracker.worked.dxcc[sDXCC + "|" + band] = true;
if (isDigi == true)
{
g_tracker.worked.dxcc[sDXCC + "|dg"] = true;
g_tracker.worked.dxcc[sDXCC + "|" + band + "dg"] = true;
}
if (isCurrentYear)
{
g_tracker.worked.dxcc[`${sDXCC}-${currentYear}`] = true;
}
}
if (details.px)
{
g_tracker.worked.px[details.px + band + mode] = true;
// store the last one
g_tracker.worked.px[details.px] = hash;
g_tracker.worked.px[details.px + mode] = true;
g_tracker.worked.px[details.px + band] = true;
if (isDigi == true)
{
g_tracker.worked.px[details.px + "dg"] = true;
g_tracker.worked.px[details.px + band + "dg"] = true;
}
if (isPhone == true)
{
g_tracker.worked.px[details.px + "ph"] = true;
g_tracker.worked.px[details.px + band + "ph"] = true;
}
}
if (details.cont)
{
g_tracker.worked.cont[details.cont + band + mode] = true;
// store the last one
g_tracker.worked.cont[details.cont] = hash;
g_tracker.worked.cont[details.cont + mode] = true;
g_tracker.worked.cont[details.cont + band] = true;
if (isDigi == true)
{
g_tracker.worked.cont[details.cont + "dg"] = true;
g_tracker.worked.cont[details.cont + band + "dg"] = true;
}
if (isPhone == true)
{
g_tracker.worked.cont[details.cont + "ph"] = true;
g_tracker.worked.cont[details.cont + band + "ph"] = true;
}
}
if (finalPOTA)
{
g_tracker.worked.pota[dayAsString + finalDXcall + finalPOTA] = true;
g_tracker.worked.pota[dayAsString + finalDXcall + finalPOTA + mode] = true;
g_tracker.worked.pota[dayAsString + finalDXcall + finalPOTA + band] = true;
g_tracker.worked.pota[dayAsString + finalDXcall + finalPOTA + band + mode] = true;
if (isDigi == true)
{
g_tracker.worked.pota[dayAsString + finalDXcall + finalPOTA + "dg"] = true;
g_tracker.worked.pota[dayAsString + finalDXcall + finalPOTA + band + "dg"] = true;
}
if (isPhone == true)
{
g_tracker.worked.pota[dayAsString + finalDXcall + finalPOTA + "ph"] = true;
g_tracker.worked.pota[dayAsString + finalDXcall + finalPOTA + band + "ph"] = true;
}
}
worked = true;
locked = true;
details.worked = worked;
if (typeof details.confirmed == "undefined" || details.confirmed == false)
{
details.confirmed = confirmed;
}
g_QSOhash[hash] = details;
setState(details);
if (lookupCall)
{
if (g_callsignLookups.ulsUseEnable)
{
lookupUsCallsign(details, true);
}
}
if (confirmed == true)
{
if (fourGrid != "")
{
g_tracker.confirmed.grid[fourGrid + band + mode] = true;
g_tracker.confirmed.grid[fourGrid] = true;
g_tracker.confirmed.grid[fourGrid + mode] = true;
g_tracker.confirmed.grid[fourGrid + band] = true;
if (isDigi == true)
{
g_tracker.confirmed.grid[fourGrid + "dg"] = true;
g_tracker.confirmed.grid[fourGrid + band + "dg"] = true;
}
}
if (details.ituz && details.ituz.length > 0)
{
g_tracker.confirmed.ituz[details.ituz + "|" + band + mode] = true;
g_tracker.confirmed.ituz[details.ituz + "|"] = true;
g_tracker.confirmed.ituz[details.ituz + "|" + mode] = true;
g_tracker.confirmed.ituz[details.ituz + "|" + band] = true;
if (isDigi == true)
{
g_tracker.confirmed.ituz[details.ituz + "|dg"] = true;
g_tracker.confirmed.ituz[details.ituz + "|" + band + "dg"] = true;
}
}
if (details.cqz && details.cqz.length > 0)
{
g_tracker.confirmed.cqz[details.cqz + "|" + band + mode] = true;
g_tracker.confirmed.cqz[details.cqz + "|"] = true;
g_tracker.confirmed.cqz[details.cqz + "|" + mode] = true;
g_tracker.confirmed.cqz[details.cqz + "|" + band] = true;
if (isDigi == true)
{
g_tracker.confirmed.cqz[details.cqz + "|dg"] = true;
g_tracker.confirmed.cqz[details.cqz + "|" + band + "dg"] = true;
}
}
if (details.dxcc > 0)
{
var sDXCC = String(details.dxcc);
g_tracker.confirmed.dxcc[sDXCC + "|" + band + mode] = true;
g_tracker.confirmed.dxcc[sDXCC + "|"] = true;
g_tracker.confirmed.dxcc[sDXCC + "|" + mode] = true;
g_tracker.confirmed.dxcc[sDXCC + "|" + band] = true;
if (isDigi == true)
{
g_tracker.confirmed.dxcc[sDXCC + "|dg"] = true;
g_tracker.confirmed.dxcc[sDXCC + "|" + band + "dg"] = true;
}
}
if (details.px)
{
g_tracker.confirmed.px[details.px + band + mode] = true;
// store the last one
g_tracker.confirmed.px[details.px] = hash;
g_tracker.confirmed.px[details.px + mode] = true;
g_tracker.confirmed.px[details.px + band] = true;
if (isDigi == true)
{
g_tracker.confirmed.px[details.px + "dg"] = true;
g_tracker.confirmed.px[details.px + band + "dg"] = true;
}
}
if (details.cont)
{
g_tracker.confirmed.cont[details.cont + band + mode] = true;
// store the last one
g_tracker.confirmed.cont[details.cont] = hash;
g_tracker.confirmed.cont[details.cont + mode] = true;
g_tracker.confirmed.cont[details.cont + band] = true;
if (isDigi == true)
{
g_tracker.confirmed.cont[details.cont + "dg"] = true;
g_tracker.confirmed.cont[details.cont + band + "dg"] = true;
}
}
// we don't need confirmations, worked is enough
/* if (finalPOTA)
{
g_tracker.confirmed.pota[dayAsString + finalDXcall + finalPOTA] = true;
g_tracker.confirmed.pota[dayAsString + finalDXcall + finalPOTA + mode] = true;
g_tracker.confirmed.pota[dayAsString + finalDXcall + finalPOTA + band] = true;
g_tracker.confirmed.pota[dayAsString + finalDXcall + finalPOTA + band + mode] = true;
if (isDigi == true)
{
g_tracker.confirmed.pota[dayAsString + finalDXcall + finalPOTA + "dg"] = true;
g_tracker.confirmed.pota[dayAsString + finalDXcall + finalPOTA + band + "dg"] = true;
}
} */
g_tracker.confirmed.call[finalDXcall + band + mode] = true;
g_tracker.confirmed.call[finalDXcall] = true;
g_tracker.confirmed.call[finalDXcall + mode] = true;
g_tracker.confirmed.call[finalDXcall + band] = true;
if (isDigi == true)
{
g_tracker.confirmed.call[finalDXcall + "dg"] = true;
g_tracker.confirmed.call[finalDXcall + band + "dg"] = true;
}
didConfirm = true;
}
}
if (finalDxcc < 1) finalDxcc = callsignToDxcc(finalDXcall);
hash = finalDXcall + band + mode;
if (!isQSO)
{
if (hash in g_liveCallsigns) callsign = g_liveCallsigns[hash];
}
if (isQSO)
{
if (validateMapBandAndMode(band, mode) && validatePropMode(finalPropMode))
{
details.rect = qthToQsoBox(
finalGrid,
hash,
locked,
finalDEcall,
worked,
didConfirm,
band,
wspr
);
}
return;
}
else
{
if (finalDxcc in g_dxccCount) g_dxccCount[finalDxcc]++;
else g_dxccCount[finalDxcc] = 1;
if (validateMapBandAndMode(band, mode))
{
rect = qthToBox(
finalGrid,
finalDXcall,
false,
locked,
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 = g_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 (g_callsignLookups.ulsUseEnable)
{
lookupUsCallsign(newCallsign);
}
if (newCallsign.state == null && isKnownCallsignUSplus(finalDxcc))
{
var fourGrid = finalGrid.substr(0, 4);
if (
fourGrid in g_gridToState &&
g_gridToState[finalGrid.substr(0, 4)].length == 1
)
{
newCallsign.state = g_gridToState[finalGrid.substr(0, 4)][0];
}
}
}
g_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()
{
g_appSettings.wsjtUdpPort = udpPortInput.value;
lastMsgTimeDiv.innerHTML = "Waiting for msg...";
g_setNewUdpPortTimeoutHandle = null;
}
function setUdpPort()
{
if (g_setNewUdpPortTimeoutHandle != null) { nodeTimers.clearTimeout(g_setNewUdpPortTimeoutHandle); }
lastMsgTimeDiv.innerHTML = "..setting..";
g_setNewUdpPortTimeoutHandle = nodeTimers.setTimeout(timeoutSetUdpPort, 1000);
}
function changeGridDecay()
{
g_appSettings.gridsquareDecayTime = parseInt(gridDecay.value);
decayRateTd.innerHTML =
Number(g_appSettings.gridsquareDecayTime) == 0
? "<I>No Decay</I>"
: Number(g_appSettings.gridsquareDecayTime).toDHMS();
}
function changeMouseOverValue()
{
g_mapSettings.mouseOver = mouseOverValue.checked;
saveMapSettings();
}
function changeMergeOverlayValue()
{
g_mapSettings.mergeOverlay = mergeOverlayValue.checked;
saveMapSettings();
setTrophyOverlay(g_currentOverlay);
}
function getPathColor()
{
if (g_mapSettings.nightMapEnable && g_nightTime)
{
if (g_mapSettings.nightPathColor == 0) return "#000";
if (g_mapSettings.nightPathColor == 361) return "#FFF";
return "hsl(" + g_mapSettings.nightPathColor + ", 100%, 50%)";
}
else
{
if (g_mapSettings.pathColor == 0) return "#000";
if (g_mapSettings.pathColor == 361) return "#FFF";
return "hsl(" + g_mapSettings.pathColor + ", 100%, 50%)";
}
}
function getQrzPathColor()
{
if (g_mapSettings.nightMapEnable && g_nightTime)
{
if (g_mapSettings.nightQrzPathColor == 0) return "#000";
if (g_mapSettings.nightQrzPathColor == 361) return "#FFF";
return "hsl(" + g_mapSettings.nightQrzPathColor + ", 100%, 50%)";
}
else
{
if (g_mapSettings.qrzPathColor == 0) return "#000";
if (g_mapSettings.qrzPathColor == 361) return "#FFF";
return "hsl(" + g_mapSettings.qrzPathColor + ", 100%, 50%)";
}
}
function changeShadow()
{
g_mapSettings.shadow = shadowValue.value;
showDarknessTd.innerHTML = parseInt(shadowValue.value * 100) + "%";
saveMapSettings();
g_nightTime = dayNight.refresh();
}
function changePathWidth()
{
g_appSettings.pathWidthWeight = pathWidthValue.value;
g_appSettings.qrzPathWidthWeight = qrzPathWidthValue.value;
pathWidthTd.innerHTML = pathWidthValue.value;
qrzPathWidthTd.innerHTML = qrzPathWidthValue.value;
for (var i = g_flightPaths.length - 1; i >= 0; i--)
{
var featureStyle = g_flightPaths[i].getStyle();
var featureStroke = featureStyle.getStroke();
var color = g_flightPaths[i].isQRZ ? getQrzPathColor() : getPathColor();
var width = g_flightPaths[i].isQRZ
? qrzPathWidthValue.value
: pathWidthValue.value;
if (width == 0)
{
if ("Arrow" in g_flightPaths[i]) { g_layerSources.flight.removeFeature(g_flightPaths[i].Arrow); }
g_layerSources.flight.removeFeature(g_flightPaths[i]);
delete g_flightPaths[i];
g_flightPaths[i] = null;
g_flightPaths.splice(i, 1);
continue;
}
featureStroke.setWidth(width);
if (g_flightPaths[i].isShapeFlight == 0) featureStroke.setColor(color);
featureStyle.setStroke(featureStroke);
g_flightPaths[i].setStyle(featureStyle);
if ("Arrow" in g_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
})
});
g_flightPaths[i].Arrow.setStyle(thisStle);
}
}
if (g_transmitFlightPath != null)
{
var featureStyle = g_transmitFlightPath.getStyle();
var featureStroke = featureStyle.getStroke();
if (qrzPathWidthValue.value == 0)
{
g_layerSources.transmit.clear();
g_transmitFlightPath = null;
}
else
{
featureStroke.setWidth(qrzPathWidthValue.value);
featureStroke.setColor(getQrzPathColor());
featureStyle.setStroke(featureStroke);
g_transmitFlightPath.setStyle(featureStyle);
if ("Arrow" in g_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
})
});
g_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 createFlagTipTable(toolElement)
{
var worker = "";
if (toolElement.size == 1)
{
var key = toolElement.key;
var dxcc = callsignToDxcc(g_gtFlagPins[key].call);
var dxccName = g_dxccToAltName[dxcc];
var workColor = "cyan";
if (g_gtFlagPins[key].call + myBand + myMode in g_tracker.worked.call)
{
workColor = "yellow";
}
if (g_gtFlagPins[key].call + myBand + myMode in g_tracker.confirmed.call)
{
workColor = "#00FF00";
}
worker += "<div style='background-color:" + workColor + ";color:#000;font-weight:bold;font-size:18px;border:2px solid gray;margin:0px' class='roundBorder'>" + g_gtFlagPins[key].call.formatCallsign() + "</div>";
worker += "<table id='tooltipTable' class='darkTable' >";
worker += "<tr><td>DXCC</td><td style='color:orange;'>" + dxccName + " <font color='lightgreen'>(" + g_dxccInfo[dxcc].pp + ")</font></td>";
worker += "<tr><td>Grid</td><td style='color:cyan;' >" + g_gtFlagPins[key].grid + "</td></tr>";
worker += "<tr><td>Freq</td><td style='color:lightgreen' >" + Number(g_gtFlagPins[key].freq / 1000).formatMhz(3, 3) + " <font color='yellow'>(" + Number(g_gtFlagPins[key].freq / 1000000).formatBand() + ")</font></td></tr>";
worker += "<tr><td>Mode</td><td style='color:orange' >" + g_gtFlagPins[key].mode + "</td></tr>";
var LL = squareToCenter(g_gtFlagPins[key].grid);
var bearing = parseInt(MyCircle.bearing(g_myLat, g_myLon, LL.a, LL.o));
worker += "<tr><td>Dist</td><td style='color:cyan'>" + parseInt(MyCircle.distance(g_myLat, g_myLon, LL.a, LL.o, distanceUnit.value) * MyCircle.validateRadius(distanceUnit.value)) + distanceUnit.value.toLowerCase() + "</td></tr>";
worker += "<tr><td>Azim</td><td style='color:yellow'>" + bearing + "&deg;</td></tr>";
worker += "</table>";
}
else if (toolElement.size == 73)
{
var props = toolElement.getProperties();
moment.locale(navigator.languages[0]);
var m = moment().tz(props.tzid);
worker +=
"<div style='background-color:cyan;color:#000;font-weight:bold;font-size:16px;border:2px solid gray;margin:0px;padding:1px' class='roundBorder'>" +
props.tzid +
"</div>";
worker += "<table id='tooltipTable' class='darkTable' align=center>";
var abbr = m.format("zz");
var zone = m.format("Z");
if (zone.indexOf(abbr) > -1) abbr = "";
else abbr = " <font color='orange'>(" + abbr + ")</font>";
worker +=
"<tr><td style='color:yellow;font-weight:bold'>" +
m.format("LLLL") +
"</td></tr>";
worker +=
"<tr><td style='color:#00FF00;font-weight:bold'>" +
zone +
abbr +
"</td></tr>";
worker += "</table>";
}
myFlagtip.innerHTML = worker;
return 1;
}
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 myTooltip = document.getElementById("myTooltip");
var worker = "";
if (toolElement.spot in g_receptionReports.spots)
{
g_layerSources["psk-hop"].clear();
var report = g_receptionReports.spots[toolElement.spot];
var LL = squareToCenter(myRawGrid);
var fromPoint = ol.proj.fromLonLat([LL.o, LL.a]);
worker = "<table id='tooltipTable' class='darkTable' ><tr><th colspan=2 style='color:cyan'>Rx Spot</th></tr>";
worker += "<tr><td>Age</td><td>" + Number(now - report.when).toDHMS() + "</td></tr>";
worker += "<tr><td>dB</td><td style='color:#DD44DD' >" + Number(report.snr).formatSignalReport() + "</td></tr>";
worker += "<tr><td>Call</td><td style='color:#ff0' >" + report.call.formatCallsign() + "</td></tr>";
if (report.dxcc > 0)
{
worker += "<tr><td>DXCC</td><td style='color:orange;'>" + g_dxccToAltName[report.dxcc] + " <font color='lightgreen'>(" + g_dxccInfo[report.dxcc].pp + ")</font></td>";
}
worker += "<tr><td>Grid</td><td style='color:cyan;cursor:pointer' >" + report.grid + "</td></tr>";
worker += "<tr><td>Freq</td><td style='color:lightgreen' >" + report.freq.formatMhz() + " <font color='yellow'>(" + report.band + ")</font></td></tr>";
worker += "<tr><td>Mode</td><td style='color:orange' >" + report.mode + "</td></tr>";
LL = squareToCenter(report.grid);
report.bearing = parseInt(MyCircle.bearing(g_myLat, g_myLon, LL.a, LL.o));
worker += "<tr><td>Dist</td><td style='color:cyan'>" + parseInt(MyCircle.distance(g_myLat, g_myLon, LL.a, LL.o, distanceUnit.value) * MyCircle.validateRadius(distanceUnit.value)) + distanceUnit.value.toLowerCase() + "</td></tr>";
worker += "<tr><td>Azim</td><td style='color:yellow'>" + report.bearing + "&deg;</td></tr>";
worker += "<tr><td>Time</td><td>" + userTimeString(report.when * 1000) + "</td></tr>";
worker += "</table>";
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;
g_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 myTooltip = document.getElementById("myTooltip");
var colspan = 10;
if (g_callsignLookups.lotwUseEnable == true) colspan++;
if (g_callsignLookups.eqslUseEnable == true) colspan++;
if (g_callsignLookups.oqrsUseEnable == true) colspan++;
if (toolElement.qso == true) colspan += 2;
var worker =
"<table id='tooltipTable' class='darkTable' ><tr><th colspan=" +
colspan +
" style='color:cyan'>" +
toolElement.qth +
"</th></tr>";
if (toolElement.qth in g_gridToDXCC)
{
worker += "<tr><th colspan=" + colspan + " style='color:yellow'><small>";
for (var x = 0; x < g_gridToDXCC[toolElement.qth].length; x++)
{
worker += g_dxccToAltName[g_gridToDXCC[toolElement.qth][x]];
if (toolElement.qth in g_gridToState)
{
worker += " (<font color='orange'>";
var added = false;
for (var y = 0; y < g_gridToState[toolElement.qth].length; y++)
{
if (
g_gridToDXCC[toolElement.qth][x] ==
g_StateData[g_gridToState[toolElement.qth][y]].dxcc
)
{
worker +=
g_StateData[g_gridToState[toolElement.qth][y]].name + " / ";
added = true;
}
}
if (added == true) { worker = worker.substr(0, worker.length - " / ".length); }
worker += "</font>)";
}
if (x + 1 < g_gridToDXCC[toolElement.qth].length) worker += ", ";
}
worker += "</small></th></tr>";
}
var newCallList = Array();
if (toolElement.qso == true)
{
if (Object.keys(toolElement.hashes).length > 0)
{
worker +=
"<tr align='center'><td>Call</td><td>Freq</td><td>Sent</td><td>Rcvd</td><td>Station</td><td>Mode</td><td>Band</td><td>QSL</td><td>Last Msg</td><td>DXCC</td><td>Time</td>";
if (g_callsignLookups.lotwUseEnable == true) worker += "<td>LoTW</td>";
if (g_callsignLookups.eqslUseEnable == true) worker += "<td>eQSL</td>";
if (g_callsignLookups.oqrsUseEnable == true) worker += "<td>OQRS</td>";
worker += "</tr>";
}
for (var KeyIsHash in toolElement.hashes)
{
if (KeyIsHash in g_QSOhash)
{
newCallList.push(g_QSOhash[KeyIsHash]);
}
}
if (
toolElement.qth in g_liveGrids &&
g_liveGrids[toolElement.qth].rectangle != null &&
g_liveGrids[toolElement.qth].isTriangle == false
)
{
for (var KeyIsCall in g_liveGrids[toolElement.qth].rectangle.liveHash)
{
if (KeyIsCall in g_liveCallsigns && g_appSettings.gridViewMode == 3) { newCallList.push(g_liveCallsigns[KeyIsCall]); }
}
}
}
else
{
if (toolElement.liveHash != null && Object.keys(toolElement.liveHash).length > 0)
{
worker +=
"<tr align='center'><td>Call</td><td>Freq</td><td>Sent</td><td>Rcvd</td><td>Station</td><td>Mode</td><td>Band</td><td>Last Msg</td><td>DXCC</td><td>Time</td>";
if (g_callsignLookups.lotwUseEnable == true) worker += "<td>LoTW</td>";
if (g_callsignLookups.eqslUseEnable == true) worker += "<td>eQSL</td>";
if (g_callsignLookups.oqrsUseEnable == true) worker += "<td>OQRS</td>";
worker += "</tr>";
}
for (var KeyIsCall in toolElement.liveHash)
{
if (KeyIsCall in g_liveCallsigns) { newCallList.push(g_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 == myDEcall) { bgDX = " style='background-color:cyan;color:#000;font-weight:bold' "; }
if (callsign.DEcall == myDEcall) { 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 = (timeNowSec() - callsign.time).toDHMS(); }
else
{
ageString = userTimeString(callsign.time * 1000);
}
worker += "<tr><td" + bgDE + ">";
worker +=
"<div style='display:inline-table;cursor:pointer' onclick='startLookup(\"" +
callsign.DEcall +
"\",\"" +
toolElement.qth +
"\");' >" +
callsign.DEcall.formatCallsign() +
"</div>";
worker += "</td>";
worker += "<td>" + (callsign.delta > -1 ? callsign.delta : "-") + "</td>";
worker += "<td>" + callsign.RSTsent + "</td>";
worker += "<td>" + callsign.RSTrecv + "</td>" + "<td" + bgDX + ">";
if (callsign.DXcall.indexOf("CQ") == 0 || callsign.DXcall == "-") { worker += callsign.DXcall.formatCallsign(); }
else
{
worker +=
"<div style='display:inline-table;cursor:pointer' onclick='startLookup(\"" +
callsign.DXcall +
"\",null);' >" +
callsign.DXcall.formatCallsign() +
"</div>";
}
worker +=
"</td>" +
"<td style='color:lightblue'>" +
callsign.mode +
"</td>" +
"<td style='color:lightgreen'>" +
callsign.band +
"</td>";
if (toolElement.qso == true)
{
worker +=
"<td align='center'>" +
(callsign.confirmed ? "&#10004;" : "") +
"</td>";
}
worker +=
"<td>" +
callsign.msg +
"</td><td style='color:yellow'>" +
g_dxccToAltName[callsign.dxcc] +
" <font color='lightgreen'>(" +
g_dxccInfo[callsign.dxcc].pp +
")</font></td>" +
"<td align='center' style='color:lightblue' >" +
ageString +
"</td>";
if (g_callsignLookups.lotwUseEnable == true)
{
worker +=
"<td align='center'>" +
(callsign.DEcall in g_lotwCallsigns ? "&#10004;" : "") +
"</td>";
}
if (g_callsignLookups.eqslUseEnable == true)
{
worker +=
"<td align='center'>" +
(callsign.DEcall in g_eqslCallsigns ? "&#10004;" : "") +
"</td>";
}
if (g_callsignLookups.oqrsUseEnable == true)
{
worker +=
"<td align='center'>" +
(callsign.DEcall in g_oqrsCallsigns ? "&#10004;" : "") +
"</td>";
}
worker += "</tr>";
}
worker += "</table>";
myTooltip.innerHTML = worker;
g_passingToolTipTableString = worker;
return newCallList.length;
}
// creates table for filling the pop-up winodw with log entries of unconfirmed qsos.
function createTooltTipTableLogbook(toolElement)
{
var myTooltip = document.getElementById("myTooltip");
var colspan = 10;
if (g_callsignLookups.lotwUseEnable == true) colspan++;
if (g_callsignLookups.eqslUseEnable == true) colspan++;
if (g_callsignLookups.oqrsUseEnable == true) colspan++;
if (toolElement.qso == true) colspan += 2;
var worker =
"<table id='tooltipTable' class='darkTable' ><tr><th colspan=" +
colspan +
" style='color:cyan'>" +
"Logbook entries" +
"</th></tr>";
worker +=
"<tr align='center'><td>Call</td><td>Freq</td><td>Sent</td><td>Rcvd</td><td>Station</td><td>Mode</td><td>Band</td><td>DXCC</td><td>Time</td>";
if (g_callsignLookups.lotwUseEnable == true) worker += "<td>LoTW</td>";
if (g_callsignLookups.eqslUseEnable == true) worker += "<td>eQSL</td>";
if (g_callsignLookups.oqrsUseEnable == true) worker += "<td>OQRS</td>";
worker += "</tr>";
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 == myDEcall) { bgDX = " style='background-color:cyan;color:#000;font-weight:bold' "; }
if (callsign.DEcall == myDEcall) { bgDE = " style='background-color:#FFFF00;color:#000;font-weight:bold' "; }
var ageString = "";
if (timeNowSec() - callsign.time < 3601) { ageString = (timeNowSec() - callsign.time).toDHMS(); }
else
{
ageString = userTimeString(callsign.time * 1000);
}
worker += "<tr><td" + bgDE + ">";
worker +=
"<div style='display:inline-table;cursor:pointer' onclick='startLookup(\"" +
callsign.DEcall +
"\",\"" +
toolElement.qth +
"\");' >" +
callsign.DEcall.formatCallsign() +
"</div>";
worker += "</td>";
worker += "<td>" + (callsign.delta > -1 ? callsign.delta : "-") + "</td>";
worker += "<td>" + callsign.RSTsent + "</td>";
worker += "<td>" + callsign.RSTrecv + "</td>" + "<td" + bgDX + ">";
if (callsign.DXcall.indexOf("CQ") == 0 || callsign.DXcall == "-") { worker += callsign.DXcall.formatCallsign(); }
else
{
worker +=
"<div style='display:inline-table;cursor:pointer' onclick='startLookup(\"" +
callsign.DXcall +
"\",null);' >" +
callsign.DXcall.formatCallsign() +
"</div>";
}
worker +=
"</td>" +
"<td style='color:lightblue'>" +
callsign.mode +
"</td>" +
"<td style='color:lightgreen'>" +
callsign.band +
"</td>";
worker +=
"<td style='color:yellow'>" +
g_dxccToAltName[callsign.dxcc] +
" <font color='lightgreen'>(" +
g_dxccInfo[callsign.dxcc].pp +
")</font></td>" +
"<td align='center' style='color:lightblue' >" +
ageString +
"</td>";
if (g_callsignLookups.lotwUseEnable == true)
{
worker +=
"<td align='center'>" +
(callsign.DEcall in g_lotwCallsigns ? "&#10004;" : "") +
"</td>";
}
if (g_callsignLookups.eqslUseEnable == true)
{
worker +=
"<td align='center'>" +
(callsign.DEcall in g_eqslCallsigns ? "&#10004;" : "") +
"</td>";
}
if (g_callsignLookups.oqrsUseEnable == true)
{
if (callsign.DEcall in g_oqrsCallsigns)
{
worker +=
"<td align='center' " +
"onClick='window.opener.openSite(\"https://clublog.org/logsearch/logsearch.php?log=" +
callsign.DEcall + "&call=" + callsign.DXcall + "&SubmitLogSearch=Show+contacts\");'>" +
"&#10004;&#128236;</td>";
}
else
{
worker +=
"<td align='center'></td>";
}
}
worker += "</tr>";
}
worker += "</table>";
myTooltip.innerHTML = worker;
g_passingToolTipTableString = worker;
return newCallList.length;
}
function renderTooltipWindow(feature)
{
if (g_popupWindowHandle != null)
{
try
{
createTooltTipTable(feature);
var adif = g_popupWindowHandle.window.document.getElementById(
"adifTable"
);
adif.innerHTML = g_passingToolTipTableString;
var myTooltip = document.getElementById("myTooltip");
var positionInfo = myTooltip.getBoundingClientRect();
g_popupWindowHandle.show();
g_popupWindowHandle.focus();
g_popupWindowHandle.width = parseInt(positionInfo.width) + 20;
g_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 (g_popupWindowHandle != null)
{
try
{
createTooltTipTableLogbook(logbookEntries);
var adif = g_popupWindowHandle.window.document.getElementById(
"adifTable"
);
adif.innerHTML = g_passingToolTipTableString;
var myTooltip = document.getElementById("myTooltip");
var positionInfo = myTooltip.getBoundingClientRect();
g_popupWindowHandle.show();
g_popupWindowHandle.focus();
g_popupWindowHandle.width = parseInt(positionInfo.width) + 20;
g_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(g_gtFlagPins[feature.key].call, g_gtFlagPins[feature.key].grid);
}
return false;
}
function openConditionsWindow()
{
if (g_conditionsWindowHandle == null)
{
popupNewWindows();
var gui = require("nw.gui");
gui.Window.open(
"gt_conditions.html",
{
show: false,
id: "GT-Conditions"
},
function (new_win)
{
g_conditionsWindowHandle = new_win;
new_win.on("loaded", function ()
{
g_conditionsWindowHandle.setMinimumSize(490, 290);
});
new_win.on("close", function ()
{
g_conditionsWindowHandle.window.g_isShowing = false;
g_conditionsWindowHandle.window.saveScreenSettings();
g_conditionsWindowHandle.hide();
});
}
);
lockNewWindows();
}
else
{
try
{
if (g_conditionsWindowHandle.window.g_isShowing == false)
{
g_conditionsWindowHandle.window.g_isShowing = true;
g_conditionsWindowHandle.window.saveScreenSettings();
g_conditionsWindowHandle.show();
g_conditionsWindowHandle.focus();
}
else
{
g_conditionsWindowHandle.window.g_isShowing = false;
g_conditionsWindowHandle.window.saveScreenSettings();
g_conditionsWindowHandle.hide();
}
}
catch (e)
{
console.error(e);
}
}
}
var g_rosterInitialized = false;
var g_callRoster = {};
var g_rosterUpdateTimer = null;
function insertMessageInRoster(newMessage, msgDEcallsign, msgDXcallsign, callObj, hash)
{
if (g_rosterUpdateTimer != null)
{
nodeTimers.clearTimeout(g_rosterUpdateTimer);
g_rosterUpdateTimer = null;
}
var now = timeNowSec();
if (!(hash in g_callRoster))
{
g_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;
}
g_callRoster[hash].message = newMessage;
g_callRoster[hash].callObj = callObj;
g_callRoster[hash].DXcall = msgDXcallsign;
g_callRoster[hash].DEcall = msgDEcallsign;
g_rosterUpdateTimer = nodeTimers.setTimeout(delayedRosterUpdate, 150);
}
function delayedRosterUpdate()
{
g_rosterUpdateTimer = null;
goProcessRoster();
}
function openCallRosterWindow(show = true)
{
if (g_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)
{
g_callRosterWindowHandle = new_win;
new_win.on("loaded", function ()
{
g_callRosterWindowHandle.setMinimumSize(390, 250);
g_callRosterWindowHandle.setResizable(true);
});
new_win.on("close", function ()
{
g_callRosterWindowHandle.window.g_isShowing = false;
g_callRosterWindowHandle.window.saveScreenSettings();
g_callRosterWindowHandle.hide();
});
}
);
lockNewWindows();
}
else
{
try
{
if (g_rosterInitialized)
{
if (g_callRosterWindowHandle.window.g_isShowing == false)
{
g_callRosterWindowHandle.show();
g_callRosterWindowHandle.window.g_isShowing = true;
g_callRosterWindowHandle.window.saveScreenSettings();
g_callRosterWindowHandle.focus();
goProcessRoster();
}
else
{
g_callRosterWindowHandle.window.g_isShowing = false;
g_callRosterWindowHandle.window.saveScreenSettings();
g_callRosterWindowHandle.hide();
}
}
}
catch (e)
{
console.error(e);
}
}
}
function updateRosterWorked()
{
if (g_rosterInitialized)
{
try
{
g_callRosterWindowHandle.window.updateWorked();
}
catch (e)
{
console.error(e);
}
}
}
function updateRosterInstances()
{
if (g_rosterInitialized)
{
try
{
g_callRosterWindowHandle.window.updateInstances();
}
catch (e)
{
console.error(e);
}
}
}
function updateLogbook()
{
showWorkedBox(0, 0, true);
}
function openStatsWindow(show = true)
{
if (g_statsWindowHandle == null)
{
popupNewWindows();
var gui = require("nw.gui");
gui.Window.open(
"gt_stats.html",
{
show: false,
id: "GT-stats"
},
function (new_win)
{
g_statsWindowHandle = new_win;
new_win.on("loaded", function ()
{
g_statsWindowHandle.setMinimumSize(620, 200);
g_statsWindowHandle.setResizable(true);
});
new_win.on("close", function ()
{
g_statsWindowHandle.window.g_isShowing = false;
g_statsWindowHandle.window.saveScreenSettings();
g_statsWindowHandle.hide();
});
}
);
lockNewWindows();
}
else
{
try
{
if (g_statsWindowHandle.window.g_isShowing == false)
{
g_statsWindowHandle.show();
g_statsWindowHandle.window.g_isShowing = true;
g_statsWindowHandle.window.saveScreenSettings();
g_statsWindowHandle.focus();
}
else
{
g_statsWindowHandle.window.g_isShowing = false;
g_statsWindowHandle.window.saveScreenSettings();
g_statsWindowHandle.hide();
}
}
catch (e)
{
console.error(e);
}
}
}
function showMessaging(show = true, cid)
{
if (g_chatWindowHandle == null)
{
popupNewWindows();
var gui = require("nw.gui");
gui.Window.open(
"gt_chat.html",
{
show: false,
id: "GT-chat"
},
function (new_win)
{
g_chatWindowHandle = new_win;
g_chatWindowHandle.on("loaded", function ()
{
g_chatWindowHandle.setMinimumSize(450, 140);
g_chatWindowHandle.setResizable(true);
});
g_chatWindowHandle.on("close", function ()
{
g_chatWindowHandle.window.closeMessageArea();
g_chatWindowHandle.window.g_isShowing = false;
g_chatWindowHandle.window.saveScreenSettings();
g_chatWindowHandle.hide();
});
}
);
lockNewWindows();
}
else
{
try
{
g_chatWindowHandle.window.g_isShowing = true;
g_chatWindowHandle.window.saveScreenSettings();
g_chatWindowHandle.show();
g_chatWindowHandle.focus();
if (typeof cid != "undefined") g_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)
)
{
var myTooltip = document.getElementById("myTooltip");
createTooltTipTable(feature);
selectElementContents(myTooltip);
}
else if (e.button == 0 && g_mapSettings.mouseOver == false)
{
mouseOverDataItem(feature, false);
}
else if ((e.which && e.which == 3) || (e.button && e.button == 2))
{
if (g_popupWindowHandle == null)
{
popupNewWindows();
var gui = require("nw.gui");
gui.Window.open(
"gt_popup.html",
{
show: false,
id: "GT-popup"
},
function (new_win)
{
g_popupWindowHandle = new_win;
new_win.on("loaded", function ()
{
g_popupWindowHandle.show();
renderTooltipWindow(feature);
});
new_win.on("close", function ()
{
g_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 (typeof feature.spot != "undefined")
{
spotLookupAndSetCall(feature.spot);
}
}
return false;
}
function onMouseUpdate(e)
{
g_mouseX = e.pageX;
g_mouseY = e.pageY;
mouseMoveGrid();
}
function getMouseX()
{
return g_mouseX;
}
function getMouseY()
{
return g_mouseY;
}
var g_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 (g_layerSources.temp.hasFeature(oldGrid)) { g_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;
g_layerSources.temp.addFeature(newGridBox);
return newGridBox;
}
var g_tempGrids = Array();
function onMyKeyDown(event)
{
if (g_MyGridIsUp == true && g_MyCurrentGrid.length == 4)
{
var processedAlert = false;
var mediaClip = "";
var failedToAdd = g_dirSeperator + "Balloon-deflating-1.mp3";
if (event.code == "KeyM")
{
mediaClip = g_dirSeperator + "Clicky-1.mp3";
var valid = addAlert(g_MyCurrentGrid, 2, 3, 2, "", "");
if (!valid)
{
mediaClip = failedToAdd;
}
processedAlert = true;
}
else if (event.code == "KeyT")
{
mediaClip = g_dirSeperator + "Ping-coin.mp3";
var valid = addAlert(g_MyCurrentGrid, 2, 1, 2, "", "");
if (!valid)
{
mediaClip = failedToAdd;
}
processedAlert = true;
}
else if (event.code == "KeyV")
{
mediaClip = g_dirSeperator + "Slide-ping.mp3";
var valid = addAlert(g_MyCurrentGrid, 2, 2, 2, "", "");
if (!valid)
{
mediaClip = failedToAdd;
}
processedAlert = true;
}
if (processedAlert == true)
{
playAlertMediaFile(mediaClip);
}
return;
}
if (event.keyCode == 27)
{
alertsPopDiv.style.display = "none";
rootSettingsDiv.style.display = "none";
helpDiv.style.display = "none";
g_helpShow = false;
}
if (
alertsPopDiv.style.display == "none" &&
rootSettingsDiv.style.display == "none"
)
{
if (event.code in g_hotKeys)
{
if (typeof g_hotKeys[event.code].param1 != "undefined")
{
var param2 = null;
if (typeof g_hotKeys[event.code].param2 != "undefined")
{
if (typeof event[g_hotKeys[event.code].param2] != "undefined") { param2 = event[g_hotKeys[event.code].param2]; }
}
g_hotKeys[event.code].func(g_hotKeys[event.code].param1, param2);
}
else
{
if (event.ctrlKey == false) g_hotKeys[event.code].func();
}
}
else if (event.key in g_hotKeys)
{
if (typeof g_hotKeys[event.key].param1 != "undefined")
{
var param2 = null;
if (typeof g_hotKeys[event.key].param2 != "undefined")
{
if (typeof event[g_hotKeys[event.key].param2] != "undefined") { param2 = event[g_hotKeys[event.key].param2]; }
}
g_hotKeys[event.key].func(g_hotKeys[event.key].param1, param2);
}
else
{
if (event.ctrlKey == false) g_hotKeys[event.key].func();
}
}
}
}
function clearTempGrids()
{
g_layerSources.temp.clear();
g_tempGrids = Array();
}
var g_currentShapes = {};
function clearCurrentShapes()
{
g_layerSources.award.clear();
g_currentShapes = {};
}
function mapMemory(x, save, exit = false)
{
if (save == true)
{
g_mapMemory[x].LoLa = g_mapView.getCenter();
g_mapMemory[x].zoom = g_mapView.getZoom();
localStorage.mapMemory = JSON.stringify(g_mapMemory);
if (exit == false)
{
playAlertMediaFile("Clicky-3.mp3");
}
}
else
{
if (g_mapMemory[x].zoom != -1)
{
g_mapView.setCenter(g_mapMemory[x].LoLa);
g_mapView.setZoom(g_mapMemory[x].zoom);
}
}
}
var g_hotKeys = {};
function registerHotKey(key, func, param1, param2)
{
g_hotKeys[key] = {};
g_hotKeys[key].func = func;
g_hotKeys[key].param1 = param1;
g_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("KeyH", cycleSpotView);
registerHotKey("KeyI", showRootInfoBox);
// registerHotKey("KeyJ", setTrophyOverlay, 8);
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("KeyY", toggleGlobalStrikes);
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()
{
g_appSettings.moonTrack ^= 1;
if (g_appSettings.moonTrack == 1)
{
moonLayer.show();
}
else
{
moonLayer.hide();
}
}
function toggleMoonTrack()
{
g_appSettings.moonPath ^= 1;
moonLayer.refresh();
}
function toggleFullscreen()
{
if (document.fullscreenElement == null)
{
mainBody.requestFullscreen();
}
else
{
document.exitFullscreen();
}
}
function toggleMenu()
{
if (g_menuShowing == false) collapseMenu(false);
else collapseMenu(true);
}
g_helpShow = false;
function toggleHelp()
{
g_helpShow = !g_helpShow;
if (g_helpShow == true)
{
helpDiv.style.display = "block";
}
else helpDiv.style.display = "none";
}
function onMyKeyUp(event) { }
var g_currentOverlay = 0;
function cycleTrophyOverlay()
{
g_currentOverlay++;
g_currentOverlay %= 8;
setTrophyOverlay(g_currentOverlay);
}
function didWork(testObj)
{
return testObj.worked;
}
function didConfirm(testObj)
{
return testObj.confirmed;
}
function makeTitleInfo(mapWindow)
{
var band =
g_appSettings.gtBandFilter.length == 0
? "Mixed"
: g_appSettings.gtBandFilter == "auto"
? myBand
: g_appSettings.gtBandFilter;
var mode =
g_appSettings.gtModeFilter.length == 0
? "Mixed"
: g_appSettings.gtModeFilter == "auto"
? myMode
: g_appSettings.gtModeFilter;
var news = `GridTracker ${gtVersionStr} [Band: ${band} Mode: ${mode}`;
var end = "]";
if (mapWindow)
{
news += ` Layer: ${g_viewInfo[g_currentOverlay][1]}`;
}
if (g_currentOverlay == 0 && g_appSettings.gridViewMode == 1) { return news + end; }
var workline = ` - Worked ${g_viewInfo[g_currentOverlay][2]} Confirmed ${g_viewInfo[g_currentOverlay][3]}`
if (
g_viewInfo[g_currentOverlay][2] <= g_viewInfo[g_currentOverlay][4] &&
g_viewInfo[g_currentOverlay][4] > 0
)
{
end = ` Needed ${(g_viewInfo[g_currentOverlay][4] - g_viewInfo[g_currentOverlay][2])}]`;
}
return news + workline + end;
}
function setTrophyOverlay(which)
{
g_currentOverlay = which;
window.document.title = makeTitleInfo(true);
trophyImg.src = g_trophyImageArray[which];
myTrophyTooltip.style.zIndex = -1;
clearCurrentShapes();
// set the scope of key
var key = 0;
if (which == 0)
{
for (key in g_layerVectors)
{
g_layerVectors[key].setVisible(true);
}
if (
g_appSettings.gtFlagImgSrc > 0 &&
g_appSettings.gtShareEnable == true &&
g_mapSettings.offlineMode == false
)
{
g_layerVectors.gtflags.setVisible(true);
}
else
{
g_layerVectors.gtflags.setVisible(false);
}
g_layerVectors.award.setVisible(false);
if (g_showAllGrids == false)
{
g_layerVectors["line-grids"].setVisible(false);
g_layerVectors["big-grids"].setVisible(false);
g_layerVectors["long-grids"].setVisible(false);
}
if (g_timezoneLayer)
{
if (g_timezonesEnable == 1)
{
g_timezoneLayer.setVisible(true);
}
else
{
g_timezoneLayer.setVisible(false);
}
}
}
else
{
if (g_mapSettings.mergeOverlay == false)
{
for (key in g_layerVectors)
{
g_layerVectors[key].setVisible(false);
}
}
else
{
for (key in g_layerVectors)
{
g_layerVectors[key].setVisible(true);
}
if (
g_appSettings.gtFlagImgSrc > 0 &&
g_appSettings.gtShareEnable == true &&
g_mapSettings.offlineMode == false
)
{
g_layerVectors.gtflags.setVisible(true);
}
else
{
g_layerVectors.gtflags.setVisible(false);
}
if (g_showAllGrids == false)
{
g_layerVectors["line-grids"].setVisible(false);
g_layerVectors["big-grids"].setVisible(false);
g_layerVectors["long-grids"].setVisible(false);
}
}
g_layerVectors.award.setVisible(true);
if (g_timezoneLayer)
{
g_timezoneLayer.setVisible(false);
}
mapLoseFocus();
}
if (which == 1)
{
for (key in g_cqZones)
{
var boxColor = "#FF000015";
var borderColor = "#005500FF";
var borderWeight = 1;
if (didConfirm(g_cqZones[key]))
{
boxColor = "#00FF0066";
}
else if (didWork(g_cqZones[key]))
{
boxColor = "#FFFF0066";
}
g_currentShapes[key] = shapeFeature(
key,
g_cqZones[key].geo,
"cqzone",
boxColor,
borderColor,
borderWeight
);
g_layerSources.award.addFeature(g_currentShapes[key]);
}
}
if (which == 2)
{
for (key in g_ituZones)
{
var boxColor = "#FF000015";
var borderColor = "#800080FF";
var borderWeight = 1;
if (didConfirm(g_ituZones[key]))
{
boxColor = "#00FF0066";
borderWeight = 1;
}
else if (didWork(g_ituZones[key]))
{
boxColor = "#FFFF0066";
borderWeight = 1;
}
g_currentShapes[key] = shapeFeature(
key,
g_ituZones[key].geo,
"ituzone",
boxColor,
borderColor,
borderWeight
);
g_layerSources.award.addFeature(g_currentShapes[key]);
}
}
if (which == 3)
{
for (key in g_wacZones)
{
var boxColor = "#FF000015";
var borderColor = "#006666FF";
var borderWeight = 1;
var originalKey = key;
if (didConfirm(g_wacZones[key]))
{
boxColor = "#00FF0066";
}
else if (didWork(g_wacZones[key]))
{
boxColor = "#FFFF0066";
}
g_currentShapes[originalKey] = shapeFeature(
originalKey,
g_wacZones[originalKey].geo,
"wac",
boxColor,
borderColor,
borderWeight
);
g_layerSources.award.addFeature(g_currentShapes[originalKey]);
}
}
if (which == 4)
{
for (key in g_wasZones)
{
var boxColor = "#FF000020";
var borderColor = "#0000FFFF";
var borderWeight = 1;
if (didConfirm(g_wasZones[key]))
{
boxColor = "#00FF0066";
}
else if (didWork(g_wasZones[key]))
{
boxColor = "#FFFF0066";
}
g_currentShapes[key] = shapeFeature(
key,
g_wasZones[key].geo,
"was",
boxColor,
borderColor,
borderWeight
);
g_layerSources.award.addFeature(g_currentShapes[key]);
}
}
if (which == 5)
{
for (key in g_dxccInfo)
{
var boxColor = "#FF000015";
var borderColor = "#0000FFFF";
var borderWeight = 1;
if (didConfirm(g_dxccInfo[key]))
{
boxColor = "#00FF0066";
}
else if (didWork(g_dxccInfo[key]))
{
boxColor = "#FFFF0066";
}
if (g_dxccInfo[key].geo != "deleted")
{
g_currentShapes[key] = shapeFeature(
key,
g_dxccInfo[key].geo,
"dxcc",
boxColor,
borderColor,
borderWeight
);
g_layerSources.award.addFeature(g_currentShapes[key]);
}
}
}
if (which == 6)
{
for (key in g_countyData)
{
var boxColor = "#00000000";
var borderColor = "#0000FFFF";
var borderWeight = 0.1;
if (didConfirm(g_countyData[key]))
{
boxColor = "#00FF0066";
borderWeight = 1;
}
else if (didWork(g_countyData[key]))
{
boxColor = "#FFFF0066";
borderWeight = 1;
}
g_currentShapes[key] = shapeFeature(
key,
g_countyData[key].geo,
"usc",
boxColor,
borderColor,
borderWeight
);
g_layerSources.award.addFeature(g_currentShapes[key]);
}
}
if (which == 7)
{
for (key in g_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 (g_us48Data[key].confirmed)
{
boxColor = "#00FF0066";
borderWeight = 0.2;
}
else if (g_us48Data[key].worked)
{
boxColor = "#FFFF0066";
borderWeight = 0.2;
}
g_currentShapes[key] = gridFeature(
key,
rectangle(bounds),
"us48",
boxColor,
borderColor,
borderWeight
);
g_layerSources.award.addFeature(g_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;
}
var g_lastMoon = null;
function moonOver(feature)
{
var data = subLunar(timeNowSec());
var object = doRAconvert(g_myLon, g_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 = "<table class='darkTable'>";
worker +=
"<tr><th colspan=2 style='font-size:15px;color:cyan;'>Moon</th></tr>";
worker +=
"<tr><th >Azimuth</th><td style='color:lightgreen'>" +
object.azimuth.toFixed(1) +
"&deg;</td></tr>";
worker +=
"<tr><th >Elevation</th><td style='color:" +
elColor +
"'>" +
elevation +
"</td></tr>";
worker += "</table>";
myMoonTooltip.innerHTML = worker;
if (g_lastMoon)
{
moonMove();
return;
}
g_lastMoon = feature;
moonMove();
myMoonTooltip.style.zIndex = 499;
myMoonTooltip.style.display = "block";
}
function moonOut()
{
g_lastMoon = null;
myMoonTooltip.style.zIndex = -1;
}
function moonMove()
{
var positionInfo = myMoonTooltip.getBoundingClientRect();
myMoonTooltip.style.left = getMouseX() - positionInfo.width / 2 + "px";
myMoonTooltip.style.top = getMouseY() + 22 + "px";
}
var g_lastTrophy = null;
function trophyOver(feature)
{
if (g_lastTrophy && g_lastTrophy == feature)
{
trophyMove();
return;
}
g_lastTrophy = feature;
var name = feature.getGeometryName();
var infoObject = {};
var trophy = "";
var zone = null;
var key = feature.get("prop");
if (key == "cqzone")
{
trophy = "CQ Zone";
infoObject = g_cqZones[name];
zone = name;
name = g_cqZones[name].name;
}
if (key == "ituzone")
{
trophy = "ITU Zone";
infoObject = g_ituZones[name];
}
if (key == "wac" && name in g_wacZones)
{
trophy = "Continent";
infoObject = g_wacZones[name];
}
if (key == "was" && name in g_wasZones)
{
trophy = "US State";
infoObject = g_wasZones[name];
}
if (key == "dxcc" && name in g_dxccInfo)
{
trophy = "DXCC";
var ref = name;
infoObject = g_dxccInfo[ref];
name =
g_dxccInfo[ref].name +
" <font color='orange'>(" +
g_dxccInfo[ref].pp +
")</font>";
}
if (key == "usc")
{
trophy = "US County";
infoObject = g_countyData[name];
name = infoObject.geo.properties.n + ", " + infoObject.geo.properties.st;
}
if (key == "us48")
{
trophy = "US Continental Grids";
infoObject = g_us48Data[feature.get("grid")];
name = feature.get("grid");
if (name in g_gridToState)
{
zone = "";
for (var x = 0; x < g_gridToDXCC[name].length; x++)
{
if (name in g_gridToState)
{
for (var y = 0; y < g_gridToState[name].length; y++)
{
if (g_gridToDXCC[name][x] == g_StateData[g_gridToState[name][y]].dxcc && g_gridToDXCC[name][x] == 291)
{
zone += g_StateData[g_gridToState[name][y]].name + ", ";
}
}
}
}
zone = zone.substr(0, zone.length - 2);
}
}
var worker = "<table>";
worker += "<tr><th colspan=2 >" + trophy + "</th></tr>";
worker +=
"<tr><td colspan=2><font color='white'><b>" +
name +
"</b></font></td></tr>";
if (zone)
{
worker +=
" <tr><td colspan=2><font color='lightgreen'>" +
zone +
"</font></td></tr>";
}
var wc1Table = "<td></td>";
if (infoObject.worked)
{
wc1Table = "<td align=center><table class='darkTable'>";
wc1Table +=
"<tr><td colspan=2 ><font color='yellow'>Worked</font></td></tr>";
wc1Table += "<tr><td align=right><font color='green'>Band</font></td>";
wc1Table += "<td align=left><table class='subtable'>";
var keys = Object.keys(infoObject.worked_bands).sort();
for (key in keys)
{
wc1Table +=
"<tr><td align=right>" +
keys[key] +
"</td><td align=left> <font color='white'>(" +
infoObject.worked_bands[keys[key]] +
") " +
"</font></td></tr>";
}
wc1Table += "</table></td>";
wc1Table += "</tr>";
wc1Table += "<tr>";
wc1Table += "<td align=right><font color='orange'>Mode</font></td>";
wc1Table += "<td align=left><table class='subtable'>";
keys = Object.keys(infoObject.worked_modes).sort();
for (key in keys)
{
wc1Table +=
"<tr><td align=right>" +
keys[key] +
"</td><td align=left> <font color='white'>(" +
infoObject.worked_modes[keys[key]] +
") " +
"</font></td></tr>";
}
wc1Table += "</table></td>";
wc1Table += "</tr>";
wc1Table += "</table></td>";
}
var wcTable = "<td></td>";
if (infoObject.confirmed)
{
wcTable = "<td align=center><table class='darkTable'>";
wcTable +=
"<tr><td colspan=2 ><font color='lightgreen'>Confirmed</font></td></tr>";
wcTable += "<tr><td align=right><font color='green'>Band</font></td>";
wcTable += "<td align=left><table class='subtable'>";
var keys = Object.keys(infoObject.confirmed_bands).sort();
for (key in keys)
{
wcTable +=
"<tr><td align=right>" +
keys[key] +
"</td><td align=left> <font color='white'>(" +
infoObject.confirmed_bands[keys[key]] +
") " +
"</font></td></tr>";
}
wcTable += "</table></td>";
wcTable += "</tr>";
wcTable += "<tr>";
wcTable += "<td align=right><font color='orange'>Mode</font></td>";
wcTable += "<td align=left><table class='subtable'>";
keys = Object.keys(infoObject.confirmed_modes).sort();
for (key in keys)
{
wcTable +=
"<tr><td align=right>" +
keys[key] +
"</td><td align=left> <font color='white'>(" +
infoObject.confirmed_modes[keys[key]] +
") " +
"</font></td></tr>";
}
wcTable += "</table></td>";
wcTable += "</tr>";
wcTable += "</table></td>";
}
if (!infoObject.worked && !infoObject.confirmed)
{
worker +=
"<tr><td colspan=2 ><font color='orange'>Needed</font></td></tr>";
}
else
{
worker += "<tr>" + wc1Table + wcTable + "</tr>";
}
worker += "</table>";
myTrophyTooltip.innerHTML =
"<div style='font-size:15px;color:cyan;' class='roundBorder'>" +
worker +
"</div>";
trophyMove();
myTrophyTooltip.style.zIndex = 499;
myTrophyTooltip.style.display = "block";
}
function trophyOut()
{
g_lastTrophy = null;
myTrophyTooltip.style.zIndex = -1;
}
function trophyMove()
{
var positionInfo = myTrophyTooltip.getBoundingClientRect();
myTrophyTooltip.style.left = getMouseX() - positionInfo.width / 2 + "px";
myTrophyTooltip.style.top = getMouseY() - positionInfo.height - 22 + "px";
}
var g_MyCurrentGrid = "";
var g_MyGridIsUp = false;
function mouseDownGrid(longlat, event)
{
var grid = "";
grid = latLonToGridSquare(longlat[1], longlat[0]);
g_MyCurrentGrid = grid.substr(0, 4);
var worker = "";
worker += "<table align='center' class='darkTable'><tr style='color:white;'>";
var bearing = parseInt(
MyCircle.bearing(g_myLat, g_myLon, longlat[1], longlat[0])
);
worker +=
"<tr><td>Dist</td><td style='color:lightgreen'>" +
parseInt(
MyCircle.distance(
g_myLat,
g_myLon,
longlat[1],
longlat[0],
distanceUnit.value
) * MyCircle.validateRadius(distanceUnit.value)
) +
distanceUnit.value.toLowerCase() +
"</td></tr>";
worker +=
"<tr><td>Azim</td><td style='color:yellow'>" + bearing + "&deg;</td></tr>";
worker +=
"<tr><td>Lat</td><td style='color:orange'>" +
longlat[1].toFixed(3) +
"</td></tr>";
worker +=
"<tr><td>Long</td><td style='color:lightblue'>" +
longlat[0].toFixed(3) +
"</td></tr></table>";
if (grid in g_gridToDXCC)
{
worker +=
"<table align='center' class='darkTable' style='border-top:none'><tr style='color:white;'>";
worker += "<tr style='color:orange;'>";
for (var x = 0; x < g_gridToDXCC[grid].length; x++)
{
worker +=
"<td>" +
g_dxccToAltName[g_gridToDXCC[grid][x]] +
" <font color='lightgreen'>(" +
g_dxccInfo[g_gridToDXCC[grid][x]].pp +
")</font></td>";
}
if (grid in g_gridToState)
{
worker += "</tr><tr style='color:yellow;'>";
for (var x = 0; x < g_gridToDXCC[grid].length; x++)
{
worker += "<td>";
if (grid in g_gridToState)
{
for (var y = 0; y < g_gridToState[grid].length; y++)
{
if (
g_gridToDXCC[grid][x] == g_StateData[g_gridToState[grid][y]].dxcc
)
{
worker += g_StateData[g_gridToState[grid][y]].name + "<br/>";
}
}
}
worker += "</td>";
}
}
worker += "</tr></table>";
}
g_tempGridBox = tempGridToBox(grid, g_tempGridBox, "#000000FF", "#00000000");
myGridTooltip.innerHTML =
"<div style='font-size:14px;font-weight:bold;color:cyan;margin:0 auto' class='roundBorder'>" +
grid +
"</div>" +
worker;
g_MyGridIsUp = true;
mouseMoveGrid();
myGridTooltip.style.zIndex = 499;
myGridTooltip.style.display = "block";
}
function mouseMoveGrid()
{
if (g_MyGridIsUp == true)
{
var positionInfo = myGridTooltip.getBoundingClientRect();
myGridTooltip.style.left = getMouseX() - positionInfo.width / 2 + "px";
myGridTooltip.style.top = getMouseY() - positionInfo.height - 22 + "px";
}
}
function mouseUpGrid()
{
g_MyGridIsUp = false;
myGridTooltip.style.zIndex = -1;
if (g_tempGridBox)
{
if (g_layerSources.temp.hasFeature(g_tempGridBox)) { g_layerSources.temp.removeFeature(g_tempGridBox); }
}
g_tempGridBox = null;
}
var g_lastGtFlag = null;
function mouseOverGtFlag(feature)
{
if (g_lastGtFlag && g_lastGtFlag == feature)
{
gtFlagMove();
return;
}
g_lastGtFlag = feature;
createFlagTipTable(feature);
gtFlagMove();
myFlagtip.style.zIndex = 499;
myFlagtip.style.display = "block";
if (feature.size == 73 && feature != g_lasttimezone)
{
if (g_lasttimezone != null)
{
g_lasttimezone.setStyle(null);
}
var style = new ol.style.Style({
fill: new ol.style.Fill({
color: "#FFFF0088"
})
});
feature.setStyle(style);
g_lasttimezone = feature;
}
}
function mouseOutGtFlag(mouseEvent)
{
g_lastGtFlag = null;
myFlagtip.style.zIndex = -1;
if (g_lasttimezone != null)
{
g_lasttimezone.setStyle(null);
g_lasttimezone = null;
}
}
function gtFlagMove()
{
var positionInfo = myFlagtip.getBoundingClientRect();
myFlagtip.style.left = getMouseX() + 15 + "px";
myFlagtip.style.top = getMouseY() - positionInfo.height - 5 + "px";
}
var g_lastDataGridUp = null;
function mouseOverDataItem(mouseEvent, fromHover)
{
if (g_MyGridIsUp) return;
if (g_lastDataGridUp && g_lastDataGridUp == mouseEvent)
{
mouseMoveDataItem(mouseEvent);
return;
}
if (g_mapSettings.mouseOver == true && fromHover == false) return;
if (g_mapSettings.mouseOver == false && fromHover == true) return;
g_lastDataGridUp = mouseEvent;
var isFlag = false;
var callListLength = createTooltTipTable(mouseEvent);
var positionInfo = myTooltip.getBoundingClientRect();
var windowWidth = window.innerWidth;
var top = 0;
var noRoomLeft = false;
var noRoomRight = false;
if (
typeof mouseEvent.spot != "undefined" &&
g_receptionReports.spots[mouseEvent.spot].bearing > 180
) { noRoomRight = true; }
myTooltip.style.left = getMouseX() + 15 + "px";
top = parseInt(getMouseY() - 20 - (callListLength / 2) * 25);
if (windowWidth - getMouseX() < positionInfo.width || noRoomRight == true)
{
myTooltip.style.left = getMouseX() - (10 + positionInfo.width) + "px";
top = parseInt(getMouseY() - 20 - (callListLength / 2) * 25);
noRoomRight = true;
}
if (getMouseX() - positionInfo.width < 0)
{
noRoomLeft = true;
}
if (noRoomLeft == true && noRoomRight == true)
{
myTooltip.style.left = getMouseX() - positionInfo.width / 2 + "px";
top = getMouseY() + 30;
}
if (top < 0) top = 0;
myTooltip.style.top = top + "px";
myTooltip.style.zIndex = 500;
myTooltip.style.display = "block";
}
function mouseMoveDataItem(mouseEvent)
{
var positionInfo = myTooltip.getBoundingClientRect();
var windowWidth = window.innerWidth;
var top = 0;
var noRoomLeft = false;
var noRoomRight = false;
if (
typeof mouseEvent.spot != "undefined" &&
g_receptionReports.spots[mouseEvent.spot].bearing > 180
) { noRoomRight = true; }
myTooltip.style.left = getMouseX() + 15 + "px";
top = Number(myTooltip.style.top);
if (top > 20) top = getMouseY() - 20 + "px";
if (windowWidth - getMouseX() < positionInfo.width || noRoomRight == true)
{
myTooltip.style.left = getMouseX() - (10 + positionInfo.width) + "px";
if (top > 20) top = getMouseY() - 20 + "px";
noRoomRight = true;
}
if (getMouseX() - positionInfo.width < 0)
{
noRoomLeft = true;
}
if (noRoomLeft == true && noRoomRight == true)
{
myTooltip.style.left = getMouseX() - positionInfo.width / 2 + "px";
top = getMouseY() + 30;
}
if (top < 0) top = 0;
myTooltip.style.top = top + "px";
}
function mouseOutOfDataItem(mouseEvent)
{
var myTooltip = document.getElementById("myTooltip");
myTooltip.style.zIndex = -1;
g_lastDataGridUp = null;
if (g_spotView == 1) g_layerSources["psk-hop"].clear();
}
function reloadInfo(bandOrMode)
{
if (g_statsWindowHandle != null)
{
try
{
g_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 || g_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)
{
var feature = new ol.Feature({
geometry: new ol.geom.Point(center),
name: "pin"
});
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 (g_appSettings.gridViewMode == 1) return null;
var borderColor = g_mainBorderColor;
var boxColor = g_legendColors.QSX + g_gridAlpha;
var borderWeight = 0.5;
var myDEzOffset = 10;
var myDEbox = false;
if (worked)
{
boxColor = g_legendColors.QSO + g_gridAlpha;
}
if (confirmed)
{
boxColor = g_legendColors.QSL + g_gridAlpha;
}
if (wspr != null)
{
boxColor = "hsl(" + wspr + ",100%,50%)";
borderColor = "gray";
}
var zIndex = 2;
var entityVisibility = g_appSettings.gridViewMode > 1;
var returnRectangle = null;
if (g_appSettings.sixWideMode == 0) iQTH = iQTH.substr(0, 4);
else iQTH = iQTH.substr(0, 6);
var rect = null;
if (iQTH == "")
{
for (var key in g_qsoGrids)
{
if (iHash in g_qsoGrids[key].rectangle.hashes)
{
rect = g_qsoGrids[key];
break;
}
}
}
else
{
if (iQTH in g_qsoGrids)
{
rect = g_qsoGrids[iQTH];
}
}
if (rect == null)
{
if (iQTH != "")
{
// Valid QTH
var triangleView = false;
if (
g_appSettings.gridViewMode == 3 &&
iQTH in g_liveGrids &&
entityVisibility == true &&
g_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 (g_pushPinMode == false && entityVisibility == true) { g_layerSources.qso.addFeature(newRect.rectangle); }
var newPin = g_colorLeafletQPins.worked[band];
if (confirmed) newPin = g_colorLeafletQPins.confirmed[band];
newRect.rectangle.pin = iconFeature(
ol.extent.getCenter(newRect.rectangle.getGeometry().getExtent()),
g_appSettings.sixWideMode == 1 ? newPin : g_pushPinIconOff,
zIndex
);
newRect.rectangle.pin.qth = iQTH;
newRect.rectangle.pin.hashes = {};
newRect.rectangle.pin.hashes[iHash] = 1;
newRect.rectangle.pin.size = LL.size;
if (g_pushPinMode && entityVisibility == true) { g_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;
g_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 = g_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 (g_appSettings.gridViewMode == 2) return null;
var borderColor = g_mainBorderColor;
var boxColor = g_legendColors.QSX + g_gridAlpha;
var borderWeight = 0.5;
var myDEzOffset = 0;
var myDEbox = false;
if (DE == "CQ" || iCQ)
{
boxColor = g_legendColors.CQ + g_gridAlpha;
}
if (DE == myDEcall)
{
borderColor = "#FF0000FF";
boxColor = g_legendColors.QRZ + g_gridAlpha;
borderWeight = 1.0;
myDEzOffset = 20;
myDEbox = true;
}
if (DE.indexOf("CQ DX") > -1)
{
boxColor = g_legendColors.CQDX + g_gridAlpha;
}
if (locked)
{
boxColor = g_legendColors.QTH + g_gridAlpha;
borderColor = "#000000FF";
borderOpacity = 1;
}
if (wspr != null)
{
boxColor = "hsl(" + wspr + ",100%,50%)";
borderColor = "gray";
}
var zIndex = 2;
var returnRectangle = null;
if (g_appSettings.sixWideMode == 0) iQTH = iQTH.substr(0, 4);
else iQTH = iQTH.substr(0, 6);
var rect = null;
if (iQTH == "")
{
for (var key in g_liveGrids)
{
if (hash in g_liveGrids[key].rectangle.liveHash)
{
rect = g_liveGrids[key];
break;
}
}
}
else
{
if (iQTH in g_liveGrids)
{
rect = g_liveGrids[iQTH];
}
}
if (rect == null)
{
if (iQTH != "")
{
// Valid QTH
var entityVisibility = true;
var triangleView = false;
if (
Number(g_appSettings.gridViewMode) == 3 &&
iQTH in g_qsoGrids &&
g_pushPinMode == false
)
{
if (
g_mapSettings.splitQSL ||
g_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 = g_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 (g_pushPinMode == false && entityVisibility)
{
g_layerSources.live.addFeature(newRect.rectangle);
}
newRect.rectangle.pin = iconFeature(
ol.extent.getCenter(newRect.rectangle.getGeometry().getExtent()),
g_colorLeafletPins[band],
zIndex
);
newRect.rectangle.pin.qth = iQTH;
newRect.rectangle.pin.liveHash = {};
newRect.rectangle.pin.liveHash[hash] = 1;
newRect.rectangle.pin.size = LL.size;
if (g_pushPinMode && entityVisibility == true) { g_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;
g_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 = g_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 - (g_timeNow - qthObj.age) / gridDecay.value;
var alpha = Math.max(0.06, (g_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()
{
g_mapSettings.trafficDecode = trafficDecode.checked;
trafficDecodeView();
saveMapSettings();
}
function trafficDecodeView()
{
if (g_mapSettings.trafficDecode == false)
{
trafficDiv.innerHTML = "";
g_lastTraffic = Array();
}
}
function changeFitQRZvalue()
{
g_mapSettings.fitQRZ = fitQRZvalue.checked;
saveMapSettings();
}
function changeQrzDxccFallbackValue()
{
g_mapSettings.qrzDxccFallback = qrzDxccFallbackValue.checked;
saveMapSettings();
}
function changeCqHiliteValue(check)
{
g_mapSettings.CQhilite = check.checked;
saveMapSettings();
if (check.checked == false) removePaths();
}
function changeFocusRigValue(check)
{
g_mapSettings.focusRig = check.checked;
saveMapSettings();
}
function changeHaltOntTxValue(check)
{
g_mapSettings.haltAllOnTx = check.checked;
saveMapSettings();
}
function changeSplitQSL()
{
g_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()
{
g_showAllGrids = !g_showAllGrids;
setTrophyOverlay(g_currentOverlay);
gridOverlayImg.style.filter = g_showAllGrids ? "" : "grayscale(1)";
}
function changeAnimate()
{
g_mapSettings.animate = animateValue.checked;
saveMapSettings();
var dash = [];
var dashOff = 0;
if (g_mapSettings.animate == true)
{
dash = g_flightPathLineDash;
dashOff = g_flightPathTotal - g_flightPathOffset;
}
for (var i = g_flightPaths.length - 1; i >= 0; i--)
{
if (g_flightPaths[i].isShapeFlight == 0)
{
var featureStyle = g_flightPaths[i].getStyle();
var featureStroke = featureStyle.getStroke();
featureStroke.setLineDash(dash);
featureStroke.setLineDashOffset(dashOff);
featureStyle.setStroke(featureStroke);
g_flightPaths[i].setStyle(featureStyle);
}
}
if (g_transmitFlightPath != null)
{
var featureStyle = g_transmitFlightPath.getStyle();
var featureStroke = featureStyle.getStroke();
featureStroke.setLineDash(dash);
featureStroke.setLineDashOffset(dashOff);
featureStyle.setStroke(featureStroke);
g_transmitFlightPath.setStyle(featureStyle);
}
setAnimateView();
}
function changeAnimateSpeedValue()
{
g_mapSettings.animateSpeed = 21 - animateSpeedValue.value;
saveMapSettings();
}
var g_animateFrame = 0;
var g_nextDimTime = 0;
var g_last = 0;
function removeFlightPathsAndDimSquares()
{
for (var i = g_flightPaths.length - 1; i >= 0; i--)
{
if (g_flightPaths[i].age < g_timeNow)
{
if (typeof g_flightPaths[i].Arrow != "undefined") { g_layerSources.flight.removeFeature(g_flightPaths[i].Arrow); }
g_layerSources.flight.removeFeature(g_flightPaths[i]);
delete g_flightPaths[i];
g_flightPaths[i] = null;
g_flightPaths.splice(i, 1);
}
}
if (g_timeNow > g_nextDimTime)
{
dimGridsquare();
}
}
function animatePaths()
{
requestAnimationFrame(animatePaths);
g_last ^= g_last;
if (g_last == 1) return;
g_animateFrame++;
g_animateFrame %= g_mapSettings.animateSpeed;
if (g_animateFrame > 0) return;
if (g_mapSettings.animate == false) return;
g_flightPathOffset += 1;
g_flightPathOffset %= g_flightPathTotal;
var targetOffset = g_flightPathTotal - g_flightPathOffset;
var featureStyle = null;
var featureStroke = null;
for (var i = 0; i < g_flightPaths.length; i++)
{
if (g_flightPaths[i].isShapeFlight == 0)
{
featureStyle = g_flightPaths[i].getStyle();
featureStroke = featureStyle.getStroke();
featureStroke.setLineDashOffset(targetOffset);
g_flightPaths[i].setStyle(featureStyle);
}
}
if (g_transmitFlightPath != null)
{
var featureStyle = g_transmitFlightPath.getStyle();
var featureStroke = featureStyle.getStroke();
featureStroke.setLineDashOffset(targetOffset);
featureStyle.setStroke(featureStroke);
g_transmitFlightPath.setStyle(featureStyle);
}
}
function removePaths()
{
g_layerSources.flight.clear();
g_flightPaths = Array();
}
function fadePaths()
{
if (pathWidthValue.value == 0)
{
removePaths();
}
}
function dimGridsquare()
{
if (gridDecay.value == 0) return;
for (var i in g_liveGrids)
{
dimFunction(g_liveGrids[i]);
if (
g_timeNow - g_liveGrids[i].age >= gridDecay.value &&
g_liveGrids[i].rectangle.locked == false
)
{
// Walk the rectangles DEcall's and remove them from g_liveCallsigns
for (var CallIsKey in g_liveGrids[i].rectangle.liveHash)
{
if (CallIsKey in g_liveCallsigns)
{
g_liveCallsigns[CallIsKey].rect = null;
delete g_liveCallsigns[CallIsKey];
}
}
if (g_liveGrids[i].rectangle.pin != null)
{
if (
g_layerSources["live-pins"].hasFeature(g_liveGrids[i].rectangle.pin)
)
{
g_layerSources["live-pins"].removeFeature(
g_liveGrids[i].rectangle.pin
);
}
}
if (g_layerSources.live.hasFeature(g_liveGrids[i].rectangle))
{
g_layerSources.live.removeFeature(g_liveGrids[i].rectangle);
if (g_appSettings.gridViewMode == 3 && i in g_qsoGrids)
{
if (g_qsoGrids[i].isTriangle)
{
triangleToGrid(i, g_qsoGrids[i].rectangle);
g_qsoGrids[i].isTriangle = false;
}
}
}
g_liveGrids[i] = null;
delete g_liveGrids[i];
}
}
g_nextDimTime = g_timeNow + 7;
}
function updateCountStats()
{
var count = Object.keys(g_liveCallsigns).length;
if (myDEcall in g_liveCallsigns) count--;
callsignCount.innerHTML = count;
qsoCount.innerHTML = g_QSOcount;
qslCount.innerHTML = g_QSLcount;
countryCount.innerHTML = Object.keys(g_dxccCount).length;
if (Object.keys(g_QSOhash).length > 0)
{
clearOrLoadButton.innerHTML = "Clear Log";
g_loadQSOs = false;
}
else
{
clearOrLoadButton.innerHTML = "Load Logs";
g_loadQSOs = true;
}
}
function clearGrids()
{
g_layerSources.live.clear();
g_layerSources["live-pins"].clear();
for (var i in g_liveGrids)
{
// Walk the rectangles DEcall's and remove the rect from the g_liveCallsigns
for (var CallIsKey in g_liveGrids[i].rectangle.liveHash)
{
if (CallIsKey in g_liveCallsigns) g_liveCallsigns[CallIsKey].rect = null;
}
}
g_liveGrids = {};
}
function clearQsoGrids()
{
g_layerSources.qso.clear();
g_layerSources["qso-pins"].clear();
g_qsoGrids = {};
for (var key in g_dxccInfo)
{
g_dxccInfo[key].worked = false;
g_dxccInfo[key].confirmed = false;
g_dxccInfo[key].worked_bands = {};
g_dxccInfo[key].confirmed_bands = {};
g_dxccInfo[key].worked_modes = {};
g_dxccInfo[key].confirmed_modes = {};
}
for (var key in g_cqZones)
{
g_cqZones[key].worked = false;
g_cqZones[key].confirmed = false;
g_cqZones[key].worked_bands = {};
g_cqZones[key].confirmed_bands = {};
g_cqZones[key].worked_modes = {};
g_cqZones[key].confirmed_modes = {};
}
for (var key in g_ituZones)
{
g_ituZones[key].worked = false;
g_ituZones[key].confirmed = false;
g_ituZones[key].worked_bands = {};
g_ituZones[key].confirmed_bands = {};
g_ituZones[key].worked_modes = {};
g_ituZones[key].confirmed_modes = {};
}
for (var key in g_wasZones)
{
g_wasZones[key].worked = false;
g_wasZones[key].confirmed = false;
g_wasZones[key].worked_bands = {};
g_wasZones[key].confirmed_bands = {};
g_wasZones[key].worked_modes = {};
g_wasZones[key].confirmed_modes = {};
}
for (var key in g_wacZones)
{
g_wacZones[key].worked = false;
g_wacZones[key].confirmed = false;
g_wacZones[key].worked_bands = {};
g_wacZones[key].confirmed_bands = {};
g_wacZones[key].worked_modes = {};
g_wacZones[key].confirmed_modes = {};
}
for (var key in g_countyData)
{
g_countyData[key].worked = false;
g_countyData[key].confirmed = false;
g_countyData[key].worked_bands = {};
g_countyData[key].confirmed_bands = {};
g_countyData[key].worked_modes = {};
g_countyData[key].confirmed_modes = {};
}
for (var key in g_us48Data)
{
g_us48Data[key].worked = false;
g_us48Data[key].confirmed = false;
g_us48Data[key].worked_bands = {};
g_us48Data[key].confirmed_bands = {};
g_us48Data[key].worked_modes = {};
g_us48Data[key].confirmed_modes = {};
}
}
function clearCalls()
{
removePaths();
for (var i in g_liveCallsigns)
{
if (
typeof g_liveCallsigns[i].rect != "undefined" &&
g_liveCallsigns[i].rect != null
)
{
if (i in g_liveCallsigns[i].rect.liveHash) { delete g_liveCallsigns[i].rect.liveHash[i]; }
}
}
g_liveCallsigns = {};
g_dxccCount = {};
redrawGrids();
}
function clearLive()
{
g_Decodes = 0;
g_lastMessages = Array();
g_lastTraffic = Array();
g_callRoster = {};
g_dxccCount = {};
removePaths();
removePaths();
clearGrids();
clearCalls();
clearTempGrids();
setHomeGridsquare();
redrawGrids();
updateRosterWorked();
goProcessRoster();
}
function clearAll()
{
clearTempGrids();
clearCalls();
clearQSOs();
g_lastMessages = Array();
g_lastTraffic = Array();
g_dxccCount = {};
redrawGrids();
g_callRoster = {};
updateRosterWorked();
goProcessRoster();
}
function clearOrLoadQSOs()
{
if (g_loadQSOs == true)
{
startupAdifLoadCheck();
}
else
{
clearQSOs();
}
}
function clearAndLoadQSOs()
{
clearQSOs();
startupAdifLoadCheck();
}
function clearQSOs()
{
initQSOdata();
g_QSOhash = {};
g_QSLcount = 0;
g_QSOcount = 0;
setTrophyOverlay(g_currentOverlay);
redrawGrids();
updateLogbook();
updateRosterWorked();
goProcessRoster();
clearLogFilesAndCounts();
}
function clearLogFilesAndCounts()
{
tryToDeleteLog("LogbookOfTheWorld.adif");
tryToDeleteLog("qrz.adif");
tryToDeleteLog("clublog.adif");
g_adifLogSettings.downloads = {};
g_adifLogSettings.lastFetch.lotw_qso = "1970-01-01";
g_adifLogSettings.lastFetch.lotw_qsl = "1970-01-01";
saveAdifSettings();
}
function getCurrentBandModeHTML()
{
var band = g_appSettings.gtBandFilter == "auto" ? myBand + " (Auto)" : g_appSettings.gtBandFilter.length == 0 ? "Mixed Bands" : g_appSettings.gtBandFilter;
var mode = g_appSettings.gtModeFilter == "auto" ? myMode + " (Auto)" : g_appSettings.gtModeFilter.length == 0 ? "Mixed Modes" : g_appSettings.gtModeFilter;
return (
"<div style='vertical-align:top;display:inline-block;margin-bottom:3px;color:lightgreen;font-weight:bold;font-size:larger'>Viewing: <text style='color:yellow'>" +
band +
"</text> / <text style='color:orange'>" +
mode +
"</text></b></div><br/>"
);
}
var g_currentDay = 0;
var g_nightTime = false;
var g_currentNightState = false;
var g_timeNow = timeNowSec();
function displayTime()
{
g_timeNow = timeNowSec();
if (menuDiv.className == "menuDivStart" && g_menuShowing == true)
{
menuDiv.className = "menuDivEnd";
mapDiv.className = "mapDivEnd";
LegendDiv.className = "legendDivEnd";
g_map.updateSize();
}
currentTime.innerHTML =
"<font color='lightblue'>" + userTimeString(null) + "</font>";
if (g_lastTimeSinceMessageInSeconds > 0)
{
var since = g_timeNow - g_lastTimeSinceMessageInSeconds;
secondsAgoMsg.innerHTML = since.toDHMS();
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 = "<b>Never</b>";
checkWsjtxListener();
if (g_timeNow % 22 == 0)
{
g_nightTime = dayNight.refresh();
moonLayer.refresh();
}
pskSpotCheck(g_timeNow);
if (g_currentNightState != g_nightTime)
{
changeMapLayer();
g_currentNightState = g_nightTime;
}
}
function timeNowSec()
{
return parseInt(Date.now() / 1000);
}
function createGlobalHeatmapLayer(name, radius, blur)
{
g_layerSources[name] = new ol.source.Vector({});
g_layerVectors[name] = new ol.layer.Heatmap({
source: g_layerSources[name],
zIndex: Object.keys(g_layerVectors).length + 1
});
g_layerVectors[name].set("name", name);
}
function createGlobalMapLayer(name, maxResolution, minResolution)
{
g_layerSources[name] = new ol.source.Vector({});
if (
typeof maxResolution == "undefined" &&
typeof minResolution == "undefined"
)
{
var zIndex = Object.keys(g_layerVectors).length + 1;
g_layerVectors[name] = new ol.layer.Vector({
source: g_layerSources[name],
zIndex: zIndex
});
}
else if (typeof minResolution == "undefined")
{
g_layerVectors[name] = new ol.layer.Vector({
source: g_layerSources[name],
maxResolution: maxResolution,
zIndex: Object.keys(g_layerVectors).length + 1
});
}
else
{
g_layerVectors[name] = new ol.layer.Vector({
source: g_layerSources[name],
maxResolution: maxResolution,
minResolution: minResolution,
zIndex: Object.keys(g_layerVectors).length + 1
});
}
g_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;
}
var g_gtFlagIcon = new ol.style.Icon({
src: "./img/flag_gt_user.png",
anchorYUnits: "pixels",
anchorXUnits: "pixels",
anchor: [12, 17]
});
var g_pushPinIconOff = new ol.style.Icon({
src: "./img/red-circle.png",
anchorYUnits: "pixels",
anchorXUnits: "pixels",
anchor: [5, 18]
});
function panTo(location)
{
var duration = 1000;
g_mapView.animate({
center: location,
duration: duration
});
}
function toggleMouseTrack()
{
g_appSettings.mouseTrack ^= 1;
if (g_appSettings.mouseTrack == 0) mouseTrackDiv.style.display = "none";
}
function myGmapNameCompare(a, b)
{
return g_maps[a].name.localeCompare(g_maps[b].name);
}
var g_Nexrad = null;
function initMap()
{
document.getElementById("mapDiv").innerHTML = "";
g_maps = JSON.parse(fs.readFileSync(g_mapsFile));
if (g_maps)
{
var saveSettings = false;
g_maps = Object.keys(g_maps).sort().reduce((obj, key) => { obj[key] = g_maps[key]; return obj; }, {});
if (!(g_mapSettings.mapIndex in g_maps))
{
g_mapSettings.mapIndex = def_mapSettings.mapIndex;
saveSettings = true;
}
if (!(g_mapSettings.nightMapIndex in g_maps))
{
g_mapSettings.nightMapIndex = def_mapSettings.nightMapIndex;
saveSettings = true;
}
if (saveSettings)
{
saveMapSettings();
}
for (const key in g_maps)
{
g_mapsLayer[key] = new ol.source.XYZ(g_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 = g_mapSettings.mapIndex;
mapNightSelect.value = g_mapSettings.nightMapIndex;
}
else g_mapsLayer[0] = new ol.source.OSM();
g_offlineLayer = new ol.source.XYZ({
url: "/map/sat/{z}/{x}/{y}.png"
});
if (g_mapSettings.offlineMode)
{
g_tileLayer = new ol.layer.Tile({
source: g_offlineLayer,
loadTilesWhileInteracting: true,
loadTilesWhileAnimating: true
});
}
else
{
g_tileLayer = new ol.layer.Tile({
source: g_mapsLayer[mapSelect.value],
loadTilesWhileInteracting: true,
loadTilesWhileAnimating: true
});
}
g_scaleLine = new ol.control.ScaleLine({
units: g_scaleUnits[g_appSettings.distanceUnit]
});
var g_mapControl = [
g_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("pota");
createGlobalMapLayer("psk-flights");
createGlobalMapLayer("psk-spots");
createGlobalMapLayer("psk-hop");
createGlobalMapLayer("flight");
createGlobalMapLayer("transmit");
createGlobalMapLayer("gtflags");
createGlobalMapLayer("temp");
createGlobalMapLayer("tz");
createGlobalMapLayer("radar");
g_mapView = new ol.View({
center: [g_myLon, g_myLat],
zoomFactor: 1.25,
zoom: g_mapSettings.zoom,
showFullExtent: true
});
g_map = new ol.Map({
target: "mapDiv",
layers: [
g_tileLayer,
g_layerVectors.award,
g_layerVectors["psk-heat"],
g_layerVectors.qso,
g_layerVectors["qso-pins"],
g_layerVectors.live,
g_layerVectors["live-pins"],
g_layerVectors["line-grids"],
g_layerVectors["long-grids"],
g_layerVectors["big-grids"],
g_layerVectors.pota,
g_layerVectors["psk-flights"],
g_layerVectors["psk-spots"],
g_layerVectors["psk-hop"],
g_layerVectors.flight,
g_layerVectors.transmit,
g_layerVectors.gtflags,
g_layerVectors.temp,
g_layerVectors.tz,
g_layerVectors.radar
],
controls: g_mapControl,
loadTilesWhileInteracting: false,
loadTilesWhileAnimating: false,
view: g_mapView
});
mapDiv.addEventListener("mousemove", function (event)
{
onMouseUpdate(event);
var mousePosition = g_map.getEventPixel(event);
if (g_appSettings.mouseTrack == 1)
{
var mouseLngLat = g_map.getEventCoordinate(event);
if (mouseLngLat)
{
var LL = ol.proj.toLonLat(mouseLngLat);
var dist =
parseInt(
MyCircle.distance(
g_myLat,
g_myLon,
LL[1],
LL[0],
distanceUnit.value
) * MyCircle.validateRadius(distanceUnit.value)
) + distanceUnit.value.toLowerCase();
var azim =
parseInt(MyCircle.bearing(g_myLat, g_myLon, LL[1], LL[0])) + "&deg;";
var gg = latLonToGridSquare(LL[1], LL[0], (g_appSettings.sixWideMode == 1 ? 6 : 4));
mouseTrackDiv.innerHTML =
LL[1].toFixed(3) +
", " +
LL[0].toFixed(3) +
" " +
dist +
" " +
azim +
" " +
gg;
mouseTrackDiv.style.display = "block";
}
}
var noFeature = true;
var noFlag = true;
var noAward = true;
var noMoon = true;
var noTimeZone = true;
var noPark = true;
if (g_map.hasFeatureAtPixel(mousePosition))
{
var features = g_map.getFeaturesAtPixel(mousePosition);
if (features != null)
{
features = features.reverse();
var finalGridFeature = null;
for (var index in features)
{
if (features[index].geometryName_ == "tz")
{
features[index].size = 73;
}
if (typeof features[index].size == "undefined") continue;
if (features[index].size == 99 && finalGridFeature == null)
{
moonOver(features[index]);
noMoon = false;
break;
}
if (features[index].size == 2 && g_currentOverlay != 0)
{
trophyOver(features[index]);
noAward = false;
break;
}
if (features[index].size == 1)
{
mouseOverGtFlag(features[index]);
noFlag = false;
noFeature = true;
break;
}
if (features[index].size == 22)
{
mouseOverPark(features[index]);
noPark = false;
noFlag = true;
noFeature = true;
break;
}
if (features[index].size == 6)
{
noFeature = false;
finalGridFeature = features[index];
}
if (features[index].size == 4 && finalGridFeature == null)
{
noFeature = false;
finalGridFeature = features[index];
noFlag = true;
}
if (features[index].size == 73 && finalGridFeature == null)
{
mouseOverGtFlag(features[index]);
noFlag = false;
}
}
if (finalGridFeature)
{
mouseOverDataItem(finalGridFeature, true);
}
}
}
if (noFeature) mouseOutOfDataItem();
if (noFlag) mouseOutGtFlag();
if (noPark) mouseOutPark();
if (noAward) trophyOut();
if (noMoon) moonOut();
});
// mapDiv.addEventListener('mouseout', mapLoseFocus, false);
mapDiv.addEventListener("mouseleave", mapLoseFocus, false);
mapDiv.addEventListener("contextmenu", function (event)
{
event.preventDefault();
});
g_map.on("pointerdown", function (event)
{
var shouldReturn = false;
var features = g_map.getFeaturesAtPixel(event.pixel);
if (features != null)
{
features = features.reverse();
var finalGridFeature = null;
for (var index in features)
{
if (typeof features[index].size == "undefined") 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 (finalGridFeature)
{
onRightClickGridSquare(finalGridFeature);
shouldReturn = true;
}
}
if (shouldReturn) return true;
if (event.pointerEvent.buttons == 1 && event.pointerEvent.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(g_myLat, g_myLon, LL[1], LL[0]));
aimRotator(info);
}
if (event.pointerEvent.buttons == 2 && g_currentOverlay == 0)
{
mouseDownGrid(ol.proj.toLonLat(event.coordinate), event);
return true;
}
});
g_map.on("pointerup", function (event)
{
mouseUpGrid();
if (g_mapSettings.mouseOver == false) mouseOutOfDataItem();
});
document.getElementById("menuDiv").style.display = "block";
dayNight.init(g_map);
if (g_appSettings.earthImgSrc == 1)
{
dayNight.hide();
}
else
{
g_nightTime = dayNight.show();
}
moonLayer.init(g_map);
if (g_appSettings.moonTrack == 1)
{
moonLayer.show();
}
else
{
moonLayer.hide();
}
g_tileLayer.setOpacity(Number(g_mapSettings.loudness));
requestAnimationFrame(animatePaths);
nightMapEnable.checked = g_mapSettings.nightMapEnable;
changeNightMapEnable(nightMapEnable);
}
function changeNightMapEnable(check)
{
if (check.checked)
{
nightMapTd.style.display = "inline-table";
spotNightPathColorDiv.style.display = "inline-block";
g_mapSettings.nightMapEnable = true;
g_nightTime = dayNight.refresh();
}
else
{
nightMapTd.style.display = "none";
spotNightPathColorDiv.style.display = "none";
g_mapSettings.nightMapEnable = false;
}
changeMapLayer();
redrawSpots();
saveMapSettings();
}
var g_lasttimezone = null;
var g_nexradInterval = null;
var g_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()
{
g_nexradEnable ^= 1;
if (g_nexradEnable == 1)
{
if (g_Nexrad != null)
{
g_map.removeLayer(g_Nexrad);
}
g_Nexrad = createNexRad();
g_map.addLayer(g_Nexrad);
if (g_nexradInterval == null) { g_nexradInterval = nodeTimers.setInterval(nexradRefresh, 600000); }
}
else
{
if (g_nexradInterval != null)
{
nodeTimers.clearInterval(g_nexradInterval);
g_nexradInterval = null;
}
if (g_Nexrad)
{
g_map.removeLayer(g_Nexrad);
g_Nexrad = null;
}
}
g_mapSettings.usNexrad = g_nexradEnable == 1;
radarImg.style.filter = g_mapSettings.usNexrad ? "" : "grayscale(1)";
saveMapSettings();
}
function nexradRefresh()
{
if (g_Nexrad != null)
{
g_Nexrad.getSource().updateParams({ ol3_salt: Math.random() });
g_Nexrad.getSource().refresh();
}
}
function collapseMenu(shouldCollapse)
{
if (shouldCollapse == true)
{
g_menuShowing = false;
mapDiv.className = "mapDivStart";
menuDiv.className = "menuDivStart";
LegendDiv.className = "legendDivStart";
chevronDiv.className = "chevronDivEnd";
}
else
{
g_menuShowing = true;
chevronDiv.className = "chevronDivStart";
displayTime();
}
g_map.updateSize();
}
function mapLoseFocus()
{
mouseOutOfDataItem();
trophyOut();
mouseUpGrid();
moonOut();
mouseOutGtFlag();
mouseOutPark();
}
function lineString(points)
{
var thing = new ol.geom.LineString(points);
var rect = new ol.Feature({
geometry: thing
});
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({
name: "rect",
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({
name: "rect",
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()
{
g_appSettings.centerGridsquare = myDEGrid;
if (g_appSettings.centerGridsquare.length > 0)
{
homeQTHInput.value = g_appSettings.centerGridsquare;
}
var hash = myDEcall;
var rect = qthToBox(
myDEGrid,
myDEcall,
false,
true,
"",
myBand,
null,
hash
);
if (typeof rect != "undefined" && rect != null)
{
var push = false;
if (!(hash in g_liveCallsigns))
{
newCallsign = {};
push = true;
}
else newCallsign = g_liveCallsigns[hash];
newCallsign.DEcall = myDEcall;
newCallsign.grid = myDEGrid;
newCallsign.wspr = null;
newCallsign.msg = myDEGrid;
newCallsign.RSTsent = "-";
newCallsign.RSTrecv = "-";
newCallsign.time = timeNowSec();
newCallsign.delta = -1;
newCallsign.DXcall = "Self";
newCallsign.rect = rect;
newCallsign.mode = myMode;
newCallsign.band = 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;
g_myDXCC = newCallsign.dxcc = callsignToDxcc(myDEcall);
newCallsign.locked = true;
if (push) g_liveCallsigns[hash] = newCallsign;
}
}
var g_transmitFlightPath = null;
function haltAllTx(allTx = false)
{
for (var instance in g_instances)
{
if (instance != g_activeInstance || allTx == true)
{
var responseArray = Buffer.alloc(1024);
var length = 0;
var port = g_instances[instance].remote.port;
var address = g_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 g_callRoster && g_callRoster[thisCall].message.instance in g_instances)
{
if (g_mapSettings.focusRig && g_activeInstance != g_callRoster[thisCall].message.instance)
{
activeRig(g_callRoster[thisCall].message.instance);
}
if (g_mapSettings.haltAllOnTx)
{
haltAllTx();
}
var newMessage = g_callRoster[thisCall].message;
var responseArray = Buffer.alloc(1024);
var length = 0;
var instance = g_callRoster[thisCall].message.instance;
var port = g_instances[instance].remote.port;
var address = g_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 = g_receptionReports.spots[spot].call;
var grid = g_receptionReports.spots[spot].grid;
var band = g_receptionReports.spots[spot].band;
var mode = g_receptionReports.spots[spot].mode;
for (var instance in g_instances)
{
if (g_instances[instance].valid && g_instances[instance].status.Band == band && g_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 g_instances)
{
thisInstance = g_instances[instance].status;
port = g_instances[instance].remote.port;
address = g_instances[instance].remote.address;
}
else
{
alert("major instance error");
}
}
else
{
if (g_instances[g_activeInstance].valid)
{
thisInstance = g_instances[g_activeInstance].status;
port = g_instances[g_activeInstance].remote.port;
address = g_instances[g_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 g_liveCallsigns && g_liveCallsigns[hash].grid.length > 1) { grid = g_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("<font color='lightgreen'>Generated Msgs</font>");
}
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("<font color='yellow'>Transmit Enabled!</font><br/><font color='yellow'>Generate Msgs Aborted</font>");
}
}
var g_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
};
var g_oldQSOTimer = null;
function handleWsjtxADIF(newMessage)
{
if (g_oldQSOTimer)
{
nodeTimers.clearTimeout(g_oldQSOTimer);
g_oldQSOTimer = null;
}
sendToLogger(newMessage.ADIF);
}
function handleWsjtxQSO(newMessage)
{
if (g_oldQSOTimer)
{
nodeTimers.clearTimeout(g_oldQSOTimer);
g_oldQSOTimer = null;
}
g_oldStyleLogMessage = Object.assign({}, newMessage);
g_oldQSOTimer = nodeTimers.setTimeout(oldSendToLogger, 3000);
}
function handleWsjtxNotSupported(newMessage) { }
var g_lastBand = "";
var g_lastMode = "";
var g_lastRawGrid = "AA00AA";
var g_weAreDecoding = false;
var g_localDXcall = "";
var g_countIndex = 0;
var g_lastCountIndex = 0;
function rigChange(up)
{
if (g_activeInstance == "") return;
var targetInstance = 0;
if (up)
{
targetInstance = g_instances[g_activeInstance].intId + 1;
}
else
{
targetInstance = g_instances[g_activeInstance].intId - 1;
if (targetInstance < 0) targetInstance = g_instancesIndex.length - 1;
}
targetInstance %= g_instancesIndex.length;
setRig(targetInstance);
}
function setRig(instanceId)
{
if (g_instances[g_instancesIndex[instanceId]].valid)
{
if (g_lastMapView != null)
{
g_mapView.animate({ zoom: g_lastMapView.zoom, duration: 100 });
g_mapView.animate({ center: g_lastMapView.LoLa, duration: 100 });
g_lastMapView = null;
}
g_activeInstance = g_instancesIndex[instanceId];
handleWsjtxStatus(g_instances[g_activeInstance].status);
handleClosed(g_instances[g_activeInstance].status);
}
}
function activeRig(instance)
{
if (g_instances[instance].valid)
{
if (g_lastMapView != null)
{
g_mapView.animate({ zoom: g_lastMapView.zoom, duration: 100 });
g_mapView.animate({ center: g_lastMapView.LoLa, duration: 100 });
g_lastMapView = null;
}
g_activeInstance = instance;
handleWsjtxStatus(g_instances[g_activeInstance].status);
handleClosed(g_instances[g_activeInstance].status);
}
}
var g_lastTransmitCallsign = {};
var g_lastStatusCallsign = {};
var g_lastTxMessage = null;
function handleWsjtxStatus(newMessage)
{
if (g_ignoreMessages == 1) return;
if (g_rosterInitialized)
{
try
{
g_callRosterWindowHandle.window.processStatus(newMessage);
}
catch (e)
{
console.error(e);
}
}
if (g_activeInstance == "")
{
g_activeInstance = newMessage.instance;
}
if (Object.keys(g_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 g_lastTransmitCallsign)) { g_lastTransmitCallsign[newMessage.instance] = ""; }
if (!(newMessage.instance in g_lastStatusCallsign)) { g_lastStatusCallsign[newMessage.instance] = ""; }
if (lookupOnTx.checked == true && newMessage.Transmitting == 1 && g_lastTransmitCallsign[newMessage.instance] != DXcall)
{
openLookupWindow(true);
g_lastTransmitCallsign[newMessage.instance] = DXcall;
}
if (g_lastStatusCallsign[newMessage.instance] != DXcall)
{
g_lastStatusCallsign[newMessage.instance] = DXcall;
lookupCallsign(DXcall, newMessage.DXgrid.trim());
}
}
if (g_rosterInitialized && g_callRosterWindowHandle.window.g_rosterSettings.clearRosterOnBandChange && g_instances[newMessage.instance].oldStatus)
{
if (g_instances[newMessage.instance].oldStatus.Band != newMessage.Band || g_instances[newMessage.instance].oldStatus.MO != newMessage.MO)
{
for (const call in g_callRoster)
{
if (g_callRoster[call].callObj.instance == newMessage.instance) { delete g_callRoster[call]; }
}
if (g_activeInstance == newMessage.instance)
{
goProcessRoster();
}
}
}
if (g_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 = "<font color='orange'>" + newMessage.MO + "</font>";
myMode = newMessage.MO;
myBand = newMessage.Band;
if (g_lastBand != myBand)
{
g_lastBand = myBand;
bandChange = true;
if (g_pskBandActivityTimerHandle != null)
{
nodeTimers.clearInterval(g_pskBandActivityTimerHandle);
g_pskBandActivityTimerHandle = null;
}
}
if (g_lastMode != myMode)
{
g_lastMode = myMode;
modeChange = true;
if (g_pskBandActivityTimerHandle != null)
{
nodeTimers.clearInterval(g_pskBandActivityTimerHandle);
g_pskBandActivityTimerHandle = null;
}
}
if (g_pskBandActivityTimerHandle == null) pskGetBandActivity();
if (bandChange || modeChange)
{
removePaths();
goProcessRoster();
redrawGrids();
redrawSpots();
redrawParks();
redrawPins();
var msg = "<font color='yellow'>" + myBand + "</font> / <font color='orange'>" + myMode + "</font>";
addLastTraffic(msg);
ackAlerts();
updateChatWindow();
oamsBandActivityCheck();
g_gtLiveStatusUpdate = true;
}
myRawFreq = newMessage.Frequency;
frequency.innerHTML = "<font color='lightgreen'>" + Number(newMessage.Frequency / 1000).formatMhz(3, 3) + " Hz </font><font color='yellow'>(" + myBand + ")</font>";
myRawCall = newMessage.DEcall.trim();
myRawGrid = newMessage.DEgrid.trim().substr(0, 6);
var LL = squareToCenter(myRawGrid);
g_mapSettings.latitude = g_myLat = LL.a;
g_mapSettings.longitude = g_myLon = LL.o;
if (myRawGrid != g_lastRawGrid)
{
g_lastRawGrid = myRawGrid;
}
dxCallBoxDiv.className = "DXCallBox";
var hash = DXcall + myBand + myMode;
if (hash in g_tracker.worked.call)
{
dxCallBoxDiv.className = "DXCallBoxWorked";
}
if (hash in g_tracker.confirmed.call)
{
dxCallBoxDiv.className = "DXCallBoxConfirmed";
}
if (g_appSettings.clearOnCQ && newMessage.Transmitting == 1 && newMessage.TxMessage && g_lastTxMessage != newMessage.TxMessage)
{
g_lastTxMessage = newMessage.TxMessage;
if (newMessage.TxMessage.substring(0, 2) == "CQ" && DXcall.length > 0)
{
setCallAndGrid("", "", newMessage.instance, false);
DXcall = "";
newMessage.DXgrid = "";
}
}
g_localDXcall = DXcall;
localDXcall.innerHTML = DXcall.formatCallsign();
if (localDXcall.innerHTML.length == 0)
{
localDXcall.innerHTML = "-";
g_localDXcall = "";
}
localDXGrid.innerHTML = myDXGrid = newMessage.DXgrid.trim();
if (myDXGrid.length == 0 && hash in g_liveCallsigns)
{
localDXGrid.innerHTML = myDXGrid = g_liveCallsigns[hash].grid.substr(0, 4);
}
if (localDXGrid.innerHTML.length == 0)
{
localDXGrid.innerHTML = "-";
localDXDistance.innerHTML = "&nbsp;";
localDXAzimuth.innerHTML = "&nbsp;";
}
else
{
var LL = squareToCenter(myDXGrid);
localDXDistance.innerHTML = parseInt(MyCircle.distance(g_myLat, g_myLon, LL.a, LL.o, distanceUnit.value) * MyCircle.validateRadius(distanceUnit.value)) + distanceUnit.value.toLowerCase();
localDXAzimuth.innerHTML = parseInt(MyCircle.bearing(g_myLat, g_myLon, LL.a, LL.o)) + "&deg;";
}
if (localDXcall.innerHTML != "-")
{
localDXReport.innerHTML = Number(newMessage.Report.trim()).formatSignalReport();
if (DXcall.length > 0)
{
localDXCountry.innerHTML = g_dxccToAltName[callsignToDxcc(DXcall)];
}
else
{
localDXCountry.innerHTML = "&nbsp;";
}
}
else
{
localDXReport.innerHTML = localDXCountry.innerHTML = "";
}
myDEcall = newMessage.DEcall;
myDEGrid = newMessage.DEgrid.trim().substr(0, 6);
if (myDEGrid.length > 0) setHomeGridsquare();
if (myDEGrid.length > 0) g_appSettings.centerGridsquare = myDEGrid;
if (newMessage.Decoding == 1)
{
// Decoding
dimGridsquare();
fadePaths();
txrxdec.style.backgroundColor = "Blue";
txrxdec.style.borderColor = "Cyan";
txrxdec.innerHTML = "DECODE";
g_countIndex++;
g_weAreDecoding = true;
}
else
{
g_weAreDecoding = false;
if (g_countIndex != g_lastCountIndex)
{
g_lastCountIndex = g_countIndex;
updateCountStats();
if (bandChange || modeChange) reloadInfo(bandChange || modeChange);
var worker = "";
worker += "<div style='vertical-align:top;display:inline-block;margin-right:8px;'>";
worker += "<table class='darkTable' align=center>";
worker += "<tr><th colspan=7>Last " + g_lastMessages.length + " Decoded Messages</th></tr>";
worker += "<tr><th>Time</th><th>dB</th><th>DT</th><th>Freq</th><th>Mode</th><th>Message</th><th>DXCC</th></tr>";
worker += g_lastMessages.join("");
worker += "</table></div>";
setStatsDiv("decodeLastListDiv", worker);
setStatsDivHeight("decodeLastListDiv", getStatsWindowHeight() + 26 + "px");
if (g_appSettings.gtShareEnable === true && Object.keys(g_spotCollector).length > 0)
{
gtChatSendSpots(g_spotCollector, g_spotDetailsCollector);
g_spotCollector = {};
g_spotDetailsCollector = {};
}
}
txrxdec.style.backgroundColor = "Green";
txrxdec.style.borderColor = "GreenYellow";
txrxdec.innerHTML = "RECEIVE";
}
if (newMessage.TxEnabled)
{
if (g_mapSettings.fitQRZ && (g_spotView == 0 || g_receptionSettings.mergeSpots))
{
if (g_lastMapView == null)
{
g_lastMapView = {};
g_lastMapView.LoLa = g_mapView.getCenter();
g_lastMapView.zoom = g_mapView.getZoom();
}
if (myDXGrid.length > 0)
{
fitViewBetweenPoints([getPoint(myRawGrid), getPoint(myDXGrid)]);
}
else if (g_mapSettings.qrzDxccFallback && DXcall.length > 0 && callsignToDxcc(DXcall) > 0)
{
var dxcc = callsignToDxcc(DXcall);
var Lat = g_dxccInfo[dxcc].lat;
var Lon = g_dxccInfo[dxcc].lon;
fitViewBetweenPoints([getPoint(myRawGrid), ol.proj.fromLonLat([Lon, Lat])], 15);
}
}
}
else
{
if (g_lastMapView != null)
{
g_mapView.animate({ zoom: g_lastMapView.zoom, duration: 1200 });
g_mapView.animate({ center: g_lastMapView.LoLa, duration: 1200 });
g_lastMapView = null;
}
}
if (newMessage.Transmitting == 0)
{
// Not Transmitting
g_lastTxMessage = null;
g_layerSources.transmit.clear();
g_transmitFlightPath = null;
}
else
{
g_lastTrasmissionTimeSec = g_timeNow;
txrxdec.style.backgroundColor = "Red";
txrxdec.style.borderColor = "Orange";
txrxdec.innerHTML = "TRANSMIT";
g_layerSources.transmit.clear();
g_transmitFlightPath = null;
if (qrzPathWidthValue.value != 0 && g_appSettings.gridViewMode != 2 && validateGridFromString(myRawGrid))
{
var strokeColor = getQrzPathColor();
var strokeWeight = qrzPathWidthValue.value;
var LL = squareToCenter(myRawGrid);
var fromPoint = ol.proj.fromLonLat([LL.o, LL.a]);
var toPoint = null;
if (validateGridFromString(myDXGrid))
{
LL = squareToCenter(myDXGrid);
toPoint = ol.proj.fromLonLat([LL.o, LL.a]);
}
else if (g_mapSettings.qrzDxccFallback && DXcall.length > 0 && callsignToDxcc(DXcall) > 0)
{
var dxcc = callsignToDxcc(DXcall);
toPoint = ol.proj.fromLonLat([g_dxccInfo[dxcc].lon, g_dxccInfo[dxcc].lat]);
var locality = g_dxccInfo[dxcc].geo;
if (locality == "deleted") locality = null;
if (locality != null)
{
var feature = shapeFeature("qrz", locality, "qrz", "#FFFF0010", "#FF0000FF", 1.0);
g_layerSources.transmit.addFeature(feature);
}
}
if (toPoint)
{
try
{
g_transmitFlightPath = flightFeature(
[fromPoint, toPoint],
{
weight: strokeWeight,
color: strokeColor,
steps: 75,
zIndex: 90
},
"transmit",
true
);
}
catch (err)
{
console.error("Unexpected error inside handleWsjtxStatus", err)
}
}
}
g_weAreDecoding = false;
}
g_appSettings.myDEcall = myDEcall;
g_appSettings.myDEGrid = myDEGrid;
g_appSettings.myMode = myMode;
g_appSettings.myBand = myBand;
g_appSettings.myRawFreq = myRawFreq;
g_appSettings.myRawCall = myRawCall;
g_appSettings.myRawGrid = myRawGrid;
}
if (newMessage.Decoding == 0)
{
goProcessRoster();
processClassicAlerts();
}
}
function reportDecodes()
{
if (Object.keys(g_decodeCollector).length > 0)
{
gtChatSendDecodes(g_decodeCollector);
g_decodeCollector = {};
}
}
var g_lastMapView = null;
function drawTraffic()
{
while (g_lastTraffic.length > 60) g_lastTraffic.pop();
var worker = g_lastTraffic.join("<br/>");
worker = worker.split("80%'><br/>").join("80%'>");
if (g_localDXcall.length > 1)
{
worker = worker
.split(g_localDXcall)
.join("<font style='color:cyan'>" + g_localDXcall + "</font>");
}
if (myRawCall.length > 1)
{
worker = worker
.split(myRawCall)
.join("<font style='color:yellow'>" + myRawCall + "</font>");
}
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();
g_mapView.fit(extent, {
duration: 500,
maxZoom: maxZoom,
padding: [75, 75, 75, 75]
});
}
var g_spotCollector = {};
var g_spotDetailsCollector = {};
var g_decodeCollector = {};
function handleWsjtxDecode(newMessage)
{
if (g_ignoreMessages == 1 || g_map == null) return;
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 = Number((newMessage.OF + newMessage.DF) / 1000).formatMhz(3, 3);
}
else
{
newF = newMessage.DF;
}
var theTimeStamp = timeNowSec() - (timeNowSec() % 86400) + parseInt(newMessage.TM / 1000);
// Break up the decoded message
var decodeWords = newMessage.Msg.split(" ").slice(0, 5);
while (decodeWords[decodeWords.length - 1] == "") decodeWords.pop();
if (decodeWords.length > 1 && newMessage.Msg.indexOf("<...>") == -1)
{
if (newMessage.Msg.indexOf("<") != -1)
{
for (const i in decodeWords)
{
decodeWords[i] = decodeWords[i].replace("<", "").replace(">", "");
}
}
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 == 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 g_liveCallsigns) callsign = g_liveCallsigns[hash];
var canPath = false;
if (
(g_appSettings.gtBandFilter.length == 0 ||
(g_appSettings.gtBandFilter == "auto" && newMessage.OB == myBand) ||
newMessage.OB == g_appSettings.gtBandFilter) &&
(g_appSettings.gtModeFilter.length == 0 ||
(g_appSettings.gtModeFilter == "auto" && newMessage.OM == myMode) ||
newMessage.OM == g_appSettings.gtModeFilter ||
g_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)
{
g_liveGrids[theirQTH].age = g_timeNow;
}
if (callsign == null)
{
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 = g_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 (g_callsignLookups.ulsUseEnable == true && isKnownCallsignDXCC(newCallsign.dxcc))
{
lookupUsCallsign(newCallsign, false);
}
if (newCallsign.dxcc in g_dxccCount) g_dxccCount[newCallsign.dxcc]++;
else g_dxccCount[newCallsign.dxcc] = 1;
newCallsign.alerted = false;
newCallsign.shouldAlert = false;
g_liveCallsigns[hash] = newCallsign;
callsign = newCallsign;
}
else
{
if (validQTH)
{
callsign.grid = theirQTH;
if (rect != null && callsign.grid != rect.qth)
{
if (
(g_appSettings.gtBandFilter.length == 0 ||
(g_appSettings.gtBandFilter == "auto" &&
newMessage.OB == myBand) ||
newMessage.OB == g_appSettings.gtBandFilter) &&
(g_appSettings.gtModeFilter.length == 0 ||
(g_appSettings.gtModeFilter == "auto" &&
newMessage.OM == myMode) ||
newMessage.OM == g_appSettings.gtModeFilter ||
g_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.qrz = (msgDXcallsign == myDEcall);
if (callsign.grid.length > 0 && callsign.distance == 0)
{
var LL = squareToCenter(callsign.grid);
callsign.distance = MyCircle.distance(g_myLat, g_myLon, LL.a, LL.o, distanceUnit.value);
callsign.heading = MyCircle.bearing(g_myLat, g_myLon, LL.a, LL.o);
}
if (g_appSettings.potaEnabled == 1)
{
callsign.pota = null;
if (callsign.DEcall in g_pota.callSpots || callsign.DEcall in g_pota.callSchedule)
{
var now = Date.now();
if (callsign.DEcall in g_pota.callSpots)
{
if (g_pota.callSpots[callsign.DEcall] in g_pota.parkSpots && g_pota.parkSpots[g_pota.callSpots[callsign.DEcall]][callsign.DEcall].expire > now)
{
callsign.pota = g_pota.callSpots[callsign.DEcall];
}
}
else if (callsign.DEcall in g_pota.callSchedule)
{
for (var i in g_pota.callSchedule[callsign.DEcall])
{
if (now < g_pota.callSchedule[callsign.DEcall][i].end && now >= g_pota.callSchedule[callsign.DEcall][i].start)
{
callsign.pota = g_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,
newMessage.Msg.substr(0, 30).trim(),
callsign.band,
callsign.mode
);
didAlert = checkClassicAlerts(CQ, callsign, newMessage, msgDXcallsign);
insertMessageInRoster(
newMessage,
msgDEcallsign,
msgDXcallsign,
callsign,
hash
);
if (
g_mapSettings.trafficDecode &&
(didAlert == true || didCustomAlert == true)
)
{
var traffic = htmlEntities(newMessage.Msg);
if (didAlert == true)
{
traffic = "⚠️ " + traffic;
}
if (didCustomAlert == true)
{
traffic = traffic + " 🚩";
}
g_lastTraffic.unshift(traffic);
g_lastTraffic.unshift(userTimeString(null));
g_lastTraffic.unshift("<hr style='border-color:#333;margin-top:0px;margin-bottom:2px;width:80%'>");
drawTraffic();
lastMessageWasInfo = true;
}
if (g_appSettings.gtSpotEnable == true && newMessage.OF > 0)
{
let freq = callsign.delta + newMessage.OF;
if (callsign.DEcall in g_gtCallsigns)
{
for (const cid in g_gtCallsigns[callsign.DEcall])
{
if (cid in g_gtFlagPins && g_gtFlagPins[cid].o == 1)
{
g_spotCollector[cid] = callsign.RSTsent;
g_spotDetailsCollector[cid] = [freq, callsign.mode];
}
}
}
freq = freq - (freq % k_frequencyBucket);
g_decodeCollector[freq] ??= 0;
g_decodeCollector[freq]++;
}
}
if (callsign.dxcc != -1) countryName = g_dxccToAltName[callsign.dxcc];
if (canPath == true)
{
if (callsign.DXcall.indexOf("CQ") < 0 && g_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 g_liveCallsigns)
{
DEcallsign = g_liveCallsigns[callsign.DXcall + newMessage.OB + newMessage.OM];
}
else if (callsign.DXcall in g_liveCallsigns)
{
DEcallsign = g_liveCallsigns[callsign.DXcall];
}
if (DEcallsign != null && DEcallsign.grid != "")
{
var strokeColor = getPathColor();
var strokeWeight = pathWidthValue.value;
var flightPath = null;
var isQRZ = false;
if (msgDXcallsign == myDEcall)
{
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 = g_timeNow + g_flightDuration;
flightPath.isShapeFlight = 0;
flightPath.isQRZ = isQRZ;
g_flightPaths.push(flightPath);
}
catch (err)
{
console.error("Unexpected error inside handleWsjtxDecode 1", err)
}
}
}
}
else if (g_mapSettings.qrzDxccFallback && msgDXcallsign == myDEcall && 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 = g_liveCallsigns[myDEcall];
if (strokeWeight != 0)
{
var toPoint = getPoint(DEcallsign.grid);
var Lat = g_dxccInfo[callsign.dxcc].lat;
var Lon = g_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 = g_timeNow + g_flightDuration;
flightPath.isShapeFlight = 0;
flightPath.isQRZ = isQRZ;
g_flightPaths.push(flightPath);
}
catch (err)
{
console.error("Unexpected error inside handleWsjtxDecode 2", err)
}
var feature = shapeFeature(
"qrz",
g_dxccInfo[callsign.dxcc].geo,
"qrz",
"#FFFF0010",
"#FF0000FF",
1.0
);
feature.age = g_timeNow + g_flightDuration;
feature.isShapeFlight = 1;
feature.isQRZ = isQRZ;
g_layerSources.flight.addFeature(feature);
g_flightPaths.push(feature);
}
}
}
else if (g_mapSettings.CQhilite && msgDXcallsign.indexOf("CQ ") == 0 && callsign.grid != "" && g_appSettings.gridViewMode != 2 && pathWidthValue.value != 0)
{
var CCd = msgDXcallsign.replace("CQ ", "").split(" ")[0];
if (CCd.length < 5 && !(CCd in g_pathIgnore))
{
var locality = null;
// Direct lookup US states, Continents, possibly
if (CCd in g_replaceCQ) CCd = g_replaceCQ[CCd];
if (CCd.length == 2 && CCd in g_shapeData)
{
locality = g_shapeData[CCd];
}
else if (CCd.length == 3)
{
// maybe it's DEL, or WYO. check the first two letters
if (CCd.substr(0, 2) in g_shapeData) { locality = g_shapeData[CCd.substr(0, 2)]; }
}
if (locality == null)
{
// Check the prefix for dxcc direct
if (CCd in g_prefixToMap)
{
locality = g_dxccInfo[g_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 = g_timeNow + g_flightDuration;
feature.isShapeFlight = 1;
feature.isQRZ = false;
g_layerSources.flight.addFeature(feature);
g_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 = g_timeNow + g_flightDuration;
flightPath.isShapeFlight = 0;
flightPath.isQRZ = false;
g_flightPaths.push(flightPath);
}
catch (err)
{
console.error("Unexpected error inside handleWsjtxDecode 3", err)
}
}
}
}
}
}
var bgColor = "black";
if (newMessage.LC > 0) bgColor = "#880000";
g_lastMessages.unshift(
"<tr style='background-color:" +
bgColor +
"'><td style='color:lightblue'>" +
userTimeString(theTimeStamp * 1000) +
"</td><td style='color:orange'>" +
newMessage.SR +
"</td><td style='color:gray'>" +
newMessage.DT.toFixed(1) +
"</td><td style='color:lightgreen'>" +
newF +
"</td><td>" +
newMessage.MO +
"</td><td style='color:" +
(CQ ? "cyan" : "white") +
"'>" +
htmlEntities(newMessage.Msg) +
"</td><td style='color:yellow'>" +
countryName +
"</td></tr>"
);
while (g_lastMessages.length > 100) g_lastMessages.pop();
}
function addLastTraffic(traffic)
{
g_lastTraffic.unshift(traffic);
g_lastTraffic.unshift(
"<hr style='border-color:#333;margin-top:0px;margin-bottom:2px;width:80%'>"
);
drawTraffic();
}
function htmlEntities(str)
{
return String(str)
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;");
}
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 g_liveCallsigns)
{
if (g_liveCallsigns[hash].instance == newMessage.instance || g_liveCallsigns[hash].mode == g_instances[newMessage.instance].status.MO)
{
delete g_liveCallsigns[hash];
}
}
for (var call in g_callRoster)
{
if (g_callRoster[call].callObj.instance == newMessage.instance) { delete g_callRoster[call]; }
}
redrawGrids();
redrawPins();
updateCountStats();
goProcessRoster();
}
function goProcessRoster()
{
var now = timeNowSec();
for (const call in g_callRoster)
{
if (now - g_callRoster[call].callObj.age > 300)
{
g_callRoster[call].callObj.alerted = false;
g_callRoster[call].callObj.shouldAlert = false;
delete g_callRoster[call];
continue;
}
}
if (g_rosterInitialized)
{
try
{
g_callRosterWindowHandle.window.processRoster(g_callRoster);
}
catch (e)
{
console.log("Call Roster exception");
console.log(e.message);
}
}
}
function handleClosed(newMessage)
{
if (g_activeInstance == newMessage.Id && g_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();
g_instances[newMessage.Id].open = false;
handleClosed(newMessage);
updateRosterInstances();
}
function handleWsjtxWSPR(newMessage)
{
if (g_ignoreMessages == 1) return;
addDeDx(
newMessage.Grid,
newMessage.Callsign,
"-",
Number(newMessage.SR),
timeNowSec(),
"Pwr:" + newMessage.Power + " Freq:" + Number(newMessage.Frequency / 1000).formatMhz(3, 3) + " Delta:" + Number(newMessage.DT).toFixed(2) + " Drift:" +
newMessage.Drift,
"WSPR",
Number(newMessage.Frequency / 1000000).formatBand(),
false,
false,
null,
callsignToDxcc(newMessage.Callsign),
null,
null,
null,
"",
""
);
processAlertMessage(newMessage.Callsign.trim() + " " + newMessage.Grid);
updateCountStats();
}
function centerOn(grid)
{
if (grid.length >= 4)
{
var LL = squareToLatLong(grid);
g_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)
{
g_appSettings.centerGridsquare = homeQTHInput.value;
// Grab home QTH Gridsquare from Center QTH
var LL = squareToLatLong(homeQTHInput.value);
g_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 (g_mapMemory[6].zoom != -1)
{
mapMemory(6, false);
return;
}
setCenterQTH();
}
function changeLookupMerge()
{
g_appSettings.lookupMerge = lookupMerge.checked;
g_appSettings.lookupMissingGrid = lookupMissingGrid.checked;
if (g_appSettings.lookupMerge == true)
{
lookupMissingGridDiv.style.display = "inline-block";
}
else
{
lookupMissingGridDiv.style.display = "none";
}
}
function changelookupOnTx()
{
g_appSettings.lookupOnTx = lookupOnTx.checked;
g_appSettings.lookupCloseLog = lookupCloseLog.checked;
}
function exportSettings()
{
var filename = g_appData + g_dirSeperator + "gt_settings.json";
var toWrite = JSON.stringify(localStorage);
fs.writeFileSync(filename, toWrite);
checkForSettings();
}
function checkForSettings()
{
var filename = g_appData + g_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 = g_appData + g_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 =
"<font style='color:red'>Settings File Corrupt!</font>";
}
else if (data.currentVersion != localStorage.currentVersion)
{
importSettingsFile.innerHTML =
"<font style='color:red'>Settings Version Mismatch!</font>";
}
}
}
}
function showCallsignBox(redraw)
{
var worker =
"<div style='vertical-align:top;display:inline-block;margin:2px;color:cyan;font-weight:bold'>Callsigns and DXCC Heard</div><br/>";
g_newCallsignCount = Object.keys(g_liveCallsigns).length;
if (g_newCallsignCount > 0)
{
var newCallList = Array();
worker +=
"<div style='display:inline-block;padding-right:8px;overflow:auto;overflow-x:hidden;height:" +
Math.min(g_newCallsignCount * 24 + 26, getStatsWindowHeight()) +
"px;'><table class='darkTable' align=center><th align=left>Callsign</th><th align=left>Grid</th><th>DXCC</th><th>CQ</th><th>ITU</th><th>Flag</th><th align=left>QSO</th><th>QSL</th><th>When</th>"; // <th>ITUz</th><th>CQz</th><th>ISO</th>";
if (g_callsignLookups.lotwUseEnable == true) worker += "<th>LoTW</th>";
if (g_callsignLookups.eqslUseEnable == true) worker += "<th>eQSL</th>";
if (g_callsignLookups.oqrsUseEnable == true) worker += "<th>OQRS</th>";
for (var x in g_liveCallsigns)
{
if (g_liveCallsigns[x].dxcc != -1)
{
newCallList.push(g_liveCallsigns[x]);
}
}
newCallList.sort(compareCallsignTime).reverse();
for (var x in newCallList)
{
if (newCallList[x].DEcall == 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 = g_dxccInfo[newCallList[x].dxcc];
var thisCall = newCallList[x].DEcall.formatCallsign();
worker +=
"<tr><td align=left style='color:#ff0;cursor:pointer' onClick='window.opener.startLookup(\"" +
newCallList[x].DEcall +
"\",\"" +
grid +
"\");'>" +
thisCall +
"</td><td align=left style='color:cyan;' >" +
grid +
"</td><td style='color:orange;'>" +
geo.name +
"<font style='color:lightgreen;'> (" +
geo.pp +
")<font></td>";
worker += "<td>" + cqzone + "</td><td>" + ituzone + "</td>";
worker +=
"<td align='center' style='margin:0;padding:0'><img style='padding-top:4px' src='./img/flags/16/" +
geo.flag +
"'></td>";
worker +=
"<td>" +
(thisCall in g_tracker.worked.call ? "&#10004;" : "") +
"</td><td>" +
(thisCall in g_tracker.confirmed.call ? "&#10004;" : "") +
"</td>";
var ageString = "";
if (timeNowSec() - newCallList[x].time < 3601) { ageString = (timeNowSec() - newCallList[x].time).toDHMS(); }
else
{
ageString = userTimeString(newCallList[x].time * 1000);
}
worker += "<td>" + ageString + "</td>";
if (g_callsignLookups.lotwUseEnable == true)
{
worker +=
"<td align='center'>" +
(thisCall in g_lotwCallsigns ? "&#10004;" : "") +
"</td>";
}
if (g_callsignLookups.eqslUseEnable == true)
{
worker +=
"<td align='center'>" +
(thisCall in g_eqslCallsigns ? "&#10004;" : "") +
"</td>";
}
if (g_callsignLookups.oqrsUseEnable == true)
{
worker +=
"<td align='center'>" +
(thisCall in g_oqrsCallsigns ? "&#10004;" : "") +
"</td>";
}
worker += "</tr>";
}
worker += "</table></div>";
}
var heard = 0;
var List = {};
if (Object.keys(g_dxccCount).length > 0)
{
for (var key in g_dxccCount)
{
if (key != -1)
{
var item = {};
item.total = g_dxccCount[key];
item.confirmed = g_dxccInfo[key].confirmed;
item.worked = g_dxccInfo[key].worked;
item.dxcc = key;
item.flag = g_dxccInfo[key].flag;
List[g_dxccToAltName[key]] = item;
heard++;
}
}
worker +=
"<div style='vertical-align:top;display:inline-block;margin-right:2px;overflow:auto;overflow-x:hidden;height:" +
Math.min(
Object.keys(g_dxccCount).length * 23 + 45,
getStatsWindowHeight()
) +
"px;'><table class='darkTable' align=center><tr><th colspan=4 style='font-weight:bold'>DXCC (" +
heard +
")</th><tr><th align=left>Name</th><th>Flag</th><th align=left>Calls</th></tr>";
Object.keys(List)
.sort()
.forEach(function (key, i)
{
worker += "<tr><td align=left style='color:#ff0;' >" + key + "</td>";
worker +=
"<td align='center' style='margin:0;padding:0'><img style='padding-top:3px' src='./img/flags/16/" +
List[key].flag +
"'></td>";
worker +=
"<td align=left style='color:lightblue;' >" +
List[key].total +
"</td>";
worker += "</tr>";
});
worker += "</table></div>";
}
worker += "</div>";
setStatsDiv("callsignListDiv", worker);
}
function setStatsDiv(div, worker)
{
if (
g_statsWindowHandle != null &&
typeof g_statsWindowHandle.window[div] !== "undefined"
)
{
g_statsWindowHandle.window[div].innerHTML = worker;
}
}
function setStatsDivHeight(div, heightWithPx)
{
if (
g_statsWindowHandle != null &&
typeof g_statsWindowHandle.window[div] !== "undefined"
)
{
g_statsWindowHandle.window[div].style.height = heightWithPx;
}
}
function getStatsWindowHeight()
{
if (
g_statsWindowHandle != null &&
typeof g_statsWindowHandle.window.window !== "undefined"
)
{
return g_statsWindowHandle.window.window.innerHeight - 63;
}
return 300;
}
function setLookupDiv(div, worker)
{
if (
g_lookupWindowHandle && g_lookupWindowInitialized &&
typeof g_lookupWindowHandle.window[div].innerHTML !== "undefined"
)
{
g_lookupWindowHandle.window[div].innerHTML = worker;
}
}
function setLookupDivHeight(div, heightWithPx)
{
if (
g_lookupWindowHandle && g_lookupWindowInitialized &&
typeof g_lookupWindowHandle.window[div].style !== "undefined"
)
{
g_lookupWindowHandle.window[div].style.height = heightWithPx;
}
}
function getLookupWindowHeight()
{
if (
g_lookupWindowHandle && g_lookupWindowInitialized &&
typeof g_lookupWindowHandle.window.window !== "undefined"
)
{
return g_lookupWindowHandle.window.window.innerHeight;
}
return 300;
}
function showConditionsBox()
{
if (g_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 g_dxccToAltName[a.dxcc].localeCompare(g_dxccToAltName[b.dxcc]);
}
function myDxccIntCompare(a, b)
{
if (!(a in g_dxccToAltName)) return 0;
if (!(b in g_dxccToAltName)) { return g_dxccToAltName[a].localeCompare(g_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;
}
var g_sortFunction = [
myCallCompare,
myGridCompare,
myModeCompare,
myDxccCompare,
myTimeCompare,
myBandCompare,
myConfirmedCompare
];
var g_lastSortIndex = 4;
var g_qsoPages = 1;
var g_qsoPage = 0;
var g_qsoItemsPerPage = 100;
var g_lastSortType = 0;
var g_searchWB = "";
var g_gridSearch = "";
var g_filterBand = "Mixed";
var g_filterMode = "Mixed";
var g_filterDxcc = 0;
var g_filterQSL = "All";
var g_lastSearchSelection = null;
function resetSearch()
{
g_lastSortIndex = 4;
g_qsoPages = 1;
g_qsoPage = 0;
g_qsoItemsPerPage = 100;
g_lastSortType = 2;
g_searchWB = "";
g_gridSearch = "";
g_filterBand = "Mixed";
g_filterMode = "Mixed";
g_filterDxcc = 0;
g_filterQSL = "All";
g_lastSearchSelection = null;
}
function showWorkedByCall(callsign, evt)
{
evt.preventDefault();
resetSearch();
g_searchWB = callsign;
if (event.shiftKey == true) g_filterQSL = "true";
openInfoTab("qsobox", "workedBoxDiv", showWorkedBox);
}
function showWorkedSearchChanged(object, index)
{
ValidateCallsign(object, null);
g_searchWB = object.value.toUpperCase();
g_lastSearchSelection = object.id;
showWorkedBox(index, 0);
}
function showWorkedSearchGrid(object, index)
{
ValidateCallsign(object, null);
g_gridSearch = object.value.toUpperCase();
g_lastSearchSelection = object.id;
showWorkedBox(index, 0);
}
function filterBandFunction(event, index)
{
g_filterBand = this.value;
g_lastSearchSelection = this.id;
showWorkedBox(index, 0);
}
function filterModeFunction(event, index)
{
g_filterMode = this.value;
g_lastSearchSelection = this.id;
showWorkedBox(index, 0);
}
function filterDxccFunction(event, index)
{
g_filterDxcc = this.value;
g_lastSearchSelection = this.id;
showWorkedBox(index, 0);
}
function filterQSLFunction(event, index)
{
g_filterQSL = this.value;
g_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 = g_QSOhash;
if (sortIndex == null || typeof sortIndex == "undefined")
{
mySort = 4;
g_lastSortIndex = 4;
g_lastSortType = 2;
}
var list = Object.values(myObjects);
if (g_searchWB.length > 0)
{
list = list.filter(function (value)
{
return value.DEcall.indexOf(g_searchWB) > -1;
});
}
if (g_gridSearch.length > 0)
{
list = list.filter(function (value)
{
var x = value.grid.indexOf(g_gridSearch);
var y = value.vucc_grids.indexOf(g_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 (
g_unconfirmedCalls.has(unconfirmedCallsKey.key) &&
list[key].confirmed
)
{
g_unconfirmedCalls.set(unconfirmedCallsKey.key, 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
g_unconfirmedCalls.get(unconfirmedCallsKey.key) != unconfirmedCallsSentinel
)
{
var logs = g_unconfirmedCalls.get(unconfirmedCallsKey.key);
if (logs == undefined)
{
logs = new Set();
logs.add(list[key]);
g_unconfirmedCalls.set(unconfirmedCallsKey.key, logs);
}
else if (!logs.has(list[key]))
{
logs.add(list[key]);
}
}
var pp = list[key].dxcc in g_dxccInfo ? g_dxccInfo[list[key].dxcc].pp : "?";
dxccs[g_dxccToAltName[list[key].dxcc] + " (" + pp + ")"] = list[key].dxcc;
}
if (g_filterBand != "Mixed")
{
list = list.filter(function (value)
{
return value.band == g_filterBand;
});
}
if (g_filterMode != "Mixed")
{
list = list.filter(function (value)
{
if (
g_filterMode == "Phone" &&
value.mode in g_modes_phone &&
g_modes_phone[value.mode]
) { return true; }
if (
g_filterMode == "Digital" &&
value.mode in g_modes &&
g_modes[value.mode]
) { return true; }
return value.mode == g_filterMode;
});
}
if (g_filterDxcc != 0)
{
list = list.filter(function (value)
{
return value.dxcc == g_filterDxcc;
});
}
if (g_filterQSL != "All")
{
list = list.filter(function (value)
{
return value.confirmed == (g_filterQSL == "true");
});
}
if (typeof redraw == "undefined")
{
if (typeof nextPage == "undefined")
{
nextPage = 0;
if (g_lastSortIndex != mySort)
{
list = list.sort(g_sortFunction[mySort]);
g_lastSortIndex = mySort;
g_lastSortType = 1;
g_qsoPage = 0;
}
else
{
list = list.sort(g_sortFunction[mySort]).reverse();
g_lastSortIndex = -1;
g_lastSortType = 2;
g_qsoPage = 0;
}
}
else
{
if (g_lastSortType == 1)
{
list = list.sort(g_sortFunction[mySort]);
}
else
{
list = list.sort(g_sortFunction[mySort]).reverse();
}
}
}
else
{
mySort = g_lastSortIndex;
if (mySort == -1) mySort = 4;
if (g_lastSortType == 1)
{
list = list.sort(g_sortFunction[mySort]);
}
else
{
list = list.sort(g_sortFunction[mySort]).reverse();
}
}
ObjectCount = list.length;
var g_qsoPages = parseInt(ObjectCount / g_qsoItemsPerPage) + 1;
g_qsoPage += nextPage;
g_qsoPage %= g_qsoPages;
if (g_qsoPage < 0) g_qsoPage = g_qsoPages - 1;
var startIndex = g_qsoPage * g_qsoItemsPerPage;
var endIndex = startIndex + g_qsoItemsPerPage;
if (endIndex > ObjectCount) endIndex = ObjectCount;
var workHead = "<b> Entries (" + ObjectCount + ")</b>";
if (g_qsoPages > 1)
{
workHead +=
"<br/><font style='font-size:15px;' color='cyan' onClick='window.opener.showWorkedBox(" +
mySort +
", -1);'>&#8678;&nbsp;</font>";
workHead +=
" Page " +
(g_qsoPage + 1) +
" of " +
g_qsoPages +
" (" +
(endIndex - startIndex) +
") ";
workHead +=
"<font style='font-size:16px;' color='cyan' onClick='window.opener.showWorkedBox(" +
mySort +
", 1);'>&nbsp;&#8680;</font>";
}
setStatsDiv("workedHeadDiv", workHead);
if (myObjects != null)
{
var worker = "";
worker +=
"<table id='logTable' style='white-space:nowrap;overflow:auto;overflow-x;hidden;' class='darkTable' align=center>";
worker += "<tr><th><input type='text' id='searchWB' style='margin:0px' class='inputTextValue' value='" + g_searchWB + "' size='8' oninput='window.opener.showWorkedSearchChanged(this);' / >";
if (g_searchWB.length > 0)
{
worker += "<img title='Clear Callsign' onclick='searchWB.value=\"\";window.opener.showWorkedSearchChanged(searchWB);' src='/img/trash_24x48.png' style='width: 30px; margin:0px; padding:0px; margin-bottom: -4px; cursor: pointer;'/>";
}
worker += "</th>";
worker += "<th><input type='text' id='searchGrid' style='margin:0px' class='inputTextValue' value='" + g_gridSearch + "' size='6' oninput='window.opener.showWorkedSearchGrid(this);' / >";
if (g_gridSearch.length > 0)
{
worker += "<img title='Clear Grid' onclick='searchGrid.value=\"\";window.opener.showWorkedSearchGrid(searchGrid);' src='/img/trash_24x48.png' style='width: 30px; margin:0px; padding:0px; margin-bottom: -4px; cursor: pointer;'/>";
}
worker += "</th>";
worker += "<th><div id='bandFilterDiv'></div></th>";
worker += "<th><div id='modeFilterDiv'></div></th>";
worker += "<th><div id='qslFilterDiv'></div></th>";
worker += "<th></th>";
worker += "<th></th>";
worker += "<th colspan=2><div id='dxccFilterDiv'></div></th>";
worker += "</tr> ";
worker += "<tr><th style='cursor:pointer;' align=center onclick='window.opener.showWorkedBox(0);'>Station</th>";
worker += "<th style='cursor:pointer;' align=center onclick='window.opener.showWorkedBox(1);'>Grid</th>";
worker += "<th style='cursor:pointer;' align=center onclick='window.opener.showWorkedBox(5);'>Band</th>";
worker += "<th style='cursor:pointer;' align=center onclick='window.opener.showWorkedBox(2);'>Mode</th>";
worker += "<th style='cursor:pointer;' align=center onclick='window.opener.showWorkedBox(6);'>QSL</th>";
worker += "<th align=center>Sent</th>";
worker += "<th align=center>Rcvd</th>";
worker += "<th style='cursor:pointer;' align=center onclick='window.opener.showWorkedBox(3);'>DXCC</th>";
worker += "<th style='cursor:pointer;' align=center onclick='window.opener.showWorkedBox(3);'>Flag</th>";
worker += "<th style='cursor:pointer;' align=center onclick='window.opener.showWorkedBox(4);'>When</th>";
if (g_callsignLookups.lotwUseEnable == true) worker += "<th>LoTW</th>";
if (g_callsignLookups.eqslUseEnable == true) worker += "<th>eQSL</th>";
if (g_callsignLookups.oqrsUseEnable == true) worker += "<th>OQRS</th>";
worker += "</tr>";
var key = null;
for (var i = startIndex; i < endIndex; i++)
{
key = list[i];
worker +=
"<tr align=left><td style='color:#ff0;cursor:pointer' onclick='window.opener.startLookup(\"" +
key.DEcall +
"\",\"" +
key.grid +
"\");' >" +
key.DEcall.formatCallsign() +
"</td>";
worker +=
"<td style='color:cyan;' >" +
key.grid +
(key.vucc_grids.length ? ", " + key.vucc_grids.join(", ") : "") +
"</td>";
worker += "<td style='color:lightgreen'>" + key.band + "</td>";
worker += "<td style='color:lightblue'>" + key.mode + "</td>";
worker +=
"<td align=center>" + (key.confirmed ? "&#10004;" : "") + "</td>";
worker += "<td>" + key.RSTsent + "</td>";
worker += "<td>" + key.RSTrecv + "</td>";
worker +=
"<td style='color:orange'>" +
g_dxccToAltName[key.dxcc] +
" <font color='lightgreen'>(" +
(key.dxcc in g_dxccInfo
? g_dxccInfo[key.dxcc].pp
: "?") +
")</font></td>";
worker +=
"<td align=center style='margin:0;padding:0' ><img style='padding-top:4px' src='./img/flags/16/" +
(key.dxcc in g_dxccInfo
? g_dxccInfo[key.dxcc].flag
: "_United Nations.png") +
"'></td>";
worker +=
"<td style='color:lightblue'>" +
userTimeString(key.time * 1000) +
"</td>";
if (g_callsignLookups.lotwUseEnable == true)
{
worker +=
"<td align=center>" +
(key.DEcall in g_lotwCallsigns ? "&#10004;" : "") +
"</td>";
}
if (g_callsignLookups.eqslUseEnable == true)
{
worker +=
"<td align=center>" +
(key.DEcall in g_eqslCallsigns ? "&#10004;" : "") +
"</td>";
}
if (g_callsignLookups.oqrsUseEnable == true)
{
worker +=
"<td align=center>" +
(key.DEcall in g_oqrsCallsigns ? "&#10004;" : "") +
"</td>";
}
worker += "</tr>";
}
worker += "</table>";
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",
g_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",
g_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",
g_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",
g_filterQSL,
true
);
statsFocus(g_lastSearchSelection);
setStatsDivHeight("workedListDiv", getStatsWindowHeight() - 6 + "px");
}
else setStatsDiv("workedListDiv", "None");
myObjects = null;
}
catch (e)
{
console.error(e);
}
}
function statsValidateCallByElement(elementString)
{
if (
g_statsWindowHandle != null &&
typeof g_statsWindowHandle.window.validateCallByElement !== "undefined"
)
{
g_statsWindowHandle.window.validateCallByElement(elementString);
}
}
function statsFocus(selection)
{
if (
g_statsWindowHandle != null &&
typeof g_statsWindowHandle.window.statsFocus !== "undefined"
)
{
g_statsWindowHandle.window.statsFocus(selection);
}
}
function lookupValidateCallByElement(elementString)
{
if (
g_lookupWindowHandle != null && g_lookupWindowInitialized &&
typeof g_lookupWindowHandle.window.validateCallByElement !== "undefined"
)
{
g_lookupWindowHandle.window.validateCallByElement(elementString);
}
}
function lookupFocus(selection)
{
if (
g_lookupWindowHandle != null && g_lookupWindowInitialized &&
typeof g_lookupWindowHandle.window.statsFocus !== "undefined"
)
{
g_lookupWindowHandle.window.statsFocus(selection);
}
}
function statsAppendChild(elementString, object, onInputString, defaultValue)
{
if (
g_statsWindowHandle != null &&
typeof g_statsWindowHandle.window.appendToChild !== "undefined"
)
{
g_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 g_dxccInfo)
{
if (key != -1 && Number(g_dxccInfo[key].dxcc) > 0)
{
if (g_dxccInfo[key].worked == true)
{
var item = {};
item.dxcc = g_dxccInfo[key].dxcc;
item.flag = g_dxccInfo[key].flag;
item.confirmed = g_dxccInfo[key].confirmed;
List[g_dxccInfo[key].name] = item;
worked++;
}
if (g_dxccInfo[key].confirmed == true)
{
var item = {};
item.dxcc = g_dxccInfo[key].dxcc;
item.flag = g_dxccInfo[key].flag;
item.confirmed = g_dxccInfo[key].confirmed;
ListConfirmed[g_dxccInfo[key].name] = item;
confirmed++;
}
if (
g_dxccInfo[key].worked == false &&
g_dxccInfo[key].confirmed == false &&
g_dxccInfo[key].pp != "" &&
g_dxccInfo[key].geo != "deleted"
)
{
var item = {};
item.dxcc = g_dxccInfo[key].dxcc;
item.flag = g_dxccInfo[key].flag;
item.confirmed = g_dxccInfo[key].confirmed;
ListNotWorked[g_dxccInfo[key].name] = item;
needed++;
}
}
}
if (worked > 0)
{
worker +=
"<div style='vertical-align:top;display:inline-block;margin-right:2px;overflow:auto;overflow-x:hidden;height:" +
Math.min(Object.keys(List).length * 23 + 45, getStatsWindowHeight()) +
"px;'><table class='darkTable' align=center><tr><th colspan=5 style='font-weight:bold'>Worked (" +
worked +
")</th><tr><th align=left>Name</th><th>Flag</th><th align=left>DXCC</th></tr>";
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 +=
"<tr><td align=left style='color:#ff0;" + rowStyle + "' " + rowAttributes + ">" +
key +
"</td>";
worker +=
"<td align='center' style='margin:0;padding:0'><img style='padding-top:3px' src='./img/flags/16/" +
List[key].flag +
"'></td>";
worker +=
"<td align=left style='color:cyan;' >" + List[key].dxcc + "</td>";
});
worker += "</table></div>";
}
if (confirmed > 0)
{
worker +=
"<div style='padding:0px;vertical-align:top;display:inline-block;margin-right:2px;overflow:auto;overflow-x:hidden;height:" +
Math.min(
Object.keys(ListConfirmed).length * 23 + 45,
getStatsWindowHeight()
) +
"px;'><table class='darkTable' align=center><tr><th colspan=5 style='font-weight:bold'>Confirmed (" +
confirmed +
")</th><tr><th align=left>Name</th><th>Flag</th><th align=left>DXCC</th></tr>";
Object.keys(ListConfirmed)
.sort()
.forEach(function (key, i)
{
worker += "<tr><td align=left style='color:#ff0;' >" + key + "</td>";
worker +=
"<td align='center' style='margin:0;padding:0'><img style='padding-top:3px' src='./img/flags/16/" +
ListConfirmed[key].flag +
"'></td>";
worker +=
"<td align=left style='color:cyan;' >" +
ListConfirmed[key].dxcc +
"</td>";
});
worker += "</table></div>";
}
if (needed > 0)
{
worker +=
"<div style='vertical-align:top;display:inline-block;overflow:auto;overflow-x:hidden;height:" +
Math.min(
Object.keys(ListNotWorked).length * 23 + 45,
getStatsWindowHeight()
) +
"px;'><table class='darkTable' align=center><tr><th colspan=3 style='font-weight:bold'>Needed (" +
needed +
")</th><tr><th align=left>Name</th><th>Flag</th><th align=left>DXCC</th></tr>";
Object.keys(ListNotWorked)
.sort()
.forEach(function (key, i)
{
worker += "<tr><td align=left style='color:#ff0;' >" + key + "</td>";
worker +=
"<td align='center' style='margin:0;padding:0'><img style='padding-top:3px' src='./img/flags/16/" +
ListNotWorked[key].flag +
"'></td>";
worker +=
"<td align=left style='color:cyan;' >" +
ListNotWorked[key].dxcc +
"</td>";
});
worker += "</table></div>";
}
setStatsDiv("dxccListDiv", worker);
Object.keys(List).forEach(function (key, i)
{
var band = g_appSettings.gtBandFilter == "auto" ? myBand : g_appSettings.gtBandFilter.length == 0 ? "" : g_appSettings.gtBandFilter;
var unconfirmedCallsKey = new UnconfirmedCallsKey(List[key].dxcc, band);
if (g_unconfirmedCalls.has(unconfirmedCallsKey.key) && g_unconfirmedCalls.get(unconfirmedCallsKey.key) != unconfirmedCallsSentinel)
{
var onMousedown = function (e)
{
if (e.which === 1)
{
if (g_popupWindowHandle == null)
{
popupNewWindows();
var gui = require("nw.gui");
gui.Window.open(
"gt_popup.html",
{
show: false,
id: "GT-popup"
},
function (new_win)
{
g_popupWindowHandle = new_win;
new_win.on("loaded", function ()
{
g_popupWindowHandle.show();
renderTooltipWindowLogbook(g_unconfirmedCalls.get(unconfirmedCallsKey.key));
});
new_win.on("close", function ()
{
g_popupWindowHandle.hide();
});
}
);
lockNewWindows();
}
else
{
renderTooltipWindowLogbook(g_unconfirmedCalls.get(unconfirmedCallsKey.key));
}
}
};
var unconfirmedTd = g_statsWindowHandle.window.document.getElementById("unconfirmed" + List[key].dxcc + "Id");
if (unconfirmedTd != null) { unconfirmedTd.addEventListener("mousedown", onMousedown); }
}
});
}
function showCQzoneBox()
{
var worker = getCurrentBandModeHTML();
worker +=
"<div style='vertical-align:top;display:inline-block;margin-right:8px;overflow:auto;overflow-x:hidden;color:cyan;'><b>Worked CQ Zones</b><br/>";
worker += displayItemList(g_cqZones, "#FFFFFF");
worker += "</div>";
setStatsDiv("cqzoneListDiv", worker);
}
function showITUzoneBox()
{
var worker = getCurrentBandModeHTML();
worker +=
"<div style='vertical-align:top;display:inline-block;margin-right:8px;overflow:auto;overflow-x:hidden;color:cyan;'><b>Worked ITU Zones</b><br/>";
worker += displayItemList(g_ituZones, "#FFFFFF");
worker += "</div>";
setStatsDiv("ituzoneListDiv", worker);
}
function showWASWACzoneBox()
{
var worker = getCurrentBandModeHTML();
worker +=
"<div style='vertical-align:top;display:inline-block;margin-right:8px;overflow:auto;overflow-x:hidden;color:cyan;'><b>Worked All Continents</b><br/>";
worker += displayItemList(g_wacZones, "#90EE90");
worker += "</div>";
worker +=
"<div style='vertical-align:top;display:inline-block;margin-right:8px;overflow:auto;overflow-x:hidden;color:cyan;'><b>Worked All States</b><br/>";
worker += displayItemList(g_wasZones, "#00DDDD");
worker += "</div>";
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 =
"<div style='color:white;vertical-align:top;display:inline-block;margin-right:8px;overflow:auto;overflow-x:hidden;height:" +
Math.min(
Object.keys(table).length * 23 + (23 + 45),
getStatsWindowHeight() - 12
) +
"px;'>";
worker += "<table class='darkTable' align=center>";
worker +=
"<tr><th style='font-weight:bold'>Worked (" + worked + ")</th></tr>";
worker +=
"<tr><th style='font-weight:bold'>Confirmed (" + confirmed + ")</th></tr>";
worker +=
"<tr><th style='font-weight:bold'>Needed (" + needed + ")</th></tr>";
worker += "<tr><th align=left>Name</th></tr>";
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 +=
"<tr><td align=left style='" + style + "'>" + name + "</td></tr>";
});
worker += "</table></div>";
return worker;
}
function showWPXBox()
{
var worker = getCurrentBandModeHTML();
var band = g_appSettings.gtBandFilter == "auto" ? myBand : g_appSettings.gtBandFilter.length == 0 ? "" : g_appSettings.gtBandFilter;
var mode = g_appSettings.gtModeFilter == "auto" ? myMode : g_appSettings.gtModeFilter.length == 0 ? "" : g_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 g_tracker.worked.px)
{
if (typeof g_tracker.worked.px[key] == "string" && key + modifier in g_tracker.worked.px)
{
List[key] = key;
}
}
for (var key in g_tracker.confirmed.px)
{
if (typeof g_tracker.confirmed.px[key] == "string" && key + modifier in g_tracker.confirmed.px)
{
ListConfirmed[key] = key;
}
}
worked = Object.keys(List).length;
confirmed = Object.keys(ListConfirmed).length;
if (worked > 0)
{
worker +=
"<div style='vertical-align:top;display:inline-block;margin-right:8px;overflow:auto;overflow-x:hidden;color:cyan;'><b>Worked Prefixes (<font color='#fff'>" +
worked +
"</font>)</b><br/>";
worker +=
"<div style='color:white;vertical-align:top;display:inline-block;margin-right:8px;overflow:auto;overflow-x:hidden;height:" +
Math.min(worked * 23 + 45, getStatsWindowHeight() - 6) +
"px;'><table class='darkTable' align=center>";
Object.keys(List)
.sort()
.forEach(function (key, i)
{
worker +=
"<tr><td align=left style='color:#ff0;' >" +
key.formatCallsign() +
"</td><td style='color:#0ff;'>" +
g_QSOhash[g_tracker.worked.px[key]].DEcall.formatCallsign() +
"</td></tr>";
});
worker += "</table></div>";
worker += "</div>";
}
if (confirmed > 0)
{
worker +=
"<div style='vertical-align:top;display:inline-block;margin-right:8px;overflow:auto;overflow-x:hidden;color:cyan;'><b>Confirmed Prefixes (<font color='#fff'>" +
confirmed +
"</font>)</b><br/>";
worker +=
"<div style='color:white;vertical-align:top;display:inline-block;margin-right:8px;overflow:auto;overflow-x:hidden;height:" +
Math.min(confirmed * 23 + 45, getStatsWindowHeight() - 6) +
"px;'><table class='darkTable' align=center>";
Object.keys(ListConfirmed)
.sort()
.forEach(function (key, i)
{
worker +=
"<tr><td align=left style='color:#ff0;' >" +
key.formatCallsign() +
"</td><td style='color:#0ff;'>" +
g_QSOhash[g_tracker.confirmed.px[key]].DEcall.formatCallsign() +
"</td></tr>";
});
worker += "</table></div>";
worker += "</div>";
}
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";
g_helpShow = false;
rootSettingsDiv.style.display = "inline-block";
}
}
function toggleBaWindow(event)
{
event.preventDefault();
if (g_baWindowHandle == null)
{
openBaWindow(true);
}
else
{
if (g_baWindowHandle.window.g_isShowing == true)
{
openBaWindow(false);
}
else
{
openBaWindow(true);
}
}
}
function openBaWindow(show = true)
{
if (g_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)
{
g_baWindowHandle = new_win;
new_win.on("loaded", function ()
{
g_baWindowHandle.setMinimumSize(198, 52);
});
new_win.on("close", function ()
{
g_baWindowHandle.window.g_isShowing = false;
g_baWindowHandle.window.saveScreenSettings();
g_baWindowHandle.hide();
});
}
);
lockNewWindows();
}
else
{
try
{
if (show == true)
{
g_baWindowHandle.show();
g_baWindowHandle.window.g_isShowing = true;
g_baWindowHandle.window.saveScreenSettings();
}
else
{
g_baWindowHandle.window.g_isShowing = false;
g_baWindowHandle.window.saveScreenSettings();
g_baWindowHandle.hide();
}
}
catch (e)
{
console.error(e);
}
}
}
function openLookupWindow(show = false)
{
if (g_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)
{
g_lookupWindowHandle = new_win;
new_win.on("loaded", function ()
{
g_lookupWindowHandle.setMinimumSize(680, 200);
g_lookupWindowHandle.setResizable(true);
});
new_win.on("close", function ()
{
g_lookupWindowHandle.window.g_isShowing = false;
g_lookupWindowHandle.window.saveScreenSettings();
g_lookupWindowHandle.hide();
});
}
);
lockNewWindows();
}
else
{
try
{
if (show)
{
g_lookupWindowHandle.show();
g_lookupWindowHandle.window.g_isShowing = true;
g_lookupWindowHandle.window.saveScreenSettings();
}
else
{
g_lookupWindowHandle.hide();
g_lookupWindowHandle.window.g_isShowing = false;
g_lookupWindowHandle.window.saveScreenSettings();
}
}
catch (e)
{
console.error(e);
}
}
}
function openInfoTab(evt, tabName, callFunc, callObj)
{
openStatsWindow();
if (g_statsWindowHandle != null)
{
// Declare all variables
var i, infoTabcontent, infoTablinks;
// Get all elements with class="infoTabcontent" and hide them
infoTabcontent = g_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 = g_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
g_statsWindowHandle.window.document.getElementById(tabName).style.display =
"block";
if (evt)
{
evt = g_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)
{
g_appSettings.sixWideMode = mode;
modeImg.src = g_maidenheadModeImageArray[g_appSettings.sixWideMode];
clearTempGrids();
redrawGrids();
}
function toggleGridMode()
{
g_appSettings.sixWideMode ^= 1;
modeImg.src = g_maidenheadModeImageArray[g_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;
}
var g_statBoxTimer = null;
function showStatBox(resize)
{
var count = Object.keys(g_QSOhash).length;
if (typeof resize != "undefined" && resize)
{
setStatsDivHeight("statViewDiv", getStatsWindowHeight() + 29 + "px");
return;
}
if (g_statBoxTimer) nodeTimers.clearTimeout(g_statBoxTimer);
if (count > 0)
{
setStatsDiv(
"statViewDiv",
"&nbsp;<br/>...Parsing Log Entries...<br/>&nbsp;"
);
setStatsDivHeight("statViewDiv", "auto");
g_statBoxTimer = nodeTimers.setTimeout(renderStatsBox, 250);
}
else
{
setStatsDiv(
"statViewDiv",
"&nbsp;<br/>No log entries available, load one or more ADIF logs<br/>&nbsp;"
);
setStatsDivHeight("statViewDiv", "auto");
}
}
function getTypeFromMode(mode)
{
if (mode in g_modes)
{
if (g_modes[mode] == true) return "Digital";
else if (g_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 g_QSOhash)
{
var finalGrid = g_QSOhash[i].grid;
var didConfirm = g_QSOhash[i].confirmed;
var band = g_QSOhash[i].band;
var mode = g_QSOhash[i].mode;
var state = g_QSOhash[i].state;
var cont = g_QSOhash[i].cont;
var finalDxcc = g_QSOhash[i].dxcc;
var cnty = g_QSOhash[i].cnty;
var ituz = g_QSOhash[i].ituz;
var cqz = g_QSOhash[i].cqz;
var wpx = g_QSOhash[i].px;
var call = g_QSOhash[i].DXcall;
var who = g_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 (g_QSOhash[i].time < details.oldest) { details.oldest = g_QSOhash[i].time; }
if (g_QSOhash[i].time > details.newest) { details.newest = g_QSOhash[i].time; }
workObject(modet.Mixed, true, band, mode, type, didConfirm);
if (mode in g_modes)
{
if (g_modes[mode] == true)
{
workObject(modet.Digital, true, band, mode, type, didConfirm);
}
else if (g_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 g_StateData)
{
var name = g_StateData[state].name;
if (name in g_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 g_cntyToCounty)
{
if (!(cnty in countyData)) countyData[cnty] = newStatObject();
workObject(countyData[cnty], false, band, mode, type, didConfirm);
}
}
if (cont != null)
{
if (cont in g_shapeData)
{
var name = g_shapeData[cont].properties.name;
if (name in g_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(g_myLat, g_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 (!(g_dxccToAltName[finalDxcc] in dxccInfo)) { dxccInfo[g_dxccToAltName[finalDxcc]] = newStatObject(); }
workObject(
dxccInfo[g_dxccToAltName[finalDxcc]],
false,
band,
mode,
type,
didConfirm
);
}
if (cqz && cqz.length > 0)
{
var name = g_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", "Mixed", ""],
1: ["DIGITAL", "Digital", ""],
2: ["PHONE", "Phone", ""],
3: ["CW", "CW", ""],
4: ["Other", "Other", ""]
};
var AwardNames = {
0: ["WRFA", "Callsigns", "WRFA", "yellow"],
1: ["GRID", "Grids", "GSA", "cyan"],
2: ["DXCC", "DXCCs", "DXWA", "orange"],
3: ["CQ", "CQ Zones", "WAZ", "lightgreen"],
4: ["ITU", "ITU Zones", "ITUz", "#DD44DD"],
5: ["WAC", "Continents", "WAC", "cyan"],
6: ["WAS", "US States", "WAS", "lightblue"],
7: ["USC", "US Counties", "USA-CA", "orange"],
8: ["WPX", "Prefixes", "WPX", "yellow"]
};
worker = "<font color='cyan'>";
worker += "<h1>Logbook</h1>";
worker +=
"<table style='display:inline-table;margin:5px;' class='darkTable'>";
var ws = "";
if (Object.keys(details.callsigns).length > 1) ws = "s";
worker +=
"<tr><td>Callsign" +
ws +
"</td><td style='color:yellow' ><b>" +
Object.keys(details.callsigns).sort().join(", ") +
"</b></td></tr>";
worker +=
"<tr><td>First Contact</td><td style='color:white' >" +
userTimeString(details.oldest * 1000) +
"</td></tr>";
worker +=
"<tr><td>Last Contact</td><td style='color:white' >" +
userTimeString(details.newest * 1000) +
"</td></tr>";
worker += "</table>";
worker += "</br>";
worker += "<h1>Score Card</h1>";
worker +=
"<table style='display:inline-table;margin:5px;' class='darkTable'>";
worker +=
"<tr><th>Top Score</th><th style='color:yellow'>Worked</th><th style='color:lightgreen'>Confirmed</th></tr>";
for (var key in AwardNames)
{
scoreSection = "Award " + AwardNames[key][1];
var infoObject = output[AwardNames[key][0]];
worker += "<tr><td style='color:white'>" + AwardNames[key][1] + "</td>";
worker +=
"<td style='color:" +
AwardNames[key][3] +
"'>" +
infoObject.worked_high_key +
"<font color='white'> (" +
infoObject.worked_high +
")</font></td>";
if (infoObject.confirmed_high_key)
{
worker +=
"<td style='color:" +
AwardNames[key][3] +
"'>" +
infoObject.confirmed_high_key +
"<font color='white'> (" +
infoObject.confirmed_high +
")</font></td>";
}
else worker += "<td></td>";
worker += "</tr>";
}
scoreSection = "Long Distance";
worker += "<tr><td style='color:white'>Long Distance</td>";
worker +=
"<td style='color:lightgreen'>" +
long_distance.worked_unit +
" " +
distanceUnit.value.toLowerCase();
worker +=
"<font style='color:yellow' > " +
g_QSOhash[long_distance.worked_hash].DEcall +
"</font>";
worker +=
"<font style='color:orange' > " +
g_QSOhash[long_distance.worked_hash].grid +
"</font></td>";
if (long_distance.confirmed_hash && long_distance.confirmed_unit > 0)
{
worker +=
"<td style='color:lightgreen'>" +
long_distance.confirmed_unit +
" " +
distanceUnit.value.toLowerCase();
worker +=
"<font style='color:yellow' > " +
g_QSOhash[long_distance.confirmed_hash].DEcall +
"</font>";
worker +=
"<font style='color:orange' > " +
g_QSOhash[long_distance.confirmed_hash].grid +
"</font></td>";
}
else worker += "<td></td>";
scoreSection = "Short Distance";
worker += "<tr><td style='color:white' >Short Distance</td>";
worker +=
"<td style='color:lightblue'>" +
short_distance.worked_unit +
" " +
distanceUnit.value.toLowerCase();
worker +=
"<font style='color:yellow' > " +
g_QSOhash[short_distance.worked_hash].DEcall +
"</font>";
worker +=
"<font style='color:orange' > " +
g_QSOhash[short_distance.worked_hash].grid +
"</font></td>";
if (short_distance.confirmed_hash && short_distance.confirmed_unit > 0)
{
worker +=
"<td style='color:lightblue'>" +
short_distance.confirmed_unit +
" " +
distanceUnit.value.toLowerCase();
worker +=
"<font style='color:yellow' > " +
g_QSOhash[short_distance.confirmed_hash].DEcall +
"</font>";
worker +=
"<font style='color:orange' > " +
g_QSOhash[short_distance.confirmed_hash].grid +
"</font></td>";
}
else worker += "<td></td>";
worker += "</tr>";
worker += "</table>";
worker += "</br>";
worker += "<h1>Award Types</h1>";
scoreSection = "Award Types";
for (var key in AwardNames)
{
worker += createStatTable(
AwardNames[key][1],
output[AwardNames[key][0]],
AwardNames[key][2]
);
}
worker += "<br/>";
scoreSection = "Mode Types";
worker += "<h1>Mode Types</h1>";
for (var key in TypeNames)
{
worker += createStatTable(
TypeNames[key][1],
output[TypeNames[key][0]],
TypeNames[key][2]
);
}
worker += "<br/>";
worker += "<h1>Distances</h1>";
scoreSection = "Distances";
worker += createDistanceTable(long_distance, "Longest Distance");
worker += createDistanceTable(short_distance, "Shortest Distance");
worker += "<br/>";
}
catch (e)
{
worker +=
"<br/> In Section: " +
scoreSection +
"<br/>Error Generating Stats<br/>Please take a screenshot and send to team@gridtracker.org";
}
setStatsDiv("statViewDiv", worker);
setStatsDivHeight("statViewDiv", getStatsWindowHeight() + 29 + "px");
}
function hashNameSort(a, b)
{
if (g_QSOhash[a].DEcall > g_QSOhash[b].DEcall) return 1;
if (g_QSOhash[b].DEcall > g_QSOhash[a].DEcall) return -1;
return 0;
}
function createDistanceTable(obj, name)
{
var worker =
"<table style='display:inline-table;margin:5px;' class='darkTable'>";
worker +=
"<tr><th colspan = 3 align=left style='font-size:15px;color:cyan;'>" +
name +
"</th></tr>";
worker +=
"<tr><td></td><td><font color='yellow'>Worked</font></td><td colspan=2 ><font color='lightgreen'>Confirmed</font></td></tr>";
worker += "<tr><td align=center><font color='lightgreen'>Bands</font></td>";
worker += "<td align=left><table class='subtable'>";
var keys = Object.keys(obj.band).sort(numberSort);
for (var key in keys)
{
var grid = g_QSOhash[obj.band[keys[key]].worked_hash].grid;
var call = g_QSOhash[obj.band[keys[key]].worked_hash].DEcall;
worker +=
"<tr><td align=right>" +
keys[key] +
"</td><td style='color:lightgreen' align=left>(" +
obj.band[keys[key]].worked_unit +
" " +
distanceUnit.value.toLowerCase() +
")</td>";
worker +=
"<td style='color:yellow;cursor:pointer' align=left onclick='window.opener.startLookup(\"" +
call +
"\",\"" +
grid +
"\");' >" +
call +
"</td>";
worker += "<td style='color:orange' align=left>" + grid + "</td>";
worker += "</tr>";
}
worker += "</table></td>";
worker += "<td align=left><table class='subtable'>";
for (var key in keys)
{
if (keys[key] in obj.band && obj.band[keys[key]].confirmed_hash)
{
var grid = g_QSOhash[obj.band[keys[key]].confirmed_hash].grid;
var call = g_QSOhash[obj.band[keys[key]].confirmed_hash].DEcall;
worker +=
"<tr><td align=right>" +
keys[key] +
"</td><td style='color:lightgreen' align=left>(" +
obj.band[keys[key]].confirmed_unit +
" " +
distanceUnit.value.toLowerCase() +
")</td>";
worker +=
"<td style='color:yellow;cursor:pointer' align=left onclick='window.opener.startLookup(\"" +
call +
"\",\"" +
grid +
"\");'>" +
call +
"</td>";
worker += "<td style='color:orange' align=left>" + grid + "</td>";
worker += "</tr>";
}
else worker += "<tr><td>&nbsp;</td></tr>";
}
worker += "</table></td>";
worker += "</tr>";
worker += "<tr><td align=center><font color='orange'>Modes</font></td>";
worker += "<td align=left><table class='subtable'>";
keys = Object.keys(obj.mode).sort();
for (var key in keys)
{
var grid = g_QSOhash[obj.mode[keys[key]].worked_hash].grid;
var call = g_QSOhash[obj.mode[keys[key]].worked_hash].DEcall;
worker +=
"<tr><td align=right>" +
keys[key] +
"</td><td style='color:lightgreen' align=left>(" +
obj.mode[keys[key]].worked_unit +
" " +
distanceUnit.value.toLowerCase() +
")</td>";
worker +=
"<td style='color:yellow;cursor:pointer' align=left onclick='window.opener.startLookup(\"" +
call +
"\",\"" +
grid +
"\");' >" +
call +
"</td>";
worker += "<td style='color:orange' align=left>" + grid + "</td>";
worker += "</tr>";
}
worker += "</table></td>";
worker += "<td align=left><table class='subtable'>";
for (var key in keys)
{
if (keys[key] in obj.mode && obj.mode[keys[key]].confirmed_hash)
{
var grid = g_QSOhash[obj.mode[keys[key]].confirmed_hash].grid;
var call = g_QSOhash[obj.mode[keys[key]].confirmed_hash].DEcall;
worker +=
"<tr><td align=right>" +
keys[key] +
"</td><td style='color:lightgreen' align=left>(" +
obj.mode[keys[key]].confirmed_unit +
" " +
distanceUnit.value.toLowerCase() +
")</td>";
worker +=
"<td style='color:yellow;cursor:pointer' align=left onclick='window.opener.startLookup(\"" +
call +
"\",\"" +
grid +
"\");' >" +
call +
"</td>";
worker += "<td style='color:orange' align=left>" + grid + "</td>";
worker += "</tr>";
}
else worker += "<tr><td>&nbsp;</td></tr>";
}
worker += "</table></td>";
worker += "</tr>";
worker += "<tr><td align=center><font color='#DD44DD'>Types</font></td>";
worker += "<td align=left><table class='subtable'>";
keys = Object.keys(obj.type).sort();
for (var key in keys)
{
var grid = g_QSOhash[obj.type[keys[key]].worked_hash].grid;
var call = g_QSOhash[obj.type[keys[key]].worked_hash].DEcall;
worker +=
"<tr><td align=right>" +
keys[key] +
"</td><td style='color:lightgreen' align=left>(" +
obj.type[keys[key]].worked_unit +
" " +
distanceUnit.value.toLowerCase() +
")</td>";
worker +=
"<td style='color:yellow;cursor:pointer' align=left onclick='window.opener.startLookup(\"" +
call +
"\",\"" +
grid +
"\");' >" +
call +
"</td>";
worker += "<td style='color:orange' align=left>" + grid + "</td>";
worker += "</tr>";
}
worker += "</table></td>";
worker += "<td align=left><table class='subtable'>";
for (var key in keys)
{
if (keys[key] in obj.type && obj.type[keys[key]].confirmed_hash)
{
var grid = g_QSOhash[obj.type[keys[key]].confirmed_hash].grid;
var call = g_QSOhash[obj.type[keys[key]].confirmed_hash].DEcall;
worker +=
"<tr><td align=right>" +
keys[key] +
"</td><td style='color:lightgreen' align=left>(" +
obj.type[keys[key]].confirmed_unit +
" " +
distanceUnit.value.toLowerCase() +
")</td>";
worker +=
"<td style='color:yellow;cursor:pointer' align=left onclick='window.opener.startLookup(\"" +
call +
"\",\"" +
grid +
"\");' >" +
call +
"</td>";
worker += "<td style='color:orange' align=left>" + grid + "</td>";
worker += "</tr>";
}
else worker += "<tr><td>&nbsp;</td></tr>";
}
worker += "</table></td>";
worker += "</tr>";
worker += "</table>";
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 =
"<table style='display:inline-table;margin:5px;' class='darkTable'>";
wc1Table +=
"<tr><th colspan = 3 align=left style='font-size:15px;color:cyan;'>" +
title +
"</th></tr>";
var award = "<th></th>";
wc1Table +=
"<tr>" +
award +
"<td><font color='yellow'>Worked</font> <font color='white'>(" +
infoObject.worked +
")</font></td><td colspan=2 ><font color='lightgreen'>Confirmed</font> <font color='white'>(" +
infoObject.confirmed +
")</font></td></tr>";
wc1Table +=
"<tr><td align=center><font color='lightgreen'>Bands</font></td>";
wc1Table += "<td align=left><table class='subtable'>";
var keys = Object.keys(infoObject.worked_bands).sort(numberSort);
for (var key in keys)
{
wc1Table +=
"<tr><td align=right>" +
keys[key] +
"</td><td align=left> <font color='white'>(" +
infoObject.worked_bands[keys[key]] +
")</font></td></tr>";
}
wc1Table += "</table></td>";
wc1Table += "<td align=left><table class='subtable'>";
for (var key in keys)
{
if (keys[key] in infoObject.confirmed_bands)
{
wc1Table +=
"<tr><td align=right>" +
keys[key] +
"</td><td align=left> <font color='white'>(" +
infoObject.confirmed_bands[keys[key]] +
")</font></td></tr>";
}
else wc1Table += "<tr><td>&nbsp;</td></tr>";
}
wc1Table += "</table></td>";
wc1Table += "</tr>";
wc1Table += "<tr>";
wc1Table += "<td align=center><font color='orange'>Modes</font></td>";
wc1Table += "<td align=left><table class='subtable'>";
keys = Object.keys(infoObject.worked_modes).sort();
for (var key in keys)
{
wc1Table +=
"<tr><td align=right>" +
keys[key] +
"</td><td align=left> <font color='white'>(" +
infoObject.worked_modes[keys[key]] +
")</font></td></tr>";
}
wc1Table += "</table></td>";
wc1Table += "<td align=left><table class='subtable'>";
for (var key in keys)
{
if (keys[key] in infoObject.confirmed_modes)
{
wc1Table +=
"<tr><td align=right>" +
keys[key] +
"</td><td align=left> <font color='white'>(" +
infoObject.confirmed_modes[keys[key]] +
")</font></td></tr>";
}
else wc1Table += "<tr><td>&nbsp;</td></tr>";
}
wc1Table += "</table></td>";
wc1Table += "</tr>";
if (infoObject.worked_type_count > 0)
{
wc1Table += "<tr>";
wc1Table += "<td align=center><font color='#DD44DD'>Types</font></td>";
wc1Table += "<td align=left><table class='subtable'>";
var keys = Object.keys(infoObject.worked_types).sort();
for (var key in keys)
{
wc1Table +=
"<tr><td align=right>" +
keys[key] +
"</td><td align=left> <font color='white'>(" +
infoObject.worked_types[keys[key]] +
") " +
"</font></td></tr>";
}
wc1Table += "</table></td>";
wc1Table += "<td align=left><table class='subtable'>";
for (var key in keys)
{
if (keys[key] in infoObject.confirmed_types)
{
wc1Table +=
"<tr><td align=right>" +
keys[key] +
"</td><td align=left> <font color='white'>(" +
infoObject.confirmed_types[keys[key]] +
") " +
"</font></td></tr>";
}
else wc1Table += "<tr><td>&nbsp;</td></tr>";
}
wc1Table += "</table></td>";
wc1Table += "</tr>";
}
wc1Table += "</table>";
}
return wc1Table;
}
function validatePropMode(propMode)
{
if (g_appSettings.gtPropFilter == "mixed") return true;
return g_appSettings.gtPropFilter == propMode;
}
function validateMapBandAndMode(band, mode)
{
if ((g_appSettings.gtBandFilter.length == 0 || (g_appSettings.gtBandFilter == "auto" ? myBand == band : g_appSettings.gtBandFilter == band)))
{
if (g_appSettings.gtModeFilter.length == 0) return true;
if (g_appSettings.gtModeFilter == "auto") return myMode == mode;
if (g_appSettings.gtModeFilter == "Digital")
{
if (mode in g_modes && g_modes[mode]) return true;
return false;
}
if (g_appSettings.gtModeFilter == "Phone")
{
if (mode in g_modes_phone && g_modes_phone[mode]) return true;
return false;
}
if (g_appSettings.gtModeFilter == "CW" && mode == "CW") return true;
return g_appSettings.gtModeFilter == mode;
}
else
{
return false;
}
}
function redrawGrids()
{
if (g_appSettings.gridViewMode == 2) removePaths();
clearGrids();
clearQsoGrids();
g_QSLcount = 0;
g_QSOcount = 0;
for (var i in g_QSOhash)
{
var finalGrid = g_QSOhash[i].grid;
var worked = g_QSOhash[i].worked;
var didConfirm = g_QSOhash[i].confirmed;
var band = g_QSOhash[i].band;
var mode = g_QSOhash[i].mode;
g_QSOcount++;
if (didConfirm) g_QSLcount++;
if (validateMapBandAndMode(g_QSOhash[i].band, g_QSOhash[i].mode) && validatePropMode(g_QSOhash[i].propMode))
{
if (g_appSettings.gridViewMode > 1)
{
g_QSOhash[i].rect = qthToQsoBox(
g_QSOhash[i].grid,
i,
false,
g_QSOhash[i].DXcall,
g_QSOhash[i].worked,
g_QSOhash[i].confirmed,
g_QSOhash[i].band,
g_QSOhash[i].wspr
);
for (var vucc in g_QSOhash[i].vucc_grids)
{
qthToQsoBox(
g_QSOhash[i].vucc_grids[vucc],
i,
false,
g_QSOhash[i].DXcall,
g_QSOhash[i].worked,
g_QSOhash[i].confirmed,
g_QSOhash[i].band,
g_QSOhash[i].wspr
);
}
}
var state = g_QSOhash[i].state;
var cont = g_QSOhash[i].cont;
var finalDxcc = g_QSOhash[i].dxcc;
var cnty = g_QSOhash[i].cnty;
var ituz = g_QSOhash[i].ituz;
var cqz = g_QSOhash[i].cqz;
if (state != null && isKnownCallsignUS(finalDxcc))
{
if (state.substr(0, 2) != "US") state = "US-" + state;
if (state in g_StateData)
{
var name = g_StateData[state].name;
if (name in g_wasZones)
{
if (g_wasZones[name].worked == false)
{
g_wasZones[name].worked = worked;
}
if (worked)
{
g_wasZones[name].worked_bands[band] =
~~g_wasZones[name].worked_bands[band] + 1;
g_wasZones[name].worked_modes[mode] =
~~g_wasZones[name].worked_modes[mode] + 1;
}
if (g_wasZones[name].confirmed == false)
{
g_wasZones[name].confirmed = didConfirm;
}
if (didConfirm)
{
g_wasZones[name].confirmed_bands[band] =
~~g_wasZones[name].confirmed_bands[band] + 1;
g_wasZones[name].confirmed_modes[mode] =
~~g_wasZones[name].confirmed_modes[mode] + 1;
}
}
}
}
if (cnty != null)
{
if (cnty in g_cntyToCounty)
{
if (g_countyData[cnty].worked == false)
{
g_countyData[cnty].worked = worked;
}
if (worked)
{
g_countyData[cnty].worked_bands[band] =
~~g_countyData[cnty].worked_bands[band] + 1;
g_countyData[cnty].worked_modes[mode] =
~~g_countyData[cnty].worked_modes[mode] + 1;
}
if (g_countyData[cnty].confirmed == false)
{
g_countyData[cnty].confirmed = didConfirm;
}
if (didConfirm)
{
g_countyData[cnty].confirmed_bands[band] =
~~g_countyData[cnty].confirmed_bands[band] + 1;
g_countyData[cnty].confirmed_modes[mode] =
~~g_countyData[cnty].confirmed_modes[mode] + 1;
}
}
}
if (cont != null)
{
if (cont in g_shapeData)
{
var name = g_shapeData[cont].properties.name;
if (name in g_wacZones)
{
if (g_wacZones[name].worked == false)
{
g_wacZones[name].worked = worked;
}
if (worked)
{
g_wacZones[name].worked_bands[band] =
~~g_wacZones[name].worked_bands[band] + 1;
g_wacZones[name].worked_modes[mode] =
~~g_wacZones[name].worked_modes[mode] + 1;
}
if (g_wacZones[name].confirmed == false)
{
g_wacZones[name].confirmed = didConfirm;
}
if (didConfirm)
{
g_wacZones[name].confirmed_bands[band] =
~~g_wacZones[name].confirmed_bands[band] + 1;
g_wacZones[name].confirmed_modes[mode] =
~~g_wacZones[name].confirmed_modes[mode] + 1;
}
}
}
}
if (g_dxccInfo[finalDxcc].worked == false)
{
g_dxccInfo[finalDxcc].worked = worked;
}
if (worked)
{
g_dxccInfo[finalDxcc].worked_bands[band] =
~~g_dxccInfo[finalDxcc].worked_bands[band] + 1;
g_dxccInfo[finalDxcc].worked_modes[mode] =
~~g_dxccInfo[finalDxcc].worked_modes[mode] + 1;
}
if (g_dxccInfo[finalDxcc].confirmed == false)
{
g_dxccInfo[finalDxcc].confirmed = didConfirm;
}
if (didConfirm)
{
g_dxccInfo[finalDxcc].confirmed_bands[band] =
~~g_dxccInfo[finalDxcc].confirmed_bands[band] +
1;
g_dxccInfo[finalDxcc].confirmed_modes[mode] =
~~g_dxccInfo[finalDxcc].confirmed_modes[mode] +
1;
}
if (cqz && cqz.length > 0)
{
if (g_cqZones[cqz].worked == false)
{
g_cqZones[cqz].worked = worked;
}
if (worked)
{
g_cqZones[cqz].worked_bands[band] =
~~g_cqZones[cqz].worked_bands[band] + 1;
g_cqZones[cqz].worked_modes[mode] =
~~g_cqZones[cqz].worked_modes[mode] + 1;
}
if (g_cqZones[cqz].confirmed == false)
{
g_cqZones[cqz].confirmed = didConfirm;
}
if (didConfirm)
{
g_cqZones[cqz].confirmed_bands[band] =
~~g_cqZones[cqz].confirmed_bands[band] + 1;
g_cqZones[cqz].confirmed_modes[mode] =
~~g_cqZones[cqz].confirmed_modes[mode] + 1;
}
}
if (ituz && ituz.length > 0)
{
if (g_ituZones[ituz].worked == false)
{
g_ituZones[ituz].worked = worked;
}
if (worked)
{
g_ituZones[ituz].worked_bands[band] =
~~g_ituZones[ituz].worked_bands[band] + 1;
g_ituZones[ituz].worked_modes[mode] =
~~g_ituZones[ituz].worked_modes[mode] + 1;
}
if (g_ituZones[ituz].confirmed == false)
{
g_ituZones[ituz].confirmed = didConfirm;
}
if (didConfirm)
{
g_ituZones[ituz].confirmed_bands[band] =
~~g_ituZones[ituz].confirmed_bands[band] + 1;
g_ituZones[ituz].confirmed_modes[mode] =
~~g_ituZones[ituz].confirmed_modes[mode] + 1;
}
}
if (finalGrid.length > 0)
{
var gridCheck = finalGrid.substr(0, 4);
if (gridCheck in g_us48Data)
{
if (g_us48Data[gridCheck].worked == false)
{
g_us48Data[gridCheck].worked = worked;
}
if (worked)
{
g_us48Data[gridCheck].worked_bands[band] =
~~g_us48Data[gridCheck].worked_bands[band] + 1;
g_us48Data[gridCheck].worked_modes[mode] =
~~g_us48Data[gridCheck].worked_modes[mode] + 1;
}
if (g_us48Data[gridCheck].confirmed == false)
{
g_us48Data[gridCheck].confirmed = didConfirm;
}
if (didConfirm)
{
g_us48Data[gridCheck].confirmed_bands[band] =
~~g_us48Data[gridCheck].confirmed_bands[band] + 1;
g_us48Data[gridCheck].confirmed_modes[mode] =
~~g_us48Data[gridCheck].confirmed_modes[mode] + 1;
}
}
}
for (var key in g_QSOhash[i].vucc_grids)
{
var grid = g_QSOhash[i].vucc_grids[key].substr(0, 4);
if (grid in g_us48Data)
{
if (g_us48Data[grid].worked == false)
{
g_us48Data[grid].worked = worked;
}
if (worked)
{
g_us48Data[grid].worked_bands[band] =
~~g_us48Data[grid].worked_bands[band] + 1;
g_us48Data[grid].worked_modes[mode] =
~~g_us48Data[grid].worked_modes[mode] + 1;
}
if (g_us48Data[grid].confirmed == false)
{
g_us48Data[grid].confirmed = didConfirm;
}
if (didConfirm)
{
g_us48Data[grid].confirmed_bands[band] =
~~g_us48Data[grid].confirmed_bands[band] + 1;
g_us48Data[grid].confirmed_modes[mode] =
~~g_us48Data[grid].confirmed_modes[mode] + 1;
}
}
}
}
}
for (var layer in g_viewInfo)
{
var search = window[g_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++;
}
g_viewInfo[layer][2] = worked;
g_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++;
}
}
g_viewInfo[layer][2] = worked;
g_viewInfo[layer][3] = confirmed;
}
else
{
for (var key in search)
{
if (search[key].worked) worked++;
if (search[key].confirmed) confirmed++;
}
g_viewInfo[layer][2] = worked;
g_viewInfo[layer][3] = confirmed;
}
}
for (var i in g_liveCallsigns)
{
if (g_appSettings.gridViewMode != 2 && validateMapBandAndMode(g_liveCallsigns[i].band, g_liveCallsigns[i].mode))
{
if (g_appSettings.gridViewMode == 1 || g_appSettings.gridViewMode == 3)
{
g_liveCallsigns[i].rect = qthToBox(
g_liveCallsigns[i].grid,
g_liveCallsigns[i].DEcall,
false,
false,
g_liveCallsigns[i].DXcall,
g_liveCallsigns[i].band,
g_liveCallsigns[i].wspr,
i
);
}
}
}
reloadInfo(false);
setHomeGridsquare();
setTrophyOverlay(g_currentOverlay);
updateCountStats();
}
function toggleAlertMute()
{
g_appSettings.alertMute ^= 1;
alertMuteImg.src = g_alertImageArray[g_appSettings.alertMute];
if (g_appSettings.alertMute == 1)
{
chrome.tts.stop();
}
}
function togglePushPinMode()
{
if (g_pushPinMode == false) g_pushPinMode = true;
else g_pushPinMode = false;
g_appSettings.pushPinMode = g_pushPinMode;
pinImg.src = g_pinImageArray[g_pushPinMode == false ? 0 : 1];
clearTempGrids();
redrawGrids();
}
function stopAsking(checkbox)
{
g_appSettings.stopAskingVersion = checkbox.checked;
}
function toggleGtShareEnable()
{
if (g_appSettings.gtShareEnable == true)
{
g_appSettings.gtShareEnable = false;
}
else g_appSettings.gtShareEnable = true;
setGtShareButtons();
}
function setGtShareButtons()
{
if (g_appSettings.gtShareEnable == true && g_mapSettings.offlineMode == false)
{
if (g_appSettings.gtMsgEnable == true) { msgButton.style.display = "inline-block"; }
else msgButton.style.display = "none";
gtFlagButton.style.display = "inline-block";
if (g_appSettings.gtFlagImgSrc > 0)
{
g_layerVectors.gtflags.setVisible(true);
}
else
{
g_layerVectors.gtflags.setVisible(false);
}
}
else
{
g_oamsBandActivityData = null;
renderBandActivity();
msgButton.style.display = "none";
gtFlagButton.style.display = "none";
g_layerVectors.gtflags.setVisible(false);
clearGtFlags();
// Clear list
g_gtFlagPins = Object()
g_gtMessages = Object();
g_gtUnread = Object();
g_gtCallsigns = Object();
g_gtSentAwayToCid = Object();
if (g_chatWindowHandle != null)
{
try
{
g_chatWindowHandle.hide();
g_chatWindowHandle.window.allCallDiv.innerHTML = "";
g_chatWindowHandle.window.updateCount();
}
catch (e)
{
console.error(e);
}
}
goProcessRoster();
}
gtShareFlagImg.src = g_gtShareFlagImageArray[g_appSettings.gtShareEnable == false ? 0 : 1];
}
function setMulticastIp()
{
g_appSettings.wsjtIP = multicastIpInput.value;
}
function setMulticastEnable(checkbox)
{
if (checkbox.checked == true)
{
multicastTD.style.display = "block";
if (ValidateMulticast(multicastIpInput))
{
g_appSettings.wsjtIP = multicastIpInput.value;
}
else
{
g_appSettings.wsjtIP = "";
}
}
else
{
multicastTD.style.display = "none";
g_appSettings.wsjtIP = "";
}
g_appSettings.multicast = checkbox.checked;
}
function setUdpForwardEnable(checkbox)
{
if (checkbox.checked)
{
if (
ValidatePort(
udpForwardPortInput,
null,
CheckForwardPortIsNotReceivePort
) &&
ValidateIPaddress(udpForwardIpInput, null)
)
{
g_appSettings.wsjtForwardUdpEnable = checkbox.checked;
return;
}
}
checkbox.checked = false;
g_appSettings.wsjtForwardUdpEnable = checkbox.checked;
}
function setGTspotEnable(checkbox)
{
g_appSettings.gtSpotEnable = checkbox.checked;
if (g_appSettings.gtSpotEnable == false)
{
g_spotCollector = {};
g_spotDetailsCollector = {};
g_decodeCollector = {};
}
g_gtLiveStatusUpdate = true;
}
function setOamsBandActivity(checkbox)
{
g_appSettings.oamsBandActivity = checkbox.checked;
if (g_appSettings.oamsBandActivity == false)
{
bandActivityNeighborDiv.style.display = "none";
g_oamsBandActivityData = null;
}
else
{
bandActivityNeighborDiv.style.display = "";
oamsBandActivityCheck();
}
renderBandActivity();
}
function setOamsBandActivityNeighbors(checkbox)
{
g_appSettings.oamsBandActivityNeighbors = checkbox.checked;
oamsBandActivityCheck();
}
function setMsgEnable(checkbox)
{
g_appSettings.gtMsgEnable = checkbox.checked;
if (g_appSettings.gtShareEnable == true)
{
if (g_appSettings.gtMsgEnable == true) { msgButton.style.display = "inline-block"; }
else
{
msgButton.style.display = "none";
if (g_chatWindowHandle != null)
{
g_chatWindowHandle.hide();
}
}
}
g_gtLiveStatusUpdate = true;
setMsgSettingsView();
}
function newMessageSetting(whichSetting)
{
if (whichSetting.id in g_msgSettings)
{
g_msgSettings[whichSetting.id] = whichSetting.value;
localStorage.msgSettings = JSON.stringify(g_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 (g_mapSettings.offlineMode == false)
{
getBuffer(
"https://storage.googleapis.com/gt_app/acknowledgements.json",
updateAcks,
null,
"http",
80
);
nodeTimers.setTimeout(downloadAcknowledgements, 8640000);
}
}
var g_non_us_bands = [
"630m",
"160m",
"80m",
"60m",
"40m",
"30m",
"20m",
"17m",
"15m",
"12m",
"10m",
"6m",
"4m",
"2m"
];
var g_us_bands = [
"630m",
"160m",
"80m",
"60m",
"40m",
"30m",
"20m",
"17m",
"15m",
"12m",
"10m",
"6m",
"2m"
];
function renderBandActivity()
{
var buffer = "";
if (typeof g_bandActivity.lines[myMode] != "undefined" || g_oamsBandActivityData != null)
{
var lines = (myMode in g_bandActivity.lines) ? g_bandActivity.lines[myMode] : [];
var bands = (g_myDXCC in g_callsignDatabaseUSplus) ? g_us_bands : g_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 = Number(Number(values[0]) / 1000000).formatBand();
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 (g_appSettings.gtShareEnable == true && g_appSettings.oamsBandActivity == true && g_oamsBandActivityData)
{
for (const grid in g_oamsBandActivityData)
{
for (const band in g_oamsBandActivityData[grid])
{
if (band in bandData)
{
var place = bandData[band];
place.oamsDecodes += g_oamsBandActivityData[grid][band].d;
place.oamsRxSpots += g_oamsBandActivityData[grid][band].rS;
place.oamsTxSpots += g_oamsBandActivityData[grid][band].tS;
place.oamsTx += g_oamsBandActivityData[grid][band].t;
place.oamsRx += g_oamsBandActivityData[grid][band].r
if (place.oamsRx > 0)
{
place.oamsScore = parseInt((place.oamsDecodes > place.oamsRxSpots) ? ((place.oamsDecodes - place.oamsRxSpots) / place.oamsRx) + (place.oamsTxSpots * place.oamsTx) : (place.oamsRxSpots / place.oamsRx) + (place.oamsTxSpots * place.oamsTx));
}
else
{
place.oamsScore = parseInt(place.oamsTxSpots * place.oamsTx);
}
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 == myBand) ? " class='myBand' " : "";
let title;
let blueBarValue;
if (g_appSettings.gtShareEnable == true && g_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 += "<div title='" + title + "' style='display:inline-block;margin:1px;' class='aBand'>";
buffer += "<div style='height: " + (bandData[band].pskScore * scaleFactor + 1) + "px;' class='barTx'></div>"; buffer += "<div style='height: " + blueBarValue + "px;' class='barRx'></div>";
buffer += "<div style='font-size:10px' " + blockMyBand + ">" + parseInt(band) + "</div>";
buffer += "</div>";
}
}
else
{
buffer = "..no data yet..";
}
graphDiv.innerHTML = buffer;
if (g_baWindowInitialized == true)
{
g_baWindowHandle.window.graphDiv.innerHTML = buffer;
}
}
function pskBandActivityCallback(buffer, flag)
{
var result = String(buffer);
if (result.indexOf("frequency score") > -1)
{
// looks good so far
g_bandActivity.lines[myMode] = result.split("\n");
g_bandActivity.lastUpdate[myMode] = g_timeNow + 600;
localStorage.bandActivity = JSON.stringify(g_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.
************************************************************************************
*/
function pskGetBandActivity()
{
if (g_mapSettings.offlineMode == true) return;
if (typeof g_bandActivity.lastUpdate[myMode] == "undefined")
{
g_bandActivity.lastUpdate[myMode] = 0;
}
if (myMode.length > 0 && myDEGrid.length > 0 && g_timeNow > g_bandActivity.lastUpdate[myMode])
{
getBuffer(
"https://pskreporter.info/cgi-bin/psk-freq.pl?mode=" +
myMode +
"&grid=" +
myDEGrid.substr(0, 4),
pskBandActivityCallback,
null,
"https",
443
);
}
renderBandActivity();
if (g_pskBandActivityTimerHandle != null)
{
nodeTimers.clearInterval(g_pskBandActivityTimerHandle);
}
g_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 (g_platform == "windows")
{
end = data.indexOf("GridTracker\\User Data\\Default");
if (end > -1)
{
wsjtxCfgPath = data.substr(0, end) + appName + "\\" + appName + ".ini";
}
}
else if (g_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 = Number(portSplit[1] / 1000000).formatBand();
}
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 =
g_platform == "windows"
? child_process.execFileSync("tasklist.exe")
: child_process.execFileSync("ps", ["-aef"]);
g_wsjtxProcessRunning = list.indexOf("wsjtx") > -1;
g_jtdxProcessRunning = list.indexOf("jtdx") > -1;
}
function updateRunningProcesses()
{
try
{
checkRunningProcesses();
}
catch (e)
{
g_wsjtxProcessRunning = false;
g_jtdxProcessRunning = false;
}
runningAppsDiv.innerHTML = "WSJT-X ";
if (g_wsjtxProcessRunning == true) runningAppsDiv.innerHTML += " - up - ";
else runningAppsDiv.innerHTML += " - ? - ";
g_wsjtxIni = getIniFromApp("WSJT-X");
if (g_wsjtxIni.port > -1)
{
runningAppsDiv.innerHTML +=
"<b>(" + g_wsjtxIni.ip + " / " + g_wsjtxIni.port + ")</b> ";
}
else runningAppsDiv.innerHTML += "<b>(?)</b> ";
if (g_platform != "mac")
{
runningAppsDiv.innerHTML += " / JTDX ";
if (g_jtdxProcessRunning == true) runningAppsDiv.innerHTML += " - up - ";
else runningAppsDiv.innerHTML += " - ? - ";
g_jtdxIni = getIniFromApp("JTDX");
if (g_jtdxIni.port > -1)
{
runningAppsDiv.innerHTML +=
"<b>(" + g_jtdxIni.ip + " / " + g_jtdxIni.port + ")</b> ";
}
else runningAppsDiv.innerHTML += "<b>(?)</b> ";
}
}
function updateBasedOnIni()
{
var which = null;
var count = 0;
if (g_wsjtxProcessRunning)
{
count++;
}
if (g_jtdxProcessRunning)
{
count++;
}
// UdpPortNotSet
if (g_appSettings.wsjtUdpPort == 0 && count < 2)
{
if (g_wsjtxProcessRunning || count == 0)
{
which = g_wsjtxIni;
}
else if (g_jtdxProcessRunning)
{
which = g_jtdxIni;
}
if (which != null && which.port > -1)
{
g_appSettings.wsjtUdpPort = which.port;
g_appSettings.wsjtIP = which.ip;
}
if (which == null)
{
g_appSettings.wsjtUdpPort = 2237;
g_appSettings.wsjtIP = "";
}
if (ipToInt(g_appSettings.wsjtIP) >= ipToInt("224.0.0.0") && ipToInt(g_appSettings.wsjtIP) < ipToInt("240.0.0.0"))
{
g_appSettings.multicast = true;
}
else
{
g_appSettings.multicast = false;
}
}
// Which INI do we load?
if (g_appSettings.wsjtUdpPort)
{
which = null;
if (g_wsjtxIni.port == g_appSettings.wsjtUdpPort)
{
which = g_wsjtxIni;
}
else if (g_jtdxIni.port == g_appSettings.wsjtUdpPort)
{
which = g_jtdxIni;
}
if (which != null)
{
myDEcall = which.MyCall;
myDEGrid = which.MyGrid;
g_lastBand = myBand;
g_lastMode = myMode;
g_workingIniPath = which.IniPath;
}
if (which != null && which.BroadcastToN1MM == true && g_N1MMSettings.enable == true)
{
if (which.N1MMServer == g_N1MMSettings.ip && which.N1MMServerPort == g_N1MMSettings.port)
{
buttonN1MMCheckBox.checked = g_N1MMSettings.enable = false;
localStorage.N1MMSettings = JSON.stringify(g_N1MMSettings);
alert(which.appName + " N1MM Logger+ is enabled with same settings, disabled GridTracker N1MM logger");
}
}
if (which != null)
{
if (g_appSettings.wsjtIP == "")
{
g_appSettings.wsjtIP = which.ip;
}
}
}
if (myDEGrid.length > 0)
{
setHomeGridsquare();
}
else
{
alert("Location not available!\nEither start WSJT-X/JTDX or enter your grid square in settings");
}
}
function CheckReceivePortIsNotForwardPort(value)
{
if (udpForwardIpInput.value == "127.0.0.1" && udpForwardPortInput.value == value && g_appSettings.wsjtIP == "" && udpForwardEnable.checked)
{
return false;
}
return true;
}
function CheckForwardPortIsNotReceivePort(value)
{
if (udpForwardIpInput.value == "127.0.0.1" && udpPortInput.value == value && g_appSettings.wsjtIP == "")
{
return false;
}
return true;
}
function setForwardIp()
{
g_appSettings.wsjtForwardUdpIp = udpForwardIpInput.value;
if (ValidatePort(udpPortInput, null, CheckReceivePortIsNotForwardPort))
{
setUdpPort();
}
ValidatePort(udpForwardPortInput, null, CheckForwardPortIsNotReceivePort);
}
function setForwardPort()
{
g_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)
{
g_appSettings.workingCallsignEnable = ele.checked;
applyCallsignsAndDateDiv.style.display = "";
}
function workingDateEnableChanged(ele)
{
g_appSettings.workingDateEnable = ele.checked;
applyCallsignsAndDateDiv.style.display = "";
}
function workingDateChanged()
{
var fields = workingDateValue.value.split("-");
var date = new Date(
Date.UTC(
parseInt(fields[0]),
parseInt(fields[1]) - 1,
parseInt(fields[2]),
0,
0,
0
)
);
g_appSettings.workingDate =
Date.UTC(
parseInt(fields[0]),
parseInt(fields[1]) - 1,
parseInt(fields[2]),
0,
0,
0
) / 1000;
displayWorkingDate();
applyCallsignsAndDateDiv.style.display = "";
}
function displayWorkingDate()
{
var date = new Date(g_appSettings.workingDate * 1000);
workingDateString.innerHTML = dateToString(date);
}
var g_tempWorkingCallsigns = {};
function workingCallsignsChanged(ele)
{
g_tempWorkingCallsigns = {};
var callsigns = ele.value.split(",");
for (var call in callsigns)
{
g_tempWorkingCallsigns[callsigns[call]] = true;
}
if (callsigns.length > 0)
{
g_appSettings.workingCallsigns = Object.assign({}, g_tempWorkingCallsigns);
if (g_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);
}
}
var g_lastUrl = "";
function newFrame(frame, url, policy)
{
if (url != g_lastUrl)
{
nw.Shell.openExternal(url);
g_lastUrl = url;
nodeTimers.setTimeout(clearLastUrlTimeOut, 5000);
}
policy.ignore();
}
function clearLastUrlTimeOut()
{
g_lastUrl = "";
}
function byName(a, b)
{
if (g_enums[a] < g_enums[b]) return -1;
if (g_enums[a] > g_enums[b]) return 1;
return 0;
}
var 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 g_directCallToDXCC) { return Number(g_directCallToDXCC[callsign]); }
if (callsign.includes("/"))
{
var parts = callsign.split("/");
var end = parts.length - 1;
if (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 g_directCallToDXCC) { return Number(g_directCallToDXCC[callsign]); }
}
for (var x = callsign.length; x > 0; x--)
{
if (callsign.substr(0, x) in g_prefixToMap)
{
return Number(g_dxccInfo[g_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 g_directCallToCQzone) { return g_directCallToCQzone[callsign]; }
for (var x = callsign.length; x > 0; x--)
{
if (callsign.substr(0, x) in g_prefixToCQzone)
{
return g_prefixToCQzone[callsign.substr(0, x)];
}
}
if (dxcc > 0)
{
return g_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 g_directCallToITUzone) { return g_directCallToITUzone[callsign]; }
for (var x = callsign.length; x > 0; x--)
{
if (callsign.substr(0, x) in g_prefixToITUzone)
{
return g_prefixToITUzone[callsign.substr(0, x)];
}
}
if (dxcc > 0)
{
return g_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");
g_dxccInfo = JSON.parse(fileBuf);
for (var key in g_dxccInfo)
{
g_dxccToAltName[g_dxccInfo[key].dxcc] = g_dxccInfo[key].name;
g_dxccToADIFName[g_dxccInfo[key].dxcc] = g_dxccInfo[key].aname;
for (var x = 0; x < g_dxccInfo[key].prefix.length; x++)
{
g_prefixToMap[g_dxccInfo[key].prefix[x]] = key;
}
delete g_dxccInfo[key].prefix;
for (var x = 0; x < g_dxccInfo[key].direct.length; x++)
{
g_directCallToDXCC[g_dxccInfo[key].direct[x]] = g_dxccInfo[key].dxcc;
}
delete g_dxccInfo[key].direct;
for (var val in g_dxccInfo[key].prefixCQ)
{
g_prefixToCQzone[val] = g_dxccInfo[key].prefixCQ[val];
}
delete g_dxccInfo[key].prefixCQ;
for (var val in g_dxccInfo[key].prefixITU)
{
g_prefixToITUzone[val] = g_dxccInfo[key].prefixITU[val];
}
delete g_dxccInfo[key].prefixITU;
for (var val in g_dxccInfo[key].directCQ)
{
g_directCallToCQzone[val] = g_dxccInfo[key].directCQ[val];
}
delete g_dxccInfo[key].directCQ;
for (var val in g_dxccInfo[key].directITU)
{
g_directCallToITUzone[val] = g_dxccInfo[key].directITU[val];
}
delete g_dxccInfo[key].directITU;
for (var x = 0; x < g_dxccInfo[key].mh.length; x++)
{
if (!(g_dxccInfo[key].mh[x] in g_gridToDXCC)) { g_gridToDXCC[g_dxccInfo[key].mh[x]] = Array(); }
g_gridToDXCC[g_dxccInfo[key].mh[x]].push(g_dxccInfo[key].dxcc);
}
if (g_dxccInfo[key].dxcc != 291) { delete g_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;
g_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 g_stateToCounty)) { g_stateToCounty[countyData[id].properties.st] = Array(); }
g_stateToCounty[countyData[id].properties.st].push(id);
var cnty = countyData[id].properties.st + "," + countyData[id].properties.n.toUpperCase().replaceAll(" ", "");
if (!(cnty in g_cntyToCounty)) { g_cntyToCounty[cnty] = countyData[id].properties.n.toProperCase(); }
g_countyData[cnty] = {};
g_countyData[cnty].geo = countyData[id];
g_countyData[cnty].worked = false;
g_countyData[cnty].confirmed = false;
g_countyData[cnty].worked_bands = {};
g_countyData[cnty].confirmed_bands = {};
g_countyData[cnty].worked_modes = {};
g_countyData[cnty].confirmed_modes = {};
for (var x in countyData[id].properties.z)
{
var zipS = String(countyData[id].properties.z[x]);
if (!(zipS in g_zipToCounty))
{
g_zipToCounty[zipS] = Array();
}
g_zipToCounty[zipS].push(cnty);
}
}
files = null;
countyData = null;
g_shapeData = JSON.parse(fs.readFileSync(g_shapeFile));
g_StateData = JSON.parse(fs.readFileSync("./data/state.json"));
for (var key in g_StateData)
{
for (var x = 0; x < g_StateData[key].mh.length; x++)
{
if (!(g_StateData[key].mh[x] in g_gridToState)) { g_gridToState[g_StateData[key].mh[x]] = Array(); }
g_gridToState[g_StateData[key].mh[x]].push(g_StateData[key].postal);
}
}
file = "./data/phone.json";
fileBuf = fs.readFileSync(file, "UTF-8");
g_phonetics = JSON.parse(fileBuf);
file = "./data/enums.json";
fileBuf = fs.readFileSync(file, "UTF-8");
g_enums = JSON.parse(fileBuf);
for (var key in g_dxccInfo)
{
if (g_dxccInfo[key].pp != "" && g_dxccInfo[key].geo != "deleted")
{
g_enums[g_dxccInfo[key].dxcc] = g_dxccInfo[key].name;
}
if (key == 291)
{
// US Mainland
for (var mh in g_dxccInfo[key].mh)
{
var sqr = g_dxccInfo[key].mh[mh];
g_us48Data[sqr] = {};
g_us48Data[sqr].name = sqr;
g_us48Data[sqr].worked = false;
g_us48Data[sqr].confirmed = false;
g_us48Data[sqr].worked_bands = {};
g_us48Data[sqr].confirmed_bands = {};
g_us48Data[sqr].worked_modes = {};
g_us48Data[sqr].confirmed_modes = {};
}
delete g_dxccInfo[key].mh;
}
}
fileBuf = fs.readFileSync("./data/cqzone.json");
g_cqZones = JSON.parse(fileBuf);
fileBuf = fs.readFileSync("./data/ituzone.json");
g_ituZones = JSON.parse(fileBuf);
for (var key in g_StateData)
{
if (key.substr(0, 3) == "US-")
{
var shapeKey = key.substr(3, 2);
var name = g_StateData[key].name;
if (shapeKey in g_shapeData)
{
g_wasZones[name] = {};
g_wasZones[name].geo = g_shapeData[shapeKey];
g_wasZones[name].worked = false;
g_wasZones[name].confirmed = false;
g_wasZones[name].worked_bands = {};
g_wasZones[name].confirmed_bands = {};
g_wasZones[name].worked_modes = {};
g_wasZones[name].confirmed_modes = {};
}
}
}
for (var key in g_shapeData)
{
if (g_shapeData[key].properties.type == "Continent")
{
var name = g_shapeData[key].properties.name;
g_wacZones[name] = {};
g_wacZones[name].geo = g_shapeData[key];
g_wacZones[name].worked = false;
g_wacZones[name].confirmed = false;
g_wacZones[name].worked_bands = {};
g_wacZones[name].confirmed_bands = {};
g_wacZones[name].worked_modes = {};
g_wacZones[name].confirmed_modes = {};
}
}
}
var localeDxcc = "./i18n/" + g_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 g_dxccInfo)
{
g_dxccInfo[dxcc].name = langDxcc[dxcc];
g_dxccToAltName[dxcc] = langDxcc[dxcc];
}
}
}
}
var localeState = "./i18n/" + g_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 g_StateData)
{
g_StateData[state].name = langState[state];
}
}
}
}
}
var g_timezonesEnable = 0;
var g_timezoneLayer = null;
function createZoneLayer()
{
g_timezoneLayer = createGeoJsonLayer(
"tz",
"./data/combined-with-oceans.json",
"#000088FF",
0.5
);
g_map.addLayer(g_timezoneLayer);
g_timezoneLayer.setVisible(false);
}
function toggleTimezones()
{
if (g_currentOverlay != 0) return;
g_timezonesEnable ^= 1;
mouseOutGtFlag();
if (g_timezonesEnable == 1)
{
if (g_timezoneLayer == null)
{
createZoneLayer();
}
g_timezoneLayer.setVisible(true);
}
else
{
if (g_timezoneLayer != null)
{
g_map.removeLayer(g_timezoneLayer);
g_timezoneLayer = null;
}
}
timezoneImg.style.filter = g_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);
g_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);
g_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),
name: 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);
g_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);
g_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.<br />Go there now?<br /><br />";
versionDiv.style.display = "block";
}
else
{
if (flag)
{
if (gtVersion < betaVersion)
{
var verString = String(betaVersion);
main.style.display = "none";
newVersionMustDownloadDiv.innerHTML =
"New <b><i>Beta</i></b> Version v" +
verString.substr(0, 1) +
"." +
verString.substr(1, 2) +
"." +
verString.substr(3) +
" available for download.<br />Go there now?<br /><br />";
versionDiv.style.display = "block";
}
else
{
main.style.display = "none";
upToDateDiv.style.display = "block";
}
}
}
}
}
}
function updateAcks(buffer)
{
try
{
g_acknowledgedCalls = JSON.parse(buffer);
}
catch (e)
{
// can't write, somethings broke
}
}
function readAcksFromDisk()
{
try
{
var fileBuf = fs.readFileSync(g_NWappData + "acknowledgements.json");
var loadedData = JSON.parse(fileBuf);
// some validation here?
g_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": gtVersionString }
};
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
}
};
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 != "undefined")
{
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()
{
g_mapHue = colorToHex(hueDiv.style.backgroundColor);
if (g_mapHue == "#000000") g_mapHue = 0;
}
function loadMapSettings()
{
shadowValue.value = g_mapSettings.shadow;
showDarknessTd.innerHTML = parseInt(shadowValue.value * 100) + "%";
pathWidthTd.innerHTML = pathWidthValue.value = g_appSettings.pathWidthWeight;
qrzPathWidthTd.innerHTML = qrzPathWidthValue.value =
g_appSettings.qrzPathWidthWeight;
gridDecay.value = g_appSettings.gridsquareDecayTime;
changeGridDecay();
pathColorValue.value = g_mapSettings.pathColor;
qrzPathColorValue.value = g_mapSettings.qrzPathColor;
brightnessValue.value = g_mapSettings.loudness;
nightBrightnessValue.value = g_mapSettings.nightLoudness;
nightPathColorValue.value = g_mapSettings.nightPathColor;
nightQrzPathColorValue.value = g_mapSettings.nightQrzPathColor;
mouseOverValue.checked = g_mapSettings.mouseOver;
mergeOverlayValue.checked = g_mapSettings.mergeOverlay;
offlineImg.src = g_mapImageArray[g_mapSettings.offlineMode ? 0 : 1];
mapSelect.value = g_mapSettings.mapIndex;
mapNightSelect.value = g_mapSettings.nightMapIndex;
animateValue.checked = g_mapSettings.animate;
animateSpeedValue.value = 21 - g_mapSettings.animateSpeed;
setAnimateView();
splitQSLValue.checked = g_mapSettings.splitQSL;
fitQRZvalue.checked = g_mapSettings.fitQRZ;
qrzDxccFallbackValue.checked = g_mapSettings.qrzDxccFallback;
CqHiliteValue.checked = g_mapSettings.CQhilite;
focusRigValue.checked = g_mapSettings.focusRig;
haltAllOnTxValue.checked = g_mapSettings.haltAllOnTx;
trafficDecode.checked = g_mapSettings.trafficDecode;
setSpotImage();
timezoneImg.style.filter = g_timezonesEnable == 1 ? "" : "grayscale(1)";
radarImg.style.filter = g_mapSettings.usNexrad ? "" : "grayscale(1)";
gridOverlayImg.style.filter = g_showAllGrids ? "" : "grayscale(1)";
g_bandToColor = JSON.parse(JSON.stringify(g_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()
{
g_appSettings.distanceUnit = distanceUnit.value;
g_scaleLine.setUnits(g_scaleUnits[g_appSettings.distanceUnit]);
goProcessRoster();
}
function changeMapNightValues()
{
g_mapSettings.nightPathColor = nightPathColorValue.value;
g_mapSettings.nightQrzPathColor = nightQrzPathColorValue.value;
g_mapSettings.nightMapIndex = mapNightSelect.value;
g_mapSettings.nightLoudness = nightBrightnessValue.value;
saveMapSettings();
setNightHtml();
changeMapLayer();
}
function setNightHtml()
{
var pathColor =
g_mapSettings.nightPathColor == 0
? "#000"
: g_mapSettings.nightPathColor == 361
? "#FFF"
: "hsl(" + g_mapSettings.nightPathColor + ", 100%, 50%)";
if (g_mapSettings.nightPathColor != 0)
{
pathNightColorDiv.style.color = "#000";
pathNightColorDiv.style.backgroundColor = pathColor;
}
else
{
pathNightColorDiv.style.color = "#FFF";
pathNightColorDiv.style.backgroundColor = pathColor;
}
pathColor =
g_mapSettings.nightQrzPathColor == 0
? "#000"
: g_mapSettings.nightQrzPathColor == 361
? "#FFF"
: "hsl(" + g_mapSettings.nightQrzPathColor + ", 100%, 50%)";
if (g_mapSettings.nightQrzPathColor != 0)
{
pathNightQrzColorDiv.style.color = "#000";
pathNightQrzColorDiv.style.backgroundColor = pathColor;
}
else
{
pathNightQrzColorDiv.style.color = "#FFF";
pathNightQrzColorDiv.style.backgroundColor = pathColor;
}
}
function changeMapValues()
{
g_mapSettings.pathColor = pathColorValue.value;
g_mapSettings.qrzPathColor = qrzPathColorValue.value;
g_mapSettings.loudness = brightnessValue.value;
g_mapSettings.mapIndex = mapSelect.value;
if (g_appSettings.gtFlagImgSrc > 0 && g_mapSettings.offlineMode == false && g_appSettings.gtShareEnable == true)
{
g_layerVectors.gtflags.setVisible(true);
}
else
{
g_layerVectors.gtflags.setVisible(false);
}
saveMapSettings();
saveAlertSettings();
var pathColor =
g_mapSettings.pathColor == 0
? "#000"
: g_mapSettings.pathColor == 361
? "#FFF"
: "hsl(" + g_mapSettings.pathColor + ", 100%, 50%)";
if (g_mapSettings.pathColor != 0)
{
pathColorDiv.style.color = "#000";
pathColorDiv.style.backgroundColor = pathColor;
}
else
{
pathColorDiv.style.color = "#FFF";
pathColorDiv.style.backgroundColor = pathColor;
}
pathColor =
g_mapSettings.qrzPathColor == 0
? "#000"
: g_mapSettings.qrzPathColor == 361
? "#FFF"
: "hsl(" + g_mapSettings.qrzPathColor + ", 100%, 50%)";
if (g_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 g_legendColors)
{
setLegendColor(key, g_legendColors[key]);
setLegendGrid(key, g_legendColors[key]);
}
}
function resetLegendColors()
{
for (var key in def_legendColors)
{
g_legendColors[key] = def_legendColors[key];
}
setLegendAndGridSettings();
saveLegendColors();
redrawGrids();
}
var g_redrawFromLegendTimeoutHandle = null;
function changeLegendColor(source)
{
var newColor = source.value;
var name = source.id.replace("gridValue", "");
setLegendColor(name, newColor);
g_legendColors[name] = newColor;
if (g_redrawFromLegendTimeoutHandle != null)
{
nodeTimers.clearTimeout(g_redrawFromLegendTimeoutHandle);
}
g_redrawFromLegendTimeoutHandle = nodeTimers.setTimeout(redrawGrids, 500);
}
function toggleLegend()
{
if (g_mapSettings.legend == true) g_mapSettings.legend = false;
else g_mapSettings.legend = true;
saveMapSettings();
displayLegend();
}
function hideLegend()
{
LegendDiv.style.display = "none";
}
function displayLegend()
{
if (g_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 (g_mapSettings.offlineMode)
{
g_tileLayer.setSource(g_offlineLayer);
g_tileLayer.setOpacity(Number(g_mapSettings.loudness));
}
else
{
if (g_mapSettings.nightMapEnable && g_nightTime)
{
g_tileLayer.setSource(g_mapsLayer[g_mapSettings.nightMapIndex]);
g_tileLayer.setOpacity(Number(g_mapSettings.nightLoudness));
}
else
{
g_tileLayer.setSource(g_mapsLayer[g_mapSettings.mapIndex]);
g_tileLayer.setOpacity(Number(g_mapSettings.loudness));
}
}
changePathWidth();
redrawSpots();
redrawParks();
}
function voiceChangedValue()
{
g_speechSettings.voice = Number(alertVoiceInput.value) + 1;
changeSpeechValues();
}
function timedGetVoices()
{
g_voices = window.speechSynthesis.getVoices();
if (g_voices.length > 0)
{
var newSelect = document.createElement("select");
newSelect.id = "alertVoiceInput";
newSelect.title = "Select Voice";
for (var i = 0; i < g_voices.length; i++)
{
var option = document.createElement("option");
option.value = i;
newstring = g_voices[i].name.replace(/ /g, "");
option.text = newstring;
if (g_voices[i].default)
{
option.selected = true;
}
newSelect.appendChild(option);
}
newSelect.oninput = voiceChangedValue;
voicesDiv.appendChild(newSelect);
}
g_speechAvailable = true;
loadAlerts();
}
function initSpeech()
{
window.speechSynthesis.onvoiceschanged = function ()
{
nodeTimers.setTimeout(timedGetVoices, 500);
};
var msg = new SpeechSynthesisUtterance(".");
msg.lang = g_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 = g_soundCard;
}
function soundCardChangedValue()
{
g_appSettings.soundCard = g_soundCard = soundCardInput.value;
playTestFile();
}
function setPins()
{
g_colorLeafletPins = {};
g_colorLeafleteQPins = {};
g_colorLeafletQPins.worked = {};
g_colorLeafletQPins.confirmed = {};
for (var i = 0; i < g_colorBands.length; i++)
{
var pin = new ol.style.Icon({
src: "./img/pin/" + g_colorBands[i] + ".png",
anchorYUnits: "pixels",
anchorXUnits: "pixels",
anchor: [5, 18]
});
g_colorLeafletPins[g_colorBands[i]] = pin;
pin = new ol.style.Icon({
src: "./img/pin/" + g_colorBands[i] + "w.png",
anchorYUnits: "pixels",
anchorXUnits: "pixels",
anchor: [5, 18]
});
g_colorLeafletQPins.worked[g_colorBands[i]] = pin;
pin = new ol.style.Icon({
src: "./img/pin/" + g_colorBands[i] + "q.png",
anchorYUnits: "pixels",
anchorXUnits: "pixels",
anchor: [5, 18]
});
g_colorLeafletQPins.confirmed[g_colorBands[i]] = pin;
}
}
function changeClearOnCQ()
{
g_appSettings.clearOnCQ = clearOnCQ.checked;
saveAppSettings();
}
function loadViewSettings()
{
gtBandFilter.value = g_appSettings.gtBandFilter;
gtModeFilter.value = g_appSettings.gtModeFilter;
gtPropFilter.value = g_appSettings.gtPropFilter;
distanceUnit.value = g_appSettings.distanceUnit;
languageLocale.value = g_appSettings.locale;
N1MMIpInput.value = g_N1MMSettings.ip;
N1MMPortInput.value = g_N1MMSettings.port;
buttonN1MMCheckBox.checked = g_N1MMSettings.enable;
ValidatePort(N1MMPortInput, buttonN1MMCheckBox, null);
ValidateIPaddress(N1MMIpInput, buttonN1MMCheckBox, null);
log4OMIpInput.value = g_log4OMSettings.ip;
log4OMPortInput.value = g_log4OMSettings.port;
buttonLog4OMCheckBox.checked = g_log4OMSettings.enable;
ValidatePort(log4OMPortInput, buttonLog4OMCheckBox, null);
ValidateIPaddress(log4OMIpInput, buttonLog4OMCheckBox, null);
acLogIpInput.value = g_acLogSettings.ip;
acLogPortInput.value = g_acLogSettings.port;
buttonacLogCheckBox.checked = g_acLogSettings.enable;
ValidatePort(acLogPortInput, buttonacLogCheckBox, null);
ValidateIPaddress(acLogIpInput, buttonacLogCheckBox, null);
dxkLogIpInput.value = g_dxkLogSettings.ip;
dxkLogPortInput.value = g_dxkLogSettings.port;
buttondxkLogCheckBox.checked = g_dxkLogSettings.enable;
ValidatePort(dxkLogPortInput, buttondxkLogCheckBox, null);
ValidateIPaddress(dxkLogIpInput, buttondxkLogCheckBox, null);
hrdLogbookIpInput.value = g_HRDLogbookLogSettings.ip;
hrdLogbookPortInput.value = g_HRDLogbookLogSettings.port;
buttonHrdLogbookCheckBox.checked = g_HRDLogbookLogSettings.enable;
ValidatePort(hrdLogbookPortInput, buttonHrdLogbookCheckBox, null);
ValidateIPaddress(hrdLogbookIpInput, buttonHrdLogbookCheckBox, null);
pstrotatorIpInput.value = g_pstrotatorSettings.ip;
pstrotatorPortInput.value = g_pstrotatorSettings.port;
pstrotatorCheckBox.checked = g_pstrotatorSettings.enable;
ValidatePort(pstrotatorPortInput, pstrotatorCheckBox, null);
ValidateIPaddress(pstrotatorIpInput, pstrotatorCheckBox, null);
spotHistoryTimeValue.value = parseInt(
g_receptionSettings.viewHistoryTimeSec / 60
);
spotHistoryTimeTd.innerHTML =
"Max Age: " + Number(g_receptionSettings.viewHistoryTimeSec).toDHM();
spotPathsValue.checked = g_receptionSettings.viewPaths;
spotPathColorValue.value = g_receptionSettings.pathColor;
spotNightPathColorValue.value = g_receptionSettings.pathNightColor;
spotWidthTd.innerHTML = spotWidthValue.value = g_receptionSettings.spotWidth;
spotMergeValue.checked = g_receptionSettings.mergeSpots;
lookupOnTx.checked = g_appSettings.lookupOnTx;
lookupCallookPreferred.checked = g_appSettings.lookupCallookPreferred;
lookupCloseLog.checked = g_appSettings.lookupCloseLog;
lookupMerge.checked = g_appSettings.lookupMerge;
lookupMissingGrid.checked = g_appSettings.lookupMissingGrid;
clearOnCQ.checked = g_appSettings.clearOnCQ;
if (g_appSettings.lookupMerge == true)
{
lookupMissingGridDiv.style.display = "inline-block";
}
else
{
lookupMissingGridDiv.style.display = "none";
}
if (g_receptionSettings.viewPaths)
{
spotPathWidthDiv.style.display = "inline-block";
}
else
{
spotPathWidthDiv.style.display = "none";
}
spotPathChange();
setLegendAndGridSettings();
}
function loadMsgSettings()
{
msgEnable.checked = g_appSettings.gtMsgEnable;
GTspotEnable.checked = g_appSettings.gtSpotEnable;
oamsBandActivity.checked = g_appSettings.oamsBandActivity;
oamsBandActivityNeighbors.checked = g_appSettings.oamsBandActivityNeighbors;
setOamsBandActivity(oamsBandActivity);
setSpotImage();
for (var key in g_msgSettings)
{
document.getElementById(key).value = g_msgSettings[key];
}
ValidateText(msgAwayText);
setMsgSettingsView();
}
function setMsgSettingsView()
{
if (msgEnable.checked) msgSettingsDiv.style.display = "inline-block";
else msgSettingsDiv.style.display = "none";
if (g_msgSettings.msgAlertSelect > 0)
{
msgFrequencySelectDiv.style.display = "inline-block";
if (g_msgSettings.msgAlertSelect == 1)
{
msgAlertWord.style.display = "inline-block";
msgAlertMedia.style.display = "none";
ValidateText(msgAlertWord);
}
if (g_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 (g_msgSettings.msgAwaySelect > 0) { msgAwayTextDiv.style.display = "inline-block"; }
else msgAwayTextDiv.style.display = "none";
}
function loadAdifSettings()
{
workingCallsignEnable.checked = g_appSettings.workingCallsignEnable;
workingCallsignsValue.value = Object.keys(
g_appSettings.workingCallsigns
).join(",");
ValidateCallsigns(workingCallsignsValue);
workingDateEnable.checked = g_appSettings.workingDateEnable;
displayWorkingDate();
if (g_platform == "mac")
{
selectTQSLButton.style.display = "none";
}
for (var key in g_adifLogSettings.menu)
{
var value = g_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 g_adifLogSettings.startup)
{
if (document.getElementById(key) != null) { document.getElementById(key).checked = g_adifLogSettings.startup[key]; }
}
for (var key in g_adifLogSettings.nickname)
{
if (document.getElementById(key) != null)
{
document.getElementById(key).checked = g_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 g_adifLogSettings.text)
{
if (document.getElementById(key) != null)
{
document.getElementById(key).value = g_adifLogSettings.text[key];
ValidateText(document.getElementById(key));
}
}
for (var key in g_adifLogSettings.qsolog)
{
if (document.getElementById(key) != null)
{
document.getElementById(key).checked = g_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 == "" && myRawCall != "NOCALL")
{
clubCall.value = myRawCall;
ValidateText(clubCall);
localStorage.adifLogSettings = JSON.stringify(g_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 (!g_developerMode)
{
document.body.addEventListener("contextmenu", function (ev)
{
ev.preventDefault();
});
}
imSureCheck.checked = false;
stopAskingCheckbox.checked = g_appSettings.stopAskingVersion;
if (stopAskingCheckbox.checked == false)
{
checkForNewVersion();
nodeTimers.setInterval(checkForNewVersion, 86400000);
}
}
function startupButtonsAndInputs()
{
try
{
g_pushPinMode = !(g_appSettings.pushPinMode == true);
togglePushPinMode();
udpForwardEnable.checked = g_appSettings.wsjtForwardUdpEnable;
multicastEnable.checked = g_appSettings.multicast;
gridViewButton.innerHTML = g_gridViewArray[g_appSettings.gridViewMode];
earthImg.src = g_earthShadowImageArray[g_appSettings.earthImgSrc];
gtFlagImg.src = g_gtFlagImageArray[g_appSettings.gtFlagImgSrc % 2];
gtShareFlagImg.src =
g_gtShareFlagImageArray[g_appSettings.gtShareEnable == false ? 0 : 1];
alertMuteImg.src = g_alertImageArray[g_appSettings.alertMute];
modeImg.src = g_maidenheadModeImageArray[g_appSettings.sixWideMode];
if (g_appSettings.centerGridsquare.length > 0)
{
homeQTHInput.value = g_appSettings.centerGridsquare.substr(0, 6);
if (ValidateGridsquare(homeQTHInput, null)) setCenterGridsquare();
}
ValidateCallsign(alertValueInput, null);
if (g_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);
}
var g_finishedLoading = false;
function postInit()
{
setGridViewMode(g_appSettings.gridViewMode);
redrawSpots();
checkForSettings();
updateForwardListener();
addLastTraffic("GridTracker</br>" + gtShortVersion);
g_nexradEnable = g_mapSettings.usNexrad ? 0 : 1;
toggleNexrad();
if (String(gtVersion) != String(g_startVersion))
{
// generalbut.className = "settingsTablinks";
showSettingsBox();
openSettingsTab(updatebut, "updateSettingsDiv");
}
g_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);
openCallRosterWindow(false);
openConditionsWindow(false);
showMessaging(false);
if (g_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 (g_finishedLoading == true) dropHandler(event);
});
var g_startupTable = [
[startupVersionInit, "Completed Version Check"],
[loadi18n, "Loading Locales"],
[qsoBackupFileInit, "QSO Backup Initialized"],
[callsignServicesInit, "Callsign Services Initialized"],
[loadMapSettings, "Map Settings Initialized"],
[initMap, "Loaded Map"],
[setPins, "Created Pins"],
[loadViewSettings, "Loaded View Settings"],
[loadMsgSettings, "Loaded Messaging Settings"],
[setFileSelectors, "Set File Selectors"],
[lockNewWindows, "Locked New Windows"],
[loadMaidenHeadData, "Loaded Maidenhead Dataset"],
[drawAllGrids, "Rendered All Maidenhead Grids"],
[updateRunningProcesses, "Updated Running Processes"],
[updateBasedOnIni, "Updated from WSJT-X/JTDX"],
[loadAdifSettings, "Loaded ADIF Settings"],
[startupButtonsAndInputs, "Buttons and Inputs Initialized"],
[initSpeech, "Speech Initialized"],
[initSoundCards, "Sounds Initialized"],
[loadPortSettings, "Loaded Network Settings"],
[loadLookupDetails, "Callsign Lookup Details Loaded"],
[renderLocale, "Rendering Locale"],
[startupEventsAndTimers, "Set Events and Timers"],
[registerHotKeys, "Registered Hotkeys"],
[gtChatSystemInit, "Chat System Initialized"],
[initPota, "POTA Initialized"],
[downloadAcknowledgements, "Contributor Acknowledgements Loaded"],
[postInit, "Finalizing System"]
];
function init()
{
startupVersionDiv.innerHTML = gtVersionString;
aboutVersionDiv.innerHTML = gtVersionString;
g_currentDay = parseInt(timeNowSec() / 86400);
if (mediaCheck() == false)
{
startupDiv.style.display = "none";
documentsDiv.style.display = "block";
searchedDocFolder.innerHTML = g_appData;
}
else
{
documentsDiv.style.display = "none";
startupDiv.style.display = "block";
startupStatusDiv.innerHTML = "Starting...";
nodeTimers.setTimeout(startupEngine, 32);
}
}
function startupEngine()
{
if (g_startupTable.length > 0)
{
var funcInfo = g_startupTable.shift();
funcInfo[0]();
startupStatusDiv.innerHTML = funcInfo[1];
nodeTimers.setTimeout(startupEngine, 32);
}
else
{
startupStatusDiv.innerHTML = "Completed";
setTimeout(endStartup, 2000);
startupAdifLoadCheck();
openStatsWindow(false);
}
}
function directoryInput(what)
{
g_appSettings.savedAppData = what.files[0].path;
init();
}
function endStartup()
{
startupDiv.style.display = "none";
main.style.display = "block";
g_map.updateSize();
}
function loadPortSettings()
{
multicastEnable.checked = g_appSettings.multicast;
multicastIpInput.value = g_appSettings.wsjtIP;
setMulticastEnable(multicastEnable);
udpPortInput.value = g_appSettings.wsjtUdpPort;
ValidatePort(udpPortInput, null, CheckReceivePortIsNotForwardPort);
udpForwardPortInput.value = g_appSettings.wsjtForwardUdpPort;
ValidatePort(udpForwardPortInput, null, CheckForwardPortIsNotReceivePort);
udpForwardIpInput.value = g_appSettings.wsjtForwardUdpIp;
ValidateIPaddress(udpForwardIpInput, null);
udpForwardEnable.checked = g_appSettings.wsjtForwardUdpEnable;
setUdpForwardEnable(udpForwardEnable);
}
var g_wsjtCurrentPort = -1;
var g_wsjtUdpServer = null;
var g_wsjtUdpSocketReady = false;
var g_wsjtUdpSocketError = false;
var g_qtToSplice = 0;
function decodeQUINT8(byteArray)
{
g_qtToSplice = 1;
return byteArray[0];
}
function encodeQBOOL(byteArray, offset, value)
{
return byteArray.writeUInt8(value, offset);
}
function decodeQUINT32(byteArray)
{
g_qtToSplice = 4;
return byteArray.readUInt32BE(0);
}
function encodeQUINT32(byteArray, offset, value)
{
if (value == -1) value = 4294967295;
return byteArray.writeUInt32BE(value, offset);
}
function decodeQINT32(byteArray)
{
g_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];
}
g_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(g_qtToSplice);
if (utf8_len == 0xffffffff) utf8_len = 0;
else result = byteArray.slice(0, utf8_len);
g_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)
{
g_qtToSplice = 8;
return byteArray.readDoubleBE(0);
}
function encodeQDOUBLE(byteArray, offset, value)
{
return byteArray.writeDoubleBE(value, offset);
}
var g_forwardUdpServer = null;
function updateForwardListener()
{
if (g_forwardUdpServer != null)
{
g_forwardUdpServer.close();
}
if (g_closing == true) return;
var dgram = require("dgram");
g_forwardUdpServer = dgram.createSocket({
type: "udp4",
reuseAddr: true
});
g_forwardUdpServer.on("listening", function () { });
g_forwardUdpServer.on("error", function ()
{
g_forwardUdpServer.close();
g_forwardUdpServer = null;
});
g_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(g_qtToSplice);
if (newMessage.magic_key == 0xadbccbda)
{
newMessage.schema_number = decodeQUINT32(message);
message = message.slice(g_qtToSplice);
newMessage.type = decodeQUINT32(message);
message = message.slice(g_qtToSplice);
newMessage.Id = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
var instanceId = newMessage.Id;
if (instanceId in g_instances)
{
wsjtUdpMessage(
originalMessage,
originalMessage.length,
g_instances[instanceId].remote.port,
g_instances[instanceId].remote.address
);
}
}
});
g_forwardUdpServer.bind(0);
}
function sendForwardUdpMessage(msg, length, port, address)
{
if (g_forwardUdpServer)
{
g_forwardUdpServer.send(msg, 0, length, port, address);
}
}
function wsjtUdpMessage(msg, length, port, address)
{
if (g_wsjtUdpServer)
{
g_wsjtUdpServer.send(msg, 0, length, port, address);
}
}
function checkWsjtxListener()
{
if (
g_wsjtUdpServer == null ||
(g_wsjtUdpSocketReady == false && g_wsjtUdpSocketError == true)
)
{
g_wsjtCurrentPort = -1;
g_wsjtCurrentIP = "none";
}
updateWsjtxListener(g_appSettings.wsjtUdpPort);
}
var g_instances = {};
var g_instancesIndex = Array();
var g_activeInstance = "";
var g_activeIndex = 0;
var g_currentID = null;
function updateWsjtxListener(port)
{
if (port == g_wsjtCurrentPort && g_appSettings.wsjtIP == g_wsjtCurrentIP) { return; }
if (g_wsjtUdpServer != null)
{
if (multicastEnable.checked == true && g_appSettings.wsjtIP != "")
{
try
{
g_wsjtUdpServer.dropMembership(g_appSettings.wsjtIP);
}
catch (e)
{
console.error(e);
}
}
g_wsjtUdpServer.close();
g_wsjtUdpServer = null;
g_wsjtUdpSocketReady = false;
}
if (g_closing == true) return;
g_wsjtUdpSocketError = false;
var dgram = require("dgram");
g_wsjtUdpServer = dgram.createSocket({
type: "udp4",
reuseAddr: true
});
if (multicastEnable.checked == true && g_appSettings.wsjtIP != "")
{
g_wsjtUdpServer.on("listening", function ()
{
var address = g_wsjtUdpServer.address();
g_wsjtUdpServer.setBroadcast(true);
g_wsjtUdpServer.setMulticastTTL(128);
g_wsjtUdpServer.addMembership(g_appSettings.wsjtIP);
g_wsjtUdpSocketReady = true;
});
}
else
{
g_appSettings.multicast = false;
g_wsjtCurrentIP = g_appSettings.wsjtIP = "";
g_wsjtUdpServer.on("listening", function ()
{
g_wsjtUdpServer.setBroadcast(true);
g_wsjtUdpSocketReady = true;
});
}
g_wsjtUdpServer.on("error", function ()
{
g_wsjtUdpServer.close();
g_wsjtUdpServer = null;
g_wsjtUdpSocketReady = false;
g_wsjtUdpSocketError = true;
});
g_wsjtUdpServer.on("message", function (message, remote)
{
// if (g_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(g_qtToSplice);
if (newMessage.magic_key == 0xadbccbda)
{
newMessage.schema_number = decodeQUINT32(message);
message = message.slice(g_qtToSplice);
newMessage.type = decodeQUINT32(message);
message = message.slice(g_qtToSplice);
newMessage.Id = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
var instanceId = newMessage.Id;
if (!(instanceId in g_instances))
{
g_instances[instanceId] = {};
g_instances[instanceId].valid = false;
g_instancesIndex.push(instanceId);
g_instances[instanceId].intId = g_instancesIndex.length - 1;
g_instances[instanceId].crEnable = true;
g_instances[instanceId].oldStatus = null;
g_instances[instanceId].status = null;
if (g_instancesIndex.length > 1)
{
multiRigCRDiv.style.display = "inline-block";
haltTXDiv.style.display = "inline-block";
}
updateRosterInstances();
}
var notify = false;
if (g_instances[instanceId].open == false) notify = true;
g_instances[instanceId].open = true;
g_instances[instanceId].remote = remote;
if (notify) updateRosterInstances();
if (newMessage.type == 1)
{
newMessage.event = "Status";
newMessage.Frequency = decodeQUINT64(message);
newMessage.Band = Number(newMessage.Frequency / 1000000).formatBand();
message = message.slice(g_qtToSplice);
newMessage.MO = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
newMessage.DXcall = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
newMessage.Report = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
newMessage.TxMode = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
newMessage.TxEnabled = decodeQUINT8(message);
message = message.slice(g_qtToSplice);
newMessage.Transmitting = decodeQUINT8(message);
message = message.slice(g_qtToSplice);
newMessage.Decoding = decodeQUINT8(message);
message = message.slice(g_qtToSplice);
newMessage.RxDF = decodeQINT32(message);
message = message.slice(g_qtToSplice);
newMessage.TxDF = decodeQINT32(message);
message = message.slice(g_qtToSplice);
newMessage.DEcall = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
newMessage.DEgrid = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
newMessage.DXgrid = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
newMessage.TxWatchdog = decodeQUINT8(message);
message = message.slice(g_qtToSplice);
newMessage.Submode = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
newMessage.Fastmode = decodeQUINT8(message);
message = message.slice(g_qtToSplice);
if (message.length > 0)
{
newMessage.SopMode = decodeQUINT8(message);
message = message.slice(g_qtToSplice);
}
else
{
newMessage.SopMode = -1;
}
if (message.length > 0)
{
newMessage.FreqTol = decodeQINT32(message);
message = message.slice(g_qtToSplice);
}
else
{
newMessage.FreqTol = -1;
}
if (message.length > 0)
{
newMessage.TRP = decodeQINT32(message);
message = message.slice(g_qtToSplice);
}
else
{
newMessage.TRP = -1;
}
if (message.length > 0)
{
newMessage.ConfName = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
}
else
{
newMessage.ConfName = null;
}
if (message.length > 0)
{
newMessage.TxMessage = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
}
else
{
newMessage.TxMessage = null;
}
g_instances[instanceId].oldStatus = g_instances[instanceId].status;
g_instances[instanceId].status = newMessage;
g_instances[instanceId].valid = true;
}
if (g_instances[instanceId].valid == true)
{
if (newMessage.type == 2)
{
newMessage.event = "Decode";
newMessage.NW = decodeQUINT8(message);
message = message.slice(g_qtToSplice);
newMessage.TM = decodeQUINT32(message);
message = message.slice(g_qtToSplice);
newMessage.SR = decodeQINT32(message);
message = message.slice(g_qtToSplice);
newMessage.DT = decodeQDOUBLE(message);
message = message.slice(g_qtToSplice);
newMessage.DF = decodeQUINT32(message);
message = message.slice(g_qtToSplice);
newMessage.MO = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
newMessage.Msg = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
newMessage.LC = decodeQUINT8(message);
message = message.slice(g_qtToSplice);
newMessage.OA = decodeQUINT8(message);
message = message.slice(g_qtToSplice);
newMessage.OF = g_instances[instanceId].status.Frequency;
newMessage.OC = g_instances[instanceId].status.DEcall;
newMessage.OG = g_instances[instanceId].status.DEgrid;
newMessage.OM = g_instances[instanceId].status.MO;
newMessage.OB = g_instances[instanceId].status.Band;
newMessage.SP = g_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(g_qtToSplice);
newMessage.TimeOff = decodeQUINT32(message);
message = message.slice(g_qtToSplice);
newMessage.timespecOff = decodeQUINT8(message);
message = message.slice(g_qtToSplice);
if (newMessage.timespecOff == 2)
{
newMessage.offsetOff = decodeQINT32(message);
message = message.slice(g_qtToSplice);
}
newMessage.DXCall = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
newMessage.DXGrid = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
newMessage.Frequency = decodeQUINT64(message);
message = message.slice(g_qtToSplice);
newMessage.MO = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
newMessage.ReportSend = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
newMessage.ReportRecieved = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
newMessage.TXPower = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
newMessage.Comments = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
newMessage.Name = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
newMessage.DateOn = decodeQUINT64(message);
message = message.slice(g_qtToSplice);
newMessage.TimeOn = decodeQUINT32(message);
message = message.slice(g_qtToSplice);
newMessage.timespecOn = decodeQUINT8(message);
message = message.slice(g_qtToSplice);
if (newMessage.timespecOn == 2)
{
newMessage.offsetOn = decodeQINT32(message);
message = message.slice(g_qtToSplice);
}
if (message.length > 0)
{
newMessage.Operatorcall = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
}
else newMessage.Operatorcall = "";
if (message.length > 0)
{
newMessage.Mycall = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
}
else newMessage.Mycall = "";
if (message.length > 0)
{
newMessage.Mygrid = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
}
else newMessage.Mygrid = "";
if (message.length > 0)
{
newMessage.ExchangeSent = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
}
else newMessage.ExchangeSent = "";
if (message.length > 0)
{
newMessage.ExchangeReceived = decodeQUTF8(message);
message = message.slice(g_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(g_qtToSplice);
newMessage.TM = decodeQUINT32(message);
message = message.slice(g_qtToSplice);
newMessage.SR = decodeQINT32(message);
message = message.slice(g_qtToSplice);
newMessage.DT = decodeQDOUBLE(message);
message = message.slice(g_qtToSplice);
newMessage.Frequency = decodeQUINT64(message);
message = message.slice(g_qtToSplice);
newMessage.Drift = decodeQINT32(message);
message = message.slice(g_qtToSplice);
newMessage.Callsign = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
newMessage.Grid = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
newMessage.Power = decodeQINT32(message);
message = message.slice(g_qtToSplice);
newMessage.OA = decodeQUINT8(message);
message = message.slice(g_qtToSplice);
newMessage.OF = g_instances[instanceId].status.Frequency;
newMessage.OC = g_instances[instanceId].status.DEcall;
newMessage.OG = g_instances[instanceId].status.DEgrid;
newMessage.OM = g_instances[instanceId].status.MO;
newMessage.OB = g_instances[instanceId].status.Band;
}
if (newMessage.type == 12)
{
newMessage.event = "ADIF";
newMessage.ADIF = decodeQUTF8(message);
message = message.slice(g_qtToSplice);
}
if (newMessage.type in g_wsjtHandlers)
{
newMessage.remote = remote;
newMessage.instance = instanceId;
lastMsgTimeDiv.innerHTML = "Received from " + newMessage.Id;
g_wsjtHandlers[newMessage.type](newMessage);
g_lastTimeSinceMessageInSeconds = parseInt(Date.now() / 1000);
}
}
}
});
g_wsjtUdpServer.bind(port);
g_wsjtCurrentPort = port;
g_wsjtCurrentIP = g_appSettings.wsjtIP;
}
function loadLookupDetails()
{
lookupService.value = g_appSettings.lookupService;
if (lookupService.value == "QRZ")
{
lookupLogin.value = g_appSettings.lookupLoginQrz;
lookupPassword.value = g_appSettings.lookupPasswordQrz;
}
if (lookupService.value == "QRZCQ")
{
lookupLogin.value = g_appSettings.lookupLoginCq;
lookupPassword.value = g_appSettings.lookupPasswordCq;
}
if (lookupService.value == "HAMQTH")
{
lookupLogin.value = g_appSettings.lookupLoginQth;
lookupPassword.value = g_appSettings.lookupPasswordQth;
}
ValidateText(lookupLogin);
ValidateText(lookupPassword);
if (lookupService.value == "CALLOOK") { lookupCredentials.style.display = "none"; }
else lookupCredentials.style.display = "block";
}
function lookupValueChanged(what)
{
if (g_appSettings.lookupService != lookupService.value)
{
g_lastLookupCallsign = "";
if (lookupService.value == "QRZ")
{
lookupLogin.value = g_appSettings.lookupLoginQrz;
lookupPassword.value = g_appSettings.lookupPasswordQrz;
}
if (lookupService.value == "QRZCQ")
{
lookupLogin.value = g_appSettings.lookupLoginCq;
lookupPassword.value = g_appSettings.lookupPasswordCq;
}
if (lookupService.value == "HAMQTH")
{
lookupLogin.value = g_appSettings.lookupLoginQth;
lookupPassword.value = g_appSettings.lookupPasswordQth;
}
}
g_appSettings.lookupService = lookupService.value;
g_appSettings.lookupCallookPreferred = lookupCallookPreferred.checked;
lookupQrzTestResult.innerHTML = "";
g_qrzLookupSessionId = null;
if (lookupService.value == "CALLOOK") { lookupCredentials.style.display = "none"; }
else lookupCredentials.style.display = "block";
if (ValidateText(lookupLogin) && ValidateText(lookupPassword))
{
if (lookupService.value == "QRZ")
{
g_appSettings.lookupLoginQrz = lookupLogin.value;
g_appSettings.lookupPasswordQrz = lookupPassword.value;
}
if (lookupService.value == "QRZCQ")
{
g_appSettings.lookupLoginCq = lookupLogin.value;
g_appSettings.lookupPasswordCq = lookupPassword.value;
}
if (lookupService.value == "HAMQTH")
{
g_appSettings.lookupLoginQth = lookupLogin.value;
g_appSettings.lookupPasswordQth = lookupPassword.value;
}
}
}
var g_lastLookupCallsign = "";
var g_lookupTimeout = null;
function lookupCallsign(callsign, gridPass, useCache = true)
{
if (g_mapSettings.offlineMode == true && useCache == false) return;
g_lastLookupCallsign = callsign;
if (g_lookupWindowHandle && g_lookupWindowInitialized)
{
g_lookupWindowHandle.window.lookupCallsignInput.value = callsign;
lookupValidateCallByElement("lookupCallsignInput");
}
if (g_lookupTimeout != null)
{
nodeTimers.clearTimeout(g_lookupTimeout);
g_lookupTimeout = null;
}
g_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 <font color='cyan'>" + callsign + "</font>, please wait..."
);
if (g_appSettings.lookupCallookPreferred)
{
var dxcc = callsignToDxcc(callsign);
var where;
var ccode = 0;
if (dxcc in g_dxccToAltName)
{
where = g_dxccToAltName[dxcc];
ccode = g_dxccInfo[dxcc].ccode;
}
else where = "Unknown";
if (ccode == 840)
{
getBuffer(
"https://callook.info/" + callsign + "/json",
callookResults,
gridPass,
"https",
443,
true
);
}
}
if (g_appSettings.lookupService != "CALLOOK")
{
g_qrzLookupCallsign = callsign;
g_qrzLookupGrid = gridPass;
if (
g_qrzLookupSessionId == null ||
timeNowSec() - g_sinceLastLookup > 3600
)
{
g_qrzLookupSessionId = null;
g_sinceLastLookup = timeNowSec();
GetSessionID(null, true);
}
else
{
g_sinceLastLookup = timeNowSec();
GetLookup(true);
}
}
else
{
var dxcc = callsignToDxcc(callsign);
var where;
var ccode = 0;
if (dxcc in g_dxccToAltName)
{
where = g_dxccToAltName[dxcc];
ccode = g_dxccInfo[dxcc].ccode;
}
else where = "Unknown";
if (ccode == 840)
{
getBuffer(
"https://callook.info/" + callsign + "/json",
callookResults,
gridPass,
"https",
443,
true
);
}
else
{
var worker =
"<center>C A L L O O K<br/>NO-NONSENSE AMATEUR RADIO U.S.A. CALLSIGN LOOKUPS<br/>are limited to United States and United States Territories Only<br/>";
worker +=
"<br/>The callsign <font color='orange'>" +
callsign +
"</font> requested is from <font color='yellow'>" +
where +
"</font><br/>";
worker +=
"<br/><br/>You might want to consider using QRZ.com, they have a free membership that provides limited data for most callsigns<br/>";
worker +=
"and they have full details available for paid members<br/></center>";
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 g_dxccToAltName) callObject.land = g_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 =
"<tr><td>Source</td><td><font color='orange'><b><div style='cursor:pointer' onClick='window.opener.openSite(\"https://callook.info/" +
results.current.callsign +
"\");'>C A L L O O K</div></b></font></td></tr>";
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");
}
var g_qrzLookupSessionId = null;
var g_qrzLookupCallsign = "";
var g_qrzLookupGrid = "";
var g_sinceLastLookup = 0;
function GetSessionID(resultTd, useCache)
{
if (g_mapSettings.offlineMode == true) return;
if (resultTd != null) resultTd.innerHTML = "Testing";
if (g_appSettings.lookupService == "QRZCQ")
{
getBuffer(
"https://ssl.qrzcq.com/xml?username=" +
g_appSettings.lookupLoginCq +
"&password=" +
encodeURIComponent(g_appSettings.lookupPasswordCq) +
"&agent=GridTracker1.18",
qrzGetSessionCallback,
resultTd,
"https",
443,
useCache
);
}
else if (g_appSettings.lookupService == "QRZ")
{
getBuffer(
"https://xmldata.qrz.com/xml/current/?username=" +
g_appSettings.lookupLoginQrz +
";password=" +
encodeURIComponent(g_appSettings.lookupPasswordQrz),
qrzGetSessionCallback,
resultTd,
"https",
443,
useCache
);
}
else
{
getBuffer(
"https://www.hamqth.com/xml.php?u=" +
g_appSettings.lookupLoginQth +
"&p=" +
encodeURIComponent(g_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 = "<font color='green'>Valid</font>";
g_qrzLookupSessionId = json.session.session_id;
}
else
{
result = "<font color='red'>" + json.session.error + "</font>";
g_qrzLookupSessionId = null;
}
}
else
{
result = "<font color='red'>Invalid Response</font>";
g_qrzLookupSessionId = null;
}
}
else
{
result = "<font color='red'>Unknown Error</font>";
g_qrzLookupSessionId = null;
}
if (resultTd == null)
{
// It's a true session Request
SessionResponse(g_qrzLookupSessionId, result);
}
else
{
g_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 = "<font color='green'>Valid</font>";
g_qrzLookupSessionId = json.Session.Key;
}
else
{
result = "<font color='red'>" + json.Session.Error + "</font>";
g_qrzLookupSessionId = null;
}
}
else
{
result = "<font color='red'>Invalid Response</font>";
g_qrzLookupSessionId = null;
}
}
else
{
result = "<font color='red'>Unknown Error</font>";
g_qrzLookupSessionId = null;
}
if (resultTd == null)
{
// It's a true session Request
SessionResponse(g_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 (g_appSettings.lookupService == "QRZCQ")
{
getBuffer(
"https://ssl.qrzcq.com/xml?s=" +
g_qrzLookupSessionId +
"&callsign=" +
g_qrzLookupCallsign +
"&agent=GridTracker",
qrzLookupResults,
g_qrzLookupGrid,
"https",
443,
useCache
);
}
else if (g_appSettings.lookupService == "QRZ")
{
getBuffer(
"http://xmldata.qrz.com/xml/current/?s=" +
g_qrzLookupSessionId +
";callsign=" +
g_qrzLookupCallsign,
qrzLookupResults,
g_qrzLookupGrid,
"http",
80,
useCache
);
}
else
{
getBuffer(
"https://www.hamqth.com/xml.php?id=" +
g_qrzLookupSessionId +
"&callsign=" +
g_qrzLookupCallsign +
"&prg=GridTracker",
qthHamLookupResults,
g_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 =
"<tr><td>Source</td><td><font color='orange'><b><div style='cursor:pointer' onClick='window.opener.openSite(\"https://www.hamqth.com/" +
json.search.callsign.toUpperCase() +
"\");'>HamQTH</div></b></font></td></tr>";
cacheLookupObject(json.search, gridPass, true);
}
else
{
g_qrzLookupSessionId = null;
setLookupDiv(
"lookupInfoDiv",
"<br/><b>No result for callsign</b><br/><br/>"
);
}
}
else
{
setLookupDiv("lookupInfoDiv", buffer);
g_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 (g_appSettings.lookupService == "QRZ")
{
json.Callsign.source =
"<tr><td>Source</td><td><font color='orange'><b><div style='cursor:pointer' onClick='window.opener.openSite(\"https://www.qrz.com/lookup?callsign=" +
call +
"\");'>QRZ.com</div></b></font></td></tr>";
}
else
{
json.Callsign.source =
"<tr><td>Source</td><td><font color='orange'><b><div style='cursor:pointer' onClick='window.opener.openSite(\"https://www.qrzcq.com/call/" +
call +
"\");'>QRZCQ.com</div></b></font></td></tr>";
}
if (gridPass) json.Callsign.gtGrid = gridPass;
cacheLookupObject(json.Callsign, gridPass, true);
}
else
{
setLookupDiv(
"lookupInfoDiv",
"<br/><b>No result for callsign</b><br/><br/>"
);
g_qrzLookupSessionId = null;
}
}
else
{
setLookupDiv("lookupInfoDiv", buffer);
g_qrzLookupSessionId = null;
}
}
var g_lastLookupAddress = null;
var g_Idb = null;
var g_Irequest = null;
function initialDatabases()
{
g_Irequest = window.indexedDB.open("GridTracker", 1);
g_Irequest.onerror = function (event)
{
alert(
"Database error: " +
event.target.errorCode +
" : GridTracker will have issues"
);
};
g_Irequest.onsuccess = function (event)
{
g_Idb = g_Irequest.result;
if (!g_Idb.objectStoreNames.contains("lookups"))
{
g_Idb.createObjectStore("lookups", { keyPath: "call" });
}
init();
};
g_Irequest.onupgradeneeded = function (event)
{
g_Idb = g_Irequest.result;
if (!g_Idb.objectStoreNames.contains("lookups"))
{
g_Idb.createObjectStore("lookups", { keyPath: "call" });
}
init();
};
}
function addLookupObjectToIndexedDB(lookupObject)
{
var request = g_Idb
.transaction(["lookups"], "readwrite")
.objectStore("lookups")
.put(lookupObject);
request.onerror = function (event)
{
addLastTraffic("<font style='color:orange'>Lookup Write Issue</font>");
};
}
function getLookupCachedObject(
call,
gridPass,
resultFunction = null,
noResultFunction = null,
callObject = null
)
{
var request = g_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;
g_Idb
.transaction(["lookups"], "readwrite")
.objectStore("lookups")
.delete(call);
}
if (callObject != null)
{
if (request.result != null)
{
callObject.cnty = request.result.cnty;
if (callObject.cnty in g_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 = lookup.county.toUpperCase().replaceAll(" ", "");
}
if (lookup.cnty in g_countyData)
{
for (const hash in g_liveCallsigns)
{
if (
g_liveCallsigns[hash].DEcall == lookup.call &&
g_liveCallsigns[hash].state == "US-" + lookup.state
)
{
g_liveCallsigns[hash].cnty = lookup.cnty;
g_liveCallsigns[hash].qual = true;
g_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 +=
"<table title='Click to copy address to clipboard' onclick='setClipboardFromLookup();' style='cursor:pointer' >";
worker += "<tr>";
worker += "<td style='font-size:36pt;color:cyan;font-weight:bold'>";
worker += getLookProp(lookup, "call").toUpperCase().formatCallsign();
worker += "</td>";
worker += "<td align='center' style='margin:0;padding:0'>";
if (lookup.dxcc > 0 && lookup.dxcc in g_dxccInfo)
{
worker +=
"<img style='padding-top:4px' src='./img/flags/24/" +
g_dxccInfo[lookup.dxcc].flag +
"'>";
}
worker += "</td>";
worker += "<td rowspan=6>";
var image = getLookProp(lookup, "image");
if (image.length > 0)
{
worker +=
"<img style='border:1px solid gray' class='roundBorder' width='220px' src='" +
image +
"'>";
}
worker += "</td>";
worker += "</tr>";
g_lastLookupAddress = "";
if (getLookProp(lookup, "addrAttn").length > 0)
{
worker += "<tr>";
worker += "<td>";
worker += getLookProp(lookup, "addrAttn");
g_lastLookupAddress += getLookProp(lookup, "addrAttn") + "\n";
worker += "</td>";
worker += "</tr>";
}
worker += "<tr>";
worker += "<td>";
worker += "<b>" + getLookProp(lookup, "name") + "</b>";
g_lastLookupAddress += getLookProp(lookup, "name") + "\n";
worker += "</td>";
worker += "</tr>";
worker += "<tr>";
worker += "<td>";
worker += getLookProp(lookup, "addr1");
g_lastLookupAddress += getLookProp(lookup, "addr1") + "\n";
worker += "</td>";
worker += "</tr>";
worker += "<tr>";
worker += "<td>";
worker += joinCommaIf(
getLookProp(lookup, "addr2"),
joinSpaceIf(getLookProp(lookup, "state"), getLookProp(lookup, "zip"))
);
g_lastLookupAddress +=
joinCommaIf(
getLookProp(lookup, "addr2"),
joinSpaceIf(getLookProp(lookup, "state"), getLookProp(lookup, "zip"))
) + "\n";
worker += "</td>";
worker += "</tr>";
worker += "<tr>";
worker += "<td>";
var country = getLookProp(lookup, "country");
worker += country;
g_lastLookupAddress += country + "\n";
worker += "</td>";
worker += "</tr>";
worker += "<tr>";
worker += "<td>";
var email = getLookProp(lookup, "email");
if (email.length > 0)
{
worker +=
"<div style='cursor:pointer;font-weight:bold;vertical-align:top' onclick='window.opener.mailThem(\"" +
email +
"\");'>" +
email +
"</div>";
g_lastLookupAddress += email + "\n";
}
worker += "</td>";
worker += "</tr>";
worker += "</table>";
var card =
"<div class='mapItem' id='callCard' style='top:0;padding:4px;'>" +
worker +
"</div>";
worker = "";
worker += "<table align='center' class='bioTable' >";
worker += "<tr><th colspan=2>Details</th></tr>";
if (getLookProp(lookup, "url").length > 0)
{
worker += "<tr>";
worker += "<td>Website</td>";
worker += "<td >";
worker +=
"<font color='orange'><b><div style='cursor:pointer' onClick='window.opener.openSite(\"" +
getLookProp(lookup, "url") +
"\");' >Link</div></b></font>";
worker += "</td>";
worker += "</tr>";
}
if (Number(getLookProp(lookup, "bio")) > 0)
{
worker += "<tr>";
worker += "<td>Biography</td>";
worker += "<td>";
worker +=
"<font color='orange'><b><div style='cursor:pointer' onClick='window.opener.openSite(\"https://www.qrz.com/db/" +
getLookProp(lookup, "call") +
"\");'>Link</div></b></font>";
worker += "</td>";
worker += "</tr>";
}
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 += "<tr><td>Effective Dates</td><td>" + dates + "</td></tr>";
}
var Aliases = joinCommaIf(
getLookProp(lookup, "aliases"),
getLookProp(lookup, "p_call")
);
if (Aliases.length > 0)
{
worker +=
"<tr title='" +
Aliases +
"' ><td>Aliases</td><td>" +
Aliases +
"</td></tr>";
}
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 +=
"<tr><td>DXCC</td><td>" +
getLookProp(lookup, "dxcc") + " - " + g_dxccToAltName[getLookProp(lookup, "dxcc")] +
"</td></tr>";
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 += "<tr><td>Distance</td><td style='color:cyan'>" +
parseInt(
MyCircle.distance(
g_myLat,
g_myLon,
Number(lookup.lat), Number(lookup.lon),
distanceUnit.value
) * MyCircle.validateRadius(distanceUnit.value)
) + distanceUnit.value.toLowerCase() + "</td></tr>";
var bearing = parseInt(MyCircle.bearing(g_myLat, g_myLon, Number(lookup.lat), Number(lookup.lon)));
worker += "<tr><td>Azimuth</td><td style='color:yellow'>" + bearing + "&deg;</td></tr>";
}
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 (g_callsignLookups.lotwUseEnable == true && thisCall in g_lotwCallsigns)
{
lookup.ulotw =
"&#10004; (" +
userDayString(g_lotwCallsigns[thisCall] * 86400 * 1000) +
")";
worker += makeRow("LoTW Member", lookup, "ulotw");
}
if (g_callsignLookups.eqslUseEnable == true && thisCall in g_eqslCallsigns)
{
lookup.ueqsl = "&#10004;";
worker += makeRow("eQSL Member", lookup, "ueqsl");
}
if (g_callsignLookups.oqrsUseEnable == true && thisCall in g_oqrsCallsigns)
{
lookup.uoqrs = "&#10004;";
worker += makeRow("ClubLog OQRS", lookup, "uoqrs");
}
if (fromCache)
{
worker +=
"<tr><td>Cached Record</td><td>" +
userTimeString(lookup.cached * 1000) +
"</td></tr>";
}
worker += "</table>";
var details =
"<div class='mapItem' id='callDetails' style='padding:4px;'>" +
worker +
"</div>";
var genMessage =
"<tr><td colspan=2><div title=\"Clear\" class=\"button\" onclick=\"window.opener.clearLookup();\" >Clear</div> <div title=\"Generate Messages\" class=\"button\" onclick=\"window.opener.setCallAndGrid('" +
getLookProp(lookup, "call") +
"','" +
getLookProp(lookup, "grid") +
"');\">Generate Messages</div></td></tr>";
setLookupDiv(
"lookupInfoDiv",
"<table align='center'><tr><td>" +
card +
"</td><td>" +
details +
"</td></tr>" +
genMessage +
"</table>"
);
setLookupDivHeight("lookupBoxDiv", getLookupWindowHeight() + "px");
}
function clearLookup()
{
if (g_lookupWindowHandle && g_lookupWindowInitialized)
{
g_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 "<tr><td>" + first + "</td><td>Yes</td></tr>";
if (test == "N") return "<tr><td>" + first + "</td><td>No</td></tr>";
if (test == "?") return "";
return (
"<tr><td>" +
first +
"</td><td>" +
(object[key] == 1 ? "Yes" : "No") +
"</td></tr>"
);
}
return "";
}
function makeRow(first, object, key, clip = false)
{
var value = getLookProp(object, key);
if (value.length > 0)
{
if (clip)
{
return (
"<tr><td>" +
first +
"</td><td title='Copy to clipboard' style='cursor:pointer;color:cyan;font-weight: bold;' onClick='addTextToClipboard(\"" +
object[key].substr(0, 45) +
"\")'>" +
object[key].substr(0, 45) +
"</td></tr>"
);
}
else
{
return (
"<tr><td>" +
first +
"</td><td>" +
object[key].substr(0, 45) +
"</td></tr>"
);
}
}
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(g_QSOhash)
.filter(function (value)
{
return value.DEcall == call;
})
.sort(myBandCompare);
var worker = ""
if (call in g_acknowledgedCalls)
{
worker = `<h3>GridTracker would like to acknowledge ${call}: ` +
`<img class='lookupAckBadge' src='${g_acknowledgedCalls[call].badge}'> ${g_acknowledgedCalls[call].message}</h3>`
}
if (list.length > 0)
{
var work = {};
var conf = {};
var lastTime = 0;
var lastRow = null;
var dxcc = list[0].dxcc;
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] = g_pskColors[list[row].band];
if (what in work) delete work[what];
}
else if (!(what in conf)) work[what] = g_pskColors[list[row].band];
}
worker +=
"<div class='mapItemNoSize'><table align='center' class='darkTable'>";
if (Object.keys(work).length > 0)
{
worker += "<tr><th style='color:yellow'>Worked</th><td>";
var k = Object.keys(work).sort();
for (var key in k)
{
worker += "<font color='#" + work[k[key]] + "'>" + k[key] + " </font>";
}
worker += "</td></tr>";
}
if (Object.keys(conf).length > 0)
{
worker += "<tr><th style='color:lightgreen'>Confirmed</th><td>";
var k = Object.keys(conf).sort();
for (var key in k)
{
worker += "<font color='#" + conf[k[key]] + "'>" + k[key] + " </font>";
}
worker += "</td></tr>";
}
if (lastRow)
{
worker += "<tr><th style='color:cyan'>Last QSO</th><td>";
worker +=
"<font color='#" +
g_pskColors[list[lastRow].band] +
"'>" +
list[lastRow].band +
"," +
list[lastRow].mode +
" </font> " +
userTimeString(list[lastRow].time * 1000);
worker += "</td></tr>";
}
worker +=
"<tr><th style='color:orange'>" +
g_dxccToAltName[dxcc] +
" (" +
g_dxccInfo[dxcc].pp +
")</th><td>";
for (var band in g_colorBands)
{
if (String(dxcc) + "|" + g_colorBands[band] in g_tracker.worked.dxcc)
{
var strike = "";
if (String(dxcc) + "|" + g_colorBands[band] in g_tracker.confirmed.dxcc) { strike = "text-decoration: underline overline;"; }
worker +=
"<div style='" +
strike +
"display:inline-block;color:#" +
g_pskColors[g_colorBands[band]] +
"'>" +
g_colorBands[band] +
"</div>&nbsp;";
}
}
worker += "</td></tr></table></div>";
}
setLookupDiv("lookupLocalDiv", worker);
list = null;
}
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 = (g_platform == "windows") ? process.env.USERPROFILE : process.env.HOME;
g_appData = path.join(homeDir, "OneDrive\\Dokumente");
if (!is_dir(g_appData))
{
g_appData = path.join(homeDir, "OneDrive\\Documents");
if (!is_dir(g_appData))
{
g_appData = path.join(homeDir, "Dokumente")
if (!is_dir(g_appData))
{
g_appData = path.join(homeDir, "Documents")
if (!is_dir(g_appData))
{
if (g_appSettings.savedAppData != null)
{
g_appData = g_appSettings.savedAppData;
if (!is_dir(g_appData)) return false;
}
else
{
return false;
}
}
}
}
}
g_appData = path.join(g_appData, "GridTracker");
g_userMediaDir = path.join(g_appData, "media");
g_jsonDir = path.join(g_appData, "data");
g_screenshotDir = path.join(g_appData, "screenshots");
g_scriptDir = path.join(g_appData, "scripts");
g_NWappData = path.join(nw.App.dataPath, "Ginternal");
try
{
var tryDirectory = "";
var userdirs = [
g_appData,
g_NWappData,
g_screenshotDir,
g_scriptDir,
g_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();
}
g_jsonDir += g_dirSeperator;
g_NWappData += g_dirSeperator;
g_screenshotDir += g_dirSeperator;
g_scriptDir += g_dirSeperator;
g_qsoLogFile = path.join(g_appData, "GridTracker_QSO.adif");
g_LoTWLogFile = path.join(g_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(g_userMediaDir, g_gtMediaDir);
// add all the files in both directories to the list, user filenames
// override system filenames later
var mediaFiles = [].concat(
fs.readdirSync(g_userMediaDir),
fs.readdirSync(g_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");
g_modes = JSON.parse(modeData);
for (var key in g_modes)
{
gtModeFilter.appendChild(newOption(key));
}
modeData = fs.readFileSync("./data/modes-phone.json");
g_modes_phone = JSON.parse(modeData);
initQSOdata();
g_QSOhash = {};
g_QSLcount = 0;
g_QSOcount = 0;
// Old log filenames, no longer referenced
tryToDeleteLog("lotw_QSL.adif");
tryToDeleteLog("lotw_QSO.adif");
tryToDeleteLog("lotw.adif");
try
{
if (fs.existsSync(g_NWappData + "internal_qso.json"))
{
var data = JSON.parse(fs.readFileSync(g_NWappData + "internal_qso.json"));
g_tracker = data.tracker;
if (typeof g_tracker.worked.px == "undefined")
{
g_tracker.worked.px = {};
g_tracker.confirmed.px = {};
}
if (typeof g_tracker.worked.pota == "undefined")
{
g_tracker.worked.pota = {};
g_tracker.confirmed.pota = {};
}
for (const i in data.g_QSOhash)
{
g_QSOhash[i] = fillObjectFromTemplate(def_qso, data.g_QSOhash[i]);
g_QSOcount++;
if (g_QSOhash[i].confirmed) g_QSLcount++;
}
fs.unlinkSync(g_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;
}
var g_rosterSpot = false;
function setRosterSpot(enabled)
{
g_rosterSpot = enabled;
}
function saveReceptionReports()
{
try
{
fs.writeFileSync(
g_NWappData + "spots.json",
JSON.stringify(g_receptionReports)
);
}
catch (e)
{
console.error(e);
}
}
function loadReceptionReports()
{
try
{
var clear = true;
if (fs.existsSync(g_NWappData + "spots.json"))
{
g_receptionReports = JSON.parse(
fs.readFileSync(g_NWappData + "spots.json")
);
if (timeNowSec() - g_receptionReports.lastDownloadTimeSec <= 86400) { clear = false; }
}
if (clear == true)
{
g_receptionReports = {
lastDownloadTimeSec: 0,
lastSequenceNumber: "0",
spots: {}
};
}
}
catch (e)
{
g_receptionReports = {
lastDownloadTimeSec: 0,
lastSequenceNumber: "0",
spots: {}
};
}
}
function pskSpotCheck(timeSec)
{
if (g_mapSettings.offlineMode == true) return;
if (myDEcall == null || myDEcall == "NOCALL" || myDEcall == "") return;
if (
(g_spotView > 0 || g_rosterSpot) &&
(g_receptionReports.lastDownloadTimeSec < g_lastTrasmissionTimeSec) &&
(
timeSec - g_receptionReports.lastDownloadTimeSec > PSKREPORTER_INTERVAL_IN_SECONDS ||
g_receptionReports.lastDownloadTimeSec > timeSec
)
)
{
g_receptionReports.lastDownloadTimeSec = timeSec;
localStorage.receptionSettings = JSON.stringify(g_receptionSettings);
spotRefreshDiv.innerHTML = "…refreshing…";
getBuffer(
`https://retrieve.pskreporter.info/query?rronly=1&lastseqno=${g_receptionReports.lastSequenceNumber}` +
`&senderCallsign=${encodeURIComponent(myRawCall)}` +
`&appcontact=${encodeURIComponent(`GT-${pjson.version}`)}`,
pskSpotResults,
null,
"https",
443
);
}
else if (g_spotView > 0)
{
if (
g_lastTrasmissionTimeSec < g_receptionReports.lastDownloadTimeSec &&
(timeSec - g_receptionReports.lastDownloadTimeSec) > PSKREPORTER_INTERVAL_IN_SECONDS
)
{
spotRefreshDiv.innerHTML = "No recent TX";
}
else
{
spotRefreshDiv.innerHTML =
"Refresh: " +
Number(PSKREPORTER_INTERVAL_IN_SECONDS - (timeSec - g_receptionReports.lastDownloadTimeSec)).toDHMS();
}
}
}
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)
{
g_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 = Number(parseInt(json.receptionReport[key].frequency) / 1000000).formatBand();
var hash = call + mode + band + grid.substr(0, 4);
if (hash in g_receptionReports.spots)
{
report = g_receptionReports.spots[hash];
if (parseInt(json.receptionReport[key].flowStartSeconds) < report.when) { continue; }
}
else
{
report = g_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;
}
}
}
}
}
g_receptionReports.lastDownloadTimeSec = timeNowSec();
localStorage.receptionSettings = JSON.stringify(g_receptionSettings);
redrawSpots();
if (g_rosterSpot) goProcessRoster();
}
var g_oamsSpotTimeout = null;
function addNewOAMSSpot(cid, db, frequency, band, mode)
{
if (g_oamsSpotTimeout !== null)
{
nodeTimers.clearTimeout(g_oamsSpotTimeout);
g_oamsSpotTimeout = null;
}
var report;
var call = g_gtFlagPins[cid].call;
var grid = g_gtFlagPins[cid].grid.substr(0, 6);
var hash = call + mode + band + grid.substr(0, 4);
if (hash in g_receptionReports.spots)
{
report = g_receptionReports.spots[hash];
}
else
{
report = g_receptionReports.spots[hash] = {};
report.call = call;
report.band = band;
report.grid = grid;
report.mode = mode;
}
report.dxcc = g_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;
g_oamsSpotTimeout = nodeTimers.setTimeout(redrawSpots, 250);
}
function spotFeature(center)
{
return new ol.Feature(
ol.geom.Polygon.circular(center, 30000, 63).transform(
"EPSG:4326",
"EPSG:3857"
)
);
}
var g_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 = "#" + g_bandToColor[report.band];
var colorAlpha = intAlphaToRGB(colorNoAlpha, report.color);
var spotColor = colorAlpha;
var workingColor = g_mapSettings.nightMapEnable && g_nightTime ? g_receptionSettings.pathNightColor : g_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.size = 6; // Mouseover detection
g_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
});
g_layerSources["psk-heat"].addFeature(pointFeature);
if (g_receptionSettings.viewPaths && g_receptionSettings.spotWidth > 0)
{
var strokeWeight = g_receptionSettings.spotWidth;
var flightColor =
workingColor == -1
? colorNoAlpha + "BB"
: g_mapSettings.nightMapEnable && g_nightTime
? g_spotNightFlightColor
: g_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();
g_spotTotalCount = 0;
g_layerSources["psk-spots"].clear();
g_layerSources["psk-flights"].clear();
g_layerSources["psk-hop"].clear();
g_layerSources["psk-heat"].clear();
var fromPoint = getPoint(myRawGrid);
if (g_receptionSettings.mergeSpots == false)
{
var spot = iconFeature(fromPoint, g_gtFlagIcon, 100);
g_layerSources["psk-spots"].addFeature(spot);
g_layerSources["psk-heat"].addFeature(spot);
}
for (var key in g_receptionReports.spots)
{
report = g_receptionReports.spots[key];
if ((now - report.when > 86400) || (report.grid.length < 4))
{
delete g_receptionReports.spots[key];
shouldSave = true;
continue;
}
if (validateMapBandAndMode(report.band, report.mode))
{
if (now - report.when <= g_receptionSettings.viewHistoryTimeSec)
{
createSpot(report, key, fromPoint);
g_spotTotalCount++;
}
}
}
if (shouldSave)
{
saveReceptionReports();
}
updateSpotCountDiv();
}
function updateSpotCountDiv()
{
spotCountDiv.innerHTML = "Spots: " + g_spotTotalCount;
}
var g_spotFlightColor = "#FFFFFFBB";
var g_spotNightFlightColor = "#FFFFFFBB";
function changeSpotValues()
{
g_receptionSettings.viewHistoryTimeSec = parseInt(spotHistoryTimeValue.value) * 60;
spotHistoryTimeTd.innerHTML = "Max Age: " + Number(g_receptionSettings.viewHistoryTimeSec).toDHM();
g_receptionSettings.viewPaths = spotPathsValue.checked;
if (g_receptionSettings.viewPaths)
{
spotPathWidthDiv.style.display = "inline-block";
}
else
{
spotPathWidthDiv.style.display = "none";
}
g_receptionSettings.mergeSpots = spotMergeValue.checked;
localStorage.receptionSettings = JSON.stringify(g_receptionSettings);
setTrophyOverlay(g_currentOverlay);
updateSpotView();
if (g_rosterSpot) goProcessRoster();
}
function mapTransChange()
{
g_mapSettings.mapTrans = mapTransValue.value;
mapTransTd.innerHTML = String(100 - parseInt(((g_mapSettings.mapTrans * 255) / 255) * 100)) + "%";
mapSettingsDiv.style.backgroundColor = "rgba(0,0,0, " + g_mapSettings.mapTrans + ")";
}
function spotPathChange()
{
g_receptionSettings.pathColor = spotPathColorValue.value;
var pathColor = g_receptionSettings.pathColor < 1
? "#000"
: g_receptionSettings.pathColor == 361
? "#FFF"
: "hsl(" + g_receptionSettings.pathColor + ", 100%, 50%)";
if (g_receptionSettings.pathColor > 0)
{
spotPathColorDiv.style.color = "#000";
spotPathColorDiv.style.backgroundColor = pathColor;
}
else
{
spotPathColorDiv.style.color = "#FFF";
spotPathColorDiv.style.backgroundColor = pathColor;
}
if (g_receptionSettings.pathColor == -1) { spotPathInfoTd.innerHTML = "PSK-Reporter Palette"; }
else spotPathInfoTd.innerHTML = "";
g_spotFlightColor =
g_receptionSettings.pathColor < 1
? "#0000000BB"
: g_receptionSettings.pathColor == 361
? "#FFFFFFBB"
: "hsla(" + g_receptionSettings.pathColor + ", 100%, 50%,0.73)";
g_receptionSettings.pathNightColor = spotNightPathColorValue.value;
var pathNightColor =
g_receptionSettings.pathNightColor < 1
? "#000"
: g_receptionSettings.pathNightColor == 361
? "#FFF"
: "hsl(" + g_receptionSettings.pathNightColor + ", 100%, 50%)";
if (g_receptionSettings.pathNightColor > 0)
{
spotNightPathColorDiv.style.color = "#000";
spotNightPathColorDiv.style.backgroundColor = pathNightColor;
}
else
{
spotNightPathColorDiv.style.color = "#FFF";
spotNightPathColorDiv.style.backgroundColor = pathNightColor;
}
if (g_receptionSettings.pathNightColor == -1) { spotNightPathInfoTd.innerHTML = "PSK-Reporter Palette"; }
else spotNightPathInfoTd.innerHTML = "";
g_spotNightFlightColor =
g_receptionSettings.pathNightColor < 1
? "#0000000BB"
: g_receptionSettings.pathNightColor == 361
? "#FFFFFFBB"
: "hsla(" + g_receptionSettings.pathNightColor + ", 100%, 50%,0.73)";
spotWidthTd.innerHTML = g_receptionSettings.spotWidth = spotWidthValue.value;
localStorage.receptionSettings = JSON.stringify(g_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;
g_receptionSettings.viewPaths = spotPathsValue.checked;
localStorage.receptionSettings = JSON.stringify(g_receptionSettings);
if (g_receptionSettings.viewPaths)
{
spotPathWidthDiv.style.display = "inline-block";
}
else
{
spotPathWidthDiv.style.display = "none";
}
redrawSpots();
}
function setSpotImage()
{
spotsButtonImg.src = g_spotImageArray[g_spotView];
spotsButtonImg.style.filter = (g_spotView == 0) ? "grayscale(1)" : "";
}
function cycleSpotsView()
{
g_spotView++;
g_spotView %= 3;
g_appSettings.spotView = g_spotView;
setSpotImage();
setTrophyOverlay(g_currentOverlay);
updateSpotView();
}
function toggleCRScript()
{
g_crScript ^= 1;
g_appSettings.crScript = g_crScript;
if (g_crScript == 1)
{
addLastTraffic(
"<font style='color:lightgreen'>Call Roster Script Enabled</font>"
);
}
else
{
addLastTraffic(
"<font style='color:yellow'>Call Roster Script Disabled</font>"
);
}
goProcessRoster();
}
function updateSpotView(leaveCount = true)
{
if (g_spotView > 0)
{
if (g_receptionSettings.mergeSpots == false)
{
for (var key in g_layerVectors)
{
g_layerVectors[key].setVisible(false);
}
}
if (g_spotView == 1)
{
g_layerVectors["psk-spots"].setVisible(true);
g_layerVectors["psk-flights"].setVisible(true);
g_layerVectors["psk-hop"].setVisible(true);
g_layerVectors["psk-heat"].setVisible(false);
}
else
{
g_layerVectors["psk-spots"].setVisible(false);
g_layerVectors["psk-flights"].setVisible(false);
g_layerVectors["psk-hop"].setVisible(false);
g_layerVectors["psk-heat"].setVisible(true);
}
SpotsDiv.style.display = "block";
if (leaveCount == false) spotRefreshDiv.innerHTML = "&nbsp;";
}
else
{
g_layerVectors["psk-spots"].setVisible(false);
g_layerVectors["psk-flights"].setVisible(false);
g_layerVectors["psk-hop"].setVisible(false);
g_layerVectors["psk-heat"].setVisible(false);
SpotsDiv.style.display = "none";
spotRefreshDiv.innerHTML = "&nbsp;";
}
}
function gotoDonate()
{
var gui = require("nw.gui");
gui.Shell.openExternal("https://gridtracker.org/donations/");
}
function getSpotTime(hash)
{
if (hash in g_receptionReports.spots)
{
return g_receptionReports.spots[hash];
}
else return null;
}
function setGridOpacity()
{
opacityValue.value = g_mapSettings.gridAlpha;
showOpacityTd.innerHTML =
parseInt((g_mapSettings.gridAlpha / 255) * 100) + "%";
g_gridAlpha = parseInt(g_mapSettings.gridAlpha).toString(16);
}
function changeGridOpacity()
{
g_mapSettings.gridAlpha = opacityValue.value;
showOpacityTd.innerHTML =
parseInt((g_mapSettings.gridAlpha / 255) * 100) + "%";
g_gridAlpha = parseInt(g_mapSettings.gridAlpha).toString(16);
saveMapSettings();
}
function currentTimeStampString()
{
var now = new Date();
return (
now.getFullYear() +
"-" +
(now.getMonth() + 1) +
"-" +
now.getDate() +
" " +
now.getHours().pad() +
"." +
now.getMinutes().pad() +
"." +
now.getSeconds().pad()
);
}
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 =
g_screenshotDir + "Screenshot " + currentTimeStampString() + ".png";
fs.writeFileSync(fn, buffer);
addLastTraffic(
"<font style='color:lightgreen;cursor:pointer;' onclick='showNativeFolder(\"" +
encodeURI(fn).trim() +
"\");''>Saved Screenshot</font>"
);
}
catch (e)
{
addLastTraffic(
"<font style='color:red'>Screenshot write failed</font>"
);
}
},
{ format: "png", datatype: "buffer" }
);
}
window.addEventListener("load", function ()
{
picker.attach({
target: "workingDateValue",
container: "pick-inline",
fire: "workingDateChanged"
});
});
function refreshSpotsNoTx()
{
redrawSpots();
}
nodeTimers.setInterval(refreshSpotsNoTx, 300000);
nodeTimers.setTimeout(refreshSpotsNoTx, 300000);