| 
									
										
										
										
											2018-10-18 11:25:33 +02:00
										 |  |  | import server from "./server.js"; | 
					
						
							|  |  |  | import noteDetailService from "./note_detail.js"; | 
					
						
							| 
									
										
										
										
											2018-10-18 11:46:07 +02:00
										 |  |  | import libraryLoader from "./library_loader.js"; | 
					
						
							| 
									
										
										
										
											2018-10-18 11:25:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | const $noteDetailRelationMap = $("#note-detail-relation-map"); | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | const $relationMapCanvas = $("#relation-map-canvas"); | 
					
						
							| 
									
										
										
										
											2018-10-21 10:26:14 +02:00
										 |  |  | const $addChildNotesButton = $("#relation-map-add-child-notes"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | let mapData; | 
					
						
							|  |  |  | let instance; | 
					
						
							| 
									
										
										
										
											2018-10-29 22:38:51 +01:00
										 |  |  | // outside of mapData because they are not persisted in the note content
 | 
					
						
							|  |  |  | let relations; | 
					
						
							| 
									
										
										
										
											2018-10-18 11:25:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  | const uniDirectionalOverlays = [ | 
					
						
							|  |  |  |     [ "Arrow", { | 
					
						
							|  |  |  |         location: 1, | 
					
						
							|  |  |  |         id: "arrow", | 
					
						
							|  |  |  |         length: 14, | 
					
						
							|  |  |  |         foldback: 0.8 | 
					
						
							|  |  |  |     } ], | 
					
						
							|  |  |  |     [ "Label", { label: "", id: "label", cssClass: "aLabel" }] | 
					
						
							|  |  |  | ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const biDirectionalOverlays = [ | 
					
						
							|  |  |  |     [ "Arrow", { | 
					
						
							|  |  |  |         location: 1, | 
					
						
							|  |  |  |         id: "arrow", | 
					
						
							|  |  |  |         length: 14, | 
					
						
							|  |  |  |         foldback: 0.8 | 
					
						
							|  |  |  |     } ], | 
					
						
							|  |  |  |     [ "Label", { label: "", id: "label", cssClass: "aLabel" }], | 
					
						
							|  |  |  |     [ "Arrow", { | 
					
						
							|  |  |  |         location: 0, | 
					
						
							|  |  |  |         id: "arrow2", | 
					
						
							|  |  |  |         length: 14, | 
					
						
							|  |  |  |         direction: -1, | 
					
						
							|  |  |  |         foldback: 0.8 | 
					
						
							|  |  |  |     } ] | 
					
						
							|  |  |  | ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function loadMapData() { | 
					
						
							| 
									
										
										
										
											2018-10-21 10:26:14 +02:00
										 |  |  |     const currentNote = noteDetailService.getCurrentNote(); | 
					
						
							|  |  |  |     mapData = { | 
					
						
							|  |  |  |         notes: [], | 
					
						
							|  |  |  |         relations: [] | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (currentNote.content) { | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |             mapData = JSON.parse(currentNote.content); | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |         } catch (e) { | 
					
						
							| 
									
										
										
										
											2018-10-21 10:26:14 +02:00
										 |  |  |             console.log("Could not parse content: ", e); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-10-21 10:26:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  | async function show() { | 
					
						
							|  |  |  |     $noteDetailRelationMap.show(); | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |     await libraryLoader.requireLibrary(libraryLoader.RELATION_MAP); | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |     loadMapData(); | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |     jsPlumb.ready(initJsPlumb); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  | async function loadNotesAndRelations() { | 
					
						
							|  |  |  |     const noteIds = mapData.notes.map(note => note.id); | 
					
						
							|  |  |  |     const data = await server.post("notes/relation-map", {noteIds}); | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 22:38:51 +01:00
										 |  |  |     relations = []; | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |     for (const relation of data.relations) { | 
					
						
							|  |  |  |         const match = relations.find(rel => | 
					
						
							|  |  |  |             rel.name === relation.name | 
					
						
							|  |  |  |             && ((rel.sourceNoteId === relation.sourceNoteId && rel.targetNoteId === relation.targetNoteId) | 
					
						
							|  |  |  |             || (rel.sourceNoteId === relation.targetNoteId && rel.targetNoteId === relation.sourceNoteId))); | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |         if (match) { | 
					
						
							|  |  |  |             match.type = 'biDirectional'; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             relation.type = 'uniDirectional'; | 
					
						
							|  |  |  |             relations.push(relation); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |     mapData.notes = mapData.notes.filter(note => note.id in data.noteTitles); | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |     instance.batch(function () { | 
					
						
							|  |  |  |         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; | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |         for (const note of mapData.notes) { | 
					
						
							|  |  |  |             const title = data.noteTitles[note.id]; | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |             if (note.x && note.y) { | 
					
						
							|  |  |  |                 newNode(note.id, title, note.x, note.y); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 newNode(note.id, title, curX, curY); | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |                 if (curX > 1000) { | 
					
						
							|  |  |  |                     curX = 100; | 
					
						
							|  |  |  |                     curY += 200; | 
					
						
							|  |  |  |                 } else { | 
					
						
							|  |  |  |                     curX += 200; | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |         for (const relation of relations) { | 
					
						
							|  |  |  |             if (relation.name === 'isChildOf') { | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |             const connection = instance.connect({ | 
					
						
							|  |  |  |                 id: `${relation.sourceNoteId}${relation.targetNoteId}`, | 
					
						
							|  |  |  |                 source: relation.sourceNoteId, | 
					
						
							|  |  |  |                 target: relation.targetNoteId, | 
					
						
							|  |  |  |                 type: relation.type | 
					
						
							|  |  |  |             }); | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |             relation.connectionId = connection.id; | 
					
						
							| 
									
										
										
										
											2018-10-25 12:06:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |             connection.getOverlay("label").setLabel(relation.name); | 
					
						
							|  |  |  |             connection.canvas.setAttribute("data-connection-id", connection.id); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-10-25 14:01:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  | function initPanZoom() { | 
					
						
							|  |  |  |     const pz = panzoom($relationMapCanvas[0], { | 
					
						
							|  |  |  |         maxZoom: 2, | 
					
						
							|  |  |  |         minZoom: 0.1, | 
					
						
							|  |  |  |         smoothScroll: false | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-10-25 14:01:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |     if (mapData.transform) { | 
					
						
							|  |  |  |         pz.moveTo(mapData.transform.x, mapData.transform.y); | 
					
						
							|  |  |  |         pz.zoomTo(0, 0, mapData.transform.scale); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-10-25 14:01:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |     $relationMapCanvas[0].addEventListener('zoom', function (e) { | 
					
						
							|  |  |  |         mapData.transform = pz.getTransform(); | 
					
						
							|  |  |  |         saveData(); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |     $relationMapCanvas[0].addEventListener('panend', function (e) { | 
					
						
							|  |  |  |         mapData.transform = pz.getTransform(); | 
					
						
							|  |  |  |         saveData(); | 
					
						
							|  |  |  |     }, true); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-10-25 14:01:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  | async function initJsPlumb () { | 
					
						
							|  |  |  |     instance = jsPlumb.getInstance({ | 
					
						
							|  |  |  |         Endpoint: ["Dot", {radius: 2}], | 
					
						
							|  |  |  |         Connector: "StateMachine", | 
					
						
							|  |  |  |         HoverPaintStyle: {stroke: "#1e8151", strokeWidth: 2 }, | 
					
						
							|  |  |  |         Container: "relation-map-canvas" | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-25 12:06:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |     instance.registerConnectionType("uniDirectional", { anchor:"Continuous", connector:"StateMachine", overlays: uniDirectionalOverlays }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     instance.registerConnectionType("biDirectional", { anchor:"Continuous", connector:"StateMachine", overlays: biDirectionalOverlays }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 22:38:51 +01:00
										 |  |  |     instance.bind("connection", async function (info, originalEvent) { | 
					
						
							|  |  |  |         // if there's no event, then this has been triggered programatically
 | 
					
						
							|  |  |  |         if (!originalEvent) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         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); | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     $relationMapCanvas.contextmenu({ | 
					
						
							|  |  |  |         delegate: ".note-box", | 
					
						
							|  |  |  |         menu: [ | 
					
						
							|  |  |  |             {title: "Remove note", cmd: "remove", uiIcon: "ui-icon-trash"}, | 
					
						
							|  |  |  |             {title: "Edit title", cmd: "edit-title", uiIcon: "ui-icon-pencil"}, | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |         select: noteContextMenuHandler | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |     $.widget("moogle.contextmenuRelation", $.moogle.contextmenu, {}); | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |     $relationMapCanvas.contextmenuRelation({ | 
					
						
							|  |  |  |         delegate: ".aLabel,.jtk-connector", | 
					
						
							|  |  |  |         autoTrigger: false, // it doesn't open automatically, needs to be triggered explicitly by .open() call
 | 
					
						
							|  |  |  |         menu: [ | 
					
						
							|  |  |  |             {title: "Remove relation", cmd: "remove", uiIcon: "ui-icon-trash"}, | 
					
						
							|  |  |  |             {title: "Edit relation name", cmd: "edit-name", uiIcon: "ui-icon-pencil"}, | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |         select: relationContextMenuHandler | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     instance.bind("contextmenu", function (c, e) { | 
					
						
							|  |  |  |         e.preventDefault(); | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |         $relationMapCanvas.contextmenuRelation("open", e, { connection: c }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     await loadNotesAndRelations(); | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |     // so that canvas is not panned when clicking/dragging note box
 | 
					
						
							|  |  |  |     $relationMapCanvas.on('mousedown touchstart', '.note-box, .aLabel', e => e.stopPropagation()); | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |     jsPlumb.fire("jsPlumbDemoLoaded", instance); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     initPanZoom(); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-10-18 11:53:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  | function relationContextMenuHandler(event, ui) { | 
					
						
							|  |  |  |     const {connection} = ui.extraData; | 
					
						
							| 
									
										
										
										
											2018-10-25 15:45:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |     if (ui.cmd === 'remove') { | 
					
						
							|  |  |  |         if (!confirm("Are you sure you want to remove the relation?")) { | 
					
						
							|  |  |  |             return; | 
					
						
							| 
									
										
										
										
											2018-10-25 15:45:14 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |         instance.deleteConnection(connection); | 
					
						
							| 
									
										
										
										
											2018-10-25 15:45:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 19:25:45 +01:00
										 |  |  |         mapData.relations = mapData.relations.filter(relation => relation.connectionId !== connection.id); | 
					
						
							|  |  |  |         saveData(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (ui.cmd === 'edit-name') { | 
					
						
							|  |  |  |         const relationName = prompt("Specify new relation name:"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         connection.getOverlay("label").setLabel(relationName); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const relation = mapData.relations.find(relation => relation.connectionId === connection.id); | 
					
						
							|  |  |  |         relation.name = relationName; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         saveData(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function noteContextMenuHandler(event, ui) { | 
					
						
							|  |  |  |     const $noteBox = ui.target.closest(".note-box"); | 
					
						
							|  |  |  |     const noteId = $noteBox.prop("id"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (ui.cmd === "remove") { | 
					
						
							|  |  |  |         if (!confirm("Are you sure you want to remove the note?")) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         instance.remove(noteId); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         mapData.notes = mapData.notes.filter(note => note.id !== noteId); | 
					
						
							|  |  |  |         mapData.relations = mapData.relations.filter(relation => relation.source !== noteId && relation.target !== noteId); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         saveData(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (ui.cmd === "edit-title") { | 
					
						
							|  |  |  |         const title = prompt("Enter new note title:"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!title) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const note = mapData.notes.find(note => note.id === noteId); | 
					
						
							|  |  |  |         note.title = title; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $noteBox.find(".title").text(note.title); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         saveData(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-10-18 11:25:33 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-21 10:26:14 +02:00
										 |  |  | function saveData() { | 
					
						
							| 
									
										
										
										
											2018-10-25 15:45:14 +02:00
										 |  |  |     noteDetailService.noteChanged(); | 
					
						
							| 
									
										
										
										
											2018-10-21 10:26:14 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-25 14:01:03 +02:00
										 |  |  | function newNode(id, title, x, y) { | 
					
						
							| 
									
										
										
										
											2018-10-21 10:26:14 +02:00
										 |  |  |     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") | 
					
						
							| 
									
										
										
										
											2018-10-25 14:01:03 +02:00
										 |  |  |         .css("top", y + "px"); | 
					
						
							| 
									
										
										
										
											2018-10-21 10:26:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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) { | 
					
						
							| 
									
										
										
										
											2018-10-25 12:06:36 +02:00
										 |  |  |         if (mapData.notes.some(note => note.id === child.noteId)) { | 
					
						
							|  |  |  |             // note already exists
 | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-25 14:01:03 +02:00
										 |  |  |         const note = { id: child.noteId }; | 
					
						
							| 
									
										
										
										
											2018-10-21 10:26:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         mapData.notes.push(note); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-25 14:01:03 +02:00
										 |  |  |         newNode(note.id, note.title, curX, curY); | 
					
						
							| 
									
										
										
										
											2018-10-21 10:26:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         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(); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 11:25:33 +02:00
										 |  |  | export default { | 
					
						
							| 
									
										
										
										
											2018-10-18 11:46:07 +02:00
										 |  |  |     show, | 
					
						
							| 
									
										
										
										
											2018-10-21 10:26:14 +02:00
										 |  |  |     getContent: () => JSON.stringify(mapData), | 
					
						
							| 
									
										
										
										
											2018-10-18 11:25:33 +02:00
										 |  |  |     focus: () => null, | 
					
						
							|  |  |  |     onNoteChange: () => null | 
					
						
							|  |  |  | } |