Merge branch 'call-roster-refactor' into 'master'

big roster refactor - starting

Closes #107, #91, and #76

See merge request gridtracker.org/gridtracker!139
pipelines/432154651 test_1.21.1212_RollNWJS49
Matthew Chambers 2021-12-16 15:53:20 +00:00
commit 537cd24e0f
29 zmienionych plików z 2575 dodań i 2123 usunięć

2
.gitignore vendored
Wyświetl plik

@ -10,4 +10,4 @@ debian/tmp
.DS_Store .DS_Store
node_modules node_modules
package-lock.json package-lock.json
.vscode .vscode

Wyświetl plik

@ -1,6 +1,7 @@
BSD 3-Clause License BSD 3-Clause License
Copyright (c) 2018-2020 GridTricker.org Copyright (c) 2018-2020 Stephen Tag Loomis
Copyright (c) 2018-2022 GridTricker.org
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

20
debian/changelog vendored
Wyświetl plik

@ -1,6 +1,24 @@
gridtracker (1.21.1212) unstable; urgency=low
Release build with the call roster refactor code that's been in the works for some time.
[Bug Fixes]
- Fix #76, unfinished ignore CQ and ITU zones.
- Improved handling of stations that are not in a valid DXCC (ie; /MM stations)
- Improved handling of free text decodes that don't contain valid callsigns (ie "HI BOB" and "MERRY XMAS")
- Fix how the Call Roster title bar counts are calculated.
[Enhancements]
- More clarity when a ULS Zip code falls in more then one county, replacing ~ with ? symbols and
better tool tip message.
- Fix #107, where the call roster timeout was longer then a single FT4 cycle.
- Fix #91, CQ is always highlighted, no matter status of CQ Only.
- Performance improvement by changing how call roster vars are handled ('let' vs 'var')
- Build system improved to push to Arch AUR, building of Debian (.deb) packages and triggering
of COPR RPM builds for Fedora/Cent/RHEL and their cousins.
-- Matthew Chambers <nr0q@gridtracker.org> Thu, 12 Dec 2021 15:10:00 -0000
gridtracker (1.21.0928) unstable; urgency=medium gridtracker (1.21.0928) unstable; urgency=medium
[Bug Fixes] [Bug Fixes]
- Treat ADIF record values as byte length vs string length (to better handle UTF-8 data). - Treat ADIF record values as byte length vs string length (to better handle UTSF-8 data).
- Remove looking at fetched records for last date for LoTW fetches, Use only headers (More reliable LoTW fetches). - Remove looking at fetched records for last date for LoTW fetches, Use only headers (More reliable LoTW fetches).
[Enhancements] [Enhancements]
- ARM builds now with NWJS 0.54.2 and 64 bit ARM binaries. - ARM builds now with NWJS 0.54.2 and 64 bit ARM binaries.

4
debian/copyright vendored
Wyświetl plik

@ -4,9 +4,9 @@ Upstream-Contact: GridTracker Team <contact@gridtracker.org>
Source: https://gitlab.com/gridtracker.org/gridtracker Source: https://gitlab.com/gridtracker.org/gridtracker
Files: * Files: *
Copyright: Copyright (c) 2018-2020 by Tag Loomis, 2020 by GridTracker.org Copyright: Copyright (c) 2018-2020 by Tag Loomis, 2020-2022 by GridTracker.org
License: BSD-3-clause License: BSD-3-clause
Copyright (c) 2018-2020 GridTricker.org Copyright (c) 2018-2022 GridTricker.org
All rights reserved. All rights reserved.
. .
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

Wyświetl plik

@ -43,7 +43,7 @@ Run gridtracker, no arguments needed.
.SH COPYRIGHT .SH COPYRIGHT
.PP .PP
Copyright (c) 2018-2020 Stephen Tag Loomis. All rights reserved. Copyright (c) 2018-2020 Stephen Tag Loomis. All rights reserved.
Copyright (c) 2020 GridTracker.org. All rights reserved. Copyright (c) 2020-2022 GridTracker.org. All rights reserved.
Released under BSD 3-Clause License Released under BSD 3-Clause License
https://gridtracker.org https://gridtracker.org

Wyświetl plik

@ -40,7 +40,19 @@ DESTDIR=${RPM_BUILD_ROOT} make clean
%license %{_docdir}/%{name}/ %license %{_docdir}/%{name}/
%changelog %changelog
* Sun Dec 13 2021 Matthew Chambers <nr0q@gridtracker.org> - 1.21.1212-1 * Sun Dec 12 2021 Matthew Chambers <nr0q@gridtracker.org> - 1.21.1212-1
- Release with refactored Call Roster code and minor improvements. - Release build with the call roster refactor code that's been in the works for some time.
- [Bug Fixes]
- Fix #76, unfinished ignore CQ and ITU zones.
- Improved handling of stations that are not in a valid DXCC (ie; /MM stations)
- Improved handling of free text decodes that don't contain valid callsigns (ie "HI BOB" and "MERRY XMAS")
- Fix how the Call Roster title bar counts are calculated.
- [Enhancements]
- More clarity when a ULS Zip code falls in more then one county, replacing ~ with ? symbols and better tool tip message.
- Fix #107, where the call roster timeout was longer then a single FT4 cycle.
- Fix #91, CQ is always highlighted, no matter status of CQ Only.
- Performance improvement by changing how call roster vars are handled ('let' vs 'var')
- Build system improved to push to Arch AUR, building of Debian (.deb) packages and triggering
of COPR RPM builds for Fedora/Cent/RHEL and their cousins.
* Thu Sep 30 2021 Matthew Chambers <nr0q@gridtracker.org> - 1.21.0928-1 * Thu Sep 30 2021 Matthew Chambers <nr0q@gridtracker.org> - 1.21.0928-1
- First attempt at repo grade RPM builds - First attempt at repo grade RPM builds

Wyświetl plik

@ -1,6 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<!-- <!--
GridTracker Copyright © 2018-2021 GridTracker.org GridTracker Copyright © 2018-2022 GridTracker.org
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -2893,7 +2893,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<td colspan="2"> <td colspan="2">
<input <input
type="range" type="range"
min="15" min="5"
max="300" max="300"
value="120" value="120"
step="15" step="15"
@ -2905,6 +2905,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</tr> </tr>
</table> </table>
</div> </div>
<div class="mapItem">
<table align="center">
<tr align="center">
<td align="center">Clear Call Roster on Band change</td>
</tr>
<tr align="center">
<td colspan="2">
<input type="checkbox" id="clearRosterOnBandChange" onchange="clearRosterOnBandChangeValueChanged(this);" />
</td>
</tr>
</table>
</div>
<br /> <br />
<div class="mapItem" id="haltTXDiv" style="display: none"> <div class="mapItem" id="haltTXDiv" style="display: none">
<table align="center"> <table align="center">
@ -3526,7 +3538,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
>GridTracker.org!</a >GridTracker.org!</a
> >
</p> </p>
<p>Copyright &copy; 2021 GridTracker.org</p> <p>Copyright &copy; 2022 GridTracker.org</p>
<img src="./gridview.png" /> <br /> <img src="./gridview.png" /> <br />
</div> </div>
</div> </div>

