.
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user