mirror of
				https://github.com/craigerl/aprsd.git
				synced 2025-10-26 02:20:21 -04:00 
			
		
		
		
	Merge pull request #130 from craigerl/webchat-saved-bootstrapjs
Webchat saved bootstrapjs
This commit is contained in:
		
						commit
						9985c8bf25
					
				| @ -15,7 +15,6 @@ from flask.logging import default_handler | |||||||
| from flask_httpauth import HTTPBasicAuth | from flask_httpauth import HTTPBasicAuth | ||||||
| from flask_socketio import Namespace, SocketIO | from flask_socketio import Namespace, SocketIO | ||||||
| from oslo_config import cfg | from oslo_config import cfg | ||||||
| from user_agents import parse as ua_parse |  | ||||||
| from werkzeug.security import check_password_hash, generate_password_hash | from werkzeug.security import check_password_hash, generate_password_hash | ||||||
| import wrapt | import wrapt | ||||||
| 
 | 
 | ||||||
| @ -217,20 +216,10 @@ def _get_transport(stats): | |||||||
| @auth.login_required | @auth.login_required | ||||||
| @flask_app.route("/") | @flask_app.route("/") | ||||||
| def index(): | def index(): | ||||||
|     ua_str = request.headers.get("User-Agent") |  | ||||||
|     # this takes about 2 seconds :( |  | ||||||
|     user_agent = ua_parse(ua_str) |  | ||||||
|     LOG.debug(f"Is mobile? {user_agent.is_mobile}") |  | ||||||
|     stats = _stats() |     stats = _stats() | ||||||
| 
 | 
 | ||||||
|     if user_agent.is_mobile: |  | ||||||
|         html_template = "mobile.html" |  | ||||||
|     else: |  | ||||||
|         html_template = "index.html" |  | ||||||
| 
 |  | ||||||
|     # For development |     # For development | ||||||
|     # html_template = "mobile.html" |     html_template = "index.html" | ||||||
| 
 |  | ||||||
|     LOG.debug(f"Template {html_template}") |     LOG.debug(f"Template {html_template}") | ||||||
| 
 | 
 | ||||||
|     transport, aprs_connection = _get_transport(stats) |     transport, aprs_connection = _get_transport(stats) | ||||||
|  | |||||||
| @ -246,7 +246,6 @@ class APRSDStats: | |||||||
|             }, |             }, | ||||||
|             "plugins": plugin_stats, |             "plugins": plugin_stats, | ||||||
|         } |         } | ||||||
|         LOG.info("APRSD Stats: DONE") |  | ||||||
|         return stats |         return stats | ||||||
| 
 | 
 | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|  | |||||||
							
								
								
									
										97
									
								
								aprsd/web/chat/static/css/chat.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								aprsd/web/chat/static/css/chat.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,97 @@ | |||||||
|  | input[type=search]::-webkit-search-cancel-button { | ||||||
|  |     -webkit-appearance: searchfield-cancel-button; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .speech-wrapper { | ||||||
|  |   padding: 5px 30px; | ||||||
|  |   border: 1px solid #ccc; | ||||||
|  |   height: 450px; | ||||||
|  |   overflow-y: scroll; | ||||||
|  |   overflow-x: none; | ||||||
|  |   background-color: #CCCCCC; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .bubble-row { | ||||||
|  |    display: flex; | ||||||
|  |    width: 100%; | ||||||
|  |    justify-content: flex-start; | ||||||
|  |    &.alt { | ||||||
|  |      justify-content: flex-end; | ||||||
|  |    } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .bubble { | ||||||
|  |     /*width: 350px; */ | ||||||
|  |     height: auto; | ||||||
|  |     display: block; | ||||||
|  |     background: #f5f5f5; | ||||||
|  |     border-radius: 4px; | ||||||
|  |     box-shadow: 2px 8px 5px #555; | ||||||
|  |     position: relative; | ||||||
|  |     margin: 0 0 15px; | ||||||
|  |     &.alt { | ||||||
|  |       margin: 0 0 15px; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .bubble-text { | ||||||
|  |       padding: 5px 5px 0px 8px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .bubble-name { | ||||||
|  |     width: 280px; | ||||||
|  |     font-weight: 600; | ||||||
|  |     font-size: 12px; | ||||||
|  |     margin: 0 0 4px; | ||||||
|  |     color: #3498db; | ||||||
|  |     display: flex; | ||||||
|  |     align-items: center; | ||||||
|  |     .material-symbols-rounded { | ||||||
|  |       margin-left: auto; | ||||||
|  |       font-weight: normal; | ||||||
|  |       color: #808080; | ||||||
|  |     } | ||||||
|  |     &.alt { | ||||||
|  |       color: #2ecc71; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .bubble-timestamp { | ||||||
|  |   margin-right: auto; | ||||||
|  |   font-size: 11px; | ||||||
|  |   text-transform: uppercase; | ||||||
|  |   color: #bbb | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .bubble-message { | ||||||
|  |     font-size: 16px; | ||||||
|  |     margin: 0px; | ||||||
|  |     padding: 0px 5px 5px 0px; | ||||||
|  |     color: #2b2b2b; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .bubble-arrow { | ||||||
|  |   position: absolute; | ||||||
|  |   width: 0; | ||||||
|  |   bottom:30px; | ||||||
|  |   left: -16px; | ||||||
|  |   height: 0px; | ||||||
|  |   &.alt{ | ||||||
|  |     right: -2px; | ||||||
|  |     bottom: 30px; | ||||||
|  |     left: auto; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | .bubble-arrow:after { | ||||||
|  |   content: ""; | ||||||
|  |   position: absolute; | ||||||
|  |   border: 0 solid transparent; | ||||||
|  |   border-top: 9px solid #f5f5f5; | ||||||
|  |   border-radius: 0 20px 0; | ||||||
|  |   width: 15px; | ||||||
|  |   height: 30px; | ||||||
|  |   transform: rotate(145deg); | ||||||
|  | } | ||||||
|  | .bubble-arrow.alt:after { | ||||||
|  |   transform: rotate(45deg) scaleY(-1); | ||||||
|  | } | ||||||
| @ -1,6 +1,6 @@ | |||||||
| body { | body { | ||||||
|     background: #eeeeee; |     background: #eeeeee; | ||||||
|     margin: 2em; |     margin: 1em; | ||||||
|     text-align: center; |     text-align: center; | ||||||
|     font-family: system-ui, sans-serif; |     font-family: system-ui, sans-serif; | ||||||
| } | } | ||||||
| @ -11,34 +11,13 @@ footer { | |||||||
|     height: 10vh; |     height: 10vh; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .ui.segment { |  | ||||||
|     background: #eeeeee; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| ul.list { |  | ||||||
|   list-style-type: disc; |  | ||||||
| } |  | ||||||
| ul.list li { |  | ||||||
|   list-style-position: outside; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #left { |  | ||||||
|     margin-right: 2px; |  | ||||||
|     height: 300px; |  | ||||||
| } |  | ||||||
| #right { |  | ||||||
|     height: 300px; |  | ||||||
| } |  | ||||||
| #center { |  | ||||||
|     height: 300px; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #title { | #title { | ||||||
|     font-size: 4em; |     font-size: 4em; | ||||||
| } | } | ||||||
| #version{ | #version{ | ||||||
|     font-size: .5em; |     font-size: .5em; | ||||||
| } | } | ||||||
|  | 
 | ||||||
| #uptime, #aprsis { | #uptime, #aprsis { | ||||||
|     font-size: 1em; |     font-size: 1em; | ||||||
| } | } | ||||||
| @ -66,29 +45,3 @@ ul.list li { | |||||||
|     width: 16px; |     width: 16px; | ||||||
|     height: 16px; |     height: 16px; | ||||||
| } | } | ||||||
| 
 |  | ||||||
| #msgsTabsDiv .ui.tab { |  | ||||||
|    margin:0px; |  | ||||||
|    padding:0px; |  | ||||||
|    display: block; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #msgsTabsDiv .header, .tiny.text, .content, .break, |  | ||||||
|   .thumbs.down.outline.icon, |  | ||||||
|   .phone.volume.icon |  | ||||||
|  { |  | ||||||
|     display: inline-block; |  | ||||||
|     float: left; |  | ||||||
|     position: relative; |  | ||||||
| } |  | ||||||
| #msgsTabsDiv .tiny.text { |  | ||||||
|   width:100px; |  | ||||||
| } |  | ||||||
| #msgsTabsDiv .tiny.header { |  | ||||||
|   width:100px; |  | ||||||
|   text-align: left; |  | ||||||
| } |  | ||||||
| #msgsTabsDiv .break { |  | ||||||
|   margin: 2px; |  | ||||||
|   text-align: left; |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -37,5 +37,5 @@ | |||||||
|   border: 1px solid #ccc; |   border: 1px solid #ccc; | ||||||
|   height: 450px; |   height: 450px; | ||||||
|   overflow-y: scroll; |   overflow-y: scroll; | ||||||
|   background-color: white; |   background-color: #CCCCCC; | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,246 +0,0 @@ | |||||||
| var cleared = false; |  | ||||||
| var callsign_list = {}; |  | ||||||
| var message_list = {}; |  | ||||||
| var from_msg_list = {}; |  | ||||||
| const socket = io("/sendmsg"); |  | ||||||
| 
 |  | ||||||
| function size_dict(d){c=0; for (i in d) ++c; return c} |  | ||||||
| 
 |  | ||||||
