diff --git a/.gitignore b/.gitignore index d4073ad..c900259 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ debian/tmp node_modules package-lock.json .vscode +desktop.ini diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 135a6f2..256ef43 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,9 +10,9 @@ variables: # We have code in here for releasing on both GS and S3, control it through variables # on GitLab, do not change it in this file. # + GCLOUD_PROJECT_ID: "cent7-288417" GCLOUD_SERVICE_ACCOUNT: /dev/null - GCLOUD_RELEASE_DEPLOY_PATH: gs://download.gridtracker.org/release/$CI_COMMIT_TAG - GCLOUD_TESTING_DEPLOY_PATH: gs://download.gridtracker.org/testing/$CI_COMMIT_TAG + GCLOUD_DEPLOY_PATH: gs://gt_download/$CI_COMMIT_TAG NR0Q_SERVER_ADDRESS: "" NR0Q_SERVER_PASSWORD: "" @@ -86,15 +86,18 @@ win:package: mkdir -p artifacts echo -e "\e[0Ksection_start:`date +%s`:apt_get[collapsed=true]\r\e[0KGetting Build Dependencies" apt-get update && apt-get upgrade -y + apt-get install p7zip -y wget https://nsis.sourceforge.io/mediawiki/images/4/47/Registry.zip - unzip Registry.zip - mv Desktop/Plugin/registry.dll /usr/share/nsis/Plugins/x86-unicode/ - mv Desktop/Include/Registry.nsh /usr/share/nsis/Include/ - rm -Rf Desktop PocketPC Source - eval $(ssh-agent -s) - echo "$NR0Q_PRIV" | tr -d '\r' | ssh-add - - mkdir -p ~/.ssh; chmod 700 ~/.ssh - scp -o StrictHostKeyChecking=no mchambers@$NR0Q_SERVER_ADDRESS:~/codecert.spc ./ + unzip -bj Registry.zip Desktop/Plugin/registry.dll -d /usr/share/nsis/Plugins/x86-unicode/ + unzip -bj Registry.zip Desktop/Include/Registry.nsh -d /usr/share/nsis/Include/ + wget https://nsis.sourceforge.io/mediawiki/images/1/18/NsProcess.zip + 7zr e NsProcess.zip -y -o/usr/share/nsis/Include/ Include/nsProcess.nsh + 7zr e NsProcess.zip -y -o/usr/share/nsis/Plugins/x86-unicode/ Plugin/nsProcessW.dll + mv /usr/share/nsis/Plugins/x86-unicode/nsProcessW.dll /usr/share/nsis/Plugins/x86-unicode/nsProcess.dll + ## eval $(ssh-agent -s) + ## echo "$NR0Q_PRIV" | tr -d '\r' | ssh-add - + ## mkdir -p ~/.ssh; chmod 700 ~/.ssh + ## scp -o StrictHostKeyChecking=no -P $NR0Q_SSH_PORT mchambers@$NR0Q_SERVER_ADDRESS:~/codecert.spc ./ script: - | # Making our Windows packages @@ -104,30 +107,22 @@ win:package: npm install --prefer-offline npm run dist-win for dir in dist/*-win-* ; do - if [ -d $dir ] ; then - rm $dir/locales/*.info - mkdir $dir/package.nw - for file in package.nw/* ; do - mv $dir/`basename $file` $dir/package.nw - done - elif [ -f $dir ] && [[ "$dir" == *"win-x86-Setup.exe"* ]] ; then + if [ -f $dir ] && [[ "$dir" == *"-Setup.exe" ]] ; then echo "deleting broken installer $dir" rm $dir fi done # Now we need to sign the executable before it get's stuffed into Nullsoft # using mono signcode - signcode -spc codecert.spc -t http://time.certum.pl/ -a sha256 dist/GridTracker-*-win-*/*.exe + ## signcode -spc codecert.spc -t http://time.certum.pl/ -a sha256 dist/GridTracker-*-win-*/*.exe # Now the executable should be signed - sed "s#GridTracker-\${VERSION}-win-x86/#`pwd`/dist/GridTracker-\${VERSION}-win-x86/#g" windows/setup.nsi.tmpl > windows/setup.nsi.tmp.1 - sed "s#GridTracker-Installer.#`pwd`/dist/GridTracker-Installer.#g" windows/setup.nsi.tmp.1 > windows/setup.nsi.tmp.2 - sed "s#define VERSION windows/setup.nsi + sed "s##`node version.js`#g" windows/win_installer.nsi > windows/setup.nsi.tmp.1 + sed "s##`pwd`#g" windows/setup.nsi.tmp.1 > windows/setup.nsi makensis windows/setup.nsi # clean up generated files rm windows/setup.nsi rm windows/setup.nsi.tmp.1 - rm windows/setup.nsi.tmp.2 - signcode -spc codecert.spc -t http://time.certum.pl/ -a sha256 dist/GridTracker-Installer.*.exe + ## signcode -spc codecert.spc -t http://time.certum.pl/ -a sha256 dist/GridTracker-Installer.*.exe (cd dist ; mv GridTracker-Installer.*.exe ../artifacts) echo -e "\e[0Ksection_end:`date +%s`:native_build\e[0K" @@ -282,51 +277,20 @@ arm:package: echo "we made ARM packages!" ls -laR artifacts -# copy test assets to NR0Q's server -uploadtest: +# copy test assets to Google Storage +upload-Google: stage: deploy - image: alpine + image: google/cloud-sdk variables: GIT_STRATEGY: none rules: - - if: '$CI_COMMIT_TAG =~ /^(test_).*/ && $NR0Q_SERVER_KEY != ""' - before_script: - - | - apk add openssh-client - eval $(ssh-agent -s) - echo "$NR0Q_SERVER_KEY" | tr -d '\r' | ssh-add - - mkdir -p ~/.ssh; chmod 700 ~/.ssh + - if: '$CI_COMMIT_TAG =~ /^(v|test_).*/' script: - | - cd artifacts - for FILE in *.* - do - echo "Calculating MD5 Hash for $FILE" - md5sum $FILE > $FILE.md5 - done - ssh -o StrictHostKeyChecking=no gridtracker@$NR0Q_SERVER_ADDRESS "mkdir ~/$CI_COMMIT_TAG" && scp -o StrictHostKeyChecking=no -r ./* gridtracker@$NR0Q_SERVER_ADDRESS:~/$CI_COMMIT_TAG/ && ssh -o StrictHostKeyChecking=no gridtracker@$NR0Q_SERVER_ADDRESS "rm latest_test && ln -s $CI_COMMIT_TAG latest_test" - -# copy release assets to NR0Q's server -uploadrelease: - stage: deploy - image: alpine - rules: - - if: '$CI_COMMIT_TAG =~ /^(v).*/ && $NR0Q_SERVER_KEY != ""' - before_script: - - | - apk add openssh-client - eval $(ssh-agent -s) - echo "$NR0Q_SERVER_KEY" | tr -d '\r' | ssh-add - - mkdir -p ~/.ssh; chmod 700 ~/.ssh - script: - - | - cd artifacts - for FILE in *.* - do - echo "Calculating MD5 Hash for $FILE" - md5sum $FILE > $FILE.md5 - done - ssh -o StrictHostKeyChecking=no gridtracker@$NR0Q_SERVER_ADDRESS "mkdir ~/$CI_COMMIT_TAG" && scp -o StrictHostKeyChecking=no -r ./* gridtracker@$NR0Q_SERVER_ADDRESS:~/$CI_COMMIT_TAG/ + echo $GCP_SERVICE_KEY > gcloud-service-key.json + gcloud auth activate-service-account --key-file gcloud-service-key.json + gcloud config set project $GCLOUD_PROJECT_ID + gsutil -m cp -R artifacts/* $GCLOUD_DEPLOY_PATH/ # this only creates a "source code release" -- gitlab doesn't specify binaries # except as links to external storage, which is suboptimal for now @@ -346,7 +310,7 @@ sourcerelease: assets: links: - name: Release Packages for $CI_COMMIT_TAG - url: https://fleetwood.mchambersradio.com/gridtracker/$CI_COMMIT_TAG/ + url: https://https://storage.googleapis.com/gt_download/$CI_COMMIT_TAG/ external: true link_type: package script: @@ -355,8 +319,6 @@ sourcerelease: update_arch_aur: stage: deploy image: archlinux:base-devel - variables: - GIT_STRATEGY: none rules: # only do this with a manual tag starting with v - if: '$CI_COMMIT_TAG =~ /^v.*/ && $AUR_KEY != ""' @@ -386,7 +348,7 @@ update_arch_aur: sudo -u builder makepkg -si --noconfirm PKGBUILD # push the new version - | - makepkg --printsrcinfo > .SRCINFO + sudo -u builder makepkg --printsrcinfo > .SRCINFO git clone ssh://aur@aur.archlinux.org/gridtracker.git cp PKGBUILD gridtracker/PKGBUILD cp .SRCINFO gridtracker/.SRCINFO diff --git a/README.md b/README.md index 5d60858..bcba315 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Run `npm install` and then `npm start` Phoenix does not support ARM-based macs, so we have to explicitly tell it to use Intel-based versions of NWJS. -Run `npm install` and then `npm start-x64` +Run `npm install` and then `npm run start-x64` ## ARM-based Raspberry @@ -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/arch-linux/PKGBUILD.template b/arch-linux/PKGBUILD.template index 09f1f89..d83f614 100644 --- a/arch-linux/PKGBUILD.template +++ b/arch-linux/PKGBUILD.template @@ -8,7 +8,7 @@ pkgdesc="Companion program for WSJT-X for mapping contacts" arch=('x86_64') url="https://gridtracker.org/grid-tracker/" license=('BSD') -depends=('nwjs-bin>=0.48.0') +depends=('nwjs-bin>=0.54.0') replaces=('gridtracker-bin') source=("https://gitlab.com/gridtracker.org/$pkgname/-/archive/v$pkgver/$pkgname-v$pkgver.tar.gz") sha256sums=('REPLACE_WITH_SHASUM') diff --git a/debian/changelog b/debian/changelog index 1829cea..680fa9a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,27 @@ +gridtracker (1.22.0503) unstable; urgency=low + - Increment version for build with correct NWJS version + + -- Matthew Chambers Mon, 01 May 2022 16:07:00 -0000 + +gridtracker (1.22.0502) unstable; urgency=low + [Bug Fixes] + - Fixed broken Call Roster due to online assets being moved from a web server to Google Storage Bucket. + - Don't highlight "CQ" rows if filtering by "CQ Only". + - Resolved #126 Windows Installer script updated to fix issues with install location and missing registry keys + - Resolved #124 removing IP-Geolocation when no all other means of locating failed, we now tell the user to + start WSJT-X or enter a location as Geo-Location services are costly and unreliable + - Resolved #137 missing libatomic dependency in Linux DEB and RPM spec files + [Enhancements] + - Include version number in main window title + - Call Roster colums refactored and wanted column added + + -- Matthew Chambers Mon, 01 May 2022 02:25:40 -0000 + +gridtracker (1.21.1217) unstable; urgency=low + - Changed to newer NWJS to fix upstream bug that caused media playback to fail. + + -- Matthew Chambers Fri, 17 Dec 2021 20:08:00 -0000 + gridtracker (1.21.1212) unstable; urgency=low Release build with the call roster refactor code that's been in the works for some time. [Bug Fixes] diff --git a/docker/build-all.sh b/docker/build-all.sh index 269a4c8..ba02331 100755 --- a/docker/build-all.sh +++ b/docker/build-all.sh @@ -15,26 +15,18 @@ for dir in dist/*-linux-* ; do fi done for dir in dist/*-win-* ; do - if [ -d $dir ] ; then - mkdir $dir/package.nw - for file in package.nw/* ; do - mv $dir/`basename $file` $dir/package.nw - done - elif [ -f $dir ] && [[ "$dir" == *"win-x86-Setup.exe"* ]] ; then + if [ -f $dir ] && [[ "$dir" == *"-Setup.exe" ]] ; then echo "deleting broken installer $dir" rm $dir fi done -sed "s#GridTracker-\${VERSION}-win-x86/#`pwd`/dist/GridTracker-\${VERSION}-win-x86/#g" windows/setup.nsi.tmpl > windows/setup.nsi.tmp.1 -sed "s#GridTracker-Installer.#`pwd`/dist/GridTracker-Installer.#g" windows/setup.nsi.tmp.1 > windows/setup.nsi.tmp.2 -sed "s#define VERSION windows/setup.nsi - +sed "s##`node version.js`#g" windows/win_installer.nsi > windows/setup.nsi.tmp.1 +sed "s##`pwd`#g" windows/setup.nsi.tmp.1 > windows/setup.nsi makensis windows/setup.nsi # clean up generated files rm windows/setup.nsi rm windows/setup.nsi.tmp.1 -rm windows/setup.nsi.tmp.2 mv dist/*{.exe,mac-x64.zip,.tar.gz} ../dist rpmbuild -D "version `node ./version.js`" --build-in-place -bb gridtracker.i386.spec diff --git a/gridtracker.spec b/gridtracker.spec index d791545..77d6189 100644 --- a/gridtracker.spec +++ b/gridtracker.spec @@ -1,9 +1,9 @@ -Name: gridtracker +Name: {{{ git_name name=gridtracker }}} Summary: GridTracker: An amateur radio companion to WSJT-X or JTDX -Version: 1.21.1212 +Version: {{{ git_version lead=1.22.0503 }}} Release: 1%{?dist} BuildArch: noarch -Source0: %{name}-%{version}.tar.gz +Source0: {{{ git_dir_pack }}} License: BSD 3-Clause License URL: https://gridtracker.org @@ -19,7 +19,7 @@ working interesting stations. It also will upload QSO records to multiple logging frameworks including Logbook of the World. %prep -%setup -q GridTracker +{{{ git_dir_setup_macro }}} %build @@ -40,6 +40,21 @@ DESTDIR=${RPM_BUILD_ROOT} make clean %license %{_docdir}/%{name}/ %changelog +* Mon May 02 2022 Matthew Chambers - 1.22.0503-1 +- Increment version number for build with correct vesion of NWJS +* Mon May 02 2022 Matthew Chambers - 1.22.0502-1 +- [Bug Fixes] + - Fixed broken Call Roster due to online assets being moved from a web server to Google Storage Bucket. + - Don't highlight "CQ" rows if filtering by "CQ Only". + - Resolved #126 Windows Installer script updated to fix issues with install location and missing registry keys + - Resolved #124 removing IP-Geolocation when no all other means of locating failed, we now tell the user to + start WSJT-X or enter a location as Geo-Location services are costly and unreliable + - Resolved #137 missing libatomic dependency in Linux DEB and RPM spec files +- [Enhancements] + - Include version number in main window title + - Call Roster colums refactored and wanted column added +* Fri Dec 17 2021 Matthew Chambers - 1.21.1217-1 +- Changed to newer NWJS to fix upstream bug that caused media playback to fail. * Sun Dec 12 2021 Matthew Chambers - 1.21.1212-1 - Release build with the call roster refactor code that's been in the works for some time. - [Bug Fixes] diff --git a/package.json b/package.json index 40bcd6f..f5c940d 100644 --- a/package.json +++ b/package.json @@ -17,9 +17,7 @@ "dist-mac": "build --concurrent --tasks mac-x64 package.nw", "dist-win": "build --concurrent --tasks win-x86,win-x64 package.nw", "distsome": "build --debug --tasks linux-x64,mac-x64 package.nw", - "start": "run package.nw" - }, - "dependencies": { - "banana-i18n": "^2.1.0" + "start": "run package.nw", + "start-x64": "run --x64 package.nw" } } diff --git a/package.nw/GridTracker.html b/package.nw/GridTracker.html index 847c012..348bd39 100644 --- a/package.nw/GridTracker.html +++ b/package.nw/GridTracker.html @@ -788,6 +788,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. id="myTooltip" style=" -webkit-user-select: text; + user-select: text; background-color: black; padding: 5px; text-align: center; @@ -1103,7 +1104,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Print
@@ -3555,7 +3556,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >GridTracker.org!

