mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-04 05:28:59 +01:00 
			
		
		
		
	hide attribute "status bar" for relation map to maximize screen space, some refactoring
This commit is contained in:
		
							parent
							
								
									1ce26ed704
								
							
						
					
					
						commit
						db17b05db1
					
				@ -26,9 +26,9 @@ async function getAttributes() {
 | 
			
		||||
 | 
			
		||||
async function showAttributes() {
 | 
			
		||||
    $promotedAttributesContainer.empty();
 | 
			
		||||
    $attributeList.hide();
 | 
			
		||||
    $attributeList.hide().empty();
 | 
			
		||||
 | 
			
		||||
    const noteId = noteDetailService.getCurrentNoteId();
 | 
			
		||||
    const note = noteDetailService.getCurrentNote();
 | 
			
		||||
 | 
			
		||||
    const attributes = await attributePromise;
 | 
			
		||||
 | 
			
		||||
@ -37,168 +37,6 @@ async function showAttributes() {
 | 
			
		||||
        && !attr.name.startsWith("child:")
 | 
			
		||||
        && attr.value.isPromoted);
 | 
			
		||||
 | 
			
		||||
    let idx = 1;
 | 
			
		||||
 | 
			
		||||
    async function createRow(definitionAttr, valueAttr) {
 | 
			
		||||
        const definition = definitionAttr.value;
 | 
			
		||||
        const inputId = "promoted-input-" + idx;
 | 
			
		||||
        const $tr = $("<tr>");
 | 
			
		||||
        const $labelCell = $("<th>").append(valueAttr.name);
 | 
			
		||||
        const $input = $("<input>")
 | 
			
		||||
            .prop("id", inputId)
 | 
			
		||||
            .prop("tabindex", definitionAttr.position)
 | 
			
		||||
            .prop("attribute-id", valueAttr.isOwned ? valueAttr.attributeId : '') // if not owned, we'll force creation of a new attribute instead of updating the inherited one
 | 
			
		||||
            .prop("attribute-type", valueAttr.type)
 | 
			
		||||
            .prop("attribute-name", valueAttr.name)
 | 
			
		||||
            .prop("value", valueAttr.value)
 | 
			
		||||
            .addClass("form-control")
 | 
			
		||||
            .addClass("promoted-attribute-input")
 | 
			
		||||
            .change(promotedAttributeChanged);
 | 
			
		||||
 | 
			
		||||
        idx++;
 | 
			
		||||
 | 
			
		||||
        const $inputCell = $("<td>").append($("<div>").addClass("input-group").append($input));
 | 
			
		||||
 | 
			
		||||
        const $actionCell = $("<td>");
 | 
			
		||||
        const $multiplicityCell = $("<td>").addClass("multiplicity");
 | 
			
		||||
 | 
			
		||||
        $tr
 | 
			
		||||
            .append($labelCell)
 | 
			
		||||
            .append($inputCell)
 | 
			
		||||
            .append($actionCell)
 | 
			
		||||
            .append($multiplicityCell);
 | 
			
		||||
 | 
			
		||||
        if (valueAttr.type === 'label') {
 | 
			
		||||
            if (definition.labelType === 'text') {
 | 
			
		||||
                $input.prop("type", "text");
 | 
			
		||||
 | 
			
		||||
                // no need to await for this, can be done asynchronously
 | 
			
		||||
                server.get('attributes/values/' + encodeURIComponent(valueAttr.name)).then(attributeValues => {
 | 
			
		||||
                    if (attributeValues.length === 0) {
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    attributeValues = attributeValues.map(attribute => { return { value: attribute }; });
 | 
			
		||||
 | 
			
		||||
                    $input.autocomplete({
 | 
			
		||||
                        appendTo: document.querySelector('body'),
 | 
			
		||||
                        hint: false,
 | 
			
		||||
                        autoselect: true,
 | 
			
		||||
                        openOnFocus: true,
 | 
			
		||||
                        minLength: 0
 | 
			
		||||
                    }, [{
 | 
			
		||||
                        displayKey: 'value',
 | 
			
		||||
                        source: function (term, cb) {
 | 
			
		||||
                            term = term.toLowerCase();
 | 
			
		||||
 | 
			
		||||
                            const filtered = attributeValues.filter(attr => attr.value.toLowerCase().includes(term));
 | 
			
		||||
 | 
			
		||||
                            cb(filtered);
 | 
			
		||||
                        }
 | 
			
		||||
                    }]);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            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", "date");
 | 
			
		||||
 | 
			
		||||
                const $todayButton = $("<button>").addClass("btn btn-sm").text("Today").click(() => {
 | 
			
		||||
                    $input.val(utils.formatDateISO(new Date()));
 | 
			
		||||
                    $input.trigger("change");
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                $actionCell.append($todayButton);
 | 
			
		||||
            }
 | 
			
		||||
            else if (definition.labelType === 'url') {
 | 
			
		||||
                $input.prop("placeholder", "http://website...");
 | 
			
		||||
 | 
			
		||||
                const $openButton = $("<button>").addClass("btn btn-sm").text("Open").click(() => {
 | 
			
		||||
                    window.open($input.val(), '_blank');
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                $actionCell.append($openButton);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                messagingService.logError("Unknown labelType=" + definitionAttr.labelType);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if (valueAttr.type === 'relation') {
 | 
			
		||||
            if (valueAttr.value) {
 | 
			
		||||
                $input.val(await treeUtils.getNoteTitle(valueAttr.value));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // no need to wait for this
 | 
			
		||||
            noteAutocompleteService.initNoteAutocomplete($input);
 | 
			
		||||
 | 
			
		||||
            $input.on('autocomplete:selected', function(event, suggestion, dataset) {
 | 
			
		||||
                promotedAttributeChanged(event);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            $input.prop("data-selected-path", valueAttr.value);
 | 
			
		||||
 | 
			
		||||
            // ideally we'd use link instead of button which would allow tooltip preview, but
 | 
			
		||||
            // we can't guarantee updating the link in the a element
 | 
			
		||||
            const $openButton = $("<button>").addClass("btn btn-sm").text("Open").click(() => {
 | 
			
		||||
                const notePath = $input.getSelectedPath();
 | 
			
		||||
 | 
			
		||||
                if (notePath) {
 | 
			
		||||
                    treeService.activateNote(notePath);
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    console.log("Empty note path, nothing to open.");
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            $actionCell.append($openButton);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            messagingService.logError("Unknown attribute type=" + valueAttr.type);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (definition.multiplicityType === "multivalue") {
 | 
			
		||||
            const addButton = $("<span>")
 | 
			
		||||
                .addClass("jam jam-plus pointer")
 | 
			
		||||
                .prop("title", "Add new attribute")
 | 
			
		||||
                .click(async () => {
 | 
			
		||||
                    const $new = await createRow(definitionAttr, {
 | 
			
		||||
                        attributeId: "",
 | 
			
		||||
                        type: valueAttr.type,
 | 
			
		||||
                        name: definitionAttr.name,
 | 
			
		||||
                        value: ""
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    $tr.after($new);
 | 
			
		||||
 | 
			
		||||
                    $new.find('input').focus();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            const removeButton = $("<span>")
 | 
			
		||||
                .addClass("jam jam-trash pointer")
 | 
			
		||||
                .prop("title", "Remove this attribute")
 | 
			
		||||
                .click(async () => {
 | 
			
		||||
                    if (valueAttr.attributeId) {
 | 
			
		||||
                        await server.remove("notes/" + noteId + "/attributes/" + valueAttr.attributeId);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    $tr.remove();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            $multiplicityCell.append(addButton).append("   ").append(removeButton);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $tr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (promoted.length > 0) {
 | 
			
		||||
        const $tbody = $("<tbody>");
 | 
			
		||||
 | 
			
		||||
@ -222,7 +60,7 @@ async function showAttributes() {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            for (const valueAttr of valueAttrs) {
 | 
			
		||||
                const $tr = await createRow(definitionAttr, valueAttr);
 | 
			
		||||
                const $tr = await createPromotedAttributeRow(definitionAttr, valueAttr);
 | 
			
		||||
 | 
			
		||||
                $tbody.append($tr);
 | 
			
		||||
            }
 | 
			
		||||
@ -232,9 +70,7 @@ async function showAttributes() {
 | 
			
		||||
        // (previously we saw promoted attributes doubling)
 | 
			
		||||
        $promotedAttributesContainer.empty().append($tbody);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        $attributeListInner.empty();
 | 
			
		||||
 | 
			
		||||
    else if (note.type !== 'relation-map') {
 | 
			
		||||
        if (attributes.length > 0) {
 | 
			
		||||
            for (const attribute of attributes) {
 | 
			
		||||
                if (attribute.type === 'label') {
 | 
			
		||||
@ -265,6 +101,162 @@ async function showAttributes() {
 | 
			
		||||
    return attributes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function createPromotedAttributeRow(definitionAttr, valueAttr) {
 | 
			
		||||
    const definition = definitionAttr.value;
 | 
			
		||||
    const $tr = $("<tr>");
 | 
			
		||||
    const $labelCell = $("<th>").append(valueAttr.name);
 | 
			
		||||
    const $input = $("<input>")
 | 
			
		||||
        .prop("tabindex", definitionAttr.position)
 | 
			
		||||
        .prop("attribute-id", valueAttr.isOwned ? valueAttr.attributeId : '') // if not owned, we'll force creation of a new attribute instead of updating the inherited one
 | 
			
		||||
        .prop("attribute-type", valueAttr.type)
 | 
			
		||||
        .prop("attribute-name", valueAttr.name)
 | 
			
		||||
        .prop("value", valueAttr.value)
 | 
			
		||||
        .addClass("form-control")
 | 
			
		||||
        .addClass("promoted-attribute-input")
 | 
			
		||||
        .change(promotedAttributeChanged);
 | 
			
		||||
 | 
			
		||||
    const $inputCell = $("<td>").append($("<div>").addClass("input-group").append($input));
 | 
			
		||||
 | 
			
		||||
    const $actionCell = $("<td>");
 | 
			
		||||
    const $multiplicityCell = $("<td>").addClass("multiplicity");
 | 
			
		||||
 | 
			
		||||
    $tr
 | 
			
		||||
        .append($labelCell)
 | 
			
		||||
        .append($inputCell)
 | 
			
		||||
        .append($actionCell)
 | 
			
		||||
        .append($multiplicityCell);
 | 
			
		||||
 | 
			
		||||
    if (valueAttr.type === 'label') {
 | 
			
		||||
        if (definition.labelType === 'text') {
 | 
			
		||||
            $input.prop("type", "text");
 | 
			
		||||
 | 
			
		||||
            // no need to await for this, can be done asynchronously
 | 
			
		||||
            server.get('attributes/values/' + encodeURIComponent(valueAttr.name)).then(attributeValues => {
 | 
			
		||||
                if (attributeValues.length === 0) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                attributeValues = attributeValues.map(attribute => { return { value: attribute }; });
 | 
			
		||||
 | 
			
		||||
                $input.autocomplete({
 | 
			
		||||
                    appendTo: document.querySelector('body'),
 | 
			
		||||
                    hint: false,
 | 
			
		||||
                    autoselect: true,
 | 
			
		||||
                    openOnFocus: true,
 | 
			
		||||
                    minLength: 0
 | 
			
		||||
                }, [{
 | 
			
		||||
                    displayKey: 'value',
 | 
			
		||||
                    source: function (term, cb) {
 | 
			
		||||
                        term = term.toLowerCase();
 | 
			
		||||
 | 
			
		||||
                        const filtered = attributeValues.filter(attr => attr.value.toLowerCase().includes(term));
 | 
			
		||||
 | 
			
		||||
                        cb(filtered);
 | 
			
		||||
                    }
 | 
			
		||||
                }]);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        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", "date");
 | 
			
		||||
 | 
			
		||||
            const $todayButton = $("<button>").addClass("btn btn-sm").text("Today").click(() => {
 | 
			
		||||
                $input.val(utils.formatDateISO(new Date()));
 | 
			
		||||
                $input.trigger("change");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            $actionCell.append($todayButton);
 | 
			
		||||
        }
 | 
			
		||||
        else if (definition.labelType === 'url') {
 | 
			
		||||
            $input.prop("placeholder", "http://website...");
 | 
			
		||||
 | 
			
		||||
            const $openButton = $("<button>").addClass("btn btn-sm").text("Open").click(() => {
 | 
			
		||||
                window.open($input.val(), '_blank');
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            $actionCell.append($openButton);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            messagingService.logError("Unknown labelType=" + definitionAttr.labelType);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else if (valueAttr.type === 'relation') {
 | 
			
		||||
        if (valueAttr.value) {
 | 
			
		||||
            $input.val(await treeUtils.getNoteTitle(valueAttr.value));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // no need to wait for this
 | 
			
		||||
        noteAutocompleteService.initNoteAutocomplete($input);
 | 
			
		||||
 | 
			
		||||
        $input.on('autocomplete:selected', function(event, suggestion, dataset) {
 | 
			
		||||
            promotedAttributeChanged(event);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $input.prop("data-selected-path", valueAttr.value);
 | 
			
		||||
 | 
			
		||||
        // ideally we'd use link instead of button which would allow tooltip preview, but
 | 
			
		||||
        // we can't guarantee updating the link in the a element
 | 
			
		||||
        const $openButton = $("<button>").addClass("btn btn-sm").text("Open").click(() => {
 | 
			
		||||
            const notePath = $input.getSelectedPath();
 | 
			
		||||
 | 
			
		||||
            if (notePath) {
 | 
			
		||||
                treeService.activateNote(notePath);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                console.log("Empty note path, nothing to open.");
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $actionCell.append($openButton);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        messagingService.logError("Unknown attribute type=" + valueAttr.type);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (definition.multiplicityType === "multivalue") {
 | 
			
		||||
        const addButton = $("<span>")
 | 
			
		||||
            .addClass("jam jam-plus pointer")
 | 
			
		||||
            .prop("title", "Add new attribute")
 | 
			
		||||
            .click(async () => {
 | 
			
		||||
                const $new = await createPromotedAttributeRow(definitionAttr, {
 | 
			
		||||
                    attributeId: "",
 | 
			
		||||
                    type: valueAttr.type,
 | 
			
		||||
                    name: definitionAttr.name,
 | 
			
		||||
                    value: ""
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                $tr.after($new);
 | 
			
		||||
 | 
			
		||||
                $new.find('input').focus();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        const removeButton = $("<span>")
 | 
			
		||||
            .addClass("jam jam-trash pointer")
 | 
			
		||||
            .prop("title", "Remove this attribute")
 | 
			
		||||
            .click(async () => {
 | 
			
		||||
                if (valueAttr.attributeId) {
 | 
			
		||||
                    await server.remove("notes/" + noteId + "/attributes/" + valueAttr.attributeId);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                $tr.remove();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        $multiplicityCell.append(addButton).append("   ").append(removeButton);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $tr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function promotedAttributeChanged(event) {
 | 
			
		||||
    const $attr = $(event.target);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user