diff --git a/client/client.js b/client/client.js index e5e341691daae3d0b25775a633268edb02462896..90e450d46c3c6fbf149c1e7aebf32fd3c5669a6a 100644 --- a/client/client.js +++ b/client/client.js @@ -1,619 +1,669 @@ -// -// -// new node controller / VIEW -// reconfigurable unviersal numeric dataflow machine controller -// 'RUN DMC' -// dataflow numeric controller -// DNC -// -// client.js -// -// -// Jake Read at the Center for Bits and Atoms -// (c) Massachusetts Institute of Technology 2018 -// -// This work may be reproduced, modified, distributed, performed, and -// displayed for any purpose, but must acknowledge the mods -// project. Copyright is retained and must be preserved. The work is -// provided as is; no warranty is provided, and users accept all -// liability. - -/* - -CLIENT GLOBALS --------------------------------------------------- - -*/ - -var sckt = {} -var lastPos = { x: 10, y: 30 } - -// drawing / div-ing -var wrapper = {} -var nav = {} - -/* - -STARTUP --------------------------------------------------- - -*/ - -window.onload = function() { - svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg') - svg.style.position = 'absolute' - svg.style.left = 0 - svg.style.top = 0 - svg.style.zIndex = 0 - svg.style.overflow = 'visible' - svg.setAttribute('width', 2) - svg.setAttribute('height', 2) - svg.setAttribute('id', 'svg') - svg.setAttribute('width', '100%') - svg.setAttribute('height', '100%') - document.body.appendChild(svg) - - wrapper = document.createElement('div') - wrapper.id = 'wrapper' - document.body.append(wrapper) - - nav = document.getElementById('nav') - - const socket = new WebSocket('ws://localhost:8081') - - socket.onopen = function(evt) { - // pass to global ref - sckt = this - // say hello - socketSend('console', 'hello server') - console.log('socket open') - // ask for the current program - socketSend('get current program', '') - // main socket entry point - this.onmessage = (evt) => { - socketRecv(evt) - } - // others - this.onerror = (err) => { - alert('link to server is broken') - location.reload() - console.log('socket error', err) - } - this.onclose = (evt) => { - console.log('socket closed', evt) - sckt = null + // + // + // new node controller / VIEW + // reconfigurable unviersal numeric dataflow machine controller + // 'RUN DMC' + // dataflow numeric controller + // DNC + // + // client.js + // + // + // Jake Read at the Center for Bits and Atoms + // (c) Massachusetts Institute of Technology 2018 + // + // This work may be reproduced, modified, distributed, performed, and + // displayed for any purpose, but must acknowledge the mods + // project. Copyright is retained and must be preserved. The work is + // provided as is; no warranty is provided, and users accept all + // liability. + + /* + + CLIENT GLOBALS --------------------------------------------------- + + */ + + var sckt = {} + var lastPos = { x: 10, y: 30 } + + // drawing / div-ing + var wrapper = {} + var nav = {} + + /* + + STARTUP --------------------------------------------------- + + */ + + window.onload = function() { + svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg') + svg.style.position = 'absolute' + svg.style.left = 0 + svg.style.top = 0 + svg.style.zIndex = 0 + svg.style.overflow = 'visible' + svg.setAttribute('width', 2) + svg.setAttribute('height', 2) + svg.setAttribute('id', 'svg') + svg.setAttribute('width', '100%') + svg.setAttribute('height', '100%') + document.body.appendChild(svg) + + wrapper = document.createElement('div') + wrapper.id = 'wrapper' + document.body.append(wrapper) + + nav = document.getElementById('nav') + + const socket = new WebSocket('ws://localhost:8081') + + socket.onopen = function(evt) { + // pass to global ref + sckt = this + // say hello + socketSend('console', 'hello server') + console.log('socket open') + // ask for the current program + socketSend('get current program', '') + // main socket entry point + this.onmessage = (evt) => { + socketRecv(evt) + } + // others + this.onerror = (err) => { + alert('link to server is broken') + location.reload() + console.log('socket error', err) + } + this.onclose = (evt) => { + console.log('socket closed', evt) + sckt = null + } } } -} -/* + /* -RECV / SEND PORTALS --------------------------------------------------- + RECV / SEND PORTALS --------------------------------------------------- -*/ + */ -function socketSend(type, data) { - var msg = { - type: type, - data: data + function socketSend(type, data) { + var msg = { + type: type, + data: data + } + console.log('SEND', msg) + sckt.send(JSON.stringify(msg)) } - console.log('SEND', msg) - sckt.send(JSON.stringify(msg)) -} - -function socketRecv(evt) { - var recv = JSON.parse(evt.data) - var type = recv.type - var data = recv.data - console.log('RECV', recv) - // tree banger - switch (type) { - case 'console': - console.log('RECV CONSOLE:', data) - break - case 'put module menu': - console.log('RECV MODULE MENU') - heapSendsModuleMenu(data) - break - case 'put program menu': - console.log('RECV PRG MENU') - heapSendsProgramMenu(data) - break - case 'put program': - console.log('RECV PROGRAM') - heapSendsNewProgram(data) - break - case 'put module': - console.log('RECV NEW MODULE') - heapSendsNewModule(data) - break - case 'put module change': - console.log('RECV MODULE CHANGE') - heapSendsModuleChange(data) - break - case 'put state change': - console.log('RECV STATE CHANGE') - heapSendsStateChange(data) - break - case 'restart': - location.reload() - default: - console.log('ERR recv with non recognized type', recv) - break + + function socketRecv(evt) { + var recv = JSON.parse(evt.data) + var type = recv.type + var data = recv.data + console.log('RECV', recv) + // tree banger + switch (type) { + case 'console': + console.log('RECV CONSOLE:', data) + break + case 'put module menu': + console.log('RECV MODULE MENU') + heapSendsModuleMenu(data) + break + case 'put program menu': + console.log('RECV PRG MENU') + heapSendsProgramMenu(data) + break + case 'put program': + console.log('RECV PROGRAM') + heapSendsNewProgram(data) + break + case 'put module': + console.log('RECV NEW MODULE') + heapSendsNewModule(data) + break + case 'put module change': + console.log('RECV MODULE CHANGE') + heapSendsModuleChange(data) + break + case 'put state change': + console.log('RECV STATE CHANGE') + heapSendsStateChange(data) + break + case 'restart': + location.reload() + default: + console.log('ERR recv with non recognized type', recv) + break + } } -} -/* + /* -MISC --------------------------------------------------- + MISC --------------------------------------------------- -*/ + */ -/* + /* -HEAP -> SERVER --------------------------------------------------- + HEAP -> SERVER --------------------------------------------------- -*/ + */ -// always a rep, tho -var program = {} + // always a rep, tho + var program = {} -// re-writes the program, adds a description, -// and loads multiple representations of modules to the view + // re-writes the program, adds a description, + // and loads multiple representations of modules to the view -function heapSendsNewProgram(prgm) { - // whole hearted replace - // hello for bugs when we lay this on top of something else - program = prgm - // 1st we want to git rm old files ... - // when adding links, we'll have to add all and then draw links - console.log(program) - for (mdlName in program.modules) { - addRepToView(program.modules[mdlName]) + function heapSendsNewProgram(prgm) { + // whole hearted replace + // hello for bugs when we lay this on top of something else + program = prgm + // 1st we want to git rm old files ... + // when adding links, we'll have to add all and then draw links + console.log(program) + for (mdlName in program.modules) { + addRepToView(program.modules[mdlName]) + } + redrawLinks() } - redrawLinks() -} -function heapSendsNewModule(mdl) { - if (program.description == null) { - program.description.name = 'unnamed program' - } - if (program.modules == null) { - program.modules = {} - } - addRepToView(mdl) - program.modules[mdl.description.id] = mdl - redrawLinks() -} - -// writes DOM elements to represent the module, appends to the wrapper -// and appends to the rep object a .ui object -// containing references to those DOM objects - -function heapSendsModuleChange(data) { - console.log(data) - // data should be rep of changed module - var rep = program.modules[data.description.id] - // we want a general case, but for now we know we're looking for - // new event hookups or new state items - for (key in rep.outputs) { - var output = rep.outputs[key] - if (output.calls.length !== data.outputs[key].calls.length) { - rep.outputs = data.outputs + function heapSendsNewModule(mdl) { + if (program.description == null) { + program.description.name = 'unnamed program' + } + if (program.modules == null) { + program.modules = {} } + addRepToView(mdl) + program.modules[mdl.description.id] = mdl + redrawLinks() } - // ok - for (key in rep.state) { - var stateItem = rep.state[key] - if (stateItem != data.state[key]) { - stateItem = data.state[key] - rep.ui.state[key].value = data.state[key] + + // writes DOM elements to represent the module, appends to the wrapper + // and appends to the rep object a .ui object + // containing references to those DOM objects + + function heapSendsModuleChange(data) { + console.log(data) + // data should be rep of changed module + var rep = program.modules[data.description.id] + // we want a general case, but for now we know we're looking for + // new event hookups or new state items + for (key in rep.outputs) { + var output = rep.outputs[key] + if (output.calls.length !== data.outputs[key].calls.length) { + rep.outputs = data.outputs + } + } + // ok + for (key in rep.state) { + var stateItem = rep.state[key] + if (stateItem != data.state[key]) { + stateItem = data.state[key] + rep.ui.state[key].value = data.state[key] + } } + // wreckless or wonderful? + //clear(rep) + redrawLinks() } - // wreckless or wonderful? - //clear(rep) - redrawLinks() -} - -// update state from server to UI -function heapSendsStateChange(data) { - console.log('HEAP SENDS CHANGE STATE IN MODULE', data) - var rep = program.modules[data.id] - rep.state[data.key] = data.val - if (rep.state[data.key].type == 'multiline') { - rep.ui.state[data.key].value = data.val.value - } else { - rep.ui.state[data.key].value = data.val + + // update state from server to UI + function heapSendsStateChange(data) { + console.log('HEAP SENDS CHANGE STATE IN MODULE', data) + var rep = program.modules[data.id] + rep.state[data.key] = data.val + if (rep.state[data.key].type == 'multiline') { + rep.ui.state[data.key].value = data.val.value + } else { + rep.ui.state[data.key].value = data.val + } } -} -/* + /* -UI -> HEAP --------------------------------------------------- + UI -> HEAP --------------------------------------------------- -*/ + */ + -// push new state from UI to server -function putState(rep, key) { - var data = { - id: rep.description.id, - key: key, - val: rep.state[key] - } - socketSend('put state change', data) -} -// save ui position to server for reload -function putUi(rep) { - var data = { - description: { + // push new state from UI to server + function putState(rep, key) { + var data = { id: rep.description.id, - position: { - left: rep.description.position.left, - top: rep.description.position.top - } + key: key, + val: rep.state[key] } + socketSend('put state change', 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) + // save ui position to server for reload + function putUi(rep) { var data = { - from: { - id: oClk.rep.description.id, - output: oClk.name - }, - to: { - id: tClk.rep.description.id, - input: tClk.name + description: { + id: rep.description.id, + position: { + left: rep.description.position.left, + top: rep.description.position.top + } + } + } + + 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) } - socketSend('put link change', data) } -} -/* + /* -UTILITIES --------------------------------------------------- + UTILITIES --------------------------------------------------- -*/ + */ -function isStateKey(key) { - if (key.indexOf('_') == 0 || key == 'emitters' || key == 'onChange' || key == 'emitChange') { - return false - } else { - return true + function isStateKey(key) { + if (key.indexOf('_') == 0 || key == 'emitters' || key == 'onChange' || key == 'emitChange') { + return false + } else { + return true + } } -} -function redrawLinks() { - // probably not a great way to do this, we're removing everything - // svg -rm -r - while (svg.firstChild) { - svg.removeChild(svg.firstChild) - } - // find that link - var lnkPt - var nLnk = 0 - for (mdlName in program.modules) { - if (program.modules[mdlName].description.isLink) { - lnkPt = getLeftWall(program.modules[mdlName].ui.domElem) + function redrawLinks() { + // probably not a great way to do this, we're removing everything + // svg -rm -r + while (svg.firstChild) { + svg.removeChild(svg.firstChild) } - } - // redraw thru all links, just look at reps - for (mdlName in program.modules) { - var mdlRep = program.modules[mdlName] - for (key in mdlRep.outputs) { - var output = mdlRep.outputs[key] - var outputUi = mdlRep.ui.outputs[key] - for (input in output.calls) { - var toId = output.calls[input].parentId - var toKey = output.calls[input].key - var inputUi = program.modules[toId].ui.inputs[toKey] - var outPos = getOutputArrow(outputUi) - var inPos = getInputArrow(inputUi) - if (inputUi.isHovering || outputUi.isHovering) { - var bz = newBezier(outPos.x, outPos.y, inPos.x, inPos.y, true) - } else { - var bz = newBezier(outPos.x, outPos.y, inPos.x, inPos.y, false) - } + // find that link + var lnkPt + var nLnk = 0 + for (mdlName in program.modules) { + if (program.modules[mdlName].description.isLink) { + lnkPt = getLeftWall(program.modules[mdlName].ui.domElem) } } - if (mdlRep.description.isHardware && !mdlRep.description.isLink) { - nLnk++ - var hwPt = getRightWall(mdlRep.ui.domElem) - lnkPt.y += 10 * nLnk - var ln = newLine(hwPt.x, hwPt.y, lnkPt.x, lnkPt.y) + // redraw thru all links, just look at reps + for (mdlName in program.modules) { + var mdlRep = program.modules[mdlName] + for (key in mdlRep.outputs) { + var output = mdlRep.outputs[key] + var outputUi = mdlRep.ui.outputs[key] + for (input in output.calls) { + var toId = output.calls[input].parentId + var toKey = output.calls[input].key + var inputUi = program.modules[toId].ui.inputs[toKey] + var outPos = getOutputArrow(outputUi) + var inPos = getInputArrow(inputUi) + if (inputUi.isHovering || outputUi.isHovering) { + var bz = newBezier(outPos.x, outPos.y, inPos.x, inPos.y, true) + } else { + var bz = newBezier(outPos.x, outPos.y, inPos.x, inPos.y, false) + } + } + } + if (mdlRep.description.isHardware && !mdlRep.description.isLink) { + nLnk++ + var hwPt = getRightWall(mdlRep.ui.domElem) + lnkPt.y += 10 * nLnk + var ln = newLine(hwPt.x, hwPt.y, lnkPt.x, lnkPt.y) + } } } -} - -/* - -UI EVENTS --------------------------------------------------------------------- - -*/ - -// drag / pan etc - -document.body.style.overflow = 'hidden' -document.body.style.transform = 'scale(1) translate(0px, 0px)' -document.body.style.transformOrigin = '0px 0px' -// s/o @ Neil -function getCurrentTransform() { - // a string - var transform = document.body.style.transform - - var index = transform.indexOf('scale') - var left = transform.indexOf('(', index) - var right = transform.indexOf(')', index) - var s = parseFloat(transform.slice(left + 1, right)) - var index = transform.indexOf('translate') - var left = transform.indexOf('(', index) - var right = transform.indexOf('px', left) - var tx = parseFloat(transform.slice(left + 1, right)) - var left = transform.indexOf(',', right) - var right = transform.indexOf('px', left) - var ty = parseFloat(transform.slice(left + 1, right)) - var origin = document.body.style.transformOrigin - var pxx = origin.indexOf('px') - var ox = parseFloat(origin.slice(0, pxx)) - var pxy = origin.indexOf('px', pxx + 2) - var oy = parseFloat(origin.slice(pxx + 2, pxy)) - - return ({ - s: s, - tx: tx, - ty: ty, - ox: ox, - oy: oy - }) -} - -function elementIsNotModule(element) { - if ((element.tagName == 'HTML') || (element.tagName == 'BODY') || (element.tagName == 'svg')) { - return true - } else { - return false + + /* + + UI EVENTS --------------------------------------------------------------------- + + */ + + // drag / pan etc + + document.body.style.overflow = 'hidden' + document.body.style.transform = 'scale(1) translate(0px, 0px)' + document.body.style.transformOrigin = '0px 0px' + // s/o @ Neil + function getCurrentTransform() { + // a string + var transform = document.body.style.transform + + var index = transform.indexOf('scale') + var left = transform.indexOf('(', index) + var right = transform.indexOf(')', index) + var s = parseFloat(transform.slice(left + 1, right)) + var index = transform.indexOf('translate') + var left = transform.indexOf('(', index) + var right = transform.indexOf('px', left) + var tx = parseFloat(transform.slice(left + 1, right)) + var left = transform.indexOf(',', right) + var right = transform.indexOf('px', left) + var ty = parseFloat(transform.slice(left + 1, right)) + var origin = document.body.style.transformOrigin + var pxx = origin.indexOf('px') + var ox = parseFloat(origin.slice(0, pxx)) + var pxy = origin.indexOf('px', pxx + 2) + var oy = parseFloat(origin.slice(pxx + 2, pxy)) + + return ({ + s: s, + tx: tx, + ty: ty, + ox: ox, + oy: oy + }) } -} -onwheel = function(evt) { - var el = document.elementFromPoint(evt.pageX, evt.pageY) - if (elementIsNotModule(el)) { - var cT = getCurrentTransform() - evt.preventDefault() - evt.stopPropagation() - if (evt.deltaY > 0) { - var scale = 1.05 * cT.s + function elementIsNotModule(element) { + if ((element.tagName == 'HTML') || (element.tagName == 'BODY') || (element.tagName == 'svg')) { + return true } else { - var scale = 0.95 * cT.s + return false } - var tx = cT.tx + (evt.pageX - cT.ox) * (1 - 1 / cT.s) - var ty = cT.ty + (evt.pageY - cT.oy) * (1 - 1 / cT.s) + } + + onwheel = function(evt) { + var el = document.elementFromPoint(evt.pageX, evt.pageY) + if (elementIsNotModule(el)) { + var cT = getCurrentTransform() + evt.preventDefault() + evt.stopPropagation() + if (evt.deltaY > 0) { + var scale = 1.05 * cT.s + } else { + var scale = 0.95 * cT.s + } + var tx = cT.tx + (evt.pageX - cT.ox) * (1 - 1 / cT.s) + var ty = cT.ty + (evt.pageY - cT.oy) * (1 - 1 / cT.s) - // body - document.body.style.transform = `scale(${scale}) translate(${tx}px,${ty}px)` - document.body.style.transformOrigin = `${evt.pageX}px ${evt.pageY}px` + // body + document.body.style.transform = `scale(${scale}) translate(${tx}px,${ty}px)` + document.body.style.transformOrigin = `${evt.pageX}px ${evt.pageY}px` - // opposite for nav - nav.style.transformOrigin = `${evt.pageX}px ${evt.pageY}px` - nav.style.transform = `scale(${1/scale}) translate(${-tx*scale}px,${-ty*scale}px)` + // opposite for nav + nav.style.transformOrigin = `${evt.pageX}px ${evt.pageY}px` + nav.style.transform = `scale(${1/scale}) translate(${-tx*scale}px,${-ty*scale}px)` + } } -} -onmousedown = function(evt) { - var qr = document.querySelector(':focus') - if (qr) { - qr.blur() + onmousedown = function(evt) { + var qr = document.querySelector(':focus') + if (qr) { + qr.blur() + } + var el = document.elementFromPoint(evt.pageX, evt.pageY) + if (elementIsNotModule(el)) { + evt.preventDefault() + evt.stopPropagation() + window.addEventListener('mousemove', mouseMoveDragListener) + window.addEventListener('mouseup', mouseUpDragListener) + } + // removes any popup descriptions for list items in Module Menu + rmDescription() } - var el = document.elementFromPoint(evt.pageX, evt.pageY) - if (elementIsNotModule(el)) { + + function mouseMoveDragListener(evt) { evt.preventDefault() evt.stopPropagation() - window.addEventListener('mousemove', mouseMoveDragListener) - window.addEventListener('mouseup', mouseUpDragListener) + var cT = getCurrentTransform() + var dx = evt.movementX + var dy = evt.movementY + var tx = cT.tx + dx / cT.s + var ty = cT.ty + dy / cT.s + + // for body + document.body.style.transform = `scale(${cT.s}) translate(${tx}px,${ty}px)` + + // opposite for nav + nav.style.transform = `scale(${1/cT.s}) translate(${-tx*cT.s}px,${-ty*cT.s}px)` } -} - -function mouseMoveDragListener(evt) { - evt.preventDefault() - evt.stopPropagation() - var cT = getCurrentTransform() - var dx = evt.movementX - var dy = evt.movementY - var tx = cT.tx + dx / cT.s - var ty = cT.ty + dy / cT.s - - // for body - document.body.style.transform = `scale(${cT.s}) translate(${tx}px,${ty}px)` - - // opposite for nav - nav.style.transform = `scale(${1/cT.s}) translate(${-tx*cT.s}px,${-ty*cT.s}px)` -} - -function mouseUpDragListener(evt) { - window.removeEventListener('mousemove', mouseMoveDragListener) - window.removeEventListener('mouseup', mouseUpDragListener) -} - -// get json menu item and render -// and ask for module at /obj/key -oncontextmenu = function(evt) { - console.log(evt.target) - if (evt.target.className == 'modname') { - var modRep = program.modules[evt.target.innerHTML] - if (modRep) { - writeModuleOptionMenu(modRep) - } - } else { - if (sckt) { - socketSend('get module menu', '') + + function mouseUpDragListener(evt) { + window.removeEventListener('mousemove', mouseMoveDragListener) + window.removeEventListener('mouseup', mouseUpDragListener) + } + + // get json menu item and render + // and ask for module at /obj/key + oncontextmenu = function(evt) { + console.log(evt.target) + if (evt.target.className == 'modname') { + var modRep = program.modules[evt.target.innerHTML] + if (modRep) { + writeModuleOptionMenu(modRep) + } } else { - // socket brkn, reload page - location.reload() + if (sckt) { + socketSend('get module menu', '') + } else { + // socket brkn, reload page + location.reload() + } + // prevents event bubbling } - // prevents event bubbling + return false } - return false -} - -onmousemove = function(evt) { - var cT = getCurrentTransform() - lastPos.x = cT.ox - cT.tx + (evt.pageX - cT.ox) / cT.s - lastPos.y = cT.oy - cT.ty + (evt.pageY - cT.oy) / cT.s -} - -document.onkeydown = function(evt) { - switch (evt.key) { - case 'Escape': - location.reload() - break - case 's': - // get path ? - var path = prompt("path? starting at atkapi/programs/") - socketSend('save program', path) - break - case 'l': - socketSend('get program menu', '') - break - case 'm': - socketSend('get module menu', '') - break - default: - break + + + onmousemove = function(evt) { + var cT = getCurrentTransform() + lastPos.x = cT.ox - cT.tx + (evt.pageX - cT.ox) / cT.s + lastPos.y = cT.oy - cT.ty + (evt.pageY - cT.oy) / cT.s } -} - -function writeModuleOptionMenu(modRep) { - var menuDom = document.createElement('div') - menuDom.id = 'perModuleMenu' - menuDom.style.left = 10 + modRep.ui.domElem.offsetLeft + modRep.ui.domElem.offsetWidth + 'px' - menuDom.style.top = modRep.ui.domElem.offsetTop + 'px' - // future: rm all inputs, rm all outputs, rename, open (heirarchy) - var opts = ['delete', 'copy'] - for (i in opts) { - var li = document.createElement('li') - li.innerHTML = opts[i] - li.id = opts[i] - if (opts[i] == 'delete') { - li.addEventListener('click', function(evt) { - var data = { - id: modRep.description.id - } - socketSend('remove module', data) - wrapper.removeChild(document.getElementById('perModuleMenu')) - }) - } else if (opts[i] == 'copy') { - li.addEventListener('click', function(evt) { - var data = modRep.description.path - socketSend('put module', data) - wrapper.removeChild(document.getElementById('perModuleMenu')) - }) + + document.onkeydown = function(evt) { + switch (evt.key) { + case 'Escape': + location.reload() + break + case 's': + // get path ? + var path = prompt("path? starting at atkapi/programs/") + socketSend('save program', path) + break + case 'l': + socketSend('get program menu', '') + break + case 'm': + socketSend('get module menu', '') + break + default: + break + } + } + + function writeModuleOptionMenu(modRep) { + var menuDom = document.createElement('div') + menuDom.id = 'perModuleMenu' + menuDom.style.left = 10 + modRep.ui.domElem.offsetLeft + modRep.ui.domElem.offsetWidth + 'px' + menuDom.style.top = modRep.ui.domElem.offsetTop + 'px' + // future: rm all inputs, rm all outputs, rename, open (heirarchy) + var opts = ['delete', 'copy'] + for (i in opts) { + var li = document.createElement('li') + li.innerHTML = opts[i] + li.id = opts[i] + if (opts[i] == 'delete') { + li.addEventListener('click', function(evt) { + var data = { + id: modRep.description.id + } + socketSend('remove module', data) + wrapper.removeChild(document.getElementById('perModuleMenu')) + }) + } else if (opts[i] == 'copy') { + li.addEventListener('click', function(evt) { + var data = modRep.description.path + socketSend('put module', data) + wrapper.removeChild(document.getElementById('perModuleMenu')) + }) + } + menuDom.appendChild(li) } - menuDom.appendChild(li) + wrapper.append(menuDom) + + function rmListener(evt) { + var findMenu = document.getElementById('perModuleMenu') + if (findMenu != null && findMenu.id == 'perModuleMenu') { + wrapper.removeChild(findMenu) + } + evt.target.removeEventListener(evt.type, arguments.callee) + } + + document.addEventListener('click', rmListener) } - wrapper.append(menuDom) - function rmListener(evt) { - var findMenu = document.getElementById('perModuleMenu') - if (findMenu != null && findMenu.id == 'perModuleMenu') { - wrapper.removeChild(findMenu) + + // 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' + var title = document.createElement('div') + title.className = 'title' + title.innerHTML = 'module menu' + menuDom.appendChild(title) + for (key in tree) { + var ul = document.createElement('ul') + var header = document.createElement('h4') + //ul.innerHTML = key.toString() + // create header for ul + header.innerHTML = key.toString() + ul.append(header) + 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('mouseover', function(evt){ + rmDescription()// + writeModuleDescription(evt)// + }) + ////////////////////////////////////////////////////////// + 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) } - evt.target.removeEventListener(evt.type, arguments.callee) + + document.addEventListener('click', rmListener) } - document.addEventListener('click', rmListener) -} - -// 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' - var title = document.createElement('div') - title.className = 'title' - title.innerHTML = 'module menu' - menuDom.appendChild(title) - for (key in tree) { - var ul = document.createElement('ul') - ul.innerHTML = key.toString() - for (subkey in tree[key]) { + 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][subkey].path - li.innerHTML = subkey.toString() + var path = tree[key].path + li.innerHTML = key.toString() li.id = path li.addEventListener('click', function(evt) { var data = this.id - socketSend('put module', data) - wrapper.removeChild(document.getElementById('moduleMenu')) + socketSend('load program', data) + wrapper.removeChild(document.getElementById('programMenu')) }) - ul.appendChild(li) + menuDom.appendChild(li) } - menuDom.appendChild(ul) - } - wrapper.append(menuDom) + wrapper.append(menuDom) - function rmListener(evt) { - var findMenu = document.getElementById('moduleMenu') - if (findMenu !== null && findMenu.id == 'moduleMenu') { - wrapper.removeChild(findMenu) + 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) } - 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) + document.addEventListener('click', rmListener) } - wrapper.append(menuDom) - function rmListener(evt) { - var findMenu = document.getElementById('programMenu') - if (findMenu !== null && findMenu.id == 'programMenu') { - wrapper.removeChild(findMenu) + + // Paloma adds + + // module descriptions + const moduleDescriptionsObj = + { + and : 'this is the description for and', + atkbreadboard: 'this is the description for atkbreadboard', + atkseriallink: 'this is the description for atkseriallink', + atkstepper: 'this is the description for akstepper', + webcam : 'this is description for webcam', + planner: 'this is the description for planner', + rawmove: 'this is the description for rawmove', + gcode: 'this is the descriprion for gcode' } - // rm this listner... - evt.target.removeEventListener(evt.type, arguments.callee) + + function writeModuleDescription(evt) { + let liRect = evt.target.getBoundingClientRect(); + let menuDes = document.createElement('div') + menuDes.id = 'moduleDescription' + menuDes.style.left = 255 + liRect.left + 'px' + menuDes.style.top = liRect.top - 18 + 'px' + let parentEl = evt.target.parentElement + let headerKey = parentEl.firstChild.innerHTML + menuDes.innerHTML = moduleDescriptionsObj[evt.target.innerHTML] + wrapper.append(menuDes) } - document.addEventListener('click', rmListener) -} \ No newline at end of file + function rmDescription() { + let modDes = document.getElementById('moduleDescription') + if (modDes != null) { + wrapper.removeChild(modDes) + } + } \ No newline at end of file diff --git a/client/style.css b/client/style.css index 7ad87f552315c08de4042d0d1e173f90182d32fc..4156d2e14efdac91259f5f0964da2a7290453b7f 100644 --- a/client/style.css +++ b/client/style.css @@ -122,6 +122,14 @@ li:active{ background-color: #303030; } +#moduleDescription { + position: absolute; + width: 245px; + padding: 10px; + background-color: #303030; + color: white; +} + #programMenu { position: absolute; width: 245px; diff --git a/package-lock.json b/package-lock.json index c36b3529307813e28adaeecb7bb29d35fef8edb5..625b7fa709520ae142ad6fae9b426b94371f9207 100644 --- a/package-lock.json +++ b/package-lock.json @@ -784,6 +784,11 @@ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, + "http": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/http/-/http-0.0.0.tgz", + "integrity": "sha1-huYybSnF0Dnen6xYSkVon5KfT3I=" + }, "http-errors": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",