Wyświetl plik

@ -43923,6 +43923,31 @@
"worked_modes": {}, "worked_modes": {},
"confirmed_modes": {} "confirmed_modes": {}
}, },
"390": {
"dxcc": "0",
"cc": "-",
"ccc": "-",
"name": "None",
"continent": "-",
"ituzone": ["-"],
"cqzone": ["-"],
"timezone": "1",
"ccode": "-",
"aname": "None",
"mh": [],
"prefix": [],
"worked": false,
"confirmed": false,
"flag": "un.png",
"pp": "-",
"lat": 0.0,
"lon": 0.0,
"geo": "deleted",
"worked_bands": {},
"confirmed_bands": {},
"worked_modes": {},
"confirmed_modes": {}
},
"-1": { "-1": {
"dxcc": "-1", "dxcc": "-1",
"cc": "-", "cc": "-",

Wyświetl plik

@ -22,6 +22,13 @@
<script src="./lib/protos.js" type="text/javascript"></script> <script src="./lib/protos.js" type="text/javascript"></script>
<script src="./lib/third-party.js" type="text/javascript"></script> <script src="./lib/third-party.js" type="text/javascript"></script>
<script src="./lib/roster.js" type="text/javascript"></script> <script src="./lib/roster.js" type="text/javascript"></script>
<script src="./lib/roster/prepareRosterSettings.js" type="text/javascript"></script>
<script src="./lib/roster/processRosterFiltering.js" type="text/javascript"></script>
<script src="./lib/roster/processRosterHunting.js" type="text/javascript"></script>
<script src="./lib/roster/renderCompactRoster.js" type="text/javascript"></script>
<script src="./lib/roster/renderNormalRoster.js" type="text/javascript"></script>
<script src="./lib/roster/renderRoster.js" type="text/javascript"></script>
<script src="./lib/roster/sendAlerts.js" type="text/javascript"></script>
<script src="./lib/screens.js"></script> <script src="./lib/screens.js"></script>
</head> </head>
<body onload="init()" class="roster" oncontextmenu="return handleContextMenu(event);"> <body onload="init()" class="roster" oncontextmenu="return handleContextMenu(event);">

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -1,4 +1,4 @@
// GridTracker Copyright © 2021 GridTracker.org // GridTracker Copyright © 2022 GridTracker.org
// All rights reserved. // All rights reserved.
// See LICENSE for more information. // See LICENSE for more information.

Wyświetl plik

@ -1,4 +1,4 @@
// GridTracker Copyright © 2021 GridTracker.org // GridTracker Copyright © 2022 GridTracker.org
// All rights reserved. // All rights reserved.
// See LICENSE for more information. // See LICENSE for more information.

Wyświetl plik

@ -1,4 +1,4 @@
// GridTracker Copyright © 2021 GridTracker.org // GridTracker Copyright © 2022 GridTracker.org
// All rights reserved. // All rights reserved.
// See LICENSE for more information. // See LICENSE for more information.

Wyświetl plik

@ -61,6 +61,7 @@ var def_appSettings = {
lookupPasswordQth: "", lookupPasswordQth: "",
lookupService: "CALLOOK", lookupService: "CALLOOK",
lookupCallookPreferred: false, lookupCallookPreferred: false,
clearRosterOnBandChange: false,
moonPath: 0, moonPath: 0,
moonTrack: 0, moonTrack: 0,
mouseTrack: 0, mouseTrack: 0,

Wyświetl plik

@ -1,4 +1,4 @@
// GridTracker Copyright © 2021 GridTracker.org // GridTracker Copyright © 2022 GridTracker.org
// All rights reserved. // All rights reserved.
// See LICENSE for more information. // See LICENSE for more information.
const pjson = require("./package.json"); const pjson = require("./package.json");
@ -12138,7 +12138,7 @@ function callsignToDxcc(insign)
{ {
if (parts[end].toUpperCase() == "MM") if (parts[end].toUpperCase() == "MM")
{ {
return -1; return 0;
} }
parts.pop(); parts.pop();
end = parts.length - 1; end = parts.length - 1;
@ -12962,6 +12962,7 @@ function loadMapSettings()
focusRigValue.checked = g_mapSettings.focusRig; focusRigValue.checked = g_mapSettings.focusRig;
haltAllOnTxValue.checked = g_mapSettings.haltAllOnTx; haltAllOnTxValue.checked = g_mapSettings.haltAllOnTx;
strikesAlert.value = g_mapSettings.strikesAlert; strikesAlert.value = g_mapSettings.strikesAlert;
clearRosterOnBandChange.checked = g_appSettings.clearRosterOnBandChange;
setStrikesButton(); setStrikesButton();
@ -14393,6 +14394,11 @@ function loadLookupDetails()
else lookupCredentials.style.display = "block"; else lookupCredentials.style.display = "block";
} }
function clearRosterOnBandChangeValueChanged(what)
{
g_appSettings.clearRosterOnBandChange = clearRosterOnBandChange.checked;
}
function lookupValueChanged(what) function lookupValueChanged(what)
{ {
if (g_appSettings.lookupService != lookupService.value) if (g_appSettings.lookupService != lookupService.value)

Wyświetl plik

@ -1,4 +1,4 @@
// GridTracker Copyright © 2021 GridTracker.org // GridTracker Copyright © 2022 GridTracker.org
// All rights reserved. // All rights reserved.
// See LICENSE for more information. // See LICENSE for more information.

Wyświetl plik

@ -1,4 +1,4 @@
// GridTracker Copyright © 2021 GridTracker.org // GridTracker Copyright © 2022 GridTracker.org
// All rights reserved. // All rights reserved.
// See LICENSE for more information. // See LICENSE for more information.
@ -141,7 +141,7 @@ Number.prototype.toDHM = function ()
days = days ? days + "d " : ""; days = days ? days + "d " : "";
hrs = hrs ? hrs + "h " : ""; hrs = hrs ? hrs + "h " : "";
mnts = mnts ? mnts + "m " : ""; mnts = mnts || seconds ? mnts + "m " : "";
val = days + hrs + mnts; val = days + hrs + mnts;
return val; return val;
}; };

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,83 @@
function prepareRosterSettings()
{
let rosterSettings = {
bands: {},
modes: {},
callMode: g_rosterSettings.callsign,
onlyHits: false,
isAwardTracker: false,
now: timeNowSec()
}
if (rosterSettings.callMode == "hits")
{
rosterSettings.callMode = "all"
rosterSettings.onlyHits = true;
}
if (referenceNeed.value == LOGBOOK_AWARD_TRACKER)
{
rosterSettings.callMode = "all";
rosterSettings.onlyHits = false;
rosterSettings.isAwardTracker = true;
g_rosterSettings.huntNeed = "confirmed";
}
// this appears to be determine if we should show the OAMS column
// if the user is not in offline mode and has OAMS enabled, this could
// be it's own function maybe?
rosterSettings.canMsg =
window.opener.g_mapSettings.offlineMode == false &&
window.opener.g_appSettings.gtShareEnable == "true" &&
window.opener.g_appSettings.gtMsgEnable == "true";
// The following 3 sections deal with QSLing, do we break them out
// individually or lump them into a qslUser function that sets
// all three at the same time?
// this section is for LoTW users, can be a function
if (window.opener.g_callsignLookups.lotwUseEnable == true)
{
usesLoTWDiv.style.display = "";
if (g_rosterSettings.usesLoTW == true)
{
maxLoTW.style.display = "";
maxLoTWView.style.display = "";
}
else
{
maxLoTW.style.display = "none";
maxLoTWView.style.display = "none";
}
}
else
{
usesLoTWDiv.style.display = "none";
maxLoTW.style.display = "none";
maxLoTWView.style.display = "none";
}
if (g_rosterSettings.huntNeed == "mixed")
{
rosterSettings.huntIndex = g_confirmed;
rosterSettings.workedIndex = g_worked;
rosterSettings.layeredMode = LAYERED_MODE_FOR[String(g_rosterSettings.reference)];
}
else if (g_rosterSettings.huntNeed == "worked")
{
rosterSettings.huntIndex = g_worked;
rosterSettings.workedIndex = false;
rosterSettings.layeredMode = false;
}
else if (g_rosterSettings.huntNeed == "confirmed")
{
rosterSettings.huntIndex = g_confirmed;
rosterSettings.workedIndex = g_worked;
rosterSettings.layeredMode = false;
}
else
{
rosterSettings.huntIndex = false;
rosterSettings.workedIndex = false;
rosterSettings.layeredMode = false;
}
return rosterSettings
}

Wyświetl plik

@ -0,0 +1,384 @@
function processRosterFiltering(callRoster, rosterSettings)
{
// First loop, exclude calls, mostly based on "Exceptions" settings
// this whole section is full of individual if's that could be broken out
for (let callHash in callRoster)
{
let entry = callRoster[callHash];
let callObj = entry.callObj;
let call = entry.DEcall;
entry.tx = true;
callObj.shouldAlert = false;
callObj.reason = Array();
callObj.awardReason = "Callsign";
if (rosterSettings.now - callObj.age > window.opener.g_mapSettings.rosterTime)
{
entry.tx = false;
entry.alerted = false;
callObj.qrz = false;
callObj.reset = true;
continue;
}
if (!callObj.dxcc || callObj.dxcc == -1)
{
entry.tx = false;
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.ituza in g_blockedITUz)
{
entry.tx = false;
continue;
}
if (callObj.cqza in g_blockedCQz)
{
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)
{
let 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 (rosterSettings.callMode != "all")
{
if (entry.DXcall == "CQ DX" && callObj.dxcc == window.opener.g_myDXCC)
{
entry.tx = false;
continue;
}
let hash = hashMaker(call, callObj, g_rosterSettings.reference);
if (rosterSettings.callMode == "worked" && hash in g_worked.call)
{
entry.tx = false;
continue;
}
if (rosterSettings.callMode == "confirmed" && hash in g_confirmed.call)
{
entry.tx = false;
continue;
}
if (g_rosterSettings.hunting == "grid")
{
let hash = hashMaker(callObj.grid.substr(0, 4),
callObj, g_rosterSettings.reference);
if (rosterSettings.huntIndex && hash in rosterSettings.huntIndex.grid)
{
entry.tx = false;
continue;
}
if (callObj.grid.length == 0)
{
entry.tx = false;
continue;
}
continue;
}
if (g_rosterSettings.hunting == "dxcc")
{
let hash = hashMaker(String(callObj.dxcc),
callObj, g_rosterSettings.reference);
if (rosterSettings.huntIndex && (hash in rosterSettings.huntIndex.dxcc))
{
entry.tx = false;
continue;
}
continue;
}
if (callObj.dxcc === -1)
{
entry.tx = false;
continue;
}
if (g_rosterSettings.hunting == "dxccs" && r_currentDXCCs != -1)
{
if (callObj.dxcc != r_currentDXCCs)
{
entry.tx = false;
continue;
}
}
if (g_rosterSettings.hunting == "wpx")
{
if (String(callObj.px) == null)
{
entry.tx = false;
continue;
}
let hash = hashMaker(String(callObj.px),
callObj, g_rosterSettings.reference);
if (rosterSettings.huntIndex && (hash in rosterSettings.huntIndex.px))
{
entry.tx = false;
continue;
}
continue;
}
if (g_rosterSettings.hunting == "cq")
{
let huntTotal = callObj.cqza.length;
if (huntTotal == 0 || !rosterSettings.huntIndex)
{
entry.tx = false;
continue;
}
let huntFound = 0;
for (index in callObj.cqza)
{
let hash = hashMaker(callObj.cqza[index], callObj, g_rosterSettings.reference);
if (hash in rosterSettings.huntIndex.cqz) huntFound++;
}
if (huntFound == huntTotal)
{
entry.tx = false;
continue;
}
continue;
}
if (g_rosterSettings.hunting == "itu")
{
let huntTotal = callObj.ituza.length;
if (huntTotal == 0 || !rosterSettings.huntIndex)
{
entry.tx = false;
continue;
}
let huntFound = 0;
for (index in callObj.ituza)
{
let hash = hashMaker(callObj.ituza[index], callObj, g_rosterSettings.reference);
if (hash in rosterSettings.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)
{
let state = callObj.state;
let finalDxcc = callObj.dxcc;
if (finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6)
{
if (state in window.opener.g_StateData)
{
let hash = hashMaker(state, callObj, g_rosterSettings.reference);
if (rosterSettings.huntIndex && hash in rosterSettings.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 (rosterSettings.isAwardTracker)
{
let tx = false;
let baseHash = hashMaker("", callObj, g_rosterSettings.reference);
for (let award in g_awardTracker)
{
if (g_awardTracker[award].enable)
{
tx = testAward(award, callObj, baseHash);
if (tx)
{
let x = g_awardTracker[award];
// TODO: Move award reason out of exclusions code?
callObj.awardReason =
g_awards[x.sponsor].awards[x.name].tooltip +
" (" +
g_awards[x.sponsor].sponsor +
")";
break;
}
}
}
entry.tx = tx;
}
}
}

Wyświetl plik

@ -0,0 +1,700 @@
function processRosterHunting(callRoster, rosterSettings)
{
// these lets, do they rely on anything between the top and here?
// if not could they be put in the let list at the beginning?
let hasGtPin = false;
let inversionAlpha = "DD";
let row = "#000000";
let bold = "#000000;font-weight: bold;";
let unconf = "background-clip:padding-box;box-shadow: 0 0 7px 3px inset ";
let layeredAlpha = "77";
let layeredInversionAlpha = "66";
let layeredUnconf = "background-clip:padding-box;box-shadow: 0 0 4px 2px inset ";
let layeredUnconfAlpha = "AA";
// TODO: Hunting results might be used to filter, based on the "Callsigns: Only Wanted" option,
// so maybe we can move this loop first, and add a check to the filtering loop?
// Second loop, hunting and highlighting
for (let callHash in callRoster)
{
let entry = callRoster[callHash];
let 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, let it through
// TODO: This is here because it's after the filtering stage
if ((!(entry.DEcall in g_blockedCalls) && !(callObj.dxcc in g_blockedDxcc)) ||
window.opener.g_instances[callObj.instance].status.DXcall == entry.DEcall)
{
entry.tx = true;
}
}
}
// Only render entries with `tx == true`, ignore the rest
if (callObj.dxcc != -1 && entry.tx == true)
{
// In layered mode ("Hunting: mixed") the workHashSuffix becomes a more stricter 'live band',
// while the layered suffix is a broader 'mixed band'
let workHashSuffix, layeredHashSuffix;
if (rosterSettings.layeredMode)
{
workHashSuffix = hashMaker("", callObj, rosterSettings.layeredMode);
layeredHashSuffix = hashMaker("", callObj, g_rosterSettings.reference);
}
else
{
workHashSuffix = hashMaker("", callObj, g_rosterSettings.reference);
layeredHashSuffix = false
}
let workHash = workHashSuffix; // TODO: Remove after replacing all occurrences with Suffix
let callsign = entry.DEcall;
callObj.hunting = {}
callObj.callFlags = {}
let colorObject = Object();
let callPointer = callObj.CQ == true ? "cursor:pointer" : "";
let didWork = false;
let call = "#FFFF00";
let grid = "#00FFFF";
let calling = "#90EE90";
let dxcc = "#FFA500";
let state = "#90EE90";
let cnty = "#CCDD00";
let cont = "#00DDDD";
let cqz = "#DDDDDD";
let ituz = "#DDDDDD";
let wpx = "#FFFF00";
hasGtPin = false;
let shouldAlert = false;
let callBg, gridBg, callingBg, dxccBg, stateBg, cntyBg, contBg, cqzBg, ituzBg, wpxBg, gtBg;
let 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 =
"";
let hash = callsign + workHashSuffix;
let 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 (rosterSettings.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)
{
let hash = callsign + workHashSuffix;
let layeredHash = rosterSettings.layeredMode && (callsign + layeredHashSuffix)
if (rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.call))
{
shouldAlert = true;
callObj.reason.push("call");
if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.call)
{
if (rosterSettings.layeredMode && layeredHash in rosterSettings.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 (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.call)
// {
// callObj.hunting.call = "worked-and-mixed-worked";
// callConf = `${layeredUnconf}${call}${layeredAlpha};`;
// }
else
{
callObj.hunting.call = "worked";
callConf = `${unconf}${call}${inversionAlpha};`;
}
}
else
{
if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.call)
{
callObj.hunting.call = "mixed";
callBg = `${call}${layeredAlpha};`;
call = bold;
}
else if (rosterSettings.layeredMode && layeredHash in rosterSettings.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)
{
let hash = callObj.grid.substr(0, 4) + workHashSuffix;
let layeredHash = rosterSettings.layeredMode && (callObj.grid.substr(0, 4) + layeredHashSuffix)
if (rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.grid))
{
shouldAlert = true;
callObj.reason.push("grid");
if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.grid)
{
if (rosterSettings.layeredMode && layeredHash in rosterSettings.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 (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.grid)
{
callObj.hunting.grid = "mixed";
gridBg = `${grid}${layeredAlpha};`;
grid = bold;
}
else if (rosterSettings.layeredMode && layeredHash in rosterSettings.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)
{
let hash = String(callObj.dxcc) + workHashSuffix;
let layeredHash = rosterSettings.layeredMode && (String(callObj.dxcc) + layeredHashSuffix)
if (rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.dxcc))
{
shouldAlert = true;
callObj.reason.push("dxcc");
if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.dxcc)
{
if (rosterSettings.layeredMode && layeredHash in rosterSettings.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 (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.dxcc)
{
callObj.hunting.dxcc = "mixed";
dxccBg = `${dxcc}${layeredAlpha};`;
dxcc = bold;
}
else if (rosterSettings.layeredMode && layeredHash in rosterSettings.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)
{
let stateSearch = callObj.state;
let finalDxcc = callObj.dxcc;
if (finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6)
{
if (stateSearch in window.opener.g_StateData)
{
let hash = stateSearch + workHashSuffix;
let layeredHash = rosterSettings.layeredMode && (stateSearch + layeredHashSuffix)
if (rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.state))
{
shouldAlert = true;
callObj.reason.push("state");
if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.state)
{
if (rosterSettings.layeredMode && layeredHash in rosterSettings.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 (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.state)
{
callObj.hunting.state = "mixed";
stateBg = `${state}${layeredAlpha};`;
state = bold;
}
else if (rosterSettings.layeredMode && layeredHash in rosterSettings.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)
{
let finalDxcc = callObj.dxcc;
if (
callObj.cnty &&
(finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6 || finalDxcc == 202) &&
callObj.cnty.length > 0
)
{
let hash = callObj.cnty + (rosterSettings.layeredMode ? layeredHashSuffix : workHashSuffix);
if ((rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.cnty)) || callObj.qual == false)
{
if (callObj.qual == false)
{
let counties = window.opener.g_zipToCounty[callObj.zipcode];
let foundHit = false;
for (let cnt in counties)
{
let hh = counties[cnt] + workHash;
callObj.cnty = counties[cnt];
if (rosterSettings.huntIndex && !(hh in rosterSettings.huntIndex.cnty))
{
foundHit = true;
break;
}
}
if (foundHit) shouldAlert = true;
}
else
{
shouldAlert = true;
}
if (shouldAlert)
{
callObj.reason.push("cnty");
if (rosterSettings.workedIndex && hash in rosterSettings.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)
{
let huntTotal = callObj.cqza.length;
let huntFound = 0, layeredFound = 0, workedFound = 0, layeredWorkedFound = 0;
for (index in callObj.cqza)
{
let hash = callObj.cqza[index] + workHashSuffix;
let layeredHash = rosterSettings.layeredMode && (callObj.cqza[index] + layeredHashSuffix)
if (rosterSettings.huntIndex && hash in rosterSettings.huntIndex.cqz) huntFound++;
if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.cqz) layeredFound++;
if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.cqz) workedFound++;
if (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.cqz) layeredWorkedFound++;
}
if (huntFound != huntTotal)
{
shouldAlert = true;
callObj.reason.push("cqz");
if (rosterSettings.workedIndex && workedFound == huntTotal)
{
if (rosterSettings.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 (rosterSettings.layeredMode && layeredFound == huntTotal)
{
callObj.hunting.cqz = "mixed";
cqzBg = `${cqz}${layeredAlpha};`;
cqz = bold;
}
else if (rosterSettings.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)
{
let huntTotal = callObj.ituza.length;
let huntFound = 0, layeredFound = 0, workedFound = 0, layeredWorkedFound = 0;
for (index in callObj.ituza)
{
let hash = callObj.ituza[index] + workHashSuffix;
let layeredHash = rosterSettings.layeredMode && (callObj.ituza[index] + layeredHashSuffix)
if (rosterSettings.huntIndex && hash in rosterSettings.huntIndex.ituz) huntFound++;
if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.ituz) layeredFound++;
if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.ituz) workedFound++;
if (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.ituz) layeredWorkedFound++;
}
if (huntFound != huntTotal)
{
shouldAlert = true;
callObj.reason.push("ituz");
if (rosterSettings.workedIndex && workedFound == huntTotal)
{
if (rosterSettings.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 (rosterSettings.layeredMode && layeredFound == huntTotal)
{
callObj.hunting.ituz = "mixed";
ituzBg = `${ituz}${layeredAlpha};`;
ituz = bold;
}
else if (rosterSettings.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)
{
let hash = String(callObj.px) + workHashSuffix;
let layeredHash = rosterSettings.layeredMode && (String(callObj.px) + layeredHashSuffix)
if (rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.px))
{
shouldAlert = true;
callObj.reason.push("wpx");
if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.px)
{
if (rosterSettings.layeredMode && layeredHash in rosterSettings.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 (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.px)
{
callObj.hunting.wpx = "mixed";
wpxBg = `${wpx}${layeredAlpha};`;
wpx = bold;
}
else if (rosterSettings.layeredMode && layeredHash in rosterSettings.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)
{
let hash = String(callObj.cont) + workHashSuffix;
let layeredHash = rosterSettings.layeredMode && (String(callObj.cont) + layeredHashSuffix)
if (rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.cont))
{
shouldAlert = true;
callObj.reason.push("cont");
if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.cont)
{
if (rosterSettings.layeredMode && layeredHash in rosterSettings.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 (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.cont)
{
callObj.hunting.cont = "mixed";
contBg = `${cont}${layeredAlpha};`;
cont = bold;
}
else if (rosterSettings.layeredMode && layeredHash in rosterSettings.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)
{
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 };
}
rosterSettings.modes[callObj.mode] = true;
rosterSettings.bands[callObj.band] = true;
}
}
}

Wyświetl plik

@ -0,0 +1,55 @@
function renderCompactRosterHeaders()
{
return "<div id=\"buttonsDiv\" style=\"margin-left:0px;white-space:normal;\">";
}
function renderCompactRosterRow(callObj)
{
var thisCall = callObj.DEcall;
var tt =
callObj.RSTsent +
"&#13256;, " +
parseInt(callObj.dt * 100) +
"ms, " +
callObj.delta +
"hz" +
(callObj.grid.length ? ", " + callObj.grid : "") +
", " +
(timeNowSec() - callObj.age).toDHMS();
var worker =
"<div class='compact' onClick='initiateQso(\"" +
thisCall +
callObj.band +
callObj.mode +
"\")' ";
worker +=
"id='" +
thisCall +
callObj.band +
callObj.mode +
"' title='" +
tt +
"'>";
worker +=
"<div class='compactCallsign' name='Callsign' " +
callObj.style.call +
" >" +
thisCall.formatCallsign() +
"</div>";
worker +=
"<div class='compactDXCC' name='DXCC (" +
callObj.dxcc +
")' " +
callObj.style.dxcc +
">" +
window.opener.g_dxccToAltName[callObj.dxcc] +
"</div>";
worker += "</div>";
return worker;
}
function renderCompactRosterFooter()
{
return "</div>";
}

Wyświetl plik

@ -0,0 +1,413 @@
function renderNormalRosterHeaders(showBands, showModes)
{
let worker = ""
worker = "<table id='callTable' class='rosterTable' align=left>";
worker += "<thead><th style='cursor:pointer;' onclick='showRosterBox(0);' align=left>Callsign</th>";
if (showBands)
{ worker += "<th onclick='' >Band</th>"; }
if (showModes)
{ worker += "<th onclick='' >Mode</th>"; }
worker += "<th style='cursor:pointer;' onclick='showRosterBox(1);' >Grid</th>";
if (g_rosterSettings.columns.Calling)
{ worker += "<th style='cursor:pointer;' onclick='showRosterBox(10);' >Calling</th>"; }
if (g_rosterSettings.columns.Msg)
{ worker += "<th >Msg</th>"; }
if (g_rosterSettings.columns.DXCC)
{ worker += "<th style='cursor:pointer;' onclick='showRosterBox(5);' >DXCC</th>"; }
if (g_rosterSettings.columns.Flag)
{ worker += "<th style='cursor:pointer;' onclick='showRosterBox(5);' >Flag</th>"; }
if (g_rosterSettings.columns.State)
{ worker += "<th style='cursor:pointer;' onclick='showRosterBox(9);' >State</th>"; }
if (g_rosterSettings.columns.County)
{ worker += "<th style='cursor:pointer;' onclick='showRosterBox(15);' >County</th>"; }
if (g_rosterSettings.columns.Cont)
{ worker += "<th style='cursor:pointer;' onclick='showRosterBox(16);' >Cont</th>"; }
if (g_rosterSettings.columns.dB)
{ worker += "<th style='cursor:pointer;' onclick='showRosterBox(2);' >dB</th>"; }
if (g_rosterSettings.columns.Freq)
{ worker += "<th style='cursor:pointer;' onclick='showRosterBox(4);' >Freq</th>"; }
if (g_rosterSettings.columns.DT)
{ worker += "<th style='cursor:pointer;' onclick='showRosterBox(3);' >DT</th>"; }
if (g_rosterSettings.columns.Dist)
{
worker += "<th style='cursor:pointer;' onclick='showRosterBox(7);' >Dist(" +
window.opener.distanceUnit.value.toLowerCase() + ")</th>";
}
if (g_rosterSettings.columns.Azim)
{ worker += "<th style='cursor:pointer;' onclick='showRosterBox(8);' >Azim</th>"; }
if (g_rosterSettings.columns.CQz)
{ worker += "<th>CQz</th>"; }
if (g_rosterSettings.columns.ITUz)
{ worker += "<th>ITUz</th>"; }
if (g_rosterSettings.columns.PX)
{ worker += "<th style='cursor:pointer;' onclick='showRosterBox(11);'>PX</th>"; }
if (window.opener.g_callsignLookups.lotwUseEnable == true && g_rosterSettings.columns.LoTW)
{ worker += "<th >LoTW</th>"; }
if (window.opener.g_callsignLookups.eqslUseEnable == true && g_rosterSettings.columns.eQSL)
{ worker += "<th >eQSL</th>"; }
if (window.opener.g_callsignLookups.oqrsUseEnable == true && g_rosterSettings.columns.OQRS)
{ worker += "<th >OQRS</th>"; }
if (g_rosterSettings.columns.Spot)
{ worker += "<th style='cursor:pointer;' onclick='showRosterBox(13);' >Spot</th>"; }
if (g_rosterSettings.columns.Life)
{ worker += "<th style='cursor:pointer;' onclick='showRosterBox(12);' >Life</th>"; }
if (g_rosterSettings.columns.OAMS)
{ worker += "<th title='Off-Air Message User' style='cursor:pointer;' onclick='showRosterBox(14);'>OAMS</th>"; }
if (g_rosterSettings.columns.Age)
{ worker += "<th style='cursor:pointer;' onclick='showRosterBox(6);' >Age</th></thead>"; }
return worker
}
function renderNormalRosterRow(callObj, showBands, showModes)
{
let thisCall = callObj.DEcall;
let acks = window.opener.g_acknowledgedCalls;
let grid = callObj.grid.length > 1 ? callObj.grid.substr(0, 4) : "-";
let geo = window.opener.g_worldGeoData[window.opener.g_dxccToGeoData[callObj.dxcc]];
let cqzone = grid in window.opener.g_gridToCQZone ? window.opener.g_gridToCQZone[grid].join(", ") : "-";
let ituzone = grid in window.opener.g_gridToITUZone ? window.opener.g_gridToITUZone[grid].join(", ") : "-";
let spotString = "";
if (g_rosterSettings.columns.Spot && callObj.qrz == false)
{
spotString = getSpotString(callObj);
}
let thisHash = thisCall + callObj.band + callObj.mode;
let callStr = thisCall.formatCallsign()
if (acks[thisCall])
{
callStr = `${callStr} <span class='acknowledged'><img class='ackBadge' src='${acks[thisCall].badge}'></span>`
callObj.awardReason += ` - ${acks[thisCall].message}`
}
let worker = "<tbody><tr id='" + thisHash + "'>";
worker +=
"<td title='" +
callObj.awardReason +
"' name='Callsign' align=left " +
callObj.style.call +
" onClick='initiateQso(\"" +
thisCall +
callObj.band +
callObj.mode +
"\")'>" +
callStr +
"</td>";
if (showBands)
{
worker +=
"<td style='color:#" +
window.opener.g_pskColors[callObj.band] +
"' >" +
callObj.band +
"</td>";
}
if (showModes)
{
let color = "888888";
if (callObj.mode in g_modeColors)
{ color = g_modeColors[callObj.mode]; }
worker +=
"<td style='color:#" + color + "' >" + callObj.mode + "</td>";
}
worker +=
"<td " +
callObj.style.grid +
" onClick='centerOn(\"" +
grid +
"\")' >" +
grid +
"</td>";
if (g_rosterSettings.columns.Calling)
{
let lookString = callObj.CQ ? "name='CQ'" : "name='Calling'";
worker +=
"<td " +
callObj.style.calling +
" " +
lookString +
">" +
callObj.DXcall.formatCallsign() +
"</td>";
}
if (g_rosterSettings.columns.Msg)
{ worker += "<td>" + callObj.msg + "</td>"; }
if (g_rosterSettings.columns.DXCC)
{
worker +=
"<td title='" + window.opener.g_worldGeoData[window.opener.g_dxccToGeoData[callObj.dxcc]].pp +
"' name='DXCC (" +
callObj.dxcc +
")' " +
callObj.style.dxcc +
">" +
window.opener.g_dxccToAltName[callObj.dxcc] + "</td>";
}
if (g_rosterSettings.columns.Flag)
{
worker +=
"<td align='center' style='margin:0;padding:0'><img style='padding-top:3px' src='./img/flags/16/" +
geo.flag +
"'></td>";
}
if (g_rosterSettings.columns.State)
{
worker +=
"<td align='center' " +
callObj.style.state +
" >" +
(callObj.state ? callObj.state.substr(3) : "") +
"</td>";
}
if (g_rosterSettings.columns.County)
{
worker +=
"<td align='center' " +
callObj.style.cnty +
" " +
(callObj.cnty
? (callObj.qual
? ""
: "title='ZIP Code matches multiple counties, click to do a full lookup' " +
"onClick='window.opener.lookupCallsign(\"" +
thisCall +
"\",\"" +
grid +
"\")'"
)
: "") +
">" +
(callObj.cnty
? (callObj.qual ? "" : "¿ ") +
window.opener.g_cntyToCounty[callObj.cnty] +
(callObj.qual ? "" : " ?")
: "") +
"</td>";
}
if (g_rosterSettings.columns.Cont)
{
worker +=
"<td align='center' " +
callObj.style.cont +
" >" +
(callObj.cont ? callObj.cont : "") +
"</td>";
}
if (g_rosterSettings.columns.dB)
{
worker +=
"<td style='color:#DD44DD'><b>" +
callObj.RSTsent +
"</b></td>";
}
if (g_rosterSettings.columns.Freq)
{ worker += "<td style='color:#00FF00'>" + callObj.delta + "</td>"; }
if (g_rosterSettings.columns.DT)
{ worker += "<td style='color:#1E90FF'>" + callObj.dt + "</td>"; }
if (g_rosterSettings.columns.Dist)
{
worker +=
"<td style='color:cyan'>" +
parseInt(
callObj.distance *
MyCircle.validateRadius(window.opener.distanceUnit.value)
) +
"</td>";
}
if (g_rosterSettings.columns.Azim)
{
worker +=
"<td style='color:yellow'>" +
parseInt(callObj.heading) +
"</td>";
}
if (g_rosterSettings.columns.CQz)
{
worker +=
"<td name='CQz' " +
callObj.style.cqz +
">" +
callObj.cqza.join(",") +
"</td>";
}
if (g_rosterSettings.columns.ITUz)
{
worker +=
"<td name='ITUz'" +
callObj.style.ituz +
">" +
callObj.ituza.join(",") +
"</td>";
}
if (g_rosterSettings.columns.PX)
{
worker +=
"<td " +
callObj.style.px +
">" +
(callObj.px ? callObj.px : "") +
"</td>";
}
if (
window.opener.g_callsignLookups.lotwUseEnable == true &&
g_rosterSettings.columns.LoTW
)
{
if (thisCall in window.opener.g_lotwCallsigns)
{
if (g_rosterSettings.maxLoTW < 27)
{
let months = (g_day - window.opener.g_lotwCallsigns[thisCall]) / 30;
if (months > g_rosterSettings.maxLoTW)
{
worker +=
"<td style='color:yellow' align='center' title='Has not uploaded a QSO in " +
Number(months).toYM() +
"'>?</td>";
}
else
{
worker +=
"<td style='color:#0F0' align='center' title=' Last Upload&#10;" +
window.opener.userDayString(
window.opener.g_lotwCallsigns[thisCall] * 86400000
) +
"'>&#10004;</td>";
}
}
else
{
worker +=
"<td style='color:#0F0' align='center' title=' Last Upload&#10;" +
window.opener.userDayString(
window.opener.g_lotwCallsigns[thisCall] * 86400000
) +
"'>&#10004;</td>";
}
}
else worker += "<td></td>";
}
if (
window.opener.g_callsignLookups.eqslUseEnable == true &&
g_rosterSettings.columns.eQSL
)
{
worker +=
"<td style='color:#0F0;' align='center'>" +
(thisCall in window.opener.g_eqslCallsigns ? "&#10004;" : "") +
"</td>";
}
if (
window.opener.g_callsignLookups.oqrsUseEnable == true &&
g_rosterSettings.columns.OQRS
)
{
worker +=
"<td style='color:#0F0;' align='center'>" +
(thisCall in window.opener.g_oqrsCallsigns ? "&#10004;" : "") +
"</td>";
}
if (g_rosterSettings.columns.Spot)
{
worker +=
"<td style='color:#EEE;' class='spotCol' id='sp" +
thisCall +
callObj.band +
callObj.mode +
"'>" +
spotString +
"</td>";
}
if (g_rosterSettings.columns.Life)
{
worker +=
"<td style='color:#EEE;' class='lifeCol' id='lm" +
thisCall +
callObj.band +
callObj.mode +
"'>" +
(timeNowSec() - callObj.life).toDHMS() +
"</td>";
}
if (g_rosterSettings.columns.OAMS)
{
if (callObj.style.gt != 0)
{
if (callObj.reason.includes("oams"))
{
worker +=
"<td align='center' style='margin:0;padding:0;cursor:pointer;background-clip:content-box;box-shadow: 0 0 4px 4px inset #2222FFFF;' onClick='openChatToCid(\"" +
callObj.style.gt +
"\")'><img height='16px' style='' src='./img/gt_chat.png'></td>";
}
else
{
worker +=
"<td align='center' style='margin:0;padding:0;cursor:pointer;' onClick='openChatToCid(\"" +
callObj.style.gt +
"\")'><img height='16px' style='' src='./img/gt_chat.png'></td>";
}
}
else worker += "<td></td>";
}
if (g_rosterSettings.columns.Age)
{
worker +=
"<td style='color:#EEE' class='timeCol' id='tm" +
thisCall +
callObj.band +
callObj.mode +
"'>" +
(timeNowSec() - callObj.age).toDHMS() +
"</td>";
}
worker += "</tr></tbody>";
return worker;
}
function renderNormalRosterFooter()
{
return "</table>";
}

Wyświetl plik

@ -0,0 +1,119 @@
function renderRoster(callRoster, rosterSettings)
{
// eQSL - function
if (window.opener.g_callsignLookups.eqslUseEnable == true) useseQSLDiv.style.display = "";
else useseQSLDiv.style.display = "none";
// OQRS - function
if (window.opener.g_callsignLookups.oqrsUseEnable == true) usesOQRSDiv.style.display = "";
else usesOQRSDiv.style.display = "none";
// dealing with spots
if (g_rosterSettings.columns.Spot == true) onlySpotDiv.style.display = "";
else onlySpotDiv.style.display = "none";
// callmode (all or only new)
if (rosterSettings.callMode == "all") allOnlyNewDiv.style.display = "";
else allOnlyNewDiv.style.display = "none";
// Show the roster count in the window title
// let visibleCallList = callRoster.filter(entry => entry.tx);
let visibleCallList = [];
let band =
window.opener.g_appSettings.gtBandFilter == "auto"
? window.opener.g_appSettings.myBand
: window.opener.g_appSettings.gtBandFilter.length == 0
? ""
: window.opener.g_appSettings.gtBandFilter;
for (entry in callRoster)
{
// entry should populate in general
if (callRoster[entry].tx)
{
// check setting for call roster clear on band change.
// if true and band is current band, populate
if (window.opener.g_appSettings.clearRosterOnBandChange)
{
if (callRoster[entry].callObj.band == band)
{
visibleCallList.push(callRoster[entry]);
}
}
else if (!window.opener.g_appSettings.clearRosterOnBandChange)
{
visibleCallList.push(callRoster[entry]);
}
}
}
let totalCount = Object.keys(callRoster).length;
let visibleCount = visibleCallList.length;
let huntedCount = visibleCallList.filter(obj => Object.keys(obj.callObj.hunting).length > 0).length
let countParts = [];
if (totalCount != visibleCount)
{
countParts.push(`${totalCount} heard`);
}
countParts.push(`${visibleCount} in roster`);
if (huntedCount != visibleCount)
{
countParts.push(`${huntedCount} wanted`);
}
window.document.title = `Call Roster: ${countParts.join(" • ")}`;
if (g_rosterSettings.compact == false)
{
visibleCallList.sort(r_sortFunction[g_rosterSettings.lastSortIndex]);
if (g_rosterSettings.lastSortReverse == 1)
{
visibleCallList.reverse();
}
}
else
{
// Age sort for now... make this happen Tag
visibleCallList.sort(r_sortFunction[6]).reverse();
}
let showBands = (Object.keys(rosterSettings.bands).length > 1) || g_rosterSettings.columns.Band;
let showModes = (Object.keys(rosterSettings.modes).length > 1) || g_rosterSettings.columns.Mode;
let worker = g_rosterSettings.compact ? renderCompactRosterHeaders() : renderNormalRosterHeaders(showBands, showModes)
// Third loop: render all rows
for (let x in visibleCallList)
{
let callObj = visibleCallList[x].callObj;
// TODO: This is filtering
if (callObj.shouldAlert == false && rosterSettings.onlyHits == true && callObj.qrz == false)
{ continue; }
let thisCall = callObj.DEcall;
if (thisCall.match("^[A-Z][0-9][A-Z](/w+)?$"))
{ callObj.style.call = "class='oneByOne'"; }
if (thisCall == window.opener.g_instances[callObj.instance].status.DXcall)
{
if (window.opener.g_instances[callObj.instance].status.TxEnabled == 1)
{
callObj.style.call = "class='dxCalling'";
}
else
{
callObj.style.call = "class='dxCaller'";
}
}
worker += g_rosterSettings.compact ? renderCompactRosterRow(callObj) : renderNormalRosterRow(callObj, showBands, showModes)
}
worker += g_rosterSettings.compact ? renderCompactRosterFooter() : renderNormalRosterFooter()
RosterTable.innerHTML = worker;
}

Wyświetl plik

@ -0,0 +1,140 @@
function sendAlerts(callRoster, rosterSettings)
{
var dirPath = window.opener.g_scriptDir;
var scriptExists = false;
var script = "cr-alert.sh";
var shouldAlert = 0;
for (entry in callRoster)
{
var callObj = callRoster[entry].callObj;
// chrbayer: what does the tx field mean? no alerts are generated (at all) if this is in place...
// if (!callObj.tx) continue;
// TODO: Get rid of realtime
if (g_rosterSettings.realtime == false)
{
var call = callObj.DEcall;
g_scriptReport[call] = Object.assign({}, callObj);
g_scriptReport[call].dxccName =
window.opener.g_dxccToAltName[callObj.dxcc];
g_scriptReport[call].distance = parseInt(
callObj.distance *
MyCircle.validateRadius(window.opener.distanceUnit.value)
);
delete g_scriptReport[call].DEcall;
g_scriptReport[call].rect = null;
delete g_scriptReport[call].rect;
delete g_scriptReport[call].style;
delete g_scriptReport[call].wspr;
delete g_scriptReport[call].qso;
delete g_scriptReport[call].instance;
if (rosterSettings.callMode != "all")
{
g_scriptReport[call].shouldAlert = true;
g_scriptReport[call].reason.push(g_rosterSettings.hunting);
}
}
if (
callObj.alerted == false &&
rosterSettings.callMode == "all" &&
callObj.shouldAlert == true
)
{
callObj.alerted = true;
shouldAlert++;
}
else if (callObj.alerted == false && rosterSettings.callMode != "all")
{
callObj.alerted = true;
shouldAlert++;
}
callObj.shouldAlert = false;
}
// NOTE: Ring alerts if needed
try
{
if (fs.existsSync(dirPath))
{
if (window.opener.g_platform == "windows")
{
script = "cr-alert.bat";
}
if (
fs.existsSync(dirPath + script) &&
g_rosterSettings.realtime == false
)
{
scriptExists = true;
scriptIcon.innerHTML =
"<div class='buttonScript' onclick='window.opener.toggleCRScript();'>" +
(window.opener.g_crScript == 1
? "<font color='lightgreen'>Script Enabled</font>"
: "<font color='yellow'>Script Disabled</font>") +
"</div>";
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();
}
}

Wyświetl plik

@ -1,4 +1,4 @@
// GridTracker Copyright © 2021 GridTracker.org // GridTracker Copyright © 2022 GridTracker.org
// All rights reserved. // All rights reserved.
// See LICENSE for more information. // See LICENSE for more information.

Wyświetl plik

@ -1,7 +1,7 @@
{ {
"name": "GridTracker", "name": "GridTracker",
"product_string_do_not_use": "gridtracker", "product_string_do_not_use": "gridtracker",
"version": "1.21.0928", "version": "1.21.1212",
"betaVersion": "", "betaVersion": "",
"description": "GridTracker, an amateur radio companion", "description": "GridTracker, an amateur radio companion",
"author": "Stephen Loomis (N0TTL) and GridTracker.org", "author": "Stephen Loomis (N0TTL) and GridTracker.org",
@ -31,7 +31,7 @@
], ],
"mac": { "mac": {
"icon": "gridview.icns", "icon": "gridview.icns",
"copyright": "Copyright (c) 2021 GridTracker.org", "copyright": "Copyright (c) 2022 GridTracker.org",
"plistStrings": { "plistStrings": {
"CFBundleIdentifier": "org.gridtracker.gridtracker", "CFBundleIdentifier": "org.gridtracker.gridtracker",
"CFBundleDocumentTypes": [] "CFBundleDocumentTypes": []
@ -39,7 +39,7 @@
}, },
"win": { "win": {
"icon": "gridview.ico", "icon": "gridview.ico",
"copyright": "Copyright (c) 2021 GridTracker.org" "copyright": "Copyright (c) 2022 GridTracker.org"
}, },
"nsis": { "nsis": {
"installDirectory": "$PROGRAMFILES\\${_APPNAME}", "installDirectory": "$PROGRAMFILES\\${_APPNAME}",

Wyświetl plik

@ -65,7 +65,7 @@ VIAddVersionKey CompanyName "${COMPANY}"
VIAddVersionKey CompanyWebsite "${URL}" VIAddVersionKey CompanyWebsite "${URL}"
VIAddVersionKey FileVersion "${VERSION}" VIAddVersionKey FileVersion "${VERSION}"
VIAddVersionKey FileDescription "An Amateur Radio Community" VIAddVersionKey FileDescription "An Amateur Radio Community"
VIAddVersionKey LegalCopyright "2021 Gridtracker.org" VIAddVersionKey LegalCopyright "2022 Gridtracker.org"
InstallDirRegKey HKLM "${REGKEY}" Path InstallDirRegKey HKLM "${REGKEY}" Path
ShowUninstDetails nevershow ShowUninstDetails nevershow