kopia lustrzana https://gitlab.com/gridtracker.org/gridtracker
Refactor roster columns
rodzic
797ac6859c
commit
c54252a805
16
README.md
16
README.md
|
@ -107,3 +107,19 @@ 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.
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
<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/rosterColumns.js" type="text/javascript"></script>
|
||||
<script src="./lib/roster/rosterColumnFunctions.js" type="text/javascript"></script>
|
||||
<script src="./lib/roster/sendAlerts.js" type="text/javascript"></script>
|
||||
<script src="./lib/screens.js"></script>
|
||||
</head>
|
||||
|
|
|
@ -1092,7 +1092,11 @@ function addDeDx(
|
|||
details.grid.length < 6 &&
|
||||
(details.grid.substr(0, 4) == finalGrid.substr(0, 4) ||
|
||||
details.grid.length == 0)
|
||||
) { details.grid = finalGrid; }
|
||||
)
|
||||
{
|
||||
details.grid = finalGrid;
|
||||
details.grid4 = finalGrid.substr(0, 4);
|
||||
}
|
||||
}
|
||||
if (finalRSTsent.length > 0) details.RSTsent = finalRSTsent;
|
||||
if (finalRSTrecv.length > 0) details.RSTrecv = finalRSTrecv;
|
||||
|
@ -1112,6 +1116,7 @@ function addDeDx(
|
|||
{
|
||||
details = {};
|
||||
details.grid = finalGrid;
|
||||
details.grid4 = finalGrid.length > 0 ? finalGrid.substr(0, 4) : "-";
|
||||
details.RSTsent = finalRSTsent;
|
||||
details.RSTrecv = finalRSTrecv;
|
||||
details.msg = "-";
|
||||
|
@ -1153,10 +1158,9 @@ function addDeDx(
|
|||
finalGrid.length > 0
|
||||
)
|
||||
{
|
||||
var fourGrid = finalGrid.substr(0, 4);
|
||||
if (fourGrid in g_gridToState && g_gridToState[fourGrid].length == 1)
|
||||
if (details.grid4 in g_gridToState && g_gridToState[details.grid4].length == 1)
|
||||
{
|
||||
details.state = g_gridToState[fourGrid][0];
|
||||
details.state = g_gridToState[details.grid4][0];
|
||||
}
|
||||
lookupCall = true;
|
||||
}
|
||||
|
@ -14588,6 +14592,7 @@ function callookResults(buffer, gridPass)
|
|||
callObject.lat = results.location.latitude;
|
||||
callObject.lon = results.location.longitude;
|
||||
callObject.grid = results.location.gridsquare;
|
||||
callObject.grid4 = callObject.grid.length > 1 ? callObject.grid.substr(0, 4) : "-";
|
||||
callObject.efdate = results.otherInfo.grantDate;
|
||||
callObject.expdate = results.otherInfo.expiryDate;
|
||||
callObject.frn = results.otherInfo.frn;
|
||||
|
|
|
@ -129,6 +129,27 @@ Number.prototype.toDHMS = function ()
|
|||
return val;
|
||||
};
|
||||
|
||||
Number.prototype.toDHMS15 = function ()
|
||||
{
|
||||
// round to earliest 15 seconds
|
||||
|
||||
var seconds = Math.floor(this / 15) * 15;
|
||||
var days = Math.floor(seconds / (3600 * 24));
|
||||
seconds -= days * 3600 * 24;
|
||||
var hrs = Math.floor(seconds / 3600);
|
||||
seconds -= hrs * 3600;
|
||||
var mnts = Math.floor(seconds / 60);
|
||||
seconds -= mnts * 60;
|
||||
|
||||
days = days ? days + "d " : "";
|
||||
hrs = hrs ? hrs + "h " : "";
|
||||
mnts = mnts ? mnts + "m " : "";
|
||||
var first = days + hrs + mnts;
|
||||
if (first == "") val = seconds + "s";
|
||||
else val = first + (seconds > 0 ? seconds + "s" : "");
|
||||
return val;
|
||||
};
|
||||
|
||||
Number.prototype.toDHM = function ()
|
||||
{
|
||||
var seconds = this;
|
||||
|
@ -143,6 +164,8 @@ Number.prototype.toDHM = function ()
|
|||
hrs = hrs ? hrs + "h " : "";
|
||||
mnts = mnts || seconds ? mnts + "m " : "";
|
||||
val = days + hrs + mnts;
|
||||
if (val == "") val = "0m";
|
||||
|
||||
return val;
|
||||
};
|
||||
|
||||
|
|
|
@ -134,8 +134,9 @@ var g_defaultSettings = {
|
|||
controlsExtended: false,
|
||||
compact: false,
|
||||
settingProfiles: false,
|
||||
lastSortIndex: 6,
|
||||
lastSortReverse: 1
|
||||
|
||||
sortColumn: "Age",
|
||||
sortReverse: false
|
||||
};
|
||||
|
||||
const LOGBOOK_LIVE_BAND_LIVE_MODE = "0";
|
||||
|
@ -219,11 +220,34 @@ function loadSettings()
|
|||
}
|
||||
g_rosterSettings = deepmerge(g_defaultSettings, readSettings);
|
||||
|
||||
if ("GT" in g_rosterSettings.columns) delete g_rosterSettings.columns.GT;
|
||||
fixLegacySettings();
|
||||
|
||||
writeRosterSettings();
|
||||
}
|
||||
|
||||
function fixLegacySettings()
|
||||
{
|
||||
// Not sure why, but Paul Traina added this settings cleanup in August 2020.
|
||||
if ("GT" in g_rosterSettings.columns) delete g_rosterSettings.columns.GT;
|
||||
|
||||
// In January 2022, we refactored roster column sorting
|
||||
if (g_rosterSettings.lastSortIndex)
|
||||
{
|
||||
g_rosterSettings.sortColumn = LEGACY_COLUMN_SORT_ID[g_rosterSettings.lastSortIndex] || "Age";
|
||||
delete g_rosterSettings.lastSortIndex;
|
||||
}
|
||||
|
||||
// In January 2022, we refactored roster column sorting
|
||||
if (g_rosterSettings.lastSortReverse)
|
||||
{
|
||||
g_rosterSettings.sortReverse = g_rosterSettings.lastSortReverse;
|
||||
delete g_rosterSettings.lastSortReverse;
|
||||
}
|
||||
|
||||
// In January 2022, we added a `columnOrder` setting, which we need to ensure always includes all columns
|
||||
g_rosterSettings.columnOrder = validateRosterColumnOrder(g_rosterSettings.columnOrder);
|
||||
}
|
||||
|
||||
function writeRosterSettings()
|
||||
{
|
||||
localStorage.rosterSettings = JSON.stringify(g_rosterSettings);
|
||||
|
@ -266,178 +290,6 @@ function lockNewWindows()
|
|||
}
|
||||
}
|
||||
|
||||
var r_sortFunction = [
|
||||
myCallCompare,
|
||||
myGridCompare,
|
||||
myDbCompare,
|
||||
myDTCompare,
|
||||
myFreqCompare,
|
||||
myDxccCompare,
|
||||
myTimeCompare,
|
||||
myDistanceCompare,
|
||||
myHeadingCompare,
|
||||
myStateCompare,
|
||||
myCQCompare,
|
||||
myWPXCompare,
|
||||
myLifeCompare,
|
||||
mySpotCompare,
|
||||
myGTCompare,
|
||||
myCntyCompare,
|
||||
myContCompare
|
||||
];
|
||||
|
||||
function myCallCompare(a, b)
|
||||
{
|
||||
return a.callObj.DEcall.localeCompare(b.callObj.DEcall);
|
||||
}
|
||||
|
||||
function myGridCompare(a, b)
|
||||
{
|
||||
let gridA = a.callObj.grid ? a.callObj.grid : "0";
|
||||
let gridB = b.callObj.grid ? b.callObj.grid : "0";
|
||||
|
||||
if (gridA > gridB) return 1;
|
||||
if (gridA < gridB) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
function myDxccCompare(a, b)
|
||||
{
|
||||
return window.opener.myDxccCompare(a.callObj, b.callObj);
|
||||
}
|
||||
|
||||
function myTimeCompare(a, b)
|
||||
{
|
||||
if (a.callObj.age > b.callObj.age) return 1;
|
||||
if (a.callObj.age < b.callObj.age) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
function myLifeCompare(a, b)
|
||||
{
|
||||
if (a.callObj.life > b.callObj.life) return 1;
|
||||
if (a.callObj.life < b.callObj.life) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
function mySpotCompare(a, b)
|
||||
{
|
||||
let cutoff = timeNowSec() - window.opener.g_receptionSettings.viewHistoryTimeSec;
|
||||
|
||||
if (a.callObj.spot.when <= cutoff) return -1;
|
||||
if (b.callObj.spot.when <= cutoff) return 1;
|
||||
|
||||
let aSNR = Number(a.callObj.spot.snr);
|
||||
let bSNR = Number(b.callObj.spot.snr);
|
||||
|
||||
if (aSNR > bSNR) return 1;
|
||||
if (aSNR < bSNR) return -1;
|
||||
|
||||
if (a.callObj.spot.when > b.callObj.spot.when) return 1;
|
||||
if (a.callObj.spot.when < b.callObj.spot.when) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function myDbCompare(a, b)
|
||||
{
|
||||
if (a.callObj.RSTsent > b.callObj.RSTsent) return 1;
|
||||
if (a.callObj.RSTsent < b.callObj.RSTsent) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
function myFreqCompare(a, b)
|
||||
{
|
||||
if (a.callObj.delta > b.callObj.delta) return 1;
|
||||
if (a.callObj.delta < b.callObj.delta) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
function myDTCompare(a, b)
|
||||
{
|
||||
if (a.callObj.dt > b.callObj.dt) return 1;
|
||||
if (a.callObj.dt < b.callObj.dt) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
function myDistanceCompare(a, b)
|
||||
{
|
||||
if (a.callObj.distance > b.callObj.distance) return 1;
|
||||
if (a.callObj.distance < b.callObj.distance) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
function myHeadingCompare(a, b)
|
||||
{
|
||||
if (a.callObj.heading > b.callObj.heading) return 1;
|
||||
if (a.callObj.heading < b.callObj.heading) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
function myStateCompare(a, b)
|
||||
{
|
||||
if (a.callObj.state == null) return 1;
|
||||
if (b.callObj.state == null) return -1;
|
||||
if (a.callObj.state > b.callObj.state) return 1;
|
||||
if (a.callObj.state < b.callObj.state) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
function myCQCompare(a, b)
|
||||
{
|
||||
return a.callObj.DXcall.localeCompare(b.callObj.DXcall);
|
||||
}
|
||||
|
||||
function myWPXCompare(a, b)
|
||||
{
|
||||
if (a.callObj.px == null) return 1;
|
||||
if (b.callObj.px == null) return -1;
|
||||
if (a.callObj.px > b.callObj.px) return 1;
|
||||
if (a.callObj.px < b.callObj.px) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
function myCntyCompare(a, b)
|
||||
{
|
||||
if (a.callObj.cnty == null) return 1;
|
||||
if (b.callObj.cnty == null) return -1;
|
||||
if (a.callObj.cnty.substr(3) > b.callObj.cnty.substr(3)) return 1;
|
||||
if (a.callObj.cnty.substr(3) < b.callObj.cnty.substr(3)) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
function myContCompare(a, b)
|
||||
{
|
||||
if (a.callObj.cont == null) return 1;
|
||||
if (b.callObj.cont == null) return -1;
|
||||
if (a.callObj.cont > b.callObj.cont) return 1;
|
||||
if (a.callObj.cont < b.callObj.cont) return -1;
|
||||
return 0;
|
||||
}
|
||||
function myGTCompare(a, b)
|
||||
{
|
||||
if (a.callObj.style.gt != 0 && b.callObj.style.gt == 0) return 1;
|
||||
if (a.callObj.style.gt == 0 && b.callObj.style.gt != 0) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
function showRosterBox(sortIndex)
|
||||
{
|
||||
if (g_rosterSettings.lastSortIndex != sortIndex)
|
||||
{
|
||||
g_rosterSettings.lastSortIndex = sortIndex;
|
||||
g_rosterSettings.lastSortReverse = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_rosterSettings.lastSortReverse ^= 1;
|
||||
}
|
||||
|
||||
writeRosterSettings();
|
||||
|
||||
window.opener.goProcessRoster();
|
||||
}
|
||||
|
||||
function hashMaker(start, callObj, reference)
|
||||
{
|
||||
if (reference == LOGBOOK_LIVE_BAND_LIVE_MODE) return `${start}${callObj.band}${callObj.mode}`;
|
||||
|
@ -524,7 +376,7 @@ function getSpotString(callObj)
|
|||
{
|
||||
when = timeNowSec() - callObj.spot.when;
|
||||
if (when <= window.opener.g_receptionSettings.viewHistoryTimeSec)
|
||||
{ result = parseInt(when).toDHMS(); }
|
||||
{ result = parseInt(when).toDHM(); }
|
||||
}
|
||||
if (result) result += " / " + callObj.spot.snr;
|
||||
return result;
|
||||
|
@ -1852,8 +1704,10 @@ function init()
|
|||
item = new nw.MenuItem({ type: "separator" });
|
||||
g_menu.append(item);
|
||||
|
||||
for (let key in g_rosterSettings.columns)
|
||||
for (let columnIndex in g_rosterSettings.columnOrder)
|
||||
{
|
||||
let key = g_rosterSettings.columnOrder[columnIndex];
|
||||
|
||||
let itemx = new nw.MenuItem({
|
||||
type: "checkbox",
|
||||
label: key,
|
||||
|
|
|
@ -117,12 +117,12 @@ function processRosterHunting(callRoster, rosterSettings)
|
|||
{
|
||||
callObj.callFlags.oams = true;
|
||||
// grab the CID
|
||||
colorObject.gt = window.opener.g_gtCallsigns[callsign];
|
||||
callObj.gt = window.opener.g_gtCallsigns[callsign];
|
||||
hasGtPin = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
colorObject.gt = 0;
|
||||
callObj.gt = 0;
|
||||
}
|
||||
|
||||
// We only do hunt highlighting when showing all entries
|
||||
|
|
|
@ -1,413 +1,27 @@
|
|||
function renderNormalRosterHeaders(showBands, showModes)
|
||||
function renderNormalRosterHeaders(columns)
|
||||
{
|
||||
let worker = ""
|
||||
worker = "<table id='callTable' class='rosterTable' align=left>";
|
||||
let html = "<table id='callTable' class='rosterTable' align=left><thead>"
|
||||
html = html + columns.map(column => renderHeaderForColumn(column)).join("\n")
|
||||
html = html + "</thead><tbody>"
|
||||
|
||||
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
|
||||
return html
|
||||
}
|
||||
|
||||
function renderNormalRosterRow(callObj, showBands, showModes)
|
||||
function renderNormalRosterRow(columns, callObj)
|
||||
{
|
||||
let thisCall = callObj.DEcall;
|
||||
let acks = window.opener.g_acknowledgedCalls;
|
||||
let grid = callObj.grid.length > 1 ? callObj.grid.substr(0, 4) : "-";
|
||||
callObj.grid4 = callObj.grid4 || (callObj.grid && callObj.grid.length > 1) ? callObj.grid.substr(0, 4) : "-";
|
||||
callObj.hash = callObj.hash || `${callObj.DEcall}${callObj.band}${callObj.mode}`;
|
||||
|
||||
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 html = `<tr id='${callObj.hash}'>`;
|
||||
|
||||
let spotString = "";
|
||||
if (g_rosterSettings.columns.Spot && callObj.qrz == false)
|
||||
{
|
||||
spotString = getSpotString(callObj);
|
||||
}
|
||||
html = html + columns.map(column => renderEntryForColumn(column, callObj)).join("\n")
|
||||
|
||||
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}`
|
||||
}
|
||||
html += "</tr>";
|
||||
|
||||
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 " +
|
||||
window.opener.userDayString(
|
||||
window.opener.g_lotwCallsigns[thisCall] * 86400000
|
||||
) +
|
||||
"'>✔</td>";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
worker +=
|
||||
"<td style='color:#0F0' align='center' title=' Last Upload " +
|
||||
window.opener.userDayString(
|
||||
window.opener.g_lotwCallsigns[thisCall] * 86400000
|
||||
) +
|
||||
"'>✔</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 ? "✔" : "") +
|
||||
"</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 ? "✔" : "") +
|
||||
"</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;
|
||||
return html;
|
||||
}
|
||||
|
||||
function renderNormalRosterFooter()
|
||||
{
|
||||
return "</table>";
|
||||
return "</tbody></table>";
|
||||
}
|
||||
|
|
|
@ -1,12 +1,38 @@
|
|||
function renderRoster(callRoster, rosterSettings)
|
||||
{
|
||||
// eQSL - function
|
||||
if (window.opener.g_callsignLookups.eqslUseEnable == true) useseQSLDiv.style.display = "";
|
||||
else useseQSLDiv.style.display = "none";
|
||||
let columnOverrides = {
|
||||
Callsign: true,
|
||||
Grid: true
|
||||
}
|
||||
|
||||
// OQRS - function
|
||||
if (window.opener.g_callsignLookups.oqrsUseEnable == true) usesOQRSDiv.style.display = "";
|
||||
else usesOQRSDiv.style.display = "none";
|
||||
if (window.opener.g_callsignLookups.eqslUseEnable == true)
|
||||
{
|
||||
useseQSLDiv.style.display = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
columnOverrides.eQSL = false;
|
||||
useseQSLDiv.style.display = "none";
|
||||
}
|
||||
|
||||
if (window.opener.g_callsignLookups.oqrsUseEnable == true)
|
||||
{
|
||||
usesOQRSDiv.style.display = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
columnOverrides.OQRS = false;
|
||||
usesOQRSDiv.style.display = "none";
|
||||
}
|
||||
|
||||
if (window.opener.g_callsignLookups.lotwUseEnable == true)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
columnOverrides.LoTW = false;
|
||||
}
|
||||
|
||||
// dealing with spots
|
||||
if (g_rosterSettings.columns.Spot == true) onlySpotDiv.style.display = "";
|
||||
|
@ -67,24 +93,23 @@ function renderRoster(callRoster, rosterSettings)
|
|||
|
||||
window.document.title = `Call Roster: ${countParts.join(" • ")}`;
|
||||
|
||||
if (g_rosterSettings.compact == false)
|
||||
if (g_rosterSettings.compact)
|
||||
{
|
||||
visibleCallList.sort(r_sortFunction[g_rosterSettings.lastSortIndex]);
|
||||
if (g_rosterSettings.lastSortReverse == 1)
|
||||
{
|
||||
visibleCallList.reverse();
|
||||
}
|
||||
sortCallList(visibleCallList, "Age", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Age sort for now... make this happen Tag
|
||||
visibleCallList.sort(r_sortFunction[6]).reverse();
|
||||
sortCallList(visibleCallList, g_rosterSettings.sortColumn, g_rosterSettings.sortReverse);
|
||||
}
|
||||
|
||||
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)
|
||||
columnOverrides.Band = showBands
|
||||
columnOverrides.Mode = showModes
|
||||
const rosterColumns = rosterColumnList(g_rosterSettings.columns, columnOverrides)
|
||||
|
||||
let worker = g_rosterSettings.compact ? renderCompactRosterHeaders() : renderNormalRosterHeaders(rosterColumns)
|
||||
|
||||
// Third loop: render all rows
|
||||
for (let x in visibleCallList)
|
||||
|
@ -95,11 +120,9 @@ function renderRoster(callRoster, rosterSettings)
|
|||
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+)?$"))
|
||||
if (callObj.DEcall.match("^[A-Z][0-9][A-Z](/w+)?$"))
|
||||
{ callObj.style.call = "class='oneByOne'"; }
|
||||
if (thisCall == window.opener.g_instances[callObj.instance].status.DXcall)
|
||||
if (callObj.DEcall == window.opener.g_instances[callObj.instance].status.DXcall)
|
||||
{
|
||||
if (window.opener.g_instances[callObj.instance].status.TxEnabled == 1)
|
||||
{
|
||||
|
@ -111,7 +134,7 @@ function renderRoster(callRoster, rosterSettings)
|
|||
}
|
||||
}
|
||||
|
||||
worker += g_rosterSettings.compact ? renderCompactRosterRow(callObj) : renderNormalRosterRow(callObj, showBands, showModes)
|
||||
worker += g_rosterSettings.compact ? renderCompactRosterRow(callObj) : renderNormalRosterRow(rosterColumns, callObj)
|
||||
}
|
||||
|
||||
worker += g_rosterSettings.compact ? renderCompactRosterFooter() : renderNormalRosterFooter()
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
function rosterColumnList(settings = {}, overrides = {})
|
||||
{
|
||||
return g_rosterSettings.columnOrder.filter(column =>
|
||||
{
|
||||
return column && (settings[column] || overrides[column]) && !(overrides[column] === false)
|
||||
})
|
||||
}
|
||||
|
||||
function renderHeaderForColumn(column)
|
||||
{
|
||||
const columnInfo = ROSTER_COLUMNS[column]
|
||||
|
||||
let attrs = (columnInfo && columnInfo.tableHeader && columnInfo.tableHeader()) || {}
|
||||
|
||||
attrs.html = attrs.html || column
|
||||
|
||||
if (columnInfo.compare)
|
||||
{
|
||||
attrs.style = "cursor: pointer"
|
||||
attrs.onClick = `setRosterSorting('${column}');`
|
||||
}
|
||||
|
||||
return renderRosterTableHTML("th", attrs)
|
||||
}
|
||||
|
||||
function renderEntryForColumn(column, entry)
|
||||
{
|
||||
const columnInfo = ROSTER_COLUMNS[column]
|
||||
|
||||
let attrs = (columnInfo && columnInfo.tableData && columnInfo.tableData(entry)) || {}
|
||||
|
||||
return renderRosterTableHTML("td", attrs)
|
||||
}
|
||||
|
||||
function renderRosterTableHTML(tag, attrs)
|
||||
{
|
||||
let innerHtml = attrs.html || ""
|
||||
delete attrs.html
|
||||
|
||||
let rawAttrs = attrs.rawAttrs || ""
|
||||
delete attrs.rawAttrs
|
||||
|
||||
let attrEntries = Object.entries(attrs).filter(kv => !!kv[1])
|
||||
|
||||
return `<${tag} ${rawAttrs} ${attrEntries.map((kv) => `${kv[0]}="${kv[1].replace(/"/g, """)}"`).join(" ")}>${innerHtml}</${tag}>`
|
||||
}
|
||||
|
||||
function setRosterSorting(column)
|
||||
{
|
||||
if (g_rosterSettings.sortColumn === column)
|
||||
{
|
||||
g_rosterSettings.sortReverse = !g_rosterSettings.sortReverse
|
||||
}
|
||||
else
|
||||
{
|
||||
g_rosterSettings.sortColumn = column
|
||||
g_rosterSettings.sortReverse = false
|
||||
}
|
||||
|
||||
writeRosterSettings();
|
||||
|
||||
window.opener.goProcessRoster();
|
||||
}
|
||||
|
||||
function sortCallList(callList, sortColumn, sortReverse)
|
||||
{
|
||||
const columnInfo = ROSTER_COLUMNS[sortColumn]
|
||||
|
||||
callList.sort((columnInfo && columnInfo.compare) || ROSTER_COLUMNS.Age.compare)
|
||||
|
||||
if (sortReverse)
|
||||
{
|
||||
callList.reverse()
|
||||
}
|
||||
}
|
||||
|
||||
function validateRosterColumnOrder(columns)
|
||||
{
|
||||
let correctedColumnOrder = (columns || DEFAULT_COLUMN_ORDER || []).slice();
|
||||
|
||||
DEFAULT_COLUMN_ORDER.forEach(column =>
|
||||
{
|
||||
if (!correctedColumnOrder.includes(column)) correctedColumnOrder.push(column);
|
||||
})
|
||||
correctedColumnOrder = correctedColumnOrder.filter(column => !!ROSTER_COLUMNS[column])
|
||||
|
||||
return correctedColumnOrder;
|
||||
}
|
||||
|
||||
function changeRosterColumnOrder(columns)
|
||||
{
|
||||
g_rosterSettings.columnOrder = validateRosterColumnOrder(columns);
|
||||
writeRosterSettings();
|
||||
window.opener.goProcessRoster();
|
||||
}
|
|
@ -0,0 +1,378 @@
|
|||
const DEFAULT_COLUMN_ORDER = [
|
||||
"Callsign", "Band", "Mode", "Grid", "Calling", "Msg",
|
||||
"DXCC", "Flag", "State", "County", "Cont",
|
||||
"dB", "Freq", "DT", "Dist", "Azim",
|
||||
"CQz", "ITUz", "PX",
|
||||
"LoTW", "eQSL", "OQRS",
|
||||
"Life", "Spot", "OAMS", "Age"
|
||||
]
|
||||
|
||||
const LEGACY_COLUMN_SORT_ID = {
|
||||
0: "Callsign",
|
||||
1: "Grid",
|
||||
2: "dB",
|
||||
3: "DT",
|
||||
4: "Freq",
|
||||
5: "DXCC",
|
||||
7: "Dist",
|
||||
8: "Azim",
|
||||
9: "State",
|
||||
10: "Calling",
|
||||
11: "PX",
|
||||
12: "Life",
|
||||
13: "Spot",
|
||||
14: "OAMS",
|
||||
15: "County",
|
||||
16: "Cont"
|
||||
}
|
||||
|
||||
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;
|
||||
if (aVal < bVal) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const callObjSimpleComparer = (attr) => getterSimpleComparer((elem) => elem.callObj[attr])
|
||||
|
||||
const callObjLocaleComparer = (attr) => (a, b) =>
|
||||
{
|
||||
if (a.callObj[attr] == null) return 1;
|
||||
if (b.callObj[attr] == null) return -1;
|
||||
return a.callObj[attr].localeCompare(b.callObj[attr]);
|
||||
}
|
||||
|
||||
const ROSTER_COLUMNS = {
|
||||
|
||||
Callsign: {
|
||||
compare: callObjLocaleComparer("DEcall"),
|
||||
tableHeader: () => ({ align: "left" }),
|
||||
tableData: (callObj) =>
|
||||
{
|
||||
let attrs = {
|
||||
title: callObj.awardReason,
|
||||
name: "Callsign",
|
||||
align: "left",
|
||||
onClick: `initiateQso("${callObj.hash}")`,
|
||||
rawAttrs: callObj.style.call,
|
||||
html: html = callObj.DEcall.formatCallsign()
|
||||
}
|
||||
|
||||
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>`
|
||||
attrs.title = `${attrs.title} - ${acks[callObj.DEcall].message}`
|
||||
}
|
||||
|
||||
return attrs
|
||||
}
|
||||
},
|
||||
|
||||
Band: {
|
||||
compare: false,
|
||||
tableData: (callObj) => ({
|
||||
style: `color: #${window.opener.g_pskColors[callObj.band]};`,
|
||||
html: callObj.band
|
||||
})
|
||||
},
|
||||
|
||||
Mode: {
|
||||
compare: false,
|
||||
tableData: (callObj) => ({
|
||||
style: `color: #${g_modeColors[callObj.mode] || "888888"};`,
|
||||
html: callObj.mode
|
||||
})
|
||||
},
|
||||
|
||||
Grid: {
|
||||
compare: callObjSimpleComparer("grid"),
|
||||
tableData: (callObj) => ({
|
||||
rawAttrs: callObj.style.grid,
|
||||
onClick: `centerOn("${callObj.grid4}")`,
|
||||
html: callObj.grid4
|
||||
})
|
||||
},
|
||||
|
||||
Calling: {
|
||||
compare: callObjLocaleComparer("DXcall"),
|
||||
tableData: (callObj) => ({
|
||||
rawAttrs: callObj.style.calling,
|
||||
name: callObj.CQ ? "CQ" : "Calling",
|
||||
html: callObj.DXcall.formatCallsign()
|
||||
})
|
||||
},
|
||||
|
||||
Msg: {
|
||||
compare: callObjLocaleComparer("DXcall"),
|
||||
tableData: (callObj) => ({ html: callObj.msg })
|
||||
},
|
||||
|
||||
DXCC: {
|
||||
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})`,
|
||||
rawAttrs: callObj.style.dxcc,
|
||||
html: window.opener.g_dxccToAltName[callObj.dxcc]
|
||||
})
|
||||
},
|
||||
|
||||
Flag: {
|
||||
compare: (a, b) => window.opener.myDxccCompare(a.callObj, b.callObj),
|
||||
tableData: (callObj) => ({
|
||||
align: "center",
|
||||
style: "margin:0; padding:0;",
|
||||
html: `<img style='padding-top:3px' src='./img/flags/16/${window.opener.g_worldGeoData[window.opener.g_dxccToGeoData[callObj.dxcc]].flag}'>`
|
||||
})
|
||||
},
|
||||
|
||||
State: {
|
||||
compare: callObjSimpleComparer("state"),
|
||||
tableData: (callObj) => ({
|
||||
align: "center",
|
||||
rawAttrs: callObj.style.state,
|
||||
html: callObj.state ? callObj.state.substr(3) : ""
|
||||
})
|
||||
},
|
||||
|
||||
County: {
|
||||
// Not sure why this comparison uses substring, but this is what the original code did
|
||||
compare: getterSimpleComparer((elem) => elem.callObj.cnty && elem.callObj.cnty.substr(3)),
|
||||
tableData: (callObj) =>
|
||||
{
|
||||
let attrs = {
|
||||
align: "center",
|
||||
rawAttrs: callObj.style.cnty,
|
||||
html: callObj.cnty ? window.opener.g_cntyToCounty[callObj.cnty] : ""
|
||||
}
|
||||
if (callObj.cnty && callObj.qual)
|
||||
{
|
||||
attrs.title = "ZIP Code matches multiple counties, click to do a full lookup"
|
||||
attrs.onClick = `lookupZip("${callObj.DEcall}", "${callObj.grid4}")`
|
||||
attrs.html = `¿ ${attrs.html} ?`
|
||||
}
|
||||
return attrs
|
||||
}
|
||||
},
|
||||
|
||||
Cont: {
|
||||
compare: callObjSimpleComparer("cont"),
|
||||
tableData: (callObj) => ({
|
||||
align: "center",
|
||||
rawAttrs: callObj.style.cont,
|
||||
html: callObj.cont ? callObj.cont : ""
|
||||
})
|
||||
},
|
||||
|
||||
dB: {
|
||||
compare: callObjSimpleComparer("RSTsent"),
|
||||
tableData: (callObj) => ({
|
||||
style: "color:#DD44DD;",
|
||||
html: `<b>${callObj.RSTsent}</b>`
|
||||
})
|
||||
},
|
||||
|
||||
Freq: {
|
||||
compare: callObjSimpleComparer("delta"),
|
||||
tableData: (callObj) => ({
|
||||
style: "color: #00FF00;",
|
||||
html: callObj.delta
|
||||
})
|
||||
},
|
||||
|
||||
DT: {
|
||||
compare: callObjSimpleComparer("dt"),
|
||||
tableData: (callObj) => ({
|
||||
style: "color: #1E90FF;",
|
||||
html: callObj.dt
|
||||
})
|
||||
},
|
||||
|
||||
Dist: {
|
||||
compare: callObjSimpleComparer("distance"),
|
||||
tableHeader: () => ({ html: `Dist (${window.opener.distanceUnit.value.toLowerCase()})` }),
|
||||
tableData: (callObj) => ({
|
||||
style: "color: cyan;",
|
||||
html: Math.round(callObj.distance * MyCircle.validateRadius(window.opener.distanceUnit.value))
|
||||
})
|
||||
},
|
||||
|
||||
Azim: {
|
||||
compare: callObjSimpleComparer("heading"),
|
||||
tableData: (callObj) => ({
|
||||
style: "color: yellow;",
|
||||
html: Math.round(callObj.heading)
|
||||
})
|
||||
},
|
||||
|
||||
CQz: {
|
||||
compare: false,
|
||||
tableData: (callObj) => ({
|
||||
name: "CQz",
|
||||
rawAttrs: callObj.style.cqz,
|
||||
html: callObj.cqza.join(",")
|
||||
})
|
||||
},
|
||||
|
||||
ITUz: {
|
||||
compare: false,
|
||||
tableData: (callObj) => ({
|
||||
name: "ITUz",
|
||||
rawAttrs: callObj.style.ituz,
|
||||
html: callObj.ituza.join(",")
|
||||
})
|
||||
},
|
||||
|
||||
PX: {
|
||||
compare: callObjSimpleComparer("px"),
|
||||
tableData: (callObj) => ({
|
||||
rawAttrs: callObj.style.px,
|
||||
html: callObj.px ? callObj.px : ""
|
||||
})
|
||||
},
|
||||
|
||||
LoTW: {
|
||||
compare: false,
|
||||
tableData: (callObj) =>
|
||||
{
|
||||
if (callObj.DEcall in window.opener.g_lotwCallsigns)
|
||||
{
|
||||
if (g_rosterSettings.maxLoTW < 27)
|
||||
{
|
||||
let months = (g_day - window.opener.g_lotwCallsigns[callObj.DEcall]) / 30;
|
||||
if (months > g_rosterSettings.maxLoTW)
|
||||
{
|
||||
return {
|
||||
style: "color: yellow;",
|
||||
align: "center",
|
||||
title: `Has not updated a QSO in ${Number(months).toYM()}`,
|
||||
html: "?"
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return {
|
||||
style: "color: #0F0;",
|
||||
align: "center",
|
||||
title: `Last Upload ${
|
||||
window.opener.userDayString(window.opener.g_lotwCallsigns[callObj.DEcall] * 86400000)
|
||||
}`,
|
||||
html: "✔"
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return {
|
||||
style: "color: #0F0;",
|
||||
align: "center",
|
||||
title: `Last Upload ${
|
||||
window.opener.userDayString(window.opener.g_lotwCallsigns[callObj.DEcall] * 86400000)
|
||||
}`,
|
||||
html: "✔"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
eQSL: {
|
||||
compare: false,
|
||||
tableData: (callObj) => ({
|
||||
style: "color: #0F0;",
|
||||
align: "center",
|
||||
html: (callObj.DEcall in window.opener.g_eqslCallsigns ? "✔" : "")
|
||||
})
|
||||
},
|
||||
|
||||
OQRS: {
|
||||
compare: false,
|
||||
tableData: (callObj) => ({
|
||||
style: "color: #0F0;",
|
||||
align: "center",
|
||||
html: (callObj.DEcall in window.opener.g_oqrsCallsigns ? "✔" : "")
|
||||
})
|
||||
},
|
||||
|
||||
Life: {
|
||||
compare: callObjSimpleComparer("life"),
|
||||
tableData: (callObj) => ({
|
||||
style: "color: #EEE;",
|
||||
class: "lifeCol",
|
||||
id: `lm${callObj.hash}`,
|
||||
html: (timeNowSec() - callObj.life).toDHMS15()
|
||||
})
|
||||
},
|
||||
|
||||
OAMS: {
|
||||
tableHeader: () => ({ description: "Off-Air Message User" }),
|
||||
compare: getterSimpleComparer((elem) => elem.callObj.gt != 0 ? 1 : 0),
|
||||
tableData: (callObj) =>
|
||||
{
|
||||
if (callObj.gt != 0)
|
||||
{
|
||||
if (callObj.reason.includes("oams"))
|
||||
{
|
||||
return {
|
||||
align: "center",
|
||||
style: "margin: 0; padding: 0; cursor: pointer; background-clip: content-box; box-shadow: 0 0 4px 4px inset #2222FFFF;",
|
||||
onClick: `openChatToCid("${callObj.gt}")`,
|
||||
html: "<img height='16px' style='' src='./img/gt_chat.png' />"
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return {
|
||||
align: "center",
|
||||
style: "margin: 0; padding: 0; cursor: pointer;",
|
||||
onClick: `openChatToCid("${callObj.gt}")`,
|
||||
html: "<img height='16px' style='' src='./img/gt_chat.png' />"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Age: {
|
||||
compare: callObjSimpleComparer("time"),
|
||||
tableData: (callObj) => ({
|
||||
style: "color: #EEE;",
|
||||
class: "timeCol",
|
||||
id: `tm${callObj.hash}`,
|
||||
title: (timeNowSec() - callObj.age).toDHMS(),
|
||||
html: (timeNowSec() - callObj.age).toDHMS15()
|
||||
})
|
||||
},
|
||||
|
||||
Spot: {
|
||||
compare: (a, b) =>
|
||||
{
|
||||
let cutoff = timeNowSec() - window.opener.g_receptionSettings.viewHistoryTimeSec;
|
||||
|
||||
if (a.callObj.spot.when <= cutoff) return -1;
|
||||
if (b.callObj.spot.when <= cutoff) return 1;
|
||||
|
||||
let aSNR = Number(a.callObj.spot.snr);
|
||||
let bSNR = Number(b.callObj.spot.snr);
|
||||
|
||||
if (aSNR > bSNR) return 1;
|
||||
if (aSNR < bSNR) return -1;
|
||||
|
||||
if (a.callObj.spot.when > b.callObj.spot.when) return 1;
|
||||
if (a.callObj.spot.when < b.callObj.spot.when) return -1;
|
||||
|
||||
return 0;
|
||||
},
|
||||
tableData: (callObj) => ({
|
||||
style: "color: #EEE;",
|
||||
class: "spotCol",
|
||||
id: `sp${callObj.hash}`,
|
||||
html: getSpotString(callObj)
|
||||
})
|
||||
}
|
||||
}
|
Ładowanie…
Reference in New Issue