Merge branch 'master' into cbayer-i18n

merge-requests/182/merge
Christian Bayer 2022-08-06 22:39:24 +02:00
commit 8da135bb6d
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 090D0F8B431A7C88
19 zmienionych plików z 528 dodań i 53 usunięć

Wyświetl plik

@ -107,19 +107,3 @@ Final build results are left in:
# Editing GeoJSON files
We've had success using https://vector.rocks/ and then cleaning up the output with https://jsonformatter.org/
# Hacks
### Roster Column Ordering
We've added internal support for reordering roster columns, but have yet to implement a UI to change these settings.
In the meantime you can:
* Open the roster window, right click on the "More Controls" link on the top right corner and select "Inspect" from the context menu.
* Select the "Console" tab in the Chrome DevTools window that should have appeared.
* Enter `g_rosterSettings.columnOrder` in the Console and press `[return]` to see the current list of columns.
* Enter the following in the Console, changing the values of `columnOrder` to fit your needs: `changeRosterColumnOrder(["Callsign", "Grid", "Spot"]);` and press `[return]`.
Any columns included in this list will be shown before all other columns.

11
debian/changelog vendored
Wyświetl plik

@ -1,3 +1,14 @@
gridtracker (1.22.0725) unstable; urgency=low
- Resolved #9 Call roster columns order can be changed
- Resolved $95 Puts calling/called stations at the top of the call roster if sorting by Wanted
- Resolved #118 Introduce POTA hunting in the call roster
- Resolved #133 Fixes missing CloudLog Station Profile ID
- Resolved #150 Highlights RR73/73 the same as a station calling CQ
- Fixes pattern match for US 1x1 callsigns to match actual FCC rules around them.
- Add WSJT-X/JTDX active instance name to roster window title when operating with multiple instances.
-- Matthew Chambers <nr0q@gridtracker.org> Sun, 24 Jul 2022 19:05:00 -0000
gridtracker (1.22.0503) unstable; urgency=low
- Increment version for build with correct NWJS version

Wyświetl plik

@ -1,6 +1,6 @@
Name: {{{ git_name name=gridtracker }}}
Summary: GridTracker: An amateur radio companion to WSJT-X or JTDX
Version: {{{ git_version lead=1.22.0503 }}}
Version: {{{ git_version lead=1.22.0725 }}}
Release: 1%{?dist}
BuildArch: noarch
Source0: {{{ git_dir_pack }}}
@ -40,6 +40,14 @@ DESTDIR=${RPM_BUILD_ROOT} make clean
%license %{_docdir}/%{name}/
%changelog
* Sun Jul 24 2022 Matthew Chambers <nr0q@gridtracker.org> - 1.22.0725-1
- Resolved #9 Call roster columns order can be changed
- Resolved $95 Puts calling/called stations at the top of the call roster if sorting by Wanted
- Resolved #118 Introduce POTA hunting in the call roster
- Resolved #133 Fixes missing CloudLog Station Profile ID
- Resolved #150 Highlights RR73/73 the same as a station calling CQ
- Fixes pattern match for US 1x1 callsigns to match actual FCC rules around them.
- Add WSJT-X/JTDX active instance name to roster window title when operating with multiple instances.
* Mon May 02 2022 Matthew Chambers <nr0q@gridtracker.org> - 1.22.0503-1
- Increment version number for build with correct vesion of NWJS
* Mon May 02 2022 Matthew Chambers <nr0q@gridtracker.org> - 1.22.0502-1

Wyświetl plik

@ -58,8 +58,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<script src="./lib/jquery.i18n.language.js"></script>
<script src="./lib/shadow.js" type="text/javascript"></script>
<script src="./lib/gtws.js" type="text/javascript"></script>
<script src="./lib/pota.js" type="text/javascript"></script>
<script src="./lib/gt.js" type="text/javascript"></script>
<script src="./lib/screens.js"></script>
<script src="./lib/screens.js" type="text/javascript"></script>
</head>
<body id="mainBody" onload="initialDatabases();">
<div id="startupDiv">
@ -2675,6 +2676,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
size="12"
oninput=" ValidateText(this); adifTextValueChange(this);"
/>
<br />
Station Profile ID<input
id="CloudlogStationProfileID"
type="text"
class="inputTextValue"
size="12"
oninput=" ValidateText(this); adifTextValueChange(this);"
/>
</td>
<td>
<div

