mirror of
https://github.com/MarekWo/mc-webui.git
synced 2026-03-28 17:42:45 +01:00
refactor(paths): move Add Path form into its own modal
The path creation form is now a separate modal (z-index 1070) that opens above Contact Info with its own backdrop, making the UI layers clearly distinguishable. Map picker modal bumped to z-index 1080 so it stacks correctly above both Contact Info and Add Path modals. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1807,34 +1807,36 @@ async function movePathItem(pubkey, paths, currentIndex, direction) {
|
||||
*/
|
||||
function setupPathFormHandlers(pubkey) {
|
||||
const addBtn = document.getElementById('dmAddPathBtn');
|
||||
const form = document.getElementById('dmAddPathForm');
|
||||
const cancelBtn = document.getElementById('dmCancelPathBtn');
|
||||
const saveBtn = document.getElementById('dmSavePathBtn');
|
||||
const pickBtn = document.getElementById('dmPickRepeaterBtn');
|
||||
const picker = document.getElementById('dmRepeaterPicker');
|
||||
const resetFloodBtn = document.getElementById('dmResetFloodBtn');
|
||||
const addPathModalEl = document.getElementById('addPathModal');
|
||||
|
||||
if (!addBtn || !form) return;
|
||||
if (!addBtn || !addPathModalEl) return;
|
||||
|
||||
// Remove old listeners by cloning
|
||||
const addPathModal = new bootstrap.Modal(addPathModalEl);
|
||||
|
||||
// "+" button opens the Add Path modal
|
||||
const newAddBtn = addBtn.cloneNode(true);
|
||||
addBtn.parentNode.replaceChild(newAddBtn, addBtn);
|
||||
newAddBtn.addEventListener('click', () => {
|
||||
form.style.display = '';
|
||||
newAddBtn.style.display = 'none';
|
||||
document.getElementById('dmPathHexInput').value = '';
|
||||
document.getElementById('dmPathLabelInput').value = '';
|
||||
document.getElementById('dmPathUniquenessWarning').style.display = 'none';
|
||||
if (picker) picker.style.display = 'none';
|
||||
addPathModal.show();
|
||||
});
|
||||
|
||||
const newCancelBtn = cancelBtn.cloneNode(true);
|
||||
cancelBtn.parentNode.replaceChild(newCancelBtn, cancelBtn);
|
||||
newCancelBtn.addEventListener('click', () => {
|
||||
form.style.display = 'none';
|
||||
newAddBtn.style.display = '';
|
||||
// Raise backdrop when Add Path modal opens (above Contact Info)
|
||||
addPathModalEl.addEventListener('shown.bs.modal', () => {
|
||||
const backdrops = document.querySelectorAll('.modal-backdrop');
|
||||
if (backdrops.length > 1) {
|
||||
backdrops[backdrops.length - 1].style.zIndex = '1060';
|
||||
}
|
||||
});
|
||||
|
||||
// Save button
|
||||
const newSaveBtn = saveBtn.cloneNode(true);
|
||||
saveBtn.parentNode.replaceChild(newSaveBtn, saveBtn);
|
||||
newSaveBtn.addEventListener('click', async () => {
|
||||
@@ -1855,8 +1857,7 @@ function setupPathFormHandlers(pubkey) {
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data.success) {
|
||||
form.style.display = 'none';
|
||||
newAddBtn.style.display = '';
|
||||
addPathModal.hide();
|
||||
await renderPathList(pubkey);
|
||||
showNotification('Path added', 'info');
|
||||
} else {
|
||||
@@ -2069,10 +2070,10 @@ function openRepeaterMapPicker() {
|
||||
const modal = new bootstrap.Modal(modalEl);
|
||||
|
||||
const onShown = async function () {
|
||||
// Raise backdrop z-index so it covers the Contact Info modal behind
|
||||
// Raise backdrop z-index so it covers modals behind (Contact Info + Add Path)
|
||||
const backdrops = document.querySelectorAll('.modal-backdrop');
|
||||
if (backdrops.length > 1) {
|
||||
backdrops[backdrops.length - 1].style.zIndex = '1060';
|
||||
if (backdrops.length > 0) {
|
||||
backdrops[backdrops.length - 1].style.zIndex = '1075';
|
||||
}
|
||||
|
||||
// Init map once
|
||||
|
||||
@@ -327,59 +327,6 @@
|
||||
</button>
|
||||
</div>
|
||||
<div id="dmPathList"></div>
|
||||
<!-- Add Path form (hidden by default) -->
|
||||
<div id="dmAddPathForm" style="display: none;" class="border rounded p-2 mb-2">
|
||||
<div class="mb-2">
|
||||
<label class="form-label small mb-1">Hash Size</label>
|
||||
<div class="btn-group btn-group-sm w-100" role="group">
|
||||
<input type="radio" class="btn-check" name="pathHashSize" id="pathHash1" value="1" checked>
|
||||
<label class="btn btn-outline-secondary" for="pathHash1">1B (max 64)</label>
|
||||
<input type="radio" class="btn-check" name="pathHashSize" id="pathHash2" value="2">
|
||||
<label class="btn btn-outline-secondary" for="pathHash2">2B (max 32)</label>
|
||||
<input type="radio" class="btn-check" name="pathHashSize" id="pathHash3" value="3">
|
||||
<label class="btn btn-outline-secondary" for="pathHash3">3B (max 21)</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label class="form-label small mb-1">Path (hex)</label>
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="text" class="form-control font-monospace" id="dmPathHexInput"
|
||||
placeholder="e.g. 5e,e7 or 5e34,e761" autocomplete="off">
|
||||
<button type="button" class="btn btn-outline-secondary" id="dmPickRepeaterBtn"
|
||||
title="Pick repeater from list">
|
||||
<i class="bi bi-plus-circle"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" id="dmPickRepeaterMapBtn"
|
||||
title="Pick repeater from map">
|
||||
<i class="bi bi-geo-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="dmPathUniquenessWarning" class="path-uniqueness-warning mt-1" style="display: none;"></div>
|
||||
</div>
|
||||
<!-- Repeater picker (hidden by default) -->
|
||||
<div id="dmRepeaterPicker" style="display: none;" class="border rounded mb-2">
|
||||
<div class="d-flex border-bottom">
|
||||
<div class="btn-group btn-group-sm flex-shrink-0" role="group">
|
||||
<input type="radio" class="btn-check" name="repeaterSearchMode" id="rptSearchName" value="name" checked>
|
||||
<label class="btn btn-outline-secondary border-0 rounded-0" for="rptSearchName">Name</label>
|
||||
<input type="radio" class="btn-check" name="repeaterSearchMode" id="rptSearchId" value="id">
|
||||
<label class="btn btn-outline-secondary border-0 rounded-0" for="rptSearchId">ID</label>
|
||||
</div>
|
||||
<input type="text" class="form-control form-control-sm border-0"
|
||||
id="dmRepeaterSearch" placeholder="Search by name..." autocomplete="off">
|
||||
</div>
|
||||
<div id="dmRepeaterList" style="max-height: 180px; overflow-y: auto;"></div>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label class="form-label small mb-1">Label (optional)</label>
|
||||
<input type="text" class="form-control form-control-sm" id="dmPathLabelInput"
|
||||
placeholder="e.g. via Mountain RPT" maxlength="50">
|
||||
</div>
|
||||
<div class="d-flex justify-content-end gap-2">
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="dmCancelPathBtn">Cancel</button>
|
||||
<button type="button" class="btn btn-sm btn-primary" id="dmSavePathBtn">Add Path</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Reset to FLOOD button -->
|
||||
<div class="text-end mt-1">
|
||||
<button type="button" class="btn btn-outline-danger btn-sm" id="dmResetFloodBtn"
|
||||
@@ -408,7 +355,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Repeater Map Picker Modal -->
|
||||
<div class="modal fade" id="repeaterMapModal" tabindex="-1" style="z-index: 1070;">
|
||||
<div class="modal fade" id="repeaterMapModal" tabindex="-1" style="z-index: 1080;">
|
||||
<div class="modal-dialog modal-lg modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header py-2">
|
||||
@@ -434,6 +381,70 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add Path Modal -->
|
||||
<div class="modal fade" id="addPathModal" tabindex="-1" style="z-index: 1070;">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header py-2">
|
||||
<h6 class="modal-title"><i class="bi bi-signpost-split"></i> Add Path</h6>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="dmAddPathForm">
|
||||
<div class="mb-2">
|
||||
<label class="form-label small mb-1">Hash Size</label>
|
||||
<div class="btn-group btn-group-sm w-100" role="group">
|
||||
<input type="radio" class="btn-check" name="pathHashSize" id="pathHash1" value="1" checked>
|
||||
<label class="btn btn-outline-secondary" for="pathHash1">1B (max 64)</label>
|
||||
<input type="radio" class="btn-check" name="pathHashSize" id="pathHash2" value="2">
|
||||
<label class="btn btn-outline-secondary" for="pathHash2">2B (max 32)</label>
|
||||
<input type="radio" class="btn-check" name="pathHashSize" id="pathHash3" value="3">
|
||||
<label class="btn btn-outline-secondary" for="pathHash3">3B (max 21)</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label class="form-label small mb-1">Path (hex)</label>
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="text" class="form-control font-monospace" id="dmPathHexInput"
|
||||
placeholder="e.g. 5e,e7 or 5e34,e761" autocomplete="off">
|
||||
<button type="button" class="btn btn-outline-secondary" id="dmPickRepeaterBtn"
|
||||
title="Pick repeater from list">
|
||||
<i class="bi bi-plus-circle"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" id="dmPickRepeaterMapBtn"
|
||||
title="Pick repeater from map">
|
||||
<i class="bi bi-geo-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="dmPathUniquenessWarning" class="path-uniqueness-warning mt-1" style="display: none;"></div>
|
||||
</div>
|
||||
<!-- Repeater picker (hidden by default) -->
|
||||
<div id="dmRepeaterPicker" style="display: none;" class="border rounded mb-2">
|
||||
<div class="d-flex border-bottom">
|
||||
<div class="btn-group btn-group-sm flex-shrink-0" role="group">
|
||||
<input type="radio" class="btn-check" name="repeaterSearchMode" id="rptSearchName" value="name" checked>
|
||||
<label class="btn btn-outline-secondary border-0 rounded-0" for="rptSearchName">Name</label>
|
||||
<input type="radio" class="btn-check" name="repeaterSearchMode" id="rptSearchId" value="id">
|
||||
<label class="btn btn-outline-secondary border-0 rounded-0" for="rptSearchId">ID</label>
|
||||
</div>
|
||||
<input type="text" class="form-control form-control-sm border-0"
|
||||
id="dmRepeaterSearch" placeholder="Search by name..." autocomplete="off">
|
||||
</div>
|
||||
<div id="dmRepeaterList" style="max-height: 180px; overflow-y: auto;"></div>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label class="form-label small mb-1">Label (optional)</label>
|
||||
<input type="text" class="form-control form-control-sm" id="dmPathLabelInput"
|
||||
placeholder="e.g. via Mountain RPT" maxlength="50">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer py-2">
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="dmCancelPathBtn" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-sm btn-primary" id="dmSavePathBtn">Add Path</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast container for notifications -->
|
||||
<div class="toast-container position-fixed top-0 start-0 p-3">
|
||||
<div id="notificationToast" class="toast" role="alert">
|
||||
|
||||
Reference in New Issue
Block a user