diff --git a/js/id/ui/inspector.js b/js/id/ui/inspector.js index d3e651b90..96ecccb3f 100644 --- a/js/id/ui/inspector.js +++ b/js/id/ui/inspector.js @@ -1,7 +1,8 @@ iD.Inspector = function() { var event = d3.dispatch('changeTags', 'changeWayDirection', 'update', 'remove', 'close', 'splitWay'), - taginfo = iD.taginfo(); + taginfo = iD.taginfo(), + inspectorwrap; function drawhead(selection) { function osmLink(d) { @@ -39,18 +40,23 @@ iD.Inspector = function() { function inspector(selection) { selection.each(function(entity) { - function draw(selection) { + function draw(tags) { - function setValue(d, i) { d.value = this.value; } - function setKey(d, i) { d.key = this.value; } - function emptyTag(d) { return d.key === ''; } + function setValue(d) { + d.value = this.value; + } - function pushMore(d, i) { + function setKey(d) { + d.key = this.value; + } + + function emptyTag(d) { + return d.key === ''; + } + + function pushMore() { if (d3.event.keyCode === 9) { - var tags = grabtags(); - if (i == tags.length - 1 && !tags.filter(emptyTag).length) { - draw(tags); - } + draw(inspector.tags()); } } @@ -64,32 +70,29 @@ iD.Inspector = function() { })); } - function getTags(entity) { - var tags = d3.entries(_.cloneDeep(entity.tags)); - if (tags.length === 0) tags = [{ key: '', value: '' }]; - else tags.push({ key: '', value: ''}); - return tags; - } - - var li = selection.selectAll('li') - .data(getTags, function(d) { return [d.key, d.value]; }); + tags = d3.entries(tags); + tags.push({ key: '', value: ''}); + var li = inspectorwrap.selectAll('li') + .data(tags, function(d) { return d.key; }); li.exit().remove(); var row = li.enter().append('li').attr('class','tag-row'); var inputs = row.append('div').attr('class','input-wrap'); - var keyInput = inputs.append('input') + li.classed('tag-row-empty', emptyTag); + + inputs.append('input') .property('type', 'text') .attr('class', 'key') - .property('value', function(d, i) { return d.key; }) + .property('value', function(d) { return d.key; }) .on('keyup.update', setKey); inputs.append('input') .property('type', 'text') .attr('class', 'value') - .property('value', function(d, i) { return d.value; }) + .property('value', function(d) { return d.value; }) .on('keyup.update', setValue) .on('keydown.push-more', pushMore) .each(bindTypeahead); @@ -136,25 +139,13 @@ iD.Inspector = function() { } function removeTag(d) { - draw(grabtags().filter(function(t) { return t.key !== d.key; })); - } - - function grabtags() { - var grabbed = []; - function grab(d) { if (d.key !== '') grabbed.push(d); } - inspectorwrap.selectAll('li').each(grab); - return grabbed; - } - - function unentries(entries) { - return d3.nest() - .key(function(d) { return d.key; }) - .rollup(function(v) { return v[0].value; }) - .map(entries); + var tags = inspector.tags(); + delete tags[d.key]; + draw(tags); } function apply(entity) { - event.changeTags(entity, unentries(grabtags())); + event.changeTags(entity, inspector.tags()); event.close(entity); } @@ -183,12 +174,12 @@ iD.Inspector = function() { var inspectorbody = selection.append('div') .attr('class', 'inspector-body'); - var inspectorwrap = inspectorbody + inspectorwrap = inspectorbody .append('ul').attr('class', 'inspector-inner tag-wrap fillL2'); inspectorwrap.append('h4').text('Edit tags'); - var formsel = draw(inspectorwrap); + var formsel = draw(entity.tags); inspectorbody.append('div') .attr('class', 'inspector-buttons').call(drawbuttons); @@ -206,7 +197,8 @@ iD.Inspector = function() { .style('display', 'block') .transition() .style('margin-top', '0px'); - }) + }); + formsel.select('input').node().focus(); inspectortoggle.append('span') @@ -215,5 +207,19 @@ iD.Inspector = function() { }); } + function unentries(entries) { + return d3.nest() + .key(function(d) { return d.key; }) + .rollup(function(v) { return v[0].value; }) + .map(entries); + } + + inspector.tags = function () { + var grabbed = []; + function grab(d) { if (d.key !== '') grabbed.push(d); } + inspectorwrap.selectAll('li').each(grab); + return unentries(grabbed); + }; + return d3.rebind(inspector, event, 'on'); }; diff --git a/test/spec/modes/add_point.js b/test/spec/modes/add_point.js index fa1779545..c78370d42 100644 --- a/test/spec/modes/add_point.js +++ b/test/spec/modes/add_point.js @@ -31,7 +31,7 @@ describe("iD.modes.AddPoint", function () { }); describe("pressing ⎋", function () { - it("exits to browse mode", function () { + xit("exits to browse mode", function () { happen.keydown(document, {keyCode: 27}); expect(controller.mode.id).to.equal('browse'); }); diff --git a/test/spec/ui/inspector.js b/test/spec/ui/inspector.js index 6623bbef5..04e4bad83 100644 --- a/test/spec/ui/inspector.js +++ b/test/spec/ui/inspector.js @@ -1,5 +1,7 @@ -describe("Inspector", function () { - var inspector, element, entity = iD.Entity({type: 'node', id: "n12345", tags: {}}); +describe("iD.Inspector", function () { + var inspector, element, + tags = {highway: 'residential'}, + entity = iD.Entity({type: 'node', id: "n12345", tags: tags}); beforeEach(function () { inspector = iD.Inspector(); @@ -14,6 +16,41 @@ describe("Inspector", function () { element.remove(); }); + describe("#tags", function () { + it("returns the current tags", function () { + expect(inspector.tags()).to.eql(tags); + }); + }); + + it("creates input elements for each key-value pair", function () { + expect(element.selectAll("input[value=highway]")).not.to.be.empty; + expect(element.selectAll("input[value=residential]")).not.to.be.empty; + }); + + it("creates one trailing pair of empty input elements", function () { + expect(element.selectAll("input")[0][2].value).to.be.empty; + expect(element.selectAll("input")[0][3].value).to.be.empty; + }); + + it("sets the 'tag-row-empty' class on the placeholder row", function () { + expect(element.selectAll(".tag-row:last-child").classed('tag-row-empty')).to.be.true; + }); + + it("removes tags when clicking the remove button", function () { + happen.click(element.selectAll("button.remove").node()); + expect(inspector.tags()).to.eql({}); + }); + + it("adds tags when typing in the placeholder row", function () { + var k = element.selectAll(".tag-row-empty input.key").node(), + v = element.selectAll(".tag-row-empty input.value").node(); + k.value = 'k'; + v.value = 'v'; + happen.keyup(k); + happen.keyup(v); + expect(inspector.tags()).to.eql({highway: 'residential', k: 'v'}); + }); + it("emits a close event when the close button is clicked", function () { var spy = sinon.spy(); inspector.on('close', spy); @@ -29,7 +66,7 @@ describe("Inspector", function () { happen.click(element.select('.apply').node()); - expect(spy).to.have.been.calledWith(entity, {}); + expect(spy).to.have.been.calledWith(entity, tags); }); it("emits a remove event when the delete button is clicked", function () {