Wyświetl plik

@ -165,15 +165,26 @@
<label data-i18n="roster.secondary.wanted.wpx" for="huntPX">WPX</label>
</div>
<div>
<label title="Parks On The Air">
<input type="checkbox" id="huntPOTA" onchange="wantedChanged(this);" /> POTA
</label>
</div>
<div>
<input type="checkbox" id="huntOAMS" onchange="wantedChanged(this);" />
<label data-i18n="roster.secondary.wanted.OAMS" for="huntOAMS" title="Off-Air Message Service Users">OAMS</label>
</div>
<div>
</div>
<div>
<label><input type="checkbox" id="huntCQz" onchange="wantedChanged(this);" /> CQz</label>
</div>
<div>
<label><input type="checkbox" id="huntITUz" onchange="wantedChanged(this);" /> ITUz</label>
</div>
<div>
<label title='CQ DX Marathon'><input type="checkbox" id="huntMarathon" onchange="wantedChanged(this);" /> Marathon</label>
</div>
<div>
<label><input type="checkbox" id="huntState" onchange="wantedChanged(this);" /> State</label>
</div>

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -2670,7 +2670,7 @@ function sendCloudlogEntry(report)
{
if (typeof nw != "undefined")
{
var postData = { key: CloudlogAPI.value, type: "adif", string: report };
var postData = { key: CloudlogAPI.value, station_profile_id: CloudlogStationProfileID.value, type: "adif", string: report };
getPostJSONBuffer(
CloudlogURL.value,
CloudlogSendLogResult,

Wyświetl plik

@ -172,6 +172,7 @@ var def_adifLogSettings = {
HRDLOGUploadCode: "",
CloudlogURL: "http://127.0.0.1/index.php/api/qso",
CloudlogAPI: "",
CloudlogStationProfileID: "1",
eQSLUser: "",
eQSLPassword: "",
eQSLNickname: ""

Wyświetl plik

@ -1065,6 +1065,10 @@ function addDeDx(
finalSatName = ""
)
{
var currentYear = new Date().getFullYear();
var qsoDate = new Date(1970, 0, 1); qsoDate.setSeconds(finalTime);
var isCurrentYear = (qsoDate.getFullYear() == currentYear);
var callsign = null;
var rect = null;
var worked = false;
@ -1262,6 +1266,10 @@ function addDeDx(
g_tracker.worked.cqz[details.cqz + "dg"] = true;
g_tracker.worked.cqz[details.cqz + band + "dg"] = true;
}
if (isCurrentYear)
{
g_tracker.worked.cqz[`${details.cqz}-${currentYear}`] = true;
}
}
if (details.dxcc > 0)
@ -1276,6 +1284,10 @@ function addDeDx(
g_tracker.worked.dxcc[sDXCC + "dg"] = true;
g_tracker.worked.dxcc[sDXCC + band + "dg"] = true;
}
if (isCurrentYear)
{
g_tracker.worked.dxcc[`${sDXCC}-${currentYear}`] = true;
}
}
if (details.px)
@ -6945,7 +6957,6 @@ function handleWsjtxDecode(newMessage)
theTimeStamp =
timeNowSec() - (timeNowSec() % 86400) + parseInt(newMessage.TM / 1000);
var messageColor = "white";
if (CQ == true) messageColor = "cyan";
// Break up the decoded message
var decodeWords = newMessage.Msg.split(" ").slice(0, 5);
@ -6991,6 +7002,7 @@ function handleWsjtxDecode(newMessage)
CQ = true;
msgDXcallsign = "CQ";
}
if (decodeWords.length == 4 && CQ == true)
{
msgDXcallsign += " " + decodeWords[1];
@ -7011,6 +7023,12 @@ function handleWsjtxDecode(newMessage)
msgDEcallsign = decodeWords[1];
}
if (decodeWords[2] == "RR73")
{
CQ = true;
msgDXcallsign = "RR73";
}
var callsign = null;
var hash = msgDEcallsign + newMessage.OB + newMessage.OM;
@ -7079,6 +7097,7 @@ function handleWsjtxDecode(newMessage)
newCallsign.qso = false;
newCallsign.dxcc = callsignToDxcc(newCallsign.DEcall);
newCallsign.px = null;
newCallsign.pota = null;
newCallsign.zone = null;
newCallsign.vucc_grids = [];
newCallsign.propMode = "";
@ -7209,6 +7228,11 @@ function handleWsjtxDecode(newMessage)
}
}
if (g_potaSpots && g_potaSpots.some(item => item.activator === callsign.DEcall))
{
callsign.pota = g_potaSpots.filter(item => item.activator === callsign.DEcall)[0];
}
if (newMessage.NW)
{
didCustomAlert = processAlertMessage(
@ -12763,7 +12787,8 @@ function getBuffer(file_url, callback, flag, mode, port, cache = null)
host: url.parse(file_url).host, // eslint-disable-line node/no-deprecated-api
port: port,
followAllRedirects: true,
path: url.parse(file_url).path // eslint-disable-line node/no-deprecated-api
path: url.parse(file_url).path, // eslint-disable-line node/no-deprecated-api
headers: { "User-Agent": gtVersionString }
};
http.get(options, function (res)
@ -13758,7 +13783,9 @@ var g_startupTable = [
[loadLookupDetails, "Callsign Lookup Details Loaded"],
[startupEventsAndTimers, "Set Events and Timers"],
[registerHotKeys, "Registered Hotkeys"],
[gtChatSystemInit, "User System Initialized"],
[gtChatSystemInit, "Chat System Initialized"],
[getPotaPlaces, "Loading POTA Database"],
[getPotaSpots, "Starting POTA Spots Pump"],
[downloadAcknowledgements, "Contributor Acknowledgements Loaded"],
[postInit, "Finalizing System"]
];

Wyświetl plik

@ -0,0 +1,67 @@
// GridTracker Copyright © 2022 GridTracker.org
// All rights reserved.
// See LICENSE for more information.
var g_potaPlaces = null;
var g_potaSpots = null;
function ingestPotaPlaces(buffer)
{
try
{
g_potaPlaces = JSON.parse(buffer);
}
catch (e)
{
// can't write, somethings broke
}
}
function getPotaPlaces()
{
if (g_mapSettings.offlineMode == false)
{
getBuffer(
"https://storage.googleapis.com/gt_app/pota.json",
ingestPotaPlaces,
null,
"https",
443
);
setTimeout(getPotaPlaces, 86400000)
}
}
function ingestPotaSpots(buffer)
{
try
{
g_potaSpots = JSON.parse(buffer);
}
catch (e)
{
// can't write, somethings broke
}
}
function getPotaSpots()
{
if (g_mapSettings.offlineMode == false && g_spotsEnabled == 1)
{
getBuffer(
"https://api.pota.app/spot/activator",
ingestPotaSpots,
null,
"https",
443
);
setTimeout(getPotaSpots, 300000);
}
}
function g_sendPotaSpot()
{
// if Pota spotting enabled, and we have enough info, send a spot to Pota
}

Wyświetl plik

@ -26,6 +26,8 @@ var g_callMenu = null;
var g_ageMenu = null;
var g_callingMenu = null;
var g_compactMenu = null;
var g_menuItemForCurrentColumn = null;
var g_currentColumnName = null;
var g_targetHash = "";
var g_clearIgnores = null;
var g_clearIgnoresCall = null;
@ -96,10 +98,12 @@ var g_defaultSettings = {
huntDXCC: true,
huntCQz: false,
huntITUz: false,
huntMarathon: false,
huntState: false,
huntCounty: false,
huntCont: false,
huntPX: false,
huntPOTA: false,
huntQRZ: true,
huntOAMS: false
},
@ -112,6 +116,7 @@ var g_defaultSettings = {
Flag: true,
State: true,
County: true,
POTA: false,
Cont: true,
dB: true,
Freq: false,
@ -1704,6 +1709,19 @@ function init()
item = new nw.MenuItem({ type: "separator" });
g_menu.append(item);
g_menuItemForCurrentColumn = new nw.MenuItem({
type: "normal",
label: "Move Column Left",
click: function ()
{
moveColumnLeft(g_currentColumnName);
}
})
g_menu.append(g_menuItemForCurrentColumn)
item = new nw.MenuItem({ type: "separator" });
g_menu.append(item);
for (let columnIndex in g_rosterSettings.columnOrder)
{
let key = g_rosterSettings.columnOrder[columnIndex];
@ -2162,7 +2180,9 @@ function handleContextMenu(ev)
}
}
let name = ev.target.getAttribute("name");
let name
if (ev.target.tagName == "TD") name = ev.target.getAttribute("name");
if (name == "Callsign")
{
g_targetHash = ev.target.parentNode.id;
@ -2200,13 +2220,24 @@ function handleContextMenu(ev)
}
else
{
if (g_rosterSettings.compact == false)
if (g_rosterSettings.compact)
{
g_menu.popup(mouseX, mouseY);
g_compactMenu.popup(mouseX, mouseY);
}
else
{
g_compactMenu.popup(mouseX, mouseY);
if (ev.target.tagName == "TH" && ev.target.getAttribute("name"))
{
g_menuItemForCurrentColumn.enabled = true;
g_currentColumnName = ev.target.getAttribute("name");
}
else
{
g_menuItemForCurrentColumn.enabled = false;
g_currentColumnName = null;
}
g_menu.popup(mouseX, mouseY);
}
}
}
@ -3429,3 +3460,24 @@ function doubleCompile(award, firstLevel)
return singleCompile(award, firstLevel);
}
function listShortInstances()
{
let shortInstances = [];
if (typeof window.opener.g_instancesIndex != "undefined" && typeof window.opener.g_instances != "undefined")
{
if (window.opener.g_instancesIndex.length > 1)
{
let instances = window.opener.g_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;
}

Wyświetl plik

@ -45,6 +45,18 @@ function processRosterFiltering(callRoster, rosterSettings)
entry.tx = false;
continue;
}
if (entry.DXcall == "CQ POTA" && huntPOTA.checked == true)
{
entry.tx = true;
if (callObj.pota == null)
{
callObj.pota = {
reference: "?-????",
name: "Unknown Park"
}
}
continue;
}
if (callObj.ituza in g_blockedITUz)
{
entry.tx = false;
@ -378,6 +390,12 @@ function processRosterFiltering(callRoster, rosterSettings)
}
}
}
if (callObj.shouldAlert == false && rosterSettings.onlyHits == true && callObj.qrz == false)
{
tx = false
}
entry.tx = tx;
}
}

