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')