-

Copyright © 2021 GridTracker.org

+

Copyright © 2022 GridTracker.org


@@ -3647,6 +3648,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

GridTracker is up to date!

OK
-
+
diff --git a/package.nw/data/acknowledgements.json b/package.nw/data/acknowledgements.json index e523949..159d816 100644 --- a/package.nw/data/acknowledgements.json +++ b/package.nw/data/acknowledgements.json @@ -1,96 +1,20 @@ { - "2M0SYH": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "A41MK": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "AA5KD": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "AD0WB": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "AE4ON": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, "AF2V": { "badge": "img/emojis/books.png", "message": "GridTracker Documentation" }, - "AI5CA": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "AJ6RX": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, "BD3OOX": { "badge": "img/emojis/speech.png", "message": "GridTracker Translator" }, - "CX4CD": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "DE1JPJ": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "DL6RA": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "DL9QB": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "EI8GS": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, "GI1MIC": { "badge": "img/emojis/pizza.png", "message": "GridTracker Tester" }, - "GM4SJB": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "HA5OLA": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "HB9HKE": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "HB9VKL": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, "HI80": { "badge": "img/emojis/speech.png", "message": "GridTracker Translator" }, - "I4SOI": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "IK0ZSN": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "IW2BUW": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, "IW3HMH": { "badge": "img/emojis/logbook.png", "message": "Creator of Log4OM" @@ -99,222 +23,42 @@ "badge": "img/emojis/books.png", "message": "GridTracker Documentation" }, - "K0GUZ": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, "K1JT": { "badge": "img/emojis/star.png", "message": "Creator of FT8 and WSJT-X" }, - "K2PF": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "K4KPG": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "K4TLS": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "K5DCC": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, "K5TUX": { "badge": "img/emojis/penguin.png", "message": "GridTracker Partner" }, - "K6WRF": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "K7CGA": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "K7YD": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "K8VSY": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, "K9AN": { "badge": "img/emojis/star.png", "message": "Co-Creator of FT8" }, - "K9BAW": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "K9MIH": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, "KA0AZS": { "badge": "img/emojis/pizza.png", "message": "GridTracker Tester" }, - "KA4JON": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KA7JAZ": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KB2BK": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, "KB2YSI": { "badge": "img/emojis/coffee.png", "message": "GridTracker Developer" }, - "KB4RSM": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KB5ITC": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KB5KUY": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KC4HN": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KC7ZXY": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, "KD0YTE": { "badge": "img/emojis/pizza.png", "message": "GridTracker Tester" }, - "KD9QGP": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, "KE0UL": { "badge": "img/emojis/grandfather.png", "message": "GridTracker's Grandfather" }, - "KE1Q": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KE4GNB": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KE4WLE": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KE8HIM": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, "KF5QHQ": { "badge": "img/emojis/trophy.png", "message": "GridTracker Developer" }, - "KG5RJ": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KI0Y": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, "KI2D": { "badge": "img/emojis/flatbread.png", "message": "GridTracker Developer" }, - "KJ6RJY": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KJ7KRN": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KK4WZI": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KL4NE": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KM3T": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KM4RL": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KM4TY": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KM5GN": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KM6JS": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KM6LBW": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KN4YZY": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KN6NCT": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KNC6EWM": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KO4BCN": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KQ4Y": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "KW4AU": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "LA6YJA": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "LU7DK": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "N0GTO": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, "N0TTL": { "badge": "img/emojis/star.png", "message": "Creator of GridTracker" @@ -327,122 +71,10 @@ "badge": "img/emojis/books.png", "message": "GridTracker Documentation" }, - "N3TQM": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "N3UGI": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "N4MCC": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "N4SFS": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "N6GEB": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "N7HQ": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "N8VWQ": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, "NR0Q": { "badge": "img/emojis/coffee.png", "message": "GridTracker Developer" }, - "OH1LEU": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "OH3NZW": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "ON4VT": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "ON7IVE": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "OZ1LNR": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "OZ8QI": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "PA0LMA": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "PD9DP": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "SM0ONR": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "SV2RIM": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "VA3DJL": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "VA7CND": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "VE3FMQ": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "VE3HNA": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "VE4MAR": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "VE7LGP": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "VK2WJ": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "VK4OO": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "W0SP": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "W0YRE": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "W4DHK": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, "W4IPA": { "badge": "img/emojis/beer-mug.png", "message": "GridTracker Tester" @@ -451,60 +83,8 @@ "badge": "img/emojis/pizza.png", "message": "GridTracker Tester" }, - "W6FVO": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "W8PSP": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "W9LL": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "W9VZR": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "WA2LAN": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, "WA4YA": { "badge": "img/emojis/trophy.png", "message": "GridTracker Developer" - }, - "WA6JQB": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "WA8P": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "WB0SMX": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "WB5WAJ": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "WB6RJH": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "WD5FBW": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "WS4S": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" - }, - "ZL4CAT": { - "badge": "img/emojis/money-bag.png", - "message": "GridTracker Donor" } } \ No newline at end of file diff --git a/package.nw/gt_roster.html b/package.nw/gt_roster.html index 0fb7480..ef0b639 100644 --- a/package.nw/gt_roster.html +++ b/package.nw/gt_roster.html @@ -28,6 +28,8 @@ + + diff --git a/package.nw/lib/adif.js b/package.nw/lib/adif.js index 082151a..d52236d 100644 --- a/package.nw/lib/adif.js +++ b/package.nw/lib/adif.js @@ -1,4 +1,4 @@ -// GridTracker Copyright © 2021 GridTracker.org +// GridTracker Copyright © 2022 GridTracker.org // All rights reserved. // See LICENSE for more information. @@ -607,9 +607,13 @@ function lotwCallback(buffer, flag) if (lotwQSHeader !== null) { if (lotwQSHeader[1].toUpperCase() == "QSORX") - { g_adifLogSettings.lastFetch.lotw_qso = lotwQSHeader[2] } - elseif(lotwQSHeader[1].toUpperCase() == "QSL") - g_adifLogSettings.lastFetch.lotw_qsl = lotwQSHeader[2]; + { + g_adifLogSettings.lastFetch.lotw_qso = lotwQSHeader[2] + } + else if (lotwQSHeader[1].toUpperCase() == "QSL") + { + g_adifLogSettings.lastFetch.lotw_qsl = lotwQSHeader[2]; + } } rawAdiBuffer = cleanAndPrepADIF( @@ -663,39 +667,86 @@ var g_isGettingLOTW = false; function grabLOtWLog(test) { - var dLoTWQSO = Date.parse(g_adifLogSettings.lastFetch.lotw_qso); - var dLoTWQSL = Date.parse(g_adifLogSettings.lastFetch.lotw_qsl); - var tmpDate = ((new Date().getTime()) - 300); + var lastQSLDateString = ""; - // Be nice to LoTW and only fetch if last fetch was > 5 mins ago - if ((g_isGettingLOTW == false) && - (((isNaN(dLoTWQSO) == false) && (dLoTWQSO < tmpDate)) || - ((isNaN(dLoTWQSL) == false) && (dLoTWQSL < tmpDate)) - )) + if (test == true && g_isGettingLOTW == false) { - var lastQSLDateString = - "&qso_qsorxsince=" + g_adifLogSettings.lastFetch.lotw_qso + - "&qso_qslsince=" + g_adifLogSettings.lastFetch.lotw_qsl; - if (test == true) - { - lotwTestResult.innerHTML = "Testing"; - lastQSLDateString = "&qso_qsosince=2100-01-01"; - } + lotwTestResult.innerHTML = "Testing"; + lastQSLDateString = "&qso_qsosince=2100-01-01"; - // Fetch QSOs + // Fetch Test Results getABuffer( "https://lotw.arrl.org/lotwuser/lotwreport.adi?login=" + - lotwLogin.value + - "&password=" + - encodeURIComponent(lotwPassword.value) + - "&qso_query=1&qso_qsl=no&qso_qsldetail=yes&qso_withown=yes" + - lastQSLDateString, + lotwLogin.value + + "&password=" + + encodeURIComponent(lotwPassword.value) + + "&qso_query=1&qso_qsl=no&qso_qsldetail=yes&qso_withown=yes" + + lastQSLDateString, lotwCallback, test, "https", 443, lotwLogImg, "g_isGettingLOTW", + 150000 + ); + } + + if (test == false) + { + setTimeout(grabLoTWQSO, 500); + setTimeout(grabLoTWQSL, 10000); + } +} + +function grabLoTWQSO() +{ + var dLoTWQSO = Date.parse(dateToISO8601(g_adifLogSettings.lastFetch.lotw_qso, "Z")); + var tmpDate = ((new Date().getTime()) - 300); + + if ((g_isGettingLOTW == false) && ((isNaN(dLoTWQSO) == false) && (dLoTWQSO < tmpDate))) + { + // Fetch QSOs + lastQSLDateString = "&qso_qsorxsince=" + g_adifLogSettings.lastFetch.lotw_qso; + getABuffer( + "https://lotw.arrl.org/lotwuser/lotwreport.adi?login=" + + lotwLogin.value + + "&password=" + + encodeURIComponent(lotwPassword.value) + + "&qso_query=1&qso_qsl=no&qso_qsldetail=yes&qso_withown=yes" + + lastQSLDateString, + lotwCallback, + false, + "https", + 443, + lotwLogImg, + "g_isGettingLOTW", + 120000 + ); + } +} + +function grabLoTWQSL() +{ + var dLoTWQSL = Date.parse(dateToISO8601(g_adifLogSettings.lastFetch.lotw_qsl, "Z")); + var tmpDate = ((new Date().getTime()) - 300); + + if ((g_isGettingLOTW == false) && ((isNaN(dLoTWQSL) == false) && (dLoTWQSL < tmpDate))) + { + lastQSLDateString = "&qso_qslsince=" + g_adifLogSettings.lastFetch.lotw_qsl; + getABuffer( + "https://lotw.arrl.org/lotwuser/lotwreport.adi?login=" + + lotwLogin.value + + "&password=" + + encodeURIComponent(lotwPassword.value) + + "&qso_query=1&qso_qsl=yes&qso_qsldetail=yes&qso_withown=yes" + + lastQSLDateString, + lotwCallback, + false, + "https", + 443, + lotwLogImg, + "g_isGettingLOTW", 120000 ); @@ -1457,11 +1508,6 @@ function getABuffer( }) .on("end", function () { - if (typeof callback === "function") - { - // Call it, since we have confirmed it is callable - callback(fileBuffer, flag, cookies); - } if (typeof stringOfFlag != "undefined") { window[stringOfFlag] = false; @@ -1471,6 +1517,11 @@ function getABuffer( imgToGray.parentNode.style.background = ""; imgToGray.style.webkitFilter = ""; } + if (typeof callback === "function") + { + // Call it, since we have confirmed it is callable + callback(fileBuffer, flag, cookies); + } }) .on("error", function () { @@ -1638,7 +1689,7 @@ function sendTcpMessage(msg, length, port, address) client.setTimeout(30000); client.connect(port, address, function () { - client.write(msg); + client.write(Buffer.from(msg, "utf-8")); }); client.on("close", function () {}); @@ -1647,7 +1698,7 @@ function sendTcpMessage(msg, length, port, address) function valueToAdiField(field, value) { var adi = "<" + field + ":"; - adi += String(value).length + ">"; + adi += Buffer.byteLength(String(value)) + ">"; adi += String(value) + " "; return adi; } @@ -1927,7 +1978,7 @@ function finishSendingReport(record, localMode) for (let key in record) { - report += "<" + key + ":" + record[key].length + ">" + record[key] + " "; + report += "<" + key + ":" + Buffer.byteLength(record[key]) + ">" + record[key] + " "; } report += ""; @@ -2109,7 +2160,7 @@ function finishSendingReport(record, localMode) for (var key in record) { report += - "<" + key + ":" + record[key].length + ">" + record[key] + " "; + "<" + key + ":" + Buffer.byteLength(record[key]) + ">" + record[key] + " "; } report += ""; } diff --git a/package.nw/lib/callsigns.js b/package.nw/lib/callsigns.js index d6916f0..4ab078d 100644 --- a/package.nw/lib/callsigns.js +++ b/package.nw/lib/callsigns.js @@ -279,7 +279,7 @@ function oqrsDownload(fromSettings) { oqrsUpdatedTd.innerHTML = "Downloading..."; getBuffer( - "http://app.gridtracker.org/callsigns/clublog.json", + "https://storage.googleapis.com/gt_app/callsigns/clublog.json", processoqrsCallsigns, null, "http", @@ -539,7 +539,7 @@ function ulsDownload() ulsUpdatedTd.innerHTML = "Downloading..."; ulsCountTd.innerHTML = 0; getChunkedBuffer( - "http://app.gridtracker.org/callsigns/callsigns.txt", + "https://storage.googleapis.com/gt_app/callsigns/callsigns.txt", processulsCallsigns, null, "http", diff --git a/package.nw/lib/datepicker.js b/package.nw/lib/datepicker.js index 0c871f5..0186901 100644 --- a/package.nw/lib/datepicker.js +++ b/package.nw/lib/datepicker.js @@ -1,3 +1,9 @@ +// FIXME ****************************************************************************** // +// The datepicker's "Time" section doesn't work. This really needs to be fixed before +// the next big RTTY Roundup or Field Day where there may be a lot of hams that want +// to use this feature to only reference their log starting when the contest starts. +// Which isn't always 00:00 UTC. +// ************************************************************************************ // var picker = { attach: function (opt) { diff --git a/package.nw/lib/defaults.js b/package.nw/lib/defaults.js index 51a9bee..c0c4594 100644 --- a/package.nw/lib/defaults.js +++ b/package.nw/lib/defaults.js @@ -1,265 +1,266 @@ -var validSettings = [ - "HRDLogbookLogSettings", - "N1MMSettings", - "acLogSettings", - "adifLogSettings", - "alertSettings", - "appSettings", - "audioSettings", - "awardTracker", - "bandActivity", - "blockedCQ", - "blockedCalls", - "blockedDxcc", - "callsignLookups", - "classicAlerts", - "classicAlertsVersion", - "currentVersion", - "dxkLogSettings", - "log4OMSettings", - "mapMemory", - "mapSettings", - "msgSettings", - "receptionSettings", - "rosterSettings", - "savedAlerts", - "speechSettings", - "startupLogs", - "trustedQslSettings", - "screenSettings", - "legendColors" -]; - -var def_appSettings = { - alertMute: 0, - rosterAlwaysOnTop: false, - centerGridsquare: "", - chatUUID: "", - crScript: 0, - distanceUnit: "MI", - earthImgSrc: 0, - gridViewMode: 3, - gridsquareDecayTime: 300, - gtAgree: "", - gtBandFilter: "", - gtFlagImgSrc: 0, - gtModeFilter: "", - gtPropFilter: "mixed", - gtMsgEnable: true, - gtShareEnable: true, - heatEnabled: 0, - loadAdifAtStartup: false, - lookupLoginCq: "", - lookupLoginQrz: "", - lookupLoginQth: "", - lookupOnTx: false, - lookupCloseLog: false, - lookupMerge: true, - lookupMissingGrid: false, - lookupPasswordCq: "", - lookupPasswordQrz: "", - lookupPasswordQth: "", - lookupService: "CALLOOK", - lookupCallookPreferred: false, - moonPath: 0, - moonTrack: 0, - mouseTrack: 0, - multicast: false, - myBand: "OOB", - myDEGrid: "", - myDEcall: "NOCALL", - myMode: "", - myRawCall: "NOCALL", - myRawFreq: "", - myRawGrid: "", - pathWidthWeight: 1.0, - pushPinMode: false, - qrzPathWidthWeight: 1.2, - sixWideMode: 0, - savedAppData: null, - soundCard: "default", - spotsEnabled: 0, - stopAskingVersion: false, - useLocalTime: 0, - wsjtForwardUdpEnable: false, - wsjtForwardUdpIp: "127.0.0.1", - wsjtForwardUdpPort: 2238, - wsjtIP: "", - wsjtUdpPort: 0, - workingCallsignEnable: false, - workingCallsigns: {}, - workingDateEnable: false, - workingDate: 0, - gtSpotEnable: true -}; - -var def_mapSettings = { - animate: true, - animateSpeed: 4, - CQhilite: true, - fitQRZ: false, - focusRig: true, - gridAlpha: 136, - haltAllOnTx: true, - legend: true, - longitude: 0.0, - latitude: 0.0, - loudness: 1, - mapIndex: 19, - mergeOverlay: false, - mouseOver: true, - nightLoudness: 0.8, - nightMapEnable: false, - nightMapIndex: 20, - nightPathColor: 361, - nightQrzPathColor: 1, - offlineMode: false, - pathColor: 0, - qrzDxccFallback: false, - qrzPathColor: 1, - rosterTime: 120, - shadow: 0.1, - splitQSL: true, - strikes: false, - strikesAlert: 2, - strikesGlobal: false, - strikesNotify: false, - trafficDecode: true, - usNexrad: false, - zoom: 4, - mapTrans: 0.5 -}; - -var def_adifLogSettings = { - menu: { - buttonAdifCheckBox: false, - buttonClubCheckBox: false, - buttonLOTWCheckBox: false, - buttonQRZCheckBox: false, - buttonPsk24CheckBox: true - }, - startup: { - loadAdifCheckBox: false, - loadPsk24CheckBox: false, - loadQRZCheckBox: false, - loadLOTWCheckBox: false, - loadClubCheckBox: false, - loadGTCheckBox: true - }, - qsolog: { - logQRZqsoCheckBox: false, - logGTqsoCheckBox: true, - logLOTWqsoCheckBox: false, - logHRDLOGqsoCheckBox: false, - logClubqsoCheckBox: false, - logCloudlogQSOCheckBox: false, - logeQSLQSOCheckBox: false - }, - nickname: { - nicknameeQSLCheckBox: false - }, - text: { - lotwLogin: "", - clubCall: "", - clubEmail: "", - clubPassword: "", - lotwPassword: "", - lotwTrusted: "", - lotwStation: "", - qrzApiKey: "", - HRDLOGCallsign: "", - HRDLOGUploadCode: "", - CloudlogURL: "http://127.0.0.1/index.php/api/qso", - CloudlogAPI: "", - eQSLUser: "", - eQSLPassword: "", - eQSLNickname: "" - }, - downloads: {}, - lastFetch: { - lotw_qso: "1970-01-01", - lotw_qsl: "1970-01-01" - } -}; - -var def_msgSettings = { - msgAlertSelect: 1, - msgAlertWord: "New chat message", - msgAlertMedia: "none", - msgFrequencySelect: 0, - msgActionSelect: 1, - msgAwaySelect: 0, - msgAwayText: "I am away from the shack at the moment" -}; - -var def_receptionSettings = { - lastSequenceNumber: "0", // Treat as a string, it's friggin big - lastDownloadTimeSec: 0, - viewHistoryTimeSec: 900, - viewPaths: false, - pathColor: -1, - pathNightColor: 361, - spotWidth: 0.8, - mergeSpots: true -}; - -var def_N1MMSettings = { - enable: false, - port: 2333, - ip: "127.0.0.1" -}; -var def_log4OMSettings = { - enable: false, - port: 2236, - ip: "127.0.0.1" -}; -var def_dxkLogSettings = { - enable: false, - port: 52000, - ip: "127.0.0.1" -}; -var def_HRDLogbookLogSettings = { - enable: false, - port: 7826, - ip: "127.0.0.1" -}; -var def_acLogSettings = { - enable: false, - port: 1100, - ip: "127.0.0.1" -}; -var def_trustedQslSettings = { - stationFile: "", - stationFileValid: false, - binaryFile: "", - binaryFileValid: false -}; -var def_callsignLookups = { - lotwUseEnable: true, - lotwWeeklyEnable: true, - lotwLastUpdate: 0, - eqslUseEnable: true, - eqslWeeklyEnable: true, - eqslLastUpdate: 0, - ulsUseEnable: true, - ulsWeeklyEnable: true, - ulsLastUpdate: 0, - oqrsUseEnable: false, - oqrsWeeklyEnable: false, - oqrsLastUpdate: 0 -}; - -var def_bandActivity = { - lastUpdate: {}, - lines: {} -}; - -var def_legendColors = { - QSO: "#EEEE00", - QSL: "#EE0000", - QSX: "#1111EE", - CQ: "#00FF00", - CQDX: "#00FFFF", - QRZ: "#FFFF00", - QTH: "#FFA600" -}; +var validSettings = [ + "HRDLogbookLogSettings", + "N1MMSettings", + "acLogSettings", + "adifLogSettings", + "alertSettings", + "appSettings", + "audioSettings", + "awardTracker", + "bandActivity", + "blockedCQ", + "blockedCalls", + "blockedDxcc", + "callsignLookups", + "classicAlerts", + "classicAlertsVersion", + "currentVersion", + "dxkLogSettings", + "log4OMSettings", + "mapMemory", + "mapSettings", + "msgSettings", + "receptionSettings", + "rosterSettings", + "savedAlerts", + "speechSettings", + "startupLogs", + "trustedQslSettings", + "screenSettings", + "legendColors" +]; + +var def_appSettings = { + alertMute: 0, + rosterAlwaysOnTop: false, + centerGridsquare: "", + chatUUID: "", + crScript: 0, + distanceUnit: "MI", + earthImgSrc: 0, + gridViewMode: 3, + gridsquareDecayTime: 300, + gtAgree: "", + gtBandFilter: "", + gtFlagImgSrc: 0, + gtModeFilter: "", + gtPropFilter: "mixed", + gtMsgEnable: true, + gtShareEnable: true, + heatEnabled: 0, + loadAdifAtStartup: false, + lookupLoginCq: "", + lookupLoginQrz: "", + lookupLoginQth: "", + lookupOnTx: false, + lookupCloseLog: false, + lookupMerge: true, + lookupMissingGrid: false, + lookupPasswordCq: "", + lookupPasswordQrz: "", + lookupPasswordQth: "", + lookupService: "CALLOOK", + lookupCallookPreferred: false, + clearRosterOnBandChange: false, + moonPath: 0, + moonTrack: 0, + mouseTrack: 0, + multicast: false, + myBand: "OOB", + myDEGrid: "", + myDEcall: "NOCALL", + myMode: "", + myRawCall: "NOCALL", + myRawFreq: "", + myRawGrid: "", + pathWidthWeight: 1.0, + pushPinMode: false, + qrzPathWidthWeight: 1.2, + sixWideMode: 0, + savedAppData: null, + soundCard: "default", + spotsEnabled: 0, + stopAskingVersion: false, + useLocalTime: 0, + wsjtForwardUdpEnable: false, + wsjtForwardUdpIp: "127.0.0.1", + wsjtForwardUdpPort: 2238, + wsjtIP: "", + wsjtUdpPort: 0, + workingCallsignEnable: false, + workingCallsigns: {}, + workingDateEnable: false, + workingDate: 0, + gtSpotEnable: true +}; + +var def_mapSettings = { + animate: true, + animateSpeed: 4, + CQhilite: true, + fitQRZ: false, + focusRig: true, + gridAlpha: 136, + haltAllOnTx: true, + legend: true, + longitude: 0.0, + latitude: 0.0, + loudness: 1, + mapIndex: 19, + mergeOverlay: false, + mouseOver: true, + nightLoudness: 0.8, + nightMapEnable: false, + nightMapIndex: 20, + nightPathColor: 361, + nightQrzPathColor: 1, + offlineMode: false, + pathColor: 0, + qrzDxccFallback: false, + qrzPathColor: 1, + rosterTime: 120, + shadow: 0.1, + splitQSL: true, + strikes: false, + strikesAlert: 2, + strikesGlobal: false, + strikesNotify: false, + trafficDecode: true, + usNexrad: false, + zoom: 4, + mapTrans: 0.5 +}; + +var def_adifLogSettings = { + menu: { + buttonAdifCheckBox: false, + buttonClubCheckBox: false, + buttonLOTWCheckBox: false, + buttonQRZCheckBox: false, + buttonPsk24CheckBox: true + }, + startup: { + loadAdifCheckBox: false, + loadPsk24CheckBox: false, + loadQRZCheckBox: false, + loadLOTWCheckBox: false, + loadClubCheckBox: false, + loadGTCheckBox: true + }, + qsolog: { + logQRZqsoCheckBox: false, + logGTqsoCheckBox: true, + logLOTWqsoCheckBox: false, + logHRDLOGqsoCheckBox: false, + logClubqsoCheckBox: false, + logCloudlogQSOCheckBox: false, + logeQSLQSOCheckBox: false + }, + nickname: { + nicknameeQSLCheckBox: false + }, + text: { + lotwLogin: "", + clubCall: "", + clubEmail: "", + clubPassword: "", + lotwPassword: "", + lotwTrusted: "", + lotwStation: "", + qrzApiKey: "", + HRDLOGCallsign: "", + HRDLOGUploadCode: "", + CloudlogURL: "http://127.0.0.1/index.php/api/qso", + CloudlogAPI: "", + eQSLUser: "", + eQSLPassword: "", + eQSLNickname: "" + }, + downloads: {}, + lastFetch: { + lotw_qso: "1970-01-01", + lotw_qsl: "1970-01-01" + } +}; + +var def_msgSettings = { + msgAlertSelect: 1, + msgAlertWord: "New chat message", + msgAlertMedia: "none", + msgFrequencySelect: 0, + msgActionSelect: 1, + msgAwaySelect: 0, + msgAwayText: "I am away from the shack at the moment" +}; + +var def_receptionSettings = { + lastSequenceNumber: "0", // Treat as a string, it's friggin big + lastDownloadTimeSec: 0, + viewHistoryTimeSec: 900, + viewPaths: false, + pathColor: -1, + pathNightColor: 361, + spotWidth: 0.8, + mergeSpots: true +}; + +var def_N1MMSettings = { + enable: false, + port: 2333, + ip: "127.0.0.1" +}; +var def_log4OMSettings = { + enable: false, + port: 2236, + ip: "127.0.0.1" +}; +var def_dxkLogSettings = { + enable: false, + port: 52000, + ip: "127.0.0.1" +}; +var def_HRDLogbookLogSettings = { + enable: false, + port: 7826, + ip: "127.0.0.1" +}; +var def_acLogSettings = { + enable: false, + port: 1100, + ip: "127.0.0.1" +}; +var def_trustedQslSettings = { + stationFile: "", + stationFileValid: false, + binaryFile: "", + binaryFileValid: false +}; +var def_callsignLookups = { + lotwUseEnable: true, + lotwWeeklyEnable: true, + lotwLastUpdate: 0, + eqslUseEnable: true, + eqslWeeklyEnable: true, + eqslLastUpdate: 0, + ulsUseEnable: true, + ulsWeeklyEnable: true, + ulsLastUpdate: 0, + oqrsUseEnable: false, + oqrsWeeklyEnable: false, + oqrsLastUpdate: 0 +}; + +var def_bandActivity = { + lastUpdate: {}, + lines: {} +}; + +var def_legendColors = { + QSO: "#EEEE00", + QSL: "#EE0000", + QSX: "#1111EE", + CQ: "#00FF00", + CQDX: "#00FFFF", + QRZ: "#FFFF00", + QTH: "#FFA600" +}; diff --git a/package.nw/lib/gt.js b/package.nw/lib/gt.js index a0e1114..1172023 100644 --- a/package.nw/lib/gt.js +++ b/package.nw/lib/gt.js @@ -2,28 +2,14 @@ // All rights reserved. // See LICENSE for more information. const pjson = require("./package.json"); -var gtVersion = parseInt(pjson.version.replace(/\./g, "")); +var gtVersionStr = pjson.version +var gtVersion = parseInt(gtVersionStr.replace(/\./g, "")); var gtBeta = pjson.betaVersion; var banana = require("../../node_modules/banana-i18n/dist/banana-i18n.js"); var g_startVersion = 0; if (typeof localStorage.currentVersion != "undefined") { g_startVersion = localStorage.currentVersion; } -// const messages = { -// 'en': { -// 'appname-sub-title': 'Example Application' -// }, -// 'ru' : { -// 'appname-sub-title': 'Демонстрационное приложение' -// }, -// 'zn' : { -// 'appname-sub-title': '业余无线电数据通信助手' -// } -// }; - -// const banana = new Banana('en'); -// banana.load(messages); - if ( typeof localStorage.currentVersion == "undefined" || localStorage.currentVersion != String(gtVersion) @@ -132,14 +118,6 @@ function loadAllSettings() def_adifLogSettings ); g_msgSettings = loadDefaultsAndMerge("msgSettings", def_msgSettings); - // one-time override of oams pop-up messages: if pop-ups disabled - // and new version, reset msgActionSelect to 1 (pop up) - if (g_msgSettings.msgActionSelect == 0 && - String(gtVersion) != String(g_startVersion)) - { - g_msgSettings.msgActionSelect = 1; - localStorage.msgSettings = JSON.stringify(g_msgSettings); - } g_receptionSettings = loadDefaultsAndMerge( "receptionSettings", def_receptionSettings @@ -1114,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; @@ -1134,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 = "-"; @@ -1175,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; } @@ -3124,30 +3106,23 @@ function makeTitleInfo(mapWindow) ? myMode : g_appSettings.gtModeFilter; var space = " "; - var news = "GridTracker [Band: " + band + " Mode: " + mode; + var news = `GridTracker ${gtVersionStr} [Band: ${band} Mode: ${mode}`; var end = "]"; if (mapWindow) { - news += " Layer: " + g_viewInfo[g_currentOverlay][1]; + news += ` Layer: ${g_viewInfo[g_currentOverlay][1]}`; } if (g_currentOverlay == 0 && g_appSettings.gridViewMode == 1) { return news + end; } - var workline = - " - Worked " + - g_viewInfo[g_currentOverlay][2] + - " Confirmed " + - g_viewInfo[g_currentOverlay][3]; + var workline = ` - Worked ${g_viewInfo[g_currentOverlay][2]} Confirmed ${g_viewInfo[g_currentOverlay][3]}` if ( g_viewInfo[g_currentOverlay][2] <= g_viewInfo[g_currentOverlay][4] && g_viewInfo[g_currentOverlay][4] > 0 ) { - end = - " Needed " + - (g_viewInfo[g_currentOverlay][4] - g_viewInfo[g_currentOverlay][2]) + - "]"; + end = ` Needed ${(g_viewInfo[g_currentOverlay][4] - g_viewInfo[g_currentOverlay][2])}]`; } return news + workline + end; } @@ -5141,7 +5116,7 @@ function clearLogFilesAndCounts() g_adifLogSettings.downloads = {}; g_adifLogSettings.lastFetch.lotw_qso = "1940-01-01"; g_adifLogSettings.lastFetch.lotw_qsl = "1940-01-01"; - localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); + saveAdifSettings(); } function getCurrentBandModeHTML() @@ -10099,7 +10074,7 @@ function renderStatsBox() worker += "
In Section: " + scoreSection + - "
Error Generating Stats
Please take a screenshot and send to gridtracker@gmail.com"; + "
Error Generating Stats
Please take a screenshot and send to team@gridtracker.org"; } setStatsDiv("statViewDiv", worker); @@ -11170,7 +11145,7 @@ function checkForNewVersion(showUptoDate) if (typeof nw != "undefined") { getBuffer( - "http://app.gridtracker.org/version.txt?lang=", + "https://storage.googleapis.com/gt_app/version.txt", versionCheck, showUptoDate, "http", @@ -11179,15 +11154,20 @@ function checkForNewVersion(showUptoDate) } } -function checkForNewAcks() +function downloadAcknowledgements() { - getBuffer( - "http://app.gridtracker.org/acknowledgements.json?lang=" + g_localeString, - updateAcks, - null, - http, - 80 - ); + if (g_mapSettings.offlineMode == false) + { + getBuffer( + "https://storage.googleapis.com/gt_app/acknowledgements.json", + updateAcks, + null, + "http", + 80 + ); + + setTimeout(downloadAcknowledgements, 8640000); + } } function renderBandActivity() @@ -11329,7 +11309,13 @@ function pskBandActivityCallback(buffer, flag) renderBandActivity(); } - +/* FIXME ****************************************************************************** + Should we somewhere in settings, have a checkbox to enable / disable PSK spots + specifically? We can disable the overall spots, both PSK and OAMS, and OAMS has a + checkbox in the OAMS tab. I'm thinking for the situation where I only want to + pull in OAMS spots and not PSK reporter's spots. + ************************************************************************************ +*/ function pskGetBandActivity() { if (g_mapSettings.offlineMode == true) return; @@ -11593,14 +11579,7 @@ function updateBasedOnIni() { if (typeof nw != "undefined") { - // lets see if we can find our location the hard way - getBuffer( - "https://api.ipstack.com/check?access_key=8c9233ec1c09861a707951ab3718a7f6&format=1", - ipLocation, - null, - "https", - 443 - ); + alert("Location not available!\nEither start WSJT-X/JTDX or enter your grid square in the settings "); } } } @@ -12078,27 +12057,6 @@ function selectElementContents(el) } } -function ipLocation(buffer, flag) -{ - var obj = JSON.parse(buffer); - if ( - typeof obj != "undefined" && - obj != null && - typeof obj.latitude != "undefined" - ) - { - g_appSettings.centerGridsquare = latLonToGridSquare( - obj.latitude, - obj.longitude - ).substr(0, 6); - if (g_appSettings.centerGridsquare.length > 0) - { - homeQTHInput.value = g_appSettings.centerGridsquare; - if (ValidateGridsquare(homeQTHInput, null)) setCenterGridsquare(); - } - } -} - function popupNewWindows() { if (typeof nw != "undefined") @@ -12741,8 +12699,29 @@ function versionCheck(buffer, flag) function updateAcks(buffer) { - g_acks = JSON.parse(buffer); - fs.writeFileSync("./data/acknowledgements.json", JSON.stringify(g_acks)); + try + { + g_acknowledgedCalls = JSON.parse(buffer); + } + catch (e) + { + // can't write, somethings broke + } +} + +function readAcksFromDisk() +{ + try + { + var fileBuf = fs.readFileSync(g_NWappData + "acknowledgements.json"); + var loadedData = JSON.parse(fileBuf); + // some validation here? + g_acknowledgedCalls = loadedData; + } + catch (e) + { + // file failed to load, probably not downloaded + } } function onExitAppToGoWebsite() @@ -14608,6 +14587,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..544d384 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; @@ -1308,7 +1160,7 @@ function stateChangedValue(what) { let callState = r_currentUSState.replace("CN-", ""); getBuffer( - "http://app.gridtracker.org/callsigns/" + callState + ".callsigns.json", + "https://storage.googleapis.com/gt_app/callsigns/" + callState + ".callsigns.json", callsignResult, r_currentUSState, "http", @@ -1674,7 +1526,7 @@ function init() if (window.opener.g_mapSettings.offlineMode == false) { getBuffer( - "http://app.gridtracker.org/callsigns/manifest.json", + "https://storage.googleapis.com/gt_app/callsigns/manifest.json", manifestResult, null, "http", @@ -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 6805969..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 @@ -652,7 +652,7 @@ function processRosterHunting(callRoster, rosterSettings) callingBg = "#0000FF" + inversionAlpha; calling = "#FFFF00;text-shadow: 0px 0px 2px #FFFF00"; } - else if (callObj.CQ == true) + else if (callObj.CQ == true && !g_rosterSettings.cqOnly) { callingBg = calling + inversionAlpha; calling = bold; 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 = ""; + let html = "
" + html = html + columns.map(column => renderHeaderForColumn(column)).join("\n") + html = html + "" - worker += ""; - - if (showBands) - { worker += ""; } - - if (showModes) - { worker += ""; } - - worker += ""; - - if (g_rosterSettings.columns.Calling) - { worker += ""; } - - if (g_rosterSettings.columns.Msg) - { worker += ""; } - - if (g_rosterSettings.columns.DXCC) - { worker += ""; } - - if (g_rosterSettings.columns.Flag) - { worker += ""; } - - if (g_rosterSettings.columns.State) - { worker += ""; } - - if (g_rosterSettings.columns.County) - { worker += ""; } - - if (g_rosterSettings.columns.Cont) - { worker += ""; } - - if (g_rosterSettings.columns.dB) - { worker += ""; } - - if (g_rosterSettings.columns.Freq) - { worker += ""; } - - if (g_rosterSettings.columns.DT) - { worker += ""; } - - if (g_rosterSettings.columns.Dist) - { - worker += ""; - } - - if (g_rosterSettings.columns.Azim) - { worker += ""; } - - if (g_rosterSettings.columns.CQz) - { worker += ""; } - - if (g_rosterSettings.columns.ITUz) - { worker += ""; } - - if (g_rosterSettings.columns.PX) - { worker += ""; } - - if (window.opener.g_callsignLookups.lotwUseEnable == true && g_rosterSettings.columns.LoTW) - { worker += ""; } - - if (window.opener.g_callsignLookups.eqslUseEnable == true && g_rosterSettings.columns.eQSL) - { worker += ""; } - - if (window.opener.g_callsignLookups.oqrsUseEnable == true && g_rosterSettings.columns.OQRS) - { worker += ""; } - - if (g_rosterSettings.columns.Spot) - { worker += ""; } - - if (g_rosterSettings.columns.Life) - { worker += ""; } - - if (g_rosterSettings.columns.OAMS) - { worker += ""; } - - if (g_rosterSettings.columns.Age) - { worker += ""; } - - 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 = ``; - 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} ` - callObj.awardReason += ` - ${acks[thisCall].message}` - } + html += ""; - let worker = ""; - - worker += - ""; - - if (showBands) - { - worker += - ""; - } - if (showModes) - { - let color = "888888"; - if (callObj.mode in g_modeColors) - { color = g_modeColors[callObj.mode]; } - worker += - ""; - } - - worker += - ""; - if (g_rosterSettings.columns.Calling) - { - let lookString = callObj.CQ ? "name='CQ'" : "name='Calling'"; - worker += - ""; - } - if (g_rosterSettings.columns.Msg) - { worker += ""; } - - if (g_rosterSettings.columns.DXCC) - { - worker += - ""; - } - if (g_rosterSettings.columns.Flag) - { - worker += - ""; - } - if (g_rosterSettings.columns.State) - { - worker += - ""; - } - if (g_rosterSettings.columns.County) - { - worker += - ""; - } - if (g_rosterSettings.columns.Cont) - { - worker += - ""; - } - - if (g_rosterSettings.columns.dB) - { - worker += - ""; - } - if (g_rosterSettings.columns.Freq) - { worker += ""; } - if (g_rosterSettings.columns.DT) - { worker += ""; } - if (g_rosterSettings.columns.Dist) - { - worker += - ""; - } - if (g_rosterSettings.columns.Azim) - { - worker += - ""; - } - - if (g_rosterSettings.columns.CQz) - { - worker += - ""; - } - if (g_rosterSettings.columns.ITUz) - { - worker += - ""; - } - - if (g_rosterSettings.columns.PX) - { - worker += - ""; - } - - 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 += - ""; - } - if ( - window.opener.g_callsignLookups.oqrsUseEnable == true && - g_rosterSettings.columns.OQRS - ) - { - worker += - ""; - } - - if (g_rosterSettings.columns.Spot) - { - worker += - ""; - } - if (g_rosterSettings.columns.Life) - { - worker += - ""; - } - - 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 += - ""; - } - - worker += ""; - - return worker; + return html; } function renderNormalRosterFooter() { - return "
CallsignBandModeGridCallingMsgDXCCFlagStateCountyContdBFreqDTDist(" + - window.opener.distanceUnit.value.toLowerCase() + ")AzimCQzITUzPXLoTWeQSLOQRSSpotLifeOAMSAge
" + - callStr + - "" + - callObj.band + - "" + callObj.mode + "" + - grid + - "" + - callObj.DXcall.formatCallsign() + - "" + callObj.msg + "" + - window.opener.g_dxccToAltName[callObj.dxcc] + "" + - (callObj.state ? callObj.state.substr(3) : "") + - "" + - (callObj.cnty - ? (callObj.qual ? "" : "¿ ") + - window.opener.g_cntyToCounty[callObj.cnty] + - (callObj.qual ? "" : " ?") - : "") + - "" + - (callObj.cont ? callObj.cont : "") + - "" + - callObj.RSTsent + - "" + callObj.delta + "" + callObj.dt + "" + - parseInt( - callObj.distance * - MyCircle.validateRadius(window.opener.distanceUnit.value) - ) + - "" + - parseInt(callObj.heading) + - "" + - callObj.cqza.join(",") + - "" + - callObj.ituza.join(",") + - "" + - (callObj.px ? callObj.px : "") + - "?" + - (thisCall in window.opener.g_eqslCallsigns ? "✔" : "") + - "" + - (thisCall in window.opener.g_oqrsCallsigns ? "✔" : "") + - "" + - spotString + - "" + - (timeNowSec() - callObj.life).toDHMS() + - "" + - (timeNowSec() - callObj.age).toDHMS() + - "
"; + return ""; } diff --git a/package.nw/lib/roster/renderRoster.js b/package.nw/lib/roster/renderRoster.js index fa14e57..1e7ffa7 100644 --- a/package.nw/lib/roster/renderRoster.js +++ b/package.nw/lib/roster/renderRoster.js @@ -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() diff --git a/package.nw/lib/roster/rosterColumnFunctions.js b/package.nw/lib/roster/rosterColumnFunctions.js new file mode 100644 index 0000000..51d64e0 --- /dev/null +++ b/package.nw/lib/roster/rosterColumnFunctions.js @@ -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}` +} + +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(); +} diff --git a/package.nw/lib/roster/rosterColumns.js b/package.nw/lib/roster/rosterColumns.js new file mode 100644 index 0000000..81ae91a --- /dev/null +++ b/package.nw/lib/roster/rosterColumns.js @@ -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} ` + 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: `` + }) + }, + + 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: `${callObj.RSTsent}` + }) + }, + + 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: "" + } + } + else + { + return { + align: "center", + style: "margin: 0; padding: 0; cursor: pointer;", + onClick: `openChatToCid("${callObj.gt}")`, + html: "" + } + } + } + } + }, + + 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) + }) + } +} diff --git a/package.nw/package.json b/package.nw/package.json index f3ded10..df4d731 100644 --- a/package.nw/package.json +++ b/package.nw/package.json @@ -1,7 +1,7 @@ { "name": "GridTracker", "product_string_do_not_use": "gridtracker", - "version": "1.21.1212", + "version": "1.22.0503", "betaVersion": "", "description": "GridTracker, an amateur radio companion", "author": "Stephen Loomis (N0TTL) and GridTracker.org", @@ -23,7 +23,7 @@ "start": "run --mirror https://dl.nwjs.io/ ." }, "build": { - "nwVersion": "0.54.0", + "nwVersion": "0.59.0", "output": "../dist/.", "targets": [ "zip", diff --git a/windows/win_installer.nsi b/windows/win_installer.nsi new file mode 100644 index 0000000..da30c34 --- /dev/null +++ b/windows/win_installer.nsi @@ -0,0 +1,170 @@ +/* + GridTracker Installation Script +*/ + +# Installer Attributes +RequestExecutionLevel highest +SetCompressor /SOLID LZMA +Unicode true +!include Sections.nsh +!include Registry.nsh +!include LogicLib.nsh +ReserveFile "${NSISDIR}/Plugins/x86-unicode/registry.dll" +CRCCheck on + + +# Define Common Variables +!define NAME "GridTracker" +!define COMPANY "Gridtracker.org" +!define VERSION +!define URL "http://gridtracker.org" +!define HELPURL "https://gitlab.com/gridtracker.org/gridtracker/-/wikis/Home" +!define REGPATH_UNINSTSUBKEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${NAME}" +!define SMPATH "$SMPROGRAMS\${NAME}" +!define /date CPYEAR "%Y" +!define BUILDPATH "" +Name "${NAME} ${VERSION} Installer" +Icon "${BUILDPATH}/dist/GridTracker-${VERSION}-win-x86/gridview.ico" +OutFile "${BUILDPATH}/dist/GridTracker-Installer.${VERSION}.exe" + + +VIProductVersion ${VERSION}.0 +VIAddVersionKey ProductName "${NAME}" +VIAddVersionKey ProductVersion "${VERSION}" +VIAddVersionKey CompanyName "${COMPANY}" +VIAddVersionKey CompanyWebsite "${URL}" +VIAddVersionKey FileVersion "${VERSION}" +VIAddVersionKey FileDescription "An Amateur Radio Community" +VIAddVersionKey LegalCopyright "${CPYEAR} Gridtracker.org" + + +# Add registry reading plugin early on as we need to see if we are installed already + +# Set Default install dir then look at uninstall key to find if previously installed # +InstallDir "$ProgramFiles\${NAME}" + +## For 32 bit installs on 64 bit OS this is located in the WOW6432Node [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall] ## +InstallDirRegKey HKLM "${REGPATH_UNINSTSUBKEY}" "InstallPath" + + +# Pages displayed +#Page license +Page directory +Page components +Page instfiles + +# Display license file to user # +#LicenseData "LICENSE" + +Function .onInit + nsProcess::_FindProcess "GridTracker.exe" + Pop $R0 + ${If} $R0 = 0 + MessageBox MB_OK|MB_ICONEXCLAMATION "GridTracker is still running. Please close GridTracker and run the installer again." + Abort + ${EndIf} + call checkMSVC +FunctionEnd + +Function checkMSVC + ClearErrors + ReadRegStr $0 HKCR "Installer\Dependencies\VC,redist.x86,x86,14.30,bundle" "" + IfErrors 0 +15 + ClearErrors + ReadRegStr $0 HKCR "Installer\Dependencies\Microsoft.VS.VC_RuntimeMinimumVSU_x86,v14" "" + IfErrors 0 +12 + ClearErrors + ReadRegStr $0 HKCR "Installer\Dependencies\Microsoft.VS.VC_RuntimeAdditionalVSU_x86,v14" "" + IfErrors 0 +9 + ClearErrors + ReadRegStr $0 HKCR "Installer\Products\679E80FBE29B63345BF612177149674C" "PackageCode" + IfErrors 0 +6 + MessageBox MB_YESNO|MB_ICONQUESTION "GridTracker requires MSVC Runtime Libraries. Do you want to install them now?" IDYES InstallNow IDNO Next + InstallNow: + Call InstallMSVC + Goto Next + Next: + +FunctionEnd + + +Function InstallMSVC + NSISdl::download "https://aka.ms/vs/17/release/vc_redist.x86.exe" "$TEMP\vc_redist.x86.exe" $0 + StrCmp $0 success fail + success: + ExecWait '"$TEMP\vc_redist.x86.exe" /PASSIVE /NORESTART' $1 + Goto is_reboot_requested + fail: + MessageBox MB_OK|MB_ICONEXCLAMATION "Unable to download MSVC Runtime files. Please see GridTracker.org for details on download" + is_reboot_requested: + ${If} $1 = 1641 + ${OrIf} $1 = 3010 + SetRebootFlag true + ${EndIf} +FunctionEnd + +InstType "Full" +InstType "Minimal" + +Section "Program Files (Required)" + SectionIn 1 2 RO + SetOverwrite ifdiff + + SetOutPath $InstDir + File /r "${BUILDPATH}/dist/GridTracker-${VERSION}-win-x86/*" + + CreateDirectory "${SMPATH}" + CreateShortcut "${SMPATH}\${NAME}.lnk" "$InstDir\${NAME}.exe" + CreateShortcut "${SMPATH}\Help Wiki.lnk" "${HELPURL}" "" "$InstDir\gridview.ico" + CreateShortcut "${SMPATH}\Uninstall.lnk" $INSTDIR\uninstall.exe + + WriteRegStr HKLM "${REGPATH_UNINSTSUBKEY}" "DisplayName" "${NAME}" + WriteRegStr HKLM "${REGPATH_UNINSTSUBKEY}" "DisplayVersion" "${VERSION}" + WriteRegStr HKLM "${REGPATH_UNINSTSUBKEY}" "Publisher" "${COMPANY}" + WriteRegStr HKLM "${REGPATH_UNINSTSUBKEY}" "URLInfoAbout" "${URL}" + WriteRegStr HKLM "${REGPATH_UNINSTSUBKEY}" "DisplayIcon" "$InstDir\gridview.ico" + WriteRegStr HKLM "${REGPATH_UNINSTSUBKEY}" "UninstallString" '"$InstDir\uninstall.exe"' + WriteRegStr HKLM "${REGPATH_UNINSTSUBKEY}" "QuietUninstallString" '"$InstDir\uninstall.exe" /S' + WriteRegStr HKLM "${REGPATH_UNINSTSUBKEY}" "InstallPath" $InstDir + WriteRegDWORD HKLM "${REGPATH_UNINSTSUBKEY}" "NoModify" 1 + WriteRegDWORD HKLM "${REGPATH_UNINSTSUBKEY}" "NoRepair" 1 + + WriteUninstaller "$InstDir\uninstall.exe" + +SectionEnd + +# Section for PDF when we have it # +/* +Section "Offline Help Docs" + SectionIn 1 +SectionEnd +*/ + +# Section for Locales when we have it # +/* +SectionGroup "Locales" + SetOutPath $INSTDIR\locales + Section "de" + + SectionEnd + + Section "es" + + SectionEnd +SectionGroupEnd +*/ + +# Give User Option for Desktop Shortcut # +Section "Desktop Shortcut" + SectionIn 1 + CreateShortcut /NoWorkingDir "$DESKTOP\${NAME}.lnk" "$InstDir\${NAME}.exe" +SectionEnd + +# Uninstall stuffs # +Section -un.Main + RmDir /r /REBOOTOK $INSTDIR + RmDir /r /REBOOTOK "${SMPATH}" + Delete /REBOOTOK "$DESKTOP\${NAME}.lnk" + DeleteRegKey HKLM "${REGPATH_UNINSTSUBKEY}" + Delete "$InstDir\uninstall.exe" +SectionEnd