Wyświetl plik

@ -13,6 +13,9 @@ function processRosterHunting(callRoster, rosterSettings)
let layeredUnconf = "background-clip:padding-box;box-shadow: 0 0 4px 2px inset ";
let layeredUnconfAlpha = "AA";
const currentYear = new Date().getFullYear();
const currentYearSuffix = `&rsquo;${currentYear - 2000}`;
// 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?
@ -62,6 +65,7 @@ function processRosterHunting(callRoster, rosterSettings)
callObj.hunting = {}
callObj.callFlags = {}
callObj.style = callObj.style || {}
let colorObject = Object();
@ -76,18 +80,19 @@ function processRosterHunting(callRoster, rosterSettings)
let state = "#90EE90";
let cnty = "#CCDD00";
let cont = "#00DDDD";
let pota = "#fbb6fc";
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;
let callBg, gridBg, callingBg, dxccBg, stateBg, cntyBg, contBg, potaBg, cqzBg, ituzBg, wpxBg, gtBg;
let callConf, gridConf, callingConf, dxccConf, stateConf, cntyConf, contConf, potaConf, cqzConf, ituzConf, wpxConf;
callBg = gridBg = callingBg = dxccBg = stateBg = cntyBg = contBg = cqzBg = ituzBg = wpxBg = gtBg = row;
callBg = gridBg = callingBg = dxccBg = stateBg = cntyBg = contBg = potaBg = cqzBg = ituzBg = wpxBg = gtBg = row;
callConf = gridConf = callingConf = dxccConf = stateConf = cntyConf = contConf = cqzConf = ituzConf = wpxConf =
callConf = gridConf = callingConf = dxccConf = stateConf = cntyConf = contConf = potaConf = cqzConf = ituzConf = wpxConf =
"";
let hash = callsign + workHashSuffix;
@ -138,6 +143,27 @@ function processRosterHunting(callRoster, rosterSettings)
continue;
}
// Special Calls
if (callObj.DEcall.match("^[A-Z][0-9][A-Z](/w+)?$"))
{
callObj.style.call = "class='oneByOne'";
}
// Entries currently calling or being called by us
if (callObj.DEcall == window.opener.g_instances[callObj.instance].status.DXcall)
{
if (window.opener.g_instances[callObj.instance].status.TxEnabled == 1)
{
callObj.hunting.call = "calling";
callObj.style.call = "class='dxCalling'";
}
else
{
callObj.hunting.call = "caller";
callObj.style.call = "class='dxCaller'";
}
}
// Hunting for callsigns
if (huntCallsign.checked == true)
{
@ -202,6 +228,7 @@ function processRosterHunting(callRoster, rosterSettings)
if (huntQRZ.checked == true && callObj.qrz == true)
{
callObj.callFlags.calling = true
callObj.hunting.qrz = "hunted";
shouldAlert = true;
callObj.reason.push("qrz");
}
@ -312,6 +339,27 @@ function processRosterHunting(callRoster, rosterSettings)
}
}
}
callObj.dxccSuffix = null
if (huntMarathon.checked && callObj.hunting.dxcc != "hunted" && callObj.hunting.dxcc != "checked")
{
callObj.reason.push("dxcc-marathon");
let hash = `${callObj.dxcc}-${currentYear}`;
if (rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.dxcc))
{
if (!rosterSettings.workedIndex || !(hash in rosterSettings.workedIndex.dxcc))
{
callObj.dxccSuffix = currentYearSuffix;
callObj.hunting.dxccMarathon = "hunted";
if (!callObj.hunting.dxcc)
{
dxccConf = `${unconf}${dxcc}${layeredAlpha};`;
}
}
}
}
}
// Hunting for US States
@ -427,21 +475,86 @@ function processRosterHunting(callRoster, rosterSettings)
}
}
// Hunting for POTAs
if (huntPOTA.checked == true && window.opener.g_mapSettings.offlineMode == false && callObj.pota != null)
{
let huntTotal = callObj.pota.length;
let huntFound = 0, layeredFound = 0, workedFound = 0, layeredWorkedFound = 0;
for (index in callObj.pota)
{
let hash = callObj.pota[index] + workHashSuffix;
let layeredHash = rosterSettings.layeredMode && (callObj.pota[index] + layeredHashSuffix)
// if (rosterSettings.huntIndex && hash in rosterSettings.huntIndex.pota) layeredFound++;
// if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.pota) layeredFound++;
// if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.pota) workedFound++;
// if (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.pota) layeredWorkedFound++;
}
if (huntFound != huntTotal)
{
shouldAlert = true;
callObj.reason.push("pota");
if (rosterSettings.workedIndex && workedFound == huntTotal)
{
if (rosterSettings.layeredMode && layeredFound == huntTotal)
{
callObj.hunting.pota = "worked-and-mixed";
potaConf = `${layeredUnconf}${pota}${layeredUnconfAlpha};`;
potaBg = `${potaBg}${layeredInversionAlpha}`;
pota = bold;
}
else
{
callObj.hunting.pota = "worked";
potaConf = `${unconf}${pota}${inversionAlpha};`;
}
}
else
{
if (rosterSettings.layeredMode && layeredFound == huntTotal)
{
callObj.hunting.pota = "mixed";
potaBg = `${pota}${layeredAlpha};`;
pota = bold;
}
else if (rosterSettings.layeredMode && layeredWorkedFound == huntTotal)
{
callObj.hunting.pota = "mixed-worked";
potaConf = `${unconf}${pota}${layeredAlpha};`;
}
else
{
callObj.hunting.pota = "hunted";
potaBg = `${pota}${inversionAlpha};`;
pota = bold;
}
}
}
}
// Hunting for CQ Zones
if (huntCQz.checked == true)
{
let huntTotal = callObj.cqza.length;
let huntFound = 0, layeredFound = 0, workedFound = 0, layeredWorkedFound = 0;
let huntFound = 0, layeredFound = 0, workedFound = 0, layeredWorkedFound = 0, marathonFound = 0;
for (index in callObj.cqza)
{
let hash = callObj.cqza[index] + workHashSuffix;
let layeredHash = rosterSettings.layeredMode && (callObj.cqza[index] + layeredHashSuffix)
let layeredHash = rosterSettings.layeredMode && (callObj.cqza[index] + layeredHashSuffix);
let marathonHash = huntMarathon.checked && `${callObj.cqza[index]}-${currentYear}`;
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 (marathonHash)
{
if (rosterSettings.huntIndex && marathonHash in rosterSettings.huntIndex.cqz) marathonFound++;
else if (rosterSettings.workedIndex && marathonHash in rosterSettings.workedIndex.cqz) marathonFound++;
}
}
if (huntFound != huntTotal)
{
@ -484,6 +597,23 @@ function processRosterHunting(callRoster, rosterSettings)
}
}
}
callObj.cqzSuffix = null
if (huntMarathon.checked && callObj.hunting.cqz != "hunted" && callObj.hunting.cqz != "worked")
{
if (marathonFound != huntTotal)
{
callObj.reason.push("cqz-marathon");
callObj.cqzSuffix = currentYearSuffix;
callObj.hunting.cqzMarathon = "hunted";
if (!callObj.hunting.cqz)
{
cqzConf = `${unconf}${cqz}${layeredAlpha};`;
}
}
}
}
// Hunting for ITU Zones
@ -666,6 +796,7 @@ function processRosterHunting(callRoster, rosterSettings)
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.pota = "style='" + potaConf + "background-color:" + potaBg + ";color:" + pota + "'";
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 + "'";

