import { USER_NOTES_MODULE_ID, USER_NOTES_WINDOW_ID, USER_NOTES_DEFAULT_POSITION, USER_NOTES_MIN_WIDTH, USER_NOTES_MIN_HEIGHT, USER_NOTES_VIEWPORT_MARGIN } from "./user-notes-constants.js"; import { userNotesLoadNotes, userNotesSaveNotes, userNotesPositionKey, userNotesRemoveSavedPosition } from "./user-notes-storage.js"; import { userNotesApplyWindowSettings } from "./user-notes-settings.js"; let userNotesSaveTimer = null; export function userNotesSetStatus(text) { const status = document.querySelector( `#${USER_NOTES_WINDOW_ID} .user-notes-status` ); if (status) { status.textContent = text; } } export function userNotesDebouncedSave(value) { window.clearTimeout(userNotesSaveTimer); userNotesSetStatus("Ungespeichert …"); userNotesSaveTimer = window.setTimeout(() => { userNotesSaveNotes(value); userNotesSetStatus("Gespeichert"); }, 250); } export function userNotesApplyPosition(win, position) { win.style.left = `${position.left}px`; win.style.top = `${position.top}px`; win.style.width = `${position.width}px`; win.style.height = `${position.height}px`; } export function userNotesClampPosition(position) { const viewportWidth = Math.max( window.innerWidth, USER_NOTES_MIN_WIDTH + USER_NOTES_VIEWPORT_MARGIN ); const viewportHeight = Math.max( window.innerHeight, USER_NOTES_MIN_HEIGHT + USER_NOTES_VIEWPORT_MARGIN ); const maxWidth = Math.max( USER_NOTES_MIN_WIDTH, viewportWidth - USER_NOTES_VIEWPORT_MARGIN ); const maxHeight = Math.max( USER_NOTES_MIN_HEIGHT, viewportHeight - USER_NOTES_VIEWPORT_MARGIN ); const width = Math.max( USER_NOTES_MIN_WIDTH, Math.min(position.width, maxWidth) ); const height = Math.max( USER_NOTES_MIN_HEIGHT, Math.min(position.height, maxHeight) ); const maxLeft = Math.max(0, viewportWidth - width - 20); const maxTop = Math.max(0, viewportHeight - height - 20); const left = Math.max(0, Math.min(position.left, maxLeft)); const top = Math.max(0, Math.min(position.top, maxTop)); return { left, top, width, height }; } export function userNotesRestorePosition(win) { try { const raw = window.localStorage.getItem(userNotesPositionKey()); if (!raw) { userNotesApplyPosition( win, userNotesClampPosition(USER_NOTES_DEFAULT_POSITION) ); return; } const pos = JSON.parse(raw); const restoredPosition = { left: Number.isFinite(pos.left) ? pos.left : USER_NOTES_DEFAULT_POSITION.left, top: Number.isFinite(pos.top) ? pos.top : USER_NOTES_DEFAULT_POSITION.top, width: Number.isFinite(pos.width) ? pos.width : USER_NOTES_DEFAULT_POSITION.width, height: Number.isFinite(pos.height) ? pos.height : USER_NOTES_DEFAULT_POSITION.height }; userNotesApplyPosition( win, userNotesClampPosition(restoredPosition) ); } catch (err) { console.warn( `${USER_NOTES_MODULE_ID} | Could not restore note window position`, err ); userNotesApplyPosition( win, userNotesClampPosition(USER_NOTES_DEFAULT_POSITION) ); } } export function userNotesSavePosition(win) { if (!win || win.hidden) { return; } const rect = win.getBoundingClientRect(); if (rect.width < USER_NOTES_MIN_WIDTH || rect.height < USER_NOTES_MIN_HEIGHT) { return; } const position = userNotesClampPosition({ left: Math.round(rect.left), top: Math.round(rect.top), width: Math.round(rect.width), height: Math.round(rect.height) }); window.localStorage.setItem( userNotesPositionKey(), JSON.stringify(position) ); } export function userNotesResetPositionAndSize() { userNotesRemoveSavedPosition(); const win = document.getElementById(USER_NOTES_WINDOW_ID); if (win) { userNotesApplyPosition( win, userNotesClampPosition(USER_NOTES_DEFAULT_POSITION) ); userNotesSavePosition(win); } } export function userNotesBringToFront(win) { const currentTop = Number.parseInt(win.style.zIndex || "100000", 10); win.style.zIndex = String(Math.max(currentTop + 1, 100000)); } export function userNotesMakeDraggable(win) { const handle = win.querySelector(".user-notes-titlebar"); if (!handle) { return; } let drag = null; handle.addEventListener("pointerdown", event => { const target = event.target; if (target instanceof HTMLElement && target.closest("button")) { return; } const rect = win.getBoundingClientRect(); drag = { pointerId: event.pointerId, startX: event.clientX, startY: event.clientY, left: rect.left, top: rect.top }; userNotesBringToFront(win); handle.setPointerCapture(event.pointerId); }); handle.addEventListener("pointermove", event => { if (!drag || drag.pointerId !== event.pointerId) { return; } const rect = win.getBoundingClientRect(); const clamped = userNotesClampPosition({ left: drag.left + event.clientX - drag.startX, top: drag.top + event.clientY - drag.startY, width: rect.width, height: rect.height }); win.style.left = `${clamped.left}px`; win.style.top = `${clamped.top}px`; }); handle.addEventListener("pointerup", event => { if (!drag || drag.pointerId !== event.pointerId) { return; } drag = null; userNotesSavePosition(win); }); handle.addEventListener("pointercancel", event => { if (!drag || drag.pointerId !== event.pointerId) { return; } drag = null; userNotesSavePosition(win); }); } export function userNotesOpenNotes() { let win = document.getElementById(USER_NOTES_WINDOW_ID); if (win) { win.hidden = false; userNotesRestorePosition(win); userNotesApplyWindowSettings(win); userNotesBringToFront(win); win.querySelector("textarea")?.focus(); return; } win = document.createElement("section"); win.id = USER_NOTES_WINDOW_ID; win.className = "user-notes-window"; win.innerHTML = `
User Notes
Gespeichert
`; document.body.appendChild(win); userNotesApplyWindowSettings(win); userNotesRestorePosition(win); const textarea = win.querySelector(".user-notes-textarea"); if (!(textarea instanceof HTMLTextAreaElement)) { console.error(`${USER_NOTES_MODULE_ID} | Notes textarea could not be created.`); return; } textarea.value = userNotesLoadNotes(); textarea.addEventListener("input", event => { userNotesDebouncedSave(event.currentTarget.value); }); win.querySelector(".user-notes-save")?.addEventListener("click", () => { userNotesSaveNotes(textarea.value); userNotesSetStatus("Gespeichert"); userNotesSavePosition(win); }); win.querySelector(".user-notes-close")?.addEventListener("click", () => { userNotesSaveNotes(textarea.value); userNotesSavePosition(win); win.hidden = true; }); win.addEventListener("pointerdown", () => { userNotesBringToFront(win); }); const resizeObserver = new ResizeObserver(() => { if (win.hidden) { return; } const rect = win.getBoundingClientRect(); if (rect.width < USER_NOTES_MIN_WIDTH || rect.height < USER_NOTES_MIN_HEIGHT) { return; } userNotesSavePosition(win); }); resizeObserver.observe(win); userNotesMakeDraggable(win); userNotesBringToFront(win); textarea.focus(); } export function userNotesRefreshOpenWindow() { const oldWin = document.getElementById(USER_NOTES_WINDOW_ID); if (!oldWin) { return; } const textarea = oldWin.querySelector(".user-notes-textarea"); if (textarea instanceof HTMLTextAreaElement) { userNotesSaveNotes(textarea.value); } userNotesSavePosition(oldWin); oldWin.remove(); userNotesOpenNotes(); }