@dualbox/editor 1.0.26 → 1.0.28

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.
@@ -86000,7 +86000,7 @@ var script$d = {
86000
86000
  },
86001
86001
 
86002
86002
  getInterfacesNames : function() {
86003
- return _.keys( _.get(this.view.m, ["data","root", "interface"]) || {} );
86003
+ return lodash.keys( lodash.get(this.view.m, ["data","root", "interface"]) || {} );
86004
86004
  },
86005
86005
 
86006
86006
  "selectInterface": function(e) {
@@ -87016,7 +87016,7 @@ __vue_render__$d._withStripped = true;
87016
87016
  /* style */
87017
87017
  const __vue_inject_styles__$d = function (inject) {
87018
87018
  if (!inject) return
87019
- inject("data-v-73882bf0_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=\"#1\" data-toggle=\"tab\">Application Graph</a>\n </li>\n <li class=\"nav-item\">\n <a class=\"nav-link interface-tab\" href=\"#2\" 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=\"1\" 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=\"2\" 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 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 == \"#1\" ) {\n self.view.killApp();\n }\n else if( target == \"#2\" ) {\n self.htmlCode.refresh();\n self.cssCode.refresh();\n self.view.runApp( self.getOptions() );\n }\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 });
87019
+ inject("data-v-30027b44_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=\"#1\" data-toggle=\"tab\">Application Graph</a>\n </li>\n <li class=\"nav-item\">\n <a class=\"nav-link interface-tab\" href=\"#2\" 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=\"1\" 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=\"2\" 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 == \"#1\" ) {\n self.view.killApp();\n }\n else if( target == \"#2\" ) {\n self.htmlCode.refresh();\n self.cssCode.refresh();\n self.view.runApp( self.getOptions() );\n }\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 });
87020
87020
 
87021
87021
  };
87022
87022
  /* scoped */
@@ -550,6 +550,7 @@
550
550
  </template>
551
551
 
552
552
  <script>
553
+ import _ from 'lodash';
553
554
  import swal from 'sweetalert2';
554
555
 
555
556
  import graphVue from './graph.vue';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dualbox/editor",
3
- "version": "1.0.26",
3
+ "version": "1.0.28",
4
4
  "description": "Editor of Dualbox apps",
5
5
  "browser": "js/dist/GraphEditor.js",
6
6
  "main": "js/dist/GraphEditor.js",
@@ -9,7 +9,8 @@
9
9
  },
10
10
  "scripts": {
11
11
  "test": "node test.js",
12
- "build": "rollup -c"
12
+ "build": "rollup -c",
13
+ "prepublish": "npm run build"
13
14
  },
14
15
  "author": "The Dualbox Team <contact@dualbox.com>",
15
16
  "license": "UNLICENSED",