2023-11-12 20:06:15 +00:00
|
|
|
{% extends "base.html" %}
|
|
|
|
|
|
|
|
{% block title %}
|
|
|
|
SAR job details
|
|
|
|
{% endblock %}
|
|
|
|
|
|
|
|
{% block content %}
|
|
|
|
|
2023-11-14 10:07:43 +00:00
|
|
|
<div class="container mt-4">
|
2023-11-19 21:08:19 +00:00
|
|
|
<h2 class="mb-4">#{{ sar.SARCall.id }} : {{ sar.SARCall.title }}</h2>
|
2023-11-14 10:07:43 +00:00
|
|
|
<div class="card mb-4">
|
|
|
|
<div class="card-body">
|
2023-11-17 06:50:24 +00:00
|
|
|
<table>
|
|
|
|
<tr>
|
|
|
|
<td>
|
|
|
|
<div class="card-mb5">
|
|
|
|
<div class="card-body">
|
|
|
|
<div>
|
2023-11-19 21:08:19 +00:00
|
|
|
<p>Created at: {{ sar.SARCall.created }}</p>
|
|
|
|
<p>Last updated: {{ sar.SARCall.updated }}</p>
|
2023-11-17 06:50:24 +00:00
|
|
|
</div>
|
2023-11-26 19:06:43 +00:00
|
|
|
<p><strong>Coordination
|
|
|
|
manager:</strong> {{ sar.SARCall.coordination_officer.full_name }}</p>
|
2023-11-19 21:08:19 +00:00
|
|
|
<p><strong>Search manager:</strong> {{ sar.SARCall.search_officer.full_name }}</p>
|
|
|
|
<p>Status: {{ sar.SARStatus.name }}</p>
|
|
|
|
{% if is_logged_in %}
|
2023-11-26 19:06:43 +00:00
|
|
|
<p>Category: {{ sar.SARCategory.name }}</p>
|
2023-11-19 21:08:19 +00:00
|
|
|
{% endif %}
|
|
|
|
<p><strong>Start Date:</strong> {{ sar.SARCall.start_date }}</p>
|
|
|
|
<p><strong>Finish Date:</strong> {{ sar.SARCall.finish_date }}</p>
|
|
|
|
<p>Result: {{ sar.SARResult.name }}</p>
|
2023-11-17 06:50:24 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</td>
|
|
|
|
<td>
|
|
|
|
<div class="card-mb5">
|
|
|
|
<div class="card-body">
|
2023-12-11 16:59:07 +00:00
|
|
|
<p>IPP lat: {{ sar.SARCall.latitude }}</p>
|
|
|
|
<p>IPP lon: {{ sar.SARCall.longitude }} </p>
|
2023-12-11 16:59:20 +00:00
|
|
|
<p>Found lat: {{ sar.SARCall.latitude_found }}</p>
|
2023-12-11 16:59:07 +00:00
|
|
|
<p>Found lon: {{ sar.SARCall.longitude_found }}</p>
|
2023-11-19 21:08:19 +00:00
|
|
|
<p>Description: {{ sar.SARCall.description }}</p>
|
|
|
|
{% if is_logged_in %}
|
2023-11-26 19:06:43 +00:00
|
|
|
<p>Description private: {{ sar.SARCall.description_hidden }}</p>
|
2023-11-19 21:08:19 +00:00
|
|
|
{% endif %}
|
2023-11-17 06:50:24 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</td>
|
|
|
|
<!-- Other SAR details -->
|
|
|
|
</tr>
|
|
|
|
</table>
|
2023-12-09 21:21:44 +00:00
|
|
|
<div>
|
|
|
|
{% if is_logged_in %}
|
|
|
|
<a href="{{ url_for('edit_sar', sar_id=sar.SARCall.id) }}" class="btn btn-primary"> ✎</a>
|
|
|
|
{# EDIT #}
|
|
|
|
<a href="{{ url_for('delete_sar', sar_id=sar.SARCall.id) }}"
|
|
|
|
class="btn btn-danger">🗑</a> {# DELETE #}
|
|
|
|
{% endif %}
|
|
|
|
</div>
|
2023-11-14 10:07:43 +00:00
|
|
|
</div>
|
2023-11-12 20:06:15 +00:00
|
|
|
</div>
|
2023-11-13 17:51:57 +00:00
|
|
|
|
|
|
|
|
2023-11-14 10:07:43 +00:00
|
|
|
<div id="map" class="mb-4"></div>
|
2023-12-11 15:12:12 +00:00
|
|
|
<div id="markers" class="mb-4"></div> <!-- New element for displaying marker coordinates -->
|
2023-11-14 10:07:43 +00:00
|
|
|
|
|
|
|
<!-- Display Comments -->
|
2023-11-19 21:08:19 +00:00
|
|
|
{% for comment in sar.SARCall.comments %}
|
2023-11-14 10:07:43 +00:00
|
|
|
<div class="comment">
|
2023-11-16 08:59:39 +00:00
|
|
|
<div class="card mb-4">
|
|
|
|
<div class="card-body">
|
2023-12-09 21:21:44 +00:00
|
|
|
<small> Comment # {{ comment.id }} by <strong>{{ comment.user.full_name }}</strong>
|
|
|
|
at {{ comment.created }},
|
|
|
|
updated {{ comment.updated }} </small>
|
2023-11-16 08:59:39 +00:00
|
|
|
<div class="card mb-5">
|
2023-12-09 21:21:44 +00:00
|
|
|
{# Comment text #}
|
2023-11-16 08:59:39 +00:00
|
|
|
<div class="card-body">
|
2023-12-12 20:15:38 +00:00
|
|
|
{% if is_logged_in %}
|
2023-12-09 21:21:44 +00:00
|
|
|
|
2023-12-12 20:15:38 +00:00
|
|
|
<div class="comment-text"><p
|
|
|
|
id="comment-text-{{ comment.id }}">{{ comment.text }}</p>
|
|
|
|
</div>
|
2023-12-09 21:21:44 +00:00
|
|
|
|
|
|
|
{% if current_user.id == comment.user_id or current_user.id == 1 or current_user.id == sar.SARCall.user_id %}
|
|
|
|
<button class="edit-comment-btn" data-comment-id="{{ comment.id }}"
|
|
|
|
data-comment-text="{{ comment.text }}"> ✎ {# EDIT #}
|
|
|
|
</button>
|
|
|
|
<button type="button" class="delete-comment-btn">
|
|
|
|
<a href="{{ url_for('delete_comment', id=comment.id) }}">🗑</a>
|
|
|
|
{# DELETE #}
|
|
|
|
</button>
|
|
|
|
{% endif %}
|
|
|
|
</div>
|
|
|
|
{# GPX tracks part #}
|
|
|
|
<div class="card mb-6">
|
|
|
|
<div class="card-body">
|
|
|
|
{% set ns = namespace(drawn = false) %}
|
|
|
|
<small><strong>GPX track:</strong></small>
|
|
|
|
{% for gpx_track in comments_with_gpx %}
|
|
|
|
{% if gpx_track.comment_id == comment.id %}
|
|
|
|
<li>
|
|
|
|
<a href="{{ url_for('get_gpx', gpx_id=gpx_track.id) }}">{{ gpx_track.name }}</a>
|
|
|
|
</li>
|
|
|
|
{% set ns.drawn = true %}
|
|
|
|
<!-- Button to delete GPX Upload Modal -->
|
2023-12-10 12:58:09 +00:00
|
|
|
<button type="button" class="gpx-delete-button">
|
2023-12-10 13:14:23 +00:00
|
|
|
<a href="{{ url_for('delete_gpx', gpx_id=gpx_track.id, sar_id=sar.SARCall.id ) }}">
|
|
|
|
🗑</a>
|
2023-12-09 21:21:44 +00:00
|
|
|
</button>
|
|
|
|
{% endif %}
|
|
|
|
{% endfor %}
|
|
|
|
{% if ns.drawn == false %}
|
|
|
|
<!-- Button to Open GPX Upload Modal -->
|
|
|
|
<button type="button" class="gpx-upload-button" data-toggle="modal"
|
|
|
|
data-target="#uploadGPXModal"
|
|
|
|
data-comment-id="{{ comment.id }}">
|
|
|
|
Upload GPX File
|
|
|
|
</button>
|
|
|
|
{% endif %}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="card mb-6">
|
|
|
|
<div class="card-body">
|
|
|
|
{# File attachments part #}
|
|
|
|
<small><strong>File attachment:</strong></small><p>
|
|
|
|
{% set ns=namespace(has_file = false) %}
|
2023-12-10 13:14:23 +00:00
|
|
|
{% set fs=namespace(filename = 0) %}
|
2023-12-09 21:21:44 +00:00
|
|
|
{% for file in comments_with_attachment %}
|
|
|
|
{% if file.comment_id == comment.id %}
|
|
|
|
{% set ns.has_file = true %}
|
2023-12-10 13:14:23 +00:00
|
|
|
<a href="{{ url_for('download_file', filename = file.file_name) }}">
|
|
|
|
{% if file.is_image %}
|
|
|
|
<img src="{{ url_for('download_thumb', filename=file.file_name) }}"
|
|
|
|
class="img-thumbnail">
|
|
|
|
{% else %}
|
|
|
|
<i class="fa fa-file" aria-hidden="true"></i> {{ file.file_name }}
|
|
|
|
{% endif %}
|
|
|
|
{% set fs.filename = file.id %}
|
|
|
|
</a>
|
2023-12-09 21:21:44 +00:00
|
|
|
{% endif %}
|
|
|
|
{% endfor %}
|
|
|
|
|
|
|
|
{% if is_logged_in %}
|
|
|
|
{% if ns.has_file %}
|
|
|
|
<!-- Display the attachment -->
|
2023-12-10 13:14:23 +00:00
|
|
|
<!-- Button to delete the attachment -->
|
|
|
|
<form method="POST"
|
|
|
|
action="{{ url_for('delete_file', attachment_id=fs.filename) }}">
|
|
|
|
{# Delete attachment #}
|
|
|
|
<input type="hidden" id="sar_call_id" name="sarId"
|
|
|
|
value="{{ sar.SARCall.id }}">
|
|
|
|
<button type="submit" class="btn btn-danger">🗑</button>
|
|
|
|
</form>
|
2023-12-09 21:21:44 +00:00
|
|
|
{% else %}
|
|
|
|
|
|
|
|
<form method="POST"
|
|
|
|
action={{ url_for("upload_file") }} enctype="multipart/form-data">
|
|
|
|
<input type="file" name="file" accept="image/*">
|
|
|
|
<input type="submit" value="Upload">
|
|
|
|
<input type="file" id="attachmentInput" style="display: none;">
|
|
|
|
<input type="hidden" id="comment_id" name="commentId"
|
|
|
|
value="{{ comment.id }}">
|
|
|
|
<input type="hidden" id="sar_call_id" name="sarId"
|
|
|
|
value="{{ sar.SARCall.id }}">
|
|
|
|
</form>
|
|
|
|
|
|
|
|
{% endif %}
|
|
|
|
|
|
|
|
|
|
|
|
{% endif %}
|
|
|
|
|
|
|
|
{% endif %}
|
|
|
|
</div>
|
|
|
|
</div>
|
2023-11-16 08:59:39 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
2023-11-14 20:33:57 +00:00
|
|
|
</div>
|
2023-11-14 10:07:43 +00:00
|
|
|
</div>
|
|
|
|
{% endfor %}
|
|
|
|
|
|
|
|
<!-- Edit Comment Modal -->
|
|
|
|
<div class="modal fade" id="editCommentModal" tabindex="-1" aria-labelledby="editCommentModalLabel"
|
|
|
|
aria-hidden="true">
|
|
|
|
<div class="modal-dialog">
|
|
|
|
<div class="modal-content">
|
|
|
|
<div class="modal-header">
|
|
|
|
<h5 class="modal-title" id="editCommentModalLabel">Edit Comment</h5>
|
|
|
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
|
|
<span aria-hidden="true">×</span>
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
<div class="modal-body">
|
|
|
|
<form id="editCommentForm">
|
|
|
|
<div class="form-group">
|
|
|
|
<label for="commentText" class="col-form-label">Comment:</label>
|
|
|
|
<textarea class="form-control" id="commentText"></textarea>
|
|
|
|
</div>
|
|
|
|
</form>
|
|
|
|
</div>
|
|
|
|
<div class="modal-footer">
|
|
|
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
|
|
|
<button type="button" class="btn btn-primary" id="saveComment">Save changes</button>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2023-11-13 17:51:57 +00:00
|
|
|
|
|
|
|
|
2023-11-14 10:07:43 +00:00
|
|
|
<!-- Add Comment Form -->
|
2023-11-26 19:06:43 +00:00
|
|
|
{% if is_logged_in %}
|
|
|
|
<form action="{{ url_for('add_comment', sar_call_id=sar.SARCall.id) }}" method="post"
|
|
|
|
enctype="multipart/form-data">
|
|
|
|
<div class="form-group">
|
2023-12-09 21:21:44 +00:00
|
|
|
<label for="text"><small>Add comment:</small></label>
|
2023-11-26 19:06:43 +00:00
|
|
|
<textarea name="text" class="form-control"></textarea>
|
|
|
|
</div>
|
|
|
|
<div class="form-group">
|
2023-11-14 20:33:57 +00:00
|
|
|
|
|
|
|
|
2023-11-26 19:06:43 +00:00
|
|
|
</div>
|
|
|
|
<button type="submit" class="btn btn-primary">Add Comment</button>
|
|
|
|
</form>
|
|
|
|
{% endif %}
|
2023-11-14 10:07:43 +00:00
|
|
|
</div>
|
2023-11-13 17:51:57 +00:00
|
|
|
|
2023-11-14 20:33:57 +00:00
|
|
|
<!-- GPX File Upload Modal -->
|
|
|
|
<div class="modal fade" id="uploadGPXModal" tabindex="-1" aria-labelledby="uploadGPXModalLabel" aria-hidden="true">
|
|
|
|
<div class="modal-dialog">
|
|
|
|
<div class="modal-content">
|
|
|
|
<div class="modal-header">
|
|
|
|
<h5 class="modal-title" id="uploadGPXModalLabel">Upload GPX File</h5>
|
|
|
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
|
|
<span aria-hidden="true">×</span>
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
<form id="uploadGPXForm" method="post" enctype="multipart/form-data">
|
|
|
|
<div class="modal-body">
|
|
|
|
<div class="form-group">
|
|
|
|
<label for="gpxFileName">Description: </label>
|
|
|
|
<input type="text" class="form-control" id="gpxFileName" name="gpxFileName" required>
|
|
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
|
|
<label for="gpxFile">GPX File</label>
|
|
|
|
<input type="file" class="form-control" id="gpxFile" name="gpxFile" required>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<input type="hidden" id="commentIdForGPX" name="commentId">
|
2023-11-19 21:08:19 +00:00
|
|
|
<input type="hidden" id="sarIdForGPX" name="sarId" value="{{ sar.SARCall.id }}">
|
2023-11-14 20:33:57 +00:00
|
|
|
<div class="modal-footer">
|
|
|
|
<button type="submit" class="btn btn-primary">Upload</button>
|
|
|
|
</div>
|
|
|
|
</form>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
2023-12-09 21:21:44 +00:00
|
|
|
<!-- The GPX upload modal -->
|
2023-11-30 19:47:54 +00:00
|
|
|
<div class="modal fade" id="saveTrackModal" tabindex="-1" role="dialog" aria-labelledby="saveTrackModalLabel"
|
|
|
|
aria-hidden="true">
|
|
|
|
<div class="modal-dialog" role="document">
|
|
|
|
<div class="modal-content">
|
|
|
|
<div class="modal-header">
|
|
|
|
<h5 class="modal-title" id="saveTrackModalLabel">Save Track</h5>
|
|
|
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
|
|
<span aria-hidden="true">×</span>
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
<form id="uploadTRKForm" method="post" enctype="multipart/form-data">
|
|
|
|
<div class="modal-body">
|
|
|
|
<!-- Form inputs for track name and comment -->
|
|
|
|
<div class="form-group">
|
|
|
|
<label for="track-name">Track Name:</label>
|
|
|
|
<input type="text" class="form-control" id="track-name">
|
|
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
|
|
<label for="track-comment">Comment:</label>
|
|
|
|
<textarea class="form-control" id="track-comment"></textarea>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<input type="hidden" id="sarIdForTRK" name="sarId" value="{{ sar.SARCall.id }}">
|
|
|
|
<div class="modal-footer">
|
|
|
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
|
|
|
<button type="button" class="btn btn-primary" id="confirm-save-track">Save</button>
|
|
|
|
</div>
|
|
|
|
</form>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-11-12 20:06:15 +00:00
|
|
|
<script>
|
2023-11-15 14:24:56 +00:00
|
|
|
|
|
|
|
// Load GPX file and add to map
|
|
|
|
function loadAndDisplayGPX(gpxId) {
|
|
|
|
fetch('/get_gpx/' + gpxId)
|
|
|
|
.then(response => response.text())
|
|
|
|
.then(gpxData => {
|
2023-11-26 19:06:43 +00:00
|
|
|
new L.GPX(gpxData, {
|
|
|
|
async: true,
|
|
|
|
marker_options: {
|
|
|
|
startIconUrl: '/static/pin-icon-start.png',
|
|
|
|
endIconUrl: '/static/pin-icon-end.png',
|
2023-11-30 20:44:08 +00:00
|
|
|
shadowUrl: '/static/pin-shadow.png',
|
|
|
|
wptIconUrls: {
|
|
|
|
'': '/static/pin-icon-wpt.png'
|
|
|
|
}
|
2023-11-26 19:06:43 +00:00
|
|
|
}
|
|
|
|
}).on('loaded', function (e) {
|
2023-11-15 14:24:56 +00:00
|
|
|
map.fitBounds(e.target.getBounds());
|
|
|
|
}).addTo(map);
|
|
|
|
})
|
|
|
|
.catch(error => console.error('Error loading GPX file:', error));
|
|
|
|
}
|
|
|
|
|
2023-12-11 15:12:12 +00:00
|
|
|
var coords = [];
|
|
|
|
|
|
|
|
function addMarker(e) {
|
|
|
|
// remove last marker if any
|
|
|
|
// markers.clearLayers();
|
|
|
|
|
|
|
|
// update circle count
|
|
|
|
circleCount++;
|
|
|
|
coords.push([e.latlng.lat.toFixed(5), e.latlng.lng.toFixed(5)]);
|
|
|
|
|
|
|
|
|
|
|
|
// create a new divIcon
|
|
|
|
var circleIcon = L.divIcon({
|
|
|
|
className: 'circle-icon',
|
|
|
|
html: circleCount,
|
|
|
|
iconSize: [15, 15]
|
|
|
|
});
|
|
|
|
|
|
|
|
// add new marker with custom icon
|
|
|
|
var marker = L.marker(e.latlng, {icon: circleIcon}).addTo(markers);
|
|
|
|
|
|
|
|
// update coordinates display
|
|
|
|
document.getElementById('markers').innerText = coords.join(' ');
|
|
|
|
|
|
|
|
// Create a temporary input to copy the text.
|
|
|
|
var tempInput = document.createElement('input');
|
|
|
|
document.body.appendChild(tempInput);
|
|
|
|
tempInput.value = coords.join(' ');
|
|
|
|
tempInput.select();
|
|
|
|
document.execCommand('copy');
|
|
|
|
document.body.removeChild(tempInput);
|
|
|
|
}
|
2023-12-02 11:48:49 +00:00
|
|
|
|
2023-11-15 14:24:56 +00:00
|
|
|
var gpxData = {{ gpx_ids | tojson }};
|
2023-11-14 20:33:57 +00:00
|
|
|
|
2023-12-10 13:46:54 +00:00
|
|
|
var map = L.map('map',
|
2023-12-11 15:12:12 +00:00
|
|
|
{
|
|
|
|
fullscreenControl: true,
|
|
|
|
}
|
2023-12-10 13:46:54 +00:00
|
|
|
).setView([{{ sar.SARCall.latitude }}, {{ sar.SARCall.longitude }}], 13);
|
2023-12-11 15:13:28 +00:00
|
|
|
|
2023-11-12 20:06:15 +00:00
|
|
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
|
|
|
maxZoom: 19,
|
|
|
|
attribution: '© OpenStreetMap contributors'
|
|
|
|
}).addTo(map);
|
2023-11-19 21:08:19 +00:00
|
|
|
L.marker([{{ sar.SARCall.latitude }}, {{ sar.SARCall.longitude }}]).addTo(map);
|
2023-11-14 20:33:57 +00:00
|
|
|
|
2023-11-30 19:47:54 +00:00
|
|
|
|
2023-11-15 14:24:56 +00:00
|
|
|
gpxData.forEach(function (id) {
|
|
|
|
loadAndDisplayGPX(id);
|
2023-11-14 20:33:57 +00:00
|
|
|
});
|
2023-11-15 14:24:56 +00:00
|
|
|
|
2023-12-10 13:46:54 +00:00
|
|
|
// context menu
|
2023-12-12 20:15:38 +00:00
|
|
|
{% if is_logged_in %}
|
2023-12-10 13:46:54 +00:00
|
|
|
|
2023-12-11 15:12:12 +00:00
|
|
|
var markers = L.layerGroup().addTo(map);
|
|
|
|
var circleCount = 0;
|
|
|
|
|
|
|
|
|
2023-12-10 13:46:54 +00:00
|
|
|
var coordControl = L.control({position: 'bottomright'});
|
|
|
|
|
|
|
|
map.on('contextmenu', function (e) {
|
|
|
|
var coords = e.latlng.lat.toFixed(5) + ", " + e.latlng.lng.toFixed(5);
|
|
|
|
|
2023-12-11 15:12:12 +00:00
|
|
|
|
2023-12-10 13:46:54 +00:00
|
|
|
coordControl.getContainer().innerHTML = "<strong>To clipboard: </strong> " + e.latlng.lat.toFixed(5) + ", " + e.latlng.lng.toFixed(5);
|
2023-12-11 15:12:12 +00:00
|
|
|
|
|
|
|
addMarker(e);
|
2023-12-10 13:46:54 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
2023-11-30 19:47:54 +00:00
|
|
|
// Initialize drawing capabilities
|
|
|
|
var drawnItems = new L.FeatureGroup();
|
|
|
|
map.addLayer(drawnItems);
|
|
|
|
|
|
|
|
var drawControl = new L.Control.Draw({
|
|
|
|
edit: {
|
|
|
|
featureGroup: drawnItems,
|
|
|
|
},
|
|
|
|
draw: {
|
|
|
|
polygon: true,
|
|
|
|
polyline: true,
|
|
|
|
rectangle: false,
|
|
|
|
circle: true,
|
2023-12-11 17:49:44 +00:00
|
|
|
marker: true,
|
2023-11-30 19:47:54 +00:00
|
|
|
},
|
|
|
|
});
|
|
|
|
map.addControl(drawControl);
|
2023-12-12 20:15:38 +00:00
|
|
|
{% endif %}
|
|
|
|
|
2023-11-30 19:47:54 +00:00
|
|
|
|
2023-12-10 13:46:54 +00:00
|
|
|
// Create a control for displaying the coordinates.
|
|
|
|
|
|
|
|
coordControl.onAdd = function (map) {
|
|
|
|
this._container = L.DomUtil.create('div', 'leaflet-control-coordinates');
|
|
|
|
return this._container;
|
|
|
|
}
|
|
|
|
coordControl.addTo(map);
|
|
|
|
|
|
|
|
// Update the control when the mouse is moved.
|
|
|
|
map.on('mousemove', function (e) {
|
|
|
|
coordControl.getContainer().innerHTML = " " + e.latlng.lat.toFixed(5) + ", " + e.latlng.lng.toFixed(5);
|
|
|
|
});
|
|
|
|
|
2023-12-11 15:12:12 +00:00
|
|
|
// remove all markers on left click and reset circle count
|
|
|
|
map.on('click', function () {
|
|
|
|
markers.clearLayers();
|
|
|
|
circleCount = 0;
|
|
|
|
document.getElementById('markers').innerText = "";
|
|
|
|
coords = [];
|
|
|
|
});
|
2023-12-10 13:46:54 +00:00
|
|
|
|
2023-11-30 19:47:54 +00:00
|
|
|
|
|
|
|
map.on('draw:created', function (e) {
|
|
|
|
var layer = e.layer;
|
|
|
|
|
|
|
|
// Add the drawn layer to the map and drawnItems feature group
|
|
|
|
map.addLayer(layer);
|
|
|
|
drawnItems.addLayer(layer);
|
|
|
|
|
|
|
|
// Get the GeoJSON representation of the drawn shape
|
|
|
|
var geoJSON = layer.toGeoJSON();
|
|
|
|
|
|
|
|
// Send the GeoJSON data to your server to save as a comment
|
|
|
|
// You can use AJAX or any method you prefer for this part
|
|
|
|
});
|
|
|
|
|
2023-11-30 20:44:08 +00:00
|
|
|
// Create a custom control for the "Save Track" button
|
|
|
|
var saveTrackControl = L.Control.extend({
|
|
|
|
options: {
|
|
|
|
position: 'bottomleft', // You can adjust the position as needed
|
|
|
|
},
|
|
|
|
|
|
|
|
onAdd: function (map) {
|
|
|
|
// Create a container div for the button
|
|
|
|
var container = L.DomUtil.create('div', 'leaflet-bar leaflet-control');
|
|
|
|
|
|
|
|
// Create the "Save Track" button and add it to the container
|
|
|
|
var button = L.DomUtil.create('a', 'leaflet-control-button', container);
|
|
|
|
button.innerHTML = '💾' //floppy disk icon :)
|
|
|
|
|
|
|
|
// Add a click event handler to the button
|
|
|
|
L.DomEvent.on(button, 'click', function () {
|
|
|
|
// Open your modal dialog for saving the track here
|
|
|
|
$('#saveTrackModal').modal('show');
|
|
|
|
});
|
|
|
|
|
|
|
|
return container;
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
// Add the custom control to your map
|
|
|
|
new saveTrackControl().addTo(map);
|
2023-11-30 19:47:54 +00:00
|
|
|
|
2023-11-12 20:06:15 +00:00
|
|
|
</script>
|
|
|
|
|
|
|
|
|
2023-11-14 10:07:43 +00:00
|
|
|
<script>
|
|
|
|
var commentId; // Declare this outside of the .edit-comment-btn click handler
|
|
|
|
var commentText; // Declare this outside of the .edit-comment-btn click handler
|
|
|
|
$(document).ready(function () {
|
|
|
|
$('.edit-comment-btn').on('click', function () {
|
|
|
|
// Get the comment data
|
|
|
|
commentId = $(this).data('comment-id');
|
|
|
|
commentText = $(this).data('comment-text');
|
|
|
|
|
|
|
|
// Set the comment data in the modal
|
|
|
|
$('#commentText').val(commentText);
|
|
|
|
$('#editCommentModal').modal('show');
|
|
|
|
|
|
|
|
// Save changes
|
|
|
|
$('#saveComment').on('click', function () {
|
|
|
|
$.ajax({
|
|
|
|
url: '/edit_comment/' + commentId,
|
|
|
|
method: 'POST',
|
|
|
|
data: {comment: $('#commentText').val()},
|
|
|
|
success: function (response) {
|
|
|
|
// Update the comment display on the page
|
2023-11-14 20:33:57 +00:00
|
|
|
$('#comment-text-' + commentId).text($('#commentText').val());
|
|
|
|
$('button.edit-comment-btn[data-comment-id="' + commentId + '"]').data('comment-text', $('#commentText').val());
|
2023-11-14 10:07:43 +00:00
|
|
|
$('#editCommentModal').modal('hide');
|
|
|
|
// Update the comment display on the page as needed
|
|
|
|
},
|
|
|
|
error: function () {
|
|
|
|
// Handle error
|
|
|
|
alert("Error updating comment");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
2023-11-14 20:33:57 +00:00
|
|
|
<script>
|
|
|
|
var commentId;
|
|
|
|
|
|
|
|
$('.gpx-upload-button').on('click', function () {
|
|
|
|
var commentId = $(this).data('comment-id');
|
|
|
|
$('#commentIdForGPX').val(commentId);
|
|
|
|
});
|
|
|
|
|
2023-12-09 21:21:44 +00:00
|
|
|
$('#uploadGPXModal').on('hidden.bs.modal', function (e) {
|
|
|
|
// Refresh the parent page (assuming you want to refresh the entire page)
|
|
|
|
console.log("page refresh!!!");
|
|
|
|
location.reload(); // This will refresh the current page
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2023-11-14 20:33:57 +00:00
|
|
|
$(document).ready(function () {
|
|
|
|
{#commentId = $(this).data('comment-id');#}
|
|
|
|
{#console.log(commentId);#}
|
|
|
|
// Handle form submission
|
|
|
|
$('#uploadGPXForm').on('submit', function (e) {
|
|
|
|
e.preventDefault();
|
|
|
|
var formData = new FormData(this);
|
|
|
|
|
|
|
|
$.ajax({
|
|
|
|
url: '/upload_gpx', // Update with the correct route
|
|
|
|
type: 'POST',
|
|
|
|
data: formData,
|
|
|
|
contentType: false,
|
|
|
|
processData: false,
|
|
|
|
success: function (response) {
|
|
|
|
// Handle success - Close modal, Update the map with new GPX data
|
|
|
|
$('#uploadGPXModal').modal('hide');
|
|
|
|
},
|
|
|
|
error: function () {
|
|
|
|
// Handle error
|
|
|
|
alert("Error uploading GPX file");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2023-12-02 10:23:28 +00:00
|
|
|
|
2023-12-09 21:21:44 +00:00
|
|
|
|
2023-11-14 20:33:57 +00:00
|
|
|
</script>
|
|
|
|
|
2023-11-30 19:47:54 +00:00
|
|
|
<script>
|
|
|
|
function getTrackData() {
|
2023-12-02 11:48:49 +00:00
|
|
|
|
|
|
|
var drItems = {
|
|
|
|
"type": "FeatureCollection",
|
|
|
|
"features": []
|
|
|
|
};
|
|
|
|
|
2023-11-30 19:47:54 +00:00
|
|
|
// Assuming you are using a Leaflet.Draw FeatureGroup for drawn items
|
2023-12-02 11:48:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
// Later in your code, when you want to iterate over the features
|
|
|
|
drawnItems.eachLayer(function (layer) {
|
|
|
|
feature = layer.toGeoJSON();
|
|
|
|
|
|
|
|
if (layer instanceof L.Circle) {
|
|
|
|
feature.properties.radius = layer.getRadius();
|
|
|
|
drItems.features.push(feature);
|
2023-12-09 21:21:44 +00:00
|
|
|
} else if (layer instanceof L.CircleMarker) {
|
2023-12-02 11:48:49 +00:00
|
|
|
feature.properties.radius = layer.getRadius();
|
|
|
|
drItems.features.push(feature);
|
2023-12-09 21:21:44 +00:00
|
|
|
} else {
|
2023-12-02 11:48:49 +00:00
|
|
|
drItems.features.push(feature);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-11-30 19:47:54 +00:00
|
|
|
|
|
|
|
// Check if there are any features (tracks) drawn
|
|
|
|
if (drItems.features.length === 0) {
|
|
|
|
return null; // No tracks drawn
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert GeoJSON to GPX format (you can use a library like togeojson or turf.js)
|
|
|
|
var gpxData = geoJSONToGPX(drItems);
|
|
|
|
|
|
|
|
return gpxData;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Function to convert GeoJSON to GPX
|
|
|
|
function geoJSONToGPX(geoJSONData) {
|
2023-12-02 10:23:28 +00:00
|
|
|
|
|
|
|
// Convert each point to a circle polygon
|
|
|
|
let convertedFeatures = geoJSONData.features.map(feature => {
|
|
|
|
console.log(feature);
|
|
|
|
if (feature.geometry.type === 'Point' && feature.properties.radius) {
|
|
|
|
// Convert radius from meters to kilometers for turf.circle
|
|
|
|
let radiusInKm = feature.properties.radius / 1000;
|
|
|
|
|
|
|
|
// Create a circular polygon
|
|
|
|
let circle = turf.circle(feature.geometry.coordinates, radiusInKm);
|
|
|
|
|
|
|
|
// Optional: transfer other properties to the new feature
|
|
|
|
circle.properties = {...feature.properties};
|
|
|
|
|
|
|
|
return circle;
|
|
|
|
}
|
|
|
|
return feature;
|
|
|
|
});
|
|
|
|
|
|
|
|
// Create a new GeoJSON FeatureCollection
|
|
|
|
let convertedGeoJSON = {
|
|
|
|
"type": "FeatureCollection",
|
|
|
|
"features": convertedFeatures
|
|
|
|
};
|
|
|
|
console.log(convertedGeoJSON);
|
2023-12-09 21:21:44 +00:00
|
|
|
// Convert GeoJSON to GPX
|
|
|
|
return togpx(convertedGeoJSON);
|
2023-11-30 19:47:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// JavaScript to handle the confirmation and capture data
|
|
|
|
document.getElementById('confirm-save-track').addEventListener('click', function () {
|
|
|
|
var trackName = document.getElementById('track-name').value;
|
|
|
|
var trackComment = document.getElementById('track-comment').value;
|
|
|
|
var sarID = document.getElementById('sarIdForGPX').value;
|
|
|
|
|
2023-12-02 10:23:28 +00:00
|
|
|
// Get the track data
|
2023-11-30 19:47:54 +00:00
|
|
|
var trackData = getTrackData();
|
|
|
|
|
|
|
|
// Send trackName, trackComment, and trackData to the server
|
|
|
|
$.ajax({
|
|
|
|
url: '/save_track',
|
|
|
|
method: 'POST',
|
|
|
|
data: {
|
|
|
|
track_data: trackData,
|
|
|
|
track_name: trackName,
|
|
|
|
track_comment: trackComment,
|
|
|
|
sar_call_id: sarID,
|
|
|
|
},
|
|
|
|
success: function (response) {
|
|
|
|
// Handle success response
|
|
|
|
alert(response.message);
|
|
|
|
},
|
|
|
|
error: function (error) {
|
|
|
|
// Handle error response
|
|
|
|
alert('An error occurred while saving the track.');
|
|
|
|
}
|
|
|
|
});
|
2023-11-14 20:33:57 +00:00
|
|
|
|
2023-11-30 19:47:54 +00:00
|
|
|
// Close the modal
|
|
|
|
$('#saveTrackModal').modal('hide');
|
|
|
|
});
|
2023-12-02 10:23:28 +00:00
|
|
|
|
|
|
|
$('#saveTrackModal').on('hidden.bs.modal', function (e) {
|
|
|
|
// Refresh the parent page (assuming you want to refresh the entire page)
|
|
|
|
location.reload(); // This will refresh the current page
|
|
|
|
});
|
|
|
|
|
2023-11-30 19:47:54 +00:00
|
|
|
</script>
|
2023-11-14 20:33:57 +00:00
|
|
|
|
|
|
|
|
2023-11-12 20:06:15 +00:00
|
|
|
{% endblock %}
|