Skip to content

Commit d752e8f

Browse files
committed
implement manual date/time "handkey" interface
Signed-off-by: Jason D. McCormick <[email protected]>
1 parent f07e8b1 commit d752e8f

File tree

4 files changed

+270
-16
lines changed

4 files changed

+270
-16
lines changed

CHANGELOG.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
-------------------------
2+
** v3.1.0 - 2022-06-11
3+
-------------------------
4+
- Implement an interface for manual entry of logs with a
5+
user-setable date and time
6+
17
-------------------------
28
** v3.0.0 - 2022-04-27
39
-------------------------

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ The following URL endpoints are the support "entries" into the system:
155155

156156
`/index.html` - Main interface
157157

158+
`/handkey.html` - Interface for hand-keying in a paper log
159+
158160
`/board.html` - Display "board" for a running tally display screen
159161

160162
`/cabrillo.html` - Download a Cabrillo log of all contacts
@@ -217,6 +219,15 @@ found in `api/config_bands.json`. Users of `adif.php` and `cabrillo.php`
217219
will also have to hand-edit those export functions to map added bands appropriately.
218220
A future release will fix this.
219221

222+
## Handkey Interface
223+
224+
The `handkey.html` screen is for someone to hand-enter QSOs from people who
225+
didn't want to log electronically. Obviously not using the live interface can
226+
cause potential dupes, etc. However this provides a way for someone to either
227+
bulk-enter someone's paper log or provide and interface to someone who likes
228+
to write the QSO on paper then enter it and still the correct date/time. On
229+
the main screen, the log time is not editable.
230+
220231
## Issues
221232

222233
For any discovered issues, please file an Issue within Github.

