"use strict"; function editNotes(id, name) { // elements const notesLegend = byId("notesLegend"); const notesName = byId("notesName"); const notesSelect = byId("notesSelect"); const notesPin = byId("notesPin"); // update list of objects notesSelect.options.length = 0; notes.forEach(({id}) => notesSelect.options.add(new Option(id, id))); // update pin notes icon const notesArePinned = options.pinNotes; if (notesArePinned) notesPin.classList.add("pressed"); else notesPin.classList.remove("pressed"); // select an object if (notes.length || id) { if (!id) id = notes[0].id; let note = notes.find(note => note.id === id); if (!note) { if (!name) name = id; note = {id, name, legend: ""}; notes.push(note); notesSelect.options.add(new Option(id, id)); } notesSelect.value = id; notesName.value = note.name; notesLegend.innerHTML = note.legend; initEditor(); updateNotesBox(note); } else { // if notes array is empty notesName.value = ""; notesLegend.innerHTML = "No notes added. Click on an element (e.g. label or marker) and add a free text note"; } $("#notesEditor").dialog({ title: "Notes Editor", width: window.innerWidth * 0.8, height: window.innerHeight * 0.75, position: {my: "center", at: "center", of: "svg"}, close: removeEditor }); if (modules.editNotes) return; modules.editNotes = true; // add listeners byId("notesSelect").addEventListener("change", changeElement); byId("notesName").addEventListener("input", changeName); byId("notesLegend").addEventListener("blur", updateLegend); byId("notesPin").addEventListener("click", toggleNotesPin); byId("notesFocus").addEventListener("click", validateHighlightElement); byId("notesGenerateWithAi").addEventListener("click", openAiGenerator); byId("notesDownload").addEventListener("click", downloadLegends); byId("notesUpload").addEventListener("click", () => legendsToLoad.click()); byId("legendsToLoad").addEventListener("change", function () { uploadFile(this, uploadLegends); }); byId("notesRemove").addEventListener("click", triggerNotesRemove); async function initEditor() { if (!window.tinymce) { const url = "https://azgaar.github.io/Fantasy-Map-Generator/libs/tinymce/tinymce.min.js"; try { await import(url); } catch (error) { // error may be caused by failed request being cached, try again with random hash try { const hash = Math.random().toString(36).substring(2, 15); await import(`${url}#${hash}`); } catch (error) { console.error(error); } } } if (window.tinymce) { window.tinymce._setBaseUrl("https://azgaar.github.io/Fantasy-Map-Generator/libs/tinymce"); tinymce.init({ license_key: "gpl", selector: "#notesLegend", height: "90%", menubar: false, plugins: `autolink lists link charmap code fullscreen image link media table wordcount`, toolbar: `code | undo redo | removeformat | bold italic strikethrough | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image media table | fontselect fontsizeselect | blockquote hr charmap | print fullscreen`, media_alt_source: false, media_poster: false, browser_spellcheck: true, contextmenu: false, setup: editor => { editor.on("Change", updateLegend); } }); } } function updateLegend() { const note = notes.find(note => note.id === notesSelect.value); if (!note) return tip("Note element is not found", true, "error", 4000); const isTinyEditorActive = window.tinymce?.activeEditor; note.legend = isTinyEditorActive ? tinymce.activeEditor.getContent() : notesLegend.innerHTML; updateNotesBox(note); } function updateNotesBox(note) { byId("notesHeader").innerHTML = note.name; byId("notesBody").innerHTML = note.legend; } function changeElement() { const note = notes.find(note => note.id === this.value); if (!note) return tip("Note element is not found", true, "error", 4000); notesName.value = note.name; notesLegend.innerHTML = note.legend; updateNotesBox(note); if (window.tinymce) tinymce.activeEditor.setContent(note.legend); } function changeName() { const note = notes.find(note => note.id === notesSelect.value); if (!note) return tip("Note element is not found", true, "error", 4000); note.name = this.value; } function validateHighlightElement() { const element = byId(notesSelect.value); if (element) return highlightElement(element, 3); confirmationDialog({ title: "Element not found", message: "Note element is not found. Would you like to remove the note?", confirm: "Remove", cancel: "Keep", onConfirm: removeLegend }); } function openAiGenerator() { const note = notes.find(note => note.id === notesSelect.value); let prompt = `Respond with description. Use simple dry language. Invent facts, names and details. Split to paragraphs and format to HTML. Remove h tags, remove markdown.`; if (note?.name) prompt += ` Name: ${note.name}.`; if (note?.legend) prompt += ` Data: ${note.legend}`; const onApply = result => { notesLegend.innerHTML = result; if (note) { note.legend = result; updateNotesBox(note); if (window.tinymce) tinymce.activeEditor.setContent(note.legend); } }; geneateWithAi(prompt, onApply); } function downloadLegends() { const notesData = JSON.stringify(notes); const name = getFileName("Notes") + ".txt"; downloadFile(notesData, name); } function uploadLegends(dataLoaded) { if (!dataLoaded) return tip("Cannot load the file. Please check the data format", false, "error"); notes = JSON.parse(dataLoaded); notesSelect.options.length = 0; editNotes(notes[0].id, notes[0].name); } function triggerNotesRemove() { function removeLegend() { notes = notes.filter(({id}) => id !== notesSelect.value); if (!notes.length) { $("#notesEditor").dialog("close"); return; } removeEditor(); editNotes(notes[0].id, notes[0].name); } confirmationDialog({ title: "Remove note", message: "Are you sure you want to remove the selected note? There is no way to undo this action", confirm: "Remove", onConfirm: removeLegend }); } function toggleNotesPin() { options.pinNotes = !options.pinNotes; this.classList.toggle("pressed"); } function removeEditor() { if (window.tinymce) tinymce.remove(); } }