");
+ 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);
+ }
}
}
}
@@ -347,6 +365,19 @@ messagingService.subscribeToSyncMessages(syncData => {
}
});
+$promotedAttributesContainer.on('change', '.promoted-attribute-input', async event => {
+ const $attr = $(event.target);
+
+ await server.put("notes/" + getCurrentNoteId() + "/attribute", {
+ attributeId: $attr.prop("attribute-id"),
+ type: $attr.prop("attribute-type"),
+ name: $attr.prop("attribute-name"),
+ value: $attr.val()
+ });
+
+ infoService.showMessage("Attribute has been saved.");
+});
+
$(document).ready(() => {
$noteTitle.on('input', () => {
noteChanged();
diff --git a/src/public/stylesheets/style.css b/src/public/stylesheets/style.css
index 8468f92b6..6d323f1f2 100644
--- a/src/public/stylesheets/style.css
+++ b/src/public/stylesheets/style.css
@@ -424,4 +424,9 @@ html.theme-dark body {
.ck.ck-block-toolbar-button {
transform: translateX(10px);
+}
+
+#note-detail-promoted-attributes {
+ width: 50%;
+ margin: auto;
}
\ No newline at end of file
diff --git a/src/routes/api/attributes.js b/src/routes/api/attributes.js
index fa2283482..7d175aa82 100644
--- a/src/routes/api/attributes.js
+++ b/src/routes/api/attributes.js
@@ -54,6 +54,31 @@ async function getEffectiveNoteAttributes(req) {
return filteredAttributes;
}
+async function updateNoteAttribute(req) {
+ const noteId = req.params.noteId;
+ const body = req.body;
+
+ let attribute;
+
+ if (body.attributeId) {
+ attribute = await repository.getAttribute(body.attributeId);
+ }
+ else {
+ attribute = new Attribute();
+ attribute.noteId = noteId;
+ attribute.name = body.name;
+ attribute.type = body.type;
+ }
+
+ if (attribute.noteId !== noteId) {
+ throw new Error(`Attribute ${body.attributeId} does not belong to note ${noteId}`);
+ }
+
+ attribute.value = body.value;
+
+ await attribute.save();
+}
+
async function updateNoteAttributes(req) {
const noteId = req.params.noteId;
const attributes = req.body;
@@ -104,6 +129,7 @@ async function getValuesForAttribute(req) {
module.exports = {
updateNoteAttributes,
+ updateNoteAttribute,
getAttributeNames,
getValuesForAttribute,
getEffectiveNoteAttributes
diff --git a/src/routes/routes.js b/src/routes/routes.js
index 7576ffc78..f8fd1d17b 100644
--- a/src/routes/routes.js
+++ b/src/routes/routes.js
@@ -136,6 +136,7 @@ function register(app) {
apiRoute(GET, '/api/notes/:noteId/attributes', attributesRoute.getEffectiveNoteAttributes);
apiRoute(PUT, '/api/notes/:noteId/attributes', attributesRoute.updateNoteAttributes);
+ apiRoute(PUT, '/api/notes/:noteId/attribute', attributesRoute.updateNoteAttribute);
apiRoute(GET, '/api/attributes/names', attributesRoute.getAttributeNames);
apiRoute(GET, '/api/attributes/values/:attributeName', attributesRoute.getValuesForAttribute);
diff --git a/src/views/index.ejs b/src/views/index.ejs
index 05021754d..bfad24bb7 100644
--- a/src/views/index.ejs
+++ b/src/views/index.ejs
@@ -183,7 +183,7 @@
|