Wyświetl plik

@ -92,14 +92,9 @@ function renderRoster(callRoster, rosterSettings)
}
window.document.title = `Call Roster: ${countParts.join(" • ")}`;
if (g_rosterSettings.compact)
if (listShortInstances().length > 0)
{
sortCallList(visibleCallList, "Age", false);
}
else
{
sortCallList(visibleCallList, g_rosterSettings.sortColumn, g_rosterSettings.sortReverse);
window.document.title += " | " + listShortInstances().join(" • ");
}
let showBands = (Object.keys(rosterSettings.bands).length > 1) || g_rosterSettings.columns.Band;
@ -109,6 +104,15 @@ function renderRoster(callRoster, rosterSettings)
columnOverrides.Mode = showModes
const rosterColumns = rosterColumnList(g_rosterSettings.columns, columnOverrides)
if (g_rosterSettings.compact)
{
sortCallList(visibleCallList, "Age", false, rosterColumns);
}
else
{
sortCallList(visibleCallList, g_rosterSettings.sortColumn, g_rosterSettings.sortReverse);
}
let worker = g_rosterSettings.compact ? renderCompactRosterHeaders() : renderNormalRosterHeaders(rosterColumns)
// Third loop: render all rows
@ -120,7 +124,7 @@ function renderRoster(callRoster, rosterSettings)
if (callObj.shouldAlert == false && rosterSettings.onlyHits == true && callObj.qrz == false)
{ continue; }
if (callObj.DEcall.match("^[A-Z][0-9][A-Z](/w+)?$"))
if (callObj.DEcall.match("^[KNW][0-9][A-W|Y|Z](/w+)?$"))
{ callObj.style.call = "class='oneByOne'"; }
if (callObj.DEcall == window.opener.g_instances[callObj.instance].status.DXcall)
{
@ -138,5 +142,6 @@ function renderRoster(callRoster, rosterSettings)
}
worker += g_rosterSettings.compact ? renderCompactRosterFooter() : renderNormalRosterFooter()
RosterTable.innerHTML = worker;
}

