From 1f452992861643d61caf5bcf85739c199a28582b Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Mon, 28 Jun 2021 17:26:44 -0500 Subject: [PATCH] big roster refactor - starting Co-authored-by: Sebastian Delmont Matthew Chambers --- package.nw/lib/roster.js | 1814 +---------------- .../lib/roster/prepareRosterSettings.js | 83 + package.nw/lib/roster/processFiltering.js | 363 ++++ package.nw/lib/roster/processHunting.js | 706 +++++++ .../lib/roster/processRosterFiltering.js | 369 ++++ package.nw/lib/roster/processRosterHunting.js | 700 +++++++ package.nw/lib/roster/renderCompactRoster.js | 55 + package.nw/lib/roster/renderNormalRoster.js | 400 ++++ package.nw/lib/roster/renderRoster.js | 102 + package.nw/lib/roster/sendAlerts.js | 135 ++ 10 files changed, 2918 insertions(+), 1809 deletions(-) create mode 100644 package.nw/lib/roster/prepareRosterSettings.js create mode 100644 package.nw/lib/roster/processFiltering.js create mode 100644 package.nw/lib/roster/processHunting.js create mode 100644 package.nw/lib/roster/processRosterFiltering.js create mode 100644 package.nw/lib/roster/processRosterHunting.js create mode 100644 package.nw/lib/roster/renderCompactRoster.js create mode 100644 package.nw/lib/roster/renderNormalRoster.js create mode 100644 package.nw/lib/roster/renderRoster.js create mode 100644 package.nw/lib/roster/sendAlerts.js diff --git a/package.nw/lib/roster.js b/package.nw/lib/roster.js index d015832..d7997f6 100644 --- a/package.nw/lib/roster.js +++ b/package.nw/lib/roster.js @@ -465,1815 +465,11 @@ function processRoster(roster) function viewRoster() { - var bands = Object(); - var modes = Object(); - - // can the following block where we figure out how the roster is being used - // be a function itself that we can call in at the start of this? - 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"; - } - // this appears to be determine if we should show the OAMS column - // if the user is not in offline mode and has OAMS enabled, this could - // be it's own function maybe? - var canMsg = - window.opener.g_mapSettings.offlineMode == false && - window.opener.g_appSettings.gtShareEnable == "true" && - window.opener.g_appSettings.gtMsgEnable == "true"; - - // The following 3 sections deal with QSLing, do we break them out - // individually or lump them into a qslUser function that sets - // all three at the same time? - // this section is for LoTW users, can be a function - 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"; - } - - // eQSL - function - if (window.opener.g_callsignLookups.eqslUseEnable == true) useseQSLDiv.style.display = ""; - else useseQSLDiv.style.display = "none"; - - // OQRS - function - if (window.opener.g_callsignLookups.oqrsUseEnable == true) usesOQRSDiv.style.display = ""; - else usesOQRSDiv.style.display = "none"; - - // dealing with spots - if (g_rosterSettings.columns.Spot == true) onlySpotDiv.style.display = ""; - else onlySpotDiv.style.display = "none"; - - // callmode (all or only new) - if (callMode == "all") allOnlyNewDiv.style.display = ""; - else allOnlyNewDiv.style.display = "none"; - - // hunting mode - can this be comibined with the roster mode stuff on - // on line 441 above in that function or be it's own? - 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 - // this whole section is full of individual if's that could be broken out - 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; - } - } - - // these vars, do they rely on anything between the top and here? - // if not could they be put in the var list at the beginning? - 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 = ""; - - worker += ""; - - if (showBands) - { worker += ""; } - - if (showModes) - { worker += ""; } - - worker += ""; - - if (g_rosterSettings.columns.Calling) - { worker += ""; } - - if (g_rosterSettings.columns.Msg) - { worker += ""; } - - if (g_rosterSettings.columns.DXCC) - { worker += ""; } - - if (g_rosterSettings.columns.Flag) - { worker += ""; } - - if (g_rosterSettings.columns.State) - { worker += ""; } - - if (g_rosterSettings.columns.County) - { worker += ""; } - - if (g_rosterSettings.columns.Cont) - { worker += ""; } - - if (g_rosterSettings.columns.dB) - { worker += ""; } - - if (g_rosterSettings.columns.Freq) - { worker += ""; } - - if (g_rosterSettings.columns.DT) - { worker += ""; } - - if (g_rosterSettings.columns.Dist) - { - worker += ""; - } - - if (g_rosterSettings.columns.Azim) - { worker += ""; } - - if (g_rosterSettings.columns.CQz) - { worker += ""; } - - if (g_rosterSettings.columns.ITUz) - { worker += ""; } - - if (g_rosterSettings.columns.PX) - { worker += ""; } - - if (window.opener.g_callsignLookups.lotwUseEnable == true && g_rosterSettings.columns.LoTW) - { worker += ""; } - - if (window.opener.g_callsignLookups.eqslUseEnable == true && g_rosterSettings.columns.eQSL) - { worker += ""; } - - if (window.opener.g_callsignLookups.oqrsUseEnable == true && g_rosterSettings.columns.OQRS) - { worker += ""; } - - if (g_rosterSettings.columns.Spot) - { worker += ""; } - - if (g_rosterSettings.columns.Life) - { worker += ""; } - - if (g_rosterSettings.columns.OAMS) - { worker += ""; } - - if (g_rosterSettings.columns.Age) - { worker += ""; } - } - // No headers for compact roster table - else - { - worker = "
"; - } - - var shouldAlert = 0; - - // Render all rows - for (var x in newCallList) - { - var callObj = newCallList[x]; - - if (callObj.shouldAlert == false && onlyHits == true && callObj.qrz == false) - { continue; } - - var spotString = ""; - if (g_rosterSettings.columns.Spot && callObj.qrz == false) - { - spotString = getSpotString(callObj); - if (g_rosterSettings.onlySpot && spotString == "") continue; - } - var grid = callObj.grid.length > 1 ? callObj.grid.substr(0, 4) : "-"; - - var geo = window.opener.g_worldGeoData[window.opener.g_dxccToGeoData[callObj.dxcc]]; - var cqzone = grid in window.opener.g_gridToCQZone ? window.opener.g_gridToCQZone[grid].join(", ") : "-"; - var ituzone = grid in window.opener.g_gridToITUZone ? window.opener.g_gridToITUZone[grid].join(", ") : "-"; - var thisCall = callObj.DEcall; - - if (thisCall.match("^[A-Z][0-9][A-Z](/w+)?$")) - { callObj.style.call = "class='oneByOne'"; } - if (thisCall == window.opener.g_instances[callObj.instance].status.DXcall) - { - if (window.opener.g_instances[callObj.instance].status.TxEnabled == 1) - { - callObj.style.call = "class='dxCalling'"; - } - else - { - callObj.style.call = "class='dxCaller'"; - } - } - - if (g_rosterSettings.compact == false) - { - var acks = window.opener.g_acknowledgedCalls - - var thisHash = thisCall + callObj.band + callObj.mode; - var callStr = thisCall.formatCallsign() - if (acks[thisCall]) - { - callStr = `${callStr} ` - callObj.awardReason += ` - ${acks[thisCall].message}` - } - - worker += "
"; - worker += - ""; - - if (showBands) - { - worker += - ""; - } - if (showModes) - { - var color = "888888"; - if (callObj.mode in g_modeColors) - { color = g_modeColors[callObj.mode]; } - worker += - ""; - } - - worker += - ""; - if (g_rosterSettings.columns.Calling) - { - var lookString = callObj.CQ ? "name='CQ'" : "name='Calling'"; - worker += - ""; - } - if (g_rosterSettings.columns.Msg) - { worker += ""; } - - if (g_rosterSettings.columns.DXCC) - { - worker += - ""; - } - if (g_rosterSettings.columns.Flag) - { - worker += - ""; - } - if (g_rosterSettings.columns.State) - { - worker += - ""; - } - if (g_rosterSettings.columns.County) - { - worker += - ""; - } - if (g_rosterSettings.columns.Cont) - { - worker += - ""; - } - - if (g_rosterSettings.columns.dB) - { - worker += - ""; - } - if (g_rosterSettings.columns.Freq) - { worker += ""; } - if (g_rosterSettings.columns.DT) - { worker += ""; } - if (g_rosterSettings.columns.Dist) - { - worker += - ""; - } - if (g_rosterSettings.columns.Azim) - { - worker += - ""; - } - - if (g_rosterSettings.columns.CQz) - { - worker += - ""; - } - if (g_rosterSettings.columns.ITUz) - { - worker += - ""; - } - - if (g_rosterSettings.columns.PX) - { - worker += - ""; - } - - if ( - window.opener.g_callsignLookups.lotwUseEnable == true && - g_rosterSettings.columns.LoTW - ) - { - if (thisCall in window.opener.g_lotwCallsigns) - { - if (g_rosterSettings.maxLoTW < 27) - { - var months = (g_day - window.opener.g_lotwCallsigns[thisCall]) / 30; - if (months > g_rosterSettings.maxLoTW) - { - worker += - ""; - } - else - { - worker += - ""; - } - } - else - { - worker += - ""; - } - } - else worker += ""; - } - if ( - window.opener.g_callsignLookups.eqslUseEnable == true && - g_rosterSettings.columns.eQSL - ) - { - worker += - ""; - } - if ( - window.opener.g_callsignLookups.oqrsUseEnable == true && - g_rosterSettings.columns.OQRS - ) - { - worker += - ""; - } - - if (g_rosterSettings.columns.Spot) - { - worker += - ""; - } - if (g_rosterSettings.columns.Life) - { - worker += - ""; - } - - if (g_rosterSettings.columns.OAMS) - { - if (callObj.style.gt != 0) - { - if (callObj.reason.includes("oams")) - { - worker += - ""; - } - else - { - worker += - ""; - } - } - else worker += ""; - } - - if (g_rosterSettings.columns.Age) - { - worker += - ""; - } - - worker += ""; - } - else - { - var tt = - callObj.RSTsent + - "㏈, " + - parseInt(callObj.dt * 100) + - "ms, " + - callObj.delta + - "hz" + - (callObj.grid.length ? ", " + callObj.grid : "") + - ", " + - (timeNowSec() - callObj.age).toDHMS(); - worker += - "
"; - worker += - "
" + - thisCall.formatCallsign() + - "
"; - worker += - "
" + - window.opener.g_dxccToAltName[callObj.dxcc] + - "
"; - worker += "
"; - } - - if (g_rosterSettings.realtime == false) - { - var call = callObj.DEcall; - g_scriptReport[call] = Object.assign({}, callObj); - g_scriptReport[call].dxccName = - window.opener.g_dxccToAltName[callObj.dxcc]; - g_scriptReport[call].distance = parseInt( - callObj.distance * - MyCircle.validateRadius(window.opener.distanceUnit.value) - ); - - delete g_scriptReport[call].DEcall; - g_scriptReport[call].rect = null; - delete g_scriptReport[call].rect; - delete g_scriptReport[call].style; - delete g_scriptReport[call].wspr; - delete g_scriptReport[call].qso; - delete g_scriptReport[call].instance; - - if (callMode != "all") - { - g_scriptReport[call].shouldAlert = true; - g_scriptReport[call].reason.push(g_rosterSettings.hunting); - } - } - - if ( - callObj.alerted == false && - callMode == "all" && - callObj.shouldAlert == true - ) - { - callObj.alerted = true; - shouldAlert++; - } - else if (callObj.alerted == false && callMode != "all") - { - callObj.alerted = true; - shouldAlert++; - } - - callObj.shouldAlert = false; - } - - if (g_rosterSettings.compact == false) - { - worker += "
CallsignBandModeGridCallingMsgDXCCFlagStateCountyContdBFreqDTDist(" + - window.opener.distanceUnit.value.toLowerCase() + ")AzimCQzITUzPXLoTWeQSLOQRSSpotLifeOAMSAge
" + - callStr + - "" + - callObj.band + - "" + callObj.mode + "" + - grid + - "" + - callObj.DXcall.formatCallsign() + - "" + callObj.msg + "" + - window.opener.g_dxccToAltName[callObj.dxcc] + "" + - (callObj.state ? callObj.state.substr(3) : "") + - "" + - (callObj.cnty - ? (callObj.qual ? "" : "~ ") + - window.opener.g_cntyToCounty[callObj.cnty] + - (callObj.qual ? "" : " ~") - : "") + - "" + - (callObj.cont ? callObj.cont : "") + - "" + - callObj.RSTsent + - "" + callObj.delta + "" + callObj.dt + "" + - parseInt( - callObj.distance * - MyCircle.validateRadius(window.opener.distanceUnit.value) - ) + - "" + - parseInt(callObj.heading) + - "" + - callObj.cqza.join(",") + - "" + - callObj.ituza.join(",") + - "" + - (callObj.px ? callObj.px : "") + - "?" + - (thisCall in window.opener.g_eqslCallsigns ? "✔" : "") + - "" + - (thisCall in window.opener.g_oqrsCallsigns ? "✔" : "") + - "" + - spotString + - "" + - (timeNowSec() - callObj.life).toDHMS() + - "" + - (timeNowSec() - callObj.age).toDHMS() + - "
"; - RosterTable.innerHTML = worker; - } - else - { - RosterTable.innerHTML = worker + ""; - } - - var dirPath = window.opener.g_scriptDir; - var scriptExists = false; - var script = "cr-alert.sh"; - - try - { - if (fs.existsSync(dirPath)) - { - if (window.opener.g_platform == "windows") - { - script = "cr-alert.bat"; - } - if ( - fs.existsSync(dirPath + script) && - g_rosterSettings.realtime == false - ) - { - scriptExists = true; - scriptIcon.innerHTML = - "
" + - (window.opener.g_crScript == 1 - ? "Script Enabled" - : "Script Disabled") + - "
"; - scriptIcon.style.display = "block"; - } - else - { - scriptIcon.style.display = "none"; - } - } - } - catch (e) {} - - if (shouldAlert > 0) - { - if (window.opener.g_classicAlerts.huntRoster == true) - { - var notify = window.opener.huntRosterNotify.value; - if (notify == "0") - { - var media = window.opener.huntRosterNotifyMedia.value; - if (media != "none") window.opener.playAlertMediaFile(media); - } - else if (notify == "1") - { - window.opener.speakAlertString( - window.opener.huntRosterNotifyWord.value - ); - } - } - - if ( - g_rosterSettings.realtime == false && - scriptExists && - window.opener.g_crScript == 1 - ) - { - try - { - fs.writeFileSync( - dirPath + "cr-alert.json", - JSON.stringify(g_scriptReport, null, 2) - ); - - var thisProc = dirPath + script; - var cp = require("child_process"); - var child = cp.spawn(thisProc, [], { - detached: true, - cwd: dirPath.slice(0, -1), - stdio: ["ignore", "ignore", "ignore"] - }); - child.unref(); - } - catch (e) - { - conosle.log(e); - } - g_scriptReport = Object(); - } - else g_scriptReport = Object(); - } + var rosterSettings = prepareRosterSettings(); + processRosterFiltering(callRoster, rosterSettings); + processRosterHunting(callRoster, rosterSettings); + renderRoster(callRoster, rosterSettings); + sendAlerts(callRoster, rosterSettings); } function realtimeRoster() diff --git a/package.nw/lib/roster/prepareRosterSettings.js b/package.nw/lib/roster/prepareRosterSettings.js new file mode 100644 index 0000000..5aa845b --- /dev/null +++ b/package.nw/lib/roster/prepareRosterSettings.js @@ -0,0 +1,83 @@ +function prepareRosterSettings() +{ + var rosterSettings = { + bands: {}, + modes: {}, + callMode: g_rosterSettings.callsign, + onlyHits: false, + isAwardTracker: false, + now: timeNowSec() + } + + if (rosterSettings.callMode == "hits") + { + rosterSettings.callMode = "all" + rosterSettings.onlyHits = true; + } + if (referenceNeed.value == LOGBOOK_AWARD_TRACKER) + { + rosterSettings.callMode = "all"; + rosterSettings.onlyHits = false; + rosterSettings.isAwardTracker = true; + g_rosterSettings.huntNeed = "confirmed"; + } + // this appears to be determine if we should show the OAMS column + // if the user is not in offline mode and has OAMS enabled, this could + // be it's own function maybe? + rosterSettings.canMsg = + window.opener.g_mapSettings.offlineMode == false && + window.opener.g_appSettings.gtShareEnable == "true" && + window.opener.g_appSettings.gtMsgEnable == "true"; + + // The following 3 sections deal with QSLing, do we break them out + // individually or lump them into a qslUser function that sets + // all three at the same time? + // this section is for LoTW users, can be a function + 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 (g_rosterSettings.huntNeed == "mixed") + { + rosterSettings.huntIndex = g_confirmed; + rosterSettings.workedIndex = g_worked; + rosterSettings.layeredMode = LAYERED_MODE_FOR[String(g_rosterSettings.reference)]; + } + else if (g_rosterSettings.huntNeed == "worked") + { + rosterSettings.huntIndex = g_worked; + rosterSettings.workedIndex = false; + rosterSettings.layeredMode = false; + } + else if (g_rosterSettings.huntNeed == "confirmed") + { + rosterSettings.huntIndex = g_confirmed; + rosterSettings.workedIndex = g_worked; + rosterSettings.layeredMode = false; + } + else + { + rosterSettings.huntIndex = false; + rosterSettings.workedIndex = false; + rosterSettings.layeredMode = false; + } + + return rosterSettings +} diff --git a/package.nw/lib/roster/processFiltering.js b/package.nw/lib/roster/processFiltering.js new file mode 100644 index 0000000..9d6c21e --- /dev/null +++ b/package.nw/lib/roster/processFiltering.js @@ -0,0 +1,363 @@ +function processRosterFiltering() +{ + // First loop, exclude calls, mostly based on "Exceptions" settings + // this whole section is full of individual if's that could be broken out + 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]; + + // TODO: Move award reason out of exclusions code? + callObj.awardReason = + g_awards[x.sponsor].awards[x.name].tooltip + + " (" + + g_awards[x.sponsor].sponsor + + ")"; + + break; + } + } + } + entry.tx = tx; + } + } +} diff --git a/package.nw/lib/roster/processHunting.js b/package.nw/lib/roster/processHunting.js new file mode 100644 index 0000000..c569e08 --- /dev/null +++ b/package.nw/lib/roster/processHunting.js @@ -0,0 +1,706 @@ +function processHunting() +{ + // these vars, do they rely on anything between the top and here? + // if not could they be put in the var list at the beginning? + 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"; + + // TODO: Hunting results might be used to filter, based on the "Callsigns: Only Wanted" option, + // so maybe we can move this loop first, and add a check to the filtering loop? + + // 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 + + // TODO: This is here because it's after the filtering stage + 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; + + // NOTE: This is where calls that were filtered are passed into an array that will be used for the rendering loop + newCallList.push(callObj); + } + } + + return newCallList; +} diff --git a/package.nw/lib/roster/processRosterFiltering.js b/package.nw/lib/roster/processRosterFiltering.js new file mode 100644 index 0000000..9c41142 --- /dev/null +++ b/package.nw/lib/roster/processRosterFiltering.js @@ -0,0 +1,369 @@ +function processRosterFiltering(callRoster, rosterSettings) +{ + // First loop, exclude calls, mostly based on "Exceptions" settings + // this whole section is full of individual if's that could be broken out + 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 (callObj.dxcc === -1) + { + entry.tx = false; + 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]; + + // TODO: Move award reason out of exclusions code? + callObj.awardReason = + g_awards[x.sponsor].awards[x.name].tooltip + + " (" + + g_awards[x.sponsor].sponsor + + ")"; + + break; + } + } + } + entry.tx = tx; + } + } +} diff --git a/package.nw/lib/roster/processRosterHunting.js b/package.nw/lib/roster/processRosterHunting.js new file mode 100644 index 0000000..6adaeab --- /dev/null +++ b/package.nw/lib/roster/processRosterHunting.js @@ -0,0 +1,700 @@ +function processRosterHunting(callRoster, rosterSettings) +{ + // these vars, do they rely on anything between the top and here? + // if not could they be put in the var list at the beginning? + var hasGtPin = false; + + 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"; + + // TODO: Hunting results might be used to filter, based on the "Callsigns: Only Wanted" option, + // so maybe we can move this loop first, and add a check to the filtering loop? + + // 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 + + // TODO: This is here because it's after the filtering stage + 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 (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; + } + } +} diff --git a/package.nw/lib/roster/renderCompactRoster.js b/package.nw/lib/roster/renderCompactRoster.js new file mode 100644 index 0000000..271a0bc --- /dev/null +++ b/package.nw/lib/roster/renderCompactRoster.js @@ -0,0 +1,55 @@ +function renderCompactRosterHeaders() +{ + return "
"; +} + +function renderCompactRosterRow(callObj) +{ + var thisCall = callObj.DEcall; + var tt = + callObj.RSTsent + + "㏈, " + + parseInt(callObj.dt * 100) + + "ms, " + + callObj.delta + + "hz" + + (callObj.grid.length ? ", " + callObj.grid : "") + + ", " + + (timeNowSec() - callObj.age).toDHMS(); + worker += + "
"; + worker += + "
" + + thisCall.formatCallsign() + + "
"; + worker += + "
" + + window.opener.g_dxccToAltName[callObj.dxcc] + + "
"; + worker += "
"; + + return worker; +} + +function renderCompactRosterFooter() +{ + return "
"; +} diff --git a/package.nw/lib/roster/renderNormalRoster.js b/package.nw/lib/roster/renderNormalRoster.js new file mode 100644 index 0000000..80fa5a8 --- /dev/null +++ b/package.nw/lib/roster/renderNormalRoster.js @@ -0,0 +1,400 @@ +function renderNormalRosterHeaders() +{ + var worker = "" + worker = ""; + + worker += ""; + + if (showBands) + { worker += ""; } + + if (showModes) + { worker += ""; } + + worker += ""; + + if (g_rosterSettings.columns.Calling) + { worker += ""; } + + if (g_rosterSettings.columns.Msg) + { worker += ""; } + + if (g_rosterSettings.columns.DXCC) + { worker += ""; } + + if (g_rosterSettings.columns.Flag) + { worker += ""; } + + if (g_rosterSettings.columns.State) + { worker += ""; } + + if (g_rosterSettings.columns.County) + { worker += ""; } + + if (g_rosterSettings.columns.Cont) + { worker += ""; } + + if (g_rosterSettings.columns.dB) + { worker += ""; } + + if (g_rosterSettings.columns.Freq) + { worker += ""; } + + if (g_rosterSettings.columns.DT) + { worker += ""; } + + if (g_rosterSettings.columns.Dist) + { + worker += ""; + } + + if (g_rosterSettings.columns.Azim) + { worker += ""; } + + if (g_rosterSettings.columns.CQz) + { worker += ""; } + + if (g_rosterSettings.columns.ITUz) + { worker += ""; } + + if (g_rosterSettings.columns.PX) + { worker += ""; } + + if (window.opener.g_callsignLookups.lotwUseEnable == true && g_rosterSettings.columns.LoTW) + { worker += ""; } + + if (window.opener.g_callsignLookups.eqslUseEnable == true && g_rosterSettings.columns.eQSL) + { worker += ""; } + + if (window.opener.g_callsignLookups.oqrsUseEnable == true && g_rosterSettings.columns.OQRS) + { worker += ""; } + + if (g_rosterSettings.columns.Spot) + { worker += ""; } + + if (g_rosterSettings.columns.Life) + { worker += ""; } + + if (g_rosterSettings.columns.OAMS) + { worker += ""; } + + if (g_rosterSettings.columns.Age) + { worker += ""; } + + return worker +} + +function renderNormalRosterRow(callObj) +{ + var thisCall = callObj.DEcall; + var acks = window.opener.g_acknowledgedCalls; + + var thisHash = thisCall + callObj.band + callObj.mode; + var callStr = thisCall.formatCallsign() + if (acks[thisCall]) + { + callStr = `${callStr} ` + callObj.awardReason += ` - ${acks[thisCall].message}` + } + + var worker = ""; + worker += + ""; + + if (showBands) + { + worker += + ""; + } + if (showModes) + { + var color = "888888"; + if (callObj.mode in g_modeColors) + { color = g_modeColors[callObj.mode]; } + worker += + ""; + } + + worker += + ""; + if (g_rosterSettings.columns.Calling) + { + var lookString = callObj.CQ ? "name='CQ'" : "name='Calling'"; + worker += + ""; + } + if (g_rosterSettings.columns.Msg) + { worker += ""; } + + if (g_rosterSettings.columns.DXCC) + { + worker += + ""; + } + if (g_rosterSettings.columns.Flag) + { + worker += + ""; + } + if (g_rosterSettings.columns.State) + { + worker += + ""; + } + if (g_rosterSettings.columns.County) + { + worker += + ""; + } + if (g_rosterSettings.columns.Cont) + { + worker += + ""; + } + + if (g_rosterSettings.columns.dB) + { + worker += + ""; + } + if (g_rosterSettings.columns.Freq) + { worker += ""; } + if (g_rosterSettings.columns.DT) + { worker += ""; } + if (g_rosterSettings.columns.Dist) + { + worker += + ""; + } + if (g_rosterSettings.columns.Azim) + { + worker += + ""; + } + + if (g_rosterSettings.columns.CQz) + { + worker += + ""; + } + if (g_rosterSettings.columns.ITUz) + { + worker += + ""; + } + + if (g_rosterSettings.columns.PX) + { + worker += + ""; + } + + if ( + window.opener.g_callsignLookups.lotwUseEnable == true && + g_rosterSettings.columns.LoTW + ) + { + if (thisCall in window.opener.g_lotwCallsigns) + { + if (g_rosterSettings.maxLoTW < 27) + { + var months = (g_day - window.opener.g_lotwCallsigns[thisCall]) / 30; + if (months > g_rosterSettings.maxLoTW) + { + worker += + ""; + } + else + { + worker += + ""; + } + } + else + { + worker += + ""; + } + } + else worker += ""; + } + if ( + window.opener.g_callsignLookups.eqslUseEnable == true && + g_rosterSettings.columns.eQSL + ) + { + worker += + ""; + } + if ( + window.opener.g_callsignLookups.oqrsUseEnable == true && + g_rosterSettings.columns.OQRS + ) + { + worker += + ""; + } + + if (g_rosterSettings.columns.Spot) + { + worker += + ""; + } + if (g_rosterSettings.columns.Life) + { + worker += + ""; + } + + if (g_rosterSettings.columns.OAMS) + { + if (callObj.style.gt != 0) + { + if (callObj.reason.includes("oams")) + { + worker += + ""; + } + else + { + worker += + ""; + } + } + else worker += ""; + } + + if (g_rosterSettings.columns.Age) + { + worker += + ""; + } + + worker += ""; + + return worker; +} + +function renderNormalRosterFooter() +{ + return "
CallsignBandModeGridCallingMsgDXCCFlagStateCountyContdBFreqDTDist(" + + window.opener.distanceUnit.value.toLowerCase() + ")AzimCQzITUzPXLoTWeQSLOQRSSpotLifeOAMSAge
" + + callStr + + "" + + callObj.band + + "" + callObj.mode + "" + + grid + + "" + + callObj.DXcall.formatCallsign() + + "" + callObj.msg + "" + + window.opener.g_dxccToAltName[callObj.dxcc] + "" + + (callObj.state ? callObj.state.substr(3) : "") + + "" + + (callObj.cnty + ? (callObj.qual ? "" : "~ ") + + window.opener.g_cntyToCounty[callObj.cnty] + + (callObj.qual ? "" : " ~") + : "") + + "" + + (callObj.cont ? callObj.cont : "") + + "" + + callObj.RSTsent + + "" + callObj.delta + "" + callObj.dt + "" + + parseInt( + callObj.distance * + MyCircle.validateRadius(window.opener.distanceUnit.value) + ) + + "" + + parseInt(callObj.heading) + + "" + + callObj.cqza.join(",") + + "" + + callObj.ituza.join(",") + + "" + + (callObj.px ? callObj.px : "") + + "?" + + (thisCall in window.opener.g_eqslCallsigns ? "✔" : "") + + "" + + (thisCall in window.opener.g_oqrsCallsigns ? "✔" : "") + + "" + + spotString + + "" + + (timeNowSec() - callObj.life).toDHMS() + + "" + + (timeNowSec() - callObj.age).toDHMS() + + "
"; +} diff --git a/package.nw/lib/roster/renderRoster.js b/package.nw/lib/roster/renderRoster.js new file mode 100644 index 0000000..20f4be9 --- /dev/null +++ b/package.nw/lib/roster/renderRoster.js @@ -0,0 +1,102 @@ +function renderRoster(callRoster, rosterSettings) +{ + // eQSL - function + if (window.opener.g_callsignLookups.eqslUseEnable == true) useseQSLDiv.style.display = ""; + else useseQSLDiv.style.display = "none"; + + // OQRS - function + if (window.opener.g_callsignLookups.oqrsUseEnable == true) usesOQRSDiv.style.display = ""; + else usesOQRSDiv.style.display = "none"; + + // dealing with spots + if (g_rosterSettings.columns.Spot == true) onlySpotDiv.style.display = ""; + else onlySpotDiv.style.display = "none"; + + // callmode (all or only new) + if (rosterSettings.callMode == "all") allOnlyNewDiv.style.display = ""; + else allOnlyNewDiv.style.display = "none"; + + // Show the roster count in the window title + + var visibleCallList = callRoster.filter(entry => entry.tx); + + var totalCount = Object.keys(callRoster).length; + var visibleCount = visibleCallList.length; + var huntedCount = visibleCallList.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(" • ")}`; + + if (g_rosterSettings.compact == false) + { + visibleCallList.sort(r_sortFunction[g_rosterSettings.lastSortIndex]); + if (g_rosterSettings.lastSortReverse == 1) + { + visibleCallList.reverse(); + } + } + else + { + // Age sort for now... make this happen Tag + visibleCallList.sort(r_sortFunction[6]).reverse(); + } + + var showBands = (Object.keys(rosterSettings.bands).length > 1) || g_rosterSettings.columns.Band; + var showModes = (Object.keys(rosterSettings.modes).length > 1) || g_rosterSettings.columns.Mode; + + var worker = g_rosterSettings.compact ? renderCompactRosterHeaders() : renderNormalRosterHeaders() + + // Third loop: render all rows + for (var x in visibleCallList) + { + var callObj = visibleCallList[x]; + + // TODO: This is filtering + if (callObj.shouldAlert == false && onlyHits == true && callObj.qrz == false) + { continue; } + + var spotString = ""; + if (g_rosterSettings.columns.Spot && callObj.qrz == false) + { + spotString = getSpotString(callObj); + // TODO: This is filtering + if (g_rosterSettings.onlySpot && spotString == "") continue; + } + var grid = callObj.grid.length > 1 ? callObj.grid.substr(0, 4) : "-"; + + var geo = window.opener.g_worldGeoData[window.opener.g_dxccToGeoData[callObj.dxcc]]; + var cqzone = grid in window.opener.g_gridToCQZone ? window.opener.g_gridToCQZone[grid].join(", ") : "-"; + var ituzone = grid in window.opener.g_gridToITUZone ? window.opener.g_gridToITUZone[grid].join(", ") : "-"; + var thisCall = callObj.DEcall; + + if (thisCall.match("^[A-Z][0-9][A-Z](/w+)?$")) + { callObj.style.call = "class='oneByOne'"; } + if (thisCall == window.opener.g_instances[callObj.instance].status.DXcall) + { + if (window.opener.g_instances[callObj.instance].status.TxEnabled == 1) + { + callObj.style.call = "class='dxCalling'"; + } + else + { + callObj.style.call = "class='dxCaller'"; + } + } + + worker += g_rosterSettings.compact ? renderCompactRosterRow(callObj) : renderNormalRosterRow(callObj) + } + + RosterTable.innerHTML = g_rosterSettings.compact ? renderCompactRosterFooter() : renderNormalRosterFooter() +} diff --git a/package.nw/lib/roster/sendAlerts.js b/package.nw/lib/roster/sendAlerts.js new file mode 100644 index 0000000..ab814f1 --- /dev/null +++ b/package.nw/lib/roster/sendAlerts.js @@ -0,0 +1,135 @@ +function sendAlerts(callRoster, rosterSettings) +{ + var dirPath = window.opener.g_scriptDir; + var scriptExists = false; + var script = "cr-alert.sh"; + + var shouldAlert = 0; + + for (var callObj in callRoster) + { if (!callObj.tx) continue } + + // TODO: Get rid of realtime + if (g_rosterSettings.realtime == false) + { + var call = callObj.DEcall; + g_scriptReport[call] = Object.assign({}, callObj); + g_scriptReport[call].dxccName = + window.opener.g_dxccToAltName[callObj.dxcc]; + g_scriptReport[call].distance = parseInt( + callObj.distance * + MyCircle.validateRadius(window.opener.distanceUnit.value) + ); + + delete g_scriptReport[call].DEcall; + g_scriptReport[call].rect = null; + delete g_scriptReport[call].rect; + delete g_scriptReport[call].style; + delete g_scriptReport[call].wspr; + delete g_scriptReport[call].qso; + delete g_scriptReport[call].instance; + + if (callMode != "all") + { + g_scriptReport[call].shouldAlert = true; + g_scriptReport[call].reason.push(g_rosterSettings.hunting); + } + } + + if ( + callObj.alerted == false && + callMode == "all" && + callObj.shouldAlert == true + ) + { + callObj.alerted = true; + shouldAlert++; + } + else if (callObj.alerted == false && callMode != "all") + { + callObj.alerted = true; + shouldAlert++; + } + + callObj.shouldAlert = false; +} + +// NOTE: Ring alerts if needed +try +{ + if (fs.existsSync(dirPath)) + { + if (window.opener.g_platform == "windows") + { + script = "cr-alert.bat"; + } + if ( + fs.existsSync(dirPath + script) && + g_rosterSettings.realtime == false + ) + { + scriptExists = true; + scriptIcon.innerHTML = + "
" + + (window.opener.g_crScript == 1 + ? "Script Enabled" + : "Script Disabled") + + "
"; + scriptIcon.style.display = "block"; + } + else + { + scriptIcon.style.display = "none"; + } + } +} +catch (e) {} + +if (shouldAlert > 0) +{ + if (window.opener.g_classicAlerts.huntRoster == true) + { + var notify = window.opener.huntRosterNotify.value; + if (notify == "0") + { + var media = window.opener.huntRosterNotifyMedia.value; + if (media != "none") window.opener.playAlertMediaFile(media); + } + else if (notify == "1") + { + window.opener.speakAlertString( + window.opener.huntRosterNotifyWord.value + ); + } + } + + if ( + g_rosterSettings.realtime == false && + scriptExists && + window.opener.g_crScript == 1 + ) + { + try + { + fs.writeFileSync( + dirPath + "cr-alert.json", + JSON.stringify(g_scriptReport, null, 2) + ); + + var thisProc = dirPath + script; + var cp = require("child_process"); + var child = cp.spawn(thisProc, [], { + detached: true, + cwd: dirPath.slice(0, -1), + stdio: ["ignore", "ignore", "ignore"] + }); + child.unref(); + } + catch (e) + { + conosle.log(e); + } + g_scriptReport = Object(); + } + else g_scriptReport = Object(); +}