summaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
Diffstat (limited to 'src/client')
-rw-r--r--src/client/rz_core.js168
-rw-r--r--src/client/view/svg_input.js185
2 files changed, 192 insertions, 161 deletions
diff --git a/src/client/rz_core.js b/src/client/rz_core.js
index e048ca43..7528d5d3 100644
--- a/src/client/rz_core.js
+++ b/src/client/rz_core.js
@@ -1,7 +1,7 @@
"use strict"
-define(['jquery', 'd3', 'consts', 'rz_bus', 'util', 'model/graph', 'model/core', 'view/helpers', 'view/view', 'rz_observer', 'view/selection', 'rz_config', 'rz_mesh', 'model/diff', "view/graph_view"],
-function($, d3, consts, rz_bus, util, model_graph, model_core, view_helpers, view, rz_observer, selection, rz_config, rz_mesh, model_diff, graph_view) {
+define(['jquery', 'd3', 'consts', 'rz_bus', 'util', 'model/graph', 'model/core', 'view/helpers', 'view/view', 'rz_observer', 'view/selection', 'rz_config', 'rz_mesh', 'model/diff', "view/graph_view", 'view/svg_input'],
+function($, d3, consts, rz_bus, util, model_graph, model_core, view_helpers, view, rz_observer, selection, rz_config, rz_mesh, model_diff, graph_view, svg_input) {
var addednodes = [],
vis,
@@ -17,168 +17,12 @@ var addednodes = [],
// "CSS" for SVG elements. Reused for editing elements.
var node_text_dx = 15,
- node_text_dy = '.30em',
- svg_input_fo_node_y = '-.70em',
- svg_input_fo_height = '30px';
-
-/**
- * svgInput - creates an embedded input element under a given
- *
- * edit_node(@sibling, @node)
- * edit_link(@sibling, @link)
- */
-var svgInput = (function() {
- var measure_node = $('#measure-node')[0],
- measure_link = $('#measure-link')[0],
- original_element,
- is_link;
-
- function appendForeignElementInputWithID(base, elemid, width, height)
- {
- var input = document.createElement('input'),
- body = document.createElement('body'),
- fo = document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject');
-
- body.appendChild(input);
-
- fo.setAttribute('height', height || svg_input_fo_height);
- fo.style.pointerEvents = 'none';
- input.style.pointerEvents = 'all';
- fo.appendChild(body);
- base.appendChild(fo);
- input.setAttribute('id', elemid);
- return input;
- }
-
- function measure(text)
- {
- var span;
-
- span = is_link ? measure_link : measure_node;
- span.innerHTML = text;
- return span.getBoundingClientRect().width; // $().width() works too
- }
-
- function onkeydown(e) {
- var ret = undefined,
- jelement = createOrGetSvgInput(),
- element = jelement[0],
- newname = jelement.val(),
- fo = createOrGetSvgInputFO(),
- d;
-
- if (element != this) {
- console.log('unexpected editname_on_keypress this should be the svg-input element');
- }
-
- if (e.which == 13 || e.which == 27) {
- ret = false;
- d = jelement.data().d;
- if (e.which == 13 && newname != d.name) {
- if (d.hasOwnProperty('__src')) {
- main_graph.update_link(d, {name: newname});
- } else {
- // TODO - display hourglass
- // TODO - use promises to make A follows B readable.
- main_graph.update_node(d, {name: newname});
- }
- }
- hide();
- }
- rz_bus.ui_key.push({where: consts.KEYSTROKE_WHERE_EDIT_NODE, keys: [e.which]});
- return ret;
- };
-
- function resize_measure(e) {
- resize(measure($(e.target).val()) + 30);
- }
-
- function resize(new_width) {
- var svg_input = createOrGetSvgInput(),
- fo = createOrGetSvgInputFO();
-
- svg_input.css('width', new_width);
- fo.attr('width', new_width);
- }
-
- // FIXME: element being deleted. Some delete is legit - removal of related element. Some isn't (a click).
- // Instead of investigating (time constraint) reparenting as sibling, and introducing
- // this function. Cost of creation of element is negligble, it's just ugly..
- function createOrGetSvgInput()
- {
- var svg_input_name = 'svg-input',
- svg_input_selector = '#' + svg_input_name,
- svg_input = $(svg_input_selector);
-
- if (svg_input.length == 0) {
- console.log('creating new svg-input');
- svg_input = $(appendForeignElementInputWithID(vis[0][0], svg_input_name));
- svg_input.on('keydown', onkeydown);
- svg_input.bind('change keypress', resize_measure);
- }
- return svg_input;
- }
-
- function createOrGetSvgInputFO()
- {
- return createOrGetSvgInput().parent().parent();
- }
-
- /*
- * @param e visual node element
- * @param n node model object
- */
- function enable(e, n, x) {
- var oldname = n.name,
- svg_input = createOrGetSvgInput(),
- fo = createOrGetSvgInputFO();
-
- is_link = n.hasOwnProperty('__src');
-
- e.parentNode.appendChild(fo[0]); // This will unparent from the old parent
- if (is_link) {
- fo.attr('transform', e.getAttribute('transform'));
- // XXX links set the text-anchor middle attribute. no idea how to do that
- fo.attr('x', -$(e).width() / 2);
- fo.attr('y', -$(e).height() / 2 - 3); // XXX This minus 3 is only kinda ok.
- fo.attr('class', 'svg-input-fo-link');
- } else {
- fo.attr('x', x);
- fo.attr('y', svg_input_fo_node_y);
- fo.attr('transform', null);
- fo.attr('class', 'svg-input-fo-node');
- }
- // Set width correctly
- resize(measure(oldname) + 30);
- fo.show();
- svg_input.val(oldname);
- svg_input.data().d = n;
- svg_input.focus();
- if (original_element) {
- original_element.show();
- }
- original_element = $(e);
- original_element.hide();
- // TODO: set cursor to correct location in text
- }
-
- function hide() {
- createOrGetSvgInputFO().hide();
- if (original_element && original_element.show) {
- original_element.show();
- }
- }
-
- return {
- enable: enable,
- hide: hide,
- };
-}());
+ node_text_dy = '.30em';
var zoomProgress = false;
var zoomBus = new Bacon.Bus();
-var zoom_property = zoomBus.toProperty();
-zoomBus.push(zoomProgress); // set initial value
+var zoom_property = zoomBus.toProperty(zoomProgress);
+var svgInput;
function svg_click_handler(e) {
if (zoomProgress) {
@@ -242,6 +86,8 @@ var initDrawingArea = function () {
.append("g")
.attr("class", "zoom");
+ svgInput = svg_input(vis, main_graph);
+
d3.select(el).select("svg").append("svg:defs")
.data(["end"]) // Different link/path types can be defined here
.append("svg:marker") // This section adds in the arrows
diff --git a/src/client/view/svg_input.js b/src/client/view/svg_input.js
new file mode 100644
index 00000000..6318dca7
--- /dev/null
+++ b/src/client/view/svg_input.js
@@ -0,0 +1,185 @@
+define(['jquery', 'Bacon', 'model/diff', 'rz_bus', 'consts'],
+function($, Bacon, model_diff, rz_bus, consts)
+{
+var svg_input_fo_node_y = '-.70em',
+ svg_input_fo_height = '30px';
+
+/**
+ * svgInput - creates an embedded input element in an svg node.
+ *
+ * edit_node(@sibling, @node)
+ * edit_link(@sibling, @link)
+ */
+var svgInput = function(vis, graph) {
+ var measure_node = $('#measure-node')[0],
+ measure_link = $('#measure-link')[0],
+ original_element,
+ is_link,
+ graphEditBus = new Bacon.Bus(),
+ currentIdBus = new Bacon.Bus(),
+ current_id = currentIdBus.toProperty(null);
+
+ graph.diffBus
+ .filter(model_diff.is_attr_diff)
+ .combine(current_id, function(diff, id) { return [diff, id]; })
+ .filter(function (val) {
+ var diff = val[0],
+ id = val[1];
+ return (is_link && diff.has_link_id_attr_write(id, 'name')) ||
+ (!is_link && diff.has_node_id_attr_write(id, 'name'));
+ })
+ .map(function (val) { return graph.find_node__by_id(val[1]).name; })
+ .onValue(function (name) {
+ var svg_input = createOrGetSvgInput();
+ svg_input.val(name);
+ });
+
+ function appendForeignElementInputWithID(base, elemid, width, height)
+ {
+ var input = document.createElement('input'),
+ body = document.createElement('body'),
+ fo = document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject');
+
+ body.appendChild(input);
+
+ fo.setAttribute('height', height || svg_input_fo_height);
+ fo.style.pointerEvents = 'none';
+ input.style.pointerEvents = 'all';
+ fo.appendChild(body);
+ base.appendChild(fo);
+ input.setAttribute('id', elemid);
+ return input;
+ }
+
+ function measure(text)
+ {
+ var span;
+
+ span = is_link ? measure_link : measure_node;
+ span.innerHTML = text;
+ return span.getBoundingClientRect().width; // $().width() works too
+ }
+
+ function onkeydown(e) {
+ var ret = undefined,
+ jelement = createOrGetSvgInput(),
+ element = jelement[0],
+ newname = jelement.val(),
+ fo = createOrGetSvgInputFO(),
+ d;
+
+ if (element != this) {
+ console.log('unexpected editname_on_keypress this should be the svg-input element');
+ }
+
+ if (e.which == 13 || e.which == 27) {
+ ret = false;
+ d = jelement.data().d;
+ if (e.which == 13 && newname != d.name) {
+ if (d.hasOwnProperty('__src')) {
+ graph.update_link(d, {name: newname});
+ } else {
+ // TODO - display hourglass
+ // TODO - use promises to make A follows B readable.
+ graph.update_node(d, {name: newname});
+ }
+ }
+ hide();
+ }
+ rz_bus.ui_key.push({where: consts.KEYSTROKE_WHERE_EDIT_NODE, keys: [e.which]});
+ return ret;
+ };
+
+ function resize_measure(e) {
+ resize(measure($(e.target).val()) + 30);
+ }
+
+ function resize(new_width) {
+ var svg_input = createOrGetSvgInput(),
+ fo = createOrGetSvgInputFO();
+
+ svg_input.css('width', new_width);
+ fo.attr('width', new_width);
+ }
+
+ // FIXME: element being deleted. Some delete is legit - removal of related element. Some isn't (a click).
+ // Instead of investigating (time constraint) reparenting as sibling, and introducing
+ // this function. Cost of creation of element is negligble, it's just ugly..
+ function createOrGetSvgInput()
+ {
+ var svg_input_name = 'svg-input',
+ svg_input_selector = '#' + svg_input_name,
+ svg_input = $(svg_input_selector);
+
+ if (svg_input.length == 0) {
+ console.log('creating new svg-input');
+ svg_input = $(appendForeignElementInputWithID(vis[0][0], svg_input_name));
+ svg_input.on('keydown', onkeydown);
+ svg_input.bind('change keypress', resize_measure);
+ }
+ return svg_input;
+ }
+
+ function createOrGetSvgInputFO()
+ {
+ return createOrGetSvgInput().parent().parent();
+ }
+
+ /*
+ * @param e visual node element
+ * @param n node model object
+ */
+ function enable(e, n, x) {
+ var oldname = n.name,
+ svg_input = createOrGetSvgInput(),
+ fo = createOrGetSvgInputFO();
+
+ is_link = n.hasOwnProperty('__src');
+ currentIdBus.push(n.id);
+
+ e.parentNode.appendChild(fo[0]); // This will unparent from the old parent
+ if (is_link) {
+ fo.attr('transform', e.getAttribute('transform'));
+ // XXX links set the text-anchor middle attribute. no idea how to do that
+ fo.attr('x', -$(e).width() / 2);
+ fo.attr('y', -$(e).height() / 2 - 3); // XXX This minus 3 is only kinda ok.
+ fo.attr('class', 'svg-input-fo-link');
+ } else {
+ fo.attr('x', x);
+ fo.attr('y', svg_input_fo_node_y);
+ fo.attr('transform', null);
+ fo.attr('class', 'svg-input-fo-node');
+ }
+ // Set width correctly
+ resize(measure(oldname) + 30);
+ fo.show();
+ svg_input.val(oldname);
+ svg_input.data().d = n;
+ svg_input.focus();
+ if (original_element) {
+ original_element.show();
+ }
+ original_element = $(e);
+ original_element.hide();
+ // TODO: set cursor to correct location in text
+ }
+
+ function hide() {
+ createOrGetSvgInputFO().hide();
+ if (original_element && original_element.show) {
+ original_element.show();
+ }
+ }
+
+ // on change to graph.node[id] update val
+ // on change to graph.link[id] update val
+ // on delete of id hide
+
+ return {
+ enable: enable,
+ hide: hide,
+ };
+};
+
+return svgInput;
+});