diff --git a/css/app.css b/css/app.css index d85c50d5f..68dc185e4 100644 --- a/css/app.css +++ b/css/app.css @@ -1043,6 +1043,7 @@ a:hover .icon.out-link { background-position: -500px -14px;} .inspector-hover .toggle-list button::before, .inspector-hover .toggle-list button:not(.active), .inspector-hover .inspector-inner .add-tag, +.inspector-hover .inspector-inner .add-relation, .inspector-hover .toggle-list button.remove .icon { height: 0; width: 0; @@ -1730,6 +1731,23 @@ img.wiki-image { padding-left: 10px; } +.member-row-new .member-entity-input { + border-radius: 4px 4px 0 0; + border: 1px solid #cfcfcf; +} + +.add-relation { + width: 40%; + height: 30px; + background: rgba(0,0,0,.5); + border-radius: 4px; + margin-top: 10px; +} + +.add-relation:hover { + background: rgba(0,0,0,.8); +} + /* Map Controls */ .map-controls { diff --git a/data/core.yaml b/data/core.yaml index c50fd9d9c..bc9b130be 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -68,6 +68,8 @@ en: relation: Deleted a relation. multiple: "Deleted {n} objects." incomplete_relation: This feature can't be deleted because it hasn't been fully downloaded. + add_member: + annotation: Added a member to a relation. delete_member: annotation: Removed a member from a relation. connect: @@ -168,7 +170,6 @@ en: no_documentation_combination: There is no documentation available for this tag combination no_documentation_key: There is no documentation available for this key show_more: Show More - new_tag: New tag view_on_osm: View on openstreetmap.org all_tags: All tags all_members: All members diff --git a/dist/locales/en.json b/dist/locales/en.json index f50831e2e..4ac4f4252 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -90,6 +90,9 @@ }, "incomplete_relation": "This feature can't be deleted because it hasn't been fully downloaded." }, + "add_member": { + "annotation": "Added a member to a relation." + }, "delete_member": { "annotation": "Removed a member from a relation." }, @@ -210,7 +213,6 @@ "no_documentation_combination": "There is no documentation available for this tag combination", "no_documentation_key": "There is no documentation available for this key", "show_more": "Show More", - "new_tag": "New tag", "view_on_osm": "View on openstreetmap.org", "all_tags": "All tags", "all_members": "All members", diff --git a/index.html b/index.html index d83fde6f3..5cdaec831 100644 --- a/index.html +++ b/index.html @@ -121,6 +121,7 @@ + diff --git a/js/id/actions/add_member.js b/js/id/actions/add_member.js new file mode 100644 index 000000000..75961bd80 --- /dev/null +++ b/js/id/actions/add_member.js @@ -0,0 +1,5 @@ +iD.actions.AddMember = function(relationId, member, memberIndex) { + return function(graph) { + return graph.replace(graph.entity(relationId).addMember(member, memberIndex)); + } +}; diff --git a/js/id/ui/raw_membership_editor.js b/js/id/ui/raw_membership_editor.js index a51d922d5..0c9112016 100644 --- a/js/id/ui/raw_membership_editor.js +++ b/js/id/ui/raw_membership_editor.js @@ -1,5 +1,5 @@ iD.ui.RawMembershipEditor = function(context) { - var id; + var id, showBlank; function selectRelation(d) { context.enter(iD.modes.Select(context, [d.relation.id])); @@ -12,12 +12,43 @@ iD.ui.RawMembershipEditor = function(context) { t('operations.change_role.annotation')); } + function addMembership(d, role) { + showBlank = false; + context.perform( + iD.actions.AddMember(d.relation.id, {id: id, type: context.entity(id).type, role: role}), + t('operations.add_member.annotation')) + } + function deleteMembership(d) { context.perform( iD.actions.DeleteMember(d.relation.id, d.index), t('operations.delete_member.annotation')); } + function relations(q) { + var result = [], + graph = context.graph(); + + context.intersects(context.extent()).forEach(function(entity) { + if (entity.type !== 'relation') + return; + + var presetName = context.presets().match(entity, graph).name(), + entityName = iD.util.displayName(entity) || ''; + + if (q && entityName.toLowerCase().indexOf(q) === -1 && + presetName.toLowerCase().indexOf(q) === -1) + return; + + result.push({ + relation: entity, + value: presetName + ' ' + entityName + }); + }); + + return result; + } + function rawMembershipEditor(selection) { var entity = context.entity(id), memberships = []; @@ -49,11 +80,11 @@ iD.ui.RawMembershipEditor = function(context) { $list.enter().append('ul') .attr('class', 'member-list'); - var $items = $list.selectAll('li') + var $items = $list.selectAll('li.member-row-normal') .data(memberships, function(d) { return iD.Entity.key(d.relation) + ',' + d.index; }); var $enter = $items.enter().append('li') - .attr('class', 'member-row form-field'); + .attr('class', 'member-row member-row-normal form-field'); var $label = $enter.append('label') .attr('class', 'form-label') @@ -62,7 +93,7 @@ iD.ui.RawMembershipEditor = function(context) { .on('click', selectRelation); $label.append('span') - .attr('class','member-entity-type') + .attr('class', 'member-entity-type') .text(function(d) { return context.presets().match(d.relation, context.graph()).name(); }); $label.append('span') @@ -86,6 +117,58 @@ iD.ui.RawMembershipEditor = function(context) { $items.exit() .remove(); + + if (showBlank) { + var $new = $list.selectAll('.member-row-new') + .data([0]); + + $enter = $new.enter().append('li') + .attr('class', 'member-row member-row-new form-field'); + + $enter.append('input') + .attr('type', 'text') + .attr('class', 'member-entity-input') + .call(d3.combobox() + .fetcher(function(value, _, callback) { + callback(relations(value)); + }) + .on('accept', function(d) { + addMembership(d, $new.select('.member-role').property('value')); + })); + + $enter.append('input') + .attr('class', 'member-role') + .property('type', 'text') + .attr('maxlength', 255) + .attr('placeholder', t('inspector.role')) + .on('change', changeRole); + + $enter.append('button') + .attr('tabindex', -1) + .attr('class', 'remove button-input-action member-delete minor') + .on('click', deleteMembership) + .append('span') + .attr('class', 'icon delete'); + + } else { + $list.selectAll('.member-row-new') + .remove(); + } + + var $add = $wrap.selectAll('.add-relation') + .data([0]); + + $add.enter().append('button') + .attr('class', 'add-relation') + .append('span') + .attr('class', 'icon plus light'); + + $wrap.selectAll('.add-relation') + .on('click', function() { + showBlank = true; + content($wrap); + $list.selectAll('.member-entity-input').node().focus(); + }); } } diff --git a/js/id/ui/raw_tag_editor.js b/js/id/ui/raw_tag_editor.js index b7dd4a20e..80a0d0051 100644 --- a/js/id/ui/raw_tag_editor.js +++ b/js/id/ui/raw_tag_editor.js @@ -47,10 +47,6 @@ iD.ui.RawTagEditor = function(context) { $enter.append('span') .attr('class', 'icon plus light'); - $enter.append('span') - .attr('class', 'label') - .text(t('inspector.new_tag')); - $newTag.on('click', addTag); var $items = $list.selectAll('li')