export default class DialogBox { constructor() { this.dialog = null; this.isDragging = false; this.dragOffset = { x: 0, y: 0 }; this._isEdit = false; this._existingNote = null; this._highlightElement = null; this._onSave = null; this._onCancel = null; this._onDelete = null; this._timestamp = null; } show( selectionRect, isEdit = false, existingNote = null, onSave, onCancel, onDelete, highlightElement = null, timestamp ) { this._removeExistingDialog(); this._isEdit = isEdit; this._existingNote = existingNote; this._highlightElement = highlightElement; this._onSave = onSave; this._onCancel = onCancel; this._onDelete = onDelete; this._timestamp = timestamp; const dialog = document.createElement("div"); dialog.id = "dialog"; dialog.className = "dialog"; this._positionDialog(dialog, selectionRect); const titleBar = this._createTitleBar(); const textarea = this._createTextArea(); dialog.appendChild(titleBar); dialog.appendChild(textarea); document.body.appendChild(dialog); this.dialog = dialog; textarea.focus(); } handleOutsideClick(event) { if (this._isClickOutside(event.target)) { this._processCloseAction(); } } _positionDialog(dialog, selectionRect) { const scrollX = window.scrollX; const scrollY = window.scrollY; dialog.style.left = `${selectionRect.left + scrollX}px`; dialog.style.top = `${selectionRect.bottom + scrollY + 10}px`; } _createTitleBar() { const titleBar = document.createElement("div"); titleBar.className = "dialogTitleBar"; const displayTimestamp = this._formatTimestamp( this._isEdit && this._existingNote ? this._existingNote.timestamp : this._timestamp ); const timestampElement = document.createElement("span"); timestampElement.className = "dialogTimestamp"; timestampElement.textContent = displayTimestamp; const closeButton = document.createElement("span"); closeButton.className = "dialogCloseButton"; closeButton.textContent = "×"; closeButton.addEventListener("click", () => { this._processCloseAction(); }); titleBar.appendChild(timestampElement); titleBar.appendChild(closeButton); this._setupDragHandlers(titleBar); return titleBar; } _createTextArea() { const textarea = document.createElement("textarea"); textarea.placeholder = "Add your note..."; textarea.rows = 3; textarea.className = "dialogTextarea"; if (this._isEdit && this._existingNote) { textarea.value = this._existingNote.note; } textarea.addEventListener("keydown", (event) => { if (event.key === "Escape") { this._processCloseAction(); } }); return textarea; } _processCloseAction() { const noteText = this._getTextContent().trim(); if (noteText === "") { this._onDelete(); } else { this._onSave(noteText); } this._removeExistingDialog(); } _setupDragHandlers(titleBar) { titleBar.style.cursor = "move"; titleBar.addEventListener("mousedown", (e) => { if (e.button === 0 && !e.target.classList.contains("dialogCloseButton")) { this.isDragging = true; const rect = this.dialog.getBoundingClientRect(); this.dragOffset = { x: e.clientX - rect.left, y: e.clientY - rect.top, }; e.preventDefault(); } }); document.addEventListener("mousemove", (e) => { if (this.isDragging) { const x = e.clientX - this.dragOffset.x; const y = e.clientY - this.dragOffset.y; this.dialog.style.left = `${x}px`; this.dialog.style.top = `${y}px`; } }); document.addEventListener("mouseup", () => { this.isDragging = false; }); } _removeExistingDialog() { if (this.dialog) { this.dialog.remove(); this.dialog = null; } } _isClickOutside(target) { return this.dialog && !this.dialog.contains(target); } _getTextContent() { const textarea = this.dialog?.querySelector(".dialogTextarea"); return textarea ? textarea.value : ""; } _formatTimestamp(date) { const formatDate = new Intl.DateTimeFormat("en", { day: "2-digit", month: "short", year: "numeric", hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false, }); const parts = formatDate.formatToParts(date); return `${parts.find((part) => part.type === "year").value}-${ parts.find((part) => part.type === "month").value }-${parts.find((part) => part.type === "day").value} ${ parts.find((part) => part.type === "hour").value }:${parts.find((part) => part.type === "minute").value}:${ parts.find((part) => part.type === "second").value }`; } }