From b2d6e2b4ac56e4ece3ecbe3f98d64ea9bd107151 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Sat, 13 Jun 2020 23:57:19 +0200 Subject: Refactor the way node hierarchies are being represented. Add state attribute. --- src/ws/munia.css | 61 +++++++++++++++++------ src/ws/node.js | 146 +++++++++++++++++++++++++++++++++++++------------------ src/ws/view.js | 143 ++++++++++++++++++++++++++++++++++------------------- 3 files changed, 239 insertions(+), 111 deletions(-) diff --git a/src/ws/munia.css b/src/ws/munia.css index 8eeebba..38b435f 100644 --- a/src/ws/munia.css +++ b/src/ws/munia.css @@ -27,12 +27,20 @@ body border-width: 1px; border-color: black; border-radius: 3px; - padding: 6px; - margin: 10px; -/* max-width: 800px;*/ + padding: 0px; + margin: 0px; margin-left: auto; margin-right: auto; - overflow: hidden; +} + +.node + .node +{ + margin-top: 12px; +} + +.node .data +{ + background-color: grey; } .node .id @@ -52,9 +60,27 @@ body pointer-events: none; } +.node .state +{ + float: right; + padding-left: 5px; + padding-right: 5px; + background: transparent; + pointer-events: none; +} + +.node .description +{ + clear: both; + padding-left: 5px; + background: transparent; + pointer-events: none; +} + .node .edit { border-color: red; + pointer-events: all; /* border: inherit; padding: inherit; @@ -63,30 +89,33 @@ body */ } -.node .add_button +.node .button { float: right; display: inline-box; width: 1em; height: 1em; - font-size: 0.5em; + font-size: 0.7em; vertical-align: text-center; text-align: center; border: solid green 2px; cursor: pointer; + pointer-events: auto; } -.node .collapse_button +.node .children { - float: right; - display: inline-box; - width: 1em; - height: 1em; - font-size: 0.5em; - vertical-align: text-center; - text-align: center; - border: solid green 2px; - cursor: pointer; + padding: 6px; + min-height: 5px; + border: dotted 1px black; + overflow: hidden; +} + +.collapsed +{ + background-image: linear-gradient(to bottom, rgba(0,0,0,0), rgba(0,0,0,0.6)); + max-height: 16px; + padding: 16px; } .board diff --git a/src/ws/node.js b/src/ws/node.js index fa97368..dff7056 100644 --- a/src/ws/node.js +++ b/src/ws/node.js @@ -33,6 +33,11 @@ function findNode(id, subscribeid) return null; } +function findNodeFromString(idstr) +{ + return findNode(idFromStr(idstr), subscriptionIdFromStr(idstr)); +} + function Node(id, subscribeid) { this.id = id; @@ -40,13 +45,6 @@ function Node(id, subscribeid) this.children = new Array(); this.attributes = {}; this.parent = null; - - // Elements: - this.element = document.createElement("div"); - this.div_id = document.createElement("span"); - this.div_id.setAttribute("class", "id"); - this.div_title = document.createElement("span"); - this.div_title.setAttribute("class", "title"); } Node.prototype.dump = function() @@ -94,8 +92,7 @@ Node.prototype.addChild = function(node, insertBeforeId) if(this.children[i].id == insertBeforeId) { this.children.splice(i - 1, 0, node); - // Insert after id, title, add button and collapse button (ie. + 4) - this.element.insertBefore(node.element, this.element.childNodes[i + 4]); + this.children_element.insertBefore(node.element, this.children_element.childNodes[i]); inserted = true; break; } @@ -104,17 +101,17 @@ Node.prototype.addChild = function(node, insertBeforeId) if(inserted == false) { this.children.push(node); - this.element.appendChild(node.element); + this.children_element.appendChild(node.element); } - if(this.children.length == 0) - { - this.element.style.backgroundColor = "#aaa"; - } - else - { - this.element.style.backgroundColor = "#aaaa81"; - } +// if(this.children.length == 0) +// { +// this.element.style.backgroundColor = "#aaa"; +// } +// else +// { +// this.element.style.backgroundColor = "#aaaa81"; +// } }; Node.prototype.removeChild = function(node) @@ -124,32 +121,57 @@ Node.prototype.removeChild = function(node) return e.id != node.id; }); node.parent = null; - this.element.removeChild(node.element); - - if(this.children.length == 0) - { - this.element.style.backgroundColor = "#aaa"; - } - else - { - this.element.style.backgroundColor = "#aaaa81"; - } + this.children_element.removeChild(node.element); + +// if(this.children.length == 0) +// { +// this.element.style.backgroundColor = "#aaa"; +// } +// else +// { +// this.element.style.backgroundColor = "#aaaa81"; +// } }; Node.prototype.create = function() { + // Node root element + this.element = document.createElement("div"); + + // Element for title, description, state, etc... + this.data_element = document.createElement("div"); + this.data_element.className = "data"; + this.data_element.style.pointerEvents = "none"; + this.element.appendChild(this.data_element); + + // Root element for child nodes. + this.children_element = document.createElement("div"); + this.children_element.className = "children"; + this.element.appendChild(this.children_element); + + + this.div_id = document.createElement("span"); + this.div_id.setAttribute("class", "id"); + this.data_element.appendChild(this.div_id); + + this.div_title = document.createElement("span"); + this.div_title.setAttribute("class", "title"); + var id_txt = document.createTextNode(this.id); + this.div_id.appendChild(id_txt); + this.data_element.appendChild(this.div_title); + this.setAttribute("title", ""); + var node = this.element; node.name = "node"; node.setAttribute("class", "node"); node.setAttribute("ondblclick", "editTitle(event)"); - //node.setAttribute("onclick", "showHideChildren(this, event)"); node.setAttribute("ondrop", "drop(event)"); node.setAttribute("ondragenter", "dragenter(event)"); node.setAttribute("ondragover", "dragover(event)"); node.setAttribute("ondragleave", "dragleave(event)"); node.setAttribute("draggable", true); - node.setAttribute("ondragstart", "drag(this, event)"); + node.setAttribute("ondragstart", "drag(event)"); node.setAttribute("ondragend", "dragEnd(event)"); node.setAttribute("nodeid", this.id); @@ -161,19 +183,28 @@ Node.prototype.create = function() add_child_button.name = "add_button"; add_child_button.setAttribute("onclick", "addChild(event)"); add_child_button.setAttribute("nodeid", this.id); - add_child_button.setAttribute("class", "add_button"); + add_child_button.setAttribute("class", "button"); var txt_plus = document.createTextNode("+"); add_child_button.appendChild(txt_plus); - node.appendChild(add_child_button); + this.data_element.appendChild(add_child_button); var collapse_button = document.createElement("div"); collapse_button.name = "add_button"; collapse_button.setAttribute("onclick", "collapse(event)"); collapse_button.setAttribute("nodeid", this.id); - collapse_button.setAttribute("class", "collapse_button"); - var txt_plus = document.createTextNode("v"); - collapse_button.appendChild(txt_plus); - node.appendChild(collapse_button); + collapse_button.setAttribute("class", "button"); + var txt_v = document.createTextNode("v"); + collapse_button.appendChild(txt_v); + this.data_element.appendChild(collapse_button); + + this.state_element = document.createElement("div"); + this.state_element.name = "state"; + this.state_element.setAttribute("onclick", "changeState(event)"); + this.state_element.setAttribute("nodeid", this.id); + this.state_element.setAttribute("class", "state"); + var txt_state = document.createTextNode(""); + this.state_element.appendChild(txt_state); + this.data_element.appendChild(this.state_element); /* var subscribe_button = document.createElement("div"); @@ -183,7 +214,7 @@ Node.prototype.create = function() subscribe_button.setAttribute("style", "float: left; display: inline-box; width:14px; height: 14px; border: solid green 2px; cursor: pointer;"); var txt_plus = document.createTextNode("+"); subscribe_button.appendChild(txt_plus); - node.appendChild(subscribe_button); + this.data_element.appendChild(subscribe_button); var unsubscribe_button = document.createElement("div"); unsubscribe_button.name = "unsubscribe_button"; @@ -192,24 +223,20 @@ Node.prototype.create = function() unsubscribe_button.setAttribute("style", "float: left; display: inline-box; width:14px; height: 14px; border: solid red 2px; cursor: pointer;"); var txt_minus = document.createTextNode("-"); unsubscribe_button.appendChild(txt_minus); - node.appendChild(unsubscribe_button); + this.data_element.appendChild(unsubscribe_button); */ - this.element.appendChild(this.div_id); - var id_txt = document.createTextNode(this.id); - this.div_id.appendChild(id_txt); - this.element.appendChild(this.div_title); - this.setAttribute("title", ""); - { var collapsed = getCookie(node.id+"_collapsed") == "true"; if(collapsed) { - this.element.style.maxHeight = "32px"; + //this.children_element.style.maxHeight = "16px"; + this.children_element.classList.add('collapsed'); } else { - this.element.style.maxHeight = "inherit"; + //this.children_element.style.maxHeight = "inherit"; + this.children_element.classList.remove('collapsed'); } } }; @@ -245,6 +272,33 @@ Node.prototype.setAttribute = function(name, value) this.element.setAttribute("draggable", true); } } + + if(name == "state") + { + var txt = this.state_element.firstChild; + if(txt != null) + { + this.state_element.removeChild(txt); + } + txt = document.createTextNode(value); + this.state_element.appendChild(txt); + if(value == "done") + { + this.state_element.style.color = "green"; + } + else if(value == "in-progress") + { + this.state_element.style.color = "yellow"; + } + else if(value == "blocked") + { + this.state_element.style.color = "red"; + } + else + { + this.state_element.style.color = "black"; + } + } }; Node.prototype.getTitle = function() diff --git a/src/ws/view.js b/src/ws/view.js index 2c9d507..986e3f9 100644 --- a/src/ws/view.js +++ b/src/ws/view.js @@ -82,6 +82,11 @@ function deleteNode(id) function getElementAfter(e) { + if(e.target.className != "children") + { + return null; + } + var element_after = null; var min_y_diff = 9999999999999; for(i = 0; i < e.target.children.length; ++i) @@ -102,15 +107,22 @@ function getElementAfter(e) return element_after; } -function drag(target, e) +function drag(e) { - e.dataTransfer.setData('id', target.id); + // e.target is always a node.element here + var id = e.target.id; + e.dataTransfer.setData('id', id); e.stopPropagation(); // <--- this fixes the drag target problem - update(idFromStr(target.id), "dragged", "true"); + update(idFromStr(id), "dragged", "true"); } function dragenter(e) { + // Only highlight children areas + if(e.target.className != "children") + { + return; + } e.target.style.backgroundColor = "#646588"; last_over = e.target; } @@ -118,6 +130,12 @@ function dragenter(e) var last_after = null; function dragover(e) { +// // Only highlight children areas +// if(e.target.className != "children") +// { +// return; +// } + e.preventDefault(); var after = getElementAfter(e); @@ -134,11 +152,29 @@ function dragover(e) function dragleave(e) { + // Only highlight children areas + if(e.target.className != "children") + { + return; + } + e.target.style.backgroundColor = "#aaa"; } function dragEnd(e) { + e.stopPropagation(); + + // FIXME: This doesn't seem to work in Chromium 65 + var id = e.dataTransfer.getData('id'); + update(idFromStr(id), "dragged", "false"); + +// // Only highlight children areas +// if(e.target.className != "children") +// { +// return; +// } + e.target.style.backgroundColor = "#aaa"; if(last_after != null) @@ -154,20 +190,26 @@ function dragEnd(e) } e.preventDefault(); - e.stopPropagation(); - - // FIXME: This doesn't seem to work in Chromium 65 - var id = e.dataTransfer.getData('id'); - update(idFromStr(id), "dragged", "false"); } function drop(e) { + e.stopPropagation(); + + // Only allow drops in children areas + if(e.target.className != "children") + { + return; + } + var id = e.dataTransfer.getData('id'); - update(idFromStr(id), "dragged", "false"); + //update(idFromStr(id), "dragged", "false"); + // Get drop id from targets parent (children tag inside the node) + var dropid = e.target.parentElement.id; + console.log("dropid: " + dropid); // Prevent dropping on item itself - if(id == e.target.id) + if(id == dropid) { return; } @@ -178,7 +220,7 @@ function drop(e) { before_id = idFromStr(element_after.id); } - move(idFromStr(id), idFromStr(e.target.id), before_id); + move(idFromStr(id), idFromStr(dropid), before_id); } function subscribeMe(target, e) @@ -193,28 +235,6 @@ function unsubscribeMe(target, e) unsubscribe(target.nodeid); } -function showHideChildren(target, e) -{ - e.stopPropagation(); - updateid = idFromStr(target.id); - if(target.style.backgroundColor != "red") - { - target.style.backgroundColor = "red"; - for(i = 1; i < target.childNodes.length; i++) - { - target.childNodes[i].style.display = "none"; - } - } - else - { - target.style.backgroundColor = "#aaa"; - for(i = 1; i < target.childNodes.length; i++) - { - target.childNodes[i].style.display = "block"; - } - } -} - function node_submit() { var data = document.getElementById("input_node_data"); @@ -238,52 +258,77 @@ var lineedit; var lineeditparent; function onKeyUpHandler(e) { + var node = findNodeFromString(e.target.id); + if(node == null) + { + return; // no node + } + + var lineedit = e.target; + var updateid = idFromStr(lineedit.id); + if(e.which == 13) { // enter - lineeditparent.removeChild(lineedit); - lineeditparent.nodeValue = 'updating...'; + node.data_element.removeChild(lineedit); + //node.data_element.nodeValue = 'updating...'; update(updateid, "title", lineedit.value); } if(e.which == 27) { // escape - lineeditparent.removeChild(lineedit); + node.data_element.removeChild(lineedit); } } function onLostFocusHandler(e) { - lineeditparent.removeChild(lineedit); + var node = findNodeFromString(e.target.id); + if(node == null) + { + return; // no node + } + + var lineedit = e.target; + + node.data_element.removeChild(lineedit); } function editTitle(e) { e.stopPropagation(); - updateid = idFromStr(e.target.id); - subscriptionId = subscriptionIdFromStr(e.target.id); - - var node = findNode(updateid, subscriptionId); + var node = findNodeFromString(e.target.id); + if(node == null) + { + return; // no node + } - lineedit = document.createElement("input"); + var lineedit = document.createElement("input"); lineedit.setAttribute("class", "edit"); lineedit.setAttribute("onkeyup", "onKeyUpHandler(event)"); lineedit.setAttribute("onblur", "onLostFocusHandler(event)"); lineedit.value = node.getTitle(); - e.target.appendChild(lineedit); - //e.target.insertBefore(e.target.childNodes[2], lineedit); - lineeditparent = e.target; + lineedit.id = e.target.id; + node.data_element.appendChild(lineedit); + //lineeditparent = e.target; lineedit.focus(); } function addChild(e) { e.stopPropagation(); - id = idFromStr(e.target.parentElement.id); + id = idFromStr(e.target.parentElement.parentElement.id); create("x", id, -1); } function collapse(e) { - var id = e.target.parentElement.id; + var id = e.target.parentElement.parentElement.id; + + var node = findNodeFromString(id); + if(node == null) + { + return; // no node + } + var collapsed = getCookie(id+"_collapsed") == "true"; collapsed = !collapsed; setCookie(id+"_collapsed", collapsed?"true":"false"); @@ -291,10 +336,10 @@ function collapse(e) e.stopPropagation(); if(collapsed) { - e.target.parentElement.style.maxHeight = "32px"; + node.children_element.classList.add('collapsed'); } else { - e.target.parentElement.style.maxHeight = "inherit"; + node.children_element.classList.remove('collapsed'); } } -- cgit v1.2.3