import treeService from './tree.js'; import treeUtils from './tree_utils.js'; import noteTypeService from './note_type.js'; import protectedSessionService from './protected_session.js'; import protectedSessionHolder from './protected_session_holder.js'; import utils from './utils.js'; import server from './server.js'; import messagingService from "./messaging.js"; import infoService from "./info.js"; import linkService from "./link.js"; import treeCache from "./tree_cache.js"; import NoteFull from "../entities/note_full.js"; import noteDetailCode from './note_detail_code.js'; import noteDetailText from './note_detail_text.js'; import noteDetailFile from './note_detail_file.js'; import noteDetailSearch from './note_detail_search.js'; import noteDetailRender from './note_detail_render.js'; import bundleService from "./bundle.js"; const $noteTitle = $("#note-title"); const $noteDetailComponents = $(".note-detail-component"); const $protectButton = $("#protect-button"); const $unprotectButton = $("#unprotect-button"); const $noteDetailWrapper = $("#note-detail-wrapper"); const $noteDetailComponentWrapper = $("#note-detail-component-wrapper"); const $noteIdDisplay = $("#note-id-display"); const $attributeList = $("#attribute-list"); const $attributeListInner = $("#attribute-list-inner"); const $labelList = $("#label-list"); const $labelListInner = $("#label-list-inner"); const $relationList = $("#relation-list"); const $relationListInner = $("#relation-list-inner"); const $childrenOverview = $("#children-overview"); const $scriptArea = $("#note-detail-script-area"); const $promotedAttributesContainer = $("#note-detail-promoted-attributes"); let currentNote = null; let noteChangeDisabled = false; let isNoteChanged = false; const components = { 'code': noteDetailCode, 'text': noteDetailText, 'file': noteDetailFile, 'search': noteDetailSearch, 'render': noteDetailRender }; function getComponent(type) { if (components[type]) { return components[type]; } else { infoService.throwError("Unrecognized type: " + type); } } function getCurrentNote() { return currentNote; } function getCurrentNoteId() { return currentNote ? currentNote.noteId : null; } function getCurrentNoteType() { const currentNote = getCurrentNote(); return currentNote ? currentNote.type : null; } function noteChanged() { if (noteChangeDisabled) { return; } isNoteChanged = true; } async function reload() { // no saving here await loadNoteDetail(getCurrentNoteId()); } async function switchToNote(noteId) { if (getCurrentNoteId() !== noteId) { await saveNoteIfChanged(); await loadNoteDetail(noteId); } } async function saveNote() { const note = getCurrentNote(); note.title = $noteTitle.val(); note.content = getComponent(note.type).getContent(); treeService.setNoteTitle(note.noteId, note.title); await server.put('notes/' + note.noteId, note.dto); isNoteChanged = false; if (note.isProtected) { protectedSessionHolder.touchProtectedSession(); } infoService.showMessage("Saved!"); } async function saveNoteIfChanged() { if (!isNoteChanged) { return; } await saveNote(); } function setNoteBackgroundIfProtected(note) { const isProtected = !!note.isProtected; $noteDetailComponentWrapper.toggleClass("protected", isProtected); $protectButton.toggleClass("active", isProtected); $unprotectButton.toggleClass("active", !isProtected); } let isNewNoteCreated = false; function newNoteCreated() { isNewNoteCreated = true; } async function handleProtectedSession() { await protectedSessionService.ensureProtectedSession(currentNote.isProtected, false); if (currentNote.isProtected) { protectedSessionHolder.touchProtectedSession(); } // this might be important if we focused on protected note when not in protected note and we got a dialog // to login, but we chose instead to come to another node - at that point the dialog is still visible and this will close it. protectedSessionService.ensureDialogIsClosed(); } async function loadNoteDetail(noteId) { currentNote = await loadNote(noteId); if (isNewNoteCreated) { isNewNoteCreated = false; $noteTitle.focus().select(); } $noteIdDisplay.html(noteId); setNoteBackgroundIfProtected(currentNote); await handleProtectedSession(); $noteDetailWrapper.show(); noteChangeDisabled = true; try { $noteTitle.val(currentNote.title); noteTypeService.setNoteType(currentNote.type); noteTypeService.setNoteMime(currentNote.mime); $noteDetailComponents.hide(); await getComponent(currentNote.type).show(); } finally { noteChangeDisabled = false; } treeService.setBranchBackgroundBasedOnProtectedStatus(noteId); // after loading new note make sure editor is scrolled to the top $noteDetailWrapper.scrollTop(0); const labels = await loadLabelList(); const hideChildrenOverview = labels.some(label => label.name === 'hideChildrenOverview'); await showChildrenOverview(hideChildrenOverview); await loadRelationList(); $scriptArea.html(''); await bundleService.executeRelationBundles(getCurrentNote(), 'runOnNoteView'); await loadAttributes(); } async function showChildrenOverview(hideChildrenOverview) { if (hideChildrenOverview) { $childrenOverview.hide(); return; } const note = getCurrentNote(); $childrenOverview.empty(); const notePath = treeService.getCurrentNotePath(); for (const childBranch of await note.getChildBranches()) { const link = $('', { href: 'javascript:', text: await treeUtils.getNoteTitle(childBranch.noteId, childBranch.parentNoteId) }).attr('action', 'note').attr('note-path', notePath + '/' + childBranch.noteId); const childEl = $('
').html(link); $childrenOverview.append(childEl); } $childrenOverview.show(); } async function loadAttributes() { $promotedAttributesContainer.empty(); const noteId = getCurrentNoteId(); const attributes = await server.get('notes/' + noteId + '/attributes'); const promoted = attributes.filter(attr => (attr.type === 'label-definition' || attr.type === 'relation-definition') && attr.value.isPromoted); let idx = 1; if (promoted.length > 0) { for (const definitionAttr of promoted) { const definitionType = definitionAttr.type; const definition = definitionAttr.value; const valueType = definitionType.substr(0, definitionType.length - 11); const valueAttrs = attributes.filter(el => el.name === definitionAttr.name && el.type === valueType); if (valueAttrs.length === 0) { valueAttrs.push({ attributeId: "", type: valueType, name: definitionAttr.name, value: "" }); } for (const valueAttr of valueAttrs) { const inputId = "promoted-input-" + (idx++); const $tr = $(""); const $labelCell = $("").append(valueAttr.name); const $input = $("") .prop("id", inputId) .prop("attribute-id", valueAttr.attributeId) .prop("attribute-type", valueAttr.type) .prop("attribute-name", valueAttr.name) .prop("value", valueAttr.value) .addClass("form-control") .addClass("promoted-attribute-input"); const $inputCell = $("").append($input); $tr.append($labelCell).append($inputCell); $promotedAttributesContainer.append($tr); if (valueAttr.type === 'label') { if (definition.labelType === 'text') { $input.prop("type", "text"); } else if (definition.labelType === 'number') { $input.prop("type", "number"); } else if (definition.labelType === 'boolean') { $input.prop("type", "checkbox"); if (valueAttr.value === "true") { $input.prop("checked", "checked"); } } else if (definition.labelType === 'date') { $input.prop("type", "text"); $input.datepicker({ changeMonth: true, changeYear: true, dateFormat: "yy-mm-dd" }); const $todayButton = $("