.
This commit is contained in:
@@ -47,13 +47,17 @@
|
|||||||
document.body.addEventListener('htmx:afterSwap', function(evt){
|
document.body.addEventListener('htmx:afterSwap', function(evt){
|
||||||
try{
|
try{
|
||||||
const target = evt.detail && evt.detail.target;
|
const target = evt.detail && evt.detail.target;
|
||||||
|
// DEBUG: log HTMX swap target and modal children to help diagnose intermittent swapErrors
|
||||||
|
try{ console.debug('[DEBUG] htmx:afterSwap target=', target && (target.id || target), ' evt.detail=', evt.detail); }catch(e){}
|
||||||
if(!target || target.id !== 'modal') return;
|
if(!target || target.id !== 'modal') return;
|
||||||
const modal = document.getElementById('modal');
|
const modal = document.getElementById('modal');
|
||||||
if(!modal) return;
|
if(!modal) return;
|
||||||
|
|
||||||
// If server returned empty content, hide modal and clear selections
|
// If server returned empty content, hide modal and clear selections
|
||||||
const raw = modal.innerHTML || '';
|
const raw = modal.innerHTML || '';
|
||||||
|
try{ console.debug('[DEBUG] modal.innerHTML length=', raw.length, ' modal.children=', Array.from(modal.children).map(c => c.nodeName + (c.id ? '#'+c.id : '') + (c.className ? '.'+c.className.split(' ').join('.') : ''))); }catch(e){}
|
||||||
if(!raw.trim()){
|
if(!raw.trim()){
|
||||||
|
try{ console.debug('[DEBUG] modal content empty — hiding modal'); }catch(e){}
|
||||||
modal.style.display='none';
|
modal.style.display='none';
|
||||||
try{ if(window.clearAllCalendarSelections) window.clearAllCalendarSelections(); else if(window._calendars) Object.values(window._calendars).forEach(c=>c.clearSelection && c.clearSelection()); }catch(e){}
|
try{ if(window.clearAllCalendarSelections) window.clearAllCalendarSelections(); else if(window._calendars) Object.values(window._calendars).forEach(c=>c.clearSelection && c.clearSelection()); }catch(e){}
|
||||||
return;
|
return;
|
||||||
@@ -81,6 +85,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(contentElem){
|
if(contentElem){
|
||||||
|
try{ console.debug('[DEBUG] tagging existing element as modal-content:', contentElem); }catch(e){}
|
||||||
contentElem.classList.add('modal-content');
|
contentElem.classList.add('modal-content');
|
||||||
} else {
|
} else {
|
||||||
// fallback: if there was no element to mark (unlikely), safely create a wrapper
|
// fallback: if there was no element to mark (unlikely), safely create a wrapper
|
||||||
@@ -98,7 +103,7 @@
|
|||||||
modal.appendChild(wrapper);
|
modal.appendChild(wrapper);
|
||||||
}catch(e){
|
}catch(e){
|
||||||
// If moving nodes fails, log but don't throw — keep modal visible with whatever was returned.
|
// If moving nodes fails, log but don't throw — keep modal visible with whatever was returned.
|
||||||
console.error('modal wrapping fallback failed', e);
|
console.error('[DEBUG] modal wrapping fallback failed', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-29
@@ -266,15 +266,13 @@ def worker_create(request):
|
|||||||
{"rota": rota},
|
{"rota": rota},
|
||||||
request=request,
|
request=request,
|
||||||
)
|
)
|
||||||
resp = (
|
resp = f'<div id="worker-list" hx-swap-oob="true">{worker_list_html}</div>'
|
||||||
f'<div id="worker-list" hx-swap-oob="true">{worker_list_html}</div>'
|
|
||||||
+ '<div id="modal" hx-swap-oob="true"></div>'
|
|
||||||
)
|
|
||||||
response = HttpResponse(resp)
|
response = HttpResponse(resp)
|
||||||
|
# close modal via HX-Trigger to avoid racing OOB swaps that target #modal
|
||||||
response["HX-Trigger"] = "closeModal"
|
response["HX-Trigger"] = "closeModal"
|
||||||
return response
|
return response
|
||||||
# If we couldn't render the worker list (no rota), just close modal
|
# If we couldn't render the worker list (no rota), just close modal via trigger
|
||||||
response = HttpResponse('<div id="modal" hx-swap-oob="true"></div>')
|
response = HttpResponse('')
|
||||||
response["HX-Trigger"] = "closeModal"
|
response["HX-Trigger"] = "closeModal"
|
||||||
return response
|
return response
|
||||||
# Non-HTMX POST -> redirect
|
# Non-HTMX POST -> redirect
|
||||||
@@ -332,10 +330,7 @@ def worker_edit(request, rota_id, worker_id):
|
|||||||
form.save()
|
form.save()
|
||||||
# Return updated worker list OOB and close modal
|
# Return updated worker list OOB and close modal
|
||||||
worker_list_html = render_to_string("rota/partials/worker_list.html", {"rota": rota}, request=request)
|
worker_list_html = render_to_string("rota/partials/worker_list.html", {"rota": rota}, request=request)
|
||||||
resp = (
|
resp = f'<div id="worker-list" hx-swap-oob="true">{worker_list_html}</div>'
|
||||||
f'<div id="worker-list" hx-swap-oob="true">{worker_list_html}</div>'
|
|
||||||
+ '<div id="modal" hx-swap-oob="true"></div>'
|
|
||||||
)
|
|
||||||
response = HttpResponse(resp)
|
response = HttpResponse(resp)
|
||||||
response["HX-Trigger"] = "closeModal"
|
response["HX-Trigger"] = "closeModal"
|
||||||
return response
|
return response
|
||||||
@@ -405,10 +400,7 @@ def worker_delete(request, rota_id, worker_id):
|
|||||||
|
|
||||||
rota = get_object_or_404(RotaSchedule, pk=rota_id)
|
rota = get_object_or_404(RotaSchedule, pk=rota_id)
|
||||||
worker_list_html = render_to_string("rota/partials/worker_list.html", {"rota": rota}, request=request)
|
worker_list_html = render_to_string("rota/partials/worker_list.html", {"rota": rota}, request=request)
|
||||||
resp = (
|
resp = f'<div id="worker-list" hx-swap-oob="true">{worker_list_html}</div>'
|
||||||
f'<div id="worker-list" hx-swap-oob="true">{worker_list_html}</div>'
|
|
||||||
+ '<div id="modal" hx-swap-oob="true"></div>'
|
|
||||||
)
|
|
||||||
response = HttpResponse(resp)
|
response = HttpResponse(resp)
|
||||||
response["HX-Trigger"] = "closeModal"
|
response["HX-Trigger"] = "closeModal"
|
||||||
return response
|
return response
|
||||||
@@ -515,10 +507,7 @@ def request_leave(request, token=None):
|
|||||||
{"leaves": worker.leaves.all(), "token": token},
|
{"leaves": worker.leaves.all(), "token": token},
|
||||||
request=request,
|
request=request,
|
||||||
)
|
)
|
||||||
resp = (
|
resp = f'<div id="leave-list" hx-swap-oob="true">{leave_list_html}</div>'
|
||||||
f'<div id="leave-list" hx-swap-oob="true">{leave_list_html}</div>'
|
|
||||||
+ '<div id="modal" hx-swap-oob="true"></div>'
|
|
||||||
)
|
|
||||||
response = HttpResponse(resp)
|
response = HttpResponse(resp)
|
||||||
# Trigger modal close and a leaveUpdated event so client can refresh calendar highlights
|
# Trigger modal close and a leaveUpdated event so client can refresh calendar highlights
|
||||||
response["HX-Trigger"] = "closeModal,leaveUpdated"
|
response["HX-Trigger"] = "closeModal,leaveUpdated"
|
||||||
@@ -633,7 +622,7 @@ def _oob_update_options_display(request, rota):
|
|||||||
{"rota": rota, "options_pretty": options_pretty},
|
{"rota": rota, "options_pretty": options_pretty},
|
||||||
request=request,
|
request=request,
|
||||||
)
|
)
|
||||||
resp = '<div id="rota-options-display" hx-swap-oob="true">' + options_html + '</div>' + '<div id="modal" hx-swap-oob="true"></div>'
|
resp = '<div id="rota-options-display" hx-swap-oob="true">' + options_html + '</div>'
|
||||||
response = HttpResponse(resp)
|
response = HttpResponse(resp)
|
||||||
response["HX-Trigger"] = "closeModal"
|
response["HX-Trigger"] = "closeModal"
|
||||||
return response
|
return response
|
||||||
@@ -943,11 +932,11 @@ def leaves_json(request, worker_id):
|
|||||||
"""Return JSON list of leave ranges for a given worker."""
|
"""Return JSON list of leave ranges for a given worker."""
|
||||||
worker = get_object_or_404(Worker, pk=worker_id)
|
worker = get_object_or_404(Worker, pk=worker_id)
|
||||||
data = []
|
data = []
|
||||||
for l in worker.leaves.all().order_by('start_date'):
|
for leave in worker.leaves.all().order_by('start_date'):
|
||||||
data.append({
|
data.append({
|
||||||
'start': l.start_date.isoformat(),
|
'start': leave.start_date.isoformat(),
|
||||||
'end': l.end_date.isoformat(),
|
'end': leave.end_date.isoformat(),
|
||||||
'reason': l.reason,
|
'reason': leave.reason,
|
||||||
})
|
})
|
||||||
return JsonResponse({'leaves': data})
|
return JsonResponse({'leaves': data})
|
||||||
|
|
||||||
@@ -1100,8 +1089,7 @@ def shift_add(request, rota_id):
|
|||||||
resp = (
|
resp = (
|
||||||
f'<div id="shift-list" hx-swap-oob="true">{shift_list_html}</div>'
|
f'<div id="shift-list" hx-swap-oob="true">{shift_list_html}</div>'
|
||||||
+ '<div id="shift-form" hx-swap-oob="true"></div>'
|
+ '<div id="shift-form" hx-swap-oob="true"></div>'
|
||||||
+ '<div id="modal" hx-swap-oob="true"></div>'
|
)
|
||||||
)
|
|
||||||
response = HttpResponse(resp)
|
response = HttpResponse(resp)
|
||||||
response["HX-Trigger"] = "closeModal"
|
response["HX-Trigger"] = "closeModal"
|
||||||
return response
|
return response
|
||||||
@@ -1146,8 +1134,7 @@ def shift_edit(request, rota_id, idx):
|
|||||||
resp = (
|
resp = (
|
||||||
f'<div id="shift-list" hx-swap-oob="true">{shift_list_html}</div>'
|
f'<div id="shift-list" hx-swap-oob="true">{shift_list_html}</div>'
|
||||||
+ '<div id="shift-form" hx-swap-oob="true"></div>'
|
+ '<div id="shift-form" hx-swap-oob="true"></div>'
|
||||||
+ '<div id="modal" hx-swap-oob="true"></div>'
|
)
|
||||||
)
|
|
||||||
response = HttpResponse(resp)
|
response = HttpResponse(resp)
|
||||||
response["HX-Trigger"] = "closeModal"
|
response["HX-Trigger"] = "closeModal"
|
||||||
return response
|
return response
|
||||||
@@ -1191,8 +1178,7 @@ def shift_delete(request, rota_id, idx):
|
|||||||
resp = (
|
resp = (
|
||||||
f'<div id="shift-list" hx-swap-oob="true">{shift_list_html}</div>'
|
f'<div id="shift-list" hx-swap-oob="true">{shift_list_html}</div>'
|
||||||
+ '<div id="shift-form" hx-swap-oob="true"></div>'
|
+ '<div id="shift-form" hx-swap-oob="true"></div>'
|
||||||
+ '<div id="modal" hx-swap-oob="true"></div>'
|
)
|
||||||
)
|
|
||||||
response = HttpResponse(resp)
|
response = HttpResponse(resp)
|
||||||
response["HX-Trigger"] = "closeModal"
|
response["HX-Trigger"] = "closeModal"
|
||||||
return response
|
return response
|
||||||
|
|||||||
Reference in New Issue
Block a user