diff --git a/README.md b/README.md index a039fb36eeef9ca910520c399bba2610ade75867..07dcdda1640cebe9bf5f49c3948efdf16fb211bd 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,16 @@ This project serves the developement environment / api we use to write and repre ## For MW + - top menu bar instructions + - rick click on menu bar to delete module + + - upd8ts to modules: + - rename inout to jsunit + - buttons get onClick evt + + - as you test, to track, + - weird state types solution: arrays, numbers, buttons, etc ? + - GIFS - load a program - drag around @@ -25,12 +35,6 @@ This project serves the developement environment / api we use to write and repre - rm modules - change settings - - right now - - push state down & up - - note below : - - not actually setting, do node main, change ms, watch console - - some wholistic test ... - - *don't forget* - onload, load state... - when hooking back to server, server.emitChange(key) ... from writeStateObject diff --git a/client/client.js b/client/client.js index 69c0c79a6afcb4ad9ed70f6a67b9de19c6d216c0..84d0f845f5ef15076597fc85900393ece6328b83 100644 --- a/client/client.js +++ b/client/client.js @@ -66,6 +66,8 @@ window.onload = function() { } // others this.onerror = (err) => { + alert('link to server is broken') + location.reload() console.log('socket error', err) } this.onclose = (evt) => { @@ -138,73 +140,6 @@ MISC --------------------------------------------------- */ -// return ul element with name and alt and link? -// TODO: not properly a tree, see note @ reciprocal fn in views.js -function heapSendsModuleMenu(tree) { - var menuDom = document.createElement('div') - menuDom.id = 'moduleMenu' - menuDom.style.left = lastPos.x + 'px' - menuDom.style.top = lastPos.y + 'px' - for (key in tree) { - var ul = document.createElement('ul') - ul.innerHTML = key.toString() - for (subkey in tree[key]) { - var li = document.createElement('li') - var path = tree[key][subkey].path - li.innerHTML = subkey.toString() - li.id = path - li.addEventListener('click', function(evt) { - var data = this.id - socketSend('put module', data) - wrapper.removeChild(document.getElementById('moduleMenu')) - }) - ul.appendChild(li) - } - menuDom.appendChild(ul) - } - wrapper.append(menuDom) - - function rmListener(evt) { - var findMenu = document.getElementById('moduleMenu') - if (findMenu !== null && findMenu.id == 'moduleMenu') { - wrapper.removeChild(findMenu) - } - evt.target.removeEventListener(evt.type, arguments.callee) - } - - document.addEventListener('click', rmListener) -} - -function heapSendsProgramMenu(tree) { - var menuDom = document.createElement('div') - menuDom.id = 'programMenu' - menuDom.style.left = lastPos.x + 'px' - menuDom.style.top = lastPos.y + 'px' - for(key in tree){ - var li = document.createElement('li') - var path = tree[key].path - li.innerHTML = key.toString() - li.id = path - li.addEventListener('click', function(evt){ - var data = this.id - socketSend('load program', data) - wrapper.removeChild(document.getElementById('programMenu')) - }) - menuDom.appendChild(li) - } - wrapper.append(menuDom) - - function rmListener(evt){ - var findMenu = document.getElementById('programMenu') - if(findMenu !== null && findMenu.id == 'programMenu'){ - wrapper.removeChild(findMenu) - } - // rm this listner... - evt.target.removeEventListener(evt.type, arguments.callee) - } - - document.addEventListener('click', rmListener) -} /* @@ -215,7 +150,6 @@ HEAP -> SERVER --------------------------------------------------- // always a rep, tho var program = {} - // re-writes the program, adds a description, // and loads multiple representations of modules to the view @@ -248,112 +182,6 @@ function heapSendsNewModule(mdl) { // and appends to the rep object a .ui object // containing references to those DOM objects -function addRepToView(rep) { - // a div to locate it - var domElem = document.createElement('div') - // dif. color for hardwares ? - domElem.className = 'block' - if (rep.description.isHardware) { - domElem.classList.add('hardware') - } - domElem.style.left = lastPos.x + 'px' - domElem.style.top = lastPos.y + 'px' - - // more html: the title - var title = document.createElement('div') - title.className = 'modname' - title.innerHTML = rep.description.id - title.alt = rep.description.alt - domElem.appendChild(title) - - var uiSetFlag - // place in pos if info present - // the rep.ui object will store references to the module's related DOM elements - if (rep.description.position != null) { - uiSetFlag = false - if (rep.description.position.left != null) { - domElem.style.left = rep.description.position.left + 'px' - } - if (rep.description.position.top != null) { - domElem.style.top = rep.description.position.top + 'px' - } - } else { - uiSetFlag = true - rep.description.position = {} - rep.description.position.left = lastPos.x - rep.description.position.top = lastPos.y - } - - if(rep.ui == null){ - rep.ui = {} - } - - rep.ui.domElem = domElem - - // WRITE UI STATE ELEMENTS - var stateElem = document.createElement('div') - stateElem.className = 'state' - rep.ui.state = {} - for (st in rep.state) { - var inputItem = writeStateRep(stateElem, rep, st) - rep.ui.state[st] = inputItem - } - - // WRITE INPUTS - var inElem = document.createElement('div') - inElem.className = 'inputs' - rep.ui.inputs = {} - for (ip in rep.inputs) { - var li = writeEventRep(rep, 'input', ip) - inElem.appendChild(li) - rep.ui.inputs[ip] = li - } - - // WRITE OUTPUTS - var outElem = document.createElement('div') - outElem.className = 'outputs' - rep.ui.outputs = {} - for (op in rep.outputs) { - var li = writeEventRep(rep, 'output', op) - outElem.appendChild(li) - rep.ui.outputs[op] = li - } - - // APPEND TO CONTAINER - domElem.appendChild(inElem) - domElem.appendChild(outElem) - domElem.appendChild(stateElem) - var clearElem = document.createElement('div') - clearElem.className = 'clear' - domElem.appendChild(clearElem) - - // MOVEABOUT CODE - title.onmousedown = function(evt) { - offsetX = evt.clientX - domElem.getBoundingClientRect().left - offsetY = evt.clientY - domElem.getBoundingClientRect().top - - function domElemMouseMove(mv) { - domElem.style.left = mv.pageX - offsetX + 'px' - domElem.style.top = mv.pageY - offsetY + 'px' - redrawLinks() - } - - document.addEventListener('mousemove', domElemMouseMove) - - title.onmouseup = function() { - rep.description.position.left = parseInt(domElem.style.left, 10) - rep.description.position.top = parseInt(domElem.style.top, 10) - putUi(rep) - document.removeEventListener('mousemove', domElemMouseMove) - title.onmouseup = null - } - } - - wrapper.appendChild(rep.ui.domElem) - if(uiSetFlag){ - putUi(rep) - } -} function heapSendsModuleChange(data){ console.log(data) @@ -383,7 +211,9 @@ function heapSendsModuleChange(data){ // update state from server to UI function heapSendsStateChange(data) { console.log('HEAP SENDS CHANGE STATE IN MODULE', data) - heapSendsModuleChange(data) + var rep = program.modules[data.id] + rep.state[data.key] = data.val + rep.ui.state[data.key].value = data.val } /* @@ -394,17 +224,12 @@ UI -> HEAP --------------------------------------------------- // push new state from UI to server function putState(rep, key) { - // ship it all home: not perfect, but hey var data = { - description: { - id: rep.description.id - }, - state: { - key: key, - val: rep.state[key] - } + id: rep.description.id, + key: key, + val: rep.state[key] } - socketSend('put state', data) + socketSend('put state change', data) } // save ui position to server for reload @@ -419,12 +244,47 @@ function putUi(rep) { } } - socketSend('put ui', data) + socketSend('put ui change', data) +} + +// input / output click handling +var clkState = false +var oClk = {} +var tmpBz = {} + +function evtConnectHandler(clk) { + if (!clkState) { + // first click + oClk = clk + clkState = true + } else { + // second click + var tClk = clk + //console.log(oClk, tClk) + var x1 = parseInt(oClk.evt.target.offsetParent.style.left, 10) + oClk.evt.target.offsetLeft + oClk.evt.target.clientWidth + var y1 = parseInt(oClk.evt.target.offsetParent.style.top, 10) + oClk.evt.target.offsetTop + oClk.evt.target.clientHeight / 2 + var x2 = parseInt(tClk.evt.target.offsetParent.style.left, 10) + tClk.evt.target.offsetLeft + var y2 = parseInt(tClk.evt.target.offsetParent.style.top, 10) + tClk.evt.target.offsetTop + tClk.evt.target.clientHeight / 2 + //var bz = newBezier(x1, y1, x2, y2) + clkState = false + //console.log('connect', oClk.rep.description.id, oClk.name, 'to', tClk.rep.description.id, tClk.name) + var data = { + from: { + id: oClk.rep.description.id, + output: oClk.name + }, + to: { + id: tClk.rep.description.id, + input: tClk.name + } + } + socketSend('put link change', data) + } } /* -UTILITIES? --------------------------------------------------- +UTILITIES --------------------------------------------------- */ @@ -460,17 +320,6 @@ function redrawLinks() { } } - -// need top level rep of program - nice to think of how to handle heirarchy later on? tl rep is internal rep ... is same ? -// how to handle movement of rep, incl. svg - goes with moving mouse after 1st click: svg lives 'in' rep ? - -// trying to do this top level from the program config itself, will try sending jsonified modules[] - -// consistency with saved formats, written formats, sent... json objs - -var svgns = 'http://www.w3.org/2000/svg' -var svg = {} - /* UI EVENTS --------------------------------------------------------------------- @@ -519,39 +368,70 @@ document.onkeydown = function(evt){ } } -// input / output click hookups +// return ul element with name and alt and link? +// TODO: not properly a tree, see note @ reciprocal fn in views.js +function heapSendsModuleMenu(tree) { + var menuDom = document.createElement('div') + menuDom.id = 'moduleMenu' + menuDom.style.left = lastPos.x + 'px' + menuDom.style.top = lastPos.y + 'px' + for (key in tree) { + var ul = document.createElement('ul') + ul.innerHTML = key.toString() + for (subkey in tree[key]) { + var li = document.createElement('li') + var path = tree[key][subkey].path + li.innerHTML = subkey.toString() + li.id = path + li.addEventListener('click', function(evt) { + var data = this.id + socketSend('put module', data) + wrapper.removeChild(document.getElementById('moduleMenu')) + }) + ul.appendChild(li) + } + menuDom.appendChild(ul) + } + wrapper.append(menuDom) -var clkState = false -var oClk = {} -var tmpBz = {} + function rmListener(evt) { + var findMenu = document.getElementById('moduleMenu') + if (findMenu !== null && findMenu.id == 'moduleMenu') { + wrapper.removeChild(findMenu) + } + evt.target.removeEventListener(evt.type, arguments.callee) + } -// input / output click handling -function evtConnectHandler(clk) { - if (!clkState) { - // first click - oClk = clk - clkState = true - } else { - // second click - var tClk = clk - //console.log(oClk, tClk) - var x1 = parseInt(oClk.evt.target.offsetParent.style.left, 10) + oClk.evt.target.offsetLeft + oClk.evt.target.clientWidth - var y1 = parseInt(oClk.evt.target.offsetParent.style.top, 10) + oClk.evt.target.offsetTop + oClk.evt.target.clientHeight / 2 - var x2 = parseInt(tClk.evt.target.offsetParent.style.left, 10) + tClk.evt.target.offsetLeft - var y2 = parseInt(tClk.evt.target.offsetParent.style.top, 10) + tClk.evt.target.offsetTop + tClk.evt.target.clientHeight / 2 - //var bz = newBezier(x1, y1, x2, y2) - clkState = false - //console.log('connect', oClk.rep.description.id, oClk.name, 'to', tClk.rep.description.id, tClk.name) - var data = { - from: { - id: oClk.rep.description.id, - output: oClk.name - }, - to: { - id: tClk.rep.description.id, - input: tClk.name - } + document.addEventListener('click', rmListener) +} + +function heapSendsProgramMenu(tree) { + var menuDom = document.createElement('div') + menuDom.id = 'programMenu' + menuDom.style.left = lastPos.x + 'px' + menuDom.style.top = lastPos.y + 'px' + for(key in tree){ + var li = document.createElement('li') + var path = tree[key].path + li.innerHTML = key.toString() + li.id = path + li.addEventListener('click', function(evt){ + var data = this.id + socketSend('load program', data) + wrapper.removeChild(document.getElementById('programMenu')) + }) + menuDom.appendChild(li) + } + wrapper.append(menuDom) + + function rmListener(evt){ + var findMenu = document.getElementById('programMenu') + if(findMenu !== null && findMenu.id == 'programMenu'){ + wrapper.removeChild(findMenu) } - socketSend('put link', data) + // rm this listner... + evt.target.removeEventListener(evt.type, arguments.callee) } -} \ No newline at end of file + + document.addEventListener('click', rmListener) +} diff --git a/client/divtools.js b/client/divtools.js index ed2866c32d1ddd58cccd84a5a2f0d0a8b3458557..337a85cf5a4257bf169b8816b462f055be446479 100644 --- a/client/divtools.js +++ b/client/divtools.js @@ -1,5 +1,130 @@ // writing representations + +function addRepToView(rep) { + // a div to locate it + var domElem = document.createElement('div') + // dif. color for hardwares ? + domElem.className = 'block' + if (rep.description.isHardware) { + domElem.classList.add('hardware') + } + domElem.style.left = lastPos.x + 'px' + domElem.style.top = lastPos.y + 'px' + + // more html: the title + var title = document.createElement('div') + title.className = 'modname' + title.innerHTML = rep.description.id + title.alt = rep.description.alt + domElem.appendChild(title) + + var uiSetFlag + // place in pos if info present + // the rep.ui object will store references to the module's related DOM elements + if (rep.description.position != null) { + uiSetFlag = false + if (rep.description.position.left != null) { + domElem.style.left = rep.description.position.left + 'px' + } + if (rep.description.position.top != null) { + domElem.style.top = rep.description.position.top + 'px' + } + } else { + uiSetFlag = true + rep.description.position = {} + rep.description.position.left = lastPos.x + rep.description.position.top = lastPos.y + } + + if(rep.ui == null){ + rep.ui = {} + } + + rep.ui.domElem = domElem + + // WRITE UI STATE ELEMENTS + var stateElem = document.createElement('div') + stateElem.className = 'state' + rep.ui.state = {} + for (st in rep.state) { + var inputItem = writeStateRep(stateElem, rep, st) + rep.ui.state[st] = inputItem + } + + // WRITE INPUTS + var inElem = document.createElement('div') + inElem.className = 'inputs' + rep.ui.inputs = {} + for (ip in rep.inputs) { + var li = writeEventRep(rep, 'input', ip) + inElem.appendChild(li) + rep.ui.inputs[ip] = li + } + + // WRITE OUTPUTS + var outElem = document.createElement('div') + outElem.className = 'outputs' + rep.ui.outputs = {} + for (op in rep.outputs) { + var li = writeEventRep(rep, 'output', op) + outElem.appendChild(li) + rep.ui.outputs[op] = li + } + + // APPEND TO CONTAINER + domElem.appendChild(inElem) + domElem.appendChild(outElem) + domElem.appendChild(stateElem) + var clearElem = document.createElement('div') + clearElem.className = 'clear' + domElem.appendChild(clearElem) + + // MOVEABOUT CODE + title.onmousedown = function(evt) { + offsetX = evt.clientX - domElem.getBoundingClientRect().left + offsetY = evt.clientY - domElem.getBoundingClientRect().top + + function domElemMouseMove(mv) { + domElem.style.left = mv.pageX - offsetX + 'px' + domElem.style.top = mv.pageY - offsetY + 'px' + redrawLinks() + } + + document.addEventListener('mousemove', domElemMouseMove) + + title.onmouseup = function() { + rep.description.position.left = parseInt(domElem.style.left, 10) + rep.description.position.top = parseInt(domElem.style.top, 10) + putUi(rep) + document.removeEventListener('mousemove', domElemMouseMove) + title.onmouseup = null + } + } + + wrapper.appendChild(rep.ui.domElem) + if(uiSetFlag){ + putUi(rep) + } +} + +function writeEventRep(rep, type, key) { + var li = document.createElement('li') + li.innerHTML = key.toString() + li.id = rep.id + ' ' + type + ' ' + key + li.addEventListener('click', (evt) => { + var ipclk = { + rep: rep, + type: type, + name: key, + evt: evt + } + console.log('clicked', key) + evtConnectHandler(ipclk) + }) + return li +} + function writeStateRep(container, rep, key) { var variable = rep.state[key] switch (variable.type) { @@ -8,12 +133,6 @@ function writeStateRep(container, rep, key) { var li = document.createElement('li') li.appendChild(document.createTextNode(variable.label)) li.addEventListener('click', function() { - // invert - if (rep.state[key].isPressed) { - rep.state[key].isPressed = false - } else { - rep.state[key].isPressed = true - } putState(rep, key) }) container.appendChild(li) @@ -58,7 +177,7 @@ function writeStateRep(container, rep, key) { input.type = 'text' input.size = 24 input.value = variable.toString() - input.addEventListener('change', function() { + input.addEventListener('change', function(evt) { rep.state[key] = parseFloat(input.value) putState(rep, key) }) @@ -92,25 +211,11 @@ function writeStateRep(container, rep, key) { } } -function writeEventRep(rep, type, key) { - var li = document.createElement('li') - li.innerHTML = key.toString() - li.id = rep.id + ' ' + type + ' ' + key - li.addEventListener('click', (evt) => { - var ipclk = { - rep: rep, - type: type, - name: key, - evt: evt - } - console.log('clicked', key) - evtConnectHandler(ipclk) - }) - return li -} // bezier utilities +var svgns = 'http://www.w3.org/2000/svg' +var svg = {} function newBezier(x1, y1, x2, y2) { var bz = {} diff --git a/lib/jsunit.js b/lib/jsunit.js index 071b68d602d3c409561eff213eb88b10d8226673..1bc3075475210c7bddfe250c1a105db7f8f02f8f 100644 --- a/lib/jsunit.js +++ b/lib/jsunit.js @@ -66,7 +66,7 @@ function State() { this.emitters[item]() } } - + return state } diff --git a/main.js b/main.js index 07ede52c69609cd9ba16c076cf75459e5cff101e..51c6645f7729326e98af4a5d194c5f9044056c70 100644 --- a/main.js +++ b/main.js @@ -23,6 +23,7 @@ programs are assemblies of modules */ +// business const Reps = require('./reps.js') const Programs = require('./programs.js') @@ -30,109 +31,11 @@ var program = {} program = Programs.open('programs/default.json') + +// UI const View = require('./views.js') View.startHttp() View.startWs() Programs.assignSocket(View.uiSocket) View.assignProgram(program) - -/* - -PROGRAM REPRESENT - -*/ - -/* - -// update state from UI to server -function changeState(data) { - // of one module - // should just recv all state, walk tree for differences - var oldState = modules[data.id].state - var newState = data.state - // rep only holds proper key-values w/o emitters, _values etc - for (var key in newState) { - if (isStateKey(key)) { - if (oldState[key].isButton) { - if (oldState[key].isPressed != newState[key].isPressed) { - console.log('CHANGE BUTTON STATE', key, 'to', newState[key], 'in', data.id) - // this will trigger some 'onChange' f'ns - // that might change some state - oldState[key] = newState[key] - // to prevent quickly changing it back, we'll exit now (one state change from UI per trx) - return true - } - } else if (oldState[key].isMultiLine) { - if (oldState[key].value != newState[key].value) { - console.log('CHANGE MULTILINE STATE', key, 'to', newState[key].value, 'in', data.id) - oldState[key].value = newState[key].value - return true - } - } else if (oldState[key] !== newState[key]) { - console.log('CHANGE STATE', key, 'to', newState[key], 'in', data.id) - oldState[key] = newState[key] - return true - } - } - } -} - -function changeUi(data) { - var mod = modules[data.id] - if (mod.ui == null) { - console.log("NO UI") - mod.ui = {} - } - mod.ui = data.ui - console.log('CHANGE UI', mod.id, mod.ui) -} - -function setUiPos(module, left, top) { - if (module.ui == null) { - module.ui = {} - } - module.ui.left = left - module.ui.top = top -} - -// push new state from server to UI -function putState(mod) { - // push just the state to the individual mod - // copy only the keys we want to see - var state = {} - for (var key in mod.state) { - if (isStateKey(key)) { - state[key] = mod.state[key] - } - } - var data = { - id: mod.id, - state: state - } - socketSend('change state', data) -} - -function putLink(data) { - var fromModule = modules.find((module) => { - return module.id === data.from.id - }) - - var toModule = modules.find((module) => { - return module.id === data.to.id - }) - - if (fromModule.outputs[data.from.output].isLinked(toModule.inputs[data.to.input])) { - console.log("HOOKDOWN") - fromModule.outputs[data.from.output].remove(toModule.inputs[data.to.input]) - } else { - fromModule.outputs[data.from.output].attach(toModule.inputs[data.to.input]) - } - - // replace it - changeRep(fromModule) -} - -*/ - -// put \ No newline at end of file diff --git a/programs.js b/programs.js index 9959f93a988cbe6a749fd6b347672d74ecd3408b..427ce16d1c92f9bba0586a0800613f8a60243222 100644 --- a/programs.js +++ b/programs.js @@ -72,7 +72,7 @@ function writeStateObject(mod, key) { // when we change it within the module // this.emitChange(key) // push to external view - if(link){ + if(socket){ pushState(mod, key) } } @@ -96,8 +96,12 @@ function assignSocket(sckt){ } function pushState(mod, key){ - console.log("GONNA PUSH IT OOOOOUT") - console.log('link', socket) + var data = { + id: mod.description.id, + key: key, + val: mod.state[key] + } + socket.send('put state change', data) } diff --git a/src/util/delay.js b/src/util/delay.js index d7f8500fcbf577dcc728e32a8fc76bdfcddbe2e2..abf1b6fa6ce81b7dce81e941ed812151eb40bd86 100644 --- a/src/util/delay.js +++ b/src/util/delay.js @@ -21,6 +21,7 @@ function Delay() { var state = delay.state state.ms = 100 + state.onChange('ms', onMsChange) delay.inputs = { thru: Input('any', onDelayBegin) // makes anything into '1' event @@ -30,6 +31,11 @@ function Delay() { out: Output('any') } + function onMsChange(){ + console.log("noting state change", state.ms) + state.ms = 1200 + } + function onDelayBegin(input){ setTimeout(function(){ delay.outputs.out.emit(input) diff --git a/src/util/gate.js b/src/util/gate.js index 100706779262c6b337d5d6056f5a9e3c55557565..cb46f95703784131cdc2e471ea5ea989160d452f 100644 --- a/src/util/gate.js +++ b/src/util/gate.js @@ -15,13 +15,12 @@ function Gate() { alt: 'in ... out' } } - + gate.state = State() // alias ! var state = gate.state - state.toggle = Button("Open / Close") - state.onChange('toggle', onButtonPress) + state.toggle = Button("Open / Close", onButtonPress) // yikes gate.isOpen = false state.message = 'closed' @@ -35,6 +34,7 @@ function Gate() { } function onButtonPress(evt){ + console.log("GATE BUTTON") state.toggle.isPressed = false if(gate.isOpen){ gate.isOpen = false diff --git a/views.js b/views.js index 44a6514608e94e736dfb8b259153b942fbe1754a..6f7416d1faa08c269edee89fda93913a243f5ea6 100644 --- a/views.js +++ b/views.js @@ -99,14 +99,14 @@ function socketRecv(evt) { case 'put module': uiRequestNewModule(data) break - case 'put state': + case 'put state change': uiRequestStateChange(data) break - case 'put link': + case 'put link change': uiRequestLinkChange(data) // id:output > id:input break - case 'put ui': + case 'put ui change': uiRequestUiChange(data) break default: @@ -226,36 +226,26 @@ function uiRequestNewModule(data) { function uiRequestStateChange(data) { console.log('UI REQUEST CHANGE STATE IN MODULE', data) - // there should only be one ! - var id = data.description.id - var key = data.state.key - var val = data.state.val - - var mdlState = program.modules[id].state - console.log('mdlState', mdlState) - var mdlStateItem = program.modules[id].state[key] - console.log('mdlStateItem', mdlStateItem) - - if (mdlStateItem) { - switch (mdlState.type) { + + var mdlState = program.modules[data.id].state + + if (mdlState[data.key]) { + switch (mdlState[data.key].type) { case 'button': - mdlStateItem.onClick() + mdlState[data.key].onClick() break case 'multiline': - mdlStateItem.value = val - mdlState.emitChange(key) + mdlState[data.key].value = data.val + mdlState.emitChange(data.key) break default: - mdlStateItem = val - mdlState.emitChange(key) + mdlState[data.key] = data.val + mdlState.emitChange(data.key) break } } else { console.log("ERR no state key,", key, "found here", data) } - - console.log('mdlStateItem', mdlStateItem) - console.log(program.modules[id]) } function uiRequestLinkChange(data) { @@ -265,14 +255,17 @@ function uiRequestLinkChange(data) { var toId = data.to.id var inputName = data.to.input - // HERE: check if hooked already - var fromMdl = program.modules[fromId] var toMdl = program.modules[toId] - fromMdl.outputs[outputName].attach(toMdl.inputs[inputName]) - var nRep = Reps.makeFromModule(fromMdl) + // if it's already attached, we rm + if(fromMdl.outputs[outputName].isLinked(toMdl.inputs[inputName])){ + fromMdl.outputs[outputName].remove(toMdl.inputs[inputName]) + } else { + fromMdl.outputs[outputName].attach(toMdl.inputs[inputName]) + } + var nRep = Reps.makeFromModule(fromMdl) socketSend('put module change', nRep) }