diff --git a/css/45_waterways.css b/css/45_waterways.css
index 34d970e04..8f7ea9ba2 100644
--- a/css/45_waterways.css
+++ b/css/45_waterways.css
@@ -2,13 +2,13 @@
/* defaults */
.preset-icon .icon.tag-waterway.other-line {
- color: #77d3de;
- fill: #77d3de;
+ color: #7dd;
+ fill: #7dd;
}
.preset-icon .icon.iD-category-water,
.preset-icon .icon.tag-type-waterway,
.preset-icon .icon.tag-waterway {
- color: #77d3de;
+ color: #7dd;
fill: #fff;
}
@@ -38,10 +38,10 @@ path.line.fill.tag-waterway {
fill: rgba(119, 211, 222, 0.3);
}
path.line.casing.tag-waterway {
- stroke: #3d6c71;
+ stroke: #444;
}
path.line.stroke.tag-waterway {
- stroke: #77d3de;
+ stroke: #7dd;
}
@@ -91,9 +91,9 @@ path.line.stroke.tag-waterway-river {
/* ditch */
.preset-icon .icon.tag-waterway-ditch {
- color: #8eabf3;
+ color: #39a;
}
path.line.stroke.tag-waterway-ditch {
- stroke: #8eabf3;
+ stroke: #39a;
}
diff --git a/css/50_misc.css b/css/50_misc.css
index fe454adab..f7ac406be 100644
--- a/css/50_misc.css
+++ b/css/50_misc.css
@@ -93,7 +93,7 @@ path.line.casing.tag-aerialway {
/* pistes */
path.line.stroke.tag-piste {
- stroke: #9ac;
+ stroke: #a9d;
}
path.line.casing.tag-piste {
stroke: #444;
diff --git a/css/65_data.css b/css/65_data.css
index 2b19ae553..8de9ca09c 100644
--- a/css/65_data.css
+++ b/css/65_data.css
@@ -1,7 +1,7 @@
/* OSM Notes and KeepRight Layers */
-.kr_error-header-icon .qa_error-fill,
+.error-header-icon .qa_error-fill,
.layer-keepRight .qa_error .qa_error-fill,
.layer-improveOSM .qa_error .qa_error-fill {
stroke: #333;
@@ -44,12 +44,12 @@
/* adjustment for error icon */
-.kr_error-header-icon .preset-icon-28 {
+.error-header-icon .preset-icon-28 {
top: auto;
left: auto;
}
-.kr_error-header-icon {
+.error-header-icon {
display: flex;
align-items: center;
justify-content: center;
@@ -211,4 +211,4 @@
stroke: #000;
stroke-width: 5px;
stroke-miterlimit: 1;
-}
\ No newline at end of file
+}
diff --git a/css/80_app.css b/css/80_app.css
index f8aeb054f..d73dfa5b4 100644
--- a/css/80_app.css
+++ b/css/80_app.css
@@ -593,7 +593,7 @@ button.add-note svg.icon {
.field-help-title button.close,
.sidebar-component .header button.data-editor-close,
.sidebar-component .header button.note-editor-close,
-.sidebar-component .header button.keepRight-editor-close,
+.sidebar-component .header button.error-editor-close,
.entity-editor-pane .header button.preset-close,
.preset-list-pane .header button.preset-choose {
position: absolute;
@@ -603,7 +603,7 @@ button.add-note svg.icon {
[dir='rtl'] .field-help-title button.close,
[dir='rtl'] .sidebar-component .header button.data-editor-close,
[dir='rtl'] .sidebar-component .header button.note-editor-close,
-[dir='rtl'] .sidebar-component .header button.keepRight-editor-close,
+[dir='rtl'] .sidebar-component .header button.error-editor-close,
[dir='rtl'] .entity-editor-pane .header button.preset-close,
[dir='rtl'] .preset-list-pane .header button.preset-choose {
left: 0;
@@ -1177,7 +1177,7 @@ img.tag-reference-wiki-image {
}
.data-editor .quick-links,
-.keepRight-editor .quick-links,
+.error-editor .quick-links,
.note-editor .quick-links {
padding: 5px 0 0 0;
}
@@ -2500,7 +2500,7 @@ input.key-trap {
/* OSM Note / KeepRight Editors
------------------------------------------------------- */
.note-header,
-.kr_error-header {
+.error-header {
background-color: #f6f6f6;
border-radius: 5px;
border: 1px solid #ccc;
@@ -2510,7 +2510,7 @@ input.key-trap {
}
.note-header-icon,
-.kr_error-header-icon {
+.error-header-icon {
background-color: #fff;
padding: 10px;
flex: 0 0 62px;
@@ -2521,20 +2521,20 @@ input.key-trap {
border-radius: 5px 0 0 5px;
}
[dir='rtl'] .note-header-icon,
-[dir='rtl'] .kr_error-header-icon {
+[dir='rtl'] .error-header-icon {
border-right: unset;
border-left: 1px solid #ccc;
border-radius: 0 5px 5px 0;
}
.note-header-icon .icon-wrap,
-.kr_error-header-icon .icon-wrap {
+.error-header-icon .icon-wrap {
position: absolute;
top: 0px;
}
.note-header-label,
-.kr_error-header-label {
+.error-header-label {
background-color: #f6f6f6;
padding: 0 15px;
flex: 1 1 100%;
@@ -2543,7 +2543,7 @@ input.key-trap {
border-radius: 0 5px 5px 0;
}
[dir='rtl'] .note-header-label,
-[dir='rtl'] .kr_error-header-label {
+[dir='rtl'] .error-header-label {
border-radius: 5px 0 0 5px;
}
@@ -2610,46 +2610,44 @@ input.key-trap {
}
.note-save,
-.keepRight-save {
+.error-save {
padding-top: 20px;
}
-.kr_error-details,
-.kr_error-comment-container {
+
+.error-details {
padding: 10px;
}
-
-.keepRight-save .new-comment-input,
-.note-save .new-comment-input {
- width: 100%;
- height: 100px;
- max-height: 300px;
- min-height: 100px;
-}
-
-.keepRight-save .detail-section,
-.note-save .detail-section {
- margin: 10px 0;
-}
-
-.note-report {
- float: right;
-}
-
-.kr_error-details-container {
+.error-details-container {
background: #ececec;
padding: 10px;
margin-top: 20px;
border-radius: 4px;
border: 1px solid #ccc;
}
-
-.kr_error-details-description {
+.error-details-description {
margin-bottom: 10px;
}
-.kr_error-details-description-text::first-letter {
+.error-details-description-text::first-letter {
text-transform: capitalize;
}
+.note-save .new-comment-input,
+.error-save .new-comment-input {
+ width: 100%;
+ height: 100px;
+ max-height: 300px;
+ min-height: 100px;
+}
+
+.note-save .detail-section,
+.error-save .detail-section {
+ margin: 10px 0;
+}
+
+.note-report {
+ float: right;
+}
+
/* Custom Data Editor
------------------------------------------------------- */
diff --git a/modules/core/history.js b/modules/core/history.js
index feb496362..97f730579 100644
--- a/modules/core/history.js
+++ b/modules/core/history.js
@@ -101,7 +101,7 @@ export function coreHistory(context) {
}
- // determine diffrence and dispatch a change event
+ // determine difference and dispatch a change event
function change(previous, isAnnotated) {
var difference = coreDifference(previous, history.graph());
dispatch.call('change', this, difference);
diff --git a/modules/services/improveOSM.js b/modules/services/improveOSM.js
index 5623a09db..9d3b51ab7 100644
--- a/modules/services/improveOSM.js
+++ b/modules/services/improveOSM.js
@@ -65,11 +65,11 @@ function updateRtree(item, replace) {
}
function linkErrorObject(d) {
- return '' + d + '';
+ return '' + d + '';
}
function linkEntity(d) {
- return '' + d + '';
+ return '' + d + '';
}
function pointAverage(points) {
@@ -329,6 +329,36 @@ export default {
});
},
+ getComments: function(d, callback) {
+ // If comments already retrieved no need to do so again
+ if (d.comments !== undefined) { return callback({}, d); }
+
+ var key = d.error_key;
+ var qParams = {};
+
+ if (key === 'ow') {
+ qParams = d.identifier;
+ } else if (key === 'mr') {
+ qParams.tileX = d.identifier.x;
+ qParams.tileY = d.identifier.y;
+ } else if (key === 'tr') {
+ qParams.targetId = d.identifier;
+ }
+
+ var url = _impOsmUrls[key] + '/retrieveComments?' + utilQsString(qParams);
+
+ var that = this;
+ d3_json(url, function(err, data) {
+ // comments are served newest to oldest
+ var comments = data.comments ? data.comments.reverse() : [];
+
+ that.replaceError(d.update({
+ comments: comments
+ }));
+ return callback(err, d);
+ });
+ },
+
postUpdate: function(d, callback) {
if (!services.osm.authenticated()) { // Username required in payload
return callback({ message: 'Not Authenticated', status: -3}, d);
@@ -360,17 +390,16 @@ export default {
payload.targetIds = [ d.identifier ];
}
- // Comments don't currently work, if they ever do in future
- // it looks as though they require a separate post
- // if (d.newComment !== undefined) {
- // payload.text = d.newComment;
- // }
-
- if (d.newStatus !== d.status) {
+ if (d.newStatus !== undefined) {
payload.status = d.newStatus;
payload.text = 'status changed';
}
+ // Comment take place of default text
+ if (d.newComment !== undefined) {
+ payload.text = d.newComment;
+ }
+
_erCache.inflightPost[d.id] = d3_request(url)
.header('Content-Type', 'application/json')
.post(JSON.stringify(payload), function(err) {
@@ -379,12 +408,29 @@ export default {
// Unsuccessful response status, keep issue open
if (err.status !== 200) { return callback(err, d); }
- that.removeError(d);
+ // Just a comment, update error in cache
+ if (d.newStatus === undefined) {
+ var now = new Date();
+ var comments = d.comments ? d.comments : [];
- // No pretty identifier, so we just use coordinates
- if (d.newStatus === 'SOLVED') {
- var closedID = d.loc[1].toFixed(5) + '/' + d.loc[0].toFixed(5);
- _erCache.closed[key + ':' + closedID] = true;
+ comments.push({
+ username: payload.username,
+ text: payload.text,
+ timestamp: now.getTime() / 1000
+ });
+
+ that.replaceError(d.update({
+ comments: comments,
+ newComment: undefined
+ }));
+ } else {
+ that.removeError(d);
+
+ if (d.newStatus === 'SOLVED') {
+ // No pretty identifier, so we just use coordinates
+ var closedID = d.loc[1].toFixed(5) + '/' + d.loc[0].toFixed(5);
+ _erCache.closed[key + ':' + closedID] = true;
+ }
}
return callback(err, d);
@@ -430,4 +476,4 @@ export default {
getClosedIDs: function() {
return Object.keys(_erCache.closed).sort();
}
-};
\ No newline at end of file
+};
diff --git a/modules/services/keepRight.js b/modules/services/keepRight.js
index 0995cab27..68e34587a 100644
--- a/modules/services/keepRight.js
+++ b/modules/services/keepRight.js
@@ -168,11 +168,11 @@ function parseError(capture, idType) {
function linkErrorObject(d) {
- return '' + d + '';
+ return '' + d + '';
}
function linkEntity(d) {
- return '' + d + '';
+ return '' + d + '';
}
function linkURL(d) {
@@ -499,4 +499,4 @@ export default {
return Object.keys(_krCache.closed).sort();
}
-};
\ No newline at end of file
+};
diff --git a/modules/ui/combobox.js b/modules/ui/combobox.js
index 93b0ae596..def5e1fed 100644
--- a/modules/ui/combobox.js
+++ b/modules/ui/combobox.js
@@ -177,7 +177,6 @@ export function uiCombobox(context, klass) {
break;
case 9: // ⇥ Tab
- d3_event.stopPropagation();
accept();
break;
diff --git a/modules/ui/improveOSM_comments.js b/modules/ui/improveOSM_comments.js
new file mode 100644
index 000000000..47608e0c5
--- /dev/null
+++ b/modules/ui/improveOSM_comments.js
@@ -0,0 +1,94 @@
+import { select as d3_select } from 'd3-selection';
+
+import { t } from '../util/locale';
+import { svgIcon } from '../svg';
+import { services } from '../services';
+import { utilDetect } from '../util/detect';
+
+export function uiImproveOsmComments() {
+ var _error;
+
+
+ function errorComments(selection) {
+ // make the div immediately so it appears above the buttons
+ var comments = selection.selectAll('.comments-container')
+ .data([0]);
+
+ comments = comments.enter()
+ .append('div')
+ .attr('class', 'comments-container')
+ .merge(comments);
+
+ // must retrieve comments from API before they can be displayed
+ services.improveOSM.getComments(_error, function(err, d) {
+ if (!d.comments) { return; } // nothing to do here
+
+ var commentEnter = comments.selectAll('.comment')
+ .data(d.comments)
+ .enter()
+ .append('div')
+ .attr('class', 'comment');
+
+ commentEnter
+ .append('div')
+ .attr('class', 'comment-avatar')
+ .call(svgIcon('#iD-icon-avatar', 'comment-avatar-icon'));
+
+ var mainEnter = commentEnter
+ .append('div')
+ .attr('class', 'comment-main');
+
+ var metadataEnter = mainEnter
+ .append('div')
+ .attr('class', 'comment-metadata');
+
+ metadataEnter
+ .append('div')
+ .attr('class', 'comment-author')
+ .each(function(d) {
+ var selection = d3_select(this);
+ var osm = services.osm;
+ if (osm && d.username) {
+ selection = selection
+ .append('a')
+ .attr('class', 'comment-author-link')
+ .attr('href', osm.userURL(d.username))
+ .attr('tabindex', -1)
+ .attr('target', '_blank');
+ }
+ selection
+ .text(function(d) { return d.username; });
+ });
+
+ metadataEnter
+ .append('div')
+ .attr('class', 'comment-date')
+ .text(function(d) {
+ return t('note.status.commented', { when: localeDateString(d.timestamp) });
+ });
+
+ mainEnter
+ .append('div')
+ .attr('class', 'comment-text')
+ .append('p')
+ .text(function(d) { return d.text; });
+ });
+ }
+
+ function localeDateString(s) {
+ if (!s) return null;
+ var detected = utilDetect();
+ var options = { day: 'numeric', month: 'short', year: 'numeric' };
+ var d = new Date(s * 1000); // timestamp is served in seconds, date takes ms
+ if (isNaN(d.getTime())) return null;
+ return d.toLocaleDateString(detected.locale, options);
+ }
+
+ errorComments.error = function(val) {
+ if (!arguments.length) return _error;
+ _error = val;
+ return errorComments;
+ };
+
+ return errorComments;
+}
\ No newline at end of file
diff --git a/modules/ui/improveOSM_details.js b/modules/ui/improveOSM_details.js
index 075ccd0cb..efa27ef9b 100644
--- a/modules/ui/improveOSM_details.js
+++ b/modules/ui/improveOSM_details.js
@@ -32,7 +32,7 @@ export function uiImproveOsmDetails(context) {
function improveOsmDetails(selection) {
- var details = selection.selectAll('.kr_error-details')
+ var details = selection.selectAll('.error-details')
.data(
(_error ? [_error] : []),
function(d) { return d.id + '-' + (d.status || 0); }
@@ -43,13 +43,13 @@ export function uiImproveOsmDetails(context) {
var detailsEnter = details.enter()
.append('div')
- .attr('class', 'kr_error-details kr_error-details-container');
+ .attr('class', 'error-details error-details-container');
// description
var descriptionEnter = detailsEnter
.append('div')
- .attr('class', 'kr_error-details-description');
+ .attr('class', 'error-details-description');
descriptionEnter
.append('h4')
@@ -57,14 +57,14 @@ export function uiImproveOsmDetails(context) {
descriptionEnter
.append('div')
- .attr('class', 'kr_error-details-description-text')
+ .attr('class', 'error-details-description-text')
.html(errorDetail);
// If there are entity links in the error message..
- descriptionEnter.selectAll('.kr_error_entity_link, .kr_error_object_link')
+ descriptionEnter.selectAll('.error_entity_link, .error_object_link')
.each(function() {
var link = d3_select(this);
- var isObjectLink = link.classed('kr_error_object_link');
+ var isObjectLink = link.classed('error_object_link');
var entityID = isObjectLink ?
(utilEntityRoot(_error.object_type) + _error.object_id)
: this.textContent;
@@ -124,4 +124,4 @@ export function uiImproveOsmDetails(context) {
return improveOsmDetails;
-}
\ No newline at end of file
+}
diff --git a/modules/ui/improveOSM_editor.js b/modules/ui/improveOSM_editor.js
index c1c29c1b5..14405b538 100644
--- a/modules/ui/improveOSM_editor.js
+++ b/modules/ui/improveOSM_editor.js
@@ -1,4 +1,5 @@
import { dispatch as d3_dispatch } from 'd3-dispatch';
+import { select as d3_select } from 'd3-selection';
import { t } from '../util/locale';
import { services } from '../services';
@@ -6,18 +7,20 @@ import { modeBrowse } from '../modes';
import { svgIcon } from '../svg';
import {
+ uiImproveOsmComments,
uiImproveOsmDetails,
uiImproveOsmHeader,
uiQuickLinks,
uiTooltipHtml
} from './index';
-import { utilRebind } from '../util';
+import { utilNoAuto, utilRebind } from '../util';
export function uiImproveOsmEditor(context) {
var dispatch = d3_dispatch('change');
var errorDetails = uiImproveOsmDetails(context);
+ var errorComments = uiImproveOsmComments(context);
var errorHeader = uiImproveOsmHeader(context);
var quickLinks = uiQuickLinks();
@@ -47,7 +50,7 @@ export function uiImproveOsmEditor(context) {
headerEnter
.append('button')
- .attr('class', 'fr keepRight-editor-close')
+ .attr('class', 'fr error-editor-close')
.on('click', function() {
context.enter(modeBrowse(context));
})
@@ -66,16 +69,17 @@ export function uiImproveOsmEditor(context) {
.attr('class', 'body')
.merge(body);
- var editor = body.selectAll('.keepRight-editor')
+ var editor = body.selectAll('.error-editor')
.data([0]);
editor.enter()
.append('div')
- .attr('class', 'modal-section keepRight-editor')
+ .attr('class', 'modal-section error-editor')
.merge(editor)
.call(errorHeader.error(_error))
.call(quickLinks.choices(choices))
.call(errorDetails.error(_error))
+ .call(errorComments.error(_error))
.call(improveOsmSaveSection);
}
@@ -95,12 +99,47 @@ export function uiImproveOsmEditor(context) {
// enter
var saveSectionEnter = saveSection.enter()
.append('div')
- .attr('class', 'keepRight-save save-section cf');
+ .attr('class', 'error-save save-section cf');
+
+ saveSectionEnter
+ .append('h4')
+ .attr('class', '.error-save-header')
+ .text(t('note.newComment'));
+
+ saveSectionEnter
+ .append('textarea')
+ .attr('class', 'new-comment-input')
+ .attr('placeholder', t('QA.keepRight.comment_placeholder'))
+ .attr('maxlength', 1000)
+ .property('value', function(d) { return d.newComment; })
+ .call(utilNoAuto)
+ .on('input', changeInput)
+ .on('blur', changeInput);
// update
saveSection = saveSectionEnter
.merge(saveSection)
.call(errorSaveButtons);
+
+ function changeInput() {
+ var input = d3_select(this);
+ var val = input.property('value').trim();
+
+ if (val === '') {
+ val = undefined;
+ }
+
+ // store the unsaved comment with the error itself
+ _error = _error.update({ newComment: val });
+
+ var errorService = services.improveOSM;
+ if (errorService) {
+ errorService.replaceError(_error);
+ }
+
+ saveSection
+ .call(errorSaveButtons);
+ }
}
function errorSaveButtons(selection) {
@@ -117,11 +156,10 @@ export function uiImproveOsmEditor(context) {
.append('div')
.attr('class', 'buttons');
- // Comments don't currently work
- // buttonEnter
- // .append('button')
- // .attr('class', 'button comment-button action')
- // .text(t('QA.keepRight.save_comment'));
+ buttonEnter
+ .append('button')
+ .attr('class', 'button comment-button action')
+ .text(t('QA.keepRight.save_comment'));
buttonEnter
.append('button')
@@ -136,20 +174,19 @@ export function uiImproveOsmEditor(context) {
buttonSection = buttonSection
.merge(buttonEnter);
- // Comments don't currently work
- // buttonSection.select('.comment-button')
- // .attr('disabled', function(d) {
- // return d.newComment === undefined ? true : null;
- // })
- // .on('click.comment', function(d) {
- // this.blur(); // avoid keeping focus on the button - #4641
- // var errorService = services.improveOSM;
- // if (errorService) {
- // errorService.postUpdate(d, function(err, error) {
- // dispatch.call('change', error);
- // });
- // }
- // });
+ buttonSection.select('.comment-button')
+ .attr('disabled', function(d) {
+ return d.newComment === undefined ? true : null;
+ })
+ .on('click.comment', function(d) {
+ this.blur(); // avoid keeping focus on the button - #4641
+ var errorService = services.improveOSM;
+ if (errorService) {
+ errorService.postUpdate(d, function(err, error) {
+ dispatch.call('change', error);
+ });
+ }
+ });
buttonSection.select('.close-button')
.text(function(d) {
diff --git a/modules/ui/improveOSM_header.js b/modules/ui/improveOSM_header.js
index d87b7cb3e..f9ae38327 100644
--- a/modules/ui/improveOSM_header.js
+++ b/modules/ui/improveOSM_header.js
@@ -22,7 +22,7 @@ export function uiImproveOsmHeader() {
function improveOsmHeader(selection) {
- var header = selection.selectAll('.kr_error-header')
+ var header = selection.selectAll('.error-header')
.data(
(_error ? [_error] : []),
function(d) { return d.id + '-' + (d.status || 0); }
@@ -33,11 +33,11 @@ export function uiImproveOsmHeader() {
var headerEnter = header.enter()
.append('div')
- .attr('class', 'kr_error-header');
+ .attr('class', 'error-header');
var iconEnter = headerEnter
.append('div')
- .attr('class', 'kr_error-header-icon')
+ .attr('class', 'error-header-icon')
.classed('new', function(d) { return d.id < 0; });
var svgEnter = iconEnter
@@ -81,7 +81,7 @@ export function uiImproveOsmHeader() {
headerEnter
.append('div')
- .attr('class', 'kr_error-header-label')
+ .attr('class', 'error-header-label')
.text(errorTitle);
}
@@ -94,4 +94,4 @@ export function uiImproveOsmHeader() {
return improveOsmHeader;
-}
\ No newline at end of file
+}
diff --git a/modules/ui/index.js b/modules/ui/index.js
index c1361064e..25775c454 100644
--- a/modules/ui/index.js
+++ b/modules/ui/index.js
@@ -28,6 +28,7 @@ export { uiFormFields } from './form_fields';
export { uiFullScreen } from './full_screen';
export { uiGeolocate } from './geolocate';
export { uiHelp } from './help';
+export { uiImproveOsmComments } from './improveOSM_comments';
export { uiImproveOsmDetails } from './improveOSM_details';
export { uiImproveOsmEditor } from './improveOSM_editor';
export { uiImproveOsmHeader } from './improveOSM_header';
@@ -72,4 +73,4 @@ export { uiUndoRedo } from './undo_redo';
export { uiVersion } from './version';
export { uiViewOnOSM } from './view_on_osm';
export { uiViewOnKeepRight } from './view_on_keepRight';
-export { uiZoom } from './zoom';
+export { uiZoom } from './zoom';
\ No newline at end of file
diff --git a/modules/ui/keepRight_details.js b/modules/ui/keepRight_details.js
index 12d613448..96b6536b6 100644
--- a/modules/ui/keepRight_details.js
+++ b/modules/ui/keepRight_details.js
@@ -37,7 +37,7 @@ export function uiKeepRightDetails(context) {
function keepRightDetails(selection) {
- var details = selection.selectAll('.kr_error-details')
+ var details = selection.selectAll('.error-details')
.data(
(_error ? [_error] : []),
function(d) { return d.id + '-' + (d.status || 0); }
@@ -48,13 +48,13 @@ export function uiKeepRightDetails(context) {
var detailsEnter = details.enter()
.append('div')
- .attr('class', 'kr_error-details kr_error-details-container');
+ .attr('class', 'error-details error-details-container');
// description
var descriptionEnter = detailsEnter
.append('div')
- .attr('class', 'kr_error-details-description');
+ .attr('class', 'error-details-description');
descriptionEnter
.append('h4')
@@ -62,14 +62,14 @@ export function uiKeepRightDetails(context) {
descriptionEnter
.append('div')
- .attr('class', 'kr_error-details-description-text')
+ .attr('class', 'error-details-description-text')
.html(errorDetail);
// If there are entity links in the error message..
- descriptionEnter.selectAll('.kr_error_entity_link, .kr_error_object_link')
+ descriptionEnter.selectAll('.error_entity_link, .error_object_link')
.each(function() {
var link = d3_select(this);
- var isObjectLink = link.classed('kr_error_object_link');
+ var isObjectLink = link.classed('error_object_link');
var entityID = isObjectLink ?
(utilEntityRoot(_error.object_type) + _error.object_id)
: this.textContent;
diff --git a/modules/ui/keepRight_editor.js b/modules/ui/keepRight_editor.js
index ca502b1e1..c35ea4b5e 100644
--- a/modules/ui/keepRight_editor.js
+++ b/modules/ui/keepRight_editor.js
@@ -49,7 +49,7 @@ export function uiKeepRightEditor(context) {
headerEnter
.append('button')
- .attr('class', 'fr keepRight-editor-close')
+ .attr('class', 'fr error-editor-close')
.on('click', function() {
context.enter(modeBrowse(context));
})
@@ -68,12 +68,12 @@ export function uiKeepRightEditor(context) {
.attr('class', 'body')
.merge(body);
- var editor = body.selectAll('.keepRight-editor')
+ var editor = body.selectAll('.error-editor')
.data([0]);
editor.enter()
.append('div')
- .attr('class', 'modal-section keepRight-editor')
+ .attr('class', 'modal-section error-editor')
.merge(editor)
.call(keepRightHeader.error(_error))
.call(quickLinks.choices(choices))
@@ -108,7 +108,7 @@ export function uiKeepRightEditor(context) {
// enter
var saveSectionEnter = saveSection.enter()
.append('div')
- .attr('class', 'keepRight-save save-section cf');
+ .attr('class', 'error-save save-section cf');
saveSectionEnter
.append('h4')
diff --git a/modules/ui/keepRight_header.js b/modules/ui/keepRight_header.js
index 0e611c74f..33a958b75 100644
--- a/modules/ui/keepRight_header.js
+++ b/modules/ui/keepRight_header.js
@@ -28,7 +28,7 @@ export function uiKeepRightHeader() {
function keepRightHeader(selection) {
- var header = selection.selectAll('.kr_error-header')
+ var header = selection.selectAll('.error-header')
.data(
(_error ? [_error] : []),
function(d) { return d.id + '-' + (d.status || 0); }
@@ -39,11 +39,11 @@ export function uiKeepRightHeader() {
var headerEnter = header.enter()
.append('div')
- .attr('class', 'kr_error-header');
+ .attr('class', 'error-header');
var iconEnter = headerEnter
.append('div')
- .attr('class', 'kr_error-header-icon')
+ .attr('class', 'error-header-icon')
.classed('new', function(d) { return d.id < 0; });
iconEnter
@@ -55,7 +55,7 @@ export function uiKeepRightHeader() {
headerEnter
.append('div')
- .attr('class', 'kr_error-header-label')
+ .attr('class', 'error-header-label')
.text(errorTitle);
}
@@ -68,4 +68,4 @@ export function uiKeepRightHeader() {
return keepRightHeader;
-}
\ No newline at end of file
+}
diff --git a/modules/ui/raw_tag_editor.js b/modules/ui/raw_tag_editor.js
index 50b37de57..47069e159 100644
--- a/modules/ui/raw_tag_editor.js
+++ b/modules/ui/raw_tag_editor.js
@@ -155,10 +155,10 @@ export function uiRawTagEditor(context) {
.order();
items
- .each(function(tag) {
+ .each(function(d) {
var row = d3_select(this);
- var key = row.select('input.key'); // propagate bound data to child
- var value = row.select('input.value'); // propagate bound data to child
+ var key = row.select('input.key'); // propagate bound data
+ var value = row.select('input.value'); // propagate bound data
if (_entityID && taginfo && _state !== 'hover') {
bindTypeahead(key, value);
@@ -167,20 +167,22 @@ export function uiRawTagEditor(context) {
var isRelation = (_entityID && context.entity(_entityID).type === 'relation');
var reference;
- if (isRelation && tag.key === 'type') {
- reference = uiTagReference({ rtype: tag.value }, context);
+ if (isRelation && d.key === 'type') {
+ reference = uiTagReference({ rtype: d.value }, context);
} else {
- reference = uiTagReference({ key: tag.key, value: tag.value }, context);
+ reference = uiTagReference({ key: d.key, value: d.value }, context);
}
if (_state === 'hover') {
reference.showing(false);
}
- row.select('.inner-wrap')
+ row.select('.inner-wrap') // propagate bound data
.call(reference.button);
row.call(reference.body);
+
+ row.select('button.remove'); // propagate bound data
});
items.selectAll('input.key')
@@ -344,10 +346,15 @@ export function uiRawTagEditor(context) {
function removeTag(d) {
if (isReadOnly(d)) return;
- var t = {};
- t[d.key] = undefined;
- dispatch.call('change', this, t);
- d3_select(this.parentNode).remove();
+
+ if (d.key === '') { // removing the blank row
+ _showBlank = false;
+ content(wrap);
+ } else {
+ var t = {};
+ t[d.key] = undefined;
+ dispatch.call('change', this, t);
+ }
}
@@ -359,7 +366,7 @@ export function uiRawTagEditor(context) {
_showBlank = true;
content(wrap);
list.selectAll('li:last-child input.key').node().focus();
- }, 1);
+ }, 10);
}
}
diff --git a/modules/util/util.js b/modules/util/util.js
index dc5220916..75d70a7b4 100644
--- a/modules/util/util.js
+++ b/modules/util/util.js
@@ -159,9 +159,6 @@ export function utilStringQs(str) {
if (parts.length === 2) {
obj[parts[0]] = (null === parts[1]) ? '' : decodeURIComponent(parts[1]);
}
- if (parts[0] === 'mvt') {
- obj[parts[0]] = (parts[2] !== undefined) ? (decodeURIComponent(parts[1]) + '=' + decodeURIComponent(parts[2])) : (decodeURIComponent(parts[1]));
- }
return obj;
}, {});
}
diff --git a/test/spec/services/mapillary.js b/test/spec/services/mapillary.js
index f1ca87dc4..8642b9b51 100644
--- a/test/spec/services/mapillary.js
+++ b/test/spec/services/mapillary.js
@@ -14,7 +14,7 @@ describe('iD.serviceMapillary', function() {
beforeEach(function() {
context = iD.coreContext().assetPath('../dist/');
context.projection
- .scale(667544.214430109) // z14
+ .scale(iD.geoZoomToScale(14))
.translate([-116508, 0]) // 10,0
.clipExtent([[0,0], dimensions]);
diff --git a/test/spec/services/openstreetcam.js b/test/spec/services/openstreetcam.js
index a3f512986..13d03b56a 100644
--- a/test/spec/services/openstreetcam.js
+++ b/test/spec/services/openstreetcam.js
@@ -1,6 +1,6 @@
describe('iD.serviceOpenstreetcam', function() {
- var dimensions = [64, 64],
- context, server, openstreetcam;
+ var dimensions = [64, 64];
+ var context, server, openstreetcam;
before(function() {
iD.services.openstreetcam = iD.serviceOpenstreetcam;
@@ -13,7 +13,7 @@ describe('iD.serviceOpenstreetcam', function() {
beforeEach(function() {
context = iD.coreContext().assetPath('../dist/');
context.projection
- .scale(667544.214430109) // z14
+ .scale(iD.geoZoomToScale(14))
.translate([-116508, 0]) // 10,0
.clipExtent([[0,0], dimensions]);
diff --git a/test/spec/services/osm.js b/test/spec/services/osm.js
index 0bc95d8f3..476ff73c3 100644
--- a/test/spec/services/osm.js
+++ b/test/spec/services/osm.js
@@ -596,21 +596,42 @@ describe('iD.serviceOsm', function () {
});
describe('#loadNotes', function() {
+ var notesXML = '' +
+ '' +
+ '' +
+ ' 1' +
+ ' https://www.openstreetmap.org/api/0.6/notes/1' +
+ ' https://www.openstreetmap.org/api/0.6/notes/1/comment' +
+ ' https://www.openstreetmap.org/api/0.6/notes/1/close' +
+ ' 2019-01-01 00:00:00 UTC' +
+ ' open' +
+ ' ' +
+ ' ' +
+ ' 2019-01-01 00:00:00 UTC' +
+ ' 1' +
+ ' Steve' +
+ ' https://www.openstreetmap.org/user/Steve' +
+ ' opened' +
+ ' This is a note' +
+ ' <p>This is a note</p>' +
+ ' ' +
+ ' ' +
+ '' +
+ '';
+
beforeEach(function() {
+ var dimensions = [64, 64];
context.projection
- .scale(116722210.56960216)
- .translate([244505613.61327893, 74865520.92230521])
- .clipExtent([[0,0], [609.34375, 826]]);
+ .scale(iD.geoZoomToScale(14))
+ .translate([-116508, 0]) // 10,0
+ .clipExtent([[0,0], dimensions]);
});
it('fires loadedNotes when notes are loaded', function() {
connection.on('loadedNotes', spy);
- connection.loadNotes(context.projection, [64, 64], {});
+ connection.loadNotes(context.projection, {});
- var url = 'http://www.openstreetmap.org/api/0.6/notes?limit=10000&closed=7&bbox=-120.05859375,34.45221847282654,-119.970703125,34.52466147177173';
- var notesXML = ''; // TODO: determine output even though this test note is closed and will be gone soon
-
- server.respondWith('GET', url,
+ server.respondWith('GET', /notes\?/,
[200, { 'Content-Type': 'text/xml' }, notesXML ]);
server.respond();
@@ -623,7 +644,7 @@ describe('iD.serviceOsm', function () {
beforeEach(function() {
var dimensions = [64, 64];
context.projection
- .scale(667544.214430109) // z14
+ .scale(iD.geoZoomToScale(14))
.translate([-116508, 0]) // 10,0
.clipExtent([[0,0], dimensions]);
});
@@ -646,17 +667,17 @@ describe('iD.serviceOsm', function () {
describe('#getNote', function() {
- it('returns a note', function (done) {
- var note = iD.osmNote({ id: 1, loc: [0, 0], });
- var obj = {
- note: { note: { 1: note } }
- };
- connection.caches(obj);
- var result = connection.getNote(1);
- expect(result).to.deep.equal(note);
- done();
- });
+ it('returns a note', function (done) {
+ var note = iD.osmNote({ id: 1, loc: [0, 0], });
+ var obj = {
+ note: { note: { 1: note } }
+ };
+ connection.caches(obj);
+ var result = connection.getNote(1);
+ expect(result).to.deep.equal(note);
+ done();
});
+ });
describe('#removeNote', function() {
it('removes a note that is new', function(done) {
@@ -701,7 +722,8 @@ describe('iD.serviceOsm', function () {
describe('API capabilities', function() {
- var capabilitiesXML = '' +
+ var capabilitiesXML = '' +
+ '' +
'' +
'' +
'' +
diff --git a/test/spec/services/streetside.js b/test/spec/services/streetside.js
index b8adb2f1c..8221718d1 100644
--- a/test/spec/services/streetside.js
+++ b/test/spec/services/streetside.js
@@ -1,6 +1,6 @@
describe('iD.serviceStreetside', function() {
- var dimensions = [64, 64],
- context, server, streetside;
+ var dimensions = [64, 64];
+ var context, server, streetside;
before(function() {
iD.services.streetside = iD.serviceStreetside;
@@ -13,7 +13,7 @@ describe('iD.serviceStreetside', function() {
beforeEach(function() {
context = iD.coreContext().assetPath('../dist/');
context.projection
- .scale(667544.214430109) // z14
+ .scale(iD.geoZoomToScale(14))
.translate([-116508, 0]) // 10,0
.clipExtent([[0,0], dimensions]);
@@ -53,7 +53,7 @@ describe('iD.serviceStreetside', function() {
// adjust projection so that only one tile is fetched
// (JSONP hack will return the same data for every fetch)
context.projection
- .scale(10680707.430881744) // z18
+ .scale(iD.geoZoomToScale(18))
.translate([-1863988.9381333336, 762.8270222954452]) // 10.002,0.002
.clipExtent([[0,0], dimensions]);
@@ -84,7 +84,7 @@ describe('iD.serviceStreetside', function() {
it('does not load bubbles around null island', function() {
context.projection
- .scale(10680707.430881744) // z18
+ .scale(iD.geoZoomToScale(18))
.translate([0, 0])
.clipExtent([[0,0], dimensions]);