new version

This commit is contained in:
coulisse 2023-11-11 16:30:43 +01:00
commit 85da257729
30 changed files with 1644 additions and 1455 deletions

4
.gitignore vendored
View File

@ -4,3 +4,7 @@ config.json
__init__/
__pycache__/
.vscode/
*report.html
venv/
.idea/

View File

@ -24,5 +24,10 @@ keywords:
- dxcluster
- spiderweb
license: GPL-3.0
<<<<<<< HEAD
version: v2.4.2
date-released: 2023-02-12
=======
version: v2.4.5
date-released: 2023-11-11
>>>>>>> staging

View File

@ -3,14 +3,13 @@
### Ham radio cluster web viewer for DxSpider
[![GPLv3 license](https://img.shields.io/badge/License-GPLv3-blue.svg)](http://perso.crans.org/besson/LICENSE.html)
[![Linux](https://svgshare.com/i/Zhy.svg)](https://svgshare.com/i/Zhy.svg)
[![made-with-python](https://img.shields.io/badge/B.e.-Python-1f425f.svg)](https://www.python.org/)
[![made-with-javascript](https://img.shields.io/badge/F.e.-JavaScript-yellow)](https://www.javascript.com)
[![bootstrap](https://img.shields.io/badge/CSS%20Fwk-Bootstrap-purple)](https://getbootstrap.com/)
[![CodeFactor](https://www.codefactor.io/repository/github/coulisse/spiderweb/badge)](https://www.codefactor.io/repository/github/coulisse/spiderweb)
- **Release:** v2.4.2
- **Release:** v2.4.5
- **Author:** Corrado Gerbaldo - [IU1BOW](https://www.qrz.com/db/IU1BOW)
- **Mail:** <corrado.gerbaldo@gmail.com>
- **Licensing:** Gpl V3.0 see [LICENSE](LICENSE) file.

View File

@ -71,9 +71,9 @@
{ "WPX": "60", "ISO": "fr", "desc": "French Guiana" },
{ "WPX": "61", "ISO": "gb", "desc": "England" },
{ "WPX": "62", "ISO": "im", "desc": "Isle of Man" },
{ "WPX": "63", "ISO": "ie", "desc": "Northern Ireland" },
{ "WPX": "63", "ISO": "gb-nir", "desc": "Northern Ireland" },
{ "WPX": "64", "ISO": "je", "desc": "Jersey" },
{ "WPX": "65", "ISO": "gb", "desc": "Scotland" },
{ "WPX": "65", "ISO": "gb-sct", "desc": "Scotland" },
{ "WPX": "66", "ISO": "gg", "desc": "Guernsey" },
{ "WPX": "67", "ISO": "gb", "desc": "Wales" },
{ "WPX": "68", "ISO": "sb", "desc": "Solomon Islands" },

View File

@ -11,100 +11,103 @@
"min": 3500.0,
"max": 3569.9
},
{
{
"min": 7000.0,
"max": 7039.9
},
{
{
"min": 10100.0,
"max": 10129.9
},
{
{
"min": 14000.0,
"max": 14069.9
},
{
{
"min": 18068.0,
"max": 18099.9
},
{
{
"min": 21000.0,
"max": 21069.9
},
{
{
"min": 24890.0,
"max": 24914.9
},
{
{
"min": 28000.0,
"max": 28069.9
},
{
{
"min": 50000.0,
"max": 50312.9
},
{
"min": 50314.0,
"max": 50499.9
},
{
{
"min": 51000.0,
"max": 52000.0
},
{
"min": 70030,
"max": 70250
},
{
"min": 144000,
"max": 144150
},
{
"min": 432000,
"max": 432150
},
{
"min": 1296000,
"max": 1296150
},
{
"min": 2320100,
"max": 2320150
},
{
"min": 3400000,
"max": 3402000
},
{
"min": 5668000,
"max": 5670000
},
{
"min": 5760000,
"max": 5762000
},
{
"min": 10368000,
"max": 10370000
},
{
"min": 10450000,
"max": 10452000
},
{
"min": 24048000,
"max": 24050000
},
{
"min": 47087000,
"max": 47089000
}
{
"min": 70030,
"max": 70250
},
{
"min": 144000,
"max": 144150
},
{
"min": 432000,
"max": 432150
},
{
"min": 1296000,
"max": 1296150
},
{
"min": 2320100,
"max": 2320150
},
{
"min": 3400000,
"max": 3402000
},
{
"min": 5668000,
"max": 5670000
},
{
"min": 5760000,
"max": 5762000
},
{
"min": 10368000,
"max": 10370000
},
{
"min": 10450000,
"max": 10452000
},
{
"min": 24048000,
"max": 24050000
},
{
"min": 47087000,
"max": 47089000
}
]
},
{
{
"id": "digi",
"freq": [
{
"min": 1840.0,
"max": 1841.0
},
},
{
"min": 3570.0,
"max": 3600.0
@ -129,7 +132,7 @@
"min": 21070.0,
"max": 21100.0
},
{
{
"min": 21140.0,
"max": 21141.0
},
@ -144,13 +147,17 @@
{
"min": 28180.0,
"max": 28180.0
},
},
{
"min": 50313.0,
"max": 50313.9
},
{
"min": 50500.0,
"max": 51000.0
}
]
},
},
{
"id": "phone",
"freq": [
@ -177,7 +184,7 @@
{
"min": 21100.0,
"max": 21139.0
},
},
{
"min": 21141.0,
"max": 21450.0
@ -190,60 +197,59 @@
"min": 28120.0,
"max": 29700.0
},
{
"min": 50100,
"max": 50500
},
{
"min": 70030,
"max": 70250
},
{
"min": 144150,
"max": 144500
},
{
"min": 432150,
"max": 432500
},
{
"min": 1296150,
"max": 1296800
},
{
"min": 2320150,
"max": 2320800
},
{
"min": 3400000,
"max": 3402000
},
{
"min": 5668000,
"max": 5670000
},
{
"min": 5760000,
"max": 5762000
},
{
"min": 10368000,
"max": 10370000
},
{
"min": 10450000,
"max": 10452000
},
{
"min": 24048000,
"max": 24050000
},
{
"min": 47087000,
"max": 47089000
}
{
"min": 50100,
"max": 50500
},
{
"min": 70030,
"max": 70250
},
{
"min": 144150,
"max": 144500
},
{
"min": 432150,
"max": 432500
},
{
"min": 1296150,
"max": 1296800
},
{
"min": 2320150,
"max": 2320800
},
{
"min": 3400000,
"max": 3402000
},
{
"min": 5668000,
"max": 5670000
},
{
"min": 5760000,
"max": 5762000
},
{
"min": 10368000,
"max": 10370000
},
{
"min": 10450000,
"max": 10452000
},
{
"min": 24048000,
"max": 24050000
},
{
"min": 47087000,
"max": 47089000
}
]
}
}
]
}
}

View File

@ -1,5 +1,29 @@
### Change log
<<<<<<< HEAD
Date: 12/02/2023
=======
Date: 11/11/2023
Release: v2.4.5
- added "back to top" button
- enancement request #44 : added reset filter
- fixed dependencie #32 : mysql connector
- fixed FT8 frequency on CW 6 meter band #40
- upgraded echarts library from 5.4.1 to 5.4.3
- upgraded flag icons library from 6.6.0 to 6.15
- upgraded bootstrap to 5.2.3
___
Date: 26/02/2023
Release: v2.4.4
- replaced multipart form post with url encoded for security reasons
- fixed bands and continents in band activity chart
- upgraded Werkzeug to 2.2.3
- changed some api call from get to post method in order to not caching it
- fixed flags of Scothland and Northern Ireland
___
Date: 11/02/2023
>>>>>>> staging
Release: v2.4.2
- changed cache-control header
- fixed Layout scrolling (SEO)

View File

@ -1,23 +0,0 @@
#
# little script used to build static pages
#
__author__ = "IU1BOW - Corrado"
import sys
from staticjinja import Site
def csrf_token():
return "none"
if __name__ == "__main__":
print (sys.argv)
site = Site.make_site(
searchpath=sys.argv[1],
outpath=sys.argv[2],
env_globals={
"cookies_check": False,
"csrf_token": csrf_token,
"telnet": "none",
"mail": "none"
},
)
site.render(use_reloader=False)

View File

@ -1,13 +1,14 @@
astroid==2.12.14
blinker==1.6.2
charset-normalizer==2.1.1
click==8.1.3
dill==0.3.6
docopt-ng==0.8.1
easywatch==0.0.5
Flask==2.2.2
Flask==2.2.5
Flask-Consent==0.0.3
Flask-Minify==0.41
Flask-WTF==1.0.1
Flask-WTF==1.1.1
htmlmin==0.1.12
idna==3.4
isort==5.11.4
@ -16,9 +17,10 @@ Jinja2==3.1.2
jsmin==3.0.1
lazy-object-proxy==1.9.0
lesscpy==0.15.1
markup==0.2
MarkupSafe==2.1.1
mccabe==0.7.0
mysql-connector-python==8.0.31
mysql-connector-python>=8.0.31
numpy==1.24.1
pandas==1.5.2
platformdirs==2.6.2
@ -27,11 +29,11 @@ protobuf==4.21.12
python-dateutil==2.8.2
pytz==2022.7
rcssmin==1.1.1
requests==2.28.1
requests==2.31.0
six==1.16.0
tomlkit==0.11.6
urllib3==1.26.13
watchdog==2.2.0
urllib3==2.0.7
watchdog==3.0.0
Werkzeug==2.2.2
wrapt==1.14.1
WTForms==3.0.1

View File

@ -129,6 +129,9 @@ if [ "$1" == "-r" ]; then
sed -i '/staticjinja==/d' ../requirements.txt
sed -i '/lighthouse==/d' ../requirements.txt
echo 'force some requirements...'
sed -i 's/mysql-connector-python==8.0.31/mysql-connector-python>=8.0.31/' ../requirements.txt
if ! sed -i '13,20s/level=DEBUG/level=INFO/g' ${app_ini}; then
echo 'ERROR settimg loglevel=INFO '
exit 12
@ -260,31 +263,31 @@ elif [ "${1}" == "-d" ]; then
fi
static_build_path_i=$(mktemp -d /tmp/spiderweb_static_build_i-XXXXXXXXX)
static_build_path_o=$(mktemp -d /tmp/spiderweb_static_build_o-XXXXXXXXX)
cp ${path_templates}/_base.html ${static_build_path_i}
cp ${path_templates}/offline.html ${static_build_path_i}
echo 'generating static pages...'
if ! python ../lib/static_build.py ${static_build_path_i} ${static_build_path_o}
then
echo 'ERROR generating static pages'
rm -rf ${static_build_path_i}
rm -rf ${static_build_path_o}
exit 50
fi
if ! cp ${static_build_path_o}/offline.html ${path_static_html}
then
echo 'ERROR copying static pages'
rm -rf ${static_build_path_i}
rm -rf ${static_build_path_o}
exit 51
fi
rm -rf ${static_build_path_i}
rm -rf ${static_build_path_o}
#static_build_path_i=$(mktemp -d /tmp/spiderweb_static_build_i-XXXXXXXXX)
#static_build_path_o=$(mktemp -d /tmp/spiderweb_static_build_o-XXXXXXXXX)
#
#cp ${path_templates}/_base.html ${static_build_path_i}
#cp ${path_templates}/offline.html ${static_build_path_i}
#
#echo 'generating static pages...'
#if ! python ../lib/static_build.py ${static_build_path_i} ${static_build_path_o}
#then
# echo 'ERROR generating static pages'
# rm -rf ${static_build_path_i}
# rm -rf ${static_build_path_o}
# exit 50
#fi
#
#if ! cp ${static_build_path_o}/offline.html ${path_static_html}
#then
# echo 'ERROR copying static pages'
# rm -rf ${static_build_path_i}
# rm -rf ${static_build_path_o}
# exit 51
#fi
#
#rm -rf ${static_build_path_i}
#rm -rf ${static_build_path_o}
echo

View File

@ -115,4 +115,12 @@ span.search-callsign {
#silo-propagation-img {
width: 95%;
height: auto;
}
}
#btn-back-to-top {
position: fixed;
bottom: 20px;
right: 20px;
display: none;
opacity: 0.7;
}

View File

@ -1 +1 @@
@import url("https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.3/font/bootstrap-icons.css");@font-face{font-display:swap;font-family:bootstrap-icons}.badge-responsive{width:70px}@media screen and (max-width:768px){.text-responsive{font-size:12px}.badge-responsive{width:40px}#collapseFilters.collapsing{position:absolute!important;z-index:20}#collapseFilters.collapse.show{display:block;position:absolute;z-index:20}.navbar-collapse{max-height:none!important}}.img-flag{background-color:#fff;background-size:cover!important;border:1px solid #ddd;border-radius:2px;-webkit-box-shadow:0 2px 10px rgba(0,0,0,.5),0 2px 3px rgba(0,0,0,.5);-moz-box-shadow:0 2px 10px rgba(0,0,0,.5),0 2px 3px rgba(0,0,0,.5);-o-box-shadow:0 2px 10px rgba(0,0,0,.5),0 2px 3px rgba(0,0,0,.5);box-shadow:0 2px 10px rgba(0,0,0,.5),0 2px 3px rgba(0,0,0,.5);height:19px!important;max-height:auto;max-width:auto;padding:3px;width:32px!important}.ipcs{background-image:url(/static/images/background.webp);background-repeat:no-repeat;background-size:cover}.copyleft{display:inline-block;transform:rotate(180deg)}span.search-callsign{background:url(/static/images/search-callsign.svg) no-repeat 0 0;background-size:contain;cursor:pointer;display:inline-block;height:16px;width:20px}#input-group-callsign{margin-bottom:.5rem;margin-right:1rem}#collapseFilters{background-color:#dde2e6;margin-top:10px}#spotsTable{margin-top:10px}#band{margin-top:5px}#dashboard{gap:10px;padding:10px}#telnet-thead{position:sticky;top:0}#chart-band_activity{height:400px;width:100%}.spider_chart{height:480px;width:600px}#silo-propagation-img{height:auto;width:95%}
@import url("https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.3/font/bootstrap-icons.css");@font-face{font-display:swap;font-family:bootstrap-icons}.badge-responsive{width:70px}@media screen and (max-width:768px){.text-responsive{font-size:12px}.badge-responsive{width:40px}#collapseFilters.collapsing{position:absolute!important;z-index:20}#collapseFilters.collapse.show{display:block;position:absolute;z-index:20}.navbar-collapse{max-height:none!important}}.img-flag{background-color:#fff;background-size:cover!important;border:1px solid #ddd;border-radius:2px;-webkit-box-shadow:0 2px 10px rgba(0,0,0,.5),0 2px 3px rgba(0,0,0,.5);-moz-box-shadow:0 2px 10px rgba(0,0,0,.5),0 2px 3px rgba(0,0,0,.5);-o-box-shadow:0 2px 10px rgba(0,0,0,.5),0 2px 3px rgba(0,0,0,.5);box-shadow:0 2px 10px rgba(0,0,0,.5),0 2px 3px rgba(0,0,0,.5);height:19px!important;max-height:auto;max-width:auto;padding:3px;width:32px!important}.ipcs{background-image:url(/static/images/background.webp);background-repeat:no-repeat;background-size:cover}.copyleft{display:inline-block;transform:rotate(180deg)}span.search-callsign{background:url(/static/images/search-callsign.svg) no-repeat 0 0;background-size:contain;cursor:pointer;display:inline-block;height:16px;width:20px}#input-group-callsign{margin-bottom:.5rem;margin-right:1rem}#collapseFilters{background-color:#dde2e6;margin-top:10px}#spotsTable{margin-top:10px}#band{margin-top:5px}#dashboard{gap:10px;padding:10px}#telnet-thead{position:sticky;top:0}#chart-band_activity{height:400px;width:100%}.spider_chart{height:480px;width:600px}#silo-propagation-img{height:auto;width:95%}#btn-back-to-top{bottom:20px;display:none;opacity:.7;position:fixed;right:20px}

File diff suppressed because it is too large Load Diff

View File

@ -1,124 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Spiderweb: OFFLINE</title>
<meta charset="utf-8">
<meta name="description" content="Web Ham Radio DX Cluster and spot search">
<meta name="author" content="Corrado Gerbaldo - IU1BOW">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#2196f3">
<link rel="icon" href="/static/images/icons/favicon.ico">
<link rel="icon" href="/static/images/icons/spider_ico_master.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/static/images/icons/icon-apple.png">
<link rel="manifest" href="/static/pwa/manifest.webmanifest">
<link rel="stylesheet" href="/static/css/rel/style.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css"
integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/6.6.6/css/flag-icons.min.css"
integrity="sha512-uvXdJud8WaOlQFjlz9B15Yy2Au/bMAvz79F7Xa6OakCl2jvQPdHD0hb3dEqZRdSwG4/sknePXlE7GiarwA/9Wg=="
crossorigin="anonymous" referrerpolicy="no-referrer" />
</head>
<body>
<header>
<!-- nav bar -->
<nav class="navbar px-2 navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="/">
<img src="/static/images/icons/icon-72x72.png" width="30" height="30"
class="d-inline-block align-top" alt="">
</a>
<button class="navbar-toggler" type="button" aria-controls="navbarToggler01" aria-expanded="false"
aria-label="Toggle navigation" data-bs-toggle="collapse" data-bs-target="#navbarToggler01">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarToggler01">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
</ul>
<div id="MyClockDisplay" class="text-white-50 d-none d-lg-block"></div>
<div class="text-white-50 d-none d-lg-block">&nbsp;(UTC)&nbsp;&nbsp;</div>
<form method="POST" class="d-flex" id="form-callsign" enctype="multipart/form-data">
<input type="hidden" name="csrf_token" value="none" />
<div class="input-group" id='input-group-callsign'>
<input type="text" class="form-control" placeholder="callsign" aria-label="callsign"
aria-describedby="button-addon2" id="callsignInput">
<div class="input-group-append">
<button id="btn-callsign-search" class="btn btn-secondary" type="submit">
<span class="bi-search" role="button" aria-label="search-callsign"></span>
</button>
</div>
</div>
</form>
</div>
</div>
</nav>
</header>
<div class="container-fluid mt-1 ml-0 mr-0 px-0">
<div class="ipcs bg-light p-4 rounded-lg m-2">
<h1 class="display-4 text-white">WEB DX Cluster</h1>
<p class="lead text-light">Missing connection &nbsp<i class="bi-wifi-off"></i></p>
<p class="text-light">Telnet access: <a href="telnet://none" class="text-white">none</a></p>
<p class="text-light">For connect your cluster, write to <a
href="mailto:none?Subject=Connect%20my%20DxCluster%20node" target="_top" class="text-white">none</a></p>
</div>
<div class="jumbotron alert" role="alert">
<h2 class="display-4">No internet connection</h2>
<p class="lead">The features in this area require Internet connectivity. Please connect your computer to the
Internet</p>
<p class="lead">
<a class="btn btn-primary btn-lg" href="/" role="button">Try again</a>
</p>
</div>
</div>
<footer class="page-footer font-small blue">
<div class="footer-copyright text-center py-3">
<span class="copyleft">&copy;</span> Copyleft:
<span id="copyDate"></span>
<a href="https://github.com/coulisse/spiderweb/" target="blank" rel="noopener">IU1BOW - Spiderweb</a>
<span id="version">v2.4.2</span>
<!--
<a href="https://github.com/coulisse/spiderweb/" target="blank" rel="noopener"><img src="/static/images/icons/github-mark.svg" alt="github.com" width="16px" height="16px"></a>
-->
</div>
</footer>
<script async src="static/js/rel/load-sw.min.js"></script>
<script nonce="">
</script>
<script defer src="static/js/rel/common.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js"
integrity="sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa"
crossorigin="anonymous"></script>
<script async src="static/js/rel/callsign_search.min.js"></script>
<!-- cookie consent management -->
</body>
</html>

View File

@ -5,9 +5,22 @@
//var my_adxo_events=jQuery.parseJSON(my_adxo_events_json.replaceAll("\t",""));
var my_adxo_events = JSON.parse(my_adxo_events_json.replaceAll('\t', ''));
//var qryString = 'spotlist?c=' + my_callsign;
var qryString = 'spotlist?c=' + callsign;
fetch(qryString)
//var qryString = 'spotlist?c=' + callsign;
let params = {};
params['callsign']=callsign;
//let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content");
fetch('spotlist', {
method: 'POST',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify( params )
})
.then((response) => response.json())
.then((data) => {
try {

View File

@ -9,7 +9,6 @@ function myCallsignSearch(event) {
//construct query parameters
if (callsign.replace(/\s/g, '').length > 0) {
location.href = ('/callsign.html?c=').concat((callsign.trim()).toUpperCase());
console.log(location.href);
//form.action="index.html";
}

View File

@ -49,7 +49,7 @@ function getCookie(cname) {
function get_last_refresh(data) {
let dt_refresh = new Date(0); // The 0 there is the key, which sets the date to the epoch
//var dt_refresh;
dt_refresh.setUTCSeconds(data["last_refresh"]);
dt_refresh.setUTCSeconds(data['last_refresh']);
const pad = (n, s = 2) => (`${new Array(s).fill(0)}${n}`).slice(-s);
const hours = pad(dt_refresh.getHours());
const minutes = pad(dt_refresh.getMinutes());
@ -57,7 +57,7 @@ function get_last_refresh(data) {
const month = months_names[dt_refresh.getMonth()];
const day = dt_refresh.getDate();
const year = dt_refresh.getFullYear();
const last_refresh = "Data refresh: " + day + " of " + month + " " + year + " at " + hours + ":" + minutes;
const last_refresh = 'Data refresh: ' + day + ' of ' + month + ' ' + year + ' at ' + hours + ':' + minutes;
return last_refresh;
}
@ -145,29 +145,46 @@ function setText(id, newvalue) {
s.innerHTML = newvalue;
}
function showTime(){
let date=new Date();
function showTime() {
let date = new Date();
let utc = new Date(date.getTime() + date.getTimezoneOffset() * 60000);
let time = utc.toTimeString().split(' ')[0];
time = time.split(':')[0]+':'+time.split(':')[1];
document.getElementById("MyClockDisplay").innerText = time;
document.getElementById("MyClockDisplay").textContent = time;
setTimeout(showTime, 1000);
time = time.split(':')[0] + ':' + time.split(':')[1];
document.getElementById('MyClockDisplay').innerText = time;
document.getElementById('MyClockDisplay').textContent = time;
setTimeout(showTime, 1000);
}
document.getElementById('MyClockDisplay').addEventListener('load',showTime());
document.getElementById('copyDate').innerHTML='2020-'.concat(new Date().getFullYear());
/*
function doRefresh(){
document.getElementById('MyClockDisplay').addEventListener('load', showTime());
document.getElementById('copyDate').innerHTML = '2020-'.concat(new Date().getFullYear());
var chartDom = document.getElementById('chart-dx_spots_trend');
var myChart = echarts.init(chartDom);
plot_dst.refresh(myChart,'/plot_get_dx_spots_trend');
//Get the button for return to top page
let button_top = document.getElementById('btn-back-to-top');
};
// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = function () {
scrollFunction();
};
setInterval(function(){doRefresh()}, 5000);
function scrollFunction() {
if (
document.body.scrollTop > 20 ||
document.documentElement.scrollTop > 20
) {
button_top.style.display = 'block';
} else {
button_top.style.display = 'none';
}
}
// When the user clicks on the button, scroll to the top of the document
//button_top.addEventListener('click', backToTop);
*/
// When the user clicks on the button, scroll to the top of the document
button_top.addEventListener('click', backToTop);
function backToTop() {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
}

View File

@ -14,4 +14,5 @@ window.onload = () => {
document.getElementById('form-filters').addEventListener('submit', mySearch);
};
document.getElementById('MyClockDisplay').addEventListener('load',showTime());

View File

@ -1,25 +1,25 @@
class plot_base {
//refresh = function(){
refresh() {
refresh() {
}
/**
* Chart creator
*
* @constructor
* @param {String} chart_id The HTML id where place chart
* @param {string} end_point This is backend end-point for chart datas
*/
constructor(chart_id,end_point) {
* Chart creator
*
* @constructor
* @param {String} chart_id The HTML id where place chart
* @param {string} end_point This is backend end-point for chart datas
*/
constructor(chart_id, end_point) {
// Initialize the echarts instance based on the prepared dom
let chartDom = document.getElementById(chart_id);
this.end_point=end_point;
this.end_point = end_point;
this.myChart = echarts.init(chartDom);
//resize
let chart = echarts.init(document.querySelector('#'+chart_id), null);
window.addEventListener('resize',function(){
let chart = echarts.init(document.querySelector('#' + chart_id), null);
window.addEventListener('resize', function () {
chart.resize();
});
}
@ -33,13 +33,13 @@ class plot_base {
class band_activity extends plot_base {
/**
* refresh and populate chart
*
* @param {string} region This is the continent name (EU,AF,NA...) of the selected
*/
* refresh and populate chart
*
* @param {string} region This is the continent name (EU,AF,NA...) of the selected
*/
//refresh = function(this.myChart, end_point, region, bands, continents){
//refresh = function(region){
refresh (region) {
refresh(region) {
super.refresh();
console.log('refresh band_activity');
if (typeof region !== 'undefined') {
@ -47,12 +47,25 @@ class band_activity extends plot_base {
}
// Asynchronous Data Loading
fetch(this.end_point+'?continent='+this.selectedContinent)
.then((response) => response.json())
//fetch(this.end_point + '?continent=' + this.selectedContinent)
const params = {
continent: this.selectedContinent
};
fetch(this.end_point, {
method: 'POST',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify( params )
})
.then((response) => response.json())
.then((data) => {
// Fill in the data
var last_refresh=get_last_refresh(data);
var dataMap=Array.from(data['band activity']).map(function (item) {
var last_refresh = get_last_refresh(data);
var dataMap = Array.from(data['band activity']).map(function (item) {
return [item[1], item[0], item[2] || '-'];
});
//options
@ -60,29 +73,29 @@ class band_activity extends plot_base {
tooltip: {
position: 'top',
formatter: function (p) {
var format = p.seriesName +' on ' + p.name +' band: '+'<strong>'+p.data[2]+'</strong>';
var format = p.seriesName + ' on ' + p.name + ' band: ' + '<strong>' + p.data[2] + '</strong>';
return format;
}
}
},
title: {
text:'Band activity',
text: 'Band activity',
subtext: last_refresh,
top: 'top',
left:'left'
},
left: 'left'
},
toolbox: {
show: true,
showTitle: false,
orient: 'vertical',
right: 'right',
top : 'bottom',
top: 'bottom',
feature: {
mark: { show: true },
dataView: { show: true, readOnly: true },
restore: { show: true },
saveAsImage: { show: true }
}
},
},
grid: {
height: '80%',
left: 25,
@ -90,12 +103,12 @@ class band_activity extends plot_base {
right: 60,
bottom: 0,
show: true,
backgroundColor: 'rgb(255, 255, 255)',
backgroundColor: 'rgb(255, 255, 255)',
},
xAxis: {
type: 'category',
data: this.bands,
axisTick: {
axisTick: {
show: true,
},
axisLine: {
@ -108,12 +121,12 @@ class band_activity extends plot_base {
yAxis: {
type: 'category',
data: this.continents,
axisTick: {
axisTick: {
show: true,
},
axisLine: {
show: false,
},
},
splitArea: {
show: true
}
@ -125,10 +138,10 @@ class band_activity extends plot_base {
top: 'center',
min: 0,
max: 30,
inRange : {
color: ['#ffffe6','yellow','red']
}
inRange: {
color: ['#ffffe6', 'yellow', 'red']
}
},
series: [
{
@ -147,56 +160,58 @@ class band_activity extends plot_base {
}
]
});
});
});
}
/**
* Chart creator
*
* @constructor
* @param {String} chart_id The HTML id where place chart
* @param {string} end_point This is backend end-point for chart datas
* @param {integer} refresh_time Time to refesh chart
* @param {Json} cont_cq The continent list( EU, SA, ...)
* @param {Json} band_freq The frequency band list (160, 80, 60... UHF, SHF)
*/
constructor(chart_id, end_point, cont_cq, band_freq) {
super(chart_id,end_point);
* Chart creator
*
* @constructor
* @param {String} chart_id The HTML id where place chart
* @param {string} end_point This is backend end-point for chart datas
* @param {integer} refresh_time Time to refesh chart
* @param {Json} cont_cq The continent list( EU, SA, ...)
* @param {Json} band_freq The frequency band list (160, 80, 60... UHF, SHF)
*/
constructor(chart_id, end_point, cont_cq, band_freq) {
super(chart_id, end_point);
//populate continents array
var continents=[];
let continents = [];
cont_cq.forEach(function myFunction(item, index) {
continents[index]=item['id'];
continents[index] = item['id'];
});
this.continents = continents;
//populate bands array
var bands=[];
let bands = [];
band_freq.forEach(function myFunction(item, index) {
bands[index]=item['id'];
bands[index] = item['id'];
});
this.bands = bands;
//managing region
var selectedContinent=getCookie('user_region');
var selectedContinent_desc=getCookie('user_region_desc');
var selectedContinent = getCookie('user_region');
var selectedContinent_desc = getCookie('user_region_desc');
if (!selectedContinent) {
selectedContinent='EU';
selectedContinent_desc='Europe';
setCookie('user_region',selectedContinent,60);
setCookie('user_region_desc',selectedContinent_desc,60);
selectedContinent = 'EU';
selectedContinent_desc = 'Europe';
setCookie('user_region', selectedContinent, 60);
setCookie('user_region_desc', selectedContinent_desc, 60);
}
selectElement('continentInput', selectedContinent);
addEventHandler(document.getElementById('continentInput'), 'change', function() {
selectedContinent=this.value;
selectedContinent_desc=this.options[this.selectedIndex].text;
setCookie('user_region',selectedContinent,60);
setCookie('user_region_desc',selectedContinent_desc,60);
addEventHandler(document.getElementById('continentInput'), 'change', function () {
selectedContinent = this.value;
selectedContinent_desc = this.options[this.selectedIndex].text;
setCookie('user_region', selectedContinent, 60);
setCookie('user_region_desc', selectedContinent_desc, 60);
plot_ba.refresh(selectedContinent);
setText('txt_continent','\xa0 Based on DX SPOTS from stations in '+ selectedContinent_desc +' during the last 15 minutes, displayed by Continent and Band');
setText('txt_continent', '\xa0 Based on DX SPOTS from stations in ' + selectedContinent_desc + ' during the last 15 minutes, displayed by Continent and Band');
});
setText('txt_continent','\xa0 Based on DX SPOTS from stations in '+ selectedContinent_desc +' during the last 15 minutes, displayed by Continent and Band');
setText('txt_continent', '\xa0 Based on DX SPOTS from stations in ' + selectedContinent_desc + ' during the last 15 minutes, displayed by Continent and Band');
this.refresh(selectedContinent);
}
@ -208,7 +223,7 @@ class band_activity extends plot_base {
* ******************************************************************************/
class world_dx_spots_live extends plot_base {
/**
* refresh and populate chart
*
@ -217,23 +232,32 @@ class world_dx_spots_live extends plot_base {
super.refresh();
console.log('refresh world_dx_spots_live');
// Asynchronous Data Loading
fetch(this.end_point)
.then((response) => response.json())
.then((data) => {
fetch(this.end_point, {
method: 'POST',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
}
})
.then((response) => response.json())
.then((data) => {
fetch('world.json')
.then(response => response.text())
.then(geoJson => {
var last_refresh=get_last_refresh(data);
var dataMap=[];
var last_refresh = get_last_refresh(data);
var dataMap = [];
data['world_dx_spots_live'].forEach(function myFunction(item, index) {
//lon, lat, number of qso
dataMap.push({'value':[item['lat'],item['lon'],item['count']]});
dataMap.push({ 'value': [item['lat'], item['lon'], item['count']] });
});
this.myChart.hideLoading();
echarts.registerMap('WR', geoJson);
this.myChart.setOption( {
echarts.registerMap('WR', geoJson);
this.myChart.setOption({
visualMap: {
show: false,
@ -241,7 +265,7 @@ class world_dx_spots_live extends plot_base {
max: 30,
inRange: {
symbolSize: [5, 20]
}
}
},
geo: {
@ -259,36 +283,36 @@ class world_dx_spots_live extends plot_base {
},
emphasis: {
areaColor: '#3ba272' //3ba272 91cc75
}
}
},
label: {
emphasis: {
show: false
}
},
},
},
tooltip: {
trigger: 'item',
formatter: function(val) {
var out='Spots: <STRONG>'+ val.value[2] +'</STRONG>';
formatter: function (val) {
var out = 'Spots: <STRONG>' + val.value[2] + '</STRONG>';
return out;
}
},
toolbox: {
show: true,
showTitle: false,
orient: 'vertical',
left: 'right',
top: 'center',
top: 'center',
feature: {
mark: { show: true },
dataView: { show: true, readOnly: false },
restore: { show: true },
saveAsImage: { show: true }
}
},
},
legend: {
show: false
},
@ -296,13 +320,13 @@ class world_dx_spots_live extends plot_base {
text: 'World DX SPOTS in last hour',
subtext: last_refresh,
top: 'top',
right:'right',
},
series: [
right: 'right',
},
series: [
{
type: 'scatter',
coordinateSystem: 'geo',
data:dataMap,
type: 'scatter',
coordinateSystem: 'geo',
data: dataMap,
label: {
emphasis: {
position: 'right',
@ -314,20 +338,20 @@ class world_dx_spots_live extends plot_base {
color: '#fc8452',
borderColor: '#fa0a0a',
}
},
},
/*
symbolSize: function (val) {
return val[2] / 4;
},
*/
symbolSize: function (val) {
return val[2] / 4;
},
*/
}
]
]
}); //end options
}
);
});
}
);
});
}
/**
* Chart creator
@ -335,9 +359,9 @@ class world_dx_spots_live extends plot_base {
* @constructor
* @param {String} chart_id The HTML id where place chart
* @param {string} end_point This is backend end-point for chart datas
*/
constructor(chart_id, end_point) {
super(chart_id,end_point);
*/
constructor(chart_id, end_point) {
super(chart_id, end_point);
this.refresh();
}
@ -348,7 +372,7 @@ class world_dx_spots_live extends plot_base {
* ******************************************************************************/
class hour_band extends plot_base {
/**
* refresh and populate chart
*
@ -358,39 +382,47 @@ class hour_band extends plot_base {
// Asynchronous Data Loading
super.refresh();
console.log ('refresh hour_band');
fetch(this.end_point)
.then((response) => response.json())
.then((data) => {
console.log('refresh hour_band');
fetch(this.end_point, {
method: 'POST',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
}
})
.then((response) => response.json())
.then((data) => {
// Fill in the dat
var last_refresh=get_last_refresh(data);
var last_refresh = get_last_refresh(data);
//set hour indicator names
var hour_indicators=[];
var hour_indicators = [];
for (let i = 23; i > -1; i--) {
var hour_name={};
var s=i.toString();
hour_name['name']=s;
var hour_name = {};
var s = i.toString();
hour_name['name'] = s;
hour_indicators.push(hour_name);
}
//cycling whithin each bands and hours
var dataMap=[];
var dataMap = [];
this.bands.forEach(band_item => {
var qso=[];
for (let i = 23; i > -1; i--) {
var qso = [];
for (let i = 23; i > -1; i--) {
try {
var value=data['hour_band'][band_item][i];
var value = data['hour_band'][band_item][i];
if (typeof value == 'undefined') {
value = 0;
}
}
qso.push(value);
} catch (TypeError) {
//TODO
}
}
var tot={'value':qso,'name':band_item};
}
var tot = { 'value': qso, 'name': band_item };
dataMap.push(tot);
});
@ -398,17 +430,17 @@ class hour_band extends plot_base {
//options
this.myChart.setOption({
legend: {
orient: 'horizontal',
left: 'left',
bottom: 'bottom'
bottom: 'bottom'
},
title: {
text: 'DX SPOTS per hour in last month',
subtext: last_refresh,
top: 'top',
right: 'right',
},
},
tooltip: {
trigger: 'axis',
},
@ -417,23 +449,23 @@ class hour_band extends plot_base {
showTitle: false,
orient: 'vertical',
left: 'right',
top: 'center',
top: 'center',
feature: {
mark: { show: true },
dataView: { show: true, readOnly: true },
restore: { show: true },
saveAsImage: { show: true }
}
},
},
radar: {
shape: 'circle',
shape: 'circle',
//startAngle: 285, //0 on left side
startAngle: 105, //0 on top
indicator: hour_indicators,
center: ['47%', '46%'],
axisName: {
color: 'rgb(80,80,80)',
},
},
},
series: [
{
@ -441,25 +473,25 @@ class hour_band extends plot_base {
width: 2
},
type: 'radar',
symbol: 'none',
symbol: 'none',
data: dataMap,
tooltip: {
trigger: 'item',
formatter: (params) => {
return 'Band: '+params.name;
},
},
return 'Band: ' + params.name;
},
},
emphasis: {
lineStyle: {
width: 4
}
},
},
}
]
});
});
}
/**
* Chart creator
@ -468,15 +500,15 @@ class hour_band extends plot_base {
* @param {String} chart_id The HTML id where place chart
* @param {string} end_point This is backend end-point for chart datas
* @param {Json} band_freq The frequency band list (160, 80, 60... UHF, SHF)
*/
constructor(chart_id,end_point,band_freq) {
*/
constructor(chart_id, end_point, band_freq) {
// Initialize the echarts instance based on the prepared dom
super(chart_id,end_point);
super(chart_id, end_point);
//populate bands array
let lcl_bands=[];
let lcl_bands = [];
band_freq.forEach(function myFunction(item, index) {
lcl_bands[index]=item['id'];
lcl_bands[index] = item['id'];
});
this.bands = lcl_bands;
this.refresh();
@ -489,22 +521,30 @@ class hour_band extends plot_base {
* javascript used to build dx spots per month chart
* ******************************************************************************/
class dx_spots_per_month extends plot_base {
class dx_spots_per_month extends plot_base {
/**
* refresh and populate chart
*/
* refresh and populate chart
*/
refresh() {
console.log('refresh dx_spots_per_month');
// Asynchronous Data Loading
//$.getJSON(end_point).done(function(data) {
fetch(this.end_point)
.then((response) => response.json())
.then((data) => {
fetch(this.end_point, {
method: 'POST',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
}
})
.then((response) => response.json())
.then((data) => {
// Fill in the data
var last_refresh=get_last_refresh(data);
var last_refresh = get_last_refresh(data);
var year_now = new Date().getFullYear();
var year_0 = (year_now - 0).toString();
var year_1 = (year_now - 1).toString();
@ -512,14 +552,14 @@ class dx_spots_per_month extends plot_base {
var months_name = get_months_names();
var dataMap_year_0=[];
var dataMap_year_1=[];
var dataMap_year_2=[];
var dataMap_year_0 = [];
var dataMap_year_1 = [];
var dataMap_year_2 = [];
for (let i = 1; i < 13; i++) {
dataMap_year_0.push(data.spots_per_month[i].year_0);
dataMap_year_1.push(data.spots_per_month[i].year_1);
dataMap_year_2.push(data.spots_per_month[i].year_2);
}
}
//options
this.myChart.setOption({
@ -533,11 +573,11 @@ class dx_spots_per_month extends plot_base {
text: 'DX SPOTS per month',
subtext: last_refresh,
top: 'top',
left:'left'
},
left: 'left'
},
legend: {
data: [year_2, year_1, year_0],
bottom: 'bottom'
bottom: 'bottom'
},
toolbox: {
show: true,
@ -564,7 +604,7 @@ class dx_spots_per_month extends plot_base {
{
type: 'value',
axisLabel: {
formatter: (function (value){
formatter: (function (value) {
return format_u_k_m(value);
})
}
@ -587,7 +627,7 @@ class dx_spots_per_month extends plot_base {
focus: 'series'
},
data: dataMap_year_1
},
{
name: year_0,
@ -595,9 +635,9 @@ class dx_spots_per_month extends plot_base {
emphasis: {
focus: 'series'
},
data: dataMap_year_0
data: dataMap_year_0
},
]
]
});
});
}
@ -608,9 +648,9 @@ class dx_spots_per_month extends plot_base {
* @constructor
* @param {String} chart_id The HTML id where place chart
* @param {string} end_point This is backend end-point for chart datas
*/
constructor(chart_id, end_point) {
super(chart_id,end_point);
*/
constructor(chart_id, end_point) {
super(chart_id, end_point);
this.refresh();
}
}
@ -620,27 +660,34 @@ class dx_spots_per_month extends plot_base {
* ******************************************************************************/
class dx_spots_trend extends plot_base {
/**
* refresh and populate chart
*/
* refresh and populate chart
*/
refresh() {
console.log('refresh dx_spots_trend');
console.log('refresh dx_spots_trend');
// Asynchronous Data Loading
fetch(this.end_point)
.then((response) => response.json())
.then((data) => {
fetch(this.end_point, {
method: 'POST',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
}
})
.then((response) => response.json())
.then((data) => {
// Fill in the data
var last_refresh=get_last_refresh(data);
var dataMap=[];
var last_refresh = get_last_refresh(data);
var dataMap = [];
for (const [key, value] of Object.entries(data['spots_trend'])) {
var tuple=[];
var tuple = [];
tuple.push(key);
tuple.push(value);
dataMap.push(tuple);
}
}
//options
this.myChart.setOption({
tooltip: {
@ -653,22 +700,22 @@ class dx_spots_trend extends plot_base {
text: 'DX SPOTS trend',
subtext: last_refresh,
top: 'top',
left:'left'
left: 'left'
},
toolbox: {
show: true,
showTitle: false,
orient: 'vertical',
left: 'right',
top: 'center',
top: 'center',
feature: {
dataView: { show: true, readOnly: false },
dataZoom: {
yAxisIndex: 'none'
},
},
restore: {},
magicType: { show: true, type: ['line', 'bar'] },
saveAsImage: {},
magicType: { show: true, type: ['line', 'bar'] },
saveAsImage: {},
}
},
xAxis: {
@ -679,10 +726,10 @@ class dx_spots_trend extends plot_base {
type: 'value',
boundaryGap: [0, '10%'],
axisLabel: {
formatter: (function (value){
formatter: (function (value) {
return format_u_k_m(value);
})
}
}
},
dataZoom: [
{
@ -704,53 +751,54 @@ class dx_spots_trend extends plot_base {
symbol: 'none',
itemStyle: {
color: '#078513'
},
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: '#57fa75'
color: '#57fa75'
},
{
offset: 1,
color: '#118226'
color: '#118226'
}
])
},
data: dataMap
}
]
]
});
});
}
/**
* Chart creator
*
* @constructor
* @param {String} chart_id The HTML id where place chart
* @param {string} end_point This is backend end-point for chart datas
*/
constructor(chart_id,end_point) {
* Chart creator
*
* @constructor
* @param {String} chart_id The HTML id where place chart
* @param {string} end_point This is backend end-point for chart datas
*/
constructor(chart_id, end_point) {
// Initialize the echarts instance based on the prepared dom
super(chart_id,end_point);
super(chart_id, end_point);
this.refresh();
}
}
//create objects and timing
var plot_ba = new band_activity ('chart-band_activity','/plot_get_heatmap_data', continents_cq,band_frequencies);
setInterval(function(){plot_ba.refresh();},5*60*1000);
var plot_wdsl = new world_dx_spots_live ('chart-world_dx_spots_live','/plot_get_world_dx_spots_live');
setInterval(function(){plot_wdsl.refresh();},5*60*1000);
var plot_ba = new band_activity('chart-band_activity', '/plot_get_heatmap_data', continents_cq, band_frequencies);
setInterval(function () { plot_ba.refresh(); }, 5 * 60 * 1000);
var plot_hb = new hour_band('chart-hour_band','/plot_get_hour_band',band_frequencies);
setInterval(function(){plot_hb.refresh();},1*60*60*1000);
var plot_wdsl = new world_dx_spots_live('chart-world_dx_spots_live', '/plot_get_world_dx_spots_live');
setInterval(function () { plot_wdsl.refresh(); }, 5 * 60 * 1000);
var plot_dspm = new dx_spots_per_month ('chart-dx_spots_x_month','/plot_get_dx_spots_per_month');
setInterval(function(){plot_dspm.refresh();},12*60*60*1000);
var plot_hb = new hour_band('chart-hour_band', '/plot_get_hour_band', band_frequencies);
setInterval(function () { plot_hb.refresh(); }, 1 * 60 * 60 * 1000);
var plot_dst = new dx_spots_trend ('chart-dx_spots_trend','/plot_get_dx_spots_trend');
setInterval(function(){plot_dst.refresh();},12*60*60*1000);
var plot_dspm = new dx_spots_per_month('chart-dx_spots_x_month', '/plot_get_dx_spots_per_month');
setInterval(function () { plot_dspm.refresh(); }, 12 * 60 * 60 * 1000);
var plot_dst = new dx_spots_trend('chart-dx_spots_trend', '/plot_get_dx_spots_trend');
setInterval(function () { plot_dst.refresh(); }, 12 * 60 * 60 * 1000);

View File

@ -164,7 +164,7 @@ class table_builder {
const td_comm = document.createElement('td');
td_comm.className = 'd-none d-lg-table-cell d-xl-table-cell';
try {
td_comm.textContent = line.comm.substring(0,100);
td_comm.textContent = line.comm.substring(0, 100);
} catch (err) {
td_comm.textContent = '';
}
@ -245,7 +245,7 @@ class table_builder {
return new bootstrap.Popover(popoverTriggerEl);
});
this.first_time=false;
this.first_time = false;
}
}
} //end class
@ -257,7 +257,7 @@ class table_builder {
const adxo_url = 'https://www.ng3k.com/misc/adxo.html';
const qrz_url = 'https://www.qrz.com/db/';
const tb = new table_builder('bodyspot');
var qryAll_sv = '';
var params_sv = {};
/**
* Decode Announced Dx Operation (ng3k)
@ -274,6 +274,8 @@ function findAdxo(adxo, callsign_to_find) {
}
}
}
/**
* Function to filter spot when pressed the search button on filter
* This function trigger the search, also triggered by timer
@ -287,38 +289,42 @@ function mySearch(event) {
* Function for construct query string for single value selection
*
* @param id {string} The html identifier used for filter
* @param param {string}the parameter for the query
* @param len {number} The maximum number of element that could be selected; use -1 if the filter permits a single selection
* @param qrystr {string} Th initial query string to be completed with the new filter
* @param qry_json {object} The input json
*/
function getFilter(id, param, len, qrystr) {
function compose_filter(id, len, qry_json) {
try {
let selectedFilter = [].map.call(document.getElementById(id).selectedOptions, option => option.value);
let qryFilter = '';
if (selectedFilter.length < len || len == -1) {
qryFilter = selectedFilter.map(function (el) {
if (selectedFilter.length < len) {
qry_json[id] = [];
selectedFilter.map(function (el) {
if (el) {
return param + '=' + el;
qry_json[id].push(el);
} else {
return '';
}
}).join('&');
qrystr = qrystr.concat('&'.concat(qryFilter));
if (qrystr.substring(0, 1) == '&') {
qrystr = qrystr.substring(1);
}
}
});
} else if (len == -1) {
selectedFilter.map(function (el) {
if (el) {
qry_json[id]=el;
} else {
return '';
}
});
}
}
catch (err) {
if (err.name == 'TypeError') {
/* error managed: it is ok: probabilly ther is no filter on cq region */
if (err.name == 'TypeError') {
console.error(err.name);
/* error managed: it is ok: probabilly ther is no filter on cq region */
} else {
throw err;
}
}
}
return qrystr;
return qry_json;
}
/**
@ -328,35 +334,41 @@ function getFilter(id, param, len, qrystr) {
*/
function refresh_timer() {
let qryAll = '';
let params = {};
//get other filters
qryAll = getFilter('band', 'b', 14, qryAll);
qryAll = getFilter('de_re', 'e', 7, qryAll);
qryAll = getFilter('dx_re', 'x', 7, qryAll);
qryAll = getFilter('mode', 'm', 3, qryAll);
qryAll = getFilter('cqdeInput', 'qe', -1, qryAll);
qryAll = getFilter('cqdxInput', 'qx', -1, qryAll);
params = compose_filter('band', 14, params);
params = compose_filter('de_re', 7, params);
params = compose_filter('dx_re', 7, params);
params = compose_filter('mode', 3, params);
params = compose_filter('cqdeInput', -1, params);
params = compose_filter('cqdxInput', -1, params);
//Composing query string
let qryString;
delete params_sv['lr']; //remove line row number, for future param comparison
//If the filter is changed we need to reset the data table and restart from rowid=0
if (qryAll != qryAll_sv) {
if (JSON.stringify(params) !== JSON.stringify(params_sv)) {
tb.resetData();
qryAll_sv = qryAll;
params_sv = params;
}
qryString = ('spotlist?lr=').concat(tb.getLastRowId());
if (qryAll) {
qryString = qryString.concat('&'.concat(qryAll));
}
params['lr']=tb.getLastRowId();
//Open a new connection, using the GET request on the URL endpoint
<<<<<<< HEAD
qryString=qryString.concat('&'.concat(Math.random())); //used to prevent caching
fetch(qryString)
=======
//let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content");
fetch('spotlist', {
method: 'POST',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify( params )
})
>>>>>>> staging
.then((response) => response.json())
.then((data_new) => {
try {

View File

@ -1 +1 @@
var my_adxo_events=JSON.parse(my_adxo_events_json.replaceAll("\t","")),qryString="spotlist?c="+callsign;fetch(qryString).then(l=>l.json()).then(o=>{try{tb.build(o,callsign)}catch(l){console.log(l),console.log(l.stack),console.log(o)}});
var my_adxo_events=JSON.parse(my_adxo_events_json.replaceAll("\t",""));let params={};params.callsign=callsign,fetch("spotlist",{method:"POST",cache:"no-cache",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify(params)}).then(e=>e.json()).then(a=>{try{tb.build(a,callsign)}catch(e){console.log(e),console.log(e.stack),console.log(a)}});

View File

@ -1 +1 @@
function myCallsignSearch(e){e.preventDefault(),0<(callsign=document.getElementById("callsignInput").value).replace(/\s/g,"").length&&(location.href="/callsign.html?c=".concat(callsign.trim().toUpperCase()),console.log(location.href))}document.getElementById("form-callsign").addEventListener("submit",myCallsignSearch);
function myCallsignSearch(e){e.preventDefault(),0<(callsign=document.getElementById("callsignInput").value).replace(/\s/g,"").length&&(location.href="/callsign.html?c=".concat(callsign.trim().toUpperCase()))}document.getElementById("form-callsign").addEventListener("submit",myCallsignSearch);

View File

@ -1 +1 @@
function setCookie(e,t,n){var o=new Date,n=(o.setTime(o.getTime()+24*n*60*60*1e3),"expires="+o.toUTCString());"https:"==location.protocol?document.cookie=e+"="+t+";"+n+";path=/;Samesite=Strict;Secure=True":(console.log("Warning: could not set secure cookie: try with Samsite Lax..."),document.cookie=e+"="+t+";"+n+";path=/;Samesite=Lax")}function getCookie(e){var n=e+"=",o=decodeURIComponent(document.cookie).split(";");for(let t=0;t<o.length;t++){let e=o[t];for(;" "==e.charAt(0);)e=e.substring(1);if(0==e.indexOf(n))return e.substring(n.length,e.length)}return""}function get_last_refresh(e){var t=new Date(0),e=(t.setUTCSeconds(e.last_refresh),(e,t=2)=>(""+new Array(t).fill(0)+e).slice(-t)),n=e(t.getHours()),e=e(t.getMinutes()),o=get_months_names()[t.getMonth()];return"Data refresh: "+t.getDate()+" of "+o+" "+t.getFullYear()+" at "+n+":"+e}function get_months_names(){var t=[];for(let e=1;e<13;e++){var n=new Date;n.setMonth(e-1),t.push(n.toLocaleString("en-US",{month:"short"}))}return t}function format_u_k_m(e){let t,n=1;e<0&&(n=-1);e=Math.abs(e);return 0==e?t=e:0<e&&e<1e3?t=e*n:1e3<=e&&e<1e6?t=e/1e3*n+"K":1e6<=e&&(t=e/1e6*n+"M"),t}function selectElement(e,t){document.getElementById(e).value=t}function addEventHandler(e,t,n){e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent&&e.attachEvent("on"+t,n)}function setText(e,t){document.getElementById(e).innerHTML=t}function showTime(){var e=new Date;let t=new Date(e.getTime()+6e4*e.getTimezoneOffset()).toTimeString().split(" ")[0];t=t.split(":")[0]+":"+t.split(":")[1],document.getElementById("MyClockDisplay").innerText=t,document.getElementById("MyClockDisplay").textContent=t,setTimeout(showTime,1e3)}document.getElementById("MyClockDisplay").addEventListener("load",showTime()),document.getElementById("copyDate").innerHTML="2020-".concat((new Date).getFullYear());
function setCookie(e,t,n){var o=new Date,n=(o.setTime(o.getTime()+24*n*60*60*1e3),"expires="+o.toUTCString());"https:"==location.protocol?document.cookie=e+"="+t+";"+n+";path=/;Samesite=Strict;Secure=True":(console.log("Warning: could not set secure cookie: try with Samsite Lax..."),document.cookie=e+"="+t+";"+n+";path=/;Samesite=Lax")}function getCookie(e){var n=e+"=",o=decodeURIComponent(document.cookie).split(";");for(let t=0;t<o.length;t++){let e=o[t];for(;" "==e.charAt(0);)e=e.substring(1);if(0==e.indexOf(n))return e.substring(n.length,e.length)}return""}function get_last_refresh(e){var t=new Date(0),e=(t.setUTCSeconds(e.last_refresh),(e,t=2)=>(""+new Array(t).fill(0)+e).slice(-t)),n=e(t.getHours()),e=e(t.getMinutes()),o=get_months_names()[t.getMonth()];return"Data refresh: "+t.getDate()+" of "+o+" "+t.getFullYear()+" at "+n+":"+e}function get_months_names(){var t=[];for(let e=1;e<13;e++){var n=new Date;n.setMonth(e-1),t.push(n.toLocaleString("en-US",{month:"short"}))}return t}function format_u_k_m(e){let t,n=1;e<0&&(n=-1);e=Math.abs(e);return 0==e?t=e:0<e&&e<1e3?t=e*n:1e3<=e&&e<1e6?t=e/1e3*n+"K":1e6<=e&&(t=e/1e6*n+"M"),t}function selectElement(e,t){document.getElementById(e).value=t}function addEventHandler(e,t,n){e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent&&e.attachEvent("on"+t,n)}function setText(e,t){document.getElementById(e).innerHTML=t}function showTime(){var e=new Date;let t=new Date(e.getTime()+6e4*e.getTimezoneOffset()).toTimeString().split(" ")[0];t=t.split(":")[0]+":"+t.split(":")[1],document.getElementById("MyClockDisplay").innerText=t,document.getElementById("MyClockDisplay").textContent=t,setTimeout(showTime,1e3)}document.getElementById("MyClockDisplay").addEventListener("load",showTime()),document.getElementById("copyDate").innerHTML="2020-".concat((new Date).getFullYear());let button_top=document.getElementById("btn-back-to-top");function scrollFunction(){20<document.body.scrollTop||20<document.documentElement.scrollTop?button_top.style.display="block":button_top.style.display="none"}function backToTop(){document.body.scrollTop=0,document.documentElement.scrollTop=0}window.onscroll=function(){scrollFunction()},button_top.addEventListener("click",backToTop);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
{
"name": "IU1BOW Spiderweb v2.4.2",
"name": "IU1BOW Spiderweb v2.4.5",
"description": "DXCluser for ham radio by IU1BOW",
"short_name": "Spiderweb",
"theme_color": "#f3b221",

View File

@ -1,5 +1,5 @@
// Dichiarazione della costante per il nome della cache
const CACHE_NAME = 'pwa-spiderweb_v2.4.2'
const CACHE_NAME = 'pwa-spiderweb_v2.4.5'
// Dichiarazione della costante per gli URL da mettere in cache
const URLS_TO_CACHE = [
@ -21,9 +21,10 @@ const URLS_TO_CACHE = [
'/static/js/rel/callsign_inline.min.js',
'/static/js/rel/callsign_search.min.js',
'/static/js/rel/common.min.js',
'/index.html',
'/plots.html',
'/privacy.html',
'/cookies.html',
'/offline.html',
'/cookies.html'
];
@ -65,7 +66,7 @@ self.addEventListener('fetch', event => {
.then(response => {
if (response.status === 502) {
console.log("response status: " + response.status);
return caches.match('/offline.html');
return caches.match('/index.html');
}
if (!response || response.status !== 200 || response.type !== 'basic') {
console.log("response: " + response.status);
@ -80,7 +81,7 @@ self.addEventListener('fetch', event => {
})
.catch(error => {
console.log(error);
return caches.match('/offline.html');
return caches.match('/index.html');
});
})
);

View File

@ -17,9 +17,8 @@
<link rel="stylesheet" href="/static/css/rel/style.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css"
integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/6.6.6/css/flag-icons.min.css"
integrity="sha512-uvXdJud8WaOlQFjlz9B15Yy2Au/bMAvz79F7Xa6OakCl2jvQPdHD0hb3dEqZRdSwG4/sknePXlE7GiarwA/9Wg=="
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/6.15.0/css/flag-icons.min.css"
integrity="sha512-bZBu2H0+FGFz/stDN/L0k8J0G8qVsAL0ht1qg5kTwtAheiXwiRKyCq1frwfbSFSJN3jooR5kauE0YjtPzhZtJQ=="
crossorigin="anonymous" referrerpolicy="no-referrer" />
{% endblock head %}
@ -44,18 +43,18 @@
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
{% for dict_item in menu_list %}
<li class="nav-item">
<a class="nav-link {% if request.path == dict_item["link"] %} active {% endif %}" href="{{dict_item["link"]}}"
{% if dict_item["external"] %}
<a class="nav-link {% if request.path == dict_item["link"] %} active {% endif %}" href="{{dict_item['link']}}"
{% if dict_item['external'] %}
target="blank" rel="noopener"
{% endif %}
>{{dict_item["label"]}}<span class="sr-only"></span></a>
</li>
{% endfor %}
{% endfor %}
</ul>
<div id="MyClockDisplay" class="text-white-50 d-none d-lg-block"></div>
<div class="text-white-50 d-none d-lg-block">&nbsp;(UTC)&nbsp;&nbsp;</div>
{% block callsign %}
<form method="POST" class="d-flex" id="form-callsign" enctype="multipart/form-data">
<form method="POST" class="d-flex" id="form-callsign" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<div class="input-group" id='input-group-callsign'>
<input type="text" class="form-control" placeholder="callsign" aria-label="callsign"
@ -92,10 +91,7 @@
<span class="copyleft">&copy;</span> Copyleft:
<span id="copyDate"></span>
<a href="https://github.com/coulisse/spiderweb/" target="blank" rel="noopener">IU1BOW - Spiderweb</a>
<span id="version">v2.4.2</span>
<!--
<a href="https://github.com/coulisse/spiderweb/" target="blank" rel="noopener"><img src="/static/images/icons/github-mark.svg" alt="github.com" width="16px" height="16px"></a>
-->
<span id="version">v2.4.5</span>
</div>
</footer>
<script async src="static/js/rel/load-sw.min.js"></script>
@ -105,9 +101,11 @@
{% endblock app_data %}
</script>
<script defer src="static/js/rel/common.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js"
integrity="sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa"
<script defer src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4"
crossorigin="anonymous"></script>
</body>
{% block app_scripts %}
<script async src="static/js/rel/callsign_search.min.js"></script>
{% endblock app_scripts %}
@ -119,7 +117,6 @@
{# then user has already consented so no requirement for consent banner #}
{% else %}
{# show a cookie consent banner #}
<!-- Modal for cookie consent-->
<div class="modal fade" id="cookie_consent_modal" tabindex="-1" aria-labelledby="cookie-consent-container"
aria-hidden="true">
@ -142,7 +139,11 @@
<script defer src="static/js/rel/cookie_consent.min.js"></script>
{% endif %}
{% endblock cookie %}
{% endblock cookie %}
<!-- Back to top button -->
<button type="button" class="btn btn-secondary btn-floating btn-lg" id="btn-back-to-top">
<i class="bi bi-arrow-up"></i>
</button>
</body>
</html>

View File

@ -24,7 +24,7 @@
<div class="row mx-auto">
<!--Sidebar content-->
<div class="col-md-auto ml-2 collapse rounded-sm shadow mb-5 bg-body" id="collapseFilters">
<form method="POST" id="form-filters" enctype="multipart/form-data">
<form method="POST" id="form-filters" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<strong>Band</strong>
<select class="form-select overflow-hidden" id="band" size="14" multiple>
@ -167,7 +167,14 @@
<button type="submit" class="btn btn-primary btn-block w-100" aria-pressed="true" data-toggle="collapse"
data-target="#collapseFilters" aria-expanded="false" aria-controls="collapseFilters"
aria-label="filter">Search</button>
<p></p>
<button type="Reset" class="btn btn-primary btn-block w-100" aria-pressed="true" data-toggle="collapse"
data-target="#collapseFilters" aria-expanded="false" aria-controls="collapseFilters"
aria-label="reset_filter">Reset</button>
</div>
<div class="mx-auto">
</div>
</form>
</div>
@ -288,7 +295,6 @@
</tr>
<tr>
</tr>
</tbody>
</table>
</div>

View File

@ -20,7 +20,7 @@
<div id="dashboard" class="d-flex flex-wrap justify-content-around">
<div class="shadow-lg mb-5 rounded spider_chart" id="form-band_activity">
<div class="d-flex flex-column">
<form method="POST" id="form-continents" enctype="multipart/form-data">
<form method="POST" id="form-continents" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<div class="container">
Your continent is:
@ -86,8 +86,8 @@ var band_frequencies={{bands["bands"]|tojson|safe}};
{% block app_scripts %}
{{ super() }}
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.4.1/echarts.min.js"
integrity="sha512-OTbGFYPLe3jhy4bUwbB8nls0TFgz10kn0TLkmyA+l3FyivDs31zsXCjOis7YGDtE2Jsy0+fzW+3/OVoPVujPmQ=="
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.4.3/echarts.min.js"
integrity="sha512-EmNxF3E6bM0Xg1zvmkeYD3HDBeGxtsG92IxFt1myNZhXdCav9MzvuH/zNMBU1DmIPN6njrhX1VTbqdJxQ2wHDg=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script defer src="static/js/rel/plot.min.js"></script>
{% endblock app_scripts %}

View File

@ -30,6 +30,7 @@ app.config.update(
inline_script_nonce = ""
csrf = CSRFProtect(app)
logger.debug(app.config)
if app.config["DEBUG"]:
@ -94,17 +95,24 @@ def query_build_callsign(callsign):
return query_string
def query_build():
def query_build(parameters):
try:
# get url parameters
last_rowid = request.args.get("lr") # Last rowid fetched by front end
band = request.args.getlist("b") # band filter
dere = request.args.getlist("e") # DE continent filter
dxre = request.args.getlist("x") # Dx continent filter
mode = request.args.getlist("m") # mode filter
decq = request.args.getlist("qe") # DE cq zone filter
dxcq = request.args.getlist("qx") # DX cq zone filter
last_rowid = str(parameters["lr"]) # Last rowid fetched by front end
get_param = lambda parameters, parm_name: parameters[parm_name] if (parm_name in parameters) else []
band=get_param(parameters, "band")
dere=get_param(parameters, "de_re")
dxre=get_param(parameters, "dx_re")
mode=get_param(parameters, "mode")
decq = []
if "cqdeInput" in parameters:
decq[0] = parameters["cqdeInput"]
dxcq = []
if "cqdxInput" in parameters:
dxcq[0] = parameters["cqdxInput"]
query_string = ""
@ -120,7 +128,6 @@ def query_build():
)
band_qry_string += "))"
# construct mode query
mode_qry_string = " AND (("
for i, item_mode in enumerate(mode):
@ -138,7 +145,6 @@ def query_build():
)
mode_qry_string += "))"
# construct DE continent region query
dere_qry_string = " AND spottercq IN ("
for i, item_dere in enumerate(dere):
@ -179,6 +185,7 @@ def query_build():
+ last_rowid
)
if len(band) > 0:
query_string += band_qry_string
@ -210,15 +217,15 @@ def query_build():
# the main query to show spots
# it gets url parameter in order to apply the build the right query
# and apply the filter required. It returns a json with the spots
def spotquery():
def spotquery(parameters):
try:
callsign = request.args.get("c") # search specific callsign
if callsign:
query_string = query_build_callsign(callsign)
if 'callsign' in parameters:
logging.debug('search callsign')
query_string = query_build_callsign( parameters['callsign'] )
else:
query_string = query_build()
logging.debug('search eith other filters')
query_string = query_build(parameters)
qm.qry(query_string)
data = qm.get_data()
@ -246,11 +253,9 @@ def spotquery():
except Exception as e:
logger.error(e)
# find adxo events
adxo_events = None
def get_adxo():
global adxo_events
adxo_events = get_adxo_events()
@ -267,15 +272,19 @@ bubble_graph_hb = HourBand(logger, qm, band_frequencies)
geo_graph_wdsl = WorldDxSpotsLive(logger, qm, pfxt)
# ROUTINGS
@app.route("/spotlist", methods=["GET"])
@app.route("/spotlist", methods=["POST"])
@csrf.exempt
def spotlist():
response = flask.Response(json.dumps(spotquery()))
logger.debug(request.json)
response = flask.Response(json.dumps(spotquery(request.json)))
return response
def who_is_connected():
host_port = cfg["telnet"].split(":")
response = who(host_port[0], host_port[1], cfg["mycallsign"])
logger.debug("list of connected clusters:")
logger.debug(response)
return response
#Calculate nonce token used in inline script and in csp "script-src" header
@ -313,7 +322,6 @@ def sw():
def root():
return app.send_static_file("html/offline.html")
@app.route("/world.json")
def world_data():
return app.send_static_file("data/world.json")
@ -336,7 +344,6 @@ def plots():
)
return response
@app.route("/cookies.html", methods=["GET"])
def cookies():
response = flask.Response(
@ -351,7 +358,6 @@ def cookies():
)
return response
@app.route("/privacy.html", methods=["GET"])
def privacy():
response = flask.Response(
@ -366,7 +372,6 @@ def privacy():
)
return response
@app.route("/sitemap.xml")
def sitemap():
return app.send_static_file("sitemap.xml")
@ -404,9 +409,12 @@ def find_callsign():
return response
@app.route("/plot_get_heatmap_data", methods=["GET"])
@app.route("/plot_get_heatmap_data", methods=["POST"])
@csrf.exempt
def get_heatmap_data():
continent = request.args.get("continent")
#continent = request.args.get("continent")
continent = request.json['continent']
logger.debug(request.get_json());
response = flask.Response(json.dumps(heatmap_cbp.get_data(continent)))
logger.debug(response)
if response is None:
@ -414,7 +422,8 @@ def get_heatmap_data():
return response
@app.route("/plot_get_dx_spots_per_month", methods=["GET"])
@app.route("/plot_get_dx_spots_per_month", methods=["POST"])
@csrf.exempt
def get_dx_spots_per_month():
response = flask.Response(json.dumps(bar_graph_spm.get_data()))
logger.debug(response)
@ -423,7 +432,8 @@ def get_dx_spots_per_month():
return response
@app.route("/plot_get_dx_spots_trend", methods=["GET"])
@app.route("/plot_get_dx_spots_trend", methods=["POST"])
@csrf.exempt
def get_dx_spots_trend():
response = flask.Response(json.dumps(line_graph_st.get_data()))
logger.debug(response)
@ -432,7 +442,8 @@ def get_dx_spots_trend():
return response
@app.route("/plot_get_hour_band", methods=["GET"])
@app.route("/plot_get_hour_band", methods=["POST"])
@csrf.exempt
def get_dx_hour_band():
response = flask.Response(json.dumps(bubble_graph_hb.get_data()))
logger.debug(response)
@ -441,7 +452,8 @@ def get_dx_hour_band():
return response
@app.route("/plot_get_world_dx_spots_live", methods=["GET"])
@app.route("/plot_get_world_dx_spots_live", methods=["POST"])
@csrf.exempt
def get_world_dx_spots_live():
response = flask.Response(json.dumps(geo_graph_wdsl.get_data()))
logger.debug(response)