From 2a129809b365f0b9bc0abd76553d1a2741cd19de Mon Sep 17 00:00:00 2001 From: azivner Date: Mon, 29 Oct 2018 22:38:51 +0100 Subject: [PATCH] support for adding new relations from relation map with drag & drop --- .../services/note_detail_relation_map.js | 61 +++++++++++-------- src/routes/api/attributes.js | 21 ++++++- src/routes/routes.js | 1 + 3 files changed, 57 insertions(+), 26 deletions(-) diff --git a/src/public/javascripts/services/note_detail_relation_map.js b/src/public/javascripts/services/note_detail_relation_map.js index 86611e0ec..99d082d68 100644 --- a/src/public/javascripts/services/note_detail_relation_map.js +++ b/src/public/javascripts/services/note_detail_relation_map.js @@ -8,7 +8,8 @@ const $addChildNotesButton = $("#relation-map-add-child-notes"); let mapData; let instance; -let initDone = false; +// outside of mapData because they are not persisted in the note content +let relations; const uniDirectionalOverlays = [ [ "Arrow", { @@ -67,7 +68,7 @@ async function loadNotesAndRelations() { const noteIds = mapData.notes.map(note => note.id); const data = await server.post("notes/relation-map", {noteIds}); - const relations = []; + relations = []; for (const relation of data.relations) { const match = relations.find(rel => @@ -124,8 +125,6 @@ async function loadNotesAndRelations() { connection.getOverlay("label").setLabel(relation.name); connection.canvas.setAttribute("data-connection-id", connection.id); } - - initDone = true; }); } @@ -165,28 +164,40 @@ async function initJsPlumb () { instance.registerConnectionType("biDirectional", { anchor:"Continuous", connector:"StateMachine", overlays: biDirectionalOverlays }); - // instance.bind("connection", function (info) { - // const connection = info.connection; - // let name = "none"; - // - // if (initDone) { - // name = prompt("Specify new connection label:"); - // - // mapData.relations.push({ - // connectionId: connection.id, - // source: connection.sourceId, - // target: connection.targetId, - // name: name - // }); - // - // saveData(); - // } - // - // connection.getOverlay("label").setLabel(name); - // }); + instance.bind("connection", async function (info, originalEvent) { + // if there's no event, then this has been triggered programatically + if (!originalEvent) { + return; + } - jsPlumb.on($relationMapCanvas[0], "dblclick", function(e) { - newNode(jsPlumbUtil.uuid(),"new", e.offsetX, e.offsetY); + const name = prompt("Specify new relation name:"); + + if (!name || !name.trim()) { + return; + } + + const connection = info.connection; + + const targetNoteId = connection.target.id; + const sourceNoteId = connection.source.id; + + const existing = relations.some(rel => + rel.targetNoteId === targetNoteId + && rel.sourceNoteId === sourceNoteId + && rel.name === name); + + if (existing) { + alert("Connection '" + name + "' between these notes already exists."); + + return; + } + + await server.put(`notes/${sourceNoteId}/relations/${name}/to/${targetNoteId}`); + + relations.push({ targetNoteId, sourceNoteId, name }); + + connection.setType("uniDirectional"); + connection.getOverlay("label").setLabel(name); }); $relationMapCanvas.contextmenu({ diff --git a/src/routes/api/attributes.js b/src/routes/api/attributes.js index 159ce91ba..4e8da34af 100644 --- a/src/routes/api/attributes.js +++ b/src/routes/api/attributes.js @@ -107,11 +107,30 @@ async function getValuesForAttribute(req) { return await sql.getColumn("SELECT DISTINCT value FROM attributes WHERE isDeleted = 0 AND name = ? AND type = 'label' AND value != '' ORDER BY value", [attributeName]); } +async function createRelation(req) { + const sourceNoteId = req.params.noteId; + const targetNoteId = req.params.targetNoteId; + const name = req.params.name; + + let attribute = await repository.getEntity(`SELECT * FROM attributes WHERE isDeleted = 0 AND noteId = ? AND type = 'relation' AND name = ? AND value = ?`, [sourceNoteId, name, targetNoteId]); + + if (!attribute) { + attribute = new Attribute(); + attribute.noteId = sourceNoteId; + attribute.name = name; + attribute.type = 'relation'; + attribute.value = targetNoteId; + + await attribute.save(); + } +} + module.exports = { updateNoteAttributes, updateNoteAttribute, deleteNoteAttribute, getAttributeNames, getValuesForAttribute, - getEffectiveNoteAttributes + getEffectiveNoteAttributes, + createRelation }; \ No newline at end of file diff --git a/src/routes/routes.js b/src/routes/routes.js index 4625a3c09..2c565c36c 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -137,6 +137,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(PUT, '/api/notes/:noteId/relations/:name/to/:targetNoteId', attributesRoute.createRelation); apiRoute(DELETE, '/api/notes/:noteId/attributes/:attributeId', attributesRoute.deleteNoteAttribute); apiRoute(GET, '/api/attributes/names', attributesRoute.getAttributeNames); apiRoute(GET, '/api/attributes/values/:attributeName', attributesRoute.getValuesForAttribute);