From 69d95a6082be23b64fdad29c2c75ffa0b0c35e40 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Tue, 29 Jan 2013 12:05:52 -0500 Subject: [PATCH] Refactor operations They're something distinct from actions. Actions are independent of UI, operations are actions + UI (title, keybinding, modality, etc.) --- Makefile | 2 + index.html | 7 +++ js/id/actions/circular.js | 2 +- js/id/actions/delete_node.js | 8 +--- js/id/actions/delete_way.js | 8 +--- js/id/actions/reverse_way.js | 8 +--- js/id/modes/select.js | 2 +- js/id/operations.js | 1 + js/id/operations/circular.js | 34 ++++++++++++++ js/id/operations/delete.js | 42 +++++++++++++++++ js/id/operations/reverse.js | 21 +++++++++ js/id/operations/split.js | 21 +++++++++ js/id/operations/unjoin.js | 21 +++++++++ js/id/ui/radial_menu.js | 87 ++++-------------------------------- test/index.html | 7 +++ 15 files changed, 169 insertions(+), 102 deletions(-) create mode 100644 js/id/operations.js create mode 100644 js/id/operations/circular.js create mode 100644 js/id/operations/delete.js create mode 100644 js/id/operations/reverse.js create mode 100644 js/id/operations/split.js create mode 100644 js/id/operations/unjoin.js diff --git a/Makefile b/Makefile index c9d13ff60..70ac208d6 100644 --- a/Makefile +++ b/Makefile @@ -38,6 +38,8 @@ all: \ js/id/behavior/*.js \ js/id/modes.js \ js/id/modes/*.js \ + js/id/operations.js \ + js/id/operations/*.js \ js/id/controller/*.js \ js/id/graph/*.js \ js/id/renderer/*.js \ diff --git a/index.html b/index.html index af436a86e..cc45f4a48 100644 --- a/index.html +++ b/index.html @@ -106,6 +106,13 @@ + + + + + + + diff --git a/js/id/actions/circular.js b/js/id/actions/circular.js index d6af08560..da7965c79 100644 --- a/js/id/actions/circular.js +++ b/js/id/actions/circular.js @@ -51,7 +51,7 @@ iD.actions.Circular = function(wayId, map) { }; action.enabled = function(graph) { - return true; + return graph.entity(wayId).isClosed(); }; return action; diff --git a/js/id/actions/delete_node.js b/js/id/actions/delete_node.js index 48e704ac3..a93129ce3 100644 --- a/js/id/actions/delete_node.js +++ b/js/id/actions/delete_node.js @@ -1,6 +1,6 @@ // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteNodeAction.as iD.actions.DeleteNode = function(nodeId) { - var action = function(graph) { + return function(graph) { var node = graph.entity(nodeId); graph.parentWays(node) @@ -20,10 +20,4 @@ iD.actions.DeleteNode = function(nodeId) { return graph.remove(node); }; - - action.enabled = function(graph) { - return true; - }; - - return action; }; diff --git a/js/id/actions/delete_way.js b/js/id/actions/delete_way.js index eb58223cb..211447228 100644 --- a/js/id/actions/delete_way.js +++ b/js/id/actions/delete_way.js @@ -1,6 +1,6 @@ // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteWayAction.as iD.actions.DeleteWay = function(wayId) { - var action = function(graph) { + return function(graph) { var way = graph.entity(wayId); graph.parentRelations(way) @@ -27,10 +27,4 @@ iD.actions.DeleteWay = function(wayId) { return graph.remove(way); }; - - action.enabled = function(graph) { - return true; - }; - - return action; }; diff --git a/js/id/actions/reverse_way.js b/js/id/actions/reverse_way.js index 4a7d392b7..160017637 100644 --- a/js/id/actions/reverse_way.js +++ b/js/id/actions/reverse_way.js @@ -53,7 +53,7 @@ iD.actions.ReverseWay = function(wayId) { } } - var action = function(graph) { + return function(graph) { var way = graph.entity(wayId), nodes = way.nodes.slice().reverse(), tags = {}, key, role; @@ -73,10 +73,4 @@ iD.actions.ReverseWay = function(wayId) { return graph.replace(way.update({nodes: nodes, tags: tags})); }; - - action.enabled = function(graph) { - return true; - }; - - return action; }; diff --git a/js/id/modes/select.js b/js/id/modes/select.js index fb4e5dc06..8871dd2ec 100644 --- a/js/id/modes/select.js +++ b/js/id/modes/select.js @@ -138,7 +138,7 @@ iD.modes.Select = function(entity, initial) { }) .classed('selected', true); - radialMenu = iD.ui.RadialMenu(entity, history, mode.map); + radialMenu = iD.ui.RadialMenu(entity, mode); if (d3.event && !initial) { var loc = map.mouseCoordinates(); diff --git a/js/id/operations.js b/js/id/operations.js new file mode 100644 index 000000000..2786d046f --- /dev/null +++ b/js/id/operations.js @@ -0,0 +1 @@ +iD.operations = {} diff --git a/js/id/operations/circular.js b/js/id/operations/circular.js new file mode 100644 index 000000000..0af64aa20 --- /dev/null +++ b/js/id/operations/circular.js @@ -0,0 +1,34 @@ +iD.operations.Circular = function(entityId, mode) { + var action = iD.actions.Circular(entityId, mode.map); + + var operation = function(history) { + var graph = history.graph(), + entity = graph.entity(entityId), + geometry = entity.geometry(graph); + + if (geometry === 'line') { + history.perform( + action, + 'made a line circular'); + + } else if (geometry === 'area') { + history.perform( + action, + 'made an area circular'); + } + }; + + operation.available = function(graph) { + var entity = graph.entity(entityId); + return entity.geometry(graph) === 'area' || entity.geometry(graph) === 'line'; + }; + + operation.enabled = function(graph) { + return action.enabled(graph); + }; + + operation.id = "circular"; + operation.title = "Circular"; + + return operation; +}; diff --git a/js/id/operations/delete.js b/js/id/operations/delete.js new file mode 100644 index 000000000..53038dbc4 --- /dev/null +++ b/js/id/operations/delete.js @@ -0,0 +1,42 @@ +iD.operations.Delete = function(entityId) { + var operation = function(history) { + var graph = history.graph(), + entity = graph.entity(entityId), + geometry = entity.geometry(graph); + + if (geometry === 'vertex') { + history.perform( + iD.actions.DeleteNode(entityId), + 'deleted a vertex'); + + } else if (geometry === 'point') { + history.perform( + iD.actions.DeleteNode(entityId), + 'deleted a point'); + + } else if (geometry === 'line') { + history.perform( + iD.actions.DeleteWay(entityId), + 'deleted a line'); + + } else if (geometry === 'area') { + history.perform( + iD.actions.DeleteWay(entityId), + 'deleted an area'); + } + }; + + operation.available = function(graph) { + var entity = graph.entity(entityId); + return _.contains(['vertex', 'point', 'line', 'area'], entity.geometry(graph)); + }; + + operation.enabled = function() { + return true; + }; + + operation.id = "delete"; + operation.title = "Delete"; + + return operation; +}; diff --git a/js/id/operations/reverse.js b/js/id/operations/reverse.js new file mode 100644 index 000000000..941d8a4da --- /dev/null +++ b/js/id/operations/reverse.js @@ -0,0 +1,21 @@ +iD.operations.Reverse = function(entityId) { + var operation = function(history) { + history.perform( + iD.actions.ReverseWay(entityId), + 'reversed a line'); + }; + + operation.available = function(graph) { + var entity = graph.entity(entityId); + return entity.geometry(graph) === 'line'; + }; + + operation.enabled = function() { + return true; + }; + + operation.id = "reverse"; + operation.title = "Reverse"; + + return operation; +}; diff --git a/js/id/operations/split.js b/js/id/operations/split.js new file mode 100644 index 000000000..838dac88e --- /dev/null +++ b/js/id/operations/split.js @@ -0,0 +1,21 @@ +iD.operations.Split = function(entityId) { + var action = iD.actions.SplitWay(entityId); + + var operation = function(history) { + history.perform(action, 'split a way'); + }; + + operation.available = function(graph) { + var entity = graph.entity(entityId); + return entity.geometry(graph) === 'vertex'; + }; + + operation.enabled = function(graph) { + return action.enabled(graph); + }; + + operation.id = "split"; + operation.title = "Split"; + + return operation; +}; diff --git a/js/id/operations/unjoin.js b/js/id/operations/unjoin.js new file mode 100644 index 000000000..985a41697 --- /dev/null +++ b/js/id/operations/unjoin.js @@ -0,0 +1,21 @@ +iD.operations.Unjoin = function(entityId) { + var action = iD.actions.UnjoinNode(entityId); + + var operation = function(history) { + history.perform(action, 'unjoined lines'); + }; + + operation.available = function(graph) { + var entity = graph.entity(entityId); + return entity.geometry(graph) === 'vertex'; + }; + + operation.enabled = function(graph) { + return action.enabled(graph); + }; + + operation.id = "unjoin"; + operation.title = "Unjoin"; + + return operation; +}; diff --git a/js/id/ui/radial_menu.js b/js/id/ui/radial_menu.js index ff895ea81..a891b7d8e 100644 --- a/js/id/ui/radial_menu.js +++ b/js/id/ui/radial_menu.js @@ -1,83 +1,12 @@ -iD.ui.RadialMenu = function(entity, history, map) { +iD.ui.RadialMenu = function(entity, mode) { var arcs; var radialMenu = function(selection, center) { - var operations, + var history = mode.map.history(), graph = history.graph(), - geometry = entity.geometry(graph); - - if (geometry === 'vertex') { - operations = [ - { - id: 'delete', - text: 'Delete', - description: 'deleted a node', - action: iD.actions.DeleteNode(entity.id) - }, - { - id: 'split', - text: 'Split Way', - description: 'split a way', - action: iD.actions.SplitWay(entity.id) - }, - { - id: 'unjoin', - text: 'Unjoin', - description: 'unjoined lines', - action: iD.actions.UnjoinNode(entity.id) - } - ]; - } else if (geometry === 'point') { - operations = [ - { - id: 'delete', - text: 'Delete', - description: 'deleted a point', - action: iD.actions.DeleteNode(entity.id) - } - ]; - } else if (geometry === 'line') { - operations = [ - { - id: 'delete', - text: 'Delete', - description: 'deleted a line', - action: iD.actions.DeleteWay(entity.id) - }, - { - id: 'reverse', - text: 'Reverse', - description: 'reversed a way', - action: iD.actions.ReverseWay(entity.id) - } - ]; - if (entity.isClosed()) { - operations.push({ - id: 'circlar', - text: 'Circular', - description: 'made way circular', - action: iD.actions.Circular(entity.id, map) - }); - } - } else if (geometry === 'area') { - operations = [ - { - id: 'delete', - text: 'Delete', - description: 'deleted an area', - action: iD.actions.DeleteWay(entity.id) - }, - { - id: 'circlar', - text: 'Circular', - description: 'made area circular', - action: iD.actions.Circular(entity.id, map) - } - ]; - } else { - // Relation, not implemented yet. - return; - } + operations = d3.values(iD.operations) + .map(function (o) { return o(entity.id, mode); }) + .filter(function (o) { return o.available(graph); }); var arc = d3.svg.arc() .outerRadius(70) @@ -98,14 +27,14 @@ iD.ui.RadialMenu = function(entity, history, map) { arcs.append('path') .attr('class', function (d) { return 'radial-menu-item radial-menu-item-' + d.id; }) .attr('d', arc) - .classed('disabled', function (d) { return !d.action.enabled(history.graph()); }) - .on('click', function (d) { history.perform(d.action, d.description); }); + .classed('disabled', function (d) { return !d.enabled(graph); }) + .on('click', function (d) { d(history); }); arcs.append('text') .attr("transform", function(d, i) { return "translate(" + arc.centroid(d, i) + ")"; }) .attr("dy", ".35em") .style("text-anchor", "middle") - .text(function(d) { return d.text; }); + .text(function(d) { return d.title; }); }; radialMenu.close = function(selection) { diff --git a/test/index.html b/test/index.html index 859d5b95d..de83d89e0 100644 --- a/test/index.html +++ b/test/index.html @@ -100,6 +100,13 @@ + + + + + + +