import server from "./server.js"; import utils from "./utils.js"; import messagingService from "./messaging.js"; import treeUtils from "./tree_utils.js"; import noteAutocompleteService from "./note_autocomplete.js"; import linkService from "./link.js"; import noteDetailService from "./note_detail.js"; const $attributeList = $("#attribute-list"); const $attributeListInner = $("#attribute-list-inner"); const $promotedAttributesContainer = $("#note-detail-promoted-attributes"); const $savedIndicator = $("#saved-indicator"); let attributePromise; function invalidateAttributes() { attributePromise = null; } function reloadAttributes() { attributePromise = server.get('notes/' + noteDetailService.getCurrentNoteId() + '/attributes'); } async function refreshAttributes() { reloadAttributes(); await showAttributes(); } async function getAttributes() { if (!attributePromise) { reloadAttributes(); } return await attributePromise; } async function showAttributes() { $promotedAttributesContainer.empty(); $attributeList.hide(); $attributeListInner.empty(); const note = noteDetailService.getCurrentNote(); const attributes = await attributePromise; const promoted = attributes.filter(attr => (attr.type === 'label-definition' || attr.type === 'relation-definition') && !attr.name.startsWith("child:") && attr.value.isPromoted); const hidePromotedAttributes = attributes.some(attr => attr.type === 'label' && attr.name === 'hidePromotedAttributes'); if (promoted.length > 0 && !hidePromotedAttributes) { const $tbody = $("
"); for (const definitionAttr of promoted) { const definitionType = definitionAttr.type; const valueType = definitionType.substr(0, definitionType.length - 11); let valueAttrs = attributes.filter(el => el.name === definitionAttr.name && el.type === valueType); if (valueAttrs.length === 0) { valueAttrs.push({ attributeId: "", type: valueType, name: definitionAttr.name, value: "" }); } if (definitionAttr.value.multiplicityType === 'singlevalue') { valueAttrs = valueAttrs.slice(0, 1); } for (const valueAttr of valueAttrs) { const $tr = await createPromotedAttributeRow(definitionAttr, valueAttr); $tbody.append($tr); } } // we replace the whole content in one step so there can't be any race conditions // (previously we saw promoted attributes doubling) $promotedAttributesContainer.empty().append($tbody); } else if (note.type !== 'relation-map') { // display only "own" notes const ownedAttributes = attributes.filter(attr => attr.noteId === note.noteId); if (ownedAttributes.length > 0) { for (const attribute of ownedAttributes) { if (attribute.type === 'label') { $attributeListInner.append(utils.formatLabel(attribute) + " "); } else if (attribute.type === 'relation') { if (attribute.value) { $attributeListInner.append('@' + attribute.name + "="); $attributeListInner.append(await linkService.createNoteLink(attribute.value)); $attributeListInner.append(" "); } else { messagingService.logError(`Relation ${attribute.attributeId} has empty target`); } } else if (attribute.type === 'label-definition' || attribute.type === 'relation-definition') { $attributeListInner.append(attribute.name + " definition "); } else { messagingService.logError("Unknown attr type: " + attribute.type); } } $attributeList.show(); } } return attributes; } async function createPromotedAttributeRow(definitionAttr, valueAttr) { const definition = definitionAttr.value; const $tr = $("