handkey.html

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
<html>
2+
<head>
3+
<meta charset="utf-8">
4+
<meta name="viewport" content="width=device-width, initial-scale=1">
5+
<title>Firefly Field Day Logger</title>
6+
<link href="css/bootstrap.min.css" rel="stylesheet">
7+
<link href="css/jquery.typeahead.min.css" rel="stylesheet">
8+
<link href="css/local.css" rel="stylesheet">
9+
<link rel="shortcut icon" href="img/firefly.svg" sizes="any" type="image/svg+xml">
10+
<link rel="manifest" href="manifest.json">
11+
</head>
12+
<body>
13+
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
14+
<symbol id="check-circle-fill" fill="currentColor" viewBox="0 0 16 16">
15+
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"/>
16+
</symbol>
17+
<symbol id="info-fill" fill="currentColor" viewBox="0 0 16 16">
18+
<path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm.93-9.412-1 4.705c-.07.34.029.533.304.533.194 0 .487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703 0-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381 2.29-.287zM8 5.5a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/>
19+
</symbol>
20+
<symbol id="exclamation-triangle-fill" fill="currentColor" viewBox="0 0 16 16">
21+
<path d="M8.982 1.566a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566zM8 5c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995A.905.905 0 0 1 8 5zm.002 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2z"/>
22+
</symbol>
23+
</svg>
24+
<main>
25+
<div class="titlebars" style="height: 75px;">
26+
<table width="100%" height="100%">
27+
<tr class="titlebars">
28+
<td width="20%" style="vertical-align: middle; text-align: center;">
29+
<img src="img/firefly.svg" height="45px"><span class="px-2">Firefly Logger</span>
30+
</td>
31+
<td width="60%" style="vertical-align: middle; text-align: center;">
32+
<form id="stationset" name="stationset">
33+
<table width="100%" height="100%" class="stationsett">
34+
<tbody style="background-color: rgba(255,255,255,0.5);" class="shadow">
35+
<td style="text-align: center;" class="p-2">
36+
<b>Station Info</b>
37+
</td>
38+
<td>
39+
<input type="text" id="callsign" name="callsign" size="10" class="form-control" placeholder="Callsign" autocomplete="off" readonly>
40+
</td>
41+
<td id="set-operator">
42+
<input type="text" id="operator" name="operator" size="10" class="form-control" placeholder="Operator" autocomplete="off">
43+
</td>
44+
<td>
45+
<select id="band" name="band" class="form-control">
46+
<option value="X">Select Band...</option>
47+
</select>
48+
</td>
49+
<td>
50+
<select id="mode" name="mode" class="form-control">
51+
<option value="X">Select Mode...</option>
52+
</select>
53+
</td>
54+
<td style="text-align: center;" class="p-2">
55+
<button type="button" class="btn btn-misc btn-sm" onclick="saveStationData()">Set</button>
56+
</td>
57+
</tbody>
58+
</table>
59+
</form>
60+
</td>
61+
<td width="20%" style="vertical-align: middle; text-align: center;">
62+
<img src="img/firefly.svg" height="45px"><span class="px-2">Firefly Logger</span>
63+
</td>
64+
</tr>
65+
</table>
66+
</div>
67+
<div class="container-md qso-entry-container shadow">
68+
<div class="row">
69+
<form id="log" name="log">
70+
<table class="table table-borderless">
71+
<thead>
72+
<th scope="col" style="width: 15%">Date<br><i>YYYY-MM-DD</i></th>
73+
<th scope="col" style="width: 10%">Time<br><i>HHMM</i></th>
74+
<th scope="col" style="width: 15%">Callsign</th>
75+
<th scope="col" style="width: 10%">Class</th>
76+
<th scope="col" style="width: 10%">Section</th>
77+
<th scope="col" style="width: 10%">&nbsp;</th>
78+
<th scope="col" style="width: 10%">&nbsp;</th>
79+
<th scope="col" style="width: 15%"></th>
80+
81+
82+
</thead>
83+
<tbody>
84+
<td class="align-top">
85+
<input type="text" size=12 name="logclockdate" id="logclockdate" class="form-control"
86+
tabindex="-1" autocomplete="off">
87+
</td>
88+
<td class="align-top">
89+
<input type="text" size=5 name="logclocktime" id="logclocktime" class="form-control"
90+
autocomplete="off">
91+
</td>
92+
<td class="align-top">
93+
<input id="call" name="call" type="text" size="10" class="form-control"
94+
onkeyup="this.value = this.value.toUpperCase();" onblur="isDupeQSO()" autocomplete="off">
95+
</td>
96+
<td class="align-top">
97+
<input id="opclass" name="opclass" type="text" size="10" class="form-control"
98+
onkeyup="this.value = this.value.toUpperCase();" autocomplete="off">
99+
</td>
100+
<td class="align-top">
101+
<div id="arrl-sections">
102+
<input id="section" name="section" class="typeahead form-control" type="text"
103+
size="10" autocomplete="off" onkeyup="this.value = this.value.toUpperCase();">
104+
</div>
105+
</td>
106+
<td class="align-top" align="center">
107+
<button id="logsubmit" name="logsubmit" type="button" class="btn btn-danger"
108+
onclick="logSubmit()">Log</button>
109+
</td>
110+
<td class="align-top" align="left">
111+
<button id="logclear" name="logclear" type="button" class="btn btn-misc"
112+
onclick="logReset()" tabindex="-1">Clear</button>
113+
</td>
114+
<td><!-- future --> </td>
115+
</tbody>
116+
</table>
117+
<input type="hidden" id="logclock" name="logclock" value="">
118+
<input type="hidden" id="opcallsign" name="opcallsign" value="">
119+
<input type="hidden" id="opoperator" name="opoperator" value="">
120+
<input type="hidden" id="opband" name="opband" value="">
121+
<input type="hidden" id="opmode" name="opmode" value="">
122+
<input type="hidden" id="qkey" name="qkey" value="">
123+
</form>
124+
</div>
125+
<div class="row">
126+
<div id="d-flex">
127+
<div id="statusarea" class="invisible alert d-flex align-items-center alert-dismissable fade show" role="alert"></div>
128+
</div>
129+
</div>
130+
</div>
131+
<script src="js/bootstrap.min.js"></script>
132+
<script src="js/jquery-3.6.0.min.js"></script>
133+
<script src="js/typeahead.jquery.js"></script>
134+
<script src="js/statusmsg.js"></script>
135+
<script src="js/index.js"></script>
136+
</main>
137+
<footer>
138+
<div class="d-flex footerbar p-2"><i>Powered by Firefly Field Day Logger by Jason McCormick N8EI - <a href="https://github.com/jxmx/ffdl" tabindex="-1">GitHub</a></i></div>
139+
</footer>
140+
</body>
141+
</html>

