Commit ec3a71b6 authored by Matija Obreza's avatar Matija Obreza

Merge branch '29-add-node-id' into 'master'

Resolve "Add node ID"

Closes #29

See merge request genesys-pgr/diversity-tree-editor!63
parents 5cf905ca c647cb1a
......@@ -39,6 +39,7 @@
</div>
<div class="top-bar-right">
<ul class="menu">
<li><a href="#" id="nodesListBtn">All nodes</a></li>
<li><a href="#" id="creditsBtn">Credits</a></li>
<li><a href="#" id="instructionsBtn">Help</a></li>
<!-- <li><input type="search" placeholder="Search"></li>
......@@ -56,6 +57,7 @@
<h2 id="modalTitle">Node properties</h2>
<form id="NodePropertiesForm">
<input type="hidden" id="NodeAction" value="create" />
<input type="hidden" id="ParentFullID" value="" />
<div class="row">
<div class="large-12 columns">
<label>
......@@ -72,13 +74,29 @@
</label>
</div>
</div>
<div class="row">
<div class="large-12 columns">
<label>
Node ID
<input type="text" class="inputName" id='NodeID' placeholder="PEA" />
</label>
</div>
</div>
<div class="row">
<div class="large-12 columns">
<label>
Full node ID
<input type="text" class="inputName" id='FullNodeID' disabled/>
</label>
</div>
</div>
<div class="row">
<div class="large-8 columns">
&nbsp;
</div>
<div class="large-4 columns">
<a href="#" data-close class="button info closeModal">Cancel</a>
<button type="submit" class="button success">Confirm</button>
<button type="submit" id="ConfirmBtn" class="button success">Confirm</button>
</div>
</div>
</form>
......@@ -148,6 +166,16 @@
<a class="close-button" data-close aria-label="Close">&#215;</a>
</div>
<div id="AllNodesListModal" class="reveal" data-reveal aria-labelledby="modalTitle" aria-hidden="true" role="dialog" style="width: 700px">
<table id="nodesTable" border="1">
<caption>List of all nodes</caption>
<tbody>
<tr><th>ID</th><th>Node title</th></tr>
</tbody>
</table>
<a class="close-button" data-close aria-label="Close">&#215;</a>
</div>
<div id="InstructionsModal" class="reveal" data-reveal aria-labelledby="modalTitle" aria-hidden="true" role="dialog">
<h2 id="modalTitle">How to use the interactive tree editor</h2>
<div class="text">
......
This diff is collapsed.
......@@ -16,12 +16,12 @@
"author": "",
"license": "MIT",
"dependencies": {
"axios": "^0.17.1",
"axios": "^0.19.2",
"babel-polyfill": "^6.26.0",
"d3": "^3.5.17",
"foundation": "^4.2.1",
"foundation-sites": "^6.4.4-rc1",
"jquery": "^3.3.1",
"jquery": "^3.5.1",
"underscore": "^1.8.3"
},
"babel": {
......@@ -42,6 +42,6 @@
"json-loader": "^0.5.7",
"style-loader": "^0.20.3",
"webpack": "^3.11.0",
"webpack-dev-server": "^2.11.2"
"webpack-dev-server": "^2.11.5"
}
}
......@@ -11,6 +11,7 @@ function close_modal(dialog) {
const NODE_HEIGHT = 30; // 30 pixels for node
const NODE_WIDTH = 350; // 350px for level.
let nodes_keys = [];
var tree_root;
var create_node_modal_active = false;
var rename_node_modal_active = false;
......@@ -60,16 +61,23 @@ export function create_node() {
create_node_parent.children = [];
}
let id = generateUUID();
let nodeId = $('#NodeID').val();
let fullId = `${create_node_parent.fullID}.${nodeId}`;
let name = $('#NodeName').val();
let nodeWeight = parseFloat($('#NodeWeight').val()) || undefined;
let new_node = { 'name': name,
'weight': nodeWeight,
'id' : id,
'nodeId' : nodeId,
'fullID' : fullId,
'parent' : create_node_parent,
'depth': create_node_parent.depth + 1,
};
console.log('Create Node name: ' + name, new_node);
create_node_parent.children.push(new_node);
computeAbsoluteWeight(tree_root, 100);
assignIDs(create_node_parent);
updateNodesKeys();
create_node_modal_active = false;
$('#NodeName').val('');
}
......@@ -93,16 +101,48 @@ function computeAbsoluteWeight(node, weight) {
}
}
function assignIDs(node) {
if (! node.nodeId) {
node.nodeId = '';
}
if (node.parent) {
if (node.nodeId !== '') {
node.fullID = `${node.parent.fullID}.${node.nodeId}`;
} else {
node.nodeId = (node.parent.children ? node.parent.children.indexOf(node) : node.parent._children.indexOf(node)) + 1;
node.fullID = `${node.parent.fullID}.${node.nodeId}`
}
} else {
node.fullID = node.nodeId || '0';
}
if (node.children && node.children.length !== 0) {
node.children.forEach((child) => {
assignIDs(child);
});
} else if (node._children && node._children.length !== 0) {
node._children.forEach((child) => {
assignIDs(child);
});
}
}
export function rename_node() {
console.log('Modifying node', node_to_rename);
if (node_to_rename && rename_node_modal_active) {
let name = $('#NodeName').val();
let nodeWeight = parseFloat($('#NodeWeight').val()) || undefined;
let nodeId = $('#NodeID').val();
let fullId = $('#FullNodeID').val();
console.log('Modified node name: ' + name);
node_to_rename.name = name;
node_to_rename.weight = nodeWeight;
node_to_rename.nodeId = nodeId;
node_to_rename.fullID = fullId;
rename_node_modal_active = false;
computeAbsoluteWeight(tree_root, 100);
assignIDs(node_to_rename);
updateNodesKeys();
}
close_modal($('#NodePropertiesModal'));
outer_update(node_to_rename);
......@@ -112,6 +152,10 @@ export function getTree() {
return tree_root;
}
export function getNodesKeys() {
return nodes_keys;
}
export function editContributors(contributors) {
if (Array.isArray(contributors)) {
if (contributors.length === 1 && !contributors[0]) {
......@@ -124,6 +168,52 @@ export function editContributors(contributors) {
let outer_update = null;
export function draw_nodes_table(tbody) {
$(tbody).empty();
$(tbody).append(`<tr><th>ID</th><th>Node title</th></tr>`);
const nodes = getNodesKeys().sort((a, b) => {
if ((a.id !== null && a.id !== undefined) && (b.id !== null || b.id !== undefined)) {
const dA = a.id.match(/\./g) || 0; // dots in A
const dB = b.id.match(/\./g) || 0; // dots in B
if (dA.length === dB.length) {
return a.id.localeCompare(b.id);
} else {
return dA - dB;
}
} else if (a.id !== null) {
return 1;
} else {
return -1;
}
});
for (let n of nodes) {
$(tbody).append(`<tr><td>${n.id}</td><td>${n.name}</td></tr>`);
}
}
function updateNodesKeys() {
nodes_keys = updateKeys(tree_root);
}
function updateKeys(node) {
if (! node) {
return [];
}
let array = [{id: node.fullID, name: node.name}];
if (hasChildren(node)) {
if (node.children) {
for (let ch of node.children) {
array = array.concat(updateKeys(ch));
}
} else if (node._children) {
for (let ch of node._children) {
array = array.concat(updateKeys(ch));
}
}
}
return array.sort((a, b) => (a.id > b.id) ? 1 : -1);
}
export function draw_tree(container, treeData) {
// clear the container
$(container).empty();
......@@ -167,10 +257,14 @@ export function draw_tree(container, treeData) {
{
title: 'Node properties',
action: function(elm, d, i) {
console.log('Rename node');
console.log('Update node');
rename_node_modal_active = true;
node_to_rename = d;
$('#NodeAction').val('modify');
$('#ConfirmBtn').removeAttr('disabled');
$("#ParentFullID").val(d.parent ? d.parent.fullID : '');
$("#FullNodeID").val(d.fullID);
$("#NodeID").val(d.nodeId);
$("#NodeName").val(d.name);
$("#NodeWeight").val(d.weight);
$('#NodePropertiesModal').foundation('open');
......@@ -184,6 +278,10 @@ export function draw_tree(container, treeData) {
create_node_parent = d;
create_node_modal_active = true;
$('#NodeAction').val('create');
$('#ConfirmBtn').removeAttr('disabled');
$("#ParentFullID").val(d.fullID);
$("#FullNodeID").val('');
$("#NodeID").val('');
$("#NodeName").val('');
$("#NodeWeight").val(''); // 100 - sumChildrenWeights(d)
$('#NodePropertiesModal').foundation('open');
......@@ -239,6 +337,7 @@ export function draw_tree(container, treeData) {
function(d) {
return d.children && d.children.length > 0 ? d.children : null;
});
updateNodesKeys();
}
......@@ -741,4 +840,10 @@ export function draw_tree(container, treeData) {
update(root);
centerNode(root);
tree_root = root;
if (root.fullID === undefined) {
console.log('Calculating fullID for each node...');
assignIDs(root);
}
updateNodesKeys();
}
......@@ -10,7 +10,7 @@ import '../styles/app.css';
import '../styles/d3-context-menu.css';
import '../src/d3-context-menu';
import {draw_tree, create_node, rename_node, getTree, editContributors} from './dndTree';
import {draw_tree, create_node, getNodesKeys, draw_nodes_table, rename_node, getTree, editContributors} from './dndTree';
import {MENU_TREES} from './menu/trees';
......@@ -31,7 +31,7 @@ const TREE_STORAGE_NAME = 'lastTree';
// We need to remove parent property from all nodes to avoid an error with converting circular structure to JSON
const cleanTreeJson = (node) => {
const keepProperties = ['name', 'weight', 'contributors'];
const keepProperties = ['name', 'weight', 'contributors', 'nodeId', 'fullID'];
// console.log('Cleaning', node);
const copy = {};
......@@ -208,6 +208,12 @@ $('document').ready(function() {
$('#ImportTreeModal').focus();
});
$('#nodesListBtn').on('click', () => {
draw_nodes_table($('#nodesTable').find('tbody'));
$('#AllNodesListModal').foundation('open');
$('#AllNodesListModal').focus();
});
$('#editContributorsBtn').on('click', () => {
const contributorsText = $('#contributorsText');
contributorsText.attr('placeholder', contributorsText.prop('placeholder').replace(/\\n/g, '\n'));
......@@ -237,10 +243,28 @@ $('document').ready(function() {
}
});
$('#NodePropertiesForm #NodeID').on('input propertychange', () => {
const parentFullIdValue = $('#ParentFullID').val();
const typedValue = $('#NodeID').val();
if (typedValue.length > 0) {
const fullId = parentFullIdValue.length > 0 ? `${parentFullIdValue}.${typedValue}` : typedValue;
if (getNodesKeys().findIndex(x => x.id === fullId) !== -1) {
$('#ConfirmBtn').attr('disabled', true);
} else {
$('#ConfirmBtn').removeAttr('disabled');
}
$('#FullNodeID').val(fullId);
} else {
$('#FullNodeID').val('');
}
});
const resetTree = () => {
let newTree = {
name: 'Entire genepool',
weight: undefined,
nodeId: undefined,
fullID: undefined,
};
draw_tree($('#tree-container'), newTree);
rememberCurrentTree(newTree);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment