Commit b4db07e0 authored by Jérome Perrin's avatar Jérome Perrin

graph editor: (partially) update to new json format

parent 87834a56
...@@ -15,28 +15,14 @@ ...@@ -15,28 +15,14 @@
return gadget.getDeclaredGadget("productionline_graph"); return gadget.getDeclaredGadget("productionline_graph");
}) })
.push(function (graph_gadget) { .push(function (graph_gadget) {
return graph_gadget.getData(); return graph_gadget.getContent();
})
.push(function (data) {
graph_data = data;
// Always get a fresh version, to prevent deleting spreadsheet & co
return gadget.aq_getAttachment({
"_id": gadget.props.jio_key,
"_attachment": "body.json"
});
}) })
.push(function (body) { .push(function (body) {
var data = JSON.parse(body), console.log("saving", JSON.parse(body));
json_graph_data = JSON.parse(graph_data);
data.nodes = json_graph_data.nodes;
data.edges = json_graph_data.edges;
data.preference = json_graph_data.preference;
return gadget.aq_putAttachment({ return gadget.aq_putAttachment({
"_id": gadget.props.jio_key, "_id": gadget.props.jio_key,
"_attachment": "body.json", "_attachment": "body.json",
"_data": JSON.stringify(data, null, 2), "_data": body, //JSON.stringify(data, null, 2),
"_mimetype": "application/json" "_mimetype": "application/json"
}); });
}) })
......
...@@ -24,7 +24,19 @@ ...@@ -24,7 +24,19 @@
loopEventListener, promiseEventListener, DOMParser) { loopEventListener, promiseEventListener, DOMParser) {
"use strict"; "use strict";
/*jslint nomen: true*/ /*jslint nomen: true */
/* TODO:
* - make node edit a gadget ?
* - add function to turn event handlers in promise. Or just use event
* handlers ? XXX understand the diff with example
*
* tests:
* - loading
* - dragging a node
* - clicking a node
* - connecting two nodes ? (see jsplumb tests)
* - removing a connection
*/
var gadget_klass = rJS(window), var gadget_klass = rJS(window),
node_template_source = gadget_klass.__template_element node_template_source = gadget_klass.__template_element
.getElementById('node-template').innerHTML, .getElementById('node-template').innerHTML,
...@@ -88,18 +100,20 @@ ...@@ -88,18 +100,20 @@
return node_id; return node_id;
} }
function getElementId(node_container, node_id) { function getElementId(gadget, node_id) {
return node_container[node_id].element_id; // TODO: inline
return gadget.props.dom_element_id_container[node_id];
} }
function generateNodeId(gadget, element_type, option) { function generateNodeId(gadget, element) {
var n = 1; var n = 1,
while (gadget.props.node_container[ class_def = gadget.props.data.class_definition[element._class],
((option.short_id || element_type) + n) id = class_def.short_id || element._class;
] !== undefined) { console.log("gni", element, class_def);
while (gadget.props.node_container[id + n] !== undefined) {
n += 1; n += 1;
} }
return (option.short_id || element_type) + n; return id + n;
} }
function generateElementId(gadget_element) { function generateElementId(gadget_element) {
...@@ -112,13 +126,14 @@ ...@@ -112,13 +126,14 @@
function updateConnectionData(gadget, connection, remove, edge_data) { function updateConnectionData(gadget, connection, remove, edge_data) {
if (remove) { if (remove) {
delete gadget.props.edge_container[connection.id]; delete gadget.props.data.graph.main_graph.edge[connection.id];
} else { } else {
gadget.props.edge_container[connection.id] = [ edge_data = edge_data || {'_class': 'Dream.Edge'};
getNodeId(gadget.props.node_container, connection.sourceId), edge_data.source = getNodeId(gadget.props.node_container,
getNodeId(gadget.props.node_container, connection.targetId), connection.sourceId);
edge_data || {} edge_data.destination = getNodeId(gadget.props.node_container,
]; connection.targetId);
gadget.props.data.graph.main_graph.edge[connection.id] = edge_data;
} }
gadget.notifyDataChanged(); gadget.notifyDataChanged();
} }
...@@ -149,8 +164,7 @@ ...@@ -149,8 +164,7 @@
} }
function convertToAbsolutePosition(gadget, x, y) { function convertToAbsolutePosition(gadget, x, y) {
var zoom_level = (gadget.props.preference_container.zoom_level || 1.0) * var zoom_level = gadget.props.zoom_level * 1.1111,
1.1111,
canvas_size_x = $(gadget.props.element).find('#main').width(), canvas_size_x = $(gadget.props.element).find('#main').width(),
canvas_size_y = $(gadget.props.element).find('#main').height(), canvas_size_y = $(gadget.props.element).find('#main').height(),
size_x = $(gadget.props.element).find('.dummy_window').width() * size_x = $(gadget.props.element).find('.dummy_window').width() *
...@@ -163,8 +177,7 @@ ...@@ -163,8 +177,7 @@
} }
function convertToRelativePosition(gadget, x, y) { function convertToRelativePosition(gadget, x, y) {
var zoom_level = (gadget.props.preference_container.zoom_level || 1.0) * var zoom_level = gadget.props.zoom_level * 1.1111,
1.1111,
canvas_size_x = $(gadget.props.element).find('#main').width(), canvas_size_x = $(gadget.props.element).find('#main').width(),
canvas_size_y = $(gadget.props.element).find('#main').height(), canvas_size_y = $(gadget.props.element).find('#main').height(),
size_x = $(gadget.props.element).find('.dummy_window').width() * size_x = $(gadget.props.element).find('.dummy_window').width() *
...@@ -179,8 +192,7 @@ ...@@ -179,8 +192,7 @@
} }
function updateElementCoordinate(gadget, node_id, coordinate) { function updateElementCoordinate(gadget, node_id, coordinate) {
var element_id = gadget.props.node_container[node_id].element_id, var element_id = gadget.props.dom_element_id_container[node_id],
coordinates = gadget.props.preference_container.coordinates || {},
element, element,
relative_position; relative_position;
if (coordinate === undefined) { if (coordinate === undefined) {
...@@ -194,8 +206,8 @@ ...@@ -194,8 +206,8 @@
coordinate.top = relative_position[1]; coordinate.top = relative_position[1];
coordinate.left = relative_position[0]; coordinate.left = relative_position[0];
} }
coordinates[node_id] = coordinate; console.log("uec", node_id, gadget.props.node_container);
gadget.props.preference_container.coordinates = coordinates; gadget.props.node_container[node_id].coordinate = coordinate;
gadget.notifyDataChanged(); gadget.notifyDataChanged();
return coordinate; return coordinate;
} }
...@@ -282,8 +294,7 @@ ...@@ -282,8 +294,7 @@
} }
function updateNodeStyle(gadget, element_id) { function updateNodeStyle(gadget, element_id) {
var zoom_level = (gadget.props.preference_container.zoom_level || 1.0) * var zoom_level = gadget.props.zoom_level * 1.1111,
1.1111,
element = $(gadget.props.element).find("#" + element_id), element = $(gadget.props.element).find("#" + element_id),
new_value; new_value;
$.each(gadget.props.style_attr_list, function (i, j) { $.each(gadget.props.style_attr_list, function (i, j) {
...@@ -353,32 +364,6 @@ ...@@ -353,32 +364,6 @@
// ); // );
// } // }
// function setZoom(gadget, zoom_level) {
// $.each(gadget.props.style_attr_list, function (i, j) {
// var new_value = $(gadget.props.element).find('.dummy_window')
// .css(j).replace('px', '') * zoom_level + 'px';
// $(gadget.props.element).find('.window').css(j, new_value);
// });
// }
// function zoom_in(gadget) {
// var zoom_level = (gadget.props.preference_container.zoom_level || 1.0) *
// 1.1111;
// setZoom(gadget, zoom_level);
// gadget.props.preference_container.zoom_level = zoom_level;
// gadget.notifyDataChanged();
// redraw(gadget);
// }
// function zoom_out(gadget) {
// var zoom_level = (gadget.props.preference_container.zoom_level || 1.0) *
// 0.9;
// setZoom(gadget, zoom_level);
// gadget.props.preference_container.zoom_level = zoom_level;
// gadget.notifyDataChanged();
// redraw(gadget);
// }
function removeElement(gadget, node_id) { function removeElement(gadget, node_id) {
var element_id = gadget.props.node_container[node_id].element_id; var element_id = gadget.props.node_container[node_id].element_id;
...@@ -387,7 +372,6 @@ ...@@ -387,7 +372,6 @@
); );
$(gadget.props.element).find("#" + element_id).remove(); $(gadget.props.element).find("#" + element_id).remove();
delete gadget.props.node_container[node_id]; delete gadget.props.node_container[node_id];
delete gadget.props.preference_container.coordinates[node_id];
$.each(gadget.props.edge_container, function (k, v) { $.each(gadget.props.edge_container, function (k, v) {
if (node_id === v[0] || node_id === v[1]) { if (node_id === v[0] || node_id === v[1]) {
delete gadget.props.edge_container[k]; delete gadget.props.edge_container[k];
...@@ -397,7 +381,7 @@ ...@@ -397,7 +381,7 @@
} }
function updateElementData(gadget, node_id, data) { function updateElementData(gadget, node_id, data) {
var element_id = gadget.props.node_container[node_id].element_id, var element_id = gadget.props.dom_element_id_container[node_id];
new_id = data.id; new_id = data.id;
if (data.data.name) { if (data.data.name) {
$(gadget.props.element).find("#" + element_id).text(data.data.name) $(gadget.props.element).find("#" + element_id).text(data.data.name)
...@@ -419,56 +403,31 @@ ...@@ -419,56 +403,31 @@
v[1] = new_id; v[1] = new_id;
} }
}); });
gadget.props.preference_container.coordinates[new_id]
= gadget.props.preference_container.coordinates[node_id];
delete gadget.props.preference_container.coordinates[node_id];
} }
gadget.notifyDataChanged(); gadget.notifyDataChanged();
} }
// function clearAll(gadget) {
// $.each(gadget.props.node_container, function (node_id) {
// removeElement(gadget, node_id);
// });
// // delete anything if still remains
// $(gadget.props.element).find("#main").children().remove();
// gadget.props.node_container = {};
// gadget.props.edge_container = {};
// gadget.props.preference_container = {};
// gadget.props.general_container = {};
// gadget.props.initGeneralProperties();
// gadget.props.prepareDialogForGeneralProperties();
// }
function addEdge(gadget, edge_id, edge_data) { function addEdge(gadget, edge_id, edge_data) {
var source_id = edge_data[0], var overlays = [],
target_id = edge_data[1],
data = edge_data[2],
overlays = [],
connection; connection;
if (data && data.title) {
if (edge_data.name) {
overlays = [["Label", { overlays = [["Label", {
cssClass: "l1 component label", cssClass: "l1 component label",
label: data.title label: edge_data.name
}]]; }]];
} }
connection = gadget.props.jsplumb_instance.connect({ connection = gadget.props.jsplumb_instance.connect({
source: getElementId(gadget.props.node_container, source_id), source: getElementId(gadget, edge_data.source),
target: getElementId(gadget.props.node_container, target_id), target: getElementId(gadget, edge_data.destination),
Connector: [ "Bezier", {curviness: 75} ], Connector: [ "Bezier", {curviness: 75} ],
overlays: overlays overlays: overlays
}); });
// call again updateConnectionData to set the connection data that // jsplumb assigned an id, but we are controlling ids ourselves.
// was not passed to the connection hook connection.id = edge_id;
updateConnectionData(gadget, connection, 0, data);
} }
// function setPreferences(gadget, preferences) {
// gadget.props.preference_container = preferences;
// var zoom_level = gadget.props.preference_container.zoom_level || 1.0;
// setZoom(gadget, zoom_level);
// }
function openNodeDialog(gadget, element, config_dict) { function openNodeDialog(gadget, element, config_dict) {
var node_id = getNodeId(gadget.props.node_container, element.id), var node_id = getNodeId(gadget.props.node_container, element.id),
node_data = gadget.props.node_container[node_id], node_data = gadget.props.node_container[node_id],
...@@ -578,45 +537,48 @@ ...@@ -578,45 +537,48 @@
)); ));
} }
function newElement(gadget, element, configuration) { function addNode(gadget, node_id, node_data) {
var element_type = element._class.replace('.', '-'), var render_element = $(gadget.props.element).find("#main"),
option = configuration[element_type], class_definition = gadget.props.data.class_definition[node_data._class],
render_element = $(gadget.props.element).find("#main"), coordinate = node_data.coordinate,
coordinate = element.coordinate,
box, box,
absolute_position, absolute_position,
domElement; domElement;
// we don't save coordinates as properties of nodes console.log("adding", node_id, gadget.props.dom_element_id_container);
delete element.coordinate; gadget.props.dom_element_id_container[node_id] =
element.element_id = generateElementId(gadget.props.element); generateElementId(gadget.props.element);
/*
if (!element.id) { if (!element.id) {
element.id = generateNodeId(gadget, element_type, option); element.id = generateNodeId(gadget, element);
} }
element.name = element.name || option.name; */
addElementToContainer(gadget.props.node_container, element); // element.name = element.name || element.class_definition.name;
node_data.name = node_data.name || class_definition.name;
addElementToContainer(gadget.props.node_container, node_data);
if (coordinate !== undefined) { if (coordinate !== undefined) {
coordinate = updateElementCoordinate( node_data.coordinate = updateElementCoordinate(
gadget, gadget,
element.id, node_id,
coordinate coordinate
); );
} }
if (element.element_id === undefined) {
element.element_id = generateElementId(gadget.props.element); // XXX stop using handlebars
}
/*jslint nomen: true*/ /*jslint nomen: true*/
domElement = domParser.parseFromString( domElement = domParser.parseFromString(
node_template({ node_template({
"class": element._class.replace('.', '-'), "class": node_data._class.replace('.', '-'),
"element_id": element.element_id, "element_id": node_data.element_id,
"title": element.name || element.id, "title": node_data.name || node_data.id,
"name": element.name || element.id "name": node_data.name || node_data.id
}), }),
"text/html" "text/html"
).querySelector('.window'); ).querySelector('.window');
render_element.append(domElement); render_element.append(domElement);
waitForNodeClick(gadget, domElement, configuration);
box = $(gadget.props.element).find("#" + element.element_id); waitForNodeClick(gadget, domElement, class_definition);
box = $(gadget.props.element).find("#" + node_data.element_id);
absolute_position = convertToAbsolutePosition( absolute_position = convertToAbsolutePosition(
gadget, gadget,
coordinate.left, coordinate.left,
...@@ -624,11 +586,12 @@ ...@@ -624,11 +586,12 @@
); );
box.css("top", absolute_position[1]); box.css("top", absolute_position[1]);
box.css("left", absolute_position[0]); box.css("left", absolute_position[0]);
updateNodeStyle(gadget, element.element_id); updateNodeStyle(gadget, node_data.element_id);
draggable(gadget); draggable(gadget);
gadget.notifyDataChanged(); gadget.notifyDataChanged();
} }
// XXX why is that needed ?
function waitForDragover(gadget) { function waitForDragover(gadget) {
return loopEventListener( return loopEventListener(
gadget.props.main, gadget.props.main,
...@@ -638,7 +601,7 @@ ...@@ -638,7 +601,7 @@
); );
} }
function waitForDrop(gadget, config) { function waitForDrop(gadget) {
var callback; var callback;
function canceller() { function canceller() {
...@@ -649,31 +612,32 @@ ...@@ -649,31 +612,32 @@
/*jslint unparam: true*/ /*jslint unparam: true*/
function itsANonResolvableTrap(resolve, reject) { function itsANonResolvableTrap(resolve, reject) {
// XXX name this function seriously
callback = function (evt) { callback = function (evt) {
try { try {
var element = domParser.parseFromString( var class_name_and_class_definition = JSON.parse(
evt.dataTransfer.getData('text/html'), evt.dataTransfer.getData('application/json')
'text/html' ),
).querySelector(".tool"), class_name = class_name_and_class_definition[0],
class_definition = class_name_and_class_definition[1],
offset = $(gadget.props.main).offset(), offset = $(gadget.props.main).offset(),
box_top = evt.clientY - offset.top + "px", box_top = evt.clientY - offset.top + "px",
box_left = evt.clientX - offset.left + "px", box_left = evt.clientX - offset.left + "px",
element_class = element.id.replace('-', '.'),
relative_position = convertToRelativePosition( relative_position = convertToRelativePosition(
gadget, gadget,
box_left, box_left,
box_top box_top
); );
newElement(gadget, {
coordinate: {
left: relative_position[0],
top: relative_position[1]
},
"_class": element_class
},
config);
addNode(gadget,
generateNodeId(gadget, {_class: class_name}),
{
coordinate: {
left: relative_position[0],
top: relative_position[1]
},
_class: class_name
});
} catch (e) { } catch (e) {
reject(e); reject(e);
} }
...@@ -693,7 +657,8 @@ ...@@ -693,7 +657,8 @@
.ready(function (g) { .ready(function (g) {
g.props.edge_container = {}; g.props.edge_container = {};
g.props.preference_container = {}; g.props.dom_element_id_container = {};
g.props.zoom_level = 1.0;
g.props.style_attr_list = [ g.props.style_attr_list = [
'width', 'width',
'height', 'height',
...@@ -704,62 +669,37 @@ ...@@ -704,62 +669,37 @@
.declareMethod('render', function (data) { .declareMethod('render', function (data) {
this.props.data = JSON.parse(data); this.props.data = JSON.parse(data);
this.props.node_container = this.props.data.nodes; console.log("render", this.props.data);
this.props.node_container = this.props.data.graph.main_graph.node;
this.props.jsplumb_instance = jsPlumb.getInstance(); this.props.jsplumb_instance = jsPlumb.getInstance();
}) })
.declareMethod('getData', function () { .declareMethod('getContent', function () {
return JSON.stringify({ return JSON.stringify(this.props.data)
"nodes": this.props.node_container,
"edges": this.props.edge_container,
"preference": this.props.preference_container
});
}) })
.declareMethod('startService', function () { .declareMethod('startService', function () {
var g = this, var gadget = this;
preference = g.props.data.preference !== undefined ? this.props.main = this.props.element.querySelector('#main');
g.props.data.preference : {}, initJsPlumb(this);
coordinates = preference.coordinates, // XXX what is this ?
config; this.props.nodes_click_monitor = RSVP.Monitor();
g.notifyDataChanged();
return g.getConfigurationDict() $.each(this.props.data.graph.main_graph.node, function (key, value) {
.push(function (config_dict) { addNode(gadget, key, value);
config = config_dict; });
g.props.main = g.props.element.querySelector('#main'); $.each(this.props.data.graph.main_graph.edge, function (key, value) {
initJsPlumb(g); addEdge(gadget, key, value);
g.props.nodes_click_monitor = RSVP.Monitor(); });
$.each(g.props.data.graph.main_graph.node, function (key, value) {
if (coordinates === undefined || coordinates[key] === undefined) { return RSVP.all([
value.coordinate = { waitForDragover(gadget),
'top': 0.0, waitForDrop(gadget),
'left': 0.0 waitForConnection(gadget),
}; waitForConnectionDetached(gadget),
} else { waitForConnectionClick(gadget),
value.coordinate = coordinates[key]; gadget.props.nodes_click_monitor
} ]);
value.id = key;
newElement(g, value, config);
if (value.data) { // backward compatibility
updateElementData(g, key, {
data: value.data
});
}
});
$.each(g.props.data.graph.main_graph.edge, function (key, value) {
addEdge(g, key, value);
});
})
.push(function () {
return RSVP.all([
waitForDragover(g),
waitForDrop(g, config),
waitForConnection(g),
waitForConnectionDetached(g),
waitForConnectionClick(g),
g.props.nodes_click_monitor
]);
});
}); });
}(RSVP, rJS, $, jsPlumb, Handlebars, initGadgetMixin, }(RSVP, rJS, $, jsPlumb, Handlebars, initGadgetMixin,
loopEventListener, promiseEventListener, DOMParser)); loopEventListener, promiseEventListener, DOMParser));
...@@ -42,13 +42,14 @@ ...@@ -42,13 +42,14 @@
tools_container.className = 'tools-container'; tools_container.className = 'tools-container';
Object.keys(data.class_definition).forEach(function (key) { Object.keys(data.class_definition).forEach(function (key) {
var _class = data.class_definition[key], tool; var _class = data.class_definition[key], tool;
// XXX "expand" the json schema "allOF" etc
if (_class._class === 'node') { if (_class._class === 'node') {
tool = document.createElement('div'); tool = document.createElement('div');
// XXX maybe allow to configure the class name ? // XXX maybe allow to configure the class name ?
tool.className = "tool " + key; tool.className = "tool " + key;
tool.textContent = _class.name || key; tool.textContent = _class.name || key;
tool.draggable = true; tool.draggable = true;
tool.dataset.class_definition = JSON.stringify(_class); tool.dataset.class_definition = JSON.stringify([key, _class]);
Object.keys(_class.css || {}).forEach(function (k) { Object.keys(_class.css || {}).forEach(function (k) {
tool.style[k] = _class.css[k]; tool.style[k] = _class.css[k];
}); });
......
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