1export class ModalService { 2 static createModal({ title, content, onClose }) { 3 const overlay = document.createElement('div'); 4 overlay.id = 'modalOverlay'; 5 overlay.className = 'modal-overlay'; 6 7 const modal = document.createElement('div'); 8 modal.className = 'preset-modal'; 9 10 const header = document.createElement('div'); 11 header.className = 'modal-header'; 12 13 const titleElement = document.createElement('h2'); 14 titleElement.textContent = title; 15 16 const closeButton = document.createElement('button'); 17 closeButton.className = 'close-modal'; 18 closeButton.innerHTML = '×'; 19 closeButton.onclick = () => { 20 this.closeModal(overlay); 21 if (onClose) onClose(); 22 }; 23 24 header.appendChild(titleElement); 25 header.appendChild(closeButton); 26 27 const contentContainer = document.createElement('div'); 28 contentContainer.className = 'modal-content'; 29 30 if (typeof content === 'string') { 31 contentContainer.innerHTML = content; 32 } else if (content instanceof Element) { 33 contentContainer.appendChild(content); 34 } 35 36 modal.appendChild(header); 37 modal.appendChild(contentContainer); 38 overlay.appendChild(modal); 39 40 // Close on overlay click 41 overlay.addEventListener('click', (e) => { 42 if (e.target === overlay) { 43 this.closeModal(overlay); 44 if (onClose) onClose(); 45 } 46 }); 47 48 // Close on escape key 49 document.addEventListener('keydown', (e) => { 50 if (e.key === 'Escape') { 51 this.closeModal(overlay); 52 if (onClose) onClose(); 53 } 54 }); 55 56 return overlay; 57 } 58 59 static showModal(options) { 60 const modal = this.createModal(options); 61 document.body.appendChild(modal); 62 return modal; 63 } 64 65 static closeModal(modal) { 66 if (modal && modal.parentElement) { 67 modal.parentElement.removeChild(modal); 68 } 69 } 70 71 static showError(message, duration = 5000) {
72 const errorModal = this.createModal({ 73 title: 'Error', 74 content: `<div class="error-message">${message}</div>` 75 }); 76 77 document.body.appendChild(errorModal); 78 79 if (duration > 0) { 80 setTimeout(() => this.closeModal(errorModal), duration); 81 } 82 83 return errorModal; 84 } 85 86 static showSuccess(message, duration = 3000) { 87 const successModal = this.createModal({ 88 title: 'Success', 89 content: `<div class="success-message">${message}</div>` 90 }); 91 92 document.body.appendChild(successModal); 93 94 if (duration > 0) { 95 setTimeout(() => this.closeModal(successModal), duration); 96 } 97 98 return successModal; 99 } 100 101 static showConfirm({ title, message, onConfirm, onCancel }) { 102 const content = document.createElement('div'); 103 content.className = 'confirm-dialog'; 104 content.innerHTML = ` 105 <p>${message}</p> 106 <div class="confirm-actions"> 107 <button class="btn-confirm">Confirm</button> 108 <button class="btn-cancel">Cancel</button> 109 </div> 110 `; 111 112 const modal = this.showModal({ 113 title, 114 content, 115 onClose: onCancel 116 }); 117 118 content.querySelector('.btn-confirm').onclick = () => { 119 this.closeModal(modal); 120 if (onConfirm) onConfirm(); 121 }; 122 123 content.querySelector('.btn-cancel').onclick = () => { 124 this.closeModal(modal); 125 if (onCancel) onCancel(); 126 }; 127 128 return modal; 129 } 130}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.