gridtracker/package.nw/lib/roster/rosterColumns.js

522 wiersze
14 KiB
JavaScript
Czysty Zwykły widok Historia

2022-03-05 03:25:45 +00:00
const DEFAULT_COLUMN_ORDER = [
2022-01-02 23:38:46 +00:00
"Callsign", "Band", "Mode", "Calling", "Wanted", "Grid", "Msg",
2022-05-20 15:35:49 +00:00
"POTA", "DXCC", "Flag", "State", "County", "Cont",
2022-03-05 03:25:45 +00:00
"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);
2022-01-02 23:38:46 +00:00
2022-03-05 03:25:45 +00:00
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,
2022-10-10 12:37:55 +00:00
html: html = (callObj.DEcallHTML || callObj.DEcall).formatCallsign()
2022-03-05 03:25:45 +00:00
}
2022-05-02 12:11:41 +00:00
let acks = window.opener.g_acknowledgedCalls || {};
2022-03-05 03:25:45 +00:00
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,
2022-09-19 02:06:49 +00:00
onClick: `centerOn("${callObj.grid}")`,
html: callObj.grid
2022-03-05 03:25:45 +00:00
})
},
Calling: {
compare: callObjLocaleComparer("DXcall"),
tableData: (callObj) => ({
rawAttrs: callObj.style.calling,
name: callObj.CQ ? "CQ" : "Calling",
2022-09-27 00:27:22 +00:00
html: (g_rosterSettings.wantRRCQ && callObj.RR73) ? "RR73" : callObj.DXcall.formatCallsign()
2022-03-05 03:25:45 +00:00
})
},
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_dxccInfo[callObj.dxcc].pp,
2022-09-26 18:45:04 +00:00
name: `DXCC (${callObj.dxcc})`,
2022-03-05 03:25:45 +00:00
rawAttrs: callObj.style.dxcc,
2022-01-05 14:37:21 +00:00
html: [window.opener.g_dxccToAltName[callObj.dxcc], callObj.dxccSuffix].join("&nbsp;")
2022-03-05 03:25:45 +00:00
})
},
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_dxccInfo[callObj.dxcc].flag}'>`
2022-03-05 03:25:45 +00:00
})
},
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
2022-09-19 02:06:49 +00:00
// Because we're sorting on the county name, the data contains "CO,Adams", we don't want to sort by state.
2022-03-05 03:25:45 +00:00
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] : ""
}
2022-09-19 02:06:49 +00:00
if (callObj.cnty && callObj.qual == false)
2022-03-05 03:25:45 +00:00
{
2022-09-22 02:30:52 +00:00
attrs.title = $.i18n("rosterColumns.County.title")
2022-09-19 02:06:49 +00:00
attrs.onClick = `window.opener.lookupCallsign("${callObj.DEcall}", "${callObj.grid}")`
2022-09-25 07:03:00 +00:00
attrs.html = attrs.html + " +" + String(window.opener.g_zipToCounty[callObj.zipcode].length - 1)
2022-09-19 02:06:49 +00:00
attrs.style = "cursor: pointer; color: cyan;"
2022-03-05 03:25:45 +00:00
}
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,
2022-10-07 23:44:11 +00:00
html: [callObj.cqz, callObj.cqzSuffix].join("&nbsp;")
2022-03-05 03:25:45 +00:00
})
},
ITUz: {
compare: false,
tableData: (callObj) => ({
name: "ITUz",
rawAttrs: callObj.style.ituz,
2022-10-07 23:44:11 +00:00
html: callObj.ituz
2022-03-05 03:25:45 +00:00
})
},
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",
2022-09-22 02:30:52 +00:00
title: `${$.i18n("rosterColumns.LoTW.NoUpdate")} ${Number(months).toYM()}`,
2022-03-05 03:25:45 +00:00
html: "?"
}
}
else
{
return {
style: "color: #0F0;",
align: "center",
2022-09-22 02:30:52 +00:00
title: `${$.i18n("rosterColumns.LoTW.LastUpdate")}${
2022-03-05 03:25:45 +00:00
window.opener.userDayString(window.opener.g_lotwCallsigns[callObj.DEcall] * 86400000)
}`,
html: "&#10004;"
}
}
}
else
{
return {
style: "color: #0F0;",
align: "center",
2022-09-22 02:30:52 +00:00
title: `${$.i18n("rosterColumns.LoTW.LastUpdate")}${
2022-03-05 03:25:45 +00:00
window.opener.userDayString(window.opener.g_lotwCallsigns[callObj.DEcall] * 86400000)
}`,
html: "&#10004;"
}
}
}
}
},
eQSL: {
compare: false,
tableData: (callObj) => ({
style: "color: #0F0;",
align: "center",
html: (callObj.DEcall in window.opener.g_eqslCallsigns ? "&#10004;" : "")
})
},
OQRS: {
compare: false,
tableData: (callObj) => ({
style: "color: #0F0;",
align: "center",
html: (callObj.DEcall in window.opener.g_oqrsCallsigns ? "&#10004;" : "")
})
},
Life: {
compare: callObjSimpleComparer("life"),
tableData: (callObj) => ({
style: "color: #EEE;",
class: "lifeCol",
id: `lm${callObj.hash}`,
2022-09-19 02:06:49 +00:00
html: (timeNowSec() - callObj.life).toDHMS()
2022-03-05 03:25:45 +00:00
})
},
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: {
2022-09-19 02:06:49 +00:00
compare: callObjSimpleComparer("age"),
2022-03-05 03:25:45 +00:00
tableData: (callObj) => ({
style: "color: #EEE;",
class: "timeCol",
id: `tm${callObj.hash}`,
2022-09-19 02:06:49 +00:00
html: (timeNowSec() - callObj.age).toDHMS()
2022-03-05 03:25:45 +00:00
})
},
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)
})
2022-05-20 01:19:24 +00:00
},
POTA: {
compare: false,
tableData: (callObj) => ({
name: "POTA",
rawAttrs: callObj.style.pota,
title: potaColumnHover(callObj),
html: potaColumnRef(callObj)
2022-05-20 01:19:24 +00:00
})
2022-01-02 23:38:46 +00:00
},
Wanted: {
2022-01-03 18:07:16 +00:00
compare: (a, b) => wantedColumnComparer(a.callObj, b.callObj),
2022-01-02 23:38:46 +00:00
tableData: (callObj) => ({
class: "wantedCol",
2022-01-03 18:07:16 +00:00
title: wantedColumnParts(callObj).map(entry => `${entry}`).join("\n"),
html: wantedColumnParts(callObj).join(" - ", { html: true })
2022-01-02 23:38:46 +00:00
})
2022-03-05 03:25:45 +00:00
}
}
2022-01-02 23:38:46 +00:00
function potaColumnRef(callObj)
{
2022-09-19 02:06:49 +00:00
if (callObj.pota.length > 0)
{
2022-09-19 02:06:49 +00:00
let value = callObj.pota[0];
if (callObj.pota.length > 1)
2022-09-11 20:18:00 +00:00
{
2022-09-25 07:03:00 +00:00
value += " +" + String(callObj.pota.length - 1);
}
2022-09-19 02:06:49 +00:00
return value;
2022-09-11 20:18:00 +00:00
}
else
{
2022-09-19 02:06:49 +00:00
return "";
}
}
function potaColumnHover(callObj)
{
let value = ""
2022-09-19 02:06:49 +00:00
for (let i in callObj.pota)
{
2022-09-19 02:06:49 +00:00
if (callObj.pota[i] in window.opener.g_pota.parks)
2022-09-11 20:18:00 +00:00
{
value += callObj.pota[i] + " - " + window.opener.g_pota.parks[callObj.pota[i]].name + "\n";
}
2022-09-11 20:18:00 +00:00
}
return value;
}
2022-10-10 21:16:25 +00:00
WANTED_ORDER = ["call", "qrz", "regex", "cont", "dxcc", "cqz", "ituz", "dxccMarathon", "cqzMarathon", "state", "pota", "grid", "cnty", "wpx", "oams"];
2022-01-02 23:38:46 +00:00
WANTED_LABELS = {
2022-09-22 02:30:52 +00:00
cont: $.i18n("rosterColumns.Wanted.cont"),
cqz: $.i18n("rosterColumns.Wanted.cqz"),
ituz: $.i18n("rosterColumns.Wanted.ituz"),
dxcc: $.i18n("rosterColumns.Wanted.dxcc"),
dxccMarathon: $.i18n("rosterColumns.Wanted.dxccMarathon"),
cqzMarathon: $.i18n("rosterColumns.Wanted.cqzMarathon"),
state: $.i18n("rosterColumns.Wanted.state"),
grid: $.i18n("rosterColumns.Wanted.grid"),
cnty: $.i18n("rosterColumns.Wanted.county"),
wpx: $.i18n("rosterColumns.Wanted.wpx"),
call: $.i18n("rosterColumns.Wanted.call"),
oams: $.i18n("rosterColumns.Wanted.oams"),
pota: $.i18n("rosterColumns.Wanted.pota"),
2022-01-02 23:38:46 +00:00
}
2022-01-03 18:07:16 +00:00
function wantedColumnParts(callObj, options)
2022-01-02 23:38:46 +00:00
{
2022-01-03 18:07:16 +00:00
options = options || {};
if (Object.keys(callObj.hunting).length == 0)
{
// is this an award reason?
// Hack until I talk with seb
if (callObj.awardReason != "Callsign")
{
return callObj.reason;
}
else
{
return [];
}
}
2022-01-02 23:38:46 +00:00
let parts = [];
2022-01-03 18:07:16 +00:00
2022-01-02 23:38:46 +00:00
WANTED_ORDER.forEach(field =>
{
let wanted = callObj.hunting[field];
if (wanted == "calling") { parts.push("Calling"); }
2022-01-05 14:37:21 +00:00
// else if (wanted == "caller") { parts.push("Called"); }
else if (wanted == "hunted" && field == "qrz") { parts.push("Caller"); }
2022-01-03 18:07:16 +00:00
else if (wanted == "hunted" && field == "oams") { parts.push("OAMS User"); }
2022-10-10 12:37:55 +00:00
else if (wanted == "hunted" && field == "regex") { parts.push("Regex match"); }
2022-01-03 18:07:16 +00:00
else if (wanted == "hunted") { parts.push(`${options.html ? "<b>" : ""}New ${WANTED_LABELS[field]}${options.html ? "<b>" : ""}`); }
2022-01-02 23:38:46 +00:00
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]}`); }
})
2022-01-05 14:37:21 +00:00
if (parts[0] == "Calling" && parts[1] == "Caller")
2022-01-03 18:07:16 +00:00
{
parts.shift(); parts.shift();
parts.unshift(`${options.html ? "<b>" : ""}Working${options.html ? "<b>" : ""}`);
2022-01-03 18:07:16 +00:00
}
2022-01-02 23:38:46 +00:00
return parts;
}
2022-01-03 18:07:16 +00:00
function wantedColumnWeighter(callObj, field)
2022-01-02 23:38:46 +00:00
{
2022-01-03 18:07:16 +00:00
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;
}
2022-01-02 23:38:46 +00:00
2022-01-03 18:07:16 +00:00
function wantedColumnComparer(a, b)
{
if (!a.hunting) return 1;
if (!b.hunting) return -1;
2022-01-02 23:38:46 +00:00
2022-01-03 18:07:16 +00:00
for (const index in WANTED_ORDER)
{
const field = WANTED_ORDER[index];
const aWeight = wantedColumnWeighter(a, field);
const bWeight = wantedColumnWeighter(b, field);
2022-01-02 23:38:46 +00:00
2022-01-03 18:07:16 +00:00
if (aWeight < bWeight) return 1;
if (aWeight > bWeight) return -1;
}
return 0;
2022-09-22 02:30:52 +00:00
}