diff --git a/data/core.yaml b/data/core.yaml
index 61343d5dc..fce1134da 100644
--- a/data/core.yaml
+++ b/data/core.yaml
@@ -481,7 +481,7 @@ en:
tooltip: Note data from OpenStreetMap
title: OpenStreetMap notes
keepRight:
- tooltip: Quality Assurance data from keepright.at
+ tooltip: Automatically detected map issues from keepright.at
title: KeepRight Issues
custom:
tooltip: "Drag and drop a data file onto the page, or click the button to setup"
@@ -649,9 +649,7 @@ en:
full_screen: Toggle Full Screen
QA:
keepRight:
- tooltip: automatically detected errors from keepright.at
- description: Keep Right
- title: Edit KeepRight Error
+ title: KeepRight Error
detail_title: Error
detail_description: Description
comment_header: Comment
@@ -659,22 +657,20 @@ en:
updateInputPlaceholder: Update the comment above to share with other users.
newComment: New Comment
updateComment: Update Comment
- upload_explanation: Your comments will be publicly visible to all keepRight.at users.
- upload_explanation_with_user: "Your comments as {user} will be publicly visible to all keepRight.at users."
+ upload_explanation: Your comments will be publicly visible on KeepRight.
+ upload_explanation_with_user: "Your comments as {user} will be publicly visible on KeepRight."
resolve_comment: Comment and Resolve
ignore_comment: Comment and Ignore
resolve: Resolve
ignore: Ignore
- toggle-on: All on
- toggle-off: All off
entities:
- node: node
- way: way
- relation: relation
- highway: highway
- cycleway: cycleway
- waterway: waterway
- riverbank: riverbank
+ node: "Node {id}"
+ way: "Way {id}"
+ relation: "Relation {id}"
+ highway: "Highway {id}"
+ cycleway: "Cycleway {id}"
+ waterway: "Waterway {id}"
+ riverbank: "Riverbank {id}"
errorTypes:
errors:
_30:
diff --git a/modules/util/keepRight/errorSchema.json b/data/keepRight.json
similarity index 100%
rename from modules/util/keepRight/errorSchema.json
rename to data/keepRight.json
diff --git a/dist/locales/en.json b/dist/locales/en.json
index ed5847ee5..fa9999527 100644
--- a/dist/locales/en.json
+++ b/dist/locales/en.json
@@ -584,7 +584,7 @@
"title": "OpenStreetMap notes"
},
"keepRight": {
- "tooltip": "Quality Assurance data from keepright.at",
+ "tooltip": "Automatically detected map issues from keepright.at",
"title": "KeepRight Issues"
},
"custom": {
@@ -789,9 +789,7 @@
"full_screen": "Toggle Full Screen",
"QA": {
"keepRight": {
- "tooltip": "automatically detected errors from keepright.at",
- "description": "Keep Right",
- "title": "Edit KeepRight Error",
+ "title": "KeepRight Error",
"detail_title": "Error",
"detail_description": "Description",
"comment_header": "Comment",
@@ -799,22 +797,20 @@
"updateInputPlaceholder": "Update the comment above to share with other users.",
"newComment": "New Comment",
"updateComment": "Update Comment",
- "upload_explanation": "Your comments will be publicly visible to all keepRight.at users.",
- "upload_explanation_with_user": "Your comments as {user} will be publicly visible to all keepRight.at users.",
+ "upload_explanation": "Your comments will be publicly visible on KeepRight.",
+ "upload_explanation_with_user": "Your comments as {user} will be publicly visible on KeepRight.",
"resolve_comment": "Comment and Resolve",
"ignore_comment": "Comment and Ignore",
"resolve": "Resolve",
"ignore": "Ignore",
- "toggle-on": "All on",
- "toggle-off": "All off",
"entities": {
- "node": "node",
- "way": "way",
- "relation": "relation",
- "highway": "highway",
- "cycleway": "cycleway",
- "waterway": "waterway",
- "riverbank": "riverbank"
+ "node": "Node {id}",
+ "way": "Way {id}",
+ "relation": "Relation {id}",
+ "highway": "Highway {id}",
+ "cycleway": "Cycleway {id}",
+ "waterway": "Waterway {id}",
+ "riverbank": "Riverbank {id}"
},
"errorTypes": {
"errors": {
diff --git a/modules/services/keepRight.js b/modules/services/keepRight.js
index 6aed5b8fd..1e74627e7 100644
--- a/modules/services/keepRight.js
+++ b/modules/services/keepRight.js
@@ -9,11 +9,14 @@ import { json as d3_json } from 'd3-request';
import { request as d3_request } from 'd3-request';
import { geoExtent, geoVecAdd } from '../geo';
-import { services } from './index';
import { krError } from '../osm';
-
+import { services } from './index';
+import { t } from '../util/locale';
import { utilRebind, utilTiler, utilQsString } from '../util';
+import { errorTypes } from '../../data/keepRight.json';
+
+
var tiler = utilTiler();
var dispatch = d3_dispatch('loaded');
@@ -22,6 +25,7 @@ var _krZoom = 14;
var apibase = 'https://www.keepright.at/';
var defaultRuleset = [0,30,40,50,70,90,100,110,120,130,150,160,170,180,191,192,193,194,195,196,197,198,201,202,203,204,205,206,207,208,210,220,231,232,270,281,282,283,284,285,291,292,293,294,295,296,297,298,311,312,313,320,350,370,380,401,402,411,412,413];
+
function abortRequest(i) {
if (i) {
i.abort();
@@ -58,6 +62,179 @@ function updateRtree(item, replace) {
}
+function tokenReplacements(datum) {
+ if (!(datum instanceof krError)) return;
+
+ var replacements = {};
+ var html_re = new RegExp(/<\/[a-z][\s\S]*>/);
+ var commonEntities = ['node', 'way', 'relation', 'highway', 'cycleway', 'waterway', 'riverbank'];
+
+ var errorType;
+ var errorTemplate;
+ var errorDescription;
+ var errorRegex;
+ var errorMatch;
+
+ // find the matching template from the error schema
+ errorType = '_' + datum.error_type;
+ errorTemplate = errorTypes.errors[errorType] || errorTypes.warnings[errorType];
+ if (!errorTemplate) return;
+
+ // some descriptions are just fixed text
+ if (!('regex' in errorTemplate)) return;
+
+ // regex pattern should match description with variable details captured as groups
+ errorDescription = datum.description;
+ errorRegex = new RegExp(errorTemplate.description);
+ errorMatch = errorRegex.exec(errorDescription);
+ if (!errorMatch) {
+ // TODO: Remove, for regex dev testing
+ console.log('Unmatched:', errorType, errorDescription, errorRegex);
+ return;
+ }
+
+ errorMatch.forEach(function(group, index) {
+ var idType;
+
+ // index 0 is the whole match, skip it
+ if (!index) return;
+
+ // link IDs if present in the group
+ idType = 'IDs' in errorTemplate ? errorTemplate.IDs[index-1] : '';
+ if (idType && group) {
+ group = parseError(group, idType);
+ } else if (html_re.test(group)) {
+ // escape any html in non-IDs
+ group = '\\' + group + '\\';
+ }
+
+ // translate common words (e.g. node, way, relation)
+ if (commonEntities.includes(group)) {
+ group = t('QA.keepRight.entities.' + group);
+ }
+
+ replacements['var' + index] = group;
+ });
+
+ return replacements;
+}
+
+
+function parseError(group, idType) {
+
+ function fillPlaceholder(d) { return '' + d + ''; }
+
+ // arbitrary node list of form: #ID, #ID, #ID...
+ function parseError211(list) {
+ var newList = [];
+ var items = list.split(', ');
+
+ items.forEach(function(item) {
+ // ID has # at the front
+ var id = fillPlaceholder('n' + item.slice(1));
+ newList.push(id);
+ });
+
+ return newList.join(', ');
+ }
+
+ // arbitrary way list of form: #ID(layer),#ID(layer),#ID(layer)...
+ function parseError231(list) {
+ var newList = [];
+ var items = list.split(',');
+
+ items.forEach(function(item) {
+ var id;
+ var layer;
+
+ // item of form "#ID(layer)"
+ item = item.split('(');
+
+ // ID has # at the front
+ id = item[0].slice(1);
+ id = fillPlaceholder('w' + id);
+
+ // layer has trailing )
+ layer = item[1].slice(0,-1);
+
+ // TODO: translation
+ newList.push(id + ' (layer: ' + layer + ')');
+ });
+
+ return newList.join(', ');
+ }
+
+ // arbitrary node/relation list of form: from node #ID,to relation #ID,to node #ID...
+ function parseError294(list) {
+ var newList = [];
+ var items = list.split(',');
+
+ items.forEach(function(item) {
+ var role;
+ var idType;
+ var id;
+
+ // item of form "from/to node/relation #ID"
+ item = item.split(' ');
+
+ // to/from role is more clear in quotes
+ role = '"' + item[0] + '"';
+
+ // first letter of node/relation provides the type
+ idType = item[1].slice(0,1);
+
+ // ID has # at the front
+ id = item[2].slice(1);
+ id = fillPlaceholder(idType + id);
+
+ item = [role, item[1], id].join(' ');
+ newList.push(item);
+ });
+
+ return newList.join(', ');
+ }
+
+ // TODO: Handle error 401 template addition
+
+ // arbitrary node list of form: #ID,#ID,#ID...
+ function parseWarning20(list) {
+ var newList = [];
+ var items = list.split(',');
+
+ items.forEach(function(item) {
+ // ID has # at the front
+ var id = fillPlaceholder('n' + item.slice(1));
+ newList.push(id);
+ });
+
+ return newList.join(', ');
+ }
+
+ switch (idType) {
+ // simple case just needs a linking span
+ case 'n':
+ case 'w':
+ case 'r':
+ group = fillPlaceholder(idType + group);
+ break;
+ // some errors have more complex ID lists/variance
+ case '211':
+ group = parseError211(group);
+ break;
+ case '231':
+ group = parseError231(group);
+ break;
+ case '294':
+ group = parseError294(group);
+ break;
+ case '20':
+ group = parseWarning20(group);
+ }
+
+ return group;
+}
+
+
export default {
init: function() {
if (!_krCache) {
@@ -77,11 +254,8 @@ export default {
// KeepRight API: http://osm.mueschelsoft.de/keepright/interfacing.php
loadErrors: function(context, projection) {
- var options = {
- format: 'geojson'
- };
+ var options = { format: 'geojson' };
var rules = defaultRuleset.join();
- var that = this;
// determine the needed tiles to cover the view
var tiles = tiler
@@ -136,6 +310,8 @@ export default {
title: props.title
});
+ d.replacements = tokenReplacements(d);
+
_krCache.keepRight[d.id] = d;
_krCache.rtree.insert(encodeErrorRtree(d));
});
diff --git a/modules/ui/keepRight_details.js b/modules/ui/keepRight_details.js
index 0092c535d..f5edc8a23 100644
--- a/modules/ui/keepRight_details.js
+++ b/modules/ui/keepRight_details.js
@@ -1,7 +1,7 @@
-import { t } from '../util/locale';
-import { parseErrorDescriptions, errorTypes } from '../util';
+import { event as d3_event } from 'd3-selection';
-import { clickLink } from '../util/keepRight';
+import { errorTypes } from '../../data/keepRight.json';
+import { t } from '../util/locale';
export function uiKeepRightDetails(context) {
@@ -97,12 +97,18 @@ export function uiKeepRightDetails(context) {
.append('div')
.attr('class', 'kr_error-details-description-text')
.html(function(d) {
- return t(_titleBase + _templateErrorType + '.description', parseErrorDescriptions(d));
+ return t(_titleBase + _templateErrorType + '.description', d.replacements);
});
description.selectAll('.kr_error_description-id')
.on('click', function() { clickLink(context, this.text); });
+
+ function clickLink(context, id) {
+ d3_event.preventDefault();
+ context.layers().layer('osm').enabled(true);
+ context.zoomToEntity(id);
+ }
}
diff --git a/modules/ui/keepRight_header.js b/modules/ui/keepRight_header.js
index 978008572..878eb588a 100644
--- a/modules/ui/keepRight_header.js
+++ b/modules/ui/keepRight_header.js
@@ -1,10 +1,8 @@
import { t } from '../util/locale';
-import { utilEntityRoot } from '../util';
-import { clickLink } from '../util/keepRight';
import { svgIcon } from '../svg';
-export function uiKeepRightHeader(context) {
+export function uiKeepRightHeader() {
var _error;
@@ -32,17 +30,12 @@ export function uiKeepRightHeader(context) {
.attr('class', function(d) {
return 'preset-icon-28 kr_error kr_error-' + d.id + ' kr_error_type_' + d.error_type;
})
-
.call(svgIcon('#iD-icon-bolt', 'kr_error-fill'));
headerEnter
.append('div')
.attr('class', 'kr_error-header-label')
- .text(function(d) { return t('QA.keepRight.entities.' + d.object_type) + ' '; })
- .append('span')
- .append('a')
- .text(function(d) { return d.object_id; })
- .on('click', function(d) { clickLink(context, (utilEntityRoot(d.object_type) + d.object_id)); });
+ .text(function(d) { return t('QA.keepRight.entities.' + d.object_type, { id: d.object_id }); });
}
diff --git a/modules/ui/map_data.js b/modules/ui/map_data.js
index a96b255cf..a6cee9fd7 100644
--- a/modules/ui/map_data.js
+++ b/modules/ui/map_data.js
@@ -1,11 +1,9 @@
-import { dispatch as d3_dispatch } from 'd3-dispatch';
import {
event as d3_event,
select as d3_select
} from 'd3-selection';
import { svgIcon } from '../svg';
-import { errorTypes } from '../util';
import { t, textDirection } from '../util/locale';
import { tooltip } from '../util/tooltip';
import { geoExtent } from '../geo';
@@ -18,8 +16,6 @@ import { uiTooltipHtml } from './tooltipHtml';
export function uiMapData(context) {
- var dispatch = d3_dispatch('change');
-
var key = t('map_data.key');
var features = context.features().keys();
var layers = context.layers();
@@ -485,46 +481,6 @@ export function uiMapData(context) {
}
- function drawQAButtons(selection) {
- var QAButtons = d3_select('.layer-QA').selectAll('li').select('label').select('input');
- var buttonSection = selection.selectAll('.QA-buttons')
- .data([0]);
-
- // var buttonSection = selection.selectAll('.QA-buttons')
- // .data([0]);
-
- // // exit
- // buttonSection.exit()
- // .remove();
-
- // // enter
- // var buttonEnter = buttonSection.enter()
- // .append('div')
- // .attr('class', 'QA-buttons');
-
- // buttonEnter
- // .append('button')
- // .attr('class', 'button QA-toggle-on action')
- // .text(t('QA.keepRight.toggle-on'))
- // .on('click', function() {
- // QAButtons.property('checked', true);
- // dispatch.call('change');
- // });
-
- // buttonEnter
- // .append('button')
- // .attr('class', 'button QA-toggle-off action')
- // .text(t('QA.keepRight.toggle-off'))
- // .on('click', function() {
- // QAButtons.property('checked', false);
- // dispatch.call('change');
- // });
-
- // buttonSection = buttonSection
- // .merge(buttonEnter);
- }
-
-
function drawListItems(selection, data, type, name, change, active) {
var items = selection.selectAll('li')
.data(data);
diff --git a/modules/util/index.js b/modules/util/index.js
index b386875c3..98755addd 100644
--- a/modules/util/index.js
+++ b/modules/util/index.js
@@ -14,7 +14,6 @@ export { utilExternalValidationRules } from './util';
export { utilFastMouse } from './util';
export { utilFunctor } from './util';
export { utilGetAllNodes } from './util';
-export { errorTypes, parseErrorDescriptions, clickLink } from './keepRight';
export { utilGetPrototypeOf } from './util';
export { utilGetSetValue } from './get_set_value';
export { utilHashcode } from './util';
@@ -29,7 +28,6 @@ export { utilRebind } from './rebind';
export { utilSetTransform } from './util';
export { utilSessionMutex } from './session_mutex';
export { utilStringQs } from './util';
-// export { utilSuggestNames } from './suggest_names';
export { utilTagText } from './util';
export { utilTiler } from './tiler';
export { utilTriggerEvent } from './trigger_event';
diff --git a/modules/util/keepRight/index.js b/modules/util/keepRight/index.js
deleted file mode 100644
index 0f95dc9a7..000000000
--- a/modules/util/keepRight/index.js
+++ /dev/null
@@ -1,3 +0,0 @@
-export { errorTypes } from './errorSchema.json';
-export { parseError } from './parse_error';
-export { parseErrorDescriptions, clickLink } from './keepRight_error';
\ No newline at end of file
diff --git a/modules/util/keepRight/keepRight_error.js b/modules/util/keepRight/keepRight_error.js
deleted file mode 100644
index 6e50728a4..000000000
--- a/modules/util/keepRight/keepRight_error.js
+++ /dev/null
@@ -1,80 +0,0 @@
-import { event as d3_event } from 'd3-selection';
-
-import { t } from '../locale';
-import { krError } from '../../osm';
-
-import { errorTypes } from './errorSchema.json';
-import { parseError } from './parse_error';
-
-
-export function parseErrorDescriptions(entity) {
- var parsedDetails = {};
- var html_re = new RegExp(/<\/[a-z][\s\S]*>/);
- var commonEntities = [
- 'node',
- 'way',
- 'relation',
- 'highway',
- 'cycleway',
- 'waterway',
- 'riverbank'
- ]; // TODO: expand this list, or implement a different translation function
-
- var errorType;
- var errorTemplate;
- var errorDescription;
- var errorRegex;
- var errorMatch;
-
- if (!(entity instanceof krError)) return;
-
- // find the matching template from the error schema
- errorType = '_' + entity.error_type;
- errorTemplate = errorTypes.errors[errorType] || errorTypes.warnings[errorType];
- if (!errorTemplate) return;
-
- // some descriptions are just fixed text
- if (!('regex' in errorTemplate)) return;
-
- // regex pattern should match description with variable details captured as groups
- errorDescription = entity.description;
- errorRegex = new RegExp(errorTemplate.description);
- errorMatch = errorRegex.exec(errorDescription);
- if (!errorMatch) {
- // TODO: Remove, for regex dev testing
- console.log('Unmatched:', errorType, errorDescription, errorRegex);
- return;
- }
-
- errorMatch.forEach(function(group, index) {
- var idType;
-
- // index 0 is the whole match, skip it
- if (!index) return;
-
- // link IDs if present in the group
- idType = 'IDs' in errorTemplate ? errorTemplate.IDs[index-1] : '';
- if (idType && group) {
- group = parseError(group, idType);
- } else if (html_re.test(group)) {
- // escape any html in non-IDs
- group = '\\' + group + '\\';
- }
-
- // translate common words (e.g. node, way, relation)
- if (commonEntities.includes(group)) {
- group = t('QA.keepRight.entities.' + group);
- }
-
- parsedDetails['var' + index] = group;
- });
-
- return parsedDetails;
-}
-
-
-export function clickLink(context, id) {
- d3_event.preventDefault();
- context.layers().layer('osm').enabled(true);
- context.zoomToEntity(id);
- }
diff --git a/modules/util/keepRight/parse_error.js b/modules/util/keepRight/parse_error.js
deleted file mode 100644
index 37eed18dc..000000000
--- a/modules/util/keepRight/parse_error.js
+++ /dev/null
@@ -1,113 +0,0 @@
-export function parseError(group, idType) {
-
- function fillPlaceholder(d) { return '' + d + ''; }
-
- // arbitrary node list of form: #ID, #ID, #ID...
- function parseError211(list) {
- var newList = [];
- var items = list.split(', ');
-
- items.forEach(function(item) {
- // ID has # at the front
- var id = fillPlaceholder('n' + item.slice(1));
- newList.push(id);
- });
-
- return newList.join(', ');
- }
-
- // arbitrary way list of form: #ID(layer),#ID(layer),#ID(layer)...
- function parseError231(list) {
- var newList = [];
- var items = list.split(',');
-
- items.forEach(function(item) {
- var id;
- var layer;
-
- // item of form "#ID(layer)"
- item = item.split('(');
-
- // ID has # at the front
- id = item[0].slice(1);
- id = fillPlaceholder('w' + id);
-
- // layer has trailing )
- layer = item[1].slice(0,-1);
-
- // TODO: translation
- newList.push(id + ' (layer: ' + layer + ')');
- });
-
- return newList.join(', ');
- }
-
- // arbitrary node/relation list of form: from node #ID,to relation #ID,to node #ID...
- function parseError294(list) {
- var newList = [];
- var items = list.split(',');
-
- items.forEach(function(item) {
- var role;
- var idType;
- var id;
-
- // item of form "from/to node/relation #ID"
- item = item.split(' ');
-
- // to/from role is more clear in quotes
- role = '"' + item[0] + '"';
-
- // first letter of node/relation provides the type
- idType = item[1].slice(0,1);
-
- // ID has # at the front
- id = item[2].slice(1);
- id = fillPlaceholder(idType + id);
-
- item = [role, item[1], id].join(' ');
- newList.push(item);
- });
-
- return newList.join(', ');
- }
-
- // TODO: Handle error 401 template addition
-
- // arbitrary node list of form: #ID,#ID,#ID...
- function parseWarning20(list) {
- var newList = [];
- var items = list.split(',');
-
- items.forEach(function(item) {
- // ID has # at the front
- var id = fillPlaceholder('n' + item.slice(1));
- newList.push(id);
- });
-
- return newList.join(', ');
- }
-
- switch (idType) {
- // simple case just needs a linking span
- case 'n':
- case 'w':
- case 'r':
- group = fillPlaceholder(idType + group);
- break;
- // some errors have more complex ID lists/variance
- case '211':
- group = parseError211(group);
- break;
- case '231':
- group = parseError231(group);
- break;
- case '294':
- group = parseError294(group);
- break;
- case '20':
- group = parseWarning20(group);
- }
-
- return group;
-}
\ No newline at end of file