Wyświetl plik

@ -12,6 +12,8 @@ function renderHeaderForColumn(column)
let attrs = (columnInfo && columnInfo.tableHeader && columnInfo.tableHeader()) || {}
attrs.name = column
attrs.html = attrs.html || column
if (columnInfo.compare)
@ -62,11 +64,20 @@ function setRosterSorting(column)
window.opener.goProcessRoster();
}
function sortCallList(callList, sortColumn, sortReverse)
function sortCallList(callList, sortColumn, sortReverse, columns)
{
const columnInfo = ROSTER_COLUMNS[sortColumn]
callList.sort((columnInfo && columnInfo.compare) || ROSTER_COLUMNS.Age.compare)
const comparerList = [
(columnInfo && columnInfo.compare) || ROSTER_COLUMNS.Age.compare,
columns && columns.includes("Spot") && ROSTER_COLUMNS.Spot.compare,
columns && columns.includes("dB") && ROSTER_COLUMNS.dB.compare,
columns && columns.includes("Age") && ROSTER_COLUMNS.Age.compare,
columns && columns.includes("Life") && ROSTER_COLUMNS.Life.compare,
columns && columns.includes("Callsign") && ROSTER_COLUMNS.Callsign.compare
]
callList.sort(multiColumnComparer(comparerList))
if (sortReverse)
{
@ -74,16 +85,36 @@ function sortCallList(callList, sortColumn, sortReverse)
}
}
const multiColumnComparer = (comparers) => (a, b) =>
{
let result = 0;
for (let i in comparers)
{
result = comparers[i] && comparers[i](a, b);
if (result) return result;
}
return 0;
}
function validateRosterColumnOrder(columns)
{
let correctedColumnOrder = (columns || DEFAULT_COLUMN_ORDER || []).slice();
// Aappend columns not included in the suggested list.
DEFAULT_COLUMN_ORDER.forEach(column =>
{
if (!correctedColumnOrder.includes(column)) correctedColumnOrder.push(column);
})
// Exclude any unexpected values
correctedColumnOrder = correctedColumnOrder.filter(column => !!ROSTER_COLUMNS[column])
// Ensure the first three columns are always the same
correctedColumnOrder = correctedColumnOrder.filter(column => column != "Callsign" && column != "Band" && column != "Mode");
correctedColumnOrder.unshift("Mode");
correctedColumnOrder.unshift("Band");
correctedColumnOrder.unshift("Callsign");
return correctedColumnOrder;
}
@ -93,3 +124,15 @@ function changeRosterColumnOrder(columns)
writeRosterSettings();
window.opener.goProcessRoster();
}
function moveColumnLeft(column)
{
const columns = rosterColumnList(g_rosterSettings.columns, { Callsign: true, Grid: true });
const pos = columns.indexOf(column);
if (pos > 1)
{
columns[pos] = columns[pos - 1];
columns[pos - 1] = column;
}
changeRosterColumnOrder(columns);
}

