This commit is contained in:
Ross
2025-12-14 17:16:59 +00:00
parent c43ff7fc73
commit 5165fe78bd
+61 -19
View File
@@ -40,28 +40,70 @@
#modal .modal-content { position:relative; background:white; padding:1rem; border-radius:6px; box-shadow:0 6px 24px rgba(0,0,0,0.2); max-width:90%; max-height:90%; overflow:auto; z-index:2 }
</style>
<script>
// Show modal when HTMX swaps content into #modal, and provide backdrop/close behavior
// Show modal when HTMX swaps content into #modal, and provide backdrop/close behavior.
// Important: avoid destructive DOM moves (innerHTML replacement) while HTMX may still hold
// references to nodes. Instead, add a backdrop and tag the first returned element as
// the modal content to minimize structural changes and avoid racing HTMX internals.
document.body.addEventListener('htmx:afterSwap', function(evt){
try{
const target = evt.detail.target;
if(target && target.id === 'modal'){
const modal = document.getElementById('modal');
// If server returned empty content, hide modal
if(!modal.innerHTML.trim()){ modal.style.display='none';
// clear calendar selections on modal close
try{ if(window.clearAllCalendarSelections) window.clearAllCalendarSelections(); else if(window._calendars) Object.values(window._calendars).forEach(c=>c.clearSelection && c.clearSelection()); }catch(e){}
return; }
// wrap content if needed
if(!modal.querySelector('.modal-backdrop')){
const backdrop = document.createElement('div'); backdrop.className='modal-backdrop';
const content = document.createElement('div'); content.className='modal-content';
// move existing children into content
while(modal.firstChild){ content.appendChild(modal.firstChild); }
modal.appendChild(backdrop);
modal.appendChild(content);
}
modal.style.display = 'flex';
const target = evt.detail && evt.detail.target;
if(!target || target.id !== 'modal') return;
const modal = document.getElementById('modal');
if(!modal) return;
// If server returned empty content, hide modal and clear selections
const raw = modal.innerHTML || '';
if(!raw.trim()){
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){}
return;
}
// If no element with .modal-content exists, try a non-destructive approach:
// 1) ensure a backdrop element exists (insert if missing)
// 2) find the first returned element (excluding backdrop) and mark it as modal-content
if(!modal.querySelector('.modal-content')){
if(!modal.querySelector('.modal-backdrop')){
const backdrop = document.createElement('div');
backdrop.className = 'modal-backdrop';
// insert backdrop as first child to sit behind content
modal.insertBefore(backdrop, modal.firstChild);
}
// choose an existing child element to be the content. Prefer the first element
// that isn't the backdrop. Do not recreate nodes if possible — just add a class.
let contentElem = null;
for(const child of Array.from(modal.children)){
if(child.classList && child.classList.contains('modal-backdrop')) continue;
if(child.classList && child.classList.contains('modal-content')){ contentElem = child; break; }
// skip empty text nodes
if(child.nodeType === Node.ELEMENT_NODE){ contentElem = child; break; }
}
if(contentElem){
contentElem.classList.add('modal-content');
} else {
// fallback: if there was no element to mark (unlikely), safely create a wrapper
// and move other nodes inside it. This is a last-resort path guarded in try/catch.
try{
const wrapper = document.createElement('div');
wrapper.className = 'modal-content';
// move existing children into wrapper
while(modal.firstChild){
wrapper.appendChild(modal.firstChild);
}
// ensure backdrop is first child
const backdrop = document.createElement('div'); backdrop.className='modal-backdrop';
modal.appendChild(backdrop);
modal.appendChild(wrapper);
}catch(e){
// If moving nodes fails, log but don't throw — keep modal visible with whatever was returned.
console.error('modal wrapping fallback failed', e);
}
}
}
modal.style.display = 'flex';
}catch(e){ console.error('modal afterSwap handler error', e); }
});
// Helper to close the app modal and clear calendar selections