()
| 1598 | modal.onclick = (e) => { if (e.target === modal) this.cleanup(); }; |
| 1599 | |
| 1600 | // Auto-focus input when typing anywhere in the modal (while form is visible) |
| 1601 | modal.addEventListener('keydown', (e) => { |
| 1602 | if (formSection.classList.contains('hidden')) return; |
| 1603 | if (e.key === 'Escape' || e.key === 'Enter' || e.key === 'Tab') return; |
| 1604 | if (e.metaKey || e.ctrlKey || e.altKey) return; |
| 1605 | |
| 1606 | const activeEl = document.activeElement; |
| 1607 | const isInputFocused = activeEl && (activeEl.tagName === 'INPUT' || activeEl.tagName === 'TEXTAREA'); |
| 1608 | if (isInputFocused) return; |
| 1609 | |
| 1610 | // Focus the appropriate input for typing |
| 1611 | if (currentMode === 'pin') { |
| 1612 | pinInput?.focus(); |
| 1613 | } else { |
| 1614 | passwordInput?.focus(); |
| 1615 | } |
| 1616 | }); |
| 1617 | |
| 1618 | // Escape key closes modal |
| 1619 | const handleEscape = (e) => { if (e.key === 'Escape') this.cleanup(); }; |
| 1620 | document.addEventListener('keydown', handleEscape); |
| 1621 | this._escapeHandler = handleEscape; |
| 1622 | |
| 1623 | // Submit handler |
| 1624 | const handleSubmit = async () => { |
| 1625 | const pinValue = pinInput?.value || ''; |
| 1626 | const passwordValue = passwordInput?.value || ''; |
| 1627 | |
| 1628 | // Validate PIN: must be empty (no encryption) or exactly 6 characters |
| 1629 | if (currentMode === 'pin' && pinValue.length > 0 && pinValue.length < 6) { |
| 1630 | // Shake the PIN boxes to indicate error |
| 1631 | const pinBoxes = modal.querySelector('.pin-boxes'); |
| 1632 | if (pinBoxes) { |
| 1633 | pinBoxes.classList.add('shake'); |
| 1634 | setTimeout(() => pinBoxes.classList.remove('shake'), 500); |
| 1635 | } |
| 1636 | pinInput?.focus(); |
| 1637 | return; |
| 1638 | } |
| 1639 | |
| 1640 | const ttlSeconds = getTtlSeconds(); |
| 1641 | if (ttlSeconds === null) return; // invalid custom expiry is shown inline |
| 1642 | |
| 1643 | const password = currentMode === 'pin' |
| 1644 | ? (pinValue || null) |
| 1645 | : (passwordValue || null); |
| 1646 | |
| 1647 | const settings = { |
| 1648 | password, |
| 1649 | ttlSeconds, |
| 1650 | shareApiKeyMetadata: apiMetadataCheckbox?.checked || false |
| 1651 | }; |
| 1652 | |
| 1653 | // Show loading state |
| 1654 | const submitBtn = modal.querySelector('#submit-btn'); |
| 1655 | if (submitBtn) { |
| 1656 | submitBtn.disabled = true; |
| 1657 | submitBtn.textContent = 'Sharing...'; |
nothing calls this directly
no test coverage detected