diff --git a/js/id/behavior/select.js b/js/id/behavior/select.js index e078fdbf1..b5276a4d0 100644 --- a/js/id/behavior/select.js +++ b/js/id/behavior/select.js @@ -2,8 +2,12 @@ iD.behavior.Select = function(context) { function click() { var datum = d3.select(d3.event.target).datum(); if (datum instanceof iD.Entity) { - context.enter(iD.modes.Select(context, [datum.id])); - } else { + if (d3.event.shiftKey) { + context.enter(iD.modes.Select(context, context.selection().concat([datum.id]))); + } else { + context.enter(iD.modes.Select(context, [datum.id])); + } + } else if (!d3.event.shiftKey) { context.enter(iD.modes.Browse(context)); } } diff --git a/js/id/id.js b/js/id/id.js index 0b2bbd617..358610525 100644 --- a/js/id/id.js +++ b/js/id/id.js @@ -56,6 +56,14 @@ window.iD = function () { return mode; }; + context.selection = function() { + if (mode.id === 'select') { + return mode.selection(); + } else { + return []; + } + }; + /* Behaviors */ context.install = function(behavior) { context.surface().call(behavior); diff --git a/test/index.html b/test/index.html index d32331ba9..16f86b781 100644 --- a/test/index.html +++ b/test/index.html @@ -185,6 +185,7 @@ + diff --git a/test/index_packaged.html b/test/index_packaged.html index 11f8368f4..588c8e0a3 100644 --- a/test/index_packaged.html +++ b/test/index_packaged.html @@ -80,6 +80,7 @@ + diff --git a/test/spec/behavior/select.js b/test/spec/behavior/select.js new file mode 100644 index 000000000..42c568cca --- /dev/null +++ b/test/spec/behavior/select.js @@ -0,0 +1,54 @@ +describe("iD.behavior.Select", function() { + var a, b, context, behavior, container; + + beforeEach(function() { + container = d3.select('body').append('div'); + + context = iD().container(container); + + a = iD.Node({loc: [0, 0]}); + b = iD.Node({loc: [0, 0]}); + + context.perform(iD.actions.AddEntity(a), iD.actions.AddEntity(b)); + + container.call(context.map()) + .append('div') + .attr('class', 'inspector-wrap'); + + context.surface().selectAll('circle') + .data([a, b]) + .enter().append('circle') + .attr('class', function(d) { return d.id; }); + + behavior = iD.behavior.Select(context); + context.install(behavior); + }); + + afterEach(function() { + context.uninstall(behavior); + container.remove(); + }); + + specify("click on entity selects the entity", function() { + happen.click(context.surface().select('.' + a.id).node()); + expect(context.selection()).to.eql([a.id]); + }); + + specify("click on empty space clears the selection", function() { + context.enter(iD.modes.Select(context, [a.id])); + happen.click(context.surface().node()); + expect(context.selection()).to.eql([]); + }); + + specify("shift-click on entity adds the entity to the selection", function() { + context.enter(iD.modes.Select(context, [a.id])); + happen.click(context.surface().select('.' + b.id).node(), {shiftKey: true}); + expect(context.selection()).to.eql([a.id, b.id]); + }); + + specify("shift-click on empty space leaves the selection unchanged", function() { + context.enter(iD.modes.Select(context, [a.id])); + happen.click(context.surface().node(), {shiftKey: true}); + expect(context.selection()).to.eql([a.id]); + }); +});