@dualbox/editor 1.0.39 → 1.0.41

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.
@@ -42610,7 +42610,9 @@ class GraphModel {
42610
42610
  windows: null
42611
42611
  };
42612
42612
  this.data.app = this.data.root;
42613
- this.data.windows = [[this.e.rootAppName, this.data.app]];
42613
+ this.data.windows = [
42614
+ [this.e.rootAppName, this.data.app]
42615
+ ];
42614
42616
 
42615
42617
  // An object to save/restore different states of this.data (ctrl-z/ctrl-y)
42616
42618
  this.history = new History(this);
@@ -42629,7 +42631,9 @@ class GraphModel {
42629
42631
 
42630
42632
  this.data.root = json;
42631
42633
  this.data.app = this.data.root; // reset ptr
42632
- this.data.windows = [[this.e.rootAppName, this.data.app]];
42634
+ this.data.windows = [
42635
+ [this.e.rootAppName, this.data.app]
42636
+ ];
42633
42637
 
42634
42638
  await this.addNativeTypes();
42635
42639
 
@@ -42905,24 +42909,21 @@ class GraphModel {
42905
42909
  return false;
42906
42910
  }
42907
42911
  var node = this.data.app.modules[id] = desc;
42908
- }
42909
- else if (utils.isUI(pkg.name)) {
42912
+ } else if (utils.isUI(pkg.name)) {
42910
42913
  this.ensure('ui');
42911
42914
  if (this.data.app.ui[id]) {
42912
42915
  console.error('Could not add ui ' + id + ': already exists');
42913
42916
  return false;
42914
42917
  }
42915
42918
  var node = this.data.app.ui[id] = desc;
42916
- }
42917
- else {
42919
+ } else {
42918
42920
  // may be a metanode
42919
42921
  var nodeDef = idx_1(this.data.app, o => o.metanodes[pkg.name]);
42920
42922
  if (nodeDef) {
42921
42923
  this.ensure('modules');
42922
42924
  var node = this.data.app.modules[id] = desc;
42923
42925
  return node;
42924
- }
42925
- else {
42926
+ } else {
42926
42927
  throw pkg.name + " is not module or ui, can't add node !";
42927
42928
  }
42928
42929
  }
@@ -43037,8 +43038,7 @@ class GraphModel {
43037
43038
  try {
43038
43039
  var n = this.getNode(id);
43039
43040
  return true;
43040
- }
43041
- catch (e) {
43041
+ } catch (e) {
43042
43042
  return false;
43043
43043
  }
43044
43044
  }
@@ -43070,8 +43070,7 @@ class GraphModel {
43070
43070
  .concat(lodash.map(lodash.keys(this.data.app.output), k => this.outputPrefix + k))
43071
43071
  .concat(lodash.keys(this.data.app.modules))
43072
43072
  .concat(lodash.keys(this.data.app.ui));
43073
- }
43074
- else {
43073
+ } else {
43075
43074
  throw new Error('unknown node type: ' + type);
43076
43075
  }
43077
43076
  }
@@ -43118,11 +43117,9 @@ class GraphModel {
43118
43117
  node.graphId = id; // for UIs and modules
43119
43118
  if (pkgName.startsWith('@dualbox/dualbox-module-') || pkgName.startsWith('dualbox-core')) {
43120
43119
  node.type = "module";
43121
- }
43122
- else if (pkgName.startsWith('@dualbox/dualbox-ui-')) {
43120
+ } else if (pkgName.startsWith('@dualbox/dualbox-ui-')) {
43123
43121
  node.type = "ui";
43124
- }
43125
- else {
43122
+ } else {
43126
43123
  throw "pkg " + pkgName + " does not appear to be a module or ui";
43127
43124
  }
43128
43125
 
@@ -43154,11 +43151,9 @@ class GraphModel {
43154
43151
  prefixId(id, type) {
43155
43152
  if (type == "input" && !id.startsWith('in-')) {
43156
43153
  return this.inputPrefix + id;
43157
- }
43158
- else if (type == "output" && !id.startsWith('out-')) {
43154
+ } else if (type == "output" && !id.startsWith('out-')) {
43159
43155
  return this.outputPrefix + id;
43160
- }
43161
- else {
43156
+ } else {
43162
43157
  return id;
43163
43158
  }
43164
43159
  }
@@ -43167,8 +43162,7 @@ class GraphModel {
43167
43162
  if (typeof v == "string" && v.startsWith('____dualbox_storage')) {
43168
43163
  var id = v.replace("____dualbox_storage(", "").slice(0, -1);
43169
43164
  return this.data.root.snapshotObjects[id];
43170
- }
43171
- else {
43165
+ } else {
43172
43166
  return v;
43173
43167
  }
43174
43168
  }
@@ -43190,27 +43184,22 @@ class GraphNode {
43190
43184
  this.type = "input";
43191
43185
  this.graphId = id.substring(3); // the id to identify it in the dualbox graph
43192
43186
  this.def = this.app.input[this.graphId];
43193
- }
43194
- else if (id.startsWith(this.m.outputPrefix)) {
43187
+ } else if (id.startsWith(this.m.outputPrefix)) {
43195
43188
  this.type = "output";
43196
43189
  this.graphId = id.substring(4);
43197
43190
  this.def = this.app.output[this.graphId];
43198
- }
43199
- else if (this.app.modules && this.app.modules[id]) {
43191
+ } else if (this.app.modules && this.app.modules[id]) {
43200
43192
  this.graphId = id;
43201
43193
  this.type = "module";
43202
43194
  this.def = this.app.modules[this.graphId];
43203
- }
43204
- else if (this.app.ui && this.app.ui[id]) {
43195
+ } else if (this.app.ui && this.app.ui[id]) {
43205
43196
  this.graphId = id;
43206
43197
  this.type = "ui";
43207
43198
  this.def = this.app.ui[this.graphId];
43208
- }
43209
- else {
43199
+ } else {
43210
43200
  throw "Cant find node " + id;
43211
43201
  }
43212
- }
43213
- else {
43202
+ } else {
43214
43203
  this.def = null;
43215
43204
  this.graphId = null;
43216
43205
  }
@@ -43256,8 +43245,9 @@ class GraphNode {
43256
43245
 
43257
43246
  // return the input links for a node
43258
43247
  getNormalizeLinksDef() {
43259
- return this.type == "input" || this.type == "output" ?
43260
- { "value": this.def.link } :
43248
+ return this.type == "input" || this.type == "output" ? {
43249
+ "value": this.def.link
43250
+ } :
43261
43251
  this.def.links;
43262
43252
  }
43263
43253
 
@@ -43299,8 +43289,7 @@ class GraphNode {
43299
43289
  }
43300
43290
  };
43301
43291
  return r;
43302
- }
43303
- else {
43292
+ } else {
43304
43293
  switch (this.type) {
43305
43294
  case "input":
43306
43295
  case "output":
@@ -43322,25 +43311,59 @@ class GraphNode {
43322
43311
  // return the assigned input type if there is one. Else, return the module's definition type for this input
43323
43312
  // Also, take loops into account
43324
43313
  getInputType(inputName) {
43325
- var assignedType = lodash.get(this.def, ["assignedTypes", "input", inputName]);
43314
+ var assignedType = this.getInputAssignedType(inputName);
43326
43315
  var t = assignedType ? assignedType : this.getDefinitionInputType(inputName);
43327
43316
  return this.hasIterator(inputName) ? "Array<" + t + ">" : t;
43328
43317
  }
43329
43318
 
43330
43319
  // return the assigned input type if there is one. Else, return the module's definition type for this input
43331
- getAttributeType(inputName) {
43332
- var assignedType = lodash.get(this.def, ["assignedTypes", "input", inputName]);
43320
+ getAttributeType(attrName) {
43321
+ var assignedType = this.getAttributeAssignedType(attrName);
43333
43322
  return assignedType ? assignedType : this.getDefinitionAttributeType(inputName);
43334
43323
  }
43335
43324
 
43325
+ getInputAssignedType(inputName) {
43326
+ return lodash.get(this.def, ["assignedTypes", "input", inputName]);
43327
+ }
43328
+
43329
+ getAttributeAssignedType(attrName) {
43330
+ return lodash.get(this.def, ["assignedTypes", "attr", attrName]);
43331
+ }
43332
+
43336
43333
  getDefinitionInputType(inputName) {
43337
43334
  if ((this.isInput() || this.isOutput()) && inputName == "value") {
43338
43335
  return this.getType();
43339
- }
43340
- else {
43336
+ } else {
43341
43337
  var pkg = this.getPackage();
43342
- var type = pkg && pkg.dualbox && pkg.dualbox.input && pkg.dualbox.input[inputName] && pkg.dualbox.input[inputName].type || "*";
43343
- return type;
43338
+ var type = lodash.get(pkg, ["dualbox", "input", inputName, "type"]) || "*";
43339
+
43340
+ if (type === "*") {
43341
+ return this.getLinkedType(inputName);
43342
+ } else {
43343
+ return type;
43344
+ }
43345
+ }
43346
+ }
43347
+
43348
+ // resolve typelinks, if some other linked input has user-assigned type already
43349
+ getLinkedType(inputName) {
43350
+ var linkedType = "*";
43351
+ var inputsDescription = lodash.get(this.getPackage(), ["dualbox", "input"]);
43352
+ var inputDef = inputsDescription[inputName];
43353
+ if (inputDef.typeLink) {
43354
+ var typeLink = inputDef.typeLink;
43355
+ var linkedInputs = lodash.pickBy(inputsDescription, v => v.typeLink === typeLink); // linked inputs
43356
+ lodash.each(linkedInputs, (linkedInputDef, linkedInputName) => {
43357
+ var assignedType = this.getInputAssignedType(linkedInputName);
43358
+ if (assignedType !== undefined && assignedType !== null) {
43359
+ linkedType = assignedType;
43360
+ return false; // eol
43361
+ }
43362
+ });
43363
+
43364
+ return linkedType;
43365
+ } else {
43366
+ return inputDef.type; // should be "*"
43344
43367
  }
43345
43368
  }
43346
43369
 
@@ -43384,8 +43407,7 @@ class GraphNode {
43384
43407
  getDescription() {
43385
43408
  if (this.def.desc) {
43386
43409
  return this.def.desc;
43387
- }
43388
- else {
43410
+ } else {
43389
43411
  var pkg = this.getPackage();
43390
43412
  return pkg && pkg.description;
43391
43413
  }
@@ -43396,9 +43418,11 @@ class GraphNode {
43396
43418
  var pkgDefault = pkg && pkg.dualbox && pkg.dualbox.input && pkg.dualbox.input[inputName] && pkg.dualbox.input[inputName].value;
43397
43419
  var appDefault = this.def.defaultInputs && this.def.defaultInputs[inputName];
43398
43420
 
43399
- if (appDefault !== undefined) { return appDefault; }
43400
- else if (pkgDefault !== undefined) { return pkgDefault; }
43401
- else return undefined;
43421
+ if (appDefault !== undefined) {
43422
+ return appDefault;
43423
+ } else if (pkgDefault !== undefined) {
43424
+ return pkgDefault;
43425
+ } else return undefined;
43402
43426
  }
43403
43427
 
43404
43428
  setInputDefaultValue(inputName, val) {
@@ -43422,15 +43446,13 @@ class GraphNode {
43422
43446
  getOutputType(outputName) {
43423
43447
  if ((this.isInput() || this.isOutput()) && outputName == "value") {
43424
43448
  return this.getType();
43425
- }
43426
- else {
43449
+ } else {
43427
43450
  var pkg = this.getPackage();
43428
43451
  var type = idx_1(pkg, o => o.dualbox.output[outputName].type) || "*";
43429
43452
  if (this.hasLoop()) {
43430
43453
  // if this output is not a feedback, "arrayize" it
43431
43454
  return this.hasFeedback(outputName) ? type : "Array<" + type + ">";
43432
- }
43433
- else {
43455
+ } else {
43434
43456
  return type;
43435
43457
  }
43436
43458
  }
@@ -43470,9 +43492,11 @@ class GraphNode {
43470
43492
  var pkg = this.getPackage();
43471
43493
  var pkgDefault = pkg && pkg.dualbox && pkg.dualbox.attr && pkg.dualbox.attr[attrName].value;
43472
43494
  var appDefault = this.def.attr && this.def.attr[attrName];
43473
- if (appDefault !== undefined) { return appDefault; }
43474
- else if (pkgDefault !== undefined) { return pkgDefault; }
43475
- else return undefined;
43495
+ if (appDefault !== undefined) {
43496
+ return appDefault;
43497
+ } else if (pkgDefault !== undefined) {
43498
+ return pkgDefault;
43499
+ } else return undefined;
43476
43500
  }
43477
43501
 
43478
43502
  setAttributeValue(attrName, val) {
@@ -43499,17 +43523,14 @@ class GraphNode {
43499
43523
  // it's a get
43500
43524
  if (srcType === "input") {
43501
43525
  return this.getInputDefaultValue(name);
43502
- }
43503
- else if (srcType === "attr") {
43526
+ } else if (srcType === "attr") {
43504
43527
  return this.getAttributeValue(name);
43505
43528
  }
43506
- }
43507
- else {
43529
+ } else {
43508
43530
  // it's a set
43509
43531
  if (srcType === "input") {
43510
43532
  return this.setInputDefaultValue(name, val);
43511
- }
43512
- else if (srcType === "attr") {
43533
+ } else if (srcType === "attr") {
43513
43534
  return this.setAttributeValue(name, val);
43514
43535
  }
43515
43536
  }
@@ -43526,8 +43547,7 @@ class GraphNode {
43526
43547
  getValueType(srcType, name) {
43527
43548
  if (srcType === "input") {
43528
43549
  return this.getInputType(name);
43529
- }
43530
- else if (srcType === "attr") {
43550
+ } else if (srcType === "attr") {
43531
43551
  return this.getAttributeType(name);
43532
43552
  }
43533
43553
  }
@@ -43790,17 +43810,14 @@ class GraphNode {
43790
43810
  isInputVisible(inputName) {
43791
43811
  if (this.isInput() || this.isOutput()) {
43792
43812
  return true;
43793
- }
43794
- else {
43813
+ } else {
43795
43814
  if (this.isInputConnected(inputName)) {
43796
43815
  return true;
43797
- }
43798
- else {
43816
+ } else {
43799
43817
  var val = idx_1(this.def, o => o.graph.in.visible[inputName]);
43800
43818
  if (val !== undefined) {
43801
43819
  return val !== false;
43802
- }
43803
- else {
43820
+ } else {
43804
43821
  // check if the app did set a default value for this input
43805
43822
  var defaultVal = idx_1(this.def, o => o.defaultInputs[inputName]);
43806
43823
  if (defaultVal !== undefined) {
@@ -43813,15 +43830,12 @@ class GraphNode {
43813
43830
  if (pkgDef) {
43814
43831
  if (pkgDef.visible === false) {
43815
43832
  return false;
43816
- }
43817
- else if (pkgDef.value !== undefined) {
43833
+ } else if (pkgDef.value !== undefined) {
43818
43834
  return false;
43819
- }
43820
- else {
43835
+ } else {
43821
43836
  return true;
43822
43837
  }
43823
- }
43824
- else {
43838
+ } else {
43825
43839
  return true;
43826
43840
  }
43827
43841
  }
@@ -43832,17 +43846,14 @@ class GraphNode {
43832
43846
  isOutputVisible(outputName) {
43833
43847
  if (this.isInput() || this.isOutput()) {
43834
43848
  return true;
43835
- }
43836
- else {
43849
+ } else {
43837
43850
  if (this.isOutputConnected(outputName)) {
43838
43851
  return true;
43839
- }
43840
- else {
43852
+ } else {
43841
43853
  var val = idx_1(this.def, o => o.graph.out.visible[outputName]);
43842
43854
  if (val === false) {
43843
43855
  return false;
43844
- }
43845
- else {
43856
+ } else {
43846
43857
  var pkg = this.getPackage();
43847
43858
  var pkgDef = idx_1(pkg, o => o.dualbox.output[outputName]);
43848
43859
  return pkgDef.visible !== false;
@@ -43917,11 +43928,9 @@ class GraphNode {
43917
43928
  isInputResolvable(input) {
43918
43929
  if (this.hasDefaultValue(input)) {
43919
43930
  return true;
43920
- }
43921
- else if (this.isInputConnected(input)) {
43931
+ } else if (this.isInputConnected(input)) {
43922
43932
  return true;
43923
- }
43924
- else {
43933
+ } else {
43925
43934
  return false;
43926
43935
  }
43927
43936
  }
@@ -44005,8 +44014,7 @@ class GraphNode {
44005
44014
  if ((this.isInput() || this.isOutput()) && inputName === "value") {
44006
44015
  var targetId = this.isInput() ? "input" : "output";
44007
44016
  var targetInput = this.graphId;
44008
- }
44009
- else {
44017
+ } else {
44010
44018
  var targetId = this.graphId;
44011
44019
  var targetInput = inputName;
44012
44020
  }
@@ -44026,8 +44034,7 @@ class GraphNode {
44026
44034
  if ((this.isInput() || this.isOutput()) && outputName === "value") {
44027
44035
  var sourceId = this.isInput() ? "input" : "output";
44028
44036
  var sourceOutput = this.graphId;
44029
- }
44030
- else {
44037
+ } else {
44031
44038
  var sourceId = this.graphId;
44032
44039
  var sourceOutput = outputName;
44033
44040
  }
@@ -44117,7 +44124,10 @@ class GraphNode {
44117
44124
  }
44118
44125
 
44119
44126
  getPosition() {
44120
- var pos = this.def.graph && this.def.graph.position || { left: 0, top: 0 };
44127
+ var pos = this.def.graph && this.def.graph.position || {
44128
+ left: 0,
44129
+ top: 0
44130
+ };
44121
44131
  pos.top = parseInt(pos.top);
44122
44132
  pos.left = parseInt(pos.left);
44123
44133
  return pos;
@@ -44138,8 +44148,7 @@ class GraphNode {
44138
44148
  if (nodeId == id) {
44139
44149
  if (this.isInput() || this.isOutput()) {
44140
44150
  delete this.def.link;
44141
- }
44142
- else {
44151
+ } else {
44143
44152
  delete this.def.links[inputName];
44144
44153
  }
44145
44154
  }
@@ -44184,10 +44193,18 @@ class GraphNode {
44184
44193
 
44185
44194
  addTo(app) {
44186
44195
  switch (this.type) {
44187
- case "module": app.modules[this.graphId] = this.def; break;
44188
- case "ui": app.ui[this.graphId] = this.def; break;
44189
- case "input": app.input[this.graphId] = this.def; break;
44190
- case "output": app.output[this.graphId] = this.def; break;
44196
+ case "module":
44197
+ app.modules[this.graphId] = this.def;
44198
+ break;
44199
+ case "ui":
44200
+ app.ui[this.graphId] = this.def;
44201
+ break;
44202
+ case "input":
44203
+ app.input[this.graphId] = this.def;
44204
+ break;
44205
+ case "output":
44206
+ app.output[this.graphId] = this.def;
44207
+ break;
44191
44208
  default:
44192
44209
  throw "wtf";
44193
44210
  }
@@ -44198,8 +44215,12 @@ class GraphNode {
44198
44215
  this.detachEvents();
44199
44216
 
44200
44217
  switch (this.type) {
44201
- case "module": delete app.modules[this.graphId]; break;
44202
- case "ui": delete app.ui[this.graphId]; break;
44218
+ case "module":
44219
+ delete app.modules[this.graphId];
44220
+ break;
44221
+ case "ui":
44222
+ delete app.ui[this.graphId];
44223
+ break;
44203
44224
  case "input":
44204
44225
  delete app.input[this.graphId];
44205
44226
  if (!this.m.isRootApp(app)) {
@@ -44301,22 +44322,18 @@ class GraphNode {
44301
44322
  if (this.isInput()) {
44302
44323
  if (newId.startsWith(this.m.inputPrefix)) {
44303
44324
  newGraphId = newId.substring(3);
44304
- }
44305
- else {
44325
+ } else {
44306
44326
  newGraphId = newId;
44307
44327
  newId = this.m.inputPrefix + newId;
44308
44328
  }
44309
- }
44310
- else if (this.isOutput()) {
44329
+ } else if (this.isOutput()) {
44311
44330
  if (newId.startsWith(this.m.outputPrefix)) {
44312
44331
  newGraphId = newId.substring(4);
44313
- }
44314
- else {
44332
+ } else {
44315
44333
  newGraphId = newId;
44316
44334
  newId = this.m.outputPrefix + newId;
44317
44335
  }
44318
- }
44319
- else {
44336
+ } else {
44320
44337
  newGraphId = newId;
44321
44338
  }
44322
44339
 
@@ -44372,8 +44389,7 @@ class GraphNode {
44372
44389
  }
44373
44390
  });
44374
44391
  });
44375
- }
44376
- else if (this.isOutput()) {
44392
+ } else if (this.isOutput()) {
44377
44393
  // get inboundLinks of this node that target this input, and detach them
44378
44394
  lodash.each(parentNodes, (n) => {
44379
44395
  lodash.each(n.getOutboundLinks(), (l) => {
@@ -44416,8 +44432,7 @@ class GraphNode {
44416
44432
  lodash.each(links2node, (link) => {
44417
44433
  if (link.sourceId == "input" || link.sourceId == "output") {
44418
44434
  link.sourceOutput = newId;
44419
- }
44420
- else {
44435
+ } else {
44421
44436
  link.sourceId = newId;
44422
44437
  }
44423
44438
  link.attach();
@@ -44480,8 +44495,7 @@ class DataLink {
44480
44495
  if (sourceNode.isInput()) {
44481
44496
  this.sourceId = "input";
44482
44497
  this.sourceOutput = this.m.inputPrefix + sourceNode.graphId;
44483
- }
44484
- else if (sourceNode.isOutput()) {
44498
+ } else if (sourceNode.isOutput()) {
44485
44499
  this.sourceId = "output";
44486
44500
  this.sourceOutput = this.m.outputPrefix + sourceNode.graphId;
44487
44501
  }
@@ -44490,8 +44504,7 @@ class DataLink {
44490
44504
  if (targetNode.isInput()) {
44491
44505
  this.targetId = "input";
44492
44506
  this.targetInput = this.m.inputPrefix + targetNode.graphId;
44493
- }
44494
- else if (targetNode.isOutput()) {
44507
+ } else if (targetNode.isOutput()) {
44495
44508
  this.targetId = "output";
44496
44509
  this.targetInput = this.m.outputPrefix + targetNode.graphId;
44497
44510
  }
@@ -44501,20 +44514,16 @@ class DataLink {
44501
44514
  if (this.sourceId === "input") {
44502
44515
  if (this.sourceOutput.startsWith(this.m.inputPrefix)) {
44503
44516
  return this.m.getNode(this.sourceOutput);
44504
- }
44505
- else {
44517
+ } else {
44506
44518
  return this.m.getNode(this.m.inputPrefix + this.sourceOutput);
44507
44519
  }
44508
- }
44509
- else if (this.sourceId === "output") {
44520
+ } else if (this.sourceId === "output") {
44510
44521
  if (this.sourceOutput.startsWith(this.m.outputPrefix)) {
44511
44522
  return this.m.getNode(this.sourceOutput);
44512
- }
44513
- else {
44523
+ } else {
44514
44524
  return this.m.getNode(this.m.outputPrefix + this.sourceOutput);
44515
44525
  }
44516
- }
44517
- else {
44526
+ } else {
44518
44527
  return this.m.getNode(this.sourceId);
44519
44528
  }
44520
44529
  }
@@ -44523,20 +44532,16 @@ class DataLink {
44523
44532
  if (this.targetId === "input") {
44524
44533
  if (this.targetInput.startsWith(this.m.inputPrefix)) {
44525
44534
  return this.m.getNode(this.targetInput);
44526
- }
44527
- else {
44535
+ } else {
44528
44536
  return this.m.getNode(this.m.inputPrefix + this.targetInput);
44529
44537
  }
44530
- }
44531
- else if (this.targetId == "output") {
44538
+ } else if (this.targetId == "output") {
44532
44539
  if (this.targetInput.startsWith(this.m.outputPrefix)) {
44533
44540
  return this.m.getNode(this.targetInput);
44534
- }
44535
- else {
44541
+ } else {
44536
44542
  return this.m.getNode(this.m.outputPrefix + this.targetInput);
44537
44543
  }
44538
- }
44539
- else {
44544
+ } else {
44540
44545
  return this.m.getNode(this.targetId);
44541
44546
  }
44542
44547
  }
@@ -44558,8 +44563,7 @@ class DataLink {
44558
44563
  def.graph = def.graph || {};
44559
44564
  def.graph.path = def.graph.path || [];
44560
44565
  def.graph.path.unshift(pos);
44561
- }
44562
- else {
44566
+ } else {
44563
44567
  // we need to find pos1 in the array to add pos at the right location
44564
44568
  var index;
44565
44569
  lodash.each(def.graph.path, (p, i) => {
@@ -44607,11 +44611,9 @@ class DataLink {
44607
44611
  var targetNode = this.getTargetNode();
44608
44612
  if (targetNode.isInput()) {
44609
44613
  return targetNode.def.link;
44610
- }
44611
- else if (targetNode.isOutput()) {
44614
+ } else if (targetNode.isOutput()) {
44612
44615
  return targetNode.def.link;
44613
- }
44614
- else {
44616
+ } else {
44615
44617
  return targetNode.def.links && targetNode.def.links[this.targetInput] || {};
44616
44618
  }
44617
44619
  }
@@ -44624,11 +44626,9 @@ class DataLink {
44624
44626
  var targetNode = this.getTargetNode();
44625
44627
  if (targetNode.isInput()) {
44626
44628
  targetNode.def.link = def;
44627
- }
44628
- else if (targetNode.isOutput()) {
44629
+ } else if (targetNode.isOutput()) {
44629
44630
  targetNode.def.link = def;
44630
- }
44631
- else {
44631
+ } else {
44632
44632
  targetNode.def.links = targetNode.def.links || {};
44633
44633
  targetNode.def.links[this.targetInput] = def;
44634
44634
  }
@@ -44646,12 +44646,14 @@ class DataLink {
44646
44646
  // build the connection object
44647
44647
  var sourceNode = this.getSourceNode();
44648
44648
  if (sourceNode.isInput()) {
44649
- var connection = { "input": sourceNode.graphId };
44650
- }
44651
- else if (sourceNode.isOutput()) {
44652
- var connection = { "output": sourceNode.graphId };
44653
- }
44654
- else {
44649
+ var connection = {
44650
+ "input": sourceNode.graphId
44651
+ };
44652
+ } else if (sourceNode.isOutput()) {
44653
+ var connection = {
44654
+ "output": sourceNode.graphId
44655
+ };
44656
+ } else {
44655
44657
  var connection = {};
44656
44658
  connection[sourceNode.graphId] = this.sourceOutput;
44657
44659
  }
@@ -44666,7 +44668,7 @@ class DataLink {
44666
44668
  var l = new DataLink(this.m, key, val, this.targetId, this.targetInput);
44667
44669
  if (!this.equals(l)) {
44668
44670
  throw "Can not add link " + this.sourceId + ":" + this.sourceOutput + " -> " +
44669
- this.targetId + ":" + this.targetInput + " : a link already exist to target input";
44671
+ this.targetId + ":" + this.targetInput + " : a link already exist to target input";
44670
44672
  }
44671
44673
  }
44672
44674
 
@@ -44678,8 +44680,7 @@ class DataLink {
44678
44680
  var targetNode = this.getTargetNode();
44679
44681
  if (targetNode.isInput() || targetNode.isOutput()) {
44680
44682
  delete targetNode.def.link;
44681
- }
44682
- else {
44683
+ } else {
44683
44684
  delete targetNode.def.links[this.targetInput];
44684
44685
  }
44685
44686
  }
@@ -44731,8 +44732,7 @@ class EventLink {
44731
44732
 
44732
44733
  if (index) {
44733
44734
  n.def.events[index] = def;
44734
- }
44735
- else {
44735
+ } else {
44736
44736
  n.def.events.push(def);
44737
44737
  }
44738
44738
  }
@@ -44767,8 +44767,7 @@ class EventLink {
44767
44767
  def.graph = def.graph || {};
44768
44768
  def.graph.path = def.graph.path || [];
44769
44769
  def.graph.path.unshift(pos);
44770
- }
44771
- else {
44770
+ } else {
44772
44771
  // we need to find pos1 in the array to add pos at the right location
44773
44772
  var index;
44774
44773
  lodash.each(def.graph.path, (p, i) => {
@@ -44901,7 +44900,10 @@ class Application {
44901
44900
  addSubEvent(name, nodeName, evtName) {
44902
44901
  var inputEvents = lodash.get(this.json.events, [name, "in"]);
44903
44902
  if (!inputEvents) inputEvents = [];
44904
- inputEvents.push({ "node": nodeName, "event": evtName });
44903
+ inputEvents.push({
44904
+ "node": nodeName,
44905
+ "event": evtName
44906
+ });
44905
44907
  }
44906
44908
 
44907
44909
  addCallback(name) {
@@ -44917,7 +44919,9 @@ class Application {
44917
44919
  }
44918
44920
 
44919
44921
  addAppEvent(name) {
44920
- this.json.events[name] = { "in": [] };
44922
+ this.json.events[name] = {
44923
+ "in": []
44924
+ };
44921
44925
  }
44922
44926
  }
44923
44927
 
@@ -45706,12 +45710,23 @@ var script = {
45706
45710
  // resize the canvas if necessary
45707
45711
  self.$parent.canvasSizeHandler.debouncedResize();
45708
45712
 
45709
- // set the new position in the graph model
45710
- var el = self.$parent.jsPlumbInstance.getElement(id);
45711
- $(el).ready(function() {
45712
- var pos = self.$parent.jsPlumbInstance.getPosition(el);
45713
- view.m.getNode(id).setPosition(pos);
45714
- });
45713
+ if( self.$parent.selector.isMultipleSelectionActive() ) {
45714
+ // We just dropped a bunch of divs, ajust all their positions
45715
+ self.view.m.history.batch(() => {
45716
+ self.$parent.selector.each(div => {
45717
+ var pos = self.$parent.jsPlumbInstance.getPosition(div);
45718
+ view.m.getNode($(div).attr('id')).setPosition(pos);
45719
+ });
45720
+ });
45721
+ }
45722
+ else {
45723
+ // We just dropped this one, set the new position in the graph model
45724
+ var el = self.$parent.jsPlumbInstance.getElement(id);
45725
+ $(el).ready(function() {
45726
+ var pos = self.$parent.jsPlumbInstance.getPosition(el);
45727
+ view.m.getNode(id).setPosition(pos);
45728
+ });
45729
+ }
45715
45730
  }
45716
45731
  });
45717
45732
  }
@@ -46348,7 +46363,7 @@ __vue_render__._withStripped = true;
46348
46363
  /* style */
46349
46364
  const __vue_inject_styles__ = function (inject) {
46350
46365
  if (!inject) return
46351
- inject("data-v-0f18803e_0", { source: "\n.card-ui {\n background-color: #bff2ca!important;\n}\n.card-loop {\n /* background-color: #e5e8ea!important; */\n border: 5px double #dddddd;\n border-width: 4px;\n}\n.card-input {\n background-color: #f5d76e!important;\n}\n.card-output {\n background-color: #ffb3a7!important;\n}\n.box-inputs {\n float: left;\n padding-left: 2px;\n padding-right: 5px;\n vertical-align: top;\n text-align: left;\n}\n.box-outputs {\n float: right;\n padding-left: 5px;\n padding-right: 2px;\n vertical-align: top;\n text-align: right;\n}\n.dualbox-graph-canvas .card, .card-node {\n /*border: 1px solid #dddddd;*/\n box-shadow: 1px 1px 5px #716f6f;\n opacity: 1;\n cursor: pointer;\n z-index: 20;\n position: absolute;\n\n -webkit-transition: -webkit-box-shadow 0.15s ease-in;\n -moz-transition: -moz-box-shadow 0.15s ease-in;\n -o-transition: -o-box-shadow 0.15s ease-in;\n transition: box-shadow 0.15s ease-in;\n\n color: #4d4d4d;\n user-select: none;\n padding: 0px 8px 0px 8px;\n overflow:hidden;\n background-color: #fff;\n -moz-border-radius: 3px;\n border-radius:3px;\n font-size: 14px;\n font-family: \"Helvetica Neue\", Arial, Helvetica, sans-serif;\n}\n.card-node .card-top {\n padding-top: 2px;\n}\n.card-node .card-bottom {\n padding-bottom: 2px;\n text-align: center;\n line-height: 14px;\n white-space: nowrap;\n}\n.card-node hr {\n margin-top: 2px;\n margin-bottom: 2px;\n border-color: rgba(0,0,0,0.1);\n margin-left: -8px;\n margin-right: -8px;\n}\n.card-node:hover {\n border-color: #80b2fc;\n box-shadow: 1px 1px 10px #80b2fc;\n}\n.card-node.selected, .card-node.selected:hover {\n border-color: #0066ff;\n box-shadow: 1px 1px 10px #0066ff;\n}\n.card-node-incomplete {\n box-shadow: 1px 1px 5px #dd6666 !important;\n}\n.input-not-resolvable {\n color: #dd6666!important;\n}\n.card-node .title {\n vertical-align:top;\n font-weight: bold;\n}\n.card-node .subtitle {\n color:#929292;\n font-size: 11px;\n font-style: italic;\n vertical-align:center;\n font-family: tahoma, sans-serif;\n}\n.card-node .input {\n font-size: 13px;\n color: #8c8c8c;\n}\n.card-node .output {\n font-size: 13px;\n color: #8c8c8c;\n text-align:right;\n}\n.card-node .jtk-endpoint.active svg circle {\n /* fill: #99ff33 */\n stroke: #59b300;\n}\n.point {\n /* display: inline-block; */\n display: none;\n position: relative;\n top: 3px;\n margin-right: 5px;\n margin-left: 5px;\n}\n.dualbox-io {\n overflow: visible;\n margin-left: -8px;\n margin-right: -8px;\n}\n.box-inputs {\n display: flex;\n justify-content: space-between;\n position: relative;\n padding: 0;\n pointer-events: none;\n}\n.types {\n color: #6c757d!important;\n opacity: 0.7;\n pointer-events: none;\n}\n.box-inputs .types {\n display: inline-block;\n}\n.box-inputs .name {\n display: inline-block;\n}\n.box-inputs .type {\n display: block;\n text-align: right;\n}\n.box-inputs .point {\n display: block;\n}\n.box-inputs .name {\n display: block;\n}\n.box-outputs {\n display: flex;\n justify-content: center;\n position: relative;\n padding: 0;\n pointer-events: none;\n}\n.box-outputs .types {\n display: inline-block;\n}\n.box-outputs .point {\n display: inline-block;\n}\n.box-outputs .name {\n display: inline-block;\n}\n.box-outputs .type {\n display: block;\n text-align: left;\n}\n.box-outputs .point {\n display: block;\n}\n.box-outputs .name {\n display: block;\n}\nspan.feedback {\n font-weight: bold;\n}\n.event-dock {\n background-color: rgb(136, 137, 138);\n background-color: #a6a6a6;\n width: calc(100% + 18px);\n height: 12px;\n z-index: 3!important;\n}\n.event-dock-top {\n margin-left: -9px;\n margin-right: -9px;\n margin-top: -3px;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n margin-bottom: 4px;\n}\n.event-dock-bottom {\n margin-left: -9px;\n margin-right: -9px;\n margin-bottom: -3px;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n margin-top: 4px;\n height: 11px; /* shorter because of box-shadow */\n}\n.event-label {\n z-index: 21;\n padding-left: 15px;\n transform: rotate(-90deg) translate(0%, -50%)!important;\n transform-origin: 0% 0%;\n color: #6c757d!important;\n font-family: \"Helvetica Neue\", Arial, Helvetica, sans-serif;\n font-size: 14px;\n opacity: 0.7;\n cursor: pointer;\n}\n.transparent {\n opacity: 0.3!important;\n}\n.card-node {\n position: relative;\n}\n.card-comment {\n position: absolute;\n top: 0;\n right: 0;\n margin-top: -22px;\n color: #f4ad42!important;\n}\n.card-problem {\n position: absolute;\n top: 0;\n left: 0;\n margin-top: -22px;\n color: red!important;\n}\n.card-snapshot {\n}\n.card-snapshot-idle {\n border: 2px solid gray!important;\n box-shadow: 1px 1px 5px gray!important;\n opacity: 0.7!important;\n}\n.card-snapshot-computing {\n border: 2px solid darkgreen!important;\n box-shadow: 1px 1px 5px darkgreen!important;\n opacity: 1!important;\n}\n.card-snapshot-awaiting-data {\n border: 2px solid blue!important;\n box-shadow: 1px 1px 5px blue!important;\n opacity: 0.7!important;\n}\n.card-snapshot-ready {\n border: 2px solid lightgreen!important;\n box-shadow: 1px 1px 5px lightgreen!important;\n opacity: 1!important;\n}\n.card-status {\n position: absolute;\n bottom: 0;\n right: 0;\n left: 0;\n margin-bottom: -26px;\n color: #f4ad42!important;\n font-family: \"Helvetica Neue\", Arial, Helvetica, sans-serif;\n font-weight: bold;\n text-align: center;\n}\n.card-status-idle {\n color: gray!important;\n min-width: 85px;\n}\n.card-status-computing {\n color: darkgreen!important;\n min-width: 110px;\n}\n.card-status-awaiting-data {\n color: blue!important;\n min-width: 85px;\n}\n.card-status-ready {\n color: lightgreen!important;\n min-width: 85px;\n}\n.btn-snapshot-details {\n position: relative;\n margin-top: -2px;\n color: inherit;\n}\nspan.name {\n overflow-wrap: normal;\n}\n", map: {"version":3,"sources":["/home/seb/dev/dualbox/editor/js/src/v/templates/graphNode.vue"],"names":[],"mappings":";AACA;IACA,mCAAA;AACA;AAEA;IACA,yCAAA;IACA,0BAAA;IACA,iBAAA;AACA;AAEA;IACA,mCAAA;AACA;AAEA;IACA,mCAAA;AACA;AAEA;IACA,WAAA;IACA,iBAAA;IACA,kBAAA;IACA,mBAAA;IACA,gBAAA;AACA;AAEA;IACA,YAAA;IACA,iBAAA;IACA,kBAAA;IACA,mBAAA;IACA,iBAAA;AACA;AAEA;IACA,6BAAA;IACA,+BAAA;IACA,UAAA;IACA,eAAA;IACA,WAAA;IACA,kBAAA;;IAEA,oDAAA;IACA,8CAAA;IACA,0CAAA;IACA,oCAAA;;IAEA,cAAA;IACA,iBAAA;IACA,wBAAA;IACA,eAAA;IACA,sBAAA;IACA,uBAAA;IACA,iBAAA;IACA,eAAA;IACA,2DAAA;AACA;AAEA;IACA,gBAAA;AACA;AAEA;IACA,mBAAA;IACA,kBAAA;IACA,iBAAA;IACA,mBAAA;AACA;AAEA;IACA,eAAA;IACA,kBAAA;IACA,6BAAA;IACA,iBAAA;IACA,kBAAA;AACA;AAEA;IACA,qBAAA;IACA,gCAAA;AACA;AAEA;IACA,qBAAA;IACA,gCAAA;AACA;AAEA;IACA,0CAAA;AACA;AAEA;IACA,wBAAA;AACA;AAEA;IACA,kBAAA;IACA,iBAAA;AACA;AAEA;IACA,aAAA;IACA,eAAA;IACA,kBAAA;IACA,qBAAA;IACA,+BAAA;AACA;AAEA;IACA,eAAA;IACA,cAAA;AACA;AAEA;IACA,eAAA;IACA,cAAA;IACA,gBAAA;AACA;AAEA;IACA,kBAAA;IACA,eAAA;AACA;AAEA;IACA,2BAAA;IACA,aAAA;IACA,kBAAA;IACA,QAAA;IACA,iBAAA;IACA,gBAAA;AACA;AAEA;IACA,iBAAA;IACA,iBAAA;IACA,kBAAA;AACA;AAEA;IACA,aAAA;IACA,8BAAA;IACA,kBAAA;IACA,UAAA;IACA,oBAAA;AACA;AAEA;IACA,wBAAA;IACA,YAAA;IACA,oBAAA;AACA;AAEA;IACA,qBAAA;AACA;AAEA;IACA,qBAAA;AACA;AAEA;IACA,cAAA;IACA,iBAAA;AACA;AAEA;IACA,cAAA;AACA;AAEA;IACA,cAAA;AACA;AAEA;IACA,aAAA;IACA,uBAAA;IACA,kBAAA;IACA,UAAA;IACA,oBAAA;AACA;AAEA;IACA,qBAAA;AACA;AAEA;IACA,qBAAA;AACA;AAEA;IACA,qBAAA;AACA;AAEA;IACA,cAAA;IACA,gBAAA;AACA;AAEA;IACA,cAAA;AACA;AAEA;IACA,cAAA;AACA;AAEA;IACA,iBAAA;AACA;AAEA;IACA,oCAAA;IACA,2BAAA;IACA,wBAAA;IACA,YAAA;IACA,oBAAA;AACA;AAEA;IACA,iBAAA;IACA,kBAAA;IACA,gBAAA;IACA,2BAAA;IACA,4BAAA;IACA,kBAAA;AACA;AAEA;IACA,iBAAA;IACA,kBAAA;IACA,mBAAA;IACA,8BAAA;IACA,+BAAA;IACA,eAAA;IACA,YAAA,EAAA,kCAAA;AACA;AAEA;IACA,WAAA;IACA,kBAAA;IACA,uDAAA;IACA,uBAAA;IACA,wBAAA;IACA,2DAAA;IACA,eAAA;IACA,YAAA;IACA,eAAA;AACA;AAEA;IACA,sBAAA;AACA;AAEA;IACA,kBAAA;AACA;AAEA;IACA,kBAAA;IACA,MAAA;IACA,QAAA;IACA,iBAAA;IACA,wBAAA;AACA;AAEA;IACA,kBAAA;IACA,MAAA;IACA,OAAA;IACA,iBAAA;IACA,oBAAA;AACA;AAEA;AAEA;AAEA;IACA,gCAAA;IACA,sCAAA;IACA,sBAAA;AACA;AAEA;IACA,qCAAA;IACA,2CAAA;IACA,oBAAA;AACA;AAEA;IACA,gCAAA;IACA,sCAAA;IACA,sBAAA;AACA;AAEA;IACA,sCAAA;IACA,4CAAA;IACA,oBAAA;AACA;AAEA;IACA,kBAAA;IACA,SAAA;IACA,QAAA;IACA,OAAA;IACA,oBAAA;IACA,wBAAA;IACA,2DAAA;IACA,iBAAA;IACA,kBAAA;AACA;AAEA;IACA,qBAAA;IACA,eAAA;AACA;AAEA;IACA,0BAAA;IACA,gBAAA;AACA;AAEA;IACA,qBAAA;IACA,eAAA;AACA;AAEA;IACA,2BAAA;IACA,eAAA;AACA;AAEA;IACA,kBAAA;IACA,gBAAA;IACA,cAAA;AACA;AAEA;IACA,qBAAA;AACA","file":"graphNode.vue","sourcesContent":["<style>\n.card-ui {\n background-color: #bff2ca!important;\n}\n\n.card-loop {\n /* background-color: #e5e8ea!important; */\n border: 5px double #dddddd;\n border-width: 4px;\n}\n\n.card-input {\n background-color: #f5d76e!important;\n}\n\n.card-output {\n background-color: #ffb3a7!important;\n}\n\n.box-inputs {\n float: left;\n padding-left: 2px;\n padding-right: 5px;\n vertical-align: top;\n text-align: left;\n}\n\n.box-outputs {\n float: right;\n padding-left: 5px;\n padding-right: 2px;\n vertical-align: top;\n text-align: right;\n}\n\n.dualbox-graph-canvas .card, .card-node {\n /*border: 1px solid #dddddd;*/\n box-shadow: 1px 1px 5px #716f6f;\n opacity: 1;\n cursor: pointer;\n z-index: 20;\n position: absolute;\n\n -webkit-transition: -webkit-box-shadow 0.15s ease-in;\n -moz-transition: -moz-box-shadow 0.15s ease-in;\n -o-transition: -o-box-shadow 0.15s ease-in;\n transition: box-shadow 0.15s ease-in;\n\n color: #4d4d4d;\n user-select: none;\n padding: 0px 8px 0px 8px;\n overflow:hidden;\n background-color: #fff;\n -moz-border-radius: 3px;\n border-radius:3px;\n font-size: 14px;\n font-family: \"Helvetica Neue\", Arial, Helvetica, sans-serif;\n}\n\n.card-node .card-top {\n padding-top: 2px;\n}\n\n.card-node .card-bottom {\n padding-bottom: 2px;\n text-align: center;\n line-height: 14px;\n white-space: nowrap;\n}\n\n.card-node hr {\n margin-top: 2px;\n margin-bottom: 2px;\n border-color: rgba(0,0,0,0.1);\n margin-left: -8px;\n margin-right: -8px;\n}\n\n.card-node:hover {\n border-color: #80b2fc;\n box-shadow: 1px 1px 10px #80b2fc;\n}\n\n.card-node.selected, .card-node.selected:hover {\n border-color: #0066ff;\n box-shadow: 1px 1px 10px #0066ff;\n}\n\n.card-node-incomplete {\n box-shadow: 1px 1px 5px #dd6666 !important;\n}\n\n.input-not-resolvable {\n color: #dd6666!important;\n}\n\n.card-node .title {\n vertical-align:top;\n font-weight: bold;\n}\n\n.card-node .subtitle {\n color:#929292;\n font-size: 11px;\n font-style: italic;\n vertical-align:center;\n font-family: tahoma, sans-serif;\n}\n\n.card-node .input {\n font-size: 13px;\n color: #8c8c8c;\n}\n\n.card-node .output {\n font-size: 13px;\n color: #8c8c8c;\n text-align:right;\n}\n\n.card-node .jtk-endpoint.active svg circle {\n /* fill: #99ff33 */\n stroke: #59b300;\n}\n\n.point {\n /* display: inline-block; */\n display: none;\n position: relative;\n top: 3px;\n margin-right: 5px;\n margin-left: 5px;\n}\n\n.dualbox-io {\n overflow: visible;\n margin-left: -8px;\n margin-right: -8px;\n}\n\n.box-inputs {\n display: flex;\n justify-content: space-between;\n position: relative;\n padding: 0;\n pointer-events: none;\n}\n\n.types {\n color: #6c757d!important;\n opacity: 0.7;\n pointer-events: none;\n}\n\n.box-inputs .types {\n display: inline-block;\n}\n\n.box-inputs .name {\n display: inline-block;\n}\n\n.box-inputs .type {\n display: block;\n text-align: right;\n}\n\n.box-inputs .point {\n display: block;\n}\n\n.box-inputs .name {\n display: block;\n}\n\n.box-outputs {\n display: flex;\n justify-content: center;\n position: relative;\n padding: 0;\n pointer-events: none;\n}\n\n.box-outputs .types {\n display: inline-block;\n}\n\n.box-outputs .point {\n display: inline-block;\n}\n\n.box-outputs .name {\n display: inline-block;\n}\n\n.box-outputs .type {\n display: block;\n text-align: left;\n}\n\n.box-outputs .point {\n display: block;\n}\n\n.box-outputs .name {\n display: block;\n}\n\nspan.feedback {\n font-weight: bold;\n}\n\n.event-dock {\n background-color: rgb(136, 137, 138);\n background-color: #a6a6a6;\n width: calc(100% + 18px);\n height: 12px;\n z-index: 3!important;\n}\n\n.event-dock-top {\n margin-left: -9px;\n margin-right: -9px;\n margin-top: -3px;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n margin-bottom: 4px;\n}\n\n.event-dock-bottom {\n margin-left: -9px;\n margin-right: -9px;\n margin-bottom: -3px;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n margin-top: 4px;\n height: 11px; /* shorter because of box-shadow */\n}\n\n.event-label {\n z-index: 21;\n padding-left: 15px;\n transform: rotate(-90deg) translate(0%, -50%)!important;\n transform-origin: 0% 0%;\n color: #6c757d!important;\n font-family: \"Helvetica Neue\", Arial, Helvetica, sans-serif;\n font-size: 14px;\n opacity: 0.7;\n cursor: pointer;\n}\n\n.transparent {\n opacity: 0.3!important;\n}\n\n.card-node {\n position: relative;\n}\n\n.card-comment {\n position: absolute;\n top: 0;\n right: 0;\n margin-top: -22px;\n color: #f4ad42!important;\n}\n\n.card-problem {\n position: absolute;\n top: 0;\n left: 0;\n margin-top: -22px;\n color: red!important;\n}\n\n.card-snapshot {\n\n}\n\n.card-snapshot-idle {\n border: 2px solid gray!important;\n box-shadow: 1px 1px 5px gray!important;\n opacity: 0.7!important;\n}\n\n.card-snapshot-computing {\n border: 2px solid darkgreen!important;\n box-shadow: 1px 1px 5px darkgreen!important;\n opacity: 1!important;\n}\n\n.card-snapshot-awaiting-data {\n border: 2px solid blue!important;\n box-shadow: 1px 1px 5px blue!important;\n opacity: 0.7!important;\n}\n\n.card-snapshot-ready {\n border: 2px solid lightgreen!important;\n box-shadow: 1px 1px 5px lightgreen!important;\n opacity: 1!important;\n}\n\n.card-status {\n position: absolute;\n bottom: 0;\n right: 0;\n left: 0;\n margin-bottom: -26px;\n color: #f4ad42!important;\n font-family: \"Helvetica Neue\", Arial, Helvetica, sans-serif;\n font-weight: bold;\n text-align: center;\n}\n\n.card-status-idle {\n color: gray!important;\n min-width: 85px;\n}\n\n.card-status-computing {\n color: darkgreen!important;\n min-width: 110px;\n}\n\n.card-status-awaiting-data {\n color: blue!important;\n min-width: 85px;\n}\n\n.card-status-ready {\n color: lightgreen!important;\n min-width: 85px;\n}\n\n.btn-snapshot-details {\n position: relative;\n margin-top: -2px;\n color: inherit;\n}\n\nspan.name {\n overflow-wrap: normal;\n}\n</style>\n\n<template>\n <div class=\"jtk-node card card-node contextmenu\" v-bind:class=\"{ 'card-loop': n.hasLoop(), 'card-ui': n.isUI(), 'card-metanode': n.isMetanode(), 'card-input': n.isInput(), 'card-output': n.isOutput(), 'card-snapshot': n.hasSnapshot(), 'card-snapshot-idle': n.hasSnapshot() && n.isSnapshotStatus(0), 'card-snapshot-computing': n.hasSnapshot() && n.isSnapshotStatus(1), 'card-snapshot-awaiting-data': n.hasSnapshot() && n.isSnapshotStatus(2), 'card-snapshot-ready': n.hasSnapshot() && n.isSnapshotStatus(3) }\" v-bind:id=\"getId()\" v-bind:data-id=\"getId()\" v-bind:data-name=\"pkg.name\" style=\"overflow: visible;\">\n <div v-if=\"n.hasComment()\">\n <div class=\"card-comment\" data-toggle=\"tooltip\" data-placement=\"top\" :title=\"n.getComment()\">\n <i class=\"fas fa-comment-alt\" data-container=\"body\"></i>\n </div>\n </div>\n\n <div v-if=\"n.hasSnapshot()\">\n <div class=\"card-status\">\n <div v-if=\"n.isSnapshotStatus(0)\">\n <div class=\"card-status-idle\">\n <span>IDLE</span>\n <button class=\"btn btn-editor-xs btn-outline-secondary btn-outline-discrete btn-snapshot-details d-inline-block\" data-id=\"getId()\" v-on:click=\"openSnapshotDetails\"><i class=\"fas fa-info-circle\"></i></button>\n </div>\n </div>\n\n <div v-if=\"n.isSnapshotStatus(1)\">\n <div class=\"card-status-computing\">\n <span>COMPUTING</span>\n <button class=\"btn btn-editor-xs btn-outline-secondary btn-outline-discrete btn-snapshot-details d-inline-block\" data-id=\"getId()\" v-on:click=\"openSnapshotDetails\"><i class=\"fas fa-info-circle\"></i></button>\n </div>\n </div>\n\n <div v-if=\"n.isSnapshotStatus(2)\">\n <div class=\"card-status-awaiting-data\">\n <span>WAITING</span>\n <button class=\"btn btn-editor-xs btn-outline-secondary btn-outline-discrete btn-snapshot-details d-inline-block\" data-id=\"getId()\" v-on:click=\"openSnapshotDetails\"><i class=\"fas fa-info-circle\"></i></button>\n </div>\n </div>\n\n <div v-if=\"n.isSnapshotStatus(3)\">\n <div class=\"card-status-ready\">\n <span>READY</span>\n <button class=\"btn btn-editor-xs btn-outline-secondary btn-outline-discrete btn-snapshot-details d-inline-block\" data-id=\"getId()\" v-on:click=\"openSnapshotDetails\"><i class=\"fas fa-info-circle\"></i></button>\n </div>\n </div>\n </div>\n </div>\n\n <div v-if=\"!example && n.isUI() && !n.isOnAPanel()\">\n <div class=\"card-problem\">\n <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>\n </div>\n </div>\n\n <div class=\"card-top\">\n <div class=\"d-flex\">\n <span class=\"title\" style=\"white-space: nowrap; margin-right: 5px;\">\n <span v-if=\"n.isMetanode()\" class=\"badge badge-secondary\"><b>META</b></span>\n {{n.graphId}}\n <i v-if=\"n.isParallel()\" class=\"fas fa-server\" style=\"color: orange;\" title=\"this module is computed in a web worker\"></i>\n </span>\n\n <div class=\"ml-auto\">\n <button class=\"btn btn-outline-secondary btn-outline-discrete btn-editor-xs btn-settings\" v-on:click=\"openNodeSettings\"><i class=\"fas fa-cog\"></i></button>\n </div>\n </div>\n </div>\n <div v-if=\"!n.isInput() && !n.isOutput()\" class=\"card-center\">\n <hr style=\"margin-bottom: 5px;\"/>\n <div class=\"dualbox-io\" style=\"overflow: visible;\">\n <div class=\"inputs\" style=\"display: inline-block; float: left;\">\n <div class=\"box-inputs\">\n <div class=\"types\">\n <span class=\"type\" v-for=\"key in getVisibleInputs()\" v-bind:data-key=\"key\">\n {{ n.getInputType(key) }}\n </span>\n </div>\n <div class=\"points\">\n <div class=\"point\" v-for=\"key in getVisibleInputs()\" v-bind:data-key=\"key\" v-bind:data-type=\"n.getInputDef(key).type\" v-html=\"point\"></div>\n </div>\n <div class=\"names\">\n <span class=\"name\" v-for=\"key in getVisibleInputs()\" :class=\"{'feedback': n.isFeedbackTarget(key), 'input-not-resolvable': !example && !n.isInputResolvable(key) }\" v-bind:data-input=\"key\">\n <span v-if=\"n.hasIterator(key)\">&lt;{{key}}&gt;</span>\n <span v-else>{{key}}</span>\n <small v-if=\"!n.isInputConst(key)\" data-toggle=\"tooltip\" data-trigger=\"hover\" title=\"this value will be cloned at execution time\"><i class=\"fas fa-clone transparent\"></i></small>\n </span>\n </div>\n </div>\n </div>\n <div class=\"outputs\" style=\"display: inline-block; float: right\">\n <div class=\"box-outputs\">\n <div class=\"names\">\n <span class=\"name\" v-for=\"key in getVisibleOutputs()\" v-bind:class=\"{feedback: n.isFeedbackTarget(key)}\" v-bind:data-output=\"key\">\n <span v-if=\"n.hasLoop() && n.hasFeedback(key)\">{{key}}</span>\n <span v-else-if=\"n.hasLoop() && !n.hasFeedback(key)\" v-html='\"&lt;\"+key+\"&gt;\"'></span>\n <span v-else>{{key}}</span>\n\n <span v-if=\"n.hasCacheActivated()\">\n &nbsp;<i class=\"fa fa-hdd\" title=\"This module has cache activated\"></i>\n </span>\n </span>\n </div>\n <div class=\"points\">\n <div class=\"point\" v-for=\"key in getVisibleOutputs()\" v-bind:data-key=\"key\" v-bind:data-type=\"n.getOutputDef(key).type\" v-html=\"point\"></div>\n </div>\n <div class=\"types\">\n <span class=\"type\" v-for=\"key in getVisibleOutputs()\" v-bind:data-key=\"key\">\n {{ n.getOutputType(key) }}\n </span>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <hr style=\"margin-top: 5px;\"/>\n <div class=\"card-bottom\">\n <span class=\"subtitle\">{{ shortName }}</span>\n\n <div v-if=\"n.isMetanode()\" class=\"d-inline-block\">\n <button class=\"btn btn-outline-secondary btn-outline-discrete btn-editor-xs btn-enter-metanode\" v-on:click=\"enterMetanode\"><i class=\"fas fa-sign-in-alt\"></i></button>\n </div>\n\n <!--\n <div v-if=\"n.isUI()\" class=\"event-dock event-dock-bottom\"></div>\n -->\n </div>\n </div>\n</template>\n\n<script>\nimport ContextMenu from '../ContextMenu';\nimport _ from 'lodash';\nimport dbutils from '../../m/DualboxUtils';\n\n// fix inputs types and output types position relatively to the div\n$.fn.fixCardDisplay = function() {\n var offsetPoint = 12;\n var offsetBorder = parseInt($(this).css(\"border-top-width\"));\n\n if( $(this).find('.box-inputs').height() === 0 && $(this).find('.box-outputs').height() === 0 ) {\n // if this card has no input/output, remove the card center\n $(this).find('.card-center').remove();\n }\n else {\n // else, adjust the input/output display for endpoints\n // 1) translate inputs by the right amount of pixels to have the circle on the line\n var boxInputs = $(this).find('.box-inputs');\n\n // fix css names width\n var namesDiv = boxInputs.find('.names');\n namesDiv.css('width', (namesDiv.width()+1) + 'px');\n\n // translate inputs to the left\n var translateLeft = boxInputs.find('.types').width() + offsetPoint + offsetBorder/2;\n $(this).find('.box-inputs').css('transform', 'translateX(-' + translateLeft + 'px)');\n\n // adjust inputs main div width\n $(this).find('.inputs').width( $(this).find('.inputs').width() - translateLeft + 10 /* margin */ );\n\n\n // 2) translate outputs by the right amount of pixels to have the circle on the line\n var boxOutputs = $(this).find('.box-outputs');\n\n // fix css names with\n var namesDiv = boxOutputs.find('.names');\n namesDiv.css('width', (namesDiv.width() + 1) + 'px');\n\n // translate inputs to the right\n var translateRight = boxOutputs.find('.types').width() + offsetPoint + offsetBorder/2;\n $(this).find('.box-outputs').css('transform', 'translateX(' + translateRight + 'px)');\n\n // adjust output main div width\n $(this).find('.outputs').width( $(this).find('.outputs').width() - translateRight + 10 /* margin */ );\n\n // fix io width\n //$('.dualbox-io').css('width', (($(this).find('.inputs').width() + $(this).find('.outputs').width()) + \"px\"));\n }\n}\n\n// take the current width and add it as a css property\n$.fn.fixWidth = function() {\n var width = $(this).width();\n width += parseInt($(this).css('padding-right'));\n width += parseInt($(this).css('padding-left'));\n width += parseInt($(this).css('border-left-width'));\n width += parseInt($(this).css('border-right-width'));\n $(this).css('width', width + 'px');\n}\n\n// find position of element relative to an ancestor matching selector\n$.fn.positionFrom = function( selector ) {\n var ancestor = $(this).closest(selector);\n var offset = $(this).offset();\n var ancestorOffset = ancestor.offset();\n return {\n top: offset.top - ancestorOffset.top,\n left: offset.left - ancestorOffset.left,\n }\n}\n\nexport default {\n props: [\n \"id\", // the module id\n \"pkg\", // the module package.json\n \"n\", // the GraphNode object (from model)\n \"example\", // true if this vue is used as an example display (no need to connect)\n ],\n data: function () {\n return {\n shortName: \"\",\n point: '<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>',\n }\n },\n beforeUpdate: function() {\n //console.log('[UPDATING] ' + this.n.getUniqId());\n },\n destroyed: function() {\n console.log('[DESTROYED] ' + this.n.getUniqId());\n },\n created: function() {\n this.initialized = false;\n this.view = window.dualboxEditor.v;\n\n //console.log('[CREATED] ' + this.n.getUniqId());\n // We compute the shortname of our box\n if( this.n.isInput() || this.n.isOutput() ) {\n this.shortName = this.n.getType();\n }\n else {\n this.shortName = dbutils.shortName(this.pkg.name);\n }\n },\n mounted: async function() {\n console.log('[MOUNTED] ' + this.n.getUniqId());\n var div = $(this.$el);\n div.fixCardDisplay();\n div.ready(() => {\n //if( !this.example ) {\n div.fixWidth();\n //}\n });\n this.activateTooltip();\n return await this.initialize();\n },\n beforeUpdate: function() {\n this.deactivateTooltip();\n },\n updated: async function() {\n console.log('[UPDATED] ' + this.n.getUniqId());\n\n // we reset jsPlumb before app update (in graph.vue)\n // so we need to initialize again\n this.assignContextMenu();\n\n $(this.$el).fixCardDisplay();\n $(this.$el).ready(()=>{\n $(this.$el).fixWidth();\n this.activateTooltip();\n });\n return await this.initialize();\n },\n activate: function() {\n this.activateTooltip();\n },\n deactivate: function() {\n this.deactivateTooltip();\n },\n methods: {\n getId: function() {\n // if this is an example graphNode, change our \"id\" to \"id-junk\"\n // to avoid connection jsplumb conflicts with the real node\n return this.example ? this.id + '-junk' : this.id;\n },\n\n activateTooltip: function() {\n $(this.$el).find('[data-toggle=\"tooltip\"]').tooltip();\n },\n\n deactivateTooltip: function() {\n $(this.$el).find('[data-toggle=\"tooltip\"]').tooltip(\"dispose\");\n },\n\n initialize: async function() {\n var self = this;\n var div = $(this.$el);\n var id = this.getId();\n var view = this.view;\n\n this.initialized = false;\n\n if( !this.example ) {\n // if we have a position, set it\n var def = this.n.getDef();\n var position = _.get(def, [\"graph\", \"position\"]);\n if( position ) {\n var jsPlumbElement = self.$parent.jsPlumbInstance.getElement(id);\n self.$parent.jsPlumbInstance.setPosition(jsPlumbElement, position);\n }\n\n // This needs to be registered before draggable\n div.on('mousedown', function(e) {\n // if this div is not selected already, deselect the other divs\n if( !self.$parent.selector.isSelected(this) ) {\n self.$parent.selector.deselect();\n }\n });\n\n await this.initializeJsPlumb();\n\n div.click(function(e) {\n if( e.ctrlKey ) {\n view.selector.toggleSelection(this);\n }\n });\n\n this.assignContextMenu();\n }\n\n return new Promise(resolve => {\n div.ready(() => {\n console.log('[INITIALIZED] ' + this.n.getUniqId());\n this.initialized = true;\n resolve();\n });\n });\n },\n\n initializeJsPlumb: function() {\n var self = this;\n var div = $(this.$el);\n var id = this.getId();\n var view = this.view;\n\n if( !this.example ) {\n // If this node was never initialized in this jsplumb instance, do it\n if( !_.get(this.$parent.jsPlumbInstance, [\"initializedNodes\", id]) ) {\n _.set(this.$parent.jsPlumbInstance, [\"initializedNodes\", id], true); // initialized\n\n if( this.n.isInput() || this.n.isOutput() ) {\n var type = \"*\";\n var input = \"value\";\n var output = \"value\";\n var offsetTop = $(div).find('.card-top').height() + 12 /* hr size */ - 3;\n\n var uuid = [ id, \"input\", input].join('#');\n var ep = this.$parent.jsPlumbInstance.addEndpoint(id, {\n isSource : false,\n isTarget : true,\n uuid : uuid,\n anchor : [0,0,-1,0,0,offsetTop],\n maxConnections : 1,\n parameters : {\n type: \"data\",\n target : {\n id : id,\n input : output\n }\n }\n }, this.$parent.style.inputEndpoint);\n\n // add data to the endpoint div so we can identify it easier\n $(ep.canvas).attr('data-node', id);\n $(ep.canvas).attr('data-type', 'input');\n $(ep.canvas).attr('data-input', input);\n\n // bind tooltip\n $(ep.canvas).attr('data-toggle', \"tooltip\");\n $(ep.canvas).attr('data-trigger', \"hover\");\n $(ep.canvas).attr('data-placement', \"left\");\n $(ep.canvas).attr('data-html', \"true\");\n var inputType = view.m.getNode(id).getInputType(\"value\");\n $(ep.canvas).attr('title', \"Type: <b>\" + inputType + \"</b>\");\n $(ep.canvas).tooltip();\n\n // bind context menu to the endpoint\n $(ep.canvas).addClass('capture-right-click');\n $(ep.canvas).ready(function() {\n var menu = new ContextMenu(\".jtk-endpoint-anchor[data-node='\"+id.trim()+\"'][data-input='\" + input + \"']\", [\n {\n name: 'Create input for here',\n fn: () => {\n view.c.createInputFromConnection(id, input);\n }\n },\n ]);\n });\n\n var uuid = [ id, \"output\", output].join('#');\n var ep = this.$parent.jsPlumbInstance.addEndpoint(id, {\n isSource : true,\n isTarget : false,\n uuid : uuid,\n anchor : [1,0,1,0,0,offsetTop],\n parameters : {\n type: \"data\",\n source : {\n id : id,\n output : output\n }\n }\n }, this.$parent.style.outputEndpoint);\n\n // add data to the endpoint div so we can identify it easier\n $(ep.canvas).attr('data-node', id);\n $(ep.canvas).attr('data-type', \"output\");\n $(ep.canvas).attr('data-output', output);\n\n // bind tooltip\n $(ep.canvas).attr('data-toggle', \"tooltip\");\n $(ep.canvas).attr('data-trigger', \"hover\");\n $(ep.canvas).attr('data-placement', \"right\");\n $(ep.canvas).attr('data-html', \"true\");\n var outputType = view.m.getNode(id).getOutputType(\"value\");\n $(ep.canvas).attr('title', \"Type: <b>\" + outputType + \"</b>\");\n $(ep.canvas).tooltip();\n\n // bind context menu to the endpoint\n $(ep.canvas).addClass('capture-right-click');\n $(ep.canvas).ready(function() {\n var menu = new ContextMenu(\".jtk-endpoint-anchor[data-node='\"+id.trim()+\"'][data-output='\" + output.trim() + \"']\", [\n {\n name: 'Create output for here',\n fn: () => {\n view.c.createOutputFromConnection(id, output);\n }\n },\n ]);\n });\n }\n else {\n // add input endoints\n div.find('.box-inputs').find('.point').each( function(index) {\n $(this).css('visibility', 'hidden').css('opacity', '0'); // replaced by jsPlumb point\n\n var input = div.find('.box-inputs').find('.name').eq(index).attr('data-input').trim();\n var type = view.m.getNode(id).getInputType(input);\n\n var offsetTop = $(this).positionFrom('.card').top + $(this).height()/2 - 3;\n var uuid = [ id, \"input\", $(this).data('key')].join('#');\n var ep = self.$parent.jsPlumbInstance.addEndpoint(id, {\n isSource : false,\n isTarget : true,\n uuid : uuid,\n anchor : [0,0,-1,0,0,offsetTop],\n maxConnections : 1,\n parameters : {\n type: \"data\",\n target : {\n id : id,\n input : $(this).data('key')\n }\n }\n }, self.$parent.style.inputEndpoint);\n\n // add data to the endpoint div so we can identify it easier\n $(ep.canvas).attr('data-node', id);\n $(ep.canvas).attr('data-type', 'input');\n $(ep.canvas).attr('data-input', input);\n\n // bind tooltip\n $(ep.canvas).attr('data-toggle', \"tooltip\");\n $(ep.canvas).attr('data-trigger', \"hover\");\n $(ep.canvas).attr('data-placement', \"left\");\n $(ep.canvas).attr('data-html', \"true\");\n $(ep.canvas).attr('title', \"Type: <b>\" + type + \"</b>\");\n $(ep.canvas).tooltip();\n\n // bind context menu to the endpoint\n $(ep.canvas).addClass('capture-right-click');\n $(ep.canvas).ready(function() {\n var menu = new ContextMenu(\".jtk-endpoint-anchor[data-node='\"+id.trim()+\"'][data-input='\" + input.trim() + \"']\", [\n {\n name: 'Create input for here',\n fn: () => {\n view.c.createInputFromConnection(id, input);\n }\n },\n ]);\n });\n });\n\n // add output endpoints\n div.find('.box-outputs').find('.point').each( function(index) {\n $(this).css('visibility', 'hidden').css('opacity', '0'); // replaced by jsPlumb point\n\n var output = div.find('.box-outputs').find('.name').eq(index).attr('data-output').trim();\n var type = view.m.getNode(id).getOutputType(output);\n\n var offsetTop = $(this).positionFrom('.card').top + $(this).height()/2 - 3;\n var uuid = [ id, \"output\", $(this).data('key')].join('#');\n var ep = self.$parent.jsPlumbInstance.addEndpoint(id, {\n isSource : true,\n isTarget : false,\n uuid : uuid,\n anchor : [1,0,1,0,0,offsetTop],\n parameters : {\n type: \"data\",\n source : {\n id : id,\n output : $(this).data('key')\n }\n }\n }, self.$parent.style.outputEndpoint);\n\n // add data to the endpoint div so we can identify it easier\n $(ep.canvas).attr('data-node', id);\n $(ep.canvas).attr('data-type', \"output\");\n $(ep.canvas).attr('data-output', output);\n\n // bind tooltip\n $(ep.canvas).attr('data-toggle', \"tooltip\");\n $(ep.canvas).attr('data-trigger', \"hover\");\n $(ep.canvas).attr('data-placement', \"right\");\n $(ep.canvas).attr('data-html', \"true\");\n $(ep.canvas).attr('title', \"Type: <b>\" + type + \"</b>\");\n $(ep.canvas).tooltip();\n\n // bind context menu to the endpoint\n $(ep.canvas).addClass('capture-right-click');\n $(ep.canvas).ready(function() {\n var menu = new ContextMenu(\".jtk-endpoint-anchor[data-node='\"+id.trim()+\"'][data-output='\" + output.trim() + \"']\", [\n {\n name: 'Create output for here',\n fn: () => {\n view.c.createOutputFromConnection(id, output);\n }\n },\n ]);\n });\n });\n\n if( this.n.isUI() && view.showEvents ) {\n // Make this a target for events\n this.$parent.jsPlumbInstance.makeTarget(id, {\n isSource:false,\n isTarget:true,\n uniqueEndpoint: false,\n anchor:\"Continuous\",\n uuid: id + \"#event-in\",\n paintStyle:{ fill:\"green\" },\n parameters: {\n type: \"event\",\n target: { \"id\" : id }\n },\n }, self.$parent.style.eventEndpoint);\n\n // Create an enpoint to create a new event\n var ep = this.$parent.jsPlumbInstance.addEndpoint(id, {\n isSource : true,\n isTarget : false,\n uuid : id + \"#event-out\",\n anchor : [1, 1, 0, 1, 0, -10],\n parameters : {\n type: \"event\",\n source: { \"id\" : id }\n },\n }, this.$parent.style.eventEndpoint);\n\n // Add overlay here so we don't mess with splitConnection\n ep.addOverlay([\"PlainArrow\", { width:15, length:15, location:1, id:\"arrow\" }]);\n\n $(ep.canvas).attr('data-toggle', \"tooltip\");\n $(ep.canvas).attr('data-trigger', \"hover\");\n $(ep.canvas).attr('data-placement', \"bottom\");\n $(ep.canvas).attr('data-html', \"true\");\n $(ep.canvas).attr('title', \"Connect from here ito add an event that will be triggered when this box is done computing.\");\n $(ep.canvas).tooltip();\n }\n }\n\n // Make the div draggable\n this.$parent.jsPlumbInstance.draggable(div, {\n //containment:true, // not allowed outside of container div\n drag: function(e) {\n // TODO: bug. After a repaint(), jsPlumb seems to be broken (connections dont follow on div drag)\n // It doesn't occur on jsPlumb.reset() instead of creating another instance on beforeUpdate(),\n // (as it should be), but we can't do that, because JsPlumb is broken on zoom otherwise...\n // One of thoses problem may be fixed later by updating jsPlumb...\n // Note: this \"fix\" may affect performances on drag, maybe a setTimeout will do\n //self.$parent.jsPlumbInstance.repaintEverything();\n self.$parent.jsPlumbInstance.repaint(id);\n },\n stop: function(e) {\n // resize the canvas if necessary\n self.$parent.canvasSizeHandler.debouncedResize();\n\n // set the new position in the graph model\n var el = self.$parent.jsPlumbInstance.getElement(id);\n $(el).ready(function() {\n var pos = self.$parent.jsPlumbInstance.getPosition(el);\n view.m.getNode(id).setPosition(pos);\n });\n }\n });\n }\n }\n\n return new Promise((resolve) => this.$parent.jsPlumbInstance.ready(resolve));\n },\n\n assignContextMenu: function() {\n var id = this.getId();\n\n // Create a contextmenu for the div\n var contextOptions = [\n {\n name: 'Remove this box',\n fn: () => {\n this.view.c.removeBox(id);\n }\n }\n ];\n if( this.n.isModule() || this.n.isUI() ) {\n contextOptions.push({\n name: 'Duplicate this box',\n fn: () => {\n this.view.c.duplicateBox(id);\n }\n });\n }\n var nodeMenu = new ContextMenu(\"#\" + id, contextOptions);\n },\n\n htmlentities: function( s ) {\n return this.view.utils.htmlentities(s);\n },\n\n getVisibleInputs: function() {\n return this.n.getInputsNames().filter((inputName) => {\n return this.n.isInputVisible(inputName);\n })\n },\n\n getVisibleOutputs: function() {\n return this.n.getOutputsNames().filter((outputName) => {\n return this.n.isOutputVisible(outputName);\n })\n },\n\n enterMetanode: function(e) {\n e.preventDefault();\n e.stopPropagation();\n\n this.view.c.enterMetanode(this.id);\n },\n\n openNodeSettings: function(e) {\n e.preventDefault();\n e.stopPropagation();\n this.view.openBoxSettings(this.id);\n },\n\n openSnapshotDetails: function(e) {\n e.preventDefault();\n e.stopPropagation();\n this.view.openDebug(this.id);\n }\n },\n watch: {\n 'app': {\n handler: () => {\n console.log('graphVue.app changed');\n },\n deep: true\n }\n }\n}\n\n</script>\n"]}, media: undefined });
46366
+ inject("data-v-51e7220d_0", { source: "\n.card-ui {\n background-color: #bff2ca!important;\n}\n.card-loop {\n /* background-color: #e5e8ea!important; */\n border: 5px double #dddddd;\n border-width: 4px;\n}\n.card-input {\n background-color: #f5d76e!important;\n}\n.card-output {\n background-color: #ffb3a7!important;\n}\n.box-inputs {\n float: left;\n padding-left: 2px;\n padding-right: 5px;\n vertical-align: top;\n text-align: left;\n}\n.box-outputs {\n float: right;\n padding-left: 5px;\n padding-right: 2px;\n vertical-align: top;\n text-align: right;\n}\n.dualbox-graph-canvas .card, .card-node {\n /*border: 1px solid #dddddd;*/\n box-shadow: 1px 1px 5px #716f6f;\n opacity: 1;\n cursor: pointer;\n z-index: 20;\n position: absolute;\n\n -webkit-transition: -webkit-box-shadow 0.15s ease-in;\n -moz-transition: -moz-box-shadow 0.15s ease-in;\n -o-transition: -o-box-shadow 0.15s ease-in;\n transition: box-shadow 0.15s ease-in;\n\n color: #4d4d4d;\n user-select: none;\n padding: 0px 8px 0px 8px;\n overflow:hidden;\n background-color: #fff;\n -moz-border-radius: 3px;\n border-radius:3px;\n font-size: 14px;\n font-family: \"Helvetica Neue\", Arial, Helvetica, sans-serif;\n}\n.card-node .card-top {\n padding-top: 2px;\n}\n.card-node .card-bottom {\n padding-bottom: 2px;\n text-align: center;\n line-height: 14px;\n white-space: nowrap;\n}\n.card-node hr {\n margin-top: 2px;\n margin-bottom: 2px;\n border-color: rgba(0,0,0,0.1);\n margin-left: -8px;\n margin-right: -8px;\n}\n.card-node:hover {\n border-color: #80b2fc;\n box-shadow: 1px 1px 10px #80b2fc;\n}\n.card-node.selected, .card-node.selected:hover {\n border-color: #0066ff;\n box-shadow: 1px 1px 10px #0066ff;\n}\n.card-node-incomplete {\n box-shadow: 1px 1px 5px #dd6666 !important;\n}\n.input-not-resolvable {\n color: #dd6666!important;\n}\n.card-node .title {\n vertical-align:top;\n font-weight: bold;\n}\n.card-node .subtitle {\n color:#929292;\n font-size: 11px;\n font-style: italic;\n vertical-align:center;\n font-family: tahoma, sans-serif;\n}\n.card-node .input {\n font-size: 13px;\n color: #8c8c8c;\n}\n.card-node .output {\n font-size: 13px;\n color: #8c8c8c;\n text-align:right;\n}\n.card-node .jtk-endpoint.active svg circle {\n /* fill: #99ff33 */\n stroke: #59b300;\n}\n.point {\n /* display: inline-block; */\n display: none;\n position: relative;\n top: 3px;\n margin-right: 5px;\n margin-left: 5px;\n}\n.dualbox-io {\n overflow: visible;\n margin-left: -8px;\n margin-right: -8px;\n}\n.box-inputs {\n display: flex;\n justify-content: space-between;\n position: relative;\n padding: 0;\n pointer-events: none;\n}\n.types {\n color: #6c757d!important;\n opacity: 0.7;\n pointer-events: none;\n}\n.box-inputs .types {\n display: inline-block;\n}\n.box-inputs .name {\n display: inline-block;\n}\n.box-inputs .type {\n display: block;\n text-align: right;\n}\n.box-inputs .point {\n display: block;\n}\n.box-inputs .name {\n display: block;\n}\n.box-outputs {\n display: flex;\n justify-content: center;\n position: relative;\n padding: 0;\n pointer-events: none;\n}\n.box-outputs .types {\n display: inline-block;\n}\n.box-outputs .point {\n display: inline-block;\n}\n.box-outputs .name {\n display: inline-block;\n}\n.box-outputs .type {\n display: block;\n text-align: left;\n}\n.box-outputs .point {\n display: block;\n}\n.box-outputs .name {\n display: block;\n}\nspan.feedback {\n font-weight: bold;\n}\n.event-dock {\n background-color: rgb(136, 137, 138);\n background-color: #a6a6a6;\n width: calc(100% + 18px);\n height: 12px;\n z-index: 3!important;\n}\n.event-dock-top {\n margin-left: -9px;\n margin-right: -9px;\n margin-top: -3px;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n margin-bottom: 4px;\n}\n.event-dock-bottom {\n margin-left: -9px;\n margin-right: -9px;\n margin-bottom: -3px;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n margin-top: 4px;\n height: 11px; /* shorter because of box-shadow */\n}\n.event-label {\n z-index: 21;\n padding-left: 15px;\n transform: rotate(-90deg) translate(0%, -50%)!important;\n transform-origin: 0% 0%;\n color: #6c757d!important;\n font-family: \"Helvetica Neue\", Arial, Helvetica, sans-serif;\n font-size: 14px;\n opacity: 0.7;\n cursor: pointer;\n}\n.transparent {\n opacity: 0.3!important;\n}\n.card-node {\n position: relative;\n}\n.card-comment {\n position: absolute;\n top: 0;\n right: 0;\n margin-top: -22px;\n color: #f4ad42!important;\n}\n.card-problem {\n position: absolute;\n top: 0;\n left: 0;\n margin-top: -22px;\n color: red!important;\n}\n.card-snapshot {\n}\n.card-snapshot-idle {\n border: 2px solid gray!important;\n box-shadow: 1px 1px 5px gray!important;\n opacity: 0.7!important;\n}\n.card-snapshot-computing {\n border: 2px solid darkgreen!important;\n box-shadow: 1px 1px 5px darkgreen!important;\n opacity: 1!important;\n}\n.card-snapshot-awaiting-data {\n border: 2px solid blue!important;\n box-shadow: 1px 1px 5px blue!important;\n opacity: 0.7!important;\n}\n.card-snapshot-ready {\n border: 2px solid lightgreen!important;\n box-shadow: 1px 1px 5px lightgreen!important;\n opacity: 1!important;\n}\n.card-status {\n position: absolute;\n bottom: 0;\n right: 0;\n left: 0;\n margin-bottom: -26px;\n color: #f4ad42!important;\n font-family: \"Helvetica Neue\", Arial, Helvetica, sans-serif;\n font-weight: bold;\n text-align: center;\n}\n.card-status-idle {\n color: gray!important;\n min-width: 85px;\n}\n.card-status-computing {\n color: darkgreen!important;\n min-width: 110px;\n}\n.card-status-awaiting-data {\n color: blue!important;\n min-width: 85px;\n}\n.card-status-ready {\n color: lightgreen!important;\n min-width: 85px;\n}\n.btn-snapshot-details {\n position: relative;\n margin-top: -2px;\n color: inherit;\n}\nspan.name {\n overflow-wrap: normal;\n}\n", map: {"version":3,"sources":["/home/seb/dev/dualbox/editor/js/src/v/templates/graphNode.vue"],"names":[],"mappings":";AACA;IACA,mCAAA;AACA;AAEA;IACA,yCAAA;IACA,0BAAA;IACA,iBAAA;AACA;AAEA;IACA,mCAAA;AACA;AAEA;IACA,mCAAA;AACA;AAEA;IACA,WAAA;IACA,iBAAA;IACA,kBAAA;IACA,mBAAA;IACA,gBAAA;AACA;AAEA;IACA,YAAA;IACA,iBAAA;IACA,kBAAA;IACA,mBAAA;IACA,iBAAA;AACA;AAEA;IACA,6BAAA;IACA,+BAAA;IACA,UAAA;IACA,eAAA;IACA,WAAA;IACA,kBAAA;;IAEA,oDAAA;IACA,8CAAA;IACA,0CAAA;IACA,oCAAA;;IAEA,cAAA;IACA,iBAAA;IACA,wBAAA;IACA,eAAA;IACA,sBAAA;IACA,uBAAA;IACA,iBAAA;IACA,eAAA;IACA,2DAAA;AACA;AAEA;IACA,gBAAA;AACA;AAEA;IACA,mBAAA;IACA,kBAAA;IACA,iBAAA;IACA,mBAAA;AACA;AAEA;IACA,eAAA;IACA,kBAAA;IACA,6BAAA;IACA,iBAAA;IACA,kBAAA;AACA;AAEA;IACA,qBAAA;IACA,gCAAA;AACA;AAEA;IACA,qBAAA;IACA,gCAAA;AACA;AAEA;IACA,0CAAA;AACA;AAEA;IACA,wBAAA;AACA;AAEA;IACA,kBAAA;IACA,iBAAA;AACA;AAEA;IACA,aAAA;IACA,eAAA;IACA,kBAAA;IACA,qBAAA;IACA,+BAAA;AACA;AAEA;IACA,eAAA;IACA,cAAA;AACA;AAEA;IACA,eAAA;IACA,cAAA;IACA,gBAAA;AACA;AAEA;IACA,kBAAA;IACA,eAAA;AACA;AAEA;IACA,2BAAA;IACA,aAAA;IACA,kBAAA;IACA,QAAA;IACA,iBAAA;IACA,gBAAA;AACA;AAEA;IACA,iBAAA;IACA,iBAAA;IACA,kBAAA;AACA;AAEA;IACA,aAAA;IACA,8BAAA;IACA,kBAAA;IACA,UAAA;IACA,oBAAA;AACA;AAEA;IACA,wBAAA;IACA,YAAA;IACA,oBAAA;AACA;AAEA;IACA,qBAAA;AACA;AAEA;IACA,qBAAA;AACA;AAEA;IACA,cAAA;IACA,iBAAA;AACA;AAEA;IACA,cAAA;AACA;AAEA;IACA,cAAA;AACA;AAEA;IACA,aAAA;IACA,uBAAA;IACA,kBAAA;IACA,UAAA;IACA,oBAAA;AACA;AAEA;IACA,qBAAA;AACA;AAEA;IACA,qBAAA;AACA;AAEA;IACA,qBAAA;AACA;AAEA;IACA,cAAA;IACA,gBAAA;AACA;AAEA;IACA,cAAA;AACA;AAEA;IACA,cAAA;AACA;AAEA;IACA,iBAAA;AACA;AAEA;IACA,oCAAA;IACA,2BAAA;IACA,wBAAA;IACA,YAAA;IACA,oBAAA;AACA;AAEA;IACA,iBAAA;IACA,kBAAA;IACA,gBAAA;IACA,2BAAA;IACA,4BAAA;IACA,kBAAA;AACA;AAEA;IACA,iBAAA;IACA,kBAAA;IACA,mBAAA;IACA,8BAAA;IACA,+BAAA;IACA,eAAA;IACA,YAAA,EAAA,kCAAA;AACA;AAEA;IACA,WAAA;IACA,kBAAA;IACA,uDAAA;IACA,uBAAA;IACA,wBAAA;IACA,2DAAA;IACA,eAAA;IACA,YAAA;IACA,eAAA;AACA;AAEA;IACA,sBAAA;AACA;AAEA;IACA,kBAAA;AACA;AAEA;IACA,kBAAA;IACA,MAAA;IACA,QAAA;IACA,iBAAA;IACA,wBAAA;AACA;AAEA;IACA,kBAAA;IACA,MAAA;IACA,OAAA;IACA,iBAAA;IACA,oBAAA;AACA;AAEA;AAEA;AAEA;IACA,gCAAA;IACA,sCAAA;IACA,sBAAA;AACA;AAEA;IACA,qCAAA;IACA,2CAAA;IACA,oBAAA;AACA;AAEA;IACA,gCAAA;IACA,sCAAA;IACA,sBAAA;AACA;AAEA;IACA,sCAAA;IACA,4CAAA;IACA,oBAAA;AACA;AAEA;IACA,kBAAA;IACA,SAAA;IACA,QAAA;IACA,OAAA;IACA,oBAAA;IACA,wBAAA;IACA,2DAAA;IACA,iBAAA;IACA,kBAAA;AACA;AAEA;IACA,qBAAA;IACA,eAAA;AACA;AAEA;IACA,0BAAA;IACA,gBAAA;AACA;AAEA;IACA,qBAAA;IACA,eAAA;AACA;AAEA;IACA,2BAAA;IACA,eAAA;AACA;AAEA;IACA,kBAAA;IACA,gBAAA;IACA,cAAA;AACA;AAEA;IACA,qBAAA;AACA","file":"graphNode.vue","sourcesContent":["<style>\n.card-ui {\n background-color: #bff2ca!important;\n}\n\n.card-loop {\n /* background-color: #e5e8ea!important; */\n border: 5px double #dddddd;\n border-width: 4px;\n}\n\n.card-input {\n background-color: #f5d76e!important;\n}\n\n.card-output {\n background-color: #ffb3a7!important;\n}\n\n.box-inputs {\n float: left;\n padding-left: 2px;\n padding-right: 5px;\n vertical-align: top;\n text-align: left;\n}\n\n.box-outputs {\n float: right;\n padding-left: 5px;\n padding-right: 2px;\n vertical-align: top;\n text-align: right;\n}\n\n.dualbox-graph-canvas .card, .card-node {\n /*border: 1px solid #dddddd;*/\n box-shadow: 1px 1px 5px #716f6f;\n opacity: 1;\n cursor: pointer;\n z-index: 20;\n position: absolute;\n\n -webkit-transition: -webkit-box-shadow 0.15s ease-in;\n -moz-transition: -moz-box-shadow 0.15s ease-in;\n -o-transition: -o-box-shadow 0.15s ease-in;\n transition: box-shadow 0.15s ease-in;\n\n color: #4d4d4d;\n user-select: none;\n padding: 0px 8px 0px 8px;\n overflow:hidden;\n background-color: #fff;\n -moz-border-radius: 3px;\n border-radius:3px;\n font-size: 14px;\n font-family: \"Helvetica Neue\", Arial, Helvetica, sans-serif;\n}\n\n.card-node .card-top {\n padding-top: 2px;\n}\n\n.card-node .card-bottom {\n padding-bottom: 2px;\n text-align: center;\n line-height: 14px;\n white-space: nowrap;\n}\n\n.card-node hr {\n margin-top: 2px;\n margin-bottom: 2px;\n border-color: rgba(0,0,0,0.1);\n margin-left: -8px;\n margin-right: -8px;\n}\n\n.card-node:hover {\n border-color: #80b2fc;\n box-shadow: 1px 1px 10px #80b2fc;\n}\n\n.card-node.selected, .card-node.selected:hover {\n border-color: #0066ff;\n box-shadow: 1px 1px 10px #0066ff;\n}\n\n.card-node-incomplete {\n box-shadow: 1px 1px 5px #dd6666 !important;\n}\n\n.input-not-resolvable {\n color: #dd6666!important;\n}\n\n.card-node .title {\n vertical-align:top;\n font-weight: bold;\n}\n\n.card-node .subtitle {\n color:#929292;\n font-size: 11px;\n font-style: italic;\n vertical-align:center;\n font-family: tahoma, sans-serif;\n}\n\n.card-node .input {\n font-size: 13px;\n color: #8c8c8c;\n}\n\n.card-node .output {\n font-size: 13px;\n color: #8c8c8c;\n text-align:right;\n}\n\n.card-node .jtk-endpoint.active svg circle {\n /* fill: #99ff33 */\n stroke: #59b300;\n}\n\n.point {\n /* display: inline-block; */\n display: none;\n position: relative;\n top: 3px;\n margin-right: 5px;\n margin-left: 5px;\n}\n\n.dualbox-io {\n overflow: visible;\n margin-left: -8px;\n margin-right: -8px;\n}\n\n.box-inputs {\n display: flex;\n justify-content: space-between;\n position: relative;\n padding: 0;\n pointer-events: none;\n}\n\n.types {\n color: #6c757d!important;\n opacity: 0.7;\n pointer-events: none;\n}\n\n.box-inputs .types {\n display: inline-block;\n}\n\n.box-inputs .name {\n display: inline-block;\n}\n\n.box-inputs .type {\n display: block;\n text-align: right;\n}\n\n.box-inputs .point {\n display: block;\n}\n\n.box-inputs .name {\n display: block;\n}\n\n.box-outputs {\n display: flex;\n justify-content: center;\n position: relative;\n padding: 0;\n pointer-events: none;\n}\n\n.box-outputs .types {\n display: inline-block;\n}\n\n.box-outputs .point {\n display: inline-block;\n}\n\n.box-outputs .name {\n display: inline-block;\n}\n\n.box-outputs .type {\n display: block;\n text-align: left;\n}\n\n.box-outputs .point {\n display: block;\n}\n\n.box-outputs .name {\n display: block;\n}\n\nspan.feedback {\n font-weight: bold;\n}\n\n.event-dock {\n background-color: rgb(136, 137, 138);\n background-color: #a6a6a6;\n width: calc(100% + 18px);\n height: 12px;\n z-index: 3!important;\n}\n\n.event-dock-top {\n margin-left: -9px;\n margin-right: -9px;\n margin-top: -3px;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n margin-bottom: 4px;\n}\n\n.event-dock-bottom {\n margin-left: -9px;\n margin-right: -9px;\n margin-bottom: -3px;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n margin-top: 4px;\n height: 11px; /* shorter because of box-shadow */\n}\n\n.event-label {\n z-index: 21;\n padding-left: 15px;\n transform: rotate(-90deg) translate(0%, -50%)!important;\n transform-origin: 0% 0%;\n color: #6c757d!important;\n font-family: \"Helvetica Neue\", Arial, Helvetica, sans-serif;\n font-size: 14px;\n opacity: 0.7;\n cursor: pointer;\n}\n\n.transparent {\n opacity: 0.3!important;\n}\n\n.card-node {\n position: relative;\n}\n\n.card-comment {\n position: absolute;\n top: 0;\n right: 0;\n margin-top: -22px;\n color: #f4ad42!important;\n}\n\n.card-problem {\n position: absolute;\n top: 0;\n left: 0;\n margin-top: -22px;\n color: red!important;\n}\n\n.card-snapshot {\n\n}\n\n.card-snapshot-idle {\n border: 2px solid gray!important;\n box-shadow: 1px 1px 5px gray!important;\n opacity: 0.7!important;\n}\n\n.card-snapshot-computing {\n border: 2px solid darkgreen!important;\n box-shadow: 1px 1px 5px darkgreen!important;\n opacity: 1!important;\n}\n\n.card-snapshot-awaiting-data {\n border: 2px solid blue!important;\n box-shadow: 1px 1px 5px blue!important;\n opacity: 0.7!important;\n}\n\n.card-snapshot-ready {\n border: 2px solid lightgreen!important;\n box-shadow: 1px 1px 5px lightgreen!important;\n opacity: 1!important;\n}\n\n.card-status {\n position: absolute;\n bottom: 0;\n right: 0;\n left: 0;\n margin-bottom: -26px;\n color: #f4ad42!important;\n font-family: \"Helvetica Neue\", Arial, Helvetica, sans-serif;\n font-weight: bold;\n text-align: center;\n}\n\n.card-status-idle {\n color: gray!important;\n min-width: 85px;\n}\n\n.card-status-computing {\n color: darkgreen!important;\n min-width: 110px;\n}\n\n.card-status-awaiting-data {\n color: blue!important;\n min-width: 85px;\n}\n\n.card-status-ready {\n color: lightgreen!important;\n min-width: 85px;\n}\n\n.btn-snapshot-details {\n position: relative;\n margin-top: -2px;\n color: inherit;\n}\n\nspan.name {\n overflow-wrap: normal;\n}\n</style>\n\n<template>\n <div class=\"jtk-node card card-node contextmenu\" v-bind:class=\"{ 'card-loop': n.hasLoop(), 'card-ui': n.isUI(), 'card-metanode': n.isMetanode(), 'card-input': n.isInput(), 'card-output': n.isOutput(), 'card-snapshot': n.hasSnapshot(), 'card-snapshot-idle': n.hasSnapshot() && n.isSnapshotStatus(0), 'card-snapshot-computing': n.hasSnapshot() && n.isSnapshotStatus(1), 'card-snapshot-awaiting-data': n.hasSnapshot() && n.isSnapshotStatus(2), 'card-snapshot-ready': n.hasSnapshot() && n.isSnapshotStatus(3) }\" v-bind:id=\"getId()\" v-bind:data-id=\"getId()\" v-bind:data-name=\"pkg.name\" style=\"overflow: visible;\">\n <div v-if=\"n.hasComment()\">\n <div class=\"card-comment\" data-toggle=\"tooltip\" data-placement=\"top\" :title=\"n.getComment()\">\n <i class=\"fas fa-comment-alt\" data-container=\"body\"></i>\n </div>\n </div>\n\n <div v-if=\"n.hasSnapshot()\">\n <div class=\"card-status\">\n <div v-if=\"n.isSnapshotStatus(0)\">\n <div class=\"card-status-idle\">\n <span>IDLE</span>\n <button class=\"btn btn-editor-xs btn-outline-secondary btn-outline-discrete btn-snapshot-details d-inline-block\" data-id=\"getId()\" v-on:click=\"openSnapshotDetails\"><i class=\"fas fa-info-circle\"></i></button>\n </div>\n </div>\n\n <div v-if=\"n.isSnapshotStatus(1)\">\n <div class=\"card-status-computing\">\n <span>COMPUTING</span>\n <button class=\"btn btn-editor-xs btn-outline-secondary btn-outline-discrete btn-snapshot-details d-inline-block\" data-id=\"getId()\" v-on:click=\"openSnapshotDetails\"><i class=\"fas fa-info-circle\"></i></button>\n </div>\n </div>\n\n <div v-if=\"n.isSnapshotStatus(2)\">\n <div class=\"card-status-awaiting-data\">\n <span>WAITING</span>\n <button class=\"btn btn-editor-xs btn-outline-secondary btn-outline-discrete btn-snapshot-details d-inline-block\" data-id=\"getId()\" v-on:click=\"openSnapshotDetails\"><i class=\"fas fa-info-circle\"></i></button>\n </div>\n </div>\n\n <div v-if=\"n.isSnapshotStatus(3)\">\n <div class=\"card-status-ready\">\n <span>READY</span>\n <button class=\"btn btn-editor-xs btn-outline-secondary btn-outline-discrete btn-snapshot-details d-inline-block\" data-id=\"getId()\" v-on:click=\"openSnapshotDetails\"><i class=\"fas fa-info-circle\"></i></button>\n </div>\n </div>\n </div>\n </div>\n\n <div v-if=\"!example && n.isUI() && !n.isOnAPanel()\">\n <div class=\"card-problem\">\n <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>\n </div>\n </div>\n\n <div class=\"card-top\">\n <div class=\"d-flex\">\n <span class=\"title\" style=\"white-space: nowrap; margin-right: 5px;\">\n <span v-if=\"n.isMetanode()\" class=\"badge badge-secondary\"><b>META</b></span>\n {{n.graphId}}\n <i v-if=\"n.isParallel()\" class=\"fas fa-server\" style=\"color: orange;\" title=\"this module is computed in a web worker\"></i>\n </span>\n\n <div class=\"ml-auto\">\n <button class=\"btn btn-outline-secondary btn-outline-discrete btn-editor-xs btn-settings\" v-on:click=\"openNodeSettings\"><i class=\"fas fa-cog\"></i></button>\n </div>\n </div>\n </div>\n <div v-if=\"!n.isInput() && !n.isOutput()\" class=\"card-center\">\n <hr style=\"margin-bottom: 5px;\"/>\n <div class=\"dualbox-io\" style=\"overflow: visible;\">\n <div class=\"inputs\" style=\"display: inline-block; float: left;\">\n <div class=\"box-inputs\">\n <div class=\"types\">\n <span class=\"type\" v-for=\"key in getVisibleInputs()\" v-bind:data-key=\"key\">\n {{ n.getInputType(key) }}\n </span>\n </div>\n <div class=\"points\">\n <div class=\"point\" v-for=\"key in getVisibleInputs()\" v-bind:data-key=\"key\" v-bind:data-type=\"n.getInputDef(key).type\" v-html=\"point\"></div>\n </div>\n <div class=\"names\">\n <span class=\"name\" v-for=\"key in getVisibleInputs()\" :class=\"{'feedback': n.isFeedbackTarget(key), 'input-not-resolvable': !example && !n.isInputResolvable(key) }\" v-bind:data-input=\"key\">\n <span v-if=\"n.hasIterator(key)\">&lt;{{key}}&gt;</span>\n <span v-else>{{key}}</span>\n <small v-if=\"!n.isInputConst(key)\" data-toggle=\"tooltip\" data-trigger=\"hover\" title=\"this value will be cloned at execution time\"><i class=\"fas fa-clone transparent\"></i></small>\n </span>\n </div>\n </div>\n </div>\n <div class=\"outputs\" style=\"display: inline-block; float: right\">\n <div class=\"box-outputs\">\n <div class=\"names\">\n <span class=\"name\" v-for=\"key in getVisibleOutputs()\" v-bind:class=\"{feedback: n.isFeedbackTarget(key)}\" v-bind:data-output=\"key\">\n <span v-if=\"n.hasLoop() && n.hasFeedback(key)\">{{key}}</span>\n <span v-else-if=\"n.hasLoop() && !n.hasFeedback(key)\" v-html='\"&lt;\"+key+\"&gt;\"'></span>\n <span v-else>{{key}}</span>\n\n <span v-if=\"n.hasCacheActivated()\">\n &nbsp;<i class=\"fa fa-hdd\" title=\"This module has cache activated\"></i>\n </span>\n </span>\n </div>\n <div class=\"points\">\n <div class=\"point\" v-for=\"key in getVisibleOutputs()\" v-bind:data-key=\"key\" v-bind:data-type=\"n.getOutputDef(key).type\" v-html=\"point\"></div>\n </div>\n <div class=\"types\">\n <span class=\"type\" v-for=\"key in getVisibleOutputs()\" v-bind:data-key=\"key\">\n {{ n.getOutputType(key) }}\n </span>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <hr style=\"margin-top: 5px;\"/>\n <div class=\"card-bottom\">\n <span class=\"subtitle\">{{ shortName }}</span>\n\n <div v-if=\"n.isMetanode()\" class=\"d-inline-block\">\n <button class=\"btn btn-outline-secondary btn-outline-discrete btn-editor-xs btn-enter-metanode\" v-on:click=\"enterMetanode\"><i class=\"fas fa-sign-in-alt\"></i></button>\n </div>\n\n <!--\n <div v-if=\"n.isUI()\" class=\"event-dock event-dock-bottom\"></div>\n -->\n </div>\n </div>\n</template>\n\n<script>\nimport ContextMenu from '../ContextMenu';\nimport _ from 'lodash';\nimport dbutils from '../../m/DualboxUtils';\n\n// fix inputs types and output types position relatively to the div\n$.fn.fixCardDisplay = function() {\n var offsetPoint = 12;\n var offsetBorder = parseInt($(this).css(\"border-top-width\"));\n\n if( $(this).find('.box-inputs').height() === 0 && $(this).find('.box-outputs').height() === 0 ) {\n // if this card has no input/output, remove the card center\n $(this).find('.card-center').remove();\n }\n else {\n // else, adjust the input/output display for endpoints\n // 1) translate inputs by the right amount of pixels to have the circle on the line\n var boxInputs = $(this).find('.box-inputs');\n\n // fix css names width\n var namesDiv = boxInputs.find('.names');\n namesDiv.css('width', (namesDiv.width()+1) + 'px');\n\n // translate inputs to the left\n var translateLeft = boxInputs.find('.types').width() + offsetPoint + offsetBorder/2;\n $(this).find('.box-inputs').css('transform', 'translateX(-' + translateLeft + 'px)');\n\n // adjust inputs main div width\n $(this).find('.inputs').width( $(this).find('.inputs').width() - translateLeft + 10 /* margin */ );\n\n\n // 2) translate outputs by the right amount of pixels to have the circle on the line\n var boxOutputs = $(this).find('.box-outputs');\n\n // fix css names with\n var namesDiv = boxOutputs.find('.names');\n namesDiv.css('width', (namesDiv.width() + 1) + 'px');\n\n // translate inputs to the right\n var translateRight = boxOutputs.find('.types').width() + offsetPoint + offsetBorder/2;\n $(this).find('.box-outputs').css('transform', 'translateX(' + translateRight + 'px)');\n\n // adjust output main div width\n $(this).find('.outputs').width( $(this).find('.outputs').width() - translateRight + 10 /* margin */ );\n\n // fix io width\n //$('.dualbox-io').css('width', (($(this).find('.inputs').width() + $(this).find('.outputs').width()) + \"px\"));\n }\n}\n\n// take the current width and add it as a css property\n$.fn.fixWidth = function() {\n var width = $(this).width();\n width += parseInt($(this).css('padding-right'));\n width += parseInt($(this).css('padding-left'));\n width += parseInt($(this).css('border-left-width'));\n width += parseInt($(this).css('border-right-width'));\n $(this).css('width', width + 'px');\n}\n\n// find position of element relative to an ancestor matching selector\n$.fn.positionFrom = function( selector ) {\n var ancestor = $(this).closest(selector);\n var offset = $(this).offset();\n var ancestorOffset = ancestor.offset();\n return {\n top: offset.top - ancestorOffset.top,\n left: offset.left - ancestorOffset.left,\n }\n}\n\nexport default {\n props: [\n \"id\", // the module id\n \"pkg\", // the module package.json\n \"n\", // the GraphNode object (from model)\n \"example\", // true if this vue is used as an example display (no need to connect)\n ],\n data: function () {\n return {\n shortName: \"\",\n point: '<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>',\n }\n },\n beforeUpdate: function() {\n //console.log('[UPDATING] ' + this.n.getUniqId());\n },\n destroyed: function() {\n console.log('[DESTROYED] ' + this.n.getUniqId());\n },\n created: function() {\n this.initialized = false;\n this.view = window.dualboxEditor.v;\n\n //console.log('[CREATED] ' + this.n.getUniqId());\n // We compute the shortname of our box\n if( this.n.isInput() || this.n.isOutput() ) {\n this.shortName = this.n.getType();\n }\n else {\n this.shortName = dbutils.shortName(this.pkg.name);\n }\n },\n mounted: async function() {\n console.log('[MOUNTED] ' + this.n.getUniqId());\n var div = $(this.$el);\n div.fixCardDisplay();\n div.ready(() => {\n //if( !this.example ) {\n div.fixWidth();\n //}\n });\n this.activateTooltip();\n return await this.initialize();\n },\n beforeUpdate: function() {\n this.deactivateTooltip();\n },\n updated: async function() {\n console.log('[UPDATED] ' + this.n.getUniqId());\n\n // we reset jsPlumb before app update (in graph.vue)\n // so we need to initialize again\n this.assignContextMenu();\n\n $(this.$el).fixCardDisplay();\n $(this.$el).ready(()=>{\n $(this.$el).fixWidth();\n this.activateTooltip();\n });\n return await this.initialize();\n },\n activate: function() {\n this.activateTooltip();\n },\n deactivate: function() {\n this.deactivateTooltip();\n },\n methods: {\n getId: function() {\n // if this is an example graphNode, change our \"id\" to \"id-junk\"\n // to avoid connection jsplumb conflicts with the real node\n return this.example ? this.id + '-junk' : this.id;\n },\n\n activateTooltip: function() {\n $(this.$el).find('[data-toggle=\"tooltip\"]').tooltip();\n },\n\n deactivateTooltip: function() {\n $(this.$el).find('[data-toggle=\"tooltip\"]').tooltip(\"dispose\");\n },\n\n initialize: async function() {\n var self = this;\n var div = $(this.$el);\n var id = this.getId();\n var view = this.view;\n\n this.initialized = false;\n\n if( !this.example ) {\n // if we have a position, set it\n var def = this.n.getDef();\n var position = _.get(def, [\"graph\", \"position\"]);\n if( position ) {\n var jsPlumbElement = self.$parent.jsPlumbInstance.getElement(id);\n self.$parent.jsPlumbInstance.setPosition(jsPlumbElement, position);\n }\n\n // This needs to be registered before draggable\n div.on('mousedown', function(e) {\n // if this div is not selected already, deselect the other divs\n if( !self.$parent.selector.isSelected(this) ) {\n self.$parent.selector.deselect();\n }\n });\n\n await this.initializeJsPlumb();\n\n div.click(function(e) {\n if( e.ctrlKey ) {\n view.selector.toggleSelection(this);\n }\n });\n\n this.assignContextMenu();\n }\n\n return new Promise(resolve => {\n div.ready(() => {\n console.log('[INITIALIZED] ' + this.n.getUniqId());\n this.initialized = true;\n resolve();\n });\n });\n },\n\n initializeJsPlumb: function() {\n var self = this;\n var div = $(this.$el);\n var id = this.getId();\n var view = this.view;\n\n if( !this.example ) {\n // If this node was never initialized in this jsplumb instance, do it\n if( !_.get(this.$parent.jsPlumbInstance, [\"initializedNodes\", id]) ) {\n _.set(this.$parent.jsPlumbInstance, [\"initializedNodes\", id], true); // initialized\n\n if( this.n.isInput() || this.n.isOutput() ) {\n var type = \"*\";\n var input = \"value\";\n var output = \"value\";\n var offsetTop = $(div).find('.card-top').height() + 12 /* hr size */ - 3;\n\n var uuid = [ id, \"input\", input].join('#');\n var ep = this.$parent.jsPlumbInstance.addEndpoint(id, {\n isSource : false,\n isTarget : true,\n uuid : uuid,\n anchor : [0,0,-1,0,0,offsetTop],\n maxConnections : 1,\n parameters : {\n type: \"data\",\n target : {\n id : id,\n input : output\n }\n }\n }, this.$parent.style.inputEndpoint);\n\n // add data to the endpoint div so we can identify it easier\n $(ep.canvas).attr('data-node', id);\n $(ep.canvas).attr('data-type', 'input');\n $(ep.canvas).attr('data-input', input);\n\n // bind tooltip\n $(ep.canvas).attr('data-toggle', \"tooltip\");\n $(ep.canvas).attr('data-trigger', \"hover\");\n $(ep.canvas).attr('data-placement', \"left\");\n $(ep.canvas).attr('data-html', \"true\");\n var inputType = view.m.getNode(id).getInputType(\"value\");\n $(ep.canvas).attr('title', \"Type: <b>\" + inputType + \"</b>\");\n $(ep.canvas).tooltip();\n\n // bind context menu to the endpoint\n $(ep.canvas).addClass('capture-right-click');\n $(ep.canvas).ready(function() {\n var menu = new ContextMenu(\".jtk-endpoint-anchor[data-node='\"+id.trim()+\"'][data-input='\" + input + \"']\", [\n {\n name: 'Create input for here',\n fn: () => {\n view.c.createInputFromConnection(id, input);\n }\n },\n ]);\n });\n\n var uuid = [ id, \"output\", output].join('#');\n var ep = this.$parent.jsPlumbInstance.addEndpoint(id, {\n isSource : true,\n isTarget : false,\n uuid : uuid,\n anchor : [1,0,1,0,0,offsetTop],\n parameters : {\n type: \"data\",\n source : {\n id : id,\n output : output\n }\n }\n }, this.$parent.style.outputEndpoint);\n\n // add data to the endpoint div so we can identify it easier\n $(ep.canvas).attr('data-node', id);\n $(ep.canvas).attr('data-type', \"output\");\n $(ep.canvas).attr('data-output', output);\n\n // bind tooltip\n $(ep.canvas).attr('data-toggle', \"tooltip\");\n $(ep.canvas).attr('data-trigger', \"hover\");\n $(ep.canvas).attr('data-placement', \"right\");\n $(ep.canvas).attr('data-html', \"true\");\n var outputType = view.m.getNode(id).getOutputType(\"value\");\n $(ep.canvas).attr('title', \"Type: <b>\" + outputType + \"</b>\");\n $(ep.canvas).tooltip();\n\n // bind context menu to the endpoint\n $(ep.canvas).addClass('capture-right-click');\n $(ep.canvas).ready(function() {\n var menu = new ContextMenu(\".jtk-endpoint-anchor[data-node='\"+id.trim()+\"'][data-output='\" + output.trim() + \"']\", [\n {\n name: 'Create output for here',\n fn: () => {\n view.c.createOutputFromConnection(id, output);\n }\n },\n ]);\n });\n }\n else {\n // add input endoints\n div.find('.box-inputs').find('.point').each( function(index) {\n $(this).css('visibility', 'hidden').css('opacity', '0'); // replaced by jsPlumb point\n\n var input = div.find('.box-inputs').find('.name').eq(index).attr('data-input').trim();\n var type = view.m.getNode(id).getInputType(input);\n\n var offsetTop = $(this).positionFrom('.card').top + $(this).height()/2 - 3;\n var uuid = [ id, \"input\", $(this).data('key')].join('#');\n var ep = self.$parent.jsPlumbInstance.addEndpoint(id, {\n isSource : false,\n isTarget : true,\n uuid : uuid,\n anchor : [0,0,-1,0,0,offsetTop],\n maxConnections : 1,\n parameters : {\n type: \"data\",\n target : {\n id : id,\n input : $(this).data('key')\n }\n }\n }, self.$parent.style.inputEndpoint);\n\n // add data to the endpoint div so we can identify it easier\n $(ep.canvas).attr('data-node', id);\n $(ep.canvas).attr('data-type', 'input');\n $(ep.canvas).attr('data-input', input);\n\n // bind tooltip\n $(ep.canvas).attr('data-toggle', \"tooltip\");\n $(ep.canvas).attr('data-trigger', \"hover\");\n $(ep.canvas).attr('data-placement', \"left\");\n $(ep.canvas).attr('data-html', \"true\");\n $(ep.canvas).attr('title', \"Type: <b>\" + type + \"</b>\");\n $(ep.canvas).tooltip();\n\n // bind context menu to the endpoint\n $(ep.canvas).addClass('capture-right-click');\n $(ep.canvas).ready(function() {\n var menu = new ContextMenu(\".jtk-endpoint-anchor[data-node='\"+id.trim()+\"'][data-input='\" + input.trim() + \"']\", [\n {\n name: 'Create input for here',\n fn: () => {\n view.c.createInputFromConnection(id, input);\n }\n },\n ]);\n });\n });\n\n // add output endpoints\n div.find('.box-outputs').find('.point').each( function(index) {\n $(this).css('visibility', 'hidden').css('opacity', '0'); // replaced by jsPlumb point\n\n var output = div.find('.box-outputs').find('.name').eq(index).attr('data-output').trim();\n var type = view.m.getNode(id).getOutputType(output);\n\n var offsetTop = $(this).positionFrom('.card').top + $(this).height()/2 - 3;\n var uuid = [ id, \"output\", $(this).data('key')].join('#');\n var ep = self.$parent.jsPlumbInstance.addEndpoint(id, {\n isSource : true,\n isTarget : false,\n uuid : uuid,\n anchor : [1,0,1,0,0,offsetTop],\n parameters : {\n type: \"data\",\n source : {\n id : id,\n output : $(this).data('key')\n }\n }\n }, self.$parent.style.outputEndpoint);\n\n // add data to the endpoint div so we can identify it easier\n $(ep.canvas).attr('data-node', id);\n $(ep.canvas).attr('data-type', \"output\");\n $(ep.canvas).attr('data-output', output);\n\n // bind tooltip\n $(ep.canvas).attr('data-toggle', \"tooltip\");\n $(ep.canvas).attr('data-trigger', \"hover\");\n $(ep.canvas).attr('data-placement', \"right\");\n $(ep.canvas).attr('data-html', \"true\");\n $(ep.canvas).attr('title', \"Type: <b>\" + type + \"</b>\");\n $(ep.canvas).tooltip();\n\n // bind context menu to the endpoint\n $(ep.canvas).addClass('capture-right-click');\n $(ep.canvas).ready(function() {\n var menu = new ContextMenu(\".jtk-endpoint-anchor[data-node='\"+id.trim()+\"'][data-output='\" + output.trim() + \"']\", [\n {\n name: 'Create output for here',\n fn: () => {\n view.c.createOutputFromConnection(id, output);\n }\n },\n ]);\n });\n });\n\n if( this.n.isUI() && view.showEvents ) {\n // Make this a target for events\n this.$parent.jsPlumbInstance.makeTarget(id, {\n isSource:false,\n isTarget:true,\n uniqueEndpoint: false,\n anchor:\"Continuous\",\n uuid: id + \"#event-in\",\n paintStyle:{ fill:\"green\" },\n parameters: {\n type: \"event\",\n target: { \"id\" : id }\n },\n }, self.$parent.style.eventEndpoint);\n\n // Create an enpoint to create a new event\n var ep = this.$parent.jsPlumbInstance.addEndpoint(id, {\n isSource : true,\n isTarget : false,\n uuid : id + \"#event-out\",\n anchor : [1, 1, 0, 1, 0, -10],\n parameters : {\n type: \"event\",\n source: { \"id\" : id }\n },\n }, this.$parent.style.eventEndpoint);\n\n // Add overlay here so we don't mess with splitConnection\n ep.addOverlay([\"PlainArrow\", { width:15, length:15, location:1, id:\"arrow\" }]);\n\n $(ep.canvas).attr('data-toggle', \"tooltip\");\n $(ep.canvas).attr('data-trigger', \"hover\");\n $(ep.canvas).attr('data-placement', \"bottom\");\n $(ep.canvas).attr('data-html', \"true\");\n $(ep.canvas).attr('title', \"Connect from here ito add an event that will be triggered when this box is done computing.\");\n $(ep.canvas).tooltip();\n }\n }\n\n // Make the div draggable\n this.$parent.jsPlumbInstance.draggable(div, {\n //containment:true, // not allowed outside of container div\n drag: function(e) {\n // TODO: bug. After a repaint(), jsPlumb seems to be broken (connections dont follow on div drag)\n // It doesn't occur on jsPlumb.reset() instead of creating another instance on beforeUpdate(),\n // (as it should be), but we can't do that, because JsPlumb is broken on zoom otherwise...\n // One of thoses problem may be fixed later by updating jsPlumb...\n // Note: this \"fix\" may affect performances on drag, maybe a setTimeout will do\n //self.$parent.jsPlumbInstance.repaintEverything();\n self.$parent.jsPlumbInstance.repaint(id);\n },\n stop: function(e) {\n // resize the canvas if necessary\n self.$parent.canvasSizeHandler.debouncedResize();\n\n if( self.$parent.selector.isMultipleSelectionActive() ) {\n // We just dropped a bunch of divs, ajust all their positions\n self.view.m.history.batch(() => {\n self.$parent.selector.each(div => {\n var pos = self.$parent.jsPlumbInstance.getPosition(div);\n view.m.getNode($(div).attr('id')).setPosition(pos);\n });\n });\n }\n else {\n // We just dropped this one, set the new position in the graph model\n var el = self.$parent.jsPlumbInstance.getElement(id);\n $(el).ready(function() {\n var pos = self.$parent.jsPlumbInstance.getPosition(el);\n view.m.getNode(id).setPosition(pos);\n });\n }\n }\n });\n }\n }\n\n return new Promise((resolve) => this.$parent.jsPlumbInstance.ready(resolve));\n },\n\n assignContextMenu: function() {\n var id = this.getId();\n\n // Create a contextmenu for the div\n var contextOptions = [\n {\n name: 'Remove this box',\n fn: () => {\n this.view.c.removeBox(id);\n }\n }\n ];\n if( this.n.isModule() || this.n.isUI() ) {\n contextOptions.push({\n name: 'Duplicate this box',\n fn: () => {\n this.view.c.duplicateBox(id);\n }\n });\n }\n var nodeMenu = new ContextMenu(\"#\" + id, contextOptions);\n },\n\n htmlentities: function( s ) {\n return this.view.utils.htmlentities(s);\n },\n\n getVisibleInputs: function() {\n return this.n.getInputsNames().filter((inputName) => {\n return this.n.isInputVisible(inputName);\n })\n },\n\n getVisibleOutputs: function() {\n return this.n.getOutputsNames().filter((outputName) => {\n return this.n.isOutputVisible(outputName);\n })\n },\n\n enterMetanode: function(e) {\n e.preventDefault();\n e.stopPropagation();\n\n this.view.c.enterMetanode(this.id);\n },\n\n openNodeSettings: function(e) {\n e.preventDefault();\n e.stopPropagation();\n this.view.openBoxSettings(this.id);\n },\n\n openSnapshotDetails: function(e) {\n e.preventDefault();\n e.stopPropagation();\n this.view.openDebug(this.id);\n }\n },\n watch: {\n 'app': {\n handler: () => {\n console.log('graphVue.app changed');\n },\n deep: true\n }\n }\n}\n\n</script>\n"]}, media: undefined });
46352
46367
 
46353
46368
  };
46354
46369
  /* scoped */
@@ -46578,15 +46593,19 @@ class Selector {
46578
46593
  this.parent = parent;
46579
46594
  this.container = container;
46580
46595
  // translateZ(0) avoid paint glitches in chrome as it forces a repaint every time
46581
- this.div = $('<div/>', { id: 'selector', hidden: true, style: "border: 1px dotted #000; position: absolute; z-index: 100; transform: translateZ(0);" });
46596
+ this.div = $('<div/>', {
46597
+ id: 'selector',
46598
+ hidden: true,
46599
+ style: "border: 1px dotted #000; position: absolute; z-index: 100; transform: translateZ(0);"
46600
+ });
46582
46601
  this.x1 = 0;
46583
46602
  this.x2 = 0;
46584
46603
  this.y1 = 0;
46585
46604
  this.y2 = 0;
46586
46605
 
46587
46606
  this.startEventHandler = this.onSelectionStart.bind(this);
46588
- this.moveEventHandler = this.onSelectionMove.bind(this);
46589
- this.stopEventHandler = this.onSelectionStop.bind(this);
46607
+ this.moveEventHandler = this.onSelectionMove.bind(this);
46608
+ this.stopEventHandler = this.onSelectionStop.bind(this);
46590
46609
 
46591
46610
  // offset difference relative to pageX/Y
46592
46611
  // we can't use offsetX and offsetY directly cause their value will be 0
@@ -46607,10 +46626,20 @@ class Selector {
46607
46626
  this.container.append(this.div);
46608
46627
  this.container.off('mousedown', this.startEventHandler);
46609
46628
  this.container.off('mousemove', this.moveEventHandler);
46610
- this.container.off('mouseup', this.stopEventHandler);
46629
+ this.container.off('mouseup', this.stopEventHandler);
46611
46630
  this.container.on('mousedown', this.startEventHandler);
46612
46631
  this.container.on('mousemove', this.moveEventHandler);
46613
- this.container.on('mouseup', this.stopEventHandler);
46632
+ this.container.on('mouseup', this.stopEventHandler);
46633
+ }
46634
+
46635
+ each(cb) {
46636
+ _.each(this.selection, selected => {
46637
+ cb(selected);
46638
+ });
46639
+ }
46640
+
46641
+ isMultipleSelectionActive() {
46642
+ return this.selection.length > 1;
46614
46643
  }
46615
46644
 
46616
46645
  getSelection() {
@@ -46625,7 +46654,7 @@ class Selector {
46625
46654
  isSelected(div) {
46626
46655
  var selected = false;
46627
46656
  _.each(this.selection, (selectedDiv) => {
46628
- if( $(div).is( $(selectedDiv) ) ) {
46657
+ if ($(div).is($(selectedDiv))) {
46629
46658
  selected = true;
46630
46659
  return false; // end of loop
46631
46660
  }
@@ -46643,7 +46672,7 @@ class Selector {
46643
46672
 
46644
46673
  // find the index
46645
46674
  _.each(this.selection, (selectedDiv, index) => {
46646
- if( $(div).is( $(selectedDiv) ) ) {
46675
+ if ($(div).is($(selectedDiv))) {
46647
46676
  i = index;
46648
46677
  return false; // end of loop
46649
46678
  }
@@ -46654,32 +46683,31 @@ class Selector {
46654
46683
  }
46655
46684
 
46656
46685
  toggleSelection(div) {
46657
- if( this.isSelected(div) ) {
46686
+ if (this.isSelected(div)) {
46658
46687
  this.removeFromSelection(div);
46659
- }
46660
- else {
46688
+ } else {
46661
46689
  this.addToSelection(div);
46662
46690
  }
46663
46691
  this.handleSelectionMenu();
46664
46692
  }
46665
46693
 
46666
- onSelect( cb ) {
46694
+ onSelect(cb) {
46667
46695
  this.onSelectCb = cb;
46668
46696
  }
46669
46697
 
46670
- onSelecting( cb ) {
46698
+ onSelecting(cb) {
46671
46699
  this.onSelectingCb = cb;
46672
46700
  }
46673
46701
 
46674
- onDeselect( cb ) {
46702
+ onDeselect(cb) {
46675
46703
  this.onDeselectCb = cb;
46676
46704
  }
46677
46705
 
46678
46706
  reCalc() {
46679
- var x3 = Math.min(this.x1,this.x2);
46680
- var x4 = Math.max(this.x1,this.x2);
46681
- var y3 = Math.min(this.y1,this.y2);
46682
- var y4 = Math.max(this.y1,this.y2);
46707
+ var x3 = Math.min(this.x1, this.x2);
46708
+ var x4 = Math.max(this.x1, this.x2);
46709
+ var y3 = Math.min(this.y1, this.y2);
46710
+ var y4 = Math.max(this.y1, this.y2);
46683
46711
 
46684
46712
  this.div[0].style.left = (x3 - this.diffX) + 'px';
46685
46713
  this.div[0].style.top = (y3 - this.diffY) + 'px';
@@ -46693,19 +46721,19 @@ class Selector {
46693
46721
  // - it's over the container
46694
46722
  // - it's not over a container's button
46695
46723
  // - it's not over a "capture-left-click" item
46696
- if( e.which === 1 &&
46724
+ if (e.which === 1 &&
46697
46725
  this.container.find('.btn:hover').length == 0 &&
46698
46726
  this.container.find('.nodrag:hover').length == 0 &&
46699
46727
  this.container.find('.jtk-connector:hover').length == 0 &&
46700
46728
  this.container.find('.capture-left-click:hover').length == 0
46701
46729
  ) {
46702
- if( this.container.is(':hover') ) {
46730
+ if (this.container.is(':hover')) {
46703
46731
  // we're starting a selection
46704
46732
  e.preventDefault();
46705
46733
  e.stopPropagation();
46706
46734
 
46707
46735
  // remove previous selection
46708
- if( this.onDeselectCb ) {
46736
+ if (this.onDeselectCb) {
46709
46737
  this.onDeselectCb(this.selection);
46710
46738
  this.selection = [];
46711
46739
  }
@@ -46725,7 +46753,7 @@ class Selector {
46725
46753
  }
46726
46754
 
46727
46755
  onSelectionMove(e) {
46728
- if( this.selecting ) {
46756
+ if (this.selecting) {
46729
46757
  e.preventDefault();
46730
46758
  e.stopPropagation();
46731
46759
 
@@ -46734,14 +46762,14 @@ class Selector {
46734
46762
  this.y2 = e.pageY;
46735
46763
  this.reCalc();
46736
46764
 
46737
- if( this.onSelectingCb ) {
46765
+ if (this.onSelectingCb) {
46738
46766
  // now we have our area, find all divs in it and return
46739
46767
  // result to the onSelectCb
46740
46768
  this.findCardDivs({
46741
- left : Math.min(this.x1, this.x2),
46742
- right : Math.max(this.x1, this.x2),
46743
- top : Math.min(this.y1, this.y2),
46744
- bottom : Math.max(this.y1, this.y2)
46769
+ left: Math.min(this.x1, this.x2),
46770
+ right: Math.max(this.x1, this.x2),
46771
+ top: Math.min(this.y1, this.y2),
46772
+ bottom: Math.max(this.y1, this.y2)
46745
46773
  }, (divs) => {
46746
46774
  this.selection = divs;
46747
46775
  this.handleSelectionMenu();
@@ -46752,7 +46780,7 @@ class Selector {
46752
46780
  }
46753
46781
 
46754
46782
  onSelectionStop(e) {
46755
- if( this.selecting && e.which === 1 ) {
46783
+ if (this.selecting && e.which === 1) {
46756
46784
  e.preventDefault();
46757
46785
  e.stopPropagation();
46758
46786
 
@@ -46760,14 +46788,14 @@ class Selector {
46760
46788
  this.selecting = false;
46761
46789
  this.div[0].hidden = 1;
46762
46790
 
46763
- if( this.onSelectCb ) {
46791
+ if (this.onSelectCb) {
46764
46792
  // now we have our area, find all divs in it and return
46765
46793
  // result to the onSelectCb
46766
46794
  this.findCardDivs({
46767
- left : Math.min(this.x1, this.x2),
46768
- right : Math.max(this.x1, this.x2),
46769
- top : Math.min(this.y1, this.y2),
46770
- bottom : Math.max(this.y1, this.y2)
46795
+ left: Math.min(this.x1, this.x2),
46796
+ right: Math.max(this.x1, this.x2),
46797
+ top: Math.min(this.y1, this.y2),
46798
+ bottom: Math.max(this.y1, this.y2)
46771
46799
  }, (divs) => {
46772
46800
  this.selection = divs;
46773
46801
  this.handleSelectionMenu();
@@ -46777,12 +46805,12 @@ class Selector {
46777
46805
  }
46778
46806
  }
46779
46807
 
46780
- findCardDivs( area, cb ) {
46808
+ findCardDivs(area, cb) {
46781
46809
  var self = this;
46782
46810
  var selectedCards = [];
46783
- this.container.find('.card, .connection-control').each(function() {
46784
- if( self._intersects( $(this), area ) ) {
46785
- selectedCards.push($(this));
46811
+ this.container.find('.card, .connection-control').each(function () {
46812
+ if (self._intersects($(this), area)) {
46813
+ selectedCards.push($(this)[0]);
46786
46814
  }
46787
46815
  });
46788
46816
 
@@ -46790,22 +46818,21 @@ class Selector {
46790
46818
  }
46791
46819
 
46792
46820
  // utilities
46793
- _intersects( div, area ) {
46821
+ _intersects(div, area) {
46794
46822
  var r1 = $(div)[0].getBoundingClientRect();
46795
46823
  var r2 = area;
46796
46824
  var res = !(r2.left > r1.right ||
46797
- r2.right < r1.left ||
46798
- r2.top > r1.bottom ||
46799
- r2.bottom < r1.top);
46825
+ r2.right < r1.left ||
46826
+ r2.top > r1.bottom ||
46827
+ r2.bottom < r1.top);
46800
46828
  return res;
46801
46829
  }
46802
46830
 
46803
46831
  // show/hide the selection menu if we have more than 2 divs selected
46804
46832
  handleSelectionMenu() {
46805
- if( this.selection.length > 1 ) {
46833
+ if (this.selection.length > 1) {
46806
46834
  this.parent.view.div.find('.selection-menu').show();
46807
- }
46808
- else {
46835
+ } else {
46809
46836
  this.parent.view.div.find('.selection-menu').hide();
46810
46837
  }
46811
46838
  }
@@ -62150,7 +62177,7 @@ var script$5 = {
62150
62177
  closeModal: function() {
62151
62178
  // don't mutate prop directly, mute the parent
62152
62179
  // this.display = false;
62153
- this.$emit('close');
62180
+ this.$emit('closed');
62154
62181
  },
62155
62182
 
62156
62183
  setSearchFocus : function() {
@@ -62936,11 +62963,11 @@ __vue_render__$5._withStripped = true;
62936
62963
  /* style */
62937
62964
  const __vue_inject_styles__$5 = function (inject) {
62938
62965
  if (!inject) return
62939
- inject("data-v-11457554_0", { source: "\n.add-node-modal .modal-body[data-v-11457554] {\n height: 70vh;\n}\n.h100[data-v-11457554] {\n height: 100%!important;\n min-height: 100%!important;\n}\n.table-desc th[data-v-11457554], .table-desc td[data-v-11457554] {\n margin-right: 10px;\n}\n#add-node-modal .modal-dialog[data-v-11457554] {\n min-width: calc(100% - 40px)!important;\n height: calc(100% - 40px);\n margin: 20px;\n padding: 0;\n}\n#add-node-modal .modal-content[data-v-11457554] {\n height: auto;\n min-height: 100%;\n border-radius: 0;\n}\n.nav-item[data-v-11457554] {\n margin-left: 15px;\n margin-right: 15px;\n}\n.nav-link[data-v-11457554] {\n padding-left: 4px;\n padding-right: 4px;\n padding-bottom: 4px;\n padding-top: 4px;\n vertical-align: middle;\n position: relative;\n user-select: none;\n}\n.nav-link.active[data-v-11457554] {\n top: 0px;\n border-top-left-radius: 5px;\n border-bottom-left-radius: 5px;\n}\n.nav-link > span[data-v-11457554] {\n padding-left: 10px;\n padding-right: 10px;\n}\n.nav-link.active > span[data-v-11457554] {\n color: black;\n}\n.input-search[data-v-11457554] {\n display: none;\n width: 1px;\n height: 24px;\n box-shadow: none!important;\n border-color: rgba(0,0,0,0.3)!important;\n}\n.nav-link.active .input-search[data-v-11457554] {\n display: inline-block;\n border-top-left-radius: 0px;\n border-bottom-left-radius: 0px;\n transition: width 1s;\n width: 200px;\n}\n.nav-compute > a.active > input[data-v-11457554] {\n background-color: rgba(0,0,0,0.3)!important;\n}\n.nav-compute > a.active[data-v-11457554], .nav-compute > a.active > input[data-v-11457554] {\n background-color: rgba(0,0,0,0.3)!important;\n color: rgba(255,255,255,0.5);\n}\n.nav-compute> a.active > .input-search[data-v-11457554]::placeholder {\n color: rgba(255,255,255,0.5);\n}\n.nav-uis > a.active[data-v-11457554], .nav-uis > a.active > input[data-v-11457554] {\n background-color: #bff2ca!important;\n}\n.nav-inputs > a.active[data-v-11457554] {\n background-color: #f5d76e!important;\n}\n.nav-compute > a.active > input[data-v-11457554] {\n background-color: rgba(0,0,0,0.8);\n}\n.nav-outputs > a.active[data-v-11457554], .nav-outputs > a.active > input[data-v-11457554] {\n background-color: #ffb3a7!important;\n}\n.message-container[data-v-11457554] {\n position: relative;\n width: 100%;\n height: 100%;\n}\n.message[data-v-11457554] {\n position: absolute;\n top: 50%;\n transform: translateY(-80%);\n left: 0;\n right: 0;\n opacity: 0.6;\n text-align: center;\n}\n.tab-content[data-v-11457554], .tab-pane[data-v-11457554] {\n width: 100%;\n height: 100%;\n}\nlabel[data-v-11457554] {\n font-size: 20px;\n margin-top: 20px;\n}\nfieldset[data-v-11457554] {\n border: 1px solid rgba(0,0,0,0.1);\n margin: 10px;\n padding: 20px;\n min-width: 600px;\n}\n", map: {"version":3,"sources":["/home/seb/dev/dualbox/editor/js/src/v/templates/addNode.vue"],"names":[],"mappings":";AACA;IACA,YAAA;AACA;AAEA;IACA,sBAAA;IACA,0BAAA;AACA;AAEA;IACA,kBAAA;AACA;AAEA;EACA,sCAAA;EACA,yBAAA;EACA,YAAA;EACA,UAAA;AACA;AAEA;EACA,YAAA;EACA,gBAAA;EACA,gBAAA;AACA;AAEA;IACA,iBAAA;IACA,kBAAA;AACA;AAEA;IACA,iBAAA;IACA,kBAAA;IACA,mBAAA;IACA,gBAAA;IACA,sBAAA;IACA,kBAAA;IACA,iBAAA;AACA;AAEA;IACA,QAAA;IACA,2BAAA;IACA,8BAAA;AACA;AAEA;IACA,kBAAA;IACA,mBAAA;AACA;AAEA;IACA,YAAA;AACA;AAEA;IACA,aAAA;IACA,UAAA;IACA,YAAA;IACA,0BAAA;IACA,uCAAA;AACA;AAEA;IACA,qBAAA;IACA,2BAAA;IACA,8BAAA;IACA,oBAAA;IACA,YAAA;AACA;AACA;IACA,2CAAA;AACA;AAEA;IACA,2CAAA;IACA,4BAAA;AACA;AAEA;IACA,4BAAA;AACA;AAEA;IACA,mCAAA;AACA;AAEA;IACA,mCAAA;AACA;AAEA;IACA,iCAAA;AACA;AAEA;IACA,mCAAA;AACA;AAEA;IACA,kBAAA;IACA,WAAA;IACA,YAAA;AACA;AAEA;IACA,kBAAA;IACA,QAAA;IACA,2BAAA;IACA,OAAA;IACA,QAAA;IACA,YAAA;IACA,kBAAA;AACA;AAEA;IACA,WAAA;IACA,YAAA;AACA;AAEA;IACA,eAAA;IACA,gBAAA;AACA;AAEA;IACA,iCAAA;IACA,YAAA;IACA,aAAA;IACA,gBAAA;AACA","file":"addNode.vue","sourcesContent":["<style scoped>\n.add-node-modal .modal-body {\n height: 70vh;\n}\n\n.h100 {\n height: 100%!important;\n min-height: 100%!important;\n}\n\n.table-desc th, .table-desc td {\n margin-right: 10px;\n}\n\n#add-node-modal .modal-dialog {\n min-width: calc(100% - 40px)!important;\n height: calc(100% - 40px);\n margin: 20px;\n padding: 0;\n}\n\n#add-node-modal .modal-content {\n height: auto;\n min-height: 100%;\n border-radius: 0;\n}\n\n.nav-item {\n margin-left: 15px;\n margin-right: 15px;\n}\n\n.nav-link {\n padding-left: 4px;\n padding-right: 4px;\n padding-bottom: 4px;\n padding-top: 4px;\n vertical-align: middle;\n position: relative;\n user-select: none;\n}\n\n.nav-link.active {\n top: 0px;\n border-top-left-radius: 5px;\n border-bottom-left-radius: 5px;\n}\n\n.nav-link > span {\n padding-left: 10px;\n padding-right: 10px;\n}\n\n.nav-link.active > span {\n color: black;\n}\n\n.input-search {\n display: none;\n width: 1px;\n height: 24px;\n box-shadow: none!important;\n border-color: rgba(0,0,0,0.3)!important;\n}\n\n.nav-link.active .input-search {\n display: inline-block;\n border-top-left-radius: 0px;\n border-bottom-left-radius: 0px;\n transition: width 1s;\n width: 200px;\n}\n.nav-compute > a.active > input {\n background-color: rgba(0,0,0,0.3)!important;\n}\n\n.nav-compute > a.active, .nav-compute > a.active > input {\n background-color: rgba(0,0,0,0.3)!important;\n color: rgba(255,255,255,0.5);\n}\n\n.nav-compute> a.active > .input-search::placeholder {\n color: rgba(255,255,255,0.5);\n}\n\n.nav-uis > a.active, .nav-uis > a.active > input {\n background-color: #bff2ca!important;\n}\n\n.nav-inputs > a.active {\n background-color: #f5d76e!important;\n}\n\n.nav-compute > a.active > input {\n background-color: rgba(0,0,0,0.8);\n}\n\n.nav-outputs > a.active, .nav-outputs > a.active > input {\n background-color: #ffb3a7!important;\n}\n\n.message-container {\n position: relative;\n width: 100%;\n height: 100%;\n}\n\n.message {\n position: absolute;\n top: 50%;\n transform: translateY(-80%);\n left: 0;\n right: 0;\n opacity: 0.6;\n text-align: center;\n}\n\n.tab-content, .tab-pane {\n width: 100%;\n height: 100%;\n}\n\nlabel {\n font-size: 20px;\n margin-top: 20px;\n}\n\nfieldset {\n border: 1px solid rgba(0,0,0,0.1);\n margin: 10px;\n padding: 20px;\n min-width: 600px;\n}\n</style>\n\n<template>\n <div class=\"modal fade add-node-modal\" :class=\"{ 'hide' : !display }\" id=\"add-node-modal\" tabindex=\"-1\" role=\"dialog\">\n <div class=\"modal-dialog\" role=\"document\">\n <div class=\"modal-content h100\">\n <div class=\"modal-header\">\n <h5 class=\"modal-title\">Add Box</h5>\n <ul class=\"nav nav-pills mr-auto ml-2\">\n <li class=\"nav-item nav-compute\">\n <a class=\"nav-link active\" href=\"#add-module-or-ui\" data-toggle=\"pill\" @click=\"selectType('module')\" draggable=\"false\">\n <span>Compute</span>\n <input class=\"form-control input-sm input-search search-modules\" type=\"text\" placeholder=\"Search modules...\" id=\"search-modules\" v-model=\"searchText['module']\" @input=\"searchModules\" autofocus/>\n </a>\n </li>\n <li class=\"nav-item nav-uis\">\n <a class=\"nav-link\" href=\"#add-module-or-ui\" data-toggle=\"pill\" @click=\"selectType('ui')\" draggable=\"false\">\n <span>UI</span>\n <input class=\"form-control input-sm input-search search-ui\" type=\"text\" placeholder=\"Search UIs...\" id=\"search-uis\" @input=\"searchModules\" v-model=\"searchText['ui']\" autofocus/>\n </a>\n </li>\n <li class=\"nav-item nav-inputs\" @click=\"selectType('input')\">\n <a class=\"nav-link\" href=\"#add-input\" data-toggle=\"pill\" draggable=\"false\"><span>Input</span></a>\n </li>\n <li class=\"nav-item nav-outputs\" @click=\"selectType('output')\">\n <a class=\"nav-link\" href=\"#add-output\"data-toggle=\"pill\" draggable=\"false\"><span>Output</span></a>\n </li>\n <li class=\"nav-item nav-outputs\" @click=\"selectType('metanode')\">\n <a class=\"nav-link\" href=\"#add-metanode\"data-toggle=\"pill\" draggable=\"false\"><span>Metabox</span></a>\n </li>\n </ul>\n\n <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">\n <span aria-hidden=\"true\">&times;</span>\n </button>\n </div>\n <div class=\"modal-body\">\n <div class=\"container-fluid h100\">\n\n <div class=\"tab-content\">\n <div class=\"tab-pane active\" id=\"add-module-or-ui\" role=\"tabpanel\" aria-labelledby=\"add-module-or-ui-tab\">\n <div class=\"row h100\">\n <div v-if=\"getSearchText().length == 0\" class=\"message-container\">\n <p class=\"message\"><i class=\"fas fa-search\"></i> Type something to search through the Dualbox library.</p>\n </div>\n <div v-else-if=\"getNbResults() == 0\">\n <p class=\"message\"><i class=\"fas fa-search\"></i> No results.</p>\n </div>\n <template v-else>\n <div class=\"col-md-4 h100\" style=\"padding-left: 0; padding-right: 0; overflow-y: auto; overflow-x: hidden;\">\n <search-results ref=\"searchResults\" :results=\"getResults()\" :err=\"error\" @resultSelected=\"setSelectedResult\"></search-results>\n </div>\n <div class=\"col-md-8 h100\" style=\"padding-left: 15px; padding-right: 0;\">\n <display-result ref=\"displayResults\" v-if=\"getSelectedResult()\" :result=\"getSelectedResult()\"></display-result>\n <div v-else class=\"message-container\">\n <p class=\"message\">Select a result to display</p>\n </div>\n </div>\n </template>\n </div>\n </div>\n <div class=\"tab-pane\" id=\"add-input\" role=\"tabpanel\" aria-labelledby=\"add-input-tab\">\n <div class=\"row\">\n <fieldset class=\"mx-auto\" style=\"margin-top: 50px;\">\n <h2 class=\"mt-2\">Add a new input</h2>\n\n <div class=\"form-group\">\n <label for=\"input-name\">Input name:</label>\n <input type=\"text\" class=\"form-control input-name\" id=\"input-name\" placeholder=\"Enter name...\" autofocus required>\n </div>\n\n <div class=\"form-group\">\n <label for=\"input-name\">Input type:</label>\n <input style=\"display: none;\" required/>\n <edit-type ref=\"inputType\" :type=\"inputType\" :displayOKButton=\"false\"></edit-type>\n </div>\n\n <div class=\"form-group\">\n <label for=\"input-description\">Input description:</label>\n <textarea class=\"input-description\" rows=4 style=\"width: 100%;\" placeholder=\"Enter description\" autofocus>\n </textarea>\n </div>\n </fieldset>\n </div>\n </div>\n <div class=\"tab-pane\" id=\"add-output\" role=\"tabpanel\" aria-labelledby=\"add-output-tab\">\n <div class=\"row\">\n <fieldset class=\"mx-auto\" style=\"margin-top: 50px;\">\n <h2 class=\"mt-2\">Add a new output</h2>\n\n <div class=\"form-group\">\n <label for=\"output-name\">Output name:</label>\n <input type=\"text\" class=\"form-control output-name\" id=\"output-name\" placeholder=\"Enter name...\" autofocus required>\n </div>\n\n <div class=\"form-group\">\n <label for=\"output-name\">Output type:</label>\n <input style=\"display: none;\" required/>\n <edit-type ref=\"outputType\" :type=\"outputType\" :displayOKButton=\"false\"></edit-type>\n </div>\n\n <div class=\"form-group\">\n <label for=\"output-description\">Output description:</label>\n <textarea class=\"output-description\" rows=4 style=\"width: 100%;\" placeholder=\"Enter description\" autofocus>\n </textarea>\n </div>\n </fieldset>\n </div>\n </div>\n <div class=\"tab-pane\" id=\"add-metanode\" role=\"tabpanel\" aria-labelledby=\"add-metanode-tab\">\n <div class=\"row\">\n <fieldset class=\"mx-auto\" style=\"margin-top: 50px;\">\n <h2 class=\"mt-2\">Add a new Metabox <!--<button class=\"btn btn-outline-secondary float-right\" @click=\"importMetabox\"><i class=\"fas fa-upload\"></i></button>--></h2>\n\n <div class=\"form-group\">\n <label for=\"metanode-name\">Metabox name:</label>\n <input type=\"text\" class=\"form-control metanode-name\" id=\"metanode-name\" placeholder=\"Enter name...\" autofocus required>\n </div>\n\n <div class=\"form-group\">\n <label for=\"metanode-def\">Metabox definition (optional):</label>\n <input type=\"file\" class=\"form-control-file\" id=\"metanode-def\" @change=\"onMetaboxFileSelect\">\n </div>\n\n <div class=\"form-group\">\n <label for=\"metanode-description\">Metabox description:</label>\n <textarea class=\"metanode-description\" rows=4 style=\"width: 100%;\" placeholder=\"Enter description\" autofocus>\n </textarea>\n </div>\n </fieldset>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">Close</button>\n <button type=\"button\" class=\"btn btn-primary add-node-btn\" @click=\"addSelectedNode\">Add node</button>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script>\nimport _ from 'lodash';\nimport swal from 'sweetalert2';\nimport SearchResultsVue from './searchResults.vue';\nimport DisplayResultVue from './displayResult.vue';\nimport EditTypeVue from './editType.vue'\n\nexport default {\n props: [\n \"display\", // original state (true = show, false=hide) of the modal\n \"mousePosition\" // mouse position when this panel was opened\n ],\n components: {\n 'search-results' : SearchResultsVue,\n 'display-result' : DisplayResultVue,\n 'edit-type' : EditTypeVue\n },\n data: function () {\n return {\n error: null,\n\n searchText: {}, // the search text, indexed by selectedType\n results: {}, // dictionary of arrays, indexed by selectedType\n selectedResult : {}, // dictionary of string, indexed by selectedType\n selectedType: \"module\",\n inputType: \"*\",\n outputType: \"*\"\n }\n },\n created: function() {\n this.view = window.dualboxEditor.v;\n },\n updated: function() {\n console.log('AddNode updated !');\n this.updateVisibility();\n this.setSearchFocus();\n },\n mounted: function() {\n var self = this;\n this.updateVisibility(); // to init our modal\n\n $(this.$el).on(\"shown.bs.modal\", () => {\n this.setSearchFocus();\n });\n $(this.$el).on(\"hide.bs.modal\", () => {\n self.$emit('closed');\n });\n\n $(this.$el).find('[data-toggle=\"pill\"]').on('shown.bs.tab', (e) => {\n this.setSearchFocus();\n var selectedResult = this.getSelectedResult();\n if( selectedResult ) {\n this.$refs.searchResults.selected = selectedResult.name;\n }\n });\n },\n methods: {\n updateVisibility : function() {\n if( this.display ) {\n $(this.$el).modal(\"show\");\n }\n else {\n $(this.$el).modal(\"hide\");\n }\n },\n\n closeModal: function() {\n // don't mutate prop directly, mute the parent\n // this.display = false;\n this.$emit('close');\n },\n\n setSearchFocus : function() {\n $(this.$el).find('.nav-link.active').find('input').focus();\n },\n\n selectType(t) {\n this.selectedType = t;\n },\n\n addSelectedNode: function(e) {\n switch( this.selectedType ) {\n case \"module\":\n case \"ui\":\n var selectedNode = $('.node-result.selected')[0];\n if( selectedNode ) {\n // add node to the controller\n var packageName = $(selectedNode).data('package');\n this.view.c.addNewBox(packageName, this.mousePosition);\n this.closeModal();\n }\n else {\n swal('Please select a node', '', 'error');\n return;\n }\n break;\n\n case \"input\":\n var type = this.$refs.inputType.get();\n var name = $(this.$el).find('.input-name').val();\n var desc = $(this.$el).find('.input-description').val();\n if( type !== undefined && name ) {\n this.view.c.addInput(name, type, desc, this.mousePosition);\n // reset fields\n this.$refs.inputType.resetChanges();\n $(this.$el).find('.input-name').val(\"\");\n $(this.$el).find('.input-description').val(\"\");\n this.closeModal();\n }\n else {\n swal('Please complete all fields', '', 'error');\n return;\n }\n break;\n\n case \"output\":\n var name = $(this.$el).find('.output-name').val();\n var type = this.$refs.outputType.get();\n var desc = $(this.$el).find('.output-description').val();\n if( type !== undefined && name ) {\n this.view.c.addOutput(name, type, desc, this.mousePosition);\n // reset fields\n this.$refs.outputType.resetChanges();\n $(this.$el).find('.output-name').val(\"\");\n $(this.$el).find('.output-description').val(\"\");\n this.closeModal();\n }\n else {\n swal('Please complete all fields', '', 'error');\n return;\n }\n break;\n\n case \"metanode\":\n var name = $(this.$el).find('.metanode-name').val();\n var desc = $(this.$el).find('.metanode-description').val();\n if( !name ) {\n swal('Please complete name field', '', 'error');\n return;\n }\n\n var json = this.metanodeJSON || {};\n json.description = desc;\n\n this.view.c.addNewMetabox(name, json, this.mousePosition);\n this.closeModal();\n default:\n }\n },\n\n searchModules: async function(e) {\n //var text = $(e.target).val();\n var text = this.searchText[this.selectedType];\n try {\n this.error = null;\n this.results[this.selectedType] = await this.view.e.search(text, this.selectedType);\n this.$forceUpdate();\n }\n catch(e) {\n this.error = e;\n swal('error searching packages', e.reason, \"error\");\n }\n },\n\n getSearchText: function() {\n return this.searchText[this.selectedType] || \"\";\n },\n\n setSelectedResult: function(packageName) {\n // first, find the selected result in the list\n var selectedPackage = null;\n _.each(this.getResults(), (r) => {\n if( r.name == packageName ) {\n selectedPackage = r;\n return false;\n }\n });\n\n if( !selectedPackage ) {\n throw \"Could not find package named \" + packageName;\n }\n\n this.selectedResult[this.selectedType] = selectedPackage;\n this.$forceUpdate();\n },\n\n getSelectedResult: function() {\n return this.selectedResult[this.selectedType];\n },\n\n getResults: function() {\n return this.results[this.selectedType] || null;\n },\n\n getNbResults: function() {\n var results = this.getResults();\n return results && results.length ? results.length: 0;\n },\n\n onMetaboxFileSelect: function(e) {\n var file = e.target.files[0];\n const reader = new FileReader()\n reader.onload = (e) => {\n this.metanodeJSON = JSON.parse(e.target.result);\n if( this.metanodeJSON.description ) {\n $(this.$el).find('.metanode-description').val(this.metanodeJSON.description);\n }\n }\n reader.readAsText(file)\n }\n }\n}\n\n</script>\n\n"]}, media: undefined });
62966
+ inject("data-v-b85f4cf4_0", { source: "\n.add-node-modal .modal-body[data-v-b85f4cf4] {\n height: 70vh;\n}\n.h100[data-v-b85f4cf4] {\n height: 100%!important;\n min-height: 100%!important;\n}\n.table-desc th[data-v-b85f4cf4], .table-desc td[data-v-b85f4cf4] {\n margin-right: 10px;\n}\n#add-node-modal .modal-dialog[data-v-b85f4cf4] {\n min-width: calc(100% - 40px)!important;\n height: calc(100% - 40px);\n margin: 20px;\n padding: 0;\n}\n#add-node-modal .modal-content[data-v-b85f4cf4] {\n height: auto;\n min-height: 100%;\n border-radius: 0;\n}\n.nav-item[data-v-b85f4cf4] {\n margin-left: 15px;\n margin-right: 15px;\n}\n.nav-link[data-v-b85f4cf4] {\n padding-left: 4px;\n padding-right: 4px;\n padding-bottom: 4px;\n padding-top: 4px;\n vertical-align: middle;\n position: relative;\n user-select: none;\n}\n.nav-link.active[data-v-b85f4cf4] {\n top: 0px;\n border-top-left-radius: 5px;\n border-bottom-left-radius: 5px;\n}\n.nav-link > span[data-v-b85f4cf4] {\n padding-left: 10px;\n padding-right: 10px;\n}\n.nav-link.active > span[data-v-b85f4cf4] {\n color: black;\n}\n.input-search[data-v-b85f4cf4] {\n display: none;\n width: 1px;\n height: 24px;\n box-shadow: none!important;\n border-color: rgba(0,0,0,0.3)!important;\n}\n.nav-link.active .input-search[data-v-b85f4cf4] {\n display: inline-block;\n border-top-left-radius: 0px;\n border-bottom-left-radius: 0px;\n transition: width 1s;\n width: 200px;\n}\n.nav-compute > a.active > input[data-v-b85f4cf4] {\n background-color: rgba(0,0,0,0.3)!important;\n}\n.nav-compute > a.active[data-v-b85f4cf4], .nav-compute > a.active > input[data-v-b85f4cf4] {\n background-color: rgba(0,0,0,0.3)!important;\n color: rgba(255,255,255,0.5);\n}\n.nav-compute> a.active > .input-search[data-v-b85f4cf4]::placeholder {\n color: rgba(255,255,255,0.5);\n}\n.nav-uis > a.active[data-v-b85f4cf4], .nav-uis > a.active > input[data-v-b85f4cf4] {\n background-color: #bff2ca!important;\n}\n.nav-inputs > a.active[data-v-b85f4cf4] {\n background-color: #f5d76e!important;\n}\n.nav-compute > a.active > input[data-v-b85f4cf4] {\n background-color: rgba(0,0,0,0.8);\n}\n.nav-outputs > a.active[data-v-b85f4cf4], .nav-outputs > a.active > input[data-v-b85f4cf4] {\n background-color: #ffb3a7!important;\n}\n.message-container[data-v-b85f4cf4] {\n position: relative;\n width: 100%;\n height: 100%;\n}\n.message[data-v-b85f4cf4] {\n position: absolute;\n top: 50%;\n transform: translateY(-80%);\n left: 0;\n right: 0;\n opacity: 0.6;\n text-align: center;\n}\n.tab-content[data-v-b85f4cf4], .tab-pane[data-v-b85f4cf4] {\n width: 100%;\n height: 100%;\n}\nlabel[data-v-b85f4cf4] {\n font-size: 20px;\n margin-top: 20px;\n}\nfieldset[data-v-b85f4cf4] {\n border: 1px solid rgba(0,0,0,0.1);\n margin: 10px;\n padding: 20px;\n min-width: 600px;\n}\n", map: {"version":3,"sources":["/home/seb/dev/dualbox/editor/js/src/v/templates/addNode.vue"],"names":[],"mappings":";AACA;IACA,YAAA;AACA;AAEA;IACA,sBAAA;IACA,0BAAA;AACA;AAEA;IACA,kBAAA;AACA;AAEA;EACA,sCAAA;EACA,yBAAA;EACA,YAAA;EACA,UAAA;AACA;AAEA;EACA,YAAA;EACA,gBAAA;EACA,gBAAA;AACA;AAEA;IACA,iBAAA;IACA,kBAAA;AACA;AAEA;IACA,iBAAA;IACA,kBAAA;IACA,mBAAA;IACA,gBAAA;IACA,sBAAA;IACA,kBAAA;IACA,iBAAA;AACA;AAEA;IACA,QAAA;IACA,2BAAA;IACA,8BAAA;AACA;AAEA;IACA,kBAAA;IACA,mBAAA;AACA;AAEA;IACA,YAAA;AACA;AAEA;IACA,aAAA;IACA,UAAA;IACA,YAAA;IACA,0BAAA;IACA,uCAAA;AACA;AAEA;IACA,qBAAA;IACA,2BAAA;IACA,8BAAA;IACA,oBAAA;IACA,YAAA;AACA;AACA;IACA,2CAAA;AACA;AAEA;IACA,2CAAA;IACA,4BAAA;AACA;AAEA;IACA,4BAAA;AACA;AAEA;IACA,mCAAA;AACA;AAEA;IACA,mCAAA;AACA;AAEA;IACA,iCAAA;AACA;AAEA;IACA,mCAAA;AACA;AAEA;IACA,kBAAA;IACA,WAAA;IACA,YAAA;AACA;AAEA;IACA,kBAAA;IACA,QAAA;IACA,2BAAA;IACA,OAAA;IACA,QAAA;IACA,YAAA;IACA,kBAAA;AACA;AAEA;IACA,WAAA;IACA,YAAA;AACA;AAEA;IACA,eAAA;IACA,gBAAA;AACA;AAEA;IACA,iCAAA;IACA,YAAA;IACA,aAAA;IACA,gBAAA;AACA","file":"addNode.vue","sourcesContent":["<style scoped>\n.add-node-modal .modal-body {\n height: 70vh;\n}\n\n.h100 {\n height: 100%!important;\n min-height: 100%!important;\n}\n\n.table-desc th, .table-desc td {\n margin-right: 10px;\n}\n\n#add-node-modal .modal-dialog {\n min-width: calc(100% - 40px)!important;\n height: calc(100% - 40px);\n margin: 20px;\n padding: 0;\n}\n\n#add-node-modal .modal-content {\n height: auto;\n min-height: 100%;\n border-radius: 0;\n}\n\n.nav-item {\n margin-left: 15px;\n margin-right: 15px;\n}\n\n.nav-link {\n padding-left: 4px;\n padding-right: 4px;\n padding-bottom: 4px;\n padding-top: 4px;\n vertical-align: middle;\n position: relative;\n user-select: none;\n}\n\n.nav-link.active {\n top: 0px;\n border-top-left-radius: 5px;\n border-bottom-left-radius: 5px;\n}\n\n.nav-link > span {\n padding-left: 10px;\n padding-right: 10px;\n}\n\n.nav-link.active > span {\n color: black;\n}\n\n.input-search {\n display: none;\n width: 1px;\n height: 24px;\n box-shadow: none!important;\n border-color: rgba(0,0,0,0.3)!important;\n}\n\n.nav-link.active .input-search {\n display: inline-block;\n border-top-left-radius: 0px;\n border-bottom-left-radius: 0px;\n transition: width 1s;\n width: 200px;\n}\n.nav-compute > a.active > input {\n background-color: rgba(0,0,0,0.3)!important;\n}\n\n.nav-compute > a.active, .nav-compute > a.active > input {\n background-color: rgba(0,0,0,0.3)!important;\n color: rgba(255,255,255,0.5);\n}\n\n.nav-compute> a.active > .input-search::placeholder {\n color: rgba(255,255,255,0.5);\n}\n\n.nav-uis > a.active, .nav-uis > a.active > input {\n background-color: #bff2ca!important;\n}\n\n.nav-inputs > a.active {\n background-color: #f5d76e!important;\n}\n\n.nav-compute > a.active > input {\n background-color: rgba(0,0,0,0.8);\n}\n\n.nav-outputs > a.active, .nav-outputs > a.active > input {\n background-color: #ffb3a7!important;\n}\n\n.message-container {\n position: relative;\n width: 100%;\n height: 100%;\n}\n\n.message {\n position: absolute;\n top: 50%;\n transform: translateY(-80%);\n left: 0;\n right: 0;\n opacity: 0.6;\n text-align: center;\n}\n\n.tab-content, .tab-pane {\n width: 100%;\n height: 100%;\n}\n\nlabel {\n font-size: 20px;\n margin-top: 20px;\n}\n\nfieldset {\n border: 1px solid rgba(0,0,0,0.1);\n margin: 10px;\n padding: 20px;\n min-width: 600px;\n}\n</style>\n\n<template>\n <div class=\"modal fade add-node-modal\" :class=\"{ 'hide' : !display }\" id=\"add-node-modal\" tabindex=\"-1\" role=\"dialog\">\n <div class=\"modal-dialog\" role=\"document\">\n <div class=\"modal-content h100\">\n <div class=\"modal-header\">\n <h5 class=\"modal-title\">Add Box</h5>\n <ul class=\"nav nav-pills mr-auto ml-2\">\n <li class=\"nav-item nav-compute\">\n <a class=\"nav-link active\" href=\"#add-module-or-ui\" data-toggle=\"pill\" @click=\"selectType('module')\" draggable=\"false\">\n <span>Compute</span>\n <input class=\"form-control input-sm input-search search-modules\" type=\"text\" placeholder=\"Search modules...\" id=\"search-modules\" v-model=\"searchText['module']\" @input=\"searchModules\" autofocus/>\n </a>\n </li>\n <li class=\"nav-item nav-uis\">\n <a class=\"nav-link\" href=\"#add-module-or-ui\" data-toggle=\"pill\" @click=\"selectType('ui')\" draggable=\"false\">\n <span>UI</span>\n <input class=\"form-control input-sm input-search search-ui\" type=\"text\" placeholder=\"Search UIs...\" id=\"search-uis\" @input=\"searchModules\" v-model=\"searchText['ui']\" autofocus/>\n </a>\n </li>\n <li class=\"nav-item nav-inputs\" @click=\"selectType('input')\">\n <a class=\"nav-link\" href=\"#add-input\" data-toggle=\"pill\" draggable=\"false\"><span>Input</span></a>\n </li>\n <li class=\"nav-item nav-outputs\" @click=\"selectType('output')\">\n <a class=\"nav-link\" href=\"#add-output\"data-toggle=\"pill\" draggable=\"false\"><span>Output</span></a>\n </li>\n <li class=\"nav-item nav-outputs\" @click=\"selectType('metanode')\">\n <a class=\"nav-link\" href=\"#add-metanode\"data-toggle=\"pill\" draggable=\"false\"><span>Metabox</span></a>\n </li>\n </ul>\n\n <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">\n <span aria-hidden=\"true\">&times;</span>\n </button>\n </div>\n <div class=\"modal-body\">\n <div class=\"container-fluid h100\">\n\n <div class=\"tab-content\">\n <div class=\"tab-pane active\" id=\"add-module-or-ui\" role=\"tabpanel\" aria-labelledby=\"add-module-or-ui-tab\">\n <div class=\"row h100\">\n <div v-if=\"getSearchText().length == 0\" class=\"message-container\">\n <p class=\"message\"><i class=\"fas fa-search\"></i> Type something to search through the Dualbox library.</p>\n </div>\n <div v-else-if=\"getNbResults() == 0\">\n <p class=\"message\"><i class=\"fas fa-search\"></i> No results.</p>\n </div>\n <template v-else>\n <div class=\"col-md-4 h100\" style=\"padding-left: 0; padding-right: 0; overflow-y: auto; overflow-x: hidden;\">\n <search-results ref=\"searchResults\" :results=\"getResults()\" :err=\"error\" @resultSelected=\"setSelectedResult\"></search-results>\n </div>\n <div class=\"col-md-8 h100\" style=\"padding-left: 15px; padding-right: 0;\">\n <display-result ref=\"displayResults\" v-if=\"getSelectedResult()\" :result=\"getSelectedResult()\"></display-result>\n <div v-else class=\"message-container\">\n <p class=\"message\">Select a result to display</p>\n </div>\n </div>\n </template>\n </div>\n </div>\n <div class=\"tab-pane\" id=\"add-input\" role=\"tabpanel\" aria-labelledby=\"add-input-tab\">\n <div class=\"row\">\n <fieldset class=\"mx-auto\" style=\"margin-top: 50px;\">\n <h2 class=\"mt-2\">Add a new input</h2>\n\n <div class=\"form-group\">\n <label for=\"input-name\">Input name:</label>\n <input type=\"text\" class=\"form-control input-name\" id=\"input-name\" placeholder=\"Enter name...\" autofocus required>\n </div>\n\n <div class=\"form-group\">\n <label for=\"input-name\">Input type:</label>\n <input style=\"display: none;\" required/>\n <edit-type ref=\"inputType\" :type=\"inputType\" :displayOKButton=\"false\"></edit-type>\n </div>\n\n <div class=\"form-group\">\n <label for=\"input-description\">Input description:</label>\n <textarea class=\"input-description\" rows=4 style=\"width: 100%;\" placeholder=\"Enter description\" autofocus>\n </textarea>\n </div>\n </fieldset>\n </div>\n </div>\n <div class=\"tab-pane\" id=\"add-output\" role=\"tabpanel\" aria-labelledby=\"add-output-tab\">\n <div class=\"row\">\n <fieldset class=\"mx-auto\" style=\"margin-top: 50px;\">\n <h2 class=\"mt-2\">Add a new output</h2>\n\n <div class=\"form-group\">\n <label for=\"output-name\">Output name:</label>\n <input type=\"text\" class=\"form-control output-name\" id=\"output-name\" placeholder=\"Enter name...\" autofocus required>\n </div>\n\n <div class=\"form-group\">\n <label for=\"output-name\">Output type:</label>\n <input style=\"display: none;\" required/>\n <edit-type ref=\"outputType\" :type=\"outputType\" :displayOKButton=\"false\"></edit-type>\n </div>\n\n <div class=\"form-group\">\n <label for=\"output-description\">Output description:</label>\n <textarea class=\"output-description\" rows=4 style=\"width: 100%;\" placeholder=\"Enter description\" autofocus>\n </textarea>\n </div>\n </fieldset>\n </div>\n </div>\n <div class=\"tab-pane\" id=\"add-metanode\" role=\"tabpanel\" aria-labelledby=\"add-metanode-tab\">\n <div class=\"row\">\n <fieldset class=\"mx-auto\" style=\"margin-top: 50px;\">\n <h2 class=\"mt-2\">Add a new Metabox <!--<button class=\"btn btn-outline-secondary float-right\" @click=\"importMetabox\"><i class=\"fas fa-upload\"></i></button>--></h2>\n\n <div class=\"form-group\">\n <label for=\"metanode-name\">Metabox name:</label>\n <input type=\"text\" class=\"form-control metanode-name\" id=\"metanode-name\" placeholder=\"Enter name...\" autofocus required>\n </div>\n\n <div class=\"form-group\">\n <label for=\"metanode-def\">Metabox definition (optional):</label>\n <input type=\"file\" class=\"form-control-file\" id=\"metanode-def\" @change=\"onMetaboxFileSelect\">\n </div>\n\n <div class=\"form-group\">\n <label for=\"metanode-description\">Metabox description:</label>\n <textarea class=\"metanode-description\" rows=4 style=\"width: 100%;\" placeholder=\"Enter description\" autofocus>\n </textarea>\n </div>\n </fieldset>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">Close</button>\n <button type=\"button\" class=\"btn btn-primary add-node-btn\" @click=\"addSelectedNode\">Add node</button>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script>\nimport _ from 'lodash';\nimport swal from 'sweetalert2';\nimport SearchResultsVue from './searchResults.vue';\nimport DisplayResultVue from './displayResult.vue';\nimport EditTypeVue from './editType.vue'\n\nexport default {\n props: [\n \"display\", // original state (true = show, false=hide) of the modal\n \"mousePosition\" // mouse position when this panel was opened\n ],\n components: {\n 'search-results' : SearchResultsVue,\n 'display-result' : DisplayResultVue,\n 'edit-type' : EditTypeVue\n },\n data: function () {\n return {\n error: null,\n\n searchText: {}, // the search text, indexed by selectedType\n results: {}, // dictionary of arrays, indexed by selectedType\n selectedResult : {}, // dictionary of string, indexed by selectedType\n selectedType: \"module\",\n inputType: \"*\",\n outputType: \"*\"\n }\n },\n created: function() {\n this.view = window.dualboxEditor.v;\n },\n updated: function() {\n console.log('AddNode updated !');\n this.updateVisibility();\n this.setSearchFocus();\n },\n mounted: function() {\n var self = this;\n this.updateVisibility(); // to init our modal\n\n $(this.$el).on(\"shown.bs.modal\", () => {\n this.setSearchFocus();\n });\n $(this.$el).on(\"hide.bs.modal\", () => {\n self.$emit('closed');\n });\n\n $(this.$el).find('[data-toggle=\"pill\"]').on('shown.bs.tab', (e) => {\n this.setSearchFocus();\n var selectedResult = this.getSelectedResult();\n if( selectedResult ) {\n this.$refs.searchResults.selected = selectedResult.name;\n }\n });\n },\n methods: {\n updateVisibility : function() {\n if( this.display ) {\n $(this.$el).modal(\"show\");\n }\n else {\n $(this.$el).modal(\"hide\");\n }\n },\n\n closeModal: function() {\n // don't mutate prop directly, mute the parent\n // this.display = false;\n this.$emit('closed');\n },\n\n setSearchFocus : function() {\n $(this.$el).find('.nav-link.active').find('input').focus();\n },\n\n selectType(t) {\n this.selectedType = t;\n },\n\n addSelectedNode: function(e) {\n switch( this.selectedType ) {\n case \"module\":\n case \"ui\":\n var selectedNode = $('.node-result.selected')[0];\n if( selectedNode ) {\n // add node to the controller\n var packageName = $(selectedNode).data('package');\n this.view.c.addNewBox(packageName, this.mousePosition);\n this.closeModal();\n }\n else {\n swal('Please select a node', '', 'error');\n return;\n }\n break;\n\n case \"input\":\n var type = this.$refs.inputType.get();\n var name = $(this.$el).find('.input-name').val();\n var desc = $(this.$el).find('.input-description').val();\n if( type !== undefined && name ) {\n this.view.c.addInput(name, type, desc, this.mousePosition);\n // reset fields\n this.$refs.inputType.resetChanges();\n $(this.$el).find('.input-name').val(\"\");\n $(this.$el).find('.input-description').val(\"\");\n this.closeModal();\n }\n else {\n swal('Please complete all fields', '', 'error');\n return;\n }\n break;\n\n case \"output\":\n var name = $(this.$el).find('.output-name').val();\n var type = this.$refs.outputType.get();\n var desc = $(this.$el).find('.output-description').val();\n if( type !== undefined && name ) {\n this.view.c.addOutput(name, type, desc, this.mousePosition);\n // reset fields\n this.$refs.outputType.resetChanges();\n $(this.$el).find('.output-name').val(\"\");\n $(this.$el).find('.output-description').val(\"\");\n this.closeModal();\n }\n else {\n swal('Please complete all fields', '', 'error');\n return;\n }\n break;\n\n case \"metanode\":\n var name = $(this.$el).find('.metanode-name').val();\n var desc = $(this.$el).find('.metanode-description').val();\n if( !name ) {\n swal('Please complete name field', '', 'error');\n return;\n }\n\n var json = this.metanodeJSON || {};\n json.description = desc;\n\n this.view.c.addNewMetabox(name, json, this.mousePosition);\n this.closeModal();\n default:\n }\n },\n\n searchModules: async function(e) {\n //var text = $(e.target).val();\n var text = this.searchText[this.selectedType];\n try {\n this.error = null;\n this.results[this.selectedType] = await this.view.e.search(text, this.selectedType);\n this.$forceUpdate();\n }\n catch(e) {\n this.error = e;\n swal('error searching packages', e.reason, \"error\");\n }\n },\n\n getSearchText: function() {\n return this.searchText[this.selectedType] || \"\";\n },\n\n setSelectedResult: function(packageName) {\n // first, find the selected result in the list\n var selectedPackage = null;\n _.each(this.getResults(), (r) => {\n if( r.name == packageName ) {\n selectedPackage = r;\n return false;\n }\n });\n\n if( !selectedPackage ) {\n throw \"Could not find package named \" + packageName;\n }\n\n this.selectedResult[this.selectedType] = selectedPackage;\n this.$forceUpdate();\n },\n\n getSelectedResult: function() {\n return this.selectedResult[this.selectedType];\n },\n\n getResults: function() {\n return this.results[this.selectedType] || null;\n },\n\n getNbResults: function() {\n var results = this.getResults();\n return results && results.length ? results.length: 0;\n },\n\n onMetaboxFileSelect: function(e) {\n var file = e.target.files[0];\n const reader = new FileReader()\n reader.onload = (e) => {\n this.metanodeJSON = JSON.parse(e.target.result);\n if( this.metanodeJSON.description ) {\n $(this.$el).find('.metanode-description').val(this.metanodeJSON.description);\n }\n }\n reader.readAsText(file)\n }\n }\n}\n\n</script>\n\n"]}, media: undefined });
62940
62967
 
62941
62968
  };
62942
62969
  /* scoped */
62943
- const __vue_scope_id__$5 = "data-v-11457554";
62970
+ const __vue_scope_id__$5 = "data-v-b85f4cf4";
62944
62971
  /* module identifier */
62945
62972
  const __vue_module_identifier__$5 = undefined;
62946
62973
  /* functional template */
@@ -64283,8 +64310,22 @@ var script$a = {
64283
64310
  mounted: function() {
64284
64311
  // bind tooltips
64285
64312
  $(this.$el).find('button[data-toggle="tooltip"]').tooltip();
64313
+ this.fixMaxHeightForCategories();
64314
+ },
64315
+ updated: function() {
64316
+ this.fixMaxHeightForCategories();
64286
64317
  },
64287
64318
  methods: {
64319
+ // setup a max height for each menu, so a scroll appears if there's too much item in it
64320
+ fixMaxHeightForCategories : function() {
64321
+ let nbActiveCategories = $(this.$el).find('.edit-body > .card').length;
64322
+ let headerHeight = $(this.$el).find('.edit-body > .card > .card-header').outerHeight();
64323
+ let panelHeight = $(this.$el).height() - $(this.$el).find('.edit-main-presentation').outerHeight();
64324
+ let maxCategoryHeight = panelHeight - nbActiveCategories * headerHeight;
64325
+ $(this.$el).find('.edit-body').css('height', panelHeight);
64326
+ $(this.$el).find('.edit-body > .card > .collapse > .card-body').css('max-height', maxCategoryHeight + "px");
64327
+ },
64328
+
64288
64329
  onEdited: function() {
64289
64330
  this.view.repaint();
64290
64331
  },
@@ -64517,7 +64558,7 @@ var __vue_render__$a = function() {
64517
64558
  [
64518
64559
  _vm._m(0),
64519
64560
  _vm._v(" "),
64520
- _c("div", { staticClass: "edit-body" }, [
64561
+ _c("div", { staticClass: "edit-body h100" }, [
64521
64562
  _c("div", { staticClass: "card" }, [
64522
64563
  _vm._m(1),
64523
64564
  _vm._v(" "),
@@ -65304,6 +65345,7 @@ var __vue_staticRenderFns__$a = [
65304
65345
  return _c(
65305
65346
  "div",
65306
65347
  {
65348
+ staticClass: "edit-main-presentation",
65307
65349
  staticStyle: {
65308
65350
  "padding-left": "10px",
65309
65351
  "padding-top": "10px",
@@ -65311,18 +65353,25 @@ var __vue_staticRenderFns__$a = [
65311
65353
  }
65312
65354
  },
65313
65355
  [
65314
- _c("h2", { staticClass: "edit-dualbox-app" }, [
65315
- _c("div", { staticClass: "dualbox-node-name" }, [
65316
- _c(
65317
- "span",
65318
- {
65319
- staticClass: "text-truncate d-inline-block",
65320
- staticStyle: { width: "290px" }
65321
- },
65322
- [_vm._v("Application")]
65323
- )
65324
- ])
65325
- ])
65356
+ _c(
65357
+ "h2",
65358
+ {
65359
+ staticClass: "edit-dualbox-app",
65360
+ staticStyle: { "margin-bottom": "none" }
65361
+ },
65362
+ [
65363
+ _c("div", { staticClass: "dualbox-node-name" }, [
65364
+ _c(
65365
+ "span",
65366
+ {
65367
+ staticClass: "text-truncate d-inline-block",
65368
+ staticStyle: { width: "290px" }
65369
+ },
65370
+ [_vm._v("Application")]
65371
+ )
65372
+ ])
65373
+ ]
65374
+ )
65326
65375
  ]
65327
65376
  )
65328
65377
  },
@@ -65680,7 +65729,7 @@ __vue_render__$a._withStripped = true;
65680
65729
  /* style */
65681
65730
  const __vue_inject_styles__$a = function (inject) {
65682
65731
  if (!inject) return
65683
- inject("data-v-78348dd6_0", { source: "\n.card-settings .card-body {\n font-size: 12px;\n padding-left: 5px;\n padding-right: 5px;\n}\n.fa {\n pointer-events: none;\n}\n.table-desc {\n width: 100%;\n}\n.table-desc > thead > th > td {\n margin-right: 6px;\n}\n.table-desc > tbody > tr > td {\n margin-right: 6px;\n padding-top: 8px;\n padding-bottom: 8px;\n height: 40px;\n}\n.application-description {\n margin-top: 20px;\n text-align: left;\n font-size: 12px;\n}\n.card-header[data-toggle=\"collapse\"] {\n cursor: pointer;\n}\n.card-header[data-toggle=\"collapse\"] h5 {\n user-select: none;\n}\n.card-header[data-toggle=\"collapse\"]:hover .btn-link {\n text-decoration: none;\n}\n.text-value, .number-value, .boolean-value {\n max-width: 140px;\n}\n.select-event-target, .select-event-name, .event-if, .event-data {\n font-size: 12px;\n}\n.edit-body {\n overflow-y: auto;\n overflow-x: hidden;\n max-height: calc(100% - 80px);\n}\n\n/* remove bs4 transition on collapsing */\n.edit-main-panel .collapsing {\n -webkit-transition: none!important;\n transition: none!important;\n display: none!important;\n}\n.table-events .event-rooting {\n margin-top: 10px;\n}\n.table-events thead {\n border-bottom: 1px solid #ddd;\n}\n.table-events .tr-event-condition td {\n padding-left: 10px;\n}\n.table-events .tr-event-data td {\n padding-left: 10px;\n}\n.tr-event-condition td, .tr-event-data td {\n height: 20px!important;\n}\n.tr-event-condition, .tr-event-condition td, .tr-event-data, .tr-event-data td {\n padding-top: 1px!important;\n padding-bottom: 1px!important;\n}\n.table-events tr + .event-rooting {\n /* border-top: 1px solid #ddd; */\n}\n.event-rooting td {\n padding-top: 8px!important;\n padding-bottom: 4px!important;\n}\n.event-data-type {\n font-size: 75%;\n border-radius: 5px;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n}\n.event-data-display {\n font-size: 75%;\n border-radius: 5px;\n border: 1px solid #ddd;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n}\n.event-if {\n font-size: 75%;\n border-radius: 5px;\n border: 1px solid #ddd;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n}\ni.fa, i.fas, i.far {\n pointer-events: none;\n}\n\n", map: {"version":3,"sources":["/home/seb/dev/dualbox/editor/js/src/v/templates/editMainSettings.vue"],"names":[],"mappings":";AACA;IACA,eAAA;IACA,iBAAA;IACA,kBAAA;AACA;AAEA;IACA,oBAAA;AACA;AAEA;IACA,WAAA;AACA;AAEA;IACA,iBAAA;AACA;AAEA;IACA,iBAAA;IACA,gBAAA;IACA,mBAAA;IACA,YAAA;AACA;AAEA;IACA,gBAAA;IACA,gBAAA;IACA,eAAA;AACA;AAEA;IACA,eAAA;AACA;AAEA;IACA,iBAAA;AACA;AAEA;IACA,qBAAA;AACA;AAEA;IACA,gBAAA;AACA;AAEA;IACA,eAAA;AACA;AAEA;IACA,gBAAA;IACA,kBAAA;IACA,6BAAA;AACA;;AAEA,wCAAA;AACA;IACA,kCAAA;IACA,0BAAA;IACA,uBAAA;AACA;AAEA;IACA,gBAAA;AACA;AAEA;IACA,6BAAA;AACA;AAEA;IACA,kBAAA;AACA;AAEA;IACA,kBAAA;AACA;AAEA;IACA,sBAAA;AACA;AAEA;IACA,0BAAA;IACA,6BAAA;AACA;AAEA;IACA,gCAAA;AACA;AAEA;IACA,0BAAA;IACA,6BAAA;AACA;AAEA;IACA,cAAA;IACA,kBAAA;IACA,iBAAA;IACA,kBAAA;IACA,gBAAA;IACA,mBAAA;AACA;AAEA;IACA,cAAA;IACA,kBAAA;IACA,sBAAA;IACA,iBAAA;IACA,kBAAA;IACA,gBAAA;IACA,mBAAA;AACA;AAEA;IACA,cAAA;IACA,kBAAA;IACA,sBAAA;IACA,iBAAA;IACA,kBAAA;IACA,gBAAA;IACA,mBAAA;AACA;AAEA;IACA,oBAAA;AACA","file":"editMainSettings.vue","sourcesContent":["<style>\n.card-settings .card-body {\n font-size: 12px;\n padding-left: 5px;\n padding-right: 5px;\n}\n\n.fa {\n pointer-events: none;\n}\n\n.table-desc {\n width: 100%;\n}\n\n.table-desc > thead > th > td {\n margin-right: 6px;\n}\n\n.table-desc > tbody > tr > td {\n margin-right: 6px;\n padding-top: 8px;\n padding-bottom: 8px;\n height: 40px;\n}\n\n.application-description {\n margin-top: 20px;\n text-align: left;\n font-size: 12px;\n}\n\n.card-header[data-toggle=\"collapse\"] {\n cursor: pointer;\n}\n\n.card-header[data-toggle=\"collapse\"] h5 {\n user-select: none;\n}\n\n.card-header[data-toggle=\"collapse\"]:hover .btn-link {\n text-decoration: none;\n}\n\n.text-value, .number-value, .boolean-value {\n max-width: 140px;\n}\n\n.select-event-target, .select-event-name, .event-if, .event-data {\n font-size: 12px;\n}\n\n.edit-body {\n overflow-y: auto;\n overflow-x: hidden;\n max-height: calc(100% - 80px);\n}\n\n/* remove bs4 transition on collapsing */\n.edit-main-panel .collapsing {\n -webkit-transition: none!important;\n transition: none!important;\n display: none!important;\n}\n\n.table-events .event-rooting {\n margin-top: 10px;\n}\n\n.table-events thead {\n border-bottom: 1px solid #ddd;\n}\n\n.table-events .tr-event-condition td {\n padding-left: 10px;\n}\n\n.table-events .tr-event-data td {\n padding-left: 10px;\n}\n\n.tr-event-condition td, .tr-event-data td {\n height: 20px!important;\n}\n\n.tr-event-condition, .tr-event-condition td, .tr-event-data, .tr-event-data td {\n padding-top: 1px!important;\n padding-bottom: 1px!important;\n}\n\n.table-events tr + .event-rooting {\n /* border-top: 1px solid #ddd; */\n}\n\n.event-rooting td {\n padding-top: 8px!important;\n padding-bottom: 4px!important;\n}\n\n.event-data-type {\n font-size: 75%;\n border-radius: 5px;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n}\n\n.event-data-display {\n font-size: 75%;\n border-radius: 5px;\n border: 1px solid #ddd;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n}\n\n.event-if {\n font-size: 75%;\n border-radius: 5px;\n border: 1px solid #ddd;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n}\n\ni.fa, i.fas, i.far {\n pointer-events: none;\n}\n\n</style>\n\n<template>\n\n<div class=\"edit-main-panel h100\" id=\"edit-main-panel\">\n <div style=\"padding-left: 10px; padding-top: 10px; padding-right: 10px;\">\n <h2 class=\"edit-dualbox-app\">\n <div class=\"dualbox-node-name\">\n <span class=\"text-truncate d-inline-block\" style=\"width: 290px\">Application</span>\n </div>\n </h2>\n </div>\n\n <div class=\"edit-body\">\n <div class=\"card\">\n <div class=\"card-header\" id=\"dualbox-main-desc\" data-toggle=\"collapse\" data-target=\"#dualbox-main-desc-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-main-desc-collapse\">\n <h5 class=\"mb-0 btn-link\">Description</h5>\n </div>\n\n <div id=\"dualbox-main-desc-collapse\" class=\"collapse show\" aria-labelledby=\"dualbox-main-desc\" data-parent=\"#edit-main-panel\">\n <div class=\"card-body\">\n <p class=\"application-description\">{{ app.getDescription() || \"[No description available]\" }} <button class=\"btn btn-editor-xs btn-light btn-edit-app-description\" @click=\"editAppDescription\"><i class=\"fa fa-edit\"></i></button></p>\n </div>\n </div>\n </div>\n <div class=\"card\">\n <div class=\"card-header\" id=\"dualbox-main-events\" data-toggle=\"collapse\" data-target=\"#dualbox-main-events-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-main-events-collapse\">\n <h5 class=\"mb-0 btn-link\">Events</h5>\n </div>\n\n <div id=\"dualbox-main-events-collapse\" class=\"collapse\" aria-labelledby=\"dualbox-main-events\" data-parent=\"#edit-main-panel\">\n <div class=\"card-body\" style=\"padding-left: 4px; padding-right: 4px;\">\n <button class=\"btn btn-success btn-add-app-event mb-3\" @click=\"addAppEvent\">Add application event</button>\n <div v-for=\"key in app.getEventsNames()\" class=\"card\" :key=\"'app-event-' + key\">\n <div class=\"card-header\" :id=\"'dualbox-event-' + key\" data-toggle=\"collapse\" :data-target=\"'#dualbox-event-' + key + '-collapse'\" aria-expanded=\"false\" aria-controls=\"'dualbox-event-' + key + '-collapse'\">\n <h5 class=\"mb-0 btn-link\" style=\"font-size: 16px; font-weight: normal;\">\n {{key}}\n <div class=\"float-right d-inline-block\">\n <button class=\"btn btn-light btn-editor-xs btn-rename-app-event\" :data-event=\"key\" @click=\"renameAppEvent\">\n <i class=\"fa fa-edit\"></i>\n </button>\n <button class=\"btn btn-danger btn-editor-xs btn-remove-app-event\" :data-event=\"key\" @click=\"removeAppEvent\">\n <i class=\"fa fa-minus\"></i>\n </button>\n </div>\n </h5>\n </div>\n\n <div :id=\"'dualbox-event-'+ key + '-collapse'\" class=\"collapse\" :aria-labelledby=\"'dualbox-event-' + key\" data-parent=\"#dualbox-main-events\">\n <div class=\"card-body\" style=\"padding-left: 4px; padding-right: 4px;\">\n <h5 style=\"font-size: 16px; text-decoration: underline; font-weight: normal;\">Description</h5>\n <p>{{ app.getEventDescription(key) || \"[no description available]\" }} <button class=\"btn btn-editor-xs btn-light btn-edit-event-description\" :data-event=\"key\" @click=\"editEventDescription\"><i class=\"fa fa-edit\"></i></button></p>\n <h5 class=\"mt-3\" style=\"font-size: 16px; text-decoration: underline; font-weight: normal;\">Triggers</h5>\n\n <table class=\"table-events table-desc\" style=\"font-size: 12px!important;\">\n <thead class=\"thead-dark\">\n <th>Target</th>\n <th>Event</th>\n <!--<th>If</th>-->\n <!--<th>Data</th>-->\n <th>Action</th>\n </thead>\n <tbody>\n <template v-for=\"(evt,index) in app.getEventIn(key)\" :data-index=\"index\">\n <tr class=\"event-rooting\">\n <td>\n <select v-if=\"evt.node !== undefined\" class=\"form-control form-control-sm select-event-target\" dualbox-target=\"events-in\" :data-event=\"key\" :data-index=\"index\" @change=\"selectEventTarget\">\n <option v-for=\"node in getNodesWithInEvents()\" :value=\"node.getGraphId()\" :selected=\"node.getGraphId()==evt.node\" :key=\"'event-in-target-' + node.getGraphId()\">{{node.getGraphId()}}</option>\n </select>\n <span v-else>{{evt.selector}}</span>\n </td>\n <td>\n <select class=\"form-control form-control-sm select-event-name\" dualbox-target=\"events-in\" :data-event=\"key\" :data-index=\"index\" @change=\"selectEventName\" >\n <template v-if=\"evt.node\">\n <option v-for=\"te in getNodeInEvents(evt.node)\" :value=\"te\" :selected=\"te == evt.event\" :key=\"'app-event-in-target-' + evt.node + '-' + te\">{{te}}</option>\n </template>\n <template v-else>\n <option value=\"hide\">hide</option>\n <option value=\"show\">show</option>\n </template>\n </select>\n </td>\n <td style=\"min-width: 58px;\">\n <button class=\"btn btn-secondary btn-editor-xs\" :data-event=\"key\" :data-index=\"index\" @click=\"toggleAdvancedAppEventSettings\" style=\"margin-left: 10px;\" title=\"Toggle advanced event settings\" >\n <i class=\"fas fa-cog\"></i>\n </button>\n <button class=\"btn btn-danger btn-editor-xs\" :data-event=\"key\" :data-index=\"index\" @click=\"removeInEvent\" >\n <i class=\"fas fa-minus\"></i>\n </button>\n </td>\n </tr>\n <tr v-if=\"evt.if || expanded[key+'##'+index]\" class=\"tr-event-condition\">\n <td colspan=\"3\">\n <span style=\"width: 60px; display: inline-block;\"><i class=\"fas fa-caret-right\"></i> Occur if:</span>\n\n <input style=\"max-width: 340px; width: 340px;\" class=\"form-control form-control-sm event-if d-inline-block\" type=\"text\" dualbox-target=\"events-in\" :data-event=\"key\" :data-index=\"index\" :value=\"evt.if\" @change=\"setEventIf\" />\n </td>\n </tr>\n <tr v-if=\"evt.data || evt.datatype || expanded[key+'##'+index]\" class=\"tr-event-data\" colspan=\"3\">\n <td colspan=\"3\">\n <span style=\"width: 53px; display: inline-block;\"><i class=\"fas fa-caret-right\"></i> Data:</span>\n <span style=\"width: 350px;\">\n <display-type :type=\"getDataType(evt)\" @edited=\"onEditEventInDataType(key, index, $event)\"></display-type>\n <display-value :v=\"evt.data\" :type=\"getDataType(evt)\" @edited=\"onEditEventInData(key, index, $event)\"></display-value>\n </span>\n </td>\n </tr>\n </template>\n <tr>\n <td colspan=\"5\" style=\"padding-top: 0px; padding-bottom: 0px;\">\n <button class=\"btn btn-sm btn-add-subevent\" style=\"width: 100%;\" @click=\"addSubEvent(key)\">Add a subevent</button>\n </td>\n </tr>\n </tbody>\n </table>\n\n <h5 class=\"mt-3\" style=\"font-size: 16px; text-decoration: underline; font-weight: normal;\">Callback</h5>\n\n <table class=\"table-desc table-striped\" style=\"font-size: 12px!important;\">\n <thead class=\"thead-dark\">\n <th>Target</th>\n <th>Event</th>\n <th>Action</th>\n </thead>\n <tbody>\n <tr v-if=\"app.getEventOut(key) !== undefined\">\n <td>\n <select class=\"form-control form-control-sm select-event-target select-callback-target\" dualbox-target=\"events-out\" @change=\"setCallback(key)\">\n <option v-for=\"node in getNodesWithOutEvents()\" :value=\"node.getGraphId()\" :selected=\"node.getGraphId()===app.getEventOut(key).node\" :key=\"'app-event-out-target-' + node.getGraphId()\">{{ node.getGraphId() }}</option>\n </select>\n </td>\n <td>\n <select class=\"form-control form-control-sm select-event-name select-callback-event\" dualbox-target=\"events-out\">\n <template v-if=\"app.getEventOut(key).node\" @change=\"setCallback(key)\">\n <option v-for=\"(te, index) in getNodeOutEvents(app.getEventOut(key).node)\" :value=\"te\" :selected=\"te == app.getEventOut(key).event\" :key=\"'app-event-out-' + index\">{{te}}</option>\n </template>\n </select>\n </td>\n <td>\n <button class=\"btn btn-danger btn-editor-xs btn-remove-out-event\" :data-event=\"key\" @click=\"removeOutEvent\">\n <i class=\"fa fa-minus\"></i>\n </button>\n </td>\n </tr>\n <tr v-else>\n <td colspan=\"3\" style=\"padding-top: 0px; padding-bottom: 0px;\">\n <button class=\"btn btn-sm btn-add-callback\" style=\"width: 100%;\" @click=\"addCallback(key)\">Add a callback</button>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"modal edit-value-modal\" tabindex=\"-1\" role=\"dialog\">\n <div class=\"modal-dialog\" role=\"document\">\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <h5 class=\"modal-title\">Edit value</h5>\n <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">\n <span aria-hidden=\"true\">&times;</span>\n </button>\n </div>\n <div class=\"modal-body\">\n <div>\n <div class=\"form-check\">\n <input type=\"radio\" class=\"form-check-input set-value unset-value\" id=\"unset-value\" name=\"set-value\" value=\"unset-value\" checked>\n <label class=\"form-check-label\" for=\"unset-value\">\n don't set a value\n </label>\n </div>\n <div class=\"form-check\">\n <input type=\"radio\" class=\"form-check-input set-value set-value-null\" id=\"set-value-null\" name=\"set-value\" value=\"set-value-null\">\n <label class=\"form-check-label\" for=\"set-value-null\">\n set null\n </label>\n </div>\n <div class=\"form-check\">\n <input type=\"radio\" class=\"form-check-input set-value set-value-type\" id=\"set-value-type\" name=\"set-value\" value=\"set-value-type\" aria-label=\"Set a value of type\">\n <div class=\"form-inline form-check-label\" style=\"height: 24px;\">\n <label for=\"set-value-type\">\n set a value of type:\n <select class=\"form-control choose-value-type d-inline-block form-control-sm ml-2\">\n <option value=\"string\">String</option>\n <option value=\"number\">Number</option>\n <option value=\"boolean\">Boolean</option>\n <option value=\"object\">Object</option>\n </select>\n </label>\n </div>\n </div>\n </div>\n <div class=\"has-value\" style=\"display: none;\">\n <hr/>\n <div class=\"define-value define-boolean\" style=\"display: none;\">\n <div class=\"form-inline\">\n <label>Value: </label>\n <select class=\"form-control form-control-sm bool-value d-inline-block ml-2\">\n <option value=true>True</option>\n <option value=false>False</option>\n </select>\n </div>\n </div>\n <div class=\"define-value define-number\" style=\"display: none;\">\n <div class=\"form-inline\">\n <label>Value: </label>\n <input type=\"number\" class=\"form-control form-control-sm number-value ml-2\"/>\n </div>\n </div>\n <div class=\"define-value define-string\" style=\"display: none;\">\n <div class=\"form-inline\">\n <label>Value: </label>\n <input type=\"text\" class=\"form-control form-control-sm text-value ml-2\"/>\n </div>\n </div>\n <div class=\"define-value define-object\" style=\"display: none;\">\n <label>Value: </label>\n <div class=\"json-editor\" style=\"height: 400px;\"></div>\n </div>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\" class=\"btn btn-primary btn-save\">Save changes</button>\n <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">Close</button>\n </div>\n </div>\n </div>\n </div>\n</div>\n\n</template>\n\n<script>\nimport _ from 'lodash';\nimport swal from 'sweetalert2';\nimport DisplayTypeVue from './displayType.vue';\nimport DisplayValueVue from './displayValue.vue';\n\nexport default {\n props: [\n \"app\"\n ],\n components: {\n \"display-type\" : DisplayTypeVue,\n \"display-value\" : DisplayValueVue,\n },\n data: function () {\n return {\n expanded: {} // expanded app events (advanced settings)\n };\n },\n created: function() {\n this.view = window.dualboxEditor.v;\n },\n mounted: function() {\n // bind tooltips\n $(this.$el).find('button[data-toggle=\"tooltip\"]').tooltip();\n },\n methods: {\n onEdited: function() {\n this.view.repaint();\n },\n\n getNodesWithInEvents: function() {\n var l = [];\n var nodes = this.view.m.getNodes(\"ui\");\n _.each(nodes, (n) => {\n if( n.getInEventsNames().length > 0 ) {\n l.push(n);\n }\n });\n return l;\n },\n\n getNodesWithOutEvents: function() {\n var l = [];\n var nodes = this.view.m.getNodes(\"ui\");\n _.each(nodes, (n) => {\n if( n.getOutEventsNames().length > 0 ) {\n l.push(n);\n }\n });\n return l;\n },\n\n getNodeEvents: function( nodeId ) {\n var node = this.view.m.getNode(nodeId);\n return node.getEventsNames();\n },\n\n getNodeInEvents: function( nodeId ) {\n var node = this.view.m.getNode(nodeId);\n return node.getInEventsNames();\n },\n\n getNodeOutEvents: function( nodeId ) {\n var node = this.view.m.getNode(nodeId);\n return node.getOutEventsNames();\n },\n\n editAppDescription: function() {\n swal({\n input: 'text',\n title: 'Enter the description',\n }).then((result) => {\n this.view.c.setAppDescription(result.value);\n });\n },\n\n editEventDescription: function(e) {\n var eventName = $(e.target).attr('data-event');\n\n swal({\n input: 'text',\n title: 'Enter the description',\n }).then((result) => {\n this.view.c.setAppEventDescription(eventName, result.value);\n });\n },\n\n removeAppEvent: function(e) {\n var name = $(e.target).attr('data-event');\n this.view.c.removeAppEvent(name);\n this.onEdited();\n },\n\n renameAppEvent: function(e) {\n var name = $(e.target).attr('data-event');\n swal({\n input: 'text',\n title: 'Enter the new event name',\n }).then((result) => {\n if( result.value ) {\n this.view.c.renameAppEvent(name, result.value);\n this.onEdited();\n }\n });\n },\n\n setEventIf: function(e) {\n var index = parseInt($(e.target).attr('data-index'));\n var val = $(e.target).val();\n this.view.c.setEventIf( \"#application-\" + $(e.target).attr('dualbox-target') + '-' + $(e.target).attr('data-event'), index, val);\n this.onEdited();\n },\n\n setEventData: function(e) {\n var index = parseInt($(e.target).attr('data-index'));\n var val = $(e.target).val();\n this.view.c.setEventData( \"#application-\" + $(e.target).attr('dualbox-target') + '-' + $(e.target).attr('data-event'), index, val);\n this.onEdited();\n },\n\n selectEventTarget: function(e) {\n var target = $(e.target).val();\n\n // change options of closest .select-event-name according to this new target\n var targetNode = this.view.m.getNode(target);\n var targetEvents = targetNode.getEventsNames();\n var select = $(e.target).closest('tr').find('.select-event-name');\n select.html('');\n _.each(targetEvents, (eventName) => {\n select.append( $('<option/>', {\n value: eventName\n }).append(eventName));\n });\n\n var index = parseInt($(e.target).attr('data-index'));\n this.view.c.setEventTarget( \"#application-\" + $(e.target).attr('dualbox-target') + '-' + $(e.target).attr('data-event'), index, target);\n this.onEdited();\n },\n\n selectEventName: function(e) {\n var index = parseInt($(e.target).attr('data-index'));\n var val = $(e.target).val();\n this.view.c.setEventName( \"#application-\" + $(e.target).attr('dualbox-target') + '-' + $(e.target).attr('data-event'), index, val );\n this.onEdited();\n },\n\n addCallback: function(appEventName) {\n var nodesWithOutEvents = this.getNodesWithOutEvents();\n if( nodesWithOutEvents.length > 0 ) {\n var firstNode = nodesWithOutEvents[0];\n var firstEvent = firstNode.getOutEventsNames()[0];\n this.setCallback(appEventName, firstNode, firstEvent);\n }\n else {\n swal({\n title: \"You can not add an API callback here\",\n text: \"None of the UIs of the application does have an OUT event, usable for API callbacks\",\n type: \"error\"\n })\n }\n },\n\n setCallback: function(appEventName, e) {\n var targetNodeId = $(this.$el).find('.select-callback-target').val();\n var targetNodeEvent = $(this.$el).find('.select-callback-event').val();\n this.view.c.setCallback(appEventName, targetNodeId, targetNodeEvent);\n this.onEdited();\n },\n\n addAppEvent: function(e) {\n swal({\n input: 'text',\n title: 'Enter the event name',\n }).then((result) => {\n this.view.c.addAppEvent(result.value);\n this.onEdited();\n });\n },\n\n removeInEvent: function(e) {\n var eventName = $(e.target).attr('data-event');\n var index = parseInt($(e.target).attr('data-index'));\n this.view.c.removeAppInEvent(eventName, index);\n this.onEdited();\n },\n\n removeOutEvent: function(e) {\n var eventName = $(e.target).attr('data-event');\n this.view.c.removeAppOutEvent(eventName);\n this.onEdited();\n },\n\n addSubEvent: function(eventName) {\n this.view.c.addSubEvent(eventName);\n this.onEdited();\n },\n\n getDataType: function(evt) {\n if( evt.datatype ) {\n return evt.datatype;\n }\n else if( evt.data ) {\n return window.DualBox.Type.detectType(evt.data);\n }\n else {\n return undefined;\n }\n },\n\n toggleAdvancedAppEventSettings: function(e) {\n var key = $(e.target).data('event');\n var index = $(e.target).data('index');\n var k=key+'##'+index;\n this.expanded[k] = this.expanded[k] ? false : true;\n this.$forceUpdate();\n },\n\n onEditEventInData(key, index, val) {\n this.view.c.setEventData( \"#application-events-in-\" + key, index, val);\n this.$emit('edited');\n },\n\n onEditEventInDataType(key, index, type) {\n this.view.c.setEventDataType( \"#application-events-in-\" + key, index, type);\n\n // check that the set value still match the new type\n // delete it otherwise\n var val = this.app.getEventIn(key)[index].data;\n try {\n // TODO: ensure type is already loaded (after dualbox) and remove the try/catch\n if( !window.DualBox.Type.check(type, val) ) {\n // delete data (== set undefined)\n this.view.c.setEventData( \"#application-events-in-\" + key, index, undefined);\n }\n }\n catch(e) {\n this.view.c.setEventData( \"#application-events-in-\" + key, index, undefined);\n }\n\n this.$emit('edited');\n },\n }\n}\n</script>\n"]}, media: undefined });
65732
+ inject("data-v-bdaa381a_0", { source: "\n.card-settings .card-body {\n font-size: 12px;\n padding-left: 5px;\n padding-right: 5px;\n}\n.fa {\n pointer-events: none;\n}\n.table-desc {\n width: 100%;\n}\n.table-desc > thead > th > td {\n margin-right: 6px;\n}\n.table-desc > tbody > tr > td {\n margin-right: 6px;\n padding-top: 8px;\n padding-bottom: 8px;\n height: 40px;\n}\n.application-description {\n margin-top: 20px;\n text-align: left;\n font-size: 12px;\n}\n.card-header[data-toggle=\"collapse\"] {\n cursor: pointer;\n}\n.card-header[data-toggle=\"collapse\"] h5 {\n user-select: none;\n}\n.card-header[data-toggle=\"collapse\"]:hover .btn-link {\n text-decoration: none;\n}\n.text-value, .number-value, .boolean-value {\n max-width: 140px;\n}\n.select-event-target, .select-event-name, .event-if, .event-data {\n font-size: 12px;\n}\n.edit-body {\n overflow-y: hidden;\n overflow-x: hidden;\n max-height: calc(100% - 90px);\n}\n\n/* remove bs4 transition on collapsing */\n.edit-main-panel .collapsing {\n -webkit-transition: none!important;\n transition: none!important;\n display: none!important;\n}\n.table-events .event-rooting {\n margin-top: 10px;\n}\n.table-events thead {\n border-bottom: 1px solid #ddd;\n}\n.table-events .tr-event-condition td {\n padding-left: 10px;\n}\n.table-events .tr-event-data td {\n padding-left: 10px;\n}\n.tr-event-condition td, .tr-event-data td {\n height: 20px!important;\n}\n.tr-event-condition, .tr-event-condition td, .tr-event-data, .tr-event-data td {\n padding-top: 1px!important;\n padding-bottom: 1px!important;\n}\n.table-events tr + .event-rooting {\n /* border-top: 1px solid #ddd; */\n}\n.event-rooting td {\n padding-top: 8px!important;\n padding-bottom: 4px!important;\n}\n.event-data-type {\n font-size: 75%;\n border-radius: 5px;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n}\n.event-data-display {\n font-size: 75%;\n border-radius: 5px;\n border: 1px solid #ddd;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n}\n.event-if {\n font-size: 75%;\n border-radius: 5px;\n border: 1px solid #ddd;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n}\ni.fa, i.fas, i.far {\n pointer-events: none;\n}\n.h100 {\n height: 100%;\n}\n\n", map: {"version":3,"sources":["/home/seb/dev/dualbox/editor/js/src/v/templates/editMainSettings.vue"],"names":[],"mappings":";AACA;IACA,eAAA;IACA,iBAAA;IACA,kBAAA;AACA;AAEA;IACA,oBAAA;AACA;AAEA;IACA,WAAA;AACA;AAEA;IACA,iBAAA;AACA;AAEA;IACA,iBAAA;IACA,gBAAA;IACA,mBAAA;IACA,YAAA;AACA;AAEA;IACA,gBAAA;IACA,gBAAA;IACA,eAAA;AACA;AAEA;IACA,eAAA;AACA;AAEA;IACA,iBAAA;AACA;AAEA;IACA,qBAAA;AACA;AAEA;IACA,gBAAA;AACA;AAEA;IACA,eAAA;AACA;AAEA;IACA,kBAAA;IACA,kBAAA;IACA,6BAAA;AACA;;AAEA,wCAAA;AACA;IACA,kCAAA;IACA,0BAAA;IACA,uBAAA;AACA;AAEA;IACA,gBAAA;AACA;AAEA;IACA,6BAAA;AACA;AAEA;IACA,kBAAA;AACA;AAEA;IACA,kBAAA;AACA;AAEA;IACA,sBAAA;AACA;AAEA;IACA,0BAAA;IACA,6BAAA;AACA;AAEA;IACA,gCAAA;AACA;AAEA;IACA,0BAAA;IACA,6BAAA;AACA;AAEA;IACA,cAAA;IACA,kBAAA;IACA,iBAAA;IACA,kBAAA;IACA,gBAAA;IACA,mBAAA;AACA;AAEA;IACA,cAAA;IACA,kBAAA;IACA,sBAAA;IACA,iBAAA;IACA,kBAAA;IACA,gBAAA;IACA,mBAAA;AACA;AAEA;IACA,cAAA;IACA,kBAAA;IACA,sBAAA;IACA,iBAAA;IACA,kBAAA;IACA,gBAAA;IACA,mBAAA;AACA;AAEA;IACA,oBAAA;AACA;AAEA;IACA,YAAA;AACA","file":"editMainSettings.vue","sourcesContent":["<style>\n.card-settings .card-body {\n font-size: 12px;\n padding-left: 5px;\n padding-right: 5px;\n}\n\n.fa {\n pointer-events: none;\n}\n\n.table-desc {\n width: 100%;\n}\n\n.table-desc > thead > th > td {\n margin-right: 6px;\n}\n\n.table-desc > tbody > tr > td {\n margin-right: 6px;\n padding-top: 8px;\n padding-bottom: 8px;\n height: 40px;\n}\n\n.application-description {\n margin-top: 20px;\n text-align: left;\n font-size: 12px;\n}\n\n.card-header[data-toggle=\"collapse\"] {\n cursor: pointer;\n}\n\n.card-header[data-toggle=\"collapse\"] h5 {\n user-select: none;\n}\n\n.card-header[data-toggle=\"collapse\"]:hover .btn-link {\n text-decoration: none;\n}\n\n.text-value, .number-value, .boolean-value {\n max-width: 140px;\n}\n\n.select-event-target, .select-event-name, .event-if, .event-data {\n font-size: 12px;\n}\n\n.edit-body {\n overflow-y: hidden;\n overflow-x: hidden;\n max-height: calc(100% - 90px);\n}\n\n/* remove bs4 transition on collapsing */\n.edit-main-panel .collapsing {\n -webkit-transition: none!important;\n transition: none!important;\n display: none!important;\n}\n\n.table-events .event-rooting {\n margin-top: 10px;\n}\n\n.table-events thead {\n border-bottom: 1px solid #ddd;\n}\n\n.table-events .tr-event-condition td {\n padding-left: 10px;\n}\n\n.table-events .tr-event-data td {\n padding-left: 10px;\n}\n\n.tr-event-condition td, .tr-event-data td {\n height: 20px!important;\n}\n\n.tr-event-condition, .tr-event-condition td, .tr-event-data, .tr-event-data td {\n padding-top: 1px!important;\n padding-bottom: 1px!important;\n}\n\n.table-events tr + .event-rooting {\n /* border-top: 1px solid #ddd; */\n}\n\n.event-rooting td {\n padding-top: 8px!important;\n padding-bottom: 4px!important;\n}\n\n.event-data-type {\n font-size: 75%;\n border-radius: 5px;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n}\n\n.event-data-display {\n font-size: 75%;\n border-radius: 5px;\n border: 1px solid #ddd;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n}\n\n.event-if {\n font-size: 75%;\n border-radius: 5px;\n border: 1px solid #ddd;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n}\n\ni.fa, i.fas, i.far {\n pointer-events: none;\n}\n\n.h100 {\n height: 100%;\n}\n\n</style>\n\n<template>\n\n<div class=\"edit-main-panel h100\" id=\"edit-main-panel\">\n <div class=\"edit-main-presentation\" style=\"padding-left: 10px; padding-top: 10px; padding-right: 10px; padding-bottom 10px;\">\n <h2 class=\"edit-dualbox-app\" style=\"margin-bottom: none;\">\n <div class=\"dualbox-node-name\">\n <span class=\"text-truncate d-inline-block\" style=\"width: 290px\">Application</span>\n </div>\n </h2>\n </div>\n\n <div class=\"edit-body h100\">\n <div class=\"card\">\n <div class=\"card-header\" id=\"dualbox-main-desc\" data-toggle=\"collapse\" data-target=\"#dualbox-main-desc-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-main-desc-collapse\">\n <h5 class=\"mb-0 btn-link\">Description</h5>\n </div>\n\n <div id=\"dualbox-main-desc-collapse\" class=\"collapse show\" aria-labelledby=\"dualbox-main-desc\" data-parent=\"#edit-main-panel\">\n <div class=\"card-body\">\n <p class=\"application-description\">{{ app.getDescription() || \"[No description available]\" }} <button class=\"btn btn-editor-xs btn-light btn-edit-app-description\" @click=\"editAppDescription\"><i class=\"fa fa-edit\"></i></button></p>\n </div>\n </div>\n </div>\n <div class=\"card\">\n <div class=\"card-header\" id=\"dualbox-main-events\" data-toggle=\"collapse\" data-target=\"#dualbox-main-events-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-main-events-collapse\">\n <h5 class=\"mb-0 btn-link\">Events</h5>\n </div>\n\n <div id=\"dualbox-main-events-collapse\" class=\"collapse\" aria-labelledby=\"dualbox-main-events\" data-parent=\"#edit-main-panel\">\n <div class=\"card-body\" style=\"padding-left: 4px; padding-right: 4px;\">\n <button class=\"btn btn-success btn-add-app-event mb-3\" @click=\"addAppEvent\">Add application event</button>\n <div v-for=\"key in app.getEventsNames()\" class=\"card\" :key=\"'app-event-' + key\">\n <div class=\"card-header\" :id=\"'dualbox-event-' + key\" data-toggle=\"collapse\" :data-target=\"'#dualbox-event-' + key + '-collapse'\" aria-expanded=\"false\" aria-controls=\"'dualbox-event-' + key + '-collapse'\">\n <h5 class=\"mb-0 btn-link\" style=\"font-size: 16px; font-weight: normal;\">\n {{key}}\n <div class=\"float-right d-inline-block\">\n <button class=\"btn btn-light btn-editor-xs btn-rename-app-event\" :data-event=\"key\" @click=\"renameAppEvent\">\n <i class=\"fa fa-edit\"></i>\n </button>\n <button class=\"btn btn-danger btn-editor-xs btn-remove-app-event\" :data-event=\"key\" @click=\"removeAppEvent\">\n <i class=\"fa fa-minus\"></i>\n </button>\n </div>\n </h5>\n </div>\n\n <div :id=\"'dualbox-event-'+ key + '-collapse'\" class=\"collapse\" :aria-labelledby=\"'dualbox-event-' + key\" data-parent=\"#dualbox-main-events\">\n <div class=\"card-body\" style=\"padding-left: 4px; padding-right: 4px;\">\n <h5 style=\"font-size: 16px; text-decoration: underline; font-weight: normal;\">Description</h5>\n <p>{{ app.getEventDescription(key) || \"[no description available]\" }} <button class=\"btn btn-editor-xs btn-light btn-edit-event-description\" :data-event=\"key\" @click=\"editEventDescription\"><i class=\"fa fa-edit\"></i></button></p>\n <h5 class=\"mt-3\" style=\"font-size: 16px; text-decoration: underline; font-weight: normal;\">Triggers</h5>\n\n <table class=\"table-events table-desc\" style=\"font-size: 12px!important;\">\n <thead class=\"thead-dark\">\n <th>Target</th>\n <th>Event</th>\n <!--<th>If</th>-->\n <!--<th>Data</th>-->\n <th>Action</th>\n </thead>\n <tbody>\n <template v-for=\"(evt,index) in app.getEventIn(key)\" :data-index=\"index\">\n <tr class=\"event-rooting\">\n <td>\n <select v-if=\"evt.node !== undefined\" class=\"form-control form-control-sm select-event-target\" dualbox-target=\"events-in\" :data-event=\"key\" :data-index=\"index\" @change=\"selectEventTarget\">\n <option v-for=\"node in getNodesWithInEvents()\" :value=\"node.getGraphId()\" :selected=\"node.getGraphId()==evt.node\" :key=\"'event-in-target-' + node.getGraphId()\">{{node.getGraphId()}}</option>\n </select>\n <span v-else>{{evt.selector}}</span>\n </td>\n <td>\n <select class=\"form-control form-control-sm select-event-name\" dualbox-target=\"events-in\" :data-event=\"key\" :data-index=\"index\" @change=\"selectEventName\" >\n <template v-if=\"evt.node\">\n <option v-for=\"te in getNodeInEvents(evt.node)\" :value=\"te\" :selected=\"te == evt.event\" :key=\"'app-event-in-target-' + evt.node + '-' + te\">{{te}}</option>\n </template>\n <template v-else>\n <option value=\"hide\">hide</option>\n <option value=\"show\">show</option>\n </template>\n </select>\n </td>\n <td style=\"min-width: 58px;\">\n <button class=\"btn btn-secondary btn-editor-xs\" :data-event=\"key\" :data-index=\"index\" @click=\"toggleAdvancedAppEventSettings\" style=\"margin-left: 10px;\" title=\"Toggle advanced event settings\" >\n <i class=\"fas fa-cog\"></i>\n </button>\n <button class=\"btn btn-danger btn-editor-xs\" :data-event=\"key\" :data-index=\"index\" @click=\"removeInEvent\" >\n <i class=\"fas fa-minus\"></i>\n </button>\n </td>\n </tr>\n <tr v-if=\"evt.if || expanded[key+'##'+index]\" class=\"tr-event-condition\">\n <td colspan=\"3\">\n <span style=\"width: 60px; display: inline-block;\"><i class=\"fas fa-caret-right\"></i> Occur if:</span>\n\n <input style=\"max-width: 340px; width: 340px;\" class=\"form-control form-control-sm event-if d-inline-block\" type=\"text\" dualbox-target=\"events-in\" :data-event=\"key\" :data-index=\"index\" :value=\"evt.if\" @change=\"setEventIf\" />\n </td>\n </tr>\n <tr v-if=\"evt.data || evt.datatype || expanded[key+'##'+index]\" class=\"tr-event-data\" colspan=\"3\">\n <td colspan=\"3\">\n <span style=\"width: 53px; display: inline-block;\"><i class=\"fas fa-caret-right\"></i> Data:</span>\n <span style=\"width: 350px;\">\n <display-type :type=\"getDataType(evt)\" @edited=\"onEditEventInDataType(key, index, $event)\"></display-type>\n <display-value :v=\"evt.data\" :type=\"getDataType(evt)\" @edited=\"onEditEventInData(key, index, $event)\"></display-value>\n </span>\n </td>\n </tr>\n </template>\n <tr>\n <td colspan=\"5\" style=\"padding-top: 0px; padding-bottom: 0px;\">\n <button class=\"btn btn-sm btn-add-subevent\" style=\"width: 100%;\" @click=\"addSubEvent(key)\">Add a subevent</button>\n </td>\n </tr>\n </tbody>\n </table>\n\n <h5 class=\"mt-3\" style=\"font-size: 16px; text-decoration: underline; font-weight: normal;\">Callback</h5>\n\n <table class=\"table-desc table-striped\" style=\"font-size: 12px!important;\">\n <thead class=\"thead-dark\">\n <th>Target</th>\n <th>Event</th>\n <th>Action</th>\n </thead>\n <tbody>\n <tr v-if=\"app.getEventOut(key) !== undefined\">\n <td>\n <select class=\"form-control form-control-sm select-event-target select-callback-target\" dualbox-target=\"events-out\" @change=\"setCallback(key)\">\n <option v-for=\"node in getNodesWithOutEvents()\" :value=\"node.getGraphId()\" :selected=\"node.getGraphId()===app.getEventOut(key).node\" :key=\"'app-event-out-target-' + node.getGraphId()\">{{ node.getGraphId() }}</option>\n </select>\n </td>\n <td>\n <select class=\"form-control form-control-sm select-event-name select-callback-event\" dualbox-target=\"events-out\">\n <template v-if=\"app.getEventOut(key).node\" @change=\"setCallback(key)\">\n <option v-for=\"(te, index) in getNodeOutEvents(app.getEventOut(key).node)\" :value=\"te\" :selected=\"te == app.getEventOut(key).event\" :key=\"'app-event-out-' + index\">{{te}}</option>\n </template>\n </select>\n </td>\n <td>\n <button class=\"btn btn-danger btn-editor-xs btn-remove-out-event\" :data-event=\"key\" @click=\"removeOutEvent\">\n <i class=\"fa fa-minus\"></i>\n </button>\n </td>\n </tr>\n <tr v-else>\n <td colspan=\"3\" style=\"padding-top: 0px; padding-bottom: 0px;\">\n <button class=\"btn btn-sm btn-add-callback\" style=\"width: 100%;\" @click=\"addCallback(key)\">Add a callback</button>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"modal edit-value-modal\" tabindex=\"-1\" role=\"dialog\">\n <div class=\"modal-dialog\" role=\"document\">\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <h5 class=\"modal-title\">Edit value</h5>\n <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">\n <span aria-hidden=\"true\">&times;</span>\n </button>\n </div>\n <div class=\"modal-body\">\n <div>\n <div class=\"form-check\">\n <input type=\"radio\" class=\"form-check-input set-value unset-value\" id=\"unset-value\" name=\"set-value\" value=\"unset-value\" checked>\n <label class=\"form-check-label\" for=\"unset-value\">\n don't set a value\n </label>\n </div>\n <div class=\"form-check\">\n <input type=\"radio\" class=\"form-check-input set-value set-value-null\" id=\"set-value-null\" name=\"set-value\" value=\"set-value-null\">\n <label class=\"form-check-label\" for=\"set-value-null\">\n set null\n </label>\n </div>\n <div class=\"form-check\">\n <input type=\"radio\" class=\"form-check-input set-value set-value-type\" id=\"set-value-type\" name=\"set-value\" value=\"set-value-type\" aria-label=\"Set a value of type\">\n <div class=\"form-inline form-check-label\" style=\"height: 24px;\">\n <label for=\"set-value-type\">\n set a value of type:\n <select class=\"form-control choose-value-type d-inline-block form-control-sm ml-2\">\n <option value=\"string\">String</option>\n <option value=\"number\">Number</option>\n <option value=\"boolean\">Boolean</option>\n <option value=\"object\">Object</option>\n </select>\n </label>\n </div>\n </div>\n </div>\n <div class=\"has-value\" style=\"display: none;\">\n <hr/>\n <div class=\"define-value define-boolean\" style=\"display: none;\">\n <div class=\"form-inline\">\n <label>Value: </label>\n <select class=\"form-control form-control-sm bool-value d-inline-block ml-2\">\n <option value=true>True</option>\n <option value=false>False</option>\n </select>\n </div>\n </div>\n <div class=\"define-value define-number\" style=\"display: none;\">\n <div class=\"form-inline\">\n <label>Value: </label>\n <input type=\"number\" class=\"form-control form-control-sm number-value ml-2\"/>\n </div>\n </div>\n <div class=\"define-value define-string\" style=\"display: none;\">\n <div class=\"form-inline\">\n <label>Value: </label>\n <input type=\"text\" class=\"form-control form-control-sm text-value ml-2\"/>\n </div>\n </div>\n <div class=\"define-value define-object\" style=\"display: none;\">\n <label>Value: </label>\n <div class=\"json-editor\" style=\"height: 400px;\"></div>\n </div>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\" class=\"btn btn-primary btn-save\">Save changes</button>\n <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">Close</button>\n </div>\n </div>\n </div>\n </div>\n</div>\n\n</template>\n\n<script>\nimport _ from 'lodash';\nimport swal from 'sweetalert2';\nimport DisplayTypeVue from './displayType.vue';\nimport DisplayValueVue from './displayValue.vue';\n\nexport default {\n props: [\n \"app\"\n ],\n components: {\n \"display-type\" : DisplayTypeVue,\n \"display-value\" : DisplayValueVue,\n },\n data: function () {\n return {\n expanded: {} // expanded app events (advanced settings)\n };\n },\n created: function() {\n this.view = window.dualboxEditor.v;\n },\n mounted: function() {\n // bind tooltips\n $(this.$el).find('button[data-toggle=\"tooltip\"]').tooltip();\n this.fixMaxHeightForCategories();\n },\n updated: function() {\n this.fixMaxHeightForCategories();\n },\n methods: {\n // setup a max height for each menu, so a scroll appears if there's too much item in it\n fixMaxHeightForCategories : function() {\n let nbActiveCategories = $(this.$el).find('.edit-body > .card').length;\n let headerHeight = $(this.$el).find('.edit-body > .card > .card-header').outerHeight();\n let panelHeight = $(this.$el).height() - $(this.$el).find('.edit-main-presentation').outerHeight();\n let maxCategoryHeight = panelHeight - nbActiveCategories * headerHeight;\n $(this.$el).find('.edit-body').css('height', panelHeight);\n $(this.$el).find('.edit-body > .card > .collapse > .card-body').css('max-height', maxCategoryHeight + \"px\");\n },\n\n onEdited: function() {\n this.view.repaint();\n },\n\n getNodesWithInEvents: function() {\n var l = [];\n var nodes = this.view.m.getNodes(\"ui\");\n _.each(nodes, (n) => {\n if( n.getInEventsNames().length > 0 ) {\n l.push(n);\n }\n });\n return l;\n },\n\n getNodesWithOutEvents: function() {\n var l = [];\n var nodes = this.view.m.getNodes(\"ui\");\n _.each(nodes, (n) => {\n if( n.getOutEventsNames().length > 0 ) {\n l.push(n);\n }\n });\n return l;\n },\n\n getNodeEvents: function( nodeId ) {\n var node = this.view.m.getNode(nodeId);\n return node.getEventsNames();\n },\n\n getNodeInEvents: function( nodeId ) {\n var node = this.view.m.getNode(nodeId);\n return node.getInEventsNames();\n },\n\n getNodeOutEvents: function( nodeId ) {\n var node = this.view.m.getNode(nodeId);\n return node.getOutEventsNames();\n },\n\n editAppDescription: function() {\n swal({\n input: 'text',\n title: 'Enter the description',\n }).then((result) => {\n this.view.c.setAppDescription(result.value);\n });\n },\n\n editEventDescription: function(e) {\n var eventName = $(e.target).attr('data-event');\n\n swal({\n input: 'text',\n title: 'Enter the description',\n }).then((result) => {\n this.view.c.setAppEventDescription(eventName, result.value);\n });\n },\n\n removeAppEvent: function(e) {\n var name = $(e.target).attr('data-event');\n this.view.c.removeAppEvent(name);\n this.onEdited();\n },\n\n renameAppEvent: function(e) {\n var name = $(e.target).attr('data-event');\n swal({\n input: 'text',\n title: 'Enter the new event name',\n }).then((result) => {\n if( result.value ) {\n this.view.c.renameAppEvent(name, result.value);\n this.onEdited();\n }\n });\n },\n\n setEventIf: function(e) {\n var index = parseInt($(e.target).attr('data-index'));\n var val = $(e.target).val();\n this.view.c.setEventIf( \"#application-\" + $(e.target).attr('dualbox-target') + '-' + $(e.target).attr('data-event'), index, val);\n this.onEdited();\n },\n\n setEventData: function(e) {\n var index = parseInt($(e.target).attr('data-index'));\n var val = $(e.target).val();\n this.view.c.setEventData( \"#application-\" + $(e.target).attr('dualbox-target') + '-' + $(e.target).attr('data-event'), index, val);\n this.onEdited();\n },\n\n selectEventTarget: function(e) {\n var target = $(e.target).val();\n\n // change options of closest .select-event-name according to this new target\n var targetNode = this.view.m.getNode(target);\n var targetEvents = targetNode.getEventsNames();\n var select = $(e.target).closest('tr').find('.select-event-name');\n select.html('');\n _.each(targetEvents, (eventName) => {\n select.append( $('<option/>', {\n value: eventName\n }).append(eventName));\n });\n\n var index = parseInt($(e.target).attr('data-index'));\n this.view.c.setEventTarget( \"#application-\" + $(e.target).attr('dualbox-target') + '-' + $(e.target).attr('data-event'), index, target);\n this.onEdited();\n },\n\n selectEventName: function(e) {\n var index = parseInt($(e.target).attr('data-index'));\n var val = $(e.target).val();\n this.view.c.setEventName( \"#application-\" + $(e.target).attr('dualbox-target') + '-' + $(e.target).attr('data-event'), index, val );\n this.onEdited();\n },\n\n addCallback: function(appEventName) {\n var nodesWithOutEvents = this.getNodesWithOutEvents();\n if( nodesWithOutEvents.length > 0 ) {\n var firstNode = nodesWithOutEvents[0];\n var firstEvent = firstNode.getOutEventsNames()[0];\n this.setCallback(appEventName, firstNode, firstEvent);\n }\n else {\n swal({\n title: \"You can not add an API callback here\",\n text: \"None of the UIs of the application does have an OUT event, usable for API callbacks\",\n type: \"error\"\n })\n }\n },\n\n setCallback: function(appEventName, e) {\n var targetNodeId = $(this.$el).find('.select-callback-target').val();\n var targetNodeEvent = $(this.$el).find('.select-callback-event').val();\n this.view.c.setCallback(appEventName, targetNodeId, targetNodeEvent);\n this.onEdited();\n },\n\n addAppEvent: function(e) {\n swal({\n input: 'text',\n title: 'Enter the event name',\n }).then((result) => {\n this.view.c.addAppEvent(result.value);\n this.onEdited();\n });\n },\n\n removeInEvent: function(e) {\n var eventName = $(e.target).attr('data-event');\n var index = parseInt($(e.target).attr('data-index'));\n this.view.c.removeAppInEvent(eventName, index);\n this.onEdited();\n },\n\n removeOutEvent: function(e) {\n var eventName = $(e.target).attr('data-event');\n this.view.c.removeAppOutEvent(eventName);\n this.onEdited();\n },\n\n addSubEvent: function(eventName) {\n this.view.c.addSubEvent(eventName);\n this.onEdited();\n },\n\n getDataType: function(evt) {\n if( evt.datatype ) {\n return evt.datatype;\n }\n else if( evt.data ) {\n return window.DualBox.Type.detectType(evt.data);\n }\n else {\n return undefined;\n }\n },\n\n toggleAdvancedAppEventSettings: function(e) {\n var key = $(e.target).data('event');\n var index = $(e.target).data('index');\n var k=key+'##'+index;\n this.expanded[k] = this.expanded[k] ? false : true;\n this.$forceUpdate();\n },\n\n onEditEventInData(key, index, val) {\n this.view.c.setEventData( \"#application-events-in-\" + key, index, val);\n this.$emit('edited');\n },\n\n onEditEventInDataType(key, index, type) {\n this.view.c.setEventDataType( \"#application-events-in-\" + key, index, type);\n\n // check that the set value still match the new type\n // delete it otherwise\n var val = this.app.getEventIn(key)[index].data;\n try {\n // TODO: ensure type is already loaded (after dualbox) and remove the try/catch\n if( !window.DualBox.Type.check(type, val) ) {\n // delete data (== set undefined)\n this.view.c.setEventData( \"#application-events-in-\" + key, index, undefined);\n }\n }\n catch(e) {\n this.view.c.setEventData( \"#application-events-in-\" + key, index, undefined);\n }\n\n this.$emit('edited');\n },\n }\n}\n</script>\n"]}, media: undefined });
65684
65733
 
65685
65734
  };
65686
65735
  /* scoped */
@@ -65743,6 +65792,7 @@ var script$b = {
65743
65792
  // adapt the style of the example graph node
65744
65793
  // remove the "position: absolute;" that messes up the display
65745
65794
  this.fixCardStyle();
65795
+ this.fixMaxHeightForCategories();
65746
65796
 
65747
65797
  // allow tooltips
65748
65798
  this.activateTooltip();
@@ -65760,6 +65810,7 @@ var script$b = {
65760
65810
  updated: function() {
65761
65811
  //console.log('[Updated] node-settings');
65762
65812
  this.fixCardStyle();
65813
+ this.fixMaxHeightForCategories();
65763
65814
  this.activateTooltip();
65764
65815
  this.focus();
65765
65816
  },
@@ -65786,6 +65837,16 @@ var script$b = {
65786
65837
  });
65787
65838
  },
65788
65839
 
65840
+ // setup a max height for each menu, so a scroll appears if there's too much item in it
65841
+ fixMaxHeightForCategories : function() {
65842
+ let nbActiveCategories = $(this.$el).find('.edit-body > .card-settings').length;
65843
+ let headerHeight = $(this.$el).find('.edit-body > .card-settings > .card-header').outerHeight();
65844
+ let panelHeight = $(this.$el).height() - $(this.$el).find('.edit-node-presentation').outerHeight();
65845
+ let maxCategoryHeight = panelHeight - nbActiveCategories * headerHeight;
65846
+ $(this.$el).find('.edit-body').css('height', panelHeight);
65847
+ $(this.$el).find('.edit-body > .card-settings > .collapse > .card-body').css('max-height', maxCategoryHeight + "px");
65848
+ },
65849
+
65789
65850
  activateTooltip: function() {
65790
65851
  $(this.$el).find('[data-toggle="tooltip"]').tooltip();
65791
65852
  },
@@ -65836,7 +65897,7 @@ var script$b = {
65836
65897
 
65837
65898
  addEvent: function(e) {
65838
65899
  this.view.c.addEvent(this.n.id);
65839
- this.$forceUpdate();
65900
+ this.onEdited();
65840
65901
  },
65841
65902
 
65842
65903
  toggleInputVisibility: function(e) {
@@ -65934,22 +65995,17 @@ var script$b = {
65934
65995
  // change options of closest .select-event-name according to this new target
65935
65996
  var targetNode = this.view.m.getNode(target);
65936
65997
  var targetEvents = targetNode.getEventsNames();
65937
- var select = $(e.target).closest('tr').find('.select-event-name');
65938
- select.html('');
65939
- lodash.each(targetEvents, (eventName) => {
65940
- select.append( $('<option/>', {
65941
- value: eventName
65942
- }).append(eventName));
65943
- });
65944
65998
 
65945
65999
  var index = parseInt($(e.target).attr('data-index'));
65946
66000
  this.view.c.setEventTarget( this.n.id, index, target );
66001
+ this.onEdited();
65947
66002
  },
65948
66003
 
65949
66004
  selectEventName: function(e) {
65950
66005
  var index = parseInt($(e.target).attr('data-index'));
65951
66006
  var val = $(e.target).val();
65952
66007
  this.view.c.setEventName( this.n.id, index, val );
66008
+ this.onEdited();
65953
66009
  },
65954
66010
 
65955
66011
  toggleCache: function(e) {
@@ -65961,6 +66017,7 @@ var script$b = {
65961
66017
  var val = $(e.target).is(':checked');
65962
66018
  this.view.c.setBoxParallel( this.n.id, val );
65963
66019
  this.isParallel = val;
66020
+ this.onEdited();
65964
66021
  },
65965
66022
 
65966
66023
  editModuleDescription: function(e) {
@@ -65999,7 +66056,7 @@ var script$b = {
65999
66056
  onEditAttributeType(attributeName, typeStr) {
66000
66057
  this.n.assignAttributeType(attributeName, typeStr);
66001
66058
  this.onEdited();
66002
- this.view.repaint();
66059
+ this.view.repaint();
66003
66060
  },
66004
66061
 
66005
66062
  onEditDefaultValue(val) {
@@ -66136,10 +66193,12 @@ var __vue_render__$b = function() {
66136
66193
  _c(
66137
66194
  "div",
66138
66195
  {
66196
+ staticClass: "edit-node-presentation",
66139
66197
  staticStyle: {
66140
66198
  "padding-left": "10px",
66141
66199
  "padding-top": "10px",
66142
- "padding-right": "10px"
66200
+ "padding-right": "10px",
66201
+ "padding-bottom": "10px"
66143
66202
  }
66144
66203
  },
66145
66204
  [
@@ -66187,7 +66246,7 @@ var __vue_render__$b = function() {
66187
66246
  ])
66188
66247
  ]),
66189
66248
  _vm._v(" "),
66190
- _c("p", [
66249
+ _c("p", { staticStyle: { "margin-bottom": "0" } }, [
66191
66250
  _c("small", { staticClass: "edit-dualbox-node-package-name" }, [
66192
66251
  _vm._v(_vm._s(_vm.n.getPackageName()))
66193
66252
  ])
@@ -66196,7 +66255,7 @@ var __vue_render__$b = function() {
66196
66255
  ),
66197
66256
  _vm._v(" "),
66198
66257
  _c("div", { staticClass: "edit-body" }, [
66199
- _c("div", { staticClass: "card" }, [
66258
+ _c("div", { staticClass: "card card-settings" }, [
66200
66259
  _vm._m(0),
66201
66260
  _vm._v(" "),
66202
66261
  _c(
@@ -66447,37 +66506,10 @@ var __vue_render__$b = function() {
66447
66506
  "data-id": _vm.n.id
66448
66507
  },
66449
66508
  domProps: { checked: _vm.n.isParallel() },
66450
- on: {
66451
- change: function($event) {
66452
- return _vm.toggleWorker()
66453
- }
66454
- }
66509
+ on: { change: _vm.toggleWorker }
66455
66510
  }),
66456
66511
  _vm._v(" "),
66457
- _vm._m(4),
66458
- _c("br"),
66459
- _vm.isParallel
66460
- ? _c(
66461
- "span",
66462
- {
66463
- directives: [
66464
- {
66465
- name: "show",
66466
- rawName: "v-show",
66467
- value: _vm.n.isParallel(),
66468
- expression: "n.isParallel()"
66469
- }
66470
- ],
66471
- staticClass:
66472
- "text-danger worker-warning"
66473
- },
66474
- [
66475
- _vm._v(
66476
- "Due to some technical limitations, this will only affect the built bundle. Please run tests on the built bundle as well."
66477
- )
66478
- ]
66479
- )
66480
- : _vm._e()
66512
+ _vm._m(4)
66481
66513
  ])
66482
66514
  ])
66483
66515
  : _vm._e()
@@ -67977,7 +68009,7 @@ __vue_render__$b._withStripped = true;
67977
68009
  /* style */
67978
68010
  const __vue_inject_styles__$b = function (inject) {
67979
68011
  if (!inject) return
67980
- inject("data-v-476d4859_0", { source: "\n.edit-dualbox-node-id {\n margin-bottom: 0px;\n display: inline-block;\n width: 100%;\n}\n.edit-dualbox-node-package-name {\n font-style: italic;\n}\n.btn-edit-dualbox-node-name {\n display: inline-block;\n margin-left: 5px;\n margin-top: -10px;\n position: relative;\n top: -10px;\n vertical-align: bottom;\n}\n.module-left-description {\n padding-top: 30px;\n font-size: 12px;\n text-align: center;\n}\n.card-settings .card-body {\n font-size: 12px;\n padding-left: 5px;\n padding-right: 5px;\n}\n.table-desc {\n width: 100%;\n}\n.table-desc > thead > th > td {\n margin-right: 6px;\n}\n.table-desc > tbody > tr > td {\n margin-right: 6px;\n padding-top: 8px;\n padding-bottom: 8px;\n height: 40px;\n}\n.card-header[data-toggle=\"collapse\"] {\n cursor: pointer;\n}\n.card-header[data-toggle=\"collapse\"] h5 {\n user-select: none;\n}\n.card-header[data-toggle=\"collapse\"]:hover .btn-link {\n text-decoration: none;\n}\n.dualbox-node-name, .dualbox-node-name-input {\n max-width: 400px;\n}\n.dualbox-node-name-span {\n max-width: 350px;\n}\n.dualbox-node-name-input {\n display: inline-block;\n border-radius: 4px;\n padding: 4px 8px 4px 8px;\n font-size: 20px;\n max-width: 280px;\n}\n.text-value, .number-value, .boolean-value {\n max-width: 140px;\n}\n.event-if, .event-data {\n max-width: 80px;\n}\n.select-event-target, .select-event-name, .event-if, .event-data {\n font-size: 12px;\n}\n.edit-body {\n overflow-y: auto;\n overflow-x: hidden;\n max-height: calc(100% - 80px);\n}\n.table-events .event-rooting {\n margin-top: 10px;\n}\n.table-events thead {\n border-bottom: 1px solid #ddd;\n}\n.table-events .tr-event-condition td {\n padding-left: 10px;\n}\n.table-events .tr-event-data td {\n padding-left: 10px;\n}\n.tr-event-condition td, .tr-event-data td {\n height: 20px!important;\n}\n.tr-event-condition, .tr-event-condition td, .tr-event-data, .tr-event-data td {\n padding-top: 1px!important;\n padding-bottom: 1px!important;\n}\n.table-events tr + .event-rooting {\n /* border-top: 1px solid #ddd; */\n}\n.event-rooting td {\n padding-top: 8px!important;\n padding-bottom: 4px!important;\n}\n.event-data-type {\n font-size: 75%;\n border-radius: 5px;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n}\n.event-data-display {\n font-size: 75%;\n border-radius: 5px;\n border: 1px solid #ddd;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n}\n.event-if {\n font-size: 75%;\n border-radius: 5px;\n border: 1px solid #ddd;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n}\ni.fa, i.fas, i.far {\n pointer-events: none;\n}\n\n", map: {"version":3,"sources":["/home/seb/dev/dualbox/editor/js/src/v/templates/editNodeSettings.vue"],"names":[],"mappings":";AACA;IACA,kBAAA;IACA,qBAAA;IACA,WAAA;AACA;AAEA;IACA,kBAAA;AACA;AAEA;IACA,qBAAA;IACA,gBAAA;IACA,iBAAA;IACA,kBAAA;IACA,UAAA;IACA,sBAAA;AACA;AAEA;IACA,iBAAA;IACA,eAAA;IACA,kBAAA;AACA;AAEA;IACA,eAAA;IACA,iBAAA;IACA,kBAAA;AACA;AAEA;IACA,WAAA;AACA;AAEA;IACA,iBAAA;AACA;AAEA;IACA,iBAAA;IACA,gBAAA;IACA,mBAAA;IACA,YAAA;AACA;AAEA;IACA,eAAA;AACA;AAEA;IACA,iBAAA;AACA;AAEA;IACA,qBAAA;AACA;AAEA;IACA,gBAAA;AACA;AAEA;IACA,gBAAA;AACA;AAEA;IACA,qBAAA;IACA,kBAAA;IACA,wBAAA;IACA,eAAA;IACA,gBAAA;AACA;AAEA;IACA,gBAAA;AACA;AAEA;IACA,eAAA;AACA;AAEA;IACA,eAAA;AACA;AAEA;IACA,gBAAA;IACA,kBAAA;IACA,6BAAA;AACA;AAEA;IACA,gBAAA;AACA;AAEA;IACA,6BAAA;AACA;AAEA;IACA,kBAAA;AACA;AAEA;IACA,kBAAA;AACA;AAEA;IACA,sBAAA;AACA;AAEA;IACA,0BAAA;IACA,6BAAA;AACA;AAEA;IACA,gCAAA;AACA;AAEA;IACA,0BAAA;IACA,6BAAA;AACA;AAEA;IACA,cAAA;IACA,kBAAA;IACA,iBAAA;IACA,kBAAA;IACA,gBAAA;IACA,mBAAA;AACA;AAEA;IACA,cAAA;IACA,kBAAA;IACA,sBAAA;IACA,iBAAA;IACA,kBAAA;IACA,gBAAA;IACA,mBAAA;AACA;AAEA;IACA,cAAA;IACA,kBAAA;IACA,sBAAA;IACA,iBAAA;IACA,kBAAA;IACA,gBAAA;IACA,mBAAA;AACA;AAEA;IACA,oBAAA;AACA","file":"editNodeSettings.vue","sourcesContent":["<style>\n .edit-dualbox-node-id {\n margin-bottom: 0px;\n display: inline-block;\n width: 100%;\n }\n\n .edit-dualbox-node-package-name {\n font-style: italic;\n }\n\n .btn-edit-dualbox-node-name {\n display: inline-block;\n margin-left: 5px;\n margin-top: -10px;\n position: relative;\n top: -10px;\n vertical-align: bottom;\n }\n\n .module-left-description {\n padding-top: 30px;\n font-size: 12px;\n text-align: center;\n }\n\n .card-settings .card-body {\n font-size: 12px;\n padding-left: 5px;\n padding-right: 5px;\n }\n\n .table-desc {\n width: 100%;\n }\n\n .table-desc > thead > th > td {\n margin-right: 6px;\n }\n\n .table-desc > tbody > tr > td {\n margin-right: 6px;\n padding-top: 8px;\n padding-bottom: 8px;\n height: 40px;\n }\n\n .card-header[data-toggle=\"collapse\"] {\n cursor: pointer;\n }\n\n .card-header[data-toggle=\"collapse\"] h5 {\n user-select: none;\n }\n\n .card-header[data-toggle=\"collapse\"]:hover .btn-link {\n text-decoration: none;\n }\n\n .dualbox-node-name, .dualbox-node-name-input {\n max-width: 400px;\n }\n\n .dualbox-node-name-span {\n max-width: 350px;\n }\n\n .dualbox-node-name-input {\n display: inline-block;\n border-radius: 4px;\n padding: 4px 8px 4px 8px;\n font-size: 20px;\n max-width: 280px;\n }\n\n .text-value, .number-value, .boolean-value {\n max-width: 140px;\n }\n\n .event-if, .event-data {\n max-width: 80px;\n }\n\n .select-event-target, .select-event-name, .event-if, .event-data {\n font-size: 12px;\n }\n\n .edit-body {\n overflow-y: auto;\n overflow-x: hidden;\n max-height: calc(100% - 80px);\n }\n\n .table-events .event-rooting {\n margin-top: 10px;\n }\n\n .table-events thead {\n border-bottom: 1px solid #ddd;\n }\n\n .table-events .tr-event-condition td {\n padding-left: 10px;\n }\n\n .table-events .tr-event-data td {\n padding-left: 10px;\n }\n\n .tr-event-condition td, .tr-event-data td {\n height: 20px!important;\n }\n\n .tr-event-condition, .tr-event-condition td, .tr-event-data, .tr-event-data td {\n padding-top: 1px!important;\n padding-bottom: 1px!important;\n }\n\n .table-events tr + .event-rooting {\n /* border-top: 1px solid #ddd; */\n }\n\n .event-rooting td {\n padding-top: 8px!important;\n padding-bottom: 4px!important;\n }\n\n .event-data-type {\n font-size: 75%;\n border-radius: 5px;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n }\n\n .event-data-display {\n font-size: 75%;\n border-radius: 5px;\n border: 1px solid #ddd;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n }\n\n .event-if {\n font-size: 75%;\n border-radius: 5px;\n border: 1px solid #ddd;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n }\n\n i.fa, i.fas, i.far {\n pointer-events: none;\n }\n\n</style>\n\n<template>\n <div class=\"edit-node-panel h100\" id=\"edit-node-panel\" :key=\"n.id\">\n <div style=\"padding-left: 10px; padding-top: 10px; padding-right: 10px;\">\n <h2 class=\"edit-dualbox-node-id\">\n <div v-if=\"nowEditingNodeName\" class=\"dualbox-node-name-edit\">\n <input type=\"text\" class=\"form-control dualbox-node-name-input\" style=\"display: inline-block;\" :value=\"n.graphId\" @keypress=\"changeNodeName\" autofocus/>\n <button class=\"btn btn-primary btn-save-node-name-change\" :data-id=\"n.graphId\" style=\"display: inline-block;\" @click=\"saveNodeName\">Save</button>\n </div>\n <div v-else class=\"dualbox-node-name\">\n <button class=\"btn btn-light btn-sm btn-edit-dualbox-node-name\" @click=\"editNodeName\"><i class=\"fa fa-edit\"></i></button>\n <span class=\"dualbox-node-name-span text-truncate d-inline-block\">{{n.graphId}}</span>\n </div>\n </h2>\n <p><small class=\"edit-dualbox-node-package-name\">{{n.getPackageName()}}</small></p>\n </div>\n\n <div class=\"edit-body\">\n <div class=\"card\">\n <div class=\"card-header\" id=\"dualbox-node-desc\" data-toggle=\"collapse\" data-target=\"#dualbox-node-desc-collapse\" aria-expanded=\"true\" aria-controls=\"dualbox-node-desc-collapse\">\n <h5 class=\"mb-0 btn-link\">Description</h5>\n </div>\n\n <div id=\"dualbox-node-desc-collapse\" class=\"collapse show\" aria-labelledby=\"dualbox-node-desc\" data-parent=\"#edit-node-panel\">\n <div class=\"card-body\" style=\"padding-left: 15px;\">\n <div class=\"module-left-signature\">\n <graph-node :id=\"n.id\" :example=\"true\" :pkg=\"n.getPackage()\" :n=\"createExampleNode(n)\"></graph-node>\n </div>\n <p class=\"module-left-description\">\n <template v-if=\"n.isInput() || n.isOutput() || n.isMetanode()\">\n <template v-if=\"nowEditingDescription\">\n <textarea class=\"edit-node-description\" rows=4 style=\"width: 100%;\" :value=\"n.getDescription()\" autofocus>\n </textarea>\n <button class=\"btn btn-success\" @click=\"setDescription\">Save</button>\n </template>\n <template v-else>\n <button class=\"btn btn-transparent btn-xs\" @click=\"editDescription\"><i class=\"fa fa-edit\" ></i></button>\n <span> {{ getDescription() }}</span>\n </template>\n </template>\n <span v-else>\n {{ n.getPackage().description || \"[No description available]\" }}\n </span>\n </p>\n </div>\n </div>\n </div>\n\n <div class=\"card card-settings\">\n <div class=\"card-header\" id=\"dualbox-node-comments\" data-toggle=\"collapse\" data-target=\"#dualbox-node-comments-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-node-comments-collapse\">\n <h5 class=\"mb-0 btn-link\">Comments</h5>\n </div>\n <div id=\"dualbox-node-comments-collapse\" class=\"collapse\" aria-labelledby=\"dualbox-node-comments\" data-parent=\"#edit-node-panel\">\n <div class=\"card-body\">\n <div style=\"padding-left: 15px; padding-right: 15px;\">\n <div v-if=\"nowEditingComment\" class=\"node-comment-edit\">\n <textarea class=\"node-comment\" rows=4 style=\"width: 100%;\" :data-id=\"n.id\" v-model=\"comment\" autofocus>\n </textarea>\n <div style=\"text-align: right; margin-top: 10px;\">\n <button class=\"btn btn-sm btn-secundary\" @click=\"deleteComment\">Delete</button>\n <button class=\"btn btn-sm btn-primary btn-save-comment\" @click=\"saveComment\">Save</button>\n </div>\n </div>\n <p v-else class=\"node-comment-text\">\n <span>{{ n.hasComment() ? n.getComment() : \"[Add a comment]\" }} </span>\n <button class=\"btn btn-sm btn-transparent\" @click=\"editComment\"><i class=\"fa fa-edit\"></i></button>\n </p>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Compute options -->\n <div v-if=\"n.isModule()\" class=\"card card-settings\">\n <div class=\"card-header\" id=\"dualbox-node-inputs\" data-toggle=\"collapse\" data-target=\"#dualbox-node-compute-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-node-compute-collapse\">\n <h5 class=\"mb-0 btn-link\">Compute options</h5>\n </div>\n <div id=\"dualbox-node-compute-collapse\" class=\"collapse\" aria-labelledby=\"dualbox-node-inputs\" data-parent=\"#edit-node-panel\">\n <div class=\"card-body\">\n <div class=\"form-group\" style=\"padding-left: 20px;\">\n <div>\n <label>\n <input class=\"input-cache-toggle\" type=\"checkbox\" v-bind:checked=\"n.hasCacheActivated()\" @change=\"toggleCache\">\n <span>Cache result <button type=\"button\" class=\"btn btn-transparent\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Keep the result in memory (the cache) to avoid computing this box every-time its result is required. The cache will be invalidated if an input prior to this box is changed.\" style=\"padding: 0;\"><i class=\"text-info far fa-question-circle\"></i></button></span>\n </label>\n </div>\n\n <div v-if=\"!n.isMetanode()\">\n <label>\n <input class=\"input-worker-toggle\" type=\"checkbox\" v-bind:data-id=\"n.id\" v-bind:checked=\"n.isParallel()\" @change=\"toggleWorker()\" />\n <span>Execute in a worker <button type=\"button\" class=\"btn btn-transparent\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Workers are separate contexts of executions that can execute long-running tasks without blocking the browser execution. Use this for heavy computations.\" style=\"padding: 0;\"><i class=\"text-info far fa-question-circle\"></i></button></span><br/><span v-if=\"isParallel\" class=\"text-danger worker-warning\" v-show=\"n.isParallel()\">Due to some technical limitations, this will only affect the built bundle. Please run tests on the built bundle as well.</span>\n </label>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Widget options -->\n <div v-if=\"n.isWidget()\" class=\"card card-default\">\n <div class=\"card-header\" id=\"dualbox-node-widget\" data-toggle=\"collapse\" data-target=\"#dualbox-node-widget-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-node-widget-collapse\">\n <h5 class=\"mb-0 btn-link\">Widget Options</h5>\n </div>\n <div id=\"dualbox-node-widget-collapse\" class=\"collapse\" aria-labelledby=\"dualbox-node-widget\" data-parent=\"#edit-node-panel\">\n <div class=\"card-body\">\n <span>Widget registered to: </span>\n <select class=\"form-control form-control-sm select-widget-registerTo\" style=\"max-width: 250px;\" @change=\"registerToWidget\">\n <option value=\"\">none</option>\n <option v-for=\"target in getSpecialUINodes()\" :key=\"'target-'+target.id\" :value=\"target.graphId\" :selected=\"n.getWidgetRegistration() == target.graphId\">{{target.id}}</option>\n\n </select>\n </div>\n </div>\n </div>\n\n <!-- Inputs -->\n <div v-if=\"n.isInput()\" class=\"card card-default\">\n <div class=\"card-header\" id=\"dualbox-node-default\" data-toggle=\"collapse\" data-target=\"#dualbox-node-default-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-node-default-collapse\">\n <h5 class=\"mb-0 btn-link\">Default value</h5>\n </div>\n <div id=\"dualbox-node-default-collapse\" class=\"collapse\" aria-labelledby=\"dualbox-node-default\" data-parent=\"#edit-node-panel\">\n <div class=\"card-body\">\n <span>Default value:</span>\n <span><display-value :v=\"n.getDefaultValue()\" :type=\"n.getType()\" @edited=\"onEditDefaultValue\"></display-value></span>\n </div>\n </div>\n </div>\n <div v-else-if=\"n.hasInputs()\" class=\"card card-settings\">\n <div class=\"card-header\" id=\"dualbox-node-inputs\" data-toggle=\"collapse\" data-target=\"#dualbox-node-inputs-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-node-inputs-collapse\">\n <h5 class=\"mb-0 btn-link\">Inputs <small><span class=\"badge badge-secondary\">{{n.getInputsNames().length}}</span></small></h5>\n </div>\n <div id=\"dualbox-node-inputs-collapse\" class=\"collapse\" aria-labelledby=\"dualbox-node-inputs\" data-parent=\"#edit-node-panel\">\n <div class=\"card-body\">\n <table class=\"table-desc table-striped\">\n <thead class=\"thead-dark\">\n <th>Input</th>\n <th>Visible</th>\n <th>Type</th>\n <th>Default</th>\n </thead>\n <tbody>\n <tr v-for=\"key in n.getInputsNames()\" :key=\"'input-'+key\">\n <td>\n {{key}}\n <button v-if=\"n.hasInputDesc(key)\" type=\"button\" class=\"btn btn-transparent\" data-toggle=\"tooltip\" data-placement=\"right\" v-bind:title=\"n.getInputDesc(key)\" style=\"padding: 0;\"><i class=\"text-info far fa-question-circle\"></i></button>\n </td>\n <td>\n <input class=\"input-visibility-toggle\" type=\"checkbox\" v-bind:data-id=\"n.id\" v-bind:data-input=\"key\" v-bind:checked=\"n.isInputVisible(key)\" @change=\"toggleInputVisibility\">\n </td>\n <td>\n <!-- If there's a start, then we must edit the type -->\n <display-type :type=\"n.getInputType(key)\" :readonly=\"!n.isInputTemplateType(key)\" @edited=\"onEditInputType(key, $event)\"></display-type>\n </td>\n <td>\n <display-value :v=\"n.getInputDefaultValue(key)\" :type=\"n.getInputType(key)\" @edited=\"onEditInputDefaultValue(key, $event)\" :readonly=\"!n.isFullyDefinedInputType(key)\" :readonlyReason=\"!n.isFullyDefinedInputType(key) ? 'You must first define a full type (without *) before you can edit this value' : ''\"></display-value>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n </div>\n\n <!-- Outputs -->\n <div v-if=\"n.hasOutputs()\" class=\"card card-settings\">\n <div class=\"card-header\" id=\"dualbox-node-outputs\" data-toggle=\"collapse\" data-target=\"#dualbox-node-outputs-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-node-outputs-collapse\">\n <h5 class=\"mb-0 btn-link\">Outputs <small><span class=\"badge badge-secondary\">{{n.getOutputsNames().length}}</span></small></h5>\n </div>\n <div id=\"dualbox-node-outputs-collapse\" class=\"collapse\" aria-labelledby=\"dualbox-node-outputs\" data-parent=\"#edit-node-panel\">\n <div class=\"card-body\">\n <table class=\"table-desc table-striped\">\n <thead class=\"thead-dark\">\n <th>Output</th>\n <th>Type</th>\n <th>Visible</th>\n </thead>\n <tbody>\n <tr v-for=\"key in n.getOutputsNames()\" :key=\"'output-'+key\">\n <td>{{key}}\n <button v-if=\"n.hasOutputDesc(key)\" type=\"button\" class=\"btn btn-transparent\" data-toggle=\"tooltip\" data-placement=\"right\" v-bind:title=\"n.getOutputDesc(key)\" style=\"padding: 0;\"><i class=\"text-info far fa-question-circle\"></i></button>\n </td>\n <td><display-type :type=\"n.getOutputType(key)\"></display-type></td>\n <td>\n <input class=\"output-visibility-toggle\" type=\"checkbox\" v-bind:data-id=\"n.id\" v-bind:data-output=\"key\" v-bind:checked=\"n.isOutputVisible(key)\" @change=\"toggleOutputVisibility\">\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n </div>\n\n <!-- Attributes -->\n <div v-if=\"n.hasAttributes()\" class=\"card card-settings\">\n <div class=\"card-header\" id=\"dualbox-node-attrs\" data-toggle=\"collapse\" data-target=\"#dualbox-node-attrs-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-node-attrs-collapse\">\n <h5 class=\"mb-0 btn-link\">Attributes <small><span class=\"badge badge-secondary\">{{n.getAttributesNames().length}}</span></small></h5>\n </div>\n <div id=\"dualbox-node-attrs-collapse\" class=\"collapse\" aria-labelledby=\"dualbox-node-attrs\" data-parent=\"#edit-node-panel\">\n <div class=\"card-body\">\n <table class=\"table-desc table-striped\">\n <thead class=\"thead-dark\">\n <th>Output</th>\n <th>Type</th>\n <th>Value</th>\n </thead>\n <tbody>\n <tr v-for=\"key in n.getAttributesNames()\" :key=\"'attr-'+key\">\n <td>{{key}}\n <button v-if=\"n.hasAttributeDesc(key)\" type=\"button\" class=\"btn btn-transparent\" data-toggle=\"tooltip\" data-placement=\"right\" :title=\"n.getAttributeDesc(key)\" style=\"padding: 0;\"><i class=\"text-info far fa-question-circle\"></i></button>\n </td>\n <td>\n <!-- If there's a start, then we must edit the type -->\n <display-type :type=\"n.getAttributeType(key)\" :readonly=\"!n.isAttributeTemplateType(key)\" @edited=\"onEditAttributeType(key, $event)\"></display-type>\n </td>\n <td>\n <display-value :v=\"n.getAttributeValue(key)\" :type=\"n.getAttributeType(key)\" @edited=\"onEditAttribute(key, $event)\" :readonly=\"!n.isFullyDefinedAttributeType(key)\" :readonlyReason=\"!n.isFullyDefinedInputType(key) ? 'You must first define a full type (without *) before you can edit this value' : ''\"></display-value>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n </div>\n\n\n <!-- Loops -->\n <div v-if=\"n.hasInputs()\" class=\"card card-settings\">\n <div class=\"card-header\" id=\"dualbox-node-inputs\" data-toggle=\"collapse\" data-target=\"#dualbox-node-loops-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-node-loops-collapse\">\n <h5 class=\"mb-0 btn-link\">Loops <small><span class=\"badge badge-secondary\">{{ n.hasLoop() ? \"on\" : \"off\" }}</span></small></h5>\n </div>\n <div id=\"dualbox-node-loops-collapse\" class=\"collapse\" aria-labelledby=\"dualbox-node-inputs\" data-parent=\"#edit-node-panel\">\n <div class=\"card-body\">\n <h4>Iterators\n <button type=\"button\" class=\"btn btn-transparent\" data-toggle=\"tooltip\" data-placement=\"right\" title=\"Iterators will break an array in input into a list of their components. The module will be computed several times, each time with one different component from every iterator input. Inputs that don't define iterators will use their current value as-is for the different computations.\" style=\"padding: 0;\"><i class=\"text-info far fa-question-circle\"></i></button>\n </h4>\n <table class=\"table-desc table-striped\">\n <tbody>\n <tr v-for=\"key in n.getInputsNames()\" :key=\"'loop-iterator-'+key\">\n <td>{{key}}</td>\n <td>\n <input class=\"input-iterator-toggle\" type=\"checkbox\" :data-input=\"key\" :checked=\"n.hasIterator(key)\" @change=\"toggleIterator\" />\n </td>\n </tr>\n </tbody>\n </table>\n\n <h4 class=\"mt-2\">Feedback\n <button type=\"button\" class=\"btn btn-transparent\" data-toggle=\"tooltip\" data-placement=\"right\" title=\"Feedback (during a loop) is a reinjection of an output result of one iteration into an input of the next iteration.\" style=\"padding: 0;\"><i class=\"text-info far fa-question-circle\"></i></button>\n </h4>\n <table class=\"table-desc table-striped\">\n <tbody>\n <tr v-for=\"key in n.getOutputsNames()\" :key=\"'loop-feedback-'+key\">\n <td>{{key}}</td>\n <td>\n <select class=\"form-control form-control-sm select-output-feedback\" :data-output=\"key\" @change=\"selectOutputFeedback\">\n <option value=\"none\">No feedback</option>\n <option v-for=\"i in n.getInputsNames()\" :value=\"i\" :selected=\"n.getFeedback(key) == i\" :key=\"'loop-feedback-input-'+i\">{{i}}</option>\n </select>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n </div>\n\n <!-- Events -->\n <div v-if=\"n.isUI()\" class=\"card card-settings\">\n <div class=\"card-header\" id=\"dualbox-node-events\" data-toggle=\"collapse\" data-target=\"#dualbox-node-events-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-node-events-collapse\">\n <h5 class=\"mb-0 btn-link\">Events <small><span class=\"badge badge-secondary\">{{n.getOutboundEvents().length}}</span></small></h5>\n </div>\n <div id=\"dualbox-node-events-collapse\" class=\"collapse\" aria-labelledby=\"dualbox-node-events\" data-parent=\"#edit-node-panel\">\n <div class=\"card-body\">\n <table class=\"table-events table-desc\" style=\"font-size: 12px!important;\">\n <thead class=\"thead-dark\">\n <th>Target</th>\n <th>Event</th>\n <th>Action</th>\n </thead>\n <tbody>\n <template v-if=\"n.hasOutEvents()\" v-for=\"(evt, index) in n.getOutboundEvents()\" :data-index=\"index\">\n <tr class=\"event-rooting\">\n <td>\n <select v-if=\"evt.node\" class=\"form-control form-control-sm select-event-target\" :data-index=\"index\"@change=\"selectEventTarget\" >\n <option v-for=\"node in getUINodesWithEvents()\" :value=\"node.getGraphId()\" :selected=\"node.getGraphId()==evt.node\" :key=\"node.id\">{{node.getGraphId()}}</option>\n </select>\n <span v-else>{{evt.selector}}</span>\n </td>\n <td>\n <select class=\"form-control form-control-sm select-event-name\" :data-index=\"index\" @change=\"selectEventName\">\n <template v-if=\"evt.node\">\n <option v-for=\"targetEvent in getTargetNodeEvents(evt.node)\" :value=\"targetEvent\" :selected=\"evt.event===targetEvent\" :key=\"targetEvent\">{{targetEvent}}</option>\n </template>\n <template v-else>\n <option value=\"hide\">hide</option>\n <option value=\"show\">show</option>\n </template>\n </select>\n </td>\n <td>\n <button class=\"btn btn-secondary btn-editor-xs\" :data-index=\"index\" @click=\"toggleAdvancedAppEventSettings\" style=\"margin-left: 10px;\" title=\"Toggle advanced event settings\" >\n <i class=\"fas fa-cog\"></i>\n </button>\n <button class=\"btn btn-danger btn-editor-xs btn-remove-event\" :data-index=\"index\" @click=\"removeEvent\">\n <i class=\"fa fa-minus\"></i>\n </button>\n </td>\n </tr>\n <tr v-if=\"evt.if || expanded[index]\" class=\"tr-event-condition\">\n <td colspan=\"3\">\n <span style=\"width: 60px; display: inline-block;\"><i class=\"fas fa-caret-right\"></i> Occur if:</span>\n\n <input style=\"max-width: 340px; width: 340px;\" class=\"form-control form-control-sm event-if d-inline-block\" type=\"text\" dualbox-target=\"events-in\" :data-index=\"index\" :value=\"evt.if\" @change=\"setEventIf\" />\n </td>\n </tr>\n <tr v-if=\"evt.data || evt.datatype || expanded[index]\" class=\"tr-event-data\" colspan=\"3\">\n <td colspan=\"3\">\n <span style=\"width: 53px; display: inline-block;\"><i class=\"fas fa-caret-right\"></i> Data:</span>\n <span style=\"width: 350px;\">\n <display-type :type=\"getDataType(evt)\" @edited=\"onEditEventInDataType(key, index, $event)\"></display-type>\n <display-value :v=\"evt.data\" :type=\"getDataType(evt)\" @edited=\"onEditEventData(key, index, $event)\"></display-value>\n </span>\n </td>\n </tr>\n </template>\n <tr>\n <td colspan=\"5\" style=\"padding-top: 0px; padding-bottom: 0px;\">\n <button class=\"btn btn-sm\" :data-id=\"n.id\" style=\"width: 100%;\" @click=\"addEvent\">Add event</button>\n </td>\n </tr>\n </tbody>\n </table>\n\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"modal edit-value-modal\" tabindex=\"-1\" role=\"dialog\">\n <div class=\"modal-dialog\" role=\"document\">\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <h5 class=\"modal-title\">Edit value</h5>\n <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">\n <span aria-hidden=\"true\">&times;</span>\n </button>\n </div>\n <div class=\"modal-body\">\n <div class=\"set-type\">\n <div class=\"form-check\">\n <input type=\"radio\" class=\"form-check-input set-value unset-value\" id=\"unset-value\" name=\"set-value\" value=\"unset-value\" checked>\n <label class=\"form-check-label\" for=\"unset-value\">\n don't set a value\n </label>\n </div>\n <div class=\"form-check\">\n <input type=\"radio\" class=\"form-check-input set-value set-value-null\" id=\"set-value-null\" name=\"set-value\" value=\"set-value-null\">\n <label class=\"form-check-label\" for=\"set-value-null\">\n set null\n </label>\n </div>\n <div class=\"form-check\">\n <input type=\"radio\" class=\"form-check-input set-value set-value-type\" id=\"set-value-type\" name=\"set-value\" value=\"set-value-type\" aria-label=\"Set a value of type\">\n <div class=\"form-inline form-check-label\" style=\"height: 24px;\">\n <label for=\"set-value-type\">\n set a value of type:\n <select class=\"form-control choose-value-type d-inline-block form-control-sm ml-2\">\n <option value=\"string\">String</option>\n <option value=\"number\">Number</option>\n <option value=\"boolean\">Boolean</option>\n <option value=\"object\">Object</option>\n <option value=\"file\">File</option>\n </select>\n </label>\n </div>\n </div>\n </div>\n <hr class=\"separator\"/>\n <div class=\"has-value\" style=\"display: none;\">\n <div class=\"define-value define-boolean\" style=\"display: none;\">\n <div class=\"form-inline\">\n <label>Value: </label>\n <select class=\"form-control form-control-sm bool-value d-inline-block ml-2\">\n <option value=true>True</option>\n <option value=false>False</option>\n </select>\n </div>\n </div>\n <div class=\"define-value define-file\" style=\"display: none;\">\n <div class=\"form-inline\">\n <label>File input</label>\n <input type=\"file\" class=\"form-control-file form-control-sm file-value\">\n </div>\n </div>\n <div class=\"define-value define-number\" style=\"display: none;\">\n <div class=\"form-inline\">\n <label>Value: </label>\n <input type=\"number\" class=\"form-control form-control-sm number-value ml-2\"/>\n </div>\n </div>\n <div class=\"define-value define-string\" style=\"display: none;\">\n <div class=\"form-inline\">\n <label>Value: </label>\n <input type=\"text\" class=\"form-control form-control-sm text-value ml-2\"/>\n </div>\n </div>\n <div class=\"define-value define-object\" style=\"display: none;\">\n <label>Value: </label>\n <div class=\"json-editor\" style=\"height: 400px;\"></div>\n </div>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\" class=\"btn btn-primary btn-save\">Save changes</button>\n <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">Close</button>\n </div>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script>\nimport _ from 'lodash';\nimport DisplayTypeVue from './displayType.vue';\nimport DisplayValueVue from './displayValue.vue';\nimport GraphNodeVue from './graphNode.vue';\nimport JSONEditor from '@dualbox/dualbox-lib-jsoneditor';\nimport swal from 'sweetalert2';\n\nexport default {\n props: [\n \"id\", // the GraphNode object\n ],\n components: {\n \"display-type\" : DisplayTypeVue,\n \"display-value\" : DisplayValueVue,\n \"graph-node\" : GraphNodeVue\n },\n data: function () {\n return {\n comment: null,\n expanded: {}, // expanded app events (advanced settings)\n\n // states\n isParallel: false,\n nowEditingComment: false,\n nowEditingNodeName: false,\n nowEditingDescription: false,\n };\n },\n created: function() {\n this.view = window.dualboxEditor.v;\n this.n = this.view.m.getNode(this.id);\n\n // fetch the comment for this node\n this.comment = this.n.hasComment() ? this.n.getComment() : \"\";\n this.isParallel = this.n.isParallel();\n },\n mounted: function() {\n // adapt the style of the example graph node\n // remove the \"position: absolute;\" that messes up the display\n this.fixCardStyle();\n\n // allow tooltips\n this.activateTooltip();\n\n // bind the json editor\n editor = new JSONEditor($(this.$el).find('.json-editor')[0], { modes: ['tree', 'code', 'text' ]});\n editor.set({});\n },\n beforeUpdate: function() {\n //console.log('[Updating] node-settings');\n // we need to refresh our node object\n this.n = this.view.m.getNode(this.id); // it breaks updating node name\n this.deactivateTooltip();\n },\n updated: function() {\n //console.log('[Updated] node-settings');\n this.fixCardStyle();\n this.activateTooltip();\n this.focus();\n },\n activate: function() {\n this.activateTooltip();\n this.focus();\n },\n deactivate: function() {\n this.deactivateTooltip();\n },\n methods: {\n fixCardStyle: function() {\n var card = $(this.$el).find('.module-left-signature .card');\n card.css('position', 'static').css('point-events', 'none');\n card.find('.point').css(\"visibibility\", \"visible\").find('svg').css(\"visibibility\", \"visible\");\n card.ready(() => {\n var width = Math.max(\n card.find('.inputs').width() + card.find('.outputs').width() + 20,\n card.find('.title').width() + 60,\n card.find('.subtitle').width() + 40\n );\n card.css('width', width + 'px');\n card.addClass('mx-auto');\n });\n },\n\n activateTooltip: function() {\n $(this.$el).find('[data-toggle=\"tooltip\"]').tooltip();\n },\n\n deactivateTooltip: function() {\n $(this.$el).find('[data-toggle=\"tooltip\"]').tooltip(\"dispose\");\n },\n\n focus: function() {\n $(this.$el).find('[autofocus]').focus();\n },\n\n // for widget registration\n getSpecialUINodes: function() {\n var targets = this.n.m.getSpecialUINodes( this.n.getRegisterType() );\n return targets;\n },\n\n getUINodesWithEvents : function() {\n var nodes = this.n.m.getNodes(\"ui\");\n var eventNodes = nodes.filter( function(n) {\n return n.getEventsNames().length > 0;\n });\n return eventNodes;\n },\n\n getTargetNodeEvents: function(nodeId) {\n var targetNode = this.n.m.getNode(nodeId);\n return targetNode.getEventsNames();\n },\n\n editComment: function(e) {\n this.nowEditingComment = true;\n },\n\n saveComment: function(e) {\n var val = $(this.$el).find('.node-comment').val();\n this.view.c.setComment(this.n.id, val);\n this.nowEditingComment = false;\n this.onEdited();\n },\n\n deleteComment: function(e) {\n this.view.c.deleteComment(this.n.id);\n this.nowEditingComment = false;\n this.onEdited();\n },\n\n addEvent: function(e) {\n this.view.c.addEvent(this.n.id);\n this.$forceUpdate();\n },\n\n toggleInputVisibility: function(e) {\n var inputName = $(e.target).data('input');\n var visible = $(e.target).is(\":checked\");\n if( !this.view.c.setInputVisibility(this.n.id, inputName, visible) ) {\n // failed, reset this to old value\n $(e.target).prop('checked', !visible);\n }\n },\n\n toggleOutputVisibility: function(e) {\n var outputName = $(e.target).data('output');\n var visible = $(e.target).is(\":checked\");\n if( !this.view.c.setOutputVisibility(this.n.id, outputName, visible) ) {\n // failed, reset this to old value\n $(e.target).prop('checked', !visible);\n }\n },\n\n editNodeName: function(e) {\n this.nowEditingNodeName = true;\n },\n\n changeNodeName: function(e) {\n // user pressed enter\n if(e.which == 13 || e.keyCode == 13) {\n this.saveNodeName(e);\n }\n },\n\n saveNodeName: function(e) {\n var newId = $(e.target).parent().find('.dualbox-node-name-input').val();\n this.view.c.renameBox(this.n.graphId, newId, this.n.type);\n\n // get the new node\n switch( this.n.type ) {\n case \"input\": this.n = this.view.m.getNode(\"in-\"+newId); break;\n case \"output\": this.n = this.view.m.getNode(\"in-\"+newId); break;\n default: this.n = this.view.m.getNode(newId);\n }\n\n this.nowEditingNodeName = false;\n },\n\n toggleIterator: function(e) {\n var destInput = $(e.target).attr('data-input');\n if( $(e.target).is(\":checked\") ) {\n this.view.c.setIterator( this.n.id, destInput );\n }\n else {\n this.view.c.unsetIterator( this.n.id, destInput );\n }\n this.onEdited();\n },\n\n registerToWidget: function(e) {\n var targetId = $(e.target).val();\n this.view.c.registerWidget(this.n.id, targetId);\n },\n\n selectOutputFeedback: function(e) {\n var val = $(e.target).val();\n var destOutput = $(e.target).attr('data-output');\n if( val !== \"none\" ) {\n this.view.c.setFeedback( this.n.id, destOutput, val );\n }\n else {\n this.view.c.unsetFeedback( this.n.id, destOutput );\n }\n },\n\n removeEvent: function(e) {\n var index = parseInt($(e.target).attr('data-index'));\n this.view.c.removeEvent( this.n.id, index );\n this.$forceUpdate();\n },\n\n setEventIf: function(e) {\n var index = parseInt($(e.target).attr('data-index'));\n var val = $(e.target).val();\n this.view.c.setEventIf( this.n.id, index, val );\n },\n\n setEventData: function(e) {\n var index = parseInt($(e.target).attr('data-index'));\n var val = $(e.target).val();\n this.view.c.setEventData( this.n.id, index, val );\n },\n\n // TODO: remake this into it's own vue\n selectEventTarget: function(e) {\n var target = $(e.target).val();\n\n // change options of closest .select-event-name according to this new target\n var targetNode = this.view.m.getNode(target);\n var targetEvents = targetNode.getEventsNames();\n var select = $(e.target).closest('tr').find('.select-event-name');\n select.html('');\n _.each(targetEvents, (eventName) => {\n select.append( $('<option/>', {\n value: eventName\n }).append(eventName));\n });\n\n var index = parseInt($(e.target).attr('data-index'));\n this.view.c.setEventTarget( this.n.id, index, target );\n },\n\n selectEventName: function(e) {\n var index = parseInt($(e.target).attr('data-index'));\n var val = $(e.target).val();\n this.view.c.setEventName( this.n.id, index, val );\n },\n\n toggleCache: function(e) {\n var val = $(e.target).is(':checked');\n this.view.c.setBoxCache( this.n.id, val );\n },\n\n toggleWorker: function(e) {\n var val = $(e.target).is(':checked');\n this.view.c.setBoxParallel( this.n.id, val );\n this.isParallel = val;\n },\n\n editModuleDescription: function(e) {\n var desc = $(e.target).attr('data-desc');\n\n swal({\n title: \"Describe what this metabox does\",\n input: \"textarea\",\n inputValue: desc || \"\",\n showCancelButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n animation: \"slide-from-top\",\n inputPlaceholder: \"This metabox...\"\n }).then( (result) => {\n if (result.value === \"\") {\n swal.showInputError(\"You need to write something!\");\n return false;\n }\n else {\n this.view.c.setMetanodeDescription(this.n.id, result.value);\n }\n });\n },\n\n createExampleNode(n) {\n return this.view.m.createCloneNode(n.getPackage().name, n.id)\n },\n\n onEditInputType(inputName, typeStr) {\n this.n.assignInputType(inputName, typeStr);\n this.onEdited();\n this.view.repaint();\n },\n\n onEditAttributeType(attributeName, typeStr) {\n this.n.assignAttributeType(attributeName, typeStr);\n this.onEdited();\n this.view.repaint(); \n },\n\n onEditDefaultValue(val) {\n this.n.setDefaultValue(val);\n this.onEdited();\n this.view.repaint();\n },\n\n onEditInputDefaultValue(inputName, val) {\n if( val === undefined ) {\n this.n.deleteVal(\"input\", inputName);\n this.n.setInputVisibility(inputName, true); // show the input then (connection needed)\n }\n else {\n this.n.val(\"input\", inputName, val );\n this.n.setInputVisibility(inputName, false); // hide inputs with values (no connection needed)\n }\n this.onEdited();\n this.view.repaint();\n },\n\n onEditAttribute(attrName, val) {\n if( val === undefined ) {\n this.n.deleteVal(\"attr\", attrName);\n }\n else {\n this.n.val(\"attr\", attrName, val);\n }\n this.onEdited();\n },\n\n onEditDefaultInput(inputName, val) {\n if( val === undefined ) {\n this.n.deleteVal(\"input\", inputName);\n }\n else {\n this.n.val(\"input\", inputName, val);\n }\n this.onEdited();\n this.view.repaint();\n },\n\n onEdited() {\n // we need to refresh our node object\n this.n = this.view.m.getNode(this.id); // it breaks updating node name\n this.$forceUpdate();\n },\n\n getDataType: function(evt) {\n if( evt.datatype ) {\n return evt.datatype;\n }\n else if( evt.data ) {\n return window.DualBox.Type.detectType(evt.data);\n }\n else {\n return undefined;\n }\n },\n\n toggleAdvancedAppEventSettings: function(e) {\n var index = $(e.target).data('index');\n this.expanded[index] = this.expanded[index] ? false : true;\n this.$forceUpdate();\n },\n\n onEditEventData(key, index, val) {\n this.view.c.setEventData( this.n.id, index, val );\n this.$forceUpdate();\n },\n\n onEditEventInDataType(key, index, type) {\n this.view.c.setEventDataType( this.n.id, index, type);\n\n // check that the set value still match the new type\n // delete it otherwise\n var val = this.n.getOutboundEvents()[index].data;\n try {\n // TODO: ensure type is already loaded (after dualbox) and remove the try/catch\n if( !window.DualBox.Type.check(type, val) ) {\n // delete data (== set undefined)\n this.view.c.setEventData( this.n.id, index, undefined);\n }\n }\n catch(e) {\n this.view.c.setEventData( this.n.id, index, undefined);\n }\n\n this.$forceUpdate();\n },\n\n getDescription() {\n return this.n.getDescription() || \"[Add a description]\"\n },\n\n editDescription() {\n this.nowEditingDescription = true;\n },\n\n setDescription() {\n var val = $(this.$el).find('.edit-node-description').val();\n if( this.n.isInput() ) {\n this.view.c.setInputDescription(this.n.graphId, val);\n }\n else if( this.n.isOutput() ) {\n this.view.c.setOutputDescription(this.n.graphId, val);\n }\n else if( this.n.isMetanode() ) {\n this.view.c.setMetanodeDescription(this.n.graphId, val);\n }\n this.nowEditingDescription = false;\n\n this.$forceUpdate();\n },\n }\n}\n\n\n</script>\n"]}, media: undefined });
68012
+ inject("data-v-5af66f22_0", { source: "\n.edit-dualbox-node-id {\n margin-bottom: 0px;\n display: inline-block;\n width: 100%;\n}\n.edit-dualbox-node-package-name {\n font-style: italic;\n}\n.btn-edit-dualbox-node-name {\n display: inline-block;\n margin-left: 5px;\n margin-top: -10px;\n position: relative;\n top: -10px;\n vertical-align: bottom;\n}\n.module-left-description {\n padding-top: 30px;\n font-size: 12px;\n text-align: center;\n}\n.card-settings .card-body {\n font-size: 12px;\n padding-left: 5px;\n padding-right: 5px;\n overflow-y: auto;\n}\n.table-desc {\n width: 100%;\n}\n.table-desc > thead > th > td {\n margin-right: 6px;\n}\n.table-desc > tbody > tr > td {\n margin-right: 6px;\n padding-top: 8px;\n padding-bottom: 8px;\n height: 40px;\n}\n.card-header[data-toggle=\"collapse\"] {\n cursor: pointer;\n}\n.card-header[data-toggle=\"collapse\"] h5 {\n user-select: none;\n}\n.card-header[data-toggle=\"collapse\"]:hover .btn-link {\n text-decoration: none;\n}\n.dualbox-node-name, .dualbox-node-name-input {\n max-width: 400px;\n}\n.dualbox-node-name-span {\n max-width: 350px;\n}\n.dualbox-node-name-input {\n display: inline-block;\n border-radius: 4px;\n padding: 4px 8px 4px 8px;\n font-size: 20px;\n max-width: 280px;\n}\n.text-value, .number-value, .boolean-value {\n max-width: 140px;\n}\n.event-if, .event-data {\n max-width: 80px;\n}\n.select-event-target, .select-event-name, .event-if, .event-data {\n font-size: 12px;\n}\n.edit-body {\n overflow-y: hidden;\n overflow-x: hidden;\n max-height: calc(100% - 90px);\n}\n.table-events .event-rooting {\n margin-top: 10px;\n}\n.table-events thead {\n border-bottom: 1px solid #ddd;\n}\n.table-events .tr-event-condition td {\n padding-left: 10px;\n}\n.table-events .tr-event-data td {\n padding-left: 10px;\n}\n.tr-event-condition td, .tr-event-data td {\n height: 20px!important;\n}\n.tr-event-condition, .tr-event-condition td, .tr-event-data, .tr-event-data td {\n padding-top: 1px!important;\n padding-bottom: 1px!important;\n}\n.table-events tr + .event-rooting {\n /* border-top: 1px solid #ddd; */\n}\n.event-rooting td {\n padding-top: 8px!important;\n padding-bottom: 4px!important;\n}\n.event-data-type {\n font-size: 75%;\n border-radius: 5px;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n}\n.event-data-display {\n font-size: 75%;\n border-radius: 5px;\n border: 1px solid #ddd;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n}\n.event-if {\n font-size: 75%;\n border-radius: 5px;\n border: 1px solid #ddd;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n}\ni.fa, i.fas, i.far {\n pointer-events: none;\n}\n.h100 {\n height: 100%;\n}\n\n", map: {"version":3,"sources":["/home/seb/dev/dualbox/editor/js/src/v/templates/editNodeSettings.vue"],"names":[],"mappings":";AACA;IACA,kBAAA;IACA,qBAAA;IACA,WAAA;AACA;AAEA;IACA,kBAAA;AACA;AAEA;IACA,qBAAA;IACA,gBAAA;IACA,iBAAA;IACA,kBAAA;IACA,UAAA;IACA,sBAAA;AACA;AAEA;IACA,iBAAA;IACA,eAAA;IACA,kBAAA;AACA;AAEA;IACA,eAAA;IACA,iBAAA;IACA,kBAAA;IACA,gBAAA;AACA;AAEA;IACA,WAAA;AACA;AAEA;IACA,iBAAA;AACA;AAEA;IACA,iBAAA;IACA,gBAAA;IACA,mBAAA;IACA,YAAA;AACA;AAEA;IACA,eAAA;AACA;AAEA;IACA,iBAAA;AACA;AAEA;IACA,qBAAA;AACA;AAEA;IACA,gBAAA;AACA;AAEA;IACA,gBAAA;AACA;AAEA;IACA,qBAAA;IACA,kBAAA;IACA,wBAAA;IACA,eAAA;IACA,gBAAA;AACA;AAEA;IACA,gBAAA;AACA;AAEA;IACA,eAAA;AACA;AAEA;IACA,eAAA;AACA;AAEA;IACA,kBAAA;IACA,kBAAA;IACA,6BAAA;AACA;AAEA;IACA,gBAAA;AACA;AAEA;IACA,6BAAA;AACA;AAEA;IACA,kBAAA;AACA;AAEA;IACA,kBAAA;AACA;AAEA;IACA,sBAAA;AACA;AAEA;IACA,0BAAA;IACA,6BAAA;AACA;AAEA;IACA,gCAAA;AACA;AAEA;IACA,0BAAA;IACA,6BAAA;AACA;AAEA;IACA,cAAA;IACA,kBAAA;IACA,iBAAA;IACA,kBAAA;IACA,gBAAA;IACA,mBAAA;AACA;AAEA;IACA,cAAA;IACA,kBAAA;IACA,sBAAA;IACA,iBAAA;IACA,kBAAA;IACA,gBAAA;IACA,mBAAA;AACA;AAEA;IACA,cAAA;IACA,kBAAA;IACA,sBAAA;IACA,iBAAA;IACA,kBAAA;IACA,gBAAA;IACA,mBAAA;AACA;AAEA;IACA,oBAAA;AACA;AAEA;IACA,YAAA;AACA","file":"editNodeSettings.vue","sourcesContent":["<style>\n .edit-dualbox-node-id {\n margin-bottom: 0px;\n display: inline-block;\n width: 100%;\n }\n\n .edit-dualbox-node-package-name {\n font-style: italic;\n }\n\n .btn-edit-dualbox-node-name {\n display: inline-block;\n margin-left: 5px;\n margin-top: -10px;\n position: relative;\n top: -10px;\n vertical-align: bottom;\n }\n\n .module-left-description {\n padding-top: 30px;\n font-size: 12px;\n text-align: center;\n }\n\n .card-settings .card-body {\n font-size: 12px;\n padding-left: 5px;\n padding-right: 5px;\n overflow-y: auto;\n }\n\n .table-desc {\n width: 100%;\n }\n\n .table-desc > thead > th > td {\n margin-right: 6px;\n }\n\n .table-desc > tbody > tr > td {\n margin-right: 6px;\n padding-top: 8px;\n padding-bottom: 8px;\n height: 40px;\n }\n\n .card-header[data-toggle=\"collapse\"] {\n cursor: pointer;\n }\n\n .card-header[data-toggle=\"collapse\"] h5 {\n user-select: none;\n }\n\n .card-header[data-toggle=\"collapse\"]:hover .btn-link {\n text-decoration: none;\n }\n\n .dualbox-node-name, .dualbox-node-name-input {\n max-width: 400px;\n }\n\n .dualbox-node-name-span {\n max-width: 350px;\n }\n\n .dualbox-node-name-input {\n display: inline-block;\n border-radius: 4px;\n padding: 4px 8px 4px 8px;\n font-size: 20px;\n max-width: 280px;\n }\n\n .text-value, .number-value, .boolean-value {\n max-width: 140px;\n }\n\n .event-if, .event-data {\n max-width: 80px;\n }\n\n .select-event-target, .select-event-name, .event-if, .event-data {\n font-size: 12px;\n }\n\n .edit-body {\n overflow-y: hidden;\n overflow-x: hidden;\n max-height: calc(100% - 90px);\n }\n\n .table-events .event-rooting {\n margin-top: 10px;\n }\n\n .table-events thead {\n border-bottom: 1px solid #ddd;\n }\n\n .table-events .tr-event-condition td {\n padding-left: 10px;\n }\n\n .table-events .tr-event-data td {\n padding-left: 10px;\n }\n\n .tr-event-condition td, .tr-event-data td {\n height: 20px!important;\n }\n\n .tr-event-condition, .tr-event-condition td, .tr-event-data, .tr-event-data td {\n padding-top: 1px!important;\n padding-bottom: 1px!important;\n }\n\n .table-events tr + .event-rooting {\n /* border-top: 1px solid #ddd; */\n }\n\n .event-rooting td {\n padding-top: 8px!important;\n padding-bottom: 4px!important;\n }\n\n .event-data-type {\n font-size: 75%;\n border-radius: 5px;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n }\n\n .event-data-display {\n font-size: 75%;\n border-radius: 5px;\n border: 1px solid #ddd;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n }\n\n .event-if {\n font-size: 75%;\n border-radius: 5px;\n border: 1px solid #ddd;\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n }\n\n i.fa, i.fas, i.far {\n pointer-events: none;\n }\n\n .h100 {\n height: 100%;\n }\n\n</style>\n\n<template>\n <div class=\"edit-node-panel h100\" id=\"edit-node-panel\" :key=\"n.id\">\n <div class=\"edit-node-presentation\" style=\"padding-left: 10px; padding-top: 10px; padding-right: 10px; padding-bottom: 10px;\">\n <h2 class=\"edit-dualbox-node-id\">\n <div v-if=\"nowEditingNodeName\" class=\"dualbox-node-name-edit\">\n <input type=\"text\" class=\"form-control dualbox-node-name-input\" style=\"display: inline-block;\" :value=\"n.graphId\" @keypress=\"changeNodeName\" autofocus/>\n <button class=\"btn btn-primary btn-save-node-name-change\" :data-id=\"n.graphId\" style=\"display: inline-block;\" @click=\"saveNodeName\">Save</button>\n </div>\n <div v-else class=\"dualbox-node-name\">\n <button class=\"btn btn-light btn-sm btn-edit-dualbox-node-name\" @click=\"editNodeName\"><i class=\"fa fa-edit\"></i></button>\n <span class=\"dualbox-node-name-span text-truncate d-inline-block\">{{n.graphId}}</span>\n </div>\n </h2>\n <p style=\"margin-bottom: 0\"><small class=\"edit-dualbox-node-package-name\">{{n.getPackageName()}}</small></p>\n </div>\n\n <div class=\"edit-body\">\n <div class=\"card card-settings\">\n <div class=\"card-header\" id=\"dualbox-node-desc\" data-toggle=\"collapse\" data-target=\"#dualbox-node-desc-collapse\" aria-expanded=\"true\" aria-controls=\"dualbox-node-desc-collapse\">\n <h5 class=\"mb-0 btn-link\">Description</h5>\n </div>\n\n <div id=\"dualbox-node-desc-collapse\" class=\"collapse show\" aria-labelledby=\"dualbox-node-desc\" data-parent=\"#edit-node-panel\">\n <div class=\"card-body\" style=\"padding-left: 15px;\">\n <div class=\"module-left-signature\">\n <graph-node :id=\"n.id\" :example=\"true\" :pkg=\"n.getPackage()\" :n=\"createExampleNode(n)\"></graph-node>\n </div>\n <p class=\"module-left-description\">\n <template v-if=\"n.isInput() || n.isOutput() || n.isMetanode()\">\n <template v-if=\"nowEditingDescription\">\n <textarea class=\"edit-node-description\" rows=4 style=\"width: 100%;\" :value=\"n.getDescription()\" autofocus>\n </textarea>\n <button class=\"btn btn-success\" @click=\"setDescription\">Save</button>\n </template>\n <template v-else>\n <button class=\"btn btn-transparent btn-xs\" @click=\"editDescription\"><i class=\"fa fa-edit\" ></i></button>\n <span> {{ getDescription() }}</span>\n </template>\n </template>\n <span v-else>\n {{ n.getPackage().description || \"[No description available]\" }}\n </span>\n </p>\n </div>\n </div>\n </div>\n\n <div class=\"card card-settings\">\n <div class=\"card-header\" id=\"dualbox-node-comments\" data-toggle=\"collapse\" data-target=\"#dualbox-node-comments-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-node-comments-collapse\">\n <h5 class=\"mb-0 btn-link\">Comments</h5>\n </div>\n <div id=\"dualbox-node-comments-collapse\" class=\"collapse\" aria-labelledby=\"dualbox-node-comments\" data-parent=\"#edit-node-panel\">\n <div class=\"card-body\">\n <div style=\"padding-left: 15px; padding-right: 15px;\">\n <div v-if=\"nowEditingComment\" class=\"node-comment-edit\">\n <textarea class=\"node-comment\" rows=4 style=\"width: 100%;\" :data-id=\"n.id\" v-model=\"comment\" autofocus>\n </textarea>\n <div style=\"text-align: right; margin-top: 10px;\">\n <button class=\"btn btn-sm btn-secundary\" @click=\"deleteComment\">Delete</button>\n <button class=\"btn btn-sm btn-primary btn-save-comment\" @click=\"saveComment\">Save</button>\n </div>\n </div>\n <p v-else class=\"node-comment-text\">\n <span>{{ n.hasComment() ? n.getComment() : \"[Add a comment]\" }} </span>\n <button class=\"btn btn-sm btn-transparent\" @click=\"editComment\"><i class=\"fa fa-edit\"></i></button>\n </p>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Compute options -->\n <div v-if=\"n.isModule()\" class=\"card card-settings\">\n <div class=\"card-header\" id=\"dualbox-node-inputs\" data-toggle=\"collapse\" data-target=\"#dualbox-node-compute-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-node-compute-collapse\">\n <h5 class=\"mb-0 btn-link\">Compute options</h5>\n </div>\n <div id=\"dualbox-node-compute-collapse\" class=\"collapse\" aria-labelledby=\"dualbox-node-inputs\" data-parent=\"#edit-node-panel\">\n <div class=\"card-body\">\n <div class=\"form-group\" style=\"padding-left: 20px;\">\n <div>\n <label>\n <input class=\"input-cache-toggle\" type=\"checkbox\" v-bind:checked=\"n.hasCacheActivated()\" @change=\"toggleCache\">\n <span>Cache result <button type=\"button\" class=\"btn btn-transparent\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Keep the result in memory (the cache) to avoid computing this box every-time its result is required. The cache will be invalidated if an input prior to this box is changed.\" style=\"padding: 0;\"><i class=\"text-info far fa-question-circle\"></i></button></span>\n </label>\n </div>\n\n <div v-if=\"!n.isMetanode()\">\n <label>\n <input class=\"input-worker-toggle\" type=\"checkbox\" v-bind:data-id=\"n.id\" v-bind:checked=\"n.isParallel()\" @change=\"toggleWorker\" />\n <span>Execute in a worker <button type=\"button\" class=\"btn btn-transparent\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Workers are separate contexts of executions that can execute long-running tasks without blocking the browser execution. Use this for heavy computations.\" style=\"padding: 0;\"><i class=\"text-info far fa-question-circle\"></i></button></span>\n </label>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Widget options -->\n <div v-if=\"n.isWidget()\" class=\"card card-default\">\n <div class=\"card-header\" id=\"dualbox-node-widget\" data-toggle=\"collapse\" data-target=\"#dualbox-node-widget-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-node-widget-collapse\">\n <h5 class=\"mb-0 btn-link\">Widget Options</h5>\n </div>\n <div id=\"dualbox-node-widget-collapse\" class=\"collapse\" aria-labelledby=\"dualbox-node-widget\" data-parent=\"#edit-node-panel\">\n <div class=\"card-body\">\n <span>Widget registered to: </span>\n <select class=\"form-control form-control-sm select-widget-registerTo\" style=\"max-width: 250px;\" @change=\"registerToWidget\">\n <option value=\"\">none</option>\n <option v-for=\"target in getSpecialUINodes()\" :key=\"'target-'+target.id\" :value=\"target.graphId\" :selected=\"n.getWidgetRegistration() == target.graphId\">{{target.id}}</option>\n\n </select>\n </div>\n </div>\n </div>\n\n <!-- Inputs -->\n <div v-if=\"n.isInput()\" class=\"card card-default\">\n <div class=\"card-header\" id=\"dualbox-node-default\" data-toggle=\"collapse\" data-target=\"#dualbox-node-default-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-node-default-collapse\">\n <h5 class=\"mb-0 btn-link\">Default value</h5>\n </div>\n <div id=\"dualbox-node-default-collapse\" class=\"collapse\" aria-labelledby=\"dualbox-node-default\" data-parent=\"#edit-node-panel\">\n <div class=\"card-body\">\n <span>Default value:</span>\n <span><display-value :v=\"n.getDefaultValue()\" :type=\"n.getType()\" @edited=\"onEditDefaultValue\"></display-value></span>\n </div>\n </div>\n </div>\n <div v-else-if=\"n.hasInputs()\" class=\"card card-settings\">\n <div class=\"card-header\" id=\"dualbox-node-inputs\" data-toggle=\"collapse\" data-target=\"#dualbox-node-inputs-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-node-inputs-collapse\">\n <h5 class=\"mb-0 btn-link\">Inputs <small><span class=\"badge badge-secondary\">{{n.getInputsNames().length}}</span></small></h5>\n </div>\n <div id=\"dualbox-node-inputs-collapse\" class=\"collapse\" aria-labelledby=\"dualbox-node-inputs\" data-parent=\"#edit-node-panel\">\n <div class=\"card-body\">\n <table class=\"table-desc table-striped\">\n <thead class=\"thead-dark\">\n <th>Input</th>\n <th>Visible</th>\n <th>Type</th>\n <th>Default</th>\n </thead>\n <tbody>\n <tr v-for=\"key in n.getInputsNames()\" :key=\"'input-'+key\">\n <td>\n {{key}}\n <button v-if=\"n.hasInputDesc(key)\" type=\"button\" class=\"btn btn-transparent\" data-toggle=\"tooltip\" data-placement=\"right\" v-bind:title=\"n.getInputDesc(key)\" style=\"padding: 0;\"><i class=\"text-info far fa-question-circle\"></i></button>\n </td>\n <td>\n <input class=\"input-visibility-toggle\" type=\"checkbox\" v-bind:data-id=\"n.id\" v-bind:data-input=\"key\" v-bind:checked=\"n.isInputVisible(key)\" @change=\"toggleInputVisibility\">\n </td>\n <td>\n <!-- If there's a start, then we must edit the type -->\n <display-type :type=\"n.getInputType(key)\" :readonly=\"!n.isInputTemplateType(key)\" @edited=\"onEditInputType(key, $event)\"></display-type>\n </td>\n <td>\n <display-value :v=\"n.getInputDefaultValue(key)\" :type=\"n.getInputType(key)\" @edited=\"onEditInputDefaultValue(key, $event)\" :readonly=\"!n.isFullyDefinedInputType(key)\" :readonlyReason=\"!n.isFullyDefinedInputType(key) ? 'You must first define a full type (without *) before you can edit this value' : ''\"></display-value>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n </div>\n\n <!-- Outputs -->\n <div v-if=\"n.hasOutputs()\" class=\"card card-settings\">\n <div class=\"card-header\" id=\"dualbox-node-outputs\" data-toggle=\"collapse\" data-target=\"#dualbox-node-outputs-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-node-outputs-collapse\">\n <h5 class=\"mb-0 btn-link\">Outputs <small><span class=\"badge badge-secondary\">{{n.getOutputsNames().length}}</span></small></h5>\n </div>\n <div id=\"dualbox-node-outputs-collapse\" class=\"collapse\" aria-labelledby=\"dualbox-node-outputs\" data-parent=\"#edit-node-panel\">\n <div class=\"card-body\">\n <table class=\"table-desc table-striped\">\n <thead class=\"thead-dark\">\n <th>Output</th>\n <th>Type</th>\n <th>Visible</th>\n </thead>\n <tbody>\n <tr v-for=\"key in n.getOutputsNames()\" :key=\"'output-'+key\">\n <td>{{key}}\n <button v-if=\"n.hasOutputDesc(key)\" type=\"button\" class=\"btn btn-transparent\" data-toggle=\"tooltip\" data-placement=\"right\" v-bind:title=\"n.getOutputDesc(key)\" style=\"padding: 0;\"><i class=\"text-info far fa-question-circle\"></i></button>\n </td>\n <td><display-type :type=\"n.getOutputType(key)\"></display-type></td>\n <td>\n <input class=\"output-visibility-toggle\" type=\"checkbox\" v-bind:data-id=\"n.id\" v-bind:data-output=\"key\" v-bind:checked=\"n.isOutputVisible(key)\" @change=\"toggleOutputVisibility\">\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n </div>\n\n <!-- Attributes -->\n <div v-if=\"n.hasAttributes()\" class=\"card card-settings\">\n <div class=\"card-header\" id=\"dualbox-node-attrs\" data-toggle=\"collapse\" data-target=\"#dualbox-node-attrs-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-node-attrs-collapse\">\n <h5 class=\"mb-0 btn-link\">Attributes <small><span class=\"badge badge-secondary\">{{n.getAttributesNames().length}}</span></small></h5>\n </div>\n <div id=\"dualbox-node-attrs-collapse\" class=\"collapse\" aria-labelledby=\"dualbox-node-attrs\" data-parent=\"#edit-node-panel\">\n <div class=\"card-body\">\n <table class=\"table-desc table-striped\">\n <thead class=\"thead-dark\">\n <th>Output</th>\n <th>Type</th>\n <th>Value</th>\n </thead>\n <tbody>\n <tr v-for=\"key in n.getAttributesNames()\" :key=\"'attr-'+key\">\n <td>{{key}}\n <button v-if=\"n.hasAttributeDesc(key)\" type=\"button\" class=\"btn btn-transparent\" data-toggle=\"tooltip\" data-placement=\"right\" :title=\"n.getAttributeDesc(key)\" style=\"padding: 0;\"><i class=\"text-info far fa-question-circle\"></i></button>\n </td>\n <td>\n <!-- If there's a start, then we must edit the type -->\n <display-type :type=\"n.getAttributeType(key)\" :readonly=\"!n.isAttributeTemplateType(key)\" @edited=\"onEditAttributeType(key, $event)\"></display-type>\n </td>\n <td>\n <display-value :v=\"n.getAttributeValue(key)\" :type=\"n.getAttributeType(key)\" @edited=\"onEditAttribute(key, $event)\" :readonly=\"!n.isFullyDefinedAttributeType(key)\" :readonlyReason=\"!n.isFullyDefinedInputType(key) ? 'You must first define a full type (without *) before you can edit this value' : ''\"></display-value>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n </div>\n\n\n <!-- Loops -->\n <div v-if=\"n.hasInputs()\" class=\"card card-settings\">\n <div class=\"card-header\" id=\"dualbox-node-inputs\" data-toggle=\"collapse\" data-target=\"#dualbox-node-loops-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-node-loops-collapse\">\n <h5 class=\"mb-0 btn-link\">Loops <small><span class=\"badge badge-secondary\">{{ n.hasLoop() ? \"on\" : \"off\" }}</span></small></h5>\n </div>\n <div id=\"dualbox-node-loops-collapse\" class=\"collapse\" aria-labelledby=\"dualbox-node-inputs\" data-parent=\"#edit-node-panel\">\n <div class=\"card-body\">\n <h4>Iterators\n <button type=\"button\" class=\"btn btn-transparent\" data-toggle=\"tooltip\" data-placement=\"right\" title=\"Iterators will break an array in input into a list of their components. The module will be computed several times, each time with one different component from every iterator input. Inputs that don't define iterators will use their current value as-is for the different computations.\" style=\"padding: 0;\"><i class=\"text-info far fa-question-circle\"></i></button>\n </h4>\n <table class=\"table-desc table-striped\">\n <tbody>\n <tr v-for=\"key in n.getInputsNames()\" :key=\"'loop-iterator-'+key\">\n <td>{{key}}</td>\n <td>\n <input class=\"input-iterator-toggle\" type=\"checkbox\" :data-input=\"key\" :checked=\"n.hasIterator(key)\" @change=\"toggleIterator\" />\n </td>\n </tr>\n </tbody>\n </table>\n\n <h4 class=\"mt-2\">Feedback\n <button type=\"button\" class=\"btn btn-transparent\" data-toggle=\"tooltip\" data-placement=\"right\" title=\"Feedback (during a loop) is a reinjection of an output result of one iteration into an input of the next iteration.\" style=\"padding: 0;\"><i class=\"text-info far fa-question-circle\"></i></button>\n </h4>\n <table class=\"table-desc table-striped\">\n <tbody>\n <tr v-for=\"key in n.getOutputsNames()\" :key=\"'loop-feedback-'+key\">\n <td>{{key}}</td>\n <td>\n <select class=\"form-control form-control-sm select-output-feedback\" :data-output=\"key\" @change=\"selectOutputFeedback\">\n <option value=\"none\">No feedback</option>\n <option v-for=\"i in n.getInputsNames()\" :value=\"i\" :selected=\"n.getFeedback(key) == i\" :key=\"'loop-feedback-input-'+i\">{{i}}</option>\n </select>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n </div>\n\n <!-- Events -->\n <div v-if=\"n.isUI()\" class=\"card card-settings\">\n <div class=\"card-header\" id=\"dualbox-node-events\" data-toggle=\"collapse\" data-target=\"#dualbox-node-events-collapse\" aria-expanded=\"false\" aria-controls=\"dualbox-node-events-collapse\">\n <h5 class=\"mb-0 btn-link\">Events <small><span class=\"badge badge-secondary\">{{n.getOutboundEvents().length}}</span></small></h5>\n </div>\n <div id=\"dualbox-node-events-collapse\" class=\"collapse\" aria-labelledby=\"dualbox-node-events\" data-parent=\"#edit-node-panel\">\n <div class=\"card-body\">\n <table class=\"table-events table-desc\" style=\"font-size: 12px!important;\">\n <thead class=\"thead-dark\">\n <th>Target</th>\n <th>Event</th>\n <th>Action</th>\n </thead>\n <tbody>\n <template v-if=\"n.hasOutEvents()\" v-for=\"(evt, index) in n.getOutboundEvents()\" :data-index=\"index\">\n <tr class=\"event-rooting\">\n <td>\n <select v-if=\"evt.node\" class=\"form-control form-control-sm select-event-target\" :data-index=\"index\"@change=\"selectEventTarget\" >\n <option v-for=\"node in getUINodesWithEvents()\" :value=\"node.getGraphId()\" :selected=\"node.getGraphId()==evt.node\" :key=\"node.id\">{{node.getGraphId()}}</option>\n </select>\n <span v-else>{{evt.selector}}</span>\n </td>\n <td>\n <select class=\"form-control form-control-sm select-event-name\" :data-index=\"index\" @change=\"selectEventName\">\n <template v-if=\"evt.node\">\n <option v-for=\"targetEvent in getTargetNodeEvents(evt.node)\" :value=\"targetEvent\" :selected=\"evt.event===targetEvent\" :key=\"targetEvent\">{{targetEvent}}</option>\n </template>\n <template v-else>\n <option value=\"hide\">hide</option>\n <option value=\"show\">show</option>\n </template>\n </select>\n </td>\n <td>\n <button class=\"btn btn-secondary btn-editor-xs\" :data-index=\"index\" @click=\"toggleAdvancedAppEventSettings\" style=\"margin-left: 10px;\" title=\"Toggle advanced event settings\" >\n <i class=\"fas fa-cog\"></i>\n </button>\n <button class=\"btn btn-danger btn-editor-xs btn-remove-event\" :data-index=\"index\" @click=\"removeEvent\">\n <i class=\"fa fa-minus\"></i>\n </button>\n </td>\n </tr>\n <tr v-if=\"evt.if || expanded[index]\" class=\"tr-event-condition\">\n <td colspan=\"3\">\n <span style=\"width: 60px; display: inline-block;\"><i class=\"fas fa-caret-right\"></i> Occur if:</span>\n\n <input style=\"max-width: 340px; width: 340px;\" class=\"form-control form-control-sm event-if d-inline-block\" type=\"text\" dualbox-target=\"events-in\" :data-index=\"index\" :value=\"evt.if\" @change=\"setEventIf\" />\n </td>\n </tr>\n <tr v-if=\"evt.data || evt.datatype || expanded[index]\" class=\"tr-event-data\" colspan=\"3\">\n <td colspan=\"3\">\n <span style=\"width: 53px; display: inline-block;\"><i class=\"fas fa-caret-right\"></i> Data:</span>\n <span style=\"width: 350px;\">\n <display-type :type=\"getDataType(evt)\" @edited=\"onEditEventInDataType(key, index, $event)\"></display-type>\n <display-value :v=\"evt.data\" :type=\"getDataType(evt)\" @edited=\"onEditEventData(key, index, $event)\"></display-value>\n </span>\n </td>\n </tr>\n </template>\n <tr>\n <td colspan=\"5\" style=\"padding-top: 0px; padding-bottom: 0px;\">\n <button class=\"btn btn-sm\" :data-id=\"n.id\" style=\"width: 100%;\" @click=\"addEvent\">Add event</button>\n </td>\n </tr>\n </tbody>\n </table>\n\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"modal edit-value-modal\" tabindex=\"-1\" role=\"dialog\">\n <div class=\"modal-dialog\" role=\"document\">\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <h5 class=\"modal-title\">Edit value</h5>\n <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">\n <span aria-hidden=\"true\">&times;</span>\n </button>\n </div>\n <div class=\"modal-body\">\n <div class=\"set-type\">\n <div class=\"form-check\">\n <input type=\"radio\" class=\"form-check-input set-value unset-value\" id=\"unset-value\" name=\"set-value\" value=\"unset-value\" checked>\n <label class=\"form-check-label\" for=\"unset-value\">\n don't set a value\n </label>\n </div>\n <div class=\"form-check\">\n <input type=\"radio\" class=\"form-check-input set-value set-value-null\" id=\"set-value-null\" name=\"set-value\" value=\"set-value-null\">\n <label class=\"form-check-label\" for=\"set-value-null\">\n set null\n </label>\n </div>\n <div class=\"form-check\">\n <input type=\"radio\" class=\"form-check-input set-value set-value-type\" id=\"set-value-type\" name=\"set-value\" value=\"set-value-type\" aria-label=\"Set a value of type\">\n <div class=\"form-inline form-check-label\" style=\"height: 24px;\">\n <label for=\"set-value-type\">\n set a value of type:\n <select class=\"form-control choose-value-type d-inline-block form-control-sm ml-2\">\n <option value=\"string\">String</option>\n <option value=\"number\">Number</option>\n <option value=\"boolean\">Boolean</option>\n <option value=\"object\">Object</option>\n <option value=\"file\">File</option>\n </select>\n </label>\n </div>\n </div>\n </div>\n <hr class=\"separator\"/>\n <div class=\"has-value\" style=\"display: none;\">\n <div class=\"define-value define-boolean\" style=\"display: none;\">\n <div class=\"form-inline\">\n <label>Value: </label>\n <select class=\"form-control form-control-sm bool-value d-inline-block ml-2\">\n <option value=true>True</option>\n <option value=false>False</option>\n </select>\n </div>\n </div>\n <div class=\"define-value define-file\" style=\"display: none;\">\n <div class=\"form-inline\">\n <label>File input</label>\n <input type=\"file\" class=\"form-control-file form-control-sm file-value\">\n </div>\n </div>\n <div class=\"define-value define-number\" style=\"display: none;\">\n <div class=\"form-inline\">\n <label>Value: </label>\n <input type=\"number\" class=\"form-control form-control-sm number-value ml-2\"/>\n </div>\n </div>\n <div class=\"define-value define-string\" style=\"display: none;\">\n <div class=\"form-inline\">\n <label>Value: </label>\n <input type=\"text\" class=\"form-control form-control-sm text-value ml-2\"/>\n </div>\n </div>\n <div class=\"define-value define-object\" style=\"display: none;\">\n <label>Value: </label>\n <div class=\"json-editor\" style=\"height: 400px;\"></div>\n </div>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\" class=\"btn btn-primary btn-save\">Save changes</button>\n <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">Close</button>\n </div>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script>\nimport _ from 'lodash';\nimport DisplayTypeVue from './displayType.vue';\nimport DisplayValueVue from './displayValue.vue';\nimport GraphNodeVue from './graphNode.vue';\nimport JSONEditor from '@dualbox/dualbox-lib-jsoneditor';\nimport swal from 'sweetalert2';\n\nexport default {\n props: [\n \"id\", // the GraphNode object\n ],\n components: {\n \"display-type\" : DisplayTypeVue,\n \"display-value\" : DisplayValueVue,\n \"graph-node\" : GraphNodeVue\n },\n data: function () {\n return {\n comment: null,\n expanded: {}, // expanded app events (advanced settings)\n\n // states\n isParallel: false,\n nowEditingComment: false,\n nowEditingNodeName: false,\n nowEditingDescription: false,\n };\n },\n created: function() {\n this.view = window.dualboxEditor.v;\n this.n = this.view.m.getNode(this.id);\n\n // fetch the comment for this node\n this.comment = this.n.hasComment() ? this.n.getComment() : \"\";\n this.isParallel = this.n.isParallel();\n },\n mounted: function() {\n // adapt the style of the example graph node\n // remove the \"position: absolute;\" that messes up the display\n this.fixCardStyle();\n this.fixMaxHeightForCategories();\n\n // allow tooltips\n this.activateTooltip();\n\n // bind the json editor\n editor = new JSONEditor($(this.$el).find('.json-editor')[0], { modes: ['tree', 'code', 'text' ]});\n editor.set({});\n },\n beforeUpdate: function() {\n //console.log('[Updating] node-settings');\n // we need to refresh our node object\n this.n = this.view.m.getNode(this.id); // it breaks updating node name\n this.deactivateTooltip();\n },\n updated: function() {\n //console.log('[Updated] node-settings');\n this.fixCardStyle();\n this.fixMaxHeightForCategories();\n this.activateTooltip();\n this.focus();\n },\n activate: function() {\n this.activateTooltip();\n this.focus();\n },\n deactivate: function() {\n this.deactivateTooltip();\n },\n methods: {\n fixCardStyle: function() {\n var card = $(this.$el).find('.module-left-signature .card');\n card.css('position', 'static').css('point-events', 'none');\n card.find('.point').css(\"visibibility\", \"visible\").find('svg').css(\"visibibility\", \"visible\");\n card.ready(() => {\n var width = Math.max(\n card.find('.inputs').width() + card.find('.outputs').width() + 20,\n card.find('.title').width() + 60,\n card.find('.subtitle').width() + 40\n );\n card.css('width', width + 'px');\n card.addClass('mx-auto');\n });\n },\n\n // setup a max height for each menu, so a scroll appears if there's too much item in it\n fixMaxHeightForCategories : function() {\n let nbActiveCategories = $(this.$el).find('.edit-body > .card-settings').length;\n let headerHeight = $(this.$el).find('.edit-body > .card-settings > .card-header').outerHeight();\n let panelHeight = $(this.$el).height() - $(this.$el).find('.edit-node-presentation').outerHeight();\n let maxCategoryHeight = panelHeight - nbActiveCategories * headerHeight;\n $(this.$el).find('.edit-body').css('height', panelHeight);\n $(this.$el).find('.edit-body > .card-settings > .collapse > .card-body').css('max-height', maxCategoryHeight + \"px\");\n },\n\n activateTooltip: function() {\n $(this.$el).find('[data-toggle=\"tooltip\"]').tooltip();\n },\n\n deactivateTooltip: function() {\n $(this.$el).find('[data-toggle=\"tooltip\"]').tooltip(\"dispose\");\n },\n\n focus: function() {\n $(this.$el).find('[autofocus]').focus();\n },\n\n // for widget registration\n getSpecialUINodes: function() {\n var targets = this.n.m.getSpecialUINodes( this.n.getRegisterType() );\n return targets;\n },\n\n getUINodesWithEvents : function() {\n var nodes = this.n.m.getNodes(\"ui\");\n var eventNodes = nodes.filter( function(n) {\n return n.getEventsNames().length > 0;\n });\n return eventNodes;\n },\n\n getTargetNodeEvents: function(nodeId) {\n var targetNode = this.n.m.getNode(nodeId);\n return targetNode.getEventsNames();\n },\n\n editComment: function(e) {\n this.nowEditingComment = true;\n },\n\n saveComment: function(e) {\n var val = $(this.$el).find('.node-comment').val();\n this.view.c.setComment(this.n.id, val);\n this.nowEditingComment = false;\n this.onEdited();\n },\n\n deleteComment: function(e) {\n this.view.c.deleteComment(this.n.id);\n this.nowEditingComment = false;\n this.onEdited();\n },\n\n addEvent: function(e) {\n this.view.c.addEvent(this.n.id);\n this.onEdited();\n },\n\n toggleInputVisibility: function(e) {\n var inputName = $(e.target).data('input');\n var visible = $(e.target).is(\":checked\");\n if( !this.view.c.setInputVisibility(this.n.id, inputName, visible) ) {\n // failed, reset this to old value\n $(e.target).prop('checked', !visible);\n }\n },\n\n toggleOutputVisibility: function(e) {\n var outputName = $(e.target).data('output');\n var visible = $(e.target).is(\":checked\");\n if( !this.view.c.setOutputVisibility(this.n.id, outputName, visible) ) {\n // failed, reset this to old value\n $(e.target).prop('checked', !visible);\n }\n },\n\n editNodeName: function(e) {\n this.nowEditingNodeName = true;\n },\n\n changeNodeName: function(e) {\n // user pressed enter\n if(e.which == 13 || e.keyCode == 13) {\n this.saveNodeName(e);\n }\n },\n\n saveNodeName: function(e) {\n var newId = $(e.target).parent().find('.dualbox-node-name-input').val();\n this.view.c.renameBox(this.n.graphId, newId, this.n.type);\n\n // get the new node\n switch( this.n.type ) {\n case \"input\": this.n = this.view.m.getNode(\"in-\"+newId); break;\n case \"output\": this.n = this.view.m.getNode(\"in-\"+newId); break;\n default: this.n = this.view.m.getNode(newId);\n }\n\n this.nowEditingNodeName = false;\n },\n\n toggleIterator: function(e) {\n var destInput = $(e.target).attr('data-input');\n if( $(e.target).is(\":checked\") ) {\n this.view.c.setIterator( this.n.id, destInput );\n }\n else {\n this.view.c.unsetIterator( this.n.id, destInput );\n }\n this.onEdited();\n },\n\n registerToWidget: function(e) {\n var targetId = $(e.target).val();\n this.view.c.registerWidget(this.n.id, targetId);\n },\n\n selectOutputFeedback: function(e) {\n var val = $(e.target).val();\n var destOutput = $(e.target).attr('data-output');\n if( val !== \"none\" ) {\n this.view.c.setFeedback( this.n.id, destOutput, val );\n }\n else {\n this.view.c.unsetFeedback( this.n.id, destOutput );\n }\n },\n\n removeEvent: function(e) {\n var index = parseInt($(e.target).attr('data-index'));\n this.view.c.removeEvent( this.n.id, index );\n this.$forceUpdate();\n },\n\n setEventIf: function(e) {\n var index = parseInt($(e.target).attr('data-index'));\n var val = $(e.target).val();\n this.view.c.setEventIf( this.n.id, index, val );\n },\n\n setEventData: function(e) {\n var index = parseInt($(e.target).attr('data-index'));\n var val = $(e.target).val();\n this.view.c.setEventData( this.n.id, index, val );\n },\n\n // TODO: remake this into it's own vue\n selectEventTarget: function(e) {\n var target = $(e.target).val();\n\n // change options of closest .select-event-name according to this new target\n var targetNode = this.view.m.getNode(target);\n var targetEvents = targetNode.getEventsNames();\n\n var index = parseInt($(e.target).attr('data-index'));\n this.view.c.setEventTarget( this.n.id, index, target );\n this.onEdited();\n },\n\n selectEventName: function(e) {\n var index = parseInt($(e.target).attr('data-index'));\n var val = $(e.target).val();\n this.view.c.setEventName( this.n.id, index, val );\n this.onEdited();\n },\n\n toggleCache: function(e) {\n var val = $(e.target).is(':checked');\n this.view.c.setBoxCache( this.n.id, val );\n },\n\n toggleWorker: function(e) {\n var val = $(e.target).is(':checked');\n this.view.c.setBoxParallel( this.n.id, val );\n this.isParallel = val;\n this.onEdited();\n },\n\n editModuleDescription: function(e) {\n var desc = $(e.target).attr('data-desc');\n\n swal({\n title: \"Describe what this metabox does\",\n input: \"textarea\",\n inputValue: desc || \"\",\n showCancelButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n animation: \"slide-from-top\",\n inputPlaceholder: \"This metabox...\"\n }).then( (result) => {\n if (result.value === \"\") {\n swal.showInputError(\"You need to write something!\");\n return false;\n }\n else {\n this.view.c.setMetanodeDescription(this.n.id, result.value);\n }\n });\n },\n\n createExampleNode(n) {\n return this.view.m.createCloneNode(n.getPackage().name, n.id)\n },\n\n onEditInputType(inputName, typeStr) {\n this.n.assignInputType(inputName, typeStr);\n this.onEdited();\n this.view.repaint();\n },\n\n onEditAttributeType(attributeName, typeStr) {\n this.n.assignAttributeType(attributeName, typeStr);\n this.onEdited();\n this.view.repaint();\n },\n\n onEditDefaultValue(val) {\n this.n.setDefaultValue(val);\n this.onEdited();\n this.view.repaint();\n },\n\n onEditInputDefaultValue(inputName, val) {\n if( val === undefined ) {\n this.n.deleteVal(\"input\", inputName);\n this.n.setInputVisibility(inputName, true); // show the input then (connection needed)\n }\n else {\n this.n.val(\"input\", inputName, val );\n this.n.setInputVisibility(inputName, false); // hide inputs with values (no connection needed)\n }\n this.onEdited();\n this.view.repaint();\n },\n\n onEditAttribute(attrName, val) {\n if( val === undefined ) {\n this.n.deleteVal(\"attr\", attrName);\n }\n else {\n this.n.val(\"attr\", attrName, val);\n }\n this.onEdited();\n },\n\n onEditDefaultInput(inputName, val) {\n if( val === undefined ) {\n this.n.deleteVal(\"input\", inputName);\n }\n else {\n this.n.val(\"input\", inputName, val);\n }\n this.onEdited();\n this.view.repaint();\n },\n\n onEdited() {\n // we need to refresh our node object\n this.n = this.view.m.getNode(this.id); // it breaks updating node name\n this.$forceUpdate();\n },\n\n getDataType: function(evt) {\n if( evt.datatype ) {\n return evt.datatype;\n }\n else if( evt.data ) {\n return window.DualBox.Type.detectType(evt.data);\n }\n else {\n return undefined;\n }\n },\n\n toggleAdvancedAppEventSettings: function(e) {\n var index = $(e.target).data('index');\n this.expanded[index] = this.expanded[index] ? false : true;\n this.$forceUpdate();\n },\n\n onEditEventData(key, index, val) {\n this.view.c.setEventData( this.n.id, index, val );\n this.$forceUpdate();\n },\n\n onEditEventInDataType(key, index, type) {\n this.view.c.setEventDataType( this.n.id, index, type);\n\n // check that the set value still match the new type\n // delete it otherwise\n var val = this.n.getOutboundEvents()[index].data;\n try {\n // TODO: ensure type is already loaded (after dualbox) and remove the try/catch\n if( !window.DualBox.Type.check(type, val) ) {\n // delete data (== set undefined)\n this.view.c.setEventData( this.n.id, index, undefined);\n }\n }\n catch(e) {\n this.view.c.setEventData( this.n.id, index, undefined);\n }\n\n this.$forceUpdate();\n },\n\n getDescription() {\n return this.n.getDescription() || \"[Add a description]\"\n },\n\n editDescription() {\n this.nowEditingDescription = true;\n },\n\n setDescription() {\n var val = $(this.$el).find('.edit-node-description').val();\n if( this.n.isInput() ) {\n this.view.c.setInputDescription(this.n.graphId, val);\n }\n else if( this.n.isOutput() ) {\n this.view.c.setOutputDescription(this.n.graphId, val);\n }\n else if( this.n.isMetanode() ) {\n this.view.c.setMetanodeDescription(this.n.graphId, val);\n }\n this.nowEditingDescription = false;\n\n this.$forceUpdate();\n },\n }\n}\n\n\n</script>\n"]}, media: undefined });
67981
68013
 
67982
68014
  };
67983
68015
  /* scoped */
@@ -87044,7 +87076,7 @@ __vue_render__$d._withStripped = true;
87044
87076
  /* style */
87045
87077
  const __vue_inject_styles__$d = function (inject) {
87046
87078
  if (!inject) return
87047
- inject("data-v-402f1ef4_0", { source: "\n.code-panel {\n width: 30%;\n height: 100%;\n vertical-align: top;\n float: left;\n}\n.application-container {\n width: calc(70% - 5px);\n height: 100%;\n display: inline-block;\n vertical-align: top;\n float: right;\n}\n.code-controls, .run-options {\n width: 100%;\n height: 60px;\n}\n.application {\n width: 100%;\n height: calc(100% - 60px);\n background-color: #ccc;\n}\n.dragbar {\n height: 100%;\n width: 5px;\n background-color: #e7e7e7;\n display: inline-block;\n cursor: col-resize;\n}\n.code-content {\n position: relative;\n height: calc(100% - 56px);\n}\n.code-html-container {\n position: relative;\n height: 50%;\n border-bottom: 1px solid #e7e7e7;\n}\n.code-css-container {\n position: relative;\n height: calc(50% - 1px);\n overflow: hidden;\n}\n.code-css {\n width: 100%;\n height: 100%;\n}\n.code-html {\n height: calc(100% - 40px);\n width: 100%;\n}\n.CodeMirror {\n height: 100%!important;\n}\n.code-badge {\n position: absolute;\n top: 10px;\n right: 10px;\n padding: 10px;\n}\n.btn-light.focus, .btn-light:focus {\n box-shadow: none!important;\n}\n.button-bar {\n width: 60px;\n padding: 10px;\n border-bottom: 1px solid #e7e7e7;\n width: 100%;\n background-color: white;\n}\n.noselect {\n -webkit-user-select: none; /* Chrome/Safari */\n -moz-user-select: none; /* Firefox */\n -ms-user-select: none; /* IE10+ */\n -o-user-select: none;\n user-select: none;\n}\n.btn + .btn {\n margin-left: 5px;\n}\n.btn-graph-goto {\n box-shadow: none!important;\n}\n.nav-tabs {\n border-bottom: none;\n}\n.main-navigation a.nav-link {\n color: white;\n}\n.main-navigation a.nav-link.active {\n color: #212529;\n}\n.dualbox-editor-body {\n width: 100%;\n height: 100%;\n overflow: hidden;\n background-color: rgb(85, 85, 85);\n}\n.dualbox-graph-left-section {\n height: 100%;\n width: 500px;\n float: left;\n position: relative;\n overflow: hidden;\n margin-left: -465px;\n transition: margin-left 0.3s ease;\n}\n.dualbox-graph-left-window {\n width: calc(100% - 35px);\n height: calc(100% - 20px);\n margin-top: 10px;\n margin-bottom: 30px;\n /* background-color: #ECF2F8; */\n background-color: #f8f9fa;\n /* border: 1px solid grey; */\n border-radius: 5px;\n position: relative;\n float: left;\n}\n.dualbox-graph-left-panel {\n width: 100%;\n height: 100%;\n}\n.btn-toggle-left-window {\n position: absolute;\n right: 0;\n top: 0;\n margin-right: -35px;\n z-index: 100;\n border-top-left-radius: 0px;\n border-bottom-left-radius: 0px;\n}\n.btn-toggle-left-window:hover, .btn-toggle-right-window:hover, .btn-toggle-left-window:focus, .btn-toggle-right-window:focus, .btn-toggle-left-window:active, .btn-toggle-right-window:active, .btn-toggle-left-window:active:hover, .btn-toggle-right-window:active:hover {\n color: #212529!important;\n background-color: #f8f9fa!important;\n border-color: #f8f9fa!important;\n}\n.dualbox-graph-right-section {\n height: 100%;\n width: 500px;\n float: right;\n position: relative;\n overflow: hidden;\n margin-right: -465px;\n transition: margin-right 0.3s ease;\n}\n.dualbox-graph-right-window {\n width: calc(100% - 35px);\n height: calc(100% - 20px);\n margin-top: 10px;\n margin-bottom: 30px;\n /* background-color: #ECF2F8; */\n background-color: #f8f9fa;\n /* border: 1px solid grey; */\n border-radius: 5px;\n position: relative;\n float: right;\n}\n.dualbox-graph-right-panel {\n width: 100%;\n height: 100%;\n}\n.btn-toggle-right-window {\n position: absolute;\n left: 0;\n top: 0;\n margin-left: -35px;\n z-index: 100;\n border-top-right-radius: 0px;\n border-bottom-right-radius: 0px;\n}\n.dualbox-graph-tab {\n height: 100%;\n width: 100%;\n background-color: #555!important;\n}\n.dualbox-graph-main {\n height: 100%;\n width: calc(100% - 70px);\n float: right;\n background-color: #555!important;\n transition: width 0.3s ease;\n}\n.dualbox-graph-main.left-panel-expanded {\n width: calc(100% - 535px);\n margin-left: -465px;\n}\n.dualbox-graph-main.right-panel-expanded {\n width: calc(100% - 535px);\n}\n.dualbox-graph-main.left-panel-expanded.right-panel-expanded {\n width: calc(100% - 1000px);\n margin-left: -465px;\n}\n.opacity0 {\n opacity: 0;\n}\n.btn-editor-xs {\n width: 18px;\n padding : 3px!important;\n line-height : .5;\n border-radius : 2px;\n}\n.btn-editor-xs > i {\n font-size : 10px;\n}\n.btn-outline-discrete {\n border-color: rgba(0,0,0,0.05);\n border-color: transparent;\n color: rgba(0,0,0,0.3);\n}\n.dualbox-app-navigation {\n background-color: transparent;\n margin-bottom: 0;\n vertical-align: middle;\n padding-top: 7px;\n padding-bottom: 7px;\n font-weight: bold;\n user-select: none;\n}\n.app-topbar {\n border-bottom: none;\n padding-left: 15px;\n padding-right: 15px;\n display: flex;\n width: 100%;\n height: 58px;\n padding-top: 10px;\n padding-bottom: 10px;\n}\n.dark, .graph-tab.active, .nav-item.active .graph-tab {\n color: white!important;\n background-color: #555!important;\n}\n.light {\n color: #4d4d4d!important;\n background-color: #f8f9fa!important;\n}\n.main-navigation .nav-link, .main-navigation .nav-link.active, .nav-item.active .nav-link {\n border-bottom: none;\n border-left: none;\n border-top: none;\n border-right: none;\n position: relative;\n top: 1px;\n}\n.btn:focus, button:focus {\n outline: none;\n box-shadow: none;\n}\n.btn-transparent, .btn-transparent:hover, .btn-transparent:focus {\n background-color: transparent;\n}\n.connection-control {\n position: absolute;\n height: 14px;\n width: 14px;\n background-color: transparent;\n z-index: 19;\n cursor: move;\n}\n.connection-control.selected {\n border-color: #0066ff;\n box-shadow: 1px 1px 10px #0066ff;\n}\n.connection-label {\n z-index: 22!important;\n color: #004d00!important;\n background-color: white!important;\n padding: 4px 4px;\n border: 2px solid #004d00;\n font-size: 16px!important;\n border-radius: 5px;\n}\n.input-color-tag {\n background-color: #F2D600;\n}\n.output-color-tag {\n background-color: #FFAB4A;\n}\n.ui-color-tag {\n background-color: #61BD4F;\n}\n.metanode-color-tag {\n background-color: #DDDDDD;\n}\n.input {\n}\n.output {\n}\n.fileUpload {\n position: relative;\n overflow: hidden;\n margin: 10px;\n}\n.fileUpload input.upload {\n position: absolute;\n top: 0;\n right: 0;\n margin: 0;\n padding: 0;\n font-size: 20px;\n cursor: pointer;\n opacity: 0;\n filter: alpha(opacity=0);\n}\n.module-edit-modal-body .btn+.btn {\n margin-bottom: 0;\n margin-left: 5px;\n}\n.btn-add-node {\n width:46%;\n margin:1%;\n}\nbutton.close {\n position: absolute;\n right: 0;\n margin-right: 5px!important;\n}\n.CodeMirror {\n height: auto;\n min-height: 300px;\n}\n.load-app, .save-app {\n margin-left: 5px;\n margin-right: 5px;\n}\n.btn-xs {\n padding: 0px 4px;\n font-size: 12px;\n}\n", map: {"version":3,"sources":["/home/seb/dev/dualbox/editor/js/src/v/templates/main.vue"],"names":[],"mappings":";AACA;IACA,UAAA;IACA,YAAA;IACA,mBAAA;IACA,WAAA;AACA;AAEA;IACA,sBAAA;IACA,YAAA;IACA,qBAAA;IACA,mBAAA;IACA,YAAA;AACA;AAEA;IACA,WAAA;IACA,YAAA;AACA;AAEA;IACA,WAAA;IACA,yBAAA;IACA,sBAAA;AACA;AAEA;IACA,YAAA;IACA,UAAA;IACA,yBAAA;IACA,qBAAA;IACA,kBAAA;AACA;AAEA;IACA,kBAAA;IACA,yBAAA;AACA;AAEA;IACA,kBAAA;IACA,WAAA;IACA,gCAAA;AACA;AAEA;IACA,kBAAA;IACA,uBAAA;IACA,gBAAA;AACA;AAEA;IACA,WAAA;IACA,YAAA;AACA;AAEA;IACA,yBAAA;IACA,WAAA;AACA;AAEA;IACA,sBAAA;AACA;AAEA;IACA,kBAAA;IACA,SAAA;IACA,WAAA;IACA,aAAA;AACA;AAEA;IACA,0BAAA;AACA;AAEA;IACA,WAAA;IACA,aAAA;IACA,gCAAA;IACA,WAAA;IACA,uBAAA;AACA;AAEA;IACA,yBAAA,EAAA,kBAAA;IACA,sBAAA,EAAA,YAAA;IACA,qBAAA,EAAA,UAAA;IACA,oBAAA;IACA,iBAAA;AACA;AAEA;IACA,gBAAA;AACA;AAEA;IACA,0BAAA;AACA;AAEA;IACA,mBAAA;AACA;AAEA;IACA,YAAA;AACA;AAEA;IACA,cAAA;AACA;AAEA;IACA,WAAA;IACA,YAAA;IACA,gBAAA;IACA,iCAAA;AACA;AAEA;IACA,YAAA;IACA,YAAA;IACA,WAAA;IACA,kBAAA;IACA,gBAAA;IACA,mBAAA;IACA,iCAAA;AACA;AAEA;IACA,wBAAA;IACA,yBAAA;IACA,gBAAA;IACA,mBAAA;IACA,+BAAA;IACA,yBAAA;IACA,4BAAA;IACA,kBAAA;IACA,kBAAA;IACA,WAAA;AACA;AAEA;IACA,WAAA;IACA,YAAA;AACA;AAEA;IACA,kBAAA;IACA,QAAA;IACA,MAAA;IACA,mBAAA;IACA,YAAA;IACA,2BAAA;IACA,8BAAA;AACA;AAEA;IACA,wBAAA;IACA,mCAAA;IACA,+BAAA;AACA;AAEA;IACA,YAAA;IACA,YAAA;IACA,YAAA;IACA,kBAAA;IACA,gBAAA;IACA,oBAAA;IACA,kCAAA;AACA;AAEA;IACA,wBAAA;IACA,yBAAA;IACA,gBAAA;IACA,mBAAA;IACA,+BAAA;IACA,yBAAA;IACA,4BAAA;IACA,kBAAA;IACA,kBAAA;IACA,YAAA;AACA;AAEA;IACA,WAAA;IACA,YAAA;AACA;AAEA;IACA,kBAAA;IACA,OAAA;IACA,MAAA;IACA,kBAAA;IACA,YAAA;IACA,4BAAA;IACA,+BAAA;AACA;AAEA;IACA,YAAA;IACA,WAAA;IACA,gCAAA;AACA;AAEA;IACA,YAAA;IACA,wBAAA;IACA,YAAA;IACA,gCAAA;IACA,2BAAA;AACA;AAEA;IACA,yBAAA;IACA,mBAAA;AACA;AAEA;IACA,yBAAA;AACA;AAEA;IACA,0BAAA;IACA,mBAAA;AACA;AAEA;IACA,UAAA;AACA;AAEA;IACA,WAAA;IACA,wBAAA;IACA,iBAAA;IACA,mBAAA;AACA;AAEA;IACA,iBAAA;AACA;AAEA;IACA,8BAAA;IACA,yBAAA;IACA,sBAAA;AACA;AAEA;IACA,6BAAA;IACA,gBAAA;IACA,sBAAA;IACA,gBAAA;IACA,mBAAA;IACA,iBAAA;IACA,iBAAA;AACA;AAEA;IACA,mBAAA;IACA,kBAAA;IACA,mBAAA;IACA,aAAA;IACA,WAAA;IACA,YAAA;IACA,iBAAA;IACA,oBAAA;AACA;AAEA;IACA,sBAAA;IACA,gCAAA;AACA;AAEA;IACA,wBAAA;IACA,mCAAA;AACA;AAEA;IACA,mBAAA;IACA,iBAAA;IACA,gBAAA;IACA,kBAAA;IACA,kBAAA;IACA,QAAA;AACA;AAEA;IACA,aAAA;IACA,gBAAA;AACA;AAEA;IACA,6BAAA;AACA;AAEA;IACA,kBAAA;IACA,YAAA;IACA,WAAA;IACA,6BAAA;IACA,WAAA;IACA,YAAA;AACA;AAEA;IACA,qBAAA;IACA,gCAAA;AACA;AAEA;IACA,qBAAA;IACA,wBAAA;IACA,iCAAA;IACA,gBAAA;IACA,yBAAA;IACA,yBAAA;IACA,kBAAA;AACA;AAEA;IACA,yBAAA;AACA;AAEA;IACA,yBAAA;AACA;AAEA;IACA,yBAAA;AACA;AAEA;IACA,yBAAA;AACA;AAEA;AACA;AAEA;AACA;AAGA;IACA,kBAAA;IACA,gBAAA;IACA,YAAA;AACA;AACA;IACA,kBAAA;IACA,MAAA;IACA,QAAA;IACA,SAAA;IACA,UAAA;IACA,eAAA;IACA,eAAA;IACA,UAAA;IACA,wBAAA;AACA;AAGA;IACA,gBAAA;IACA,gBAAA;AACA;AAEA;IACA,SAAA;IACA,SAAA;AACA;AAEA;IACA,kBAAA;IACA,QAAA;IACA,2BAAA;AACA;AAEA;IACA,YAAA;IACA,iBAAA;AACA;AAEA;IACA,gBAAA;IACA,iBAAA;AACA;AAEA;IACA,gBAAA;IACA,eAAA;AACA","file":"main.vue","sourcesContent":["<style>\n .code-panel {\n width: 30%;\n height: 100%;\n vertical-align: top;\n float: left;\n }\n\n .application-container {\n width: calc(70% - 5px);\n height: 100%;\n display: inline-block;\n vertical-align: top;\n float: right;\n }\n\n .code-controls, .run-options {\n width: 100%;\n height: 60px;\n }\n\n .application {\n width: 100%;\n height: calc(100% - 60px);\n background-color: #ccc;\n }\n\n .dragbar {\n height: 100%;\n width: 5px;\n background-color: #e7e7e7;\n display: inline-block;\n cursor: col-resize;\n }\n\n .code-content {\n position: relative;\n height: calc(100% - 56px);\n }\n\n .code-html-container {\n position: relative;\n height: 50%;\n border-bottom: 1px solid #e7e7e7;\n }\n\n .code-css-container {\n position: relative;\n height: calc(50% - 1px);\n overflow: hidden;\n }\n\n .code-css {\n width: 100%;\n height: 100%;\n }\n\n .code-html {\n height: calc(100% - 40px);\n width: 100%;\n }\n\n .CodeMirror {\n height: 100%!important;\n }\n\n .code-badge {\n position: absolute;\n top: 10px;\n right: 10px;\n padding: 10px;\n }\n\n .btn-light.focus, .btn-light:focus {\n box-shadow: none!important;\n }\n\n .button-bar {\n width: 60px;\n padding: 10px;\n border-bottom: 1px solid #e7e7e7;\n width: 100%;\n background-color: white;\n }\n\n .noselect {\n -webkit-user-select: none; /* Chrome/Safari */\n -moz-user-select: none; /* Firefox */\n -ms-user-select: none; /* IE10+ */\n -o-user-select: none;\n user-select: none;\n }\n\n .btn + .btn {\n margin-left: 5px;\n }\n\n .btn-graph-goto {\n box-shadow: none!important;\n }\n\n .nav-tabs {\n border-bottom: none;\n }\n\n .main-navigation a.nav-link {\n color: white;\n }\n\n .main-navigation a.nav-link.active {\n color: #212529;\n }\n\n .dualbox-editor-body {\n width: 100%;\n height: 100%;\n overflow: hidden;\n background-color: rgb(85, 85, 85);\n }\n\n .dualbox-graph-left-section {\n height: 100%;\n width: 500px;\n float: left;\n position: relative;\n overflow: hidden;\n margin-left: -465px;\n transition: margin-left 0.3s ease;\n }\n\n .dualbox-graph-left-window {\n width: calc(100% - 35px);\n height: calc(100% - 20px);\n margin-top: 10px;\n margin-bottom: 30px;\n /* background-color: #ECF2F8; */\n background-color: #f8f9fa;\n /* border: 1px solid grey; */\n border-radius: 5px;\n position: relative;\n float: left;\n }\n\n .dualbox-graph-left-panel {\n width: 100%;\n height: 100%;\n }\n\n .btn-toggle-left-window {\n position: absolute;\n right: 0;\n top: 0;\n margin-right: -35px;\n z-index: 100;\n border-top-left-radius: 0px;\n border-bottom-left-radius: 0px;\n }\n\n .btn-toggle-left-window:hover, .btn-toggle-right-window:hover, .btn-toggle-left-window:focus, .btn-toggle-right-window:focus, .btn-toggle-left-window:active, .btn-toggle-right-window:active, .btn-toggle-left-window:active:hover, .btn-toggle-right-window:active:hover {\n color: #212529!important;\n background-color: #f8f9fa!important;\n border-color: #f8f9fa!important;\n }\n\n .dualbox-graph-right-section {\n height: 100%;\n width: 500px;\n float: right;\n position: relative;\n overflow: hidden;\n margin-right: -465px;\n transition: margin-right 0.3s ease;\n }\n\n .dualbox-graph-right-window {\n width: calc(100% - 35px);\n height: calc(100% - 20px);\n margin-top: 10px;\n margin-bottom: 30px;\n /* background-color: #ECF2F8; */\n background-color: #f8f9fa;\n /* border: 1px solid grey; */\n border-radius: 5px;\n position: relative;\n float: right;\n }\n\n .dualbox-graph-right-panel {\n width: 100%;\n height: 100%;\n }\n\n .btn-toggle-right-window {\n position: absolute;\n left: 0;\n top: 0;\n margin-left: -35px;\n z-index: 100;\n border-top-right-radius: 0px;\n border-bottom-right-radius: 0px;\n }\n\n .dualbox-graph-tab {\n height: 100%;\n width: 100%;\n background-color: #555!important;\n }\n\n .dualbox-graph-main {\n height: 100%;\n width: calc(100% - 70px);\n float: right;\n background-color: #555!important;\n transition: width 0.3s ease;\n }\n\n .dualbox-graph-main.left-panel-expanded {\n width: calc(100% - 535px);\n margin-left: -465px;\n }\n\n .dualbox-graph-main.right-panel-expanded {\n width: calc(100% - 535px);\n }\n\n .dualbox-graph-main.left-panel-expanded.right-panel-expanded {\n width: calc(100% - 1000px);\n margin-left: -465px;\n }\n\n .opacity0 {\n opacity: 0;\n }\n\n .btn-editor-xs {\n width: 18px;\n padding : 3px!important;\n line-height : .5;\n border-radius : 2px;\n }\n\n .btn-editor-xs > i {\n font-size : 10px;\n }\n\n .btn-outline-discrete {\n border-color: rgba(0,0,0,0.05);\n border-color: transparent;\n color: rgba(0,0,0,0.3);\n }\n\n .dualbox-app-navigation {\n background-color: transparent;\n margin-bottom: 0;\n vertical-align: middle;\n padding-top: 7px;\n padding-bottom: 7px;\n font-weight: bold;\n user-select: none;\n }\n\n .app-topbar {\n border-bottom: none;\n padding-left: 15px;\n padding-right: 15px;\n display: flex;\n width: 100%;\n height: 58px;\n padding-top: 10px;\n padding-bottom: 10px;\n }\n\n .dark, .graph-tab.active, .nav-item.active .graph-tab {\n color: white!important;\n background-color: #555!important;\n }\n\n .light {\n color: #4d4d4d!important;\n background-color: #f8f9fa!important;\n }\n\n .main-navigation .nav-link, .main-navigation .nav-link.active, .nav-item.active .nav-link {\n border-bottom: none;\n border-left: none;\n border-top: none;\n border-right: none;\n position: relative;\n top: 1px;\n }\n\n .btn:focus, button:focus {\n outline: none;\n box-shadow: none;\n }\n\n .btn-transparent, .btn-transparent:hover, .btn-transparent:focus {\n background-color: transparent;\n }\n\n .connection-control {\n position: absolute;\n height: 14px;\n width: 14px;\n background-color: transparent;\n z-index: 19;\n cursor: move;\n }\n\n .connection-control.selected {\n border-color: #0066ff;\n box-shadow: 1px 1px 10px #0066ff;\n }\n\n .connection-label {\n z-index: 22!important;\n color: #004d00!important;\n background-color: white!important;\n padding: 4px 4px;\n border: 2px solid #004d00;\n font-size: 16px!important;\n border-radius: 5px;\n }\n\n .input-color-tag {\n background-color: #F2D600;\n }\n\n .output-color-tag {\n background-color: #FFAB4A;\n }\n\n .ui-color-tag {\n background-color: #61BD4F;\n }\n\n .metanode-color-tag {\n background-color: #DDDDDD;\n }\n\n .input {\n }\n\n .output {\n }\n\n\n .fileUpload {\n position: relative;\n overflow: hidden;\n margin: 10px;\n }\n .fileUpload input.upload {\n position: absolute;\n top: 0;\n right: 0;\n margin: 0;\n padding: 0;\n font-size: 20px;\n cursor: pointer;\n opacity: 0;\n filter: alpha(opacity=0);\n }\n\n\n .module-edit-modal-body .btn+.btn {\n margin-bottom: 0;\n margin-left: 5px;\n }\n\n .btn-add-node {\n width:46%;\n margin:1%;\n }\n\n button.close {\n position: absolute;\n right: 0;\n margin-right: 5px!important;\n }\n\n .CodeMirror {\n height: auto;\n min-height: 300px;\n }\n\n .load-app, .save-app {\n margin-left: 5px;\n margin-right: 5px;\n }\n\n .btn-xs {\n padding: 0px 4px;\n font-size: 12px;\n }\n</style>\n\n<template>\n <div class=\"dualbox-editor-body\">\n <nav class=\"main-navigation navbar navbar-default\" style=\"position: relative; margin-bottom: 0px; padding: 0; padding-top: 5px; background-color: #2e6da4;\">\n <ul class=\"nav nav-tabs\">\n <li class=\"nav-item active\">\n <a class=\"nav-link graph-tab\" href=\"#editor-graph-tab\" data-toggle=\"tab\">Application Graph</a>\n </li>\n <li class=\"nav-item\">\n <a class=\"nav-link interface-tab\" href=\"#editor-interface-tab\" data-toggle=\"tab\">Interface Editor</a>\n </li>\n </ul>\n\n <div class=\"nav navbar-right\" style=\"vertical-align: top; margin-top: 5px; margin-right: 10px; margin-bottom: 5px;\">\n <div v-if=\"showLoadButton === true\">\n <button class=\"load-app btn btn-sm btn-light\" style=\"position: relative; bottom: 3px;\" @click=\"loadApp\">Load App</button>\n </div>\n <div v-if=\"showSaveButton\">\n <button class=\"save-app btn btn-sm btn-light\" style=\"position: relative; bottom: 3px;\" @click=\"saveApp\">Save App</button>\n </div>\n </div>\n </nav>\n <div class=\"tab-content dualbox-graph-tab\" style=\"width: 100%; height: calc(100% - 46px);\">\n <div class=\"tab-pane active\" id=\"editor-graph-tab\" style=\"width: 100%; height: 100%;\">\n <div class=\"dualbox-graph-left-section dark\">\n <div class=\"dualbox-graph-left-window\">\n <button class=\"btn btn-light btn-toggle-left-window\" @click=\"toggleLeftWindow\" title=\"shrink window\" data-expanded=\"false\"><i class=\"fa fa-angle-double-right\"></i></button>\n <div class=\"dualbox-graph-left-panel light\">\n <edit-node-settings v-if=\"leftPanelMode == 'node' && selectedNodeId !== null\" :id=\"selectedNodeId\" :key=\"selectedNodeId\"></edit-node-settings>\n <edit-main-settings v-else-if=\"leftPanelMode == 'main'\" :app=\"getCurrentApplication()\" @edited=\"onEdited()\"></edit-main-settings>\n </div>\n </div>\n </div>\n <div class=\"dualbox-graph-right-section dark\">\n <div class=\"dualbox-graph-right-window\">\n <button class=\"btn btn-light btn-toggle-right-window\" @click=\"toggleRightWindow\" title=\"shrink window\" data-expanded=\"false\"><i class=\"fa fa-angle-double-left\"></i></button>\n <div class=\"dualbox-graph-right-panel light\">\n <debug-node-infos v-if=\"debugNodeId !== null\" :id=\"debugNodeId\"></debug-node-infos>\n </div>\n </div>\n </div>\n <div class=\"container-fluid dualbox-graph-main\" @click=\"setMainMenu\">\n <div class=\"row\">\n <div class=\"app-topbar dark\">\n <div class=\"justify-content-left\">\n <div class=\"dropdown\">\n <button class=\"btn btn-primary dropdown-toggle d-none\" type=\"button\" id=\"add-node-dropdown\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\" style=\"margin-right: 5px;\">\n Add\n </button>\n <div class=\"dropdown-menu\" aria-labelledby=\"add-node-dropdown\">\n <a class=\"dropdown-item add-box\" @click=\"addBox\" href=\"#\">Add box</a>\n <a class=\"dropdown-item add-metabox\" @click=\"addMetabox\" href=\"#\">Add metabox</a>\n <a class=\"dropdown-item add-input\" @click=\"addInput\" href=\"#\">Add input</a>\n <a class=\"dropdown-item add-output\" @click=\"addOutput\" href=\"#\">Add output</a>\n <a class=\"dropdown-item import-metabox\" @click=\"importMetabox\" href=\"#\">Import metabox</a>\n </div>\n <button class=\"btn btn-light btn-undo\" title=\"undo (ctrl-z)\" @click=\"undo\"><i class=\"fa fa-undo\"></i></button>\n <button class=\"btn btn-light btn-redo\" title=\"redo (ctrl-y)\" @click=\"redo\"><i class=\"fa fa-repeat fa-redo\"></i></button>\n <div class=\"form-check d-inline-block ml-2\">\n <label class=\"form-check-label\">\n <input class=\"form-check-input show-events\" type=\"checkbox\" value=\"false\" @click=\"showEvents\">\n <span class=\"noselect\">Show events</span>\n </label>\n </div>\n </div>\n </div>\n\n <div class=\"justify-content-center mx-auto\">\n <ol class=\"dualbox-app-navigation breadcrumb\"></ol>\n </div>\n\n <div class=\"justify-content-right\">\n <div class=\"dropdown selection-menu\" style=\"display: none;\">\n <button class=\"btn btn-primary dropdown-toggle\" type=\"button\" id=\"selection-dropdown\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">\n Selection\n </button>\n <div class=\"dropdown-menu dropdown-menu-right\" aria-labelledby=\"add-node-dropdown\">\n <a class=\"dropdown-item dualbox-merge-selection\" @click=\"mergeSelection\" href=\"#\">Merge</a>\n <a class=\"dropdown-item dualbox-remove-selection\" @click=\"removeSelection\" href=\"#\" style=\"color: red;\">Delete</a>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"row\" style=\"height: calc(100% - 58px);\">\n <graph-vue :app=\"app\" ref=\"graph\"></graph-vue>\n </div>\n </div>\n </div>\n <div class=\"tab-pane\" id=\"editor-interface-tab\" style=\"width 100%; height: 100%; background-color: white;\">\n <div class=\"db-editor-main\" style=\"width: 100%; height: 100%; overflow: hidden;\">\n <div class=\"code-panel\">\n <div class=\"button-bar form-inline code-controls\" style=\"position: relative;\">\n <button class=\"btn btn-primary btn-save-interface-element\" @click=\"saveInterfaceElement\">Save changes</button>\n </div>\n <div class=\"code-content\">\n <div class=\"code-html-container\">\n <div style=\"padding-top: 5px; padding-bottom: 5px; height: 50px; position: relative;\">\n <h3 style=\"position: absolute; top: 0; margin: 5px; font-size: 16px; z-index: 100; display: inline-block; margin-top: 5px;\">HTML</h3>\n <div class=\"d-inline-block ml-auto form-inline mr-2 mt-2\" style=\"position: absolute; top: 0; right: 0;\">\n <button class=\"btn btn-success btn-sm btn-add-interface\" @click=\"addInterface\"><i class=\"fas fa-plus\"></i></button>\n <select class=\"form-control btn-sm app-interface-select\" @change=\"selectInterface\" style=\"width: 150px; height: 32px;\">\n <option>Load UI...</option>\n <option v-for=\"interfaceName in getInterfacesNames()\" :value=\"interfaceName\">{{interfaceName}}</option>\n </select>\n <button class=\"btn btn-sm btn-light btn-edit-panel-description\" @click=\"editPanelDescription\"><i class=\"fas fa-info\" style=\"padding-left: 8px; padding-right: 8px;\"></i></button>\n <button class=\"btn btn-danger btn-sm btn-remove-interface\" @click=\"removeInterface\"><i class=\"fas fa-minus\"></i></button>\n </div>\n </div>\n <div class=\"code-html-text-container\" style=\"position: relative; height: calc(100% - 50px);\">\n <textarea class=\"code-html\"></textarea>\n </div>\n </div>\n <div class=\"code-css-container\">\n <div style=\"height: 30px;\">\n <h3 style=\"position: absolute; top: 0; margin: 5px; font-size: 16px; z-index: 100;\">CSS</h3>\n </div>\n <div class=\"colde-css-text-container\" style=\"position: relative; height: calc(100% - 30px);\">\n <textarea class=\"code-css\" v-model=\"appCss\"></textarea>\n </div>\n </div>\n </div>\n </div>\n <div class=\"dragbar\"></div>\n <div class=\"application-container\">\n <div class=\"button-bar form-inline run-options\" style=\"position: relative;\">\n <button class=\"btn btn-success btn-run mr-2\" @click=\"runApp\">Run</button>\n\n <select class=\"form-control run-loglevel mr-1 ml-2\">\n <option>error</option>\n <option>warn</option>\n <option>info</option>\n <option>log</option>\n <option>debug</option>\n </select>\n\n <input class=\"form-control run-noversioncheck mr-1 ml-3\" type=\"checkbox\" checked>No version checking</input>\n <input class=\"form-control run-removetrycatch mr-1 ml-3\" type=\"checkbox\">Remove Try/catch</input>\n <input class=\"form-control run-makesynchrone mr-1 ml-3\" type=\"checkbox\">Make Synchrone</input>\n\n <div class=\"ml-auto\">\n <input class=\"form-control run-profiler mr-1 ml-3\" type=\"checkbox\">Profiler</input>\n <input class=\"form-control run-record mr-1 ml-3\" type=\"checkbox\">Record</input>\n <button class=\"btn btn-secondary btn-snapshot\" @click=\"takeAndLoadSnapshot\">Snapshot</button>\n </div>\n </div>\n <div class=\"application capture-left-click capture-right-click\"></div>\n </div>\n </div>\n </div>\n </div>\n <add-node-vue :display=\"this.addingBox\" :mousePosition=\"this.newBoxPosition\" @closed=\"onAddBoxClosed\"></add-node-vue>\n </div>\n</template>\n\n<script>\nimport _ from 'lodash';\nimport swal from 'sweetalert2';\n\nimport graphVue from './graph.vue';\nimport addNodeVue from './addNode.vue';\nimport editMainSettingsVue from './editMainSettings.vue';\nimport editNodeSettingsVue from './editNodeSettings.vue';\nimport debugNodeInfosVue from './debugNodeInfos.vue';\n\n// CodeMirror\nimport CodeMirror from 'codemirror/lib/codemirror.js';\nimport 'codemirror/mode/xml/xml.js';\nimport 'codemirror/mode/css/css.js';\nimport 'codemirror/mode/javascript/javascript.js';\nimport 'codemirror/mode/htmlmixed/htmlmixed.js';\n\nimport htmltool from '@dualbox/dualbox-lib-htmltool';\n\nexport default {\n props: [\n 'app', // the app\n\n // Display configuration (online or offline ?)\n 'showLoadButton',\n 'showSaveButton',\n 'saveButtonFunction',\n\n // modes\n 'eventVisibility' // are events visible\n ],\n components: {\n 'graph-vue': graphVue,\n 'add-node-vue' : addNodeVue,\n 'edit-main-settings' : editMainSettingsVue,\n 'edit-node-settings' : editNodeSettingsVue,\n 'debug-node-infos' : debugNodeInfosVue,\n },\n data () {\n return {\n // modes\n addingBox : false,\n leftPanelMode : 'main', // 'main' to display main menu, 'node' for a node\n selectedNodeId : null, // id of the node to display in left menu\n debugNodeId: null, // on a snapshot, id of the node to display debug infos\n newBoxPosition: null, // track mouse position relative to the graph when adding a node\n\n // the specific app css\n appCss: \"\",\n }\n },\n created: function() {\n this.view = window.dualboxEditor.v;\n // TODO: restore this when all menus are migrated to Vue.js\n\n this.cssCode = null;\n this.htmlCode = null;\n },\n updated: function() {\n //console.log('updating main view with: ' + JSON.stringify(this.app));\n this.appCss = (this.app && this.app.css) || \"\";\n\n // Update html and css code editor\n this.updateCode();\n },\n mounted: function() {\n //this.view.setMainMenu();\n\n $(this.$el).bind('expandSettings', function(e) {\n // expand\n $(this).find('.dualbox-graph-left-section').css('margin-left', '0');\n $(this).find('.dualbox-graph-main').addClass('left-panel-expanded');\n $(this).find('.btn-toggle-left-window').data('expanded', true).find('i')\n .removeClass('fa-angle-double-right')\n .addClass('fa-angle-double-left')\n .attr('title', 'shrink window');\n });\n\n $(this.$el).bind('shrinkSettings', function(e) {\n // shrink\n $(this).find('.dualbox-graph-left-section').css('margin-left', '-465px');\n $(this).find('.dualbox-graph-main').removeClass('left-panel-expanded');\n $(this).find('.btn-toggle-left-window').data('expanded', false).find('i')\n .removeClass('fa-angle-double-left')\n .addClass('fa-angle-double-right')\n .attr('title', 'expand window');\n });\n\n $(this.$el).bind('expandDebug', function(e) {\n // expand\n $(this).find('.dualbox-graph-right-section').css('margin-right', '0');\n $(this).find('.dualbox-graph-main').addClass('right-panel-expanded');\n $(this).find('.btn-toggle-right-window').data('expanded', true).find('i')\n .removeClass('fa-angle-double-left')\n .addClass('fa-angle-double-right')\n .attr('title', 'shrink window');\n });\n\n $(this.$el).bind('shrinkDebug', function(e) {\n // shrink\n $(this).find('.dualbox-graph-right-section').css('margin-right', '-465px');\n $(this).find('.dualbox-graph-main').removeClass('right-panel-expanded');\n $(this).find('.btn-toggle-right-window').data('expanded', false).find('i')\n .removeClass('fa-angle-double-right')\n .addClass('fa-angle-double-left')\n .attr('title', 'expand window');\n });\n\n // bind tabs\n var self = this;\n $(this.$el).find(\"a[data-toggle='tab']\").on(\"shown.bs.tab\", function(e) {\n var target = $(e.target).attr(\"href\") // activated tab\n if( target == \"#editor-graph-tab\" ) {\n self.view.killApp();\n }\n else if( target == \"#editor-interface-tab\" ) {\n self.htmlCode.refresh();\n self.cssCode.refresh();\n self.view.runApp( self.getOptions() );\n }\n });\n\n $(this.$el).find(\"a[data-toggle='tab']\").on('click', function (e) {\n e.preventDefault()\n $(this).tab('show')\n });\n\n // Update html and css code editor\n this.updateCode();\n\n // Resize horizontally\n $(this.$el).find('.dragbar').mousedown(function(e){\n e.preventDefault();\n $(document).mouseup(function(e){\n $(document).unbind('mousemove');\n });\n $(document).mousemove(function(e){\n $('.code-panel').css('width', e.pageX + \"px\");\n $('.application-container').css('width', ($(\".db-editor-main\").width() - e.pageX - 5) + \"px\");\n })\n });\n\n },\n methods: {\n \"getOptions\": function() {\n return {\n profiler : $(this.$el).find('.run-profiler').is(':checked'),\n logLevel : $(this.$el).find('.run-loglevel').val(),\n options : {\n noVersionCheck: $(this.$el).find('.run-noversioncheck').is(':checked'),\n debug: {\n removeTryCatch: $(this.$el).find('.run-removetrycatch').is(':checked'),\n makeSynchrone: $(this.$el).find('.run-makesynchrone').is(':checked'),\n record: $(this.$el).find('.run-record').is(':checked'),\n }\n }\n }\n },\n\n \"updateCode\": function() {\n // instanciate codemirror for html and css\n if( !this.htmlCode ) {\n this.htmlCode = CodeMirror.fromTextArea( $(this.$el).find(\".code-html\")[0], {\n lineNumbers: true,\n mode : \"htmlmixed\",\n lineWrapping: true\n });\n }\n if( !this.cssCode ) {\n this.cssCode = CodeMirror.fromTextArea( $(this.$el).find(\".code-css\")[0], {\n lineNumbers: true,\n mode : \"css\",\n lineWrapping: true\n });\n }\n this.cssCode.setValue(this.view.m.get().css || \"\");\n },\n\n \"loadApp\" : function() {\n var self = this;\n\n // create a fake input and click it to select a file\n var input = $('<input/>', { \"type\": \"file\", \"class\": \"upload\", \"accept\" : \".json\" });\n input.change( function(e) {\n // if we're not here, go to 1st tab\n $(\"a[data-toggle='tab'][href='#1']\").click();\n\n // parse the file JSON and load it\n var files = e.target.files; // FileList object\n var r = new FileReader();\n r.onload = function(e) {\n var contents = e.target.result;\n var json = JSON.parse(contents);\n self.view.e.setApp(json);\n };\n\n r.readAsText(files[0]);\n });\n input.click();\n },\n \"saveApp\": function() {\n // bind the app load\n if( this.saveButtonFunction ) {\n var saveButtonFunction = (e) => {\n var json = this.view.m.getCleanJson();\n return this.saveButtonFunction(json);\n }\n }\n else {\n var saveButtonFunction = (e) => {\n var app = this.view.m.getCleanJson();\n var text = JSON.stringify(app, null, 2);\n var blob = new Blob([text], { \"type\" : \"application/octet-stream\" });\n\n var a = document.createElement('a');\n a.href = window.URL.createObjectURL(blob);\n a.download = \"app.json\";\n\n // simulate a click on the link\n if (document.createEvent) {\n var event = document.createEvent(\"MouseEvents\");\n event.initEvent(\"click\", true, true);\n a.dispatchEvent(event);\n } else {\n a.click();\n }\n }\n }\n saveButtonFunction();\n },\n \"getCurrentMousePosition\": function(e) {\n return this.$refs.graph.getCurrentMousePosition(e);\n },\n \"addBox\" : function(e) {\n this.addingBox = true;\n this.newBoxPosition = this.getCurrentMousePosition(e);\n this.$forceUpdate();\n },\n \"onAddBoxClosed\" : function() {\n this.addingBox = false;\n this.$forceUpdate();\n },\n \"addMetabox\" : function(e) {\n var self = this;\n e.preventDefault();\n e.stopPropagation();\n\n swal({\n input: 'text',\n title: 'Choose a name for the metabox',\n }).then(function(result) {\n if( result.value ) {\n self.view.c.addNewMetabox(result.value);\n }\n });\n },\n \"addInput\" : function(e) {\n this.view.c.createInput();\n },\n \"addOutput\": function(e) {\n this.view.c.createOutput();\n },\n \"importMetabox\": async function(e) {\n var self = this;\n\n const { value: file } = await swal({\n title: 'Select your metabox file',\n input: 'file',\n inputAttributes: {\n 'accept': 'application/json',\n 'aria-label': 'Select your metabox file'\n }\n })\n\n if (file) {\n const reader = new FileReader()\n reader.onload = (e) => {\n var json = JSON.parse(e.target.result);\n\n self.view.e.loadPackages(json).then(async () => {\n const { value: name } = await swal({\n title: 'Choose a name for your metabox',\n input: 'text',\n showCancelButton: true,\n inputValidator: (value) => {\n return !value && 'You need to write something!'\n }\n });\n\n self.view.c.addNewMetabox(name, json);\n }).catch((err) => {\n console.error(err);\n });\n }\n reader.readAsText(file)\n }\n },\n\n getInterfacesNames : function() {\n return _.keys( _.get(this.view.m, [\"data\",\"root\", \"interface\"]) || {} );\n },\n\n \"selectInterface\": function(e) {\n // Load the interface HTML when selected\n var uiName = $(e.target).val();\n if( uiName !== \"\" && uiName !== \"Load UI...\" ) {\n var itf = this.view.m.data.root.interface;\n var htmlString = htmltool.json2html(itf[uiName]);\n var prettyString = htmltool.htmlPrettyPrint(htmlString);\n this.htmlCode.setValue(prettyString);\n }\n else {\n this.htmlCode.setValue(\"\");\n }\n },\n \"saveInterfaceElement\": function(e) {\n var currentInterface = $(this.$el).find('.app-interface-select').val();\n if( currentInterface !== \"\" ) {\n var currentHTML = this.htmlCode.getValue();\n\n // save html code into app\n this.view.m.data.root.interface[currentInterface] = htmltool.html2json(currentHTML);\n }\n\n // save css code into app\n this.view.m.data.root.css = this.cssCode.getValue();\n },\n \"addInterface\": function(e) {\n var self = this;\n\n swal.mixin({\n confirmButtonText: 'Next &rarr;',\n showCancelButton: true,\n progressSteps: ['1', '2', '3']\n }).queue([\n {\n input: 'text',\n title: 'Choose a name',\n text: 'Enter a name for the new interface'\n },\n {\n input: 'select',\n title: 'Choose the type',\n text : 'Is it a viewer panel or a control panel?',\n inputOptions: {\n 'control': 'A control panel',\n 'viewer': 'A viewer',\n },\n },\n {\n input: 'select',\n title: 'Choose the position',\n text : 'Where do you want to position your panel?',\n inputOptions: {\n 'top-left': 'At the top-left',\n 'top-center': 'At the top-center',\n 'top-right': 'At the top-right',\n 'center-left': 'At the center-left',\n 'center': 'At the center',\n 'center-right': 'At the center-right',\n 'bottom-left': 'At the bottom-left',\n 'bottom-center': 'At the bottom-center',\n 'bottom-right': 'At the bottom-right',\n 'whole-screen': 'I want my panel in full-screen',\n },\n }\n ]).then((result) => {\n if (result.value) {\n var name = result.value[0];\n var type = result.value[1];\n var position = result.value[2];\n\n if (name === \"\") {\n swal.showInputError(\"the name is empty!\");\n return false\n }\n\n var appInterface = self.view.m.data.root.interface;\n if( appInterface[name] ) {\n swal.showInputError(\"Interface \" + name + \" already exists!\");\n return false\n }\n else {\n var style={};\n switch(position) {\n case 'top-left': style={ 'position': 'absolute', 'top': 0, 'left': 0, 'margin': '15px' }; break;\n case 'top-center': style={ 'position': 'absolute', 'top': 0, 'margin': '15px auto' }; break;\n case 'top-right': style={ 'position': 'absolute', 'top': 0, 'right': 0, 'margin': '15px' }; break;\n case 'center-left': style={ 'position': 'absolute', 'top': 0, 'bottom': 0, 'left': 0, 'margin': 'auto 15px' }; break;\n case 'center': style={ 'position': 'absolute', 'top': 0, 'bottom': 0, 'left': 0, 'right': 0, 'margin': 'auto' }; break;\n case 'center-right': style={ 'position': 'absolute', 'top': 0, 'bottom': 0, 'right': 0, 'margin': 'auto 15px' }; break;\n case 'bottom-left': style={ 'position': 'absolute', 'bottom': 0, 'left': 0, 'margin': '15px' }; break;\n case 'bottom-center': style={ 'position': 'absolute', 'bottom': 0, 'left': 0, 'right': 0, 'margin': '15px auto' }; break;\n case 'bottom-right': style={ 'position': 'absolute', 'bottom': 0, 'right': 0, 'margin': '15px' }; break;\n case 'whole-screen': style={ 'position': 'absolute', 'top': 0, 'left': 0 }; break;\n }\n\n // some prefilled data\n style['width'] = \"300px\";\n style['padding'] = \"15px\";\n style['border'] = \"1px solid #ccc\";\n style['border-radius'] = \"4px\";\n style['background'] = \"white\";\n if( position.startsWith(\"center\") ) {\n style['height'] = \"60px\"; // must define height\n }\n else {\n style['height'] = \"auto\";\n }\n\n // add a basic control\n appInterface[name] = {\n type: \"Element\",\n tagName: \"div\",\n attributes: {\n className: [\n \"dualbox\",\n \"dualbox-container\",\n \"dualbox-container-\" + name,\n type==\"viewer\" ? \"dualbox-viewer\" : \"dualbox-controls\"\n ],\n style: style,\n },\n children: []\n }\n\n // add the value to our select, and load it\n $(self.$el).find(\".app-interface-select\").append(\n $(\"<option/>\", { \"value\" : name }).append(name)\n );\n $(document).ready(() => {\n $(self.$el).find('.app-interface-select').val(name).change();\n\n // set it into the editor\n var htmlString = htmltool.json2html(appInterface[name]);\n var prettyString = htmltool.htmlPrettyPrint(htmlString);\n this.htmlCode.setValue(prettyString);\n self.updateCode();\n });\n\n self.view.runApp( self.getOptions() );\n }\n }\n })\n },\n \"removeInterface\": function(e) {\n var self = this;\n var name = $('.app-interface-select').val();\n\n swal({\n title: \"Confirm deleting \" + name + \" ?\",\n type: \"warning\",\n showCancelButton: true,\n confirmButtonColor: \"#DD6B55\",\n confirmButtonText: \"Yes, delete it!\",\n closeOnConfirm: true,\n closeOnCancel: true\n }).then((result) => {\n if( result.value ) {\n // set the interface back to first value\n $(this.$el).find(\".app-interface-select option[value='\" + name + \"']\").remove();\n $(this.$el).find(\".app-interface-select\").change();\n delete self.view.m.data.root.interface[name];\n self.htmlCode.setValue(\"\");\n self.view.runApp( self.getOptions() );\n }\n });\n },\n \"editPanelDescription\": function(e) {\n var self = this;\n var name = $('.app-interface-select').val();\n\n swal({\n title: \"Enter a description for this panel!\",\n input: \"textarea\",\n inputValue: this.view.m.data.root.interface[name].description || \"\",\n showCancelButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n animation: \"slide-from-top\",\n inputPlaceholder: \"Write something\"\n }).then( (result) => {\n if (result.value === \"\") {\n swal.showInputError(\"You need to write something!\");\n return false\n }\n else {\n self.view.m.data.root.interface[name].description = result.value;\n }\n });\n },\n \"toggleLeftWindow\": function(e) {\n var expanded = $(e.target).closest('button').data('expanded');\n if( expanded ) {\n $(this.$el).trigger('shrinkSettings');\n }\n else {\n $(this.$el).trigger('expandSettings');\n }\n },\n \"toggleRightWindow\": function(e) {\n var expanded = $(e.target).closest('button').data('expanded');\n if( expanded ) {\n $(this.$el).trigger('shrinkDebug');\n }\n else {\n $(this.$el).trigger('expandDebug');\n }\n },\n\n \"showEvents\": function(e) {\n this.view.setEventsVisibility( $(e.target).is(':checked') );\n },\n\n \"runApp\": function(e) {\n this.view.runApp( this.getOptions() );\n },\n\n \"takeAndLoadSnapshot\": function(e) {\n this.view.takeAndLoadSnapshot();\n },\n\n \"undo\": function(e) {\n this.view.c.undo();\n },\n\n \"redo\" : function(e) {\n this.view.c.redo();\n },\n\n \"removeSelection\": function(e) {\n this.view.c.deleteSelection();\n },\n\n \"mergeSelection\": function(e) {\n this.view.c.mergeSelection();\n },\n\n \"setMainMenu\": function(e) {\n this.view.setMainMenu();\n },\n\n \"getCurrentApplication\" : function(e) {\n // trick to make this function reactive to \"app\" field update\n if( this.app ) {\n return this.view.m.getCurrentApp(true);\n }\n else {\n throw \"Error: no app found\";\n }\n },\n\n \"onEdited\": function(e) {\n console.log('Something was edited, forcing new render');\n this.$forceUpdate();\n },\n\n \"ready\" : function() {\n return new Promise(resolve => {\n this.$nextTick(() => {\n window.requestAnimationFrame(() => {\n $(this.$el).ready(resolve);\n })\n })\n })\n }\n }\n}\n</script>\n"]}, media: undefined });
87079
+ inject("data-v-dc4fde12_0", { source: "\n.code-panel {\n width: 30%;\n height: 100%;\n vertical-align: top;\n float: left;\n}\n.application-container {\n width: calc(70% - 5px);\n height: 100%;\n display: inline-block;\n vertical-align: top;\n float: right;\n}\n.code-controls, .run-options {\n width: 100%;\n height: 60px;\n}\n.application {\n width: 100%;\n height: calc(100% - 60px);\n background-color: #ccc;\n}\n.dragbar {\n height: 100%;\n width: 5px;\n background-color: #e7e7e7;\n display: inline-block;\n cursor: col-resize;\n}\n.code-content {\n position: relative;\n height: calc(100% - 56px);\n}\n.code-html-container {\n position: relative;\n height: 50%;\n border-bottom: 1px solid #e7e7e7;\n}\n.code-css-container {\n position: relative;\n height: calc(50% - 1px);\n overflow: hidden;\n}\n.code-css {\n width: 100%;\n height: 100%;\n}\n.code-html {\n height: calc(100% - 40px);\n width: 100%;\n}\n.CodeMirror {\n height: 100%!important;\n}\n.code-badge {\n position: absolute;\n top: 10px;\n right: 10px;\n padding: 10px;\n}\n.btn-light.focus, .btn-light:focus {\n box-shadow: none!important;\n}\n.button-bar {\n width: 60px;\n padding: 10px;\n border-bottom: 1px solid #e7e7e7;\n width: 100%;\n background-color: white;\n}\n.noselect {\n -webkit-user-select: none; /* Chrome/Safari */\n -moz-user-select: none; /* Firefox */\n -ms-user-select: none; /* IE10+ */\n -o-user-select: none;\n user-select: none;\n}\n.btn + .btn {\n margin-left: 5px;\n}\n.btn-graph-goto {\n box-shadow: none!important;\n}\n.nav-tabs {\n border-bottom: none;\n}\n.main-navigation a.nav-link {\n color: white;\n}\n.main-navigation a.nav-link.active {\n color: #212529;\n}\n.dualbox-editor-body {\n width: 100%;\n height: 100%;\n overflow: hidden;\n background-color: rgb(85, 85, 85);\n}\n.dualbox-graph-left-section {\n height: 100%;\n width: 500px;\n float: left;\n position: relative;\n overflow: hidden;\n margin-left: -465px;\n transition: margin-left 0.3s ease;\n}\n.dualbox-graph-left-window {\n width: calc(100% - 35px);\n height: calc(100% - 10px);\n margin-top: 10px;\n /* background-color: #ECF2F8; */\n background-color: #f8f9fa;\n /* border: 1px solid grey; */\n border-radius: 5px;\n position: relative;\n float: left;\n}\n.dualbox-graph-left-panel {\n width: 100%;\n height: 100%;\n}\n.btn-toggle-left-window {\n position: absolute;\n right: 0;\n top: 0;\n margin-right: -35px;\n z-index: 100;\n border-top-left-radius: 0px;\n border-bottom-left-radius: 0px;\n}\n.btn-toggle-left-window:hover, .btn-toggle-right-window:hover, .btn-toggle-left-window:focus, .btn-toggle-right-window:focus, .btn-toggle-left-window:active, .btn-toggle-right-window:active, .btn-toggle-left-window:active:hover, .btn-toggle-right-window:active:hover {\n color: #212529!important;\n background-color: #f8f9fa!important;\n border-color: #f8f9fa!important;\n}\n.dualbox-graph-right-section {\n height: 100%;\n width: 500px;\n float: right;\n position: relative;\n overflow: hidden;\n margin-right: -465px;\n transition: margin-right 0.3s ease;\n}\n.dualbox-graph-right-window {\n width: calc(100% - 35px);\n height: calc(100% - 20px);\n margin-top: 10px;\n margin-bottom: 30px;\n /* background-color: #ECF2F8; */\n background-color: #f8f9fa;\n /* border: 1px solid grey; */\n border-radius: 5px;\n position: relative;\n float: right;\n}\n.dualbox-graph-right-panel {\n width: 100%;\n height: 100%;\n}\n.btn-toggle-right-window {\n position: absolute;\n left: 0;\n top: 0;\n margin-left: -35px;\n z-index: 100;\n border-top-right-radius: 0px;\n border-bottom-right-radius: 0px;\n}\n.dualbox-graph-tab {\n height: 100%;\n width: 100%;\n background-color: #555!important;\n}\n.dualbox-graph-main {\n height: 100%;\n width: calc(100% - 70px);\n float: right;\n background-color: #555!important;\n transition: width 0.3s ease;\n}\n.dualbox-graph-main.left-panel-expanded {\n width: calc(100% - 535px);\n margin-left: -465px;\n}\n.dualbox-graph-main.right-panel-expanded {\n width: calc(100% - 535px);\n}\n.dualbox-graph-main.left-panel-expanded.right-panel-expanded {\n width: calc(100% - 1000px);\n margin-left: -465px;\n}\n.opacity0 {\n opacity: 0;\n}\n.btn-editor-xs {\n width: 18px;\n padding : 3px!important;\n line-height : .5;\n border-radius : 2px;\n}\n.btn-editor-xs > i {\n font-size : 10px;\n}\n.btn-outline-discrete {\n border-color: rgba(0,0,0,0.05);\n border-color: transparent;\n color: rgba(0,0,0,0.3);\n}\n.dualbox-app-navigation {\n background-color: transparent;\n margin-bottom: 0;\n vertical-align: middle;\n padding-top: 7px;\n padding-bottom: 7px;\n font-weight: bold;\n user-select: none;\n}\n.app-topbar {\n border-bottom: none;\n padding-left: 15px;\n padding-right: 15px;\n display: flex;\n width: 100%;\n height: 58px;\n padding-top: 10px;\n padding-bottom: 10px;\n}\n.dark, .graph-tab.active, .nav-item.active .graph-tab {\n color: white!important;\n background-color: #555!important;\n}\n.light {\n color: #4d4d4d!important;\n background-color: #f8f9fa!important;\n}\n.main-navigation .nav-link, .main-navigation .nav-link.active, .nav-item.active .nav-link {\n border-bottom: none;\n border-left: none;\n border-top: none;\n border-right: none;\n position: relative;\n top: 1px;\n}\n.btn:focus, button:focus {\n outline: none;\n box-shadow: none;\n}\n.btn-transparent, .btn-transparent:hover, .btn-transparent:focus {\n background-color: transparent;\n}\n.connection-control {\n position: absolute;\n height: 14px;\n width: 14px;\n background-color: transparent;\n z-index: 19;\n cursor: move;\n}\n.connection-control.selected {\n border-color: #0066ff;\n box-shadow: 1px 1px 10px #0066ff;\n}\n.connection-label {\n z-index: 22!important;\n color: #004d00!important;\n background-color: white!important;\n padding: 4px 4px;\n border: 2px solid #004d00;\n font-size: 16px!important;\n border-radius: 5px;\n}\n.input-color-tag {\n background-color: #F2D600;\n}\n.output-color-tag {\n background-color: #FFAB4A;\n}\n.ui-color-tag {\n background-color: #61BD4F;\n}\n.metanode-color-tag {\n background-color: #DDDDDD;\n}\n.input {\n}\n.output {\n}\n.fileUpload {\n position: relative;\n overflow: hidden;\n margin: 10px;\n}\n.fileUpload input.upload {\n position: absolute;\n top: 0;\n right: 0;\n margin: 0;\n padding: 0;\n font-size: 20px;\n cursor: pointer;\n opacity: 0;\n filter: alpha(opacity=0);\n}\n.module-edit-modal-body .btn+.btn {\n margin-bottom: 0;\n margin-left: 5px;\n}\n.btn-add-node {\n width:46%;\n margin:1%;\n}\nbutton.close {\n position: absolute;\n right: 0;\n margin-right: 5px!important;\n}\n.CodeMirror {\n height: auto;\n min-height: 300px;\n}\n.load-app, .save-app {\n margin-left: 5px;\n margin-right: 5px;\n}\n.btn-xs {\n padding: 0px 4px;\n font-size: 12px;\n}\n", map: {"version":3,"sources":["/home/seb/dev/dualbox/editor/js/src/v/templates/main.vue"],"names":[],"mappings":";AACA;IACA,UAAA;IACA,YAAA;IACA,mBAAA;IACA,WAAA;AACA;AAEA;IACA,sBAAA;IACA,YAAA;IACA,qBAAA;IACA,mBAAA;IACA,YAAA;AACA;AAEA;IACA,WAAA;IACA,YAAA;AACA;AAEA;IACA,WAAA;IACA,yBAAA;IACA,sBAAA;AACA;AAEA;IACA,YAAA;IACA,UAAA;IACA,yBAAA;IACA,qBAAA;IACA,kBAAA;AACA;AAEA;IACA,kBAAA;IACA,yBAAA;AACA;AAEA;IACA,kBAAA;IACA,WAAA;IACA,gCAAA;AACA;AAEA;IACA,kBAAA;IACA,uBAAA;IACA,gBAAA;AACA;AAEA;IACA,WAAA;IACA,YAAA;AACA;AAEA;IACA,yBAAA;IACA,WAAA;AACA;AAEA;IACA,sBAAA;AACA;AAEA;IACA,kBAAA;IACA,SAAA;IACA,WAAA;IACA,aAAA;AACA;AAEA;IACA,0BAAA;AACA;AAEA;IACA,WAAA;IACA,aAAA;IACA,gCAAA;IACA,WAAA;IACA,uBAAA;AACA;AAEA;IACA,yBAAA,EAAA,kBAAA;IACA,sBAAA,EAAA,YAAA;IACA,qBAAA,EAAA,UAAA;IACA,oBAAA;IACA,iBAAA;AACA;AAEA;IACA,gBAAA;AACA;AAEA;IACA,0BAAA;AACA;AAEA;IACA,mBAAA;AACA;AAEA;IACA,YAAA;AACA;AAEA;IACA,cAAA;AACA;AAEA;IACA,WAAA;IACA,YAAA;IACA,gBAAA;IACA,iCAAA;AACA;AAEA;IACA,YAAA;IACA,YAAA;IACA,WAAA;IACA,kBAAA;IACA,gBAAA;IACA,mBAAA;IACA,iCAAA;AACA;AAEA;IACA,wBAAA;IACA,yBAAA;IACA,gBAAA;IACA,+BAAA;IACA,yBAAA;IACA,4BAAA;IACA,kBAAA;IACA,kBAAA;IACA,WAAA;AACA;AAEA;IACA,WAAA;IACA,YAAA;AACA;AAEA;IACA,kBAAA;IACA,QAAA;IACA,MAAA;IACA,mBAAA;IACA,YAAA;IACA,2BAAA;IACA,8BAAA;AACA;AAEA;IACA,wBAAA;IACA,mCAAA;IACA,+BAAA;AACA;AAEA;IACA,YAAA;IACA,YAAA;IACA,YAAA;IACA,kBAAA;IACA,gBAAA;IACA,oBAAA;IACA,kCAAA;AACA;AAEA;IACA,wBAAA;IACA,yBAAA;IACA,gBAAA;IACA,mBAAA;IACA,+BAAA;IACA,yBAAA;IACA,4BAAA;IACA,kBAAA;IACA,kBAAA;IACA,YAAA;AACA;AAEA;IACA,WAAA;IACA,YAAA;AACA;AAEA;IACA,kBAAA;IACA,OAAA;IACA,MAAA;IACA,kBAAA;IACA,YAAA;IACA,4BAAA;IACA,+BAAA;AACA;AAEA;IACA,YAAA;IACA,WAAA;IACA,gCAAA;AACA;AAEA;IACA,YAAA;IACA,wBAAA;IACA,YAAA;IACA,gCAAA;IACA,2BAAA;AACA;AAEA;IACA,yBAAA;IACA,mBAAA;AACA;AAEA;IACA,yBAAA;AACA;AAEA;IACA,0BAAA;IACA,mBAAA;AACA;AAEA;IACA,UAAA;AACA;AAEA;IACA,WAAA;IACA,wBAAA;IACA,iBAAA;IACA,mBAAA;AACA;AAEA;IACA,iBAAA;AACA;AAEA;IACA,8BAAA;IACA,yBAAA;IACA,sBAAA;AACA;AAEA;IACA,6BAAA;IACA,gBAAA;IACA,sBAAA;IACA,gBAAA;IACA,mBAAA;IACA,iBAAA;IACA,iBAAA;AACA;AAEA;IACA,mBAAA;IACA,kBAAA;IACA,mBAAA;IACA,aAAA;IACA,WAAA;IACA,YAAA;IACA,iBAAA;IACA,oBAAA;AACA;AAEA;IACA,sBAAA;IACA,gCAAA;AACA;AAEA;IACA,wBAAA;IACA,mCAAA;AACA;AAEA;IACA,mBAAA;IACA,iBAAA;IACA,gBAAA;IACA,kBAAA;IACA,kBAAA;IACA,QAAA;AACA;AAEA;IACA,aAAA;IACA,gBAAA;AACA;AAEA;IACA,6BAAA;AACA;AAEA;IACA,kBAAA;IACA,YAAA;IACA,WAAA;IACA,6BAAA;IACA,WAAA;IACA,YAAA;AACA;AAEA;IACA,qBAAA;IACA,gCAAA;AACA;AAEA;IACA,qBAAA;IACA,wBAAA;IACA,iCAAA;IACA,gBAAA;IACA,yBAAA;IACA,yBAAA;IACA,kBAAA;AACA;AAEA;IACA,yBAAA;AACA;AAEA;IACA,yBAAA;AACA;AAEA;IACA,yBAAA;AACA;AAEA;IACA,yBAAA;AACA;AAEA;AACA;AAEA;AACA;AAGA;IACA,kBAAA;IACA,gBAAA;IACA,YAAA;AACA;AACA;IACA,kBAAA;IACA,MAAA;IACA,QAAA;IACA,SAAA;IACA,UAAA;IACA,eAAA;IACA,eAAA;IACA,UAAA;IACA,wBAAA;AACA;AAGA;IACA,gBAAA;IACA,gBAAA;AACA;AAEA;IACA,SAAA;IACA,SAAA;AACA;AAEA;IACA,kBAAA;IACA,QAAA;IACA,2BAAA;AACA;AAEA;IACA,YAAA;IACA,iBAAA;AACA;AAEA;IACA,gBAAA;IACA,iBAAA;AACA;AAEA;IACA,gBAAA;IACA,eAAA;AACA","file":"main.vue","sourcesContent":["<style>\n .code-panel {\n width: 30%;\n height: 100%;\n vertical-align: top;\n float: left;\n }\n\n .application-container {\n width: calc(70% - 5px);\n height: 100%;\n display: inline-block;\n vertical-align: top;\n float: right;\n }\n\n .code-controls, .run-options {\n width: 100%;\n height: 60px;\n }\n\n .application {\n width: 100%;\n height: calc(100% - 60px);\n background-color: #ccc;\n }\n\n .dragbar {\n height: 100%;\n width: 5px;\n background-color: #e7e7e7;\n display: inline-block;\n cursor: col-resize;\n }\n\n .code-content {\n position: relative;\n height: calc(100% - 56px);\n }\n\n .code-html-container {\n position: relative;\n height: 50%;\n border-bottom: 1px solid #e7e7e7;\n }\n\n .code-css-container {\n position: relative;\n height: calc(50% - 1px);\n overflow: hidden;\n }\n\n .code-css {\n width: 100%;\n height: 100%;\n }\n\n .code-html {\n height: calc(100% - 40px);\n width: 100%;\n }\n\n .CodeMirror {\n height: 100%!important;\n }\n\n .code-badge {\n position: absolute;\n top: 10px;\n right: 10px;\n padding: 10px;\n }\n\n .btn-light.focus, .btn-light:focus {\n box-shadow: none!important;\n }\n\n .button-bar {\n width: 60px;\n padding: 10px;\n border-bottom: 1px solid #e7e7e7;\n width: 100%;\n background-color: white;\n }\n\n .noselect {\n -webkit-user-select: none; /* Chrome/Safari */\n -moz-user-select: none; /* Firefox */\n -ms-user-select: none; /* IE10+ */\n -o-user-select: none;\n user-select: none;\n }\n\n .btn + .btn {\n margin-left: 5px;\n }\n\n .btn-graph-goto {\n box-shadow: none!important;\n }\n\n .nav-tabs {\n border-bottom: none;\n }\n\n .main-navigation a.nav-link {\n color: white;\n }\n\n .main-navigation a.nav-link.active {\n color: #212529;\n }\n\n .dualbox-editor-body {\n width: 100%;\n height: 100%;\n overflow: hidden;\n background-color: rgb(85, 85, 85);\n }\n\n .dualbox-graph-left-section {\n height: 100%;\n width: 500px;\n float: left;\n position: relative;\n overflow: hidden;\n margin-left: -465px;\n transition: margin-left 0.3s ease;\n }\n\n .dualbox-graph-left-window {\n width: calc(100% - 35px);\n height: calc(100% - 10px);\n margin-top: 10px;\n /* background-color: #ECF2F8; */\n background-color: #f8f9fa;\n /* border: 1px solid grey; */\n border-radius: 5px;\n position: relative;\n float: left;\n }\n\n .dualbox-graph-left-panel {\n width: 100%;\n height: 100%;\n }\n\n .btn-toggle-left-window {\n position: absolute;\n right: 0;\n top: 0;\n margin-right: -35px;\n z-index: 100;\n border-top-left-radius: 0px;\n border-bottom-left-radius: 0px;\n }\n\n .btn-toggle-left-window:hover, .btn-toggle-right-window:hover, .btn-toggle-left-window:focus, .btn-toggle-right-window:focus, .btn-toggle-left-window:active, .btn-toggle-right-window:active, .btn-toggle-left-window:active:hover, .btn-toggle-right-window:active:hover {\n color: #212529!important;\n background-color: #f8f9fa!important;\n border-color: #f8f9fa!important;\n }\n\n .dualbox-graph-right-section {\n height: 100%;\n width: 500px;\n float: right;\n position: relative;\n overflow: hidden;\n margin-right: -465px;\n transition: margin-right 0.3s ease;\n }\n\n .dualbox-graph-right-window {\n width: calc(100% - 35px);\n height: calc(100% - 20px);\n margin-top: 10px;\n margin-bottom: 30px;\n /* background-color: #ECF2F8; */\n background-color: #f8f9fa;\n /* border: 1px solid grey; */\n border-radius: 5px;\n position: relative;\n float: right;\n }\n\n .dualbox-graph-right-panel {\n width: 100%;\n height: 100%;\n }\n\n .btn-toggle-right-window {\n position: absolute;\n left: 0;\n top: 0;\n margin-left: -35px;\n z-index: 100;\n border-top-right-radius: 0px;\n border-bottom-right-radius: 0px;\n }\n\n .dualbox-graph-tab {\n height: 100%;\n width: 100%;\n background-color: #555!important;\n }\n\n .dualbox-graph-main {\n height: 100%;\n width: calc(100% - 70px);\n float: right;\n background-color: #555!important;\n transition: width 0.3s ease;\n }\n\n .dualbox-graph-main.left-panel-expanded {\n width: calc(100% - 535px);\n margin-left: -465px;\n }\n\n .dualbox-graph-main.right-panel-expanded {\n width: calc(100% - 535px);\n }\n\n .dualbox-graph-main.left-panel-expanded.right-panel-expanded {\n width: calc(100% - 1000px);\n margin-left: -465px;\n }\n\n .opacity0 {\n opacity: 0;\n }\n\n .btn-editor-xs {\n width: 18px;\n padding : 3px!important;\n line-height : .5;\n border-radius : 2px;\n }\n\n .btn-editor-xs > i {\n font-size : 10px;\n }\n\n .btn-outline-discrete {\n border-color: rgba(0,0,0,0.05);\n border-color: transparent;\n color: rgba(0,0,0,0.3);\n }\n\n .dualbox-app-navigation {\n background-color: transparent;\n margin-bottom: 0;\n vertical-align: middle;\n padding-top: 7px;\n padding-bottom: 7px;\n font-weight: bold;\n user-select: none;\n }\n\n .app-topbar {\n border-bottom: none;\n padding-left: 15px;\n padding-right: 15px;\n display: flex;\n width: 100%;\n height: 58px;\n padding-top: 10px;\n padding-bottom: 10px;\n }\n\n .dark, .graph-tab.active, .nav-item.active .graph-tab {\n color: white!important;\n background-color: #555!important;\n }\n\n .light {\n color: #4d4d4d!important;\n background-color: #f8f9fa!important;\n }\n\n .main-navigation .nav-link, .main-navigation .nav-link.active, .nav-item.active .nav-link {\n border-bottom: none;\n border-left: none;\n border-top: none;\n border-right: none;\n position: relative;\n top: 1px;\n }\n\n .btn:focus, button:focus {\n outline: none;\n box-shadow: none;\n }\n\n .btn-transparent, .btn-transparent:hover, .btn-transparent:focus {\n background-color: transparent;\n }\n\n .connection-control {\n position: absolute;\n height: 14px;\n width: 14px;\n background-color: transparent;\n z-index: 19;\n cursor: move;\n }\n\n .connection-control.selected {\n border-color: #0066ff;\n box-shadow: 1px 1px 10px #0066ff;\n }\n\n .connection-label {\n z-index: 22!important;\n color: #004d00!important;\n background-color: white!important;\n padding: 4px 4px;\n border: 2px solid #004d00;\n font-size: 16px!important;\n border-radius: 5px;\n }\n\n .input-color-tag {\n background-color: #F2D600;\n }\n\n .output-color-tag {\n background-color: #FFAB4A;\n }\n\n .ui-color-tag {\n background-color: #61BD4F;\n }\n\n .metanode-color-tag {\n background-color: #DDDDDD;\n }\n\n .input {\n }\n\n .output {\n }\n\n\n .fileUpload {\n position: relative;\n overflow: hidden;\n margin: 10px;\n }\n .fileUpload input.upload {\n position: absolute;\n top: 0;\n right: 0;\n margin: 0;\n padding: 0;\n font-size: 20px;\n cursor: pointer;\n opacity: 0;\n filter: alpha(opacity=0);\n }\n\n\n .module-edit-modal-body .btn+.btn {\n margin-bottom: 0;\n margin-left: 5px;\n }\n\n .btn-add-node {\n width:46%;\n margin:1%;\n }\n\n button.close {\n position: absolute;\n right: 0;\n margin-right: 5px!important;\n }\n\n .CodeMirror {\n height: auto;\n min-height: 300px;\n }\n\n .load-app, .save-app {\n margin-left: 5px;\n margin-right: 5px;\n }\n\n .btn-xs {\n padding: 0px 4px;\n font-size: 12px;\n }\n</style>\n\n<template>\n <div class=\"dualbox-editor-body\">\n <nav class=\"main-navigation navbar navbar-default\" style=\"position: relative; margin-bottom: 0px; padding: 0; padding-top: 5px; background-color: #2e6da4;\">\n <ul class=\"nav nav-tabs\">\n <li class=\"nav-item active\">\n <a class=\"nav-link graph-tab\" href=\"#editor-graph-tab\" data-toggle=\"tab\">Application Graph</a>\n </li>\n <li class=\"nav-item\">\n <a class=\"nav-link interface-tab\" href=\"#editor-interface-tab\" data-toggle=\"tab\">Interface Editor</a>\n </li>\n </ul>\n\n <div class=\"nav navbar-right\" style=\"vertical-align: top; margin-top: 5px; margin-right: 10px; margin-bottom: 5px;\">\n <div v-if=\"showLoadButton === true\">\n <button class=\"load-app btn btn-sm btn-light\" style=\"position: relative; bottom: 3px;\" @click=\"loadApp\">Load App</button>\n </div>\n <div v-if=\"showSaveButton\">\n <button class=\"save-app btn btn-sm btn-light\" style=\"position: relative; bottom: 3px;\" @click=\"saveApp\">Save App</button>\n </div>\n </div>\n </nav>\n <div class=\"tab-content dualbox-graph-tab\" style=\"width: 100%; height: calc(100% - 46px);\">\n <div class=\"tab-pane active\" id=\"editor-graph-tab\" style=\"width: 100%; height: 100%;\">\n <div class=\"dualbox-graph-left-section dark\">\n <div class=\"dualbox-graph-left-window\">\n <button class=\"btn btn-light btn-toggle-left-window\" @click=\"toggleLeftWindow\" title=\"shrink window\" data-expanded=\"false\"><i class=\"fa fa-angle-double-right\"></i></button>\n <div class=\"dualbox-graph-left-panel light\">\n <edit-node-settings v-if=\"leftPanelMode == 'node' && selectedNodeId !== null\" :id=\"selectedNodeId\" :key=\"selectedNodeId\"></edit-node-settings>\n <edit-main-settings v-else-if=\"leftPanelMode == 'main'\" :app=\"getCurrentApplication()\" @edited=\"onEdited()\"></edit-main-settings>\n </div>\n </div>\n </div>\n <div class=\"dualbox-graph-right-section dark\">\n <div class=\"dualbox-graph-right-window\">\n <button class=\"btn btn-light btn-toggle-right-window\" @click=\"toggleRightWindow\" title=\"shrink window\" data-expanded=\"false\"><i class=\"fa fa-angle-double-left\"></i></button>\n <div class=\"dualbox-graph-right-panel light\">\n <debug-node-infos v-if=\"debugNodeId !== null\" :id=\"debugNodeId\"></debug-node-infos>\n </div>\n </div>\n </div>\n <div class=\"container-fluid dualbox-graph-main\" @click=\"setMainMenu\">\n <div class=\"row\">\n <div class=\"app-topbar dark\">\n <div class=\"justify-content-left\">\n <div class=\"dropdown\">\n <button class=\"btn btn-primary dropdown-toggle d-none\" type=\"button\" id=\"add-node-dropdown\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\" style=\"margin-right: 5px;\">\n Add\n </button>\n <div class=\"dropdown-menu\" aria-labelledby=\"add-node-dropdown\">\n <a class=\"dropdown-item add-box\" @click=\"addBox\" href=\"#\">Add box</a>\n <a class=\"dropdown-item add-metabox\" @click=\"addMetabox\" href=\"#\">Add metabox</a>\n <a class=\"dropdown-item add-input\" @click=\"addInput\" href=\"#\">Add input</a>\n <a class=\"dropdown-item add-output\" @click=\"addOutput\" href=\"#\">Add output</a>\n <a class=\"dropdown-item import-metabox\" @click=\"importMetabox\" href=\"#\">Import metabox</a>\n </div>\n <button class=\"btn btn-light btn-undo\" title=\"undo (ctrl-z)\" @click=\"undo\"><i class=\"fa fa-undo\"></i></button>\n <button class=\"btn btn-light btn-redo\" title=\"redo (ctrl-y)\" @click=\"redo\"><i class=\"fa fa-repeat fa-redo\"></i></button>\n <div class=\"form-check d-inline-block ml-2\">\n <label class=\"form-check-label\">\n <input class=\"form-check-input show-events\" type=\"checkbox\" value=\"false\" @click=\"showEvents\">\n <span class=\"noselect\">Show events</span>\n </label>\n </div>\n </div>\n </div>\n\n <div class=\"justify-content-center mx-auto\">\n <ol class=\"dualbox-app-navigation breadcrumb\"></ol>\n </div>\n\n <div class=\"justify-content-right\">\n <div class=\"dropdown selection-menu\" style=\"display: none;\">\n <button class=\"btn btn-primary dropdown-toggle\" type=\"button\" id=\"selection-dropdown\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">\n Selection\n </button>\n <div class=\"dropdown-menu dropdown-menu-right\" aria-labelledby=\"add-node-dropdown\">\n <a class=\"dropdown-item dualbox-merge-selection\" @click=\"mergeSelection\" href=\"#\">Merge</a>\n <a class=\"dropdown-item dualbox-remove-selection\" @click=\"removeSelection\" href=\"#\" style=\"color: red;\">Delete</a>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"row\" style=\"height: calc(100% - 58px);\">\n <graph-vue :app=\"app\" ref=\"graph\"></graph-vue>\n </div>\n </div>\n </div>\n <div class=\"tab-pane\" id=\"editor-interface-tab\" style=\"width 100%; height: 100%; background-color: white;\">\n <div class=\"db-editor-main\" style=\"width: 100%; height: 100%; overflow: hidden;\">\n <div class=\"code-panel\">\n <div class=\"button-bar form-inline code-controls\" style=\"position: relative;\">\n <button class=\"btn btn-primary btn-save-interface-element\" @click=\"saveInterfaceElement\">Save changes</button>\n </div>\n <div class=\"code-content\">\n <div class=\"code-html-container\">\n <div style=\"padding-top: 5px; padding-bottom: 5px; height: 50px; position: relative;\">\n <h3 style=\"position: absolute; top: 0; margin: 5px; font-size: 16px; z-index: 100; display: inline-block; margin-top: 5px;\">HTML</h3>\n <div class=\"d-inline-block ml-auto form-inline mr-2 mt-2\" style=\"position: absolute; top: 0; right: 0;\">\n <button class=\"btn btn-success btn-sm btn-add-interface\" @click=\"addInterface\"><i class=\"fas fa-plus\"></i></button>\n <select class=\"form-control btn-sm app-interface-select\" @change=\"selectInterface\" style=\"width: 150px; height: 32px;\">\n <option>Load UI...</option>\n <option v-for=\"interfaceName in getInterfacesNames()\" :value=\"interfaceName\">{{interfaceName}}</option>\n </select>\n <button class=\"btn btn-sm btn-light btn-edit-panel-description\" @click=\"editPanelDescription\"><i class=\"fas fa-info\" style=\"padding-left: 8px; padding-right: 8px;\"></i></button>\n <button class=\"btn btn-danger btn-sm btn-remove-interface\" @click=\"removeInterface\"><i class=\"fas fa-minus\"></i></button>\n </div>\n </div>\n <div class=\"code-html-text-container\" style=\"position: relative; height: calc(100% - 50px);\">\n <textarea class=\"code-html\"></textarea>\n </div>\n </div>\n <div class=\"code-css-container\">\n <div style=\"height: 30px;\">\n <h3 style=\"position: absolute; top: 0; margin: 5px; font-size: 16px; z-index: 100;\">CSS</h3>\n </div>\n <div class=\"colde-css-text-container\" style=\"position: relative; height: calc(100% - 30px);\">\n <textarea class=\"code-css\" v-model=\"appCss\"></textarea>\n </div>\n </div>\n </div>\n </div>\n <div class=\"dragbar\"></div>\n <div class=\"application-container\">\n <div class=\"button-bar form-inline run-options\" style=\"position: relative;\">\n <button class=\"btn btn-success btn-run mr-2\" @click=\"runApp\">Run</button>\n\n <select class=\"form-control run-loglevel mr-1 ml-2\">\n <option>error</option>\n <option>warn</option>\n <option>info</option>\n <option>log</option>\n <option>debug</option>\n </select>\n\n <input class=\"form-control run-noversioncheck mr-1 ml-3\" type=\"checkbox\" checked>No version checking</input>\n <input class=\"form-control run-removetrycatch mr-1 ml-3\" type=\"checkbox\">Remove Try/catch</input>\n <input class=\"form-control run-makesynchrone mr-1 ml-3\" type=\"checkbox\">Make Synchrone</input>\n\n <div class=\"ml-auto\">\n <input class=\"form-control run-profiler mr-1 ml-3\" type=\"checkbox\">Profiler</input>\n <input class=\"form-control run-record mr-1 ml-3\" type=\"checkbox\">Record</input>\n <button class=\"btn btn-secondary btn-snapshot\" @click=\"takeAndLoadSnapshot\">Snapshot</button>\n </div>\n </div>\n <div class=\"application capture-left-click capture-right-click\"></div>\n </div>\n </div>\n </div>\n </div>\n <add-node-vue :display=\"this.addingBox\" :mousePosition=\"this.newBoxPosition\" @closed=\"onAddBoxClosed\"></add-node-vue>\n </div>\n</template>\n\n<script>\nimport _ from 'lodash';\nimport swal from 'sweetalert2';\n\nimport graphVue from './graph.vue';\nimport addNodeVue from './addNode.vue';\nimport editMainSettingsVue from './editMainSettings.vue';\nimport editNodeSettingsVue from './editNodeSettings.vue';\nimport debugNodeInfosVue from './debugNodeInfos.vue';\n\n// CodeMirror\nimport CodeMirror from 'codemirror/lib/codemirror.js';\nimport 'codemirror/mode/xml/xml.js';\nimport 'codemirror/mode/css/css.js';\nimport 'codemirror/mode/javascript/javascript.js';\nimport 'codemirror/mode/htmlmixed/htmlmixed.js';\n\nimport htmltool from '@dualbox/dualbox-lib-htmltool';\n\nexport default {\n props: [\n 'app', // the app\n\n // Display configuration (online or offline ?)\n 'showLoadButton',\n 'showSaveButton',\n 'saveButtonFunction',\n\n // modes\n 'eventVisibility' // are events visible\n ],\n components: {\n 'graph-vue': graphVue,\n 'add-node-vue' : addNodeVue,\n 'edit-main-settings' : editMainSettingsVue,\n 'edit-node-settings' : editNodeSettingsVue,\n 'debug-node-infos' : debugNodeInfosVue,\n },\n data () {\n return {\n // modes\n addingBox : false,\n leftPanelMode : 'main', // 'main' to display main menu, 'node' for a node\n selectedNodeId : null, // id of the node to display in left menu\n debugNodeId: null, // on a snapshot, id of the node to display debug infos\n newBoxPosition: null, // track mouse position relative to the graph when adding a node\n\n // the specific app css\n appCss: \"\",\n }\n },\n created: function() {\n this.view = window.dualboxEditor.v;\n // TODO: restore this when all menus are migrated to Vue.js\n\n this.cssCode = null;\n this.htmlCode = null;\n },\n updated: function() {\n //console.log('updating main view with: ' + JSON.stringify(this.app));\n this.appCss = (this.app && this.app.css) || \"\";\n\n // Update html and css code editor\n this.updateCode();\n },\n mounted: function() {\n //this.view.setMainMenu();\n\n $(this.$el).bind('expandSettings', function(e) {\n // expand\n $(this).find('.dualbox-graph-left-section').css('margin-left', '0');\n $(this).find('.dualbox-graph-main').addClass('left-panel-expanded');\n $(this).find('.btn-toggle-left-window').data('expanded', true).find('i')\n .removeClass('fa-angle-double-right')\n .addClass('fa-angle-double-left')\n .attr('title', 'shrink window');\n });\n\n $(this.$el).bind('shrinkSettings', function(e) {\n // shrink\n $(this).find('.dualbox-graph-left-section').css('margin-left', '-465px');\n $(this).find('.dualbox-graph-main').removeClass('left-panel-expanded');\n $(this).find('.btn-toggle-left-window').data('expanded', false).find('i')\n .removeClass('fa-angle-double-left')\n .addClass('fa-angle-double-right')\n .attr('title', 'expand window');\n });\n\n $(this.$el).bind('expandDebug', function(e) {\n // expand\n $(this).find('.dualbox-graph-right-section').css('margin-right', '0');\n $(this).find('.dualbox-graph-main').addClass('right-panel-expanded');\n $(this).find('.btn-toggle-right-window').data('expanded', true).find('i')\n .removeClass('fa-angle-double-left')\n .addClass('fa-angle-double-right')\n .attr('title', 'shrink window');\n });\n\n $(this.$el).bind('shrinkDebug', function(e) {\n // shrink\n $(this).find('.dualbox-graph-right-section').css('margin-right', '-465px');\n $(this).find('.dualbox-graph-main').removeClass('right-panel-expanded');\n $(this).find('.btn-toggle-right-window').data('expanded', false).find('i')\n .removeClass('fa-angle-double-right')\n .addClass('fa-angle-double-left')\n .attr('title', 'expand window');\n });\n\n // bind tabs\n var self = this;\n $(this.$el).find(\"a[data-toggle='tab']\").on(\"shown.bs.tab\", function(e) {\n var target = $(e.target).attr(\"href\") // activated tab\n if( target == \"#editor-graph-tab\" ) {\n self.view.killApp();\n }\n else if( target == \"#editor-interface-tab\" ) {\n self.htmlCode.refresh();\n self.cssCode.refresh();\n self.view.runApp( self.getOptions() );\n }\n });\n\n $(this.$el).find(\"a[data-toggle='tab']\").on('click', function (e) {\n e.preventDefault()\n $(this).tab('show')\n });\n\n // Update html and css code editor\n this.updateCode();\n\n // Resize horizontally\n $(this.$el).find('.dragbar').mousedown(function(e){\n e.preventDefault();\n $(document).mouseup(function(e){\n $(document).unbind('mousemove');\n });\n $(document).mousemove(function(e){\n $('.code-panel').css('width', e.pageX + \"px\");\n $('.application-container').css('width', ($(\".db-editor-main\").width() - e.pageX - 5) + \"px\");\n })\n });\n\n },\n methods: {\n \"getOptions\": function() {\n return {\n profiler : $(this.$el).find('.run-profiler').is(':checked'),\n logLevel : $(this.$el).find('.run-loglevel').val(),\n options : {\n noVersionCheck: $(this.$el).find('.run-noversioncheck').is(':checked'),\n debug: {\n removeTryCatch: $(this.$el).find('.run-removetrycatch').is(':checked'),\n makeSynchrone: $(this.$el).find('.run-makesynchrone').is(':checked'),\n record: $(this.$el).find('.run-record').is(':checked'),\n }\n }\n }\n },\n\n \"updateCode\": function() {\n // instanciate codemirror for html and css\n if( !this.htmlCode ) {\n this.htmlCode = CodeMirror.fromTextArea( $(this.$el).find(\".code-html\")[0], {\n lineNumbers: true,\n mode : \"htmlmixed\",\n lineWrapping: true\n });\n }\n if( !this.cssCode ) {\n this.cssCode = CodeMirror.fromTextArea( $(this.$el).find(\".code-css\")[0], {\n lineNumbers: true,\n mode : \"css\",\n lineWrapping: true\n });\n }\n this.cssCode.setValue(this.view.m.get().css || \"\");\n },\n\n \"loadApp\" : function() {\n var self = this;\n\n // create a fake input and click it to select a file\n var input = $('<input/>', { \"type\": \"file\", \"class\": \"upload\", \"accept\" : \".json\" });\n input.change( function(e) {\n // if we're not here, go to 1st tab\n $(\"a[data-toggle='tab'][href='#1']\").click();\n\n // parse the file JSON and load it\n var files = e.target.files; // FileList object\n var r = new FileReader();\n r.onload = function(e) {\n var contents = e.target.result;\n var json = JSON.parse(contents);\n self.view.e.setApp(json);\n };\n\n r.readAsText(files[0]);\n });\n input.click();\n },\n \"saveApp\": function() {\n // bind the app load\n if( this.saveButtonFunction ) {\n var saveButtonFunction = (e) => {\n var json = this.view.m.getCleanJson();\n return this.saveButtonFunction(json);\n }\n }\n else {\n var saveButtonFunction = (e) => {\n var app = this.view.m.getCleanJson();\n var text = JSON.stringify(app, null, 2);\n var blob = new Blob([text], { \"type\" : \"application/octet-stream\" });\n\n var a = document.createElement('a');\n a.href = window.URL.createObjectURL(blob);\n a.download = \"app.json\";\n\n // simulate a click on the link\n if (document.createEvent) {\n var event = document.createEvent(\"MouseEvents\");\n event.initEvent(\"click\", true, true);\n a.dispatchEvent(event);\n } else {\n a.click();\n }\n }\n }\n saveButtonFunction();\n },\n \"getCurrentMousePosition\": function(e) {\n return this.$refs.graph.getCurrentMousePosition(e);\n },\n \"addBox\" : function(e) {\n this.addingBox = true;\n this.newBoxPosition = this.getCurrentMousePosition(e);\n this.$forceUpdate();\n },\n \"onAddBoxClosed\" : function() {\n this.addingBox = false;\n this.$forceUpdate();\n },\n \"addMetabox\" : function(e) {\n var self = this;\n e.preventDefault();\n e.stopPropagation();\n\n swal({\n input: 'text',\n title: 'Choose a name for the metabox',\n }).then(function(result) {\n if( result.value ) {\n self.view.c.addNewMetabox(result.value);\n }\n });\n },\n \"addInput\" : function(e) {\n this.view.c.createInput();\n },\n \"addOutput\": function(e) {\n this.view.c.createOutput();\n },\n \"importMetabox\": async function(e) {\n var self = this;\n\n const { value: file } = await swal({\n title: 'Select your metabox file',\n input: 'file',\n inputAttributes: {\n 'accept': 'application/json',\n 'aria-label': 'Select your metabox file'\n }\n })\n\n if (file) {\n const reader = new FileReader()\n reader.onload = (e) => {\n var json = JSON.parse(e.target.result);\n\n self.view.e.loadPackages(json).then(async () => {\n const { value: name } = await swal({\n title: 'Choose a name for your metabox',\n input: 'text',\n showCancelButton: true,\n inputValidator: (value) => {\n return !value && 'You need to write something!'\n }\n });\n\n self.view.c.addNewMetabox(name, json);\n }).catch((err) => {\n console.error(err);\n });\n }\n reader.readAsText(file)\n }\n },\n\n getInterfacesNames : function() {\n return _.keys( _.get(this.view.m, [\"data\",\"root\", \"interface\"]) || {} );\n },\n\n \"selectInterface\": function(e) {\n // Load the interface HTML when selected\n var uiName = $(e.target).val();\n if( uiName !== \"\" && uiName !== \"Load UI...\" ) {\n var itf = this.view.m.data.root.interface;\n var htmlString = htmltool.json2html(itf[uiName]);\n var prettyString = htmltool.htmlPrettyPrint(htmlString);\n this.htmlCode.setValue(prettyString);\n }\n else {\n this.htmlCode.setValue(\"\");\n }\n },\n \"saveInterfaceElement\": function(e) {\n var currentInterface = $(this.$el).find('.app-interface-select').val();\n if( currentInterface !== \"\" ) {\n var currentHTML = this.htmlCode.getValue();\n\n // save html code into app\n this.view.m.data.root.interface[currentInterface] = htmltool.html2json(currentHTML);\n }\n\n // save css code into app\n this.view.m.data.root.css = this.cssCode.getValue();\n },\n \"addInterface\": function(e) {\n var self = this;\n\n swal.mixin({\n confirmButtonText: 'Next &rarr;',\n showCancelButton: true,\n progressSteps: ['1', '2', '3']\n }).queue([\n {\n input: 'text',\n title: 'Choose a name',\n text: 'Enter a name for the new interface'\n },\n {\n input: 'select',\n title: 'Choose the type',\n text : 'Is it a viewer panel or a control panel?',\n inputOptions: {\n 'control': 'A control panel',\n 'viewer': 'A viewer',\n },\n },\n {\n input: 'select',\n title: 'Choose the position',\n text : 'Where do you want to position your panel?',\n inputOptions: {\n 'top-left': 'At the top-left',\n 'top-center': 'At the top-center',\n 'top-right': 'At the top-right',\n 'center-left': 'At the center-left',\n 'center': 'At the center',\n 'center-right': 'At the center-right',\n 'bottom-left': 'At the bottom-left',\n 'bottom-center': 'At the bottom-center',\n 'bottom-right': 'At the bottom-right',\n 'whole-screen': 'I want my panel in full-screen',\n },\n }\n ]).then((result) => {\n if (result.value) {\n var name = result.value[0];\n var type = result.value[1];\n var position = result.value[2];\n\n if (name === \"\") {\n swal.showInputError(\"the name is empty!\");\n return false\n }\n\n var appInterface = self.view.m.data.root.interface;\n if( appInterface[name] ) {\n swal.showInputError(\"Interface \" + name + \" already exists!\");\n return false\n }\n else {\n var style={};\n switch(position) {\n case 'top-left': style={ 'position': 'absolute', 'top': 0, 'left': 0, 'margin': '15px' }; break;\n case 'top-center': style={ 'position': 'absolute', 'top': 0, 'margin': '15px auto' }; break;\n case 'top-right': style={ 'position': 'absolute', 'top': 0, 'right': 0, 'margin': '15px' }; break;\n case 'center-left': style={ 'position': 'absolute', 'top': 0, 'bottom': 0, 'left': 0, 'margin': 'auto 15px' }; break;\n case 'center': style={ 'position': 'absolute', 'top': 0, 'bottom': 0, 'left': 0, 'right': 0, 'margin': 'auto' }; break;\n case 'center-right': style={ 'position': 'absolute', 'top': 0, 'bottom': 0, 'right': 0, 'margin': 'auto 15px' }; break;\n case 'bottom-left': style={ 'position': 'absolute', 'bottom': 0, 'left': 0, 'margin': '15px' }; break;\n case 'bottom-center': style={ 'position': 'absolute', 'bottom': 0, 'left': 0, 'right': 0, 'margin': '15px auto' }; break;\n case 'bottom-right': style={ 'position': 'absolute', 'bottom': 0, 'right': 0, 'margin': '15px' }; break;\n case 'whole-screen': style={ 'position': 'absolute', 'top': 0, 'left': 0 }; break;\n }\n\n // some prefilled data\n style['width'] = \"300px\";\n style['padding'] = \"15px\";\n style['border'] = \"1px solid #ccc\";\n style['border-radius'] = \"4px\";\n style['background'] = \"white\";\n if( position.startsWith(\"center\") ) {\n style['height'] = \"60px\"; // must define height\n }\n else {\n style['height'] = \"auto\";\n }\n\n // add a basic control\n appInterface[name] = {\n type: \"Element\",\n tagName: \"div\",\n attributes: {\n className: [\n \"dualbox\",\n \"dualbox-container\",\n \"dualbox-container-\" + name,\n type==\"viewer\" ? \"dualbox-viewer\" : \"dualbox-controls\"\n ],\n style: style,\n },\n children: []\n }\n\n // add the value to our select, and load it\n $(self.$el).find(\".app-interface-select\").append(\n $(\"<option/>\", { \"value\" : name }).append(name)\n );\n $(document).ready(() => {\n $(self.$el).find('.app-interface-select').val(name).change();\n\n // set it into the editor\n var htmlString = htmltool.json2html(appInterface[name]);\n var prettyString = htmltool.htmlPrettyPrint(htmlString);\n this.htmlCode.setValue(prettyString);\n self.updateCode();\n });\n\n self.view.runApp( self.getOptions() );\n }\n }\n })\n },\n \"removeInterface\": function(e) {\n var self = this;\n var name = $('.app-interface-select').val();\n\n swal({\n title: \"Confirm deleting \" + name + \" ?\",\n type: \"warning\",\n showCancelButton: true,\n confirmButtonColor: \"#DD6B55\",\n confirmButtonText: \"Yes, delete it!\",\n closeOnConfirm: true,\n closeOnCancel: true\n }).then((result) => {\n if( result.value ) {\n // set the interface back to first value\n $(this.$el).find(\".app-interface-select option[value='\" + name + \"']\").remove();\n $(this.$el).find(\".app-interface-select\").change();\n delete self.view.m.data.root.interface[name];\n self.htmlCode.setValue(\"\");\n self.view.runApp( self.getOptions() );\n }\n });\n },\n \"editPanelDescription\": function(e) {\n var self = this;\n var name = $('.app-interface-select').val();\n\n swal({\n title: \"Enter a description for this panel!\",\n input: \"textarea\",\n inputValue: this.view.m.data.root.interface[name].description || \"\",\n showCancelButton: true,\n closeOnConfirm: false,\n showLoaderOnConfirm: true,\n animation: \"slide-from-top\",\n inputPlaceholder: \"Write something\"\n }).then( (result) => {\n if (result.value === \"\") {\n swal.showInputError(\"You need to write something!\");\n return false\n }\n else {\n self.view.m.data.root.interface[name].description = result.value;\n }\n });\n },\n \"toggleLeftWindow\": function(e) {\n var expanded = $(e.target).closest('button').data('expanded');\n if( expanded ) {\n $(this.$el).trigger('shrinkSettings');\n }\n else {\n $(this.$el).trigger('expandSettings');\n }\n },\n \"toggleRightWindow\": function(e) {\n var expanded = $(e.target).closest('button').data('expanded');\n if( expanded ) {\n $(this.$el).trigger('shrinkDebug');\n }\n else {\n $(this.$el).trigger('expandDebug');\n }\n },\n\n \"showEvents\": function(e) {\n this.view.setEventsVisibility( $(e.target).is(':checked') );\n },\n\n \"runApp\": function(e) {\n this.view.runApp( this.getOptions() );\n },\n\n \"takeAndLoadSnapshot\": function(e) {\n this.view.takeAndLoadSnapshot();\n },\n\n \"undo\": function(e) {\n this.view.c.undo();\n },\n\n \"redo\" : function(e) {\n this.view.c.redo();\n },\n\n \"removeSelection\": function(e) {\n this.view.c.deleteSelection();\n },\n\n \"mergeSelection\": function(e) {\n this.view.c.mergeSelection();\n },\n\n \"setMainMenu\": function(e) {\n this.view.setMainMenu();\n },\n\n \"getCurrentApplication\" : function(e) {\n // trick to make this function reactive to \"app\" field update\n if( this.app ) {\n return this.view.m.getCurrentApp(true);\n }\n else {\n throw \"Error: no app found\";\n }\n },\n\n \"onEdited\": function(e) {\n console.log('Something was edited, forcing new render');\n this.$forceUpdate();\n },\n\n \"ready\" : function() {\n return new Promise(resolve => {\n this.$nextTick(() => {\n window.requestAnimationFrame(() => {\n $(this.$el).ready(resolve);\n })\n })\n })\n }\n }\n}\n</script>\n"]}, media: undefined });
87048
87080
 
87049
87081
  };
87050
87082
  /* scoped */
@@ -104022,10 +104054,10 @@ class DualboxEditor {
104022
104054
 
104023
104055
  var pkgName = "@dualbox/dualbox";
104024
104056
  await this.loadPackage(pkgName);
104025
- if (!window.DualBox && window.DualBox.start) {
104026
- this.DualBox = window.DualBox = this.require(pkgName);
104027
- } else {
104057
+ if (window.DualBox && window.DualBox.start) {
104028
104058
  this.DualBox = window.DualBox;
104059
+ } else {
104060
+ this.DualBox = window.DualBox = this.require(pkgName);
104029
104061
  }
104030
104062
  lodash.each(this.DualBox.core, async corePackage => {
104031
104063
  await this.loadPackage(corePackage.name);