Wyświetl plik

@ -1,6 +1,6 @@
const DEFAULT_COLUMN_ORDER = [
"Callsign", "Band", "Mode", "Grid", "Calling", "Msg",
"DXCC", "Flag", "State", "County", "Cont",
"Callsign", "Band", "Mode", "Calling", "Wanted", "Grid", "Msg",
"POTA", "DXCC", "Flag", "State", "County", "Cont",
"dB", "Freq", "DT", "Dist", "Azim",
"CQz", "ITUz", "PX",
"LoTW", "eQSL", "OQRS",
@ -30,6 +30,7 @@ const getterSimpleComparer = (getter) => (a, b) =>
{
const aVal = getter(a);
const bVal = getter(b);
if (aVal == null) return 1;
if (bVal == null) return -1;
if (aVal > bVal) return 1;
@ -62,7 +63,7 @@ const ROSTER_COLUMNS = {
html: html = callObj.DEcall.formatCallsign()
}
let acks = window.opener.g_acknowledgedCalls;
let acks = window.opener.g_acknowledgedCalls || {};
if (acks[callObj.DEcall])
{
attrs.html = `${attrs.html} <span class='acknowledged'><img class='ackBadge' src='${acks[callObj.DEcall].badge}'></span>`
@ -116,9 +117,9 @@ const ROSTER_COLUMNS = {
compare: (a, b) => window.opener.myDxccCompare(a.callObj, b.callObj),
tableData: (callObj) => ({
title: window.opener.g_worldGeoData[window.opener.g_dxccToGeoData[callObj.dxcc]].pp,
name: `DXCC (${callObj.dxcc})`,
name: `${callObj.dxcc}`,
rawAttrs: callObj.style.dxcc,
html: window.opener.g_dxccToAltName[callObj.dxcc]
html: [window.opener.g_dxccToAltName[callObj.dxcc], callObj.dxccSuffix].join("&nbsp;")
})
},
@ -215,7 +216,7 @@ const ROSTER_COLUMNS = {
tableData: (callObj) => ({
name: "CQz",
rawAttrs: callObj.style.cqz,
html: callObj.cqza.join(",")
html: [callObj.cqza.join(","), callObj.cqzSuffix].join("&nbsp;")
})
},
@ -374,5 +375,104 @@ const ROSTER_COLUMNS = {
id: `sp${callObj.hash}`,
html: getSpotString(callObj)
})
},
POTA: {
compare: false,
tableData: (callObj) => ({
name: "POTA",
rawAttrs: callObj.style.pota,
title: callObj.pota ? callObj.pota.name : "",
html: callObj.pota ? callObj.pota.reference : ""
})
},
Wanted: {
compare: (a, b) => wantedColumnComparer(a.callObj, b.callObj),
tableData: (callObj) => ({
class: "wantedCol",
title: wantedColumnParts(callObj).map(entry => `${entry}`).join("\n"),
html: wantedColumnParts(callObj).join(" - ", { html: true })
})
}
}
WANTED_ORDER = ["call", "qrz", "cont", "dxcc", "cqz", "ituz", "dxccMarathon", "cqzMarathon", "state", "pota", "grid", "cnty", "wpx", "oams"];
WANTED_LABELS = {
cont: "Continent",
cqz: "CQ Zone",
ituz: "ITU Zone",
dxcc: "DXCC",
dxccMarathon: "Marathon DXCC",
cqzMarathon: "Marathon CQ Zone",
state: "State",
grid: "Grid",
cnty: "County",
wpx: "WPX",
call: "Call",
oams: "OAMS",
pota: "POTA"
}
function wantedColumnParts(callObj, options)
{
options = options || {};
if (!callObj.hunting) return [];
let parts = [];
WANTED_ORDER.forEach(field =>
{
let wanted = callObj.hunting[field];
if (wanted == "calling") { parts.push("Calling"); }
// else if (wanted == "caller") { parts.push("Called"); }
else if (wanted == "hunted" && field == "qrz") { parts.push("Caller"); }
else if (wanted == "hunted" && field == "oams") { parts.push("OAMS User"); }
else if (wanted == "hunted") { parts.push(`${options.html ? "<b>" : ""}New ${WANTED_LABELS[field]}${options.html ? "<b>" : ""}`); }
else if (wanted == "worked") { parts.push(`Worked ${WANTED_LABELS[field]}`); }
else if (wanted == "mixed") { parts.push(`${callObj.band} ${WANTED_LABELS[field]}`); }
else if (wanted == "mixed-worked") { parts.push(`${callObj.band} ${WANTED_LABELS[field]}`); parts.push(`Worked ${WANTED_LABELS[field]}`); }
else if (wanted == "worked-and-mixed") { parts.push(`Worked ${callObj.band} ${WANTED_LABELS[field]}`); }
})
if (parts[0] == "Calling" && parts[1] == "Caller")
{
parts.shift(); parts.shift();
parts.unshift(`${options.html ? "<b>" : ""}Working${options.html ? "<b>" : ""}`);
}
return parts;
}
function wantedColumnWeighter(callObj, field)
{
let wanted = callObj.hunting[field];
// We use negative numbers so that sorting is "reversed" by default, placing most interesting items up top.
if (wanted == "calling" || wanted == "caller") return -10;
else if (wanted == "hunted") return -5;
else if (wanted == "worked") return -4;
else if (wanted == "mixed") return -3;
else if (wanted == "mixed-worked") return -2;
else if (wanted == "worked-and-mixed") return -1;
else return 0;
}
function wantedColumnComparer(a, b)
{
if (!a.hunting) return 1;
if (!b.hunting) return -1;
for (const index in WANTED_ORDER)
{
const field = WANTED_ORDER[index];
const aWeight = wantedColumnWeighter(a, field);
const bWeight = wantedColumnWeighter(b, field);
if (aWeight < bWeight) return 1;
if (aWeight > bWeight) return -1;
}
return 0;
}

Wyświetl plik

@ -310,11 +310,11 @@ body.roster {
}
#huntingMatrixDiv {
flex: 0.5;
flex: 0.75;
}
#exceptionDiv {
flex: 1.5;
flex: 1.25;
}
.secondaryControlGroup h3 {
@ -557,4 +557,12 @@ table.rosterTable thead th:first-child {
.ackBadge {
padding: 0;
width: 1.5em;
}
}
.wantedCol {
max-width: 160px;
overflow: hidden;
text-overflow:
ellipsis;
white-space: nowrap;
}

Wyświetl plik

@ -1,10 +1,10 @@
{
"name": "GridTracker",
"product_string_do_not_use": "gridtracker",
"version": "1.22.0503",
"version": "1.22.0725",
"betaVersion": "",
"description": "GridTracker, an amateur radio companion",
"author": "Stephen Loomis (N0TTL) and GridTracker.org",
"author": "GridTracker.org",
"license": "BSD-3-Clause",
"main": "GridTracker.html",
"window": {