| function init_chat() { |  | ||||||
|    socket.on('connect', function () { |  | ||||||
|        console.log("Connected to socketio"); |  | ||||||
|    }); |  | ||||||
|    socket.on('connected', function(msg) { |  | ||||||
|        console.log("Connected!"); |  | ||||||
|        console.log(msg); |  | ||||||
|    }); |  | ||||||
| 
 |  | ||||||
|    socket.on("sent", function(msg) { |  | ||||||
|        if (cleared == false) { |  | ||||||
|            var msgsdiv = $("#msgsTabsDiv"); |  | ||||||
|            msgsdiv.html('') |  | ||||||
|            cleared = true |  | ||||||
|        } |  | ||||||
|        sent_msg(msg); |  | ||||||
|    }); |  | ||||||
| 
 |  | ||||||
|    socket.on("ack", function(msg) { |  | ||||||
|        update_msg(msg); |  | ||||||
|    }); |  | ||||||
| 
 |  | ||||||
|    socket.on("new", function(msg) { |  | ||||||
|        if (cleared == false) { |  | ||||||
|            var msgsdiv = $("#msgsTabsDiv"); |  | ||||||
|            msgsdiv.html('') |  | ||||||
|            cleared = true |  | ||||||
|        } |  | ||||||
|        from_msg(msg); |  | ||||||
|    }); |  | ||||||
| 
 |  | ||||||
|    $("#sendform").submit(function(event) { |  | ||||||
|        event.preventDefault(); |  | ||||||
|        msg = {'to': $('#to_call').val().toUpperCase(), |  | ||||||
|               'message': $('#message').val(), |  | ||||||
|               } |  | ||||||
|        socket.emit("send", msg); |  | ||||||
|        $('#message').val(''); |  | ||||||
|    }); |  | ||||||
| 
 |  | ||||||
|    init_gps(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| function add_callsign(callsign) { |  | ||||||
|    /* Ensure a callsign exists in the left hand nav */ |  | ||||||
|    dropdown = $('#callsign_dropdown') |  | ||||||
| 
 |  | ||||||
|   if (callsign in callsign_list) { |  | ||||||
|       console.log(callsign+' already in list.') |  | ||||||
|       return false |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   var callsignTabs = $("#callsignTabs"); |  | ||||||
|   tab_name = tab_string(callsign); |  | ||||||
|   tab_content = tab_content_name(callsign); |  | ||||||
|   divname = content_divname(callsign); |  | ||||||
| 
 |  | ||||||
|   item_html = '<div class="active item" id="'+tab_name+'" onclick="openCallsign(event, \''+callsign+'\');">'+callsign+'</div>'; |  | ||||||
|   callsignTabs.append(item_html); |  | ||||||
| 
 |  | ||||||
|   callsign_list[callsign] = {'name': callsign, 'value': callsign, 'text': callsign} |  | ||||||
|   return true |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function append_message(callsign, msg, msg_html) { |  | ||||||
|   console.log('append_message'); |  | ||||||
|   new_callsign = false |  | ||||||
|   if (!message_list.hasOwnProperty(callsign)) { |  | ||||||
|        message_list[callsign] = new Array(); |  | ||||||
|   } |  | ||||||
|   message_list[callsign].push(msg); |  | ||||||
| 
 |  | ||||||
|   // Find the right div to place the html
 |  | ||||||
|   new_callsign = add_callsign(callsign); |  | ||||||
|   append_message_html(callsign, msg_html, new_callsign); |  | ||||||
|   if (new_callsign) { |  | ||||||
|       //click on the new tab
 |  | ||||||
|       click_div = '#'+tab_string(callsign); |  | ||||||
|       console.log("Click on "+click_div); |  | ||||||
|       $(click_div).click(); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function tab_string(callsign) { |  | ||||||
|   return "msgs"+callsign; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function tab_content_name(callsign) { |  | ||||||
|    return tab_string(callsign)+"Content"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function content_divname(callsign) { |  | ||||||
|     return "#"+tab_content_name(callsign); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function append_message_html(callsign, msg_html, new_callsign) { |  | ||||||
|   var msgsTabs = $('#msgsTabsDiv'); |  | ||||||
|   divname_str = tab_content_name(callsign); |  | ||||||
|   divname = content_divname(callsign); |  | ||||||
|   if (new_callsign) { |  | ||||||
|       // we have to add a new DIV
 |  | ||||||
|       msg_div_html = '<div class="tabcontent" id="'+divname_str+'" style="height:450px;">'+msg_html+'</div>'; |  | ||||||
|       msgsTabs.append(msg_div_html); |  | ||||||
|   } else { |  | ||||||
|       var msgDiv = $(divname); |  | ||||||
|       msgDiv.append(msg_html); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   $(divname).animate({scrollTop: $(divname)[0].scrollHeight}, "slow"); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function create_message_html(time, from, to, message, ack, msg) { |  | ||||||
|     div_id = from + "_" + msg.id; |  | ||||||
|     msg_html = '<div class="item" id="'+div_id+'">'; |  | ||||||
|     msg_html += '<div class="tiny text">'+time+'</div>'; |  | ||||||
|     msg_html += '<div class="middle aligned content">'; |  | ||||||
|     msg_html += '<div class="tiny red header">'+from+'</div>'; |  | ||||||
|     if (ack) { |  | ||||||
|         msg_html += '<i class="thumbs down outline icon" id="' + ack_id + '" data-content="Waiting for ACK"></i>'; |  | ||||||
|     } else { |  | ||||||
|         msg_html += '<i class="phone volume icon" data-content="Recieved Message"></i>'; |  | ||||||
|     } |  | ||||||
|     msg_html += '<div class="middle aligned content">>   </div>'; |  | ||||||
|     msg_html += '</div>'; |  | ||||||
|     msg_html += '<div class="middle aligned content">'+message+'</div>'; |  | ||||||
|     msg_html += '</div><br>'; |  | ||||||
| 
 |  | ||||||
|     return msg_html |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function flash_message(msg) { |  | ||||||
|     // Callback function to bring a hidden box back
 |  | ||||||
|     id = msg.from + "_" + msg.id; |  | ||||||
|     var msgid = $('#'+id); |  | ||||||
|     msgid.effect("pulsate", { times:3 }, 2000); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function sent_msg(msg) { |  | ||||||
|     var msgsdiv = $("#sendMsgsDiv"); |  | ||||||
| 
 |  | ||||||
|     ts_str = msg["ts"].toString(); |  | ||||||
|     ts = ts_str.split(".")[0]*1000; |  | ||||||
|     id = ts_str.split('.')[0] |  | ||||||
|     ack_id = "ack_" + id |  | ||||||
| 
 |  | ||||||
|     var d = new Date(ts).toLocaleDateString("en-US") |  | ||||||
|     var t = new Date(ts).toLocaleTimeString("en-US") |  | ||||||
| 
 |  | ||||||
|     msg_html = create_message_html(t, msg['from'], msg['to'], msg['message'], ack_id, msg); |  | ||||||
|     append_message(msg['to'], msg, msg_html); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function from_msg(msg) { |  | ||||||
|    var msgsdiv = $("#sendMsgsDiv"); |  | ||||||
|    console.log(msg); |  | ||||||
|    if (!from_msg_list.hasOwnProperty(msg.from)) { |  | ||||||
|         from_msg_list[msg.from] = new Array(); |  | ||||||
|    } |  | ||||||
| 
 |  | ||||||
|    if (msg.id in from_msg_list[msg.from]) { |  | ||||||
|        // We already have this message
 |  | ||||||
|        console.log("We already have this message " + msg); |  | ||||||
|        // Do some flashy thing?
 |  | ||||||
|        flash_message(msg); |  | ||||||
|        return false |  | ||||||
|    } else { |  | ||||||
|        console.log("Adding message " + msg.id + " to " + msg.from); |  | ||||||
|        from_msg_list[msg.from][msg.id] = msg |  | ||||||
|    } |  | ||||||
| 
 |  | ||||||
|    // We have an existing entry
 |  | ||||||
|    ts_str = msg["ts"].toString(); |  | ||||||
|    ts = ts_str.split(".")[0]*1000; |  | ||||||
|    id = ts_str.split('.')[0] |  | ||||||
|    ack_id = "ack_" + id |  | ||||||
| 
 |  | ||||||
|    var d = new Date(ts).toLocaleDateString("en-US") |  | ||||||
|    var t = new Date(ts).toLocaleTimeString("en-US") |  | ||||||
| 
 |  | ||||||
|    from = msg['from'] |  | ||||||
|    msg_html = create_message_html(t, from, false, msg['message'], false, msg); |  | ||||||
|    append_message(from, msg, msg_html); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function update_msg(msg) { |  | ||||||
|    var msgsdiv = $("#sendMsgsDiv"); |  | ||||||
|     // We have an existing entry
 |  | ||||||
|     ts_str = msg["ts"].toString(); |  | ||||||
|     id = ts_str.split('.')[0] |  | ||||||
|     pretty_id = "pretty_" + id |  | ||||||
|     loader_id = "loader_" + id |  | ||||||
|     ack_id = "ack_" + id |  | ||||||
|     span_id = "span_" + id |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     if (msg['ack'] == true) { |  | ||||||
|         var loader_div = $('#' + loader_id); |  | ||||||
|         var ack_div = $('#' + ack_id); |  | ||||||
|         loader_div.removeClass('ui active inline loader'); |  | ||||||
|         loader_div.addClass('ui disabled loader'); |  | ||||||
|         ack_div.removeClass('thumbs up outline icon'); |  | ||||||
|         ack_div.addClass('thumbs up outline icon'); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $('.ui.accordion').accordion('refresh'); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function callsign_select(callsign) { |  | ||||||
|    var tocall = $("#to_call"); |  | ||||||
|    tocall.val(callsign); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function reset_Tabs() { |  | ||||||
|   tabcontent = document.getElementsByClassName("tabcontent"); |  | ||||||
|   for (i = 0; i < tabcontent.length; i++) { |  | ||||||
|     tabcontent[i].style.display = "none"; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function openCallsign(evt, callsign) { |  | ||||||
|   var i, tabcontent, tablinks; |  | ||||||
| 
 |  | ||||||
|   tab_content = tab_content_name(callsign); |  | ||||||
| 
 |  | ||||||
|   tabcontent = document.getElementsByClassName("tabcontent"); |  | ||||||
|   for (i = 0; i < tabcontent.length; i++) { |  | ||||||
|     tabcontent[i].style.display = "none"; |  | ||||||
|   } |  | ||||||
|   tablinks = document.getElementsByClassName("tablinks"); |  | ||||||
|   for (i = 0; i < tablinks.length; i++) { |  | ||||||
|     tablinks[i].className = tablinks[i].className.replace(" active", ""); |  | ||||||
|   } |  | ||||||
|   document.getElementById(tab_content).style.display = "block"; |  | ||||||
|   evt.target.className += " active"; |  | ||||||
|   callsign_select(callsign); |  | ||||||
| } |  | ||||||
| @ -4,6 +4,10 @@ var message_list = {}; | |||||||
| var from_msg_list = {}; | var from_msg_list = {}; | ||||||
| const socket = io("/sendmsg"); | const socket = io("/sendmsg"); | ||||||
| 
 | 
 | ||||||
|  | MSG_TYPE_TX = "tx"; | ||||||
|  | MSG_TYPE_RX = "rx"; | ||||||
|  | MSG_TYPE_ACK = "ack"; | ||||||
|  | 
 | ||||||
| function size_dict(d){c=0; for (i in d) ++c; return c} | function size_dict(d){c=0; for (i in d) ++c; return c} | ||||||
| 
 | 
 | ||||||
| function init_chat() { | function init_chat() { | ||||||
| @ -16,24 +20,28 @@ function init_chat() { | |||||||
|    }); |    }); | ||||||
| 
 | 
 | ||||||
|    socket.on("sent", function(msg) { |    socket.on("sent", function(msg) { | ||||||
|        if (cleared == false) { |        if (cleared === false) { | ||||||
|  |            console.log("CLEARING #msgsTabsDiv"); | ||||||
|            var msgsdiv = $("#msgsTabsDiv"); |            var msgsdiv = $("#msgsTabsDiv"); | ||||||
|            msgsdiv.html('') |            msgsdiv.html(''); | ||||||
|            cleared = true |            cleared = true; | ||||||
|        } |        } | ||||||
|  |        msg["type"] = MSG_TYPE_TX; | ||||||
|        sent_msg(msg); |        sent_msg(msg); | ||||||
|    }); |    }); | ||||||
| 
 | 
 | ||||||
|    socket.on("ack", function(msg) { |    socket.on("ack", function(msg) { | ||||||
|        update_msg(msg); |        msg["type"] = MSG_TYPE_ACK; | ||||||
|  |        ack_msg(msg); | ||||||
|    }); |    }); | ||||||
| 
 | 
 | ||||||
|    socket.on("new", function(msg) { |    socket.on("new", function(msg) { | ||||||
|        if (cleared == false) { |        if (cleared === false) { | ||||||
|            var msgsdiv = $("#msgsTabsDiv"); |            var msgsdiv = $("#msgsTabsDiv"); | ||||||
|            msgsdiv.html('') |            msgsdiv.html('') | ||||||
|            cleared = true |            cleared = true; | ||||||
|        } |        } | ||||||
|  |        msg["type"] = MSG_TYPE_RX; | ||||||
|        from_msg(msg); |        from_msg(msg); | ||||||
|    }); |    }); | ||||||
| 
 | 
 | ||||||
| @ -47,22 +55,175 @@ function init_chat() { | |||||||
|    }); |    }); | ||||||
| 
 | 
 | ||||||
|    init_gps(); |    init_gps(); | ||||||
|  |    // Try and load any existing chat threads from last time
 | ||||||
|  |    init_messages(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function tab_string(callsign, id=false) { | ||||||
|  |     name = "msgs"+callsign; | ||||||
|  |     if (id) { | ||||||
|  |         return "#"+name; | ||||||
|  |     } else { | ||||||
|  |         return name; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function tab_content_name(callsign, id=false) { | ||||||
|  |    return tab_string(callsign, id)+"Content"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function tab_content_speech_wrapper(callsign, id=false) { | ||||||
|  |     return tab_string(callsign, id)+"SpeechWrapper"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function tab_content_speech_wrapper_id(callsign) { | ||||||
|  |     return "#"+tab_content_speech_wrapper(callsign); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function content_divname(callsign) { | ||||||
|  |     return "#"+tab_content_name(callsign); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function callsign_tab(callsign) { | ||||||
|  |     return "#"+tab_string(callsign); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function message_ts_id(msg) { | ||||||
|  |     //Create a 'id' from the message timestamp
 | ||||||
|  |     ts_str = msg["ts"].toString(); | ||||||
|  |     ts = ts_str.split(".")[0]*1000; | ||||||
|  |     id = ts_str.split('.')[0]; | ||||||
|  |     return {'timestamp': ts, 'id': id}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function time_ack_from_msg(msg)  { | ||||||
|  |     // Return the time and ack_id from a message
 | ||||||
|  |     ts_id = message_ts_id(msg); | ||||||
|  |     ts = ts_id['timestamp']; | ||||||
|  |     id = ts_id['id']; | ||||||
|  |     ack_id = "ack_" + id | ||||||
|  | 
 | ||||||
|  |     var d = new Date(ts).toLocaleDateString("en-US") | ||||||
|  |     var t = new Date(ts).toLocaleTimeString("en-US") | ||||||
|  |     return {'time': t, 'date': d, 'ack_id': ack_id}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function save_data() { | ||||||
|  |   // Save the relevant data to local storage
 | ||||||
|  |   localStorage.setItem('callsign_list', JSON.stringify(callsign_list)); | ||||||
|  |   localStorage.setItem('message_list', JSON.stringify(message_list)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function init_messages() { | ||||||
|  |     // This tries to load any previous conversations from local storage
 | ||||||
|  |     callsign_list = JSON.parse(localStorage.getItem('callsign_list')); | ||||||
|  |     message_list = JSON.parse(localStorage.getItem('message_list')); | ||||||
|  |     if (callsign_list == null) { | ||||||
|  |        callsign_list = {}; | ||||||
|  |     } | ||||||
|  |     if (message_list == null) { | ||||||
|  |        message_list = {}; | ||||||
|  |     } | ||||||
|  |     console.log(callsign_list); | ||||||
|  |     console.log(message_list); | ||||||
|  | 
 | ||||||
|  |     // Now loop through each callsign and add the tabs
 | ||||||
|  |     first_callsign = null; | ||||||
|  |     for (callsign in callsign_list) { | ||||||
|  |         if (first_callsign === null) { | ||||||
|  |             first_callsign = callsign; | ||||||
|  |             active = true; | ||||||
|  |         } else { | ||||||
|  |             active = false; | ||||||
|  |         } | ||||||
|  |         create_callsign_tab(callsign, active); | ||||||
|  |     } | ||||||
|  |     // and then populate the messages in order
 | ||||||
|  |     for (callsign in message_list) { | ||||||
|  |         new_callsign = true; | ||||||
|  |         cleared = true; | ||||||
|  |         for (id in message_list[callsign]) { | ||||||
|  |             msg = message_list[callsign][id]; | ||||||
|  |             info = time_ack_from_msg(msg); | ||||||
|  |             t = info['time']; | ||||||
|  |             d = info['date']; | ||||||
|  |             ack_id = false; | ||||||
|  |             acked = false; | ||||||
|  |             if (msg['type'] == MSG_TYPE_TX) { | ||||||
|  |                 ack_id = info['ack_id']; | ||||||
|  |                 acked = msg['ack']; | ||||||
|  |             } | ||||||
|  |             msg_html = create_message_html(d, t, msg['from'], msg['to'], msg['message'], ack_id, msg, acked); | ||||||
|  |             append_message_html(callsign, msg_html, new_callsign); | ||||||
|  |             new_callsign = false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function create_callsign_tab(callsign, active=false) { | ||||||
|  |   //Create the html for the callsign tab and insert it into the DOM
 | ||||||
|  |   var callsignTabs = $("#msgsTabList"); | ||||||
|  |   tab_id = tab_string(callsign); | ||||||
|  |   tab_content = tab_content_name(callsign); | ||||||
|  |   if (active) { | ||||||
|  |     active_str = "active"; | ||||||
|  |   } else { | ||||||
|  |     active_str = ""; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   item_html = '<li class="nav-item" role="presentation">'; | ||||||
|  |   item_html += '<button onClick="$(\'#to_call\').val(\''+callsign+'\');" callsign="'+callsign+'" class="nav-link '+active_str+'" id="'+tab_id+'" data-bs-toggle="tab" data-bs-target="#'+tab_content+'" type="button" role="tab" aria-controls="'+callsign+'" aria-selected="true">'; | ||||||
|  |   item_html += callsign+'  '; | ||||||
|  |   item_html += '<span onclick="delete_tab(\''+callsign+'\');">×</span>'; | ||||||
|  |   item_html += '</button></li>' | ||||||
|  |   callsignTabs.append(item_html); | ||||||
|  |   create_callsign_tab_content(callsign, active); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function create_callsign_tab_content(callsign, active=false) { | ||||||
|  |   var callsignTabsContent = $("#msgsTabContent"); | ||||||
|  |   tab_id = tab_string(callsign); | ||||||
|  |   tab_content = tab_content_name(callsign); | ||||||
|  |   wrapper_id = tab_content_speech_wrapper(callsign); | ||||||
|  |   if (active) { | ||||||
|  |     active_str = "show active"; | ||||||
|  |   } else { | ||||||
|  |     active_str = ''; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   item_html = '<div class="tab-pane fade '+active_str+'" id="'+tab_content+'" role="tabpanel" aria-labelledby="'+tab_id+'">'; | ||||||
|  |   item_html += '<div class="speech-wrapper" id="'+wrapper_id+'"></div>'; | ||||||
|  |   item_html += '</div>'; | ||||||
|  |   callsignTabsContent.append(item_html); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function delete_tab(callsign) { | ||||||
|  |     // User asked to delete the tab and the conversation
 | ||||||
|  |     tab_id = tab_string(callsign, true); | ||||||
|  |     tab_content = tab_content_name(callsign, true); | ||||||
|  |     $(tab_id).remove(); | ||||||
|  |     $(tab_content).remove(); | ||||||
|  |     delete callsign_list[callsign]; | ||||||
|  |     delete message_list[callsign]; | ||||||
|  | 
 | ||||||
|  |     // Now select the first tab
 | ||||||
|  |     first_tab = $("#msgsTabList").children().first().children().first(); | ||||||
|  |     $(first_tab).click(); | ||||||
|  |     save_data(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function add_callsign(callsign) { | function add_callsign(callsign) { | ||||||
|    /* Ensure a callsign exists in the left hand nav */ |    /* Ensure a callsign exists in the left hand nav */ | ||||||
| 
 |  | ||||||
|   if (callsign in callsign_list) { |   if (callsign in callsign_list) { | ||||||
|       return false |       return false | ||||||
|   } |   } | ||||||
| 
 |   len = Object.keys(callsign_list).length; | ||||||
|   var callsignTabs = $("#callsignTabs"); |   if (len == 0) { | ||||||
|   tab_name = tab_string(callsign); |       active = true; | ||||||
|   tab_content = tab_content_name(callsign); |   } else { | ||||||
|   divname = content_divname(callsign); |       active = false; | ||||||
| 
 |   } | ||||||
|   item_html = '<div class="tablinks" id="'+tab_name+'" onclick="openCallsign(event, \''+callsign+'\');">'+callsign+'</div>'; |   create_callsign_tab(callsign, active); | ||||||
|   callsignTabs.append(item_html); |  | ||||||
|   callsign_list[callsign] = true; |   callsign_list[callsign] = true; | ||||||
|   return true |   return true | ||||||
| } | } | ||||||
| @ -70,64 +231,74 @@ function add_callsign(callsign) { | |||||||
| function append_message(callsign, msg, msg_html) { | function append_message(callsign, msg, msg_html) { | ||||||
|   new_callsign = false |   new_callsign = false | ||||||
|   if (!message_list.hasOwnProperty(callsign)) { |   if (!message_list.hasOwnProperty(callsign)) { | ||||||
|        message_list[callsign] = new Array(); |        //message_list[callsign] = new Array();
 | ||||||
|  |        message_list[callsign] = {}; | ||||||
|   } |   } | ||||||
|   message_list[callsign].push(msg); |   ts_id = message_ts_id(msg); | ||||||
|  |   id = ts_id['id'] | ||||||
|  |   message_list[callsign][id] = msg; | ||||||
| 
 | 
 | ||||||
|   // Find the right div to place the html
 |   // Find the right div to place the html
 | ||||||
|   new_callsign = add_callsign(callsign); |   new_callsign = add_callsign(callsign); | ||||||
|   append_message_html(callsign, msg_html, new_callsign); |   append_message_html(callsign, msg_html, new_callsign); | ||||||
|   if (new_callsign) { |   if (new_callsign) { | ||||||
|       //click on the new tab
 |       //Now click the tab
 | ||||||
|       click_div = '#'+tab_string(callsign); |       callsign_tab_id = callsign_tab(callsign); | ||||||
|       $(click_div).click(); |       $(callsign_tab_id).click(); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function tab_string(callsign) { |  | ||||||
|   return "msgs"+callsign; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function tab_content_name(callsign) { |  | ||||||
|    return tab_string(callsign)+"Content"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function content_divname(callsign) { |  | ||||||
|     return "#"+tab_content_name(callsign); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| function append_message_html(callsign, msg_html, new_callsign) { | function append_message_html(callsign, msg_html, new_callsign) { | ||||||
|   var msgsTabs = $('#msgsTabsDiv'); |   var msgsTabs = $('#msgsTabsDiv'); | ||||||
|   divname_str = tab_content_name(callsign); |   divname_str = tab_content_name(callsign); | ||||||
|   divname = content_divname(callsign); |   divname = content_divname(callsign); | ||||||
|   if (new_callsign) { |   tab_content = tab_content_name(callsign); | ||||||
|       // we have to add a new DIV
 |   wrapper_id = tab_content_speech_wrapper_id(callsign); | ||||||
|       msg_div_html = '<div class="tabcontent" id="'+divname_str+'" style="height:450px;">'+msg_html+'</div>'; | 
 | ||||||
|       msgsTabs.append(msg_div_html); |   $(wrapper_id).append(msg_html); | ||||||
|   } else { | 
 | ||||||
|       var msgDiv = $(divname); |   if ($(wrapper_id).children().length > 0) { | ||||||
|       msgDiv.append(msg_html); |       $(wrapper_id).animate({scrollTop: $(wrapper_id)[0].scrollHeight}, "fast"); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   $(divname).animate({scrollTop: $(divname)[0].scrollHeight}, "slow"); |  | ||||||
|   $(divname).trigger('click'); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function create_message_html(time, from, to, message, ack, msg) { | function create_message_html(date, time, from, to, message, ack_id, msg, acked=false) { | ||||||
|     div_id = from + "_" + msg.id; |     div_id = from + "_" + msg.id; | ||||||
|     msg_html = '<div class="item" id="'+div_id+'">'; |     if (ack_id) { | ||||||
|     msg_html += '<div class="tiny text">'+time+'</div>'; |       alt = " alt" | ||||||
|     msg_html += '<div class="middle aligned content">'; |  | ||||||
|     msg_html += '<div class="tiny red header">'+from+'</div>'; |  | ||||||
|     if (ack) { |  | ||||||
|         msg_html += '<i class="thumbs down outline icon" id="' + ack_id + '" data-content="Waiting for ACK"></i>'; |  | ||||||
|     } else { |     } else { | ||||||
|         msg_html += '<i class="phone volume icon" data-content="Recieved Message"></i>'; |       alt = "" | ||||||
|     } |     } | ||||||
|     msg_html += '<div class="middle aligned content">>   </div>'; | 
 | ||||||
|     msg_html += '</div>'; |     bubble_class = "bubble" + alt | ||||||
|     msg_html += '<div class="middle aligned content">'+message+'</div>'; |     bubble_name_class = "bubble-name" + alt | ||||||
|     msg_html += '</div><br>'; |     date_str = date + " " + time; | ||||||
|  | 
 | ||||||
|  |     msg_html = '<div class="bubble-row'+alt+'">'; | ||||||
|  |     msg_html += '<div class="'+ bubble_class + '">'; | ||||||
|  |     msg_html += '<div class="bubble-text">'; | ||||||
|  |     msg_html += '<p class="'+ bubble_name_class +'">'+from+'  '; | ||||||
|  |     msg_html += '<span class="bubble-timestamp">'+date_str+'</span>'; | ||||||
|  |     if (ack_id) { | ||||||
|  |         if (acked) { | ||||||
|  |             msg_html += '<span class="material-symbols-rounded" id="' + ack_id + '">thumb_up</span>'; | ||||||
|  |         } else { | ||||||
|  |             msg_html += '<span class="material-symbols-rounded" id="' + ack_id + '">thumb_down</span>'; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     msg_html += "</p>"; | ||||||
|  |     bubble_msg_class = "bubble-message" | ||||||
|  |     if (ack_id) { | ||||||
|  |       bubble_arrow_class = "bubble-arrow alt" | ||||||
|  |     } else { | ||||||
|  |       bubble_arrow_class = "bubble-arrow" | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     msg_html += '<p class="' +bubble_msg_class+ '">'+message+'</p>'; | ||||||
|  |     msg_html += '<div class="'+ bubble_arrow_class + '"></div>'; | ||||||
|  |     msg_html += "</div></div></div>"; | ||||||
| 
 | 
 | ||||||
|     return msg_html |     return msg_html | ||||||
| } | } | ||||||
| @ -139,24 +310,19 @@ function flash_message(msg) { | |||||||
|     msgid.effect("pulsate", { times:3 }, 2000); |     msgid.effect("pulsate", { times:3 }, 2000); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| function sent_msg(msg) { | function sent_msg(msg) { | ||||||
|     var msgsdiv = $("#sendMsgsDiv"); |     info = time_ack_from_msg(msg); | ||||||
|  |     t = info['time']; | ||||||
|  |     d = info['date']; | ||||||
|  |     ack_id = info['ack_id']; | ||||||
| 
 | 
 | ||||||
|     ts_str = msg["ts"].toString(); |     msg_html = create_message_html(d, t, msg['from'], msg['to'], msg['message'], ack_id, msg, false); | ||||||
|     ts = ts_str.split(".")[0]*1000; |  | ||||||
|     id = ts_str.split('.')[0] |  | ||||||
|     ack_id = "ack_" + id |  | ||||||
| 
 |  | ||||||
|     var d = new Date(ts).toLocaleDateString("en-US") |  | ||||||
|     var t = new Date(ts).toLocaleTimeString("en-US") |  | ||||||
| 
 |  | ||||||
|     msg_html = create_message_html(t, msg['from'], msg['to'], msg['message'], ack_id, msg); |  | ||||||
|     append_message(msg['to'], msg, msg_html); |     append_message(msg['to'], msg, msg_html); | ||||||
|  |     save_data(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function from_msg(msg) { | function from_msg(msg) { | ||||||
|    var msgsdiv = $("#sendMsgsDiv"); |  | ||||||
|    console.log(msg); |  | ||||||
|    if (!from_msg_list.hasOwnProperty(msg.from)) { |    if (!from_msg_list.hasOwnProperty(msg.from)) { | ||||||
|         from_msg_list[msg.from] = new Array(); |         from_msg_list[msg.from] = new Array(); | ||||||
|    } |    } | ||||||
| @ -172,70 +338,55 @@ function from_msg(msg) { | |||||||
|        from_msg_list[msg.from][msg.id] = msg |        from_msg_list[msg.from][msg.id] = msg | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    // We have an existing entry
 |    info = time_ack_from_msg(msg); | ||||||
|    ts_str = msg["ts"].toString(); |    t = info['time']; | ||||||
|    ts = ts_str.split(".")[0]*1000; |    d = info['date']; | ||||||
|    id = ts_str.split('.')[0] |    ack_id = info['ack_id']; | ||||||
|    ack_id = "ack_" + id |  | ||||||
| 
 |  | ||||||
|    var d = new Date(ts).toLocaleDateString("en-US") |  | ||||||
|    var t = new Date(ts).toLocaleTimeString("en-US") |  | ||||||
| 
 | 
 | ||||||
|    from = msg['from'] |    from = msg['from'] | ||||||
|    msg_html = create_message_html(t, from, false, msg['message'], false, msg); |    msg_html = create_message_html(d, t, from, false, msg['message'], false, msg, false); | ||||||
|    append_message(from, msg, msg_html); |    append_message(from, msg, msg_html); | ||||||
|  |    save_data(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function update_msg(msg) { | function ack_msg(msg) { | ||||||
|    var msgsdiv = $("#sendMsgsDiv"); |    // Acknowledge a message
 | ||||||
|     // We have an existing entry
 |    console.log("ack_msg "); | ||||||
|     ts_str = msg["ts"].toString(); |  | ||||||
|     id = ts_str.split('.')[0] |  | ||||||
|     pretty_id = "pretty_" + id |  | ||||||
|     loader_id = "loader_" + id |  | ||||||
|     ack_id = "ack_" + id |  | ||||||
|     span_id = "span_" + id |  | ||||||
| 
 | 
 | ||||||
|  |    // We have an existing entry
 | ||||||
|  |    ts_id = message_ts_id(msg); | ||||||
|  |    console.log(ts_id) | ||||||
|  |    id = ts_id['id']; | ||||||
|  |    //Mark the message as acked
 | ||||||
|  |    callsign = msg['to']; | ||||||
|  |    // Ensure the message_list has this callsign
 | ||||||
|  |    if (!message_list.hasOwnProperty(callsign)) { | ||||||
|  |        console.log("No message_list for " + callsign); | ||||||
|  |        return false | ||||||
|  |    } | ||||||
|  |    // Ensure the message_list has this id
 | ||||||
|  |    if (!message_list[callsign].hasOwnProperty(id)) { | ||||||
|  |        console.log("No message_list for " + callsign + " " + id); | ||||||
|  |        return false | ||||||
|  |    } | ||||||
|  |    console.log("Marking message as acked " + callsign + " " + id) | ||||||
|  |    if (message_list[callsign][id]['ack'] == true) { | ||||||
|  |        console.log("Message already acked"); | ||||||
|  |        return false; | ||||||
|  |    } | ||||||
|  |    message_list[callsign][id]['ack'] = true; | ||||||
|  |    ack_id = "ack_" + id | ||||||
| 
 | 
 | ||||||
|  |    if (msg['ack'] == true) { | ||||||
|  |        var ack_div = $('#' + ack_id); | ||||||
|  |        ack_div.html('thumb_up'); | ||||||
|  |    } | ||||||
| 
 | 
 | ||||||
|     if (msg['ack'] == true) { |    $('.ui.accordion').accordion('refresh'); | ||||||
|         var loader_div = $('#' + loader_id); |    save_data(); | ||||||
|         var ack_div = $('#' + ack_id); |  | ||||||
|         loader_div.removeClass('ui active inline loader'); |  | ||||||
|         loader_div.addClass('ui disabled loader'); |  | ||||||
|         ack_div.removeClass('thumbs up outline icon'); |  | ||||||
|         ack_div.addClass('thumbs up outline icon'); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $('.ui.accordion').accordion('refresh'); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function callsign_select(callsign) { | function callsign_select(callsign) { | ||||||
|    var tocall = $("#to_call"); |    var tocall = $("#to_call"); | ||||||
|    tocall.val(callsign); |    tocall.val(callsign); | ||||||
| } | } | ||||||
| 
 |  | ||||||
| function reset_Tabs() { |  | ||||||
|   tabcontent = document.getElementsByClassName("tabcontent"); |  | ||||||
|   for (i = 0; i < tabcontent.length; i++) { |  | ||||||
|     tabcontent[i].style.display = "none"; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function openCallsign(evt, callsign) { |  | ||||||
|   var i, tabcontent, tablinks; |  | ||||||
| 
 |  | ||||||
|   tab_content = tab_content_name(callsign); |  | ||||||
| 
 |  | ||||||
|   tabcontent = document.getElementsByClassName("tabcontent"); |  | ||||||
|   for (i = 0; i < tabcontent.length; i++) { |  | ||||||
|     tabcontent[i].style.display = "none"; |  | ||||||
|   } |  | ||||||
|   tablinks = document.getElementsByClassName("tablinks"); |  | ||||||
|   for (i = 0; i < tablinks.length; i++) { |  | ||||||
|     tablinks[i].className = tablinks[i].className.replace(" active", ""); |  | ||||||
|   } |  | ||||||
|   document.getElementById(tab_content).style.display = "block"; |  | ||||||
|   evt.target.className += " active"; |  | ||||||
|   callsign_select(callsign); |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -10,11 +10,12 @@ | |||||||
|         <!-- <script src="https://cdn.socket.io/4.1.2/socket.io.min.js" integrity="sha384-toS6mmwu70G0fw54EGlWWeA4z3dyJ+dlXBtSURSKN4vyRFOcxd3Bzjj/AoOwY+Rg" crossorigin="anonymous"></script> --> |         <!-- <script src="https://cdn.socket.io/4.1.2/socket.io.min.js" integrity="sha384-toS6mmwu70G0fw54EGlWWeA4z3dyJ+dlXBtSURSKN4vyRFOcxd3Bzjj/AoOwY+Rg" crossorigin="anonymous"></script> --> | ||||||
|         <script src="/static/js/upstream/socket.io.min.js"></script> |         <script src="/static/js/upstream/socket.io.min.js"></script> | ||||||
| 
 | 
 | ||||||
|         <!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.9.0/semantic.min.css"> --> |         <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous"> | ||||||
|         <link rel="stylesheet" href="/static/css/upstream/semantic.min.css"> |         <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-HwwvtgBNo3bZJJLYd8oVXjrBZt8cqVSpeBNS5n7C8IVInixGAoxmnlMuBnhbgrkm" crossorigin="anonymous"></script> | ||||||
|         <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.9.0/semantic.min.js"></script> --> |  | ||||||
|         <script src="/static/js/upstream/semantic.min.js"></script> |  | ||||||
| 
 | 
 | ||||||
|  |         <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,200,1,200"> | ||||||
|  | 
 | ||||||
|  |         <link rel="stylesheet" href="/static/css/chat.css"> | ||||||
|         <link rel="stylesheet" href="/static/css/index.css"> |         <link rel="stylesheet" href="/static/css/index.css"> | ||||||
|         <link rel="stylesheet" href="/static/css/tabs.css"> |         <link rel="stylesheet" href="/static/css/tabs.css"> | ||||||
|         <script src="/static/js/main.js"></script> |         <script src="/static/js/main.js"></script> | ||||||
| @ -33,7 +34,7 @@ | |||||||
|                 console.log(initial_stats); |                 console.log(initial_stats); | ||||||
|                 start_update(); |                 start_update(); | ||||||
|                 init_chat(); |                 init_chat(); | ||||||
|                 reset_Tabs(); |                 //reset_Tabs(); | ||||||
| 
 | 
 | ||||||
|                 console.log("latitude", latitude); |                 console.log("latitude", latitude); | ||||||
|                 console.log("longitude", longitude); |                 console.log("longitude", longitude); | ||||||
| @ -42,54 +43,64 @@ | |||||||
|                     // Have to disable the beacon button. |                     // Have to disable the beacon button. | ||||||
|                     $('#send_beacon').prop('disabled', true); |                     $('#send_beacon').prop('disabled', true); | ||||||
|                 } |                 } | ||||||
|  | 
 | ||||||
|  |                 $("#wipe_local").click(function() { | ||||||
|  |                     console.log('Wipe local storage'); | ||||||
|  |                     localStorage.clear(); | ||||||
|  |                 }); | ||||||
|  | 
 | ||||||
|  |                 // When a tab is clicked, populate the to_call form field. | ||||||
|  |                 $(document).on('shown.bs.tab', 'button[data-bs-toggle="tab"]', function (e) { | ||||||
|  |                     var tab = $(e.target); | ||||||
|  |                     var callsign = tab.attr("callsign"); | ||||||
|  |                     var to_call = $('#to_call'); | ||||||
|  |                     to_call.val(callsign); | ||||||
|  |                 }); | ||||||
|             }); |             }); | ||||||
|  | 
 | ||||||
|         </script> |         </script> | ||||||
|     </head> |     </head> | ||||||
| 
 | 
 | ||||||
|     <body> |     <body> | ||||||
|         <div class='ui text container'> |         <div class='container text-center'> | ||||||
|             <h1 class='ui dividing header'>APRSD WebChat {{ version }}</h1> |             <div class="row"> | ||||||
|         </div> |                 <div class="column"> | ||||||
| 
 |                     <h1>APRSD WebChat {{ version }}</h1> | ||||||
|         <div class='ui grid text container'> |                 </div> | ||||||
|             <div class='left floated ten wide column'> |  | ||||||
|                 <span style='color: green'>{{ callsign }}</span> |  | ||||||
|                 connected to |  | ||||||
|                 <span style='color: blue' id='aprs_connection'>{{ aprs_connection|safe }}</span> |  | ||||||
|             </div> |             </div> | ||||||
| 
 |             <div class="row"> | ||||||
|             <div class='right floated four wide column'> |                 <div class="column"> | ||||||
|                 <span id='uptime'>NONE</span> |                     <span style='color: green'>{{ callsign }}</span> | ||||||
|  |                     connected to | ||||||
|  |                     <span style='color: blue' id='aprs_connection'>{{ aprs_connection|safe }}</span> | ||||||
|  |                     <span id='uptime'>NONE</span> | ||||||
|  |                 </div> | ||||||
|             </div> |             </div> | ||||||
|         </div> |             <div class="row"> | ||||||
| 
 |                 <form class="row gx-1 gy-1 justify-content-center align-items-center" id="sendform" name="sendmsg" action=""> | ||||||
|         <div class="ui container"> |                     <div class="col-sm-3"> | ||||||
|             <h3 class="ui dividing header">Send Message</h3> |                         <label for="to_call" class="visually-hidden">Callsign</label> | ||||||
|             <div id="sendMsgDiv" class="ui mini text"> |                         <input type="search" class="form-control mb-2 mr-sm-2" name="to_call" id="to_call" placeholder="To Callsign" size="11" maxlength="9"> | ||||||
|                 <form id="sendform" name="sendmsg" action=""> |  | ||||||
|                     <div class="ui corner labeled input"> |  | ||||||
|                         <label for="to_call" class="ui label">Callsign</label> |  | ||||||
|                         <input type="text" name="to_call" id="to_call" placeholder="To Callsign" size="11" maxlength="9"> |  | ||||||
|                         <div class="ui corner label"> |  | ||||||
|                             <i class="asterisk icon"></i> |  | ||||||
|                         </div> |  | ||||||
|                     </div> |                     </div> | ||||||
|                     <div class="ui labeled input"> |                     <div class="col-sm-3"> | ||||||
|                         <label for="message" class="ui label">Message</label> |                       <label for="message" class="visually-hidden">Message</label> | ||||||
|                         <input type="text" name="message" id="message" size="40" maxlength="40"> |                       <input type="text" class="form-control mb-2 mr-sm-2" name="message" id="message" size="40" maxlength="40" placeholder="Message"> | ||||||
|  |                     </div> | ||||||
|  |                     <div class="col-auto"> | ||||||
|  |                     <input type="submit" name="submit" class="btn btn-primary mb-2" id="send_msg" value="Send" /> | ||||||
|  |                     <button type="button" class="btn btn-primary mb-2" id="send_beacon" value="Send GPS Beacon">Send GPS Beacon</button> | ||||||
|  |                     <!-- <button type="button" class="btn btn-primary mb-2" id="wipe_local" value="wipe local storage">Wipe LocalStorage</button> --> | ||||||
|                     </div> |                     </div> | ||||||
|                     <input type="submit" name="submit" class="ui button" id="send_msg" value="Send" /> |  | ||||||
|                     <button type="button" class="ui button" id="send_beacon" value="Send GPS Beacon">Send GPS Beacon</button> |  | ||||||
|                 </form> |                 </form> | ||||||
|             </div> |             </div> | ||||||
|         </div> |  | ||||||
| 
 | 
 | ||||||
|         <div class="ui grid"> |             <div class="row"> | ||||||
|             <div class="three wide column"> |                 <div class="container-sm" style="max-width: 800px;"> | ||||||
|                 <div class="tab" id="callsignTabs"></div> |                     <ul class="nav nav-tabs" id="msgsTabList" role="tablist"> | ||||||
|             </div> |                     </ul> | ||||||
|             <div class="ten wide column ui raised segment" id="msgsTabsDiv" style="height:450px;padding:0px;"> |                     <div class="tab-content" id="msgsTabContent"> | ||||||
|                   |                     </div> | ||||||
|  |                 </div> | ||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,98 +0,0 @@ | |||||||
| <html> |  | ||||||
|     <head> |  | ||||||
|         <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1"> |  | ||||||
|         <!-- <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> --> |  | ||||||
|         <script src="/static/js/upstream/jquery.min.js"></script> |  | ||||||
|         <!-- <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css"> --> |  | ||||||
|         <link rel="stylesheet" href="/static/css/upstream/jquery-ui.css"> |  | ||||||
|         <!-- <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script> --> |  | ||||||
|         <script src="/static/js/upstream/jquery-ui.min.js"></script> |  | ||||||
|         <!-- <script src="https://cdn.socket.io/4.1.2/socket.io.min.js" integrity="sha384-toS6mmwu70G0fw54EGlWWeA4z3dyJ+dlXBtSURSKN4vyRFOcxd3Bzjj/AoOwY+Rg" crossorigin="anonymous"></script> --> |  | ||||||
|         <script src="/static/js/upstream/socket.io.min.js"></script> |  | ||||||
| 
 |  | ||||||
|         <!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.9.0/semantic.min.css"> --> |  | ||||||
|         <link rel="stylesheet" href="/static/css/upstream/semantic.min.css"> |  | ||||||
|         <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.9.0/semantic.min.js"></script> --> |  | ||||||
|         <script src="/static/js/upstream/semantic.min.js"></script> |  | ||||||
| 
 |  | ||||||
|         <link rel="stylesheet" href="/static/css/index.css"> |  | ||||||
|         <script src="/static/js/main.js"></script> |  | ||||||
|         <script src="/static/js/gps.js"></script> |  | ||||||
|         <script src="/static/js/send-message-mobile.js"></script> |  | ||||||
| 
 |  | ||||||
|         <script type="text/javascript"> |  | ||||||
|             var initial_stats = {{ initial_stats|tojson|safe }}; |  | ||||||
|             var latitude = parseFloat('{{ latitude|safe }}'); |  | ||||||
|             var longitude = parseFloat('{{ longitude|safe }}'); |  | ||||||
| 
 |  | ||||||
|             var memory_chart = null |  | ||||||
|             var message_chart = null |  | ||||||
| 
 |  | ||||||
|             $(document).ready(function() { |  | ||||||
|                 console.log(initial_stats); |  | ||||||
|                 start_update(); |  | ||||||
|                 init_chat(); |  | ||||||
| 
 |  | ||||||
|                 console.log("latitude", latitude); |  | ||||||
|                 console.log("longitude", longitude); |  | ||||||
| 
 |  | ||||||
|                 if (isNaN(latitude) || isNaN(longitude) && location.protocol != 'https:') { |  | ||||||
|                     // Have to disable the beacon button. |  | ||||||
|                     $('#send_beacon').prop('disabled', true); |  | ||||||
|                 } |  | ||||||
|             }); |  | ||||||
|         </script> |  | ||||||
|     </head> |  | ||||||
| 
 |  | ||||||
|     <body> |  | ||||||
|         <div class='ui text container'> |  | ||||||
|             <h1 class='ui dividing header'>APRSD WebChat {{ version }}</h1> |  | ||||||
|         </div> |  | ||||||
| 
 |  | ||||||
|         <div class='ui grid text container' style="padding-bottom: 5px;"> |  | ||||||
|             <div class='left floated twelve wide column'> |  | ||||||
|                 <span style='color: green'>{{ callsign }}</span> |  | ||||||
|                 connected to |  | ||||||
|                 <span style='color: blue' id='aprs_connection'>{{ aprs_connection|safe }}</span> |  | ||||||
|             </div> |  | ||||||
| 
 |  | ||||||
|             <div class='right floated four wide column'> |  | ||||||
|                 <span id='uptime'>NONE</span> |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
| 
 |  | ||||||
|         <div id="sendMsgDiv" class="ui grid" align="left" style="padding-top: 2px;"> |  | ||||||
|             <h3 class="sixteen wide column ui dividing header">Send Message</h3> |  | ||||||
|             <form id="sendform" name="sendmsg" action=""> |  | ||||||
|                 <div class="sixteen wide column ui left labeled icon input"> |  | ||||||
|                         <div class="ui label">Callsign</div> |  | ||||||
|                         <input type="text" name="to_call" id="to_call" placeholder="To Callsign" size="11" maxlength="9"> |  | ||||||
|                         <i class="users icon"></i> |  | ||||||
|                 </div> |  | ||||||
|                 <div class="sixteen wide column ui left labeled icon input" style="padding-bottom: 5px;"> |  | ||||||
|                         <label for="message" class="ui label">Message</label> |  | ||||||
|                         <input type="text" name="message" id="message" maxlength="40" placeholder="Message"> |  | ||||||
|                         <i class="comment icon"></i> |  | ||||||
|                 </div> |  | ||||||
|                 <div class="right floated column"> |  | ||||||
|                     <input type="submit" name="submit" class="ui button" id="send_msg" value="Send" /> |  | ||||||
|                     <button type="button" class="ui button" id="send_beacon" value="Send GPS Beacon">Send GPS Beacon</button> |  | ||||||
|                 </div> |  | ||||||
| 
 |  | ||||||
|             </form> |  | ||||||
|         </div> |  | ||||||
| 
 |  | ||||||
|         <div class="ui grid"> |  | ||||||
|             <div class="ui top attached tabular raised menu" id="callsignTabs"> |  | ||||||
|             </div> |  | ||||||
|             <div class="sixteen wide column ui bottom attached raised tab segment" id="msgsTabsDiv" style="height:250px;padding:5px;"> |  | ||||||
|                   |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
| 
 |  | ||||||
|         <div class="ui text container" style="padding-top: 40px"> |  | ||||||
|             <a href="https://badge.fury.io/py/aprsd"><img src="https://badge.fury.io/py/aprsd.svg" alt="PyPI version" height="18"></a> |  | ||||||
|             <a href="https://github.com/craigerl/aprsd"><img src="https://img.shields.io/badge/Made%20with-Python-1f425f.svg" height="18"></a> |  | ||||||
|         </div> |  | ||||||
|     </body> |  | ||||||
| </html> |  | ||||||
| @ -1,34 +1,33 @@ | |||||||
| # | # | ||||||
| # This file is autogenerated by pip-compile with Python 3.10 | # This file is autogenerated by pip-compile with Python 3.11 | ||||||
| # by the following command: | # by the following command: | ||||||
| # | # | ||||||
| #    pip-compile --annotation-style=line dev-requirements.in | #    pip-compile --annotation-style=line dev-requirements.in | ||||||
| # | # | ||||||
| add-trailing-comma==3.0.1  # via gray | add-trailing-comma==3.1.0  # via gray | ||||||
| alabaster==0.7.13         # via sphinx | alabaster==0.7.13         # via sphinx | ||||||
| attrs==23.1.0             # via jsonschema, referencing | attrs==23.1.0             # via jsonschema, referencing | ||||||
| autoflake==1.5.3          # via gray | autoflake==1.5.3          # via gray | ||||||
| babel==2.12.1             # via sphinx | babel==2.12.1             # via sphinx | ||||||
| black==23.7.0             # via gray | black==23.7.0             # via gray | ||||||
| build==0.10.0             # via pip-tools | build==1.0.3              # via pip-tools | ||||||
| cachetools==5.3.1         # via tox | cachetools==5.3.1         # via tox | ||||||
| certifi==2023.7.22        # via requests | certifi==2023.7.22        # via requests | ||||||
| cfgv==3.4.0               # via pre-commit | cfgv==3.4.0               # via pre-commit | ||||||
| chardet==5.2.0            # via tox | chardet==5.2.0            # via tox | ||||||
| charset-normalizer==3.2.0  # via requests | charset-normalizer==3.2.0  # via requests | ||||||
| click==8.1.6              # via black, pip-tools | click==8.1.7              # via black, pip-tools | ||||||
| colorama==0.4.6           # via tox | colorama==0.4.6           # via tox | ||||||
| commonmark==0.9.1         # via rich | commonmark==0.9.1         # via rich | ||||||
| configargparse==1.7       # via gray | configargparse==1.7       # via gray | ||||||
| coverage[toml]==7.3.0     # via pytest-cov | coverage[toml]==7.3.1     # via pytest-cov | ||||||
| distlib==0.3.7            # via virtualenv | distlib==0.3.7            # via virtualenv | ||||||
| docutils==0.20.1          # via sphinx | docutils==0.20.1          # via sphinx | ||||||
| exceptiongroup==1.1.3     # via pytest | filelock==3.12.3          # via tox, virtualenv | ||||||
| filelock==3.12.2          # via tox, virtualenv |  | ||||||
| fixit==0.1.4              # via gray | fixit==0.1.4              # via gray | ||||||
| flake8==6.1.0             # via -r dev-requirements.in, fixit, pep8-naming | flake8==6.1.0             # via -r dev-requirements.in, fixit, pep8-naming | ||||||
| gray==0.13.0              # via -r dev-requirements.in | gray==0.13.0              # via -r dev-requirements.in | ||||||
| identify==2.5.26          # via pre-commit | identify==2.5.27          # via pre-commit | ||||||
| idna==3.4                 # via requests | idna==3.4                 # via requests | ||||||
| imagesize==1.4.1          # via sphinx | imagesize==1.4.1          # via sphinx | ||||||
| importlib-resources==6.0.1  # via fixit | importlib-resources==6.0.1  # via fixit | ||||||
| @ -40,7 +39,7 @@ jsonschema-specifications==2023.7.1  # via jsonschema | |||||||
| libcst==1.0.1             # via fixit | libcst==1.0.1             # via fixit | ||||||
| markupsafe==2.1.3         # via jinja2 | markupsafe==2.1.3         # via jinja2 | ||||||
| mccabe==0.7.0             # via flake8 | mccabe==0.7.0             # via flake8 | ||||||
| mypy==1.5.0               # via -r dev-requirements.in | mypy==1.5.1               # via -r dev-requirements.in | ||||||
| mypy-extensions==1.0.0    # via black, mypy, typing-inspect | mypy-extensions==1.0.0    # via black, mypy, typing-inspect | ||||||
| nodeenv==1.8.0            # via pre-commit | nodeenv==1.8.0            # via pre-commit | ||||||
| packaging==23.1           # via black, build, pyproject-api, pytest, sphinx, tox | packaging==23.1           # via black, build, pyproject-api, pytest, sphinx, tox | ||||||
| @ -48,40 +47,39 @@ pathspec==0.11.2          # via black | |||||||
| pep8-naming==0.13.3       # via -r dev-requirements.in | pep8-naming==0.13.3       # via -r dev-requirements.in | ||||||
| pip-tools==7.3.0          # via -r dev-requirements.in | pip-tools==7.3.0          # via -r dev-requirements.in | ||||||
| platformdirs==3.10.0      # via black, tox, virtualenv | platformdirs==3.10.0      # via black, tox, virtualenv | ||||||
| pluggy==1.2.0             # via pytest, tox | pluggy==1.3.0             # via pytest, tox | ||||||
| pre-commit==3.3.3         # via -r dev-requirements.in | pre-commit==3.4.0         # via -r dev-requirements.in | ||||||
| pycodestyle==2.11.0       # via flake8 | pycodestyle==2.11.0       # via flake8 | ||||||
| pyflakes==3.1.0           # via autoflake, flake8 | pyflakes==3.1.0           # via autoflake, flake8 | ||||||
| pygments==2.16.1          # via rich, sphinx | pygments==2.16.1          # via rich, sphinx | ||||||
| pyproject-api==1.5.3      # via tox | pyproject-api==1.6.1      # via tox | ||||||
| pyproject-hooks==1.0.0    # via build | pyproject-hooks==1.0.0    # via build | ||||||
| pytest==7.4.0             # via -r dev-requirements.in, pytest-cov | pytest==7.4.2             # via -r dev-requirements.in, pytest-cov | ||||||
| pytest-cov==4.1.0         # via -r dev-requirements.in | pytest-cov==4.1.0         # via -r dev-requirements.in | ||||||
| pyupgrade==3.10.1         # via gray | pyupgrade==3.10.1         # via gray | ||||||
| pyyaml==6.0.1             # via fixit, libcst, pre-commit | pyyaml==6.0.1             # via fixit, libcst, pre-commit | ||||||
| referencing==0.30.2       # via jsonschema, jsonschema-specifications | referencing==0.30.2       # via jsonschema, jsonschema-specifications | ||||||
| requests==2.31.0          # via sphinx | requests==2.31.0          # via sphinx | ||||||
| rich==12.6.0              # via gray | rich==12.6.0              # via gray | ||||||
| rpds-py==0.9.2            # via jsonschema, referencing | rpds-py==0.10.2           # via jsonschema, referencing | ||||||
| snowballstemmer==2.2.0    # via sphinx | snowballstemmer==2.2.0    # via sphinx | ||||||
| sphinx==7.1.2             # via -r dev-requirements.in, sphinxcontrib-applehelp, sphinxcontrib-devhelp, sphinxcontrib-htmlhelp, sphinxcontrib-qthelp, sphinxcontrib-serializinghtml | sphinx==7.2.5             # via -r dev-requirements.in, sphinxcontrib-applehelp, sphinxcontrib-devhelp, sphinxcontrib-htmlhelp, sphinxcontrib-qthelp, sphinxcontrib-serializinghtml | ||||||
| sphinxcontrib-applehelp==1.0.7  # via sphinx | sphinxcontrib-applehelp==1.0.7  # via sphinx | ||||||
| sphinxcontrib-devhelp==1.0.5  # via sphinx | sphinxcontrib-devhelp==1.0.5  # via sphinx | ||||||
| sphinxcontrib-htmlhelp==2.0.4  # via sphinx | sphinxcontrib-htmlhelp==2.0.4  # via sphinx | ||||||
| sphinxcontrib-jsmath==1.0.1  # via sphinx | sphinxcontrib-jsmath==1.0.1  # via sphinx | ||||||
| sphinxcontrib-qthelp==1.0.6  # via sphinx | sphinxcontrib-qthelp==1.0.6  # via sphinx | ||||||
| sphinxcontrib-serializinghtml==1.1.8  # via sphinx | sphinxcontrib-serializinghtml==1.1.9  # via sphinx | ||||||
| tokenize-rt==5.2.0        # via add-trailing-comma, pyupgrade | tokenize-rt==5.2.0        # via add-trailing-comma, pyupgrade | ||||||
| toml==0.10.2              # via autoflake | toml==0.10.2              # via autoflake | ||||||
| tomli==2.0.1              # via black, build, coverage, mypy, pip-tools, pyproject-api, pyproject-hooks, pytest, tox | tox==4.11.2               # via -r dev-requirements.in | ||||||
| tox==4.8.0                # via -r dev-requirements.in |  | ||||||
| typing-extensions==4.7.1  # via libcst, mypy, typing-inspect | typing-extensions==4.7.1  # via libcst, mypy, typing-inspect | ||||||
| typing-inspect==0.9.0     # via libcst | typing-inspect==0.9.0     # via libcst | ||||||
| unify==0.5                # via gray | unify==0.5                # via gray | ||||||
| untokenize==0.1.1         # via unify | untokenize==0.1.1         # via unify | ||||||
| urllib3==2.0.4            # via requests | urllib3==2.0.4            # via requests | ||||||
| virtualenv==20.24.3       # via pre-commit, tox | virtualenv==20.24.5       # via pre-commit, tox | ||||||
| wheel==0.41.1             # via pip-tools | wheel==0.41.2             # via pip-tools | ||||||
| 
 | 
 | ||||||
| # The following packages are considered to be unsafe in a requirements file: | # The following packages are considered to be unsafe in a requirements file: | ||||||
| # pip | # pip | ||||||
|  | |||||||
| @ -27,8 +27,6 @@ wrapt | |||||||
| # kiss3 uses attrs | # kiss3 uses attrs | ||||||
| kiss3 | kiss3 | ||||||
| attrs | attrs | ||||||
| # for mobile checking |  | ||||||
| user-agents |  | ||||||
| dataclasses | dataclasses | ||||||
| dacite2 | dacite2 | ||||||
| oslo.config | oslo.config | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| # | # | ||||||
| # This file is autogenerated by pip-compile with Python 3.10 | # This file is autogenerated by pip-compile with Python 3.11 | ||||||
| # by the following command: | # by the following command: | ||||||
| # | # | ||||||
| #    pip-compile --annotation-style=line requirements.in | #    pip-compile --annotation-style=line requirements.in | ||||||
| @ -13,7 +13,7 @@ bitarray==2.8.1           # via ax253, kiss3 | |||||||
| blinker==1.6.2            # via flask | blinker==1.6.2            # via flask | ||||||
| certifi==2023.7.22        # via requests | certifi==2023.7.22        # via requests | ||||||
| charset-normalizer==3.2.0  # via requests | charset-normalizer==3.2.0  # via requests | ||||||
| click==8.1.6              # via -r requirements.in, click-completion, click-params, flask | click==8.1.7              # via -r requirements.in, click-completion, click-params, flask | ||||||
| click-completion==0.5.2   # via -r requirements.in | click-completion==0.5.2   # via -r requirements.in | ||||||
| click-params==0.4.1       # via -r requirements.in | click-params==0.4.1       # via -r requirements.in | ||||||
| commonmark==0.9.1         # via rich | commonmark==0.9.1         # via rich | ||||||
| @ -23,12 +23,12 @@ debtcollector==2.5.0      # via oslo-config | |||||||
| decorator==5.1.1          # via validators | decorator==5.1.1          # via validators | ||||||
| dnspython==2.4.2          # via eventlet | dnspython==2.4.2          # via eventlet | ||||||
| eventlet==0.33.3          # via -r requirements.in | eventlet==0.33.3          # via -r requirements.in | ||||||
| flask==2.3.2              # via -r requirements.in, flask-httpauth, flask-socketio | flask==2.3.3              # via -r requirements.in, flask-httpauth, flask-socketio | ||||||
| flask-httpauth==4.8.0     # via -r requirements.in | flask-httpauth==4.8.0     # via -r requirements.in | ||||||
| flask-socketio==5.3.5     # via -r requirements.in | flask-socketio==5.3.6     # via -r requirements.in | ||||||
| geographiclib==2.0        # via geopy | geographiclib==2.0        # via geopy | ||||||
| geopy==2.3.0              # via -r requirements.in | geopy==2.4.0              # via -r requirements.in | ||||||
| gevent==23.7.0            # via -r requirements.in | gevent==23.9.0.post1      # via -r requirements.in | ||||||
| greenlet==2.0.2           # via eventlet, gevent | greenlet==2.0.2           # via eventlet, gevent | ||||||
| idna==3.4                 # via requests | idna==3.4                 # via requests | ||||||
| imapclient==2.3.1         # via -r requirements.in | imapclient==2.3.1         # via -r requirements.in | ||||||
| @ -38,33 +38,31 @@ jinja2==3.1.2             # via click-completion, flask | |||||||
| kiss3==8.0.0              # via -r requirements.in | kiss3==8.0.0              # via -r requirements.in | ||||||
| markupsafe==2.1.3         # via jinja2, werkzeug | markupsafe==2.1.3         # via jinja2, werkzeug | ||||||
| netaddr==0.8.0            # via oslo-config | netaddr==0.8.0            # via oslo-config | ||||||
| oslo-config==9.1.1        # via -r requirements.in | oslo-config==9.2.0        # via -r requirements.in | ||||||
| oslo-i18n==6.0.0          # via oslo-config | oslo-i18n==6.1.0          # via oslo-config | ||||||
| pbr==5.11.1               # via -r requirements.in, oslo-i18n, stevedore | pbr==5.11.1               # via -r requirements.in, oslo-i18n, stevedore | ||||||
| pluggy==1.2.0             # via -r requirements.in | pluggy==1.3.0             # via -r requirements.in | ||||||
| plumbum==1.8.2            # via rpyc | plumbum==1.8.2            # via rpyc | ||||||
| pygments==2.16.1          # via rich | pygments==2.16.1          # via rich | ||||||
| pyserial==3.5             # via pyserial-asyncio | pyserial==3.5             # via pyserial-asyncio | ||||||
| pyserial-asyncio==0.6     # via kiss3 | pyserial-asyncio==0.6     # via kiss3 | ||||||
| python-engineio==4.5.1    # via python-socketio | python-engineio==4.7.0    # via python-socketio | ||||||
| python-socketio==5.8.0    # via -r requirements.in, flask-socketio | python-socketio==5.9.0    # via -r requirements.in, flask-socketio | ||||||
| pytz==2023.3              # via -r requirements.in | pytz==2023.3.post1        # via -r requirements.in | ||||||
| pyyaml==6.0.1             # via -r requirements.in, oslo-config | pyyaml==6.0.1             # via -r requirements.in, oslo-config | ||||||
| requests==2.31.0          # via -r requirements.in, oslo-config, update-checker | requests==2.31.0          # via -r requirements.in, oslo-config, update-checker | ||||||
| rfc3986==2.0.0            # via oslo-config | rfc3986==2.0.0            # via oslo-config | ||||||
| rich==12.6.0              # via -r requirements.in | rich==12.6.0              # via -r requirements.in | ||||||
| rpyc==5.3.1               # via -r requirements.in | rpyc==5.3.1               # via -r requirements.in | ||||||
| rush==2021.4.0            # via -r requirements.in | rush==2021.4.0            # via -r requirements.in | ||||||
| shellingham==1.5.0.post1  # via -r requirements.in, click-completion | shellingham==1.5.3        # via -r requirements.in, click-completion | ||||||
| six==1.16.0               # via -r requirements.in, click-completion, eventlet, imapclient | six==1.16.0               # via -r requirements.in, click-completion, eventlet, imapclient | ||||||
| soupsieve==2.4.1          # via beautifulsoup4 | soupsieve==2.5            # via beautifulsoup4 | ||||||
| stevedore==5.1.0          # via oslo-config | stevedore==5.1.0          # via oslo-config | ||||||
| tabulate==0.9.0           # via -r requirements.in | tabulate==0.9.0           # via -r requirements.in | ||||||
| thesmuggler==1.0.1        # via -r requirements.in | thesmuggler==1.0.1        # via -r requirements.in | ||||||
| ua-parser==0.18.0         # via user-agents |  | ||||||
| update-checker==0.18.0    # via -r requirements.in | update-checker==0.18.0    # via -r requirements.in | ||||||
| urllib3==2.0.4            # via requests | urllib3==2.0.4            # via requests | ||||||
| user-agents==2.2.0        # via -r requirements.in |  | ||||||
| validators==0.20.0        # via click-params | validators==0.20.0        # via click-params | ||||||
| werkzeug==2.3.7           # via -r requirements.in, flask | werkzeug==2.3.7           # via -r requirements.in, flask | ||||||
| wrapt==1.15.0             # via -r requirements.in, debtcollector | wrapt==1.15.0             # via -r requirements.in, debtcollector | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user