mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 02:16:05 +01:00 
			
		
		
		
	add children to relation map
This commit is contained in:
		| @@ -4,14 +4,34 @@ import libraryLoader from "./library_loader.js"; | ||||
|  | ||||
| const $noteDetailRelationMap = $("#note-detail-relation-map"); | ||||
| const $relationMapCanvas = $("#relation-map-canvas"); | ||||
| const $addChildNotesButton = $("#relation-map-add-child-notes"); | ||||
|  | ||||
| let mapData; | ||||
| let instance; | ||||
| let initDone = false; | ||||
|  | ||||
| async function show() { | ||||
|     $noteDetailRelationMap.show(); | ||||
|  | ||||
|     await libraryLoader.requireLibrary(libraryLoader.RELATION_MAP); | ||||
|  | ||||
|     const currentNote = noteDetailService.getCurrentNote(); | ||||
|     mapData = { | ||||
|         notes: [], | ||||
|         relations: [] | ||||
|     }; | ||||
|  | ||||
|     if (currentNote.content) { | ||||
|         try { | ||||
|             mapData = JSON.parse(currentNote.content); | ||||
|         } | ||||
|         catch (e) { | ||||
|             console.log("Could not parse content: ", e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     jsPlumb.ready(function () { | ||||
|         const instance = jsPlumb.getInstance({ | ||||
|         instance = jsPlumb.getInstance({ | ||||
|             Endpoint: ["Dot", {radius: 2}], | ||||
|             Connector: "StateMachine", | ||||
|             HoverPaintStyle: {stroke: "#1e8151", strokeWidth: 2 }, | ||||
| @@ -29,156 +49,30 @@ async function show() { | ||||
|  | ||||
|         instance.registerConnectionType("basic", { anchor:"Continuous", connector:"StateMachine" }); | ||||
|  | ||||
|         window.jsp = instance; | ||||
|  | ||||
|         let data; | ||||
|         let initDone = false; | ||||
|  | ||||
|         instance.bind("connection", function (info) { | ||||
|             const connection = info.connection; | ||||
|             let type; | ||||
|  | ||||
|             if (initDone) { | ||||
|                 type = prompt("Specify new connection label:"); | ||||
|  | ||||
|                 data.relations.push({ | ||||
|                     connectionId: connection.id, | ||||
|                     source: connection.sourceId, | ||||
|                     target: connection.targetId, | ||||
|                     type: type | ||||
|                 }); | ||||
|  | ||||
|                 saveData(); | ||||
|             } | ||||
|             else { | ||||
|                 type = "none"; | ||||
|             } | ||||
|  | ||||
|             connection.getOverlay("label").setLabel(type); | ||||
|         }); | ||||
|         // 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); | ||||
|         // }); | ||||
|  | ||||
|         jsPlumb.on($relationMapCanvas[0], "dblclick", function(e) { | ||||
|             newNode(jsPlumbUtil.uuid(),"new", e.offsetX, e.offsetY, "auto", "auto"); | ||||
|         }); | ||||
|  | ||||
|         function saveData() { | ||||
|             localStorage.setItem('triliumData', JSON.stringify(data)); | ||||
|         } | ||||
|  | ||||
|         function initNode(el) { | ||||
|             instance.draggable(el, { | ||||
|                 handle: ".handle", | ||||
|                 start:function(params) { | ||||
|                 }, | ||||
|                 drag:function(params) { | ||||
|  | ||||
|                 }, | ||||
|                 stop:function(params) { | ||||
|                     const note = data.notes.find(note => note.id === params.el.id); | ||||
|  | ||||
|                     if (!note) { | ||||
|                         console.error(`Note ${params.el.id} not found!`); | ||||
|                         return; | ||||
|                     } | ||||
|  | ||||
|                     [note.x, note.y] = params.finalPos; | ||||
|  | ||||
|                     saveData(); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|             instance.makeSource(el, { | ||||
|                 filter: ".endpoint", | ||||
|                 anchor: "Continuous", | ||||
|                 connectorStyle: { stroke: "#5c96bc", strokeWidth: 2, outlineStroke: "transparent", outlineWidth: 4 }, | ||||
|                 connectionType:"basic", | ||||
|                 extract:{ | ||||
|                     "action":"the-action" | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|             instance.makeTarget(el, { | ||||
|                 dropOptions: { hoverClass: "dragHover" }, | ||||
|                 anchor: "Continuous", | ||||
|                 allowLoopback: true | ||||
|             }); | ||||
|  | ||||
|             // this is not part of the core demo functionality; it is a means for the Toolkit edition's wrapped | ||||
|             // version of this demo to find out about new nodes being added. | ||||
|             // | ||||
|             instance.fire("jsPlumbDemoNodeAdded", el); | ||||
|  | ||||
|             $(el).resizable({ | ||||
|                 resize: function(event, ui) { | ||||
| //                instance.repaint(ui.helper.prop("id")); | ||||
|  | ||||
|                     instance.repaintEverything(); | ||||
|                 }, | ||||
|                 stop: function(event, ui) { | ||||
|                     const note = data.notes.find(note => note.id === ui.helper.prop("id")); | ||||
|  | ||||
|                     note.width = ui.helper.width(); | ||||
|                     note.height = ui.helper.height(); | ||||
|  | ||||
|                     saveData(); | ||||
|                 }, | ||||
|                 handles: "all" | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         function newNode(id, title, x, y, width, height) { | ||||
|             const $noteBox = $("<div>") | ||||
|                 .addClass("note-box") | ||||
|                 .prop("id", id) | ||||
|                 .append($("<div>").addClass("handle")) | ||||
|                 .append($("<span>").addClass("title").text(title)) | ||||
|                 .append($("<div>").addClass("endpoint")) | ||||
|                 .css("left", x + "px") | ||||
|                 .css("top", y + "px") | ||||
|                 .css("width", width) | ||||
|                 .css("height", height); | ||||
|  | ||||
|             instance.getContainer().appendChild($noteBox[0]); | ||||
|  | ||||
|             initNode($noteBox[0]); | ||||
|         } | ||||
|  | ||||
|         const notes = [ | ||||
|             { id: "eliI", title: "Queen Elizabeth", x: 100, y: 100 }, | ||||
|             { id: "kinggeorge", title: "King George VI.", x: 300, y: 100 }, | ||||
|             { id: "phillip", title: "Prince Phillip" }, | ||||
|             { id: "eliII", title: "Queen Elizabeth II.", x: 300, y: 300 }, | ||||
|             { id: "charles", title: "Prince Charles" }, | ||||
|             { id: "diana", title: "Princess Diana" }, | ||||
|             { id: "harry", title: "Prince Harry" }, | ||||
|             { id: "william", title: "Prince William "} | ||||
|         ]; | ||||
|  | ||||
|         const relations = [ | ||||
|             { source: "eliI", target: "kinggeorge", type: "isSpouse" }, | ||||
|             { source: "eliI", target: "eliII", type: "hasChild" }, | ||||
|             { source: "kinggeorge", target: "eliII", type: "hasChild" }, | ||||
|             { source: "eliII", target: "charles", type: "hasChild" }, | ||||
|             { source: "phillip", target: "charles", type: "hasChild" }, | ||||
|             { source: "phillip", target: "eliII", type: "isSpouse" }, | ||||
|             { source: "charles", target: "diana", type: "isSpouse" }, | ||||
|             { source: "charles", target: "william", type: "hasChild" }, | ||||
|             { source: "charles", target: "harry", type: "hasChild" }, | ||||
|             { source: "diana", target: "william", type: "hasChild" }, | ||||
|             { source: "diana", target: "harry", type: "hasChild" } | ||||
|         ]; | ||||
|  | ||||
|         data = localStorage.getItem('triliumData'); | ||||
|  | ||||
|         if (data) { | ||||
|             data = JSON.parse(data); | ||||
|         } | ||||
|         else { | ||||
|             data = { notes, relations }; | ||||
|  | ||||
|             saveData(); | ||||
|         } | ||||
|  | ||||
|         $relationMapCanvas.contextmenu({ | ||||
|             delegate: ".note-box", | ||||
|             menu: [ | ||||
| @@ -196,8 +90,8 @@ async function show() { | ||||
|  | ||||
|                     instance.remove(noteId); | ||||
|  | ||||
|                     data.notes = data.notes.filter(note => note.id !== noteId); | ||||
|                     data.relations = data.relations.filter(relation => relation.source !== noteId && relation.target !== noteId); | ||||
|                     mapData.notes = mapData.notes.filter(note => note.id !== noteId); | ||||
|                     mapData.relations = mapData.relations.filter(relation => relation.source !== noteId && relation.target !== noteId); | ||||
|  | ||||
|                     saveData(); | ||||
|                 } | ||||
| @@ -208,7 +102,7 @@ async function show() { | ||||
|                         return; | ||||
|                     } | ||||
|  | ||||
|                     const note = data.notes.find(note => note.id === noteId); | ||||
|                     const note = mapData.notes.find(note => note.id === noteId); | ||||
|                     note.title = title; | ||||
|  | ||||
|                     $noteBox.find(".title").text(note.title); | ||||
| @@ -237,7 +131,7 @@ async function show() { | ||||
|  | ||||
|                     instance.deleteConnection(connection); | ||||
|  | ||||
|                     data.relations = data.relations.filter(relation => relation.connectionId !== connection.id); | ||||
|                     mapData.relations = mapData.relations.filter(relation => relation.connectionId !== connection.id); | ||||
|                     saveData(); | ||||
|                 } | ||||
|                 else if (ui.cmd === 'edit-name') { | ||||
| @@ -245,8 +139,8 @@ async function show() { | ||||
|  | ||||
|                     connection.getOverlay("label").setLabel(relationName); | ||||
|  | ||||
|                     const relation = data.relations.find(relation => relation.connectionId === connection.id); | ||||
|                     relation.type = relationName; | ||||
|                     const relation = mapData.relations.find(relation => relation.connectionId === connection.id); | ||||
|                     relation.name = relationName; | ||||
|  | ||||
|                     saveData(); | ||||
|                 } | ||||
| @@ -260,11 +154,11 @@ async function show() { | ||||
|         }); | ||||
|  | ||||
|         instance.batch(function () { | ||||
|             const maxY = notes.filter(note => !!note.y).map(note => note.y).reduce((a, b) => Math.max(a, b)); | ||||
|             const maxY = mapData.notes.filter(note => !!note.y).map(note => note.y).reduce((a, b) => Math.max(a, b), 0); | ||||
|             let curX = 100; | ||||
|             let curY = maxY + 200; | ||||
|  | ||||
|             for (const note of data.notes) { | ||||
|             for (const note of mapData.notes) { | ||||
|                 if (note.x && note.y) { | ||||
|                     newNode(note.id, note.title, note.x, note.y, note.width + "px", note.height + "px"); | ||||
|                 } | ||||
| @@ -284,12 +178,12 @@ async function show() { | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             for (const relation of data.relations) { | ||||
|                 const connection = instance.connect({ id: relation.id, source: relation.source, target: relation.target, type:"basic" }); | ||||
|             for (const relation of mapData.relations) { | ||||
|                 const connection = instance.connect({ id: relation.id, source: relation.source, target: relation.target, type: "basic" }); | ||||
|  | ||||
|                 relation.connectionId = connection.id; | ||||
|  | ||||
|                 connection.getOverlay("label").setLabel(relation.type); | ||||
|                 connection.getOverlay("label").setLabel(relation.name); | ||||
|                 connection.canvas.setAttribute("data-connection-id", connection.id); | ||||
|             } | ||||
|  | ||||
| @@ -305,9 +199,155 @@ async function show() { | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function saveData() { | ||||
|     const currentNote = noteDetailService.getCurrentNote(); | ||||
|  | ||||
|     noteDetailService.saveNote(); | ||||
| } | ||||
|  | ||||
| function initNode(el) { | ||||
|     instance.draggable(el, { | ||||
|         handle: ".handle", | ||||
|         start:function(params) { | ||||
|         }, | ||||
|         drag:function(params) { | ||||
|  | ||||
|         }, | ||||
|         stop:function(params) { | ||||
|             const note = mapData.notes.find(note => note.id === params.el.id); | ||||
|  | ||||
|             if (!note) { | ||||
|                 console.error(`Note ${params.el.id} not found!`); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             [note.x, note.y] = params.finalPos; | ||||
|  | ||||
|             saveData(); | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     instance.makeSource(el, { | ||||
|         filter: ".endpoint", | ||||
|         anchor: "Continuous", | ||||
|         connectorStyle: { | ||||
|             stroke: "#5c96bc", | ||||
|             strokeWidth: 2, | ||||
|             outlineStroke: "transparent", | ||||
|             outlineWidth: 4 | ||||
|         }, | ||||
|         connectionType: "basic", | ||||
|         extract:{ | ||||
|             "action": "the-action" | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     instance.makeTarget(el, { | ||||
|         dropOptions: { hoverClass: "dragHover" }, | ||||
|         anchor: "Continuous", | ||||
|         allowLoopback: true | ||||
|     }); | ||||
|  | ||||
|     // this is not part of the core demo functionality; it is a means for the Toolkit edition's wrapped | ||||
|     // version of this demo to find out about new nodes being added. | ||||
|     // | ||||
|     instance.fire("jsPlumbDemoNodeAdded", el); | ||||
|  | ||||
|     $(el).resizable({ | ||||
|         resize: function(event, ui) { | ||||
| //                instance.repaint(ui.helper.prop("id")); | ||||
|  | ||||
|             instance.repaintEverything(); | ||||
|         }, | ||||
|         stop: function(event, ui) { | ||||
|             const note = mapData.notes.find(note => note.id === ui.helper.prop("id")); | ||||
|  | ||||
|             note.width = ui.helper.width(); | ||||
|             note.height = ui.helper.height(); | ||||
|  | ||||
|             saveData(); | ||||
|         }, | ||||
|         handles: "all" | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function newNode(id, title, x, y, width, height) { | ||||
|     const $noteBox = $("<div>") | ||||
|         .addClass("note-box") | ||||
|         .prop("id", id) | ||||
|         .append($("<div>").addClass("handle")) | ||||
|         .append($("<span>").addClass("title").text(title)) | ||||
|         .append($("<div>").addClass("endpoint")) | ||||
|         .css("left", x + "px") | ||||
|         .css("top", y + "px") | ||||
|         .css("width", width) | ||||
|         .css("height", height); | ||||
|  | ||||
|     instance.getContainer().appendChild($noteBox[0]); | ||||
|  | ||||
|     initNode($noteBox[0]); | ||||
| } | ||||
|  | ||||
| $addChildNotesButton.click(async () => { | ||||
|     const children = await server.get("notes/" + noteDetailService.getCurrentNoteId() + "/children"); | ||||
|  | ||||
|     const maxY = mapData.notes.filter(note => !!note.y).map(note => note.y).reduce((a, b) => Math.max(a, b), 0); | ||||
|     let curX = 100; | ||||
|     let curY = maxY + 200; | ||||
|  | ||||
|     for (const child of children) { | ||||
|         const note = { | ||||
|             id: child.noteId, | ||||
|             title: child.title, | ||||
|             width: "auto", | ||||
|             height: "auto" | ||||
|         }; | ||||
|  | ||||
|         mapData.notes.push(note); | ||||
|  | ||||
|         newNode(note.id, note.title, curX, curY, note.width, note.height); | ||||
|  | ||||
|         if (curX > 1000) { | ||||
|             curX = 100; | ||||
|             curY += 200; | ||||
|         } | ||||
|         else { | ||||
|             curX += 200; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     for (const child of children) { | ||||
|         for (const relation of child.relations) { | ||||
|             const connection = instance.connect({ | ||||
|                 id: relation.attributeId, | ||||
|                 source: child.noteId, | ||||
|                 target: relation.targetNoteId, | ||||
|                 type: "basic" | ||||
|             }); | ||||
|  | ||||
|             if (!connection) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             mapData.relations.push({ | ||||
|                 source: child.noteId, | ||||
|                 target: relation.targetNoteId, | ||||
|                 name: relation.name | ||||
|             }); | ||||
|  | ||||
|             relation.connectionId = connection.id; | ||||
|  | ||||
|             connection.getOverlay("label").setLabel(relation.name); | ||||
|             connection.canvas.setAttribute("data-connection-id", connection.id); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     saveData(); | ||||
| }); | ||||
|  | ||||
| export default { | ||||
|     show, | ||||
|     getContent: () => "", | ||||
|     getContent: () => JSON.stringify(mapData), | ||||
|     focus: () => null, | ||||
|     onNoteChange: () => null | ||||
| } | ||||
		Reference in New Issue
	
	Block a user