// GridTracker Copyright © 2021 GridTracker.org // All rights reserved. // See LICENSE for more information. var fs = require("fs"); var callRoster = {}; var g_blockedCalls = {}; var g_blockedCQ = {}; var g_blockedDxcc = {}; var g_scriptReport = {}; var g_worked = {}; var g_confirmed = {}; var g_modes = {}; var g_modes_phone = {}; var g_currentUSCallsigns = null; var r_currentUSState = ""; var r_currentDXCCs = -1; var r_callsignManifest = null; var g_rosterSettings = {}; var g_day = 0; var g_menu = null; var g_callMenu = null; var g_ageMenu = null; var g_callingMenu = null; var g_compactMenu = null; var g_targetHash = ""; var g_clearIgnores = null; var g_clearIgnoresCall = null; var g_dxccMenu = null; var g_targetDxcc = -1; var g_clearDxccIgnore = null; var g_clearDxccIgnoreMainMenu = null; var g_CQMenu = null; var g_targetCQ = ""; var g_clearCQIgnore = null; var g_clearCQIgnoreMainMenu = null; var g_timerInterval = null; var g_regFocus = false; var g_awards = {}; var g_awardTypes = {}; var g_awardTracker = {}; var g_callsignDatabaseDXCC = {}; var g_callsignDatabaseUS = {}; var g_callsignDatabaseUSplus = {}; var g_developerMode = process.versions["nw-flavor"] == "sdk"; var g_modeColors = {}; g_modeColors.FT4 = "1111FF"; g_modeColors.FT8 = "11FF11"; g_modeColors.JT4 = "EE1111"; g_modeColors.JT9 = "7CFC00"; g_modeColors.JT65 = "E550E5"; g_modeColors.QRA64 = "FF00FF"; g_modeColors.MSK144 = "4949FF"; var g_defaultSettings = { callsign: "all", hunting: "dxcc", huntNeed: "confirmed", requireGrid: true, wantMaxDT: false, wantMinDB: false, wantMinFreq: false, wantMaxFreq: false, maxDT: 0.5, minDb: -25, minFreq: 0, maxFreq: 3500, noMyDxcc: false, onlyMyDxcc: false, noMsg: false, noMsgValue: "CQ RU", onlyMsg: false, onlyMsgValue: "CQ FD", cqOnly: true, usesLoTW: false, maxLoTW: 27, useseQSL: false, usesOQRS: false, onlySpot: false, allOnlyNew: false, useRegex: false, callsignRegex: "", realtime: false, wanted: { huntCallsign: false, huntGrid: true, huntDXCC: true, huntCQz: false, huntITUz: false, huntState: false, huntCounty: false, huntCont: false, huntPX: false, huntQRZ: true, huntOAMS: false }, columns: { Band: false, Mode: false, Calling: true, Msg: false, DXCC: true, Flag: true, State: true, County: true, Cont: true, dB: true, Freq: false, DT: false, Dist: false, Azim: true, CQz: false, ITUz: false, PX: true, LoTW: false, eQSL: false, OQRS: false, Spot: false, Life: false, OAMS: true, Age: true }, reference: 0, controls: true, controlsExpanded: false, compact: false, settingProfiles: false, lastSortIndex: 6, lastSortReverse: 1 }; const LOGBOOK_LIVE_BAND_LIVE_MODE = "0"; const LOGBOOK_LIVE_BAND_MIX_MODE = "1"; const LOGBOOK_LIVE_BAND_DIGI_MODE = "2"; const LOGBOOK_MIX_BAND_LIVE_MODE = "3"; const LOGBOOK_MIX_BAND_MIX_MODE = "4"; const LOGBOOK_MIX_BAND_DIGI_MODE = "5"; const LOGBOOK_AWARD_TRACKER = "6"; const LAYERED_MODE_FOR = {} LAYERED_MODE_FOR[LOGBOOK_MIX_BAND_LIVE_MODE] = LOGBOOK_LIVE_BAND_LIVE_MODE; LAYERED_MODE_FOR[LOGBOOK_MIX_BAND_MIX_MODE] = LOGBOOK_LIVE_BAND_MIX_MODE; LAYERED_MODE_FOR[LOGBOOK_MIX_BAND_DIGI_MODE] = LOGBOOK_LIVE_BAND_DIGI_MODE; document.addEventListener("dragover", function (event) { event.preventDefault(); }); document.addEventListener("drop", function (event) { event.preventDefault(); }); window.addEventListener("message", receiveMessage, false); if (typeof localStorage.blockedCQ == "undefined") { localStorage.blockedCQ = "{}"; } if (typeof localStorage.awardTracker == "undefined") { localStorage.awardTracker = "{}"; g_rosterSettings = {}; writeRosterSettings(); } g_awardTracker = JSON.parse(localStorage.awardTracker); if (typeof localStorage.blockedCalls != "undefined") { g_blockedCalls = JSON.parse(localStorage.blockedCalls); g_blockedCQ = JSON.parse(localStorage.blockedCQ); g_blockedDxcc = JSON.parse(localStorage.blockedDxcc); } function storeBlocks() { localStorage.blockedCalls = JSON.stringify(g_blockedCalls); localStorage.blockedCQ = JSON.stringify(g_blockedCQ); localStorage.blockedDxcc = JSON.stringify(g_blockedDxcc); } function storeAwardTracker() { localStorage.awardTracker = JSON.stringify(g_awardTracker); } function loadSettings() { var readSettings = {}; if (typeof localStorage.rosterSettings != "undefined") { readSettings = JSON.parse(localStorage.rosterSettings); } g_rosterSettings = deepmerge(g_defaultSettings, readSettings); if ("GT" in g_rosterSettings.columns) delete g_rosterSettings.columns.GT; writeRosterSettings(); } function writeRosterSettings() { localStorage.rosterSettings = JSON.stringify(g_rosterSettings); } function isKnownCallsignDXCC(dxcc) { if (dxcc in g_callsignDatabaseDXCC) return true; return false; } function isKnownCallsignUS(dxcc) { if (dxcc in g_callsignDatabaseUS) return true; return false; } function isKnownCallsignUSplus(dxcc) { if (dxcc in g_callsignDatabaseUSplus) return true; return false; } function timeNowSec() { return parseInt(Date.now() / 1000); } function lockNewWindows() { if (typeof nw != "undefined") { var gui = require("nw.gui"); var win = gui.Window.get(); win.on("new-win-policy", function (frame, url, policy) { gui.Shell.openExternal(url); policy.ignore(); }); } } function myCallCompare(a, b) { return a.DEcall.localeCompare(b.DEcall); } function myGridCompare(a, b) { var gridA = a.grid ? a.grid : "0"; var gridB = b.grid ? b.grid : "0"; if (gridA > gridB) return 1; if (gridA < gridB) return -1; return 0; } function myDxccCompare(a, b) { return window.opener.myDxccCompare(a, b); } function myTimeCompare(a, b) { if (a.age > b.age) return 1; if (a.age < b.age) return -1; return 0; } function myLifeCompare(a, b) { if (a.life > b.life) return 1; if (a.life < b.life) return -1; return 0; } function mySpotCompare(a, b) { if (a.spot.when > b.spot.when) return 1; if (a.spot.when < b.spot.when) return -1; return 0; } function myDbCompare(a, b) { if (a.RSTsent > b.RSTsent) return 1; if (a.RSTsent < b.RSTsent) return -1; return 0; } function myFreqCompare(a, b) { if (a.delta > b.delta) return 1; if (a.delta < b.delta) return -1; return 0; } function myDTCompare(a, b) { if (a.dt > b.dt) return 1; if (a.dt < b.dt) return -1; return 0; } function myDistanceCompare(a, b) { if (a.distance > b.distance) return 1; if (a.distance < b.distance) return -1; return 0; } function myHeadingCompare(a, b) { if (a.heading > b.heading) return 1; if (a.heading < b.heading) return -1; return 0; } function myStateCompare(a, b) { if (a.state == null) return 1; if (b.state == null) return -1; if (a.state > b.state) return 1; if (a.state < b.state) return -1; return 0; } function myCQCompare(a, b) { return a.DXcall.localeCompare(b.DXcall); } function myWPXCompare(a, b) { if (a.px == null) return 1; if (b.px == null) return -1; if (a.px > b.px) return 1; if (a.px < b.px) return -1; return 0; } function myCntyCompare(a, b) { if (a.cnty == null) return 1; if (b.cnty == null) return -1; if (a.cnty.substr(3) > b.cnty.substr(3)) return 1; if (a.cnty.substr(3) < b.cnty.substr(3)) return -1; return 0; } function myContCompare(a, b) { if (a.cont == null) return 1; if (b.cont == null) return -1; if (a.cont > b.cont) return 1; if (a.cont < b.cont) return -1; return 0; } function myGTCompare(a, b) { if (a.style.gt != 0 && b.style.gt == 0) return 1; if (a.style.gt == 0 && b.style.gt != 0) return -1; return 0; } var r_sortFunction = [ myCallCompare, myGridCompare, myDbCompare, myDTCompare, myFreqCompare, myDxccCompare, myTimeCompare, myDistanceCompare, myHeadingCompare, myStateCompare, myCQCompare, myWPXCompare, myLifeCompare, mySpotCompare, myGTCompare, myCntyCompare, myContCompare ]; function showRosterBox(sortIndex) { if (g_rosterSettings.lastSortIndex != sortIndex) { g_rosterSettings.lastSortIndex = sortIndex; g_rosterSettings.lastSortReverse = 0; } else { g_rosterSettings.lastSortReverse ^= 1; } writeRosterSettings(); window.opener.goProcessRoster(); } function hashMaker(start, callObj, reference) { if (reference == LOGBOOK_LIVE_BAND_LIVE_MODE) return `${start}${callObj.band}${callObj.mode}`; if (reference == LOGBOOK_AWARD_TRACKER) return `${start}${callObj.band}${callObj.mode}`; if (reference == LOGBOOK_LIVE_BAND_MIX_MODE) return `${start}${callObj.band}`; if (reference == LOGBOOK_LIVE_BAND_DIGI_MODE) return `${start}${callObj.band}dg`; if (reference == LOGBOOK_MIX_BAND_LIVE_MODE) return `${start}${callObj.mode}`; if (reference == LOGBOOK_MIX_BAND_MIX_MODE) return `${start}`; if (reference == LOGBOOK_MIX_BAND_DIGI_MODE) return `${start}dg`; return ""; } function processRoster(roster) { callRoster = roster; viewRoster(); } function viewRoster() { var bands = Object(); var modes = Object(); var callMode = g_rosterSettings.callsign; var onlyHits = false; var isAwardTracker = false; if (callMode == "hits") { callMode = "all"; onlyHits = true; } if (referenceNeed.value == LOGBOOK_AWARD_TRACKER) { callMode = "all"; onlyHits = false; isAwardTracker = true; g_rosterSettings.huntNeed = "confirmed"; } var canMsg = window.opener.g_mapSettings.offlineMode == false && window.opener.g_appSettings.gtShareEnable == "true" && window.opener.g_appSettings.gtMsgEnable == "true"; if (window.opener.g_callsignLookups.lotwUseEnable == true) { usesLoTWDiv.style.display = ""; if (g_rosterSettings.usesLoTW == true) { maxLoTW.style.display = ""; maxLoTWView.style.display = ""; } else { maxLoTW.style.display = "none"; maxLoTWView.style.display = "none"; } } else { usesLoTWDiv.style.display = "none"; maxLoTW.style.display = "none"; maxLoTWView.style.display = "none"; } if (window.opener.g_callsignLookups.eqslUseEnable == true) useseQSLDiv.style.display = ""; else useseQSLDiv.style.display = "none"; if (window.opener.g_callsignLookups.oqrsUseEnable == true) usesOQRSDiv.style.display = ""; else usesOQRSDiv.style.display = "none"; if (g_rosterSettings.columns.Spot == true) onlySpotDiv.style.display = ""; else onlySpotDiv.style.display = "none"; if (callMode == "all") allOnlyNewDiv.style.display = ""; else allOnlyNewDiv.style.display = "none"; var huntIndex, workedIndex, layeredMode; if (g_rosterSettings.huntNeed == "mixed") { huntIndex = g_confirmed; workedIndex = g_worked; layeredMode = LAYERED_MODE_FOR[String(g_rosterSettings.reference)]; } else if (g_rosterSettings.huntNeed == "worked") { huntIndex = g_worked; workedIndex = false; layeredMode = false; } else if (g_rosterSettings.huntNeed == "confirmed") { huntIndex = g_confirmed; workedIndex = g_worked; layeredMode = false; } else { huntIndex = false; workedIndex = false; layeredMode = false; } var now = timeNowSec(); // First loop, exclude calls, mostly based on "Exceptions" settings for (var callHash in callRoster) { var entry = callRoster[callHash]; var callObj = entry.callObj; var call = entry.DEcall; entry.tx = true; callObj.shouldAlert = false; callObj.reason = Array(); callObj.awardReason = "Callsign"; if (now - callObj.age > window.opener.g_mapSettings.rosterTime) { entry.tx = false; entry.alerted = false; callObj.qrz = false; callObj.reset = true; continue; } if (window.opener.g_instances[callObj.instance].crEnable == false) { entry.tx = false; continue; } if (call in g_blockedCalls) { entry.tx = false; continue; } if ( entry.DXcall + " from All" in g_blockedCQ || entry.DXcall + " from " + window.opener.g_dxccToAltName[callObj.dxcc] in g_blockedCQ ) { entry.tx = false; continue; } if (callObj.dxcc in g_blockedDxcc) { entry.tx = false; continue; } if (g_rosterSettings.cqOnly == true && callObj.CQ == false) { entry.tx = false; continue; } if (g_rosterSettings.useRegex && g_rosterSettings.callsignRegex.length > 0) { try { if (!call.match(g_rosterSettings.callsignRegex)) { entry.tx = false; continue; } } catch (e) {} } if (g_rosterSettings.requireGrid == true && callObj.grid.length != 4) { entry.tx = false; continue; } if (g_rosterSettings.wantMinDB == true && entry.message.SR < g_rosterSettings.minDb) { entry.tx = false; continue; } if (g_rosterSettings.wantMaxDT == true && Math.abs(entry.message.DT) > g_rosterSettings.maxDT) { entry.tx = false; continue; } if (g_rosterSettings.wantMinFreq == true && entry.message.DF < g_rosterSettings.minFreq) { entry.tx = false; continue; } if (g_rosterSettings.wantMaxFreq == true && entry.message.DF > g_rosterSettings.maxFreq) { entry.tx = false; continue; } if (g_rosterSettings.noMsg == true) { try { if (callObj.msg.match(g_rosterSettings.noMsgValue)) { entry.tx = false; continue; } } catch (e) {} } if (g_rosterSettings.onlyMsg == true) { try { if (!callObj.msg.match(g_rosterSettings.onlyMsgValue)) { entry.tx = false; continue; } } catch (e) {} } if (callObj.dxcc == window.opener.g_myDXCC) { if (g_rosterSettings.noMyDxcc == true) { entry.tx = false; continue; } } else { if (g_rosterSettings.onlyMyDxcc == true) { entry.tx = false; continue; } } if (window.opener.g_callsignLookups.lotwUseEnable == true && g_rosterSettings.usesLoTW == true) { if (!(call in window.opener.g_lotwCallsigns)) { entry.tx = false; continue; } if (g_rosterSettings.maxLoTW < 27) { var months = (g_day - window.opener.g_lotwCallsigns[call]) / 30; if (months > g_rosterSettings.maxLoTW) { entry.tx = false; continue; } } } if (window.opener.g_callsignLookups.eqslUseEnable == true && g_rosterSettings.useseQSL == true) { if (!(call in window.opener.g_eqslCallsigns)) { entry.tx = false; continue; } } if (window.opener.g_callsignLookups.oqrsUseEnable == true && g_rosterSettings.usesOQRS == true) { if (!(call in window.opener.g_oqrsCallsigns)) { entry.tx = false; continue; } } if (callMode != "all") { if (entry.DXcall == "CQ DX" && callObj.dxcc == window.opener.g_myDXCC) { entry.tx = false; continue; } var hash = hashMaker(call, callObj, g_rosterSettings.reference); if (callMode == "worked" && hash in g_worked.call) { entry.tx = false; continue; } if (callMode == "confirmed" && hash in g_confirmed.call) { entry.tx = false; continue; } if (g_rosterSettings.hunting == "grid") { var hash = hashMaker(callObj.grid.substr(0, 4), callObj, g_rosterSettings.reference); if (huntIndex && hash in huntIndex.grid) { entry.tx = false; continue; } if (callObj.grid.length == 0) { entry.tx = false; continue; } continue; } if (g_rosterSettings.hunting == "dxcc") { var hash = hashMaker(String(callObj.dxcc), callObj, g_rosterSettings.reference); if (huntIndex && (hash in huntIndex.dxcc)) { entry.tx = false; continue; } continue; } if (g_rosterSettings.hunting == "dxccs" && r_currentDXCCs != -1) { if (callObj.dxcc != r_currentDXCCs) { entry.tx = false; continue; } } if (g_rosterSettings.hunting == "wpx") { if (String(callObj.px) == null) { entry.tx = false; continue; } var hash = hashMaker(String(callObj.px), callObj, g_rosterSettings.reference); if (huntIndex && (hash in huntIndex.px)) { entry.tx = false; continue; } continue; } if (g_rosterSettings.hunting == "cq") { var huntTotal = callObj.cqza.length; if (huntTotal == 0 || !huntIndex) { entry.tx = false; continue; } var huntFound = 0; for (index in callObj.cqza) { var hash = hashMaker(callObj.cqza[index], callObj, g_rosterSettings.reference); if (hash in huntIndex.cqz) huntFound++; } if (huntFound == huntTotal) { entry.tx = false; continue; } continue; } if (g_rosterSettings.hunting == "itu") { var huntTotal = callObj.ituza.length; if (huntTotal == 0 || !huntIndex) { entry.tx = false; continue; } var huntFound = 0; for (index in callObj.ituza) { var hash = hashMaker(callObj.ituza[index], callObj, g_rosterSettings.reference); if (hash in huntIndex.ituz) huntFound++; } if (huntFound == huntTotal) { entry.tx = false; continue; } if (callObj.grid.length == 0) { entry.tx = false; continue; } continue; } if (g_rosterSettings.hunting == "usstates" && window.opener.g_callsignLookups.ulsUseEnable == true) { var state = callObj.state; var finalDxcc = callObj.dxcc; if (finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6) { if (state in window.opener.g_StateData) { var hash = hashMaker(state, callObj, g_rosterSettings.reference); if (huntIndex && hash in huntIndex.state) { entry.tx = false; continue; } } else entry.tx = false; } else entry.tx = false; continue; } if (g_rosterSettings.hunting == "usstate" && g_currentUSCallsigns) { if (call in g_currentUSCallsigns) { // Do Nothing } else { entry.tx = false; continue; } continue; } } if (isAwardTracker) { var tx = false; var baseHash = hashMaker("", callObj, g_rosterSettings.reference); for (var award in g_awardTracker) { if (g_awardTracker[award].enable) { tx = testAward(award, callObj, baseHash); if (tx) { var x = g_awardTracker[award]; callObj.awardReason = g_awards[x.sponsor].awards[x.name].tooltip + " (" + g_awards[x.sponsor].sponsor + ")"; break; } } } entry.tx = tx; } } var hasGtPin = false; var newCallList = Array(); var inversionAlpha = "DD"; var row = "#000000"; var bold = "#000000;font-weight: bold;"; var unconf = "background-clip:padding-box;box-shadow: 0 0 7px 3px inset "; var layeredAlpha = "77"; var layeredInversionAlpha = "66"; var layeredUnconf = "background-clip:padding-box;box-shadow: 0 0 4px 2px inset "; var layeredUnconfAlpha = "AA"; // Second loop, hunting and highlighting for (var callHash in callRoster) { var entry = callRoster[callHash]; var callObj = entry.callObj; // Special case check for called station if (callObj.qrz == true && entry.tx == false) { // The instance has to be enabled if (window.opener.g_instances[callObj.instance].crEnable == true) { // Calling us, but we wouldn't normally display // If they are not ignored or we're in a QSO with them, var it through if ((!(entry.DEcall in g_blockedCalls) && !(callObj.dxcc in g_blockedDxcc)) || window.opener.g_instances[callObj.instance].status.DXcall == entry.DEcall) { entry.tx = true; } } } // Only render entries with `tx == true`, ignore the rest if (callObj.dxcc != -1 && entry.tx == true) { // In layered mode ("Hunting: mixed") the workHashSuffix becomes a more stricter 'live band', // while the layered suffix is a broader 'mixed band' var workHashSuffix, layeredHashSuffix; if (layeredMode) { workHashSuffix = hashMaker("", callObj, layeredMode); layeredHashSuffix = hashMaker("", callObj, g_rosterSettings.reference); } else { workHashSuffix = hashMaker("", callObj, g_rosterSettings.reference); layeredHashSuffix = false } var workHash = workHashSuffix; // TODO: Remove after replacing all occurrences with Suffix var callsign = entry.DEcall; callObj.hunting = {} callObj.callFlags = {} var colorObject = Object(); var callPointer = callObj.CQ == true ? "cursor:pointer" : ""; var didWork = false; var call = "#FFFF00"; var grid = "#00FFFF"; var calling = "#90EE90"; var dxcc = "#FFA500"; var state = "#90EE90"; var cnty = "#CCDD00"; var cont = "#00DDDD"; var cqz = "#DDDDDD"; var ituz = "#DDDDDD"; var wpx = "#FFFF00"; hasGtPin = false; var shouldAlert = false; var callBg, gridBg, callingBg, dxccBg, stateBg, cntyBg, contBg, cqzBg, ituzBg, wpxBg, gtBg; var callConf, gridConf, callingConf, dxccConf, stateConf, cntyConf, contConf, cqzConf, ituzConf, wpxConf; callBg = gridBg = callingBg = dxccBg = stateBg = cntyBg = contBg = cqzBg = ituzBg = wpxBg = gtBg = row; callConf = gridConf = callingConf = dxccConf = stateConf = cntyConf = contConf = cqzConf = ituzConf = wpxConf = ""; var hash = callsign + workHashSuffix; var layeredHash = layeredHashSuffix && (callsign + layeredHashSuffix) // Call worked in current logbook settings, regardless of hunting mode if (hash in g_worked.call) { callObj.callFlags.worked = true; didWork = true; callConf = `${unconf}${call}${inversionAlpha};`; if (hash in g_confirmed.call) { callObj.callFlags.confirmed = true; callPointer = "text-decoration: line-through; "; callConf = ""; } } // Calls that have OAMS chat support if ( callsign in window.opener.g_gtCallsigns && window.opener.g_gtCallsigns[callsign] in window.opener.g_gtFlagPins && window.opener.g_gtFlagPins[window.opener.g_gtCallsigns[callsign]].canmsg == true ) { callObj.callFlags.oams = true; // grab the CID colorObject.gt = window.opener.g_gtCallsigns[callsign]; hasGtPin = true; } else { colorObject.gt = 0; } // We only do hunt highlighting when showing all entries // This means "Callsigns: All Traffic", "Callsigns: All Traffic/Only Wanted" and "Logbook: Award Tracker" // There is no highlighting in other modes if (callMode == "all") { // Skip when "only new calls" // Questions: Move to the first loop? Why only skip new calls in "all traffic" and not other modes? if (allOnlyNew.checked == true && didWork && callObj.qrz == false) { entry.tx = false; continue; } // Hunting for callsigns if (huntCallsign.checked == true) { var hash = callsign + workHashSuffix; var layeredHash = layeredMode && (callsign + layeredHashSuffix) if (huntIndex && !(hash in huntIndex.call)) { shouldAlert = true; callObj.reason.push("call"); if (workedIndex && hash in workedIndex.call) { if (layeredMode && layeredHash in huntIndex.call) { callObj.hunting.call = "worked-and-mixed"; callConf = `${layeredUnconf}${call}${layeredUnconfAlpha};`; callBg = `${call}${layeredInversionAlpha}`; call = bold; } // /* Currently we don't have a way to figure out // * if the call is worked only in this band or also others, // * so we cannot cover this particular combination // * and have to default to just showing it as plain "worked" // */ // else if (layeredMode && layeredHash in workedIndex.call) // { // callObj.hunting.call = "worked-and-mixed-worked"; // callConf = `${layeredUnconf}${call}${layeredAlpha};`; // } else { callObj.hunting.call = "worked"; callConf = `${unconf}${call}${inversionAlpha};`; } } else { if (layeredMode && layeredHash in huntIndex.call) { callObj.hunting.call = "mixed"; callBg = `${call}${layeredAlpha};`; call = bold; } else if (layeredMode && layeredHash in workedIndex.call) { callObj.hunting.call = "mixed-worked"; callConf = `${unconf}${call}${layeredAlpha};`; } else { callObj.hunting.call = "hunted"; callBg = `${call}${inversionAlpha};`; call = bold; } } } } // Hunting for "stations calling you" if (huntQRZ.checked == true && callObj.qrz == true) { callObj.callFlags.calling = true shouldAlert = true; callObj.reason.push("qrz"); } // Hunting for stations with OAMS if (huntOAMS.checked == true && hasGtPin == true) { callObj.hunting.oams = "hunted"; shouldAlert = true; callObj.reason.push("oams"); } // Hunting for grids if (huntGrid.checked == true && callObj.grid.length > 1) { var hash = callObj.grid.substr(0, 4) + workHashSuffix; var layeredHash = layeredMode && (callObj.grid.substr(0, 4) + layeredHashSuffix) if (huntIndex && !(hash in huntIndex.grid)) { shouldAlert = true; callObj.reason.push("grid"); if (workedIndex && hash in workedIndex.grid) { if (layeredMode && layeredHash in huntIndex.grid) { callObj.hunting.grid = "worked-and-mixed"; gridConf = `${layeredUnconf}${grid}${layeredUnconfAlpha};`; gridBg = `${grid}${layeredInversionAlpha}`; grid = bold; } else { callObj.hunting.grid = "worked"; gridConf = `${unconf}${grid}${inversionAlpha};`; } } else { if (layeredMode && layeredHash in huntIndex.grid) { callObj.hunting.grid = "mixed"; gridBg = `${grid}${layeredAlpha};`; grid = bold; } else if (layeredMode && layeredHash in workedIndex.grid) { callObj.hunting.grid = "mixed-worked"; gridConf = `${unconf}${grid}${layeredAlpha};`; } else { callObj.hunting.grid = "hunted"; gridBg = `${grid}${inversionAlpha};`; grid = bold; } } } } // Hunting for DXCC if (huntDXCC.checked == true) { var hash = String(callObj.dxcc) + workHashSuffix; var layeredHash = layeredMode && (String(callObj.dxcc) + layeredHashSuffix) if (huntIndex && !(hash in huntIndex.dxcc)) { shouldAlert = true; callObj.reason.push("dxcc"); if (workedIndex && hash in workedIndex.dxcc) { if (layeredMode && layeredHash in huntIndex.dxcc) { callObj.hunting.dxcc = "worked-and-mixed"; dxccConf = `${layeredUnconf}${dxcc}${layeredUnconfAlpha};`; dxccBg = `${dxcc}${layeredInversionAlpha}`; dxcc = bold; } else { callObj.hunting.dxcc = "worked"; dxccConf = `${unconf}${dxcc}${inversionAlpha};`; } } else { if (layeredMode && layeredHash in huntIndex.dxcc) { callObj.hunting.dxcc = "mixed"; dxccBg = `${dxcc}${layeredAlpha};`; dxcc = bold; } else if (layeredMode && layeredHash in workedIndex.dxcc) { callObj.hunting.dxcc = "mixed-worked"; dxccConf = `${unconf}${dxcc}${layeredAlpha};`; } else { callObj.hunting.dxcc = "hunted"; dxccBg = `${dxcc}${inversionAlpha};`; dxcc = bold; } } } } // Hunting for US States if (huntState.checked == true && window.opener.g_callsignLookups.ulsUseEnable == true) { var stateSearch = callObj.state; var finalDxcc = callObj.dxcc; if (finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6) { if (stateSearch in window.opener.g_StateData) { var hash = stateSearch + workHashSuffix; var layeredHash = layeredMode && (stateSearch + layeredHashSuffix) if (huntIndex && !(hash in huntIndex.state)) { shouldAlert = true; callObj.reason.push("state"); if (workedIndex && hash in workedIndex.state) { if (layeredMode && layeredHash in huntIndex.state) { callObj.hunting.state = "worked-and-mixed"; stateConf = `${layeredUnconf}${state}${layeredUnconfAlpha};`; stateBg = `${state}${layeredInversionAlpha}`; state = bold; } else { callObj.hunting.state = "worked"; stateConf = `${unconf}${state}${inversionAlpha};`; } } else { if (layeredMode && layeredHash in huntIndex.state) { callObj.hunting.state = "mixed"; stateBg = `${state}${layeredAlpha};`; state = bold; } else if (layeredMode && layeredHash in workedIndex.state) { callObj.hunting.state = "mixed-worked"; stateConf = `${unconf}${state}${layeredAlpha};`; } else { callObj.hunting.state = "hunted"; stateBg = `${state}${inversionAlpha};`; state = bold; } } } } } } // Hunting for US Counties if (huntCounty.checked == true && window.opener.g_callsignLookups.ulsUseEnable == true) { var finalDxcc = callObj.dxcc; if ( callObj.cnty && (finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6 || finalDxcc == 202) && callObj.cnty.length > 0 ) { var hash = callObj.cnty + (layeredMode ? layeredHashSuffix : workHashSuffix); if ((huntIndex && !(hash in huntIndex.cnty)) || callObj.qual == false) { if (callObj.qual == false) { var counties = window.opener.g_zipToCounty[callObj.zipcode]; var foundHit = false; for (var cnt in counties) { var hh = counties[cnt] + workHash; callObj.cnty = counties[cnt]; if (huntIndex && !(hh in huntIndex.cnty)) { foundHit = true; break; } } if (foundHit) shouldAlert = true; } else { shouldAlert = true; } if (shouldAlert) { callObj.reason.push("cnty"); if (workedIndex && hash in workedIndex.cnty) { callObj.hunting.cnty = "worked"; cntyConf = `${unconf}${cnty}${inversionAlpha};`; } else { callObj.hunting.cnty = "hunted"; cntyBg = `${cnty}${inversionAlpha}`; cnty = bold; } } } } } // Hunting for CQ Zones if (huntCQz.checked == true) { var huntTotal = callObj.cqza.length; var huntFound = 0, layeredFound = 0, workedFound = 0, layeredWorkedFound = 0; for (index in callObj.cqza) { var hash = callObj.cqza[index] + workHashSuffix; var layeredHash = layeredMode && (callObj.cqza[index] + layeredHashSuffix) if (huntIndex && hash in huntIndex.cqz) huntFound++; if (layeredMode && layeredHash in huntIndex.cqz) layeredFound++; if (workedIndex && hash in workedIndex.cqz) workedFound++; if (layeredMode && layeredHash in workedIndex.cqz) layeredWorkedFound++; } if (huntFound != huntTotal) { shouldAlert = true; callObj.reason.push("cqz"); if (workedIndex && workedFound == huntTotal) { if (layeredMode && layeredFound == huntTotal) { callObj.hunting.cqz = "worked-and-mixed"; cqzConf = `${layeredUnconf}${cqz}${layeredUnconfAlpha};`; cqzBg = `${cqz}${layeredInversionAlpha}`; cqz = bold; } else { callObj.hunting.cqz = "worked"; cqzConf = `${unconf}${cqz}${inversionAlpha};`; } } else { if (layeredMode && layeredFound == huntTotal) { callObj.hunting.cqz = "mixed"; cqzBg = `${cqz}${layeredAlpha};`; cqz = bold; } else if (layeredMode && layeredWorkedFound == huntTotal) { callObj.hunting.cqz = "mixed-worked"; cqzConf = `${unconf}${cqz}${layeredAlpha};`; } else { callObj.hunting.cqz = "hunted"; cqzBg = `${cqz}${inversionAlpha};`; cqz = bold; } } } } // Hunting for ITU Zones if (huntITUz.checked == true) { var huntTotal = callObj.ituza.length; var huntFound = 0, layeredFound = 0, workedFound = 0, layeredWorkedFound = 0; for (index in callObj.ituza) { var hash = callObj.ituza[index] + workHashSuffix; var layeredHash = layeredMode && (callObj.ituza[index] + layeredHashSuffix) if (huntIndex && hash in huntIndex.ituz) huntFound++; if (layeredMode && layeredHash in huntIndex.ituz) layeredFound++; if (workedIndex && hash in workedIndex.ituz) workedFound++; if (layeredMode && layeredHash in workedIndex.ituz) layeredWorkedFound++; } if (huntFound != huntTotal) { shouldAlert = true; callObj.reason.push("ituz"); if (workedIndex && workedFound == huntTotal) { if (layeredMode && layeredFound == huntTotal) { callObj.hunting.ituz = "worked-and-mixed"; ituzConf = `${layeredUnconf}${ituz}${layeredUnconfAlpha};`; ituzBg = `${ituz}${layeredInversionAlpha}`; ituz = bold; } else { callObj.hunting.ituz = "worked"; ituzConf = `${unconf}${ituz}${inversionAlpha};`; } } else { if (layeredMode && layeredFound == huntTotal) { callObj.hunting.ituz = "mixed"; ituzBg = `${ituz}${layeredAlpha};`; ituz = bold; } else if (layeredMode && layeredWorkedFound == huntTotal) { callObj.hunting.ituz = "mixed-worked"; ituzConf = `${unconf}${ituz}${layeredAlpha};`; } else { callObj.hunting.ituz = "hunted"; ituzBg = `${ituz}${inversionAlpha};`; ituz = bold; } } } } // Hunting for WPX (Prefixes) if (huntPX.checked == true && callObj.px) { var hash = String(callObj.px) + workHashSuffix; var layeredHash = layeredMode && (String(callObj.px) + layeredHashSuffix) if (huntIndex && !(hash in huntIndex.px)) { shouldAlert = true; callObj.reason.push("wpx"); if (workedIndex && hash in workedIndex.px) { if (layeredMode && layeredHash in huntIndex.px) { callObj.hunting.wpx = "worked-and-mixed"; wpxConf = `${layeredUnconf}${wpx}${layeredUnconfAlpha};`; wpxBg = `${wpx}${layeredInversionAlpha}`; wpx = bold; } else { callObj.hunting.wpx = "worked"; wpxConf = `${unconf}${wpx}${inversionAlpha};`; } } else { if (layeredMode && layeredHash in huntIndex.px) { callObj.hunting.wpx = "mixed"; wpxBg = `${wpx}${layeredAlpha};`; wpx = bold; } else if (layeredMode && layeredHash in workedIndex.px) { callObj.hunting.wpx = "mixed-worked"; wpxConf = `${unconf}${wpx}${layeredAlpha};`; } else { callObj.hunting.wpx = "hunted"; wpxBg = `${wpx}${inversionAlpha};`; wpx = bold; } } } } // Hunting for Continents if (huntCont.checked == true && callObj.cont) { var hash = String(callObj.cont) + workHashSuffix; var layeredHash = layeredMode && (String(callObj.cont) + layeredHashSuffix) if (huntIndex && !(hash in huntIndex.cont)) { shouldAlert = true; callObj.reason.push("cont"); if (workedIndex && hash in workedIndex.cont) { if (layeredMode && layeredHash in huntIndex.cont) { callObj.hunting.cont = "worked-and-mixed"; contConf = `${layeredUnconf}${cont}${layeredUnconfAlpha};`; contBg = `${cont}${layeredInversionAlpha}`; cont = bold; } else { callObj.hunting.cont = "worked"; contConf = `${unconf}${cont}${inversionAlpha};`; } } else { if (layeredMode && layeredHash in huntIndex.cont) { callObj.hunting.cont = "mixed"; contBg = `${cont}${layeredAlpha};`; cont = bold; } else if (layeredMode && layeredHash in workedIndex.cont) { callObj.hunting.cont = "mixed-worked"; contConf = `${unconf}${cont}${layeredAlpha};`; } else { callObj.hunting.cont = "hunted"; contBg = `${cont}${inversionAlpha};`; cont = bold; } } } } } // Station is calling us if (callObj.DXcall == window.opener.myDEcall) { callingBg = "#0000FF" + inversionAlpha; calling = "#FFFF00;text-shadow: 0px 0px 2px #FFFF00"; } else if (callObj.CQ == true && g_rosterSettings.cqOnly == false) { callingBg = calling + inversionAlpha; calling = bold; } // Assemble all styles colorObject.call = "style='" + callConf + "background-color:" + callBg + ";color:" + call + ";" + callPointer + "'"; colorObject.grid = "style='" + gridConf + "background-color:" + gridBg + ";color:" + grid + ";cursor:pointer'"; colorObject.calling = "style='" + callingConf + "background-color:" + callingBg + ";color:" + calling + "'"; colorObject.dxcc = "style='" + dxccConf + "background-color:" + dxccBg + ";color:" + dxcc + "'"; colorObject.state = "style='" + stateConf + "background-color:" + stateBg + ";color:" + state + "'"; colorObject.cnty = "style='" + cntyConf + "background-color:" + cntyBg + ";color:" + cnty + "'"; colorObject.cont = "style='" + contConf + "background-color:" + contBg + ";color:" + cont + "'"; colorObject.cqz = "style='" + cqzConf + "background-color:" + cqzBg + ";color:" + cqz + "'"; colorObject.ituz = "style='" + ituzConf + "background-color:" + ituzBg + ";color:" + ituz + "'"; colorObject.px = "style='" + wpxConf + "background-color:" + wpxBg + ";color:" + wpx + "'"; // Just in case, don't alert if we worked this callsign alread if (didWork && shouldAlert) shouldAlert = false; callObj.shouldAlert = shouldAlert; callObj.style = colorObject; if (g_rosterSettings.columns.Spot) { callObj.spot = window.opener.getSpotTime( callObj.DEcall + callObj.mode + callObj.band + callObj.grid ); if (callObj.spot == null) { callObj.spot = { when: 0, snr: 0 }; } } else { callObj.spot = { when: 0, snr: 0 }; } modes[callObj.mode] = true; bands[callObj.band] = true; newCallList.push(callObj); } } // Show the roster count in the window title var totalCount = Object.keys(callRoster).length; var visibleCount = newCallList.length; var huntedCount = newCallList.filter(obj => Object.keys(obj.hunting).length > 0).length var countParts = []; if (totalCount != visibleCount) { countParts.push(`${totalCount} heard`); } countParts.push(`${visibleCount} in roster`); if (huntedCount != visibleCount) { countParts.push(`${huntedCount} wanted`); } window.document.title = `Call Roster: ${countParts.join(" • ")}`; // Render the roster if (g_rosterSettings.compact == false) { newCallList.sort(r_sortFunction[g_rosterSettings.lastSortIndex]); if (g_rosterSettings.lastSortReverse == 1) { newCallList.reverse(); } } else { // Age sort for now... make this happen Tag newCallList.sort(r_sortFunction[6]).reverse(); } var showBands = (Object.keys(bands).length > 1) || g_rosterSettings.columns.Band; var showModes = (Object.keys(modes).length > 1) || g_rosterSettings.columns.Mode; var worker = ""; // Render the table headers for the regular roster table if (g_rosterSettings.compact == false) { worker = ""; 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(); } } function realtimeRoster() { var now = timeNowSec(); g_day = now / 86400; if (g_rosterSettings.realtime == false) return; var timeCols = document.getElementsByClassName("timeCol"); for (var x in timeCols) { if ((typeof timeCols[x].id != "undefined") && (typeof callRoster[timeCols[x].id.substr(2)] != "undefined")) { var when = now - callRoster[timeCols[x].id.substr(2)].callObj.age; timeCols[x].innerHTML = when.toDHMS(); } } var lifeCols = document.getElementsByClassName("lifeCol"); for (var x in lifeCols) { if ((typeof lifeCols[x].id != "undefined") && (typeof callRoster[lifeCols[x].id.substr(2)] != "undefined")) { var when = now - callRoster[lifeCols[x].id.substr(2)].callObj.life; lifeCols[x].innerHTML = when.toDHMS(); } } if (g_rosterSettings.columns.Spot) { var spotCols = document.getElementsByClassName("spotCol"); for (var x in spotCols) { if ((typeof spotCols[x].id != "undefined") && (typeof callRoster[spotCols[x].id.substr(2)] != "undefined")) { spotCols[x].innerHTML = getSpotString( callRoster[spotCols[x].id.substr(2)].callObj ); if (g_rosterSettings.onlySpot && spotCols[x].innerHTML == "") { viewRoster(); return; } } } } } function getSpotString(callObj) { var result = ""; if (callObj.spot && callObj.spot.when > 0) { when = timeNowSec() - callObj.spot.when; if (when <= window.opener.g_receptionSettings.viewHistoryTimeSec) { result = parseInt(when).toDHMS(); } } if (result) result += " / " + callObj.spot.snr; return result; } function openChatToCid(cid) { window.opener.showMessaging(true, cid); } function initiateQso(thisHash) { window.opener.initiateQso(thisHash); } function callLookup(thisHash, grid) { window.opener.startLookup( callRoster[thisHash].DEcall, callRoster[thisHash].grid ); } function callingLookup(thisHash, grid) { var thisCall = callRoster[thisHash].DXcall; window.opener.startLookup(thisCall, grid); } function callGenMessage(thisHash, grid) { var thisCall = callRoster[thisHash].DEcall; var instance = callRoster[thisHash].callObj.instance; window.opener.startGenMessages(thisCall, grid, instance); } function callingGenMessage(thisHash, grid) { var thisCall = callRoster[thisHash].DXcall; var instance = callRoster[thisHash].callObj.instance; window.opener.startGenMessages(thisCall, grid, instance); } function centerOn(grid) { window.opener.centerOn(grid); } function instanceChange(what) { window.opener.g_instances[what.id].crEnable = what.checked; window.opener.goProcessRoster(); } function updateInstances() { if (window.opener.g_instancesIndex.length > 1) { var instances = window.opener.g_instances; var worker = ""; var keys = Object.keys(instances).sort(); for (var key in keys) { var inst = keys[key]; var sp = inst.split(" - "); var shortInst = sp[sp.length - 1].substring(0, 18); var color = "blue"; if (instances[inst].open == false) { color = "purple"; } worker += `
` + ` ${shortInst}
` } instancesDiv.innerHTML = worker; instancesWrapper.style.display = ""; } else { instancesDiv.innerHTML = ""; instancesWrapper.style.display = "none"; } } function processStatus(newMessage) { if (newMessage.Transmitting == 0) { // Not Transmitting if (newMessage.Decoding == 1) { // Decoding txrxdec.style.backgroundColor = "Blue"; txrxdec.style.borderColor = "Cyan"; txrxdec.innerHTML = "DECODE"; } else { txrxdec.style.backgroundColor = "Green"; txrxdec.style.borderColor = "GreenYellow"; txrxdec.innerHTML = "RECEIVE"; } } else { txrxdec.style.backgroundColor = "Red"; txrxdec.style.borderColor = "Orange"; txrxdec.innerHTML = "TRANSMIT"; } } function toTitleCase(str) { return str.replace(/\w\S*/g, function (txt) { return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); }); } function newOption(value, text) { if (typeof text == "undefined") text = value; var option = document.createElement("option"); option.value = value; option.text = text; return option; } function createSelectOptions( selectElementString, selectNameDefault, forObject, altName = null, defaultValue = null, checkSponsor = null ) { var selector = document.getElementById(selectElementString); selector.innerHTML = ""; var option = document.createElement("option"); option.value = defaultValue; option.text = selectNameDefault; option.selected = true; option.disabled = true; option.style.display = "none"; selector.appendChild(option); var obj = null; if (forObject) { obj = Object.keys(forObject).sort(); } for (var k in obj) { var opt = obj[k]; var option = document.createElement("option"); option.value = opt; option.text = altName ? forObject[opt][altName] : opt; if (checkSponsor && opt + "-" + checkSponsor in g_awardTracker) { option.disabled = true; } selector.appendChild(option); } } function awardSponsorChanged() { awardName.style.display = ""; createSelectOptions( "awardName", "Select Award", g_awards[awardSponsor.value].awards, "name", null, awardSponsor.value ); } function awardNameChanged() { var awardToAdd = newAwardTrackerObject( awardSponsor.value, awardName.value, true ); var hash = awardToAdd.name + "-" + awardToAdd.sponsor; if (!(hash in g_awardTracker)) { g_awardTracker[hash] = awardToAdd; storeAwardTracker(); processAward(hash); updateAwardList(hash); window.opener.goProcessRoster(); } createSelectOptions( "awardName", "Select Award", g_awards[awardToAdd.sponsor].awards, "name", null, awardToAdd.sponsor ); } function updateAwardList(target = null) { var worker = ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += ""; worker += "
"; worker += "Name"; worker += ""; worker += "Award"; worker += ""; worker += "Track"; worker += ""; worker += ""; worker += "
"; AwardWantedList.innerHTML = worker; var keys = Object.keys(g_awardTracker).sort(); for (var key in keys) { var award = g_awardTracker[keys[key]]; var rule = g_awards[award.sponsor].awards[award.name].rule; var row = awardTable.insertRow(); row.id = keys[key]; var baseAward = false; var baseCount = 0; var endorseCount = 0; var endorseTotal = 0; var allEndorse = false; var tooltip = g_awards[award.sponsor].awards[award.name].tooltip + " (" + g_awards[award.sponsor].sponsor + ")\n"; tooltip += toTitleCase(award.test.qsl_req) + " QSO\n"; for (var mode in award.comp.counts) { tooltip += mode + "\n"; for (var count in award.comp.counts[mode]) { endorseTotal++; if (award.comp.counts[mode][count].per == 100) { baseAward = true; endorseCount++; } if (award.comp.counts[mode][count].num > baseCount) { baseCount = award.comp.counts[mode][count].num; } tooltip += "\t" + award.comp.counts[mode][count].num + "/" + count + " (" + award.comp.counts[mode][count].per + "%)\n"; var wrk = ""; if (Object.keys(award.comp.endorse).length > 0) { for (var band in award.comp.endorse[mode]) { endorseTotal++; if (award.comp.endorse[mode][band][count] == true) { endorseCount++; wrk += band + " "; } } } if (wrk.length > 0) { tooltip += "\t\t" + wrk + "\n"; } } } if (baseCount > 0 && endorseCount == endorseTotal) allEndorse = true; var cell = createCellHtml( row, "

" + award.name + " - " + award.sponsor ); cell.style.textAlign = "left"; cell.style.color = "lightblue"; createCellHtml( row, "

" + (allEndorse ? "" : baseAward ? "" : baseCount > 0 ? "" : ""), tooltip ); createCell( row, "enable", award.enable, award.enable, "Toggle Tracking", true ); createCellHtml( row, "

" ); } } function deleteAwardTracker(sender) { var id = sender.parentNode.parentNode.id; delete g_awardTracker[id]; storeAwardTracker(); resetAwardAdd(); updateAwardList(); window.opener.goProcessRoster(); } function awardCheckboxChanged(sender) { var awardId = sender.target.parentNode.parentNode.id; g_awardTracker[sender.target.parentNode.parentNode.id][sender.target.name] = sender.target.checked; storeAwardTracker(); window.opener.goProcessRoster(); } function awardValueChanged(sender) { var awardId = sender.target.parentNode.parentNode.id; g_awardTracker[sender.target.parentNode.parentNode.id][sender.target.name] = sender.target.value; storeAwardTracker(); window.opener.goProcessRoster(); } function createCell( row, target, value, data = null, title = null, checkbox = false ) { var cell = row.insertCell(); if (data == null) cell.innerHTML = value; if (title) cell.title = title; if (checkbox) { var x = document.createElement("INPUT"); x.setAttribute("type", "checkbox"); x.checked = value; x.name = target; x.addEventListener("change", awardCheckboxChanged); cell.appendChild(x); } else if (data) { cell.appendChild(createAwardSelector(cell, target, value, data)); } return cell; } function createCellHtml(row, html, title = null) { var cell = row.insertCell(); cell.innerHTML = html; if (title) cell.title = title; return cell; } function createAwardSelector(cell, target, value, forObject) { var selector = document.createElement("select"); selector.name = target; selector.value = value; selector.disabled = forObject.length == 1; selector.style.margin = "0px"; selector.style.padding = "1px"; if (selector.disabled) selector.style.cursor = "auto"; selector.addEventListener("change", awardValueChanged); for (var opt in forObject) { var option = document.createElement("option"); option.value = forObject[opt]; if (option.value == "Phone" || option.value == "CW") option.disabled = true; option.text = forObject[opt]; selector.appendChild(option); } return selector; } function resetAwardAdd() { awardName.style.display = "none"; createSelectOptions("awardName", "Select Award", null); createSelectOptions("awardSponsor", "Select Sponsor", g_awards, "sponsor"); } function openAwardPopup() { awardHunterDiv.style.display = ""; resetAwardAdd(); } function closeAwardPopup() { awardHunterDiv.style.display = "none"; resetAwardAdd(); } function toggleMoreControls() { g_rosterSettings.controlsExtended = !g_rosterSettings.controlsExtended; localStorage.rosterSettings = JSON.stringify(g_rosterSettings); setVisual(); } function setVisual() { huntNeed.style.display = "none"; stateSelect.style.display = "none"; DXCCsSelect.style.display = "none"; if (g_rosterSettings.controls) { if (g_rosterSettings.controlsExtended) { RosterControls.className = "extended"; } else { RosterControls.className = "normal"; } } else { RosterControls.className = "hidden"; } // Award Hunter if (referenceNeed.value == LOGBOOK_AWARD_TRACKER) { /* for ( key in g_rosterSettings.wanted ) { document.getElementById(key).checked = true; var t = key.replace("hunt",""); if ( t in g_rosterSettings.columns ) g_rosterSettings.columns[t] = true; } */ HuntModeControls.style.display = "none"; CallsignsControls.style.display = "none"; AwardTrackerControls.style.display = ""; huntingMatrixDiv.style.display = ""; updateAwardList(); } else { for (var key in g_rosterSettings.wanted) { if (document.getElementById(key)) { document.getElementById(key).checked = g_rosterSettings.wanted[key]; } } AwardTrackerControls.style.display = "none"; HuntModeControls.style.display = ""; huntMode.style.display = ""; CallsignsControls.style.display = ""; closeAwardPopup(); if (callsignNeed.value == "all" || callsignNeed.value == "hits") { huntingMatrixDiv.style.display = ""; huntNeed.style.display = ""; huntMode.style.display = "none"; } else { huntingMatrixDiv.style.display = "none"; huntMode.style.display = ""; if ( huntMode.value != "callsign" && huntMode.value != "usstate" && huntMode.value != "dxccs" ) { huntNeed.style.display = ""; } if (huntMode.value == "usstate") { stateSelect.style.display = ""; } if (huntMode.value == "usstates") { huntNeed.style.display = ""; } if (huntMode.value == "dxccs") { DXCCsSelect.style.display = ""; } } } if (wantMaxDT.checked == true) { maxDT.style.display = ""; maxDTView.style.display = ""; } else { maxDT.style.display = "none"; maxDTView.style.display = "none"; } if (wantMinDB.checked == true) { minDb.style.display = ""; minDbView.style.display = ""; } else { minDb.style.display = "none"; minDbView.style.display = "none"; } if (wantMinFreq.checked == true) { minFreq.style.display = ""; minFreqView.style.display = ""; } else { minFreq.style.display = "none"; minFreqView.style.display = "none"; } if (wantMaxFreq.checked == true) { maxFreq.style.display = ""; maxFreqView.style.display = ""; } else { maxFreq.style.display = "none"; maxFreqView.style.display = "none"; } if (useRegex.checked == true) { callsignRegex.style.display = ""; } else { callsignRegex.style.display = "none"; } if (window.opener.g_callsignLookups.lotwUseEnable == true) { usesLoTWDiv.style.display = ""; if (g_rosterSettings.usesLoTW == true) { maxLoTW.style.display = ""; maxLoTWView.style.display = ""; } else { maxLoTW.style.display = "none"; maxLoTWView.style.display = "none"; } } else { usesLoTWDiv.style.display = "none"; maxLoTW.style.display = "none"; maxLoTWView.style.display = "none"; } if (window.opener.g_callsignLookups.eqslUseEnable == true) { useseQSLDiv.style.display = ""; } else useseQSLDiv.style.display = "none"; if (window.opener.g_callsignLookups.oqrsUseEnable == true) { usesOQRSDiv.style.display = ""; } else usesOQRSDiv.style.display = "none"; if (g_rosterSettings.columns.Spot == true) { onlySpotDiv.style.display = ""; } else onlySpotDiv.style.display = "none"; if (g_rosterSettings.callsign == "all" || g_rosterSettings.callsign == "hits") { allOnlyNewDiv.style.display = ""; } else allOnlyNewDiv.style.display = "none"; resize(); } function wantedChanged(element) { g_rosterSettings.wanted[element.id] = element.checked; if (element.checked == true) { var t = element.id.replace("hunt", ""); if (t in g_rosterSettings.columns) { g_rosterSettings.columns[t] = true; for (var i = 0; i < g_menu.items.length; ++i) { if ( typeof g_menu.items[i].checked != "undefined" && g_menu.items[i].label == t ) { g_menu.items[i].checked = true; } } } } writeRosterSettings(); g_scriptReport = Object(); for (var callHash in window.opener.g_callRoster) { window.opener.g_callRoster[callHash].callObj.alerted = false; } window.opener.goProcessRoster(); } function valuesChanged() { setVisual(); g_rosterSettings.callsign = callsignNeed.value; g_rosterSettings.hunting = huntMode.value; g_rosterSettings.huntNeed = huntNeed.value; g_rosterSettings.requireGrid = wantGrid.checked; g_rosterSettings.wantMaxDT = wantMaxDT.checked; g_rosterSettings.wantMinDB = wantMinDB.checked; g_rosterSettings.wantMinFreq = wantMinFreq.checked; g_rosterSettings.wantMaxFreq = wantMaxFreq.checked; maxDTView.innerHTML = g_rosterSettings.maxDT = maxDT.value; minDbView.innerHTML = g_rosterSettings.minDb = minDb.value; minFreqView.innerHTML = g_rosterSettings.minFreq = minFreq.value; maxFreqView.innerHTML = g_rosterSettings.maxFreq = maxFreq.value; g_rosterSettings.maxLoTW = maxLoTW.value; maxLoTWView.innerHTML = g_rosterSettings.maxLoTW < 27 ? Number(g_rosterSettings.maxLoTW).toYM() : ""; g_rosterSettings.maxLoTW = maxLoTW.value; g_rosterSettings.cqOnly = cqOnly.checked; g_rosterSettings.noMyDxcc = noMyDxcc.checked; g_rosterSettings.onlyMyDxcc = onlyMyDxcc.checked; if ( noMsg.checked && onlyMsg.checked && noMsgValue.value == onlyMsgValue.value ) { if (g_rosterSettings.noMsg) noMsg.checked = false; else onlyMsg.checked = false; } g_rosterSettings.noMsg = noMsg.checked; g_rosterSettings.onlyMsg = onlyMsg.checked; g_rosterSettings.noMsgValue = noMsgValue.value; g_rosterSettings.onlyMsgValue = onlyMsgValue.value; g_rosterSettings.usesLoTW = usesLoTW.checked; g_rosterSettings.useseQSL = useseQSL.checked; g_rosterSettings.usesOQRS = usesOQRS.checked; g_rosterSettings.onlySpot = onlySpot.checked; g_rosterSettings.reference = referenceNeed.value; g_rosterSettings.allOnlyNew = allOnlyNew.checked; g_rosterSettings.useRegex = useRegex.checked; g_rosterSettings.callsignRegex = callsignRegex.value; writeRosterSettings(); g_scriptReport = Object(); for (var callHash in window.opener.g_callRoster) { window.opener.g_callRoster[callHash].callObj.alerted = false; } window.opener.goProcessRoster(); } function getBuffer(file_url, callback, flag, mode, port, cookie) { var url = require("url"); var http = require(mode); var fileBuffer = null; var options = null; if (cookie != null) { options = { host: url.parse(file_url).host, // eslint-disable-line node/no-deprecated-api port: port, path: url.parse(file_url).path, // eslint-disable-line node/no-deprecated-api headers: { Cookie: cookie } }; } else { options = { host: url.parse(file_url).host, // eslint-disable-line node/no-deprecated-api port: port, path: url.parse(file_url).path // eslint-disable-line node/no-deprecated-api }; } http.get(options, function (res) { var fsize = res.headers["content-length"]; var cookies = null; if (typeof res.headers["set-cookie"] != "undefined") { cookies = res.headers["set-cookie"]; } res .on("data", function (data) { if (fileBuffer == null) fileBuffer = data; else fileBuffer += data; }) .on("end", function () { if (typeof callback === "function") { // Call it, since we have confirmed it is callable callback(fileBuffer, flag, cookies); } }) .on("error", function () {}); }); } function callsignResult(buffer, flag) { var rawData = JSON.parse(buffer); r_currentUSState = flag; g_currentUSCallsigns = Object(); for (var key in rawData.c) g_currentUSCallsigns[rawData.c[key]] = true; window.opener.goProcessRoster(); } function stateChangedValue(what) { if (r_currentUSState != stateSelect.value && stateSelect.value != "") { r_currentUSState = stateSelect.value; if (window.opener.g_mapSettings.offlineMode == false) { var callState = r_currentUSState.replace("CN-", ""); getBuffer( "http://app.gridtracker.org/callsigns/" + callState + ".callsigns.json", callsignResult, r_currentUSState, "http", 80 ); } else { window.opener.goProcessRoster(); r_currentUSState = ""; g_currentUSCallsigns = null; stateSelect.value = ""; return; } } if (stateSelect.value == "") { r_currentUSState = ""; g_currentUSCallsigns = null; window.opener.goProcessRoster(); } } function DXCCsChangedValue(what) { r_currentDXCCs = DXCCsSelect.value; window.opener.goProcessRoster(); } function initDXCCSelector() { var items = Object.keys(window.opener.g_dxccToAltName).sort(function (a, b) { return window.opener.g_dxccToAltName[a].localeCompare( window.opener.g_dxccToAltName[b] ); }); var newSelect = document.getElementById("DXCCsSelect"); for (var i in items) { var key = items[i]; if ( window.opener.g_worldGeoData[window.opener.g_dxccToGeoData[key]].geo != "deleted" ) { var option = document.createElement("option"); option.value = key; option.text = window.opener.g_dxccToAltName[key] + " (" + window.opener.g_worldGeoData[window.opener.g_dxccToGeoData[key]].pp + ")"; newSelect.appendChild(option); } } newSelect.oninput = DXCCsChangedValue; } function manifestResult(buffer, flag) { r_callsignManifest = JSON.parse(buffer); var newSelect = document.getElementById("stateSelect"); for (var key in r_callsignManifest.cnt) { var option = document.createElement("option"); if (window.opener.g_enums[key]) { option.value = key; option.text = window.opener.g_enums[key]; } else { option.value = "CN-" + key; option.text = window.opener.g_enums["CN-" + key]; } newSelect.appendChild(option); } newSelect.oninput = stateChangedValue; } function receiveMessage(event) {} var g_tracker = {}; function updateWorked() { g_worked = window.opener.g_tracker.worked; g_confirmed = window.opener.g_tracker.confirmed; g_modes = window.opener.g_modes; g_modes_phone = window.opener.g_modes_phone; g_tracker = window.opener.g_tracker; processAllAwardTrackers(); } function deleteCallsignIgnore(key) { delete g_blockedCalls[key]; storeBlocks(); openIgnoreEdit(); window.opener.goProcessRoster(); } function deleteDxccIgnore(key) { delete g_blockedDxcc[key]; storeBlocks(); openIgnoreEdit(); window.opener.goProcessRoster(); } function deleteCQIgnore(key) { delete g_blockedCQ[key]; storeBlocks(); openIgnoreEdit(); window.opener.goProcessRoster(); } function clearAllCallsignIgnores() { g_blockedCalls = Object(); storeBlocks(); openIgnoreEdit(); window.opener.goProcessRoster(); } function clearAllDxccIgnores() { g_blockedDxcc = Object(); storeBlocks(); openIgnoreEdit(); window.opener.goProcessRoster(); } function clearAllCQIgnores() { g_blockedCQ = Object(); storeBlocks(); openIgnoreEdit(); window.opener.goProcessRoster(); } function closeEditIgnores() { MainCallRoster.style.display = "block"; editView.style.display = "none"; } function openIgnoreEdit() { MainCallRoster.style.display = "none"; editView.style.display = "inline-block"; var worker = ""; var clearString = "none"; if (Object.keys(g_blockedCalls).length > 0) { clearString = "Clear All"; } worker += "

" + clearString + ""; Object.keys(g_blockedCalls) .sort() .forEach(function (key, i) { worker += ""; }); worker += "
Callsigns
" + key + "
"; clearString = "none"; if (Object.keys(g_blockedCQ).length > 0) { clearString = "Clear All"; } worker += "
" + clearString + ""; Object.keys(g_blockedCQ) .sort() .forEach(function (key, i) { worker += ""; }); worker += "
CQ
" + key + "
"; clearString = "none"; if (Object.keys(g_blockedDxcc).length > 0) { clearString = "Clear All"; } worker += "
" + clearString + ""; Object.keys(g_blockedDxcc) .sort() .forEach(function (key, i) { worker += ""; }); worker += "
DXCCs
" + window.opener.g_dxccToAltName[key] + " (" + window.opener.g_worldGeoData[window.opener.g_dxccToGeoData[key]].pp + ")
"; editTables.innerHTML = worker; } function onMyKeyDown(event) { if (!g_regFocus) { window.opener.onMyKeyDown(event); } } function checkForEnter(ele) { if (event.key === "Enter") { ele.blur(); } } function resize() { if (editView.style.display == "inline-block") openIgnoreEdit(); window.opener.goProcessRoster(); } function init() { g_callsignDatabaseDXCC = window.opener.g_callsignDatabaseDXCC; g_callsignDatabaseUS = window.opener.g_callsignDatabaseUS; g_callsignDatabaseUSplus = window.opener.g_callsignDatabaseUSplus; loadAwardJson(); updateWorked(); // addAllAwards(); window.addEventListener("message", receiveMessage, false); lockNewWindows(); if (window.opener.g_mapSettings.offlineMode == false) { getBuffer( "http://app.gridtracker.org/callsigns/manifest.json", manifestResult, null, "http", 80 ); } loadSettings(); window.opener.setRosterSpot(g_rosterSettings.columns.Spot); for (var key in g_rosterSettings.wanted) { if (document.getElementById(key)) { document.getElementById(key).checked = g_rosterSettings.wanted[key]; } } g_menu = new nw.Menu(); g_compactMenu = new nw.Menu(); var item = new nw.MenuItem({ type: "normal", label: g_rosterSettings.controls ? "Hide Controls" : "Show Controls", click: function () { if (this.label == "Hide Controls") { this.label = "Show Controls"; g_rosterSettings.controls = false; } else { this.label = "Hide Controls"; g_rosterSettings.controls = true; } g_compactMenu.items[0].label = g_rosterSettings.controls ? "Hide Controls" : "Show Controls"; localStorage.rosterSettings = JSON.stringify(g_rosterSettings); setVisual(); } }); g_menu.append(item); item = new nw.MenuItem({ type: "normal", label: g_rosterSettings.controls ? "Hide Controls" : "Show Controls", click: function () { if (this.label == "Hide Controls") { this.label = "Show Controls"; g_rosterSettings.controls = false; } else { this.label = "Hide Controls"; g_rosterSettings.controls = true; } g_menu.items[0].label = g_rosterSettings.controls ? "Hide Controls" : "Show Controls"; localStorage.rosterSettings = JSON.stringify(g_rosterSettings); setVisual(); } }); g_compactMenu.append(item); item = new nw.MenuItem({ type: "normal", label: "Compact Mode", click: function () { g_rosterSettings.compact = true; localStorage.rosterSettings = JSON.stringify(g_rosterSettings); resize(); } }); g_menu.append(item); item = new nw.MenuItem({ type: "normal", label: "Roster Mode", click: function () { g_rosterSettings.compact = false; localStorage.rosterSettings = JSON.stringify(g_rosterSettings); resize(); } }); g_compactMenu.append(item); g_callMenu = new nw.Menu(); item = new nw.MenuItem({ type: "normal", label: "Lookup", click: function () { callLookup(g_targetHash, ""); } }); g_callMenu.append(item); item = new nw.MenuItem({ type: "normal", label: "Gen Msgs", click: function () { callGenMessage(g_targetHash, ""); } }); g_callMenu.append(item); item = new nw.MenuItem({ type: "separator" }); g_callMenu.append(item); item = new nw.MenuItem({ type: "normal", label: "Ignore Call", click: function () { var thisCall = callRoster[g_targetHash].DEcall; g_blockedCalls[thisCall] = true; storeBlocks(); window.opener.goProcessRoster(); } }); g_callMenu.append(item); g_callingMenu = new nw.Menu(); item = new nw.MenuItem({ type: "normal", label: "Lookup", click: function () { callingLookup(g_targetHash, ""); } }); g_callingMenu.append(item); item = new nw.MenuItem({ type: "normal", label: "Gen Msgs", click: function () { callingGenMessage(g_targetHash, ""); } }); g_callingMenu.append(item); item = new nw.MenuItem({ type: "separator" }); g_menu.append(item); item = new nw.MenuItem({ type: "checkbox", label: "Realtime", checked: g_rosterSettings.realtime, click: function () { g_rosterSettings.realtime = this.checked; writeRosterSettings(); window.opener.goProcessRoster(); } }); g_menu.append(item); item = new nw.MenuItem({ type: "separator" }); g_menu.append(item); for (var key in g_rosterSettings.columns) { var itemx = new nw.MenuItem({ type: "checkbox", label: key, checked: g_rosterSettings.columns[key], click: function () { g_rosterSettings.columns[this.label] = this.checked; if (this.label == "Spot") { window.opener.setRosterSpot(g_rosterSettings.columns.Spot); } writeRosterSettings(); window.opener.goProcessRoster(); resize(); } }); g_menu.append(itemx); } item = new nw.MenuItem({ type: "separator" }); g_menu.append(item); g_clearIgnores = new nw.MenuItem({ type: "normal", label: "Clear Call Ignore", enabled: false, click: function () { g_blockedCalls = Object(); storeBlocks(); window.opener.goProcessRoster(); } }); g_menu.append(g_clearIgnores); g_clearIgnoresCall = new nw.MenuItem({ type: "normal", label: "Clear Ignore", enabled: false, click: function () { g_blockedCalls = Object(); storeBlocks(); window.opener.goProcessRoster(); } }); g_callMenu.append(g_clearIgnoresCall); g_CQMenu = new nw.Menu(); item = new nw.MenuItem({ type: "normal", label: "Ignore CQ from DXCC", click: function () { g_blockedCQ[ callRoster[g_targetCQ].DXcall + " from " + window.opener.g_dxccToAltName[callRoster[g_targetCQ].callObj.dxcc] ] = true; storeBlocks(); window.opener.goProcessRoster(); } }); g_CQMenu.append(item); item = new nw.MenuItem({ type: "normal", label: "Ignore CQ from All", click: function () { g_blockedCQ[callRoster[g_targetCQ].DXcall + " from All"] = true; storeBlocks(); window.opener.goProcessRoster(); } }); g_CQMenu.append(item); g_clearCQIgnoreMainMenu = new nw.MenuItem({ type: "normal", label: "Clear CQ Ignore", enabled: false, click: function () { g_blockedCQ = Object(); storeBlocks(); window.opener.goProcessRoster(); } }); g_menu.append(g_clearCQIgnoreMainMenu); g_clearCQIgnore = new nw.MenuItem({ type: "normal", label: "Clear Ignore", enabled: false, click: function () { g_blockedCQ = Object(); storeBlocks(); window.opener.goProcessRoster(); } }); g_CQMenu.append(g_clearCQIgnore); item = new nw.MenuItem({ type: "normal", label: "Edit Ignores", enabled: true, click: function () { openIgnoreEdit(); } }); g_CQMenu.append(item); g_dxccMenu = new nw.Menu(); item = new nw.MenuItem({ type: "normal", label: "Ignore DXCC", click: function () { g_blockedDxcc[g_targetDxcc] = true; storeBlocks(); window.opener.goProcessRoster(); } }); g_dxccMenu.append(item); g_clearDxccIgnoreMainMenu = new nw.MenuItem({ type: "normal", label: "Clear DXCC Ignore", enabled: false, click: function () { g_blockedDxcc = Object(); storeBlocks(); window.opener.goProcessRoster(); } }); g_menu.append(g_clearDxccIgnoreMainMenu); g_clearDxccIgnore = new nw.MenuItem({ type: "normal", label: "Clear Ignore", enabled: false, click: function () { g_blockedDxcc = Object(); storeBlocks(); window.opener.goProcessRoster(); } }); g_dxccMenu.append(g_clearDxccIgnore); item = new nw.MenuItem({ type: "normal", label: "Edit Ignores", enabled: true, click: function () { openIgnoreEdit(); } }); g_menu.append(item); item = new nw.MenuItem({ type: "normal", label: "Edit Ignores", enabled: true, click: function () { openIgnoreEdit(); } }); g_callMenu.append(item); item = new nw.MenuItem({ type: "normal", label: "Edit Ignores", enabled: true, click: function () { openIgnoreEdit(); } }); g_dxccMenu.append(item); callsignNeed.value = g_rosterSettings.callsign; huntMode.value = g_rosterSettings.hunting; huntNeed.value = g_rosterSettings.huntNeed; wantGrid.checked = g_rosterSettings.requireGrid; wantMaxDT.checked = g_rosterSettings.wantMaxDT; wantMinDB.checked = g_rosterSettings.wantMinDB; wantMinFreq.checked = g_rosterSettings.wantMinFreq; wantMaxFreq.checked = g_rosterSettings.wantMaxFreq; maxDTView.innerHTML = maxDT.value = g_rosterSettings.maxDT; minDbView.innerHTML = minDb.value = g_rosterSettings.minDb; minFreqView.innerHTML = minFreq.value = g_rosterSettings.minFreq; maxFreqView.innerHTML = maxFreq.value = g_rosterSettings.maxFreq; maxLoTW.value = g_rosterSettings.maxLoTW; maxLoTWView.innerHTML = maxLoTW.value < 27 ? Number(maxLoTW.value).toYM() : ""; cqOnly.checked = g_rosterSettings.cqOnly; noMyDxcc.checked = g_rosterSettings.noMyDxcc; onlyMyDxcc.checked = g_rosterSettings.onlyMyDxcc; noMsg.checked = g_rosterSettings.noMsg; onlyMsg.checked = g_rosterSettings.onlyMsg; noMsgValue.value = g_rosterSettings.noMsgValue; onlyMsgValue.value = g_rosterSettings.onlyMsgValue; usesLoTW.checked = g_rosterSettings.usesLoTW; useseQSL.checked = g_rosterSettings.useseQSL; onlySpot.checked = g_rosterSettings.onlySpot; usesOQRS.checked = g_rosterSettings.usesOQRS; referenceNeed.value = g_rosterSettings.reference; allOnlyNew.checked = g_rosterSettings.allOnlyNew; useRegex.checked = g_rosterSettings.useRegex; callsignRegex.value = g_rosterSettings.callsignRegex; setVisual(); document.addEventListener("keydown", onMyKeyDown, false); initDXCCSelector(); g_timerInterval = setInterval(realtimeRoster, 1000); updateInstances(); } function handleContextMenu(ev) { if (editView.style.display == "inline-block") return false; var mouseX = Math.round(ev.x); var mouseY = Math.round(ev.y); var len = Object.keys(g_blockedCalls).length; if (len > 0) { g_clearIgnores.enabled = true; g_clearIgnores.label = "Clear Call Ignore" + (len > 1 ? "s (" + len + ")" : ""); g_clearIgnoresCall.enabled = true; g_clearIgnoresCall.label = "Clear Ignore" + (len > 1 ? "s (" + len + ")" : ""); } else { g_clearIgnores.label = "Clear Call Ignore"; g_clearIgnores.enabled = false; g_clearIgnoresCall.label = "Clear Ignore"; g_clearIgnoresCall.enabled = false; } len = Object.keys(g_blockedDxcc).length; if (len > 0) { g_clearDxccIgnoreMainMenu.enabled = true; g_clearDxccIgnoreMainMenu.label = "Clear DXCC Ignore" + (len > 1 ? "s (" + len + ")" : ""); g_clearDxccIgnore.enabled = true; g_clearDxccIgnore.label = "Clear Ignore" + (len > 1 ? "s (" + len + ")" : ""); } else { g_clearDxccIgnoreMainMenu.label = "Clear DXCC Ignore"; g_clearDxccIgnoreMainMenu.enabled = false; g_clearDxccIgnore.label = "Clear Ignore"; g_clearDxccIgnore.enabled = false; } len = Object.keys(g_blockedCQ).length; if (len > 0) { g_clearCQIgnoreMainMenu.enabled = true; g_clearCQIgnoreMainMenu.label = "Clear CQ Ignore" + (len > 1 ? "s (" + len + ")" : ""); g_clearCQIgnore.enabled = true; g_clearCQIgnore.label = "Clear Ignore" + (len > 1 ? "s (" + len + ")" : ""); } else { g_clearCQIgnoreMainMenu.label = "Clear CQ Ignore"; g_clearCQIgnoreMainMenu.enabled = false; g_clearCQIgnore.label = "Clear Ignore"; g_clearCQIgnore.enabled = false; } if (typeof ev.target != "undefined") { if (g_developerMode) { if ((ev.target.id === "ShowMoreControlsLink") || (ev.target.id === "ShowFewerControlsLink") || (ev.target.id === "txrxdec")) { // Allow event to bubble up so that NWJS will show the developer menu return true; } } var name = ev.target.getAttribute("name"); if (name == "Callsign") { g_targetHash = ev.target.parentNode.id; g_callMenu.popup(mouseX, mouseY); } else if (name == "Calling") { g_targetHash = ev.target.parentNode.id; g_callingMenu.popup(mouseX, mouseY); } else if (name == "CQ") { if (callRoster[ev.target.parentNode.id].DXcall != "CQ") { g_targetCQ = ev.target.parentNode.id; g_CQMenu.popup(mouseX, mouseY); } } else if (name && name.startsWith("DXCC")) { var dxcca = name.split("("); var dxcc = parseInt(dxcca[1]); g_targetDxcc = dxcc; g_dxccMenu.popup(mouseX, mouseY); } else { if (g_rosterSettings.compact == false) { g_menu.popup(mouseX, mouseY); } else { g_compactMenu.popup(mouseX, mouseY); } } } else { if (g_rosterSettings.compact == false) { g_menu.popup(mouseX, mouseY); } else { g_compactMenu.popup(mouseX, mouseY); } } ev.preventDefault(); return false; } function getTypeFromMode(mode) { if (mode in g_modes) { if (g_modes[mode] == true) return "Digital"; else if (g_modes_phone[mode] == true) return "Phone"; } return ""; } function testAward(awardName, obj, baseHash) { if ( g_awardTracker[awardName].test.dxcc && g_awardTracker[awardName].rule.dxcc.indexOf(obj.dxcc) == -1 ) { return false; } if ( g_awardTracker[awardName].test.mode && g_awardTracker[awardName].rule.mode.indexOf(obj.mode) == -1 ) { return false; } if ( g_awardTracker[awardName].test.band && g_awardTracker[awardName].rule.band.indexOf(obj.band) == -1 ) { return false; } if ( g_awardTracker[awardName].test.DEcall && g_awardTracker[awardName].rule.call.indexOf(obj.DEcall) == -1 ) { return false; } if ( g_awardTracker[awardName].test.cont && g_awardTracker[awardName].rule.cont.indexOf(obj.cont) == -1 ) { return false; } if ( g_awardTracker[awardName].test.prop && g_awardTracker[awardName].rule.propMode != obj.propMode ) { return false; } if ( g_awardTracker[awardName].test.sat && g_awardTracker[awardName].rule.satName.indexOf(obj.satName) == -1 ) { return false; } return g_awardTypes[g_awardTracker[awardName].rule.type].test( g_awardTracker[awardName], obj, baseHash ); } function processAward(awardName) { var award = g_awards[g_awardTracker[awardName].sponsor].awards[ g_awardTracker[awardName].name ]; g_awardTracker[awardName].rule = award.rule; var test = (g_awardTracker[awardName].test = {}); var mode = award.rule.mode.slice(); var Index = mode.indexOf("Mixed"); if (Index > -1) mode.splice(Index, 1); Index = mode.indexOf("Digital"); if (Index > -1) mode.splice(Index, 1); Index = mode.indexOf("Phone"); if (Index > -1) mode.splice(Index, 1); test.mode = mode.length > 0; test.confirmed = "qsl_req" in g_awards[g_awardTracker[awardName].sponsor].awards[ g_awardTracker[awardName].name ].rule ? g_awards[g_awardTracker[awardName].sponsor].awards[ g_awardTracker[awardName].name ].rule.qsl_req == "confirmed" : g_awards[g_awardTracker[awardName].sponsor].qsl_req == "confirmed"; test.look = "confirmed"; test.qsl_req = "qsl_req" in g_awards[g_awardTracker[awardName].sponsor].awards[ g_awardTracker[awardName].name ].rule ? g_awards[g_awardTracker[awardName].sponsor].awards[ g_awardTracker[awardName].name ].rule.qsl_req : g_awards[g_awardTracker[awardName].sponsor].qsl_req; test.DEcall = "call" in award.rule; test.band = "band" in award.rule && award.rule.band.indexOf("Mixed") == -1; test.dxcc = "dxcc" in award.rule; test.cont = "cont" in award.rule; test.prop = "propMode" in award.rule; test.sat = "satName" in award.rule; g_awardTracker[awardName].stat = {}; for (var i in window.opener.g_QSOhash) { var obj = window.opener.g_QSOhash[i]; if (test.confirmed && !obj.confirmed) continue; if (obj.dxcc < 1) continue; if (test.dxcc && award.rule.dxcc.indexOf(obj.dxcc) == -1) continue; if (test.mode && award.rule.mode.indexOf(obj.mode) == -1) continue; if (test.band && award.rule.band.indexOf(obj.band) == -1) continue; if (test.DEcall && award.rule.call.indexOf(obj.DEcall) == -1) continue; if (test.cont && award.rule.cont.indexOf(obj.cont) == -1) continue; if (test.prop && award.rule.propMode != obj.propMode) continue; if (test.sat && award.rule.satName.indexOf(obj.satName) == -1) continue; g_awardTypes[award.rule.type].score(g_awardTracker[awardName], obj); } g_awardTracker[awardName].comp = g_awardTypes[award.rule.type].compile( g_awardTracker[awardName], g_awardTracker[awardName].stat ); g_awardTracker[awardName].stat = {}; } function newAwardCountObject() { var statCountObject = {}; statCountObject.bands = {}; statCountObject.bands.Mixed = {}; statCountObject.bands.Digital = {}; statCountObject.bands.Phone = {}; statCountObject.modes = {}; statCountObject.modes.Mixed = {}; statCountObject.modes.Digital = {}; statCountObject.modes.Phone = {}; statCountObject.unique = null; return statCountObject; } function workAwardObject(obj, band, mode, isDigital, isPhone, unique = null) { obj.bands.Mixed[band] = ~~obj.bands.Mixed[band] + 1; if (!(mode in obj.bands)) obj.bands[mode] = {}; obj.bands[mode][band] = ~~obj.bands[mode][band] + 1; obj.modes.Mixed[mode] = ~~obj.modes.Mixed[mode] + 1; if (isDigital) { obj.bands.Digital[band] = ~~obj.bands.Digital[band] + 1; obj.modes.Digital[mode] = ~~obj.modes.Digital[mode] + 1; } if (isPhone) { obj.bands.Phone[band] = ~~obj.bands.Phone[band] + 1; obj.modes.Phone[mode] = ~~obj.modes.Phone[mode] + 1; } if (unique) { if (obj.unique == null) obj.unique = {}; if (!(unique in obj.unique)) obj.unique[unique] = newAwardCountObject(); workAwardObject(obj.unique[unique], band, mode, isDigital, isPhone); } return true; } function buildAwardTypeHandlers() { g_awardTypes = { IOTA: { name: "Islands On The Air" }, call: { name: "Callsign" }, callarea: { name: "Call Area" }, calls2dxcc: { name: "Stations per DXCC" }, cnty: { name: "County" }, cont: { name: "Continents" }, cont5: { name: "5 Continents" }, cont52band: { name: "5 Continents per Band" }, cqz: { name: "CQ Zone" }, dxcc: { name: "DXCC" }, grids: { name: "Grids" }, numsfx: { name: "Call Area + Suffix" }, px: { name: "Prefix" }, pxa: { name: "Prefixes" }, pxplus: { name: "Special Calls" }, sfx: { name: "Suffix" }, states: { name: "States" }, cont2band: { name: "Continents per Band" }, calls2band: { name: "Stations per Band" }, dxcc2band: { name: "DXCC per Band" }, states2band: { name: "States per Band" } }; g_awardTypes.IOTA.score = scoreAIOTA; g_awardTypes.call.score = scoreAcall; g_awardTypes.callarea.score = scoreAcallarea; g_awardTypes.calls2dxcc.score = scoreAcalls2dxcc; g_awardTypes.cnty.score = scoreAcnty; g_awardTypes.cont.score = scoreAcont; g_awardTypes.cont5.score = scoreAcont5; g_awardTypes.cont52band.score = scoreAcont52band; g_awardTypes.cqz.score = scoreAcqz; g_awardTypes.dxcc.score = scoreAdxcc; g_awardTypes.grids.score = scoreAgrids; g_awardTypes.numsfx.score = scoreAnumsfx; g_awardTypes.px.score = scoreApx; g_awardTypes.pxa.score = scoreApxa; g_awardTypes.pxplus.score = scoreApxplus; g_awardTypes.sfx.score = scoreAsfx; g_awardTypes.states.score = scoreAstates; g_awardTypes.cont2band.score = scoreAcont2band; g_awardTypes.calls2band.score = scoreAcalls2band; g_awardTypes.dxcc2band.score = scoreAdxcc2band; g_awardTypes.states2band.score = scoreAstates2band; g_awardTypes.IOTA.test = testAIOTA; g_awardTypes.call.test = testAcall; g_awardTypes.callarea.test = testAcallarea; g_awardTypes.calls2dxcc.test = testAcalls2dxcc; g_awardTypes.cnty.test = testAcnty; g_awardTypes.cont.test = testAcont; g_awardTypes.cont5.test = testAcont5; g_awardTypes.cont52band.test = testAcont52band; g_awardTypes.cqz.test = testAcqz; g_awardTypes.dxcc.test = testAdxcc; g_awardTypes.grids.test = testAgrids; g_awardTypes.numsfx.test = testAnumsfx; g_awardTypes.px.test = testApx; g_awardTypes.pxa.test = testApxa; g_awardTypes.pxplus.test = testApxplus; g_awardTypes.sfx.test = testAsfx; g_awardTypes.states.test = testAstates; g_awardTypes.cont2band.test = testAcont2band; g_awardTypes.calls2band.test = testAcalls2band; g_awardTypes.dxcc2band.test = testAdxcc2band; g_awardTypes.states2band.test = testAstates2band; g_awardTypes.IOTA.compile = singleCompile; g_awardTypes.call.compile = singleCompile; g_awardTypes.callarea.compile = singleCompile; g_awardTypes.calls2dxcc.compile = doubleCompile; g_awardTypes.cnty.compile = singleCompile; g_awardTypes.cont.compile = singleCompile; g_awardTypes.cont5.compile = singleCompile; g_awardTypes.cont52band.compile = doubleCompile; g_awardTypes.cqz.compile = singleCompile; g_awardTypes.dxcc.compile = singleCompile; g_awardTypes.grids.compile = singleCompile; g_awardTypes.numsfx.compile = singleCompile; g_awardTypes.px.compile = singleCompile; g_awardTypes.pxa.compile = singleCompile; g_awardTypes.pxplus.compile = singleCompile; g_awardTypes.sfx.compile = singleCompile; g_awardTypes.states.compile = singleCompile; g_awardTypes.cont2band.compile = doubleCompile; g_awardTypes.calls2band.compile = doubleCompile; g_awardTypes.dxcc2band.compile = doubleCompile; g_awardTypes.states2band.compile = doubleCompile; } function scoreAstates(award, obj) { if (obj.state) { if (!(obj.state in award.stat)) { award.stat[obj.state] = newAwardCountObject(); } return workAwardObject( award.stat[obj.state], obj.band, obj.mode, obj.digital, obj.phone ); } return false; } function testAstates(award, obj, baseHash) { if (obj.state && obj.state + baseHash in g_tracker[award.test.look].state) { return false; } return true; } function scoreAstates2band(award, obj) { if (obj.state) { if (!(obj.band in award.stat)) award.stat[obj.band] = newAwardCountObject(); return workAwardObject( award.stat[obj.band], obj.band, obj.mode, obj.digital, obj.phone, obj.state ); } return false; } function testAstates2band(award, obj, baseHash) { if (obj.state && obj.state + baseHash in g_tracker[award.test.look].state) { return false; } return true; } function scoreAdxcc(award, obj) { if (!(obj.dxcc in award.stat)) award.stat[obj.dxcc] = newAwardCountObject(); return workAwardObject( award.stat[obj.dxcc], obj.band, obj.mode, obj.digital, obj.phone ); } function testAdxcc(award, obj, baseHash) { if (String(obj.dxcc) + baseHash in g_tracker[award.test.look].dxcc) { return false; } return true; } function scoreAcont(award, obj) { if (obj.cont) { var cont = obj.cont; if (cont == "AN") cont = "OC"; if (!(cont in award.stat)) award.stat[cont] = newAwardCountObject(); return workAwardObject( award.stat[cont], obj.band, obj.mode, obj.digital, obj.phone ); } return false; } function testAcont(award, obj, baseHash) { if (obj.cont) { var cont = obj.cont; if (cont == "AN") cont = "OC"; if (cont + baseHash in g_tracker[award.test.look].cont) { return false; } } return true; } function scoreAcont5(award, obj, baseHash) { if (obj.cont) { var cont = obj.cont; if (cont == "NA" || cont == "SA") cont = "AM"; if (cont == "AN") cont = "OC"; if (!(cont in award.stat)) award.stat[cont] = newAwardCountObject(); return workAwardObject( award.stat[cont], obj.band, obj.mode, obj.digital, obj.phone ); } return false; } function testAcont5(award, obj, baseHash) { if (obj.cont) { var cont = obj.cont; if (cont == "NA" || cont == "SA") cont = "AM"; if (cont == "AN") cont = "OC"; if (cont + baseHash in g_tracker[award.test.look].cont) { return false; } } return true; } function scoreAcont2band(award, obj) { if (!(obj.band in award.stat)) award.stat[obj.band] = newAwardCountObject(); return workAwardObject( award.stat[obj.band], obj.band, obj.mode, obj.digital, obj.phone, obj.cont ); } function testAcont2band(award, obj, baseHash) { if (obj.cont) { var cont = obj.cont; if (cont == "AN") cont = "OC"; if (cont + baseHash in g_tracker[award.test.look].cont) { return false; } } return true; } function scoreAcont52band(award, obj) { if (obj.cont) { var cont = obj.cont; if (cont == "NA" || cont == "SA") cont = "AM"; if (cont == "AN") cont = "OC"; if (!(obj.band in award.stat)) award.stat[obj.band] = newAwardCountObject(); return workAwardObject( award.stat[obj.band], obj.band, obj.mode, obj.digital, obj.phone, cont ); } return false; } function testAcont52band(award, obj, baseHash) { if (obj.cont) { var cont = obj.cont; if (cont == "NA" || cont == "SA") cont = "AM"; if (cont == "AN") cont = "OC"; if (cont + baseHash in g_tracker[award.test.look].cont) { return false; } } return true; } function scoreAgrids(award, obj) { if (obj.grid) { var grid = obj.grid.substr(0, 4); if (!(grid in award.stat)) award.stat[grid] = newAwardCountObject(); return workAwardObject( award.stat[grid], obj.band, obj.mode, obj.digital, obj.phone ); } return false; } function testAgrids(award, obj, baseHash) { if (obj.grid && obj.grid + baseHash in g_tracker[award.test.look].grid) { return false; } return true; } function scoreAcnty(award, obj) { if (obj.cnty) { if (!(obj.cnty in award.stat)) award.stat[obj.cnty] = newAwardCountObject(); return workAwardObject( award.stat[obj.cnty], obj.band, obj.mode, obj.digital, obj.phone ); } return false; } function testAcnty(award, obj, baseHash) { if (obj.cnty && obj.cnty + baseHash in g_tracker[award.test.look].cnty) { return false; } return true; } function scoreAcall(award, obj) { var call = obj.DEcall; if (call.indexOf("/") > -1) { if (call.endsWith("/MM")) return false; call = call.replace("/P", "").replace("/R", "").replace("/QRP"); } if (!(call in award.stat)) award.stat[call] = newAwardCountObject(); return workAwardObject( award.stat[call], obj.band, obj.mode, obj.digital, obj.phone ); } function testAcall(award, obj, baseHash) { if (obj.DEcall.indexOf("/") > -1 && obj.DEcall.endsWith("/MM")) return false; if (obj.DEcall + baseHash in g_tracker[award.test.look].call) { return false; } return true; } function scoreAIOTA(award, obj) { if (obj.IOTA) { var test = g_awards[award.sponsor].awards[award.name]; if ("IOTA" in test.rule && test.rule.IOTA.indexOf(obj.IOTA) == -1) { return false; } if (!(obj.IOTA in award.stat)) award.stat[obj.IOTA] = newAwardCountObject(); return workAwardObject( award.stat[obj.IOTA], obj.band, obj.mode, obj.digital, obj.phone ); } return false; } // NO IOTA YET function testAIOTA(award, obj, baseHash) { /* if ( obj.IOTA ) { var test = g_awards[award.sponsor].awards[award.name]; if ( "IOTA" in test.rule && test.rule.IOTA.indexOf(obj.IOTA) == -1 ) return false; } */ return false; } function scoreAcallarea(award, obj) { if (obj.zone != null) { var test = g_awards[award.sponsor].awards[award.name]; if ("zone" in test.rule && test.rule.zone.indexOf(obj.zone) == -1) { return false; } if (!(obj.zone in award.stat)) award.stat[obj.zone] = newAwardCountObject(); return workAwardObject( award.stat[obj.zone], obj.band, obj.mode, obj.digital, obj.phone ); } return false; } function testAcallarea(award, obj, baseHash) { if (obj.zone != null) { var test = g_awards[award.sponsor].awards[award.name]; if ("zone" in test.rule && test.rule.zone.indexOf(obj.zone) == -1) { return false; } } return true; } function scoreApx(award, obj) { if (obj.px) { var test = g_awards[award.sponsor].awards[award.name]; var px = obj.px; if ("px" in test.rule) { px = px.substr(0, test.rule.px[0].length); if (test.rule.px.indexOf(px) == -1) return false; } if (!(px in award.stat)) award.stat[px] = newAwardCountObject(); return workAwardObject( award.stat[px], obj.band, obj.mode, obj.digital, obj.phone ); } return false; } function testApx(award, obj, baseHash) { if (obj.px) { var test = g_awards[award.sponsor].awards[award.name]; var px = obj.px; if ("px" in test.rule) { px = px.substr(0, test.rule.px[0].length); if (test.rule.px.indexOf(px) == -1) return false; } if (String(obj.px) + baseHash in g_tracker[award.test.look].px) { return false; } } return true; } function scoreApxa(award, obj) { if (obj.px) { var test = g_awards[award.sponsor].awards[award.name]; for (var i in test.rule.pxa) { if (test.rule.pxa[i].indexOf(obj.px) > -1) { if (!(i in award.stat)) award.stat[i] = newAwardCountObject(); return workAwardObject( award.stat[i], obj.band, obj.mode, obj.digital, obj.phone ); } } } return false; } function testApxa(award, obj, baseHash) { if (obj.px) { var test = g_awards[award.sponsor].awards[award.name]; for (var i in test.rule.pxa) { if (test.rule.pxa[i].indexOf(obj.px) > -1) { if (String(obj.px) + baseHash in g_tracker[award.test.look].px) { return false; } else { return true; } } } } return false; } function scoreAsfx(award, obj) { var test = g_awards[award.sponsor].awards[award.name]; var suf = obj.DEcall.replace(obj.px, ""); for (var i in test.rule.sfx) { for (var s in test.rule.sfx[i]) { if (suf.indexOf(test.rule.sfx[i][s]) == 0) { if (!(i in award.stat)) award.stat[i] = newAwardCountObject(); return workAwardObject( award.stat[i], obj.band, obj.mode, obj.digital, obj.phone ); } } } return false; } function testAsfx(award, obj, baseHash) { var test = g_awards[award.sponsor].awards[award.name]; var suf = obj.DEcall.replace(obj.px, ""); for (var i in test.rule.sfx) { for (var s in test.rule.sfx[i]) { if (suf.indexOf(test.rule.sfx[i][s]) == 0) { return false; } } } return true; } function scoreAcalls2dxcc(award, obj) { if (!(obj.dxcc in award.stat)) award.stat[obj.dxcc] = newAwardCountObject(); return workAwardObject( award.stat[obj.dxcc], obj.band, obj.mode, obj.digital, obj.phone, obj.DEcall ); } function testAcalls2dxcc(award, obj, baseHash) { if (obj.DEcall + baseHash in g_tracker[award.test.look].call) { return false; } return true; } function scoreAcalls2band(award, obj) { if (!(obj.band in award.stat)) award.stat[obj.band] = newAwardCountObject(); return workAwardObject( award.stat[obj.band], obj.band, obj.mode, obj.digital, obj.phone, obj.DEcall ); } function testAcalls2band(award, obj, baseHash) { if (obj.DEcall + baseHash in g_tracker[award.test.look].call) { return false; } return true; } function scoreAdxcc2band(award, obj) { if (!(obj.band in award.stat)) award.stat[obj.band] = newAwardCountObject(); return workAwardObject( award.stat[obj.band], obj.band, obj.mode, obj.digital, obj.phone, obj.dxcc ); } function testAdxcc2band(award, obj, baseHash) { if (String(obj.dxcc) + baseHash in g_tracker[award.test.look].dxcc) { return false; } return true; } function scoreAcqz(award, obj) { if (obj.cqz) { if (!(obj.cqz in award.stat)) award.stat[obj.cqz] = newAwardCountObject(); return workAwardObject( award.stat[obj.cqz], obj.band, obj.mode, obj.digital, obj.phone ); } return false; } function testAcqz(award, obj, baseHash) { if (obj.cqza) { var x = 0; for (var z in obj.cqza) { if (obj.cqza[z] + baseHash in g_tracker[award.test.look].cqz) x++; } if (obj.cqza.length == x) return false; } return true; } function scoreAnumsfx(award, obj) { var test = g_awards[award.sponsor].awards[award.name]; var px = obj.px.substr(0, obj.px.length - 1); var suf = obj.DEcall.replace(px, ""); suf = suf.substr(0, test.rule.numsfx[0][0].length); for (var i in test.rule.numsfx) { for (var s in test.rule.numsfx[i]) { if (suf.indexOf(test.rule.numsfx[i][s]) == 0) { if (!(i in award.stat)) award.stat[i] = newAwardCountObject(); return workAwardObject( award.stat[i], obj.band, obj.mode, obj.digital, obj.phone ); } } } return false; } function testAnumsfx(award, obj) { var test = g_awards[award.sponsor].awards[award.name]; var px = obj.px.substr(0, obj.px.length - 1); var suf = obj.DEcall.replace(px, ""); suf = suf.substr(0, test.rule.numsfx[0][0].length); for (var i in test.rule.numsfx) { for (var s in test.rule.numsfx[i]) { if (suf.indexOf(test.rule.numsfx[i][s]) == 0) { return false; } } } return true; } function scoreApxplus(award, obj) { var test = g_awards[award.sponsor].awards[award.name]; if (test.rule.pxplus) { for (var i in test.rule.pxplus) { if (obj.DEcall.indexOf(test.rule.pxplus[i]) == 0) { if (!(i in award.stat)) award.stat[i] = newAwardCountObject(); return workAwardObject( award.stat[i], obj.band, obj.mode, obj.digital, obj.phone ); } } } return false; } function testApxplus(award, obj) { var test = g_awards[award.sponsor].awards[award.name]; if (test.rule.pxplus) { for (var i in test.rule.pxplus) { if (obj.DEcall.indexOf(test.rule.pxplus[i]) == 0) { return false; } } } return true; } function loadAwardJson() { g_awards = {}; var fs = require("fs"); if (fs.existsSync("./data/awards.json")) { fileBuf = fs.readFileSync("./data/awards.json"); try { g_awards = JSON.parse(fileBuf); // fs.writeFileSync("./data/awards.json", JSON.stringify(g_awards,null,2)); for (var sp in g_awards) { for (var aw in g_awards[sp].awards) { if (!("unique" in g_awards[sp].awards[aw].rule)) { g_awards[sp].awards[aw].rule.unique = 1; } if (g_awards[sp].awards[aw].rule.band[0] == "Mixed") { g_awards[sp].awards[aw].rule.band.shift(); } if (g_awards[sp].awards[aw].rule.band.length == 0) { g_awards[sp].awards[aw].rule.band = []; for (var key in g_awards[sp].mixed) { g_awards[sp].awards[aw].rule.band.push(g_awards[sp].mixed[key]); } } if ( g_awards[sp].awards[aw].rule.endorse.length == 1 && g_awards[sp].awards[aw].rule.endorse[0] == "Mixed" ) { g_awards[sp].awards[aw].rule.endorse = []; for (var key in g_awards[sp].mixed) { g_awards[sp].awards[aw].rule.endorse.push( g_awards[sp].mixed[key] ); } } } } buildAwardTypeHandlers(); } catch (e) { alert("Core awards.json : " + e); g_awards = {}; } } else alert("Missing core awards.json"); } function processAllAwardTrackers() { for (var tracker in g_awardTracker) { if (!(g_awardTracker[tracker].sponsor in g_awards)) { delete g_awardTracker[tracker]; continue; } if ( !( g_awardTracker[tracker].name in g_awards[g_awardTracker[tracker].sponsor].awards ) ) { delete g_awardTracker[tracker]; continue; } processAward(tracker); } updateAwardList(); } function newAwardTrackerObject(sponsor, award, enable) { var newAward = {}; newAward.sponsor = sponsor; newAward.name = award; newAward.enable = enable; newAward.mode = g_awards[sponsor].awards[award].rule.mode[0]; newAward.band = g_awards[sponsor].awards[award].rule.band[0]; newAward.count = g_awards[sponsor].awards[award].rule.count[0]; newAward.stat = {}; newAward.comp = {}; newAward.test = {}; return newAward; } function addAllAwards() { for (var sponsor in g_awards) { for (var award in g_awards[sponsor].awards) { var awardToAdd = newAwardTrackerObject(sponsor, award, true); var hash = awardToAdd.name + "-" + awardToAdd.sponsor; if (!(hash in g_awardTracker)) { g_awardTracker[hash] = awardToAdd; processAward(hash); storeAwardTracker(); } } } updateAwardList(); window.opener.goProcessRoster(); } function delAllAwards() { g_awardTracker = {}; storeAwardTracker(); updateAwardList(); window.opener.goProcessRoster(); } function newCompileCountObject() { var compileCountObject = {}; compileCountObject.bands = {}; compileCountObject.modes = {}; compileCountObject.endorse = {}; compileCountObject.counts = {}; return compileCountObject; } function singleCompile(award, obj) { var test = g_awards[award.sponsor].awards[award.name]; var rule = test.rule; var comp = newCompileCountObject(); for (var mode in rule.mode) { comp.modes[rule.mode[mode]] = 0; comp.bands[rule.mode[mode]] = {}; for (var band in rule.band) { comp.bands[rule.mode[mode]][rule.band[band]] = 0; } for (var key in obj) { if ( rule.mode[mode] in obj[key].bands && Object.keys(obj[key].bands[rule.mode[mode]]).length ) { comp.modes[rule.mode[mode]] += 1; for (var band in rule.band) { if (rule.band[band] in obj[key].bands[rule.mode[mode]]) { comp.bands[rule.mode[mode]][rule.band[band]] += 1; } } } } } for (var mode in comp.modes) { comp.endorse[mode] = {}; comp.counts[mode] = {}; for (var cnts in rule.count) { comp.counts[mode][rule.count[cnts]] = { num: comp.modes[mode], per: parseInt( Math.min(100, (comp.modes[mode] / rule.count[cnts]) * 100.0) ) }; } for (var endorse in rule.endorse) { comp.endorse[mode][rule.endorse[endorse]] = {}; for (var cnts in rule.count) { comp.endorse[mode][rule.endorse[endorse]][rule.count[cnts]] = comp.bands[mode][rule.endorse[endorse]] >= rule.count[cnts]; } } } return comp; } function doubleCompile(award, firstLevel) { var test = g_awards[award.sponsor].awards[award.name]; var rule = test.rule; for (var k in firstLevel) { firstLevel[k].bands = {}; // firstLevel[k].modes = {}; var obj = singleCompile(award, firstLevel[k].unique); for (var mode in obj.bands) { for (var cnt in test.rule.count) { if (obj.counts[mode][test.rule.count[cnt]].num >= test.rule.unique) { for (var band in obj.bands[mode]) { if (!(mode in firstLevel[k].bands)) firstLevel[k].bands[mode] = {}; if (obj.bands[mode][band] > 0) { firstLevel[k].bands[mode][band] = ~~firstLevel[k].bands[mode][band] + 1; } } } } } /* for ( var mode in obj.modes ) { if ( !(mode in firstLevel[k].modes) ) firstLevel[k].modes[mode] = 0; if ( obj.modes[mode] > 0 ) firstLevel[k].modes[mode] += 1; } */ delete firstLevel[k].unique; firstLevel[k].unique = null; } return singleCompile(award, firstLevel); }