diff --git a/css/80_app.css b/css/80_app.css
index 6a47129e9..5a4d52be1 100644
--- a/css/80_app.css
+++ b/css/80_app.css
@@ -3009,50 +3009,60 @@ div.full-screen > button:hover {
width: 100%;
font-weight: inherit;
border-radius: 0;
+ text-align: inherit;
+ display: flex;
+ color: inherit;
}
[dir='rtl'] .issue button {
padding: 5px 5px 5px 10px;
}
-
-.issue button.label {
- text-align: inherit;
- display: flex;
-}
.warnings-list,
.issue.severity-warning,
-.issue.severity-warning li,
li.issue.severity-warning {
border-color: #FFDF5C;
}
.errors-list,
.issue.severity-error,
-.issue.severity-error li,
li.issue.severity-error {
border-color: #f5b0ab;
}
+.issue.severity-warning,
.issue.severity-warning button,
.mode-save .warning-section {
background: #ffb;
}
-.issue.severity-warning button:hover,
-.issue.severity-warning button:focus {
+.issue.severity-warning:not(.expanded) button:hover,
+.issue.severity-warning:not(.expanded) button:focus {
background: #FFFF99;
}
-.issue.severity-warning .icon {
- color: #FFB300
+.issue.severity-warning .issue-icon,
+.issue.severity-warning .issue-fix-item.actionable {
+ color: #ff9205;
+ fill: #ff9205;
+}
+.issue.severity-warning .issue-fix-item.actionable:hover {
+ color: #f07504;
+ fill: #f07504;
}
+.issue.severity-error,
.issue.severity-error button,
.mode-save .error-section {
background: #FFD5D4;
}
-.issue.severity-error button:hover,
-.issue.severity-error button:focus {
+.issue.severity-error:not(.expanded) button:hover,
+.issue.severity-error:not(.expanded) button:focus {
background: #ffc9c7;
}
-.issue.severity-error .icon {
- color: #DD1400
+.issue.severity-error .issue-icon,
+.issue.severity-error .issue-fix-item.actionable {
+ color: #DD1400;
+ fill: #DD1400;
+}
+.issue.severity-error .issue-fix-item.actionable:hover {
+ color: #ab0f00;
+ fill: #ab0f00;
}
/* Issues Pane */
@@ -3091,13 +3101,27 @@ div.full-screen > button:hover {
.entity-issues .issue:not(:last-of-type) {
margin-bottom: 10px;
}
-ul.issue-fix-list li:first-child {
- border-top-style: solid;
- border-top-width: 2px;
+.issue.expanded button.label {
+ cursor: pointer;
+ pointer-events: none;
+ padding-bottom: 0px;
}
-ul.issue-fix-list li:not(:last-of-type) {
- border-bottom-style: solid;
- border-bottom-width: 1px;
+ul.issue-fix-list button {
+ padding: 2px 10px 2px 26px;
+}
+.issue-fix-item:first-of-type button {
+ padding-top:4px;
+}
+.issue-fix-item:last-of-type button {
+ padding-bottom:7px;
+}
+.issue-fix-item:not(.actionable) button {
+ cursor: pointer;
+ pointer-events: none;
+}
+.issue-fix-item:not(.actionable) .fix-icon {
+ color: #555;
+ fill: #555;
}
.issue:not(.expanded) ul.issue-fix-list {
height: 0px;
diff --git a/data/core.yaml b/data/core.yaml
index be513a2ed..7d8314cb1 100644
--- a/data/core.yaml
+++ b/data/core.yaml
@@ -1266,6 +1266,8 @@ en:
remove_tag:
title: Remove the tag
annotation: Removed tag.
+ reposition_features:
+ title: Reposition the features
select_preset:
title: Select a feature type
tag_as_disconnected:
diff --git a/dist/locales/en.json b/dist/locales/en.json
index 6ec4c597c..8400cde39 100644
--- a/dist/locales/en.json
+++ b/dist/locales/en.json
@@ -1556,6 +1556,9 @@
"title": "Remove the tag",
"annotation": "Removed tag."
},
+ "reposition_features": {
+ "title": "Reposition the features"
+ },
"select_preset": {
"title": "Select a feature type"
},
diff --git a/modules/core/validator.js b/modules/core/validator.js
index cf917f3bb..09726117d 100644
--- a/modules/core/validator.js
+++ b/modules/core/validator.js
@@ -222,6 +222,7 @@ export function validationIssue(attrs) {
export function validationIssueFix(attrs) {
+ this.icon = attrs.icon;
this.title = attrs.title;
this.onClick = attrs.onClick;
this.entityIds = attrs.entityIds || []; // Used for hover-higlighting.
diff --git a/modules/ui/entity_issues.js b/modules/ui/entity_issues.js
index ee962faf0..86b044299 100644
--- a/modules/ui/entity_issues.js
+++ b/modules/ui/entity_issues.js
@@ -14,11 +14,13 @@ export function uiEntityIssues(context) {
var _entityID;
- // context.validator().on('reload.entity_issues', function() {
- // _selection.selectAll('.entity-issues')
- // .call(render);
- // update();
- // });
+ context.validator().on('reload.entity_issues', function() {
+
+ update();
+
+ _selection.selectAll('.entity-issues')
+ .call(render);
+ });
function clamp(num, min, max) {
@@ -64,6 +66,11 @@ export function uiEntityIssues(context) {
var itemsEnter = items.enter()
.append('div')
.attr('class', function(d) { return 'issue severity-' + d.severity; })
+ .call(tooltip()
+ .html(true)
+ .title(function(d) { return uiTooltipHtml(d.tooltip); })
+ .placement('top')
+ )
.on('mouseover.highlight', function(d) {
var ids = d.entities.map(function(e) { return e.id; });
utilHighlightEntities(ids, true, context);
@@ -91,13 +98,6 @@ export function uiEntityIssues(context) {
.append('button')
.attr('class', 'label');
- labelsEnter
- .call(tooltip()
- .html(true)
- .title(function(d) { return uiTooltipHtml(d.tooltip); })
- .placement('top')
- );
-
labelsEnter
.append('span')
.attr('class', 'issue-icon')
@@ -129,14 +129,39 @@ export function uiEntityIssues(context) {
// fixes
var fixLists = items.selectAll('.issue-fix-list');
- fixLists.selectAll('.issue-fix-item')
+ var fixes = fixLists.selectAll('.issue-fix-item')
.data(function(d) { return d.fixes; })
.enter()
.append('li')
- .attr('class', 'issue-fix-item')
+ .attr('class', function(d) {
+ return 'issue-fix-item ' + (!!d.onClick ? 'actionable' : '');
+ })
.append('button')
- .text(function(d) { return d.title; })
- .on('click', function(d) { d.onClick(); });
+ .on('click', function(d) {
+ if (d.onClick) {
+ utilHighlightEntities(d.entityIds, false, context);
+ d.onClick();
+ }
+ })
+ .on('mouseover.highlight', function(d) {
+ utilHighlightEntities(d.entityIds, true, context);
+ })
+ .on('mouseout.highlight', function(d) {
+ utilHighlightEntities(d.entityIds, false, context);
+ });
+
+ fixes.append('span')
+ .attr('class', 'fix-icon')
+ .each(function(d) {
+ var iconName = d.icon || 'iD-icon-wrench';
+ if (iconName.startsWith('maki')) {
+ iconName += '-15';
+ }
+ d3_select(this).call(svgIcon('#' + iconName, 'pre-text'));
+ });
+
+ fixes.append('span')
+ .text(function(d) { return d.title; });
}
diff --git a/modules/validations/almost_junction.js b/modules/validations/almost_junction.js
index 31aeb9e88..00cc79b06 100644
--- a/modules/validations/almost_junction.js
+++ b/modules/validations/almost_junction.js
@@ -162,6 +162,7 @@ export function validationAlmostJunction() {
if (Object.keys(node.tags).length === 0) {
// node has no tags, suggest noexit fix
fixes.push(new validationIssueFix({
+ icon: 'maki-barrier',
title: t('issues.fix.tag_as_disconnected.title'),
onClick: function() {
var nodeID = this.issue.entities[1].id;
diff --git a/modules/validations/crossing_ways.js b/modules/validations/crossing_ways.js
index 5b3007b7d..27d0a7458 100644
--- a/modules/validations/crossing_ways.js
+++ b/modules/validations/crossing_ways.js
@@ -398,7 +398,9 @@ export function validationCrossingWays() {
}
}));
}
-
+ fixes.push(new validationIssueFix({
+ title: t('issues.fix.reposition_features.title')
+ }));
return new validationIssue({
type: type,
severity: 'warning',
diff --git a/modules/validations/deprecated_tag.js b/modules/validations/deprecated_tag.js
index a3da623c1..2247ad14a 100644
--- a/modules/validations/deprecated_tag.js
+++ b/modules/validations/deprecated_tag.js
@@ -30,6 +30,7 @@ export function validationDeprecatedTag() {
},
fixes: [
new validationIssueFix({
+ icon: 'iD-icon-up',
title: t('issues.fix.upgrade_tags.title'),
onClick: function() {
var entity = this.issue.entities[0];
diff --git a/modules/validations/disconnected_way.js b/modules/validations/disconnected_way.js
index 85c514b5c..55645960f 100644
--- a/modules/validations/disconnected_way.js
+++ b/modules/validations/disconnected_way.js
@@ -38,6 +38,7 @@ export function validationDisconnectedWay() {
if (!entity.isClosed()) {
fixes.push(new validationIssueFix({
+ icon: 'iD-operation-continue-left',
title: t('issues.fix.continue_from_start.title'),
entityIds: [entity.first()],
onClick: function() {
@@ -46,6 +47,7 @@ export function validationDisconnectedWay() {
}
}));
fixes.push(new validationIssueFix({
+ icon: 'iD-operation-continue',
title: t('issues.fix.continue_from_end.title'),
entityIds: [entity.last()],
onClick: function() {
@@ -56,6 +58,7 @@ export function validationDisconnectedWay() {
}
fixes.push(new validationIssueFix({
+ icon: 'iD-operation-delete',
title: t('issues.fix.delete_feature.title'),
entityIds: [entity.id],
onClick: function() {
@@ -80,7 +83,7 @@ export function validationDisconnectedWay() {
function continueDrawing(way, vertex) {
// make sure the vertex is actually visible and editable
var map = context.map();
- if (!map.editable() || !map.contains(vertex.loc)) {
+ if (!map.editable() || !map.trimmedExtent().contains(vertex.loc)) {
map.zoomToEase(vertex);
}
diff --git a/modules/validations/generic_name.js b/modules/validations/generic_name.js
index 9c5293706..9ab314901 100644
--- a/modules/validations/generic_name.js
+++ b/modules/validations/generic_name.js
@@ -6,7 +6,7 @@ import { actionChangeTags } from '../actions';
import { discardNames } from '../../node_modules/name-suggestion-index/config/filters.json';
-export function validationGenericName(context) {
+export function validationGenericName() {
var type = 'generic_name';
@@ -37,7 +37,7 @@ export function validationGenericName(context) {
}
- var validation = function(entity) {
+ var validation = function(entity, context) {
var issues = [];
var generic = isGenericName(entity);
if (generic) {
@@ -50,6 +50,7 @@ export function validationGenericName(context) {
entities: [entity],
fixes: [
new validationIssueFix({
+ icon: 'iD-operation-delete',
title: t('issues.fix.remove_generic_name.title'),
onClick: function() {
var entity = this.issue.entities[0];
diff --git a/modules/validations/missing_tag.js b/modules/validations/missing_tag.js
index 3ed4313a7..6d472c4ae 100644
--- a/modules/validations/missing_tag.js
+++ b/modules/validations/missing_tag.js
@@ -58,12 +58,14 @@ export function validationMissingTag() {
entities: [entity],
fixes: [
new validationIssueFix({
+ icon: 'iD-icon-search',
title: t('issues.fix.select_preset.title'),
onClick: function() {
context.ui().sidebar.showPresetList();
}
}),
new validationIssueFix({
+ icon: 'iD-operation-delete',
title: t('issues.fix.delete_feature.title'),
onClick: function() {
var id = this.issue.entities[0].id;
diff --git a/svg/iD-sprite/icons/icon-wrench.svg b/svg/iD-sprite/icons/icon-wrench.svg
new file mode 100644
index 000000000..0eaef0b6b
--- /dev/null
+++ b/svg/iD-sprite/icons/icon-wrench.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/svg/iD-sprite/operations/operation-continue-left.svg b/svg/iD-sprite/operations/operation-continue-left.svg
new file mode 100644
index 000000000..28e35f6b9
--- /dev/null
+++ b/svg/iD-sprite/operations/operation-continue-left.svg
@@ -0,0 +1,4 @@
+
+