@dualbox/editor 1.0.1 → 1.0.2
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.
- package/js/src/GraphEditor.js +159 -0
- package/js/src/c/GraphController.js +646 -0
- package/js/src/libs/CodeMirror.js +8 -0
- package/js/src/libs/fontawesome.js +1 -0
- package/js/src/libs/jsoneditor.css +2 -0
- package/js/src/libs/jsoneditor.js +4 -0
- package/js/src/m/DualboxUtils.js +35 -0
- package/js/src/m/GraphModel.js +2167 -0
- package/js/src/m/History.js +94 -0
- package/js/src/m/Merger.js +357 -0
- package/js/src/v/AppManager.js +61 -0
- package/js/src/v/CanvasSizeHandler.js +136 -0
- package/js/src/v/ContextMenu.css +45 -0
- package/js/src/v/ContextMenu.js +239 -0
- package/js/src/v/GraphView.js +928 -0
- package/js/src/v/PlumbStyle.js +254 -0
- package/js/src/v/Selector.js +239 -0
- package/js/src/v/TemplateManager.js +79 -0
- package/js/src/v/Translater.js +174 -0
- package/js/src/v/Utils.js +7 -0
- package/js/src/v/Zoomer.js +201 -0
- package/js/src/v/templates/addNode.css +45 -0
- package/js/src/v/templates/addNode.html +62 -0
- package/js/src/v/templates/addNode.js +34 -0
- package/js/src/v/templates/debugNodeInfos.css +5 -0
- package/js/src/v/templates/debugNodeInfos.html +336 -0
- package/js/src/v/templates/debugNodeInfos.js +31 -0
- package/js/src/v/templates/editMainSettings.css +67 -0
- package/js/src/v/templates/editMainSettings.html +265 -0
- package/js/src/v/templates/editMainSettings.js +240 -0
- package/js/src/v/templates/editNodeSettings.css +86 -0
- package/js/src/v/templates/editNodeSettings.html +539 -0
- package/js/src/v/templates/editNodeSettings.js +356 -0
- package/js/src/v/templates/graphNode.css +333 -0
- package/js/src/v/templates/graphNode.html +227 -0
- package/js/src/v/templates/graphNode.js +412 -0
- package/js/src/v/templates/main.css +353 -0
- package/js/src/v/templates/main.html +149 -0
- package/js/src/v/templates/main.js +511 -0
- package/js/src/v/templates/searchResults.css +50 -0
- package/js/src/v/templates/searchResults.html +46 -0
- package/js/src/v/templates/searchResults.js +176 -0
- package/package.json +4 -3
|
@@ -0,0 +1,646 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Implementing the Controller of the MVC
|
|
3
|
+
* Every change in the application starts here.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const _ = require('lodash');
|
|
7
|
+
const utils = require('../m/DualboxUtils');
|
|
8
|
+
const swal = require('sweetalert2');
|
|
9
|
+
const Merger = require('../m/Merger');
|
|
10
|
+
const idx = require('idx');
|
|
11
|
+
const AppParser = require('@dualbox/dualbox-lib-appparser');
|
|
12
|
+
|
|
13
|
+
class GraphController {
|
|
14
|
+
constructor(editor) {
|
|
15
|
+
this.e = editor;
|
|
16
|
+
this.m = editor.m;
|
|
17
|
+
this.v = editor.v;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
createId(name) {
|
|
21
|
+
var shortName = utils.shortName(name);
|
|
22
|
+
return shortName + '-' + utils.randomString(8);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Add a node from the search results
|
|
26
|
+
addNewBox(packageName) {
|
|
27
|
+
// first, make sure the package is loaded
|
|
28
|
+
this.e.loadPackage(packageName).then(() => {
|
|
29
|
+
var id = this.createId(packageName);
|
|
30
|
+
var pkg = null;
|
|
31
|
+
|
|
32
|
+
// close the modal
|
|
33
|
+
this.v.div.find('.add-node-modal').modal('toggle');
|
|
34
|
+
|
|
35
|
+
// add the node
|
|
36
|
+
var pkg = _.find(this.e.searchResults, { 'name': packageName });
|
|
37
|
+
if( pkg ) {
|
|
38
|
+
// first, add node in the model
|
|
39
|
+
var nodeAdded = this.m.addNode(id, pkg);
|
|
40
|
+
if( nodeAdded ) {
|
|
41
|
+
// if model accepts the operation, add it to the view
|
|
42
|
+
this.v.addNode(id, pkg);
|
|
43
|
+
|
|
44
|
+
// if the node is an UI, we also need to add it to a panel
|
|
45
|
+
var n = this.m.getNode(id);
|
|
46
|
+
if( n.isUI() ) {
|
|
47
|
+
if( n.isWidget() ) {
|
|
48
|
+
var options = {};
|
|
49
|
+
var registerTargets = n.m.getSpecialUINodes( n.getRegisterType() );
|
|
50
|
+
_.each(registerTargets, (n) => options[n.graphId] = n.graphId );
|
|
51
|
+
|
|
52
|
+
swal({
|
|
53
|
+
title: 'Select a registration target',
|
|
54
|
+
text: 'You just added a Widget node. It must be registered to an element of type ' + n.getRegisterType() +
|
|
55
|
+
" to work. Please choose one on the following list.",
|
|
56
|
+
input: 'select',
|
|
57
|
+
inputOptions: options
|
|
58
|
+
}).then( (result) => {
|
|
59
|
+
if( result.value ) {
|
|
60
|
+
// register the widget
|
|
61
|
+
this.registerWidget(n.id, result.value);
|
|
62
|
+
|
|
63
|
+
// find the panel of the target and put the widget on the same panel
|
|
64
|
+
var panel = this.m.getNode(result.value).getPanel();
|
|
65
|
+
this.m.addNodeToPanel(n.id, panel);
|
|
66
|
+
|
|
67
|
+
this.v.repaint();
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
var options = {};
|
|
73
|
+
_.each(this.m.getPanels(), (name) => options[name] = name );
|
|
74
|
+
|
|
75
|
+
swal({
|
|
76
|
+
title: 'Select a panel',
|
|
77
|
+
text: 'You just added an UI. Please select in which panel of the app we should locate it.',
|
|
78
|
+
input: 'select',
|
|
79
|
+
inputOptions: options
|
|
80
|
+
}).then( (result) => {
|
|
81
|
+
if( result.value ) {
|
|
82
|
+
this.m.addNodeToPanel(id, result.value);
|
|
83
|
+
this.v.repaint();
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
console.error('Package ' + packageName + ' not found');
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// create a new metabox
|
|
97
|
+
addNewMetabox(name, json = {}) {
|
|
98
|
+
if( this.m.hasMetanode(name) ) {
|
|
99
|
+
swal("Can't add metabox", "metabox with name '" + name + "' already exists.", "error");
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
// add metabox def
|
|
103
|
+
this.m.addMetanode(name, json);
|
|
104
|
+
|
|
105
|
+
// add 1 node of this metabox on the graph
|
|
106
|
+
var id = this.createId(name);
|
|
107
|
+
|
|
108
|
+
this.m.addNode(id, {
|
|
109
|
+
"name" : name,
|
|
110
|
+
"version" : "*"
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// repaint editor
|
|
114
|
+
this.v.repaint();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// remove a box from it's id
|
|
119
|
+
removeBox(id) {
|
|
120
|
+
this.m.getNode(id).remove();
|
|
121
|
+
this.v.repaint();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
duplicateBox(id) {
|
|
125
|
+
// copy def
|
|
126
|
+
var node = this.m.getNode(id);
|
|
127
|
+
var type = node.type;
|
|
128
|
+
var def = _.cloneDeep(node.getDef());
|
|
129
|
+
var newId = this.createId(def.module);
|
|
130
|
+
|
|
131
|
+
// remove links, change position a little bit
|
|
132
|
+
delete def.links;
|
|
133
|
+
var leftPosition = idx(def, o=>o.graph.position.left);
|
|
134
|
+
if( leftPosition ) {
|
|
135
|
+
def.graph.position.left = (parseInt(leftPosition) + 200).toString();
|
|
136
|
+
}
|
|
137
|
+
def.id = newId;
|
|
138
|
+
|
|
139
|
+
this.m.addNodeFromDef(newId, type, def);
|
|
140
|
+
this.v.repaint();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
setInputVisibility(id, input, visible) {
|
|
144
|
+
var node = this.m.getNode(id);
|
|
145
|
+
if( node.isInputConnected(input) && !visible ) {
|
|
146
|
+
swal('Not yet', 'Please remove all connections to this input before changing its visibility', 'error');
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
node.setInputVisibility(input, visible);
|
|
151
|
+
this.v.repaint();
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
setOutputVisibility(id, output, visible) {
|
|
157
|
+
var node = this.m.getNode(id);
|
|
158
|
+
if( node.isOutputConnected(output) && !visible ) {
|
|
159
|
+
swal('Not yet', 'Please remove all connections to this output before changing its visibility', 'error');
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
node.setOutputVisibility(output, visible);
|
|
164
|
+
this.v.repaint();
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
setComment(id, comment) {
|
|
170
|
+
var node = this.m.getNode(id);
|
|
171
|
+
node.setComment(comment);
|
|
172
|
+
this.v.repaint();
|
|
173
|
+
this.v.openBoxSettings(id);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
deleteComment(id) {
|
|
177
|
+
var node = this.m.getNode(id);
|
|
178
|
+
node.deleteComment();
|
|
179
|
+
this.v.repaint();
|
|
180
|
+
this.v.openBoxSettings(id);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
registerWidget(id, targetId) {
|
|
184
|
+
var node = this.m.getNode(id);
|
|
185
|
+
node.registerWidget(targetId);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
renameBox(oldId, newId, type) {
|
|
189
|
+
if( newId == "length" ) {
|
|
190
|
+
// crash jsPlumb to have a div named "length"
|
|
191
|
+
swal("Forbidden name", "Sorry, this is a forbidden name", "error");
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// newId can't start with a number
|
|
196
|
+
if( newId.match(/^\d/) ) {
|
|
197
|
+
swal("Wrong name", "You can't set a name that starts with a number.", "error");
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if( oldId !== newId ) {
|
|
202
|
+
if( type == "input" ) {
|
|
203
|
+
oldId = this.m.inputPrefix + oldId;
|
|
204
|
+
newId = this.m.inputPrefix + newId;
|
|
205
|
+
}
|
|
206
|
+
else if( type == "output" ) {
|
|
207
|
+
oldId = this.m.outputPrefix + oldId;
|
|
208
|
+
newId = this.m.outputPrefix + newId;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
if( newId.startsWith(this.m.inputPrefix) ||
|
|
212
|
+
newId.startsWith(this.m.outputPrefix) ) {
|
|
213
|
+
swal('Breaking convention', 'Only input boxes and output boxes can have a name that starts with "' + this.m.inputPrefix + '" or "' + this.m.outputPrefix + '".', "error");
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
this.m.getNode(oldId).rename(newId);
|
|
218
|
+
this.v.repaint();
|
|
219
|
+
}
|
|
220
|
+
this.v.openBoxSettings(newId);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
addAppEvent(name) {
|
|
224
|
+
this.m.getCurrentApp().addAppEvent(name);
|
|
225
|
+
this.v.setMainMenu();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
removeEvent(id, index) {
|
|
229
|
+
this.m.getNode(id).removeEvent(index);
|
|
230
|
+
this.v.repaint();
|
|
231
|
+
this.v.openBoxSettings(id);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
removeAppEvent(name) {
|
|
235
|
+
this.m.getCurrentApp().removeAppEvent(name);
|
|
236
|
+
this.v.repaint();
|
|
237
|
+
this.v.setMainMenu();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
renameAppEvent(oldName, newName) {
|
|
241
|
+
this.m.getCurrentApp().renameAppEvent(oldName, newName);
|
|
242
|
+
this.v.repaint();
|
|
243
|
+
this.v.setMainMenu();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
setEventProperty(id, index, prop, val) {
|
|
247
|
+
if( id.startsWith("#application-events-in") ) {
|
|
248
|
+
var eventName = id.split('-')[ id.split('-').length -1 ];
|
|
249
|
+
var def = this.m.getCurrentApp().getEventIn(eventName)[index];
|
|
250
|
+
def[prop] = val;
|
|
251
|
+
}
|
|
252
|
+
else if( id.startsWith("#application-events-out") ) {
|
|
253
|
+
var def = this.m.getCurrentApp().getEventOut();
|
|
254
|
+
def[prop] = val;
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
var def = this.m.getNode(id).getEvent(index);
|
|
258
|
+
def[prop] = val;
|
|
259
|
+
this.m.getNode(id).setEvent(index, def);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
this.v.repaint();
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
setEventIf(id, index, val) {
|
|
266
|
+
this.setEventProperty(id, index, "if", val);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
setEventData(id, index, val) {
|
|
270
|
+
this.setEventProperty(id, index, "data", val);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
setEventTarget(id, index, val) {
|
|
274
|
+
this.setEventProperty(id, index, "node", val);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
setEventName(id, index, val) {
|
|
278
|
+
this.setEventProperty(id, index, "event", val);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
setBoxCache(id, val) {
|
|
282
|
+
var n = this.m.getNode(id).setCache(val);
|
|
283
|
+
this.v.repaint();
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
setBoxParallel(id, val) {
|
|
287
|
+
var n = this.m.getNode(id).setParallel(val);
|
|
288
|
+
this.v.repaint();
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
setAppDescription( desc ) {
|
|
292
|
+
this.m.getCurrentApp().setDescription(desc);
|
|
293
|
+
this.v.setMainMenu();
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
setAppEventDescription( name, desc ) {
|
|
297
|
+
this.m.getCurrentApp().setEventDescription(name, desc);
|
|
298
|
+
this.v.setMainMenu();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
removeAppInEvent(name, index) {
|
|
302
|
+
this.m.getCurrentApp().removeAppInEvent(name, index);
|
|
303
|
+
this.v.setMainMenu();
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
removeAppOutEvent(name) {
|
|
307
|
+
this.m.getCurrentApp().removeAppOutEvent(name);
|
|
308
|
+
this.v.setMainMenu();
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
getFirstNodeWithEvents() {
|
|
312
|
+
var nodes = this.m.getNodes('ui');
|
|
313
|
+
for(var i=0; i<nodes.length; i++) {
|
|
314
|
+
var node = nodes[i];
|
|
315
|
+
if( node.getEventsNames().length !== 0 ) {
|
|
316
|
+
return node;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
addEvent(id, name) {
|
|
324
|
+
var node = this.getFirstNodeWithEvents();
|
|
325
|
+
if( node != null ) {
|
|
326
|
+
var evtName = node.getEventsNames()[0];
|
|
327
|
+
this.m.addEventLink(id, node.id, evtName);
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
this.m.addEventLink(id, null, null);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
this.v.openBoxSettings(id);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
addSubEvent(name) {
|
|
337
|
+
var node = this.getFirstNodeWithEvents();
|
|
338
|
+
if( node != null ) {
|
|
339
|
+
var evtName = node.getEventsNames()[0];
|
|
340
|
+
this.m.getCurrentApp().addSubEvent(name, node.getGraphId(), evtName);
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
this.m.getCurrentApp().addSubEvent(name, null, null);
|
|
344
|
+
}
|
|
345
|
+
this.v.setMainMenu();
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
addCallback(name) {
|
|
349
|
+
this.m.getCurrentApp().addCallback(name);
|
|
350
|
+
this.v.setMainMenu();
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// create a new input in the current window (metanode)
|
|
354
|
+
createInput() {
|
|
355
|
+
swal.mixin({
|
|
356
|
+
confirmButtonText: 'Next →',
|
|
357
|
+
showCancelButton: true,
|
|
358
|
+
progressSteps: ['1', '2', '3']
|
|
359
|
+
}).queue([
|
|
360
|
+
{
|
|
361
|
+
input: 'text',
|
|
362
|
+
title: 'Enter the input name',
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
input: 'text',
|
|
366
|
+
title: 'Enter the input type',
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
input: 'text',
|
|
370
|
+
title: 'Enter a description',
|
|
371
|
+
}
|
|
372
|
+
]).then(async (result) => {
|
|
373
|
+
if( result.value ) {
|
|
374
|
+
const [ inputName, inputType, inputDesc ] = result.value;
|
|
375
|
+
var input = this.m.addInput(inputName, inputType, inputDesc);
|
|
376
|
+
this.v.repaint();
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// create a new output in the current window (metanode)
|
|
382
|
+
createOutput() {
|
|
383
|
+
swal.mixin({
|
|
384
|
+
confirmButtonText: 'Next →',
|
|
385
|
+
showCancelButton: true,
|
|
386
|
+
progressSteps: ['1', '2', '3']
|
|
387
|
+
}).queue([
|
|
388
|
+
{
|
|
389
|
+
input: 'text',
|
|
390
|
+
title: 'Enter the output name',
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
input: 'text',
|
|
394
|
+
title: 'Enter the output type',
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
input: 'text',
|
|
398
|
+
title: 'Enter a description',
|
|
399
|
+
}
|
|
400
|
+
]).then(async (result) => {
|
|
401
|
+
if( result.value ) {
|
|
402
|
+
const [ outputName, outputType, outputDesc ] = result.value;
|
|
403
|
+
var output = this.m.addOutput(outputName, outputType, outputDesc);
|
|
404
|
+
this.v.repaint();
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// create a new input, determine the type from the connection
|
|
410
|
+
createInputFromConnection(id, name) {
|
|
411
|
+
swal.mixin({
|
|
412
|
+
confirmButtonText: 'Next →',
|
|
413
|
+
showCancelButton: true,
|
|
414
|
+
progressSteps: ['1', '2']
|
|
415
|
+
}).queue([
|
|
416
|
+
{
|
|
417
|
+
input: 'text',
|
|
418
|
+
title: 'Enter the input name',
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
input: 'text',
|
|
422
|
+
title: 'Enter a description',
|
|
423
|
+
}
|
|
424
|
+
]).then(async (result) => {
|
|
425
|
+
if( result.value ) {
|
|
426
|
+
var inputName = result.value[0];
|
|
427
|
+
var inputDesc = result.value[1];
|
|
428
|
+
var inputType = await this.m.getNode(id).getInputType(name);
|
|
429
|
+
|
|
430
|
+
// add the input
|
|
431
|
+
var input = this.m.addInput(inputName, inputType, inputDesc);
|
|
432
|
+
|
|
433
|
+
// make the position a bit to the left
|
|
434
|
+
var pos = _.clone(this.m.getNode(id).getDef().graph.position);
|
|
435
|
+
pos.left = parseInt(pos.left) > 150 ? parseInt(pos.left) - 150 : 0;
|
|
436
|
+
input.graph = {};
|
|
437
|
+
input.graph.position = pos;
|
|
438
|
+
|
|
439
|
+
// add the connection
|
|
440
|
+
this.m.addDataLink("input", inputName, id, name);
|
|
441
|
+
|
|
442
|
+
this.v.repaint();
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// create a new output, determine the type from the connection
|
|
448
|
+
createOutputFromConnection(id, name) {
|
|
449
|
+
swal.mixin({
|
|
450
|
+
confirmButtonText: 'Next →',
|
|
451
|
+
showCancelButton: true,
|
|
452
|
+
progressSteps: ['1', '2']
|
|
453
|
+
}).queue([
|
|
454
|
+
{
|
|
455
|
+
input: 'text',
|
|
456
|
+
title: 'Enter the output name',
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
input: 'text',
|
|
460
|
+
title: 'Enter a description',
|
|
461
|
+
}
|
|
462
|
+
]).then(async (result) => {
|
|
463
|
+
if( result.value ) {
|
|
464
|
+
var outputName = result.value[0];
|
|
465
|
+
var outputDesc = result.value[1];
|
|
466
|
+
var outputType = await this.m.getNode(id).getOutputType(name);
|
|
467
|
+
|
|
468
|
+
// add the output
|
|
469
|
+
var output = this.m.addOutput(outputName, outputType, outputDesc);
|
|
470
|
+
|
|
471
|
+
// make the position a bit to the left
|
|
472
|
+
var pos = _.clone(this.m.getNode(id).getDef().graph.position);
|
|
473
|
+
pos.left = parseInt(pos.left) + 250;
|
|
474
|
+
output.graph = {};
|
|
475
|
+
output.graph.position = pos;
|
|
476
|
+
|
|
477
|
+
// add the connection
|
|
478
|
+
this.m.addDataLink(id, name, "output", outputName);
|
|
479
|
+
|
|
480
|
+
this.v.repaint();
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
setIterator(id, input) {
|
|
486
|
+
var node = this.m.getNode(id);
|
|
487
|
+
node.detachInput(input); // this connection is invalid now
|
|
488
|
+
node.setIterator(input);
|
|
489
|
+
this.v.repaint();
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
unsetIterator(id, input) {
|
|
493
|
+
var node = this.m.getNode(id);
|
|
494
|
+
node.detachInput(input); // this connection is invalid now
|
|
495
|
+
node.unsetIterator(input);
|
|
496
|
+
this.v.repaint();
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
setFeedback(id, output, input) {
|
|
500
|
+
this.m.getNode(id).setFeedback(output, input);
|
|
501
|
+
this.v.repaint();
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
unsetFeedback(id, output) {
|
|
505
|
+
this.m.getNode(id).setFeedback(output);
|
|
506
|
+
this.v.repaint();
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
setMetanodeDescription(nodeId, description) {
|
|
510
|
+
var node = this.m.getNode(nodeId);
|
|
511
|
+
var metanodeName = node.def.module;
|
|
512
|
+
this.m.getCurrentApp().json.metanodes[metanodeName].description = description;
|
|
513
|
+
this.v.openBoxSettings(nodeId);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// enter inside a metanode
|
|
517
|
+
enterMetanode(nodeId) {
|
|
518
|
+
(async () => {
|
|
519
|
+
// 1 - hide the canvas
|
|
520
|
+
await this.v.hideCanvas();
|
|
521
|
+
|
|
522
|
+
// 2 - Save the actual position/zoom state
|
|
523
|
+
var viewState = this.v.zoomer.saveState();
|
|
524
|
+
|
|
525
|
+
// 3 - Enter the metanode
|
|
526
|
+
this.m.enterMetanode(nodeId, viewState);
|
|
527
|
+
|
|
528
|
+
// 4 - Repaint
|
|
529
|
+
await this.v.repaint();
|
|
530
|
+
|
|
531
|
+
// 5 - Zoom back to 1, position to top-left
|
|
532
|
+
await this.v.zoomer.setZoom(1);
|
|
533
|
+
await this.v.translater.gotoTopLeft();
|
|
534
|
+
|
|
535
|
+
// 6 - Show the canvas back again
|
|
536
|
+
await this.v.showCanvas();
|
|
537
|
+
})();
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// exit to the given window
|
|
541
|
+
setWindow( w ) {
|
|
542
|
+
this.m.setWindow(w[0]);
|
|
543
|
+
this.v.repaint().then(() => {
|
|
544
|
+
this.v.zoomer.restoreState(w[2]);
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
load( json ) {
|
|
549
|
+
// first load the packages
|
|
550
|
+
this.e.loadPackages(json).then( async () => {
|
|
551
|
+
console.log('LOADED ALL PACKAGES !');
|
|
552
|
+
|
|
553
|
+
// hold state saving for now
|
|
554
|
+
this.m.history.holdSaving(true);
|
|
555
|
+
|
|
556
|
+
// 1st, load the json in the model
|
|
557
|
+
await this.m.load(json);
|
|
558
|
+
|
|
559
|
+
// set the new app's menu
|
|
560
|
+
this.v.setMainMenu();
|
|
561
|
+
|
|
562
|
+
// then, repaint
|
|
563
|
+
this.v.repaint().then(() => {
|
|
564
|
+
this.m.history.holdSaving(false);
|
|
565
|
+
this.m.history.save();
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
// load the css into the css editor
|
|
569
|
+
this.v.cssCode.setValue(this.m.get().css || "");
|
|
570
|
+
|
|
571
|
+
// load the html templates into the html editor
|
|
572
|
+
this.v.div.find('.app-interface-select').empty();
|
|
573
|
+
this.v.div.find('.app-interface-select').append(
|
|
574
|
+
$("<option/>", { "value" : "" }).append('Load UI...')
|
|
575
|
+
);
|
|
576
|
+
_.each(this.m.get().interface, (val, uiName) => {
|
|
577
|
+
this.v.div.find(".app-interface-select").append(
|
|
578
|
+
$("<option/>", { "value" : uiName }).append(uiName)
|
|
579
|
+
);
|
|
580
|
+
});
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
get() {
|
|
585
|
+
return this.m.get();
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
undo() {
|
|
589
|
+
this.m.undo();
|
|
590
|
+
this.v.repaint();
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
redo() {
|
|
594
|
+
this.m.redo();
|
|
595
|
+
this.v.repaint();
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
deleteSelection() {
|
|
599
|
+
var selectedDivs = this.v.selector.getSelection();
|
|
600
|
+
_.each(selectedDivs, (div) => {
|
|
601
|
+
this.m.getNode( $(div).attr('id') ).remove();
|
|
602
|
+
});
|
|
603
|
+
this.v.repaint();
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
mergeSelection() {
|
|
607
|
+
swal.mixin({
|
|
608
|
+
confirmButtonText: 'Next →',
|
|
609
|
+
showCancelButton: true,
|
|
610
|
+
progressSteps: ['1', '2']
|
|
611
|
+
}).queue([
|
|
612
|
+
{
|
|
613
|
+
input: 'text',
|
|
614
|
+
title: 'Enter the metabox name',
|
|
615
|
+
},
|
|
616
|
+
{
|
|
617
|
+
input: 'text',
|
|
618
|
+
title: 'Enter the metabox description',
|
|
619
|
+
}
|
|
620
|
+
]).then(async (result) => {
|
|
621
|
+
if( result.value ) {
|
|
622
|
+
var mName = result.value[0];
|
|
623
|
+
var mDesc = result.value[1];
|
|
624
|
+
|
|
625
|
+
var selectedDivs = this.v.selector.getSelection();
|
|
626
|
+
var ids = [];
|
|
627
|
+
_.each(selectedDivs, (div) => {
|
|
628
|
+
if( div.is('.card') ) { // filter cards only
|
|
629
|
+
ids.push( $(div).attr('id') );
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
var merger = new Merger(this.m, ids);
|
|
634
|
+
merger.merge(mName, mDesc);
|
|
635
|
+
|
|
636
|
+
this.v.repaint();
|
|
637
|
+
}
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
removeSplit(id) {
|
|
642
|
+
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
module.exports = GraphController;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
var CodeMirror = require('codemirror/lib/codemirror.js');
|
|
2
|
+
require('codemirror/lib/codemirror.css');
|
|
3
|
+
require('codemirror/mode/xml/xml.js');
|
|
4
|
+
require('codemirror/mode/css/css.js');
|
|
5
|
+
require('codemirror/mode/javascript/javascript.js');
|
|
6
|
+
require('codemirror/mode/htmlmixed/htmlmixed.js');
|
|
7
|
+
|
|
8
|
+
module.exports = CodeMirror;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('../../../node_modules/@fortawesome/fontawesome-free/css/all.min.css');
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
//require('../../../node_modules/jsoneditor/dist/jsoneditor.css');
|
|
2
|
+
require('./jsoneditor.css'); // local import to rebase urls in css
|
|
3
|
+
//require('../../../node_modules/jsoneditor/dist/img/jsoneditor-icons.svg');
|
|
4
|
+
module.exports = require('../../../node_modules/jsoneditor/dist/jsoneditor.js');
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
class DualboxUtils {
|
|
2
|
+
// return the short name of a dualbox package: "@dualbox/dualbox-core-if" => "if"
|
|
3
|
+
shortName(packageName) {
|
|
4
|
+
var str = packageName;
|
|
5
|
+
str = str.replace('@dualbox/', '');
|
|
6
|
+
str = str.replace('dualbox-core-', '');
|
|
7
|
+
str = str.replace('dualbox-lib-', '');
|
|
8
|
+
str = str.replace('dualbox-ui-', '');
|
|
9
|
+
str = str.replace('dualbox-module-', '');
|
|
10
|
+
return str
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
randomString(len) {
|
|
14
|
+
// converts a single byte to a hex string
|
|
15
|
+
function byteToHex(byte) {
|
|
16
|
+
return ('0' + byte.toString(16)).slice(-2);
|
|
17
|
+
}
|
|
18
|
+
var arr = new Uint8Array((len || 40) / 2);
|
|
19
|
+
window.crypto.getRandomValues(arr);
|
|
20
|
+
return [].map.call(arr, byteToHex).join("");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// return true if package is an UI
|
|
24
|
+
isUI(packageName) {
|
|
25
|
+
return packageName.indexOf('dualbox-ui-') !== -1;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// return true if package is a Module
|
|
29
|
+
isModule(packageName) {
|
|
30
|
+
return packageName.indexOf('dualbox-module-') !== -1 ||
|
|
31
|
+
packageName.indexOf('dualbox-core-') !== -1;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = new DualboxUtils();
|