gridtracker/package.nw/lib/roster.js

3766 wiersze
88 KiB
JavaScript

// GridTracker Copyright © 2023 GridTracker.org
// All rights reserved.
// See LICENSE for more information.
const fs = require("fs");
// var CR is in screen.js
CR.developerMode = process.versions["nw-flavor"] == "sdk";
CR.callRoster = {};
CR.blockedCalls = {};
CR.blockedCQ = {};
CR.blockedDxcc = {};
CR.blockedCQz = {};
CR.blockedITUz = {};
CR.scriptReport = {};
CR.worked = {};
CR.confirmed = {};
CR.modes = {};
CR.modes_phone = {};
CR.currentUSCallsigns = null;
CR.currentUSState = "";
CR.currentDXCCs = -1;
CR.callsignManifest = null;
CR.rosterSettings = {};
CR.day = 0;
CR.dayAsString = "0";
CR.menu = null;
CR.callMenu = null;
CR.ageMenu = null;
CR.callingMenu = null;
CR.compactMenu = null;
CR.menuItemForCurrentColumn = null;
CR.currentColumnName = null;
CR.targetHash = "";
CR.clearIgnores = null;
CR.clearIgnoresCall = null;
CR.dxccMenu = null;
CR.targetDxcc = -1;
CR.clearDxccIgnore = null;
CR.clearDxccIgnoreMainMenu = null;
CR.CQMenu = null;
CR.targetCQ = "";
CR.clearCQIgnore = null;
CR.clearCQIgnoreMainMenu = null;
CR.clearCQzIgnore = null;
CR.clearCQzIgnoreMainMenu = null;
CR.clearITUzIgnore = null;
CR.clearITUzIgnoreMainMenu = null;
CR.timerInterval = null;
CR.typingInRoster = false;
CR.awards = {};
CR.awardTypes = {};
CR.awardTracker = {};
CR.callsignDatabaseDXCC = {};
CR.callsignDatabaseUS = {};
CR.callsignDatabaseUSplus = {};
CR.modeColors = {};
CR.modeColors.FT4 = "1111FF";
CR.modeColors.FT8 = "11FF11";
CR.modeColors.JT4 = "EE1111";
CR.modeColors.JT9 = "7CFC00";
CR.modeColors.JT65 = "E550E5";
CR.modeColors.QRA64 = "FF00FF";
CR.modeColors.MSK144 = "4949FF";
CR.rosterTimeout = null;
CR.rosterFocus = false;
CR.defaultSettings = {
callsign: "all",
hunting: "dxcc",
huntNeed: "confirmed",
requireGrid: false,
wantMaxDT: false,
wantMinDB: false,
wantMinFreq: false,
wantMaxFreq: false,
wantRRCQ: 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,
noUnknownDXCC: true,
callsignRegex: "",
huntRegexValue: "",
realtime: true,
wanted: {
huntCallsign: false,
huntGrid: true,
huntDXCC: true,
huntCQz: false,
huntITUz: false,
huntMarathon: false,
huntState: false,
huntCounty: false,
huntCont: false,
huntPX: false,
huntPOTA: false,
huntQRZ: true,
huntOAMS: false,
huntRegex: false
},
columns: {
Callsign: true,
Band: false,
Mode: false,
Calling: true,
Rig: false,
Grid: true,
Msg: false,
DXCC: true,
Flag: true,
State: true,
County: false,
POTA: false,
Cont: false,
dB: true,
Freq: false,
DT: false,
Dist: false,
Azim: true,
CQz: false,
ITUz: false,
PX: false,
LoTW: false,
eQSL: false,
OQRS: false,
Spot: false,
Life: false,
OAMS: true,
Age: true,
UTC: true
},
displayFilters: {
brightness: 100,
contrast: 100,
saturate: 100,
invert: 0,
grayscale: 0,
sepia: 0,
huerotate: 0
},
reference: 0,
controls: true,
controlsExtended: true,
compact: false,
settingProfiles: false,
sortColumn: "Age",
sortReverse: true,
clearRosterOnBandChange: true,
rosterAlwaysOnTop: false,
rosterDelayOnFocus: false,
rosterDelayTime: 1500,
rosterTime: 120,
compactEntity: "DXCC"
};
CR.def_displayFilters = {
brightness: 100,
contrast: 100,
saturate: 100,
invert: 0,
sepia: 0,
huerotate: 0
};
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.blockedCQz == "undefined")
{
localStorage.blockedCQz = "{}";
}
if (typeof localStorage.blockedITUz == "undefined")
{
localStorage.blockedITUz = "{}";
}
if (typeof localStorage.awardTracker == "undefined")
{
localStorage.awardTracker = "{}";
CR.rosterSettings = {};
writeRosterSettings();
}
CR.awardTracker = JSON.parse(localStorage.awardTracker);
if (typeof localStorage.blockedCalls != "undefined")
{
CR.blockedCalls = JSON.parse(localStorage.blockedCalls);
CR.blockedCQ = JSON.parse(localStorage.blockedCQ);
CR.blockedDxcc = JSON.parse(localStorage.blockedDxcc);
CR.blockedCQz = JSON.parse(localStorage.blockedCQz);
CR.blockedITUz = JSON.parse(localStorage.blockedITUz);
}
function storeBlocks()
{
localStorage.blockedCalls = JSON.stringify(CR.blockedCalls);
localStorage.blockedCQ = JSON.stringify(CR.blockedCQ);
localStorage.blockedDxcc = JSON.stringify(CR.blockedDxcc);
localStorage.blockedCQz = JSON.stringify(CR.blockedCQz);
localStorage.blockedITUz = JSON.stringify(CR.blockedITUz);
}
function storeAwardTracker()
{
localStorage.awardTracker = JSON.stringify(CR.awardTracker);
}
function loadSettings()
{
let readSettings = {};
if (typeof localStorage.rosterSettings != "undefined")
{
readSettings = JSON.parse(localStorage.rosterSettings);
}
CR.rosterSettings = deepmerge(CR.defaultSettings, readSettings);
fixLegacySettings();
writeRosterSettings();
}
function fixLegacySettings()
{
// Not sure why, but Paul Traina added this settings cleanup in August 2020.
if ("GT" in CR.rosterSettings.columns) delete CR.rosterSettings.columns.GT;
// In January 2022, we refactored roster column sorting
if (CR.rosterSettings.lastSortIndex)
{
CR.rosterSettings.sortColumn = LEGACY_COLUMN_SORT_ID[CR.rosterSettings.lastSortIndex] || "Age";
delete CR.rosterSettings.lastSortIndex;
}
// In January 2022, we refactored roster column sorting
if (CR.rosterSettings.lastSortReverse)
{
CR.rosterSettings.sortReverse = CR.rosterSettings.lastSortReverse;
delete CR.rosterSettings.lastSortReverse;
}
// In January 2022, we added a `columnOrder` setting, which we need to ensure always includes all columns
CR.rosterSettings.columnOrder = validateRosterColumnOrder(CR.rosterSettings.columnOrder);
}
function writeRosterSettings()
{
localStorage.rosterSettings = JSON.stringify(CR.rosterSettings);
}
function isKnownCallsignDXCC(dxcc)
{
if (dxcc in CR.callsignDatabaseDXCC) return true;
return false;
}
function isKnownCallsignUS(dxcc)
{
if (dxcc in CR.callsignDatabaseUS) return true;
return false;
}
function isKnownCallsignUSplus(dxcc)
{
if (dxcc in CR.callsignDatabaseUSplus) return true;
return false;
}
function timeNowSec()
{
return parseInt(Date.now() / 1000);
}
function lockNewWindows()
{
if (typeof nw != "undefined")
{
let gui = require("nw.gui");
let win = gui.Window.get();
win.on("new-win-policy", function (frame, url, policy)
{
gui.Shell.openExternal(url);
policy.ignore();
});
}
}
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 rosterInFocus()
{
if (CR.rosterSettings.rosterDelayOnFocus)
{
CR.rosterFocus = true;
}
}
function rosterNoFocus()
{
CR.rosterFocus = false;
if (CR.rosterTimeout != null)
{
nodeTimers.clearTimeout(CR.rosterTimeout);
CR.rosterTimeout = null;
viewRoster();
}
}
function processRoster(roster)
{
CR.callRoster = roster;
if (CR.rosterTimeout != null)
{
nodeTimers.clearTimeout(CR.rosterTimeout);
CR.rosterTimeout = null;
}
if (CR.rosterFocus)
{
CR.rosterTimeout = nodeTimers.setTimeout(viewRoster, CR.rosterSettings.rosterDelayTime);
rosterDelayDiv.style.display = "inline-block";
}
else
{
viewRoster();
}
}
function viewRoster()
{
CR.rosterTimeout = null;
rosterDelayDiv.style.display = "none";
let rosterSettings = prepareRosterSettings();
processRosterFiltering(CR.callRoster, rosterSettings);
processRosterHunting(CR.callRoster, rosterSettings, CR.awardTracker);
renderRoster(CR.callRoster, rosterSettings);
sendAlerts(CR.callRoster, rosterSettings);
}
function realtimeRoster()
{
let now = timeNowSec();
CR.day = parseInt(now / 86400);
CR.dayAsString = String(CR.day);
if (CR.rosterSettings.realtime == false) return;
let timeCols = document.getElementsByClassName("timeCol");
for (const x in timeCols)
{
if ((typeof timeCols[x].id != "undefined") && (typeof CR.callRoster[timeCols[x].id.substr(2)] != "undefined"))
{
let when = now - CR.callRoster[timeCols[x].id.substr(2)].callObj.age;
timeCols[x].innerHTML = toDHMS(when);
}
}
let lifeCols = document.getElementsByClassName("lifeCol");
for (const x in lifeCols)
{
if ((typeof lifeCols[x].id != "undefined") && (typeof CR.callRoster[lifeCols[x].id.substr(2)] != "undefined"))
{
let when = now - CR.callRoster[lifeCols[x].id.substr(2)].callObj.life;
lifeCols[x].innerHTML = toDHMS(when);
}
}
if (CR.rosterSettings.columns.Spot)
{
let spotCols = document.getElementsByClassName("spotCol");
for (const x in spotCols)
{
if ((typeof spotCols[x].id != "undefined") && (typeof CR.callRoster[spotCols[x].id.substr(2)] != "undefined"))
{
spotCols[x].innerHTML = getSpotString(CR.callRoster[spotCols[x].id.substr(2)].callObj);
}
}
}
}
function getSpotString(callObj)
{
let result = " ";
if (callObj.spot && callObj.spot.when > 0)
{
when = timeNowSec() - callObj.spot.when;
if (when <= window.opener.GT.receptionSettings.viewHistoryTimeSec)
{ result = toDHM(parseInt(when)); }
}
if (result != "&nbsp;") 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(
CR.callRoster[thisHash].DEcall,
CR.callRoster[thisHash].grid
);
}
function callingLookup(thisHash, grid)
{
let thisCall = CR.callRoster[thisHash].DXcall;
window.opener.startLookup(thisCall, grid);
}
function callGenMessage(thisHash, grid)
{
let thisCall = CR.callRoster[thisHash].DEcall;
let instance = CR.callRoster[thisHash].callObj.instance;
window.opener.startGenMessages(thisCall, grid, instance);
}
function callingGenMessage(thisHash, grid)
{
let thisCall = CR.callRoster[thisHash].DXcall;
let instance = CR.callRoster[thisHash].callObj.instance;
window.opener.startGenMessages(thisCall, grid, instance);
}
function centerOn(grid)
{
window.opener.centerOn(grid);
}
function instanceChange(what)
{
window.opener.GT.instances[what.id].crEnable = what.checked;
viewRoster();
}
function updateInstances()
{
if (window.opener.GT.instancesIndex.length > 1)
{
let instances = window.opener.GT.instances;
let worker = "";
let keys = Object.keys(instances).sort();
for (const key in keys)
{
let inst = keys[key];
let sp = inst.split(" - ");
let shortInst = sp[sp.length - 1].substring(0, 18);
let color = "blue";
if (instances[inst].open == false)
{
color = "purple";
}
worker +=
`<div class='button' style='background-color:${color};'>` +
`<input type='checkbox' id='${inst}' onchange='instanceChange(this);' ` +
(instances[inst].crEnable ? "checked" : "") +
`>&nbsp;${shortInst}</div>`
}
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;
let option = document.createElement("option");
option.value = value;
option.text = text;
return option;
}
function createSelectOptions(
selectElementString,
selectNameDefault,
forObject,
altName = null,
defaultValue = null,
checkSponsor = null
)
{
let selector = document.getElementById(selectElementString);
selector.innerHTML = "";
let option = document.createElement("option");
option.value = defaultValue;
option.text = selectNameDefault;
option.selected = true;
option.disabled = true;
option.style.display = "none";
selector.appendChild(option);
let obj = null;
if (forObject)
{
obj = Object.keys(forObject).sort();
}
for (const k in obj)
{
let opt = obj[k];
let option = document.createElement("option");
option.value = opt;
option.text = altName ? forObject[opt][altName] : opt;
if (checkSponsor && opt + "-" + checkSponsor in CR.awardTracker)
{ option.disabled = true; }
selector.appendChild(option);
}
}
function awardSponsorChanged()
{
awardName.style.display = "";
createSelectOptions(
"awardName",
"Select Award",
CR.awards[awardSponsor.value].awards,
"name",
null,
awardSponsor.value
);
}
function awardNameChanged()
{
let awardToAdd = newAwardTrackerObject(
awardSponsor.value,
awardName.value,
true
);
let hash = awardToAdd.name + "-" + awardToAdd.sponsor;
if (!(hash in CR.awardTracker))
{
CR.awardTracker[hash] = awardToAdd;
storeAwardTracker();
processAward(hash);
updateAwardList(hash);
viewRoster();
}
createSelectOptions(
"awardName",
"Select Award",
CR.awards[awardToAdd.sponsor].awards,
"name",
null,
awardToAdd.sponsor
);
}
function updateAwardList(target = null)
{
let worker =
"<table id='awardTable' class='awardTableCSS' >";
worker += "<tr>";
worker += "<th align='left'>Name</th><th>Award</th><th>Track</th><th></th>";
worker += "</tr>";
worker += "</table>";
AwardWantedList.innerHTML = worker;
let keys = Object.keys(CR.awardTracker).sort();
for (const key in keys)
{
let award = CR.awardTracker[keys[key]];
let rule = CR.awards[award.sponsor].awards[award.name].rule;
let row = awardTable.insertRow();
row.id = keys[key];
let baseAward = false;
let baseCount = 0;
let endorseCount = 0;
let endorseTotal = 0;
let allEndorse = false;
let tooltip = CR.awards[award.sponsor].awards[award.name].tooltip + " (" + CR.awards[award.sponsor].sponsor + ")\n";
tooltip += toTitleCase(award.test.qsl_req) + " QSO\n";
for (const mode in award.comp.counts)
{
tooltip += mode + "\n";
for (const 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";
let wrk = "";
if (Object.keys(award.comp.endorse).length > 0)
{
for (const 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;
let cell = createCellHtml(row, award.name + " - " + award.sponsor);
cell.style.textAlign = "left";
cell.style.color = "lightblue";
createCellHtml(
row, (allEndorse
? "<img src='./img/award-trophy.png' height='14px'>"
: baseAward
? "<img src='./img/award-medal.png' height='13px'>"
: baseCount > 0
? "<img src='./img/award-tally.png' height='15px'>"
: "<img src='./img/award-empty.png' height='12px'>"),
tooltip
);
createCell(row, "enable", award.enable, award.enable, "Toggle Tracking", true);
createCellHtml(row, "<img title='Remove Tracker' onclick='deleteAwardTracker(this)' style='margin:0;padding:0;margin-top:2px;cursor:pointer;' src='./img/award-delete.png' height='12px'>");
}
}
function deleteAwardTracker(sender)
{
let id = sender.parentNode.parentNode.id;
delete CR.awardTracker[id];
storeAwardTracker();
resetAwardAdd();
updateAwardList();
viewRoster();
}
function awardCheckboxChanged(sender)
{
let awardId = sender.target.parentNode.parentNode.id;
CR.awardTracker[sender.target.parentNode.parentNode.id][sender.target.name] =
sender.target.checked;
storeAwardTracker();
viewRoster();
}
function awardValueChanged(sender)
{
let awardId = sender.target.parentNode.parentNode.id;
CR.awardTracker[sender.target.parentNode.parentNode.id][sender.target.name] =
sender.target.value;
storeAwardTracker();
viewRoster();
}
function createCell(
row,
target,
value,
data = null,
title = null,
checkbox = false
)
{
let cell = row.insertCell();
if (data == null) cell.innerHTML = value;
if (title) cell.title = title;
if (checkbox)
{
let 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)
{
let cell = row.insertCell();
cell.innerHTML = html;
if (title) cell.title = title;
return cell;
}
function createAwardSelector(cell, target, value, forObject)
{
let 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 (const opt in forObject)
{
let 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", CR.awards, "sponsor");
}
function openAwardPopup()
{
awardHunterDiv.style.display = "";
resetAwardAdd();
}
function closeAwardPopup()
{
awardHunterDiv.style.display = "none";
resetAwardAdd();
}
function toggleMoreControls()
{
CR.rosterSettings.controlsExtended = !CR.rosterSettings.controlsExtended;
localStorage.rosterSettings = JSON.stringify(CR.rosterSettings);
setVisual();
}
function setVisual()
{
huntNeed.style.display = "none";
stateSelect.style.display = "none";
DXCCsSelect.style.display = "none";
if (CR.rosterSettings.controls)
{
if (CR.rosterSettings.controlsExtended)
{
RosterControls.className = "extended";
instancesWrapper.style.display = "";
}
else
{
RosterControls.className = "normal";
instancesWrapper.style.display = "none";
}
}
else
{
RosterControls.className = "hidden";
instancesWrapper.style.display = "none";
}
// Award Hunter
if (referenceNeed.value == LOGBOOK_AWARD_TRACKER)
{
HuntModeControls.style.display = "none";
CallsignsControls.style.display = "none";
AwardTrackerControls.style.display = "";
updateAwardList();
}
else
{
for (const key in CR.rosterSettings.wanted)
{
if (document.getElementById(key))
{
document.getElementById(key).checked = CR.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 (huntRegex.checked == true)
{
huntRegexValue.style.display = "";
}
else
{
huntRegexValue.style.display = "none";
}
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.GT.callsignLookups.lotwUseEnable == true)
{
usesLoTWDiv.style.display = "";
if (CR.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.GT.callsignLookups.eqslUseEnable == true)
{
useseQSLDiv.style.display = "";
}
else
{
useseQSLDiv.style.display = "none";
}
if (window.opener.GT.callsignLookups.oqrsUseEnable == true)
{
usesOQRSDiv.style.display = "";
}
else
{
usesOQRSDiv.style.display = "none";
}
if (CR.rosterSettings.columns.Spot == true)
{
onlySpotDiv.style.display = "";
}
else
{
onlySpotDiv.style.display = "none";
}
if (CR.rosterSettings.callsign == "all" || CR.rosterSettings.callsign == "hits")
{
allOnlyNewDiv.style.display = "";
}
else
{
allOnlyNewDiv.style.display = "none";
}
rosterBody.style.display = "block";
resize();
}
function wantedChanged(element)
{
CR.rosterSettings.wanted[element.id] = element.checked;
if (element.checked == true)
{
let t = element.id.replace("hunt", "");
if (t in CR.rosterSettings.columns)
{
CR.rosterSettings.columns[t] = true;
for (const i in CR.menu.items)
{
if (
typeof CR.menu.items[i].checked != "undefined" &&
CR.menu.items[i].label == t
)
{ CR.menu.items[i].checked = true; }
}
}
}
setVisual();
writeRosterSettings();
CR.scriptReport = Object();
for (const callHash in window.opener.GT.callRoster)
{
window.opener.GT.callRoster[callHash].callObj.alerted = false;
}
viewRoster();
}
function valuesChanged()
{
CR.rosterSettings.callsign = callsignNeed.value;
CR.rosterSettings.hunting = huntMode.value;
CR.rosterSettings.huntNeed = huntNeed.value;
CR.rosterSettings.requireGrid = wantGrid.checked;
CR.rosterSettings.wantMaxDT = wantMaxDT.checked;
CR.rosterSettings.wantMinDB = wantMinDB.checked;
CR.rosterSettings.wantMinFreq = wantMinFreq.checked;
CR.rosterSettings.wantMaxFreq = wantMaxFreq.checked;
CR.rosterSettings.wantRRCQ = wantRRCQ.checked;
maxDTView.innerHTML = CR.rosterSettings.maxDT = maxDT.value;
minDbView.innerHTML = CR.rosterSettings.minDb = minDb.value;
minFreqView.innerHTML = CR.rosterSettings.minFreq = minFreq.value;
maxFreqView.innerHTML = CR.rosterSettings.maxFreq = maxFreq.value;
CR.rosterSettings.maxLoTW = maxLoTW.value;
maxLoTWView.innerHTML = CR.rosterSettings.maxLoTW < 27 ? toYM(Number(CR.rosterSettings.maxLoTW)) : "<b>&infin;</b>";
CR.rosterSettings.maxLoTW = maxLoTW.value;
CR.rosterSettings.cqOnly = cqOnly.checked;
CR.rosterSettings.noMyDxcc = noMyDxcc.checked;
CR.rosterSettings.onlyMyDxcc = onlyMyDxcc.checked;
if (noMsg.checked && onlyMsg.checked && noMsgValue.value == onlyMsgValue.value)
{
if (CR.rosterSettings.noMsg)
{
noMsg.checked = false;
}
else
{
onlyMsg.checked = false;
}
}
CR.rosterSettings.noMsg = noMsg.checked;
CR.rosterSettings.onlyMsg = onlyMsg.checked;
CR.rosterSettings.noMsgValue = noMsgValue.value;
CR.rosterSettings.onlyMsgValue = onlyMsgValue.value;
CR.rosterSettings.usesLoTW = usesLoTW.checked;
CR.rosterSettings.useseQSL = useseQSL.checked;
CR.rosterSettings.usesOQRS = usesOQRS.checked;
CR.rosterSettings.onlySpot = onlySpot.checked;
CR.rosterSettings.reference = referenceNeed.value;
CR.rosterSettings.allOnlyNew = allOnlyNew.checked;
CR.rosterSettings.useRegex = useRegex.checked;
CR.rosterSettings.callsignRegex = callsignRegex.value;
CR.rosterSettings.huntRegexValue = huntRegexValue.value;
CR.rosterSettings.noUnknownDXCC = noUnknownDXCC.checked;
writeRosterSettings();
CR.scriptReport = Object();
for (const callHash in window.opener.GT.callRoster)
{
window.opener.GT.callRoster[callHash].callObj.alerted = false;
}
setVisual();
}
function loadFilterSettings()
{
let filters = "";
for (const filter in CR.rosterSettings.displayFilters)
{
let slider = document.getElementById("filter" + filter + "Slider");
if (slider)
{
slider.value = CR.rosterSettings.displayFilters[filter];
let td = document.getElementById("filter" + filter + "Td");
if (filter != "huerotate")
{
td.innerHTML = slider.value + "%";
filters += filter + "(" + slider.value + "%) ";
}
else
{
td.innerHTML = slider.value + " deg";
filters += "hue-rotate(" + slider.value + "deg) ";
}
}
}
document.documentElement.style.filter = filters;
}
function filtersChanged()
{
for (const filter in CR.rosterSettings.displayFilters)
{
let slider = document.getElementById("filter" + filter + "Slider");
if (slider)
{
CR.rosterSettings.displayFilters[filter] = slider.value;
}
else
{
// no longer a filter, get rid of it
delete CR.rosterSettings.displayFilters[filter];
}
}
loadFilterSettings();
}
function resetFilters()
{
for (const filter in CR.rosterSettings.displayFilters)
{
CR.rosterSettings.displayFilters[filter] = CR.def_displayFilters[filter];
}
loadFilterSettings();
}
function getBuffer(file_url, callback, flag, mode, port, cookie)
{
let url = require("url");
let http = require(mode);
let fileBuffer = null;
let 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)
{
// let fsize = res.headers["content-length"];
let 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)
{
let rawData = JSON.parse(buffer);
CR.currentUSState = flag;
CR.currentUSCallsigns = Object();
for (const key in rawData.c) CR.currentUSCallsigns[rawData.c[key]] = true;
viewRoster();
}
function stateChangedValue(what)
{
if (CR.currentUSState != stateSelect.value && stateSelect.value != "")
{
CR.currentUSState = stateSelect.value;
if (window.opener.GT.mapSettings.offlineMode == false)
{
let callState = CR.currentUSState.replace("CN-", "");
getBuffer(
"https://storage.googleapis.com/gt_app/callsigns/" + callState + ".callsigns.json",
callsignResult,
CR.currentUSState,
"http",
80
);
}
else
{
viewRoster();
CR.currentUSState = "";
CR.currentUSCallsigns = null;
stateSelect.value = "";
return;
}
}
if (stateSelect.value == "")
{
CR.currentUSState = "";
CR.currentUSCallsigns = null;
viewRoster();
}
}
function DXCCsChangedValue(what)
{
CR.currentDXCCs = DXCCsSelect.value;
viewRoster();
}
function initDXCCSelector()
{
let items = Object.keys(window.opener.GT.dxccToAltName).sort(function (a, b)
{
return window.opener.GT.dxccToAltName[a].localeCompare(
window.opener.GT.dxccToAltName[b]
);
});
let newSelect = document.getElementById("DXCCsSelect");
for (const i in items)
{
let key = items[i];
if (
window.opener.GT.dxccInfo[key].geo !=
"deleted"
)
{
let option = document.createElement("option");
option.value = key;
option.text =
window.opener.GT.dxccToAltName[key] +
" (" +
window.opener.GT.dxccInfo[key].pp +
")";
newSelect.appendChild(option);
}
}
newSelect.oninput = DXCCsChangedValue;
}
function manifestResult(buffer, flag)
{
CR.callsignManifest = JSON.parse(buffer);
let newSelect = document.getElementById("stateSelect");
for (const key in CR.callsignManifest.cnt)
{
let option = document.createElement("option");
if (window.opener.GT.enums[key])
{
option.value = key;
option.text = window.opener.GT.enums[key];
}
else
{
option.value = "CN-" + key;
option.text = window.opener.GT.enums["CN-" + key];
}
newSelect.appendChild(option);
}
newSelect.oninput = stateChangedValue;
}
function receiveMessage(event) {}
CR.tracker = {};
function updateWorked()
{
CR.worked = window.opener.GT.tracker.worked;
CR.confirmed = window.opener.GT.tracker.confirmed;
CR.modes = window.opener.GT.modes;
CR.modes_phone = window.opener.GT.modes_phone;
CR.tracker = window.opener.GT.tracker;
processAllAwardTrackers();
}
function deleteCallsignIgnore(key)
{
delete CR.blockedCalls[key];
storeBlocks();
openIgnoreEdit();
viewRoster();
}
function deleteDxccIgnore(key)
{
delete CR.blockedDxcc[key];
storeBlocks();
openIgnoreEdit();
viewRoster();
}
function deleteCQIgnore(key)
{
delete CR.blockedCQ[key];
storeBlocks();
openIgnoreEdit();
viewRoster();
}
function deleteCQzIgnore(key)
{
delete CR.blockedCQz[key];
storeBlocks();
openIgnoreEdit();
viewRoster();
}
function deleteITUzIgnore(key)
{
delete CR.blockedITUz[key];
storeBlocks();
openIgnoreEdit();
viewRoster();
}
function clearAllCallsignIgnores()
{
CR.blockedCalls = Object();
storeBlocks();
openIgnoreEdit();
viewRoster();
}
function clearAllDxccIgnores()
{
CR.blockedDxcc = Object();
storeBlocks();
openIgnoreEdit();
viewRoster();
}
function clearAllCQIgnores()
{
CR.blockedCQ = Object();
storeBlocks();
openIgnoreEdit();
viewRoster();
}
function clearAllCQzIgnores()
{
CR.blockedCQz = Object();
storeBlocks();
openIgnoreEdit();
viewRoster();
}
function clearAllITUzIgnores()
{
CR.blockedITUz = Object();
storeBlocks();
openIgnoreEdit();
viewRoster();
}
function openSettings()
{
MainCallRoster.style.display = "block";
settingsDiv.style.display = "block";
editView.style.display = "none";
}
function closeSettings()
{
MainCallRoster.style.display = "block";
settingsDiv.style.display = "none";
editView.style.display = "none";
}
function closeEditIgnores()
{
MainCallRoster.style.display = "block";
editView.style.display = "none";
}
function openIgnoreEdit()
{
MainCallRoster.style.display = "none";
editView.style.display = "inline-block";
let worker = "";
let clearString = "<th>none</th>";
if (Object.keys(CR.blockedCalls).length > 0)
{
clearString =
"<th style='cursor:pointer;' onclick='clearAllCallsignIgnores()'>Clear All</th>";
}
worker +=
"<div style='margin:10px;padding:0px;vertical-align:top;display:inline-block;margin-right:2px;overflow:auto;overflow-x:hidden;height:" +
(window.innerHeight - 135) +
"px;'><table class='darkTable' align=center><tr><th align=left>Callsigns</th>" +
clearString +
"</tr>";
Object.keys(CR.blockedCalls)
.sort()
.forEach(function (key, i)
{
worker +=
"<tr><td align=left style='color:#FFFF00;' >" +
key +
"</td><td style='cursor:pointer;' onclick='deleteCallsignIgnore(\"" +
key +
"\")'><img src='/img/trash_24x48.png' style='height:17px;margin:-1px;margin-bottom:-3px;padding:0px'></td></tr>";
});
worker += "</table></div>";
clearString = "<th>none</th>";
if (Object.keys(CR.blockedCQ).length > 0)
{
clearString =
"<th style='cursor:pointer;' onclick='clearAllCQIgnores()'>Clear All</th>";
}
worker +=
"<div style='margin:10px;padding:0px;vertical-align:top;display:inline-block;margin-right:2px;overflow:auto;overflow-x:hidden;height:" +
(window.innerHeight - 135) +
"px;'><table class='darkTable' align=center><tr><th align=left>CQ</th>" +
clearString +
"</tr>";
Object.keys(CR.blockedCQ)
.sort()
.forEach(function (key, i)
{
worker +=
"<tr><td align=left style='color:cyan;' >" +
key +
"</td><td style='cursor:pointer;' onclick='deleteCQIgnore(\"" +
key +
"\")'><img src='/img/trash_24x48.png' style='height:17px;margin:-1px;margin-bottom:-3px;padding:0px'></td></tr>";
});
worker += "</table></div>";
clearString = "<th>none</th>";
if (Object.keys(CR.blockedDxcc).length > 0)
{
clearString =
"<th style='cursor:pointer;' onclick='clearAllDxccIgnores()'>Clear All</th>";
}
worker +=
"<div style='margin:10px;vertical-align:top;display:inline-block;overflow:auto;overflow-x:hidden;height:" +
(window.innerHeight - 135) +
"px;'><table class='darkTable' align=center><tr><th align=left>DXCCs</th>" +
clearString +
"</tr>";
Object.keys(CR.blockedDxcc)
.sort()
.forEach(function (key, i)
{
worker +=
"<tr><td align=left style='color:#FFA500' >" +
window.opener.GT.dxccToAltName[key] +
" (" +
window.opener.GT.dxccInfo[key].pp +
")</td><td style='cursor:pointer;' onclick='deleteDxccIgnore(\"" +
key +
"\")'><img src='/img/trash_24x48.png' style='height:17px;margin:-1px;margin-bottom:-3px;padding:0px'></td></tr>";
});
worker += "</table></div>";
if (Object.keys(CR.blockedCQz).length > 0)
{
clearString =
"<th style='cursor:pointer;' onclick='clearAllCQzIgnores()'>Clear All</th>";
}
worker +=
"<div style='margin:10px;padding:0px;vertical-align:top;display:inline-block;margin-right:2px;overflow:auto;overflow-x:hidden;height:" +
(window.innerHeight - 135) +
"px;'><table class='darkTable' align=center><tr><th align=left>CQ Zones</th>" +
clearString +
"</tr>";
Object.keys(CR.blockedCQz)
.sort()
.forEach(function (key, i)
{
worker +=
"<tr><td align=left style='color:cyan;' >" +
key +
"</td><td style='cursor:pointer;' onclick='deleteCQzIgnore(\"" +
key +
"\")'><img src='/img/trash_24x48.png' style='height:17px;margin:-1px;margin-bottom:-3px;padding:0px'></td></tr>";
});
worker += "</table></div>";
if (Object.keys(CR.blockedITUz).length > 0)
{
clearString =
"<th style='cursor:pointer;' onclick='clearAllITUzIgnores()'>Clear All</th>";
}
worker +=
"<div style='margin:10px;padding:0px;vertical-align:top;display:inline-block;margin-right:2px;overflow:auto;overflow-x:hidden;height:" +
(window.innerHeight - 135) +
"px;'><table class='darkTable' align=center><tr><th align=left>ITU Zones</th>" +
clearString +
"</tr>";
Object.keys(CR.blockedITUz)
.sort()
.forEach(function (key, i)
{
worker +=
"<tr><td align=left style='color:cyan;' >" +
key +
"</td><td style='cursor:pointer;' onclick='deleteITUzIgnore(\"" +
key +
"\")'><img src='/img/trash_24x48.png' style='height:17px;margin:-1px;margin-bottom:-3px;padding:0px'></td></tr>";
});
worker += "</table></div>";
editTables.innerHTML = worker;
editView.style.height = (window.innerHeight - 45) + "px";
}
function onMyKeyDown(event)
{
if (!CR.typingInRoster)
{
if (event.code == "KeyS" && event.ctrlKey == true)
{
openSettings();
}
else if (event.code == "KeyR" && event.ctrlKey == true)
{
resetFilters();
}
else
{
window.opener.onMyKeyDown(event);
}
}
}
function blurOnEnter(ele)
{
if (event.key == "Enter")
{
ele.blur();
}
}
function resize()
{
if (editView.style.display == "inline-block") openIgnoreEdit();
window.opener.goProcessRoster();
}
function init()
{
window.opener.GT.rosterInitialized = true;
CR.callsignDatabaseDXCC = window.opener.GT.callsignDatabaseDXCC;
CR.callsignDatabaseUS = window.opener.GT.callsignDatabaseUS;
CR.callsignDatabaseUSplus = window.opener.GT.callsignDatabaseUSplus;
loadAwardJson();
updateWorked();
// addAllAwards();
window.addEventListener("message", receiveMessage, false);
lockNewWindows();
if (window.opener.GT.mapSettings.offlineMode == false)
{
getBuffer(
"https://storage.googleapis.com/gt_app/callsigns/manifest.json",
manifestResult,
null,
"http",
80
);
}
loadSettings();
loadFilterSettings();
updateInstances();
// callback to addControls();
loadRosterI18n();
setRosterTop();
}
// From i18n.js
function addControls()
{
WANTED_LABELS = {
cont: $.i18n("rosterColumns.Wanted.cont"),
cqz: $.i18n("rosterColumns.Wanted.cqz"),
ituz: $.i18n("rosterColumns.Wanted.ituz"),
dxcc: $.i18n("rosterColumns.Wanted.dxcc"),
dxccMarathon: $.i18n("rosterColumns.Wanted.dxccMarathon"),
cqzMarathon: $.i18n("rosterColumns.Wanted.cqzMarathon"),
state: $.i18n("rosterColumns.Wanted.state"),
grid: $.i18n("rosterColumns.Wanted.grid"),
cnty: $.i18n("rosterColumns.Wanted.cnty"),
wpx: $.i18n("rosterColumns.Wanted.wpx"),
call: $.i18n("rosterColumns.Wanted.call"),
regex: $.i18n("rosterColumns.Wanted.regex"),
oams: $.i18n("rosterColumns.Wanted.oams"),
pota: $.i18n("rosterColumns.Wanted.pota")
}
window.opener.setRosterSpot(CR.rosterSettings.columns.Spot);
for (const key in CR.rosterSettings.wanted)
{
if (document.getElementById(key))
{ document.getElementById(key).checked = CR.rosterSettings.wanted[key]; }
}
CR.menu = new nw.Menu();
CR.compactMenu = new nw.Menu();
let showControlsText = $.i18n("roster.menu.ShowControls");
let hideControlsText = $.i18n("roster.menu.HideControls");
let item = new nw.MenuItem({
type: "normal",
label: CR.rosterSettings.controls ? hideControlsText : showControlsText,
click: function ()
{
if (this.label == "Hide Controls")
{
this.label = showControlsText;
CR.rosterSettings.controls = false;
}
else
{
this.label = hideControlsText;
CR.rosterSettings.controls = true;
}
CR.compactMenu.items[0].label = CR.rosterSettings.controls ? hideControlsText : showControlsText;
localStorage.rosterSettings = JSON.stringify(CR.rosterSettings);
setVisual();
}
});
CR.menu.append(item);
item = new nw.MenuItem({
type: "normal",
label: CR.rosterSettings.controls ? hideControlsText : showControlsText,
click: function ()
{
if (this.label == hideControlsText)
{
this.label = showControlsText;
CR.rosterSettings.controls = false;
}
else
{
this.label = hideControlsText;
CR.rosterSettings.controls = true;
}
CR.menu.items[0].label = CR.rosterSettings.controls ? hideControlsText : showControlsText;
localStorage.rosterSettings = JSON.stringify(CR.rosterSettings);
setVisual();
}
});
CR.compactMenu.append(item);
item = new nw.MenuItem({
type: "normal",
label: $.i18n("roster.menu.Settings"),
click: function ()
{
openSettings();
}
});
CR.menu.append(item);
item = new nw.MenuItem({
type: "normal",
label: $.i18n("roster.menu.Settings"),
click: function ()
{
openSettings();
}
});
CR.compactMenu.append(item);
item = new nw.MenuItem({
type: "normal",
label: $.i18n("roster.menu.CompactMode"),
click: function ()
{
CR.rosterSettings.compact = true;
localStorage.rosterSettings = JSON.stringify(CR.rosterSettings);
resize();
}
});
CR.menu.append(item);
item = new nw.MenuItem({
type: "normal",
label: $.i18n("roster.menu.RosterMode"),
click: function ()
{
CR.rosterSettings.compact = false;
localStorage.rosterSettings = JSON.stringify(CR.rosterSettings);
resize();
}
});
CR.compactMenu.append(item);
CR.callMenu = new nw.Menu();
item = new nw.MenuItem({
type: "normal",
label: $.i18n("roster.menu.Lookup"),
click: function ()
{
callLookup(CR.targetHash, "");
}
});
CR.callMenu.append(item);
item = new nw.MenuItem({
type: "normal",
label: $.i18n("roster.menu.GenMesg"),
click: function ()
{
callGenMessage(CR.targetHash, "");
}
});
CR.callMenu.append(item);
item = new nw.MenuItem({ type: "separator" });
CR.callMenu.append(item);
if (window.opener.GT.pstrotatorSettings.enable)
{
item = new nw.MenuItem({
type: "normal",
label: $.i18n("roster.menu.AimRotator"),
click: function ()
{
let target = CR.callRoster[CR.targetHash]
window.opener.aimRotator(target, "");
}
});
CR.callMenu.append(item);
item = new nw.MenuItem({ type: "separator" });
CR.callMenu.append(item);
}
item = new nw.MenuItem({
type: "normal",
label: $.i18n("roster.menu.IgnoreCall"),
click: function ()
{
let thisCall = CR.callRoster[CR.targetHash].DEcall;
CR.blockedCalls[thisCall] = true;
storeBlocks();
viewRoster();
}
});
CR.callMenu.append(item);
CR.callingMenu = new nw.Menu();
item = new nw.MenuItem({
type: "normal",
label: $.i18n("roster.menu.Lookup"),
click: function ()
{
callingLookup(CR.targetHash, "");
}
});
CR.callingMenu.append(item);
item = new nw.MenuItem({
type: "normal",
label: $.i18n("roster.menu.GenMesg"),
click: function ()
{
callingGenMessage(CR.targetHash, "");
}
});
CR.callingMenu.append(item);
item = new nw.MenuItem({ type: "separator" });
CR.menu.append(item);
if (window.opener.GT.pstrotatorSettings.enable)
{
item = new nw.MenuItem({
type: "normal",
label: $.i18n("roster.menu.AimRotator"),
click: function ()
{
let target = CR.callRoster[CR.targetHash]
window.opener.aimRotator(target, "");
}
});
CR.callingMenu.append(item);
item = new nw.MenuItem({ type: "separator" });
CR.callingMenu.append(item);
}
item = new nw.MenuItem({
type: "checkbox",
label: $.i18n("roster.menu.Realtime"),
checked: CR.rosterSettings.realtime,
click: function ()
{
CR.rosterSettings.realtime = this.checked;
writeRosterSettings();
viewRoster();
}
});
CR.menu.append(item);
item = new nw.MenuItem({ type: "separator" });
CR.menu.append(item);
CR.menuItemForCurrentColumn = new nw.MenuItem({
type: "normal",
label: $.i18n("roster.menu.MoveLeft"),
click: function ()
{
moveColumnLeft(CR.currentColumnName);
}
})
CR.menu.append(CR.menuItemForCurrentColumn)
item = new nw.MenuItem({ type: "separator" });
CR.menu.append(item);
for (const columnIndex in CR.rosterSettings.columnOrder)
{
let key = CR.rosterSettings.columnOrder[columnIndex];
if (key != "Callsign")
{
let itemx = new nw.MenuItem({
type: "checkbox",
label: key,
checked: CR.rosterSettings.columns[key],
click: function ()
{
CR.rosterSettings.columns[this.label] = this.checked;
if (this.label == "Spot")
{ window.opener.setRosterSpot(CR.rosterSettings.columns.Spot); }
writeRosterSettings();
viewRoster();
resize();
}
});
CR.menu.append(itemx);
}
}
item = new nw.MenuItem({ type: "separator" });
CR.menu.append(item);
CR.clearIgnores = new nw.MenuItem({
type: "normal",
label: "Clear Call Ignore",
enabled: false,
click: function ()
{
CR.blockedCalls = Object();
storeBlocks();
viewRoster();
}
});
CR.menu.append(CR.clearIgnores);
CR.clearIgnoresCall = new nw.MenuItem({
type: "normal",
label: "Clear Ignore",
enabled: false,
click: function ()
{
CR.blockedCalls = Object();
storeBlocks();
viewRoster();
}
});
CR.callMenu.append(CR.clearIgnoresCall);
CR.CQMenu = new nw.Menu();
item = new nw.MenuItem({
type: "normal",
label: "Ignore CQ from DXCC",
click: function ()
{
CR.blockedCQ[
CR.callRoster[CR.targetCQ].DXcall +
" from " +
window.opener.GT.dxccToAltName[CR.callRoster[CR.targetCQ].callObj.dxcc]
] = true;
storeBlocks();
viewRoster();
}
});
CR.CQMenu.append(item);
item = new nw.MenuItem({
type: "normal",
label: "Ignore CQ from All",
click: function ()
{
CR.blockedCQ[CR.callRoster[CR.targetCQ].DXcall + " from All"] = true;
storeBlocks();
viewRoster();
}
});
CR.CQMenu.append(item);
CR.clearCQIgnoreMainMenu = new nw.MenuItem({
type: "normal",
label: "Clear CQ Ignore",
enabled: false,
click: function ()
{
CR.blockedCQ = Object();
storeBlocks();
viewRoster();
}
});
CR.menu.append(CR.clearCQIgnoreMainMenu);
CR.clearCQIgnore = new nw.MenuItem({
type: "normal",
label: "Clear Ignore",
enabled: false,
click: function ()
{
CR.blockedCQ = Object();
storeBlocks();
viewRoster();
}
});
CR.CQMenu.append(CR.clearCQIgnore);
item = new nw.MenuItem({
type: "normal",
label: "Edit Ignores",
enabled: true,
click: function ()
{
openIgnoreEdit();
}
});
CR.CQMenu.append(item);
CR.CQzMenu = new nw.Menu();
item = new nw.MenuItem({
type: "normal",
label: "Ignore CQ Zone",
click: function ()
{
CR.blockedCQz[CR.callRoster[CR.targetCQz].callObj.cqz] = true;
storeBlocks();
viewRoster();
}
});
CR.CQzMenu.append(item);
CR.clearCQzIgnoreMainMenu = new nw.MenuItem({
type: "normal",
label: "Clear CQ Zone Ignore",
enabled: false,
click: function ()
{
CR.blockedCQz = Object();
storeBlocks();
viewRoster();
}
});
CR.clearCQzIgnore = new nw.MenuItem({
type: "normal",
label: "Clear Ignore",
enabled: false,
click: function ()
{
CR.blockedCQz = Object();
storeBlocks();
viewRoster();
}
});
CR.CQzMenu.append(CR.clearCQzIgnore);
CR.CQzMenu.append(CR.clearCQzIgnoreMainMenu);
item = new nw.MenuItem({
type: "normal",
label: "Edit Ignores",
enabled: true,
click: function ()
{
openIgnoreEdit();
}
});
CR.CQzMenu.append(item);
CR.ITUzMenu = new nw.Menu();
item = new nw.MenuItem({
type: "normal",
label: "Ignore ITU Zone",
click: function ()
{
CR.blockedITUz[CR.callRoster[CR.targetITUz].callObj.ituz] = true;
storeBlocks();
viewRoster();
}
});
CR.ITUzMenu.append(item);
CR.clearITUzIgnoreMainMenu = new nw.MenuItem({
type: "normal",
label: "Clear ITU Zone Ignore",
enabled: false,
click: function ()
{
CR.blockedITUz = Object();
storeBlocks();
viewRoster();
}
});
CR.ITUzMenu.append(CR.clearITUzIgnoreMainMenu);
CR.clearITUzIgnore = new nw.MenuItem({
type: "normal",
label: "Clear Ignore",
enabled: false,
click: function ()
{
CR.blockedITUz = Object();
storeBlocks();
viewRoster();
}
});
CR.ITUzMenu.append(CR.clearITUzIgnore);
item = new nw.MenuItem({
type: "normal",
label: "Edit Ignores",
enabled: true,
click: function ()
{
openIgnoreEdit();
}
});
CR.ITUzMenu.append(item);
CR.dxccMenu = new nw.Menu();
item = new nw.MenuItem({
type: "normal",
label: "Ignore DXCC",
click: function ()
{
CR.blockedDxcc[CR.targetDxcc] = true;
storeBlocks();
viewRoster();
}
});
CR.dxccMenu.append(item);
CR.clearDxccIgnoreMainMenu = new nw.MenuItem({
type: "normal",
label: "Clear DXCC Ignore",
enabled: false,
click: function ()
{
CR.blockedDxcc = Object();
storeBlocks();
viewRoster();
}
});
CR.menu.append(CR.clearDxccIgnoreMainMenu);
CR.clearDxccIgnore = new nw.MenuItem({
type: "normal",
label: "Clear Ignore",
enabled: false,
click: function ()
{
CR.blockedDxcc = Object();
storeBlocks();
viewRoster();
}
});
CR.dxccMenu.append(CR.clearDxccIgnore);
item = new nw.MenuItem({
type: "normal",
label: "Edit Ignores",
enabled: true,
click: function ()
{
openIgnoreEdit();
}
});
CR.menu.append(item);
item = new nw.MenuItem({
type: "normal",
label: "Edit Ignores",
enabled: true,
click: function ()
{
openIgnoreEdit();
}
});
CR.callMenu.append(item);
item = new nw.MenuItem({
type: "normal",
label: "Edit Ignores",
enabled: true,
click: function ()
{
openIgnoreEdit();
}
});
CR.dxccMenu.append(item);
callsignNeed.value = CR.rosterSettings.callsign;
huntMode.value = CR.rosterSettings.hunting;
huntNeed.value = CR.rosterSettings.huntNeed;
wantGrid.checked = CR.rosterSettings.requireGrid;
wantMaxDT.checked = CR.rosterSettings.wantMaxDT;
wantMinDB.checked = CR.rosterSettings.wantMinDB;
wantMinFreq.checked = CR.rosterSettings.wantMinFreq;
wantMaxFreq.checked = CR.rosterSettings.wantMaxFreq;
wantRRCQ.checked = CR.rosterSettings.wantRRCQ;
maxDTView.innerHTML = maxDT.value = CR.rosterSettings.maxDT;
minDbView.innerHTML = minDb.value = CR.rosterSettings.minDb;
minFreqView.innerHTML = minFreq.value = CR.rosterSettings.minFreq;
maxFreqView.innerHTML = maxFreq.value = CR.rosterSettings.maxFreq;
maxLoTW.value = CR.rosterSettings.maxLoTW;
maxLoTWView.innerHTML = maxLoTW.value < 27 ? toYM(Number(maxLoTW.value)) : "<b>&infin;</b>";
cqOnly.checked = CR.rosterSettings.cqOnly;
noMyDxcc.checked = CR.rosterSettings.noMyDxcc;
onlyMyDxcc.checked = CR.rosterSettings.onlyMyDxcc;
noMsg.checked = CR.rosterSettings.noMsg;
onlyMsg.checked = CR.rosterSettings.onlyMsg;
noMsgValue.value = CR.rosterSettings.noMsgValue;
onlyMsgValue.value = CR.rosterSettings.onlyMsgValue;
usesLoTW.checked = CR.rosterSettings.usesLoTW;
useseQSL.checked = CR.rosterSettings.useseQSL;
onlySpot.checked = CR.rosterSettings.onlySpot;
usesOQRS.checked = CR.rosterSettings.usesOQRS;
referenceNeed.value = CR.rosterSettings.reference;
allOnlyNew.checked = CR.rosterSettings.allOnlyNew;
useRegex.checked = CR.rosterSettings.useRegex;
callsignRegex.value = CR.rosterSettings.callsignRegex;
huntRegexValue.value = CR.rosterSettings.huntRegexValue;
noUnknownDXCC.checked = CR.rosterSettings.noUnknownDXCC;
clearRosterOnBandChange.checked = CR.rosterSettings.clearRosterOnBandChange;
rosterAlwaysOnTop.checked = CR.rosterSettings.rosterAlwaysOnTop;
rosterDelayOnFocus.checked = CR.rosterSettings.rosterDelayOnFocus;
displayDelayOnFocus();
rosterDelayTime.value = CR.rosterSettings.rosterDelayTime;
rosterDelayTimeTd.innerHTML = rosterDelayTime.value + "ms";
setRosterTimeView();
for (const column in ROSTER_COLUMNS)
{
if (column != "Callsign")
{
let option = newOption(column, column);
if (column == CR.rosterSettings.compactEntity)
{
option.selected = true;
}
compactEntitySelect.appendChild(option);
}
}
setVisual();
document.addEventListener("keydown", onMyKeyDown, false);
initDXCCSelector();
CR.timerInterval = nodeTimers.setInterval(realtimeRoster, 1000);
updateInstances();
}
function compactEntityChanged()
{
CR.rosterSettings.compactEntity = compactEntitySelect.value;
viewRoster();
}
function clearRosterOnBandChangeValueChanged(what)
{
CR.rosterSettings.clearRosterOnBandChange = clearRosterOnBandChange.checked;
writeRosterSettings();
}
function rosterDelayOnFocusValueChanged(what)
{
CR.rosterSettings.rosterDelayOnFocus = rosterDelayOnFocus.checked;
displayDelayOnFocus();
writeRosterSettings();
}
function displayDelayOnFocus()
{
if (CR.rosterSettings.rosterDelayOnFocus)
{
rosterDelayTimeTd.style.display = "block";
rosterDelayTime.style.display = "block";
}
else
{
rosterDelayTimeTd.style.display = "none";
rosterDelayTime.style.display = "none";
}
}
function changeRosterDelayTime()
{
CR.rosterSettings.rosterDelayTime = rosterDelayTime.value;
rosterDelayTimeTd.innerHTML = rosterDelayTime.value + "ms";
writeRosterSettings();
}
function changeRosterTime()
{
CR.rosterSettings.rosterTime = rosterTime.value;
setRosterTimeView();
writeRosterSettings();
viewRoster();
}
function changeRosterTop(butt)
{
CR.rosterSettings.rosterAlwaysOnTop = butt.checked;
setRosterTop();
}
function setRosterTop()
{
nw.Window.get().setAlwaysOnTop(CR.rosterSettings.rosterAlwaysOnTop);
}
function setRosterTimeView()
{
rosterTime.value = CR.rosterSettings.rosterTime;
rosterTimeTd.innerHTML = toDHMS(Number(rosterTime.value));
}
function handleContextMenu(ev)
{
if (editView.style.display == "inline-block") return false;
let mouseX = Math.round(ev.x);
let mouseY = Math.round(ev.y);
let len = Object.keys(CR.blockedCalls).length;
if (len > 0)
{
CR.clearIgnores.enabled = true;
CR.clearIgnores.label =
"Clear Call Ignore" + (len > 1 ? "s (" + len + ")" : "");
CR.clearIgnoresCall.enabled = true;
CR.clearIgnoresCall.label =
"Clear Ignore" + (len > 1 ? "s (" + len + ")" : "");
}
else
{
CR.clearIgnores.label = "Clear Call Ignore";
CR.clearIgnores.enabled = false;
CR.clearIgnoresCall.label = "Clear Ignore";
CR.clearIgnoresCall.enabled = false;
}
len = Object.keys(CR.blockedDxcc).length;
if (len > 0)
{
CR.clearDxccIgnoreMainMenu.enabled = true;
CR.clearDxccIgnoreMainMenu.label =
"Clear DXCC Ignore" + (len > 1 ? "s (" + len + ")" : "");
CR.clearDxccIgnore.enabled = true;
CR.clearDxccIgnore.label =
"Clear Ignore" + (len > 1 ? "s (" + len + ")" : "");
}
else
{
CR.clearDxccIgnoreMainMenu.label = "Clear DXCC Ignore";
CR.clearDxccIgnoreMainMenu.enabled = false;
CR.clearDxccIgnore.label = "Clear Ignore";
CR.clearDxccIgnore.enabled = false;
}
len = Object.keys(CR.blockedCQ).length;
if (len > 0)
{
CR.clearCQIgnoreMainMenu.enabled = true;
CR.clearCQIgnoreMainMenu.label =
"Clear CQ Ignore" + (len > 1 ? "s (" + len + ")" : "");
CR.clearCQIgnore.enabled = true;
CR.clearCQIgnore.label = "Clear Ignore" + (len > 1 ? "s (" + len + ")" : "");
}
else
{
CR.clearCQIgnoreMainMenu.label = "Clear CQ Ignore";
CR.clearCQIgnoreMainMenu.enabled = false;
CR.clearCQIgnore.label = "Clear Ignore";
CR.clearCQIgnore.enabled = false;
}
len = Object.keys(CR.blockedCQz).length;
if (len > 0)
{
CR.clearCQzIgnoreMainMenu.enabled = true;
CR.clearCQzIgnoreMainMenu.label =
"Clear CQ Zone Ignore" + (len > 1 ? "s (" + len + ")" : "");
CR.clearCQzIgnore.enabled = true;
CR.clearCQzIgnore.label = "Clear Ignore" + (len > 1 ? "s (" + len + ")" : "");
}
else
{
CR.clearCQzIgnoreMainMenu.label = "Clear CQ Zone Ignore";
CR.clearCQzIgnoreMainMenu.enabled = false;
CR.clearCQzIgnore.label = "Clear Ignore";
CR.clearCQzIgnore.enabled = false;
}
len = Object.keys(CR.blockedITUz).length;
if (len > 0)
{
CR.clearITUzIgnoreMainMenu.enabled = true;
CR.clearITUzIgnoreMainMenu.label =
"Clear ITU Zone Ignore" + (len > 1 ? "s (" + len + ")" : "");
CR.clearITUzIgnore.enabled = true;
CR.clearITUzIgnore.label = "Clear Ignore" + (len > 1 ? "s (" + len + ")" : "");
}
else
{
CR.clearITUzIgnoreMainMenu.label = "Clear ITU Zone Ignore";
CR.clearITUzIgnoreMainMenu.enabled = false;
CR.clearITUzIgnore.label = "Clear Ignore";
CR.clearITUzIgnore.enabled = false;
}
if (typeof ev.target != "undefined")
{
if (CR.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;
}
}
let name = "";
if (ev.target.tagName == "TD" || (CR.rosterSettings.compact && ev.target.tagName == "DIV"))
{
name = ev.target.getAttribute("name");
}
if (name == "Callsign")
{
CR.targetHash = ev.target.parentNode.id;
CR.callMenu.popup(mouseX, mouseY);
}
else if (name == "Calling")
{
CR.targetHash = ev.target.parentNode.id;
CR.callingMenu.popup(mouseX, mouseY);
}
else if (name == "CQ")
{
if (CR.callRoster[ev.target.parentNode.id].DXcall != "CQ")
{
CR.targetCQ = ev.target.parentNode.id;
CR.CQMenu.popup(mouseX, mouseY);
}
}
else if (name == "CQz")
{
CR.targetCQz = ev.target.parentNode.id;
CR.CQzMenu.popup(mouseX, mouseY);
}
else if (name == "ITUz")
{
CR.targetITUz = ev.target.parentNode.id;
CR.ITUzMenu.popup(mouseX, mouseY);
}
else if (name && name.startsWith("DXCC"))
{
let dxcca = name.split("(");
let dxcc = parseInt(dxcca[1]);
CR.targetDxcc = dxcc;
CR.dxccMenu.popup(mouseX, mouseY);
}
else
{
if (CR.rosterSettings.compact)
{
CR.compactMenu.popup(mouseX, mouseY);
}
else
{
if (ev.target.tagName == "TH" && ev.target.getAttribute("name"))
{
CR.menuItemForCurrentColumn.enabled = true;
CR.currentColumnName = ev.target.getAttribute("name");
}
else
{
CR.menuItemForCurrentColumn.enabled = false;
CR.currentColumnName = null;
}
CR.menu.popup(mouseX, mouseY);
}
}
}
else
{
if (CR.rosterSettings.compact == false)
{
CR.menu.popup(mouseX, mouseY);
}
else
{
CR.compactMenu.popup(mouseX, mouseY);
}
}
ev.preventDefault();
return false;
}
function getTypeFromMode(mode)
{
if (mode in CR.modes)
{
if (CR.modes[mode] == true) return "Digital";
else if (CR.modes_phone[mode] == true) return "Phone";
}
return "";
}
function testAward(awardName, obj, baseHash)
{
if (
CR.awardTracker[awardName].test.dxcc &&
CR.awardTracker[awardName].rule.dxcc.indexOf(obj.dxcc) == -1
)
{ return false; }
if (
CR.awardTracker[awardName].test.mode &&
CR.awardTracker[awardName].rule.mode.indexOf(obj.mode) == -1
)
{ return false; }
if (
CR.awardTracker[awardName].test.band &&
CR.awardTracker[awardName].rule.band.indexOf(obj.band) == -1
)
{ return false; }
if (
CR.awardTracker[awardName].test.DEcall &&
CR.awardTracker[awardName].rule.call.indexOf(obj.DEcall) == -1
)
{ return false; }
if (
CR.awardTracker[awardName].test.cont &&
CR.awardTracker[awardName].rule.cont.indexOf(obj.cont) == -1
)
{ return false; }
if (
CR.awardTracker[awardName].test.prop &&
CR.awardTracker[awardName].rule.propMode != obj.propMode
)
{ return false; }
if (
CR.awardTracker[awardName].test.sat &&
CR.awardTracker[awardName].rule.satName.indexOf(obj.satName) == -1
)
{ return false; }
return CR.awardTypes[CR.awardTracker[awardName].rule.type].test(
CR.awardTracker[awardName],
obj,
baseHash
);
}
function processAward(awardName)
{
let award =
CR.awards[CR.awardTracker[awardName].sponsor].awards[
CR.awardTracker[awardName].name
];
CR.awardTracker[awardName].rule = award.rule;
let test = (CR.awardTracker[awardName].test = {});
let mode = award.rule.mode.slice();
let 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 CR.awards[CR.awardTracker[awardName].sponsor].awards[CR.awardTracker[awardName].name].rule ? CR.awards[CR.awardTracker[awardName].sponsor].awards[CR.awardTracker[awardName].name].rule.qsl_req == "confirmed" : CR.awards[CR.awardTracker[awardName].sponsor].qsl_req == "confirmed";
test.look = "confirmed";
test.qsl_req = "qsl_req" in CR.awards[CR.awardTracker[awardName].sponsor].awards[CR.awardTracker[awardName].name].rule ? CR.awards[CR.awardTracker[awardName].sponsor].awards[CR.awardTracker[awardName].name].rule.qsl_req : CR.awards[CR.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;
CR.awardTracker[awardName].stat = {};
for (const i in window.opener.GT.QSOhash)
{
let obj = window.opener.GT.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;
CR.awardTypes[award.rule.type].score(CR.awardTracker[awardName], obj);
}
CR.awardTracker[awardName].comp = CR.awardTypes[award.rule.type].compile(
CR.awardTracker[awardName],
CR.awardTracker[awardName].stat
);
CR.awardTracker[awardName].stat = {};
}
function newAwardCountObject()
{
let 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()
{
CR.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" }
};
CR.awardTypes.IOTA.score = scoreAIOTA;
CR.awardTypes.call.score = scoreAcall;
CR.awardTypes.callarea.score = scoreAcallarea;
CR.awardTypes.calls2dxcc.score = scoreAcalls2dxcc;
CR.awardTypes.cnty.score = scoreAcnty;
CR.awardTypes.cont.score = scoreAcont;
CR.awardTypes.cont5.score = scoreAcont5;
CR.awardTypes.cont52band.score = scoreAcont52band;
CR.awardTypes.cqz.score = scoreAcqz;
CR.awardTypes.dxcc.score = scoreAdxcc;
CR.awardTypes.grids.score = scoreAgrids;
CR.awardTypes.numsfx.score = scoreAnumsfx;
CR.awardTypes.px.score = scoreApx;
CR.awardTypes.pxa.score = scoreApxa;
CR.awardTypes.pxplus.score = scoreApxplus;
CR.awardTypes.sfx.score = scoreAsfx;
CR.awardTypes.states.score = scoreAstates;
CR.awardTypes.cont2band.score = scoreAcont2band;
CR.awardTypes.calls2band.score = scoreAcalls2band;
CR.awardTypes.dxcc2band.score = scoreAdxcc2band;
CR.awardTypes.states2band.score = scoreAstates2band;
CR.awardTypes.IOTA.test = testAIOTA;
CR.awardTypes.call.test = testAcall;
CR.awardTypes.callarea.test = testAcallarea;
CR.awardTypes.calls2dxcc.test = testAcalls2dxcc;
CR.awardTypes.cnty.test = testAcnty;
CR.awardTypes.cont.test = testAcont;
CR.awardTypes.cont5.test = testAcont5;
CR.awardTypes.cont52band.test = testAcont52band;
CR.awardTypes.cqz.test = testAcqz;
CR.awardTypes.dxcc.test = testAdxcc;
CR.awardTypes.grids.test = testAgrids;
CR.awardTypes.numsfx.test = testAnumsfx;
CR.awardTypes.px.test = testApx;
CR.awardTypes.pxa.test = testApxa;
CR.awardTypes.pxplus.test = testApxplus;
CR.awardTypes.sfx.test = testAsfx;
CR.awardTypes.states.test = testAstates;
CR.awardTypes.cont2band.test = testAcont2band;
CR.awardTypes.calls2band.test = testAcalls2band;
CR.awardTypes.dxcc2band.test = testAdxcc2band;
CR.awardTypes.states2band.test = testAstates;
CR.awardTypes.IOTA.compile = singleCompile;
CR.awardTypes.call.compile = singleCompile;
CR.awardTypes.callarea.compile = singleCompile;
CR.awardTypes.calls2dxcc.compile = doubleCompile;
CR.awardTypes.cnty.compile = singleCompile;
CR.awardTypes.cont.compile = singleCompile;
CR.awardTypes.cont5.compile = singleCompile;
CR.awardTypes.cont52band.compile = doubleCompile;
CR.awardTypes.cqz.compile = singleCompile;
CR.awardTypes.dxcc.compile = singleCompile;
CR.awardTypes.grids.compile = singleCompile;
CR.awardTypes.numsfx.compile = singleCompile;
CR.awardTypes.px.compile = singleCompile;
CR.awardTypes.pxa.compile = singleCompile;
CR.awardTypes.pxplus.compile = singleCompile;
CR.awardTypes.sfx.compile = singleCompile;
CR.awardTypes.states.compile = singleCompile;
CR.awardTypes.cont2band.compile = doubleCompile;
CR.awardTypes.calls2band.compile = doubleCompile;
CR.awardTypes.dxcc2band.compile = doubleCompile;
CR.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)
{
// calls with empty state will not match anything in the hash map. so filter those out
if (!obj.state || obj.state + baseHash in CR.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 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 CR.tracker[award.test.look].dxcc)
{
return false;
}
return true;
}
function scoreAcont(award, obj)
{
if (obj.cont)
{
let 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)
{
let cont = obj.cont;
if (cont == "AN") cont = "OC";
if (cont + baseHash in CR.tracker[award.test.look].cont)
{
return false;
}
}
return true;
}
function scoreAcont5(award, obj, baseHash)
{
if (obj.cont)
{
let 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)
{
let cont = obj.cont;
if (cont == "NA" || cont == "SA") cont = "AM";
if (cont == "AN") cont = "OC";
if (cont + baseHash in CR.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)
{
let cont = obj.cont;
if (cont == "AN") cont = "OC";
if (cont + baseHash in CR.tracker[award.test.look].cont)
{
return false;
}
}
return true;
}
function scoreAcont52band(award, obj)
{
if (obj.cont)
{
let 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)
{
let cont = obj.cont;
if (cont == "NA" || cont == "SA") cont = "AM";
if (cont == "AN") cont = "OC";
if (cont + baseHash in CR.tracker[award.test.look].cont)
{
return false;
}
}
return true;
}
function scoreAgrids(award, obj)
{
if (obj.grid && obj.grid.length > 0)
{
let 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 CR.tracker[award.test.look].grid)
{
return false;
}
if (!obj.grid || obj.grid.length == 0)
{
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 CR.tracker[award.test.look].cnty)
{
return false;
}
return true;
}
function scoreAcall(award, obj)
{
let 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 CR.tracker[award.test.look].call)
{
return false;
}
return true;
}
function scoreAIOTA(award, obj)
{
if (obj.IOTA)
{
let test = CR.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 )
{
let test = CR.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)
{
let test = CR.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)
{
let test = CR.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)
{
let test = CR.awards[award.sponsor].awards[award.name];
let 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)
{
let test = CR.awards[award.sponsor].awards[award.name];
let 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 CR.tracker[award.test.look].px)
{
return false;
}
}
return true;
}
function scoreApxa(award, obj)
{
if (obj.px)
{
let test = CR.awards[award.sponsor].awards[award.name];
for (const 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)
{
let test = CR.awards[award.sponsor].awards[award.name];
for (const i in test.rule.pxa)
{
if (test.rule.pxa[i].indexOf(obj.px) > -1)
{
if (String(obj.px) + baseHash in CR.tracker[award.test.look].px)
{
return false;
}
else
{
return true;
}
}
}
}
return false;
}
function scoreAsfx(award, obj)
{
let test = CR.awards[award.sponsor].awards[award.name];
let suf = obj.DEcall.replace(obj.px, "");
for (const i in test.rule.sfx)
{
for (const 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)
{
let test = CR.awards[award.sponsor].awards[award.name];
let suf = obj.DEcall.replace(obj.px, "");
for (const i in test.rule.sfx)
{
for (const 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 CR.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 CR.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 CR.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)
{
// calls with empty cqz will not match anything in the hash map. so filter those out
if (!obj.cqz || obj.cqz + "|" + baseHash in CR.tracker[award.test.look].cqz)
{
return false;
}
return true;
}
function scoreAnumsfx(award, obj)
{
if (obj.px)
{
let test = CR.awards[award.sponsor].awards[award.name];
let px = obj.px.substr(0, obj.px.length - 1);
let suf = obj.DEcall.replace(px, "");
suf = suf.substr(0, test.rule.numsfx[0][0].length);
for (const i in test.rule.numsfx)
{
for (const 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)
{
if (obj.px)
{
let test = CR.awards[award.sponsor].awards[award.name];
let px = obj.px.substr(0, obj.px.length - 1);
let suf = obj.DEcall.replace(px, "");
suf = suf.substr(0, test.rule.numsfx[0][0].length);
for (const i in test.rule.numsfx)
{
for (const s in test.rule.numsfx[i])
{
if (suf.indexOf(test.rule.numsfx[i][s]) == 0)
{
return false;
}
}
}
}
return true;
}
function scoreApxplus(award, obj)
{
let test = CR.awards[award.sponsor].awards[award.name];
if (test.rule.pxplus)
{
for (const 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)
{
let test = CR.awards[award.sponsor].awards[award.name];
if (test.rule.pxplus)
{
for (const i in test.rule.pxplus)
{
if (obj.DEcall.indexOf(test.rule.pxplus[i]) == 0)
{
return false;
}
}
}
return true;
}
function loadAwardJson()
{
CR.awards = {};
let fs = require("fs");
if (fs.existsSync("./data/awards.json"))
{
fileBuf = fs.readFileSync("./data/awards.json");
try
{
CR.awards = JSON.parse(fileBuf);
// fs.writeFileSync("./data/awards.json", JSON.stringify(CR.awards,null,2));
for (const sp in CR.awards)
{
for (const aw in CR.awards[sp].awards)
{
if (!("unique" in CR.awards[sp].awards[aw].rule))
{ CR.awards[sp].awards[aw].rule.unique = 1; }
if (CR.awards[sp].awards[aw].rule.band[0] == "Mixed")
{
CR.awards[sp].awards[aw].rule.band.shift();
}
if (CR.awards[sp].awards[aw].rule.band.length == 0)
{
CR.awards[sp].awards[aw].rule.band = [];
for (let key in CR.awards[sp].mixed)
{
CR.awards[sp].awards[aw].rule.band.push(CR.awards[sp].mixed[key]);
}
}
if (
CR.awards[sp].awards[aw].rule.endorse.length == 1 &&
CR.awards[sp].awards[aw].rule.endorse[0] == "Mixed"
)
{
CR.awards[sp].awards[aw].rule.endorse = [];
for (let key in CR.awards[sp].mixed)
{
CR.awards[sp].awards[aw].rule.endorse.push(
CR.awards[sp].mixed[key]
);
}
}
}
}
buildAwardTypeHandlers();
}
catch (e)
{
alert("Core awards.json : " + e);
CR.awards = {};
}
}
else alert("Missing core awards.json");
}
function processAllAwardTrackers()
{
for (let tracker in CR.awardTracker)
{
if (!(CR.awardTracker[tracker].sponsor in CR.awards))
{
delete CR.awardTracker[tracker];
continue;
}
if (
!(
CR.awardTracker[tracker].name in
CR.awards[CR.awardTracker[tracker].sponsor].awards
)
)
{
delete CR.awardTracker[tracker];
continue;
}
processAward(tracker);
}
updateAwardList();
}
function newAwardTrackerObject(sponsor, award, enable)
{
let newAward = {};
newAward.sponsor = sponsor;
newAward.name = award;
newAward.enable = enable;
newAward.mode = CR.awards[sponsor].awards[award].rule.mode[0];
newAward.band = CR.awards[sponsor].awards[award].rule.band[0];
newAward.count = CR.awards[sponsor].awards[award].rule.count[0];
newAward.stat = {};
newAward.comp = {};
newAward.test = {};
return newAward;
}
function addAllAwards()
{
for (let sponsor in CR.awards)
{
for (let award in CR.awards[sponsor].awards)
{
let awardToAdd = newAwardTrackerObject(sponsor, award, true);
let hash = awardToAdd.name + "-" + awardToAdd.sponsor;
if (!(hash in CR.awardTracker))
{
CR.awardTracker[hash] = awardToAdd;
processAward(hash);
storeAwardTracker();
}
}
}
updateAwardList();
viewRoster();
}
function delAllAwards()
{
CR.awardTracker = {};
storeAwardTracker();
updateAwardList();
viewRoster();
}
function newCompileCountObject()
{
let compileCountObject = {};
compileCountObject.bands = {};
compileCountObject.modes = {};
compileCountObject.endorse = {};
compileCountObject.counts = {};
return compileCountObject;
}
function singleCompile(award, obj)
{
let test = CR.awards[award.sponsor].awards[award.name];
let rule = test.rule;
let comp = newCompileCountObject();
for (let mode in rule.mode)
{
comp.modes[rule.mode[mode]] = 0;
comp.bands[rule.mode[mode]] = {};
for (let band in rule.band)
{
comp.bands[rule.mode[mode]][rule.band[band]] = 0;
}
for (let 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 (let 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 (let mode in comp.modes)
{
comp.endorse[mode] = {};
comp.counts[mode] = {};
for (let 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 (let endorse in rule.endorse)
{
comp.endorse[mode][rule.endorse[endorse]] = {};
for (let 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)
{
let test = CR.awards[award.sponsor].awards[award.name];
let rule = test.rule;
for (let k in firstLevel)
{
firstLevel[k].bands = {};
// firstLevel[k].modes = {};
let obj = singleCompile(award, firstLevel[k].unique);
for (let mode in obj.bands)
{
for (let cnt in test.rule.count)
{
if (obj.counts[mode][test.rule.count[cnt]].num >= test.rule.unique)
{
for (let 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 ( let 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);
}
function listShortInstances()
{
let shortInstances = [];
if (typeof window.opener.GT.instancesIndex != "undefined" && typeof window.opener.GT.instances != "undefined")
{
if (window.opener.GT.instancesIndex.length > 1)
{
let instances = window.opener.GT.instances;
let keys = Object.keys(instances).sort();
for (let key in keys)
{
let inst = keys[key];
let sp = inst.split(" - ");
let shortInst = sp[sp.length - 1].substring(0, 18);
shortInstances.push(shortInst);
}
}
}
return shortInstances;
}