@dualbox/editor 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/js/src/GraphEditor.js +159 -0
  2. package/js/src/c/GraphController.js +646 -0
  3. package/js/src/libs/CodeMirror.js +8 -0
  4. package/js/src/libs/fontawesome.js +1 -0
  5. package/js/src/libs/jsoneditor.css +2 -0
  6. package/js/src/libs/jsoneditor.js +4 -0
  7. package/js/src/m/DualboxUtils.js +35 -0
  8. package/js/src/m/GraphModel.js +2167 -0
  9. package/js/src/m/History.js +94 -0
  10. package/js/src/m/Merger.js +357 -0
  11. package/js/src/v/AppManager.js +61 -0
  12. package/js/src/v/CanvasSizeHandler.js +136 -0
  13. package/js/src/v/ContextMenu.css +45 -0
  14. package/js/src/v/ContextMenu.js +239 -0
  15. package/js/src/v/GraphView.js +928 -0
  16. package/js/src/v/PlumbStyle.js +254 -0
  17. package/js/src/v/Selector.js +239 -0
  18. package/js/src/v/TemplateManager.js +79 -0
  19. package/js/src/v/Translater.js +174 -0
  20. package/js/src/v/Utils.js +7 -0
  21. package/js/src/v/Zoomer.js +201 -0
  22. package/js/src/v/templates/addNode.css +45 -0
  23. package/js/src/v/templates/addNode.html +62 -0
  24. package/js/src/v/templates/addNode.js +34 -0
  25. package/js/src/v/templates/debugNodeInfos.css +5 -0
  26. package/js/src/v/templates/debugNodeInfos.html +336 -0
  27. package/js/src/v/templates/debugNodeInfos.js +31 -0
  28. package/js/src/v/templates/editMainSettings.css +67 -0
  29. package/js/src/v/templates/editMainSettings.html +265 -0
  30. package/js/src/v/templates/editMainSettings.js +240 -0
  31. package/js/src/v/templates/editNodeSettings.css +86 -0
  32. package/js/src/v/templates/editNodeSettings.html +539 -0
  33. package/js/src/v/templates/editNodeSettings.js +356 -0
  34. package/js/src/v/templates/graphNode.css +333 -0
  35. package/js/src/v/templates/graphNode.html +227 -0
  36. package/js/src/v/templates/graphNode.js +412 -0
  37. package/js/src/v/templates/main.css +353 -0
  38. package/js/src/v/templates/main.html +149 -0
  39. package/js/src/v/templates/main.js +511 -0
  40. package/js/src/v/templates/searchResults.css +50 -0
  41. package/js/src/v/templates/searchResults.html +46 -0
  42. package/js/src/v/templates/searchResults.js +176 -0
  43. package/package.json +3 -2