js/index.js

Lines changed: 112 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ let config = {
2424
var qsinceload = 0;
2525
var sectionsloaded = false;
2626
var stationcookieexists = false;
27+
var thispage = location.href.split("/").slice(-1);
28+
29+
if(thispage == "handkey.html")
30+
var isHandKey = true;
2731

2832
// load configuration from JSON files
2933
function getConfig(configType){
@@ -34,25 +38,20 @@ function getConfig(configType){
3438
var a = JSON.parse(this.responseText);
3539
switch(configType){
3640
case "general":
37-
console.log("get config general");
3841
config.general = a;
39-
console.log("set config general");
4042
setGeneralConfig();
4143
break;
4244
case "bands":
43-
console.log("get config bands");
4445
config.bands = a;
4546
refreshBandList(config.bands.band);
4647
setStationDataFromCookie();
4748
break;
4849
case "modes":
49-
console.log("get config modes");
5050
config.modes = a;
5151
refreshModeList(config.modes.modes);
5252
setStationDataFromCookie();
5353
break;
5454
case "sections":
55-
console.log("get config sections");
5655
config.sections = a;
5756
sectionsloaded = true;
5857
break;
@@ -91,10 +90,14 @@ window.addEventListener("load", function(){
9190
getConfig("bands");
9291
getConfig("modes");
9392
getConfig("sections");
94-
setGeneralConfig();
95-
updateLogTime();
96-
setInterval(updateLogTime,1000);
97-
setInterval(testCookieExists,1000);
93+
94+
// Only things for the main form at index.html
95+
if(thispage == "index.html" || thispage == ""){
96+
setGeneralConfig();
97+
updateLogTime();
98+
setInterval(updateLogTime,1000);
99+
setInterval(testCookieExists,1000);
100+
}
98101
});
99102

100103
//
@@ -135,6 +138,8 @@ var submitOkCall = false;
135138
var submitOkClass = false;
136139
var submitOkSection = false;
137140
var submitOkDupe = false;
141+
var submitOkLogClockDate = false;
142+
var submitOkLogClockTime = false;
138143

139144
//
140145
// QSO Call Validation - is callsign well-formed
@@ -301,12 +306,21 @@ function resetSubmitOkStatus() {
301306
submitOkClass = false;
302307
submitOkSection = false;
303308
submitOkDupe = false;
309+
submitOkLogClockDate = false;
310+
submitOkLogClockTime = false;
304311
toggleLogButton(false);
305312
}
306313

307314
// check if it's ready to submit
308315
function checkSubmitOkStatus() {
309-
if( submitOkCall && submitOkClass && submitOkSection ){ // && submitOkDupe )
316+
if( submitOkCall && submitOkClass && submitOkSection ){
317+
if(isHandKey){
318+
if(submitOkLogClockDate && submitOkLogClockTime){
319+
return true;
320+
} else {
321+
return false;
322+
}
323+
}
310324
return true;
311325
} else {
312326
return false;
@@ -331,7 +345,9 @@ function logSubmit() {
331345
lform.method = "POST";
332346
lform.action = "#";
333347

334-
// Generate and store the qkey hash
348+
// If this is the handkey.html version the date/time needs to be parsed out
349+
if(isHandKey)
350+
handkeyDateTime();
335351

336352
// I have no idea whyu these can't be directly assigned by value.... Javascript is annoying
337353
var opcallsign= document.getElementById("callsign").value;
@@ -367,7 +383,8 @@ function logSubmit() {
367383
}
368384

369385
// update the display and clear the entry
370-
updateDisplayLog();
386+
if(!isHandKey)
387+
updateDisplayLog();
371388
logReset();
372389
},
373390
failure: function(msg) {
@@ -380,13 +397,92 @@ function logSubmit() {
380397

381398
// reset the log form
382399
function logReset() {
383-
clearStatusMsg();
400+
// clearStatusMsg();
384401
resetSubmitOkStatus();
402+
403+
// save the date for handkeying
404+
if(isHandKey)
405+
var lcd = document.getElementById("logclockdate").value;
406+
385407
document.getElementById("log").reset();
408+
386409
$('#log input').parent().find('input').removeClass("is-invalid").removeClass("is-valid");
387-
document.getElementById("call").focus();
410+
411+
if(isHandKey){
412+
document.getElementById("logclockdate").value = lcd;
413+
document.getElementById("logclocktime").focus();
414+
} else {
415+
document.getElementById("call").focus();
416+
}
388417
};
389418

419+
// handkey.html variant support
420+
function handkeyDateTime() {
421+
var lcd = document.getElementById("logclockdate").value;
422+
var lct = document.getElementById("logclocktime").value;
423+
var logclock = lcd.concat(" ", lct.slice(0,2), ":", lct.slice(2,4), ":", "00");
424+
document.getElementById("logclock").value = logclock;
425+
};
426+
427+
$('#logclockdate').focusout(function() {
428+
var input=$(this);
429+
var re = /^[0-9]{4}\-[0-9]{2}\-[0-9]{2}$/;
430+
var is_valid = true;
431+
var dt = input.val();
432+
433+
if(re.test(input.val())){
434+
var y = dt.slice(0,4);
435+
var m = dt.slice(5,7);
436+
var d = dt.slice(8,12);
437+
438+
// Y2K1 problem!
439+
if(y < 2000 || y > 2100 ) is_valid = false;
440+
if(m < 1 || m > 12 ) is_valid = false;
441+
if(d < 1 || d > 31 ) is_valid = false;
442+
443+
} else {
444+
is_valid = false;
445+
}
446+
447+
if(is_valid){
448+
input.removeClass("is-invalid").addClass("is-valid");
449+
submitOkLogClockDate = true;
450+
} else {
451+
input.removeClass("is-valid").addClass("is-invalid");
452+
submitOkLogClockDate = false;
453+
}
454+
});
455+
456+
$('#logclocktime').focusout(function() {
457+
var input=$(this);
458+
var re = /^[0-9]{3,4}$/;
459+
var is_valid = true;
460+
var t = input.val();
461+
462+
if(re.test(input.val())){
463+
if(t.length == 3)
464+
t = "0".concat(t);
465+
document.getElementById("logclocktime").value = t;
466+
var hh = t.slice(0,2);
467+
var mm = t.slice(2,4);
468+
469+
if(hh < 0 || hh > 23) is_valid = false;
470+
if(mm < 0 || mm > 59) is_valid = false;
471+
472+
} else {
473+
is_valid = false;
474+
}
475+
476+
if(is_valid){
477+
input.removeClass("is-invalid").addClass("is-valid");
478+
submitOkLogClockTime = true;
479+
} else {
480+
input.removeClass("is-valid").addClass("is-invalid");
481+
submitOkLogClockTime = false;
482+
}
483+
});
484+
485+
390486
//
391487
// Manage QSOs
392488
//
@@ -395,7 +491,7 @@ function editQSO(qkey){
395491
}
396492

397493
function delQSO(qkey, qcall){
398-
if( confirm("Are you sue your want to delete QSO with " + qcall + "?\n(QSO ID# " + qkey + ")") ){
494+
if( confirm("Are you sure your want to delete QSO with " + qcall + "?\n(QSO ID# " + qkey + ")") ){
399495
$.ajax({
400496
type: "GET",
401497
url: "api/delqso.php?qkey=" + qkey,
@@ -572,4 +668,4 @@ function testCookieExists(){
572668
stationcookieexists = false;
573669
}
574670
}
575-
}
671+
}

0 commit comments

Comments
 (0)