diff --git a/src/public/app/widgets/ribbon_widgets/promoted_attributes.js b/src/public/app/widgets/ribbon_widgets/promoted_attributes.js index 0fea1a4a8..d35fe4f0f 100644 --- a/src/public/app/widgets/ribbon_widgets/promoted_attributes.js +++ b/src/public/app/widgets/ribbon_widgets/promoted_attributes.js @@ -115,9 +115,9 @@ export default class PromotedAttributesWidget extends NoteContextAwareWidget { const $input = $("") .prop("tabindex", 200 + definitionAttr.position) - .prop("attribute-id", valueAttr.noteId === this.noteId ? 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) + .attr("data-attribute-id", valueAttr.noteId === this.noteId ? valueAttr.attributeId : '') // if not owned, we'll force creation of a new attribute instead of updating the inherited one + .attr("data-attribute-type", valueAttr.type) + .attr("data-attribute-name", valueAttr.name) .prop("value", valueAttr.value) .addClass("form-control") .addClass("promoted-attribute-input") @@ -230,7 +230,7 @@ export default class PromotedAttributesWidget extends NoteContextAwareWidget { } if (definition.multiplicity === "multi") { - const addButton = $("") + const $addButton = $("") .addClass("bx bx-plus pointer") .prop("title", "Add new attribute") .on('click', async () => { @@ -246,12 +246,28 @@ export default class PromotedAttributesWidget extends NoteContextAwareWidget { $new.find('input').trigger('focus'); }); - const removeButton = $("") + const $removeButton = $("") .addClass("bx bx-trash pointer") .prop("title", "Remove this attribute") .on('click', async () => { - if (valueAttr.attributeId) { - await server.remove("notes/" + this.noteId + "/attributes/" + valueAttr.attributeId, this.componentId); + const attributeId = $input.attr("data-attribute-id"); + + if (attributeId) { + await server.remove("notes/" + this.noteId + "/attributes/" + attributeId, this.componentId); + } + + // if it's the last one the create new empty form immediately + const sameAttrSelector = `input[data-attribute-type='${valueAttr.type}'][data-attribute-name='${valueName}']`; + + if (this.$widget.find(sameAttrSelector).length <= 1) { + const $new = await this.createPromotedAttributeCell(definitionAttr, { + attributeId: "", + type: valueAttr.type, + name: valueName, + value: "" + }, valueName); + + $wrapper.after($new); } $wrapper.remove(); @@ -259,9 +275,9 @@ export default class PromotedAttributesWidget extends NoteContextAwareWidget { $multiplicityCell .append("  ") - .append(addButton) + .append($addButton) .append("  ") - .append(removeButton); + .append($removeButton); } return $wrapper; @@ -275,7 +291,7 @@ export default class PromotedAttributesWidget extends NoteContextAwareWidget { if ($attr.prop("type") === "checkbox") { value = $attr.is(':checked') ? "true" : "false"; } - else if ($attr.prop("attribute-type") === "relation") { + else if ($attr.attr("data-attribute-type") === "relation") { const selectedPath = $attr.getSelectedNotePath(); value = selectedPath ? treeService.getNoteIdFromNotePath(selectedPath) : ""; @@ -285,13 +301,13 @@ export default class PromotedAttributesWidget extends NoteContextAwareWidget { } const result = await server.put(`notes/${this.noteId}/attribute`, { - attributeId: $attr.prop("attribute-id"), - type: $attr.prop("attribute-type"), - name: $attr.prop("attribute-name"), + attributeId: $attr.attr("data-attribute-id"), + type: $attr.attr("data-attribute-type"), + name: $attr.attr("data-attribute-name"), value: value }, this.componentId); - $attr.prop("attribute-id", result.attributeId); + $attr.attr("data-attribute-id", result.attributeId); } entitiesReloadedEvent({loadResults}) { diff --git a/src/services/attributes.js b/src/services/attributes.js index 175605deb..eb5484fdc 100644 --- a/src/services/attributes.js +++ b/src/services/attributes.js @@ -65,6 +65,7 @@ const BUILTIN_ATTRIBUTES = [ { type: 'relation', name: 'renderNote', isDangerous: true } ]; +/** @returns {Note[]} */ function getNotesWithLabel(name, value) { const query = formatAttrForSearch({type: 'label', name, value}, true); return searchService.searchNotes(query, { @@ -74,6 +75,7 @@ function getNotesWithLabel(name, value) { } // TODO: should be in search service +/** @returns {Note|null} */ function getNoteWithLabel(name, value) { // optimized version (~20 times faster) without using normal search, useful for e.g. finding date notes const attrs = becca.findAttributes('label', name); diff --git a/src/services/date_notes.js b/src/services/date_notes.js index 66606f11a..7d9940690 100644 --- a/src/services/date_notes.js +++ b/src/services/date_notes.js @@ -25,15 +25,6 @@ function createNote(parentNote, noteTitle) { }).note; } -function getNoteStartingWith(parentNoteId, startsWith) { - const noteId = sql.getValue(`SELECT notes.noteId FROM notes JOIN branches USING(noteId) - WHERE parentNoteId = ? AND title LIKE '${startsWith}%' - AND notes.isDeleted = 0 AND isProtected = 0 - AND branches.isDeleted = 0`, [parentNoteId]); - - return becca.getNote(noteId); -} - /** @returns {Note} */ function getRootCalendarNote() { let rootNote = attributeService.getNoteWithLabel(CALENDAR_ROOT_LABEL); @@ -164,12 +155,6 @@ function getDateNote(dateStr) { const monthNote = getMonthNote(dateStr, rootNote); const dayNumber = dateStr.substr(8, 2); - dateNote = getNoteStartingWith(monthNote.noteId, dayNumber); - - if (dateNote) { - return dateNote; - } - const dateObj = dateUtils.parseLocalDate(dateStr); const noteTitle = getDateNoteTitle(rootNote, dayNumber, dateObj);