@@ -0,0 +1,227 @@
1
+ @{ var utils = require('../../m/DualboxUtils') }
2
+
3
+ @!(data)
4
+ @{ var id = data.example ? data.id + "-junk" : data.id; }
5
+ <div class="jtk-node card card-node @cardColor(data.id) @cardLoop(data.id) @cardSnapshot(data.id) contextmenu" id="@(id)" data-id="@(data.id)" data-name="@(data.pkg.name)" style="overflow: visible;">
6
+ @if( data.n.hasComment() ) {
7
+ <div class="card-comment">
8
+ <i class="fas fa-comment-alt" data-container="body" data-toggle="popover" data-placement="top" data-content="@(data.n.getComment())"></i>
9
+ </div>
10
+ }
11
+
12
+ @if( data.n.hasSnapshot() ) {
13
+ <div class="card-status">
14
+ @if( data.n.isSnapshotStatus(0) ) {
15
+ <div class="card-status-idle">
16
+ <span>IDLE</span>
17
+ <button class="btn btn-xs btn-outline-secondary btn-outline-discrete btn-snapshot-details d-inline-block" data-id="@(data.id)"><i class="fas fa-info-circle"></i></button>
18
+ </div>
19
+ }
20
+ @if( data.n.isSnapshotStatus(1) ) {
21
+ <div class="card-status-computing">
22
+ <span>COMPUTING</span>
23
+ <button class="btn btn-xs btn-outline-secondary btn-outline-discrete btn-snapshot-details d-inline-block" data-id="@(data.id)"><i class="fas fa-info-circle"></i></button>
24
+ </div>
25
+ }
26
+ @if( data.n.isSnapshotStatus(2) ) {
27
+ <div class="card-status-awaiting-data">
28
+ <span>WAITING</span>
29
+ <button class="btn btn-xs btn-outline-secondary btn-outline-discrete btn-snapshot-details d-inline-block" data-id="@(data.id)"><i class="fas fa-info-circle"></i></button>
30
+ </div>
31
+ }
32
+ @if( data.n.isSnapshotStatus(3) ) {
33
+ <div class="card-status-ready">
34
+ <span>READY</span>
35
+ <button class="btn btn-xs btn-outline-secondary btn-outline-discrete btn-snapshot-details d-inline-block" data-id="@(data.id)"><i class="fas fa-info-circle"></i></button>
36
+ </div>
37
+ }
38
+ </div>
39
+ }
40
+
41
+ @if( !data.example && data.n.isUI() && !data.n.isOnAPanel() ) {
42
+ <div class="card-problem">
43
+ <i class="fas fa-exclamation-circle" data-container="body" data-toggle="popover" data-placement="top" data-content="This UI is not set in a panel. It won't have any effect. Go to the Interface tab to add it to a panel."></i>
44
+ </div>
45
+ }
46
+
47
+ <div class="card-top">
48
+ <div class="d-flex">
49
+ <span class="title" style="white-space: nowrap; margin-right: 5px;">
50
+ @if( data.n.isMetanode() ) { <span class="badge badge-secondary"><b>META</b></span> }
51
+ @(data.n.graphId)
52
+ @if( data.n.isParallel() ) { <i class="fas fa-server" style="color: orange;" title="this module is computed in a web worker"></i> }
53
+ </span>
54
+
55
+ <div class="ml-auto">
56
+ <button class="btn btn-outline-secondary btn-outline-discrete btn-xs btn-settings"><i class="fas fa-cog"></i></button>
57
+ </div>
58
+ </div>
59
+ </div>
60
+ @if( !data.n.isInput() && !data.n.isOutput() ) {
61
+ <div class="card-center">
62
+ <hr style="margin-bottom: 5px;"/>
63
+ <div class="dualbox-io" style="overflow: visible;">
64
+ <div class="inputs" style="display: inline-block; float: left;">
65
+ <div class="box-inputs">
66
+ @{var keys = data.n.getInputsNames(); }
67
+ @if( keys && keys.length > 0 ) {
68
+ <div class="types">
69
+ @* Build types *@
70
+ @for(var i=0; i<keys.length; i++) {
71
+ @{var key = keys[i] }
72
+ @{var inputDesc = data.n.getInputDef(key); }
73
+ @if( data.n.isInputVisible(key) ) {
74
+ <span class="type" data-key="@key">@( data.utils.htmlentities(data.n.getInputType(key)) )</span>
75
+ }
76
+ }
77
+ </div>
78
+
79
+ <div class="points">
80
+ @* Build points *@
81
+ @for(var i=0; i<keys.length; i++) {
82
+ @{var key = keys[i] }
83
+ @{var inputDesc = data.n.getInputDef(key); }
84
+ @if( data.n.isInputVisible(key) ) {
85
+ <div class="point" data-key="@key" data-type="@(inputDesc.type)">@point()</div>
86
+ }
87
+ }
88
+ </div>
89
+ <div class="names">
90
+ @* Build names *@
91
+ @for(var i=0; i<keys.length; i++) {
92
+ @{var key = keys[i] }
93
+ @{var inputDesc = data.n.getInputDesc(key); }
94
+ @if( data.n.isInputVisible(key) ) {
95
+ <span class="name @if(data.n.isFeedbackTarget(key)){feedback}" data-input="@(key)">
96
+ @if( data.n.hasIterator(key) ) {
97
+ &lt;@(key)&gt;
98
+ }
99
+ else {
100
+ @(key)
101
+ }
102
+ @if( !data.n.isInputConst(key) ) {
103
+ <small><i class="fas fa-clone transparent"></i></small>
104
+ }
105
+ </span>
106
+ }
107
+ }
108
+ </div>
109
+ }
110
+ </div>
111
+ </div>
112
+ <div class="outputs" style="display: inline-block; float: right">
113
+ <div class="box-outputs">
114
+ @{var keys = data.n.getOutputsNames() }
115
+ @if( keys && keys.length > 0 ) {
116
+ <div class="names">
117
+ @* Build names *@
118
+ @for(var i=0; i<keys.length; i++) {
119
+ @{var key = keys[i] }
120
+ @if( data.n.isOutputVisible(key) ) {
121
+ <span class="name @if(data.n.hasFeedback(key)){feedback}" data-output="@(key)">
122
+ @if( data.n.hasLoop() ) {
123
+ @if( data.n.hasFeedback(key) ) {
124
+ @(key)
125
+ }
126
+ else {
127
+ &lt;@(key)&gt;
128
+ }
129
+ }
130
+ else {
131
+ @(key)
132
+ }
133
+
134
+ @if( data.n.hasCacheActivated() ) {
135
+ &nbsp;<i class="fa fa-hdd" title="This module has cache activated"></i>
136
+ }
137
+ </span>
138
+ }
139
+ }
140
+ </div>
141
+
142
+ <div class="points">
143
+ @* Build points *@
144
+ @for(var i=0; i<keys.length; i++) {
145
+ @{var key = keys[i] }
146
+ @{var outputDesc = data.n.getOutputDef(key); }
147
+ @if( data.n.isOutputVisible(key) ) {
148
+ <div class="point" data-key="@key" data-type="@(outputDesc.type)">@point()</div>
149
+ }
150
+ }
151
+ </div>
152
+
153
+ <div class="types">
154
+ @* Build types *@
155
+ @for(var i=0; i<keys.length; i++) {
156
+ @{var key = keys[i] }
157
+ @{var outputDesc = data.n.getOutputDef(key); }
158
+ @if( data.n.isOutputVisible(key) ) {
159
+ <span class="type" data-key="@key">@( data.utils.htmlentities(data.n.getOutputType(key)) )</span>
160
+ }
161
+ }
162
+ </div>
163
+ }
164
+ </div>
165
+ </div>
166
+ </div>
167
+ </div>
168
+ }
169
+ <hr style="margin-top: 5px;"/>
170
+ <div class="card-bottom">
171
+ <span class="subtitle">@( data.utils.htmlentities(shortname(data.id, data.pkg.name)) )</span>
172
+ @if( data.n.isMetanode() ) {
173
+ <div class="d-inline-block">
174
+ <button class="btn btn-outline-secondary btn-outline-discrete btn-xs btn-enter-metanode"><i class="fas fa-sign-in-alt"></i></button>
175
+ </div>
176
+ }
177
+
178
+ <!--
179
+ @if( data.n.isUI() ) {
180
+ <div class="event-dock event-dock-bottom"></div>
181
+ }
182
+ -->
183
+ </div>
184
+ </div>
185
+
186
+ @function cardColor( id ) {
187
+ @if( data.n.isUI() ) { card-ui }
188
+ else if( data.n.isMetanode() ) { card-metanode }
189
+ else if( data.n.isInput() ) { card-input }
190
+ else if( data.n.isOutput() ) { card-output }
191
+ }
192
+
193
+ @function cardLoop( id ) {
194
+ @if( data.n.hasLoop() ) { card-loop }
195
+ }
196
+
197
+ @function cardSnapshot(id) {
198
+ @if( data.n.hasSnapshot() ) {
199
+ card-snapshot
200
+ @if( data.n.isSnapshotStatus(0) ) {
201
+ card-snapshot-idle
202
+ }
203
+ @if( data.n.isSnapshotStatus(1) ) {
204
+ card-snapshot-computing
205
+ }
206
+ @if( data.n.isSnapshotStatus(2) ) {
207
+ card-snapshot-awaiting-data
208
+ }
209
+ @if( data.n.isSnapshotStatus(3) ) {
210
+ card-snapshot-ready
211
+ }
212
+ }
213
+ }
214
+
215
+ @function shortname( id, pkgName ) {
216
+ @if( data.n.isInput() || data.n.isOutput() ) {
217
+ @( data.n.getType() )
218
+ }
219
+ else {
220
+ @{ var shortname = utils.shortName(pkgName) }
221
+ @(shortname)
222
+ }
223
+ }
224
+
225
+ @function point() {
226
+ <svg width="14" height="14" pointer-events="all" position="absolute" version="1.1" xmlns="http://www.w3.org/1999/xhtml"><circle cx="7" cy="7" r="5" version="1.1" xmlns="http://www.w3.org/1999/xhtml" fill="#ffffff" stroke="#727272" style="" stroke-width="2"></circle></svg>
227
+ }
@@ -0,0 +1,412 @@
1
+ const ContextMenu = require('../ContextMenu');
2
+ const _ = require('lodash');
3
+
4
+ // fix inputs types and output types position relatively to the div
5
+ $.fn.fixCardDisplay = function() {
6
+ var offsetPoint = 12;
7
+ var offsetBorder = parseInt($(this).css("border-top-width"));
8
+
9
+ if( $(this).find('.box-inputs').height() === 0 && $(this).find('.box-outputs').height() === 0 ) {
10
+ // if this card has no input/output, remove the card center
11
+ $(this).find('.card-center').remove();
12
+ }
13
+ else {
14
+ // else, adjust the input/output display for endpoints
15
+ // 1) translate inputs by the right amount of pixels to have the circle on the line
16
+ var boxInputs = $(this).find('.box-inputs');
17
+
18
+ // fix css names width
19
+ var namesDiv = boxInputs.find('.names');
20
+ namesDiv.css('width', (namesDiv.width()+1) + 'px');
21
+
22
+ // translate inputs to the left
23
+ var translateLeft = boxInputs.find('.types').width() + offsetPoint + offsetBorder/2;
24
+ $(this).find('.box-inputs').css('transform', 'translateX(-' + translateLeft + 'px)');
25
+
26
+ // adjust inputs main div width
27
+ $(this).find('.inputs').width( $(this).find('.inputs').width() - translateLeft + 10 /* margin */ );
28
+
29
+
30
+ // 2) translate outputs by the right amount of pixels to have the circle on the line
31
+ var boxOutputs = $(this).find('.box-outputs');
32
+
33
+ // fix css names with
34
+ var namesDiv = boxOutputs.find('.names');
35
+ namesDiv.css('width', (namesDiv.width() + 1) + 'px');
36
+
37
+ // translate inputs to the right
38
+ var translateRight = boxOutputs.find('.types').width() + offsetPoint + offsetBorder/2;
39
+ $(this).find('.box-outputs').css('transform', 'translateX(' + translateRight + 'px)');
40
+
41
+ // adjust output main div width
42
+ $(this).find('.outputs').width( $(this).find('.outputs').width() - translateRight + 10 /* margin */ );
43
+
44
+ // fix io width
45
+ //$('.dualbox-io').css('width', (($(this).find('.inputs').width() + $(this).find('.outputs').width()) + "px"));
46
+ }
47
+ }
48
+
49
+ // take the current width and add it as a css property
50
+ $.fn.fixWidth = function() {
51
+ var width = $(this).width();
52
+ width += parseInt($(this).css('padding-right'));
53
+ width += parseInt($(this).css('padding-left'));
54
+ width += parseInt($(this).css('border-left-width'));
55
+ width += parseInt($(this).css('border-right-width'));
56
+ $(this).css('width', width + 'px');
57
+ }
58
+
59
+ // find position of element relative to an ancestor matching selector
60
+ $.fn.positionFrom = function( selector ) {
61
+ var ancestor = $(this).closest(selector);
62
+ var offset = $(this).offset();
63
+ var ancestorOffset = ancestor.offset();
64
+ return {
65
+ top: offset.top - ancestorOffset.top,
66
+ left: offset.left - ancestorOffset.left,
67
+ }
68
+ }
69
+
70
+ var editorView = null;
71
+ $.fn.savePosition = function( selector ) {
72
+ var id = $(this).attr('id');
73
+ if( id ) {
74
+ var jsPlumbElement = editorView.jsPlumbInstance.getElement(id);
75
+ if( jsPlumbElement ) {
76
+ var pos = editorView.jsPlumbInstance.getPosition(jsPlumbElement);
77
+ editorView.m.getNode(id).setPosition(pos);
78
+ }
79
+ }
80
+ }
81
+
82
+ var TemplateBinds = function(view, div, data) {
83
+ editorView = view;
84
+
85
+ var id = $(div).attr('id');
86
+ var jsPlumbInstance = view.jsPlumbInstance;
87
+
88
+ div.fixCardDisplay();
89
+ div.ready(function() {
90
+ // div resize must be completed before jsplumb touches it
91
+ div.fixWidth();
92
+
93
+ if( !data.example ) {
94
+ // if we have a position, set it
95
+ var position = data && data.def && data.def.graph && data.def.graph.position;
96
+ if( position ) {
97
+ var jsPlumbElement = jsPlumbInstance.getElement(id);
98
+ jsPlumbInstance.setPosition(jsPlumbElement, position);
99
+ }
100
+
101
+ // This needs to be registered before draggable
102
+ div.on('mousedown', function(e) {
103
+ // if this div is not selected already, deselect the other divs
104
+ if( !view.selector.isSelected(this) ) {
105
+ view.selector.deselect();
106
+ }
107
+ });
108
+
109
+ // Make the div draggable
110
+ jsPlumbInstance.draggable(div, {
111
+ //containment:true, // not allowed outside of container div
112
+ drag: function(e) {
113
+ },
114
+ stop: function(e) {
115
+ // resize the canvas if necessary
116
+ view.canvasSizeHandler.debouncedResize();
117
+
118
+ // set the new position in the graph model
119
+ var el = jsPlumbInstance.getElement(id);
120
+ $(el).ready(function() {
121
+ var pos = jsPlumbInstance.getPosition(el);
122
+ view.m.getNode(id).setPosition(pos);
123
+ });
124
+ }
125
+ });
126
+
127
+ if( data.n.isInput() || data.n.isOutput() ) {
128
+ var type = "*";
129
+ var input = output = "value";
130
+ var offsetTop = $(div).find('.card-top').height() + 12 /* hr size */ - 3;
131
+
132
+ var uuid = [ id, "input", input].join('#');
133
+ var ep = jsPlumbInstance.addEndpoint(id, {
134
+ isSource : false,
135
+ isTarget : true,
136
+ uuid : uuid,
137
+ anchor : [0,0,-1,0,0,offsetTop],
138
+ maxConnections : 1,
139
+ parameters : {
140
+ type: "data",
141
+ target : {
142
+ id : id,
143
+ input : output
144
+ }
145
+ }
146
+ }, view.style.inputEndpoint);
147
+
148
+ // add data to the endpoint div so we can identify it easier
149
+ $(ep.canvas).attr('data-node', id);
150
+ $(ep.canvas).attr('data-type', 'input');
151
+ $(ep.canvas).attr('data-input', input);
152
+
153
+ // bind tooltip
154
+ $(ep.canvas).attr('data-toggle', "tooltip");
155
+ $(ep.canvas).attr('data-trigger', "hover");
156
+ $(ep.canvas).attr('data-placement', "left");
157
+ $(ep.canvas).attr('data-html', "true");
158
+ var inputType = view.m.getNode(id).getInputType("value");
159
+ $(ep.canvas).attr('title', "Type: <b>" + inputType + "</b>");
160
+ $(ep.canvas).tooltip();
161
+
162
+ // bind context menu to the endpoint
163
+ $(ep.canvas).addClass('capture-right-click');
164
+ $(ep.canvas).ready(function() {
165
+ var menu = new ContextMenu(".jsplumb-endpoint-anchor[data-node='"+id.trim()+"'][data-input='" + input + "']", [
166
+ {
167
+ name: 'Create input for here',
168
+ fn: () => {
169
+ view.c.createInputFromConnection(id, input);
170
+ }
171
+ },
172
+ ]);
173
+ });
174
+
175
+ var uuid = [ id, "output", output].join('#');
176
+ var ep = jsPlumbInstance.addEndpoint(id, {
177
+ isSource : true,
178
+ isTarget : false,
179
+ uuid : uuid,
180
+ anchor : [1,0,1,0,0,offsetTop],
181
+ parameters : {
182
+ type: "data",
183
+ source : {
184
+ id : id,
185
+ output : output
186
+ }
187
+ }
188
+ }, view.style.outputEndpoint);
189
+
190
+ // add data to the endpoint div so we can identify it easier
191
+ $(ep.canvas).attr('data-node', id);
192
+ $(ep.canvas).attr('data-type', "output");
193
+ $(ep.canvas).attr('data-output', output);
194
+
195
+ // bind tooltip
196
+ $(ep.canvas).attr('data-toggle', "tooltip");
197
+ $(ep.canvas).attr('data-trigger', "hover");
198
+ $(ep.canvas).attr('data-placement', "right");
199
+ $(ep.canvas).attr('data-html', "true");
200
+ var outputType = view.m.getNode(id).getOutputType("value");
201
+ $(ep.canvas).attr('title', "Type: <b>" + outputType + "</b>");
202
+ $(ep.canvas).tooltip();
203
+
204
+ // bind context menu to the endpoint
205
+ $(ep.canvas).addClass('capture-right-click');
206
+ $(ep.canvas).ready(function() {
207
+ var menu = new ContextMenu(".jsplumb-endpoint-anchor[data-node='"+id.trim()+"'][data-output='" + output.trim() + "']", [
208
+ {
209
+ name: 'Create output for here',
210
+ fn: () => {
211
+ view.c.createOutputFromConnection(id, output);
212
+ }
213
+ },
214
+ ]);
215
+ });
216
+ }
217
+ else {
218
+ // add input endoints
219
+ div.find('.box-inputs').find('.point').each( function(index) {
220
+ $(this).css('visibility', 'hidden').css('opacity', '0'); // replaced by jsPlumb point
221
+
222
+ var input = div.find('.box-inputs').find('.name').eq(index).attr('data-input').trim();
223
+ var type = view.m.getNode(id).getInputType(input);
224
+
225
+ var offsetTop = $(this).positionFrom('.card').top + $(this).height()/2 - 3;
226
+ var uuid = [ id, "input", $(this).data('key')].join('#');
227
+ var ep = jsPlumbInstance.addEndpoint(id, {
228
+ isSource : false,
229
+ isTarget : true,
230
+ uuid : uuid,
231
+ anchor : [0,0,-1,0,0,offsetTop],
232
+ maxConnections : 1,
233
+ parameters : {
234
+ type: "data",
235
+ target : {
236
+ id : id,
237
+ input : $(this).data('key')
238
+ }
239
+ }
240
+ }, view.style.inputEndpoint);
241
+
242
+ // add data to the endpoint div so we can identify it easier
243
+ $(ep.canvas).attr('data-node', id);
244
+ $(ep.canvas).attr('data-type', 'input');
245
+ $(ep.canvas).attr('data-input', input);
246
+
247
+ // bind tooltip
248
+ $(ep.canvas).attr('data-toggle', "tooltip");
249
+ $(ep.canvas).attr('data-trigger', "hover");
250
+ $(ep.canvas).attr('data-placement', "left");
251
+ $(ep.canvas).attr('data-html', "true");
252
+ $(ep.canvas).attr('title', "Type: <b>" + type + "</b>");
253
+ $(ep.canvas).tooltip();
254
+
255
+ // bind context menu to the endpoint
256
+ $(ep.canvas).addClass('capture-right-click');
257
+ $(ep.canvas).ready(function() {
258
+ var menu = new ContextMenu(".jsplumb-endpoint-anchor[data-node='"+id.trim()+"'][data-input='" + input.trim() + "']", [
259
+ {
260
+ name: 'Create input for here',
261
+ fn: () => {
262
+ view.c.createInputFromConnection(id, input);
263
+ }
264
+ },
265
+ ]);
266
+ });
267
+ });
268
+
269
+ // add output endpoints
270
+ div.find('.box-outputs').find('.point').each( function(index) {
271
+ $(this).css('visibility', 'hidden').css('opacity', '0'); // replaced by jsPlumb point
272
+
273
+ var output = div.find('.box-outputs').find('.name').eq(index).attr('data-output').trim();
274
+ var type = view.m.getNode(id).getOutputType(output);
275
+
276
+ var offsetTop = $(this).positionFrom('.card').top + $(this).height()/2 - 3;
277
+ var uuid = [ id, "output", $(this).data('key')].join('#');
278
+ var ep = jsPlumbInstance.addEndpoint(id, {
279
+ isSource : true,
280
+ isTarget : false,
281
+ uuid : uuid,
282
+ anchor : [1,0,1,0,0,offsetTop],
283
+ parameters : {
284
+ type: "data",
285
+ source : {
286
+ id : id,
287
+ output : $(this).data('key')
288
+ }
289
+ }
290
+ }, view.style.outputEndpoint);
291
+
292
+ // add data to the endpoint div so we can identify it easier
293
+ $(ep.canvas).attr('data-node', id);
294
+ $(ep.canvas).attr('data-type', "output");
295
+ $(ep.canvas).attr('data-output', output);
296
+
297
+ // bind tooltip
298
+ $(ep.canvas).attr('data-toggle', "tooltip");
299
+ $(ep.canvas).attr('data-trigger', "hover");
300
+ $(ep.canvas).attr('data-placement', "right");
301
+ $(ep.canvas).attr('data-html', "true");
302
+ $(ep.canvas).attr('title', "Type: <b>" + type + "</b>");
303
+ $(ep.canvas).tooltip();
304
+
305
+ // bind context menu to the endpoint
306
+ $(ep.canvas).addClass('capture-right-click');
307
+ $(ep.canvas).ready(function() {
308
+ var menu = new ContextMenu(".jsplumb-endpoint-anchor[data-node='"+id.trim()+"'][data-output='" + output.trim() + "']", [
309
+ {
310
+ name: 'Create output for here',
311
+ fn: () => {
312
+ view.c.createOutputFromConnection(id, output);
313
+ }
314
+ },
315
+ ]);
316
+ });
317
+ });
318
+
319
+ if( data.n.isUI() && view.showEvents ) {
320
+ // Make this a target for events
321
+ view.jsPlumbInstance.makeTarget(id, {
322
+ isSource:false,
323
+ isTarget:true,
324
+ uniqueEndpoint: false,
325
+ anchor:"Continuous",
326
+ uuid: id + "#event-in",
327
+ paintStyle:{ fill:"green" },
328
+ parameters: {
329
+ type: "event",
330
+ target: { "id" : id }
331
+ },
332
+ }, view.style.eventEndpoint);
333
+
334
+ // Create an enpoint to create a new event
335
+ var ep = jsPlumbInstance.addEndpoint(id, {
336
+ isSource : true,
337
+ isTarget : false,
338
+ uuid : id + "#event-out",
339
+ anchor : [1, 1, 0, 1, 0, -10],
340
+ parameters : {
341
+ type: "event",
342
+ source: { "id" : id }
343
+ },
344
+ }, view.style.eventEndpoint);
345
+
346
+ // Add overlay here so we don't mess with splitConnection
347
+ ep.addOverlay(["PlainArrow", { width:15, length:15, location:1, id:"arrow" }]);
348
+
349
+ $(ep.canvas).attr('data-toggle', "tooltip");
350
+ $(ep.canvas).attr('data-trigger', "hover");
351
+ $(ep.canvas).attr('data-placement', "bottom");
352
+ $(ep.canvas).attr('data-html', "true");
353
+ $(ep.canvas).attr('title', "Connect from here ito add an event that will be triggered when this box is done computing.");
354
+ $(ep.canvas).tooltip();
355
+ }
356
+ }
357
+
358
+ // enter metanode button
359
+ div.find('.btn-enter-metanode').click(function(e) {
360
+ e.preventDefault();
361
+ e.stopPropagation();
362
+
363
+ var nodeId = $(this).closest('.card').attr('id');
364
+ view.c.enterMetanode(nodeId);
365
+ });
366
+
367
+ // settings button
368
+ div.find('.btn-settings').click(function(e) {
369
+ e.preventDefault();
370
+ e.stopPropagation();
371
+ view.openBoxSettings(div.attr('id'));
372
+ });
373
+
374
+ // snapshot details button
375
+ div.find('.btn-snapshot-details').click(function(e) {
376
+ e.preventDefault();
377
+ e.stopPropagation();
378
+ view.openDebug(div.attr('id'));
379
+ });
380
+
381
+ div.click(function(e) {
382
+ if( e.ctrlKey ) {
383
+ view.selector.toggleSelection(this);
384
+ }
385
+ });
386
+
387
+ // enable tooltips
388
+ div.find('[data-toggle="popover"]').popover();
389
+
390
+ // Create a contextmenu for the div
391
+ var contextOptions = [
392
+ {
393
+ name: 'Remove this box',
394
+ fn: () => {
395
+ view.c.removeBox(id);
396
+ }
397
+ }
398
+ ];
399
+ if( data.n.isModule() || data.n.isUI() ) {
400
+ contextOptions.push({
401
+ name: 'Duplicate this box',
402
+ fn: () => {
403
+ view.c.duplicateBox(id);
404
+ }
405
+ });
406
+ }
407
+ var nodeMenu = new ContextMenu("#" + id, contextOptions);
408
+ }
409
+ });
410
+ }
411
+
412
+ module.exports = TemplateBinds;