| 1429 | |
| 1430 | // ---- Create dropdown + its two modals ---- |
| 1431 | function wireCreateDropdown() { |
| 1432 | const container = document.getElementById('createDropdown'); |
| 1433 | const btn = document.getElementById('createBtn'); |
| 1434 | const menu = document.getElementById('createMenu'); |
| 1435 | const makeF = document.getElementById('createFileOption'); |
| 1436 | const makeD = document.getElementById('createFolderOption'); |
| 1437 | if (!container || !btn || !menu) return; |
| 1438 | |
| 1439 | // Ensure layout basics |
| 1440 | if (getComputedStyle(container).position === 'static') container.style.position = 'relative'; |
| 1441 | btn.style.pointerEvents = 'auto'; |
| 1442 | menu.style.pointerEvents = 'auto'; |
| 1443 | menu.style.zIndex = '10010'; |
| 1444 | |
| 1445 | // Show/hide button based on live auth flags |
| 1446 | const st = (window.__FR_AUTH_STATE || {}); |
| 1447 | const readOnly = !!st.readOnly || (localStorage.getItem('readOnly') === 'true' || localStorage.getItem('readOnly') === '1'); |
| 1448 | const disableUpload = !!st.disableUpload || (localStorage.getItem('disableUpload') === 'true' || localStorage.getItem('disableUpload') === '1'); |
| 1449 | btn.style.display = (!readOnly && !disableUpload) ? 'inline-flex' : 'none'; |
| 1450 | |
| 1451 | let justToggledAt = 0; |
| 1452 | |
| 1453 | function openMenu() { |
| 1454 | // Beat any CSS with !important |
| 1455 | menu.style.setProperty('display', 'block', 'important'); |
| 1456 | btn.setAttribute('aria-expanded', 'true'); |
| 1457 | justToggledAt = Date.now(); |
| 1458 | } |
| 1459 | function closeMenu() { |
| 1460 | menu.style.setProperty('display', 'none', 'important'); |
| 1461 | btn.setAttribute('aria-expanded', 'false'); |
| 1462 | } |
| 1463 | function isOpen() { |
| 1464 | return getComputedStyle(menu).display !== 'none'; |
| 1465 | } |
| 1466 | |
| 1467 | if (!btn.__bound) { |
| 1468 | btn.__bound = true; |
| 1469 | btn.addEventListener('click', (e) => { |
| 1470 | e.preventDefault(); |
| 1471 | e.stopPropagation(); // block bubble-phase global closers |
| 1472 | if (isOpen()) closeMenu(); else openMenu(); |
| 1473 | }, true); // use capture so we run before bubble-phase closers |
| 1474 | } |
| 1475 | |
| 1476 | // Close only when clicking truly outside our container. |
| 1477 | // Use capture and ignore the click that immediately follows our open() call. |
| 1478 | if (!menu.__outside) { |
| 1479 | menu.__outside = true; |
| 1480 | document.addEventListener('click', (e) => { |
| 1481 | // ignore the same-tick/rapid click that opened the menu |
| 1482 | if (Date.now() - justToggledAt < 120) return; |
| 1483 | if (!container.contains(e.target)) closeMenu(); |
| 1484 | }, true); // capture to pre-empt other handlers |
| 1485 | } |
| 1486 | |
| 1487 | if (!menu.__esc) { |
| 1488 | menu.__esc = true; |