mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +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