diff --git a/package.nw/lib/gt.js b/package.nw/lib/gt.js index fe6cedf..e4fd898 100644 --- a/package.nw/lib/gt.js +++ b/package.nw/lib/gt.js @@ -11165,13 +11165,18 @@ function checkForNewVersion(showUptoDate) function checkForNewAcks() { - getBuffer( - "http://app.gridtracker.org/acknowledgements.json?lang=" + g_localeString, - updateAcks, - null, - http, - 80 - ); + if (g_mapSettings.offlineMode == false) + { + getBuffer( + "http://app.gridtracker.org/acknowledgements.json", + updateAcks, + null, + "http", + 80 + ); + + setTimeout(downloadAcknowledgements, 8640000); + } } function renderBandActivity() @@ -12725,8 +12730,29 @@ function versionCheck(buffer, flag) function updateAcks(buffer) { - g_acks = JSON.parse(buffer); - fs.writeFileSync("./data/acknowledgements.json", JSON.stringify(g_acks)); + 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 + } } function onExitAppToGoWebsite() diff --git a/package.nw/lib/roster.js b/package.nw/lib/roster.js index 60d90fb..6d98b14 100644 --- a/package.nw/lib/roster.js +++ b/package.nw/lib/roster.js @@ -445,11 +445,1800 @@ function processRoster(roster) function viewRoster() { - var rosterSettings = prepareRosterSettings(); - processRosterFiltering(callRoster, rosterSettings); - processRosterHunting(callRoster, rosterSettings); - renderRoster(callRoster, rosterSettings); - sendAlerts(callRoster, rosterSettings); + var bands = Object(); + var modes = Object(); + + var callMode = g_rosterSettings.callsign; + var onlyHits = false; + var isAwardTracker = false; + + if (callMode == "hits") + { + callMode = "all"; + onlyHits = true; + } + if (referenceNeed.value == LOGBOOK_AWARD_TRACKER) + { + callMode = "all"; + onlyHits = false; + isAwardTracker = true; + g_rosterSettings.huntNeed = "confirmed"; + } + + var canMsg = + window.opener.g_mapSettings.offlineMode == false && + window.opener.g_appSettings.gtShareEnable == "true" && + window.opener.g_appSettings.gtMsgEnable == "true"; + + if (window.opener.g_callsignLookups.lotwUseEnable == true) + { + usesLoTWDiv.style.display = ""; + if (g_rosterSettings.usesLoTW == true) + { + maxLoTW.style.display = ""; + maxLoTWView.style.display = ""; + } + else + { + maxLoTW.style.display = "none"; + maxLoTWView.style.display = "none"; + } + } + else + { + usesLoTWDiv.style.display = "none"; + maxLoTW.style.display = "none"; + maxLoTWView.style.display = "none"; + } + + if (window.opener.g_callsignLookups.eqslUseEnable == true) useseQSLDiv.style.display = ""; + else useseQSLDiv.style.display = "none"; + + if (window.opener.g_callsignLookups.oqrsUseEnable == true) usesOQRSDiv.style.display = ""; + else usesOQRSDiv.style.display = "none"; + + if (g_rosterSettings.columns.Spot == true) onlySpotDiv.style.display = ""; + else onlySpotDiv.style.display = "none"; + + if (callMode == "all") allOnlyNewDiv.style.display = ""; + else allOnlyNewDiv.style.display = "none"; + + var huntIndex, workedIndex, layeredMode; + if (g_rosterSettings.huntNeed == "mixed") + { + huntIndex = g_confirmed; + workedIndex = g_worked; + layeredMode = LAYERED_MODE_FOR[String(g_rosterSettings.reference)]; + } + else if (g_rosterSettings.huntNeed == "worked") + { + huntIndex = g_worked; + workedIndex = false; + layeredMode = false; + } + else if (g_rosterSettings.huntNeed == "confirmed") + { + huntIndex = g_confirmed; + workedIndex = g_worked; + layeredMode = false; + } + else + { + huntIndex = false; + workedIndex = false; + layeredMode = false; + } + + var now = timeNowSec(); + + // First loop, exclude calls, mostly based on "Exceptions" settings + for (var callHash in callRoster) + { + var entry = callRoster[callHash]; + var callObj = entry.callObj; + + var call = entry.DEcall; + + entry.tx = true; + callObj.shouldAlert = false; + callObj.reason = Array(); + callObj.awardReason = "Callsign"; + + if (now - callObj.age > window.opener.g_mapSettings.rosterTime) + { + entry.tx = false; + entry.alerted = false; + callObj.qrz = false; + callObj.reset = true; + continue; + } + if (window.opener.g_instances[callObj.instance].crEnable == false) + { + entry.tx = false; + continue; + } + if (call in g_blockedCalls) + { + entry.tx = false; + continue; + } + if ( + entry.DXcall + " from All" in g_blockedCQ || + entry.DXcall + " from " + window.opener.g_dxccToAltName[callObj.dxcc] in g_blockedCQ + ) + { + entry.tx = false; + continue; + } + if (callObj.dxcc in g_blockedDxcc) + { + entry.tx = false; + continue; + } + if (g_rosterSettings.cqOnly == true && callObj.CQ == false) + { + entry.tx = false; + continue; + } + if (g_rosterSettings.useRegex && g_rosterSettings.callsignRegex.length > 0) + { + try + { + if (!call.match(g_rosterSettings.callsignRegex)) + { + entry.tx = false; + continue; + } + } + catch (e) {} + } + if (g_rosterSettings.requireGrid == true && callObj.grid.length != 4) + { + entry.tx = false; + continue; + } + if (g_rosterSettings.wantMinDB == true && entry.message.SR < g_rosterSettings.minDb) + { + entry.tx = false; + continue; + } + if (g_rosterSettings.wantMaxDT == true && Math.abs(entry.message.DT) > g_rosterSettings.maxDT) + { + entry.tx = false; + continue; + } + if (g_rosterSettings.wantMinFreq == true && entry.message.DF < g_rosterSettings.minFreq) + { + entry.tx = false; + continue; + } + if (g_rosterSettings.wantMaxFreq == true && entry.message.DF > g_rosterSettings.maxFreq) + { + entry.tx = false; + continue; + } + + if (g_rosterSettings.noMsg == true) + { + try + { + if (callObj.msg.match(g_rosterSettings.noMsgValue)) + { + entry.tx = false; + continue; + } + } + catch (e) {} + } + if (g_rosterSettings.onlyMsg == true) + { + try + { + if (!callObj.msg.match(g_rosterSettings.onlyMsgValue)) + { + entry.tx = false; + continue; + } + } + catch (e) {} + } + + if (callObj.dxcc == window.opener.g_myDXCC) + { + if (g_rosterSettings.noMyDxcc == true) + { + entry.tx = false; + continue; + } + } + else + { + if (g_rosterSettings.onlyMyDxcc == true) + { + entry.tx = false; + continue; + } + } + + if (window.opener.g_callsignLookups.lotwUseEnable == true && g_rosterSettings.usesLoTW == true) + { + if (!(call in window.opener.g_lotwCallsigns)) + { + entry.tx = false; + continue; + } + if (g_rosterSettings.maxLoTW < 27) + { + var months = (g_day - window.opener.g_lotwCallsigns[call]) / 30; + if (months > g_rosterSettings.maxLoTW) + { + entry.tx = false; + continue; + } + } + } + + if (window.opener.g_callsignLookups.eqslUseEnable == true && g_rosterSettings.useseQSL == true) + { + if (!(call in window.opener.g_eqslCallsigns)) + { + entry.tx = false; + continue; + } + } + + if (window.opener.g_callsignLookups.oqrsUseEnable == true && g_rosterSettings.usesOQRS == true) + { + if (!(call in window.opener.g_oqrsCallsigns)) + { + entry.tx = false; + continue; + } + } + + if (callMode != "all") + { + if (entry.DXcall == "CQ DX" && callObj.dxcc == window.opener.g_myDXCC) + { + entry.tx = false; + continue; + } + + var hash = hashMaker(call, callObj, g_rosterSettings.reference); + if (callMode == "worked" && hash in g_worked.call) + { + entry.tx = false; + continue; + } + if (callMode == "confirmed" && hash in g_confirmed.call) + { + entry.tx = false; + continue; + } + + if (g_rosterSettings.hunting == "grid") + { + var hash = hashMaker(callObj.grid.substr(0, 4), + callObj, g_rosterSettings.reference); + if (huntIndex && hash in huntIndex.grid) + { + entry.tx = false; + continue; + } + if (callObj.grid.length == 0) + { + entry.tx = false; + continue; + } + continue; + } + if (g_rosterSettings.hunting == "dxcc") + { + var hash = hashMaker(String(callObj.dxcc), + callObj, g_rosterSettings.reference); + + if (huntIndex && (hash in huntIndex.dxcc)) + { + entry.tx = false; + continue; + } + + continue; + } + + if (g_rosterSettings.hunting == "dxccs" && r_currentDXCCs != -1) + { + if (callObj.dxcc != r_currentDXCCs) + { + entry.tx = false; + continue; + } + } + + if (g_rosterSettings.hunting == "wpx") + { + if (String(callObj.px) == null) + { + entry.tx = false; + continue; + } + var hash = hashMaker(String(callObj.px), + callObj, g_rosterSettings.reference); + + if (huntIndex && (hash in huntIndex.px)) + { + entry.tx = false; + continue; + } + + continue; + } + + if (g_rosterSettings.hunting == "cq") + { + var huntTotal = callObj.cqza.length; + if (huntTotal == 0 || !huntIndex) + { + entry.tx = false; + continue; + } + var huntFound = 0; + for (index in callObj.cqza) + { + var hash = hashMaker(callObj.cqza[index], callObj, g_rosterSettings.reference); + + if (hash in huntIndex.cqz) huntFound++; + } + if (huntFound == huntTotal) + { + entry.tx = false; + continue; + } + + continue; + } + + if (g_rosterSettings.hunting == "itu") + { + var huntTotal = callObj.ituza.length; + if (huntTotal == 0 || !huntIndex) + { + entry.tx = false; + continue; + } + var huntFound = 0; + for (index in callObj.ituza) + { + var hash = hashMaker(callObj.ituza[index], callObj, g_rosterSettings.reference); + + if (hash in huntIndex.ituz) huntFound++; + } + if (huntFound == huntTotal) + { + entry.tx = false; + continue; + } + + if (callObj.grid.length == 0) + { + entry.tx = false; + continue; + } + continue; + } + + if (g_rosterSettings.hunting == "usstates" && window.opener.g_callsignLookups.ulsUseEnable == true) + { + var state = callObj.state; + var finalDxcc = callObj.dxcc; + if (finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6) + { + if (state in window.opener.g_StateData) + { + var hash = hashMaker(state, callObj, g_rosterSettings.reference); + + if (huntIndex && hash in huntIndex.state) + { + entry.tx = false; + continue; + } + } + else entry.tx = false; + } + else entry.tx = false; + + continue; + } + + if (g_rosterSettings.hunting == "usstate" && g_currentUSCallsigns) + { + if (call in g_currentUSCallsigns) + { + // Do Nothing + } + else + { + entry.tx = false; + continue; + } + continue; + } + } + if (isAwardTracker) + { + var tx = false; + var baseHash = hashMaker("", callObj, g_rosterSettings.reference); + + for (var award in g_awardTracker) + { + if (g_awardTracker[award].enable) + { + tx = testAward(award, callObj, baseHash); + if (tx) + { + var x = g_awardTracker[award]; + callObj.awardReason = + g_awards[x.sponsor].awards[x.name].tooltip + + " (" + + g_awards[x.sponsor].sponsor + + ")"; + + break; + } + } + } + entry.tx = tx; + } + } + + var hasGtPin = false; + + var newCallList = Array(); + var inversionAlpha = "DD"; + var row = "#000000"; + var bold = "#000000;font-weight: bold;"; + var unconf = "background-clip:padding-box;box-shadow: 0 0 7px 3px inset "; + var layeredAlpha = "77"; + var layeredInversionAlpha = "66"; + var layeredUnconf = "background-clip:padding-box;box-shadow: 0 0 4px 2px inset "; + var layeredUnconfAlpha = "AA"; + + // Second loop, hunting and highlighting + for (var callHash in callRoster) + { + var entry = callRoster[callHash]; + var callObj = entry.callObj; + + // Special case check for called station + if (callObj.qrz == true && entry.tx == false) + { + // The instance has to be enabled + if (window.opener.g_instances[callObj.instance].crEnable == true) + { + // Calling us, but we wouldn't normally display + // If they are not ignored or we're in a QSO with them, var it through + + if ((!(entry.DEcall in g_blockedCalls) && !(callObj.dxcc in g_blockedDxcc)) || + window.opener.g_instances[callObj.instance].status.DXcall == entry.DEcall) + { + entry.tx = true; + } + } + } + + // Only render entries with `tx == true`, ignore the rest + if (callObj.dxcc != -1 && entry.tx == true) + { + // In layered mode ("Hunting: mixed") the workHashSuffix becomes a more stricter 'live band', + // while the layered suffix is a broader 'mixed band' + var workHashSuffix, layeredHashSuffix; + if (layeredMode) + { + workHashSuffix = hashMaker("", callObj, layeredMode); + layeredHashSuffix = hashMaker("", callObj, g_rosterSettings.reference); + } + else + { + workHashSuffix = hashMaker("", callObj, g_rosterSettings.reference); + layeredHashSuffix = false + } + var workHash = workHashSuffix; // TODO: Remove after replacing all occurrences with Suffix + + var callsign = entry.DEcall; + + callObj.hunting = {} + callObj.callFlags = {} + + var colorObject = Object(); + + var callPointer = callObj.CQ == true ? "cursor:pointer" : ""; + + var didWork = false; + + var call = "#FFFF00"; + var grid = "#00FFFF"; + var calling = "#90EE90"; + var dxcc = "#FFA500"; + var state = "#90EE90"; + var cnty = "#CCDD00"; + var cont = "#00DDDD"; + var cqz = "#DDDDDD"; + var ituz = "#DDDDDD"; + var wpx = "#FFFF00"; + + hasGtPin = false; + var shouldAlert = false; + var callBg, gridBg, callingBg, dxccBg, stateBg, cntyBg, contBg, cqzBg, ituzBg, wpxBg, gtBg; + var callConf, gridConf, callingConf, dxccConf, stateConf, cntyConf, contConf, cqzConf, ituzConf, wpxConf; + + callBg = gridBg = callingBg = dxccBg = stateBg = cntyBg = contBg = cqzBg = ituzBg = wpxBg = gtBg = row; + + callConf = gridConf = callingConf = dxccConf = stateConf = cntyConf = contConf = cqzConf = ituzConf = wpxConf = + ""; + + var hash = callsign + workHashSuffix; + var layeredHash = layeredHashSuffix && (callsign + layeredHashSuffix) + + // Call worked in current logbook settings, regardless of hunting mode + if (hash in g_worked.call) + { + callObj.callFlags.worked = true; + didWork = true; + callConf = `${unconf}${call}${inversionAlpha};`; + + if (hash in g_confirmed.call) + { + callObj.callFlags.confirmed = true; + callPointer = "text-decoration: line-through; "; + callConf = ""; + } + } + + // Calls that have OAMS chat support + if ( + callsign in window.opener.g_gtCallsigns && + window.opener.g_gtCallsigns[callsign] in window.opener.g_gtFlagPins && + window.opener.g_gtFlagPins[window.opener.g_gtCallsigns[callsign]].canmsg == true + ) + { + callObj.callFlags.oams = true; + // grab the CID + colorObject.gt = window.opener.g_gtCallsigns[callsign]; + hasGtPin = true; + } + else + { + colorObject.gt = 0; + } + + // We only do hunt highlighting when showing all entries + // This means "Callsigns: All Traffic", "Callsigns: All Traffic/Only Wanted" and "Logbook: Award Tracker" + // There is no highlighting in other modes + if (callMode == "all") + { + // Skip when "only new calls" + // Questions: Move to the first loop? Why only skip new calls in "all traffic" and not other modes? + if (allOnlyNew.checked == true && didWork && callObj.qrz == false) + { + entry.tx = false; + continue; + } + + // Hunting for callsigns + if (huntCallsign.checked == true) + { + var hash = callsign + workHashSuffix; + var layeredHash = layeredMode && (callsign + layeredHashSuffix) + + if (huntIndex && !(hash in huntIndex.call)) + { + shouldAlert = true; + + callObj.reason.push("call"); + + if (workedIndex && hash in workedIndex.call) + { + if (layeredMode && layeredHash in huntIndex.call) + { + callObj.hunting.call = "worked-and-mixed"; + callConf = `${layeredUnconf}${call}${layeredUnconfAlpha};`; + callBg = `${call}${layeredInversionAlpha}`; + call = bold; + } + // /* Currently we don't have a way to figure out + // * if the call is worked only in this band or also others, + // * so we cannot cover this particular combination + // * and have to default to just showing it as plain "worked" + // */ + // else if (layeredMode && layeredHash in workedIndex.call) + // { + // callObj.hunting.call = "worked-and-mixed-worked"; + // callConf = `${layeredUnconf}${call}${layeredAlpha};`; + // } + else + { + callObj.hunting.call = "worked"; + callConf = `${unconf}${call}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredHash in huntIndex.call) + { + callObj.hunting.call = "mixed"; + callBg = `${call}${layeredAlpha};`; + call = bold; + } + else if (layeredMode && layeredHash in workedIndex.call) + { + callObj.hunting.call = "mixed-worked"; + callConf = `${unconf}${call}${layeredAlpha};`; + } + else + { + callObj.hunting.call = "hunted"; + callBg = `${call}${inversionAlpha};`; + call = bold; + } + } + } + } + + // Hunting for "stations calling you" + if (huntQRZ.checked == true && callObj.qrz == true) + { + callObj.callFlags.calling = true + shouldAlert = true; + callObj.reason.push("qrz"); + } + + // Hunting for stations with OAMS + if (huntOAMS.checked == true && hasGtPin == true) + { + callObj.hunting.oams = "hunted"; + shouldAlert = true; + callObj.reason.push("oams"); + } + + // Hunting for grids + if (huntGrid.checked == true && callObj.grid.length > 1) + { + var hash = callObj.grid.substr(0, 4) + workHashSuffix; + var layeredHash = layeredMode && (callObj.grid.substr(0, 4) + layeredHashSuffix) + + if (huntIndex && !(hash in huntIndex.grid)) + { + shouldAlert = true; + + callObj.reason.push("grid"); + + if (workedIndex && hash in workedIndex.grid) + { + if (layeredMode && layeredHash in huntIndex.grid) + { + callObj.hunting.grid = "worked-and-mixed"; + gridConf = `${layeredUnconf}${grid}${layeredUnconfAlpha};`; + gridBg = `${grid}${layeredInversionAlpha}`; + grid = bold; + } + else + { + callObj.hunting.grid = "worked"; + gridConf = `${unconf}${grid}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredHash in huntIndex.grid) + { + callObj.hunting.grid = "mixed"; + gridBg = `${grid}${layeredAlpha};`; + grid = bold; + } + else if (layeredMode && layeredHash in workedIndex.grid) + { + callObj.hunting.grid = "mixed-worked"; + gridConf = `${unconf}${grid}${layeredAlpha};`; + } + else + { + callObj.hunting.grid = "hunted"; + gridBg = `${grid}${inversionAlpha};`; + grid = bold; + } + } + } + } + + // Hunting for DXCC + if (huntDXCC.checked == true) + { + var hash = String(callObj.dxcc) + workHashSuffix; + var layeredHash = layeredMode && (String(callObj.dxcc) + layeredHashSuffix) + + if (huntIndex && !(hash in huntIndex.dxcc)) + { + shouldAlert = true; + + callObj.reason.push("dxcc"); + + if (workedIndex && hash in workedIndex.dxcc) + { + if (layeredMode && layeredHash in huntIndex.dxcc) + { + callObj.hunting.dxcc = "worked-and-mixed"; + dxccConf = `${layeredUnconf}${dxcc}${layeredUnconfAlpha};`; + dxccBg = `${dxcc}${layeredInversionAlpha}`; + dxcc = bold; + } + else + { + callObj.hunting.dxcc = "worked"; + dxccConf = `${unconf}${dxcc}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredHash in huntIndex.dxcc) + { + callObj.hunting.dxcc = "mixed"; + dxccBg = `${dxcc}${layeredAlpha};`; + dxcc = bold; + } + else if (layeredMode && layeredHash in workedIndex.dxcc) + { + callObj.hunting.dxcc = "mixed-worked"; + dxccConf = `${unconf}${dxcc}${layeredAlpha};`; + } + else + { + callObj.hunting.dxcc = "hunted"; + dxccBg = `${dxcc}${inversionAlpha};`; + dxcc = bold; + } + } + } + } + + // Hunting for US States + if (huntState.checked == true && window.opener.g_callsignLookups.ulsUseEnable == true) + { + var stateSearch = callObj.state; + var finalDxcc = callObj.dxcc; + if (finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6) + { + if (stateSearch in window.opener.g_StateData) + { + var hash = stateSearch + workHashSuffix; + var layeredHash = layeredMode && (stateSearch + layeredHashSuffix) + + if (huntIndex && !(hash in huntIndex.state)) + { + shouldAlert = true; + + callObj.reason.push("state"); + + if (workedIndex && hash in workedIndex.state) + { + if (layeredMode && layeredHash in huntIndex.state) + { + callObj.hunting.state = "worked-and-mixed"; + stateConf = `${layeredUnconf}${state}${layeredUnconfAlpha};`; + stateBg = `${state}${layeredInversionAlpha}`; + state = bold; + } + else + { + callObj.hunting.state = "worked"; + stateConf = `${unconf}${state}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredHash in huntIndex.state) + { + callObj.hunting.state = "mixed"; + stateBg = `${state}${layeredAlpha};`; + state = bold; + } + else if (layeredMode && layeredHash in workedIndex.state) + { + callObj.hunting.state = "mixed-worked"; + stateConf = `${unconf}${state}${layeredAlpha};`; + } + else + { + callObj.hunting.state = "hunted"; + stateBg = `${state}${inversionAlpha};`; + state = bold; + } + } + } + } + } + } + + // Hunting for US Counties + if (huntCounty.checked == true && window.opener.g_callsignLookups.ulsUseEnable == true) + { + var finalDxcc = callObj.dxcc; + if ( + callObj.cnty && + (finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6 || finalDxcc == 202) && + callObj.cnty.length > 0 + ) + { + var hash = callObj.cnty + (layeredMode ? layeredHashSuffix : workHashSuffix); + + if ((huntIndex && !(hash in huntIndex.cnty)) || callObj.qual == false) + { + if (callObj.qual == false) + { + var counties = window.opener.g_zipToCounty[callObj.zipcode]; + var foundHit = false; + for (var cnt in counties) + { + var hh = counties[cnt] + workHash; + callObj.cnty = counties[cnt]; + if (huntIndex && !(hh in huntIndex.cnty)) + { + foundHit = true; + break; + } + } + if (foundHit) shouldAlert = true; + } + else + { + shouldAlert = true; + } + + if (shouldAlert) + { + callObj.reason.push("cnty"); + + if (workedIndex && hash in workedIndex.cnty) + { + callObj.hunting.cnty = "worked"; + cntyConf = `${unconf}${cnty}${inversionAlpha};`; + } + else + { + callObj.hunting.cnty = "hunted"; + cntyBg = `${cnty}${inversionAlpha}`; + cnty = bold; + } + } + } + } + } + + // Hunting for CQ Zones + if (huntCQz.checked == true) + { + var huntTotal = callObj.cqza.length; + var huntFound = 0, layeredFound = 0, workedFound = 0, layeredWorkedFound = 0; + + for (index in callObj.cqza) + { + var hash = callObj.cqza[index] + workHashSuffix; + var layeredHash = layeredMode && (callObj.cqza[index] + layeredHashSuffix) + + if (huntIndex && hash in huntIndex.cqz) huntFound++; + if (layeredMode && layeredHash in huntIndex.cqz) layeredFound++; + if (workedIndex && hash in workedIndex.cqz) workedFound++; + if (layeredMode && layeredHash in workedIndex.cqz) layeredWorkedFound++; + } + if (huntFound != huntTotal) + { + shouldAlert = true; + callObj.reason.push("cqz"); + + if (workedIndex && workedFound == huntTotal) + { + if (layeredMode && layeredFound == huntTotal) + { + callObj.hunting.cqz = "worked-and-mixed"; + cqzConf = `${layeredUnconf}${cqz}${layeredUnconfAlpha};`; + cqzBg = `${cqz}${layeredInversionAlpha}`; + cqz = bold; + } + else + { + callObj.hunting.cqz = "worked"; + cqzConf = `${unconf}${cqz}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredFound == huntTotal) + { + callObj.hunting.cqz = "mixed"; + cqzBg = `${cqz}${layeredAlpha};`; + cqz = bold; + } + else if (layeredMode && layeredWorkedFound == huntTotal) + { + callObj.hunting.cqz = "mixed-worked"; + cqzConf = `${unconf}${cqz}${layeredAlpha};`; + } + else + { + callObj.hunting.cqz = "hunted"; + cqzBg = `${cqz}${inversionAlpha};`; + cqz = bold; + } + } + } + } + + // Hunting for ITU Zones + if (huntITUz.checked == true) + { + var huntTotal = callObj.ituza.length; + var huntFound = 0, layeredFound = 0, workedFound = 0, layeredWorkedFound = 0; + + for (index in callObj.ituza) + { + var hash = callObj.ituza[index] + workHashSuffix; + var layeredHash = layeredMode && (callObj.ituza[index] + layeredHashSuffix) + + if (huntIndex && hash in huntIndex.ituz) huntFound++; + if (layeredMode && layeredHash in huntIndex.ituz) layeredFound++; + if (workedIndex && hash in workedIndex.ituz) workedFound++; + if (layeredMode && layeredHash in workedIndex.ituz) layeredWorkedFound++; + } + if (huntFound != huntTotal) + { + shouldAlert = true; + callObj.reason.push("ituz"); + + if (workedIndex && workedFound == huntTotal) + { + if (layeredMode && layeredFound == huntTotal) + { + callObj.hunting.ituz = "worked-and-mixed"; + ituzConf = `${layeredUnconf}${ituz}${layeredUnconfAlpha};`; + ituzBg = `${ituz}${layeredInversionAlpha}`; + ituz = bold; + } + else + { + callObj.hunting.ituz = "worked"; + ituzConf = `${unconf}${ituz}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredFound == huntTotal) + { + callObj.hunting.ituz = "mixed"; + ituzBg = `${ituz}${layeredAlpha};`; + ituz = bold; + } + else if (layeredMode && layeredWorkedFound == huntTotal) + { + callObj.hunting.ituz = "mixed-worked"; + ituzConf = `${unconf}${ituz}${layeredAlpha};`; + } + else + { + callObj.hunting.ituz = "hunted"; + ituzBg = `${ituz}${inversionAlpha};`; + ituz = bold; + } + } + } + } + + // Hunting for WPX (Prefixes) + if (huntPX.checked == true && callObj.px) + { + var hash = String(callObj.px) + workHashSuffix; + var layeredHash = layeredMode && (String(callObj.px) + layeredHashSuffix) + + if (huntIndex && !(hash in huntIndex.px)) + { + shouldAlert = true; + + callObj.reason.push("wpx"); + + if (workedIndex && hash in workedIndex.px) + { + if (layeredMode && layeredHash in huntIndex.px) + { + callObj.hunting.wpx = "worked-and-mixed"; + wpxConf = `${layeredUnconf}${wpx}${layeredUnconfAlpha};`; + wpxBg = `${wpx}${layeredInversionAlpha}`; + wpx = bold; + } + else + { + callObj.hunting.wpx = "worked"; + wpxConf = `${unconf}${wpx}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredHash in huntIndex.px) + { + callObj.hunting.wpx = "mixed"; + wpxBg = `${wpx}${layeredAlpha};`; + wpx = bold; + } + else if (layeredMode && layeredHash in workedIndex.px) + { + callObj.hunting.wpx = "mixed-worked"; + wpxConf = `${unconf}${wpx}${layeredAlpha};`; + } + else + { + callObj.hunting.wpx = "hunted"; + wpxBg = `${wpx}${inversionAlpha};`; + wpx = bold; + } + } + } + } + + // Hunting for Continents + if (huntCont.checked == true && callObj.cont) + { + var hash = String(callObj.cont) + workHashSuffix; + var layeredHash = layeredMode && (String(callObj.cont) + layeredHashSuffix) + + if (huntIndex && !(hash in huntIndex.cont)) + { + shouldAlert = true; + + callObj.reason.push("cont"); + + if (workedIndex && hash in workedIndex.cont) + { + if (layeredMode && layeredHash in huntIndex.cont) + { + callObj.hunting.cont = "worked-and-mixed"; + contConf = `${layeredUnconf}${cont}${layeredUnconfAlpha};`; + contBg = `${cont}${layeredInversionAlpha}`; + cont = bold; + } + else + { + callObj.hunting.cont = "worked"; + contConf = `${unconf}${cont}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredHash in huntIndex.cont) + { + callObj.hunting.cont = "mixed"; + contBg = `${cont}${layeredAlpha};`; + cont = bold; + } + else if (layeredMode && layeredHash in workedIndex.cont) + { + callObj.hunting.cont = "mixed-worked"; + contConf = `${unconf}${cont}${layeredAlpha};`; + } + else + { + callObj.hunting.cont = "hunted"; + contBg = `${cont}${inversionAlpha};`; + cont = bold; + } + } + } + } + } + + // Station is calling us + if (callObj.DXcall == window.opener.myDEcall) + { + callingBg = "#0000FF" + inversionAlpha; + calling = "#FFFF00;text-shadow: 0px 0px 2px #FFFF00"; + } + else if (callObj.CQ == true && g_rosterSettings.cqOnly == false) + { + callingBg = calling + inversionAlpha; + calling = bold; + } + + // Assemble all styles + colorObject.call = "style='" + callConf + "background-color:" + callBg + ";color:" + + call + ";" + callPointer + "'"; + colorObject.grid = "style='" + gridConf + "background-color:" + gridBg + ";color:" + grid + ";cursor:pointer'"; + colorObject.calling = "style='" + callingConf + "background-color:" + callingBg + ";color:" + calling + "'"; + colorObject.dxcc = "style='" + dxccConf + "background-color:" + dxccBg + ";color:" + dxcc + "'"; + colorObject.state = "style='" + stateConf + "background-color:" + stateBg + ";color:" + state + "'"; + colorObject.cnty = "style='" + cntyConf + "background-color:" + cntyBg + ";color:" + cnty + "'"; + colorObject.cont = "style='" + contConf + "background-color:" + contBg + ";color:" + cont + "'"; + colorObject.cqz = "style='" + cqzConf + "background-color:" + cqzBg + ";color:" + cqz + "'"; + colorObject.ituz = "style='" + ituzConf + "background-color:" + ituzBg + ";color:" + ituz + "'"; + colorObject.px = "style='" + wpxConf + "background-color:" + wpxBg + ";color:" + wpx + "'"; + + // Just in case, don't alert if we worked this callsign alread + if (didWork && shouldAlert) shouldAlert = false; + + callObj.shouldAlert = shouldAlert; + + callObj.style = colorObject; + + if (g_rosterSettings.columns.Spot) + { + callObj.spot = window.opener.getSpotTime( + callObj.DEcall + callObj.mode + callObj.band + callObj.grid + ); + if (callObj.spot == null) + { + callObj.spot = { when: 0, snr: 0 }; + } + } + else + { + callObj.spot = { when: 0, snr: 0 }; + } + + modes[callObj.mode] = true; + bands[callObj.band] = true; + + newCallList.push(callObj); + } + } + + // Show the roster count in the window title + + var totalCount = Object.keys(callRoster).length; + var visibleCount = newCallList.length; + var huntedCount = newCallList.filter(obj => Object.keys(obj.hunting).length > 0).length + var countParts = []; + + if (totalCount != visibleCount) + { + countParts.push(`${totalCount} heard`); + } + + countParts.push(`${visibleCount} in roster`); + + if (huntedCount != visibleCount) + { + countParts.push(`${huntedCount} wanted`); + } + + window.document.title = `Call Roster: ${countParts.join(" • ")}`; + + // Render the roster + + if (g_rosterSettings.compact == false) + { + newCallList.sort(r_sortFunction[g_rosterSettings.lastSortIndex]); + if (g_rosterSettings.lastSortReverse == 1) + { + newCallList.reverse(); + } + } + else + { + // Age sort for now... make this happen Tag + newCallList.sort(r_sortFunction[6]).reverse(); + } + + var showBands = (Object.keys(bands).length > 1) || g_rosterSettings.columns.Band; + var showModes = (Object.keys(modes).length > 1) || g_rosterSettings.columns.Mode; + + var worker = ""; + + // Render the table headers for the regular roster table + if (g_rosterSettings.compact == false) + { + worker = "
Callsign | "; + + if (showBands) + { worker += "Band | "; } + + if (showModes) + { worker += "Mode | "; } + + worker += "Grid | "; + + if (g_rosterSettings.columns.Calling) + { worker += "Calling | "; } + + if (g_rosterSettings.columns.Msg) + { worker += "Msg | "; } + + if (g_rosterSettings.columns.DXCC) + { worker += "DXCC | "; } + + if (g_rosterSettings.columns.Flag) + { worker += "Flag | "; } + + if (g_rosterSettings.columns.State) + { worker += "State | "; } + + if (g_rosterSettings.columns.County) + { worker += "County | "; } + + if (g_rosterSettings.columns.Cont) + { worker += "Cont | "; } + + if (g_rosterSettings.columns.dB) + { worker += "dB | "; } + + if (g_rosterSettings.columns.Freq) + { worker += "Freq | "; } + + if (g_rosterSettings.columns.DT) + { worker += "DT | "; } + + if (g_rosterSettings.columns.Dist) + { + worker += "Dist(" + + window.opener.distanceUnit.value.toLowerCase() + ") | "; + } + + if (g_rosterSettings.columns.Azim) + { worker += "Azim | "; } + + if (g_rosterSettings.columns.CQz) + { worker += "CQz | "; } + + if (g_rosterSettings.columns.ITUz) + { worker += "ITUz | "; } + + if (g_rosterSettings.columns.PX) + { worker += "PX | "; } + + if (window.opener.g_callsignLookups.lotwUseEnable == true && g_rosterSettings.columns.LoTW) + { worker += "LoTW | "; } + + if (window.opener.g_callsignLookups.eqslUseEnable == true && g_rosterSettings.columns.eQSL) + { worker += "eQSL | "; } + + if (window.opener.g_callsignLookups.oqrsUseEnable == true && g_rosterSettings.columns.OQRS) + { worker += "OQRS | "; } + + if (g_rosterSettings.columns.Spot) + { worker += "Spot | "; } + + if (g_rosterSettings.columns.Life) + { worker += "Life | "; } + + if (g_rosterSettings.columns.OAMS) + { worker += "OAMS | "; } + + if (g_rosterSettings.columns.Age) + { worker += "Age | "; } + } + // No headers for compact roster table + else + { + worker = "
---|