import { USER_NOTES_MODULE_ID, USER_NOTES_WINDOW_ID } from "./user-notes-constants.js"; import { userNotesLoadAppearance, userNotesSaveAppearance, userNotesRemoveSavedAppearance } from "./user-notes-storage.js"; let resetPositionCallback = null; const USER_NOTES_APPEARANCE_DEFAULTS = { windowBackgroundColor: "#191813", windowBackgroundAlpha: 0.96, windowTextColor: "#f0f0e0", textareaBackgroundColor: "#ffffff", textareaBackgroundAlpha: 0.92, textareaTextColor: "#111111" }; function userNotesClampAlpha(value, fallback = 1) { const number = Number(value); if (!Number.isFinite(number)) { return fallback; } return Math.max(0, Math.min(1, number)); } function userNotesNormalizeHexColor(value, fallback) { const normalized = String(value ?? "").trim(); if (/^#[0-9a-f]{6}$/i.test(normalized)) { return normalized; } return fallback; } function userNotesHexToRgba(hex, alpha) { const normalized = userNotesNormalizeHexColor(hex, "#000000"); const match = normalized.match(/^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i); if (!match) { return `rgba(0, 0, 0, ${userNotesClampAlpha(alpha)})`; } const red = parseInt(match[1], 16); const green = parseInt(match[2], 16); const blue = parseInt(match[3], 16); return `rgba(${red}, ${green}, ${blue}, ${userNotesClampAlpha(alpha)})`; } function userNotesLoadValidatedAppearance() { const values = userNotesLoadAppearance(USER_NOTES_APPEARANCE_DEFAULTS); return { windowBackgroundColor: userNotesNormalizeHexColor( values.windowBackgroundColor, USER_NOTES_APPEARANCE_DEFAULTS.windowBackgroundColor ), windowBackgroundAlpha: userNotesClampAlpha( values.windowBackgroundAlpha, USER_NOTES_APPEARANCE_DEFAULTS.windowBackgroundAlpha ), windowTextColor: userNotesNormalizeHexColor( values.windowTextColor, USER_NOTES_APPEARANCE_DEFAULTS.windowTextColor ), textareaBackgroundColor: userNotesNormalizeHexColor( values.textareaBackgroundColor, USER_NOTES_APPEARANCE_DEFAULTS.textareaBackgroundColor ), textareaBackgroundAlpha: userNotesClampAlpha( values.textareaBackgroundAlpha, USER_NOTES_APPEARANCE_DEFAULTS.textareaBackgroundAlpha ), textareaTextColor: userNotesNormalizeHexColor( values.textareaTextColor, USER_NOTES_APPEARANCE_DEFAULTS.textareaTextColor ) }; } export function userNotesRegisterSettings(onResetPosition) { resetPositionCallback = onResetPosition; game.settings.registerMenu(USER_NOTES_MODULE_ID, "appearanceSettings", { name: "Darstellung", label: "Farben und Transparenz einstellen", hint: "Öffnet lokale Colorpicker für Fenster, Notizfeld und Schriftfarben. Die Werte werden nur im localStorage dieses Browsers gespeichert.", icon: "fas fa-palette", type: UserNotesAppearanceSettings, restricted: false }); game.settings.registerMenu(USER_NOTES_MODULE_ID, "resetWindowPosition", { name: "Position und Größe zurücksetzen", label: "Jetzt zurücksetzen", hint: "Setzt nur Position und Größe des User-Notes-Fensters für diesen Browser zurück. Notizen, Farben und Transparenzwerte bleiben unverändert.", icon: "fas fa-undo", type: UserNotesDirectResetWindowPosition, restricted: false }); } export function userNotesApplySettingsToOpenWindow() { const win = document.getElementById(USER_NOTES_WINDOW_ID); if (!win) { return; } userNotesApplyWindowSettings(win); } export function userNotesApplyWindowSettings(win) { const appearance = userNotesLoadValidatedAppearance(); win.style.setProperty( "--user-notes-window-background", userNotesHexToRgba( appearance.windowBackgroundColor, appearance.windowBackgroundAlpha ) ); win.style.setProperty( "--user-notes-window-text-color", appearance.windowTextColor ); win.style.setProperty( "--user-notes-textarea-background", userNotesHexToRgba( appearance.textareaBackgroundColor, appearance.textareaBackgroundAlpha ) ); win.style.setProperty( "--user-notes-textarea-color", appearance.textareaTextColor ); } class UserNotesDirectResetWindowPosition extends FormApplication { render(_force, _options) { if (typeof resetPositionCallback === "function") { resetPositionCallback(); ui.notifications?.info("User Notes: Position und Größe wurden zurückgesetzt."); } else { console.warn("User Notes | resetPositionCallback is not available"); ui.notifications?.warn("User Notes: Reset-Funktion ist nicht verfügbar."); } return this; } } class UserNotesAppearanceSettings extends FormApplication { static get defaultOptions() { return foundry.utils.mergeObject(super.defaultOptions, { id: "user-notes-appearance-settings", title: "User Notes Darstellung", template: null, width: 520, height: "auto", closeOnSubmit: false, submitOnChange: false, submitOnClose: false }); } getData() { const appearance = userNotesLoadValidatedAppearance(); return { ...appearance, windowBackgroundAlphaPercent: Math.round(appearance.windowBackgroundAlpha * 100), textareaBackgroundAlphaPercent: Math.round(appearance.textareaBackgroundAlpha * 100) }; } async _renderInner(data) { const html = `

Diese Werte werden lokal im Browser gespeichert. Foundry-Settings werden dadurch nicht überschrieben und die Seite wird nicht neu geladen.

Fenster

Farbe des äußeren Notizfensters.

${data.windowBackgroundAlphaPercent}%

0% ist vollständig transparent, 100% ist vollständig deckend.

Farbe für Titelleiste, Status und Buttons.

Notizfeld

Farbe des eigentlichen Textfeldes.

${data.textareaBackgroundAlphaPercent}%

0% ist vollständig transparent, 100% ist vollständig deckend.

Farbe des Textes innerhalb des Notizfeldes.

`; return $(html); } activateListeners(html) { super.activateListeners(html); const root = html[0]; if (!root) { console.warn("User Notes | appearance settings root element not found"); return; } html.on("submit", event => { event.preventDefault(); event.stopPropagation(); return false; }); const syncColorPair = (colorName, textName) => { const colorInput = root.querySelector(`input[name="${colorName}"]`); const textInput = root.querySelector(`input[name="${textName}"]`); if (!colorInput || !textInput) { return; } colorInput.addEventListener("input", () => { textInput.value = colorInput.value; }); textInput.addEventListener("input", () => { if (/^#[0-9a-f]{6}$/i.test(textInput.value)) { colorInput.value = textInput.value; } }); }; syncColorPair("windowBackgroundColor", "windowBackgroundColorText"); syncColorPair("windowTextColor", "windowTextColorText"); syncColorPair("textareaBackgroundColor", "textareaBackgroundColorText"); syncColorPair("textareaTextColor", "textareaTextColorText"); for (const range of root.querySelectorAll('input[type="range"]')) { const output = range .closest(".user-notes-range-row") ?.querySelector("output"); const updateOutput = () => { if (output) { output.textContent = `${Math.round(Number(range.value) * 100)}%`; } }; range.addEventListener("input", updateOutput); range.addEventListener("change", updateOutput); updateOutput(); } root.querySelector(".user-notes-apply-appearance")?.addEventListener("click", event => { event.preventDefault(); event.stopPropagation(); this.userNotesSaveAppearanceFromDialog(root, { closeDialog: false, notify: true }); }); root.querySelector(".user-notes-save-appearance")?.addEventListener("click", event => { event.preventDefault(); event.stopPropagation(); this.userNotesSaveAppearanceFromDialog(root, { closeDialog: true, notify: true }); }); root.querySelector(".user-notes-reset-appearance")?.addEventListener("click", event => { event.preventDefault(); event.stopPropagation(); userNotesRemoveSavedAppearance(); userNotesApplySettingsToOpenWindow(); ui.notifications?.info("User Notes: Standardfarben wurden wiederhergestellt."); this.render(true); }); } userNotesSaveAppearanceFromDialog(root, options = {}) { const closeDialog = options.closeDialog ?? true; const notify = options.notify ?? true; const getInputValue = name => { const input = root.querySelector(`[name="${name}"]`); return input?.value; }; const appearance = { windowBackgroundColor: userNotesNormalizeHexColor( getInputValue("windowBackgroundColorText") || getInputValue("windowBackgroundColor"), USER_NOTES_APPEARANCE_DEFAULTS.windowBackgroundColor ), windowBackgroundAlpha: userNotesClampAlpha( getInputValue("windowBackgroundAlpha"), USER_NOTES_APPEARANCE_DEFAULTS.windowBackgroundAlpha ), windowTextColor: userNotesNormalizeHexColor( getInputValue("windowTextColorText") || getInputValue("windowTextColor"), USER_NOTES_APPEARANCE_DEFAULTS.windowTextColor ), textareaBackgroundColor: userNotesNormalizeHexColor( getInputValue("textareaBackgroundColorText") || getInputValue("textareaBackgroundColor"), USER_NOTES_APPEARANCE_DEFAULTS.textareaBackgroundColor ), textareaBackgroundAlpha: userNotesClampAlpha( getInputValue("textareaBackgroundAlpha"), USER_NOTES_APPEARANCE_DEFAULTS.textareaBackgroundAlpha ), textareaTextColor: userNotesNormalizeHexColor( getInputValue("textareaTextColorText") || getInputValue("textareaTextColor"), USER_NOTES_APPEARANCE_DEFAULTS.textareaTextColor ) }; userNotesSaveAppearance(appearance); userNotesApplySettingsToOpenWindow(); if (notify) { ui.notifications?.info( closeDialog ? "User Notes: Darstellung wurde gespeichert." : "User Notes: Darstellung wurde angewendet." ); } if (closeDialog) { this.close(); } } async _updateObject(_event, _formData) { // Wird absichtlich nicht verwendet. // Die Buttons speichern direkt in localStorage, damit kein nativer GET-Submit stattfindet. } }