diff --git a/README.md b/README.md index f0f7515..bcba315 100644 --- a/README.md +++ b/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. diff --git a/package.nw/gt_roster.html b/package.nw/gt_roster.html index 3909386..871fc52 100644 --- a/package.nw/gt_roster.html +++ b/package.nw/gt_roster.html @@ -28,6 +28,8 @@ + + diff --git a/package.nw/lib/gt.js b/package.nw/lib/gt.js index e005978..6a3c9df 100644 --- a/package.nw/lib/gt.js +++ b/package.nw/lib/gt.js @@ -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; diff --git a/package.nw/lib/protos.js b/package.nw/lib/protos.js index 5e71394..4e38943 100644 --- a/package.nw/lib/protos.js +++ b/package.nw/lib/protos.js @@ -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; }; diff --git a/package.nw/lib/roster.js b/package.nw/lib/roster.js index 4a9298b..1bb4af9 100644 --- a/package.nw/lib/roster.js +++ b/package.nw/lib/roster.js @@ -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, diff --git a/package.nw/lib/roster/processRosterHunting.js b/package.nw/lib/roster/processRosterHunting.js index eb81d15..97c9661 100644 --- a/package.nw/lib/roster/processRosterHunting.js +++ b/package.nw/lib/roster/processRosterHunting.js @@ -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 diff --git a/package.nw/lib/roster/renderNormalRoster.js b/package.nw/lib/roster/renderNormalRoster.js index f71f8b9..b4fc5ec 100644 --- a/package.nw/lib/roster/renderNormalRoster.js +++ b/package.nw/lib/roster/renderNormalRoster.js @@ -1,413 +1,27 @@ -function renderNormalRosterHeaders(showBands, showModes) +function renderNormalRosterHeaders(columns) { - let worker = "" - worker = "
Callsign | "; - - if (showBands) - { worker += "Band | "; } - - if (showModes) - { worker += "Mode | "; } - - worker += "Grid | "; - - if (g_rosterSettings.columns.Calling) - { worker += "Calling | "; } - - if (g_rosterSettings.columns.Msg) - { worker += "Msg | "; } - - if (g_rosterSettings.columns.DXCC) - { worker += "DXCC | "; } - - if (g_rosterSettings.columns.Flag) - { worker += "Flag | "; } - - if (g_rosterSettings.columns.State) - { worker += "State | "; } - - if (g_rosterSettings.columns.County) - { worker += "County | "; } - - if (g_rosterSettings.columns.Cont) - { worker += "Cont | "; } - - if (g_rosterSettings.columns.dB) - { worker += "dB | "; } - - if (g_rosterSettings.columns.Freq) - { worker += "Freq | "; } - - if (g_rosterSettings.columns.DT) - { worker += "DT | "; } - - if (g_rosterSettings.columns.Dist) - { - worker += "Dist(" + - window.opener.distanceUnit.value.toLowerCase() + ") | "; - } - - if (g_rosterSettings.columns.Azim) - { worker += "Azim | "; } - - if (g_rosterSettings.columns.CQz) - { worker += "CQz | "; } - - if (g_rosterSettings.columns.ITUz) - { worker += "ITUz | "; } - - if (g_rosterSettings.columns.PX) - { worker += "PX | "; } - - if (window.opener.g_callsignLookups.lotwUseEnable == true && g_rosterSettings.columns.LoTW) - { worker += "LoTW | "; } - - if (window.opener.g_callsignLookups.eqslUseEnable == true && g_rosterSettings.columns.eQSL) - { worker += "eQSL | "; } - - if (window.opener.g_callsignLookups.oqrsUseEnable == true && g_rosterSettings.columns.OQRS) - { worker += "OQRS | "; } - - if (g_rosterSettings.columns.Spot) - { worker += "Spot | "; } - - if (g_rosterSettings.columns.Life) - { worker += "Life | "; } - - if (g_rosterSettings.columns.OAMS) - { worker += "OAMS | "; } - - if (g_rosterSettings.columns.Age) - { worker += "Age | "; } - - 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 = `|||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
" + - callStr + - " | "; - - if (showBands) - { - worker += - "" + - callObj.band + - " | "; - } - if (showModes) - { - let color = "888888"; - if (callObj.mode in g_modeColors) - { color = g_modeColors[callObj.mode]; } - worker += - "" + callObj.mode + " | "; - } - - worker += - "" + - grid + - " | "; - if (g_rosterSettings.columns.Calling) - { - let lookString = callObj.CQ ? "name='CQ'" : "name='Calling'"; - worker += - "" + - callObj.DXcall.formatCallsign() + - " | "; - } - if (g_rosterSettings.columns.Msg) - { worker += "" + callObj.msg + " | "; } - - if (g_rosterSettings.columns.DXCC) - { - worker += - "" + - window.opener.g_dxccToAltName[callObj.dxcc] + " | "; - } - if (g_rosterSettings.columns.Flag) - { - worker += - ""; - } - if (g_rosterSettings.columns.State) - { - worker += - " | " + - (callObj.state ? callObj.state.substr(3) : "") + - " | "; - } - if (g_rosterSettings.columns.County) - { - worker += - "" + - (callObj.cnty - ? (callObj.qual ? "" : "¿ ") + - window.opener.g_cntyToCounty[callObj.cnty] + - (callObj.qual ? "" : " ?") - : "") + - " | "; - } - if (g_rosterSettings.columns.Cont) - { - worker += - "" + - (callObj.cont ? callObj.cont : "") + - " | "; - } - - if (g_rosterSettings.columns.dB) - { - worker += - "" + - callObj.RSTsent + - " | "; - } - if (g_rosterSettings.columns.Freq) - { worker += "" + callObj.delta + " | "; } - if (g_rosterSettings.columns.DT) - { worker += "" + callObj.dt + " | "; } - if (g_rosterSettings.columns.Dist) - { - worker += - "" + - parseInt( - callObj.distance * - MyCircle.validateRadius(window.opener.distanceUnit.value) - ) + - " | "; - } - if (g_rosterSettings.columns.Azim) - { - worker += - "" + - parseInt(callObj.heading) + - " | "; - } - - if (g_rosterSettings.columns.CQz) - { - worker += - "" + - callObj.cqza.join(",") + - " | "; - } - if (g_rosterSettings.columns.ITUz) - { - worker += - "" + - callObj.ituza.join(",") + - " | "; - } - - if (g_rosterSettings.columns.PX) - { - worker += - "" + - (callObj.px ? callObj.px : "") + - " | "; - } - - 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 += - "? | "; - } - else - { - worker += - "✔ | "; - } - } - else - { - worker += - "✔ | "; - } - } - else worker += ""; - } - if ( - window.opener.g_callsignLookups.eqslUseEnable == true && - g_rosterSettings.columns.eQSL - ) - { - worker += - " | " + - (thisCall in window.opener.g_eqslCallsigns ? "✔" : "") + - " | "; - } - if ( - window.opener.g_callsignLookups.oqrsUseEnable == true && - g_rosterSettings.columns.OQRS - ) - { - worker += - "" + - (thisCall in window.opener.g_oqrsCallsigns ? "✔" : "") + - " | "; - } - - if (g_rosterSettings.columns.Spot) - { - worker += - "" + - spotString + - " | "; - } - if (g_rosterSettings.columns.Life) - { - worker += - "" + - (timeNowSec() - callObj.life).toDHMS() + - " | "; - } - - if (g_rosterSettings.columns.OAMS) - { - if (callObj.style.gt != 0) - { - if (callObj.reason.includes("oams")) - { - worker += - ""; - } - else - { - worker += - " | "; - } - } - else worker += " | "; - } - - if (g_rosterSettings.columns.Age) - { - worker += - " | " + - (timeNowSec() - callObj.age).toDHMS() + - " | "; - } - - worker += "